From b989456eceb5a2122d4563dc81e683c023ce10d0 Mon Sep 17 00:00:00 2001 From: Ajay Kumar Date: Tue, 15 Sep 2026 02:36:26 -0500 Subject: [PATCH] feat(nonstop_cli): harden the melos starter and enforce full coverage --- .github/workflows/nonstop-template.yml | 42 ++ README.md | 6 + packages/nonstop_cli/CHANGELOG.md | 13 +- packages/nonstop_cli/README.md | 51 +- .../flutter_project_with_mono_repo/README.md | 16 +- .../.github/workflows/quality.yml | 24 + .../{{ name.snakeCase() }}/README.md | 75 ++- .../apps/{{ name.snakeCase() }}/lib/app.dart | 56 +- .../{{ name.snakeCase() }}/lib/bootstrap.dart | 92 ++-- .../apps/{{ name.snakeCase() }}/lib/main.dart | 46 +- .../lib/router/router.dart | 31 +- .../lib/{{firebase_options_file}} | 4 +- .../lib/{{notification_lifecycle_file}} | 59 +++ .../apps/{{ name.snakeCase() }}/pubspec.yaml | 13 +- .../{{ name.snakeCase() }}/test/app_test.dart | 45 ++ .../test/entrypoint_test.dart | 36 ++ .../test/startup_test.dart | 32 ++ .../test/{{firebase_bootstrap_test_file}} | 250 +++++++++ .../test/{{notification_lifecycle_test_file}} | 98 ++++ .../test/{{smoke_test_file}} | 17 - .../docs/architecture.md | 61 +++ .../{{auth_dir}}/lib/analytics/analytics.dart | 3 +- .../features/{{auth_dir}}/lib/auth.dart | 28 +- .../{{auth_dir}}/lib/constants/routes.dart | 4 +- .../lib/data/services/auth_service_imp.dart | 13 +- .../token/firebase_auth_token_provider.dart | 205 +++----- .../{{auth_dir}}/lib/router/router.dart | 5 +- .../lib/ui/components/header_builder.dart | 46 +- .../lib/ui/screens/register_screen.dart | 6 +- .../lib/ui/screens/sign_in_screen.dart | 8 +- .../features/{{auth_dir}}/pubspec.yaml | 1 + .../{{auth_dir}}/test/auth_service_test.dart | 63 +++ .../{{auth_dir}}/test/presentation_test.dart | 219 ++++++++ .../test/{{auth_token_provider_test_file}} | 146 ++++++ .../lib/router/dashboard_router.dart | 15 +- .../test/dashboard_test.dart | 97 ++++ .../{{ name.snakeCase() }}/melos.yaml | 18 +- .../packages/core/lib/constants/defaults.dart | 4 +- .../core/lib/constants/environment.dart | 4 +- .../packages/core/lib/constants/keys.dart | 4 +- .../packages/core/lib/constants/routes.dart | 4 +- .../lib/converters/datetime_converter.dart | 4 +- .../core/lib/developer/emulators.dart | 19 +- .../core/lib/observer/core_bloc_observer.dart | 19 +- .../lib/observer/core_route_observer.dart | 33 +- .../packages/core/pubspec.yaml | 2 - .../packages/core/test/core_test.dart | 206 ++++++++ .../lib/components/auth_headers_builder.dart | 150 +++--- .../design_system/lib/components/header.dart | 4 + .../lib/constants/navigation_icons.dart | 4 +- .../packages/design_system/pubspec.yaml | 1 + .../design_system/test/components_test.dart | 209 ++++++++ .../design_system/test/integration_test.dart | 238 +++++++++ .../di/lib/src/dependency_injection_imp.dart | 10 +- .../packages/di/test/lifecycle_test.dart | 72 +++ .../localization/test/localization_test.dart | 16 + .../utils/lib/src/number_formatter.dart | 5 +- .../utils/test/number_formatter_test.dart | 44 ++ .../{{analytics_dir}}/lib/analytics.dart | 16 +- .../src/client/firebase_analytics_client.dart | 33 +- .../lib/src/models/analytics_event.dart | 9 +- .../lib/src/models/analytics_events.dart | 6 +- .../observer/analytics_route_observer.dart | 68 +-- .../lib/src/utils/analytics_helper.dart | 30 +- .../packages/{{analytics_dir}}/pubspec.yaml | 1 + .../{{analytics_dir}}/test/client_test.dart | 173 ++++++ .../test/event_names_test.dart | 84 +++ .../{{analytics_dir}}/test/helper_test.dart | 157 ++++++ .../{{crashlytics_dir}}/lib/crashlytics.dart | 55 +- .../client/firebase_crashlytics_client.dart | 67 ++- .../lib/src/config/crashlytics_config.dart | 4 +- .../lib/src/models/crash_report.dart | 4 +- .../lib/src/models/user_metadata.dart | 4 +- .../packages/{{crashlytics_dir}}/pubspec.yaml | 1 + .../{{crashlytics_dir}}/test/client_test.dart | 223 ++++++++ .../{{crashlytics_dir}}/test/models_test.dart | 78 +++ .../lib/src/routes/developer_routes.dart | 15 + .../lib/src/screens/developer_screen.dart | 6 +- .../test/navigation_test.dart | 127 +++++ .../lib/feature_flags.dart | 4 +- .../lib/src/feature_flag_wrapper.dart | 44 +- .../src/firebase_remote_config_provider.dart | 61 +-- .../lib/src/register.dart | 20 +- .../{{feature_flags_dir}}/pubspec.yaml | 1 + .../test/feature_flags_test.dart | 216 ++++++++ .../packages/{{network_dir}}/lib/network.dart | 7 +- .../lib/src/client/dio_network_client.dart | 48 +- .../src/interceptors/auth_interceptor.dart | 98 ++-- .../src/interceptors/logging_interceptor.dart | 25 +- .../packages/{{network_dir}}/pubspec.yaml | 1 + .../test/dio_network_client_test.dart | 496 ++++++++++++++++++ .../{{network_dir}}/test/models_test.dart | 133 +++++ .../test/response_contract_test.dart | 79 +++ .../lib/notifications.dart | 5 +- .../client/firebase_notification_client.dart | 322 +++++------- .../lib/src/config/notification_config.dart | 9 +- .../lib/src/device_info/device_info.dart | 5 + .../lib/src/device_info/device_info_impl.dart | 251 +++------ .../lib/src/di/notification_di.dart | 26 +- .../notification_permission_manager.dart | 8 +- .../services/notification_token_manager.dart | 10 +- .../{{notifications_dir}}/pubspec.yaml | 12 +- .../test/client_test.dart | 230 ++++++++ .../test/device_info_test.dart | 104 ++++ .../test/services_test.dart | 204 +++++++ .../{{ name.snakeCase() }}/pubspec.yaml | 1 + .../{{ name.snakeCase() }}/tool/check.dart | 49 ++ .../{{ name.snakeCase() }}/tool/coverage.dart | 163 ++++++ .../hooks/commands/melos_command.dart | 11 +- .../hooks/commands/module_vars.dart | 20 +- .../hooks/commands/next_steps_command.dart | 4 + .../lib/commands/create/command.dart | 24 +- ...flutter_project_with_mono_repo_bundle.dart | 364 ++++++++++--- packages/nonstop_cli/pubspec.yaml | 2 +- .../nonstop_cli/test/coverage_gate_test.dart | 117 +++++ .../src/commands/create_command_test.dart | 19 + .../test/template_contract_test.dart | 124 +++++ .../nonstop_cli/tool/verify_template.dart | 62 +++ 118 files changed, 6267 insertions(+), 1269 deletions(-) create mode 100644 .github/workflows/nonstop-template.yml create mode 100644 packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/.github/workflows/quality.yml create mode 100644 packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/lib/{{notification_lifecycle_file}} create mode 100644 packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/test/app_test.dart create mode 100644 packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/test/entrypoint_test.dart create mode 100644 packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/test/startup_test.dart create mode 100644 packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/test/{{firebase_bootstrap_test_file}} create mode 100644 packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/test/{{notification_lifecycle_test_file}} delete mode 100644 packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/test/{{smoke_test_file}} create mode 100644 packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/docs/architecture.md create mode 100644 packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/test/auth_service_test.dart create mode 100644 packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/test/presentation_test.dart create mode 100644 packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/test/{{auth_token_provider_test_file}} create mode 100644 packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{dashboard_dir}}/test/dashboard_test.dart create mode 100644 packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/test/core_test.dart create mode 100644 packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/design_system/test/components_test.dart create mode 100644 packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/design_system/test/integration_test.dart create mode 100644 packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/di/test/lifecycle_test.dart create mode 100644 packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/utils/test/number_formatter_test.dart create mode 100644 packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/test/client_test.dart create mode 100644 packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/test/event_names_test.dart create mode 100644 packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/test/helper_test.dart create mode 100644 packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/test/client_test.dart create mode 100644 packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/test/models_test.dart create mode 100644 packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{developer_dir}}/test/navigation_test.dart create mode 100644 packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{feature_flags_dir}}/test/feature_flags_test.dart create mode 100644 packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{network_dir}}/test/dio_network_client_test.dart create mode 100644 packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{network_dir}}/test/models_test.dart create mode 100644 packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{network_dir}}/test/response_contract_test.dart create mode 100644 packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/test/client_test.dart create mode 100644 packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/test/device_info_test.dart create mode 100644 packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/test/services_test.dart create mode 100644 packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/tool/check.dart create mode 100644 packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/tool/coverage.dart create mode 100644 packages/nonstop_cli/test/coverage_gate_test.dart create mode 100644 packages/nonstop_cli/test/template_contract_test.dart create mode 100644 packages/nonstop_cli/tool/verify_template.dart diff --git a/.github/workflows/nonstop-template.yml b/.github/workflows/nonstop-template.yml new file mode 100644 index 0000000..f28caf1 --- /dev/null +++ b/.github/workflows/nonstop-template.yml @@ -0,0 +1,42 @@ +name: NonStop generated template +on: + pull_request: + paths: ['packages/nonstop_cli/**', '.github/workflows/nonstop-template.yml'] + push: + branches: [main] + paths: ['packages/nonstop_cli/**', '.github/workflows/nonstop-template.yml'] +permissions: + contents: read +jobs: + contracts: + runs-on: ubuntu-latest + defaults: + run: + working-directory: packages/nonstop_cli + steps: + - uses: actions/checkout@v4 + - uses: subosito/flutter-action@v2 + with: + flutter-version: '3.44.0' + cache: true + - run: dart pub get + - run: dart analyze --fatal-infos lib test tool + - run: dart test --exclude-tags version-verify + generated: + needs: contracts + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + profile: [full, default, minimal, auth-only, firestore-only, network-only] + defaults: + run: + working-directory: packages/nonstop_cli + steps: + - uses: actions/checkout@v4 + - uses: subosito/flutter-action@v2 + with: + flutter-version: '3.44.0' + cache: true + - run: dart pub get + - run: dart run tool/verify_template.dart ${{ matrix.profile }} diff --git a/README.md b/README.md index 3480a63..256e930 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,12 @@ A place where Flutter packages are crafted and built. +[NonStop CLI](packages/nonstop_cli/README.md) generates a Melos-managed Flutter +starter with SOLID-oriented boundaries, offline unit/widget tests, a strict +100% handwritten-runtime line-coverage gate and generated CI. Its template is +verified by generating and building real applications, including minimal and +optional-module configurations. + - All shared [packages](packages/README.md) are in the `/packages` directory - All [plugins](plugins/README.md) are in the `/plugins` directory diff --git a/packages/nonstop_cli/CHANGELOG.md b/packages/nonstop_cli/CHANGELOG.md index f64a7b9..8baf398 100644 --- a/packages/nonstop_cli/CHANGELOG.md +++ b/packages/nonstop_cli/CHANGELOG.md @@ -1,3 +1,15 @@ +## Unreleased + +- Refactor the mono-repo template around injectable SDK adapters, explicit app + composition and owned asynchronous lifecycles. +- Fix authenticated request retries, response contracts, token refresh races, + remote-config defaults, notification registration and fail-closed guards. +- Generate offline unit/widget tests, a strict 100% handwritten-runtime line + coverage gate, portable quality commands, architecture docs and GitHub CI. +- Verify every module selection structurally and representative fresh projects + through analysis, tests, coverage and web builds. +- Generate from the shipped bundle and use workspace-local Melos for bootstrap. + ## 0.0.8+2 - **FIX**(nonstop_cli): boot apps before flutterfire configure. @@ -98,4 +110,3 @@ - **FIX**(nonstop_cli): rename nonstop_cli.dart to nonstop.dart. - **FEAT**(nonstop_cli): initial release of core commands. - diff --git a/packages/nonstop_cli/README.md b/packages/nonstop_cli/README.md index 78ab506..f562af1 100644 --- a/packages/nonstop_cli/README.md +++ b/packages/nonstop_cli/README.md @@ -152,14 +152,61 @@ youtube/ └── 📄 pubspec.yaml ``` -The generated workspace is bootstrapped, formatted and passes its own -`melos lint` and `melos test` before you touch it. If you picked any Firebase +The generated workspace is bootstrapped and formatted, with offline unit and +widget tests and a strict 100% executable-line coverage gate. Run its checks: + +```bash +dart run melos run lint +dart run melos run coverage +cd apps/youtube +flutter run +``` + +Melos is a workspace dependency; no global Melos installation is needed. +If you picked any Firebase module, run `flutterfire configure` in the app directory when you want those features live. Until then the app still runs; Firebase-backed modules are skipped at startup. +### Template quality and architecture + +The default `mono` template separates app composition, feature behavior and +reusable adapters. SDK clients receive explicit dependencies, asynchronous +startup is awaited, and disposable services own their subscriptions and error +handlers. The generated `docs/architecture.md` explains the SOLID boundaries +and how to extend them without coupling UI to infrastructure. + +Every runtime package includes tests. `dart run melos run coverage` runs them, +imports otherwise untested libraries, merges cross-package coverage and fails +below **100% executable-line coverage of handwritten runtime Dart**. Only +generated `.g.dart`, `.freezed.dart` and `.i69n.dart` files are excluded; test, +tooling and native platform code are outside this metric. Coverage does not +prove every branch, platform integration or security property. Live Firebase, +push delivery and backend authorization still need project-specific integration +tests. The generated GitHub workflow checks formatting, analysis, coverage and +a web build on Flutter 3.44.0. + +Templates are bundled with the CLI release, not fetched from the registry at +generation time. To change the default template, generate an app, implement and +verify the change there, then port it into the brick and rebuild the bundle: + +```bash +# From packages/nonstop_cli; requires Flutter 3.44.0 and Mason CLI. +dart pub get +mason bundle bricks/flutter_project_with_mono_repo -t dart -o lib/commands/create +dart format lib/commands/create/flutter_project_with_mono_repo_bundle.dart +dart test --exclude-tags version-verify +dart run tool/verify_template.dart full +dart run tool/verify_template.dart minimal +``` + +The contract suite checks the source/bundle match and parses all 512 module +selections. End-to-end CI generates fresh `full`, `default`, `minimal`, +`auth-only`, `firestore-only` and `network-only` workspaces and runs their real +checks. The verification tool retains each temporary workspace for diagnosis. +
📦 Create a Flutter package for a mono-repo diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/README.md b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/README.md index 63966be..80d96ba 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/README.md +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/README.md @@ -1 +1,15 @@ -# flutter_project_with_mono_repo \ No newline at end of file +# Flutter mono-repo template + +The default NonStop CLI template: a Melos-managed application, reusable packages +and optional feature/SDK modules. See the [CLI guide](../../README.md) for module +flags and the generate → improve → verify → port → regenerate workflow. + +The generated README and `docs/architecture.md` describe the architecture, +configuration and testing contract. All handwritten runtime Dart is subject to +a 100% executable-line coverage gate; generated code, tools and native code are +outside that scope. + +After editing `__brick__` or hooks, rebuild the embedded bundle from the CLI +package directory and run its tests and `tool/verify_template.dart`. Do not edit +the encoded bundle directly. Contract tests reject stale bundled source and +invalid Dart across all 512 module selections; CI also exercises fresh projects. diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/.github/workflows/quality.yml b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/.github/workflows/quality.yml new file mode 100644 index 0000000..a64bb2f --- /dev/null +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/.github/workflows/quality.yml @@ -0,0 +1,24 @@ +name: Template quality +on: [push, pull_request] +permissions: + contents: read +jobs: + quality: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: subosito/flutter-action@v2 + with: + flutter-version: '3.44.0' + cache: true + - run: dart pub get + - run: dart run melos bootstrap + - run: dart run melos run lint + - run: dart run melos run coverage + - run: flutter build web + working-directory: apps/{{name.snakeCase()}} + - uses: actions/upload-artifact@v4 + if: always() + with: + name: coverage + path: coverage/lcov.info diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/README.md b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/README.md index 6fa588b..fd71fce 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/README.md +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/README.md @@ -39,8 +39,8 @@ packages, packages depend on nothing above them. ## Getting started ```sh -dart pub global activate melos -melos bootstrap +dart pub get +dart run melos bootstrap ``` {{#firebase}} ### Firebase @@ -71,25 +71,78 @@ To run against the Firebase emulator suite, add ## Day-to-day ```sh -melos lint # format + analyze everything -melos test # run every package's tests -melos run generate # build_runner where it is needed -melos run generate:i69n # regenerate strings after editing messages.i69n.yaml +dart run melos run lint # format-check and analyze +dart run melos run test # run every package's tests +dart run melos run coverage # tests + strict 100% line-coverage gate +dart run melos run generate # rebuild serializers +dart run melos run generate:i69n # rebuild localization ``` ## Adding to the monorepo ```sh -nonstop create package my_feature -o features -nonstop create package my_package -o packages -nonstop create app my_second_app -o apps -nonstop create plugin my_plugin -o plugins +nonstop create my_feature --template package -o features +nonstop create my_package --template package -o packages +nonstop create my_second_app --template app -o apps +nonstop create my_plugin --template plugin -o plugins ``` ## Where to start -1. Replace the placeholder tabs in `features/dashboard`. +1. Replace the {{#dashboard}}placeholder tabs in `features/dashboard`{{/dashboard}}{{^dashboard}}placeholder home screen in the app router{{/dashboard}}. 2. Put your product strings in `packages/localization/lib/messages.i69n.yaml`. 3. Set the palette in `packages/design_system/lib/generated/theme.dart`. 4. Add feature modules and spread their routes into `apps/{{name.snakeCase()}}/lib/router/router.dart`. + +## Architecture and testing + +The starter separates the app view, routing, startup and foreground lifecycle. +Clients accept injected SDKs, loggers and transports; feature code consumes small +interfaces rather than subclassing platform SDKs. See [architecture](docs/architecture.md) +for the SOLID boundaries and an example of adding a tested feature. + +Every generated package has tests. Unit and widget tests run without a Firebase +account or network service; Firebase integration tests use offline platform doubles. +The strict gate imports otherwise-unloaded libraries, runs all suites, merges their +LCOV records and requires **100% executable-line coverage of workspace `lib/` code**. +It includes entrypoints, startup, theme and error paths. Only compiler-generated +`.g.dart`, `.freezed.dart` and `.i69n.dart` files are excluded. + +```sh +dart run tool/coverage.dart +# Inspect existing reports without rerunning tests (not a validation run): +dart run tool/coverage.dart --report-only +``` + +The gate fails for failed tests, missing tests/reports, or uncovered lines. +The merged report is `coverage/lcov.info`. Do not run two coverage jobs in the +same checkout: each owns a temporary `test/coverage_imports_test.dart` fixture, +removed on normal completion. After an interrupted run, inspect and remove only +that generated fixture before retrying. + +Coverage is not a proof of correctness, branch completeness, security, or native +plugin compatibility. Keep assertions about behavior, and add device integration +tests for your Firebase project, native permissions, provider sign-in and backend. +The generated GitHub Actions workflow checks analysis, tests, coverage and a web build. + +{{#auth}}### Authentication and demo mode + +`GoAuthRoute` denies access when authentication is missing or signed out. +{{#dashboard}}The starter dashboard explicitly allows **unconfigured demo mode** so +you can explore it before `flutterfire configure`. It contains no protected data. +Do not use `allowUnconfigured: true` for real protected routes. +{{/dashboard}}Client-side guards are navigation helpers; enforce authorization in +backend endpoints and Firebase security rules. +{{/auth}} +{{#notifications}}### Notifications + +The SDK client owns subscriptions, not navigation or toast widgets. The app +supplies callbacks, queues cold-start routes until the router is ready, and owns +foreground lifecycle handling. Device IDs are random per installation and +persisted locally; they are not hardware fingerprints. + +Implement the `POST /device-tokens/me` and `DELETE /device-tokens/me/:deviceId` +backend endpoints before enabling token registration in production. Configure +native capabilities, Firebase messaging and your app's permission explanation. +{{/notifications}} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/lib/app.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/lib/app.dart index 2bd1519..12b9946 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/lib/app.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/lib/app.dart @@ -1,55 +1,15 @@ import 'package:core/core.dart'; import 'package:design_system/design_system.dart'; -{{#notifications}}import 'package:di/di.dart'; -{{/notifications}}import 'package:flutter/material.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; import 'package:localization/localization.dart'; -{{#notifications}}import 'package:notifications/notifications.dart'; -{{/notifications}}import 'package:{{name.snakeCase()}}/router/router.dart'; -class App extends StatefulWidget { - const App({super.key}); +/// The application view. Its owner creates and disposes the router. +class App extends StatelessWidget { + const App({required this.router, super.key}); - @override - State createState() => _AppState(); -} + final GoRouter router; -class _AppState extends State { -{{#notifications}} late final AppLifecycleListener _lifecycleListener; - -{{/notifications}} @override - void initState() { - super.initState(); -{{#notifications}} // Asking for notification permission needs a foreground surface, so this - // runs from the first frame rather than from bootstrap. Move it behind - // sign-in once you would rather ask a user who has committed to the app. - _lifecycleListener = AppLifecycleListener(onResume: _clearBadge); - WidgetsBinding.instance.addPostFrameCallback((_) async { - if (!di.has()) return; - final logger = di.get(); - try { - await di.get().init(); - } catch (e, s) { - logger.e('Failed to initialize NotificationClient', e, s); - } - }); -{{/notifications}} } -{{#notifications}} - void _clearBadge() { - if (!di.has()) return; - final logger = di.get(); - try { - di.get().clearBadge(); - } catch (e, s) { - logger.e('Failed to clear badge on app resume', e, s); - } - } - - @override - void dispose() { - _lifecycleListener.dispose(); - super.dispose(); - } -{{/notifications}} @override Widget build(BuildContext context) { return GlobalEventChannelProvider( @@ -58,9 +18,7 @@ class _AppState extends State { debugShowCheckedModeBanner: false, title: strings.app.name, theme: theme, - routeInformationParser: AppRouter.routeInformationParser, - routeInformationProvider: AppRouter.routeInformationProvider, - routerDelegate: AppRouter.routerDelegate, + routerConfig: router, ), ), ); diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/lib/bootstrap.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/lib/bootstrap.dart index f0aec4d..ada11e6 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/lib/bootstrap.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/lib/bootstrap.dart @@ -1,25 +1,41 @@ {{#analytics}}import 'package:analytics/analytics.dart' as analytics; -{{/analytics}}{{#auth}}import 'package:auth/auth.dart' as auth; -{{/auth}}import 'package:bloc/bloc.dart'; +{{/analytics}} +{{#auth}}import 'package:auth/auth.dart' as auth; +{{/auth}} +import 'package:bloc/bloc.dart'; import 'package:core/core.dart' as core; {{#firebase}}import 'package:core/developer/emulators.dart' as emulators; -{{/firebase}}import 'package:core/logger/logger.dart'; +{{/firebase}} +import 'package:core/logger/logger.dart'; {{#crashlytics}}import 'package:crashlytics/crashlytics.dart' as crashlytics; -{{/crashlytics}}import 'package:di/di.dart'; +{{/crashlytics}} +import 'package:di/di.dart'; +{{#notifications}}import 'package:design_system/toast/toasts.dart'; +{{/notifications}} {{#feature_flags}}import 'package:feature_flags/feature_flags.dart' as feature_flags; -{{/feature_flags}}{{#firebase}}import 'package:firebase_core/firebase_core.dart'; -{{/firebase}}import 'package:flutter/widgets.dart'; +{{/feature_flags}} +{{#firebase}}import 'package:firebase_core/firebase_core.dart'; +{{/firebase}} +import 'package:flutter/widgets.dart'; {{#network}}import 'package:network/network.dart' as network; -{{/network}}{{#notifications}}import 'package:notifications/notifications.dart' as notifications; -{{/notifications}}{{#firebase}}import 'package:{{name.snakeCase()}}/firebase_options.dart'; +{{/network}} +{{#notifications}}import 'package:notifications/notifications.dart' as notifications; +{{/notifications}} +{{#firebase}}import 'package:{{name.snakeCase()}}/firebase_options.dart'; {{/firebase}} + /// Brings every module up, in dependency order, before the first frame. /// /// Order matters: the logger is registered first so everything after it can /// report failures, and Firebase must be live before any Firebase-backed /// module initialises. If `flutterfire configure` has not been run yet, those /// modules are skipped so the rest of the app still boots. -Future init() async { +Future init({ + void Function(String route)? onOpenRoute, +{{#firebase}} FirebaseOptions? firebaseOptions, + bool useEmulators = core.Environment.useEmulators, +{{/firebase}} +}) async { WidgetsFlutterBinding.ensureInitialized(); final stopwatch = Stopwatch()..start(); @@ -28,13 +44,14 @@ Future init() async { logger.i('Core ready in ${stopwatch.elapsedMilliseconds} ms'); Bloc.observer = core.CoreBlocObserver(); -{{#firebase}} - var firebaseReady = false; + +{{#firebase}} var firebaseReady = false; + FirebaseOptions? resolvedOptions; try { - final options = DefaultFirebaseOptions.currentPlatform; - await Firebase.initializeApp(options: options); + resolvedOptions = firebaseOptions ?? DefaultFirebaseOptions.currentPlatform; + await Firebase.initializeApp(options: resolvedOptions); firebaseReady = true; - if (core.Environment.useEmulators) { + if (useEmulators) { await emulators.init(); } } on UnsupportedError catch (error) { @@ -45,31 +62,42 @@ Future init() async { ? 'Firebase ready' : 'Firebase not configured yet; skipping Firebase modules', ); -{{/firebase}} -{{#crashlytics}} if (firebaseReady) await crashlytics.init(); -{{/crashlytics}}{{#analytics}} if (firebaseReady) await analytics.init(); -{{/analytics}}{{#feature_flags}} if (firebaseReady) await feature_flags.init(); -{{/feature_flags}}{{#auth}} - if (firebaseReady) { - final options = DefaultFirebaseOptions.currentPlatform; - final clientId = options.iosClientId ?? options.androidClientId ?? ''; + +{{/firebase}}{{#crashlytics}} if (firebaseReady) await crashlytics.init(); +{{/crashlytics}} +{{#analytics}} if (firebaseReady) await analytics.init(); +{{/analytics}} +{{#feature_flags}} if (firebaseReady) await feature_flags.init(); +{{/feature_flags}} + +{{#auth}} if (firebaseReady) { + final clientId = + resolvedOptions!.iosClientId ?? resolvedOptions.androidClientId ?? ''; await auth.init(auth.DefaultAuthConfig(clientId: clientId)); } -{{/auth}}{{#network}} - await network.init( + +{{/auth}}{{#network}} await network.init( config: network.DefaultNetworkConfig(baseUrl: core.Environment.baseUrl), ); -{{/network}}{{#notifications}} - if (firebaseReady) await notifications.init(); -{{/notifications}} - // TODO: initialise your own feature modules here. + +{{/network}}{{#notifications}} if (firebaseReady) { + await notifications.init( + config: notifications.NotificationConfig( + onForeground: (title, body) => + Toast.notification(title: title, body: body), + onOpenRoute: onOpenRoute, + ), + ); + } + +{{/notifications}} // TODO: initialise your own feature modules here. stopwatch.stop(); logger.i('Bootstrap completed in ${stopwatch.elapsedMilliseconds} ms'); -{{#analytics}} - if (firebaseReady) { + +{{#analytics}} if (firebaseReady) { await analytics.AnalyticsHelper.logAppOpen( parameters: {'bootstrap_duration': stopwatch.elapsedMilliseconds}, ); - } -{{/analytics}}} + }{{/analytics}} +} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/lib/main.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/lib/main.dart index 7178b59..b28deab 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/lib/main.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/lib/main.dart @@ -1,8 +1,48 @@ import 'package:flutter/material.dart'; +{{#notifications}}import 'package:core/core.dart'; +{{/notifications}} +import 'package:di/di.dart'; +import 'package:go_router/go_router.dart'; +{{#notifications}}import 'package:notifications/notifications.dart'; +{{/notifications}} import 'package:{{name.snakeCase()}}/app.dart'; import 'package:{{name.snakeCase()}}/bootstrap.dart' as bootstrap; +{{#notifications}}import 'package:{{name.snakeCase()}}/notification_lifecycle.dart'; +{{/notifications}} +import 'package:{{name.snakeCase()}}/router/router.dart'; -void main() async { - await bootstrap.init(); - runApp(const App()); +Future main() => startApp(); + +/// Composition root. Queue cold-start notification routes until routing exists. +Future startApp({ + Future Function(void Function(String) onOpenRoute)? initialize, + void Function(Widget) mount = runApp, +}) async { + GoRouter? activeRouter; + String? pendingRoute; + void onOpenRoute(String route) { + if (activeRouter == null) { + pendingRoute = route; + } else { + activeRouter.go(route); + } + } + + if (initialize == null) { + await bootstrap.init(onOpenRoute: onOpenRoute); + } else { + await initialize(onOpenRoute); + } + final router = AppRouter.createRouter(initialLocation: pendingRoute); + activeRouter = router; + di.register(router, dispose: (router) => router.dispose()); + mount( +{{#notifications}} NotificationLifecycle( + logger: di.get(), + client: di.has() + ? di.get() + : null, + child: App(router: router), + ),{{/notifications}}{{^notifications}} App(router: router),{{/notifications}} + ); } diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/lib/router/router.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/lib/router/router.dart index 74ead4b..b8bc4ed 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/lib/router/router.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/lib/router/router.dart @@ -4,40 +4,28 @@ {{#dashboard}}import 'package:dashboard/dashboard.dart'; {{/dashboard}}import 'package:design_system/design_system.dart'; {{#developer}}import 'package:developer/developer.dart' as developer; -{{/developer}}import 'package:di/di.dart'; -{{#analytics}}import 'package:firebase_core/firebase_core.dart'; -{{/analytics}}import 'package:flutter/foundation.dart'; +{{/developer}}{{#analytics}}import 'package:di/di.dart'; +{{/analytics}} +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:localization/localization.dart'; -import 'package:navigation_history_observer/navigation_history_observer.dart'; import 'package:{{name.snakeCase()}}/ui/splash_screen.dart'; /// The app's single [GoRouter]. /// /// Feature packages expose their own `routes` list and are spliced in here, so /// adding a feature is one import plus one spread - no route table to merge. -class AppRouter { - const AppRouter._(); +abstract final class AppRouter { - static final GoRouter _router = createRouter(); - - static RouterDelegate get routerDelegate => _router.routerDelegate; - - static RouteInformationParser get routeInformationParser => - _router.routeInformationParser; - - static RouteInformationProvider? get routeInformationProvider => - _router.routeInformationProvider; - - static GoRouter createRouter() { + static GoRouter createRouter({String? initialLocation}) { final router = GoRouter( debugLogDiagnostics: kDebugMode, - initialLocation: core.CoreRoutes.root, + initialLocation: initialLocation ?? core.CoreRoutes.root, observers: [ - NavigationHistoryObserver(), core.CoreRouteObserver(), -{{#analytics}} if (Firebase.apps.isNotEmpty) AnalyticsRouteObserver(), +{{#analytics}} if (di.has()) + AnalyticsRouteObserver(client: di.get(), logger: di.get()), {{/analytics}} ], errorBuilder: (context, state) => ErrorScreen( title: strings.errors.page_not_found, @@ -80,7 +68,6 @@ class AppRouter { ], ); - di.register(router); return router; } {{#auth}} @@ -112,4 +99,4 @@ class _HomeScreen extends StatelessWidget { ); } } -{{/dashboard}} \ No newline at end of file +{{/dashboard}} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/lib/{{firebase_options_file}} b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/lib/{{firebase_options_file}} index f99cf2a..86f0174 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/lib/{{firebase_options_file}} +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/lib/{{firebase_options_file}} @@ -8,9 +8,7 @@ // so the rest of the app still runs. import 'package:firebase_core/firebase_core.dart' show FirebaseOptions; -class DefaultFirebaseOptions { - const DefaultFirebaseOptions._(); - +abstract final class DefaultFirebaseOptions { static FirebaseOptions get currentPlatform => throw UnsupportedError( 'Firebase has not been configured for {{name.titleCase()}}.\n' 'Run `flutterfire configure` inside apps/{{name.snakeCase()}} ' diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/lib/{{notification_lifecycle_file}} b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/lib/{{notification_lifecycle_file}} new file mode 100644 index 0000000..481ab7c --- /dev/null +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/lib/{{notification_lifecycle_file}} @@ -0,0 +1,59 @@ +import 'package:core/core.dart'; +import 'package:flutter/widgets.dart'; +import 'package:notifications/notifications.dart'; + +/// Owns foreground notification work independently of the application view. +class NotificationLifecycle extends StatefulWidget { + const NotificationLifecycle({ + required this.child, + required this.logger, + this.client, + super.key, + }); + + final Widget child; + final Logger logger; + final NotificationClient? client; + + @override + State createState() => _NotificationLifecycleState(); +} + +class _NotificationLifecycleState extends State { + late final AppLifecycleListener _listener; + + @override + void initState() { + super.initState(); + _listener = AppLifecycleListener(onResume: _clearBadge); + WidgetsBinding.instance.addPostFrameCallback((_) async { + if (!mounted) return; + try { + await widget.client?.init(); + } catch (error, stackTrace) { + widget.logger.e( + 'Notification initialization failed', + error, + stackTrace, + ); + } + }); + } + + Future _clearBadge() async { + try { + await widget.client?.clearBadge(); + } catch (error, stackTrace) { + widget.logger.e('Notification badge clearing failed', error, stackTrace); + } + } + + @override + void dispose() { + _listener.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) => widget.child; +} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/pubspec.yaml b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/pubspec.yaml index b60cd50..03d4754 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/pubspec.yaml +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/pubspec.yaml @@ -13,7 +13,6 @@ dependencies: cupertino_icons: ^1.0.8 go_router: ^15.1.3 bloc: ^9.0.0 - navigation_history_observer: ^1.1.1 core: path: ../../packages/core design_system: @@ -43,7 +42,15 @@ dependencies: path: ../../features/dashboard {{/dashboard}} dev_dependencies: - flutter_test: +{{#firebase}} mocktail: ^1.0.4 + plugin_platform_interface: ^2.1.8 + firebase_core_platform_interface: ^6.0.3 +{{/firebase}}{{#auth}} firebase_auth_platform_interface: ^7.7.3 +{{/auth}}{{#analytics}} firebase_analytics_platform_interface: ^4.4.3 +{{/analytics}}{{#crashlytics}} firebase_crashlytics_platform_interface: ^3.8.10 +{{/crashlytics}}{{#feature_flags}} firebase_remote_config_platform_interface: ^2.0.0 +{{/feature_flags}}{{#notifications}} firebase_messaging_platform_interface: ^4.6.10 +{{/notifications}} flutter_test: sdk: flutter flutter_lints: ^5.0.0 @@ -58,4 +65,4 @@ flutter: - family: SocialIcons fonts: - asset: packages/firebase_ui_auth/fonts/SocialIcons.ttf -{{/auth}} \ No newline at end of file +{{/auth}} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/test/app_test.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/test/app_test.dart new file mode 100644 index 0000000..d8c10e7 --- /dev/null +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/test/app_test.dart @@ -0,0 +1,45 @@ +import 'package:core/core.dart' as core; +import 'package:di/di.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:go_router/go_router.dart'; +import 'package:localization/localization.dart'; +import 'package:{{name.snakeCase()}}/app.dart'; +import 'package:{{name.snakeCase()}}/router/router.dart'; + +void main() { + setUp(core.init); + tearDown(di.reset); + + testWidgets('renders an injected router without platform initialization', ( + tester, + ) async { + final router = GoRouter( + routes: [ + GoRoute(path: '/', builder: (_, _) => const Text('Test destination')), + ], + ); + addTearDown(router.dispose); + await tester.pumpWidget(App(router: router)); + await tester.pumpAndSettle(); + expect(find.text('Test destination'), findsOneWidget); + expect(tester.takeException(), isNull); + }); + + testWidgets('real routes boot without configured Firebase and switch tabs', ( + tester, + ) async { + final router = AppRouter.createRouter(); + addTearDown(router.dispose); + await tester.pumpWidget(App(router: router)); + await tester.pumpAndSettle(); +{{#dashboard}} expect(find.text('Explore'), findsWidgets); + await tester.tap(find.text('Explore').first); + await tester.pumpAndSettle(); +{{/dashboard}} router.go('/error'); + await tester.pumpAndSettle(); + expect(find.text(strings.generic.error), findsWidgets); + expect(find.text(strings.errors.unexpected_error), findsWidgets); + expect(tester.takeException(), isNull); + }); +} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/test/entrypoint_test.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/test/entrypoint_test.dart new file mode 100644 index 0000000..cba57d7 --- /dev/null +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/test/entrypoint_test.dart @@ -0,0 +1,36 @@ +import 'package:di/di.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:go_router/go_router.dart'; +{{#network}}import 'package:network/network.dart'; +{{/network}} +import 'package:{{name.snakeCase()}}/main.dart' as entrypoint; + +void main() { + tearDown(di.reset); + testWidgets('real entrypoint starts offline without Firebase credentials', ( + tester, + ) async { + await entrypoint.main(); + await tester.pump(); + await tester.pumpAndSettle(); +{{#network}} expect(di.has(), isTrue); +{{/network}} + expect(di.has(), isTrue); +{{#dashboard}} expect(find.text('Explore'), findsWidgets); +{{/dashboard}} + final router = di.get(); + router.go('/unknown'); + await tester.pumpAndSettle(); + expect(find.byType(OutlinedButton), findsOneWidget); + await tester.tap(find.byType(OutlinedButton)); + await tester.pumpAndSettle(); + router.go('/error?title=Test&message=Try%20later&error=Details'); + await tester.pumpAndSettle(); + expect(find.text('Try later'), findsOneWidget); + await tester.tap(find.byType(OutlinedButton)); + await tester.pumpAndSettle(); + expect(tester.takeException(), isNull); + await tester.pumpWidget(const SizedBox()); + }); +} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/test/startup_test.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/test/startup_test.dart new file mode 100644 index 0000000..84127d7 --- /dev/null +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/test/startup_test.dart @@ -0,0 +1,32 @@ +import 'package:di/di.dart'; +import 'package:core/core.dart' as core; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:{{name.snakeCase()}}/main.dart' as entrypoint; + +void main() { + tearDown(di.reset); + testWidgets( + 'cold-start notification routes wait for the router; later routes navigate directly', + (tester) async { + late void Function(String) openRoute; + late Widget app; + await entrypoint.startApp( + initialize: (callback) async { + await core.init(); + openRoute = callback; + callback('/error?title=From%20notification'); + }, + mount: (widget) => app = widget, + ); + await tester.pumpWidget(app); + await tester.pumpAndSettle(); + expect(find.text('From notification'), findsOneWidget); + openRoute('/home'); + await tester.pumpAndSettle(); +{{#dashboard}} expect(find.text('Explore'), findsWidgets); +{{/dashboard}} + await tester.pumpWidget(const SizedBox()); + }, + ); +} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/test/{{firebase_bootstrap_test_file}} b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/test/{{firebase_bootstrap_test_file}} new file mode 100644 index 0000000..5dc417b --- /dev/null +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/test/{{firebase_bootstrap_test_file}} @@ -0,0 +1,250 @@ +// Protected delegate methods are the FlutterFire platform mocking seam. +// ignore_for_file: invalid_use_of_protected_member +{{#analytics}}import 'package:analytics/analytics.dart'; +{{/analytics}} +{{#auth}}import 'package:auth/auth.dart' as auth; +{{/auth}} +{{#auth}}import 'package:core/developer/emulators.dart' as emulators; +{{/auth}} +{{#crashlytics}}import 'package:crashlytics/crashlytics.dart'; +{{/crashlytics}} +import 'package:di/di.dart'; +{{#feature_flags}}import 'package:feature_flags/feature_flags.dart'; +{{/feature_flags}} +import 'package:firebase_core/firebase_core.dart'; +import 'package:firebase_core_platform_interface/test.dart'; +{{#auth}}import 'package:firebase_auth_platform_interface/firebase_auth_platform_interface.dart'; +{{/auth}} +{{#analytics}}import 'package:firebase_analytics_platform_interface/firebase_analytics_platform_interface.dart'; +{{/analytics}} +{{#crashlytics}}import 'package:firebase_crashlytics_platform_interface/firebase_crashlytics_platform_interface.dart'; +{{/crashlytics}} +{{#feature_flags}}import 'package:firebase_remote_config_platform_interface/firebase_remote_config_platform_interface.dart'; +{{/feature_flags}} +{{#notifications}}import 'package:firebase_messaging_platform_interface/firebase_messaging_platform_interface.dart'; +{{/notifications}} +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +{{#auth}}import 'package:go_router/go_router.dart'; +{{/auth}} +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +{{#notifications}}import 'package:notifications/notifications.dart'; +{{/notifications}} +{{#firebase_sdk_mocks}}import 'package:plugin_platform_interface/plugin_platform_interface.dart'; +{{/firebase_sdk_mocks}} +import 'package:{{name.snakeCase()}}/bootstrap.dart' as bootstrap; +import 'package:{{name.snakeCase()}}/main.dart' as entrypoint; +import 'package:{{name.snakeCase()}}/app.dart'; +import 'package:{{name.snakeCase()}}/router/router.dart'; + +class _Core extends MockFirebaseApp { + @override + Future> initializeCore() async { + final apps = await super.initializeCore(); +{{#crashlytics}} apps.first.pluginConstants['plugins.flutter.io/firebase_crashlytics'] = { + 'isCrashlyticsCollectionEnabled': false, + }; +{{/crashlytics}} return apps; + } +} + +{{#auth}}class _Auth extends Mock + with MockPlatformInterfaceMixin + implements FirebaseAuthPlatform {} +{{/auth}} + +{{#analytics}}class _Analytics extends Mock + with MockPlatformInterfaceMixin + implements FirebaseAnalyticsPlatform {} +{{/analytics}} + +{{#crashlytics}}class _Crash extends Mock + with MockPlatformInterfaceMixin + implements FirebaseCrashlyticsPlatform {} +{{/crashlytics}} + +{{#feature_flags}}class _Flags extends Mock + with MockPlatformInterfaceMixin + implements FirebaseRemoteConfigPlatform {} +{{/feature_flags}} + +{{#notifications}}class _Messaging extends Mock + with MockPlatformInterfaceMixin + implements FirebaseMessagingPlatform {} +{{/notifications}} + +{{#auth}}class _User extends Mock + with MockPlatformInterfaceMixin + implements UserPlatform {} +{{/auth}} + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + testWidgets( + 'configured bootstrap composes all modules against offline platform doubles', + (tester) async { + TestFirebaseCoreHostApi.setUp(_Core()); + final app = await Firebase.initializeApp(); + registerFallbackValue(app); +{{#feature_flags}} registerFallbackValue( + RemoteConfigSettings( + fetchTimeout: const Duration(seconds: 1), + minimumFetchInterval: Duration.zero, + ), + ); +{{/feature_flags}}{{#auth}} final identity = _Auth(); +{{/auth}} +{{#analytics}} final analytics = _Analytics(); +{{/analytics}} +{{#crashlytics}} final crash = _Crash(); +{{/crashlytics}} +{{#feature_flags}} final flags = _Flags(); +{{/feature_flags}} +{{#notifications}} final messaging = _Messaging(); +{{/notifications}} +{{#auth}} FirebaseAuthPlatform.instance = identity; +{{/auth}} +{{#analytics}} FirebaseAnalyticsPlatform.instance = analytics; +{{/analytics}} +{{#crashlytics}} FirebaseCrashlyticsPlatform.instance = crash; +{{/crashlytics}} +{{#feature_flags}} FirebaseRemoteConfigPlatform.instance = flags; +{{/feature_flags}} +{{#notifications}} FirebaseMessagingPlatform.instance = messaging; +{{/notifications}} +{{#auth}} when( + () => identity.delegateFor(app: any(named: 'app')), + ).thenReturn(identity); + when( + () => identity.setInitialValues( + currentUser: any(named: 'currentUser'), + languageCode: any(named: 'languageCode'), + ), + ).thenReturn(identity); + when( + identity.idTokenChanges, + ).thenAnswer((_) => const Stream.empty()); + when( + identity.authStateChanges, + ).thenAnswer((_) => const Stream.empty()); + when( + identity.userChanges, + ).thenAnswer((_) => const Stream.empty()); + when( + () => identity.useAuthEmulator(any(), any()), + ).thenAnswer((_) async {}); +{{/auth}}{{#analytics}} when( + () => analytics.delegateFor( + app: any(named: 'app'), + webOptions: any(named: 'webOptions'), + ), + ).thenReturn(analytics); + when( + () => analytics.setAnalyticsCollectionEnabled(any()), + ).thenAnswer((_) async {}); + when( + () => analytics.logEvent( + name: any(named: 'name'), + parameters: any(named: 'parameters'), + ), + ).thenAnswer((_) async {}); +{{/analytics}}{{#crashlytics}} when( + () => crash.setInitialValues( + isCrashlyticsCollectionEnabled: any( + named: 'isCrashlyticsCollectionEnabled', + ), + ), + ).thenReturn(crash); + when( + () => crash.setCrashlyticsCollectionEnabled(any()), + ).thenAnswer((_) async {}); + when(crash.checkForUnsentReports).thenAnswer((_) async => false); +{{/crashlytics}}{{#feature_flags}} when(() => flags.delegateFor(app: any(named: 'app'))).thenReturn(flags); + when( + () => flags.setInitialValues( + remoteConfigValues: any(named: 'remoteConfigValues'), + ), + ).thenReturn(flags); + when(() => flags.setConfigSettings(any())).thenAnswer((_) async {}); + when(() => flags.setDefaults(any())).thenAnswer((_) async {}); + when(flags.fetchAndActivate).thenAnswer((_) async => false); + when(() => flags.lastFetchTime).thenReturn(DateTime(2026)); + when( + () => flags.lastFetchStatus, + ).thenReturn(RemoteConfigFetchStatus.success); +{{/feature_flags}}{{#notifications}} when( + () => messaging.delegateFor(app: any(named: 'app')), + ).thenReturn(messaging); + when( + () => messaging.setInitialValues( + isAutoInitEnabled: any(named: 'isAutoInitEnabled'), + ), + ).thenReturn(messaging); +{{/notifications}} addTearDown(di.reset); + debugDefaultTargetPlatformOverride = TargetPlatform.iOS; + addTearDown(() => debugDefaultTargetPlatformOverride = null); + await bootstrap.init(firebaseOptions: app.options, useEmulators: true); + debugDefaultTargetPlatformOverride = null; +{{#analytics}} expect(di.has(), isTrue); +{{/analytics}} +{{#crashlytics}} expect(di.has(), isTrue); +{{/crashlytics}} +{{#feature_flags}} expect(di.has(), isTrue); +{{/feature_flags}} +{{#auth}} expect(di.has(), isTrue); +{{/auth}} +{{#notifications}} expect(di.has(), isTrue); +{{/notifications}} +{{#notifications}} expect(FirebaseTokenManager(), isA()); +{{/notifications}} +{{#notifications}} expect(FirebasePermissionManager(), isA()); +{{/notifications}} +{{#analytics}} verify( + () => analytics.logEvent( + name: 'app_open', + parameters: any(named: 'parameters'), + ), + ).called(1); +{{/analytics}}{{#auth}} when( + () => identity.useAuthEmulator(any(), any()), + ).thenThrow(StateError('offline')); + await expectLater(emulators.init(), throwsStateError); +{{/auth}} late Widget composed; + await entrypoint.startApp( + initialize: (_) async {}, + mount: (app) => composed = app, + ); + expect(composed, isA()); + final router = AppRouter.createRouter(initialLocation: '/error'); + addTearDown(router.dispose); + await tester.pumpWidget(App(router: router)); + await tester.pumpAndSettle(); +{{#auth}} final context = tester.element(find.byType(OutlinedButton)); + final route = router.configuration.routes.whereType().firstWhere( + (r) => r.path == auth.AuthRoutes.signIn, + ); + final screen = + route.builder!(context, GoRouterState.of(context)) + as auth.SignInScreen; + when(() => identity.currentUser).thenReturn(_User()); + await screen.onSignedIn(context); + await tester.pumpAndSettle(); +{{#dashboard}} expect(find.text('Explore'), findsWidgets); +{{/dashboard}} +{{/auth}}{{#notifications}} await di.get().onForeground!('Notice', 'Details'); + await tester.pump(); + await tester.pump(const Duration(milliseconds: 500)); + await tester.pump(const Duration(milliseconds: 500)); + expect(find.text('Notice'), findsOneWidget); + await tester.pump(const Duration(seconds: 4)); + await tester.pumpAndSettle(); +{{/notifications}}{{#auth}} when(() => identity.currentUser).thenReturn(null); + router.go('/'); + await tester.pumpAndSettle(); + expect(find.byType(auth.SignInScreen), findsOneWidget); +{{/auth}} expect(tester.takeException(), isNull); + await tester.pumpWidget(const SizedBox()); + }, + ); +} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/test/{{notification_lifecycle_test_file}} b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/test/{{notification_lifecycle_test_file}} new file mode 100644 index 0000000..cf50ecb --- /dev/null +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/test/{{notification_lifecycle_test_file}} @@ -0,0 +1,98 @@ +import 'package:core/core.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:notifications/notifications.dart'; +import 'package:{{name.snakeCase()}}/notification_lifecycle.dart'; + +class _Logger implements Logger { + final errors = []; + @override + Object get logger => this; + @override + void d(String message) {} + @override + void i(String message) {} + @override + void w(String message) {} + @override + void e(String message, [Object? error, StackTrace? stackTrace]) => + errors.add(error); +} + +class _Client implements NotificationClient { + int starts = 0; + int clears = 0; + bool fail = false; + @override + Future init() async { + starts++; + if (fail) throw StateError('init failed'); + } + + @override + Future clearBadge() async { + clears++; + if (fail) throw StateError('badge failed'); + } + + @override + dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); +} + +void main() { + testWidgets('initializes after the first frame and clears badge on resume', ( + tester, + ) async { + final client = _Client(); + final logger = _Logger(); + await tester.pumpWidget( + NotificationLifecycle( + logger: logger, + client: client, + child: const SizedBox(), + ), + ); + expect(client.starts, 1); + tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.inactive); + tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.resumed); + await tester.pump(); + expect(client.clears, 1); + expect(logger.errors, isEmpty); + await tester.pumpWidget(const SizedBox()); + tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.inactive); + tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.resumed); + await tester.pump(); + expect(client.clears, 1); + }); + + testWidgets('catches asynchronous initialization and badge failures', ( + tester, + ) async { + final client = _Client()..fail = true; + final logger = _Logger(); + await tester.pumpWidget( + NotificationLifecycle( + logger: logger, + client: client, + child: const SizedBox(), + ), + ); + await tester.pump(); + tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.inactive); + tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.resumed); + await tester.pump(); + expect(logger.errors, hasLength(2)); + expect(tester.takeException(), isNull); + }); + + testWidgets('works when notifications are not configured', (tester) async { + final logger = _Logger(); + await tester.pumpWidget( + NotificationLifecycle(logger: logger, child: const SizedBox()), + ); + tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.inactive); + tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.resumed); + await tester.pump(); + expect(logger.errors, isEmpty); + }); +} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/test/{{smoke_test_file}} b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/test/{{smoke_test_file}} deleted file mode 100644 index a87dd87..0000000 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/test/{{smoke_test_file}} +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:{{name.snakeCase()}}/app.dart'; -import 'package:{{name.snakeCase()}}/bootstrap.dart' as bootstrap; - -void main() { - testWidgets('the app boots and reaches its first screen', (tester) async { - // Exercises the whole graph: module init order, DI registration and the - // splash redirect. If a module forgets to register something, this fails - // here rather than on a device. - await bootstrap.init(); - await tester.pumpWidget(const App()); - await tester.pumpAndSettle(); - - expect(tester.takeException(), isNull); -{{#dashboard}} expect(find.text('Explore'), findsWidgets); -{{/dashboard}} }); -} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/docs/architecture.md b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/docs/architecture.md new file mode 100644 index 0000000..94cf46f --- /dev/null +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/docs/architecture.md @@ -0,0 +1,61 @@ +# Architecture decisions + +The app is the composition root. Features own screens and feature behavior; +shared packages expose cohesive contracts and implementations. Keep dependencies +pointing from apps to features to packages, never back toward the app. + +## SOLID boundaries + +| Principle | Starter boundary | +| --- | --- | +| Single responsibility | `App` renders an injected router; bootstrap composes services; lifecycle handling owns foreground work. | +| Open/closed | Implement the client/provider contracts to swap a backend or add a feature without editing existing consumers. | +| Liskov substitution | Tests exercise fakes against the same contracts; core observers accept any `Logger`, not only Talker. | +| Interface segregation | Auth tokens, device identity, notification permission and notification delivery have separate contracts. | +| Dependency inversion | Clients accept their transport, SDK, logger and clock dependencies. Resolve the locator at composition boundaries. | + +The locator is a convenience at Flutter composition edges, not a requirement for +business logic. Prefer constructor injection in new services and repositories. +The container disposes dependents before dependencies and awaits async cleanup. +Only one component should own each subscription or disposable service. + +## Adding a feature + +1. Put behavior behind a small contract in the owning feature or shared package. +2. Inject its dependencies. Use an optional clock callback for time-sensitive behavior. +3. Write tests for success, invalid input, platform failure and lifecycle cleanup. +4. Expose feature routes and compose them in the app router. +5. Register implementations in bootstrap; keep registration separate from widget rendering. +6. Run `dart run melos run lint` and `dart run melos run coverage` before committing. + +```dart +abstract interface class GreetingRepository { + Future loadGreeting(); +} + +class LoadGreeting { + const LoadGreeting(this.repository); + final GreetingRepository repository; + + Future call() => repository.loadGreeting(); +} +``` + +Test `LoadGreeting` using a small fake repository. Test a real repository's adapter +with an injected transport rather than making live requests in unit tests. + +## Failure and privacy policy + +- HTTP failures stay typed; application-level error envelopes never masquerade as success. +- Automatic bearer headers stay on the configured API origin. One retry follows a shared token refresh; consumed streams are not replayed. +- SDK initialization is awaited. An unavailable optional Firebase configuration permits the starter demo to boot; emulator setup failures are surfaced. +- Analytics failures do not interrupt UI behavior. SDK state is not cached across DI resets. +- Network logs omit headers, query values and bodies. Auth success logs omit email addresses; add your own redaction rules for domain errors. +- Platform crash handlers are restored when their owning client is disposed. + +## What the tests do not replace + +100% line coverage measures execution, not every branch or possible input. Add +security rules tests, device tests, accessibility checks and backend integration +tests for your product. Configure provider credentials, privacy consent and native +permissions deliberately; a starter cannot choose these product policies for you. diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/lib/analytics/analytics.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/lib/analytics/analytics.dart index e19d0ba..7752e67 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/lib/analytics/analytics.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/lib/analytics/analytics.dart @@ -8,8 +8,7 @@ {{^analytics}}/// /// Analytics is not enabled in this project, so the log methods are no-ops. /// Wire them up by adding the `analytics` package back to `pubspec.yaml`. -{{/analytics}}class AuthAnalytics { - const AuthAnalytics._(); +{{/analytics}}abstract final class AuthAnalytics { /// 'google', 'apple' or 'email', derived from the signed-in provider. static String getAuthMethod(List? providerData) { diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/lib/auth.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/lib/auth.dart index 520383f..3c075e4 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/lib/auth.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/lib/auth.dart @@ -1,4 +1,5 @@ -import 'dart:io'; +import 'package:flutter/foundation.dart'; +import 'package:firebase_auth/firebase_auth.dart' show FirebaseAuth; import 'package:auth/config/config.dart'; import 'package:auth/data/index.dart'; @@ -9,6 +10,7 @@ import 'package:firebase_ui_oauth_apple/firebase_ui_oauth_apple.dart'; import 'package:firebase_ui_oauth_google/firebase_ui_oauth_google.dart'; {{#network}}import 'package:network/network.dart'; {{/network}} + export 'analytics/analytics.dart'; export 'config/index.dart'; export 'constants/index.dart'; @@ -20,21 +22,27 @@ export 'ui/screens/index.dart'; /// /// Call this after `Firebase.initializeApp` and before the router is built - /// route guards resolve [AuthService] from the locator on the first frame. -Future init(AuthConfig config) async { +Future init( + AuthConfig config, { + FirebaseAuth? firebaseAuth, + void Function(List)? configureProviders, +}) async { final logger = di.get(); logger.i('Initializing Auth...'); - FirebaseUIAuth.configureProviders([ + (configureProviders ?? FirebaseUIAuth.configureProviders)([ EmailAuthProvider(), GoogleProvider(clientId: config.clientId, iOSPreferPlist: true), - if (Platform.isIOS) AppleProvider(), + if (!kIsWeb && defaultTargetPlatform == TargetPlatform.iOS) AppleProvider(), ]); - di.register(AuthServiceImp()); -{{#network}} - // The network layer reads bearer tokens through this provider, so auth has + final sdk = firebaseAuth ?? FirebaseAuth.instance; + di.register(AuthServiceImp(firebaseAuth: sdk, logger: logger)); + +{{#network}} // The network layer reads bearer tokens through this provider, so auth has // to own it - registering it anywhere else risks a stale token on refresh. - di.register(FirebaseAuthTokenProvider()); -{{/network}} - logger.i('Auth initialized'); + final tokens = FirebaseAuthTokenProvider(firebaseAuth: sdk, logger: logger); + di.register(tokens, dispose: (_) => tokens.dispose()); + +{{/network}} logger.i('Auth initialized'); } diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/lib/constants/routes.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/lib/constants/routes.dart index 9289a7a..30f6003 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/lib/constants/routes.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/lib/constants/routes.dart @@ -1,6 +1,4 @@ -class AuthRoutes { - AuthRoutes._(); - +abstract final class AuthRoutes { static const String auth = '/auth'; static const String signIn = '$auth/sign-in'; diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/lib/data/services/auth_service_imp.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/lib/data/services/auth_service_imp.dart index 9c407ff..bdd477f 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/lib/data/services/auth_service_imp.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/lib/data/services/auth_service_imp.dart @@ -1,12 +1,15 @@ import 'package:auth/analytics/analytics.dart'; import 'package:auth/data/services/auth_service.dart'; import 'package:core/core.dart'; -import 'package:di/di.dart'; import 'package:firebase_auth/firebase_auth.dart'; class AuthServiceImp implements AuthService { - final _logger = di.get(); - final FirebaseAuth _firebaseAuth = FirebaseAuth.instance; + AuthServiceImp({required FirebaseAuth firebaseAuth, required Logger logger}) + : _firebaseAuth = firebaseAuth, + _logger = logger; + + final Logger _logger; + final FirebaseAuth _firebaseAuth; @override String get uid => _firebaseAuth.currentUser?.uid ?? ''; @@ -22,12 +25,12 @@ class AuthServiceImp implements AuthService { _logger.d('User signed out successfully'); // Log successful sign out - AuthAnalytics.logSignOutSuccess(); + await AuthAnalytics.logSignOutSuccess(); } catch (e, s) { _logger.e('Error signing out user: $e', e, s); // Log sign out error - AuthAnalytics.logSignOutError(errorMessage: e.toString()); + await AuthAnalytics.logSignOutError(errorMessage: e.toString()); rethrow; } diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/lib/data/token/firebase_auth_token_provider.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/lib/data/token/firebase_auth_token_provider.dart index 321743f..32ba980 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/lib/data/token/firebase_auth_token_provider.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/lib/data/token/firebase_auth_token_provider.dart @@ -1,163 +1,114 @@ {{#network}}import 'dart:async'; import 'package:core/core.dart'; -import 'package:di/di.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:network/network.dart'; -final _tag = 'FirebaseAuthTokenProvider'; - +/// Adapts Firebase tokens to the network contract and owns its subscription. class FirebaseAuthTokenProvider implements AuthTokenProvider { - FirebaseAuthTokenProvider() : _logger = di.get() { - _initializeTokenStream(); - } - - final FirebaseAuth _firebaseAuth = FirebaseAuth.instance; - final Logger _logger; - - late final StreamController _tokenController; - StreamSubscription? _authStateSubscription; - String? _cachedToken; - DateTime? _tokenExpiry; - - void _initializeTokenStream() { - _tokenController = StreamController.broadcast(); - - // Listen to auth state changes - _authStateSubscription = _firebaseAuth.authStateChanges().listen( - (User? user) async { - if (user != null) { - try { - final token = await user.getIdToken(); - _cachedToken = token; - _setTokenExpiry(token!); - _tokenController.add(token); - _logger.d('🔐$_tag: Auth token updated for user: ${user.uid}'); - } catch (e, s) { - _logger.e( - '🚨$_tag: Error getting token for user: ${user.uid}', - e, - s, - ); - _cachedToken = null; - _tokenExpiry = null; - _tokenController.add(null); - } - } else { - _cachedToken = null; - _tokenExpiry = null; - _tokenController.add(null); - _logger.d('🔓$_tag: User signed out, token cleared'); - } + FirebaseAuthTokenProvider({ + required FirebaseAuth firebaseAuth, + required Logger logger, + DateTime Function()? now, + }) : _auth = firebaseAuth, + _logger = logger, + _now = now ?? DateTime.now { + _subscription = _auth.idTokenChanges().listen( + (user) { + _revision++; + _publish(null); + if (user != null) unawaited(_readToken(user, force: false)); }, - onError: (e, s) { - _logger.e('🚨 $_tag: Auth state change error', e, s); - _tokenController.add(null); + onError: (Object error, StackTrace stackTrace) { + _revision++; + _publish(null); + _logger.e('Auth token stream failed', error, stackTrace); }, ); } - void _setTokenExpiry(String token) { - try { - // Firebase ID tokens are typically valid for 1 hour - // We'll refresh 5 minutes before expiry - _tokenExpiry = DateTime.now().add(const Duration(minutes: 55)); - } catch (e) { - _logger.w('⚠️$_tag: Could not determine token expiry, using default $e'); - _tokenExpiry = DateTime.now().add(const Duration(minutes: 55)); - } + final FirebaseAuth _auth; + final Logger _logger; + final DateTime Function() _now; + final _controller = StreamController.broadcast(); + late final StreamSubscription _subscription; + String? _token; + DateTime? _expiry; + int _revision = 0; + bool _disposed = false; + + void _publish(String? token, [DateTime? expiry]) { + if (_disposed) return; + _token = token; + _expiry = expiry; + _controller.add(token); } - @override - Future getValidToken() async { - final user = _firebaseAuth.currentUser; - if (user == null) { - _logger.d('🔓$_tag: No authenticated user available'); - return null; - } - - // Check if cached token is still valid - if (_cachedToken != null && !isTokenExpired) { - _logger.d('🔐$_tag: Using cached token'); - return _cachedToken; - } - - // Get fresh token + Future _readToken(User user, {required bool force}) async { + final revision = _revision; try { - _logger.d('🔄$_tag: Fetching fresh token for user: ${user.uid}'); - final token = await user.getIdToken(true); // Force refresh - _cachedToken = token; - _setTokenExpiry(token!); - _tokenController.add(token); - return token; - } catch (e, s) { - _logger.e('🚨$_tag: Error getting fresh token', e, s); - _cachedToken = null; - _tokenExpiry = null; + final result = await user.getIdTokenResult(force); + // A late refresh from an old session must never restore its token. + if (_disposed || + revision != _revision || + _auth.currentUser?.uid != user.uid) { + return null; + } + _publish(result.token, result.expirationTime); + return result.token; + } catch (error, stackTrace) { + if (!_disposed && revision == _revision) { + _publish(null); + _logger.e('Unable to read authentication token', error, stackTrace); + } return null; } } @override - String? getCurrentToken() { - return _cachedToken; + Future getValidToken() async { + final user = _auth.currentUser; + if (_disposed || user == null) return null; + if (_token != null && !isTokenExpired) return _token; + return _readToken(user, force: false); } @override - Stream get tokenStream => _tokenController.stream; + Future refreshToken() async { + final user = _auth.currentUser; + if (_disposed || user == null) return null; + return _readToken(user, force: true); + } @override - Future refreshToken() async { - final user = _firebaseAuth.currentUser; - if (user == null) { - _logger.w('🔓$_tag: Cannot refresh token - no authenticated user'); - return null; - } + String? getCurrentToken() => _token; - try { - _logger.d('🔄$_tag: Refreshing token for user: ${user.uid}'); - final token = await user.getIdToken(true); // Force refresh - _cachedToken = token; - _setTokenExpiry(token!); - _tokenController.add(token); - _logger.i('✅$_tag: Token refreshed successfully'); - return token; - } catch (e, s) { - _logger.e('🚨$_tag: Token refresh failed', e, s); - _cachedToken = null; - _tokenExpiry = null; - _tokenController.add(null); - return null; - } - } + @override + Stream get tokenStream => _controller.stream; @override - bool get isAuthenticated => _firebaseAuth.currentUser != null; + bool get isAuthenticated => !_disposed && _auth.currentUser != null; @override - bool get isTokenExpired { - if (_tokenExpiry == null) return true; - return DateTime.now().isAfter(_tokenExpiry!); - } + bool get isTokenExpired => + _expiry == null || + !_now().isBefore(_expiry!.subtract(const Duration(minutes: 5))); @override Future signOut() async { - try { - _logger.d('🔓$_tag: Signing out user'); - await _firebaseAuth.signOut(); - _cachedToken = null; - _tokenExpiry = null; - _tokenController.add(null); - _logger.i('✅$_tag: User signed out successfully'); - } catch (e, s) { - _logger.e('🚨$_tag: Error signing out user', e, s); - rethrow; - } + _revision++; + _publish(null); + await _auth.signOut(); } - void dispose() { - _authStateSubscription?.cancel(); - _tokenController.close(); - _logger.d('🧹$_tag: disposed'); + Future dispose() async { + if (_disposed) return; + _disposed = true; + _revision++; + _token = null; + _expiry = null; + await _subscription.cancel(); + await _controller.close(); } -}{{/network}} +} +{{/network}} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/lib/router/router.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/lib/router/router.dart index 5de29c6..86b63fb 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/lib/router/router.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/lib/router/router.dart @@ -39,9 +39,12 @@ final class GoAuthRoute extends GoRoute { required super.builder, List super.routes = const [], super.pageBuilder, + bool allowUnconfigured = false, }) : super( redirect: (context, state) async { - if (!di.has()) return null; + if (!di.has()) { + return allowUnconfigured ? null : AuthRoutes.signIn; + } final authService = di.get(); diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/lib/ui/components/header_builder.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/lib/ui/components/header_builder.dart index 80eed4c..c6f728b 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/lib/ui/components/header_builder.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/lib/ui/components/header_builder.dart @@ -12,29 +12,33 @@ Widget headerBuilder(BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(vertical: 24), - child: Column( - children: [ - Container( - height: 72, - width: 72, - decoration: BoxDecoration( - color: theme.colorScheme.primaryContainer, - borderRadius: BorderRadius.circular(20), + child: FittedBox( + fit: BoxFit.scaleDown, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + height: 72, + width: 72, + decoration: BoxDecoration( + color: theme.colorScheme.primaryContainer, + borderRadius: BorderRadius.circular(20), + ), + child: Icon( + Icons.bolt_outlined, + size: 40, + color: theme.colorScheme.onPrimaryContainer, + ), ), - child: Icon( - Icons.bolt_outlined, - size: 40, - color: theme.colorScheme.onPrimaryContainer, + const SizedBox(height: 16), + Text( + strings.app.name, + style: theme.textTheme.titleLarge?.copyWith( + fontWeight: FontWeight.bold, + ), ), - ), - const SizedBox(height: 16), - Text( - strings.app.name, - style: theme.textTheme.titleLarge?.copyWith( - fontWeight: FontWeight.bold, - ), - ), - ], + ], + ), ), ); } diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/lib/ui/screens/register_screen.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/lib/ui/screens/register_screen.dart index 67688ea..ccbaa9d 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/lib/ui/screens/register_screen.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/lib/ui/screens/register_screen.dart @@ -19,7 +19,7 @@ class RegisterScreen extends StatelessWidget { showAuthActionSwitch: false, actions: [ ui_auth.AuthStateChangeAction((context, state) async { - logger.d('User registered successfully: ${state.user?.email}'); + logger.d('User registered successfully'); final method = AuthAnalytics.getAuthMethod(state.user?.providerData); @@ -35,9 +35,7 @@ class RegisterScreen extends StatelessWidget { context, state, ) async { - logger.d( - 'User created successfully: ${state.credential.user?.email}', - ); + logger.d('User created successfully'); final method = AuthAnalytics.getAuthMethod( state.credential.user?.providerData, diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/lib/ui/screens/sign_in_screen.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/lib/ui/screens/sign_in_screen.dart index 13f00f3..0b530ad 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/lib/ui/screens/sign_in_screen.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/lib/ui/screens/sign_in_screen.dart @@ -25,7 +25,7 @@ class SignInScreen extends StatelessWidget { oauthButtonVariant: ui_auth.OAuthButtonVariant.icon_and_text, actions: [ ui_auth.ForgotPasswordAction((context, email) { - logger.d('Navigating to forgot password screen for email: $email'); + logger.d('Navigating to forgot password screen'); final uri = Uri( path: AuthRoutes.forgotPassword, @@ -34,7 +34,7 @@ class SignInScreen extends StatelessWidget { context.push(uri.toString()); }), ui_auth.AuthStateChangeAction((context, state) async { - logger.d('User signed in successfully: ${state.user?.email}'); + logger.d('User signed in successfully'); final method = AuthAnalytics.getAuthMethod(state.user?.providerData); @@ -50,9 +50,7 @@ class SignInScreen extends StatelessWidget { context, state, ) async { - logger.d( - 'User signed in successfully: ${state.credential.user?.email}', - ); + logger.d('User signed in successfully'); final method = AuthAnalytics.getAuthMethod( state.credential.user?.providerData, diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/pubspec.yaml b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/pubspec.yaml index 8c82322..d862aa5 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/pubspec.yaml +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/pubspec.yaml @@ -33,6 +33,7 @@ dependencies: path: ../../packages/analytics {{/analytics}} dev_dependencies: + mocktail: ^1.0.4 flutter_test: sdk: flutter flutter_lints: ^5.0.0 diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/test/auth_service_test.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/test/auth_service_test.dart new file mode 100644 index 0000000..314d9c1 --- /dev/null +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/test/auth_service_test.dart @@ -0,0 +1,63 @@ +import 'package:auth/auth.dart' as module; +import 'package:auth/data/services/auth_service_imp.dart'; +import 'package:core/core.dart'; +import 'package:di/di.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +{{#network}}import 'package:network/network.dart'; +{{/network}} + +class _Auth extends Mock implements FirebaseAuth {} + +class _User extends Mock implements User {} + +class _Logger extends Mock implements Logger {} + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + tearDown(di.reset); + test('service reads injected identity and awaits sign-out', () async { + final auth = _Auth(); + final user = _User(); + final service = AuthServiceImp(firebaseAuth: auth, logger: _Logger()); + when(() => auth.currentUser).thenReturn(user); + when(() => user.uid).thenReturn('test-user'); + when(auth.signOut).thenAnswer((_) async { + when(() => auth.currentUser).thenReturn(null); + }); + expect(service.uid, 'test-user'); + expect(service.isSignedIn, isTrue); + await service.signOut(); + expect(service.uid, isEmpty); + expect(service.isSignedIn, isFalse); + verify(auth.signOut).called(1); + }); + + test('SDK sign-out errors remain visible to the caller', () async { + final auth = _Auth(); + final error = FirebaseAuthException(code: 'network-request-failed'); + when(auth.signOut).thenThrow(error); + final service = AuthServiceImp(firebaseAuth: auth, logger: _Logger()); + await expectLater(service.signOut(), throwsA(same(error))); + }); + + test( + 'module composes injected SDK and disposes owned token provider', + () async { + di.register(_Logger()); + final auth = _Auth(); + when(auth.idTokenChanges).thenAnswer((_) => const Stream.empty()); + await module.init( + module.DefaultAuthConfig(clientId: 'client-id'), + firebaseAuth: auth, + configureProviders: (providers) => + expect(providers.length, greaterThanOrEqualTo(2)), + ); + expect(di.get(), isA()); +{{#network}} final tokens = di.get(); + await di.reset(); + expect(tokens.isAuthenticated, isFalse);{{/network}} + }, + ); +} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/test/presentation_test.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/test/presentation_test.dart new file mode 100644 index 0000000..4ad7db0 --- /dev/null +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/test/presentation_test.dart @@ -0,0 +1,219 @@ +import 'package:auth/auth.dart'; +import 'package:auth/ui/components/footer_builder.dart'; +import 'package:core/core.dart' as core; +import 'package:di/di.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:firebase_ui_auth/firebase_ui_auth.dart' as ui; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:go_router/go_router.dart'; +import 'package:mocktail/mocktail.dart'; + +class _User extends Mock implements User {} + +class _UserInfo extends Mock implements UserInfo {} + +class _Credential extends Mock implements UserCredential {} + +class _AuthService extends Mock implements AuthService {} + +void main() { + setUp(core.init); + tearDown(di.reset); + + test( + 'provider analytics handles every supported method and empty identities', + () async { + expect(AuthAnalytics.getAuthMethod(null), 'email'); + expect(AuthAnalytics.getAuthMethod([]), 'email'); + for (final provider in ['google.com', 'apple.com', 'password']) { + final info = _UserInfo(); + when(() => info.providerId).thenReturn(provider); + expect( + AuthAnalytics.getAuthMethod([info]), + provider == 'password' ? 'email' : provider.split('.').first, + ); + } + await AuthAnalytics.logSignInSuccess( + method: 'email', + userEmail: 'person@example.test', + ); + await AuthAnalytics.logSignUpSuccess(method: 'email'); + await AuthAnalytics.logUserCreationSuccess(method: 'email'); + await AuthAnalytics.logAuthError(errorType: 'test', flowType: 'sign_in'); + await AuthAnalytics.logSignOutError(errorMessage: 'test'); + await AuthAnalytics.logSignOutSuccess(); + }, + ); + + testWidgets( + 'auth screen adapters wire headers, footers and SDK state actions', + (tester) async { + late BuildContext context; + final router = GoRouter( + routes: [ + GoRoute( + path: '/', + builder: (ctx, _) { + context = ctx; + return const SizedBox(); + }, + ), + GoRoute( + path: AuthRoutes.forgotPassword, + builder: (_, state) => + Text(state.uri.queryParameters['email'] ?? ''), + ), + GoRoute( + path: AuthRoutes.signIn, + builder: (_, _) => const Text('sign-in route'), + ), + GoRoute( + path: AuthRoutes.signUp, + builder: (_, _) => const Text('sign-up route'), + ), + ], + ); + addTearDown(router.dispose); + await tester.pumpWidget(MaterialApp.router(routerConfig: router)); + await tester.pumpAndSettle(); + var signedIn = 0; + var signedUp = 0; + final routes = AuthRouter( + onSignedIn: (_) {}, + onSignedUp: (_) {}, + ).routes.whereType().toList(); + final state = GoRouterState.of(context); + expect(routes[0].builder!(context, state), isA()); + expect(routes[1].builder!(context, state), isA()); + expect( + (routes[2].builder!(context, state) as ForgotPasswordScreen).email, + isNull, + ); + final signIn = + SignInScreen(onSignedIn: (_) => signedIn++).build(context) + as ui.SignInScreen; + final register = + RegisterScreen(onSignedUp: (_) => signedUp++).build(context) + as ui.RegisterScreen; + final recovery = + const ForgotPasswordScreen( + email: 'person@example.test', + ).build(context) + as ui.ForgotPasswordScreen; + expect(recovery.email, 'person@example.test'); + final user = _User(); + final credential = _Credential(); + when(() => user.providerData).thenReturn([]); + when(() => user.email).thenReturn('person@example.test'); + when(() => credential.user).thenReturn(user); + for (final actions in [signIn.actions, register.actions!]) { + actions + .whereType>() + .single + .invoke(context, ui.SignedIn(user)); + actions + .whereType>() + .single + .invoke(context, ui.UserCreated(credential)); + actions + .whereType>() + .single + .invoke(context, ui.AuthFailed(Exception('test'))); + } + await tester.pump(); + expect(signedIn, 2); + expect(signedUp, 2); + signIn.actions.whereType().single.callback( + context, + 'person@example.test', + ); + await tester.pumpAndSettle(); + expect(find.text('person@example.test'), findsOneWidget); + router.pop(); + await tester.pumpAndSettle(); + // Validate our builders independently of Firebase UI's platform implementation. + final widgets = [ + signIn.headerBuilder!(context, const BoxConstraints(), 0), + register.headerBuilder!(context, const BoxConstraints(), 0), + recovery.headerBuilder!(context, const BoxConstraints(), 0), + signIn.footerBuilder!(context, ui.AuthAction.signIn), + register.footerBuilder!(context, ui.AuthAction.signUp), + ]; + for (final widget in widgets) { + await tester.pumpWidget(MaterialApp(home: Scaffold(body: widget))); + expect(tester.takeException(), isNull); + } + await tester.pumpWidget(const SizedBox()); + await tester.pump(const Duration(seconds: 5)); + }, + ); + + for (final signedIn in [null, false, true]) { + testWidgets('route guard handles registered identity $signedIn', ( + tester, + ) async { + if (signedIn != null) { + final service = _AuthService(); + when(() => service.isSignedIn).thenReturn(signedIn); + di.register(service); + } + final router = GoRouter( + initialLocation: '/private', + routes: [ + GoAuthRoute( + path: '/private', + builder: (_, _) => const Text('private'), + ), + GoRoute( + path: AuthRoutes.signIn, + builder: (_, _) => const Text('login'), + ), + ], + ); + addTearDown(router.dispose); + await tester.pumpWidget(MaterialApp.router(routerConfig: router)); + await tester.pumpAndSettle(); + expect(find.text(signedIn == true ? 'private' : 'login'), findsOneWidget); + }); + } + + testWidgets('footers navigate to the opposite authentication route', ( + tester, + ) async { + for (final type in FooterType.values) { + final router = GoRouter( + routes: [ + GoRoute( + path: '/', + builder: (context, _) => Scaffold( + body: footerBuilder(context, ui.AuthAction.signIn, type), + ), + ), + GoRoute( + path: AuthRoutes.signIn, + builder: (_, _) => const Text('login destination'), + ), + GoRoute( + path: AuthRoutes.signUp, + builder: (_, _) => const Text('register destination'), + ), + ], + ); + await tester.pumpWidget(MaterialApp.router(routerConfig: router)); + await tester.pumpAndSettle(); + await tester.tap(find.byType(GestureDetector).last); + await tester.pumpAndSettle(); + expect( + find.text( + type == FooterType.signIn + ? 'register destination' + : 'login destination', + ), + findsOneWidget, + ); + await tester.pumpWidget(const SizedBox()); + router.dispose(); + } + }); +} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/test/{{auth_token_provider_test_file}} b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/test/{{auth_token_provider_test_file}} new file mode 100644 index 0000000..fd7c3b2 --- /dev/null +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{auth_dir}}/test/{{auth_token_provider_test_file}} @@ -0,0 +1,146 @@ +import 'dart:async'; + +import 'package:auth/data/token/firebase_auth_token_provider.dart'; +import 'package:core/core.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; + +class _Auth extends Mock implements FirebaseAuth {} + +class _User extends Mock implements User {} + +class _Token extends Mock implements IdTokenResult {} + +class _Logger extends Mock implements Logger {} + +void main() { + late _Auth auth; + late _User user; + late _Logger logger; + late _Token token; + late StreamController events; + late FirebaseAuthTokenProvider provider; + late DateTime now; + + setUp(() { + auth = _Auth(); + user = _User(); + token = _Token(); + logger = _Logger(); + now = DateTime(2026); + events = StreamController(); + when(auth.idTokenChanges).thenAnswer((_) => events.stream); + when(() => auth.currentUser).thenReturn(user); + when(() => user.uid).thenReturn('user-1'); + when(() => token.token).thenReturn('test-token'); + when( + () => token.expirationTime, + ).thenReturn(now.add(const Duration(hours: 1))); + when(() => user.getIdTokenResult(any())).thenAnswer((_) async => token); + when(auth.signOut).thenAnswer((_) async {}); + provider = FirebaseAuthTokenProvider( + firebaseAuth: auth, + logger: logger, + now: () => now, + ); + }); + tearDown(() async { + await provider.dispose(); + await events.close(); + }); + + test('Firebase expiration controls cached-token reuse and refresh', () async { + expect(provider.isTokenExpired, isTrue); + expect(provider.isAuthenticated, isTrue); + expect(await provider.getValidToken(), 'test-token'); + expect(provider.getCurrentToken(), 'test-token'); + expect(provider.isTokenExpired, isFalse); + expect(await provider.getValidToken(), 'test-token'); + verify(() => user.getIdTokenResult(false)).called(1); + now = now.add(const Duration(minutes: 55)); + expect(provider.isTokenExpired, isTrue); + await provider.getValidToken(); + verify(() => user.getIdTokenResult(false)).called(1); + await provider.refreshToken(); + verify(() => user.getIdTokenResult(true)).called(1); + }); + + test('signed-out users have no token', () async { + when(() => auth.currentUser).thenReturn(null); + expect(provider.isAuthenticated, isFalse); + expect(await provider.getValidToken(), isNull); + expect(await provider.refreshToken(), isNull); + }); + + test('token events publish refreshed tokens and clear on sign-out', () async { + final values = []; + final subscription = provider.tokenStream.listen(values.add); + events.add(user); + await pumpEventQueue(); + expect(values, [null, 'test-token']); + when(() => auth.currentUser).thenReturn(null); + events.add(null); + await pumpEventQueue(); + expect(provider.getCurrentToken(), isNull); + expect(values.last, isNull); + await subscription.cancel(); + }); + + test('read and stream errors clear cached credentials', () async { + await provider.getValidToken(); + when( + () => user.getIdTokenResult(any()), + ).thenThrow(StateError('unavailable')); + expect(await provider.refreshToken(), isNull); + expect(provider.getCurrentToken(), isNull); + events.addError(StateError('stream failure'), StackTrace.current); + await pumpEventQueue(); + expect(provider.isTokenExpired, isTrue); + }); + + test( + 'sign-out clears credentials and late refreshes cannot restore them', + () async { + final pending = Completer(); + when( + () => user.getIdTokenResult(any()), + ).thenAnswer((_) => pending.future); + final refresh = provider.refreshToken(); + await provider.signOut(); + pending.complete(token); + expect(await refresh, isNull); + expect(provider.getCurrentToken(), isNull); + verify(auth.signOut).called(1); + }, + ); + + test('an account change invalidates an in-flight response', () async { + final pending = Completer(); + when(() => user.getIdTokenResult(any())).thenAnswer((_) => pending.future); + final refresh = provider.refreshToken(); + when(() => auth.currentUser).thenReturn(null); + pending.complete(token); + expect(await refresh, isNull); + }); + + test('disposing during refresh closes safely and is idempotent', () async { + final pending = Completer(); + when(() => user.getIdTokenResult(any())).thenAnswer((_) => pending.future); + final refresh = provider.refreshToken(); + await provider.dispose(); + pending.completeError(StateError('late error')); + expect(await refresh, isNull); + expect(provider.isAuthenticated, isFalse); + expect(await provider.getValidToken(), isNull); + expect(await provider.refreshToken(), isNull); + await provider.dispose(); + }); + + test('null token results do not throw', () async { + when(() => token.token).thenReturn(null); + when(() => token.expirationTime).thenReturn(null); + expect(await provider.getValidToken(), isNull); + expect(provider.isTokenExpired, isTrue); + }); +} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{dashboard_dir}}/lib/router/dashboard_router.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{dashboard_dir}}/lib/router/dashboard_router.dart index 1c08705..e589437 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{dashboard_dir}}/lib/router/dashboard_router.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{dashboard_dir}}/lib/router/dashboard_router.dart @@ -2,15 +2,15 @@ {{/auth}}import 'package:dashboard/ui/screens/index.dart'; import 'package:go_router/go_router.dart'; -{{#auth}}/// Every shell branch is guarded - unauthenticated users bounce to sign-in. +{{#auth}}/// Demo content is available before Firebase configuration; configured apps +/// require a signed-in identity. Do not enable this bypass for protected data. typedef _ShellRoute = auth.GoAuthRoute;{{/auth}}{{^auth}}typedef _ShellRoute = GoRoute;{{/auth}} /// Bottom-navigation shell for the signed-in part of the app. /// /// Add a tab by adding a [StatefulShellBranch] here and a destination in /// [DashboardShellScreen]. -class DashboardRouter { - const DashboardRouter._(); +abstract final class DashboardRouter { static const String home = '/home/dashboard'; static const String explore = '/home/explore'; @@ -24,7 +24,8 @@ class DashboardRouter { StatefulShellBranch( routes: [ _ShellRoute( - path: home, +{{#auth}} allowUnconfigured: true, +{{/auth}} path: home, builder: (context, state) => const HomeTabScreen(), ), ], @@ -32,7 +33,8 @@ class DashboardRouter { StatefulShellBranch( routes: [ _ShellRoute( - path: explore, +{{#auth}} allowUnconfigured: true, +{{/auth}} path: explore, builder: (context, state) => const ExploreTabScreen(), ), ], @@ -40,7 +42,8 @@ class DashboardRouter { StatefulShellBranch( routes: [ _ShellRoute( - path: profile, +{{#auth}} allowUnconfigured: true, +{{/auth}} path: profile, builder: (context, state) => const ProfileTabScreen(), ), ], diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{dashboard_dir}}/test/dashboard_test.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{dashboard_dir}}/test/dashboard_test.dart new file mode 100644 index 0000000..8324844 --- /dev/null +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/features/{{dashboard_dir}}/test/dashboard_test.dart @@ -0,0 +1,97 @@ +{{#auth}}import 'package:auth/auth.dart' as auth; +{{/auth}} +import 'package:core/core.dart' as core; +import 'package:dashboard/dashboard.dart'; +import 'package:di/di.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:go_router/go_router.dart'; +import 'package:localization/localization.dart'; + +{{#auth}}class _Auth implements auth.AuthService { + int signOuts = 0; + @override + String get uid => 'test'; + @override + bool get isSignedIn => true; + @override + Future signOut() async { + signOuts++; + } +} + +{{/auth}}void main() { + setUp(core.init); + tearDown(di.reset); + + testWidgets('tabs navigate and profile sign-out requires confirmation', ( + tester, + ) async { +{{#auth}} final service = _Auth(); + di.register(service); +{{/auth}} final router = GoRouter( + initialLocation: DashboardRouter.home, + routes: [ + DashboardRouter.createShellRoute(), +{{#auth}} GoRoute( + path: auth.AuthRoutes.signIn, + builder: (_, _) => const Text('Signed out'), + ), +{{/auth}} ], + ); + addTearDown(router.dispose); + await tester.pumpWidget(MaterialApp.router(routerConfig: router)); + await tester.pumpAndSettle(); + expect( + router.routeInformationProvider.value.uri.path, + DashboardRouter.home, + ); + await tester.tap(find.text('Explore').last); + await tester.pumpAndSettle(); + expect( + router.routeInformationProvider.value.uri.path, + DashboardRouter.explore, + ); + await tester.tap(find.text(strings.nav.profile).last); + await tester.pumpAndSettle(); + expect( + router.routeInformationProvider.value.uri.path, + DashboardRouter.profile, + ); + await tester.tap(find.text(strings.profile.settings)); +{{#auth}} await tester.tap(find.text(strings.auth.sign_out)); + await tester.pumpAndSettle(); + await tester.tap(find.text(strings.generic.cancel)); + await tester.pumpAndSettle(); + expect(service.signOuts, 0); + await tester.tap(find.text(strings.auth.sign_out)); + await tester.pumpAndSettle(); + await tester.tap(find.widgetWithText(FilledButton, strings.auth.sign_out)); + await tester.pumpAndSettle(); + expect(service.signOuts, 1); + expect(find.text('Signed out'), findsOneWidget); +{{/auth}} }); + + testWidgets('placeholder supports an action', (tester) async { + var calls = 0; + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: PlaceholderTab( + icon: Icons.add, + title: 'Title', + subtitle: 'Subtitle', + action: TextButton( + onPressed: () { + calls++; + }, + child: const Text('Start'), + ), + ), + ), + ), + ); + await tester.tap(find.text('Start')); + expect(calls, 1); + }); +} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/melos.yaml b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/melos.yaml index 338f220..5814dac 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/melos.yaml +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/melos.yaml @@ -35,16 +35,8 @@ scripts: flutter: true lint: - description: "Run format and analyze all packages" - # `dart format` has no exclude of its own, so build output and the plugin - # sources CocoaPods symlinks into the app are filtered out here. - run: | - find . -name '*.dart' -not -path '*/build/*' -not -path '*/.dart_tool/*' \ - -not -path '*/.symlinks/*' -exec dart format --set-exit-if-changed {} + && - dart analyze --fatal-infos . - exec: - concurrency: 5 - failFast: true + description: "Check formatting and analyze all workspace code" + run: dart run tool/check.dart fix: description: "Apply Dart automated fixes to all packages" @@ -82,7 +74,11 @@ scripts: test: description: "Run all tests (Dart and Flutter)" - run: melos run test:select --no-select + run: dart run melos run test:select --no-select + + coverage: + description: "Run every test and require 100% handwritten line coverage" + run: dart run tool/coverage.dart test:select: description: "Run tests in Flutter packages" diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/lib/constants/defaults.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/lib/constants/defaults.dart index 9ca3832..c7961c2 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/lib/constants/defaults.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/lib/constants/defaults.dart @@ -1,6 +1,4 @@ /// App-wide default values. -class Defaults { - Defaults._(); - +abstract final class Defaults { static const int defaultPageSize = 20; } diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/lib/constants/environment.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/lib/constants/environment.dart index 205f857..ebbd718 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/lib/constants/environment.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/lib/constants/environment.dart @@ -6,9 +6,7 @@ /// ```sh /// flutter run --dart-define=BASE_URL=https://staging.example.com /// ``` -class Environment { - Environment._(); - +abstract final class Environment { static const bool useEmulators = bool.fromEnvironment('USE_EMULATORS'); static const String baseUrl = String.fromEnvironment( diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/lib/constants/keys.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/lib/constants/keys.dart index 2faa261..dd8685f 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/lib/constants/keys.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/lib/constants/keys.dart @@ -1,9 +1,7 @@ /// Query-parameter and `extra` keys shared between routers and screens. /// /// Keep these here rather than inline so a rename is a single edit. -class Keys { - Keys._(); - +abstract final class Keys { static const String email = 'email'; static const String title = 'title'; static const String message = 'message'; diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/lib/constants/routes.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/lib/constants/routes.dart index 51921d5..03f0293 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/lib/constants/routes.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/lib/constants/routes.dart @@ -2,9 +2,7 @@ /// /// Feature packages declare their own route constants; these are the ones /// every app has. -class CoreRoutes { - CoreRoutes._(); - +abstract final class CoreRoutes { static const String root = '/'; static const String home = '/home'; static const String dashboard = '/home/dashboard'; diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/lib/converters/datetime_converter.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/lib/converters/datetime_converter.dart index 7c477d7..76d3729 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/lib/converters/datetime_converter.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/lib/converters/datetime_converter.dart @@ -1,8 +1,6 @@ import 'package:intl/intl.dart'; -final class DateTimeConverter { - const DateTimeConverter(); - +abstract final class DateTimeConverter { /// Converts a [DateTime] to a [String] in the format 'MMMM d, y'. /// If the [date] is null, it returns an empty string. /// diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/lib/developer/emulators.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/lib/developer/emulators.dart index 9586507..8400d9b 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/lib/developer/emulators.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/lib/developer/emulators.dart @@ -1,25 +1,28 @@ -{{#firebase}}{{#auth}}import 'package:firebase_auth/firebase_auth.dart'; +{{#emulators}}{{#auth}}import 'package:firebase_auth/firebase_auth.dart'; {{/auth}}{{#firestore}}import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:cloud_functions/cloud_functions.dart'; {{/firestore}}import 'package:core/logger/logger.dart'; import 'package:di/di.dart'; +import 'package:flutter/foundation.dart'; /// Points every Firebase SDK at the local emulator suite. /// /// Ports match the defaults in `firebase.json`; change both together. -Future init() async { +Future init({String? host}) async { final logger = di.get(); + final emulatorHost = host ?? (!kIsWeb && defaultTargetPlatform == TargetPlatform.android ? '10.0.2.2' : 'localhost'); logger.i('Using Firebase emulators'); try { -{{#auth}} await FirebaseAuth.instance.useAuthEmulator('localhost', 9099); -{{/auth}}{{#firestore}} FirebaseFirestore.instance.useFirestoreEmulator('localhost', 8080); - FirebaseFunctions.instance.useFunctionsEmulator('localhost', 5001); +{{#auth}} await FirebaseAuth.instance.useAuthEmulator(emulatorHost, 9099); +{{/auth}}{{#firestore}} FirebaseFirestore.instance.useFirestoreEmulator(emulatorHost, 8080); + FirebaseFunctions.instance.useFunctionsEmulator(emulatorHost, 5001); {{/firestore}} logger.i('Successfully initialised the Firebase emulators'); } catch (error, stackTrace) { logger.e('Failed to initialise the Firebase emulators:', error, stackTrace); + rethrow; } } -{{/firebase}}{{^firebase}}/// No Firebase services are enabled in this project, so there is nothing to +{{/emulators}}{{^emulators}}/// No Firebase services are enabled in this project, so there is nothing to /// point at an emulator. Kept as a no-op so bootstrap stays uniform. -Future init() async {} -{{/firebase}} \ No newline at end of file +Future init({String? host}) async {} +{{/emulators}} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/lib/observer/core_bloc_observer.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/lib/observer/core_bloc_observer.dart index 1de8928..695f29e 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/lib/observer/core_bloc_observer.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/lib/observer/core_bloc_observer.dart @@ -1,34 +1,29 @@ import 'package:bloc/bloc.dart'; import 'package:core/core.dart'; import 'package:di/di.dart'; -import 'package:talker_bloc_logger/talker_bloc_logger_observer.dart'; -import 'package:talker_bloc_logger/talker_bloc_logger_settings.dart'; -import 'package:talker_flutter/talker_flutter.dart'; class CoreBlocObserver extends BlocObserver { - final TalkerBlocObserver _observer; + final Logger _logger; - CoreBlocObserver() - : _observer = TalkerBlocObserver( - talker: di.get().logger as Talker, - settings: TalkerBlocLoggerSettings(printEventFullData: true), - ); + CoreBlocObserver({Logger? logger}) : _logger = logger ?? di.get(); @override void onEvent(Bloc bloc, Object? event) { super.onEvent(bloc, event); - _observer.onEvent(bloc, event); + _logger.d('${bloc.runtimeType}: event ${event.runtimeType}'); } @override void onTransition(Bloc bloc, Transition transition) { super.onTransition(bloc, transition); - _observer.onTransition(bloc, transition); + _logger.d( + '${bloc.runtimeType}: ${transition.currentState.runtimeType} -> ${transition.nextState.runtimeType}', + ); } @override void onError(BlocBase bloc, Object error, StackTrace stackTrace) { super.onError(bloc, error, stackTrace); - _observer.onError(bloc, error, stackTrace); + _logger.e('${bloc.runtimeType}: unhandled error', error, stackTrace); } } diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/lib/observer/core_route_observer.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/lib/observer/core_route_observer.dart index 776e95c..f09a084 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/lib/observer/core_route_observer.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/lib/observer/core_route_observer.dart @@ -1,13 +1,12 @@ import 'package:core/core.dart'; import 'package:di/di.dart'; import 'package:flutter/material.dart'; -import 'package:navigation_history_observer/navigation_history_observer.dart'; import 'package:talker_flutter/talker_flutter.dart'; class CoreRouteObserver extends NavigatorObserver { - CoreRouteObserver() : _observer = di.get().logger as Talker; + CoreRouteObserver({Logger? logger}) : _logger = logger ?? di.get(); - final Talker _observer; + final Logger _logger; @override void didPush(Route route, Route? previousRoute) { @@ -15,7 +14,7 @@ class CoreRouteObserver extends NavigatorObserver { if (route.settings.name == null) { return; } - _observer.logCustom(TalkerRouteLog(route: route, type: RouteLogType.push)); + _logger.d(TalkerRouteLog._createMessage(route, RouteLogType.push)); } @override @@ -24,7 +23,7 @@ class CoreRouteObserver extends NavigatorObserver { if (route.settings.name == null) { return; } - _observer.logCustom(TalkerRouteLog(route: route, type: RouteLogType.pop)); + _logger.d(TalkerRouteLog._createMessage(route, RouteLogType.pop)); } @override @@ -33,9 +32,7 @@ class CoreRouteObserver extends NavigatorObserver { if (route.settings.name == null) { return; } - _observer.logCustom( - TalkerRouteLog(route: route, type: RouteLogType.remove), - ); + _logger.d(TalkerRouteLog._createMessage(route, RouteLogType.remove)); } @override @@ -44,9 +41,7 @@ class CoreRouteObserver extends NavigatorObserver { if (newRoute?.settings.name == null) { return; } - _observer.logCustom( - TalkerRouteLog(route: newRoute!, type: RouteLogType.replace), - ); + _logger.d(TalkerRouteLog._createMessage(newRoute!, RouteLogType.replace)); } } @@ -68,22 +63,6 @@ class TalkerRouteLog extends TalkerLog { buffer.write(' route named '); buffer.write(route.settings.name ?? 'null'); - final args = route.settings.arguments; - if (args != null) { - buffer.write('\nArguments: $args'); - } - - final historyObserver = NavigationHistoryObserver(); - final history = historyObserver.history; - if (history.isEmpty) { - buffer.write('\nHistory: na'); - } else { - final historyAsString = historyObserver.history - .map((r) => r.settings.name) - .join(' -> '); - buffer.write('\nHistory: $historyAsString'); - } - return buffer.toString(); } } diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/pubspec.yaml b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/pubspec.yaml index 2076f23..a87edca 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/pubspec.yaml +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/pubspec.yaml @@ -16,8 +16,6 @@ dependencies: go_router: ^15.1.3 intl: ^0.20.2 json_annotation: ^4.9.0 - navigation_history_observer: ^1.1.1 - talker_bloc_logger: ^4.9.1 talker_flutter: ^4.4.1 di: path: ../di diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/test/core_test.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/test/core_test.dart new file mode 100644 index 0000000..b4ed6c9 --- /dev/null +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/core/test/core_test.dart @@ -0,0 +1,206 @@ +import 'package:core/developer/emulators.dart' as emulators; +{{#firestore}}import 'package:cloud_firestore/cloud_firestore.dart'; +{{/firestore}} +import 'package:core/core.dart'; +import 'package:core/logger/talker_logger_impl.dart'; +import 'package:di/di.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:talker_flutter/talker_flutter.dart' hide TalkerRouteLog; + +class _Counter extends Bloc { + _Counter() : super(0) { + on((event, emit) => emit(event)); + } +} + +void main() { +{{#emulators}} test('emulator setup failures are surfaced before Firebase initialization', () async { + await expectLater(emulators.init(), throwsA(anything)); + }); +{{/emulators}} +{{^emulators}} test('emulator setup is a no-op without emulated services', emulators.init); +{{/emulators}} + setUp(init); + tearDown(di.reset); + + test( + 'event base defines value equality and DI exposes its configured container', + () { + final event = RefreshProfile(); + expect(event.props, isEmpty); + expect(event, RefreshProfile()); + expect(di.getIt.isRegistered(), isTrue); + }, + ); + + testWidgets('context event extension broadcasts to the owned channel', ( + tester, + ) async { + late BuildContext context; + await tester.pumpWidget( + GlobalEventChannelProvider( + child: Builder( + builder: (ctx) { + context = ctx; + return const SizedBox(); + }, + ), + ), + ); + context.fire(const RefreshProfile()); + await tester.pump(); + expect( + context.read().state.current, + const RefreshProfile(), + ); + }); + + test('event channel bounds history while retaining total counts', () async { + final channel = GlobalEventChannel(maxRecentEvents: 2); + final states = []; + final subscription = channel.stream.listen(states.add); + for (var i = 0; i < 3; i++) { + channel.add(const FireGlobalEvent(eventType: RefreshProfile())); + } + await pumpEventQueue(); + expect(states, hasLength(3)); + expect(channel.state.history, hasLength(2)); + expect(channel.state.eventCounts[RefreshProfile], 3); + expect(channel.state.current, const RefreshProfile()); + expect(channel.state.copyWith(), channel.state); + expect(channel.state.copyWith(maxRecentEvents: 9).maxRecentEvents, 9); + expect(const FireGlobalEvent(eventType: RefreshProfile()).props, [ + const RefreshProfile(), + ]); + await subscription.cancel(); + await channel.close(); + }); + + testWidgets( + 'provider, builder, listener and consumer share the event channel', + (tester) async { + var listeners = 0; + await tester.pumpWidget( + MaterialApp( + home: GlobalEventChannelProvider( + lazy: false, + child: GlobalEventChannelListener( + listener: (_, state) { + listeners++; + }, + child: GlobalEventChannelConsumer( + listener: (_, state) { + listeners++; + }, + builder: (_, state) => GlobalEventChannelBuilder( + builder: (_, state) => + Text('Events: ${state.history.length}'), + ), + ), + ), + ), + ), + ); + expect(find.text('Events: 0'), findsOneWidget); + BlocProvider.of( + tester.element(find.text('Events: 0')), + ).add(const FireGlobalEvent(eventType: RefreshProfile())); + await tester.pumpAndSettle(); + expect(find.text('Events: 1'), findsOneWidget); + expect(listeners, 2); + await tester.pumpWidget(const SizedBox()); + }, + ); + + test('date and string helpers handle null and valid input', () { + final date = DateTime(2026, 1, 15, 13, 14, 15); + expect(DateTimeConverter.toViewFormat(null), ''); + expect(DateTimeConverter.toViewFormat(date), 'January 15, 2026'); + expect(DateTimeConverter.toViewFormatWithTime(null), ''); + expect( + DateTimeConverter.toViewFormatWithTime(date), + 'January 15, 2026, 1:14 PM', + ); + expect(DateTimeConverter.toViewFormatTime(null), ''); + expect(DateTimeConverter.toViewFormatTime(date), '1:14:15 PM'); + expect((null as String?).asBool, isFalse); + for (final value in ['TRUE', 'true', '1']) { + expect(value.asBool, isTrue); + } + expect('false'.asBool, isFalse); + expect(CoreException(message: 'message').message, 'message'); + expect(UserNotFoundException().message, isNotEmpty); + }); + + test( + 'timestamp adapters accept documented forms and reject invalid shapes', + () { + // Exercise runtime construction as well as annotation-style const use. + // ignore: prefer_const_constructors + final converter = TimestampConverter(); + // ignore: prefer_const_constructors + final nullable = TimestampConverterNullable(); + final date = DateTime.utc(2026); + expect(converter.fromJson(date.toIso8601String()).toUtc(), date); +{{#firestore}} expect(converter.fromJson(Timestamp.fromDate(date)).toUtc(), date); +{{/firestore}} + expect( + converter.fromJson({ + '_seconds': 1, + '_nanoseconds': 500000000, + }).millisecondsSinceEpoch, + 1500, + ); + expect(converter.toJson(date), date.toIso8601String()); + expect(converter.toJson(null), isNull); + expect(nullable.fromJson(null), isNull); + expect(nullable.toJson(null), isNull); + expect(nullable.toJson(date), date.toIso8601String()); + expect(() => converter.fromJson(null), throwsArgumentError); + }, + ); + + test('logger forwards every level and exposes its adapter', () { + final talker = Talker(settings: TalkerSettings(useConsoleLogs: false)); + final logger = TalkerLoggerImpl(talker); + logger.d('debug'); + logger.i('info'); + logger.w('warning'); + logger.e('error'); + expect(logger.logger, same(talker)); + expect(talker.history, hasLength(4)); + }); + + test( + 'observers support event, transition, error and route lifecycles', + () async { + final bloc = _Counter(); + final observer = CoreBlocObserver(); + observer.onEvent(bloc, 1); + observer.onTransition( + bloc, + const Transition(currentState: 0, event: 1, nextState: 1), + ); + observer.onError(bloc, StateError('test'), StackTrace.current); + final routes = CoreRouteObserver(); + final named = MaterialPageRoute( + builder: (_) => const SizedBox(), + settings: const RouteSettings(name: '/test', arguments: 'arg'), + ); + final unnamed = MaterialPageRoute(builder: (_) => const SizedBox()); + for (final route in [named, unnamed]) { + routes.didPush(route, null); + routes.didPop(route, null); + routes.didRemove(route, null); + routes.didReplace(newRoute: route); + } + routes.didReplace(); + final log = TalkerRouteLog(route: unnamed, type: RouteLogType.push); + expect(log.key, TalkerLogType.route.key); + expect(log.pen, isA()); + await bloc.close(); + }, + ); +} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/design_system/lib/components/auth_headers_builder.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/design_system/lib/components/auth_headers_builder.dart index 09d09e4..5b40857 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/design_system/lib/components/auth_headers_builder.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/design_system/lib/components/auth_headers_builder.dart @@ -3,114 +3,90 @@ import 'package:di/di.dart'; import 'package:flutter/material.dart'; import 'package:network/network.dart'; -/// A widget that provides authentication headers to its child builder. -/// -/// This widget automatically fetches the current authentication token -/// using the [AuthTokenProvider] from dependency injection and constructs -/// HTTP headers with the Bearer token. -/// -/// Example usage: -/// ```dart -/// // Without token validation (default - faster, uses cached token) -/// AuthHeadersBuilder( -/// builder: (context, headers) { -/// return CachedNetworkImage( -/// imageUrl: imageUrl, -/// httpHeaders: headers, -/// ); -/// }, -/// ) -/// -/// // With token validation (ensures fresh token) -/// AuthHeadersBuilder(d -/// validateToken: true, -/// builder: (context, headers) { -/// return CachedNetworkImage( -/// imageUrl: imageUrl, -/// httpHeaders: headers, -/// ); -/// }, -/// ) -/// ``` -class AuthHeadersBuilder extends StatelessWidget { - static final _logger = di.get(); - - /// Creates an [AuthHeadersBuilder]. - /// - /// The [builder] function is called with the current [BuildContext] and - /// a map of HTTP headers. If authentication fails or no token is available, - /// an empty map is provided. - /// - /// If [validateToken] is true, the token will be validated and - /// refreshed if needed. If false (default), the current cached token will be used - /// without validation. +/// Supplies bearer headers without starting a new refresh on every rebuild. +/// Inject a provider in tests; the composition-root registration is the default. +/// Use a new key when the signed-in identity changes. +class AuthHeadersBuilder extends StatefulWidget { const AuthHeadersBuilder({ super.key, required this.builder, this.validateToken = false, + this.provider, + this.logger, }); - /// The builder function that receives the authentication headers. - /// - /// The headers map will contain: - /// - 'Authorization': 'Bearer {token}' (if authenticated) - /// - 'Content-Type': 'application/json' - /// - /// If no authentication token is available, an empty map {} is provided. final Widget Function(BuildContext context, Map headers) builder; - - /// Whether to validate and potentially refresh the token. - /// - /// If true, uses [AuthTokenProvider.getValidToken] which validates - /// the token and refreshes it if needed. - /// If false (default), uses [AuthTokenProvider.getCurrentToken] which returns the - /// cached token without validation. final bool validateToken; + final AuthTokenProvider? provider; + final Logger? logger; - Map _getSyncAuthHeaders() { - try { - final authTokenProvider = di.get(); - final token = authTokenProvider.getCurrentToken(); + @override + State createState() => _AuthHeadersBuilderState(); +} - if (token != null) { - return {'Authorization': 'Bearer $token'}; - } - } catch (e) { - _logger.e('Error getting auth headers: $e'); +class _AuthHeadersBuilderState extends State { + Future>? _headers; + + AuthTokenProvider? get _provider => + widget.provider ?? + (di.has() ? di.get() : null); + + @override + void initState() { + super.initState(); + _refresh(); + } + + @override + void didUpdateWidget(covariant AuthHeadersBuilder oldWidget) { + super.didUpdateWidget(oldWidget); + if (oldWidget.provider != widget.provider || + oldWidget.validateToken != widget.validateToken) { + _refresh(); } - return {}; } - Future> _getAsyncAuthHeaders() async { - try { - final authTokenProvider = di.get(); - final token = await authTokenProvider.getValidToken(); + void _refresh() { + _headers = widget.validateToken ? _load() : null; + } - if (token != null) { - return {'Authorization': 'Bearer $token'}; - } - } catch (e) { - _logger.e('Error getting auth headers: $e'); + Map _fromToken(String? token) => + token == null || token.isEmpty ? {} : {'Authorization': 'Bearer $token'}; + + void _log(Object error, StackTrace stack) { + final logger = + widget.logger ?? (di.has() ? di.get() : null); + logger?.e('Unable to obtain image authentication headers', error, stack); + } + + Future> _load() async { + try { + return _fromToken(await _provider?.getValidToken()); + } catch (error, stack) { + _log(error, stack); + return {}; } - return {}; } @override Widget build(BuildContext context) { - // If validation is not needed, return synchronously without FutureBuilder - if (!validateToken) { - final headers = _getSyncAuthHeaders(); - return builder(context, headers); + if (!widget.validateToken) { + Map headers; + try { + headers = _fromToken(_provider?.getCurrentToken()); + } catch (error, stack) { + _log(error, stack); + headers = {}; + } + return widget.builder(context, headers); } - - // If validation is needed, use FutureBuilder return FutureBuilder>( - future: _getAsyncAuthHeaders(), - builder: (context, snapshot) { - final headers = snapshot.data ?? {}; - return builder(context, headers); - }, + key: ValueKey(_headers), + future: _headers, + builder: (context, snapshot) => + widget.builder(context, snapshot.data ?? {}), ); } -}{{/network}} +} +{{/network}} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/design_system/lib/components/header.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/design_system/lib/components/header.dart index 415c857..ca9e820 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/design_system/lib/components/header.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/design_system/lib/components/header.dart @@ -32,12 +32,16 @@ class Header extends StatelessWidget { Widget _buildImage(BuildContext context) { switch (type) { case HeaderType.asset: + if (assetPath == null || assetPath!.isEmpty) { + return const Icon(Icons.image); + } return Hero( tag: assetPath!, child: Image.asset( assetPath!, fit: BoxFit.contain, alignment: Alignment.center, + errorBuilder: (_, _, _) => const Icon(Icons.image), ), ); case HeaderType.image: diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/design_system/lib/constants/navigation_icons.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/design_system/lib/constants/navigation_icons.dart index 5697b47..b94aba3 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/design_system/lib/constants/navigation_icons.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/design_system/lib/constants/navigation_icons.dart @@ -4,9 +4,7 @@ import 'package:flutter/material.dart'; /// /// Swap these for your product's icon set - every navigation surface reads /// from here so a single edit re-skins the whole shell. -class NavigationIcons { - const NavigationIcons._(); - +abstract final class NavigationIcons { static const IconData home = Icons.home_outlined; static const IconData homeSelected = Icons.home; diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/design_system/pubspec.yaml b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/design_system/pubspec.yaml index 71dfdf9..f77567f 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/design_system/pubspec.yaml +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/design_system/pubspec.yaml @@ -26,6 +26,7 @@ dependencies: path: ../network {{/network}} dev_dependencies: + mocktail: ^1.0.4 flutter_test: sdk: flutter flutter_lints: ^5.0.0 diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/design_system/test/components_test.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/design_system/test/components_test.dart new file mode 100644 index 0000000..3a5f6d2 --- /dev/null +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/design_system/test/components_test.dart @@ -0,0 +1,209 @@ +import 'package:design_system/design_system.dart' as ds; +import 'package:design_system/utils/extensions/string.dart'; +import 'package:design_system/generated/theme.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:localization/localization.dart'; + +void main() { + test( + 'extended palettes retain custom color families for each contrast mode', + () { + final family = ColorFamily( + color: Colors.red, + onColor: Colors.white, + colorContainer: Colors.pink, + onColorContainer: Colors.black, + ); + final extended = ExtendedColor( + seed: Colors.red, + value: Colors.pink, + light: family, + lightHighContrast: family, + lightMediumContrast: family, + dark: family, + darkHighContrast: family, + darkMediumContrast: family, + ); + expect(extended.seed, Colors.red); + expect(extended.light.color, Colors.red); + expect(extended.dark.onColorContainer, Colors.black); + }, + ); + testWidgets( + 'date filters select another period without deselecting the current one', + (tester) async { + final changes = []; + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: ds.DateFilterChips( + selectedFilter: ds.DateFilterType.week, + onFilterChanged: changes.add, + ), + ), + ), + ); + await tester.tap(find.text(strings.common.week)); + expect(changes, isEmpty); + await tester.tap(find.text(strings.common.month)); + expect(changes, [ds.DateFilterType.month]); + }, + ); + + testWidgets('error view explains failures and exposes retry', (tester) async { + var retries = 0; + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: ds.DefaultErrorView( + error: StateError('failure'), + stackTrace: StackTrace.current, + descriptionBuilder: (_) => 'Try another connection', + onRetry: () { + retries++; + }, + ), + ), + ), + ); + expect(find.text('Try another connection'), findsOneWidget); + await tester.tap(find.text(strings.generic.try_again)); + expect(retries, 1); + }); + + testWidgets('error screen provides retry and home actions', (tester) async { + var retries = 0; + var homes = 0; + await tester.pumpWidget( + MaterialApp( + home: ds.ErrorScreen( + title: 'Unavailable', + message: 'Try later', + error: 'Details', + onRetry: () { + retries++; + }, + onGoHome: () { + homes++; + }, + ), + ), + ); + expect(find.text('Unavailable'), findsOneWidget); + await tester.tap(find.byType(FilledButton)); + await tester.tap(find.byType(OutlinedButton)); + expect(retries, 1); + expect(homes, 1); + }); + + for (final extension in ['png', 'svg']) { + testWidgets('missing $extension assets render a fallback', (tester) async { + await tester.pumpWidget( + MaterialApp(home: ds.AssetImage(assetPath: 'missing.$extension')), + ); + await tester.runAsync( + () => Future.delayed(const Duration(milliseconds: 100)), + ); + await tester.pumpAndSettle(); + expect(find.byIcon(Icons.image), findsOneWidget); + }); + } + + testWidgets( + 'all theme variants expose appropriate brightness and selected styles', + (tester) async { + await tester.pumpWidget( + MaterialApp( + home: Builder( + builder: (context) { + final design = ds.DesignSystem(context); + for (final theme in [design.light(), design.dark()]) { + expect( + theme.navigationBarTheme.iconTheme!.resolve({ + WidgetState.selected, + })!.size, + 20, + ); + expect( + theme.navigationBarTheme.iconTheme!.resolve({})!.size, + 20, + ); + expect( + theme.navigationBarTheme.labelTextStyle!.resolve({ + WidgetState.selected, + })!.fontWeight, + FontWeight.w600, + ); + expect( + theme.navigationBarTheme.labelTextStyle! + .resolve({})! + .fontWeight, + FontWeight.w500, + ); + } + final palette = design.theme; + for (final theme in [ + palette.light(), + palette.lightMediumContrast(), + palette.lightHighContrast(), + ]) { + expect(theme.brightness, Brightness.light); + } + for (final theme in [ + palette.dark(), + palette.darkMediumContrast(), + palette.darkHighContrast(), + ]) { + expect(theme.brightness, Brightness.dark); + } + expect(palette.extendedColors, isEmpty); + return const SizedBox(); + }, + ), + ), + ); + }, + ); + + testWidgets('wrapper changes brightness and supports loader show and hide', ( + tester, + ) async { + tester.platformDispatcher.platformBrightnessTestValue = Brightness.light; + addTearDown(tester.platformDispatcher.clearPlatformBrightnessTestValue); + late BuildContext loaderContext; + await tester.pumpWidget( + ds.DesignSystemWrapper( + builder: (_, theme) => MaterialApp( + theme: theme, + home: Builder( + builder: (context) { + loaderContext = context; + return Scaffold(body: Text(theme.brightness.name)); + }, + ), + ), + ), + ); + expect(find.text('light'), findsOneWidget); + tester.platformDispatcher.platformBrightnessTestValue = Brightness.dark; + await tester.pumpAndSettle(); + expect(find.text('dark'), findsOneWidget); + ds.Loader.show(loaderContext); + await tester.pump(const Duration(milliseconds: 400)); + expect(find.byType(ds.DefaultLoader), findsOneWidget); + ds.Loader.hide(loaderContext); + await tester.pumpAndSettle(); + expect(find.byType(ds.DefaultLoader), findsNothing); + }); + + test('nullable string helpers preserve nonempty text', () { + expect((null as String?).asEmptyIfNull, ''); + expect('text'.asEmptyIfNull, 'text'); + expect((null as String?).isNotNullAndNotEmpty, isFalse); + expect(''.isNotNullAndNotEmpty, isFalse); + expect('text'.isNotNullAndNotEmpty, isTrue); + expect(ds.HeaderType.image.ratio, 4); + expect(ds.HeaderType.asset.ratio, 1); + }); +} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/design_system/test/integration_test.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/design_system/test/integration_test.dart new file mode 100644 index 0000000..b2ba94f --- /dev/null +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/design_system/test/integration_test.dart @@ -0,0 +1,238 @@ +import 'dart:io'; + +import 'package:cached_network_image/cached_network_image.dart'; +{{#network}}import 'package:core/core.dart'; +{{/network}} +import 'package:design_system/design_system.dart' as ds; +import 'package:design_system/toast/toasts.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +{{#network}}import 'package:network/network.dart'; +{{/network}} +import 'package:toastification/toastification.dart'; + +class _File extends Mock implements File {} + +class _Stat extends Mock implements FileStat {} + +{{#network}}class _Tokens extends Mock implements AuthTokenProvider {} +{{/network}} + +{{#network}}class _Logger extends Mock implements Logger {} +{{/network}} + +void main() { + testWidgets( + 'file dialog renders supported metadata sizes and copies each field', + (tester) async { + final copied = []; + tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( + SystemChannels.platform, + (call) async { + if (call.method == 'Clipboard.setData') { + copied.add((call.arguments as Map)['text'] as String); + } + return null; + }, + ); + addTearDown( + () => tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( + SystemChannels.platform, + null, + ), + ); + for (final (extension, label, size, expectedSize) in [ + ('jpg', 'JPEG Image', 20, '20 B'), + ('png', 'PNG Image', 1024, '1.0 KB'), + ('gif', 'GIF Image', 1048576, '1.0 MB'), + ('webp', 'WebP Image', 0, '0 B'), + ('bmp', 'BMP Image', 0, '0 B'), + ('tiff', 'TIFF Image', 0, '0 B'), + ('heic', 'HEIF Image', 0, '0 B'), + ('unknown', 'Image File', 0, '0 B'), + ]) { + final file = _File(); + final stat = _Stat(); + when(() => file.path).thenReturn('/fixture/image.$extension'); + when(file.statSync).thenReturn(stat); + when(() => stat.size).thenReturn(size); + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: Builder( + builder: (context) => TextButton( + onPressed: () => ds.FileInfoDialog.show(context, file), + child: const Text('show'), + ), + ), + ), + ), + ); + await tester.tap(find.text('show')); + await tester.pumpAndSettle(); + expect(find.text(label), findsOneWidget); + expect(find.text(expectedSize), findsOneWidget); + for (final field in [ + 'File Name', + 'File Type', + 'File Extension', + 'File Size', + 'File Path', + ]) { + await tester.ensureVisible(find.text(field)); + await tester.tap(find.text(field)); + await tester.pump(); + } + expect(copied.last, file.path); + await tester.tap(find.byIcon(Icons.close)); + await tester.pumpAndSettle(); + expect(find.byType(ds.FileInfoDialog), findsNothing); + } + expect(copied.length, 40); + }, + ); + + testWidgets( + 'image adapters expose placeholder and errors and tolerate missing header assets', + (tester) async { + late CachedNetworkImage image; + late BuildContext context; + await tester.pumpWidget( + MaterialApp( + home: Builder( + builder: (ctx) { + context = ctx; + image = + const ds.NetworkUrlImage( + url: 'https://example.test/image', + width: 40, + height: 60, + ).build(ctx) + as CachedNetworkImage; + return image.placeholder!(ctx, ''); + }, + ), + ), + ); + expect(image.width, 40); + expect(find.byIcon(Icons.image), findsOneWidget); + final error = image.errorWidget!(context, '', Exception('missing')); + await tester.pumpWidget(MaterialApp(home: error)); + expect(find.byIcon(Icons.image), findsOneWidget); + for (final path in [null, '', 'missing.png']) { + await tester.pumpWidget( + MaterialApp( + home: ds.Header(type: ds.HeaderType.asset, assetPath: path), + ), + ); + await tester.runAsync( + () => Future.delayed(const Duration(milliseconds: 50)), + ); + await tester.pumpAndSettle(); + expect(find.byIcon(Icons.image), findsOneWidget); + expect(tester.takeException(), isNull); + } + await tester.pumpWidget( + MaterialApp( + home: Builder( + builder: (context) { + final header = + const ds.Header( + imageUrl: 'https://example.test/cover', + ).build(context) + as AspectRatio; + expect(header.aspectRatio, 4); + expect( + (header.child as ds.NetworkUrlImage).url, + 'https://example.test/cover', + ); + return const SizedBox(); + }, + ), + ), + ); + }, + ); + +{{#network}} testWidgets( + 'auth headers support missing providers, failures and stable async rebuilds', + (tester) async { + final tokens = _Tokens(); + when(tokens.getCurrentToken).thenReturn('cached'); + when(tokens.getValidToken).thenAnswer((_) async => 'fresh'); + Widget subject({AuthTokenProvider? provider, bool validate = false}) => + MaterialApp( + home: ds.AuthHeadersBuilder( + provider: provider, + logger: _Logger(), + validateToken: validate, + builder: (_, headers) => + Text(headers['Authorization'] ?? 'anonymous'), + ), + ); + await tester.pumpWidget(subject()); + expect(find.text('anonymous'), findsOneWidget); + await tester.pumpWidget(subject(provider: tokens)); + expect(find.text('Bearer cached'), findsOneWidget); + await tester.pumpWidget(subject(provider: tokens, validate: true)); + await tester.pumpAndSettle(); + await tester.pumpWidget(subject(provider: tokens, validate: true)); + await tester.pumpAndSettle(); + expect(find.text('Bearer fresh'), findsOneWidget); + verify(tokens.getValidToken).called(1); + when(tokens.getCurrentToken).thenThrow(StateError('unavailable')); + await tester.pumpWidget(subject(provider: tokens)); + expect(find.text('anonymous'), findsOneWidget); + when(tokens.getValidToken).thenThrow(StateError('unavailable')); + await tester.pumpWidget(subject(provider: tokens, validate: true)); + await tester.pumpAndSettle(); + expect(find.text('anonymous'), findsOneWidget); + await tester.pumpWidget(subject(validate: true)); + await tester.pumpAndSettle(); + expect(find.text('anonymous'), findsOneWidget); + }, + ); + +{{/network}} testWidgets('toast variants render their messages and dismiss cleanly', ( + tester, + ) async { + late BuildContext context; + await tester.pumpWidget( + ToastificationWrapper( + child: MaterialApp( + home: Scaffold( + body: Builder( + builder: (ctx) { + context = ctx; + return const SizedBox(); + }, + ), + ), + ), + ), + ); + final callbacks = [ + () => Toast.notification(title: 'Notice', body: 'Details'), + () => Toast.error(context, message: 'Notice', description: 'Details'), + () => Toast.success(context, message: 'Notice', description: 'Details'), + () => Toast.warning(context, message: 'Notice', description: 'Details'), + ]; + for (final show in callbacks) { + show(); + await tester.pump(); + await tester.pump(const Duration(milliseconds: 500)); + await tester.pump(const Duration(milliseconds: 500)); + expect( + find.text('Notice'), + findsOneWidget, + reason: 'toast variant ${callbacks.indexOf(show)}', + ); + expect(find.text('Details'), findsOneWidget); + toastification.dismissAll(delayForAnimation: false); + await tester.pump(const Duration(seconds: 1)); + await tester.pumpAndSettle(); + } + }); +} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/di/lib/src/dependency_injection_imp.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/di/lib/src/dependency_injection_imp.dart index 7fb9bfe..2304549 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/di/lib/src/dependency_injection_imp.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/di/lib/src/dependency_injection_imp.dart @@ -24,7 +24,8 @@ class GetItDependencyInjection implements DependencyInjection { @override Future dispose() async { // Call dispose functions for all registered instances - for (final entry in _disposeFunctions.entries) { + // Dependents are registered after dependencies; tear them down first. + for (final entry in _disposeFunctions.entries.toList().reversed) { final type = entry.key; final disposeFunc = entry.value; final instance = _registeredInstances[type]; @@ -71,6 +72,13 @@ class GetItDependencyInjection implements DependencyInjection { if (!_getIt.isRegistered()) { return; } + if (instance != null && !identical(instance, _getIt.get())) { + throw ArgumentError.value( + instance, + 'instance', + 'Does not match the registered instance of $T', + ); + } // Call dispose function if it exists final disposeFunc = _disposeFunctions[T]; diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/di/test/lifecycle_test.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/di/test/lifecycle_test.dart new file mode 100644 index 0000000..6065893 --- /dev/null +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/di/test/lifecycle_test.dart @@ -0,0 +1,72 @@ +import 'package:di/di.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:get_it/get_it.dart'; + +class _Service {} + +void main() { + late GetItDependencyInjection container; + setUp( + () => container = GetItDependencyInjection(getIt: GetIt.asNewInstance()), + ); + tearDown(() => container.dispose()); + + test( + 'disposes dependents first, awaits cleanup and continues after failures', + () async { + final order = []; + container.register( + 'service', + dispose: (_) async { + order.add('service'); + }, + ); + container.register( + 1, + dispose: (_) async { + order.add('repository'); + throw StateError('cleanup'); + }, + ); + container.register( + true, + dispose: (_) async { + order.add('controller'); + }, + ); + await container.reset(); + expect(order, ['controller', 'repository', 'service']); + expect(container.has(), isFalse); + await container.reset(); + expect(order, hasLength(3)); + }, + ); + + test('unregister cleanup failure still removes the registration', () async { + container.register( + 'value', + dispose: (_) => throw StateError('cleanup'), + ); + await container.unregister(null); + expect(container.has(), isFalse); + }); + + test('wrong-instance unregistration has no disposal side effects', () async { + final first = _Service(); + var disposed = false; + container.register<_Service>( + first, + dispose: (_) { + disposed = true; + }, + ); + await expectLater( + container.unregister<_Service>(_Service()), + throwsArgumentError, + ); + expect(container.get<_Service>(), same(first)); + expect(disposed, isFalse); + await container.unregister<_Service>(first); + expect(disposed, isTrue); + }); +} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/localization/test/localization_test.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/localization/test/localization_test.dart index 52f0988..80ee9d8 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/localization/test/localization_test.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/localization/test/localization_test.dart @@ -1,7 +1,23 @@ import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter/material.dart'; import 'package:localization/localization.dart'; void main() { + test('locale matching selects supported language or defaults to English', () { + expect(LocalizationProvider.getMessages('en'), isA()); + expect( + LocalizationProvider.getBestMatchingLocale([ + const Locale('es'), + const Locale('en', 'US'), + ]), + 'en', + ); + expect( + LocalizationProvider.getBestMatchingLocale([const Locale('es')]), + 'en', + ); + expect(LocalizationProvider.getBestMatchingLocale([]), 'en'); + }); group('LocalizationProvider Tests', () { test('should initialize with default locale', () { LocalizationProvider.initialize(); diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/utils/lib/src/number_formatter.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/utils/lib/src/number_formatter.dart index 06e58a4..ebece1b 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/utils/lib/src/number_formatter.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/utils/lib/src/number_formatter.dart @@ -58,9 +58,8 @@ extension IntTimeFormatting on int { } extension DateTimeFormatting on DateTime { - String formatRelative() { - final now = DateTime.now(); - final difference = now.difference(this); + String formatRelative({DateTime? now}) { + final difference = (now ?? DateTime.now()).difference(this); if (difference.inMinutes < 1) { return 'Just now'; diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/utils/test/number_formatter_test.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/utils/test/number_formatter_test.dart new file mode 100644 index 0000000..6e579c7 --- /dev/null +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/utils/test/number_formatter_test.dart @@ -0,0 +1,44 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:utils/utils.dart'; + +void main() { + test('formats decimals and domain conveniences consistently', () { + expect(2.0.format(), '2'); + expect(2.125.format(decimalPlaces: 2), '2.13'); + expect(2.25.asScore(), '2.3'); + expect(2.25.asHrv(), '2.3'); + expect(2.25.asSleepHours(), '2.3'); + expect(2.25.asRespiratoryRate(), '2.3'); + expect(1250.compact(), '1.25K'); + expect(72.6.asHeartRate(), '73'); + }); + + test('formats duration boundaries', () { + for (final entry in { + 0: '0 sec', + 59: '59 sec', + 60: '1 min', + 61: '1 min 1 sec', + 3599: '59 min 59 sec', + 3600: '1 hr', + 3660: '1 hr 1 min', + }.entries) { + expect(entry.key.asTime(), entry.value); + } + }); + + test('relative time has deterministic minute, hour and date boundaries', () { + final now = DateTime(2026, 1, 15, 12); + for (final entry in { + Duration.zero: 'Just now', + const Duration(minutes: 1): '1m ago', + const Duration(hours: 1): '1h ago', + const Duration(days: 1): 'Yesterday', + const Duration(days: 3): '3d ago', + const Duration(days: 7): '8/1/2026', + }.entries) { + expect(now.subtract(entry.key).formatRelative(now: now), entry.value); + } + expect(DateTime.now().formatRelative(), 'Just now'); + }); +} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/lib/analytics.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/lib/analytics.dart index e1cc4bf..bd6c6bd 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/lib/analytics.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/lib/analytics.dart @@ -4,6 +4,7 @@ import 'package:analytics/src/client/index.dart'; import 'package:analytics/src/config/index.dart'; import 'package:core/core.dart'; import 'package:di/di.dart'; +import 'package:firebase_analytics/firebase_analytics.dart'; export 'src/client/index.dart'; export 'src/config/index.dart'; @@ -13,16 +14,25 @@ export 'src/utils/index.dart'; Future init({ AnalyticsConfig config = const DefaultAnalyticsConfig(), + FirebaseAnalytics? analytics, }) async { - await registerAnalyticsWithDI(config); + await registerAnalyticsWithDI(config, analytics: analytics); final logger = di.get(); logger.i('Analytics module initialized with Firebase Analytics'); } -Future registerAnalyticsWithDI(AnalyticsConfig config) async { +Future registerAnalyticsWithDI( + AnalyticsConfig config, { + FirebaseAnalytics? analytics, +}) async { final logger = di.get(); - final analyticsClient = FirebaseAnalyticsClient(config); + final analyticsClient = FirebaseAnalyticsClient( + config, + analytics: analytics ?? FirebaseAnalytics.instance, + logger: logger, + ); + await analyticsClient.initialize(); di.register( analyticsClient, dispose: (client) => client.dispose(), diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/lib/src/client/firebase_analytics_client.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/lib/src/client/firebase_analytics_client.dart index d9f7206..e37882a 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/lib/src/client/firebase_analytics_client.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/lib/src/client/firebase_analytics_client.dart @@ -2,30 +2,33 @@ import 'package:analytics/src/client/analytics_client.dart'; import 'package:analytics/src/config/analytics_config.dart'; import 'package:analytics/src/models/analytics_event.dart'; import 'package:core/core.dart'; -import 'package:di/di.dart'; import 'package:firebase_analytics/firebase_analytics.dart'; class FirebaseAnalyticsClient implements AnalyticsClient { - FirebaseAnalyticsClient(this._config) - : _analytics = FirebaseAnalytics.instance { - _setupAnalytics(); - } + FirebaseAnalyticsClient( + this._config, { + required FirebaseAnalytics analytics, + required Logger logger, + }) : _analytics = analytics, + _logger = logger, + _enabled = _config.enableAnalytics; final AnalyticsConfig _config; final FirebaseAnalytics _analytics; - final Logger _logger = di.get(); + final Logger _logger; + bool _enabled; - void _setupAnalytics() { - _analytics.setAnalyticsCollectionEnabled(_config.enableAnalytics); + Future initialize() async { + await _analytics.setAnalyticsCollectionEnabled(_enabled); if (_config.userId != null) { - _analytics.setUserId(id: _config.userId); + await _analytics.setUserId(id: _config.userId); _logger.d('🔍 Analytics user ID set: ${_config.userId}'); } if (_config.defaultUserProperties != null) { for (final entry in _config.defaultUserProperties!.entries) { - _analytics.setUserProperty(name: entry.key, value: entry.value); + await _analytics.setUserProperty(name: entry.key, value: entry.value); } _logger.d('🔍 Analytics default user properties set'); } @@ -43,7 +46,7 @@ class FirebaseAnalyticsClient implements AnalyticsClient { Map? parameters, }) async { try { - if (!_config.enableAnalytics) { + if (!_enabled) { if (_config.enableDebugLogging) { _logger.d('🔍 Analytics disabled, skipping event: $name'); } @@ -52,7 +55,12 @@ class FirebaseAnalyticsClient implements AnalyticsClient { await _analytics.logEvent( name: name, - parameters: parameters?.cast(), + parameters: parameters == null + ? null + : { + for (final entry in parameters.entries) + if (entry.value != null) entry.key: entry.value as Object, + }, ); if (_config.enableDebugLogging) { @@ -116,6 +124,7 @@ class FirebaseAnalyticsClient implements AnalyticsClient { Future setAnalyticsCollectionEnabled(bool enabled) async { try { await _analytics.setAnalyticsCollectionEnabled(enabled); + _enabled = enabled; if (_config.enableDebugLogging) { _logger.d( diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/lib/src/models/analytics_event.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/lib/src/models/analytics_event.dart index 97ab101..81a47ea 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/lib/src/models/analytics_event.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/lib/src/models/analytics_event.dart @@ -20,7 +20,14 @@ class AnalyticsEvent { } @override - int get hashCode => name.hashCode ^ parameters.hashCode; + int get hashCode => Object.hash( + name, + parameters == null + ? null + : Object.hashAllUnordered( + parameters!.entries.map((e) => Object.hash(e.key, e.value)), + ), + ); bool _mapEquals(Map? a, Map? b) { if (a == null) return b == null; diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/lib/src/models/analytics_events.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/lib/src/models/analytics_events.dart index ea381eb..b4ec336 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/lib/src/models/analytics_events.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/lib/src/models/analytics_events.dart @@ -3,9 +3,7 @@ /// Usage: `AnalyticsEvents.user.authenticatedRedirect`. Naming events here /// instead of inline keeps them discoverable and typo-free, and gives you one /// place to add the groups your own product needs. -class AnalyticsEvents { - AnalyticsEvents._(); - +abstract final class AnalyticsEvents { /// User-related events static const user = _UserEvents(); @@ -145,8 +143,6 @@ class _AppEvents { String get uninstalled => 'app_uninstalled'; } - - class _ProfileEvents { const _ProfileEvents(); diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/lib/src/observer/analytics_route_observer.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/lib/src/observer/analytics_route_observer.dart index d30f281..9a4b60b 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/lib/src/observer/analytics_route_observer.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/lib/src/observer/analytics_route_observer.dart @@ -1,65 +1,43 @@ +import 'dart:async'; +import 'package:analytics/src/client/analytics_client.dart'; import 'package:core/core.dart'; -import 'package:di/di.dart'; -import 'package:firebase_analytics/firebase_analytics.dart'; import 'package:flutter/material.dart'; -/// Analytics route observer that uses Firebase Analytics Observer internally -/// while providing additional logging and error handling capabilities +/// Tracks named pages through the analytics abstraction, including async errors. class AnalyticsRouteObserver extends NavigatorObserver { - AnalyticsRouteObserver() - : _logger = di.get(), - _firebaseObserver = FirebaseAnalyticsObserver( - analytics: FirebaseAnalytics.instance, - ); + AnalyticsRouteObserver({ + required AnalyticsClient client, + required Logger logger, + }) : _client = client, + _logger = logger; + final AnalyticsClient _client; final Logger _logger; - final FirebaseAnalyticsObserver _firebaseObserver; - - @override - void didPush(Route route, Route? previousRoute) { - super.didPush(route, previousRoute); + Future _track(Route? route) async { + if (route is! PageRoute || route.settings.name == null) return; try { - // Delegate to Firebase Analytics Observer for native screen tracking - _firebaseObserver.didPush(route, previousRoute); - } catch (e, s) { - _logger.e('Failed to track screen push event', e, s); + await _client.logScreenView(screenName: route.settings.name!); + } catch (error, stack) { + _logger.e('Failed to track screen navigation', error, stack); } } @override - void didPop(Route route, Route? previousRoute) { - super.didPop(route, previousRoute); - - try { - // Delegate to Firebase Analytics Observer - _firebaseObserver.didPop(route, previousRoute); - } catch (e, s) { - _logger.e('Failed to track screen pop event', e, s); - } + void didPush(Route route, Route? previousRoute) { + super.didPush(route, previousRoute); + unawaited(_track(route)); } @override - void didReplace({Route? newRoute, Route? oldRoute}) { - super.didReplace(newRoute: newRoute, oldRoute: oldRoute); - - try { - // Delegate to Firebase Analytics Observer - _firebaseObserver.didReplace(newRoute: newRoute, oldRoute: oldRoute); - } catch (e, s) { - _logger.e('Failed to track screen replace event', e, s); - } + void didPop(Route route, Route? previousRoute) { + super.didPop(route, previousRoute); + unawaited(_track(previousRoute)); } @override - void didRemove(Route route, Route? previousRoute) { - super.didRemove(route, previousRoute); - - try { - // Delegate to Firebase Analytics Observer - _firebaseObserver.didRemove(route, previousRoute); - } catch (e, s) { - _logger.e('Failed to track screen remove event', e, s); - } + void didReplace({Route? newRoute, Route? oldRoute}) { + super.didReplace(newRoute: newRoute, oldRoute: oldRoute); + unawaited(_track(newRoute)); } } diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/lib/src/utils/analytics_helper.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/lib/src/utils/analytics_helper.dart index 90509ed..0ad1254 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/lib/src/utils/analytics_helper.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/lib/src/utils/analytics_helper.dart @@ -5,24 +5,15 @@ import 'package:core/core.dart'; import 'package:di/di.dart'; class AnalyticsHelper { - static AnalyticsClient? _client; - static Logger? _logger; + static AnalyticsClient? get _analyticsClient => _getAnalyticsClient(); - static AnalyticsClient? get _analyticsClient { - _client ??= _getAnalyticsClient(); - return _client; - } - - static Logger get _log { - _logger ??= di.get(); - return _logger!; - } + static Logger? get _log => di.has() ? di.get() : null; static AnalyticsClient? _getAnalyticsClient() { try { return di.get(); } catch (e) { - _log.w('Analytics client not available: $e'); + _log?.w('Analytics client not available: $e'); return null; } } @@ -38,7 +29,7 @@ class AnalyticsHelper { try { await client.logEvent(name: name, parameters: parameters); } catch (e, s) { - _log.e('Failed to log analytics event: $name', e, s); + _log?.e('Failed to log analytics event: $name', e, s); } } @@ -53,7 +44,7 @@ class AnalyticsHelper { try { await client.logLogin(loginMethod: method, parameters: parameters); } catch (e, s) { - _log.e('Failed to log sign in event', e, s); + _log?.e('Failed to log sign in event', e, s); } } @@ -68,7 +59,7 @@ class AnalyticsHelper { try { await client.logSignUp(signUpMethod: method, parameters: parameters); } catch (e, s) { - _log.e('Failed to log sign up event', e, s); + _log?.e('Failed to log sign up event', e, s); } } @@ -80,7 +71,7 @@ class AnalyticsHelper { try { await client.setUserId(userId); } catch (e, s) { - _log.e('Failed to set analytics user ID', e, s); + _log?.e('Failed to set analytics user ID', e, s); } } @@ -95,7 +86,7 @@ class AnalyticsHelper { try { await client.setUserProperty(name: name, value: value); } catch (e, s) { - _log.e('Failed to set analytics user property: $name', e, s); + _log?.e('Failed to set analytics user property: $name', e, s); } } @@ -107,7 +98,7 @@ class AnalyticsHelper { try { await client.logAppOpen(parameters: parameters); } catch (e, s) { - _log.e('Failed to log app open event', e, s); + _log?.e('Failed to log app open event', e, s); } } @@ -119,7 +110,7 @@ class AnalyticsHelper { try { await client.logCustomEvent(event); } catch (e, s) { - _log.e('Failed to log custom analytics event: ${event.name}', e, s); + _log?.e('Failed to log custom analytics event: ${event.name}', e, s); } } @@ -169,5 +160,4 @@ class AnalyticsHelper { }, ); } - } diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/pubspec.yaml b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/pubspec.yaml index 8253dde..4e26573 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/pubspec.yaml +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/pubspec.yaml @@ -17,6 +17,7 @@ dependencies: path: ../di dev_dependencies: + mocktail: ^1.0.4 flutter_test: sdk: flutter flutter_lints: ^5.0.0 diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/test/client_test.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/test/client_test.dart new file mode 100644 index 0000000..4b0eb50 --- /dev/null +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/test/client_test.dart @@ -0,0 +1,173 @@ +import 'package:analytics/analytics.dart'; +import 'package:analytics/analytics.dart' as analytics; +import 'package:core/core.dart'; +import 'package:di/di.dart'; +import 'package:firebase_analytics/firebase_analytics.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; + +class _Sdk extends Mock implements FirebaseAnalytics {} + +class _Logger extends Mock implements Logger {} + +void main() { + late _Sdk sdk; + late _Logger logger; + late FirebaseAnalyticsClient client; + setUp(() { + sdk = _Sdk(); + logger = _Logger(); + when( + () => sdk.setAnalyticsCollectionEnabled(any()), + ).thenAnswer((_) async {}); + when(() => sdk.setUserId(id: any(named: 'id'))).thenAnswer((_) async {}); + when( + () => sdk.setUserProperty( + name: any(named: 'name'), + value: any(named: 'value'), + ), + ).thenAnswer((_) async {}); + when( + () => sdk.logEvent( + name: any(named: 'name'), + parameters: any(named: 'parameters'), + ), + ).thenAnswer((_) async {}); + when(sdk.resetAnalyticsData).thenAnswer((_) async {}); + client = FirebaseAnalyticsClient( + const DefaultAnalyticsConfig( + enableDebugLogging: true, + userId: 'user', + defaultUserProperties: {'role': 'tester'}, + ), + analytics: sdk, + logger: logger, + ); + }); + tearDown(di.reset); + + test('semantic events forward additional parameters', () async { + await client.logScreenView( + screenName: 'home', + parameters: {'source': 'link'}, + ); + await client.logLogin(parameters: {'source': 'link'}); + await client.logSignUp(parameters: {'source': 'link'}); + await client.logPurchase( + currency: 'USD', + value: 2, + parameters: {'source': 'link'}, + ); + verify( + () => sdk.logEvent(name: 'login', parameters: {'source': 'link'}), + ).called(1); + verify( + () => sdk.logEvent(name: 'sign_up', parameters: {'source': 'link'}), + ).called(1); + }); + + test( + 'initialization awaits SDK setup and propagates startup failures', + () async { + await client.initialize(); + verify(() => sdk.setUserId(id: 'user')).called(1); + verify( + () => sdk.setUserProperty(name: 'role', value: 'tester'), + ).called(1); + when( + () => sdk.setAnalyticsCollectionEnabled(any()), + ).thenThrow(StateError('setup')); + await expectLater(client.initialize(), throwsStateError); + }, + ); + + test('null event parameters are removed before SDK submission', () async { + await client.logEvent( + name: 'event', + parameters: {'valid': 1, 'optional': null}, + ); + verify( + () => sdk.logEvent(name: 'event', parameters: {'valid': 1}), + ).called(1); + }); + + test('collection changes affect future logging', () async { + await client.setAnalyticsCollectionEnabled(false); + await client.logEvent(name: 'disabled'); + verifyNever(() => sdk.logEvent(name: 'disabled')); + await client.setAnalyticsCollectionEnabled(true); + await client.logEvent(name: 'enabled'); + verify(() => sdk.logEvent(name: 'enabled')).called(1); + }); + + test( + 'semantic events preserve their expected names and parameters', + () async { + await client.logCustomEvent(const AnalyticsEvent(name: 'custom')); + await client.logAppOpen(); + await client.logScreenView(screenName: 'home', screenClass: 'Home'); + await client.logLogin(loginMethod: 'email'); + await client.logSignUp(signUpMethod: 'google'); + await client.logPurchase(currency: 'USD', value: 3.5); + verify( + () => sdk.logEvent(name: 'login', parameters: {'method': 'email'}), + ).called(1); + verify( + () => sdk.logEvent( + name: 'purchase', + parameters: {'currency': 'USD', 'value': 3.5}, + ), + ).called(1); + await client.setUserId(null); + await client.setUserProperty(name: 'role', value: null); + await client.resetAnalyticsData(); + client.dispose(); + }, + ); + + test('SDK event and property failures are contained', () async { + when( + () => sdk.logEvent( + name: any(named: 'name'), + parameters: any(named: 'parameters'), + ), + ).thenThrow(StateError('event')); + when( + () => sdk.setUserId(id: any(named: 'id')), + ).thenThrow(StateError('user')); + when( + () => sdk.setUserProperty( + name: any(named: 'name'), + value: any(named: 'value'), + ), + ).thenThrow(StateError('property')); + when(sdk.resetAnalyticsData).thenThrow(StateError('reset')); + when( + () => sdk.setAnalyticsCollectionEnabled(any()), + ).thenThrow(StateError('collection')); + await client.logEvent(name: 'event'); + await client.setUserId('user'); + await client.setUserProperty(name: 'role', value: 'value'); + await client.resetAnalyticsData(); + await client.setAnalyticsCollectionEnabled(false); + verify(() => logger.e(any(), any(), any())).called(5); + }); + + test( + 'module startup is injectable and helpers resolve fresh clients after reset', + () async { + di.register(logger); + await analytics.init(analytics: sdk); + await AnalyticsHelper.logEvent('before'); + await di.reset(); + di.register(logger); + await analytics.init( + analytics: sdk, + config: const DefaultAnalyticsConfig(enableAnalytics: false), + ); + await AnalyticsHelper.logEvent('after'); + verify(() => sdk.logEvent(name: 'before')).called(1); + verifyNever(() => sdk.logEvent(name: 'after')); + }, + ); +} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/test/event_names_test.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/test/event_names_test.dart new file mode 100644 index 0000000..909bd47 --- /dev/null +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/test/event_names_test.dart @@ -0,0 +1,84 @@ +import 'package:analytics/analytics.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + test('event catalog keeps stable unique names', () { + final events = [ + AnalyticsEvents.user.authenticatedRedirect, + AnalyticsEvents.user.profileUpdated, + AnalyticsEvents.user.preferencesChanged, + AnalyticsEvents.user.onboardingCompleted, + AnalyticsEvents.user.accountDeleted, + AnalyticsEvents.auth.signIn, + AnalyticsEvents.auth.signUp, + AnalyticsEvents.auth.signOut, + AnalyticsEvents.auth.passwordReset, + AnalyticsEvents.auth.failed, + AnalyticsEvents.auth.socialLogin, + AnalyticsEvents.navigation.screenView, + AnalyticsEvents.navigation.tabSwitched, + AnalyticsEvents.navigation.backPressed, + AnalyticsEvents.navigation.deepLinkOpened, + AnalyticsEvents.feature.used, + AnalyticsEvents.feature.tutorialStarted, + AnalyticsEvents.feature.tutorialCompleted, + AnalyticsEvents.feature.feedbackGiven, + AnalyticsEvents.feature.buttonPressed, + AnalyticsEvents.error.appError, + AnalyticsEvents.error.networkError, + AnalyticsEvents.error.crash, + AnalyticsEvents.error.apiError, + AnalyticsEvents.error.validationError, + AnalyticsEvents.app.open, + AnalyticsEvents.app.background, + AnalyticsEvents.app.foreground, + AnalyticsEvents.app.updated, + AnalyticsEvents.app.installed, + AnalyticsEvents.app.uninstalled, + AnalyticsEvents.profile.viewed, + AnalyticsEvents.profile.edited, + AnalyticsEvents.profile.photoUpdated, + AnalyticsEvents.profile.settingsChanged, + AnalyticsEvents.profile.privacyUpdated, + ]; + expect(events, [ + 'user_authenticated_redirect', + 'user_profile_updated', + 'user_preferences_changed', + 'user_onboarding_completed', + 'user_account_deleted', + 'auth_sign_in', + 'auth_sign_up', + 'auth_sign_out', + 'auth_password_reset', + 'auth_failed', + 'auth_social_login', + 'screen_view', + 'navigation_tab_switched', + 'navigation_back_pressed', + 'navigation_deep_link_opened', + 'feature_used', + 'feature_tutorial_started', + 'feature_tutorial_completed', + 'feature_feedback_given', + 'button_pressed', + 'app_error', + 'network_error', + 'app_crash', + 'api_error', + 'validation_error', + 'app_open', + 'app_background', + 'app_foreground', + 'app_updated', + 'app_installed', + 'app_uninstalled', + 'profile_viewed', + 'profile_edited', + 'profile_photo_updated', + 'profile_settings_changed', + 'profile_privacy_updated', + ]); + expect(events.toSet(), hasLength(events.length)); + }); +} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/test/helper_test.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/test/helper_test.dart new file mode 100644 index 0000000..ed02d54 --- /dev/null +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{analytics_dir}}/test/helper_test.dart @@ -0,0 +1,157 @@ +import 'package:analytics/analytics.dart'; +import 'package:core/core.dart'; +import 'package:di/di.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; + +class _Client extends Mock implements AnalyticsClient {} + +class _Logger extends Mock implements Logger {} + +void main() { + tearDown(di.reset); + setUpAll(() => registerFallbackValue(const AnalyticsEvent(name: 'fallback'))); + test( + 'all helpers tolerate absent services, forward calls and contain asynchronous failures', + () async { + final logger = _Logger(); + final client = _Client(); + final operations = Function()>[ + () => AnalyticsHelper.logEvent('custom', parameters: {'key': 1}), + () => AnalyticsHelper.logSignIn(method: 'email'), + () => AnalyticsHelper.logSignUp(method: 'email'), + () => AnalyticsHelper.setUserId('user'), + () => AnalyticsHelper.setUserProperty(name: 'role', value: 'tester'), + () => AnalyticsHelper.logAppOpen(), + () => AnalyticsHelper.logCustomEvent( + const AnalyticsEvent(name: 'custom'), + ), + () => AnalyticsHelper.logFeatureUsed( + 'search', + parameters: {'source': 'home'}, + ), + () => AnalyticsHelper.logButtonPressed( + 'submit', + screenName: 'home', + parameters: {'source': 'link'}, + ), + () => AnalyticsHelper.logAppError( + 'validation', + errorMessage: 'invalid', + parameters: {'source': 'link'}, + ), + ]; + for (final operation in operations) { + await operation(); + } + di.register(logger); + di.register(client); + final stubs = [ + () => client.logEvent( + name: any(named: 'name'), + parameters: any(named: 'parameters'), + ), + () => client.logLogin( + loginMethod: any(named: 'loginMethod'), + parameters: any(named: 'parameters'), + ), + () => client.logSignUp( + signUpMethod: any(named: 'signUpMethod'), + parameters: any(named: 'parameters'), + ), + () => client.setUserId(any()), + () => client.setUserProperty( + name: any(named: 'name'), + value: any(named: 'value'), + ), + () => client.logAppOpen(parameters: any(named: 'parameters')), + () => client.logCustomEvent(any()), + ]; + for (final stub in stubs) { + when(stub).thenAnswer((_) async {}); + } + for (final operation in operations) { + await operation(); + } + verify(() => client.logLogin(loginMethod: 'email')).called(1); + verify(() => client.setUserId('user')).called(1); + for (final stub in stubs) { + when(stub).thenAnswer((_) async => throw StateError('offline')); + } + for (final operation in operations) { + await operation(); + } + verify(() => logger.e(any(), any(), any())).called(operations.length); + }, + ); + + test( + 'route observer tracks named pages and catches asynchronous failures', + () async { + final client = _Client(); + final logger = _Logger(); + when( + () => client.logScreenView(screenName: any(named: 'screenName')), + ).thenAnswer((_) async {}); + final observer = AnalyticsRouteObserver(client: client, logger: logger); + final page = MaterialPageRoute( + settings: const RouteSettings(name: '/home'), + builder: (_) => const SizedBox(), + ); + final unnamed = MaterialPageRoute(builder: (_) => const SizedBox()); + observer.didPush(page, null); + observer.didPop(unnamed, page); + observer.didReplace(newRoute: page); + observer.didPush(unnamed, page); + observer.didPop(page, null); + await pumpEventQueue(); + verify(() => client.logScreenView(screenName: '/home')).called(3); + when( + () => client.logScreenView(screenName: any(named: 'screenName')), + ).thenAnswer((_) async => throw StateError('offline')); + observer.didPush(page, null); + await pumpEventQueue(); + verify(() => logger.e(any(), any(), any())).called(1); + page.dispose(); + unnamed.dispose(); + }, + ); + + test('event value equality agrees with hash codes and map serialization', () { + final a = AnalyticsEvent(name: 'event', parameters: {'one': 1, 'two': 2}); + final b = AnalyticsEvent(name: 'event', parameters: {'two': 2, 'one': 1}); + expect(a, b); + expect(a.hashCode, b.hashCode); + expect(a, a); + expect(a.toMap()['name'], 'event'); + expect(a.toString(), contains('event')); + expect(a, isNot(const AnalyticsEvent(name: 'event'))); + expect(const AnalyticsEvent(name: 'event'), isNot(a)); + expect( + a, + isNot(const AnalyticsEvent(name: 'event', parameters: {'one': 1})), + ); + expect( + a, + isNot( + const AnalyticsEvent(name: 'event', parameters: {'one': 1, 'two': 3}), + ), + ); + expect( + const AnalyticsEvent(name: 'empty'), + const AnalyticsEvent(name: 'empty'), + ); + final config = const DefaultAnalyticsConfig(userId: 'user') + .copyWith( + enableAnalytics: false, + enableDebugLogging: true, + defaultUserProperties: {'role': 'test'}, + ) + .copyWith(); + expect(config.enableAnalytics, isFalse); + expect(config.enableDebugLogging, isTrue); + expect(config.userId, 'user'); + expect(config.defaultUserProperties, {'role': 'test'}); + }); +} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/lib/crashlytics.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/lib/crashlytics.dart index ca23fce..7bb963e 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/lib/crashlytics.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/lib/crashlytics.dart @@ -1,55 +1,60 @@ library; -import 'dart:async'; - import 'package:core/core.dart'; import 'package:crashlytics/src/client/index.dart'; import 'package:crashlytics/src/config/index.dart'; import 'package:di/di.dart'; +import 'package:firebase_crashlytics/firebase_crashlytics.dart'; export 'src/client/index.dart'; export 'src/config/index.dart'; export 'src/models/index.dart'; /// Initialize the crashlytics module with dependency injection -Future init({CrashlyticsConfig? config}) async { - await registerCrashlyticsWithDI(config ?? const DefaultCrashlyticsConfig()); +Future init({ + CrashlyticsConfig? config, + FirebaseCrashlytics? crashlytics, +}) async { + await registerCrashlyticsWithDI( + config ?? const DefaultCrashlyticsConfig(), + crashlytics: crashlytics, + ); final logger = di.get(); logger.i('🔥 Crashlytics module initialized'); } /// Register crashlytics components with DI container -Future registerCrashlyticsWithDI(CrashlyticsConfig config) async { +Future registerCrashlyticsWithDI( + CrashlyticsConfig config, { + FirebaseCrashlytics? crashlytics, +}) async { final logger = di.get(); + final client = FirebaseCrashlyticsClient( + config: config, + logger: logger, + crashlytics: crashlytics ?? FirebaseCrashlytics.instance, + ); try { - // Register config - di.register(config); + // Publish only a fully initialized client; failed startup remains retryable. + await client.initialize(); - // Create and register crashlytics client - final client = FirebaseCrashlyticsClient(config: config, logger: logger); + // Check if there are any unsent reports + if (await client.checkForUnsentReports()) { + logger.w('⚠️ There are unsent crash reports.'); + await client.sendUnsentReports(); + } else { + logger.i('✅ No unsent crash reports found.'); + } + + di.register(config); di.register( client, dispose: (client) => client.dispose(), ); - - // Initialize the client - await client.initialize(); - - // Check if there are any unsent reports - unawaited( - client.checkForUnsentReports().then((hasReports) { - if (hasReports) { - logger.w('⚠️ There are unsent crash reports.'); - unawaited(client.sendUnsentReports()); - } else { - logger.i('✅ No unsent crash reports found.'); - } - }), - ); - logger.i('🔥 Crashlytics registered with DI container'); } catch (e, stackTrace) { + client.dispose(); logger.e('❌ Failed to register crashlytics with DI', e, stackTrace); rethrow; } diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/lib/src/client/firebase_crashlytics_client.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/lib/src/client/firebase_crashlytics_client.dart index 5317dba..d9000a6 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/lib/src/client/firebase_crashlytics_client.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/lib/src/client/firebase_crashlytics_client.dart @@ -5,49 +5,64 @@ import 'package:core/core.dart'; import 'package:crashlytics/src/client/crashlytics_client.dart'; import 'package:crashlytics/src/config/crashlytics_config.dart'; import 'package:crashlytics/src/models/user_metadata.dart'; -import 'package:di/di.dart'; import 'package:firebase_crashlytics/firebase_crashlytics.dart'; import 'package:flutter/foundation.dart'; class FirebaseCrashlyticsClient implements CrashlyticsClient { - FirebaseCrashlyticsClient({required this.config, Logger? logger}) - : _logger = logger ?? di.get(); + FirebaseCrashlyticsClient({ + required this.config, + required Logger logger, + required FirebaseCrashlytics crashlytics, + }) : _logger = logger, + _crashlytics = crashlytics; final CrashlyticsConfig config; final Logger _logger; - late final FirebaseCrashlytics _crashlytics; + final FirebaseCrashlytics _crashlytics; final Queue _logBuffer = Queue(); bool _isInitialized = false; + FlutterExceptionHandler? _previousFlutterHandler; + bool Function(Object, StackTrace)? _previousPlatformHandler; + FlutterExceptionHandler? _flutterHandler; + bool Function(Object, StackTrace)? _platformHandler; @override Future initialize() async { + if (_isInitialized) return; try { - _crashlytics = FirebaseCrashlytics.instance; - // Set crashlytics collection enabled based on config await _crashlytics.setCrashlyticsCollectionEnabled( config.enableInDebugMode || kReleaseMode, ); - // Set up automatic Flutter error handling + // Apply startup metadata before advertising readiness. + for (final entry in config.customKeys.entries) { + await _crashlytics.setCustomKey(entry.key, entry.value); + } + _isInitialized = true; + + // Own the handlers we install and restore them on disposal. if (config.enableAutomaticDataCollection) { - FlutterError.onError = (errorDetails) { - _crashlytics.recordFlutterFatalError(errorDetails); + _previousFlutterHandler = FlutterError.onError; + _previousPlatformHandler = PlatformDispatcher.instance.onError; + _flutterHandler = (errorDetails) { + unawaited( + recordError( + errorDetails.exception, + errorDetails.stack, + fatal: true, + ), + ); + _previousFlutterHandler?.call(errorDetails); }; - - // Catch errors from the Flutter framework that are not handled by FlutterError - PlatformDispatcher.instance.onError = (error, stack) { - _crashlytics.recordError(error, stack, fatal: true); + _platformHandler = (error, stack) { + unawaited(recordError(error, stack, fatal: true)); + _previousPlatformHandler?.call(error, stack); return true; }; + FlutterError.onError = _flutterHandler; + PlatformDispatcher.instance.onError = _platformHandler; } - - // Set default custom keys - if (config.customKeys.isNotEmpty) { - await setCustomKeys(config.customKeys); - } - - _isInitialized = true; _logger.i('🔥 Firebase Crashlytics initialized successfully'); } catch (e, stackTrace) { _logger.e('❌ Failed to initialize Firebase Crashlytics: $e', stackTrace); @@ -141,7 +156,7 @@ class FirebaseCrashlyticsClient implements CrashlyticsClient { try { await _crashlytics.setUserIdentifier(identifier); - _logger.d('👤 Set user identifier: $identifier'); + _logger.d('👤 User identifier updated'); } catch (e) { _logger.e('❌ Failed to set user identifier: $e'); } @@ -166,7 +181,7 @@ class FirebaseCrashlyticsClient implements CrashlyticsClient { }; await setCustomKeys(allAttributes); - _logger.d('👤 Set user metadata: $metadata'); + _logger.d('👤 User metadata updated'); } catch (e) { _logger.e('❌ Failed to set user metadata: $e'); } @@ -279,6 +294,14 @@ class FirebaseCrashlyticsClient implements CrashlyticsClient { @override void dispose() { + if (_flutterHandler != null && + identical(FlutterError.onError, _flutterHandler)) { + FlutterError.onError = _previousFlutterHandler; + } + if (_platformHandler != null && + identical(PlatformDispatcher.instance.onError, _platformHandler)) { + PlatformDispatcher.instance.onError = _previousPlatformHandler; + } _logBuffer.clear(); _isInitialized = false; _logger.d('🧹 Firebase Crashlytics client disposed'); diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/lib/src/config/crashlytics_config.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/lib/src/config/crashlytics_config.dart index 5a52e29..0681f8c 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/lib/src/config/crashlytics_config.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/lib/src/config/crashlytics_config.dart @@ -81,7 +81,9 @@ class CrashlyticsConfig { enableCustomLogs.hashCode ^ logBufferSize.hashCode ^ enableUserMetadata.hashCode ^ - customKeys.hashCode; + Object.hashAllUnordered( + customKeys.entries.map((entry) => Object.hash(entry.key, entry.value)), + ); bool _mapEquals(Map a, Map b) { if (a.length != b.length) return false; diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/lib/src/models/crash_report.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/lib/src/models/crash_report.dart index e86c428..93670d6 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/lib/src/models/crash_report.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/lib/src/models/crash_report.dart @@ -66,8 +66,8 @@ class CrashReport { @override int get hashCode => - exception.hashCode ^ - stackTrace.hashCode ^ + exception.toString().hashCode ^ + stackTrace.toString().hashCode ^ fatal.hashCode ^ timestamp.hashCode; } diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/lib/src/models/user_metadata.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/lib/src/models/user_metadata.dart index fc8633c..3450960 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/lib/src/models/user_metadata.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/lib/src/models/user_metadata.dart @@ -54,7 +54,9 @@ class UserMetadata { userId.hashCode ^ email.hashCode ^ name.hashCode ^ - customAttributes.hashCode; + Object.hashAllUnordered( + customAttributes.entries.map((e) => Object.hash(e.key, e.value)), + ); bool _mapEquals(Map a, Map b) { if (a.length != b.length) return false; diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/pubspec.yaml b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/pubspec.yaml index 7a0ae42..433f1f2 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/pubspec.yaml +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/pubspec.yaml @@ -18,6 +18,7 @@ dependencies: path: ../di dev_dependencies: + mocktail: ^1.0.4 flutter_test: sdk: flutter flutter_lints: ^5.0.0 diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/test/client_test.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/test/client_test.dart new file mode 100644 index 0000000..32edb93 --- /dev/null +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/test/client_test.dart @@ -0,0 +1,223 @@ +import 'package:core/core.dart'; +import 'package:crashlytics/crashlytics.dart'; +import 'package:crashlytics/crashlytics.dart' as crash; +import 'package:di/di.dart'; +import 'package:firebase_crashlytics/firebase_crashlytics.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; + +class _Sdk extends Mock implements FirebaseCrashlytics {} + +class _Logger extends Mock implements Logger {} + +class _Metadata extends Mock implements UserMetadata {} + +void main() { + late _Sdk sdk; + late _Logger logger; + late FirebaseCrashlyticsClient client; + setUp(() { + sdk = _Sdk(); + logger = _Logger(); + when( + () => sdk.setCrashlyticsCollectionEnabled(any()), + ).thenAnswer((_) async {}); + when(() => sdk.setCustomKey(any(), any())).thenAnswer((_) async {}); + when(() => sdk.setUserIdentifier(any())).thenAnswer((_) async {}); + when(() => sdk.log(any())).thenAnswer((_) async {}); + when( + () => sdk.recordError( + any(), + any(), + fatal: any(named: 'fatal'), + information: any(named: 'information'), + ), + ).thenAnswer((_) async {}); + when(() => sdk.isCrashlyticsCollectionEnabled).thenReturn(true); + when(sdk.checkForUnsentReports).thenAnswer((_) async => false); + when(sdk.sendUnsentReports).thenAnswer((_) async {}); + when(sdk.deleteUnsentReports).thenAnswer((_) async {}); + client = FirebaseCrashlyticsClient( + config: const CrashlyticsConfig( + enableAutomaticDataCollection: false, + logBufferSize: 2, + customKeys: {'build': 'test'}, + ), + logger: logger, + crashlytics: sdk, + ); + }); + tearDown(() async { + client.dispose(); + await di.reset(); + }); + + Future exerciseClient() async { + await client.recordError('error', StackTrace.current); + await client.recordFlutterFatalError( + 'fatal', + StackTrace.current, + context: {'screen': 'home'}, + ); + await client.log('log'); + await client.setUserIdentifier('user'); + await client.setUserMetadata( + const UserMetadata( + userId: 'user', + email: 'test@example.test', + name: 'Test', + customAttributes: {'role': 'tester'}, + ), + ); + await client.setCustomKey('key', 'value'); + await client.setCustomKeys({'key': 'value'}); + await client.setCrashlyticsCollectionEnabled(false); + await client.sendUnsentReports(); + await client.deleteUnsentReports(); + await client.checkForUnsentReports(); + } + + test( + 'invalid metadata is contained and startup SDK errors propagate', + () async { + await client.initialize(); + final metadata = _Metadata(); + when(() => metadata.userId).thenThrow(StateError('invalid metadata')); + await client.setUserMetadata(metadata); + verify(() => logger.e(any())).called(1); + di.register(logger); + when( + () => sdk.setCrashlyticsCollectionEnabled(any()), + ).thenThrow(StateError('startup')); + await expectLater(crash.init(crashlytics: sdk), throwsStateError); + expect(di.has(), isFalse); + expect(di.has(), isFalse); + when( + () => sdk.setCrashlyticsCollectionEnabled(any()), + ).thenAnswer((_) async {}); + await crash.init(crashlytics: sdk); + expect(di.has(), isTrue); + }, + ); + + test('before initialization operations safely skip SDK calls', () async { + await exerciseClient(); + expect(client.isCrashlyticsCollectionEnabled, isFalse); + verifyNever(() => sdk.log(any())); + }); + + test('initialization applies custom keys and can be called twice', () async { + await client.initialize(); + await client.initialize(); + verify(() => sdk.setCustomKey('build', 'test')).called(1); + expect(client.isCrashlyticsCollectionEnabled, isTrue); + await exerciseClient(); + await client.log('second'); + await client.log('third'); + expect(client.bufferedLogs, hasLength(2)); + expect(client.bufferedLogs.last, endsWith('third')); + client.clearLogBuffer(); + expect(client.bufferedLogs, isEmpty); + }); + + test('SDK failures are contained after initialization', () async { + await client.initialize(); + when( + () => sdk.setCrashlyticsCollectionEnabled(any()), + ).thenThrow(StateError('sdk')); + when(() => sdk.setCustomKey(any(), any())).thenThrow(StateError('sdk')); + when(() => sdk.setUserIdentifier(any())).thenThrow(StateError('sdk')); + when(() => sdk.log(any())).thenThrow(StateError('sdk')); + when( + () => sdk.recordError( + any(), + any(), + fatal: any(named: 'fatal'), + information: any(named: 'information'), + ), + ).thenThrow(StateError('sdk')); + when(sdk.checkForUnsentReports).thenThrow(StateError('sdk')); + when(sdk.sendUnsentReports).thenThrow(StateError('sdk')); + when(sdk.deleteUnsentReports).thenThrow(StateError('sdk')); + await exerciseClient(); + expect(await client.checkForUnsentReports(), isFalse); + }); + + test('failed initialization remains retryable', () async { + when( + () => sdk.setCrashlyticsCollectionEnabled(any()), + ).thenThrow(StateError('sdk')); + await expectLater(client.initialize(), throwsStateError); + expect(client.isCrashlyticsCollectionEnabled, isFalse); + when( + () => sdk.setCrashlyticsCollectionEnabled(any()), + ).thenAnswer((_) async {}); + await client.initialize(); + expect(client.isCrashlyticsCollectionEnabled, isTrue); + }); + + test('global handlers are chained and restored when disposed', () async { + final previousFlutter = FlutterError.onError; + final previousPlatform = PlatformDispatcher.instance.onError; + var flutterCalls = 0; + var platformCalls = 0; + void flutterHandler(FlutterErrorDetails details) { + flutterCalls++; + } + + bool platformHandler(Object error, StackTrace stack) { + platformCalls++; + return true; + } + + FlutterError.onError = flutterHandler; + PlatformDispatcher.instance.onError = platformHandler; + try { + client = FirebaseCrashlyticsClient( + config: const CrashlyticsConfig(), + logger: logger, + crashlytics: sdk, + ); + await client.initialize(); + FlutterError.onError!(FlutterErrorDetails(exception: StateError('test'))); + expect( + PlatformDispatcher.instance.onError!( + StateError('test'), + StackTrace.current, + ), + isTrue, + ); + await pumpEventQueue(); + expect(flutterCalls, 1); + expect(platformCalls, 1); + client.dispose(); + expect(FlutterError.onError, same(flutterHandler)); + expect(PlatformDispatcher.instance.onError, same(platformHandler)); + } finally { + FlutterError.onError = previousFlutter; + PlatformDispatcher.instance.onError = previousPlatform; + } + }); + + for (final hasReports in [false, true]) { + test('module initializes with pending reports=$hasReports', () async { + di.register(logger); + when(sdk.checkForUnsentReports).thenAnswer((_) async => hasReports); + await crash.init( + config: const CrashlyticsConfig(enableAutomaticDataCollection: false), + crashlytics: sdk, + ); + expect(di.has(), isTrue); + if (hasReports) verify(sdk.sendUnsentReports).called(1); + }); + } + + test('equal config values have equal hashes regardless of map order', () { + const first = CrashlyticsConfig(customKeys: {'a': 1, 'b': 2}); + const second = CrashlyticsConfig(customKeys: {'b': 2, 'a': 1}); + expect(first, second); + expect(first.hashCode, second.hashCode); + expect({first, second}, hasLength(1)); + }); +} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/test/models_test.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/test/models_test.dart new file mode 100644 index 0000000..e72d0ec --- /dev/null +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/test/models_test.dart @@ -0,0 +1,78 @@ +import 'package:crashlytics/crashlytics.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + test( + 'user metadata value equality is order-independent and agrees with hashing', + () { + final user = UserMetadata( + userId: 'user', + email: 'example@test', + name: 'Tester', + customAttributes: {'a': 1, 'b': 2}, + ); + final equal = user.copyWith(customAttributes: {'b': 2, 'a': 1}); + expect(user, user); + expect(user, equal); + expect(user.hashCode, equal.hashCode); + expect(user.copyWith(), user); + expect(user.toMap()['userId'], 'user'); + expect(user.toString(), contains('Tester')); + expect(user, isNot(user.copyWith(customAttributes: {}))); + expect(user, isNot(user.copyWith(customAttributes: {'a': 1, 'b': 3}))); + expect(user, isNot(user.copyWith(userId: 'another'))); + }, + ); + + test( + 'crash reports preserve fields, serialize and hash equivalent errors', + () { + final report = CrashReport( + exception: StateError('failure'), + stackTrace: StackTrace.fromString('trace'), + fatal: true, + timestamp: DateTime(2026), + customKeys: {'build': 'test'}, + logs: ['first'], + userMetadata: {'userId': 'user'}, + ); + final equal = report.copyWith( + exception: StateError('failure'), + stackTrace: StackTrace.fromString('trace'), + ); + expect(report, report); + expect(report, equal); + expect(report.hashCode, equal.hashCode); + expect(report.copyWith(), report); + expect(report, isNot(report.copyWith(fatal: false))); + expect(report.toMap()['logs'], ['first']); + expect(report.toMap()['timestamp'], DateTime(2026).toIso8601String()); + expect(report.toString(), contains('failure')); + expect( + report + .copyWith(customKeys: {'new': true}, logs: [], userMetadata: {}) + .customKeys, + {'new': true}, + ); + }, + ); + + test('crash configuration copying retains and overrides each option', () { + const config = CrashlyticsConfig(); + final changed = config.copyWith( + enableInDebugMode: true, + enableAutomaticDataCollection: false, + enableCustomLogs: false, + enableUserMetadata: false, + logBufferSize: 10, + customKeys: {'build': 'test'}, + ); + expect(changed.copyWith(), changed); + expect(changed.hashCode, changed.copyWith().hashCode); + expect(changed.toString(), contains('10')); + expect(changed.enableCustomLogs, isFalse); + expect(changed.enableInDebugMode, isTrue); + expect(changed.toMap()['logBufferSize'], 10); + expect(changed, isNot(config)); + }); +} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{developer_dir}}/lib/src/routes/developer_routes.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{developer_dir}}/lib/src/routes/developer_routes.dart index 2992c41..69233f7 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{developer_dir}}/lib/src/routes/developer_routes.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{developer_dir}}/lib/src/routes/developer_routes.dart @@ -1,5 +1,7 @@ import 'package:core/core.dart' as core; import 'package:developer/src/screens/index.dart'; +import 'package:di/di.dart'; +import 'package:feature_flags/feature_flags.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; @@ -13,6 +15,19 @@ class DeveloperRouter extends core.CoreRouter { GoRoute( path: DeveloperRoutes.developer, name: 'developer-screen', + redirect: (context, state) async { + // Hiding the entry gesture does not protect a directly entered route. + if (!di.has()) return core.CoreRoutes.root; + try { + return await di.get().isEnabled( + 'developer_screen_enabled', + ) + ? null + : core.CoreRoutes.root; + } catch (_) { + return core.CoreRoutes.root; + } + }, builder: (BuildContext context, GoRouterState state) { return const DeveloperScreen(); }, diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{developer_dir}}/lib/src/screens/developer_screen.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{developer_dir}}/lib/src/screens/developer_screen.dart index 9c4cba5..965ffcc 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{developer_dir}}/lib/src/screens/developer_screen.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{developer_dir}}/lib/src/screens/developer_screen.dart @@ -8,6 +8,10 @@ class DeveloperScreen extends StatelessWidget { @override Widget build(BuildContext context) { - return TalkerScreen(talker: di.get().logger as Talker); + final logger = di.get().logger; + if (logger is Talker) return TalkerScreen(talker: logger); + return const Scaffold( + body: Center(child: Text('This logger has no interactive viewer.')), + ); } } diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{developer_dir}}/test/navigation_test.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{developer_dir}}/test/navigation_test.dart new file mode 100644 index 0000000..a872449 --- /dev/null +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{developer_dir}}/test/navigation_test.dart @@ -0,0 +1,127 @@ +import 'package:core/core.dart' as core; +import 'package:developer/developer.dart'; +import 'package:di/di.dart'; +import 'package:feature_flags/feature_flags.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:go_router/go_router.dart'; +import 'package:talker_flutter/talker_flutter.dart'; + +class _PlainLogger implements core.Logger { + @override + Object get logger => this; + @override + void d(String message) {} + @override + void i(String message) {} + @override + void w(String message) {} + @override + void e(String message, [Object? error, StackTrace? stackTrace]) {} +} + +class _Flags implements FeatureFlagProvider { + bool enabled = true; + @override + Future init() async {} + @override + Future getBool(String key, {bool defaultValue = false}) async => + enabled; + @override + void dispose() {} + @override + dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); +} + +void main() { + setUp(core.init); + tearDown(di.reset); + + testWidgets('a custom logger does not need to expose Talker', (tester) async { + await di.reset(); + di.register(_PlainLogger()); + await tester.pumpWidget(const MaterialApp(home: DeveloperScreen())); + expect(find.text('This logger has no interactive viewer.'), findsOneWidget); + }); + + testWidgets('disabled developer gesture remains inert', (tester) async { + final provider = _Flags()..enabled = false; + final service = FeatureFlag( + provider: provider, + logger: di.get(), + ); + await service.init(); + di.register(service, dispose: (service) => service.dispose()); + await tester.pumpWidget( + const MaterialApp(home: OpenDevToolsWrapper(child: Text('Demo'))), + ); + await tester.pumpAndSettle(); + await tester.tap(find.text('Demo')); + await tester.pumpAndSettle(); + expect(find.text('Demo'), findsOneWidget); + expect(find.byType(TalkerScreen), findsNothing); + }); + + testWidgets( + 'direct navigation is denied before feature flags are configured', + (tester) async { + final router = GoRouter( + initialLocation: DeveloperRoutes.developer, + routes: [ + GoRoute(path: '/', builder: (_, _) => const Text('Home')), + ...DeveloperRouter().routes, + ], + ); + addTearDown(router.dispose); + await tester.pumpWidget(MaterialApp.router(routerConfig: router)); + await tester.pumpAndSettle(); + expect(find.text('Home'), findsOneWidget); + expect(find.byType(TalkerScreen), findsNothing); + }, + ); + + for (final visual in [false, true]) { + testWidgets('enabled gesture respects its tap window (visual=$visual)', ( + tester, + ) async { + final provider = _Flags(); + final flags = FeatureFlag( + provider: provider, + logger: di.get(), + ); + await flags.init(); + di.register(flags); + final router = GoRouter( + routes: [ + GoRoute( + path: '/', + builder: (_, _) => Scaffold( + body: Center( + child: OpenDevToolsWrapper( + tapCount: 3, + enableVisualFeedback: visual, + child: const Text('Open tools'), + ), + ), + ), + ), + ...DeveloperRouter().routes, + ], + ); + addTearDown(router.dispose); + await tester.pumpWidget(MaterialApp.router(routerConfig: router)); + await tester.pumpAndSettle(); + await tester.tap(find.text('Open tools')); + await tester.pump(const Duration(seconds: 3)); + await tester.tap(find.text('Open tools')); + await tester.pump(const Duration(milliseconds: 500)); + expect(find.byType(TalkerScreen), findsNothing); + await tester.tap(find.text('Open tools')); + await tester.pump(const Duration(milliseconds: 500)); + await tester.tap(find.text('Open tools')); + await tester.pumpAndSettle(); + expect(find.byType(TalkerScreen), findsOneWidget); + expect(tester.takeException(), isNull); + }); + } +} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{feature_flags_dir}}/lib/feature_flags.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{feature_flags_dir}}/lib/feature_flags.dart index e683947..3cb56ee 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{feature_flags_dir}}/lib/feature_flags.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{feature_flags_dir}}/lib/feature_flags.dart @@ -4,11 +4,13 @@ import 'package:core/logger/logger.dart'; import 'package:di/di.dart'; import 'package:feature_flags/src/feature_flag_service.dart'; import 'package:feature_flags/src/register.dart'; +import 'package:feature_flags/src/feature_flag_provider.dart'; export 'src/index.dart'; /// Initialize the feature flags module and register with DI Future init({ + FeatureFlagProvider? provider, FeatureFlagsConfig config = const FeatureFlagsConfig( fetchTimeout: Duration(seconds: 10), minimumFetchInterval: Duration(minutes: 30), @@ -18,7 +20,7 @@ Future init({ final logger = di.get(); try { logger.i('init feature flags module with Firebase Remote Config'); - await registerFeatureFlagsWithDI(config: config); + await registerFeatureFlagsWithDI(config: config, provider: provider); final service = di.get(); await service.init(); logger.i('Feature flags module initialized with Firebase Remote Config'); diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{feature_flags_dir}}/lib/src/feature_flag_wrapper.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{feature_flags_dir}}/lib/src/feature_flag_wrapper.dart index 56d22a6..dc71ddb 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{feature_flags_dir}}/lib/src/feature_flag_wrapper.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{feature_flags_dir}}/lib/src/feature_flag_wrapper.dart @@ -3,13 +3,14 @@ import 'package:feature_flags/src/feature_flag_service.dart'; import 'package:flutter/material.dart'; /// A wrapper widget that conditionally renders content based on feature flags -class FeatureFlagWrapper extends StatelessWidget { +class FeatureFlagWrapper extends StatefulWidget { const FeatureFlagWrapper({ super.key, required this.flagKey, required this.builder, this.defaultValue = false, this.loading, + this.service, }); /// The feature flag key to check @@ -23,34 +24,61 @@ class FeatureFlagWrapper extends StatelessWidget { /// Widget to show while loading the feature flag value final Widget? loading; + final FeatureFlag? service; + + @override + State createState() => _FeatureFlagWrapperState(); +} + +class _FeatureFlagWrapperState extends State { + late Future _value; + + @override + void initState() { + super.initState(); + _value = _checkFeatureFlag(); + } + + @override + void didUpdateWidget(FeatureFlagWrapper oldWidget) { + super.didUpdateWidget(oldWidget); + if (oldWidget.flagKey != widget.flagKey || + oldWidget.defaultValue != widget.defaultValue || + oldWidget.service != widget.service) { + _value = _checkFeatureFlag(); + } + } @override Widget build(BuildContext context) { return FutureBuilder( - future: _checkFeatureFlag(), + future: _value, builder: (context, snapshot) { // Show loading widget while waiting for feature flag if (snapshot.connectionState == ConnectionState.waiting) { - return loading ?? const SizedBox.shrink(); + return widget.loading ?? const SizedBox.shrink(); } // Get the feature flag value, defaulting to false if there's an error - final isEnabled = snapshot.data ?? defaultValue; + final isEnabled = snapshot.data ?? widget.defaultValue; // Return the widget built by the builder function - return builder(context, isEnabled); + return widget.builder(context, isEnabled); }, ); } Future _checkFeatureFlag() async { try { - final featureFlag = di.get(); - return await featureFlag.isEnabled(flagKey, defaultValue: defaultValue); + final featureFlag = widget.service ?? di.get(); + return await featureFlag.isEnabled( + widget.flagKey, + defaultValue: widget.defaultValue, + ); } catch (e) { // If there's an error accessing the feature flag service, // return the default value - return defaultValue; + return widget.defaultValue; } } } diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{feature_flags_dir}}/lib/src/firebase_remote_config_provider.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{feature_flags_dir}}/lib/src/firebase_remote_config_provider.dart index 7116a8c..00c8a29 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{feature_flags_dir}}/lib/src/firebase_remote_config_provider.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{feature_flags_dir}}/lib/src/firebase_remote_config_provider.dart @@ -1,32 +1,29 @@ import 'package:core/logger/logger.dart'; -import 'package:di/di.dart'; import 'package:feature_flags/feature_flags.dart'; import 'package:firebase_remote_config/firebase_remote_config.dart'; /// Firebase Remote Config implementation of FeatureFlagProvider class FirebaseRemoteConfigProvider implements FeatureFlagProvider { - late final FirebaseRemoteConfig _remoteConfig; + final FirebaseRemoteConfig _remoteConfig; final FeatureFlagsConfig _config; - late final Logger logger; - - FirebaseRemoteConfigProvider({FeatureFlagsConfig? config}) - : _config = - config ?? - const FeatureFlagsConfig( - defaultParameters: {}, - fetchTimeout: Duration(seconds: 10), - minimumFetchInterval: Duration(hours: 1), - ) { - if (di.has()) { - logger = di.get(); - } - } + final Logger logger; + + FirebaseRemoteConfigProvider({ + required FirebaseRemoteConfig remoteConfig, + required this.logger, + FeatureFlagsConfig? config, + }) : _remoteConfig = remoteConfig, + _config = + config ?? + const FeatureFlagsConfig( + defaultParameters: {}, + fetchTimeout: Duration(seconds: 10), + minimumFetchInterval: Duration(hours: 1), + ); @override Future init() async { try { - _remoteConfig = FirebaseRemoteConfig.instance; - // Configure settings await _remoteConfig.setConfigSettings( RemoteConfigSettings( @@ -46,12 +43,6 @@ class FirebaseRemoteConfigProvider implements FeatureFlagProvider { logger.i('Remote Config activated: $activated'); logger.i('Last fetch status: ${_remoteConfig.lastFetchStatus}'); logger.i('Last fetch time: ${_remoteConfig.lastFetchTime}'); - - // Log all current values for debugging - final allValues = _remoteConfig.getAll(); - for (final entry in allValues.entries) { - logger.i('Remote Config - ${entry.key}: ${entry.value.asString()}'); - } } catch (e, stackTrace) { logger.e('Failed to initialize Firebase Remote Config', e, stackTrace); rethrow; @@ -65,13 +56,10 @@ class FirebaseRemoteConfigProvider implements FeatureFlagProvider { @override Future getBool(String key, {bool defaultValue = false}) async { try { - final value = _remoteConfig.getBool(key); final configValue = _remoteConfig.getValue(key); - logger.i( - 'Getting bool flag "$key": value=$value,' - ' source=${configValue.source}', - ); - return value; + return configValue.source == ValueSource.valueStatic + ? defaultValue + : _remoteConfig.getBool(key); } catch (e) { logger.e( 'Failed to get bool flag: $key, using default: $defaultValue', @@ -84,8 +72,9 @@ class FirebaseRemoteConfigProvider implements FeatureFlagProvider { @override Future getString(String key, {String defaultValue = ''}) async { try { - final value = _remoteConfig.getString(key); - return value.isEmpty ? defaultValue : value; + return _remoteConfig.getValue(key).source == ValueSource.valueStatic + ? defaultValue + : _remoteConfig.getString(key); } catch (e) { logger.w('Failed to get string flag: $key, using default: $defaultValue'); return defaultValue; @@ -95,7 +84,9 @@ class FirebaseRemoteConfigProvider implements FeatureFlagProvider { @override Future getInt(String key, {int defaultValue = 0}) async { try { - return _remoteConfig.getInt(key); + return _remoteConfig.getValue(key).source == ValueSource.valueStatic + ? defaultValue + : _remoteConfig.getInt(key); } catch (e) { logger.w('Failed to get int flag: $key, using default: $defaultValue'); return defaultValue; @@ -105,7 +96,9 @@ class FirebaseRemoteConfigProvider implements FeatureFlagProvider { @override Future getDouble(String key, {double defaultValue = 0.0}) async { try { - return _remoteConfig.getDouble(key); + return _remoteConfig.getValue(key).source == ValueSource.valueStatic + ? defaultValue + : _remoteConfig.getDouble(key); } catch (e) { logger.w('Failed to get double flag: $key, using default: $defaultValue'); return defaultValue; diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{feature_flags_dir}}/lib/src/register.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{feature_flags_dir}}/lib/src/register.dart index 0cc8c04..40254fe 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{feature_flags_dir}}/lib/src/register.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{feature_flags_dir}}/lib/src/register.dart @@ -3,17 +3,29 @@ import 'package:di/di.dart'; import 'package:feature_flags/src/feature_flag_provider.dart'; import 'package:feature_flags/src/feature_flag_service.dart'; import 'package:feature_flags/src/firebase_remote_config_provider.dart'; +import 'package:firebase_remote_config/firebase_remote_config.dart'; /// Register feature flags services with dependency injection /// -Future registerFeatureFlagsWithDI({FeatureFlagsConfig? config}) async { +Future registerFeatureFlagsWithDI({ + FeatureFlagsConfig? config, + FeatureFlagProvider? provider, +}) async { final logger = di.get(); // Register the provider - final provider = FirebaseRemoteConfigProvider(config: config); - di.register(provider, dispose: (p) => p.dispose()); + final selectedProvider = + provider ?? + FirebaseRemoteConfigProvider( + config: config, + logger: logger, + remoteConfig: FirebaseRemoteConfig.instance, + ); + // The service owns provider disposal; registering it twice would dispose + // platform subscriptions twice when the container is reset. + di.register(selectedProvider); // Register the service - final service = FeatureFlag(provider: provider, logger: logger); + final service = FeatureFlag(provider: selectedProvider, logger: logger); di.register(service, dispose: (s) => s.dispose()); } diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{feature_flags_dir}}/pubspec.yaml b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{feature_flags_dir}}/pubspec.yaml index 60d0a14..2ae6a61 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{feature_flags_dir}}/pubspec.yaml +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{feature_flags_dir}}/pubspec.yaml @@ -18,6 +18,7 @@ dependencies: path: ../di dev_dependencies: + mocktail: ^1.0.4 flutter_test: sdk: flutter flutter_lints: ^5.0.0 diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{feature_flags_dir}}/test/feature_flags_test.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{feature_flags_dir}}/test/feature_flags_test.dart new file mode 100644 index 0000000..8192d3c --- /dev/null +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{feature_flags_dir}}/test/feature_flags_test.dart @@ -0,0 +1,216 @@ +import 'package:core/core.dart'; +import 'package:di/di.dart'; +import 'package:feature_flags/feature_flags.dart'; +import 'package:feature_flags/feature_flags.dart' as flags; +import 'package:firebase_remote_config/firebase_remote_config.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; + +class _Logger extends Mock implements Logger {} + +class _Provider extends Mock implements FeatureFlagProvider {} + +class _RemoteConfig extends Mock implements FirebaseRemoteConfig {} + +void main() { + late _Logger logger; + late _Provider provider; + late FeatureFlag service; + setUp(() { + logger = _Logger(); + provider = _Provider(); + when(provider.init).thenAnswer((_) async {}); + service = FeatureFlag(provider: provider, logger: logger); + }); + tearDown(di.reset); + + test('reads require initialization; lifecycle is idempotent', () async { + expect(service.isInitialized, isFalse); + await expectLater(service.isEnabled('flag'), throwsStateError); + await service.init(); + await service.init(); + verify(provider.init).called(1); + expect(service.isInitialized, isTrue); + service.dispose(); + verify(provider.dispose).called(1); + expect(service.isInitialized, isFalse); + }); + + test('failed initialization propagates and can be retried', () async { + when(provider.init).thenThrow(StateError('offline')); + await expectLater(service.init(), throwsStateError); + expect(service.isInitialized, isFalse); + when(provider.init).thenAnswer((_) async {}); + await service.init(); + expect(service.isInitialized, isTrue); + }); + + test('typed reads preserve caller defaults', () async { + await service.init(); + when( + () => provider.getBool('b', defaultValue: true), + ).thenAnswer((_) async => true); + when( + () => provider.getString('s', defaultValue: 'fallback'), + ).thenAnswer((_) async => 'value'); + when( + () => provider.getInt('i', defaultValue: 3), + ).thenAnswer((_) async => 5); + when( + () => provider.getDouble('d', defaultValue: 1.5), + ).thenAnswer((_) async => 2.5); + expect(await service.isEnabled('b', defaultValue: true), isTrue); + expect(await service.getConfig('s', defaultValue: 'fallback'), 'value'); + expect(await service.getIntConfig('i', defaultValue: 3), 5); + expect(await service.getDoubleConfig('d', defaultValue: 1.5), 2.5); + }); + + test( + 'module injection initializes and disposes the provider exactly once', + () async { + di.register(logger); + await flags.init(provider: provider); + expect(di.get().isInitialized, isTrue); + await di.reset(); + verify(provider.dispose).called(1); + }, + ); + + test('module initialization failures propagate', () async { + di.register(logger); + when(provider.init).thenThrow(StateError('offline')); + await expectLater(flags.init(provider: provider), throwsStateError); + }); + + testWidgets('wrapper caches reads until its inputs change', (tester) async { + await service.init(); + when( + () => provider.getBool('flag', defaultValue: false), + ).thenAnswer((_) async => true); + when( + () => provider.getBool('other', defaultValue: false), + ).thenAnswer((_) async => false); + Widget view(String key) => MaterialApp( + home: FeatureFlagWrapper( + service: service, + flagKey: key, + loading: const Text('Loading'), + builder: (_, value) => Text('Enabled: $value'), + ), + ); + await tester.pumpWidget(view('flag')); + expect(find.text('Loading'), findsOneWidget); + await tester.pumpAndSettle(); + expect(find.text('Enabled: true'), findsOneWidget); + await tester.pumpWidget(view('flag')); + await tester.pumpAndSettle(); + verify(() => provider.getBool('flag', defaultValue: false)).called(1); + await tester.pumpWidget(view('other')); + await tester.pumpAndSettle(); + expect(find.text('Enabled: false'), findsOneWidget); + }); + + testWidgets('wrapper uses fallback when the service is unavailable', ( + tester, + ) async { + await tester.pumpWidget( + MaterialApp( + home: FeatureFlagWrapper( + flagKey: 'flag', + defaultValue: true, + builder: (_, value) => Text('Enabled: $value'), + ), + ), + ); + await tester.pumpAndSettle(); + expect(find.text('Enabled: true'), findsOneWidget); + }); + + group('Firebase adapter', () { + late _RemoteConfig remote; + late FirebaseRemoteConfigProvider adapter; + setUp(() { + remote = _RemoteConfig(); + adapter = FirebaseRemoteConfigProvider( + remoteConfig: remote, + logger: logger, + ); + registerFallbackValue( + RemoteConfigSettings( + fetchTimeout: const Duration(seconds: 10), + minimumFetchInterval: const Duration(hours: 1), + ), + ); + when(() => remote.setConfigSettings(any())).thenAnswer((_) async {}); + when(() => remote.setDefaults(any())).thenAnswer((_) async {}); + when(remote.fetchAndActivate).thenAnswer((_) async => true); + when( + () => remote.lastFetchStatus, + ).thenReturn(RemoteConfigFetchStatus.success); + when(() => remote.lastFetchTime).thenReturn(DateTime(2026)); + when( + () => remote.onConfigUpdated, + ).thenAnswer((_) => const Stream.empty()); + }); + + test('configures Firebase and exposes update metadata', () async { + await adapter.init(); + verify(() => remote.setDefaults({})).called(1); + expect(adapter.config.defaultParameters, isEmpty); + expect(adapter.lastFetchTime, DateTime(2026)); + expect(adapter.lastFetchStatus, RemoteConfigFetchStatus.success); + expect(await adapter.onConfigUpdated.toList(), isEmpty); + adapter.dispose(); + }); + + test('initialization failure propagates', () async { + when(remote.fetchAndActivate).thenThrow(StateError('offline')); + await expectLater(adapter.init(), throwsStateError); + }); + + test('missing keys respect nonzero and true defaults', () async { + when( + () => remote.getValue(any()), + ).thenReturn(RemoteConfigValue([], ValueSource.valueStatic)); + expect(await adapter.getBool('missing', defaultValue: true), isTrue); + expect( + await adapter.getString('missing', defaultValue: 'fallback'), + 'fallback', + ); + expect(await adapter.getInt('missing', defaultValue: 9), 9); + expect(await adapter.getDouble('missing', defaultValue: 1.5), 1.5); + expect(await adapter.hasFlag('missing'), isFalse); + }); + + test( + 'configured false, zero and empty values remain valid values', + () async { + when( + () => remote.getValue(any()), + ).thenReturn(RemoteConfigValue([], ValueSource.valueRemote)); + when(() => remote.getBool(any())).thenReturn(false); + when(() => remote.getString(any())).thenReturn(''); + when(() => remote.getInt(any())).thenReturn(0); + when(() => remote.getDouble(any())).thenReturn(0); + expect(await adapter.getBool('key', defaultValue: true), isFalse); + expect(await adapter.getString('key', defaultValue: 'fallback'), ''); + expect(await adapter.getInt('key', defaultValue: 9), 0); + expect(await adapter.getDouble('key', defaultValue: 1.5), 0); + expect(await adapter.hasFlag('key'), isTrue); + }, + ); + + test('SDK read failures return defaults', () async { + when(() => remote.getValue(any())).thenThrow(StateError('unavailable')); + expect(await adapter.getBool('key', defaultValue: true), isTrue); + expect( + await adapter.getString('key', defaultValue: 'fallback'), + 'fallback', + ); + expect(await adapter.getInt('key', defaultValue: 9), 9); + expect(await adapter.getDouble('key', defaultValue: 1.5), 1.5); + expect(await adapter.hasFlag('key'), isFalse); + }); + }); +} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{network_dir}}/lib/network.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{network_dir}}/lib/network.dart index 4cabe41..f2b26ca 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{network_dir}}/lib/network.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{network_dir}}/lib/network.dart @@ -41,14 +41,15 @@ Future registerNetworkWithDI( '🔓 No AuthTokenProvider found in DI, creating unauthenticated client', ); } - } else if (config.authTokenProvider != null) { + } else if (useAuthentication && config.authTokenProvider != null) { authTokenProvider = config.authTokenProvider; logger.d('🔐 Using provided AuthTokenProvider'); } // Create network config with auth provider if available late final NetworkConfig finalConfig; - if (authTokenProvider != null && config.authTokenProvider == null) { + if (!useAuthentication || + (authTokenProvider != null && config.authTokenProvider == null)) { // Create a new config with the auth provider finalConfig = DefaultNetworkConfig( baseUrl: config.baseUrl, @@ -63,7 +64,7 @@ Future registerNetworkWithDI( finalConfig = config; } - final networkClient = DioNetworkClient(finalConfig); + final networkClient = DioNetworkClient(finalConfig, logger: logger); di.register( networkClient, dispose: (client) => client.dispose(), diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{network_dir}}/lib/src/client/dio_network_client.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{network_dir}}/lib/src/client/dio_network_client.dart index 5c5712c..6af07cb 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{network_dir}}/lib/src/client/dio_network_client.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{network_dir}}/lib/src/client/dio_network_client.dart @@ -1,7 +1,6 @@ import 'dart:io'; import 'package:core/core.dart'; -import 'package:di/di.dart'; import 'package:dio/dio.dart'; import 'package:flutter/foundation.dart'; import 'package:localization/localization.dart'; @@ -10,17 +9,18 @@ import 'package:network/src/config/network_config.dart'; import 'package:network/src/exceptions/network_exceptions.dart'; import 'package:network/src/interceptors/auth_interceptor.dart'; import 'package:network/src/models/network_response.dart'; -import 'package:talker_dio_logger/talker_dio_logger.dart'; -import 'package:talker_flutter/talker_flutter.dart'; +import 'package:network/src/interceptors/logging_interceptor.dart'; class DioNetworkClient implements NetworkClient { - DioNetworkClient(this._config) : _dio = Dio() { + DioNetworkClient(this._config, {required Logger logger, Dio? dio}) + : _logger = logger, + _dio = dio ?? Dio() { _setupDio(); } final NetworkConfig _config; final Dio _dio; - final Logger _logger = di.get(); + final Logger _logger; void _setupDio() { _dio.options = BaseOptions( @@ -34,20 +34,14 @@ class DioNetworkClient implements NetworkClient { // Add authentication interceptor if token provider is available if (_config.authTokenProvider != null) { - _dio.interceptors.add(AuthInterceptor(_config.authTokenProvider!)); + _dio.interceptors.add( + AuthInterceptor(_config.authTokenProvider!, dio: _dio, logger: _logger), + ); _logger.d('🔐 Auth interceptor added to network client'); } if (_config.enableLogging) { - _dio.interceptors.add( - TalkerDioLogger( - talker: di.get().logger as Talker, - settings: TalkerDioLoggerSettings( - printResponseData: true, - printResponseTime: true, - ), - ), - ); + _dio.interceptors.add(LoggingInterceptor(logger: _logger)); } } @@ -165,15 +159,15 @@ class DioNetworkClient implements NetworkClient { if (responseData.containsKey('success')) { if (responseData['success'] == true) { return SuccessResponse.fromJson({ + ...responseData, 'statusCode': response.statusCode ?? 200, 'headers': response.headers.map, - ...responseData, }, fromJsonT); } else { - ErrorResponse.fromJson({ + return ErrorResponse.fromJson({ + ...responseData, 'statusCode': response.statusCode ?? 500, 'headers': response.headers.map, - ...responseData, }); } } @@ -181,14 +175,16 @@ class DioNetworkClient implements NetworkClient { // Ideally, should not reach here if the API follows the // standard response format - _logger.w('Invalid response format: ${response.data}'); + _logger.d('Decoding response without an API envelope'); // Fallback to a generic success response - return SuccessResponse.fromJson({ - 'statusCode': response.statusCode ?? 200, - 'headers': response.headers.map, - 'data': response.data, - }, (value) => value as T); + return SuccessResponse( + statusCode: response.statusCode ?? 200, + headers: response.headers.map, + success: true, + timestamp: DateTime.now().toIso8601String(), + data: fromJsonT(response.data), + ); } catch (e, s) { _logger.e('Error parsing response', e); return ErrorResponse( @@ -228,9 +224,9 @@ class DioNetworkClient implements NetworkClient { responseData.containsKey('success') && responseData['success'] == false) { return ErrorResponse.fromJson({ + ...responseData, 'statusCode': response?.statusCode ?? 500, 'headers': response?.headers.map, - ...responseData, }); } } catch (e) { @@ -296,7 +292,7 @@ class DioNetworkClient implements NetworkClient { T handleResponse(final NetworkResponse response) { switch (response) { case SuccessResponse(): - return response.data!; + return response.data; case ErrorResponse(): throw UnknownNetworkException( message: response.message ?? strings.errors.network_error, diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{network_dir}}/lib/src/interceptors/auth_interceptor.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{network_dir}}/lib/src/interceptors/auth_interceptor.dart index 8aed94b..5ae76ff 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{network_dir}}/lib/src/interceptors/auth_interceptor.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{network_dir}}/lib/src/interceptors/auth_interceptor.dart @@ -1,13 +1,24 @@ +import 'dart:async'; + import 'package:core/core.dart'; -import 'package:di/di.dart'; import 'package:dio/dio.dart'; import 'package:network/src/auth/auth_token_provider.dart'; +/// Adds session credentials and retries an authenticated request at most once. class AuthInterceptor extends Interceptor { - AuthInterceptor(this._authTokenProvider) : _logger = di.get(); + AuthInterceptor( + this._authTokenProvider, { + required Dio dio, + required Logger logger, + }) : _dio = dio, + _logger = logger; final AuthTokenProvider _authTokenProvider; + final Dio _dio; final Logger _logger; + Future? _refreshing; + static const _managed = 'nonstop.auth.managed'; + static const _retried = 'nonstop.auth.retried'; @override void onRequest( @@ -15,59 +26,68 @@ class AuthInterceptor extends Interceptor { RequestInterceptorHandler handler, ) async { try { - // Skip authentication for requests that already have authorization header - if (options.headers.containsKey('Authorization')) { + final origin = Uri.parse(options.baseUrl); + if (!origin.hasScheme || options.uri.origin != origin.origin) { + handler.next(options); + return; + } + if (options.headers.keys.any( + (key) => key.toLowerCase() == 'authorization', + )) { handler.next(options); return; } - final token = await _authTokenProvider.getValidToken(); if (token != null) { options.headers['Authorization'] = 'Bearer $token'; - _logger.d('🔐 Added Bearer token to request: ${options.uri}'); - } else { - _logger.d('🔓 No auth token available for request: ${options.uri}'); + options.extra[_managed] = true; } - handler.next(options); - } catch (e) { - _logger.e('🚨 Error adding auth token to request', e); + } catch (error) { + _logger.e('Unable to obtain an authentication token', error); handler.next(options); } } + Future _refresh() async { + if (_refreshing != null) return _refreshing; + final pending = _authTokenProvider.refreshToken(); + _refreshing = pending; + try { + return await pending; + } finally { + _refreshing = null; + } + } + @override void onError(DioException err, ErrorInterceptorHandler handler) async { - // Handle 401 Unauthorized - token might be expired - if (err.response?.statusCode == 401) { - _logger.w('🔐 Received 401 Unauthorized, attempting token refresh'); - - try { - final newToken = await _authTokenProvider.refreshToken(); - if (newToken != null) { - _logger.i('🔄 Token refreshed successfully, retrying request'); - - // Clone the request with new token - final requestOptions = err.requestOptions; - requestOptions.headers['Authorization'] = 'Bearer $newToken'; - - // Retry the request - final response = await Dio().fetch(requestOptions); - handler.resolve(response); - return; - } else { - _logger.w('❌ Token refresh failed, user needs to re-authenticate'); - } - } catch (refreshError) { - _logger.e('🚨 Error during token refresh', refreshError); - } + final request = err.requestOptions; + if (err.response?.statusCode != 401 || + request.extra[_managed] != true || + request.extra[_retried] == true || + request.data is Stream) { + handler.next(err); + return; } - - // Handle 403 Forbidden - user doesn't have permission - if (err.response?.statusCode == 403) { - _logger.w('🚫 Received 403 Forbidden, insufficient permissions'); + try { + final token = await _refresh(); + if (token != null) { + final response = await _dio.fetch( + request.copyWith( + headers: {...request.headers, 'Authorization': 'Bearer $token'}, + extra: {...request.extra, _retried: true}, + data: request.data is FormData + ? (request.data as FormData).clone() + : request.data, + ), + ); + handler.resolve(response); + return; + } + } catch (refreshError) { + _logger.e('Authentication retry failed', refreshError); } - handler.next(err); } } diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{network_dir}}/lib/src/interceptors/logging_interceptor.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{network_dir}}/lib/src/interceptors/logging_interceptor.dart index 897650e..87c9289 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{network_dir}}/lib/src/interceptors/logging_interceptor.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{network_dir}}/lib/src/interceptors/logging_interceptor.dart @@ -1,44 +1,33 @@ import 'package:core/core.dart'; -import 'package:di/di.dart'; import 'package:dio/dio.dart'; class LoggingInterceptor extends Interceptor { - LoggingInterceptor() : _logger = di.get(); + LoggingInterceptor({required Logger logger}) : _logger = logger; final Logger _logger; @override void onRequest(RequestOptions options, RequestInterceptorHandler handler) { - _logger.d('🚀 Request: ${options.method} ${options.uri}'); - _logger.d('Headers: ${options.headers}'); - if (options.data != null) { - _logger.d('Data: ${options.data}'); - } - if (options.queryParameters.isNotEmpty) { - _logger.d('Query Parameters: ${options.queryParameters}'); - } + // Credentials and personal data can occur in headers, query strings and + // bodies. Log only the HTTP method and path by default. + _logger.d('Request: ${options.method} ${options.uri.path}'); super.onRequest(options, handler); } @override void onResponse(Response response, ResponseInterceptorHandler handler) { _logger.d( - '✅ Response: ${response.statusCode} ${response.requestOptions.uri}', + 'Response: ${response.statusCode} ${response.requestOptions.uri.path}', ); - _logger.d('Response Data: ${response.data}'); super.onResponse(response, handler); } @override void onError(DioException err, ErrorInterceptorHandler handler) { _logger.e( - '❌ Error: ${err.response?.statusCode} ${err.requestOptions.uri}', - err, - err.stackTrace, + 'Network error: ${err.type.name} ${err.response?.statusCode} ' + '${err.requestOptions.uri.path}', ); - if (err.response?.data != null) { - _logger.e('Error Data: ${err.response?.data}'); - } super.onError(err, handler); } } diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{network_dir}}/pubspec.yaml b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{network_dir}}/pubspec.yaml index 6fe7754..61fa86c 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{network_dir}}/pubspec.yaml +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{network_dir}}/pubspec.yaml @@ -22,6 +22,7 @@ dependencies: path: ../di dev_dependencies: + mocktail: ^1.0.4 flutter_test: sdk: flutter flutter_lints: ^5.0.0 diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{network_dir}}/test/dio_network_client_test.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{network_dir}}/test/dio_network_client_test.dart new file mode 100644 index 0000000..0b0132f --- /dev/null +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{network_dir}}/test/dio_network_client_test.dart @@ -0,0 +1,496 @@ +import 'dart:convert'; +import 'dart:async'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:core/core.dart'; +import 'package:dio/dio.dart'; +import 'package:di/di.dart'; +import 'package:network/network.dart' as network; +import 'package:flutter_test/flutter_test.dart'; +import 'package:network/network.dart'; + +class _Logger implements Logger { + final messages = []; + @override + Object get logger => this; + @override + void d(String message) => messages.add(message); + @override + void i(String message) => messages.add(message); + @override + void w(String message) => messages.add(message); + @override + void e(String message, [Object? error, StackTrace? stackTrace]) => + messages.add(message); +} + +class _Adapter implements HttpClientAdapter { + Object? body; + int status = 200; + final statuses = []; + bool closed = false; + Object? failure; + final requests = []; + + @override + Future fetch( + RequestOptions options, + Stream? requestStream, + Future? cancelFuture, + ) async { + requests.add(options); + if (failure != null) throw failure!; + return ResponseBody.fromString( + jsonEncode(body), + statuses.isEmpty ? status : statuses.removeAt(0), + headers: { + Headers.contentTypeHeader: [Headers.jsonContentType], + }, + ); + } + + @override + void close({bool force = false}) => closed = true; +} + +class _Tokens implements AuthTokenProvider { + int refreshes = 0; + String? refreshed = 'new-token'; + bool failRefresh = false; + bool failRead = false; + @override + Future getValidToken() async { + if (failRead) throw StateError('token unavailable'); + return 'old-token'; + } + + @override + Future refreshToken() async { + refreshes++; + if (failRefresh) throw StateError('refresh failed'); + return refreshed; + } + + @override + dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); +} + +class _DelayedTokens extends _Tokens { + final pending = Completer(); + @override + Future refreshToken() { + refreshes++; + return pending.future; + } +} + +void main() { + late _Adapter adapter; + late _Logger logger; + late DioNetworkClient client; + + setUp(() { + adapter = _Adapter(); + logger = _Logger(); + client = DioNetworkClient( + DefaultNetworkConfig(baseUrl: 'https://example.test'), + logger: logger, + dio: Dio()..httpClientAdapter = adapter, + ); + }); + tearDown(() => client.dispose()); + + test('concurrent unauthorized requests share one token refresh', () async { + final tokens = _DelayedTokens(); + adapter.statuses.addAll([401, 401, 200, 200]); + final authenticated = DioNetworkClient( + DefaultNetworkConfig( + baseUrl: 'https://example.test', + authTokenProvider: tokens, + ), + logger: logger, + dio: Dio()..httpClientAdapter = adapter, + ); + addTearDown(authenticated.dispose); + final first = authenticated.get( + '/first', + fromJsonT: (json) => json, + ); + final second = authenticated.get( + '/second', + fromJsonT: (json) => json, + ); + await pumpEventQueue(); + expect(tokens.refreshes, 1); + tokens.pending.complete('new-token'); + final results = await Future.wait([first, second]); + expect(results.every((r) => r.isSuccess), isTrue); + expect(adapter.requests, hasLength(4)); + }); + + test( + 'multipart retries clone consumed bodies; streams are never replayed', + () async { + final tokens = _Tokens(); + final authenticated = DioNetworkClient( + DefaultNetworkConfig( + baseUrl: 'https://example.test', + authTokenProvider: tokens, + ), + logger: logger, + dio: Dio()..httpClientAdapter = adapter, + ); + addTearDown(authenticated.dispose); + adapter.statuses.addAll([401, 200]); + final form = FormData.fromMap({'field': 'value'}); + expect( + (await authenticated.post( + '/file', + data: form, + fromJsonT: (json) => json, + )).isSuccess, + isTrue, + ); + expect(adapter.requests.last.data, isNot(same(form))); + adapter.status = 401; + await expectLater( + authenticated.post( + '/stream', + data: Stream.value([1, 2]), + fromJsonT: (json) => json, + ), + throwsA(isA()), + ); + expect(tokens.refreshes, 1); + }, + ); + + test('API payload cannot override HTTP status or response headers', () async { + adapter.body = { + 'success': true, + 'timestamp': 'now', + 'data': 1, + 'statusCode': 500, + 'headers': { + 'fake': ['value'], + }, + }; + final response = await client.get( + '/value', + fromJsonT: (json) => json as int, + ); + expect(response.statusCode, 200); + expect(response.headers, isNot(contains('fake'))); + }); + + for (final (status, expected) in <(int, Type)>[ + (400, BadRequestException), + (403, ForbiddenException), + (404, NotFoundException), + (409, ConflictException), + (422, UnprocessableEntityException), + (500, InternalServerException), + (502, InternalServerException), + (503, InternalServerException), + (504, InternalServerException), + (418, UnknownNetworkException), + ]) { + test( + 'HTTP $status maps to $expected and preserves API error details', + () async { + adapter.status = status; + adapter.body = { + 'success': false, + 'timestamp': '2026-01-01', + 'error': {'code': 'FAIL', 'message': 'Request rejected'}, + }; + await expectLater( + client.get('/request', fromJsonT: (json) => json), + throwsA( + predicate( + (e) => + e.runtimeType == expected && e.message == 'Request rejected', + ), + ), + ); + }, + ); + } + + test('every transport failure maps to a domain exception', () async { + for (final (type, error, expected) in <(DioExceptionType, Object?, Type)>[ + (DioExceptionType.connectionTimeout, null, ConnectionTimeoutException), + (DioExceptionType.receiveTimeout, null, ReceiveTimeoutException), + (DioExceptionType.sendTimeout, null, SendTimeoutException), + ( + DioExceptionType.connectionError, + const SocketException('offline'), + NoInternetConnectionException, + ), + (DioExceptionType.connectionError, null, UnknownNetworkException), + (DioExceptionType.cancel, null, UnknownNetworkException), + ]) { + adapter.failure = DioException( + requestOptions: RequestOptions(path: '/request'), + type: type, + error: error, + ); + await expectLater( + client.get('/request', fromJsonT: (json) => json), + throwsA(predicate((e) => e.runtimeType == expected)), + ); + } + }); + + test( + 'write verbs consistently propagate transport errors and malformed envelopes do not hide HTTP failures', + () async { + adapter.status = 500; + adapter.body = {'success': false, 'error': 'invalid shape'}; + for (final operation in [ + () => client.post('/request', fromJsonT: (j) => j), + () => client.put('/request', fromJsonT: (j) => j), + () => client.patch('/request', fromJsonT: (j) => j), + () => client.delete('/request', fromJsonT: (j) => j), + ]) { + await expectLater(operation(), throwsA(isA())); + } + }, + ); + + test( + 'auth tokens stay on the configured origin and provider failures do not crash requests', + () async { + final tokens = _Tokens(); + final transport = Dio()..httpClientAdapter = adapter; + final authenticated = DioNetworkClient( + DefaultNetworkConfig( + baseUrl: 'https://example.test', + authTokenProvider: tokens, + ), + logger: logger, + dio: transport, + ); + addTearDown(authenticated.dispose); + await authenticated.get( + 'https://external.test/image', + fromJsonT: (j) => j, + ); + expect(adapter.requests.last.headers, isNot(contains('Authorization'))); + tokens.failRead = true; + await authenticated.get('/image', fromJsonT: (j) => j); + expect(adapter.requests.last.headers, isNot(contains('Authorization'))); + }, + ); + + test( + 'module respects explicit disable, injected credentials and unconfigured auth', + () async { + addTearDown(di.reset); + for (final supplied in [false, true]) { + for (final enabled in [false, true]) { + await di.reset(); + di.register(logger); + final tokens = _Tokens(); + await network.init( + config: DefaultNetworkConfig( + baseUrl: 'https://example.test', + authTokenProvider: supplied ? tokens : null, + ), + useAuthentication: enabled, + ); + expect( + di.get().authTokenProvider, + supplied && enabled ? same(tokens) : isNull, + ); + } + } + await di.reset(); + di.register(logger); + final tokens = _Tokens(); + di.register(tokens); + await network.init( + config: DefaultNetworkConfig(baseUrl: 'https://example.test'), + ); + expect(di.get().authTokenProvider, same(tokens)); + }, + ); + + test('plain JSON uses the supplied decoder', () async { + adapter.body = {'count': 7}; + final response = await client.get( + '/count', + fromJsonT: (json) => (json as Map)['count'] as int, + ); + expect(response.isSuccess, isTrue); + expect(client.handleResponse(response), 7); + expect(client.handleSuccessResponse(response).data, 7); + }); + + test('API errors in HTTP 200 stay errors', () async { + adapter.body = { + 'success': false, + 'timestamp': '2026-01-01', + 'message': 'Cannot save', + 'error': {'code': 'INVALID', 'message': 'Invalid input'}, + }; + final response = await client.post( + '/save', + fromJsonT: (json) => json as String, + ); + expect(response, isA>()); + expect(response.isSuccess, isFalse); + expect((response as ErrorResponse).error.code, 'INVALID'); + expect( + () => client.handleResponse(response), + throwsA(isA()), + ); + }); + + test('envelope success decodes data and retains metadata', () async { + adapter.body = { + 'success': true, + 'timestamp': '2026-01-01', + 'data': {'count': 3}, + }; + final response = await client.get( + '/count', + fromJsonT: (json) => (json as Map)['count'] as int, + ); + expect(client.handleResponse(response), 3); + expect(response.timestamp, '2026-01-01'); + }); + + test('invalid payload becomes a parse error', () async { + adapter.body = 'invalid'; + final response = await client.get( + '/count', + fromJsonT: (json) => json as int, + ); + expect(response, isA>()); + expect((response as ErrorResponse).error.code, 'PARSE_ERROR'); + }); + + for (final method in ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']) { + test('$method forwards query and headers and decodes response', () async { + adapter.body = 8; + final request = switch (method) { + 'POST' => client.post, + 'PUT' => client.put, + 'PATCH' => client.patch, + 'DELETE' => client.delete, + _ => client.get, + }; + final response = await request( + '/items', + queryParameters: {'page': 2}, + headers: {'X-Request': 'test'}, + fromJsonT: (json) => json as int, + ); + expect(client.handleResponse(response), 8); + expect(adapter.requests.single.method, method); + expect(adapter.requests.single.queryParameters, {'page': 2}); + expect(adapter.requests.single.headers['X-Request'], 'test'); + }); + } + + test('unauthorized HTTP responses throw a typed exception', () async { + adapter.status = 401; + adapter.body = {'message': 'Unauthorized'}; + await expectLater( + client.get('/private', fromJsonT: (json) => json as int), + throwsA(isA()), + ); + }); + + test('logs do not contain credentials, query values or payloads', () async { + adapter.body = {'secret': 'response-secret'}; + await client.post( + '/items', + headers: {'Authorization': 'Bearer header-secret'}, + queryParameters: {'token': 'query-secret'}, + data: {'password': 'body-secret'}, + fromJsonT: (json) => json, + ); + expect(logger.messages.join('\n'), isNot(contains('secret'))); + }); + + test('dispose closes the transport', () { + client.dispose(); + expect(adapter.closed, isTrue); + }); + + group('authentication retries', () { + late _Tokens tokens; + setUp(() { + client.dispose(); + adapter = _Adapter()..body = 9; + tokens = _Tokens(); + client = DioNetworkClient( + DefaultNetworkConfig( + baseUrl: 'https://example.test', + authTokenProvider: tokens, + ), + logger: logger, + dio: Dio()..httpClientAdapter = adapter, + ); + }); + + test('uses the configured transport and refreshes once', () async { + adapter.statuses.addAll([401, 200]); + final response = await client.get( + '/items', + fromJsonT: (json) => json as int, + ); + expect(client.handleResponse(response), 9); + expect(adapter.requests, hasLength(2)); + expect( + adapter.requests.last.headers['Authorization'], + 'Bearer new-token', + ); + expect(tokens.refreshes, 1); + }); + + test('a repeated 401 does not loop', () async { + adapter.status = 401; + await expectLater( + client.get('/items', fromJsonT: (json) => json as int), + throwsA(isA()), + ); + expect(adapter.requests, hasLength(2)); + expect(tokens.refreshes, 1); + }); + + test('caller authorization is respected case-insensitively', () async { + adapter.status = 401; + await expectLater( + client.get( + '/items', + headers: {'authorization': 'custom'}, + fromJsonT: (json) => json as int, + ), + throwsA(isA()), + ); + expect(adapter.requests, hasLength(1)); + expect(adapter.requests.single.headers['authorization'], 'custom'); + expect(tokens.refreshes, 0); + }); + + for (final fails in [true, false]) { + test( + 'unavailable refreshed token preserves the original error ($fails)', + () async { + tokens.failRefresh = fails; + tokens.refreshed = null; + adapter.status = 401; + await expectLater( + client.get('/items', fromJsonT: (json) => json as int), + throwsA(isA()), + ); + expect(adapter.requests, hasLength(1)); + }, + ); + } + }); +} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{network_dir}}/test/models_test.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{network_dir}}/test/models_test.dart new file mode 100644 index 0000000..2716aaa --- /dev/null +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{network_dir}}/test/models_test.dart @@ -0,0 +1,133 @@ +import 'package:core/core.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:network/network.dart'; + +class _BaseError extends NetworkException {} + +class _OtherError extends Error {} + +class _Urls extends ApiUrlConfig { + _Urls() : super(pathPrefix: '/v1'); +} + +class _Api extends NetworkApi<_Urls> { + _Api() : super(urlConfig: _Urls()); + @override + Map get headers => {}; +} + +void main() { + test('network failures provide readable localized messages and statuses', () { + final errors = [ + _BaseError(), + const BadRequestException(), + const UnauthorizedException(), + const ForbiddenException(), + const NotFoundException(), + const ConflictException(), + const UnprocessableEntityException(), + const InternalServerException(), + const ConnectionTimeoutException(), + const ReceiveTimeoutException(), + const SendTimeoutException(), + const NoInternetConnectionException(), + const UnknownNetworkException(), + ]; + for (final error in errors) { + expect(error.displayMessage, isNotEmpty); + expect(error.toString(), contains(error.displayMessage)); + expect((error as Object).message(), error.displayMessage); + } + expect( + const UnauthorizedException(message: 'Custom').displayMessage, + 'Custom', + ); + expect(const UnauthorizedException().statusCode, 401); + final api = _Api(); + expect(api.urlConfig.pathPrefix, '/v1'); + expect(api.headers, isEmpty); + }); + + test('application errors map to readable messages with diagnostic codes', () { + TypeError? typeError; + try { + final dynamic value = 'not a number'; + value as int; + } on TypeError catch (error) { + typeError = error; + } + final errors = [ + CoreException(message: 'Core error'), + const FormatException('invalid'), + typeError, + IndexError.withLength(2, 1), + RangeError('range'), + ArgumentError('arg'), + StateError('state'), + UnimplementedError(), + UnsupportedError('unsupported'), + ConcurrentModificationError(), + const OutOfMemoryError(), + const StackOverflowError(), + _OtherError(), + null, + ]; + for (final error in errors) { + expect(error.message(), isNotEmpty); + } + expect( + (CoreException(message: 'Core error') as Object).message(), + 'Core error', + ); + expect( + (StateError('state') as Error).message(), + contains(ErrorCodes.stateError), + ); + }); + + test('success, error and pagination metadata round-trip JSON', () { + const pagination = Pagination( + page: 1, + limit: 10, + total: 20, + totalPages: 2, + hasNextPage: true, + hasPreviousPage: false, + ); + const success = SuccessResponse( + statusCode: 200, + success: true, + data: 3, + timestamp: '2026', + pagination: pagination, + headers: { + 'x': ['y'], + }, + ); + final json = success.toJson((value) => value); + // toJson intentionally retains nested objects until JSON encoding. + json['pagination'] = pagination.toJson(); + final decoded = SuccessResponse.fromJson( + json, + (value) => value as int, + ); + expect(decoded.data, 3); + expect(decoded.pagination!.hasNextPage, isTrue); + expect(decoded.isSuccess, isTrue); + const details = ErrorDetails( + code: 'INVALID', + message: 'Invalid', + details: {'field': 'email'}, + ); + const error = ErrorResponse( + statusCode: 400, + success: false, + error: details, + timestamp: '2026', + ); + final errorJson = error.toJson()..['error'] = details.toJson(); + expect(ErrorResponse.fromJson(errorJson).error.code, 'INVALID'); + expect(ErrorDetails.fromJson(details.toJson()).details, {'field': 'email'}); + expect(error.isSuccess, isFalse); + }); +} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{network_dir}}/test/response_contract_test.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{network_dir}}/test/response_contract_test.dart new file mode 100644 index 0000000..41c4da6 --- /dev/null +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{network_dir}}/test/response_contract_test.dart @@ -0,0 +1,79 @@ +import 'package:core/core.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:network/network.dart'; + +class _Dio extends Mock implements Dio {} + +class _Logger extends Mock implements Logger {} + +class _UnknownResponse extends NetworkResponse { + const _UnknownResponse() + : super(statusCode: 202, success: false, timestamp: 'now'); +} + +void main() { + setUpAll(() => registerFallbackValue(Options())); + test( + 'unexpected transport failures are normalized at the client boundary', + () async { + final dio = _Dio(); + when(() => dio.interceptors).thenReturn(Interceptors()); + when( + () => dio.get(any(), options: any(named: 'options')), + ).thenThrow(StateError('transport')); + final client = DioNetworkClient( + const DefaultNetworkConfig(baseUrl: 'https://example.test'), + logger: _Logger(), + dio: dio, + ); + addTearDown(client.dispose); + await expectLater( + client.get('/request', fromJsonT: (json) => json), + throwsA(isA()), + ); + }, + ); + + test( + 'response handlers preserve nullable successes and reject unsupported or failed envelopes', + () { + final client = DioNetworkClient( + const DefaultNetworkConfig(baseUrl: 'https://example.test'), + logger: _Logger(), + ); + addTearDown(client.dispose); + const success = SuccessResponse( + statusCode: 204, + success: true, + data: null, + timestamp: 'now', + ); + expect(client.handleResponse(success), isNull); + expect(client.handleSuccessResponse(success), same(success)); + const error = ErrorResponse( + statusCode: 200, + success: false, + timestamp: 'now', + error: ErrorDetails(code: 'INVALID', message: 'Rejected'), + ); + expect( + () => client.handleSuccessResponse(error), + throwsA(isA()), + ); + expect( + () => client.handleResponse(error), + throwsA(isA()), + ); + expect( + () => client.handleResponse(const _UnknownResponse()), + throwsA(isA()), + ); + expect( + () => client.handleSuccessResponse(const _UnknownResponse()), + throwsA(isA()), + ); + }, + ); +} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/notifications.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/notifications.dart index 21ecd44..18f43db 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/notifications.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/notifications.dart @@ -4,6 +4,7 @@ import 'dart:async'; import 'package:core/core.dart'; import 'package:di/di.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:notifications/src/config/index.dart'; import 'package:notifications/src/di/index.dart'; @@ -17,12 +18,14 @@ export 'src/services/index.dart'; /// Initialize the notifications module with dependency injection Future init({ NotificationConfig config = const DefaultNotificationConfig(), + FirebaseMessaging? messaging, }) async { final logger = di.get(); try { - await registerNotificationWithDI(config); + await registerNotificationWithDI(config, messaging: messaging); logger.i('🔔 Notifications module initialized'); } catch (e, s) { logger.e('🔔 Failed to initialize notifications module', e, s); + rethrow; } } diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/src/client/firebase_notification_client.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/src/client/firebase_notification_client.dart index cbe1cb7..e3631ec 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/src/client/firebase_notification_client.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/src/client/firebase_notification_client.dart @@ -2,206 +2,156 @@ import 'dart:async'; import 'package:app_badge_plus/app_badge_plus.dart'; import 'package:core/logger/logger.dart'; -import 'package:design_system/toast/toasts.dart'; -import 'package:di/di.dart'; import 'package:firebase_messaging/firebase_messaging.dart' hide NotificationSettings; -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:network/network.dart'; +import 'package:flutter/foundation.dart'; import 'package:notifications/notifications.dart'; -const String _tag = 'FirebaseNotificationClient'; - -/// Firebase implementation of the notification client +/// Owns messaging subscriptions; presentation is supplied by the app. class FirebaseNotificationClient implements NotificationClient { FirebaseNotificationClient({ required this.config, - Logger? logger, - NotificationTokenManager? tokenManager, - NotificationPermissionManager? permissionManager, - }) : _logger = logger ?? di.get(), - _tokenManager = tokenManager ?? di.get(), - _permissionManager = - permissionManager ?? di.get(); + required Logger logger, + required NotificationTokenManager tokenManager, + required NotificationPermissionManager permissionManager, + required FirebaseMessaging messaging, + Stream? foregroundMessages, + Stream? openedMessages, + Future Function()? supportsBadge, + Future Function(int)? updateBadge, + void Function(Future Function(RemoteMessage))? registerBackground, + }) : _logger = logger, + _tokenManager = tokenManager, + _permissionManager = permissionManager, + _messaging = messaging, + _foregroundMessages = foregroundMessages ?? FirebaseMessaging.onMessage, + _openedMessages = openedMessages ?? FirebaseMessaging.onMessageOpenedApp, + _supportsBadge = supportsBadge ?? AppBadgePlus.isSupported, + _updateBadge = updateBadge ?? AppBadgePlus.updateBadge, + _registerBackground = + registerBackground ?? FirebaseMessaging.onBackgroundMessage; final NotificationConfig config; final Logger _logger; final NotificationTokenManager _tokenManager; final NotificationPermissionManager _permissionManager; + final FirebaseMessaging _messaging; + final Stream _foregroundMessages; + final Stream _openedMessages; + final Future Function() _supportsBadge; + final Future Function(int) _updateBadge; + final void Function(Future Function(RemoteMessage)) _registerBackground; bool _isGranted = false; - - FirebaseMessaging? _firebaseMessaging; - + bool _initialized = false; + bool _disposed = false; + Future? _initializing; String? _fcmToken; String? _deviceId; - - // Store subscriptions for cleanup - StreamSubscription? _foregroundMessageSubscription; - StreamSubscription? _messageOpenedAppSubscription; - StreamSubscription? _tokenRefreshSubscription; + StreamSubscription? _foregroundSubscription; + StreamSubscription? _openedSubscription; + StreamSubscription? _tokenSubscription; @override - Future init() async { - try { - _logger.i('$_tag: Initializing Firebase notification client'); - - // Initialize Firebase Messaging - _firebaseMessaging = FirebaseMessaging.instance; + Future init() { + if (_disposed) { + return Future.error(StateError('Notification client is disposed')); + } + if (_initialized) return Future.value(); + return _initializing ??= _initialize().whenComplete( + () => _initializing = null, + ); + } - final isGranted = await requestPermissions(); - if (!isGranted) { - _logger.w('$_tag: Notification permissions not granted'); - return; + Future _initialize() async { + try { + _isGranted = await requestPermissions(); + if (_disposed || !_isGranted) return; + _registerBackground(handleBackgroundNotification); + _foregroundSubscription = _foregroundMessages.listen( + (message) => unawaited(handleForegroundNotification(message)), + onError: (Object error) => + _logger.e('Foreground notification stream failed', error), + ); + _openedSubscription = _openedMessages.listen( + (message) => + unawaited(handleNotificationOpened(message, source: 'background')), + onError: (Object error) => + _logger.e('Opened notification stream failed', error), + ); + _tokenSubscription = _messaging.onTokenRefresh.listen( + (token) async { + try { + await _tokenManager.handleTokenRefresh(token); + if (!_disposed) _fcmToken = token; + } catch (error, stack) { + _logger.e('Notification token refresh failed', error, stack); + } + }, + onError: (Object error) => + _logger.e('Notification token stream failed', error), + ); + final initial = await _messaging.getInitialMessage(); + if (_disposed) return; + if (initial != null) { + await handleNotificationOpened(initial, source: 'terminated'); } - _isGranted = isGranted; - - // Setup FCM handlers if background notifications are enabled - await _setupFCMHandlers(); - - // Get FCM token and register if backend registration is enabled await getFCMToken(); - - // Clear badge count as the last step of initialization await clearBadge(); - - _logger.i('$_tag: Firebase notification client initialized successfully'); - } catch (e, s) { - _logger.e('$_tag: Error initializing Firebase notification client', e, s); - throw NotificationException(message: e.message()); + if (!_disposed) _initialized = true; + } catch (error, stack) { + await _cancelSubscriptions(); + _logger.e('Notification initialization failed', error, stack); + rethrow; } } @override - Future requestPermissions({bool provisional = false}) async { - return await _permissionManager.requestPermissions(); - } + Future requestPermissions({bool provisional = false}) => + _permissionManager.requestPermissions(provisional: provisional); @override Future clearBadge() async { try { - _logger.i('🔔 Clearing badge count'); - if (!_isGranted) { - _logger.w( - '🔔 Notification permissions ' - 'not granted, cannot clear badge', - ); - return; - } - if (!await AppBadgePlus.isSupported()) { - _logger.w('🔔 AppBadgePlus is not supported on this platform'); - return; - } - await AppBadgePlus.updateBadge(0); - _logger.i('🔔 Badge count cleared'); - } catch (e) { - _logger.w('🔔 Failed to clear badge count: $e'); + if (_disposed || !_isGranted || !await _supportsBadge()) return; + if (!_disposed) await _updateBadge(0); + } catch (error, stack) { + _logger.e('Notification badge clearing failed', error, stack); } } - Future _setupFCMHandlers() async { - // Handle background messages (when app is terminated) - FirebaseMessaging.onBackgroundMessage(_handleBackgroundNotification); - - // Handle foreground messages - _foregroundMessageSubscription = FirebaseMessaging.onMessage.listen( - (RemoteMessage message) { - _logger.i('$_tag: Received foreground message: ${message.messageId}'); - handleForegroundNotification(message); - }, - onError: (error) { - _logger.e('$_tag: Error in foreground message handler', error); - }, - ); - - // Handle notification opened (from background/terminated) - _messageOpenedAppSubscription = FirebaseMessaging.onMessageOpenedApp.listen( - (RemoteMessage message) { - _logger.i('$_tag: Notification opened app: ${message.messageId}'); - handleNotificationOpened(message, source: 'background'); - }, - onError: (error) { - _logger.e('$_tag: Error in notification opened handler', error); - }, - ); - - // Handle initial message (if app was opened from terminated state) - if (_firebaseMessaging != null) { - final initialMessage = await _firebaseMessaging!.getInitialMessage(); - if (initialMessage != null) { - _logger.i( - '$_tag: App opened from terminated state: ${initialMessage.messageId}', - ); - handleNotificationOpened(initialMessage, source: 'terminated'); - } - - // Handle token refresh - _tokenRefreshSubscription = _firebaseMessaging!.onTokenRefresh.listen( - (String newToken) { - _fcmToken = newToken; - _tokenManager.handleTokenRefresh(newToken); - }, - onError: (error) { - _logger.e('$_tag: Error in token refresh handler', error); - }, - ); - } - - _logger.i('$_tag: FCM handlers setup complete'); - } - @override Future getFCMToken() async { + if (_disposed) return null; try { - _fcmToken = await _tokenManager.getFCMToken(); - - if (_fcmToken != null) { - _deviceId = await _tokenManager.registerToken(_fcmToken!); - _logger.i('$_tag: Token registered with device ID: $_deviceId'); - } - - return _fcmToken; - } catch (e, s) { - _logger.e('$_tag: Error getting FCM token', e, s); + final token = await _tokenManager.getFCMToken(); + if (_disposed) return null; + final device = token == null + ? null + : await _tokenManager.registerToken(token); + if (_disposed) return null; + _fcmToken = token; + _deviceId = device; + return token; + } catch (error, stack) { + _fcmToken = null; + _deviceId = null; + _logger.e('Notification token registration failed', error, stack); return null; } } - /// Handle background notification (when app is not running) - @pragma('vm:entry-point') - static Future _handleBackgroundNotification( - RemoteMessage message, - ) async { - try { - debugPrint( - '$_tag: Handling background notification: ${message.messageId}', - ); - } catch (e, s) { - debugPrint( - '$_tag: Error handling background notification:' - ' ${message.messageId} - $e $s', - ); - } - } - @override Future handleForegroundNotification(RemoteMessage message) async { + if (_disposed) return; try { - _logger.i( - '$_tag: Handling foreground notification: ${message.messageId}', - ); - final notification = message.notification; - if (notification != null && - notification.title != null && - notification.body != null) { - Toast.notification( - title: notification.title!, - body: notification.body!, - ); + final title = notification?.title; + final body = notification?.body; + if (title != null && body != null) { + await config.onForeground?.call(title, body); } - } catch (e, s) { - _logger.e('$_tag: Error handling foreground notification', e, s); + } catch (error, stack) { + _logger.e('Foreground notification presentation failed', error, stack); } } @@ -210,46 +160,48 @@ class FirebaseNotificationClient implements NotificationClient { RemoteMessage message, { String? source, }) async { + if (_disposed) return; try { - _logger.i('$_tag: Handling notification opened: ${message.messageId}'); - - final notification = message.notification; - - _logger.i( - '$_tag: Notification opened from $source: ${notification?.title} - ${notification?.body}', - ); - - // Deep link contract: send a `route` in the message data and the app - // navigates there, e.g. {"route": "/home/orders/42"}. Branch on your own - // payload fields here if you need something richer than a path. final route = message.data['route']; - if (route is! String || route.isEmpty) return; - - di.get().push(route); - } catch (e, s) { - _logger.e('$_tag: Error handling notification opened', e, s); + // Notifications may navigate only to local app paths. + if (route is! String || + !route.startsWith('/') || + route.startsWith('//')) { + return; + } + await config.onOpenRoute?.call(route); + } catch (error, stack) { + _logger.e('Notification navigation failed', error, stack); } } @override String? get fcmToken => _fcmToken; - @override String? get deviceId => _deviceId; + Future _cancelSubscriptions() async { + await _foregroundSubscription?.cancel(); + await _openedSubscription?.cancel(); + await _tokenSubscription?.cancel(); + _foregroundSubscription = null; + _openedSubscription = null; + _tokenSubscription = null; + } + @override Future dispose() async { - _logger.i('$_tag: Disposing Firebase notification client'); - - // Cancel all subscriptions to prevent memory leaks - _foregroundMessageSubscription?.cancel(); - _messageOpenedAppSubscription?.cancel(); - _tokenRefreshSubscription?.cancel(); - - _foregroundMessageSubscription = null; - _messageOpenedAppSubscription = null; - _tokenRefreshSubscription = null; - - _firebaseMessaging = null; + _disposed = true; + _initialized = false; + _isGranted = false; + _fcmToken = null; + _deviceId = null; + await _cancelSubscriptions(); } } + +/// Background work runs in its own isolate, without app DI or navigation. +@pragma('vm:entry-point') +Future handleBackgroundNotification(RemoteMessage message) async { + debugPrint('Background notification received: ${message.messageId}'); +} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/src/config/notification_config.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/src/config/notification_config.dart index 54d3860..550f726 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/src/config/notification_config.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/src/config/notification_config.dart @@ -1,7 +1,12 @@ +import 'dart:async'; + class NotificationConfig { - const NotificationConfig(); + const NotificationConfig({this.onForeground, this.onOpenRoute}); + + final FutureOr Function(String title, String body)? onForeground; + final FutureOr Function(String route)? onOpenRoute; } class DefaultNotificationConfig extends NotificationConfig { - const DefaultNotificationConfig() : super(); + const DefaultNotificationConfig({super.onForeground, super.onOpenRoute}); } diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/src/device_info/device_info.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/src/device_info/device_info.dart index 7e9166c..70149dd 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/src/device_info/device_info.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/src/device_info/device_info.dart @@ -3,3 +3,8 @@ abstract class DeviceInfo { Future getDeviceName(); } + +abstract class InstallationIdStore { + Future read(); + Future write(String id); +} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/src/device_info/device_info_impl.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/src/device_info/device_info_impl.dart index 9f11e5a..cd27a78 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/src/device_info/device_info_impl.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/src/device_info/device_info_impl.dart @@ -1,210 +1,87 @@ -import 'dart:convert'; -import 'dart:io'; +import 'dart:math'; import 'package:core/logger/logger.dart'; -import 'package:crypto/crypto.dart'; import 'package:device_info_plus/device_info_plus.dart'; -import 'package:di/di.dart'; +import 'package:flutter/foundation.dart'; import 'package:notifications/src/device_info/device_info.dart'; +import 'package:shared_preferences/shared_preferences.dart'; -/// Concrete implementation of DeviceInfo for Android and iOS only -/// Generates consistent device identifiers using stable device characteristics -class DeviceInfoImpl implements DeviceInfo { - static const String _tag = 'DeviceInfoImpl'; - - final Logger _logger; - final DeviceInfoPlugin _deviceInfoPlugin; - - DeviceInfoImpl({Logger? logger, DeviceInfoPlugin? deviceInfoPlugin}) - : _logger = logger ?? di.get(), - _deviceInfoPlugin = deviceInfoPlugin ?? DeviceInfoPlugin(); +/// Persists a random installation identifier, independent of hardware models. +class SharedPreferencesInstallationIdStore implements InstallationIdStore { + SharedPreferencesInstallationIdStore({SharedPreferences? preferences}) + : _provided = preferences; + final SharedPreferences? _provided; + Future get _preferences async => + _provided ?? await SharedPreferences.getInstance(); + static const _key = 'nonstop.installation_id'; @override - Future generateDeviceId() async { - try { - if (Platform.isAndroid) { - return await _generateAndroidDeviceId(); - } else if (Platform.isIOS) { - return await _generateIOSDeviceId(); - } else { - _logger.w('$_tag: Unsupported platform: ${Platform.operatingSystem}'); - throw UnsupportedError('Only Android and iOS platforms are supported'); - } - } catch (e) { - _logger.w('$_tag: Error generating device ID: $e'); - return _generateFallbackId(); - } - } + Future read() async => (await _preferences).getString(_key); @override - Future getDeviceName() async { - try { - if (Platform.isAndroid) { - return await _getAndroidDeviceName(); - } else if (Platform.isIOS) { - return await _getIOSDeviceName(); - } else { - _logger.w('$_tag: Unsupported platform: ${Platform.operatingSystem}'); - throw UnsupportedError('Only Android and iOS platforms are supported'); - } - } catch (e) { - _logger.w('$_tag: Error getting device name: $e'); - return _getFallbackDeviceName(); - } + Future write(String id) async { + final saved = await (await _preferences).setString(_key, id); + if (!saved) throw StateError('Could not persist installation ID'); } +} - /// Generate Android device ID using stable hardware characteristics - Future _generateAndroidDeviceId() async { - try { - final androidInfo = await _deviceInfoPlugin.androidInfo; - - // Use only the most stable hardware characteristics that don't change - final stableCharacteristics = [ - androidInfo.brand, - androidInfo.model, - androidInfo.device, - androidInfo.hardware, - androidInfo.board, - androidInfo.bootloader, - androidInfo.product, - // fingerprint contains build info but is generally stable for same device - androidInfo.fingerprint, - // Physical device indicator - androidInfo.isPhysicalDevice.toString(), - // Hardware features that are stable - androidInfo.supportedAbis.join(','), - androidInfo.supported32BitAbis.join(','), - androidInfo.supported64BitAbis.join(','), - ]; - - // Remove empty values and create a deterministic string - final cleanCharacteristics = stableCharacteristics - .where((char) => char.isNotEmpty && char != 'null') - .toList(); - - if (cleanCharacteristics.isEmpty) { - throw Exception('No stable characteristics found for Android device'); - } - - // Sort to ensure consistent ordering - cleanCharacteristics.sort(); - - final deviceString = cleanCharacteristics.join('|'); - final deviceHash = _generateDeterministicHash(deviceString); +/// Supplies installation identity and a human-readable device label. +class DeviceInfoImpl implements DeviceInfo { + DeviceInfoImpl({ + required Logger logger, + DeviceInfoPlugin? deviceInfoPlugin, + InstallationIdStore? store, + String Function()? createId, + }) : _logger = logger, + _plugin = deviceInfoPlugin ?? DeviceInfoPlugin(), + _store = store ?? SharedPreferencesInstallationIdStore(), + _createId = createId ?? _randomId; - _logger.d( - '$_tag: Generated Android device ID from ' - '${cleanCharacteristics.length} characteristics', - ); - return 'android_$deviceHash'; - } catch (e) { - _logger.w('$_tag: Android device ID generation failed: $e'); - rethrow; - } + final Logger _logger; + final DeviceInfoPlugin _plugin; + final InstallationIdStore _store; + final String Function() _createId; + Future? _id; + + static String _randomId() { + final random = Random.secure(); + return List.generate( + 16, + (_) => random.nextInt(256).toRadixString(16).padLeft(2, '0'), + ).join(); } - /// Generate iOS device ID using identifierForVendor or stable characteristics - Future _generateIOSDeviceId() async { + @override + Future generateDeviceId() async { + if (_id != null) return _id!; + final pending = _loadId(); + _id = pending; try { - final iosInfo = await _deviceInfoPlugin.iosInfo; - - // First preference: use identifierForVendor as it's designed to be stable - final identifier = iosInfo.identifierForVendor; - if (identifier != null && identifier.isNotEmpty && identifier != 'null') { - _logger.d('$_tag: Using iOS identifierForVendor'); - return 'ios_$identifier'; - } - - // Fallback: use stable device characteristics - _logger.i( - '$_tag: iOS identifierForVendor not available, ' - 'using device characteristics', - ); - - final stableCharacteristics = [ - iosInfo.model, - iosInfo.localizedModel, - iosInfo.systemName, - iosInfo.isPhysicalDevice.toString(), - // Machine identifier from utsname (hardware model) - iosInfo.utsname.machine, - iosInfo.utsname.sysname, - // These are generally stable for the same device model - iosInfo.utsname.nodename, - ]; - - // Remove empty values and create a deterministic string - final cleanCharacteristics = stableCharacteristics - .where((char) => char.isNotEmpty && char != 'null') - .toList(); - - if (cleanCharacteristics.isEmpty) { - throw Exception('No stable characteristics found for iOS device'); - } - - // Sort to ensure consistent ordering - cleanCharacteristics.sort(); - - final deviceString = cleanCharacteristics.join('|'); - final deviceHash = _generateDeterministicHash(deviceString); - - _logger.d( - '$_tag: Generated iOS device ID from ' - '${cleanCharacteristics.length} characteristics', - ); - return 'ios_$deviceHash'; - } catch (e) { - _logger.w('$_tag: iOS device ID generation failed: $e'); + return await pending; + } catch (error) { + _id = null; + _logger.w('Installation ID storage failed: $error'); rethrow; } } - /// Get Android device name in format "Brand Model" - Future _getAndroidDeviceName() async { - final androidInfo = await _deviceInfoPlugin.androidInfo; - final brand = androidInfo.brand; - final model = androidInfo.model; - - return '$brand $model'; - } - - /// Get iOS device name in format "Name (Model)" - Future _getIOSDeviceName() async { - final iosInfo = await _deviceInfoPlugin.iosInfo; - final name = iosInfo.name; - final model = iosInfo.model; - - return '$name ($model)'; - } - - /// Generate a deterministic hash from device characteristics - /// Uses SHA-256 to create a consistent, stable hash - String _generateDeterministicHash(String input) { - // Add a salt to make the hash more unique while keeping it deterministic - const salt = 'device_identifier_salt_2024'; - final saltedInput = '$salt|$input'; - - final bytes = utf8.encode(saltedInput); - final digest = sha256.convert(bytes); - - // Return first 16 characters for reasonable length - return digest.toString().substring(0, 16); - } - - /// Generate a fallback device ID when all other methods fail - String _generateFallbackId() { - final platform = Platform.isAndroid ? 'android' : 'ios'; - - // Use a deterministic fallback based on platform - final fallbackString = '${platform}_fallback_device'; - final fallbackHash = _generateDeterministicHash(fallbackString); - - _logger.w('$_tag: Using deterministic fallback ID'); - return '${platform}_$fallbackHash'; + Future _loadId() async { + final existing = await _store.read(); + if (existing != null && existing.isNotEmpty) return existing; + final id = _createId(); + await _store.write(id); + return id; } - /// Get fallback device name when detection fails - String _getFallbackDeviceName() { - return Platform.isAndroid ? 'Android Device' : 'iOS Device'; + @override + Future getDeviceName() async { + try { + final data = (await _plugin.deviceInfo).data; + final name = data['name'] ?? data['model'] ?? data['computerName']; + if (name is String && name.isNotEmpty) return name; + } catch (error) { + _logger.w('Device name unavailable: $error'); + } + return kIsWeb ? 'Web browser' : defaultTargetPlatform.name; } } diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/src/di/notification_di.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/src/di/notification_di.dart index 160c0a7..4561cf0 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/src/di/notification_di.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/src/di/notification_di.dart @@ -1,4 +1,6 @@ import 'package:di/di.dart'; +import 'package:core/core.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:notifications/src/client/index.dart'; import 'package:notifications/src/config/index.dart'; import 'package:notifications/src/device_info/index.dart'; @@ -6,22 +8,36 @@ import 'package:notifications/src/services/notification_permission_manager.dart' import 'package:notifications/src/services/notification_token_manager.dart'; /// Register notification services with dependency injection -Future registerNotificationWithDI(NotificationConfig config) async { +Future registerNotificationWithDI( + NotificationConfig config, { + FirebaseMessaging? messaging, +}) async { + final selectedMessaging = messaging ?? FirebaseMessaging.instance; // Register config di.register(config); // Register device info service - di.register(DeviceInfoImpl()); + di.register(DeviceInfoImpl(logger: di.get())); // Register token manager - di.register(FirebaseTokenManager()); + di.register( + FirebaseTokenManager(firebaseMessaging: selectedMessaging), + ); // Register permission manager - di.register(FirebasePermissionManager()); + di.register( + FirebasePermissionManager(firebaseMessaging: selectedMessaging), + ); // Register notification client with proper disposal di.register( - FirebaseNotificationClient(config: config), + FirebaseNotificationClient( + config: config, + logger: di.get(), + messaging: selectedMessaging, + tokenManager: di.get(), + permissionManager: di.get(), + ), dispose: (client) => client.dispose(), ); } diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/src/services/notification_permission_manager.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/src/services/notification_permission_manager.dart index 3c5cd20..62c8510 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/src/services/notification_permission_manager.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/src/services/notification_permission_manager.dart @@ -5,7 +5,7 @@ import 'package:network/network.dart'; import 'package:notifications/src/exceptions/notification_exceptions.dart'; abstract class NotificationPermissionManager { - Future requestPermissions(); + Future requestPermissions({bool provisional = false}); } class FirebasePermissionManager implements NotificationPermissionManager { @@ -21,10 +21,12 @@ class FirebasePermissionManager implements NotificationPermissionManager { _firebaseMessaging = firebaseMessaging ?? FirebaseMessaging.instance; @override - Future requestPermissions() async { + Future requestPermissions({bool provisional = false}) async { try { _logger.i('$_tag: Requesting notification permissions'); - final authSettings = await _firebaseMessaging.requestPermission(); + final authSettings = await _firebaseMessaging.requestPermission( + provisional: provisional, + ); final isGranted = authSettings.authorizationStatus == AuthorizationStatus.authorized || diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/src/services/notification_token_manager.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/src/services/notification_token_manager.dart index fc10913..b585586 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/src/services/notification_token_manager.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/src/services/notification_token_manager.dart @@ -1,4 +1,4 @@ -import 'dart:io'; +import 'package:flutter/foundation.dart'; import 'package:core/logger/logger.dart'; import 'package:di/di.dart'; @@ -57,7 +57,7 @@ class FirebaseTokenManager implements NotificationTokenManager { final deviceId = await _deviceInfo.generateDeviceId(); final deviceName = await _deviceInfo.getDeviceName(); - final deviceType = Platform.isIOS ? 'ios' : 'android'; + final deviceType = kIsWeb ? 'web' : defaultTargetPlatform.name; final request = DeviceTokenRequest( fcmToken: fcmToken, @@ -66,11 +66,12 @@ class FirebaseTokenManager implements NotificationTokenManager { deviceType: deviceType, ); - await _networkClient.post>( + final response = await _networkClient.post>( '/device-tokens/me', data: request.toJson(), fromJsonT: (json) => json as Map, ); + _networkClient.handleSuccessResponse(response); _logger.i('$_tag: FCM token registered successfully'); return deviceId; } catch (e, s) { @@ -84,10 +85,11 @@ class FirebaseTokenManager implements NotificationTokenManager { try { _logger.i('$_tag: Removing FCM token from backend'); - await _networkClient.delete>( + final response = await _networkClient.delete>( '/device-tokens/me/$deviceId', fromJsonT: (json) => json as Map, ); + _networkClient.handleSuccessResponse(response); _logger.i('$_tag: FCM token removed successfully'); } catch (e, s) { _logger.e('$_tag: Error removing FCM token', e, s); diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/pubspec.yaml b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/pubspec.yaml index e555076..2c8c8f3 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/pubspec.yaml +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/pubspec.yaml @@ -8,29 +8,23 @@ environment: flutter: ">=3.29.0" dependencies: + shared_preferences: ^2.5.3 flutter: sdk: flutter app_badge_plus: ^1.1.2 - crypto: ^3.0.6 device_info_plus: ^11.1.1 firebase_core: ^3.14.0 firebase_messaging: ^15.1.6 - go_router: ^15.1.3 json_annotation: ^4.9.0 - permission_handler: ^11.1.0 - timezone: ^0.9.4 core: path: ../core - design_system: - path: ../design_system di: path: ../di {{#network}} network: path: ../network -{{/network}}{{#analytics}} analytics: - path: ../analytics -{{/analytics}} +{{/network}} dev_dependencies: + mocktail: ^1.0.4 flutter_test: sdk: flutter flutter_lints: ^5.0.0 diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/test/client_test.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/test/client_test.dart new file mode 100644 index 0000000..bb2f76c --- /dev/null +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/test/client_test.dart @@ -0,0 +1,230 @@ +import 'dart:async'; + +import 'package:core/core.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:notifications/notifications.dart'; + +class _Logger extends Mock implements Logger {} + +class _Messaging extends Mock implements FirebaseMessaging {} + +class _Tokens extends Mock implements NotificationTokenManager {} + +class _Permission extends Mock implements NotificationPermissionManager {} + +void main() { + late _Logger logger; + late _Messaging messaging; + late _Tokens tokens; + late _Permission permission; + late StreamController foreground; + late StreamController opened; + late StreamController refreshed; + late FirebaseNotificationClient client; + late List routes; + late List notifications; + late List badges; + late bool supported; + late bool callbackError; + late Future Function(RemoteMessage) background; + + setUp(() { + logger = _Logger(); + messaging = _Messaging(); + tokens = _Tokens(); + permission = _Permission(); + foreground = StreamController.broadcast(); + opened = StreamController.broadcast(); + refreshed = StreamController.broadcast(); + routes = []; + notifications = []; + badges = []; + supported = true; + callbackError = false; + when( + () => + permission.requestPermissions(provisional: any(named: 'provisional')), + ).thenAnswer((_) async => true); + when(() => messaging.onTokenRefresh).thenAnswer((_) => refreshed.stream); + when(messaging.getInitialMessage).thenAnswer((_) async => null); + when(tokens.getFCMToken).thenAnswer((_) async => 'token'); + when(() => tokens.registerToken(any())).thenAnswer((_) async => 'device'); + when(() => tokens.handleTokenRefresh(any())).thenAnswer((_) async {}); + client = FirebaseNotificationClient( + config: NotificationConfig( + onForeground: (title, body) { + if (callbackError) throw StateError('presentation'); + notifications.add('$title: $body'); + }, + onOpenRoute: (route) { + if (callbackError) throw StateError('navigation'); + routes.add(route); + }, + ), + logger: logger, + tokenManager: tokens, + permissionManager: permission, + messaging: messaging, + foregroundMessages: foreground.stream, + openedMessages: opened.stream, + supportsBadge: () async => supported, + updateBadge: (value) async { + if (callbackError) throw StateError('badge'); + badges.add(value); + }, + registerBackground: (handler) { + background = handler; + }, + ); + }); + tearDown(() async { + await client.dispose(); + await foreground.close(); + await opened.close(); + await refreshed.close(); + }); + + test( + 'concurrent initialization creates one subscription and registers a token', + () async { + await Future.wait([client.init(), client.init()]); + await client.init(); + verify(() => permission.requestPermissions(provisional: false)).called(1); + expect(client.fcmToken, 'token'); + expect(client.deviceId, 'device'); + expect(badges, [0]); + await background(const RemoteMessage(messageId: 'background')); + await client.requestPermissions(provisional: true); + verify(() => permission.requestPermissions(provisional: true)).called(1); + }, + ); + + test( + 'permission denial can be retried and unsupported badges are skipped', + () async { + when( + () => permission.requestPermissions(provisional: false), + ).thenAnswer((_) async => false); + await client.init(); + await client.clearBadge(); + expect(foreground.hasListener, isFalse); + expect(badges, isEmpty); + when( + () => permission.requestPermissions(provisional: false), + ).thenAnswer((_) async => true); + supported = false; + await client.init(); + expect(foreground.hasListener, isTrue); + expect(badges, isEmpty); + }, + ); + + test( + 'foreground, opened, initial and token-refresh events reach their owners', + () async { + when(messaging.getInitialMessage).thenAnswer( + (_) async => const RemoteMessage(data: {'route': '/initial'}), + ); + await client.init(); + foreground.add( + const RemoteMessage( + notification: RemoteNotification(title: 'Title', body: 'Body'), + ), + ); + opened.add(const RemoteMessage(data: {'route': '/opened'})); + refreshed.add('new-token'); + await pumpEventQueue(); + expect(routes, ['/initial', '/opened']); + expect(notifications, ['Title: Body']); + expect(client.fcmToken, 'new-token'); + verify(() => tokens.handleTokenRefresh('new-token')).called(1); + for (final data in [ + {}, + {'route': ''}, + {'route': 1}, + {'route': 'https://outside.test'}, + {'route': '//outside.test'}, + ]) { + await client.handleNotificationOpened(RemoteMessage(data: data)); + } + await client.handleForegroundNotification(const RemoteMessage()); + expect(routes, hasLength(2)); + expect(notifications, hasLength(1)); + }, + ); + + test( + 'stream, presentation, navigation and badge failures are contained', + () async { + await client.init(); + callbackError = true; + when( + () => tokens.handleTokenRefresh(any()), + ).thenThrow(StateError('refresh')); + foreground.addError(StateError('foreground')); + opened.addError(StateError('opened')); + refreshed.addError(StateError('tokens')); + refreshed.add('new-token'); + await client.handleForegroundNotification( + const RemoteMessage( + notification: RemoteNotification(title: 'T', body: 'B'), + ), + ); + await client.handleNotificationOpened( + const RemoteMessage(data: {'route': '/home'}), + ); + await client.clearBadge(); + await pumpEventQueue(); + expect(client.fcmToken, 'token'); + expect(routes, isEmpty); + expect(notifications, isEmpty); + }, + ); + + test( + 'registration failures clear cached state and a null token does not register', + () async { + when(tokens.getFCMToken).thenAnswer((_) async => null); + expect(await client.getFCMToken(), isNull); + verifyNever(() => tokens.registerToken(any())); + when(tokens.getFCMToken).thenAnswer((_) async => 'token'); + when(() => tokens.registerToken(any())).thenThrow(StateError('backend')); + expect(await client.getFCMToken(), isNull); + expect(client.fcmToken, isNull); + expect(client.deviceId, isNull); + }, + ); + + test('failed startup cancels subscriptions and can be retried', () async { + when(messaging.getInitialMessage).thenThrow(StateError('startup')); + await expectLater(client.init(), throwsStateError); + expect(foreground.hasListener, isFalse); + // Retry before subscribing again is supported by real broadcast FCM streams; + // a denied permission also demonstrates that the failed future was cleared. + when( + () => permission.requestPermissions(provisional: false), + ).thenAnswer((_) async => false); + await client.init(); + }); + + test('dispose closes listeners and prevents late startup work', () async { + final initial = Completer(); + when(messaging.getInitialMessage).thenAnswer((_) => initial.future); + final startup = client.init(); + await pumpEventQueue(); + await client.dispose(); + initial.complete(const RemoteMessage(data: {'route': '/late'})); + await startup; + expect(foreground.hasListener, isFalse); + expect(await client.getFCMToken(), isNull); + await client.handleForegroundNotification(const RemoteMessage()); + await client.handleNotificationOpened( + const RemoteMessage(data: {'route': '/late'}), + ); + await client.clearBadge(); + expect(routes, isEmpty); + await expectLater(client.init(), throwsStateError); + }); +} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/test/device_info_test.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/test/device_info_test.dart new file mode 100644 index 0000000..e3c93ab --- /dev/null +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/test/device_info_test.dart @@ -0,0 +1,104 @@ +import 'package:core/core.dart'; +import 'package:device_info_plus/device_info_plus.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:notifications/notifications.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +class _Logger extends Mock implements Logger {} + +class _Plugin extends Mock implements DeviceInfoPlugin {} + +class _Info extends Mock implements BaseDeviceInfo {} + +class _Preferences extends Mock implements SharedPreferences {} + +class _Store implements InstallationIdStore { + String? value; + bool fail = false; + int writes = 0; + @override + Future read() async => value; + @override + Future write(String id) async { + if (fail) throw StateError('disk unavailable'); + writes++; + value = id; + } +} + +void main() { + test('storage rejects unsuccessful preference writes', () async { + final preferences = _Preferences(); + when( + () => preferences.setString(any(), any()), + ).thenAnswer((_) async => false); + final store = SharedPreferencesInstallationIdStore( + preferences: preferences, + ); + await expectLater(store.write('id'), throwsStateError); + }); + test( + 'concurrent requests persist one ID and new instances reuse it', + () async { + final store = _Store(); + var generated = 0; + final device = DeviceInfoImpl( + logger: _Logger(), + store: store, + createId: () => 'id-${++generated}', + ); + expect( + await Future.wait([ + device.generateDeviceId(), + device.generateDeviceId(), + ]), + ['id-1', 'id-1'], + ); + expect(store.writes, 1); + final second = DeviceInfoImpl(logger: _Logger(), store: store); + expect(await second.generateDeviceId(), 'id-1'); + }, + ); + + test('storage failures propagate and can be retried', () async { + final store = _Store()..fail = true; + final device = DeviceInfoImpl( + logger: _Logger(), + store: store, + createId: () => 'id', + ); + await expectLater(device.generateDeviceId(), throwsStateError); + store.fail = false; + expect(await device.generateDeviceId(), 'id'); + }); + + test( + 'default storage persists random IDs without hardware fingerprinting', + () async { + SharedPreferences.setMockInitialValues({}); + final first = await DeviceInfoImpl(logger: _Logger()).generateDeviceId(); + expect(first, matches(RegExp(r'^[0-9a-f]{32}$'))); + expect(await DeviceInfoImpl(logger: _Logger()).generateDeviceId(), first); + }, + ); + + test( + 'device names use plugin metadata and fall back when unavailable', + () async { + final plugin = _Plugin(); + final info = _Info(); + when(() => plugin.deviceInfo).thenAnswer((_) async => info); + final device = DeviceInfoImpl( + logger: _Logger(), + deviceInfoPlugin: plugin, + ); + when(() => info.data).thenReturn({'model': 'Test phone'}); + expect(await device.getDeviceName(), 'Test phone'); + when(() => info.data).thenReturn({}); + expect(await device.getDeviceName(), isNotEmpty); + when(() => plugin.deviceInfo).thenThrow(StateError('unavailable')); + expect(await device.getDeviceName(), isNotEmpty); + }, + ); +} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/test/services_test.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/test/services_test.dart new file mode 100644 index 0000000..2b03f50 --- /dev/null +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/packages/{{notifications_dir}}/test/services_test.dart @@ -0,0 +1,204 @@ +import 'package:core/core.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:network/network.dart'; +import 'package:notifications/notifications.dart'; +import 'package:notifications/notifications.dart' as notifications; +import 'package:di/di.dart'; + +class _Logger extends Mock implements Logger {} + +class _Messaging extends Mock implements FirebaseMessaging {} + +class _Settings extends Mock implements NotificationSettings {} + +class _Network extends Mock implements NetworkClient {} + +class _Device extends Mock implements DeviceInfo {} + +void main() { + late _Logger logger; + late _Messaging messaging; + setUp(() { + logger = _Logger(); + messaging = _Messaging(); + }); + tearDown(di.reset); + + test('module registration failures are surfaced to startup', () async { + di.register(logger); + await expectLater( + notifications.init(messaging: messaging), + throwsA(anything), + ); + }); + + test( + 'module composition registers swappable contracts without device calls', + () async { + di.register(logger); + di.register(_Network()); + await notifications.init(messaging: messaging); + expect(di.has(), isTrue); + expect(di.has(), isTrue); + expect(di.has(), isTrue); + expect(di.has(), isTrue); + }, + ); + + for (final status in AuthorizationStatus.values) { + test( + 'permission status $status is mapped correctly and provisional forwarded', + () async { + final settings = _Settings(); + when(() => settings.authorizationStatus).thenReturn(status); + when( + () => messaging.requestPermission(provisional: true), + ).thenAnswer((_) async => settings); + final manager = FirebasePermissionManager( + logger: logger, + firebaseMessaging: messaging, + ); + expect( + await manager.requestPermissions(provisional: true), + status == AuthorizationStatus.authorized || + status == AuthorizationStatus.provisional, + ); + }, + ); + } + + test( + 'permission errors are reported through the notification contract', + () async { + when( + () => messaging.requestPermission(provisional: false), + ).thenThrow(StateError('unavailable')); + final manager = FirebasePermissionManager( + logger: logger, + firebaseMessaging: messaging, + ); + await expectLater( + manager.requestPermissions(), + throwsA(isA()), + ); + }, + ); + + group('token manager', () { + late _Network network; + late _Device device; + late FirebaseTokenManager manager; + const success = SuccessResponse>( + statusCode: 200, + success: true, + data: {}, + timestamp: '2026-01-01', + ); + setUp(() { + network = _Network(); + device = _Device(); + manager = FirebaseTokenManager( + logger: logger, + networkClient: network, + deviceInfo: device, + firebaseMessaging: messaging, + ); + registerFallbackValue((Object? json) => json as Map); + when(device.generateDeviceId).thenAnswer((_) async => 'install-1'); + when(device.getDeviceName).thenAnswer((_) async => 'Test device'); + when( + () => network.post>( + any(), + data: any(named: 'data'), + fromJsonT: any(named: 'fromJsonT'), + ), + ).thenAnswer((call) async { + final decode = + call.namedArguments[#fromJsonT] + as Map Function(Object?); + expect(decode({'ok': true}), {'ok': true}); + return success; + }); + when( + () => network.delete>( + any(), + fromJsonT: any(named: 'fromJsonT'), + ), + ).thenAnswer((call) async { + final decode = + call.namedArguments[#fromJsonT] + as Map Function(Object?); + expect(decode({'ok': true}), {'ok': true}); + return success; + }); + when( + () => network.handleSuccessResponse>(success), + ).thenReturn(success); + }); + + test('returns nullable FCM tokens and propagates SDK failures', () async { + when(() => messaging.getToken()).thenAnswer((_) async => 'token'); + expect(await manager.getFCMToken(), 'token'); + when(() => messaging.getToken()).thenAnswer((_) async => null); + expect(await manager.getFCMToken(), isNull); + when(() => messaging.getToken()).thenThrow(StateError('offline')); + await expectLater(manager.getFCMToken(), throwsStateError); + }); + + test('registers metadata, refreshes and unregisters', () async { + expect(await manager.registerToken('token'), 'install-1'); + final data = + verify( + () => network.post>( + '/device-tokens/me', + data: captureAny(named: 'data'), + fromJsonT: any(named: 'fromJsonT'), + ), + ).captured.single + as Map; + expect(data['fcmToken'], 'token'); + expect(data['deviceId'], 'install-1'); + expect(data['deviceName'], 'Test device'); + await manager.handleTokenRefresh('next-token'); + await manager.unRegisterToken('install-1'); + verify( + () => network.handleSuccessResponse>(success), + ).called(3); + }); + + test( + 'application-level backend rejection cannot be reported as success', + () async { + when( + () => network.handleSuccessResponse>(success), + ).thenThrow(UnauthorizedException()); + await expectLater( + manager.registerToken('token'), + throwsA(isA()), + ); + await expectLater( + manager.unRegisterToken('install-1'), + throwsA(isA()), + ); + }, + ); + }); + + test('token request models round-trip JSON', () { + const request = DeviceTokenRequest( + fcmToken: 'token', + deviceId: 'id', + deviceName: 'phone', + deviceType: 'ios', + ); + expect( + DeviceTokenRequest.fromJson(request.toJson()).toJson(), + request.toJson(), + ); + const update = DeviceTokenUpdateRequest(fcmToken: 'next'); + expect(DeviceTokenUpdateRequest.fromJson(update.toJson()).fcmToken, 'next'); + expect(const DefaultNotificationConfig(), isA()); + }); +} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/pubspec.yaml b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/pubspec.yaml index 07334b7..162dae0 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/pubspec.yaml +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/pubspec.yaml @@ -8,3 +8,4 @@ environment: dev_dependencies: flutter_lints: ^5.0.0 melos: ^6.2.0 + path: ^1.9.1 diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/tool/check.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/tool/check.dart new file mode 100644 index 0000000..b125563 --- /dev/null +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/tool/check.dart @@ -0,0 +1,49 @@ +import 'dart:io'; +import 'package:path/path.dart' as p; + +/// Portable, non-mutating format and analyzer checks from the workspace root. +Future main() async { + final sources = []; + void collect(Directory directory) { + if (!directory.existsSync()) { + return; + } + for (final entry in directory.listSync(followLinks: false)) { + if (entry is Directory) { + if (!['build', '.dart_tool', '.symlinks'] + .contains(p.basename(entry.path))) { + collect(entry); + } + } else if (entry is File && + entry.path.endsWith('.dart') && + !RegExp(r'\.(g|freezed|i69n)\.dart$').hasMatch(entry.path)) { + sources.add(entry.path); + } + } + } + + collect(Directory('tool')); + for (final area in ['apps', 'features', 'packages', 'plugins']) { + final directory = Directory(area); + if (!directory.existsSync()) { + continue; + } + for (final package in directory.listSync().whereType()) { + collect(Directory(p.join(package.path, 'lib'))); + collect(Directory(p.join(package.path, 'test'))); + } + } + sources.sort(); + for (final arguments in [ + ['format', '--output=none', '--set-exit-if-changed', ...sources], + ['analyze', '--fatal-infos', '.'], + ]) { + final process = await Process.start('dart', arguments, + mode: ProcessStartMode.inheritStdio); + final result = await process.exitCode; + if (result != 0) { + exitCode = result; + return; + } + } +} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/tool/coverage.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/tool/coverage.dart new file mode 100644 index 0000000..31310cd --- /dev/null +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/__brick__/{{ name.snakeCase() }}/tool/coverage.dart @@ -0,0 +1,163 @@ +import 'dart:io'; +import 'package:path/path.dart' as p; + +/// Run from the workspace root: dart run tool/coverage.dart [--report-only]. +/// Only compiler-generated serializers/translations are excluded. +Future main(List args) async { + final root = Directory(Directory.current.resolveSymbolicLinksSync()); + final merged = >{}; + var failed = false; + final reportOnly = args.contains('--report-only'); + final names = []; + for (final area in ['apps', 'features', 'packages', 'plugins']) { + final directory = Directory('${root.path}/$area'); + if (!directory.existsSync()) continue; + for (final package in directory.listSync().whereType()) { + final manifest = File('${package.path}/pubspec.yaml'); + if (manifest.existsSync()) { + final name = RegExp( + r'^name:\s*(\S+)', + multiLine: true, + ).firstMatch(manifest.readAsStringSync())!.group(1)!; + names.add(RegExp.escape(name)); + } + } + } + final coveragePackages = '^(${names.join('|')})\$'; + for (final area in ['apps', 'features', 'packages', 'plugins']) { + final directory = Directory('${root.path}/$area'); + if (!directory.existsSync()) continue; + final packages = directory.listSync().whereType().toList() + ..sort((a, b) => a.path.compareTo(b.path)); + for (final package in packages) { + final manifest = File('${package.path}/pubspec.yaml'); + if (!manifest.existsSync()) continue; + final name = RegExp( + r'^name:\s*(\S+)', + multiLine: true, + ).firstMatch(manifest.readAsStringSync())!.group(1)!; + final testDirectory = Directory('${package.path}/test'); + if (!testDirectory.existsSync() || + !testDirectory + .listSync(recursive: true) + .whereType() + .any((f) => f.path.endsWith('_test.dart'))) { + stderr.writeln('$area/$name: missing tests'); + failed = true; + continue; + } + final report = File('${package.path}/coverage/lcov.info'); + if (!reportOnly) { + final imports = File( + '${testDirectory.path}/coverage_imports_test.dart', + ); + if (imports.existsSync()) { + throw StateError('Refusing to overwrite ${imports.path}'); + } + final sources = Directory('${package.path}/lib') + .listSync(recursive: true) + .whereType() + .where((f) => f.path.endsWith('.dart')) + .where( + (f) => !RegExp(r'\.(g|freezed|i69n)\.dart$').hasMatch(f.path), + ) + .where( + (f) => !RegExp( + r'^part of ', + multiLine: true, + ).hasMatch(f.readAsStringSync()), + ) + .toList() + ..sort((a, b) => a.path.compareTo(b.path)); + imports.writeAsStringSync( + [ + '// Generated temporarily by tool/coverage.dart.', + '// ignore_for_file: unused_import', + for (final source in sources) + "import 'package:$name/${p.relative(source.path, from: p.join(package.path, 'lib')).replaceAll(r'\', '/')}';", + 'void main() {}', + ].join('\n'), + ); + try { + if (report.existsSync()) report.deleteSync(); + final process = await Process.start( + 'flutter', + ['test', '--coverage', '--coverage-package=$coveragePackages'], + workingDirectory: package.path, + mode: ProcessStartMode.inheritStdio, + ); + if (await process.exitCode != 0) failed = true; + } finally { + imports.deleteSync(); + } + } + if (!report.existsSync()) { + stderr.writeln('$area/$name: missing coverage report'); + failed = true; + continue; + } + String? source; + for (final line in report.readAsLinesSync()) { + if (line.startsWith('SF:')) { + final path = line.substring(3); + var absolute = p.normalize( + p.isAbsolute(path) ? path : p.join(package.path, path)); + // VM reports may use /var while the workspace resolves to /private/var + // on macOS (or another symlink on Linux). Merge the same real source. + final sourceFile = File(absolute); + if (sourceFile.existsSync()) { + absolute = sourceFile.resolveSymbolicLinksSync(); + } + source = p.isWithin(root.path, absolute) + ? p.relative(absolute, from: root.path).replaceAll(r'\', '/') + : null; + if (source != null && + !RegExp(r'^(apps|features|packages|plugins)/[^/]+/lib/') + .hasMatch(source)) { + source = null; + } + if (source != null && + RegExp(r'\.(g|freezed|i69n)\.dart$').hasMatch(source)) { + source = null; + } + } else if (line.startsWith('DA:') && source != null) { + final fields = line.substring(3).split(','); + final number = int.parse(fields[0]); + final hits = int.parse(fields[1]); + final lines = merged.putIfAbsent(source, () => {}); + lines[number] = (lines[number] ?? 0) + hits; + } + } + } + } + var covered = 0; + var total = 0; + final output = StringBuffer(); + for (final source in merged.keys.toList()..sort()) { + final lines = merged[source]!; + final missing = lines.entries + .where((e) => e.value == 0) + .map((e) => e.key) + .toList() + ..sort(); + covered += lines.length - missing.length; + total += lines.length; + output.writeln('SF:$source'); + for (final line in lines.keys.toList()..sort()) { + output.writeln('DA:$line,${lines[line]}'); + } + output.writeln('LF:${lines.length}'); + output.writeln('LH:${lines.length - missing.length}'); + output.writeln('end_of_record'); + if (missing.isNotEmpty) { + stdout.writeln('$source: uncovered lines ${missing.join(", ")}'); + } + } + Directory('coverage').createSync(recursive: true); + File('coverage/lcov.info').writeAsStringSync(output.toString()); + stdout.writeln( + 'Coverage: $covered/$total executable lines ' + '(${total == 0 ? "0.00" : (100 * covered / total).toStringAsFixed(2)}%)', + ); + if (failed || total == 0 || covered != total) exitCode = 1; +} diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/hooks/commands/melos_command.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/hooks/commands/melos_command.dart index 15ad78a..afd29a1 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/hooks/commands/melos_command.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/hooks/commands/melos_command.dart @@ -11,18 +11,19 @@ final class MelosCommand extends CliCommand { await runChecked( context, - startMessage: 'Activating Melos globally', - endMessage: 'Melos activated globally', + startMessage: 'Installing workspace tooling', + endMessage: 'Workspace tooling installed', executable: 'dart', - arguments: ['pub', 'global', 'activate', 'melos'], + arguments: ['pub', 'get'], + workingDirectory: appName, ); await runChecked( context, startMessage: 'Running melos bootstrap', endMessage: 'Dependencies installed', - executable: 'melos', - arguments: ['bootstrap'], + executable: 'dart', + arguments: ['run', 'melos', 'bootstrap'], workingDirectory: appName, ); } diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/hooks/commands/module_vars.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/hooks/commands/module_vars.dart index 3e044c6..b472511 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/hooks/commands/module_vars.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/hooks/commands/module_vars.dart @@ -46,14 +46,24 @@ void resolveModuleVars(HookContext context) { final usesFirebase = _firebaseBackedModules.any((module) => _flag(context, module)); context.vars['firebase'] = usesFirebase; + context.vars['emulators'] = + _flag(context, 'auth') || _flag(context, 'firestore'); + context.vars['firebase_sdk_mocks'] = _firebaseBackedModules + .where((module) => module != 'firestore') + .any((module) => _flag(context, module)); // Empty path segment → mason skips the file, so a project with no Firebase // modules never ships a placeholder `firebase_options.dart`. context.vars['firebase_options_file'] = usesFirebase ? 'firebase_options.dart' : ''; - // The boot test runs the real bootstrap. Firebase projects can boot before - // `flutterfire configure` now (those modules are skipped), but after - // configure the splash may land on sign-in instead of the dashboard, so - // they still don't ship this file. - context.vars['smoke_test_file'] = usesFirebase ? '' : 'smoke_test.dart'; + // Every project ships an entrypoint smoke test. SDK-specific suites and + // lifecycle adapters are omitted only when their module is absent. + context.vars['notification_lifecycle_file'] = + _flag(context, 'notifications') ? 'notification_lifecycle.dart' : ''; + context.vars['notification_lifecycle_test_file'] = + _flag(context, 'notifications') ? 'notification_lifecycle_test.dart' : ''; + context.vars['firebase_bootstrap_test_file'] = + usesFirebase ? 'firebase_bootstrap_test.dart' : ''; + context.vars['auth_token_provider_test_file'] = + _flag(context, 'network') ? 'token_provider_test.dart' : ''; } diff --git a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/hooks/commands/next_steps_command.dart b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/hooks/commands/next_steps_command.dart index 7bc8352..f62f071 100644 --- a/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/hooks/commands/next_steps_command.dart +++ b/packages/nonstop_cli/bricks/flutter_project_with_mono_repo/hooks/commands/next_steps_command.dart @@ -21,6 +21,10 @@ final class NextStepsCommand extends CliCommand { } logger + ..info('') + ..info('Verify the workspace (from $appName):') + ..info(' dart run melos run lint') + ..info(' dart run melos run coverage') ..info('') ..info('Run the app:') ..info(' cd $appName/apps/$appName && flutter run'); diff --git a/packages/nonstop_cli/lib/commands/create/command.dart b/packages/nonstop_cli/lib/commands/create/command.dart index d175c8d..dc3150f 100644 --- a/packages/nonstop_cli/lib/commands/create/command.dart +++ b/packages/nonstop_cli/lib/commands/create/command.dart @@ -23,9 +23,7 @@ class CreateCommand extends Command { CreateCommand({ required this.logger, @visibleForTesting MasonGeneratorFromBundle? generatorFromBundle, - @visibleForTesting MasonGeneratorFromBrick? generatorFromBrick, - }) : _generatorFromBundle = generatorFromBundle ?? MasonGenerator.fromBundle, - _generatorFromBrick = generatorFromBrick ?? MasonGenerator.fromBrick { + }) : _generatorFromBundle = generatorFromBundle ?? MasonGenerator.fromBundle { argParser ..addOption( 'output-directory', @@ -79,7 +77,6 @@ class CreateCommand extends Command { final Logger logger; final MasonGeneratorFromBundle _generatorFromBundle; - final MasonGeneratorFromBrick _generatorFromBrick; @override String get name => 'create'; @@ -204,19 +201,10 @@ class CreateCommand extends Command { } } - Future _getGeneratorForTemplate() async { - try { - final brick = Brick.version( - name: template.bundle.name, - version: '^${template.bundle.version}', - ); - logger.detail( - '''Building generator from brick: ${brick.name} ${brick.location.version}''', - ); - return await _generatorFromBrick(brick); - } catch (error) { - logger.detail('Building generator from brick failed: $error'); - } + /// Use the tested template shipped with this CLI version, without silently + /// replacing it with a different registry version at generation time. + @visibleForTesting + Future createGenerator() async { logger.detail( '''Building generator from bundle ${template.bundle.name} ${template.bundle.version}''', ); @@ -227,7 +215,7 @@ class CreateCommand extends Command { Future run() async { logger.logSignature(); final template = this.template; - final generator = await _getGeneratorForTemplate(); + final generator = await createGenerator(); final result = await runCreate(generator, template); return result; diff --git a/packages/nonstop_cli/lib/commands/create/flutter_project_with_mono_repo_bundle.dart b/packages/nonstop_cli/lib/commands/create/flutter_project_with_mono_repo_bundle.dart index 5448b17..18aa27c 100644 --- a/packages/nonstop_cli/lib/commands/create/flutter_project_with_mono_repo_bundle.dart +++ b/packages/nonstop_cli/lib/commands/create/flutter_project_with_mono_repo_bundle.dart @@ -5,6 +5,12 @@ import 'package:mason/mason.dart'; final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "files": [ + { + "path": "{{ name.snakeCase() }}/.github/workflows/quality.yml", + "data": + "bmFtZTogVGVtcGxhdGUgcXVhbGl0eQpvbjogW3B1c2gsIHB1bGxfcmVxdWVzdF0KcGVybWlzc2lvbnM6CiAgY29udGVudHM6IHJlYWQKam9iczoKICBxdWFsaXR5OgogICAgcnVucy1vbjogdWJ1bnR1LWxhdGVzdAogICAgc3RlcHM6CiAgICAgIC0gdXNlczogYWN0aW9ucy9jaGVja291dEB2NAogICAgICAtIHVzZXM6IHN1Ym9zaXRvL2ZsdXR0ZXItYWN0aW9uQHYyCiAgICAgICAgd2l0aDoKICAgICAgICAgIGZsdXR0ZXItdmVyc2lvbjogJzMuNDQuMCcKICAgICAgICAgIGNhY2hlOiB0cnVlCiAgICAgIC0gcnVuOiBkYXJ0IHB1YiBnZXQKICAgICAgLSBydW46IGRhcnQgcnVuIG1lbG9zIGJvb3RzdHJhcAogICAgICAtIHJ1bjogZGFydCBydW4gbWVsb3MgcnVuIGxpbnQKICAgICAgLSBydW46IGRhcnQgcnVuIG1lbG9zIHJ1biBjb3ZlcmFnZQogICAgICAtIHJ1bjogZmx1dHRlciBidWlsZCB3ZWIKICAgICAgICB3b3JraW5nLWRpcmVjdG9yeTogYXBwcy97e25hbWUuc25ha2VDYXNlKCl9fQogICAgICAtIHVzZXM6IGFjdGlvbnMvdXBsb2FkLWFydGlmYWN0QHY0CiAgICAgICAgaWY6IGFsd2F5cygpCiAgICAgICAgd2l0aDoKICAgICAgICAgIG5hbWU6IGNvdmVyYWdlCiAgICAgICAgICBwYXRoOiBjb3ZlcmFnZS9sY292LmluZm8K", + "type": "text" + }, { "path": "{{ name.snakeCase() }}/.gitignore", "data": @@ -26,28 +32,28 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ { "path": "{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/lib/app.dart", "data": - "aW1wb3J0ICdwYWNrYWdlOmNvcmUvY29yZS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRlc2lnbl9zeXN0ZW0vZGVzaWduX3N5c3RlbS5kYXJ0JzsKe3sjbm90aWZpY2F0aW9uc319aW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwp7ey9ub3RpZmljYXRpb25zfX1pbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlci9tYXRlcmlhbC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmxvY2FsaXphdGlvbi9sb2NhbGl6YXRpb24uZGFydCc7Cnt7I25vdGlmaWNhdGlvbnN9fWltcG9ydCAncGFja2FnZTpub3RpZmljYXRpb25zL25vdGlmaWNhdGlvbnMuZGFydCc7Cnt7L25vdGlmaWNhdGlvbnN9fWltcG9ydCAncGFja2FnZTp7e25hbWUuc25ha2VDYXNlKCl9fS9yb3V0ZXIvcm91dGVyLmRhcnQnOwoKY2xhc3MgQXBwIGV4dGVuZHMgU3RhdGVmdWxXaWRnZXQgewogIGNvbnN0IEFwcCh7c3VwZXIua2V5fSk7CgogIEBvdmVycmlkZQogIFN0YXRlPEFwcD4gY3JlYXRlU3RhdGUoKSA9PiBfQXBwU3RhdGUoKTsKfQoKY2xhc3MgX0FwcFN0YXRlIGV4dGVuZHMgU3RhdGU8QXBwPiB7Cnt7I25vdGlmaWNhdGlvbnN9fSAgbGF0ZSBmaW5hbCBBcHBMaWZlY3ljbGVMaXN0ZW5lciBfbGlmZWN5Y2xlTGlzdGVuZXI7Cgp7ey9ub3RpZmljYXRpb25zfX0gIEBvdmVycmlkZQogIHZvaWQgaW5pdFN0YXRlKCkgewogICAgc3VwZXIuaW5pdFN0YXRlKCk7Cnt7I25vdGlmaWNhdGlvbnN9fSAgICAvLyBBc2tpbmcgZm9yIG5vdGlmaWNhdGlvbiBwZXJtaXNzaW9uIG5lZWRzIGEgZm9yZWdyb3VuZCBzdXJmYWNlLCBzbyB0aGlzCiAgICAvLyBydW5zIGZyb20gdGhlIGZpcnN0IGZyYW1lIHJhdGhlciB0aGFuIGZyb20gYm9vdHN0cmFwLiBNb3ZlIGl0IGJlaGluZAogICAgLy8gc2lnbi1pbiBvbmNlIHlvdSB3b3VsZCByYXRoZXIgYXNrIGEgdXNlciB3aG8gaGFzIGNvbW1pdHRlZCB0byB0aGUgYXBwLgogICAgX2xpZmVjeWNsZUxpc3RlbmVyID0gQXBwTGlmZWN5Y2xlTGlzdGVuZXIob25SZXN1bWU6IF9jbGVhckJhZGdlKTsKICAgIFdpZGdldHNCaW5kaW5nLmluc3RhbmNlLmFkZFBvc3RGcmFtZUNhbGxiYWNrKChfKSBhc3luYyB7CiAgICAgIGlmICghZGkuaGFzPE5vdGlmaWNhdGlvbkNsaWVudD4oKSkgcmV0dXJuOwogICAgICBmaW5hbCBsb2dnZXIgPSBkaS5nZXQ8TG9nZ2VyPigpOwogICAgICB0cnkgewogICAgICAgIGF3YWl0IGRpLmdldDxOb3RpZmljYXRpb25DbGllbnQ+KCkuaW5pdCgpOwogICAgICB9IGNhdGNoIChlLCBzKSB7CiAgICAgICAgbG9nZ2VyLmUoJ0ZhaWxlZCB0byBpbml0aWFsaXplIE5vdGlmaWNhdGlvbkNsaWVudCcsIGUsIHMpOwogICAgICB9CiAgICB9KTsKe3svbm90aWZpY2F0aW9uc319ICB9Cnt7I25vdGlmaWNhdGlvbnN9fQogIHZvaWQgX2NsZWFyQmFkZ2UoKSB7CiAgICBpZiAoIWRpLmhhczxOb3RpZmljYXRpb25DbGllbnQ+KCkpIHJldHVybjsKICAgIGZpbmFsIGxvZ2dlciA9IGRpLmdldDxMb2dnZXI+KCk7CiAgICB0cnkgewogICAgICBkaS5nZXQ8Tm90aWZpY2F0aW9uQ2xpZW50PigpLmNsZWFyQmFkZ2UoKTsKICAgIH0gY2F0Y2ggKGUsIHMpIHsKICAgICAgbG9nZ2VyLmUoJ0ZhaWxlZCB0byBjbGVhciBiYWRnZSBvbiBhcHAgcmVzdW1lJywgZSwgcyk7CiAgICB9CiAgfQoKICBAb3ZlcnJpZGUKICB2b2lkIGRpc3Bvc2UoKSB7CiAgICBfbGlmZWN5Y2xlTGlzdGVuZXIuZGlzcG9zZSgpOwogICAgc3VwZXIuZGlzcG9zZSgpOwogIH0Ke3svbm90aWZpY2F0aW9uc319CiAgQG92ZXJyaWRlCiAgV2lkZ2V0IGJ1aWxkKEJ1aWxkQ29udGV4dCBjb250ZXh0KSB7CiAgICByZXR1cm4gR2xvYmFsRXZlbnRDaGFubmVsUHJvdmlkZXIoCiAgICAgIGNoaWxkOiBEZXNpZ25TeXN0ZW1XcmFwcGVyKAogICAgICAgIGJ1aWxkZXI6IChjb250ZXh0LCB0aGVtZSkgPT4gTWF0ZXJpYWxBcHAucm91dGVyKAogICAgICAgICAgZGVidWdTaG93Q2hlY2tlZE1vZGVCYW5uZXI6IGZhbHNlLAogICAgICAgICAgdGl0bGU6IHN0cmluZ3MuYXBwLm5hbWUsCiAgICAgICAgICB0aGVtZTogdGhlbWUsCiAgICAgICAgICByb3V0ZUluZm9ybWF0aW9uUGFyc2VyOiBBcHBSb3V0ZXIucm91dGVJbmZvcm1hdGlvblBhcnNlciwKICAgICAgICAgIHJvdXRlSW5mb3JtYXRpb25Qcm92aWRlcjogQXBwUm91dGVyLnJvdXRlSW5mb3JtYXRpb25Qcm92aWRlciwKICAgICAgICAgIHJvdXRlckRlbGVnYXRlOiBBcHBSb3V0ZXIucm91dGVyRGVsZWdhdGUsCiAgICAgICAgKSwKICAgICAgKSwKICAgICk7CiAgfQp9Cg==", + "aW1wb3J0ICdwYWNrYWdlOmNvcmUvY29yZS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRlc2lnbl9zeXN0ZW0vZGVzaWduX3N5c3RlbS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZsdXR0ZXIvbWF0ZXJpYWwuZGFydCc7CmltcG9ydCAncGFja2FnZTpnb19yb3V0ZXIvZ29fcm91dGVyLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6bG9jYWxpemF0aW9uL2xvY2FsaXphdGlvbi5kYXJ0JzsKCi8vLyBUaGUgYXBwbGljYXRpb24gdmlldy4gSXRzIG93bmVyIGNyZWF0ZXMgYW5kIGRpc3Bvc2VzIHRoZSByb3V0ZXIuCmNsYXNzIEFwcCBleHRlbmRzIFN0YXRlbGVzc1dpZGdldCB7CiAgY29uc3QgQXBwKHtyZXF1aXJlZCB0aGlzLnJvdXRlciwgc3VwZXIua2V5fSk7CgogIGZpbmFsIEdvUm91dGVyIHJvdXRlcjsKCiAgQG92ZXJyaWRlCiAgV2lkZ2V0IGJ1aWxkKEJ1aWxkQ29udGV4dCBjb250ZXh0KSB7CiAgICByZXR1cm4gR2xvYmFsRXZlbnRDaGFubmVsUHJvdmlkZXIoCiAgICAgIGNoaWxkOiBEZXNpZ25TeXN0ZW1XcmFwcGVyKAogICAgICAgIGJ1aWxkZXI6IChjb250ZXh0LCB0aGVtZSkgPT4gTWF0ZXJpYWxBcHAucm91dGVyKAogICAgICAgICAgZGVidWdTaG93Q2hlY2tlZE1vZGVCYW5uZXI6IGZhbHNlLAogICAgICAgICAgdGl0bGU6IHN0cmluZ3MuYXBwLm5hbWUsCiAgICAgICAgICB0aGVtZTogdGhlbWUsCiAgICAgICAgICByb3V0ZXJDb25maWc6IHJvdXRlciwKICAgICAgICApLAogICAgICApLAogICAgKTsKICB9Cn0K", "type": "text" }, { "path": "{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/lib/bootstrap.dart", "data": - "e3sjYW5hbHl0aWNzfX1pbXBvcnQgJ3BhY2thZ2U6YW5hbHl0aWNzL2FuYWx5dGljcy5kYXJ0JyBhcyBhbmFseXRpY3M7Cnt7L2FuYWx5dGljc319e3sjYXV0aH19aW1wb3J0ICdwYWNrYWdlOmF1dGgvYXV0aC5kYXJ0JyBhcyBhdXRoOwp7ey9hdXRofX1pbXBvcnQgJ3BhY2thZ2U6YmxvYy9ibG9jLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Y29yZS9jb3JlLmRhcnQnIGFzIGNvcmU7Cnt7I2ZpcmViYXNlfX1pbXBvcnQgJ3BhY2thZ2U6Y29yZS9kZXZlbG9wZXIvZW11bGF0b3JzLmRhcnQnIGFzIGVtdWxhdG9yczsKe3svZmlyZWJhc2V9fWltcG9ydCAncGFja2FnZTpjb3JlL2xvZ2dlci9sb2dnZXIuZGFydCc7Cnt7I2NyYXNobHl0aWNzfX1pbXBvcnQgJ3BhY2thZ2U6Y3Jhc2hseXRpY3MvY3Jhc2hseXRpY3MuZGFydCcgYXMgY3Jhc2hseXRpY3M7Cnt7L2NyYXNobHl0aWNzfX1pbXBvcnQgJ3BhY2thZ2U6ZGkvZGkuZGFydCc7Cnt7I2ZlYXR1cmVfZmxhZ3N9fWltcG9ydCAncGFja2FnZTpmZWF0dXJlX2ZsYWdzL2ZlYXR1cmVfZmxhZ3MuZGFydCcgYXMgZmVhdHVyZV9mbGFnczsKe3svZmVhdHVyZV9mbGFnc319e3sjZmlyZWJhc2V9fWltcG9ydCAncGFja2FnZTpmaXJlYmFzZV9jb3JlL2ZpcmViYXNlX2NvcmUuZGFydCc7Cnt7L2ZpcmViYXNlfX1pbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlci93aWRnZXRzLmRhcnQnOwp7eyNuZXR3b3JrfX1pbXBvcnQgJ3BhY2thZ2U6bmV0d29yay9uZXR3b3JrLmRhcnQnIGFzIG5ldHdvcms7Cnt7L25ldHdvcmt9fXt7I25vdGlmaWNhdGlvbnN9fWltcG9ydCAncGFja2FnZTpub3RpZmljYXRpb25zL25vdGlmaWNhdGlvbnMuZGFydCcgYXMgbm90aWZpY2F0aW9uczsKe3svbm90aWZpY2F0aW9uc319e3sjZmlyZWJhc2V9fWltcG9ydCAncGFja2FnZTp7e25hbWUuc25ha2VDYXNlKCl9fS9maXJlYmFzZV9vcHRpb25zLmRhcnQnOwp7ey9maXJlYmFzZX19Ci8vLyBCcmluZ3MgZXZlcnkgbW9kdWxlIHVwLCBpbiBkZXBlbmRlbmN5IG9yZGVyLCBiZWZvcmUgdGhlIGZpcnN0IGZyYW1lLgovLy8KLy8vIE9yZGVyIG1hdHRlcnM6IHRoZSBsb2dnZXIgaXMgcmVnaXN0ZXJlZCBmaXJzdCBzbyBldmVyeXRoaW5nIGFmdGVyIGl0IGNhbgovLy8gcmVwb3J0IGZhaWx1cmVzLCBhbmQgRmlyZWJhc2UgbXVzdCBiZSBsaXZlIGJlZm9yZSBhbnkgRmlyZWJhc2UtYmFja2VkCi8vLyBtb2R1bGUgaW5pdGlhbGlzZXMuIElmIGBmbHV0dGVyZmlyZSBjb25maWd1cmVgIGhhcyBub3QgYmVlbiBydW4geWV0LCB0aG9zZQovLy8gbW9kdWxlcyBhcmUgc2tpcHBlZCBzbyB0aGUgcmVzdCBvZiB0aGUgYXBwIHN0aWxsIGJvb3RzLgpGdXR1cmU8dm9pZD4gaW5pdCgpIGFzeW5jIHsKICBXaWRnZXRzRmx1dHRlckJpbmRpbmcuZW5zdXJlSW5pdGlhbGl6ZWQoKTsKICBmaW5hbCBzdG9wd2F0Y2ggPSBTdG9wd2F0Y2goKS4uc3RhcnQoKTsKCiAgYXdhaXQgY29yZS5pbml0KCk7CiAgZmluYWwgbG9nZ2VyID0gZGkuZ2V0PExvZ2dlcj4oKTsKICBsb2dnZXIuaSgnQ29yZSByZWFkeSBpbiAke3N0b3B3YXRjaC5lbGFwc2VkTWlsbGlzZWNvbmRzfSBtcycpOwoKICBCbG9jLm9ic2VydmVyID0gY29yZS5Db3JlQmxvY09ic2VydmVyKCk7Cnt7I2ZpcmViYXNlfX0KICB2YXIgZmlyZWJhc2VSZWFkeSA9IGZhbHNlOwogIHRyeSB7CiAgICBmaW5hbCBvcHRpb25zID0gRGVmYXVsdEZpcmViYXNlT3B0aW9ucy5jdXJyZW50UGxhdGZvcm07CiAgICBhd2FpdCBGaXJlYmFzZS5pbml0aWFsaXplQXBwKG9wdGlvbnM6IG9wdGlvbnMpOwogICAgZmlyZWJhc2VSZWFkeSA9IHRydWU7CiAgICBpZiAoY29yZS5FbnZpcm9ubWVudC51c2VFbXVsYXRvcnMpIHsKICAgICAgYXdhaXQgZW11bGF0b3JzLmluaXQoKTsKICAgIH0KICB9IG9uIFVuc3VwcG9ydGVkRXJyb3IgY2F0Y2ggKGVycm9yKSB7CiAgICBsb2dnZXIudygnJGVycm9yJyk7CiAgfQogIGxvZ2dlci5pKAogICAgZmlyZWJhc2VSZWFkeQogICAgICAgID8gJ0ZpcmViYXNlIHJlYWR5JwogICAgICAgIDogJ0ZpcmViYXNlIG5vdCBjb25maWd1cmVkIHlldDsgc2tpcHBpbmcgRmlyZWJhc2UgbW9kdWxlcycsCiAgKTsKe3svZmlyZWJhc2V9fQp7eyNjcmFzaGx5dGljc319ICBpZiAoZmlyZWJhc2VSZWFkeSkgYXdhaXQgY3Jhc2hseXRpY3MuaW5pdCgpOwp7ey9jcmFzaGx5dGljc319e3sjYW5hbHl0aWNzfX0gIGlmIChmaXJlYmFzZVJlYWR5KSBhd2FpdCBhbmFseXRpY3MuaW5pdCgpOwp7ey9hbmFseXRpY3N9fXt7I2ZlYXR1cmVfZmxhZ3N9fSAgaWYgKGZpcmViYXNlUmVhZHkpIGF3YWl0IGZlYXR1cmVfZmxhZ3MuaW5pdCgpOwp7ey9mZWF0dXJlX2ZsYWdzfX17eyNhdXRofX0KICBpZiAoZmlyZWJhc2VSZWFkeSkgewogICAgZmluYWwgb3B0aW9ucyA9IERlZmF1bHRGaXJlYmFzZU9wdGlvbnMuY3VycmVudFBsYXRmb3JtOwogICAgZmluYWwgY2xpZW50SWQgPSBvcHRpb25zLmlvc0NsaWVudElkID8/IG9wdGlvbnMuYW5kcm9pZENsaWVudElkID8/ICcnOwogICAgYXdhaXQgYXV0aC5pbml0KGF1dGguRGVmYXVsdEF1dGhDb25maWcoY2xpZW50SWQ6IGNsaWVudElkKSk7CiAgfQp7ey9hdXRofX17eyNuZXR3b3JrfX0KICBhd2FpdCBuZXR3b3JrLmluaXQoCiAgICBjb25maWc6IG5ldHdvcmsuRGVmYXVsdE5ldHdvcmtDb25maWcoYmFzZVVybDogY29yZS5FbnZpcm9ubWVudC5iYXNlVXJsKSwKICApOwp7ey9uZXR3b3JrfX17eyNub3RpZmljYXRpb25zfX0KICBpZiAoZmlyZWJhc2VSZWFkeSkgYXdhaXQgbm90aWZpY2F0aW9ucy5pbml0KCk7Cnt7L25vdGlmaWNhdGlvbnN9fQogIC8vIFRPRE86IGluaXRpYWxpc2UgeW91ciBvd24gZmVhdHVyZSBtb2R1bGVzIGhlcmUuCgogIHN0b3B3YXRjaC5zdG9wKCk7CiAgbG9nZ2VyLmkoJ0Jvb3RzdHJhcCBjb21wbGV0ZWQgaW4gJHtzdG9wd2F0Y2guZWxhcHNlZE1pbGxpc2Vjb25kc30gbXMnKTsKe3sjYW5hbHl0aWNzfX0KICBpZiAoZmlyZWJhc2VSZWFkeSkgewogICAgYXdhaXQgYW5hbHl0aWNzLkFuYWx5dGljc0hlbHBlci5sb2dBcHBPcGVuKAogICAgICBwYXJhbWV0ZXJzOiB7J2Jvb3RzdHJhcF9kdXJhdGlvbic6IHN0b3B3YXRjaC5lbGFwc2VkTWlsbGlzZWNvbmRzfSwKICAgICk7CiAgfQp7ey9hbmFseXRpY3N9fX0K", + "e3sjYW5hbHl0aWNzfX1pbXBvcnQgJ3BhY2thZ2U6YW5hbHl0aWNzL2FuYWx5dGljcy5kYXJ0JyBhcyBhbmFseXRpY3M7Cnt7L2FuYWx5dGljc319Cnt7I2F1dGh9fWltcG9ydCAncGFja2FnZTphdXRoL2F1dGguZGFydCcgYXMgYXV0aDsKe3svYXV0aH19CmltcG9ydCAncGFja2FnZTpibG9jL2Jsb2MuZGFydCc7CmltcG9ydCAncGFja2FnZTpjb3JlL2NvcmUuZGFydCcgYXMgY29yZTsKe3sjZmlyZWJhc2V9fWltcG9ydCAncGFja2FnZTpjb3JlL2RldmVsb3Blci9lbXVsYXRvcnMuZGFydCcgYXMgZW11bGF0b3JzOwp7ey9maXJlYmFzZX19CmltcG9ydCAncGFja2FnZTpjb3JlL2xvZ2dlci9sb2dnZXIuZGFydCc7Cnt7I2NyYXNobHl0aWNzfX1pbXBvcnQgJ3BhY2thZ2U6Y3Jhc2hseXRpY3MvY3Jhc2hseXRpY3MuZGFydCcgYXMgY3Jhc2hseXRpY3M7Cnt7L2NyYXNobHl0aWNzfX0KaW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwp7eyNub3RpZmljYXRpb25zfX1pbXBvcnQgJ3BhY2thZ2U6ZGVzaWduX3N5c3RlbS90b2FzdC90b2FzdHMuZGFydCc7Cnt7L25vdGlmaWNhdGlvbnN9fQp7eyNmZWF0dXJlX2ZsYWdzfX1pbXBvcnQgJ3BhY2thZ2U6ZmVhdHVyZV9mbGFncy9mZWF0dXJlX2ZsYWdzLmRhcnQnIGFzIGZlYXR1cmVfZmxhZ3M7Cnt7L2ZlYXR1cmVfZmxhZ3N9fQp7eyNmaXJlYmFzZX19aW1wb3J0ICdwYWNrYWdlOmZpcmViYXNlX2NvcmUvZmlyZWJhc2VfY29yZS5kYXJ0JzsKe3svZmlyZWJhc2V9fQppbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlci93aWRnZXRzLmRhcnQnOwp7eyNuZXR3b3JrfX1pbXBvcnQgJ3BhY2thZ2U6bmV0d29yay9uZXR3b3JrLmRhcnQnIGFzIG5ldHdvcms7Cnt7L25ldHdvcmt9fQp7eyNub3RpZmljYXRpb25zfX1pbXBvcnQgJ3BhY2thZ2U6bm90aWZpY2F0aW9ucy9ub3RpZmljYXRpb25zLmRhcnQnIGFzIG5vdGlmaWNhdGlvbnM7Cnt7L25vdGlmaWNhdGlvbnN9fQp7eyNmaXJlYmFzZX19aW1wb3J0ICdwYWNrYWdlOnt7bmFtZS5zbmFrZUNhc2UoKX19L2ZpcmViYXNlX29wdGlvbnMuZGFydCc7Cnt7L2ZpcmViYXNlfX0KCi8vLyBCcmluZ3MgZXZlcnkgbW9kdWxlIHVwLCBpbiBkZXBlbmRlbmN5IG9yZGVyLCBiZWZvcmUgdGhlIGZpcnN0IGZyYW1lLgovLy8KLy8vIE9yZGVyIG1hdHRlcnM6IHRoZSBsb2dnZXIgaXMgcmVnaXN0ZXJlZCBmaXJzdCBzbyBldmVyeXRoaW5nIGFmdGVyIGl0IGNhbgovLy8gcmVwb3J0IGZhaWx1cmVzLCBhbmQgRmlyZWJhc2UgbXVzdCBiZSBsaXZlIGJlZm9yZSBhbnkgRmlyZWJhc2UtYmFja2VkCi8vLyBtb2R1bGUgaW5pdGlhbGlzZXMuIElmIGBmbHV0dGVyZmlyZSBjb25maWd1cmVgIGhhcyBub3QgYmVlbiBydW4geWV0LCB0aG9zZQovLy8gbW9kdWxlcyBhcmUgc2tpcHBlZCBzbyB0aGUgcmVzdCBvZiB0aGUgYXBwIHN0aWxsIGJvb3RzLgpGdXR1cmU8dm9pZD4gaW5pdCh7CiAgdm9pZCBGdW5jdGlvbihTdHJpbmcgcm91dGUpPyBvbk9wZW5Sb3V0ZSwKe3sjZmlyZWJhc2V9fSAgRmlyZWJhc2VPcHRpb25zPyBmaXJlYmFzZU9wdGlvbnMsCiAgYm9vbCB1c2VFbXVsYXRvcnMgPSBjb3JlLkVudmlyb25tZW50LnVzZUVtdWxhdG9ycywKe3svZmlyZWJhc2V9fQp9KSBhc3luYyB7CiAgV2lkZ2V0c0ZsdXR0ZXJCaW5kaW5nLmVuc3VyZUluaXRpYWxpemVkKCk7CiAgZmluYWwgc3RvcHdhdGNoID0gU3RvcHdhdGNoKCkuLnN0YXJ0KCk7CgogIGF3YWl0IGNvcmUuaW5pdCgpOwogIGZpbmFsIGxvZ2dlciA9IGRpLmdldDxMb2dnZXI+KCk7CiAgbG9nZ2VyLmkoJ0NvcmUgcmVhZHkgaW4gJHtzdG9wd2F0Y2guZWxhcHNlZE1pbGxpc2Vjb25kc30gbXMnKTsKCiAgQmxvYy5vYnNlcnZlciA9IGNvcmUuQ29yZUJsb2NPYnNlcnZlcigpOwoKe3sjZmlyZWJhc2V9fSAgdmFyIGZpcmViYXNlUmVhZHkgPSBmYWxzZTsKICBGaXJlYmFzZU9wdGlvbnM/IHJlc29sdmVkT3B0aW9uczsKICB0cnkgewogICAgcmVzb2x2ZWRPcHRpb25zID0gZmlyZWJhc2VPcHRpb25zID8/IERlZmF1bHRGaXJlYmFzZU9wdGlvbnMuY3VycmVudFBsYXRmb3JtOwogICAgYXdhaXQgRmlyZWJhc2UuaW5pdGlhbGl6ZUFwcChvcHRpb25zOiByZXNvbHZlZE9wdGlvbnMpOwogICAgZmlyZWJhc2VSZWFkeSA9IHRydWU7CiAgICBpZiAodXNlRW11bGF0b3JzKSB7CiAgICAgIGF3YWl0IGVtdWxhdG9ycy5pbml0KCk7CiAgICB9CiAgfSBvbiBVbnN1cHBvcnRlZEVycm9yIGNhdGNoIChlcnJvcikgewogICAgbG9nZ2VyLncoJyRlcnJvcicpOwogIH0KICBsb2dnZXIuaSgKICAgIGZpcmViYXNlUmVhZHkKICAgICAgICA/ICdGaXJlYmFzZSByZWFkeScKICAgICAgICA6ICdGaXJlYmFzZSBub3QgY29uZmlndXJlZCB5ZXQ7IHNraXBwaW5nIEZpcmViYXNlIG1vZHVsZXMnLAogICk7Cgp7ey9maXJlYmFzZX19e3sjY3Jhc2hseXRpY3N9fSAgaWYgKGZpcmViYXNlUmVhZHkpIGF3YWl0IGNyYXNobHl0aWNzLmluaXQoKTsKe3svY3Jhc2hseXRpY3N9fQp7eyNhbmFseXRpY3N9fSAgaWYgKGZpcmViYXNlUmVhZHkpIGF3YWl0IGFuYWx5dGljcy5pbml0KCk7Cnt7L2FuYWx5dGljc319Cnt7I2ZlYXR1cmVfZmxhZ3N9fSAgaWYgKGZpcmViYXNlUmVhZHkpIGF3YWl0IGZlYXR1cmVfZmxhZ3MuaW5pdCgpOwp7ey9mZWF0dXJlX2ZsYWdzfX0KCnt7I2F1dGh9fSAgaWYgKGZpcmViYXNlUmVhZHkpIHsKICAgIGZpbmFsIGNsaWVudElkID0KICAgICAgICByZXNvbHZlZE9wdGlvbnMhLmlvc0NsaWVudElkID8/IHJlc29sdmVkT3B0aW9ucy5hbmRyb2lkQ2xpZW50SWQgPz8gJyc7CiAgICBhd2FpdCBhdXRoLmluaXQoYXV0aC5EZWZhdWx0QXV0aENvbmZpZyhjbGllbnRJZDogY2xpZW50SWQpKTsKICB9Cgp7ey9hdXRofX17eyNuZXR3b3JrfX0gIGF3YWl0IG5ldHdvcmsuaW5pdCgKICAgIGNvbmZpZzogbmV0d29yay5EZWZhdWx0TmV0d29ya0NvbmZpZyhiYXNlVXJsOiBjb3JlLkVudmlyb25tZW50LmJhc2VVcmwpLAogICk7Cgp7ey9uZXR3b3JrfX17eyNub3RpZmljYXRpb25zfX0gIGlmIChmaXJlYmFzZVJlYWR5KSB7CiAgICBhd2FpdCBub3RpZmljYXRpb25zLmluaXQoCiAgICAgIGNvbmZpZzogbm90aWZpY2F0aW9ucy5Ob3RpZmljYXRpb25Db25maWcoCiAgICAgICAgb25Gb3JlZ3JvdW5kOiAodGl0bGUsIGJvZHkpID0+CiAgICAgICAgICAgIFRvYXN0Lm5vdGlmaWNhdGlvbih0aXRsZTogdGl0bGUsIGJvZHk6IGJvZHkpLAogICAgICAgIG9uT3BlblJvdXRlOiBvbk9wZW5Sb3V0ZSwKICAgICAgKSwKICAgICk7CiAgfQoKe3svbm90aWZpY2F0aW9uc319ICAvLyBUT0RPOiBpbml0aWFsaXNlIHlvdXIgb3duIGZlYXR1cmUgbW9kdWxlcyBoZXJlLgoKICBzdG9wd2F0Y2guc3RvcCgpOwogIGxvZ2dlci5pKCdCb290c3RyYXAgY29tcGxldGVkIGluICR7c3RvcHdhdGNoLmVsYXBzZWRNaWxsaXNlY29uZHN9IG1zJyk7Cgp7eyNhbmFseXRpY3N9fSAgaWYgKGZpcmViYXNlUmVhZHkpIHsKICAgIGF3YWl0IGFuYWx5dGljcy5BbmFseXRpY3NIZWxwZXIubG9nQXBwT3BlbigKICAgICAgcGFyYW1ldGVyczogeydib290c3RyYXBfZHVyYXRpb24nOiBzdG9wd2F0Y2guZWxhcHNlZE1pbGxpc2Vjb25kc30sCiAgICApOwogIH17ey9hbmFseXRpY3N9fQp9Cg==", "type": "text" }, { "path": "{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/lib/main.dart", "data": - "aW1wb3J0ICdwYWNrYWdlOmZsdXR0ZXIvbWF0ZXJpYWwuZGFydCc7CmltcG9ydCAncGFja2FnZTp7e25hbWUuc25ha2VDYXNlKCl9fS9hcHAuZGFydCc7CmltcG9ydCAncGFja2FnZTp7e25hbWUuc25ha2VDYXNlKCl9fS9ib290c3RyYXAuZGFydCcgYXMgYm9vdHN0cmFwOwoKdm9pZCBtYWluKCkgYXN5bmMgewogIGF3YWl0IGJvb3RzdHJhcC5pbml0KCk7CiAgcnVuQXBwKGNvbnN0IEFwcCgpKTsKfQo=", + "aW1wb3J0ICdwYWNrYWdlOmZsdXR0ZXIvbWF0ZXJpYWwuZGFydCc7Cnt7I25vdGlmaWNhdGlvbnN9fWltcG9ydCAncGFja2FnZTpjb3JlL2NvcmUuZGFydCc7Cnt7L25vdGlmaWNhdGlvbnN9fQppbXBvcnQgJ3BhY2thZ2U6ZGkvZGkuZGFydCc7CmltcG9ydCAncGFja2FnZTpnb19yb3V0ZXIvZ29fcm91dGVyLmRhcnQnOwp7eyNub3RpZmljYXRpb25zfX1pbXBvcnQgJ3BhY2thZ2U6bm90aWZpY2F0aW9ucy9ub3RpZmljYXRpb25zLmRhcnQnOwp7ey9ub3RpZmljYXRpb25zfX0KaW1wb3J0ICdwYWNrYWdlOnt7bmFtZS5zbmFrZUNhc2UoKX19L2FwcC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOnt7bmFtZS5zbmFrZUNhc2UoKX19L2Jvb3RzdHJhcC5kYXJ0JyBhcyBib290c3RyYXA7Cnt7I25vdGlmaWNhdGlvbnN9fWltcG9ydCAncGFja2FnZTp7e25hbWUuc25ha2VDYXNlKCl9fS9ub3RpZmljYXRpb25fbGlmZWN5Y2xlLmRhcnQnOwp7ey9ub3RpZmljYXRpb25zfX0KaW1wb3J0ICdwYWNrYWdlOnt7bmFtZS5zbmFrZUNhc2UoKX19L3JvdXRlci9yb3V0ZXIuZGFydCc7CgpGdXR1cmU8dm9pZD4gbWFpbigpID0+IHN0YXJ0QXBwKCk7CgovLy8gQ29tcG9zaXRpb24gcm9vdC4gUXVldWUgY29sZC1zdGFydCBub3RpZmljYXRpb24gcm91dGVzIHVudGlsIHJvdXRpbmcgZXhpc3RzLgpGdXR1cmU8dm9pZD4gc3RhcnRBcHAoewogIEZ1dHVyZTx2b2lkPiBGdW5jdGlvbih2b2lkIEZ1bmN0aW9uKFN0cmluZykgb25PcGVuUm91dGUpPyBpbml0aWFsaXplLAogIHZvaWQgRnVuY3Rpb24oV2lkZ2V0KSBtb3VudCA9IHJ1bkFwcCwKfSkgYXN5bmMgewogIEdvUm91dGVyPyBhY3RpdmVSb3V0ZXI7CiAgU3RyaW5nPyBwZW5kaW5nUm91dGU7CiAgdm9pZCBvbk9wZW5Sb3V0ZShTdHJpbmcgcm91dGUpIHsKICAgIGlmIChhY3RpdmVSb3V0ZXIgPT0gbnVsbCkgewogICAgICBwZW5kaW5nUm91dGUgPSByb3V0ZTsKICAgIH0gZWxzZSB7CiAgICAgIGFjdGl2ZVJvdXRlci5nbyhyb3V0ZSk7CiAgICB9CiAgfQoKICBpZiAoaW5pdGlhbGl6ZSA9PSBudWxsKSB7CiAgICBhd2FpdCBib290c3RyYXAuaW5pdChvbk9wZW5Sb3V0ZTogb25PcGVuUm91dGUpOwogIH0gZWxzZSB7CiAgICBhd2FpdCBpbml0aWFsaXplKG9uT3BlblJvdXRlKTsKICB9CiAgZmluYWwgcm91dGVyID0gQXBwUm91dGVyLmNyZWF0ZVJvdXRlcihpbml0aWFsTG9jYXRpb246IHBlbmRpbmdSb3V0ZSk7CiAgYWN0aXZlUm91dGVyID0gcm91dGVyOwogIGRpLnJlZ2lzdGVyPEdvUm91dGVyPihyb3V0ZXIsIGRpc3Bvc2U6IChyb3V0ZXIpID0+IHJvdXRlci5kaXNwb3NlKCkpOwogIG1vdW50KAp7eyNub3RpZmljYXRpb25zfX0gICAgTm90aWZpY2F0aW9uTGlmZWN5Y2xlKAogICAgICBsb2dnZXI6IGRpLmdldDxMb2dnZXI+KCksCiAgICAgIGNsaWVudDogZGkuaGFzPE5vdGlmaWNhdGlvbkNsaWVudD4oKQogICAgICAgICAgPyBkaS5nZXQ8Tm90aWZpY2F0aW9uQ2xpZW50PigpCiAgICAgICAgICA6IG51bGwsCiAgICAgIGNoaWxkOiBBcHAocm91dGVyOiByb3V0ZXIpLAogICAgKSx7ey9ub3RpZmljYXRpb25zfX17e15ub3RpZmljYXRpb25zfX0gICAgQXBwKHJvdXRlcjogcm91dGVyKSx7ey9ub3RpZmljYXRpb25zfX0KICApOwp9Cg==", "type": "text" }, { "path": "{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/lib/router/router.dart", "data": - "e3sjYW5hbHl0aWNzfX1pbXBvcnQgJ3BhY2thZ2U6YW5hbHl0aWNzL2FuYWx5dGljcy5kYXJ0JzsKe3svYW5hbHl0aWNzfX17eyNhdXRofX1pbXBvcnQgJ3BhY2thZ2U6YXV0aC9hdXRoLmRhcnQnIGFzIGF1dGg7Cnt7L2F1dGh9fWltcG9ydCAncGFja2FnZTpjb3JlL2NvcmUuZGFydCcgYXMgY29yZTsKe3sjZGFzaGJvYXJkfX1pbXBvcnQgJ3BhY2thZ2U6ZGFzaGJvYXJkL2Rhc2hib2FyZC5kYXJ0JzsKe3svZGFzaGJvYXJkfX1pbXBvcnQgJ3BhY2thZ2U6ZGVzaWduX3N5c3RlbS9kZXNpZ25fc3lzdGVtLmRhcnQnOwp7eyNkZXZlbG9wZXJ9fWltcG9ydCAncGFja2FnZTpkZXZlbG9wZXIvZGV2ZWxvcGVyLmRhcnQnIGFzIGRldmVsb3BlcjsKe3svZGV2ZWxvcGVyfX1pbXBvcnQgJ3BhY2thZ2U6ZGkvZGkuZGFydCc7Cnt7I2FuYWx5dGljc319aW1wb3J0ICdwYWNrYWdlOmZpcmViYXNlX2NvcmUvZmlyZWJhc2VfY29yZS5kYXJ0JzsKe3svYW5hbHl0aWNzfX1pbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlci9mb3VuZGF0aW9uLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlci9tYXRlcmlhbC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmdvX3JvdXRlci9nb19yb3V0ZXIuZGFydCc7CmltcG9ydCAncGFja2FnZTpsb2NhbGl6YXRpb24vbG9jYWxpemF0aW9uLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6bmF2aWdhdGlvbl9oaXN0b3J5X29ic2VydmVyL25hdmlnYXRpb25faGlzdG9yeV9vYnNlcnZlci5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOnt7bmFtZS5zbmFrZUNhc2UoKX19L3VpL3NwbGFzaF9zY3JlZW4uZGFydCc7CgovLy8gVGhlIGFwcCdzIHNpbmdsZSBbR29Sb3V0ZXJdLgovLy8KLy8vIEZlYXR1cmUgcGFja2FnZXMgZXhwb3NlIHRoZWlyIG93biBgcm91dGVzYCBsaXN0IGFuZCBhcmUgc3BsaWNlZCBpbiBoZXJlLCBzbwovLy8gYWRkaW5nIGEgZmVhdHVyZSBpcyBvbmUgaW1wb3J0IHBsdXMgb25lIHNwcmVhZCAtIG5vIHJvdXRlIHRhYmxlIHRvIG1lcmdlLgpjbGFzcyBBcHBSb3V0ZXIgewogIGNvbnN0IEFwcFJvdXRlci5fKCk7CgogIHN0YXRpYyBmaW5hbCBHb1JvdXRlciBfcm91dGVyID0gY3JlYXRlUm91dGVyKCk7CgogIHN0YXRpYyBSb3V0ZXJEZWxlZ2F0ZTxPYmplY3Q+IGdldCByb3V0ZXJEZWxlZ2F0ZSA9PiBfcm91dGVyLnJvdXRlckRlbGVnYXRlOwoKICBzdGF0aWMgUm91dGVJbmZvcm1hdGlvblBhcnNlcjxPYmplY3Q+IGdldCByb3V0ZUluZm9ybWF0aW9uUGFyc2VyID0+CiAgICAgIF9yb3V0ZXIucm91dGVJbmZvcm1hdGlvblBhcnNlcjsKCiAgc3RhdGljIFJvdXRlSW5mb3JtYXRpb25Qcm92aWRlcj8gZ2V0IHJvdXRlSW5mb3JtYXRpb25Qcm92aWRlciA9PgogICAgICBfcm91dGVyLnJvdXRlSW5mb3JtYXRpb25Qcm92aWRlcjsKCiAgc3RhdGljIEdvUm91dGVyIGNyZWF0ZVJvdXRlcigpIHsKICAgIGZpbmFsIHJvdXRlciA9IEdvUm91dGVyKAogICAgICBkZWJ1Z0xvZ0RpYWdub3N0aWNzOiBrRGVidWdNb2RlLAogICAgICBpbml0aWFsTG9jYXRpb246IGNvcmUuQ29yZVJvdXRlcy5yb290LAogICAgICBvYnNlcnZlcnM6IFsKICAgICAgICBOYXZpZ2F0aW9uSGlzdG9yeU9ic2VydmVyKCksCiAgICAgICAgY29yZS5Db3JlUm91dGVPYnNlcnZlcigpLAp7eyNhbmFseXRpY3N9fSAgICAgICAgaWYgKEZpcmViYXNlLmFwcHMuaXNOb3RFbXB0eSkgQW5hbHl0aWNzUm91dGVPYnNlcnZlcigpLAp7ey9hbmFseXRpY3N9fSAgICAgIF0sCiAgICAgIGVycm9yQnVpbGRlcjogKGNvbnRleHQsIHN0YXRlKSA9PiBFcnJvclNjcmVlbigKICAgICAgICB0aXRsZTogc3RyaW5ncy5lcnJvcnMucGFnZV9ub3RfZm91bmQsCiAgICAgICAgbWVzc2FnZTogc3RyaW5ncy5lcnJvcnMucGFnZV9ub3RfZm91bmRfZGVzY3JpcHRpb24sCiAgICAgICAgb25Hb0hvbWU6ICgpID0+IGNvbnRleHQuZ28oY29yZS5Db3JlUm91dGVzLnJvb3QpLAogICAgICAgIGVycm9yOiBzdGF0ZS51cmkudG9TdHJpbmcoKSwKICAgICAgKSwKICAgICAgcm91dGVzOiBbCiAgICAgICAgR29Sb3V0ZSgKICAgICAgICAgIHBhdGg6IGNvcmUuQ29yZVJvdXRlcy5yb290LAogICAgICAgICAgYnVpbGRlcjogKGNvbnRleHQsIHN0YXRlKSA9PiBjb25zdCBTcGxhc2hTY3JlZW4oKSwKICAgICAgICApLAp7eyNkYXNoYm9hcmR9fSAgICAgICAgR29Sb3V0ZSgKICAgICAgICAgIHBhdGg6IGNvcmUuQ29yZVJvdXRlcy5ob21lLAogICAgICAgICAgcmVkaXJlY3Q6IChjb250ZXh0LCBzdGF0ZSkgPT4gRGFzaGJvYXJkUm91dGVyLmhvbWUsCiAgICAgICAgKSwKICAgICAgICBEYXNoYm9hcmRSb3V0ZXIuY3JlYXRlU2hlbGxSb3V0ZSgpLAp7ey9kYXNoYm9hcmR9fXt7XmRhc2hib2FyZH19ICAgICAgICBHb1JvdXRlKAogICAgICAgICAgcGF0aDogY29yZS5Db3JlUm91dGVzLmhvbWUsCiAgICAgICAgICBidWlsZGVyOiAoY29udGV4dCwgc3RhdGUpID0+IGNvbnN0IF9Ib21lU2NyZWVuKCksCiAgICAgICAgKSwKe3svZGFzaGJvYXJkfX17eyNhdXRofX0gICAgICAgIC4uLmF1dGguQXV0aFJvdXRlcigKICAgICAgICAgIG9uU2lnbmVkSW46IF9vbkF1dGhlbnRpY2F0ZWQsCiAgICAgICAgICBvblNpZ25lZFVwOiBfb25BdXRoZW50aWNhdGVkLAogICAgICAgICkucm91dGVzLAp7ey9hdXRofX17eyNkZXZlbG9wZXJ9fSAgICAgICAgLi4uZGV2ZWxvcGVyLkRldmVsb3BlclJvdXRlcigpLnJvdXRlcywKe3svZGV2ZWxvcGVyfX0gICAgICAgIEdvUm91dGUoCiAgICAgICAgICBwYXRoOiBjb3JlLkNvcmVSb3V0ZXMuZXJyb3IsCiAgICAgICAgICBidWlsZGVyOiAoY29udGV4dCwgc3RhdGUpID0+IEVycm9yU2NyZWVuKAogICAgICAgICAgICB0aXRsZToKICAgICAgICAgICAgICAgIHN0YXRlLnVyaS5xdWVyeVBhcmFtZXRlcnNbY29yZS5LZXlzLnRpdGxlXSA/PwogICAgICAgICAgICAgICAgc3RyaW5ncy5nZW5lcmljLmVycm9yLAogICAgICAgICAgICBtZXNzYWdlOgogICAgICAgICAgICAgICAgc3RhdGUudXJpLnF1ZXJ5UGFyYW1ldGVyc1tjb3JlLktleXMubWVzc2FnZV0gPz8KICAgICAgICAgICAgICAgIHN0cmluZ3MuZXJyb3JzLnVuZXhwZWN0ZWRfZXJyb3IsCiAgICAgICAgICAgIGVycm9yOiBzdGF0ZS51cmkucXVlcnlQYXJhbWV0ZXJzW2NvcmUuS2V5cy5lcnJvcl0sCiAgICAgICAgICAgIG9uR29Ib21lOiAoKSA9PiBjb250ZXh0LmdvKGNvcmUuQ29yZVJvdXRlcy5yb290KSwKICAgICAgICAgICksCiAgICAgICAgKSwKICAgICAgXSwKICAgICk7CgogICAgZGkucmVnaXN0ZXI8R29Sb3V0ZXI+KHJvdXRlcik7CiAgICByZXR1cm4gcm91dGVyOwogIH0Ke3sjYXV0aH19CiAgLy8vIFdoZXJlIGEgdXNlciBsYW5kcyBvbmNlIHNpZ24taW4gb3Igc2lnbi11cCBzdWNjZWVkcy4KICAvLy8KICAvLy8gTG9hZCB0aGUgcHJvZmlsZSAvIGVudGl0bGVtZW50cyB5b3UgbmVlZCBoZXJlIGJlZm9yZSByb3V0aW5nIG9uLgogIHN0YXRpYyBGdXR1cmU8dm9pZD4gX29uQXV0aGVudGljYXRlZChCdWlsZENvbnRleHQgY29udGV4dCkgYXN5bmMgewp7eyNhbmFseXRpY3N9fSAgICBhd2FpdCBBbmFseXRpY3NIZWxwZXIubG9nRXZlbnQoQW5hbHl0aWNzRXZlbnRzLnVzZXIuYXV0aGVudGljYXRlZFJlZGlyZWN0KTsKe3svYW5hbHl0aWNzfX0gICAgaWYgKGNvbnRleHQubW91bnRlZCkgewogICAgICBjb250ZXh0LmdvKHt7I2Rhc2hib2FyZH19RGFzaGJvYXJkUm91dGVyLmhvbWV7ey9kYXNoYm9hcmR9fXt7XmRhc2hib2FyZH19Y29yZS5Db3JlUm91dGVzLmhvbWV7ey9kYXNoYm9hcmR9fSk7CiAgICB9CiAgfQp7ey9hdXRofX19Cnt7XmRhc2hib2FyZH19Ci8vLyBQbGFjZWhvbGRlciBsYW5kaW5nIHNjcmVlbiAtIHJlcGxhY2UgaXQgd2l0aCB5b3VyIGZpcnN0IGZlYXR1cmUuCmNsYXNzIF9Ib21lU2NyZWVuIGV4dGVuZHMgU3RhdGVsZXNzV2lkZ2V0IHsKICBjb25zdCBfSG9tZVNjcmVlbigpOwoKICBAb3ZlcnJpZGUKICBXaWRnZXQgYnVpbGQoQnVpbGRDb250ZXh0IGNvbnRleHQpIHsKICAgIHJldHVybiBTY2FmZm9sZCgKICAgICAgYXBwQmFyOiBBcHBCYXIodGl0bGU6IFRleHQoc3RyaW5ncy5hcHAubmFtZSkpLAogICAgICBib2R5OiBDZW50ZXIoCiAgICAgICAgY2hpbGQ6IHt7I2RldmVsb3Blcn19ZGV2ZWxvcGVyLk9wZW5EZXZUb29sc1dyYXBwZXIoCiAgICAgICAgICAvLyBUYXAgNXggdG8gcmVhY2ggdGhlIGRldmVsb3BlciB0b29scy4KICAgICAgICAgIGNoaWxkOiBUZXh0KHN0cmluZ3MuYXBwLndlbGNvbWVfdG9fYXBwKSwKICAgICAgICApe3svZGV2ZWxvcGVyfX17e15kZXZlbG9wZXJ9fVRleHQoc3RyaW5ncy5hcHAud2VsY29tZV90b19hcHApe3svZGV2ZWxvcGVyfX0sCiAgICAgICksCiAgICApOwogIH0KfQp7ey9kYXNoYm9hcmR9fQ==", + "e3sjYW5hbHl0aWNzfX1pbXBvcnQgJ3BhY2thZ2U6YW5hbHl0aWNzL2FuYWx5dGljcy5kYXJ0JzsKe3svYW5hbHl0aWNzfX17eyNhdXRofX1pbXBvcnQgJ3BhY2thZ2U6YXV0aC9hdXRoLmRhcnQnIGFzIGF1dGg7Cnt7L2F1dGh9fWltcG9ydCAncGFja2FnZTpjb3JlL2NvcmUuZGFydCcgYXMgY29yZTsKe3sjZGFzaGJvYXJkfX1pbXBvcnQgJ3BhY2thZ2U6ZGFzaGJvYXJkL2Rhc2hib2FyZC5kYXJ0JzsKe3svZGFzaGJvYXJkfX1pbXBvcnQgJ3BhY2thZ2U6ZGVzaWduX3N5c3RlbS9kZXNpZ25fc3lzdGVtLmRhcnQnOwp7eyNkZXZlbG9wZXJ9fWltcG9ydCAncGFja2FnZTpkZXZlbG9wZXIvZGV2ZWxvcGVyLmRhcnQnIGFzIGRldmVsb3BlcjsKe3svZGV2ZWxvcGVyfX17eyNhbmFseXRpY3N9fWltcG9ydCAncGFja2FnZTpkaS9kaS5kYXJ0JzsKe3svYW5hbHl0aWNzfX0KaW1wb3J0ICdwYWNrYWdlOmZsdXR0ZXIvZm91bmRhdGlvbi5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZsdXR0ZXIvbWF0ZXJpYWwuZGFydCc7CmltcG9ydCAncGFja2FnZTpnb19yb3V0ZXIvZ29fcm91dGVyLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6bG9jYWxpemF0aW9uL2xvY2FsaXphdGlvbi5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOnt7bmFtZS5zbmFrZUNhc2UoKX19L3VpL3NwbGFzaF9zY3JlZW4uZGFydCc7CgovLy8gVGhlIGFwcCdzIHNpbmdsZSBbR29Sb3V0ZXJdLgovLy8KLy8vIEZlYXR1cmUgcGFja2FnZXMgZXhwb3NlIHRoZWlyIG93biBgcm91dGVzYCBsaXN0IGFuZCBhcmUgc3BsaWNlZCBpbiBoZXJlLCBzbwovLy8gYWRkaW5nIGEgZmVhdHVyZSBpcyBvbmUgaW1wb3J0IHBsdXMgb25lIHNwcmVhZCAtIG5vIHJvdXRlIHRhYmxlIHRvIG1lcmdlLgphYnN0cmFjdCBmaW5hbCBjbGFzcyBBcHBSb3V0ZXIgewoKICBzdGF0aWMgR29Sb3V0ZXIgY3JlYXRlUm91dGVyKHtTdHJpbmc/IGluaXRpYWxMb2NhdGlvbn0pIHsKICAgIGZpbmFsIHJvdXRlciA9IEdvUm91dGVyKAogICAgICBkZWJ1Z0xvZ0RpYWdub3N0aWNzOiBrRGVidWdNb2RlLAogICAgICBpbml0aWFsTG9jYXRpb246IGluaXRpYWxMb2NhdGlvbiA/PyBjb3JlLkNvcmVSb3V0ZXMucm9vdCwKICAgICAgb2JzZXJ2ZXJzOiBbCiAgICAgICAgY29yZS5Db3JlUm91dGVPYnNlcnZlcigpLAp7eyNhbmFseXRpY3N9fSAgICAgICAgaWYgKGRpLmhhczxBbmFseXRpY3NDbGllbnQ+KCkpCiAgICAgICAgICBBbmFseXRpY3NSb3V0ZU9ic2VydmVyKGNsaWVudDogZGkuZ2V0PEFuYWx5dGljc0NsaWVudD4oKSwgbG9nZ2VyOiBkaS5nZXQ8Y29yZS5Mb2dnZXI+KCkpLAp7ey9hbmFseXRpY3N9fSAgICAgIF0sCiAgICAgIGVycm9yQnVpbGRlcjogKGNvbnRleHQsIHN0YXRlKSA9PiBFcnJvclNjcmVlbigKICAgICAgICB0aXRsZTogc3RyaW5ncy5lcnJvcnMucGFnZV9ub3RfZm91bmQsCiAgICAgICAgbWVzc2FnZTogc3RyaW5ncy5lcnJvcnMucGFnZV9ub3RfZm91bmRfZGVzY3JpcHRpb24sCiAgICAgICAgb25Hb0hvbWU6ICgpID0+IGNvbnRleHQuZ28oY29yZS5Db3JlUm91dGVzLnJvb3QpLAogICAgICAgIGVycm9yOiBzdGF0ZS51cmkudG9TdHJpbmcoKSwKICAgICAgKSwKICAgICAgcm91dGVzOiBbCiAgICAgICAgR29Sb3V0ZSgKICAgICAgICAgIHBhdGg6IGNvcmUuQ29yZVJvdXRlcy5yb290LAogICAgICAgICAgYnVpbGRlcjogKGNvbnRleHQsIHN0YXRlKSA9PiBjb25zdCBTcGxhc2hTY3JlZW4oKSwKICAgICAgICApLAp7eyNkYXNoYm9hcmR9fSAgICAgICAgR29Sb3V0ZSgKICAgICAgICAgIHBhdGg6IGNvcmUuQ29yZVJvdXRlcy5ob21lLAogICAgICAgICAgcmVkaXJlY3Q6IChjb250ZXh0LCBzdGF0ZSkgPT4gRGFzaGJvYXJkUm91dGVyLmhvbWUsCiAgICAgICAgKSwKICAgICAgICBEYXNoYm9hcmRSb3V0ZXIuY3JlYXRlU2hlbGxSb3V0ZSgpLAp7ey9kYXNoYm9hcmR9fXt7XmRhc2hib2FyZH19ICAgICAgICBHb1JvdXRlKAogICAgICAgICAgcGF0aDogY29yZS5Db3JlUm91dGVzLmhvbWUsCiAgICAgICAgICBidWlsZGVyOiAoY29udGV4dCwgc3RhdGUpID0+IGNvbnN0IF9Ib21lU2NyZWVuKCksCiAgICAgICAgKSwKe3svZGFzaGJvYXJkfX17eyNhdXRofX0gICAgICAgIC4uLmF1dGguQXV0aFJvdXRlcigKICAgICAgICAgIG9uU2lnbmVkSW46IF9vbkF1dGhlbnRpY2F0ZWQsCiAgICAgICAgICBvblNpZ25lZFVwOiBfb25BdXRoZW50aWNhdGVkLAogICAgICAgICkucm91dGVzLAp7ey9hdXRofX17eyNkZXZlbG9wZXJ9fSAgICAgICAgLi4uZGV2ZWxvcGVyLkRldmVsb3BlclJvdXRlcigpLnJvdXRlcywKe3svZGV2ZWxvcGVyfX0gICAgICAgIEdvUm91dGUoCiAgICAgICAgICBwYXRoOiBjb3JlLkNvcmVSb3V0ZXMuZXJyb3IsCiAgICAgICAgICBidWlsZGVyOiAoY29udGV4dCwgc3RhdGUpID0+IEVycm9yU2NyZWVuKAogICAgICAgICAgICB0aXRsZToKICAgICAgICAgICAgICAgIHN0YXRlLnVyaS5xdWVyeVBhcmFtZXRlcnNbY29yZS5LZXlzLnRpdGxlXSA/PwogICAgICAgICAgICAgICAgc3RyaW5ncy5nZW5lcmljLmVycm9yLAogICAgICAgICAgICBtZXNzYWdlOgogICAgICAgICAgICAgICAgc3RhdGUudXJpLnF1ZXJ5UGFyYW1ldGVyc1tjb3JlLktleXMubWVzc2FnZV0gPz8KICAgICAgICAgICAgICAgIHN0cmluZ3MuZXJyb3JzLnVuZXhwZWN0ZWRfZXJyb3IsCiAgICAgICAgICAgIGVycm9yOiBzdGF0ZS51cmkucXVlcnlQYXJhbWV0ZXJzW2NvcmUuS2V5cy5lcnJvcl0sCiAgICAgICAgICAgIG9uR29Ib21lOiAoKSA9PiBjb250ZXh0LmdvKGNvcmUuQ29yZVJvdXRlcy5yb290KSwKICAgICAgICAgICksCiAgICAgICAgKSwKICAgICAgXSwKICAgICk7CgogICAgcmV0dXJuIHJvdXRlcjsKICB9Cnt7I2F1dGh9fQogIC8vLyBXaGVyZSBhIHVzZXIgbGFuZHMgb25jZSBzaWduLWluIG9yIHNpZ24tdXAgc3VjY2VlZHMuCiAgLy8vCiAgLy8vIExvYWQgdGhlIHByb2ZpbGUgLyBlbnRpdGxlbWVudHMgeW91IG5lZWQgaGVyZSBiZWZvcmUgcm91dGluZyBvbi4KICBzdGF0aWMgRnV0dXJlPHZvaWQ+IF9vbkF1dGhlbnRpY2F0ZWQoQnVpbGRDb250ZXh0IGNvbnRleHQpIGFzeW5jIHsKe3sjYW5hbHl0aWNzfX0gICAgYXdhaXQgQW5hbHl0aWNzSGVscGVyLmxvZ0V2ZW50KEFuYWx5dGljc0V2ZW50cy51c2VyLmF1dGhlbnRpY2F0ZWRSZWRpcmVjdCk7Cnt7L2FuYWx5dGljc319ICAgIGlmIChjb250ZXh0Lm1vdW50ZWQpIHsKICAgICAgY29udGV4dC5nbyh7eyNkYXNoYm9hcmR9fURhc2hib2FyZFJvdXRlci5ob21le3svZGFzaGJvYXJkfX17e15kYXNoYm9hcmR9fWNvcmUuQ29yZVJvdXRlcy5ob21le3svZGFzaGJvYXJkfX0pOwogICAgfQogIH0Ke3svYXV0aH19fQp7e15kYXNoYm9hcmR9fQovLy8gUGxhY2Vob2xkZXIgbGFuZGluZyBzY3JlZW4gLSByZXBsYWNlIGl0IHdpdGggeW91ciBmaXJzdCBmZWF0dXJlLgpjbGFzcyBfSG9tZVNjcmVlbiBleHRlbmRzIFN0YXRlbGVzc1dpZGdldCB7CiAgY29uc3QgX0hvbWVTY3JlZW4oKTsKCiAgQG92ZXJyaWRlCiAgV2lkZ2V0IGJ1aWxkKEJ1aWxkQ29udGV4dCBjb250ZXh0KSB7CiAgICByZXR1cm4gU2NhZmZvbGQoCiAgICAgIGFwcEJhcjogQXBwQmFyKHRpdGxlOiBUZXh0KHN0cmluZ3MuYXBwLm5hbWUpKSwKICAgICAgYm9keTogQ2VudGVyKAogICAgICAgIGNoaWxkOiB7eyNkZXZlbG9wZXJ9fWRldmVsb3Blci5PcGVuRGV2VG9vbHNXcmFwcGVyKAogICAgICAgICAgLy8gVGFwIDV4IHRvIHJlYWNoIHRoZSBkZXZlbG9wZXIgdG9vbHMuCiAgICAgICAgICBjaGlsZDogVGV4dChzdHJpbmdzLmFwcC53ZWxjb21lX3RvX2FwcCksCiAgICAgICAgKXt7L2RldmVsb3Blcn19e3teZGV2ZWxvcGVyfX1UZXh0KHN0cmluZ3MuYXBwLndlbGNvbWVfdG9fYXBwKXt7L2RldmVsb3Blcn19LAogICAgICApLAogICAgKTsKICB9Cn0Ke3svZGFzaGJvYXJkfX0K", "type": "text" }, { @@ -61,20 +67,61 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "path": "{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/lib/{{firebase_options_file}}", "data": - "Ly8gVGhpcyBmaWxlIGlzIGEgcGxhY2Vob2xkZXIuIEdlbmVyYXRlIHRoZSByZWFsIG9uZSB3aXRoOgovLwovLyAgIGNkIGFwcHMve3tuYW1lLnNuYWtlQ2FzZSgpfX0gJiYgZmx1dHRlcmZpcmUgY29uZmlndXJlCi8vCi8vIEZsdXR0ZXJGaXJlIG92ZXJ3cml0ZXMgdGhpcyBmaWxlIHdpdGggeW91ciBwcm9qZWN0J3Mgb3B0aW9ucyBhbmQgYWxzbyBkcm9wcwovLyBnb29nbGUtc2VydmljZXMuanNvbiAvIEdvb2dsZVNlcnZpY2UtSW5mby5wbGlzdCBpbnRvIHRoZSBuYXRpdmUgZm9sZGVycy4KLy8gVW50aWwgdGhlbiwgYm9vdHN0cmFwIGNhdGNoZXMgdGhlIHRocm93IGFuZCBza2lwcyBGaXJlYmFzZS1iYWNrZWQgbW9kdWxlcwovLyBzbyB0aGUgcmVzdCBvZiB0aGUgYXBwIHN0aWxsIHJ1bnMuCmltcG9ydCAncGFja2FnZTpmaXJlYmFzZV9jb3JlL2ZpcmViYXNlX2NvcmUuZGFydCcgc2hvdyBGaXJlYmFzZU9wdGlvbnM7CgpjbGFzcyBEZWZhdWx0RmlyZWJhc2VPcHRpb25zIHsKICBjb25zdCBEZWZhdWx0RmlyZWJhc2VPcHRpb25zLl8oKTsKCiAgc3RhdGljIEZpcmViYXNlT3B0aW9ucyBnZXQgY3VycmVudFBsYXRmb3JtID0+IHRocm93IFVuc3VwcG9ydGVkRXJyb3IoCiAgICAnRmlyZWJhc2UgaGFzIG5vdCBiZWVuIGNvbmZpZ3VyZWQgZm9yIHt7bmFtZS50aXRsZUNhc2UoKX19LlxuJwogICAgJ1J1biBgZmx1dHRlcmZpcmUgY29uZmlndXJlYCBpbnNpZGUgYXBwcy97e25hbWUuc25ha2VDYXNlKCl9fSAnCiAgICAndG8gcmVwbGFjZSBsaWIvZmlyZWJhc2Vfb3B0aW9ucy5kYXJ0LicsCiAgKTsKfQo=", + "Ly8gVGhpcyBmaWxlIGlzIGEgcGxhY2Vob2xkZXIuIEdlbmVyYXRlIHRoZSByZWFsIG9uZSB3aXRoOgovLwovLyAgIGNkIGFwcHMve3tuYW1lLnNuYWtlQ2FzZSgpfX0gJiYgZmx1dHRlcmZpcmUgY29uZmlndXJlCi8vCi8vIEZsdXR0ZXJGaXJlIG92ZXJ3cml0ZXMgdGhpcyBmaWxlIHdpdGggeW91ciBwcm9qZWN0J3Mgb3B0aW9ucyBhbmQgYWxzbyBkcm9wcwovLyBnb29nbGUtc2VydmljZXMuanNvbiAvIEdvb2dsZVNlcnZpY2UtSW5mby5wbGlzdCBpbnRvIHRoZSBuYXRpdmUgZm9sZGVycy4KLy8gVW50aWwgdGhlbiwgYm9vdHN0cmFwIGNhdGNoZXMgdGhlIHRocm93IGFuZCBza2lwcyBGaXJlYmFzZS1iYWNrZWQgbW9kdWxlcwovLyBzbyB0aGUgcmVzdCBvZiB0aGUgYXBwIHN0aWxsIHJ1bnMuCmltcG9ydCAncGFja2FnZTpmaXJlYmFzZV9jb3JlL2ZpcmViYXNlX2NvcmUuZGFydCcgc2hvdyBGaXJlYmFzZU9wdGlvbnM7CgphYnN0cmFjdCBmaW5hbCBjbGFzcyBEZWZhdWx0RmlyZWJhc2VPcHRpb25zIHsKICBzdGF0aWMgRmlyZWJhc2VPcHRpb25zIGdldCBjdXJyZW50UGxhdGZvcm0gPT4gdGhyb3cgVW5zdXBwb3J0ZWRFcnJvcigKICAgICdGaXJlYmFzZSBoYXMgbm90IGJlZW4gY29uZmlndXJlZCBmb3Ige3tuYW1lLnRpdGxlQ2FzZSgpfX0uXG4nCiAgICAnUnVuIGBmbHV0dGVyZmlyZSBjb25maWd1cmVgIGluc2lkZSBhcHBzL3t7bmFtZS5zbmFrZUNhc2UoKX19ICcKICAgICd0byByZXBsYWNlIGxpYi9maXJlYmFzZV9vcHRpb25zLmRhcnQuJywKICApOwp9Cg==", + "type": "text" + }, + { + "path": + "{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/lib/{{notification_lifecycle_file}}", + "data": + "aW1wb3J0ICdwYWNrYWdlOmNvcmUvY29yZS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZsdXR0ZXIvd2lkZ2V0cy5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOm5vdGlmaWNhdGlvbnMvbm90aWZpY2F0aW9ucy5kYXJ0JzsKCi8vLyBPd25zIGZvcmVncm91bmQgbm90aWZpY2F0aW9uIHdvcmsgaW5kZXBlbmRlbnRseSBvZiB0aGUgYXBwbGljYXRpb24gdmlldy4KY2xhc3MgTm90aWZpY2F0aW9uTGlmZWN5Y2xlIGV4dGVuZHMgU3RhdGVmdWxXaWRnZXQgewogIGNvbnN0IE5vdGlmaWNhdGlvbkxpZmVjeWNsZSh7CiAgICByZXF1aXJlZCB0aGlzLmNoaWxkLAogICAgcmVxdWlyZWQgdGhpcy5sb2dnZXIsCiAgICB0aGlzLmNsaWVudCwKICAgIHN1cGVyLmtleSwKICB9KTsKCiAgZmluYWwgV2lkZ2V0IGNoaWxkOwogIGZpbmFsIExvZ2dlciBsb2dnZXI7CiAgZmluYWwgTm90aWZpY2F0aW9uQ2xpZW50PyBjbGllbnQ7CgogIEBvdmVycmlkZQogIFN0YXRlPE5vdGlmaWNhdGlvbkxpZmVjeWNsZT4gY3JlYXRlU3RhdGUoKSA9PiBfTm90aWZpY2F0aW9uTGlmZWN5Y2xlU3RhdGUoKTsKfQoKY2xhc3MgX05vdGlmaWNhdGlvbkxpZmVjeWNsZVN0YXRlIGV4dGVuZHMgU3RhdGU8Tm90aWZpY2F0aW9uTGlmZWN5Y2xlPiB7CiAgbGF0ZSBmaW5hbCBBcHBMaWZlY3ljbGVMaXN0ZW5lciBfbGlzdGVuZXI7CgogIEBvdmVycmlkZQogIHZvaWQgaW5pdFN0YXRlKCkgewogICAgc3VwZXIuaW5pdFN0YXRlKCk7CiAgICBfbGlzdGVuZXIgPSBBcHBMaWZlY3ljbGVMaXN0ZW5lcihvblJlc3VtZTogX2NsZWFyQmFkZ2UpOwogICAgV2lkZ2V0c0JpbmRpbmcuaW5zdGFuY2UuYWRkUG9zdEZyYW1lQ2FsbGJhY2soKF8pIGFzeW5jIHsKICAgICAgaWYgKCFtb3VudGVkKSByZXR1cm47CiAgICAgIHRyeSB7CiAgICAgICAgYXdhaXQgd2lkZ2V0LmNsaWVudD8uaW5pdCgpOwogICAgICB9IGNhdGNoIChlcnJvciwgc3RhY2tUcmFjZSkgewogICAgICAgIHdpZGdldC5sb2dnZXIuZSgKICAgICAgICAgICdOb3RpZmljYXRpb24gaW5pdGlhbGl6YXRpb24gZmFpbGVkJywKICAgICAgICAgIGVycm9yLAogICAgICAgICAgc3RhY2tUcmFjZSwKICAgICAgICApOwogICAgICB9CiAgICB9KTsKICB9CgogIEZ1dHVyZTx2b2lkPiBfY2xlYXJCYWRnZSgpIGFzeW5jIHsKICAgIHRyeSB7CiAgICAgIGF3YWl0IHdpZGdldC5jbGllbnQ/LmNsZWFyQmFkZ2UoKTsKICAgIH0gY2F0Y2ggKGVycm9yLCBzdGFja1RyYWNlKSB7CiAgICAgIHdpZGdldC5sb2dnZXIuZSgnTm90aWZpY2F0aW9uIGJhZGdlIGNsZWFyaW5nIGZhaWxlZCcsIGVycm9yLCBzdGFja1RyYWNlKTsKICAgIH0KICB9CgogIEBvdmVycmlkZQogIHZvaWQgZGlzcG9zZSgpIHsKICAgIF9saXN0ZW5lci5kaXNwb3NlKCk7CiAgICBzdXBlci5kaXNwb3NlKCk7CiAgfQoKICBAb3ZlcnJpZGUKICBXaWRnZXQgYnVpbGQoQnVpbGRDb250ZXh0IGNvbnRleHQpID0+IHdpZGdldC5jaGlsZDsKfQo=", "type": "text" }, { "path": "{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/pubspec.yaml", "data": - "bmFtZToge3tuYW1lLnNuYWtlQ2FzZSgpfX0KZGVzY3JpcHRpb246ICJ7e3tkZXNjcmlwdGlvbn19fSIKcHVibGlzaF90bzogJ25vbmUnCnZlcnNpb246IDAuMS4wKzEKCmVudmlyb25tZW50OgogIHNkazogXjMuOC4wCiAgZmx1dHRlcjogIj49My4yOS4wIgoKZGVwZW5kZW5jaWVzOgogIGZsdXR0ZXI6CiAgICBzZGs6IGZsdXR0ZXIKICBjdXBlcnRpbm9faWNvbnM6IF4xLjAuOAogIGdvX3JvdXRlcjogXjE1LjEuMwogIGJsb2M6IF45LjAuMAogIG5hdmlnYXRpb25faGlzdG9yeV9vYnNlcnZlcjogXjEuMS4xCiAgY29yZToKICAgIHBhdGg6IC4uLy4uL3BhY2thZ2VzL2NvcmUKICBkZXNpZ25fc3lzdGVtOgogICAgcGF0aDogLi4vLi4vcGFja2FnZXMvZGVzaWduX3N5c3RlbQogIGRpOgogICAgcGF0aDogLi4vLi4vcGFja2FnZXMvZGkKICBsb2NhbGl6YXRpb246CiAgICBwYXRoOiAuLi8uLi9wYWNrYWdlcy9sb2NhbGl6YXRpb24KICB1dGlsczoKICAgIHBhdGg6IC4uLy4uL3BhY2thZ2VzL3V0aWxzCnt7I2ZpcmViYXNlfX0gIGZpcmViYXNlX2NvcmU6IF4zLjE0LjAKe3svZmlyZWJhc2V9fXt7I25ldHdvcmt9fSAgbmV0d29yazoKICAgIHBhdGg6IC4uLy4uL3BhY2thZ2VzL25ldHdvcmsKe3svbmV0d29ya319e3sjYW5hbHl0aWNzfX0gIGFuYWx5dGljczoKICAgIHBhdGg6IC4uLy4uL3BhY2thZ2VzL2FuYWx5dGljcwp7ey9hbmFseXRpY3N9fXt7I2NyYXNobHl0aWNzfX0gIGNyYXNobHl0aWNzOgogICAgcGF0aDogLi4vLi4vcGFja2FnZXMvY3Jhc2hseXRpY3MKe3svY3Jhc2hseXRpY3N9fXt7I2ZlYXR1cmVfZmxhZ3N9fSAgZmVhdHVyZV9mbGFnczoKICAgIHBhdGg6IC4uLy4uL3BhY2thZ2VzL2ZlYXR1cmVfZmxhZ3MKe3svZmVhdHVyZV9mbGFnc319e3sjbm90aWZpY2F0aW9uc319ICBub3RpZmljYXRpb25zOgogICAgcGF0aDogLi4vLi4vcGFja2FnZXMvbm90aWZpY2F0aW9ucwp7ey9ub3RpZmljYXRpb25zfX17eyNkZXZlbG9wZXJ9fSAgZGV2ZWxvcGVyOgogICAgcGF0aDogLi4vLi4vcGFja2FnZXMvZGV2ZWxvcGVyCnt7L2RldmVsb3Blcn19e3sjYXV0aH19ICBhdXRoOgogICAgcGF0aDogLi4vLi4vZmVhdHVyZXMvYXV0aAp7ey9hdXRofX17eyNkYXNoYm9hcmR9fSAgZGFzaGJvYXJkOgogICAgcGF0aDogLi4vLi4vZmVhdHVyZXMvZGFzaGJvYXJkCnt7L2Rhc2hib2FyZH19CmRldl9kZXBlbmRlbmNpZXM6CiAgZmx1dHRlcl90ZXN0OgogICAgc2RrOiBmbHV0dGVyCiAgZmx1dHRlcl9saW50czogXjUuMC4wCgpkZXBlbmRlbmN5X292ZXJyaWRlczoKICBpbnRsOiBeMC4yMC4yCgpmbHV0dGVyOgogIHVzZXMtbWF0ZXJpYWwtZGVzaWduOiB0cnVlCnt7I2F1dGh9fSAgZm9udHM6CiAgICAjIGZpcmViYXNlX3VpX2F1dGggc2hpcHMgdGhpcyBmb250IGJ1dCBuZXZlciByZWdpc3RlcnMgaXQsIHNvIHRoZSBHb29nbGUKICAgICMgYW5kIEFwcGxlIGJ1dHRvbnMgcmVuZGVyIGFzIHRvZnUgdW5sZXNzIHRoZSBhcHAgZGVjbGFyZXMgaXQgaGVyZS4KICAgIC0gZmFtaWx5OiBTb2NpYWxJY29ucwogICAgICBmb250czoKICAgICAgICAtIGFzc2V0OiBwYWNrYWdlcy9maXJlYmFzZV91aV9hdXRoL2ZvbnRzL1NvY2lhbEljb25zLnR0Zgp7ey9hdXRofX0=", + "bmFtZToge3tuYW1lLnNuYWtlQ2FzZSgpfX0KZGVzY3JpcHRpb246ICJ7e3tkZXNjcmlwdGlvbn19fSIKcHVibGlzaF90bzogJ25vbmUnCnZlcnNpb246IDAuMS4wKzEKCmVudmlyb25tZW50OgogIHNkazogXjMuOC4wCiAgZmx1dHRlcjogIj49My4yOS4wIgoKZGVwZW5kZW5jaWVzOgogIGZsdXR0ZXI6CiAgICBzZGs6IGZsdXR0ZXIKICBjdXBlcnRpbm9faWNvbnM6IF4xLjAuOAogIGdvX3JvdXRlcjogXjE1LjEuMwogIGJsb2M6IF45LjAuMAogIGNvcmU6CiAgICBwYXRoOiAuLi8uLi9wYWNrYWdlcy9jb3JlCiAgZGVzaWduX3N5c3RlbToKICAgIHBhdGg6IC4uLy4uL3BhY2thZ2VzL2Rlc2lnbl9zeXN0ZW0KICBkaToKICAgIHBhdGg6IC4uLy4uL3BhY2thZ2VzL2RpCiAgbG9jYWxpemF0aW9uOgogICAgcGF0aDogLi4vLi4vcGFja2FnZXMvbG9jYWxpemF0aW9uCiAgdXRpbHM6CiAgICBwYXRoOiAuLi8uLi9wYWNrYWdlcy91dGlscwp7eyNmaXJlYmFzZX19ICBmaXJlYmFzZV9jb3JlOiBeMy4xNC4wCnt7L2ZpcmViYXNlfX17eyNuZXR3b3JrfX0gIG5ldHdvcms6CiAgICBwYXRoOiAuLi8uLi9wYWNrYWdlcy9uZXR3b3JrCnt7L25ldHdvcmt9fXt7I2FuYWx5dGljc319ICBhbmFseXRpY3M6CiAgICBwYXRoOiAuLi8uLi9wYWNrYWdlcy9hbmFseXRpY3MKe3svYW5hbHl0aWNzfX17eyNjcmFzaGx5dGljc319ICBjcmFzaGx5dGljczoKICAgIHBhdGg6IC4uLy4uL3BhY2thZ2VzL2NyYXNobHl0aWNzCnt7L2NyYXNobHl0aWNzfX17eyNmZWF0dXJlX2ZsYWdzfX0gIGZlYXR1cmVfZmxhZ3M6CiAgICBwYXRoOiAuLi8uLi9wYWNrYWdlcy9mZWF0dXJlX2ZsYWdzCnt7L2ZlYXR1cmVfZmxhZ3N9fXt7I25vdGlmaWNhdGlvbnN9fSAgbm90aWZpY2F0aW9uczoKICAgIHBhdGg6IC4uLy4uL3BhY2thZ2VzL25vdGlmaWNhdGlvbnMKe3svbm90aWZpY2F0aW9uc319e3sjZGV2ZWxvcGVyfX0gIGRldmVsb3BlcjoKICAgIHBhdGg6IC4uLy4uL3BhY2thZ2VzL2RldmVsb3Blcgp7ey9kZXZlbG9wZXJ9fXt7I2F1dGh9fSAgYXV0aDoKICAgIHBhdGg6IC4uLy4uL2ZlYXR1cmVzL2F1dGgKe3svYXV0aH19e3sjZGFzaGJvYXJkfX0gIGRhc2hib2FyZDoKICAgIHBhdGg6IC4uLy4uL2ZlYXR1cmVzL2Rhc2hib2FyZAp7ey9kYXNoYm9hcmR9fQpkZXZfZGVwZW5kZW5jaWVzOgp7eyNmaXJlYmFzZX19ICBtb2NrdGFpbDogXjEuMC40CiAgcGx1Z2luX3BsYXRmb3JtX2ludGVyZmFjZTogXjIuMS44CiAgZmlyZWJhc2VfY29yZV9wbGF0Zm9ybV9pbnRlcmZhY2U6IF42LjAuMwp7ey9maXJlYmFzZX19e3sjYXV0aH19ICBmaXJlYmFzZV9hdXRoX3BsYXRmb3JtX2ludGVyZmFjZTogXjcuNy4zCnt7L2F1dGh9fXt7I2FuYWx5dGljc319ICBmaXJlYmFzZV9hbmFseXRpY3NfcGxhdGZvcm1faW50ZXJmYWNlOiBeNC40LjMKe3svYW5hbHl0aWNzfX17eyNjcmFzaGx5dGljc319ICBmaXJlYmFzZV9jcmFzaGx5dGljc19wbGF0Zm9ybV9pbnRlcmZhY2U6IF4zLjguMTAKe3svY3Jhc2hseXRpY3N9fXt7I2ZlYXR1cmVfZmxhZ3N9fSAgZmlyZWJhc2VfcmVtb3RlX2NvbmZpZ19wbGF0Zm9ybV9pbnRlcmZhY2U6IF4yLjAuMAp7ey9mZWF0dXJlX2ZsYWdzfX17eyNub3RpZmljYXRpb25zfX0gIGZpcmViYXNlX21lc3NhZ2luZ19wbGF0Zm9ybV9pbnRlcmZhY2U6IF40LjYuMTAKe3svbm90aWZpY2F0aW9uc319ICBmbHV0dGVyX3Rlc3Q6CiAgICBzZGs6IGZsdXR0ZXIKICBmbHV0dGVyX2xpbnRzOiBeNS4wLjAKCmRlcGVuZGVuY3lfb3ZlcnJpZGVzOgogIGludGw6IF4wLjIwLjIKCmZsdXR0ZXI6CiAgdXNlcy1tYXRlcmlhbC1kZXNpZ246IHRydWUKe3sjYXV0aH19ICBmb250czoKICAgICMgZmlyZWJhc2VfdWlfYXV0aCBzaGlwcyB0aGlzIGZvbnQgYnV0IG5ldmVyIHJlZ2lzdGVycyBpdCwgc28gdGhlIEdvb2dsZQogICAgIyBhbmQgQXBwbGUgYnV0dG9ucyByZW5kZXIgYXMgdG9mdSB1bmxlc3MgdGhlIGFwcCBkZWNsYXJlcyBpdCBoZXJlLgogICAgLSBmYW1pbHk6IFNvY2lhbEljb25zCiAgICAgIGZvbnRzOgogICAgICAgIC0gYXNzZXQ6IHBhY2thZ2VzL2ZpcmViYXNlX3VpX2F1dGgvZm9udHMvU29jaWFsSWNvbnMudHRmCnt7L2F1dGh9fQo=", + "type": "text" + }, + { + "path": + "{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/test/app_test.dart", + "data": + "aW1wb3J0ICdwYWNrYWdlOmNvcmUvY29yZS5kYXJ0JyBhcyBjb3JlOwppbXBvcnQgJ3BhY2thZ2U6ZGkvZGkuZGFydCc7CmltcG9ydCAncGFja2FnZTpmbHV0dGVyL21hdGVyaWFsLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlcl90ZXN0L2ZsdXR0ZXJfdGVzdC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmdvX3JvdXRlci9nb19yb3V0ZXIuZGFydCc7CmltcG9ydCAncGFja2FnZTpsb2NhbGl6YXRpb24vbG9jYWxpemF0aW9uLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6e3tuYW1lLnNuYWtlQ2FzZSgpfX0vYXBwLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6e3tuYW1lLnNuYWtlQ2FzZSgpfX0vcm91dGVyL3JvdXRlci5kYXJ0JzsKCnZvaWQgbWFpbigpIHsKICBzZXRVcChjb3JlLmluaXQpOwogIHRlYXJEb3duKGRpLnJlc2V0KTsKCiAgdGVzdFdpZGdldHMoJ3JlbmRlcnMgYW4gaW5qZWN0ZWQgcm91dGVyIHdpdGhvdXQgcGxhdGZvcm0gaW5pdGlhbGl6YXRpb24nLCAoCiAgICB0ZXN0ZXIsCiAgKSBhc3luYyB7CiAgICBmaW5hbCByb3V0ZXIgPSBHb1JvdXRlcigKICAgICAgcm91dGVzOiBbCiAgICAgICAgR29Sb3V0ZShwYXRoOiAnLycsIGJ1aWxkZXI6IChfLCBfKSA9PiBjb25zdCBUZXh0KCdUZXN0IGRlc3RpbmF0aW9uJykpLAogICAgICBdLAogICAgKTsKICAgIGFkZFRlYXJEb3duKHJvdXRlci5kaXNwb3NlKTsKICAgIGF3YWl0IHRlc3Rlci5wdW1wV2lkZ2V0KEFwcChyb3V0ZXI6IHJvdXRlcikpOwogICAgYXdhaXQgdGVzdGVyLnB1bXBBbmRTZXR0bGUoKTsKICAgIGV4cGVjdChmaW5kLnRleHQoJ1Rlc3QgZGVzdGluYXRpb24nKSwgZmluZHNPbmVXaWRnZXQpOwogICAgZXhwZWN0KHRlc3Rlci50YWtlRXhjZXB0aW9uKCksIGlzTnVsbCk7CiAgfSk7CgogIHRlc3RXaWRnZXRzKCdyZWFsIHJvdXRlcyBib290IHdpdGhvdXQgY29uZmlndXJlZCBGaXJlYmFzZSBhbmQgc3dpdGNoIHRhYnMnLCAoCiAgICB0ZXN0ZXIsCiAgKSBhc3luYyB7CiAgICBmaW5hbCByb3V0ZXIgPSBBcHBSb3V0ZXIuY3JlYXRlUm91dGVyKCk7CiAgICBhZGRUZWFyRG93bihyb3V0ZXIuZGlzcG9zZSk7CiAgICBhd2FpdCB0ZXN0ZXIucHVtcFdpZGdldChBcHAocm91dGVyOiByb3V0ZXIpKTsKICAgIGF3YWl0IHRlc3Rlci5wdW1wQW5kU2V0dGxlKCk7Cnt7I2Rhc2hib2FyZH19ICAgIGV4cGVjdChmaW5kLnRleHQoJ0V4cGxvcmUnKSwgZmluZHNXaWRnZXRzKTsKICAgIGF3YWl0IHRlc3Rlci50YXAoZmluZC50ZXh0KCdFeHBsb3JlJykuZmlyc3QpOwogICAgYXdhaXQgdGVzdGVyLnB1bXBBbmRTZXR0bGUoKTsKe3svZGFzaGJvYXJkfX0gICAgcm91dGVyLmdvKCcvZXJyb3InKTsKICAgIGF3YWl0IHRlc3Rlci5wdW1wQW5kU2V0dGxlKCk7CiAgICBleHBlY3QoZmluZC50ZXh0KHN0cmluZ3MuZ2VuZXJpYy5lcnJvciksIGZpbmRzV2lkZ2V0cyk7CiAgICBleHBlY3QoZmluZC50ZXh0KHN0cmluZ3MuZXJyb3JzLnVuZXhwZWN0ZWRfZXJyb3IpLCBmaW5kc1dpZGdldHMpOwogICAgZXhwZWN0KHRlc3Rlci50YWtlRXhjZXB0aW9uKCksIGlzTnVsbCk7CiAgfSk7Cn0K", + "type": "text" + }, + { + "path": + "{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/test/entrypoint_test.dart", + "data": + "aW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlci9tYXRlcmlhbC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZsdXR0ZXJfdGVzdC9mbHV0dGVyX3Rlc3QuZGFydCc7CmltcG9ydCAncGFja2FnZTpnb19yb3V0ZXIvZ29fcm91dGVyLmRhcnQnOwp7eyNuZXR3b3JrfX1pbXBvcnQgJ3BhY2thZ2U6bmV0d29yay9uZXR3b3JrLmRhcnQnOwp7ey9uZXR3b3JrfX0KaW1wb3J0ICdwYWNrYWdlOnt7bmFtZS5zbmFrZUNhc2UoKX19L21haW4uZGFydCcgYXMgZW50cnlwb2ludDsKCnZvaWQgbWFpbigpIHsKICB0ZWFyRG93bihkaS5yZXNldCk7CiAgdGVzdFdpZGdldHMoJ3JlYWwgZW50cnlwb2ludCBzdGFydHMgb2ZmbGluZSB3aXRob3V0IEZpcmViYXNlIGNyZWRlbnRpYWxzJywgKAogICAgdGVzdGVyLAogICkgYXN5bmMgewogICAgYXdhaXQgZW50cnlwb2ludC5tYWluKCk7CiAgICBhd2FpdCB0ZXN0ZXIucHVtcCgpOwogICAgYXdhaXQgdGVzdGVyLnB1bXBBbmRTZXR0bGUoKTsKe3sjbmV0d29ya319ICAgIGV4cGVjdChkaS5oYXM8TmV0d29ya0NsaWVudD4oKSwgaXNUcnVlKTsKe3svbmV0d29ya319CiAgICBleHBlY3QoZGkuaGFzPEdvUm91dGVyPigpLCBpc1RydWUpOwp7eyNkYXNoYm9hcmR9fSAgICBleHBlY3QoZmluZC50ZXh0KCdFeHBsb3JlJyksIGZpbmRzV2lkZ2V0cyk7Cnt7L2Rhc2hib2FyZH19CiAgICBmaW5hbCByb3V0ZXIgPSBkaS5nZXQ8R29Sb3V0ZXI+KCk7CiAgICByb3V0ZXIuZ28oJy91bmtub3duJyk7CiAgICBhd2FpdCB0ZXN0ZXIucHVtcEFuZFNldHRsZSgpOwogICAgZXhwZWN0KGZpbmQuYnlUeXBlKE91dGxpbmVkQnV0dG9uKSwgZmluZHNPbmVXaWRnZXQpOwogICAgYXdhaXQgdGVzdGVyLnRhcChmaW5kLmJ5VHlwZShPdXRsaW5lZEJ1dHRvbikpOwogICAgYXdhaXQgdGVzdGVyLnB1bXBBbmRTZXR0bGUoKTsKICAgIHJvdXRlci5nbygnL2Vycm9yP3RpdGxlPVRlc3QmbWVzc2FnZT1UcnklMjBsYXRlciZlcnJvcj1EZXRhaWxzJyk7CiAgICBhd2FpdCB0ZXN0ZXIucHVtcEFuZFNldHRsZSgpOwogICAgZXhwZWN0KGZpbmQudGV4dCgnVHJ5IGxhdGVyJyksIGZpbmRzT25lV2lkZ2V0KTsKICAgIGF3YWl0IHRlc3Rlci50YXAoZmluZC5ieVR5cGUoT3V0bGluZWRCdXR0b24pKTsKICAgIGF3YWl0IHRlc3Rlci5wdW1wQW5kU2V0dGxlKCk7CiAgICBleHBlY3QodGVzdGVyLnRha2VFeGNlcHRpb24oKSwgaXNOdWxsKTsKICAgIGF3YWl0IHRlc3Rlci5wdW1wV2lkZ2V0KGNvbnN0IFNpemVkQm94KCkpOwogIH0pOwp9Cg==", "type": "text" }, { "path": - "{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/test/{{smoke_test_file}}", + "{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/test/startup_test.dart", "data": - "aW1wb3J0ICdwYWNrYWdlOmZsdXR0ZXJfdGVzdC9mbHV0dGVyX3Rlc3QuZGFydCc7CmltcG9ydCAncGFja2FnZTp7e25hbWUuc25ha2VDYXNlKCl9fS9hcHAuZGFydCc7CmltcG9ydCAncGFja2FnZTp7e25hbWUuc25ha2VDYXNlKCl9fS9ib290c3RyYXAuZGFydCcgYXMgYm9vdHN0cmFwOwoKdm9pZCBtYWluKCkgewogIHRlc3RXaWRnZXRzKCd0aGUgYXBwIGJvb3RzIGFuZCByZWFjaGVzIGl0cyBmaXJzdCBzY3JlZW4nLCAodGVzdGVyKSBhc3luYyB7CiAgICAvLyBFeGVyY2lzZXMgdGhlIHdob2xlIGdyYXBoOiBtb2R1bGUgaW5pdCBvcmRlciwgREkgcmVnaXN0cmF0aW9uIGFuZCB0aGUKICAgIC8vIHNwbGFzaCByZWRpcmVjdC4gSWYgYSBtb2R1bGUgZm9yZ2V0cyB0byByZWdpc3RlciBzb21ldGhpbmcsIHRoaXMgZmFpbHMKICAgIC8vIGhlcmUgcmF0aGVyIHRoYW4gb24gYSBkZXZpY2UuCiAgICBhd2FpdCBib290c3RyYXAuaW5pdCgpOwogICAgYXdhaXQgdGVzdGVyLnB1bXBXaWRnZXQoY29uc3QgQXBwKCkpOwogICAgYXdhaXQgdGVzdGVyLnB1bXBBbmRTZXR0bGUoKTsKCiAgICBleHBlY3QodGVzdGVyLnRha2VFeGNlcHRpb24oKSwgaXNOdWxsKTsKe3sjZGFzaGJvYXJkfX0gICAgZXhwZWN0KGZpbmQudGV4dCgnRXhwbG9yZScpLCBmaW5kc1dpZGdldHMpOwp7ey9kYXNoYm9hcmR9fSAgfSk7Cn0K", + "aW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Y29yZS9jb3JlLmRhcnQnIGFzIGNvcmU7CmltcG9ydCAncGFja2FnZTpmbHV0dGVyL21hdGVyaWFsLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlcl90ZXN0L2ZsdXR0ZXJfdGVzdC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOnt7bmFtZS5zbmFrZUNhc2UoKX19L21haW4uZGFydCcgYXMgZW50cnlwb2ludDsKCnZvaWQgbWFpbigpIHsKICB0ZWFyRG93bihkaS5yZXNldCk7CiAgdGVzdFdpZGdldHMoCiAgICAnY29sZC1zdGFydCBub3RpZmljYXRpb24gcm91dGVzIHdhaXQgZm9yIHRoZSByb3V0ZXI7IGxhdGVyIHJvdXRlcyBuYXZpZ2F0ZSBkaXJlY3RseScsCiAgICAodGVzdGVyKSBhc3luYyB7CiAgICAgIGxhdGUgdm9pZCBGdW5jdGlvbihTdHJpbmcpIG9wZW5Sb3V0ZTsKICAgICAgbGF0ZSBXaWRnZXQgYXBwOwogICAgICBhd2FpdCBlbnRyeXBvaW50LnN0YXJ0QXBwKAogICAgICAgIGluaXRpYWxpemU6IChjYWxsYmFjaykgYXN5bmMgewogICAgICAgICAgYXdhaXQgY29yZS5pbml0KCk7CiAgICAgICAgICBvcGVuUm91dGUgPSBjYWxsYmFjazsKICAgICAgICAgIGNhbGxiYWNrKCcvZXJyb3I/dGl0bGU9RnJvbSUyMG5vdGlmaWNhdGlvbicpOwogICAgICAgIH0sCiAgICAgICAgbW91bnQ6ICh3aWRnZXQpID0+IGFwcCA9IHdpZGdldCwKICAgICAgKTsKICAgICAgYXdhaXQgdGVzdGVyLnB1bXBXaWRnZXQoYXBwKTsKICAgICAgYXdhaXQgdGVzdGVyLnB1bXBBbmRTZXR0bGUoKTsKICAgICAgZXhwZWN0KGZpbmQudGV4dCgnRnJvbSBub3RpZmljYXRpb24nKSwgZmluZHNPbmVXaWRnZXQpOwogICAgICBvcGVuUm91dGUoJy9ob21lJyk7CiAgICAgIGF3YWl0IHRlc3Rlci5wdW1wQW5kU2V0dGxlKCk7Cnt7I2Rhc2hib2FyZH19ICAgICAgZXhwZWN0KGZpbmQudGV4dCgnRXhwbG9yZScpLCBmaW5kc1dpZGdldHMpOwp7ey9kYXNoYm9hcmR9fQogICAgICBhd2FpdCB0ZXN0ZXIucHVtcFdpZGdldChjb25zdCBTaXplZEJveCgpKTsKICAgIH0sCiAgKTsKfQo=", + "type": "text" + }, + { + "path": + "{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/test/{{firebase_bootstrap_test_file}}", + "data": + "Ly8gUHJvdGVjdGVkIGRlbGVnYXRlIG1ldGhvZHMgYXJlIHRoZSBGbHV0dGVyRmlyZSBwbGF0Zm9ybSBtb2NraW5nIHNlYW0uCi8vIGlnbm9yZV9mb3JfZmlsZTogaW52YWxpZF91c2Vfb2ZfcHJvdGVjdGVkX21lbWJlcgp7eyNhbmFseXRpY3N9fWltcG9ydCAncGFja2FnZTphbmFseXRpY3MvYW5hbHl0aWNzLmRhcnQnOwp7ey9hbmFseXRpY3N9fQp7eyNhdXRofX1pbXBvcnQgJ3BhY2thZ2U6YXV0aC9hdXRoLmRhcnQnIGFzIGF1dGg7Cnt7L2F1dGh9fQp7eyNhdXRofX1pbXBvcnQgJ3BhY2thZ2U6Y29yZS9kZXZlbG9wZXIvZW11bGF0b3JzLmRhcnQnIGFzIGVtdWxhdG9yczsKe3svYXV0aH19Cnt7I2NyYXNobHl0aWNzfX1pbXBvcnQgJ3BhY2thZ2U6Y3Jhc2hseXRpY3MvY3Jhc2hseXRpY3MuZGFydCc7Cnt7L2NyYXNobHl0aWNzfX0KaW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwp7eyNmZWF0dXJlX2ZsYWdzfX1pbXBvcnQgJ3BhY2thZ2U6ZmVhdHVyZV9mbGFncy9mZWF0dXJlX2ZsYWdzLmRhcnQnOwp7ey9mZWF0dXJlX2ZsYWdzfX0KaW1wb3J0ICdwYWNrYWdlOmZpcmViYXNlX2NvcmUvZmlyZWJhc2VfY29yZS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZpcmViYXNlX2NvcmVfcGxhdGZvcm1faW50ZXJmYWNlL3Rlc3QuZGFydCc7Cnt7I2F1dGh9fWltcG9ydCAncGFja2FnZTpmaXJlYmFzZV9hdXRoX3BsYXRmb3JtX2ludGVyZmFjZS9maXJlYmFzZV9hdXRoX3BsYXRmb3JtX2ludGVyZmFjZS5kYXJ0JzsKe3svYXV0aH19Cnt7I2FuYWx5dGljc319aW1wb3J0ICdwYWNrYWdlOmZpcmViYXNlX2FuYWx5dGljc19wbGF0Zm9ybV9pbnRlcmZhY2UvZmlyZWJhc2VfYW5hbHl0aWNzX3BsYXRmb3JtX2ludGVyZmFjZS5kYXJ0JzsKe3svYW5hbHl0aWNzfX0Ke3sjY3Jhc2hseXRpY3N9fWltcG9ydCAncGFja2FnZTpmaXJlYmFzZV9jcmFzaGx5dGljc19wbGF0Zm9ybV9pbnRlcmZhY2UvZmlyZWJhc2VfY3Jhc2hseXRpY3NfcGxhdGZvcm1faW50ZXJmYWNlLmRhcnQnOwp7ey9jcmFzaGx5dGljc319Cnt7I2ZlYXR1cmVfZmxhZ3N9fWltcG9ydCAncGFja2FnZTpmaXJlYmFzZV9yZW1vdGVfY29uZmlnX3BsYXRmb3JtX2ludGVyZmFjZS9maXJlYmFzZV9yZW1vdGVfY29uZmlnX3BsYXRmb3JtX2ludGVyZmFjZS5kYXJ0JzsKe3svZmVhdHVyZV9mbGFnc319Cnt7I25vdGlmaWNhdGlvbnN9fWltcG9ydCAncGFja2FnZTpmaXJlYmFzZV9tZXNzYWdpbmdfcGxhdGZvcm1faW50ZXJmYWNlL2ZpcmViYXNlX21lc3NhZ2luZ19wbGF0Zm9ybV9pbnRlcmZhY2UuZGFydCc7Cnt7L25vdGlmaWNhdGlvbnN9fQppbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlci9mb3VuZGF0aW9uLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlci9tYXRlcmlhbC5kYXJ0JzsKe3sjYXV0aH19aW1wb3J0ICdwYWNrYWdlOmdvX3JvdXRlci9nb19yb3V0ZXIuZGFydCc7Cnt7L2F1dGh9fQppbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlcl90ZXN0L2ZsdXR0ZXJfdGVzdC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOm1vY2t0YWlsL21vY2t0YWlsLmRhcnQnOwp7eyNub3RpZmljYXRpb25zfX1pbXBvcnQgJ3BhY2thZ2U6bm90aWZpY2F0aW9ucy9ub3RpZmljYXRpb25zLmRhcnQnOwp7ey9ub3RpZmljYXRpb25zfX0Ke3sjZmlyZWJhc2Vfc2RrX21vY2tzfX1pbXBvcnQgJ3BhY2thZ2U6cGx1Z2luX3BsYXRmb3JtX2ludGVyZmFjZS9wbHVnaW5fcGxhdGZvcm1faW50ZXJmYWNlLmRhcnQnOwp7ey9maXJlYmFzZV9zZGtfbW9ja3N9fQppbXBvcnQgJ3BhY2thZ2U6e3tuYW1lLnNuYWtlQ2FzZSgpfX0vYm9vdHN0cmFwLmRhcnQnIGFzIGJvb3RzdHJhcDsKaW1wb3J0ICdwYWNrYWdlOnt7bmFtZS5zbmFrZUNhc2UoKX19L21haW4uZGFydCcgYXMgZW50cnlwb2ludDsKaW1wb3J0ICdwYWNrYWdlOnt7bmFtZS5zbmFrZUNhc2UoKX19L2FwcC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOnt7bmFtZS5zbmFrZUNhc2UoKX19L3JvdXRlci9yb3V0ZXIuZGFydCc7CgpjbGFzcyBfQ29yZSBleHRlbmRzIE1vY2tGaXJlYmFzZUFwcCB7CiAgQG92ZXJyaWRlCiAgRnV0dXJlPExpc3Q8Q29yZUluaXRpYWxpemVSZXNwb25zZT4+IGluaXRpYWxpemVDb3JlKCkgYXN5bmMgewogICAgZmluYWwgYXBwcyA9IGF3YWl0IHN1cGVyLmluaXRpYWxpemVDb3JlKCk7Cnt7I2NyYXNobHl0aWNzfX0gICAgYXBwcy5maXJzdC5wbHVnaW5Db25zdGFudHNbJ3BsdWdpbnMuZmx1dHRlci5pby9maXJlYmFzZV9jcmFzaGx5dGljcyddID0gewogICAgICAnaXNDcmFzaGx5dGljc0NvbGxlY3Rpb25FbmFibGVkJzogZmFsc2UsCiAgICB9Owp7ey9jcmFzaGx5dGljc319ICAgIHJldHVybiBhcHBzOwogIH0KfQoKe3sjYXV0aH19Y2xhc3MgX0F1dGggZXh0ZW5kcyBNb2NrCiAgICB3aXRoIE1vY2tQbGF0Zm9ybUludGVyZmFjZU1peGluCiAgICBpbXBsZW1lbnRzIEZpcmViYXNlQXV0aFBsYXRmb3JtIHt9Cnt7L2F1dGh9fQoKe3sjYW5hbHl0aWNzfX1jbGFzcyBfQW5hbHl0aWNzIGV4dGVuZHMgTW9jawogICAgd2l0aCBNb2NrUGxhdGZvcm1JbnRlcmZhY2VNaXhpbgogICAgaW1wbGVtZW50cyBGaXJlYmFzZUFuYWx5dGljc1BsYXRmb3JtIHt9Cnt7L2FuYWx5dGljc319Cgp7eyNjcmFzaGx5dGljc319Y2xhc3MgX0NyYXNoIGV4dGVuZHMgTW9jawogICAgd2l0aCBNb2NrUGxhdGZvcm1JbnRlcmZhY2VNaXhpbgogICAgaW1wbGVtZW50cyBGaXJlYmFzZUNyYXNobHl0aWNzUGxhdGZvcm0ge30Ke3svY3Jhc2hseXRpY3N9fQoKe3sjZmVhdHVyZV9mbGFnc319Y2xhc3MgX0ZsYWdzIGV4dGVuZHMgTW9jawogICAgd2l0aCBNb2NrUGxhdGZvcm1JbnRlcmZhY2VNaXhpbgogICAgaW1wbGVtZW50cyBGaXJlYmFzZVJlbW90ZUNvbmZpZ1BsYXRmb3JtIHt9Cnt7L2ZlYXR1cmVfZmxhZ3N9fQoKe3sjbm90aWZpY2F0aW9uc319Y2xhc3MgX01lc3NhZ2luZyBleHRlbmRzIE1vY2sKICAgIHdpdGggTW9ja1BsYXRmb3JtSW50ZXJmYWNlTWl4aW4KICAgIGltcGxlbWVudHMgRmlyZWJhc2VNZXNzYWdpbmdQbGF0Zm9ybSB7fQp7ey9ub3RpZmljYXRpb25zfX0KCnt7I2F1dGh9fWNsYXNzIF9Vc2VyIGV4dGVuZHMgTW9jawogICAgd2l0aCBNb2NrUGxhdGZvcm1JbnRlcmZhY2VNaXhpbgogICAgaW1wbGVtZW50cyBVc2VyUGxhdGZvcm0ge30Ke3svYXV0aH19Cgp2b2lkIG1haW4oKSB7CiAgVGVzdFdpZGdldHNGbHV0dGVyQmluZGluZy5lbnN1cmVJbml0aWFsaXplZCgpOwogIHRlc3RXaWRnZXRzKAogICAgJ2NvbmZpZ3VyZWQgYm9vdHN0cmFwIGNvbXBvc2VzIGFsbCBtb2R1bGVzIGFnYWluc3Qgb2ZmbGluZSBwbGF0Zm9ybSBkb3VibGVzJywKICAgICh0ZXN0ZXIpIGFzeW5jIHsKICAgICAgVGVzdEZpcmViYXNlQ29yZUhvc3RBcGkuc2V0VXAoX0NvcmUoKSk7CiAgICAgIGZpbmFsIGFwcCA9IGF3YWl0IEZpcmViYXNlLmluaXRpYWxpemVBcHAoKTsKICAgICAgcmVnaXN0ZXJGYWxsYmFja1ZhbHVlKGFwcCk7Cnt7I2ZlYXR1cmVfZmxhZ3N9fSAgICAgIHJlZ2lzdGVyRmFsbGJhY2tWYWx1ZSgKICAgICAgICBSZW1vdGVDb25maWdTZXR0aW5ncygKICAgICAgICAgIGZldGNoVGltZW91dDogY29uc3QgRHVyYXRpb24oc2Vjb25kczogMSksCiAgICAgICAgICBtaW5pbXVtRmV0Y2hJbnRlcnZhbDogRHVyYXRpb24uemVybywKICAgICAgICApLAogICAgICApOwp7ey9mZWF0dXJlX2ZsYWdzfX17eyNhdXRofX0gICAgICBmaW5hbCBpZGVudGl0eSA9IF9BdXRoKCk7Cnt7L2F1dGh9fQp7eyNhbmFseXRpY3N9fSAgICAgIGZpbmFsIGFuYWx5dGljcyA9IF9BbmFseXRpY3MoKTsKe3svYW5hbHl0aWNzfX0Ke3sjY3Jhc2hseXRpY3N9fSAgICAgIGZpbmFsIGNyYXNoID0gX0NyYXNoKCk7Cnt7L2NyYXNobHl0aWNzfX0Ke3sjZmVhdHVyZV9mbGFnc319ICAgICAgZmluYWwgZmxhZ3MgPSBfRmxhZ3MoKTsKe3svZmVhdHVyZV9mbGFnc319Cnt7I25vdGlmaWNhdGlvbnN9fSAgICAgIGZpbmFsIG1lc3NhZ2luZyA9IF9NZXNzYWdpbmcoKTsKe3svbm90aWZpY2F0aW9uc319Cnt7I2F1dGh9fSAgICAgIEZpcmViYXNlQXV0aFBsYXRmb3JtLmluc3RhbmNlID0gaWRlbnRpdHk7Cnt7L2F1dGh9fQp7eyNhbmFseXRpY3N9fSAgICAgIEZpcmViYXNlQW5hbHl0aWNzUGxhdGZvcm0uaW5zdGFuY2UgPSBhbmFseXRpY3M7Cnt7L2FuYWx5dGljc319Cnt7I2NyYXNobHl0aWNzfX0gICAgICBGaXJlYmFzZUNyYXNobHl0aWNzUGxhdGZvcm0uaW5zdGFuY2UgPSBjcmFzaDsKe3svY3Jhc2hseXRpY3N9fQp7eyNmZWF0dXJlX2ZsYWdzfX0gICAgICBGaXJlYmFzZVJlbW90ZUNvbmZpZ1BsYXRmb3JtLmluc3RhbmNlID0gZmxhZ3M7Cnt7L2ZlYXR1cmVfZmxhZ3N9fQp7eyNub3RpZmljYXRpb25zfX0gICAgICBGaXJlYmFzZU1lc3NhZ2luZ1BsYXRmb3JtLmluc3RhbmNlID0gbWVzc2FnaW5nOwp7ey9ub3RpZmljYXRpb25zfX0Ke3sjYXV0aH19ICAgICAgd2hlbigKICAgICAgICAoKSA9PiBpZGVudGl0eS5kZWxlZ2F0ZUZvcihhcHA6IGFueShuYW1lZDogJ2FwcCcpKSwKICAgICAgKS50aGVuUmV0dXJuKGlkZW50aXR5KTsKICAgICAgd2hlbigKICAgICAgICAoKSA9PiBpZGVudGl0eS5zZXRJbml0aWFsVmFsdWVzKAogICAgICAgICAgY3VycmVudFVzZXI6IGFueShuYW1lZDogJ2N1cnJlbnRVc2VyJyksCiAgICAgICAgICBsYW5ndWFnZUNvZGU6IGFueShuYW1lZDogJ2xhbmd1YWdlQ29kZScpLAogICAgICAgICksCiAgICAgICkudGhlblJldHVybihpZGVudGl0eSk7CiAgICAgIHdoZW4oCiAgICAgICAgaWRlbnRpdHkuaWRUb2tlbkNoYW5nZXMsCiAgICAgICkudGhlbkFuc3dlcigoXykgPT4gY29uc3QgU3RyZWFtPFVzZXJQbGF0Zm9ybT8+LmVtcHR5KCkpOwogICAgICB3aGVuKAogICAgICAgIGlkZW50aXR5LmF1dGhTdGF0ZUNoYW5nZXMsCiAgICAgICkudGhlbkFuc3dlcigoXykgPT4gY29uc3QgU3RyZWFtPFVzZXJQbGF0Zm9ybT8+LmVtcHR5KCkpOwogICAgICB3aGVuKAogICAgICAgIGlkZW50aXR5LnVzZXJDaGFuZ2VzLAogICAgICApLnRoZW5BbnN3ZXIoKF8pID0+IGNvbnN0IFN0cmVhbTxVc2VyUGxhdGZvcm0/Pi5lbXB0eSgpKTsKICAgICAgd2hlbigKICAgICAgICAoKSA9PiBpZGVudGl0eS51c2VBdXRoRW11bGF0b3IoYW55KCksIGFueSgpKSwKICAgICAgKS50aGVuQW5zd2VyKChfKSBhc3luYyB7fSk7Cnt7L2F1dGh9fXt7I2FuYWx5dGljc319ICAgICAgd2hlbigKICAgICAgICAoKSA9PiBhbmFseXRpY3MuZGVsZWdhdGVGb3IoCiAgICAgICAgICBhcHA6IGFueShuYW1lZDogJ2FwcCcpLAogICAgICAgICAgd2ViT3B0aW9uczogYW55KG5hbWVkOiAnd2ViT3B0aW9ucycpLAogICAgICAgICksCiAgICAgICkudGhlblJldHVybihhbmFseXRpY3MpOwogICAgICB3aGVuKAogICAgICAgICgpID0+IGFuYWx5dGljcy5zZXRBbmFseXRpY3NDb2xsZWN0aW9uRW5hYmxlZChhbnkoKSksCiAgICAgICkudGhlbkFuc3dlcigoXykgYXN5bmMge30pOwogICAgICB3aGVuKAogICAgICAgICgpID0+IGFuYWx5dGljcy5sb2dFdmVudCgKICAgICAgICAgIG5hbWU6IGFueShuYW1lZDogJ25hbWUnKSwKICAgICAgICAgIHBhcmFtZXRlcnM6IGFueShuYW1lZDogJ3BhcmFtZXRlcnMnKSwKICAgICAgICApLAogICAgICApLnRoZW5BbnN3ZXIoKF8pIGFzeW5jIHt9KTsKe3svYW5hbHl0aWNzfX17eyNjcmFzaGx5dGljc319ICAgICAgd2hlbigKICAgICAgICAoKSA9PiBjcmFzaC5zZXRJbml0aWFsVmFsdWVzKAogICAgICAgICAgaXNDcmFzaGx5dGljc0NvbGxlY3Rpb25FbmFibGVkOiBhbnkoCiAgICAgICAgICAgIG5hbWVkOiAnaXNDcmFzaGx5dGljc0NvbGxlY3Rpb25FbmFibGVkJywKICAgICAgICAgICksCiAgICAgICAgKSwKICAgICAgKS50aGVuUmV0dXJuKGNyYXNoKTsKICAgICAgd2hlbigKICAgICAgICAoKSA9PiBjcmFzaC5zZXRDcmFzaGx5dGljc0NvbGxlY3Rpb25FbmFibGVkKGFueSgpKSwKICAgICAgKS50aGVuQW5zd2VyKChfKSBhc3luYyB7fSk7CiAgICAgIHdoZW4oY3Jhc2guY2hlY2tGb3JVbnNlbnRSZXBvcnRzKS50aGVuQW5zd2VyKChfKSBhc3luYyA9PiBmYWxzZSk7Cnt7L2NyYXNobHl0aWNzfX17eyNmZWF0dXJlX2ZsYWdzfX0gICAgICB3aGVuKCgpID0+IGZsYWdzLmRlbGVnYXRlRm9yKGFwcDogYW55KG5hbWVkOiAnYXBwJykpKS50aGVuUmV0dXJuKGZsYWdzKTsKICAgICAgd2hlbigKICAgICAgICAoKSA9PiBmbGFncy5zZXRJbml0aWFsVmFsdWVzKAogICAgICAgICAgcmVtb3RlQ29uZmlnVmFsdWVzOiBhbnkobmFtZWQ6ICdyZW1vdGVDb25maWdWYWx1ZXMnKSwKICAgICAgICApLAogICAgICApLnRoZW5SZXR1cm4oZmxhZ3MpOwogICAgICB3aGVuKCgpID0+IGZsYWdzLnNldENvbmZpZ1NldHRpbmdzKGFueSgpKSkudGhlbkFuc3dlcigoXykgYXN5bmMge30pOwogICAgICB3aGVuKCgpID0+IGZsYWdzLnNldERlZmF1bHRzKGFueSgpKSkudGhlbkFuc3dlcigoXykgYXN5bmMge30pOwogICAgICB3aGVuKGZsYWdzLmZldGNoQW5kQWN0aXZhdGUpLnRoZW5BbnN3ZXIoKF8pIGFzeW5jID0+IGZhbHNlKTsKICAgICAgd2hlbigoKSA9PiBmbGFncy5sYXN0RmV0Y2hUaW1lKS50aGVuUmV0dXJuKERhdGVUaW1lKDIwMjYpKTsKICAgICAgd2hlbigKICAgICAgICAoKSA9PiBmbGFncy5sYXN0RmV0Y2hTdGF0dXMsCiAgICAgICkudGhlblJldHVybihSZW1vdGVDb25maWdGZXRjaFN0YXR1cy5zdWNjZXNzKTsKe3svZmVhdHVyZV9mbGFnc319e3sjbm90aWZpY2F0aW9uc319ICAgICAgd2hlbigKICAgICAgICAoKSA9PiBtZXNzYWdpbmcuZGVsZWdhdGVGb3IoYXBwOiBhbnkobmFtZWQ6ICdhcHAnKSksCiAgICAgICkudGhlblJldHVybihtZXNzYWdpbmcpOwogICAgICB3aGVuKAogICAgICAgICgpID0+IG1lc3NhZ2luZy5zZXRJbml0aWFsVmFsdWVzKAogICAgICAgICAgaXNBdXRvSW5pdEVuYWJsZWQ6IGFueShuYW1lZDogJ2lzQXV0b0luaXRFbmFibGVkJyksCiAgICAgICAgKSwKICAgICAgKS50aGVuUmV0dXJuKG1lc3NhZ2luZyk7Cnt7L25vdGlmaWNhdGlvbnN9fSAgICAgIGFkZFRlYXJEb3duKGRpLnJlc2V0KTsKICAgICAgZGVidWdEZWZhdWx0VGFyZ2V0UGxhdGZvcm1PdmVycmlkZSA9IFRhcmdldFBsYXRmb3JtLmlPUzsKICAgICAgYWRkVGVhckRvd24oKCkgPT4gZGVidWdEZWZhdWx0VGFyZ2V0UGxhdGZvcm1PdmVycmlkZSA9IG51bGwpOwogICAgICBhd2FpdCBib290c3RyYXAuaW5pdChmaXJlYmFzZU9wdGlvbnM6IGFwcC5vcHRpb25zLCB1c2VFbXVsYXRvcnM6IHRydWUpOwogICAgICBkZWJ1Z0RlZmF1bHRUYXJnZXRQbGF0Zm9ybU92ZXJyaWRlID0gbnVsbDsKe3sjYW5hbHl0aWNzfX0gICAgICBleHBlY3QoZGkuaGFzPEFuYWx5dGljc0NsaWVudD4oKSwgaXNUcnVlKTsKe3svYW5hbHl0aWNzfX0Ke3sjY3Jhc2hseXRpY3N9fSAgICAgIGV4cGVjdChkaS5oYXM8Q3Jhc2hseXRpY3NDbGllbnQ+KCksIGlzVHJ1ZSk7Cnt7L2NyYXNobHl0aWNzfX0Ke3sjZmVhdHVyZV9mbGFnc319ICAgICAgZXhwZWN0KGRpLmhhczxGZWF0dXJlRmxhZz4oKSwgaXNUcnVlKTsKe3svZmVhdHVyZV9mbGFnc319Cnt7I2F1dGh9fSAgICAgIGV4cGVjdChkaS5oYXM8YXV0aC5BdXRoU2VydmljZT4oKSwgaXNUcnVlKTsKe3svYXV0aH19Cnt7I25vdGlmaWNhdGlvbnN9fSAgICAgIGV4cGVjdChkaS5oYXM8Tm90aWZpY2F0aW9uQ2xpZW50PigpLCBpc1RydWUpOwp7ey9ub3RpZmljYXRpb25zfX0Ke3sjbm90aWZpY2F0aW9uc319ICAgICAgZXhwZWN0KEZpcmViYXNlVG9rZW5NYW5hZ2VyKCksIGlzQTxOb3RpZmljYXRpb25Ub2tlbk1hbmFnZXI+KCkpOwp7ey9ub3RpZmljYXRpb25zfX0Ke3sjbm90aWZpY2F0aW9uc319ICAgICAgZXhwZWN0KEZpcmViYXNlUGVybWlzc2lvbk1hbmFnZXIoKSwgaXNBPE5vdGlmaWNhdGlvblBlcm1pc3Npb25NYW5hZ2VyPigpKTsKe3svbm90aWZpY2F0aW9uc319Cnt7I2FuYWx5dGljc319ICAgICAgdmVyaWZ5KAogICAgICAgICgpID0+IGFuYWx5dGljcy5sb2dFdmVudCgKICAgICAgICAgIG5hbWU6ICdhcHBfb3BlbicsCiAgICAgICAgICBwYXJhbWV0ZXJzOiBhbnkobmFtZWQ6ICdwYXJhbWV0ZXJzJyksCiAgICAgICAgKSwKICAgICAgKS5jYWxsZWQoMSk7Cnt7L2FuYWx5dGljc319e3sjYXV0aH19ICAgICAgd2hlbigKICAgICAgICAoKSA9PiBpZGVudGl0eS51c2VBdXRoRW11bGF0b3IoYW55KCksIGFueSgpKSwKICAgICAgKS50aGVuVGhyb3coU3RhdGVFcnJvcignb2ZmbGluZScpKTsKICAgICAgYXdhaXQgZXhwZWN0TGF0ZXIoZW11bGF0b3JzLmluaXQoKSwgdGhyb3dzU3RhdGVFcnJvcik7Cnt7L2F1dGh9fSAgICAgIGxhdGUgV2lkZ2V0IGNvbXBvc2VkOwogICAgICBhd2FpdCBlbnRyeXBvaW50LnN0YXJ0QXBwKAogICAgICAgIGluaXRpYWxpemU6IChfKSBhc3luYyB7fSwKICAgICAgICBtb3VudDogKGFwcCkgPT4gY29tcG9zZWQgPSBhcHAsCiAgICAgICk7CiAgICAgIGV4cGVjdChjb21wb3NlZCwgaXNBPFdpZGdldD4oKSk7CiAgICAgIGZpbmFsIHJvdXRlciA9IEFwcFJvdXRlci5jcmVhdGVSb3V0ZXIoaW5pdGlhbExvY2F0aW9uOiAnL2Vycm9yJyk7CiAgICAgIGFkZFRlYXJEb3duKHJvdXRlci5kaXNwb3NlKTsKICAgICAgYXdhaXQgdGVzdGVyLnB1bXBXaWRnZXQoQXBwKHJvdXRlcjogcm91dGVyKSk7CiAgICAgIGF3YWl0IHRlc3Rlci5wdW1wQW5kU2V0dGxlKCk7Cnt7I2F1dGh9fSAgICAgIGZpbmFsIGNvbnRleHQgPSB0ZXN0ZXIuZWxlbWVudChmaW5kLmJ5VHlwZShPdXRsaW5lZEJ1dHRvbikpOwogICAgICBmaW5hbCByb3V0ZSA9IHJvdXRlci5jb25maWd1cmF0aW9uLnJvdXRlcy53aGVyZVR5cGU8R29Sb3V0ZT4oKS5maXJzdFdoZXJlKAogICAgICAgIChyKSA9PiByLnBhdGggPT0gYXV0aC5BdXRoUm91dGVzLnNpZ25JbiwKICAgICAgKTsKICAgICAgZmluYWwgc2NyZWVuID0KICAgICAgICAgIHJvdXRlLmJ1aWxkZXIhKGNvbnRleHQsIEdvUm91dGVyU3RhdGUub2YoY29udGV4dCkpCiAgICAgICAgICAgICAgYXMgYXV0aC5TaWduSW5TY3JlZW47CiAgICAgIHdoZW4oKCkgPT4gaWRlbnRpdHkuY3VycmVudFVzZXIpLnRoZW5SZXR1cm4oX1VzZXIoKSk7CiAgICAgIGF3YWl0IHNjcmVlbi5vblNpZ25lZEluKGNvbnRleHQpOwogICAgICBhd2FpdCB0ZXN0ZXIucHVtcEFuZFNldHRsZSgpOwp7eyNkYXNoYm9hcmR9fSAgICAgIGV4cGVjdChmaW5kLnRleHQoJ0V4cGxvcmUnKSwgZmluZHNXaWRnZXRzKTsKe3svZGFzaGJvYXJkfX0Ke3svYXV0aH19e3sjbm90aWZpY2F0aW9uc319ICAgICAgYXdhaXQgZGkuZ2V0PE5vdGlmaWNhdGlvbkNvbmZpZz4oKS5vbkZvcmVncm91bmQhKCdOb3RpY2UnLCAnRGV0YWlscycpOwogICAgICBhd2FpdCB0ZXN0ZXIucHVtcCgpOwogICAgICBhd2FpdCB0ZXN0ZXIucHVtcChjb25zdCBEdXJhdGlvbihtaWxsaXNlY29uZHM6IDUwMCkpOwogICAgICBhd2FpdCB0ZXN0ZXIucHVtcChjb25zdCBEdXJhdGlvbihtaWxsaXNlY29uZHM6IDUwMCkpOwogICAgICBleHBlY3QoZmluZC50ZXh0KCdOb3RpY2UnKSwgZmluZHNPbmVXaWRnZXQpOwogICAgICBhd2FpdCB0ZXN0ZXIucHVtcChjb25zdCBEdXJhdGlvbihzZWNvbmRzOiA0KSk7CiAgICAgIGF3YWl0IHRlc3Rlci5wdW1wQW5kU2V0dGxlKCk7Cnt7L25vdGlmaWNhdGlvbnN9fXt7I2F1dGh9fSAgICAgIHdoZW4oKCkgPT4gaWRlbnRpdHkuY3VycmVudFVzZXIpLnRoZW5SZXR1cm4obnVsbCk7CiAgICAgIHJvdXRlci5nbygnLycpOwogICAgICBhd2FpdCB0ZXN0ZXIucHVtcEFuZFNldHRsZSgpOwogICAgICBleHBlY3QoZmluZC5ieVR5cGUoYXV0aC5TaWduSW5TY3JlZW4pLCBmaW5kc09uZVdpZGdldCk7Cnt7L2F1dGh9fSAgICAgIGV4cGVjdCh0ZXN0ZXIudGFrZUV4Y2VwdGlvbigpLCBpc051bGwpOwogICAgICBhd2FpdCB0ZXN0ZXIucHVtcFdpZGdldChjb25zdCBTaXplZEJveCgpKTsKICAgIH0sCiAgKTsKfQo=", + "type": "text" + }, + { + "path": + "{{ name.snakeCase() }}/apps/{{ name.snakeCase() }}/test/{{notification_lifecycle_test_file}}", + "data": + "aW1wb3J0ICdwYWNrYWdlOmNvcmUvY29yZS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZsdXR0ZXIvd2lkZ2V0cy5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZsdXR0ZXJfdGVzdC9mbHV0dGVyX3Rlc3QuZGFydCc7CmltcG9ydCAncGFja2FnZTpub3RpZmljYXRpb25zL25vdGlmaWNhdGlvbnMuZGFydCc7CmltcG9ydCAncGFja2FnZTp7e25hbWUuc25ha2VDYXNlKCl9fS9ub3RpZmljYXRpb25fbGlmZWN5Y2xlLmRhcnQnOwoKY2xhc3MgX0xvZ2dlciBpbXBsZW1lbnRzIExvZ2dlciB7CiAgZmluYWwgZXJyb3JzID0gPE9iamVjdD8+W107CiAgQG92ZXJyaWRlCiAgT2JqZWN0IGdldCBsb2dnZXIgPT4gdGhpczsKICBAb3ZlcnJpZGUKICB2b2lkIGQoU3RyaW5nIG1lc3NhZ2UpIHt9CiAgQG92ZXJyaWRlCiAgdm9pZCBpKFN0cmluZyBtZXNzYWdlKSB7fQogIEBvdmVycmlkZQogIHZvaWQgdyhTdHJpbmcgbWVzc2FnZSkge30KICBAb3ZlcnJpZGUKICB2b2lkIGUoU3RyaW5nIG1lc3NhZ2UsIFtPYmplY3Q/IGVycm9yLCBTdGFja1RyYWNlPyBzdGFja1RyYWNlXSkgPT4KICAgICAgZXJyb3JzLmFkZChlcnJvcik7Cn0KCmNsYXNzIF9DbGllbnQgaW1wbGVtZW50cyBOb3RpZmljYXRpb25DbGllbnQgewogIGludCBzdGFydHMgPSAwOwogIGludCBjbGVhcnMgPSAwOwogIGJvb2wgZmFpbCA9IGZhbHNlOwogIEBvdmVycmlkZQogIEZ1dHVyZTx2b2lkPiBpbml0KCkgYXN5bmMgewogICAgc3RhcnRzKys7CiAgICBpZiAoZmFpbCkgdGhyb3cgU3RhdGVFcnJvcignaW5pdCBmYWlsZWQnKTsKICB9CgogIEBvdmVycmlkZQogIEZ1dHVyZTx2b2lkPiBjbGVhckJhZGdlKCkgYXN5bmMgewogICAgY2xlYXJzKys7CiAgICBpZiAoZmFpbCkgdGhyb3cgU3RhdGVFcnJvcignYmFkZ2UgZmFpbGVkJyk7CiAgfQoKICBAb3ZlcnJpZGUKICBkeW5hbWljIG5vU3VjaE1ldGhvZChJbnZvY2F0aW9uIGludm9jYXRpb24pID0+IHN1cGVyLm5vU3VjaE1ldGhvZChpbnZvY2F0aW9uKTsKfQoKdm9pZCBtYWluKCkgewogIHRlc3RXaWRnZXRzKCdpbml0aWFsaXplcyBhZnRlciB0aGUgZmlyc3QgZnJhbWUgYW5kIGNsZWFycyBiYWRnZSBvbiByZXN1bWUnLCAoCiAgICB0ZXN0ZXIsCiAgKSBhc3luYyB7CiAgICBmaW5hbCBjbGllbnQgPSBfQ2xpZW50KCk7CiAgICBmaW5hbCBsb2dnZXIgPSBfTG9nZ2VyKCk7CiAgICBhd2FpdCB0ZXN0ZXIucHVtcFdpZGdldCgKICAgICAgTm90aWZpY2F0aW9uTGlmZWN5Y2xlKAogICAgICAgIGxvZ2dlcjogbG9nZ2VyLAogICAgICAgIGNsaWVudDogY2xpZW50LAogICAgICAgIGNoaWxkOiBjb25zdCBTaXplZEJveCgpLAogICAgICApLAogICAgKTsKICAgIGV4cGVjdChjbGllbnQuc3RhcnRzLCAxKTsKICAgIHRlc3Rlci5iaW5kaW5nLmhhbmRsZUFwcExpZmVjeWNsZVN0YXRlQ2hhbmdlZChBcHBMaWZlY3ljbGVTdGF0ZS5pbmFjdGl2ZSk7CiAgICB0ZXN0ZXIuYmluZGluZy5oYW5kbGVBcHBMaWZlY3ljbGVTdGF0ZUNoYW5nZWQoQXBwTGlmZWN5Y2xlU3RhdGUucmVzdW1lZCk7CiAgICBhd2FpdCB0ZXN0ZXIucHVtcCgpOwogICAgZXhwZWN0KGNsaWVudC5jbGVhcnMsIDEpOwogICAgZXhwZWN0KGxvZ2dlci5lcnJvcnMsIGlzRW1wdHkpOwogICAgYXdhaXQgdGVzdGVyLnB1bXBXaWRnZXQoY29uc3QgU2l6ZWRCb3goKSk7CiAgICB0ZXN0ZXIuYmluZGluZy5oYW5kbGVBcHBMaWZlY3ljbGVTdGF0ZUNoYW5nZWQoQXBwTGlmZWN5Y2xlU3RhdGUuaW5hY3RpdmUpOwogICAgdGVzdGVyLmJpbmRpbmcuaGFuZGxlQXBwTGlmZWN5Y2xlU3RhdGVDaGFuZ2VkKEFwcExpZmVjeWNsZVN0YXRlLnJlc3VtZWQpOwogICAgYXdhaXQgdGVzdGVyLnB1bXAoKTsKICAgIGV4cGVjdChjbGllbnQuY2xlYXJzLCAxKTsKICB9KTsKCiAgdGVzdFdpZGdldHMoJ2NhdGNoZXMgYXN5bmNocm9ub3VzIGluaXRpYWxpemF0aW9uIGFuZCBiYWRnZSBmYWlsdXJlcycsICgKICAgIHRlc3RlciwKICApIGFzeW5jIHsKICAgIGZpbmFsIGNsaWVudCA9IF9DbGllbnQoKS4uZmFpbCA9IHRydWU7CiAgICBmaW5hbCBsb2dnZXIgPSBfTG9nZ2VyKCk7CiAgICBhd2FpdCB0ZXN0ZXIucHVtcFdpZGdldCgKICAgICAgTm90aWZpY2F0aW9uTGlmZWN5Y2xlKAogICAgICAgIGxvZ2dlcjogbG9nZ2VyLAogICAgICAgIGNsaWVudDogY2xpZW50LAogICAgICAgIGNoaWxkOiBjb25zdCBTaXplZEJveCgpLAogICAgICApLAogICAgKTsKICAgIGF3YWl0IHRlc3Rlci5wdW1wKCk7CiAgICB0ZXN0ZXIuYmluZGluZy5oYW5kbGVBcHBMaWZlY3ljbGVTdGF0ZUNoYW5nZWQoQXBwTGlmZWN5Y2xlU3RhdGUuaW5hY3RpdmUpOwogICAgdGVzdGVyLmJpbmRpbmcuaGFuZGxlQXBwTGlmZWN5Y2xlU3RhdGVDaGFuZ2VkKEFwcExpZmVjeWNsZVN0YXRlLnJlc3VtZWQpOwogICAgYXdhaXQgdGVzdGVyLnB1bXAoKTsKICAgIGV4cGVjdChsb2dnZXIuZXJyb3JzLCBoYXNMZW5ndGgoMikpOwogICAgZXhwZWN0KHRlc3Rlci50YWtlRXhjZXB0aW9uKCksIGlzTnVsbCk7CiAgfSk7CgogIHRlc3RXaWRnZXRzKCd3b3JrcyB3aGVuIG5vdGlmaWNhdGlvbnMgYXJlIG5vdCBjb25maWd1cmVkJywgKHRlc3RlcikgYXN5bmMgewogICAgZmluYWwgbG9nZ2VyID0gX0xvZ2dlcigpOwogICAgYXdhaXQgdGVzdGVyLnB1bXBXaWRnZXQoCiAgICAgIE5vdGlmaWNhdGlvbkxpZmVjeWNsZShsb2dnZXI6IGxvZ2dlciwgY2hpbGQ6IGNvbnN0IFNpemVkQm94KCkpLAogICAgKTsKICAgIHRlc3Rlci5iaW5kaW5nLmhhbmRsZUFwcExpZmVjeWNsZVN0YXRlQ2hhbmdlZChBcHBMaWZlY3ljbGVTdGF0ZS5pbmFjdGl2ZSk7CiAgICB0ZXN0ZXIuYmluZGluZy5oYW5kbGVBcHBMaWZlY3ljbGVTdGF0ZUNoYW5nZWQoQXBwTGlmZWN5Y2xlU3RhdGUucmVzdW1lZCk7CiAgICBhd2FpdCB0ZXN0ZXIucHVtcCgpOwogICAgZXhwZWN0KGxvZ2dlci5lcnJvcnMsIGlzRW1wdHkpOwogIH0pOwp9Cg==", + "type": "text" + }, + { + "path": "{{ name.snakeCase() }}/docs/architecture.md", + "data": + "IyBBcmNoaXRlY3R1cmUgZGVjaXNpb25zCgpUaGUgYXBwIGlzIHRoZSBjb21wb3NpdGlvbiByb290LiBGZWF0dXJlcyBvd24gc2NyZWVucyBhbmQgZmVhdHVyZSBiZWhhdmlvcjsKc2hhcmVkIHBhY2thZ2VzIGV4cG9zZSBjb2hlc2l2ZSBjb250cmFjdHMgYW5kIGltcGxlbWVudGF0aW9ucy4gS2VlcCBkZXBlbmRlbmNpZXMKcG9pbnRpbmcgZnJvbSBhcHBzIHRvIGZlYXR1cmVzIHRvIHBhY2thZ2VzLCBuZXZlciBiYWNrIHRvd2FyZCB0aGUgYXBwLgoKIyMgU09MSUQgYm91bmRhcmllcwoKfCBQcmluY2lwbGUgfCBTdGFydGVyIGJvdW5kYXJ5IHwKfCAtLS0gfCAtLS0gfAp8IFNpbmdsZSByZXNwb25zaWJpbGl0eSB8IGBBcHBgIHJlbmRlcnMgYW4gaW5qZWN0ZWQgcm91dGVyOyBib290c3RyYXAgY29tcG9zZXMgc2VydmljZXM7IGxpZmVjeWNsZSBoYW5kbGluZyBvd25zIGZvcmVncm91bmQgd29yay4gfAp8IE9wZW4vY2xvc2VkIHwgSW1wbGVtZW50IHRoZSBjbGllbnQvcHJvdmlkZXIgY29udHJhY3RzIHRvIHN3YXAgYSBiYWNrZW5kIG9yIGFkZCBhIGZlYXR1cmUgd2l0aG91dCBlZGl0aW5nIGV4aXN0aW5nIGNvbnN1bWVycy4gfAp8IExpc2tvdiBzdWJzdGl0dXRpb24gfCBUZXN0cyBleGVyY2lzZSBmYWtlcyBhZ2FpbnN0IHRoZSBzYW1lIGNvbnRyYWN0czsgY29yZSBvYnNlcnZlcnMgYWNjZXB0IGFueSBgTG9nZ2VyYCwgbm90IG9ubHkgVGFsa2VyLiB8CnwgSW50ZXJmYWNlIHNlZ3JlZ2F0aW9uIHwgQXV0aCB0b2tlbnMsIGRldmljZSBpZGVudGl0eSwgbm90aWZpY2F0aW9uIHBlcm1pc3Npb24gYW5kIG5vdGlmaWNhdGlvbiBkZWxpdmVyeSBoYXZlIHNlcGFyYXRlIGNvbnRyYWN0cy4gfAp8IERlcGVuZGVuY3kgaW52ZXJzaW9uIHwgQ2xpZW50cyBhY2NlcHQgdGhlaXIgdHJhbnNwb3J0LCBTREssIGxvZ2dlciBhbmQgY2xvY2sgZGVwZW5kZW5jaWVzLiBSZXNvbHZlIHRoZSBsb2NhdG9yIGF0IGNvbXBvc2l0aW9uIGJvdW5kYXJpZXMuIHwKClRoZSBsb2NhdG9yIGlzIGEgY29udmVuaWVuY2UgYXQgRmx1dHRlciBjb21wb3NpdGlvbiBlZGdlcywgbm90IGEgcmVxdWlyZW1lbnQgZm9yCmJ1c2luZXNzIGxvZ2ljLiBQcmVmZXIgY29uc3RydWN0b3IgaW5qZWN0aW9uIGluIG5ldyBzZXJ2aWNlcyBhbmQgcmVwb3NpdG9yaWVzLgpUaGUgY29udGFpbmVyIGRpc3Bvc2VzIGRlcGVuZGVudHMgYmVmb3JlIGRlcGVuZGVuY2llcyBhbmQgYXdhaXRzIGFzeW5jIGNsZWFudXAuCk9ubHkgb25lIGNvbXBvbmVudCBzaG91bGQgb3duIGVhY2ggc3Vic2NyaXB0aW9uIG9yIGRpc3Bvc2FibGUgc2VydmljZS4KCiMjIEFkZGluZyBhIGZlYXR1cmUKCjEuIFB1dCBiZWhhdmlvciBiZWhpbmQgYSBzbWFsbCBjb250cmFjdCBpbiB0aGUgb3duaW5nIGZlYXR1cmUgb3Igc2hhcmVkIHBhY2thZ2UuCjIuIEluamVjdCBpdHMgZGVwZW5kZW5jaWVzLiBVc2UgYW4gb3B0aW9uYWwgY2xvY2sgY2FsbGJhY2sgZm9yIHRpbWUtc2Vuc2l0aXZlIGJlaGF2aW9yLgozLiBXcml0ZSB0ZXN0cyBmb3Igc3VjY2VzcywgaW52YWxpZCBpbnB1dCwgcGxhdGZvcm0gZmFpbHVyZSBhbmQgbGlmZWN5Y2xlIGNsZWFudXAuCjQuIEV4cG9zZSBmZWF0dXJlIHJvdXRlcyBhbmQgY29tcG9zZSB0aGVtIGluIHRoZSBhcHAgcm91dGVyLgo1LiBSZWdpc3RlciBpbXBsZW1lbnRhdGlvbnMgaW4gYm9vdHN0cmFwOyBrZWVwIHJlZ2lzdHJhdGlvbiBzZXBhcmF0ZSBmcm9tIHdpZGdldCByZW5kZXJpbmcuCjYuIFJ1biBgZGFydCBydW4gbWVsb3MgcnVuIGxpbnRgIGFuZCBgZGFydCBydW4gbWVsb3MgcnVuIGNvdmVyYWdlYCBiZWZvcmUgY29tbWl0dGluZy4KCmBgYGRhcnQKYWJzdHJhY3QgaW50ZXJmYWNlIGNsYXNzIEdyZWV0aW5nUmVwb3NpdG9yeSB7CiAgRnV0dXJlPFN0cmluZz4gbG9hZEdyZWV0aW5nKCk7Cn0KCmNsYXNzIExvYWRHcmVldGluZyB7CiAgY29uc3QgTG9hZEdyZWV0aW5nKHRoaXMucmVwb3NpdG9yeSk7CiAgZmluYWwgR3JlZXRpbmdSZXBvc2l0b3J5IHJlcG9zaXRvcnk7CgogIEZ1dHVyZTxTdHJpbmc+IGNhbGwoKSA9PiByZXBvc2l0b3J5LmxvYWRHcmVldGluZygpOwp9CmBgYAoKVGVzdCBgTG9hZEdyZWV0aW5nYCB1c2luZyBhIHNtYWxsIGZha2UgcmVwb3NpdG9yeS4gVGVzdCBhIHJlYWwgcmVwb3NpdG9yeSdzIGFkYXB0ZXIKd2l0aCBhbiBpbmplY3RlZCB0cmFuc3BvcnQgcmF0aGVyIHRoYW4gbWFraW5nIGxpdmUgcmVxdWVzdHMgaW4gdW5pdCB0ZXN0cy4KCiMjIEZhaWx1cmUgYW5kIHByaXZhY3kgcG9saWN5CgotIEhUVFAgZmFpbHVyZXMgc3RheSB0eXBlZDsgYXBwbGljYXRpb24tbGV2ZWwgZXJyb3IgZW52ZWxvcGVzIG5ldmVyIG1hc3F1ZXJhZGUgYXMgc3VjY2Vzcy4KLSBBdXRvbWF0aWMgYmVhcmVyIGhlYWRlcnMgc3RheSBvbiB0aGUgY29uZmlndXJlZCBBUEkgb3JpZ2luLiBPbmUgcmV0cnkgZm9sbG93cyBhIHNoYXJlZCB0b2tlbiByZWZyZXNoOyBjb25zdW1lZCBzdHJlYW1zIGFyZSBub3QgcmVwbGF5ZWQuCi0gU0RLIGluaXRpYWxpemF0aW9uIGlzIGF3YWl0ZWQuIEFuIHVuYXZhaWxhYmxlIG9wdGlvbmFsIEZpcmViYXNlIGNvbmZpZ3VyYXRpb24gcGVybWl0cyB0aGUgc3RhcnRlciBkZW1vIHRvIGJvb3Q7IGVtdWxhdG9yIHNldHVwIGZhaWx1cmVzIGFyZSBzdXJmYWNlZC4KLSBBbmFseXRpY3MgZmFpbHVyZXMgZG8gbm90IGludGVycnVwdCBVSSBiZWhhdmlvci4gU0RLIHN0YXRlIGlzIG5vdCBjYWNoZWQgYWNyb3NzIERJIHJlc2V0cy4KLSBOZXR3b3JrIGxvZ3Mgb21pdCBoZWFkZXJzLCBxdWVyeSB2YWx1ZXMgYW5kIGJvZGllcy4gQXV0aCBzdWNjZXNzIGxvZ3Mgb21pdCBlbWFpbCBhZGRyZXNzZXM7IGFkZCB5b3VyIG93biByZWRhY3Rpb24gcnVsZXMgZm9yIGRvbWFpbiBlcnJvcnMuCi0gUGxhdGZvcm0gY3Jhc2ggaGFuZGxlcnMgYXJlIHJlc3RvcmVkIHdoZW4gdGhlaXIgb3duaW5nIGNsaWVudCBpcyBkaXNwb3NlZC4KCiMjIFdoYXQgdGhlIHRlc3RzIGRvIG5vdCByZXBsYWNlCgoxMDAlIGxpbmUgY292ZXJhZ2UgbWVhc3VyZXMgZXhlY3V0aW9uLCBub3QgZXZlcnkgYnJhbmNoIG9yIHBvc3NpYmxlIGlucHV0LiBBZGQKc2VjdXJpdHkgcnVsZXMgdGVzdHMsIGRldmljZSB0ZXN0cywgYWNjZXNzaWJpbGl0eSBjaGVja3MgYW5kIGJhY2tlbmQgaW50ZWdyYXRpb24KdGVzdHMgZm9yIHlvdXIgcHJvZHVjdC4gQ29uZmlndXJlIHByb3ZpZGVyIGNyZWRlbnRpYWxzLCBwcml2YWN5IGNvbnNlbnQgYW5kIG5hdGl2ZQpwZXJtaXNzaW9ucyBkZWxpYmVyYXRlbHk7IGEgc3RhcnRlciBjYW5ub3QgY2hvb3NlIHRoZXNlIHByb2R1Y3QgcG9saWNpZXMgZm9yIHlvdS4K", "type": "text" }, { @@ -87,13 +134,13 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "path": "{{ name.snakeCase() }}/features/{{auth_dir}}/lib/analytics/analytics.dart", "data": - "e3sjYW5hbHl0aWNzfX1pbXBvcnQgJ3BhY2thZ2U6YW5hbHl0aWNzL2FuYWx5dGljcy5kYXJ0JzsKe3svYW5hbHl0aWNzfX1pbXBvcnQgJ3BhY2thZ2U6ZmlyZWJhc2VfYXV0aC9maXJlYmFzZV9hdXRoLmRhcnQnOwoKLy8vIEV2ZXJ5IGF1dGgtcmVsYXRlZCBhbmFseXRpY3MgZXZlbnQgaW4gb25lIHBsYWNlLgovLy8KLy8vIFNjcmVlbnMgY2FsbCB0aGVzZSBpbnN0ZWFkIG9mIGBBbmFseXRpY3NIZWxwZXJgIGRpcmVjdGx5IHNvIHRoZSBldmVudCBuYW1lcwovLy8gYW5kIHBhcmFtZXRlciBzaGFwZXMgc3RheSBjb25zaXN0ZW50IGFjcm9zcyBzaWduLWluLCBzaWduLXVwIGFuZCByZWNvdmVyeS4Ke3teYW5hbHl0aWNzfX0vLy8KLy8vIEFuYWx5dGljcyBpcyBub3QgZW5hYmxlZCBpbiB0aGlzIHByb2plY3QsIHNvIHRoZSBsb2cgbWV0aG9kcyBhcmUgbm8tb3BzLgovLy8gV2lyZSB0aGVtIHVwIGJ5IGFkZGluZyB0aGUgYGFuYWx5dGljc2AgcGFja2FnZSBiYWNrIHRvIGBwdWJzcGVjLnlhbWxgLgp7ey9hbmFseXRpY3N9fWNsYXNzIEF1dGhBbmFseXRpY3MgewogIGNvbnN0IEF1dGhBbmFseXRpY3MuXygpOwoKICAvLy8gJ2dvb2dsZScsICdhcHBsZScgb3IgJ2VtYWlsJywgZGVyaXZlZCBmcm9tIHRoZSBzaWduZWQtaW4gcHJvdmlkZXIuCiAgc3RhdGljIFN0cmluZyBnZXRBdXRoTWV0aG9kKExpc3Q8VXNlckluZm8+PyBwcm92aWRlckRhdGEpIHsKICAgIGlmIChwcm92aWRlckRhdGE/LmlzTm90RW1wdHkgPz8gZmFsc2UpIHsKICAgICAgZmluYWwgcHJvdmlkZXJJZCA9IHByb3ZpZGVyRGF0YSEuZmlyc3QucHJvdmlkZXJJZDsKICAgICAgaWYgKHByb3ZpZGVySWQuY29udGFpbnMoJ2dvb2dsZScpKSByZXR1cm4gJ2dvb2dsZSc7CiAgICAgIGlmIChwcm92aWRlcklkLmNvbnRhaW5zKCdhcHBsZScpKSByZXR1cm4gJ2FwcGxlJzsKICAgIH0KICAgIHJldHVybiAnZW1haWwnOwogIH0KCiAgc3RhdGljIEZ1dHVyZTx2b2lkPiBsb2dTaWduSW5TdWNjZXNzKHsKICAgIHJlcXVpcmVkIFN0cmluZyBtZXRob2QsCiAgICBTdHJpbmc/IHVzZXJFbWFpbCwKICB9KSBhc3luYyB7Cnt7I2FuYWx5dGljc319ICAgIGF3YWl0IEFuYWx5dGljc0hlbHBlci5sb2dTaWduSW4oCiAgICAgIG1ldGhvZDogbWV0aG9kLAogICAgICBwYXJhbWV0ZXJzOiBfc3VjY2Vzc1BhcmFtcyh1c2VyRW1haWwpLAogICAgKTsKe3svYW5hbHl0aWNzfX0gIH0KCiAgc3RhdGljIEZ1dHVyZTx2b2lkPiBsb2dTaWduVXBTdWNjZXNzKHsKICAgIHJlcXVpcmVkIFN0cmluZyBtZXRob2QsCiAgICBTdHJpbmc/IHVzZXJFbWFpbCwKICB9KSBhc3luYyB7Cnt7I2FuYWx5dGljc319ICAgIGF3YWl0IEFuYWx5dGljc0hlbHBlci5sb2dTaWduVXAoCiAgICAgIG1ldGhvZDogbWV0aG9kLAogICAgICBwYXJhbWV0ZXJzOiBfc3VjY2Vzc1BhcmFtcyh1c2VyRW1haWwpLAogICAgKTsKe3svYW5hbHl0aWNzfX0gIH0KCiAgc3RhdGljIEZ1dHVyZTx2b2lkPiBsb2dVc2VyQ3JlYXRpb25TdWNjZXNzKHsKICAgIHJlcXVpcmVkIFN0cmluZyBtZXRob2QsCiAgICBTdHJpbmc/IHVzZXJFbWFpbCwKICB9KSBhc3luYyB7Cnt7I2FuYWx5dGljc319ICAgIGF3YWl0IEFuYWx5dGljc0hlbHBlci5sb2dFdmVudCgKICAgICAgQW5hbHl0aWNzRXZlbnRzLnVzZXIuYXV0aGVudGljYXRlZFJlZGlyZWN0LAogICAgICBwYXJhbWV0ZXJzOiB7CiAgICAgICAgJ2F1dGhfbWV0aG9kJzogbWV0aG9kLAogICAgICAgICdmbG93X3R5cGUnOiAncmVnaXN0cmF0aW9uJywKICAgICAgICAuLi5fc3VjY2Vzc1BhcmFtcyh1c2VyRW1haWwpLAogICAgICB9LAogICAgKTsKe3svYW5hbHl0aWNzfX0gIH0KCiAgc3RhdGljIEZ1dHVyZTx2b2lkPiBsb2dTaWduT3V0U3VjY2VzcygpIGFzeW5jIHsKe3sjYW5hbHl0aWNzfX0gICAgYXdhaXQgQW5hbHl0aWNzSGVscGVyLmxvZ0V2ZW50KAogICAgICBBbmFseXRpY3NFdmVudHMuYXV0aC5zaWduT3V0LAogICAgICBwYXJhbWV0ZXJzOiBfc3VjY2Vzc1BhcmFtcyhudWxsKSwKICAgICk7Cnt7L2FuYWx5dGljc319ICB9CgogIC8vLyBbZmxvd1R5cGVdIGlzIG9uZSBvZiAnc2lnbl9pbicsICdzaWduX3VwJywgJ2ZvcmdvdF9wYXNzd29yZCcuCiAgc3RhdGljIEZ1dHVyZTx2b2lkPiBsb2dBdXRoRXJyb3IoewogICAgcmVxdWlyZWQgU3RyaW5nIGVycm9yVHlwZSwKICAgIHJlcXVpcmVkIFN0cmluZyBmbG93VHlwZSwKICAgIFN0cmluZz8gZXJyb3JNZXNzYWdlLAogICAgU3RyaW5nPyBtZXRob2QsCiAgfSkgYXN5bmMgewp7eyNhbmFseXRpY3N9fSAgICBhd2FpdCBBbmFseXRpY3NIZWxwZXIubG9nRXZlbnQoCiAgICAgIEFuYWx5dGljc0V2ZW50cy5hdXRoLmZhaWxlZCwKICAgICAgcGFyYW1ldGVyczogewogICAgICAgICdlcnJvcl90eXBlJzogZXJyb3JUeXBlLAogICAgICAgICdmbG93X3R5cGUnOiBmbG93VHlwZSwKICAgICAgICAnYXV0aF9tZXRob2QnOiBtZXRob2QsCiAgICAgICAgJ2Vycm9yX21lc3NhZ2UnOiBlcnJvck1lc3NhZ2UsCiAgICAgICAgJ3RpbWVzdGFtcCc6IERhdGVUaW1lLm5vdygpLnRvSXNvODYwMVN0cmluZygpLAogICAgICB9LAogICAgKTsKe3svYW5hbHl0aWNzfX0gIH0KCiAgc3RhdGljIEZ1dHVyZTx2b2lkPiBsb2dTaWduT3V0RXJyb3Ioe3JlcXVpcmVkIFN0cmluZyBlcnJvck1lc3NhZ2V9KSBhc3luYyB7Cnt7I2FuYWx5dGljc319ICAgIGF3YWl0IEFuYWx5dGljc0hlbHBlci5sb2dFdmVudCgKICAgICAgQW5hbHl0aWNzRXZlbnRzLmVycm9yLmFwcEVycm9yLAogICAgICBwYXJhbWV0ZXJzOiB7CiAgICAgICAgJ2Vycm9yX3R5cGUnOiAnc2lnbl9vdXRfZmFpbGVkJywKICAgICAgICAnZXJyb3JfbWVzc2FnZSc6IGVycm9yTWVzc2FnZSwKICAgICAgICAnZmVhdHVyZSc6ICdhdXRoJywKICAgICAgICAndGltZXN0YW1wJzogRGF0ZVRpbWUubm93KCkudG9Jc284NjAxU3RyaW5nKCksCiAgICAgIH0sCiAgICApOwp7ey9hbmFseXRpY3N9fSAgfQp7eyNhbmFseXRpY3N9fQogIHN0YXRpYyBNYXA8U3RyaW5nLCBPYmplY3Q/PiBfc3VjY2Vzc1BhcmFtcyhTdHJpbmc/IHVzZXJFbWFpbCkgPT4gewogICAgJ3N1Y2Nlc3MnOiAndHJ1ZScsCiAgICAndXNlcl9lbWFpbF9kb21haW4nOiB1c2VyRW1haWw/LnNwbGl0KCdAJykubGFzdCwKICAgICd0aW1lc3RhbXAnOiBEYXRlVGltZS5ub3coKS50b0lzbzg2MDFTdHJpbmcoKSwKICB9Owp7ey9hbmFseXRpY3N9fX0K", + "e3sjYW5hbHl0aWNzfX1pbXBvcnQgJ3BhY2thZ2U6YW5hbHl0aWNzL2FuYWx5dGljcy5kYXJ0JzsKe3svYW5hbHl0aWNzfX1pbXBvcnQgJ3BhY2thZ2U6ZmlyZWJhc2VfYXV0aC9maXJlYmFzZV9hdXRoLmRhcnQnOwoKLy8vIEV2ZXJ5IGF1dGgtcmVsYXRlZCBhbmFseXRpY3MgZXZlbnQgaW4gb25lIHBsYWNlLgovLy8KLy8vIFNjcmVlbnMgY2FsbCB0aGVzZSBpbnN0ZWFkIG9mIGBBbmFseXRpY3NIZWxwZXJgIGRpcmVjdGx5IHNvIHRoZSBldmVudCBuYW1lcwovLy8gYW5kIHBhcmFtZXRlciBzaGFwZXMgc3RheSBjb25zaXN0ZW50IGFjcm9zcyBzaWduLWluLCBzaWduLXVwIGFuZCByZWNvdmVyeS4Ke3teYW5hbHl0aWNzfX0vLy8KLy8vIEFuYWx5dGljcyBpcyBub3QgZW5hYmxlZCBpbiB0aGlzIHByb2plY3QsIHNvIHRoZSBsb2cgbWV0aG9kcyBhcmUgbm8tb3BzLgovLy8gV2lyZSB0aGVtIHVwIGJ5IGFkZGluZyB0aGUgYGFuYWx5dGljc2AgcGFja2FnZSBiYWNrIHRvIGBwdWJzcGVjLnlhbWxgLgp7ey9hbmFseXRpY3N9fWFic3RyYWN0IGZpbmFsIGNsYXNzIEF1dGhBbmFseXRpY3MgewoKICAvLy8gJ2dvb2dsZScsICdhcHBsZScgb3IgJ2VtYWlsJywgZGVyaXZlZCBmcm9tIHRoZSBzaWduZWQtaW4gcHJvdmlkZXIuCiAgc3RhdGljIFN0cmluZyBnZXRBdXRoTWV0aG9kKExpc3Q8VXNlckluZm8+PyBwcm92aWRlckRhdGEpIHsKICAgIGlmIChwcm92aWRlckRhdGE/LmlzTm90RW1wdHkgPz8gZmFsc2UpIHsKICAgICAgZmluYWwgcHJvdmlkZXJJZCA9IHByb3ZpZGVyRGF0YSEuZmlyc3QucHJvdmlkZXJJZDsKICAgICAgaWYgKHByb3ZpZGVySWQuY29udGFpbnMoJ2dvb2dsZScpKSByZXR1cm4gJ2dvb2dsZSc7CiAgICAgIGlmIChwcm92aWRlcklkLmNvbnRhaW5zKCdhcHBsZScpKSByZXR1cm4gJ2FwcGxlJzsKICAgIH0KICAgIHJldHVybiAnZW1haWwnOwogIH0KCiAgc3RhdGljIEZ1dHVyZTx2b2lkPiBsb2dTaWduSW5TdWNjZXNzKHsKICAgIHJlcXVpcmVkIFN0cmluZyBtZXRob2QsCiAgICBTdHJpbmc/IHVzZXJFbWFpbCwKICB9KSBhc3luYyB7Cnt7I2FuYWx5dGljc319ICAgIGF3YWl0IEFuYWx5dGljc0hlbHBlci5sb2dTaWduSW4oCiAgICAgIG1ldGhvZDogbWV0aG9kLAogICAgICBwYXJhbWV0ZXJzOiBfc3VjY2Vzc1BhcmFtcyh1c2VyRW1haWwpLAogICAgKTsKe3svYW5hbHl0aWNzfX0gIH0KCiAgc3RhdGljIEZ1dHVyZTx2b2lkPiBsb2dTaWduVXBTdWNjZXNzKHsKICAgIHJlcXVpcmVkIFN0cmluZyBtZXRob2QsCiAgICBTdHJpbmc/IHVzZXJFbWFpbCwKICB9KSBhc3luYyB7Cnt7I2FuYWx5dGljc319ICAgIGF3YWl0IEFuYWx5dGljc0hlbHBlci5sb2dTaWduVXAoCiAgICAgIG1ldGhvZDogbWV0aG9kLAogICAgICBwYXJhbWV0ZXJzOiBfc3VjY2Vzc1BhcmFtcyh1c2VyRW1haWwpLAogICAgKTsKe3svYW5hbHl0aWNzfX0gIH0KCiAgc3RhdGljIEZ1dHVyZTx2b2lkPiBsb2dVc2VyQ3JlYXRpb25TdWNjZXNzKHsKICAgIHJlcXVpcmVkIFN0cmluZyBtZXRob2QsCiAgICBTdHJpbmc/IHVzZXJFbWFpbCwKICB9KSBhc3luYyB7Cnt7I2FuYWx5dGljc319ICAgIGF3YWl0IEFuYWx5dGljc0hlbHBlci5sb2dFdmVudCgKICAgICAgQW5hbHl0aWNzRXZlbnRzLnVzZXIuYXV0aGVudGljYXRlZFJlZGlyZWN0LAogICAgICBwYXJhbWV0ZXJzOiB7CiAgICAgICAgJ2F1dGhfbWV0aG9kJzogbWV0aG9kLAogICAgICAgICdmbG93X3R5cGUnOiAncmVnaXN0cmF0aW9uJywKICAgICAgICAuLi5fc3VjY2Vzc1BhcmFtcyh1c2VyRW1haWwpLAogICAgICB9LAogICAgKTsKe3svYW5hbHl0aWNzfX0gIH0KCiAgc3RhdGljIEZ1dHVyZTx2b2lkPiBsb2dTaWduT3V0U3VjY2VzcygpIGFzeW5jIHsKe3sjYW5hbHl0aWNzfX0gICAgYXdhaXQgQW5hbHl0aWNzSGVscGVyLmxvZ0V2ZW50KAogICAgICBBbmFseXRpY3NFdmVudHMuYXV0aC5zaWduT3V0LAogICAgICBwYXJhbWV0ZXJzOiBfc3VjY2Vzc1BhcmFtcyhudWxsKSwKICAgICk7Cnt7L2FuYWx5dGljc319ICB9CgogIC8vLyBbZmxvd1R5cGVdIGlzIG9uZSBvZiAnc2lnbl9pbicsICdzaWduX3VwJywgJ2ZvcmdvdF9wYXNzd29yZCcuCiAgc3RhdGljIEZ1dHVyZTx2b2lkPiBsb2dBdXRoRXJyb3IoewogICAgcmVxdWlyZWQgU3RyaW5nIGVycm9yVHlwZSwKICAgIHJlcXVpcmVkIFN0cmluZyBmbG93VHlwZSwKICAgIFN0cmluZz8gZXJyb3JNZXNzYWdlLAogICAgU3RyaW5nPyBtZXRob2QsCiAgfSkgYXN5bmMgewp7eyNhbmFseXRpY3N9fSAgICBhd2FpdCBBbmFseXRpY3NIZWxwZXIubG9nRXZlbnQoCiAgICAgIEFuYWx5dGljc0V2ZW50cy5hdXRoLmZhaWxlZCwKICAgICAgcGFyYW1ldGVyczogewogICAgICAgICdlcnJvcl90eXBlJzogZXJyb3JUeXBlLAogICAgICAgICdmbG93X3R5cGUnOiBmbG93VHlwZSwKICAgICAgICAnYXV0aF9tZXRob2QnOiBtZXRob2QsCiAgICAgICAgJ2Vycm9yX21lc3NhZ2UnOiBlcnJvck1lc3NhZ2UsCiAgICAgICAgJ3RpbWVzdGFtcCc6IERhdGVUaW1lLm5vdygpLnRvSXNvODYwMVN0cmluZygpLAogICAgICB9LAogICAgKTsKe3svYW5hbHl0aWNzfX0gIH0KCiAgc3RhdGljIEZ1dHVyZTx2b2lkPiBsb2dTaWduT3V0RXJyb3Ioe3JlcXVpcmVkIFN0cmluZyBlcnJvck1lc3NhZ2V9KSBhc3luYyB7Cnt7I2FuYWx5dGljc319ICAgIGF3YWl0IEFuYWx5dGljc0hlbHBlci5sb2dFdmVudCgKICAgICAgQW5hbHl0aWNzRXZlbnRzLmVycm9yLmFwcEVycm9yLAogICAgICBwYXJhbWV0ZXJzOiB7CiAgICAgICAgJ2Vycm9yX3R5cGUnOiAnc2lnbl9vdXRfZmFpbGVkJywKICAgICAgICAnZXJyb3JfbWVzc2FnZSc6IGVycm9yTWVzc2FnZSwKICAgICAgICAnZmVhdHVyZSc6ICdhdXRoJywKICAgICAgICAndGltZXN0YW1wJzogRGF0ZVRpbWUubm93KCkudG9Jc284NjAxU3RyaW5nKCksCiAgICAgIH0sCiAgICApOwp7ey9hbmFseXRpY3N9fSAgfQp7eyNhbmFseXRpY3N9fQogIHN0YXRpYyBNYXA8U3RyaW5nLCBPYmplY3Q/PiBfc3VjY2Vzc1BhcmFtcyhTdHJpbmc/IHVzZXJFbWFpbCkgPT4gewogICAgJ3N1Y2Nlc3MnOiAndHJ1ZScsCiAgICAndXNlcl9lbWFpbF9kb21haW4nOiB1c2VyRW1haWw/LnNwbGl0KCdAJykubGFzdCwKICAgICd0aW1lc3RhbXAnOiBEYXRlVGltZS5ub3coKS50b0lzbzg2MDFTdHJpbmcoKSwKICB9Owp7ey9hbmFseXRpY3N9fX0K", "type": "text" }, { "path": "{{ name.snakeCase() }}/features/{{auth_dir}}/lib/auth.dart", "data": - "aW1wb3J0ICdkYXJ0OmlvJzsKCmltcG9ydCAncGFja2FnZTphdXRoL2NvbmZpZy9jb25maWcuZGFydCc7CmltcG9ydCAncGFja2FnZTphdXRoL2RhdGEvaW5kZXguZGFydCc7CmltcG9ydCAncGFja2FnZTpjb3JlL2xvZ2dlci9sb2dnZXIuZGFydCc7CmltcG9ydCAncGFja2FnZTpkaS9kaS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZpcmViYXNlX3VpX2F1dGgvZmlyZWJhc2VfdWlfYXV0aC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZpcmViYXNlX3VpX29hdXRoX2FwcGxlL2ZpcmViYXNlX3VpX29hdXRoX2FwcGxlLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZmlyZWJhc2VfdWlfb2F1dGhfZ29vZ2xlL2ZpcmViYXNlX3VpX29hdXRoX2dvb2dsZS5kYXJ0JzsKe3sjbmV0d29ya319aW1wb3J0ICdwYWNrYWdlOm5ldHdvcmsvbmV0d29yay5kYXJ0JzsKe3svbmV0d29ya319CmV4cG9ydCAnYW5hbHl0aWNzL2FuYWx5dGljcy5kYXJ0JzsKZXhwb3J0ICdjb25maWcvaW5kZXguZGFydCc7CmV4cG9ydCAnY29uc3RhbnRzL2luZGV4LmRhcnQnOwpleHBvcnQgJ2RhdGEvaW5kZXguZGFydCc7CmV4cG9ydCAncm91dGVyL3JvdXRlci5kYXJ0JzsKZXhwb3J0ICd1aS9zY3JlZW5zL2luZGV4LmRhcnQnOwoKLy8vIFJlZ2lzdGVycyB0aGUgYXV0aCBwcm92aWRlcnMgYW5kIHNlcnZpY2VzLgovLy8KLy8vIENhbGwgdGhpcyBhZnRlciBgRmlyZWJhc2UuaW5pdGlhbGl6ZUFwcGAgYW5kIGJlZm9yZSB0aGUgcm91dGVyIGlzIGJ1aWx0IC0KLy8vIHJvdXRlIGd1YXJkcyByZXNvbHZlIFtBdXRoU2VydmljZV0gZnJvbSB0aGUgbG9jYXRvciBvbiB0aGUgZmlyc3QgZnJhbWUuCkZ1dHVyZTx2b2lkPiBpbml0KEF1dGhDb25maWcgY29uZmlnKSBhc3luYyB7CiAgZmluYWwgbG9nZ2VyID0gZGkuZ2V0PExvZ2dlcj4oKTsKICBsb2dnZXIuaSgnSW5pdGlhbGl6aW5nIEF1dGguLi4nKTsKCiAgRmlyZWJhc2VVSUF1dGguY29uZmlndXJlUHJvdmlkZXJzKFsKICAgIEVtYWlsQXV0aFByb3ZpZGVyKCksCiAgICBHb29nbGVQcm92aWRlcihjbGllbnRJZDogY29uZmlnLmNsaWVudElkLCBpT1NQcmVmZXJQbGlzdDogdHJ1ZSksCiAgICBpZiAoUGxhdGZvcm0uaXNJT1MpIEFwcGxlUHJvdmlkZXIoKSwKICBdKTsKCiAgZGkucmVnaXN0ZXI8QXV0aFNlcnZpY2U+KEF1dGhTZXJ2aWNlSW1wKCkpOwp7eyNuZXR3b3JrfX0KICAvLyBUaGUgbmV0d29yayBsYXllciByZWFkcyBiZWFyZXIgdG9rZW5zIHRocm91Z2ggdGhpcyBwcm92aWRlciwgc28gYXV0aCBoYXMKICAvLyB0byBvd24gaXQgLSByZWdpc3RlcmluZyBpdCBhbnl3aGVyZSBlbHNlIHJpc2tzIGEgc3RhbGUgdG9rZW4gb24gcmVmcmVzaC4KICBkaS5yZWdpc3RlcjxBdXRoVG9rZW5Qcm92aWRlcj4oRmlyZWJhc2VBdXRoVG9rZW5Qcm92aWRlcigpKTsKe3svbmV0d29ya319CiAgbG9nZ2VyLmkoJ0F1dGggaW5pdGlhbGl6ZWQnKTsKfQo=", + "aW1wb3J0ICdwYWNrYWdlOmZsdXR0ZXIvZm91bmRhdGlvbi5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZpcmViYXNlX2F1dGgvZmlyZWJhc2VfYXV0aC5kYXJ0JyBzaG93IEZpcmViYXNlQXV0aDsKCmltcG9ydCAncGFja2FnZTphdXRoL2NvbmZpZy9jb25maWcuZGFydCc7CmltcG9ydCAncGFja2FnZTphdXRoL2RhdGEvaW5kZXguZGFydCc7CmltcG9ydCAncGFja2FnZTpjb3JlL2xvZ2dlci9sb2dnZXIuZGFydCc7CmltcG9ydCAncGFja2FnZTpkaS9kaS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZpcmViYXNlX3VpX2F1dGgvZmlyZWJhc2VfdWlfYXV0aC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZpcmViYXNlX3VpX29hdXRoX2FwcGxlL2ZpcmViYXNlX3VpX29hdXRoX2FwcGxlLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZmlyZWJhc2VfdWlfb2F1dGhfZ29vZ2xlL2ZpcmViYXNlX3VpX29hdXRoX2dvb2dsZS5kYXJ0JzsKe3sjbmV0d29ya319aW1wb3J0ICdwYWNrYWdlOm5ldHdvcmsvbmV0d29yay5kYXJ0JzsKe3svbmV0d29ya319CgpleHBvcnQgJ2FuYWx5dGljcy9hbmFseXRpY3MuZGFydCc7CmV4cG9ydCAnY29uZmlnL2luZGV4LmRhcnQnOwpleHBvcnQgJ2NvbnN0YW50cy9pbmRleC5kYXJ0JzsKZXhwb3J0ICdkYXRhL2luZGV4LmRhcnQnOwpleHBvcnQgJ3JvdXRlci9yb3V0ZXIuZGFydCc7CmV4cG9ydCAndWkvc2NyZWVucy9pbmRleC5kYXJ0JzsKCi8vLyBSZWdpc3RlcnMgdGhlIGF1dGggcHJvdmlkZXJzIGFuZCBzZXJ2aWNlcy4KLy8vCi8vLyBDYWxsIHRoaXMgYWZ0ZXIgYEZpcmViYXNlLmluaXRpYWxpemVBcHBgIGFuZCBiZWZvcmUgdGhlIHJvdXRlciBpcyBidWlsdCAtCi8vLyByb3V0ZSBndWFyZHMgcmVzb2x2ZSBbQXV0aFNlcnZpY2VdIGZyb20gdGhlIGxvY2F0b3Igb24gdGhlIGZpcnN0IGZyYW1lLgpGdXR1cmU8dm9pZD4gaW5pdCgKICBBdXRoQ29uZmlnIGNvbmZpZywgewogIEZpcmViYXNlQXV0aD8gZmlyZWJhc2VBdXRoLAogIHZvaWQgRnVuY3Rpb24oTGlzdDxBdXRoUHJvdmlkZXI+KT8gY29uZmlndXJlUHJvdmlkZXJzLAp9KSBhc3luYyB7CiAgZmluYWwgbG9nZ2VyID0gZGkuZ2V0PExvZ2dlcj4oKTsKICBsb2dnZXIuaSgnSW5pdGlhbGl6aW5nIEF1dGguLi4nKTsKCiAgKGNvbmZpZ3VyZVByb3ZpZGVycyA/PyBGaXJlYmFzZVVJQXV0aC5jb25maWd1cmVQcm92aWRlcnMpKFsKICAgIEVtYWlsQXV0aFByb3ZpZGVyKCksCiAgICBHb29nbGVQcm92aWRlcihjbGllbnRJZDogY29uZmlnLmNsaWVudElkLCBpT1NQcmVmZXJQbGlzdDogdHJ1ZSksCiAgICBpZiAoIWtJc1dlYiAmJiBkZWZhdWx0VGFyZ2V0UGxhdGZvcm0gPT0gVGFyZ2V0UGxhdGZvcm0uaU9TKSBBcHBsZVByb3ZpZGVyKCksCiAgXSk7CgogIGZpbmFsIHNkayA9IGZpcmViYXNlQXV0aCA/PyBGaXJlYmFzZUF1dGguaW5zdGFuY2U7CiAgZGkucmVnaXN0ZXI8QXV0aFNlcnZpY2U+KEF1dGhTZXJ2aWNlSW1wKGZpcmViYXNlQXV0aDogc2RrLCBsb2dnZXI6IGxvZ2dlcikpOwoKe3sjbmV0d29ya319ICAvLyBUaGUgbmV0d29yayBsYXllciByZWFkcyBiZWFyZXIgdG9rZW5zIHRocm91Z2ggdGhpcyBwcm92aWRlciwgc28gYXV0aCBoYXMKICAvLyB0byBvd24gaXQgLSByZWdpc3RlcmluZyBpdCBhbnl3aGVyZSBlbHNlIHJpc2tzIGEgc3RhbGUgdG9rZW4gb24gcmVmcmVzaC4KICBmaW5hbCB0b2tlbnMgPSBGaXJlYmFzZUF1dGhUb2tlblByb3ZpZGVyKGZpcmViYXNlQXV0aDogc2RrLCBsb2dnZXI6IGxvZ2dlcik7CiAgZGkucmVnaXN0ZXI8QXV0aFRva2VuUHJvdmlkZXI+KHRva2VucywgZGlzcG9zZTogKF8pID0+IHRva2Vucy5kaXNwb3NlKCkpOwoKe3svbmV0d29ya319ICBsb2dnZXIuaSgnQXV0aCBpbml0aWFsaXplZCcpOwp9Cg==", "type": "text" }, { @@ -127,7 +174,7 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "path": "{{ name.snakeCase() }}/features/{{auth_dir}}/lib/constants/routes.dart", "data": - "Y2xhc3MgQXV0aFJvdXRlcyB7CiAgQXV0aFJvdXRlcy5fKCk7CgogIHN0YXRpYyBjb25zdCBTdHJpbmcgYXV0aCA9ICcvYXV0aCc7CgogIHN0YXRpYyBjb25zdCBTdHJpbmcgc2lnbkluID0gJyRhdXRoL3NpZ24taW4nOwogIHN0YXRpYyBjb25zdCBTdHJpbmcgc2lnblVwID0gJyRhdXRoL3NpZ24tdXAnOwogIHN0YXRpYyBjb25zdCBTdHJpbmcgZm9yZ290UGFzc3dvcmQgPSAnJGF1dGgvZm9yZ290LXBhc3N3b3JkJzsKICBzdGF0aWMgY29uc3QgU3RyaW5nIHJlc2V0UGFzc3dvcmQgPSAnJGF1dGgvcmVzZXQtcGFzc3dvcmQnOwp9Cg==", + "YWJzdHJhY3QgZmluYWwgY2xhc3MgQXV0aFJvdXRlcyB7CiAgc3RhdGljIGNvbnN0IFN0cmluZyBhdXRoID0gJy9hdXRoJzsKCiAgc3RhdGljIGNvbnN0IFN0cmluZyBzaWduSW4gPSAnJGF1dGgvc2lnbi1pbic7CiAgc3RhdGljIGNvbnN0IFN0cmluZyBzaWduVXAgPSAnJGF1dGgvc2lnbi11cCc7CiAgc3RhdGljIGNvbnN0IFN0cmluZyBmb3Jnb3RQYXNzd29yZCA9ICckYXV0aC9mb3Jnb3QtcGFzc3dvcmQnOwogIHN0YXRpYyBjb25zdCBTdHJpbmcgcmVzZXRQYXNzd29yZCA9ICckYXV0aC9yZXNldC1wYXNzd29yZCc7Cn0K", "type": "text" }, { @@ -148,7 +195,7 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "path": "{{ name.snakeCase() }}/features/{{auth_dir}}/lib/data/services/auth_service_imp.dart", "data": - "aW1wb3J0ICdwYWNrYWdlOmF1dGgvYW5hbHl0aWNzL2FuYWx5dGljcy5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmF1dGgvZGF0YS9zZXJ2aWNlcy9hdXRoX3NlcnZpY2UuZGFydCc7CmltcG9ydCAncGFja2FnZTpjb3JlL2NvcmUuZGFydCc7CmltcG9ydCAncGFja2FnZTpkaS9kaS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZpcmViYXNlX2F1dGgvZmlyZWJhc2VfYXV0aC5kYXJ0JzsKCmNsYXNzIEF1dGhTZXJ2aWNlSW1wIGltcGxlbWVudHMgQXV0aFNlcnZpY2UgewogIGZpbmFsIF9sb2dnZXIgPSBkaS5nZXQ8TG9nZ2VyPigpOwogIGZpbmFsIEZpcmViYXNlQXV0aCBfZmlyZWJhc2VBdXRoID0gRmlyZWJhc2VBdXRoLmluc3RhbmNlOwoKICBAb3ZlcnJpZGUKICBTdHJpbmcgZ2V0IHVpZCA9PiBfZmlyZWJhc2VBdXRoLmN1cnJlbnRVc2VyPy51aWQgPz8gJyc7CgogIEBvdmVycmlkZQogIGJvb2wgZ2V0IGlzU2lnbmVkSW4gPT4gX2ZpcmViYXNlQXV0aC5jdXJyZW50VXNlciAhPSBudWxsOwoKICBAb3ZlcnJpZGUKICBGdXR1cmU8dm9pZD4gc2lnbk91dCgpIGFzeW5jIHsKICAgIHRyeSB7CiAgICAgIF9sb2dnZXIuZCgnQXR0ZW1wdGluZyB0byBzaWduIG91dCB1c2VyJyk7CiAgICAgIGF3YWl0IF9maXJlYmFzZUF1dGguc2lnbk91dCgpOwogICAgICBfbG9nZ2VyLmQoJ1VzZXIgc2lnbmVkIG91dCBzdWNjZXNzZnVsbHknKTsKCiAgICAgIC8vIExvZyBzdWNjZXNzZnVsIHNpZ24gb3V0CiAgICAgIEF1dGhBbmFseXRpY3MubG9nU2lnbk91dFN1Y2Nlc3MoKTsKICAgIH0gY2F0Y2ggKGUsIHMpIHsKICAgICAgX2xvZ2dlci5lKCdFcnJvciBzaWduaW5nIG91dCB1c2VyOiAkZScsIGUsIHMpOwoKICAgICAgLy8gTG9nIHNpZ24gb3V0IGVycm9yCiAgICAgIEF1dGhBbmFseXRpY3MubG9nU2lnbk91dEVycm9yKGVycm9yTWVzc2FnZTogZS50b1N0cmluZygpKTsKCiAgICAgIHJldGhyb3c7CiAgICB9CiAgfQp9Cg==", + "aW1wb3J0ICdwYWNrYWdlOmF1dGgvYW5hbHl0aWNzL2FuYWx5dGljcy5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmF1dGgvZGF0YS9zZXJ2aWNlcy9hdXRoX3NlcnZpY2UuZGFydCc7CmltcG9ydCAncGFja2FnZTpjb3JlL2NvcmUuZGFydCc7CmltcG9ydCAncGFja2FnZTpmaXJlYmFzZV9hdXRoL2ZpcmViYXNlX2F1dGguZGFydCc7CgpjbGFzcyBBdXRoU2VydmljZUltcCBpbXBsZW1lbnRzIEF1dGhTZXJ2aWNlIHsKICBBdXRoU2VydmljZUltcCh7cmVxdWlyZWQgRmlyZWJhc2VBdXRoIGZpcmViYXNlQXV0aCwgcmVxdWlyZWQgTG9nZ2VyIGxvZ2dlcn0pCiAgICA6IF9maXJlYmFzZUF1dGggPSBmaXJlYmFzZUF1dGgsCiAgICAgIF9sb2dnZXIgPSBsb2dnZXI7CgogIGZpbmFsIExvZ2dlciBfbG9nZ2VyOwogIGZpbmFsIEZpcmViYXNlQXV0aCBfZmlyZWJhc2VBdXRoOwoKICBAb3ZlcnJpZGUKICBTdHJpbmcgZ2V0IHVpZCA9PiBfZmlyZWJhc2VBdXRoLmN1cnJlbnRVc2VyPy51aWQgPz8gJyc7CgogIEBvdmVycmlkZQogIGJvb2wgZ2V0IGlzU2lnbmVkSW4gPT4gX2ZpcmViYXNlQXV0aC5jdXJyZW50VXNlciAhPSBudWxsOwoKICBAb3ZlcnJpZGUKICBGdXR1cmU8dm9pZD4gc2lnbk91dCgpIGFzeW5jIHsKICAgIHRyeSB7CiAgICAgIF9sb2dnZXIuZCgnQXR0ZW1wdGluZyB0byBzaWduIG91dCB1c2VyJyk7CiAgICAgIGF3YWl0IF9maXJlYmFzZUF1dGguc2lnbk91dCgpOwogICAgICBfbG9nZ2VyLmQoJ1VzZXIgc2lnbmVkIG91dCBzdWNjZXNzZnVsbHknKTsKCiAgICAgIC8vIExvZyBzdWNjZXNzZnVsIHNpZ24gb3V0CiAgICAgIGF3YWl0IEF1dGhBbmFseXRpY3MubG9nU2lnbk91dFN1Y2Nlc3MoKTsKICAgIH0gY2F0Y2ggKGUsIHMpIHsKICAgICAgX2xvZ2dlci5lKCdFcnJvciBzaWduaW5nIG91dCB1c2VyOiAkZScsIGUsIHMpOwoKICAgICAgLy8gTG9nIHNpZ24gb3V0IGVycm9yCiAgICAgIGF3YWl0IEF1dGhBbmFseXRpY3MubG9nU2lnbk91dEVycm9yKGVycm9yTWVzc2FnZTogZS50b1N0cmluZygpKTsKCiAgICAgIHJldGhyb3c7CiAgICB9CiAgfQp9Cg==", "type": "text" }, { @@ -162,14 +209,14 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "path": "{{ name.snakeCase() }}/features/{{auth_dir}}/lib/data/token/firebase_auth_token_provider.dart", "data": - "e3sjbmV0d29ya319aW1wb3J0ICdkYXJ0OmFzeW5jJzsKCmltcG9ydCAncGFja2FnZTpjb3JlL2NvcmUuZGFydCc7CmltcG9ydCAncGFja2FnZTpkaS9kaS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZpcmViYXNlX2F1dGgvZmlyZWJhc2VfYXV0aC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOm5ldHdvcmsvbmV0d29yay5kYXJ0JzsKCmZpbmFsIF90YWcgPSAnRmlyZWJhc2VBdXRoVG9rZW5Qcm92aWRlcic7CgpjbGFzcyBGaXJlYmFzZUF1dGhUb2tlblByb3ZpZGVyIGltcGxlbWVudHMgQXV0aFRva2VuUHJvdmlkZXIgewogIEZpcmViYXNlQXV0aFRva2VuUHJvdmlkZXIoKSA6IF9sb2dnZXIgPSBkaS5nZXQ8TG9nZ2VyPigpIHsKICAgIF9pbml0aWFsaXplVG9rZW5TdHJlYW0oKTsKICB9CgogIGZpbmFsIEZpcmViYXNlQXV0aCBfZmlyZWJhc2VBdXRoID0gRmlyZWJhc2VBdXRoLmluc3RhbmNlOwogIGZpbmFsIExvZ2dlciBfbG9nZ2VyOwoKICBsYXRlIGZpbmFsIFN0cmVhbUNvbnRyb2xsZXI8U3RyaW5nPz4gX3Rva2VuQ29udHJvbGxlcjsKICBTdHJlYW1TdWJzY3JpcHRpb248VXNlcj8+PyBfYXV0aFN0YXRlU3Vic2NyaXB0aW9uOwogIFN0cmluZz8gX2NhY2hlZFRva2VuOwogIERhdGVUaW1lPyBfdG9rZW5FeHBpcnk7CgogIHZvaWQgX2luaXRpYWxpemVUb2tlblN0cmVhbSgpIHsKICAgIF90b2tlbkNvbnRyb2xsZXIgPSBTdHJlYW1Db250cm9sbGVyPFN0cmluZz8+LmJyb2FkY2FzdCgpOwoKICAgIC8vIExpc3RlbiB0byBhdXRoIHN0YXRlIGNoYW5nZXMKICAgIF9hdXRoU3RhdGVTdWJzY3JpcHRpb24gPSBfZmlyZWJhc2VBdXRoLmF1dGhTdGF0ZUNoYW5nZXMoKS5saXN0ZW4oCiAgICAgIChVc2VyPyB1c2VyKSBhc3luYyB7CiAgICAgICAgaWYgKHVzZXIgIT0gbnVsbCkgewogICAgICAgICAgdHJ5IHsKICAgICAgICAgICAgZmluYWwgdG9rZW4gPSBhd2FpdCB1c2VyLmdldElkVG9rZW4oKTsKICAgICAgICAgICAgX2NhY2hlZFRva2VuID0gdG9rZW47CiAgICAgICAgICAgIF9zZXRUb2tlbkV4cGlyeSh0b2tlbiEpOwogICAgICAgICAgICBfdG9rZW5Db250cm9sbGVyLmFkZCh0b2tlbik7CiAgICAgICAgICAgIF9sb2dnZXIuZCgn8J+UkCRfdGFnOiBBdXRoIHRva2VuIHVwZGF0ZWQgZm9yIHVzZXI6ICR7dXNlci51aWR9Jyk7CiAgICAgICAgICB9IGNhdGNoIChlLCBzKSB7CiAgICAgICAgICAgIF9sb2dnZXIuZSgKICAgICAgICAgICAgICAn8J+aqCRfdGFnOiBFcnJvciBnZXR0aW5nIHRva2VuIGZvciB1c2VyOiAke3VzZXIudWlkfScsCiAgICAgICAgICAgICAgZSwKICAgICAgICAgICAgICBzLAogICAgICAgICAgICApOwogICAgICAgICAgICBfY2FjaGVkVG9rZW4gPSBudWxsOwogICAgICAgICAgICBfdG9rZW5FeHBpcnkgPSBudWxsOwogICAgICAgICAgICBfdG9rZW5Db250cm9sbGVyLmFkZChudWxsKTsKICAgICAgICAgIH0KICAgICAgICB9IGVsc2UgewogICAgICAgICAgX2NhY2hlZFRva2VuID0gbnVsbDsKICAgICAgICAgIF90b2tlbkV4cGlyeSA9IG51bGw7CiAgICAgICAgICBfdG9rZW5Db250cm9sbGVyLmFkZChudWxsKTsKICAgICAgICAgIF9sb2dnZXIuZCgn8J+UkyRfdGFnOiBVc2VyIHNpZ25lZCBvdXQsIHRva2VuIGNsZWFyZWQnKTsKICAgICAgICB9CiAgICAgIH0sCiAgICAgIG9uRXJyb3I6IChlLCBzKSB7CiAgICAgICAgX2xvZ2dlci5lKCfwn5qoICRfdGFnOiBBdXRoIHN0YXRlIGNoYW5nZSBlcnJvcicsIGUsIHMpOwogICAgICAgIF90b2tlbkNvbnRyb2xsZXIuYWRkKG51bGwpOwogICAgICB9LAogICAgKTsKICB9CgogIHZvaWQgX3NldFRva2VuRXhwaXJ5KFN0cmluZyB0b2tlbikgewogICAgdHJ5IHsKICAgICAgLy8gRmlyZWJhc2UgSUQgdG9rZW5zIGFyZSB0eXBpY2FsbHkgdmFsaWQgZm9yIDEgaG91cgogICAgICAvLyBXZSdsbCByZWZyZXNoIDUgbWludXRlcyBiZWZvcmUgZXhwaXJ5CiAgICAgIF90b2tlbkV4cGlyeSA9IERhdGVUaW1lLm5vdygpLmFkZChjb25zdCBEdXJhdGlvbihtaW51dGVzOiA1NSkpOwogICAgfSBjYXRjaCAoZSkgewogICAgICBfbG9nZ2VyLncoJ+KaoO+4jyRfdGFnOiBDb3VsZCBub3QgZGV0ZXJtaW5lIHRva2VuIGV4cGlyeSwgdXNpbmcgZGVmYXVsdCAkZScpOwogICAgICBfdG9rZW5FeHBpcnkgPSBEYXRlVGltZS5ub3coKS5hZGQoY29uc3QgRHVyYXRpb24obWludXRlczogNTUpKTsKICAgIH0KICB9CgogIEBvdmVycmlkZQogIEZ1dHVyZTxTdHJpbmc/PiBnZXRWYWxpZFRva2VuKCkgYXN5bmMgewogICAgZmluYWwgdXNlciA9IF9maXJlYmFzZUF1dGguY3VycmVudFVzZXI7CiAgICBpZiAodXNlciA9PSBudWxsKSB7CiAgICAgIF9sb2dnZXIuZCgn8J+UkyRfdGFnOiBObyBhdXRoZW50aWNhdGVkIHVzZXIgYXZhaWxhYmxlJyk7CiAgICAgIHJldHVybiBudWxsOwogICAgfQoKICAgIC8vIENoZWNrIGlmIGNhY2hlZCB0b2tlbiBpcyBzdGlsbCB2YWxpZAogICAgaWYgKF9jYWNoZWRUb2tlbiAhPSBudWxsICYmICFpc1Rva2VuRXhwaXJlZCkgewogICAgICBfbG9nZ2VyLmQoJ/CflJAkX3RhZzogVXNpbmcgY2FjaGVkIHRva2VuJyk7CiAgICAgIHJldHVybiBfY2FjaGVkVG9rZW47CiAgICB9CgogICAgLy8gR2V0IGZyZXNoIHRva2VuCiAgICB0cnkgewogICAgICBfbG9nZ2VyLmQoJ/CflIQkX3RhZzogRmV0Y2hpbmcgZnJlc2ggdG9rZW4gZm9yIHVzZXI6ICR7dXNlci51aWR9Jyk7CiAgICAgIGZpbmFsIHRva2VuID0gYXdhaXQgdXNlci5nZXRJZFRva2VuKHRydWUpOyAvLyBGb3JjZSByZWZyZXNoCiAgICAgIF9jYWNoZWRUb2tlbiA9IHRva2VuOwogICAgICBfc2V0VG9rZW5FeHBpcnkodG9rZW4hKTsKICAgICAgX3Rva2VuQ29udHJvbGxlci5hZGQodG9rZW4pOwogICAgICByZXR1cm4gdG9rZW47CiAgICB9IGNhdGNoIChlLCBzKSB7CiAgICAgIF9sb2dnZXIuZSgn8J+aqCRfdGFnOiBFcnJvciBnZXR0aW5nIGZyZXNoIHRva2VuJywgZSwgcyk7CiAgICAgIF9jYWNoZWRUb2tlbiA9IG51bGw7CiAgICAgIF90b2tlbkV4cGlyeSA9IG51bGw7CiAgICAgIHJldHVybiBudWxsOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgU3RyaW5nPyBnZXRDdXJyZW50VG9rZW4oKSB7CiAgICByZXR1cm4gX2NhY2hlZFRva2VuOwogIH0KCiAgQG92ZXJyaWRlCiAgU3RyZWFtPFN0cmluZz8+IGdldCB0b2tlblN0cmVhbSA9PiBfdG9rZW5Db250cm9sbGVyLnN0cmVhbTsKCiAgQG92ZXJyaWRlCiAgRnV0dXJlPFN0cmluZz8+IHJlZnJlc2hUb2tlbigpIGFzeW5jIHsKICAgIGZpbmFsIHVzZXIgPSBfZmlyZWJhc2VBdXRoLmN1cnJlbnRVc2VyOwogICAgaWYgKHVzZXIgPT0gbnVsbCkgewogICAgICBfbG9nZ2VyLncoJ/CflJMkX3RhZzogQ2Fubm90IHJlZnJlc2ggdG9rZW4gLSBubyBhdXRoZW50aWNhdGVkIHVzZXInKTsKICAgICAgcmV0dXJuIG51bGw7CiAgICB9CgogICAgdHJ5IHsKICAgICAgX2xvZ2dlci5kKCfwn5SEJF90YWc6IFJlZnJlc2hpbmcgdG9rZW4gZm9yIHVzZXI6ICR7dXNlci51aWR9Jyk7CiAgICAgIGZpbmFsIHRva2VuID0gYXdhaXQgdXNlci5nZXRJZFRva2VuKHRydWUpOyAvLyBGb3JjZSByZWZyZXNoCiAgICAgIF9jYWNoZWRUb2tlbiA9IHRva2VuOwogICAgICBfc2V0VG9rZW5FeHBpcnkodG9rZW4hKTsKICAgICAgX3Rva2VuQ29udHJvbGxlci5hZGQodG9rZW4pOwogICAgICBfbG9nZ2VyLmkoJ+KchSRfdGFnOiBUb2tlbiByZWZyZXNoZWQgc3VjY2Vzc2Z1bGx5Jyk7CiAgICAgIHJldHVybiB0b2tlbjsKICAgIH0gY2F0Y2ggKGUsIHMpIHsKICAgICAgX2xvZ2dlci5lKCfwn5qoJF90YWc6IFRva2VuIHJlZnJlc2ggZmFpbGVkJywgZSwgcyk7CiAgICAgIF9jYWNoZWRUb2tlbiA9IG51bGw7CiAgICAgIF90b2tlbkV4cGlyeSA9IG51bGw7CiAgICAgIF90b2tlbkNvbnRyb2xsZXIuYWRkKG51bGwpOwogICAgICByZXR1cm4gbnVsbDsKICAgIH0KICB9CgogIEBvdmVycmlkZQogIGJvb2wgZ2V0IGlzQXV0aGVudGljYXRlZCA9PiBfZmlyZWJhc2VBdXRoLmN1cnJlbnRVc2VyICE9IG51bGw7CgogIEBvdmVycmlkZQogIGJvb2wgZ2V0IGlzVG9rZW5FeHBpcmVkIHsKICAgIGlmIChfdG9rZW5FeHBpcnkgPT0gbnVsbCkgcmV0dXJuIHRydWU7CiAgICByZXR1cm4gRGF0ZVRpbWUubm93KCkuaXNBZnRlcihfdG9rZW5FeHBpcnkhKTsKICB9CgogIEBvdmVycmlkZQogIEZ1dHVyZTx2b2lkPiBzaWduT3V0KCkgYXN5bmMgewogICAgdHJ5IHsKICAgICAgX2xvZ2dlci5kKCfwn5STJF90YWc6IFNpZ25pbmcgb3V0IHVzZXInKTsKICAgICAgYXdhaXQgX2ZpcmViYXNlQXV0aC5zaWduT3V0KCk7CiAgICAgIF9jYWNoZWRUb2tlbiA9IG51bGw7CiAgICAgIF90b2tlbkV4cGlyeSA9IG51bGw7CiAgICAgIF90b2tlbkNvbnRyb2xsZXIuYWRkKG51bGwpOwogICAgICBfbG9nZ2VyLmkoJ+KchSRfdGFnOiBVc2VyIHNpZ25lZCBvdXQgc3VjY2Vzc2Z1bGx5Jyk7CiAgICB9IGNhdGNoIChlLCBzKSB7CiAgICAgIF9sb2dnZXIuZSgn8J+aqCRfdGFnOiBFcnJvciBzaWduaW5nIG91dCB1c2VyJywgZSwgcyk7CiAgICAgIHJldGhyb3c7CiAgICB9CiAgfQoKICB2b2lkIGRpc3Bvc2UoKSB7CiAgICBfYXV0aFN0YXRlU3Vic2NyaXB0aW9uPy5jYW5jZWwoKTsKICAgIF90b2tlbkNvbnRyb2xsZXIuY2xvc2UoKTsKICAgIF9sb2dnZXIuZCgn8J+nuSRfdGFnOiBkaXNwb3NlZCcpOwogIH0KfXt7L25ldHdvcmt9fQo=", + "e3sjbmV0d29ya319aW1wb3J0ICdkYXJ0OmFzeW5jJzsKCmltcG9ydCAncGFja2FnZTpjb3JlL2NvcmUuZGFydCc7CmltcG9ydCAncGFja2FnZTpmaXJlYmFzZV9hdXRoL2ZpcmViYXNlX2F1dGguZGFydCc7CmltcG9ydCAncGFja2FnZTpuZXR3b3JrL25ldHdvcmsuZGFydCc7CgovLy8gQWRhcHRzIEZpcmViYXNlIHRva2VucyB0byB0aGUgbmV0d29yayBjb250cmFjdCBhbmQgb3ducyBpdHMgc3Vic2NyaXB0aW9uLgpjbGFzcyBGaXJlYmFzZUF1dGhUb2tlblByb3ZpZGVyIGltcGxlbWVudHMgQXV0aFRva2VuUHJvdmlkZXIgewogIEZpcmViYXNlQXV0aFRva2VuUHJvdmlkZXIoewogICAgcmVxdWlyZWQgRmlyZWJhc2VBdXRoIGZpcmViYXNlQXV0aCwKICAgIHJlcXVpcmVkIExvZ2dlciBsb2dnZXIsCiAgICBEYXRlVGltZSBGdW5jdGlvbigpPyBub3csCiAgfSkgOiBfYXV0aCA9IGZpcmViYXNlQXV0aCwKICAgICAgIF9sb2dnZXIgPSBsb2dnZXIsCiAgICAgICBfbm93ID0gbm93ID8/IERhdGVUaW1lLm5vdyB7CiAgICBfc3Vic2NyaXB0aW9uID0gX2F1dGguaWRUb2tlbkNoYW5nZXMoKS5saXN0ZW4oCiAgICAgICh1c2VyKSB7CiAgICAgICAgX3JldmlzaW9uKys7CiAgICAgICAgX3B1Ymxpc2gobnVsbCk7CiAgICAgICAgaWYgKHVzZXIgIT0gbnVsbCkgdW5hd2FpdGVkKF9yZWFkVG9rZW4odXNlciwgZm9yY2U6IGZhbHNlKSk7CiAgICAgIH0sCiAgICAgIG9uRXJyb3I6IChPYmplY3QgZXJyb3IsIFN0YWNrVHJhY2Ugc3RhY2tUcmFjZSkgewogICAgICAgIF9yZXZpc2lvbisrOwogICAgICAgIF9wdWJsaXNoKG51bGwpOwogICAgICAgIF9sb2dnZXIuZSgnQXV0aCB0b2tlbiBzdHJlYW0gZmFpbGVkJywgZXJyb3IsIHN0YWNrVHJhY2UpOwogICAgICB9LAogICAgKTsKICB9CgogIGZpbmFsIEZpcmViYXNlQXV0aCBfYXV0aDsKICBmaW5hbCBMb2dnZXIgX2xvZ2dlcjsKICBmaW5hbCBEYXRlVGltZSBGdW5jdGlvbigpIF9ub3c7CiAgZmluYWwgX2NvbnRyb2xsZXIgPSBTdHJlYW1Db250cm9sbGVyPFN0cmluZz8+LmJyb2FkY2FzdCgpOwogIGxhdGUgZmluYWwgU3RyZWFtU3Vic2NyaXB0aW9uPFVzZXI/PiBfc3Vic2NyaXB0aW9uOwogIFN0cmluZz8gX3Rva2VuOwogIERhdGVUaW1lPyBfZXhwaXJ5OwogIGludCBfcmV2aXNpb24gPSAwOwogIGJvb2wgX2Rpc3Bvc2VkID0gZmFsc2U7CgogIHZvaWQgX3B1Ymxpc2goU3RyaW5nPyB0b2tlbiwgW0RhdGVUaW1lPyBleHBpcnldKSB7CiAgICBpZiAoX2Rpc3Bvc2VkKSByZXR1cm47CiAgICBfdG9rZW4gPSB0b2tlbjsKICAgIF9leHBpcnkgPSBleHBpcnk7CiAgICBfY29udHJvbGxlci5hZGQodG9rZW4pOwogIH0KCiAgRnV0dXJlPFN0cmluZz8+IF9yZWFkVG9rZW4oVXNlciB1c2VyLCB7cmVxdWlyZWQgYm9vbCBmb3JjZX0pIGFzeW5jIHsKICAgIGZpbmFsIHJldmlzaW9uID0gX3JldmlzaW9uOwogICAgdHJ5IHsKICAgICAgZmluYWwgcmVzdWx0ID0gYXdhaXQgdXNlci5nZXRJZFRva2VuUmVzdWx0KGZvcmNlKTsKICAgICAgLy8gQSBsYXRlIHJlZnJlc2ggZnJvbSBhbiBvbGQgc2Vzc2lvbiBtdXN0IG5ldmVyIHJlc3RvcmUgaXRzIHRva2VuLgogICAgICBpZiAoX2Rpc3Bvc2VkIHx8CiAgICAgICAgICByZXZpc2lvbiAhPSBfcmV2aXNpb24gfHwKICAgICAgICAgIF9hdXRoLmN1cnJlbnRVc2VyPy51aWQgIT0gdXNlci51aWQpIHsKICAgICAgICByZXR1cm4gbnVsbDsKICAgICAgfQogICAgICBfcHVibGlzaChyZXN1bHQudG9rZW4sIHJlc3VsdC5leHBpcmF0aW9uVGltZSk7CiAgICAgIHJldHVybiByZXN1bHQudG9rZW47CiAgICB9IGNhdGNoIChlcnJvciwgc3RhY2tUcmFjZSkgewogICAgICBpZiAoIV9kaXNwb3NlZCAmJiByZXZpc2lvbiA9PSBfcmV2aXNpb24pIHsKICAgICAgICBfcHVibGlzaChudWxsKTsKICAgICAgICBfbG9nZ2VyLmUoJ1VuYWJsZSB0byByZWFkIGF1dGhlbnRpY2F0aW9uIHRva2VuJywgZXJyb3IsIHN0YWNrVHJhY2UpOwogICAgICB9CiAgICAgIHJldHVybiBudWxsOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPFN0cmluZz8+IGdldFZhbGlkVG9rZW4oKSBhc3luYyB7CiAgICBmaW5hbCB1c2VyID0gX2F1dGguY3VycmVudFVzZXI7CiAgICBpZiAoX2Rpc3Bvc2VkIHx8IHVzZXIgPT0gbnVsbCkgcmV0dXJuIG51bGw7CiAgICBpZiAoX3Rva2VuICE9IG51bGwgJiYgIWlzVG9rZW5FeHBpcmVkKSByZXR1cm4gX3Rva2VuOwogICAgcmV0dXJuIF9yZWFkVG9rZW4odXNlciwgZm9yY2U6IGZhbHNlKTsKICB9CgogIEBvdmVycmlkZQogIEZ1dHVyZTxTdHJpbmc/PiByZWZyZXNoVG9rZW4oKSBhc3luYyB7CiAgICBmaW5hbCB1c2VyID0gX2F1dGguY3VycmVudFVzZXI7CiAgICBpZiAoX2Rpc3Bvc2VkIHx8IHVzZXIgPT0gbnVsbCkgcmV0dXJuIG51bGw7CiAgICByZXR1cm4gX3JlYWRUb2tlbih1c2VyLCBmb3JjZTogdHJ1ZSk7CiAgfQoKICBAb3ZlcnJpZGUKICBTdHJpbmc/IGdldEN1cnJlbnRUb2tlbigpID0+IF90b2tlbjsKCiAgQG92ZXJyaWRlCiAgU3RyZWFtPFN0cmluZz8+IGdldCB0b2tlblN0cmVhbSA9PiBfY29udHJvbGxlci5zdHJlYW07CgogIEBvdmVycmlkZQogIGJvb2wgZ2V0IGlzQXV0aGVudGljYXRlZCA9PiAhX2Rpc3Bvc2VkICYmIF9hdXRoLmN1cnJlbnRVc2VyICE9IG51bGw7CgogIEBvdmVycmlkZQogIGJvb2wgZ2V0IGlzVG9rZW5FeHBpcmVkID0+CiAgICAgIF9leHBpcnkgPT0gbnVsbCB8fAogICAgICAhX25vdygpLmlzQmVmb3JlKF9leHBpcnkhLnN1YnRyYWN0KGNvbnN0IER1cmF0aW9uKG1pbnV0ZXM6IDUpKSk7CgogIEBvdmVycmlkZQogIEZ1dHVyZTx2b2lkPiBzaWduT3V0KCkgYXN5bmMgewogICAgX3JldmlzaW9uKys7CiAgICBfcHVibGlzaChudWxsKTsKICAgIGF3YWl0IF9hdXRoLnNpZ25PdXQoKTsKICB9CgogIEZ1dHVyZTx2b2lkPiBkaXNwb3NlKCkgYXN5bmMgewogICAgaWYgKF9kaXNwb3NlZCkgcmV0dXJuOwogICAgX2Rpc3Bvc2VkID0gdHJ1ZTsKICAgIF9yZXZpc2lvbisrOwogICAgX3Rva2VuID0gbnVsbDsKICAgIF9leHBpcnkgPSBudWxsOwogICAgYXdhaXQgX3N1YnNjcmlwdGlvbi5jYW5jZWwoKTsKICAgIGF3YWl0IF9jb250cm9sbGVyLmNsb3NlKCk7CiAgfQp9Cnt7L25ldHdvcmt9fQo=", "type": "text" }, { "path": "{{ name.snakeCase() }}/features/{{auth_dir}}/lib/router/router.dart", "data": - "aW1wb3J0ICdwYWNrYWdlOmF1dGgvY29uc3RhbnRzL2luZGV4LmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6YXV0aC9kYXRhL3NlcnZpY2VzL2F1dGhfc2VydmljZS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmF1dGgvdWkvc2NyZWVucy9pbmRleC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmNvcmUvY29yZS5kYXJ0JyBhcyBjb3JlOwppbXBvcnQgJ3BhY2thZ2U6ZGkvZGkuZGFydCc7CmltcG9ydCAncGFja2FnZTpmbHV0dGVyL21hdGVyaWFsLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Z29fcm91dGVyL2dvX3JvdXRlci5kYXJ0JzsKCmNsYXNzIEF1dGhSb3V0ZXIgZXh0ZW5kcyBjb3JlLkNvcmVSb3V0ZXIgewogIGZpbmFsIEZ1bmN0aW9uKEJ1aWxkQ29udGV4dCBjb250ZXh0KSBvblNpZ25lZEluOwogIGZpbmFsIEZ1bmN0aW9uKEJ1aWxkQ29udGV4dCBjb250ZXh0KSBvblNpZ25lZFVwOwoKICBBdXRoUm91dGVyKHtyZXF1aXJlZCB0aGlzLm9uU2lnbmVkSW4sIHJlcXVpcmVkIHRoaXMub25TaWduZWRVcH0pOwoKICBAb3ZlcnJpZGUKICBMaXN0PFJvdXRlQmFzZT4gZ2V0IHJvdXRlcyA9PiBbCiAgICBHb1JvdXRlKAogICAgICBwYXRoOiBBdXRoUm91dGVzLnNpZ25JbiwKICAgICAgYnVpbGRlcjogKGNvbnRleHQsIHN0YXRlKSA9PiBTaWduSW5TY3JlZW4ob25TaWduZWRJbjogb25TaWduZWRJbiksCiAgICApLAogICAgR29Sb3V0ZSgKICAgICAgcGF0aDogQXV0aFJvdXRlcy5zaWduVXAsCiAgICAgIGJ1aWxkZXI6IChjb250ZXh0LCBzdGF0ZSkgPT4gUmVnaXN0ZXJTY3JlZW4ob25TaWduZWRVcDogb25TaWduZWRVcCksCiAgICApLAogICAgR29Sb3V0ZSgKICAgICAgcGF0aDogQXV0aFJvdXRlcy5mb3Jnb3RQYXNzd29yZCwKICAgICAgYnVpbGRlcjogKGNvbnRleHQsIHN0YXRlKSB7CiAgICAgICAgZmluYWwgZW1haWwgPSBzdGF0ZS51cmkucXVlcnlQYXJhbWV0ZXJzW2NvcmUuS2V5cy5lbWFpbF07CiAgICAgICAgcmV0dXJuIEZvcmdvdFBhc3N3b3JkU2NyZWVuKGVtYWlsOiBlbWFpbCk7CiAgICAgIH0sCiAgICApLAogIF07Cn0KCmZpbmFsIGNsYXNzIEdvQXV0aFJvdXRlIGV4dGVuZHMgR29Sb3V0ZSB7CiAgLy8vIENyZWF0ZSBhIHNlY3VyZSByb3V0ZSB0aGF0IHJlcXVpcmVzIGF1dGhlbnRpY2F0aW9uCiAgR29BdXRoUm91dGUoewogICAgcmVxdWlyZWQgc3VwZXIucGF0aCwKICAgIHJlcXVpcmVkIHN1cGVyLmJ1aWxkZXIsCiAgICBMaXN0PEdvUm91dGU+IHN1cGVyLnJvdXRlcyA9IGNvbnN0IFtdLAogICAgc3VwZXIucGFnZUJ1aWxkZXIsCiAgfSkgOiBzdXBlcigKICAgICAgICAgcmVkaXJlY3Q6IChjb250ZXh0LCBzdGF0ZSkgYXN5bmMgewogICAgICAgICAgIGlmICghZGkuaGFzPEF1dGhTZXJ2aWNlPigpKSByZXR1cm4gbnVsbDsKCiAgICAgICAgICAgZmluYWwgYXV0aFNlcnZpY2UgPSBkaS5nZXQ8QXV0aFNlcnZpY2U+KCk7CgogICAgICAgICAgIGlmICghYXV0aFNlcnZpY2UuaXNTaWduZWRJbikgewogICAgICAgICAgICAgcmV0dXJuIEF1dGhSb3V0ZXMuc2lnbkluOwogICAgICAgICAgIH0KCiAgICAgICAgICAgcmV0dXJuIG51bGw7CiAgICAgICAgIH0sCiAgICAgICApOwp9Cg==", + "aW1wb3J0ICdwYWNrYWdlOmF1dGgvY29uc3RhbnRzL2luZGV4LmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6YXV0aC9kYXRhL3NlcnZpY2VzL2F1dGhfc2VydmljZS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmF1dGgvdWkvc2NyZWVucy9pbmRleC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmNvcmUvY29yZS5kYXJ0JyBhcyBjb3JlOwppbXBvcnQgJ3BhY2thZ2U6ZGkvZGkuZGFydCc7CmltcG9ydCAncGFja2FnZTpmbHV0dGVyL21hdGVyaWFsLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Z29fcm91dGVyL2dvX3JvdXRlci5kYXJ0JzsKCmNsYXNzIEF1dGhSb3V0ZXIgZXh0ZW5kcyBjb3JlLkNvcmVSb3V0ZXIgewogIGZpbmFsIEZ1bmN0aW9uKEJ1aWxkQ29udGV4dCBjb250ZXh0KSBvblNpZ25lZEluOwogIGZpbmFsIEZ1bmN0aW9uKEJ1aWxkQ29udGV4dCBjb250ZXh0KSBvblNpZ25lZFVwOwoKICBBdXRoUm91dGVyKHtyZXF1aXJlZCB0aGlzLm9uU2lnbmVkSW4sIHJlcXVpcmVkIHRoaXMub25TaWduZWRVcH0pOwoKICBAb3ZlcnJpZGUKICBMaXN0PFJvdXRlQmFzZT4gZ2V0IHJvdXRlcyA9PiBbCiAgICBHb1JvdXRlKAogICAgICBwYXRoOiBBdXRoUm91dGVzLnNpZ25JbiwKICAgICAgYnVpbGRlcjogKGNvbnRleHQsIHN0YXRlKSA9PiBTaWduSW5TY3JlZW4ob25TaWduZWRJbjogb25TaWduZWRJbiksCiAgICApLAogICAgR29Sb3V0ZSgKICAgICAgcGF0aDogQXV0aFJvdXRlcy5zaWduVXAsCiAgICAgIGJ1aWxkZXI6IChjb250ZXh0LCBzdGF0ZSkgPT4gUmVnaXN0ZXJTY3JlZW4ob25TaWduZWRVcDogb25TaWduZWRVcCksCiAgICApLAogICAgR29Sb3V0ZSgKICAgICAgcGF0aDogQXV0aFJvdXRlcy5mb3Jnb3RQYXNzd29yZCwKICAgICAgYnVpbGRlcjogKGNvbnRleHQsIHN0YXRlKSB7CiAgICAgICAgZmluYWwgZW1haWwgPSBzdGF0ZS51cmkucXVlcnlQYXJhbWV0ZXJzW2NvcmUuS2V5cy5lbWFpbF07CiAgICAgICAgcmV0dXJuIEZvcmdvdFBhc3N3b3JkU2NyZWVuKGVtYWlsOiBlbWFpbCk7CiAgICAgIH0sCiAgICApLAogIF07Cn0KCmZpbmFsIGNsYXNzIEdvQXV0aFJvdXRlIGV4dGVuZHMgR29Sb3V0ZSB7CiAgLy8vIENyZWF0ZSBhIHNlY3VyZSByb3V0ZSB0aGF0IHJlcXVpcmVzIGF1dGhlbnRpY2F0aW9uCiAgR29BdXRoUm91dGUoewogICAgcmVxdWlyZWQgc3VwZXIucGF0aCwKICAgIHJlcXVpcmVkIHN1cGVyLmJ1aWxkZXIsCiAgICBMaXN0PEdvUm91dGU+IHN1cGVyLnJvdXRlcyA9IGNvbnN0IFtdLAogICAgc3VwZXIucGFnZUJ1aWxkZXIsCiAgICBib29sIGFsbG93VW5jb25maWd1cmVkID0gZmFsc2UsCiAgfSkgOiBzdXBlcigKICAgICAgICAgcmVkaXJlY3Q6IChjb250ZXh0LCBzdGF0ZSkgYXN5bmMgewogICAgICAgICAgIGlmICghZGkuaGFzPEF1dGhTZXJ2aWNlPigpKSB7CiAgICAgICAgICAgICByZXR1cm4gYWxsb3dVbmNvbmZpZ3VyZWQgPyBudWxsIDogQXV0aFJvdXRlcy5zaWduSW47CiAgICAgICAgICAgfQoKICAgICAgICAgICBmaW5hbCBhdXRoU2VydmljZSA9IGRpLmdldDxBdXRoU2VydmljZT4oKTsKCiAgICAgICAgICAgaWYgKCFhdXRoU2VydmljZS5pc1NpZ25lZEluKSB7CiAgICAgICAgICAgICByZXR1cm4gQXV0aFJvdXRlcy5zaWduSW47CiAgICAgICAgICAgfQoKICAgICAgICAgICByZXR1cm4gbnVsbDsKICAgICAgICAgfSwKICAgICAgICk7Cn0K", "type": "text" }, { @@ -183,7 +230,7 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "path": "{{ name.snakeCase() }}/features/{{auth_dir}}/lib/ui/components/header_builder.dart", "data": - "aW1wb3J0ICdwYWNrYWdlOmZsdXR0ZXIvbWF0ZXJpYWwuZGFydCc7CmltcG9ydCAncGFja2FnZTpsb2NhbGl6YXRpb24vbG9jYWxpemF0aW9uLmRhcnQnOwoKLy8vIEJhbm5lciBzaG93biBhYm92ZSB0aGUgc2lnbi1pbiBhbmQgcmVnaXN0ZXIgZm9ybXMuCi8vLwovLy8gRGVsaWJlcmF0ZWx5IGRyYXduIGZyb20gdGhlIHRoZW1lIHJhdGhlciB0aGFuIGFuIGltYWdlLCBzbyBhIGZyZXNoIHByb2plY3QKLy8vIGhhcyBubyBhc3NldCB0byBzaGlwIGFuZCBub3RoaW5nIHRvIGZldGNoLiBTd2FwIGl0IGZvciB5b3VyIG93biBhcnR3b3JrOgovLy8gYWRkIHRoZSBmaWxlIHVuZGVyIHRoZSBhcHAncyBgYXNzZXRzOmAgYW5kIHVzZSBgZGVzaWduX3N5c3RlbWAncyBgSGVhZGVyYAovLy8gd2l0aCBgSGVhZGVyVHlwZS5hc3NldGAuCldpZGdldCBoZWFkZXJCdWlsZGVyKEJ1aWxkQ29udGV4dCBjb250ZXh0KSB7CiAgZmluYWwgdGhlbWUgPSBUaGVtZS5vZihjb250ZXh0KTsKCiAgcmV0dXJuIFBhZGRpbmcoCiAgICBwYWRkaW5nOiBjb25zdCBFZGdlSW5zZXRzLnN5bW1ldHJpYyh2ZXJ0aWNhbDogMjQpLAogICAgY2hpbGQ6IENvbHVtbigKICAgICAgY2hpbGRyZW46IFsKICAgICAgICBDb250YWluZXIoCiAgICAgICAgICBoZWlnaHQ6IDcyLAogICAgICAgICAgd2lkdGg6IDcyLAogICAgICAgICAgZGVjb3JhdGlvbjogQm94RGVjb3JhdGlvbigKICAgICAgICAgICAgY29sb3I6IHRoZW1lLmNvbG9yU2NoZW1lLnByaW1hcnlDb250YWluZXIsCiAgICAgICAgICAgIGJvcmRlclJhZGl1czogQm9yZGVyUmFkaXVzLmNpcmN1bGFyKDIwKSwKICAgICAgICAgICksCiAgICAgICAgICBjaGlsZDogSWNvbigKICAgICAgICAgICAgSWNvbnMuYm9sdF9vdXRsaW5lZCwKICAgICAgICAgICAgc2l6ZTogNDAsCiAgICAgICAgICAgIGNvbG9yOiB0aGVtZS5jb2xvclNjaGVtZS5vblByaW1hcnlDb250YWluZXIsCiAgICAgICAgICApLAogICAgICAgICksCiAgICAgICAgY29uc3QgU2l6ZWRCb3goaGVpZ2h0OiAxNiksCiAgICAgICAgVGV4dCgKICAgICAgICAgIHN0cmluZ3MuYXBwLm5hbWUsCiAgICAgICAgICBzdHlsZTogdGhlbWUudGV4dFRoZW1lLnRpdGxlTGFyZ2U/LmNvcHlXaXRoKAogICAgICAgICAgICBmb250V2VpZ2h0OiBGb250V2VpZ2h0LmJvbGQsCiAgICAgICAgICApLAogICAgICAgICksCiAgICAgIF0sCiAgICApLAogICk7Cn0K", + "aW1wb3J0ICdwYWNrYWdlOmZsdXR0ZXIvbWF0ZXJpYWwuZGFydCc7CmltcG9ydCAncGFja2FnZTpsb2NhbGl6YXRpb24vbG9jYWxpemF0aW9uLmRhcnQnOwoKLy8vIEJhbm5lciBzaG93biBhYm92ZSB0aGUgc2lnbi1pbiBhbmQgcmVnaXN0ZXIgZm9ybXMuCi8vLwovLy8gRGVsaWJlcmF0ZWx5IGRyYXduIGZyb20gdGhlIHRoZW1lIHJhdGhlciB0aGFuIGFuIGltYWdlLCBzbyBhIGZyZXNoIHByb2plY3QKLy8vIGhhcyBubyBhc3NldCB0byBzaGlwIGFuZCBub3RoaW5nIHRvIGZldGNoLiBTd2FwIGl0IGZvciB5b3VyIG93biBhcnR3b3JrOgovLy8gYWRkIHRoZSBmaWxlIHVuZGVyIHRoZSBhcHAncyBgYXNzZXRzOmAgYW5kIHVzZSBgZGVzaWduX3N5c3RlbWAncyBgSGVhZGVyYAovLy8gd2l0aCBgSGVhZGVyVHlwZS5hc3NldGAuCldpZGdldCBoZWFkZXJCdWlsZGVyKEJ1aWxkQ29udGV4dCBjb250ZXh0KSB7CiAgZmluYWwgdGhlbWUgPSBUaGVtZS5vZihjb250ZXh0KTsKCiAgcmV0dXJuIFBhZGRpbmcoCiAgICBwYWRkaW5nOiBjb25zdCBFZGdlSW5zZXRzLnN5bW1ldHJpYyh2ZXJ0aWNhbDogMjQpLAogICAgY2hpbGQ6IEZpdHRlZEJveCgKICAgICAgZml0OiBCb3hGaXQuc2NhbGVEb3duLAogICAgICBjaGlsZDogQ29sdW1uKAogICAgICAgIG1haW5BeGlzU2l6ZTogTWFpbkF4aXNTaXplLm1pbiwKICAgICAgICBjaGlsZHJlbjogWwogICAgICAgICAgQ29udGFpbmVyKAogICAgICAgICAgICBoZWlnaHQ6IDcyLAogICAgICAgICAgICB3aWR0aDogNzIsCiAgICAgICAgICAgIGRlY29yYXRpb246IEJveERlY29yYXRpb24oCiAgICAgICAgICAgICAgY29sb3I6IHRoZW1lLmNvbG9yU2NoZW1lLnByaW1hcnlDb250YWluZXIsCiAgICAgICAgICAgICAgYm9yZGVyUmFkaXVzOiBCb3JkZXJSYWRpdXMuY2lyY3VsYXIoMjApLAogICAgICAgICAgICApLAogICAgICAgICAgICBjaGlsZDogSWNvbigKICAgICAgICAgICAgICBJY29ucy5ib2x0X291dGxpbmVkLAogICAgICAgICAgICAgIHNpemU6IDQwLAogICAgICAgICAgICAgIGNvbG9yOiB0aGVtZS5jb2xvclNjaGVtZS5vblByaW1hcnlDb250YWluZXIsCiAgICAgICAgICAgICksCiAgICAgICAgICApLAogICAgICAgICAgY29uc3QgU2l6ZWRCb3goaGVpZ2h0OiAxNiksCiAgICAgICAgICBUZXh0KAogICAgICAgICAgICBzdHJpbmdzLmFwcC5uYW1lLAogICAgICAgICAgICBzdHlsZTogdGhlbWUudGV4dFRoZW1lLnRpdGxlTGFyZ2U/LmNvcHlXaXRoKAogICAgICAgICAgICAgIGZvbnRXZWlnaHQ6IEZvbnRXZWlnaHQuYm9sZCwKICAgICAgICAgICAgKSwKICAgICAgICAgICksCiAgICAgICAgXSwKICAgICAgKSwKICAgICksCiAgKTsKfQo=", "type": "text" }, { @@ -204,20 +251,20 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "path": "{{ name.snakeCase() }}/features/{{auth_dir}}/lib/ui/screens/register_screen.dart", "data": - "aW1wb3J0ICdwYWNrYWdlOmF1dGgvYW5hbHl0aWNzL2FuYWx5dGljcy5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmF1dGgvdWkvY29tcG9uZW50cy9mb290ZXJfYnVpbGRlci5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmF1dGgvdWkvY29tcG9uZW50cy9oZWFkZXJfYnVpbGRlci5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmNvcmUvbG9nZ2VyL2xvZ2dlci5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZmlyZWJhc2VfdWlfYXV0aC9maXJlYmFzZV91aV9hdXRoLmRhcnQnIGFzIHVpX2F1dGg7CmltcG9ydCAncGFja2FnZTpmbHV0dGVyL21hdGVyaWFsLmRhcnQnOwoKY2xhc3MgUmVnaXN0ZXJTY3JlZW4gZXh0ZW5kcyBTdGF0ZWxlc3NXaWRnZXQgewogIGNvbnN0IFJlZ2lzdGVyU2NyZWVuKHtzdXBlci5rZXksIHJlcXVpcmVkIHRoaXMub25TaWduZWRVcH0pOwoKICBmaW5hbCB2b2lkIEZ1bmN0aW9uKEJ1aWxkQ29udGV4dCBjb250ZXh0KSBvblNpZ25lZFVwOwoKICBAb3ZlcnJpZGUKICBXaWRnZXQgYnVpbGQoQnVpbGRDb250ZXh0IGNvbnRleHQpIHsKICAgIGZpbmFsIGxvZ2dlciA9IGRpLmdldDxMb2dnZXI+KCk7CgogICAgcmV0dXJuIHVpX2F1dGguUmVnaXN0ZXJTY3JlZW4oCiAgICAgIHNob3dBdXRoQWN0aW9uU3dpdGNoOiBmYWxzZSwKICAgICAgYWN0aW9uczogWwogICAgICAgIHVpX2F1dGguQXV0aFN0YXRlQ2hhbmdlQWN0aW9uPHVpX2F1dGguU2lnbmVkSW4+KChjb250ZXh0LCBzdGF0ZSkgYXN5bmMgewogICAgICAgICAgbG9nZ2VyLmQoJ1VzZXIgcmVnaXN0ZXJlZCBzdWNjZXNzZnVsbHk6ICR7c3RhdGUudXNlcj8uZW1haWx9Jyk7CgogICAgICAgICAgZmluYWwgbWV0aG9kID0gQXV0aEFuYWx5dGljcy5nZXRBdXRoTWV0aG9kKHN0YXRlLnVzZXI/LnByb3ZpZGVyRGF0YSk7CgogICAgICAgICAgLy8gTG9nIHN1Y2Nlc3NmdWwgc2lnbiBpbiAod2hlbiB1c2VyIGFscmVhZHkgZXhpc3RzKQogICAgICAgICAgQXV0aEFuYWx5dGljcy5sb2dTaWduSW5TdWNjZXNzKAogICAgICAgICAgICBtZXRob2Q6IG1ldGhvZCwKICAgICAgICAgICAgdXNlckVtYWlsOiBzdGF0ZS51c2VyPy5lbWFpbCwKICAgICAgICAgICk7CgogICAgICAgICAgb25TaWduZWRVcChjb250ZXh0KTsKICAgICAgICB9KSwKICAgICAgICB1aV9hdXRoLkF1dGhTdGF0ZUNoYW5nZUFjdGlvbjx1aV9hdXRoLlVzZXJDcmVhdGVkPigoCiAgICAgICAgICBjb250ZXh0LAogICAgICAgICAgc3RhdGUsCiAgICAgICAgKSBhc3luYyB7CiAgICAgICAgICBsb2dnZXIuZCgKICAgICAgICAgICAgJ1VzZXIgY3JlYXRlZCBzdWNjZXNzZnVsbHk6ICR7c3RhdGUuY3JlZGVudGlhbC51c2VyPy5lbWFpbH0nLAogICAgICAgICAgKTsKCiAgICAgICAgICBmaW5hbCBtZXRob2QgPSBBdXRoQW5hbHl0aWNzLmdldEF1dGhNZXRob2QoCiAgICAgICAgICAgIHN0YXRlLmNyZWRlbnRpYWwudXNlcj8ucHJvdmlkZXJEYXRhLAogICAgICAgICAgKTsKCiAgICAgICAgICAvLyBMb2cgc3VjY2Vzc2Z1bCBzaWduIHVwCiAgICAgICAgICBBdXRoQW5hbHl0aWNzLmxvZ1NpZ25VcFN1Y2Nlc3MoCiAgICAgICAgICAgIG1ldGhvZDogbWV0aG9kLAogICAgICAgICAgICB1c2VyRW1haWw6IHN0YXRlLmNyZWRlbnRpYWwudXNlcj8uZW1haWwsCiAgICAgICAgICApOwoKICAgICAgICAgIC8vIExvZyB1c2VyIGNyZWF0aW9uIHN1Y2Nlc3MKICAgICAgICAgIEF1dGhBbmFseXRpY3MubG9nVXNlckNyZWF0aW9uU3VjY2VzcygKICAgICAgICAgICAgbWV0aG9kOiBtZXRob2QsCiAgICAgICAgICAgIHVzZXJFbWFpbDogc3RhdGUuY3JlZGVudGlhbC51c2VyPy5lbWFpbCwKICAgICAgICAgICk7CgogICAgICAgICAgb25TaWduZWRVcChjb250ZXh0KTsKICAgICAgICB9KSwKICAgICAgICB1aV9hdXRoLkF1dGhTdGF0ZUNoYW5nZUFjdGlvbjx1aV9hdXRoLkF1dGhGYWlsZWQ+KCgKICAgICAgICAgIGNvbnRleHQsCiAgICAgICAgICBzdGF0ZSwKICAgICAgICApIGFzeW5jIHsKICAgICAgICAgIGxvZ2dlci5lKCdSZWdpc3RyYXRpb24gZmFpbGVkOiAke3N0YXRlLmV4Y2VwdGlvbn0nKTsKCiAgICAgICAgICAvLyBMb2cgYXV0aCBlcnJvcgogICAgICAgICAgQXV0aEFuYWx5dGljcy5sb2dBdXRoRXJyb3IoCiAgICAgICAgICAgIGVycm9yVHlwZTogc3RhdGUuZXhjZXB0aW9uLnJ1bnRpbWVUeXBlLnRvU3RyaW5nKCksCiAgICAgICAgICAgIGZsb3dUeXBlOiAnc2lnbl91cCcsCiAgICAgICAgICAgIGVycm9yTWVzc2FnZTogc3RhdGUuZXhjZXB0aW9uLnRvU3RyaW5nKCksCiAgICAgICAgICAgIG1ldGhvZDogJ2VtYWlsJywKICAgICAgICAgICk7CiAgICAgICAgfSksCiAgICAgIF0sCiAgICAgIGZvb3RlckJ1aWxkZXI6IChjb250ZXh0LCBhY3Rpb24pIHsKICAgICAgICByZXR1cm4gZm9vdGVyQnVpbGRlcihjb250ZXh0LCBhY3Rpb24sIEZvb3RlclR5cGUucmVnaXN0ZXIpOwogICAgICB9LAogICAgICBoZWFkZXJCdWlsZGVyOiAoY29udGV4dCwgY29uc3RyYWludHMsIHNocmlua09mZnNldCkgewogICAgICAgIHJldHVybiBoZWFkZXJCdWlsZGVyKGNvbnRleHQpOwogICAgICB9LAogICAgKTsKICB9Cn0K", + "aW1wb3J0ICdwYWNrYWdlOmF1dGgvYW5hbHl0aWNzL2FuYWx5dGljcy5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmF1dGgvdWkvY29tcG9uZW50cy9mb290ZXJfYnVpbGRlci5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmF1dGgvdWkvY29tcG9uZW50cy9oZWFkZXJfYnVpbGRlci5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmNvcmUvbG9nZ2VyL2xvZ2dlci5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZmlyZWJhc2VfdWlfYXV0aC9maXJlYmFzZV91aV9hdXRoLmRhcnQnIGFzIHVpX2F1dGg7CmltcG9ydCAncGFja2FnZTpmbHV0dGVyL21hdGVyaWFsLmRhcnQnOwoKY2xhc3MgUmVnaXN0ZXJTY3JlZW4gZXh0ZW5kcyBTdGF0ZWxlc3NXaWRnZXQgewogIGNvbnN0IFJlZ2lzdGVyU2NyZWVuKHtzdXBlci5rZXksIHJlcXVpcmVkIHRoaXMub25TaWduZWRVcH0pOwoKICBmaW5hbCB2b2lkIEZ1bmN0aW9uKEJ1aWxkQ29udGV4dCBjb250ZXh0KSBvblNpZ25lZFVwOwoKICBAb3ZlcnJpZGUKICBXaWRnZXQgYnVpbGQoQnVpbGRDb250ZXh0IGNvbnRleHQpIHsKICAgIGZpbmFsIGxvZ2dlciA9IGRpLmdldDxMb2dnZXI+KCk7CgogICAgcmV0dXJuIHVpX2F1dGguUmVnaXN0ZXJTY3JlZW4oCiAgICAgIHNob3dBdXRoQWN0aW9uU3dpdGNoOiBmYWxzZSwKICAgICAgYWN0aW9uczogWwogICAgICAgIHVpX2F1dGguQXV0aFN0YXRlQ2hhbmdlQWN0aW9uPHVpX2F1dGguU2lnbmVkSW4+KChjb250ZXh0LCBzdGF0ZSkgYXN5bmMgewogICAgICAgICAgbG9nZ2VyLmQoJ1VzZXIgcmVnaXN0ZXJlZCBzdWNjZXNzZnVsbHknKTsKCiAgICAgICAgICBmaW5hbCBtZXRob2QgPSBBdXRoQW5hbHl0aWNzLmdldEF1dGhNZXRob2Qoc3RhdGUudXNlcj8ucHJvdmlkZXJEYXRhKTsKCiAgICAgICAgICAvLyBMb2cgc3VjY2Vzc2Z1bCBzaWduIGluICh3aGVuIHVzZXIgYWxyZWFkeSBleGlzdHMpCiAgICAgICAgICBBdXRoQW5hbHl0aWNzLmxvZ1NpZ25JblN1Y2Nlc3MoCiAgICAgICAgICAgIG1ldGhvZDogbWV0aG9kLAogICAgICAgICAgICB1c2VyRW1haWw6IHN0YXRlLnVzZXI/LmVtYWlsLAogICAgICAgICAgKTsKCiAgICAgICAgICBvblNpZ25lZFVwKGNvbnRleHQpOwogICAgICAgIH0pLAogICAgICAgIHVpX2F1dGguQXV0aFN0YXRlQ2hhbmdlQWN0aW9uPHVpX2F1dGguVXNlckNyZWF0ZWQ+KCgKICAgICAgICAgIGNvbnRleHQsCiAgICAgICAgICBzdGF0ZSwKICAgICAgICApIGFzeW5jIHsKICAgICAgICAgIGxvZ2dlci5kKCdVc2VyIGNyZWF0ZWQgc3VjY2Vzc2Z1bGx5Jyk7CgogICAgICAgICAgZmluYWwgbWV0aG9kID0gQXV0aEFuYWx5dGljcy5nZXRBdXRoTWV0aG9kKAogICAgICAgICAgICBzdGF0ZS5jcmVkZW50aWFsLnVzZXI/LnByb3ZpZGVyRGF0YSwKICAgICAgICAgICk7CgogICAgICAgICAgLy8gTG9nIHN1Y2Nlc3NmdWwgc2lnbiB1cAogICAgICAgICAgQXV0aEFuYWx5dGljcy5sb2dTaWduVXBTdWNjZXNzKAogICAgICAgICAgICBtZXRob2Q6IG1ldGhvZCwKICAgICAgICAgICAgdXNlckVtYWlsOiBzdGF0ZS5jcmVkZW50aWFsLnVzZXI/LmVtYWlsLAogICAgICAgICAgKTsKCiAgICAgICAgICAvLyBMb2cgdXNlciBjcmVhdGlvbiBzdWNjZXNzCiAgICAgICAgICBBdXRoQW5hbHl0aWNzLmxvZ1VzZXJDcmVhdGlvblN1Y2Nlc3MoCiAgICAgICAgICAgIG1ldGhvZDogbWV0aG9kLAogICAgICAgICAgICB1c2VyRW1haWw6IHN0YXRlLmNyZWRlbnRpYWwudXNlcj8uZW1haWwsCiAgICAgICAgICApOwoKICAgICAgICAgIG9uU2lnbmVkVXAoY29udGV4dCk7CiAgICAgICAgfSksCiAgICAgICAgdWlfYXV0aC5BdXRoU3RhdGVDaGFuZ2VBY3Rpb248dWlfYXV0aC5BdXRoRmFpbGVkPigoCiAgICAgICAgICBjb250ZXh0LAogICAgICAgICAgc3RhdGUsCiAgICAgICAgKSBhc3luYyB7CiAgICAgICAgICBsb2dnZXIuZSgnUmVnaXN0cmF0aW9uIGZhaWxlZDogJHtzdGF0ZS5leGNlcHRpb259Jyk7CgogICAgICAgICAgLy8gTG9nIGF1dGggZXJyb3IKICAgICAgICAgIEF1dGhBbmFseXRpY3MubG9nQXV0aEVycm9yKAogICAgICAgICAgICBlcnJvclR5cGU6IHN0YXRlLmV4Y2VwdGlvbi5ydW50aW1lVHlwZS50b1N0cmluZygpLAogICAgICAgICAgICBmbG93VHlwZTogJ3NpZ25fdXAnLAogICAgICAgICAgICBlcnJvck1lc3NhZ2U6IHN0YXRlLmV4Y2VwdGlvbi50b1N0cmluZygpLAogICAgICAgICAgICBtZXRob2Q6ICdlbWFpbCcsCiAgICAgICAgICApOwogICAgICAgIH0pLAogICAgICBdLAogICAgICBmb290ZXJCdWlsZGVyOiAoY29udGV4dCwgYWN0aW9uKSB7CiAgICAgICAgcmV0dXJuIGZvb3RlckJ1aWxkZXIoY29udGV4dCwgYWN0aW9uLCBGb290ZXJUeXBlLnJlZ2lzdGVyKTsKICAgICAgfSwKICAgICAgaGVhZGVyQnVpbGRlcjogKGNvbnRleHQsIGNvbnN0cmFpbnRzLCBzaHJpbmtPZmZzZXQpIHsKICAgICAgICByZXR1cm4gaGVhZGVyQnVpbGRlcihjb250ZXh0KTsKICAgICAgfSwKICAgICk7CiAgfQp9Cg==", "type": "text" }, { "path": "{{ name.snakeCase() }}/features/{{auth_dir}}/lib/ui/screens/sign_in_screen.dart", "data": - "aW1wb3J0ICdwYWNrYWdlOmF1dGgvYW5hbHl0aWNzL2FuYWx5dGljcy5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmF1dGgvY29uc3RhbnRzL2luZGV4LmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6YXV0aC91aS9jb21wb25lbnRzL2Zvb3Rlcl9idWlsZGVyLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6YXV0aC91aS9jb21wb25lbnRzL2hlYWRlcl9idWlsZGVyLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Y29yZS9jb3JlLmRhcnQnIGFzIGNvcmU7CmltcG9ydCAncGFja2FnZTpjb3JlL2xvZ2dlci9sb2dnZXIuZGFydCc7CmltcG9ydCAncGFja2FnZTpkZXNpZ25fc3lzdGVtL3RvYXN0L3RvYXN0cy5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZmlyZWJhc2VfdWlfYXV0aC9maXJlYmFzZV91aV9hdXRoLmRhcnQnIGFzIHVpX2F1dGg7CmltcG9ydCAncGFja2FnZTpmbHV0dGVyL21hdGVyaWFsLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Z29fcm91dGVyL2dvX3JvdXRlci5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmxvY2FsaXphdGlvbi9sb2NhbGl6YXRpb24uZGFydCc7CgpjbGFzcyBTaWduSW5TY3JlZW4gZXh0ZW5kcyBTdGF0ZWxlc3NXaWRnZXQgewogIGNvbnN0IFNpZ25JblNjcmVlbih7c3VwZXIua2V5LCByZXF1aXJlZCB0aGlzLm9uU2lnbmVkSW59KTsKCiAgZmluYWwgRnVuY3Rpb24oQnVpbGRDb250ZXh0IGNvbnRleHQpIG9uU2lnbmVkSW47CgogIEBvdmVycmlkZQogIFdpZGdldCBidWlsZChCdWlsZENvbnRleHQgY29udGV4dCkgewogICAgZmluYWwgbG9nZ2VyID0gZGkuZ2V0PExvZ2dlcj4oKTsKCiAgICByZXR1cm4gdWlfYXV0aC5TaWduSW5TY3JlZW4oCiAgICAgIHNob3dBdXRoQWN0aW9uU3dpdGNoOiBmYWxzZSwKICAgICAgb2F1dGhCdXR0b25WYXJpYW50OiB1aV9hdXRoLk9BdXRoQnV0dG9uVmFyaWFudC5pY29uX2FuZF90ZXh0LAogICAgICBhY3Rpb25zOiBbCiAgICAgICAgdWlfYXV0aC5Gb3Jnb3RQYXNzd29yZEFjdGlvbigoY29udGV4dCwgZW1haWwpIHsKICAgICAgICAgIGxvZ2dlci5kKCdOYXZpZ2F0aW5nIHRvIGZvcmdvdCBwYXNzd29yZCBzY3JlZW4gZm9yIGVtYWlsOiAkZW1haWwnKTsKCiAgICAgICAgICBmaW5hbCB1cmkgPSBVcmkoCiAgICAgICAgICAgIHBhdGg6IEF1dGhSb3V0ZXMuZm9yZ290UGFzc3dvcmQsCiAgICAgICAgICAgIHF1ZXJ5UGFyYW1ldGVyczoge2NvcmUuS2V5cy5lbWFpbDogZW1haWx9LAogICAgICAgICAgKTsKICAgICAgICAgIGNvbnRleHQucHVzaCh1cmkudG9TdHJpbmcoKSk7CiAgICAgICAgfSksCiAgICAgICAgdWlfYXV0aC5BdXRoU3RhdGVDaGFuZ2VBY3Rpb248dWlfYXV0aC5TaWduZWRJbj4oKGNvbnRleHQsIHN0YXRlKSBhc3luYyB7CiAgICAgICAgICBsb2dnZXIuZCgnVXNlciBzaWduZWQgaW4gc3VjY2Vzc2Z1bGx5OiAke3N0YXRlLnVzZXI/LmVtYWlsfScpOwoKICAgICAgICAgIGZpbmFsIG1ldGhvZCA9IEF1dGhBbmFseXRpY3MuZ2V0QXV0aE1ldGhvZChzdGF0ZS51c2VyPy5wcm92aWRlckRhdGEpOwoKICAgICAgICAgIC8vIExvZyBzdWNjZXNzZnVsIHNpZ24gaW4KICAgICAgICAgIEF1dGhBbmFseXRpY3MubG9nU2lnbkluU3VjY2VzcygKICAgICAgICAgICAgbWV0aG9kOiBtZXRob2QsCiAgICAgICAgICAgIHVzZXJFbWFpbDogc3RhdGUudXNlcj8uZW1haWwsCiAgICAgICAgICApOwoKICAgICAgICAgIG9uU2lnbmVkSW4oY29udGV4dCk7CiAgICAgICAgfSksCiAgICAgICAgdWlfYXV0aC5BdXRoU3RhdGVDaGFuZ2VBY3Rpb248dWlfYXV0aC5Vc2VyQ3JlYXRlZD4oKAogICAgICAgICAgY29udGV4dCwKICAgICAgICAgIHN0YXRlLAogICAgICAgICkgYXN5bmMgewogICAgICAgICAgbG9nZ2VyLmQoCiAgICAgICAgICAgICdVc2VyIHNpZ25lZCBpbiBzdWNjZXNzZnVsbHk6ICR7c3RhdGUuY3JlZGVudGlhbC51c2VyPy5lbWFpbH0nLAogICAgICAgICAgKTsKCiAgICAgICAgICBmaW5hbCBtZXRob2QgPSBBdXRoQW5hbHl0aWNzLmdldEF1dGhNZXRob2QoCiAgICAgICAgICAgIHN0YXRlLmNyZWRlbnRpYWwudXNlcj8ucHJvdmlkZXJEYXRhLAogICAgICAgICAgKTsKCiAgICAgICAgICAvLyBMb2cgc3VjY2Vzc2Z1bCB1c2VyIGNyZWF0aW9uIChmcm9tIHNpZ24gaW4gc2NyZWVuKQogICAgICAgICAgQXV0aEFuYWx5dGljcy5sb2dVc2VyQ3JlYXRpb25TdWNjZXNzKAogICAgICAgICAgICBtZXRob2Q6IG1ldGhvZCwKICAgICAgICAgICAgdXNlckVtYWlsOiBzdGF0ZS5jcmVkZW50aWFsLnVzZXI/LmVtYWlsLAogICAgICAgICAgKTsKCiAgICAgICAgICBvblNpZ25lZEluKGNvbnRleHQpOwogICAgICAgIH0pLAogICAgICAgIHVpX2F1dGguQXV0aFN0YXRlQ2hhbmdlQWN0aW9uPHVpX2F1dGguQXV0aEZhaWxlZD4oKAogICAgICAgICAgY29udGV4dCwKICAgICAgICAgIHN0YXRlLAogICAgICAgICkgYXN5bmMgewogICAgICAgICAgbG9nZ2VyLmUoJ1NpZ24taW4gZmFpbGVkOiAke3N0YXRlLmV4Y2VwdGlvbn0nKTsKCiAgICAgICAgICAvLyBMb2cgYXV0aCBlcnJvcgogICAgICAgICAgQXV0aEFuYWx5dGljcy5sb2dBdXRoRXJyb3IoCiAgICAgICAgICAgIGVycm9yVHlwZTogc3RhdGUuZXhjZXB0aW9uLnJ1bnRpbWVUeXBlLnRvU3RyaW5nKCksCiAgICAgICAgICAgIGZsb3dUeXBlOiAnc2lnbl9pbicsCiAgICAgICAgICAgIGVycm9yTWVzc2FnZTogc3RhdGUuZXhjZXB0aW9uLnRvU3RyaW5nKCksCiAgICAgICAgICApOwoKICAgICAgICAgIFRvYXN0LmVycm9yKGNvbnRleHQsIG1lc3NhZ2U6IHN0cmluZ3MuZXJyb3JzLmRlZmF1bHRfZXJyb3JfbWVzc2FnZSk7CiAgICAgICAgfSksCiAgICAgICAgLy9UT0RPOiBIYW5kbGUgb3RoZXIgQXV0aFN0YXRlCiAgICAgIF0sCiAgICAgIGZvb3RlckJ1aWxkZXI6IChjb250ZXh0LCBhY3Rpb24pIHsKICAgICAgICByZXR1cm4gZm9vdGVyQnVpbGRlcihjb250ZXh0LCBhY3Rpb24sIEZvb3RlclR5cGUuc2lnbkluKTsKICAgICAgfSwKICAgICAgaGVhZGVyQnVpbGRlcjogKGNvbnRleHQsIGNvbnN0cmFpbnRzLCBzaHJpbmtPZmZzZXQpIHsKICAgICAgICByZXR1cm4gaGVhZGVyQnVpbGRlcihjb250ZXh0KTsKICAgICAgfSwKICAgICk7CiAgfQp9Cg==", + "aW1wb3J0ICdwYWNrYWdlOmF1dGgvYW5hbHl0aWNzL2FuYWx5dGljcy5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmF1dGgvY29uc3RhbnRzL2luZGV4LmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6YXV0aC91aS9jb21wb25lbnRzL2Zvb3Rlcl9idWlsZGVyLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6YXV0aC91aS9jb21wb25lbnRzL2hlYWRlcl9idWlsZGVyLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Y29yZS9jb3JlLmRhcnQnIGFzIGNvcmU7CmltcG9ydCAncGFja2FnZTpjb3JlL2xvZ2dlci9sb2dnZXIuZGFydCc7CmltcG9ydCAncGFja2FnZTpkZXNpZ25fc3lzdGVtL3RvYXN0L3RvYXN0cy5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZmlyZWJhc2VfdWlfYXV0aC9maXJlYmFzZV91aV9hdXRoLmRhcnQnIGFzIHVpX2F1dGg7CmltcG9ydCAncGFja2FnZTpmbHV0dGVyL21hdGVyaWFsLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Z29fcm91dGVyL2dvX3JvdXRlci5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmxvY2FsaXphdGlvbi9sb2NhbGl6YXRpb24uZGFydCc7CgpjbGFzcyBTaWduSW5TY3JlZW4gZXh0ZW5kcyBTdGF0ZWxlc3NXaWRnZXQgewogIGNvbnN0IFNpZ25JblNjcmVlbih7c3VwZXIua2V5LCByZXF1aXJlZCB0aGlzLm9uU2lnbmVkSW59KTsKCiAgZmluYWwgRnVuY3Rpb24oQnVpbGRDb250ZXh0IGNvbnRleHQpIG9uU2lnbmVkSW47CgogIEBvdmVycmlkZQogIFdpZGdldCBidWlsZChCdWlsZENvbnRleHQgY29udGV4dCkgewogICAgZmluYWwgbG9nZ2VyID0gZGkuZ2V0PExvZ2dlcj4oKTsKCiAgICByZXR1cm4gdWlfYXV0aC5TaWduSW5TY3JlZW4oCiAgICAgIHNob3dBdXRoQWN0aW9uU3dpdGNoOiBmYWxzZSwKICAgICAgb2F1dGhCdXR0b25WYXJpYW50OiB1aV9hdXRoLk9BdXRoQnV0dG9uVmFyaWFudC5pY29uX2FuZF90ZXh0LAogICAgICBhY3Rpb25zOiBbCiAgICAgICAgdWlfYXV0aC5Gb3Jnb3RQYXNzd29yZEFjdGlvbigoY29udGV4dCwgZW1haWwpIHsKICAgICAgICAgIGxvZ2dlci5kKCdOYXZpZ2F0aW5nIHRvIGZvcmdvdCBwYXNzd29yZCBzY3JlZW4nKTsKCiAgICAgICAgICBmaW5hbCB1cmkgPSBVcmkoCiAgICAgICAgICAgIHBhdGg6IEF1dGhSb3V0ZXMuZm9yZ290UGFzc3dvcmQsCiAgICAgICAgICAgIHF1ZXJ5UGFyYW1ldGVyczoge2NvcmUuS2V5cy5lbWFpbDogZW1haWx9LAogICAgICAgICAgKTsKICAgICAgICAgIGNvbnRleHQucHVzaCh1cmkudG9TdHJpbmcoKSk7CiAgICAgICAgfSksCiAgICAgICAgdWlfYXV0aC5BdXRoU3RhdGVDaGFuZ2VBY3Rpb248dWlfYXV0aC5TaWduZWRJbj4oKGNvbnRleHQsIHN0YXRlKSBhc3luYyB7CiAgICAgICAgICBsb2dnZXIuZCgnVXNlciBzaWduZWQgaW4gc3VjY2Vzc2Z1bGx5Jyk7CgogICAgICAgICAgZmluYWwgbWV0aG9kID0gQXV0aEFuYWx5dGljcy5nZXRBdXRoTWV0aG9kKHN0YXRlLnVzZXI/LnByb3ZpZGVyRGF0YSk7CgogICAgICAgICAgLy8gTG9nIHN1Y2Nlc3NmdWwgc2lnbiBpbgogICAgICAgICAgQXV0aEFuYWx5dGljcy5sb2dTaWduSW5TdWNjZXNzKAogICAgICAgICAgICBtZXRob2Q6IG1ldGhvZCwKICAgICAgICAgICAgdXNlckVtYWlsOiBzdGF0ZS51c2VyPy5lbWFpbCwKICAgICAgICAgICk7CgogICAgICAgICAgb25TaWduZWRJbihjb250ZXh0KTsKICAgICAgICB9KSwKICAgICAgICB1aV9hdXRoLkF1dGhTdGF0ZUNoYW5nZUFjdGlvbjx1aV9hdXRoLlVzZXJDcmVhdGVkPigoCiAgICAgICAgICBjb250ZXh0LAogICAgICAgICAgc3RhdGUsCiAgICAgICAgKSBhc3luYyB7CiAgICAgICAgICBsb2dnZXIuZCgnVXNlciBzaWduZWQgaW4gc3VjY2Vzc2Z1bGx5Jyk7CgogICAgICAgICAgZmluYWwgbWV0aG9kID0gQXV0aEFuYWx5dGljcy5nZXRBdXRoTWV0aG9kKAogICAgICAgICAgICBzdGF0ZS5jcmVkZW50aWFsLnVzZXI/LnByb3ZpZGVyRGF0YSwKICAgICAgICAgICk7CgogICAgICAgICAgLy8gTG9nIHN1Y2Nlc3NmdWwgdXNlciBjcmVhdGlvbiAoZnJvbSBzaWduIGluIHNjcmVlbikKICAgICAgICAgIEF1dGhBbmFseXRpY3MubG9nVXNlckNyZWF0aW9uU3VjY2VzcygKICAgICAgICAgICAgbWV0aG9kOiBtZXRob2QsCiAgICAgICAgICAgIHVzZXJFbWFpbDogc3RhdGUuY3JlZGVudGlhbC51c2VyPy5lbWFpbCwKICAgICAgICAgICk7CgogICAgICAgICAgb25TaWduZWRJbihjb250ZXh0KTsKICAgICAgICB9KSwKICAgICAgICB1aV9hdXRoLkF1dGhTdGF0ZUNoYW5nZUFjdGlvbjx1aV9hdXRoLkF1dGhGYWlsZWQ+KCgKICAgICAgICAgIGNvbnRleHQsCiAgICAgICAgICBzdGF0ZSwKICAgICAgICApIGFzeW5jIHsKICAgICAgICAgIGxvZ2dlci5lKCdTaWduLWluIGZhaWxlZDogJHtzdGF0ZS5leGNlcHRpb259Jyk7CgogICAgICAgICAgLy8gTG9nIGF1dGggZXJyb3IKICAgICAgICAgIEF1dGhBbmFseXRpY3MubG9nQXV0aEVycm9yKAogICAgICAgICAgICBlcnJvclR5cGU6IHN0YXRlLmV4Y2VwdGlvbi5ydW50aW1lVHlwZS50b1N0cmluZygpLAogICAgICAgICAgICBmbG93VHlwZTogJ3NpZ25faW4nLAogICAgICAgICAgICBlcnJvck1lc3NhZ2U6IHN0YXRlLmV4Y2VwdGlvbi50b1N0cmluZygpLAogICAgICAgICAgKTsKCiAgICAgICAgICBUb2FzdC5lcnJvcihjb250ZXh0LCBtZXNzYWdlOiBzdHJpbmdzLmVycm9ycy5kZWZhdWx0X2Vycm9yX21lc3NhZ2UpOwogICAgICAgIH0pLAogICAgICAgIC8vVE9ETzogSGFuZGxlIG90aGVyIEF1dGhTdGF0ZQogICAgICBdLAogICAgICBmb290ZXJCdWlsZGVyOiAoY29udGV4dCwgYWN0aW9uKSB7CiAgICAgICAgcmV0dXJuIGZvb3RlckJ1aWxkZXIoY29udGV4dCwgYWN0aW9uLCBGb290ZXJUeXBlLnNpZ25Jbik7CiAgICAgIH0sCiAgICAgIGhlYWRlckJ1aWxkZXI6IChjb250ZXh0LCBjb25zdHJhaW50cywgc2hyaW5rT2Zmc2V0KSB7CiAgICAgICAgcmV0dXJuIGhlYWRlckJ1aWxkZXIoY29udGV4dCk7CiAgICAgIH0sCiAgICApOwogIH0KfQo=", "type": "text" }, { "path": "{{ name.snakeCase() }}/features/{{auth_dir}}/pubspec.yaml", "data": - "bmFtZTogYXV0aApkZXNjcmlwdGlvbjogIkZpcmViYXNlIEF1dGhlbnRpY2F0aW9uIChlbWFpbCwgR29vZ2xlLCBBcHBsZSkgd2l0aCBnb19yb3V0ZXIgaW50ZWdyYXRpb24gZm9yIHt7bmFtZS50aXRsZUNhc2UoKX19LiIKdmVyc2lvbjogMC4xLjAKcHVibGlzaF90bzogJ25vbmUnCgplbnZpcm9ubWVudDoKICBzZGs6IF4zLjguMAogIGZsdXR0ZXI6ICI+PTMuMjkuMCIKCmRlcGVuZGVuY2llczoKICBmbHV0dGVyOgogICAgc2RrOiBmbHV0dGVyCiAgZXF1YXRhYmxlOiBeMi4wLjcKICBmaXJlYmFzZV9hdXRoOiBeNS42LjAKICBmaXJlYmFzZV9jb3JlOiBeMy4xNC4wCiAgZmlyZWJhc2VfdWlfYXV0aDogXjEuMTcuMAogIGZpcmViYXNlX3VpX29hdXRoX2FwcGxlOiBeMS4zLjIKICBmaXJlYmFzZV91aV9vYXV0aF9nb29nbGU6IF4xLjQuMgogIGdvX3JvdXRlcjogXjE1LjEuMwogIGpzb25fYW5ub3RhdGlvbjogXjQuOS4wCiAgY29yZToKICAgIHBhdGg6IC4uLy4uL3BhY2thZ2VzL2NvcmUKICBkZXNpZ25fc3lzdGVtOgogICAgcGF0aDogLi4vLi4vcGFja2FnZXMvZGVzaWduX3N5c3RlbQogIGRpOgogICAgcGF0aDogLi4vLi4vcGFja2FnZXMvZGkKICBsb2NhbGl6YXRpb246CiAgICBwYXRoOiAuLi8uLi9wYWNrYWdlcy9sb2NhbGl6YXRpb24Ke3sjZmlyZXN0b3JlfX0gIGNsb3VkX2ZpcmVzdG9yZTogXjUuNi4wCnt7L2ZpcmVzdG9yZX19e3sjbmV0d29ya319ICBuZXR3b3JrOgogICAgcGF0aDogLi4vLi4vcGFja2FnZXMvbmV0d29yawp7ey9uZXR3b3JrfX17eyNhbmFseXRpY3N9fSAgYW5hbHl0aWNzOgogICAgcGF0aDogLi4vLi4vcGFja2FnZXMvYW5hbHl0aWNzCnt7L2FuYWx5dGljc319CmRldl9kZXBlbmRlbmNpZXM6CiAgZmx1dHRlcl90ZXN0OgogICAgc2RrOiBmbHV0dGVyCiAgZmx1dHRlcl9saW50czogXjUuMC4wCgpmbHV0dGVyOgo=", + "bmFtZTogYXV0aApkZXNjcmlwdGlvbjogIkZpcmViYXNlIEF1dGhlbnRpY2F0aW9uIChlbWFpbCwgR29vZ2xlLCBBcHBsZSkgd2l0aCBnb19yb3V0ZXIgaW50ZWdyYXRpb24gZm9yIHt7bmFtZS50aXRsZUNhc2UoKX19LiIKdmVyc2lvbjogMC4xLjAKcHVibGlzaF90bzogJ25vbmUnCgplbnZpcm9ubWVudDoKICBzZGs6IF4zLjguMAogIGZsdXR0ZXI6ICI+PTMuMjkuMCIKCmRlcGVuZGVuY2llczoKICBmbHV0dGVyOgogICAgc2RrOiBmbHV0dGVyCiAgZXF1YXRhYmxlOiBeMi4wLjcKICBmaXJlYmFzZV9hdXRoOiBeNS42LjAKICBmaXJlYmFzZV9jb3JlOiBeMy4xNC4wCiAgZmlyZWJhc2VfdWlfYXV0aDogXjEuMTcuMAogIGZpcmViYXNlX3VpX29hdXRoX2FwcGxlOiBeMS4zLjIKICBmaXJlYmFzZV91aV9vYXV0aF9nb29nbGU6IF4xLjQuMgogIGdvX3JvdXRlcjogXjE1LjEuMwogIGpzb25fYW5ub3RhdGlvbjogXjQuOS4wCiAgY29yZToKICAgIHBhdGg6IC4uLy4uL3BhY2thZ2VzL2NvcmUKICBkZXNpZ25fc3lzdGVtOgogICAgcGF0aDogLi4vLi4vcGFja2FnZXMvZGVzaWduX3N5c3RlbQogIGRpOgogICAgcGF0aDogLi4vLi4vcGFja2FnZXMvZGkKICBsb2NhbGl6YXRpb246CiAgICBwYXRoOiAuLi8uLi9wYWNrYWdlcy9sb2NhbGl6YXRpb24Ke3sjZmlyZXN0b3JlfX0gIGNsb3VkX2ZpcmVzdG9yZTogXjUuNi4wCnt7L2ZpcmVzdG9yZX19e3sjbmV0d29ya319ICBuZXR3b3JrOgogICAgcGF0aDogLi4vLi4vcGFja2FnZXMvbmV0d29yawp7ey9uZXR3b3JrfX17eyNhbmFseXRpY3N9fSAgYW5hbHl0aWNzOgogICAgcGF0aDogLi4vLi4vcGFja2FnZXMvYW5hbHl0aWNzCnt7L2FuYWx5dGljc319CmRldl9kZXBlbmRlbmNpZXM6CiAgbW9ja3RhaWw6IF4xLjAuNAogIGZsdXR0ZXJfdGVzdDoKICAgIHNkazogZmx1dHRlcgogIGZsdXR0ZXJfbGludHM6IF41LjAuMAoKZmx1dHRlcjoK", "type": "text" }, { @@ -226,6 +273,27 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "IyBBdXRoCgpBIE1lbG9zLW1hbmFnZWQgcHJvamVjdCBmb3IgbW9uby1yZXBvLCBjcmVhdGVkIHVzaW5nIE5vblN0b3AgQ0xJLgoKWyFbbm9uc3RvcF9jbGldKGh0dHBzOi8vaW1nLnNoaWVsZHMuaW8vYmFkZ2Uvc3RhcnRlZCUyMHdpdGgtbm9uc3RvcF9jbGktMTY2QzRFLnN2Zz9zdHlsZT1mbGF0LXNxdWFyZSldKGh0dHBzOi8vcHViLmRldi9wYWNrYWdlcy9ub25zdG9wX2NsaSkKWyFbbWVsb3NdKGh0dHBzOi8vaW1nLnNoaWVsZHMuaW8vYmFkZ2UvbWFpbnRhaW5lZCUyMHdpdGgtbWVsb3MtZjcwMGZmLnN2Zz9zdHlsZT1mbGF0LXNxdWFyZSldKGh0dHBzOi8vZ2l0aHViLmNvbS9pbnZlcnRhc2UvbWVsb3MpCgojIyBJbnN0YWxsYXRpb24g8J+SuwoKKirinZcgSW4gb3JkZXIgdG8gc3RhcnQgdXNpbmcgQXV0aCB5b3UgbXVzdCBoYXZlIHRoZSBbRmx1dHRlciBTREtdW2ZsdXR0ZXJfaW5zdGFsbF9saW5rXSBpbnN0YWxsZWQgb24geW91ciBtYWNoaW5lLioqCgpJbnN0YWxsIHZpYSBgZGFydCBwdWIgYWRkYDoKCmBgYHNoCmRhcnQgcHViIGFkZCBhdXRoCmBgYAoKW2ZsdXR0ZXJfaW5zdGFsbF9saW5rXTogaHR0cHM6Ly9kb2NzLmZsdXR0ZXIuZGV2L2dldC1zdGFydGVkL2luc3RhbGw=", "type": "text" }, + { + "path": + "{{ name.snakeCase() }}/features/{{auth_dir}}/test/auth_service_test.dart", + "data": + "aW1wb3J0ICdwYWNrYWdlOmF1dGgvYXV0aC5kYXJ0JyBhcyBtb2R1bGU7CmltcG9ydCAncGFja2FnZTphdXRoL2RhdGEvc2VydmljZXMvYXV0aF9zZXJ2aWNlX2ltcC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmNvcmUvY29yZS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZmlyZWJhc2VfYXV0aC9maXJlYmFzZV9hdXRoLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlcl90ZXN0L2ZsdXR0ZXJfdGVzdC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOm1vY2t0YWlsL21vY2t0YWlsLmRhcnQnOwp7eyNuZXR3b3JrfX1pbXBvcnQgJ3BhY2thZ2U6bmV0d29yay9uZXR3b3JrLmRhcnQnOwp7ey9uZXR3b3JrfX0KCmNsYXNzIF9BdXRoIGV4dGVuZHMgTW9jayBpbXBsZW1lbnRzIEZpcmViYXNlQXV0aCB7fQoKY2xhc3MgX1VzZXIgZXh0ZW5kcyBNb2NrIGltcGxlbWVudHMgVXNlciB7fQoKY2xhc3MgX0xvZ2dlciBleHRlbmRzIE1vY2sgaW1wbGVtZW50cyBMb2dnZXIge30KCnZvaWQgbWFpbigpIHsKICBUZXN0V2lkZ2V0c0ZsdXR0ZXJCaW5kaW5nLmVuc3VyZUluaXRpYWxpemVkKCk7CiAgdGVhckRvd24oZGkucmVzZXQpOwogIHRlc3QoJ3NlcnZpY2UgcmVhZHMgaW5qZWN0ZWQgaWRlbnRpdHkgYW5kIGF3YWl0cyBzaWduLW91dCcsICgpIGFzeW5jIHsKICAgIGZpbmFsIGF1dGggPSBfQXV0aCgpOwogICAgZmluYWwgdXNlciA9IF9Vc2VyKCk7CiAgICBmaW5hbCBzZXJ2aWNlID0gQXV0aFNlcnZpY2VJbXAoZmlyZWJhc2VBdXRoOiBhdXRoLCBsb2dnZXI6IF9Mb2dnZXIoKSk7CiAgICB3aGVuKCgpID0+IGF1dGguY3VycmVudFVzZXIpLnRoZW5SZXR1cm4odXNlcik7CiAgICB3aGVuKCgpID0+IHVzZXIudWlkKS50aGVuUmV0dXJuKCd0ZXN0LXVzZXInKTsKICAgIHdoZW4oYXV0aC5zaWduT3V0KS50aGVuQW5zd2VyKChfKSBhc3luYyB7CiAgICAgIHdoZW4oKCkgPT4gYXV0aC5jdXJyZW50VXNlcikudGhlblJldHVybihudWxsKTsKICAgIH0pOwogICAgZXhwZWN0KHNlcnZpY2UudWlkLCAndGVzdC11c2VyJyk7CiAgICBleHBlY3Qoc2VydmljZS5pc1NpZ25lZEluLCBpc1RydWUpOwogICAgYXdhaXQgc2VydmljZS5zaWduT3V0KCk7CiAgICBleHBlY3Qoc2VydmljZS51aWQsIGlzRW1wdHkpOwogICAgZXhwZWN0KHNlcnZpY2UuaXNTaWduZWRJbiwgaXNGYWxzZSk7CiAgICB2ZXJpZnkoYXV0aC5zaWduT3V0KS5jYWxsZWQoMSk7CiAgfSk7CgogIHRlc3QoJ1NESyBzaWduLW91dCBlcnJvcnMgcmVtYWluIHZpc2libGUgdG8gdGhlIGNhbGxlcicsICgpIGFzeW5jIHsKICAgIGZpbmFsIGF1dGggPSBfQXV0aCgpOwogICAgZmluYWwgZXJyb3IgPSBGaXJlYmFzZUF1dGhFeGNlcHRpb24oY29kZTogJ25ldHdvcmstcmVxdWVzdC1mYWlsZWQnKTsKICAgIHdoZW4oYXV0aC5zaWduT3V0KS50aGVuVGhyb3coZXJyb3IpOwogICAgZmluYWwgc2VydmljZSA9IEF1dGhTZXJ2aWNlSW1wKGZpcmViYXNlQXV0aDogYXV0aCwgbG9nZ2VyOiBfTG9nZ2VyKCkpOwogICAgYXdhaXQgZXhwZWN0TGF0ZXIoc2VydmljZS5zaWduT3V0KCksIHRocm93c0Eoc2FtZShlcnJvcikpKTsKICB9KTsKCiAgdGVzdCgKICAgICdtb2R1bGUgY29tcG9zZXMgaW5qZWN0ZWQgU0RLIGFuZCBkaXNwb3NlcyBvd25lZCB0b2tlbiBwcm92aWRlcicsCiAgICAoKSBhc3luYyB7CiAgICAgIGRpLnJlZ2lzdGVyPExvZ2dlcj4oX0xvZ2dlcigpKTsKICAgICAgZmluYWwgYXV0aCA9IF9BdXRoKCk7CiAgICAgIHdoZW4oYXV0aC5pZFRva2VuQ2hhbmdlcykudGhlbkFuc3dlcigoXykgPT4gY29uc3QgU3RyZWFtPFVzZXI/Pi5lbXB0eSgpKTsKICAgICAgYXdhaXQgbW9kdWxlLmluaXQoCiAgICAgICAgbW9kdWxlLkRlZmF1bHRBdXRoQ29uZmlnKGNsaWVudElkOiAnY2xpZW50LWlkJyksCiAgICAgICAgZmlyZWJhc2VBdXRoOiBhdXRoLAogICAgICAgIGNvbmZpZ3VyZVByb3ZpZGVyczogKHByb3ZpZGVycykgPT4KICAgICAgICAgICAgZXhwZWN0KHByb3ZpZGVycy5sZW5ndGgsIGdyZWF0ZXJUaGFuT3JFcXVhbFRvKDIpKSwKICAgICAgKTsKICAgICAgZXhwZWN0KGRpLmdldDxtb2R1bGUuQXV0aFNlcnZpY2U+KCksIGlzQTxBdXRoU2VydmljZUltcD4oKSk7Cnt7I25ldHdvcmt9fSAgICAgIGZpbmFsIHRva2VucyA9IGRpLmdldDxBdXRoVG9rZW5Qcm92aWRlcj4oKTsKICAgICAgYXdhaXQgZGkucmVzZXQoKTsKICAgICAgZXhwZWN0KHRva2Vucy5pc0F1dGhlbnRpY2F0ZWQsIGlzRmFsc2UpO3t7L25ldHdvcmt9fQogICAgfSwKICApOwp9Cg==", + "type": "text" + }, + { + "path": + "{{ name.snakeCase() }}/features/{{auth_dir}}/test/presentation_test.dart", + "data": + "aW1wb3J0ICdwYWNrYWdlOmF1dGgvYXV0aC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmF1dGgvdWkvY29tcG9uZW50cy9mb290ZXJfYnVpbGRlci5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmNvcmUvY29yZS5kYXJ0JyBhcyBjb3JlOwppbXBvcnQgJ3BhY2thZ2U6ZGkvZGkuZGFydCc7CmltcG9ydCAncGFja2FnZTpmaXJlYmFzZV9hdXRoL2ZpcmViYXNlX2F1dGguZGFydCc7CmltcG9ydCAncGFja2FnZTpmaXJlYmFzZV91aV9hdXRoL2ZpcmViYXNlX3VpX2F1dGguZGFydCcgYXMgdWk7CmltcG9ydCAncGFja2FnZTpmbHV0dGVyL21hdGVyaWFsLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlcl90ZXN0L2ZsdXR0ZXJfdGVzdC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmdvX3JvdXRlci9nb19yb3V0ZXIuZGFydCc7CmltcG9ydCAncGFja2FnZTptb2NrdGFpbC9tb2NrdGFpbC5kYXJ0JzsKCmNsYXNzIF9Vc2VyIGV4dGVuZHMgTW9jayBpbXBsZW1lbnRzIFVzZXIge30KCmNsYXNzIF9Vc2VySW5mbyBleHRlbmRzIE1vY2sgaW1wbGVtZW50cyBVc2VySW5mbyB7fQoKY2xhc3MgX0NyZWRlbnRpYWwgZXh0ZW5kcyBNb2NrIGltcGxlbWVudHMgVXNlckNyZWRlbnRpYWwge30KCmNsYXNzIF9BdXRoU2VydmljZSBleHRlbmRzIE1vY2sgaW1wbGVtZW50cyBBdXRoU2VydmljZSB7fQoKdm9pZCBtYWluKCkgewogIHNldFVwKGNvcmUuaW5pdCk7CiAgdGVhckRvd24oZGkucmVzZXQpOwoKICB0ZXN0KAogICAgJ3Byb3ZpZGVyIGFuYWx5dGljcyBoYW5kbGVzIGV2ZXJ5IHN1cHBvcnRlZCBtZXRob2QgYW5kIGVtcHR5IGlkZW50aXRpZXMnLAogICAgKCkgYXN5bmMgewogICAgICBleHBlY3QoQXV0aEFuYWx5dGljcy5nZXRBdXRoTWV0aG9kKG51bGwpLCAnZW1haWwnKTsKICAgICAgZXhwZWN0KEF1dGhBbmFseXRpY3MuZ2V0QXV0aE1ldGhvZChbXSksICdlbWFpbCcpOwogICAgICBmb3IgKGZpbmFsIHByb3ZpZGVyIGluIFsnZ29vZ2xlLmNvbScsICdhcHBsZS5jb20nLCAncGFzc3dvcmQnXSkgewogICAgICAgIGZpbmFsIGluZm8gPSBfVXNlckluZm8oKTsKICAgICAgICB3aGVuKCgpID0+IGluZm8ucHJvdmlkZXJJZCkudGhlblJldHVybihwcm92aWRlcik7CiAgICAgICAgZXhwZWN0KAogICAgICAgICAgQXV0aEFuYWx5dGljcy5nZXRBdXRoTWV0aG9kKFtpbmZvXSksCiAgICAgICAgICBwcm92aWRlciA9PSAncGFzc3dvcmQnID8gJ2VtYWlsJyA6IHByb3ZpZGVyLnNwbGl0KCcuJykuZmlyc3QsCiAgICAgICAgKTsKICAgICAgfQogICAgICBhd2FpdCBBdXRoQW5hbHl0aWNzLmxvZ1NpZ25JblN1Y2Nlc3MoCiAgICAgICAgbWV0aG9kOiAnZW1haWwnLAogICAgICAgIHVzZXJFbWFpbDogJ3BlcnNvbkBleGFtcGxlLnRlc3QnLAogICAgICApOwogICAgICBhd2FpdCBBdXRoQW5hbHl0aWNzLmxvZ1NpZ25VcFN1Y2Nlc3MobWV0aG9kOiAnZW1haWwnKTsKICAgICAgYXdhaXQgQXV0aEFuYWx5dGljcy5sb2dVc2VyQ3JlYXRpb25TdWNjZXNzKG1ldGhvZDogJ2VtYWlsJyk7CiAgICAgIGF3YWl0IEF1dGhBbmFseXRpY3MubG9nQXV0aEVycm9yKGVycm9yVHlwZTogJ3Rlc3QnLCBmbG93VHlwZTogJ3NpZ25faW4nKTsKICAgICAgYXdhaXQgQXV0aEFuYWx5dGljcy5sb2dTaWduT3V0RXJyb3IoZXJyb3JNZXNzYWdlOiAndGVzdCcpOwogICAgICBhd2FpdCBBdXRoQW5hbHl0aWNzLmxvZ1NpZ25PdXRTdWNjZXNzKCk7CiAgICB9LAogICk7CgogIHRlc3RXaWRnZXRzKAogICAgJ2F1dGggc2NyZWVuIGFkYXB0ZXJzIHdpcmUgaGVhZGVycywgZm9vdGVycyBhbmQgU0RLIHN0YXRlIGFjdGlvbnMnLAogICAgKHRlc3RlcikgYXN5bmMgewogICAgICBsYXRlIEJ1aWxkQ29udGV4dCBjb250ZXh0OwogICAgICBmaW5hbCByb3V0ZXIgPSBHb1JvdXRlcigKICAgICAgICByb3V0ZXM6IFsKICAgICAgICAgIEdvUm91dGUoCiAgICAgICAgICAgIHBhdGg6ICcvJywKICAgICAgICAgICAgYnVpbGRlcjogKGN0eCwgXykgewogICAgICAgICAgICAgIGNvbnRleHQgPSBjdHg7CiAgICAgICAgICAgICAgcmV0dXJuIGNvbnN0IFNpemVkQm94KCk7CiAgICAgICAgICAgIH0sCiAgICAgICAgICApLAogICAgICAgICAgR29Sb3V0ZSgKICAgICAgICAgICAgcGF0aDogQXV0aFJvdXRlcy5mb3Jnb3RQYXNzd29yZCwKICAgICAgICAgICAgYnVpbGRlcjogKF8sIHN0YXRlKSA9PgogICAgICAgICAgICAgICAgVGV4dChzdGF0ZS51cmkucXVlcnlQYXJhbWV0ZXJzWydlbWFpbCddID8/ICcnKSwKICAgICAgICAgICksCiAgICAgICAgICBHb1JvdXRlKAogICAgICAgICAgICBwYXRoOiBBdXRoUm91dGVzLnNpZ25JbiwKICAgICAgICAgICAgYnVpbGRlcjogKF8sIF8pID0+IGNvbnN0IFRleHQoJ3NpZ24taW4gcm91dGUnKSwKICAgICAgICAgICksCiAgICAgICAgICBHb1JvdXRlKAogICAgICAgICAgICBwYXRoOiBBdXRoUm91dGVzLnNpZ25VcCwKICAgICAgICAgICAgYnVpbGRlcjogKF8sIF8pID0+IGNvbnN0IFRleHQoJ3NpZ24tdXAgcm91dGUnKSwKICAgICAgICAgICksCiAgICAgICAgXSwKICAgICAgKTsKICAgICAgYWRkVGVhckRvd24ocm91dGVyLmRpc3Bvc2UpOwogICAgICBhd2FpdCB0ZXN0ZXIucHVtcFdpZGdldChNYXRlcmlhbEFwcC5yb3V0ZXIocm91dGVyQ29uZmlnOiByb3V0ZXIpKTsKICAgICAgYXdhaXQgdGVzdGVyLnB1bXBBbmRTZXR0bGUoKTsKICAgICAgdmFyIHNpZ25lZEluID0gMDsKICAgICAgdmFyIHNpZ25lZFVwID0gMDsKICAgICAgZmluYWwgcm91dGVzID0gQXV0aFJvdXRlcigKICAgICAgICBvblNpZ25lZEluOiAoXykge30sCiAgICAgICAgb25TaWduZWRVcDogKF8pIHt9LAogICAgICApLnJvdXRlcy53aGVyZVR5cGU8R29Sb3V0ZT4oKS50b0xpc3QoKTsKICAgICAgZmluYWwgc3RhdGUgPSBHb1JvdXRlclN0YXRlLm9mKGNvbnRleHQpOwogICAgICBleHBlY3Qocm91dGVzWzBdLmJ1aWxkZXIhKGNvbnRleHQsIHN0YXRlKSwgaXNBPFNpZ25JblNjcmVlbj4oKSk7CiAgICAgIGV4cGVjdChyb3V0ZXNbMV0uYnVpbGRlciEoY29udGV4dCwgc3RhdGUpLCBpc0E8UmVnaXN0ZXJTY3JlZW4+KCkpOwogICAgICBleHBlY3QoCiAgICAgICAgKHJvdXRlc1syXS5idWlsZGVyIShjb250ZXh0LCBzdGF0ZSkgYXMgRm9yZ290UGFzc3dvcmRTY3JlZW4pLmVtYWlsLAogICAgICAgIGlzTnVsbCwKICAgICAgKTsKICAgICAgZmluYWwgc2lnbkluID0KICAgICAgICAgIFNpZ25JblNjcmVlbihvblNpZ25lZEluOiAoXykgPT4gc2lnbmVkSW4rKykuYnVpbGQoY29udGV4dCkKICAgICAgICAgICAgICBhcyB1aS5TaWduSW5TY3JlZW47CiAgICAgIGZpbmFsIHJlZ2lzdGVyID0KICAgICAgICAgIFJlZ2lzdGVyU2NyZWVuKG9uU2lnbmVkVXA6IChfKSA9PiBzaWduZWRVcCsrKS5idWlsZChjb250ZXh0KQogICAgICAgICAgICAgIGFzIHVpLlJlZ2lzdGVyU2NyZWVuOwogICAgICBmaW5hbCByZWNvdmVyeSA9CiAgICAgICAgICBjb25zdCBGb3Jnb3RQYXNzd29yZFNjcmVlbigKICAgICAgICAgICAgICAgIGVtYWlsOiAncGVyc29uQGV4YW1wbGUudGVzdCcsCiAgICAgICAgICAgICAgKS5idWlsZChjb250ZXh0KQogICAgICAgICAgICAgIGFzIHVpLkZvcmdvdFBhc3N3b3JkU2NyZWVuOwogICAgICBleHBlY3QocmVjb3ZlcnkuZW1haWwsICdwZXJzb25AZXhhbXBsZS50ZXN0Jyk7CiAgICAgIGZpbmFsIHVzZXIgPSBfVXNlcigpOwogICAgICBmaW5hbCBjcmVkZW50aWFsID0gX0NyZWRlbnRpYWwoKTsKICAgICAgd2hlbigoKSA9PiB1c2VyLnByb3ZpZGVyRGF0YSkudGhlblJldHVybihbXSk7CiAgICAgIHdoZW4oKCkgPT4gdXNlci5lbWFpbCkudGhlblJldHVybigncGVyc29uQGV4YW1wbGUudGVzdCcpOwogICAgICB3aGVuKCgpID0+IGNyZWRlbnRpYWwudXNlcikudGhlblJldHVybih1c2VyKTsKICAgICAgZm9yIChmaW5hbCBhY3Rpb25zIGluIFtzaWduSW4uYWN0aW9ucywgcmVnaXN0ZXIuYWN0aW9ucyFdKSB7CiAgICAgICAgYWN0aW9ucwogICAgICAgICAgICAud2hlcmVUeXBlPHVpLkF1dGhTdGF0ZUNoYW5nZUFjdGlvbjx1aS5TaWduZWRJbj4+KCkKICAgICAgICAgICAgLnNpbmdsZQogICAgICAgICAgICAuaW52b2tlKGNvbnRleHQsIHVpLlNpZ25lZEluKHVzZXIpKTsKICAgICAgICBhY3Rpb25zCiAgICAgICAgICAgIC53aGVyZVR5cGU8dWkuQXV0aFN0YXRlQ2hhbmdlQWN0aW9uPHVpLlVzZXJDcmVhdGVkPj4oKQogICAgICAgICAgICAuc2luZ2xlCiAgICAgICAgICAgIC5pbnZva2UoY29udGV4dCwgdWkuVXNlckNyZWF0ZWQoY3JlZGVudGlhbCkpOwogICAgICAgIGFjdGlvbnMKICAgICAgICAgICAgLndoZXJlVHlwZTx1aS5BdXRoU3RhdGVDaGFuZ2VBY3Rpb248dWkuQXV0aEZhaWxlZD4+KCkKICAgICAgICAgICAgLnNpbmdsZQogICAgICAgICAgICAuaW52b2tlKGNvbnRleHQsIHVpLkF1dGhGYWlsZWQoRXhjZXB0aW9uKCd0ZXN0JykpKTsKICAgICAgfQogICAgICBhd2FpdCB0ZXN0ZXIucHVtcCgpOwogICAgICBleHBlY3Qoc2lnbmVkSW4sIDIpOwogICAgICBleHBlY3Qoc2lnbmVkVXAsIDIpOwogICAgICBzaWduSW4uYWN0aW9ucy53aGVyZVR5cGU8dWkuRm9yZ290UGFzc3dvcmRBY3Rpb24+KCkuc2luZ2xlLmNhbGxiYWNrKAogICAgICAgIGNvbnRleHQsCiAgICAgICAgJ3BlcnNvbkBleGFtcGxlLnRlc3QnLAogICAgICApOwogICAgICBhd2FpdCB0ZXN0ZXIucHVtcEFuZFNldHRsZSgpOwogICAgICBleHBlY3QoZmluZC50ZXh0KCdwZXJzb25AZXhhbXBsZS50ZXN0JyksIGZpbmRzT25lV2lkZ2V0KTsKICAgICAgcm91dGVyLnBvcCgpOwogICAgICBhd2FpdCB0ZXN0ZXIucHVtcEFuZFNldHRsZSgpOwogICAgICAvLyBWYWxpZGF0ZSBvdXIgYnVpbGRlcnMgaW5kZXBlbmRlbnRseSBvZiBGaXJlYmFzZSBVSSdzIHBsYXRmb3JtIGltcGxlbWVudGF0aW9uLgogICAgICBmaW5hbCB3aWRnZXRzID0gWwogICAgICAgIHNpZ25Jbi5oZWFkZXJCdWlsZGVyIShjb250ZXh0LCBjb25zdCBCb3hDb25zdHJhaW50cygpLCAwKSwKICAgICAgICByZWdpc3Rlci5oZWFkZXJCdWlsZGVyIShjb250ZXh0LCBjb25zdCBCb3hDb25zdHJhaW50cygpLCAwKSwKICAgICAgICByZWNvdmVyeS5oZWFkZXJCdWlsZGVyIShjb250ZXh0LCBjb25zdCBCb3hDb25zdHJhaW50cygpLCAwKSwKICAgICAgICBzaWduSW4uZm9vdGVyQnVpbGRlciEoY29udGV4dCwgdWkuQXV0aEFjdGlvbi5zaWduSW4pLAogICAgICAgIHJlZ2lzdGVyLmZvb3RlckJ1aWxkZXIhKGNvbnRleHQsIHVpLkF1dGhBY3Rpb24uc2lnblVwKSwKICAgICAgXTsKICAgICAgZm9yIChmaW5hbCB3aWRnZXQgaW4gd2lkZ2V0cykgewogICAgICAgIGF3YWl0IHRlc3Rlci5wdW1wV2lkZ2V0KE1hdGVyaWFsQXBwKGhvbWU6IFNjYWZmb2xkKGJvZHk6IHdpZGdldCkpKTsKICAgICAgICBleHBlY3QodGVzdGVyLnRha2VFeGNlcHRpb24oKSwgaXNOdWxsKTsKICAgICAgfQogICAgICBhd2FpdCB0ZXN0ZXIucHVtcFdpZGdldChjb25zdCBTaXplZEJveCgpKTsKICAgICAgYXdhaXQgdGVzdGVyLnB1bXAoY29uc3QgRHVyYXRpb24oc2Vjb25kczogNSkpOwogICAgfSwKICApOwoKICBmb3IgKGZpbmFsIHNpZ25lZEluIGluIFtudWxsLCBmYWxzZSwgdHJ1ZV0pIHsKICAgIHRlc3RXaWRnZXRzKCdyb3V0ZSBndWFyZCBoYW5kbGVzIHJlZ2lzdGVyZWQgaWRlbnRpdHkgJHNpZ25lZEluJywgKAogICAgICB0ZXN0ZXIsCiAgICApIGFzeW5jIHsKICAgICAgaWYgKHNpZ25lZEluICE9IG51bGwpIHsKICAgICAgICBmaW5hbCBzZXJ2aWNlID0gX0F1dGhTZXJ2aWNlKCk7CiAgICAgICAgd2hlbigoKSA9PiBzZXJ2aWNlLmlzU2lnbmVkSW4pLnRoZW5SZXR1cm4oc2lnbmVkSW4pOwogICAgICAgIGRpLnJlZ2lzdGVyPEF1dGhTZXJ2aWNlPihzZXJ2aWNlKTsKICAgICAgfQogICAgICBmaW5hbCByb3V0ZXIgPSBHb1JvdXRlcigKICAgICAgICBpbml0aWFsTG9jYXRpb246ICcvcHJpdmF0ZScsCiAgICAgICAgcm91dGVzOiBbCiAgICAgICAgICBHb0F1dGhSb3V0ZSgKICAgICAgICAgICAgcGF0aDogJy9wcml2YXRlJywKICAgICAgICAgICAgYnVpbGRlcjogKF8sIF8pID0+IGNvbnN0IFRleHQoJ3ByaXZhdGUnKSwKICAgICAgICAgICksCiAgICAgICAgICBHb1JvdXRlKAogICAgICAgICAgICBwYXRoOiBBdXRoUm91dGVzLnNpZ25JbiwKICAgICAgICAgICAgYnVpbGRlcjogKF8sIF8pID0+IGNvbnN0IFRleHQoJ2xvZ2luJyksCiAgICAgICAgICApLAogICAgICAgIF0sCiAgICAgICk7CiAgICAgIGFkZFRlYXJEb3duKHJvdXRlci5kaXNwb3NlKTsKICAgICAgYXdhaXQgdGVzdGVyLnB1bXBXaWRnZXQoTWF0ZXJpYWxBcHAucm91dGVyKHJvdXRlckNvbmZpZzogcm91dGVyKSk7CiAgICAgIGF3YWl0IHRlc3Rlci5wdW1wQW5kU2V0dGxlKCk7CiAgICAgIGV4cGVjdChmaW5kLnRleHQoc2lnbmVkSW4gPT0gdHJ1ZSA/ICdwcml2YXRlJyA6ICdsb2dpbicpLCBmaW5kc09uZVdpZGdldCk7CiAgICB9KTsKICB9CgogIHRlc3RXaWRnZXRzKCdmb290ZXJzIG5hdmlnYXRlIHRvIHRoZSBvcHBvc2l0ZSBhdXRoZW50aWNhdGlvbiByb3V0ZScsICgKICAgIHRlc3RlciwKICApIGFzeW5jIHsKICAgIGZvciAoZmluYWwgdHlwZSBpbiBGb290ZXJUeXBlLnZhbHVlcykgewogICAgICBmaW5hbCByb3V0ZXIgPSBHb1JvdXRlcigKICAgICAgICByb3V0ZXM6IFsKICAgICAgICAgIEdvUm91dGUoCiAgICAgICAgICAgIHBhdGg6ICcvJywKICAgICAgICAgICAgYnVpbGRlcjogKGNvbnRleHQsIF8pID0+IFNjYWZmb2xkKAogICAgICAgICAgICAgIGJvZHk6IGZvb3RlckJ1aWxkZXIoY29udGV4dCwgdWkuQXV0aEFjdGlvbi5zaWduSW4sIHR5cGUpLAogICAgICAgICAgICApLAogICAgICAgICAgKSwKICAgICAgICAgIEdvUm91dGUoCiAgICAgICAgICAgIHBhdGg6IEF1dGhSb3V0ZXMuc2lnbkluLAogICAgICAgICAgICBidWlsZGVyOiAoXywgXykgPT4gY29uc3QgVGV4dCgnbG9naW4gZGVzdGluYXRpb24nKSwKICAgICAgICAgICksCiAgICAgICAgICBHb1JvdXRlKAogICAgICAgICAgICBwYXRoOiBBdXRoUm91dGVzLnNpZ25VcCwKICAgICAgICAgICAgYnVpbGRlcjogKF8sIF8pID0+IGNvbnN0IFRleHQoJ3JlZ2lzdGVyIGRlc3RpbmF0aW9uJyksCiAgICAgICAgICApLAogICAgICAgIF0sCiAgICAgICk7CiAgICAgIGF3YWl0IHRlc3Rlci5wdW1wV2lkZ2V0KE1hdGVyaWFsQXBwLnJvdXRlcihyb3V0ZXJDb25maWc6IHJvdXRlcikpOwogICAgICBhd2FpdCB0ZXN0ZXIucHVtcEFuZFNldHRsZSgpOwogICAgICBhd2FpdCB0ZXN0ZXIudGFwKGZpbmQuYnlUeXBlKEdlc3R1cmVEZXRlY3RvcikubGFzdCk7CiAgICAgIGF3YWl0IHRlc3Rlci5wdW1wQW5kU2V0dGxlKCk7CiAgICAgIGV4cGVjdCgKICAgICAgICBmaW5kLnRleHQoCiAgICAgICAgICB0eXBlID09IEZvb3RlclR5cGUuc2lnbkluCiAgICAgICAgICAgICAgPyAncmVnaXN0ZXIgZGVzdGluYXRpb24nCiAgICAgICAgICAgICAgOiAnbG9naW4gZGVzdGluYXRpb24nLAogICAgICAgICksCiAgICAgICAgZmluZHNPbmVXaWRnZXQsCiAgICAgICk7CiAgICAgIGF3YWl0IHRlc3Rlci5wdW1wV2lkZ2V0KGNvbnN0IFNpemVkQm94KCkpOwogICAgICByb3V0ZXIuZGlzcG9zZSgpOwogICAgfQogIH0pOwp9Cg==", + "type": "text" + }, + { + "path": + "{{ name.snakeCase() }}/features/{{auth_dir}}/test/{{auth_token_provider_test_file}}", + "data": + "aW1wb3J0ICdkYXJ0OmFzeW5jJzsKCmltcG9ydCAncGFja2FnZTphdXRoL2RhdGEvdG9rZW4vZmlyZWJhc2VfYXV0aF90b2tlbl9wcm92aWRlci5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmNvcmUvY29yZS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZpcmViYXNlX2F1dGgvZmlyZWJhc2VfYXV0aC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZsdXR0ZXJfdGVzdC9mbHV0dGVyX3Rlc3QuZGFydCc7CmltcG9ydCAncGFja2FnZTptb2NrdGFpbC9tb2NrdGFpbC5kYXJ0JzsKCmNsYXNzIF9BdXRoIGV4dGVuZHMgTW9jayBpbXBsZW1lbnRzIEZpcmViYXNlQXV0aCB7fQoKY2xhc3MgX1VzZXIgZXh0ZW5kcyBNb2NrIGltcGxlbWVudHMgVXNlciB7fQoKY2xhc3MgX1Rva2VuIGV4dGVuZHMgTW9jayBpbXBsZW1lbnRzIElkVG9rZW5SZXN1bHQge30KCmNsYXNzIF9Mb2dnZXIgZXh0ZW5kcyBNb2NrIGltcGxlbWVudHMgTG9nZ2VyIHt9Cgp2b2lkIG1haW4oKSB7CiAgbGF0ZSBfQXV0aCBhdXRoOwogIGxhdGUgX1VzZXIgdXNlcjsKICBsYXRlIF9Mb2dnZXIgbG9nZ2VyOwogIGxhdGUgX1Rva2VuIHRva2VuOwogIGxhdGUgU3RyZWFtQ29udHJvbGxlcjxVc2VyPz4gZXZlbnRzOwogIGxhdGUgRmlyZWJhc2VBdXRoVG9rZW5Qcm92aWRlciBwcm92aWRlcjsKICBsYXRlIERhdGVUaW1lIG5vdzsKCiAgc2V0VXAoKCkgewogICAgYXV0aCA9IF9BdXRoKCk7CiAgICB1c2VyID0gX1VzZXIoKTsKICAgIHRva2VuID0gX1Rva2VuKCk7CiAgICBsb2dnZXIgPSBfTG9nZ2VyKCk7CiAgICBub3cgPSBEYXRlVGltZSgyMDI2KTsKICAgIGV2ZW50cyA9IFN0cmVhbUNvbnRyb2xsZXI8VXNlcj8+KCk7CiAgICB3aGVuKGF1dGguaWRUb2tlbkNoYW5nZXMpLnRoZW5BbnN3ZXIoKF8pID0+IGV2ZW50cy5zdHJlYW0pOwogICAgd2hlbigoKSA9PiBhdXRoLmN1cnJlbnRVc2VyKS50aGVuUmV0dXJuKHVzZXIpOwogICAgd2hlbigoKSA9PiB1c2VyLnVpZCkudGhlblJldHVybigndXNlci0xJyk7CiAgICB3aGVuKCgpID0+IHRva2VuLnRva2VuKS50aGVuUmV0dXJuKCd0ZXN0LXRva2VuJyk7CiAgICB3aGVuKAogICAgICAoKSA9PiB0b2tlbi5leHBpcmF0aW9uVGltZSwKICAgICkudGhlblJldHVybihub3cuYWRkKGNvbnN0IER1cmF0aW9uKGhvdXJzOiAxKSkpOwogICAgd2hlbigoKSA9PiB1c2VyLmdldElkVG9rZW5SZXN1bHQoYW55KCkpKS50aGVuQW5zd2VyKChfKSBhc3luYyA9PiB0b2tlbik7CiAgICB3aGVuKGF1dGguc2lnbk91dCkudGhlbkFuc3dlcigoXykgYXN5bmMge30pOwogICAgcHJvdmlkZXIgPSBGaXJlYmFzZUF1dGhUb2tlblByb3ZpZGVyKAogICAgICBmaXJlYmFzZUF1dGg6IGF1dGgsCiAgICAgIGxvZ2dlcjogbG9nZ2VyLAogICAgICBub3c6ICgpID0+IG5vdywKICAgICk7CiAgfSk7CiAgdGVhckRvd24oKCkgYXN5bmMgewogICAgYXdhaXQgcHJvdmlkZXIuZGlzcG9zZSgpOwogICAgYXdhaXQgZXZlbnRzLmNsb3NlKCk7CiAgfSk7CgogIHRlc3QoJ0ZpcmViYXNlIGV4cGlyYXRpb24gY29udHJvbHMgY2FjaGVkLXRva2VuIHJldXNlIGFuZCByZWZyZXNoJywgKCkgYXN5bmMgewogICAgZXhwZWN0KHByb3ZpZGVyLmlzVG9rZW5FeHBpcmVkLCBpc1RydWUpOwogICAgZXhwZWN0KHByb3ZpZGVyLmlzQXV0aGVudGljYXRlZCwgaXNUcnVlKTsKICAgIGV4cGVjdChhd2FpdCBwcm92aWRlci5nZXRWYWxpZFRva2VuKCksICd0ZXN0LXRva2VuJyk7CiAgICBleHBlY3QocHJvdmlkZXIuZ2V0Q3VycmVudFRva2VuKCksICd0ZXN0LXRva2VuJyk7CiAgICBleHBlY3QocHJvdmlkZXIuaXNUb2tlbkV4cGlyZWQsIGlzRmFsc2UpOwogICAgZXhwZWN0KGF3YWl0IHByb3ZpZGVyLmdldFZhbGlkVG9rZW4oKSwgJ3Rlc3QtdG9rZW4nKTsKICAgIHZlcmlmeSgoKSA9PiB1c2VyLmdldElkVG9rZW5SZXN1bHQoZmFsc2UpKS5jYWxsZWQoMSk7CiAgICBub3cgPSBub3cuYWRkKGNvbnN0IER1cmF0aW9uKG1pbnV0ZXM6IDU1KSk7CiAgICBleHBlY3QocHJvdmlkZXIuaXNUb2tlbkV4cGlyZWQsIGlzVHJ1ZSk7CiAgICBhd2FpdCBwcm92aWRlci5nZXRWYWxpZFRva2VuKCk7CiAgICB2ZXJpZnkoKCkgPT4gdXNlci5nZXRJZFRva2VuUmVzdWx0KGZhbHNlKSkuY2FsbGVkKDEpOwogICAgYXdhaXQgcHJvdmlkZXIucmVmcmVzaFRva2VuKCk7CiAgICB2ZXJpZnkoKCkgPT4gdXNlci5nZXRJZFRva2VuUmVzdWx0KHRydWUpKS5jYWxsZWQoMSk7CiAgfSk7CgogIHRlc3QoJ3NpZ25lZC1vdXQgdXNlcnMgaGF2ZSBubyB0b2tlbicsICgpIGFzeW5jIHsKICAgIHdoZW4oKCkgPT4gYXV0aC5jdXJyZW50VXNlcikudGhlblJldHVybihudWxsKTsKICAgIGV4cGVjdChwcm92aWRlci5pc0F1dGhlbnRpY2F0ZWQsIGlzRmFsc2UpOwogICAgZXhwZWN0KGF3YWl0IHByb3ZpZGVyLmdldFZhbGlkVG9rZW4oKSwgaXNOdWxsKTsKICAgIGV4cGVjdChhd2FpdCBwcm92aWRlci5yZWZyZXNoVG9rZW4oKSwgaXNOdWxsKTsKICB9KTsKCiAgdGVzdCgndG9rZW4gZXZlbnRzIHB1Ymxpc2ggcmVmcmVzaGVkIHRva2VucyBhbmQgY2xlYXIgb24gc2lnbi1vdXQnLCAoKSBhc3luYyB7CiAgICBmaW5hbCB2YWx1ZXMgPSA8U3RyaW5nPz5bXTsKICAgIGZpbmFsIHN1YnNjcmlwdGlvbiA9IHByb3ZpZGVyLnRva2VuU3RyZWFtLmxpc3Rlbih2YWx1ZXMuYWRkKTsKICAgIGV2ZW50cy5hZGQodXNlcik7CiAgICBhd2FpdCBwdW1wRXZlbnRRdWV1ZSgpOwogICAgZXhwZWN0KHZhbHVlcywgW251bGwsICd0ZXN0LXRva2VuJ10pOwogICAgd2hlbigoKSA9PiBhdXRoLmN1cnJlbnRVc2VyKS50aGVuUmV0dXJuKG51bGwpOwogICAgZXZlbnRzLmFkZChudWxsKTsKICAgIGF3YWl0IHB1bXBFdmVudFF1ZXVlKCk7CiAgICBleHBlY3QocHJvdmlkZXIuZ2V0Q3VycmVudFRva2VuKCksIGlzTnVsbCk7CiAgICBleHBlY3QodmFsdWVzLmxhc3QsIGlzTnVsbCk7CiAgICBhd2FpdCBzdWJzY3JpcHRpb24uY2FuY2VsKCk7CiAgfSk7CgogIHRlc3QoJ3JlYWQgYW5kIHN0cmVhbSBlcnJvcnMgY2xlYXIgY2FjaGVkIGNyZWRlbnRpYWxzJywgKCkgYXN5bmMgewogICAgYXdhaXQgcHJvdmlkZXIuZ2V0VmFsaWRUb2tlbigpOwogICAgd2hlbigKICAgICAgKCkgPT4gdXNlci5nZXRJZFRva2VuUmVzdWx0KGFueSgpKSwKICAgICkudGhlblRocm93KFN0YXRlRXJyb3IoJ3VuYXZhaWxhYmxlJykpOwogICAgZXhwZWN0KGF3YWl0IHByb3ZpZGVyLnJlZnJlc2hUb2tlbigpLCBpc051bGwpOwogICAgZXhwZWN0KHByb3ZpZGVyLmdldEN1cnJlbnRUb2tlbigpLCBpc051bGwpOwogICAgZXZlbnRzLmFkZEVycm9yKFN0YXRlRXJyb3IoJ3N0cmVhbSBmYWlsdXJlJyksIFN0YWNrVHJhY2UuY3VycmVudCk7CiAgICBhd2FpdCBwdW1wRXZlbnRRdWV1ZSgpOwogICAgZXhwZWN0KHByb3ZpZGVyLmlzVG9rZW5FeHBpcmVkLCBpc1RydWUpOwogIH0pOwoKICB0ZXN0KAogICAgJ3NpZ24tb3V0IGNsZWFycyBjcmVkZW50aWFscyBhbmQgbGF0ZSByZWZyZXNoZXMgY2Fubm90IHJlc3RvcmUgdGhlbScsCiAgICAoKSBhc3luYyB7CiAgICAgIGZpbmFsIHBlbmRpbmcgPSBDb21wbGV0ZXI8SWRUb2tlblJlc3VsdD4oKTsKICAgICAgd2hlbigKICAgICAgICAoKSA9PiB1c2VyLmdldElkVG9rZW5SZXN1bHQoYW55KCkpLAogICAgICApLnRoZW5BbnN3ZXIoKF8pID0+IHBlbmRpbmcuZnV0dXJlKTsKICAgICAgZmluYWwgcmVmcmVzaCA9IHByb3ZpZGVyLnJlZnJlc2hUb2tlbigpOwogICAgICBhd2FpdCBwcm92aWRlci5zaWduT3V0KCk7CiAgICAgIHBlbmRpbmcuY29tcGxldGUodG9rZW4pOwogICAgICBleHBlY3QoYXdhaXQgcmVmcmVzaCwgaXNOdWxsKTsKICAgICAgZXhwZWN0KHByb3ZpZGVyLmdldEN1cnJlbnRUb2tlbigpLCBpc051bGwpOwogICAgICB2ZXJpZnkoYXV0aC5zaWduT3V0KS5jYWxsZWQoMSk7CiAgICB9LAogICk7CgogIHRlc3QoJ2FuIGFjY291bnQgY2hhbmdlIGludmFsaWRhdGVzIGFuIGluLWZsaWdodCByZXNwb25zZScsICgpIGFzeW5jIHsKICAgIGZpbmFsIHBlbmRpbmcgPSBDb21wbGV0ZXI8SWRUb2tlblJlc3VsdD4oKTsKICAgIHdoZW4oKCkgPT4gdXNlci5nZXRJZFRva2VuUmVzdWx0KGFueSgpKSkudGhlbkFuc3dlcigoXykgPT4gcGVuZGluZy5mdXR1cmUpOwogICAgZmluYWwgcmVmcmVzaCA9IHByb3ZpZGVyLnJlZnJlc2hUb2tlbigpOwogICAgd2hlbigoKSA9PiBhdXRoLmN1cnJlbnRVc2VyKS50aGVuUmV0dXJuKG51bGwpOwogICAgcGVuZGluZy5jb21wbGV0ZSh0b2tlbik7CiAgICBleHBlY3QoYXdhaXQgcmVmcmVzaCwgaXNOdWxsKTsKICB9KTsKCiAgdGVzdCgnZGlzcG9zaW5nIGR1cmluZyByZWZyZXNoIGNsb3NlcyBzYWZlbHkgYW5kIGlzIGlkZW1wb3RlbnQnLCAoKSBhc3luYyB7CiAgICBmaW5hbCBwZW5kaW5nID0gQ29tcGxldGVyPElkVG9rZW5SZXN1bHQ+KCk7CiAgICB3aGVuKCgpID0+IHVzZXIuZ2V0SWRUb2tlblJlc3VsdChhbnkoKSkpLnRoZW5BbnN3ZXIoKF8pID0+IHBlbmRpbmcuZnV0dXJlKTsKICAgIGZpbmFsIHJlZnJlc2ggPSBwcm92aWRlci5yZWZyZXNoVG9rZW4oKTsKICAgIGF3YWl0IHByb3ZpZGVyLmRpc3Bvc2UoKTsKICAgIHBlbmRpbmcuY29tcGxldGVFcnJvcihTdGF0ZUVycm9yKCdsYXRlIGVycm9yJykpOwogICAgZXhwZWN0KGF3YWl0IHJlZnJlc2gsIGlzTnVsbCk7CiAgICBleHBlY3QocHJvdmlkZXIuaXNBdXRoZW50aWNhdGVkLCBpc0ZhbHNlKTsKICAgIGV4cGVjdChhd2FpdCBwcm92aWRlci5nZXRWYWxpZFRva2VuKCksIGlzTnVsbCk7CiAgICBleHBlY3QoYXdhaXQgcHJvdmlkZXIucmVmcmVzaFRva2VuKCksIGlzTnVsbCk7CiAgICBhd2FpdCBwcm92aWRlci5kaXNwb3NlKCk7CiAgfSk7CgogIHRlc3QoJ251bGwgdG9rZW4gcmVzdWx0cyBkbyBub3QgdGhyb3cnLCAoKSBhc3luYyB7CiAgICB3aGVuKCgpID0+IHRva2VuLnRva2VuKS50aGVuUmV0dXJuKG51bGwpOwogICAgd2hlbigoKSA9PiB0b2tlbi5leHBpcmF0aW9uVGltZSkudGhlblJldHVybihudWxsKTsKICAgIGV4cGVjdChhd2FpdCBwcm92aWRlci5nZXRWYWxpZFRva2VuKCksIGlzTnVsbCk7CiAgICBleHBlY3QocHJvdmlkZXIuaXNUb2tlbkV4cGlyZWQsIGlzVHJ1ZSk7CiAgfSk7Cn0K", + "type": "text" + }, { "path": "{{ name.snakeCase() }}/features/{{dashboard_dir}}/lib/dashboard.dart", @@ -237,7 +305,7 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "path": "{{ name.snakeCase() }}/features/{{dashboard_dir}}/lib/router/dashboard_router.dart", "data": - "e3sjYXV0aH19aW1wb3J0ICdwYWNrYWdlOmF1dGgvYXV0aC5kYXJ0JyBhcyBhdXRoOwp7ey9hdXRofX1pbXBvcnQgJ3BhY2thZ2U6ZGFzaGJvYXJkL3VpL3NjcmVlbnMvaW5kZXguZGFydCc7CmltcG9ydCAncGFja2FnZTpnb19yb3V0ZXIvZ29fcm91dGVyLmRhcnQnOwoKe3sjYXV0aH19Ly8vIEV2ZXJ5IHNoZWxsIGJyYW5jaCBpcyBndWFyZGVkIC0gdW5hdXRoZW50aWNhdGVkIHVzZXJzIGJvdW5jZSB0byBzaWduLWluLgp0eXBlZGVmIF9TaGVsbFJvdXRlID0gYXV0aC5Hb0F1dGhSb3V0ZTt7ey9hdXRofX17e15hdXRofX10eXBlZGVmIF9TaGVsbFJvdXRlID0gR29Sb3V0ZTt7ey9hdXRofX0KCi8vLyBCb3R0b20tbmF2aWdhdGlvbiBzaGVsbCBmb3IgdGhlIHNpZ25lZC1pbiBwYXJ0IG9mIHRoZSBhcHAuCi8vLwovLy8gQWRkIGEgdGFiIGJ5IGFkZGluZyBhIFtTdGF0ZWZ1bFNoZWxsQnJhbmNoXSBoZXJlIGFuZCBhIGRlc3RpbmF0aW9uIGluCi8vLyBbRGFzaGJvYXJkU2hlbGxTY3JlZW5dLgpjbGFzcyBEYXNoYm9hcmRSb3V0ZXIgewogIGNvbnN0IERhc2hib2FyZFJvdXRlci5fKCk7CgogIHN0YXRpYyBjb25zdCBTdHJpbmcgaG9tZSA9ICcvaG9tZS9kYXNoYm9hcmQnOwogIHN0YXRpYyBjb25zdCBTdHJpbmcgZXhwbG9yZSA9ICcvaG9tZS9leHBsb3JlJzsKICBzdGF0aWMgY29uc3QgU3RyaW5nIHByb2ZpbGUgPSAnL2hvbWUvcHJvZmlsZSc7CgogIHN0YXRpYyBTdGF0ZWZ1bFNoZWxsUm91dGUgY3JlYXRlU2hlbGxSb3V0ZSgpIHsKICAgIHJldHVybiBTdGF0ZWZ1bFNoZWxsUm91dGUuaW5kZXhlZFN0YWNrKAogICAgICBidWlsZGVyOiAoY29udGV4dCwgc3RhdGUsIG5hdmlnYXRpb25TaGVsbCkgPT4KICAgICAgICAgIERhc2hib2FyZFNoZWxsU2NyZWVuKG5hdmlnYXRpb25TaGVsbDogbmF2aWdhdGlvblNoZWxsKSwKICAgICAgYnJhbmNoZXM6IFsKICAgICAgICBTdGF0ZWZ1bFNoZWxsQnJhbmNoKAogICAgICAgICAgcm91dGVzOiBbCiAgICAgICAgICAgIF9TaGVsbFJvdXRlKAogICAgICAgICAgICAgIHBhdGg6IGhvbWUsCiAgICAgICAgICAgICAgYnVpbGRlcjogKGNvbnRleHQsIHN0YXRlKSA9PiBjb25zdCBIb21lVGFiU2NyZWVuKCksCiAgICAgICAgICAgICksCiAgICAgICAgICBdLAogICAgICAgICksCiAgICAgICAgU3RhdGVmdWxTaGVsbEJyYW5jaCgKICAgICAgICAgIHJvdXRlczogWwogICAgICAgICAgICBfU2hlbGxSb3V0ZSgKICAgICAgICAgICAgICBwYXRoOiBleHBsb3JlLAogICAgICAgICAgICAgIGJ1aWxkZXI6IChjb250ZXh0LCBzdGF0ZSkgPT4gY29uc3QgRXhwbG9yZVRhYlNjcmVlbigpLAogICAgICAgICAgICApLAogICAgICAgICAgXSwKICAgICAgICApLAogICAgICAgIFN0YXRlZnVsU2hlbGxCcmFuY2goCiAgICAgICAgICByb3V0ZXM6IFsKICAgICAgICAgICAgX1NoZWxsUm91dGUoCiAgICAgICAgICAgICAgcGF0aDogcHJvZmlsZSwKICAgICAgICAgICAgICBidWlsZGVyOiAoY29udGV4dCwgc3RhdGUpID0+IGNvbnN0IFByb2ZpbGVUYWJTY3JlZW4oKSwKICAgICAgICAgICAgKSwKICAgICAgICAgIF0sCiAgICAgICAgKSwKICAgICAgXSwKICAgICk7CiAgfQp9Cg==", + "e3sjYXV0aH19aW1wb3J0ICdwYWNrYWdlOmF1dGgvYXV0aC5kYXJ0JyBhcyBhdXRoOwp7ey9hdXRofX1pbXBvcnQgJ3BhY2thZ2U6ZGFzaGJvYXJkL3VpL3NjcmVlbnMvaW5kZXguZGFydCc7CmltcG9ydCAncGFja2FnZTpnb19yb3V0ZXIvZ29fcm91dGVyLmRhcnQnOwoKe3sjYXV0aH19Ly8vIERlbW8gY29udGVudCBpcyBhdmFpbGFibGUgYmVmb3JlIEZpcmViYXNlIGNvbmZpZ3VyYXRpb247IGNvbmZpZ3VyZWQgYXBwcwovLy8gcmVxdWlyZSBhIHNpZ25lZC1pbiBpZGVudGl0eS4gRG8gbm90IGVuYWJsZSB0aGlzIGJ5cGFzcyBmb3IgcHJvdGVjdGVkIGRhdGEuCnR5cGVkZWYgX1NoZWxsUm91dGUgPSBhdXRoLkdvQXV0aFJvdXRlO3t7L2F1dGh9fXt7XmF1dGh9fXR5cGVkZWYgX1NoZWxsUm91dGUgPSBHb1JvdXRlO3t7L2F1dGh9fQoKLy8vIEJvdHRvbS1uYXZpZ2F0aW9uIHNoZWxsIGZvciB0aGUgc2lnbmVkLWluIHBhcnQgb2YgdGhlIGFwcC4KLy8vCi8vLyBBZGQgYSB0YWIgYnkgYWRkaW5nIGEgW1N0YXRlZnVsU2hlbGxCcmFuY2hdIGhlcmUgYW5kIGEgZGVzdGluYXRpb24gaW4KLy8vIFtEYXNoYm9hcmRTaGVsbFNjcmVlbl0uCmFic3RyYWN0IGZpbmFsIGNsYXNzIERhc2hib2FyZFJvdXRlciB7CgogIHN0YXRpYyBjb25zdCBTdHJpbmcgaG9tZSA9ICcvaG9tZS9kYXNoYm9hcmQnOwogIHN0YXRpYyBjb25zdCBTdHJpbmcgZXhwbG9yZSA9ICcvaG9tZS9leHBsb3JlJzsKICBzdGF0aWMgY29uc3QgU3RyaW5nIHByb2ZpbGUgPSAnL2hvbWUvcHJvZmlsZSc7CgogIHN0YXRpYyBTdGF0ZWZ1bFNoZWxsUm91dGUgY3JlYXRlU2hlbGxSb3V0ZSgpIHsKICAgIHJldHVybiBTdGF0ZWZ1bFNoZWxsUm91dGUuaW5kZXhlZFN0YWNrKAogICAgICBidWlsZGVyOiAoY29udGV4dCwgc3RhdGUsIG5hdmlnYXRpb25TaGVsbCkgPT4KICAgICAgICAgIERhc2hib2FyZFNoZWxsU2NyZWVuKG5hdmlnYXRpb25TaGVsbDogbmF2aWdhdGlvblNoZWxsKSwKICAgICAgYnJhbmNoZXM6IFsKICAgICAgICBTdGF0ZWZ1bFNoZWxsQnJhbmNoKAogICAgICAgICAgcm91dGVzOiBbCiAgICAgICAgICAgIF9TaGVsbFJvdXRlKAp7eyNhdXRofX0gICAgICAgICAgICAgIGFsbG93VW5jb25maWd1cmVkOiB0cnVlLAp7ey9hdXRofX0gICAgICAgICAgICAgIHBhdGg6IGhvbWUsCiAgICAgICAgICAgICAgYnVpbGRlcjogKGNvbnRleHQsIHN0YXRlKSA9PiBjb25zdCBIb21lVGFiU2NyZWVuKCksCiAgICAgICAgICAgICksCiAgICAgICAgICBdLAogICAgICAgICksCiAgICAgICAgU3RhdGVmdWxTaGVsbEJyYW5jaCgKICAgICAgICAgIHJvdXRlczogWwogICAgICAgICAgICBfU2hlbGxSb3V0ZSgKe3sjYXV0aH19ICAgICAgICAgICAgICBhbGxvd1VuY29uZmlndXJlZDogdHJ1ZSwKe3svYXV0aH19ICAgICAgICAgICAgICBwYXRoOiBleHBsb3JlLAogICAgICAgICAgICAgIGJ1aWxkZXI6IChjb250ZXh0LCBzdGF0ZSkgPT4gY29uc3QgRXhwbG9yZVRhYlNjcmVlbigpLAogICAgICAgICAgICApLAogICAgICAgICAgXSwKICAgICAgICApLAogICAgICAgIFN0YXRlZnVsU2hlbGxCcmFuY2goCiAgICAgICAgICByb3V0ZXM6IFsKICAgICAgICAgICAgX1NoZWxsUm91dGUoCnt7I2F1dGh9fSAgICAgICAgICAgICAgYWxsb3dVbmNvbmZpZ3VyZWQ6IHRydWUsCnt7L2F1dGh9fSAgICAgICAgICAgICAgcGF0aDogcHJvZmlsZSwKICAgICAgICAgICAgICBidWlsZGVyOiAoY29udGV4dCwgc3RhdGUpID0+IGNvbnN0IFByb2ZpbGVUYWJTY3JlZW4oKSwKICAgICAgICAgICAgKSwKICAgICAgICAgIF0sCiAgICAgICAgKSwKICAgICAgXSwKICAgICk7CiAgfQp9Cg==", "type": "text" }, { @@ -300,10 +368,17 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "IyBEYXNoYm9hcmQKCkRhc2hib2FyZCBmZWF0dXJlIHdpdGggYm90dG9tIG5hdmlnYXRpb24KClshW25vbnN0b3BfY2xpXShodHRwczovL2ltZy5zaGllbGRzLmlvL2JhZGdlL3N0YXJ0ZWQlMjB3aXRoLW5vbnN0b3BfY2xpLTE2NkM0RS5zdmc/c3R5bGU9ZmxhdC1zcXVhcmUpXShodHRwczovL3B1Yi5kZXYvcGFja2FnZXMvbm9uc3RvcF9jbGkpClshW21lbG9zXShodHRwczovL2ltZy5zaGllbGRzLmlvL2JhZGdlL21haW50YWluZWQlMjB3aXRoLW1lbG9zLWY3MDBmZi5zdmc/c3R5bGU9ZmxhdC1zcXVhcmUpXShodHRwczovL2dpdGh1Yi5jb20vaW52ZXJ0YXNlL21lbG9zKQoKIyMgSW5zdGFsbGF0aW9uIPCfkrsKCioq4p2XIEluIG9yZGVyIHRvIHN0YXJ0IHVzaW5nIERhc2hib2FyZCB5b3UgbXVzdCBoYXZlIHRoZSBbRmx1dHRlciBTREtdW2ZsdXR0ZXJfaW5zdGFsbF9saW5rXSBpbnN0YWxsZWQgb24geW91ciBtYWNoaW5lLioqCgpJbnN0YWxsIHZpYSBgZGFydCBwdWIgYWRkYDoKCmBgYHNoCmRhcnQgcHViIGFkZCBkYXNoYm9hcmQKYGBgCgpbZmx1dHRlcl9pbnN0YWxsX2xpbmtdOiBodHRwczovL2RvY3MuZmx1dHRlci5kZXYvZ2V0LXN0YXJ0ZWQvaW5zdGFsbA==", "type": "text" }, + { + "path": + "{{ name.snakeCase() }}/features/{{dashboard_dir}}/test/dashboard_test.dart", + "data": + "e3sjYXV0aH19aW1wb3J0ICdwYWNrYWdlOmF1dGgvYXV0aC5kYXJ0JyBhcyBhdXRoOwp7ey9hdXRofX0KaW1wb3J0ICdwYWNrYWdlOmNvcmUvY29yZS5kYXJ0JyBhcyBjb3JlOwppbXBvcnQgJ3BhY2thZ2U6ZGFzaGJvYXJkL2Rhc2hib2FyZC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlci9tYXRlcmlhbC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZsdXR0ZXJfdGVzdC9mbHV0dGVyX3Rlc3QuZGFydCc7CmltcG9ydCAncGFja2FnZTpnb19yb3V0ZXIvZ29fcm91dGVyLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6bG9jYWxpemF0aW9uL2xvY2FsaXphdGlvbi5kYXJ0JzsKCnt7I2F1dGh9fWNsYXNzIF9BdXRoIGltcGxlbWVudHMgYXV0aC5BdXRoU2VydmljZSB7CiAgaW50IHNpZ25PdXRzID0gMDsKICBAb3ZlcnJpZGUKICBTdHJpbmcgZ2V0IHVpZCA9PiAndGVzdCc7CiAgQG92ZXJyaWRlCiAgYm9vbCBnZXQgaXNTaWduZWRJbiA9PiB0cnVlOwogIEBvdmVycmlkZQogIEZ1dHVyZTx2b2lkPiBzaWduT3V0KCkgYXN5bmMgewogICAgc2lnbk91dHMrKzsKICB9Cn0KCnt7L2F1dGh9fXZvaWQgbWFpbigpIHsKICBzZXRVcChjb3JlLmluaXQpOwogIHRlYXJEb3duKGRpLnJlc2V0KTsKCiAgdGVzdFdpZGdldHMoJ3RhYnMgbmF2aWdhdGUgYW5kIHByb2ZpbGUgc2lnbi1vdXQgcmVxdWlyZXMgY29uZmlybWF0aW9uJywgKAogICAgdGVzdGVyLAogICkgYXN5bmMgewp7eyNhdXRofX0gICAgZmluYWwgc2VydmljZSA9IF9BdXRoKCk7CiAgICBkaS5yZWdpc3RlcjxhdXRoLkF1dGhTZXJ2aWNlPihzZXJ2aWNlKTsKe3svYXV0aH19ICAgIGZpbmFsIHJvdXRlciA9IEdvUm91dGVyKAogICAgICBpbml0aWFsTG9jYXRpb246IERhc2hib2FyZFJvdXRlci5ob21lLAogICAgICByb3V0ZXM6IFsKICAgICAgICBEYXNoYm9hcmRSb3V0ZXIuY3JlYXRlU2hlbGxSb3V0ZSgpLAp7eyNhdXRofX0gICAgICAgIEdvUm91dGUoCiAgICAgICAgICBwYXRoOiBhdXRoLkF1dGhSb3V0ZXMuc2lnbkluLAogICAgICAgICAgYnVpbGRlcjogKF8sIF8pID0+IGNvbnN0IFRleHQoJ1NpZ25lZCBvdXQnKSwKICAgICAgICApLAp7ey9hdXRofX0gICAgICBdLAogICAgKTsKICAgIGFkZFRlYXJEb3duKHJvdXRlci5kaXNwb3NlKTsKICAgIGF3YWl0IHRlc3Rlci5wdW1wV2lkZ2V0KE1hdGVyaWFsQXBwLnJvdXRlcihyb3V0ZXJDb25maWc6IHJvdXRlcikpOwogICAgYXdhaXQgdGVzdGVyLnB1bXBBbmRTZXR0bGUoKTsKICAgIGV4cGVjdCgKICAgICAgcm91dGVyLnJvdXRlSW5mb3JtYXRpb25Qcm92aWRlci52YWx1ZS51cmkucGF0aCwKICAgICAgRGFzaGJvYXJkUm91dGVyLmhvbWUsCiAgICApOwogICAgYXdhaXQgdGVzdGVyLnRhcChmaW5kLnRleHQoJ0V4cGxvcmUnKS5sYXN0KTsKICAgIGF3YWl0IHRlc3Rlci5wdW1wQW5kU2V0dGxlKCk7CiAgICBleHBlY3QoCiAgICAgIHJvdXRlci5yb3V0ZUluZm9ybWF0aW9uUHJvdmlkZXIudmFsdWUudXJpLnBhdGgsCiAgICAgIERhc2hib2FyZFJvdXRlci5leHBsb3JlLAogICAgKTsKICAgIGF3YWl0IHRlc3Rlci50YXAoZmluZC50ZXh0KHN0cmluZ3MubmF2LnByb2ZpbGUpLmxhc3QpOwogICAgYXdhaXQgdGVzdGVyLnB1bXBBbmRTZXR0bGUoKTsKICAgIGV4cGVjdCgKICAgICAgcm91dGVyLnJvdXRlSW5mb3JtYXRpb25Qcm92aWRlci52YWx1ZS51cmkucGF0aCwKICAgICAgRGFzaGJvYXJkUm91dGVyLnByb2ZpbGUsCiAgICApOwogICAgYXdhaXQgdGVzdGVyLnRhcChmaW5kLnRleHQoc3RyaW5ncy5wcm9maWxlLnNldHRpbmdzKSk7Cnt7I2F1dGh9fSAgICBhd2FpdCB0ZXN0ZXIudGFwKGZpbmQudGV4dChzdHJpbmdzLmF1dGguc2lnbl9vdXQpKTsKICAgIGF3YWl0IHRlc3Rlci5wdW1wQW5kU2V0dGxlKCk7CiAgICBhd2FpdCB0ZXN0ZXIudGFwKGZpbmQudGV4dChzdHJpbmdzLmdlbmVyaWMuY2FuY2VsKSk7CiAgICBhd2FpdCB0ZXN0ZXIucHVtcEFuZFNldHRsZSgpOwogICAgZXhwZWN0KHNlcnZpY2Uuc2lnbk91dHMsIDApOwogICAgYXdhaXQgdGVzdGVyLnRhcChmaW5kLnRleHQoc3RyaW5ncy5hdXRoLnNpZ25fb3V0KSk7CiAgICBhd2FpdCB0ZXN0ZXIucHVtcEFuZFNldHRsZSgpOwogICAgYXdhaXQgdGVzdGVyLnRhcChmaW5kLndpZGdldFdpdGhUZXh0KEZpbGxlZEJ1dHRvbiwgc3RyaW5ncy5hdXRoLnNpZ25fb3V0KSk7CiAgICBhd2FpdCB0ZXN0ZXIucHVtcEFuZFNldHRsZSgpOwogICAgZXhwZWN0KHNlcnZpY2Uuc2lnbk91dHMsIDEpOwogICAgZXhwZWN0KGZpbmQudGV4dCgnU2lnbmVkIG91dCcpLCBmaW5kc09uZVdpZGdldCk7Cnt7L2F1dGh9fSAgfSk7CgogIHRlc3RXaWRnZXRzKCdwbGFjZWhvbGRlciBzdXBwb3J0cyBhbiBhY3Rpb24nLCAodGVzdGVyKSBhc3luYyB7CiAgICB2YXIgY2FsbHMgPSAwOwogICAgYXdhaXQgdGVzdGVyLnB1bXBXaWRnZXQoCiAgICAgIE1hdGVyaWFsQXBwKAogICAgICAgIGhvbWU6IFNjYWZmb2xkKAogICAgICAgICAgYm9keTogUGxhY2Vob2xkZXJUYWIoCiAgICAgICAgICAgIGljb246IEljb25zLmFkZCwKICAgICAgICAgICAgdGl0bGU6ICdUaXRsZScsCiAgICAgICAgICAgIHN1YnRpdGxlOiAnU3VidGl0bGUnLAogICAgICAgICAgICBhY3Rpb246IFRleHRCdXR0b24oCiAgICAgICAgICAgICAgb25QcmVzc2VkOiAoKSB7CiAgICAgICAgICAgICAgICBjYWxscysrOwogICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgY2hpbGQ6IGNvbnN0IFRleHQoJ1N0YXJ0JyksCiAgICAgICAgICAgICksCiAgICAgICAgICApLAogICAgICAgICksCiAgICAgICksCiAgICApOwogICAgYXdhaXQgdGVzdGVyLnRhcChmaW5kLnRleHQoJ1N0YXJ0JykpOwogICAgZXhwZWN0KGNhbGxzLCAxKTsKICB9KTsKfQo=", + "type": "text" + }, { "path": "{{ name.snakeCase() }}/melos.yaml", "data": - "bmFtZToge3sgbmFtZS5zbmFrZUNhc2UoKSB9fV93b3Jrc3BhY2UKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBNT05PUkVQTyBDT05GSUdVUkFUSU9OCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBhcHBzLyAgICAgLSBydW5uYWJsZSBGbHV0dGVyIGFwcGxpY2F0aW9ucwojIGZlYXR1cmVzLyAtIHZlcnRpY2FsIHNsaWNlcyAodWkgKyBzdGF0ZSArIGRhdGEpIHRoYXQgYW4gYXBwIGNvbXBvc2VzCiMgcGFja2FnZXMvIC0gaG9yaXpvbnRhbCBjYXBhYmlsaXRpZXMgc2hhcmVkIGJ5IGZlYXR1cmVzIChuZXR3b3JrLCBkZXNpZ24sIC4uLikKIyBwbHVnaW5zLyAgLSBwbGF0Zm9ybSBjaGFubmVscyBhbmQgbmF0aXZlIGludGVncmF0aW9ucwpwYWNrYWdlczoKICAtIGFwcHMvKgogIC0gZmVhdHVyZXMvKgogIC0gcGFja2FnZXMvKgogIC0gcGx1Z2lucy8qCgpjb21tYW5kOgogIGJvb3RzdHJhcDoKICAgIGRlcGVuZGVuY2llczoKICAgICAganNvbl9hbm5vdGF0aW9uOiBeNC45LjAKICAgIGRldl9kZXBlbmRlbmNpZXM6CiAgICAgIGJ1aWxkX3J1bm5lcjogXjIuNC4xNQogICAgICBmbHV0dGVyX2xpbnRzOiBeNS4wLjAKICAgICAganNvbl9zZXJpYWxpemFibGU6IF42LjkuNQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIFNDUklQVFMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpzY3JpcHRzOgogIGNsZWFuOmZsdXR0ZXI6CiAgICBkZXNjcmlwdGlvbjogIlJ1biBmbHV0dGVyIGNsZWFuIGluIGFsbCBGbHV0dGVyIHBhY2thZ2VzIgogICAgcnVuOiBmbHV0dGVyIGNsZWFuCiAgICBleGVjOgogICAgICBjb25jdXJyZW5jeTogNAogICAgcGFja2FnZUZpbHRlcnM6CiAgICAgIGZsdXR0ZXI6IHRydWUKCiAgbGludDoKICAgIGRlc2NyaXB0aW9uOiAiUnVuIGZvcm1hdCBhbmQgYW5hbHl6ZSBhbGwgcGFja2FnZXMiCiAgICAjIGBkYXJ0IGZvcm1hdGAgaGFzIG5vIGV4Y2x1ZGUgb2YgaXRzIG93biwgc28gYnVpbGQgb3V0cHV0IGFuZCB0aGUgcGx1Z2luCiAgICAjIHNvdXJjZXMgQ29jb2FQb2RzIHN5bWxpbmtzIGludG8gdGhlIGFwcCBhcmUgZmlsdGVyZWQgb3V0IGhlcmUuCiAgICBydW46IHwKICAgICAgZmluZCAuIC1uYW1lICcqLmRhcnQnIC1ub3QgLXBhdGggJyovYnVpbGQvKicgLW5vdCAtcGF0aCAnKi8uZGFydF90b29sLyonIFwKICAgICAgICAtbm90IC1wYXRoICcqLy5zeW1saW5rcy8qJyAtZXhlYyBkYXJ0IGZvcm1hdCAtLXNldC1leGl0LWlmLWNoYW5nZWQge30gKyAmJgogICAgICBkYXJ0IGFuYWx5emUgLS1mYXRhbC1pbmZvcyAuCiAgICBleGVjOgogICAgICBjb25jdXJyZW5jeTogNQogICAgICBmYWlsRmFzdDogdHJ1ZQoKICBmaXg6CiAgICBkZXNjcmlwdGlvbjogIkFwcGx5IERhcnQgYXV0b21hdGVkIGZpeGVzIHRvIGFsbCBwYWNrYWdlcyIKICAgIHJ1bjogZGFydCBmaXggLS1hcHBseQogICAgZXhlYzoKICAgICAgY29uY3VycmVuY3k6IDUKICAgIHBhY2thZ2VGaWx0ZXJzOgogICAgICBkaXJFeGlzdHM6IGxpYgoKICBmaXg6ZHJ5OgogICAgZGVzY3JpcHRpb246ICJTaG93IERhcnQgYXV0b21hdGVkIGZpeGVzIHdpdGhvdXQgYXBwbHlpbmcgdGhlbSIKICAgIHJ1bjogZGFydCBmaXggLS1kcnktcnVuCiAgICBleGVjOgogICAgICBjb25jdXJyZW5jeTogNQogICAgcGFja2FnZUZpbHRlcnM6CiAgICAgIGRpckV4aXN0czogbGliCgogIGdlbmVyYXRlOgogICAgZGVzY3JpcHRpb246ICJSdW4gYnVpbGRfcnVubmVyIGluIGV2ZXJ5IHBhY2thZ2UgdGhhdCBuZWVkcyBjb2RlZ2VuIgogICAgcnVuOiBkYXJ0IHJ1biBidWlsZF9ydW5uZXIgYnVpbGQgLS1kZWxldGUtY29uZmxpY3Rpbmctb3V0cHV0cwogICAgZXhlYzoKICAgICAgY29uY3VycmVuY3k6IDEKICAgIHBhY2thZ2VGaWx0ZXJzOgogICAgICBkZXBlbmRzT246IGJ1aWxkX3J1bm5lcgoKICBnZW5lcmF0ZTppNjluOgogICAgZGVzY3JpcHRpb246ICJSZWdlbmVyYXRlIGxvY2FsaXphdGlvbiBzdHJpbmdzIGZyb20gbWVzc2FnZXMuaTY5bi55YW1sIgogICAgcnVuOiB8CiAgICAgIGRhcnQgcnVuIGJ1aWxkX3J1bm5lciBidWlsZCAtLWRlbGV0ZS1jb25mbGljdGluZy1vdXRwdXRzICYmCiAgICAgIGRhcnQgZm9ybWF0IGxpYi9tZXNzYWdlcy5pNjluLmRhcnQKICAgIGV4ZWM6CiAgICAgIGNvbmN1cnJlbmN5OiAxCiAgICBwYWNrYWdlRmlsdGVyczoKICAgICAgc2NvcGU6ICJsb2NhbGl6YXRpb24iCgogIHRlc3Q6CiAgICBkZXNjcmlwdGlvbjogIlJ1biBhbGwgdGVzdHMgKERhcnQgYW5kIEZsdXR0ZXIpIgogICAgcnVuOiBtZWxvcyBydW4gdGVzdDpzZWxlY3QgLS1uby1zZWxlY3QKCiAgdGVzdDpzZWxlY3Q6CiAgICBkZXNjcmlwdGlvbjogIlJ1biB0ZXN0cyBpbiBGbHV0dGVyIHBhY2thZ2VzIgogICAgcnVuOiBmbHV0dGVyIHRlc3QgLS1jb3ZlcmFnZQogICAgZXhlYzoKICAgICAgY29uY3VycmVuY3k6IDUKICAgICAgZmFpbEZhc3Q6IHRydWUKICAgIHBhY2thZ2VGaWx0ZXJzOgogICAgICBkaXJFeGlzdHM6IHRlc3QKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBJREUgQ09ORklHVVJBVElPTgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCmlkZToKICBpbnRlbGxpajoKICAgIGVuYWJsZWQ6IHRydWUKICAgIG1vZHVsZU5hbWVQcmVmaXg6ICcnCg==", + "bmFtZToge3sgbmFtZS5zbmFrZUNhc2UoKSB9fV93b3Jrc3BhY2UKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBNT05PUkVQTyBDT05GSUdVUkFUSU9OCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBhcHBzLyAgICAgLSBydW5uYWJsZSBGbHV0dGVyIGFwcGxpY2F0aW9ucwojIGZlYXR1cmVzLyAtIHZlcnRpY2FsIHNsaWNlcyAodWkgKyBzdGF0ZSArIGRhdGEpIHRoYXQgYW4gYXBwIGNvbXBvc2VzCiMgcGFja2FnZXMvIC0gaG9yaXpvbnRhbCBjYXBhYmlsaXRpZXMgc2hhcmVkIGJ5IGZlYXR1cmVzIChuZXR3b3JrLCBkZXNpZ24sIC4uLikKIyBwbHVnaW5zLyAgLSBwbGF0Zm9ybSBjaGFubmVscyBhbmQgbmF0aXZlIGludGVncmF0aW9ucwpwYWNrYWdlczoKICAtIGFwcHMvKgogIC0gZmVhdHVyZXMvKgogIC0gcGFja2FnZXMvKgogIC0gcGx1Z2lucy8qCgpjb21tYW5kOgogIGJvb3RzdHJhcDoKICAgIGRlcGVuZGVuY2llczoKICAgICAganNvbl9hbm5vdGF0aW9uOiBeNC45LjAKICAgIGRldl9kZXBlbmRlbmNpZXM6CiAgICAgIGJ1aWxkX3J1bm5lcjogXjIuNC4xNQogICAgICBmbHV0dGVyX2xpbnRzOiBeNS4wLjAKICAgICAganNvbl9zZXJpYWxpemFibGU6IF42LjkuNQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIFNDUklQVFMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpzY3JpcHRzOgogIGNsZWFuOmZsdXR0ZXI6CiAgICBkZXNjcmlwdGlvbjogIlJ1biBmbHV0dGVyIGNsZWFuIGluIGFsbCBGbHV0dGVyIHBhY2thZ2VzIgogICAgcnVuOiBmbHV0dGVyIGNsZWFuCiAgICBleGVjOgogICAgICBjb25jdXJyZW5jeTogNAogICAgcGFja2FnZUZpbHRlcnM6CiAgICAgIGZsdXR0ZXI6IHRydWUKCiAgbGludDoKICAgIGRlc2NyaXB0aW9uOiAiQ2hlY2sgZm9ybWF0dGluZyBhbmQgYW5hbHl6ZSBhbGwgd29ya3NwYWNlIGNvZGUiCiAgICBydW46IGRhcnQgcnVuIHRvb2wvY2hlY2suZGFydAoKICBmaXg6CiAgICBkZXNjcmlwdGlvbjogIkFwcGx5IERhcnQgYXV0b21hdGVkIGZpeGVzIHRvIGFsbCBwYWNrYWdlcyIKICAgIHJ1bjogZGFydCBmaXggLS1hcHBseQogICAgZXhlYzoKICAgICAgY29uY3VycmVuY3k6IDUKICAgIHBhY2thZ2VGaWx0ZXJzOgogICAgICBkaXJFeGlzdHM6IGxpYgoKICBmaXg6ZHJ5OgogICAgZGVzY3JpcHRpb246ICJTaG93IERhcnQgYXV0b21hdGVkIGZpeGVzIHdpdGhvdXQgYXBwbHlpbmcgdGhlbSIKICAgIHJ1bjogZGFydCBmaXggLS1kcnktcnVuCiAgICBleGVjOgogICAgICBjb25jdXJyZW5jeTogNQogICAgcGFja2FnZUZpbHRlcnM6CiAgICAgIGRpckV4aXN0czogbGliCgogIGdlbmVyYXRlOgogICAgZGVzY3JpcHRpb246ICJSdW4gYnVpbGRfcnVubmVyIGluIGV2ZXJ5IHBhY2thZ2UgdGhhdCBuZWVkcyBjb2RlZ2VuIgogICAgcnVuOiBkYXJ0IHJ1biBidWlsZF9ydW5uZXIgYnVpbGQgLS1kZWxldGUtY29uZmxpY3Rpbmctb3V0cHV0cwogICAgZXhlYzoKICAgICAgY29uY3VycmVuY3k6IDEKICAgIHBhY2thZ2VGaWx0ZXJzOgogICAgICBkZXBlbmRzT246IGJ1aWxkX3J1bm5lcgoKICBnZW5lcmF0ZTppNjluOgogICAgZGVzY3JpcHRpb246ICJSZWdlbmVyYXRlIGxvY2FsaXphdGlvbiBzdHJpbmdzIGZyb20gbWVzc2FnZXMuaTY5bi55YW1sIgogICAgcnVuOiB8CiAgICAgIGRhcnQgcnVuIGJ1aWxkX3J1bm5lciBidWlsZCAtLWRlbGV0ZS1jb25mbGljdGluZy1vdXRwdXRzICYmCiAgICAgIGRhcnQgZm9ybWF0IGxpYi9tZXNzYWdlcy5pNjluLmRhcnQKICAgIGV4ZWM6CiAgICAgIGNvbmN1cnJlbmN5OiAxCiAgICBwYWNrYWdlRmlsdGVyczoKICAgICAgc2NvcGU6ICJsb2NhbGl6YXRpb24iCgogIHRlc3Q6CiAgICBkZXNjcmlwdGlvbjogIlJ1biBhbGwgdGVzdHMgKERhcnQgYW5kIEZsdXR0ZXIpIgogICAgcnVuOiBkYXJ0IHJ1biBtZWxvcyBydW4gdGVzdDpzZWxlY3QgLS1uby1zZWxlY3QKCiAgY292ZXJhZ2U6CiAgICBkZXNjcmlwdGlvbjogIlJ1biBldmVyeSB0ZXN0IGFuZCByZXF1aXJlIDEwMCUgaGFuZHdyaXR0ZW4gbGluZSBjb3ZlcmFnZSIKICAgIHJ1bjogZGFydCBydW4gdG9vbC9jb3ZlcmFnZS5kYXJ0CgogIHRlc3Q6c2VsZWN0OgogICAgZGVzY3JpcHRpb246ICJSdW4gdGVzdHMgaW4gRmx1dHRlciBwYWNrYWdlcyIKICAgIHJ1bjogZmx1dHRlciB0ZXN0IC0tY292ZXJhZ2UKICAgIGV4ZWM6CiAgICAgIGNvbmN1cnJlbmN5OiA1CiAgICAgIGZhaWxGYXN0OiB0cnVlCiAgICBwYWNrYWdlRmlsdGVyczoKICAgICAgZGlyRXhpc3RzOiB0ZXN0CgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgSURFIENPTkZJR1VSQVRJT04KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwppZGU6CiAgaW50ZWxsaWo6CiAgICBlbmFibGVkOiB0cnVlCiAgICBtb2R1bGVOYW1lUHJlZml4OiAnJwo=", "type": "text" }, { @@ -343,14 +418,14 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "path": "{{ name.snakeCase() }}/packages/core/lib/constants/defaults.dart", "data": - "Ly8vIEFwcC13aWRlIGRlZmF1bHQgdmFsdWVzLgpjbGFzcyBEZWZhdWx0cyB7CiAgRGVmYXVsdHMuXygpOwoKICBzdGF0aWMgY29uc3QgaW50IGRlZmF1bHRQYWdlU2l6ZSA9IDIwOwp9Cg==", + "Ly8vIEFwcC13aWRlIGRlZmF1bHQgdmFsdWVzLgphYnN0cmFjdCBmaW5hbCBjbGFzcyBEZWZhdWx0cyB7CiAgc3RhdGljIGNvbnN0IGludCBkZWZhdWx0UGFnZVNpemUgPSAyMDsKfQo=", "type": "text" }, { "path": "{{ name.snakeCase() }}/packages/core/lib/constants/environment.dart", "data": - "Ly8vIEJ1aWxkLXRpbWUgY29uZmlndXJhdGlvbi4KLy8vCi8vLyBFdmVyeSB2YWx1ZSBpcyBhIGAtLWRhcnQtZGVmaW5lYCwgc28gdGhlIHNhbWUgYmluYXJ5IGNhbiBiZSBwb2ludGVkIGF0IGEKLy8vIGRpZmZlcmVudCBiYWNrZW5kIHdpdGhvdXQgYSBjb2RlIGNoYW5nZToKLy8vCi8vLyBgYGBzaAovLy8gZmx1dHRlciBydW4gLS1kYXJ0LWRlZmluZT1CQVNFX1VSTD1odHRwczovL3N0YWdpbmcuZXhhbXBsZS5jb20KLy8vIGBgYApjbGFzcyBFbnZpcm9ubWVudCB7CiAgRW52aXJvbm1lbnQuXygpOwoKICBzdGF0aWMgY29uc3QgYm9vbCB1c2VFbXVsYXRvcnMgPSBib29sLmZyb21FbnZpcm9ubWVudCgnVVNFX0VNVUxBVE9SUycpOwoKICBzdGF0aWMgY29uc3QgU3RyaW5nIGJhc2VVcmwgPSBTdHJpbmcuZnJvbUVudmlyb25tZW50KAogICAgJ0JBU0VfVVJMJywKICAgIGRlZmF1bHRWYWx1ZTogJ2h0dHBzOi8vYXBpLmV4YW1wbGUuY29tJywKICApOwp9Cg==", + "Ly8vIEJ1aWxkLXRpbWUgY29uZmlndXJhdGlvbi4KLy8vCi8vLyBFdmVyeSB2YWx1ZSBpcyBhIGAtLWRhcnQtZGVmaW5lYCwgc28gdGhlIHNhbWUgYmluYXJ5IGNhbiBiZSBwb2ludGVkIGF0IGEKLy8vIGRpZmZlcmVudCBiYWNrZW5kIHdpdGhvdXQgYSBjb2RlIGNoYW5nZToKLy8vCi8vLyBgYGBzaAovLy8gZmx1dHRlciBydW4gLS1kYXJ0LWRlZmluZT1CQVNFX1VSTD1odHRwczovL3N0YWdpbmcuZXhhbXBsZS5jb20KLy8vIGBgYAphYnN0cmFjdCBmaW5hbCBjbGFzcyBFbnZpcm9ubWVudCB7CiAgc3RhdGljIGNvbnN0IGJvb2wgdXNlRW11bGF0b3JzID0gYm9vbC5mcm9tRW52aXJvbm1lbnQoJ1VTRV9FTVVMQVRPUlMnKTsKCiAgc3RhdGljIGNvbnN0IFN0cmluZyBiYXNlVXJsID0gU3RyaW5nLmZyb21FbnZpcm9ubWVudCgKICAgICdCQVNFX1VSTCcsCiAgICBkZWZhdWx0VmFsdWU6ICdodHRwczovL2FwaS5leGFtcGxlLmNvbScsCiAgKTsKfQo=", "type": "text" }, { @@ -362,20 +437,20 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ { "path": "{{ name.snakeCase() }}/packages/core/lib/constants/keys.dart", "data": - "Ly8vIFF1ZXJ5LXBhcmFtZXRlciBhbmQgYGV4dHJhYCBrZXlzIHNoYXJlZCBiZXR3ZWVuIHJvdXRlcnMgYW5kIHNjcmVlbnMuCi8vLwovLy8gS2VlcCB0aGVzZSBoZXJlIHJhdGhlciB0aGFuIGlubGluZSBzbyBhIHJlbmFtZSBpcyBhIHNpbmdsZSBlZGl0LgpjbGFzcyBLZXlzIHsKICBLZXlzLl8oKTsKCiAgc3RhdGljIGNvbnN0IFN0cmluZyBlbWFpbCA9ICdlbWFpbCc7CiAgc3RhdGljIGNvbnN0IFN0cmluZyB0aXRsZSA9ICd0aXRsZSc7CiAgc3RhdGljIGNvbnN0IFN0cmluZyBtZXNzYWdlID0gJ21lc3NhZ2UnOwogIHN0YXRpYyBjb25zdCBTdHJpbmcgZXJyb3IgPSAnZXJyb3InOwp9Cg==", + "Ly8vIFF1ZXJ5LXBhcmFtZXRlciBhbmQgYGV4dHJhYCBrZXlzIHNoYXJlZCBiZXR3ZWVuIHJvdXRlcnMgYW5kIHNjcmVlbnMuCi8vLwovLy8gS2VlcCB0aGVzZSBoZXJlIHJhdGhlciB0aGFuIGlubGluZSBzbyBhIHJlbmFtZSBpcyBhIHNpbmdsZSBlZGl0LgphYnN0cmFjdCBmaW5hbCBjbGFzcyBLZXlzIHsKICBzdGF0aWMgY29uc3QgU3RyaW5nIGVtYWlsID0gJ2VtYWlsJzsKICBzdGF0aWMgY29uc3QgU3RyaW5nIHRpdGxlID0gJ3RpdGxlJzsKICBzdGF0aWMgY29uc3QgU3RyaW5nIG1lc3NhZ2UgPSAnbWVzc2FnZSc7CiAgc3RhdGljIGNvbnN0IFN0cmluZyBlcnJvciA9ICdlcnJvcic7Cn0K", "type": "text" }, { "path": "{{ name.snakeCase() }}/packages/core/lib/constants/routes.dart", "data": - "Ly8vIFBhdGhzIG93bmVkIGJ5IHRoZSBhcHAgc2hlbGwgaXRzZWxmLgovLy8KLy8vIEZlYXR1cmUgcGFja2FnZXMgZGVjbGFyZSB0aGVpciBvd24gcm91dGUgY29uc3RhbnRzOyB0aGVzZSBhcmUgdGhlIG9uZXMKLy8vIGV2ZXJ5IGFwcCBoYXMuCmNsYXNzIENvcmVSb3V0ZXMgewogIENvcmVSb3V0ZXMuXygpOwoKICBzdGF0aWMgY29uc3QgU3RyaW5nIHJvb3QgPSAnLyc7CiAgc3RhdGljIGNvbnN0IFN0cmluZyBob21lID0gJy9ob21lJzsKICBzdGF0aWMgY29uc3QgU3RyaW5nIGRhc2hib2FyZCA9ICcvaG9tZS9kYXNoYm9hcmQnOwogIHN0YXRpYyBjb25zdCBTdHJpbmcgcHJvZmlsZSA9ICcvaG9tZS9wcm9maWxlJzsKICBzdGF0aWMgY29uc3QgU3RyaW5nIGVycm9yID0gJy9lcnJvcic7Cn0K", + "Ly8vIFBhdGhzIG93bmVkIGJ5IHRoZSBhcHAgc2hlbGwgaXRzZWxmLgovLy8KLy8vIEZlYXR1cmUgcGFja2FnZXMgZGVjbGFyZSB0aGVpciBvd24gcm91dGUgY29uc3RhbnRzOyB0aGVzZSBhcmUgdGhlIG9uZXMKLy8vIGV2ZXJ5IGFwcCBoYXMuCmFic3RyYWN0IGZpbmFsIGNsYXNzIENvcmVSb3V0ZXMgewogIHN0YXRpYyBjb25zdCBTdHJpbmcgcm9vdCA9ICcvJzsKICBzdGF0aWMgY29uc3QgU3RyaW5nIGhvbWUgPSAnL2hvbWUnOwogIHN0YXRpYyBjb25zdCBTdHJpbmcgZGFzaGJvYXJkID0gJy9ob21lL2Rhc2hib2FyZCc7CiAgc3RhdGljIGNvbnN0IFN0cmluZyBwcm9maWxlID0gJy9ob21lL3Byb2ZpbGUnOwogIHN0YXRpYyBjb25zdCBTdHJpbmcgZXJyb3IgPSAnL2Vycm9yJzsKfQo=", "type": "text" }, { "path": "{{ name.snakeCase() }}/packages/core/lib/converters/datetime_converter.dart", "data": - "aW1wb3J0ICdwYWNrYWdlOmludGwvaW50bC5kYXJ0JzsKCmZpbmFsIGNsYXNzIERhdGVUaW1lQ29udmVydGVyIHsKICBjb25zdCBEYXRlVGltZUNvbnZlcnRlcigpOwoKICAvLy8gQ29udmVydHMgYSBbRGF0ZVRpbWVdIHRvIGEgW1N0cmluZ10gaW4gdGhlIGZvcm1hdCAnTU1NTSBkLCB5Jy4KICAvLy8gSWYgdGhlIFtkYXRlXSBpcyBudWxsLCBpdCByZXR1cm5zIGFuIGVtcHR5IHN0cmluZy4KICAvLy8KICAvLy8gRXhhbXBsZToKICAvLy8gYGBgZGFydAogIC8vLyBEYXRlVGltZSBkYXRlID0gRGF0ZVRpbWUubm93KCk7CiAgLy8vIFN0cmluZyBmb3JtYXR0ZWREYXRlID0gRGF0ZVRpbWVDb252ZXJ0ZXIudG9WaWV3Rm9ybWF0KGRhdGUpOwogIC8vLyBwcmludChmb3JtYXR0ZWREYXRlKTsgLy8gT3V0cHV0OiAnT2N0b2JlciAxLCAyMDIzJwogIC8vLyBgYGAKICBzdGF0aWMgU3RyaW5nIHRvVmlld0Zvcm1hdChEYXRlVGltZT8gZGF0ZSkgewogICAgaWYgKGRhdGUgPT0gbnVsbCkgcmV0dXJuICcnOwogICAgZmluYWwgZGF0ZUZvcm1hdGUgPSBEYXRlRm9ybWF0KCdNTU1NIGQsIHknKTsKCiAgICByZXR1cm4gZGF0ZUZvcm1hdGUuZm9ybWF0KGRhdGUudG9Mb2NhbCgpKTsKICB9CgogIHN0YXRpYyBTdHJpbmcgdG9WaWV3Rm9ybWF0V2l0aFRpbWUoRGF0ZVRpbWU/IGRhdGUpIHsKICAgIGlmIChkYXRlID09IG51bGwpIHJldHVybiAnJzsKICAgIGZpbmFsIGRhdGVGb3JtYXRlID0gRGF0ZUZvcm1hdCgnTU1NTSBkLCB5LCBoOm1tIGEnKTsKCiAgICByZXR1cm4gZGF0ZUZvcm1hdGUuZm9ybWF0KGRhdGUpOwogIH0KCiAgc3RhdGljIFN0cmluZyB0b1ZpZXdGb3JtYXRUaW1lKERhdGVUaW1lPyBkYXRlKSB7CiAgICBpZiAoZGF0ZSA9PSBudWxsKSByZXR1cm4gJyc7CiAgICBmaW5hbCBkYXRlRm9ybWF0ZSA9IERhdGVGb3JtYXQoJ2g6bW06c3MgYScpOwoKICAgIHJldHVybiBkYXRlRm9ybWF0ZS5mb3JtYXQoZGF0ZSk7CiAgfQp9Cg==", + "aW1wb3J0ICdwYWNrYWdlOmludGwvaW50bC5kYXJ0JzsKCmFic3RyYWN0IGZpbmFsIGNsYXNzIERhdGVUaW1lQ29udmVydGVyIHsKICAvLy8gQ29udmVydHMgYSBbRGF0ZVRpbWVdIHRvIGEgW1N0cmluZ10gaW4gdGhlIGZvcm1hdCAnTU1NTSBkLCB5Jy4KICAvLy8gSWYgdGhlIFtkYXRlXSBpcyBudWxsLCBpdCByZXR1cm5zIGFuIGVtcHR5IHN0cmluZy4KICAvLy8KICAvLy8gRXhhbXBsZToKICAvLy8gYGBgZGFydAogIC8vLyBEYXRlVGltZSBkYXRlID0gRGF0ZVRpbWUubm93KCk7CiAgLy8vIFN0cmluZyBmb3JtYXR0ZWREYXRlID0gRGF0ZVRpbWVDb252ZXJ0ZXIudG9WaWV3Rm9ybWF0KGRhdGUpOwogIC8vLyBwcmludChmb3JtYXR0ZWREYXRlKTsgLy8gT3V0cHV0OiAnT2N0b2JlciAxLCAyMDIzJwogIC8vLyBgYGAKICBzdGF0aWMgU3RyaW5nIHRvVmlld0Zvcm1hdChEYXRlVGltZT8gZGF0ZSkgewogICAgaWYgKGRhdGUgPT0gbnVsbCkgcmV0dXJuICcnOwogICAgZmluYWwgZGF0ZUZvcm1hdGUgPSBEYXRlRm9ybWF0KCdNTU1NIGQsIHknKTsKCiAgICByZXR1cm4gZGF0ZUZvcm1hdGUuZm9ybWF0KGRhdGUudG9Mb2NhbCgpKTsKICB9CgogIHN0YXRpYyBTdHJpbmcgdG9WaWV3Rm9ybWF0V2l0aFRpbWUoRGF0ZVRpbWU/IGRhdGUpIHsKICAgIGlmIChkYXRlID09IG51bGwpIHJldHVybiAnJzsKICAgIGZpbmFsIGRhdGVGb3JtYXRlID0gRGF0ZUZvcm1hdCgnTU1NTSBkLCB5LCBoOm1tIGEnKTsKCiAgICByZXR1cm4gZGF0ZUZvcm1hdGUuZm9ybWF0KGRhdGUpOwogIH0KCiAgc3RhdGljIFN0cmluZyB0b1ZpZXdGb3JtYXRUaW1lKERhdGVUaW1lPyBkYXRlKSB7CiAgICBpZiAoZGF0ZSA9PSBudWxsKSByZXR1cm4gJyc7CiAgICBmaW5hbCBkYXRlRm9ybWF0ZSA9IERhdGVGb3JtYXQoJ2g6bW06c3MgYScpOwoKICAgIHJldHVybiBkYXRlRm9ybWF0ZS5mb3JtYXQoZGF0ZSk7CiAgfQp9Cg==", "type": "text" }, { @@ -401,7 +476,7 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "path": "{{ name.snakeCase() }}/packages/core/lib/developer/emulators.dart", "data": - "e3sjZmlyZWJhc2V9fXt7I2F1dGh9fWltcG9ydCAncGFja2FnZTpmaXJlYmFzZV9hdXRoL2ZpcmViYXNlX2F1dGguZGFydCc7Cnt7L2F1dGh9fXt7I2ZpcmVzdG9yZX19aW1wb3J0ICdwYWNrYWdlOmNsb3VkX2ZpcmVzdG9yZS9jbG91ZF9maXJlc3RvcmUuZGFydCc7CmltcG9ydCAncGFja2FnZTpjbG91ZF9mdW5jdGlvbnMvY2xvdWRfZnVuY3Rpb25zLmRhcnQnOwp7ey9maXJlc3RvcmV9fWltcG9ydCAncGFja2FnZTpjb3JlL2xvZ2dlci9sb2dnZXIuZGFydCc7CmltcG9ydCAncGFja2FnZTpkaS9kaS5kYXJ0JzsKCi8vLyBQb2ludHMgZXZlcnkgRmlyZWJhc2UgU0RLIGF0IHRoZSBsb2NhbCBlbXVsYXRvciBzdWl0ZS4KLy8vCi8vLyBQb3J0cyBtYXRjaCB0aGUgZGVmYXVsdHMgaW4gYGZpcmViYXNlLmpzb25gOyBjaGFuZ2UgYm90aCB0b2dldGhlci4KRnV0dXJlPHZvaWQ+IGluaXQoKSBhc3luYyB7CiAgZmluYWwgbG9nZ2VyID0gZGkuZ2V0PExvZ2dlcj4oKTsKICBsb2dnZXIuaSgnVXNpbmcgRmlyZWJhc2UgZW11bGF0b3JzJyk7CiAgdHJ5IHsKe3sjYXV0aH19ICAgIGF3YWl0IEZpcmViYXNlQXV0aC5pbnN0YW5jZS51c2VBdXRoRW11bGF0b3IoJ2xvY2FsaG9zdCcsIDkwOTkpOwp7ey9hdXRofX17eyNmaXJlc3RvcmV9fSAgICBGaXJlYmFzZUZpcmVzdG9yZS5pbnN0YW5jZS51c2VGaXJlc3RvcmVFbXVsYXRvcignbG9jYWxob3N0JywgODA4MCk7CiAgICBGaXJlYmFzZUZ1bmN0aW9ucy5pbnN0YW5jZS51c2VGdW5jdGlvbnNFbXVsYXRvcignbG9jYWxob3N0JywgNTAwMSk7Cnt7L2ZpcmVzdG9yZX19ICAgIGxvZ2dlci5pKCdTdWNjZXNzZnVsbHkgaW5pdGlhbGlzZWQgdGhlIEZpcmViYXNlIGVtdWxhdG9ycycpOwogIH0gY2F0Y2ggKGVycm9yLCBzdGFja1RyYWNlKSB7CiAgICBsb2dnZXIuZSgnRmFpbGVkIHRvIGluaXRpYWxpc2UgdGhlIEZpcmViYXNlIGVtdWxhdG9yczonLCBlcnJvciwgc3RhY2tUcmFjZSk7CiAgfQp9Cnt7L2ZpcmViYXNlfX17e15maXJlYmFzZX19Ly8vIE5vIEZpcmViYXNlIHNlcnZpY2VzIGFyZSBlbmFibGVkIGluIHRoaXMgcHJvamVjdCwgc28gdGhlcmUgaXMgbm90aGluZyB0bwovLy8gcG9pbnQgYXQgYW4gZW11bGF0b3IuIEtlcHQgYXMgYSBuby1vcCBzbyBib290c3RyYXAgc3RheXMgdW5pZm9ybS4KRnV0dXJlPHZvaWQ+IGluaXQoKSBhc3luYyB7fQp7ey9maXJlYmFzZX19", + "e3sjZW11bGF0b3JzfX17eyNhdXRofX1pbXBvcnQgJ3BhY2thZ2U6ZmlyZWJhc2VfYXV0aC9maXJlYmFzZV9hdXRoLmRhcnQnOwp7ey9hdXRofX17eyNmaXJlc3RvcmV9fWltcG9ydCAncGFja2FnZTpjbG91ZF9maXJlc3RvcmUvY2xvdWRfZmlyZXN0b3JlLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Y2xvdWRfZnVuY3Rpb25zL2Nsb3VkX2Z1bmN0aW9ucy5kYXJ0JzsKe3svZmlyZXN0b3JlfX1pbXBvcnQgJ3BhY2thZ2U6Y29yZS9sb2dnZXIvbG9nZ2VyLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZGkvZGkuZGFydCc7CmltcG9ydCAncGFja2FnZTpmbHV0dGVyL2ZvdW5kYXRpb24uZGFydCc7CgovLy8gUG9pbnRzIGV2ZXJ5IEZpcmViYXNlIFNESyBhdCB0aGUgbG9jYWwgZW11bGF0b3Igc3VpdGUuCi8vLwovLy8gUG9ydHMgbWF0Y2ggdGhlIGRlZmF1bHRzIGluIGBmaXJlYmFzZS5qc29uYDsgY2hhbmdlIGJvdGggdG9nZXRoZXIuCkZ1dHVyZTx2b2lkPiBpbml0KHtTdHJpbmc/IGhvc3R9KSBhc3luYyB7CiAgZmluYWwgbG9nZ2VyID0gZGkuZ2V0PExvZ2dlcj4oKTsKICBmaW5hbCBlbXVsYXRvckhvc3QgPSBob3N0ID8/ICgha0lzV2ViICYmIGRlZmF1bHRUYXJnZXRQbGF0Zm9ybSA9PSBUYXJnZXRQbGF0Zm9ybS5hbmRyb2lkID8gJzEwLjAuMi4yJyA6ICdsb2NhbGhvc3QnKTsKICBsb2dnZXIuaSgnVXNpbmcgRmlyZWJhc2UgZW11bGF0b3JzJyk7CiAgdHJ5IHsKe3sjYXV0aH19ICAgIGF3YWl0IEZpcmViYXNlQXV0aC5pbnN0YW5jZS51c2VBdXRoRW11bGF0b3IoZW11bGF0b3JIb3N0LCA5MDk5KTsKe3svYXV0aH19e3sjZmlyZXN0b3JlfX0gICAgRmlyZWJhc2VGaXJlc3RvcmUuaW5zdGFuY2UudXNlRmlyZXN0b3JlRW11bGF0b3IoZW11bGF0b3JIb3N0LCA4MDgwKTsKICAgIEZpcmViYXNlRnVuY3Rpb25zLmluc3RhbmNlLnVzZUZ1bmN0aW9uc0VtdWxhdG9yKGVtdWxhdG9ySG9zdCwgNTAwMSk7Cnt7L2ZpcmVzdG9yZX19ICAgIGxvZ2dlci5pKCdTdWNjZXNzZnVsbHkgaW5pdGlhbGlzZWQgdGhlIEZpcmViYXNlIGVtdWxhdG9ycycpOwogIH0gY2F0Y2ggKGVycm9yLCBzdGFja1RyYWNlKSB7CiAgICBsb2dnZXIuZSgnRmFpbGVkIHRvIGluaXRpYWxpc2UgdGhlIEZpcmViYXNlIGVtdWxhdG9yczonLCBlcnJvciwgc3RhY2tUcmFjZSk7CiAgICByZXRocm93OwogIH0KfQp7ey9lbXVsYXRvcnN9fXt7XmVtdWxhdG9yc319Ly8vIE5vIEZpcmViYXNlIHNlcnZpY2VzIGFyZSBlbmFibGVkIGluIHRoaXMgcHJvamVjdCwgc28gdGhlcmUgaXMgbm90aGluZyB0bwovLy8gcG9pbnQgYXQgYW4gZW11bGF0b3IuIEtlcHQgYXMgYSBuby1vcCBzbyBib290c3RyYXAgc3RheXMgdW5pZm9ybS4KRnV0dXJlPHZvaWQ+IGluaXQoe1N0cmluZz8gaG9zdH0pIGFzeW5jIHt9Cnt7L2VtdWxhdG9yc319Cg==", "type": "text" }, { @@ -450,14 +525,14 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "path": "{{ name.snakeCase() }}/packages/core/lib/observer/core_bloc_observer.dart", "data": - "aW1wb3J0ICdwYWNrYWdlOmJsb2MvYmxvYy5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmNvcmUvY29yZS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6dGFsa2VyX2Jsb2NfbG9nZ2VyL3RhbGtlcl9ibG9jX2xvZ2dlcl9vYnNlcnZlci5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOnRhbGtlcl9ibG9jX2xvZ2dlci90YWxrZXJfYmxvY19sb2dnZXJfc2V0dGluZ3MuZGFydCc7CmltcG9ydCAncGFja2FnZTp0YWxrZXJfZmx1dHRlci90YWxrZXJfZmx1dHRlci5kYXJ0JzsKCmNsYXNzIENvcmVCbG9jT2JzZXJ2ZXIgZXh0ZW5kcyBCbG9jT2JzZXJ2ZXIgewogIGZpbmFsIFRhbGtlckJsb2NPYnNlcnZlciBfb2JzZXJ2ZXI7CgogIENvcmVCbG9jT2JzZXJ2ZXIoKQogICAgOiBfb2JzZXJ2ZXIgPSBUYWxrZXJCbG9jT2JzZXJ2ZXIoCiAgICAgICAgdGFsa2VyOiBkaS5nZXQ8TG9nZ2VyPigpLmxvZ2dlciBhcyBUYWxrZXIsCiAgICAgICAgc2V0dGluZ3M6IFRhbGtlckJsb2NMb2dnZXJTZXR0aW5ncyhwcmludEV2ZW50RnVsbERhdGE6IHRydWUpLAogICAgICApOwoKICBAb3ZlcnJpZGUKICB2b2lkIG9uRXZlbnQoQmxvYyBibG9jLCBPYmplY3Q/IGV2ZW50KSB7CiAgICBzdXBlci5vbkV2ZW50KGJsb2MsIGV2ZW50KTsKICAgIF9vYnNlcnZlci5vbkV2ZW50KGJsb2MsIGV2ZW50KTsKICB9CgogIEBvdmVycmlkZQogIHZvaWQgb25UcmFuc2l0aW9uKEJsb2MgYmxvYywgVHJhbnNpdGlvbiB0cmFuc2l0aW9uKSB7CiAgICBzdXBlci5vblRyYW5zaXRpb24oYmxvYywgdHJhbnNpdGlvbik7CiAgICBfb2JzZXJ2ZXIub25UcmFuc2l0aW9uKGJsb2MsIHRyYW5zaXRpb24pOwogIH0KCiAgQG92ZXJyaWRlCiAgdm9pZCBvbkVycm9yKEJsb2NCYXNlIGJsb2MsIE9iamVjdCBlcnJvciwgU3RhY2tUcmFjZSBzdGFja1RyYWNlKSB7CiAgICBzdXBlci5vbkVycm9yKGJsb2MsIGVycm9yLCBzdGFja1RyYWNlKTsKICAgIF9vYnNlcnZlci5vbkVycm9yKGJsb2MsIGVycm9yLCBzdGFja1RyYWNlKTsKICB9Cn0K", + "aW1wb3J0ICdwYWNrYWdlOmJsb2MvYmxvYy5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmNvcmUvY29yZS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwoKY2xhc3MgQ29yZUJsb2NPYnNlcnZlciBleHRlbmRzIEJsb2NPYnNlcnZlciB7CiAgZmluYWwgTG9nZ2VyIF9sb2dnZXI7CgogIENvcmVCbG9jT2JzZXJ2ZXIoe0xvZ2dlcj8gbG9nZ2VyfSkgOiBfbG9nZ2VyID0gbG9nZ2VyID8/IGRpLmdldDxMb2dnZXI+KCk7CgogIEBvdmVycmlkZQogIHZvaWQgb25FdmVudChCbG9jIGJsb2MsIE9iamVjdD8gZXZlbnQpIHsKICAgIHN1cGVyLm9uRXZlbnQoYmxvYywgZXZlbnQpOwogICAgX2xvZ2dlci5kKCcke2Jsb2MucnVudGltZVR5cGV9OiBldmVudCAke2V2ZW50LnJ1bnRpbWVUeXBlfScpOwogIH0KCiAgQG92ZXJyaWRlCiAgdm9pZCBvblRyYW5zaXRpb24oQmxvYyBibG9jLCBUcmFuc2l0aW9uIHRyYW5zaXRpb24pIHsKICAgIHN1cGVyLm9uVHJhbnNpdGlvbihibG9jLCB0cmFuc2l0aW9uKTsKICAgIF9sb2dnZXIuZCgKICAgICAgJyR7YmxvYy5ydW50aW1lVHlwZX06ICR7dHJhbnNpdGlvbi5jdXJyZW50U3RhdGUucnVudGltZVR5cGV9IC0+ICR7dHJhbnNpdGlvbi5uZXh0U3RhdGUucnVudGltZVR5cGV9JywKICAgICk7CiAgfQoKICBAb3ZlcnJpZGUKICB2b2lkIG9uRXJyb3IoQmxvY0Jhc2UgYmxvYywgT2JqZWN0IGVycm9yLCBTdGFja1RyYWNlIHN0YWNrVHJhY2UpIHsKICAgIHN1cGVyLm9uRXJyb3IoYmxvYywgZXJyb3IsIHN0YWNrVHJhY2UpOwogICAgX2xvZ2dlci5lKCcke2Jsb2MucnVudGltZVR5cGV9OiB1bmhhbmRsZWQgZXJyb3InLCBlcnJvciwgc3RhY2tUcmFjZSk7CiAgfQp9Cg==", "type": "text" }, { "path": "{{ name.snakeCase() }}/packages/core/lib/observer/core_route_observer.dart", "data": - "aW1wb3J0ICdwYWNrYWdlOmNvcmUvY29yZS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlci9tYXRlcmlhbC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOm5hdmlnYXRpb25faGlzdG9yeV9vYnNlcnZlci9uYXZpZ2F0aW9uX2hpc3Rvcnlfb2JzZXJ2ZXIuZGFydCc7CmltcG9ydCAncGFja2FnZTp0YWxrZXJfZmx1dHRlci90YWxrZXJfZmx1dHRlci5kYXJ0JzsKCmNsYXNzIENvcmVSb3V0ZU9ic2VydmVyIGV4dGVuZHMgTmF2aWdhdG9yT2JzZXJ2ZXIgewogIENvcmVSb3V0ZU9ic2VydmVyKCkgOiBfb2JzZXJ2ZXIgPSBkaS5nZXQ8TG9nZ2VyPigpLmxvZ2dlciBhcyBUYWxrZXI7CgogIGZpbmFsIFRhbGtlciBfb2JzZXJ2ZXI7CgogIEBvdmVycmlkZQogIHZvaWQgZGlkUHVzaChSb3V0ZSByb3V0ZSwgUm91dGU/IHByZXZpb3VzUm91dGUpIHsKICAgIHN1cGVyLmRpZFB1c2gocm91dGUsIHByZXZpb3VzUm91dGUpOwogICAgaWYgKHJvdXRlLnNldHRpbmdzLm5hbWUgPT0gbnVsbCkgewogICAgICByZXR1cm47CiAgICB9CiAgICBfb2JzZXJ2ZXIubG9nQ3VzdG9tKFRhbGtlclJvdXRlTG9nKHJvdXRlOiByb3V0ZSwgdHlwZTogUm91dGVMb2dUeXBlLnB1c2gpKTsKICB9CgogIEBvdmVycmlkZQogIHZvaWQgZGlkUG9wKFJvdXRlIHJvdXRlLCBSb3V0ZT8gcHJldmlvdXNSb3V0ZSkgewogICAgc3VwZXIuZGlkUG9wKHJvdXRlLCBwcmV2aW91c1JvdXRlKTsKICAgIGlmIChyb3V0ZS5zZXR0aW5ncy5uYW1lID09IG51bGwpIHsKICAgICAgcmV0dXJuOwogICAgfQogICAgX29ic2VydmVyLmxvZ0N1c3RvbShUYWxrZXJSb3V0ZUxvZyhyb3V0ZTogcm91dGUsIHR5cGU6IFJvdXRlTG9nVHlwZS5wb3ApKTsKICB9CgogIEBvdmVycmlkZQogIHZvaWQgZGlkUmVtb3ZlKFJvdXRlPGR5bmFtaWM+IHJvdXRlLCBSb3V0ZTxkeW5hbWljPj8gcHJldmlvdXNSb3V0ZSkgewogICAgc3VwZXIuZGlkUmVtb3ZlKHJvdXRlLCBwcmV2aW91c1JvdXRlKTsKICAgIGlmIChyb3V0ZS5zZXR0aW5ncy5uYW1lID09IG51bGwpIHsKICAgICAgcmV0dXJuOwogICAgfQogICAgX29ic2VydmVyLmxvZ0N1c3RvbSgKICAgICAgVGFsa2VyUm91dGVMb2cocm91dGU6IHJvdXRlLCB0eXBlOiBSb3V0ZUxvZ1R5cGUucmVtb3ZlKSwKICAgICk7CiAgfQoKICBAb3ZlcnJpZGUKICB2b2lkIGRpZFJlcGxhY2Uoe1JvdXRlPGR5bmFtaWM+PyBuZXdSb3V0ZSwgUm91dGU8ZHluYW1pYz4/IG9sZFJvdXRlfSkgewogICAgc3VwZXIuZGlkUmVwbGFjZShuZXdSb3V0ZTogbmV3Um91dGUsIG9sZFJvdXRlOiBvbGRSb3V0ZSk7CiAgICBpZiAobmV3Um91dGU/LnNldHRpbmdzLm5hbWUgPT0gbnVsbCkgewogICAgICByZXR1cm47CiAgICB9CiAgICBfb2JzZXJ2ZXIubG9nQ3VzdG9tKAogICAgICBUYWxrZXJSb3V0ZUxvZyhyb3V0ZTogbmV3Um91dGUhLCB0eXBlOiBSb3V0ZUxvZ1R5cGUucmVwbGFjZSksCiAgICApOwogIH0KfQoKZW51bSBSb3V0ZUxvZ1R5cGUgeyBwdXNoLCBwb3AsIHJlbW92ZSwgcmVwbGFjZSB9CgpjbGFzcyBUYWxrZXJSb3V0ZUxvZyBleHRlbmRzIFRhbGtlckxvZyB7CiAgVGFsa2VyUm91dGVMb2coe3JlcXVpcmVkIFJvdXRlIHJvdXRlLCByZXF1aXJlZCBSb3V0ZUxvZ1R5cGUgdHlwZX0pCiAgICA6IHN1cGVyKF9jcmVhdGVNZXNzYWdlKHJvdXRlLCB0eXBlKSk7CgogIEBvdmVycmlkZQogIEFuc2lQZW4gZ2V0IHBlbiA9PiBBbnNpUGVuKCkuLnh0ZXJtKDEzNSk7CgogIEBvdmVycmlkZQogIFN0cmluZyBnZXQga2V5ID0+IFRhbGtlckxvZ1R5cGUucm91dGUua2V5OwoKICBzdGF0aWMgU3RyaW5nIF9jcmVhdGVNZXNzYWdlKFJvdXRlPGR5bmFtaWM+IHJvdXRlLCBSb3V0ZUxvZ1R5cGUgdHlwZSkgewogICAgZmluYWwgYnVmZmVyID0gU3RyaW5nQnVmZmVyKCk7CiAgICBidWZmZXIud3JpdGUodHlwZS5uYW1lKTsKICAgIGJ1ZmZlci53cml0ZSgnIHJvdXRlIG5hbWVkICcpOwogICAgYnVmZmVyLndyaXRlKHJvdXRlLnNldHRpbmdzLm5hbWUgPz8gJ251bGwnKTsKCiAgICBmaW5hbCBhcmdzID0gcm91dGUuc2V0dGluZ3MuYXJndW1lbnRzOwogICAgaWYgKGFyZ3MgIT0gbnVsbCkgewogICAgICBidWZmZXIud3JpdGUoJ1xuQXJndW1lbnRzOiAkYXJncycpOwogICAgfQoKICAgIGZpbmFsIGhpc3RvcnlPYnNlcnZlciA9IE5hdmlnYXRpb25IaXN0b3J5T2JzZXJ2ZXIoKTsKICAgIGZpbmFsIGhpc3RvcnkgPSBoaXN0b3J5T2JzZXJ2ZXIuaGlzdG9yeTsKICAgIGlmIChoaXN0b3J5LmlzRW1wdHkpIHsKICAgICAgYnVmZmVyLndyaXRlKCdcbkhpc3Rvcnk6IG5hJyk7CiAgICB9IGVsc2UgewogICAgICBmaW5hbCBoaXN0b3J5QXNTdHJpbmcgPSBoaXN0b3J5T2JzZXJ2ZXIuaGlzdG9yeQogICAgICAgICAgLm1hcCgocikgPT4gci5zZXR0aW5ncy5uYW1lKQogICAgICAgICAgLmpvaW4oJyAtPiAnKTsKICAgICAgYnVmZmVyLndyaXRlKCdcbkhpc3Rvcnk6ICRoaXN0b3J5QXNTdHJpbmcnKTsKICAgIH0KCiAgICByZXR1cm4gYnVmZmVyLnRvU3RyaW5nKCk7CiAgfQp9Cg==", + "aW1wb3J0ICdwYWNrYWdlOmNvcmUvY29yZS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlci9tYXRlcmlhbC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOnRhbGtlcl9mbHV0dGVyL3RhbGtlcl9mbHV0dGVyLmRhcnQnOwoKY2xhc3MgQ29yZVJvdXRlT2JzZXJ2ZXIgZXh0ZW5kcyBOYXZpZ2F0b3JPYnNlcnZlciB7CiAgQ29yZVJvdXRlT2JzZXJ2ZXIoe0xvZ2dlcj8gbG9nZ2VyfSkgOiBfbG9nZ2VyID0gbG9nZ2VyID8/IGRpLmdldDxMb2dnZXI+KCk7CgogIGZpbmFsIExvZ2dlciBfbG9nZ2VyOwoKICBAb3ZlcnJpZGUKICB2b2lkIGRpZFB1c2goUm91dGUgcm91dGUsIFJvdXRlPyBwcmV2aW91c1JvdXRlKSB7CiAgICBzdXBlci5kaWRQdXNoKHJvdXRlLCBwcmV2aW91c1JvdXRlKTsKICAgIGlmIChyb3V0ZS5zZXR0aW5ncy5uYW1lID09IG51bGwpIHsKICAgICAgcmV0dXJuOwogICAgfQogICAgX2xvZ2dlci5kKFRhbGtlclJvdXRlTG9nLl9jcmVhdGVNZXNzYWdlKHJvdXRlLCBSb3V0ZUxvZ1R5cGUucHVzaCkpOwogIH0KCiAgQG92ZXJyaWRlCiAgdm9pZCBkaWRQb3AoUm91dGUgcm91dGUsIFJvdXRlPyBwcmV2aW91c1JvdXRlKSB7CiAgICBzdXBlci5kaWRQb3Aocm91dGUsIHByZXZpb3VzUm91dGUpOwogICAgaWYgKHJvdXRlLnNldHRpbmdzLm5hbWUgPT0gbnVsbCkgewogICAgICByZXR1cm47CiAgICB9CiAgICBfbG9nZ2VyLmQoVGFsa2VyUm91dGVMb2cuX2NyZWF0ZU1lc3NhZ2Uocm91dGUsIFJvdXRlTG9nVHlwZS5wb3ApKTsKICB9CgogIEBvdmVycmlkZQogIHZvaWQgZGlkUmVtb3ZlKFJvdXRlPGR5bmFtaWM+IHJvdXRlLCBSb3V0ZTxkeW5hbWljPj8gcHJldmlvdXNSb3V0ZSkgewogICAgc3VwZXIuZGlkUmVtb3ZlKHJvdXRlLCBwcmV2aW91c1JvdXRlKTsKICAgIGlmIChyb3V0ZS5zZXR0aW5ncy5uYW1lID09IG51bGwpIHsKICAgICAgcmV0dXJuOwogICAgfQogICAgX2xvZ2dlci5kKFRhbGtlclJvdXRlTG9nLl9jcmVhdGVNZXNzYWdlKHJvdXRlLCBSb3V0ZUxvZ1R5cGUucmVtb3ZlKSk7CiAgfQoKICBAb3ZlcnJpZGUKICB2b2lkIGRpZFJlcGxhY2Uoe1JvdXRlPGR5bmFtaWM+PyBuZXdSb3V0ZSwgUm91dGU8ZHluYW1pYz4/IG9sZFJvdXRlfSkgewogICAgc3VwZXIuZGlkUmVwbGFjZShuZXdSb3V0ZTogbmV3Um91dGUsIG9sZFJvdXRlOiBvbGRSb3V0ZSk7CiAgICBpZiAobmV3Um91dGU/LnNldHRpbmdzLm5hbWUgPT0gbnVsbCkgewogICAgICByZXR1cm47CiAgICB9CiAgICBfbG9nZ2VyLmQoVGFsa2VyUm91dGVMb2cuX2NyZWF0ZU1lc3NhZ2UobmV3Um91dGUhLCBSb3V0ZUxvZ1R5cGUucmVwbGFjZSkpOwogIH0KfQoKZW51bSBSb3V0ZUxvZ1R5cGUgeyBwdXNoLCBwb3AsIHJlbW92ZSwgcmVwbGFjZSB9CgpjbGFzcyBUYWxrZXJSb3V0ZUxvZyBleHRlbmRzIFRhbGtlckxvZyB7CiAgVGFsa2VyUm91dGVMb2coe3JlcXVpcmVkIFJvdXRlIHJvdXRlLCByZXF1aXJlZCBSb3V0ZUxvZ1R5cGUgdHlwZX0pCiAgICA6IHN1cGVyKF9jcmVhdGVNZXNzYWdlKHJvdXRlLCB0eXBlKSk7CgogIEBvdmVycmlkZQogIEFuc2lQZW4gZ2V0IHBlbiA9PiBBbnNpUGVuKCkuLnh0ZXJtKDEzNSk7CgogIEBvdmVycmlkZQogIFN0cmluZyBnZXQga2V5ID0+IFRhbGtlckxvZ1R5cGUucm91dGUua2V5OwoKICBzdGF0aWMgU3RyaW5nIF9jcmVhdGVNZXNzYWdlKFJvdXRlPGR5bmFtaWM+IHJvdXRlLCBSb3V0ZUxvZ1R5cGUgdHlwZSkgewogICAgZmluYWwgYnVmZmVyID0gU3RyaW5nQnVmZmVyKCk7CiAgICBidWZmZXIud3JpdGUodHlwZS5uYW1lKTsKICAgIGJ1ZmZlci53cml0ZSgnIHJvdXRlIG5hbWVkICcpOwogICAgYnVmZmVyLndyaXRlKHJvdXRlLnNldHRpbmdzLm5hbWUgPz8gJ251bGwnKTsKCiAgICByZXR1cm4gYnVmZmVyLnRvU3RyaW5nKCk7CiAgfQp9Cg==", "type": "text" }, { @@ -476,7 +551,7 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ { "path": "{{ name.snakeCase() }}/packages/core/pubspec.yaml", "data": - "bmFtZTogY29yZQpkZXNjcmlwdGlvbjogIkNyb3NzLWN1dHRpbmcgZm91bmRhdGlvbiBmb3Ige3tuYW1lLnRpdGxlQ2FzZSgpfX06IGxvZ2dpbmcsIERJIHdpcmluZywgcm91dGluZyBjb250cmFjdHMsIGVycm9yIHR5cGVzIGFuZCBCTG9DIHBsdW1iaW5nLiIKdmVyc2lvbjogMC4xLjAKcHVibGlzaF90bzogJ25vbmUnCgplbnZpcm9ubWVudDoKICBzZGs6IF4zLjguMAogIGZsdXR0ZXI6ICI+PTMuMjkuMCIKCmRlcGVuZGVuY2llczoKICBmbHV0dGVyOgogICAgc2RrOiBmbHV0dGVyCiAgYmxvYzogXjkuMC4wCiAgZXF1YXRhYmxlOiBeMi4wLjUKICBmbHV0dGVyX2Jsb2M6IF45LjEuMQogIGdvX3JvdXRlcjogXjE1LjEuMwogIGludGw6IF4wLjIwLjIKICBqc29uX2Fubm90YXRpb246IF40LjkuMAogIG5hdmlnYXRpb25faGlzdG9yeV9vYnNlcnZlcjogXjEuMS4xCiAgdGFsa2VyX2Jsb2NfbG9nZ2VyOiBeNC45LjEKICB0YWxrZXJfZmx1dHRlcjogXjQuNC4xCiAgZGk6CiAgICBwYXRoOiAuLi9kaQogIGxvY2FsaXphdGlvbjoKICAgIHBhdGg6IC4uL2xvY2FsaXphdGlvbgp7eyNmaXJlYmFzZX19ICBmaXJlYmFzZV9jb3JlOiBeMy4xNC4wCnt7L2ZpcmViYXNlfX17eyNhdXRofX0gIGZpcmViYXNlX2F1dGg6IF41LjMuNAp7ey9hdXRofX17eyNmaXJlc3RvcmV9fSAgY2xvdWRfZmlyZXN0b3JlOiBeNS41LjMKICBjbG91ZF9mdW5jdGlvbnM6IF41LjIuMwp7ey9maXJlc3RvcmV9fQpkZXZfZGVwZW5kZW5jaWVzOgogIGZsdXR0ZXJfdGVzdDoKICAgIHNkazogZmx1dHRlcgogIGZsdXR0ZXJfbGludHM6IF41LjAuMAoKZGVwZW5kZW5jeV9vdmVycmlkZXM6CiAgaW50bDogXjAuMjAuMgoKZmx1dHRlcjoK", + "bmFtZTogY29yZQpkZXNjcmlwdGlvbjogIkNyb3NzLWN1dHRpbmcgZm91bmRhdGlvbiBmb3Ige3tuYW1lLnRpdGxlQ2FzZSgpfX06IGxvZ2dpbmcsIERJIHdpcmluZywgcm91dGluZyBjb250cmFjdHMsIGVycm9yIHR5cGVzIGFuZCBCTG9DIHBsdW1iaW5nLiIKdmVyc2lvbjogMC4xLjAKcHVibGlzaF90bzogJ25vbmUnCgplbnZpcm9ubWVudDoKICBzZGs6IF4zLjguMAogIGZsdXR0ZXI6ICI+PTMuMjkuMCIKCmRlcGVuZGVuY2llczoKICBmbHV0dGVyOgogICAgc2RrOiBmbHV0dGVyCiAgYmxvYzogXjkuMC4wCiAgZXF1YXRhYmxlOiBeMi4wLjUKICBmbHV0dGVyX2Jsb2M6IF45LjEuMQogIGdvX3JvdXRlcjogXjE1LjEuMwogIGludGw6IF4wLjIwLjIKICBqc29uX2Fubm90YXRpb246IF40LjkuMAogIHRhbGtlcl9mbHV0dGVyOiBeNC40LjEKICBkaToKICAgIHBhdGg6IC4uL2RpCiAgbG9jYWxpemF0aW9uOgogICAgcGF0aDogLi4vbG9jYWxpemF0aW9uCnt7I2ZpcmViYXNlfX0gIGZpcmViYXNlX2NvcmU6IF4zLjE0LjAKe3svZmlyZWJhc2V9fXt7I2F1dGh9fSAgZmlyZWJhc2VfYXV0aDogXjUuMy40Cnt7L2F1dGh9fXt7I2ZpcmVzdG9yZX19ICBjbG91ZF9maXJlc3RvcmU6IF41LjUuMwogIGNsb3VkX2Z1bmN0aW9uczogXjUuMi4zCnt7L2ZpcmVzdG9yZX19CmRldl9kZXBlbmRlbmNpZXM6CiAgZmx1dHRlcl90ZXN0OgogICAgc2RrOiBmbHV0dGVyCiAgZmx1dHRlcl9saW50czogXjUuMC4wCgpkZXBlbmRlbmN5X292ZXJyaWRlczoKICBpbnRsOiBeMC4yMC4yCgpmbHV0dGVyOgo=", "type": "text" }, { @@ -485,6 +560,12 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "IyBDb3JlCgpBIE1lbG9zLW1hbmFnZWQgcHJvamVjdCBmb3IgbW9uby1yZXBvLCBjcmVhdGVkIHVzaW5nIE5vblN0b3AgQ0xJLgoKWyFbbm9uc3RvcF9jbGldKGh0dHBzOi8vaW1nLnNoaWVsZHMuaW8vYmFkZ2Uvc3RhcnRlZCUyMHdpdGgtbm9uc3RvcF9jbGktMTY2QzRFLnN2Zz9zdHlsZT1mbGF0LXNxdWFyZSldKGh0dHBzOi8vcHViLmRldi9wYWNrYWdlcy9ub25zdG9wX2NsaSkKWyFbbWVsb3NdKGh0dHBzOi8vaW1nLnNoaWVsZHMuaW8vYmFkZ2UvbWFpbnRhaW5lZCUyMHdpdGgtbWVsb3MtZjcwMGZmLnN2Zz9zdHlsZT1mbGF0LXNxdWFyZSldKGh0dHBzOi8vZ2l0aHViLmNvbS9pbnZlcnRhc2UvbWVsb3MpCgojIyBJbnN0YWxsYXRpb24g8J+SuwoKKirinZcgSW4gb3JkZXIgdG8gc3RhcnQgdXNpbmcgQ29yZSB5b3UgbXVzdCBoYXZlIHRoZSBbRmx1dHRlciBTREtdW2ZsdXR0ZXJfaW5zdGFsbF9saW5rXSBpbnN0YWxsZWQgb24geW91ciBtYWNoaW5lLioqCgpJbnN0YWxsIHZpYSBgZGFydCBwdWIgYWRkYDoKCmBgYHNoCmRhcnQgcHViIGFkZCBjb3JlCmBgYAoKW2ZsdXR0ZXJfaW5zdGFsbF9saW5rXTogaHR0cHM6Ly9kb2NzLmZsdXR0ZXIuZGV2L2dldC1zdGFydGVkL2luc3RhbGw=", "type": "text" }, + { + "path": "{{ name.snakeCase() }}/packages/core/test/core_test.dart", + "data": + "aW1wb3J0ICdwYWNrYWdlOmNvcmUvZGV2ZWxvcGVyL2VtdWxhdG9ycy5kYXJ0JyBhcyBlbXVsYXRvcnM7Cnt7I2ZpcmVzdG9yZX19aW1wb3J0ICdwYWNrYWdlOmNsb3VkX2ZpcmVzdG9yZS9jbG91ZF9maXJlc3RvcmUuZGFydCc7Cnt7L2ZpcmVzdG9yZX19CmltcG9ydCAncGFja2FnZTpjb3JlL2NvcmUuZGFydCc7CmltcG9ydCAncGFja2FnZTpjb3JlL2xvZ2dlci90YWxrZXJfbG9nZ2VyX2ltcGwuZGFydCc7CmltcG9ydCAncGFja2FnZTpkaS9kaS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZsdXR0ZXIvbWF0ZXJpYWwuZGFydCc7CmltcG9ydCAncGFja2FnZTpmbHV0dGVyX2Jsb2MvZmx1dHRlcl9ibG9jLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlcl90ZXN0L2ZsdXR0ZXJfdGVzdC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOnRhbGtlcl9mbHV0dGVyL3RhbGtlcl9mbHV0dGVyLmRhcnQnIGhpZGUgVGFsa2VyUm91dGVMb2c7CgpjbGFzcyBfQ291bnRlciBleHRlbmRzIEJsb2M8aW50LCBpbnQ+IHsKICBfQ291bnRlcigpIDogc3VwZXIoMCkgewogICAgb248aW50PigoZXZlbnQsIGVtaXQpID0+IGVtaXQoZXZlbnQpKTsKICB9Cn0KCnZvaWQgbWFpbigpIHsKe3sjZW11bGF0b3JzfX0gIHRlc3QoJ2VtdWxhdG9yIHNldHVwIGZhaWx1cmVzIGFyZSBzdXJmYWNlZCBiZWZvcmUgRmlyZWJhc2UgaW5pdGlhbGl6YXRpb24nLCAoKSBhc3luYyB7CiAgICBhd2FpdCBleHBlY3RMYXRlcihlbXVsYXRvcnMuaW5pdCgpLCB0aHJvd3NBKGFueXRoaW5nKSk7CiAgfSk7Cnt7L2VtdWxhdG9yc319Cnt7XmVtdWxhdG9yc319ICB0ZXN0KCdlbXVsYXRvciBzZXR1cCBpcyBhIG5vLW9wIHdpdGhvdXQgZW11bGF0ZWQgc2VydmljZXMnLCBlbXVsYXRvcnMuaW5pdCk7Cnt7L2VtdWxhdG9yc319CiAgc2V0VXAoaW5pdCk7CiAgdGVhckRvd24oZGkucmVzZXQpOwoKICB0ZXN0KAogICAgJ2V2ZW50IGJhc2UgZGVmaW5lcyB2YWx1ZSBlcXVhbGl0eSBhbmQgREkgZXhwb3NlcyBpdHMgY29uZmlndXJlZCBjb250YWluZXInLAogICAgKCkgewogICAgICBmaW5hbCBldmVudCA9IFJlZnJlc2hQcm9maWxlKCk7CiAgICAgIGV4cGVjdChldmVudC5wcm9wcywgaXNFbXB0eSk7CiAgICAgIGV4cGVjdChldmVudCwgUmVmcmVzaFByb2ZpbGUoKSk7CiAgICAgIGV4cGVjdChkaS5nZXRJdC5pc1JlZ2lzdGVyZWQ8TG9nZ2VyPigpLCBpc1RydWUpOwogICAgfSwKICApOwoKICB0ZXN0V2lkZ2V0cygnY29udGV4dCBldmVudCBleHRlbnNpb24gYnJvYWRjYXN0cyB0byB0aGUgb3duZWQgY2hhbm5lbCcsICgKICAgIHRlc3RlciwKICApIGFzeW5jIHsKICAgIGxhdGUgQnVpbGRDb250ZXh0IGNvbnRleHQ7CiAgICBhd2FpdCB0ZXN0ZXIucHVtcFdpZGdldCgKICAgICAgR2xvYmFsRXZlbnRDaGFubmVsUHJvdmlkZXIoCiAgICAgICAgY2hpbGQ6IEJ1aWxkZXIoCiAgICAgICAgICBidWlsZGVyOiAoY3R4KSB7CiAgICAgICAgICAgIGNvbnRleHQgPSBjdHg7CiAgICAgICAgICAgIHJldHVybiBjb25zdCBTaXplZEJveCgpOwogICAgICAgICAgfSwKICAgICAgICApLAogICAgICApLAogICAgKTsKICAgIGNvbnRleHQuZmlyZShjb25zdCBSZWZyZXNoUHJvZmlsZSgpKTsKICAgIGF3YWl0IHRlc3Rlci5wdW1wKCk7CiAgICBleHBlY3QoCiAgICAgIGNvbnRleHQucmVhZDxHbG9iYWxFdmVudENoYW5uZWw+KCkuc3RhdGUuY3VycmVudCwKICAgICAgY29uc3QgUmVmcmVzaFByb2ZpbGUoKSwKICAgICk7CiAgfSk7CgogIHRlc3QoJ2V2ZW50IGNoYW5uZWwgYm91bmRzIGhpc3Rvcnkgd2hpbGUgcmV0YWluaW5nIHRvdGFsIGNvdW50cycsICgpIGFzeW5jIHsKICAgIGZpbmFsIGNoYW5uZWwgPSBHbG9iYWxFdmVudENoYW5uZWwobWF4UmVjZW50RXZlbnRzOiAyKTsKICAgIGZpbmFsIHN0YXRlcyA9IDxHbG9iYWxFdmVudFN0YXRlPltdOwogICAgZmluYWwgc3Vic2NyaXB0aW9uID0gY2hhbm5lbC5zdHJlYW0ubGlzdGVuKHN0YXRlcy5hZGQpOwogICAgZm9yICh2YXIgaSA9IDA7IGkgPCAzOyBpKyspIHsKICAgICAgY2hhbm5lbC5hZGQoY29uc3QgRmlyZUdsb2JhbEV2ZW50KGV2ZW50VHlwZTogUmVmcmVzaFByb2ZpbGUoKSkpOwogICAgfQogICAgYXdhaXQgcHVtcEV2ZW50UXVldWUoKTsKICAgIGV4cGVjdChzdGF0ZXMsIGhhc0xlbmd0aCgzKSk7CiAgICBleHBlY3QoY2hhbm5lbC5zdGF0ZS5oaXN0b3J5LCBoYXNMZW5ndGgoMikpOwogICAgZXhwZWN0KGNoYW5uZWwuc3RhdGUuZXZlbnRDb3VudHNbUmVmcmVzaFByb2ZpbGVdLCAzKTsKICAgIGV4cGVjdChjaGFubmVsLnN0YXRlLmN1cnJlbnQsIGNvbnN0IFJlZnJlc2hQcm9maWxlKCkpOwogICAgZXhwZWN0KGNoYW5uZWwuc3RhdGUuY29weVdpdGgoKSwgY2hhbm5lbC5zdGF0ZSk7CiAgICBleHBlY3QoY2hhbm5lbC5zdGF0ZS5jb3B5V2l0aChtYXhSZWNlbnRFdmVudHM6IDkpLm1heFJlY2VudEV2ZW50cywgOSk7CiAgICBleHBlY3QoY29uc3QgRmlyZUdsb2JhbEV2ZW50KGV2ZW50VHlwZTogUmVmcmVzaFByb2ZpbGUoKSkucHJvcHMsIFsKICAgICAgY29uc3QgUmVmcmVzaFByb2ZpbGUoKSwKICAgIF0pOwogICAgYXdhaXQgc3Vic2NyaXB0aW9uLmNhbmNlbCgpOwogICAgYXdhaXQgY2hhbm5lbC5jbG9zZSgpOwogIH0pOwoKICB0ZXN0V2lkZ2V0cygKICAgICdwcm92aWRlciwgYnVpbGRlciwgbGlzdGVuZXIgYW5kIGNvbnN1bWVyIHNoYXJlIHRoZSBldmVudCBjaGFubmVsJywKICAgICh0ZXN0ZXIpIGFzeW5jIHsKICAgICAgdmFyIGxpc3RlbmVycyA9IDA7CiAgICAgIGF3YWl0IHRlc3Rlci5wdW1wV2lkZ2V0KAogICAgICAgIE1hdGVyaWFsQXBwKAogICAgICAgICAgaG9tZTogR2xvYmFsRXZlbnRDaGFubmVsUHJvdmlkZXIoCiAgICAgICAgICAgIGxhenk6IGZhbHNlLAogICAgICAgICAgICBjaGlsZDogR2xvYmFsRXZlbnRDaGFubmVsTGlzdGVuZXIoCiAgICAgICAgICAgICAgbGlzdGVuZXI6IChfLCBzdGF0ZSkgewogICAgICAgICAgICAgICAgbGlzdGVuZXJzKys7CiAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICBjaGlsZDogR2xvYmFsRXZlbnRDaGFubmVsQ29uc3VtZXIoCiAgICAgICAgICAgICAgICBsaXN0ZW5lcjogKF8sIHN0YXRlKSB7CiAgICAgICAgICAgICAgICAgIGxpc3RlbmVycysrOwogICAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAgIGJ1aWxkZXI6IChfLCBzdGF0ZSkgPT4gR2xvYmFsRXZlbnRDaGFubmVsQnVpbGRlcigKICAgICAgICAgICAgICAgICAgYnVpbGRlcjogKF8sIHN0YXRlKSA9PgogICAgICAgICAgICAgICAgICAgICAgVGV4dCgnRXZlbnRzOiAke3N0YXRlLmhpc3RvcnkubGVuZ3RofScpLAogICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICApLAogICAgICAgICAgICApLAogICAgICAgICAgKSwKICAgICAgICApLAogICAgICApOwogICAgICBleHBlY3QoZmluZC50ZXh0KCdFdmVudHM6IDAnKSwgZmluZHNPbmVXaWRnZXQpOwogICAgICBCbG9jUHJvdmlkZXIub2Y8R2xvYmFsRXZlbnRDaGFubmVsPigKICAgICAgICB0ZXN0ZXIuZWxlbWVudChmaW5kLnRleHQoJ0V2ZW50czogMCcpKSwKICAgICAgKS5hZGQoY29uc3QgRmlyZUdsb2JhbEV2ZW50KGV2ZW50VHlwZTogUmVmcmVzaFByb2ZpbGUoKSkpOwogICAgICBhd2FpdCB0ZXN0ZXIucHVtcEFuZFNldHRsZSgpOwogICAgICBleHBlY3QoZmluZC50ZXh0KCdFdmVudHM6IDEnKSwgZmluZHNPbmVXaWRnZXQpOwogICAgICBleHBlY3QobGlzdGVuZXJzLCAyKTsKICAgICAgYXdhaXQgdGVzdGVyLnB1bXBXaWRnZXQoY29uc3QgU2l6ZWRCb3goKSk7CiAgICB9LAogICk7CgogIHRlc3QoJ2RhdGUgYW5kIHN0cmluZyBoZWxwZXJzIGhhbmRsZSBudWxsIGFuZCB2YWxpZCBpbnB1dCcsICgpIHsKICAgIGZpbmFsIGRhdGUgPSBEYXRlVGltZSgyMDI2LCAxLCAxNSwgMTMsIDE0LCAxNSk7CiAgICBleHBlY3QoRGF0ZVRpbWVDb252ZXJ0ZXIudG9WaWV3Rm9ybWF0KG51bGwpLCAnJyk7CiAgICBleHBlY3QoRGF0ZVRpbWVDb252ZXJ0ZXIudG9WaWV3Rm9ybWF0KGRhdGUpLCAnSmFudWFyeSAxNSwgMjAyNicpOwogICAgZXhwZWN0KERhdGVUaW1lQ29udmVydGVyLnRvVmlld0Zvcm1hdFdpdGhUaW1lKG51bGwpLCAnJyk7CiAgICBleHBlY3QoCiAgICAgIERhdGVUaW1lQ29udmVydGVyLnRvVmlld0Zvcm1hdFdpdGhUaW1lKGRhdGUpLAogICAgICAnSmFudWFyeSAxNSwgMjAyNiwgMToxNCBQTScsCiAgICApOwogICAgZXhwZWN0KERhdGVUaW1lQ29udmVydGVyLnRvVmlld0Zvcm1hdFRpbWUobnVsbCksICcnKTsKICAgIGV4cGVjdChEYXRlVGltZUNvbnZlcnRlci50b1ZpZXdGb3JtYXRUaW1lKGRhdGUpLCAnMToxNDoxNSBQTScpOwogICAgZXhwZWN0KChudWxsIGFzIFN0cmluZz8pLmFzQm9vbCwgaXNGYWxzZSk7CiAgICBmb3IgKGZpbmFsIHZhbHVlIGluIFsnVFJVRScsICd0cnVlJywgJzEnXSkgewogICAgICBleHBlY3QodmFsdWUuYXNCb29sLCBpc1RydWUpOwogICAgfQogICAgZXhwZWN0KCdmYWxzZScuYXNCb29sLCBpc0ZhbHNlKTsKICAgIGV4cGVjdChDb3JlRXhjZXB0aW9uKG1lc3NhZ2U6ICdtZXNzYWdlJykubWVzc2FnZSwgJ21lc3NhZ2UnKTsKICAgIGV4cGVjdChVc2VyTm90Rm91bmRFeGNlcHRpb24oKS5tZXNzYWdlLCBpc05vdEVtcHR5KTsKICB9KTsKCiAgdGVzdCgKICAgICd0aW1lc3RhbXAgYWRhcHRlcnMgYWNjZXB0IGRvY3VtZW50ZWQgZm9ybXMgYW5kIHJlamVjdCBpbnZhbGlkIHNoYXBlcycsCiAgICAoKSB7CiAgICAgIC8vIEV4ZXJjaXNlIHJ1bnRpbWUgY29uc3RydWN0aW9uIGFzIHdlbGwgYXMgYW5ub3RhdGlvbi1zdHlsZSBjb25zdCB1c2UuCiAgICAgIC8vIGlnbm9yZTogcHJlZmVyX2NvbnN0X2NvbnN0cnVjdG9ycwogICAgICBmaW5hbCBjb252ZXJ0ZXIgPSBUaW1lc3RhbXBDb252ZXJ0ZXIoKTsKICAgICAgLy8gaWdub3JlOiBwcmVmZXJfY29uc3RfY29uc3RydWN0b3JzCiAgICAgIGZpbmFsIG51bGxhYmxlID0gVGltZXN0YW1wQ29udmVydGVyTnVsbGFibGUoKTsKICAgICAgZmluYWwgZGF0ZSA9IERhdGVUaW1lLnV0YygyMDI2KTsKICAgICAgZXhwZWN0KGNvbnZlcnRlci5mcm9tSnNvbihkYXRlLnRvSXNvODYwMVN0cmluZygpKS50b1V0YygpLCBkYXRlKTsKe3sjZmlyZXN0b3JlfX0gICAgICBleHBlY3QoY29udmVydGVyLmZyb21Kc29uKFRpbWVzdGFtcC5mcm9tRGF0ZShkYXRlKSkudG9VdGMoKSwgZGF0ZSk7Cnt7L2ZpcmVzdG9yZX19CiAgICAgIGV4cGVjdCgKICAgICAgICBjb252ZXJ0ZXIuZnJvbUpzb24oewogICAgICAgICAgJ19zZWNvbmRzJzogMSwKICAgICAgICAgICdfbmFub3NlY29uZHMnOiA1MDAwMDAwMDAsCiAgICAgICAgfSkubWlsbGlzZWNvbmRzU2luY2VFcG9jaCwKICAgICAgICAxNTAwLAogICAgICApOwogICAgICBleHBlY3QoY29udmVydGVyLnRvSnNvbihkYXRlKSwgZGF0ZS50b0lzbzg2MDFTdHJpbmcoKSk7CiAgICAgIGV4cGVjdChjb252ZXJ0ZXIudG9Kc29uKG51bGwpLCBpc051bGwpOwogICAgICBleHBlY3QobnVsbGFibGUuZnJvbUpzb24obnVsbCksIGlzTnVsbCk7CiAgICAgIGV4cGVjdChudWxsYWJsZS50b0pzb24obnVsbCksIGlzTnVsbCk7CiAgICAgIGV4cGVjdChudWxsYWJsZS50b0pzb24oZGF0ZSksIGRhdGUudG9Jc284NjAxU3RyaW5nKCkpOwogICAgICBleHBlY3QoKCkgPT4gY29udmVydGVyLmZyb21Kc29uKG51bGwpLCB0aHJvd3NBcmd1bWVudEVycm9yKTsKICAgIH0sCiAgKTsKCiAgdGVzdCgnbG9nZ2VyIGZvcndhcmRzIGV2ZXJ5IGxldmVsIGFuZCBleHBvc2VzIGl0cyBhZGFwdGVyJywgKCkgewogICAgZmluYWwgdGFsa2VyID0gVGFsa2VyKHNldHRpbmdzOiBUYWxrZXJTZXR0aW5ncyh1c2VDb25zb2xlTG9nczogZmFsc2UpKTsKICAgIGZpbmFsIGxvZ2dlciA9IFRhbGtlckxvZ2dlckltcGwodGFsa2VyKTsKICAgIGxvZ2dlci5kKCdkZWJ1ZycpOwogICAgbG9nZ2VyLmkoJ2luZm8nKTsKICAgIGxvZ2dlci53KCd3YXJuaW5nJyk7CiAgICBsb2dnZXIuZSgnZXJyb3InKTsKICAgIGV4cGVjdChsb2dnZXIubG9nZ2VyLCBzYW1lKHRhbGtlcikpOwogICAgZXhwZWN0KHRhbGtlci5oaXN0b3J5LCBoYXNMZW5ndGgoNCkpOwogIH0pOwoKICB0ZXN0KAogICAgJ29ic2VydmVycyBzdXBwb3J0IGV2ZW50LCB0cmFuc2l0aW9uLCBlcnJvciBhbmQgcm91dGUgbGlmZWN5Y2xlcycsCiAgICAoKSBhc3luYyB7CiAgICAgIGZpbmFsIGJsb2MgPSBfQ291bnRlcigpOwogICAgICBmaW5hbCBvYnNlcnZlciA9IENvcmVCbG9jT2JzZXJ2ZXIoKTsKICAgICAgb2JzZXJ2ZXIub25FdmVudChibG9jLCAxKTsKICAgICAgb2JzZXJ2ZXIub25UcmFuc2l0aW9uKAogICAgICAgIGJsb2MsCiAgICAgICAgY29uc3QgVHJhbnNpdGlvbihjdXJyZW50U3RhdGU6IDAsIGV2ZW50OiAxLCBuZXh0U3RhdGU6IDEpLAogICAgICApOwogICAgICBvYnNlcnZlci5vbkVycm9yKGJsb2MsIFN0YXRlRXJyb3IoJ3Rlc3QnKSwgU3RhY2tUcmFjZS5jdXJyZW50KTsKICAgICAgZmluYWwgcm91dGVzID0gQ29yZVJvdXRlT2JzZXJ2ZXIoKTsKICAgICAgZmluYWwgbmFtZWQgPSBNYXRlcmlhbFBhZ2VSb3V0ZTx2b2lkPigKICAgICAgICBidWlsZGVyOiAoXykgPT4gY29uc3QgU2l6ZWRCb3goKSwKICAgICAgICBzZXR0aW5nczogY29uc3QgUm91dGVTZXR0aW5ncyhuYW1lOiAnL3Rlc3QnLCBhcmd1bWVudHM6ICdhcmcnKSwKICAgICAgKTsKICAgICAgZmluYWwgdW5uYW1lZCA9IE1hdGVyaWFsUGFnZVJvdXRlPHZvaWQ+KGJ1aWxkZXI6IChfKSA9PiBjb25zdCBTaXplZEJveCgpKTsKICAgICAgZm9yIChmaW5hbCByb3V0ZSBpbiBbbmFtZWQsIHVubmFtZWRdKSB7CiAgICAgICAgcm91dGVzLmRpZFB1c2gocm91dGUsIG51bGwpOwogICAgICAgIHJvdXRlcy5kaWRQb3Aocm91dGUsIG51bGwpOwogICAgICAgIHJvdXRlcy5kaWRSZW1vdmUocm91dGUsIG51bGwpOwogICAgICAgIHJvdXRlcy5kaWRSZXBsYWNlKG5ld1JvdXRlOiByb3V0ZSk7CiAgICAgIH0KICAgICAgcm91dGVzLmRpZFJlcGxhY2UoKTsKICAgICAgZmluYWwgbG9nID0gVGFsa2VyUm91dGVMb2cocm91dGU6IHVubmFtZWQsIHR5cGU6IFJvdXRlTG9nVHlwZS5wdXNoKTsKICAgICAgZXhwZWN0KGxvZy5rZXksIFRhbGtlckxvZ1R5cGUucm91dGUua2V5KTsKICAgICAgZXhwZWN0KGxvZy5wZW4sIGlzQTxBbnNpUGVuPigpKTsKICAgICAgYXdhaXQgYmxvYy5jbG9zZSgpOwogICAgfSwKICApOwp9Cg==", + "type": "text" + }, { "path": "{{ name.snakeCase() }}/packages/design_system/lib/components/asset_image.dart", @@ -496,7 +577,7 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "path": "{{ name.snakeCase() }}/packages/design_system/lib/components/auth_headers_builder.dart", "data": - "e3sjbmV0d29ya319aW1wb3J0ICdwYWNrYWdlOmNvcmUvY29yZS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlci9tYXRlcmlhbC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOm5ldHdvcmsvbmV0d29yay5kYXJ0JzsKCi8vLyBBIHdpZGdldCB0aGF0IHByb3ZpZGVzIGF1dGhlbnRpY2F0aW9uIGhlYWRlcnMgdG8gaXRzIGNoaWxkIGJ1aWxkZXIuCi8vLwovLy8gVGhpcyB3aWRnZXQgYXV0b21hdGljYWxseSBmZXRjaGVzIHRoZSBjdXJyZW50IGF1dGhlbnRpY2F0aW9uIHRva2VuCi8vLyB1c2luZyB0aGUgW0F1dGhUb2tlblByb3ZpZGVyXSBmcm9tIGRlcGVuZGVuY3kgaW5qZWN0aW9uIGFuZCBjb25zdHJ1Y3RzCi8vLyBIVFRQIGhlYWRlcnMgd2l0aCB0aGUgQmVhcmVyIHRva2VuLgovLy8KLy8vIEV4YW1wbGUgdXNhZ2U6Ci8vLyBgYGBkYXJ0Ci8vLyAvLyBXaXRob3V0IHRva2VuIHZhbGlkYXRpb24gKGRlZmF1bHQgLSBmYXN0ZXIsIHVzZXMgY2FjaGVkIHRva2VuKQovLy8gQXV0aEhlYWRlcnNCdWlsZGVyKAovLy8gICBidWlsZGVyOiAoY29udGV4dCwgaGVhZGVycykgewovLy8gICAgIHJldHVybiBDYWNoZWROZXR3b3JrSW1hZ2UoCi8vLyAgICAgICBpbWFnZVVybDogaW1hZ2VVcmwsCi8vLyAgICAgICBodHRwSGVhZGVyczogaGVhZGVycywKLy8vICAgICApOwovLy8gICB9LAovLy8gKQovLy8KLy8vIC8vIFdpdGggdG9rZW4gdmFsaWRhdGlvbiAoZW5zdXJlcyBmcmVzaCB0b2tlbikKLy8vIEF1dGhIZWFkZXJzQnVpbGRlcihkCi8vLyAgIHZhbGlkYXRlVG9rZW46IHRydWUsCi8vLyAgIGJ1aWxkZXI6IChjb250ZXh0LCBoZWFkZXJzKSB7Ci8vLyAgICAgcmV0dXJuIENhY2hlZE5ldHdvcmtJbWFnZSgKLy8vICAgICAgIGltYWdlVXJsOiBpbWFnZVVybCwKLy8vICAgICAgIGh0dHBIZWFkZXJzOiBoZWFkZXJzLAovLy8gICAgICk7Ci8vLyAgIH0sCi8vLyApCi8vLyBgYGAKY2xhc3MgQXV0aEhlYWRlcnNCdWlsZGVyIGV4dGVuZHMgU3RhdGVsZXNzV2lkZ2V0IHsKICBzdGF0aWMgZmluYWwgX2xvZ2dlciA9IGRpLmdldDxMb2dnZXI+KCk7CgogIC8vLyBDcmVhdGVzIGFuIFtBdXRoSGVhZGVyc0J1aWxkZXJdLgogIC8vLwogIC8vLyBUaGUgW2J1aWxkZXJdIGZ1bmN0aW9uIGlzIGNhbGxlZCB3aXRoIHRoZSBjdXJyZW50IFtCdWlsZENvbnRleHRdIGFuZAogIC8vLyBhIG1hcCBvZiBIVFRQIGhlYWRlcnMuIElmIGF1dGhlbnRpY2F0aW9uIGZhaWxzIG9yIG5vIHRva2VuIGlzIGF2YWlsYWJsZSwKICAvLy8gYW4gZW1wdHkgbWFwIGlzIHByb3ZpZGVkLgogIC8vLwogIC8vLyBJZiBbdmFsaWRhdGVUb2tlbl0gaXMgdHJ1ZSwgdGhlIHRva2VuIHdpbGwgYmUgdmFsaWRhdGVkIGFuZAogIC8vLyByZWZyZXNoZWQgaWYgbmVlZGVkLiBJZiBmYWxzZSAoZGVmYXVsdCksIHRoZSBjdXJyZW50IGNhY2hlZCB0b2tlbiB3aWxsIGJlIHVzZWQKICAvLy8gd2l0aG91dCB2YWxpZGF0aW9uLgogIGNvbnN0IEF1dGhIZWFkZXJzQnVpbGRlcih7CiAgICBzdXBlci5rZXksCiAgICByZXF1aXJlZCB0aGlzLmJ1aWxkZXIsCiAgICB0aGlzLnZhbGlkYXRlVG9rZW4gPSBmYWxzZSwKICB9KTsKCiAgLy8vIFRoZSBidWlsZGVyIGZ1bmN0aW9uIHRoYXQgcmVjZWl2ZXMgdGhlIGF1dGhlbnRpY2F0aW9uIGhlYWRlcnMuCiAgLy8vCiAgLy8vIFRoZSBoZWFkZXJzIG1hcCB3aWxsIGNvbnRhaW46CiAgLy8vIC0gJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyIHt0b2tlbn0nIChpZiBhdXRoZW50aWNhdGVkKQogIC8vLyAtICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicKICAvLy8KICAvLy8gSWYgbm8gYXV0aGVudGljYXRpb24gdG9rZW4gaXMgYXZhaWxhYmxlLCBhbiBlbXB0eSBtYXAge30gaXMgcHJvdmlkZWQuCiAgZmluYWwgV2lkZ2V0IEZ1bmN0aW9uKEJ1aWxkQ29udGV4dCBjb250ZXh0LCBNYXA8U3RyaW5nLCBTdHJpbmc+IGhlYWRlcnMpCiAgYnVpbGRlcjsKCiAgLy8vIFdoZXRoZXIgdG8gdmFsaWRhdGUgYW5kIHBvdGVudGlhbGx5IHJlZnJlc2ggdGhlIHRva2VuLgogIC8vLwogIC8vLyBJZiB0cnVlLCB1c2VzIFtBdXRoVG9rZW5Qcm92aWRlci5nZXRWYWxpZFRva2VuXSB3aGljaCB2YWxpZGF0ZXMKICAvLy8gdGhlIHRva2VuIGFuZCByZWZyZXNoZXMgaXQgaWYgbmVlZGVkLgogIC8vLyBJZiBmYWxzZSAoZGVmYXVsdCksIHVzZXMgW0F1dGhUb2tlblByb3ZpZGVyLmdldEN1cnJlbnRUb2tlbl0gd2hpY2ggcmV0dXJucyB0aGUKICAvLy8gY2FjaGVkIHRva2VuIHdpdGhvdXQgdmFsaWRhdGlvbi4KICBmaW5hbCBib29sIHZhbGlkYXRlVG9rZW47CgogIE1hcDxTdHJpbmcsIFN0cmluZz4gX2dldFN5bmNBdXRoSGVhZGVycygpIHsKICAgIHRyeSB7CiAgICAgIGZpbmFsIGF1dGhUb2tlblByb3ZpZGVyID0gZGkuZ2V0PEF1dGhUb2tlblByb3ZpZGVyPigpOwogICAgICBmaW5hbCB0b2tlbiA9IGF1dGhUb2tlblByb3ZpZGVyLmdldEN1cnJlbnRUb2tlbigpOwoKICAgICAgaWYgKHRva2VuICE9IG51bGwpIHsKICAgICAgICByZXR1cm4geydBdXRob3JpemF0aW9uJzogJ0JlYXJlciAkdG9rZW4nfTsKICAgICAgfQogICAgfSBjYXRjaCAoZSkgewogICAgICBfbG9nZ2VyLmUoJ0Vycm9yIGdldHRpbmcgYXV0aCBoZWFkZXJzOiAkZScpOwogICAgfQogICAgcmV0dXJuIHt9OwogIH0KCiAgRnV0dXJlPE1hcDxTdHJpbmcsIFN0cmluZz4+IF9nZXRBc3luY0F1dGhIZWFkZXJzKCkgYXN5bmMgewogICAgdHJ5IHsKICAgICAgZmluYWwgYXV0aFRva2VuUHJvdmlkZXIgPSBkaS5nZXQ8QXV0aFRva2VuUHJvdmlkZXI+KCk7CiAgICAgIGZpbmFsIHRva2VuID0gYXdhaXQgYXV0aFRva2VuUHJvdmlkZXIuZ2V0VmFsaWRUb2tlbigpOwoKICAgICAgaWYgKHRva2VuICE9IG51bGwpIHsKICAgICAgICByZXR1cm4geydBdXRob3JpemF0aW9uJzogJ0JlYXJlciAkdG9rZW4nfTsKICAgICAgfQogICAgfSBjYXRjaCAoZSkgewogICAgICBfbG9nZ2VyLmUoJ0Vycm9yIGdldHRpbmcgYXV0aCBoZWFkZXJzOiAkZScpOwogICAgfQogICAgcmV0dXJuIHt9OwogIH0KCiAgQG92ZXJyaWRlCiAgV2lkZ2V0IGJ1aWxkKEJ1aWxkQ29udGV4dCBjb250ZXh0KSB7CiAgICAvLyBJZiB2YWxpZGF0aW9uIGlzIG5vdCBuZWVkZWQsIHJldHVybiBzeW5jaHJvbm91c2x5IHdpdGhvdXQgRnV0dXJlQnVpbGRlcgogICAgaWYgKCF2YWxpZGF0ZVRva2VuKSB7CiAgICAgIGZpbmFsIGhlYWRlcnMgPSBfZ2V0U3luY0F1dGhIZWFkZXJzKCk7CiAgICAgIHJldHVybiBidWlsZGVyKGNvbnRleHQsIGhlYWRlcnMpOwogICAgfQoKICAgIC8vIElmIHZhbGlkYXRpb24gaXMgbmVlZGVkLCB1c2UgRnV0dXJlQnVpbGRlcgogICAgcmV0dXJuIEZ1dHVyZUJ1aWxkZXI8TWFwPFN0cmluZywgU3RyaW5nPj4oCiAgICAgIGZ1dHVyZTogX2dldEFzeW5jQXV0aEhlYWRlcnMoKSwKICAgICAgYnVpbGRlcjogKGNvbnRleHQsIHNuYXBzaG90KSB7CiAgICAgICAgZmluYWwgaGVhZGVycyA9IHNuYXBzaG90LmRhdGEgPz8ge307CiAgICAgICAgcmV0dXJuIGJ1aWxkZXIoY29udGV4dCwgaGVhZGVycyk7CiAgICAgIH0sCiAgICApOwogIH0KfXt7L25ldHdvcmt9fQo=", + "e3sjbmV0d29ya319aW1wb3J0ICdwYWNrYWdlOmNvcmUvY29yZS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlci9tYXRlcmlhbC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOm5ldHdvcmsvbmV0d29yay5kYXJ0JzsKCi8vLyBTdXBwbGllcyBiZWFyZXIgaGVhZGVycyB3aXRob3V0IHN0YXJ0aW5nIGEgbmV3IHJlZnJlc2ggb24gZXZlcnkgcmVidWlsZC4KLy8vIEluamVjdCBhIHByb3ZpZGVyIGluIHRlc3RzOyB0aGUgY29tcG9zaXRpb24tcm9vdCByZWdpc3RyYXRpb24gaXMgdGhlIGRlZmF1bHQuCi8vLyBVc2UgYSBuZXcga2V5IHdoZW4gdGhlIHNpZ25lZC1pbiBpZGVudGl0eSBjaGFuZ2VzLgpjbGFzcyBBdXRoSGVhZGVyc0J1aWxkZXIgZXh0ZW5kcyBTdGF0ZWZ1bFdpZGdldCB7CiAgY29uc3QgQXV0aEhlYWRlcnNCdWlsZGVyKHsKICAgIHN1cGVyLmtleSwKICAgIHJlcXVpcmVkIHRoaXMuYnVpbGRlciwKICAgIHRoaXMudmFsaWRhdGVUb2tlbiA9IGZhbHNlLAogICAgdGhpcy5wcm92aWRlciwKICAgIHRoaXMubG9nZ2VyLAogIH0pOwoKICBmaW5hbCBXaWRnZXQgRnVuY3Rpb24oQnVpbGRDb250ZXh0IGNvbnRleHQsIE1hcDxTdHJpbmcsIFN0cmluZz4gaGVhZGVycykKICBidWlsZGVyOwogIGZpbmFsIGJvb2wgdmFsaWRhdGVUb2tlbjsKICBmaW5hbCBBdXRoVG9rZW5Qcm92aWRlcj8gcHJvdmlkZXI7CiAgZmluYWwgTG9nZ2VyPyBsb2dnZXI7CgogIEBvdmVycmlkZQogIFN0YXRlPEF1dGhIZWFkZXJzQnVpbGRlcj4gY3JlYXRlU3RhdGUoKSA9PiBfQXV0aEhlYWRlcnNCdWlsZGVyU3RhdGUoKTsKfQoKY2xhc3MgX0F1dGhIZWFkZXJzQnVpbGRlclN0YXRlIGV4dGVuZHMgU3RhdGU8QXV0aEhlYWRlcnNCdWlsZGVyPiB7CiAgRnV0dXJlPE1hcDxTdHJpbmcsIFN0cmluZz4+PyBfaGVhZGVyczsKCiAgQXV0aFRva2VuUHJvdmlkZXI/IGdldCBfcHJvdmlkZXIgPT4KICAgICAgd2lkZ2V0LnByb3ZpZGVyID8/CiAgICAgIChkaS5oYXM8QXV0aFRva2VuUHJvdmlkZXI+KCkgPyBkaS5nZXQ8QXV0aFRva2VuUHJvdmlkZXI+KCkgOiBudWxsKTsKCiAgQG92ZXJyaWRlCiAgdm9pZCBpbml0U3RhdGUoKSB7CiAgICBzdXBlci5pbml0U3RhdGUoKTsKICAgIF9yZWZyZXNoKCk7CiAgfQoKICBAb3ZlcnJpZGUKICB2b2lkIGRpZFVwZGF0ZVdpZGdldChjb3ZhcmlhbnQgQXV0aEhlYWRlcnNCdWlsZGVyIG9sZFdpZGdldCkgewogICAgc3VwZXIuZGlkVXBkYXRlV2lkZ2V0KG9sZFdpZGdldCk7CiAgICBpZiAob2xkV2lkZ2V0LnByb3ZpZGVyICE9IHdpZGdldC5wcm92aWRlciB8fAogICAgICAgIG9sZFdpZGdldC52YWxpZGF0ZVRva2VuICE9IHdpZGdldC52YWxpZGF0ZVRva2VuKSB7CiAgICAgIF9yZWZyZXNoKCk7CiAgICB9CiAgfQoKICB2b2lkIF9yZWZyZXNoKCkgewogICAgX2hlYWRlcnMgPSB3aWRnZXQudmFsaWRhdGVUb2tlbiA/IF9sb2FkKCkgOiBudWxsOwogIH0KCiAgTWFwPFN0cmluZywgU3RyaW5nPiBfZnJvbVRva2VuKFN0cmluZz8gdG9rZW4pID0+CiAgICAgIHRva2VuID09IG51bGwgfHwgdG9rZW4uaXNFbXB0eSA/IHt9IDogeydBdXRob3JpemF0aW9uJzogJ0JlYXJlciAkdG9rZW4nfTsKCiAgdm9pZCBfbG9nKE9iamVjdCBlcnJvciwgU3RhY2tUcmFjZSBzdGFjaykgewogICAgZmluYWwgbG9nZ2VyID0KICAgICAgICB3aWRnZXQubG9nZ2VyID8/IChkaS5oYXM8TG9nZ2VyPigpID8gZGkuZ2V0PExvZ2dlcj4oKSA6IG51bGwpOwogICAgbG9nZ2VyPy5lKCdVbmFibGUgdG8gb2J0YWluIGltYWdlIGF1dGhlbnRpY2F0aW9uIGhlYWRlcnMnLCBlcnJvciwgc3RhY2spOwogIH0KCiAgRnV0dXJlPE1hcDxTdHJpbmcsIFN0cmluZz4+IF9sb2FkKCkgYXN5bmMgewogICAgdHJ5IHsKICAgICAgcmV0dXJuIF9mcm9tVG9rZW4oYXdhaXQgX3Byb3ZpZGVyPy5nZXRWYWxpZFRva2VuKCkpOwogICAgfSBjYXRjaCAoZXJyb3IsIHN0YWNrKSB7CiAgICAgIF9sb2coZXJyb3IsIHN0YWNrKTsKICAgICAgcmV0dXJuIHt9OwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgV2lkZ2V0IGJ1aWxkKEJ1aWxkQ29udGV4dCBjb250ZXh0KSB7CiAgICBpZiAoIXdpZGdldC52YWxpZGF0ZVRva2VuKSB7CiAgICAgIE1hcDxTdHJpbmcsIFN0cmluZz4gaGVhZGVyczsKICAgICAgdHJ5IHsKICAgICAgICBoZWFkZXJzID0gX2Zyb21Ub2tlbihfcHJvdmlkZXI/LmdldEN1cnJlbnRUb2tlbigpKTsKICAgICAgfSBjYXRjaCAoZXJyb3IsIHN0YWNrKSB7CiAgICAgICAgX2xvZyhlcnJvciwgc3RhY2spOwogICAgICAgIGhlYWRlcnMgPSB7fTsKICAgICAgfQogICAgICByZXR1cm4gd2lkZ2V0LmJ1aWxkZXIoY29udGV4dCwgaGVhZGVycyk7CiAgICB9CiAgICByZXR1cm4gRnV0dXJlQnVpbGRlcjxNYXA8U3RyaW5nLCBTdHJpbmc+PigKICAgICAga2V5OiBWYWx1ZUtleShfaGVhZGVycyksCiAgICAgIGZ1dHVyZTogX2hlYWRlcnMsCiAgICAgIGJ1aWxkZXI6IChjb250ZXh0LCBzbmFwc2hvdCkgPT4KICAgICAgICAgIHdpZGdldC5idWlsZGVyKGNvbnRleHQsIHNuYXBzaG90LmRhdGEgPz8ge30pLAogICAgKTsKICB9Cn0Ke3svbmV0d29ya319Cg==", "type": "text" }, { @@ -517,7 +598,7 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "path": "{{ name.snakeCase() }}/packages/design_system/lib/components/header.dart", "data": - "aW1wb3J0ICdwYWNrYWdlOmRlc2lnbl9zeXN0ZW0vY29tcG9uZW50cy9uZXR3b3JrX3VybF9pbWFnZS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRlc2lnbl9zeXN0ZW0vdXRpbHMvaW5kZXguZGFydCc7CmltcG9ydCAncGFja2FnZTpmbHV0dGVyL21hdGVyaWFsLmRhcnQnOwoKZW51bSBIZWFkZXJUeXBlIHsKICBpbWFnZSwKICBhc3NldDsKCiAgZG91YmxlIGdldCByYXRpbyA9PiBzd2l0Y2ggKHRoaXMpIHsKICAgIEhlYWRlclR5cGUuaW1hZ2UgPT4gNCAvIDEsCiAgICBIZWFkZXJUeXBlLmFzc2V0ID0+IDEgLyAxLAogIH07Cn0KCmNsYXNzIEhlYWRlciBleHRlbmRzIFN0YXRlbGVzc1dpZGdldCB7CiAgY29uc3QgSGVhZGVyKHsKICAgIHN1cGVyLmtleSwKICAgIHRoaXMudHlwZSA9IEhlYWRlclR5cGUuaW1hZ2UsCiAgICB0aGlzLmFzc2V0UGF0aCwKICAgIHRoaXMuaW1hZ2VVcmwsCiAgfSk7CgogIGZpbmFsIEhlYWRlclR5cGUgdHlwZTsKICBmaW5hbCBTdHJpbmc/IGFzc2V0UGF0aDsKICBmaW5hbCBTdHJpbmc/IGltYWdlVXJsOwoKICBAb3ZlcnJpZGUKICBXaWRnZXQgYnVpbGQoQnVpbGRDb250ZXh0IGNvbnRleHQpIHsKICAgIHJldHVybiBBc3BlY3RSYXRpbyhhc3BlY3RSYXRpbzogdHlwZS5yYXRpbywgY2hpbGQ6IF9idWlsZEltYWdlKGNvbnRleHQpKTsKICB9CgogIFdpZGdldCBfYnVpbGRJbWFnZShCdWlsZENvbnRleHQgY29udGV4dCkgewogICAgc3dpdGNoICh0eXBlKSB7CiAgICAgIGNhc2UgSGVhZGVyVHlwZS5hc3NldDoKICAgICAgICByZXR1cm4gSGVybygKICAgICAgICAgIHRhZzogYXNzZXRQYXRoISwKICAgICAgICAgIGNoaWxkOiBJbWFnZS5hc3NldCgKICAgICAgICAgICAgYXNzZXRQYXRoISwKICAgICAgICAgICAgZml0OiBCb3hGaXQuY29udGFpbiwKICAgICAgICAgICAgYWxpZ25tZW50OiBBbGlnbm1lbnQuY2VudGVyLAogICAgICAgICAgKSwKICAgICAgICApOwogICAgICBjYXNlIEhlYWRlclR5cGUuaW1hZ2U6CiAgICAgICAgcmV0dXJuIE5ldHdvcmtVcmxJbWFnZSh1cmw6IGltYWdlVXJsLmFzRW1wdHlJZk51bGwpOwogICAgfQogIH0KfQo=", + "aW1wb3J0ICdwYWNrYWdlOmRlc2lnbl9zeXN0ZW0vY29tcG9uZW50cy9uZXR3b3JrX3VybF9pbWFnZS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRlc2lnbl9zeXN0ZW0vdXRpbHMvaW5kZXguZGFydCc7CmltcG9ydCAncGFja2FnZTpmbHV0dGVyL21hdGVyaWFsLmRhcnQnOwoKZW51bSBIZWFkZXJUeXBlIHsKICBpbWFnZSwKICBhc3NldDsKCiAgZG91YmxlIGdldCByYXRpbyA9PiBzd2l0Y2ggKHRoaXMpIHsKICAgIEhlYWRlclR5cGUuaW1hZ2UgPT4gNCAvIDEsCiAgICBIZWFkZXJUeXBlLmFzc2V0ID0+IDEgLyAxLAogIH07Cn0KCmNsYXNzIEhlYWRlciBleHRlbmRzIFN0YXRlbGVzc1dpZGdldCB7CiAgY29uc3QgSGVhZGVyKHsKICAgIHN1cGVyLmtleSwKICAgIHRoaXMudHlwZSA9IEhlYWRlclR5cGUuaW1hZ2UsCiAgICB0aGlzLmFzc2V0UGF0aCwKICAgIHRoaXMuaW1hZ2VVcmwsCiAgfSk7CgogIGZpbmFsIEhlYWRlclR5cGUgdHlwZTsKICBmaW5hbCBTdHJpbmc/IGFzc2V0UGF0aDsKICBmaW5hbCBTdHJpbmc/IGltYWdlVXJsOwoKICBAb3ZlcnJpZGUKICBXaWRnZXQgYnVpbGQoQnVpbGRDb250ZXh0IGNvbnRleHQpIHsKICAgIHJldHVybiBBc3BlY3RSYXRpbyhhc3BlY3RSYXRpbzogdHlwZS5yYXRpbywgY2hpbGQ6IF9idWlsZEltYWdlKGNvbnRleHQpKTsKICB9CgogIFdpZGdldCBfYnVpbGRJbWFnZShCdWlsZENvbnRleHQgY29udGV4dCkgewogICAgc3dpdGNoICh0eXBlKSB7CiAgICAgIGNhc2UgSGVhZGVyVHlwZS5hc3NldDoKICAgICAgICBpZiAoYXNzZXRQYXRoID09IG51bGwgfHwgYXNzZXRQYXRoIS5pc0VtcHR5KSB7CiAgICAgICAgICByZXR1cm4gY29uc3QgSWNvbihJY29ucy5pbWFnZSk7CiAgICAgICAgfQogICAgICAgIHJldHVybiBIZXJvKAogICAgICAgICAgdGFnOiBhc3NldFBhdGghLAogICAgICAgICAgY2hpbGQ6IEltYWdlLmFzc2V0KAogICAgICAgICAgICBhc3NldFBhdGghLAogICAgICAgICAgICBmaXQ6IEJveEZpdC5jb250YWluLAogICAgICAgICAgICBhbGlnbm1lbnQ6IEFsaWdubWVudC5jZW50ZXIsCiAgICAgICAgICAgIGVycm9yQnVpbGRlcjogKF8sIF8sIF8pID0+IGNvbnN0IEljb24oSWNvbnMuaW1hZ2UpLAogICAgICAgICAgKSwKICAgICAgICApOwogICAgICBjYXNlIEhlYWRlclR5cGUuaW1hZ2U6CiAgICAgICAgcmV0dXJuIE5ldHdvcmtVcmxJbWFnZSh1cmw6IGltYWdlVXJsLmFzRW1wdHlJZk51bGwpOwogICAgfQogIH0KfQo=", "type": "text" }, { @@ -545,7 +626,7 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "path": "{{ name.snakeCase() }}/packages/design_system/lib/constants/navigation_icons.dart", "data": - "aW1wb3J0ICdwYWNrYWdlOmZsdXR0ZXIvbWF0ZXJpYWwuZGFydCc7CgovLy8gSWNvbnMgdXNlZCBieSB0aGUgYXBwJ3MgcHJpbWFyeSBuYXZpZ2F0aW9uLgovLy8KLy8vIFN3YXAgdGhlc2UgZm9yIHlvdXIgcHJvZHVjdCdzIGljb24gc2V0IC0gZXZlcnkgbmF2aWdhdGlvbiBzdXJmYWNlIHJlYWRzCi8vLyBmcm9tIGhlcmUgc28gYSBzaW5nbGUgZWRpdCByZS1za2lucyB0aGUgd2hvbGUgc2hlbGwuCmNsYXNzIE5hdmlnYXRpb25JY29ucyB7CiAgY29uc3QgTmF2aWdhdGlvbkljb25zLl8oKTsKCiAgc3RhdGljIGNvbnN0IEljb25EYXRhIGhvbWUgPSBJY29ucy5ob21lX291dGxpbmVkOwogIHN0YXRpYyBjb25zdCBJY29uRGF0YSBob21lU2VsZWN0ZWQgPSBJY29ucy5ob21lOwoKICBzdGF0aWMgY29uc3QgSWNvbkRhdGEgZXhwbG9yZSA9IEljb25zLmV4cGxvcmVfb3V0bGluZWQ7CiAgc3RhdGljIGNvbnN0IEljb25EYXRhIGV4cGxvcmVTZWxlY3RlZCA9IEljb25zLmV4cGxvcmU7CgogIHN0YXRpYyBjb25zdCBJY29uRGF0YSBkYXNoYm9hcmQgPSBJY29ucy5kYXNoYm9hcmRfb3V0bGluZWQ7CiAgc3RhdGljIGNvbnN0IEljb25EYXRhIGRhc2hib2FyZFNlbGVjdGVkID0gSWNvbnMuZGFzaGJvYXJkOwoKICBzdGF0aWMgY29uc3QgSWNvbkRhdGEgaW5zaWdodHMgPSBJY29ucy50cmVuZGluZ191cF9vdXRsaW5lZDsKICBzdGF0aWMgY29uc3QgSWNvbkRhdGEgaW5zaWdodHNTZWxlY3RlZCA9IEljb25zLnRyZW5kaW5nX3VwOwoKICBzdGF0aWMgY29uc3QgSWNvbkRhdGEgcHJvZmlsZSA9IEljb25zLnBlcnNvbl9vdXRsaW5lOwogIHN0YXRpYyBjb25zdCBJY29uRGF0YSBwcm9maWxlU2VsZWN0ZWQgPSBJY29ucy5wZXJzb247CgogIHN0YXRpYyBjb25zdCBJY29uRGF0YSBzZXR0aW5ncyA9IEljb25zLnNldHRpbmdzX291dGxpbmVkOwp9Cg==", + "aW1wb3J0ICdwYWNrYWdlOmZsdXR0ZXIvbWF0ZXJpYWwuZGFydCc7CgovLy8gSWNvbnMgdXNlZCBieSB0aGUgYXBwJ3MgcHJpbWFyeSBuYXZpZ2F0aW9uLgovLy8KLy8vIFN3YXAgdGhlc2UgZm9yIHlvdXIgcHJvZHVjdCdzIGljb24gc2V0IC0gZXZlcnkgbmF2aWdhdGlvbiBzdXJmYWNlIHJlYWRzCi8vLyBmcm9tIGhlcmUgc28gYSBzaW5nbGUgZWRpdCByZS1za2lucyB0aGUgd2hvbGUgc2hlbGwuCmFic3RyYWN0IGZpbmFsIGNsYXNzIE5hdmlnYXRpb25JY29ucyB7CiAgc3RhdGljIGNvbnN0IEljb25EYXRhIGhvbWUgPSBJY29ucy5ob21lX291dGxpbmVkOwogIHN0YXRpYyBjb25zdCBJY29uRGF0YSBob21lU2VsZWN0ZWQgPSBJY29ucy5ob21lOwoKICBzdGF0aWMgY29uc3QgSWNvbkRhdGEgZXhwbG9yZSA9IEljb25zLmV4cGxvcmVfb3V0bGluZWQ7CiAgc3RhdGljIGNvbnN0IEljb25EYXRhIGV4cGxvcmVTZWxlY3RlZCA9IEljb25zLmV4cGxvcmU7CgogIHN0YXRpYyBjb25zdCBJY29uRGF0YSBkYXNoYm9hcmQgPSBJY29ucy5kYXNoYm9hcmRfb3V0bGluZWQ7CiAgc3RhdGljIGNvbnN0IEljb25EYXRhIGRhc2hib2FyZFNlbGVjdGVkID0gSWNvbnMuZGFzaGJvYXJkOwoKICBzdGF0aWMgY29uc3QgSWNvbkRhdGEgaW5zaWdodHMgPSBJY29ucy50cmVuZGluZ191cF9vdXRsaW5lZDsKICBzdGF0aWMgY29uc3QgSWNvbkRhdGEgaW5zaWdodHNTZWxlY3RlZCA9IEljb25zLnRyZW5kaW5nX3VwOwoKICBzdGF0aWMgY29uc3QgSWNvbkRhdGEgcHJvZmlsZSA9IEljb25zLnBlcnNvbl9vdXRsaW5lOwogIHN0YXRpYyBjb25zdCBJY29uRGF0YSBwcm9maWxlU2VsZWN0ZWQgPSBJY29ucy5wZXJzb247CgogIHN0YXRpYyBjb25zdCBJY29uRGF0YSBzZXR0aW5ncyA9IEljb25zLnNldHRpbmdzX291dGxpbmVkOwp9Cg==", "type": "text" }, { @@ -640,7 +721,7 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ { "path": "{{ name.snakeCase() }}/packages/design_system/pubspec.yaml", "data": - "bmFtZTogZGVzaWduX3N5c3RlbQpkZXNjcmlwdGlvbjogIlRoZW1lLCBjb21wb25lbnRzIGFuZCBkaWFsb2dzIHNoYXJlZCBhY3Jvc3Mge3tuYW1lLnRpdGxlQ2FzZSgpfX0uIgp2ZXJzaW9uOiAwLjEuMApwdWJsaXNoX3RvOiAnbm9uZScKCmVudmlyb25tZW50OgogIHNkazogXjMuOC4wCiAgZmx1dHRlcjogIj49My4yOS4wIgoKZGVwZW5kZW5jaWVzOgogIGZsdXR0ZXI6CiAgICBzZGs6IGZsdXR0ZXIKICBjYWNoZWRfbmV0d29ya19pbWFnZTogXjMuNC4xCiAgZmx1dHRlcl9zdmc6IF4yLjIuMAogIGdvb2dsZV9mb250czogXjYuMi4xCiAgaWNvbnNheF9mbHV0dGVyOiBeMS4wLjEKICBsb2FkZXJfb3ZlcmxheTogXjUuMC4wCiAgdG9hc3RpZmljYXRpb246IF4zLjAuMwogIGNvcmU6CiAgICBwYXRoOiAuLi9jb3JlCiAgZGk6CiAgICBwYXRoOiAuLi9kaQogIGxvY2FsaXphdGlvbjoKICAgIHBhdGg6IC4uL2xvY2FsaXphdGlvbgp7eyNuZXR3b3JrfX0gIG5ldHdvcms6CiAgICBwYXRoOiAuLi9uZXR3b3JrCnt7L25ldHdvcmt9fQpkZXZfZGVwZW5kZW5jaWVzOgogIGZsdXR0ZXJfdGVzdDoKICAgIHNkazogZmx1dHRlcgogIGZsdXR0ZXJfbGludHM6IF41LjAuMAoKZmx1dHRlcjoK", + "bmFtZTogZGVzaWduX3N5c3RlbQpkZXNjcmlwdGlvbjogIlRoZW1lLCBjb21wb25lbnRzIGFuZCBkaWFsb2dzIHNoYXJlZCBhY3Jvc3Mge3tuYW1lLnRpdGxlQ2FzZSgpfX0uIgp2ZXJzaW9uOiAwLjEuMApwdWJsaXNoX3RvOiAnbm9uZScKCmVudmlyb25tZW50OgogIHNkazogXjMuOC4wCiAgZmx1dHRlcjogIj49My4yOS4wIgoKZGVwZW5kZW5jaWVzOgogIGZsdXR0ZXI6CiAgICBzZGs6IGZsdXR0ZXIKICBjYWNoZWRfbmV0d29ya19pbWFnZTogXjMuNC4xCiAgZmx1dHRlcl9zdmc6IF4yLjIuMAogIGdvb2dsZV9mb250czogXjYuMi4xCiAgaWNvbnNheF9mbHV0dGVyOiBeMS4wLjEKICBsb2FkZXJfb3ZlcmxheTogXjUuMC4wCiAgdG9hc3RpZmljYXRpb246IF4zLjAuMwogIGNvcmU6CiAgICBwYXRoOiAuLi9jb3JlCiAgZGk6CiAgICBwYXRoOiAuLi9kaQogIGxvY2FsaXphdGlvbjoKICAgIHBhdGg6IC4uL2xvY2FsaXphdGlvbgp7eyNuZXR3b3JrfX0gIG5ldHdvcms6CiAgICBwYXRoOiAuLi9uZXR3b3JrCnt7L25ldHdvcmt9fQpkZXZfZGVwZW5kZW5jaWVzOgogIG1vY2t0YWlsOiBeMS4wLjQKICBmbHV0dGVyX3Rlc3Q6CiAgICBzZGs6IGZsdXR0ZXIKICBmbHV0dGVyX2xpbnRzOiBeNS4wLjAKCmZsdXR0ZXI6Cg==", "type": "text" }, { @@ -649,6 +730,13 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "IyBEZXNpZ24gU3lzdGVtCgpBIE1lbG9zLW1hbmFnZWQgcHJvamVjdCBmb3IgbW9uby1yZXBvLCBjcmVhdGVkIHVzaW5nIE5vblN0b3AgQ0xJLgoKWyFbbm9uc3RvcF9jbGldKGh0dHBzOi8vaW1nLnNoaWVsZHMuaW8vYmFkZ2Uvc3RhcnRlZCUyMHdpdGgtbm9uc3RvcF9jbGktMTY2QzRFLnN2Zz9zdHlsZT1mbGF0LXNxdWFyZSldKGh0dHBzOi8vcHViLmRldi9wYWNrYWdlcy9ub25zdG9wX2NsaSkKWyFbbWVsb3NdKGh0dHBzOi8vaW1nLnNoaWVsZHMuaW8vYmFkZ2UvbWFpbnRhaW5lZCUyMHdpdGgtbWVsb3MtZjcwMGZmLnN2Zz9zdHlsZT1mbGF0LXNxdWFyZSldKGh0dHBzOi8vZ2l0aHViLmNvbS9pbnZlcnRhc2UvbWVsb3MpCgojIyBJbnN0YWxsYXRpb24g8J+SuwoKKirinZcgSW4gb3JkZXIgdG8gc3RhcnQgdXNpbmcgRGVzaWduIFN5c3RlbSB5b3UgbXVzdCBoYXZlIHRoZSBbRmx1dHRlciBTREtdW2ZsdXR0ZXJfaW5zdGFsbF9saW5rXSBpbnN0YWxsZWQgb24geW91ciBtYWNoaW5lLioqCgpJbnN0YWxsIHZpYSBgZGFydCBwdWIgYWRkYDoKCmBgYHNoCmRhcnQgcHViIGFkZCBkZXNpZ25fc3lzdGVtCmBgYAoKW2ZsdXR0ZXJfaW5zdGFsbF9saW5rXTogaHR0cHM6Ly9kb2NzLmZsdXR0ZXIuZGV2L2dldC1zdGFydGVkL2luc3RhbGw=", "type": "text" }, + { + "path": + "{{ name.snakeCase() }}/packages/design_system/test/components_test.dart", + "data": + "aW1wb3J0ICdwYWNrYWdlOmRlc2lnbl9zeXN0ZW0vZGVzaWduX3N5c3RlbS5kYXJ0JyBhcyBkczsKaW1wb3J0ICdwYWNrYWdlOmRlc2lnbl9zeXN0ZW0vdXRpbHMvZXh0ZW5zaW9ucy9zdHJpbmcuZGFydCc7CmltcG9ydCAncGFja2FnZTpkZXNpZ25fc3lzdGVtL2dlbmVyYXRlZC90aGVtZS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZsdXR0ZXIvbWF0ZXJpYWwuZGFydCc7CmltcG9ydCAncGFja2FnZTpmbHV0dGVyX3Rlc3QvZmx1dHRlcl90ZXN0LmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6bG9jYWxpemF0aW9uL2xvY2FsaXphdGlvbi5kYXJ0JzsKCnZvaWQgbWFpbigpIHsKICB0ZXN0KAogICAgJ2V4dGVuZGVkIHBhbGV0dGVzIHJldGFpbiBjdXN0b20gY29sb3IgZmFtaWxpZXMgZm9yIGVhY2ggY29udHJhc3QgbW9kZScsCiAgICAoKSB7CiAgICAgIGZpbmFsIGZhbWlseSA9IENvbG9yRmFtaWx5KAogICAgICAgIGNvbG9yOiBDb2xvcnMucmVkLAogICAgICAgIG9uQ29sb3I6IENvbG9ycy53aGl0ZSwKICAgICAgICBjb2xvckNvbnRhaW5lcjogQ29sb3JzLnBpbmssCiAgICAgICAgb25Db2xvckNvbnRhaW5lcjogQ29sb3JzLmJsYWNrLAogICAgICApOwogICAgICBmaW5hbCBleHRlbmRlZCA9IEV4dGVuZGVkQ29sb3IoCiAgICAgICAgc2VlZDogQ29sb3JzLnJlZCwKICAgICAgICB2YWx1ZTogQ29sb3JzLnBpbmssCiAgICAgICAgbGlnaHQ6IGZhbWlseSwKICAgICAgICBsaWdodEhpZ2hDb250cmFzdDogZmFtaWx5LAogICAgICAgIGxpZ2h0TWVkaXVtQ29udHJhc3Q6IGZhbWlseSwKICAgICAgICBkYXJrOiBmYW1pbHksCiAgICAgICAgZGFya0hpZ2hDb250cmFzdDogZmFtaWx5LAogICAgICAgIGRhcmtNZWRpdW1Db250cmFzdDogZmFtaWx5LAogICAgICApOwogICAgICBleHBlY3QoZXh0ZW5kZWQuc2VlZCwgQ29sb3JzLnJlZCk7CiAgICAgIGV4cGVjdChleHRlbmRlZC5saWdodC5jb2xvciwgQ29sb3JzLnJlZCk7CiAgICAgIGV4cGVjdChleHRlbmRlZC5kYXJrLm9uQ29sb3JDb250YWluZXIsIENvbG9ycy5ibGFjayk7CiAgICB9LAogICk7CiAgdGVzdFdpZGdldHMoCiAgICAnZGF0ZSBmaWx0ZXJzIHNlbGVjdCBhbm90aGVyIHBlcmlvZCB3aXRob3V0IGRlc2VsZWN0aW5nIHRoZSBjdXJyZW50IG9uZScsCiAgICAodGVzdGVyKSBhc3luYyB7CiAgICAgIGZpbmFsIGNoYW5nZXMgPSA8ZHMuRGF0ZUZpbHRlclR5cGU+W107CiAgICAgIGF3YWl0IHRlc3Rlci5wdW1wV2lkZ2V0KAogICAgICAgIE1hdGVyaWFsQXBwKAogICAgICAgICAgaG9tZTogU2NhZmZvbGQoCiAgICAgICAgICAgIGJvZHk6IGRzLkRhdGVGaWx0ZXJDaGlwcygKICAgICAgICAgICAgICBzZWxlY3RlZEZpbHRlcjogZHMuRGF0ZUZpbHRlclR5cGUud2VlaywKICAgICAgICAgICAgICBvbkZpbHRlckNoYW5nZWQ6IGNoYW5nZXMuYWRkLAogICAgICAgICAgICApLAogICAgICAgICAgKSwKICAgICAgICApLAogICAgICApOwogICAgICBhd2FpdCB0ZXN0ZXIudGFwKGZpbmQudGV4dChzdHJpbmdzLmNvbW1vbi53ZWVrKSk7CiAgICAgIGV4cGVjdChjaGFuZ2VzLCBpc0VtcHR5KTsKICAgICAgYXdhaXQgdGVzdGVyLnRhcChmaW5kLnRleHQoc3RyaW5ncy5jb21tb24ubW9udGgpKTsKICAgICAgZXhwZWN0KGNoYW5nZXMsIFtkcy5EYXRlRmlsdGVyVHlwZS5tb250aF0pOwogICAgfSwKICApOwoKICB0ZXN0V2lkZ2V0cygnZXJyb3IgdmlldyBleHBsYWlucyBmYWlsdXJlcyBhbmQgZXhwb3NlcyByZXRyeScsICh0ZXN0ZXIpIGFzeW5jIHsKICAgIHZhciByZXRyaWVzID0gMDsKICAgIGF3YWl0IHRlc3Rlci5wdW1wV2lkZ2V0KAogICAgICBNYXRlcmlhbEFwcCgKICAgICAgICBob21lOiBTY2FmZm9sZCgKICAgICAgICAgIGJvZHk6IGRzLkRlZmF1bHRFcnJvclZpZXcoCiAgICAgICAgICAgIGVycm9yOiBTdGF0ZUVycm9yKCdmYWlsdXJlJyksCiAgICAgICAgICAgIHN0YWNrVHJhY2U6IFN0YWNrVHJhY2UuY3VycmVudCwKICAgICAgICAgICAgZGVzY3JpcHRpb25CdWlsZGVyOiAoXykgPT4gJ1RyeSBhbm90aGVyIGNvbm5lY3Rpb24nLAogICAgICAgICAgICBvblJldHJ5OiAoKSB7CiAgICAgICAgICAgICAgcmV0cmllcysrOwogICAgICAgICAgICB9LAogICAgICAgICAgKSwKICAgICAgICApLAogICAgICApLAogICAgKTsKICAgIGV4cGVjdChmaW5kLnRleHQoJ1RyeSBhbm90aGVyIGNvbm5lY3Rpb24nKSwgZmluZHNPbmVXaWRnZXQpOwogICAgYXdhaXQgdGVzdGVyLnRhcChmaW5kLnRleHQoc3RyaW5ncy5nZW5lcmljLnRyeV9hZ2FpbikpOwogICAgZXhwZWN0KHJldHJpZXMsIDEpOwogIH0pOwoKICB0ZXN0V2lkZ2V0cygnZXJyb3Igc2NyZWVuIHByb3ZpZGVzIHJldHJ5IGFuZCBob21lIGFjdGlvbnMnLCAodGVzdGVyKSBhc3luYyB7CiAgICB2YXIgcmV0cmllcyA9IDA7CiAgICB2YXIgaG9tZXMgPSAwOwogICAgYXdhaXQgdGVzdGVyLnB1bXBXaWRnZXQoCiAgICAgIE1hdGVyaWFsQXBwKAogICAgICAgIGhvbWU6IGRzLkVycm9yU2NyZWVuKAogICAgICAgICAgdGl0bGU6ICdVbmF2YWlsYWJsZScsCiAgICAgICAgICBtZXNzYWdlOiAnVHJ5IGxhdGVyJywKICAgICAgICAgIGVycm9yOiAnRGV0YWlscycsCiAgICAgICAgICBvblJldHJ5OiAoKSB7CiAgICAgICAgICAgIHJldHJpZXMrKzsKICAgICAgICAgIH0sCiAgICAgICAgICBvbkdvSG9tZTogKCkgewogICAgICAgICAgICBob21lcysrOwogICAgICAgICAgfSwKICAgICAgICApLAogICAgICApLAogICAgKTsKICAgIGV4cGVjdChmaW5kLnRleHQoJ1VuYXZhaWxhYmxlJyksIGZpbmRzT25lV2lkZ2V0KTsKICAgIGF3YWl0IHRlc3Rlci50YXAoZmluZC5ieVR5cGUoRmlsbGVkQnV0dG9uKSk7CiAgICBhd2FpdCB0ZXN0ZXIudGFwKGZpbmQuYnlUeXBlKE91dGxpbmVkQnV0dG9uKSk7CiAgICBleHBlY3QocmV0cmllcywgMSk7CiAgICBleHBlY3QoaG9tZXMsIDEpOwogIH0pOwoKICBmb3IgKGZpbmFsIGV4dGVuc2lvbiBpbiBbJ3BuZycsICdzdmcnXSkgewogICAgdGVzdFdpZGdldHMoJ21pc3NpbmcgJGV4dGVuc2lvbiBhc3NldHMgcmVuZGVyIGEgZmFsbGJhY2snLCAodGVzdGVyKSBhc3luYyB7CiAgICAgIGF3YWl0IHRlc3Rlci5wdW1wV2lkZ2V0KAogICAgICAgIE1hdGVyaWFsQXBwKGhvbWU6IGRzLkFzc2V0SW1hZ2UoYXNzZXRQYXRoOiAnbWlzc2luZy4kZXh0ZW5zaW9uJykpLAogICAgICApOwogICAgICBhd2FpdCB0ZXN0ZXIucnVuQXN5bmMoCiAgICAgICAgKCkgPT4gRnV0dXJlPHZvaWQ+LmRlbGF5ZWQoY29uc3QgRHVyYXRpb24obWlsbGlzZWNvbmRzOiAxMDApKSwKICAgICAgKTsKICAgICAgYXdhaXQgdGVzdGVyLnB1bXBBbmRTZXR0bGUoKTsKICAgICAgZXhwZWN0KGZpbmQuYnlJY29uKEljb25zLmltYWdlKSwgZmluZHNPbmVXaWRnZXQpOwogICAgfSk7CiAgfQoKICB0ZXN0V2lkZ2V0cygKICAgICdhbGwgdGhlbWUgdmFyaWFudHMgZXhwb3NlIGFwcHJvcHJpYXRlIGJyaWdodG5lc3MgYW5kIHNlbGVjdGVkIHN0eWxlcycsCiAgICAodGVzdGVyKSBhc3luYyB7CiAgICAgIGF3YWl0IHRlc3Rlci5wdW1wV2lkZ2V0KAogICAgICAgIE1hdGVyaWFsQXBwKAogICAgICAgICAgaG9tZTogQnVpbGRlcigKICAgICAgICAgICAgYnVpbGRlcjogKGNvbnRleHQpIHsKICAgICAgICAgICAgICBmaW5hbCBkZXNpZ24gPSBkcy5EZXNpZ25TeXN0ZW0oY29udGV4dCk7CiAgICAgICAgICAgICAgZm9yIChmaW5hbCB0aGVtZSBpbiBbZGVzaWduLmxpZ2h0KCksIGRlc2lnbi5kYXJrKCldKSB7CiAgICAgICAgICAgICAgICBleHBlY3QoCiAgICAgICAgICAgICAgICAgIHRoZW1lLm5hdmlnYXRpb25CYXJUaGVtZS5pY29uVGhlbWUhLnJlc29sdmUoewogICAgICAgICAgICAgICAgICAgIFdpZGdldFN0YXRlLnNlbGVjdGVkLAogICAgICAgICAgICAgICAgICB9KSEuc2l6ZSwKICAgICAgICAgICAgICAgICAgMjAsCiAgICAgICAgICAgICAgICApOwogICAgICAgICAgICAgICAgZXhwZWN0KAogICAgICAgICAgICAgICAgICB0aGVtZS5uYXZpZ2F0aW9uQmFyVGhlbWUuaWNvblRoZW1lIS5yZXNvbHZlKHt9KSEuc2l6ZSwKICAgICAgICAgICAgICAgICAgMjAsCiAgICAgICAgICAgICAgICApOwogICAgICAgICAgICAgICAgZXhwZWN0KAogICAgICAgICAgICAgICAgICB0aGVtZS5uYXZpZ2F0aW9uQmFyVGhlbWUubGFiZWxUZXh0U3R5bGUhLnJlc29sdmUoewogICAgICAgICAgICAgICAgICAgIFdpZGdldFN0YXRlLnNlbGVjdGVkLAogICAgICAgICAgICAgICAgICB9KSEuZm9udFdlaWdodCwKICAgICAgICAgICAgICAgICAgRm9udFdlaWdodC53NjAwLAogICAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICAgIGV4cGVjdCgKICAgICAgICAgICAgICAgICAgdGhlbWUubmF2aWdhdGlvbkJhclRoZW1lLmxhYmVsVGV4dFN0eWxlIQogICAgICAgICAgICAgICAgICAgICAgLnJlc29sdmUoe30pIQogICAgICAgICAgICAgICAgICAgICAgLmZvbnRXZWlnaHQsCiAgICAgICAgICAgICAgICAgIEZvbnRXZWlnaHQudzUwMCwKICAgICAgICAgICAgICAgICk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGZpbmFsIHBhbGV0dGUgPSBkZXNpZ24udGhlbWU7CiAgICAgICAgICAgICAgZm9yIChmaW5hbCB0aGVtZSBpbiBbCiAgICAgICAgICAgICAgICBwYWxldHRlLmxpZ2h0KCksCiAgICAgICAgICAgICAgICBwYWxldHRlLmxpZ2h0TWVkaXVtQ29udHJhc3QoKSwKICAgICAgICAgICAgICAgIHBhbGV0dGUubGlnaHRIaWdoQ29udHJhc3QoKSwKICAgICAgICAgICAgICBdKSB7CiAgICAgICAgICAgICAgICBleHBlY3QodGhlbWUuYnJpZ2h0bmVzcywgQnJpZ2h0bmVzcy5saWdodCk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGZvciAoZmluYWwgdGhlbWUgaW4gWwogICAgICAgICAgICAgICAgcGFsZXR0ZS5kYXJrKCksCiAgICAgICAgICAgICAgICBwYWxldHRlLmRhcmtNZWRpdW1Db250cmFzdCgpLAogICAgICAgICAgICAgICAgcGFsZXR0ZS5kYXJrSGlnaENvbnRyYXN0KCksCiAgICAgICAgICAgICAgXSkgewogICAgICAgICAgICAgICAgZXhwZWN0KHRoZW1lLmJyaWdodG5lc3MsIEJyaWdodG5lc3MuZGFyayk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGV4cGVjdChwYWxldHRlLmV4dGVuZGVkQ29sb3JzLCBpc0VtcHR5KTsKICAgICAgICAgICAgICByZXR1cm4gY29uc3QgU2l6ZWRCb3goKTsKICAgICAgICAgICAgfSwKICAgICAgICAgICksCiAgICAgICAgKSwKICAgICAgKTsKICAgIH0sCiAgKTsKCiAgdGVzdFdpZGdldHMoJ3dyYXBwZXIgY2hhbmdlcyBicmlnaHRuZXNzIGFuZCBzdXBwb3J0cyBsb2FkZXIgc2hvdyBhbmQgaGlkZScsICgKICAgIHRlc3RlciwKICApIGFzeW5jIHsKICAgIHRlc3Rlci5wbGF0Zm9ybURpc3BhdGNoZXIucGxhdGZvcm1CcmlnaHRuZXNzVGVzdFZhbHVlID0gQnJpZ2h0bmVzcy5saWdodDsKICAgIGFkZFRlYXJEb3duKHRlc3Rlci5wbGF0Zm9ybURpc3BhdGNoZXIuY2xlYXJQbGF0Zm9ybUJyaWdodG5lc3NUZXN0VmFsdWUpOwogICAgbGF0ZSBCdWlsZENvbnRleHQgbG9hZGVyQ29udGV4dDsKICAgIGF3YWl0IHRlc3Rlci5wdW1wV2lkZ2V0KAogICAgICBkcy5EZXNpZ25TeXN0ZW1XcmFwcGVyKAogICAgICAgIGJ1aWxkZXI6IChfLCB0aGVtZSkgPT4gTWF0ZXJpYWxBcHAoCiAgICAgICAgICB0aGVtZTogdGhlbWUsCiAgICAgICAgICBob21lOiBCdWlsZGVyKAogICAgICAgICAgICBidWlsZGVyOiAoY29udGV4dCkgewogICAgICAgICAgICAgIGxvYWRlckNvbnRleHQgPSBjb250ZXh0OwogICAgICAgICAgICAgIHJldHVybiBTY2FmZm9sZChib2R5OiBUZXh0KHRoZW1lLmJyaWdodG5lc3MubmFtZSkpOwogICAgICAgICAgICB9LAogICAgICAgICAgKSwKICAgICAgICApLAogICAgICApLAogICAgKTsKICAgIGV4cGVjdChmaW5kLnRleHQoJ2xpZ2h0JyksIGZpbmRzT25lV2lkZ2V0KTsKICAgIHRlc3Rlci5wbGF0Zm9ybURpc3BhdGNoZXIucGxhdGZvcm1CcmlnaHRuZXNzVGVzdFZhbHVlID0gQnJpZ2h0bmVzcy5kYXJrOwogICAgYXdhaXQgdGVzdGVyLnB1bXBBbmRTZXR0bGUoKTsKICAgIGV4cGVjdChmaW5kLnRleHQoJ2RhcmsnKSwgZmluZHNPbmVXaWRnZXQpOwogICAgZHMuTG9hZGVyLnNob3cobG9hZGVyQ29udGV4dCk7CiAgICBhd2FpdCB0ZXN0ZXIucHVtcChjb25zdCBEdXJhdGlvbihtaWxsaXNlY29uZHM6IDQwMCkpOwogICAgZXhwZWN0KGZpbmQuYnlUeXBlKGRzLkRlZmF1bHRMb2FkZXIpLCBmaW5kc09uZVdpZGdldCk7CiAgICBkcy5Mb2FkZXIuaGlkZShsb2FkZXJDb250ZXh0KTsKICAgIGF3YWl0IHRlc3Rlci5wdW1wQW5kU2V0dGxlKCk7CiAgICBleHBlY3QoZmluZC5ieVR5cGUoZHMuRGVmYXVsdExvYWRlciksIGZpbmRzTm90aGluZyk7CiAgfSk7CgogIHRlc3QoJ251bGxhYmxlIHN0cmluZyBoZWxwZXJzIHByZXNlcnZlIG5vbmVtcHR5IHRleHQnLCAoKSB7CiAgICBleHBlY3QoKG51bGwgYXMgU3RyaW5nPykuYXNFbXB0eUlmTnVsbCwgJycpOwogICAgZXhwZWN0KCd0ZXh0Jy5hc0VtcHR5SWZOdWxsLCAndGV4dCcpOwogICAgZXhwZWN0KChudWxsIGFzIFN0cmluZz8pLmlzTm90TnVsbEFuZE5vdEVtcHR5LCBpc0ZhbHNlKTsKICAgIGV4cGVjdCgnJy5pc05vdE51bGxBbmROb3RFbXB0eSwgaXNGYWxzZSk7CiAgICBleHBlY3QoJ3RleHQnLmlzTm90TnVsbEFuZE5vdEVtcHR5LCBpc1RydWUpOwogICAgZXhwZWN0KGRzLkhlYWRlclR5cGUuaW1hZ2UucmF0aW8sIDQpOwogICAgZXhwZWN0KGRzLkhlYWRlclR5cGUuYXNzZXQucmF0aW8sIDEpOwogIH0pOwp9Cg==", + "type": "text" + }, { "path": "{{ name.snakeCase() }}/packages/design_system/test/design_system_test.dart", @@ -656,6 +744,13 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "aW1wb3J0ICdwYWNrYWdlOmRlc2lnbl9zeXN0ZW0vZGVzaWduX3N5c3RlbS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZsdXR0ZXIvbWF0ZXJpYWwuZGFydCc7CmltcG9ydCAncGFja2FnZTpmbHV0dGVyX3Rlc3QvZmx1dHRlcl90ZXN0LmRhcnQnOwoKdm9pZCBtYWluKCkgewogIHRlc3RXaWRnZXRzKCdEZXNpZ25TeXN0ZW1XcmFwcGVyIGhhbmRzIHRoZSBidWlsZGVyIGEgdGhlbWVkIGNvbnRleHQnLCAoCiAgICB0ZXN0ZXIsCiAgKSBhc3luYyB7CiAgICBsYXRlIFRoZW1lRGF0YSBidWlsdDsKCiAgICBhd2FpdCB0ZXN0ZXIucHVtcFdpZGdldCgKICAgICAgTWF0ZXJpYWxBcHAoCiAgICAgICAgaG9tZTogRGVzaWduU3lzdGVtV3JhcHBlcigKICAgICAgICAgIGJ1aWxkZXI6IChjb250ZXh0LCB0aGVtZSkgewogICAgICAgICAgICBidWlsdCA9IHRoZW1lOwogICAgICAgICAgICByZXR1cm4gY29uc3QgU2l6ZWRCb3guc2hyaW5rKCk7CiAgICAgICAgICB9LAogICAgICAgICksCiAgICAgICksCiAgICApOwoKICAgIGV4cGVjdChidWlsdC51c2VNYXRlcmlhbDMsIGlzVHJ1ZSk7CiAgICBleHBlY3QoYnVpbHQuY29sb3JTY2hlbWUucHJpbWFyeSwgaXNOb3QoQ29sb3JzLnRyYW5zcGFyZW50KSk7CiAgfSk7Cn0K", "type": "text" }, + { + "path": + "{{ name.snakeCase() }}/packages/design_system/test/integration_test.dart", + "data": + "aW1wb3J0ICdkYXJ0OmlvJzsKCmltcG9ydCAncGFja2FnZTpjYWNoZWRfbmV0d29ya19pbWFnZS9jYWNoZWRfbmV0d29ya19pbWFnZS5kYXJ0JzsKe3sjbmV0d29ya319aW1wb3J0ICdwYWNrYWdlOmNvcmUvY29yZS5kYXJ0JzsKe3svbmV0d29ya319CmltcG9ydCAncGFja2FnZTpkZXNpZ25fc3lzdGVtL2Rlc2lnbl9zeXN0ZW0uZGFydCcgYXMgZHM7CmltcG9ydCAncGFja2FnZTpkZXNpZ25fc3lzdGVtL3RvYXN0L3RvYXN0cy5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZsdXR0ZXIvbWF0ZXJpYWwuZGFydCc7CmltcG9ydCAncGFja2FnZTpmbHV0dGVyL3NlcnZpY2VzLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlcl90ZXN0L2ZsdXR0ZXJfdGVzdC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOm1vY2t0YWlsL21vY2t0YWlsLmRhcnQnOwp7eyNuZXR3b3JrfX1pbXBvcnQgJ3BhY2thZ2U6bmV0d29yay9uZXR3b3JrLmRhcnQnOwp7ey9uZXR3b3JrfX0KaW1wb3J0ICdwYWNrYWdlOnRvYXN0aWZpY2F0aW9uL3RvYXN0aWZpY2F0aW9uLmRhcnQnOwoKY2xhc3MgX0ZpbGUgZXh0ZW5kcyBNb2NrIGltcGxlbWVudHMgRmlsZSB7fQoKY2xhc3MgX1N0YXQgZXh0ZW5kcyBNb2NrIGltcGxlbWVudHMgRmlsZVN0YXQge30KCnt7I25ldHdvcmt9fWNsYXNzIF9Ub2tlbnMgZXh0ZW5kcyBNb2NrIGltcGxlbWVudHMgQXV0aFRva2VuUHJvdmlkZXIge30Ke3svbmV0d29ya319Cgp7eyNuZXR3b3JrfX1jbGFzcyBfTG9nZ2VyIGV4dGVuZHMgTW9jayBpbXBsZW1lbnRzIExvZ2dlciB7fQp7ey9uZXR3b3JrfX0KCnZvaWQgbWFpbigpIHsKICB0ZXN0V2lkZ2V0cygKICAgICdmaWxlIGRpYWxvZyByZW5kZXJzIHN1cHBvcnRlZCBtZXRhZGF0YSBzaXplcyBhbmQgY29waWVzIGVhY2ggZmllbGQnLAogICAgKHRlc3RlcikgYXN5bmMgewogICAgICBmaW5hbCBjb3BpZWQgPSA8U3RyaW5nPltdOwogICAgICB0ZXN0ZXIuYmluZGluZy5kZWZhdWx0QmluYXJ5TWVzc2VuZ2VyLnNldE1vY2tNZXRob2RDYWxsSGFuZGxlcigKICAgICAgICBTeXN0ZW1DaGFubmVscy5wbGF0Zm9ybSwKICAgICAgICAoY2FsbCkgYXN5bmMgewogICAgICAgICAgaWYgKGNhbGwubWV0aG9kID09ICdDbGlwYm9hcmQuc2V0RGF0YScpIHsKICAgICAgICAgICAgY29waWVkLmFkZCgoY2FsbC5hcmd1bWVudHMgYXMgTWFwKVsndGV4dCddIGFzIFN0cmluZyk7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gbnVsbDsKICAgICAgICB9LAogICAgICApOwogICAgICBhZGRUZWFyRG93bigKICAgICAgICAoKSA9PiB0ZXN0ZXIuYmluZGluZy5kZWZhdWx0QmluYXJ5TWVzc2VuZ2VyLnNldE1vY2tNZXRob2RDYWxsSGFuZGxlcigKICAgICAgICAgIFN5c3RlbUNoYW5uZWxzLnBsYXRmb3JtLAogICAgICAgICAgbnVsbCwKICAgICAgICApLAogICAgICApOwogICAgICBmb3IgKGZpbmFsIChleHRlbnNpb24sIGxhYmVsLCBzaXplLCBleHBlY3RlZFNpemUpIGluIFsKICAgICAgICAoJ2pwZycsICdKUEVHIEltYWdlJywgMjAsICcyMCBCJyksCiAgICAgICAgKCdwbmcnLCAnUE5HIEltYWdlJywgMTAyNCwgJzEuMCBLQicpLAogICAgICAgICgnZ2lmJywgJ0dJRiBJbWFnZScsIDEwNDg1NzYsICcxLjAgTUInKSwKICAgICAgICAoJ3dlYnAnLCAnV2ViUCBJbWFnZScsIDAsICcwIEInKSwKICAgICAgICAoJ2JtcCcsICdCTVAgSW1hZ2UnLCAwLCAnMCBCJyksCiAgICAgICAgKCd0aWZmJywgJ1RJRkYgSW1hZ2UnLCAwLCAnMCBCJyksCiAgICAgICAgKCdoZWljJywgJ0hFSUYgSW1hZ2UnLCAwLCAnMCBCJyksCiAgICAgICAgKCd1bmtub3duJywgJ0ltYWdlIEZpbGUnLCAwLCAnMCBCJyksCiAgICAgIF0pIHsKICAgICAgICBmaW5hbCBmaWxlID0gX0ZpbGUoKTsKICAgICAgICBmaW5hbCBzdGF0ID0gX1N0YXQoKTsKICAgICAgICB3aGVuKCgpID0+IGZpbGUucGF0aCkudGhlblJldHVybignL2ZpeHR1cmUvaW1hZ2UuJGV4dGVuc2lvbicpOwogICAgICAgIHdoZW4oZmlsZS5zdGF0U3luYykudGhlblJldHVybihzdGF0KTsKICAgICAgICB3aGVuKCgpID0+IHN0YXQuc2l6ZSkudGhlblJldHVybihzaXplKTsKICAgICAgICBhd2FpdCB0ZXN0ZXIucHVtcFdpZGdldCgKICAgICAgICAgIE1hdGVyaWFsQXBwKAogICAgICAgICAgICBob21lOiBTY2FmZm9sZCgKICAgICAgICAgICAgICBib2R5OiBCdWlsZGVyKAogICAgICAgICAgICAgICAgYnVpbGRlcjogKGNvbnRleHQpID0+IFRleHRCdXR0b24oCiAgICAgICAgICAgICAgICAgIG9uUHJlc3NlZDogKCkgPT4gZHMuRmlsZUluZm9EaWFsb2cuc2hvdyhjb250ZXh0LCBmaWxlKSwKICAgICAgICAgICAgICAgICAgY2hpbGQ6IGNvbnN0IFRleHQoJ3Nob3cnKSwKICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgKSwKICAgICAgICAgICksCiAgICAgICAgKTsKICAgICAgICBhd2FpdCB0ZXN0ZXIudGFwKGZpbmQudGV4dCgnc2hvdycpKTsKICAgICAgICBhd2FpdCB0ZXN0ZXIucHVtcEFuZFNldHRsZSgpOwogICAgICAgIGV4cGVjdChmaW5kLnRleHQobGFiZWwpLCBmaW5kc09uZVdpZGdldCk7CiAgICAgICAgZXhwZWN0KGZpbmQudGV4dChleHBlY3RlZFNpemUpLCBmaW5kc09uZVdpZGdldCk7CiAgICAgICAgZm9yIChmaW5hbCBmaWVsZCBpbiBbCiAgICAgICAgICAnRmlsZSBOYW1lJywKICAgICAgICAgICdGaWxlIFR5cGUnLAogICAgICAgICAgJ0ZpbGUgRXh0ZW5zaW9uJywKICAgICAgICAgICdGaWxlIFNpemUnLAogICAgICAgICAgJ0ZpbGUgUGF0aCcsCiAgICAgICAgXSkgewogICAgICAgICAgYXdhaXQgdGVzdGVyLmVuc3VyZVZpc2libGUoZmluZC50ZXh0KGZpZWxkKSk7CiAgICAgICAgICBhd2FpdCB0ZXN0ZXIudGFwKGZpbmQudGV4dChmaWVsZCkpOwogICAgICAgICAgYXdhaXQgdGVzdGVyLnB1bXAoKTsKICAgICAgICB9CiAgICAgICAgZXhwZWN0KGNvcGllZC5sYXN0LCBmaWxlLnBhdGgpOwogICAgICAgIGF3YWl0IHRlc3Rlci50YXAoZmluZC5ieUljb24oSWNvbnMuY2xvc2UpKTsKICAgICAgICBhd2FpdCB0ZXN0ZXIucHVtcEFuZFNldHRsZSgpOwogICAgICAgIGV4cGVjdChmaW5kLmJ5VHlwZShkcy5GaWxlSW5mb0RpYWxvZyksIGZpbmRzTm90aGluZyk7CiAgICAgIH0KICAgICAgZXhwZWN0KGNvcGllZC5sZW5ndGgsIDQwKTsKICAgIH0sCiAgKTsKCiAgdGVzdFdpZGdldHMoCiAgICAnaW1hZ2UgYWRhcHRlcnMgZXhwb3NlIHBsYWNlaG9sZGVyIGFuZCBlcnJvcnMgYW5kIHRvbGVyYXRlIG1pc3NpbmcgaGVhZGVyIGFzc2V0cycsCiAgICAodGVzdGVyKSBhc3luYyB7CiAgICAgIGxhdGUgQ2FjaGVkTmV0d29ya0ltYWdlIGltYWdlOwogICAgICBsYXRlIEJ1aWxkQ29udGV4dCBjb250ZXh0OwogICAgICBhd2FpdCB0ZXN0ZXIucHVtcFdpZGdldCgKICAgICAgICBNYXRlcmlhbEFwcCgKICAgICAgICAgIGhvbWU6IEJ1aWxkZXIoCiAgICAgICAgICAgIGJ1aWxkZXI6IChjdHgpIHsKICAgICAgICAgICAgICBjb250ZXh0ID0gY3R4OwogICAgICAgICAgICAgIGltYWdlID0KICAgICAgICAgICAgICAgICAgY29uc3QgZHMuTmV0d29ya1VybEltYWdlKAogICAgICAgICAgICAgICAgICAgICAgICB1cmw6ICdodHRwczovL2V4YW1wbGUudGVzdC9pbWFnZScsCiAgICAgICAgICAgICAgICAgICAgICAgIHdpZHRoOiA0MCwKICAgICAgICAgICAgICAgICAgICAgICAgaGVpZ2h0OiA2MCwKICAgICAgICAgICAgICAgICAgICAgICkuYnVpbGQoY3R4KQogICAgICAgICAgICAgICAgICAgICAgYXMgQ2FjaGVkTmV0d29ya0ltYWdlOwogICAgICAgICAgICAgIHJldHVybiBpbWFnZS5wbGFjZWhvbGRlciEoY3R4LCAnJyk7CiAgICAgICAgICAgIH0sCiAgICAgICAgICApLAogICAgICAgICksCiAgICAgICk7CiAgICAgIGV4cGVjdChpbWFnZS53aWR0aCwgNDApOwogICAgICBleHBlY3QoZmluZC5ieUljb24oSWNvbnMuaW1hZ2UpLCBmaW5kc09uZVdpZGdldCk7CiAgICAgIGZpbmFsIGVycm9yID0gaW1hZ2UuZXJyb3JXaWRnZXQhKGNvbnRleHQsICcnLCBFeGNlcHRpb24oJ21pc3NpbmcnKSk7CiAgICAgIGF3YWl0IHRlc3Rlci5wdW1wV2lkZ2V0KE1hdGVyaWFsQXBwKGhvbWU6IGVycm9yKSk7CiAgICAgIGV4cGVjdChmaW5kLmJ5SWNvbihJY29ucy5pbWFnZSksIGZpbmRzT25lV2lkZ2V0KTsKICAgICAgZm9yIChmaW5hbCBwYXRoIGluIFtudWxsLCAnJywgJ21pc3NpbmcucG5nJ10pIHsKICAgICAgICBhd2FpdCB0ZXN0ZXIucHVtcFdpZGdldCgKICAgICAgICAgIE1hdGVyaWFsQXBwKAogICAgICAgICAgICBob21lOiBkcy5IZWFkZXIodHlwZTogZHMuSGVhZGVyVHlwZS5hc3NldCwgYXNzZXRQYXRoOiBwYXRoKSwKICAgICAgICAgICksCiAgICAgICAgKTsKICAgICAgICBhd2FpdCB0ZXN0ZXIucnVuQXN5bmMoCiAgICAgICAgICAoKSA9PiBGdXR1cmU8dm9pZD4uZGVsYXllZChjb25zdCBEdXJhdGlvbihtaWxsaXNlY29uZHM6IDUwKSksCiAgICAgICAgKTsKICAgICAgICBhd2FpdCB0ZXN0ZXIucHVtcEFuZFNldHRsZSgpOwogICAgICAgIGV4cGVjdChmaW5kLmJ5SWNvbihJY29ucy5pbWFnZSksIGZpbmRzT25lV2lkZ2V0KTsKICAgICAgICBleHBlY3QodGVzdGVyLnRha2VFeGNlcHRpb24oKSwgaXNOdWxsKTsKICAgICAgfQogICAgICBhd2FpdCB0ZXN0ZXIucHVtcFdpZGdldCgKICAgICAgICBNYXRlcmlhbEFwcCgKICAgICAgICAgIGhvbWU6IEJ1aWxkZXIoCiAgICAgICAgICAgIGJ1aWxkZXI6IChjb250ZXh0KSB7CiAgICAgICAgICAgICAgZmluYWwgaGVhZGVyID0KICAgICAgICAgICAgICAgICAgY29uc3QgZHMuSGVhZGVyKAogICAgICAgICAgICAgICAgICAgICAgICBpbWFnZVVybDogJ2h0dHBzOi8vZXhhbXBsZS50ZXN0L2NvdmVyJywKICAgICAgICAgICAgICAgICAgICAgICkuYnVpbGQoY29udGV4dCkKICAgICAgICAgICAgICAgICAgICAgIGFzIEFzcGVjdFJhdGlvOwogICAgICAgICAgICAgIGV4cGVjdChoZWFkZXIuYXNwZWN0UmF0aW8sIDQpOwogICAgICAgICAgICAgIGV4cGVjdCgKICAgICAgICAgICAgICAgIChoZWFkZXIuY2hpbGQgYXMgZHMuTmV0d29ya1VybEltYWdlKS51cmwsCiAgICAgICAgICAgICAgICAnaHR0cHM6Ly9leGFtcGxlLnRlc3QvY292ZXInLAogICAgICAgICAgICAgICk7CiAgICAgICAgICAgICAgcmV0dXJuIGNvbnN0IFNpemVkQm94KCk7CiAgICAgICAgICAgIH0sCiAgICAgICAgICApLAogICAgICAgICksCiAgICAgICk7CiAgICB9LAogICk7Cgp7eyNuZXR3b3JrfX0gIHRlc3RXaWRnZXRzKAogICAgJ2F1dGggaGVhZGVycyBzdXBwb3J0IG1pc3NpbmcgcHJvdmlkZXJzLCBmYWlsdXJlcyBhbmQgc3RhYmxlIGFzeW5jIHJlYnVpbGRzJywKICAgICh0ZXN0ZXIpIGFzeW5jIHsKICAgICAgZmluYWwgdG9rZW5zID0gX1Rva2VucygpOwogICAgICB3aGVuKHRva2Vucy5nZXRDdXJyZW50VG9rZW4pLnRoZW5SZXR1cm4oJ2NhY2hlZCcpOwogICAgICB3aGVuKHRva2Vucy5nZXRWYWxpZFRva2VuKS50aGVuQW5zd2VyKChfKSBhc3luYyA9PiAnZnJlc2gnKTsKICAgICAgV2lkZ2V0IHN1YmplY3Qoe0F1dGhUb2tlblByb3ZpZGVyPyBwcm92aWRlciwgYm9vbCB2YWxpZGF0ZSA9IGZhbHNlfSkgPT4KICAgICAgICAgIE1hdGVyaWFsQXBwKAogICAgICAgICAgICBob21lOiBkcy5BdXRoSGVhZGVyc0J1aWxkZXIoCiAgICAgICAgICAgICAgcHJvdmlkZXI6IHByb3ZpZGVyLAogICAgICAgICAgICAgIGxvZ2dlcjogX0xvZ2dlcigpLAogICAgICAgICAgICAgIHZhbGlkYXRlVG9rZW46IHZhbGlkYXRlLAogICAgICAgICAgICAgIGJ1aWxkZXI6IChfLCBoZWFkZXJzKSA9PgogICAgICAgICAgICAgICAgICBUZXh0KGhlYWRlcnNbJ0F1dGhvcml6YXRpb24nXSA/PyAnYW5vbnltb3VzJyksCiAgICAgICAgICAgICksCiAgICAgICAgICApOwogICAgICBhd2FpdCB0ZXN0ZXIucHVtcFdpZGdldChzdWJqZWN0KCkpOwogICAgICBleHBlY3QoZmluZC50ZXh0KCdhbm9ueW1vdXMnKSwgZmluZHNPbmVXaWRnZXQpOwogICAgICBhd2FpdCB0ZXN0ZXIucHVtcFdpZGdldChzdWJqZWN0KHByb3ZpZGVyOiB0b2tlbnMpKTsKICAgICAgZXhwZWN0KGZpbmQudGV4dCgnQmVhcmVyIGNhY2hlZCcpLCBmaW5kc09uZVdpZGdldCk7CiAgICAgIGF3YWl0IHRlc3Rlci5wdW1wV2lkZ2V0KHN1YmplY3QocHJvdmlkZXI6IHRva2VucywgdmFsaWRhdGU6IHRydWUpKTsKICAgICAgYXdhaXQgdGVzdGVyLnB1bXBBbmRTZXR0bGUoKTsKICAgICAgYXdhaXQgdGVzdGVyLnB1bXBXaWRnZXQoc3ViamVjdChwcm92aWRlcjogdG9rZW5zLCB2YWxpZGF0ZTogdHJ1ZSkpOwogICAgICBhd2FpdCB0ZXN0ZXIucHVtcEFuZFNldHRsZSgpOwogICAgICBleHBlY3QoZmluZC50ZXh0KCdCZWFyZXIgZnJlc2gnKSwgZmluZHNPbmVXaWRnZXQpOwogICAgICB2ZXJpZnkodG9rZW5zLmdldFZhbGlkVG9rZW4pLmNhbGxlZCgxKTsKICAgICAgd2hlbih0b2tlbnMuZ2V0Q3VycmVudFRva2VuKS50aGVuVGhyb3coU3RhdGVFcnJvcigndW5hdmFpbGFibGUnKSk7CiAgICAgIGF3YWl0IHRlc3Rlci5wdW1wV2lkZ2V0KHN1YmplY3QocHJvdmlkZXI6IHRva2VucykpOwogICAgICBleHBlY3QoZmluZC50ZXh0KCdhbm9ueW1vdXMnKSwgZmluZHNPbmVXaWRnZXQpOwogICAgICB3aGVuKHRva2Vucy5nZXRWYWxpZFRva2VuKS50aGVuVGhyb3coU3RhdGVFcnJvcigndW5hdmFpbGFibGUnKSk7CiAgICAgIGF3YWl0IHRlc3Rlci5wdW1wV2lkZ2V0KHN1YmplY3QocHJvdmlkZXI6IHRva2VucywgdmFsaWRhdGU6IHRydWUpKTsKICAgICAgYXdhaXQgdGVzdGVyLnB1bXBBbmRTZXR0bGUoKTsKICAgICAgZXhwZWN0KGZpbmQudGV4dCgnYW5vbnltb3VzJyksIGZpbmRzT25lV2lkZ2V0KTsKICAgICAgYXdhaXQgdGVzdGVyLnB1bXBXaWRnZXQoc3ViamVjdCh2YWxpZGF0ZTogdHJ1ZSkpOwogICAgICBhd2FpdCB0ZXN0ZXIucHVtcEFuZFNldHRsZSgpOwogICAgICBleHBlY3QoZmluZC50ZXh0KCdhbm9ueW1vdXMnKSwgZmluZHNPbmVXaWRnZXQpOwogICAgfSwKICApOwoKe3svbmV0d29ya319ICB0ZXN0V2lkZ2V0cygndG9hc3QgdmFyaWFudHMgcmVuZGVyIHRoZWlyIG1lc3NhZ2VzIGFuZCBkaXNtaXNzIGNsZWFubHknLCAoCiAgICB0ZXN0ZXIsCiAgKSBhc3luYyB7CiAgICBsYXRlIEJ1aWxkQ29udGV4dCBjb250ZXh0OwogICAgYXdhaXQgdGVzdGVyLnB1bXBXaWRnZXQoCiAgICAgIFRvYXN0aWZpY2F0aW9uV3JhcHBlcigKICAgICAgICBjaGlsZDogTWF0ZXJpYWxBcHAoCiAgICAgICAgICBob21lOiBTY2FmZm9sZCgKICAgICAgICAgICAgYm9keTogQnVpbGRlcigKICAgICAgICAgICAgICBidWlsZGVyOiAoY3R4KSB7CiAgICAgICAgICAgICAgICBjb250ZXh0ID0gY3R4OwogICAgICAgICAgICAgICAgcmV0dXJuIGNvbnN0IFNpemVkQm94KCk7CiAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgKSwKICAgICAgICAgICksCiAgICAgICAgKSwKICAgICAgKSwKICAgICk7CiAgICBmaW5hbCBjYWxsYmFja3MgPSBbCiAgICAgICgpID0+IFRvYXN0Lm5vdGlmaWNhdGlvbih0aXRsZTogJ05vdGljZScsIGJvZHk6ICdEZXRhaWxzJyksCiAgICAgICgpID0+IFRvYXN0LmVycm9yKGNvbnRleHQsIG1lc3NhZ2U6ICdOb3RpY2UnLCBkZXNjcmlwdGlvbjogJ0RldGFpbHMnKSwKICAgICAgKCkgPT4gVG9hc3Quc3VjY2Vzcyhjb250ZXh0LCBtZXNzYWdlOiAnTm90aWNlJywgZGVzY3JpcHRpb246ICdEZXRhaWxzJyksCiAgICAgICgpID0+IFRvYXN0Lndhcm5pbmcoY29udGV4dCwgbWVzc2FnZTogJ05vdGljZScsIGRlc2NyaXB0aW9uOiAnRGV0YWlscycpLAogICAgXTsKICAgIGZvciAoZmluYWwgc2hvdyBpbiBjYWxsYmFja3MpIHsKICAgICAgc2hvdygpOwogICAgICBhd2FpdCB0ZXN0ZXIucHVtcCgpOwogICAgICBhd2FpdCB0ZXN0ZXIucHVtcChjb25zdCBEdXJhdGlvbihtaWxsaXNlY29uZHM6IDUwMCkpOwogICAgICBhd2FpdCB0ZXN0ZXIucHVtcChjb25zdCBEdXJhdGlvbihtaWxsaXNlY29uZHM6IDUwMCkpOwogICAgICBleHBlY3QoCiAgICAgICAgZmluZC50ZXh0KCdOb3RpY2UnKSwKICAgICAgICBmaW5kc09uZVdpZGdldCwKICAgICAgICByZWFzb246ICd0b2FzdCB2YXJpYW50ICR7Y2FsbGJhY2tzLmluZGV4T2Yoc2hvdyl9JywKICAgICAgKTsKICAgICAgZXhwZWN0KGZpbmQudGV4dCgnRGV0YWlscycpLCBmaW5kc09uZVdpZGdldCk7CiAgICAgIHRvYXN0aWZpY2F0aW9uLmRpc21pc3NBbGwoZGVsYXlGb3JBbmltYXRpb246IGZhbHNlKTsKICAgICAgYXdhaXQgdGVzdGVyLnB1bXAoY29uc3QgRHVyYXRpb24oc2Vjb25kczogMSkpOwogICAgICBhd2FpdCB0ZXN0ZXIucHVtcEFuZFNldHRsZSgpOwogICAgfQogIH0pOwp9Cg==", + "type": "text" + }, { "path": "{{ name.snakeCase() }}/packages/di/lib/di.dart", "data": @@ -673,7 +768,7 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "path": "{{ name.snakeCase() }}/packages/di/lib/src/dependency_injection_imp.dart", "data": - "aW1wb3J0ICdkYXJ0OmFzeW5jJzsKCmltcG9ydCAnZGFydDpkZXZlbG9wZXInIGFzIGRldjsKCmltcG9ydCAncGFja2FnZTpkaS9zcmMvZGVwZW5kZW5jeV9pbmplY3Rpb24uZGFydCc7CmltcG9ydCAncGFja2FnZTpnZXRfaXQvZ2V0X2l0LmRhcnQnOwoKLy8vIEltcGxlbWVudGF0aW9uIG9mIERlcGVuZGVuY3lJbmplY3Rpb24gdXNpbmcgR2V0SXQKY2xhc3MgR2V0SXREZXBlbmRlbmN5SW5qZWN0aW9uIGltcGxlbWVudHMgRGVwZW5kZW5jeUluamVjdGlvbiB7CiAgZmluYWwgR2V0SXQgX2dldEl0OwogIGZpbmFsIE1hcDxUeXBlLCBEaXNwb3NlRnVuYz4gX2Rpc3Bvc2VGdW5jdGlvbnMgPSB7fTsKICBmaW5hbCBNYXA8VHlwZSwgT2JqZWN0PiBfcmVnaXN0ZXJlZEluc3RhbmNlcyA9IHt9OwoKICAvLy8gQ3JlYXRlcyBhIG5ldyBpbnN0YW5jZSB3aXRoIG9wdGlvbmFsIEdldEl0IGluc3RhbmNlCiAgLy8vIElmIG5vIGluc3RhbmNlIGlzIHByb3ZpZGVkLCB1c2VzIEdldEl0Lmluc3RhbmNlCiAgR2V0SXREZXBlbmRlbmN5SW5qZWN0aW9uKHtHZXRJdD8gZ2V0SXR9KSA6IF9nZXRJdCA9IGdldEl0ID8/IEdldEl0Lmluc3RhbmNlOwoKICBAb3ZlcnJpZGUKICBGdXR1cmU8dm9pZD4gaW5pdCgpIGFzeW5jIHsKICAgIC8vIEdldEl0IGRvZXNuJ3QgcmVxdWlyZSBleHBsaWNpdCBpbml0aWFsaXphdGlvbgogICAgLy8gYnV0IHdlIGNhbiB1c2UgdGhpcyB0byBzZXQgdXAgYW55IGdsb2JhbCBjb25maWd1cmF0aW9ucwogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPHZvaWQ+IGRpc3Bvc2UoKSBhc3luYyB7CiAgICAvLyBDYWxsIGRpc3Bvc2UgZnVuY3Rpb25zIGZvciBhbGwgcmVnaXN0ZXJlZCBpbnN0YW5jZXMKICAgIGZvciAoZmluYWwgZW50cnkgaW4gX2Rpc3Bvc2VGdW5jdGlvbnMuZW50cmllcykgewogICAgICBmaW5hbCB0eXBlID0gZW50cnkua2V5OwogICAgICBmaW5hbCBkaXNwb3NlRnVuYyA9IGVudHJ5LnZhbHVlOwogICAgICBmaW5hbCBpbnN0YW5jZSA9IF9yZWdpc3RlcmVkSW5zdGFuY2VzW3R5cGVdOwoKICAgICAgaWYgKGluc3RhbmNlICE9IG51bGwpIHsKICAgICAgICB0cnkgewogICAgICAgICAgYXdhaXQgZGlzcG9zZUZ1bmMoaW5zdGFuY2UpOwogICAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICAgIC8vIExvZyBlcnJvciBidXQgY29udGludWUgZGlzcG9zaW5nIG90aGVyIGluc3RhbmNlcwogICAgICAgICAgZGV2LmxvZygKICAgICAgICAgICAgJ0Vycm9yIGRpc3Bvc2luZyBpbnN0YW5jZSBvZiB0eXBlICR0eXBlJywKICAgICAgICAgICAgbmFtZTogJ2RpJywKICAgICAgICAgICAgZXJyb3I6IGUsCiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgfQogICAgfQoKICAgIC8vIENsZWFyIGRpc3Bvc2UgZnVuY3Rpb25zIGFuZCByZWdpc3RlcmVkIGluc3RhbmNlcyBtYXBzCiAgICBfZGlzcG9zZUZ1bmN0aW9ucy5jbGVhcigpOwogICAgX3JlZ2lzdGVyZWRJbnN0YW5jZXMuY2xlYXIoKTsKCiAgICAvLyBSZXNldCBHZXRJdCBpbnN0YW5jZQogICAgYXdhaXQgX2dldEl0LnJlc2V0KCk7CiAgfQoKICBAb3ZlcnJpZGUKICB2b2lkIHJlZ2lzdGVyPFQgZXh0ZW5kcyBPYmplY3Q+KAogICAgZmluYWwgVCBpbnN0YW5jZSwgewogICAgZmluYWwgRGlzcG9zZUZ1bmM/IGRpc3Bvc2UsCiAgfSkgewogICAgLy8gUmVnaXN0ZXIgdGhlIGluc3RhbmNlIGFzIGEgc2luZ2xldG9uCiAgICBfZ2V0SXQucmVnaXN0ZXJTaW5nbGV0b248VD4oaW5zdGFuY2UpOwoKICAgIC8vIFN0b3JlIHRoZSBpbnN0YW5jZSBhbmQgZGlzcG9zZSBmdW5jdGlvbiBpZiBwcm92aWRlZAogICAgX3JlZ2lzdGVyZWRJbnN0YW5jZXNbVF0gPSBpbnN0YW5jZTsKICAgIGlmIChkaXNwb3NlICE9IG51bGwpIHsKICAgICAgX2Rpc3Bvc2VGdW5jdGlvbnNbVF0gPSBkaXNwb3NlOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPHZvaWQ+IHVucmVnaXN0ZXI8VCBleHRlbmRzIE9iamVjdD4oZmluYWwgVD8gaW5zdGFuY2UpIGFzeW5jIHsKICAgIGlmICghX2dldEl0LmlzUmVnaXN0ZXJlZDxUPigpKSB7CiAgICAgIHJldHVybjsKICAgIH0KCiAgICAvLyBDYWxsIGRpc3Bvc2UgZnVuY3Rpb24gaWYgaXQgZXhpc3RzCiAgICBmaW5hbCBkaXNwb3NlRnVuYyA9IF9kaXNwb3NlRnVuY3Rpb25zW1RdOwogICAgaWYgKGRpc3Bvc2VGdW5jICE9IG51bGwpIHsKICAgICAgdHJ5IHsKICAgICAgICBmaW5hbCByZWdpc3RlcmVkSW5zdGFuY2UgPSBpbnN0YW5jZSA/PyBfcmVnaXN0ZXJlZEluc3RhbmNlc1tUXTsKICAgICAgICBpZiAocmVnaXN0ZXJlZEluc3RhbmNlICE9IG51bGwpIHsKICAgICAgICAgIGF3YWl0IGRpc3Bvc2VGdW5jKHJlZ2lzdGVyZWRJbnN0YW5jZSk7CiAgICAgICAgfQogICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgLy8gTG9nIGVycm9yIGJ1dCBjb250aW51ZSB3aXRoIHVucmVnaXN0cmF0aW9uCiAgICAgICAgZGV2LmxvZygnRXJyb3IgZGlzcG9zaW5nIGluc3RhbmNlIG9mIHR5cGUgJFQnLCBuYW1lOiAnZGknLCBlcnJvcjogZSk7CiAgICAgIH0KICAgICAgX2Rpc3Bvc2VGdW5jdGlvbnMucmVtb3ZlKFQpOwogICAgfQoKICAgIC8vIFJlbW92ZSBmcm9tIG91ciB0cmFja2luZwogICAgX3JlZ2lzdGVyZWRJbnN0YW5jZXMucmVtb3ZlKFQpOwoKICAgIC8vIFVucmVnaXN0ZXIgZnJvbSBHZXRJdAogICAgYXdhaXQgX2dldEl0LnVucmVnaXN0ZXI8VD4oaW5zdGFuY2U6IGluc3RhbmNlKTsKICB9CgogIEBvdmVycmlkZQogIFQgZ2V0PFQgZXh0ZW5kcyBPYmplY3Q+KCkgewogICAgcmV0dXJuIF9nZXRJdC5nZXQ8VD4oKTsKICB9CgogIEBvdmVycmlkZQogIGJvb2wgaGFzPFQgZXh0ZW5kcyBPYmplY3Q+KCkgewogICAgcmV0dXJuIF9nZXRJdC5pc1JlZ2lzdGVyZWQ8VD4oKTsKICB9CgogIEBvdmVycmlkZQogIEZ1dHVyZTx2b2lkPiByZXNldCgpIGFzeW5jIHsKICAgIGF3YWl0IGRpc3Bvc2UoKTsKICAgIGF3YWl0IGluaXQoKTsKICB9CgogIC8vLyBHZXQgdGhlIHVuZGVybHlpbmcgR2V0SXQgaW5zdGFuY2UgKGZvciBhZHZhbmNlZCB1c2FnZSkKICBHZXRJdCBnZXQgZ2V0SXQgPT4gX2dldEl0Owp9Cg==", + "aW1wb3J0ICdkYXJ0OmFzeW5jJzsKCmltcG9ydCAnZGFydDpkZXZlbG9wZXInIGFzIGRldjsKCmltcG9ydCAncGFja2FnZTpkaS9zcmMvZGVwZW5kZW5jeV9pbmplY3Rpb24uZGFydCc7CmltcG9ydCAncGFja2FnZTpnZXRfaXQvZ2V0X2l0LmRhcnQnOwoKLy8vIEltcGxlbWVudGF0aW9uIG9mIERlcGVuZGVuY3lJbmplY3Rpb24gdXNpbmcgR2V0SXQKY2xhc3MgR2V0SXREZXBlbmRlbmN5SW5qZWN0aW9uIGltcGxlbWVudHMgRGVwZW5kZW5jeUluamVjdGlvbiB7CiAgZmluYWwgR2V0SXQgX2dldEl0OwogIGZpbmFsIE1hcDxUeXBlLCBEaXNwb3NlRnVuYz4gX2Rpc3Bvc2VGdW5jdGlvbnMgPSB7fTsKICBmaW5hbCBNYXA8VHlwZSwgT2JqZWN0PiBfcmVnaXN0ZXJlZEluc3RhbmNlcyA9IHt9OwoKICAvLy8gQ3JlYXRlcyBhIG5ldyBpbnN0YW5jZSB3aXRoIG9wdGlvbmFsIEdldEl0IGluc3RhbmNlCiAgLy8vIElmIG5vIGluc3RhbmNlIGlzIHByb3ZpZGVkLCB1c2VzIEdldEl0Lmluc3RhbmNlCiAgR2V0SXREZXBlbmRlbmN5SW5qZWN0aW9uKHtHZXRJdD8gZ2V0SXR9KSA6IF9nZXRJdCA9IGdldEl0ID8/IEdldEl0Lmluc3RhbmNlOwoKICBAb3ZlcnJpZGUKICBGdXR1cmU8dm9pZD4gaW5pdCgpIGFzeW5jIHsKICAgIC8vIEdldEl0IGRvZXNuJ3QgcmVxdWlyZSBleHBsaWNpdCBpbml0aWFsaXphdGlvbgogICAgLy8gYnV0IHdlIGNhbiB1c2UgdGhpcyB0byBzZXQgdXAgYW55IGdsb2JhbCBjb25maWd1cmF0aW9ucwogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPHZvaWQ+IGRpc3Bvc2UoKSBhc3luYyB7CiAgICAvLyBDYWxsIGRpc3Bvc2UgZnVuY3Rpb25zIGZvciBhbGwgcmVnaXN0ZXJlZCBpbnN0YW5jZXMKICAgIC8vIERlcGVuZGVudHMgYXJlIHJlZ2lzdGVyZWQgYWZ0ZXIgZGVwZW5kZW5jaWVzOyB0ZWFyIHRoZW0gZG93biBmaXJzdC4KICAgIGZvciAoZmluYWwgZW50cnkgaW4gX2Rpc3Bvc2VGdW5jdGlvbnMuZW50cmllcy50b0xpc3QoKS5yZXZlcnNlZCkgewogICAgICBmaW5hbCB0eXBlID0gZW50cnkua2V5OwogICAgICBmaW5hbCBkaXNwb3NlRnVuYyA9IGVudHJ5LnZhbHVlOwogICAgICBmaW5hbCBpbnN0YW5jZSA9IF9yZWdpc3RlcmVkSW5zdGFuY2VzW3R5cGVdOwoKICAgICAgaWYgKGluc3RhbmNlICE9IG51bGwpIHsKICAgICAgICB0cnkgewogICAgICAgICAgYXdhaXQgZGlzcG9zZUZ1bmMoaW5zdGFuY2UpOwogICAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICAgIC8vIExvZyBlcnJvciBidXQgY29udGludWUgZGlzcG9zaW5nIG90aGVyIGluc3RhbmNlcwogICAgICAgICAgZGV2LmxvZygKICAgICAgICAgICAgJ0Vycm9yIGRpc3Bvc2luZyBpbnN0YW5jZSBvZiB0eXBlICR0eXBlJywKICAgICAgICAgICAgbmFtZTogJ2RpJywKICAgICAgICAgICAgZXJyb3I6IGUsCiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgfQogICAgfQoKICAgIC8vIENsZWFyIGRpc3Bvc2UgZnVuY3Rpb25zIGFuZCByZWdpc3RlcmVkIGluc3RhbmNlcyBtYXBzCiAgICBfZGlzcG9zZUZ1bmN0aW9ucy5jbGVhcigpOwogICAgX3JlZ2lzdGVyZWRJbnN0YW5jZXMuY2xlYXIoKTsKCiAgICAvLyBSZXNldCBHZXRJdCBpbnN0YW5jZQogICAgYXdhaXQgX2dldEl0LnJlc2V0KCk7CiAgfQoKICBAb3ZlcnJpZGUKICB2b2lkIHJlZ2lzdGVyPFQgZXh0ZW5kcyBPYmplY3Q+KAogICAgZmluYWwgVCBpbnN0YW5jZSwgewogICAgZmluYWwgRGlzcG9zZUZ1bmM/IGRpc3Bvc2UsCiAgfSkgewogICAgLy8gUmVnaXN0ZXIgdGhlIGluc3RhbmNlIGFzIGEgc2luZ2xldG9uCiAgICBfZ2V0SXQucmVnaXN0ZXJTaW5nbGV0b248VD4oaW5zdGFuY2UpOwoKICAgIC8vIFN0b3JlIHRoZSBpbnN0YW5jZSBhbmQgZGlzcG9zZSBmdW5jdGlvbiBpZiBwcm92aWRlZAogICAgX3JlZ2lzdGVyZWRJbnN0YW5jZXNbVF0gPSBpbnN0YW5jZTsKICAgIGlmIChkaXNwb3NlICE9IG51bGwpIHsKICAgICAgX2Rpc3Bvc2VGdW5jdGlvbnNbVF0gPSBkaXNwb3NlOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPHZvaWQ+IHVucmVnaXN0ZXI8VCBleHRlbmRzIE9iamVjdD4oZmluYWwgVD8gaW5zdGFuY2UpIGFzeW5jIHsKICAgIGlmICghX2dldEl0LmlzUmVnaXN0ZXJlZDxUPigpKSB7CiAgICAgIHJldHVybjsKICAgIH0KICAgIGlmIChpbnN0YW5jZSAhPSBudWxsICYmICFpZGVudGljYWwoaW5zdGFuY2UsIF9nZXRJdC5nZXQ8VD4oKSkpIHsKICAgICAgdGhyb3cgQXJndW1lbnRFcnJvci52YWx1ZSgKICAgICAgICBpbnN0YW5jZSwKICAgICAgICAnaW5zdGFuY2UnLAogICAgICAgICdEb2VzIG5vdCBtYXRjaCB0aGUgcmVnaXN0ZXJlZCBpbnN0YW5jZSBvZiAkVCcsCiAgICAgICk7CiAgICB9CgogICAgLy8gQ2FsbCBkaXNwb3NlIGZ1bmN0aW9uIGlmIGl0IGV4aXN0cwogICAgZmluYWwgZGlzcG9zZUZ1bmMgPSBfZGlzcG9zZUZ1bmN0aW9uc1tUXTsKICAgIGlmIChkaXNwb3NlRnVuYyAhPSBudWxsKSB7CiAgICAgIHRyeSB7CiAgICAgICAgZmluYWwgcmVnaXN0ZXJlZEluc3RhbmNlID0gaW5zdGFuY2UgPz8gX3JlZ2lzdGVyZWRJbnN0YW5jZXNbVF07CiAgICAgICAgaWYgKHJlZ2lzdGVyZWRJbnN0YW5jZSAhPSBudWxsKSB7CiAgICAgICAgICBhd2FpdCBkaXNwb3NlRnVuYyhyZWdpc3RlcmVkSW5zdGFuY2UpOwogICAgICAgIH0KICAgICAgfSBjYXRjaCAoZSkgewogICAgICAgIC8vIExvZyBlcnJvciBidXQgY29udGludWUgd2l0aCB1bnJlZ2lzdHJhdGlvbgogICAgICAgIGRldi5sb2coJ0Vycm9yIGRpc3Bvc2luZyBpbnN0YW5jZSBvZiB0eXBlICRUJywgbmFtZTogJ2RpJywgZXJyb3I6IGUpOwogICAgICB9CiAgICAgIF9kaXNwb3NlRnVuY3Rpb25zLnJlbW92ZShUKTsKICAgIH0KCiAgICAvLyBSZW1vdmUgZnJvbSBvdXIgdHJhY2tpbmcKICAgIF9yZWdpc3RlcmVkSW5zdGFuY2VzLnJlbW92ZShUKTsKCiAgICAvLyBVbnJlZ2lzdGVyIGZyb20gR2V0SXQKICAgIGF3YWl0IF9nZXRJdC51bnJlZ2lzdGVyPFQ+KGluc3RhbmNlOiBpbnN0YW5jZSk7CiAgfQoKICBAb3ZlcnJpZGUKICBUIGdldDxUIGV4dGVuZHMgT2JqZWN0PigpIHsKICAgIHJldHVybiBfZ2V0SXQuZ2V0PFQ+KCk7CiAgfQoKICBAb3ZlcnJpZGUKICBib29sIGhhczxUIGV4dGVuZHMgT2JqZWN0PigpIHsKICAgIHJldHVybiBfZ2V0SXQuaXNSZWdpc3RlcmVkPFQ+KCk7CiAgfQoKICBAb3ZlcnJpZGUKICBGdXR1cmU8dm9pZD4gcmVzZXQoKSBhc3luYyB7CiAgICBhd2FpdCBkaXNwb3NlKCk7CiAgICBhd2FpdCBpbml0KCk7CiAgfQoKICAvLy8gR2V0IHRoZSB1bmRlcmx5aW5nIEdldEl0IGluc3RhbmNlIChmb3IgYWR2YW5jZWQgdXNhZ2UpCiAgR2V0SXQgZ2V0IGdldEl0ID0+IF9nZXRJdDsKfQo=", "type": "text" }, { @@ -694,6 +789,12 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "aW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlcl90ZXN0L2ZsdXR0ZXJfdGVzdC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmdldF9pdC9nZXRfaXQuZGFydCc7CgovLyBUZXN0IGNsYXNzZXMgZm9yIGRlcGVuZGVuY3kgaW5qZWN0aW9uCmNsYXNzIFRlc3RTZXJ2aWNlIHsKICBmaW5hbCBTdHJpbmcgbmFtZTsKICBib29sIGlzRGlzcG9zZWQgPSBmYWxzZTsKCiAgVGVzdFNlcnZpY2UodGhpcy5uYW1lKTsKCiAgdm9pZCBkaXNwb3NlKCkgewogICAgaXNEaXNwb3NlZCA9IHRydWU7CiAgfQp9CgpjbGFzcyBUZXN0UmVwb3NpdG9yeSB7CiAgZmluYWwgVGVzdFNlcnZpY2Ugc2VydmljZTsKICBib29sIGlzRGlzcG9zZWQgPSBmYWxzZTsKCiAgVGVzdFJlcG9zaXRvcnkodGhpcy5zZXJ2aWNlKTsKCiAgdm9pZCBkaXNwb3NlKCkgewogICAgaXNEaXNwb3NlZCA9IHRydWU7CiAgfQp9Cgp2b2lkIG1haW4oKSB7CiAgZ3JvdXAoJ0dldEl0RGVwZW5kZW5jeUluamVjdGlvbicsICgpIHsKICAgIGxhdGUgR2V0SXREZXBlbmRlbmN5SW5qZWN0aW9uIGRpOwogICAgbGF0ZSBHZXRJdCB0ZXN0R2V0SXQ7CgogICAgc2V0VXAoKCkgewogICAgICAvLyBDcmVhdGUgYSBzZXBhcmF0ZSBHZXRJdCBpbnN0YW5jZSBmb3IgdGVzdGluZwogICAgICB0ZXN0R2V0SXQgPSBHZXRJdC5hc05ld0luc3RhbmNlKCk7CiAgICAgIGRpID0gR2V0SXREZXBlbmRlbmN5SW5qZWN0aW9uKGdldEl0OiB0ZXN0R2V0SXQpOwogICAgfSk7CgogICAgdGVhckRvd24oKCkgYXN5bmMgewogICAgICBhd2FpdCBkaS5kaXNwb3NlKCk7CiAgICB9KTsKCiAgICBncm91cCgnUmVnaXN0cmF0aW9uJywgKCkgewogICAgICBzZXRVcCgoKSBhc3luYyB7CiAgICAgICAgYXdhaXQgZGkuaW5pdCgpOwogICAgICB9KTsKCiAgICAgIHRlc3QoJ3Nob3VsZCByZWdpc3RlciBhbmQgcmV0cmlldmUgaW5zdGFuY2VzJywgKCkgYXN5bmMgewogICAgICAgIGZpbmFsIHNlcnZpY2UgPSBUZXN0U2VydmljZSgndGVzdCcpOwoKICAgICAgICBkaS5yZWdpc3RlcjxUZXN0U2VydmljZT4oc2VydmljZSk7CgogICAgICAgIGV4cGVjdChkaS5oYXM8VGVzdFNlcnZpY2U+KCksIHRydWUpOwogICAgICAgIGZpbmFsIHJldHJpZXZlZCA9IGRpLmdldDxUZXN0U2VydmljZT4oKTsKICAgICAgICBleHBlY3QocmV0cmlldmVkLCBzYW1lKHNlcnZpY2UpKTsKICAgICAgICBleHBlY3QocmV0cmlldmVkLm5hbWUsICd0ZXN0Jyk7CiAgICAgIH0pOwoKICAgICAgdGVzdCgnc2hvdWxkIHJlZ2lzdGVyIHdpdGggZGlzcG9zZSBmdW5jdGlvbicsICgpIGFzeW5jIHsKICAgICAgICBmaW5hbCBzZXJ2aWNlID0gVGVzdFNlcnZpY2UoJ3Rlc3QnKTsKICAgICAgICBib29sIGRpc3Bvc2VDYWxsZWQgPSBmYWxzZTsKCiAgICAgICAgZGkucmVnaXN0ZXI8VGVzdFNlcnZpY2U+KAogICAgICAgICAgc2VydmljZSwKICAgICAgICAgIGRpc3Bvc2U6IChpbnN0YW5jZSkgewogICAgICAgICAgICBkaXNwb3NlQ2FsbGVkID0gdHJ1ZTsKICAgICAgICAgICAgaW5zdGFuY2UuZGlzcG9zZSgpOwogICAgICAgICAgfSwKICAgICAgICApOwoKICAgICAgICBleHBlY3QoZGkuaGFzPFRlc3RTZXJ2aWNlPigpLCB0cnVlKTsKICAgICAgICBhd2FpdCBkaS51bnJlZ2lzdGVyPFRlc3RTZXJ2aWNlPihudWxsKTsKCiAgICAgICAgZXhwZWN0KGRpc3Bvc2VDYWxsZWQsIHRydWUpOwogICAgICAgIGV4cGVjdChzZXJ2aWNlLmlzRGlzcG9zZWQsIHRydWUpOwogICAgICAgIGV4cGVjdChkaS5oYXM8VGVzdFNlcnZpY2U+KCksIGZhbHNlKTsKICAgICAgfSk7CiAgICB9KTsKCiAgICBncm91cCgnRXJyb3IgaGFuZGxpbmcnLCAoKSB7CiAgICAgIHRlc3QoJ3JlZ2lzdGVyaW5nIGJlZm9yZSBpbml0KCkgaXMgYWxsb3dlZCcsICgpIHsKICAgICAgICAvLyBpbml0KCkgZXhpc3RzIGZvciBzeW1tZXRyeSB3aXRoIGRpc3Bvc2UoKTsgR2V0SXQgbmVlZHMgbm8gc2V0dXAsIHNvCiAgICAgICAgLy8gcmVnaXN0cmF0aW9uIHdvcmtzIHN0cmFpZ2h0IGF3YXkuCiAgICAgICAgZmluYWwgc2VydmljZSA9IFRlc3RTZXJ2aWNlKCd0ZXN0Jyk7CgogICAgICAgIGRpLnJlZ2lzdGVyPFRlc3RTZXJ2aWNlPihzZXJ2aWNlKTsKCiAgICAgICAgZXhwZWN0KGRpLmdldDxUZXN0U2VydmljZT4oKSwgc2FtZShzZXJ2aWNlKSk7CiAgICAgIH0pOwoKICAgICAgdGVzdCgnc2hvdWxkIHRocm93IHdoZW4gZ2V0dGluZyBiZWZvcmUgaW5pdGlhbGl6YXRpb24nLCAoKSB7CiAgICAgICAgZXhwZWN0KCgpID0+IGRpLmdldDxUZXN0U2VydmljZT4oKSwgdGhyb3dzQShpc0E8U3RhdGVFcnJvcj4oKSkpOwogICAgICB9KTsKCiAgICAgIHRlc3QoJ3Nob3VsZCByZXR1cm4gZmFsc2Ugd2hlbiBub3QgaW5pdGlhbGl6ZWQnLCAoKSB7CiAgICAgICAgZXhwZWN0KGRpLmhhczxUZXN0U2VydmljZT4oKSwgZmFsc2UpOwogICAgICB9KTsKICAgIH0pOwoKICAgIGdyb3VwKCdSZXRyaWV2YWwnLCAoKSB7CiAgICAgIHNldFVwKCgpIGFzeW5jIHsKICAgICAgICBhd2FpdCBkaS5pbml0KCk7CiAgICAgIH0pOwoKICAgICAgdGVzdCgnc2hvdWxkIGdldCByZWdpc3RlcmVkIGluc3RhbmNlcycsICgpIHsKICAgICAgICBmaW5hbCBzZXJ2aWNlID0gVGVzdFNlcnZpY2UoJ3Rlc3QnKTsKICAgICAgICBkaS5yZWdpc3RlcjxUZXN0U2VydmljZT4oc2VydmljZSk7CgogICAgICAgIGZpbmFsIHJldHJpZXZlZCA9IGRpLmdldDxUZXN0U2VydmljZT4oKTsKICAgICAgICBleHBlY3QocmV0cmlldmVkLCBzYW1lKHNlcnZpY2UpKTsKICAgICAgfSk7CgogICAgICB0ZXN0KCdzaG91bGQgdGhyb3cgd2hlbiBnZXR0aW5nIHVucmVnaXN0ZXJlZCB0eXBlJywgKCkgewogICAgICAgIGV4cGVjdCgoKSA9PiBkaS5nZXQ8VGVzdFNlcnZpY2U+KCksIHRocm93c0EoaXNBPE9iamVjdD4oKSkpOwogICAgICB9KTsKICAgIH0pOwoKICAgIGdyb3VwKCdIYXMvQ29udGFpbnMnLCAoKSB7CiAgICAgIHNldFVwKCgpIGFzeW5jIHsKICAgICAgICBhd2FpdCBkaS5pbml0KCk7CiAgICAgIH0pOwoKICAgICAgdGVzdCgnc2hvdWxkIHJldHVybiB0cnVlIGZvciByZWdpc3RlcmVkIHR5cGVzJywgKCkgewogICAgICAgIGZpbmFsIHNlcnZpY2UgPSBUZXN0U2VydmljZSgndGVzdCcpOwogICAgICAgIGRpLnJlZ2lzdGVyPFRlc3RTZXJ2aWNlPihzZXJ2aWNlKTsKCiAgICAgICAgZXhwZWN0KGRpLmhhczxUZXN0U2VydmljZT4oKSwgdHJ1ZSk7CiAgICAgIH0pOwoKICAgICAgdGVzdCgnc2hvdWxkIHJldHVybiBmYWxzZSBmb3IgdW5yZWdpc3RlcmVkIHR5cGVzJywgKCkgewogICAgICAgIGV4cGVjdChkaS5oYXM8VGVzdFNlcnZpY2U+KCksIGZhbHNlKTsKICAgICAgfSk7CiAgICB9KTsKCiAgICBncm91cCgnVW5yZWdpc3RyYXRpb24nLCAoKSB7CiAgICAgIHNldFVwKCgpIGFzeW5jIHsKICAgICAgICBhd2FpdCBkaS5pbml0KCk7CiAgICAgIH0pOwoKICAgICAgdGVzdCgnc2hvdWxkIHVucmVnaXN0ZXIgaW5zdGFuY2VzJywgKCkgYXN5bmMgewogICAgICAgIGZpbmFsIHNlcnZpY2UgPSBUZXN0U2VydmljZSgndGVzdCcpOwogICAgICAgIGRpLnJlZ2lzdGVyPFRlc3RTZXJ2aWNlPihzZXJ2aWNlKTsKCiAgICAgICAgZXhwZWN0KGRpLmhhczxUZXN0U2VydmljZT4oKSwgdHJ1ZSk7CiAgICAgICAgYXdhaXQgZGkudW5yZWdpc3RlcjxUZXN0U2VydmljZT4obnVsbCk7CiAgICAgICAgZXhwZWN0KGRpLmhhczxUZXN0U2VydmljZT4oKSwgZmFsc2UpOwogICAgICB9KTsKCiAgICAgIHRlc3QoJ3Nob3VsZCBjYWxsIGRpc3Bvc2UgZnVuY3Rpb24gd2hlbiB1bnJlZ2lzdGVyaW5nJywgKCkgYXN5bmMgewogICAgICAgIGZpbmFsIHNlcnZpY2UgPSBUZXN0U2VydmljZSgndGVzdCcpOwogICAgICAgIGJvb2wgZGlzcG9zZUNhbGxlZCA9IGZhbHNlOwoKICAgICAgICBkaS5yZWdpc3RlcjxUZXN0U2VydmljZT4oCiAgICAgICAgICBzZXJ2aWNlLAogICAgICAgICAgZGlzcG9zZTogKGluc3RhbmNlKSB7CiAgICAgICAgICAgIGRpc3Bvc2VDYWxsZWQgPSB0cnVlOwogICAgICAgICAgICBpbnN0YW5jZS5kaXNwb3NlKCk7CiAgICAgICAgICB9LAogICAgICAgICk7CgogICAgICAgIGF3YWl0IGRpLnVucmVnaXN0ZXI8VGVzdFNlcnZpY2U+KG51bGwpOwoKICAgICAgICBleHBlY3QoZGlzcG9zZUNhbGxlZCwgdHJ1ZSk7CiAgICAgICAgZXhwZWN0KHNlcnZpY2UuaXNEaXNwb3NlZCwgdHJ1ZSk7CiAgICAgIH0pOwoKICAgICAgdGVzdCgKICAgICAgICAnc2hvdWxkIGhhbmRsZSB1bnJlZ2lzdGVyaW5nIG5vbi1leGlzdGVudCB0eXBlcyBncmFjZWZ1bGx5JywKICAgICAgICAoKSBhc3luYyB7CiAgICAgICAgICAvLyBTaG91bGQgbm90IHRocm93CiAgICAgICAgICBhd2FpdCBkaS51bnJlZ2lzdGVyPFRlc3RTZXJ2aWNlPihudWxsKTsKICAgICAgICAgIGV4cGVjdChkaS5oYXM8VGVzdFNlcnZpY2U+KCksIGZhbHNlKTsKICAgICAgICB9LAogICAgICApOwoKICAgICAgdGVzdCgnc2hvdWxkIGhhbmRsZSB1bnJlZ2lzdGVyaW5nIHdoZW4gbm90IGluaXRpYWxpemVkJywgKCkgYXN5bmMgewogICAgICAgIC8vIFNob3VsZCBub3QgdGhyb3cKICAgICAgICBhd2FpdCBkaS51bnJlZ2lzdGVyPFRlc3RTZXJ2aWNlPihudWxsKTsKICAgICAgfSk7CiAgICB9KTsKCiAgICBncm91cCgnRGlzcG9zYWwnLCAoKSB7CiAgICAgIHNldFVwKCgpIGFzeW5jIHsKICAgICAgICBhd2FpdCBkaS5pbml0KCk7CiAgICAgIH0pOwoKICAgICAgdGVzdCgnc2hvdWxkIGRpc3Bvc2UgYWxsIHJlZ2lzdGVyZWQgaW5zdGFuY2VzJywgKCkgYXN5bmMgewogICAgICAgIGZpbmFsIHNlcnZpY2UgPSBUZXN0U2VydmljZSgnc2VydmljZScpOwogICAgICAgIGZpbmFsIHJlcG9zaXRvcnkgPSBUZXN0UmVwb3NpdG9yeShzZXJ2aWNlKTsKCiAgICAgICAgZGkucmVnaXN0ZXI8VGVzdFNlcnZpY2U+KAogICAgICAgICAgc2VydmljZSwKICAgICAgICAgIGRpc3Bvc2U6IChpbnN0YW5jZSkgPT4gaW5zdGFuY2UuZGlzcG9zZSgpLAogICAgICAgICk7CgogICAgICAgIGRpLnJlZ2lzdGVyPFRlc3RSZXBvc2l0b3J5PigKICAgICAgICAgIHJlcG9zaXRvcnksCiAgICAgICAgICBkaXNwb3NlOiAoaW5zdGFuY2UpID0+IGluc3RhbmNlLmRpc3Bvc2UoKSwKICAgICAgICApOwoKICAgICAgICBhd2FpdCBkaS5kaXNwb3NlKCk7CgogICAgICAgIGV4cGVjdChzZXJ2aWNlLmlzRGlzcG9zZWQsIHRydWUpOwogICAgICAgIGV4cGVjdChyZXBvc2l0b3J5LmlzRGlzcG9zZWQsIHRydWUpOwogICAgICAgIGV4cGVjdChkaS5oYXM8VGVzdFNlcnZpY2U+KCksIGZhbHNlKTsKICAgICAgICBleHBlY3QoZGkuaGFzPFRlc3RSZXBvc2l0b3J5PigpLCBmYWxzZSk7CiAgICAgIH0pOwogICAgfSk7CgogICAgZ3JvdXAoJ1Jlc2V0JywgKCkgewogICAgICB0ZXN0KCdzaG91bGQgcmVzZXQgYW5kIHJlaW5pdGlhbGl6ZScsICgpIGFzeW5jIHsKICAgICAgICBhd2FpdCBkaS5pbml0KCk7CgogICAgICAgIGZpbmFsIHNlcnZpY2UgPSBUZXN0U2VydmljZSgndGVzdCcpOwogICAgICAgIGRpLnJlZ2lzdGVyPFRlc3RTZXJ2aWNlPigKICAgICAgICAgIHNlcnZpY2UsCiAgICAgICAgICBkaXNwb3NlOiAoaW5zdGFuY2UpID0+IGluc3RhbmNlLmRpc3Bvc2UoKSwKICAgICAgICApOwoKICAgICAgICBleHBlY3QoZGkuaGFzPFRlc3RTZXJ2aWNlPigpLCB0cnVlKTsKCiAgICAgICAgYXdhaXQgZGkucmVzZXQoKTsKCiAgICAgICAgZXhwZWN0KGRpLmhhczxUZXN0U2VydmljZT4oKSwgZmFsc2UpOwogICAgICAgIGV4cGVjdChzZXJ2aWNlLmlzRGlzcG9zZWQsIHRydWUpOwogICAgICB9KTsKICAgIH0pOwoKICAgIGdyb3VwKCdDb21wbGV4IHNjZW5hcmlvcycsICgpIHsKICAgICAgc2V0VXAoKCkgYXN5bmMgewogICAgICAgIGF3YWl0IGRpLmluaXQoKTsKICAgICAgfSk7CgogICAgICB0ZXN0KCdzaG91bGQgaGFuZGxlIG11bHRpcGxlIGRlcGVuZGVuY2llcycsICgpIHsKICAgICAgICBmaW5hbCBzZXJ2aWNlID0gVGVzdFNlcnZpY2UoJ3NlcnZpY2UnKTsKICAgICAgICBmaW5hbCByZXBvc2l0b3J5ID0gVGVzdFJlcG9zaXRvcnkoc2VydmljZSk7CgogICAgICAgIGRpLnJlZ2lzdGVyPFRlc3RTZXJ2aWNlPihzZXJ2aWNlKTsKICAgICAgICBkaS5yZWdpc3RlcjxUZXN0UmVwb3NpdG9yeT4ocmVwb3NpdG9yeSk7CgogICAgICAgIGV4cGVjdChkaS5oYXM8VGVzdFNlcnZpY2U+KCksIHRydWUpOwogICAgICAgIGV4cGVjdChkaS5oYXM8VGVzdFJlcG9zaXRvcnk+KCksIHRydWUpOwoKICAgICAgICBmaW5hbCByZXRyaWV2ZWRTZXJ2aWNlID0gZGkuZ2V0PFRlc3RTZXJ2aWNlPigpOwogICAgICAgIGZpbmFsIHJldHJpZXZlZFJlcG9zaXRvcnkgPSBkaS5nZXQ8VGVzdFJlcG9zaXRvcnk+KCk7CgogICAgICAgIGV4cGVjdChyZXRyaWV2ZWRTZXJ2aWNlLCBzYW1lKHNlcnZpY2UpKTsKICAgICAgICBleHBlY3QocmV0cmlldmVkUmVwb3NpdG9yeSwgc2FtZShyZXBvc2l0b3J5KSk7CiAgICAgICAgZXhwZWN0KHJldHJpZXZlZFJlcG9zaXRvcnkuc2VydmljZSwgc2FtZShzZXJ2aWNlKSk7CiAgICAgIH0pOwogICAgfSk7CiAgfSk7Cn0K", "type": "text" }, + { + "path": "{{ name.snakeCase() }}/packages/di/test/lifecycle_test.dart", + "data": + "aW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlcl90ZXN0L2ZsdXR0ZXJfdGVzdC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmdldF9pdC9nZXRfaXQuZGFydCc7CgpjbGFzcyBfU2VydmljZSB7fQoKdm9pZCBtYWluKCkgewogIGxhdGUgR2V0SXREZXBlbmRlbmN5SW5qZWN0aW9uIGNvbnRhaW5lcjsKICBzZXRVcCgKICAgICgpID0+IGNvbnRhaW5lciA9IEdldEl0RGVwZW5kZW5jeUluamVjdGlvbihnZXRJdDogR2V0SXQuYXNOZXdJbnN0YW5jZSgpKSwKICApOwogIHRlYXJEb3duKCgpID0+IGNvbnRhaW5lci5kaXNwb3NlKCkpOwoKICB0ZXN0KAogICAgJ2Rpc3Bvc2VzIGRlcGVuZGVudHMgZmlyc3QsIGF3YWl0cyBjbGVhbnVwIGFuZCBjb250aW51ZXMgYWZ0ZXIgZmFpbHVyZXMnLAogICAgKCkgYXN5bmMgewogICAgICBmaW5hbCBvcmRlciA9IDxTdHJpbmc+W107CiAgICAgIGNvbnRhaW5lci5yZWdpc3RlcjxTdHJpbmc+KAogICAgICAgICdzZXJ2aWNlJywKICAgICAgICBkaXNwb3NlOiAoXykgYXN5bmMgewogICAgICAgICAgb3JkZXIuYWRkKCdzZXJ2aWNlJyk7CiAgICAgICAgfSwKICAgICAgKTsKICAgICAgY29udGFpbmVyLnJlZ2lzdGVyPGludD4oCiAgICAgICAgMSwKICAgICAgICBkaXNwb3NlOiAoXykgYXN5bmMgewogICAgICAgICAgb3JkZXIuYWRkKCdyZXBvc2l0b3J5Jyk7CiAgICAgICAgICB0aHJvdyBTdGF0ZUVycm9yKCdjbGVhbnVwJyk7CiAgICAgICAgfSwKICAgICAgKTsKICAgICAgY29udGFpbmVyLnJlZ2lzdGVyPGJvb2w+KAogICAgICAgIHRydWUsCiAgICAgICAgZGlzcG9zZTogKF8pIGFzeW5jIHsKICAgICAgICAgIG9yZGVyLmFkZCgnY29udHJvbGxlcicpOwogICAgICAgIH0sCiAgICAgICk7CiAgICAgIGF3YWl0IGNvbnRhaW5lci5yZXNldCgpOwogICAgICBleHBlY3Qob3JkZXIsIFsnY29udHJvbGxlcicsICdyZXBvc2l0b3J5JywgJ3NlcnZpY2UnXSk7CiAgICAgIGV4cGVjdChjb250YWluZXIuaGFzPGludD4oKSwgaXNGYWxzZSk7CiAgICAgIGF3YWl0IGNvbnRhaW5lci5yZXNldCgpOwogICAgICBleHBlY3Qob3JkZXIsIGhhc0xlbmd0aCgzKSk7CiAgICB9LAogICk7CgogIHRlc3QoJ3VucmVnaXN0ZXIgY2xlYW51cCBmYWlsdXJlIHN0aWxsIHJlbW92ZXMgdGhlIHJlZ2lzdHJhdGlvbicsICgpIGFzeW5jIHsKICAgIGNvbnRhaW5lci5yZWdpc3RlcjxTdHJpbmc+KAogICAgICAndmFsdWUnLAogICAgICBkaXNwb3NlOiAoXykgPT4gdGhyb3cgU3RhdGVFcnJvcignY2xlYW51cCcpLAogICAgKTsKICAgIGF3YWl0IGNvbnRhaW5lci51bnJlZ2lzdGVyPFN0cmluZz4obnVsbCk7CiAgICBleHBlY3QoY29udGFpbmVyLmhhczxTdHJpbmc+KCksIGlzRmFsc2UpOwogIH0pOwoKICB0ZXN0KCd3cm9uZy1pbnN0YW5jZSB1bnJlZ2lzdHJhdGlvbiBoYXMgbm8gZGlzcG9zYWwgc2lkZSBlZmZlY3RzJywgKCkgYXN5bmMgewogICAgZmluYWwgZmlyc3QgPSBfU2VydmljZSgpOwogICAgdmFyIGRpc3Bvc2VkID0gZmFsc2U7CiAgICBjb250YWluZXIucmVnaXN0ZXI8X1NlcnZpY2U+KAogICAgICBmaXJzdCwKICAgICAgZGlzcG9zZTogKF8pIHsKICAgICAgICBkaXNwb3NlZCA9IHRydWU7CiAgICAgIH0sCiAgICApOwogICAgYXdhaXQgZXhwZWN0TGF0ZXIoCiAgICAgIGNvbnRhaW5lci51bnJlZ2lzdGVyPF9TZXJ2aWNlPihfU2VydmljZSgpKSwKICAgICAgdGhyb3dzQXJndW1lbnRFcnJvciwKICAgICk7CiAgICBleHBlY3QoY29udGFpbmVyLmdldDxfU2VydmljZT4oKSwgc2FtZShmaXJzdCkpOwogICAgZXhwZWN0KGRpc3Bvc2VkLCBpc0ZhbHNlKTsKICAgIGF3YWl0IGNvbnRhaW5lci51bnJlZ2lzdGVyPF9TZXJ2aWNlPihmaXJzdCk7CiAgICBleHBlY3QoZGlzcG9zZWQsIGlzVHJ1ZSk7CiAgfSk7Cn0K", + "type": "text" + }, { "path": "{{ name.snakeCase() }}/packages/localization/build.yaml", "data": @@ -751,7 +852,7 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "path": "{{ name.snakeCase() }}/packages/localization/test/localization_test.dart", "data": - "aW1wb3J0ICdwYWNrYWdlOmZsdXR0ZXJfdGVzdC9mbHV0dGVyX3Rlc3QuZGFydCc7CmltcG9ydCAncGFja2FnZTpsb2NhbGl6YXRpb24vbG9jYWxpemF0aW9uLmRhcnQnOwoKdm9pZCBtYWluKCkgewogIGdyb3VwKCdMb2NhbGl6YXRpb25Qcm92aWRlciBUZXN0cycsICgpIHsKICAgIHRlc3QoJ3Nob3VsZCBpbml0aWFsaXplIHdpdGggZGVmYXVsdCBsb2NhbGUnLCAoKSB7CiAgICAgIExvY2FsaXphdGlvblByb3ZpZGVyLmluaXRpYWxpemUoKTsKICAgICAgZXhwZWN0KExvY2FsaXphdGlvblByb3ZpZGVyLmN1cnJlbnRMb2NhbGUsICdlbicpOwogICAgfSk7CgogICAgdGVzdCgnc2hvdWxkIHJldHVybiBNZXNzYWdlcyBpbnN0YW5jZScsICgpIHsKICAgICAgZmluYWwgbWVzc2FnZXMgPSBMb2NhbGl6YXRpb25Qcm92aWRlci5tZXNzYWdlczsKICAgICAgZXhwZWN0KG1lc3NhZ2VzLCBpc0E8TWVzc2FnZXM+KCkpOwogICAgfSk7CgogICAgdGVzdCgnc2hvdWxkIHJldHVybiBzdXBwb3J0ZWQgbG9jYWxlcycsICgpIHsKICAgICAgZmluYWwgbG9jYWxlcyA9IExvY2FsaXphdGlvblByb3ZpZGVyLnN1cHBvcnRlZExvY2FsZXM7CiAgICAgIGV4cGVjdChsb2NhbGVzLCBjb250YWlucygnZW4nKSk7CiAgICB9KTsKCiAgICB0ZXN0KCdzaG91bGQgY2hlY2sgaWYgbG9jYWxlIGlzIHN1cHBvcnRlZCcsICgpIHsKICAgICAgZXhwZWN0KExvY2FsaXphdGlvblByb3ZpZGVyLmlzTG9jYWxlU3VwcG9ydGVkKCdlbicpLCB0cnVlKTsKICAgICAgZXhwZWN0KExvY2FsaXphdGlvblByb3ZpZGVyLmlzTG9jYWxlU3VwcG9ydGVkKCdlcycpLCBmYWxzZSk7CiAgICB9KTsKICB9KTsKfQo=", + "aW1wb3J0ICdwYWNrYWdlOmZsdXR0ZXJfdGVzdC9mbHV0dGVyX3Rlc3QuZGFydCc7CmltcG9ydCAncGFja2FnZTpmbHV0dGVyL21hdGVyaWFsLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6bG9jYWxpemF0aW9uL2xvY2FsaXphdGlvbi5kYXJ0JzsKCnZvaWQgbWFpbigpIHsKICB0ZXN0KCdsb2NhbGUgbWF0Y2hpbmcgc2VsZWN0cyBzdXBwb3J0ZWQgbGFuZ3VhZ2Ugb3IgZGVmYXVsdHMgdG8gRW5nbGlzaCcsICgpIHsKICAgIGV4cGVjdChMb2NhbGl6YXRpb25Qcm92aWRlci5nZXRNZXNzYWdlcygnZW4nKSwgaXNBPE1lc3NhZ2VzPigpKTsKICAgIGV4cGVjdCgKICAgICAgTG9jYWxpemF0aW9uUHJvdmlkZXIuZ2V0QmVzdE1hdGNoaW5nTG9jYWxlKFsKICAgICAgICBjb25zdCBMb2NhbGUoJ2VzJyksCiAgICAgICAgY29uc3QgTG9jYWxlKCdlbicsICdVUycpLAogICAgICBdKSwKICAgICAgJ2VuJywKICAgICk7CiAgICBleHBlY3QoCiAgICAgIExvY2FsaXphdGlvblByb3ZpZGVyLmdldEJlc3RNYXRjaGluZ0xvY2FsZShbY29uc3QgTG9jYWxlKCdlcycpXSksCiAgICAgICdlbicsCiAgICApOwogICAgZXhwZWN0KExvY2FsaXphdGlvblByb3ZpZGVyLmdldEJlc3RNYXRjaGluZ0xvY2FsZShbXSksICdlbicpOwogIH0pOwogIGdyb3VwKCdMb2NhbGl6YXRpb25Qcm92aWRlciBUZXN0cycsICgpIHsKICAgIHRlc3QoJ3Nob3VsZCBpbml0aWFsaXplIHdpdGggZGVmYXVsdCBsb2NhbGUnLCAoKSB7CiAgICAgIExvY2FsaXphdGlvblByb3ZpZGVyLmluaXRpYWxpemUoKTsKICAgICAgZXhwZWN0KExvY2FsaXphdGlvblByb3ZpZGVyLmN1cnJlbnRMb2NhbGUsICdlbicpOwogICAgfSk7CgogICAgdGVzdCgnc2hvdWxkIHJldHVybiBNZXNzYWdlcyBpbnN0YW5jZScsICgpIHsKICAgICAgZmluYWwgbWVzc2FnZXMgPSBMb2NhbGl6YXRpb25Qcm92aWRlci5tZXNzYWdlczsKICAgICAgZXhwZWN0KG1lc3NhZ2VzLCBpc0E8TWVzc2FnZXM+KCkpOwogICAgfSk7CgogICAgdGVzdCgnc2hvdWxkIHJldHVybiBzdXBwb3J0ZWQgbG9jYWxlcycsICgpIHsKICAgICAgZmluYWwgbG9jYWxlcyA9IExvY2FsaXphdGlvblByb3ZpZGVyLnN1cHBvcnRlZExvY2FsZXM7CiAgICAgIGV4cGVjdChsb2NhbGVzLCBjb250YWlucygnZW4nKSk7CiAgICB9KTsKCiAgICB0ZXN0KCdzaG91bGQgY2hlY2sgaWYgbG9jYWxlIGlzIHN1cHBvcnRlZCcsICgpIHsKICAgICAgZXhwZWN0KExvY2FsaXphdGlvblByb3ZpZGVyLmlzTG9jYWxlU3VwcG9ydGVkKCdlbicpLCB0cnVlKTsKICAgICAgZXhwZWN0KExvY2FsaXphdGlvblByb3ZpZGVyLmlzTG9jYWxlU3VwcG9ydGVkKCdlcycpLCBmYWxzZSk7CiAgICB9KTsKICB9KTsKfQo=", "type": "text" }, { @@ -764,7 +865,7 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "path": "{{ name.snakeCase() }}/packages/utils/lib/src/number_formatter.dart", "data": - "aW1wb3J0ICdwYWNrYWdlOmludGwvaW50bC5kYXJ0JzsKCi8vLyBFeHRlbnNpb24gZm9yIGZvcm1hdHRpbmcgZGVjaW1hbCBudW1iZXJzIHdpdGggY2xlYW4sIHByb2Zlc3Npb25hbCBkaXNwbGF5CmV4dGVuc2lvbiBEb3VibGVGb3JtYXR0aW5nIG9uIGRvdWJsZSB7CiAgLy8vIEZvcm1hdHMgZGVjaW1hbCB2YWx1ZXMsIHJlbW92aW5nIHVubmVjZXNzYXJ5IC4wIGZvciB3aG9sZSBudW1iZXJzCiAgU3RyaW5nIGZvcm1hdCh7aW50IGRlY2ltYWxQbGFjZXMgPSAxfSkgewogICAgZmluYWwgZm9ybWF0dGVyID0gTnVtYmVyRm9ybWF0KCcjLiR7JyMnICogZGVjaW1hbFBsYWNlc30nKTsKICAgIHJldHVybiBmb3JtYXR0ZXIuZm9ybWF0KHRoaXMpOwogIH0KCiAgLy8vIEZvcm1hdHMgc2NvcmUgdmFsdWVzIHdpdGggY2xlYW4gZGVjaW1hbCBoYW5kbGluZwogIFN0cmluZyBhc1Njb3JlKCkgPT4gZm9ybWF0KGRlY2ltYWxQbGFjZXM6IDEpOwoKICAvLy8gRm9ybWF0cyBIUlYgdmFsdWVzIHdpdGggc21hcnQgZGVjaW1hbCBoYW5kbGluZwogIFN0cmluZyBhc0hydigpID0+IGZvcm1hdChkZWNpbWFsUGxhY2VzOiAxKTsKCiAgLy8vIEZvcm1hdHMgc2xlZXAgaG91cnMgd2l0aCBzbWFydCBkZWNpbWFsIGhhbmRsaW5nCiAgU3RyaW5nIGFzU2xlZXBIb3VycygpID0+IGZvcm1hdChkZWNpbWFsUGxhY2VzOiAxKTsKCiAgLy8vIEZvcm1hdHMgcmVzcGlyYXRvcnkgcmF0ZSB3aXRoIHNtYXJ0IGRlY2ltYWwgaGFuZGxpbmcKICBTdHJpbmcgYXNSZXNwaXJhdG9yeVJhdGUoKSA9PiBmb3JtYXQoZGVjaW1hbFBsYWNlczogMSk7Cn0KCi8vLyBFeHRlbnNpb24gZm9yIGZvcm1hdHRpbmcgYW55IG51bWVyaWMgdmFsdWUKZXh0ZW5zaW9uIE51bUZvcm1hdHRpbmcgb24gbnVtIHsKICAvLy8gRm9ybWF0cyBsYXJnZSBudW1iZXJzIHdpdGggSywgTSwgQiBzdWZmaXhlcyBhbmQgc21hcnQgZGVjaW1hbCBoYW5kbGluZwogIFN0cmluZyBjb21wYWN0KCkgewogICAgZmluYWwgTnVtYmVyRm9ybWF0IGZvcm1hdHRlciA9IE51bWJlckZvcm1hdC5jb21wYWN0KGxvY2FsZTogJ2VuX1VTJyk7CiAgICByZXR1cm4gZm9ybWF0dGVyLmZvcm1hdCh0aGlzKTsKICB9CgogIC8vLyBGb3JtYXRzIGhlYXJ0IHJhdGUgdmFsdWVzIChhbHdheXMgd2hvbGUgbnVtYmVycykKICBTdHJpbmcgYXNIZWFydFJhdGUoKSA9PiByb3VuZCgpLnRvU3RyaW5nKCk7Cn0KCi8vLyBFeHRlbnNpb24gZm9yIGZvcm1hdHRpbmcgdGltZSBkdXJhdGlvbiBmcm9tIHNlY29uZHMKZXh0ZW5zaW9uIEludFRpbWVGb3JtYXR0aW5nIG9uIGludCB7CiAgLy8vIEZvcm1hdCB0aW1lIGZyb20gc2Vjb25kcyB0byAxIHNlYyBvciAxbWluIDFzZWMgb3IgMWhyIDFtaW4KICBTdHJpbmcgYXNUaW1lKCkgewogICAgaWYgKHRoaXMgPCA2MCkgewogICAgICByZXR1cm4gJyR0aGlzIHNlYyc7CiAgICB9IGVsc2UgaWYgKHRoaXMgPCAzNjAwKSB7CiAgICAgIGZpbmFsIG1pbnV0ZXMgPSB0aGlzIH4vIDYwOwogICAgICBmaW5hbCByZW1haW5pbmdTZWNvbmRzID0gdGhpcyAlIDYwOwogICAgICBpZiAocmVtYWluaW5nU2Vjb25kcyA9PSAwKSB7CiAgICAgICAgcmV0dXJuICckbWludXRlcyBtaW4nOwogICAgICB9CiAgICAgIHJldHVybiAnJG1pbnV0ZXMgbWluICRyZW1haW5pbmdTZWNvbmRzIHNlYyc7CiAgICB9IGVsc2UgewogICAgICBmaW5hbCBob3VycyA9IHRoaXMgfi8gMzYwMDsKICAgICAgZmluYWwgcmVtYWluaW5nTWludXRlcyA9ICh0aGlzICUgMzYwMCkgfi8gNjA7CiAgICAgIGlmIChyZW1haW5pbmdNaW51dGVzID09IDApIHsKICAgICAgICByZXR1cm4gJyRob3VycyBocic7CiAgICAgIH0KICAgICAgcmV0dXJuICckaG91cnMgaHIgJHJlbWFpbmluZ01pbnV0ZXMgbWluJzsKICAgIH0KICB9Cn0KCmV4dGVuc2lvbiBEYXRlVGltZUZvcm1hdHRpbmcgb24gRGF0ZVRpbWUgewogIFN0cmluZyBmb3JtYXRSZWxhdGl2ZSgpIHsKICAgIGZpbmFsIG5vdyA9IERhdGVUaW1lLm5vdygpOwogICAgZmluYWwgZGlmZmVyZW5jZSA9IG5vdy5kaWZmZXJlbmNlKHRoaXMpOwoKICAgIGlmIChkaWZmZXJlbmNlLmluTWludXRlcyA8IDEpIHsKICAgICAgcmV0dXJuICdKdXN0IG5vdyc7CiAgICB9IGVsc2UgaWYgKGRpZmZlcmVuY2UuaW5NaW51dGVzIDwgNjApIHsKICAgICAgcmV0dXJuICcke2RpZmZlcmVuY2UuaW5NaW51dGVzfW0gYWdvJzsKICAgIH0gZWxzZSBpZiAoZGlmZmVyZW5jZS5pbkhvdXJzIDwgMjQpIHsKICAgICAgcmV0dXJuICcke2RpZmZlcmVuY2UuaW5Ib3Vyc31oIGFnbyc7CiAgICB9IGVsc2UgaWYgKGRpZmZlcmVuY2UuaW5EYXlzID09IDEpIHsKICAgICAgcmV0dXJuICdZZXN0ZXJkYXknOwogICAgfSBlbHNlIGlmIChkaWZmZXJlbmNlLmluRGF5cyA8IDcpIHsKICAgICAgcmV0dXJuICcke2RpZmZlcmVuY2UuaW5EYXlzfWQgYWdvJzsKICAgIH0gZWxzZSB7CiAgICAgIHJldHVybiAnJGRheS8kbW9udGgvJHllYXInOwogICAgfQogIH0KfQo=", + "aW1wb3J0ICdwYWNrYWdlOmludGwvaW50bC5kYXJ0JzsKCi8vLyBFeHRlbnNpb24gZm9yIGZvcm1hdHRpbmcgZGVjaW1hbCBudW1iZXJzIHdpdGggY2xlYW4sIHByb2Zlc3Npb25hbCBkaXNwbGF5CmV4dGVuc2lvbiBEb3VibGVGb3JtYXR0aW5nIG9uIGRvdWJsZSB7CiAgLy8vIEZvcm1hdHMgZGVjaW1hbCB2YWx1ZXMsIHJlbW92aW5nIHVubmVjZXNzYXJ5IC4wIGZvciB3aG9sZSBudW1iZXJzCiAgU3RyaW5nIGZvcm1hdCh7aW50IGRlY2ltYWxQbGFjZXMgPSAxfSkgewogICAgZmluYWwgZm9ybWF0dGVyID0gTnVtYmVyRm9ybWF0KCcjLiR7JyMnICogZGVjaW1hbFBsYWNlc30nKTsKICAgIHJldHVybiBmb3JtYXR0ZXIuZm9ybWF0KHRoaXMpOwogIH0KCiAgLy8vIEZvcm1hdHMgc2NvcmUgdmFsdWVzIHdpdGggY2xlYW4gZGVjaW1hbCBoYW5kbGluZwogIFN0cmluZyBhc1Njb3JlKCkgPT4gZm9ybWF0KGRlY2ltYWxQbGFjZXM6IDEpOwoKICAvLy8gRm9ybWF0cyBIUlYgdmFsdWVzIHdpdGggc21hcnQgZGVjaW1hbCBoYW5kbGluZwogIFN0cmluZyBhc0hydigpID0+IGZvcm1hdChkZWNpbWFsUGxhY2VzOiAxKTsKCiAgLy8vIEZvcm1hdHMgc2xlZXAgaG91cnMgd2l0aCBzbWFydCBkZWNpbWFsIGhhbmRsaW5nCiAgU3RyaW5nIGFzU2xlZXBIb3VycygpID0+IGZvcm1hdChkZWNpbWFsUGxhY2VzOiAxKTsKCiAgLy8vIEZvcm1hdHMgcmVzcGlyYXRvcnkgcmF0ZSB3aXRoIHNtYXJ0IGRlY2ltYWwgaGFuZGxpbmcKICBTdHJpbmcgYXNSZXNwaXJhdG9yeVJhdGUoKSA9PiBmb3JtYXQoZGVjaW1hbFBsYWNlczogMSk7Cn0KCi8vLyBFeHRlbnNpb24gZm9yIGZvcm1hdHRpbmcgYW55IG51bWVyaWMgdmFsdWUKZXh0ZW5zaW9uIE51bUZvcm1hdHRpbmcgb24gbnVtIHsKICAvLy8gRm9ybWF0cyBsYXJnZSBudW1iZXJzIHdpdGggSywgTSwgQiBzdWZmaXhlcyBhbmQgc21hcnQgZGVjaW1hbCBoYW5kbGluZwogIFN0cmluZyBjb21wYWN0KCkgewogICAgZmluYWwgTnVtYmVyRm9ybWF0IGZvcm1hdHRlciA9IE51bWJlckZvcm1hdC5jb21wYWN0KGxvY2FsZTogJ2VuX1VTJyk7CiAgICByZXR1cm4gZm9ybWF0dGVyLmZvcm1hdCh0aGlzKTsKICB9CgogIC8vLyBGb3JtYXRzIGhlYXJ0IHJhdGUgdmFsdWVzIChhbHdheXMgd2hvbGUgbnVtYmVycykKICBTdHJpbmcgYXNIZWFydFJhdGUoKSA9PiByb3VuZCgpLnRvU3RyaW5nKCk7Cn0KCi8vLyBFeHRlbnNpb24gZm9yIGZvcm1hdHRpbmcgdGltZSBkdXJhdGlvbiBmcm9tIHNlY29uZHMKZXh0ZW5zaW9uIEludFRpbWVGb3JtYXR0aW5nIG9uIGludCB7CiAgLy8vIEZvcm1hdCB0aW1lIGZyb20gc2Vjb25kcyB0byAxIHNlYyBvciAxbWluIDFzZWMgb3IgMWhyIDFtaW4KICBTdHJpbmcgYXNUaW1lKCkgewogICAgaWYgKHRoaXMgPCA2MCkgewogICAgICByZXR1cm4gJyR0aGlzIHNlYyc7CiAgICB9IGVsc2UgaWYgKHRoaXMgPCAzNjAwKSB7CiAgICAgIGZpbmFsIG1pbnV0ZXMgPSB0aGlzIH4vIDYwOwogICAgICBmaW5hbCByZW1haW5pbmdTZWNvbmRzID0gdGhpcyAlIDYwOwogICAgICBpZiAocmVtYWluaW5nU2Vjb25kcyA9PSAwKSB7CiAgICAgICAgcmV0dXJuICckbWludXRlcyBtaW4nOwogICAgICB9CiAgICAgIHJldHVybiAnJG1pbnV0ZXMgbWluICRyZW1haW5pbmdTZWNvbmRzIHNlYyc7CiAgICB9IGVsc2UgewogICAgICBmaW5hbCBob3VycyA9IHRoaXMgfi8gMzYwMDsKICAgICAgZmluYWwgcmVtYWluaW5nTWludXRlcyA9ICh0aGlzICUgMzYwMCkgfi8gNjA7CiAgICAgIGlmIChyZW1haW5pbmdNaW51dGVzID09IDApIHsKICAgICAgICByZXR1cm4gJyRob3VycyBocic7CiAgICAgIH0KICAgICAgcmV0dXJuICckaG91cnMgaHIgJHJlbWFpbmluZ01pbnV0ZXMgbWluJzsKICAgIH0KICB9Cn0KCmV4dGVuc2lvbiBEYXRlVGltZUZvcm1hdHRpbmcgb24gRGF0ZVRpbWUgewogIFN0cmluZyBmb3JtYXRSZWxhdGl2ZSh7RGF0ZVRpbWU/IG5vd30pIHsKICAgIGZpbmFsIGRpZmZlcmVuY2UgPSAobm93ID8/IERhdGVUaW1lLm5vdygpKS5kaWZmZXJlbmNlKHRoaXMpOwoKICAgIGlmIChkaWZmZXJlbmNlLmluTWludXRlcyA8IDEpIHsKICAgICAgcmV0dXJuICdKdXN0IG5vdyc7CiAgICB9IGVsc2UgaWYgKGRpZmZlcmVuY2UuaW5NaW51dGVzIDwgNjApIHsKICAgICAgcmV0dXJuICcke2RpZmZlcmVuY2UuaW5NaW51dGVzfW0gYWdvJzsKICAgIH0gZWxzZSBpZiAoZGlmZmVyZW5jZS5pbkhvdXJzIDwgMjQpIHsKICAgICAgcmV0dXJuICcke2RpZmZlcmVuY2UuaW5Ib3Vyc31oIGFnbyc7CiAgICB9IGVsc2UgaWYgKGRpZmZlcmVuY2UuaW5EYXlzID09IDEpIHsKICAgICAgcmV0dXJuICdZZXN0ZXJkYXknOwogICAgfSBlbHNlIGlmIChkaWZmZXJlbmNlLmluRGF5cyA8IDcpIHsKICAgICAgcmV0dXJuICcke2RpZmZlcmVuY2UuaW5EYXlzfWQgYWdvJzsKICAgIH0gZWxzZSB7CiAgICAgIHJldHVybiAnJGRheS8kbW9udGgvJHllYXInOwogICAgfQogIH0KfQo=", "type": "text" }, { @@ -779,11 +880,18 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "bmFtZTogdXRpbHMKZGVzY3JpcHRpb246ICJTaGFyZWQsIGRlcGVuZGVuY3ktbGlnaHQgaGVscGVycyBmb3Ige3tuYW1lLnRpdGxlQ2FzZSgpfX0uIgp2ZXJzaW9uOiAwLjEuMApwdWJsaXNoX3RvOiAnbm9uZScKCmVudmlyb25tZW50OgogIHNkazogXjMuOC4wCiAgZmx1dHRlcjogIj49My4yOS4wIgoKZGVwZW5kZW5jaWVzOgogIGZsdXR0ZXI6CiAgICBzZGs6IGZsdXR0ZXIKICBpbnRsOiBeMC4yMC4yCgpkZXZfZGVwZW5kZW5jaWVzOgogIGZsdXR0ZXJfdGVzdDoKICAgIHNkazogZmx1dHRlcgogIGZsdXR0ZXJfbGludHM6IF41LjAuMAoKZmx1dHRlcjoK", "type": "text" }, + { + "path": + "{{ name.snakeCase() }}/packages/utils/test/number_formatter_test.dart", + "data": + "aW1wb3J0ICdwYWNrYWdlOmZsdXR0ZXJfdGVzdC9mbHV0dGVyX3Rlc3QuZGFydCc7CmltcG9ydCAncGFja2FnZTp1dGlscy91dGlscy5kYXJ0JzsKCnZvaWQgbWFpbigpIHsKICB0ZXN0KCdmb3JtYXRzIGRlY2ltYWxzIGFuZCBkb21haW4gY29udmVuaWVuY2VzIGNvbnNpc3RlbnRseScsICgpIHsKICAgIGV4cGVjdCgyLjAuZm9ybWF0KCksICcyJyk7CiAgICBleHBlY3QoMi4xMjUuZm9ybWF0KGRlY2ltYWxQbGFjZXM6IDIpLCAnMi4xMycpOwogICAgZXhwZWN0KDIuMjUuYXNTY29yZSgpLCAnMi4zJyk7CiAgICBleHBlY3QoMi4yNS5hc0hydigpLCAnMi4zJyk7CiAgICBleHBlY3QoMi4yNS5hc1NsZWVwSG91cnMoKSwgJzIuMycpOwogICAgZXhwZWN0KDIuMjUuYXNSZXNwaXJhdG9yeVJhdGUoKSwgJzIuMycpOwogICAgZXhwZWN0KDEyNTAuY29tcGFjdCgpLCAnMS4yNUsnKTsKICAgIGV4cGVjdCg3Mi42LmFzSGVhcnRSYXRlKCksICc3MycpOwogIH0pOwoKICB0ZXN0KCdmb3JtYXRzIGR1cmF0aW9uIGJvdW5kYXJpZXMnLCAoKSB7CiAgICBmb3IgKGZpbmFsIGVudHJ5IGluIHsKICAgICAgMDogJzAgc2VjJywKICAgICAgNTk6ICc1OSBzZWMnLAogICAgICA2MDogJzEgbWluJywKICAgICAgNjE6ICcxIG1pbiAxIHNlYycsCiAgICAgIDM1OTk6ICc1OSBtaW4gNTkgc2VjJywKICAgICAgMzYwMDogJzEgaHInLAogICAgICAzNjYwOiAnMSBociAxIG1pbicsCiAgICB9LmVudHJpZXMpIHsKICAgICAgZXhwZWN0KGVudHJ5LmtleS5hc1RpbWUoKSwgZW50cnkudmFsdWUpOwogICAgfQogIH0pOwoKICB0ZXN0KCdyZWxhdGl2ZSB0aW1lIGhhcyBkZXRlcm1pbmlzdGljIG1pbnV0ZSwgaG91ciBhbmQgZGF0ZSBib3VuZGFyaWVzJywgKCkgewogICAgZmluYWwgbm93ID0gRGF0ZVRpbWUoMjAyNiwgMSwgMTUsIDEyKTsKICAgIGZvciAoZmluYWwgZW50cnkgaW4gewogICAgICBEdXJhdGlvbi56ZXJvOiAnSnVzdCBub3cnLAogICAgICBjb25zdCBEdXJhdGlvbihtaW51dGVzOiAxKTogJzFtIGFnbycsCiAgICAgIGNvbnN0IER1cmF0aW9uKGhvdXJzOiAxKTogJzFoIGFnbycsCiAgICAgIGNvbnN0IER1cmF0aW9uKGRheXM6IDEpOiAnWWVzdGVyZGF5JywKICAgICAgY29uc3QgRHVyYXRpb24oZGF5czogMyk6ICczZCBhZ28nLAogICAgICBjb25zdCBEdXJhdGlvbihkYXlzOiA3KTogJzgvMS8yMDI2JywKICAgIH0uZW50cmllcykgewogICAgICBleHBlY3Qobm93LnN1YnRyYWN0KGVudHJ5LmtleSkuZm9ybWF0UmVsYXRpdmUobm93OiBub3cpLCBlbnRyeS52YWx1ZSk7CiAgICB9CiAgICBleHBlY3QoRGF0ZVRpbWUubm93KCkuZm9ybWF0UmVsYXRpdmUoKSwgJ0p1c3Qgbm93Jyk7CiAgfSk7Cn0K", + "type": "text" + }, { "path": "{{ name.snakeCase() }}/packages/{{analytics_dir}}/lib/analytics.dart", "data": - "bGlicmFyeTsKCmltcG9ydCAncGFja2FnZTphbmFseXRpY3Mvc3JjL2NsaWVudC9pbmRleC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmFuYWx5dGljcy9zcmMvY29uZmlnL2luZGV4LmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Y29yZS9jb3JlLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZGkvZGkuZGFydCc7CgpleHBvcnQgJ3NyYy9jbGllbnQvaW5kZXguZGFydCc7CmV4cG9ydCAnc3JjL2NvbmZpZy9pbmRleC5kYXJ0JzsKZXhwb3J0ICdzcmMvbW9kZWxzL2luZGV4LmRhcnQnOwpleHBvcnQgJ3NyYy9vYnNlcnZlci9pbmRleC5kYXJ0JzsKZXhwb3J0ICdzcmMvdXRpbHMvaW5kZXguZGFydCc7CgpGdXR1cmU8dm9pZD4gaW5pdCh7CiAgQW5hbHl0aWNzQ29uZmlnIGNvbmZpZyA9IGNvbnN0IERlZmF1bHRBbmFseXRpY3NDb25maWcoKSwKfSkgYXN5bmMgewogIGF3YWl0IHJlZ2lzdGVyQW5hbHl0aWNzV2l0aERJKGNvbmZpZyk7CiAgZmluYWwgbG9nZ2VyID0gZGkuZ2V0PExvZ2dlcj4oKTsKICBsb2dnZXIuaSgnQW5hbHl0aWNzIG1vZHVsZSBpbml0aWFsaXplZCB3aXRoIEZpcmViYXNlIEFuYWx5dGljcycpOwp9CgpGdXR1cmU8dm9pZD4gcmVnaXN0ZXJBbmFseXRpY3NXaXRoREkoQW5hbHl0aWNzQ29uZmlnIGNvbmZpZykgYXN5bmMgewogIGZpbmFsIGxvZ2dlciA9IGRpLmdldDxMb2dnZXI+KCk7CgogIGZpbmFsIGFuYWx5dGljc0NsaWVudCA9IEZpcmViYXNlQW5hbHl0aWNzQ2xpZW50KGNvbmZpZyk7CiAgZGkucmVnaXN0ZXI8QW5hbHl0aWNzQ2xpZW50PigKICAgIGFuYWx5dGljc0NsaWVudCwKICAgIGRpc3Bvc2U6IChjbGllbnQpID0+IGNsaWVudC5kaXNwb3NlKCksCiAgKTsKICBkaS5yZWdpc3RlcjxBbmFseXRpY3NDb25maWc+KGNvbmZpZyk7CgogIGlmIChjb25maWcuZW5hYmxlQW5hbHl0aWNzKSB7CiAgICBsb2dnZXIuaSgn8J+UjSBBbmFseXRpY3MgY2xpZW50IHJlZ2lzdGVyZWQgd2l0aCBjb2xsZWN0aW9uIGVuYWJsZWQnKTsKICB9IGVsc2UgewogICAgbG9nZ2VyLmkoJ/CflI0gQW5hbHl0aWNzIGNsaWVudCByZWdpc3RlcmVkIHdpdGggY29sbGVjdGlvbiBkaXNhYmxlZCcpOwogIH0KfQo=", + "bGlicmFyeTsKCmltcG9ydCAncGFja2FnZTphbmFseXRpY3Mvc3JjL2NsaWVudC9pbmRleC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmFuYWx5dGljcy9zcmMvY29uZmlnL2luZGV4LmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Y29yZS9jb3JlLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZGkvZGkuZGFydCc7CmltcG9ydCAncGFja2FnZTpmaXJlYmFzZV9hbmFseXRpY3MvZmlyZWJhc2VfYW5hbHl0aWNzLmRhcnQnOwoKZXhwb3J0ICdzcmMvY2xpZW50L2luZGV4LmRhcnQnOwpleHBvcnQgJ3NyYy9jb25maWcvaW5kZXguZGFydCc7CmV4cG9ydCAnc3JjL21vZGVscy9pbmRleC5kYXJ0JzsKZXhwb3J0ICdzcmMvb2JzZXJ2ZXIvaW5kZXguZGFydCc7CmV4cG9ydCAnc3JjL3V0aWxzL2luZGV4LmRhcnQnOwoKRnV0dXJlPHZvaWQ+IGluaXQoewogIEFuYWx5dGljc0NvbmZpZyBjb25maWcgPSBjb25zdCBEZWZhdWx0QW5hbHl0aWNzQ29uZmlnKCksCiAgRmlyZWJhc2VBbmFseXRpY3M/IGFuYWx5dGljcywKfSkgYXN5bmMgewogIGF3YWl0IHJlZ2lzdGVyQW5hbHl0aWNzV2l0aERJKGNvbmZpZywgYW5hbHl0aWNzOiBhbmFseXRpY3MpOwogIGZpbmFsIGxvZ2dlciA9IGRpLmdldDxMb2dnZXI+KCk7CiAgbG9nZ2VyLmkoJ0FuYWx5dGljcyBtb2R1bGUgaW5pdGlhbGl6ZWQgd2l0aCBGaXJlYmFzZSBBbmFseXRpY3MnKTsKfQoKRnV0dXJlPHZvaWQ+IHJlZ2lzdGVyQW5hbHl0aWNzV2l0aERJKAogIEFuYWx5dGljc0NvbmZpZyBjb25maWcsIHsKICBGaXJlYmFzZUFuYWx5dGljcz8gYW5hbHl0aWNzLAp9KSBhc3luYyB7CiAgZmluYWwgbG9nZ2VyID0gZGkuZ2V0PExvZ2dlcj4oKTsKCiAgZmluYWwgYW5hbHl0aWNzQ2xpZW50ID0gRmlyZWJhc2VBbmFseXRpY3NDbGllbnQoCiAgICBjb25maWcsCiAgICBhbmFseXRpY3M6IGFuYWx5dGljcyA/PyBGaXJlYmFzZUFuYWx5dGljcy5pbnN0YW5jZSwKICAgIGxvZ2dlcjogbG9nZ2VyLAogICk7CiAgYXdhaXQgYW5hbHl0aWNzQ2xpZW50LmluaXRpYWxpemUoKTsKICBkaS5yZWdpc3RlcjxBbmFseXRpY3NDbGllbnQ+KAogICAgYW5hbHl0aWNzQ2xpZW50LAogICAgZGlzcG9zZTogKGNsaWVudCkgPT4gY2xpZW50LmRpc3Bvc2UoKSwKICApOwogIGRpLnJlZ2lzdGVyPEFuYWx5dGljc0NvbmZpZz4oY29uZmlnKTsKCiAgaWYgKGNvbmZpZy5lbmFibGVBbmFseXRpY3MpIHsKICAgIGxvZ2dlci5pKCfwn5SNIEFuYWx5dGljcyBjbGllbnQgcmVnaXN0ZXJlZCB3aXRoIGNvbGxlY3Rpb24gZW5hYmxlZCcpOwogIH0gZWxzZSB7CiAgICBsb2dnZXIuaSgn8J+UjSBBbmFseXRpY3MgY2xpZW50IHJlZ2lzdGVyZWQgd2l0aCBjb2xsZWN0aW9uIGRpc2FibGVkJyk7CiAgfQp9Cg==", "type": "text" }, { @@ -797,7 +905,7 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "path": "{{ name.snakeCase() }}/packages/{{analytics_dir}}/lib/src/client/firebase_analytics_client.dart", "data": - "aW1wb3J0ICdwYWNrYWdlOmFuYWx5dGljcy9zcmMvY2xpZW50L2FuYWx5dGljc19jbGllbnQuZGFydCc7CmltcG9ydCAncGFja2FnZTphbmFseXRpY3Mvc3JjL2NvbmZpZy9hbmFseXRpY3NfY29uZmlnLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6YW5hbHl0aWNzL3NyYy9tb2RlbHMvYW5hbHl0aWNzX2V2ZW50LmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Y29yZS9jb3JlLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZGkvZGkuZGFydCc7CmltcG9ydCAncGFja2FnZTpmaXJlYmFzZV9hbmFseXRpY3MvZmlyZWJhc2VfYW5hbHl0aWNzLmRhcnQnOwoKY2xhc3MgRmlyZWJhc2VBbmFseXRpY3NDbGllbnQgaW1wbGVtZW50cyBBbmFseXRpY3NDbGllbnQgewogIEZpcmViYXNlQW5hbHl0aWNzQ2xpZW50KHRoaXMuX2NvbmZpZykKICAgIDogX2FuYWx5dGljcyA9IEZpcmViYXNlQW5hbHl0aWNzLmluc3RhbmNlIHsKICAgIF9zZXR1cEFuYWx5dGljcygpOwogIH0KCiAgZmluYWwgQW5hbHl0aWNzQ29uZmlnIF9jb25maWc7CiAgZmluYWwgRmlyZWJhc2VBbmFseXRpY3MgX2FuYWx5dGljczsKICBmaW5hbCBMb2dnZXIgX2xvZ2dlciA9IGRpLmdldDxMb2dnZXI+KCk7CgogIHZvaWQgX3NldHVwQW5hbHl0aWNzKCkgewogICAgX2FuYWx5dGljcy5zZXRBbmFseXRpY3NDb2xsZWN0aW9uRW5hYmxlZChfY29uZmlnLmVuYWJsZUFuYWx5dGljcyk7CgogICAgaWYgKF9jb25maWcudXNlcklkICE9IG51bGwpIHsKICAgICAgX2FuYWx5dGljcy5zZXRVc2VySWQoaWQ6IF9jb25maWcudXNlcklkKTsKICAgICAgX2xvZ2dlci5kKCfwn5SNIEFuYWx5dGljcyB1c2VyIElEIHNldDogJHtfY29uZmlnLnVzZXJJZH0nKTsKICAgIH0KCiAgICBpZiAoX2NvbmZpZy5kZWZhdWx0VXNlclByb3BlcnRpZXMgIT0gbnVsbCkgewogICAgICBmb3IgKGZpbmFsIGVudHJ5IGluIF9jb25maWcuZGVmYXVsdFVzZXJQcm9wZXJ0aWVzIS5lbnRyaWVzKSB7CiAgICAgICAgX2FuYWx5dGljcy5zZXRVc2VyUHJvcGVydHkobmFtZTogZW50cnkua2V5LCB2YWx1ZTogZW50cnkudmFsdWUpOwogICAgICB9CiAgICAgIF9sb2dnZXIuZCgn8J+UjSBBbmFseXRpY3MgZGVmYXVsdCB1c2VyIHByb3BlcnRpZXMgc2V0Jyk7CiAgICB9CgogICAgaWYgKF9jb25maWcuZW5hYmxlRGVidWdMb2dnaW5nKSB7CiAgICAgIF9sb2dnZXIuZCgn8J+UjSBGaXJlYmFzZSBBbmFseXRpY3MgaW5pdGlhbGl6ZWQgd2l0aCBkZWJ1ZyBsb2dnaW5nIGVuYWJsZWQnKTsKICAgIH0gZWxzZSB7CiAgICAgIF9sb2dnZXIuaSgn8J+UjSBGaXJlYmFzZSBBbmFseXRpY3MgaW5pdGlhbGl6ZWQnKTsKICAgIH0KICB9CgogIEBvdmVycmlkZQogIEZ1dHVyZTx2b2lkPiBsb2dFdmVudCh7CiAgICByZXF1aXJlZCBTdHJpbmcgbmFtZSwKICAgIE1hcDxTdHJpbmcsIGR5bmFtaWM+PyBwYXJhbWV0ZXJzLAogIH0pIGFzeW5jIHsKICAgIHRyeSB7CiAgICAgIGlmICghX2NvbmZpZy5lbmFibGVBbmFseXRpY3MpIHsKICAgICAgICBpZiAoX2NvbmZpZy5lbmFibGVEZWJ1Z0xvZ2dpbmcpIHsKICAgICAgICAgIF9sb2dnZXIuZCgn8J+UjSBBbmFseXRpY3MgZGlzYWJsZWQsIHNraXBwaW5nIGV2ZW50OiAkbmFtZScpOwogICAgICAgIH0KICAgICAgICByZXR1cm47CiAgICAgIH0KCiAgICAgIGF3YWl0IF9hbmFseXRpY3MubG9nRXZlbnQoCiAgICAgICAgbmFtZTogbmFtZSwKICAgICAgICBwYXJhbWV0ZXJzOiBwYXJhbWV0ZXJzPy5jYXN0PFN0cmluZywgT2JqZWN0PigpLAogICAgICApOwoKICAgICAgaWYgKF9jb25maWcuZW5hYmxlRGVidWdMb2dnaW5nKSB7CiAgICAgICAgX2xvZ2dlci5kKAogICAgICAgICAgJ/CflI0gQW5hbHl0aWNzIGV2ZW50IGxvZ2dlZDogJG5hbWUgd2l0aCBwYXJhbWV0ZXJzOiAkcGFyYW1ldGVycycsCiAgICAgICAgKTsKICAgICAgfQogICAgfSBjYXRjaCAoZSwgcykgewogICAgICBfbG9nZ2VyLmUoJ0ZhaWxlZCB0byBsb2cgYW5hbHl0aWNzIGV2ZW50OiAkbmFtZScsIGUsIHMpOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPHZvaWQ+IGxvZ0N1c3RvbUV2ZW50KEFuYWx5dGljc0V2ZW50IGV2ZW50KSBhc3luYyB7CiAgICBhd2FpdCBsb2dFdmVudChuYW1lOiBldmVudC5uYW1lLCBwYXJhbWV0ZXJzOiBldmVudC5wYXJhbWV0ZXJzKTsKICB9CgogIEBvdmVycmlkZQogIEZ1dHVyZTx2b2lkPiBzZXRVc2VySWQoU3RyaW5nPyB1c2VySWQpIGFzeW5jIHsKICAgIHRyeSB7CiAgICAgIGF3YWl0IF9hbmFseXRpY3Muc2V0VXNlcklkKGlkOiB1c2VySWQpOwoKICAgICAgaWYgKF9jb25maWcuZW5hYmxlRGVidWdMb2dnaW5nKSB7CiAgICAgICAgX2xvZ2dlci5kKCfwn5SNIEFuYWx5dGljcyB1c2VyIElEIHNldDogJHVzZXJJZCcpOwogICAgICB9CiAgICB9IGNhdGNoIChlLCBzKSB7CiAgICAgIF9sb2dnZXIuZSgnRmFpbGVkIHRvIHNldCBhbmFseXRpY3MgdXNlciBJRDogJHVzZXJJZCcsIGUsIHMpOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPHZvaWQ+IHNldFVzZXJQcm9wZXJ0eSh7CiAgICByZXF1aXJlZCBTdHJpbmcgbmFtZSwKICAgIHJlcXVpcmVkIFN0cmluZz8gdmFsdWUsCiAgfSkgYXN5bmMgewogICAgdHJ5IHsKICAgICAgYXdhaXQgX2FuYWx5dGljcy5zZXRVc2VyUHJvcGVydHkobmFtZTogbmFtZSwgdmFsdWU6IHZhbHVlKTsKCiAgICAgIGlmIChfY29uZmlnLmVuYWJsZURlYnVnTG9nZ2luZykgewogICAgICAgIF9sb2dnZXIuZCgn8J+UjSBBbmFseXRpY3MgdXNlciBwcm9wZXJ0eSBzZXQ6ICRuYW1lID0gJHZhbHVlJyk7CiAgICAgIH0KICAgIH0gY2F0Y2ggKGUsIHMpIHsKICAgICAgX2xvZ2dlci5lKCdGYWlsZWQgdG8gc2V0IGFuYWx5dGljcyB1c2VyIHByb3BlcnR5OiAkbmFtZScsIGUsIHMpOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPHZvaWQ+IHJlc2V0QW5hbHl0aWNzRGF0YSgpIGFzeW5jIHsKICAgIHRyeSB7CiAgICAgIGF3YWl0IF9hbmFseXRpY3MucmVzZXRBbmFseXRpY3NEYXRhKCk7CgogICAgICBpZiAoX2NvbmZpZy5lbmFibGVEZWJ1Z0xvZ2dpbmcpIHsKICAgICAgICBfbG9nZ2VyLmQoJ/CflI0gQW5hbHl0aWNzIGRhdGEgcmVzZXQnKTsKICAgICAgfQogICAgfSBjYXRjaCAoZSwgcykgewogICAgICBfbG9nZ2VyLmUoJ0ZhaWxlZCB0byByZXNldCBhbmFseXRpY3MgZGF0YScsIGUsIHMpOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPHZvaWQ+IHNldEFuYWx5dGljc0NvbGxlY3Rpb25FbmFibGVkKGJvb2wgZW5hYmxlZCkgYXN5bmMgewogICAgdHJ5IHsKICAgICAgYXdhaXQgX2FuYWx5dGljcy5zZXRBbmFseXRpY3NDb2xsZWN0aW9uRW5hYmxlZChlbmFibGVkKTsKCiAgICAgIGlmIChfY29uZmlnLmVuYWJsZURlYnVnTG9nZ2luZykgewogICAgICAgIF9sb2dnZXIuZCgKICAgICAgICAgICfwn5SNIEFuYWx5dGljcyBjb2xsZWN0aW9uICR7ZW5hYmxlZCA/ICdlbmFibGVkJyA6ICdkaXNhYmxlZCd9JywKICAgICAgICApOwogICAgICB9CiAgICB9IGNhdGNoIChlLCBzKSB7CiAgICAgIF9sb2dnZXIuZSgnRmFpbGVkIHRvIHNldCBhbmFseXRpY3MgY29sbGVjdGlvbiBlbmFibGVkOiAkZW5hYmxlZCcsIGUsIHMpOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPHZvaWQ+IGxvZ1NjcmVlblZpZXcoewogICAgcmVxdWlyZWQgU3RyaW5nIHNjcmVlbk5hbWUsCiAgICBTdHJpbmc/IHNjcmVlbkNsYXNzLAogICAgTWFwPFN0cmluZywgZHluYW1pYz4/IHBhcmFtZXRlcnMsCiAgfSkgYXN5bmMgewogICAgZmluYWwgZXZlbnRQYXJhbWV0ZXJzID0gPFN0cmluZywgZHluYW1pYz57CiAgICAgIFByZWRlZmluZWRQYXJhbWV0ZXJzLnNjcmVlbk5hbWU6IHNjcmVlbk5hbWUsCiAgICAgIGlmIChzY3JlZW5DbGFzcyAhPSBudWxsKSBQcmVkZWZpbmVkUGFyYW1ldGVycy5zY3JlZW5DbGFzczogc2NyZWVuQ2xhc3MsCiAgICAgIC4uLj9wYXJhbWV0ZXJzLAogICAgfTsKCiAgICBhd2FpdCBsb2dFdmVudCgKICAgICAgbmFtZTogUHJlZGVmaW5lZEV2ZW50cy5zY3JlZW5WaWV3LAogICAgICBwYXJhbWV0ZXJzOiBldmVudFBhcmFtZXRlcnMsCiAgICApOwogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPHZvaWQ+IGxvZ0FwcE9wZW4oe01hcDxTdHJpbmcsIGR5bmFtaWM+PyBwYXJhbWV0ZXJzfSkgYXN5bmMgewogICAgYXdhaXQgbG9nRXZlbnQobmFtZTogUHJlZGVmaW5lZEV2ZW50cy5hcHBPcGVuLCBwYXJhbWV0ZXJzOiBwYXJhbWV0ZXJzKTsKICB9CgogIEBvdmVycmlkZQogIEZ1dHVyZTx2b2lkPiBsb2dMb2dpbih7CiAgICBTdHJpbmc/IGxvZ2luTWV0aG9kLAogICAgTWFwPFN0cmluZywgZHluYW1pYz4/IHBhcmFtZXRlcnMsCiAgfSkgYXN5bmMgewogICAgZmluYWwgZXZlbnRQYXJhbWV0ZXJzID0gPFN0cmluZywgZHluYW1pYz57CiAgICAgIGlmIChsb2dpbk1ldGhvZCAhPSBudWxsKSBQcmVkZWZpbmVkUGFyYW1ldGVycy5tZXRob2Q6IGxvZ2luTWV0aG9kLAogICAgICAuLi4/cGFyYW1ldGVycywKICAgIH07CgogICAgYXdhaXQgbG9nRXZlbnQobmFtZTogUHJlZGVmaW5lZEV2ZW50cy5sb2dpbiwgcGFyYW1ldGVyczogZXZlbnRQYXJhbWV0ZXJzKTsKICB9CgogIEBvdmVycmlkZQogIEZ1dHVyZTx2b2lkPiBsb2dTaWduVXAoewogICAgU3RyaW5nPyBzaWduVXBNZXRob2QsCiAgICBNYXA8U3RyaW5nLCBkeW5hbWljPj8gcGFyYW1ldGVycywKICB9KSBhc3luYyB7CiAgICBmaW5hbCBldmVudFBhcmFtZXRlcnMgPSA8U3RyaW5nLCBkeW5hbWljPnsKICAgICAgaWYgKHNpZ25VcE1ldGhvZCAhPSBudWxsKSBQcmVkZWZpbmVkUGFyYW1ldGVycy5tZXRob2Q6IHNpZ25VcE1ldGhvZCwKICAgICAgLi4uP3BhcmFtZXRlcnMsCiAgICB9OwoKICAgIGF3YWl0IGxvZ0V2ZW50KG5hbWU6IFByZWRlZmluZWRFdmVudHMuc2lnblVwLCBwYXJhbWV0ZXJzOiBldmVudFBhcmFtZXRlcnMpOwogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPHZvaWQ+IGxvZ1B1cmNoYXNlKHsKICAgIHJlcXVpcmVkIFN0cmluZyBjdXJyZW5jeSwKICAgIHJlcXVpcmVkIGRvdWJsZSB2YWx1ZSwKICAgIE1hcDxTdHJpbmcsIGR5bmFtaWM+PyBwYXJhbWV0ZXJzLAogIH0pIGFzeW5jIHsKICAgIGZpbmFsIGV2ZW50UGFyYW1ldGVycyA9IDxTdHJpbmcsIGR5bmFtaWM+ewogICAgICBQcmVkZWZpbmVkUGFyYW1ldGVycy5jdXJyZW5jeTogY3VycmVuY3ksCiAgICAgIFByZWRlZmluZWRQYXJhbWV0ZXJzLnZhbHVlOiB2YWx1ZSwKICAgICAgLi4uP3BhcmFtZXRlcnMsCiAgICB9OwoKICAgIGF3YWl0IGxvZ0V2ZW50KAogICAgICBuYW1lOiBQcmVkZWZpbmVkRXZlbnRzLnB1cmNoYXNlLAogICAgICBwYXJhbWV0ZXJzOiBldmVudFBhcmFtZXRlcnMsCiAgICApOwogIH0KCiAgQG92ZXJyaWRlCiAgdm9pZCBkaXNwb3NlKCkgewogICAgLy8gRmlyZWJhc2UgQW5hbHl0aWNzIGRvZXNuJ3QgbmVlZCBleHBsaWNpdCBkaXNwb3NhbAogICAgaWYgKF9jb25maWcuZW5hYmxlRGVidWdMb2dnaW5nKSB7CiAgICAgIF9sb2dnZXIuZCgn8J+UjSBGaXJlYmFzZSBBbmFseXRpY3MgY2xpZW50IGRpc3Bvc2VkJyk7CiAgICB9CiAgfQp9Cg==", + "aW1wb3J0ICdwYWNrYWdlOmFuYWx5dGljcy9zcmMvY2xpZW50L2FuYWx5dGljc19jbGllbnQuZGFydCc7CmltcG9ydCAncGFja2FnZTphbmFseXRpY3Mvc3JjL2NvbmZpZy9hbmFseXRpY3NfY29uZmlnLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6YW5hbHl0aWNzL3NyYy9tb2RlbHMvYW5hbHl0aWNzX2V2ZW50LmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Y29yZS9jb3JlLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZmlyZWJhc2VfYW5hbHl0aWNzL2ZpcmViYXNlX2FuYWx5dGljcy5kYXJ0JzsKCmNsYXNzIEZpcmViYXNlQW5hbHl0aWNzQ2xpZW50IGltcGxlbWVudHMgQW5hbHl0aWNzQ2xpZW50IHsKICBGaXJlYmFzZUFuYWx5dGljc0NsaWVudCgKICAgIHRoaXMuX2NvbmZpZywgewogICAgcmVxdWlyZWQgRmlyZWJhc2VBbmFseXRpY3MgYW5hbHl0aWNzLAogICAgcmVxdWlyZWQgTG9nZ2VyIGxvZ2dlciwKICB9KSA6IF9hbmFseXRpY3MgPSBhbmFseXRpY3MsCiAgICAgICBfbG9nZ2VyID0gbG9nZ2VyLAogICAgICAgX2VuYWJsZWQgPSBfY29uZmlnLmVuYWJsZUFuYWx5dGljczsKCiAgZmluYWwgQW5hbHl0aWNzQ29uZmlnIF9jb25maWc7CiAgZmluYWwgRmlyZWJhc2VBbmFseXRpY3MgX2FuYWx5dGljczsKICBmaW5hbCBMb2dnZXIgX2xvZ2dlcjsKICBib29sIF9lbmFibGVkOwoKICBGdXR1cmU8dm9pZD4gaW5pdGlhbGl6ZSgpIGFzeW5jIHsKICAgIGF3YWl0IF9hbmFseXRpY3Muc2V0QW5hbHl0aWNzQ29sbGVjdGlvbkVuYWJsZWQoX2VuYWJsZWQpOwoKICAgIGlmIChfY29uZmlnLnVzZXJJZCAhPSBudWxsKSB7CiAgICAgIGF3YWl0IF9hbmFseXRpY3Muc2V0VXNlcklkKGlkOiBfY29uZmlnLnVzZXJJZCk7CiAgICAgIF9sb2dnZXIuZCgn8J+UjSBBbmFseXRpY3MgdXNlciBJRCBzZXQ6ICR7X2NvbmZpZy51c2VySWR9Jyk7CiAgICB9CgogICAgaWYgKF9jb25maWcuZGVmYXVsdFVzZXJQcm9wZXJ0aWVzICE9IG51bGwpIHsKICAgICAgZm9yIChmaW5hbCBlbnRyeSBpbiBfY29uZmlnLmRlZmF1bHRVc2VyUHJvcGVydGllcyEuZW50cmllcykgewogICAgICAgIGF3YWl0IF9hbmFseXRpY3Muc2V0VXNlclByb3BlcnR5KG5hbWU6IGVudHJ5LmtleSwgdmFsdWU6IGVudHJ5LnZhbHVlKTsKICAgICAgfQogICAgICBfbG9nZ2VyLmQoJ/CflI0gQW5hbHl0aWNzIGRlZmF1bHQgdXNlciBwcm9wZXJ0aWVzIHNldCcpOwogICAgfQoKICAgIGlmIChfY29uZmlnLmVuYWJsZURlYnVnTG9nZ2luZykgewogICAgICBfbG9nZ2VyLmQoJ/CflI0gRmlyZWJhc2UgQW5hbHl0aWNzIGluaXRpYWxpemVkIHdpdGggZGVidWcgbG9nZ2luZyBlbmFibGVkJyk7CiAgICB9IGVsc2UgewogICAgICBfbG9nZ2VyLmkoJ/CflI0gRmlyZWJhc2UgQW5hbHl0aWNzIGluaXRpYWxpemVkJyk7CiAgICB9CiAgfQoKICBAb3ZlcnJpZGUKICBGdXR1cmU8dm9pZD4gbG9nRXZlbnQoewogICAgcmVxdWlyZWQgU3RyaW5nIG5hbWUsCiAgICBNYXA8U3RyaW5nLCBkeW5hbWljPj8gcGFyYW1ldGVycywKICB9KSBhc3luYyB7CiAgICB0cnkgewogICAgICBpZiAoIV9lbmFibGVkKSB7CiAgICAgICAgaWYgKF9jb25maWcuZW5hYmxlRGVidWdMb2dnaW5nKSB7CiAgICAgICAgICBfbG9nZ2VyLmQoJ/CflI0gQW5hbHl0aWNzIGRpc2FibGVkLCBza2lwcGluZyBldmVudDogJG5hbWUnKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuOwogICAgICB9CgogICAgICBhd2FpdCBfYW5hbHl0aWNzLmxvZ0V2ZW50KAogICAgICAgIG5hbWU6IG5hbWUsCiAgICAgICAgcGFyYW1ldGVyczogcGFyYW1ldGVycyA9PSBudWxsCiAgICAgICAgICAgID8gbnVsbAogICAgICAgICAgICA6IHsKICAgICAgICAgICAgICAgIGZvciAoZmluYWwgZW50cnkgaW4gcGFyYW1ldGVycy5lbnRyaWVzKQogICAgICAgICAgICAgICAgICBpZiAoZW50cnkudmFsdWUgIT0gbnVsbCkgZW50cnkua2V5OiBlbnRyeS52YWx1ZSBhcyBPYmplY3QsCiAgICAgICAgICAgICAgfSwKICAgICAgKTsKCiAgICAgIGlmIChfY29uZmlnLmVuYWJsZURlYnVnTG9nZ2luZykgewogICAgICAgIF9sb2dnZXIuZCgKICAgICAgICAgICfwn5SNIEFuYWx5dGljcyBldmVudCBsb2dnZWQ6ICRuYW1lIHdpdGggcGFyYW1ldGVyczogJHBhcmFtZXRlcnMnLAogICAgICAgICk7CiAgICAgIH0KICAgIH0gY2F0Y2ggKGUsIHMpIHsKICAgICAgX2xvZ2dlci5lKCdGYWlsZWQgdG8gbG9nIGFuYWx5dGljcyBldmVudDogJG5hbWUnLCBlLCBzKTsKICAgIH0KICB9CgogIEBvdmVycmlkZQogIEZ1dHVyZTx2b2lkPiBsb2dDdXN0b21FdmVudChBbmFseXRpY3NFdmVudCBldmVudCkgYXN5bmMgewogICAgYXdhaXQgbG9nRXZlbnQobmFtZTogZXZlbnQubmFtZSwgcGFyYW1ldGVyczogZXZlbnQucGFyYW1ldGVycyk7CiAgfQoKICBAb3ZlcnJpZGUKICBGdXR1cmU8dm9pZD4gc2V0VXNlcklkKFN0cmluZz8gdXNlcklkKSBhc3luYyB7CiAgICB0cnkgewogICAgICBhd2FpdCBfYW5hbHl0aWNzLnNldFVzZXJJZChpZDogdXNlcklkKTsKCiAgICAgIGlmIChfY29uZmlnLmVuYWJsZURlYnVnTG9nZ2luZykgewogICAgICAgIF9sb2dnZXIuZCgn8J+UjSBBbmFseXRpY3MgdXNlciBJRCBzZXQ6ICR1c2VySWQnKTsKICAgICAgfQogICAgfSBjYXRjaCAoZSwgcykgewogICAgICBfbG9nZ2VyLmUoJ0ZhaWxlZCB0byBzZXQgYW5hbHl0aWNzIHVzZXIgSUQ6ICR1c2VySWQnLCBlLCBzKTsKICAgIH0KICB9CgogIEBvdmVycmlkZQogIEZ1dHVyZTx2b2lkPiBzZXRVc2VyUHJvcGVydHkoewogICAgcmVxdWlyZWQgU3RyaW5nIG5hbWUsCiAgICByZXF1aXJlZCBTdHJpbmc/IHZhbHVlLAogIH0pIGFzeW5jIHsKICAgIHRyeSB7CiAgICAgIGF3YWl0IF9hbmFseXRpY3Muc2V0VXNlclByb3BlcnR5KG5hbWU6IG5hbWUsIHZhbHVlOiB2YWx1ZSk7CgogICAgICBpZiAoX2NvbmZpZy5lbmFibGVEZWJ1Z0xvZ2dpbmcpIHsKICAgICAgICBfbG9nZ2VyLmQoJ/CflI0gQW5hbHl0aWNzIHVzZXIgcHJvcGVydHkgc2V0OiAkbmFtZSA9ICR2YWx1ZScpOwogICAgICB9CiAgICB9IGNhdGNoIChlLCBzKSB7CiAgICAgIF9sb2dnZXIuZSgnRmFpbGVkIHRvIHNldCBhbmFseXRpY3MgdXNlciBwcm9wZXJ0eTogJG5hbWUnLCBlLCBzKTsKICAgIH0KICB9CgogIEBvdmVycmlkZQogIEZ1dHVyZTx2b2lkPiByZXNldEFuYWx5dGljc0RhdGEoKSBhc3luYyB7CiAgICB0cnkgewogICAgICBhd2FpdCBfYW5hbHl0aWNzLnJlc2V0QW5hbHl0aWNzRGF0YSgpOwoKICAgICAgaWYgKF9jb25maWcuZW5hYmxlRGVidWdMb2dnaW5nKSB7CiAgICAgICAgX2xvZ2dlci5kKCfwn5SNIEFuYWx5dGljcyBkYXRhIHJlc2V0Jyk7CiAgICAgIH0KICAgIH0gY2F0Y2ggKGUsIHMpIHsKICAgICAgX2xvZ2dlci5lKCdGYWlsZWQgdG8gcmVzZXQgYW5hbHl0aWNzIGRhdGEnLCBlLCBzKTsKICAgIH0KICB9CgogIEBvdmVycmlkZQogIEZ1dHVyZTx2b2lkPiBzZXRBbmFseXRpY3NDb2xsZWN0aW9uRW5hYmxlZChib29sIGVuYWJsZWQpIGFzeW5jIHsKICAgIHRyeSB7CiAgICAgIGF3YWl0IF9hbmFseXRpY3Muc2V0QW5hbHl0aWNzQ29sbGVjdGlvbkVuYWJsZWQoZW5hYmxlZCk7CiAgICAgIF9lbmFibGVkID0gZW5hYmxlZDsKCiAgICAgIGlmIChfY29uZmlnLmVuYWJsZURlYnVnTG9nZ2luZykgewogICAgICAgIF9sb2dnZXIuZCgKICAgICAgICAgICfwn5SNIEFuYWx5dGljcyBjb2xsZWN0aW9uICR7ZW5hYmxlZCA/ICdlbmFibGVkJyA6ICdkaXNhYmxlZCd9JywKICAgICAgICApOwogICAgICB9CiAgICB9IGNhdGNoIChlLCBzKSB7CiAgICAgIF9sb2dnZXIuZSgnRmFpbGVkIHRvIHNldCBhbmFseXRpY3MgY29sbGVjdGlvbiBlbmFibGVkOiAkZW5hYmxlZCcsIGUsIHMpOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPHZvaWQ+IGxvZ1NjcmVlblZpZXcoewogICAgcmVxdWlyZWQgU3RyaW5nIHNjcmVlbk5hbWUsCiAgICBTdHJpbmc/IHNjcmVlbkNsYXNzLAogICAgTWFwPFN0cmluZywgZHluYW1pYz4/IHBhcmFtZXRlcnMsCiAgfSkgYXN5bmMgewogICAgZmluYWwgZXZlbnRQYXJhbWV0ZXJzID0gPFN0cmluZywgZHluYW1pYz57CiAgICAgIFByZWRlZmluZWRQYXJhbWV0ZXJzLnNjcmVlbk5hbWU6IHNjcmVlbk5hbWUsCiAgICAgIGlmIChzY3JlZW5DbGFzcyAhPSBudWxsKSBQcmVkZWZpbmVkUGFyYW1ldGVycy5zY3JlZW5DbGFzczogc2NyZWVuQ2xhc3MsCiAgICAgIC4uLj9wYXJhbWV0ZXJzLAogICAgfTsKCiAgICBhd2FpdCBsb2dFdmVudCgKICAgICAgbmFtZTogUHJlZGVmaW5lZEV2ZW50cy5zY3JlZW5WaWV3LAogICAgICBwYXJhbWV0ZXJzOiBldmVudFBhcmFtZXRlcnMsCiAgICApOwogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPHZvaWQ+IGxvZ0FwcE9wZW4oe01hcDxTdHJpbmcsIGR5bmFtaWM+PyBwYXJhbWV0ZXJzfSkgYXN5bmMgewogICAgYXdhaXQgbG9nRXZlbnQobmFtZTogUHJlZGVmaW5lZEV2ZW50cy5hcHBPcGVuLCBwYXJhbWV0ZXJzOiBwYXJhbWV0ZXJzKTsKICB9CgogIEBvdmVycmlkZQogIEZ1dHVyZTx2b2lkPiBsb2dMb2dpbih7CiAgICBTdHJpbmc/IGxvZ2luTWV0aG9kLAogICAgTWFwPFN0cmluZywgZHluYW1pYz4/IHBhcmFtZXRlcnMsCiAgfSkgYXN5bmMgewogICAgZmluYWwgZXZlbnRQYXJhbWV0ZXJzID0gPFN0cmluZywgZHluYW1pYz57CiAgICAgIGlmIChsb2dpbk1ldGhvZCAhPSBudWxsKSBQcmVkZWZpbmVkUGFyYW1ldGVycy5tZXRob2Q6IGxvZ2luTWV0aG9kLAogICAgICAuLi4/cGFyYW1ldGVycywKICAgIH07CgogICAgYXdhaXQgbG9nRXZlbnQobmFtZTogUHJlZGVmaW5lZEV2ZW50cy5sb2dpbiwgcGFyYW1ldGVyczogZXZlbnRQYXJhbWV0ZXJzKTsKICB9CgogIEBvdmVycmlkZQogIEZ1dHVyZTx2b2lkPiBsb2dTaWduVXAoewogICAgU3RyaW5nPyBzaWduVXBNZXRob2QsCiAgICBNYXA8U3RyaW5nLCBkeW5hbWljPj8gcGFyYW1ldGVycywKICB9KSBhc3luYyB7CiAgICBmaW5hbCBldmVudFBhcmFtZXRlcnMgPSA8U3RyaW5nLCBkeW5hbWljPnsKICAgICAgaWYgKHNpZ25VcE1ldGhvZCAhPSBudWxsKSBQcmVkZWZpbmVkUGFyYW1ldGVycy5tZXRob2Q6IHNpZ25VcE1ldGhvZCwKICAgICAgLi4uP3BhcmFtZXRlcnMsCiAgICB9OwoKICAgIGF3YWl0IGxvZ0V2ZW50KG5hbWU6IFByZWRlZmluZWRFdmVudHMuc2lnblVwLCBwYXJhbWV0ZXJzOiBldmVudFBhcmFtZXRlcnMpOwogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPHZvaWQ+IGxvZ1B1cmNoYXNlKHsKICAgIHJlcXVpcmVkIFN0cmluZyBjdXJyZW5jeSwKICAgIHJlcXVpcmVkIGRvdWJsZSB2YWx1ZSwKICAgIE1hcDxTdHJpbmcsIGR5bmFtaWM+PyBwYXJhbWV0ZXJzLAogIH0pIGFzeW5jIHsKICAgIGZpbmFsIGV2ZW50UGFyYW1ldGVycyA9IDxTdHJpbmcsIGR5bmFtaWM+ewogICAgICBQcmVkZWZpbmVkUGFyYW1ldGVycy5jdXJyZW5jeTogY3VycmVuY3ksCiAgICAgIFByZWRlZmluZWRQYXJhbWV0ZXJzLnZhbHVlOiB2YWx1ZSwKICAgICAgLi4uP3BhcmFtZXRlcnMsCiAgICB9OwoKICAgIGF3YWl0IGxvZ0V2ZW50KAogICAgICBuYW1lOiBQcmVkZWZpbmVkRXZlbnRzLnB1cmNoYXNlLAogICAgICBwYXJhbWV0ZXJzOiBldmVudFBhcmFtZXRlcnMsCiAgICApOwogIH0KCiAgQG92ZXJyaWRlCiAgdm9pZCBkaXNwb3NlKCkgewogICAgLy8gRmlyZWJhc2UgQW5hbHl0aWNzIGRvZXNuJ3QgbmVlZCBleHBsaWNpdCBkaXNwb3NhbAogICAgaWYgKF9jb25maWcuZW5hYmxlRGVidWdMb2dnaW5nKSB7CiAgICAgIF9sb2dnZXIuZCgn8J+UjSBGaXJlYmFzZSBBbmFseXRpY3MgY2xpZW50IGRpc3Bvc2VkJyk7CiAgICB9CiAgfQp9Cg==", "type": "text" }, { @@ -824,14 +932,14 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "path": "{{ name.snakeCase() }}/packages/{{analytics_dir}}/lib/src/models/analytics_event.dart", "data": - "Y2xhc3MgQW5hbHl0aWNzRXZlbnQgewogIGNvbnN0IEFuYWx5dGljc0V2ZW50KHtyZXF1aXJlZCB0aGlzLm5hbWUsIHRoaXMucGFyYW1ldGVyc30pOwoKICBmaW5hbCBTdHJpbmcgbmFtZTsKICBmaW5hbCBNYXA8U3RyaW5nLCBkeW5hbWljPj8gcGFyYW1ldGVyczsKCiAgTWFwPFN0cmluZywgZHluYW1pYz4gdG9NYXAoKSB7CiAgICByZXR1cm4geyduYW1lJzogbmFtZSwgaWYgKHBhcmFtZXRlcnMgIT0gbnVsbCkgJ3BhcmFtZXRlcnMnOiBwYXJhbWV0ZXJzfTsKICB9CgogIEBvdmVycmlkZQogIFN0cmluZyB0b1N0cmluZygpID0+ICdBbmFseXRpY3NFdmVudChuYW1lOiAkbmFtZSwgcGFyYW1ldGVyczogJHBhcmFtZXRlcnMpJzsKCiAgQG92ZXJyaWRlCiAgYm9vbCBvcGVyYXRvciA9PShPYmplY3Qgb3RoZXIpIHsKICAgIGlmIChpZGVudGljYWwodGhpcywgb3RoZXIpKSByZXR1cm4gdHJ1ZTsKICAgIHJldHVybiBvdGhlciBpcyBBbmFseXRpY3NFdmVudCAmJgogICAgICAgIG90aGVyLm5hbWUgPT0gbmFtZSAmJgogICAgICAgIF9tYXBFcXVhbHMob3RoZXIucGFyYW1ldGVycywgcGFyYW1ldGVycyk7CiAgfQoKICBAb3ZlcnJpZGUKICBpbnQgZ2V0IGhhc2hDb2RlID0+IG5hbWUuaGFzaENvZGUgXiBwYXJhbWV0ZXJzLmhhc2hDb2RlOwoKICBib29sIF9tYXBFcXVhbHMoTWFwPFN0cmluZywgZHluYW1pYz4/IGEsIE1hcDxTdHJpbmcsIGR5bmFtaWM+PyBiKSB7CiAgICBpZiAoYSA9PSBudWxsKSByZXR1cm4gYiA9PSBudWxsOwogICAgaWYgKGIgPT0gbnVsbCB8fCBhLmxlbmd0aCAhPSBiLmxlbmd0aCkgcmV0dXJuIGZhbHNlOwogICAgZm9yIChmaW5hbCBrZXkgaW4gYS5rZXlzKSB7CiAgICAgIGlmICghYi5jb250YWluc0tleShrZXkpIHx8IGFba2V5XSAhPSBiW2tleV0pIHJldHVybiBmYWxzZTsKICAgIH0KICAgIHJldHVybiB0cnVlOwogIH0KfQoKY2xhc3MgUHJlZGVmaW5lZEV2ZW50cyB7CiAgc3RhdGljIGNvbnN0IFN0cmluZyBhcHBPcGVuID0gJ2FwcF9vcGVuJzsKICBzdGF0aWMgY29uc3QgU3RyaW5nIGxvZ2luID0gJ2xvZ2luJzsKICBzdGF0aWMgY29uc3QgU3RyaW5nIHNpZ25VcCA9ICdzaWduX3VwJzsKICBzdGF0aWMgY29uc3QgU3RyaW5nIHNjcmVlblZpZXcgPSAnc2NyZWVuX3ZpZXcnOwogIHN0YXRpYyBjb25zdCBTdHJpbmcgcHVyY2hhc2UgPSAncHVyY2hhc2UnOwogIHN0YXRpYyBjb25zdCBTdHJpbmcgc2VsZWN0Q29udGVudCA9ICdzZWxlY3RfY29udGVudCc7CiAgc3RhdGljIGNvbnN0IFN0cmluZyBzaGFyZSA9ICdzaGFyZSc7CiAgc3RhdGljIGNvbnN0IFN0cmluZyBzZWFyY2ggPSAnc2VhcmNoJzsKICBzdGF0aWMgY29uc3QgU3RyaW5nIGJlZ2luQ2hlY2tvdXQgPSAnYmVnaW5fY2hlY2tvdXQnOwogIHN0YXRpYyBjb25zdCBTdHJpbmcgYWRkVG9DYXJ0ID0gJ2FkZF90b19jYXJ0JzsKICBzdGF0aWMgY29uc3QgU3RyaW5nIHJlbW92ZUZyb21DYXJ0ID0gJ3JlbW92ZV9mcm9tX2NhcnQnOwogIHN0YXRpYyBjb25zdCBTdHJpbmcgdmlld0l0ZW0gPSAndmlld19pdGVtJzsKICBzdGF0aWMgY29uc3QgU3RyaW5nIHZpZXdJdGVtTGlzdCA9ICd2aWV3X2l0ZW1fbGlzdCc7Cn0KCmNsYXNzIFByZWRlZmluZWRQYXJhbWV0ZXJzIHsKICBzdGF0aWMgY29uc3QgU3RyaW5nIHNjcmVlbk5hbWUgPSAnc2NyZWVuX25hbWUnOwogIHN0YXRpYyBjb25zdCBTdHJpbmcgc2NyZWVuQ2xhc3MgPSAnc2NyZWVuX2NsYXNzJzsKICBzdGF0aWMgY29uc3QgU3RyaW5nIG1ldGhvZCA9ICdtZXRob2QnOwogIHN0YXRpYyBjb25zdCBTdHJpbmcgY3VycmVuY3kgPSAnY3VycmVuY3knOwogIHN0YXRpYyBjb25zdCBTdHJpbmcgdmFsdWUgPSAndmFsdWUnOwogIHN0YXRpYyBjb25zdCBTdHJpbmcgaXRlbUlkID0gJ2l0ZW1faWQnOwogIHN0YXRpYyBjb25zdCBTdHJpbmcgaXRlbU5hbWUgPSAnaXRlbV9uYW1lJzsKICBzdGF0aWMgY29uc3QgU3RyaW5nIGl0ZW1DYXRlZ29yeSA9ICdpdGVtX2NhdGVnb3J5JzsKICBzdGF0aWMgY29uc3QgU3RyaW5nIGNvbnRlbnRUeXBlID0gJ2NvbnRlbnRfdHlwZSc7CiAgc3RhdGljIGNvbnN0IFN0cmluZyBzZWFyY2hUZXJtID0gJ3NlYXJjaF90ZXJtJzsKICBzdGF0aWMgY29uc3QgU3RyaW5nIHVzZXJJZCA9ICd1c2VyX2lkJzsKfQo=", + "Y2xhc3MgQW5hbHl0aWNzRXZlbnQgewogIGNvbnN0IEFuYWx5dGljc0V2ZW50KHtyZXF1aXJlZCB0aGlzLm5hbWUsIHRoaXMucGFyYW1ldGVyc30pOwoKICBmaW5hbCBTdHJpbmcgbmFtZTsKICBmaW5hbCBNYXA8U3RyaW5nLCBkeW5hbWljPj8gcGFyYW1ldGVyczsKCiAgTWFwPFN0cmluZywgZHluYW1pYz4gdG9NYXAoKSB7CiAgICByZXR1cm4geyduYW1lJzogbmFtZSwgaWYgKHBhcmFtZXRlcnMgIT0gbnVsbCkgJ3BhcmFtZXRlcnMnOiBwYXJhbWV0ZXJzfTsKICB9CgogIEBvdmVycmlkZQogIFN0cmluZyB0b1N0cmluZygpID0+ICdBbmFseXRpY3NFdmVudChuYW1lOiAkbmFtZSwgcGFyYW1ldGVyczogJHBhcmFtZXRlcnMpJzsKCiAgQG92ZXJyaWRlCiAgYm9vbCBvcGVyYXRvciA9PShPYmplY3Qgb3RoZXIpIHsKICAgIGlmIChpZGVudGljYWwodGhpcywgb3RoZXIpKSByZXR1cm4gdHJ1ZTsKICAgIHJldHVybiBvdGhlciBpcyBBbmFseXRpY3NFdmVudCAmJgogICAgICAgIG90aGVyLm5hbWUgPT0gbmFtZSAmJgogICAgICAgIF9tYXBFcXVhbHMob3RoZXIucGFyYW1ldGVycywgcGFyYW1ldGVycyk7CiAgfQoKICBAb3ZlcnJpZGUKICBpbnQgZ2V0IGhhc2hDb2RlID0+IE9iamVjdC5oYXNoKAogICAgbmFtZSwKICAgIHBhcmFtZXRlcnMgPT0gbnVsbAogICAgICAgID8gbnVsbAogICAgICAgIDogT2JqZWN0Lmhhc2hBbGxVbm9yZGVyZWQoCiAgICAgICAgICAgIHBhcmFtZXRlcnMhLmVudHJpZXMubWFwKChlKSA9PiBPYmplY3QuaGFzaChlLmtleSwgZS52YWx1ZSkpLAogICAgICAgICAgKSwKICApOwoKICBib29sIF9tYXBFcXVhbHMoTWFwPFN0cmluZywgZHluYW1pYz4/IGEsIE1hcDxTdHJpbmcsIGR5bmFtaWM+PyBiKSB7CiAgICBpZiAoYSA9PSBudWxsKSByZXR1cm4gYiA9PSBudWxsOwogICAgaWYgKGIgPT0gbnVsbCB8fCBhLmxlbmd0aCAhPSBiLmxlbmd0aCkgcmV0dXJuIGZhbHNlOwogICAgZm9yIChmaW5hbCBrZXkgaW4gYS5rZXlzKSB7CiAgICAgIGlmICghYi5jb250YWluc0tleShrZXkpIHx8IGFba2V5XSAhPSBiW2tleV0pIHJldHVybiBmYWxzZTsKICAgIH0KICAgIHJldHVybiB0cnVlOwogIH0KfQoKY2xhc3MgUHJlZGVmaW5lZEV2ZW50cyB7CiAgc3RhdGljIGNvbnN0IFN0cmluZyBhcHBPcGVuID0gJ2FwcF9vcGVuJzsKICBzdGF0aWMgY29uc3QgU3RyaW5nIGxvZ2luID0gJ2xvZ2luJzsKICBzdGF0aWMgY29uc3QgU3RyaW5nIHNpZ25VcCA9ICdzaWduX3VwJzsKICBzdGF0aWMgY29uc3QgU3RyaW5nIHNjcmVlblZpZXcgPSAnc2NyZWVuX3ZpZXcnOwogIHN0YXRpYyBjb25zdCBTdHJpbmcgcHVyY2hhc2UgPSAncHVyY2hhc2UnOwogIHN0YXRpYyBjb25zdCBTdHJpbmcgc2VsZWN0Q29udGVudCA9ICdzZWxlY3RfY29udGVudCc7CiAgc3RhdGljIGNvbnN0IFN0cmluZyBzaGFyZSA9ICdzaGFyZSc7CiAgc3RhdGljIGNvbnN0IFN0cmluZyBzZWFyY2ggPSAnc2VhcmNoJzsKICBzdGF0aWMgY29uc3QgU3RyaW5nIGJlZ2luQ2hlY2tvdXQgPSAnYmVnaW5fY2hlY2tvdXQnOwogIHN0YXRpYyBjb25zdCBTdHJpbmcgYWRkVG9DYXJ0ID0gJ2FkZF90b19jYXJ0JzsKICBzdGF0aWMgY29uc3QgU3RyaW5nIHJlbW92ZUZyb21DYXJ0ID0gJ3JlbW92ZV9mcm9tX2NhcnQnOwogIHN0YXRpYyBjb25zdCBTdHJpbmcgdmlld0l0ZW0gPSAndmlld19pdGVtJzsKICBzdGF0aWMgY29uc3QgU3RyaW5nIHZpZXdJdGVtTGlzdCA9ICd2aWV3X2l0ZW1fbGlzdCc7Cn0KCmNsYXNzIFByZWRlZmluZWRQYXJhbWV0ZXJzIHsKICBzdGF0aWMgY29uc3QgU3RyaW5nIHNjcmVlbk5hbWUgPSAnc2NyZWVuX25hbWUnOwogIHN0YXRpYyBjb25zdCBTdHJpbmcgc2NyZWVuQ2xhc3MgPSAnc2NyZWVuX2NsYXNzJzsKICBzdGF0aWMgY29uc3QgU3RyaW5nIG1ldGhvZCA9ICdtZXRob2QnOwogIHN0YXRpYyBjb25zdCBTdHJpbmcgY3VycmVuY3kgPSAnY3VycmVuY3knOwogIHN0YXRpYyBjb25zdCBTdHJpbmcgdmFsdWUgPSAndmFsdWUnOwogIHN0YXRpYyBjb25zdCBTdHJpbmcgaXRlbUlkID0gJ2l0ZW1faWQnOwogIHN0YXRpYyBjb25zdCBTdHJpbmcgaXRlbU5hbWUgPSAnaXRlbV9uYW1lJzsKICBzdGF0aWMgY29uc3QgU3RyaW5nIGl0ZW1DYXRlZ29yeSA9ICdpdGVtX2NhdGVnb3J5JzsKICBzdGF0aWMgY29uc3QgU3RyaW5nIGNvbnRlbnRUeXBlID0gJ2NvbnRlbnRfdHlwZSc7CiAgc3RhdGljIGNvbnN0IFN0cmluZyBzZWFyY2hUZXJtID0gJ3NlYXJjaF90ZXJtJzsKICBzdGF0aWMgY29uc3QgU3RyaW5nIHVzZXJJZCA9ICd1c2VyX2lkJzsKfQo=", "type": "text" }, { "path": "{{ name.snakeCase() }}/packages/{{analytics_dir}}/lib/src/models/analytics_events.dart", "data": - "Ly8vIFN0cnVjdHVyZWQgYW5hbHl0aWNzIGV2ZW50IG5hbWVzIG9yZ2FuaXplZCBieSBjYXRlZ29yeS4KLy8vCi8vLyBVc2FnZTogYEFuYWx5dGljc0V2ZW50cy51c2VyLmF1dGhlbnRpY2F0ZWRSZWRpcmVjdGAuIE5hbWluZyBldmVudHMgaGVyZQovLy8gaW5zdGVhZCBvZiBpbmxpbmUga2VlcHMgdGhlbSBkaXNjb3ZlcmFibGUgYW5kIHR5cG8tZnJlZSwgYW5kIGdpdmVzIHlvdSBvbmUKLy8vIHBsYWNlIHRvIGFkZCB0aGUgZ3JvdXBzIHlvdXIgb3duIHByb2R1Y3QgbmVlZHMuCmNsYXNzIEFuYWx5dGljc0V2ZW50cyB7CiAgQW5hbHl0aWNzRXZlbnRzLl8oKTsKCiAgLy8vIFVzZXItcmVsYXRlZCBldmVudHMKICBzdGF0aWMgY29uc3QgdXNlciA9IF9Vc2VyRXZlbnRzKCk7CgogIC8vLyBBdXRoZW50aWNhdGlvbi1yZWxhdGVkIGV2ZW50cwogIHN0YXRpYyBjb25zdCBhdXRoID0gX0F1dGhFdmVudHMoKTsKCiAgLy8vIE5hdmlnYXRpb24tcmVsYXRlZCBldmVudHMKICBzdGF0aWMgY29uc3QgbmF2aWdhdGlvbiA9IF9OYXZpZ2F0aW9uRXZlbnRzKCk7CgogIC8vLyBGZWF0dXJlIHVzYWdlIGV2ZW50cwogIHN0YXRpYyBjb25zdCBmZWF0dXJlID0gX0ZlYXR1cmVFdmVudHMoKTsKCiAgLy8vIEVycm9yIGFuZCBkZWJ1Z2dpbmcgZXZlbnRzCiAgc3RhdGljIGNvbnN0IGVycm9yID0gX0Vycm9yRXZlbnRzKCk7CgogIC8vLyBBcHAgbGlmZWN5Y2xlIGV2ZW50cwogIHN0YXRpYyBjb25zdCBhcHAgPSBfQXBwRXZlbnRzKCk7CgogIC8vLyBQcm9maWxlLXJlbGF0ZWQgZXZlbnRzCiAgc3RhdGljIGNvbnN0IHByb2ZpbGUgPSBfUHJvZmlsZUV2ZW50cygpOwp9CgpjbGFzcyBfVXNlckV2ZW50cyB7CiAgY29uc3QgX1VzZXJFdmVudHMoKTsKCiAgLy8vIFVzZXIgc3VjY2Vzc2Z1bGx5IGF1dGhlbnRpY2F0ZWQgYW5kIHJlZGlyZWN0ZWQKICBTdHJpbmcgZ2V0IGF1dGhlbnRpY2F0ZWRSZWRpcmVjdCA9PiAndXNlcl9hdXRoZW50aWNhdGVkX3JlZGlyZWN0JzsKCiAgLy8vIFVzZXIgcHJvZmlsZSB1cGRhdGVkCiAgU3RyaW5nIGdldCBwcm9maWxlVXBkYXRlZCA9PiAndXNlcl9wcm9maWxlX3VwZGF0ZWQnOwoKICAvLy8gVXNlciBwcmVmZXJlbmNlcyBjaGFuZ2VkCiAgU3RyaW5nIGdldCBwcmVmZXJlbmNlc0NoYW5nZWQgPT4gJ3VzZXJfcHJlZmVyZW5jZXNfY2hhbmdlZCc7CgogIC8vLyBVc2VyIGNvbXBsZXRlZCBvbmJvYXJkaW5nCiAgU3RyaW5nIGdldCBvbmJvYXJkaW5nQ29tcGxldGVkID0+ICd1c2VyX29uYm9hcmRpbmdfY29tcGxldGVkJzsKCiAgLy8vIFVzZXIgYWNjb3VudCBkZWxldGVkCiAgU3RyaW5nIGdldCBhY2NvdW50RGVsZXRlZCA9PiAndXNlcl9hY2NvdW50X2RlbGV0ZWQnOwp9CgpjbGFzcyBfQXV0aEV2ZW50cyB7CiAgY29uc3QgX0F1dGhFdmVudHMoKTsKCiAgLy8vIFVzZXIgc2lnbmVkIGluCiAgU3RyaW5nIGdldCBzaWduSW4gPT4gJ2F1dGhfc2lnbl9pbic7CgogIC8vLyBVc2VyIHNpZ25lZCB1cAogIFN0cmluZyBnZXQgc2lnblVwID0+ICdhdXRoX3NpZ25fdXAnOwoKICAvLy8gVXNlciBzaWduZWQgb3V0CiAgU3RyaW5nIGdldCBzaWduT3V0ID0+ICdhdXRoX3NpZ25fb3V0JzsKCiAgLy8vIFBhc3N3b3JkIHJlc2V0IHJlcXVlc3RlZAogIFN0cmluZyBnZXQgcGFzc3dvcmRSZXNldCA9PiAnYXV0aF9wYXNzd29yZF9yZXNldCc7CgogIC8vLyBBdXRoZW50aWNhdGlvbiBmYWlsZWQKICBTdHJpbmcgZ2V0IGZhaWxlZCA9PiAnYXV0aF9mYWlsZWQnOwoKICAvLy8gU29jaWFsIGF1dGhlbnRpY2F0aW9uIChHb29nbGUsIEFwcGxlLCBldGMuKQogIFN0cmluZyBnZXQgc29jaWFsTG9naW4gPT4gJ2F1dGhfc29jaWFsX2xvZ2luJzsKfQoKY2xhc3MgX05hdmlnYXRpb25FdmVudHMgewogIGNvbnN0IF9OYXZpZ2F0aW9uRXZlbnRzKCk7CgogIC8vLyBTY3JlZW4gdmlld2VkIChhdXRvbWF0aWNhbGx5IHRyYWNrZWQpCiAgU3RyaW5nIGdldCBzY3JlZW5WaWV3ID0+ICdzY3JlZW5fdmlldyc7CgogIC8vLyBUYWIgc3dpdGNoZWQgaW4gYm90dG9tIG5hdmlnYXRpb24KICBTdHJpbmcgZ2V0IHRhYlN3aXRjaGVkID0+ICduYXZpZ2F0aW9uX3RhYl9zd2l0Y2hlZCc7CgogIC8vLyBCYWNrIGJ1dHRvbiBwcmVzc2VkCiAgU3RyaW5nIGdldCBiYWNrUHJlc3NlZCA9PiAnbmF2aWdhdGlvbl9iYWNrX3ByZXNzZWQnOwoKICAvLy8gRGVlcCBsaW5rIG9wZW5lZAogIFN0cmluZyBnZXQgZGVlcExpbmtPcGVuZWQgPT4gJ25hdmlnYXRpb25fZGVlcF9saW5rX29wZW5lZCc7Cn0KCmNsYXNzIF9GZWF0dXJlRXZlbnRzIHsKICBjb25zdCBfRmVhdHVyZUV2ZW50cygpOwoKICAvLy8gRmVhdHVyZSB3YXMgdXNlZC9hY2Nlc3NlZAogIFN0cmluZyBnZXQgdXNlZCA9PiAnZmVhdHVyZV91c2VkJzsKCiAgLy8vIEZlYXR1cmUgdHV0b3JpYWwgc3RhcnRlZAogIFN0cmluZyBnZXQgdHV0b3JpYWxTdGFydGVkID0+ICdmZWF0dXJlX3R1dG9yaWFsX3N0YXJ0ZWQnOwoKICAvLy8gRmVhdHVyZSB0dXRvcmlhbCBjb21wbGV0ZWQKICBTdHJpbmcgZ2V0IHR1dG9yaWFsQ29tcGxldGVkID0+ICdmZWF0dXJlX3R1dG9yaWFsX2NvbXBsZXRlZCc7CgogIC8vLyBGZWF0dXJlIGZlZWRiYWNrIGdpdmVuCiAgU3RyaW5nIGdldCBmZWVkYmFja0dpdmVuID0+ICdmZWF0dXJlX2ZlZWRiYWNrX2dpdmVuJzsKCiAgLy8vIEJ1dHRvbiBwcmVzc2VkCiAgU3RyaW5nIGdldCBidXR0b25QcmVzc2VkID0+ICdidXR0b25fcHJlc3NlZCc7Cn0KCmNsYXNzIF9FcnJvckV2ZW50cyB7CiAgY29uc3QgX0Vycm9yRXZlbnRzKCk7CgogIC8vLyBHZW5lcmFsIGFwcCBlcnJvciBvY2N1cnJlZAogIFN0cmluZyBnZXQgYXBwRXJyb3IgPT4gJ2FwcF9lcnJvcic7CgogIC8vLyBOZXR3b3JrIGVycm9yIG9jY3VycmVkCiAgU3RyaW5nIGdldCBuZXR3b3JrRXJyb3IgPT4gJ25ldHdvcmtfZXJyb3InOwoKICAvLy8gQ3Jhc2ggb2NjdXJyZWQKICBTdHJpbmcgZ2V0IGNyYXNoID0+ICdhcHBfY3Jhc2gnOwoKICAvLy8gQVBJIGVycm9yIG9jY3VycmVkCiAgU3RyaW5nIGdldCBhcGlFcnJvciA9PiAnYXBpX2Vycm9yJzsKCiAgLy8vIFZhbGlkYXRpb24gZXJyb3IKICBTdHJpbmcgZ2V0IHZhbGlkYXRpb25FcnJvciA9PiAndmFsaWRhdGlvbl9lcnJvcic7Cn0KCmNsYXNzIF9BcHBFdmVudHMgewogIGNvbnN0IF9BcHBFdmVudHMoKTsKCiAgLy8vIEFwcCBvcGVuZWQvbGF1bmNoZWQKICBTdHJpbmcgZ2V0IG9wZW4gPT4gJ2FwcF9vcGVuJzsKCiAgLy8vIEFwcCB3ZW50IHRvIGJhY2tncm91bmQKICBTdHJpbmcgZ2V0IGJhY2tncm91bmQgPT4gJ2FwcF9iYWNrZ3JvdW5kJzsKCiAgLy8vIEFwcCBjYW1lIHRvIGZvcmVncm91bmQKICBTdHJpbmcgZ2V0IGZvcmVncm91bmQgPT4gJ2FwcF9mb3JlZ3JvdW5kJzsKCiAgLy8vIEFwcCB1cGRhdGVkIHRvIG5ldyB2ZXJzaW9uCiAgU3RyaW5nIGdldCB1cGRhdGVkID0+ICdhcHBfdXBkYXRlZCc7CgogIC8vLyBBcHAgaW5zdGFsbGVkIGZvciBmaXJzdCB0aW1lCiAgU3RyaW5nIGdldCBpbnN0YWxsZWQgPT4gJ2FwcF9pbnN0YWxsZWQnOwoKICAvLy8gQXBwIHVuaW5zdGFsbGVkCiAgU3RyaW5nIGdldCB1bmluc3RhbGxlZCA9PiAnYXBwX3VuaW5zdGFsbGVkJzsKfQoKCgpjbGFzcyBfUHJvZmlsZUV2ZW50cyB7CiAgY29uc3QgX1Byb2ZpbGVFdmVudHMoKTsKCiAgLy8vIFByb2ZpbGUgdmlld2VkCiAgU3RyaW5nIGdldCB2aWV3ZWQgPT4gJ3Byb2ZpbGVfdmlld2VkJzsKCiAgLy8vIFByb2ZpbGUgZWRpdGVkCiAgU3RyaW5nIGdldCBlZGl0ZWQgPT4gJ3Byb2ZpbGVfZWRpdGVkJzsKCiAgLy8vIFByb2ZpbGUgcGhvdG8gdXBkYXRlZAogIFN0cmluZyBnZXQgcGhvdG9VcGRhdGVkID0+ICdwcm9maWxlX3Bob3RvX3VwZGF0ZWQnOwoKICAvLy8gUHJvZmlsZSBzZXR0aW5ncyBjaGFuZ2VkCiAgU3RyaW5nIGdldCBzZXR0aW5nc0NoYW5nZWQgPT4gJ3Byb2ZpbGVfc2V0dGluZ3NfY2hhbmdlZCc7CgogIC8vLyBQcm9maWxlIHByaXZhY3kgc2V0dGluZ3MgdXBkYXRlZAogIFN0cmluZyBnZXQgcHJpdmFjeVVwZGF0ZWQgPT4gJ3Byb2ZpbGVfcHJpdmFjeV91cGRhdGVkJzsKfQo=", + "Ly8vIFN0cnVjdHVyZWQgYW5hbHl0aWNzIGV2ZW50IG5hbWVzIG9yZ2FuaXplZCBieSBjYXRlZ29yeS4KLy8vCi8vLyBVc2FnZTogYEFuYWx5dGljc0V2ZW50cy51c2VyLmF1dGhlbnRpY2F0ZWRSZWRpcmVjdGAuIE5hbWluZyBldmVudHMgaGVyZQovLy8gaW5zdGVhZCBvZiBpbmxpbmUga2VlcHMgdGhlbSBkaXNjb3ZlcmFibGUgYW5kIHR5cG8tZnJlZSwgYW5kIGdpdmVzIHlvdSBvbmUKLy8vIHBsYWNlIHRvIGFkZCB0aGUgZ3JvdXBzIHlvdXIgb3duIHByb2R1Y3QgbmVlZHMuCmFic3RyYWN0IGZpbmFsIGNsYXNzIEFuYWx5dGljc0V2ZW50cyB7CiAgLy8vIFVzZXItcmVsYXRlZCBldmVudHMKICBzdGF0aWMgY29uc3QgdXNlciA9IF9Vc2VyRXZlbnRzKCk7CgogIC8vLyBBdXRoZW50aWNhdGlvbi1yZWxhdGVkIGV2ZW50cwogIHN0YXRpYyBjb25zdCBhdXRoID0gX0F1dGhFdmVudHMoKTsKCiAgLy8vIE5hdmlnYXRpb24tcmVsYXRlZCBldmVudHMKICBzdGF0aWMgY29uc3QgbmF2aWdhdGlvbiA9IF9OYXZpZ2F0aW9uRXZlbnRzKCk7CgogIC8vLyBGZWF0dXJlIHVzYWdlIGV2ZW50cwogIHN0YXRpYyBjb25zdCBmZWF0dXJlID0gX0ZlYXR1cmVFdmVudHMoKTsKCiAgLy8vIEVycm9yIGFuZCBkZWJ1Z2dpbmcgZXZlbnRzCiAgc3RhdGljIGNvbnN0IGVycm9yID0gX0Vycm9yRXZlbnRzKCk7CgogIC8vLyBBcHAgbGlmZWN5Y2xlIGV2ZW50cwogIHN0YXRpYyBjb25zdCBhcHAgPSBfQXBwRXZlbnRzKCk7CgogIC8vLyBQcm9maWxlLXJlbGF0ZWQgZXZlbnRzCiAgc3RhdGljIGNvbnN0IHByb2ZpbGUgPSBfUHJvZmlsZUV2ZW50cygpOwp9CgpjbGFzcyBfVXNlckV2ZW50cyB7CiAgY29uc3QgX1VzZXJFdmVudHMoKTsKCiAgLy8vIFVzZXIgc3VjY2Vzc2Z1bGx5IGF1dGhlbnRpY2F0ZWQgYW5kIHJlZGlyZWN0ZWQKICBTdHJpbmcgZ2V0IGF1dGhlbnRpY2F0ZWRSZWRpcmVjdCA9PiAndXNlcl9hdXRoZW50aWNhdGVkX3JlZGlyZWN0JzsKCiAgLy8vIFVzZXIgcHJvZmlsZSB1cGRhdGVkCiAgU3RyaW5nIGdldCBwcm9maWxlVXBkYXRlZCA9PiAndXNlcl9wcm9maWxlX3VwZGF0ZWQnOwoKICAvLy8gVXNlciBwcmVmZXJlbmNlcyBjaGFuZ2VkCiAgU3RyaW5nIGdldCBwcmVmZXJlbmNlc0NoYW5nZWQgPT4gJ3VzZXJfcHJlZmVyZW5jZXNfY2hhbmdlZCc7CgogIC8vLyBVc2VyIGNvbXBsZXRlZCBvbmJvYXJkaW5nCiAgU3RyaW5nIGdldCBvbmJvYXJkaW5nQ29tcGxldGVkID0+ICd1c2VyX29uYm9hcmRpbmdfY29tcGxldGVkJzsKCiAgLy8vIFVzZXIgYWNjb3VudCBkZWxldGVkCiAgU3RyaW5nIGdldCBhY2NvdW50RGVsZXRlZCA9PiAndXNlcl9hY2NvdW50X2RlbGV0ZWQnOwp9CgpjbGFzcyBfQXV0aEV2ZW50cyB7CiAgY29uc3QgX0F1dGhFdmVudHMoKTsKCiAgLy8vIFVzZXIgc2lnbmVkIGluCiAgU3RyaW5nIGdldCBzaWduSW4gPT4gJ2F1dGhfc2lnbl9pbic7CgogIC8vLyBVc2VyIHNpZ25lZCB1cAogIFN0cmluZyBnZXQgc2lnblVwID0+ICdhdXRoX3NpZ25fdXAnOwoKICAvLy8gVXNlciBzaWduZWQgb3V0CiAgU3RyaW5nIGdldCBzaWduT3V0ID0+ICdhdXRoX3NpZ25fb3V0JzsKCiAgLy8vIFBhc3N3b3JkIHJlc2V0IHJlcXVlc3RlZAogIFN0cmluZyBnZXQgcGFzc3dvcmRSZXNldCA9PiAnYXV0aF9wYXNzd29yZF9yZXNldCc7CgogIC8vLyBBdXRoZW50aWNhdGlvbiBmYWlsZWQKICBTdHJpbmcgZ2V0IGZhaWxlZCA9PiAnYXV0aF9mYWlsZWQnOwoKICAvLy8gU29jaWFsIGF1dGhlbnRpY2F0aW9uIChHb29nbGUsIEFwcGxlLCBldGMuKQogIFN0cmluZyBnZXQgc29jaWFsTG9naW4gPT4gJ2F1dGhfc29jaWFsX2xvZ2luJzsKfQoKY2xhc3MgX05hdmlnYXRpb25FdmVudHMgewogIGNvbnN0IF9OYXZpZ2F0aW9uRXZlbnRzKCk7CgogIC8vLyBTY3JlZW4gdmlld2VkIChhdXRvbWF0aWNhbGx5IHRyYWNrZWQpCiAgU3RyaW5nIGdldCBzY3JlZW5WaWV3ID0+ICdzY3JlZW5fdmlldyc7CgogIC8vLyBUYWIgc3dpdGNoZWQgaW4gYm90dG9tIG5hdmlnYXRpb24KICBTdHJpbmcgZ2V0IHRhYlN3aXRjaGVkID0+ICduYXZpZ2F0aW9uX3RhYl9zd2l0Y2hlZCc7CgogIC8vLyBCYWNrIGJ1dHRvbiBwcmVzc2VkCiAgU3RyaW5nIGdldCBiYWNrUHJlc3NlZCA9PiAnbmF2aWdhdGlvbl9iYWNrX3ByZXNzZWQnOwoKICAvLy8gRGVlcCBsaW5rIG9wZW5lZAogIFN0cmluZyBnZXQgZGVlcExpbmtPcGVuZWQgPT4gJ25hdmlnYXRpb25fZGVlcF9saW5rX29wZW5lZCc7Cn0KCmNsYXNzIF9GZWF0dXJlRXZlbnRzIHsKICBjb25zdCBfRmVhdHVyZUV2ZW50cygpOwoKICAvLy8gRmVhdHVyZSB3YXMgdXNlZC9hY2Nlc3NlZAogIFN0cmluZyBnZXQgdXNlZCA9PiAnZmVhdHVyZV91c2VkJzsKCiAgLy8vIEZlYXR1cmUgdHV0b3JpYWwgc3RhcnRlZAogIFN0cmluZyBnZXQgdHV0b3JpYWxTdGFydGVkID0+ICdmZWF0dXJlX3R1dG9yaWFsX3N0YXJ0ZWQnOwoKICAvLy8gRmVhdHVyZSB0dXRvcmlhbCBjb21wbGV0ZWQKICBTdHJpbmcgZ2V0IHR1dG9yaWFsQ29tcGxldGVkID0+ICdmZWF0dXJlX3R1dG9yaWFsX2NvbXBsZXRlZCc7CgogIC8vLyBGZWF0dXJlIGZlZWRiYWNrIGdpdmVuCiAgU3RyaW5nIGdldCBmZWVkYmFja0dpdmVuID0+ICdmZWF0dXJlX2ZlZWRiYWNrX2dpdmVuJzsKCiAgLy8vIEJ1dHRvbiBwcmVzc2VkCiAgU3RyaW5nIGdldCBidXR0b25QcmVzc2VkID0+ICdidXR0b25fcHJlc3NlZCc7Cn0KCmNsYXNzIF9FcnJvckV2ZW50cyB7CiAgY29uc3QgX0Vycm9yRXZlbnRzKCk7CgogIC8vLyBHZW5lcmFsIGFwcCBlcnJvciBvY2N1cnJlZAogIFN0cmluZyBnZXQgYXBwRXJyb3IgPT4gJ2FwcF9lcnJvcic7CgogIC8vLyBOZXR3b3JrIGVycm9yIG9jY3VycmVkCiAgU3RyaW5nIGdldCBuZXR3b3JrRXJyb3IgPT4gJ25ldHdvcmtfZXJyb3InOwoKICAvLy8gQ3Jhc2ggb2NjdXJyZWQKICBTdHJpbmcgZ2V0IGNyYXNoID0+ICdhcHBfY3Jhc2gnOwoKICAvLy8gQVBJIGVycm9yIG9jY3VycmVkCiAgU3RyaW5nIGdldCBhcGlFcnJvciA9PiAnYXBpX2Vycm9yJzsKCiAgLy8vIFZhbGlkYXRpb24gZXJyb3IKICBTdHJpbmcgZ2V0IHZhbGlkYXRpb25FcnJvciA9PiAndmFsaWRhdGlvbl9lcnJvcic7Cn0KCmNsYXNzIF9BcHBFdmVudHMgewogIGNvbnN0IF9BcHBFdmVudHMoKTsKCiAgLy8vIEFwcCBvcGVuZWQvbGF1bmNoZWQKICBTdHJpbmcgZ2V0IG9wZW4gPT4gJ2FwcF9vcGVuJzsKCiAgLy8vIEFwcCB3ZW50IHRvIGJhY2tncm91bmQKICBTdHJpbmcgZ2V0IGJhY2tncm91bmQgPT4gJ2FwcF9iYWNrZ3JvdW5kJzsKCiAgLy8vIEFwcCBjYW1lIHRvIGZvcmVncm91bmQKICBTdHJpbmcgZ2V0IGZvcmVncm91bmQgPT4gJ2FwcF9mb3JlZ3JvdW5kJzsKCiAgLy8vIEFwcCB1cGRhdGVkIHRvIG5ldyB2ZXJzaW9uCiAgU3RyaW5nIGdldCB1cGRhdGVkID0+ICdhcHBfdXBkYXRlZCc7CgogIC8vLyBBcHAgaW5zdGFsbGVkIGZvciBmaXJzdCB0aW1lCiAgU3RyaW5nIGdldCBpbnN0YWxsZWQgPT4gJ2FwcF9pbnN0YWxsZWQnOwoKICAvLy8gQXBwIHVuaW5zdGFsbGVkCiAgU3RyaW5nIGdldCB1bmluc3RhbGxlZCA9PiAnYXBwX3VuaW5zdGFsbGVkJzsKfQoKY2xhc3MgX1Byb2ZpbGVFdmVudHMgewogIGNvbnN0IF9Qcm9maWxlRXZlbnRzKCk7CgogIC8vLyBQcm9maWxlIHZpZXdlZAogIFN0cmluZyBnZXQgdmlld2VkID0+ICdwcm9maWxlX3ZpZXdlZCc7CgogIC8vLyBQcm9maWxlIGVkaXRlZAogIFN0cmluZyBnZXQgZWRpdGVkID0+ICdwcm9maWxlX2VkaXRlZCc7CgogIC8vLyBQcm9maWxlIHBob3RvIHVwZGF0ZWQKICBTdHJpbmcgZ2V0IHBob3RvVXBkYXRlZCA9PiAncHJvZmlsZV9waG90b191cGRhdGVkJzsKCiAgLy8vIFByb2ZpbGUgc2V0dGluZ3MgY2hhbmdlZAogIFN0cmluZyBnZXQgc2V0dGluZ3NDaGFuZ2VkID0+ICdwcm9maWxlX3NldHRpbmdzX2NoYW5nZWQnOwoKICAvLy8gUHJvZmlsZSBwcml2YWN5IHNldHRpbmdzIHVwZGF0ZWQKICBTdHJpbmcgZ2V0IHByaXZhY3lVcGRhdGVkID0+ICdwcm9maWxlX3ByaXZhY3lfdXBkYXRlZCc7Cn0K", "type": "text" }, { @@ -845,7 +953,7 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "path": "{{ name.snakeCase() }}/packages/{{analytics_dir}}/lib/src/observer/analytics_route_observer.dart", "data": - "aW1wb3J0ICdwYWNrYWdlOmNvcmUvY29yZS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZmlyZWJhc2VfYW5hbHl0aWNzL2ZpcmViYXNlX2FuYWx5dGljcy5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZsdXR0ZXIvbWF0ZXJpYWwuZGFydCc7CgovLy8gQW5hbHl0aWNzIHJvdXRlIG9ic2VydmVyIHRoYXQgdXNlcyBGaXJlYmFzZSBBbmFseXRpY3MgT2JzZXJ2ZXIgaW50ZXJuYWxseQovLy8gd2hpbGUgcHJvdmlkaW5nIGFkZGl0aW9uYWwgbG9nZ2luZyBhbmQgZXJyb3IgaGFuZGxpbmcgY2FwYWJpbGl0aWVzCmNsYXNzIEFuYWx5dGljc1JvdXRlT2JzZXJ2ZXIgZXh0ZW5kcyBOYXZpZ2F0b3JPYnNlcnZlciB7CiAgQW5hbHl0aWNzUm91dGVPYnNlcnZlcigpCiAgICA6IF9sb2dnZXIgPSBkaS5nZXQ8TG9nZ2VyPigpLAogICAgICBfZmlyZWJhc2VPYnNlcnZlciA9IEZpcmViYXNlQW5hbHl0aWNzT2JzZXJ2ZXIoCiAgICAgICAgYW5hbHl0aWNzOiBGaXJlYmFzZUFuYWx5dGljcy5pbnN0YW5jZSwKICAgICAgKTsKCiAgZmluYWwgTG9nZ2VyIF9sb2dnZXI7CiAgZmluYWwgRmlyZWJhc2VBbmFseXRpY3NPYnNlcnZlciBfZmlyZWJhc2VPYnNlcnZlcjsKCiAgQG92ZXJyaWRlCiAgdm9pZCBkaWRQdXNoKFJvdXRlIHJvdXRlLCBSb3V0ZT8gcHJldmlvdXNSb3V0ZSkgewogICAgc3VwZXIuZGlkUHVzaChyb3V0ZSwgcHJldmlvdXNSb3V0ZSk7CgogICAgdHJ5IHsKICAgICAgLy8gRGVsZWdhdGUgdG8gRmlyZWJhc2UgQW5hbHl0aWNzIE9ic2VydmVyIGZvciBuYXRpdmUgc2NyZWVuIHRyYWNraW5nCiAgICAgIF9maXJlYmFzZU9ic2VydmVyLmRpZFB1c2gocm91dGUsIHByZXZpb3VzUm91dGUpOwogICAgfSBjYXRjaCAoZSwgcykgewogICAgICBfbG9nZ2VyLmUoJ0ZhaWxlZCB0byB0cmFjayBzY3JlZW4gcHVzaCBldmVudCcsIGUsIHMpOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgdm9pZCBkaWRQb3AoUm91dGUgcm91dGUsIFJvdXRlPyBwcmV2aW91c1JvdXRlKSB7CiAgICBzdXBlci5kaWRQb3Aocm91dGUsIHByZXZpb3VzUm91dGUpOwoKICAgIHRyeSB7CiAgICAgIC8vIERlbGVnYXRlIHRvIEZpcmViYXNlIEFuYWx5dGljcyBPYnNlcnZlcgogICAgICBfZmlyZWJhc2VPYnNlcnZlci5kaWRQb3Aocm91dGUsIHByZXZpb3VzUm91dGUpOwogICAgfSBjYXRjaCAoZSwgcykgewogICAgICBfbG9nZ2VyLmUoJ0ZhaWxlZCB0byB0cmFjayBzY3JlZW4gcG9wIGV2ZW50JywgZSwgcyk7CiAgICB9CiAgfQoKICBAb3ZlcnJpZGUKICB2b2lkIGRpZFJlcGxhY2Uoe1JvdXRlPGR5bmFtaWM+PyBuZXdSb3V0ZSwgUm91dGU8ZHluYW1pYz4/IG9sZFJvdXRlfSkgewogICAgc3VwZXIuZGlkUmVwbGFjZShuZXdSb3V0ZTogbmV3Um91dGUsIG9sZFJvdXRlOiBvbGRSb3V0ZSk7CgogICAgdHJ5IHsKICAgICAgLy8gRGVsZWdhdGUgdG8gRmlyZWJhc2UgQW5hbHl0aWNzIE9ic2VydmVyCiAgICAgIF9maXJlYmFzZU9ic2VydmVyLmRpZFJlcGxhY2UobmV3Um91dGU6IG5ld1JvdXRlLCBvbGRSb3V0ZTogb2xkUm91dGUpOwogICAgfSBjYXRjaCAoZSwgcykgewogICAgICBfbG9nZ2VyLmUoJ0ZhaWxlZCB0byB0cmFjayBzY3JlZW4gcmVwbGFjZSBldmVudCcsIGUsIHMpOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgdm9pZCBkaWRSZW1vdmUoUm91dGU8ZHluYW1pYz4gcm91dGUsIFJvdXRlPGR5bmFtaWM+PyBwcmV2aW91c1JvdXRlKSB7CiAgICBzdXBlci5kaWRSZW1vdmUocm91dGUsIHByZXZpb3VzUm91dGUpOwoKICAgIHRyeSB7CiAgICAgIC8vIERlbGVnYXRlIHRvIEZpcmViYXNlIEFuYWx5dGljcyBPYnNlcnZlcgogICAgICBfZmlyZWJhc2VPYnNlcnZlci5kaWRSZW1vdmUocm91dGUsIHByZXZpb3VzUm91dGUpOwogICAgfSBjYXRjaCAoZSwgcykgewogICAgICBfbG9nZ2VyLmUoJ0ZhaWxlZCB0byB0cmFjayBzY3JlZW4gcmVtb3ZlIGV2ZW50JywgZSwgcyk7CiAgICB9CiAgfQp9Cg==", + "aW1wb3J0ICdkYXJ0OmFzeW5jJzsKaW1wb3J0ICdwYWNrYWdlOmFuYWx5dGljcy9zcmMvY2xpZW50L2FuYWx5dGljc19jbGllbnQuZGFydCc7CmltcG9ydCAncGFja2FnZTpjb3JlL2NvcmUuZGFydCc7CmltcG9ydCAncGFja2FnZTpmbHV0dGVyL21hdGVyaWFsLmRhcnQnOwoKLy8vIFRyYWNrcyBuYW1lZCBwYWdlcyB0aHJvdWdoIHRoZSBhbmFseXRpY3MgYWJzdHJhY3Rpb24sIGluY2x1ZGluZyBhc3luYyBlcnJvcnMuCmNsYXNzIEFuYWx5dGljc1JvdXRlT2JzZXJ2ZXIgZXh0ZW5kcyBOYXZpZ2F0b3JPYnNlcnZlciB7CiAgQW5hbHl0aWNzUm91dGVPYnNlcnZlcih7CiAgICByZXF1aXJlZCBBbmFseXRpY3NDbGllbnQgY2xpZW50LAogICAgcmVxdWlyZWQgTG9nZ2VyIGxvZ2dlciwKICB9KSA6IF9jbGllbnQgPSBjbGllbnQsCiAgICAgICBfbG9nZ2VyID0gbG9nZ2VyOwoKICBmaW5hbCBBbmFseXRpY3NDbGllbnQgX2NsaWVudDsKICBmaW5hbCBMb2dnZXIgX2xvZ2dlcjsKCiAgRnV0dXJlPHZvaWQ+IF90cmFjayhSb3V0ZTxkeW5hbWljPj8gcm91dGUpIGFzeW5jIHsKICAgIGlmIChyb3V0ZSBpcyEgUGFnZVJvdXRlIHx8IHJvdXRlLnNldHRpbmdzLm5hbWUgPT0gbnVsbCkgcmV0dXJuOwogICAgdHJ5IHsKICAgICAgYXdhaXQgX2NsaWVudC5sb2dTY3JlZW5WaWV3KHNjcmVlbk5hbWU6IHJvdXRlLnNldHRpbmdzLm5hbWUhKTsKICAgIH0gY2F0Y2ggKGVycm9yLCBzdGFjaykgewogICAgICBfbG9nZ2VyLmUoJ0ZhaWxlZCB0byB0cmFjayBzY3JlZW4gbmF2aWdhdGlvbicsIGVycm9yLCBzdGFjayk7CiAgICB9CiAgfQoKICBAb3ZlcnJpZGUKICB2b2lkIGRpZFB1c2goUm91dGU8ZHluYW1pYz4gcm91dGUsIFJvdXRlPGR5bmFtaWM+PyBwcmV2aW91c1JvdXRlKSB7CiAgICBzdXBlci5kaWRQdXNoKHJvdXRlLCBwcmV2aW91c1JvdXRlKTsKICAgIHVuYXdhaXRlZChfdHJhY2socm91dGUpKTsKICB9CgogIEBvdmVycmlkZQogIHZvaWQgZGlkUG9wKFJvdXRlPGR5bmFtaWM+IHJvdXRlLCBSb3V0ZTxkeW5hbWljPj8gcHJldmlvdXNSb3V0ZSkgewogICAgc3VwZXIuZGlkUG9wKHJvdXRlLCBwcmV2aW91c1JvdXRlKTsKICAgIHVuYXdhaXRlZChfdHJhY2socHJldmlvdXNSb3V0ZSkpOwogIH0KCiAgQG92ZXJyaWRlCiAgdm9pZCBkaWRSZXBsYWNlKHtSb3V0ZTxkeW5hbWljPj8gbmV3Um91dGUsIFJvdXRlPGR5bmFtaWM+PyBvbGRSb3V0ZX0pIHsKICAgIHN1cGVyLmRpZFJlcGxhY2UobmV3Um91dGU6IG5ld1JvdXRlLCBvbGRSb3V0ZTogb2xkUm91dGUpOwogICAgdW5hd2FpdGVkKF90cmFjayhuZXdSb3V0ZSkpOwogIH0KfQo=", "type": "text" }, { @@ -858,7 +966,7 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "path": "{{ name.snakeCase() }}/packages/{{analytics_dir}}/lib/src/utils/analytics_helper.dart", "data": - "aW1wb3J0ICdwYWNrYWdlOmFuYWx5dGljcy9zcmMvY2xpZW50L2FuYWx5dGljc19jbGllbnQuZGFydCc7CmltcG9ydCAncGFja2FnZTphbmFseXRpY3Mvc3JjL21vZGVscy9hbmFseXRpY3NfZXZlbnQuZGFydCc7CmltcG9ydCAncGFja2FnZTphbmFseXRpY3Mvc3JjL21vZGVscy9hbmFseXRpY3NfZXZlbnRzLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Y29yZS9jb3JlLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZGkvZGkuZGFydCc7CgpjbGFzcyBBbmFseXRpY3NIZWxwZXIgewogIHN0YXRpYyBBbmFseXRpY3NDbGllbnQ/IF9jbGllbnQ7CiAgc3RhdGljIExvZ2dlcj8gX2xvZ2dlcjsKCiAgc3RhdGljIEFuYWx5dGljc0NsaWVudD8gZ2V0IF9hbmFseXRpY3NDbGllbnQgewogICAgX2NsaWVudCA/Pz0gX2dldEFuYWx5dGljc0NsaWVudCgpOwogICAgcmV0dXJuIF9jbGllbnQ7CiAgfQoKICBzdGF0aWMgTG9nZ2VyIGdldCBfbG9nIHsKICAgIF9sb2dnZXIgPz89IGRpLmdldDxMb2dnZXI+KCk7CiAgICByZXR1cm4gX2xvZ2dlciE7CiAgfQoKICBzdGF0aWMgQW5hbHl0aWNzQ2xpZW50PyBfZ2V0QW5hbHl0aWNzQ2xpZW50KCkgewogICAgdHJ5IHsKICAgICAgcmV0dXJuIGRpLmdldDxBbmFseXRpY3NDbGllbnQ+KCk7CiAgICB9IGNhdGNoIChlKSB7CiAgICAgIF9sb2cudygnQW5hbHl0aWNzIGNsaWVudCBub3QgYXZhaWxhYmxlOiAkZScpOwogICAgICByZXR1cm4gbnVsbDsKICAgIH0KICB9CgogIC8vLyBMb2cgYSBjdXN0b20gZXZlbnQgd2l0aCBvcHRpb25hbCBwYXJhbWV0ZXJzCiAgc3RhdGljIEZ1dHVyZTx2b2lkPiBsb2dFdmVudCgKICAgIFN0cmluZyBuYW1lLCB7CiAgICBNYXA8U3RyaW5nLCBkeW5hbWljPj8gcGFyYW1ldGVycywKICB9KSBhc3luYyB7CiAgICBmaW5hbCBjbGllbnQgPSBfYW5hbHl0aWNzQ2xpZW50OwogICAgaWYgKGNsaWVudCA9PSBudWxsKSByZXR1cm47CgogICAgdHJ5IHsKICAgICAgYXdhaXQgY2xpZW50LmxvZ0V2ZW50KG5hbWU6IG5hbWUsIHBhcmFtZXRlcnM6IHBhcmFtZXRlcnMpOwogICAgfSBjYXRjaCAoZSwgcykgewogICAgICBfbG9nLmUoJ0ZhaWxlZCB0byBsb2cgYW5hbHl0aWNzIGV2ZW50OiAkbmFtZScsIGUsIHMpOwogICAgfQogIH0KCiAgLy8vIExvZyB1c2VyIHNpZ24gaW4KICBzdGF0aWMgRnV0dXJlPHZvaWQ+IGxvZ1NpZ25Jbih7CiAgICBTdHJpbmc/IG1ldGhvZCwKICAgIE1hcDxTdHJpbmcsIGR5bmFtaWM+PyBwYXJhbWV0ZXJzLAogIH0pIGFzeW5jIHsKICAgIGZpbmFsIGNsaWVudCA9IF9hbmFseXRpY3NDbGllbnQ7CiAgICBpZiAoY2xpZW50ID09IG51bGwpIHJldHVybjsKCiAgICB0cnkgewogICAgICBhd2FpdCBjbGllbnQubG9nTG9naW4obG9naW5NZXRob2Q6IG1ldGhvZCwgcGFyYW1ldGVyczogcGFyYW1ldGVycyk7CiAgICB9IGNhdGNoIChlLCBzKSB7CiAgICAgIF9sb2cuZSgnRmFpbGVkIHRvIGxvZyBzaWduIGluIGV2ZW50JywgZSwgcyk7CiAgICB9CiAgfQoKICAvLy8gTG9nIHVzZXIgc2lnbiB1cAogIHN0YXRpYyBGdXR1cmU8dm9pZD4gbG9nU2lnblVwKHsKICAgIFN0cmluZz8gbWV0aG9kLAogICAgTWFwPFN0cmluZywgZHluYW1pYz4/IHBhcmFtZXRlcnMsCiAgfSkgYXN5bmMgewogICAgZmluYWwgY2xpZW50ID0gX2FuYWx5dGljc0NsaWVudDsKICAgIGlmIChjbGllbnQgPT0gbnVsbCkgcmV0dXJuOwoKICAgIHRyeSB7CiAgICAgIGF3YWl0IGNsaWVudC5sb2dTaWduVXAoc2lnblVwTWV0aG9kOiBtZXRob2QsIHBhcmFtZXRlcnM6IHBhcmFtZXRlcnMpOwogICAgfSBjYXRjaCAoZSwgcykgewogICAgICBfbG9nLmUoJ0ZhaWxlZCB0byBsb2cgc2lnbiB1cCBldmVudCcsIGUsIHMpOwogICAgfQogIH0KCiAgLy8vIFNldCB1c2VyIElEIGZvciBhbmFseXRpY3MKICBzdGF0aWMgRnV0dXJlPHZvaWQ+IHNldFVzZXJJZChTdHJpbmc/IHVzZXJJZCkgYXN5bmMgewogICAgZmluYWwgY2xpZW50ID0gX2FuYWx5dGljc0NsaWVudDsKICAgIGlmIChjbGllbnQgPT0gbnVsbCkgcmV0dXJuOwoKICAgIHRyeSB7CiAgICAgIGF3YWl0IGNsaWVudC5zZXRVc2VySWQodXNlcklkKTsKICAgIH0gY2F0Y2ggKGUsIHMpIHsKICAgICAgX2xvZy5lKCdGYWlsZWQgdG8gc2V0IGFuYWx5dGljcyB1c2VyIElEJywgZSwgcyk7CiAgICB9CiAgfQoKICAvLy8gU2V0IHVzZXIgcHJvcGVydHkKICBzdGF0aWMgRnV0dXJlPHZvaWQ+IHNldFVzZXJQcm9wZXJ0eSh7CiAgICByZXF1aXJlZCBTdHJpbmcgbmFtZSwKICAgIHJlcXVpcmVkIFN0cmluZz8gdmFsdWUsCiAgfSkgYXN5bmMgewogICAgZmluYWwgY2xpZW50ID0gX2FuYWx5dGljc0NsaWVudDsKICAgIGlmIChjbGllbnQgPT0gbnVsbCkgcmV0dXJuOwoKICAgIHRyeSB7CiAgICAgIGF3YWl0IGNsaWVudC5zZXRVc2VyUHJvcGVydHkobmFtZTogbmFtZSwgdmFsdWU6IHZhbHVlKTsKICAgIH0gY2F0Y2ggKGUsIHMpIHsKICAgICAgX2xvZy5lKCdGYWlsZWQgdG8gc2V0IGFuYWx5dGljcyB1c2VyIHByb3BlcnR5OiAkbmFtZScsIGUsIHMpOwogICAgfQogIH0KCiAgLy8vIExvZyBhcHAgb3BlbiBldmVudAogIHN0YXRpYyBGdXR1cmU8dm9pZD4gbG9nQXBwT3Blbih7TWFwPFN0cmluZywgZHluYW1pYz4/IHBhcmFtZXRlcnN9KSBhc3luYyB7CiAgICBmaW5hbCBjbGllbnQgPSBfYW5hbHl0aWNzQ2xpZW50OwogICAgaWYgKGNsaWVudCA9PSBudWxsKSByZXR1cm47CgogICAgdHJ5IHsKICAgICAgYXdhaXQgY2xpZW50LmxvZ0FwcE9wZW4ocGFyYW1ldGVyczogcGFyYW1ldGVycyk7CiAgICB9IGNhdGNoIChlLCBzKSB7CiAgICAgIF9sb2cuZSgnRmFpbGVkIHRvIGxvZyBhcHAgb3BlbiBldmVudCcsIGUsIHMpOwogICAgfQogIH0KCiAgLy8vIExvZyBjdXN0b20gYW5hbHl0aWNzIGV2ZW50CiAgc3RhdGljIEZ1dHVyZTx2b2lkPiBsb2dDdXN0b21FdmVudChBbmFseXRpY3NFdmVudCBldmVudCkgYXN5bmMgewogICAgZmluYWwgY2xpZW50ID0gX2FuYWx5dGljc0NsaWVudDsKICAgIGlmIChjbGllbnQgPT0gbnVsbCkgcmV0dXJuOwoKICAgIHRyeSB7CiAgICAgIGF3YWl0IGNsaWVudC5sb2dDdXN0b21FdmVudChldmVudCk7CiAgICB9IGNhdGNoIChlLCBzKSB7CiAgICAgIF9sb2cuZSgnRmFpbGVkIHRvIGxvZyBjdXN0b20gYW5hbHl0aWNzIGV2ZW50OiAke2V2ZW50Lm5hbWV9JywgZSwgcyk7CiAgICB9CiAgfQoKICAvLy8gQ29tbW9uIGJ1c2luZXNzIGV2ZW50cwogIHN0YXRpYyBGdXR1cmU8dm9pZD4gbG9nRmVhdHVyZVVzZWQoCiAgICBTdHJpbmcgZmVhdHVyZU5hbWUsIHsKICAgIE1hcDxTdHJpbmcsIGR5bmFtaWM+PyBwYXJhbWV0ZXJzLAogIH0pIGFzeW5jIHsKICAgIGF3YWl0IGxvZ0V2ZW50KAogICAgICBBbmFseXRpY3NFdmVudHMuZmVhdHVyZS51c2VkLAogICAgICBwYXJhbWV0ZXJzOiB7CiAgICAgICAgJ2ZlYXR1cmVfbmFtZSc6IGZlYXR1cmVOYW1lLAogICAgICAgICd0aW1lc3RhbXAnOiBEYXRlVGltZS5ub3coKS50b0lzbzg2MDFTdHJpbmcoKSwKICAgICAgICAuLi4/cGFyYW1ldGVycywKICAgICAgfSwKICAgICk7CiAgfQoKICBzdGF0aWMgRnV0dXJlPHZvaWQ+IGxvZ0J1dHRvblByZXNzZWQoCiAgICBTdHJpbmcgYnV0dG9uTmFtZSwgewogICAgU3RyaW5nPyBzY3JlZW5OYW1lLAogICAgTWFwPFN0cmluZywgZHluYW1pYz4/IHBhcmFtZXRlcnMsCiAgfSkgYXN5bmMgewogICAgYXdhaXQgbG9nRXZlbnQoCiAgICAgIEFuYWx5dGljc0V2ZW50cy5mZWF0dXJlLmJ1dHRvblByZXNzZWQsCiAgICAgIHBhcmFtZXRlcnM6IHsKICAgICAgICAnYnV0dG9uX25hbWUnOiBidXR0b25OYW1lLAogICAgICAgIGlmIChzY3JlZW5OYW1lICE9IG51bGwpICdzY3JlZW5fbmFtZSc6IHNjcmVlbk5hbWUsCiAgICAgICAgJ3RpbWVzdGFtcCc6IERhdGVUaW1lLm5vdygpLnRvSXNvODYwMVN0cmluZygpLAogICAgICAgIC4uLj9wYXJhbWV0ZXJzLAogICAgICB9LAogICAgKTsKICB9CgogIHN0YXRpYyBGdXR1cmU8dm9pZD4gbG9nQXBwRXJyb3IoCiAgICBTdHJpbmcgZXJyb3JUeXBlLCB7CiAgICBTdHJpbmc/IGVycm9yTWVzc2FnZSwKICAgIE1hcDxTdHJpbmcsIGR5bmFtaWM+PyBwYXJhbWV0ZXJzLAogIH0pIGFzeW5jIHsKICAgIGF3YWl0IGxvZ0V2ZW50KAogICAgICBBbmFseXRpY3NFdmVudHMuZXJyb3IuYXBwRXJyb3IsCiAgICAgIHBhcmFtZXRlcnM6IHsKICAgICAgICAnZXJyb3JfdHlwZSc6IGVycm9yVHlwZSwKICAgICAgICBpZiAoZXJyb3JNZXNzYWdlICE9IG51bGwpICdlcnJvcl9tZXNzYWdlJzogZXJyb3JNZXNzYWdlLAogICAgICAgICd0aW1lc3RhbXAnOiBEYXRlVGltZS5ub3coKS50b0lzbzg2MDFTdHJpbmcoKSwKICAgICAgICAuLi4/cGFyYW1ldGVycywKICAgICAgfSwKICAgICk7CiAgfQoKfQo=", + "aW1wb3J0ICdwYWNrYWdlOmFuYWx5dGljcy9zcmMvY2xpZW50L2FuYWx5dGljc19jbGllbnQuZGFydCc7CmltcG9ydCAncGFja2FnZTphbmFseXRpY3Mvc3JjL21vZGVscy9hbmFseXRpY3NfZXZlbnQuZGFydCc7CmltcG9ydCAncGFja2FnZTphbmFseXRpY3Mvc3JjL21vZGVscy9hbmFseXRpY3NfZXZlbnRzLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Y29yZS9jb3JlLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZGkvZGkuZGFydCc7CgpjbGFzcyBBbmFseXRpY3NIZWxwZXIgewogIHN0YXRpYyBBbmFseXRpY3NDbGllbnQ/IGdldCBfYW5hbHl0aWNzQ2xpZW50ID0+IF9nZXRBbmFseXRpY3NDbGllbnQoKTsKCiAgc3RhdGljIExvZ2dlcj8gZ2V0IF9sb2cgPT4gZGkuaGFzPExvZ2dlcj4oKSA/IGRpLmdldDxMb2dnZXI+KCkgOiBudWxsOwoKICBzdGF0aWMgQW5hbHl0aWNzQ2xpZW50PyBfZ2V0QW5hbHl0aWNzQ2xpZW50KCkgewogICAgdHJ5IHsKICAgICAgcmV0dXJuIGRpLmdldDxBbmFseXRpY3NDbGllbnQ+KCk7CiAgICB9IGNhdGNoIChlKSB7CiAgICAgIF9sb2c/LncoJ0FuYWx5dGljcyBjbGllbnQgbm90IGF2YWlsYWJsZTogJGUnKTsKICAgICAgcmV0dXJuIG51bGw7CiAgICB9CiAgfQoKICAvLy8gTG9nIGEgY3VzdG9tIGV2ZW50IHdpdGggb3B0aW9uYWwgcGFyYW1ldGVycwogIHN0YXRpYyBGdXR1cmU8dm9pZD4gbG9nRXZlbnQoCiAgICBTdHJpbmcgbmFtZSwgewogICAgTWFwPFN0cmluZywgZHluYW1pYz4/IHBhcmFtZXRlcnMsCiAgfSkgYXN5bmMgewogICAgZmluYWwgY2xpZW50ID0gX2FuYWx5dGljc0NsaWVudDsKICAgIGlmIChjbGllbnQgPT0gbnVsbCkgcmV0dXJuOwoKICAgIHRyeSB7CiAgICAgIGF3YWl0IGNsaWVudC5sb2dFdmVudChuYW1lOiBuYW1lLCBwYXJhbWV0ZXJzOiBwYXJhbWV0ZXJzKTsKICAgIH0gY2F0Y2ggKGUsIHMpIHsKICAgICAgX2xvZz8uZSgnRmFpbGVkIHRvIGxvZyBhbmFseXRpY3MgZXZlbnQ6ICRuYW1lJywgZSwgcyk7CiAgICB9CiAgfQoKICAvLy8gTG9nIHVzZXIgc2lnbiBpbgogIHN0YXRpYyBGdXR1cmU8dm9pZD4gbG9nU2lnbkluKHsKICAgIFN0cmluZz8gbWV0aG9kLAogICAgTWFwPFN0cmluZywgZHluYW1pYz4/IHBhcmFtZXRlcnMsCiAgfSkgYXN5bmMgewogICAgZmluYWwgY2xpZW50ID0gX2FuYWx5dGljc0NsaWVudDsKICAgIGlmIChjbGllbnQgPT0gbnVsbCkgcmV0dXJuOwoKICAgIHRyeSB7CiAgICAgIGF3YWl0IGNsaWVudC5sb2dMb2dpbihsb2dpbk1ldGhvZDogbWV0aG9kLCBwYXJhbWV0ZXJzOiBwYXJhbWV0ZXJzKTsKICAgIH0gY2F0Y2ggKGUsIHMpIHsKICAgICAgX2xvZz8uZSgnRmFpbGVkIHRvIGxvZyBzaWduIGluIGV2ZW50JywgZSwgcyk7CiAgICB9CiAgfQoKICAvLy8gTG9nIHVzZXIgc2lnbiB1cAogIHN0YXRpYyBGdXR1cmU8dm9pZD4gbG9nU2lnblVwKHsKICAgIFN0cmluZz8gbWV0aG9kLAogICAgTWFwPFN0cmluZywgZHluYW1pYz4/IHBhcmFtZXRlcnMsCiAgfSkgYXN5bmMgewogICAgZmluYWwgY2xpZW50ID0gX2FuYWx5dGljc0NsaWVudDsKICAgIGlmIChjbGllbnQgPT0gbnVsbCkgcmV0dXJuOwoKICAgIHRyeSB7CiAgICAgIGF3YWl0IGNsaWVudC5sb2dTaWduVXAoc2lnblVwTWV0aG9kOiBtZXRob2QsIHBhcmFtZXRlcnM6IHBhcmFtZXRlcnMpOwogICAgfSBjYXRjaCAoZSwgcykgewogICAgICBfbG9nPy5lKCdGYWlsZWQgdG8gbG9nIHNpZ24gdXAgZXZlbnQnLCBlLCBzKTsKICAgIH0KICB9CgogIC8vLyBTZXQgdXNlciBJRCBmb3IgYW5hbHl0aWNzCiAgc3RhdGljIEZ1dHVyZTx2b2lkPiBzZXRVc2VySWQoU3RyaW5nPyB1c2VySWQpIGFzeW5jIHsKICAgIGZpbmFsIGNsaWVudCA9IF9hbmFseXRpY3NDbGllbnQ7CiAgICBpZiAoY2xpZW50ID09IG51bGwpIHJldHVybjsKCiAgICB0cnkgewogICAgICBhd2FpdCBjbGllbnQuc2V0VXNlcklkKHVzZXJJZCk7CiAgICB9IGNhdGNoIChlLCBzKSB7CiAgICAgIF9sb2c/LmUoJ0ZhaWxlZCB0byBzZXQgYW5hbHl0aWNzIHVzZXIgSUQnLCBlLCBzKTsKICAgIH0KICB9CgogIC8vLyBTZXQgdXNlciBwcm9wZXJ0eQogIHN0YXRpYyBGdXR1cmU8dm9pZD4gc2V0VXNlclByb3BlcnR5KHsKICAgIHJlcXVpcmVkIFN0cmluZyBuYW1lLAogICAgcmVxdWlyZWQgU3RyaW5nPyB2YWx1ZSwKICB9KSBhc3luYyB7CiAgICBmaW5hbCBjbGllbnQgPSBfYW5hbHl0aWNzQ2xpZW50OwogICAgaWYgKGNsaWVudCA9PSBudWxsKSByZXR1cm47CgogICAgdHJ5IHsKICAgICAgYXdhaXQgY2xpZW50LnNldFVzZXJQcm9wZXJ0eShuYW1lOiBuYW1lLCB2YWx1ZTogdmFsdWUpOwogICAgfSBjYXRjaCAoZSwgcykgewogICAgICBfbG9nPy5lKCdGYWlsZWQgdG8gc2V0IGFuYWx5dGljcyB1c2VyIHByb3BlcnR5OiAkbmFtZScsIGUsIHMpOwogICAgfQogIH0KCiAgLy8vIExvZyBhcHAgb3BlbiBldmVudAogIHN0YXRpYyBGdXR1cmU8dm9pZD4gbG9nQXBwT3Blbih7TWFwPFN0cmluZywgZHluYW1pYz4/IHBhcmFtZXRlcnN9KSBhc3luYyB7CiAgICBmaW5hbCBjbGllbnQgPSBfYW5hbHl0aWNzQ2xpZW50OwogICAgaWYgKGNsaWVudCA9PSBudWxsKSByZXR1cm47CgogICAgdHJ5IHsKICAgICAgYXdhaXQgY2xpZW50LmxvZ0FwcE9wZW4ocGFyYW1ldGVyczogcGFyYW1ldGVycyk7CiAgICB9IGNhdGNoIChlLCBzKSB7CiAgICAgIF9sb2c/LmUoJ0ZhaWxlZCB0byBsb2cgYXBwIG9wZW4gZXZlbnQnLCBlLCBzKTsKICAgIH0KICB9CgogIC8vLyBMb2cgY3VzdG9tIGFuYWx5dGljcyBldmVudAogIHN0YXRpYyBGdXR1cmU8dm9pZD4gbG9nQ3VzdG9tRXZlbnQoQW5hbHl0aWNzRXZlbnQgZXZlbnQpIGFzeW5jIHsKICAgIGZpbmFsIGNsaWVudCA9IF9hbmFseXRpY3NDbGllbnQ7CiAgICBpZiAoY2xpZW50ID09IG51bGwpIHJldHVybjsKCiAgICB0cnkgewogICAgICBhd2FpdCBjbGllbnQubG9nQ3VzdG9tRXZlbnQoZXZlbnQpOwogICAgfSBjYXRjaCAoZSwgcykgewogICAgICBfbG9nPy5lKCdGYWlsZWQgdG8gbG9nIGN1c3RvbSBhbmFseXRpY3MgZXZlbnQ6ICR7ZXZlbnQubmFtZX0nLCBlLCBzKTsKICAgIH0KICB9CgogIC8vLyBDb21tb24gYnVzaW5lc3MgZXZlbnRzCiAgc3RhdGljIEZ1dHVyZTx2b2lkPiBsb2dGZWF0dXJlVXNlZCgKICAgIFN0cmluZyBmZWF0dXJlTmFtZSwgewogICAgTWFwPFN0cmluZywgZHluYW1pYz4/IHBhcmFtZXRlcnMsCiAgfSkgYXN5bmMgewogICAgYXdhaXQgbG9nRXZlbnQoCiAgICAgIEFuYWx5dGljc0V2ZW50cy5mZWF0dXJlLnVzZWQsCiAgICAgIHBhcmFtZXRlcnM6IHsKICAgICAgICAnZmVhdHVyZV9uYW1lJzogZmVhdHVyZU5hbWUsCiAgICAgICAgJ3RpbWVzdGFtcCc6IERhdGVUaW1lLm5vdygpLnRvSXNvODYwMVN0cmluZygpLAogICAgICAgIC4uLj9wYXJhbWV0ZXJzLAogICAgICB9LAogICAgKTsKICB9CgogIHN0YXRpYyBGdXR1cmU8dm9pZD4gbG9nQnV0dG9uUHJlc3NlZCgKICAgIFN0cmluZyBidXR0b25OYW1lLCB7CiAgICBTdHJpbmc/IHNjcmVlbk5hbWUsCiAgICBNYXA8U3RyaW5nLCBkeW5hbWljPj8gcGFyYW1ldGVycywKICB9KSBhc3luYyB7CiAgICBhd2FpdCBsb2dFdmVudCgKICAgICAgQW5hbHl0aWNzRXZlbnRzLmZlYXR1cmUuYnV0dG9uUHJlc3NlZCwKICAgICAgcGFyYW1ldGVyczogewogICAgICAgICdidXR0b25fbmFtZSc6IGJ1dHRvbk5hbWUsCiAgICAgICAgaWYgKHNjcmVlbk5hbWUgIT0gbnVsbCkgJ3NjcmVlbl9uYW1lJzogc2NyZWVuTmFtZSwKICAgICAgICAndGltZXN0YW1wJzogRGF0ZVRpbWUubm93KCkudG9Jc284NjAxU3RyaW5nKCksCiAgICAgICAgLi4uP3BhcmFtZXRlcnMsCiAgICAgIH0sCiAgICApOwogIH0KCiAgc3RhdGljIEZ1dHVyZTx2b2lkPiBsb2dBcHBFcnJvcigKICAgIFN0cmluZyBlcnJvclR5cGUsIHsKICAgIFN0cmluZz8gZXJyb3JNZXNzYWdlLAogICAgTWFwPFN0cmluZywgZHluYW1pYz4/IHBhcmFtZXRlcnMsCiAgfSkgYXN5bmMgewogICAgYXdhaXQgbG9nRXZlbnQoCiAgICAgIEFuYWx5dGljc0V2ZW50cy5lcnJvci5hcHBFcnJvciwKICAgICAgcGFyYW1ldGVyczogewogICAgICAgICdlcnJvcl90eXBlJzogZXJyb3JUeXBlLAogICAgICAgIGlmIChlcnJvck1lc3NhZ2UgIT0gbnVsbCkgJ2Vycm9yX21lc3NhZ2UnOiBlcnJvck1lc3NhZ2UsCiAgICAgICAgJ3RpbWVzdGFtcCc6IERhdGVUaW1lLm5vdygpLnRvSXNvODYwMVN0cmluZygpLAogICAgICAgIC4uLj9wYXJhbWV0ZXJzLAogICAgICB9LAogICAgKTsKICB9Cn0K", "type": "text" }, { @@ -870,7 +978,7 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ { "path": "{{ name.snakeCase() }}/packages/{{analytics_dir}}/pubspec.yaml", "data": - "bmFtZTogYW5hbHl0aWNzCmRlc2NyaXB0aW9uOiAiRXZlbnQgdHJhY2tpbmcgZm9yIHt7bmFtZS50aXRsZUNhc2UoKX19IGJlaGluZCBhIHN3YXBwYWJsZSBjbGllbnQgaW50ZXJmYWNlLiIKdmVyc2lvbjogMC4xLjAKcHVibGlzaF90bzogJ25vbmUnCgplbnZpcm9ubWVudDoKICBzZGs6IF4zLjguMAogIGZsdXR0ZXI6ICI+PTMuMjkuMCIKCmRlcGVuZGVuY2llczoKICBmbHV0dGVyOgogICAgc2RrOiBmbHV0dGVyCiAgZmlyZWJhc2VfYW5hbHl0aWNzOiBeMTEuMy41CiAgY29yZToKICAgIHBhdGg6IC4uL2NvcmUKICBkaToKICAgIHBhdGg6IC4uL2RpCgpkZXZfZGVwZW5kZW5jaWVzOgogIGZsdXR0ZXJfdGVzdDoKICAgIHNkazogZmx1dHRlcgogIGZsdXR0ZXJfbGludHM6IF41LjAuMAoKZmx1dHRlcjoK", + "bmFtZTogYW5hbHl0aWNzCmRlc2NyaXB0aW9uOiAiRXZlbnQgdHJhY2tpbmcgZm9yIHt7bmFtZS50aXRsZUNhc2UoKX19IGJlaGluZCBhIHN3YXBwYWJsZSBjbGllbnQgaW50ZXJmYWNlLiIKdmVyc2lvbjogMC4xLjAKcHVibGlzaF90bzogJ25vbmUnCgplbnZpcm9ubWVudDoKICBzZGs6IF4zLjguMAogIGZsdXR0ZXI6ICI+PTMuMjkuMCIKCmRlcGVuZGVuY2llczoKICBmbHV0dGVyOgogICAgc2RrOiBmbHV0dGVyCiAgZmlyZWJhc2VfYW5hbHl0aWNzOiBeMTEuMy41CiAgY29yZToKICAgIHBhdGg6IC4uL2NvcmUKICBkaToKICAgIHBhdGg6IC4uL2RpCgpkZXZfZGVwZW5kZW5jaWVzOgogIG1vY2t0YWlsOiBeMS4wLjQKICBmbHV0dGVyX3Rlc3Q6CiAgICBzZGs6IGZsdXR0ZXIKICBmbHV0dGVyX2xpbnRzOiBeNS4wLjAKCmZsdXR0ZXI6Cg==", "type": "text" }, { @@ -886,11 +994,32 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "aW1wb3J0ICdwYWNrYWdlOmFuYWx5dGljcy9hbmFseXRpY3MuZGFydCc7CmltcG9ydCAncGFja2FnZTpmbHV0dGVyX3Rlc3QvZmx1dHRlcl90ZXN0LmRhcnQnOwoKdm9pZCBtYWluKCkgewogIGdyb3VwKCdBbmFseXRpY3MgUGFja2FnZScsICgpIHsKICAgIHRlc3QoJ3Nob3VsZCBjcmVhdGUgQW5hbHl0aWNzRXZlbnQgY29ycmVjdGx5JywgKCkgewogICAgICBjb25zdCBldmVudCA9IEFuYWx5dGljc0V2ZW50KAogICAgICAgIG5hbWU6ICd0ZXN0X2V2ZW50JywKICAgICAgICBwYXJhbWV0ZXJzOiB7J2tleSc6ICd2YWx1ZSd9LAogICAgICApOwoKICAgICAgZXhwZWN0KGV2ZW50Lm5hbWUsICd0ZXN0X2V2ZW50Jyk7CiAgICAgIGV4cGVjdChldmVudC5wYXJhbWV0ZXJzLCB7J2tleSc6ICd2YWx1ZSd9KTsKICAgIH0pOwoKICAgIHRlc3QoJ3Nob3VsZCBjcmVhdGUgRGVmYXVsdEFuYWx5dGljc0NvbmZpZyBjb3JyZWN0bHknLCAoKSB7CiAgICAgIGNvbnN0IGNvbmZpZyA9IERlZmF1bHRBbmFseXRpY3NDb25maWcoCiAgICAgICAgZW5hYmxlQW5hbHl0aWNzOiB0cnVlLAogICAgICAgIGVuYWJsZURlYnVnTG9nZ2luZzogZmFsc2UsCiAgICAgICk7CgogICAgICBleHBlY3QoY29uZmlnLmVuYWJsZUFuYWx5dGljcywgaXNUcnVlKTsKICAgICAgZXhwZWN0KGNvbmZpZy5lbmFibGVEZWJ1Z0xvZ2dpbmcsIGlzRmFsc2UpOwogICAgfSk7CiAgfSk7Cn0K", "type": "text" }, + { + "path": + "{{ name.snakeCase() }}/packages/{{analytics_dir}}/test/client_test.dart", + "data": + "aW1wb3J0ICdwYWNrYWdlOmFuYWx5dGljcy9hbmFseXRpY3MuZGFydCc7CmltcG9ydCAncGFja2FnZTphbmFseXRpY3MvYW5hbHl0aWNzLmRhcnQnIGFzIGFuYWx5dGljczsKaW1wb3J0ICdwYWNrYWdlOmNvcmUvY29yZS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZmlyZWJhc2VfYW5hbHl0aWNzL2ZpcmViYXNlX2FuYWx5dGljcy5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZsdXR0ZXJfdGVzdC9mbHV0dGVyX3Rlc3QuZGFydCc7CmltcG9ydCAncGFja2FnZTptb2NrdGFpbC9tb2NrdGFpbC5kYXJ0JzsKCmNsYXNzIF9TZGsgZXh0ZW5kcyBNb2NrIGltcGxlbWVudHMgRmlyZWJhc2VBbmFseXRpY3Mge30KCmNsYXNzIF9Mb2dnZXIgZXh0ZW5kcyBNb2NrIGltcGxlbWVudHMgTG9nZ2VyIHt9Cgp2b2lkIG1haW4oKSB7CiAgbGF0ZSBfU2RrIHNkazsKICBsYXRlIF9Mb2dnZXIgbG9nZ2VyOwogIGxhdGUgRmlyZWJhc2VBbmFseXRpY3NDbGllbnQgY2xpZW50OwogIHNldFVwKCgpIHsKICAgIHNkayA9IF9TZGsoKTsKICAgIGxvZ2dlciA9IF9Mb2dnZXIoKTsKICAgIHdoZW4oCiAgICAgICgpID0+IHNkay5zZXRBbmFseXRpY3NDb2xsZWN0aW9uRW5hYmxlZChhbnkoKSksCiAgICApLnRoZW5BbnN3ZXIoKF8pIGFzeW5jIHt9KTsKICAgIHdoZW4oKCkgPT4gc2RrLnNldFVzZXJJZChpZDogYW55KG5hbWVkOiAnaWQnKSkpLnRoZW5BbnN3ZXIoKF8pIGFzeW5jIHt9KTsKICAgIHdoZW4oCiAgICAgICgpID0+IHNkay5zZXRVc2VyUHJvcGVydHkoCiAgICAgICAgbmFtZTogYW55KG5hbWVkOiAnbmFtZScpLAogICAgICAgIHZhbHVlOiBhbnkobmFtZWQ6ICd2YWx1ZScpLAogICAgICApLAogICAgKS50aGVuQW5zd2VyKChfKSBhc3luYyB7fSk7CiAgICB3aGVuKAogICAgICAoKSA9PiBzZGsubG9nRXZlbnQoCiAgICAgICAgbmFtZTogYW55KG5hbWVkOiAnbmFtZScpLAogICAgICAgIHBhcmFtZXRlcnM6IGFueShuYW1lZDogJ3BhcmFtZXRlcnMnKSwKICAgICAgKSwKICAgICkudGhlbkFuc3dlcigoXykgYXN5bmMge30pOwogICAgd2hlbihzZGsucmVzZXRBbmFseXRpY3NEYXRhKS50aGVuQW5zd2VyKChfKSBhc3luYyB7fSk7CiAgICBjbGllbnQgPSBGaXJlYmFzZUFuYWx5dGljc0NsaWVudCgKICAgICAgY29uc3QgRGVmYXVsdEFuYWx5dGljc0NvbmZpZygKICAgICAgICBlbmFibGVEZWJ1Z0xvZ2dpbmc6IHRydWUsCiAgICAgICAgdXNlcklkOiAndXNlcicsCiAgICAgICAgZGVmYXVsdFVzZXJQcm9wZXJ0aWVzOiB7J3JvbGUnOiAndGVzdGVyJ30sCiAgICAgICksCiAgICAgIGFuYWx5dGljczogc2RrLAogICAgICBsb2dnZXI6IGxvZ2dlciwKICAgICk7CiAgfSk7CiAgdGVhckRvd24oZGkucmVzZXQpOwoKICB0ZXN0KCdzZW1hbnRpYyBldmVudHMgZm9yd2FyZCBhZGRpdGlvbmFsIHBhcmFtZXRlcnMnLCAoKSBhc3luYyB7CiAgICBhd2FpdCBjbGllbnQubG9nU2NyZWVuVmlldygKICAgICAgc2NyZWVuTmFtZTogJ2hvbWUnLAogICAgICBwYXJhbWV0ZXJzOiB7J3NvdXJjZSc6ICdsaW5rJ30sCiAgICApOwogICAgYXdhaXQgY2xpZW50LmxvZ0xvZ2luKHBhcmFtZXRlcnM6IHsnc291cmNlJzogJ2xpbmsnfSk7CiAgICBhd2FpdCBjbGllbnQubG9nU2lnblVwKHBhcmFtZXRlcnM6IHsnc291cmNlJzogJ2xpbmsnfSk7CiAgICBhd2FpdCBjbGllbnQubG9nUHVyY2hhc2UoCiAgICAgIGN1cnJlbmN5OiAnVVNEJywKICAgICAgdmFsdWU6IDIsCiAgICAgIHBhcmFtZXRlcnM6IHsnc291cmNlJzogJ2xpbmsnfSwKICAgICk7CiAgICB2ZXJpZnkoCiAgICAgICgpID0+IHNkay5sb2dFdmVudChuYW1lOiAnbG9naW4nLCBwYXJhbWV0ZXJzOiB7J3NvdXJjZSc6ICdsaW5rJ30pLAogICAgKS5jYWxsZWQoMSk7CiAgICB2ZXJpZnkoCiAgICAgICgpID0+IHNkay5sb2dFdmVudChuYW1lOiAnc2lnbl91cCcsIHBhcmFtZXRlcnM6IHsnc291cmNlJzogJ2xpbmsnfSksCiAgICApLmNhbGxlZCgxKTsKICB9KTsKCiAgdGVzdCgKICAgICdpbml0aWFsaXphdGlvbiBhd2FpdHMgU0RLIHNldHVwIGFuZCBwcm9wYWdhdGVzIHN0YXJ0dXAgZmFpbHVyZXMnLAogICAgKCkgYXN5bmMgewogICAgICBhd2FpdCBjbGllbnQuaW5pdGlhbGl6ZSgpOwogICAgICB2ZXJpZnkoKCkgPT4gc2RrLnNldFVzZXJJZChpZDogJ3VzZXInKSkuY2FsbGVkKDEpOwogICAgICB2ZXJpZnkoCiAgICAgICAgKCkgPT4gc2RrLnNldFVzZXJQcm9wZXJ0eShuYW1lOiAncm9sZScsIHZhbHVlOiAndGVzdGVyJyksCiAgICAgICkuY2FsbGVkKDEpOwogICAgICB3aGVuKAogICAgICAgICgpID0+IHNkay5zZXRBbmFseXRpY3NDb2xsZWN0aW9uRW5hYmxlZChhbnkoKSksCiAgICAgICkudGhlblRocm93KFN0YXRlRXJyb3IoJ3NldHVwJykpOwogICAgICBhd2FpdCBleHBlY3RMYXRlcihjbGllbnQuaW5pdGlhbGl6ZSgpLCB0aHJvd3NTdGF0ZUVycm9yKTsKICAgIH0sCiAgKTsKCiAgdGVzdCgnbnVsbCBldmVudCBwYXJhbWV0ZXJzIGFyZSByZW1vdmVkIGJlZm9yZSBTREsgc3VibWlzc2lvbicsICgpIGFzeW5jIHsKICAgIGF3YWl0IGNsaWVudC5sb2dFdmVudCgKICAgICAgbmFtZTogJ2V2ZW50JywKICAgICAgcGFyYW1ldGVyczogeyd2YWxpZCc6IDEsICdvcHRpb25hbCc6IG51bGx9LAogICAgKTsKICAgIHZlcmlmeSgKICAgICAgKCkgPT4gc2RrLmxvZ0V2ZW50KG5hbWU6ICdldmVudCcsIHBhcmFtZXRlcnM6IHsndmFsaWQnOiAxfSksCiAgICApLmNhbGxlZCgxKTsKICB9KTsKCiAgdGVzdCgnY29sbGVjdGlvbiBjaGFuZ2VzIGFmZmVjdCBmdXR1cmUgbG9nZ2luZycsICgpIGFzeW5jIHsKICAgIGF3YWl0IGNsaWVudC5zZXRBbmFseXRpY3NDb2xsZWN0aW9uRW5hYmxlZChmYWxzZSk7CiAgICBhd2FpdCBjbGllbnQubG9nRXZlbnQobmFtZTogJ2Rpc2FibGVkJyk7CiAgICB2ZXJpZnlOZXZlcigoKSA9PiBzZGsubG9nRXZlbnQobmFtZTogJ2Rpc2FibGVkJykpOwogICAgYXdhaXQgY2xpZW50LnNldEFuYWx5dGljc0NvbGxlY3Rpb25FbmFibGVkKHRydWUpOwogICAgYXdhaXQgY2xpZW50LmxvZ0V2ZW50KG5hbWU6ICdlbmFibGVkJyk7CiAgICB2ZXJpZnkoKCkgPT4gc2RrLmxvZ0V2ZW50KG5hbWU6ICdlbmFibGVkJykpLmNhbGxlZCgxKTsKICB9KTsKCiAgdGVzdCgKICAgICdzZW1hbnRpYyBldmVudHMgcHJlc2VydmUgdGhlaXIgZXhwZWN0ZWQgbmFtZXMgYW5kIHBhcmFtZXRlcnMnLAogICAgKCkgYXN5bmMgewogICAgICBhd2FpdCBjbGllbnQubG9nQ3VzdG9tRXZlbnQoY29uc3QgQW5hbHl0aWNzRXZlbnQobmFtZTogJ2N1c3RvbScpKTsKICAgICAgYXdhaXQgY2xpZW50LmxvZ0FwcE9wZW4oKTsKICAgICAgYXdhaXQgY2xpZW50LmxvZ1NjcmVlblZpZXcoc2NyZWVuTmFtZTogJ2hvbWUnLCBzY3JlZW5DbGFzczogJ0hvbWUnKTsKICAgICAgYXdhaXQgY2xpZW50LmxvZ0xvZ2luKGxvZ2luTWV0aG9kOiAnZW1haWwnKTsKICAgICAgYXdhaXQgY2xpZW50LmxvZ1NpZ25VcChzaWduVXBNZXRob2Q6ICdnb29nbGUnKTsKICAgICAgYXdhaXQgY2xpZW50LmxvZ1B1cmNoYXNlKGN1cnJlbmN5OiAnVVNEJywgdmFsdWU6IDMuNSk7CiAgICAgIHZlcmlmeSgKICAgICAgICAoKSA9PiBzZGsubG9nRXZlbnQobmFtZTogJ2xvZ2luJywgcGFyYW1ldGVyczogeydtZXRob2QnOiAnZW1haWwnfSksCiAgICAgICkuY2FsbGVkKDEpOwogICAgICB2ZXJpZnkoCiAgICAgICAgKCkgPT4gc2RrLmxvZ0V2ZW50KAogICAgICAgICAgbmFtZTogJ3B1cmNoYXNlJywKICAgICAgICAgIHBhcmFtZXRlcnM6IHsnY3VycmVuY3knOiAnVVNEJywgJ3ZhbHVlJzogMy41fSwKICAgICAgICApLAogICAgICApLmNhbGxlZCgxKTsKICAgICAgYXdhaXQgY2xpZW50LnNldFVzZXJJZChudWxsKTsKICAgICAgYXdhaXQgY2xpZW50LnNldFVzZXJQcm9wZXJ0eShuYW1lOiAncm9sZScsIHZhbHVlOiBudWxsKTsKICAgICAgYXdhaXQgY2xpZW50LnJlc2V0QW5hbHl0aWNzRGF0YSgpOwogICAgICBjbGllbnQuZGlzcG9zZSgpOwogICAgfSwKICApOwoKICB0ZXN0KCdTREsgZXZlbnQgYW5kIHByb3BlcnR5IGZhaWx1cmVzIGFyZSBjb250YWluZWQnLCAoKSBhc3luYyB7CiAgICB3aGVuKAogICAgICAoKSA9PiBzZGsubG9nRXZlbnQoCiAgICAgICAgbmFtZTogYW55KG5hbWVkOiAnbmFtZScpLAogICAgICAgIHBhcmFtZXRlcnM6IGFueShuYW1lZDogJ3BhcmFtZXRlcnMnKSwKICAgICAgKSwKICAgICkudGhlblRocm93KFN0YXRlRXJyb3IoJ2V2ZW50JykpOwogICAgd2hlbigKICAgICAgKCkgPT4gc2RrLnNldFVzZXJJZChpZDogYW55KG5hbWVkOiAnaWQnKSksCiAgICApLnRoZW5UaHJvdyhTdGF0ZUVycm9yKCd1c2VyJykpOwogICAgd2hlbigKICAgICAgKCkgPT4gc2RrLnNldFVzZXJQcm9wZXJ0eSgKICAgICAgICBuYW1lOiBhbnkobmFtZWQ6ICduYW1lJyksCiAgICAgICAgdmFsdWU6IGFueShuYW1lZDogJ3ZhbHVlJyksCiAgICAgICksCiAgICApLnRoZW5UaHJvdyhTdGF0ZUVycm9yKCdwcm9wZXJ0eScpKTsKICAgIHdoZW4oc2RrLnJlc2V0QW5hbHl0aWNzRGF0YSkudGhlblRocm93KFN0YXRlRXJyb3IoJ3Jlc2V0JykpOwogICAgd2hlbigKICAgICAgKCkgPT4gc2RrLnNldEFuYWx5dGljc0NvbGxlY3Rpb25FbmFibGVkKGFueSgpKSwKICAgICkudGhlblRocm93KFN0YXRlRXJyb3IoJ2NvbGxlY3Rpb24nKSk7CiAgICBhd2FpdCBjbGllbnQubG9nRXZlbnQobmFtZTogJ2V2ZW50Jyk7CiAgICBhd2FpdCBjbGllbnQuc2V0VXNlcklkKCd1c2VyJyk7CiAgICBhd2FpdCBjbGllbnQuc2V0VXNlclByb3BlcnR5KG5hbWU6ICdyb2xlJywgdmFsdWU6ICd2YWx1ZScpOwogICAgYXdhaXQgY2xpZW50LnJlc2V0QW5hbHl0aWNzRGF0YSgpOwogICAgYXdhaXQgY2xpZW50LnNldEFuYWx5dGljc0NvbGxlY3Rpb25FbmFibGVkKGZhbHNlKTsKICAgIHZlcmlmeSgoKSA9PiBsb2dnZXIuZShhbnkoKSwgYW55KCksIGFueSgpKSkuY2FsbGVkKDUpOwogIH0pOwoKICB0ZXN0KAogICAgJ21vZHVsZSBzdGFydHVwIGlzIGluamVjdGFibGUgYW5kIGhlbHBlcnMgcmVzb2x2ZSBmcmVzaCBjbGllbnRzIGFmdGVyIHJlc2V0JywKICAgICgpIGFzeW5jIHsKICAgICAgZGkucmVnaXN0ZXI8TG9nZ2VyPihsb2dnZXIpOwogICAgICBhd2FpdCBhbmFseXRpY3MuaW5pdChhbmFseXRpY3M6IHNkayk7CiAgICAgIGF3YWl0IEFuYWx5dGljc0hlbHBlci5sb2dFdmVudCgnYmVmb3JlJyk7CiAgICAgIGF3YWl0IGRpLnJlc2V0KCk7CiAgICAgIGRpLnJlZ2lzdGVyPExvZ2dlcj4obG9nZ2VyKTsKICAgICAgYXdhaXQgYW5hbHl0aWNzLmluaXQoCiAgICAgICAgYW5hbHl0aWNzOiBzZGssCiAgICAgICAgY29uZmlnOiBjb25zdCBEZWZhdWx0QW5hbHl0aWNzQ29uZmlnKGVuYWJsZUFuYWx5dGljczogZmFsc2UpLAogICAgICApOwogICAgICBhd2FpdCBBbmFseXRpY3NIZWxwZXIubG9nRXZlbnQoJ2FmdGVyJyk7CiAgICAgIHZlcmlmeSgoKSA9PiBzZGsubG9nRXZlbnQobmFtZTogJ2JlZm9yZScpKS5jYWxsZWQoMSk7CiAgICAgIHZlcmlmeU5ldmVyKCgpID0+IHNkay5sb2dFdmVudChuYW1lOiAnYWZ0ZXInKSk7CiAgICB9LAogICk7Cn0K", + "type": "text" + }, + { + "path": + "{{ name.snakeCase() }}/packages/{{analytics_dir}}/test/event_names_test.dart", + "data": + "aW1wb3J0ICdwYWNrYWdlOmFuYWx5dGljcy9hbmFseXRpY3MuZGFydCc7CmltcG9ydCAncGFja2FnZTpmbHV0dGVyX3Rlc3QvZmx1dHRlcl90ZXN0LmRhcnQnOwoKdm9pZCBtYWluKCkgewogIHRlc3QoJ2V2ZW50IGNhdGFsb2cga2VlcHMgc3RhYmxlIHVuaXF1ZSBuYW1lcycsICgpIHsKICAgIGZpbmFsIGV2ZW50cyA9IFsKICAgICAgQW5hbHl0aWNzRXZlbnRzLnVzZXIuYXV0aGVudGljYXRlZFJlZGlyZWN0LAogICAgICBBbmFseXRpY3NFdmVudHMudXNlci5wcm9maWxlVXBkYXRlZCwKICAgICAgQW5hbHl0aWNzRXZlbnRzLnVzZXIucHJlZmVyZW5jZXNDaGFuZ2VkLAogICAgICBBbmFseXRpY3NFdmVudHMudXNlci5vbmJvYXJkaW5nQ29tcGxldGVkLAogICAgICBBbmFseXRpY3NFdmVudHMudXNlci5hY2NvdW50RGVsZXRlZCwKICAgICAgQW5hbHl0aWNzRXZlbnRzLmF1dGguc2lnbkluLAogICAgICBBbmFseXRpY3NFdmVudHMuYXV0aC5zaWduVXAsCiAgICAgIEFuYWx5dGljc0V2ZW50cy5hdXRoLnNpZ25PdXQsCiAgICAgIEFuYWx5dGljc0V2ZW50cy5hdXRoLnBhc3N3b3JkUmVzZXQsCiAgICAgIEFuYWx5dGljc0V2ZW50cy5hdXRoLmZhaWxlZCwKICAgICAgQW5hbHl0aWNzRXZlbnRzLmF1dGguc29jaWFsTG9naW4sCiAgICAgIEFuYWx5dGljc0V2ZW50cy5uYXZpZ2F0aW9uLnNjcmVlblZpZXcsCiAgICAgIEFuYWx5dGljc0V2ZW50cy5uYXZpZ2F0aW9uLnRhYlN3aXRjaGVkLAogICAgICBBbmFseXRpY3NFdmVudHMubmF2aWdhdGlvbi5iYWNrUHJlc3NlZCwKICAgICAgQW5hbHl0aWNzRXZlbnRzLm5hdmlnYXRpb24uZGVlcExpbmtPcGVuZWQsCiAgICAgIEFuYWx5dGljc0V2ZW50cy5mZWF0dXJlLnVzZWQsCiAgICAgIEFuYWx5dGljc0V2ZW50cy5mZWF0dXJlLnR1dG9yaWFsU3RhcnRlZCwKICAgICAgQW5hbHl0aWNzRXZlbnRzLmZlYXR1cmUudHV0b3JpYWxDb21wbGV0ZWQsCiAgICAgIEFuYWx5dGljc0V2ZW50cy5mZWF0dXJlLmZlZWRiYWNrR2l2ZW4sCiAgICAgIEFuYWx5dGljc0V2ZW50cy5mZWF0dXJlLmJ1dHRvblByZXNzZWQsCiAgICAgIEFuYWx5dGljc0V2ZW50cy5lcnJvci5hcHBFcnJvciwKICAgICAgQW5hbHl0aWNzRXZlbnRzLmVycm9yLm5ldHdvcmtFcnJvciwKICAgICAgQW5hbHl0aWNzRXZlbnRzLmVycm9yLmNyYXNoLAogICAgICBBbmFseXRpY3NFdmVudHMuZXJyb3IuYXBpRXJyb3IsCiAgICAgIEFuYWx5dGljc0V2ZW50cy5lcnJvci52YWxpZGF0aW9uRXJyb3IsCiAgICAgIEFuYWx5dGljc0V2ZW50cy5hcHAub3BlbiwKICAgICAgQW5hbHl0aWNzRXZlbnRzLmFwcC5iYWNrZ3JvdW5kLAogICAgICBBbmFseXRpY3NFdmVudHMuYXBwLmZvcmVncm91bmQsCiAgICAgIEFuYWx5dGljc0V2ZW50cy5hcHAudXBkYXRlZCwKICAgICAgQW5hbHl0aWNzRXZlbnRzLmFwcC5pbnN0YWxsZWQsCiAgICAgIEFuYWx5dGljc0V2ZW50cy5hcHAudW5pbnN0YWxsZWQsCiAgICAgIEFuYWx5dGljc0V2ZW50cy5wcm9maWxlLnZpZXdlZCwKICAgICAgQW5hbHl0aWNzRXZlbnRzLnByb2ZpbGUuZWRpdGVkLAogICAgICBBbmFseXRpY3NFdmVudHMucHJvZmlsZS5waG90b1VwZGF0ZWQsCiAgICAgIEFuYWx5dGljc0V2ZW50cy5wcm9maWxlLnNldHRpbmdzQ2hhbmdlZCwKICAgICAgQW5hbHl0aWNzRXZlbnRzLnByb2ZpbGUucHJpdmFjeVVwZGF0ZWQsCiAgICBdOwogICAgZXhwZWN0KGV2ZW50cywgWwogICAgICAndXNlcl9hdXRoZW50aWNhdGVkX3JlZGlyZWN0JywKICAgICAgJ3VzZXJfcHJvZmlsZV91cGRhdGVkJywKICAgICAgJ3VzZXJfcHJlZmVyZW5jZXNfY2hhbmdlZCcsCiAgICAgICd1c2VyX29uYm9hcmRpbmdfY29tcGxldGVkJywKICAgICAgJ3VzZXJfYWNjb3VudF9kZWxldGVkJywKICAgICAgJ2F1dGhfc2lnbl9pbicsCiAgICAgICdhdXRoX3NpZ25fdXAnLAogICAgICAnYXV0aF9zaWduX291dCcsCiAgICAgICdhdXRoX3Bhc3N3b3JkX3Jlc2V0JywKICAgICAgJ2F1dGhfZmFpbGVkJywKICAgICAgJ2F1dGhfc29jaWFsX2xvZ2luJywKICAgICAgJ3NjcmVlbl92aWV3JywKICAgICAgJ25hdmlnYXRpb25fdGFiX3N3aXRjaGVkJywKICAgICAgJ25hdmlnYXRpb25fYmFja19wcmVzc2VkJywKICAgICAgJ25hdmlnYXRpb25fZGVlcF9saW5rX29wZW5lZCcsCiAgICAgICdmZWF0dXJlX3VzZWQnLAogICAgICAnZmVhdHVyZV90dXRvcmlhbF9zdGFydGVkJywKICAgICAgJ2ZlYXR1cmVfdHV0b3JpYWxfY29tcGxldGVkJywKICAgICAgJ2ZlYXR1cmVfZmVlZGJhY2tfZ2l2ZW4nLAogICAgICAnYnV0dG9uX3ByZXNzZWQnLAogICAgICAnYXBwX2Vycm9yJywKICAgICAgJ25ldHdvcmtfZXJyb3InLAogICAgICAnYXBwX2NyYXNoJywKICAgICAgJ2FwaV9lcnJvcicsCiAgICAgICd2YWxpZGF0aW9uX2Vycm9yJywKICAgICAgJ2FwcF9vcGVuJywKICAgICAgJ2FwcF9iYWNrZ3JvdW5kJywKICAgICAgJ2FwcF9mb3JlZ3JvdW5kJywKICAgICAgJ2FwcF91cGRhdGVkJywKICAgICAgJ2FwcF9pbnN0YWxsZWQnLAogICAgICAnYXBwX3VuaW5zdGFsbGVkJywKICAgICAgJ3Byb2ZpbGVfdmlld2VkJywKICAgICAgJ3Byb2ZpbGVfZWRpdGVkJywKICAgICAgJ3Byb2ZpbGVfcGhvdG9fdXBkYXRlZCcsCiAgICAgICdwcm9maWxlX3NldHRpbmdzX2NoYW5nZWQnLAogICAgICAncHJvZmlsZV9wcml2YWN5X3VwZGF0ZWQnLAogICAgXSk7CiAgICBleHBlY3QoZXZlbnRzLnRvU2V0KCksIGhhc0xlbmd0aChldmVudHMubGVuZ3RoKSk7CiAgfSk7Cn0K", + "type": "text" + }, + { + "path": + "{{ name.snakeCase() }}/packages/{{analytics_dir}}/test/helper_test.dart", + "data": + "aW1wb3J0ICdwYWNrYWdlOmFuYWx5dGljcy9hbmFseXRpY3MuZGFydCc7CmltcG9ydCAncGFja2FnZTpjb3JlL2NvcmUuZGFydCc7CmltcG9ydCAncGFja2FnZTpkaS9kaS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZsdXR0ZXIvbWF0ZXJpYWwuZGFydCc7CmltcG9ydCAncGFja2FnZTpmbHV0dGVyX3Rlc3QvZmx1dHRlcl90ZXN0LmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6bW9ja3RhaWwvbW9ja3RhaWwuZGFydCc7CgpjbGFzcyBfQ2xpZW50IGV4dGVuZHMgTW9jayBpbXBsZW1lbnRzIEFuYWx5dGljc0NsaWVudCB7fQoKY2xhc3MgX0xvZ2dlciBleHRlbmRzIE1vY2sgaW1wbGVtZW50cyBMb2dnZXIge30KCnZvaWQgbWFpbigpIHsKICB0ZWFyRG93bihkaS5yZXNldCk7CiAgc2V0VXBBbGwoKCkgPT4gcmVnaXN0ZXJGYWxsYmFja1ZhbHVlKGNvbnN0IEFuYWx5dGljc0V2ZW50KG5hbWU6ICdmYWxsYmFjaycpKSk7CiAgdGVzdCgKICAgICdhbGwgaGVscGVycyB0b2xlcmF0ZSBhYnNlbnQgc2VydmljZXMsIGZvcndhcmQgY2FsbHMgYW5kIGNvbnRhaW4gYXN5bmNocm9ub3VzIGZhaWx1cmVzJywKICAgICgpIGFzeW5jIHsKICAgICAgZmluYWwgbG9nZ2VyID0gX0xvZ2dlcigpOwogICAgICBmaW5hbCBjbGllbnQgPSBfQ2xpZW50KCk7CiAgICAgIGZpbmFsIG9wZXJhdGlvbnMgPSA8RnV0dXJlPHZvaWQ+IEZ1bmN0aW9uKCk+WwogICAgICAgICgpID0+IEFuYWx5dGljc0hlbHBlci5sb2dFdmVudCgnY3VzdG9tJywgcGFyYW1ldGVyczogeydrZXknOiAxfSksCiAgICAgICAgKCkgPT4gQW5hbHl0aWNzSGVscGVyLmxvZ1NpZ25JbihtZXRob2Q6ICdlbWFpbCcpLAogICAgICAgICgpID0+IEFuYWx5dGljc0hlbHBlci5sb2dTaWduVXAobWV0aG9kOiAnZW1haWwnKSwKICAgICAgICAoKSA9PiBBbmFseXRpY3NIZWxwZXIuc2V0VXNlcklkKCd1c2VyJyksCiAgICAgICAgKCkgPT4gQW5hbHl0aWNzSGVscGVyLnNldFVzZXJQcm9wZXJ0eShuYW1lOiAncm9sZScsIHZhbHVlOiAndGVzdGVyJyksCiAgICAgICAgKCkgPT4gQW5hbHl0aWNzSGVscGVyLmxvZ0FwcE9wZW4oKSwKICAgICAgICAoKSA9PiBBbmFseXRpY3NIZWxwZXIubG9nQ3VzdG9tRXZlbnQoCiAgICAgICAgICBjb25zdCBBbmFseXRpY3NFdmVudChuYW1lOiAnY3VzdG9tJyksCiAgICAgICAgKSwKICAgICAgICAoKSA9PiBBbmFseXRpY3NIZWxwZXIubG9nRmVhdHVyZVVzZWQoCiAgICAgICAgICAnc2VhcmNoJywKICAgICAgICAgIHBhcmFtZXRlcnM6IHsnc291cmNlJzogJ2hvbWUnfSwKICAgICAgICApLAogICAgICAgICgpID0+IEFuYWx5dGljc0hlbHBlci5sb2dCdXR0b25QcmVzc2VkKAogICAgICAgICAgJ3N1Ym1pdCcsCiAgICAgICAgICBzY3JlZW5OYW1lOiAnaG9tZScsCiAgICAgICAgICBwYXJhbWV0ZXJzOiB7J3NvdXJjZSc6ICdsaW5rJ30sCiAgICAgICAgKSwKICAgICAgICAoKSA9PiBBbmFseXRpY3NIZWxwZXIubG9nQXBwRXJyb3IoCiAgICAgICAgICAndmFsaWRhdGlvbicsCiAgICAgICAgICBlcnJvck1lc3NhZ2U6ICdpbnZhbGlkJywKICAgICAgICAgIHBhcmFtZXRlcnM6IHsnc291cmNlJzogJ2xpbmsnfSwKICAgICAgICApLAogICAgICBdOwogICAgICBmb3IgKGZpbmFsIG9wZXJhdGlvbiBpbiBvcGVyYXRpb25zKSB7CiAgICAgICAgYXdhaXQgb3BlcmF0aW9uKCk7CiAgICAgIH0KICAgICAgZGkucmVnaXN0ZXI8TG9nZ2VyPihsb2dnZXIpOwogICAgICBkaS5yZWdpc3RlcjxBbmFseXRpY3NDbGllbnQ+KGNsaWVudCk7CiAgICAgIGZpbmFsIHN0dWJzID0gWwogICAgICAgICgpID0+IGNsaWVudC5sb2dFdmVudCgKICAgICAgICAgIG5hbWU6IGFueShuYW1lZDogJ25hbWUnKSwKICAgICAgICAgIHBhcmFtZXRlcnM6IGFueShuYW1lZDogJ3BhcmFtZXRlcnMnKSwKICAgICAgICApLAogICAgICAgICgpID0+IGNsaWVudC5sb2dMb2dpbigKICAgICAgICAgIGxvZ2luTWV0aG9kOiBhbnkobmFtZWQ6ICdsb2dpbk1ldGhvZCcpLAogICAgICAgICAgcGFyYW1ldGVyczogYW55KG5hbWVkOiAncGFyYW1ldGVycycpLAogICAgICAgICksCiAgICAgICAgKCkgPT4gY2xpZW50LmxvZ1NpZ25VcCgKICAgICAgICAgIHNpZ25VcE1ldGhvZDogYW55KG5hbWVkOiAnc2lnblVwTWV0aG9kJyksCiAgICAgICAgICBwYXJhbWV0ZXJzOiBhbnkobmFtZWQ6ICdwYXJhbWV0ZXJzJyksCiAgICAgICAgKSwKICAgICAgICAoKSA9PiBjbGllbnQuc2V0VXNlcklkKGFueSgpKSwKICAgICAgICAoKSA9PiBjbGllbnQuc2V0VXNlclByb3BlcnR5KAogICAgICAgICAgbmFtZTogYW55KG5hbWVkOiAnbmFtZScpLAogICAgICAgICAgdmFsdWU6IGFueShuYW1lZDogJ3ZhbHVlJyksCiAgICAgICAgKSwKICAgICAgICAoKSA9PiBjbGllbnQubG9nQXBwT3BlbihwYXJhbWV0ZXJzOiBhbnkobmFtZWQ6ICdwYXJhbWV0ZXJzJykpLAogICAgICAgICgpID0+IGNsaWVudC5sb2dDdXN0b21FdmVudChhbnkoKSksCiAgICAgIF07CiAgICAgIGZvciAoZmluYWwgc3R1YiBpbiBzdHVicykgewogICAgICAgIHdoZW4oc3R1YikudGhlbkFuc3dlcigoXykgYXN5bmMge30pOwogICAgICB9CiAgICAgIGZvciAoZmluYWwgb3BlcmF0aW9uIGluIG9wZXJhdGlvbnMpIHsKICAgICAgICBhd2FpdCBvcGVyYXRpb24oKTsKICAgICAgfQogICAgICB2ZXJpZnkoKCkgPT4gY2xpZW50LmxvZ0xvZ2luKGxvZ2luTWV0aG9kOiAnZW1haWwnKSkuY2FsbGVkKDEpOwogICAgICB2ZXJpZnkoKCkgPT4gY2xpZW50LnNldFVzZXJJZCgndXNlcicpKS5jYWxsZWQoMSk7CiAgICAgIGZvciAoZmluYWwgc3R1YiBpbiBzdHVicykgewogICAgICAgIHdoZW4oc3R1YikudGhlbkFuc3dlcigoXykgYXN5bmMgPT4gdGhyb3cgU3RhdGVFcnJvcignb2ZmbGluZScpKTsKICAgICAgfQogICAgICBmb3IgKGZpbmFsIG9wZXJhdGlvbiBpbiBvcGVyYXRpb25zKSB7CiAgICAgICAgYXdhaXQgb3BlcmF0aW9uKCk7CiAgICAgIH0KICAgICAgdmVyaWZ5KCgpID0+IGxvZ2dlci5lKGFueSgpLCBhbnkoKSwgYW55KCkpKS5jYWxsZWQob3BlcmF0aW9ucy5sZW5ndGgpOwogICAgfSwKICApOwoKICB0ZXN0KAogICAgJ3JvdXRlIG9ic2VydmVyIHRyYWNrcyBuYW1lZCBwYWdlcyBhbmQgY2F0Y2hlcyBhc3luY2hyb25vdXMgZmFpbHVyZXMnLAogICAgKCkgYXN5bmMgewogICAgICBmaW5hbCBjbGllbnQgPSBfQ2xpZW50KCk7CiAgICAgIGZpbmFsIGxvZ2dlciA9IF9Mb2dnZXIoKTsKICAgICAgd2hlbigKICAgICAgICAoKSA9PiBjbGllbnQubG9nU2NyZWVuVmlldyhzY3JlZW5OYW1lOiBhbnkobmFtZWQ6ICdzY3JlZW5OYW1lJykpLAogICAgICApLnRoZW5BbnN3ZXIoKF8pIGFzeW5jIHt9KTsKICAgICAgZmluYWwgb2JzZXJ2ZXIgPSBBbmFseXRpY3NSb3V0ZU9ic2VydmVyKGNsaWVudDogY2xpZW50LCBsb2dnZXI6IGxvZ2dlcik7CiAgICAgIGZpbmFsIHBhZ2UgPSBNYXRlcmlhbFBhZ2VSb3V0ZTx2b2lkPigKICAgICAgICBzZXR0aW5nczogY29uc3QgUm91dGVTZXR0aW5ncyhuYW1lOiAnL2hvbWUnKSwKICAgICAgICBidWlsZGVyOiAoXykgPT4gY29uc3QgU2l6ZWRCb3goKSwKICAgICAgKTsKICAgICAgZmluYWwgdW5uYW1lZCA9IE1hdGVyaWFsUGFnZVJvdXRlPHZvaWQ+KGJ1aWxkZXI6IChfKSA9PiBjb25zdCBTaXplZEJveCgpKTsKICAgICAgb2JzZXJ2ZXIuZGlkUHVzaChwYWdlLCBudWxsKTsKICAgICAgb2JzZXJ2ZXIuZGlkUG9wKHVubmFtZWQsIHBhZ2UpOwogICAgICBvYnNlcnZlci5kaWRSZXBsYWNlKG5ld1JvdXRlOiBwYWdlKTsKICAgICAgb2JzZXJ2ZXIuZGlkUHVzaCh1bm5hbWVkLCBwYWdlKTsKICAgICAgb2JzZXJ2ZXIuZGlkUG9wKHBhZ2UsIG51bGwpOwogICAgICBhd2FpdCBwdW1wRXZlbnRRdWV1ZSgpOwogICAgICB2ZXJpZnkoKCkgPT4gY2xpZW50LmxvZ1NjcmVlblZpZXcoc2NyZWVuTmFtZTogJy9ob21lJykpLmNhbGxlZCgzKTsKICAgICAgd2hlbigKICAgICAgICAoKSA9PiBjbGllbnQubG9nU2NyZWVuVmlldyhzY3JlZW5OYW1lOiBhbnkobmFtZWQ6ICdzY3JlZW5OYW1lJykpLAogICAgICApLnRoZW5BbnN3ZXIoKF8pIGFzeW5jID0+IHRocm93IFN0YXRlRXJyb3IoJ29mZmxpbmUnKSk7CiAgICAgIG9ic2VydmVyLmRpZFB1c2gocGFnZSwgbnVsbCk7CiAgICAgIGF3YWl0IHB1bXBFdmVudFF1ZXVlKCk7CiAgICAgIHZlcmlmeSgoKSA9PiBsb2dnZXIuZShhbnkoKSwgYW55KCksIGFueSgpKSkuY2FsbGVkKDEpOwogICAgICBwYWdlLmRpc3Bvc2UoKTsKICAgICAgdW5uYW1lZC5kaXNwb3NlKCk7CiAgICB9LAogICk7CgogIHRlc3QoJ2V2ZW50IHZhbHVlIGVxdWFsaXR5IGFncmVlcyB3aXRoIGhhc2ggY29kZXMgYW5kIG1hcCBzZXJpYWxpemF0aW9uJywgKCkgewogICAgZmluYWwgYSA9IEFuYWx5dGljc0V2ZW50KG5hbWU6ICdldmVudCcsIHBhcmFtZXRlcnM6IHsnb25lJzogMSwgJ3R3byc6IDJ9KTsKICAgIGZpbmFsIGIgPSBBbmFseXRpY3NFdmVudChuYW1lOiAnZXZlbnQnLCBwYXJhbWV0ZXJzOiB7J3R3byc6IDIsICdvbmUnOiAxfSk7CiAgICBleHBlY3QoYSwgYik7CiAgICBleHBlY3QoYS5oYXNoQ29kZSwgYi5oYXNoQ29kZSk7CiAgICBleHBlY3QoYSwgYSk7CiAgICBleHBlY3QoYS50b01hcCgpWyduYW1lJ10sICdldmVudCcpOwogICAgZXhwZWN0KGEudG9TdHJpbmcoKSwgY29udGFpbnMoJ2V2ZW50JykpOwogICAgZXhwZWN0KGEsIGlzTm90KGNvbnN0IEFuYWx5dGljc0V2ZW50KG5hbWU6ICdldmVudCcpKSk7CiAgICBleHBlY3QoY29uc3QgQW5hbHl0aWNzRXZlbnQobmFtZTogJ2V2ZW50JyksIGlzTm90KGEpKTsKICAgIGV4cGVjdCgKICAgICAgYSwKICAgICAgaXNOb3QoY29uc3QgQW5hbHl0aWNzRXZlbnQobmFtZTogJ2V2ZW50JywgcGFyYW1ldGVyczogeydvbmUnOiAxfSkpLAogICAgKTsKICAgIGV4cGVjdCgKICAgICAgYSwKICAgICAgaXNOb3QoCiAgICAgICAgY29uc3QgQW5hbHl0aWNzRXZlbnQobmFtZTogJ2V2ZW50JywgcGFyYW1ldGVyczogeydvbmUnOiAxLCAndHdvJzogM30pLAogICAgICApLAogICAgKTsKICAgIGV4cGVjdCgKICAgICAgY29uc3QgQW5hbHl0aWNzRXZlbnQobmFtZTogJ2VtcHR5JyksCiAgICAgIGNvbnN0IEFuYWx5dGljc0V2ZW50KG5hbWU6ICdlbXB0eScpLAogICAgKTsKICAgIGZpbmFsIGNvbmZpZyA9IGNvbnN0IERlZmF1bHRBbmFseXRpY3NDb25maWcodXNlcklkOiAndXNlcicpCiAgICAgICAgLmNvcHlXaXRoKAogICAgICAgICAgZW5hYmxlQW5hbHl0aWNzOiBmYWxzZSwKICAgICAgICAgIGVuYWJsZURlYnVnTG9nZ2luZzogdHJ1ZSwKICAgICAgICAgIGRlZmF1bHRVc2VyUHJvcGVydGllczogeydyb2xlJzogJ3Rlc3QnfSwKICAgICAgICApCiAgICAgICAgLmNvcHlXaXRoKCk7CiAgICBleHBlY3QoY29uZmlnLmVuYWJsZUFuYWx5dGljcywgaXNGYWxzZSk7CiAgICBleHBlY3QoY29uZmlnLmVuYWJsZURlYnVnTG9nZ2luZywgaXNUcnVlKTsKICAgIGV4cGVjdChjb25maWcudXNlcklkLCAndXNlcicpOwogICAgZXhwZWN0KGNvbmZpZy5kZWZhdWx0VXNlclByb3BlcnRpZXMsIHsncm9sZSc6ICd0ZXN0J30pOwogIH0pOwp9Cg==", + "type": "text" + }, { "path": "{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/lib/crashlytics.dart", "data": - "bGlicmFyeTsKCmltcG9ydCAnZGFydDphc3luYyc7CgppbXBvcnQgJ3BhY2thZ2U6Y29yZS9jb3JlLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Y3Jhc2hseXRpY3Mvc3JjL2NsaWVudC9pbmRleC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmNyYXNobHl0aWNzL3NyYy9jb25maWcvaW5kZXguZGFydCc7CmltcG9ydCAncGFja2FnZTpkaS9kaS5kYXJ0JzsKCmV4cG9ydCAnc3JjL2NsaWVudC9pbmRleC5kYXJ0JzsKZXhwb3J0ICdzcmMvY29uZmlnL2luZGV4LmRhcnQnOwpleHBvcnQgJ3NyYy9tb2RlbHMvaW5kZXguZGFydCc7CgovLy8gSW5pdGlhbGl6ZSB0aGUgY3Jhc2hseXRpY3MgbW9kdWxlIHdpdGggZGVwZW5kZW5jeSBpbmplY3Rpb24KRnV0dXJlPHZvaWQ+IGluaXQoe0NyYXNobHl0aWNzQ29uZmlnPyBjb25maWd9KSBhc3luYyB7CiAgYXdhaXQgcmVnaXN0ZXJDcmFzaGx5dGljc1dpdGhESShjb25maWcgPz8gY29uc3QgRGVmYXVsdENyYXNobHl0aWNzQ29uZmlnKCkpOwogIGZpbmFsIGxvZ2dlciA9IGRpLmdldDxMb2dnZXI+KCk7CiAgbG9nZ2VyLmkoJ/CflKUgQ3Jhc2hseXRpY3MgbW9kdWxlIGluaXRpYWxpemVkJyk7Cn0KCi8vLyBSZWdpc3RlciBjcmFzaGx5dGljcyBjb21wb25lbnRzIHdpdGggREkgY29udGFpbmVyCkZ1dHVyZTx2b2lkPiByZWdpc3RlckNyYXNobHl0aWNzV2l0aERJKENyYXNobHl0aWNzQ29uZmlnIGNvbmZpZykgYXN5bmMgewogIGZpbmFsIGxvZ2dlciA9IGRpLmdldDxMb2dnZXI+KCk7CgogIHRyeSB7CiAgICAvLyBSZWdpc3RlciBjb25maWcKICAgIGRpLnJlZ2lzdGVyPENyYXNobHl0aWNzQ29uZmlnPihjb25maWcpOwoKICAgIC8vIENyZWF0ZSBhbmQgcmVnaXN0ZXIgY3Jhc2hseXRpY3MgY2xpZW50CiAgICBmaW5hbCBjbGllbnQgPSBGaXJlYmFzZUNyYXNobHl0aWNzQ2xpZW50KGNvbmZpZzogY29uZmlnLCBsb2dnZXI6IGxvZ2dlcik7CiAgICBkaS5yZWdpc3RlcjxDcmFzaGx5dGljc0NsaWVudD4oCiAgICAgIGNsaWVudCwKICAgICAgZGlzcG9zZTogKGNsaWVudCkgPT4gY2xpZW50LmRpc3Bvc2UoKSwKICAgICk7CgogICAgLy8gSW5pdGlhbGl6ZSB0aGUgY2xpZW50CiAgICBhd2FpdCBjbGllbnQuaW5pdGlhbGl6ZSgpOwoKICAgIC8vIENoZWNrIGlmIHRoZXJlIGFyZSBhbnkgdW5zZW50IHJlcG9ydHMKICAgIHVuYXdhaXRlZCgKICAgICAgY2xpZW50LmNoZWNrRm9yVW5zZW50UmVwb3J0cygpLnRoZW48dm9pZD4oKGhhc1JlcG9ydHMpIHsKICAgICAgICBpZiAoaGFzUmVwb3J0cykgewogICAgICAgICAgbG9nZ2VyLncoJ+KaoO+4jyBUaGVyZSBhcmUgdW5zZW50IGNyYXNoIHJlcG9ydHMuJyk7CiAgICAgICAgICB1bmF3YWl0ZWQoY2xpZW50LnNlbmRVbnNlbnRSZXBvcnRzKCkpOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBsb2dnZXIuaSgn4pyFIE5vIHVuc2VudCBjcmFzaCByZXBvcnRzIGZvdW5kLicpOwogICAgICAgIH0KICAgICAgfSksCiAgICApOwoKICAgIGxvZ2dlci5pKCfwn5SlIENyYXNobHl0aWNzIHJlZ2lzdGVyZWQgd2l0aCBESSBjb250YWluZXInKTsKICB9IGNhdGNoIChlLCBzdGFja1RyYWNlKSB7CiAgICBsb2dnZXIuZSgn4p2MIEZhaWxlZCB0byByZWdpc3RlciBjcmFzaGx5dGljcyB3aXRoIERJJywgZSwgc3RhY2tUcmFjZSk7CiAgICByZXRocm93OwogIH0KfQo=", + "bGlicmFyeTsKCmltcG9ydCAncGFja2FnZTpjb3JlL2NvcmUuZGFydCc7CmltcG9ydCAncGFja2FnZTpjcmFzaGx5dGljcy9zcmMvY2xpZW50L2luZGV4LmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Y3Jhc2hseXRpY3Mvc3JjL2NvbmZpZy9pbmRleC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZmlyZWJhc2VfY3Jhc2hseXRpY3MvZmlyZWJhc2VfY3Jhc2hseXRpY3MuZGFydCc7CgpleHBvcnQgJ3NyYy9jbGllbnQvaW5kZXguZGFydCc7CmV4cG9ydCAnc3JjL2NvbmZpZy9pbmRleC5kYXJ0JzsKZXhwb3J0ICdzcmMvbW9kZWxzL2luZGV4LmRhcnQnOwoKLy8vIEluaXRpYWxpemUgdGhlIGNyYXNobHl0aWNzIG1vZHVsZSB3aXRoIGRlcGVuZGVuY3kgaW5qZWN0aW9uCkZ1dHVyZTx2b2lkPiBpbml0KHsKICBDcmFzaGx5dGljc0NvbmZpZz8gY29uZmlnLAogIEZpcmViYXNlQ3Jhc2hseXRpY3M/IGNyYXNobHl0aWNzLAp9KSBhc3luYyB7CiAgYXdhaXQgcmVnaXN0ZXJDcmFzaGx5dGljc1dpdGhESSgKICAgIGNvbmZpZyA/PyBjb25zdCBEZWZhdWx0Q3Jhc2hseXRpY3NDb25maWcoKSwKICAgIGNyYXNobHl0aWNzOiBjcmFzaGx5dGljcywKICApOwogIGZpbmFsIGxvZ2dlciA9IGRpLmdldDxMb2dnZXI+KCk7CiAgbG9nZ2VyLmkoJ/CflKUgQ3Jhc2hseXRpY3MgbW9kdWxlIGluaXRpYWxpemVkJyk7Cn0KCi8vLyBSZWdpc3RlciBjcmFzaGx5dGljcyBjb21wb25lbnRzIHdpdGggREkgY29udGFpbmVyCkZ1dHVyZTx2b2lkPiByZWdpc3RlckNyYXNobHl0aWNzV2l0aERJKAogIENyYXNobHl0aWNzQ29uZmlnIGNvbmZpZywgewogIEZpcmViYXNlQ3Jhc2hseXRpY3M/IGNyYXNobHl0aWNzLAp9KSBhc3luYyB7CiAgZmluYWwgbG9nZ2VyID0gZGkuZ2V0PExvZ2dlcj4oKTsKCiAgZmluYWwgY2xpZW50ID0gRmlyZWJhc2VDcmFzaGx5dGljc0NsaWVudCgKICAgIGNvbmZpZzogY29uZmlnLAogICAgbG9nZ2VyOiBsb2dnZXIsCiAgICBjcmFzaGx5dGljczogY3Jhc2hseXRpY3MgPz8gRmlyZWJhc2VDcmFzaGx5dGljcy5pbnN0YW5jZSwKICApOwogIHRyeSB7CiAgICAvLyBQdWJsaXNoIG9ubHkgYSBmdWxseSBpbml0aWFsaXplZCBjbGllbnQ7IGZhaWxlZCBzdGFydHVwIHJlbWFpbnMgcmV0cnlhYmxlLgogICAgYXdhaXQgY2xpZW50LmluaXRpYWxpemUoKTsKCiAgICAvLyBDaGVjayBpZiB0aGVyZSBhcmUgYW55IHVuc2VudCByZXBvcnRzCiAgICBpZiAoYXdhaXQgY2xpZW50LmNoZWNrRm9yVW5zZW50UmVwb3J0cygpKSB7CiAgICAgIGxvZ2dlci53KCfimqDvuI8gVGhlcmUgYXJlIHVuc2VudCBjcmFzaCByZXBvcnRzLicpOwogICAgICBhd2FpdCBjbGllbnQuc2VuZFVuc2VudFJlcG9ydHMoKTsKICAgIH0gZWxzZSB7CiAgICAgIGxvZ2dlci5pKCfinIUgTm8gdW5zZW50IGNyYXNoIHJlcG9ydHMgZm91bmQuJyk7CiAgICB9CgogICAgZGkucmVnaXN0ZXI8Q3Jhc2hseXRpY3NDb25maWc+KGNvbmZpZyk7CiAgICBkaS5yZWdpc3RlcjxDcmFzaGx5dGljc0NsaWVudD4oCiAgICAgIGNsaWVudCwKICAgICAgZGlzcG9zZTogKGNsaWVudCkgPT4gY2xpZW50LmRpc3Bvc2UoKSwKICAgICk7CiAgICBsb2dnZXIuaSgn8J+UpSBDcmFzaGx5dGljcyByZWdpc3RlcmVkIHdpdGggREkgY29udGFpbmVyJyk7CiAgfSBjYXRjaCAoZSwgc3RhY2tUcmFjZSkgewogICAgY2xpZW50LmRpc3Bvc2UoKTsKICAgIGxvZ2dlci5lKCfinYwgRmFpbGVkIHRvIHJlZ2lzdGVyIGNyYXNobHl0aWNzIHdpdGggREknLCBlLCBzdGFja1RyYWNlKTsKICAgIHJldGhyb3c7CiAgfQp9Cg==", "type": "text" }, { @@ -904,7 +1033,7 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "path": "{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/lib/src/client/firebase_crashlytics_client.dart", "data": - "aW1wb3J0ICdkYXJ0OmFzeW5jJzsKaW1wb3J0ICdkYXJ0OmNvbGxlY3Rpb24nOwoKaW1wb3J0ICdwYWNrYWdlOmNvcmUvY29yZS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmNyYXNobHl0aWNzL3NyYy9jbGllbnQvY3Jhc2hseXRpY3NfY2xpZW50LmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Y3Jhc2hseXRpY3Mvc3JjL2NvbmZpZy9jcmFzaGx5dGljc19jb25maWcuZGFydCc7CmltcG9ydCAncGFja2FnZTpjcmFzaGx5dGljcy9zcmMvbW9kZWxzL3VzZXJfbWV0YWRhdGEuZGFydCc7CmltcG9ydCAncGFja2FnZTpkaS9kaS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZpcmViYXNlX2NyYXNobHl0aWNzL2ZpcmViYXNlX2NyYXNobHl0aWNzLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlci9mb3VuZGF0aW9uLmRhcnQnOwoKY2xhc3MgRmlyZWJhc2VDcmFzaGx5dGljc0NsaWVudCBpbXBsZW1lbnRzIENyYXNobHl0aWNzQ2xpZW50IHsKICBGaXJlYmFzZUNyYXNobHl0aWNzQ2xpZW50KHtyZXF1aXJlZCB0aGlzLmNvbmZpZywgTG9nZ2VyPyBsb2dnZXJ9KQogICAgOiBfbG9nZ2VyID0gbG9nZ2VyID8/IGRpLmdldDxMb2dnZXI+KCk7CgogIGZpbmFsIENyYXNobHl0aWNzQ29uZmlnIGNvbmZpZzsKICBmaW5hbCBMb2dnZXIgX2xvZ2dlcjsKICBsYXRlIGZpbmFsIEZpcmViYXNlQ3Jhc2hseXRpY3MgX2NyYXNobHl0aWNzOwogIGZpbmFsIFF1ZXVlPFN0cmluZz4gX2xvZ0J1ZmZlciA9IFF1ZXVlPFN0cmluZz4oKTsKICBib29sIF9pc0luaXRpYWxpemVkID0gZmFsc2U7CgogIEBvdmVycmlkZQogIEZ1dHVyZTx2b2lkPiBpbml0aWFsaXplKCkgYXN5bmMgewogICAgdHJ5IHsKICAgICAgX2NyYXNobHl0aWNzID0gRmlyZWJhc2VDcmFzaGx5dGljcy5pbnN0YW5jZTsKCiAgICAgIC8vIFNldCBjcmFzaGx5dGljcyBjb2xsZWN0aW9uIGVuYWJsZWQgYmFzZWQgb24gY29uZmlnCiAgICAgIGF3YWl0IF9jcmFzaGx5dGljcy5zZXRDcmFzaGx5dGljc0NvbGxlY3Rpb25FbmFibGVkKAogICAgICAgIGNvbmZpZy5lbmFibGVJbkRlYnVnTW9kZSB8fCBrUmVsZWFzZU1vZGUsCiAgICAgICk7CgogICAgICAvLyBTZXQgdXAgYXV0b21hdGljIEZsdXR0ZXIgZXJyb3IgaGFuZGxpbmcKICAgICAgaWYgKGNvbmZpZy5lbmFibGVBdXRvbWF0aWNEYXRhQ29sbGVjdGlvbikgewogICAgICAgIEZsdXR0ZXJFcnJvci5vbkVycm9yID0gKGVycm9yRGV0YWlscykgewogICAgICAgICAgX2NyYXNobHl0aWNzLnJlY29yZEZsdXR0ZXJGYXRhbEVycm9yKGVycm9yRGV0YWlscyk7CiAgICAgICAgfTsKCiAgICAgICAgLy8gQ2F0Y2ggZXJyb3JzIGZyb20gdGhlIEZsdXR0ZXIgZnJhbWV3b3JrIHRoYXQgYXJlIG5vdCBoYW5kbGVkIGJ5IEZsdXR0ZXJFcnJvcgogICAgICAgIFBsYXRmb3JtRGlzcGF0Y2hlci5pbnN0YW5jZS5vbkVycm9yID0gKGVycm9yLCBzdGFjaykgewogICAgICAgICAgX2NyYXNobHl0aWNzLnJlY29yZEVycm9yKGVycm9yLCBzdGFjaywgZmF0YWw6IHRydWUpOwogICAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgICAgfTsKICAgICAgfQoKICAgICAgLy8gU2V0IGRlZmF1bHQgY3VzdG9tIGtleXMKICAgICAgaWYgKGNvbmZpZy5jdXN0b21LZXlzLmlzTm90RW1wdHkpIHsKICAgICAgICBhd2FpdCBzZXRDdXN0b21LZXlzKGNvbmZpZy5jdXN0b21LZXlzKTsKICAgICAgfQoKICAgICAgX2lzSW5pdGlhbGl6ZWQgPSB0cnVlOwogICAgICBfbG9nZ2VyLmkoJ/CflKUgRmlyZWJhc2UgQ3Jhc2hseXRpY3MgaW5pdGlhbGl6ZWQgc3VjY2Vzc2Z1bGx5Jyk7CiAgICB9IGNhdGNoIChlLCBzdGFja1RyYWNlKSB7CiAgICAgIF9sb2dnZXIuZSgn4p2MIEZhaWxlZCB0byBpbml0aWFsaXplIEZpcmViYXNlIENyYXNobHl0aWNzOiAkZScsIHN0YWNrVHJhY2UpOwogICAgICByZXRocm93OwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPHZvaWQ+IHJlY29yZEVycm9yKAogICAgZHluYW1pYyBleGNlcHRpb24sCiAgICBTdGFja1RyYWNlPyBzdGFja1RyYWNlLCB7CiAgICBib29sIGZhdGFsID0gZmFsc2UsCiAgICBJdGVyYWJsZTxPYmplY3Q+IGluZm9ybWF0aW9uID0gY29uc3QgW10sCiAgfSkgYXN5bmMgewogICAgaWYgKCFfaXNJbml0aWFsaXplZCkgewogICAgICBfbG9nZ2VyLncoJ+KaoO+4jyBDcmFzaGx5dGljcyBub3QgaW5pdGlhbGl6ZWQsIHNraXBwaW5nIGVycm9yIHJlY29yZGluZycpOwogICAgICByZXR1cm47CiAgICB9CgogICAgdHJ5IHsKICAgICAgYXdhaXQgX2NyYXNobHl0aWNzLnJlY29yZEVycm9yKAogICAgICAgIGV4Y2VwdGlvbiwKICAgICAgICBzdGFja1RyYWNlLAogICAgICAgIGZhdGFsOiBmYXRhbCwKICAgICAgICBpbmZvcm1hdGlvbjogaW5mb3JtYXRpb24sCiAgICAgICk7CgogICAgICBfbG9nZ2VyLmQoCiAgICAgICAgJ/Cfk50gUmVjb3JkZWQgJHtmYXRhbCA/ICdmYXRhbCcgOiAnbm9uLWZhdGFsJ30gZXJyb3I6ICRleGNlcHRpb24nLAogICAgICApOwogICAgfSBjYXRjaCAoZSkgewogICAgICBfbG9nZ2VyLmUoJ+KdjCBGYWlsZWQgdG8gcmVjb3JkIGVycm9yOiAkZScpOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPHZvaWQ+IHJlY29yZEZsdXR0ZXJGYXRhbEVycm9yKAogICAgZHluYW1pYyBleGNlcHRpb24sCiAgICBTdGFja1RyYWNlIHN0YWNrVHJhY2UsIHsKICAgIE1hcDxTdHJpbmcsIGR5bmFtaWM+PyBjb250ZXh0LAogIH0pIGFzeW5jIHsKICAgIGlmICghX2lzSW5pdGlhbGl6ZWQpIHsKICAgICAgX2xvZ2dlci53KAogICAgICAgICfimqDvuI8gQ3Jhc2hseXRpY3Mgbm90IGluaXRpYWxpemVkLCBza2lwcGluZyBGbHV0dGVyIGZhdGFsIGVycm9yIHJlY29yZGluZycsCiAgICAgICk7CiAgICAgIHJldHVybjsKICAgIH0KCiAgICB0cnkgewogICAgICAvLyBTZXQgY29udGV4dCBhcyBjdXN0b20ga2V5cyBpZiBwcm92aWRlZAogICAgICBpZiAoY29udGV4dCAhPSBudWxsICYmIGNvbnRleHQuaXNOb3RFbXB0eSkgewogICAgICAgIGF3YWl0IHNldEN1c3RvbUtleXMoY29udGV4dCk7CiAgICAgIH0KCiAgICAgIGF3YWl0IF9jcmFzaGx5dGljcy5yZWNvcmRFcnJvcihleGNlcHRpb24sIHN0YWNrVHJhY2UsIGZhdGFsOiB0cnVlKTsKCiAgICAgIF9sb2dnZXIuZCgn8J+TnSBSZWNvcmRlZCBGbHV0dGVyIGZhdGFsIGVycm9yOiAkZXhjZXB0aW9uJyk7CiAgICB9IGNhdGNoIChlKSB7CiAgICAgIF9sb2dnZXIuZSgn4p2MIEZhaWxlZCB0byByZWNvcmQgRmx1dHRlciBmYXRhbCBlcnJvcjogJGUnKTsKICAgIH0KICB9CgogIEBvdmVycmlkZQogIEZ1dHVyZTx2b2lkPiBsb2coU3RyaW5nIG1lc3NhZ2UpIGFzeW5jIHsKICAgIGlmICghX2lzSW5pdGlhbGl6ZWQgfHwgIWNvbmZpZy5lbmFibGVDdXN0b21Mb2dzKSB7CiAgICAgIHJldHVybjsKICAgIH0KCiAgICB0cnkgewogICAgICBhd2FpdCBfY3Jhc2hseXRpY3MubG9nKG1lc3NhZ2UpOwoKICAgICAgLy8gQWRkIHRvIGxvY2FsIGJ1ZmZlciBmb3IgZGVidWdnaW5nCiAgICAgIF9sb2dCdWZmZXIuYWRkKCdbJHtEYXRlVGltZS5ub3coKS50b0lzbzg2MDFTdHJpbmcoKX1dICRtZXNzYWdlJyk7CgogICAgICAvLyBNYWludGFpbiBidWZmZXIgc2l6ZQogICAgICB3aGlsZSAoX2xvZ0J1ZmZlci5sZW5ndGggPiBjb25maWcubG9nQnVmZmVyU2l6ZSkgewogICAgICAgIF9sb2dCdWZmZXIucmVtb3ZlRmlyc3QoKTsKICAgICAgfQoKICAgICAgX2xvZ2dlci5kKCfwn5OKIExvZ2dlZCBtZXNzYWdlOiAkbWVzc2FnZScpOwogICAgfSBjYXRjaCAoZSkgewogICAgICBfbG9nZ2VyLmUoJ+KdjCBGYWlsZWQgdG8gbG9nIG1lc3NhZ2U6ICRlJyk7CiAgICB9CiAgfQoKICBAb3ZlcnJpZGUKICBGdXR1cmU8dm9pZD4gc2V0VXNlcklkZW50aWZpZXIoU3RyaW5nIGlkZW50aWZpZXIpIGFzeW5jIHsKICAgIGlmICghX2lzSW5pdGlhbGl6ZWQgfHwgIWNvbmZpZy5lbmFibGVVc2VyTWV0YWRhdGEpIHsKICAgICAgcmV0dXJuOwogICAgfQoKICAgIHRyeSB7CiAgICAgIGF3YWl0IF9jcmFzaGx5dGljcy5zZXRVc2VySWRlbnRpZmllcihpZGVudGlmaWVyKTsKICAgICAgX2xvZ2dlci5kKCfwn5GkIFNldCB1c2VyIGlkZW50aWZpZXI6ICRpZGVudGlmaWVyJyk7CiAgICB9IGNhdGNoIChlKSB7CiAgICAgIF9sb2dnZXIuZSgn4p2MIEZhaWxlZCB0byBzZXQgdXNlciBpZGVudGlmaWVyOiAkZScpOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPHZvaWQ+IHNldFVzZXJNZXRhZGF0YShVc2VyTWV0YWRhdGEgbWV0YWRhdGEpIGFzeW5jIHsKICAgIGlmICghX2lzSW5pdGlhbGl6ZWQgfHwgIWNvbmZpZy5lbmFibGVVc2VyTWV0YWRhdGEpIHsKICAgICAgcmV0dXJuOwogICAgfQoKICAgIHRyeSB7CiAgICAgIGlmIChtZXRhZGF0YS51c2VySWQgIT0gbnVsbCkgewogICAgICAgIGF3YWl0IHNldFVzZXJJZGVudGlmaWVyKG1ldGFkYXRhLnVzZXJJZCEpOwogICAgICB9CgogICAgICAvLyBTZXQgY3VzdG9tIGF0dHJpYnV0ZXMKICAgICAgZmluYWwgYWxsQXR0cmlidXRlcyA9IDxTdHJpbmcsIGR5bmFtaWM+ewogICAgICAgIGlmIChtZXRhZGF0YS5lbWFpbCAhPSBudWxsKSAnZW1haWwnOiBtZXRhZGF0YS5lbWFpbCEsCiAgICAgICAgaWYgKG1ldGFkYXRhLm5hbWUgIT0gbnVsbCkgJ25hbWUnOiBtZXRhZGF0YS5uYW1lISwKICAgICAgICAuLi5tZXRhZGF0YS5jdXN0b21BdHRyaWJ1dGVzLAogICAgICB9OwoKICAgICAgYXdhaXQgc2V0Q3VzdG9tS2V5cyhhbGxBdHRyaWJ1dGVzKTsKICAgICAgX2xvZ2dlci5kKCfwn5GkIFNldCB1c2VyIG1ldGFkYXRhOiAkbWV0YWRhdGEnKTsKICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgX2xvZ2dlci5lKCfinYwgRmFpbGVkIHRvIHNldCB1c2VyIG1ldGFkYXRhOiAkZScpOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPHZvaWQ+IHNldEN1c3RvbUtleShTdHJpbmcga2V5LCBkeW5hbWljIHZhbHVlKSBhc3luYyB7CiAgICBpZiAoIV9pc0luaXRpYWxpemVkKSB7CiAgICAgIHJldHVybjsKICAgIH0KCiAgICB0cnkgewogICAgICBhd2FpdCBfY3Jhc2hseXRpY3Muc2V0Q3VzdG9tS2V5KGtleSwgdmFsdWUpOwogICAgICBfbG9nZ2VyLmQoJ/CflJEgU2V0IGN1c3RvbSBrZXk6ICRrZXkgPSAkdmFsdWUnKTsKICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgX2xvZ2dlci5lKCfinYwgRmFpbGVkIHRvIHNldCBjdXN0b20ga2V5OiAkZScpOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPHZvaWQ+IHNldEN1c3RvbUtleXMoTWFwPFN0cmluZywgZHluYW1pYz4ga2V5cykgYXN5bmMgewogICAgaWYgKCFfaXNJbml0aWFsaXplZCB8fCBrZXlzLmlzRW1wdHkpIHsKICAgICAgcmV0dXJuOwogICAgfQoKICAgIHRyeSB7CiAgICAgIGZvciAoZmluYWwgZW50cnkgaW4ga2V5cy5lbnRyaWVzKSB7CiAgICAgICAgYXdhaXQgX2NyYXNobHl0aWNzLnNldEN1c3RvbUtleShlbnRyeS5rZXksIGVudHJ5LnZhbHVlKTsKICAgICAgfQogICAgICBfbG9nZ2VyLmQoJ/CflJEgU2V0ICR7a2V5cy5sZW5ndGh9IGN1c3RvbSBrZXlzJyk7CiAgICB9IGNhdGNoIChlKSB7CiAgICAgIF9sb2dnZXIuZSgn4p2MIEZhaWxlZCB0byBzZXQgY3VzdG9tIGtleXM6ICRlJyk7CiAgICB9CiAgfQoKICBAb3ZlcnJpZGUKICBib29sIGdldCBpc0NyYXNobHl0aWNzQ29sbGVjdGlvbkVuYWJsZWQgewogICAgaWYgKCFfaXNJbml0aWFsaXplZCkgcmV0dXJuIGZhbHNlOwogICAgcmV0dXJuIF9jcmFzaGx5dGljcy5pc0NyYXNobHl0aWNzQ29sbGVjdGlvbkVuYWJsZWQ7CiAgfQoKICBAb3ZlcnJpZGUKICBGdXR1cmU8dm9pZD4gc2V0Q3Jhc2hseXRpY3NDb2xsZWN0aW9uRW5hYmxlZChib29sIGVuYWJsZWQpIGFzeW5jIHsKICAgIGlmICghX2lzSW5pdGlhbGl6ZWQpIHsKICAgICAgcmV0dXJuOwogICAgfQoKICAgIHRyeSB7CiAgICAgIGF3YWl0IF9jcmFzaGx5dGljcy5zZXRDcmFzaGx5dGljc0NvbGxlY3Rpb25FbmFibGVkKGVuYWJsZWQpOwogICAgICBfbG9nZ2VyLmQoCiAgICAgICAgJ+Kame+4jyBDcmFzaGx5dGljcyBjb2xsZWN0aW9uICR7ZW5hYmxlZCA/ICdlbmFibGVkJyA6ICdkaXNhYmxlZCd9JywKICAgICAgKTsKICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgX2xvZ2dlci5lKCfinYwgRmFpbGVkIHRvIHNldCBjcmFzaGx5dGljcyBjb2xsZWN0aW9uIGVuYWJsZWQ6ICRlJyk7CiAgICB9CiAgfQoKICBAb3ZlcnJpZGUKICBGdXR1cmU8dm9pZD4gc2VuZFVuc2VudFJlcG9ydHMoKSBhc3luYyB7CiAgICBpZiAoIV9pc0luaXRpYWxpemVkKSB7CiAgICAgIHJldHVybjsKICAgIH0KCiAgICB0cnkgewogICAgICBhd2FpdCBfY3Jhc2hseXRpY3Muc2VuZFVuc2VudFJlcG9ydHMoKTsKICAgICAgX2xvZ2dlci5kKCfwn5OkIFNlbnQgdW5zZW50IGNyYXNoIHJlcG9ydHMnKTsKICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgX2xvZ2dlci5lKCfinYwgRmFpbGVkIHRvIHNlbmQgdW5zZW50IHJlcG9ydHM6ICRlJyk7CiAgICB9CiAgfQoKICBAb3ZlcnJpZGUKICBGdXR1cmU8dm9pZD4gZGVsZXRlVW5zZW50UmVwb3J0cygpIGFzeW5jIHsKICAgIGlmICghX2lzSW5pdGlhbGl6ZWQpIHsKICAgICAgcmV0dXJuOwogICAgfQoKICAgIHRyeSB7CiAgICAgIGF3YWl0IF9jcmFzaGx5dGljcy5kZWxldGVVbnNlbnRSZXBvcnRzKCk7CiAgICAgIF9sb2dnZXIuZCgn8J+Xke+4jyBEZWxldGVkIHVuc2VudCBjcmFzaCByZXBvcnRzJyk7CiAgICB9IGNhdGNoIChlKSB7CiAgICAgIF9sb2dnZXIuZSgn4p2MIEZhaWxlZCB0byBkZWxldGUgdW5zZW50IHJlcG9ydHM6ICRlJyk7CiAgICB9CiAgfQoKICBAb3ZlcnJpZGUKICBGdXR1cmU8Ym9vbD4gY2hlY2tGb3JVbnNlbnRSZXBvcnRzKCkgYXN5bmMgewogICAgaWYgKCFfaXNJbml0aWFsaXplZCkgewogICAgICByZXR1cm4gZmFsc2U7CiAgICB9CgogICAgdHJ5IHsKICAgICAgZmluYWwgaGFzVW5zZW50ID0gYXdhaXQgX2NyYXNobHl0aWNzLmNoZWNrRm9yVW5zZW50UmVwb3J0cygpOwogICAgICBfbG9nZ2VyLmQoJ/Cfk4sgSGFzIHVuc2VudCByZXBvcnRzOiAkaGFzVW5zZW50Jyk7CiAgICAgIHJldHVybiBoYXNVbnNlbnQ7CiAgICB9IGNhdGNoIChlKSB7CiAgICAgIF9sb2dnZXIuZSgn4p2MIEZhaWxlZCB0byBjaGVjayBmb3IgdW5zZW50IHJlcG9ydHM6ICRlJyk7CiAgICAgIHJldHVybiBmYWxzZTsKICAgIH0KICB9CgogIC8vLyBHZXQgYnVmZmVyZWQgbG9nIG1lc3NhZ2VzIGZvciBkZWJ1Z2dpbmcKICBMaXN0PFN0cmluZz4gZ2V0IGJ1ZmZlcmVkTG9ncyA9PiBfbG9nQnVmZmVyLnRvTGlzdCgpOwoKICAvLy8gQ2xlYXIgdGhlIGxvZyBidWZmZXIKICB2b2lkIGNsZWFyTG9nQnVmZmVyKCkgewogICAgX2xvZ0J1ZmZlci5jbGVhcigpOwogICAgX2xvZ2dlci5kKCfwn6e5IENsZWFyZWQgbG9nIGJ1ZmZlcicpOwogIH0KCiAgQG92ZXJyaWRlCiAgdm9pZCBkaXNwb3NlKCkgewogICAgX2xvZ0J1ZmZlci5jbGVhcigpOwogICAgX2lzSW5pdGlhbGl6ZWQgPSBmYWxzZTsKICAgIF9sb2dnZXIuZCgn8J+nuSBGaXJlYmFzZSBDcmFzaGx5dGljcyBjbGllbnQgZGlzcG9zZWQnKTsKICB9Cn0K", + "aW1wb3J0ICdkYXJ0OmFzeW5jJzsKaW1wb3J0ICdkYXJ0OmNvbGxlY3Rpb24nOwoKaW1wb3J0ICdwYWNrYWdlOmNvcmUvY29yZS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmNyYXNobHl0aWNzL3NyYy9jbGllbnQvY3Jhc2hseXRpY3NfY2xpZW50LmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Y3Jhc2hseXRpY3Mvc3JjL2NvbmZpZy9jcmFzaGx5dGljc19jb25maWcuZGFydCc7CmltcG9ydCAncGFja2FnZTpjcmFzaGx5dGljcy9zcmMvbW9kZWxzL3VzZXJfbWV0YWRhdGEuZGFydCc7CmltcG9ydCAncGFja2FnZTpmaXJlYmFzZV9jcmFzaGx5dGljcy9maXJlYmFzZV9jcmFzaGx5dGljcy5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZsdXR0ZXIvZm91bmRhdGlvbi5kYXJ0JzsKCmNsYXNzIEZpcmViYXNlQ3Jhc2hseXRpY3NDbGllbnQgaW1wbGVtZW50cyBDcmFzaGx5dGljc0NsaWVudCB7CiAgRmlyZWJhc2VDcmFzaGx5dGljc0NsaWVudCh7CiAgICByZXF1aXJlZCB0aGlzLmNvbmZpZywKICAgIHJlcXVpcmVkIExvZ2dlciBsb2dnZXIsCiAgICByZXF1aXJlZCBGaXJlYmFzZUNyYXNobHl0aWNzIGNyYXNobHl0aWNzLAogIH0pIDogX2xvZ2dlciA9IGxvZ2dlciwKICAgICAgIF9jcmFzaGx5dGljcyA9IGNyYXNobHl0aWNzOwoKICBmaW5hbCBDcmFzaGx5dGljc0NvbmZpZyBjb25maWc7CiAgZmluYWwgTG9nZ2VyIF9sb2dnZXI7CiAgZmluYWwgRmlyZWJhc2VDcmFzaGx5dGljcyBfY3Jhc2hseXRpY3M7CiAgZmluYWwgUXVldWU8U3RyaW5nPiBfbG9nQnVmZmVyID0gUXVldWU8U3RyaW5nPigpOwogIGJvb2wgX2lzSW5pdGlhbGl6ZWQgPSBmYWxzZTsKICBGbHV0dGVyRXhjZXB0aW9uSGFuZGxlcj8gX3ByZXZpb3VzRmx1dHRlckhhbmRsZXI7CiAgYm9vbCBGdW5jdGlvbihPYmplY3QsIFN0YWNrVHJhY2UpPyBfcHJldmlvdXNQbGF0Zm9ybUhhbmRsZXI7CiAgRmx1dHRlckV4Y2VwdGlvbkhhbmRsZXI/IF9mbHV0dGVySGFuZGxlcjsKICBib29sIEZ1bmN0aW9uKE9iamVjdCwgU3RhY2tUcmFjZSk/IF9wbGF0Zm9ybUhhbmRsZXI7CgogIEBvdmVycmlkZQogIEZ1dHVyZTx2b2lkPiBpbml0aWFsaXplKCkgYXN5bmMgewogICAgaWYgKF9pc0luaXRpYWxpemVkKSByZXR1cm47CiAgICB0cnkgewogICAgICAvLyBTZXQgY3Jhc2hseXRpY3MgY29sbGVjdGlvbiBlbmFibGVkIGJhc2VkIG9uIGNvbmZpZwogICAgICBhd2FpdCBfY3Jhc2hseXRpY3Muc2V0Q3Jhc2hseXRpY3NDb2xsZWN0aW9uRW5hYmxlZCgKICAgICAgICBjb25maWcuZW5hYmxlSW5EZWJ1Z01vZGUgfHwga1JlbGVhc2VNb2RlLAogICAgICApOwoKICAgICAgLy8gQXBwbHkgc3RhcnR1cCBtZXRhZGF0YSBiZWZvcmUgYWR2ZXJ0aXNpbmcgcmVhZGluZXNzLgogICAgICBmb3IgKGZpbmFsIGVudHJ5IGluIGNvbmZpZy5jdXN0b21LZXlzLmVudHJpZXMpIHsKICAgICAgICBhd2FpdCBfY3Jhc2hseXRpY3Muc2V0Q3VzdG9tS2V5KGVudHJ5LmtleSwgZW50cnkudmFsdWUpOwogICAgICB9CiAgICAgIF9pc0luaXRpYWxpemVkID0gdHJ1ZTsKCiAgICAgIC8vIE93biB0aGUgaGFuZGxlcnMgd2UgaW5zdGFsbCBhbmQgcmVzdG9yZSB0aGVtIG9uIGRpc3Bvc2FsLgogICAgICBpZiAoY29uZmlnLmVuYWJsZUF1dG9tYXRpY0RhdGFDb2xsZWN0aW9uKSB7CiAgICAgICAgX3ByZXZpb3VzRmx1dHRlckhhbmRsZXIgPSBGbHV0dGVyRXJyb3Iub25FcnJvcjsKICAgICAgICBfcHJldmlvdXNQbGF0Zm9ybUhhbmRsZXIgPSBQbGF0Zm9ybURpc3BhdGNoZXIuaW5zdGFuY2Uub25FcnJvcjsKICAgICAgICBfZmx1dHRlckhhbmRsZXIgPSAoZXJyb3JEZXRhaWxzKSB7CiAgICAgICAgICB1bmF3YWl0ZWQoCiAgICAgICAgICAgIHJlY29yZEVycm9yKAogICAgICAgICAgICAgIGVycm9yRGV0YWlscy5leGNlcHRpb24sCiAgICAgICAgICAgICAgZXJyb3JEZXRhaWxzLnN0YWNrLAogICAgICAgICAgICAgIGZhdGFsOiB0cnVlLAogICAgICAgICAgICApLAogICAgICAgICAgKTsKICAgICAgICAgIF9wcmV2aW91c0ZsdXR0ZXJIYW5kbGVyPy5jYWxsKGVycm9yRGV0YWlscyk7CiAgICAgICAgfTsKICAgICAgICBfcGxhdGZvcm1IYW5kbGVyID0gKGVycm9yLCBzdGFjaykgewogICAgICAgICAgdW5hd2FpdGVkKHJlY29yZEVycm9yKGVycm9yLCBzdGFjaywgZmF0YWw6IHRydWUpKTsKICAgICAgICAgIF9wcmV2aW91c1BsYXRmb3JtSGFuZGxlcj8uY2FsbChlcnJvciwgc3RhY2spOwogICAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgICAgfTsKICAgICAgICBGbHV0dGVyRXJyb3Iub25FcnJvciA9IF9mbHV0dGVySGFuZGxlcjsKICAgICAgICBQbGF0Zm9ybURpc3BhdGNoZXIuaW5zdGFuY2Uub25FcnJvciA9IF9wbGF0Zm9ybUhhbmRsZXI7CiAgICAgIH0KICAgICAgX2xvZ2dlci5pKCfwn5SlIEZpcmViYXNlIENyYXNobHl0aWNzIGluaXRpYWxpemVkIHN1Y2Nlc3NmdWxseScpOwogICAgfSBjYXRjaCAoZSwgc3RhY2tUcmFjZSkgewogICAgICBfbG9nZ2VyLmUoJ+KdjCBGYWlsZWQgdG8gaW5pdGlhbGl6ZSBGaXJlYmFzZSBDcmFzaGx5dGljczogJGUnLCBzdGFja1RyYWNlKTsKICAgICAgcmV0aHJvdzsKICAgIH0KICB9CgogIEBvdmVycmlkZQogIEZ1dHVyZTx2b2lkPiByZWNvcmRFcnJvcigKICAgIGR5bmFtaWMgZXhjZXB0aW9uLAogICAgU3RhY2tUcmFjZT8gc3RhY2tUcmFjZSwgewogICAgYm9vbCBmYXRhbCA9IGZhbHNlLAogICAgSXRlcmFibGU8T2JqZWN0PiBpbmZvcm1hdGlvbiA9IGNvbnN0IFtdLAogIH0pIGFzeW5jIHsKICAgIGlmICghX2lzSW5pdGlhbGl6ZWQpIHsKICAgICAgX2xvZ2dlci53KCfimqDvuI8gQ3Jhc2hseXRpY3Mgbm90IGluaXRpYWxpemVkLCBza2lwcGluZyBlcnJvciByZWNvcmRpbmcnKTsKICAgICAgcmV0dXJuOwogICAgfQoKICAgIHRyeSB7CiAgICAgIGF3YWl0IF9jcmFzaGx5dGljcy5yZWNvcmRFcnJvcigKICAgICAgICBleGNlcHRpb24sCiAgICAgICAgc3RhY2tUcmFjZSwKICAgICAgICBmYXRhbDogZmF0YWwsCiAgICAgICAgaW5mb3JtYXRpb246IGluZm9ybWF0aW9uLAogICAgICApOwoKICAgICAgX2xvZ2dlci5kKAogICAgICAgICfwn5OdIFJlY29yZGVkICR7ZmF0YWwgPyAnZmF0YWwnIDogJ25vbi1mYXRhbCd9IGVycm9yOiAkZXhjZXB0aW9uJywKICAgICAgKTsKICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgX2xvZ2dlci5lKCfinYwgRmFpbGVkIHRvIHJlY29yZCBlcnJvcjogJGUnKTsKICAgIH0KICB9CgogIEBvdmVycmlkZQogIEZ1dHVyZTx2b2lkPiByZWNvcmRGbHV0dGVyRmF0YWxFcnJvcigKICAgIGR5bmFtaWMgZXhjZXB0aW9uLAogICAgU3RhY2tUcmFjZSBzdGFja1RyYWNlLCB7CiAgICBNYXA8U3RyaW5nLCBkeW5hbWljPj8gY29udGV4dCwKICB9KSBhc3luYyB7CiAgICBpZiAoIV9pc0luaXRpYWxpemVkKSB7CiAgICAgIF9sb2dnZXIudygKICAgICAgICAn4pqg77iPIENyYXNobHl0aWNzIG5vdCBpbml0aWFsaXplZCwgc2tpcHBpbmcgRmx1dHRlciBmYXRhbCBlcnJvciByZWNvcmRpbmcnLAogICAgICApOwogICAgICByZXR1cm47CiAgICB9CgogICAgdHJ5IHsKICAgICAgLy8gU2V0IGNvbnRleHQgYXMgY3VzdG9tIGtleXMgaWYgcHJvdmlkZWQKICAgICAgaWYgKGNvbnRleHQgIT0gbnVsbCAmJiBjb250ZXh0LmlzTm90RW1wdHkpIHsKICAgICAgICBhd2FpdCBzZXRDdXN0b21LZXlzKGNvbnRleHQpOwogICAgICB9CgogICAgICBhd2FpdCBfY3Jhc2hseXRpY3MucmVjb3JkRXJyb3IoZXhjZXB0aW9uLCBzdGFja1RyYWNlLCBmYXRhbDogdHJ1ZSk7CgogICAgICBfbG9nZ2VyLmQoJ/Cfk50gUmVjb3JkZWQgRmx1dHRlciBmYXRhbCBlcnJvcjogJGV4Y2VwdGlvbicpOwogICAgfSBjYXRjaCAoZSkgewogICAgICBfbG9nZ2VyLmUoJ+KdjCBGYWlsZWQgdG8gcmVjb3JkIEZsdXR0ZXIgZmF0YWwgZXJyb3I6ICRlJyk7CiAgICB9CiAgfQoKICBAb3ZlcnJpZGUKICBGdXR1cmU8dm9pZD4gbG9nKFN0cmluZyBtZXNzYWdlKSBhc3luYyB7CiAgICBpZiAoIV9pc0luaXRpYWxpemVkIHx8ICFjb25maWcuZW5hYmxlQ3VzdG9tTG9ncykgewogICAgICByZXR1cm47CiAgICB9CgogICAgdHJ5IHsKICAgICAgYXdhaXQgX2NyYXNobHl0aWNzLmxvZyhtZXNzYWdlKTsKCiAgICAgIC8vIEFkZCB0byBsb2NhbCBidWZmZXIgZm9yIGRlYnVnZ2luZwogICAgICBfbG9nQnVmZmVyLmFkZCgnWyR7RGF0ZVRpbWUubm93KCkudG9Jc284NjAxU3RyaW5nKCl9XSAkbWVzc2FnZScpOwoKICAgICAgLy8gTWFpbnRhaW4gYnVmZmVyIHNpemUKICAgICAgd2hpbGUgKF9sb2dCdWZmZXIubGVuZ3RoID4gY29uZmlnLmxvZ0J1ZmZlclNpemUpIHsKICAgICAgICBfbG9nQnVmZmVyLnJlbW92ZUZpcnN0KCk7CiAgICAgIH0KCiAgICAgIF9sb2dnZXIuZCgn8J+TiiBMb2dnZWQgbWVzc2FnZTogJG1lc3NhZ2UnKTsKICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgX2xvZ2dlci5lKCfinYwgRmFpbGVkIHRvIGxvZyBtZXNzYWdlOiAkZScpOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPHZvaWQ+IHNldFVzZXJJZGVudGlmaWVyKFN0cmluZyBpZGVudGlmaWVyKSBhc3luYyB7CiAgICBpZiAoIV9pc0luaXRpYWxpemVkIHx8ICFjb25maWcuZW5hYmxlVXNlck1ldGFkYXRhKSB7CiAgICAgIHJldHVybjsKICAgIH0KCiAgICB0cnkgewogICAgICBhd2FpdCBfY3Jhc2hseXRpY3Muc2V0VXNlcklkZW50aWZpZXIoaWRlbnRpZmllcik7CiAgICAgIF9sb2dnZXIuZCgn8J+RpCBVc2VyIGlkZW50aWZpZXIgdXBkYXRlZCcpOwogICAgfSBjYXRjaCAoZSkgewogICAgICBfbG9nZ2VyLmUoJ+KdjCBGYWlsZWQgdG8gc2V0IHVzZXIgaWRlbnRpZmllcjogJGUnKTsKICAgIH0KICB9CgogIEBvdmVycmlkZQogIEZ1dHVyZTx2b2lkPiBzZXRVc2VyTWV0YWRhdGEoVXNlck1ldGFkYXRhIG1ldGFkYXRhKSBhc3luYyB7CiAgICBpZiAoIV9pc0luaXRpYWxpemVkIHx8ICFjb25maWcuZW5hYmxlVXNlck1ldGFkYXRhKSB7CiAgICAgIHJldHVybjsKICAgIH0KCiAgICB0cnkgewogICAgICBpZiAobWV0YWRhdGEudXNlcklkICE9IG51bGwpIHsKICAgICAgICBhd2FpdCBzZXRVc2VySWRlbnRpZmllcihtZXRhZGF0YS51c2VySWQhKTsKICAgICAgfQoKICAgICAgLy8gU2V0IGN1c3RvbSBhdHRyaWJ1dGVzCiAgICAgIGZpbmFsIGFsbEF0dHJpYnV0ZXMgPSA8U3RyaW5nLCBkeW5hbWljPnsKICAgICAgICBpZiAobWV0YWRhdGEuZW1haWwgIT0gbnVsbCkgJ2VtYWlsJzogbWV0YWRhdGEuZW1haWwhLAogICAgICAgIGlmIChtZXRhZGF0YS5uYW1lICE9IG51bGwpICduYW1lJzogbWV0YWRhdGEubmFtZSEsCiAgICAgICAgLi4ubWV0YWRhdGEuY3VzdG9tQXR0cmlidXRlcywKICAgICAgfTsKCiAgICAgIGF3YWl0IHNldEN1c3RvbUtleXMoYWxsQXR0cmlidXRlcyk7CiAgICAgIF9sb2dnZXIuZCgn8J+RpCBVc2VyIG1ldGFkYXRhIHVwZGF0ZWQnKTsKICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgX2xvZ2dlci5lKCfinYwgRmFpbGVkIHRvIHNldCB1c2VyIG1ldGFkYXRhOiAkZScpOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPHZvaWQ+IHNldEN1c3RvbUtleShTdHJpbmcga2V5LCBkeW5hbWljIHZhbHVlKSBhc3luYyB7CiAgICBpZiAoIV9pc0luaXRpYWxpemVkKSB7CiAgICAgIHJldHVybjsKICAgIH0KCiAgICB0cnkgewogICAgICBhd2FpdCBfY3Jhc2hseXRpY3Muc2V0Q3VzdG9tS2V5KGtleSwgdmFsdWUpOwogICAgICBfbG9nZ2VyLmQoJ/CflJEgU2V0IGN1c3RvbSBrZXk6ICRrZXkgPSAkdmFsdWUnKTsKICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgX2xvZ2dlci5lKCfinYwgRmFpbGVkIHRvIHNldCBjdXN0b20ga2V5OiAkZScpOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPHZvaWQ+IHNldEN1c3RvbUtleXMoTWFwPFN0cmluZywgZHluYW1pYz4ga2V5cykgYXN5bmMgewogICAgaWYgKCFfaXNJbml0aWFsaXplZCB8fCBrZXlzLmlzRW1wdHkpIHsKICAgICAgcmV0dXJuOwogICAgfQoKICAgIHRyeSB7CiAgICAgIGZvciAoZmluYWwgZW50cnkgaW4ga2V5cy5lbnRyaWVzKSB7CiAgICAgICAgYXdhaXQgX2NyYXNobHl0aWNzLnNldEN1c3RvbUtleShlbnRyeS5rZXksIGVudHJ5LnZhbHVlKTsKICAgICAgfQogICAgICBfbG9nZ2VyLmQoJ/CflJEgU2V0ICR7a2V5cy5sZW5ndGh9IGN1c3RvbSBrZXlzJyk7CiAgICB9IGNhdGNoIChlKSB7CiAgICAgIF9sb2dnZXIuZSgn4p2MIEZhaWxlZCB0byBzZXQgY3VzdG9tIGtleXM6ICRlJyk7CiAgICB9CiAgfQoKICBAb3ZlcnJpZGUKICBib29sIGdldCBpc0NyYXNobHl0aWNzQ29sbGVjdGlvbkVuYWJsZWQgewogICAgaWYgKCFfaXNJbml0aWFsaXplZCkgcmV0dXJuIGZhbHNlOwogICAgcmV0dXJuIF9jcmFzaGx5dGljcy5pc0NyYXNobHl0aWNzQ29sbGVjdGlvbkVuYWJsZWQ7CiAgfQoKICBAb3ZlcnJpZGUKICBGdXR1cmU8dm9pZD4gc2V0Q3Jhc2hseXRpY3NDb2xsZWN0aW9uRW5hYmxlZChib29sIGVuYWJsZWQpIGFzeW5jIHsKICAgIGlmICghX2lzSW5pdGlhbGl6ZWQpIHsKICAgICAgcmV0dXJuOwogICAgfQoKICAgIHRyeSB7CiAgICAgIGF3YWl0IF9jcmFzaGx5dGljcy5zZXRDcmFzaGx5dGljc0NvbGxlY3Rpb25FbmFibGVkKGVuYWJsZWQpOwogICAgICBfbG9nZ2VyLmQoCiAgICAgICAgJ+Kame+4jyBDcmFzaGx5dGljcyBjb2xsZWN0aW9uICR7ZW5hYmxlZCA/ICdlbmFibGVkJyA6ICdkaXNhYmxlZCd9JywKICAgICAgKTsKICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgX2xvZ2dlci5lKCfinYwgRmFpbGVkIHRvIHNldCBjcmFzaGx5dGljcyBjb2xsZWN0aW9uIGVuYWJsZWQ6ICRlJyk7CiAgICB9CiAgfQoKICBAb3ZlcnJpZGUKICBGdXR1cmU8dm9pZD4gc2VuZFVuc2VudFJlcG9ydHMoKSBhc3luYyB7CiAgICBpZiAoIV9pc0luaXRpYWxpemVkKSB7CiAgICAgIHJldHVybjsKICAgIH0KCiAgICB0cnkgewogICAgICBhd2FpdCBfY3Jhc2hseXRpY3Muc2VuZFVuc2VudFJlcG9ydHMoKTsKICAgICAgX2xvZ2dlci5kKCfwn5OkIFNlbnQgdW5zZW50IGNyYXNoIHJlcG9ydHMnKTsKICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgX2xvZ2dlci5lKCfinYwgRmFpbGVkIHRvIHNlbmQgdW5zZW50IHJlcG9ydHM6ICRlJyk7CiAgICB9CiAgfQoKICBAb3ZlcnJpZGUKICBGdXR1cmU8dm9pZD4gZGVsZXRlVW5zZW50UmVwb3J0cygpIGFzeW5jIHsKICAgIGlmICghX2lzSW5pdGlhbGl6ZWQpIHsKICAgICAgcmV0dXJuOwogICAgfQoKICAgIHRyeSB7CiAgICAgIGF3YWl0IF9jcmFzaGx5dGljcy5kZWxldGVVbnNlbnRSZXBvcnRzKCk7CiAgICAgIF9sb2dnZXIuZCgn8J+Xke+4jyBEZWxldGVkIHVuc2VudCBjcmFzaCByZXBvcnRzJyk7CiAgICB9IGNhdGNoIChlKSB7CiAgICAgIF9sb2dnZXIuZSgn4p2MIEZhaWxlZCB0byBkZWxldGUgdW5zZW50IHJlcG9ydHM6ICRlJyk7CiAgICB9CiAgfQoKICBAb3ZlcnJpZGUKICBGdXR1cmU8Ym9vbD4gY2hlY2tGb3JVbnNlbnRSZXBvcnRzKCkgYXN5bmMgewogICAgaWYgKCFfaXNJbml0aWFsaXplZCkgewogICAgICByZXR1cm4gZmFsc2U7CiAgICB9CgogICAgdHJ5IHsKICAgICAgZmluYWwgaGFzVW5zZW50ID0gYXdhaXQgX2NyYXNobHl0aWNzLmNoZWNrRm9yVW5zZW50UmVwb3J0cygpOwogICAgICBfbG9nZ2VyLmQoJ/Cfk4sgSGFzIHVuc2VudCByZXBvcnRzOiAkaGFzVW5zZW50Jyk7CiAgICAgIHJldHVybiBoYXNVbnNlbnQ7CiAgICB9IGNhdGNoIChlKSB7CiAgICAgIF9sb2dnZXIuZSgn4p2MIEZhaWxlZCB0byBjaGVjayBmb3IgdW5zZW50IHJlcG9ydHM6ICRlJyk7CiAgICAgIHJldHVybiBmYWxzZTsKICAgIH0KICB9CgogIC8vLyBHZXQgYnVmZmVyZWQgbG9nIG1lc3NhZ2VzIGZvciBkZWJ1Z2dpbmcKICBMaXN0PFN0cmluZz4gZ2V0IGJ1ZmZlcmVkTG9ncyA9PiBfbG9nQnVmZmVyLnRvTGlzdCgpOwoKICAvLy8gQ2xlYXIgdGhlIGxvZyBidWZmZXIKICB2b2lkIGNsZWFyTG9nQnVmZmVyKCkgewogICAgX2xvZ0J1ZmZlci5jbGVhcigpOwogICAgX2xvZ2dlci5kKCfwn6e5IENsZWFyZWQgbG9nIGJ1ZmZlcicpOwogIH0KCiAgQG92ZXJyaWRlCiAgdm9pZCBkaXNwb3NlKCkgewogICAgaWYgKF9mbHV0dGVySGFuZGxlciAhPSBudWxsICYmCiAgICAgICAgaWRlbnRpY2FsKEZsdXR0ZXJFcnJvci5vbkVycm9yLCBfZmx1dHRlckhhbmRsZXIpKSB7CiAgICAgIEZsdXR0ZXJFcnJvci5vbkVycm9yID0gX3ByZXZpb3VzRmx1dHRlckhhbmRsZXI7CiAgICB9CiAgICBpZiAoX3BsYXRmb3JtSGFuZGxlciAhPSBudWxsICYmCiAgICAgICAgaWRlbnRpY2FsKFBsYXRmb3JtRGlzcGF0Y2hlci5pbnN0YW5jZS5vbkVycm9yLCBfcGxhdGZvcm1IYW5kbGVyKSkgewogICAgICBQbGF0Zm9ybURpc3BhdGNoZXIuaW5zdGFuY2Uub25FcnJvciA9IF9wcmV2aW91c1BsYXRmb3JtSGFuZGxlcjsKICAgIH0KICAgIF9sb2dCdWZmZXIuY2xlYXIoKTsKICAgIF9pc0luaXRpYWxpemVkID0gZmFsc2U7CiAgICBfbG9nZ2VyLmQoJ/Cfp7kgRmlyZWJhc2UgQ3Jhc2hseXRpY3MgY2xpZW50IGRpc3Bvc2VkJyk7CiAgfQp9Cg==", "type": "text" }, { @@ -918,7 +1047,7 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "path": "{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/lib/src/config/crashlytics_config.dart", "data": - "Y2xhc3MgQ3Jhc2hseXRpY3NDb25maWcgewogIGNvbnN0IENyYXNobHl0aWNzQ29uZmlnKHsKICAgIHRoaXMuZW5hYmxlSW5EZWJ1Z01vZGUgPSBmYWxzZSwKICAgIHRoaXMuZW5hYmxlQXV0b21hdGljRGF0YUNvbGxlY3Rpb24gPSB0cnVlLAogICAgdGhpcy5lbmFibGVDdXN0b21Mb2dzID0gdHJ1ZSwKICAgIHRoaXMubG9nQnVmZmVyU2l6ZSA9IDEwMCwKICAgIHRoaXMuZW5hYmxlVXNlck1ldGFkYXRhID0gdHJ1ZSwKICAgIHRoaXMuY3VzdG9tS2V5cyA9IGNvbnN0IHt9LAogIH0pOwoKICAvLy8gRW5hYmxlIGNyYXNobHl0aWNzIGluIGRlYnVnIG1vZGUgKHR5cGljYWxseSBkaXNhYmxlZCBmb3IgZGV2ZWxvcG1lbnQpCiAgZmluYWwgYm9vbCBlbmFibGVJbkRlYnVnTW9kZTsKCiAgLy8vIEVuYWJsZSBhdXRvbWF0aWMgZGF0YSBjb2xsZWN0aW9uCiAgZmluYWwgYm9vbCBlbmFibGVBdXRvbWF0aWNEYXRhQ29sbGVjdGlvbjsKCiAgLy8vIEVuYWJsZSBjdXN0b20gbG9nZ2luZwogIGZpbmFsIGJvb2wgZW5hYmxlQ3VzdG9tTG9nczsKCiAgLy8vIE1heGltdW0gbnVtYmVyIG9mIGxvZyBtZXNzYWdlcyB0byBidWZmZXIKICBmaW5hbCBpbnQgbG9nQnVmZmVyU2l6ZTsKCiAgLy8vIEVuYWJsZSB1c2VyIG1ldGFkYXRhIGNvbGxlY3Rpb24KICBmaW5hbCBib29sIGVuYWJsZVVzZXJNZXRhZGF0YTsKCiAgLy8vIERlZmF1bHQgY3VzdG9tIGtleXMgdG8gc2V0IG9uIGluaXRpYWxpemF0aW9uCiAgZmluYWwgTWFwPFN0cmluZywgZHluYW1pYz4gY3VzdG9tS2V5czsKCiAgQ3Jhc2hseXRpY3NDb25maWcgY29weVdpdGgoewogICAgYm9vbD8gZW5hYmxlSW5EZWJ1Z01vZGUsCiAgICBib29sPyBlbmFibGVBdXRvbWF0aWNEYXRhQ29sbGVjdGlvbiwKICAgIGJvb2w/IGVuYWJsZUN1c3RvbUxvZ3MsCiAgICBpbnQ/IGxvZ0J1ZmZlclNpemUsCiAgICBib29sPyBlbmFibGVVc2VyTWV0YWRhdGEsCiAgICBNYXA8U3RyaW5nLCBkeW5hbWljPj8gY3VzdG9tS2V5cywKICB9KSB7CiAgICByZXR1cm4gQ3Jhc2hseXRpY3NDb25maWcoCiAgICAgIGVuYWJsZUluRGVidWdNb2RlOiBlbmFibGVJbkRlYnVnTW9kZSA/PyB0aGlzLmVuYWJsZUluRGVidWdNb2RlLAogICAgICBlbmFibGVBdXRvbWF0aWNEYXRhQ29sbGVjdGlvbjoKICAgICAgICAgIGVuYWJsZUF1dG9tYXRpY0RhdGFDb2xsZWN0aW9uID8/IHRoaXMuZW5hYmxlQXV0b21hdGljRGF0YUNvbGxlY3Rpb24sCiAgICAgIGVuYWJsZUN1c3RvbUxvZ3M6IGVuYWJsZUN1c3RvbUxvZ3MgPz8gdGhpcy5lbmFibGVDdXN0b21Mb2dzLAogICAgICBsb2dCdWZmZXJTaXplOiBsb2dCdWZmZXJTaXplID8/IHRoaXMubG9nQnVmZmVyU2l6ZSwKICAgICAgZW5hYmxlVXNlck1ldGFkYXRhOiBlbmFibGVVc2VyTWV0YWRhdGEgPz8gdGhpcy5lbmFibGVVc2VyTWV0YWRhdGEsCiAgICAgIGN1c3RvbUtleXM6IGN1c3RvbUtleXMgPz8gdGhpcy5jdXN0b21LZXlzLAogICAgKTsKICB9CgogIE1hcDxTdHJpbmcsIGR5bmFtaWM+IHRvTWFwKCkgewogICAgcmV0dXJuIHsKICAgICAgJ2VuYWJsZUluRGVidWdNb2RlJzogZW5hYmxlSW5EZWJ1Z01vZGUsCiAgICAgICdlbmFibGVBdXRvbWF0aWNEYXRhQ29sbGVjdGlvbic6IGVuYWJsZUF1dG9tYXRpY0RhdGFDb2xsZWN0aW9uLAogICAgICAnZW5hYmxlQ3VzdG9tTG9ncyc6IGVuYWJsZUN1c3RvbUxvZ3MsCiAgICAgICdsb2dCdWZmZXJTaXplJzogbG9nQnVmZmVyU2l6ZSwKICAgICAgJ2VuYWJsZVVzZXJNZXRhZGF0YSc6IGVuYWJsZVVzZXJNZXRhZGF0YSwKICAgICAgJ2N1c3RvbUtleXMnOiBjdXN0b21LZXlzLAogICAgfTsKICB9CgogIEBvdmVycmlkZQogIFN0cmluZyB0b1N0cmluZygpIHsKICAgIHJldHVybiAnQ3Jhc2hseXRpY3NDb25maWd7ZW5hYmxlSW5EZWJ1Z01vZGU6ICRlbmFibGVJbkRlYnVnTW9kZSwgZW5hYmxlQXV0b21hdGljRGF0YUNvbGxlY3Rpb246ICRlbmFibGVBdXRvbWF0aWNEYXRhQ29sbGVjdGlvbiwgZW5hYmxlQ3VzdG9tTG9nczogJGVuYWJsZUN1c3RvbUxvZ3MsIGxvZ0J1ZmZlclNpemU6ICRsb2dCdWZmZXJTaXplLCBlbmFibGVVc2VyTWV0YWRhdGE6ICRlbmFibGVVc2VyTWV0YWRhdGEsIGN1c3RvbUtleXM6ICRjdXN0b21LZXlzfSc7CiAgfQoKICBAb3ZlcnJpZGUKICBib29sIG9wZXJhdG9yID09KE9iamVjdCBvdGhlcikgPT4KICAgICAgaWRlbnRpY2FsKHRoaXMsIG90aGVyKSB8fAogICAgICBvdGhlciBpcyBDcmFzaGx5dGljc0NvbmZpZyAmJgogICAgICAgICAgcnVudGltZVR5cGUgPT0gb3RoZXIucnVudGltZVR5cGUgJiYKICAgICAgICAgIGVuYWJsZUluRGVidWdNb2RlID09IG90aGVyLmVuYWJsZUluRGVidWdNb2RlICYmCiAgICAgICAgICBlbmFibGVBdXRvbWF0aWNEYXRhQ29sbGVjdGlvbiA9PQogICAgICAgICAgICAgIG90aGVyLmVuYWJsZUF1dG9tYXRpY0RhdGFDb2xsZWN0aW9uICYmCiAgICAgICAgICBlbmFibGVDdXN0b21Mb2dzID09IG90aGVyLmVuYWJsZUN1c3RvbUxvZ3MgJiYKICAgICAgICAgIGxvZ0J1ZmZlclNpemUgPT0gb3RoZXIubG9nQnVmZmVyU2l6ZSAmJgogICAgICAgICAgZW5hYmxlVXNlck1ldGFkYXRhID09IG90aGVyLmVuYWJsZVVzZXJNZXRhZGF0YSAmJgogICAgICAgICAgX21hcEVxdWFscyhjdXN0b21LZXlzLCBvdGhlci5jdXN0b21LZXlzKTsKCiAgQG92ZXJyaWRlCiAgaW50IGdldCBoYXNoQ29kZSA9PgogICAgICBlbmFibGVJbkRlYnVnTW9kZS5oYXNoQ29kZSBeCiAgICAgIGVuYWJsZUF1dG9tYXRpY0RhdGFDb2xsZWN0aW9uLmhhc2hDb2RlIF4KICAgICAgZW5hYmxlQ3VzdG9tTG9ncy5oYXNoQ29kZSBeCiAgICAgIGxvZ0J1ZmZlclNpemUuaGFzaENvZGUgXgogICAgICBlbmFibGVVc2VyTWV0YWRhdGEuaGFzaENvZGUgXgogICAgICBjdXN0b21LZXlzLmhhc2hDb2RlOwoKICBib29sIF9tYXBFcXVhbHMoTWFwPFN0cmluZywgZHluYW1pYz4gYSwgTWFwPFN0cmluZywgZHluYW1pYz4gYikgewogICAgaWYgKGEubGVuZ3RoICE9IGIubGVuZ3RoKSByZXR1cm4gZmFsc2U7CiAgICBmb3IgKGZpbmFsIGtleSBpbiBhLmtleXMpIHsKICAgICAgaWYgKCFiLmNvbnRhaW5zS2V5KGtleSkgfHwgYVtrZXldICE9IGJba2V5XSkgcmV0dXJuIGZhbHNlOwogICAgfQogICAgcmV0dXJuIHRydWU7CiAgfQp9CgpjbGFzcyBEZWZhdWx0Q3Jhc2hseXRpY3NDb25maWcgZXh0ZW5kcyBDcmFzaGx5dGljc0NvbmZpZyB7CiAgY29uc3QgRGVmYXVsdENyYXNobHl0aWNzQ29uZmlnKHsKICAgIHN1cGVyLmVuYWJsZUluRGVidWdNb2RlID0gZmFsc2UsCiAgICBzdXBlci5lbmFibGVBdXRvbWF0aWNEYXRhQ29sbGVjdGlvbiA9IHRydWUsCiAgICBzdXBlci5lbmFibGVDdXN0b21Mb2dzID0gdHJ1ZSwKICAgIHN1cGVyLmxvZ0J1ZmZlclNpemUgPSAxMDAsCiAgICBzdXBlci5lbmFibGVVc2VyTWV0YWRhdGEgPSB0cnVlLAogICAgc3VwZXIuY3VzdG9tS2V5cyA9IGNvbnN0IHt9LAogIH0pOwp9Cg==", + "Y2xhc3MgQ3Jhc2hseXRpY3NDb25maWcgewogIGNvbnN0IENyYXNobHl0aWNzQ29uZmlnKHsKICAgIHRoaXMuZW5hYmxlSW5EZWJ1Z01vZGUgPSBmYWxzZSwKICAgIHRoaXMuZW5hYmxlQXV0b21hdGljRGF0YUNvbGxlY3Rpb24gPSB0cnVlLAogICAgdGhpcy5lbmFibGVDdXN0b21Mb2dzID0gdHJ1ZSwKICAgIHRoaXMubG9nQnVmZmVyU2l6ZSA9IDEwMCwKICAgIHRoaXMuZW5hYmxlVXNlck1ldGFkYXRhID0gdHJ1ZSwKICAgIHRoaXMuY3VzdG9tS2V5cyA9IGNvbnN0IHt9LAogIH0pOwoKICAvLy8gRW5hYmxlIGNyYXNobHl0aWNzIGluIGRlYnVnIG1vZGUgKHR5cGljYWxseSBkaXNhYmxlZCBmb3IgZGV2ZWxvcG1lbnQpCiAgZmluYWwgYm9vbCBlbmFibGVJbkRlYnVnTW9kZTsKCiAgLy8vIEVuYWJsZSBhdXRvbWF0aWMgZGF0YSBjb2xsZWN0aW9uCiAgZmluYWwgYm9vbCBlbmFibGVBdXRvbWF0aWNEYXRhQ29sbGVjdGlvbjsKCiAgLy8vIEVuYWJsZSBjdXN0b20gbG9nZ2luZwogIGZpbmFsIGJvb2wgZW5hYmxlQ3VzdG9tTG9nczsKCiAgLy8vIE1heGltdW0gbnVtYmVyIG9mIGxvZyBtZXNzYWdlcyB0byBidWZmZXIKICBmaW5hbCBpbnQgbG9nQnVmZmVyU2l6ZTsKCiAgLy8vIEVuYWJsZSB1c2VyIG1ldGFkYXRhIGNvbGxlY3Rpb24KICBmaW5hbCBib29sIGVuYWJsZVVzZXJNZXRhZGF0YTsKCiAgLy8vIERlZmF1bHQgY3VzdG9tIGtleXMgdG8gc2V0IG9uIGluaXRpYWxpemF0aW9uCiAgZmluYWwgTWFwPFN0cmluZywgZHluYW1pYz4gY3VzdG9tS2V5czsKCiAgQ3Jhc2hseXRpY3NDb25maWcgY29weVdpdGgoewogICAgYm9vbD8gZW5hYmxlSW5EZWJ1Z01vZGUsCiAgICBib29sPyBlbmFibGVBdXRvbWF0aWNEYXRhQ29sbGVjdGlvbiwKICAgIGJvb2w/IGVuYWJsZUN1c3RvbUxvZ3MsCiAgICBpbnQ/IGxvZ0J1ZmZlclNpemUsCiAgICBib29sPyBlbmFibGVVc2VyTWV0YWRhdGEsCiAgICBNYXA8U3RyaW5nLCBkeW5hbWljPj8gY3VzdG9tS2V5cywKICB9KSB7CiAgICByZXR1cm4gQ3Jhc2hseXRpY3NDb25maWcoCiAgICAgIGVuYWJsZUluRGVidWdNb2RlOiBlbmFibGVJbkRlYnVnTW9kZSA/PyB0aGlzLmVuYWJsZUluRGVidWdNb2RlLAogICAgICBlbmFibGVBdXRvbWF0aWNEYXRhQ29sbGVjdGlvbjoKICAgICAgICAgIGVuYWJsZUF1dG9tYXRpY0RhdGFDb2xsZWN0aW9uID8/IHRoaXMuZW5hYmxlQXV0b21hdGljRGF0YUNvbGxlY3Rpb24sCiAgICAgIGVuYWJsZUN1c3RvbUxvZ3M6IGVuYWJsZUN1c3RvbUxvZ3MgPz8gdGhpcy5lbmFibGVDdXN0b21Mb2dzLAogICAgICBsb2dCdWZmZXJTaXplOiBsb2dCdWZmZXJTaXplID8/IHRoaXMubG9nQnVmZmVyU2l6ZSwKICAgICAgZW5hYmxlVXNlck1ldGFkYXRhOiBlbmFibGVVc2VyTWV0YWRhdGEgPz8gdGhpcy5lbmFibGVVc2VyTWV0YWRhdGEsCiAgICAgIGN1c3RvbUtleXM6IGN1c3RvbUtleXMgPz8gdGhpcy5jdXN0b21LZXlzLAogICAgKTsKICB9CgogIE1hcDxTdHJpbmcsIGR5bmFtaWM+IHRvTWFwKCkgewogICAgcmV0dXJuIHsKICAgICAgJ2VuYWJsZUluRGVidWdNb2RlJzogZW5hYmxlSW5EZWJ1Z01vZGUsCiAgICAgICdlbmFibGVBdXRvbWF0aWNEYXRhQ29sbGVjdGlvbic6IGVuYWJsZUF1dG9tYXRpY0RhdGFDb2xsZWN0aW9uLAogICAgICAnZW5hYmxlQ3VzdG9tTG9ncyc6IGVuYWJsZUN1c3RvbUxvZ3MsCiAgICAgICdsb2dCdWZmZXJTaXplJzogbG9nQnVmZmVyU2l6ZSwKICAgICAgJ2VuYWJsZVVzZXJNZXRhZGF0YSc6IGVuYWJsZVVzZXJNZXRhZGF0YSwKICAgICAgJ2N1c3RvbUtleXMnOiBjdXN0b21LZXlzLAogICAgfTsKICB9CgogIEBvdmVycmlkZQogIFN0cmluZyB0b1N0cmluZygpIHsKICAgIHJldHVybiAnQ3Jhc2hseXRpY3NDb25maWd7ZW5hYmxlSW5EZWJ1Z01vZGU6ICRlbmFibGVJbkRlYnVnTW9kZSwgZW5hYmxlQXV0b21hdGljRGF0YUNvbGxlY3Rpb246ICRlbmFibGVBdXRvbWF0aWNEYXRhQ29sbGVjdGlvbiwgZW5hYmxlQ3VzdG9tTG9nczogJGVuYWJsZUN1c3RvbUxvZ3MsIGxvZ0J1ZmZlclNpemU6ICRsb2dCdWZmZXJTaXplLCBlbmFibGVVc2VyTWV0YWRhdGE6ICRlbmFibGVVc2VyTWV0YWRhdGEsIGN1c3RvbUtleXM6ICRjdXN0b21LZXlzfSc7CiAgfQoKICBAb3ZlcnJpZGUKICBib29sIG9wZXJhdG9yID09KE9iamVjdCBvdGhlcikgPT4KICAgICAgaWRlbnRpY2FsKHRoaXMsIG90aGVyKSB8fAogICAgICBvdGhlciBpcyBDcmFzaGx5dGljc0NvbmZpZyAmJgogICAgICAgICAgcnVudGltZVR5cGUgPT0gb3RoZXIucnVudGltZVR5cGUgJiYKICAgICAgICAgIGVuYWJsZUluRGVidWdNb2RlID09IG90aGVyLmVuYWJsZUluRGVidWdNb2RlICYmCiAgICAgICAgICBlbmFibGVBdXRvbWF0aWNEYXRhQ29sbGVjdGlvbiA9PQogICAgICAgICAgICAgIG90aGVyLmVuYWJsZUF1dG9tYXRpY0RhdGFDb2xsZWN0aW9uICYmCiAgICAgICAgICBlbmFibGVDdXN0b21Mb2dzID09IG90aGVyLmVuYWJsZUN1c3RvbUxvZ3MgJiYKICAgICAgICAgIGxvZ0J1ZmZlclNpemUgPT0gb3RoZXIubG9nQnVmZmVyU2l6ZSAmJgogICAgICAgICAgZW5hYmxlVXNlck1ldGFkYXRhID09IG90aGVyLmVuYWJsZVVzZXJNZXRhZGF0YSAmJgogICAgICAgICAgX21hcEVxdWFscyhjdXN0b21LZXlzLCBvdGhlci5jdXN0b21LZXlzKTsKCiAgQG92ZXJyaWRlCiAgaW50IGdldCBoYXNoQ29kZSA9PgogICAgICBlbmFibGVJbkRlYnVnTW9kZS5oYXNoQ29kZSBeCiAgICAgIGVuYWJsZUF1dG9tYXRpY0RhdGFDb2xsZWN0aW9uLmhhc2hDb2RlIF4KICAgICAgZW5hYmxlQ3VzdG9tTG9ncy5oYXNoQ29kZSBeCiAgICAgIGxvZ0J1ZmZlclNpemUuaGFzaENvZGUgXgogICAgICBlbmFibGVVc2VyTWV0YWRhdGEuaGFzaENvZGUgXgogICAgICBPYmplY3QuaGFzaEFsbFVub3JkZXJlZCgKICAgICAgICBjdXN0b21LZXlzLmVudHJpZXMubWFwKChlbnRyeSkgPT4gT2JqZWN0Lmhhc2goZW50cnkua2V5LCBlbnRyeS52YWx1ZSkpLAogICAgICApOwoKICBib29sIF9tYXBFcXVhbHMoTWFwPFN0cmluZywgZHluYW1pYz4gYSwgTWFwPFN0cmluZywgZHluYW1pYz4gYikgewogICAgaWYgKGEubGVuZ3RoICE9IGIubGVuZ3RoKSByZXR1cm4gZmFsc2U7CiAgICBmb3IgKGZpbmFsIGtleSBpbiBhLmtleXMpIHsKICAgICAgaWYgKCFiLmNvbnRhaW5zS2V5KGtleSkgfHwgYVtrZXldICE9IGJba2V5XSkgcmV0dXJuIGZhbHNlOwogICAgfQogICAgcmV0dXJuIHRydWU7CiAgfQp9CgpjbGFzcyBEZWZhdWx0Q3Jhc2hseXRpY3NDb25maWcgZXh0ZW5kcyBDcmFzaGx5dGljc0NvbmZpZyB7CiAgY29uc3QgRGVmYXVsdENyYXNobHl0aWNzQ29uZmlnKHsKICAgIHN1cGVyLmVuYWJsZUluRGVidWdNb2RlID0gZmFsc2UsCiAgICBzdXBlci5lbmFibGVBdXRvbWF0aWNEYXRhQ29sbGVjdGlvbiA9IHRydWUsCiAgICBzdXBlci5lbmFibGVDdXN0b21Mb2dzID0gdHJ1ZSwKICAgIHN1cGVyLmxvZ0J1ZmZlclNpemUgPSAxMDAsCiAgICBzdXBlci5lbmFibGVVc2VyTWV0YWRhdGEgPSB0cnVlLAogICAgc3VwZXIuY3VzdG9tS2V5cyA9IGNvbnN0IHt9LAogIH0pOwp9Cg==", "type": "text" }, { @@ -931,7 +1060,7 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "path": "{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/lib/src/models/crash_report.dart", "data": - "Y2xhc3MgQ3Jhc2hSZXBvcnQgewogIGNvbnN0IENyYXNoUmVwb3J0KHsKICAgIHJlcXVpcmVkIHRoaXMuZXhjZXB0aW9uLAogICAgdGhpcy5zdGFja1RyYWNlLAogICAgdGhpcy5mYXRhbCA9IGZhbHNlLAogICAgdGhpcy50aW1lc3RhbXAsCiAgICB0aGlzLmN1c3RvbUtleXMgPSBjb25zdCB7fSwKICAgIHRoaXMubG9ncyA9IGNvbnN0IFtdLAogICAgdGhpcy51c2VyTWV0YWRhdGEsCiAgfSk7CgogIGZpbmFsIGR5bmFtaWMgZXhjZXB0aW9uOwogIGZpbmFsIFN0YWNrVHJhY2U/IHN0YWNrVHJhY2U7CiAgZmluYWwgYm9vbCBmYXRhbDsKICBmaW5hbCBEYXRlVGltZT8gdGltZXN0YW1wOwogIGZpbmFsIE1hcDxTdHJpbmcsIGR5bmFtaWM+IGN1c3RvbUtleXM7CiAgZmluYWwgTGlzdDxTdHJpbmc+IGxvZ3M7CiAgZmluYWwgTWFwPFN0cmluZywgZHluYW1pYz4/IHVzZXJNZXRhZGF0YTsKCiAgQ3Jhc2hSZXBvcnQgY29weVdpdGgoewogICAgZHluYW1pYyBleGNlcHRpb24sCiAgICBTdGFja1RyYWNlPyBzdGFja1RyYWNlLAogICAgYm9vbD8gZmF0YWwsCiAgICBEYXRlVGltZT8gdGltZXN0YW1wLAogICAgTWFwPFN0cmluZywgZHluYW1pYz4/IGN1c3RvbUtleXMsCiAgICBMaXN0PFN0cmluZz4/IGxvZ3MsCiAgICBNYXA8U3RyaW5nLCBkeW5hbWljPj8gdXNlck1ldGFkYXRhLAogIH0pIHsKICAgIHJldHVybiBDcmFzaFJlcG9ydCgKICAgICAgZXhjZXB0aW9uOiBleGNlcHRpb24gPz8gdGhpcy5leGNlcHRpb24sCiAgICAgIHN0YWNrVHJhY2U6IHN0YWNrVHJhY2UgPz8gdGhpcy5zdGFja1RyYWNlLAogICAgICBmYXRhbDogZmF0YWwgPz8gdGhpcy5mYXRhbCwKICAgICAgdGltZXN0YW1wOiB0aW1lc3RhbXAgPz8gdGhpcy50aW1lc3RhbXAsCiAgICAgIGN1c3RvbUtleXM6IGN1c3RvbUtleXMgPz8gdGhpcy5jdXN0b21LZXlzLAogICAgICBsb2dzOiBsb2dzID8/IHRoaXMubG9ncywKICAgICAgdXNlck1ldGFkYXRhOiB1c2VyTWV0YWRhdGEgPz8gdGhpcy51c2VyTWV0YWRhdGEsCiAgICApOwogIH0KCiAgTWFwPFN0cmluZywgZHluYW1pYz4gdG9NYXAoKSB7CiAgICByZXR1cm4gewogICAgICAnZXhjZXB0aW9uJzogZXhjZXB0aW9uLnRvU3RyaW5nKCksCiAgICAgICdzdGFja1RyYWNlJzogc3RhY2tUcmFjZT8udG9TdHJpbmcoKSwKICAgICAgJ2ZhdGFsJzogZmF0YWwsCiAgICAgICd0aW1lc3RhbXAnOiB0aW1lc3RhbXA/LnRvSXNvODYwMVN0cmluZygpLAogICAgICAnY3VzdG9tS2V5cyc6IGN1c3RvbUtleXMsCiAgICAgICdsb2dzJzogbG9ncywKICAgICAgJ3VzZXJNZXRhZGF0YSc6IHVzZXJNZXRhZGF0YSwKICAgIH07CiAgfQoKICBAb3ZlcnJpZGUKICBTdHJpbmcgdG9TdHJpbmcoKSB7CiAgICByZXR1cm4gJ0NyYXNoUmVwb3J0e2V4Y2VwdGlvbjogJGV4Y2VwdGlvbiwgZmF0YWw6ICRmYXRhbCwgdGltZXN0YW1wOiAkdGltZXN0YW1wfSc7CiAgfQoKICBAb3ZlcnJpZGUKICBib29sIG9wZXJhdG9yID09KE9iamVjdCBvdGhlcikgPT4KICAgICAgaWRlbnRpY2FsKHRoaXMsIG90aGVyKSB8fAogICAgICBvdGhlciBpcyBDcmFzaFJlcG9ydCAmJgogICAgICAgICAgcnVudGltZVR5cGUgPT0gb3RoZXIucnVudGltZVR5cGUgJiYKICAgICAgICAgIGV4Y2VwdGlvbi50b1N0cmluZygpID09IG90aGVyLmV4Y2VwdGlvbi50b1N0cmluZygpICYmCiAgICAgICAgICBzdGFja1RyYWNlLnRvU3RyaW5nKCkgPT0gb3RoZXIuc3RhY2tUcmFjZS50b1N0cmluZygpICYmCiAgICAgICAgICBmYXRhbCA9PSBvdGhlci5mYXRhbCAmJgogICAgICAgICAgdGltZXN0YW1wID09IG90aGVyLnRpbWVzdGFtcDsKCiAgQG92ZXJyaWRlCiAgaW50IGdldCBoYXNoQ29kZSA9PgogICAgICBleGNlcHRpb24uaGFzaENvZGUgXgogICAgICBzdGFja1RyYWNlLmhhc2hDb2RlIF4KICAgICAgZmF0YWwuaGFzaENvZGUgXgogICAgICB0aW1lc3RhbXAuaGFzaENvZGU7Cn0K", + "Y2xhc3MgQ3Jhc2hSZXBvcnQgewogIGNvbnN0IENyYXNoUmVwb3J0KHsKICAgIHJlcXVpcmVkIHRoaXMuZXhjZXB0aW9uLAogICAgdGhpcy5zdGFja1RyYWNlLAogICAgdGhpcy5mYXRhbCA9IGZhbHNlLAogICAgdGhpcy50aW1lc3RhbXAsCiAgICB0aGlzLmN1c3RvbUtleXMgPSBjb25zdCB7fSwKICAgIHRoaXMubG9ncyA9IGNvbnN0IFtdLAogICAgdGhpcy51c2VyTWV0YWRhdGEsCiAgfSk7CgogIGZpbmFsIGR5bmFtaWMgZXhjZXB0aW9uOwogIGZpbmFsIFN0YWNrVHJhY2U/IHN0YWNrVHJhY2U7CiAgZmluYWwgYm9vbCBmYXRhbDsKICBmaW5hbCBEYXRlVGltZT8gdGltZXN0YW1wOwogIGZpbmFsIE1hcDxTdHJpbmcsIGR5bmFtaWM+IGN1c3RvbUtleXM7CiAgZmluYWwgTGlzdDxTdHJpbmc+IGxvZ3M7CiAgZmluYWwgTWFwPFN0cmluZywgZHluYW1pYz4/IHVzZXJNZXRhZGF0YTsKCiAgQ3Jhc2hSZXBvcnQgY29weVdpdGgoewogICAgZHluYW1pYyBleGNlcHRpb24sCiAgICBTdGFja1RyYWNlPyBzdGFja1RyYWNlLAogICAgYm9vbD8gZmF0YWwsCiAgICBEYXRlVGltZT8gdGltZXN0YW1wLAogICAgTWFwPFN0cmluZywgZHluYW1pYz4/IGN1c3RvbUtleXMsCiAgICBMaXN0PFN0cmluZz4/IGxvZ3MsCiAgICBNYXA8U3RyaW5nLCBkeW5hbWljPj8gdXNlck1ldGFkYXRhLAogIH0pIHsKICAgIHJldHVybiBDcmFzaFJlcG9ydCgKICAgICAgZXhjZXB0aW9uOiBleGNlcHRpb24gPz8gdGhpcy5leGNlcHRpb24sCiAgICAgIHN0YWNrVHJhY2U6IHN0YWNrVHJhY2UgPz8gdGhpcy5zdGFja1RyYWNlLAogICAgICBmYXRhbDogZmF0YWwgPz8gdGhpcy5mYXRhbCwKICAgICAgdGltZXN0YW1wOiB0aW1lc3RhbXAgPz8gdGhpcy50aW1lc3RhbXAsCiAgICAgIGN1c3RvbUtleXM6IGN1c3RvbUtleXMgPz8gdGhpcy5jdXN0b21LZXlzLAogICAgICBsb2dzOiBsb2dzID8/IHRoaXMubG9ncywKICAgICAgdXNlck1ldGFkYXRhOiB1c2VyTWV0YWRhdGEgPz8gdGhpcy51c2VyTWV0YWRhdGEsCiAgICApOwogIH0KCiAgTWFwPFN0cmluZywgZHluYW1pYz4gdG9NYXAoKSB7CiAgICByZXR1cm4gewogICAgICAnZXhjZXB0aW9uJzogZXhjZXB0aW9uLnRvU3RyaW5nKCksCiAgICAgICdzdGFja1RyYWNlJzogc3RhY2tUcmFjZT8udG9TdHJpbmcoKSwKICAgICAgJ2ZhdGFsJzogZmF0YWwsCiAgICAgICd0aW1lc3RhbXAnOiB0aW1lc3RhbXA/LnRvSXNvODYwMVN0cmluZygpLAogICAgICAnY3VzdG9tS2V5cyc6IGN1c3RvbUtleXMsCiAgICAgICdsb2dzJzogbG9ncywKICAgICAgJ3VzZXJNZXRhZGF0YSc6IHVzZXJNZXRhZGF0YSwKICAgIH07CiAgfQoKICBAb3ZlcnJpZGUKICBTdHJpbmcgdG9TdHJpbmcoKSB7CiAgICByZXR1cm4gJ0NyYXNoUmVwb3J0e2V4Y2VwdGlvbjogJGV4Y2VwdGlvbiwgZmF0YWw6ICRmYXRhbCwgdGltZXN0YW1wOiAkdGltZXN0YW1wfSc7CiAgfQoKICBAb3ZlcnJpZGUKICBib29sIG9wZXJhdG9yID09KE9iamVjdCBvdGhlcikgPT4KICAgICAgaWRlbnRpY2FsKHRoaXMsIG90aGVyKSB8fAogICAgICBvdGhlciBpcyBDcmFzaFJlcG9ydCAmJgogICAgICAgICAgcnVudGltZVR5cGUgPT0gb3RoZXIucnVudGltZVR5cGUgJiYKICAgICAgICAgIGV4Y2VwdGlvbi50b1N0cmluZygpID09IG90aGVyLmV4Y2VwdGlvbi50b1N0cmluZygpICYmCiAgICAgICAgICBzdGFja1RyYWNlLnRvU3RyaW5nKCkgPT0gb3RoZXIuc3RhY2tUcmFjZS50b1N0cmluZygpICYmCiAgICAgICAgICBmYXRhbCA9PSBvdGhlci5mYXRhbCAmJgogICAgICAgICAgdGltZXN0YW1wID09IG90aGVyLnRpbWVzdGFtcDsKCiAgQG92ZXJyaWRlCiAgaW50IGdldCBoYXNoQ29kZSA9PgogICAgICBleGNlcHRpb24udG9TdHJpbmcoKS5oYXNoQ29kZSBeCiAgICAgIHN0YWNrVHJhY2UudG9TdHJpbmcoKS5oYXNoQ29kZSBeCiAgICAgIGZhdGFsLmhhc2hDb2RlIF4KICAgICAgdGltZXN0YW1wLmhhc2hDb2RlOwp9Cg==", "type": "text" }, { @@ -945,14 +1074,14 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "path": "{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/lib/src/models/user_metadata.dart", "data": - "Y2xhc3MgVXNlck1ldGFkYXRhIHsKICBjb25zdCBVc2VyTWV0YWRhdGEoewogICAgdGhpcy51c2VySWQsCiAgICB0aGlzLmVtYWlsLAogICAgdGhpcy5uYW1lLAogICAgdGhpcy5jdXN0b21BdHRyaWJ1dGVzID0gY29uc3Qge30sCiAgfSk7CgogIGZpbmFsIFN0cmluZz8gdXNlcklkOwogIGZpbmFsIFN0cmluZz8gZW1haWw7CiAgZmluYWwgU3RyaW5nPyBuYW1lOwogIGZpbmFsIE1hcDxTdHJpbmcsIGR5bmFtaWM+IGN1c3RvbUF0dHJpYnV0ZXM7CgogIFVzZXJNZXRhZGF0YSBjb3B5V2l0aCh7CiAgICBTdHJpbmc/IHVzZXJJZCwKICAgIFN0cmluZz8gZW1haWwsCiAgICBTdHJpbmc/IG5hbWUsCiAgICBNYXA8U3RyaW5nLCBkeW5hbWljPj8gY3VzdG9tQXR0cmlidXRlcywKICB9KSB7CiAgICByZXR1cm4gVXNlck1ldGFkYXRhKAogICAgICB1c2VySWQ6IHVzZXJJZCA/PyB0aGlzLnVzZXJJZCwKICAgICAgZW1haWw6IGVtYWlsID8/IHRoaXMuZW1haWwsCiAgICAgIG5hbWU6IG5hbWUgPz8gdGhpcy5uYW1lLAogICAgICBjdXN0b21BdHRyaWJ1dGVzOiBjdXN0b21BdHRyaWJ1dGVzID8/IHRoaXMuY3VzdG9tQXR0cmlidXRlcywKICAgICk7CiAgfQoKICBNYXA8U3RyaW5nLCBkeW5hbWljPiB0b01hcCgpIHsKICAgIHJldHVybiB7CiAgICAgICd1c2VySWQnOiB1c2VySWQsCiAgICAgICdlbWFpbCc6IGVtYWlsLAogICAgICAnbmFtZSc6IG5hbWUsCiAgICAgICdjdXN0b21BdHRyaWJ1dGVzJzogY3VzdG9tQXR0cmlidXRlcywKICAgIH07CiAgfQoKICBAb3ZlcnJpZGUKICBTdHJpbmcgdG9TdHJpbmcoKSB7CiAgICByZXR1cm4gJ1VzZXJNZXRhZGF0YXt1c2VySWQ6ICR1c2VySWQsIGVtYWlsOiAkZW1haWwsIG5hbWU6ICRuYW1lLCBjdXN0b21BdHRyaWJ1dGVzOiAkY3VzdG9tQXR0cmlidXRlc30nOwogIH0KCiAgQG92ZXJyaWRlCiAgYm9vbCBvcGVyYXRvciA9PShPYmplY3Qgb3RoZXIpID0+CiAgICAgIGlkZW50aWNhbCh0aGlzLCBvdGhlcikgfHwKICAgICAgb3RoZXIgaXMgVXNlck1ldGFkYXRhICYmCiAgICAgICAgICBydW50aW1lVHlwZSA9PSBvdGhlci5ydW50aW1lVHlwZSAmJgogICAgICAgICAgdXNlcklkID09IG90aGVyLnVzZXJJZCAmJgogICAgICAgICAgZW1haWwgPT0gb3RoZXIuZW1haWwgJiYKICAgICAgICAgIG5hbWUgPT0gb3RoZXIubmFtZSAmJgogICAgICAgICAgX21hcEVxdWFscyhjdXN0b21BdHRyaWJ1dGVzLCBvdGhlci5jdXN0b21BdHRyaWJ1dGVzKTsKCiAgQG92ZXJyaWRlCiAgaW50IGdldCBoYXNoQ29kZSA9PgogICAgICB1c2VySWQuaGFzaENvZGUgXgogICAgICBlbWFpbC5oYXNoQ29kZSBeCiAgICAgIG5hbWUuaGFzaENvZGUgXgogICAgICBjdXN0b21BdHRyaWJ1dGVzLmhhc2hDb2RlOwoKICBib29sIF9tYXBFcXVhbHMoTWFwPFN0cmluZywgZHluYW1pYz4gYSwgTWFwPFN0cmluZywgZHluYW1pYz4gYikgewogICAgaWYgKGEubGVuZ3RoICE9IGIubGVuZ3RoKSByZXR1cm4gZmFsc2U7CiAgICBmb3IgKGZpbmFsIGtleSBpbiBhLmtleXMpIHsKICAgICAgaWYgKCFiLmNvbnRhaW5zS2V5KGtleSkgfHwgYVtrZXldICE9IGJba2V5XSkgcmV0dXJuIGZhbHNlOwogICAgfQogICAgcmV0dXJuIHRydWU7CiAgfQp9Cg==", + "Y2xhc3MgVXNlck1ldGFkYXRhIHsKICBjb25zdCBVc2VyTWV0YWRhdGEoewogICAgdGhpcy51c2VySWQsCiAgICB0aGlzLmVtYWlsLAogICAgdGhpcy5uYW1lLAogICAgdGhpcy5jdXN0b21BdHRyaWJ1dGVzID0gY29uc3Qge30sCiAgfSk7CgogIGZpbmFsIFN0cmluZz8gdXNlcklkOwogIGZpbmFsIFN0cmluZz8gZW1haWw7CiAgZmluYWwgU3RyaW5nPyBuYW1lOwogIGZpbmFsIE1hcDxTdHJpbmcsIGR5bmFtaWM+IGN1c3RvbUF0dHJpYnV0ZXM7CgogIFVzZXJNZXRhZGF0YSBjb3B5V2l0aCh7CiAgICBTdHJpbmc/IHVzZXJJZCwKICAgIFN0cmluZz8gZW1haWwsCiAgICBTdHJpbmc/IG5hbWUsCiAgICBNYXA8U3RyaW5nLCBkeW5hbWljPj8gY3VzdG9tQXR0cmlidXRlcywKICB9KSB7CiAgICByZXR1cm4gVXNlck1ldGFkYXRhKAogICAgICB1c2VySWQ6IHVzZXJJZCA/PyB0aGlzLnVzZXJJZCwKICAgICAgZW1haWw6IGVtYWlsID8/IHRoaXMuZW1haWwsCiAgICAgIG5hbWU6IG5hbWUgPz8gdGhpcy5uYW1lLAogICAgICBjdXN0b21BdHRyaWJ1dGVzOiBjdXN0b21BdHRyaWJ1dGVzID8/IHRoaXMuY3VzdG9tQXR0cmlidXRlcywKICAgICk7CiAgfQoKICBNYXA8U3RyaW5nLCBkeW5hbWljPiB0b01hcCgpIHsKICAgIHJldHVybiB7CiAgICAgICd1c2VySWQnOiB1c2VySWQsCiAgICAgICdlbWFpbCc6IGVtYWlsLAogICAgICAnbmFtZSc6IG5hbWUsCiAgICAgICdjdXN0b21BdHRyaWJ1dGVzJzogY3VzdG9tQXR0cmlidXRlcywKICAgIH07CiAgfQoKICBAb3ZlcnJpZGUKICBTdHJpbmcgdG9TdHJpbmcoKSB7CiAgICByZXR1cm4gJ1VzZXJNZXRhZGF0YXt1c2VySWQ6ICR1c2VySWQsIGVtYWlsOiAkZW1haWwsIG5hbWU6ICRuYW1lLCBjdXN0b21BdHRyaWJ1dGVzOiAkY3VzdG9tQXR0cmlidXRlc30nOwogIH0KCiAgQG92ZXJyaWRlCiAgYm9vbCBvcGVyYXRvciA9PShPYmplY3Qgb3RoZXIpID0+CiAgICAgIGlkZW50aWNhbCh0aGlzLCBvdGhlcikgfHwKICAgICAgb3RoZXIgaXMgVXNlck1ldGFkYXRhICYmCiAgICAgICAgICBydW50aW1lVHlwZSA9PSBvdGhlci5ydW50aW1lVHlwZSAmJgogICAgICAgICAgdXNlcklkID09IG90aGVyLnVzZXJJZCAmJgogICAgICAgICAgZW1haWwgPT0gb3RoZXIuZW1haWwgJiYKICAgICAgICAgIG5hbWUgPT0gb3RoZXIubmFtZSAmJgogICAgICAgICAgX21hcEVxdWFscyhjdXN0b21BdHRyaWJ1dGVzLCBvdGhlci5jdXN0b21BdHRyaWJ1dGVzKTsKCiAgQG92ZXJyaWRlCiAgaW50IGdldCBoYXNoQ29kZSA9PgogICAgICB1c2VySWQuaGFzaENvZGUgXgogICAgICBlbWFpbC5oYXNoQ29kZSBeCiAgICAgIG5hbWUuaGFzaENvZGUgXgogICAgICBPYmplY3QuaGFzaEFsbFVub3JkZXJlZCgKICAgICAgICBjdXN0b21BdHRyaWJ1dGVzLmVudHJpZXMubWFwKChlKSA9PiBPYmplY3QuaGFzaChlLmtleSwgZS52YWx1ZSkpLAogICAgICApOwoKICBib29sIF9tYXBFcXVhbHMoTWFwPFN0cmluZywgZHluYW1pYz4gYSwgTWFwPFN0cmluZywgZHluYW1pYz4gYikgewogICAgaWYgKGEubGVuZ3RoICE9IGIubGVuZ3RoKSByZXR1cm4gZmFsc2U7CiAgICBmb3IgKGZpbmFsIGtleSBpbiBhLmtleXMpIHsKICAgICAgaWYgKCFiLmNvbnRhaW5zS2V5KGtleSkgfHwgYVtrZXldICE9IGJba2V5XSkgcmV0dXJuIGZhbHNlOwogICAgfQogICAgcmV0dXJuIHRydWU7CiAgfQp9Cg==", "type": "text" }, { "path": "{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/pubspec.yaml", "data": - "bmFtZTogY3Jhc2hseXRpY3MKZGVzY3JpcHRpb246ICJDcmFzaCBhbmQgbm9uLWZhdGFsIGVycm9yIHJlcG9ydGluZyBmb3Ige3tuYW1lLnRpdGxlQ2FzZSgpfX0uIgp2ZXJzaW9uOiAwLjEuMApwdWJsaXNoX3RvOiAnbm9uZScKCmVudmlyb25tZW50OgogIHNkazogXjMuOC4wCiAgZmx1dHRlcjogIj49My4yOS4wIgoKZGVwZW5kZW5jaWVzOgogIGZsdXR0ZXI6CiAgICBzZGs6IGZsdXR0ZXIKICBmaXJlYmFzZV9jb3JlOiBeMy4xNC4wCiAgZmlyZWJhc2VfY3Jhc2hseXRpY3M6IF40LjEuNAogIGNvcmU6CiAgICBwYXRoOiAuLi9jb3JlCiAgZGk6CiAgICBwYXRoOiAuLi9kaQoKZGV2X2RlcGVuZGVuY2llczoKICBmbHV0dGVyX3Rlc3Q6CiAgICBzZGs6IGZsdXR0ZXIKICBmbHV0dGVyX2xpbnRzOiBeNS4wLjAKCmZsdXR0ZXI6Cg==", + "bmFtZTogY3Jhc2hseXRpY3MKZGVzY3JpcHRpb246ICJDcmFzaCBhbmQgbm9uLWZhdGFsIGVycm9yIHJlcG9ydGluZyBmb3Ige3tuYW1lLnRpdGxlQ2FzZSgpfX0uIgp2ZXJzaW9uOiAwLjEuMApwdWJsaXNoX3RvOiAnbm9uZScKCmVudmlyb25tZW50OgogIHNkazogXjMuOC4wCiAgZmx1dHRlcjogIj49My4yOS4wIgoKZGVwZW5kZW5jaWVzOgogIGZsdXR0ZXI6CiAgICBzZGs6IGZsdXR0ZXIKICBmaXJlYmFzZV9jb3JlOiBeMy4xNC4wCiAgZmlyZWJhc2VfY3Jhc2hseXRpY3M6IF40LjEuNAogIGNvcmU6CiAgICBwYXRoOiAuLi9jb3JlCiAgZGk6CiAgICBwYXRoOiAuLi9kaQoKZGV2X2RlcGVuZGVuY2llczoKICBtb2NrdGFpbDogXjEuMC40CiAgZmx1dHRlcl90ZXN0OgogICAgc2RrOiBmbHV0dGVyCiAgZmx1dHRlcl9saW50czogXjUuMC4wCgpmbHV0dGVyOgo=", "type": "text" }, { @@ -961,6 +1090,13 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "IyBDcmFzaGx5dGljcwoKRmlyZWJhc2UgQ3Jhc2hseXRpY3MgaW50ZWdyYXRpb24gcGFja2FnZSBmb3Ige3tuYW1lLnRpdGxlQ2FzZSgpfX0gLSBwcm92aWRpbmcgY29tcHJlaGVuc2l2ZSBjcmFzaCByZXBvcnRpbmcgYW5kIGVycm9yIHRyYWNraW5nIGNhcGFiaWxpdGllcy4KClshW25vbnN0b3BfY2xpXShodHRwczovL2ltZy5zaGllbGRzLmlvL2JhZGdlL3N0YXJ0ZWQlMjB3aXRoLW5vbnN0b3BfY2xpLTE2NkM0RS5zdmc/c3R5bGU9ZmxhdC1zcXVhcmUpXShodHRwczovL3B1Yi5kZXYvcGFja2FnZXMvbm9uc3RvcF9jbGkpClshW21lbG9zXShodHRwczovL2ltZy5zaGllbGRzLmlvL2JhZGdlL21haW50YWluZWQlMjB3aXRoLW1lbG9zLWY3MDBmZi5zdmc/c3R5bGU9ZmxhdC1zcXVhcmUpXShodHRwczovL2dpdGh1Yi5jb20vaW52ZXJ0YXNlL21lbG9zKQoKIyMgRmVhdHVyZXMg4pyoCgotIPCflKUgKipGaXJlYmFzZSBDcmFzaGx5dGljcyBJbnRlZ3JhdGlvbioqIC0gQ29tcGxldGUgRmlyZWJhc2UgQ3Jhc2hseXRpY3MgaW1wbGVtZW50YXRpb24KLSDwn5qAICoqQXV0b21hdGljIEVycm9yIEhhbmRsaW5nKiogLSBDYXRjaGVzIEZsdXR0ZXIgZnJhbWV3b3JrIGVycm9ycyBhdXRvbWF0aWNhbGx5Ci0g8J+RpCAqKlVzZXIgQ29udGV4dCoqIC0gVHJhY2sgY3Jhc2hlcyB3aXRoIHVzZXIgaW5mb3JtYXRpb24gYW5kIG1ldGFkYXRhCi0g8J+UkSAqKkN1c3RvbSBBdHRyaWJ1dGVzKiogLSBBZGQgY3VzdG9tIGtleS12YWx1ZSBwYWlycyBmb3IgZGVidWdnaW5nCi0g8J+TiiAqKkN1c3RvbSBMb2dnaW5nKiogLSBMb2cgY3VzdG9tIG1lc3NhZ2VzIGZvciBjcmFzaCBhbmFseXNpcwotIOKame+4jyAqKkNvbmZpZ3VyYWJsZSoqIC0gRmxleGlibGUgY29uZmlndXJhdGlvbiBmb3IgZGlmZmVyZW50IGVudmlyb25tZW50cwotIPCfp6kgKipESSBJbnRlZ3JhdGlvbioqIC0gU2VhbWxlc3MgaW50ZWdyYXRpb24gd2l0aCBkZXBlbmRlbmN5IGluamVjdGlvbgotIPCfm6HvuI8gKipUeXBlIFNhZmUqKiAtIEZ1bGwgVHlwZVNjcmlwdC1zdHlsZSB0eXBlIHNhZmV0eSB3aXRoIERhcnQKCiMjIEluc3RhbGxhdGlvbiDwn5K7CgpBZGQgdG8geW91ciBgcHVic3BlYy55YW1sYDoKCmBgYHlhbWwKZGVwZW5kZW5jaWVzOgogIGNyYXNobHl0aWNzOgogICAgcGF0aDogLi4vcGFja2FnZXMvY3Jhc2hseXRpY3MKYGBgCgojIyBRdWljayBTdGFydCDwn5qACgojIyMgMS4gSW5pdGlhbGl6ZSBpbiB5b3VyIGFwcAoKYGBgZGFydAppbXBvcnQgJ3BhY2thZ2U6Y3Jhc2hseXRpY3MvY3Jhc2hseXRpY3MuZGFydCc7Cgp2b2lkIG1haW4oKSBhc3luYyB7CiAgV2lkZ2V0c0ZsdXR0ZXJCaW5kaW5nLmVuc3VyZUluaXRpYWxpemVkKCk7CiAgCiAgLy8gSW5pdGlhbGl6ZSBjcmFzaGx5dGljcyB3aXRoIGRlZmF1bHQgY29uZmlnCiAgYXdhaXQgY3Jhc2hseXRpY3MuaW5pdCgpOwogIAogIHJ1bkFwcChNeUFwcCgpKTsKfQpgYGAKCiMjIyAyLiBVc2UgdGhlIHNlcnZpY2UKCmBgYGRhcnQKaW1wb3J0ICdwYWNrYWdlOmNyYXNobHl0aWNzL2NyYXNobHl0aWNzLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZGkvZGkuZGFydCc7CgpjbGFzcyBNeVdpZGdldCBleHRlbmRzIFN0YXRlZnVsV2lkZ2V0IHsKICBAb3ZlcnJpZGUKICBfTXlXaWRnZXRTdGF0ZSBjcmVhdGVTdGF0ZSgpID0+IF9NeVdpZGdldFN0YXRlKCk7Cn0KCmNsYXNzIF9NeVdpZGdldFN0YXRlIGV4dGVuZHMgU3RhdGU8TXlXaWRnZXQ+IHsKICBsYXRlIGZpbmFsIENyYXNobHl0aWNzU2VydmljZSBfY3Jhc2hseXRpY3M7CgogIEBvdmVycmlkZQogIHZvaWQgaW5pdFN0YXRlKCkgewogICAgc3VwZXIuaW5pdFN0YXRlKCk7CiAgICBfY3Jhc2hseXRpY3MgPSBkaS5nZXQ8Q3Jhc2hseXRpY3NTZXJ2aWNlPigpOwogIH0KCiAgdm9pZCBfcmVwb3J0RXJyb3IoKSBhc3luYyB7CiAgICB0cnkgewogICAgICAvLyBTb21lIHJpc2t5IG9wZXJhdGlvbgogICAgICB0aHJvdyBFeGNlcHRpb24oJ1NvbWV0aGluZyB3ZW50IHdyb25nIScpOwogICAgfSBjYXRjaCAoZXJyb3IsIHN0YWNrVHJhY2UpIHsKICAgICAgLy8gUmVwb3J0IHRoZSBlcnJvcgogICAgICBhd2FpdCBfY3Jhc2hseXRpY3MucmVwb3J0RXJyb3IoCiAgICAgICAgZXJyb3IsIAogICAgICAgIHN0YWNrVHJhY2U6IHN0YWNrVHJhY2UsCiAgICAgICAgY29udGV4dDogeydmZWF0dXJlJzogJ3VzZXJfYWN0aW9uJywgJ3NjcmVlbic6ICdob21lJ30sCiAgICAgICk7CiAgICB9CiAgfQp9CmBgYAoKIyMgQ29uZmlndXJhdGlvbiDimpnvuI8KCiMjIyBCYXNpYyBDb25maWd1cmF0aW9uCgpgYGBkYXJ0CmltcG9ydCAncGFja2FnZTpjcmFzaGx5dGljcy9jcmFzaGx5dGljcy5kYXJ0JzsKCmF3YWl0IGNyYXNobHl0aWNzLmluaXQoCiAgY29uZmlnOiBDcmFzaGx5dGljc0NvbmZpZygKICAgIGVuYWJsZUluRGVidWdNb2RlOiBmYWxzZSwKICAgIGVuYWJsZUF1dG9tYXRpY0RhdGFDb2xsZWN0aW9uOiB0cnVlLAogICAgZW5hYmxlQ3VzdG9tTG9nczogdHJ1ZSwKICAgIGxvZ0J1ZmZlclNpemU6IDEwMCwKICAgIGVuYWJsZVVzZXJNZXRhZGF0YTogdHJ1ZSwKICAgIGN1c3RvbUtleXM6IHsKICAgICAgJ2FwcF92ZXJzaW9uJzogJzEuMC4wJywKICAgICAgJ2Vudmlyb25tZW50JzogJ3Byb2R1Y3Rpb24nLAogICAgfSwKICApLAopOwpgYGAKCiMjIyBBZHZhbmNlZCBDb25maWd1cmF0aW9uCgpgYGBkYXJ0Ci8vIEN1c3RvbSBjb25maWd1cmF0aW9uIGZvciBkaWZmZXJlbnQgZW52aXJvbm1lbnRzCmZpbmFsIGNvbmZpZyA9IGtEZWJ1Z01vZGUgCiAgPyBDcmFzaGx5dGljc0NvbmZpZygKICAgICAgZW5hYmxlSW5EZWJ1Z01vZGU6IHRydWUsCiAgICAgIGVuYWJsZUF1dG9tYXRpY0RhdGFDb2xsZWN0aW9uOiBmYWxzZSwKICAgICAgY3VzdG9tS2V5czogeydlbnZpcm9ubWVudCc6ICdkZWJ1Zyd9LAogICAgKQogIDogQ3Jhc2hseXRpY3NDb25maWcoCiAgICAgIGVuYWJsZUF1dG9tYXRpY0RhdGFDb2xsZWN0aW9uOiB0cnVlLAogICAgICBsb2dCdWZmZXJTaXplOiAyMDAsCiAgICAgIGN1c3RvbUtleXM6IHsnZW52aXJvbm1lbnQnOiAncHJvZHVjdGlvbid9LAogICAgKTsKCmF3YWl0IGNyYXNobHl0aWNzLmluaXQoY29uZmlnOiBjb25maWcpOwpgYGAKCiMjIFVzYWdlIEV4YW1wbGVzIPCfk50KCiMjIyBFcnJvciBSZXBvcnRpbmcKCmBgYGRhcnQKZmluYWwgY3Jhc2hseXRpY3MgPSBkaS5nZXQ8Q3Jhc2hseXRpY3NTZXJ2aWNlPigpOwoKLy8gUmVwb3J0IGEgbm9uLWZhdGFsIGVycm9yCmF3YWl0IGNyYXNobHl0aWNzLnJlcG9ydEVycm9yKAogIEV4Y2VwdGlvbignTmV0d29yayB0aW1lb3V0JyksCiAgc3RhY2tUcmFjZTogU3RhY2tUcmFjZS5jdXJyZW50LAogIGNvbnRleHQ6IHsnZW5kcG9pbnQnOiAnL2FwaS91c2VycycsICd0aW1lb3V0JzogJzMwcyd9LAopOwoKLy8gUmVwb3J0IGEgZmF0YWwgZXJyb3IKYXdhaXQgY3Jhc2hseXRpY3MucmVwb3J0RXJyb3IoCiAgZXJyb3IsCiAgc3RhY2tUcmFjZTogc3RhY2tUcmFjZSwKICBmYXRhbDogdHJ1ZSwKICB1c2VySWQ6ICd1c2VyMTIzJywKKTsKYGBgCgojIyMgVXNlciBDb250ZXh0CgpgYGBkYXJ0Ci8vIFNldCB1c2VyIGluZm9ybWF0aW9uCmF3YWl0IGNyYXNobHl0aWNzLnNldFVzZXIoCiAgdXNlcklkOiAndXNlcjEyMycsCiAgZW1haWw6ICd1c2VyQGV4YW1wbGUuY29tJywKICBuYW1lOiAnSm9obiBEb2UnLAogIGN1c3RvbUF0dHJpYnV0ZXM6IHsKICAgICdzdWJzY3JpcHRpb24nOiAncHJlbWl1bScsCiAgICAnbGFzdF9sb2dpbic6IERhdGVUaW1lLm5vdygpLnRvSXNvODYwMVN0cmluZygpLAogIH0sCik7CgovLyBDbGVhciB1c2VyIGluZm9ybWF0aW9uIChlLmcuLCBvbiBsb2dvdXQpCmF3YWl0IGNyYXNobHl0aWNzLmNsZWFyVXNlcigpOwpgYGAKCiMjIyBDdXN0b20gTG9nZ2luZwoKYGBgZGFydAovLyBMb2cgY3VzdG9tIG1lc3NhZ2VzCmF3YWl0IGNyYXNobHl0aWNzLmxvZ01lc3NhZ2UoJ1VzZXIgY29tcGxldGVkIG9uYm9hcmRpbmcnKTsKYXdhaXQgY3Jhc2hseXRpY3MubG9nTWVzc2FnZSgnQVBJIGNhbGwgc3RhcnRlZDogL3VzZXJzL3Byb2ZpbGUnKTsKCi8vIFNldCBjdXN0b20gYXR0cmlidXRlcwphd2FpdCBjcmFzaGx5dGljcy5zZXRDdXN0b21BdHRyaWJ1dGVzKHsKICAnZmVhdHVyZV9mbGFnX2EnOiB0cnVlLAogICdhcGlfdmVyc2lvbic6ICd2MicsCiAgJ2RldmljZV90eXBlJzogJ21vYmlsZScsCn0pOwoKLy8gU2V0IGluZGl2aWR1YWwgY3VzdG9tIGF0dHJpYnV0ZQphd2FpdCBjcmFzaGx5dGljcy5zZXRDdXN0b21BdHRyaWJ1dGUoJ2N1cnJlbnRfc2NyZWVuJywgJ3Byb2ZpbGUnKTsKYGBgCgojIyMgTWFudWFsIENyYXNoIFJlcG9ydGluZwoKYGBgZGFydAovLyBVc2UgdGhlIGNsaWVudCBkaXJlY3RseSBmb3IgYWR2YW5jZWQgc2NlbmFyaW9zCmZpbmFsIGNsaWVudCA9IGRpLmdldDxDcmFzaGx5dGljc0NsaWVudD4oKTsKCmF3YWl0IGNsaWVudC5yZWNvcmRFcnJvcigKICBDdXN0b21FeGNlcHRpb24oJ0RhdGFiYXNlIGNvbm5lY3Rpb24gZmFpbGVkJyksCiAgU3RhY2tUcmFjZS5jdXJyZW50LAogIGZhdGFsOiBmYWxzZSwKICBpbmZvcm1hdGlvbjogWydEYXRhYmFzZSBob3N0OiBkYi5leGFtcGxlLmNvbScsICdDb25uZWN0aW9uIHRpbWVvdXQ6IDMwcyddLAopOwpgYGAKCiMjIEFQSSBSZWZlcmVuY2Ug8J+TmgoKIyMjIENyYXNobHl0aWNzU2VydmljZQoKTWFpbiBzZXJ2aWNlIGNsYXNzIGZvciBjcmFzaCByZXBvcnRpbmc6Cgp8IE1ldGhvZCB8IERlc2NyaXB0aW9uIHwKfC0tLS0tLS0tfC0tLS0tLS0tLS0tLS18CnwgYHJlcG9ydEVycm9yKClgIHwgUmVwb3J0IGFuIGVycm9yIG9yIGV4Y2VwdGlvbiB8CnwgYHJlcG9ydEZsdXR0ZXJFcnJvcigpYCB8IFJlcG9ydCBGbHV0dGVyIGZyYW1ld29yayBlcnJvcnMgfAp8IGBsb2dNZXNzYWdlKClgIHwgTG9nIGN1c3RvbSBtZXNzYWdlcyB8CnwgYHNldFVzZXIoKWAgfCBTZXQgdXNlciBpbmZvcm1hdGlvbiB8CnwgYGNsZWFyVXNlcigpYCB8IENsZWFyIHVzZXIgaW5mb3JtYXRpb24gfAp8IGBzZXRDdXN0b21BdHRyaWJ1dGVzKClgIHwgU2V0IG11bHRpcGxlIGN1c3RvbSBhdHRyaWJ1dGVzIHwKfCBgc2V0Q3VzdG9tQXR0cmlidXRlKClgIHwgU2V0IHNpbmdsZSBjdXN0b20gYXR0cmlidXRlIHwKfCBgc2V0Q3Jhc2hSZXBvcnRpbmdFbmFibGVkKClgIHwgRW5hYmxlL2Rpc2FibGUgY3Jhc2ggcmVwb3J0aW5nIHwKfCBgc2VuZFBlbmRpbmdSZXBvcnRzKClgIHwgU2VuZCB1bnNlbnQgY3Jhc2ggcmVwb3J0cyB8CnwgYGRlbGV0ZVBlbmRpbmdSZXBvcnRzKClgIHwgRGVsZXRlIHVuc2VudCBjcmFzaCByZXBvcnRzIHwKCiMjIyBDcmFzaGx5dGljc0NvbmZpZwoKQ29uZmlndXJhdGlvbiBvcHRpb25zOgoKfCBQcm9wZXJ0eSB8IERlZmF1bHQgfCBEZXNjcmlwdGlvbiB8CnwtLS0tLS0tLS0tfC0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tfAp8IGBlbmFibGVJbkRlYnVnTW9kZWAgfCBgZmFsc2VgIHwgRW5hYmxlIGNyYXNobHl0aWNzIGluIGRlYnVnIG1vZGUgfAp8IGBlbmFibGVBdXRvbWF0aWNEYXRhQ29sbGVjdGlvbmAgfCBgdHJ1ZWAgfCBFbmFibGUgYXV0b21hdGljIGVycm9yIGNvbGxlY3Rpb24gfAp8IGBlbmFibGVDdXN0b21Mb2dzYCB8IGB0cnVlYCB8IEVuYWJsZSBjdXN0b20gbG9nZ2luZyB8CnwgYGxvZ0J1ZmZlclNpemVgIHwgYDEwMGAgfCBNYXhpbXVtIGxvZyBidWZmZXIgc2l6ZSB8CnwgYGVuYWJsZVVzZXJNZXRhZGF0YWAgfCBgdHJ1ZWAgfCBFbmFibGUgdXNlciBtZXRhZGF0YSBjb2xsZWN0aW9uIHwKfCBgY3VzdG9tS2V5c2AgfCBge31gIHwgRGVmYXVsdCBjdXN0b20ga2V5cyB8CgojIyBJbnRlZ3JhdGlvbiB3aXRoIERJIPCflKcKClRoZSBwYWNrYWdlIGludGVncmF0ZXMgc2VhbWxlc3NseSB3aXRoIHRoZSBESSBjb250YWluZXI6CgpgYGBkYXJ0Ci8vIEdldCBzZXJ2aWNlcyBmcm9tIERJCmZpbmFsIGNyYXNobHl0aWNzID0gZGkuZ2V0PENyYXNobHl0aWNzU2VydmljZT4oKTsKZmluYWwgY2xpZW50ID0gZGkuZ2V0PENyYXNobHl0aWNzQ2xpZW50PigpOwpmaW5hbCBjb25maWcgPSBkaS5nZXQ8Q3Jhc2hseXRpY3NDb25maWc+KCk7CgovLyBTZXJ2aWNlcyBhcmUgYXV0b21hdGljYWxseSBkaXNwb3NlZCB3aGVuIERJIGNvbnRhaW5lciBpcyBkaXNwb3NlZApgYGAKCiMjIFRlc3Rpbmcg8J+nqgoKYGBgZGFydAovLyBVcGRhdGUgdGVzdCBmaWxlCmltcG9ydCAncGFja2FnZTpmbHV0dGVyX3Rlc3QvZmx1dHRlcl90ZXN0LmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Y3Jhc2hseXRpY3MvY3Jhc2hseXRpY3MuZGFydCc7Cgp2b2lkIG1haW4oKSB7CiAgZ3JvdXAoJ0NyYXNobHl0aWNzJywgKCkgewogICAgdGVzdCgnY2FuIGJlIGluaXRpYWxpemVkJywgKCkgYXN5bmMgewogICAgICAvLyBUZXN0IGluaXRpYWxpemF0aW9uCiAgICAgIGV4cGVjdCgoKSA9PiBjcmFzaGx5dGljcy5pbml0KCksIGlzTm90KHRocm93c0V4Y2VwdGlvbikpOwogICAgfSk7CiAgfSk7Cn0KYGBgCgojIyBCZXN0IFByYWN0aWNlcyDwn5KhCgoxLiAqKkluaXRpYWxpemUgRWFybHkqKjogSW5pdGlhbGl6ZSBjcmFzaGx5dGljcyBhcyBlYXJseSBhcyBwb3NzaWJsZSBpbiB5b3VyIGFwcAoyLiAqKkVudmlyb25tZW50IENvbmZpZ3VyYXRpb24qKjogVXNlIGRpZmZlcmVudCBjb25maWdzIGZvciBkZWJ1Zy9yZWxlYXNlIGJ1aWxkcwozLiAqKlVzZXIgUHJpdmFjeSoqOiBCZSBtaW5kZnVsIG9mIHVzZXIgcHJpdmFjeSB3aGVuIHNldHRpbmcgdXNlciBtZXRhZGF0YQo0LiAqKkNvbnRleHQgaXMgS2V5Kio6IEFsd2F5cyBwcm92aWRlIGNvbnRleHQgd2hlbiByZXBvcnRpbmcgZXJyb3JzCjUuICoqVGVzdCBpbiBEZWJ1ZyoqOiBFbmFibGUgZGVidWcgbW9kZSBkdXJpbmcgZGV2ZWxvcG1lbnQgdG8gdGVzdCBpbnRlZ3JhdGlvbgo2LiAqKk1vbml0b3IgVXNhZ2UqKjogUmVndWxhcmx5IGNoZWNrIEZpcmViYXNlIGNvbnNvbGUgZm9yIGNyYXNoIHJlcG9ydHMKCiMjIFJlcXVpcmVtZW50cyDwn5OLCgotIEZsdXR0ZXIgU0RLID49My4xOS4wCi0gRGFydCBTREsgXjMuMy4wCi0gRmlyZWJhc2UgcHJvamVjdCB3aXRoIENyYXNobHl0aWNzIGVuYWJsZWQKLSBgY29yZWAgYW5kIGBkaWAgcGFja2FnZXMgZnJvbSB7e25hbWUudGl0bGVDYXNlKCl9fSBtb25vcmVwbwoKW2ZsdXR0ZXJfaW5zdGFsbF9saW5rXTogaHR0cHM6Ly9kb2NzLmZsdXR0ZXIuZGV2L2dldC1zdGFydGVkL2luc3RhbGw=", "type": "text" }, + { + "path": + "{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/test/client_test.dart", + "data": + "aW1wb3J0ICdwYWNrYWdlOmNvcmUvY29yZS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmNyYXNobHl0aWNzL2NyYXNobHl0aWNzLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Y3Jhc2hseXRpY3MvY3Jhc2hseXRpY3MuZGFydCcgYXMgY3Jhc2g7CmltcG9ydCAncGFja2FnZTpkaS9kaS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZpcmViYXNlX2NyYXNobHl0aWNzL2ZpcmViYXNlX2NyYXNobHl0aWNzLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlci9mb3VuZGF0aW9uLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlcl90ZXN0L2ZsdXR0ZXJfdGVzdC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOm1vY2t0YWlsL21vY2t0YWlsLmRhcnQnOwoKY2xhc3MgX1NkayBleHRlbmRzIE1vY2sgaW1wbGVtZW50cyBGaXJlYmFzZUNyYXNobHl0aWNzIHt9CgpjbGFzcyBfTG9nZ2VyIGV4dGVuZHMgTW9jayBpbXBsZW1lbnRzIExvZ2dlciB7fQoKY2xhc3MgX01ldGFkYXRhIGV4dGVuZHMgTW9jayBpbXBsZW1lbnRzIFVzZXJNZXRhZGF0YSB7fQoKdm9pZCBtYWluKCkgewogIGxhdGUgX1NkayBzZGs7CiAgbGF0ZSBfTG9nZ2VyIGxvZ2dlcjsKICBsYXRlIEZpcmViYXNlQ3Jhc2hseXRpY3NDbGllbnQgY2xpZW50OwogIHNldFVwKCgpIHsKICAgIHNkayA9IF9TZGsoKTsKICAgIGxvZ2dlciA9IF9Mb2dnZXIoKTsKICAgIHdoZW4oCiAgICAgICgpID0+IHNkay5zZXRDcmFzaGx5dGljc0NvbGxlY3Rpb25FbmFibGVkKGFueSgpKSwKICAgICkudGhlbkFuc3dlcigoXykgYXN5bmMge30pOwogICAgd2hlbigoKSA9PiBzZGsuc2V0Q3VzdG9tS2V5KGFueSgpLCBhbnkoKSkpLnRoZW5BbnN3ZXIoKF8pIGFzeW5jIHt9KTsKICAgIHdoZW4oKCkgPT4gc2RrLnNldFVzZXJJZGVudGlmaWVyKGFueSgpKSkudGhlbkFuc3dlcigoXykgYXN5bmMge30pOwogICAgd2hlbigoKSA9PiBzZGsubG9nKGFueSgpKSkudGhlbkFuc3dlcigoXykgYXN5bmMge30pOwogICAgd2hlbigKICAgICAgKCkgPT4gc2RrLnJlY29yZEVycm9yKAogICAgICAgIGFueSgpLAogICAgICAgIGFueSgpLAogICAgICAgIGZhdGFsOiBhbnkobmFtZWQ6ICdmYXRhbCcpLAogICAgICAgIGluZm9ybWF0aW9uOiBhbnkobmFtZWQ6ICdpbmZvcm1hdGlvbicpLAogICAgICApLAogICAgKS50aGVuQW5zd2VyKChfKSBhc3luYyB7fSk7CiAgICB3aGVuKCgpID0+IHNkay5pc0NyYXNobHl0aWNzQ29sbGVjdGlvbkVuYWJsZWQpLnRoZW5SZXR1cm4odHJ1ZSk7CiAgICB3aGVuKHNkay5jaGVja0ZvclVuc2VudFJlcG9ydHMpLnRoZW5BbnN3ZXIoKF8pIGFzeW5jID0+IGZhbHNlKTsKICAgIHdoZW4oc2RrLnNlbmRVbnNlbnRSZXBvcnRzKS50aGVuQW5zd2VyKChfKSBhc3luYyB7fSk7CiAgICB3aGVuKHNkay5kZWxldGVVbnNlbnRSZXBvcnRzKS50aGVuQW5zd2VyKChfKSBhc3luYyB7fSk7CiAgICBjbGllbnQgPSBGaXJlYmFzZUNyYXNobHl0aWNzQ2xpZW50KAogICAgICBjb25maWc6IGNvbnN0IENyYXNobHl0aWNzQ29uZmlnKAogICAgICAgIGVuYWJsZUF1dG9tYXRpY0RhdGFDb2xsZWN0aW9uOiBmYWxzZSwKICAgICAgICBsb2dCdWZmZXJTaXplOiAyLAogICAgICAgIGN1c3RvbUtleXM6IHsnYnVpbGQnOiAndGVzdCd9LAogICAgICApLAogICAgICBsb2dnZXI6IGxvZ2dlciwKICAgICAgY3Jhc2hseXRpY3M6IHNkaywKICAgICk7CiAgfSk7CiAgdGVhckRvd24oKCkgYXN5bmMgewogICAgY2xpZW50LmRpc3Bvc2UoKTsKICAgIGF3YWl0IGRpLnJlc2V0KCk7CiAgfSk7CgogIEZ1dHVyZTx2b2lkPiBleGVyY2lzZUNsaWVudCgpIGFzeW5jIHsKICAgIGF3YWl0IGNsaWVudC5yZWNvcmRFcnJvcignZXJyb3InLCBTdGFja1RyYWNlLmN1cnJlbnQpOwogICAgYXdhaXQgY2xpZW50LnJlY29yZEZsdXR0ZXJGYXRhbEVycm9yKAogICAgICAnZmF0YWwnLAogICAgICBTdGFja1RyYWNlLmN1cnJlbnQsCiAgICAgIGNvbnRleHQ6IHsnc2NyZWVuJzogJ2hvbWUnfSwKICAgICk7CiAgICBhd2FpdCBjbGllbnQubG9nKCdsb2cnKTsKICAgIGF3YWl0IGNsaWVudC5zZXRVc2VySWRlbnRpZmllcigndXNlcicpOwogICAgYXdhaXQgY2xpZW50LnNldFVzZXJNZXRhZGF0YSgKICAgICAgY29uc3QgVXNlck1ldGFkYXRhKAogICAgICAgIHVzZXJJZDogJ3VzZXInLAogICAgICAgIGVtYWlsOiAndGVzdEBleGFtcGxlLnRlc3QnLAogICAgICAgIG5hbWU6ICdUZXN0JywKICAgICAgICBjdXN0b21BdHRyaWJ1dGVzOiB7J3JvbGUnOiAndGVzdGVyJ30sCiAgICAgICksCiAgICApOwogICAgYXdhaXQgY2xpZW50LnNldEN1c3RvbUtleSgna2V5JywgJ3ZhbHVlJyk7CiAgICBhd2FpdCBjbGllbnQuc2V0Q3VzdG9tS2V5cyh7J2tleSc6ICd2YWx1ZSd9KTsKICAgIGF3YWl0IGNsaWVudC5zZXRDcmFzaGx5dGljc0NvbGxlY3Rpb25FbmFibGVkKGZhbHNlKTsKICAgIGF3YWl0IGNsaWVudC5zZW5kVW5zZW50UmVwb3J0cygpOwogICAgYXdhaXQgY2xpZW50LmRlbGV0ZVVuc2VudFJlcG9ydHMoKTsKICAgIGF3YWl0IGNsaWVudC5jaGVja0ZvclVuc2VudFJlcG9ydHMoKTsKICB9CgogIHRlc3QoCiAgICAnaW52YWxpZCBtZXRhZGF0YSBpcyBjb250YWluZWQgYW5kIHN0YXJ0dXAgU0RLIGVycm9ycyBwcm9wYWdhdGUnLAogICAgKCkgYXN5bmMgewogICAgICBhd2FpdCBjbGllbnQuaW5pdGlhbGl6ZSgpOwogICAgICBmaW5hbCBtZXRhZGF0YSA9IF9NZXRhZGF0YSgpOwogICAgICB3aGVuKCgpID0+IG1ldGFkYXRhLnVzZXJJZCkudGhlblRocm93KFN0YXRlRXJyb3IoJ2ludmFsaWQgbWV0YWRhdGEnKSk7CiAgICAgIGF3YWl0IGNsaWVudC5zZXRVc2VyTWV0YWRhdGEobWV0YWRhdGEpOwogICAgICB2ZXJpZnkoKCkgPT4gbG9nZ2VyLmUoYW55KCkpKS5jYWxsZWQoMSk7CiAgICAgIGRpLnJlZ2lzdGVyPExvZ2dlcj4obG9nZ2VyKTsKICAgICAgd2hlbigKICAgICAgICAoKSA9PiBzZGsuc2V0Q3Jhc2hseXRpY3NDb2xsZWN0aW9uRW5hYmxlZChhbnkoKSksCiAgICAgICkudGhlblRocm93KFN0YXRlRXJyb3IoJ3N0YXJ0dXAnKSk7CiAgICAgIGF3YWl0IGV4cGVjdExhdGVyKGNyYXNoLmluaXQoY3Jhc2hseXRpY3M6IHNkayksIHRocm93c1N0YXRlRXJyb3IpOwogICAgICBleHBlY3QoZGkuaGFzPENyYXNobHl0aWNzQ2xpZW50PigpLCBpc0ZhbHNlKTsKICAgICAgZXhwZWN0KGRpLmhhczxDcmFzaGx5dGljc0NvbmZpZz4oKSwgaXNGYWxzZSk7CiAgICAgIHdoZW4oCiAgICAgICAgKCkgPT4gc2RrLnNldENyYXNobHl0aWNzQ29sbGVjdGlvbkVuYWJsZWQoYW55KCkpLAogICAgICApLnRoZW5BbnN3ZXIoKF8pIGFzeW5jIHt9KTsKICAgICAgYXdhaXQgY3Jhc2guaW5pdChjcmFzaGx5dGljczogc2RrKTsKICAgICAgZXhwZWN0KGRpLmhhczxDcmFzaGx5dGljc0NsaWVudD4oKSwgaXNUcnVlKTsKICAgIH0sCiAgKTsKCiAgdGVzdCgnYmVmb3JlIGluaXRpYWxpemF0aW9uIG9wZXJhdGlvbnMgc2FmZWx5IHNraXAgU0RLIGNhbGxzJywgKCkgYXN5bmMgewogICAgYXdhaXQgZXhlcmNpc2VDbGllbnQoKTsKICAgIGV4cGVjdChjbGllbnQuaXNDcmFzaGx5dGljc0NvbGxlY3Rpb25FbmFibGVkLCBpc0ZhbHNlKTsKICAgIHZlcmlmeU5ldmVyKCgpID0+IHNkay5sb2coYW55KCkpKTsKICB9KTsKCiAgdGVzdCgnaW5pdGlhbGl6YXRpb24gYXBwbGllcyBjdXN0b20ga2V5cyBhbmQgY2FuIGJlIGNhbGxlZCB0d2ljZScsICgpIGFzeW5jIHsKICAgIGF3YWl0IGNsaWVudC5pbml0aWFsaXplKCk7CiAgICBhd2FpdCBjbGllbnQuaW5pdGlhbGl6ZSgpOwogICAgdmVyaWZ5KCgpID0+IHNkay5zZXRDdXN0b21LZXkoJ2J1aWxkJywgJ3Rlc3QnKSkuY2FsbGVkKDEpOwogICAgZXhwZWN0KGNsaWVudC5pc0NyYXNobHl0aWNzQ29sbGVjdGlvbkVuYWJsZWQsIGlzVHJ1ZSk7CiAgICBhd2FpdCBleGVyY2lzZUNsaWVudCgpOwogICAgYXdhaXQgY2xpZW50LmxvZygnc2Vjb25kJyk7CiAgICBhd2FpdCBjbGllbnQubG9nKCd0aGlyZCcpOwogICAgZXhwZWN0KGNsaWVudC5idWZmZXJlZExvZ3MsIGhhc0xlbmd0aCgyKSk7CiAgICBleHBlY3QoY2xpZW50LmJ1ZmZlcmVkTG9ncy5sYXN0LCBlbmRzV2l0aCgndGhpcmQnKSk7CiAgICBjbGllbnQuY2xlYXJMb2dCdWZmZXIoKTsKICAgIGV4cGVjdChjbGllbnQuYnVmZmVyZWRMb2dzLCBpc0VtcHR5KTsKICB9KTsKCiAgdGVzdCgnU0RLIGZhaWx1cmVzIGFyZSBjb250YWluZWQgYWZ0ZXIgaW5pdGlhbGl6YXRpb24nLCAoKSBhc3luYyB7CiAgICBhd2FpdCBjbGllbnQuaW5pdGlhbGl6ZSgpOwogICAgd2hlbigKICAgICAgKCkgPT4gc2RrLnNldENyYXNobHl0aWNzQ29sbGVjdGlvbkVuYWJsZWQoYW55KCkpLAogICAgKS50aGVuVGhyb3coU3RhdGVFcnJvcignc2RrJykpOwogICAgd2hlbigoKSA9PiBzZGsuc2V0Q3VzdG9tS2V5KGFueSgpLCBhbnkoKSkpLnRoZW5UaHJvdyhTdGF0ZUVycm9yKCdzZGsnKSk7CiAgICB3aGVuKCgpID0+IHNkay5zZXRVc2VySWRlbnRpZmllcihhbnkoKSkpLnRoZW5UaHJvdyhTdGF0ZUVycm9yKCdzZGsnKSk7CiAgICB3aGVuKCgpID0+IHNkay5sb2coYW55KCkpKS50aGVuVGhyb3coU3RhdGVFcnJvcignc2RrJykpOwogICAgd2hlbigKICAgICAgKCkgPT4gc2RrLnJlY29yZEVycm9yKAogICAgICAgIGFueSgpLAogICAgICAgIGFueSgpLAogICAgICAgIGZhdGFsOiBhbnkobmFtZWQ6ICdmYXRhbCcpLAogICAgICAgIGluZm9ybWF0aW9uOiBhbnkobmFtZWQ6ICdpbmZvcm1hdGlvbicpLAogICAgICApLAogICAgKS50aGVuVGhyb3coU3RhdGVFcnJvcignc2RrJykpOwogICAgd2hlbihzZGsuY2hlY2tGb3JVbnNlbnRSZXBvcnRzKS50aGVuVGhyb3coU3RhdGVFcnJvcignc2RrJykpOwogICAgd2hlbihzZGsuc2VuZFVuc2VudFJlcG9ydHMpLnRoZW5UaHJvdyhTdGF0ZUVycm9yKCdzZGsnKSk7CiAgICB3aGVuKHNkay5kZWxldGVVbnNlbnRSZXBvcnRzKS50aGVuVGhyb3coU3RhdGVFcnJvcignc2RrJykpOwogICAgYXdhaXQgZXhlcmNpc2VDbGllbnQoKTsKICAgIGV4cGVjdChhd2FpdCBjbGllbnQuY2hlY2tGb3JVbnNlbnRSZXBvcnRzKCksIGlzRmFsc2UpOwogIH0pOwoKICB0ZXN0KCdmYWlsZWQgaW5pdGlhbGl6YXRpb24gcmVtYWlucyByZXRyeWFibGUnLCAoKSBhc3luYyB7CiAgICB3aGVuKAogICAgICAoKSA9PiBzZGsuc2V0Q3Jhc2hseXRpY3NDb2xsZWN0aW9uRW5hYmxlZChhbnkoKSksCiAgICApLnRoZW5UaHJvdyhTdGF0ZUVycm9yKCdzZGsnKSk7CiAgICBhd2FpdCBleHBlY3RMYXRlcihjbGllbnQuaW5pdGlhbGl6ZSgpLCB0aHJvd3NTdGF0ZUVycm9yKTsKICAgIGV4cGVjdChjbGllbnQuaXNDcmFzaGx5dGljc0NvbGxlY3Rpb25FbmFibGVkLCBpc0ZhbHNlKTsKICAgIHdoZW4oCiAgICAgICgpID0+IHNkay5zZXRDcmFzaGx5dGljc0NvbGxlY3Rpb25FbmFibGVkKGFueSgpKSwKICAgICkudGhlbkFuc3dlcigoXykgYXN5bmMge30pOwogICAgYXdhaXQgY2xpZW50LmluaXRpYWxpemUoKTsKICAgIGV4cGVjdChjbGllbnQuaXNDcmFzaGx5dGljc0NvbGxlY3Rpb25FbmFibGVkLCBpc1RydWUpOwogIH0pOwoKICB0ZXN0KCdnbG9iYWwgaGFuZGxlcnMgYXJlIGNoYWluZWQgYW5kIHJlc3RvcmVkIHdoZW4gZGlzcG9zZWQnLCAoKSBhc3luYyB7CiAgICBmaW5hbCBwcmV2aW91c0ZsdXR0ZXIgPSBGbHV0dGVyRXJyb3Iub25FcnJvcjsKICAgIGZpbmFsIHByZXZpb3VzUGxhdGZvcm0gPSBQbGF0Zm9ybURpc3BhdGNoZXIuaW5zdGFuY2Uub25FcnJvcjsKICAgIHZhciBmbHV0dGVyQ2FsbHMgPSAwOwogICAgdmFyIHBsYXRmb3JtQ2FsbHMgPSAwOwogICAgdm9pZCBmbHV0dGVySGFuZGxlcihGbHV0dGVyRXJyb3JEZXRhaWxzIGRldGFpbHMpIHsKICAgICAgZmx1dHRlckNhbGxzKys7CiAgICB9CgogICAgYm9vbCBwbGF0Zm9ybUhhbmRsZXIoT2JqZWN0IGVycm9yLCBTdGFja1RyYWNlIHN0YWNrKSB7CiAgICAgIHBsYXRmb3JtQ2FsbHMrKzsKICAgICAgcmV0dXJuIHRydWU7CiAgICB9CgogICAgRmx1dHRlckVycm9yLm9uRXJyb3IgPSBmbHV0dGVySGFuZGxlcjsKICAgIFBsYXRmb3JtRGlzcGF0Y2hlci5pbnN0YW5jZS5vbkVycm9yID0gcGxhdGZvcm1IYW5kbGVyOwogICAgdHJ5IHsKICAgICAgY2xpZW50ID0gRmlyZWJhc2VDcmFzaGx5dGljc0NsaWVudCgKICAgICAgICBjb25maWc6IGNvbnN0IENyYXNobHl0aWNzQ29uZmlnKCksCiAgICAgICAgbG9nZ2VyOiBsb2dnZXIsCiAgICAgICAgY3Jhc2hseXRpY3M6IHNkaywKICAgICAgKTsKICAgICAgYXdhaXQgY2xpZW50LmluaXRpYWxpemUoKTsKICAgICAgRmx1dHRlckVycm9yLm9uRXJyb3IhKEZsdXR0ZXJFcnJvckRldGFpbHMoZXhjZXB0aW9uOiBTdGF0ZUVycm9yKCd0ZXN0JykpKTsKICAgICAgZXhwZWN0KAogICAgICAgIFBsYXRmb3JtRGlzcGF0Y2hlci5pbnN0YW5jZS5vbkVycm9yISgKICAgICAgICAgIFN0YXRlRXJyb3IoJ3Rlc3QnKSwKICAgICAgICAgIFN0YWNrVHJhY2UuY3VycmVudCwKICAgICAgICApLAogICAgICAgIGlzVHJ1ZSwKICAgICAgKTsKICAgICAgYXdhaXQgcHVtcEV2ZW50UXVldWUoKTsKICAgICAgZXhwZWN0KGZsdXR0ZXJDYWxscywgMSk7CiAgICAgIGV4cGVjdChwbGF0Zm9ybUNhbGxzLCAxKTsKICAgICAgY2xpZW50LmRpc3Bvc2UoKTsKICAgICAgZXhwZWN0KEZsdXR0ZXJFcnJvci5vbkVycm9yLCBzYW1lKGZsdXR0ZXJIYW5kbGVyKSk7CiAgICAgIGV4cGVjdChQbGF0Zm9ybURpc3BhdGNoZXIuaW5zdGFuY2Uub25FcnJvciwgc2FtZShwbGF0Zm9ybUhhbmRsZXIpKTsKICAgIH0gZmluYWxseSB7CiAgICAgIEZsdXR0ZXJFcnJvci5vbkVycm9yID0gcHJldmlvdXNGbHV0dGVyOwogICAgICBQbGF0Zm9ybURpc3BhdGNoZXIuaW5zdGFuY2Uub25FcnJvciA9IHByZXZpb3VzUGxhdGZvcm07CiAgICB9CiAgfSk7CgogIGZvciAoZmluYWwgaGFzUmVwb3J0cyBpbiBbZmFsc2UsIHRydWVdKSB7CiAgICB0ZXN0KCdtb2R1bGUgaW5pdGlhbGl6ZXMgd2l0aCBwZW5kaW5nIHJlcG9ydHM9JGhhc1JlcG9ydHMnLCAoKSBhc3luYyB7CiAgICAgIGRpLnJlZ2lzdGVyPExvZ2dlcj4obG9nZ2VyKTsKICAgICAgd2hlbihzZGsuY2hlY2tGb3JVbnNlbnRSZXBvcnRzKS50aGVuQW5zd2VyKChfKSBhc3luYyA9PiBoYXNSZXBvcnRzKTsKICAgICAgYXdhaXQgY3Jhc2guaW5pdCgKICAgICAgICBjb25maWc6IGNvbnN0IENyYXNobHl0aWNzQ29uZmlnKGVuYWJsZUF1dG9tYXRpY0RhdGFDb2xsZWN0aW9uOiBmYWxzZSksCiAgICAgICAgY3Jhc2hseXRpY3M6IHNkaywKICAgICAgKTsKICAgICAgZXhwZWN0KGRpLmhhczxDcmFzaGx5dGljc0NsaWVudD4oKSwgaXNUcnVlKTsKICAgICAgaWYgKGhhc1JlcG9ydHMpIHZlcmlmeShzZGsuc2VuZFVuc2VudFJlcG9ydHMpLmNhbGxlZCgxKTsKICAgIH0pOwogIH0KCiAgdGVzdCgnZXF1YWwgY29uZmlnIHZhbHVlcyBoYXZlIGVxdWFsIGhhc2hlcyByZWdhcmRsZXNzIG9mIG1hcCBvcmRlcicsICgpIHsKICAgIGNvbnN0IGZpcnN0ID0gQ3Jhc2hseXRpY3NDb25maWcoY3VzdG9tS2V5czogeydhJzogMSwgJ2InOiAyfSk7CiAgICBjb25zdCBzZWNvbmQgPSBDcmFzaGx5dGljc0NvbmZpZyhjdXN0b21LZXlzOiB7J2InOiAyLCAnYSc6IDF9KTsKICAgIGV4cGVjdChmaXJzdCwgc2Vjb25kKTsKICAgIGV4cGVjdChmaXJzdC5oYXNoQ29kZSwgc2Vjb25kLmhhc2hDb2RlKTsKICAgIGV4cGVjdCh7Zmlyc3QsIHNlY29uZH0sIGhhc0xlbmd0aCgxKSk7CiAgfSk7Cn0K", + "type": "text" + }, { "path": "{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/test/crashlytics_test.dart", @@ -968,6 +1104,13 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "aW1wb3J0ICdwYWNrYWdlOmNyYXNobHl0aWNzL2NyYXNobHl0aWNzLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlcl90ZXN0L2ZsdXR0ZXJfdGVzdC5kYXJ0JzsKCnZvaWQgbWFpbigpIHsKICBncm91cCgnQ3Jhc2hseXRpY3MnLCAoKSB7CiAgICBncm91cCgnQ3Jhc2hseXRpY3NDb25maWcnLCAoKSB7CiAgICAgIHRlc3QoJ2NyZWF0ZXMgZGVmYXVsdCBjb25maWcgY29ycmVjdGx5JywgKCkgewogICAgICAgIGNvbnN0IGNvbmZpZyA9IERlZmF1bHRDcmFzaGx5dGljc0NvbmZpZygpOwoKICAgICAgICBleHBlY3QoY29uZmlnLmVuYWJsZUluRGVidWdNb2RlLCBmYWxzZSk7CiAgICAgICAgZXhwZWN0KGNvbmZpZy5lbmFibGVBdXRvbWF0aWNEYXRhQ29sbGVjdGlvbiwgdHJ1ZSk7CiAgICAgICAgZXhwZWN0KGNvbmZpZy5lbmFibGVDdXN0b21Mb2dzLCB0cnVlKTsKICAgICAgICBleHBlY3QoY29uZmlnLmxvZ0J1ZmZlclNpemUsIDEwMCk7CiAgICAgICAgZXhwZWN0KGNvbmZpZy5lbmFibGVVc2VyTWV0YWRhdGEsIHRydWUpOwogICAgICAgIGV4cGVjdChjb25maWcuY3VzdG9tS2V5cywgaXNFbXB0eSk7CiAgICAgIH0pOwoKICAgICAgdGVzdCgnY3JlYXRlcyBjdXN0b20gY29uZmlnIGNvcnJlY3RseScsICgpIHsKICAgICAgICBjb25zdCBjb25maWcgPSBDcmFzaGx5dGljc0NvbmZpZygKICAgICAgICAgIGVuYWJsZUluRGVidWdNb2RlOiB0cnVlLAogICAgICAgICAgZW5hYmxlQXV0b21hdGljRGF0YUNvbGxlY3Rpb246IGZhbHNlLAogICAgICAgICAgbG9nQnVmZmVyU2l6ZTogNTAsCiAgICAgICAgICBjdXN0b21LZXlzOiB7J3Rlc3QnOiAndmFsdWUnfSwKICAgICAgICApOwoKICAgICAgICBleHBlY3QoY29uZmlnLmVuYWJsZUluRGVidWdNb2RlLCB0cnVlKTsKICAgICAgICBleHBlY3QoY29uZmlnLmVuYWJsZUF1dG9tYXRpY0RhdGFDb2xsZWN0aW9uLCBmYWxzZSk7CiAgICAgICAgZXhwZWN0KGNvbmZpZy5sb2dCdWZmZXJTaXplLCA1MCk7CiAgICAgICAgZXhwZWN0KGNvbmZpZy5jdXN0b21LZXlzLCB7J3Rlc3QnOiAndmFsdWUnfSk7CiAgICAgIH0pOwoKICAgICAgdGVzdCgnY29weVdpdGggd29ya3MgY29ycmVjdGx5JywgKCkgewogICAgICAgIGNvbnN0IGNvbmZpZyA9IENyYXNobHl0aWNzQ29uZmlnKCk7CiAgICAgICAgZmluYWwgdXBkYXRlZCA9IGNvbmZpZy5jb3B5V2l0aChlbmFibGVJbkRlYnVnTW9kZTogdHJ1ZSk7CgogICAgICAgIGV4cGVjdCh1cGRhdGVkLmVuYWJsZUluRGVidWdNb2RlLCB0cnVlKTsKICAgICAgICBleHBlY3QoCiAgICAgICAgICB1cGRhdGVkLmVuYWJsZUF1dG9tYXRpY0RhdGFDb2xsZWN0aW9uLAogICAgICAgICAgY29uZmlnLmVuYWJsZUF1dG9tYXRpY0RhdGFDb2xsZWN0aW9uLAogICAgICAgICk7CiAgICAgIH0pOwogICAgfSk7CgogICAgZ3JvdXAoJ1VzZXJNZXRhZGF0YScsICgpIHsKICAgICAgdGVzdCgnY3JlYXRlcyB1c2VyIG1ldGFkYXRhIGNvcnJlY3RseScsICgpIHsKICAgICAgICBjb25zdCBtZXRhZGF0YSA9IFVzZXJNZXRhZGF0YSgKICAgICAgICAgIHVzZXJJZDogJ3VzZXIxMjMnLAogICAgICAgICAgZW1haWw6ICd0ZXN0QGV4YW1wbGUuY29tJywKICAgICAgICAgIG5hbWU6ICdUZXN0IFVzZXInLAogICAgICAgICAgY3VzdG9tQXR0cmlidXRlczogeydyb2xlJzogJ2FkbWluJ30sCiAgICAgICAgKTsKCiAgICAgICAgZXhwZWN0KG1ldGFkYXRhLnVzZXJJZCwgJ3VzZXIxMjMnKTsKICAgICAgICBleHBlY3QobWV0YWRhdGEuZW1haWwsICd0ZXN0QGV4YW1wbGUuY29tJyk7CiAgICAgICAgZXhwZWN0KG1ldGFkYXRhLm5hbWUsICdUZXN0IFVzZXInKTsKICAgICAgICBleHBlY3QobWV0YWRhdGEuY3VzdG9tQXR0cmlidXRlcywgeydyb2xlJzogJ2FkbWluJ30pOwogICAgICB9KTsKCiAgICAgIHRlc3QoJ3RvTWFwIHdvcmtzIGNvcnJlY3RseScsICgpIHsKICAgICAgICBjb25zdCBtZXRhZGF0YSA9IFVzZXJNZXRhZGF0YSgKICAgICAgICAgIHVzZXJJZDogJ3VzZXIxMjMnLAogICAgICAgICAgZW1haWw6ICd0ZXN0QGV4YW1wbGUuY29tJywKICAgICAgICApOwoKICAgICAgICBmaW5hbCBtYXAgPSBtZXRhZGF0YS50b01hcCgpOwogICAgICAgIGV4cGVjdChtYXBbJ3VzZXJJZCddLCAndXNlcjEyMycpOwogICAgICAgIGV4cGVjdChtYXBbJ2VtYWlsJ10sICd0ZXN0QGV4YW1wbGUuY29tJyk7CiAgICAgICAgZXhwZWN0KG1hcFsnbmFtZSddLCBudWxsKTsKICAgICAgICBleHBlY3QobWFwWydjdXN0b21BdHRyaWJ1dGVzJ10sIGlzRW1wdHkpOwogICAgICB9KTsKCiAgICAgIHRlc3QoJ2NvcHlXaXRoIHdvcmtzIGNvcnJlY3RseScsICgpIHsKICAgICAgICBjb25zdCBtZXRhZGF0YSA9IFVzZXJNZXRhZGF0YSh1c2VySWQ6ICd1c2VyMTIzJyk7CiAgICAgICAgZmluYWwgdXBkYXRlZCA9IG1ldGFkYXRhLmNvcHlXaXRoKGVtYWlsOiAnbmV3QGV4YW1wbGUuY29tJyk7CgogICAgICAgIGV4cGVjdCh1cGRhdGVkLnVzZXJJZCwgJ3VzZXIxMjMnKTsKICAgICAgICBleHBlY3QodXBkYXRlZC5lbWFpbCwgJ25ld0BleGFtcGxlLmNvbScpOwogICAgICAgIGV4cGVjdCh1cGRhdGVkLm5hbWUsIG51bGwpOwogICAgICB9KTsKCiAgICAgIHRlc3QoJ2VxdWFsaXR5IHdvcmtzIGNvcnJlY3RseScsICgpIHsKICAgICAgICBjb25zdCBtZXRhZGF0YTEgPSBVc2VyTWV0YWRhdGEodXNlcklkOiAndXNlcjEyMycpOwogICAgICAgIGNvbnN0IG1ldGFkYXRhMiA9IFVzZXJNZXRhZGF0YSh1c2VySWQ6ICd1c2VyMTIzJyk7CiAgICAgICAgY29uc3QgbWV0YWRhdGEzID0gVXNlck1ldGFkYXRhKHVzZXJJZDogJ3VzZXI0NTYnKTsKCiAgICAgICAgZXhwZWN0KG1ldGFkYXRhMSwgZXF1YWxzKG1ldGFkYXRhMikpOwogICAgICAgIGV4cGVjdChtZXRhZGF0YTEsIGlzTm90KGVxdWFscyhtZXRhZGF0YTMpKSk7CiAgICAgIH0pOwogICAgfSk7CgogICAgZ3JvdXAoJ0NyYXNoUmVwb3J0JywgKCkgewogICAgICB0ZXN0KCdjcmVhdGVzIGNyYXNoIHJlcG9ydCBjb3JyZWN0bHknLCAoKSB7CiAgICAgICAgZmluYWwgdGltZXN0YW1wID0gRGF0ZVRpbWUubm93KCk7CiAgICAgICAgZmluYWwgcmVwb3J0ID0gQ3Jhc2hSZXBvcnQoCiAgICAgICAgICBleGNlcHRpb246IEV4Y2VwdGlvbignVGVzdCBlcnJvcicpLAogICAgICAgICAgc3RhY2tUcmFjZTogU3RhY2tUcmFjZS5jdXJyZW50LAogICAgICAgICAgZmF0YWw6IHRydWUsCiAgICAgICAgICB0aW1lc3RhbXA6IHRpbWVzdGFtcCwKICAgICAgICAgIGN1c3RvbUtleXM6IHsna2V5JzogJ3ZhbHVlJ30sCiAgICAgICAgKTsKCiAgICAgICAgZXhwZWN0KHJlcG9ydC5leGNlcHRpb24udG9TdHJpbmcoKSwgY29udGFpbnMoJ1Rlc3QgZXJyb3InKSk7CiAgICAgICAgZXhwZWN0KHJlcG9ydC5mYXRhbCwgdHJ1ZSk7CiAgICAgICAgZXhwZWN0KHJlcG9ydC50aW1lc3RhbXAsIHRpbWVzdGFtcCk7CiAgICAgICAgZXhwZWN0KHJlcG9ydC5jdXN0b21LZXlzLCB7J2tleSc6ICd2YWx1ZSd9KTsKICAgICAgfSk7CgogICAgICB0ZXN0KCd0b01hcCB3b3JrcyBjb3JyZWN0bHknLCAoKSB7CiAgICAgICAgZmluYWwgcmVwb3J0ID0gQ3Jhc2hSZXBvcnQoCiAgICAgICAgICBleGNlcHRpb246IEV4Y2VwdGlvbignVGVzdCBlcnJvcicpLAogICAgICAgICAgZmF0YWw6IGZhbHNlLAogICAgICAgICAgY3VzdG9tS2V5czogeyd0ZXN0JzogJ2RhdGEnfSwKICAgICAgICApOwoKICAgICAgICBmaW5hbCBtYXAgPSByZXBvcnQudG9NYXAoKTsKICAgICAgICBleHBlY3QobWFwWydmYXRhbCddLCBmYWxzZSk7CiAgICAgICAgZXhwZWN0KG1hcFsnY3VzdG9tS2V5cyddLCB7J3Rlc3QnOiAnZGF0YSd9KTsKICAgICAgICBleHBlY3QobWFwWydleGNlcHRpb24nXSwgY29udGFpbnMoJ1Rlc3QgZXJyb3InKSk7CiAgICAgIH0pOwoKICAgICAgdGVzdCgnY29weVdpdGggd29ya3MgY29ycmVjdGx5JywgKCkgewogICAgICAgIGZpbmFsIHJlcG9ydCA9IENyYXNoUmVwb3J0KAogICAgICAgICAgZXhjZXB0aW9uOiBFeGNlcHRpb24oJ1Rlc3QgZXJyb3InKSwKICAgICAgICAgIGZhdGFsOiBmYWxzZSwKICAgICAgICApOwoKICAgICAgICBmaW5hbCB1cGRhdGVkID0gcmVwb3J0LmNvcHlXaXRoKGZhdGFsOiB0cnVlKTsKICAgICAgICBleHBlY3QodXBkYXRlZC5mYXRhbCwgdHJ1ZSk7CiAgICAgICAgZXhwZWN0KHVwZGF0ZWQuZXhjZXB0aW9uLnRvU3RyaW5nKCksIHJlcG9ydC5leGNlcHRpb24udG9TdHJpbmcoKSk7CiAgICAgIH0pOwogICAgfSk7CiAgfSk7Cn0K", "type": "text" }, + { + "path": + "{{ name.snakeCase() }}/packages/{{crashlytics_dir}}/test/models_test.dart", + "data": + "aW1wb3J0ICdwYWNrYWdlOmNyYXNobHl0aWNzL2NyYXNobHl0aWNzLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlcl90ZXN0L2ZsdXR0ZXJfdGVzdC5kYXJ0JzsKCnZvaWQgbWFpbigpIHsKICB0ZXN0KAogICAgJ3VzZXIgbWV0YWRhdGEgdmFsdWUgZXF1YWxpdHkgaXMgb3JkZXItaW5kZXBlbmRlbnQgYW5kIGFncmVlcyB3aXRoIGhhc2hpbmcnLAogICAgKCkgewogICAgICBmaW5hbCB1c2VyID0gVXNlck1ldGFkYXRhKAogICAgICAgIHVzZXJJZDogJ3VzZXInLAogICAgICAgIGVtYWlsOiAnZXhhbXBsZUB0ZXN0JywKICAgICAgICBuYW1lOiAnVGVzdGVyJywKICAgICAgICBjdXN0b21BdHRyaWJ1dGVzOiB7J2EnOiAxLCAnYic6IDJ9LAogICAgICApOwogICAgICBmaW5hbCBlcXVhbCA9IHVzZXIuY29weVdpdGgoY3VzdG9tQXR0cmlidXRlczogeydiJzogMiwgJ2EnOiAxfSk7CiAgICAgIGV4cGVjdCh1c2VyLCB1c2VyKTsKICAgICAgZXhwZWN0KHVzZXIsIGVxdWFsKTsKICAgICAgZXhwZWN0KHVzZXIuaGFzaENvZGUsIGVxdWFsLmhhc2hDb2RlKTsKICAgICAgZXhwZWN0KHVzZXIuY29weVdpdGgoKSwgdXNlcik7CiAgICAgIGV4cGVjdCh1c2VyLnRvTWFwKClbJ3VzZXJJZCddLCAndXNlcicpOwogICAgICBleHBlY3QodXNlci50b1N0cmluZygpLCBjb250YWlucygnVGVzdGVyJykpOwogICAgICBleHBlY3QodXNlciwgaXNOb3QodXNlci5jb3B5V2l0aChjdXN0b21BdHRyaWJ1dGVzOiB7fSkpKTsKICAgICAgZXhwZWN0KHVzZXIsIGlzTm90KHVzZXIuY29weVdpdGgoY3VzdG9tQXR0cmlidXRlczogeydhJzogMSwgJ2InOiAzfSkpKTsKICAgICAgZXhwZWN0KHVzZXIsIGlzTm90KHVzZXIuY29weVdpdGgodXNlcklkOiAnYW5vdGhlcicpKSk7CiAgICB9LAogICk7CgogIHRlc3QoCiAgICAnY3Jhc2ggcmVwb3J0cyBwcmVzZXJ2ZSBmaWVsZHMsIHNlcmlhbGl6ZSBhbmQgaGFzaCBlcXVpdmFsZW50IGVycm9ycycsCiAgICAoKSB7CiAgICAgIGZpbmFsIHJlcG9ydCA9IENyYXNoUmVwb3J0KAogICAgICAgIGV4Y2VwdGlvbjogU3RhdGVFcnJvcignZmFpbHVyZScpLAogICAgICAgIHN0YWNrVHJhY2U6IFN0YWNrVHJhY2UuZnJvbVN0cmluZygndHJhY2UnKSwKICAgICAgICBmYXRhbDogdHJ1ZSwKICAgICAgICB0aW1lc3RhbXA6IERhdGVUaW1lKDIwMjYpLAogICAgICAgIGN1c3RvbUtleXM6IHsnYnVpbGQnOiAndGVzdCd9LAogICAgICAgIGxvZ3M6IFsnZmlyc3QnXSwKICAgICAgICB1c2VyTWV0YWRhdGE6IHsndXNlcklkJzogJ3VzZXInfSwKICAgICAgKTsKICAgICAgZmluYWwgZXF1YWwgPSByZXBvcnQuY29weVdpdGgoCiAgICAgICAgZXhjZXB0aW9uOiBTdGF0ZUVycm9yKCdmYWlsdXJlJyksCiAgICAgICAgc3RhY2tUcmFjZTogU3RhY2tUcmFjZS5mcm9tU3RyaW5nKCd0cmFjZScpLAogICAgICApOwogICAgICBleHBlY3QocmVwb3J0LCByZXBvcnQpOwogICAgICBleHBlY3QocmVwb3J0LCBlcXVhbCk7CiAgICAgIGV4cGVjdChyZXBvcnQuaGFzaENvZGUsIGVxdWFsLmhhc2hDb2RlKTsKICAgICAgZXhwZWN0KHJlcG9ydC5jb3B5V2l0aCgpLCByZXBvcnQpOwogICAgICBleHBlY3QocmVwb3J0LCBpc05vdChyZXBvcnQuY29weVdpdGgoZmF0YWw6IGZhbHNlKSkpOwogICAgICBleHBlY3QocmVwb3J0LnRvTWFwKClbJ2xvZ3MnXSwgWydmaXJzdCddKTsKICAgICAgZXhwZWN0KHJlcG9ydC50b01hcCgpWyd0aW1lc3RhbXAnXSwgRGF0ZVRpbWUoMjAyNikudG9Jc284NjAxU3RyaW5nKCkpOwogICAgICBleHBlY3QocmVwb3J0LnRvU3RyaW5nKCksIGNvbnRhaW5zKCdmYWlsdXJlJykpOwogICAgICBleHBlY3QoCiAgICAgICAgcmVwb3J0CiAgICAgICAgICAgIC5jb3B5V2l0aChjdXN0b21LZXlzOiB7J25ldyc6IHRydWV9LCBsb2dzOiBbXSwgdXNlck1ldGFkYXRhOiB7fSkKICAgICAgICAgICAgLmN1c3RvbUtleXMsCiAgICAgICAgeyduZXcnOiB0cnVlfSwKICAgICAgKTsKICAgIH0sCiAgKTsKCiAgdGVzdCgnY3Jhc2ggY29uZmlndXJhdGlvbiBjb3B5aW5nIHJldGFpbnMgYW5kIG92ZXJyaWRlcyBlYWNoIG9wdGlvbicsICgpIHsKICAgIGNvbnN0IGNvbmZpZyA9IENyYXNobHl0aWNzQ29uZmlnKCk7CiAgICBmaW5hbCBjaGFuZ2VkID0gY29uZmlnLmNvcHlXaXRoKAogICAgICBlbmFibGVJbkRlYnVnTW9kZTogdHJ1ZSwKICAgICAgZW5hYmxlQXV0b21hdGljRGF0YUNvbGxlY3Rpb246IGZhbHNlLAogICAgICBlbmFibGVDdXN0b21Mb2dzOiBmYWxzZSwKICAgICAgZW5hYmxlVXNlck1ldGFkYXRhOiBmYWxzZSwKICAgICAgbG9nQnVmZmVyU2l6ZTogMTAsCiAgICAgIGN1c3RvbUtleXM6IHsnYnVpbGQnOiAndGVzdCd9LAogICAgKTsKICAgIGV4cGVjdChjaGFuZ2VkLmNvcHlXaXRoKCksIGNoYW5nZWQpOwogICAgZXhwZWN0KGNoYW5nZWQuaGFzaENvZGUsIGNoYW5nZWQuY29weVdpdGgoKS5oYXNoQ29kZSk7CiAgICBleHBlY3QoY2hhbmdlZC50b1N0cmluZygpLCBjb250YWlucygnMTAnKSk7CiAgICBleHBlY3QoY2hhbmdlZC5lbmFibGVDdXN0b21Mb2dzLCBpc0ZhbHNlKTsKICAgIGV4cGVjdChjaGFuZ2VkLmVuYWJsZUluRGVidWdNb2RlLCBpc1RydWUpOwogICAgZXhwZWN0KGNoYW5nZWQudG9NYXAoKVsnbG9nQnVmZmVyU2l6ZSddLCAxMCk7CiAgICBleHBlY3QoY2hhbmdlZCwgaXNOb3QoY29uZmlnKSk7CiAgfSk7Cn0K", + "type": "text" + }, { "path": "{{ name.snakeCase() }}/packages/{{developer_dir}}/lib/developer.dart", @@ -979,7 +1122,7 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "path": "{{ name.snakeCase() }}/packages/{{developer_dir}}/lib/src/routes/developer_routes.dart", "data": - "aW1wb3J0ICdwYWNrYWdlOmNvcmUvY29yZS5kYXJ0JyBhcyBjb3JlOwppbXBvcnQgJ3BhY2thZ2U6ZGV2ZWxvcGVyL3NyYy9zY3JlZW5zL2luZGV4LmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlci9tYXRlcmlhbC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmdvX3JvdXRlci9nb19yb3V0ZXIuZGFydCc7CgpjbGFzcyBEZXZlbG9wZXJSb3V0ZXMgewogIHN0YXRpYyBjb25zdCBTdHJpbmcgZGV2ZWxvcGVyID0gJy9kZXZlbG9wZXInOwp9CgpjbGFzcyBEZXZlbG9wZXJSb3V0ZXIgZXh0ZW5kcyBjb3JlLkNvcmVSb3V0ZXIgewogIEBvdmVycmlkZQogIExpc3Q8Um91dGVCYXNlPiBnZXQgcm91dGVzID0+IFsKICAgIEdvUm91dGUoCiAgICAgIHBhdGg6IERldmVsb3BlclJvdXRlcy5kZXZlbG9wZXIsCiAgICAgIG5hbWU6ICdkZXZlbG9wZXItc2NyZWVuJywKICAgICAgYnVpbGRlcjogKEJ1aWxkQ29udGV4dCBjb250ZXh0LCBHb1JvdXRlclN0YXRlIHN0YXRlKSB7CiAgICAgICAgcmV0dXJuIGNvbnN0IERldmVsb3BlclNjcmVlbigpOwogICAgICB9LAogICAgKSwKICBdOwp9Cg==", + "aW1wb3J0ICdwYWNrYWdlOmNvcmUvY29yZS5kYXJ0JyBhcyBjb3JlOwppbXBvcnQgJ3BhY2thZ2U6ZGV2ZWxvcGVyL3NyYy9zY3JlZW5zL2luZGV4LmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZGkvZGkuZGFydCc7CmltcG9ydCAncGFja2FnZTpmZWF0dXJlX2ZsYWdzL2ZlYXR1cmVfZmxhZ3MuZGFydCc7CmltcG9ydCAncGFja2FnZTpmbHV0dGVyL21hdGVyaWFsLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Z29fcm91dGVyL2dvX3JvdXRlci5kYXJ0JzsKCmNsYXNzIERldmVsb3BlclJvdXRlcyB7CiAgc3RhdGljIGNvbnN0IFN0cmluZyBkZXZlbG9wZXIgPSAnL2RldmVsb3Blcic7Cn0KCmNsYXNzIERldmVsb3BlclJvdXRlciBleHRlbmRzIGNvcmUuQ29yZVJvdXRlciB7CiAgQG92ZXJyaWRlCiAgTGlzdDxSb3V0ZUJhc2U+IGdldCByb3V0ZXMgPT4gWwogICAgR29Sb3V0ZSgKICAgICAgcGF0aDogRGV2ZWxvcGVyUm91dGVzLmRldmVsb3BlciwKICAgICAgbmFtZTogJ2RldmVsb3Blci1zY3JlZW4nLAogICAgICByZWRpcmVjdDogKGNvbnRleHQsIHN0YXRlKSBhc3luYyB7CiAgICAgICAgLy8gSGlkaW5nIHRoZSBlbnRyeSBnZXN0dXJlIGRvZXMgbm90IHByb3RlY3QgYSBkaXJlY3RseSBlbnRlcmVkIHJvdXRlLgogICAgICAgIGlmICghZGkuaGFzPEZlYXR1cmVGbGFnPigpKSByZXR1cm4gY29yZS5Db3JlUm91dGVzLnJvb3Q7CiAgICAgICAgdHJ5IHsKICAgICAgICAgIHJldHVybiBhd2FpdCBkaS5nZXQ8RmVhdHVyZUZsYWc+KCkuaXNFbmFibGVkKAogICAgICAgICAgICAgICAgJ2RldmVsb3Blcl9zY3JlZW5fZW5hYmxlZCcsCiAgICAgICAgICAgICAgKQogICAgICAgICAgICAgID8gbnVsbAogICAgICAgICAgICAgIDogY29yZS5Db3JlUm91dGVzLnJvb3Q7CiAgICAgICAgfSBjYXRjaCAoXykgewogICAgICAgICAgcmV0dXJuIGNvcmUuQ29yZVJvdXRlcy5yb290OwogICAgICAgIH0KICAgICAgfSwKICAgICAgYnVpbGRlcjogKEJ1aWxkQ29udGV4dCBjb250ZXh0LCBHb1JvdXRlclN0YXRlIHN0YXRlKSB7CiAgICAgICAgcmV0dXJuIGNvbnN0IERldmVsb3BlclNjcmVlbigpOwogICAgICB9LAogICAgKSwKICBdOwp9Cg==", "type": "text" }, { @@ -992,7 +1135,7 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "path": "{{ name.snakeCase() }}/packages/{{developer_dir}}/lib/src/screens/developer_screen.dart", "data": - "aW1wb3J0ICdwYWNrYWdlOmNvcmUvY29yZS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlci9tYXRlcmlhbC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOnRhbGtlcl9mbHV0dGVyL3RhbGtlcl9mbHV0dGVyLmRhcnQnOwoKY2xhc3MgRGV2ZWxvcGVyU2NyZWVuIGV4dGVuZHMgU3RhdGVsZXNzV2lkZ2V0IHsKICBjb25zdCBEZXZlbG9wZXJTY3JlZW4oe3N1cGVyLmtleX0pOwoKICBAb3ZlcnJpZGUKICBXaWRnZXQgYnVpbGQoQnVpbGRDb250ZXh0IGNvbnRleHQpIHsKICAgIHJldHVybiBUYWxrZXJTY3JlZW4odGFsa2VyOiBkaS5nZXQ8TG9nZ2VyPigpLmxvZ2dlciBhcyBUYWxrZXIpOwogIH0KfQo=", + "aW1wb3J0ICdwYWNrYWdlOmNvcmUvY29yZS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlci9tYXRlcmlhbC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOnRhbGtlcl9mbHV0dGVyL3RhbGtlcl9mbHV0dGVyLmRhcnQnOwoKY2xhc3MgRGV2ZWxvcGVyU2NyZWVuIGV4dGVuZHMgU3RhdGVsZXNzV2lkZ2V0IHsKICBjb25zdCBEZXZlbG9wZXJTY3JlZW4oe3N1cGVyLmtleX0pOwoKICBAb3ZlcnJpZGUKICBXaWRnZXQgYnVpbGQoQnVpbGRDb250ZXh0IGNvbnRleHQpIHsKICAgIGZpbmFsIGxvZ2dlciA9IGRpLmdldDxMb2dnZXI+KCkubG9nZ2VyOwogICAgaWYgKGxvZ2dlciBpcyBUYWxrZXIpIHJldHVybiBUYWxrZXJTY3JlZW4odGFsa2VyOiBsb2dnZXIpOwogICAgcmV0dXJuIGNvbnN0IFNjYWZmb2xkKAogICAgICBib2R5OiBDZW50ZXIoY2hpbGQ6IFRleHQoJ1RoaXMgbG9nZ2VyIGhhcyBubyBpbnRlcmFjdGl2ZSB2aWV3ZXIuJykpLAogICAgKTsKICB9Cn0K", "type": "text" }, { @@ -1027,11 +1170,18 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "aW1wb3J0ICdwYWNrYWdlOmRldmVsb3Blci9kZXZlbG9wZXIuZGFydCc7CmltcG9ydCAncGFja2FnZTpmbHV0dGVyL21hdGVyaWFsLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlcl90ZXN0L2ZsdXR0ZXJfdGVzdC5kYXJ0JzsKCnZvaWQgbWFpbigpIHsKICBncm91cCgnRGV2ZWxvcGVyIFBhY2thZ2UnLCAoKSB7CiAgICB0ZXN0KCdwYWNrYWdlIGV4cG9ydHMgYXJlIGF2YWlsYWJsZScsICgpIHsKICAgICAgZXhwZWN0KERldmVsb3BlclJvdXRlcy5kZXZlbG9wZXIsICcvZGV2ZWxvcGVyJyk7CiAgICB9KTsKCiAgICB0ZXN0V2lkZ2V0cygnRGVidWdHZXN0dXJlRGV0ZWN0b3IgZXhwb3J0cyBhcmUgYXZhaWxhYmxlJywgKHRlc3RlcikgYXN5bmMgewogICAgICAvLyBUZXN0IHRoYXQgdGhlIHdpZGdldCBjYW4gYmUgaW5zdGFudGlhdGVkCiAgICAgIGNvbnN0IHdpZGdldCA9IE9wZW5EZXZUb29sc1dyYXBwZXIoY2hpbGQ6IFRleHQoJ1Rlc3QnKSk7CgogICAgICBleHBlY3Qod2lkZ2V0LCBpc05vdE51bGwpOwogICAgICBleHBlY3Qod2lkZ2V0LnRhcENvdW50LCA1KTsgLy8gRGVmYXVsdCB2YWx1ZQogICAgICBleHBlY3Qod2lkZ2V0LnRhcFdpbmRvdywgY29uc3QgRHVyYXRpb24oc2Vjb25kczogMikpOyAvLyBEZWZhdWx0IHZhbHVlCiAgICAgIGV4cGVjdCh3aWRnZXQuZW5hYmxlSGFwdGljcywgdHJ1ZSk7IC8vIERlZmF1bHQgdmFsdWUKICAgICAgZXhwZWN0KHdpZGdldC5lbmFibGVWaXN1YWxGZWVkYmFjaywgZmFsc2UpOyAvLyBEZWZhdWx0IHZhbHVlCiAgICB9KTsKCiAgICB0ZXN0V2lkZ2V0cygnRGVidWdHZXN0dXJlRGV0ZWN0b3IgY3VzdG9tIHZhbHVlcyB3b3JrJywgKHRlc3RlcikgYXN5bmMgewogICAgICAvLyBUZXN0IGN1c3RvbSBjb25maWd1cmF0aW9uCiAgICAgIGNvbnN0IHdpZGdldCA9IE9wZW5EZXZUb29sc1dyYXBwZXIoCiAgICAgICAgdGFwQ291bnQ6IDcsCiAgICAgICAgdGFwV2luZG93OiBEdXJhdGlvbihzZWNvbmRzOiAyKSwKICAgICAgICBlbmFibGVIYXB0aWNzOiBmYWxzZSwKICAgICAgICBlbmFibGVWaXN1YWxGZWVkYmFjazogdHJ1ZSwKICAgICAgICBjaGlsZDogVGV4dCgnVGVzdCcpLAogICAgICApOwoKICAgICAgZXhwZWN0KHdpZGdldC50YXBDb3VudCwgNyk7CiAgICAgIGV4cGVjdCh3aWRnZXQudGFwV2luZG93LCBjb25zdCBEdXJhdGlvbihzZWNvbmRzOiAyKSk7CiAgICAgIGV4cGVjdCh3aWRnZXQuZW5hYmxlSGFwdGljcywgZmFsc2UpOwogICAgICBleHBlY3Qod2lkZ2V0LmVuYWJsZVZpc3VhbEZlZWRiYWNrLCB0cnVlKTsKICAgIH0pOwogIH0pOwp9Cg==", "type": "text" }, + { + "path": + "{{ name.snakeCase() }}/packages/{{developer_dir}}/test/navigation_test.dart", + "data": + "aW1wb3J0ICdwYWNrYWdlOmNvcmUvY29yZS5kYXJ0JyBhcyBjb3JlOwppbXBvcnQgJ3BhY2thZ2U6ZGV2ZWxvcGVyL2RldmVsb3Blci5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZmVhdHVyZV9mbGFncy9mZWF0dXJlX2ZsYWdzLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlci9tYXRlcmlhbC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZsdXR0ZXJfdGVzdC9mbHV0dGVyX3Rlc3QuZGFydCc7CmltcG9ydCAncGFja2FnZTpnb19yb3V0ZXIvZ29fcm91dGVyLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6dGFsa2VyX2ZsdXR0ZXIvdGFsa2VyX2ZsdXR0ZXIuZGFydCc7CgpjbGFzcyBfUGxhaW5Mb2dnZXIgaW1wbGVtZW50cyBjb3JlLkxvZ2dlciB7CiAgQG92ZXJyaWRlCiAgT2JqZWN0IGdldCBsb2dnZXIgPT4gdGhpczsKICBAb3ZlcnJpZGUKICB2b2lkIGQoU3RyaW5nIG1lc3NhZ2UpIHt9CiAgQG92ZXJyaWRlCiAgdm9pZCBpKFN0cmluZyBtZXNzYWdlKSB7fQogIEBvdmVycmlkZQogIHZvaWQgdyhTdHJpbmcgbWVzc2FnZSkge30KICBAb3ZlcnJpZGUKICB2b2lkIGUoU3RyaW5nIG1lc3NhZ2UsIFtPYmplY3Q/IGVycm9yLCBTdGFja1RyYWNlPyBzdGFja1RyYWNlXSkge30KfQoKY2xhc3MgX0ZsYWdzIGltcGxlbWVudHMgRmVhdHVyZUZsYWdQcm92aWRlciB7CiAgYm9vbCBlbmFibGVkID0gdHJ1ZTsKICBAb3ZlcnJpZGUKICBGdXR1cmU8dm9pZD4gaW5pdCgpIGFzeW5jIHt9CiAgQG92ZXJyaWRlCiAgRnV0dXJlPGJvb2w+IGdldEJvb2woU3RyaW5nIGtleSwge2Jvb2wgZGVmYXVsdFZhbHVlID0gZmFsc2V9KSBhc3luYyA9PgogICAgICBlbmFibGVkOwogIEBvdmVycmlkZQogIHZvaWQgZGlzcG9zZSgpIHt9CiAgQG92ZXJyaWRlCiAgZHluYW1pYyBub1N1Y2hNZXRob2QoSW52b2NhdGlvbiBpbnZvY2F0aW9uKSA9PiBzdXBlci5ub1N1Y2hNZXRob2QoaW52b2NhdGlvbik7Cn0KCnZvaWQgbWFpbigpIHsKICBzZXRVcChjb3JlLmluaXQpOwogIHRlYXJEb3duKGRpLnJlc2V0KTsKCiAgdGVzdFdpZGdldHMoJ2EgY3VzdG9tIGxvZ2dlciBkb2VzIG5vdCBuZWVkIHRvIGV4cG9zZSBUYWxrZXInLCAodGVzdGVyKSBhc3luYyB7CiAgICBhd2FpdCBkaS5yZXNldCgpOwogICAgZGkucmVnaXN0ZXI8Y29yZS5Mb2dnZXI+KF9QbGFpbkxvZ2dlcigpKTsKICAgIGF3YWl0IHRlc3Rlci5wdW1wV2lkZ2V0KGNvbnN0IE1hdGVyaWFsQXBwKGhvbWU6IERldmVsb3BlclNjcmVlbigpKSk7CiAgICBleHBlY3QoZmluZC50ZXh0KCdUaGlzIGxvZ2dlciBoYXMgbm8gaW50ZXJhY3RpdmUgdmlld2VyLicpLCBmaW5kc09uZVdpZGdldCk7CiAgfSk7CgogIHRlc3RXaWRnZXRzKCdkaXNhYmxlZCBkZXZlbG9wZXIgZ2VzdHVyZSByZW1haW5zIGluZXJ0JywgKHRlc3RlcikgYXN5bmMgewogICAgZmluYWwgcHJvdmlkZXIgPSBfRmxhZ3MoKS4uZW5hYmxlZCA9IGZhbHNlOwogICAgZmluYWwgc2VydmljZSA9IEZlYXR1cmVGbGFnKAogICAgICBwcm92aWRlcjogcHJvdmlkZXIsCiAgICAgIGxvZ2dlcjogZGkuZ2V0PGNvcmUuTG9nZ2VyPigpLAogICAgKTsKICAgIGF3YWl0IHNlcnZpY2UuaW5pdCgpOwogICAgZGkucmVnaXN0ZXI8RmVhdHVyZUZsYWc+KHNlcnZpY2UsIGRpc3Bvc2U6IChzZXJ2aWNlKSA9PiBzZXJ2aWNlLmRpc3Bvc2UoKSk7CiAgICBhd2FpdCB0ZXN0ZXIucHVtcFdpZGdldCgKICAgICAgY29uc3QgTWF0ZXJpYWxBcHAoaG9tZTogT3BlbkRldlRvb2xzV3JhcHBlcihjaGlsZDogVGV4dCgnRGVtbycpKSksCiAgICApOwogICAgYXdhaXQgdGVzdGVyLnB1bXBBbmRTZXR0bGUoKTsKICAgIGF3YWl0IHRlc3Rlci50YXAoZmluZC50ZXh0KCdEZW1vJykpOwogICAgYXdhaXQgdGVzdGVyLnB1bXBBbmRTZXR0bGUoKTsKICAgIGV4cGVjdChmaW5kLnRleHQoJ0RlbW8nKSwgZmluZHNPbmVXaWRnZXQpOwogICAgZXhwZWN0KGZpbmQuYnlUeXBlKFRhbGtlclNjcmVlbiksIGZpbmRzTm90aGluZyk7CiAgfSk7CgogIHRlc3RXaWRnZXRzKAogICAgJ2RpcmVjdCBuYXZpZ2F0aW9uIGlzIGRlbmllZCBiZWZvcmUgZmVhdHVyZSBmbGFncyBhcmUgY29uZmlndXJlZCcsCiAgICAodGVzdGVyKSBhc3luYyB7CiAgICAgIGZpbmFsIHJvdXRlciA9IEdvUm91dGVyKAogICAgICAgIGluaXRpYWxMb2NhdGlvbjogRGV2ZWxvcGVyUm91dGVzLmRldmVsb3BlciwKICAgICAgICByb3V0ZXM6IFsKICAgICAgICAgIEdvUm91dGUocGF0aDogJy8nLCBidWlsZGVyOiAoXywgXykgPT4gY29uc3QgVGV4dCgnSG9tZScpKSwKICAgICAgICAgIC4uLkRldmVsb3BlclJvdXRlcigpLnJvdXRlcywKICAgICAgICBdLAogICAgICApOwogICAgICBhZGRUZWFyRG93bihyb3V0ZXIuZGlzcG9zZSk7CiAgICAgIGF3YWl0IHRlc3Rlci5wdW1wV2lkZ2V0KE1hdGVyaWFsQXBwLnJvdXRlcihyb3V0ZXJDb25maWc6IHJvdXRlcikpOwogICAgICBhd2FpdCB0ZXN0ZXIucHVtcEFuZFNldHRsZSgpOwogICAgICBleHBlY3QoZmluZC50ZXh0KCdIb21lJyksIGZpbmRzT25lV2lkZ2V0KTsKICAgICAgZXhwZWN0KGZpbmQuYnlUeXBlKFRhbGtlclNjcmVlbiksIGZpbmRzTm90aGluZyk7CiAgICB9LAogICk7CgogIGZvciAoZmluYWwgdmlzdWFsIGluIFtmYWxzZSwgdHJ1ZV0pIHsKICAgIHRlc3RXaWRnZXRzKCdlbmFibGVkIGdlc3R1cmUgcmVzcGVjdHMgaXRzIHRhcCB3aW5kb3cgKHZpc3VhbD0kdmlzdWFsKScsICgKICAgICAgdGVzdGVyLAogICAgKSBhc3luYyB7CiAgICAgIGZpbmFsIHByb3ZpZGVyID0gX0ZsYWdzKCk7CiAgICAgIGZpbmFsIGZsYWdzID0gRmVhdHVyZUZsYWcoCiAgICAgICAgcHJvdmlkZXI6IHByb3ZpZGVyLAogICAgICAgIGxvZ2dlcjogZGkuZ2V0PGNvcmUuTG9nZ2VyPigpLAogICAgICApOwogICAgICBhd2FpdCBmbGFncy5pbml0KCk7CiAgICAgIGRpLnJlZ2lzdGVyPEZlYXR1cmVGbGFnPihmbGFncyk7CiAgICAgIGZpbmFsIHJvdXRlciA9IEdvUm91dGVyKAogICAgICAgIHJvdXRlczogWwogICAgICAgICAgR29Sb3V0ZSgKICAgICAgICAgICAgcGF0aDogJy8nLAogICAgICAgICAgICBidWlsZGVyOiAoXywgXykgPT4gU2NhZmZvbGQoCiAgICAgICAgICAgICAgYm9keTogQ2VudGVyKAogICAgICAgICAgICAgICAgY2hpbGQ6IE9wZW5EZXZUb29sc1dyYXBwZXIoCiAgICAgICAgICAgICAgICAgIHRhcENvdW50OiAzLAogICAgICAgICAgICAgICAgICBlbmFibGVWaXN1YWxGZWVkYmFjazogdmlzdWFsLAogICAgICAgICAgICAgICAgICBjaGlsZDogY29uc3QgVGV4dCgnT3BlbiB0b29scycpLAogICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICApLAogICAgICAgICAgICApLAogICAgICAgICAgKSwKICAgICAgICAgIC4uLkRldmVsb3BlclJvdXRlcigpLnJvdXRlcywKICAgICAgICBdLAogICAgICApOwogICAgICBhZGRUZWFyRG93bihyb3V0ZXIuZGlzcG9zZSk7CiAgICAgIGF3YWl0IHRlc3Rlci5wdW1wV2lkZ2V0KE1hdGVyaWFsQXBwLnJvdXRlcihyb3V0ZXJDb25maWc6IHJvdXRlcikpOwogICAgICBhd2FpdCB0ZXN0ZXIucHVtcEFuZFNldHRsZSgpOwogICAgICBhd2FpdCB0ZXN0ZXIudGFwKGZpbmQudGV4dCgnT3BlbiB0b29scycpKTsKICAgICAgYXdhaXQgdGVzdGVyLnB1bXAoY29uc3QgRHVyYXRpb24oc2Vjb25kczogMykpOwogICAgICBhd2FpdCB0ZXN0ZXIudGFwKGZpbmQudGV4dCgnT3BlbiB0b29scycpKTsKICAgICAgYXdhaXQgdGVzdGVyLnB1bXAoY29uc3QgRHVyYXRpb24obWlsbGlzZWNvbmRzOiA1MDApKTsKICAgICAgZXhwZWN0KGZpbmQuYnlUeXBlKFRhbGtlclNjcmVlbiksIGZpbmRzTm90aGluZyk7CiAgICAgIGF3YWl0IHRlc3Rlci50YXAoZmluZC50ZXh0KCdPcGVuIHRvb2xzJykpOwogICAgICBhd2FpdCB0ZXN0ZXIucHVtcChjb25zdCBEdXJhdGlvbihtaWxsaXNlY29uZHM6IDUwMCkpOwogICAgICBhd2FpdCB0ZXN0ZXIudGFwKGZpbmQudGV4dCgnT3BlbiB0b29scycpKTsKICAgICAgYXdhaXQgdGVzdGVyLnB1bXBBbmRTZXR0bGUoKTsKICAgICAgZXhwZWN0KGZpbmQuYnlUeXBlKFRhbGtlclNjcmVlbiksIGZpbmRzT25lV2lkZ2V0KTsKICAgICAgZXhwZWN0KHRlc3Rlci50YWtlRXhjZXB0aW9uKCksIGlzTnVsbCk7CiAgICB9KTsKICB9Cn0K", + "type": "text" + }, { "path": "{{ name.snakeCase() }}/packages/{{feature_flags_dir}}/lib/feature_flags.dart", "data": - "bGlicmFyeTsKCmltcG9ydCAncGFja2FnZTpjb3JlL2xvZ2dlci9sb2dnZXIuZGFydCc7CmltcG9ydCAncGFja2FnZTpkaS9kaS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZlYXR1cmVfZmxhZ3Mvc3JjL2ZlYXR1cmVfZmxhZ19zZXJ2aWNlLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZmVhdHVyZV9mbGFncy9zcmMvcmVnaXN0ZXIuZGFydCc7CgpleHBvcnQgJ3NyYy9pbmRleC5kYXJ0JzsKCi8vLyBJbml0aWFsaXplIHRoZSBmZWF0dXJlIGZsYWdzIG1vZHVsZSBhbmQgcmVnaXN0ZXIgd2l0aCBESQpGdXR1cmU8dm9pZD4gaW5pdCh7CiAgRmVhdHVyZUZsYWdzQ29uZmlnIGNvbmZpZyA9IGNvbnN0IEZlYXR1cmVGbGFnc0NvbmZpZygKICAgIGZldGNoVGltZW91dDogRHVyYXRpb24oc2Vjb25kczogMTApLAogICAgbWluaW11bUZldGNoSW50ZXJ2YWw6IER1cmF0aW9uKG1pbnV0ZXM6IDMwKSwKICAgIGRlZmF1bHRQYXJhbWV0ZXJzOiB7fSwKICApLAp9KSBhc3luYyB7CiAgZmluYWwgbG9nZ2VyID0gZGkuZ2V0PExvZ2dlcj4oKTsKICB0cnkgewogICAgbG9nZ2VyLmkoJ2luaXQgZmVhdHVyZSBmbGFncyBtb2R1bGUgd2l0aCBGaXJlYmFzZSBSZW1vdGUgQ29uZmlnJyk7CiAgICBhd2FpdCByZWdpc3RlckZlYXR1cmVGbGFnc1dpdGhESShjb25maWc6IGNvbmZpZyk7CiAgICBmaW5hbCBzZXJ2aWNlID0gZGkuZ2V0PEZlYXR1cmVGbGFnPigpOwogICAgYXdhaXQgc2VydmljZS5pbml0KCk7CiAgICBsb2dnZXIuaSgnRmVhdHVyZSBmbGFncyBtb2R1bGUgaW5pdGlhbGl6ZWQgd2l0aCBGaXJlYmFzZSBSZW1vdGUgQ29uZmlnJyk7CiAgfSBjYXRjaCAoZSwgc3RhY2tUcmFjZSkgewogICAgbG9nZ2VyLmUoJ0ZhaWxlZCB0byBpbml0aWFsaXplIGZlYXR1cmUgZmxhZ3MgbW9kdWxlJywgZSwgc3RhY2tUcmFjZSk7CiAgICByZXRocm93OwogIH0KfQo=", + "bGlicmFyeTsKCmltcG9ydCAncGFja2FnZTpjb3JlL2xvZ2dlci9sb2dnZXIuZGFydCc7CmltcG9ydCAncGFja2FnZTpkaS9kaS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZlYXR1cmVfZmxhZ3Mvc3JjL2ZlYXR1cmVfZmxhZ19zZXJ2aWNlLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZmVhdHVyZV9mbGFncy9zcmMvcmVnaXN0ZXIuZGFydCc7CmltcG9ydCAncGFja2FnZTpmZWF0dXJlX2ZsYWdzL3NyYy9mZWF0dXJlX2ZsYWdfcHJvdmlkZXIuZGFydCc7CgpleHBvcnQgJ3NyYy9pbmRleC5kYXJ0JzsKCi8vLyBJbml0aWFsaXplIHRoZSBmZWF0dXJlIGZsYWdzIG1vZHVsZSBhbmQgcmVnaXN0ZXIgd2l0aCBESQpGdXR1cmU8dm9pZD4gaW5pdCh7CiAgRmVhdHVyZUZsYWdQcm92aWRlcj8gcHJvdmlkZXIsCiAgRmVhdHVyZUZsYWdzQ29uZmlnIGNvbmZpZyA9IGNvbnN0IEZlYXR1cmVGbGFnc0NvbmZpZygKICAgIGZldGNoVGltZW91dDogRHVyYXRpb24oc2Vjb25kczogMTApLAogICAgbWluaW11bUZldGNoSW50ZXJ2YWw6IER1cmF0aW9uKG1pbnV0ZXM6IDMwKSwKICAgIGRlZmF1bHRQYXJhbWV0ZXJzOiB7fSwKICApLAp9KSBhc3luYyB7CiAgZmluYWwgbG9nZ2VyID0gZGkuZ2V0PExvZ2dlcj4oKTsKICB0cnkgewogICAgbG9nZ2VyLmkoJ2luaXQgZmVhdHVyZSBmbGFncyBtb2R1bGUgd2l0aCBGaXJlYmFzZSBSZW1vdGUgQ29uZmlnJyk7CiAgICBhd2FpdCByZWdpc3RlckZlYXR1cmVGbGFnc1dpdGhESShjb25maWc6IGNvbmZpZywgcHJvdmlkZXI6IHByb3ZpZGVyKTsKICAgIGZpbmFsIHNlcnZpY2UgPSBkaS5nZXQ8RmVhdHVyZUZsYWc+KCk7CiAgICBhd2FpdCBzZXJ2aWNlLmluaXQoKTsKICAgIGxvZ2dlci5pKCdGZWF0dXJlIGZsYWdzIG1vZHVsZSBpbml0aWFsaXplZCB3aXRoIEZpcmViYXNlIFJlbW90ZSBDb25maWcnKTsKICB9IGNhdGNoIChlLCBzdGFja1RyYWNlKSB7CiAgICBsb2dnZXIuZSgnRmFpbGVkIHRvIGluaXRpYWxpemUgZmVhdHVyZSBmbGFncyBtb2R1bGUnLCBlLCBzdGFja1RyYWNlKTsKICAgIHJldGhyb3c7CiAgfQp9Cg==", "type": "text" }, { @@ -1052,14 +1202,14 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "path": "{{ name.snakeCase() }}/packages/{{feature_flags_dir}}/lib/src/feature_flag_wrapper.dart", "data": - "aW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZmVhdHVyZV9mbGFncy9zcmMvZmVhdHVyZV9mbGFnX3NlcnZpY2UuZGFydCc7CmltcG9ydCAncGFja2FnZTpmbHV0dGVyL21hdGVyaWFsLmRhcnQnOwoKLy8vIEEgd3JhcHBlciB3aWRnZXQgdGhhdCBjb25kaXRpb25hbGx5IHJlbmRlcnMgY29udGVudCBiYXNlZCBvbiBmZWF0dXJlIGZsYWdzCmNsYXNzIEZlYXR1cmVGbGFnV3JhcHBlciBleHRlbmRzIFN0YXRlbGVzc1dpZGdldCB7CiAgY29uc3QgRmVhdHVyZUZsYWdXcmFwcGVyKHsKICAgIHN1cGVyLmtleSwKICAgIHJlcXVpcmVkIHRoaXMuZmxhZ0tleSwKICAgIHJlcXVpcmVkIHRoaXMuYnVpbGRlciwKICAgIHRoaXMuZGVmYXVsdFZhbHVlID0gZmFsc2UsCiAgICB0aGlzLmxvYWRpbmcsCiAgfSk7CgogIC8vLyBUaGUgZmVhdHVyZSBmbGFnIGtleSB0byBjaGVjawogIGZpbmFsIFN0cmluZyBmbGFnS2V5OwoKICAvLy8gQnVpbGRlciBmdW5jdGlvbiB0aGF0IHJlY2VpdmVzIHRoZSBjb250ZXh0IGFuZCBmZWF0dXJlIGZsYWcgdmFsdWUKICBmaW5hbCBXaWRnZXQgRnVuY3Rpb24oQnVpbGRDb250ZXh0IGNvbnRleHQsIGJvb2wgdmFsdWUpIGJ1aWxkZXI7CgogIC8vLyBUaGUgZGVmYXVsdCB2YWx1ZSB0byB1c2UgaWYgdGhlIGZlYXR1cmUgZmxhZyBzZXJ2aWNlIGlzIHVuYXZhaWxhYmxlCiAgZmluYWwgYm9vbCBkZWZhdWx0VmFsdWU7CgogIC8vLyBXaWRnZXQgdG8gc2hvdyB3aGlsZSBsb2FkaW5nIHRoZSBmZWF0dXJlIGZsYWcgdmFsdWUKICBmaW5hbCBXaWRnZXQ/IGxvYWRpbmc7CgogIEBvdmVycmlkZQogIFdpZGdldCBidWlsZChCdWlsZENvbnRleHQgY29udGV4dCkgewogICAgcmV0dXJuIEZ1dHVyZUJ1aWxkZXI8Ym9vbD4oCiAgICAgIGZ1dHVyZTogX2NoZWNrRmVhdHVyZUZsYWcoKSwKICAgICAgYnVpbGRlcjogKGNvbnRleHQsIHNuYXBzaG90KSB7CiAgICAgICAgLy8gU2hvdyBsb2FkaW5nIHdpZGdldCB3aGlsZSB3YWl0aW5nIGZvciBmZWF0dXJlIGZsYWcKICAgICAgICBpZiAoc25hcHNob3QuY29ubmVjdGlvblN0YXRlID09IENvbm5lY3Rpb25TdGF0ZS53YWl0aW5nKSB7CiAgICAgICAgICByZXR1cm4gbG9hZGluZyA/PyBjb25zdCBTaXplZEJveC5zaHJpbmsoKTsKICAgICAgICB9CgogICAgICAgIC8vIEdldCB0aGUgZmVhdHVyZSBmbGFnIHZhbHVlLCBkZWZhdWx0aW5nIHRvIGZhbHNlIGlmIHRoZXJlJ3MgYW4gZXJyb3IKICAgICAgICBmaW5hbCBpc0VuYWJsZWQgPSBzbmFwc2hvdC5kYXRhID8/IGRlZmF1bHRWYWx1ZTsKCiAgICAgICAgLy8gUmV0dXJuIHRoZSB3aWRnZXQgYnVpbHQgYnkgdGhlIGJ1aWxkZXIgZnVuY3Rpb24KICAgICAgICByZXR1cm4gYnVpbGRlcihjb250ZXh0LCBpc0VuYWJsZWQpOwogICAgICB9LAogICAgKTsKICB9CgogIEZ1dHVyZTxib29sPiBfY2hlY2tGZWF0dXJlRmxhZygpIGFzeW5jIHsKICAgIHRyeSB7CiAgICAgIGZpbmFsIGZlYXR1cmVGbGFnID0gZGkuZ2V0PEZlYXR1cmVGbGFnPigpOwogICAgICByZXR1cm4gYXdhaXQgZmVhdHVyZUZsYWcuaXNFbmFibGVkKGZsYWdLZXksIGRlZmF1bHRWYWx1ZTogZGVmYXVsdFZhbHVlKTsKICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgLy8gSWYgdGhlcmUncyBhbiBlcnJvciBhY2Nlc3NpbmcgdGhlIGZlYXR1cmUgZmxhZyBzZXJ2aWNlLAogICAgICAvLyByZXR1cm4gdGhlIGRlZmF1bHQgdmFsdWUKICAgICAgcmV0dXJuIGRlZmF1bHRWYWx1ZTsKICAgIH0KICB9Cn0K", + "aW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZmVhdHVyZV9mbGFncy9zcmMvZmVhdHVyZV9mbGFnX3NlcnZpY2UuZGFydCc7CmltcG9ydCAncGFja2FnZTpmbHV0dGVyL21hdGVyaWFsLmRhcnQnOwoKLy8vIEEgd3JhcHBlciB3aWRnZXQgdGhhdCBjb25kaXRpb25hbGx5IHJlbmRlcnMgY29udGVudCBiYXNlZCBvbiBmZWF0dXJlIGZsYWdzCmNsYXNzIEZlYXR1cmVGbGFnV3JhcHBlciBleHRlbmRzIFN0YXRlZnVsV2lkZ2V0IHsKICBjb25zdCBGZWF0dXJlRmxhZ1dyYXBwZXIoewogICAgc3VwZXIua2V5LAogICAgcmVxdWlyZWQgdGhpcy5mbGFnS2V5LAogICAgcmVxdWlyZWQgdGhpcy5idWlsZGVyLAogICAgdGhpcy5kZWZhdWx0VmFsdWUgPSBmYWxzZSwKICAgIHRoaXMubG9hZGluZywKICAgIHRoaXMuc2VydmljZSwKICB9KTsKCiAgLy8vIFRoZSBmZWF0dXJlIGZsYWcga2V5IHRvIGNoZWNrCiAgZmluYWwgU3RyaW5nIGZsYWdLZXk7CgogIC8vLyBCdWlsZGVyIGZ1bmN0aW9uIHRoYXQgcmVjZWl2ZXMgdGhlIGNvbnRleHQgYW5kIGZlYXR1cmUgZmxhZyB2YWx1ZQogIGZpbmFsIFdpZGdldCBGdW5jdGlvbihCdWlsZENvbnRleHQgY29udGV4dCwgYm9vbCB2YWx1ZSkgYnVpbGRlcjsKCiAgLy8vIFRoZSBkZWZhdWx0IHZhbHVlIHRvIHVzZSBpZiB0aGUgZmVhdHVyZSBmbGFnIHNlcnZpY2UgaXMgdW5hdmFpbGFibGUKICBmaW5hbCBib29sIGRlZmF1bHRWYWx1ZTsKCiAgLy8vIFdpZGdldCB0byBzaG93IHdoaWxlIGxvYWRpbmcgdGhlIGZlYXR1cmUgZmxhZyB2YWx1ZQogIGZpbmFsIFdpZGdldD8gbG9hZGluZzsKICBmaW5hbCBGZWF0dXJlRmxhZz8gc2VydmljZTsKCiAgQG92ZXJyaWRlCiAgU3RhdGU8RmVhdHVyZUZsYWdXcmFwcGVyPiBjcmVhdGVTdGF0ZSgpID0+IF9GZWF0dXJlRmxhZ1dyYXBwZXJTdGF0ZSgpOwp9CgpjbGFzcyBfRmVhdHVyZUZsYWdXcmFwcGVyU3RhdGUgZXh0ZW5kcyBTdGF0ZTxGZWF0dXJlRmxhZ1dyYXBwZXI+IHsKICBsYXRlIEZ1dHVyZTxib29sPiBfdmFsdWU7CgogIEBvdmVycmlkZQogIHZvaWQgaW5pdFN0YXRlKCkgewogICAgc3VwZXIuaW5pdFN0YXRlKCk7CiAgICBfdmFsdWUgPSBfY2hlY2tGZWF0dXJlRmxhZygpOwogIH0KCiAgQG92ZXJyaWRlCiAgdm9pZCBkaWRVcGRhdGVXaWRnZXQoRmVhdHVyZUZsYWdXcmFwcGVyIG9sZFdpZGdldCkgewogICAgc3VwZXIuZGlkVXBkYXRlV2lkZ2V0KG9sZFdpZGdldCk7CiAgICBpZiAob2xkV2lkZ2V0LmZsYWdLZXkgIT0gd2lkZ2V0LmZsYWdLZXkgfHwKICAgICAgICBvbGRXaWRnZXQuZGVmYXVsdFZhbHVlICE9IHdpZGdldC5kZWZhdWx0VmFsdWUgfHwKICAgICAgICBvbGRXaWRnZXQuc2VydmljZSAhPSB3aWRnZXQuc2VydmljZSkgewogICAgICBfdmFsdWUgPSBfY2hlY2tGZWF0dXJlRmxhZygpOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgV2lkZ2V0IGJ1aWxkKEJ1aWxkQ29udGV4dCBjb250ZXh0KSB7CiAgICByZXR1cm4gRnV0dXJlQnVpbGRlcjxib29sPigKICAgICAgZnV0dXJlOiBfdmFsdWUsCiAgICAgIGJ1aWxkZXI6IChjb250ZXh0LCBzbmFwc2hvdCkgewogICAgICAgIC8vIFNob3cgbG9hZGluZyB3aWRnZXQgd2hpbGUgd2FpdGluZyBmb3IgZmVhdHVyZSBmbGFnCiAgICAgICAgaWYgKHNuYXBzaG90LmNvbm5lY3Rpb25TdGF0ZSA9PSBDb25uZWN0aW9uU3RhdGUud2FpdGluZykgewogICAgICAgICAgcmV0dXJuIHdpZGdldC5sb2FkaW5nID8/IGNvbnN0IFNpemVkQm94LnNocmluaygpOwogICAgICAgIH0KCiAgICAgICAgLy8gR2V0IHRoZSBmZWF0dXJlIGZsYWcgdmFsdWUsIGRlZmF1bHRpbmcgdG8gZmFsc2UgaWYgdGhlcmUncyBhbiBlcnJvcgogICAgICAgIGZpbmFsIGlzRW5hYmxlZCA9IHNuYXBzaG90LmRhdGEgPz8gd2lkZ2V0LmRlZmF1bHRWYWx1ZTsKCiAgICAgICAgLy8gUmV0dXJuIHRoZSB3aWRnZXQgYnVpbHQgYnkgdGhlIGJ1aWxkZXIgZnVuY3Rpb24KICAgICAgICByZXR1cm4gd2lkZ2V0LmJ1aWxkZXIoY29udGV4dCwgaXNFbmFibGVkKTsKICAgICAgfSwKICAgICk7CiAgfQoKICBGdXR1cmU8Ym9vbD4gX2NoZWNrRmVhdHVyZUZsYWcoKSBhc3luYyB7CiAgICB0cnkgewogICAgICBmaW5hbCBmZWF0dXJlRmxhZyA9IHdpZGdldC5zZXJ2aWNlID8/IGRpLmdldDxGZWF0dXJlRmxhZz4oKTsKICAgICAgcmV0dXJuIGF3YWl0IGZlYXR1cmVGbGFnLmlzRW5hYmxlZCgKICAgICAgICB3aWRnZXQuZmxhZ0tleSwKICAgICAgICBkZWZhdWx0VmFsdWU6IHdpZGdldC5kZWZhdWx0VmFsdWUsCiAgICAgICk7CiAgICB9IGNhdGNoIChlKSB7CiAgICAgIC8vIElmIHRoZXJlJ3MgYW4gZXJyb3IgYWNjZXNzaW5nIHRoZSBmZWF0dXJlIGZsYWcgc2VydmljZSwKICAgICAgLy8gcmV0dXJuIHRoZSBkZWZhdWx0IHZhbHVlCiAgICAgIHJldHVybiB3aWRnZXQuZGVmYXVsdFZhbHVlOwogICAgfQogIH0KfQo=", "type": "text" }, { "path": "{{ name.snakeCase() }}/packages/{{feature_flags_dir}}/lib/src/firebase_remote_config_provider.dart", "data": - "aW1wb3J0ICdwYWNrYWdlOmNvcmUvbG9nZ2VyL2xvZ2dlci5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZmVhdHVyZV9mbGFncy9mZWF0dXJlX2ZsYWdzLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZmlyZWJhc2VfcmVtb3RlX2NvbmZpZy9maXJlYmFzZV9yZW1vdGVfY29uZmlnLmRhcnQnOwoKLy8vIEZpcmViYXNlIFJlbW90ZSBDb25maWcgaW1wbGVtZW50YXRpb24gb2YgRmVhdHVyZUZsYWdQcm92aWRlcgpjbGFzcyBGaXJlYmFzZVJlbW90ZUNvbmZpZ1Byb3ZpZGVyIGltcGxlbWVudHMgRmVhdHVyZUZsYWdQcm92aWRlciB7CiAgbGF0ZSBmaW5hbCBGaXJlYmFzZVJlbW90ZUNvbmZpZyBfcmVtb3RlQ29uZmlnOwogIGZpbmFsIEZlYXR1cmVGbGFnc0NvbmZpZyBfY29uZmlnOwogIGxhdGUgZmluYWwgTG9nZ2VyIGxvZ2dlcjsKCiAgRmlyZWJhc2VSZW1vdGVDb25maWdQcm92aWRlcih7RmVhdHVyZUZsYWdzQ29uZmlnPyBjb25maWd9KQogICAgOiBfY29uZmlnID0KICAgICAgICAgIGNvbmZpZyA/PwogICAgICAgICAgY29uc3QgRmVhdHVyZUZsYWdzQ29uZmlnKAogICAgICAgICAgICBkZWZhdWx0UGFyYW1ldGVyczoge30sCiAgICAgICAgICAgIGZldGNoVGltZW91dDogRHVyYXRpb24oc2Vjb25kczogMTApLAogICAgICAgICAgICBtaW5pbXVtRmV0Y2hJbnRlcnZhbDogRHVyYXRpb24oaG91cnM6IDEpLAogICAgICAgICAgKSB7CiAgICBpZiAoZGkuaGFzPExvZ2dlcj4oKSkgewogICAgICBsb2dnZXIgPSBkaS5nZXQ8TG9nZ2VyPigpOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPHZvaWQ+IGluaXQoKSBhc3luYyB7CiAgICB0cnkgewogICAgICBfcmVtb3RlQ29uZmlnID0gRmlyZWJhc2VSZW1vdGVDb25maWcuaW5zdGFuY2U7CgogICAgICAvLyBDb25maWd1cmUgc2V0dGluZ3MKICAgICAgYXdhaXQgX3JlbW90ZUNvbmZpZy5zZXRDb25maWdTZXR0aW5ncygKICAgICAgICBSZW1vdGVDb25maWdTZXR0aW5ncygKICAgICAgICAgIGZldGNoVGltZW91dDogX2NvbmZpZy5mZXRjaFRpbWVvdXQgPz8gY29uc3QgRHVyYXRpb24oc2Vjb25kczogMTApLAogICAgICAgICAgbWluaW11bUZldGNoSW50ZXJ2YWw6CiAgICAgICAgICAgICAgX2NvbmZpZy5taW5pbXVtRmV0Y2hJbnRlcnZhbCA/PyBjb25zdCBEdXJhdGlvbihob3VyczogMSksCiAgICAgICAgKSwKICAgICAgKTsKCiAgICAgIC8vIFNldCBkZWZhdWx0IHZhbHVlcwogICAgICBhd2FpdCBfc2V0RGVmYXVsdHMoKTsKCiAgICAgIC8vIEZldGNoIGFuZCBhY3RpdmF0ZQogICAgICBmaW5hbCBhY3RpdmF0ZWQgPSBhd2FpdCBfcmVtb3RlQ29uZmlnLmZldGNoQW5kQWN0aXZhdGUoKTsKCiAgICAgIGxvZ2dlci5pKCdGaXJlYmFzZSBSZW1vdGUgQ29uZmlnIGluaXRpYWxpemVkIHN1Y2Nlc3NmdWxseScpOwogICAgICBsb2dnZXIuaSgnUmVtb3RlIENvbmZpZyBhY3RpdmF0ZWQ6ICRhY3RpdmF0ZWQnKTsKICAgICAgbG9nZ2VyLmkoJ0xhc3QgZmV0Y2ggc3RhdHVzOiAke19yZW1vdGVDb25maWcubGFzdEZldGNoU3RhdHVzfScpOwogICAgICBsb2dnZXIuaSgnTGFzdCBmZXRjaCB0aW1lOiAke19yZW1vdGVDb25maWcubGFzdEZldGNoVGltZX0nKTsKCiAgICAgIC8vIExvZyBhbGwgY3VycmVudCB2YWx1ZXMgZm9yIGRlYnVnZ2luZwogICAgICBmaW5hbCBhbGxWYWx1ZXMgPSBfcmVtb3RlQ29uZmlnLmdldEFsbCgpOwogICAgICBmb3IgKGZpbmFsIGVudHJ5IGluIGFsbFZhbHVlcy5lbnRyaWVzKSB7CiAgICAgICAgbG9nZ2VyLmkoJ1JlbW90ZSBDb25maWcgLSAke2VudHJ5LmtleX06ICR7ZW50cnkudmFsdWUuYXNTdHJpbmcoKX0nKTsKICAgICAgfQogICAgfSBjYXRjaCAoZSwgc3RhY2tUcmFjZSkgewogICAgICBsb2dnZXIuZSgnRmFpbGVkIHRvIGluaXRpYWxpemUgRmlyZWJhc2UgUmVtb3RlIENvbmZpZycsIGUsIHN0YWNrVHJhY2UpOwogICAgICByZXRocm93OwogICAgfQogIH0KCiAgRnV0dXJlPHZvaWQ+IF9zZXREZWZhdWx0cygpIGFzeW5jIHsKICAgIGF3YWl0IF9yZW1vdGVDb25maWcuc2V0RGVmYXVsdHMoX2NvbmZpZy5kZWZhdWx0UGFyYW1ldGVycyk7CiAgfQoKICBAb3ZlcnJpZGUKICBGdXR1cmU8Ym9vbD4gZ2V0Qm9vbChTdHJpbmcga2V5LCB7Ym9vbCBkZWZhdWx0VmFsdWUgPSBmYWxzZX0pIGFzeW5jIHsKICAgIHRyeSB7CiAgICAgIGZpbmFsIHZhbHVlID0gX3JlbW90ZUNvbmZpZy5nZXRCb29sKGtleSk7CiAgICAgIGZpbmFsIGNvbmZpZ1ZhbHVlID0gX3JlbW90ZUNvbmZpZy5nZXRWYWx1ZShrZXkpOwogICAgICBsb2dnZXIuaSgKICAgICAgICAnR2V0dGluZyBib29sIGZsYWcgIiRrZXkiOiB2YWx1ZT0kdmFsdWUsJwogICAgICAgICcgc291cmNlPSR7Y29uZmlnVmFsdWUuc291cmNlfScsCiAgICAgICk7CiAgICAgIHJldHVybiB2YWx1ZTsKICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgbG9nZ2VyLmUoCiAgICAgICAgJ0ZhaWxlZCB0byBnZXQgYm9vbCBmbGFnOiAka2V5LCB1c2luZyBkZWZhdWx0OiAkZGVmYXVsdFZhbHVlJywKICAgICAgICBlLAogICAgICApOwogICAgICByZXR1cm4gZGVmYXVsdFZhbHVlOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPFN0cmluZz4gZ2V0U3RyaW5nKFN0cmluZyBrZXksIHtTdHJpbmcgZGVmYXVsdFZhbHVlID0gJyd9KSBhc3luYyB7CiAgICB0cnkgewogICAgICBmaW5hbCB2YWx1ZSA9IF9yZW1vdGVDb25maWcuZ2V0U3RyaW5nKGtleSk7CiAgICAgIHJldHVybiB2YWx1ZS5pc0VtcHR5ID8gZGVmYXVsdFZhbHVlIDogdmFsdWU7CiAgICB9IGNhdGNoIChlKSB7CiAgICAgIGxvZ2dlci53KCdGYWlsZWQgdG8gZ2V0IHN0cmluZyBmbGFnOiAka2V5LCB1c2luZyBkZWZhdWx0OiAkZGVmYXVsdFZhbHVlJyk7CiAgICAgIHJldHVybiBkZWZhdWx0VmFsdWU7CiAgICB9CiAgfQoKICBAb3ZlcnJpZGUKICBGdXR1cmU8aW50PiBnZXRJbnQoU3RyaW5nIGtleSwge2ludCBkZWZhdWx0VmFsdWUgPSAwfSkgYXN5bmMgewogICAgdHJ5IHsKICAgICAgcmV0dXJuIF9yZW1vdGVDb25maWcuZ2V0SW50KGtleSk7CiAgICB9IGNhdGNoIChlKSB7CiAgICAgIGxvZ2dlci53KCdGYWlsZWQgdG8gZ2V0IGludCBmbGFnOiAka2V5LCB1c2luZyBkZWZhdWx0OiAkZGVmYXVsdFZhbHVlJyk7CiAgICAgIHJldHVybiBkZWZhdWx0VmFsdWU7CiAgICB9CiAgfQoKICBAb3ZlcnJpZGUKICBGdXR1cmU8ZG91YmxlPiBnZXREb3VibGUoU3RyaW5nIGtleSwge2RvdWJsZSBkZWZhdWx0VmFsdWUgPSAwLjB9KSBhc3luYyB7CiAgICB0cnkgewogICAgICByZXR1cm4gX3JlbW90ZUNvbmZpZy5nZXREb3VibGUoa2V5KTsKICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgbG9nZ2VyLncoJ0ZhaWxlZCB0byBnZXQgZG91YmxlIGZsYWc6ICRrZXksIHVzaW5nIGRlZmF1bHQ6ICRkZWZhdWx0VmFsdWUnKTsKICAgICAgcmV0dXJuIGRlZmF1bHRWYWx1ZTsKICAgIH0KICB9CgogIEBvdmVycmlkZQogIEZ1dHVyZTxib29sPiBoYXNGbGFnKFN0cmluZyBrZXkpIGFzeW5jIHsKICAgIHRyeSB7CiAgICAgIGZpbmFsIHZhbHVlID0gX3JlbW90ZUNvbmZpZy5nZXRWYWx1ZShrZXkpOwogICAgICByZXR1cm4gdmFsdWUuc291cmNlICE9IFZhbHVlU291cmNlLnZhbHVlU3RhdGljOwogICAgfSBjYXRjaCAoZSkgewogICAgICBsb2dnZXIudygnRmFpbGVkIHRvIGNoZWNrIGlmIGZsYWcgZXhpc3RzOiAka2V5Jyk7CiAgICAgIHJldHVybiBmYWxzZTsKICAgIH0KICB9CgogIEBvdmVycmlkZQogIHZvaWQgZGlzcG9zZSgpIHsKICAgIC8vIEZpcmViYXNlIFJlbW90ZSBDb25maWcgZG9lc24ndCByZXF1aXJlIGV4cGxpY2l0IGRpc3Bvc2FsCiAgICBsb2dnZXIuaSgnRmlyZWJhc2UgUmVtb3RlIENvbmZpZyBwcm92aWRlciBkaXNwb3NlZCcpOwogIH0KCiAgLy8vIEdldCB0aGUgbGFzdCBmZXRjaCB0aW1lCiAgRGF0ZVRpbWUgZ2V0IGxhc3RGZXRjaFRpbWUgPT4gX3JlbW90ZUNvbmZpZy5sYXN0RmV0Y2hUaW1lOwoKICAvLy8gR2V0IHRoZSBsYXN0IGZldGNoIHN0YXR1cwogIFJlbW90ZUNvbmZpZ0ZldGNoU3RhdHVzIGdldCBsYXN0RmV0Y2hTdGF0dXMgPT4gX3JlbW90ZUNvbmZpZy5sYXN0RmV0Y2hTdGF0dXM7CgogIC8vLyBBZGQgYSBsaXN0ZW5lciBmb3IgY29uZmlnIHVwZGF0ZXMKICBTdHJlYW08UmVtb3RlQ29uZmlnVXBkYXRlPiBnZXQgb25Db25maWdVcGRhdGVkID0+CiAgICAgIF9yZW1vdGVDb25maWcub25Db25maWdVcGRhdGVkOwoKICAvLy8gR2V0IHRoZSBjdXJyZW50IGNvbmZpZ3VyYXRpb24KICBGZWF0dXJlRmxhZ3NDb25maWcgZ2V0IGNvbmZpZyA9PiBfY29uZmlnOwp9Cg==", + "aW1wb3J0ICdwYWNrYWdlOmNvcmUvbG9nZ2VyL2xvZ2dlci5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZlYXR1cmVfZmxhZ3MvZmVhdHVyZV9mbGFncy5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZpcmViYXNlX3JlbW90ZV9jb25maWcvZmlyZWJhc2VfcmVtb3RlX2NvbmZpZy5kYXJ0JzsKCi8vLyBGaXJlYmFzZSBSZW1vdGUgQ29uZmlnIGltcGxlbWVudGF0aW9uIG9mIEZlYXR1cmVGbGFnUHJvdmlkZXIKY2xhc3MgRmlyZWJhc2VSZW1vdGVDb25maWdQcm92aWRlciBpbXBsZW1lbnRzIEZlYXR1cmVGbGFnUHJvdmlkZXIgewogIGZpbmFsIEZpcmViYXNlUmVtb3RlQ29uZmlnIF9yZW1vdGVDb25maWc7CiAgZmluYWwgRmVhdHVyZUZsYWdzQ29uZmlnIF9jb25maWc7CiAgZmluYWwgTG9nZ2VyIGxvZ2dlcjsKCiAgRmlyZWJhc2VSZW1vdGVDb25maWdQcm92aWRlcih7CiAgICByZXF1aXJlZCBGaXJlYmFzZVJlbW90ZUNvbmZpZyByZW1vdGVDb25maWcsCiAgICByZXF1aXJlZCB0aGlzLmxvZ2dlciwKICAgIEZlYXR1cmVGbGFnc0NvbmZpZz8gY29uZmlnLAogIH0pIDogX3JlbW90ZUNvbmZpZyA9IHJlbW90ZUNvbmZpZywKICAgICAgIF9jb25maWcgPQogICAgICAgICAgIGNvbmZpZyA/PwogICAgICAgICAgIGNvbnN0IEZlYXR1cmVGbGFnc0NvbmZpZygKICAgICAgICAgICAgIGRlZmF1bHRQYXJhbWV0ZXJzOiB7fSwKICAgICAgICAgICAgIGZldGNoVGltZW91dDogRHVyYXRpb24oc2Vjb25kczogMTApLAogICAgICAgICAgICAgbWluaW11bUZldGNoSW50ZXJ2YWw6IER1cmF0aW9uKGhvdXJzOiAxKSwKICAgICAgICAgICApOwoKICBAb3ZlcnJpZGUKICBGdXR1cmU8dm9pZD4gaW5pdCgpIGFzeW5jIHsKICAgIHRyeSB7CiAgICAgIC8vIENvbmZpZ3VyZSBzZXR0aW5ncwogICAgICBhd2FpdCBfcmVtb3RlQ29uZmlnLnNldENvbmZpZ1NldHRpbmdzKAogICAgICAgIFJlbW90ZUNvbmZpZ1NldHRpbmdzKAogICAgICAgICAgZmV0Y2hUaW1lb3V0OiBfY29uZmlnLmZldGNoVGltZW91dCA/PyBjb25zdCBEdXJhdGlvbihzZWNvbmRzOiAxMCksCiAgICAgICAgICBtaW5pbXVtRmV0Y2hJbnRlcnZhbDoKICAgICAgICAgICAgICBfY29uZmlnLm1pbmltdW1GZXRjaEludGVydmFsID8/IGNvbnN0IER1cmF0aW9uKGhvdXJzOiAxKSwKICAgICAgICApLAogICAgICApOwoKICAgICAgLy8gU2V0IGRlZmF1bHQgdmFsdWVzCiAgICAgIGF3YWl0IF9zZXREZWZhdWx0cygpOwoKICAgICAgLy8gRmV0Y2ggYW5kIGFjdGl2YXRlCiAgICAgIGZpbmFsIGFjdGl2YXRlZCA9IGF3YWl0IF9yZW1vdGVDb25maWcuZmV0Y2hBbmRBY3RpdmF0ZSgpOwoKICAgICAgbG9nZ2VyLmkoJ0ZpcmViYXNlIFJlbW90ZSBDb25maWcgaW5pdGlhbGl6ZWQgc3VjY2Vzc2Z1bGx5Jyk7CiAgICAgIGxvZ2dlci5pKCdSZW1vdGUgQ29uZmlnIGFjdGl2YXRlZDogJGFjdGl2YXRlZCcpOwogICAgICBsb2dnZXIuaSgnTGFzdCBmZXRjaCBzdGF0dXM6ICR7X3JlbW90ZUNvbmZpZy5sYXN0RmV0Y2hTdGF0dXN9Jyk7CiAgICAgIGxvZ2dlci5pKCdMYXN0IGZldGNoIHRpbWU6ICR7X3JlbW90ZUNvbmZpZy5sYXN0RmV0Y2hUaW1lfScpOwogICAgfSBjYXRjaCAoZSwgc3RhY2tUcmFjZSkgewogICAgICBsb2dnZXIuZSgnRmFpbGVkIHRvIGluaXRpYWxpemUgRmlyZWJhc2UgUmVtb3RlIENvbmZpZycsIGUsIHN0YWNrVHJhY2UpOwogICAgICByZXRocm93OwogICAgfQogIH0KCiAgRnV0dXJlPHZvaWQ+IF9zZXREZWZhdWx0cygpIGFzeW5jIHsKICAgIGF3YWl0IF9yZW1vdGVDb25maWcuc2V0RGVmYXVsdHMoX2NvbmZpZy5kZWZhdWx0UGFyYW1ldGVycyk7CiAgfQoKICBAb3ZlcnJpZGUKICBGdXR1cmU8Ym9vbD4gZ2V0Qm9vbChTdHJpbmcga2V5LCB7Ym9vbCBkZWZhdWx0VmFsdWUgPSBmYWxzZX0pIGFzeW5jIHsKICAgIHRyeSB7CiAgICAgIGZpbmFsIGNvbmZpZ1ZhbHVlID0gX3JlbW90ZUNvbmZpZy5nZXRWYWx1ZShrZXkpOwogICAgICByZXR1cm4gY29uZmlnVmFsdWUuc291cmNlID09IFZhbHVlU291cmNlLnZhbHVlU3RhdGljCiAgICAgICAgICA/IGRlZmF1bHRWYWx1ZQogICAgICAgICAgOiBfcmVtb3RlQ29uZmlnLmdldEJvb2woa2V5KTsKICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgbG9nZ2VyLmUoCiAgICAgICAgJ0ZhaWxlZCB0byBnZXQgYm9vbCBmbGFnOiAka2V5LCB1c2luZyBkZWZhdWx0OiAkZGVmYXVsdFZhbHVlJywKICAgICAgICBlLAogICAgICApOwogICAgICByZXR1cm4gZGVmYXVsdFZhbHVlOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPFN0cmluZz4gZ2V0U3RyaW5nKFN0cmluZyBrZXksIHtTdHJpbmcgZGVmYXVsdFZhbHVlID0gJyd9KSBhc3luYyB7CiAgICB0cnkgewogICAgICByZXR1cm4gX3JlbW90ZUNvbmZpZy5nZXRWYWx1ZShrZXkpLnNvdXJjZSA9PSBWYWx1ZVNvdXJjZS52YWx1ZVN0YXRpYwogICAgICAgICAgPyBkZWZhdWx0VmFsdWUKICAgICAgICAgIDogX3JlbW90ZUNvbmZpZy5nZXRTdHJpbmcoa2V5KTsKICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgbG9nZ2VyLncoJ0ZhaWxlZCB0byBnZXQgc3RyaW5nIGZsYWc6ICRrZXksIHVzaW5nIGRlZmF1bHQ6ICRkZWZhdWx0VmFsdWUnKTsKICAgICAgcmV0dXJuIGRlZmF1bHRWYWx1ZTsKICAgIH0KICB9CgogIEBvdmVycmlkZQogIEZ1dHVyZTxpbnQ+IGdldEludChTdHJpbmcga2V5LCB7aW50IGRlZmF1bHRWYWx1ZSA9IDB9KSBhc3luYyB7CiAgICB0cnkgewogICAgICByZXR1cm4gX3JlbW90ZUNvbmZpZy5nZXRWYWx1ZShrZXkpLnNvdXJjZSA9PSBWYWx1ZVNvdXJjZS52YWx1ZVN0YXRpYwogICAgICAgICAgPyBkZWZhdWx0VmFsdWUKICAgICAgICAgIDogX3JlbW90ZUNvbmZpZy5nZXRJbnQoa2V5KTsKICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgbG9nZ2VyLncoJ0ZhaWxlZCB0byBnZXQgaW50IGZsYWc6ICRrZXksIHVzaW5nIGRlZmF1bHQ6ICRkZWZhdWx0VmFsdWUnKTsKICAgICAgcmV0dXJuIGRlZmF1bHRWYWx1ZTsKICAgIH0KICB9CgogIEBvdmVycmlkZQogIEZ1dHVyZTxkb3VibGU+IGdldERvdWJsZShTdHJpbmcga2V5LCB7ZG91YmxlIGRlZmF1bHRWYWx1ZSA9IDAuMH0pIGFzeW5jIHsKICAgIHRyeSB7CiAgICAgIHJldHVybiBfcmVtb3RlQ29uZmlnLmdldFZhbHVlKGtleSkuc291cmNlID09IFZhbHVlU291cmNlLnZhbHVlU3RhdGljCiAgICAgICAgICA/IGRlZmF1bHRWYWx1ZQogICAgICAgICAgOiBfcmVtb3RlQ29uZmlnLmdldERvdWJsZShrZXkpOwogICAgfSBjYXRjaCAoZSkgewogICAgICBsb2dnZXIudygnRmFpbGVkIHRvIGdldCBkb3VibGUgZmxhZzogJGtleSwgdXNpbmcgZGVmYXVsdDogJGRlZmF1bHRWYWx1ZScpOwogICAgICByZXR1cm4gZGVmYXVsdFZhbHVlOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPGJvb2w+IGhhc0ZsYWcoU3RyaW5nIGtleSkgYXN5bmMgewogICAgdHJ5IHsKICAgICAgZmluYWwgdmFsdWUgPSBfcmVtb3RlQ29uZmlnLmdldFZhbHVlKGtleSk7CiAgICAgIHJldHVybiB2YWx1ZS5zb3VyY2UgIT0gVmFsdWVTb3VyY2UudmFsdWVTdGF0aWM7CiAgICB9IGNhdGNoIChlKSB7CiAgICAgIGxvZ2dlci53KCdGYWlsZWQgdG8gY2hlY2sgaWYgZmxhZyBleGlzdHM6ICRrZXknKTsKICAgICAgcmV0dXJuIGZhbHNlOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgdm9pZCBkaXNwb3NlKCkgewogICAgLy8gRmlyZWJhc2UgUmVtb3RlIENvbmZpZyBkb2Vzbid0IHJlcXVpcmUgZXhwbGljaXQgZGlzcG9zYWwKICAgIGxvZ2dlci5pKCdGaXJlYmFzZSBSZW1vdGUgQ29uZmlnIHByb3ZpZGVyIGRpc3Bvc2VkJyk7CiAgfQoKICAvLy8gR2V0IHRoZSBsYXN0IGZldGNoIHRpbWUKICBEYXRlVGltZSBnZXQgbGFzdEZldGNoVGltZSA9PiBfcmVtb3RlQ29uZmlnLmxhc3RGZXRjaFRpbWU7CgogIC8vLyBHZXQgdGhlIGxhc3QgZmV0Y2ggc3RhdHVzCiAgUmVtb3RlQ29uZmlnRmV0Y2hTdGF0dXMgZ2V0IGxhc3RGZXRjaFN0YXR1cyA9PiBfcmVtb3RlQ29uZmlnLmxhc3RGZXRjaFN0YXR1czsKCiAgLy8vIEFkZCBhIGxpc3RlbmVyIGZvciBjb25maWcgdXBkYXRlcwogIFN0cmVhbTxSZW1vdGVDb25maWdVcGRhdGU+IGdldCBvbkNvbmZpZ1VwZGF0ZWQgPT4KICAgICAgX3JlbW90ZUNvbmZpZy5vbkNvbmZpZ1VwZGF0ZWQ7CgogIC8vLyBHZXQgdGhlIGN1cnJlbnQgY29uZmlndXJhdGlvbgogIEZlYXR1cmVGbGFnc0NvbmZpZyBnZXQgY29uZmlnID0+IF9jb25maWc7Cn0K", "type": "text" }, { @@ -1073,14 +1223,14 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "path": "{{ name.snakeCase() }}/packages/{{feature_flags_dir}}/lib/src/register.dart", "data": - "aW1wb3J0ICdwYWNrYWdlOmNvcmUvbG9nZ2VyL2xvZ2dlci5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZmVhdHVyZV9mbGFncy9zcmMvZmVhdHVyZV9mbGFnX3Byb3ZpZGVyLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZmVhdHVyZV9mbGFncy9zcmMvZmVhdHVyZV9mbGFnX3NlcnZpY2UuZGFydCc7CmltcG9ydCAncGFja2FnZTpmZWF0dXJlX2ZsYWdzL3NyYy9maXJlYmFzZV9yZW1vdGVfY29uZmlnX3Byb3ZpZGVyLmRhcnQnOwoKLy8vIFJlZ2lzdGVyIGZlYXR1cmUgZmxhZ3Mgc2VydmljZXMgd2l0aCBkZXBlbmRlbmN5IGluamVjdGlvbgovLy8KRnV0dXJlPHZvaWQ+IHJlZ2lzdGVyRmVhdHVyZUZsYWdzV2l0aERJKHtGZWF0dXJlRmxhZ3NDb25maWc/IGNvbmZpZ30pIGFzeW5jIHsKICBmaW5hbCBsb2dnZXIgPSBkaS5nZXQ8TG9nZ2VyPigpOwoKICAvLyBSZWdpc3RlciB0aGUgcHJvdmlkZXIKICBmaW5hbCBwcm92aWRlciA9IEZpcmViYXNlUmVtb3RlQ29uZmlnUHJvdmlkZXIoY29uZmlnOiBjb25maWcpOwogIGRpLnJlZ2lzdGVyPEZlYXR1cmVGbGFnUHJvdmlkZXI+KHByb3ZpZGVyLCBkaXNwb3NlOiAocCkgPT4gcC5kaXNwb3NlKCkpOwoKICAvLyBSZWdpc3RlciB0aGUgc2VydmljZQogIGZpbmFsIHNlcnZpY2UgPSBGZWF0dXJlRmxhZyhwcm92aWRlcjogcHJvdmlkZXIsIGxvZ2dlcjogbG9nZ2VyKTsKICBkaS5yZWdpc3RlcjxGZWF0dXJlRmxhZz4oc2VydmljZSwgZGlzcG9zZTogKHMpID0+IHMuZGlzcG9zZSgpKTsKfQo=", + "aW1wb3J0ICdwYWNrYWdlOmNvcmUvbG9nZ2VyL2xvZ2dlci5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZmVhdHVyZV9mbGFncy9zcmMvZmVhdHVyZV9mbGFnX3Byb3ZpZGVyLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZmVhdHVyZV9mbGFncy9zcmMvZmVhdHVyZV9mbGFnX3NlcnZpY2UuZGFydCc7CmltcG9ydCAncGFja2FnZTpmZWF0dXJlX2ZsYWdzL3NyYy9maXJlYmFzZV9yZW1vdGVfY29uZmlnX3Byb3ZpZGVyLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZmlyZWJhc2VfcmVtb3RlX2NvbmZpZy9maXJlYmFzZV9yZW1vdGVfY29uZmlnLmRhcnQnOwoKLy8vIFJlZ2lzdGVyIGZlYXR1cmUgZmxhZ3Mgc2VydmljZXMgd2l0aCBkZXBlbmRlbmN5IGluamVjdGlvbgovLy8KRnV0dXJlPHZvaWQ+IHJlZ2lzdGVyRmVhdHVyZUZsYWdzV2l0aERJKHsKICBGZWF0dXJlRmxhZ3NDb25maWc/IGNvbmZpZywKICBGZWF0dXJlRmxhZ1Byb3ZpZGVyPyBwcm92aWRlciwKfSkgYXN5bmMgewogIGZpbmFsIGxvZ2dlciA9IGRpLmdldDxMb2dnZXI+KCk7CgogIC8vIFJlZ2lzdGVyIHRoZSBwcm92aWRlcgogIGZpbmFsIHNlbGVjdGVkUHJvdmlkZXIgPQogICAgICBwcm92aWRlciA/PwogICAgICBGaXJlYmFzZVJlbW90ZUNvbmZpZ1Byb3ZpZGVyKAogICAgICAgIGNvbmZpZzogY29uZmlnLAogICAgICAgIGxvZ2dlcjogbG9nZ2VyLAogICAgICAgIHJlbW90ZUNvbmZpZzogRmlyZWJhc2VSZW1vdGVDb25maWcuaW5zdGFuY2UsCiAgICAgICk7CiAgLy8gVGhlIHNlcnZpY2Ugb3ducyBwcm92aWRlciBkaXNwb3NhbDsgcmVnaXN0ZXJpbmcgaXQgdHdpY2Ugd291bGQgZGlzcG9zZQogIC8vIHBsYXRmb3JtIHN1YnNjcmlwdGlvbnMgdHdpY2Ugd2hlbiB0aGUgY29udGFpbmVyIGlzIHJlc2V0LgogIGRpLnJlZ2lzdGVyPEZlYXR1cmVGbGFnUHJvdmlkZXI+KHNlbGVjdGVkUHJvdmlkZXIpOwoKICAvLyBSZWdpc3RlciB0aGUgc2VydmljZQogIGZpbmFsIHNlcnZpY2UgPSBGZWF0dXJlRmxhZyhwcm92aWRlcjogc2VsZWN0ZWRQcm92aWRlciwgbG9nZ2VyOiBsb2dnZXIpOwogIGRpLnJlZ2lzdGVyPEZlYXR1cmVGbGFnPihzZXJ2aWNlLCBkaXNwb3NlOiAocykgPT4gcy5kaXNwb3NlKCkpOwp9Cg==", "type": "text" }, { "path": "{{ name.snakeCase() }}/packages/{{feature_flags_dir}}/pubspec.yaml", "data": - "bmFtZTogZmVhdHVyZV9mbGFncwpkZXNjcmlwdGlvbjogIlJlbW90ZS1jb25maWcgYmFja2VkIGZlYXR1cmUgZmxhZ3MgZm9yIHt7bmFtZS50aXRsZUNhc2UoKX19LiIKdmVyc2lvbjogMC4xLjAKcHVibGlzaF90bzogJ25vbmUnCgplbnZpcm9ubWVudDoKICBzZGs6IF4zLjguMAogIGZsdXR0ZXI6ICI+PTMuMjkuMCIKCmRlcGVuZGVuY2llczoKICBmbHV0dGVyOgogICAgc2RrOiBmbHV0dGVyCiAgZmlyZWJhc2VfY29yZTogXjMuMTQuMAogIGZpcmViYXNlX3JlbW90ZV9jb25maWc6IF41LjEuNgogIGNvcmU6CiAgICBwYXRoOiAuLi9jb3JlCiAgZGk6CiAgICBwYXRoOiAuLi9kaQoKZGV2X2RlcGVuZGVuY2llczoKICBmbHV0dGVyX3Rlc3Q6CiAgICBzZGs6IGZsdXR0ZXIKICBmbHV0dGVyX2xpbnRzOiBeNS4wLjAKCmZsdXR0ZXI6Cg==", + "bmFtZTogZmVhdHVyZV9mbGFncwpkZXNjcmlwdGlvbjogIlJlbW90ZS1jb25maWcgYmFja2VkIGZlYXR1cmUgZmxhZ3MgZm9yIHt7bmFtZS50aXRsZUNhc2UoKX19LiIKdmVyc2lvbjogMC4xLjAKcHVibGlzaF90bzogJ25vbmUnCgplbnZpcm9ubWVudDoKICBzZGs6IF4zLjguMAogIGZsdXR0ZXI6ICI+PTMuMjkuMCIKCmRlcGVuZGVuY2llczoKICBmbHV0dGVyOgogICAgc2RrOiBmbHV0dGVyCiAgZmlyZWJhc2VfY29yZTogXjMuMTQuMAogIGZpcmViYXNlX3JlbW90ZV9jb25maWc6IF41LjEuNgogIGNvcmU6CiAgICBwYXRoOiAuLi9jb3JlCiAgZGk6CiAgICBwYXRoOiAuLi9kaQoKZGV2X2RlcGVuZGVuY2llczoKICBtb2NrdGFpbDogXjEuMC40CiAgZmx1dHRlcl90ZXN0OgogICAgc2RrOiBmbHV0dGVyCiAgZmx1dHRlcl9saW50czogXjUuMC4wCgpmbHV0dGVyOgo=", "type": "text" }, { @@ -1089,11 +1239,18 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "IyBGZWF0dXJlIEZsYWdzCgpGZWF0dXJlIGZsYWdzIGFuZCByZW1vdGUgY29uZmlndXJhdGlvbiBtYW5hZ2VtZW50IGZvciB7e25hbWUudGl0bGVDYXNlKCl9fQoKWyFbbm9uc3RvcF9jbGldKGh0dHBzOi8vaW1nLnNoaWVsZHMuaW8vYmFkZ2Uvc3RhcnRlZCUyMHdpdGgtbm9uc3RvcF9jbGktMTY2QzRFLnN2Zz9zdHlsZT1mbGF0LXNxdWFyZSldKGh0dHBzOi8vcHViLmRldi9wYWNrYWdlcy9ub25zdG9wX2NsaSkKWyFbbWVsb3NdKGh0dHBzOi8vaW1nLnNoaWVsZHMuaW8vYmFkZ2UvbWFpbnRhaW5lZCUyMHdpdGgtbWVsb3MtZjcwMGZmLnN2Zz9zdHlsZT1mbGF0LXNxdWFyZSldKGh0dHBzOi8vZ2l0aHViLmNvbS9pbnZlcnRhc2UvbWVsb3MpCgojIyBJbnN0YWxsYXRpb24g8J+SuwoKKirinZcgSW4gb3JkZXIgdG8gc3RhcnQgdXNpbmcgRmVhdHVyZSBGbGFncyB5b3UgbXVzdCBoYXZlIHRoZSBbRmx1dHRlciBTREtdW2ZsdXR0ZXJfaW5zdGFsbF9saW5rXSBpbnN0YWxsZWQgb24geW91ciBtYWNoaW5lLioqCgpJbnN0YWxsIHZpYSBgZGFydCBwdWIgYWRkYDoKCmBgYHNoCmRhcnQgcHViIGFkZCBmZWF0dXJlX2ZsYWdzCmBgYAoKW2ZsdXR0ZXJfaW5zdGFsbF9saW5rXTogaHR0cHM6Ly9kb2NzLmZsdXR0ZXIuZGV2L2dldC1zdGFydGVkL2luc3RhbGw=", "type": "text" }, + { + "path": + "{{ name.snakeCase() }}/packages/{{feature_flags_dir}}/test/feature_flags_test.dart", + "data": + "aW1wb3J0ICdwYWNrYWdlOmNvcmUvY29yZS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZmVhdHVyZV9mbGFncy9mZWF0dXJlX2ZsYWdzLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZmVhdHVyZV9mbGFncy9mZWF0dXJlX2ZsYWdzLmRhcnQnIGFzIGZsYWdzOwppbXBvcnQgJ3BhY2thZ2U6ZmlyZWJhc2VfcmVtb3RlX2NvbmZpZy9maXJlYmFzZV9yZW1vdGVfY29uZmlnLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlci9tYXRlcmlhbC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZsdXR0ZXJfdGVzdC9mbHV0dGVyX3Rlc3QuZGFydCc7CmltcG9ydCAncGFja2FnZTptb2NrdGFpbC9tb2NrdGFpbC5kYXJ0JzsKCmNsYXNzIF9Mb2dnZXIgZXh0ZW5kcyBNb2NrIGltcGxlbWVudHMgTG9nZ2VyIHt9CgpjbGFzcyBfUHJvdmlkZXIgZXh0ZW5kcyBNb2NrIGltcGxlbWVudHMgRmVhdHVyZUZsYWdQcm92aWRlciB7fQoKY2xhc3MgX1JlbW90ZUNvbmZpZyBleHRlbmRzIE1vY2sgaW1wbGVtZW50cyBGaXJlYmFzZVJlbW90ZUNvbmZpZyB7fQoKdm9pZCBtYWluKCkgewogIGxhdGUgX0xvZ2dlciBsb2dnZXI7CiAgbGF0ZSBfUHJvdmlkZXIgcHJvdmlkZXI7CiAgbGF0ZSBGZWF0dXJlRmxhZyBzZXJ2aWNlOwogIHNldFVwKCgpIHsKICAgIGxvZ2dlciA9IF9Mb2dnZXIoKTsKICAgIHByb3ZpZGVyID0gX1Byb3ZpZGVyKCk7CiAgICB3aGVuKHByb3ZpZGVyLmluaXQpLnRoZW5BbnN3ZXIoKF8pIGFzeW5jIHt9KTsKICAgIHNlcnZpY2UgPSBGZWF0dXJlRmxhZyhwcm92aWRlcjogcHJvdmlkZXIsIGxvZ2dlcjogbG9nZ2VyKTsKICB9KTsKICB0ZWFyRG93bihkaS5yZXNldCk7CgogIHRlc3QoJ3JlYWRzIHJlcXVpcmUgaW5pdGlhbGl6YXRpb247IGxpZmVjeWNsZSBpcyBpZGVtcG90ZW50JywgKCkgYXN5bmMgewogICAgZXhwZWN0KHNlcnZpY2UuaXNJbml0aWFsaXplZCwgaXNGYWxzZSk7CiAgICBhd2FpdCBleHBlY3RMYXRlcihzZXJ2aWNlLmlzRW5hYmxlZCgnZmxhZycpLCB0aHJvd3NTdGF0ZUVycm9yKTsKICAgIGF3YWl0IHNlcnZpY2UuaW5pdCgpOwogICAgYXdhaXQgc2VydmljZS5pbml0KCk7CiAgICB2ZXJpZnkocHJvdmlkZXIuaW5pdCkuY2FsbGVkKDEpOwogICAgZXhwZWN0KHNlcnZpY2UuaXNJbml0aWFsaXplZCwgaXNUcnVlKTsKICAgIHNlcnZpY2UuZGlzcG9zZSgpOwogICAgdmVyaWZ5KHByb3ZpZGVyLmRpc3Bvc2UpLmNhbGxlZCgxKTsKICAgIGV4cGVjdChzZXJ2aWNlLmlzSW5pdGlhbGl6ZWQsIGlzRmFsc2UpOwogIH0pOwoKICB0ZXN0KCdmYWlsZWQgaW5pdGlhbGl6YXRpb24gcHJvcGFnYXRlcyBhbmQgY2FuIGJlIHJldHJpZWQnLCAoKSBhc3luYyB7CiAgICB3aGVuKHByb3ZpZGVyLmluaXQpLnRoZW5UaHJvdyhTdGF0ZUVycm9yKCdvZmZsaW5lJykpOwogICAgYXdhaXQgZXhwZWN0TGF0ZXIoc2VydmljZS5pbml0KCksIHRocm93c1N0YXRlRXJyb3IpOwogICAgZXhwZWN0KHNlcnZpY2UuaXNJbml0aWFsaXplZCwgaXNGYWxzZSk7CiAgICB3aGVuKHByb3ZpZGVyLmluaXQpLnRoZW5BbnN3ZXIoKF8pIGFzeW5jIHt9KTsKICAgIGF3YWl0IHNlcnZpY2UuaW5pdCgpOwogICAgZXhwZWN0KHNlcnZpY2UuaXNJbml0aWFsaXplZCwgaXNUcnVlKTsKICB9KTsKCiAgdGVzdCgndHlwZWQgcmVhZHMgcHJlc2VydmUgY2FsbGVyIGRlZmF1bHRzJywgKCkgYXN5bmMgewogICAgYXdhaXQgc2VydmljZS5pbml0KCk7CiAgICB3aGVuKAogICAgICAoKSA9PiBwcm92aWRlci5nZXRCb29sKCdiJywgZGVmYXVsdFZhbHVlOiB0cnVlKSwKICAgICkudGhlbkFuc3dlcigoXykgYXN5bmMgPT4gdHJ1ZSk7CiAgICB3aGVuKAogICAgICAoKSA9PiBwcm92aWRlci5nZXRTdHJpbmcoJ3MnLCBkZWZhdWx0VmFsdWU6ICdmYWxsYmFjaycpLAogICAgKS50aGVuQW5zd2VyKChfKSBhc3luYyA9PiAndmFsdWUnKTsKICAgIHdoZW4oCiAgICAgICgpID0+IHByb3ZpZGVyLmdldEludCgnaScsIGRlZmF1bHRWYWx1ZTogMyksCiAgICApLnRoZW5BbnN3ZXIoKF8pIGFzeW5jID0+IDUpOwogICAgd2hlbigKICAgICAgKCkgPT4gcHJvdmlkZXIuZ2V0RG91YmxlKCdkJywgZGVmYXVsdFZhbHVlOiAxLjUpLAogICAgKS50aGVuQW5zd2VyKChfKSBhc3luYyA9PiAyLjUpOwogICAgZXhwZWN0KGF3YWl0IHNlcnZpY2UuaXNFbmFibGVkKCdiJywgZGVmYXVsdFZhbHVlOiB0cnVlKSwgaXNUcnVlKTsKICAgIGV4cGVjdChhd2FpdCBzZXJ2aWNlLmdldENvbmZpZygncycsIGRlZmF1bHRWYWx1ZTogJ2ZhbGxiYWNrJyksICd2YWx1ZScpOwogICAgZXhwZWN0KGF3YWl0IHNlcnZpY2UuZ2V0SW50Q29uZmlnKCdpJywgZGVmYXVsdFZhbHVlOiAzKSwgNSk7CiAgICBleHBlY3QoYXdhaXQgc2VydmljZS5nZXREb3VibGVDb25maWcoJ2QnLCBkZWZhdWx0VmFsdWU6IDEuNSksIDIuNSk7CiAgfSk7CgogIHRlc3QoCiAgICAnbW9kdWxlIGluamVjdGlvbiBpbml0aWFsaXplcyBhbmQgZGlzcG9zZXMgdGhlIHByb3ZpZGVyIGV4YWN0bHkgb25jZScsCiAgICAoKSBhc3luYyB7CiAgICAgIGRpLnJlZ2lzdGVyPExvZ2dlcj4obG9nZ2VyKTsKICAgICAgYXdhaXQgZmxhZ3MuaW5pdChwcm92aWRlcjogcHJvdmlkZXIpOwogICAgICBleHBlY3QoZGkuZ2V0PEZlYXR1cmVGbGFnPigpLmlzSW5pdGlhbGl6ZWQsIGlzVHJ1ZSk7CiAgICAgIGF3YWl0IGRpLnJlc2V0KCk7CiAgICAgIHZlcmlmeShwcm92aWRlci5kaXNwb3NlKS5jYWxsZWQoMSk7CiAgICB9LAogICk7CgogIHRlc3QoJ21vZHVsZSBpbml0aWFsaXphdGlvbiBmYWlsdXJlcyBwcm9wYWdhdGUnLCAoKSBhc3luYyB7CiAgICBkaS5yZWdpc3RlcjxMb2dnZXI+KGxvZ2dlcik7CiAgICB3aGVuKHByb3ZpZGVyLmluaXQpLnRoZW5UaHJvdyhTdGF0ZUVycm9yKCdvZmZsaW5lJykpOwogICAgYXdhaXQgZXhwZWN0TGF0ZXIoZmxhZ3MuaW5pdChwcm92aWRlcjogcHJvdmlkZXIpLCB0aHJvd3NTdGF0ZUVycm9yKTsKICB9KTsKCiAgdGVzdFdpZGdldHMoJ3dyYXBwZXIgY2FjaGVzIHJlYWRzIHVudGlsIGl0cyBpbnB1dHMgY2hhbmdlJywgKHRlc3RlcikgYXN5bmMgewogICAgYXdhaXQgc2VydmljZS5pbml0KCk7CiAgICB3aGVuKAogICAgICAoKSA9PiBwcm92aWRlci5nZXRCb29sKCdmbGFnJywgZGVmYXVsdFZhbHVlOiBmYWxzZSksCiAgICApLnRoZW5BbnN3ZXIoKF8pIGFzeW5jID0+IHRydWUpOwogICAgd2hlbigKICAgICAgKCkgPT4gcHJvdmlkZXIuZ2V0Qm9vbCgnb3RoZXInLCBkZWZhdWx0VmFsdWU6IGZhbHNlKSwKICAgICkudGhlbkFuc3dlcigoXykgYXN5bmMgPT4gZmFsc2UpOwogICAgV2lkZ2V0IHZpZXcoU3RyaW5nIGtleSkgPT4gTWF0ZXJpYWxBcHAoCiAgICAgIGhvbWU6IEZlYXR1cmVGbGFnV3JhcHBlcigKICAgICAgICBzZXJ2aWNlOiBzZXJ2aWNlLAogICAgICAgIGZsYWdLZXk6IGtleSwKICAgICAgICBsb2FkaW5nOiBjb25zdCBUZXh0KCdMb2FkaW5nJyksCiAgICAgICAgYnVpbGRlcjogKF8sIHZhbHVlKSA9PiBUZXh0KCdFbmFibGVkOiAkdmFsdWUnKSwKICAgICAgKSwKICAgICk7CiAgICBhd2FpdCB0ZXN0ZXIucHVtcFdpZGdldCh2aWV3KCdmbGFnJykpOwogICAgZXhwZWN0KGZpbmQudGV4dCgnTG9hZGluZycpLCBmaW5kc09uZVdpZGdldCk7CiAgICBhd2FpdCB0ZXN0ZXIucHVtcEFuZFNldHRsZSgpOwogICAgZXhwZWN0KGZpbmQudGV4dCgnRW5hYmxlZDogdHJ1ZScpLCBmaW5kc09uZVdpZGdldCk7CiAgICBhd2FpdCB0ZXN0ZXIucHVtcFdpZGdldCh2aWV3KCdmbGFnJykpOwogICAgYXdhaXQgdGVzdGVyLnB1bXBBbmRTZXR0bGUoKTsKICAgIHZlcmlmeSgoKSA9PiBwcm92aWRlci5nZXRCb29sKCdmbGFnJywgZGVmYXVsdFZhbHVlOiBmYWxzZSkpLmNhbGxlZCgxKTsKICAgIGF3YWl0IHRlc3Rlci5wdW1wV2lkZ2V0KHZpZXcoJ290aGVyJykpOwogICAgYXdhaXQgdGVzdGVyLnB1bXBBbmRTZXR0bGUoKTsKICAgIGV4cGVjdChmaW5kLnRleHQoJ0VuYWJsZWQ6IGZhbHNlJyksIGZpbmRzT25lV2lkZ2V0KTsKICB9KTsKCiAgdGVzdFdpZGdldHMoJ3dyYXBwZXIgdXNlcyBmYWxsYmFjayB3aGVuIHRoZSBzZXJ2aWNlIGlzIHVuYXZhaWxhYmxlJywgKAogICAgdGVzdGVyLAogICkgYXN5bmMgewogICAgYXdhaXQgdGVzdGVyLnB1bXBXaWRnZXQoCiAgICAgIE1hdGVyaWFsQXBwKAogICAgICAgIGhvbWU6IEZlYXR1cmVGbGFnV3JhcHBlcigKICAgICAgICAgIGZsYWdLZXk6ICdmbGFnJywKICAgICAgICAgIGRlZmF1bHRWYWx1ZTogdHJ1ZSwKICAgICAgICAgIGJ1aWxkZXI6IChfLCB2YWx1ZSkgPT4gVGV4dCgnRW5hYmxlZDogJHZhbHVlJyksCiAgICAgICAgKSwKICAgICAgKSwKICAgICk7CiAgICBhd2FpdCB0ZXN0ZXIucHVtcEFuZFNldHRsZSgpOwogICAgZXhwZWN0KGZpbmQudGV4dCgnRW5hYmxlZDogdHJ1ZScpLCBmaW5kc09uZVdpZGdldCk7CiAgfSk7CgogIGdyb3VwKCdGaXJlYmFzZSBhZGFwdGVyJywgKCkgewogICAgbGF0ZSBfUmVtb3RlQ29uZmlnIHJlbW90ZTsKICAgIGxhdGUgRmlyZWJhc2VSZW1vdGVDb25maWdQcm92aWRlciBhZGFwdGVyOwogICAgc2V0VXAoKCkgewogICAgICByZW1vdGUgPSBfUmVtb3RlQ29uZmlnKCk7CiAgICAgIGFkYXB0ZXIgPSBGaXJlYmFzZVJlbW90ZUNvbmZpZ1Byb3ZpZGVyKAogICAgICAgIHJlbW90ZUNvbmZpZzogcmVtb3RlLAogICAgICAgIGxvZ2dlcjogbG9nZ2VyLAogICAgICApOwogICAgICByZWdpc3RlckZhbGxiYWNrVmFsdWUoCiAgICAgICAgUmVtb3RlQ29uZmlnU2V0dGluZ3MoCiAgICAgICAgICBmZXRjaFRpbWVvdXQ6IGNvbnN0IER1cmF0aW9uKHNlY29uZHM6IDEwKSwKICAgICAgICAgIG1pbmltdW1GZXRjaEludGVydmFsOiBjb25zdCBEdXJhdGlvbihob3VyczogMSksCiAgICAgICAgKSwKICAgICAgKTsKICAgICAgd2hlbigoKSA9PiByZW1vdGUuc2V0Q29uZmlnU2V0dGluZ3MoYW55KCkpKS50aGVuQW5zd2VyKChfKSBhc3luYyB7fSk7CiAgICAgIHdoZW4oKCkgPT4gcmVtb3RlLnNldERlZmF1bHRzKGFueSgpKSkudGhlbkFuc3dlcigoXykgYXN5bmMge30pOwogICAgICB3aGVuKHJlbW90ZS5mZXRjaEFuZEFjdGl2YXRlKS50aGVuQW5zd2VyKChfKSBhc3luYyA9PiB0cnVlKTsKICAgICAgd2hlbigKICAgICAgICAoKSA9PiByZW1vdGUubGFzdEZldGNoU3RhdHVzLAogICAgICApLnRoZW5SZXR1cm4oUmVtb3RlQ29uZmlnRmV0Y2hTdGF0dXMuc3VjY2Vzcyk7CiAgICAgIHdoZW4oKCkgPT4gcmVtb3RlLmxhc3RGZXRjaFRpbWUpLnRoZW5SZXR1cm4oRGF0ZVRpbWUoMjAyNikpOwogICAgICB3aGVuKAogICAgICAgICgpID0+IHJlbW90ZS5vbkNvbmZpZ1VwZGF0ZWQsCiAgICAgICkudGhlbkFuc3dlcigoXykgPT4gY29uc3QgU3RyZWFtLmVtcHR5KCkpOwogICAgfSk7CgogICAgdGVzdCgnY29uZmlndXJlcyBGaXJlYmFzZSBhbmQgZXhwb3NlcyB1cGRhdGUgbWV0YWRhdGEnLCAoKSBhc3luYyB7CiAgICAgIGF3YWl0IGFkYXB0ZXIuaW5pdCgpOwogICAgICB2ZXJpZnkoKCkgPT4gcmVtb3RlLnNldERlZmF1bHRzKHt9KSkuY2FsbGVkKDEpOwogICAgICBleHBlY3QoYWRhcHRlci5jb25maWcuZGVmYXVsdFBhcmFtZXRlcnMsIGlzRW1wdHkpOwogICAgICBleHBlY3QoYWRhcHRlci5sYXN0RmV0Y2hUaW1lLCBEYXRlVGltZSgyMDI2KSk7CiAgICAgIGV4cGVjdChhZGFwdGVyLmxhc3RGZXRjaFN0YXR1cywgUmVtb3RlQ29uZmlnRmV0Y2hTdGF0dXMuc3VjY2Vzcyk7CiAgICAgIGV4cGVjdChhd2FpdCBhZGFwdGVyLm9uQ29uZmlnVXBkYXRlZC50b0xpc3QoKSwgaXNFbXB0eSk7CiAgICAgIGFkYXB0ZXIuZGlzcG9zZSgpOwogICAgfSk7CgogICAgdGVzdCgnaW5pdGlhbGl6YXRpb24gZmFpbHVyZSBwcm9wYWdhdGVzJywgKCkgYXN5bmMgewogICAgICB3aGVuKHJlbW90ZS5mZXRjaEFuZEFjdGl2YXRlKS50aGVuVGhyb3coU3RhdGVFcnJvcignb2ZmbGluZScpKTsKICAgICAgYXdhaXQgZXhwZWN0TGF0ZXIoYWRhcHRlci5pbml0KCksIHRocm93c1N0YXRlRXJyb3IpOwogICAgfSk7CgogICAgdGVzdCgnbWlzc2luZyBrZXlzIHJlc3BlY3Qgbm9uemVybyBhbmQgdHJ1ZSBkZWZhdWx0cycsICgpIGFzeW5jIHsKICAgICAgd2hlbigKICAgICAgICAoKSA9PiByZW1vdGUuZ2V0VmFsdWUoYW55KCkpLAogICAgICApLnRoZW5SZXR1cm4oUmVtb3RlQ29uZmlnVmFsdWUoW10sIFZhbHVlU291cmNlLnZhbHVlU3RhdGljKSk7CiAgICAgIGV4cGVjdChhd2FpdCBhZGFwdGVyLmdldEJvb2woJ21pc3NpbmcnLCBkZWZhdWx0VmFsdWU6IHRydWUpLCBpc1RydWUpOwogICAgICBleHBlY3QoCiAgICAgICAgYXdhaXQgYWRhcHRlci5nZXRTdHJpbmcoJ21pc3NpbmcnLCBkZWZhdWx0VmFsdWU6ICdmYWxsYmFjaycpLAogICAgICAgICdmYWxsYmFjaycsCiAgICAgICk7CiAgICAgIGV4cGVjdChhd2FpdCBhZGFwdGVyLmdldEludCgnbWlzc2luZycsIGRlZmF1bHRWYWx1ZTogOSksIDkpOwogICAgICBleHBlY3QoYXdhaXQgYWRhcHRlci5nZXREb3VibGUoJ21pc3NpbmcnLCBkZWZhdWx0VmFsdWU6IDEuNSksIDEuNSk7CiAgICAgIGV4cGVjdChhd2FpdCBhZGFwdGVyLmhhc0ZsYWcoJ21pc3NpbmcnKSwgaXNGYWxzZSk7CiAgICB9KTsKCiAgICB0ZXN0KAogICAgICAnY29uZmlndXJlZCBmYWxzZSwgemVybyBhbmQgZW1wdHkgdmFsdWVzIHJlbWFpbiB2YWxpZCB2YWx1ZXMnLAogICAgICAoKSBhc3luYyB7CiAgICAgICAgd2hlbigKICAgICAgICAgICgpID0+IHJlbW90ZS5nZXRWYWx1ZShhbnkoKSksCiAgICAgICAgKS50aGVuUmV0dXJuKFJlbW90ZUNvbmZpZ1ZhbHVlKFtdLCBWYWx1ZVNvdXJjZS52YWx1ZVJlbW90ZSkpOwogICAgICAgIHdoZW4oKCkgPT4gcmVtb3RlLmdldEJvb2woYW55KCkpKS50aGVuUmV0dXJuKGZhbHNlKTsKICAgICAgICB3aGVuKCgpID0+IHJlbW90ZS5nZXRTdHJpbmcoYW55KCkpKS50aGVuUmV0dXJuKCcnKTsKICAgICAgICB3aGVuKCgpID0+IHJlbW90ZS5nZXRJbnQoYW55KCkpKS50aGVuUmV0dXJuKDApOwogICAgICAgIHdoZW4oKCkgPT4gcmVtb3RlLmdldERvdWJsZShhbnkoKSkpLnRoZW5SZXR1cm4oMCk7CiAgICAgICAgZXhwZWN0KGF3YWl0IGFkYXB0ZXIuZ2V0Qm9vbCgna2V5JywgZGVmYXVsdFZhbHVlOiB0cnVlKSwgaXNGYWxzZSk7CiAgICAgICAgZXhwZWN0KGF3YWl0IGFkYXB0ZXIuZ2V0U3RyaW5nKCdrZXknLCBkZWZhdWx0VmFsdWU6ICdmYWxsYmFjaycpLCAnJyk7CiAgICAgICAgZXhwZWN0KGF3YWl0IGFkYXB0ZXIuZ2V0SW50KCdrZXknLCBkZWZhdWx0VmFsdWU6IDkpLCAwKTsKICAgICAgICBleHBlY3QoYXdhaXQgYWRhcHRlci5nZXREb3VibGUoJ2tleScsIGRlZmF1bHRWYWx1ZTogMS41KSwgMCk7CiAgICAgICAgZXhwZWN0KGF3YWl0IGFkYXB0ZXIuaGFzRmxhZygna2V5JyksIGlzVHJ1ZSk7CiAgICAgIH0sCiAgICApOwoKICAgIHRlc3QoJ1NESyByZWFkIGZhaWx1cmVzIHJldHVybiBkZWZhdWx0cycsICgpIGFzeW5jIHsKICAgICAgd2hlbigoKSA9PiByZW1vdGUuZ2V0VmFsdWUoYW55KCkpKS50aGVuVGhyb3coU3RhdGVFcnJvcigndW5hdmFpbGFibGUnKSk7CiAgICAgIGV4cGVjdChhd2FpdCBhZGFwdGVyLmdldEJvb2woJ2tleScsIGRlZmF1bHRWYWx1ZTogdHJ1ZSksIGlzVHJ1ZSk7CiAgICAgIGV4cGVjdCgKICAgICAgICBhd2FpdCBhZGFwdGVyLmdldFN0cmluZygna2V5JywgZGVmYXVsdFZhbHVlOiAnZmFsbGJhY2snKSwKICAgICAgICAnZmFsbGJhY2snLAogICAgICApOwogICAgICBleHBlY3QoYXdhaXQgYWRhcHRlci5nZXRJbnQoJ2tleScsIGRlZmF1bHRWYWx1ZTogOSksIDkpOwogICAgICBleHBlY3QoYXdhaXQgYWRhcHRlci5nZXREb3VibGUoJ2tleScsIGRlZmF1bHRWYWx1ZTogMS41KSwgMS41KTsKICAgICAgZXhwZWN0KGF3YWl0IGFkYXB0ZXIuaGFzRmxhZygna2V5JyksIGlzRmFsc2UpOwogICAgfSk7CiAgfSk7Cn0K", + "type": "text" + }, { "path": "{{ name.snakeCase() }}/packages/{{network_dir}}/lib/network.dart", "data": - "bGlicmFyeTsKCmltcG9ydCAncGFja2FnZTpjb3JlL2NvcmUuZGFydCc7CmltcG9ydCAncGFja2FnZTpkaS9kaS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOm5ldHdvcmsvc3JjL2F1dGgvaW5kZXguZGFydCc7CmltcG9ydCAncGFja2FnZTpuZXR3b3JrL3NyYy9jbGllbnQvaW5kZXguZGFydCc7CmltcG9ydCAncGFja2FnZTpuZXR3b3JrL3NyYy9jb25maWcvaW5kZXguZGFydCc7CgpleHBvcnQgJ3NyYy9hcGkvaW5kZXguZGFydCc7CmV4cG9ydCAnc3JjL2F1dGgvaW5kZXguZGFydCc7CmV4cG9ydCAnc3JjL2NsaWVudC9pbmRleC5kYXJ0JzsKZXhwb3J0ICdzcmMvY29uZmlnL2luZGV4LmRhcnQnOwpleHBvcnQgJ3NyYy9leGNlcHRpb25zL2luZGV4LmRhcnQnOwpleHBvcnQgJ3NyYy9pbnRlcmNlcHRvcnMvaW5kZXguZGFydCc7CmV4cG9ydCAnc3JjL21vZGVscy9pbmRleC5kYXJ0JzsKZXhwb3J0ICdzcmMvdXRpbHMvaW5kZXguZGFydCc7CgpGdXR1cmU8dm9pZD4gaW5pdCh7CiAgcmVxdWlyZWQgTmV0d29ya0NvbmZpZyBjb25maWcsCiAgYm9vbCB1c2VBdXRoZW50aWNhdGlvbiA9IHRydWUsCn0pIGFzeW5jIHsKICBhd2FpdCByZWdpc3Rlck5ldHdvcmtXaXRoREkoY29uZmlnLCB1c2VBdXRoZW50aWNhdGlvbjogdXNlQXV0aGVudGljYXRpb24pOwogIGZpbmFsIGxvZ2dlciA9IGRpLmdldDxMb2dnZXI+KCk7CiAgbG9nZ2VyLmkoJ05ldHdvcmsgbW9kdWxlIGluaXRpYWxpemVkIHdpdGggYmFzZSBVUkw6ICR7Y29uZmlnLmJhc2VVcmx9Jyk7Cn0KCkZ1dHVyZTx2b2lkPiByZWdpc3Rlck5ldHdvcmtXaXRoREkoCiAgTmV0d29ya0NvbmZpZyBjb25maWcsIHsKICBib29sIHVzZUF1dGhlbnRpY2F0aW9uID0gdHJ1ZSwKfSkgYXN5bmMgewogIGZpbmFsIGxvZ2dlciA9IGRpLmdldDxMb2dnZXI+KCk7CgogIC8vIFRyeSB0byBnZXQgQXV0aFRva2VuUHJvdmlkZXIgZnJvbSBESSBpZiBhdXRoZW50aWNhdGlvbiBpcyBlbmFibGVkCiAgQXV0aFRva2VuUHJvdmlkZXI/IGF1dGhUb2tlblByb3ZpZGVyOwogIGlmICh1c2VBdXRoZW50aWNhdGlvbiAmJiBjb25maWcuYXV0aFRva2VuUHJvdmlkZXIgPT0gbnVsbCkgewogICAgdHJ5IHsKICAgICAgYXV0aFRva2VuUHJvdmlkZXIgPSBkaS5nZXQ8QXV0aFRva2VuUHJvdmlkZXI+KCk7CiAgICAgIGxvZ2dlci5kKCfwn5SQIEZvdW5kIEF1dGhUb2tlblByb3ZpZGVyIGluIERJLCB1c2luZyBmb3IgYXV0aGVudGljYXRpb24nKTsKICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgbG9nZ2VyLmQoCiAgICAgICAgJ/CflJMgTm8gQXV0aFRva2VuUHJvdmlkZXIgZm91bmQgaW4gREksIGNyZWF0aW5nIHVuYXV0aGVudGljYXRlZCBjbGllbnQnLAogICAgICApOwogICAgfQogIH0gZWxzZSBpZiAoY29uZmlnLmF1dGhUb2tlblByb3ZpZGVyICE9IG51bGwpIHsKICAgIGF1dGhUb2tlblByb3ZpZGVyID0gY29uZmlnLmF1dGhUb2tlblByb3ZpZGVyOwogICAgbG9nZ2VyLmQoJ/CflJAgVXNpbmcgcHJvdmlkZWQgQXV0aFRva2VuUHJvdmlkZXInKTsKICB9CgogIC8vIENyZWF0ZSBuZXR3b3JrIGNvbmZpZyB3aXRoIGF1dGggcHJvdmlkZXIgaWYgYXZhaWxhYmxlCiAgbGF0ZSBmaW5hbCBOZXR3b3JrQ29uZmlnIGZpbmFsQ29uZmlnOwogIGlmIChhdXRoVG9rZW5Qcm92aWRlciAhPSBudWxsICYmIGNvbmZpZy5hdXRoVG9rZW5Qcm92aWRlciA9PSBudWxsKSB7CiAgICAvLyBDcmVhdGUgYSBuZXcgY29uZmlnIHdpdGggdGhlIGF1dGggcHJvdmlkZXIKICAgIGZpbmFsQ29uZmlnID0gRGVmYXVsdE5ldHdvcmtDb25maWcoCiAgICAgIGJhc2VVcmw6IGNvbmZpZy5iYXNlVXJsLAogICAgICBjb25uZWN0VGltZW91dDogY29uZmlnLmNvbm5lY3RUaW1lb3V0LAogICAgICByZWNlaXZlVGltZW91dDogY29uZmlnLnJlY2VpdmVUaW1lb3V0LAogICAgICBzZW5kVGltZW91dDogY29uZmlnLnNlbmRUaW1lb3V0LAogICAgICBkZWZhdWx0SGVhZGVyczogY29uZmlnLmRlZmF1bHRIZWFkZXJzLAogICAgICBlbmFibGVMb2dnaW5nOiBjb25maWcuZW5hYmxlTG9nZ2luZywKICAgICAgYXV0aFRva2VuUHJvdmlkZXI6IGF1dGhUb2tlblByb3ZpZGVyLAogICAgKTsKICB9IGVsc2UgewogICAgZmluYWxDb25maWcgPSBjb25maWc7CiAgfQoKICBmaW5hbCBuZXR3b3JrQ2xpZW50ID0gRGlvTmV0d29ya0NsaWVudChmaW5hbENvbmZpZyk7CiAgZGkucmVnaXN0ZXI8TmV0d29ya0NsaWVudD4oCiAgICBuZXR3b3JrQ2xpZW50LAogICAgZGlzcG9zZTogKGNsaWVudCkgPT4gY2xpZW50LmRpc3Bvc2UoKSwKICApOwogIGRpLnJlZ2lzdGVyPE5ldHdvcmtDb25maWc+KGZpbmFsQ29uZmlnKTsKCiAgaWYgKGZpbmFsQ29uZmlnLmF1dGhUb2tlblByb3ZpZGVyICE9IG51bGwpIHsKICAgIGxvZ2dlci5pKCfwn5SQIE5ldHdvcmsgY2xpZW50IHJlZ2lzdGVyZWQgd2l0aCBhdXRoZW50aWNhdGlvbiBzdXBwb3J0Jyk7CiAgfSBlbHNlIHsKICAgIGxvZ2dlci5pKCfwn5STIE5ldHdvcmsgY2xpZW50IHJlZ2lzdGVyZWQgd2l0aG91dCBhdXRoZW50aWNhdGlvbicpOwogIH0KfQo=", + "bGlicmFyeTsKCmltcG9ydCAncGFja2FnZTpjb3JlL2NvcmUuZGFydCc7CmltcG9ydCAncGFja2FnZTpkaS9kaS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOm5ldHdvcmsvc3JjL2F1dGgvaW5kZXguZGFydCc7CmltcG9ydCAncGFja2FnZTpuZXR3b3JrL3NyYy9jbGllbnQvaW5kZXguZGFydCc7CmltcG9ydCAncGFja2FnZTpuZXR3b3JrL3NyYy9jb25maWcvaW5kZXguZGFydCc7CgpleHBvcnQgJ3NyYy9hcGkvaW5kZXguZGFydCc7CmV4cG9ydCAnc3JjL2F1dGgvaW5kZXguZGFydCc7CmV4cG9ydCAnc3JjL2NsaWVudC9pbmRleC5kYXJ0JzsKZXhwb3J0ICdzcmMvY29uZmlnL2luZGV4LmRhcnQnOwpleHBvcnQgJ3NyYy9leGNlcHRpb25zL2luZGV4LmRhcnQnOwpleHBvcnQgJ3NyYy9pbnRlcmNlcHRvcnMvaW5kZXguZGFydCc7CmV4cG9ydCAnc3JjL21vZGVscy9pbmRleC5kYXJ0JzsKZXhwb3J0ICdzcmMvdXRpbHMvaW5kZXguZGFydCc7CgpGdXR1cmU8dm9pZD4gaW5pdCh7CiAgcmVxdWlyZWQgTmV0d29ya0NvbmZpZyBjb25maWcsCiAgYm9vbCB1c2VBdXRoZW50aWNhdGlvbiA9IHRydWUsCn0pIGFzeW5jIHsKICBhd2FpdCByZWdpc3Rlck5ldHdvcmtXaXRoREkoY29uZmlnLCB1c2VBdXRoZW50aWNhdGlvbjogdXNlQXV0aGVudGljYXRpb24pOwogIGZpbmFsIGxvZ2dlciA9IGRpLmdldDxMb2dnZXI+KCk7CiAgbG9nZ2VyLmkoJ05ldHdvcmsgbW9kdWxlIGluaXRpYWxpemVkIHdpdGggYmFzZSBVUkw6ICR7Y29uZmlnLmJhc2VVcmx9Jyk7Cn0KCkZ1dHVyZTx2b2lkPiByZWdpc3Rlck5ldHdvcmtXaXRoREkoCiAgTmV0d29ya0NvbmZpZyBjb25maWcsIHsKICBib29sIHVzZUF1dGhlbnRpY2F0aW9uID0gdHJ1ZSwKfSkgYXN5bmMgewogIGZpbmFsIGxvZ2dlciA9IGRpLmdldDxMb2dnZXI+KCk7CgogIC8vIFRyeSB0byBnZXQgQXV0aFRva2VuUHJvdmlkZXIgZnJvbSBESSBpZiBhdXRoZW50aWNhdGlvbiBpcyBlbmFibGVkCiAgQXV0aFRva2VuUHJvdmlkZXI/IGF1dGhUb2tlblByb3ZpZGVyOwogIGlmICh1c2VBdXRoZW50aWNhdGlvbiAmJiBjb25maWcuYXV0aFRva2VuUHJvdmlkZXIgPT0gbnVsbCkgewogICAgdHJ5IHsKICAgICAgYXV0aFRva2VuUHJvdmlkZXIgPSBkaS5nZXQ8QXV0aFRva2VuUHJvdmlkZXI+KCk7CiAgICAgIGxvZ2dlci5kKCfwn5SQIEZvdW5kIEF1dGhUb2tlblByb3ZpZGVyIGluIERJLCB1c2luZyBmb3IgYXV0aGVudGljYXRpb24nKTsKICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgbG9nZ2VyLmQoCiAgICAgICAgJ/CflJMgTm8gQXV0aFRva2VuUHJvdmlkZXIgZm91bmQgaW4gREksIGNyZWF0aW5nIHVuYXV0aGVudGljYXRlZCBjbGllbnQnLAogICAgICApOwogICAgfQogIH0gZWxzZSBpZiAodXNlQXV0aGVudGljYXRpb24gJiYgY29uZmlnLmF1dGhUb2tlblByb3ZpZGVyICE9IG51bGwpIHsKICAgIGF1dGhUb2tlblByb3ZpZGVyID0gY29uZmlnLmF1dGhUb2tlblByb3ZpZGVyOwogICAgbG9nZ2VyLmQoJ/CflJAgVXNpbmcgcHJvdmlkZWQgQXV0aFRva2VuUHJvdmlkZXInKTsKICB9CgogIC8vIENyZWF0ZSBuZXR3b3JrIGNvbmZpZyB3aXRoIGF1dGggcHJvdmlkZXIgaWYgYXZhaWxhYmxlCiAgbGF0ZSBmaW5hbCBOZXR3b3JrQ29uZmlnIGZpbmFsQ29uZmlnOwogIGlmICghdXNlQXV0aGVudGljYXRpb24gfHwKICAgICAgKGF1dGhUb2tlblByb3ZpZGVyICE9IG51bGwgJiYgY29uZmlnLmF1dGhUb2tlblByb3ZpZGVyID09IG51bGwpKSB7CiAgICAvLyBDcmVhdGUgYSBuZXcgY29uZmlnIHdpdGggdGhlIGF1dGggcHJvdmlkZXIKICAgIGZpbmFsQ29uZmlnID0gRGVmYXVsdE5ldHdvcmtDb25maWcoCiAgICAgIGJhc2VVcmw6IGNvbmZpZy5iYXNlVXJsLAogICAgICBjb25uZWN0VGltZW91dDogY29uZmlnLmNvbm5lY3RUaW1lb3V0LAogICAgICByZWNlaXZlVGltZW91dDogY29uZmlnLnJlY2VpdmVUaW1lb3V0LAogICAgICBzZW5kVGltZW91dDogY29uZmlnLnNlbmRUaW1lb3V0LAogICAgICBkZWZhdWx0SGVhZGVyczogY29uZmlnLmRlZmF1bHRIZWFkZXJzLAogICAgICBlbmFibGVMb2dnaW5nOiBjb25maWcuZW5hYmxlTG9nZ2luZywKICAgICAgYXV0aFRva2VuUHJvdmlkZXI6IGF1dGhUb2tlblByb3ZpZGVyLAogICAgKTsKICB9IGVsc2UgewogICAgZmluYWxDb25maWcgPSBjb25maWc7CiAgfQoKICBmaW5hbCBuZXR3b3JrQ2xpZW50ID0gRGlvTmV0d29ya0NsaWVudChmaW5hbENvbmZpZywgbG9nZ2VyOiBsb2dnZXIpOwogIGRpLnJlZ2lzdGVyPE5ldHdvcmtDbGllbnQ+KAogICAgbmV0d29ya0NsaWVudCwKICAgIGRpc3Bvc2U6IChjbGllbnQpID0+IGNsaWVudC5kaXNwb3NlKCksCiAgKTsKICBkaS5yZWdpc3RlcjxOZXR3b3JrQ29uZmlnPihmaW5hbENvbmZpZyk7CgogIGlmIChmaW5hbENvbmZpZy5hdXRoVG9rZW5Qcm92aWRlciAhPSBudWxsKSB7CiAgICBsb2dnZXIuaSgn8J+UkCBOZXR3b3JrIGNsaWVudCByZWdpc3RlcmVkIHdpdGggYXV0aGVudGljYXRpb24gc3VwcG9ydCcpOwogIH0gZWxzZSB7CiAgICBsb2dnZXIuaSgn8J+UkyBOZXR3b3JrIGNsaWVudCByZWdpc3RlcmVkIHdpdGhvdXQgYXV0aGVudGljYXRpb24nKTsKICB9Cn0K", "type": "text" }, { @@ -1127,7 +1284,7 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "path": "{{ name.snakeCase() }}/packages/{{network_dir}}/lib/src/client/dio_network_client.dart", "data": - "aW1wb3J0ICdkYXJ0OmlvJzsKCmltcG9ydCAncGFja2FnZTpjb3JlL2NvcmUuZGFydCc7CmltcG9ydCAncGFja2FnZTpkaS9kaS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRpby9kaW8uZGFydCc7CmltcG9ydCAncGFja2FnZTpmbHV0dGVyL2ZvdW5kYXRpb24uZGFydCc7CmltcG9ydCAncGFja2FnZTpsb2NhbGl6YXRpb24vbG9jYWxpemF0aW9uLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6bmV0d29yay9zcmMvY2xpZW50L25ldHdvcmtfY2xpZW50LmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6bmV0d29yay9zcmMvY29uZmlnL25ldHdvcmtfY29uZmlnLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6bmV0d29yay9zcmMvZXhjZXB0aW9ucy9uZXR3b3JrX2V4Y2VwdGlvbnMuZGFydCc7CmltcG9ydCAncGFja2FnZTpuZXR3b3JrL3NyYy9pbnRlcmNlcHRvcnMvYXV0aF9pbnRlcmNlcHRvci5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOm5ldHdvcmsvc3JjL21vZGVscy9uZXR3b3JrX3Jlc3BvbnNlLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6dGFsa2VyX2Rpb19sb2dnZXIvdGFsa2VyX2Rpb19sb2dnZXIuZGFydCc7CmltcG9ydCAncGFja2FnZTp0YWxrZXJfZmx1dHRlci90YWxrZXJfZmx1dHRlci5kYXJ0JzsKCmNsYXNzIERpb05ldHdvcmtDbGllbnQgaW1wbGVtZW50cyBOZXR3b3JrQ2xpZW50IHsKICBEaW9OZXR3b3JrQ2xpZW50KHRoaXMuX2NvbmZpZykgOiBfZGlvID0gRGlvKCkgewogICAgX3NldHVwRGlvKCk7CiAgfQoKICBmaW5hbCBOZXR3b3JrQ29uZmlnIF9jb25maWc7CiAgZmluYWwgRGlvIF9kaW87CiAgZmluYWwgTG9nZ2VyIF9sb2dnZXIgPSBkaS5nZXQ8TG9nZ2VyPigpOwoKICB2b2lkIF9zZXR1cERpbygpIHsKICAgIF9kaW8ub3B0aW9ucyA9IEJhc2VPcHRpb25zKAogICAgICBiYXNlVXJsOiBfY29uZmlnLmJhc2VVcmwsCiAgICAgIGNvbm5lY3RUaW1lb3V0OiBfY29uZmlnLmNvbm5lY3RUaW1lb3V0LAogICAgICByZWNlaXZlVGltZW91dDogX2NvbmZpZy5yZWNlaXZlVGltZW91dCwKICAgICAgLy9zZW5kVGltZW91dCBjYW5ub3QgYmUgdXNlZCB3aXRob3V0IGEgcmVxdWVzdCBib2R5IHRvIHNlbmQgb24gV2ViCiAgICAgIHNlbmRUaW1lb3V0OiBrSXNXZWIgPyBudWxsIDogX2NvbmZpZy5zZW5kVGltZW91dCwKICAgICAgaGVhZGVyczogX2NvbmZpZy5kZWZhdWx0SGVhZGVycywKICAgICk7CgogICAgLy8gQWRkIGF1dGhlbnRpY2F0aW9uIGludGVyY2VwdG9yIGlmIHRva2VuIHByb3ZpZGVyIGlzIGF2YWlsYWJsZQogICAgaWYgKF9jb25maWcuYXV0aFRva2VuUHJvdmlkZXIgIT0gbnVsbCkgewogICAgICBfZGlvLmludGVyY2VwdG9ycy5hZGQoQXV0aEludGVyY2VwdG9yKF9jb25maWcuYXV0aFRva2VuUHJvdmlkZXIhKSk7CiAgICAgIF9sb2dnZXIuZCgn8J+UkCBBdXRoIGludGVyY2VwdG9yIGFkZGVkIHRvIG5ldHdvcmsgY2xpZW50Jyk7CiAgICB9CgogICAgaWYgKF9jb25maWcuZW5hYmxlTG9nZ2luZykgewogICAgICBfZGlvLmludGVyY2VwdG9ycy5hZGQoCiAgICAgICAgVGFsa2VyRGlvTG9nZ2VyKAogICAgICAgICAgdGFsa2VyOiBkaS5nZXQ8TG9nZ2VyPigpLmxvZ2dlciBhcyBUYWxrZXIsCiAgICAgICAgICBzZXR0aW5nczogVGFsa2VyRGlvTG9nZ2VyU2V0dGluZ3MoCiAgICAgICAgICAgIHByaW50UmVzcG9uc2VEYXRhOiB0cnVlLAogICAgICAgICAgICBwcmludFJlc3BvbnNlVGltZTogdHJ1ZSwKICAgICAgICAgICksCiAgICAgICAgKSwKICAgICAgKTsKICAgIH0KICB9CgogIEBvdmVycmlkZQogIEZ1dHVyZTxOZXR3b3JrUmVzcG9uc2U8VD4+IGdldDxUPigKICAgIFN0cmluZyBwYXRoLCB7CiAgICBNYXA8U3RyaW5nLCBkeW5hbWljPj8gcXVlcnlQYXJhbWV0ZXJzLAogICAgTWFwPFN0cmluZywgU3RyaW5nPj8gaGVhZGVycywKICAgIHJlcXVpcmVkIFQgRnVuY3Rpb24oT2JqZWN0PyBqc29uKSBmcm9tSnNvblQsCiAgfSkgYXN5bmMgewogICAgdHJ5IHsKICAgICAgZmluYWwgcmVzcG9uc2UgPSBhd2FpdCBfZGlvLmdldCgKICAgICAgICBwYXRoLAogICAgICAgIHF1ZXJ5UGFyYW1ldGVyczogcXVlcnlQYXJhbWV0ZXJzLAogICAgICAgIG9wdGlvbnM6IE9wdGlvbnMoaGVhZGVyczogaGVhZGVycyksCiAgICAgICk7CiAgICAgIHJldHVybiBfaGFuZGxlUmVzcG9uc2U8VD4ocmVzcG9uc2UsIGZyb21Kc29uVDogZnJvbUpzb25UKTsKICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgcmV0dXJuIF9oYW5kbGVFcnJvcjxUPihlKTsKICAgIH0KICB9CgogIEBvdmVycmlkZQogIEZ1dHVyZTxOZXR3b3JrUmVzcG9uc2U8VD4+IHBvc3Q8VD4oCiAgICBTdHJpbmcgcGF0aCwgewogICAgZHluYW1pYyBkYXRhLAogICAgTWFwPFN0cmluZywgZHluYW1pYz4/IHF1ZXJ5UGFyYW1ldGVycywKICAgIE1hcDxTdHJpbmcsIFN0cmluZz4/IGhlYWRlcnMsCiAgICByZXF1aXJlZCBUIEZ1bmN0aW9uKE9iamVjdD8ganNvbikgZnJvbUpzb25ULAogIH0pIGFzeW5jIHsKICAgIHRyeSB7CiAgICAgIGZpbmFsIHJlc3BvbnNlID0gYXdhaXQgX2Rpby5wb3N0KAogICAgICAgIHBhdGgsCiAgICAgICAgZGF0YTogZGF0YSwKICAgICAgICBxdWVyeVBhcmFtZXRlcnM6IHF1ZXJ5UGFyYW1ldGVycywKICAgICAgICBvcHRpb25zOiBPcHRpb25zKGhlYWRlcnM6IGhlYWRlcnMpLAogICAgICApOwogICAgICByZXR1cm4gX2hhbmRsZVJlc3BvbnNlPFQ+KHJlc3BvbnNlLCBmcm9tSnNvblQ6IGZyb21Kc29uVCk7CiAgICB9IGNhdGNoIChlKSB7CiAgICAgIHJldHVybiBfaGFuZGxlRXJyb3I8VD4oZSk7CiAgICB9CiAgfQoKICBAb3ZlcnJpZGUKICBGdXR1cmU8TmV0d29ya1Jlc3BvbnNlPFQ+PiBwdXQ8VD4oCiAgICBTdHJpbmcgcGF0aCwgewogICAgZHluYW1pYyBkYXRhLAogICAgTWFwPFN0cmluZywgZHluYW1pYz4/IHF1ZXJ5UGFyYW1ldGVycywKICAgIE1hcDxTdHJpbmcsIFN0cmluZz4/IGhlYWRlcnMsCiAgICByZXF1aXJlZCBUIEZ1bmN0aW9uKE9iamVjdD8ganNvbikgZnJvbUpzb25ULAogIH0pIGFzeW5jIHsKICAgIHRyeSB7CiAgICAgIGZpbmFsIHJlc3BvbnNlID0gYXdhaXQgX2Rpby5wdXQoCiAgICAgICAgcGF0aCwKICAgICAgICBkYXRhOiBkYXRhLAogICAgICAgIHF1ZXJ5UGFyYW1ldGVyczogcXVlcnlQYXJhbWV0ZXJzLAogICAgICAgIG9wdGlvbnM6IE9wdGlvbnMoaGVhZGVyczogaGVhZGVycyksCiAgICAgICk7CiAgICAgIHJldHVybiBfaGFuZGxlUmVzcG9uc2U8VD4ocmVzcG9uc2UsIGZyb21Kc29uVDogZnJvbUpzb25UKTsKICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgcmV0dXJuIF9oYW5kbGVFcnJvcjxUPihlKTsKICAgIH0KICB9CgogIEBvdmVycmlkZQogIEZ1dHVyZTxOZXR3b3JrUmVzcG9uc2U8VD4+IHBhdGNoPFQ+KAogICAgU3RyaW5nIHBhdGgsIHsKICAgIGR5bmFtaWMgZGF0YSwKICAgIE1hcDxTdHJpbmcsIGR5bmFtaWM+PyBxdWVyeVBhcmFtZXRlcnMsCiAgICBNYXA8U3RyaW5nLCBTdHJpbmc+PyBoZWFkZXJzLAogICAgcmVxdWlyZWQgVCBGdW5jdGlvbihPYmplY3Q/IGpzb24pIGZyb21Kc29uVCwKICB9KSBhc3luYyB7CiAgICB0cnkgewogICAgICBmaW5hbCByZXNwb25zZSA9IGF3YWl0IF9kaW8ucGF0Y2goCiAgICAgICAgcGF0aCwKICAgICAgICBkYXRhOiBkYXRhLAogICAgICAgIHF1ZXJ5UGFyYW1ldGVyczogcXVlcnlQYXJhbWV0ZXJzLAogICAgICAgIG9wdGlvbnM6IE9wdGlvbnMoaGVhZGVyczogaGVhZGVycyksCiAgICAgICk7CiAgICAgIHJldHVybiBfaGFuZGxlUmVzcG9uc2U8VD4ocmVzcG9uc2UsIGZyb21Kc29uVDogZnJvbUpzb25UKTsKICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgcmV0dXJuIF9oYW5kbGVFcnJvcjxUPihlKTsKICAgIH0KICB9CgogIEBvdmVycmlkZQogIEZ1dHVyZTxOZXR3b3JrUmVzcG9uc2U8VD4+IGRlbGV0ZTxUPigKICAgIFN0cmluZyBwYXRoLCB7CiAgICBkeW5hbWljIGRhdGEsCiAgICBNYXA8U3RyaW5nLCBkeW5hbWljPj8gcXVlcnlQYXJhbWV0ZXJzLAogICAgTWFwPFN0cmluZywgU3RyaW5nPj8gaGVhZGVycywKICAgIHJlcXVpcmVkIFQgRnVuY3Rpb24oT2JqZWN0PyBqc29uKSBmcm9tSnNvblQsCiAgfSkgYXN5bmMgewogICAgdHJ5IHsKICAgICAgZmluYWwgcmVzcG9uc2UgPSBhd2FpdCBfZGlvLmRlbGV0ZSgKICAgICAgICBwYXRoLAogICAgICAgIGRhdGE6IGRhdGEsCiAgICAgICAgcXVlcnlQYXJhbWV0ZXJzOiBxdWVyeVBhcmFtZXRlcnMsCiAgICAgICAgb3B0aW9uczogT3B0aW9ucyhoZWFkZXJzOiBoZWFkZXJzKSwKICAgICAgKTsKICAgICAgcmV0dXJuIF9oYW5kbGVSZXNwb25zZTxUPihyZXNwb25zZSwgZnJvbUpzb25UOiBmcm9tSnNvblQpOwogICAgfSBjYXRjaCAoZSkgewogICAgICByZXR1cm4gX2hhbmRsZUVycm9yPFQ+KGUpOwogICAgfQogIH0KCiAgTmV0d29ya1Jlc3BvbnNlPFQ+IF9oYW5kbGVSZXNwb25zZTxUPigKICAgIFJlc3BvbnNlIHJlc3BvbnNlLCB7CiAgICByZXF1aXJlZCBUIEZ1bmN0aW9uKE9iamVjdD8ganNvbikgZnJvbUpzb25ULAogIH0pIHsKICAgIHRyeSB7CiAgICAgIGlmIChyZXNwb25zZS5kYXRhIGlzIE1hcDxTdHJpbmcsIGR5bmFtaWM+KSB7CiAgICAgICAgZmluYWwgcmVzcG9uc2VEYXRhID0gcmVzcG9uc2UuZGF0YSBhcyBNYXA8U3RyaW5nLCBkeW5hbWljPjsKCiAgICAgICAgaWYgKHJlc3BvbnNlRGF0YS5jb250YWluc0tleSgnc3VjY2VzcycpKSB7CiAgICAgICAgICBpZiAocmVzcG9uc2VEYXRhWydzdWNjZXNzJ10gPT0gdHJ1ZSkgewogICAgICAgICAgICByZXR1cm4gU3VjY2Vzc1Jlc3BvbnNlLmZyb21Kc29uKHsKICAgICAgICAgICAgICAnc3RhdHVzQ29kZSc6IHJlc3BvbnNlLnN0YXR1c0NvZGUgPz8gMjAwLAogICAgICAgICAgICAgICdoZWFkZXJzJzogcmVzcG9uc2UuaGVhZGVycy5tYXAsCiAgICAgICAgICAgICAgLi4ucmVzcG9uc2VEYXRhLAogICAgICAgICAgICB9LCBmcm9tSnNvblQpOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgRXJyb3JSZXNwb25zZS5mcm9tSnNvbih7CiAgICAgICAgICAgICAgJ3N0YXR1c0NvZGUnOiByZXNwb25zZS5zdGF0dXNDb2RlID8/IDUwMCwKICAgICAgICAgICAgICAnaGVhZGVycyc6IHJlc3BvbnNlLmhlYWRlcnMubWFwLAogICAgICAgICAgICAgIC4uLnJlc3BvbnNlRGF0YSwKICAgICAgICAgICAgfSk7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9CgogICAgICAvLyBJZGVhbGx5LCBzaG91bGQgbm90IHJlYWNoIGhlcmUgaWYgdGhlIEFQSSBmb2xsb3dzIHRoZQogICAgICAvLyBzdGFuZGFyZCByZXNwb25zZSBmb3JtYXQKICAgICAgX2xvZ2dlci53KCdJbnZhbGlkIHJlc3BvbnNlIGZvcm1hdDogJHtyZXNwb25zZS5kYXRhfScpOwoKICAgICAgLy8gRmFsbGJhY2sgdG8gYSBnZW5lcmljIHN1Y2Nlc3MgcmVzcG9uc2UKICAgICAgcmV0dXJuIFN1Y2Nlc3NSZXNwb25zZS5mcm9tSnNvbih7CiAgICAgICAgJ3N0YXR1c0NvZGUnOiByZXNwb25zZS5zdGF0dXNDb2RlID8/IDIwMCwKICAgICAgICAnaGVhZGVycyc6IHJlc3BvbnNlLmhlYWRlcnMubWFwLAogICAgICAgICdkYXRhJzogcmVzcG9uc2UuZGF0YSwKICAgICAgfSwgKHZhbHVlKSA9PiB2YWx1ZSBhcyBUKTsKICAgIH0gY2F0Y2ggKGUsIHMpIHsKICAgICAgX2xvZ2dlci5lKCdFcnJvciBwYXJzaW5nIHJlc3BvbnNlJywgZSk7CiAgICAgIHJldHVybiBFcnJvclJlc3BvbnNlKAogICAgICAgIHN0YXR1c0NvZGU6IHJlc3BvbnNlLnN0YXR1c0NvZGUgPz8gNTAwLAogICAgICAgIHN1Y2Nlc3M6IGZhbHNlLAogICAgICAgIG1lc3NhZ2U6ICdOZXR3b3JrIENsaWVudCBmYWlsZWQgdG8gcGFyc2UgcmVzcG9uc2UhJywKICAgICAgICBlcnJvcjogRXJyb3JEZXRhaWxzKAogICAgICAgICAgY29kZTogJ1BBUlNFX0VSUk9SJywKICAgICAgICAgIG1lc3NhZ2U6IGUudG9TdHJpbmcoKSwKICAgICAgICAgIGRldGFpbHM6IHsnc3RhY2tUcmFjZSc6IHMudG9TdHJpbmcoKX0sCiAgICAgICAgKSwKICAgICAgICB0aW1lc3RhbXA6IERhdGVUaW1lLm5vdygpLnRvSXNvODYwMVN0cmluZygpLAogICAgICApOwogICAgfQogIH0KCiAgTmV0d29ya1Jlc3BvbnNlPFQ+IF9oYW5kbGVFcnJvcjxUPihkeW5hbWljIGVycm9yKSB7CiAgICBOZXR3b3JrRXhjZXB0aW9uIG5ldHdvcmtFeGNlcHRpb247CiAgICBFcnJvclJlc3BvbnNlPyBhcGlFcnJvcjsKCiAgICBpZiAoZXJyb3IgaXMgRGlvRXhjZXB0aW9uKSB7CiAgICAgIGFwaUVycm9yID0gX3BhcnNlQXBpRXJyb3IoZXJyb3IucmVzcG9uc2UpOwogICAgICBuZXR3b3JrRXhjZXB0aW9uID0gX21hcERpb0V4Y2VwdGlvbihlcnJvciwgYXBpRXJyb3IpOwogICAgfSBlbHNlIHsKICAgICAgbmV0d29ya0V4Y2VwdGlvbiA9IFVua25vd25OZXR3b3JrRXhjZXB0aW9uKG1lc3NhZ2U6IGVycm9yLnRvU3RyaW5nKCkpOwogICAgfQoKICAgIF9sb2dnZXIuZSgnTmV0d29yayBlcnJvciBvY2N1cnJlZCcsIG5ldHdvcmtFeGNlcHRpb24pOwoKICAgIHRocm93IG5ldHdvcmtFeGNlcHRpb247CiAgfQoKICBFcnJvclJlc3BvbnNlPyBfcGFyc2VBcGlFcnJvcihSZXNwb25zZT8gcmVzcG9uc2UpIHsKICAgIHRyeSB7CiAgICAgIGZpbmFsIHJlc3BvbnNlRGF0YSA9IHJlc3BvbnNlPy5kYXRhOwogICAgICBpZiAocmVzcG9uc2VEYXRhIGlzIE1hcDxTdHJpbmcsIGR5bmFtaWM+ICYmCiAgICAgICAgICByZXNwb25zZURhdGEuY29udGFpbnNLZXkoJ3N1Y2Nlc3MnKSAmJgogICAgICAgICAgcmVzcG9uc2VEYXRhWydzdWNjZXNzJ10gPT0gZmFsc2UpIHsKICAgICAgICByZXR1cm4gRXJyb3JSZXNwb25zZS5mcm9tSnNvbih7CiAgICAgICAgICAnc3RhdHVzQ29kZSc6IHJlc3BvbnNlPy5zdGF0dXNDb2RlID8/IDUwMCwKICAgICAgICAgICdoZWFkZXJzJzogcmVzcG9uc2U/LmhlYWRlcnMubWFwLAogICAgICAgICAgLi4ucmVzcG9uc2VEYXRhLAogICAgICAgIH0pOwogICAgICB9CiAgICB9IGNhdGNoIChlKSB7CiAgICAgIF9sb2dnZXIudygnRmFpbGVkIHRvIHBhcnNlIEFQSSBlcnJvcjogJGUnKTsKICAgIH0KICAgIHJldHVybiBudWxsOwogIH0KCiAgTmV0d29ya0V4Y2VwdGlvbiBfbWFwRGlvRXhjZXB0aW9uKAogICAgRGlvRXhjZXB0aW9uIGRpb0V4Y2VwdGlvbiwKICAgIEVycm9yUmVzcG9uc2U/IGFwaUVycm9yLAogICkgewogICAgZmluYWwgbWVzc2FnZSA9IGFwaUVycm9yPy5lcnJvci5tZXNzYWdlOwoKICAgIHN3aXRjaCAoZGlvRXhjZXB0aW9uLnR5cGUpIHsKICAgICAgY2FzZSBEaW9FeGNlcHRpb25UeXBlLmNvbm5lY3Rpb25UaW1lb3V0OgogICAgICAgIHJldHVybiBDb25uZWN0aW9uVGltZW91dEV4Y2VwdGlvbihtZXNzYWdlOiBtZXNzYWdlKTsKICAgICAgY2FzZSBEaW9FeGNlcHRpb25UeXBlLnJlY2VpdmVUaW1lb3V0OgogICAgICAgIHJldHVybiBSZWNlaXZlVGltZW91dEV4Y2VwdGlvbihtZXNzYWdlOiBtZXNzYWdlKTsKICAgICAgY2FzZSBEaW9FeGNlcHRpb25UeXBlLnNlbmRUaW1lb3V0OgogICAgICAgIHJldHVybiBTZW5kVGltZW91dEV4Y2VwdGlvbihtZXNzYWdlOiBtZXNzYWdlKTsKICAgICAgY2FzZSBEaW9FeGNlcHRpb25UeXBlLmNvbm5lY3Rpb25FcnJvcjoKICAgICAgICBpZiAoZGlvRXhjZXB0aW9uLmVycm9yIGlzIFNvY2tldEV4Y2VwdGlvbikgewogICAgICAgICAgcmV0dXJuIE5vSW50ZXJuZXRDb25uZWN0aW9uRXhjZXB0aW9uKG1lc3NhZ2U6IG1lc3NhZ2UpOwogICAgICAgIH0KICAgICAgICByZXR1cm4gVW5rbm93bk5ldHdvcmtFeGNlcHRpb24obWVzc2FnZTogbWVzc2FnZSk7CiAgICAgIGNhc2UgRGlvRXhjZXB0aW9uVHlwZS5iYWRSZXNwb25zZToKICAgICAgICBmaW5hbCBzdGF0dXNDb2RlID0gZGlvRXhjZXB0aW9uLnJlc3BvbnNlPy5zdGF0dXNDb2RlOwogICAgICAgIHN3aXRjaCAoc3RhdHVzQ29kZSkgewogICAgICAgICAgY2FzZSA0MDA6CiAgICAgICAgICAgIHJldHVybiBCYWRSZXF1ZXN0RXhjZXB0aW9uKG1lc3NhZ2U6IG1lc3NhZ2UsIGVycm9yOiBhcGlFcnJvcik7CiAgICAgICAgICBjYXNlIDQwMToKICAgICAgICAgICAgcmV0dXJuIFVuYXV0aG9yaXplZEV4Y2VwdGlvbihtZXNzYWdlOiBtZXNzYWdlLCBlcnJvcjogYXBpRXJyb3IpOwogICAgICAgICAgY2FzZSA0MDM6CiAgICAgICAgICAgIHJldHVybiBGb3JiaWRkZW5FeGNlcHRpb24obWVzc2FnZTogbWVzc2FnZSwgZXJyb3I6IGFwaUVycm9yKTsKICAgICAgICAgIGNhc2UgNDA0OgogICAgICAgICAgICByZXR1cm4gTm90Rm91bmRFeGNlcHRpb24obWVzc2FnZTogbWVzc2FnZSwgZXJyb3I6IGFwaUVycm9yKTsKICAgICAgICAgIGNhc2UgNDA5OgogICAgICAgICAgICByZXR1cm4gQ29uZmxpY3RFeGNlcHRpb24obWVzc2FnZTogbWVzc2FnZSwgZXJyb3I6IGFwaUVycm9yKTsKICAgICAgICAgIGNhc2UgNDIyOgogICAgICAgICAgICByZXR1cm4gVW5wcm9jZXNzYWJsZUVudGl0eUV4Y2VwdGlvbigKICAgICAgICAgICAgICBtZXNzYWdlOiBtZXNzYWdlLAogICAgICAgICAgICAgIGVycm9yOiBhcGlFcnJvciwKICAgICAgICAgICAgKTsKICAgICAgICAgIGNhc2UgNTAwOgogICAgICAgICAgY2FzZSA1MDI6CiAgICAgICAgICBjYXNlIDUwMzoKICAgICAgICAgIGNhc2UgNTA0OgogICAgICAgICAgICByZXR1cm4gSW50ZXJuYWxTZXJ2ZXJFeGNlcHRpb24obWVzc2FnZTogbWVzc2FnZSwgZXJyb3I6IGFwaUVycm9yKTsKICAgICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICAgIHJldHVybiBVbmtub3duTmV0d29ya0V4Y2VwdGlvbigKICAgICAgICAgICAgICBtZXNzYWdlOiBtZXNzYWdlLAogICAgICAgICAgICAgIHN0YXR1c0NvZGU6IHN0YXR1c0NvZGUsCiAgICAgICAgICAgICAgZXJyb3I6IGFwaUVycm9yLAogICAgICAgICAgICApOwogICAgICAgIH0KICAgICAgZGVmYXVsdDoKICAgICAgICByZXR1cm4gVW5rbm93bk5ldHdvcmtFeGNlcHRpb24obWVzc2FnZTogbWVzc2FnZSwgZXJyb3I6IGFwaUVycm9yKTsKICAgIH0KICB9CgogIEBvdmVycmlkZQogIFQgaGFuZGxlUmVzcG9uc2U8VD4oZmluYWwgTmV0d29ya1Jlc3BvbnNlPFQ+IHJlc3BvbnNlKSB7CiAgICBzd2l0Y2ggKHJlc3BvbnNlKSB7CiAgICAgIGNhc2UgU3VjY2Vzc1Jlc3BvbnNlPFQ+KCk6CiAgICAgICAgcmV0dXJuIHJlc3BvbnNlLmRhdGEhOwogICAgICBjYXNlIEVycm9yUmVzcG9uc2U8VD4oKToKICAgICAgICB0aHJvdyBVbmtub3duTmV0d29ya0V4Y2VwdGlvbigKICAgICAgICAgIG1lc3NhZ2U6IHJlc3BvbnNlLm1lc3NhZ2UgPz8gc3RyaW5ncy5lcnJvcnMubmV0d29ya19lcnJvciwKICAgICAgICAgIHN0YXR1c0NvZGU6IHJlc3BvbnNlLnN0YXR1c0NvZGUsCiAgICAgICAgICBlcnJvcjogcmVzcG9uc2UsCiAgICAgICAgKTsKICAgICAgZGVmYXVsdDoKICAgICAgICB0aHJvdyBVbmtub3duTmV0d29ya0V4Y2VwdGlvbigKICAgICAgICAgIG1lc3NhZ2U6IHN0cmluZ3MuZXJyb3JzLnVua25vd25fZXJyb3IsCiAgICAgICAgICBzdGF0dXNDb2RlOiByZXNwb25zZS5zdGF0dXNDb2RlLAogICAgICAgICk7CiAgICB9CiAgfQoKICBAb3ZlcnJpZGUKICBTdWNjZXNzUmVzcG9uc2U8VD4gaGFuZGxlU3VjY2Vzc1Jlc3BvbnNlPFQ+KAogICAgZmluYWwgTmV0d29ya1Jlc3BvbnNlPFQ+IHJlc3BvbnNlLAogICkgewogICAgc3dpdGNoIChyZXNwb25zZSkgewogICAgICBjYXNlIFN1Y2Nlc3NSZXNwb25zZTxUPigpOgogICAgICAgIHJldHVybiByZXNwb25zZTsKICAgICAgY2FzZSBFcnJvclJlc3BvbnNlPFQ+KCk6CiAgICAgICAgdGhyb3cgVW5rbm93bk5ldHdvcmtFeGNlcHRpb24oCiAgICAgICAgICBtZXNzYWdlOiByZXNwb25zZS5tZXNzYWdlID8/IHN0cmluZ3MuZXJyb3JzLm5ldHdvcmtfZXJyb3IsCiAgICAgICAgICBzdGF0dXNDb2RlOiByZXNwb25zZS5zdGF0dXNDb2RlLAogICAgICAgICAgZXJyb3I6IHJlc3BvbnNlLAogICAgICAgICk7CiAgICAgIGRlZmF1bHQ6CiAgICAgICAgdGhyb3cgVW5rbm93bk5ldHdvcmtFeGNlcHRpb24oCiAgICAgICAgICBtZXNzYWdlOiBzdHJpbmdzLmVycm9ycy51bmtub3duX2Vycm9yLAogICAgICAgICAgc3RhdHVzQ29kZTogcmVzcG9uc2Uuc3RhdHVzQ29kZSwKICAgICAgICApOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgdm9pZCBkaXNwb3NlKCkgewogICAgX2Rpby5jbG9zZSgpOwogIH0KfQo=", + "aW1wb3J0ICdkYXJ0OmlvJzsKCmltcG9ydCAncGFja2FnZTpjb3JlL2NvcmUuZGFydCc7CmltcG9ydCAncGFja2FnZTpkaW8vZGlvLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlci9mb3VuZGF0aW9uLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6bG9jYWxpemF0aW9uL2xvY2FsaXphdGlvbi5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOm5ldHdvcmsvc3JjL2NsaWVudC9uZXR3b3JrX2NsaWVudC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOm5ldHdvcmsvc3JjL2NvbmZpZy9uZXR3b3JrX2NvbmZpZy5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOm5ldHdvcmsvc3JjL2V4Y2VwdGlvbnMvbmV0d29ya19leGNlcHRpb25zLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6bmV0d29yay9zcmMvaW50ZXJjZXB0b3JzL2F1dGhfaW50ZXJjZXB0b3IuZGFydCc7CmltcG9ydCAncGFja2FnZTpuZXR3b3JrL3NyYy9tb2RlbHMvbmV0d29ya19yZXNwb25zZS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOm5ldHdvcmsvc3JjL2ludGVyY2VwdG9ycy9sb2dnaW5nX2ludGVyY2VwdG9yLmRhcnQnOwoKY2xhc3MgRGlvTmV0d29ya0NsaWVudCBpbXBsZW1lbnRzIE5ldHdvcmtDbGllbnQgewogIERpb05ldHdvcmtDbGllbnQodGhpcy5fY29uZmlnLCB7cmVxdWlyZWQgTG9nZ2VyIGxvZ2dlciwgRGlvPyBkaW99KQogICAgOiBfbG9nZ2VyID0gbG9nZ2VyLAogICAgICBfZGlvID0gZGlvID8/IERpbygpIHsKICAgIF9zZXR1cERpbygpOwogIH0KCiAgZmluYWwgTmV0d29ya0NvbmZpZyBfY29uZmlnOwogIGZpbmFsIERpbyBfZGlvOwogIGZpbmFsIExvZ2dlciBfbG9nZ2VyOwoKICB2b2lkIF9zZXR1cERpbygpIHsKICAgIF9kaW8ub3B0aW9ucyA9IEJhc2VPcHRpb25zKAogICAgICBiYXNlVXJsOiBfY29uZmlnLmJhc2VVcmwsCiAgICAgIGNvbm5lY3RUaW1lb3V0OiBfY29uZmlnLmNvbm5lY3RUaW1lb3V0LAogICAgICByZWNlaXZlVGltZW91dDogX2NvbmZpZy5yZWNlaXZlVGltZW91dCwKICAgICAgLy9zZW5kVGltZW91dCBjYW5ub3QgYmUgdXNlZCB3aXRob3V0IGEgcmVxdWVzdCBib2R5IHRvIHNlbmQgb24gV2ViCiAgICAgIHNlbmRUaW1lb3V0OiBrSXNXZWIgPyBudWxsIDogX2NvbmZpZy5zZW5kVGltZW91dCwKICAgICAgaGVhZGVyczogX2NvbmZpZy5kZWZhdWx0SGVhZGVycywKICAgICk7CgogICAgLy8gQWRkIGF1dGhlbnRpY2F0aW9uIGludGVyY2VwdG9yIGlmIHRva2VuIHByb3ZpZGVyIGlzIGF2YWlsYWJsZQogICAgaWYgKF9jb25maWcuYXV0aFRva2VuUHJvdmlkZXIgIT0gbnVsbCkgewogICAgICBfZGlvLmludGVyY2VwdG9ycy5hZGQoCiAgICAgICAgQXV0aEludGVyY2VwdG9yKF9jb25maWcuYXV0aFRva2VuUHJvdmlkZXIhLCBkaW86IF9kaW8sIGxvZ2dlcjogX2xvZ2dlciksCiAgICAgICk7CiAgICAgIF9sb2dnZXIuZCgn8J+UkCBBdXRoIGludGVyY2VwdG9yIGFkZGVkIHRvIG5ldHdvcmsgY2xpZW50Jyk7CiAgICB9CgogICAgaWYgKF9jb25maWcuZW5hYmxlTG9nZ2luZykgewogICAgICBfZGlvLmludGVyY2VwdG9ycy5hZGQoTG9nZ2luZ0ludGVyY2VwdG9yKGxvZ2dlcjogX2xvZ2dlcikpOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPE5ldHdvcmtSZXNwb25zZTxUPj4gZ2V0PFQ+KAogICAgU3RyaW5nIHBhdGgsIHsKICAgIE1hcDxTdHJpbmcsIGR5bmFtaWM+PyBxdWVyeVBhcmFtZXRlcnMsCiAgICBNYXA8U3RyaW5nLCBTdHJpbmc+PyBoZWFkZXJzLAogICAgcmVxdWlyZWQgVCBGdW5jdGlvbihPYmplY3Q/IGpzb24pIGZyb21Kc29uVCwKICB9KSBhc3luYyB7CiAgICB0cnkgewogICAgICBmaW5hbCByZXNwb25zZSA9IGF3YWl0IF9kaW8uZ2V0KAogICAgICAgIHBhdGgsCiAgICAgICAgcXVlcnlQYXJhbWV0ZXJzOiBxdWVyeVBhcmFtZXRlcnMsCiAgICAgICAgb3B0aW9uczogT3B0aW9ucyhoZWFkZXJzOiBoZWFkZXJzKSwKICAgICAgKTsKICAgICAgcmV0dXJuIF9oYW5kbGVSZXNwb25zZTxUPihyZXNwb25zZSwgZnJvbUpzb25UOiBmcm9tSnNvblQpOwogICAgfSBjYXRjaCAoZSkgewogICAgICByZXR1cm4gX2hhbmRsZUVycm9yPFQ+KGUpOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPE5ldHdvcmtSZXNwb25zZTxUPj4gcG9zdDxUPigKICAgIFN0cmluZyBwYXRoLCB7CiAgICBkeW5hbWljIGRhdGEsCiAgICBNYXA8U3RyaW5nLCBkeW5hbWljPj8gcXVlcnlQYXJhbWV0ZXJzLAogICAgTWFwPFN0cmluZywgU3RyaW5nPj8gaGVhZGVycywKICAgIHJlcXVpcmVkIFQgRnVuY3Rpb24oT2JqZWN0PyBqc29uKSBmcm9tSnNvblQsCiAgfSkgYXN5bmMgewogICAgdHJ5IHsKICAgICAgZmluYWwgcmVzcG9uc2UgPSBhd2FpdCBfZGlvLnBvc3QoCiAgICAgICAgcGF0aCwKICAgICAgICBkYXRhOiBkYXRhLAogICAgICAgIHF1ZXJ5UGFyYW1ldGVyczogcXVlcnlQYXJhbWV0ZXJzLAogICAgICAgIG9wdGlvbnM6IE9wdGlvbnMoaGVhZGVyczogaGVhZGVycyksCiAgICAgICk7CiAgICAgIHJldHVybiBfaGFuZGxlUmVzcG9uc2U8VD4ocmVzcG9uc2UsIGZyb21Kc29uVDogZnJvbUpzb25UKTsKICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgcmV0dXJuIF9oYW5kbGVFcnJvcjxUPihlKTsKICAgIH0KICB9CgogIEBvdmVycmlkZQogIEZ1dHVyZTxOZXR3b3JrUmVzcG9uc2U8VD4+IHB1dDxUPigKICAgIFN0cmluZyBwYXRoLCB7CiAgICBkeW5hbWljIGRhdGEsCiAgICBNYXA8U3RyaW5nLCBkeW5hbWljPj8gcXVlcnlQYXJhbWV0ZXJzLAogICAgTWFwPFN0cmluZywgU3RyaW5nPj8gaGVhZGVycywKICAgIHJlcXVpcmVkIFQgRnVuY3Rpb24oT2JqZWN0PyBqc29uKSBmcm9tSnNvblQsCiAgfSkgYXN5bmMgewogICAgdHJ5IHsKICAgICAgZmluYWwgcmVzcG9uc2UgPSBhd2FpdCBfZGlvLnB1dCgKICAgICAgICBwYXRoLAogICAgICAgIGRhdGE6IGRhdGEsCiAgICAgICAgcXVlcnlQYXJhbWV0ZXJzOiBxdWVyeVBhcmFtZXRlcnMsCiAgICAgICAgb3B0aW9uczogT3B0aW9ucyhoZWFkZXJzOiBoZWFkZXJzKSwKICAgICAgKTsKICAgICAgcmV0dXJuIF9oYW5kbGVSZXNwb25zZTxUPihyZXNwb25zZSwgZnJvbUpzb25UOiBmcm9tSnNvblQpOwogICAgfSBjYXRjaCAoZSkgewogICAgICByZXR1cm4gX2hhbmRsZUVycm9yPFQ+KGUpOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPE5ldHdvcmtSZXNwb25zZTxUPj4gcGF0Y2g8VD4oCiAgICBTdHJpbmcgcGF0aCwgewogICAgZHluYW1pYyBkYXRhLAogICAgTWFwPFN0cmluZywgZHluYW1pYz4/IHF1ZXJ5UGFyYW1ldGVycywKICAgIE1hcDxTdHJpbmcsIFN0cmluZz4/IGhlYWRlcnMsCiAgICByZXF1aXJlZCBUIEZ1bmN0aW9uKE9iamVjdD8ganNvbikgZnJvbUpzb25ULAogIH0pIGFzeW5jIHsKICAgIHRyeSB7CiAgICAgIGZpbmFsIHJlc3BvbnNlID0gYXdhaXQgX2Rpby5wYXRjaCgKICAgICAgICBwYXRoLAogICAgICAgIGRhdGE6IGRhdGEsCiAgICAgICAgcXVlcnlQYXJhbWV0ZXJzOiBxdWVyeVBhcmFtZXRlcnMsCiAgICAgICAgb3B0aW9uczogT3B0aW9ucyhoZWFkZXJzOiBoZWFkZXJzKSwKICAgICAgKTsKICAgICAgcmV0dXJuIF9oYW5kbGVSZXNwb25zZTxUPihyZXNwb25zZSwgZnJvbUpzb25UOiBmcm9tSnNvblQpOwogICAgfSBjYXRjaCAoZSkgewogICAgICByZXR1cm4gX2hhbmRsZUVycm9yPFQ+KGUpOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPE5ldHdvcmtSZXNwb25zZTxUPj4gZGVsZXRlPFQ+KAogICAgU3RyaW5nIHBhdGgsIHsKICAgIGR5bmFtaWMgZGF0YSwKICAgIE1hcDxTdHJpbmcsIGR5bmFtaWM+PyBxdWVyeVBhcmFtZXRlcnMsCiAgICBNYXA8U3RyaW5nLCBTdHJpbmc+PyBoZWFkZXJzLAogICAgcmVxdWlyZWQgVCBGdW5jdGlvbihPYmplY3Q/IGpzb24pIGZyb21Kc29uVCwKICB9KSBhc3luYyB7CiAgICB0cnkgewogICAgICBmaW5hbCByZXNwb25zZSA9IGF3YWl0IF9kaW8uZGVsZXRlKAogICAgICAgIHBhdGgsCiAgICAgICAgZGF0YTogZGF0YSwKICAgICAgICBxdWVyeVBhcmFtZXRlcnM6IHF1ZXJ5UGFyYW1ldGVycywKICAgICAgICBvcHRpb25zOiBPcHRpb25zKGhlYWRlcnM6IGhlYWRlcnMpLAogICAgICApOwogICAgICByZXR1cm4gX2hhbmRsZVJlc3BvbnNlPFQ+KHJlc3BvbnNlLCBmcm9tSnNvblQ6IGZyb21Kc29uVCk7CiAgICB9IGNhdGNoIChlKSB7CiAgICAgIHJldHVybiBfaGFuZGxlRXJyb3I8VD4oZSk7CiAgICB9CiAgfQoKICBOZXR3b3JrUmVzcG9uc2U8VD4gX2hhbmRsZVJlc3BvbnNlPFQ+KAogICAgUmVzcG9uc2UgcmVzcG9uc2UsIHsKICAgIHJlcXVpcmVkIFQgRnVuY3Rpb24oT2JqZWN0PyBqc29uKSBmcm9tSnNvblQsCiAgfSkgewogICAgdHJ5IHsKICAgICAgaWYgKHJlc3BvbnNlLmRhdGEgaXMgTWFwPFN0cmluZywgZHluYW1pYz4pIHsKICAgICAgICBmaW5hbCByZXNwb25zZURhdGEgPSByZXNwb25zZS5kYXRhIGFzIE1hcDxTdHJpbmcsIGR5bmFtaWM+OwoKICAgICAgICBpZiAocmVzcG9uc2VEYXRhLmNvbnRhaW5zS2V5KCdzdWNjZXNzJykpIHsKICAgICAgICAgIGlmIChyZXNwb25zZURhdGFbJ3N1Y2Nlc3MnXSA9PSB0cnVlKSB7CiAgICAgICAgICAgIHJldHVybiBTdWNjZXNzUmVzcG9uc2UuZnJvbUpzb24oewogICAgICAgICAgICAgIC4uLnJlc3BvbnNlRGF0YSwKICAgICAgICAgICAgICAnc3RhdHVzQ29kZSc6IHJlc3BvbnNlLnN0YXR1c0NvZGUgPz8gMjAwLAogICAgICAgICAgICAgICdoZWFkZXJzJzogcmVzcG9uc2UuaGVhZGVycy5tYXAsCiAgICAgICAgICAgIH0sIGZyb21Kc29uVCk7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICByZXR1cm4gRXJyb3JSZXNwb25zZTxUPi5mcm9tSnNvbih7CiAgICAgICAgICAgICAgLi4ucmVzcG9uc2VEYXRhLAogICAgICAgICAgICAgICdzdGF0dXNDb2RlJzogcmVzcG9uc2Uuc3RhdHVzQ29kZSA/PyA1MDAsCiAgICAgICAgICAgICAgJ2hlYWRlcnMnOiByZXNwb25zZS5oZWFkZXJzLm1hcCwKICAgICAgICAgICAgfSk7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9CgogICAgICAvLyBJZGVhbGx5LCBzaG91bGQgbm90IHJlYWNoIGhlcmUgaWYgdGhlIEFQSSBmb2xsb3dzIHRoZQogICAgICAvLyBzdGFuZGFyZCByZXNwb25zZSBmb3JtYXQKICAgICAgX2xvZ2dlci5kKCdEZWNvZGluZyByZXNwb25zZSB3aXRob3V0IGFuIEFQSSBlbnZlbG9wZScpOwoKICAgICAgLy8gRmFsbGJhY2sgdG8gYSBnZW5lcmljIHN1Y2Nlc3MgcmVzcG9uc2UKICAgICAgcmV0dXJuIFN1Y2Nlc3NSZXNwb25zZTxUPigKICAgICAgICBzdGF0dXNDb2RlOiByZXNwb25zZS5zdGF0dXNDb2RlID8/IDIwMCwKICAgICAgICBoZWFkZXJzOiByZXNwb25zZS5oZWFkZXJzLm1hcCwKICAgICAgICBzdWNjZXNzOiB0cnVlLAogICAgICAgIHRpbWVzdGFtcDogRGF0ZVRpbWUubm93KCkudG9Jc284NjAxU3RyaW5nKCksCiAgICAgICAgZGF0YTogZnJvbUpzb25UKHJlc3BvbnNlLmRhdGEpLAogICAgICApOwogICAgfSBjYXRjaCAoZSwgcykgewogICAgICBfbG9nZ2VyLmUoJ0Vycm9yIHBhcnNpbmcgcmVzcG9uc2UnLCBlKTsKICAgICAgcmV0dXJuIEVycm9yUmVzcG9uc2UoCiAgICAgICAgc3RhdHVzQ29kZTogcmVzcG9uc2Uuc3RhdHVzQ29kZSA/PyA1MDAsCiAgICAgICAgc3VjY2VzczogZmFsc2UsCiAgICAgICAgbWVzc2FnZTogJ05ldHdvcmsgQ2xpZW50IGZhaWxlZCB0byBwYXJzZSByZXNwb25zZSEnLAogICAgICAgIGVycm9yOiBFcnJvckRldGFpbHMoCiAgICAgICAgICBjb2RlOiAnUEFSU0VfRVJST1InLAogICAgICAgICAgbWVzc2FnZTogZS50b1N0cmluZygpLAogICAgICAgICAgZGV0YWlsczogeydzdGFja1RyYWNlJzogcy50b1N0cmluZygpfSwKICAgICAgICApLAogICAgICAgIHRpbWVzdGFtcDogRGF0ZVRpbWUubm93KCkudG9Jc284NjAxU3RyaW5nKCksCiAgICAgICk7CiAgICB9CiAgfQoKICBOZXR3b3JrUmVzcG9uc2U8VD4gX2hhbmRsZUVycm9yPFQ+KGR5bmFtaWMgZXJyb3IpIHsKICAgIE5ldHdvcmtFeGNlcHRpb24gbmV0d29ya0V4Y2VwdGlvbjsKICAgIEVycm9yUmVzcG9uc2U/IGFwaUVycm9yOwoKICAgIGlmIChlcnJvciBpcyBEaW9FeGNlcHRpb24pIHsKICAgICAgYXBpRXJyb3IgPSBfcGFyc2VBcGlFcnJvcihlcnJvci5yZXNwb25zZSk7CiAgICAgIG5ldHdvcmtFeGNlcHRpb24gPSBfbWFwRGlvRXhjZXB0aW9uKGVycm9yLCBhcGlFcnJvcik7CiAgICB9IGVsc2UgewogICAgICBuZXR3b3JrRXhjZXB0aW9uID0gVW5rbm93bk5ldHdvcmtFeGNlcHRpb24obWVzc2FnZTogZXJyb3IudG9TdHJpbmcoKSk7CiAgICB9CgogICAgX2xvZ2dlci5lKCdOZXR3b3JrIGVycm9yIG9jY3VycmVkJywgbmV0d29ya0V4Y2VwdGlvbik7CgogICAgdGhyb3cgbmV0d29ya0V4Y2VwdGlvbjsKICB9CgogIEVycm9yUmVzcG9uc2U/IF9wYXJzZUFwaUVycm9yKFJlc3BvbnNlPyByZXNwb25zZSkgewogICAgdHJ5IHsKICAgICAgZmluYWwgcmVzcG9uc2VEYXRhID0gcmVzcG9uc2U/LmRhdGE7CiAgICAgIGlmIChyZXNwb25zZURhdGEgaXMgTWFwPFN0cmluZywgZHluYW1pYz4gJiYKICAgICAgICAgIHJlc3BvbnNlRGF0YS5jb250YWluc0tleSgnc3VjY2VzcycpICYmCiAgICAgICAgICByZXNwb25zZURhdGFbJ3N1Y2Nlc3MnXSA9PSBmYWxzZSkgewogICAgICAgIHJldHVybiBFcnJvclJlc3BvbnNlLmZyb21Kc29uKHsKICAgICAgICAgIC4uLnJlc3BvbnNlRGF0YSwKICAgICAgICAgICdzdGF0dXNDb2RlJzogcmVzcG9uc2U/LnN0YXR1c0NvZGUgPz8gNTAwLAogICAgICAgICAgJ2hlYWRlcnMnOiByZXNwb25zZT8uaGVhZGVycy5tYXAsCiAgICAgICAgfSk7CiAgICAgIH0KICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgX2xvZ2dlci53KCdGYWlsZWQgdG8gcGFyc2UgQVBJIGVycm9yOiAkZScpOwogICAgfQogICAgcmV0dXJuIG51bGw7CiAgfQoKICBOZXR3b3JrRXhjZXB0aW9uIF9tYXBEaW9FeGNlcHRpb24oCiAgICBEaW9FeGNlcHRpb24gZGlvRXhjZXB0aW9uLAogICAgRXJyb3JSZXNwb25zZT8gYXBpRXJyb3IsCiAgKSB7CiAgICBmaW5hbCBtZXNzYWdlID0gYXBpRXJyb3I/LmVycm9yLm1lc3NhZ2U7CgogICAgc3dpdGNoIChkaW9FeGNlcHRpb24udHlwZSkgewogICAgICBjYXNlIERpb0V4Y2VwdGlvblR5cGUuY29ubmVjdGlvblRpbWVvdXQ6CiAgICAgICAgcmV0dXJuIENvbm5lY3Rpb25UaW1lb3V0RXhjZXB0aW9uKG1lc3NhZ2U6IG1lc3NhZ2UpOwogICAgICBjYXNlIERpb0V4Y2VwdGlvblR5cGUucmVjZWl2ZVRpbWVvdXQ6CiAgICAgICAgcmV0dXJuIFJlY2VpdmVUaW1lb3V0RXhjZXB0aW9uKG1lc3NhZ2U6IG1lc3NhZ2UpOwogICAgICBjYXNlIERpb0V4Y2VwdGlvblR5cGUuc2VuZFRpbWVvdXQ6CiAgICAgICAgcmV0dXJuIFNlbmRUaW1lb3V0RXhjZXB0aW9uKG1lc3NhZ2U6IG1lc3NhZ2UpOwogICAgICBjYXNlIERpb0V4Y2VwdGlvblR5cGUuY29ubmVjdGlvbkVycm9yOgogICAgICAgIGlmIChkaW9FeGNlcHRpb24uZXJyb3IgaXMgU29ja2V0RXhjZXB0aW9uKSB7CiAgICAgICAgICByZXR1cm4gTm9JbnRlcm5ldENvbm5lY3Rpb25FeGNlcHRpb24obWVzc2FnZTogbWVzc2FnZSk7CiAgICAgICAgfQogICAgICAgIHJldHVybiBVbmtub3duTmV0d29ya0V4Y2VwdGlvbihtZXNzYWdlOiBtZXNzYWdlKTsKICAgICAgY2FzZSBEaW9FeGNlcHRpb25UeXBlLmJhZFJlc3BvbnNlOgogICAgICAgIGZpbmFsIHN0YXR1c0NvZGUgPSBkaW9FeGNlcHRpb24ucmVzcG9uc2U/LnN0YXR1c0NvZGU7CiAgICAgICAgc3dpdGNoIChzdGF0dXNDb2RlKSB7CiAgICAgICAgICBjYXNlIDQwMDoKICAgICAgICAgICAgcmV0dXJuIEJhZFJlcXVlc3RFeGNlcHRpb24obWVzc2FnZTogbWVzc2FnZSwgZXJyb3I6IGFwaUVycm9yKTsKICAgICAgICAgIGNhc2UgNDAxOgogICAgICAgICAgICByZXR1cm4gVW5hdXRob3JpemVkRXhjZXB0aW9uKG1lc3NhZ2U6IG1lc3NhZ2UsIGVycm9yOiBhcGlFcnJvcik7CiAgICAgICAgICBjYXNlIDQwMzoKICAgICAgICAgICAgcmV0dXJuIEZvcmJpZGRlbkV4Y2VwdGlvbihtZXNzYWdlOiBtZXNzYWdlLCBlcnJvcjogYXBpRXJyb3IpOwogICAgICAgICAgY2FzZSA0MDQ6CiAgICAgICAgICAgIHJldHVybiBOb3RGb3VuZEV4Y2VwdGlvbihtZXNzYWdlOiBtZXNzYWdlLCBlcnJvcjogYXBpRXJyb3IpOwogICAgICAgICAgY2FzZSA0MDk6CiAgICAgICAgICAgIHJldHVybiBDb25mbGljdEV4Y2VwdGlvbihtZXNzYWdlOiBtZXNzYWdlLCBlcnJvcjogYXBpRXJyb3IpOwogICAgICAgICAgY2FzZSA0MjI6CiAgICAgICAgICAgIHJldHVybiBVbnByb2Nlc3NhYmxlRW50aXR5RXhjZXB0aW9uKAogICAgICAgICAgICAgIG1lc3NhZ2U6IG1lc3NhZ2UsCiAgICAgICAgICAgICAgZXJyb3I6IGFwaUVycm9yLAogICAgICAgICAgICApOwogICAgICAgICAgY2FzZSA1MDA6CiAgICAgICAgICBjYXNlIDUwMjoKICAgICAgICAgIGNhc2UgNTAzOgogICAgICAgICAgY2FzZSA1MDQ6CiAgICAgICAgICAgIHJldHVybiBJbnRlcm5hbFNlcnZlckV4Y2VwdGlvbihtZXNzYWdlOiBtZXNzYWdlLCBlcnJvcjogYXBpRXJyb3IpOwogICAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgcmV0dXJuIFVua25vd25OZXR3b3JrRXhjZXB0aW9uKAogICAgICAgICAgICAgIG1lc3NhZ2U6IG1lc3NhZ2UsCiAgICAgICAgICAgICAgc3RhdHVzQ29kZTogc3RhdHVzQ29kZSwKICAgICAgICAgICAgICBlcnJvcjogYXBpRXJyb3IsCiAgICAgICAgICAgICk7CiAgICAgICAgfQogICAgICBkZWZhdWx0OgogICAgICAgIHJldHVybiBVbmtub3duTmV0d29ya0V4Y2VwdGlvbihtZXNzYWdlOiBtZXNzYWdlLCBlcnJvcjogYXBpRXJyb3IpOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgVCBoYW5kbGVSZXNwb25zZTxUPihmaW5hbCBOZXR3b3JrUmVzcG9uc2U8VD4gcmVzcG9uc2UpIHsKICAgIHN3aXRjaCAocmVzcG9uc2UpIHsKICAgICAgY2FzZSBTdWNjZXNzUmVzcG9uc2U8VD4oKToKICAgICAgICByZXR1cm4gcmVzcG9uc2UuZGF0YTsKICAgICAgY2FzZSBFcnJvclJlc3BvbnNlPFQ+KCk6CiAgICAgICAgdGhyb3cgVW5rbm93bk5ldHdvcmtFeGNlcHRpb24oCiAgICAgICAgICBtZXNzYWdlOiByZXNwb25zZS5tZXNzYWdlID8/IHN0cmluZ3MuZXJyb3JzLm5ldHdvcmtfZXJyb3IsCiAgICAgICAgICBzdGF0dXNDb2RlOiByZXNwb25zZS5zdGF0dXNDb2RlLAogICAgICAgICAgZXJyb3I6IHJlc3BvbnNlLAogICAgICAgICk7CiAgICAgIGRlZmF1bHQ6CiAgICAgICAgdGhyb3cgVW5rbm93bk5ldHdvcmtFeGNlcHRpb24oCiAgICAgICAgICBtZXNzYWdlOiBzdHJpbmdzLmVycm9ycy51bmtub3duX2Vycm9yLAogICAgICAgICAgc3RhdHVzQ29kZTogcmVzcG9uc2Uuc3RhdHVzQ29kZSwKICAgICAgICApOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgU3VjY2Vzc1Jlc3BvbnNlPFQ+IGhhbmRsZVN1Y2Nlc3NSZXNwb25zZTxUPigKICAgIGZpbmFsIE5ldHdvcmtSZXNwb25zZTxUPiByZXNwb25zZSwKICApIHsKICAgIHN3aXRjaCAocmVzcG9uc2UpIHsKICAgICAgY2FzZSBTdWNjZXNzUmVzcG9uc2U8VD4oKToKICAgICAgICByZXR1cm4gcmVzcG9uc2U7CiAgICAgIGNhc2UgRXJyb3JSZXNwb25zZTxUPigpOgogICAgICAgIHRocm93IFVua25vd25OZXR3b3JrRXhjZXB0aW9uKAogICAgICAgICAgbWVzc2FnZTogcmVzcG9uc2UubWVzc2FnZSA/PyBzdHJpbmdzLmVycm9ycy5uZXR3b3JrX2Vycm9yLAogICAgICAgICAgc3RhdHVzQ29kZTogcmVzcG9uc2Uuc3RhdHVzQ29kZSwKICAgICAgICAgIGVycm9yOiByZXNwb25zZSwKICAgICAgICApOwogICAgICBkZWZhdWx0OgogICAgICAgIHRocm93IFVua25vd25OZXR3b3JrRXhjZXB0aW9uKAogICAgICAgICAgbWVzc2FnZTogc3RyaW5ncy5lcnJvcnMudW5rbm93bl9lcnJvciwKICAgICAgICAgIHN0YXR1c0NvZGU6IHJlc3BvbnNlLnN0YXR1c0NvZGUsCiAgICAgICAgKTsKICAgIH0KICB9CgogIEBvdmVycmlkZQogIHZvaWQgZGlzcG9zZSgpIHsKICAgIF9kaW8uY2xvc2UoKTsKICB9Cn0K", "type": "text" }, { @@ -1174,7 +1331,7 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "path": "{{ name.snakeCase() }}/packages/{{network_dir}}/lib/src/interceptors/auth_interceptor.dart", "data": - "aW1wb3J0ICdwYWNrYWdlOmNvcmUvY29yZS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZGlvL2Rpby5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOm5ldHdvcmsvc3JjL2F1dGgvYXV0aF90b2tlbl9wcm92aWRlci5kYXJ0JzsKCmNsYXNzIEF1dGhJbnRlcmNlcHRvciBleHRlbmRzIEludGVyY2VwdG9yIHsKICBBdXRoSW50ZXJjZXB0b3IodGhpcy5fYXV0aFRva2VuUHJvdmlkZXIpIDogX2xvZ2dlciA9IGRpLmdldDxMb2dnZXI+KCk7CgogIGZpbmFsIEF1dGhUb2tlblByb3ZpZGVyIF9hdXRoVG9rZW5Qcm92aWRlcjsKICBmaW5hbCBMb2dnZXIgX2xvZ2dlcjsKCiAgQG92ZXJyaWRlCiAgdm9pZCBvblJlcXVlc3QoCiAgICBSZXF1ZXN0T3B0aW9ucyBvcHRpb25zLAogICAgUmVxdWVzdEludGVyY2VwdG9ySGFuZGxlciBoYW5kbGVyLAogICkgYXN5bmMgewogICAgdHJ5IHsKICAgICAgLy8gU2tpcCBhdXRoZW50aWNhdGlvbiBmb3IgcmVxdWVzdHMgdGhhdCBhbHJlYWR5IGhhdmUgYXV0aG9yaXphdGlvbiBoZWFkZXIKICAgICAgaWYgKG9wdGlvbnMuaGVhZGVycy5jb250YWluc0tleSgnQXV0aG9yaXphdGlvbicpKSB7CiAgICAgICAgaGFuZGxlci5uZXh0KG9wdGlvbnMpOwogICAgICAgIHJldHVybjsKICAgICAgfQoKICAgICAgZmluYWwgdG9rZW4gPSBhd2FpdCBfYXV0aFRva2VuUHJvdmlkZXIuZ2V0VmFsaWRUb2tlbigpOwogICAgICBpZiAodG9rZW4gIT0gbnVsbCkgewogICAgICAgIG9wdGlvbnMuaGVhZGVyc1snQXV0aG9yaXphdGlvbiddID0gJ0JlYXJlciAkdG9rZW4nOwogICAgICAgIF9sb2dnZXIuZCgn8J+UkCBBZGRlZCBCZWFyZXIgdG9rZW4gdG8gcmVxdWVzdDogJHtvcHRpb25zLnVyaX0nKTsKICAgICAgfSBlbHNlIHsKICAgICAgICBfbG9nZ2VyLmQoJ/CflJMgTm8gYXV0aCB0b2tlbiBhdmFpbGFibGUgZm9yIHJlcXVlc3Q6ICR7b3B0aW9ucy51cml9Jyk7CiAgICAgIH0KCiAgICAgIGhhbmRsZXIubmV4dChvcHRpb25zKTsKICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgX2xvZ2dlci5lKCfwn5qoIEVycm9yIGFkZGluZyBhdXRoIHRva2VuIHRvIHJlcXVlc3QnLCBlKTsKICAgICAgaGFuZGxlci5uZXh0KG9wdGlvbnMpOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgdm9pZCBvbkVycm9yKERpb0V4Y2VwdGlvbiBlcnIsIEVycm9ySW50ZXJjZXB0b3JIYW5kbGVyIGhhbmRsZXIpIGFzeW5jIHsKICAgIC8vIEhhbmRsZSA0MDEgVW5hdXRob3JpemVkIC0gdG9rZW4gbWlnaHQgYmUgZXhwaXJlZAogICAgaWYgKGVyci5yZXNwb25zZT8uc3RhdHVzQ29kZSA9PSA0MDEpIHsKICAgICAgX2xvZ2dlci53KCfwn5SQIFJlY2VpdmVkIDQwMSBVbmF1dGhvcml6ZWQsIGF0dGVtcHRpbmcgdG9rZW4gcmVmcmVzaCcpOwoKICAgICAgdHJ5IHsKICAgICAgICBmaW5hbCBuZXdUb2tlbiA9IGF3YWl0IF9hdXRoVG9rZW5Qcm92aWRlci5yZWZyZXNoVG9rZW4oKTsKICAgICAgICBpZiAobmV3VG9rZW4gIT0gbnVsbCkgewogICAgICAgICAgX2xvZ2dlci5pKCfwn5SEIFRva2VuIHJlZnJlc2hlZCBzdWNjZXNzZnVsbHksIHJldHJ5aW5nIHJlcXVlc3QnKTsKCiAgICAgICAgICAvLyBDbG9uZSB0aGUgcmVxdWVzdCB3aXRoIG5ldyB0b2tlbgogICAgICAgICAgZmluYWwgcmVxdWVzdE9wdGlvbnMgPSBlcnIucmVxdWVzdE9wdGlvbnM7CiAgICAgICAgICByZXF1ZXN0T3B0aW9ucy5oZWFkZXJzWydBdXRob3JpemF0aW9uJ10gPSAnQmVhcmVyICRuZXdUb2tlbic7CgogICAgICAgICAgLy8gUmV0cnkgdGhlIHJlcXVlc3QKICAgICAgICAgIGZpbmFsIHJlc3BvbnNlID0gYXdhaXQgRGlvKCkuZmV0Y2gocmVxdWVzdE9wdGlvbnMpOwogICAgICAgICAgaGFuZGxlci5yZXNvbHZlKHJlc3BvbnNlKTsKICAgICAgICAgIHJldHVybjsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgX2xvZ2dlci53KCfinYwgVG9rZW4gcmVmcmVzaCBmYWlsZWQsIHVzZXIgbmVlZHMgdG8gcmUtYXV0aGVudGljYXRlJyk7CiAgICAgICAgfQogICAgICB9IGNhdGNoIChyZWZyZXNoRXJyb3IpIHsKICAgICAgICBfbG9nZ2VyLmUoJ/CfmqggRXJyb3IgZHVyaW5nIHRva2VuIHJlZnJlc2gnLCByZWZyZXNoRXJyb3IpOwogICAgICB9CiAgICB9CgogICAgLy8gSGFuZGxlIDQwMyBGb3JiaWRkZW4gLSB1c2VyIGRvZXNuJ3QgaGF2ZSBwZXJtaXNzaW9uCiAgICBpZiAoZXJyLnJlc3BvbnNlPy5zdGF0dXNDb2RlID09IDQwMykgewogICAgICBfbG9nZ2VyLncoJ/CfmqsgUmVjZWl2ZWQgNDAzIEZvcmJpZGRlbiwgaW5zdWZmaWNpZW50IHBlcm1pc3Npb25zJyk7CiAgICB9CgogICAgaGFuZGxlci5uZXh0KGVycik7CiAgfQp9Cg==", + "aW1wb3J0ICdkYXJ0OmFzeW5jJzsKCmltcG9ydCAncGFja2FnZTpjb3JlL2NvcmUuZGFydCc7CmltcG9ydCAncGFja2FnZTpkaW8vZGlvLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6bmV0d29yay9zcmMvYXV0aC9hdXRoX3Rva2VuX3Byb3ZpZGVyLmRhcnQnOwoKLy8vIEFkZHMgc2Vzc2lvbiBjcmVkZW50aWFscyBhbmQgcmV0cmllcyBhbiBhdXRoZW50aWNhdGVkIHJlcXVlc3QgYXQgbW9zdCBvbmNlLgpjbGFzcyBBdXRoSW50ZXJjZXB0b3IgZXh0ZW5kcyBJbnRlcmNlcHRvciB7CiAgQXV0aEludGVyY2VwdG9yKAogICAgdGhpcy5fYXV0aFRva2VuUHJvdmlkZXIsIHsKICAgIHJlcXVpcmVkIERpbyBkaW8sCiAgICByZXF1aXJlZCBMb2dnZXIgbG9nZ2VyLAogIH0pIDogX2RpbyA9IGRpbywKICAgICAgIF9sb2dnZXIgPSBsb2dnZXI7CgogIGZpbmFsIEF1dGhUb2tlblByb3ZpZGVyIF9hdXRoVG9rZW5Qcm92aWRlcjsKICBmaW5hbCBEaW8gX2RpbzsKICBmaW5hbCBMb2dnZXIgX2xvZ2dlcjsKICBGdXR1cmU8U3RyaW5nPz4/IF9yZWZyZXNoaW5nOwogIHN0YXRpYyBjb25zdCBfbWFuYWdlZCA9ICdub25zdG9wLmF1dGgubWFuYWdlZCc7CiAgc3RhdGljIGNvbnN0IF9yZXRyaWVkID0gJ25vbnN0b3AuYXV0aC5yZXRyaWVkJzsKCiAgQG92ZXJyaWRlCiAgdm9pZCBvblJlcXVlc3QoCiAgICBSZXF1ZXN0T3B0aW9ucyBvcHRpb25zLAogICAgUmVxdWVzdEludGVyY2VwdG9ySGFuZGxlciBoYW5kbGVyLAogICkgYXN5bmMgewogICAgdHJ5IHsKICAgICAgZmluYWwgb3JpZ2luID0gVXJpLnBhcnNlKG9wdGlvbnMuYmFzZVVybCk7CiAgICAgIGlmICghb3JpZ2luLmhhc1NjaGVtZSB8fCBvcHRpb25zLnVyaS5vcmlnaW4gIT0gb3JpZ2luLm9yaWdpbikgewogICAgICAgIGhhbmRsZXIubmV4dChvcHRpb25zKTsKICAgICAgICByZXR1cm47CiAgICAgIH0KICAgICAgaWYgKG9wdGlvbnMuaGVhZGVycy5rZXlzLmFueSgKICAgICAgICAoa2V5KSA9PiBrZXkudG9Mb3dlckNhc2UoKSA9PSAnYXV0aG9yaXphdGlvbicsCiAgICAgICkpIHsKICAgICAgICBoYW5kbGVyLm5leHQob3B0aW9ucyk7CiAgICAgICAgcmV0dXJuOwogICAgICB9CiAgICAgIGZpbmFsIHRva2VuID0gYXdhaXQgX2F1dGhUb2tlblByb3ZpZGVyLmdldFZhbGlkVG9rZW4oKTsKICAgICAgaWYgKHRva2VuICE9IG51bGwpIHsKICAgICAgICBvcHRpb25zLmhlYWRlcnNbJ0F1dGhvcml6YXRpb24nXSA9ICdCZWFyZXIgJHRva2VuJzsKICAgICAgICBvcHRpb25zLmV4dHJhW19tYW5hZ2VkXSA9IHRydWU7CiAgICAgIH0KICAgICAgaGFuZGxlci5uZXh0KG9wdGlvbnMpOwogICAgfSBjYXRjaCAoZXJyb3IpIHsKICAgICAgX2xvZ2dlci5lKCdVbmFibGUgdG8gb2J0YWluIGFuIGF1dGhlbnRpY2F0aW9uIHRva2VuJywgZXJyb3IpOwogICAgICBoYW5kbGVyLm5leHQob3B0aW9ucyk7CiAgICB9CiAgfQoKICBGdXR1cmU8U3RyaW5nPz4gX3JlZnJlc2goKSBhc3luYyB7CiAgICBpZiAoX3JlZnJlc2hpbmcgIT0gbnVsbCkgcmV0dXJuIF9yZWZyZXNoaW5nOwogICAgZmluYWwgcGVuZGluZyA9IF9hdXRoVG9rZW5Qcm92aWRlci5yZWZyZXNoVG9rZW4oKTsKICAgIF9yZWZyZXNoaW5nID0gcGVuZGluZzsKICAgIHRyeSB7CiAgICAgIHJldHVybiBhd2FpdCBwZW5kaW5nOwogICAgfSBmaW5hbGx5IHsKICAgICAgX3JlZnJlc2hpbmcgPSBudWxsOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgdm9pZCBvbkVycm9yKERpb0V4Y2VwdGlvbiBlcnIsIEVycm9ySW50ZXJjZXB0b3JIYW5kbGVyIGhhbmRsZXIpIGFzeW5jIHsKICAgIGZpbmFsIHJlcXVlc3QgPSBlcnIucmVxdWVzdE9wdGlvbnM7CiAgICBpZiAoZXJyLnJlc3BvbnNlPy5zdGF0dXNDb2RlICE9IDQwMSB8fAogICAgICAgIHJlcXVlc3QuZXh0cmFbX21hbmFnZWRdICE9IHRydWUgfHwKICAgICAgICByZXF1ZXN0LmV4dHJhW19yZXRyaWVkXSA9PSB0cnVlIHx8CiAgICAgICAgcmVxdWVzdC5kYXRhIGlzIFN0cmVhbSkgewogICAgICBoYW5kbGVyLm5leHQoZXJyKTsKICAgICAgcmV0dXJuOwogICAgfQogICAgdHJ5IHsKICAgICAgZmluYWwgdG9rZW4gPSBhd2FpdCBfcmVmcmVzaCgpOwogICAgICBpZiAodG9rZW4gIT0gbnVsbCkgewogICAgICAgIGZpbmFsIHJlc3BvbnNlID0gYXdhaXQgX2Rpby5mZXRjaDxkeW5hbWljPigKICAgICAgICAgIHJlcXVlc3QuY29weVdpdGgoCiAgICAgICAgICAgIGhlYWRlcnM6IHsuLi5yZXF1ZXN0LmhlYWRlcnMsICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAkdG9rZW4nfSwKICAgICAgICAgICAgZXh0cmE6IHsuLi5yZXF1ZXN0LmV4dHJhLCBfcmV0cmllZDogdHJ1ZX0sCiAgICAgICAgICAgIGRhdGE6IHJlcXVlc3QuZGF0YSBpcyBGb3JtRGF0YQogICAgICAgICAgICAgICAgPyAocmVxdWVzdC5kYXRhIGFzIEZvcm1EYXRhKS5jbG9uZSgpCiAgICAgICAgICAgICAgICA6IHJlcXVlc3QuZGF0YSwKICAgICAgICAgICksCiAgICAgICAgKTsKICAgICAgICBoYW5kbGVyLnJlc29sdmUocmVzcG9uc2UpOwogICAgICAgIHJldHVybjsKICAgICAgfQogICAgfSBjYXRjaCAocmVmcmVzaEVycm9yKSB7CiAgICAgIF9sb2dnZXIuZSgnQXV0aGVudGljYXRpb24gcmV0cnkgZmFpbGVkJywgcmVmcmVzaEVycm9yKTsKICAgIH0KICAgIGhhbmRsZXIubmV4dChlcnIpOwogIH0KfQo=", "type": "text" }, { @@ -1188,7 +1345,7 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "path": "{{ name.snakeCase() }}/packages/{{network_dir}}/lib/src/interceptors/logging_interceptor.dart", "data": - "aW1wb3J0ICdwYWNrYWdlOmNvcmUvY29yZS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZGlvL2Rpby5kYXJ0JzsKCmNsYXNzIExvZ2dpbmdJbnRlcmNlcHRvciBleHRlbmRzIEludGVyY2VwdG9yIHsKICBMb2dnaW5nSW50ZXJjZXB0b3IoKSA6IF9sb2dnZXIgPSBkaS5nZXQ8TG9nZ2VyPigpOwoKICBmaW5hbCBMb2dnZXIgX2xvZ2dlcjsKCiAgQG92ZXJyaWRlCiAgdm9pZCBvblJlcXVlc3QoUmVxdWVzdE9wdGlvbnMgb3B0aW9ucywgUmVxdWVzdEludGVyY2VwdG9ySGFuZGxlciBoYW5kbGVyKSB7CiAgICBfbG9nZ2VyLmQoJ/CfmoAgUmVxdWVzdDogJHtvcHRpb25zLm1ldGhvZH0gJHtvcHRpb25zLnVyaX0nKTsKICAgIF9sb2dnZXIuZCgnSGVhZGVyczogJHtvcHRpb25zLmhlYWRlcnN9Jyk7CiAgICBpZiAob3B0aW9ucy5kYXRhICE9IG51bGwpIHsKICAgICAgX2xvZ2dlci5kKCdEYXRhOiAke29wdGlvbnMuZGF0YX0nKTsKICAgIH0KICAgIGlmIChvcHRpb25zLnF1ZXJ5UGFyYW1ldGVycy5pc05vdEVtcHR5KSB7CiAgICAgIF9sb2dnZXIuZCgnUXVlcnkgUGFyYW1ldGVyczogJHtvcHRpb25zLnF1ZXJ5UGFyYW1ldGVyc30nKTsKICAgIH0KICAgIHN1cGVyLm9uUmVxdWVzdChvcHRpb25zLCBoYW5kbGVyKTsKICB9CgogIEBvdmVycmlkZQogIHZvaWQgb25SZXNwb25zZShSZXNwb25zZSByZXNwb25zZSwgUmVzcG9uc2VJbnRlcmNlcHRvckhhbmRsZXIgaGFuZGxlcikgewogICAgX2xvZ2dlci5kKAogICAgICAn4pyFIFJlc3BvbnNlOiAke3Jlc3BvbnNlLnN0YXR1c0NvZGV9ICR7cmVzcG9uc2UucmVxdWVzdE9wdGlvbnMudXJpfScsCiAgICApOwogICAgX2xvZ2dlci5kKCdSZXNwb25zZSBEYXRhOiAke3Jlc3BvbnNlLmRhdGF9Jyk7CiAgICBzdXBlci5vblJlc3BvbnNlKHJlc3BvbnNlLCBoYW5kbGVyKTsKICB9CgogIEBvdmVycmlkZQogIHZvaWQgb25FcnJvcihEaW9FeGNlcHRpb24gZXJyLCBFcnJvckludGVyY2VwdG9ySGFuZGxlciBoYW5kbGVyKSB7CiAgICBfbG9nZ2VyLmUoCiAgICAgICfinYwgRXJyb3I6ICR7ZXJyLnJlc3BvbnNlPy5zdGF0dXNDb2RlfSAke2Vyci5yZXF1ZXN0T3B0aW9ucy51cml9JywKICAgICAgZXJyLAogICAgICBlcnIuc3RhY2tUcmFjZSwKICAgICk7CiAgICBpZiAoZXJyLnJlc3BvbnNlPy5kYXRhICE9IG51bGwpIHsKICAgICAgX2xvZ2dlci5lKCdFcnJvciBEYXRhOiAke2Vyci5yZXNwb25zZT8uZGF0YX0nKTsKICAgIH0KICAgIHN1cGVyLm9uRXJyb3IoZXJyLCBoYW5kbGVyKTsKICB9Cn0K", + "aW1wb3J0ICdwYWNrYWdlOmNvcmUvY29yZS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRpby9kaW8uZGFydCc7CgpjbGFzcyBMb2dnaW5nSW50ZXJjZXB0b3IgZXh0ZW5kcyBJbnRlcmNlcHRvciB7CiAgTG9nZ2luZ0ludGVyY2VwdG9yKHtyZXF1aXJlZCBMb2dnZXIgbG9nZ2VyfSkgOiBfbG9nZ2VyID0gbG9nZ2VyOwoKICBmaW5hbCBMb2dnZXIgX2xvZ2dlcjsKCiAgQG92ZXJyaWRlCiAgdm9pZCBvblJlcXVlc3QoUmVxdWVzdE9wdGlvbnMgb3B0aW9ucywgUmVxdWVzdEludGVyY2VwdG9ySGFuZGxlciBoYW5kbGVyKSB7CiAgICAvLyBDcmVkZW50aWFscyBhbmQgcGVyc29uYWwgZGF0YSBjYW4gb2NjdXIgaW4gaGVhZGVycywgcXVlcnkgc3RyaW5ncyBhbmQKICAgIC8vIGJvZGllcy4gTG9nIG9ubHkgdGhlIEhUVFAgbWV0aG9kIGFuZCBwYXRoIGJ5IGRlZmF1bHQuCiAgICBfbG9nZ2VyLmQoJ1JlcXVlc3Q6ICR7b3B0aW9ucy5tZXRob2R9ICR7b3B0aW9ucy51cmkucGF0aH0nKTsKICAgIHN1cGVyLm9uUmVxdWVzdChvcHRpb25zLCBoYW5kbGVyKTsKICB9CgogIEBvdmVycmlkZQogIHZvaWQgb25SZXNwb25zZShSZXNwb25zZSByZXNwb25zZSwgUmVzcG9uc2VJbnRlcmNlcHRvckhhbmRsZXIgaGFuZGxlcikgewogICAgX2xvZ2dlci5kKAogICAgICAnUmVzcG9uc2U6ICR7cmVzcG9uc2Uuc3RhdHVzQ29kZX0gJHtyZXNwb25zZS5yZXF1ZXN0T3B0aW9ucy51cmkucGF0aH0nLAogICAgKTsKICAgIHN1cGVyLm9uUmVzcG9uc2UocmVzcG9uc2UsIGhhbmRsZXIpOwogIH0KCiAgQG92ZXJyaWRlCiAgdm9pZCBvbkVycm9yKERpb0V4Y2VwdGlvbiBlcnIsIEVycm9ySW50ZXJjZXB0b3JIYW5kbGVyIGhhbmRsZXIpIHsKICAgIF9sb2dnZXIuZSgKICAgICAgJ05ldHdvcmsgZXJyb3I6ICR7ZXJyLnR5cGUubmFtZX0gJHtlcnIucmVzcG9uc2U/LnN0YXR1c0NvZGV9ICcKICAgICAgJyR7ZXJyLnJlcXVlc3RPcHRpb25zLnVyaS5wYXRofScsCiAgICApOwogICAgc3VwZXIub25FcnJvcihlcnIsIGhhbmRsZXIpOwogIH0KfQo=", "type": "text" }, { @@ -1233,7 +1390,7 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ { "path": "{{ name.snakeCase() }}/packages/{{network_dir}}/pubspec.yaml", "data": - "bmFtZTogbmV0d29yawpkZXNjcmlwdGlvbjogIkhUVFAgbGF5ZXIgZm9yIHt7bmFtZS50aXRsZUNhc2UoKX19OiBEaW8gY2xpZW50LCBpbnRlcmNlcHRvcnMsIHR5cGVkIHJlc3BvbnNlcyBhbmQgZXJyb3IgbWFwcGluZy4iCnZlcnNpb246IDAuMS4wCnB1Ymxpc2hfdG86ICdub25lJwoKZW52aXJvbm1lbnQ6CiAgc2RrOiBeMy44LjAKICBmbHV0dGVyOiAiPj0zLjI5LjAiCgpkZXBlbmRlbmNpZXM6CiAgZmx1dHRlcjoKICAgIHNkazogZmx1dHRlcgogIGRpbzogXjUuNy4wCiAganNvbl9hbm5vdGF0aW9uOiBeNC45LjAKICB0YWxrZXJfZGlvX2xvZ2dlcjogXjQuOS4xCiAgdGFsa2VyX2ZsdXR0ZXI6IF40LjQuMQogIGNvcmU6CiAgICBwYXRoOiAuLi9jb3JlCiAgbG9jYWxpemF0aW9uOgogICAgcGF0aDogLi4vbG9jYWxpemF0aW9uCiAgZGk6CiAgICBwYXRoOiAuLi9kaQoKZGV2X2RlcGVuZGVuY2llczoKICBmbHV0dGVyX3Rlc3Q6CiAgICBzZGs6IGZsdXR0ZXIKICBmbHV0dGVyX2xpbnRzOiBeNS4wLjAKICBidWlsZF9ydW5uZXI6IF4yLjQuMTUKICBqc29uX3NlcmlhbGl6YWJsZTogXjYuOS41CgpmbHV0dGVyOgo=", + "bmFtZTogbmV0d29yawpkZXNjcmlwdGlvbjogIkhUVFAgbGF5ZXIgZm9yIHt7bmFtZS50aXRsZUNhc2UoKX19OiBEaW8gY2xpZW50LCBpbnRlcmNlcHRvcnMsIHR5cGVkIHJlc3BvbnNlcyBhbmQgZXJyb3IgbWFwcGluZy4iCnZlcnNpb246IDAuMS4wCnB1Ymxpc2hfdG86ICdub25lJwoKZW52aXJvbm1lbnQ6CiAgc2RrOiBeMy44LjAKICBmbHV0dGVyOiAiPj0zLjI5LjAiCgpkZXBlbmRlbmNpZXM6CiAgZmx1dHRlcjoKICAgIHNkazogZmx1dHRlcgogIGRpbzogXjUuNy4wCiAganNvbl9hbm5vdGF0aW9uOiBeNC45LjAKICB0YWxrZXJfZGlvX2xvZ2dlcjogXjQuOS4xCiAgdGFsa2VyX2ZsdXR0ZXI6IF40LjQuMQogIGNvcmU6CiAgICBwYXRoOiAuLi9jb3JlCiAgbG9jYWxpemF0aW9uOgogICAgcGF0aDogLi4vbG9jYWxpemF0aW9uCiAgZGk6CiAgICBwYXRoOiAuLi9kaQoKZGV2X2RlcGVuZGVuY2llczoKICBtb2NrdGFpbDogXjEuMC40CiAgZmx1dHRlcl90ZXN0OgogICAgc2RrOiBmbHV0dGVyCiAgZmx1dHRlcl9saW50czogXjUuMC4wCiAgYnVpbGRfcnVubmVyOiBeMi40LjE1CiAganNvbl9zZXJpYWxpemFibGU6IF42LjkuNQoKZmx1dHRlcjoK", "type": "text" }, { @@ -1242,6 +1399,20 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "IyBOZXR3b3JrCgpBIE1lbG9zLW1hbmFnZWQgcHJvamVjdCBmb3IgbW9uby1yZXBvLCBjcmVhdGVkIHVzaW5nIE5vblN0b3AgQ0xJLgoKWyFbbm9uc3RvcF9jbGldKGh0dHBzOi8vaW1nLnNoaWVsZHMuaW8vYmFkZ2Uvc3RhcnRlZCUyMHdpdGgtbm9uc3RvcF9jbGktMTY2QzRFLnN2Zz9zdHlsZT1mbGF0LXNxdWFyZSldKGh0dHBzOi8vcHViLmRldi9wYWNrYWdlcy9ub25zdG9wX2NsaSkKWyFbbWVsb3NdKGh0dHBzOi8vaW1nLnNoaWVsZHMuaW8vYmFkZ2UvbWFpbnRhaW5lZCUyMHdpdGgtbWVsb3MtZjcwMGZmLnN2Zz9zdHlsZT1mbGF0LXNxdWFyZSldKGh0dHBzOi8vZ2l0aHViLmNvbS9pbnZlcnRhc2UvbWVsb3MpCgojIyBJbnN0YWxsYXRpb24g8J+SuwoKKirinZcgSW4gb3JkZXIgdG8gc3RhcnQgdXNpbmcgTmV0d29yayB5b3UgbXVzdCBoYXZlIHRoZSBbRmx1dHRlciBTREtdW2ZsdXR0ZXJfaW5zdGFsbF9saW5rXSBpbnN0YWxsZWQgb24geW91ciBtYWNoaW5lLioqCgpJbnN0YWxsIHZpYSBgZGFydCBwdWIgYWRkYDoKCmBgYHNoCmRhcnQgcHViIGFkZCBuZXR3b3JrCmBgYAoKW2ZsdXR0ZXJfaW5zdGFsbF9saW5rXTogaHR0cHM6Ly9kb2NzLmZsdXR0ZXIuZGV2L2dldC1zdGFydGVkL2luc3RhbGw=", "type": "text" }, + { + "path": + "{{ name.snakeCase() }}/packages/{{network_dir}}/test/dio_network_client_test.dart", + "data": + "aW1wb3J0ICdkYXJ0OmNvbnZlcnQnOwppbXBvcnQgJ2RhcnQ6YXN5bmMnOwppbXBvcnQgJ2RhcnQ6aW8nOwppbXBvcnQgJ2RhcnQ6dHlwZWRfZGF0YSc7CgppbXBvcnQgJ3BhY2thZ2U6Y29yZS9jb3JlLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZGlvL2Rpby5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6bmV0d29yay9uZXR3b3JrLmRhcnQnIGFzIG5ldHdvcms7CmltcG9ydCAncGFja2FnZTpmbHV0dGVyX3Rlc3QvZmx1dHRlcl90ZXN0LmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6bmV0d29yay9uZXR3b3JrLmRhcnQnOwoKY2xhc3MgX0xvZ2dlciBpbXBsZW1lbnRzIExvZ2dlciB7CiAgZmluYWwgbWVzc2FnZXMgPSA8U3RyaW5nPltdOwogIEBvdmVycmlkZQogIE9iamVjdCBnZXQgbG9nZ2VyID0+IHRoaXM7CiAgQG92ZXJyaWRlCiAgdm9pZCBkKFN0cmluZyBtZXNzYWdlKSA9PiBtZXNzYWdlcy5hZGQobWVzc2FnZSk7CiAgQG92ZXJyaWRlCiAgdm9pZCBpKFN0cmluZyBtZXNzYWdlKSA9PiBtZXNzYWdlcy5hZGQobWVzc2FnZSk7CiAgQG92ZXJyaWRlCiAgdm9pZCB3KFN0cmluZyBtZXNzYWdlKSA9PiBtZXNzYWdlcy5hZGQobWVzc2FnZSk7CiAgQG92ZXJyaWRlCiAgdm9pZCBlKFN0cmluZyBtZXNzYWdlLCBbT2JqZWN0PyBlcnJvciwgU3RhY2tUcmFjZT8gc3RhY2tUcmFjZV0pID0+CiAgICAgIG1lc3NhZ2VzLmFkZChtZXNzYWdlKTsKfQoKY2xhc3MgX0FkYXB0ZXIgaW1wbGVtZW50cyBIdHRwQ2xpZW50QWRhcHRlciB7CiAgT2JqZWN0PyBib2R5OwogIGludCBzdGF0dXMgPSAyMDA7CiAgZmluYWwgc3RhdHVzZXMgPSA8aW50PltdOwogIGJvb2wgY2xvc2VkID0gZmFsc2U7CiAgT2JqZWN0PyBmYWlsdXJlOwogIGZpbmFsIHJlcXVlc3RzID0gPFJlcXVlc3RPcHRpb25zPltdOwoKICBAb3ZlcnJpZGUKICBGdXR1cmU8UmVzcG9uc2VCb2R5PiBmZXRjaCgKICAgIFJlcXVlc3RPcHRpb25zIG9wdGlvbnMsCiAgICBTdHJlYW08VWludDhMaXN0Pj8gcmVxdWVzdFN0cmVhbSwKICAgIEZ1dHVyZTx2b2lkPj8gY2FuY2VsRnV0dXJlLAogICkgYXN5bmMgewogICAgcmVxdWVzdHMuYWRkKG9wdGlvbnMpOwogICAgaWYgKGZhaWx1cmUgIT0gbnVsbCkgdGhyb3cgZmFpbHVyZSE7CiAgICByZXR1cm4gUmVzcG9uc2VCb2R5LmZyb21TdHJpbmcoCiAgICAgIGpzb25FbmNvZGUoYm9keSksCiAgICAgIHN0YXR1c2VzLmlzRW1wdHkgPyBzdGF0dXMgOiBzdGF0dXNlcy5yZW1vdmVBdCgwKSwKICAgICAgaGVhZGVyczogewogICAgICAgIEhlYWRlcnMuY29udGVudFR5cGVIZWFkZXI6IFtIZWFkZXJzLmpzb25Db250ZW50VHlwZV0sCiAgICAgIH0sCiAgICApOwogIH0KCiAgQG92ZXJyaWRlCiAgdm9pZCBjbG9zZSh7Ym9vbCBmb3JjZSA9IGZhbHNlfSkgPT4gY2xvc2VkID0gdHJ1ZTsKfQoKY2xhc3MgX1Rva2VucyBpbXBsZW1lbnRzIEF1dGhUb2tlblByb3ZpZGVyIHsKICBpbnQgcmVmcmVzaGVzID0gMDsKICBTdHJpbmc/IHJlZnJlc2hlZCA9ICduZXctdG9rZW4nOwogIGJvb2wgZmFpbFJlZnJlc2ggPSBmYWxzZTsKICBib29sIGZhaWxSZWFkID0gZmFsc2U7CiAgQG92ZXJyaWRlCiAgRnV0dXJlPFN0cmluZz8+IGdldFZhbGlkVG9rZW4oKSBhc3luYyB7CiAgICBpZiAoZmFpbFJlYWQpIHRocm93IFN0YXRlRXJyb3IoJ3Rva2VuIHVuYXZhaWxhYmxlJyk7CiAgICByZXR1cm4gJ29sZC10b2tlbic7CiAgfQoKICBAb3ZlcnJpZGUKICBGdXR1cmU8U3RyaW5nPz4gcmVmcmVzaFRva2VuKCkgYXN5bmMgewogICAgcmVmcmVzaGVzKys7CiAgICBpZiAoZmFpbFJlZnJlc2gpIHRocm93IFN0YXRlRXJyb3IoJ3JlZnJlc2ggZmFpbGVkJyk7CiAgICByZXR1cm4gcmVmcmVzaGVkOwogIH0KCiAgQG92ZXJyaWRlCiAgZHluYW1pYyBub1N1Y2hNZXRob2QoSW52b2NhdGlvbiBpbnZvY2F0aW9uKSA9PiBzdXBlci5ub1N1Y2hNZXRob2QoaW52b2NhdGlvbik7Cn0KCmNsYXNzIF9EZWxheWVkVG9rZW5zIGV4dGVuZHMgX1Rva2VucyB7CiAgZmluYWwgcGVuZGluZyA9IENvbXBsZXRlcjxTdHJpbmc/PigpOwogIEBvdmVycmlkZQogIEZ1dHVyZTxTdHJpbmc/PiByZWZyZXNoVG9rZW4oKSB7CiAgICByZWZyZXNoZXMrKzsKICAgIHJldHVybiBwZW5kaW5nLmZ1dHVyZTsKICB9Cn0KCnZvaWQgbWFpbigpIHsKICBsYXRlIF9BZGFwdGVyIGFkYXB0ZXI7CiAgbGF0ZSBfTG9nZ2VyIGxvZ2dlcjsKICBsYXRlIERpb05ldHdvcmtDbGllbnQgY2xpZW50OwoKICBzZXRVcCgoKSB7CiAgICBhZGFwdGVyID0gX0FkYXB0ZXIoKTsKICAgIGxvZ2dlciA9IF9Mb2dnZXIoKTsKICAgIGNsaWVudCA9IERpb05ldHdvcmtDbGllbnQoCiAgICAgIERlZmF1bHROZXR3b3JrQ29uZmlnKGJhc2VVcmw6ICdodHRwczovL2V4YW1wbGUudGVzdCcpLAogICAgICBsb2dnZXI6IGxvZ2dlciwKICAgICAgZGlvOiBEaW8oKS4uaHR0cENsaWVudEFkYXB0ZXIgPSBhZGFwdGVyLAogICAgKTsKICB9KTsKICB0ZWFyRG93bigoKSA9PiBjbGllbnQuZGlzcG9zZSgpKTsKCiAgdGVzdCgnY29uY3VycmVudCB1bmF1dGhvcml6ZWQgcmVxdWVzdHMgc2hhcmUgb25lIHRva2VuIHJlZnJlc2gnLCAoKSBhc3luYyB7CiAgICBmaW5hbCB0b2tlbnMgPSBfRGVsYXllZFRva2VucygpOwogICAgYWRhcHRlci5zdGF0dXNlcy5hZGRBbGwoWzQwMSwgNDAxLCAyMDAsIDIwMF0pOwogICAgZmluYWwgYXV0aGVudGljYXRlZCA9IERpb05ldHdvcmtDbGllbnQoCiAgICAgIERlZmF1bHROZXR3b3JrQ29uZmlnKAogICAgICAgIGJhc2VVcmw6ICdodHRwczovL2V4YW1wbGUudGVzdCcsCiAgICAgICAgYXV0aFRva2VuUHJvdmlkZXI6IHRva2VucywKICAgICAgKSwKICAgICAgbG9nZ2VyOiBsb2dnZXIsCiAgICAgIGRpbzogRGlvKCkuLmh0dHBDbGllbnRBZGFwdGVyID0gYWRhcHRlciwKICAgICk7CiAgICBhZGRUZWFyRG93bihhdXRoZW50aWNhdGVkLmRpc3Bvc2UpOwogICAgZmluYWwgZmlyc3QgPSBhdXRoZW50aWNhdGVkLmdldDxPYmplY3Q/PigKICAgICAgJy9maXJzdCcsCiAgICAgIGZyb21Kc29uVDogKGpzb24pID0+IGpzb24sCiAgICApOwogICAgZmluYWwgc2Vjb25kID0gYXV0aGVudGljYXRlZC5nZXQ8T2JqZWN0Pz4oCiAgICAgICcvc2Vjb25kJywKICAgICAgZnJvbUpzb25UOiAoanNvbikgPT4ganNvbiwKICAgICk7CiAgICBhd2FpdCBwdW1wRXZlbnRRdWV1ZSgpOwogICAgZXhwZWN0KHRva2Vucy5yZWZyZXNoZXMsIDEpOwogICAgdG9rZW5zLnBlbmRpbmcuY29tcGxldGUoJ25ldy10b2tlbicpOwogICAgZmluYWwgcmVzdWx0cyA9IGF3YWl0IEZ1dHVyZS53YWl0KFtmaXJzdCwgc2Vjb25kXSk7CiAgICBleHBlY3QocmVzdWx0cy5ldmVyeSgocikgPT4gci5pc1N1Y2Nlc3MpLCBpc1RydWUpOwogICAgZXhwZWN0KGFkYXB0ZXIucmVxdWVzdHMsIGhhc0xlbmd0aCg0KSk7CiAgfSk7CgogIHRlc3QoCiAgICAnbXVsdGlwYXJ0IHJldHJpZXMgY2xvbmUgY29uc3VtZWQgYm9kaWVzOyBzdHJlYW1zIGFyZSBuZXZlciByZXBsYXllZCcsCiAgICAoKSBhc3luYyB7CiAgICAgIGZpbmFsIHRva2VucyA9IF9Ub2tlbnMoKTsKICAgICAgZmluYWwgYXV0aGVudGljYXRlZCA9IERpb05ldHdvcmtDbGllbnQoCiAgICAgICAgRGVmYXVsdE5ldHdvcmtDb25maWcoCiAgICAgICAgICBiYXNlVXJsOiAnaHR0cHM6Ly9leGFtcGxlLnRlc3QnLAogICAgICAgICAgYXV0aFRva2VuUHJvdmlkZXI6IHRva2VucywKICAgICAgICApLAogICAgICAgIGxvZ2dlcjogbG9nZ2VyLAogICAgICAgIGRpbzogRGlvKCkuLmh0dHBDbGllbnRBZGFwdGVyID0gYWRhcHRlciwKICAgICAgKTsKICAgICAgYWRkVGVhckRvd24oYXV0aGVudGljYXRlZC5kaXNwb3NlKTsKICAgICAgYWRhcHRlci5zdGF0dXNlcy5hZGRBbGwoWzQwMSwgMjAwXSk7CiAgICAgIGZpbmFsIGZvcm0gPSBGb3JtRGF0YS5mcm9tTWFwKHsnZmllbGQnOiAndmFsdWUnfSk7CiAgICAgIGV4cGVjdCgKICAgICAgICAoYXdhaXQgYXV0aGVudGljYXRlZC5wb3N0PE9iamVjdD8+KAogICAgICAgICAgJy9maWxlJywKICAgICAgICAgIGRhdGE6IGZvcm0sCiAgICAgICAgICBmcm9tSnNvblQ6IChqc29uKSA9PiBqc29uLAogICAgICAgICkpLmlzU3VjY2VzcywKICAgICAgICBpc1RydWUsCiAgICAgICk7CiAgICAgIGV4cGVjdChhZGFwdGVyLnJlcXVlc3RzLmxhc3QuZGF0YSwgaXNOb3Qoc2FtZShmb3JtKSkpOwogICAgICBhZGFwdGVyLnN0YXR1cyA9IDQwMTsKICAgICAgYXdhaXQgZXhwZWN0TGF0ZXIoCiAgICAgICAgYXV0aGVudGljYXRlZC5wb3N0PE9iamVjdD8+KAogICAgICAgICAgJy9zdHJlYW0nLAogICAgICAgICAgZGF0YTogU3RyZWFtLnZhbHVlKFsxLCAyXSksCiAgICAgICAgICBmcm9tSnNvblQ6IChqc29uKSA9PiBqc29uLAogICAgICAgICksCiAgICAgICAgdGhyb3dzQShpc0E8VW5hdXRob3JpemVkRXhjZXB0aW9uPigpKSwKICAgICAgKTsKICAgICAgZXhwZWN0KHRva2Vucy5yZWZyZXNoZXMsIDEpOwogICAgfSwKICApOwoKICB0ZXN0KCdBUEkgcGF5bG9hZCBjYW5ub3Qgb3ZlcnJpZGUgSFRUUCBzdGF0dXMgb3IgcmVzcG9uc2UgaGVhZGVycycsICgpIGFzeW5jIHsKICAgIGFkYXB0ZXIuYm9keSA9IHsKICAgICAgJ3N1Y2Nlc3MnOiB0cnVlLAogICAgICAndGltZXN0YW1wJzogJ25vdycsCiAgICAgICdkYXRhJzogMSwKICAgICAgJ3N0YXR1c0NvZGUnOiA1MDAsCiAgICAgICdoZWFkZXJzJzogewogICAgICAgICdmYWtlJzogWyd2YWx1ZSddLAogICAgICB9LAogICAgfTsKICAgIGZpbmFsIHJlc3BvbnNlID0gYXdhaXQgY2xpZW50LmdldDxpbnQ+KAogICAgICAnL3ZhbHVlJywKICAgICAgZnJvbUpzb25UOiAoanNvbikgPT4ganNvbiBhcyBpbnQsCiAgICApOwogICAgZXhwZWN0KHJlc3BvbnNlLnN0YXR1c0NvZGUsIDIwMCk7CiAgICBleHBlY3QocmVzcG9uc2UuaGVhZGVycywgaXNOb3QoY29udGFpbnMoJ2Zha2UnKSkpOwogIH0pOwoKICBmb3IgKGZpbmFsIChzdGF0dXMsIGV4cGVjdGVkKSBpbiA8KGludCwgVHlwZSk+WwogICAgKDQwMCwgQmFkUmVxdWVzdEV4Y2VwdGlvbiksCiAgICAoNDAzLCBGb3JiaWRkZW5FeGNlcHRpb24pLAogICAgKDQwNCwgTm90Rm91bmRFeGNlcHRpb24pLAogICAgKDQwOSwgQ29uZmxpY3RFeGNlcHRpb24pLAogICAgKDQyMiwgVW5wcm9jZXNzYWJsZUVudGl0eUV4Y2VwdGlvbiksCiAgICAoNTAwLCBJbnRlcm5hbFNlcnZlckV4Y2VwdGlvbiksCiAgICAoNTAyLCBJbnRlcm5hbFNlcnZlckV4Y2VwdGlvbiksCiAgICAoNTAzLCBJbnRlcm5hbFNlcnZlckV4Y2VwdGlvbiksCiAgICAoNTA0LCBJbnRlcm5hbFNlcnZlckV4Y2VwdGlvbiksCiAgICAoNDE4LCBVbmtub3duTmV0d29ya0V4Y2VwdGlvbiksCiAgXSkgewogICAgdGVzdCgKICAgICAgJ0hUVFAgJHN0YXR1cyBtYXBzIHRvICRleHBlY3RlZCBhbmQgcHJlc2VydmVzIEFQSSBlcnJvciBkZXRhaWxzJywKICAgICAgKCkgYXN5bmMgewogICAgICAgIGFkYXB0ZXIuc3RhdHVzID0gc3RhdHVzOwogICAgICAgIGFkYXB0ZXIuYm9keSA9IHsKICAgICAgICAgICdzdWNjZXNzJzogZmFsc2UsCiAgICAgICAgICAndGltZXN0YW1wJzogJzIwMjYtMDEtMDEnLAogICAgICAgICAgJ2Vycm9yJzogeydjb2RlJzogJ0ZBSUwnLCAnbWVzc2FnZSc6ICdSZXF1ZXN0IHJlamVjdGVkJ30sCiAgICAgICAgfTsKICAgICAgICBhd2FpdCBleHBlY3RMYXRlcigKICAgICAgICAgIGNsaWVudC5nZXQ8T2JqZWN0Pz4oJy9yZXF1ZXN0JywgZnJvbUpzb25UOiAoanNvbikgPT4ganNvbiksCiAgICAgICAgICB0aHJvd3NBKAogICAgICAgICAgICBwcmVkaWNhdGU8TmV0d29ya0V4Y2VwdGlvbj4oCiAgICAgICAgICAgICAgKGUpID0+CiAgICAgICAgICAgICAgICAgIGUucnVudGltZVR5cGUgPT0gZXhwZWN0ZWQgJiYgZS5tZXNzYWdlID09ICdSZXF1ZXN0IHJlamVjdGVkJywKICAgICAgICAgICAgKSwKICAgICAgICAgICksCiAgICAgICAgKTsKICAgICAgfSwKICAgICk7CiAgfQoKICB0ZXN0KCdldmVyeSB0cmFuc3BvcnQgZmFpbHVyZSBtYXBzIHRvIGEgZG9tYWluIGV4Y2VwdGlvbicsICgpIGFzeW5jIHsKICAgIGZvciAoZmluYWwgKHR5cGUsIGVycm9yLCBleHBlY3RlZCkgaW4gPChEaW9FeGNlcHRpb25UeXBlLCBPYmplY3Q/LCBUeXBlKT5bCiAgICAgIChEaW9FeGNlcHRpb25UeXBlLmNvbm5lY3Rpb25UaW1lb3V0LCBudWxsLCBDb25uZWN0aW9uVGltZW91dEV4Y2VwdGlvbiksCiAgICAgIChEaW9FeGNlcHRpb25UeXBlLnJlY2VpdmVUaW1lb3V0LCBudWxsLCBSZWNlaXZlVGltZW91dEV4Y2VwdGlvbiksCiAgICAgIChEaW9FeGNlcHRpb25UeXBlLnNlbmRUaW1lb3V0LCBudWxsLCBTZW5kVGltZW91dEV4Y2VwdGlvbiksCiAgICAgICgKICAgICAgICBEaW9FeGNlcHRpb25UeXBlLmNvbm5lY3Rpb25FcnJvciwKICAgICAgICBjb25zdCBTb2NrZXRFeGNlcHRpb24oJ29mZmxpbmUnKSwKICAgICAgICBOb0ludGVybmV0Q29ubmVjdGlvbkV4Y2VwdGlvbiwKICAgICAgKSwKICAgICAgKERpb0V4Y2VwdGlvblR5cGUuY29ubmVjdGlvbkVycm9yLCBudWxsLCBVbmtub3duTmV0d29ya0V4Y2VwdGlvbiksCiAgICAgIChEaW9FeGNlcHRpb25UeXBlLmNhbmNlbCwgbnVsbCwgVW5rbm93bk5ldHdvcmtFeGNlcHRpb24pLAogICAgXSkgewogICAgICBhZGFwdGVyLmZhaWx1cmUgPSBEaW9FeGNlcHRpb24oCiAgICAgICAgcmVxdWVzdE9wdGlvbnM6IFJlcXVlc3RPcHRpb25zKHBhdGg6ICcvcmVxdWVzdCcpLAogICAgICAgIHR5cGU6IHR5cGUsCiAgICAgICAgZXJyb3I6IGVycm9yLAogICAgICApOwogICAgICBhd2FpdCBleHBlY3RMYXRlcigKICAgICAgICBjbGllbnQuZ2V0PE9iamVjdD8+KCcvcmVxdWVzdCcsIGZyb21Kc29uVDogKGpzb24pID0+IGpzb24pLAogICAgICAgIHRocm93c0EocHJlZGljYXRlPE5ldHdvcmtFeGNlcHRpb24+KChlKSA9PiBlLnJ1bnRpbWVUeXBlID09IGV4cGVjdGVkKSksCiAgICAgICk7CiAgICB9CiAgfSk7CgogIHRlc3QoCiAgICAnd3JpdGUgdmVyYnMgY29uc2lzdGVudGx5IHByb3BhZ2F0ZSB0cmFuc3BvcnQgZXJyb3JzIGFuZCBtYWxmb3JtZWQgZW52ZWxvcGVzIGRvIG5vdCBoaWRlIEhUVFAgZmFpbHVyZXMnLAogICAgKCkgYXN5bmMgewogICAgICBhZGFwdGVyLnN0YXR1cyA9IDUwMDsKICAgICAgYWRhcHRlci5ib2R5ID0geydzdWNjZXNzJzogZmFsc2UsICdlcnJvcic6ICdpbnZhbGlkIHNoYXBlJ307CiAgICAgIGZvciAoZmluYWwgb3BlcmF0aW9uIGluIFsKICAgICAgICAoKSA9PiBjbGllbnQucG9zdDxPYmplY3Q/PignL3JlcXVlc3QnLCBmcm9tSnNvblQ6IChqKSA9PiBqKSwKICAgICAgICAoKSA9PiBjbGllbnQucHV0PE9iamVjdD8+KCcvcmVxdWVzdCcsIGZyb21Kc29uVDogKGopID0+IGopLAogICAgICAgICgpID0+IGNsaWVudC5wYXRjaDxPYmplY3Q/PignL3JlcXVlc3QnLCBmcm9tSnNvblQ6IChqKSA9PiBqKSwKICAgICAgICAoKSA9PiBjbGllbnQuZGVsZXRlPE9iamVjdD8+KCcvcmVxdWVzdCcsIGZyb21Kc29uVDogKGopID0+IGopLAogICAgICBdKSB7CiAgICAgICAgYXdhaXQgZXhwZWN0TGF0ZXIob3BlcmF0aW9uKCksIHRocm93c0EoaXNBPEludGVybmFsU2VydmVyRXhjZXB0aW9uPigpKSk7CiAgICAgIH0KICAgIH0sCiAgKTsKCiAgdGVzdCgKICAgICdhdXRoIHRva2VucyBzdGF5IG9uIHRoZSBjb25maWd1cmVkIG9yaWdpbiBhbmQgcHJvdmlkZXIgZmFpbHVyZXMgZG8gbm90IGNyYXNoIHJlcXVlc3RzJywKICAgICgpIGFzeW5jIHsKICAgICAgZmluYWwgdG9rZW5zID0gX1Rva2VucygpOwogICAgICBmaW5hbCB0cmFuc3BvcnQgPSBEaW8oKS4uaHR0cENsaWVudEFkYXB0ZXIgPSBhZGFwdGVyOwogICAgICBmaW5hbCBhdXRoZW50aWNhdGVkID0gRGlvTmV0d29ya0NsaWVudCgKICAgICAgICBEZWZhdWx0TmV0d29ya0NvbmZpZygKICAgICAgICAgIGJhc2VVcmw6ICdodHRwczovL2V4YW1wbGUudGVzdCcsCiAgICAgICAgICBhdXRoVG9rZW5Qcm92aWRlcjogdG9rZW5zLAogICAgICAgICksCiAgICAgICAgbG9nZ2VyOiBsb2dnZXIsCiAgICAgICAgZGlvOiB0cmFuc3BvcnQsCiAgICAgICk7CiAgICAgIGFkZFRlYXJEb3duKGF1dGhlbnRpY2F0ZWQuZGlzcG9zZSk7CiAgICAgIGF3YWl0IGF1dGhlbnRpY2F0ZWQuZ2V0PE9iamVjdD8+KAogICAgICAgICdodHRwczovL2V4dGVybmFsLnRlc3QvaW1hZ2UnLAogICAgICAgIGZyb21Kc29uVDogKGopID0+IGosCiAgICAgICk7CiAgICAgIGV4cGVjdChhZGFwdGVyLnJlcXVlc3RzLmxhc3QuaGVhZGVycywgaXNOb3QoY29udGFpbnMoJ0F1dGhvcml6YXRpb24nKSkpOwogICAgICB0b2tlbnMuZmFpbFJlYWQgPSB0cnVlOwogICAgICBhd2FpdCBhdXRoZW50aWNhdGVkLmdldDxPYmplY3Q/PignL2ltYWdlJywgZnJvbUpzb25UOiAoaikgPT4gaik7CiAgICAgIGV4cGVjdChhZGFwdGVyLnJlcXVlc3RzLmxhc3QuaGVhZGVycywgaXNOb3QoY29udGFpbnMoJ0F1dGhvcml6YXRpb24nKSkpOwogICAgfSwKICApOwoKICB0ZXN0KAogICAgJ21vZHVsZSByZXNwZWN0cyBleHBsaWNpdCBkaXNhYmxlLCBpbmplY3RlZCBjcmVkZW50aWFscyBhbmQgdW5jb25maWd1cmVkIGF1dGgnLAogICAgKCkgYXN5bmMgewogICAgICBhZGRUZWFyRG93bihkaS5yZXNldCk7CiAgICAgIGZvciAoZmluYWwgc3VwcGxpZWQgaW4gW2ZhbHNlLCB0cnVlXSkgewogICAgICAgIGZvciAoZmluYWwgZW5hYmxlZCBpbiBbZmFsc2UsIHRydWVdKSB7CiAgICAgICAgICBhd2FpdCBkaS5yZXNldCgpOwogICAgICAgICAgZGkucmVnaXN0ZXI8TG9nZ2VyPihsb2dnZXIpOwogICAgICAgICAgZmluYWwgdG9rZW5zID0gX1Rva2VucygpOwogICAgICAgICAgYXdhaXQgbmV0d29yay5pbml0KAogICAgICAgICAgICBjb25maWc6IERlZmF1bHROZXR3b3JrQ29uZmlnKAogICAgICAgICAgICAgIGJhc2VVcmw6ICdodHRwczovL2V4YW1wbGUudGVzdCcsCiAgICAgICAgICAgICAgYXV0aFRva2VuUHJvdmlkZXI6IHN1cHBsaWVkID8gdG9rZW5zIDogbnVsbCwKICAgICAgICAgICAgKSwKICAgICAgICAgICAgdXNlQXV0aGVudGljYXRpb246IGVuYWJsZWQsCiAgICAgICAgICApOwogICAgICAgICAgZXhwZWN0KAogICAgICAgICAgICBkaS5nZXQ8TmV0d29ya0NvbmZpZz4oKS5hdXRoVG9rZW5Qcm92aWRlciwKICAgICAgICAgICAgc3VwcGxpZWQgJiYgZW5hYmxlZCA/IHNhbWUodG9rZW5zKSA6IGlzTnVsbCwKICAgICAgICAgICk7CiAgICAgICAgfQogICAgICB9CiAgICAgIGF3YWl0IGRpLnJlc2V0KCk7CiAgICAgIGRpLnJlZ2lzdGVyPExvZ2dlcj4obG9nZ2VyKTsKICAgICAgZmluYWwgdG9rZW5zID0gX1Rva2VucygpOwogICAgICBkaS5yZWdpc3RlcjxBdXRoVG9rZW5Qcm92aWRlcj4odG9rZW5zKTsKICAgICAgYXdhaXQgbmV0d29yay5pbml0KAogICAgICAgIGNvbmZpZzogRGVmYXVsdE5ldHdvcmtDb25maWcoYmFzZVVybDogJ2h0dHBzOi8vZXhhbXBsZS50ZXN0JyksCiAgICAgICk7CiAgICAgIGV4cGVjdChkaS5nZXQ8TmV0d29ya0NvbmZpZz4oKS5hdXRoVG9rZW5Qcm92aWRlciwgc2FtZSh0b2tlbnMpKTsKICAgIH0sCiAgKTsKCiAgdGVzdCgncGxhaW4gSlNPTiB1c2VzIHRoZSBzdXBwbGllZCBkZWNvZGVyJywgKCkgYXN5bmMgewogICAgYWRhcHRlci5ib2R5ID0geydjb3VudCc6IDd9OwogICAgZmluYWwgcmVzcG9uc2UgPSBhd2FpdCBjbGllbnQuZ2V0PGludD4oCiAgICAgICcvY291bnQnLAogICAgICBmcm9tSnNvblQ6IChqc29uKSA9PiAoanNvbiBhcyBNYXApWydjb3VudCddIGFzIGludCwKICAgICk7CiAgICBleHBlY3QocmVzcG9uc2UuaXNTdWNjZXNzLCBpc1RydWUpOwogICAgZXhwZWN0KGNsaWVudC5oYW5kbGVSZXNwb25zZShyZXNwb25zZSksIDcpOwogICAgZXhwZWN0KGNsaWVudC5oYW5kbGVTdWNjZXNzUmVzcG9uc2UocmVzcG9uc2UpLmRhdGEsIDcpOwogIH0pOwoKICB0ZXN0KCdBUEkgZXJyb3JzIGluIEhUVFAgMjAwIHN0YXkgZXJyb3JzJywgKCkgYXN5bmMgewogICAgYWRhcHRlci5ib2R5ID0gewogICAgICAnc3VjY2Vzcyc6IGZhbHNlLAogICAgICAndGltZXN0YW1wJzogJzIwMjYtMDEtMDEnLAogICAgICAnbWVzc2FnZSc6ICdDYW5ub3Qgc2F2ZScsCiAgICAgICdlcnJvcic6IHsnY29kZSc6ICdJTlZBTElEJywgJ21lc3NhZ2UnOiAnSW52YWxpZCBpbnB1dCd9LAogICAgfTsKICAgIGZpbmFsIHJlc3BvbnNlID0gYXdhaXQgY2xpZW50LnBvc3Q8U3RyaW5nPigKICAgICAgJy9zYXZlJywKICAgICAgZnJvbUpzb25UOiAoanNvbikgPT4ganNvbiBhcyBTdHJpbmcsCiAgICApOwogICAgZXhwZWN0KHJlc3BvbnNlLCBpc0E8RXJyb3JSZXNwb25zZTxTdHJpbmc+PigpKTsKICAgIGV4cGVjdChyZXNwb25zZS5pc1N1Y2Nlc3MsIGlzRmFsc2UpOwogICAgZXhwZWN0KChyZXNwb25zZSBhcyBFcnJvclJlc3BvbnNlKS5lcnJvci5jb2RlLCAnSU5WQUxJRCcpOwogICAgZXhwZWN0KAogICAgICAoKSA9PiBjbGllbnQuaGFuZGxlUmVzcG9uc2UocmVzcG9uc2UpLAogICAgICB0aHJvd3NBKGlzQTxOZXR3b3JrRXhjZXB0aW9uPigpKSwKICAgICk7CiAgfSk7CgogIHRlc3QoJ2VudmVsb3BlIHN1Y2Nlc3MgZGVjb2RlcyBkYXRhIGFuZCByZXRhaW5zIG1ldGFkYXRhJywgKCkgYXN5bmMgewogICAgYWRhcHRlci5ib2R5ID0gewogICAgICAnc3VjY2Vzcyc6IHRydWUsCiAgICAgICd0aW1lc3RhbXAnOiAnMjAyNi0wMS0wMScsCiAgICAgICdkYXRhJzogeydjb3VudCc6IDN9LAogICAgfTsKICAgIGZpbmFsIHJlc3BvbnNlID0gYXdhaXQgY2xpZW50LmdldDxpbnQ+KAogICAgICAnL2NvdW50JywKICAgICAgZnJvbUpzb25UOiAoanNvbikgPT4gKGpzb24gYXMgTWFwKVsnY291bnQnXSBhcyBpbnQsCiAgICApOwogICAgZXhwZWN0KGNsaWVudC5oYW5kbGVSZXNwb25zZShyZXNwb25zZSksIDMpOwogICAgZXhwZWN0KHJlc3BvbnNlLnRpbWVzdGFtcCwgJzIwMjYtMDEtMDEnKTsKICB9KTsKCiAgdGVzdCgnaW52YWxpZCBwYXlsb2FkIGJlY29tZXMgYSBwYXJzZSBlcnJvcicsICgpIGFzeW5jIHsKICAgIGFkYXB0ZXIuYm9keSA9ICdpbnZhbGlkJzsKICAgIGZpbmFsIHJlc3BvbnNlID0gYXdhaXQgY2xpZW50LmdldDxpbnQ+KAogICAgICAnL2NvdW50JywKICAgICAgZnJvbUpzb25UOiAoanNvbikgPT4ganNvbiBhcyBpbnQsCiAgICApOwogICAgZXhwZWN0KHJlc3BvbnNlLCBpc0E8RXJyb3JSZXNwb25zZTxpbnQ+PigpKTsKICAgIGV4cGVjdCgocmVzcG9uc2UgYXMgRXJyb3JSZXNwb25zZSkuZXJyb3IuY29kZSwgJ1BBUlNFX0VSUk9SJyk7CiAgfSk7CgogIGZvciAoZmluYWwgbWV0aG9kIGluIFsnR0VUJywgJ1BPU1QnLCAnUFVUJywgJ1BBVENIJywgJ0RFTEVURSddKSB7CiAgICB0ZXN0KCckbWV0aG9kIGZvcndhcmRzIHF1ZXJ5IGFuZCBoZWFkZXJzIGFuZCBkZWNvZGVzIHJlc3BvbnNlJywgKCkgYXN5bmMgewogICAgICBhZGFwdGVyLmJvZHkgPSA4OwogICAgICBmaW5hbCByZXF1ZXN0ID0gc3dpdGNoIChtZXRob2QpIHsKICAgICAgICAnUE9TVCcgPT4gY2xpZW50LnBvc3Q8aW50PiwKICAgICAgICAnUFVUJyA9PiBjbGllbnQucHV0PGludD4sCiAgICAgICAgJ1BBVENIJyA9PiBjbGllbnQucGF0Y2g8aW50PiwKICAgICAgICAnREVMRVRFJyA9PiBjbGllbnQuZGVsZXRlPGludD4sCiAgICAgICAgXyA9PiBjbGllbnQuZ2V0PGludD4sCiAgICAgIH07CiAgICAgIGZpbmFsIHJlc3BvbnNlID0gYXdhaXQgcmVxdWVzdCgKICAgICAgICAnL2l0ZW1zJywKICAgICAgICBxdWVyeVBhcmFtZXRlcnM6IHsncGFnZSc6IDJ9LAogICAgICAgIGhlYWRlcnM6IHsnWC1SZXF1ZXN0JzogJ3Rlc3QnfSwKICAgICAgICBmcm9tSnNvblQ6IChqc29uKSA9PiBqc29uIGFzIGludCwKICAgICAgKTsKICAgICAgZXhwZWN0KGNsaWVudC5oYW5kbGVSZXNwb25zZShyZXNwb25zZSksIDgpOwogICAgICBleHBlY3QoYWRhcHRlci5yZXF1ZXN0cy5zaW5nbGUubWV0aG9kLCBtZXRob2QpOwogICAgICBleHBlY3QoYWRhcHRlci5yZXF1ZXN0cy5zaW5nbGUucXVlcnlQYXJhbWV0ZXJzLCB7J3BhZ2UnOiAyfSk7CiAgICAgIGV4cGVjdChhZGFwdGVyLnJlcXVlc3RzLnNpbmdsZS5oZWFkZXJzWydYLVJlcXVlc3QnXSwgJ3Rlc3QnKTsKICAgIH0pOwogIH0KCiAgdGVzdCgndW5hdXRob3JpemVkIEhUVFAgcmVzcG9uc2VzIHRocm93IGEgdHlwZWQgZXhjZXB0aW9uJywgKCkgYXN5bmMgewogICAgYWRhcHRlci5zdGF0dXMgPSA0MDE7CiAgICBhZGFwdGVyLmJvZHkgPSB7J21lc3NhZ2UnOiAnVW5hdXRob3JpemVkJ307CiAgICBhd2FpdCBleHBlY3RMYXRlcigKICAgICAgY2xpZW50LmdldDxpbnQ+KCcvcHJpdmF0ZScsIGZyb21Kc29uVDogKGpzb24pID0+IGpzb24gYXMgaW50KSwKICAgICAgdGhyb3dzQShpc0E8VW5hdXRob3JpemVkRXhjZXB0aW9uPigpKSwKICAgICk7CiAgfSk7CgogIHRlc3QoJ2xvZ3MgZG8gbm90IGNvbnRhaW4gY3JlZGVudGlhbHMsIHF1ZXJ5IHZhbHVlcyBvciBwYXlsb2FkcycsICgpIGFzeW5jIHsKICAgIGFkYXB0ZXIuYm9keSA9IHsnc2VjcmV0JzogJ3Jlc3BvbnNlLXNlY3JldCd9OwogICAgYXdhaXQgY2xpZW50LnBvc3Q8T2JqZWN0Pz4oCiAgICAgICcvaXRlbXMnLAogICAgICBoZWFkZXJzOiB7J0F1dGhvcml6YXRpb24nOiAnQmVhcmVyIGhlYWRlci1zZWNyZXQnfSwKICAgICAgcXVlcnlQYXJhbWV0ZXJzOiB7J3Rva2VuJzogJ3F1ZXJ5LXNlY3JldCd9LAogICAgICBkYXRhOiB7J3Bhc3N3b3JkJzogJ2JvZHktc2VjcmV0J30sCiAgICAgIGZyb21Kc29uVDogKGpzb24pID0+IGpzb24sCiAgICApOwogICAgZXhwZWN0KGxvZ2dlci5tZXNzYWdlcy5qb2luKCdcbicpLCBpc05vdChjb250YWlucygnc2VjcmV0JykpKTsKICB9KTsKCiAgdGVzdCgnZGlzcG9zZSBjbG9zZXMgdGhlIHRyYW5zcG9ydCcsICgpIHsKICAgIGNsaWVudC5kaXNwb3NlKCk7CiAgICBleHBlY3QoYWRhcHRlci5jbG9zZWQsIGlzVHJ1ZSk7CiAgfSk7CgogIGdyb3VwKCdhdXRoZW50aWNhdGlvbiByZXRyaWVzJywgKCkgewogICAgbGF0ZSBfVG9rZW5zIHRva2VuczsKICAgIHNldFVwKCgpIHsKICAgICAgY2xpZW50LmRpc3Bvc2UoKTsKICAgICAgYWRhcHRlciA9IF9BZGFwdGVyKCkuLmJvZHkgPSA5OwogICAgICB0b2tlbnMgPSBfVG9rZW5zKCk7CiAgICAgIGNsaWVudCA9IERpb05ldHdvcmtDbGllbnQoCiAgICAgICAgRGVmYXVsdE5ldHdvcmtDb25maWcoCiAgICAgICAgICBiYXNlVXJsOiAnaHR0cHM6Ly9leGFtcGxlLnRlc3QnLAogICAgICAgICAgYXV0aFRva2VuUHJvdmlkZXI6IHRva2VucywKICAgICAgICApLAogICAgICAgIGxvZ2dlcjogbG9nZ2VyLAogICAgICAgIGRpbzogRGlvKCkuLmh0dHBDbGllbnRBZGFwdGVyID0gYWRhcHRlciwKICAgICAgKTsKICAgIH0pOwoKICAgIHRlc3QoJ3VzZXMgdGhlIGNvbmZpZ3VyZWQgdHJhbnNwb3J0IGFuZCByZWZyZXNoZXMgb25jZScsICgpIGFzeW5jIHsKICAgICAgYWRhcHRlci5zdGF0dXNlcy5hZGRBbGwoWzQwMSwgMjAwXSk7CiAgICAgIGZpbmFsIHJlc3BvbnNlID0gYXdhaXQgY2xpZW50LmdldDxpbnQ+KAogICAgICAgICcvaXRlbXMnLAogICAgICAgIGZyb21Kc29uVDogKGpzb24pID0+IGpzb24gYXMgaW50LAogICAgICApOwogICAgICBleHBlY3QoY2xpZW50LmhhbmRsZVJlc3BvbnNlKHJlc3BvbnNlKSwgOSk7CiAgICAgIGV4cGVjdChhZGFwdGVyLnJlcXVlc3RzLCBoYXNMZW5ndGgoMikpOwogICAgICBleHBlY3QoCiAgICAgICAgYWRhcHRlci5yZXF1ZXN0cy5sYXN0LmhlYWRlcnNbJ0F1dGhvcml6YXRpb24nXSwKICAgICAgICAnQmVhcmVyIG5ldy10b2tlbicsCiAgICAgICk7CiAgICAgIGV4cGVjdCh0b2tlbnMucmVmcmVzaGVzLCAxKTsKICAgIH0pOwoKICAgIHRlc3QoJ2EgcmVwZWF0ZWQgNDAxIGRvZXMgbm90IGxvb3AnLCAoKSBhc3luYyB7CiAgICAgIGFkYXB0ZXIuc3RhdHVzID0gNDAxOwogICAgICBhd2FpdCBleHBlY3RMYXRlcigKICAgICAgICBjbGllbnQuZ2V0PGludD4oJy9pdGVtcycsIGZyb21Kc29uVDogKGpzb24pID0+IGpzb24gYXMgaW50KSwKICAgICAgICB0aHJvd3NBKGlzQTxVbmF1dGhvcml6ZWRFeGNlcHRpb24+KCkpLAogICAgICApOwogICAgICBleHBlY3QoYWRhcHRlci5yZXF1ZXN0cywgaGFzTGVuZ3RoKDIpKTsKICAgICAgZXhwZWN0KHRva2Vucy5yZWZyZXNoZXMsIDEpOwogICAgfSk7CgogICAgdGVzdCgnY2FsbGVyIGF1dGhvcml6YXRpb24gaXMgcmVzcGVjdGVkIGNhc2UtaW5zZW5zaXRpdmVseScsICgpIGFzeW5jIHsKICAgICAgYWRhcHRlci5zdGF0dXMgPSA0MDE7CiAgICAgIGF3YWl0IGV4cGVjdExhdGVyKAogICAgICAgIGNsaWVudC5nZXQ8aW50PigKICAgICAgICAgICcvaXRlbXMnLAogICAgICAgICAgaGVhZGVyczogeydhdXRob3JpemF0aW9uJzogJ2N1c3RvbSd9LAogICAgICAgICAgZnJvbUpzb25UOiAoanNvbikgPT4ganNvbiBhcyBpbnQsCiAgICAgICAgKSwKICAgICAgICB0aHJvd3NBKGlzQTxVbmF1dGhvcml6ZWRFeGNlcHRpb24+KCkpLAogICAgICApOwogICAgICBleHBlY3QoYWRhcHRlci5yZXF1ZXN0cywgaGFzTGVuZ3RoKDEpKTsKICAgICAgZXhwZWN0KGFkYXB0ZXIucmVxdWVzdHMuc2luZ2xlLmhlYWRlcnNbJ2F1dGhvcml6YXRpb24nXSwgJ2N1c3RvbScpOwogICAgICBleHBlY3QodG9rZW5zLnJlZnJlc2hlcywgMCk7CiAgICB9KTsKCiAgICBmb3IgKGZpbmFsIGZhaWxzIGluIFt0cnVlLCBmYWxzZV0pIHsKICAgICAgdGVzdCgKICAgICAgICAndW5hdmFpbGFibGUgcmVmcmVzaGVkIHRva2VuIHByZXNlcnZlcyB0aGUgb3JpZ2luYWwgZXJyb3IgKCRmYWlscyknLAogICAgICAgICgpIGFzeW5jIHsKICAgICAgICAgIHRva2Vucy5mYWlsUmVmcmVzaCA9IGZhaWxzOwogICAgICAgICAgdG9rZW5zLnJlZnJlc2hlZCA9IG51bGw7CiAgICAgICAgICBhZGFwdGVyLnN0YXR1cyA9IDQwMTsKICAgICAgICAgIGF3YWl0IGV4cGVjdExhdGVyKAogICAgICAgICAgICBjbGllbnQuZ2V0PGludD4oJy9pdGVtcycsIGZyb21Kc29uVDogKGpzb24pID0+IGpzb24gYXMgaW50KSwKICAgICAgICAgICAgdGhyb3dzQShpc0E8VW5hdXRob3JpemVkRXhjZXB0aW9uPigpKSwKICAgICAgICAgICk7CiAgICAgICAgICBleHBlY3QoYWRhcHRlci5yZXF1ZXN0cywgaGFzTGVuZ3RoKDEpKTsKICAgICAgICB9LAogICAgICApOwogICAgfQogIH0pOwp9Cg==", + "type": "text" + }, + { + "path": + "{{ name.snakeCase() }}/packages/{{network_dir}}/test/models_test.dart", + "data": + "aW1wb3J0ICdwYWNrYWdlOmNvcmUvY29yZS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZsdXR0ZXJfdGVzdC9mbHV0dGVyX3Rlc3QuZGFydCc7CmltcG9ydCAncGFja2FnZTpuZXR3b3JrL25ldHdvcmsuZGFydCc7CgpjbGFzcyBfQmFzZUVycm9yIGV4dGVuZHMgTmV0d29ya0V4Y2VwdGlvbiB7fQoKY2xhc3MgX090aGVyRXJyb3IgZXh0ZW5kcyBFcnJvciB7fQoKY2xhc3MgX1VybHMgZXh0ZW5kcyBBcGlVcmxDb25maWcgewogIF9VcmxzKCkgOiBzdXBlcihwYXRoUHJlZml4OiAnL3YxJyk7Cn0KCmNsYXNzIF9BcGkgZXh0ZW5kcyBOZXR3b3JrQXBpPF9VcmxzPiB7CiAgX0FwaSgpIDogc3VwZXIodXJsQ29uZmlnOiBfVXJscygpKTsKICBAb3ZlcnJpZGUKICBNYXA8U3RyaW5nLCBTdHJpbmc+IGdldCBoZWFkZXJzID0+IHt9Owp9Cgp2b2lkIG1haW4oKSB7CiAgdGVzdCgnbmV0d29yayBmYWlsdXJlcyBwcm92aWRlIHJlYWRhYmxlIGxvY2FsaXplZCBtZXNzYWdlcyBhbmQgc3RhdHVzZXMnLCAoKSB7CiAgICBmaW5hbCBlcnJvcnMgPSA8TmV0d29ya0V4Y2VwdGlvbj5bCiAgICAgIF9CYXNlRXJyb3IoKSwKICAgICAgY29uc3QgQmFkUmVxdWVzdEV4Y2VwdGlvbigpLAogICAgICBjb25zdCBVbmF1dGhvcml6ZWRFeGNlcHRpb24oKSwKICAgICAgY29uc3QgRm9yYmlkZGVuRXhjZXB0aW9uKCksCiAgICAgIGNvbnN0IE5vdEZvdW5kRXhjZXB0aW9uKCksCiAgICAgIGNvbnN0IENvbmZsaWN0RXhjZXB0aW9uKCksCiAgICAgIGNvbnN0IFVucHJvY2Vzc2FibGVFbnRpdHlFeGNlcHRpb24oKSwKICAgICAgY29uc3QgSW50ZXJuYWxTZXJ2ZXJFeGNlcHRpb24oKSwKICAgICAgY29uc3QgQ29ubmVjdGlvblRpbWVvdXRFeGNlcHRpb24oKSwKICAgICAgY29uc3QgUmVjZWl2ZVRpbWVvdXRFeGNlcHRpb24oKSwKICAgICAgY29uc3QgU2VuZFRpbWVvdXRFeGNlcHRpb24oKSwKICAgICAgY29uc3QgTm9JbnRlcm5ldENvbm5lY3Rpb25FeGNlcHRpb24oKSwKICAgICAgY29uc3QgVW5rbm93bk5ldHdvcmtFeGNlcHRpb24oKSwKICAgIF07CiAgICBmb3IgKGZpbmFsIGVycm9yIGluIGVycm9ycykgewogICAgICBleHBlY3QoZXJyb3IuZGlzcGxheU1lc3NhZ2UsIGlzTm90RW1wdHkpOwogICAgICBleHBlY3QoZXJyb3IudG9TdHJpbmcoKSwgY29udGFpbnMoZXJyb3IuZGlzcGxheU1lc3NhZ2UpKTsKICAgICAgZXhwZWN0KChlcnJvciBhcyBPYmplY3QpLm1lc3NhZ2UoKSwgZXJyb3IuZGlzcGxheU1lc3NhZ2UpOwogICAgfQogICAgZXhwZWN0KAogICAgICBjb25zdCBVbmF1dGhvcml6ZWRFeGNlcHRpb24obWVzc2FnZTogJ0N1c3RvbScpLmRpc3BsYXlNZXNzYWdlLAogICAgICAnQ3VzdG9tJywKICAgICk7CiAgICBleHBlY3QoY29uc3QgVW5hdXRob3JpemVkRXhjZXB0aW9uKCkuc3RhdHVzQ29kZSwgNDAxKTsKICAgIGZpbmFsIGFwaSA9IF9BcGkoKTsKICAgIGV4cGVjdChhcGkudXJsQ29uZmlnLnBhdGhQcmVmaXgsICcvdjEnKTsKICAgIGV4cGVjdChhcGkuaGVhZGVycywgaXNFbXB0eSk7CiAgfSk7CgogIHRlc3QoJ2FwcGxpY2F0aW9uIGVycm9ycyBtYXAgdG8gcmVhZGFibGUgbWVzc2FnZXMgd2l0aCBkaWFnbm9zdGljIGNvZGVzJywgKCkgewogICAgVHlwZUVycm9yPyB0eXBlRXJyb3I7CiAgICB0cnkgewogICAgICBmaW5hbCBkeW5hbWljIHZhbHVlID0gJ25vdCBhIG51bWJlcic7CiAgICAgIHZhbHVlIGFzIGludDsKICAgIH0gb24gVHlwZUVycm9yIGNhdGNoIChlcnJvcikgewogICAgICB0eXBlRXJyb3IgPSBlcnJvcjsKICAgIH0KICAgIGZpbmFsIGVycm9ycyA9IDxPYmplY3Q/PlsKICAgICAgQ29yZUV4Y2VwdGlvbihtZXNzYWdlOiAnQ29yZSBlcnJvcicpLAogICAgICBjb25zdCBGb3JtYXRFeGNlcHRpb24oJ2ludmFsaWQnKSwKICAgICAgdHlwZUVycm9yLAogICAgICBJbmRleEVycm9yLndpdGhMZW5ndGgoMiwgMSksCiAgICAgIFJhbmdlRXJyb3IoJ3JhbmdlJyksCiAgICAgIEFyZ3VtZW50RXJyb3IoJ2FyZycpLAogICAgICBTdGF0ZUVycm9yKCdzdGF0ZScpLAogICAgICBVbmltcGxlbWVudGVkRXJyb3IoKSwKICAgICAgVW5zdXBwb3J0ZWRFcnJvcigndW5zdXBwb3J0ZWQnKSwKICAgICAgQ29uY3VycmVudE1vZGlmaWNhdGlvbkVycm9yKCksCiAgICAgIGNvbnN0IE91dE9mTWVtb3J5RXJyb3IoKSwKICAgICAgY29uc3QgU3RhY2tPdmVyZmxvd0Vycm9yKCksCiAgICAgIF9PdGhlckVycm9yKCksCiAgICAgIG51bGwsCiAgICBdOwogICAgZm9yIChmaW5hbCBlcnJvciBpbiBlcnJvcnMpIHsKICAgICAgZXhwZWN0KGVycm9yLm1lc3NhZ2UoKSwgaXNOb3RFbXB0eSk7CiAgICB9CiAgICBleHBlY3QoCiAgICAgIChDb3JlRXhjZXB0aW9uKG1lc3NhZ2U6ICdDb3JlIGVycm9yJykgYXMgT2JqZWN0KS5tZXNzYWdlKCksCiAgICAgICdDb3JlIGVycm9yJywKICAgICk7CiAgICBleHBlY3QoCiAgICAgIChTdGF0ZUVycm9yKCdzdGF0ZScpIGFzIEVycm9yKS5tZXNzYWdlKCksCiAgICAgIGNvbnRhaW5zKEVycm9yQ29kZXMuc3RhdGVFcnJvciksCiAgICApOwogIH0pOwoKICB0ZXN0KCdzdWNjZXNzLCBlcnJvciBhbmQgcGFnaW5hdGlvbiBtZXRhZGF0YSByb3VuZC10cmlwIEpTT04nLCAoKSB7CiAgICBjb25zdCBwYWdpbmF0aW9uID0gUGFnaW5hdGlvbigKICAgICAgcGFnZTogMSwKICAgICAgbGltaXQ6IDEwLAogICAgICB0b3RhbDogMjAsCiAgICAgIHRvdGFsUGFnZXM6IDIsCiAgICAgIGhhc05leHRQYWdlOiB0cnVlLAogICAgICBoYXNQcmV2aW91c1BhZ2U6IGZhbHNlLAogICAgKTsKICAgIGNvbnN0IHN1Y2Nlc3MgPSBTdWNjZXNzUmVzcG9uc2U8aW50PigKICAgICAgc3RhdHVzQ29kZTogMjAwLAogICAgICBzdWNjZXNzOiB0cnVlLAogICAgICBkYXRhOiAzLAogICAgICB0aW1lc3RhbXA6ICcyMDI2JywKICAgICAgcGFnaW5hdGlvbjogcGFnaW5hdGlvbiwKICAgICAgaGVhZGVyczogewogICAgICAgICd4JzogWyd5J10sCiAgICAgIH0sCiAgICApOwogICAgZmluYWwganNvbiA9IHN1Y2Nlc3MudG9Kc29uKCh2YWx1ZSkgPT4gdmFsdWUpOwogICAgLy8gdG9Kc29uIGludGVudGlvbmFsbHkgcmV0YWlucyBuZXN0ZWQgb2JqZWN0cyB1bnRpbCBKU09OIGVuY29kaW5nLgogICAganNvblsncGFnaW5hdGlvbiddID0gcGFnaW5hdGlvbi50b0pzb24oKTsKICAgIGZpbmFsIGRlY29kZWQgPSBTdWNjZXNzUmVzcG9uc2U8aW50Pi5mcm9tSnNvbigKICAgICAganNvbiwKICAgICAgKHZhbHVlKSA9PiB2YWx1ZSBhcyBpbnQsCiAgICApOwogICAgZXhwZWN0KGRlY29kZWQuZGF0YSwgMyk7CiAgICBleHBlY3QoZGVjb2RlZC5wYWdpbmF0aW9uIS5oYXNOZXh0UGFnZSwgaXNUcnVlKTsKICAgIGV4cGVjdChkZWNvZGVkLmlzU3VjY2VzcywgaXNUcnVlKTsKICAgIGNvbnN0IGRldGFpbHMgPSBFcnJvckRldGFpbHMoCiAgICAgIGNvZGU6ICdJTlZBTElEJywKICAgICAgbWVzc2FnZTogJ0ludmFsaWQnLAogICAgICBkZXRhaWxzOiB7J2ZpZWxkJzogJ2VtYWlsJ30sCiAgICApOwogICAgY29uc3QgZXJyb3IgPSBFcnJvclJlc3BvbnNlPGludD4oCiAgICAgIHN0YXR1c0NvZGU6IDQwMCwKICAgICAgc3VjY2VzczogZmFsc2UsCiAgICAgIGVycm9yOiBkZXRhaWxzLAogICAgICB0aW1lc3RhbXA6ICcyMDI2JywKICAgICk7CiAgICBmaW5hbCBlcnJvckpzb24gPSBlcnJvci50b0pzb24oKS4uWydlcnJvciddID0gZGV0YWlscy50b0pzb24oKTsKICAgIGV4cGVjdChFcnJvclJlc3BvbnNlPGludD4uZnJvbUpzb24oZXJyb3JKc29uKS5lcnJvci5jb2RlLCAnSU5WQUxJRCcpOwogICAgZXhwZWN0KEVycm9yRGV0YWlscy5mcm9tSnNvbihkZXRhaWxzLnRvSnNvbigpKS5kZXRhaWxzLCB7J2ZpZWxkJzogJ2VtYWlsJ30pOwogICAgZXhwZWN0KGVycm9yLmlzU3VjY2VzcywgaXNGYWxzZSk7CiAgfSk7Cn0K", + "type": "text" + }, { "path": "{{ name.snakeCase() }}/packages/{{network_dir}}/test/network_test.dart", @@ -1249,18 +1420,25 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "aW1wb3J0ICdwYWNrYWdlOmZsdXR0ZXJfdGVzdC9mbHV0dGVyX3Rlc3QuZGFydCc7CmltcG9ydCAncGFja2FnZTpuZXR3b3JrL25ldHdvcmsuZGFydCc7Cgp2b2lkIG1haW4oKSB7CiAgdGVzdCgnRGVmYXVsdE5ldHdvcmtDb25maWcgY3JlYXRlcyBpbnN0YW5jZSB3aXRoIHByb3ZpZGVkIHZhbHVlcycsICgpIHsKICAgIGNvbnN0IGNvbmZpZyA9IERlZmF1bHROZXR3b3JrQ29uZmlnKAogICAgICBiYXNlVXJsOiAnaHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20nLAogICAgICBlbmFibGVMb2dnaW5nOiB0cnVlLAogICAgKTsKCiAgICBleHBlY3QoY29uZmlnLmJhc2VVcmwsICdodHRwczovL2FwaS5leGFtcGxlLmNvbScpOwogICAgZXhwZWN0KGNvbmZpZy5lbmFibGVMb2dnaW5nLCB0cnVlKTsKICAgIGV4cGVjdChjb25maWcuY29ubmVjdFRpbWVvdXQsIGNvbnN0IER1cmF0aW9uKHNlY29uZHM6IDMwKSk7CiAgfSk7Cn0K", "type": "text" }, + { + "path": + "{{ name.snakeCase() }}/packages/{{network_dir}}/test/response_contract_test.dart", + "data": + "aW1wb3J0ICdwYWNrYWdlOmNvcmUvY29yZS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRpby9kaW8uZGFydCc7CmltcG9ydCAncGFja2FnZTpmbHV0dGVyX3Rlc3QvZmx1dHRlcl90ZXN0LmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6bW9ja3RhaWwvbW9ja3RhaWwuZGFydCc7CmltcG9ydCAncGFja2FnZTpuZXR3b3JrL25ldHdvcmsuZGFydCc7CgpjbGFzcyBfRGlvIGV4dGVuZHMgTW9jayBpbXBsZW1lbnRzIERpbyB7fQoKY2xhc3MgX0xvZ2dlciBleHRlbmRzIE1vY2sgaW1wbGVtZW50cyBMb2dnZXIge30KCmNsYXNzIF9Vbmtub3duUmVzcG9uc2UgZXh0ZW5kcyBOZXR3b3JrUmVzcG9uc2U8aW50PiB7CiAgY29uc3QgX1Vua25vd25SZXNwb25zZSgpCiAgICA6IHN1cGVyKHN0YXR1c0NvZGU6IDIwMiwgc3VjY2VzczogZmFsc2UsIHRpbWVzdGFtcDogJ25vdycpOwp9Cgp2b2lkIG1haW4oKSB7CiAgc2V0VXBBbGwoKCkgPT4gcmVnaXN0ZXJGYWxsYmFja1ZhbHVlKE9wdGlvbnMoKSkpOwogIHRlc3QoCiAgICAndW5leHBlY3RlZCB0cmFuc3BvcnQgZmFpbHVyZXMgYXJlIG5vcm1hbGl6ZWQgYXQgdGhlIGNsaWVudCBib3VuZGFyeScsCiAgICAoKSBhc3luYyB7CiAgICAgIGZpbmFsIGRpbyA9IF9EaW8oKTsKICAgICAgd2hlbigoKSA9PiBkaW8uaW50ZXJjZXB0b3JzKS50aGVuUmV0dXJuKEludGVyY2VwdG9ycygpKTsKICAgICAgd2hlbigKICAgICAgICAoKSA9PiBkaW8uZ2V0PE9iamVjdD8+KGFueSgpLCBvcHRpb25zOiBhbnkobmFtZWQ6ICdvcHRpb25zJykpLAogICAgICApLnRoZW5UaHJvdyhTdGF0ZUVycm9yKCd0cmFuc3BvcnQnKSk7CiAgICAgIGZpbmFsIGNsaWVudCA9IERpb05ldHdvcmtDbGllbnQoCiAgICAgICAgY29uc3QgRGVmYXVsdE5ldHdvcmtDb25maWcoYmFzZVVybDogJ2h0dHBzOi8vZXhhbXBsZS50ZXN0JyksCiAgICAgICAgbG9nZ2VyOiBfTG9nZ2VyKCksCiAgICAgICAgZGlvOiBkaW8sCiAgICAgICk7CiAgICAgIGFkZFRlYXJEb3duKGNsaWVudC5kaXNwb3NlKTsKICAgICAgYXdhaXQgZXhwZWN0TGF0ZXIoCiAgICAgICAgY2xpZW50LmdldDxPYmplY3Q/PignL3JlcXVlc3QnLCBmcm9tSnNvblQ6IChqc29uKSA9PiBqc29uKSwKICAgICAgICB0aHJvd3NBKGlzQTxVbmtub3duTmV0d29ya0V4Y2VwdGlvbj4oKSksCiAgICAgICk7CiAgICB9LAogICk7CgogIHRlc3QoCiAgICAncmVzcG9uc2UgaGFuZGxlcnMgcHJlc2VydmUgbnVsbGFibGUgc3VjY2Vzc2VzIGFuZCByZWplY3QgdW5zdXBwb3J0ZWQgb3IgZmFpbGVkIGVudmVsb3BlcycsCiAgICAoKSB7CiAgICAgIGZpbmFsIGNsaWVudCA9IERpb05ldHdvcmtDbGllbnQoCiAgICAgICAgY29uc3QgRGVmYXVsdE5ldHdvcmtDb25maWcoYmFzZVVybDogJ2h0dHBzOi8vZXhhbXBsZS50ZXN0JyksCiAgICAgICAgbG9nZ2VyOiBfTG9nZ2VyKCksCiAgICAgICk7CiAgICAgIGFkZFRlYXJEb3duKGNsaWVudC5kaXNwb3NlKTsKICAgICAgY29uc3Qgc3VjY2VzcyA9IFN1Y2Nlc3NSZXNwb25zZTxTdHJpbmc/PigKICAgICAgICBzdGF0dXNDb2RlOiAyMDQsCiAgICAgICAgc3VjY2VzczogdHJ1ZSwKICAgICAgICBkYXRhOiBudWxsLAogICAgICAgIHRpbWVzdGFtcDogJ25vdycsCiAgICAgICk7CiAgICAgIGV4cGVjdChjbGllbnQuaGFuZGxlUmVzcG9uc2Uoc3VjY2VzcyksIGlzTnVsbCk7CiAgICAgIGV4cGVjdChjbGllbnQuaGFuZGxlU3VjY2Vzc1Jlc3BvbnNlKHN1Y2Nlc3MpLCBzYW1lKHN1Y2Nlc3MpKTsKICAgICAgY29uc3QgZXJyb3IgPSBFcnJvclJlc3BvbnNlPGludD4oCiAgICAgICAgc3RhdHVzQ29kZTogMjAwLAogICAgICAgIHN1Y2Nlc3M6IGZhbHNlLAogICAgICAgIHRpbWVzdGFtcDogJ25vdycsCiAgICAgICAgZXJyb3I6IEVycm9yRGV0YWlscyhjb2RlOiAnSU5WQUxJRCcsIG1lc3NhZ2U6ICdSZWplY3RlZCcpLAogICAgICApOwogICAgICBleHBlY3QoCiAgICAgICAgKCkgPT4gY2xpZW50LmhhbmRsZVN1Y2Nlc3NSZXNwb25zZShlcnJvciksCiAgICAgICAgdGhyb3dzQShpc0E8VW5rbm93bk5ldHdvcmtFeGNlcHRpb24+KCkpLAogICAgICApOwogICAgICBleHBlY3QoCiAgICAgICAgKCkgPT4gY2xpZW50LmhhbmRsZVJlc3BvbnNlKGVycm9yKSwKICAgICAgICB0aHJvd3NBKGlzQTxVbmtub3duTmV0d29ya0V4Y2VwdGlvbj4oKSksCiAgICAgICk7CiAgICAgIGV4cGVjdCgKICAgICAgICAoKSA9PiBjbGllbnQuaGFuZGxlUmVzcG9uc2UoY29uc3QgX1Vua25vd25SZXNwb25zZSgpKSwKICAgICAgICB0aHJvd3NBKGlzQTxVbmtub3duTmV0d29ya0V4Y2VwdGlvbj4oKSksCiAgICAgICk7CiAgICAgIGV4cGVjdCgKICAgICAgICAoKSA9PiBjbGllbnQuaGFuZGxlU3VjY2Vzc1Jlc3BvbnNlKGNvbnN0IF9Vbmtub3duUmVzcG9uc2UoKSksCiAgICAgICAgdGhyb3dzQShpc0E8VW5rbm93bk5ldHdvcmtFeGNlcHRpb24+KCkpLAogICAgICApOwogICAgfSwKICApOwp9Cg==", + "type": "text" + }, { "path": "{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/notifications.dart", "data": - "bGlicmFyeTsKCmltcG9ydCAnZGFydDphc3luYyc7CgppbXBvcnQgJ3BhY2thZ2U6Y29yZS9jb3JlLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZGkvZGkuZGFydCc7CmltcG9ydCAncGFja2FnZTpub3RpZmljYXRpb25zL3NyYy9jb25maWcvaW5kZXguZGFydCc7CmltcG9ydCAncGFja2FnZTpub3RpZmljYXRpb25zL3NyYy9kaS9pbmRleC5kYXJ0JzsKCmV4cG9ydCAnc3JjL2NsaWVudC9pbmRleC5kYXJ0JzsKZXhwb3J0ICdzcmMvY29uZmlnL2luZGV4LmRhcnQnOwpleHBvcnQgJ3NyYy9kZXZpY2VfaW5mby9pbmRleC5kYXJ0JzsKZXhwb3J0ICdzcmMvZXhjZXB0aW9ucy9pbmRleC5kYXJ0JzsKZXhwb3J0ICdzcmMvbW9kZWxzL2luZGV4LmRhcnQnOwpleHBvcnQgJ3NyYy9zZXJ2aWNlcy9pbmRleC5kYXJ0JzsKCi8vLyBJbml0aWFsaXplIHRoZSBub3RpZmljYXRpb25zIG1vZHVsZSB3aXRoIGRlcGVuZGVuY3kgaW5qZWN0aW9uCkZ1dHVyZTx2b2lkPiBpbml0KHsKICBOb3RpZmljYXRpb25Db25maWcgY29uZmlnID0gY29uc3QgRGVmYXVsdE5vdGlmaWNhdGlvbkNvbmZpZygpLAp9KSBhc3luYyB7CiAgZmluYWwgbG9nZ2VyID0gZGkuZ2V0PExvZ2dlcj4oKTsKICB0cnkgewogICAgYXdhaXQgcmVnaXN0ZXJOb3RpZmljYXRpb25XaXRoREkoY29uZmlnKTsKICAgIGxvZ2dlci5pKCfwn5SUIE5vdGlmaWNhdGlvbnMgbW9kdWxlIGluaXRpYWxpemVkJyk7CiAgfSBjYXRjaCAoZSwgcykgewogICAgbG9nZ2VyLmUoJ/CflJQgRmFpbGVkIHRvIGluaXRpYWxpemUgbm90aWZpY2F0aW9ucyBtb2R1bGUnLCBlLCBzKTsKICB9Cn0K", + "bGlicmFyeTsKCmltcG9ydCAnZGFydDphc3luYyc7CgppbXBvcnQgJ3BhY2thZ2U6Y29yZS9jb3JlLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZGkvZGkuZGFydCc7CmltcG9ydCAncGFja2FnZTpmaXJlYmFzZV9tZXNzYWdpbmcvZmlyZWJhc2VfbWVzc2FnaW5nLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6bm90aWZpY2F0aW9ucy9zcmMvY29uZmlnL2luZGV4LmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6bm90aWZpY2F0aW9ucy9zcmMvZGkvaW5kZXguZGFydCc7CgpleHBvcnQgJ3NyYy9jbGllbnQvaW5kZXguZGFydCc7CmV4cG9ydCAnc3JjL2NvbmZpZy9pbmRleC5kYXJ0JzsKZXhwb3J0ICdzcmMvZGV2aWNlX2luZm8vaW5kZXguZGFydCc7CmV4cG9ydCAnc3JjL2V4Y2VwdGlvbnMvaW5kZXguZGFydCc7CmV4cG9ydCAnc3JjL21vZGVscy9pbmRleC5kYXJ0JzsKZXhwb3J0ICdzcmMvc2VydmljZXMvaW5kZXguZGFydCc7CgovLy8gSW5pdGlhbGl6ZSB0aGUgbm90aWZpY2F0aW9ucyBtb2R1bGUgd2l0aCBkZXBlbmRlbmN5IGluamVjdGlvbgpGdXR1cmU8dm9pZD4gaW5pdCh7CiAgTm90aWZpY2F0aW9uQ29uZmlnIGNvbmZpZyA9IGNvbnN0IERlZmF1bHROb3RpZmljYXRpb25Db25maWcoKSwKICBGaXJlYmFzZU1lc3NhZ2luZz8gbWVzc2FnaW5nLAp9KSBhc3luYyB7CiAgZmluYWwgbG9nZ2VyID0gZGkuZ2V0PExvZ2dlcj4oKTsKICB0cnkgewogICAgYXdhaXQgcmVnaXN0ZXJOb3RpZmljYXRpb25XaXRoREkoY29uZmlnLCBtZXNzYWdpbmc6IG1lc3NhZ2luZyk7CiAgICBsb2dnZXIuaSgn8J+UlCBOb3RpZmljYXRpb25zIG1vZHVsZSBpbml0aWFsaXplZCcpOwogIH0gY2F0Y2ggKGUsIHMpIHsKICAgIGxvZ2dlci5lKCfwn5SUIEZhaWxlZCB0byBpbml0aWFsaXplIG5vdGlmaWNhdGlvbnMgbW9kdWxlJywgZSwgcyk7CiAgICByZXRocm93OwogIH0KfQo=", "type": "text" }, { "path": "{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/src/client/firebase_notification_client.dart", "data": - "aW1wb3J0ICdkYXJ0OmFzeW5jJzsKCmltcG9ydCAncGFja2FnZTphcHBfYmFkZ2VfcGx1cy9hcHBfYmFkZ2VfcGx1cy5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmNvcmUvbG9nZ2VyL2xvZ2dlci5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRlc2lnbl9zeXN0ZW0vdG9hc3QvdG9hc3RzLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZGkvZGkuZGFydCc7CmltcG9ydCAncGFja2FnZTpmaXJlYmFzZV9tZXNzYWdpbmcvZmlyZWJhc2VfbWVzc2FnaW5nLmRhcnQnCiAgICBoaWRlIE5vdGlmaWNhdGlvblNldHRpbmdzOwppbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlci9tYXRlcmlhbC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmdvX3JvdXRlci9nb19yb3V0ZXIuZGFydCc7CmltcG9ydCAncGFja2FnZTpuZXR3b3JrL25ldHdvcmsuZGFydCc7CmltcG9ydCAncGFja2FnZTpub3RpZmljYXRpb25zL25vdGlmaWNhdGlvbnMuZGFydCc7Cgpjb25zdCBTdHJpbmcgX3RhZyA9ICdGaXJlYmFzZU5vdGlmaWNhdGlvbkNsaWVudCc7CgovLy8gRmlyZWJhc2UgaW1wbGVtZW50YXRpb24gb2YgdGhlIG5vdGlmaWNhdGlvbiBjbGllbnQKY2xhc3MgRmlyZWJhc2VOb3RpZmljYXRpb25DbGllbnQgaW1wbGVtZW50cyBOb3RpZmljYXRpb25DbGllbnQgewogIEZpcmViYXNlTm90aWZpY2F0aW9uQ2xpZW50KHsKICAgIHJlcXVpcmVkIHRoaXMuY29uZmlnLAogICAgTG9nZ2VyPyBsb2dnZXIsCiAgICBOb3RpZmljYXRpb25Ub2tlbk1hbmFnZXI/IHRva2VuTWFuYWdlciwKICAgIE5vdGlmaWNhdGlvblBlcm1pc3Npb25NYW5hZ2VyPyBwZXJtaXNzaW9uTWFuYWdlciwKICB9KSA6IF9sb2dnZXIgPSBsb2dnZXIgPz8gZGkuZ2V0PExvZ2dlcj4oKSwKICAgICAgIF90b2tlbk1hbmFnZXIgPSB0b2tlbk1hbmFnZXIgPz8gZGkuZ2V0PE5vdGlmaWNhdGlvblRva2VuTWFuYWdlcj4oKSwKICAgICAgIF9wZXJtaXNzaW9uTWFuYWdlciA9CiAgICAgICAgICAgcGVybWlzc2lvbk1hbmFnZXIgPz8gZGkuZ2V0PE5vdGlmaWNhdGlvblBlcm1pc3Npb25NYW5hZ2VyPigpOwoKICBmaW5hbCBOb3RpZmljYXRpb25Db25maWcgY29uZmlnOwogIGZpbmFsIExvZ2dlciBfbG9nZ2VyOwogIGZpbmFsIE5vdGlmaWNhdGlvblRva2VuTWFuYWdlciBfdG9rZW5NYW5hZ2VyOwogIGZpbmFsIE5vdGlmaWNhdGlvblBlcm1pc3Npb25NYW5hZ2VyIF9wZXJtaXNzaW9uTWFuYWdlcjsKICBib29sIF9pc0dyYW50ZWQgPSBmYWxzZTsKCiAgRmlyZWJhc2VNZXNzYWdpbmc/IF9maXJlYmFzZU1lc3NhZ2luZzsKCiAgU3RyaW5nPyBfZmNtVG9rZW47CiAgU3RyaW5nPyBfZGV2aWNlSWQ7CgogIC8vIFN0b3JlIHN1YnNjcmlwdGlvbnMgZm9yIGNsZWFudXAKICBTdHJlYW1TdWJzY3JpcHRpb248UmVtb3RlTWVzc2FnZT4/IF9mb3JlZ3JvdW5kTWVzc2FnZVN1YnNjcmlwdGlvbjsKICBTdHJlYW1TdWJzY3JpcHRpb248UmVtb3RlTWVzc2FnZT4/IF9tZXNzYWdlT3BlbmVkQXBwU3Vic2NyaXB0aW9uOwogIFN0cmVhbVN1YnNjcmlwdGlvbjxTdHJpbmc+PyBfdG9rZW5SZWZyZXNoU3Vic2NyaXB0aW9uOwoKICBAb3ZlcnJpZGUKICBGdXR1cmU8dm9pZD4gaW5pdCgpIGFzeW5jIHsKICAgIHRyeSB7CiAgICAgIF9sb2dnZXIuaSgnJF90YWc6IEluaXRpYWxpemluZyBGaXJlYmFzZSBub3RpZmljYXRpb24gY2xpZW50Jyk7CgogICAgICAvLyBJbml0aWFsaXplIEZpcmViYXNlIE1lc3NhZ2luZwogICAgICBfZmlyZWJhc2VNZXNzYWdpbmcgPSBGaXJlYmFzZU1lc3NhZ2luZy5pbnN0YW5jZTsKCiAgICAgIGZpbmFsIGlzR3JhbnRlZCA9IGF3YWl0IHJlcXVlc3RQZXJtaXNzaW9ucygpOwogICAgICBpZiAoIWlzR3JhbnRlZCkgewogICAgICAgIF9sb2dnZXIudygnJF90YWc6IE5vdGlmaWNhdGlvbiBwZXJtaXNzaW9ucyBub3QgZ3JhbnRlZCcpOwogICAgICAgIHJldHVybjsKICAgICAgfQogICAgICBfaXNHcmFudGVkID0gaXNHcmFudGVkOwoKICAgICAgLy8gU2V0dXAgRkNNIGhhbmRsZXJzIGlmIGJhY2tncm91bmQgbm90aWZpY2F0aW9ucyBhcmUgZW5hYmxlZAogICAgICBhd2FpdCBfc2V0dXBGQ01IYW5kbGVycygpOwoKICAgICAgLy8gR2V0IEZDTSB0b2tlbiBhbmQgcmVnaXN0ZXIgaWYgYmFja2VuZCByZWdpc3RyYXRpb24gaXMgZW5hYmxlZAogICAgICBhd2FpdCBnZXRGQ01Ub2tlbigpOwoKICAgICAgLy8gQ2xlYXIgYmFkZ2UgY291bnQgYXMgdGhlIGxhc3Qgc3RlcCBvZiBpbml0aWFsaXphdGlvbgogICAgICBhd2FpdCBjbGVhckJhZGdlKCk7CgogICAgICBfbG9nZ2VyLmkoJyRfdGFnOiBGaXJlYmFzZSBub3RpZmljYXRpb24gY2xpZW50IGluaXRpYWxpemVkIHN1Y2Nlc3NmdWxseScpOwogICAgfSBjYXRjaCAoZSwgcykgewogICAgICBfbG9nZ2VyLmUoJyRfdGFnOiBFcnJvciBpbml0aWFsaXppbmcgRmlyZWJhc2Ugbm90aWZpY2F0aW9uIGNsaWVudCcsIGUsIHMpOwogICAgICB0aHJvdyBOb3RpZmljYXRpb25FeGNlcHRpb24obWVzc2FnZTogZS5tZXNzYWdlKCkpOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPGJvb2w+IHJlcXVlc3RQZXJtaXNzaW9ucyh7Ym9vbCBwcm92aXNpb25hbCA9IGZhbHNlfSkgYXN5bmMgewogICAgcmV0dXJuIGF3YWl0IF9wZXJtaXNzaW9uTWFuYWdlci5yZXF1ZXN0UGVybWlzc2lvbnMoKTsKICB9CgogIEBvdmVycmlkZQogIEZ1dHVyZTx2b2lkPiBjbGVhckJhZGdlKCkgYXN5bmMgewogICAgdHJ5IHsKICAgICAgX2xvZ2dlci5pKCfwn5SUIENsZWFyaW5nIGJhZGdlIGNvdW50Jyk7CiAgICAgIGlmICghX2lzR3JhbnRlZCkgewogICAgICAgIF9sb2dnZXIudygKICAgICAgICAgICfwn5SUIE5vdGlmaWNhdGlvbiBwZXJtaXNzaW9ucyAnCiAgICAgICAgICAnbm90IGdyYW50ZWQsIGNhbm5vdCBjbGVhciBiYWRnZScsCiAgICAgICAgKTsKICAgICAgICByZXR1cm47CiAgICAgIH0KICAgICAgaWYgKCFhd2FpdCBBcHBCYWRnZVBsdXMuaXNTdXBwb3J0ZWQoKSkgewogICAgICAgIF9sb2dnZXIudygn8J+UlCBBcHBCYWRnZVBsdXMgaXMgbm90IHN1cHBvcnRlZCBvbiB0aGlzIHBsYXRmb3JtJyk7CiAgICAgICAgcmV0dXJuOwogICAgICB9CiAgICAgIGF3YWl0IEFwcEJhZGdlUGx1cy51cGRhdGVCYWRnZSgwKTsKICAgICAgX2xvZ2dlci5pKCfwn5SUIEJhZGdlIGNvdW50IGNsZWFyZWQnKTsKICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgX2xvZ2dlci53KCfwn5SUIEZhaWxlZCB0byBjbGVhciBiYWRnZSBjb3VudDogJGUnKTsKICAgIH0KICB9CgogIEZ1dHVyZTx2b2lkPiBfc2V0dXBGQ01IYW5kbGVycygpIGFzeW5jIHsKICAgIC8vIEhhbmRsZSBiYWNrZ3JvdW5kIG1lc3NhZ2VzICh3aGVuIGFwcCBpcyB0ZXJtaW5hdGVkKQogICAgRmlyZWJhc2VNZXNzYWdpbmcub25CYWNrZ3JvdW5kTWVzc2FnZShfaGFuZGxlQmFja2dyb3VuZE5vdGlmaWNhdGlvbik7CgogICAgLy8gSGFuZGxlIGZvcmVncm91bmQgbWVzc2FnZXMKICAgIF9mb3JlZ3JvdW5kTWVzc2FnZVN1YnNjcmlwdGlvbiA9IEZpcmViYXNlTWVzc2FnaW5nLm9uTWVzc2FnZS5saXN0ZW4oCiAgICAgIChSZW1vdGVNZXNzYWdlIG1lc3NhZ2UpIHsKICAgICAgICBfbG9nZ2VyLmkoJyRfdGFnOiBSZWNlaXZlZCBmb3JlZ3JvdW5kIG1lc3NhZ2U6ICR7bWVzc2FnZS5tZXNzYWdlSWR9Jyk7CiAgICAgICAgaGFuZGxlRm9yZWdyb3VuZE5vdGlmaWNhdGlvbihtZXNzYWdlKTsKICAgICAgfSwKICAgICAgb25FcnJvcjogKGVycm9yKSB7CiAgICAgICAgX2xvZ2dlci5lKCckX3RhZzogRXJyb3IgaW4gZm9yZWdyb3VuZCBtZXNzYWdlIGhhbmRsZXInLCBlcnJvcik7CiAgICAgIH0sCiAgICApOwoKICAgIC8vIEhhbmRsZSBub3RpZmljYXRpb24gb3BlbmVkIChmcm9tIGJhY2tncm91bmQvdGVybWluYXRlZCkKICAgIF9tZXNzYWdlT3BlbmVkQXBwU3Vic2NyaXB0aW9uID0gRmlyZWJhc2VNZXNzYWdpbmcub25NZXNzYWdlT3BlbmVkQXBwLmxpc3RlbigKICAgICAgKFJlbW90ZU1lc3NhZ2UgbWVzc2FnZSkgewogICAgICAgIF9sb2dnZXIuaSgnJF90YWc6IE5vdGlmaWNhdGlvbiBvcGVuZWQgYXBwOiAke21lc3NhZ2UubWVzc2FnZUlkfScpOwogICAgICAgIGhhbmRsZU5vdGlmaWNhdGlvbk9wZW5lZChtZXNzYWdlLCBzb3VyY2U6ICdiYWNrZ3JvdW5kJyk7CiAgICAgIH0sCiAgICAgIG9uRXJyb3I6IChlcnJvcikgewogICAgICAgIF9sb2dnZXIuZSgnJF90YWc6IEVycm9yIGluIG5vdGlmaWNhdGlvbiBvcGVuZWQgaGFuZGxlcicsIGVycm9yKTsKICAgICAgfSwKICAgICk7CgogICAgLy8gSGFuZGxlIGluaXRpYWwgbWVzc2FnZSAoaWYgYXBwIHdhcyBvcGVuZWQgZnJvbSB0ZXJtaW5hdGVkIHN0YXRlKQogICAgaWYgKF9maXJlYmFzZU1lc3NhZ2luZyAhPSBudWxsKSB7CiAgICAgIGZpbmFsIGluaXRpYWxNZXNzYWdlID0gYXdhaXQgX2ZpcmViYXNlTWVzc2FnaW5nIS5nZXRJbml0aWFsTWVzc2FnZSgpOwogICAgICBpZiAoaW5pdGlhbE1lc3NhZ2UgIT0gbnVsbCkgewogICAgICAgIF9sb2dnZXIuaSgKICAgICAgICAgICckX3RhZzogQXBwIG9wZW5lZCBmcm9tIHRlcm1pbmF0ZWQgc3RhdGU6ICR7aW5pdGlhbE1lc3NhZ2UubWVzc2FnZUlkfScsCiAgICAgICAgKTsKICAgICAgICBoYW5kbGVOb3RpZmljYXRpb25PcGVuZWQoaW5pdGlhbE1lc3NhZ2UsIHNvdXJjZTogJ3Rlcm1pbmF0ZWQnKTsKICAgICAgfQoKICAgICAgLy8gSGFuZGxlIHRva2VuIHJlZnJlc2gKICAgICAgX3Rva2VuUmVmcmVzaFN1YnNjcmlwdGlvbiA9IF9maXJlYmFzZU1lc3NhZ2luZyEub25Ub2tlblJlZnJlc2gubGlzdGVuKAogICAgICAgIChTdHJpbmcgbmV3VG9rZW4pIHsKICAgICAgICAgIF9mY21Ub2tlbiA9IG5ld1Rva2VuOwogICAgICAgICAgX3Rva2VuTWFuYWdlci5oYW5kbGVUb2tlblJlZnJlc2gobmV3VG9rZW4pOwogICAgICAgIH0sCiAgICAgICAgb25FcnJvcjogKGVycm9yKSB7CiAgICAgICAgICBfbG9nZ2VyLmUoJyRfdGFnOiBFcnJvciBpbiB0b2tlbiByZWZyZXNoIGhhbmRsZXInLCBlcnJvcik7CiAgICAgICAgfSwKICAgICAgKTsKICAgIH0KCiAgICBfbG9nZ2VyLmkoJyRfdGFnOiBGQ00gaGFuZGxlcnMgc2V0dXAgY29tcGxldGUnKTsKICB9CgogIEBvdmVycmlkZQogIEZ1dHVyZTxTdHJpbmc/PiBnZXRGQ01Ub2tlbigpIGFzeW5jIHsKICAgIHRyeSB7CiAgICAgIF9mY21Ub2tlbiA9IGF3YWl0IF90b2tlbk1hbmFnZXIuZ2V0RkNNVG9rZW4oKTsKCiAgICAgIGlmIChfZmNtVG9rZW4gIT0gbnVsbCkgewogICAgICAgIF9kZXZpY2VJZCA9IGF3YWl0IF90b2tlbk1hbmFnZXIucmVnaXN0ZXJUb2tlbihfZmNtVG9rZW4hKTsKICAgICAgICBfbG9nZ2VyLmkoJyRfdGFnOiBUb2tlbiByZWdpc3RlcmVkIHdpdGggZGV2aWNlIElEOiAkX2RldmljZUlkJyk7CiAgICAgIH0KCiAgICAgIHJldHVybiBfZmNtVG9rZW47CiAgICB9IGNhdGNoIChlLCBzKSB7CiAgICAgIF9sb2dnZXIuZSgnJF90YWc6IEVycm9yIGdldHRpbmcgRkNNIHRva2VuJywgZSwgcyk7CiAgICAgIHJldHVybiBudWxsOwogICAgfQogIH0KCiAgLy8vIEhhbmRsZSBiYWNrZ3JvdW5kIG5vdGlmaWNhdGlvbiAod2hlbiBhcHAgaXMgbm90IHJ1bm5pbmcpCiAgQHByYWdtYSgndm06ZW50cnktcG9pbnQnKQogIHN0YXRpYyBGdXR1cmU8dm9pZD4gX2hhbmRsZUJhY2tncm91bmROb3RpZmljYXRpb24oCiAgICBSZW1vdGVNZXNzYWdlIG1lc3NhZ2UsCiAgKSBhc3luYyB7CiAgICB0cnkgewogICAgICBkZWJ1Z1ByaW50KAogICAgICAgICckX3RhZzogSGFuZGxpbmcgYmFja2dyb3VuZCBub3RpZmljYXRpb246ICR7bWVzc2FnZS5tZXNzYWdlSWR9JywKICAgICAgKTsKICAgIH0gY2F0Y2ggKGUsIHMpIHsKICAgICAgZGVidWdQcmludCgKICAgICAgICAnJF90YWc6IEVycm9yIGhhbmRsaW5nIGJhY2tncm91bmQgbm90aWZpY2F0aW9uOicKICAgICAgICAnICR7bWVzc2FnZS5tZXNzYWdlSWR9IC0gJGUgJHMnLAogICAgICApOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPHZvaWQ+IGhhbmRsZUZvcmVncm91bmROb3RpZmljYXRpb24oUmVtb3RlTWVzc2FnZSBtZXNzYWdlKSBhc3luYyB7CiAgICB0cnkgewogICAgICBfbG9nZ2VyLmkoCiAgICAgICAgJyRfdGFnOiBIYW5kbGluZyBmb3JlZ3JvdW5kIG5vdGlmaWNhdGlvbjogJHttZXNzYWdlLm1lc3NhZ2VJZH0nLAogICAgICApOwoKICAgICAgZmluYWwgbm90aWZpY2F0aW9uID0gbWVzc2FnZS5ub3RpZmljYXRpb247CiAgICAgIGlmIChub3RpZmljYXRpb24gIT0gbnVsbCAmJgogICAgICAgICAgbm90aWZpY2F0aW9uLnRpdGxlICE9IG51bGwgJiYKICAgICAgICAgIG5vdGlmaWNhdGlvbi5ib2R5ICE9IG51bGwpIHsKICAgICAgICBUb2FzdC5ub3RpZmljYXRpb24oCiAgICAgICAgICB0aXRsZTogbm90aWZpY2F0aW9uLnRpdGxlISwKICAgICAgICAgIGJvZHk6IG5vdGlmaWNhdGlvbi5ib2R5ISwKICAgICAgICApOwogICAgICB9CiAgICB9IGNhdGNoIChlLCBzKSB7CiAgICAgIF9sb2dnZXIuZSgnJF90YWc6IEVycm9yIGhhbmRsaW5nIGZvcmVncm91bmQgbm90aWZpY2F0aW9uJywgZSwgcyk7CiAgICB9CiAgfQoKICBAb3ZlcnJpZGUKICBGdXR1cmU8dm9pZD4gaGFuZGxlTm90aWZpY2F0aW9uT3BlbmVkKAogICAgUmVtb3RlTWVzc2FnZSBtZXNzYWdlLCB7CiAgICBTdHJpbmc/IHNvdXJjZSwKICB9KSBhc3luYyB7CiAgICB0cnkgewogICAgICBfbG9nZ2VyLmkoJyRfdGFnOiBIYW5kbGluZyBub3RpZmljYXRpb24gb3BlbmVkOiAke21lc3NhZ2UubWVzc2FnZUlkfScpOwoKICAgICAgZmluYWwgbm90aWZpY2F0aW9uID0gbWVzc2FnZS5ub3RpZmljYXRpb247CgogICAgICBfbG9nZ2VyLmkoCiAgICAgICAgJyRfdGFnOiBOb3RpZmljYXRpb24gb3BlbmVkIGZyb20gJHNvdXJjZTogJHtub3RpZmljYXRpb24/LnRpdGxlfSAtICR7bm90aWZpY2F0aW9uPy5ib2R5fScsCiAgICAgICk7CgogICAgICAvLyBEZWVwIGxpbmsgY29udHJhY3Q6IHNlbmQgYSBgcm91dGVgIGluIHRoZSBtZXNzYWdlIGRhdGEgYW5kIHRoZSBhcHAKICAgICAgLy8gbmF2aWdhdGVzIHRoZXJlLCBlLmcuIHsicm91dGUiOiAiL2hvbWUvb3JkZXJzLzQyIn0uIEJyYW5jaCBvbiB5b3VyIG93bgogICAgICAvLyBwYXlsb2FkIGZpZWxkcyBoZXJlIGlmIHlvdSBuZWVkIHNvbWV0aGluZyByaWNoZXIgdGhhbiBhIHBhdGguCiAgICAgIGZpbmFsIHJvdXRlID0gbWVzc2FnZS5kYXRhWydyb3V0ZSddOwogICAgICBpZiAocm91dGUgaXMhIFN0cmluZyB8fCByb3V0ZS5pc0VtcHR5KSByZXR1cm47CgogICAgICBkaS5nZXQ8R29Sb3V0ZXI+KCkucHVzaChyb3V0ZSk7CiAgICB9IGNhdGNoIChlLCBzKSB7CiAgICAgIF9sb2dnZXIuZSgnJF90YWc6IEVycm9yIGhhbmRsaW5nIG5vdGlmaWNhdGlvbiBvcGVuZWQnLCBlLCBzKTsKICAgIH0KICB9CgogIEBvdmVycmlkZQogIFN0cmluZz8gZ2V0IGZjbVRva2VuID0+IF9mY21Ub2tlbjsKCiAgQG92ZXJyaWRlCiAgU3RyaW5nPyBnZXQgZGV2aWNlSWQgPT4gX2RldmljZUlkOwoKICBAb3ZlcnJpZGUKICBGdXR1cmU8dm9pZD4gZGlzcG9zZSgpIGFzeW5jIHsKICAgIF9sb2dnZXIuaSgnJF90YWc6IERpc3Bvc2luZyBGaXJlYmFzZSBub3RpZmljYXRpb24gY2xpZW50Jyk7CgogICAgLy8gQ2FuY2VsIGFsbCBzdWJzY3JpcHRpb25zIHRvIHByZXZlbnQgbWVtb3J5IGxlYWtzCiAgICBfZm9yZWdyb3VuZE1lc3NhZ2VTdWJzY3JpcHRpb24/LmNhbmNlbCgpOwogICAgX21lc3NhZ2VPcGVuZWRBcHBTdWJzY3JpcHRpb24/LmNhbmNlbCgpOwogICAgX3Rva2VuUmVmcmVzaFN1YnNjcmlwdGlvbj8uY2FuY2VsKCk7CgogICAgX2ZvcmVncm91bmRNZXNzYWdlU3Vic2NyaXB0aW9uID0gbnVsbDsKICAgIF9tZXNzYWdlT3BlbmVkQXBwU3Vic2NyaXB0aW9uID0gbnVsbDsKICAgIF90b2tlblJlZnJlc2hTdWJzY3JpcHRpb24gPSBudWxsOwoKICAgIF9maXJlYmFzZU1lc3NhZ2luZyA9IG51bGw7CiAgfQp9Cg==", + "aW1wb3J0ICdkYXJ0OmFzeW5jJzsKCmltcG9ydCAncGFja2FnZTphcHBfYmFkZ2VfcGx1cy9hcHBfYmFkZ2VfcGx1cy5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmNvcmUvbG9nZ2VyL2xvZ2dlci5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZpcmViYXNlX21lc3NhZ2luZy9maXJlYmFzZV9tZXNzYWdpbmcuZGFydCcKICAgIGhpZGUgTm90aWZpY2F0aW9uU2V0dGluZ3M7CmltcG9ydCAncGFja2FnZTpmbHV0dGVyL2ZvdW5kYXRpb24uZGFydCc7CmltcG9ydCAncGFja2FnZTpub3RpZmljYXRpb25zL25vdGlmaWNhdGlvbnMuZGFydCc7CgovLy8gT3ducyBtZXNzYWdpbmcgc3Vic2NyaXB0aW9uczsgcHJlc2VudGF0aW9uIGlzIHN1cHBsaWVkIGJ5IHRoZSBhcHAuCmNsYXNzIEZpcmViYXNlTm90aWZpY2F0aW9uQ2xpZW50IGltcGxlbWVudHMgTm90aWZpY2F0aW9uQ2xpZW50IHsKICBGaXJlYmFzZU5vdGlmaWNhdGlvbkNsaWVudCh7CiAgICByZXF1aXJlZCB0aGlzLmNvbmZpZywKICAgIHJlcXVpcmVkIExvZ2dlciBsb2dnZXIsCiAgICByZXF1aXJlZCBOb3RpZmljYXRpb25Ub2tlbk1hbmFnZXIgdG9rZW5NYW5hZ2VyLAogICAgcmVxdWlyZWQgTm90aWZpY2F0aW9uUGVybWlzc2lvbk1hbmFnZXIgcGVybWlzc2lvbk1hbmFnZXIsCiAgICByZXF1aXJlZCBGaXJlYmFzZU1lc3NhZ2luZyBtZXNzYWdpbmcsCiAgICBTdHJlYW08UmVtb3RlTWVzc2FnZT4/IGZvcmVncm91bmRNZXNzYWdlcywKICAgIFN0cmVhbTxSZW1vdGVNZXNzYWdlPj8gb3BlbmVkTWVzc2FnZXMsCiAgICBGdXR1cmU8Ym9vbD4gRnVuY3Rpb24oKT8gc3VwcG9ydHNCYWRnZSwKICAgIEZ1dHVyZTx2b2lkPiBGdW5jdGlvbihpbnQpPyB1cGRhdGVCYWRnZSwKICAgIHZvaWQgRnVuY3Rpb24oRnV0dXJlPHZvaWQ+IEZ1bmN0aW9uKFJlbW90ZU1lc3NhZ2UpKT8gcmVnaXN0ZXJCYWNrZ3JvdW5kLAogIH0pIDogX2xvZ2dlciA9IGxvZ2dlciwKICAgICAgIF90b2tlbk1hbmFnZXIgPSB0b2tlbk1hbmFnZXIsCiAgICAgICBfcGVybWlzc2lvbk1hbmFnZXIgPSBwZXJtaXNzaW9uTWFuYWdlciwKICAgICAgIF9tZXNzYWdpbmcgPSBtZXNzYWdpbmcsCiAgICAgICBfZm9yZWdyb3VuZE1lc3NhZ2VzID0gZm9yZWdyb3VuZE1lc3NhZ2VzID8/IEZpcmViYXNlTWVzc2FnaW5nLm9uTWVzc2FnZSwKICAgICAgIF9vcGVuZWRNZXNzYWdlcyA9IG9wZW5lZE1lc3NhZ2VzID8/IEZpcmViYXNlTWVzc2FnaW5nLm9uTWVzc2FnZU9wZW5lZEFwcCwKICAgICAgIF9zdXBwb3J0c0JhZGdlID0gc3VwcG9ydHNCYWRnZSA/PyBBcHBCYWRnZVBsdXMuaXNTdXBwb3J0ZWQsCiAgICAgICBfdXBkYXRlQmFkZ2UgPSB1cGRhdGVCYWRnZSA/PyBBcHBCYWRnZVBsdXMudXBkYXRlQmFkZ2UsCiAgICAgICBfcmVnaXN0ZXJCYWNrZ3JvdW5kID0KICAgICAgICAgICByZWdpc3RlckJhY2tncm91bmQgPz8gRmlyZWJhc2VNZXNzYWdpbmcub25CYWNrZ3JvdW5kTWVzc2FnZTsKCiAgZmluYWwgTm90aWZpY2F0aW9uQ29uZmlnIGNvbmZpZzsKICBmaW5hbCBMb2dnZXIgX2xvZ2dlcjsKICBmaW5hbCBOb3RpZmljYXRpb25Ub2tlbk1hbmFnZXIgX3Rva2VuTWFuYWdlcjsKICBmaW5hbCBOb3RpZmljYXRpb25QZXJtaXNzaW9uTWFuYWdlciBfcGVybWlzc2lvbk1hbmFnZXI7CiAgZmluYWwgRmlyZWJhc2VNZXNzYWdpbmcgX21lc3NhZ2luZzsKICBmaW5hbCBTdHJlYW08UmVtb3RlTWVzc2FnZT4gX2ZvcmVncm91bmRNZXNzYWdlczsKICBmaW5hbCBTdHJlYW08UmVtb3RlTWVzc2FnZT4gX29wZW5lZE1lc3NhZ2VzOwogIGZpbmFsIEZ1dHVyZTxib29sPiBGdW5jdGlvbigpIF9zdXBwb3J0c0JhZGdlOwogIGZpbmFsIEZ1dHVyZTx2b2lkPiBGdW5jdGlvbihpbnQpIF91cGRhdGVCYWRnZTsKICBmaW5hbCB2b2lkIEZ1bmN0aW9uKEZ1dHVyZTx2b2lkPiBGdW5jdGlvbihSZW1vdGVNZXNzYWdlKSkgX3JlZ2lzdGVyQmFja2dyb3VuZDsKICBib29sIF9pc0dyYW50ZWQgPSBmYWxzZTsKICBib29sIF9pbml0aWFsaXplZCA9IGZhbHNlOwogIGJvb2wgX2Rpc3Bvc2VkID0gZmFsc2U7CiAgRnV0dXJlPHZvaWQ+PyBfaW5pdGlhbGl6aW5nOwogIFN0cmluZz8gX2ZjbVRva2VuOwogIFN0cmluZz8gX2RldmljZUlkOwogIFN0cmVhbVN1YnNjcmlwdGlvbjxSZW1vdGVNZXNzYWdlPj8gX2ZvcmVncm91bmRTdWJzY3JpcHRpb247CiAgU3RyZWFtU3Vic2NyaXB0aW9uPFJlbW90ZU1lc3NhZ2U+PyBfb3BlbmVkU3Vic2NyaXB0aW9uOwogIFN0cmVhbVN1YnNjcmlwdGlvbjxTdHJpbmc+PyBfdG9rZW5TdWJzY3JpcHRpb247CgogIEBvdmVycmlkZQogIEZ1dHVyZTx2b2lkPiBpbml0KCkgewogICAgaWYgKF9kaXNwb3NlZCkgewogICAgICByZXR1cm4gRnV0dXJlLmVycm9yKFN0YXRlRXJyb3IoJ05vdGlmaWNhdGlvbiBjbGllbnQgaXMgZGlzcG9zZWQnKSk7CiAgICB9CiAgICBpZiAoX2luaXRpYWxpemVkKSByZXR1cm4gRnV0dXJlLnZhbHVlKCk7CiAgICByZXR1cm4gX2luaXRpYWxpemluZyA/Pz0gX2luaXRpYWxpemUoKS53aGVuQ29tcGxldGUoCiAgICAgICgpID0+IF9pbml0aWFsaXppbmcgPSBudWxsLAogICAgKTsKICB9CgogIEZ1dHVyZTx2b2lkPiBfaW5pdGlhbGl6ZSgpIGFzeW5jIHsKICAgIHRyeSB7CiAgICAgIF9pc0dyYW50ZWQgPSBhd2FpdCByZXF1ZXN0UGVybWlzc2lvbnMoKTsKICAgICAgaWYgKF9kaXNwb3NlZCB8fCAhX2lzR3JhbnRlZCkgcmV0dXJuOwogICAgICBfcmVnaXN0ZXJCYWNrZ3JvdW5kKGhhbmRsZUJhY2tncm91bmROb3RpZmljYXRpb24pOwogICAgICBfZm9yZWdyb3VuZFN1YnNjcmlwdGlvbiA9IF9mb3JlZ3JvdW5kTWVzc2FnZXMubGlzdGVuKAogICAgICAgIChtZXNzYWdlKSA9PiB1bmF3YWl0ZWQoaGFuZGxlRm9yZWdyb3VuZE5vdGlmaWNhdGlvbihtZXNzYWdlKSksCiAgICAgICAgb25FcnJvcjogKE9iamVjdCBlcnJvcikgPT4KICAgICAgICAgICAgX2xvZ2dlci5lKCdGb3JlZ3JvdW5kIG5vdGlmaWNhdGlvbiBzdHJlYW0gZmFpbGVkJywgZXJyb3IpLAogICAgICApOwogICAgICBfb3BlbmVkU3Vic2NyaXB0aW9uID0gX29wZW5lZE1lc3NhZ2VzLmxpc3RlbigKICAgICAgICAobWVzc2FnZSkgPT4KICAgICAgICAgICAgdW5hd2FpdGVkKGhhbmRsZU5vdGlmaWNhdGlvbk9wZW5lZChtZXNzYWdlLCBzb3VyY2U6ICdiYWNrZ3JvdW5kJykpLAogICAgICAgIG9uRXJyb3I6IChPYmplY3QgZXJyb3IpID0+CiAgICAgICAgICAgIF9sb2dnZXIuZSgnT3BlbmVkIG5vdGlmaWNhdGlvbiBzdHJlYW0gZmFpbGVkJywgZXJyb3IpLAogICAgICApOwogICAgICBfdG9rZW5TdWJzY3JpcHRpb24gPSBfbWVzc2FnaW5nLm9uVG9rZW5SZWZyZXNoLmxpc3RlbigKICAgICAgICAodG9rZW4pIGFzeW5jIHsKICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgIGF3YWl0IF90b2tlbk1hbmFnZXIuaGFuZGxlVG9rZW5SZWZyZXNoKHRva2VuKTsKICAgICAgICAgICAgaWYgKCFfZGlzcG9zZWQpIF9mY21Ub2tlbiA9IHRva2VuOwogICAgICAgICAgfSBjYXRjaCAoZXJyb3IsIHN0YWNrKSB7CiAgICAgICAgICAgIF9sb2dnZXIuZSgnTm90aWZpY2F0aW9uIHRva2VuIHJlZnJlc2ggZmFpbGVkJywgZXJyb3IsIHN0YWNrKTsKICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIG9uRXJyb3I6IChPYmplY3QgZXJyb3IpID0+CiAgICAgICAgICAgIF9sb2dnZXIuZSgnTm90aWZpY2F0aW9uIHRva2VuIHN0cmVhbSBmYWlsZWQnLCBlcnJvciksCiAgICAgICk7CiAgICAgIGZpbmFsIGluaXRpYWwgPSBhd2FpdCBfbWVzc2FnaW5nLmdldEluaXRpYWxNZXNzYWdlKCk7CiAgICAgIGlmIChfZGlzcG9zZWQpIHJldHVybjsKICAgICAgaWYgKGluaXRpYWwgIT0gbnVsbCkgewogICAgICAgIGF3YWl0IGhhbmRsZU5vdGlmaWNhdGlvbk9wZW5lZChpbml0aWFsLCBzb3VyY2U6ICd0ZXJtaW5hdGVkJyk7CiAgICAgIH0KICAgICAgYXdhaXQgZ2V0RkNNVG9rZW4oKTsKICAgICAgYXdhaXQgY2xlYXJCYWRnZSgpOwogICAgICBpZiAoIV9kaXNwb3NlZCkgX2luaXRpYWxpemVkID0gdHJ1ZTsKICAgIH0gY2F0Y2ggKGVycm9yLCBzdGFjaykgewogICAgICBhd2FpdCBfY2FuY2VsU3Vic2NyaXB0aW9ucygpOwogICAgICBfbG9nZ2VyLmUoJ05vdGlmaWNhdGlvbiBpbml0aWFsaXphdGlvbiBmYWlsZWQnLCBlcnJvciwgc3RhY2spOwogICAgICByZXRocm93OwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPGJvb2w+IHJlcXVlc3RQZXJtaXNzaW9ucyh7Ym9vbCBwcm92aXNpb25hbCA9IGZhbHNlfSkgPT4KICAgICAgX3Blcm1pc3Npb25NYW5hZ2VyLnJlcXVlc3RQZXJtaXNzaW9ucyhwcm92aXNpb25hbDogcHJvdmlzaW9uYWwpOwoKICBAb3ZlcnJpZGUKICBGdXR1cmU8dm9pZD4gY2xlYXJCYWRnZSgpIGFzeW5jIHsKICAgIHRyeSB7CiAgICAgIGlmIChfZGlzcG9zZWQgfHwgIV9pc0dyYW50ZWQgfHwgIWF3YWl0IF9zdXBwb3J0c0JhZGdlKCkpIHJldHVybjsKICAgICAgaWYgKCFfZGlzcG9zZWQpIGF3YWl0IF91cGRhdGVCYWRnZSgwKTsKICAgIH0gY2F0Y2ggKGVycm9yLCBzdGFjaykgewogICAgICBfbG9nZ2VyLmUoJ05vdGlmaWNhdGlvbiBiYWRnZSBjbGVhcmluZyBmYWlsZWQnLCBlcnJvciwgc3RhY2spOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPFN0cmluZz8+IGdldEZDTVRva2VuKCkgYXN5bmMgewogICAgaWYgKF9kaXNwb3NlZCkgcmV0dXJuIG51bGw7CiAgICB0cnkgewogICAgICBmaW5hbCB0b2tlbiA9IGF3YWl0IF90b2tlbk1hbmFnZXIuZ2V0RkNNVG9rZW4oKTsKICAgICAgaWYgKF9kaXNwb3NlZCkgcmV0dXJuIG51bGw7CiAgICAgIGZpbmFsIGRldmljZSA9IHRva2VuID09IG51bGwKICAgICAgICAgID8gbnVsbAogICAgICAgICAgOiBhd2FpdCBfdG9rZW5NYW5hZ2VyLnJlZ2lzdGVyVG9rZW4odG9rZW4pOwogICAgICBpZiAoX2Rpc3Bvc2VkKSByZXR1cm4gbnVsbDsKICAgICAgX2ZjbVRva2VuID0gdG9rZW47CiAgICAgIF9kZXZpY2VJZCA9IGRldmljZTsKICAgICAgcmV0dXJuIHRva2VuOwogICAgfSBjYXRjaCAoZXJyb3IsIHN0YWNrKSB7CiAgICAgIF9mY21Ub2tlbiA9IG51bGw7CiAgICAgIF9kZXZpY2VJZCA9IG51bGw7CiAgICAgIF9sb2dnZXIuZSgnTm90aWZpY2F0aW9uIHRva2VuIHJlZ2lzdHJhdGlvbiBmYWlsZWQnLCBlcnJvciwgc3RhY2spOwogICAgICByZXR1cm4gbnVsbDsKICAgIH0KICB9CgogIEBvdmVycmlkZQogIEZ1dHVyZTx2b2lkPiBoYW5kbGVGb3JlZ3JvdW5kTm90aWZpY2F0aW9uKFJlbW90ZU1lc3NhZ2UgbWVzc2FnZSkgYXN5bmMgewogICAgaWYgKF9kaXNwb3NlZCkgcmV0dXJuOwogICAgdHJ5IHsKICAgICAgZmluYWwgbm90aWZpY2F0aW9uID0gbWVzc2FnZS5ub3RpZmljYXRpb247CiAgICAgIGZpbmFsIHRpdGxlID0gbm90aWZpY2F0aW9uPy50aXRsZTsKICAgICAgZmluYWwgYm9keSA9IG5vdGlmaWNhdGlvbj8uYm9keTsKICAgICAgaWYgKHRpdGxlICE9IG51bGwgJiYgYm9keSAhPSBudWxsKSB7CiAgICAgICAgYXdhaXQgY29uZmlnLm9uRm9yZWdyb3VuZD8uY2FsbCh0aXRsZSwgYm9keSk7CiAgICAgIH0KICAgIH0gY2F0Y2ggKGVycm9yLCBzdGFjaykgewogICAgICBfbG9nZ2VyLmUoJ0ZvcmVncm91bmQgbm90aWZpY2F0aW9uIHByZXNlbnRhdGlvbiBmYWlsZWQnLCBlcnJvciwgc3RhY2spOwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPHZvaWQ+IGhhbmRsZU5vdGlmaWNhdGlvbk9wZW5lZCgKICAgIFJlbW90ZU1lc3NhZ2UgbWVzc2FnZSwgewogICAgU3RyaW5nPyBzb3VyY2UsCiAgfSkgYXN5bmMgewogICAgaWYgKF9kaXNwb3NlZCkgcmV0dXJuOwogICAgdHJ5IHsKICAgICAgZmluYWwgcm91dGUgPSBtZXNzYWdlLmRhdGFbJ3JvdXRlJ107CiAgICAgIC8vIE5vdGlmaWNhdGlvbnMgbWF5IG5hdmlnYXRlIG9ubHkgdG8gbG9jYWwgYXBwIHBhdGhzLgogICAgICBpZiAocm91dGUgaXMhIFN0cmluZyB8fAogICAgICAgICAgIXJvdXRlLnN0YXJ0c1dpdGgoJy8nKSB8fAogICAgICAgICAgcm91dGUuc3RhcnRzV2l0aCgnLy8nKSkgewogICAgICAgIHJldHVybjsKICAgICAgfQogICAgICBhd2FpdCBjb25maWcub25PcGVuUm91dGU/LmNhbGwocm91dGUpOwogICAgfSBjYXRjaCAoZXJyb3IsIHN0YWNrKSB7CiAgICAgIF9sb2dnZXIuZSgnTm90aWZpY2F0aW9uIG5hdmlnYXRpb24gZmFpbGVkJywgZXJyb3IsIHN0YWNrKTsKICAgIH0KICB9CgogIEBvdmVycmlkZQogIFN0cmluZz8gZ2V0IGZjbVRva2VuID0+IF9mY21Ub2tlbjsKICBAb3ZlcnJpZGUKICBTdHJpbmc/IGdldCBkZXZpY2VJZCA9PiBfZGV2aWNlSWQ7CgogIEZ1dHVyZTx2b2lkPiBfY2FuY2VsU3Vic2NyaXB0aW9ucygpIGFzeW5jIHsKICAgIGF3YWl0IF9mb3JlZ3JvdW5kU3Vic2NyaXB0aW9uPy5jYW5jZWwoKTsKICAgIGF3YWl0IF9vcGVuZWRTdWJzY3JpcHRpb24/LmNhbmNlbCgpOwogICAgYXdhaXQgX3Rva2VuU3Vic2NyaXB0aW9uPy5jYW5jZWwoKTsKICAgIF9mb3JlZ3JvdW5kU3Vic2NyaXB0aW9uID0gbnVsbDsKICAgIF9vcGVuZWRTdWJzY3JpcHRpb24gPSBudWxsOwogICAgX3Rva2VuU3Vic2NyaXB0aW9uID0gbnVsbDsKICB9CgogIEBvdmVycmlkZQogIEZ1dHVyZTx2b2lkPiBkaXNwb3NlKCkgYXN5bmMgewogICAgX2Rpc3Bvc2VkID0gdHJ1ZTsKICAgIF9pbml0aWFsaXplZCA9IGZhbHNlOwogICAgX2lzR3JhbnRlZCA9IGZhbHNlOwogICAgX2ZjbVRva2VuID0gbnVsbDsKICAgIF9kZXZpY2VJZCA9IG51bGw7CiAgICBhd2FpdCBfY2FuY2VsU3Vic2NyaXB0aW9ucygpOwogIH0KfQoKLy8vIEJhY2tncm91bmQgd29yayBydW5zIGluIGl0cyBvd24gaXNvbGF0ZSwgd2l0aG91dCBhcHAgREkgb3IgbmF2aWdhdGlvbi4KQHByYWdtYSgndm06ZW50cnktcG9pbnQnKQpGdXR1cmU8dm9pZD4gaGFuZGxlQmFja2dyb3VuZE5vdGlmaWNhdGlvbihSZW1vdGVNZXNzYWdlIG1lc3NhZ2UpIGFzeW5jIHsKICBkZWJ1Z1ByaW50KCdCYWNrZ3JvdW5kIG5vdGlmaWNhdGlvbiByZWNlaXZlZDogJHttZXNzYWdlLm1lc3NhZ2VJZH0nKTsKfQo=", "type": "text" }, { @@ -1287,21 +1465,21 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "path": "{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/src/config/notification_config.dart", "data": - "Y2xhc3MgTm90aWZpY2F0aW9uQ29uZmlnIHsKICBjb25zdCBOb3RpZmljYXRpb25Db25maWcoKTsKfQoKY2xhc3MgRGVmYXVsdE5vdGlmaWNhdGlvbkNvbmZpZyBleHRlbmRzIE5vdGlmaWNhdGlvbkNvbmZpZyB7CiAgY29uc3QgRGVmYXVsdE5vdGlmaWNhdGlvbkNvbmZpZygpIDogc3VwZXIoKTsKfQo=", + "aW1wb3J0ICdkYXJ0OmFzeW5jJzsKCmNsYXNzIE5vdGlmaWNhdGlvbkNvbmZpZyB7CiAgY29uc3QgTm90aWZpY2F0aW9uQ29uZmlnKHt0aGlzLm9uRm9yZWdyb3VuZCwgdGhpcy5vbk9wZW5Sb3V0ZX0pOwoKICBmaW5hbCBGdXR1cmVPcjx2b2lkPiBGdW5jdGlvbihTdHJpbmcgdGl0bGUsIFN0cmluZyBib2R5KT8gb25Gb3JlZ3JvdW5kOwogIGZpbmFsIEZ1dHVyZU9yPHZvaWQ+IEZ1bmN0aW9uKFN0cmluZyByb3V0ZSk/IG9uT3BlblJvdXRlOwp9CgpjbGFzcyBEZWZhdWx0Tm90aWZpY2F0aW9uQ29uZmlnIGV4dGVuZHMgTm90aWZpY2F0aW9uQ29uZmlnIHsKICBjb25zdCBEZWZhdWx0Tm90aWZpY2F0aW9uQ29uZmlnKHtzdXBlci5vbkZvcmVncm91bmQsIHN1cGVyLm9uT3BlblJvdXRlfSk7Cn0K", "type": "text" }, { "path": "{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/src/device_info/device_info.dart", "data": - "YWJzdHJhY3QgY2xhc3MgRGV2aWNlSW5mbyB7CiAgRnV0dXJlPFN0cmluZz4gZ2VuZXJhdGVEZXZpY2VJZCgpOwoKICBGdXR1cmU8U3RyaW5nPiBnZXREZXZpY2VOYW1lKCk7Cn0K", + "YWJzdHJhY3QgY2xhc3MgRGV2aWNlSW5mbyB7CiAgRnV0dXJlPFN0cmluZz4gZ2VuZXJhdGVEZXZpY2VJZCgpOwoKICBGdXR1cmU8U3RyaW5nPiBnZXREZXZpY2VOYW1lKCk7Cn0KCmFic3RyYWN0IGNsYXNzIEluc3RhbGxhdGlvbklkU3RvcmUgewogIEZ1dHVyZTxTdHJpbmc/PiByZWFkKCk7CiAgRnV0dXJlPHZvaWQ+IHdyaXRlKFN0cmluZyBpZCk7Cn0K", "type": "text" }, { "path": "{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/src/device_info/device_info_impl.dart", "data": - "aW1wb3J0ICdkYXJ0OmNvbnZlcnQnOwppbXBvcnQgJ2RhcnQ6aW8nOwoKaW1wb3J0ICdwYWNrYWdlOmNvcmUvbG9nZ2VyL2xvZ2dlci5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmNyeXB0by9jcnlwdG8uZGFydCc7CmltcG9ydCAncGFja2FnZTpkZXZpY2VfaW5mb19wbHVzL2RldmljZV9pbmZvX3BsdXMuZGFydCc7CmltcG9ydCAncGFja2FnZTpkaS9kaS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOm5vdGlmaWNhdGlvbnMvc3JjL2RldmljZV9pbmZvL2RldmljZV9pbmZvLmRhcnQnOwoKLy8vIENvbmNyZXRlIGltcGxlbWVudGF0aW9uIG9mIERldmljZUluZm8gZm9yIEFuZHJvaWQgYW5kIGlPUyBvbmx5Ci8vLyBHZW5lcmF0ZXMgY29uc2lzdGVudCBkZXZpY2UgaWRlbnRpZmllcnMgdXNpbmcgc3RhYmxlIGRldmljZSBjaGFyYWN0ZXJpc3RpY3MKY2xhc3MgRGV2aWNlSW5mb0ltcGwgaW1wbGVtZW50cyBEZXZpY2VJbmZvIHsKICBzdGF0aWMgY29uc3QgU3RyaW5nIF90YWcgPSAnRGV2aWNlSW5mb0ltcGwnOwoKICBmaW5hbCBMb2dnZXIgX2xvZ2dlcjsKICBmaW5hbCBEZXZpY2VJbmZvUGx1Z2luIF9kZXZpY2VJbmZvUGx1Z2luOwoKICBEZXZpY2VJbmZvSW1wbCh7TG9nZ2VyPyBsb2dnZXIsIERldmljZUluZm9QbHVnaW4/IGRldmljZUluZm9QbHVnaW59KQogICAgOiBfbG9nZ2VyID0gbG9nZ2VyID8/IGRpLmdldDxMb2dnZXI+KCksCiAgICAgIF9kZXZpY2VJbmZvUGx1Z2luID0gZGV2aWNlSW5mb1BsdWdpbiA/PyBEZXZpY2VJbmZvUGx1Z2luKCk7CgogIEBvdmVycmlkZQogIEZ1dHVyZTxTdHJpbmc+IGdlbmVyYXRlRGV2aWNlSWQoKSBhc3luYyB7CiAgICB0cnkgewogICAgICBpZiAoUGxhdGZvcm0uaXNBbmRyb2lkKSB7CiAgICAgICAgcmV0dXJuIGF3YWl0IF9nZW5lcmF0ZUFuZHJvaWREZXZpY2VJZCgpOwogICAgICB9IGVsc2UgaWYgKFBsYXRmb3JtLmlzSU9TKSB7CiAgICAgICAgcmV0dXJuIGF3YWl0IF9nZW5lcmF0ZUlPU0RldmljZUlkKCk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgX2xvZ2dlci53KCckX3RhZzogVW5zdXBwb3J0ZWQgcGxhdGZvcm06ICR7UGxhdGZvcm0ub3BlcmF0aW5nU3lzdGVtfScpOwogICAgICAgIHRocm93IFVuc3VwcG9ydGVkRXJyb3IoJ09ubHkgQW5kcm9pZCBhbmQgaU9TIHBsYXRmb3JtcyBhcmUgc3VwcG9ydGVkJyk7CiAgICAgIH0KICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgX2xvZ2dlci53KCckX3RhZzogRXJyb3IgZ2VuZXJhdGluZyBkZXZpY2UgSUQ6ICRlJyk7CiAgICAgIHJldHVybiBfZ2VuZXJhdGVGYWxsYmFja0lkKCk7CiAgICB9CiAgfQoKICBAb3ZlcnJpZGUKICBGdXR1cmU8U3RyaW5nPiBnZXREZXZpY2VOYW1lKCkgYXN5bmMgewogICAgdHJ5IHsKICAgICAgaWYgKFBsYXRmb3JtLmlzQW5kcm9pZCkgewogICAgICAgIHJldHVybiBhd2FpdCBfZ2V0QW5kcm9pZERldmljZU5hbWUoKTsKICAgICAgfSBlbHNlIGlmIChQbGF0Zm9ybS5pc0lPUykgewogICAgICAgIHJldHVybiBhd2FpdCBfZ2V0SU9TRGV2aWNlTmFtZSgpOwogICAgICB9IGVsc2UgewogICAgICAgIF9sb2dnZXIudygnJF90YWc6IFVuc3VwcG9ydGVkIHBsYXRmb3JtOiAke1BsYXRmb3JtLm9wZXJhdGluZ1N5c3RlbX0nKTsKICAgICAgICB0aHJvdyBVbnN1cHBvcnRlZEVycm9yKCdPbmx5IEFuZHJvaWQgYW5kIGlPUyBwbGF0Zm9ybXMgYXJlIHN1cHBvcnRlZCcpOwogICAgICB9CiAgICB9IGNhdGNoIChlKSB7CiAgICAgIF9sb2dnZXIudygnJF90YWc6IEVycm9yIGdldHRpbmcgZGV2aWNlIG5hbWU6ICRlJyk7CiAgICAgIHJldHVybiBfZ2V0RmFsbGJhY2tEZXZpY2VOYW1lKCk7CiAgICB9CiAgfQoKICAvLy8gR2VuZXJhdGUgQW5kcm9pZCBkZXZpY2UgSUQgdXNpbmcgc3RhYmxlIGhhcmR3YXJlIGNoYXJhY3RlcmlzdGljcwogIEZ1dHVyZTxTdHJpbmc+IF9nZW5lcmF0ZUFuZHJvaWREZXZpY2VJZCgpIGFzeW5jIHsKICAgIHRyeSB7CiAgICAgIGZpbmFsIGFuZHJvaWRJbmZvID0gYXdhaXQgX2RldmljZUluZm9QbHVnaW4uYW5kcm9pZEluZm87CgogICAgICAvLyBVc2Ugb25seSB0aGUgbW9zdCBzdGFibGUgaGFyZHdhcmUgY2hhcmFjdGVyaXN0aWNzIHRoYXQgZG9uJ3QgY2hhbmdlCiAgICAgIGZpbmFsIHN0YWJsZUNoYXJhY3RlcmlzdGljcyA9IFsKICAgICAgICBhbmRyb2lkSW5mby5icmFuZCwKICAgICAgICBhbmRyb2lkSW5mby5tb2RlbCwKICAgICAgICBhbmRyb2lkSW5mby5kZXZpY2UsCiAgICAgICAgYW5kcm9pZEluZm8uaGFyZHdhcmUsCiAgICAgICAgYW5kcm9pZEluZm8uYm9hcmQsCiAgICAgICAgYW5kcm9pZEluZm8uYm9vdGxvYWRlciwKICAgICAgICBhbmRyb2lkSW5mby5wcm9kdWN0LAogICAgICAgIC8vIGZpbmdlcnByaW50IGNvbnRhaW5zIGJ1aWxkIGluZm8gYnV0IGlzIGdlbmVyYWxseSBzdGFibGUgZm9yIHNhbWUgZGV2aWNlCiAgICAgICAgYW5kcm9pZEluZm8uZmluZ2VycHJpbnQsCiAgICAgICAgLy8gUGh5c2ljYWwgZGV2aWNlIGluZGljYXRvcgogICAgICAgIGFuZHJvaWRJbmZvLmlzUGh5c2ljYWxEZXZpY2UudG9TdHJpbmcoKSwKICAgICAgICAvLyBIYXJkd2FyZSBmZWF0dXJlcyB0aGF0IGFyZSBzdGFibGUKICAgICAgICBhbmRyb2lkSW5mby5zdXBwb3J0ZWRBYmlzLmpvaW4oJywnKSwKICAgICAgICBhbmRyb2lkSW5mby5zdXBwb3J0ZWQzMkJpdEFiaXMuam9pbignLCcpLAogICAgICAgIGFuZHJvaWRJbmZvLnN1cHBvcnRlZDY0Qml0QWJpcy5qb2luKCcsJyksCiAgICAgIF07CgogICAgICAvLyBSZW1vdmUgZW1wdHkgdmFsdWVzIGFuZCBjcmVhdGUgYSBkZXRlcm1pbmlzdGljIHN0cmluZwogICAgICBmaW5hbCBjbGVhbkNoYXJhY3RlcmlzdGljcyA9IHN0YWJsZUNoYXJhY3RlcmlzdGljcwogICAgICAgICAgLndoZXJlKChjaGFyKSA9PiBjaGFyLmlzTm90RW1wdHkgJiYgY2hhciAhPSAnbnVsbCcpCiAgICAgICAgICAudG9MaXN0KCk7CgogICAgICBpZiAoY2xlYW5DaGFyYWN0ZXJpc3RpY3MuaXNFbXB0eSkgewogICAgICAgIHRocm93IEV4Y2VwdGlvbignTm8gc3RhYmxlIGNoYXJhY3RlcmlzdGljcyBmb3VuZCBmb3IgQW5kcm9pZCBkZXZpY2UnKTsKICAgICAgfQoKICAgICAgLy8gU29ydCB0byBlbnN1cmUgY29uc2lzdGVudCBvcmRlcmluZwogICAgICBjbGVhbkNoYXJhY3RlcmlzdGljcy5zb3J0KCk7CgogICAgICBmaW5hbCBkZXZpY2VTdHJpbmcgPSBjbGVhbkNoYXJhY3RlcmlzdGljcy5qb2luKCd8Jyk7CiAgICAgIGZpbmFsIGRldmljZUhhc2ggPSBfZ2VuZXJhdGVEZXRlcm1pbmlzdGljSGFzaChkZXZpY2VTdHJpbmcpOwoKICAgICAgX2xvZ2dlci5kKAogICAgICAgICckX3RhZzogR2VuZXJhdGVkIEFuZHJvaWQgZGV2aWNlIElEIGZyb20gJwogICAgICAgICcke2NsZWFuQ2hhcmFjdGVyaXN0aWNzLmxlbmd0aH0gY2hhcmFjdGVyaXN0aWNzJywKICAgICAgKTsKICAgICAgcmV0dXJuICdhbmRyb2lkXyRkZXZpY2VIYXNoJzsKICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgX2xvZ2dlci53KCckX3RhZzogQW5kcm9pZCBkZXZpY2UgSUQgZ2VuZXJhdGlvbiBmYWlsZWQ6ICRlJyk7CiAgICAgIHJldGhyb3c7CiAgICB9CiAgfQoKICAvLy8gR2VuZXJhdGUgaU9TIGRldmljZSBJRCB1c2luZyBpZGVudGlmaWVyRm9yVmVuZG9yIG9yIHN0YWJsZSBjaGFyYWN0ZXJpc3RpY3MKICBGdXR1cmU8U3RyaW5nPiBfZ2VuZXJhdGVJT1NEZXZpY2VJZCgpIGFzeW5jIHsKICAgIHRyeSB7CiAgICAgIGZpbmFsIGlvc0luZm8gPSBhd2FpdCBfZGV2aWNlSW5mb1BsdWdpbi5pb3NJbmZvOwoKICAgICAgLy8gRmlyc3QgcHJlZmVyZW5jZTogdXNlIGlkZW50aWZpZXJGb3JWZW5kb3IgYXMgaXQncyBkZXNpZ25lZCB0byBiZSBzdGFibGUKICAgICAgZmluYWwgaWRlbnRpZmllciA9IGlvc0luZm8uaWRlbnRpZmllckZvclZlbmRvcjsKICAgICAgaWYgKGlkZW50aWZpZXIgIT0gbnVsbCAmJiBpZGVudGlmaWVyLmlzTm90RW1wdHkgJiYgaWRlbnRpZmllciAhPSAnbnVsbCcpIHsKICAgICAgICBfbG9nZ2VyLmQoJyRfdGFnOiBVc2luZyBpT1MgaWRlbnRpZmllckZvclZlbmRvcicpOwogICAgICAgIHJldHVybiAnaW9zXyRpZGVudGlmaWVyJzsKICAgICAgfQoKICAgICAgLy8gRmFsbGJhY2s6IHVzZSBzdGFibGUgZGV2aWNlIGNoYXJhY3RlcmlzdGljcwogICAgICBfbG9nZ2VyLmkoCiAgICAgICAgJyRfdGFnOiBpT1MgaWRlbnRpZmllckZvclZlbmRvciBub3QgYXZhaWxhYmxlLCAnCiAgICAgICAgJ3VzaW5nIGRldmljZSBjaGFyYWN0ZXJpc3RpY3MnLAogICAgICApOwoKICAgICAgZmluYWwgc3RhYmxlQ2hhcmFjdGVyaXN0aWNzID0gWwogICAgICAgIGlvc0luZm8ubW9kZWwsCiAgICAgICAgaW9zSW5mby5sb2NhbGl6ZWRNb2RlbCwKICAgICAgICBpb3NJbmZvLnN5c3RlbU5hbWUsCiAgICAgICAgaW9zSW5mby5pc1BoeXNpY2FsRGV2aWNlLnRvU3RyaW5nKCksCiAgICAgICAgLy8gTWFjaGluZSBpZGVudGlmaWVyIGZyb20gdXRzbmFtZSAoaGFyZHdhcmUgbW9kZWwpCiAgICAgICAgaW9zSW5mby51dHNuYW1lLm1hY2hpbmUsCiAgICAgICAgaW9zSW5mby51dHNuYW1lLnN5c25hbWUsCiAgICAgICAgLy8gVGhlc2UgYXJlIGdlbmVyYWxseSBzdGFibGUgZm9yIHRoZSBzYW1lIGRldmljZSBtb2RlbAogICAgICAgIGlvc0luZm8udXRzbmFtZS5ub2RlbmFtZSwKICAgICAgXTsKCiAgICAgIC8vIFJlbW92ZSBlbXB0eSB2YWx1ZXMgYW5kIGNyZWF0ZSBhIGRldGVybWluaXN0aWMgc3RyaW5nCiAgICAgIGZpbmFsIGNsZWFuQ2hhcmFjdGVyaXN0aWNzID0gc3RhYmxlQ2hhcmFjdGVyaXN0aWNzCiAgICAgICAgICAud2hlcmUoKGNoYXIpID0+IGNoYXIuaXNOb3RFbXB0eSAmJiBjaGFyICE9ICdudWxsJykKICAgICAgICAgIC50b0xpc3QoKTsKCiAgICAgIGlmIChjbGVhbkNoYXJhY3RlcmlzdGljcy5pc0VtcHR5KSB7CiAgICAgICAgdGhyb3cgRXhjZXB0aW9uKCdObyBzdGFibGUgY2hhcmFjdGVyaXN0aWNzIGZvdW5kIGZvciBpT1MgZGV2aWNlJyk7CiAgICAgIH0KCiAgICAgIC8vIFNvcnQgdG8gZW5zdXJlIGNvbnNpc3RlbnQgb3JkZXJpbmcKICAgICAgY2xlYW5DaGFyYWN0ZXJpc3RpY3Muc29ydCgpOwoKICAgICAgZmluYWwgZGV2aWNlU3RyaW5nID0gY2xlYW5DaGFyYWN0ZXJpc3RpY3Muam9pbignfCcpOwogICAgICBmaW5hbCBkZXZpY2VIYXNoID0gX2dlbmVyYXRlRGV0ZXJtaW5pc3RpY0hhc2goZGV2aWNlU3RyaW5nKTsKCiAgICAgIF9sb2dnZXIuZCgKICAgICAgICAnJF90YWc6IEdlbmVyYXRlZCBpT1MgZGV2aWNlIElEIGZyb20gJwogICAgICAgICcke2NsZWFuQ2hhcmFjdGVyaXN0aWNzLmxlbmd0aH0gY2hhcmFjdGVyaXN0aWNzJywKICAgICAgKTsKICAgICAgcmV0dXJuICdpb3NfJGRldmljZUhhc2gnOwogICAgfSBjYXRjaCAoZSkgewogICAgICBfbG9nZ2VyLncoJyRfdGFnOiBpT1MgZGV2aWNlIElEIGdlbmVyYXRpb24gZmFpbGVkOiAkZScpOwogICAgICByZXRocm93OwogICAgfQogIH0KCiAgLy8vIEdldCBBbmRyb2lkIGRldmljZSBuYW1lIGluIGZvcm1hdCAiQnJhbmQgTW9kZWwiCiAgRnV0dXJlPFN0cmluZz4gX2dldEFuZHJvaWREZXZpY2VOYW1lKCkgYXN5bmMgewogICAgZmluYWwgYW5kcm9pZEluZm8gPSBhd2FpdCBfZGV2aWNlSW5mb1BsdWdpbi5hbmRyb2lkSW5mbzsKICAgIGZpbmFsIGJyYW5kID0gYW5kcm9pZEluZm8uYnJhbmQ7CiAgICBmaW5hbCBtb2RlbCA9IGFuZHJvaWRJbmZvLm1vZGVsOwoKICAgIHJldHVybiAnJGJyYW5kICRtb2RlbCc7CiAgfQoKICAvLy8gR2V0IGlPUyBkZXZpY2UgbmFtZSBpbiBmb3JtYXQgIk5hbWUgKE1vZGVsKSIKICBGdXR1cmU8U3RyaW5nPiBfZ2V0SU9TRGV2aWNlTmFtZSgpIGFzeW5jIHsKICAgIGZpbmFsIGlvc0luZm8gPSBhd2FpdCBfZGV2aWNlSW5mb1BsdWdpbi5pb3NJbmZvOwogICAgZmluYWwgbmFtZSA9IGlvc0luZm8ubmFtZTsKICAgIGZpbmFsIG1vZGVsID0gaW9zSW5mby5tb2RlbDsKCiAgICByZXR1cm4gJyRuYW1lICgkbW9kZWwpJzsKICB9CgogIC8vLyBHZW5lcmF0ZSBhIGRldGVybWluaXN0aWMgaGFzaCBmcm9tIGRldmljZSBjaGFyYWN0ZXJpc3RpY3MKICAvLy8gVXNlcyBTSEEtMjU2IHRvIGNyZWF0ZSBhIGNvbnNpc3RlbnQsIHN0YWJsZSBoYXNoCiAgU3RyaW5nIF9nZW5lcmF0ZURldGVybWluaXN0aWNIYXNoKFN0cmluZyBpbnB1dCkgewogICAgLy8gQWRkIGEgc2FsdCB0byBtYWtlIHRoZSBoYXNoIG1vcmUgdW5pcXVlIHdoaWxlIGtlZXBpbmcgaXQgZGV0ZXJtaW5pc3RpYwogICAgY29uc3Qgc2FsdCA9ICdkZXZpY2VfaWRlbnRpZmllcl9zYWx0XzIwMjQnOwogICAgZmluYWwgc2FsdGVkSW5wdXQgPSAnJHNhbHR8JGlucHV0JzsKCiAgICBmaW5hbCBieXRlcyA9IHV0ZjguZW5jb2RlKHNhbHRlZElucHV0KTsKICAgIGZpbmFsIGRpZ2VzdCA9IHNoYTI1Ni5jb252ZXJ0KGJ5dGVzKTsKCiAgICAvLyBSZXR1cm4gZmlyc3QgMTYgY2hhcmFjdGVycyBmb3IgcmVhc29uYWJsZSBsZW5ndGgKICAgIHJldHVybiBkaWdlc3QudG9TdHJpbmcoKS5zdWJzdHJpbmcoMCwgMTYpOwogIH0KCiAgLy8vIEdlbmVyYXRlIGEgZmFsbGJhY2sgZGV2aWNlIElEIHdoZW4gYWxsIG90aGVyIG1ldGhvZHMgZmFpbAogIFN0cmluZyBfZ2VuZXJhdGVGYWxsYmFja0lkKCkgewogICAgZmluYWwgcGxhdGZvcm0gPSBQbGF0Zm9ybS5pc0FuZHJvaWQgPyAnYW5kcm9pZCcgOiAnaW9zJzsKCiAgICAvLyBVc2UgYSBkZXRlcm1pbmlzdGljIGZhbGxiYWNrIGJhc2VkIG9uIHBsYXRmb3JtCiAgICBmaW5hbCBmYWxsYmFja1N0cmluZyA9ICcke3BsYXRmb3JtfV9mYWxsYmFja19kZXZpY2UnOwogICAgZmluYWwgZmFsbGJhY2tIYXNoID0gX2dlbmVyYXRlRGV0ZXJtaW5pc3RpY0hhc2goZmFsbGJhY2tTdHJpbmcpOwoKICAgIF9sb2dnZXIudygnJF90YWc6IFVzaW5nIGRldGVybWluaXN0aWMgZmFsbGJhY2sgSUQnKTsKICAgIHJldHVybiAnJHtwbGF0Zm9ybX1fJGZhbGxiYWNrSGFzaCc7CiAgfQoKICAvLy8gR2V0IGZhbGxiYWNrIGRldmljZSBuYW1lIHdoZW4gZGV0ZWN0aW9uIGZhaWxzCiAgU3RyaW5nIF9nZXRGYWxsYmFja0RldmljZU5hbWUoKSB7CiAgICByZXR1cm4gUGxhdGZvcm0uaXNBbmRyb2lkID8gJ0FuZHJvaWQgRGV2aWNlJyA6ICdpT1MgRGV2aWNlJzsKICB9Cn0K", + "aW1wb3J0ICdkYXJ0Om1hdGgnOwoKaW1wb3J0ICdwYWNrYWdlOmNvcmUvbG9nZ2VyL2xvZ2dlci5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRldmljZV9pbmZvX3BsdXMvZGV2aWNlX2luZm9fcGx1cy5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZsdXR0ZXIvZm91bmRhdGlvbi5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOm5vdGlmaWNhdGlvbnMvc3JjL2RldmljZV9pbmZvL2RldmljZV9pbmZvLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6c2hhcmVkX3ByZWZlcmVuY2VzL3NoYXJlZF9wcmVmZXJlbmNlcy5kYXJ0JzsKCi8vLyBQZXJzaXN0cyBhIHJhbmRvbSBpbnN0YWxsYXRpb24gaWRlbnRpZmllciwgaW5kZXBlbmRlbnQgb2YgaGFyZHdhcmUgbW9kZWxzLgpjbGFzcyBTaGFyZWRQcmVmZXJlbmNlc0luc3RhbGxhdGlvbklkU3RvcmUgaW1wbGVtZW50cyBJbnN0YWxsYXRpb25JZFN0b3JlIHsKICBTaGFyZWRQcmVmZXJlbmNlc0luc3RhbGxhdGlvbklkU3RvcmUoe1NoYXJlZFByZWZlcmVuY2VzPyBwcmVmZXJlbmNlc30pCiAgICA6IF9wcm92aWRlZCA9IHByZWZlcmVuY2VzOwogIGZpbmFsIFNoYXJlZFByZWZlcmVuY2VzPyBfcHJvdmlkZWQ7CiAgRnV0dXJlPFNoYXJlZFByZWZlcmVuY2VzPiBnZXQgX3ByZWZlcmVuY2VzIGFzeW5jID0+CiAgICAgIF9wcm92aWRlZCA/PyBhd2FpdCBTaGFyZWRQcmVmZXJlbmNlcy5nZXRJbnN0YW5jZSgpOwogIHN0YXRpYyBjb25zdCBfa2V5ID0gJ25vbnN0b3AuaW5zdGFsbGF0aW9uX2lkJzsKCiAgQG92ZXJyaWRlCiAgRnV0dXJlPFN0cmluZz8+IHJlYWQoKSBhc3luYyA9PiAoYXdhaXQgX3ByZWZlcmVuY2VzKS5nZXRTdHJpbmcoX2tleSk7CgogIEBvdmVycmlkZQogIEZ1dHVyZTx2b2lkPiB3cml0ZShTdHJpbmcgaWQpIGFzeW5jIHsKICAgIGZpbmFsIHNhdmVkID0gYXdhaXQgKGF3YWl0IF9wcmVmZXJlbmNlcykuc2V0U3RyaW5nKF9rZXksIGlkKTsKICAgIGlmICghc2F2ZWQpIHRocm93IFN0YXRlRXJyb3IoJ0NvdWxkIG5vdCBwZXJzaXN0IGluc3RhbGxhdGlvbiBJRCcpOwogIH0KfQoKLy8vIFN1cHBsaWVzIGluc3RhbGxhdGlvbiBpZGVudGl0eSBhbmQgYSBodW1hbi1yZWFkYWJsZSBkZXZpY2UgbGFiZWwuCmNsYXNzIERldmljZUluZm9JbXBsIGltcGxlbWVudHMgRGV2aWNlSW5mbyB7CiAgRGV2aWNlSW5mb0ltcGwoewogICAgcmVxdWlyZWQgTG9nZ2VyIGxvZ2dlciwKICAgIERldmljZUluZm9QbHVnaW4/IGRldmljZUluZm9QbHVnaW4sCiAgICBJbnN0YWxsYXRpb25JZFN0b3JlPyBzdG9yZSwKICAgIFN0cmluZyBGdW5jdGlvbigpPyBjcmVhdGVJZCwKICB9KSA6IF9sb2dnZXIgPSBsb2dnZXIsCiAgICAgICBfcGx1Z2luID0gZGV2aWNlSW5mb1BsdWdpbiA/PyBEZXZpY2VJbmZvUGx1Z2luKCksCiAgICAgICBfc3RvcmUgPSBzdG9yZSA/PyBTaGFyZWRQcmVmZXJlbmNlc0luc3RhbGxhdGlvbklkU3RvcmUoKSwKICAgICAgIF9jcmVhdGVJZCA9IGNyZWF0ZUlkID8/IF9yYW5kb21JZDsKCiAgZmluYWwgTG9nZ2VyIF9sb2dnZXI7CiAgZmluYWwgRGV2aWNlSW5mb1BsdWdpbiBfcGx1Z2luOwogIGZpbmFsIEluc3RhbGxhdGlvbklkU3RvcmUgX3N0b3JlOwogIGZpbmFsIFN0cmluZyBGdW5jdGlvbigpIF9jcmVhdGVJZDsKICBGdXR1cmU8U3RyaW5nPj8gX2lkOwoKICBzdGF0aWMgU3RyaW5nIF9yYW5kb21JZCgpIHsKICAgIGZpbmFsIHJhbmRvbSA9IFJhbmRvbS5zZWN1cmUoKTsKICAgIHJldHVybiBMaXN0LmdlbmVyYXRlKAogICAgICAxNiwKICAgICAgKF8pID0+IHJhbmRvbS5uZXh0SW50KDI1NikudG9SYWRpeFN0cmluZygxNikucGFkTGVmdCgyLCAnMCcpLAogICAgKS5qb2luKCk7CiAgfQoKICBAb3ZlcnJpZGUKICBGdXR1cmU8U3RyaW5nPiBnZW5lcmF0ZURldmljZUlkKCkgYXN5bmMgewogICAgaWYgKF9pZCAhPSBudWxsKSByZXR1cm4gX2lkITsKICAgIGZpbmFsIHBlbmRpbmcgPSBfbG9hZElkKCk7CiAgICBfaWQgPSBwZW5kaW5nOwogICAgdHJ5IHsKICAgICAgcmV0dXJuIGF3YWl0IHBlbmRpbmc7CiAgICB9IGNhdGNoIChlcnJvcikgewogICAgICBfaWQgPSBudWxsOwogICAgICBfbG9nZ2VyLncoJ0luc3RhbGxhdGlvbiBJRCBzdG9yYWdlIGZhaWxlZDogJGVycm9yJyk7CiAgICAgIHJldGhyb3c7CiAgICB9CiAgfQoKICBGdXR1cmU8U3RyaW5nPiBfbG9hZElkKCkgYXN5bmMgewogICAgZmluYWwgZXhpc3RpbmcgPSBhd2FpdCBfc3RvcmUucmVhZCgpOwogICAgaWYgKGV4aXN0aW5nICE9IG51bGwgJiYgZXhpc3RpbmcuaXNOb3RFbXB0eSkgcmV0dXJuIGV4aXN0aW5nOwogICAgZmluYWwgaWQgPSBfY3JlYXRlSWQoKTsKICAgIGF3YWl0IF9zdG9yZS53cml0ZShpZCk7CiAgICByZXR1cm4gaWQ7CiAgfQoKICBAb3ZlcnJpZGUKICBGdXR1cmU8U3RyaW5nPiBnZXREZXZpY2VOYW1lKCkgYXN5bmMgewogICAgdHJ5IHsKICAgICAgZmluYWwgZGF0YSA9IChhd2FpdCBfcGx1Z2luLmRldmljZUluZm8pLmRhdGE7CiAgICAgIGZpbmFsIG5hbWUgPSBkYXRhWyduYW1lJ10gPz8gZGF0YVsnbW9kZWwnXSA/PyBkYXRhWydjb21wdXRlck5hbWUnXTsKICAgICAgaWYgKG5hbWUgaXMgU3RyaW5nICYmIG5hbWUuaXNOb3RFbXB0eSkgcmV0dXJuIG5hbWU7CiAgICB9IGNhdGNoIChlcnJvcikgewogICAgICBfbG9nZ2VyLncoJ0RldmljZSBuYW1lIHVuYXZhaWxhYmxlOiAkZXJyb3InKTsKICAgIH0KICAgIHJldHVybiBrSXNXZWIgPyAnV2ViIGJyb3dzZXInIDogZGVmYXVsdFRhcmdldFBsYXRmb3JtLm5hbWU7CiAgfQp9Cg==", "type": "text" }, { @@ -1321,7 +1499,7 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "path": "{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/src/di/notification_di.dart", "data": - "aW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6bm90aWZpY2F0aW9ucy9zcmMvY2xpZW50L2luZGV4LmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6bm90aWZpY2F0aW9ucy9zcmMvY29uZmlnL2luZGV4LmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6bm90aWZpY2F0aW9ucy9zcmMvZGV2aWNlX2luZm8vaW5kZXguZGFydCc7CmltcG9ydCAncGFja2FnZTpub3RpZmljYXRpb25zL3NyYy9zZXJ2aWNlcy9ub3RpZmljYXRpb25fcGVybWlzc2lvbl9tYW5hZ2VyLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6bm90aWZpY2F0aW9ucy9zcmMvc2VydmljZXMvbm90aWZpY2F0aW9uX3Rva2VuX21hbmFnZXIuZGFydCc7CgovLy8gUmVnaXN0ZXIgbm90aWZpY2F0aW9uIHNlcnZpY2VzIHdpdGggZGVwZW5kZW5jeSBpbmplY3Rpb24KRnV0dXJlPHZvaWQ+IHJlZ2lzdGVyTm90aWZpY2F0aW9uV2l0aERJKE5vdGlmaWNhdGlvbkNvbmZpZyBjb25maWcpIGFzeW5jIHsKICAvLyBSZWdpc3RlciBjb25maWcKICBkaS5yZWdpc3RlcjxOb3RpZmljYXRpb25Db25maWc+KGNvbmZpZyk7CgogIC8vIFJlZ2lzdGVyIGRldmljZSBpbmZvIHNlcnZpY2UKICBkaS5yZWdpc3RlcjxEZXZpY2VJbmZvPihEZXZpY2VJbmZvSW1wbCgpKTsKCiAgLy8gUmVnaXN0ZXIgdG9rZW4gbWFuYWdlcgogIGRpLnJlZ2lzdGVyPE5vdGlmaWNhdGlvblRva2VuTWFuYWdlcj4oRmlyZWJhc2VUb2tlbk1hbmFnZXIoKSk7CgogIC8vIFJlZ2lzdGVyIHBlcm1pc3Npb24gbWFuYWdlcgogIGRpLnJlZ2lzdGVyPE5vdGlmaWNhdGlvblBlcm1pc3Npb25NYW5hZ2VyPihGaXJlYmFzZVBlcm1pc3Npb25NYW5hZ2VyKCkpOwoKICAvLyBSZWdpc3RlciBub3RpZmljYXRpb24gY2xpZW50IHdpdGggcHJvcGVyIGRpc3Bvc2FsCiAgZGkucmVnaXN0ZXI8Tm90aWZpY2F0aW9uQ2xpZW50PigKICAgIEZpcmViYXNlTm90aWZpY2F0aW9uQ2xpZW50KGNvbmZpZzogY29uZmlnKSwKICAgIGRpc3Bvc2U6IChjbGllbnQpID0+IGNsaWVudC5kaXNwb3NlKCksCiAgKTsKfQo=", + "aW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Y29yZS9jb3JlLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZmlyZWJhc2VfbWVzc2FnaW5nL2ZpcmViYXNlX21lc3NhZ2luZy5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOm5vdGlmaWNhdGlvbnMvc3JjL2NsaWVudC9pbmRleC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOm5vdGlmaWNhdGlvbnMvc3JjL2NvbmZpZy9pbmRleC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOm5vdGlmaWNhdGlvbnMvc3JjL2RldmljZV9pbmZvL2luZGV4LmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6bm90aWZpY2F0aW9ucy9zcmMvc2VydmljZXMvbm90aWZpY2F0aW9uX3Blcm1pc3Npb25fbWFuYWdlci5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOm5vdGlmaWNhdGlvbnMvc3JjL3NlcnZpY2VzL25vdGlmaWNhdGlvbl90b2tlbl9tYW5hZ2VyLmRhcnQnOwoKLy8vIFJlZ2lzdGVyIG5vdGlmaWNhdGlvbiBzZXJ2aWNlcyB3aXRoIGRlcGVuZGVuY3kgaW5qZWN0aW9uCkZ1dHVyZTx2b2lkPiByZWdpc3Rlck5vdGlmaWNhdGlvbldpdGhESSgKICBOb3RpZmljYXRpb25Db25maWcgY29uZmlnLCB7CiAgRmlyZWJhc2VNZXNzYWdpbmc/IG1lc3NhZ2luZywKfSkgYXN5bmMgewogIGZpbmFsIHNlbGVjdGVkTWVzc2FnaW5nID0gbWVzc2FnaW5nID8/IEZpcmViYXNlTWVzc2FnaW5nLmluc3RhbmNlOwogIC8vIFJlZ2lzdGVyIGNvbmZpZwogIGRpLnJlZ2lzdGVyPE5vdGlmaWNhdGlvbkNvbmZpZz4oY29uZmlnKTsKCiAgLy8gUmVnaXN0ZXIgZGV2aWNlIGluZm8gc2VydmljZQogIGRpLnJlZ2lzdGVyPERldmljZUluZm8+KERldmljZUluZm9JbXBsKGxvZ2dlcjogZGkuZ2V0PExvZ2dlcj4oKSkpOwoKICAvLyBSZWdpc3RlciB0b2tlbiBtYW5hZ2VyCiAgZGkucmVnaXN0ZXI8Tm90aWZpY2F0aW9uVG9rZW5NYW5hZ2VyPigKICAgIEZpcmViYXNlVG9rZW5NYW5hZ2VyKGZpcmViYXNlTWVzc2FnaW5nOiBzZWxlY3RlZE1lc3NhZ2luZyksCiAgKTsKCiAgLy8gUmVnaXN0ZXIgcGVybWlzc2lvbiBtYW5hZ2VyCiAgZGkucmVnaXN0ZXI8Tm90aWZpY2F0aW9uUGVybWlzc2lvbk1hbmFnZXI+KAogICAgRmlyZWJhc2VQZXJtaXNzaW9uTWFuYWdlcihmaXJlYmFzZU1lc3NhZ2luZzogc2VsZWN0ZWRNZXNzYWdpbmcpLAogICk7CgogIC8vIFJlZ2lzdGVyIG5vdGlmaWNhdGlvbiBjbGllbnQgd2l0aCBwcm9wZXIgZGlzcG9zYWwKICBkaS5yZWdpc3RlcjxOb3RpZmljYXRpb25DbGllbnQ+KAogICAgRmlyZWJhc2VOb3RpZmljYXRpb25DbGllbnQoCiAgICAgIGNvbmZpZzogY29uZmlnLAogICAgICBsb2dnZXI6IGRpLmdldDxMb2dnZXI+KCksCiAgICAgIG1lc3NhZ2luZzogc2VsZWN0ZWRNZXNzYWdpbmcsCiAgICAgIHRva2VuTWFuYWdlcjogZGkuZ2V0PE5vdGlmaWNhdGlvblRva2VuTWFuYWdlcj4oKSwKICAgICAgcGVybWlzc2lvbk1hbmFnZXI6IGRpLmdldDxOb3RpZmljYXRpb25QZXJtaXNzaW9uTWFuYWdlcj4oKSwKICAgICksCiAgICBkaXNwb3NlOiAoY2xpZW50KSA9PiBjbGllbnQuZGlzcG9zZSgpLAogICk7Cn0K", "type": "text" }, { @@ -1368,21 +1546,42 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "path": "{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/src/services/notification_permission_manager.dart", "data": - "aW1wb3J0ICdwYWNrYWdlOmNvcmUvbG9nZ2VyL2xvZ2dlci5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZmlyZWJhc2VfbWVzc2FnaW5nL2ZpcmViYXNlX21lc3NhZ2luZy5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOm5ldHdvcmsvbmV0d29yay5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOm5vdGlmaWNhdGlvbnMvc3JjL2V4Y2VwdGlvbnMvbm90aWZpY2F0aW9uX2V4Y2VwdGlvbnMuZGFydCc7CgphYnN0cmFjdCBjbGFzcyBOb3RpZmljYXRpb25QZXJtaXNzaW9uTWFuYWdlciB7CiAgRnV0dXJlPGJvb2w+IHJlcXVlc3RQZXJtaXNzaW9ucygpOwp9CgpjbGFzcyBGaXJlYmFzZVBlcm1pc3Npb25NYW5hZ2VyIGltcGxlbWVudHMgTm90aWZpY2F0aW9uUGVybWlzc2lvbk1hbmFnZXIgewogIHN0YXRpYyBjb25zdCBTdHJpbmcgX3RhZyA9ICdGaXJlYmFzZVBlcm1pc3Npb25NYW5hZ2VyJzsKCiAgZmluYWwgTG9nZ2VyIF9sb2dnZXI7CiAgZmluYWwgRmlyZWJhc2VNZXNzYWdpbmcgX2ZpcmViYXNlTWVzc2FnaW5nOwoKICBGaXJlYmFzZVBlcm1pc3Npb25NYW5hZ2VyKHsKICAgIExvZ2dlcj8gbG9nZ2VyLAogICAgRmlyZWJhc2VNZXNzYWdpbmc/IGZpcmViYXNlTWVzc2FnaW5nLAogIH0pIDogX2xvZ2dlciA9IGxvZ2dlciA/PyBkaS5nZXQ8TG9nZ2VyPigpLAogICAgICAgX2ZpcmViYXNlTWVzc2FnaW5nID0gZmlyZWJhc2VNZXNzYWdpbmcgPz8gRmlyZWJhc2VNZXNzYWdpbmcuaW5zdGFuY2U7CgogIEBvdmVycmlkZQogIEZ1dHVyZTxib29sPiByZXF1ZXN0UGVybWlzc2lvbnMoKSBhc3luYyB7CiAgICB0cnkgewogICAgICBfbG9nZ2VyLmkoJyRfdGFnOiBSZXF1ZXN0aW5nIG5vdGlmaWNhdGlvbiBwZXJtaXNzaW9ucycpOwogICAgICBmaW5hbCBhdXRoU2V0dGluZ3MgPSBhd2FpdCBfZmlyZWJhc2VNZXNzYWdpbmcucmVxdWVzdFBlcm1pc3Npb24oKTsKCiAgICAgIGZpbmFsIGlzR3JhbnRlZCA9CiAgICAgICAgICBhdXRoU2V0dGluZ3MuYXV0aG9yaXphdGlvblN0YXR1cyA9PSBBdXRob3JpemF0aW9uU3RhdHVzLmF1dGhvcml6ZWQgfHwKICAgICAgICAgIGF1dGhTZXR0aW5ncy5hdXRob3JpemF0aW9uU3RhdHVzID09IEF1dGhvcml6YXRpb25TdGF0dXMucHJvdmlzaW9uYWw7CgogICAgICBfbG9nZ2VyLmkoCiAgICAgICAgJyRfdGFnOiBOb3RpZmljYXRpb24gcGVybWlzc2lvbnMgcmVxdWVzdGVkICcKICAgICAgICAnd2l0aCBzdGF0dXM6ICR7YXV0aFNldHRpbmdzLmF1dGhvcml6YXRpb25TdGF0dXN9LCAnCiAgICAgICAgJ2dyYW50ZWQ6ICRpc0dyYW50ZWQnLAogICAgICApOwoKICAgICAgcmV0dXJuIGlzR3JhbnRlZDsKICAgIH0gY2F0Y2ggKGUsIHMpIHsKICAgICAgX2xvZ2dlci5lKCckX3RhZzogRXJyb3IgcmVxdWVzdGluZyBwZXJtaXNzaW9ucycsIGUsIHMpOwogICAgICB0aHJvdyBOb3RpZmljYXRpb25FeGNlcHRpb24obWVzc2FnZTogZS5tZXNzYWdlKCkpOwogICAgfQogIH0KfQo=", + "aW1wb3J0ICdwYWNrYWdlOmNvcmUvbG9nZ2VyL2xvZ2dlci5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6ZmlyZWJhc2VfbWVzc2FnaW5nL2ZpcmViYXNlX21lc3NhZ2luZy5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOm5ldHdvcmsvbmV0d29yay5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOm5vdGlmaWNhdGlvbnMvc3JjL2V4Y2VwdGlvbnMvbm90aWZpY2F0aW9uX2V4Y2VwdGlvbnMuZGFydCc7CgphYnN0cmFjdCBjbGFzcyBOb3RpZmljYXRpb25QZXJtaXNzaW9uTWFuYWdlciB7CiAgRnV0dXJlPGJvb2w+IHJlcXVlc3RQZXJtaXNzaW9ucyh7Ym9vbCBwcm92aXNpb25hbCA9IGZhbHNlfSk7Cn0KCmNsYXNzIEZpcmViYXNlUGVybWlzc2lvbk1hbmFnZXIgaW1wbGVtZW50cyBOb3RpZmljYXRpb25QZXJtaXNzaW9uTWFuYWdlciB7CiAgc3RhdGljIGNvbnN0IFN0cmluZyBfdGFnID0gJ0ZpcmViYXNlUGVybWlzc2lvbk1hbmFnZXInOwoKICBmaW5hbCBMb2dnZXIgX2xvZ2dlcjsKICBmaW5hbCBGaXJlYmFzZU1lc3NhZ2luZyBfZmlyZWJhc2VNZXNzYWdpbmc7CgogIEZpcmViYXNlUGVybWlzc2lvbk1hbmFnZXIoewogICAgTG9nZ2VyPyBsb2dnZXIsCiAgICBGaXJlYmFzZU1lc3NhZ2luZz8gZmlyZWJhc2VNZXNzYWdpbmcsCiAgfSkgOiBfbG9nZ2VyID0gbG9nZ2VyID8/IGRpLmdldDxMb2dnZXI+KCksCiAgICAgICBfZmlyZWJhc2VNZXNzYWdpbmcgPSBmaXJlYmFzZU1lc3NhZ2luZyA/PyBGaXJlYmFzZU1lc3NhZ2luZy5pbnN0YW5jZTsKCiAgQG92ZXJyaWRlCiAgRnV0dXJlPGJvb2w+IHJlcXVlc3RQZXJtaXNzaW9ucyh7Ym9vbCBwcm92aXNpb25hbCA9IGZhbHNlfSkgYXN5bmMgewogICAgdHJ5IHsKICAgICAgX2xvZ2dlci5pKCckX3RhZzogUmVxdWVzdGluZyBub3RpZmljYXRpb24gcGVybWlzc2lvbnMnKTsKICAgICAgZmluYWwgYXV0aFNldHRpbmdzID0gYXdhaXQgX2ZpcmViYXNlTWVzc2FnaW5nLnJlcXVlc3RQZXJtaXNzaW9uKAogICAgICAgIHByb3Zpc2lvbmFsOiBwcm92aXNpb25hbCwKICAgICAgKTsKCiAgICAgIGZpbmFsIGlzR3JhbnRlZCA9CiAgICAgICAgICBhdXRoU2V0dGluZ3MuYXV0aG9yaXphdGlvblN0YXR1cyA9PSBBdXRob3JpemF0aW9uU3RhdHVzLmF1dGhvcml6ZWQgfHwKICAgICAgICAgIGF1dGhTZXR0aW5ncy5hdXRob3JpemF0aW9uU3RhdHVzID09IEF1dGhvcml6YXRpb25TdGF0dXMucHJvdmlzaW9uYWw7CgogICAgICBfbG9nZ2VyLmkoCiAgICAgICAgJyRfdGFnOiBOb3RpZmljYXRpb24gcGVybWlzc2lvbnMgcmVxdWVzdGVkICcKICAgICAgICAnd2l0aCBzdGF0dXM6ICR7YXV0aFNldHRpbmdzLmF1dGhvcml6YXRpb25TdGF0dXN9LCAnCiAgICAgICAgJ2dyYW50ZWQ6ICRpc0dyYW50ZWQnLAogICAgICApOwoKICAgICAgcmV0dXJuIGlzR3JhbnRlZDsKICAgIH0gY2F0Y2ggKGUsIHMpIHsKICAgICAgX2xvZ2dlci5lKCckX3RhZzogRXJyb3IgcmVxdWVzdGluZyBwZXJtaXNzaW9ucycsIGUsIHMpOwogICAgICB0aHJvdyBOb3RpZmljYXRpb25FeGNlcHRpb24obWVzc2FnZTogZS5tZXNzYWdlKCkpOwogICAgfQogIH0KfQo=", "type": "text" }, { "path": "{{ name.snakeCase() }}/packages/{{notifications_dir}}/lib/src/services/notification_token_manager.dart", "data": - "aW1wb3J0ICdkYXJ0OmlvJzsKCmltcG9ydCAncGFja2FnZTpjb3JlL2xvZ2dlci9sb2dnZXIuZGFydCc7CmltcG9ydCAncGFja2FnZTpkaS9kaS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZpcmViYXNlX21lc3NhZ2luZy9maXJlYmFzZV9tZXNzYWdpbmcuZGFydCc7CmltcG9ydCAncGFja2FnZTpuZXR3b3JrL25ldHdvcmsuZGFydCc7CmltcG9ydCAncGFja2FnZTpub3RpZmljYXRpb25zL25vdGlmaWNhdGlvbnMuZGFydCc7CgphYnN0cmFjdCBjbGFzcyBOb3RpZmljYXRpb25Ub2tlbk1hbmFnZXIgewogIEZ1dHVyZTxTdHJpbmc/PiBnZXRGQ01Ub2tlbigpOwoKICBGdXR1cmU8U3RyaW5nPiByZWdpc3RlclRva2VuKFN0cmluZyBmY21Ub2tlbik7CgogIEZ1dHVyZTx2b2lkPiB1blJlZ2lzdGVyVG9rZW4oU3RyaW5nIGRldmljZUlkKTsKCiAgRnV0dXJlPHZvaWQ+IGhhbmRsZVRva2VuUmVmcmVzaChTdHJpbmcgbmV3VG9rZW4pOwp9CgpjbGFzcyBGaXJlYmFzZVRva2VuTWFuYWdlciBpbXBsZW1lbnRzIE5vdGlmaWNhdGlvblRva2VuTWFuYWdlciB7CiAgc3RhdGljIGNvbnN0IFN0cmluZyBfdGFnID0gJ0ZpcmViYXNlVG9rZW5NYW5hZ2VyJzsKCiAgZmluYWwgTG9nZ2VyIF9sb2dnZXI7CiAgZmluYWwgTmV0d29ya0NsaWVudCBfbmV0d29ya0NsaWVudDsKICBmaW5hbCBEZXZpY2VJbmZvIF9kZXZpY2VJbmZvOwogIGZpbmFsIEZpcmViYXNlTWVzc2FnaW5nIF9maXJlYmFzZU1lc3NhZ2luZzsKCiAgRmlyZWJhc2VUb2tlbk1hbmFnZXIoewogICAgTG9nZ2VyPyBsb2dnZXIsCiAgICBOZXR3b3JrQ2xpZW50PyBuZXR3b3JrQ2xpZW50LAogICAgRGV2aWNlSW5mbz8gZGV2aWNlSW5mbywKICAgIEZpcmViYXNlTWVzc2FnaW5nPyBmaXJlYmFzZU1lc3NhZ2luZywKICB9KSA6IF9sb2dnZXIgPSBsb2dnZXIgPz8gZGkuZ2V0PExvZ2dlcj4oKSwKICAgICAgIF9uZXR3b3JrQ2xpZW50ID0gbmV0d29ya0NsaWVudCA/PyBkaS5nZXQ8TmV0d29ya0NsaWVudD4oKSwKICAgICAgIF9kZXZpY2VJbmZvID0gZGV2aWNlSW5mbyA/PyBkaS5nZXQ8RGV2aWNlSW5mbz4oKSwKICAgICAgIF9maXJlYmFzZU1lc3NhZ2luZyA9IGZpcmViYXNlTWVzc2FnaW5nID8/IEZpcmViYXNlTWVzc2FnaW5nLmluc3RhbmNlOwoKICBAb3ZlcnJpZGUKICBGdXR1cmU8U3RyaW5nPz4gZ2V0RkNNVG9rZW4oKSBhc3luYyB7CiAgICB0cnkgewogICAgICBmaW5hbCB0b2tlbiA9IGF3YWl0IF9maXJlYmFzZU1lc3NhZ2luZy5nZXRUb2tlbigpOwogICAgICBpZiAodG9rZW4gIT0gbnVsbCkgewogICAgICAgIF9sb2dnZXIuaSgnJF90YWc6IEZDTSBUb2tlbiBvYnRhaW5lZCBzdWNjZXNzZnVsbHknKTsKICAgICAgfSBlbHNlIHsKICAgICAgICBfbG9nZ2VyLncoJyRfdGFnOiBGYWlsZWQgdG8gb2J0YWluIEZDTSB0b2tlbicpOwogICAgICB9CiAgICAgIHJldHVybiB0b2tlbjsKICAgIH0gY2F0Y2ggKGUsIHMpIHsKICAgICAgX2xvZ2dlci5lKCckX3RhZzogRXJyb3IgZ2V0dGluZyBGQ00gdG9rZW4nLCBlLCBzKTsKICAgICAgcmV0aHJvdzsKICAgIH0KICB9CgogIEBvdmVycmlkZQogIEZ1dHVyZTxTdHJpbmc+IHJlZ2lzdGVyVG9rZW4oU3RyaW5nIGZjbVRva2VuKSBhc3luYyB7CiAgICB0cnkgewogICAgICBfbG9nZ2VyLmkoJyRfdGFnOiBSZWdpc3RlcmluZyBGQ00gdG9rZW4gd2l0aCBiYWNrZW5kJyk7CgogICAgICBmaW5hbCBkZXZpY2VJZCA9IGF3YWl0IF9kZXZpY2VJbmZvLmdlbmVyYXRlRGV2aWNlSWQoKTsKICAgICAgZmluYWwgZGV2aWNlTmFtZSA9IGF3YWl0IF9kZXZpY2VJbmZvLmdldERldmljZU5hbWUoKTsKICAgICAgZmluYWwgZGV2aWNlVHlwZSA9IFBsYXRmb3JtLmlzSU9TID8gJ2lvcycgOiAnYW5kcm9pZCc7CgogICAgICBmaW5hbCByZXF1ZXN0ID0gRGV2aWNlVG9rZW5SZXF1ZXN0KAogICAgICAgIGZjbVRva2VuOiBmY21Ub2tlbiwKICAgICAgICBkZXZpY2VJZDogZGV2aWNlSWQsCiAgICAgICAgZGV2aWNlTmFtZTogZGV2aWNlTmFtZSwKICAgICAgICBkZXZpY2VUeXBlOiBkZXZpY2VUeXBlLAogICAgICApOwoKICAgICAgYXdhaXQgX25ldHdvcmtDbGllbnQucG9zdDxNYXA8U3RyaW5nLCBkeW5hbWljPj4oCiAgICAgICAgJy9kZXZpY2UtdG9rZW5zL21lJywKICAgICAgICBkYXRhOiByZXF1ZXN0LnRvSnNvbigpLAogICAgICAgIGZyb21Kc29uVDogKGpzb24pID0+IGpzb24gYXMgTWFwPFN0cmluZywgZHluYW1pYz4sCiAgICAgICk7CiAgICAgIF9sb2dnZXIuaSgnJF90YWc6IEZDTSB0b2tlbiByZWdpc3RlcmVkIHN1Y2Nlc3NmdWxseScpOwogICAgICByZXR1cm4gZGV2aWNlSWQ7CiAgICB9IGNhdGNoIChlLCBzKSB7CiAgICAgIF9sb2dnZXIuZSgnJF90YWc6IEVycm9yIHJlZ2lzdGVyaW5nIEZDTSB0b2tlbicsIGUsIHMpOwogICAgICByZXRocm93OwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPHZvaWQ+IHVuUmVnaXN0ZXJUb2tlbihTdHJpbmcgZGV2aWNlSWQpIGFzeW5jIHsKICAgIHRyeSB7CiAgICAgIF9sb2dnZXIuaSgnJF90YWc6IFJlbW92aW5nIEZDTSB0b2tlbiBmcm9tIGJhY2tlbmQnKTsKCiAgICAgIGF3YWl0IF9uZXR3b3JrQ2xpZW50LmRlbGV0ZTxNYXA8U3RyaW5nLCBkeW5hbWljPj4oCiAgICAgICAgJy9kZXZpY2UtdG9rZW5zL21lLyRkZXZpY2VJZCcsCiAgICAgICAgZnJvbUpzb25UOiAoanNvbikgPT4ganNvbiBhcyBNYXA8U3RyaW5nLCBkeW5hbWljPiwKICAgICAgKTsKICAgICAgX2xvZ2dlci5pKCckX3RhZzogRkNNIHRva2VuIHJlbW92ZWQgc3VjY2Vzc2Z1bGx5Jyk7CiAgICB9IGNhdGNoIChlLCBzKSB7CiAgICAgIF9sb2dnZXIuZSgnJF90YWc6IEVycm9yIHJlbW92aW5nIEZDTSB0b2tlbicsIGUsIHMpOwogICAgICByZXRocm93OwogICAgfQogIH0KCiAgQG92ZXJyaWRlCiAgRnV0dXJlPHZvaWQ+IGhhbmRsZVRva2VuUmVmcmVzaChTdHJpbmcgbmV3VG9rZW4pIGFzeW5jIHsKICAgIF9sb2dnZXIuaSgnJF90YWc6IEZDTSB0b2tlbiByZWZyZXNoZWQnKTsKICAgIGF3YWl0IHJlZ2lzdGVyVG9rZW4obmV3VG9rZW4pOwogIH0KfQo=", + "aW1wb3J0ICdwYWNrYWdlOmZsdXR0ZXIvZm91bmRhdGlvbi5kYXJ0JzsKCmltcG9ydCAncGFja2FnZTpjb3JlL2xvZ2dlci9sb2dnZXIuZGFydCc7CmltcG9ydCAncGFja2FnZTpkaS9kaS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZpcmViYXNlX21lc3NhZ2luZy9maXJlYmFzZV9tZXNzYWdpbmcuZGFydCc7CmltcG9ydCAncGFja2FnZTpuZXR3b3JrL25ldHdvcmsuZGFydCc7CmltcG9ydCAncGFja2FnZTpub3RpZmljYXRpb25zL25vdGlmaWNhdGlvbnMuZGFydCc7CgphYnN0cmFjdCBjbGFzcyBOb3RpZmljYXRpb25Ub2tlbk1hbmFnZXIgewogIEZ1dHVyZTxTdHJpbmc/PiBnZXRGQ01Ub2tlbigpOwoKICBGdXR1cmU8U3RyaW5nPiByZWdpc3RlclRva2VuKFN0cmluZyBmY21Ub2tlbik7CgogIEZ1dHVyZTx2b2lkPiB1blJlZ2lzdGVyVG9rZW4oU3RyaW5nIGRldmljZUlkKTsKCiAgRnV0dXJlPHZvaWQ+IGhhbmRsZVRva2VuUmVmcmVzaChTdHJpbmcgbmV3VG9rZW4pOwp9CgpjbGFzcyBGaXJlYmFzZVRva2VuTWFuYWdlciBpbXBsZW1lbnRzIE5vdGlmaWNhdGlvblRva2VuTWFuYWdlciB7CiAgc3RhdGljIGNvbnN0IFN0cmluZyBfdGFnID0gJ0ZpcmViYXNlVG9rZW5NYW5hZ2VyJzsKCiAgZmluYWwgTG9nZ2VyIF9sb2dnZXI7CiAgZmluYWwgTmV0d29ya0NsaWVudCBfbmV0d29ya0NsaWVudDsKICBmaW5hbCBEZXZpY2VJbmZvIF9kZXZpY2VJbmZvOwogIGZpbmFsIEZpcmViYXNlTWVzc2FnaW5nIF9maXJlYmFzZU1lc3NhZ2luZzsKCiAgRmlyZWJhc2VUb2tlbk1hbmFnZXIoewogICAgTG9nZ2VyPyBsb2dnZXIsCiAgICBOZXR3b3JrQ2xpZW50PyBuZXR3b3JrQ2xpZW50LAogICAgRGV2aWNlSW5mbz8gZGV2aWNlSW5mbywKICAgIEZpcmViYXNlTWVzc2FnaW5nPyBmaXJlYmFzZU1lc3NhZ2luZywKICB9KSA6IF9sb2dnZXIgPSBsb2dnZXIgPz8gZGkuZ2V0PExvZ2dlcj4oKSwKICAgICAgIF9uZXR3b3JrQ2xpZW50ID0gbmV0d29ya0NsaWVudCA/PyBkaS5nZXQ8TmV0d29ya0NsaWVudD4oKSwKICAgICAgIF9kZXZpY2VJbmZvID0gZGV2aWNlSW5mbyA/PyBkaS5nZXQ8RGV2aWNlSW5mbz4oKSwKICAgICAgIF9maXJlYmFzZU1lc3NhZ2luZyA9IGZpcmViYXNlTWVzc2FnaW5nID8/IEZpcmViYXNlTWVzc2FnaW5nLmluc3RhbmNlOwoKICBAb3ZlcnJpZGUKICBGdXR1cmU8U3RyaW5nPz4gZ2V0RkNNVG9rZW4oKSBhc3luYyB7CiAgICB0cnkgewogICAgICBmaW5hbCB0b2tlbiA9IGF3YWl0IF9maXJlYmFzZU1lc3NhZ2luZy5nZXRUb2tlbigpOwogICAgICBpZiAodG9rZW4gIT0gbnVsbCkgewogICAgICAgIF9sb2dnZXIuaSgnJF90YWc6IEZDTSBUb2tlbiBvYnRhaW5lZCBzdWNjZXNzZnVsbHknKTsKICAgICAgfSBlbHNlIHsKICAgICAgICBfbG9nZ2VyLncoJyRfdGFnOiBGYWlsZWQgdG8gb2J0YWluIEZDTSB0b2tlbicpOwogICAgICB9CiAgICAgIHJldHVybiB0b2tlbjsKICAgIH0gY2F0Y2ggKGUsIHMpIHsKICAgICAgX2xvZ2dlci5lKCckX3RhZzogRXJyb3IgZ2V0dGluZyBGQ00gdG9rZW4nLCBlLCBzKTsKICAgICAgcmV0aHJvdzsKICAgIH0KICB9CgogIEBvdmVycmlkZQogIEZ1dHVyZTxTdHJpbmc+IHJlZ2lzdGVyVG9rZW4oU3RyaW5nIGZjbVRva2VuKSBhc3luYyB7CiAgICB0cnkgewogICAgICBfbG9nZ2VyLmkoJyRfdGFnOiBSZWdpc3RlcmluZyBGQ00gdG9rZW4gd2l0aCBiYWNrZW5kJyk7CgogICAgICBmaW5hbCBkZXZpY2VJZCA9IGF3YWl0IF9kZXZpY2VJbmZvLmdlbmVyYXRlRGV2aWNlSWQoKTsKICAgICAgZmluYWwgZGV2aWNlTmFtZSA9IGF3YWl0IF9kZXZpY2VJbmZvLmdldERldmljZU5hbWUoKTsKICAgICAgZmluYWwgZGV2aWNlVHlwZSA9IGtJc1dlYiA/ICd3ZWInIDogZGVmYXVsdFRhcmdldFBsYXRmb3JtLm5hbWU7CgogICAgICBmaW5hbCByZXF1ZXN0ID0gRGV2aWNlVG9rZW5SZXF1ZXN0KAogICAgICAgIGZjbVRva2VuOiBmY21Ub2tlbiwKICAgICAgICBkZXZpY2VJZDogZGV2aWNlSWQsCiAgICAgICAgZGV2aWNlTmFtZTogZGV2aWNlTmFtZSwKICAgICAgICBkZXZpY2VUeXBlOiBkZXZpY2VUeXBlLAogICAgICApOwoKICAgICAgZmluYWwgcmVzcG9uc2UgPSBhd2FpdCBfbmV0d29ya0NsaWVudC5wb3N0PE1hcDxTdHJpbmcsIGR5bmFtaWM+PigKICAgICAgICAnL2RldmljZS10b2tlbnMvbWUnLAogICAgICAgIGRhdGE6IHJlcXVlc3QudG9Kc29uKCksCiAgICAgICAgZnJvbUpzb25UOiAoanNvbikgPT4ganNvbiBhcyBNYXA8U3RyaW5nLCBkeW5hbWljPiwKICAgICAgKTsKICAgICAgX25ldHdvcmtDbGllbnQuaGFuZGxlU3VjY2Vzc1Jlc3BvbnNlKHJlc3BvbnNlKTsKICAgICAgX2xvZ2dlci5pKCckX3RhZzogRkNNIHRva2VuIHJlZ2lzdGVyZWQgc3VjY2Vzc2Z1bGx5Jyk7CiAgICAgIHJldHVybiBkZXZpY2VJZDsKICAgIH0gY2F0Y2ggKGUsIHMpIHsKICAgICAgX2xvZ2dlci5lKCckX3RhZzogRXJyb3IgcmVnaXN0ZXJpbmcgRkNNIHRva2VuJywgZSwgcyk7CiAgICAgIHJldGhyb3c7CiAgICB9CiAgfQoKICBAb3ZlcnJpZGUKICBGdXR1cmU8dm9pZD4gdW5SZWdpc3RlclRva2VuKFN0cmluZyBkZXZpY2VJZCkgYXN5bmMgewogICAgdHJ5IHsKICAgICAgX2xvZ2dlci5pKCckX3RhZzogUmVtb3ZpbmcgRkNNIHRva2VuIGZyb20gYmFja2VuZCcpOwoKICAgICAgZmluYWwgcmVzcG9uc2UgPSBhd2FpdCBfbmV0d29ya0NsaWVudC5kZWxldGU8TWFwPFN0cmluZywgZHluYW1pYz4+KAogICAgICAgICcvZGV2aWNlLXRva2Vucy9tZS8kZGV2aWNlSWQnLAogICAgICAgIGZyb21Kc29uVDogKGpzb24pID0+IGpzb24gYXMgTWFwPFN0cmluZywgZHluYW1pYz4sCiAgICAgICk7CiAgICAgIF9uZXR3b3JrQ2xpZW50LmhhbmRsZVN1Y2Nlc3NSZXNwb25zZShyZXNwb25zZSk7CiAgICAgIF9sb2dnZXIuaSgnJF90YWc6IEZDTSB0b2tlbiByZW1vdmVkIHN1Y2Nlc3NmdWxseScpOwogICAgfSBjYXRjaCAoZSwgcykgewogICAgICBfbG9nZ2VyLmUoJyRfdGFnOiBFcnJvciByZW1vdmluZyBGQ00gdG9rZW4nLCBlLCBzKTsKICAgICAgcmV0aHJvdzsKICAgIH0KICB9CgogIEBvdmVycmlkZQogIEZ1dHVyZTx2b2lkPiBoYW5kbGVUb2tlblJlZnJlc2goU3RyaW5nIG5ld1Rva2VuKSBhc3luYyB7CiAgICBfbG9nZ2VyLmkoJyRfdGFnOiBGQ00gdG9rZW4gcmVmcmVzaGVkJyk7CiAgICBhd2FpdCByZWdpc3RlclRva2VuKG5ld1Rva2VuKTsKICB9Cn0K", "type": "text" }, { "path": "{{ name.snakeCase() }}/packages/{{notifications_dir}}/pubspec.yaml", "data": - "bmFtZTogbm90aWZpY2F0aW9ucwpkZXNjcmlwdGlvbjogIkZpcmViYXNlIENsb3VkIE1lc3NhZ2luZywgcGVybWlzc2lvbnMgYW5kIGRldmljZS10b2tlbiBtYW5hZ2VtZW50IGZvciB7e25hbWUudGl0bGVDYXNlKCl9fS4iCnZlcnNpb246IDAuMS4wCnB1Ymxpc2hfdG86ICdub25lJwoKZW52aXJvbm1lbnQ6CiAgc2RrOiBeMy44LjAKICBmbHV0dGVyOiAiPj0zLjI5LjAiCgpkZXBlbmRlbmNpZXM6CiAgZmx1dHRlcjoKICAgIHNkazogZmx1dHRlcgogIGFwcF9iYWRnZV9wbHVzOiBeMS4xLjIKICBjcnlwdG86IF4zLjAuNgogIGRldmljZV9pbmZvX3BsdXM6IF4xMS4xLjEKICBmaXJlYmFzZV9jb3JlOiBeMy4xNC4wCiAgZmlyZWJhc2VfbWVzc2FnaW5nOiBeMTUuMS42CiAgZ29fcm91dGVyOiBeMTUuMS4zCiAganNvbl9hbm5vdGF0aW9uOiBeNC45LjAKICBwZXJtaXNzaW9uX2hhbmRsZXI6IF4xMS4xLjAKICB0aW1lem9uZTogXjAuOS40CiAgY29yZToKICAgIHBhdGg6IC4uL2NvcmUKICBkZXNpZ25fc3lzdGVtOgogICAgcGF0aDogLi4vZGVzaWduX3N5c3RlbQogIGRpOgogICAgcGF0aDogLi4vZGkKe3sjbmV0d29ya319ICBuZXR3b3JrOgogICAgcGF0aDogLi4vbmV0d29yawp7ey9uZXR3b3JrfX17eyNhbmFseXRpY3N9fSAgYW5hbHl0aWNzOgogICAgcGF0aDogLi4vYW5hbHl0aWNzCnt7L2FuYWx5dGljc319CmRldl9kZXBlbmRlbmNpZXM6CiAgZmx1dHRlcl90ZXN0OgogICAgc2RrOiBmbHV0dGVyCiAgZmx1dHRlcl9saW50czogXjUuMC4wCiAgYnVpbGRfcnVubmVyOiBeMi40LjE1CiAganNvbl9zZXJpYWxpemFibGU6IF42LjkuNQoKZmx1dHRlcjoKICB1c2VzLW1hdGVyaWFsLWRlc2lnbjogdHJ1ZQo=", + "bmFtZTogbm90aWZpY2F0aW9ucwpkZXNjcmlwdGlvbjogIkZpcmViYXNlIENsb3VkIE1lc3NhZ2luZywgcGVybWlzc2lvbnMgYW5kIGRldmljZS10b2tlbiBtYW5hZ2VtZW50IGZvciB7e25hbWUudGl0bGVDYXNlKCl9fS4iCnZlcnNpb246IDAuMS4wCnB1Ymxpc2hfdG86ICdub25lJwoKZW52aXJvbm1lbnQ6CiAgc2RrOiBeMy44LjAKICBmbHV0dGVyOiAiPj0zLjI5LjAiCgpkZXBlbmRlbmNpZXM6CiAgc2hhcmVkX3ByZWZlcmVuY2VzOiBeMi41LjMKICBmbHV0dGVyOgogICAgc2RrOiBmbHV0dGVyCiAgYXBwX2JhZGdlX3BsdXM6IF4xLjEuMgogIGRldmljZV9pbmZvX3BsdXM6IF4xMS4xLjEKICBmaXJlYmFzZV9jb3JlOiBeMy4xNC4wCiAgZmlyZWJhc2VfbWVzc2FnaW5nOiBeMTUuMS42CiAganNvbl9hbm5vdGF0aW9uOiBeNC45LjAKICBjb3JlOgogICAgcGF0aDogLi4vY29yZQogIGRpOgogICAgcGF0aDogLi4vZGkKe3sjbmV0d29ya319ICBuZXR3b3JrOgogICAgcGF0aDogLi4vbmV0d29yawp7ey9uZXR3b3JrfX0KZGV2X2RlcGVuZGVuY2llczoKICBtb2NrdGFpbDogXjEuMC40CiAgZmx1dHRlcl90ZXN0OgogICAgc2RrOiBmbHV0dGVyCiAgZmx1dHRlcl9saW50czogXjUuMC4wCiAgYnVpbGRfcnVubmVyOiBeMi40LjE1CiAganNvbl9zZXJpYWxpemFibGU6IF42LjkuNQoKZmx1dHRlcjoKICB1c2VzLW1hdGVyaWFsLWRlc2lnbjogdHJ1ZQo=", + "type": "text" + }, + { + "path": + "{{ name.snakeCase() }}/packages/{{notifications_dir}}/test/client_test.dart", + "data": + "aW1wb3J0ICdkYXJ0OmFzeW5jJzsKCmltcG9ydCAncGFja2FnZTpjb3JlL2NvcmUuZGFydCc7CmltcG9ydCAncGFja2FnZTpmaXJlYmFzZV9tZXNzYWdpbmcvZmlyZWJhc2VfbWVzc2FnaW5nLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlcl90ZXN0L2ZsdXR0ZXJfdGVzdC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOm1vY2t0YWlsL21vY2t0YWlsLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6bm90aWZpY2F0aW9ucy9ub3RpZmljYXRpb25zLmRhcnQnOwoKY2xhc3MgX0xvZ2dlciBleHRlbmRzIE1vY2sgaW1wbGVtZW50cyBMb2dnZXIge30KCmNsYXNzIF9NZXNzYWdpbmcgZXh0ZW5kcyBNb2NrIGltcGxlbWVudHMgRmlyZWJhc2VNZXNzYWdpbmcge30KCmNsYXNzIF9Ub2tlbnMgZXh0ZW5kcyBNb2NrIGltcGxlbWVudHMgTm90aWZpY2F0aW9uVG9rZW5NYW5hZ2VyIHt9CgpjbGFzcyBfUGVybWlzc2lvbiBleHRlbmRzIE1vY2sgaW1wbGVtZW50cyBOb3RpZmljYXRpb25QZXJtaXNzaW9uTWFuYWdlciB7fQoKdm9pZCBtYWluKCkgewogIGxhdGUgX0xvZ2dlciBsb2dnZXI7CiAgbGF0ZSBfTWVzc2FnaW5nIG1lc3NhZ2luZzsKICBsYXRlIF9Ub2tlbnMgdG9rZW5zOwogIGxhdGUgX1Blcm1pc3Npb24gcGVybWlzc2lvbjsKICBsYXRlIFN0cmVhbUNvbnRyb2xsZXI8UmVtb3RlTWVzc2FnZT4gZm9yZWdyb3VuZDsKICBsYXRlIFN0cmVhbUNvbnRyb2xsZXI8UmVtb3RlTWVzc2FnZT4gb3BlbmVkOwogIGxhdGUgU3RyZWFtQ29udHJvbGxlcjxTdHJpbmc+IHJlZnJlc2hlZDsKICBsYXRlIEZpcmViYXNlTm90aWZpY2F0aW9uQ2xpZW50IGNsaWVudDsKICBsYXRlIExpc3Q8U3RyaW5nPiByb3V0ZXM7CiAgbGF0ZSBMaXN0PFN0cmluZz4gbm90aWZpY2F0aW9uczsKICBsYXRlIExpc3Q8aW50PiBiYWRnZXM7CiAgbGF0ZSBib29sIHN1cHBvcnRlZDsKICBsYXRlIGJvb2wgY2FsbGJhY2tFcnJvcjsKICBsYXRlIEZ1dHVyZTx2b2lkPiBGdW5jdGlvbihSZW1vdGVNZXNzYWdlKSBiYWNrZ3JvdW5kOwoKICBzZXRVcCgoKSB7CiAgICBsb2dnZXIgPSBfTG9nZ2VyKCk7CiAgICBtZXNzYWdpbmcgPSBfTWVzc2FnaW5nKCk7CiAgICB0b2tlbnMgPSBfVG9rZW5zKCk7CiAgICBwZXJtaXNzaW9uID0gX1Blcm1pc3Npb24oKTsKICAgIGZvcmVncm91bmQgPSBTdHJlYW1Db250cm9sbGVyLmJyb2FkY2FzdCgpOwogICAgb3BlbmVkID0gU3RyZWFtQ29udHJvbGxlci5icm9hZGNhc3QoKTsKICAgIHJlZnJlc2hlZCA9IFN0cmVhbUNvbnRyb2xsZXIuYnJvYWRjYXN0KCk7CiAgICByb3V0ZXMgPSBbXTsKICAgIG5vdGlmaWNhdGlvbnMgPSBbXTsKICAgIGJhZGdlcyA9IFtdOwogICAgc3VwcG9ydGVkID0gdHJ1ZTsKICAgIGNhbGxiYWNrRXJyb3IgPSBmYWxzZTsKICAgIHdoZW4oCiAgICAgICgpID0+CiAgICAgICAgICBwZXJtaXNzaW9uLnJlcXVlc3RQZXJtaXNzaW9ucyhwcm92aXNpb25hbDogYW55KG5hbWVkOiAncHJvdmlzaW9uYWwnKSksCiAgICApLnRoZW5BbnN3ZXIoKF8pIGFzeW5jID0+IHRydWUpOwogICAgd2hlbigoKSA9PiBtZXNzYWdpbmcub25Ub2tlblJlZnJlc2gpLnRoZW5BbnN3ZXIoKF8pID0+IHJlZnJlc2hlZC5zdHJlYW0pOwogICAgd2hlbihtZXNzYWdpbmcuZ2V0SW5pdGlhbE1lc3NhZ2UpLnRoZW5BbnN3ZXIoKF8pIGFzeW5jID0+IG51bGwpOwogICAgd2hlbih0b2tlbnMuZ2V0RkNNVG9rZW4pLnRoZW5BbnN3ZXIoKF8pIGFzeW5jID0+ICd0b2tlbicpOwogICAgd2hlbigoKSA9PiB0b2tlbnMucmVnaXN0ZXJUb2tlbihhbnkoKSkpLnRoZW5BbnN3ZXIoKF8pIGFzeW5jID0+ICdkZXZpY2UnKTsKICAgIHdoZW4oKCkgPT4gdG9rZW5zLmhhbmRsZVRva2VuUmVmcmVzaChhbnkoKSkpLnRoZW5BbnN3ZXIoKF8pIGFzeW5jIHt9KTsKICAgIGNsaWVudCA9IEZpcmViYXNlTm90aWZpY2F0aW9uQ2xpZW50KAogICAgICBjb25maWc6IE5vdGlmaWNhdGlvbkNvbmZpZygKICAgICAgICBvbkZvcmVncm91bmQ6ICh0aXRsZSwgYm9keSkgewogICAgICAgICAgaWYgKGNhbGxiYWNrRXJyb3IpIHRocm93IFN0YXRlRXJyb3IoJ3ByZXNlbnRhdGlvbicpOwogICAgICAgICAgbm90aWZpY2F0aW9ucy5hZGQoJyR0aXRsZTogJGJvZHknKTsKICAgICAgICB9LAogICAgICAgIG9uT3BlblJvdXRlOiAocm91dGUpIHsKICAgICAgICAgIGlmIChjYWxsYmFja0Vycm9yKSB0aHJvdyBTdGF0ZUVycm9yKCduYXZpZ2F0aW9uJyk7CiAgICAgICAgICByb3V0ZXMuYWRkKHJvdXRlKTsKICAgICAgICB9LAogICAgICApLAogICAgICBsb2dnZXI6IGxvZ2dlciwKICAgICAgdG9rZW5NYW5hZ2VyOiB0b2tlbnMsCiAgICAgIHBlcm1pc3Npb25NYW5hZ2VyOiBwZXJtaXNzaW9uLAogICAgICBtZXNzYWdpbmc6IG1lc3NhZ2luZywKICAgICAgZm9yZWdyb3VuZE1lc3NhZ2VzOiBmb3JlZ3JvdW5kLnN0cmVhbSwKICAgICAgb3BlbmVkTWVzc2FnZXM6IG9wZW5lZC5zdHJlYW0sCiAgICAgIHN1cHBvcnRzQmFkZ2U6ICgpIGFzeW5jID0+IHN1cHBvcnRlZCwKICAgICAgdXBkYXRlQmFkZ2U6ICh2YWx1ZSkgYXN5bmMgewogICAgICAgIGlmIChjYWxsYmFja0Vycm9yKSB0aHJvdyBTdGF0ZUVycm9yKCdiYWRnZScpOwogICAgICAgIGJhZGdlcy5hZGQodmFsdWUpOwogICAgICB9LAogICAgICByZWdpc3RlckJhY2tncm91bmQ6IChoYW5kbGVyKSB7CiAgICAgICAgYmFja2dyb3VuZCA9IGhhbmRsZXI7CiAgICAgIH0sCiAgICApOwogIH0pOwogIHRlYXJEb3duKCgpIGFzeW5jIHsKICAgIGF3YWl0IGNsaWVudC5kaXNwb3NlKCk7CiAgICBhd2FpdCBmb3JlZ3JvdW5kLmNsb3NlKCk7CiAgICBhd2FpdCBvcGVuZWQuY2xvc2UoKTsKICAgIGF3YWl0IHJlZnJlc2hlZC5jbG9zZSgpOwogIH0pOwoKICB0ZXN0KAogICAgJ2NvbmN1cnJlbnQgaW5pdGlhbGl6YXRpb24gY3JlYXRlcyBvbmUgc3Vic2NyaXB0aW9uIGFuZCByZWdpc3RlcnMgYSB0b2tlbicsCiAgICAoKSBhc3luYyB7CiAgICAgIGF3YWl0IEZ1dHVyZS53YWl0KFtjbGllbnQuaW5pdCgpLCBjbGllbnQuaW5pdCgpXSk7CiAgICAgIGF3YWl0IGNsaWVudC5pbml0KCk7CiAgICAgIHZlcmlmeSgoKSA9PiBwZXJtaXNzaW9uLnJlcXVlc3RQZXJtaXNzaW9ucyhwcm92aXNpb25hbDogZmFsc2UpKS5jYWxsZWQoMSk7CiAgICAgIGV4cGVjdChjbGllbnQuZmNtVG9rZW4sICd0b2tlbicpOwogICAgICBleHBlY3QoY2xpZW50LmRldmljZUlkLCAnZGV2aWNlJyk7CiAgICAgIGV4cGVjdChiYWRnZXMsIFswXSk7CiAgICAgIGF3YWl0IGJhY2tncm91bmQoY29uc3QgUmVtb3RlTWVzc2FnZShtZXNzYWdlSWQ6ICdiYWNrZ3JvdW5kJykpOwogICAgICBhd2FpdCBjbGllbnQucmVxdWVzdFBlcm1pc3Npb25zKHByb3Zpc2lvbmFsOiB0cnVlKTsKICAgICAgdmVyaWZ5KCgpID0+IHBlcm1pc3Npb24ucmVxdWVzdFBlcm1pc3Npb25zKHByb3Zpc2lvbmFsOiB0cnVlKSkuY2FsbGVkKDEpOwogICAgfSwKICApOwoKICB0ZXN0KAogICAgJ3Blcm1pc3Npb24gZGVuaWFsIGNhbiBiZSByZXRyaWVkIGFuZCB1bnN1cHBvcnRlZCBiYWRnZXMgYXJlIHNraXBwZWQnLAogICAgKCkgYXN5bmMgewogICAgICB3aGVuKAogICAgICAgICgpID0+IHBlcm1pc3Npb24ucmVxdWVzdFBlcm1pc3Npb25zKHByb3Zpc2lvbmFsOiBmYWxzZSksCiAgICAgICkudGhlbkFuc3dlcigoXykgYXN5bmMgPT4gZmFsc2UpOwogICAgICBhd2FpdCBjbGllbnQuaW5pdCgpOwogICAgICBhd2FpdCBjbGllbnQuY2xlYXJCYWRnZSgpOwogICAgICBleHBlY3QoZm9yZWdyb3VuZC5oYXNMaXN0ZW5lciwgaXNGYWxzZSk7CiAgICAgIGV4cGVjdChiYWRnZXMsIGlzRW1wdHkpOwogICAgICB3aGVuKAogICAgICAgICgpID0+IHBlcm1pc3Npb24ucmVxdWVzdFBlcm1pc3Npb25zKHByb3Zpc2lvbmFsOiBmYWxzZSksCiAgICAgICkudGhlbkFuc3dlcigoXykgYXN5bmMgPT4gdHJ1ZSk7CiAgICAgIHN1cHBvcnRlZCA9IGZhbHNlOwogICAgICBhd2FpdCBjbGllbnQuaW5pdCgpOwogICAgICBleHBlY3QoZm9yZWdyb3VuZC5oYXNMaXN0ZW5lciwgaXNUcnVlKTsKICAgICAgZXhwZWN0KGJhZGdlcywgaXNFbXB0eSk7CiAgICB9LAogICk7CgogIHRlc3QoCiAgICAnZm9yZWdyb3VuZCwgb3BlbmVkLCBpbml0aWFsIGFuZCB0b2tlbi1yZWZyZXNoIGV2ZW50cyByZWFjaCB0aGVpciBvd25lcnMnLAogICAgKCkgYXN5bmMgewogICAgICB3aGVuKG1lc3NhZ2luZy5nZXRJbml0aWFsTWVzc2FnZSkudGhlbkFuc3dlcigKICAgICAgICAoXykgYXN5bmMgPT4gY29uc3QgUmVtb3RlTWVzc2FnZShkYXRhOiB7J3JvdXRlJzogJy9pbml0aWFsJ30pLAogICAgICApOwogICAgICBhd2FpdCBjbGllbnQuaW5pdCgpOwogICAgICBmb3JlZ3JvdW5kLmFkZCgKICAgICAgICBjb25zdCBSZW1vdGVNZXNzYWdlKAogICAgICAgICAgbm90aWZpY2F0aW9uOiBSZW1vdGVOb3RpZmljYXRpb24odGl0bGU6ICdUaXRsZScsIGJvZHk6ICdCb2R5JyksCiAgICAgICAgKSwKICAgICAgKTsKICAgICAgb3BlbmVkLmFkZChjb25zdCBSZW1vdGVNZXNzYWdlKGRhdGE6IHsncm91dGUnOiAnL29wZW5lZCd9KSk7CiAgICAgIHJlZnJlc2hlZC5hZGQoJ25ldy10b2tlbicpOwogICAgICBhd2FpdCBwdW1wRXZlbnRRdWV1ZSgpOwogICAgICBleHBlY3Qocm91dGVzLCBbJy9pbml0aWFsJywgJy9vcGVuZWQnXSk7CiAgICAgIGV4cGVjdChub3RpZmljYXRpb25zLCBbJ1RpdGxlOiBCb2R5J10pOwogICAgICBleHBlY3QoY2xpZW50LmZjbVRva2VuLCAnbmV3LXRva2VuJyk7CiAgICAgIHZlcmlmeSgoKSA9PiB0b2tlbnMuaGFuZGxlVG9rZW5SZWZyZXNoKCduZXctdG9rZW4nKSkuY2FsbGVkKDEpOwogICAgICBmb3IgKGZpbmFsIGRhdGEgaW4gWwogICAgICAgIDxTdHJpbmcsIGR5bmFtaWM+e30sCiAgICAgICAgeydyb3V0ZSc6ICcnfSwKICAgICAgICB7J3JvdXRlJzogMX0sCiAgICAgICAgeydyb3V0ZSc6ICdodHRwczovL291dHNpZGUudGVzdCd9LAogICAgICAgIHsncm91dGUnOiAnLy9vdXRzaWRlLnRlc3QnfSwKICAgICAgXSkgewogICAgICAgIGF3YWl0IGNsaWVudC5oYW5kbGVOb3RpZmljYXRpb25PcGVuZWQoUmVtb3RlTWVzc2FnZShkYXRhOiBkYXRhKSk7CiAgICAgIH0KICAgICAgYXdhaXQgY2xpZW50LmhhbmRsZUZvcmVncm91bmROb3RpZmljYXRpb24oY29uc3QgUmVtb3RlTWVzc2FnZSgpKTsKICAgICAgZXhwZWN0KHJvdXRlcywgaGFzTGVuZ3RoKDIpKTsKICAgICAgZXhwZWN0KG5vdGlmaWNhdGlvbnMsIGhhc0xlbmd0aCgxKSk7CiAgICB9LAogICk7CgogIHRlc3QoCiAgICAnc3RyZWFtLCBwcmVzZW50YXRpb24sIG5hdmlnYXRpb24gYW5kIGJhZGdlIGZhaWx1cmVzIGFyZSBjb250YWluZWQnLAogICAgKCkgYXN5bmMgewogICAgICBhd2FpdCBjbGllbnQuaW5pdCgpOwogICAgICBjYWxsYmFja0Vycm9yID0gdHJ1ZTsKICAgICAgd2hlbigKICAgICAgICAoKSA9PiB0b2tlbnMuaGFuZGxlVG9rZW5SZWZyZXNoKGFueSgpKSwKICAgICAgKS50aGVuVGhyb3coU3RhdGVFcnJvcigncmVmcmVzaCcpKTsKICAgICAgZm9yZWdyb3VuZC5hZGRFcnJvcihTdGF0ZUVycm9yKCdmb3JlZ3JvdW5kJykpOwogICAgICBvcGVuZWQuYWRkRXJyb3IoU3RhdGVFcnJvcignb3BlbmVkJykpOwogICAgICByZWZyZXNoZWQuYWRkRXJyb3IoU3RhdGVFcnJvcigndG9rZW5zJykpOwogICAgICByZWZyZXNoZWQuYWRkKCduZXctdG9rZW4nKTsKICAgICAgYXdhaXQgY2xpZW50LmhhbmRsZUZvcmVncm91bmROb3RpZmljYXRpb24oCiAgICAgICAgY29uc3QgUmVtb3RlTWVzc2FnZSgKICAgICAgICAgIG5vdGlmaWNhdGlvbjogUmVtb3RlTm90aWZpY2F0aW9uKHRpdGxlOiAnVCcsIGJvZHk6ICdCJyksCiAgICAgICAgKSwKICAgICAgKTsKICAgICAgYXdhaXQgY2xpZW50LmhhbmRsZU5vdGlmaWNhdGlvbk9wZW5lZCgKICAgICAgICBjb25zdCBSZW1vdGVNZXNzYWdlKGRhdGE6IHsncm91dGUnOiAnL2hvbWUnfSksCiAgICAgICk7CiAgICAgIGF3YWl0IGNsaWVudC5jbGVhckJhZGdlKCk7CiAgICAgIGF3YWl0IHB1bXBFdmVudFF1ZXVlKCk7CiAgICAgIGV4cGVjdChjbGllbnQuZmNtVG9rZW4sICd0b2tlbicpOwogICAgICBleHBlY3Qocm91dGVzLCBpc0VtcHR5KTsKICAgICAgZXhwZWN0KG5vdGlmaWNhdGlvbnMsIGlzRW1wdHkpOwogICAgfSwKICApOwoKICB0ZXN0KAogICAgJ3JlZ2lzdHJhdGlvbiBmYWlsdXJlcyBjbGVhciBjYWNoZWQgc3RhdGUgYW5kIGEgbnVsbCB0b2tlbiBkb2VzIG5vdCByZWdpc3RlcicsCiAgICAoKSBhc3luYyB7CiAgICAgIHdoZW4odG9rZW5zLmdldEZDTVRva2VuKS50aGVuQW5zd2VyKChfKSBhc3luYyA9PiBudWxsKTsKICAgICAgZXhwZWN0KGF3YWl0IGNsaWVudC5nZXRGQ01Ub2tlbigpLCBpc051bGwpOwogICAgICB2ZXJpZnlOZXZlcigoKSA9PiB0b2tlbnMucmVnaXN0ZXJUb2tlbihhbnkoKSkpOwogICAgICB3aGVuKHRva2Vucy5nZXRGQ01Ub2tlbikudGhlbkFuc3dlcigoXykgYXN5bmMgPT4gJ3Rva2VuJyk7CiAgICAgIHdoZW4oKCkgPT4gdG9rZW5zLnJlZ2lzdGVyVG9rZW4oYW55KCkpKS50aGVuVGhyb3coU3RhdGVFcnJvcignYmFja2VuZCcpKTsKICAgICAgZXhwZWN0KGF3YWl0IGNsaWVudC5nZXRGQ01Ub2tlbigpLCBpc051bGwpOwogICAgICBleHBlY3QoY2xpZW50LmZjbVRva2VuLCBpc051bGwpOwogICAgICBleHBlY3QoY2xpZW50LmRldmljZUlkLCBpc051bGwpOwogICAgfSwKICApOwoKICB0ZXN0KCdmYWlsZWQgc3RhcnR1cCBjYW5jZWxzIHN1YnNjcmlwdGlvbnMgYW5kIGNhbiBiZSByZXRyaWVkJywgKCkgYXN5bmMgewogICAgd2hlbihtZXNzYWdpbmcuZ2V0SW5pdGlhbE1lc3NhZ2UpLnRoZW5UaHJvdyhTdGF0ZUVycm9yKCdzdGFydHVwJykpOwogICAgYXdhaXQgZXhwZWN0TGF0ZXIoY2xpZW50LmluaXQoKSwgdGhyb3dzU3RhdGVFcnJvcik7CiAgICBleHBlY3QoZm9yZWdyb3VuZC5oYXNMaXN0ZW5lciwgaXNGYWxzZSk7CiAgICAvLyBSZXRyeSBiZWZvcmUgc3Vic2NyaWJpbmcgYWdhaW4gaXMgc3VwcG9ydGVkIGJ5IHJlYWwgYnJvYWRjYXN0IEZDTSBzdHJlYW1zOwogICAgLy8gYSBkZW5pZWQgcGVybWlzc2lvbiBhbHNvIGRlbW9uc3RyYXRlcyB0aGF0IHRoZSBmYWlsZWQgZnV0dXJlIHdhcyBjbGVhcmVkLgogICAgd2hlbigKICAgICAgKCkgPT4gcGVybWlzc2lvbi5yZXF1ZXN0UGVybWlzc2lvbnMocHJvdmlzaW9uYWw6IGZhbHNlKSwKICAgICkudGhlbkFuc3dlcigoXykgYXN5bmMgPT4gZmFsc2UpOwogICAgYXdhaXQgY2xpZW50LmluaXQoKTsKICB9KTsKCiAgdGVzdCgnZGlzcG9zZSBjbG9zZXMgbGlzdGVuZXJzIGFuZCBwcmV2ZW50cyBsYXRlIHN0YXJ0dXAgd29yaycsICgpIGFzeW5jIHsKICAgIGZpbmFsIGluaXRpYWwgPSBDb21wbGV0ZXI8UmVtb3RlTWVzc2FnZT8+KCk7CiAgICB3aGVuKG1lc3NhZ2luZy5nZXRJbml0aWFsTWVzc2FnZSkudGhlbkFuc3dlcigoXykgPT4gaW5pdGlhbC5mdXR1cmUpOwogICAgZmluYWwgc3RhcnR1cCA9IGNsaWVudC5pbml0KCk7CiAgICBhd2FpdCBwdW1wRXZlbnRRdWV1ZSgpOwogICAgYXdhaXQgY2xpZW50LmRpc3Bvc2UoKTsKICAgIGluaXRpYWwuY29tcGxldGUoY29uc3QgUmVtb3RlTWVzc2FnZShkYXRhOiB7J3JvdXRlJzogJy9sYXRlJ30pKTsKICAgIGF3YWl0IHN0YXJ0dXA7CiAgICBleHBlY3QoZm9yZWdyb3VuZC5oYXNMaXN0ZW5lciwgaXNGYWxzZSk7CiAgICBleHBlY3QoYXdhaXQgY2xpZW50LmdldEZDTVRva2VuKCksIGlzTnVsbCk7CiAgICBhd2FpdCBjbGllbnQuaGFuZGxlRm9yZWdyb3VuZE5vdGlmaWNhdGlvbihjb25zdCBSZW1vdGVNZXNzYWdlKCkpOwogICAgYXdhaXQgY2xpZW50LmhhbmRsZU5vdGlmaWNhdGlvbk9wZW5lZCgKICAgICAgY29uc3QgUmVtb3RlTWVzc2FnZShkYXRhOiB7J3JvdXRlJzogJy9sYXRlJ30pLAogICAgKTsKICAgIGF3YWl0IGNsaWVudC5jbGVhckJhZGdlKCk7CiAgICBleHBlY3Qocm91dGVzLCBpc0VtcHR5KTsKICAgIGF3YWl0IGV4cGVjdExhdGVyKGNsaWVudC5pbml0KCksIHRocm93c1N0YXRlRXJyb3IpOwogIH0pOwp9Cg==", + "type": "text" + }, + { + "path": + "{{ name.snakeCase() }}/packages/{{notifications_dir}}/test/device_info_test.dart", + "data": + "aW1wb3J0ICdwYWNrYWdlOmNvcmUvY29yZS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmRldmljZV9pbmZvX3BsdXMvZGV2aWNlX2luZm9fcGx1cy5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZsdXR0ZXJfdGVzdC9mbHV0dGVyX3Rlc3QuZGFydCc7CmltcG9ydCAncGFja2FnZTptb2NrdGFpbC9tb2NrdGFpbC5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOm5vdGlmaWNhdGlvbnMvbm90aWZpY2F0aW9ucy5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOnNoYXJlZF9wcmVmZXJlbmNlcy9zaGFyZWRfcHJlZmVyZW5jZXMuZGFydCc7CgpjbGFzcyBfTG9nZ2VyIGV4dGVuZHMgTW9jayBpbXBsZW1lbnRzIExvZ2dlciB7fQoKY2xhc3MgX1BsdWdpbiBleHRlbmRzIE1vY2sgaW1wbGVtZW50cyBEZXZpY2VJbmZvUGx1Z2luIHt9CgpjbGFzcyBfSW5mbyBleHRlbmRzIE1vY2sgaW1wbGVtZW50cyBCYXNlRGV2aWNlSW5mbyB7fQoKY2xhc3MgX1ByZWZlcmVuY2VzIGV4dGVuZHMgTW9jayBpbXBsZW1lbnRzIFNoYXJlZFByZWZlcmVuY2VzIHt9CgpjbGFzcyBfU3RvcmUgaW1wbGVtZW50cyBJbnN0YWxsYXRpb25JZFN0b3JlIHsKICBTdHJpbmc/IHZhbHVlOwogIGJvb2wgZmFpbCA9IGZhbHNlOwogIGludCB3cml0ZXMgPSAwOwogIEBvdmVycmlkZQogIEZ1dHVyZTxTdHJpbmc/PiByZWFkKCkgYXN5bmMgPT4gdmFsdWU7CiAgQG92ZXJyaWRlCiAgRnV0dXJlPHZvaWQ+IHdyaXRlKFN0cmluZyBpZCkgYXN5bmMgewogICAgaWYgKGZhaWwpIHRocm93IFN0YXRlRXJyb3IoJ2Rpc2sgdW5hdmFpbGFibGUnKTsKICAgIHdyaXRlcysrOwogICAgdmFsdWUgPSBpZDsKICB9Cn0KCnZvaWQgbWFpbigpIHsKICB0ZXN0KCdzdG9yYWdlIHJlamVjdHMgdW5zdWNjZXNzZnVsIHByZWZlcmVuY2Ugd3JpdGVzJywgKCkgYXN5bmMgewogICAgZmluYWwgcHJlZmVyZW5jZXMgPSBfUHJlZmVyZW5jZXMoKTsKICAgIHdoZW4oCiAgICAgICgpID0+IHByZWZlcmVuY2VzLnNldFN0cmluZyhhbnkoKSwgYW55KCkpLAogICAgKS50aGVuQW5zd2VyKChfKSBhc3luYyA9PiBmYWxzZSk7CiAgICBmaW5hbCBzdG9yZSA9IFNoYXJlZFByZWZlcmVuY2VzSW5zdGFsbGF0aW9uSWRTdG9yZSgKICAgICAgcHJlZmVyZW5jZXM6IHByZWZlcmVuY2VzLAogICAgKTsKICAgIGF3YWl0IGV4cGVjdExhdGVyKHN0b3JlLndyaXRlKCdpZCcpLCB0aHJvd3NTdGF0ZUVycm9yKTsKICB9KTsKICB0ZXN0KAogICAgJ2NvbmN1cnJlbnQgcmVxdWVzdHMgcGVyc2lzdCBvbmUgSUQgYW5kIG5ldyBpbnN0YW5jZXMgcmV1c2UgaXQnLAogICAgKCkgYXN5bmMgewogICAgICBmaW5hbCBzdG9yZSA9IF9TdG9yZSgpOwogICAgICB2YXIgZ2VuZXJhdGVkID0gMDsKICAgICAgZmluYWwgZGV2aWNlID0gRGV2aWNlSW5mb0ltcGwoCiAgICAgICAgbG9nZ2VyOiBfTG9nZ2VyKCksCiAgICAgICAgc3RvcmU6IHN0b3JlLAogICAgICAgIGNyZWF0ZUlkOiAoKSA9PiAnaWQtJHsrK2dlbmVyYXRlZH0nLAogICAgICApOwogICAgICBleHBlY3QoCiAgICAgICAgYXdhaXQgRnV0dXJlLndhaXQoWwogICAgICAgICAgZGV2aWNlLmdlbmVyYXRlRGV2aWNlSWQoKSwKICAgICAgICAgIGRldmljZS5nZW5lcmF0ZURldmljZUlkKCksCiAgICAgICAgXSksCiAgICAgICAgWydpZC0xJywgJ2lkLTEnXSwKICAgICAgKTsKICAgICAgZXhwZWN0KHN0b3JlLndyaXRlcywgMSk7CiAgICAgIGZpbmFsIHNlY29uZCA9IERldmljZUluZm9JbXBsKGxvZ2dlcjogX0xvZ2dlcigpLCBzdG9yZTogc3RvcmUpOwogICAgICBleHBlY3QoYXdhaXQgc2Vjb25kLmdlbmVyYXRlRGV2aWNlSWQoKSwgJ2lkLTEnKTsKICAgIH0sCiAgKTsKCiAgdGVzdCgnc3RvcmFnZSBmYWlsdXJlcyBwcm9wYWdhdGUgYW5kIGNhbiBiZSByZXRyaWVkJywgKCkgYXN5bmMgewogICAgZmluYWwgc3RvcmUgPSBfU3RvcmUoKS4uZmFpbCA9IHRydWU7CiAgICBmaW5hbCBkZXZpY2UgPSBEZXZpY2VJbmZvSW1wbCgKICAgICAgbG9nZ2VyOiBfTG9nZ2VyKCksCiAgICAgIHN0b3JlOiBzdG9yZSwKICAgICAgY3JlYXRlSWQ6ICgpID0+ICdpZCcsCiAgICApOwogICAgYXdhaXQgZXhwZWN0TGF0ZXIoZGV2aWNlLmdlbmVyYXRlRGV2aWNlSWQoKSwgdGhyb3dzU3RhdGVFcnJvcik7CiAgICBzdG9yZS5mYWlsID0gZmFsc2U7CiAgICBleHBlY3QoYXdhaXQgZGV2aWNlLmdlbmVyYXRlRGV2aWNlSWQoKSwgJ2lkJyk7CiAgfSk7CgogIHRlc3QoCiAgICAnZGVmYXVsdCBzdG9yYWdlIHBlcnNpc3RzIHJhbmRvbSBJRHMgd2l0aG91dCBoYXJkd2FyZSBmaW5nZXJwcmludGluZycsCiAgICAoKSBhc3luYyB7CiAgICAgIFNoYXJlZFByZWZlcmVuY2VzLnNldE1vY2tJbml0aWFsVmFsdWVzKHt9KTsKICAgICAgZmluYWwgZmlyc3QgPSBhd2FpdCBEZXZpY2VJbmZvSW1wbChsb2dnZXI6IF9Mb2dnZXIoKSkuZ2VuZXJhdGVEZXZpY2VJZCgpOwogICAgICBleHBlY3QoZmlyc3QsIG1hdGNoZXMoUmVnRXhwKHInXlswLTlhLWZdezMyfSQnKSkpOwogICAgICBleHBlY3QoYXdhaXQgRGV2aWNlSW5mb0ltcGwobG9nZ2VyOiBfTG9nZ2VyKCkpLmdlbmVyYXRlRGV2aWNlSWQoKSwgZmlyc3QpOwogICAgfSwKICApOwoKICB0ZXN0KAogICAgJ2RldmljZSBuYW1lcyB1c2UgcGx1Z2luIG1ldGFkYXRhIGFuZCBmYWxsIGJhY2sgd2hlbiB1bmF2YWlsYWJsZScsCiAgICAoKSBhc3luYyB7CiAgICAgIGZpbmFsIHBsdWdpbiA9IF9QbHVnaW4oKTsKICAgICAgZmluYWwgaW5mbyA9IF9JbmZvKCk7CiAgICAgIHdoZW4oKCkgPT4gcGx1Z2luLmRldmljZUluZm8pLnRoZW5BbnN3ZXIoKF8pIGFzeW5jID0+IGluZm8pOwogICAgICBmaW5hbCBkZXZpY2UgPSBEZXZpY2VJbmZvSW1wbCgKICAgICAgICBsb2dnZXI6IF9Mb2dnZXIoKSwKICAgICAgICBkZXZpY2VJbmZvUGx1Z2luOiBwbHVnaW4sCiAgICAgICk7CiAgICAgIHdoZW4oKCkgPT4gaW5mby5kYXRhKS50aGVuUmV0dXJuKHsnbW9kZWwnOiAnVGVzdCBwaG9uZSd9KTsKICAgICAgZXhwZWN0KGF3YWl0IGRldmljZS5nZXREZXZpY2VOYW1lKCksICdUZXN0IHBob25lJyk7CiAgICAgIHdoZW4oKCkgPT4gaW5mby5kYXRhKS50aGVuUmV0dXJuKHt9KTsKICAgICAgZXhwZWN0KGF3YWl0IGRldmljZS5nZXREZXZpY2VOYW1lKCksIGlzTm90RW1wdHkpOwogICAgICB3aGVuKCgpID0+IHBsdWdpbi5kZXZpY2VJbmZvKS50aGVuVGhyb3coU3RhdGVFcnJvcigndW5hdmFpbGFibGUnKSk7CiAgICAgIGV4cGVjdChhd2FpdCBkZXZpY2UuZ2V0RGV2aWNlTmFtZSgpLCBpc05vdEVtcHR5KTsKICAgIH0sCiAgKTsKfQo=", + "type": "text" + }, + { + "path": + "{{ name.snakeCase() }}/packages/{{notifications_dir}}/test/services_test.dart", + "data": + "aW1wb3J0ICdwYWNrYWdlOmNvcmUvY29yZS5kYXJ0JzsKaW1wb3J0ICdwYWNrYWdlOmZpcmViYXNlX21lc3NhZ2luZy9maXJlYmFzZV9tZXNzYWdpbmcuZGFydCc7CmltcG9ydCAncGFja2FnZTpmbHV0dGVyX3Rlc3QvZmx1dHRlcl90ZXN0LmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6bW9ja3RhaWwvbW9ja3RhaWwuZGFydCc7CmltcG9ydCAncGFja2FnZTpuZXR3b3JrL25ldHdvcmsuZGFydCc7CmltcG9ydCAncGFja2FnZTpub3RpZmljYXRpb25zL25vdGlmaWNhdGlvbnMuZGFydCc7CmltcG9ydCAncGFja2FnZTpub3RpZmljYXRpb25zL25vdGlmaWNhdGlvbnMuZGFydCcgYXMgbm90aWZpY2F0aW9uczsKaW1wb3J0ICdwYWNrYWdlOmRpL2RpLmRhcnQnOwoKY2xhc3MgX0xvZ2dlciBleHRlbmRzIE1vY2sgaW1wbGVtZW50cyBMb2dnZXIge30KCmNsYXNzIF9NZXNzYWdpbmcgZXh0ZW5kcyBNb2NrIGltcGxlbWVudHMgRmlyZWJhc2VNZXNzYWdpbmcge30KCmNsYXNzIF9TZXR0aW5ncyBleHRlbmRzIE1vY2sgaW1wbGVtZW50cyBOb3RpZmljYXRpb25TZXR0aW5ncyB7fQoKY2xhc3MgX05ldHdvcmsgZXh0ZW5kcyBNb2NrIGltcGxlbWVudHMgTmV0d29ya0NsaWVudCB7fQoKY2xhc3MgX0RldmljZSBleHRlbmRzIE1vY2sgaW1wbGVtZW50cyBEZXZpY2VJbmZvIHt9Cgp2b2lkIG1haW4oKSB7CiAgbGF0ZSBfTG9nZ2VyIGxvZ2dlcjsKICBsYXRlIF9NZXNzYWdpbmcgbWVzc2FnaW5nOwogIHNldFVwKCgpIHsKICAgIGxvZ2dlciA9IF9Mb2dnZXIoKTsKICAgIG1lc3NhZ2luZyA9IF9NZXNzYWdpbmcoKTsKICB9KTsKICB0ZWFyRG93bihkaS5yZXNldCk7CgogIHRlc3QoJ21vZHVsZSByZWdpc3RyYXRpb24gZmFpbHVyZXMgYXJlIHN1cmZhY2VkIHRvIHN0YXJ0dXAnLCAoKSBhc3luYyB7CiAgICBkaS5yZWdpc3RlcjxMb2dnZXI+KGxvZ2dlcik7CiAgICBhd2FpdCBleHBlY3RMYXRlcigKICAgICAgbm90aWZpY2F0aW9ucy5pbml0KG1lc3NhZ2luZzogbWVzc2FnaW5nKSwKICAgICAgdGhyb3dzQShhbnl0aGluZyksCiAgICApOwogIH0pOwoKICB0ZXN0KAogICAgJ21vZHVsZSBjb21wb3NpdGlvbiByZWdpc3RlcnMgc3dhcHBhYmxlIGNvbnRyYWN0cyB3aXRob3V0IGRldmljZSBjYWxscycsCiAgICAoKSBhc3luYyB7CiAgICAgIGRpLnJlZ2lzdGVyPExvZ2dlcj4obG9nZ2VyKTsKICAgICAgZGkucmVnaXN0ZXI8TmV0d29ya0NsaWVudD4oX05ldHdvcmsoKSk7CiAgICAgIGF3YWl0IG5vdGlmaWNhdGlvbnMuaW5pdChtZXNzYWdpbmc6IG1lc3NhZ2luZyk7CiAgICAgIGV4cGVjdChkaS5oYXM8Tm90aWZpY2F0aW9uQ2xpZW50PigpLCBpc1RydWUpOwogICAgICBleHBlY3QoZGkuaGFzPE5vdGlmaWNhdGlvblRva2VuTWFuYWdlcj4oKSwgaXNUcnVlKTsKICAgICAgZXhwZWN0KGRpLmhhczxOb3RpZmljYXRpb25QZXJtaXNzaW9uTWFuYWdlcj4oKSwgaXNUcnVlKTsKICAgICAgZXhwZWN0KGRpLmhhczxEZXZpY2VJbmZvPigpLCBpc1RydWUpOwogICAgfSwKICApOwoKICBmb3IgKGZpbmFsIHN0YXR1cyBpbiBBdXRob3JpemF0aW9uU3RhdHVzLnZhbHVlcykgewogICAgdGVzdCgKICAgICAgJ3Blcm1pc3Npb24gc3RhdHVzICRzdGF0dXMgaXMgbWFwcGVkIGNvcnJlY3RseSBhbmQgcHJvdmlzaW9uYWwgZm9yd2FyZGVkJywKICAgICAgKCkgYXN5bmMgewogICAgICAgIGZpbmFsIHNldHRpbmdzID0gX1NldHRpbmdzKCk7CiAgICAgICAgd2hlbigoKSA9PiBzZXR0aW5ncy5hdXRob3JpemF0aW9uU3RhdHVzKS50aGVuUmV0dXJuKHN0YXR1cyk7CiAgICAgICAgd2hlbigKICAgICAgICAgICgpID0+IG1lc3NhZ2luZy5yZXF1ZXN0UGVybWlzc2lvbihwcm92aXNpb25hbDogdHJ1ZSksCiAgICAgICAgKS50aGVuQW5zd2VyKChfKSBhc3luYyA9PiBzZXR0aW5ncyk7CiAgICAgICAgZmluYWwgbWFuYWdlciA9IEZpcmViYXNlUGVybWlzc2lvbk1hbmFnZXIoCiAgICAgICAgICBsb2dnZXI6IGxvZ2dlciwKICAgICAgICAgIGZpcmViYXNlTWVzc2FnaW5nOiBtZXNzYWdpbmcsCiAgICAgICAgKTsKICAgICAgICBleHBlY3QoCiAgICAgICAgICBhd2FpdCBtYW5hZ2VyLnJlcXVlc3RQZXJtaXNzaW9ucyhwcm92aXNpb25hbDogdHJ1ZSksCiAgICAgICAgICBzdGF0dXMgPT0gQXV0aG9yaXphdGlvblN0YXR1cy5hdXRob3JpemVkIHx8CiAgICAgICAgICAgICAgc3RhdHVzID09IEF1dGhvcml6YXRpb25TdGF0dXMucHJvdmlzaW9uYWwsCiAgICAgICAgKTsKICAgICAgfSwKICAgICk7CiAgfQoKICB0ZXN0KAogICAgJ3Blcm1pc3Npb24gZXJyb3JzIGFyZSByZXBvcnRlZCB0aHJvdWdoIHRoZSBub3RpZmljYXRpb24gY29udHJhY3QnLAogICAgKCkgYXN5bmMgewogICAgICB3aGVuKAogICAgICAgICgpID0+IG1lc3NhZ2luZy5yZXF1ZXN0UGVybWlzc2lvbihwcm92aXNpb25hbDogZmFsc2UpLAogICAgICApLnRoZW5UaHJvdyhTdGF0ZUVycm9yKCd1bmF2YWlsYWJsZScpKTsKICAgICAgZmluYWwgbWFuYWdlciA9IEZpcmViYXNlUGVybWlzc2lvbk1hbmFnZXIoCiAgICAgICAgbG9nZ2VyOiBsb2dnZXIsCiAgICAgICAgZmlyZWJhc2VNZXNzYWdpbmc6IG1lc3NhZ2luZywKICAgICAgKTsKICAgICAgYXdhaXQgZXhwZWN0TGF0ZXIoCiAgICAgICAgbWFuYWdlci5yZXF1ZXN0UGVybWlzc2lvbnMoKSwKICAgICAgICB0aHJvd3NBKGlzQTxOb3RpZmljYXRpb25FeGNlcHRpb24+KCkpLAogICAgICApOwogICAgfSwKICApOwoKICBncm91cCgndG9rZW4gbWFuYWdlcicsICgpIHsKICAgIGxhdGUgX05ldHdvcmsgbmV0d29yazsKICAgIGxhdGUgX0RldmljZSBkZXZpY2U7CiAgICBsYXRlIEZpcmViYXNlVG9rZW5NYW5hZ2VyIG1hbmFnZXI7CiAgICBjb25zdCBzdWNjZXNzID0gU3VjY2Vzc1Jlc3BvbnNlPE1hcDxTdHJpbmcsIGR5bmFtaWM+PigKICAgICAgc3RhdHVzQ29kZTogMjAwLAogICAgICBzdWNjZXNzOiB0cnVlLAogICAgICBkYXRhOiB7fSwKICAgICAgdGltZXN0YW1wOiAnMjAyNi0wMS0wMScsCiAgICApOwogICAgc2V0VXAoKCkgewogICAgICBuZXR3b3JrID0gX05ldHdvcmsoKTsKICAgICAgZGV2aWNlID0gX0RldmljZSgpOwogICAgICBtYW5hZ2VyID0gRmlyZWJhc2VUb2tlbk1hbmFnZXIoCiAgICAgICAgbG9nZ2VyOiBsb2dnZXIsCiAgICAgICAgbmV0d29ya0NsaWVudDogbmV0d29yaywKICAgICAgICBkZXZpY2VJbmZvOiBkZXZpY2UsCiAgICAgICAgZmlyZWJhc2VNZXNzYWdpbmc6IG1lc3NhZ2luZywKICAgICAgKTsKICAgICAgcmVnaXN0ZXJGYWxsYmFja1ZhbHVlKChPYmplY3Q/IGpzb24pID0+IGpzb24gYXMgTWFwPFN0cmluZywgZHluYW1pYz4pOwogICAgICB3aGVuKGRldmljZS5nZW5lcmF0ZURldmljZUlkKS50aGVuQW5zd2VyKChfKSBhc3luYyA9PiAnaW5zdGFsbC0xJyk7CiAgICAgIHdoZW4oZGV2aWNlLmdldERldmljZU5hbWUpLnRoZW5BbnN3ZXIoKF8pIGFzeW5jID0+ICdUZXN0IGRldmljZScpOwogICAgICB3aGVuKAogICAgICAgICgpID0+IG5ldHdvcmsucG9zdDxNYXA8U3RyaW5nLCBkeW5hbWljPj4oCiAgICAgICAgICBhbnkoKSwKICAgICAgICAgIGRhdGE6IGFueShuYW1lZDogJ2RhdGEnKSwKICAgICAgICAgIGZyb21Kc29uVDogYW55KG5hbWVkOiAnZnJvbUpzb25UJyksCiAgICAgICAgKSwKICAgICAgKS50aGVuQW5zd2VyKChjYWxsKSBhc3luYyB7CiAgICAgICAgZmluYWwgZGVjb2RlID0KICAgICAgICAgICAgY2FsbC5uYW1lZEFyZ3VtZW50c1sjZnJvbUpzb25UXQogICAgICAgICAgICAgICAgYXMgTWFwPFN0cmluZywgZHluYW1pYz4gRnVuY3Rpb24oT2JqZWN0Pyk7CiAgICAgICAgZXhwZWN0KGRlY29kZSh7J29rJzogdHJ1ZX0pLCB7J29rJzogdHJ1ZX0pOwogICAgICAgIHJldHVybiBzdWNjZXNzOwogICAgICB9KTsKICAgICAgd2hlbigKICAgICAgICAoKSA9PiBuZXR3b3JrLmRlbGV0ZTxNYXA8U3RyaW5nLCBkeW5hbWljPj4oCiAgICAgICAgICBhbnkoKSwKICAgICAgICAgIGZyb21Kc29uVDogYW55KG5hbWVkOiAnZnJvbUpzb25UJyksCiAgICAgICAgKSwKICAgICAgKS50aGVuQW5zd2VyKChjYWxsKSBhc3luYyB7CiAgICAgICAgZmluYWwgZGVjb2RlID0KICAgICAgICAgICAgY2FsbC5uYW1lZEFyZ3VtZW50c1sjZnJvbUpzb25UXQogICAgICAgICAgICAgICAgYXMgTWFwPFN0cmluZywgZHluYW1pYz4gRnVuY3Rpb24oT2JqZWN0Pyk7CiAgICAgICAgZXhwZWN0KGRlY29kZSh7J29rJzogdHJ1ZX0pLCB7J29rJzogdHJ1ZX0pOwogICAgICAgIHJldHVybiBzdWNjZXNzOwogICAgICB9KTsKICAgICAgd2hlbigKICAgICAgICAoKSA9PiBuZXR3b3JrLmhhbmRsZVN1Y2Nlc3NSZXNwb25zZTxNYXA8U3RyaW5nLCBkeW5hbWljPj4oc3VjY2VzcyksCiAgICAgICkudGhlblJldHVybihzdWNjZXNzKTsKICAgIH0pOwoKICAgIHRlc3QoJ3JldHVybnMgbnVsbGFibGUgRkNNIHRva2VucyBhbmQgcHJvcGFnYXRlcyBTREsgZmFpbHVyZXMnLCAoKSBhc3luYyB7CiAgICAgIHdoZW4oKCkgPT4gbWVzc2FnaW5nLmdldFRva2VuKCkpLnRoZW5BbnN3ZXIoKF8pIGFzeW5jID0+ICd0b2tlbicpOwogICAgICBleHBlY3QoYXdhaXQgbWFuYWdlci5nZXRGQ01Ub2tlbigpLCAndG9rZW4nKTsKICAgICAgd2hlbigoKSA9PiBtZXNzYWdpbmcuZ2V0VG9rZW4oKSkudGhlbkFuc3dlcigoXykgYXN5bmMgPT4gbnVsbCk7CiAgICAgIGV4cGVjdChhd2FpdCBtYW5hZ2VyLmdldEZDTVRva2VuKCksIGlzTnVsbCk7CiAgICAgIHdoZW4oKCkgPT4gbWVzc2FnaW5nLmdldFRva2VuKCkpLnRoZW5UaHJvdyhTdGF0ZUVycm9yKCdvZmZsaW5lJykpOwogICAgICBhd2FpdCBleHBlY3RMYXRlcihtYW5hZ2VyLmdldEZDTVRva2VuKCksIHRocm93c1N0YXRlRXJyb3IpOwogICAgfSk7CgogICAgdGVzdCgncmVnaXN0ZXJzIG1ldGFkYXRhLCByZWZyZXNoZXMgYW5kIHVucmVnaXN0ZXJzJywgKCkgYXN5bmMgewogICAgICBleHBlY3QoYXdhaXQgbWFuYWdlci5yZWdpc3RlclRva2VuKCd0b2tlbicpLCAnaW5zdGFsbC0xJyk7CiAgICAgIGZpbmFsIGRhdGEgPQogICAgICAgICAgdmVyaWZ5KAogICAgICAgICAgICAgICAgKCkgPT4gbmV0d29yay5wb3N0PE1hcDxTdHJpbmcsIGR5bmFtaWM+PigKICAgICAgICAgICAgICAgICAgJy9kZXZpY2UtdG9rZW5zL21lJywKICAgICAgICAgICAgICAgICAgZGF0YTogY2FwdHVyZUFueShuYW1lZDogJ2RhdGEnKSwKICAgICAgICAgICAgICAgICAgZnJvbUpzb25UOiBhbnkobmFtZWQ6ICdmcm9tSnNvblQnKSwKICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgKS5jYXB0dXJlZC5zaW5nbGUKICAgICAgICAgICAgICBhcyBNYXA7CiAgICAgIGV4cGVjdChkYXRhWydmY21Ub2tlbiddLCAndG9rZW4nKTsKICAgICAgZXhwZWN0KGRhdGFbJ2RldmljZUlkJ10sICdpbnN0YWxsLTEnKTsKICAgICAgZXhwZWN0KGRhdGFbJ2RldmljZU5hbWUnXSwgJ1Rlc3QgZGV2aWNlJyk7CiAgICAgIGF3YWl0IG1hbmFnZXIuaGFuZGxlVG9rZW5SZWZyZXNoKCduZXh0LXRva2VuJyk7CiAgICAgIGF3YWl0IG1hbmFnZXIudW5SZWdpc3RlclRva2VuKCdpbnN0YWxsLTEnKTsKICAgICAgdmVyaWZ5KAogICAgICAgICgpID0+IG5ldHdvcmsuaGFuZGxlU3VjY2Vzc1Jlc3BvbnNlPE1hcDxTdHJpbmcsIGR5bmFtaWM+PihzdWNjZXNzKSwKICAgICAgKS5jYWxsZWQoMyk7CiAgICB9KTsKCiAgICB0ZXN0KAogICAgICAnYXBwbGljYXRpb24tbGV2ZWwgYmFja2VuZCByZWplY3Rpb24gY2Fubm90IGJlIHJlcG9ydGVkIGFzIHN1Y2Nlc3MnLAogICAgICAoKSBhc3luYyB7CiAgICAgICAgd2hlbigKICAgICAgICAgICgpID0+IG5ldHdvcmsuaGFuZGxlU3VjY2Vzc1Jlc3BvbnNlPE1hcDxTdHJpbmcsIGR5bmFtaWM+PihzdWNjZXNzKSwKICAgICAgICApLnRoZW5UaHJvdyhVbmF1dGhvcml6ZWRFeGNlcHRpb24oKSk7CiAgICAgICAgYXdhaXQgZXhwZWN0TGF0ZXIoCiAgICAgICAgICBtYW5hZ2VyLnJlZ2lzdGVyVG9rZW4oJ3Rva2VuJyksCiAgICAgICAgICB0aHJvd3NBKGlzQTxVbmF1dGhvcml6ZWRFeGNlcHRpb24+KCkpLAogICAgICAgICk7CiAgICAgICAgYXdhaXQgZXhwZWN0TGF0ZXIoCiAgICAgICAgICBtYW5hZ2VyLnVuUmVnaXN0ZXJUb2tlbignaW5zdGFsbC0xJyksCiAgICAgICAgICB0aHJvd3NBKGlzQTxVbmF1dGhvcml6ZWRFeGNlcHRpb24+KCkpLAogICAgICAgICk7CiAgICAgIH0sCiAgICApOwogIH0pOwoKICB0ZXN0KCd0b2tlbiByZXF1ZXN0IG1vZGVscyByb3VuZC10cmlwIEpTT04nLCAoKSB7CiAgICBjb25zdCByZXF1ZXN0ID0gRGV2aWNlVG9rZW5SZXF1ZXN0KAogICAgICBmY21Ub2tlbjogJ3Rva2VuJywKICAgICAgZGV2aWNlSWQ6ICdpZCcsCiAgICAgIGRldmljZU5hbWU6ICdwaG9uZScsCiAgICAgIGRldmljZVR5cGU6ICdpb3MnLAogICAgKTsKICAgIGV4cGVjdCgKICAgICAgRGV2aWNlVG9rZW5SZXF1ZXN0LmZyb21Kc29uKHJlcXVlc3QudG9Kc29uKCkpLnRvSnNvbigpLAogICAgICByZXF1ZXN0LnRvSnNvbigpLAogICAgKTsKICAgIGNvbnN0IHVwZGF0ZSA9IERldmljZVRva2VuVXBkYXRlUmVxdWVzdChmY21Ub2tlbjogJ25leHQnKTsKICAgIGV4cGVjdChEZXZpY2VUb2tlblVwZGF0ZVJlcXVlc3QuZnJvbUpzb24odXBkYXRlLnRvSnNvbigpKS5mY21Ub2tlbiwgJ25leHQnKTsKICAgIGV4cGVjdChjb25zdCBEZWZhdWx0Tm90aWZpY2F0aW9uQ29uZmlnKCksIGlzQTxOb3RpZmljYXRpb25Db25maWc+KCkpOwogIH0pOwp9Cg==", "type": "text" }, { @@ -1394,13 +1593,25 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ { "path": "{{ name.snakeCase() }}/pubspec.yaml", "data": - "bmFtZToge3sgbmFtZS5zbmFrZUNhc2UoKSB9fV93b3Jrc3BhY2UKZGVzY3JpcHRpb246ICJ7e3tkZXNjcmlwdGlvbn19fSIKcHVibGlzaF90bzogJ25vbmUnCgplbnZpcm9ubWVudDoKICBzZGs6ICc+PTMuOC4wIDw0LjAuMCcKCmRldl9kZXBlbmRlbmNpZXM6CiAgZmx1dHRlcl9saW50czogXjUuMC4wCiAgbWVsb3M6IF42LjIuMAo=", + "bmFtZToge3sgbmFtZS5zbmFrZUNhc2UoKSB9fV93b3Jrc3BhY2UKZGVzY3JpcHRpb246ICJ7e3tkZXNjcmlwdGlvbn19fSIKcHVibGlzaF90bzogJ25vbmUnCgplbnZpcm9ubWVudDoKICBzZGs6ICc+PTMuOC4wIDw0LjAuMCcKCmRldl9kZXBlbmRlbmNpZXM6CiAgZmx1dHRlcl9saW50czogXjUuMC4wCiAgbWVsb3M6IF42LjIuMAogIHBhdGg6IF4xLjkuMQo=", "type": "text" }, { "path": "{{ name.snakeCase() }}/README.md", "data": - "IyB7eyBuYW1lLnRpdGxlQ2FzZSgpIH19Cgp7e3tkZXNjcmlwdGlvbn19fQoKWyFbbm9uc3RvcF9jbGldKGh0dHBzOi8vaW1nLnNoaWVsZHMuaW8vYmFkZ2Uvc3RhcnRlZCUyMHdpdGgtbm9uc3RvcF9jbGktMTY2QzRFLnN2Zz9zdHlsZT1mbGF0LXNxdWFyZSldKGh0dHBzOi8vcHViLmRldi9wYWNrYWdlcy9ub25zdG9wX2NsaSkKWyFbbWVsb3NdKGh0dHBzOi8vaW1nLnNoaWVsZHMuaW8vYmFkZ2UvbWFpbnRhaW5lZCUyMHdpdGgtbWVsb3MtZjcwMGZmLnN2Zz9zdHlsZT1mbGF0LXNxdWFyZSldKGh0dHBzOi8vZ2l0aHViLmNvbS9pbnZlcnRhc2UvbWVsb3MpCgojIyBMYXlvdXQKCmBgYAphcHBzL3t7bmFtZS5zbmFrZUNhc2UoKX19ICAgICAgdGhlIGFwcGxpY2F0aW9uIHNoZWxsOiBib290c3RyYXAsIHJvdXRlciwgc3BsYXNoCmZlYXR1cmVzLyAgICAgICAgICAgICAgICAgICAgICB2ZXJ0aWNhbCBzbGljZXMgKHVpICsgc3RhdGUgKyBkYXRhKQpwYWNrYWdlcy8gICAgICAgICAgICAgICAgICAgICAgc2hhcmVkIGNhcGFiaWxpdGllcwpwbHVnaW5zLyAgICAgICAgICAgICAgICAgICAgICAgbmF0aXZlIGludGVncmF0aW9ucwpgYGAKCkRlcGVuZGVuY2llcyBwb2ludCBpbndhcmQ6IGFwcHMgZGVwZW5kIG9uIGZlYXR1cmVzLCBmZWF0dXJlcyBkZXBlbmQgb24KcGFja2FnZXMsIHBhY2thZ2VzIGRlcGVuZCBvbiBub3RoaW5nIGFib3ZlIHRoZW0uCgojIyMgV2hhdCBpcyBhbHJlYWR5IHdpcmVkCgp8IE1vZHVsZSB8IFJvbGUgfAp8IC0tLSB8IC0tLSB8CnwgYHBhY2thZ2VzL2NvcmVgIHwgbG9nZ2VyLCBESSBib290c3RyYXAsIHJvdXRlIG9ic2VydmVycywgZXJyb3IgdHlwZXMsIEJMb0Mgb2JzZXJ2ZXIgfAp8IGBwYWNrYWdlcy9kaWAgfCBzZXJ2aWNlIGxvY2F0b3IgKEdldEl0KSBiZWhpbmQgYSBzbWFsbCBpbnRlcmZhY2UgfAp8IGBwYWNrYWdlcy9kZXNpZ25fc3lzdGVtYCB8IE1hdGVyaWFsIDMgdGhlbWUsIHNoYXJlZCBjb21wb25lbnRzLCB0b2FzdHMsIGxvYWRlcnMgfAp8IGBwYWNrYWdlcy9sb2NhbGl6YXRpb25gIHwgdHlwZS1zYWZlIHN0cmluZ3MgZ2VuZXJhdGVkIGZyb20gWUFNTCAoaTY5bikgfAp8IGBwYWNrYWdlcy91dGlsc2AgfCBkZXBlbmRlbmN5LWxpZ2h0IGhlbHBlcnMgfAp7eyNuZXR3b3JrfX18IGBwYWNrYWdlcy9uZXR3b3JrYCB8IERpbyBjbGllbnQsIGF1dGggKyBsb2dnaW5nIGludGVyY2VwdG9ycywgdHlwZWQgZXJyb3JzIHwKe3svbmV0d29ya319e3sjYW5hbHl0aWNzfX18IGBwYWNrYWdlcy9hbmFseXRpY3NgIHwgZXZlbnQgdHJhY2tpbmcgYmVoaW5kIGEgc3dhcHBhYmxlIGNsaWVudCB8Cnt7L2FuYWx5dGljc319e3sjY3Jhc2hseXRpY3N9fXwgYHBhY2thZ2VzL2NyYXNobHl0aWNzYCB8IGNyYXNoIGFuZCBub24tZmF0YWwgcmVwb3J0aW5nIHwKe3svY3Jhc2hseXRpY3N9fXt7I25vdGlmaWNhdGlvbnN9fXwgYHBhY2thZ2VzL25vdGlmaWNhdGlvbnNgIHwgRkNNLCBwZXJtaXNzaW9ucywgZGV2aWNlLXRva2VuIHJlZ2lzdHJhdGlvbiB8Cnt7L25vdGlmaWNhdGlvbnN9fXt7I2ZlYXR1cmVfZmxhZ3N9fXwgYHBhY2thZ2VzL2ZlYXR1cmVfZmxhZ3NgIHwgUmVtb3RlIENvbmZpZyBmbGFncyB3aXRoIGEgd2lkZ2V0IHdyYXBwZXIgfAp7ey9mZWF0dXJlX2ZsYWdzfX17eyNkZXZlbG9wZXJ9fXwgYHBhY2thZ2VzL2RldmVsb3BlcmAgfCBpbi1hcHAgZGV2IHRvb2xzLCByZWFjaGFibGUgYnkgYSBoaWRkZW4gNS10YXAgZ2VzdHVyZSB8Cnt7L2RldmVsb3Blcn19e3sjYXV0aH19fCBgZmVhdHVyZXMvYXV0aGAgfCBGaXJlYmFzZSBBdXRoIChlbWFpbCwgR29vZ2xlLCBBcHBsZSkgKyByb3V0ZSBndWFyZHMgfAp7ey9hdXRofX17eyNkYXNoYm9hcmR9fXwgYGZlYXR1cmVzL2Rhc2hib2FyZGAgfCBib3R0b20tbmF2aWdhdGlvbiBzaGVsbCB3aXRoIHN0YXJ0ZXIgdGFicyB8Cnt7L2Rhc2hib2FyZH19CgojIyBHZXR0aW5nIHN0YXJ0ZWQKCmBgYHNoCmRhcnQgcHViIGdsb2JhbCBhY3RpdmF0ZSBtZWxvcwptZWxvcyBib290c3RyYXAKYGBgCnt7I2ZpcmViYXNlfX0KIyMjIEZpcmViYXNlCgpUaGlzIHByb2plY3QgdXNlcyBGaXJlYmFzZSwgc28gcnVuIHRoaXMgYmVmb3JlIHRob3NlIGZlYXR1cmVzIHdpbGwgd29yay4KVGhlIHJlc3Qgb2YgdGhlIGFwcCBzdGlsbCBib290cyB3aXRob3V0IGl0OgoKYGBgc2gKZGFydCBwdWIgZ2xvYmFsIGFjdGl2YXRlIGZsdXR0ZXJmaXJlX2NsaQpjZCBhcHBzL3t7bmFtZS5zbmFrZUNhc2UoKX19CmZsdXR0ZXJmaXJlIGNvbmZpZ3VyZQpgYGAKe3svZmlyZWJhc2V9fQojIyMgUnVuCgpgYGBzaApjZCBhcHBzL3t7bmFtZS5zbmFrZUNhc2UoKX19CmZsdXR0ZXIgcnVuIC0tZGFydC1kZWZpbmU9QkFTRV9VUkw9aHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20KYGBgCgpFdmVyeSBlbnZpcm9ubWVudCB2YWx1ZSBpcyBhIGAtLWRhcnQtZGVmaW5lYCByZWFkIGluCmBwYWNrYWdlcy9jb3JlL2xpYi9jb25zdGFudHMvZW52aXJvbm1lbnQuZGFydGAuIEFkZCBuZXcgb25lcyB0aGVyZSByYXRoZXIgdGhhbgpzY2F0dGVyaW5nIGBTdHJpbmcuZnJvbUVudmlyb25tZW50YCBhcm91bmQgdGhlIGNvZGViYXNlLgp7eyNmaXJlYmFzZX19ClRvIHJ1biBhZ2FpbnN0IHRoZSBGaXJlYmFzZSBlbXVsYXRvciBzdWl0ZSwgYWRkCmAtLWRhcnQtZGVmaW5lPVVTRV9FTVVMQVRPUlM9dHJ1ZWAuCnt7L2ZpcmViYXNlfX0KIyMgRGF5LXRvLWRheQoKYGBgc2gKbWVsb3MgbGludCAgICAgICAgICAgICAjIGZvcm1hdCArIGFuYWx5emUgZXZlcnl0aGluZwptZWxvcyB0ZXN0ICAgICAgICAgICAgICMgcnVuIGV2ZXJ5IHBhY2thZ2UncyB0ZXN0cwptZWxvcyBydW4gZ2VuZXJhdGUgICAgICMgYnVpbGRfcnVubmVyIHdoZXJlIGl0IGlzIG5lZWRlZAptZWxvcyBydW4gZ2VuZXJhdGU6aTY5biAgIyByZWdlbmVyYXRlIHN0cmluZ3MgYWZ0ZXIgZWRpdGluZyBtZXNzYWdlcy5pNjluLnlhbWwKYGBgCgojIyBBZGRpbmcgdG8gdGhlIG1vbm9yZXBvCgpgYGBzaApub25zdG9wIGNyZWF0ZSBwYWNrYWdlIG15X2ZlYXR1cmUgLW8gZmVhdHVyZXMKbm9uc3RvcCBjcmVhdGUgcGFja2FnZSBteV9wYWNrYWdlIC1vIHBhY2thZ2VzCm5vbnN0b3AgY3JlYXRlIGFwcCBteV9zZWNvbmRfYXBwIC1vIGFwcHMKbm9uc3RvcCBjcmVhdGUgcGx1Z2luIG15X3BsdWdpbiAtbyBwbHVnaW5zCmBgYAoKIyMgV2hlcmUgdG8gc3RhcnQKCjEuIFJlcGxhY2UgdGhlIHBsYWNlaG9sZGVyIHRhYnMgaW4gYGZlYXR1cmVzL2Rhc2hib2FyZGAuCjIuIFB1dCB5b3VyIHByb2R1Y3Qgc3RyaW5ncyBpbiBgcGFja2FnZXMvbG9jYWxpemF0aW9uL2xpYi9tZXNzYWdlcy5pNjluLnlhbWxgLgozLiBTZXQgdGhlIHBhbGV0dGUgaW4gYHBhY2thZ2VzL2Rlc2lnbl9zeXN0ZW0vbGliL2dlbmVyYXRlZC90aGVtZS5kYXJ0YC4KNC4gQWRkIGZlYXR1cmUgbW9kdWxlcyBhbmQgc3ByZWFkIHRoZWlyIHJvdXRlcyBpbnRvCiAgIGBhcHBzL3t7bmFtZS5zbmFrZUNhc2UoKX19L2xpYi9yb3V0ZXIvcm91dGVyLmRhcnRgLgo=", + "IyB7eyBuYW1lLnRpdGxlQ2FzZSgpIH19Cgp7e3tkZXNjcmlwdGlvbn19fQoKWyFbbm9uc3RvcF9jbGldKGh0dHBzOi8vaW1nLnNoaWVsZHMuaW8vYmFkZ2Uvc3RhcnRlZCUyMHdpdGgtbm9uc3RvcF9jbGktMTY2QzRFLnN2Zz9zdHlsZT1mbGF0LXNxdWFyZSldKGh0dHBzOi8vcHViLmRldi9wYWNrYWdlcy9ub25zdG9wX2NsaSkKWyFbbWVsb3NdKGh0dHBzOi8vaW1nLnNoaWVsZHMuaW8vYmFkZ2UvbWFpbnRhaW5lZCUyMHdpdGgtbWVsb3MtZjcwMGZmLnN2Zz9zdHlsZT1mbGF0LXNxdWFyZSldKGh0dHBzOi8vZ2l0aHViLmNvbS9pbnZlcnRhc2UvbWVsb3MpCgojIyBMYXlvdXQKCmBgYAphcHBzL3t7bmFtZS5zbmFrZUNhc2UoKX19ICAgICAgdGhlIGFwcGxpY2F0aW9uIHNoZWxsOiBib290c3RyYXAsIHJvdXRlciwgc3BsYXNoCmZlYXR1cmVzLyAgICAgICAgICAgICAgICAgICAgICB2ZXJ0aWNhbCBzbGljZXMgKHVpICsgc3RhdGUgKyBkYXRhKQpwYWNrYWdlcy8gICAgICAgICAgICAgICAgICAgICAgc2hhcmVkIGNhcGFiaWxpdGllcwpwbHVnaW5zLyAgICAgICAgICAgICAgICAgICAgICAgbmF0aXZlIGludGVncmF0aW9ucwpgYGAKCkRlcGVuZGVuY2llcyBwb2ludCBpbndhcmQ6IGFwcHMgZGVwZW5kIG9uIGZlYXR1cmVzLCBmZWF0dXJlcyBkZXBlbmQgb24KcGFja2FnZXMsIHBhY2thZ2VzIGRlcGVuZCBvbiBub3RoaW5nIGFib3ZlIHRoZW0uCgojIyMgV2hhdCBpcyBhbHJlYWR5IHdpcmVkCgp8IE1vZHVsZSB8IFJvbGUgfAp8IC0tLSB8IC0tLSB8CnwgYHBhY2thZ2VzL2NvcmVgIHwgbG9nZ2VyLCBESSBib290c3RyYXAsIHJvdXRlIG9ic2VydmVycywgZXJyb3IgdHlwZXMsIEJMb0Mgb2JzZXJ2ZXIgfAp8IGBwYWNrYWdlcy9kaWAgfCBzZXJ2aWNlIGxvY2F0b3IgKEdldEl0KSBiZWhpbmQgYSBzbWFsbCBpbnRlcmZhY2UgfAp8IGBwYWNrYWdlcy9kZXNpZ25fc3lzdGVtYCB8IE1hdGVyaWFsIDMgdGhlbWUsIHNoYXJlZCBjb21wb25lbnRzLCB0b2FzdHMsIGxvYWRlcnMgfAp8IGBwYWNrYWdlcy9sb2NhbGl6YXRpb25gIHwgdHlwZS1zYWZlIHN0cmluZ3MgZ2VuZXJhdGVkIGZyb20gWUFNTCAoaTY5bikgfAp8IGBwYWNrYWdlcy91dGlsc2AgfCBkZXBlbmRlbmN5LWxpZ2h0IGhlbHBlcnMgfAp7eyNuZXR3b3JrfX18IGBwYWNrYWdlcy9uZXR3b3JrYCB8IERpbyBjbGllbnQsIGF1dGggKyBsb2dnaW5nIGludGVyY2VwdG9ycywgdHlwZWQgZXJyb3JzIHwKe3svbmV0d29ya319e3sjYW5hbHl0aWNzfX18IGBwYWNrYWdlcy9hbmFseXRpY3NgIHwgZXZlbnQgdHJhY2tpbmcgYmVoaW5kIGEgc3dhcHBhYmxlIGNsaWVudCB8Cnt7L2FuYWx5dGljc319e3sjY3Jhc2hseXRpY3N9fXwgYHBhY2thZ2VzL2NyYXNobHl0aWNzYCB8IGNyYXNoIGFuZCBub24tZmF0YWwgcmVwb3J0aW5nIHwKe3svY3Jhc2hseXRpY3N9fXt7I25vdGlmaWNhdGlvbnN9fXwgYHBhY2thZ2VzL25vdGlmaWNhdGlvbnNgIHwgRkNNLCBwZXJtaXNzaW9ucywgZGV2aWNlLXRva2VuIHJlZ2lzdHJhdGlvbiB8Cnt7L25vdGlmaWNhdGlvbnN9fXt7I2ZlYXR1cmVfZmxhZ3N9fXwgYHBhY2thZ2VzL2ZlYXR1cmVfZmxhZ3NgIHwgUmVtb3RlIENvbmZpZyBmbGFncyB3aXRoIGEgd2lkZ2V0IHdyYXBwZXIgfAp7ey9mZWF0dXJlX2ZsYWdzfX17eyNkZXZlbG9wZXJ9fXwgYHBhY2thZ2VzL2RldmVsb3BlcmAgfCBpbi1hcHAgZGV2IHRvb2xzLCByZWFjaGFibGUgYnkgYSBoaWRkZW4gNS10YXAgZ2VzdHVyZSB8Cnt7L2RldmVsb3Blcn19e3sjYXV0aH19fCBgZmVhdHVyZXMvYXV0aGAgfCBGaXJlYmFzZSBBdXRoIChlbWFpbCwgR29vZ2xlLCBBcHBsZSkgKyByb3V0ZSBndWFyZHMgfAp7ey9hdXRofX17eyNkYXNoYm9hcmR9fXwgYGZlYXR1cmVzL2Rhc2hib2FyZGAgfCBib3R0b20tbmF2aWdhdGlvbiBzaGVsbCB3aXRoIHN0YXJ0ZXIgdGFicyB8Cnt7L2Rhc2hib2FyZH19CgojIyBHZXR0aW5nIHN0YXJ0ZWQKCmBgYHNoCmRhcnQgcHViIGdldApkYXJ0IHJ1biBtZWxvcyBib290c3RyYXAKYGBgCnt7I2ZpcmViYXNlfX0KIyMjIEZpcmViYXNlCgpUaGlzIHByb2plY3QgdXNlcyBGaXJlYmFzZSwgc28gcnVuIHRoaXMgYmVmb3JlIHRob3NlIGZlYXR1cmVzIHdpbGwgd29yay4KVGhlIHJlc3Qgb2YgdGhlIGFwcCBzdGlsbCBib290cyB3aXRob3V0IGl0OgoKYGBgc2gKZGFydCBwdWIgZ2xvYmFsIGFjdGl2YXRlIGZsdXR0ZXJmaXJlX2NsaQpjZCBhcHBzL3t7bmFtZS5zbmFrZUNhc2UoKX19CmZsdXR0ZXJmaXJlIGNvbmZpZ3VyZQpgYGAKe3svZmlyZWJhc2V9fQojIyMgUnVuCgpgYGBzaApjZCBhcHBzL3t7bmFtZS5zbmFrZUNhc2UoKX19CmZsdXR0ZXIgcnVuIC0tZGFydC1kZWZpbmU9QkFTRV9VUkw9aHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20KYGBgCgpFdmVyeSBlbnZpcm9ubWVudCB2YWx1ZSBpcyBhIGAtLWRhcnQtZGVmaW5lYCByZWFkIGluCmBwYWNrYWdlcy9jb3JlL2xpYi9jb25zdGFudHMvZW52aXJvbm1lbnQuZGFydGAuIEFkZCBuZXcgb25lcyB0aGVyZSByYXRoZXIgdGhhbgpzY2F0dGVyaW5nIGBTdHJpbmcuZnJvbUVudmlyb25tZW50YCBhcm91bmQgdGhlIGNvZGViYXNlLgp7eyNmaXJlYmFzZX19ClRvIHJ1biBhZ2FpbnN0IHRoZSBGaXJlYmFzZSBlbXVsYXRvciBzdWl0ZSwgYWRkCmAtLWRhcnQtZGVmaW5lPVVTRV9FTVVMQVRPUlM9dHJ1ZWAuCnt7L2ZpcmViYXNlfX0KIyMgRGF5LXRvLWRheQoKYGBgc2gKZGFydCBydW4gbWVsb3MgcnVuIGxpbnQgICAgICAgIyBmb3JtYXQtY2hlY2sgYW5kIGFuYWx5emUKZGFydCBydW4gbWVsb3MgcnVuIHRlc3QgICAgICAgIyBydW4gZXZlcnkgcGFja2FnZSdzIHRlc3RzCmRhcnQgcnVuIG1lbG9zIHJ1biBjb3ZlcmFnZSAgICMgdGVzdHMgKyBzdHJpY3QgMTAwJSBsaW5lLWNvdmVyYWdlIGdhdGUKZGFydCBydW4gbWVsb3MgcnVuIGdlbmVyYXRlICAgIyByZWJ1aWxkIHNlcmlhbGl6ZXJzCmRhcnQgcnVuIG1lbG9zIHJ1biBnZW5lcmF0ZTppNjluICAjIHJlYnVpbGQgbG9jYWxpemF0aW9uCmBgYAoKIyMgQWRkaW5nIHRvIHRoZSBtb25vcmVwbwoKYGBgc2gKbm9uc3RvcCBjcmVhdGUgbXlfZmVhdHVyZSAtLXRlbXBsYXRlIHBhY2thZ2UgLW8gZmVhdHVyZXMKbm9uc3RvcCBjcmVhdGUgbXlfcGFja2FnZSAtLXRlbXBsYXRlIHBhY2thZ2UgLW8gcGFja2FnZXMKbm9uc3RvcCBjcmVhdGUgbXlfc2Vjb25kX2FwcCAtLXRlbXBsYXRlIGFwcCAtbyBhcHBzCm5vbnN0b3AgY3JlYXRlIG15X3BsdWdpbiAtLXRlbXBsYXRlIHBsdWdpbiAtbyBwbHVnaW5zCmBgYAoKIyMgV2hlcmUgdG8gc3RhcnQKCjEuIFJlcGxhY2UgdGhlIHt7I2Rhc2hib2FyZH19cGxhY2Vob2xkZXIgdGFicyBpbiBgZmVhdHVyZXMvZGFzaGJvYXJkYHt7L2Rhc2hib2FyZH19e3teZGFzaGJvYXJkfX1wbGFjZWhvbGRlciBob21lIHNjcmVlbiBpbiB0aGUgYXBwIHJvdXRlcnt7L2Rhc2hib2FyZH19LgoyLiBQdXQgeW91ciBwcm9kdWN0IHN0cmluZ3MgaW4gYHBhY2thZ2VzL2xvY2FsaXphdGlvbi9saWIvbWVzc2FnZXMuaTY5bi55YW1sYC4KMy4gU2V0IHRoZSBwYWxldHRlIGluIGBwYWNrYWdlcy9kZXNpZ25fc3lzdGVtL2xpYi9nZW5lcmF0ZWQvdGhlbWUuZGFydGAuCjQuIEFkZCBmZWF0dXJlIG1vZHVsZXMgYW5kIHNwcmVhZCB0aGVpciByb3V0ZXMgaW50bwogICBgYXBwcy97e25hbWUuc25ha2VDYXNlKCl9fS9saWIvcm91dGVyL3JvdXRlci5kYXJ0YC4KCiMjIEFyY2hpdGVjdHVyZSBhbmQgdGVzdGluZwoKVGhlIHN0YXJ0ZXIgc2VwYXJhdGVzIHRoZSBhcHAgdmlldywgcm91dGluZywgc3RhcnR1cCBhbmQgZm9yZWdyb3VuZCBsaWZlY3ljbGUuCkNsaWVudHMgYWNjZXB0IGluamVjdGVkIFNES3MsIGxvZ2dlcnMgYW5kIHRyYW5zcG9ydHM7IGZlYXR1cmUgY29kZSBjb25zdW1lcyBzbWFsbAppbnRlcmZhY2VzIHJhdGhlciB0aGFuIHN1YmNsYXNzaW5nIHBsYXRmb3JtIFNES3MuIFNlZSBbYXJjaGl0ZWN0dXJlXShkb2NzL2FyY2hpdGVjdHVyZS5tZCkKZm9yIHRoZSBTT0xJRCBib3VuZGFyaWVzIGFuZCBhbiBleGFtcGxlIG9mIGFkZGluZyBhIHRlc3RlZCBmZWF0dXJlLgoKRXZlcnkgZ2VuZXJhdGVkIHBhY2thZ2UgaGFzIHRlc3RzLiBVbml0IGFuZCB3aWRnZXQgdGVzdHMgcnVuIHdpdGhvdXQgYSBGaXJlYmFzZQphY2NvdW50IG9yIG5ldHdvcmsgc2VydmljZTsgRmlyZWJhc2UgaW50ZWdyYXRpb24gdGVzdHMgdXNlIG9mZmxpbmUgcGxhdGZvcm0gZG91Ymxlcy4KVGhlIHN0cmljdCBnYXRlIGltcG9ydHMgb3RoZXJ3aXNlLXVubG9hZGVkIGxpYnJhcmllcywgcnVucyBhbGwgc3VpdGVzLCBtZXJnZXMgdGhlaXIKTENPViByZWNvcmRzIGFuZCByZXF1aXJlcyAqKjEwMCUgZXhlY3V0YWJsZS1saW5lIGNvdmVyYWdlIG9mIHdvcmtzcGFjZSBgbGliL2AgY29kZSoqLgpJdCBpbmNsdWRlcyBlbnRyeXBvaW50cywgc3RhcnR1cCwgdGhlbWUgYW5kIGVycm9yIHBhdGhzLiBPbmx5IGNvbXBpbGVyLWdlbmVyYXRlZApgLmcuZGFydGAsIGAuZnJlZXplZC5kYXJ0YCBhbmQgYC5pNjluLmRhcnRgIGZpbGVzIGFyZSBleGNsdWRlZC4KCmBgYHNoCmRhcnQgcnVuIHRvb2wvY292ZXJhZ2UuZGFydAojIEluc3BlY3QgZXhpc3RpbmcgcmVwb3J0cyB3aXRob3V0IHJlcnVubmluZyB0ZXN0cyAobm90IGEgdmFsaWRhdGlvbiBydW4pOgpkYXJ0IHJ1biB0b29sL2NvdmVyYWdlLmRhcnQgLS1yZXBvcnQtb25seQpgYGAKClRoZSBnYXRlIGZhaWxzIGZvciBmYWlsZWQgdGVzdHMsIG1pc3NpbmcgdGVzdHMvcmVwb3J0cywgb3IgdW5jb3ZlcmVkIGxpbmVzLgpUaGUgbWVyZ2VkIHJlcG9ydCBpcyBgY292ZXJhZ2UvbGNvdi5pbmZvYC4gRG8gbm90IHJ1biB0d28gY292ZXJhZ2Ugam9icyBpbiB0aGUKc2FtZSBjaGVja291dDogZWFjaCBvd25zIGEgdGVtcG9yYXJ5IGB0ZXN0L2NvdmVyYWdlX2ltcG9ydHNfdGVzdC5kYXJ0YCBmaXh0dXJlLApyZW1vdmVkIG9uIG5vcm1hbCBjb21wbGV0aW9uLiBBZnRlciBhbiBpbnRlcnJ1cHRlZCBydW4sIGluc3BlY3QgYW5kIHJlbW92ZSBvbmx5CnRoYXQgZ2VuZXJhdGVkIGZpeHR1cmUgYmVmb3JlIHJldHJ5aW5nLgoKQ292ZXJhZ2UgaXMgbm90IGEgcHJvb2Ygb2YgY29ycmVjdG5lc3MsIGJyYW5jaCBjb21wbGV0ZW5lc3MsIHNlY3VyaXR5LCBvciBuYXRpdmUKcGx1Z2luIGNvbXBhdGliaWxpdHkuIEtlZXAgYXNzZXJ0aW9ucyBhYm91dCBiZWhhdmlvciwgYW5kIGFkZCBkZXZpY2UgaW50ZWdyYXRpb24KdGVzdHMgZm9yIHlvdXIgRmlyZWJhc2UgcHJvamVjdCwgbmF0aXZlIHBlcm1pc3Npb25zLCBwcm92aWRlciBzaWduLWluIGFuZCBiYWNrZW5kLgpUaGUgZ2VuZXJhdGVkIEdpdEh1YiBBY3Rpb25zIHdvcmtmbG93IGNoZWNrcyBhbmFseXNpcywgdGVzdHMsIGNvdmVyYWdlIGFuZCBhIHdlYiBidWlsZC4KCnt7I2F1dGh9fSMjIyBBdXRoZW50aWNhdGlvbiBhbmQgZGVtbyBtb2RlCgpgR29BdXRoUm91dGVgIGRlbmllcyBhY2Nlc3Mgd2hlbiBhdXRoZW50aWNhdGlvbiBpcyBtaXNzaW5nIG9yIHNpZ25lZCBvdXQuCnt7I2Rhc2hib2FyZH19VGhlIHN0YXJ0ZXIgZGFzaGJvYXJkIGV4cGxpY2l0bHkgYWxsb3dzICoqdW5jb25maWd1cmVkIGRlbW8gbW9kZSoqIHNvCnlvdSBjYW4gZXhwbG9yZSBpdCBiZWZvcmUgYGZsdXR0ZXJmaXJlIGNvbmZpZ3VyZWAuIEl0IGNvbnRhaW5zIG5vIHByb3RlY3RlZCBkYXRhLgpEbyBub3QgdXNlIGBhbGxvd1VuY29uZmlndXJlZDogdHJ1ZWAgZm9yIHJlYWwgcHJvdGVjdGVkIHJvdXRlcy4Ke3svZGFzaGJvYXJkfX1DbGllbnQtc2lkZSBndWFyZHMgYXJlIG5hdmlnYXRpb24gaGVscGVyczsgZW5mb3JjZSBhdXRob3JpemF0aW9uIGluCmJhY2tlbmQgZW5kcG9pbnRzIGFuZCBGaXJlYmFzZSBzZWN1cml0eSBydWxlcy4Ke3svYXV0aH19Cnt7I25vdGlmaWNhdGlvbnN9fSMjIyBOb3RpZmljYXRpb25zCgpUaGUgU0RLIGNsaWVudCBvd25zIHN1YnNjcmlwdGlvbnMsIG5vdCBuYXZpZ2F0aW9uIG9yIHRvYXN0IHdpZGdldHMuIFRoZSBhcHAKc3VwcGxpZXMgY2FsbGJhY2tzLCBxdWV1ZXMgY29sZC1zdGFydCByb3V0ZXMgdW50aWwgdGhlIHJvdXRlciBpcyByZWFkeSwgYW5kIG93bnMKZm9yZWdyb3VuZCBsaWZlY3ljbGUgaGFuZGxpbmcuIERldmljZSBJRHMgYXJlIHJhbmRvbSBwZXIgaW5zdGFsbGF0aW9uIGFuZApwZXJzaXN0ZWQgbG9jYWxseTsgdGhleSBhcmUgbm90IGhhcmR3YXJlIGZpbmdlcnByaW50cy4KCkltcGxlbWVudCB0aGUgYFBPU1QgL2RldmljZS10b2tlbnMvbWVgIGFuZCBgREVMRVRFIC9kZXZpY2UtdG9rZW5zL21lLzpkZXZpY2VJZGAKYmFja2VuZCBlbmRwb2ludHMgYmVmb3JlIGVuYWJsaW5nIHRva2VuIHJlZ2lzdHJhdGlvbiBpbiBwcm9kdWN0aW9uLiBDb25maWd1cmUKbmF0aXZlIGNhcGFiaWxpdGllcywgRmlyZWJhc2UgbWVzc2FnaW5nIGFuZCB5b3VyIGFwcCdzIHBlcm1pc3Npb24gZXhwbGFuYXRpb24uCnt7L25vdGlmaWNhdGlvbnN9fQo=", + "type": "text" + }, + { + "path": "{{ name.snakeCase() }}/tool/check.dart", + "data": + "aW1wb3J0ICdkYXJ0OmlvJzsKaW1wb3J0ICdwYWNrYWdlOnBhdGgvcGF0aC5kYXJ0JyBhcyBwOwoKLy8vIFBvcnRhYmxlLCBub24tbXV0YXRpbmcgZm9ybWF0IGFuZCBhbmFseXplciBjaGVja3MgZnJvbSB0aGUgd29ya3NwYWNlIHJvb3QuCkZ1dHVyZTx2b2lkPiBtYWluKCkgYXN5bmMgewogIGZpbmFsIHNvdXJjZXMgPSA8U3RyaW5nPltdOwogIHZvaWQgY29sbGVjdChEaXJlY3RvcnkgZGlyZWN0b3J5KSB7CiAgICBpZiAoIWRpcmVjdG9yeS5leGlzdHNTeW5jKCkpIHsKICAgICAgcmV0dXJuOwogICAgfQogICAgZm9yIChmaW5hbCBlbnRyeSBpbiBkaXJlY3RvcnkubGlzdFN5bmMoZm9sbG93TGlua3M6IGZhbHNlKSkgewogICAgICBpZiAoZW50cnkgaXMgRGlyZWN0b3J5KSB7CiAgICAgICAgaWYgKCFbJ2J1aWxkJywgJy5kYXJ0X3Rvb2wnLCAnLnN5bWxpbmtzJ10KICAgICAgICAgICAgLmNvbnRhaW5zKHAuYmFzZW5hbWUoZW50cnkucGF0aCkpKSB7CiAgICAgICAgICBjb2xsZWN0KGVudHJ5KTsKICAgICAgICB9CiAgICAgIH0gZWxzZSBpZiAoZW50cnkgaXMgRmlsZSAmJgogICAgICAgICAgZW50cnkucGF0aC5lbmRzV2l0aCgnLmRhcnQnKSAmJgogICAgICAgICAgIVJlZ0V4cChyJ1wuKGd8ZnJlZXplZHxpNjluKVwuZGFydCQnKS5oYXNNYXRjaChlbnRyeS5wYXRoKSkgewogICAgICAgIHNvdXJjZXMuYWRkKGVudHJ5LnBhdGgpOwogICAgICB9CiAgICB9CiAgfQoKICBjb2xsZWN0KERpcmVjdG9yeSgndG9vbCcpKTsKICBmb3IgKGZpbmFsIGFyZWEgaW4gWydhcHBzJywgJ2ZlYXR1cmVzJywgJ3BhY2thZ2VzJywgJ3BsdWdpbnMnXSkgewogICAgZmluYWwgZGlyZWN0b3J5ID0gRGlyZWN0b3J5KGFyZWEpOwogICAgaWYgKCFkaXJlY3RvcnkuZXhpc3RzU3luYygpKSB7CiAgICAgIGNvbnRpbnVlOwogICAgfQogICAgZm9yIChmaW5hbCBwYWNrYWdlIGluIGRpcmVjdG9yeS5saXN0U3luYygpLndoZXJlVHlwZTxEaXJlY3Rvcnk+KCkpIHsKICAgICAgY29sbGVjdChEaXJlY3RvcnkocC5qb2luKHBhY2thZ2UucGF0aCwgJ2xpYicpKSk7CiAgICAgIGNvbGxlY3QoRGlyZWN0b3J5KHAuam9pbihwYWNrYWdlLnBhdGgsICd0ZXN0JykpKTsKICAgIH0KICB9CiAgc291cmNlcy5zb3J0KCk7CiAgZm9yIChmaW5hbCBhcmd1bWVudHMgaW4gWwogICAgWydmb3JtYXQnLCAnLS1vdXRwdXQ9bm9uZScsICctLXNldC1leGl0LWlmLWNoYW5nZWQnLCAuLi5zb3VyY2VzXSwKICAgIFsnYW5hbHl6ZScsICctLWZhdGFsLWluZm9zJywgJy4nXSwKICBdKSB7CiAgICBmaW5hbCBwcm9jZXNzID0gYXdhaXQgUHJvY2Vzcy5zdGFydCgnZGFydCcsIGFyZ3VtZW50cywKICAgICAgICBtb2RlOiBQcm9jZXNzU3RhcnRNb2RlLmluaGVyaXRTdGRpbyk7CiAgICBmaW5hbCByZXN1bHQgPSBhd2FpdCBwcm9jZXNzLmV4aXRDb2RlOwogICAgaWYgKHJlc3VsdCAhPSAwKSB7CiAgICAgIGV4aXRDb2RlID0gcmVzdWx0OwogICAgICByZXR1cm47CiAgICB9CiAgfQp9Cg==", + "type": "text" + }, + { + "path": "{{ name.snakeCase() }}/tool/coverage.dart", + "data": + "aW1wb3J0ICdkYXJ0OmlvJzsKaW1wb3J0ICdwYWNrYWdlOnBhdGgvcGF0aC5kYXJ0JyBhcyBwOwoKLy8vIFJ1biBmcm9tIHRoZSB3b3Jrc3BhY2Ugcm9vdDogZGFydCBydW4gdG9vbC9jb3ZlcmFnZS5kYXJ0IFstLXJlcG9ydC1vbmx5XS4KLy8vIE9ubHkgY29tcGlsZXItZ2VuZXJhdGVkIHNlcmlhbGl6ZXJzL3RyYW5zbGF0aW9ucyBhcmUgZXhjbHVkZWQuCkZ1dHVyZTx2b2lkPiBtYWluKExpc3Q8U3RyaW5nPiBhcmdzKSBhc3luYyB7CiAgZmluYWwgcm9vdCA9IERpcmVjdG9yeShEaXJlY3RvcnkuY3VycmVudC5yZXNvbHZlU3ltYm9saWNMaW5rc1N5bmMoKSk7CiAgZmluYWwgbWVyZ2VkID0gPFN0cmluZywgTWFwPGludCwgaW50Pj57fTsKICB2YXIgZmFpbGVkID0gZmFsc2U7CiAgZmluYWwgcmVwb3J0T25seSA9IGFyZ3MuY29udGFpbnMoJy0tcmVwb3J0LW9ubHknKTsKICBmaW5hbCBuYW1lcyA9IDxTdHJpbmc+W107CiAgZm9yIChmaW5hbCBhcmVhIGluIFsnYXBwcycsICdmZWF0dXJlcycsICdwYWNrYWdlcycsICdwbHVnaW5zJ10pIHsKICAgIGZpbmFsIGRpcmVjdG9yeSA9IERpcmVjdG9yeSgnJHtyb290LnBhdGh9LyRhcmVhJyk7CiAgICBpZiAoIWRpcmVjdG9yeS5leGlzdHNTeW5jKCkpIGNvbnRpbnVlOwogICAgZm9yIChmaW5hbCBwYWNrYWdlIGluIGRpcmVjdG9yeS5saXN0U3luYygpLndoZXJlVHlwZTxEaXJlY3Rvcnk+KCkpIHsKICAgICAgZmluYWwgbWFuaWZlc3QgPSBGaWxlKCcke3BhY2thZ2UucGF0aH0vcHVic3BlYy55YW1sJyk7CiAgICAgIGlmIChtYW5pZmVzdC5leGlzdHNTeW5jKCkpIHsKICAgICAgICBmaW5hbCBuYW1lID0gUmVnRXhwKAogICAgICAgICAgcidebmFtZTpccyooXFMrKScsCiAgICAgICAgICBtdWx0aUxpbmU6IHRydWUsCiAgICAgICAgKS5maXJzdE1hdGNoKG1hbmlmZXN0LnJlYWRBc1N0cmluZ1N5bmMoKSkhLmdyb3VwKDEpITsKICAgICAgICBuYW1lcy5hZGQoUmVnRXhwLmVzY2FwZShuYW1lKSk7CiAgICAgIH0KICAgIH0KICB9CiAgZmluYWwgY292ZXJhZ2VQYWNrYWdlcyA9ICdeKCR7bmFtZXMuam9pbignfCcpfSlcJCc7CiAgZm9yIChmaW5hbCBhcmVhIGluIFsnYXBwcycsICdmZWF0dXJlcycsICdwYWNrYWdlcycsICdwbHVnaW5zJ10pIHsKICAgIGZpbmFsIGRpcmVjdG9yeSA9IERpcmVjdG9yeSgnJHtyb290LnBhdGh9LyRhcmVhJyk7CiAgICBpZiAoIWRpcmVjdG9yeS5leGlzdHNTeW5jKCkpIGNvbnRpbnVlOwogICAgZmluYWwgcGFja2FnZXMgPSBkaXJlY3RvcnkubGlzdFN5bmMoKS53aGVyZVR5cGU8RGlyZWN0b3J5PigpLnRvTGlzdCgpCiAgICAgIC4uc29ydCgoYSwgYikgPT4gYS5wYXRoLmNvbXBhcmVUbyhiLnBhdGgpKTsKICAgIGZvciAoZmluYWwgcGFja2FnZSBpbiBwYWNrYWdlcykgewogICAgICBmaW5hbCBtYW5pZmVzdCA9IEZpbGUoJyR7cGFja2FnZS5wYXRofS9wdWJzcGVjLnlhbWwnKTsKICAgICAgaWYgKCFtYW5pZmVzdC5leGlzdHNTeW5jKCkpIGNvbnRpbnVlOwogICAgICBmaW5hbCBuYW1lID0gUmVnRXhwKAogICAgICAgIHInXm5hbWU6XHMqKFxTKyknLAogICAgICAgIG11bHRpTGluZTogdHJ1ZSwKICAgICAgKS5maXJzdE1hdGNoKG1hbmlmZXN0LnJlYWRBc1N0cmluZ1N5bmMoKSkhLmdyb3VwKDEpITsKICAgICAgZmluYWwgdGVzdERpcmVjdG9yeSA9IERpcmVjdG9yeSgnJHtwYWNrYWdlLnBhdGh9L3Rlc3QnKTsKICAgICAgaWYgKCF0ZXN0RGlyZWN0b3J5LmV4aXN0c1N5bmMoKSB8fAogICAgICAgICAgIXRlc3REaXJlY3RvcnkKICAgICAgICAgICAgICAubGlzdFN5bmMocmVjdXJzaXZlOiB0cnVlKQogICAgICAgICAgICAgIC53aGVyZVR5cGU8RmlsZT4oKQogICAgICAgICAgICAgIC5hbnkoKGYpID0+IGYucGF0aC5lbmRzV2l0aCgnX3Rlc3QuZGFydCcpKSkgewogICAgICAgIHN0ZGVyci53cml0ZWxuKCckYXJlYS8kbmFtZTogbWlzc2luZyB0ZXN0cycpOwogICAgICAgIGZhaWxlZCA9IHRydWU7CiAgICAgICAgY29udGludWU7CiAgICAgIH0KICAgICAgZmluYWwgcmVwb3J0ID0gRmlsZSgnJHtwYWNrYWdlLnBhdGh9L2NvdmVyYWdlL2xjb3YuaW5mbycpOwogICAgICBpZiAoIXJlcG9ydE9ubHkpIHsKICAgICAgICBmaW5hbCBpbXBvcnRzID0gRmlsZSgKICAgICAgICAgICcke3Rlc3REaXJlY3RvcnkucGF0aH0vY292ZXJhZ2VfaW1wb3J0c190ZXN0LmRhcnQnLAogICAgICAgICk7CiAgICAgICAgaWYgKGltcG9ydHMuZXhpc3RzU3luYygpKSB7CiAgICAgICAgICB0aHJvdyBTdGF0ZUVycm9yKCdSZWZ1c2luZyB0byBvdmVyd3JpdGUgJHtpbXBvcnRzLnBhdGh9Jyk7CiAgICAgICAgfQogICAgICAgIGZpbmFsIHNvdXJjZXMgPSBEaXJlY3RvcnkoJyR7cGFja2FnZS5wYXRofS9saWInKQogICAgICAgICAgICAubGlzdFN5bmMocmVjdXJzaXZlOiB0cnVlKQogICAgICAgICAgICAud2hlcmVUeXBlPEZpbGU+KCkKICAgICAgICAgICAgLndoZXJlKChmKSA9PiBmLnBhdGguZW5kc1dpdGgoJy5kYXJ0JykpCiAgICAgICAgICAgIC53aGVyZSgKICAgICAgICAgICAgICAoZikgPT4gIVJlZ0V4cChyJ1wuKGd8ZnJlZXplZHxpNjluKVwuZGFydCQnKS5oYXNNYXRjaChmLnBhdGgpLAogICAgICAgICAgICApCiAgICAgICAgICAgIC53aGVyZSgKICAgICAgICAgICAgICAoZikgPT4gIVJlZ0V4cCgKICAgICAgICAgICAgICAgIHInXnBhcnQgb2YgJywKICAgICAgICAgICAgICAgIG11bHRpTGluZTogdHJ1ZSwKICAgICAgICAgICAgICApLmhhc01hdGNoKGYucmVhZEFzU3RyaW5nU3luYygpKSwKICAgICAgICAgICAgKQogICAgICAgICAgICAudG9MaXN0KCkKICAgICAgICAgIC4uc29ydCgoYSwgYikgPT4gYS5wYXRoLmNvbXBhcmVUbyhiLnBhdGgpKTsKICAgICAgICBpbXBvcnRzLndyaXRlQXNTdHJpbmdTeW5jKAogICAgICAgICAgWwogICAgICAgICAgICAnLy8gR2VuZXJhdGVkIHRlbXBvcmFyaWx5IGJ5IHRvb2wvY292ZXJhZ2UuZGFydC4nLAogICAgICAgICAgICAnLy8gaWdub3JlX2Zvcl9maWxlOiB1bnVzZWRfaW1wb3J0JywKICAgICAgICAgICAgZm9yIChmaW5hbCBzb3VyY2UgaW4gc291cmNlcykKICAgICAgICAgICAgICAiaW1wb3J0ICdwYWNrYWdlOiRuYW1lLyR7cC5yZWxhdGl2ZShzb3VyY2UucGF0aCwgZnJvbTogcC5qb2luKHBhY2thZ2UucGF0aCwgJ2xpYicpKS5yZXBsYWNlQWxsKHInXCcsICcvJyl9JzsiLAogICAgICAgICAgICAndm9pZCBtYWluKCkge30nLAogICAgICAgICAgXS5qb2luKCdcbicpLAogICAgICAgICk7CiAgICAgICAgdHJ5IHsKICAgICAgICAgIGlmIChyZXBvcnQuZXhpc3RzU3luYygpKSByZXBvcnQuZGVsZXRlU3luYygpOwogICAgICAgICAgZmluYWwgcHJvY2VzcyA9IGF3YWl0IFByb2Nlc3Muc3RhcnQoCiAgICAgICAgICAgICdmbHV0dGVyJywKICAgICAgICAgICAgWyd0ZXN0JywgJy0tY292ZXJhZ2UnLCAnLS1jb3ZlcmFnZS1wYWNrYWdlPSRjb3ZlcmFnZVBhY2thZ2VzJ10sCiAgICAgICAgICAgIHdvcmtpbmdEaXJlY3Rvcnk6IHBhY2thZ2UucGF0aCwKICAgICAgICAgICAgbW9kZTogUHJvY2Vzc1N0YXJ0TW9kZS5pbmhlcml0U3RkaW8sCiAgICAgICAgICApOwogICAgICAgICAgaWYgKGF3YWl0IHByb2Nlc3MuZXhpdENvZGUgIT0gMCkgZmFpbGVkID0gdHJ1ZTsKICAgICAgICB9IGZpbmFsbHkgewogICAgICAgICAgaW1wb3J0cy5kZWxldGVTeW5jKCk7CiAgICAgICAgfQogICAgICB9CiAgICAgIGlmICghcmVwb3J0LmV4aXN0c1N5bmMoKSkgewogICAgICAgIHN0ZGVyci53cml0ZWxuKCckYXJlYS8kbmFtZTogbWlzc2luZyBjb3ZlcmFnZSByZXBvcnQnKTsKICAgICAgICBmYWlsZWQgPSB0cnVlOwogICAgICAgIGNvbnRpbnVlOwogICAgICB9CiAgICAgIFN0cmluZz8gc291cmNlOwogICAgICBmb3IgKGZpbmFsIGxpbmUgaW4gcmVwb3J0LnJlYWRBc0xpbmVzU3luYygpKSB7CiAgICAgICAgaWYgKGxpbmUuc3RhcnRzV2l0aCgnU0Y6JykpIHsKICAgICAgICAgIGZpbmFsIHBhdGggPSBsaW5lLnN1YnN0cmluZygzKTsKICAgICAgICAgIHZhciBhYnNvbHV0ZSA9IHAubm9ybWFsaXplKAogICAgICAgICAgICAgIHAuaXNBYnNvbHV0ZShwYXRoKSA/IHBhdGggOiBwLmpvaW4ocGFja2FnZS5wYXRoLCBwYXRoKSk7CiAgICAgICAgICAvLyBWTSByZXBvcnRzIG1heSB1c2UgL3ZhciB3aGlsZSB0aGUgd29ya3NwYWNlIHJlc29sdmVzIHRvIC9wcml2YXRlL3ZhcgogICAgICAgICAgLy8gb24gbWFjT1MgKG9yIGFub3RoZXIgc3ltbGluayBvbiBMaW51eCkuIE1lcmdlIHRoZSBzYW1lIHJlYWwgc291cmNlLgogICAgICAgICAgZmluYWwgc291cmNlRmlsZSA9IEZpbGUoYWJzb2x1dGUpOwogICAgICAgICAgaWYgKHNvdXJjZUZpbGUuZXhpc3RzU3luYygpKSB7CiAgICAgICAgICAgIGFic29sdXRlID0gc291cmNlRmlsZS5yZXNvbHZlU3ltYm9saWNMaW5rc1N5bmMoKTsKICAgICAgICAgIH0KICAgICAgICAgIHNvdXJjZSA9IHAuaXNXaXRoaW4ocm9vdC5wYXRoLCBhYnNvbHV0ZSkKICAgICAgICAgICAgICA/IHAucmVsYXRpdmUoYWJzb2x1dGUsIGZyb206IHJvb3QucGF0aCkucmVwbGFjZUFsbChyJ1wnLCAnLycpCiAgICAgICAgICAgICAgOiBudWxsOwogICAgICAgICAgaWYgKHNvdXJjZSAhPSBudWxsICYmCiAgICAgICAgICAgICAgIVJlZ0V4cChyJ14oYXBwc3xmZWF0dXJlc3xwYWNrYWdlc3xwbHVnaW5zKS9bXi9dKy9saWIvJykKICAgICAgICAgICAgICAgICAgLmhhc01hdGNoKHNvdXJjZSkpIHsKICAgICAgICAgICAgc291cmNlID0gbnVsbDsKICAgICAgICAgIH0KICAgICAgICAgIGlmIChzb3VyY2UgIT0gbnVsbCAmJgogICAgICAgICAgICAgIFJlZ0V4cChyJ1wuKGd8ZnJlZXplZHxpNjluKVwuZGFydCQnKS5oYXNNYXRjaChzb3VyY2UpKSB7CiAgICAgICAgICAgIHNvdXJjZSA9IG51bGw7CiAgICAgICAgICB9CiAgICAgICAgfSBlbHNlIGlmIChsaW5lLnN0YXJ0c1dpdGgoJ0RBOicpICYmIHNvdXJjZSAhPSBudWxsKSB7CiAgICAgICAgICBmaW5hbCBmaWVsZHMgPSBsaW5lLnN1YnN0cmluZygzKS5zcGxpdCgnLCcpOwogICAgICAgICAgZmluYWwgbnVtYmVyID0gaW50LnBhcnNlKGZpZWxkc1swXSk7CiAgICAgICAgICBmaW5hbCBoaXRzID0gaW50LnBhcnNlKGZpZWxkc1sxXSk7CiAgICAgICAgICBmaW5hbCBsaW5lcyA9IG1lcmdlZC5wdXRJZkFic2VudChzb3VyY2UsICgpID0+IHt9KTsKICAgICAgICAgIGxpbmVzW251bWJlcl0gPSAobGluZXNbbnVtYmVyXSA/PyAwKSArIGhpdHM7CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgfQogIHZhciBjb3ZlcmVkID0gMDsKICB2YXIgdG90YWwgPSAwOwogIGZpbmFsIG91dHB1dCA9IFN0cmluZ0J1ZmZlcigpOwogIGZvciAoZmluYWwgc291cmNlIGluIG1lcmdlZC5rZXlzLnRvTGlzdCgpLi5zb3J0KCkpIHsKICAgIGZpbmFsIGxpbmVzID0gbWVyZ2VkW3NvdXJjZV0hOwogICAgZmluYWwgbWlzc2luZyA9IGxpbmVzLmVudHJpZXMKICAgICAgICAud2hlcmUoKGUpID0+IGUudmFsdWUgPT0gMCkKICAgICAgICAubWFwKChlKSA9PiBlLmtleSkKICAgICAgICAudG9MaXN0KCkKICAgICAgLi5zb3J0KCk7CiAgICBjb3ZlcmVkICs9IGxpbmVzLmxlbmd0aCAtIG1pc3NpbmcubGVuZ3RoOwogICAgdG90YWwgKz0gbGluZXMubGVuZ3RoOwogICAgb3V0cHV0LndyaXRlbG4oJ1NGOiRzb3VyY2UnKTsKICAgIGZvciAoZmluYWwgbGluZSBpbiBsaW5lcy5rZXlzLnRvTGlzdCgpLi5zb3J0KCkpIHsKICAgICAgb3V0cHV0LndyaXRlbG4oJ0RBOiRsaW5lLCR7bGluZXNbbGluZV19Jyk7CiAgICB9CiAgICBvdXRwdXQud3JpdGVsbignTEY6JHtsaW5lcy5sZW5ndGh9Jyk7CiAgICBvdXRwdXQud3JpdGVsbignTEg6JHtsaW5lcy5sZW5ndGggLSBtaXNzaW5nLmxlbmd0aH0nKTsKICAgIG91dHB1dC53cml0ZWxuKCdlbmRfb2ZfcmVjb3JkJyk7CiAgICBpZiAobWlzc2luZy5pc05vdEVtcHR5KSB7CiAgICAgIHN0ZG91dC53cml0ZWxuKCckc291cmNlOiB1bmNvdmVyZWQgbGluZXMgJHttaXNzaW5nLmpvaW4oIiwgIil9Jyk7CiAgICB9CiAgfQogIERpcmVjdG9yeSgnY292ZXJhZ2UnKS5jcmVhdGVTeW5jKHJlY3Vyc2l2ZTogdHJ1ZSk7CiAgRmlsZSgnY292ZXJhZ2UvbGNvdi5pbmZvJykud3JpdGVBc1N0cmluZ1N5bmMob3V0cHV0LnRvU3RyaW5nKCkpOwogIHN0ZG91dC53cml0ZWxuKAogICAgJ0NvdmVyYWdlOiAkY292ZXJlZC8kdG90YWwgZXhlY3V0YWJsZSBsaW5lcyAnCiAgICAnKCR7dG90YWwgPT0gMCA/ICIwLjAwIiA6ICgxMDAgKiBjb3ZlcmVkIC8gdG90YWwpLnRvU3RyaW5nQXNGaXhlZCgyKX0lKScsCiAgKTsKICBpZiAoZmFpbGVkIHx8IHRvdGFsID09IDAgfHwgY292ZXJlZCAhPSB0b3RhbCkgZXhpdENvZGUgPSAxOwp9Cg==", "type": "text" } ], @@ -1426,19 +1637,19 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ { "path": "commands/melos_command.dart", "data": - "aW1wb3J0ICdwYWNrYWdlOmNsaV9jb3JlL2NsaV9jb3JlLmRhcnQnIHNob3cgQ2xpQ29tbWFuZDsKaW1wb3J0ICdwYWNrYWdlOm1hc29uL21hc29uLmRhcnQnOwoKaW1wb3J0ICdjaGVja2VkX3Byb2Nlc3MuZGFydCc7CgpmaW5hbCBjbGFzcyBNZWxvc0NvbW1hbmQgZXh0ZW5kcyBDbGlDb21tYW5kIHsKICBAb3ZlcnJpZGUKICBGdXR1cmU8dm9pZD4gcnVuKEhvb2tDb250ZXh0IGNvbnRleHQpIGFzeW5jIHsKICAgIGZpbmFsIFN0cmluZyBuYW1lID0gY29udGV4dC52YXJzWyduYW1lJ107CiAgICBmaW5hbCBhcHBOYW1lID0gbmFtZS5zbmFrZUNhc2U7CgogICAgYXdhaXQgcnVuQ2hlY2tlZCgKICAgICAgY29udGV4dCwKICAgICAgc3RhcnRNZXNzYWdlOiAnQWN0aXZhdGluZyBNZWxvcyBnbG9iYWxseScsCiAgICAgIGVuZE1lc3NhZ2U6ICdNZWxvcyBhY3RpdmF0ZWQgZ2xvYmFsbHknLAogICAgICBleGVjdXRhYmxlOiAnZGFydCcsCiAgICAgIGFyZ3VtZW50czogWydwdWInLCAnZ2xvYmFsJywgJ2FjdGl2YXRlJywgJ21lbG9zJ10sCiAgICApOwoKICAgIGF3YWl0IHJ1bkNoZWNrZWQoCiAgICAgIGNvbnRleHQsCiAgICAgIHN0YXJ0TWVzc2FnZTogJ1J1bm5pbmcgbWVsb3MgYm9vdHN0cmFwJywKICAgICAgZW5kTWVzc2FnZTogJ0RlcGVuZGVuY2llcyBpbnN0YWxsZWQnLAogICAgICBleGVjdXRhYmxlOiAnbWVsb3MnLAogICAgICBhcmd1bWVudHM6IFsnYm9vdHN0cmFwJ10sCiAgICAgIHdvcmtpbmdEaXJlY3Rvcnk6IGFwcE5hbWUsCiAgICApOwogIH0KfQo=", + "aW1wb3J0ICdwYWNrYWdlOmNsaV9jb3JlL2NsaV9jb3JlLmRhcnQnIHNob3cgQ2xpQ29tbWFuZDsKaW1wb3J0ICdwYWNrYWdlOm1hc29uL21hc29uLmRhcnQnOwoKaW1wb3J0ICdjaGVja2VkX3Byb2Nlc3MuZGFydCc7CgpmaW5hbCBjbGFzcyBNZWxvc0NvbW1hbmQgZXh0ZW5kcyBDbGlDb21tYW5kIHsKICBAb3ZlcnJpZGUKICBGdXR1cmU8dm9pZD4gcnVuKEhvb2tDb250ZXh0IGNvbnRleHQpIGFzeW5jIHsKICAgIGZpbmFsIFN0cmluZyBuYW1lID0gY29udGV4dC52YXJzWyduYW1lJ107CiAgICBmaW5hbCBhcHBOYW1lID0gbmFtZS5zbmFrZUNhc2U7CgogICAgYXdhaXQgcnVuQ2hlY2tlZCgKICAgICAgY29udGV4dCwKICAgICAgc3RhcnRNZXNzYWdlOiAnSW5zdGFsbGluZyB3b3Jrc3BhY2UgdG9vbGluZycsCiAgICAgIGVuZE1lc3NhZ2U6ICdXb3Jrc3BhY2UgdG9vbGluZyBpbnN0YWxsZWQnLAogICAgICBleGVjdXRhYmxlOiAnZGFydCcsCiAgICAgIGFyZ3VtZW50czogWydwdWInLCAnZ2V0J10sCiAgICAgIHdvcmtpbmdEaXJlY3Rvcnk6IGFwcE5hbWUsCiAgICApOwoKICAgIGF3YWl0IHJ1bkNoZWNrZWQoCiAgICAgIGNvbnRleHQsCiAgICAgIHN0YXJ0TWVzc2FnZTogJ1J1bm5pbmcgbWVsb3MgYm9vdHN0cmFwJywKICAgICAgZW5kTWVzc2FnZTogJ0RlcGVuZGVuY2llcyBpbnN0YWxsZWQnLAogICAgICBleGVjdXRhYmxlOiAnZGFydCcsCiAgICAgIGFyZ3VtZW50czogWydydW4nLCAnbWVsb3MnLCAnYm9vdHN0cmFwJ10sCiAgICAgIHdvcmtpbmdEaXJlY3Rvcnk6IGFwcE5hbWUsCiAgICApOwogIH0KfQo=", "type": "text" }, { "path": "commands/module_vars.dart", "data": - "aW1wb3J0ICdwYWNrYWdlOm1hc29uL21hc29uLmRhcnQnOwoKLy8vIE9wdGlvbmFsIG1vZHVsZXMsIGVhY2ggb2Ygd2hpY2ggbWFwcyB0byBhIGRpcmVjdG9yeSBpbiB0aGUgYnJpY2suCi8vLwovLy8gQSBkaXJlY3RvcnkgbmFtZWQgYHt7PG1vZHVsZT5fZGlyfX1gIHJlbmRlcnMgdG8gYW4gZW1wdHkgcGF0aCBzZWdtZW50IHdoZW4KLy8vIHRoZSBtb2R1bGUgaXMgb2ZmLCBhbmQgbWFzb24gc2tpcHMgZXZlcnkgZmlsZSB1bmRlcm5lYXRoIGl0Lgpjb25zdCBvcHRpb25hbE1vZHVsZXMgPSA8U3RyaW5nPlsKICAnbmV0d29yaycsCiAgJ25vdGlmaWNhdGlvbnMnLAogICdhbmFseXRpY3MnLAogICdjcmFzaGx5dGljcycsCiAgJ2ZlYXR1cmVfZmxhZ3MnLAogICdkZXZlbG9wZXInLAogICdhdXRoJywKICAnZGFzaGJvYXJkJywKXTsKCi8vLyBNb2R1bGVzIHRoYXQgY2Fubm90IHdvcmsgd2l0aG91dCBgRmlyZWJhc2UuaW5pdGlhbGl6ZUFwcGAuCmNvbnN0IF9maXJlYmFzZUJhY2tlZE1vZHVsZXMgPSA8U3RyaW5nPlsKICAnbm90aWZpY2F0aW9ucycsCiAgJ2FuYWx5dGljcycsCiAgJ2NyYXNobHl0aWNzJywKICAnZmVhdHVyZV9mbGFncycsCiAgJ2F1dGgnLAogICdmaXJlc3RvcmUnLApdOwoKYm9vbCBfZmxhZyhIb29rQ29udGV4dCBjb250ZXh0LCBTdHJpbmcga2V5KSA9PiBjb250ZXh0LnZhcnNba2V5XSA9PSB0cnVlOwoKLy8vIE5vcm1hbGlzZXMgdGhlIG1vZHVsZSBhbnN3ZXJzIGFuZCBkZXJpdmVzIGV2ZXJ5dGhpbmcgdGhlIHRlbXBsYXRlcyByZWFkLgp2b2lkIHJlc29sdmVNb2R1bGVWYXJzKEhvb2tDb250ZXh0IGNvbnRleHQpIHsKICAvLyBBIG1vZHVsZSBjYW4gYmUgaW1wbGllZCBieSBhbm90aGVyIChkZXYgdG9vbHMgcmVhZCBmZWF0dXJlIGZsYWdzKSwgc28KICAvLyByZXNvbHZlIGltcGxpY2F0aW9ucyBiZWZvcmUgZGVyaXZpbmcgYW55dGhpbmcgZnJvbSB0aGVtLiBgbm9uc3RvcCBjcmVhdGVgCiAgLy8gYWxyZWFkeSBkb2VzIHRoaXMgaW4gbGliL2NvbW1hbmRzL2NyZWF0ZS9tb2R1bGVzLmRhcnQ7IGl0IGlzIHJlcGVhdGVkIGhlcmUKICAvLyBzbyBgbWFzb24gbWFrZWAgb24gaXRzIG93biBzdGlsbCBwcm9kdWNlcyBhIHByb2plY3QgdGhhdCBjb21waWxlcy4KICBpZiAoX2ZsYWcoY29udGV4dCwgJ2RldmVsb3BlcicpKSBjb250ZXh0LnZhcnNbJ2ZlYXR1cmVfZmxhZ3MnXSA9IHRydWU7CiAgaWYgKF9mbGFnKGNvbnRleHQsICdub3RpZmljYXRpb25zJykpIGNvbnRleHQudmFyc1snbmV0d29yayddID0gdHJ1ZTsKCiAgZm9yIChmaW5hbCBtb2R1bGUgaW4gb3B0aW9uYWxNb2R1bGVzKSB7CiAgICBmaW5hbCBlbmFibGVkID0gX2ZsYWcoY29udGV4dCwgbW9kdWxlKTsKICAgIGNvbnRleHQudmFyc1ttb2R1bGVdID0gZW5hYmxlZDsKICAgIGNvbnRleHQudmFyc1snJHttb2R1bGV9X2RpciddID0gZW5hYmxlZCA/IG1vZHVsZSA6ICcnOwogIH0KCiAgY29udGV4dC52YXJzWydmaXJlc3RvcmUnXSA9IF9mbGFnKGNvbnRleHQsICdmaXJlc3RvcmUnKTsKICBmaW5hbCB1c2VzRmlyZWJhc2UgPQogICAgICBfZmlyZWJhc2VCYWNrZWRNb2R1bGVzLmFueSgobW9kdWxlKSA9PiBfZmxhZyhjb250ZXh0LCBtb2R1bGUpKTsKICBjb250ZXh0LnZhcnNbJ2ZpcmViYXNlJ10gPSB1c2VzRmlyZWJhc2U7CiAgLy8gRW1wdHkgcGF0aCBzZWdtZW50IOKGkiBtYXNvbiBza2lwcyB0aGUgZmlsZSwgc28gYSBwcm9qZWN0IHdpdGggbm8gRmlyZWJhc2UKICAvLyBtb2R1bGVzIG5ldmVyIHNoaXBzIGEgcGxhY2Vob2xkZXIgYGZpcmViYXNlX29wdGlvbnMuZGFydGAuCiAgY29udGV4dC52YXJzWydmaXJlYmFzZV9vcHRpb25zX2ZpbGUnXSA9CiAgICAgIHVzZXNGaXJlYmFzZSA/ICdmaXJlYmFzZV9vcHRpb25zLmRhcnQnIDogJyc7CgogIC8vIFRoZSBib290IHRlc3QgcnVucyB0aGUgcmVhbCBib290c3RyYXAuIEZpcmViYXNlIHByb2plY3RzIGNhbiBib290IGJlZm9yZQogIC8vIGBmbHV0dGVyZmlyZSBjb25maWd1cmVgIG5vdyAodGhvc2UgbW9kdWxlcyBhcmUgc2tpcHBlZCksIGJ1dCBhZnRlcgogIC8vIGNvbmZpZ3VyZSB0aGUgc3BsYXNoIG1heSBsYW5kIG9uIHNpZ24taW4gaW5zdGVhZCBvZiB0aGUgZGFzaGJvYXJkLCBzbwogIC8vIHRoZXkgc3RpbGwgZG9uJ3Qgc2hpcCB0aGlzIGZpbGUuCiAgY29udGV4dC52YXJzWydzbW9rZV90ZXN0X2ZpbGUnXSA9IHVzZXNGaXJlYmFzZSA/ICcnIDogJ3Ntb2tlX3Rlc3QuZGFydCc7Cn0K", + "aW1wb3J0ICdwYWNrYWdlOm1hc29uL21hc29uLmRhcnQnOwoKLy8vIE9wdGlvbmFsIG1vZHVsZXMsIGVhY2ggb2Ygd2hpY2ggbWFwcyB0byBhIGRpcmVjdG9yeSBpbiB0aGUgYnJpY2suCi8vLwovLy8gQSBkaXJlY3RvcnkgbmFtZWQgYHt7PG1vZHVsZT5fZGlyfX1gIHJlbmRlcnMgdG8gYW4gZW1wdHkgcGF0aCBzZWdtZW50IHdoZW4KLy8vIHRoZSBtb2R1bGUgaXMgb2ZmLCBhbmQgbWFzb24gc2tpcHMgZXZlcnkgZmlsZSB1bmRlcm5lYXRoIGl0Lgpjb25zdCBvcHRpb25hbE1vZHVsZXMgPSA8U3RyaW5nPlsKICAnbmV0d29yaycsCiAgJ25vdGlmaWNhdGlvbnMnLAogICdhbmFseXRpY3MnLAogICdjcmFzaGx5dGljcycsCiAgJ2ZlYXR1cmVfZmxhZ3MnLAogICdkZXZlbG9wZXInLAogICdhdXRoJywKICAnZGFzaGJvYXJkJywKXTsKCi8vLyBNb2R1bGVzIHRoYXQgY2Fubm90IHdvcmsgd2l0aG91dCBgRmlyZWJhc2UuaW5pdGlhbGl6ZUFwcGAuCmNvbnN0IF9maXJlYmFzZUJhY2tlZE1vZHVsZXMgPSA8U3RyaW5nPlsKICAnbm90aWZpY2F0aW9ucycsCiAgJ2FuYWx5dGljcycsCiAgJ2NyYXNobHl0aWNzJywKICAnZmVhdHVyZV9mbGFncycsCiAgJ2F1dGgnLAogICdmaXJlc3RvcmUnLApdOwoKYm9vbCBfZmxhZyhIb29rQ29udGV4dCBjb250ZXh0LCBTdHJpbmcga2V5KSA9PiBjb250ZXh0LnZhcnNba2V5XSA9PSB0cnVlOwoKLy8vIE5vcm1hbGlzZXMgdGhlIG1vZHVsZSBhbnN3ZXJzIGFuZCBkZXJpdmVzIGV2ZXJ5dGhpbmcgdGhlIHRlbXBsYXRlcyByZWFkLgp2b2lkIHJlc29sdmVNb2R1bGVWYXJzKEhvb2tDb250ZXh0IGNvbnRleHQpIHsKICAvLyBBIG1vZHVsZSBjYW4gYmUgaW1wbGllZCBieSBhbm90aGVyIChkZXYgdG9vbHMgcmVhZCBmZWF0dXJlIGZsYWdzKSwgc28KICAvLyByZXNvbHZlIGltcGxpY2F0aW9ucyBiZWZvcmUgZGVyaXZpbmcgYW55dGhpbmcgZnJvbSB0aGVtLiBgbm9uc3RvcCBjcmVhdGVgCiAgLy8gYWxyZWFkeSBkb2VzIHRoaXMgaW4gbGliL2NvbW1hbmRzL2NyZWF0ZS9tb2R1bGVzLmRhcnQ7IGl0IGlzIHJlcGVhdGVkIGhlcmUKICAvLyBzbyBgbWFzb24gbWFrZWAgb24gaXRzIG93biBzdGlsbCBwcm9kdWNlcyBhIHByb2plY3QgdGhhdCBjb21waWxlcy4KICBpZiAoX2ZsYWcoY29udGV4dCwgJ2RldmVsb3BlcicpKSBjb250ZXh0LnZhcnNbJ2ZlYXR1cmVfZmxhZ3MnXSA9IHRydWU7CiAgaWYgKF9mbGFnKGNvbnRleHQsICdub3RpZmljYXRpb25zJykpIGNvbnRleHQudmFyc1snbmV0d29yayddID0gdHJ1ZTsKCiAgZm9yIChmaW5hbCBtb2R1bGUgaW4gb3B0aW9uYWxNb2R1bGVzKSB7CiAgICBmaW5hbCBlbmFibGVkID0gX2ZsYWcoY29udGV4dCwgbW9kdWxlKTsKICAgIGNvbnRleHQudmFyc1ttb2R1bGVdID0gZW5hYmxlZDsKICAgIGNvbnRleHQudmFyc1snJHttb2R1bGV9X2RpciddID0gZW5hYmxlZCA/IG1vZHVsZSA6ICcnOwogIH0KCiAgY29udGV4dC52YXJzWydmaXJlc3RvcmUnXSA9IF9mbGFnKGNvbnRleHQsICdmaXJlc3RvcmUnKTsKICBmaW5hbCB1c2VzRmlyZWJhc2UgPQogICAgICBfZmlyZWJhc2VCYWNrZWRNb2R1bGVzLmFueSgobW9kdWxlKSA9PiBfZmxhZyhjb250ZXh0LCBtb2R1bGUpKTsKICBjb250ZXh0LnZhcnNbJ2ZpcmViYXNlJ10gPSB1c2VzRmlyZWJhc2U7CiAgY29udGV4dC52YXJzWydlbXVsYXRvcnMnXSA9CiAgICAgIF9mbGFnKGNvbnRleHQsICdhdXRoJykgfHwgX2ZsYWcoY29udGV4dCwgJ2ZpcmVzdG9yZScpOwogIGNvbnRleHQudmFyc1snZmlyZWJhc2Vfc2RrX21vY2tzJ10gPSBfZmlyZWJhc2VCYWNrZWRNb2R1bGVzCiAgICAgIC53aGVyZSgobW9kdWxlKSA9PiBtb2R1bGUgIT0gJ2ZpcmVzdG9yZScpCiAgICAgIC5hbnkoKG1vZHVsZSkgPT4gX2ZsYWcoY29udGV4dCwgbW9kdWxlKSk7CiAgLy8gRW1wdHkgcGF0aCBzZWdtZW50IOKGkiBtYXNvbiBza2lwcyB0aGUgZmlsZSwgc28gYSBwcm9qZWN0IHdpdGggbm8gRmlyZWJhc2UKICAvLyBtb2R1bGVzIG5ldmVyIHNoaXBzIGEgcGxhY2Vob2xkZXIgYGZpcmViYXNlX29wdGlvbnMuZGFydGAuCiAgY29udGV4dC52YXJzWydmaXJlYmFzZV9vcHRpb25zX2ZpbGUnXSA9CiAgICAgIHVzZXNGaXJlYmFzZSA/ICdmaXJlYmFzZV9vcHRpb25zLmRhcnQnIDogJyc7CgogIC8vIEV2ZXJ5IHByb2plY3Qgc2hpcHMgYW4gZW50cnlwb2ludCBzbW9rZSB0ZXN0LiBTREstc3BlY2lmaWMgc3VpdGVzIGFuZAogIC8vIGxpZmVjeWNsZSBhZGFwdGVycyBhcmUgb21pdHRlZCBvbmx5IHdoZW4gdGhlaXIgbW9kdWxlIGlzIGFic2VudC4KICBjb250ZXh0LnZhcnNbJ25vdGlmaWNhdGlvbl9saWZlY3ljbGVfZmlsZSddID0KICAgICAgX2ZsYWcoY29udGV4dCwgJ25vdGlmaWNhdGlvbnMnKSA/ICdub3RpZmljYXRpb25fbGlmZWN5Y2xlLmRhcnQnIDogJyc7CiAgY29udGV4dC52YXJzWydub3RpZmljYXRpb25fbGlmZWN5Y2xlX3Rlc3RfZmlsZSddID0KICAgICAgX2ZsYWcoY29udGV4dCwgJ25vdGlmaWNhdGlvbnMnKSA/ICdub3RpZmljYXRpb25fbGlmZWN5Y2xlX3Rlc3QuZGFydCcgOiAnJzsKICBjb250ZXh0LnZhcnNbJ2ZpcmViYXNlX2Jvb3RzdHJhcF90ZXN0X2ZpbGUnXSA9CiAgICAgIHVzZXNGaXJlYmFzZSA/ICdmaXJlYmFzZV9ib290c3RyYXBfdGVzdC5kYXJ0JyA6ICcnOwogIGNvbnRleHQudmFyc1snYXV0aF90b2tlbl9wcm92aWRlcl90ZXN0X2ZpbGUnXSA9CiAgICAgIF9mbGFnKGNvbnRleHQsICduZXR3b3JrJykgPyAndG9rZW5fcHJvdmlkZXJfdGVzdC5kYXJ0JyA6ICcnOwp9Cg==", "type": "text" }, { "path": "commands/next_steps_command.dart", "data": - "aW1wb3J0ICdwYWNrYWdlOmNsaV9jb3JlL2NsaV9jb3JlLmRhcnQnIHNob3cgQ2xpQ29tbWFuZDsKaW1wb3J0ICdwYWNrYWdlOm1hc29uL21hc29uLmRhcnQnOwoKLy8vIFByaW50cyB0aGUgaGFuZGZ1bCBvZiB0aGluZ3MgdGhlIGdlbmVyYXRvciBjYW5ub3QgZG8gZm9yIHlvdS4KZmluYWwgY2xhc3MgTmV4dFN0ZXBzQ29tbWFuZCBleHRlbmRzIENsaUNvbW1hbmQgewogIEBvdmVycmlkZQogIEZ1dHVyZTx2b2lkPiBydW4oSG9va0NvbnRleHQgY29udGV4dCkgYXN5bmMgewogICAgZmluYWwgU3RyaW5nIG5hbWUgPSBjb250ZXh0LnZhcnNbJ25hbWUnXTsKICAgIGZpbmFsIGFwcE5hbWUgPSBuYW1lLnNuYWtlQ2FzZTsKICAgIGZpbmFsIGxvZ2dlciA9IGNvbnRleHQubG9nZ2VyOwoKICAgIGlmIChjb250ZXh0LnZhcnNbJ2ZpcmViYXNlJ10gPT0gdHJ1ZSkgewogICAgICBsb2dnZXIKICAgICAgICAuLmluZm8oJycpCiAgICAgICAgLi53YXJuKCdGaXJlYmFzZSBtb2R1bGVzIGFyZSBlbmFibGVkIGJ1dCBub3QgY29uZmlndXJlZCB5ZXQuJykKICAgICAgICAuLmluZm8oJyAgZGFydCBwdWIgZ2xvYmFsIGFjdGl2YXRlIGZsdXR0ZXJmaXJlX2NsaScpCiAgICAgICAgLi5pbmZvKCcgIGNkICRhcHBOYW1lL2FwcHMvJGFwcE5hbWUgJiYgZmx1dHRlcmZpcmUgY29uZmlndXJlJykKICAgICAgICAuLmluZm8oCiAgICAgICAgICAnICAodGhlIGFwcCBzdGlsbCBydW5zOyBGaXJlYmFzZSBmZWF0dXJlcyBzdGF5IG9mZiB1bnRpbCB0aGVuKScsCiAgICAgICAgKTsKICAgIH0KCiAgICBsb2dnZXIKICAgICAgLi5pbmZvKCcnKQogICAgICAuLmluZm8oJ1J1biB0aGUgYXBwOicpCiAgICAgIC4uaW5mbygnICBjZCAkYXBwTmFtZS9hcHBzLyRhcHBOYW1lICYmIGZsdXR0ZXIgcnVuJyk7CiAgfQp9Cg==", + "aW1wb3J0ICdwYWNrYWdlOmNsaV9jb3JlL2NsaV9jb3JlLmRhcnQnIHNob3cgQ2xpQ29tbWFuZDsKaW1wb3J0ICdwYWNrYWdlOm1hc29uL21hc29uLmRhcnQnOwoKLy8vIFByaW50cyB0aGUgaGFuZGZ1bCBvZiB0aGluZ3MgdGhlIGdlbmVyYXRvciBjYW5ub3QgZG8gZm9yIHlvdS4KZmluYWwgY2xhc3MgTmV4dFN0ZXBzQ29tbWFuZCBleHRlbmRzIENsaUNvbW1hbmQgewogIEBvdmVycmlkZQogIEZ1dHVyZTx2b2lkPiBydW4oSG9va0NvbnRleHQgY29udGV4dCkgYXN5bmMgewogICAgZmluYWwgU3RyaW5nIG5hbWUgPSBjb250ZXh0LnZhcnNbJ25hbWUnXTsKICAgIGZpbmFsIGFwcE5hbWUgPSBuYW1lLnNuYWtlQ2FzZTsKICAgIGZpbmFsIGxvZ2dlciA9IGNvbnRleHQubG9nZ2VyOwoKICAgIGlmIChjb250ZXh0LnZhcnNbJ2ZpcmViYXNlJ10gPT0gdHJ1ZSkgewogICAgICBsb2dnZXIKICAgICAgICAuLmluZm8oJycpCiAgICAgICAgLi53YXJuKCdGaXJlYmFzZSBtb2R1bGVzIGFyZSBlbmFibGVkIGJ1dCBub3QgY29uZmlndXJlZCB5ZXQuJykKICAgICAgICAuLmluZm8oJyAgZGFydCBwdWIgZ2xvYmFsIGFjdGl2YXRlIGZsdXR0ZXJmaXJlX2NsaScpCiAgICAgICAgLi5pbmZvKCcgIGNkICRhcHBOYW1lL2FwcHMvJGFwcE5hbWUgJiYgZmx1dHRlcmZpcmUgY29uZmlndXJlJykKICAgICAgICAuLmluZm8oCiAgICAgICAgICAnICAodGhlIGFwcCBzdGlsbCBydW5zOyBGaXJlYmFzZSBmZWF0dXJlcyBzdGF5IG9mZiB1bnRpbCB0aGVuKScsCiAgICAgICAgKTsKICAgIH0KCiAgICBsb2dnZXIKICAgICAgLi5pbmZvKCcnKQogICAgICAuLmluZm8oJ1ZlcmlmeSB0aGUgd29ya3NwYWNlIChmcm9tICRhcHBOYW1lKTonKQogICAgICAuLmluZm8oJyAgZGFydCBydW4gbWVsb3MgcnVuIGxpbnQnKQogICAgICAuLmluZm8oJyAgZGFydCBydW4gbWVsb3MgcnVuIGNvdmVyYWdlJykKICAgICAgLi5pbmZvKCcnKQogICAgICAuLmluZm8oJ1J1biB0aGUgYXBwOicpCiAgICAgIC4uaW5mbygnICBjZCAkYXBwTmFtZS9hcHBzLyRhcHBOYW1lICYmIGZsdXR0ZXIgcnVuJyk7CiAgfQp9Cg==", "type": "text" }, { @@ -1469,7 +1680,8 @@ final flutterProjectWithMonoRepoBundle = MasonBundle.fromJson({ "https://github.com/nonstopio/flutter_forge/tree/main/packages/nonstop_cli", "readme": { "path": "README.md", - "data": "IyBmbHV0dGVyX3Byb2plY3Rfd2l0aF9tb25vX3JlcG8=", + "data": + "IyBGbHV0dGVyIG1vbm8tcmVwbyB0ZW1wbGF0ZQoKVGhlIGRlZmF1bHQgTm9uU3RvcCBDTEkgdGVtcGxhdGU6IGEgTWVsb3MtbWFuYWdlZCBhcHBsaWNhdGlvbiwgcmV1c2FibGUgcGFja2FnZXMKYW5kIG9wdGlvbmFsIGZlYXR1cmUvU0RLIG1vZHVsZXMuIFNlZSB0aGUgW0NMSSBndWlkZV0oLi4vLi4vUkVBRE1FLm1kKSBmb3IgbW9kdWxlCmZsYWdzIGFuZCB0aGUgZ2VuZXJhdGUg4oaSIGltcHJvdmUg4oaSIHZlcmlmeSDihpIgcG9ydCDihpIgcmVnZW5lcmF0ZSB3b3JrZmxvdy4KClRoZSBnZW5lcmF0ZWQgUkVBRE1FIGFuZCBgZG9jcy9hcmNoaXRlY3R1cmUubWRgIGRlc2NyaWJlIHRoZSBhcmNoaXRlY3R1cmUsCmNvbmZpZ3VyYXRpb24gYW5kIHRlc3RpbmcgY29udHJhY3QuIEFsbCBoYW5kd3JpdHRlbiBydW50aW1lIERhcnQgaXMgc3ViamVjdCB0bwphIDEwMCUgZXhlY3V0YWJsZS1saW5lIGNvdmVyYWdlIGdhdGU7IGdlbmVyYXRlZCBjb2RlLCB0b29scyBhbmQgbmF0aXZlIGNvZGUgYXJlCm91dHNpZGUgdGhhdCBzY29wZS4KCkFmdGVyIGVkaXRpbmcgYF9fYnJpY2tfX2Agb3IgaG9va3MsIHJlYnVpbGQgdGhlIGVtYmVkZGVkIGJ1bmRsZSBmcm9tIHRoZSBDTEkKcGFja2FnZSBkaXJlY3RvcnkgYW5kIHJ1biBpdHMgdGVzdHMgYW5kIGB0b29sL3ZlcmlmeV90ZW1wbGF0ZS5kYXJ0YC4gRG8gbm90IGVkaXQKdGhlIGVuY29kZWQgYnVuZGxlIGRpcmVjdGx5LiBDb250cmFjdCB0ZXN0cyByZWplY3Qgc3RhbGUgYnVuZGxlZCBzb3VyY2UgYW5kCmludmFsaWQgRGFydCBhY3Jvc3MgYWxsIDUxMiBtb2R1bGUgc2VsZWN0aW9uczsgQ0kgYWxzbyBleGVyY2lzZXMgZnJlc2ggcHJvamVjdHMuCg==", "type": "text" }, "changelog": { diff --git a/packages/nonstop_cli/pubspec.yaml b/packages/nonstop_cli/pubspec.yaml index f5e3601..ecdefe7 100644 --- a/packages/nonstop_cli/pubspec.yaml +++ b/packages/nonstop_cli/pubspec.yaml @@ -33,6 +33,7 @@ dependencies: yaml_edit: ^2.2.1 dev_dependencies: + analyzer: ^8.4.0 build_runner: ^2.4.12 build_verify: ^3.1.0 build_version: ^2.1.1 @@ -44,4 +45,3 @@ executables: nonstop: ns: nsio: - diff --git a/packages/nonstop_cli/test/coverage_gate_test.dart b/packages/nonstop_cli/test/coverage_gate_test.dart new file mode 100644 index 0000000..b7ac52e --- /dev/null +++ b/packages/nonstop_cli/test/coverage_gate_test.dart @@ -0,0 +1,117 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:nonstop_cli/commands/create/flutter_project_with_mono_repo_bundle.dart'; +import 'package:path/path.dart' as p; +import 'package:test/test.dart'; + +void main() { + late Directory workspace; + late File script; + final packages = p.absolute('.dart_tool/package_config.json'); + + File write(String name, String contents) { + final file = File(p.join(workspace.path, name)); + file.parent.createSync(recursive: true); + return file..writeAsStringSync(contents); + } + + void package(String directory, String name, String report) { + write('$directory/pubspec.yaml', 'name: $name\n'); + write('$directory/test/example_test.dart', 'void main() {}\n'); + write('$directory/coverage/lcov.info', report); + } + + Future run() => Process.run( + Platform.resolvedExecutable, + ['--packages=$packages', script.path, '--report-only'], + workingDirectory: workspace.path, + ); + + setUp(() { + workspace = Directory.systemTemp.createTempSync('nonstop-coverage-test-'); + final bundled = flutterProjectWithMonoRepoBundle.files + .singleWhere((file) => file.path.endsWith('/tool/coverage.dart')); + script = + write('tool/coverage.dart', utf8.decode(base64Decode(bundled.data))); + }); + tearDown(() => workspace.deleteSync(recursive: true)); + + test('merges relative and absolute cross-package hits without hiding misses', + () async { + final shared = p.join(workspace.path, 'packages/shared/lib/shared.dart'); + write('packages/shared/lib/shared.dart', + 'void first() {}\nvoid second() {}\n'); + package( + 'apps/app', + 'app', + 'SF:lib/app.dart\nDA:1,1\nend_of_record\n' + 'SF:$shared\nDA:1,0\nDA:2,1\nend_of_record\n'); + package('packages/shared', 'shared', + 'SF:lib/shared.dart\nDA:1,1\nDA:2,0\nend_of_record\n'); + final result = await run(); + expect(result.exitCode, 0, reason: '${result.stdout}\n${result.stderr}'); + expect(result.stdout, contains('3/3 executable lines (100.00%)')); + final report = + File(p.join(workspace.path, 'coverage/lcov.info')).readAsStringSync(); + expect(report, contains('SF:packages/shared/lib/shared.dart')); + expect(report, isNot(contains(workspace.path))); + }); + + test('fails below 100 percent and names the exact uncovered line', () async { + package( + 'apps/app', 'app', 'SF:lib/app.dart\nDA:1,1\nDA:2,0\nend_of_record\n'); + final result = await run(); + expect(result.exitCode, 1); + expect(result.stdout, contains('apps/app/lib/app.dart: uncovered lines 2')); + expect(result.stdout, contains('(50.00%)')); + }); + + test('excludes generated and non-runtime code, not handwritten source', + () async { + package( + 'apps/app', + 'app', + [ + for (final name in [ + 'lib/app.dart', + 'lib/model.g.dart', + 'lib/model.freezed.dart', + 'lib/messages.i69n.dart', + 'test/example_test.dart', + '../../tool/coverage.dart', + '../../../outside.dart', + ]) + 'SF:$name\nDA:1,${name == 'lib/app.dart' ? 1 : 0}\nend_of_record\n', + ].join()); + final result = await run(); + expect(result.exitCode, 0, reason: '${result.stdout}\n${result.stderr}'); + expect(result.stdout, contains('1/1 executable lines (100.00%)')); + }); + + test('fails when there are no executable lines', () async { + package('apps/app', 'app', ''); + final result = await run(); + expect(result.exitCode, 1); + expect(result.stdout, contains('0/0 executable lines (0.00%)')); + }); + + test('fails missing reports even if another package has full coverage', + () async { + package('apps/app', 'app', 'SF:lib/app.dart\nDA:1,1\nend_of_record\n'); + package('packages/shared', 'shared', ''); + File(p.join(workspace.path, 'packages/shared/coverage/lcov.info')) + .deleteSync(); + final result = await run(); + expect(result.exitCode, 1); + expect(result.stderr, contains('packages/shared: missing coverage report')); + }); + + test('fails a package without tests instead of silently skipping it', + () async { + write('packages/shared/pubspec.yaml', 'name: shared\n'); + final result = await run(); + expect(result.exitCode, 1); + expect(result.stderr, contains('packages/shared: missing tests')); + }); +} diff --git a/packages/nonstop_cli/test/src/commands/create_command_test.dart b/packages/nonstop_cli/test/src/commands/create_command_test.dart index ef0ace2..7abaee9 100644 --- a/packages/nonstop_cli/test/src/commands/create_command_test.dart +++ b/packages/nonstop_cli/test/src/commands/create_command_test.dart @@ -1,3 +1,4 @@ +import 'package:mason/mason.dart' as mason; import 'package:mason_logger/mason_logger.dart'; import 'package:mocktail/mocktail.dart'; import 'package:nonstop_cli/commands/commands.dart'; @@ -6,6 +7,8 @@ import 'package:test/test.dart'; class _MockLogger extends Mock implements Logger {} +class _MockGenerator extends Mock implements mason.MasonGenerator {} + /// Parses [args] through the real `create` parser so the tests exercise the /// same flag definitions users type. Map modulesFor(List args) { @@ -16,6 +19,22 @@ Map modulesFor(List args) { } void main() { + test('generation uses the bundle shipped with the selected CLI template', + () async { + final generator = _MockGenerator(); + mason.MasonBundle? selected; + final command = CreateCommand( + logger: _MockLogger(), + generatorFromBundle: (bundle) async { + selected = bundle; + return generator; + }); + command.argResultOverrides = + command.argParser.parse(['--defaults', 'example']); + expect(await command.createGenerator(), same(generator)); + expect(selected?.name, 'flutter_project_with_mono_repo'); + expect(selected?.files, isNotEmpty); + }); group('create module selection', () { test('falls back to the recommended set with --defaults', () { final modules = modulesFor(['--defaults', 'my_app']); diff --git a/packages/nonstop_cli/test/template_contract_test.dart b/packages/nonstop_cli/test/template_contract_test.dart new file mode 100644 index 0000000..d02b975 --- /dev/null +++ b/packages/nonstop_cli/test/template_contract_test.dart @@ -0,0 +1,124 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:analyzer/dart/analysis/utilities.dart'; +import 'package:analyzer/dart/ast/ast.dart'; +import 'package:mason/mason.dart'; +import 'package:nonstop_cli/commands/create/flutter_project_with_mono_repo_bundle.dart'; +import 'package:path/path.dart' as path; +import 'package:test/test.dart'; + +import '../bricks/flutter_project_with_mono_repo/hooks/commands/module_vars.dart'; + +class _Context implements HookContext { + _Context(this.vars); + @override + Map vars; + @override + final Logger logger = Logger(level: Level.quiet); +} + +class _MemoryTarget extends GeneratorTarget { + final files = >{}; + @override + Future createFile( + String name, + List contents, { + Logger? logger, + OverwriteRule? overwriteRule, + }) async { + files[path.posix.normalize(name.replaceAll(r'\', '/'))] = contents; + return GeneratedFile.created(path: name); + } +} + +void main() { + test('bundled template files exactly match the reviewed brick source', () { + const brick = 'bricks/flutter_project_with_mono_repo/__brick__'; + final expected = Directory(brick) + .listSync(recursive: true) + .whereType() + .map((file) => path.relative(file.path, from: brick)) + .toSet(); + final bundled = flutterProjectWithMonoRepoBundle.files; + expect(bundled.map((file) => file.path).toSet(), expected); + for (final file in bundled) { + expect(base64Decode(file.data), + File(path.join(brick, file.path)).readAsBytesSync(), + reason: file.path); + } + }); + + test('bundled hooks exactly match the reviewed hook source', () { + const root = 'bricks/flutter_project_with_mono_repo/hooks'; + final expected = Directory(root) + .listSync(recursive: true) + .whereType() + .where((file) => + file.path.endsWith('.dart') || + path.basename(file.path) == 'pubspec.yaml') + .map((file) => path.relative(file.path, from: root)) + .toSet(); + final bundled = flutterProjectWithMonoRepoBundle.hooks; + expect(bundled.map((file) => file.path).toSet(), expected); + for (final file in bundled) { + expect(base64Decode(file.data), + File(path.join(root, file.path)).readAsBytesSync(), + reason: file.path); + } + }); + + test( + 'all 512 module selections render parseable Dart with no disabled-module imports', + () async { + // Rendering is pure here: Flutter scaffolding and dependency installation + // are exercised by the end-to-end generation job, not by unit tests. + final bundle = flutterProjectWithMonoRepoBundle; + final generator = MasonGenerator(bundle.name, bundle.description, files: [ + for (final file in bundle.files) + TemplateFile.fromBytes(file.path, base64Decode(file.data)), + ]); + final modules = [...optionalModules, 'firestore']; + for (var mask = 0; mask < 1 << modules.length; mask++) { + final context = _Context({ + 'name': 'contract_app', + 'description': 'A contract test', + 'org_name': 'com.example', + for (var i = 0; i < modules.length; i++) + modules[i]: mask & (1 << i) != 0, + }); + resolveModuleVars(context); + final target = _MemoryTarget(); + await generator.generate(target, + vars: context.vars, logger: context.logger); + expect( + target.files.containsKey( + 'contract_app/apps/contract_app/test/entrypoint_test.dart'), + isTrue, + reason: 'mask $mask'); + expect( + target.files.containsKey('contract_app/tool/coverage.dart'), isTrue); + for (final entry in target.files.entries + .where((entry) => entry.key.endsWith('.dart'))) { + final source = utf8.decode(entry.value); + expect(source, isNot(contains('{{')), + reason: '${entry.key}, mask $mask: unresolved template'); + final parsed = parseString(content: source, throwIfDiagnostics: false); + expect(parsed.errors, isEmpty, reason: '${entry.key}, mask $mask'); + for (final directive + in parsed.unit.directives.whereType()) { + final uri = directive.uri.stringValue; + if (uri == null || !uri.startsWith('package:')) continue; + final importedPackage = + uri.substring('package:'.length).split('/').first; + if (optionalModules.contains(importedPackage)) { + expect(context.vars[importedPackage], isTrue, + reason: + '${entry.key}, mask $mask imports disabled $importedPackage'); + } + } + } + } + stdout.writeln('Validated ${1 << modules.length} module selections.'); + }, timeout: const Timeout(Duration(minutes: 5))); +} diff --git a/packages/nonstop_cli/tool/verify_template.dart b/packages/nonstop_cli/tool/verify_template.dart new file mode 100644 index 0000000..cfd290c --- /dev/null +++ b/packages/nonstop_cli/tool/verify_template.dart @@ -0,0 +1,62 @@ +import 'dart:io'; + +import 'package:nonstop_cli/commands/create/modules.dart'; +import 'package:path/path.dart' as p; + +/// Run from packages/nonstop_cli: dart run tool/verify_template.dart [profile]. +/// Leaves its temporary workspace available for diagnosis, never edits a repo. +Future main(List args) async { + final profile = args.isEmpty ? 'full' : args.single; + const profiles = [ + 'full', + 'default', + 'minimal', + 'auth-only', + 'firestore-only', + 'network-only' + ]; + if (!profiles.contains(profile)) { + throw ArgumentError('Choose one of $profiles'); + } + final cli = p.dirname(p.dirname(File.fromUri(Platform.script).path)); + final output = await Directory.systemTemp.createTemp('nonstop-verify-'); + const name = 'verified_app'; + final workspace = p.join(output.path, name); + stdout.writeln('Verifying $profile in $workspace'); + Future run( + String executable, List arguments, String directory) async { + final process = await Process.start(executable, arguments, + workingDirectory: directory, mode: ProcessStartMode.inheritStdio); + final result = await process.exitCode; + if (result != 0) { + throw ProcessException( + executable, arguments, 'Verification failed in $directory', result); + } + } + + final flags = []; + if (profile != 'default') { + for (final module in templateModules) { + final enabled = profile == 'full' || profile == '${module.flag}-only'; + flags.add('--${enabled ? '' : 'no-'}${module.flag}'); + } + } + await run( + 'dart', + [ + 'run', + 'bin/nonstop.dart', + 'create', + name, + '--defaults', + ...flags, + '--output-directory', + output.path + ], + cli); + await run('dart', ['run', 'melos', 'run', 'lint'], workspace); + await run('dart', ['run', 'melos', 'run', 'coverage'], workspace); + await run('flutter', ['build', 'web'], p.join(workspace, 'apps', name)); + stdout + .writeln('Verified $profile: analysis, tests, 100% coverage, web build.'); +}