From 38a9b40e16315dce80fb6a97d0b45379966a9bf4 Mon Sep 17 00:00:00 2001 From: Bright Etornam Sunu Date: Wed, 8 Jul 2026 20:53:25 +0000 Subject: [PATCH] Add runnable example app; remove standalone examples/ snippets Replaces the FlutterFlow-style examples/ snippets with a complete, runnable example/ Flutter app (path dependency on the plugin) covering all features: objects-on-planes, gestures, web object + updateNode, local/web/file-system objects, screenshots, debug options, and (Firebase-gated) cloud anchors + external model management. - Cleaned the ported code (fixed throwing firstWhere, dead AlertDialogs, print->debugPrint, mounted guards) and used a working web/embedded GLB instead of the broken bundled Chicken_01.gltf. - Cloud demos simplified off the discontinued geoflutterfire2 (download latest anchor); degrade gracefully without Firebase config. - Android minSdk 28, iOS NSCameraUsageDescription, plane-texture + embedded Duck.gltf assets bundled. - Repointed README example table to example/lib/demos/*. Verified: flutter analyze (0 errors, plugin + example), flutter test, and flutter build apk --debug all pass. --- README.md | 18 +- example/.gitignore | 45 ++ example/.metadata | 33 + example/README.md | 51 ++ example/analysis_options.yaml | 28 + example/android/.gitignore | 14 + example/android/app/build.gradle.kts | 46 ++ .../android/app/src/debug/AndroidManifest.xml | 7 + .../android/app/src/main/AndroidManifest.xml | 45 ++ .../MainActivity.kt | 5 + .../res/drawable-v21/launch_background.xml | 12 + .../main/res/drawable/launch_background.xml | 12 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 544 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 442 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 721 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 1031 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 1443 bytes .../app/src/main/res/values-night/styles.xml | 18 + .../app/src/main/res/values/styles.xml | 18 + .../app/src/profile/AndroidManifest.xml | 7 + example/android/build.gradle.kts | 24 + example/android/gradle.properties | 6 + .../gradle/wrapper/gradle-wrapper.properties | 5 + example/android/settings.gradle.kts | 26 + example/assets/images/triangle.png | Bin 0 -> 268 bytes example/assets/models/Duck.gltf | 219 +++++ example/ios/.gitignore | 34 + example/ios/Flutter/AppFrameworkInfo.plist | 24 + example/ios/Flutter/Debug.xcconfig | 2 + example/ios/Flutter/Release.xcconfig | 2 + example/ios/Podfile | 43 + example/ios/Podfile.lock | 164 ++++ example/ios/Runner.xcodeproj/project.pbxproj | 753 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../xcshareddata/xcschemes/Runner.xcscheme | 101 +++ .../contents.xcworkspacedata | 10 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + example/ios/Runner/AppDelegate.swift | 16 + .../AppIcon.appiconset/Contents.json | 122 +++ .../Icon-App-1024x1024@1x.png | Bin 0 -> 10932 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 0 -> 295 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 0 -> 406 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 0 -> 450 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 0 -> 282 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 0 -> 462 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 0 -> 704 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 0 -> 406 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 0 -> 586 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 0 -> 862 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 0 -> 862 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 0 -> 1674 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 0 -> 762 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 0 -> 1226 bytes .../Icon-App-83.5x83.5@2x.png | Bin 0 -> 1418 bytes .../LaunchImage.imageset/Contents.json | 23 + .../LaunchImage.imageset/LaunchImage.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/README.md | 5 + .../Runner/Base.lproj/LaunchScreen.storyboard | 37 + example/ios/Runner/Base.lproj/Main.storyboard | 26 + example/ios/Runner/Info.plist | 72 ++ example/ios/Runner/Runner-Bridging-Header.h | 1 + example/ios/Runner/SceneDelegate.swift | 6 + example/ios/RunnerTests/RunnerTests.swift | 12 + example/lib/demos/cloud_anchor_demo.dart | 311 ++++++++ example/lib/demos/debug_options_demo.dart | 107 +++ example/lib/demos/external_model_demo.dart | 295 +++++++ .../lib/demos/local_and_web_objects_demo.dart | 212 +++++ example/lib/demos/object_gestures_demo.dart | 158 ++++ example/lib/demos/objects_on_planes_demo.dart | 132 +++ example/lib/demos/screenshot_demo.dart | 155 ++++ example/lib/demos/web_object_demo.dart | 152 ++++ example/lib/firebase/firebase_manager.dart | 110 +++ example/lib/main.dart | 104 +++ example/pubspec.yaml | 105 +++ example/test/widget_test.dart | 25 + examples/README.md | 13 - examples/cloud_anchor.dart | 557 ------------- examples/debug_options.dart | 133 ---- examples/external_model_management.dart | 668 ---------------- examples/local_and_web_objects.dart | 259 ------ examples/object_gestures.dart | 195 ----- examples/objects_on_planes.dart | 167 ---- examples/screenshot.dart | 182 ----- 88 files changed, 3989 insertions(+), 2182 deletions(-) create mode 100644 example/.gitignore create mode 100644 example/.metadata create mode 100644 example/README.md create mode 100644 example/analysis_options.yaml create mode 100644 example/android/.gitignore create mode 100644 example/android/app/build.gradle.kts create mode 100644 example/android/app/src/debug/AndroidManifest.xml create mode 100644 example/android/app/src/main/AndroidManifest.xml create mode 100644 example/android/app/src/main/kotlin/com/example/ar_flutter_plugin_2_example/MainActivity.kt create mode 100644 example/android/app/src/main/res/drawable-v21/launch_background.xml create mode 100644 example/android/app/src/main/res/drawable/launch_background.xml create mode 100644 example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 example/android/app/src/main/res/values-night/styles.xml create mode 100644 example/android/app/src/main/res/values/styles.xml create mode 100644 example/android/app/src/profile/AndroidManifest.xml create mode 100644 example/android/build.gradle.kts create mode 100644 example/android/gradle.properties create mode 100644 example/android/gradle/wrapper/gradle-wrapper.properties create mode 100644 example/android/settings.gradle.kts create mode 100644 example/assets/images/triangle.png create mode 100644 example/assets/models/Duck.gltf create mode 100644 example/ios/.gitignore create mode 100644 example/ios/Flutter/AppFrameworkInfo.plist create mode 100644 example/ios/Flutter/Debug.xcconfig create mode 100644 example/ios/Flutter/Release.xcconfig create mode 100644 example/ios/Podfile create mode 100644 example/ios/Podfile.lock create mode 100644 example/ios/Runner.xcodeproj/project.pbxproj create mode 100644 example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme create mode 100644 example/ios/Runner.xcworkspace/contents.xcworkspacedata create mode 100644 example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 example/ios/Runner/AppDelegate.swift create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png create mode 100644 example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json create mode 100644 example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png create mode 100644 example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png create mode 100644 example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png create mode 100644 example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md create mode 100644 example/ios/Runner/Base.lproj/LaunchScreen.storyboard create mode 100644 example/ios/Runner/Base.lproj/Main.storyboard create mode 100644 example/ios/Runner/Info.plist create mode 100644 example/ios/Runner/Runner-Bridging-Header.h create mode 100644 example/ios/Runner/SceneDelegate.swift create mode 100644 example/ios/RunnerTests/RunnerTests.swift create mode 100644 example/lib/demos/cloud_anchor_demo.dart create mode 100644 example/lib/demos/debug_options_demo.dart create mode 100644 example/lib/demos/external_model_demo.dart create mode 100644 example/lib/demos/local_and_web_objects_demo.dart create mode 100644 example/lib/demos/object_gestures_demo.dart create mode 100644 example/lib/demos/objects_on_planes_demo.dart create mode 100644 example/lib/demos/screenshot_demo.dart create mode 100644 example/lib/demos/web_object_demo.dart create mode 100644 example/lib/firebase/firebase_manager.dart create mode 100644 example/lib/main.dart create mode 100644 example/pubspec.yaml create mode 100644 example/test/widget_test.dart delete mode 100644 examples/README.md delete mode 100644 examples/cloud_anchor.dart delete mode 100644 examples/debug_options.dart delete mode 100644 examples/external_model_management.dart delete mode 100644 examples/local_and_web_objects.dart delete mode 100644 examples/object_gestures.dart delete mode 100644 examples/objects_on_planes.dart delete mode 100644 examples/screenshot.dart diff --git a/README.md b/README.md index 9cdfeabe..30b7c7a7 100644 --- a/README.md +++ b/README.md @@ -124,17 +124,19 @@ Therefore, it is necessary to publish your project with github and make the modi -### Example Applications +### Example Application + +A complete, runnable demo app lives in [`example/`](example/) — run it on a physical ARCore/ARKit device with `cd example && flutter run`. Each feature has its own screen under [`example/lib/demos/`](example/lib/demos/). The Cloud Anchors and External Model Management demos additionally require a Firebase project (see [cloudAnchorSetup.md](cloudAnchorSetup.md)). | Example Name | Description | Link to Code | | ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |------------------------------------------------------------------------------------------------------------------------------------------------------| -| Debug Options | Simple AR scene with toggles to visualize the world origin, feature points and tracked planes | [Debug Options Code](https://github.com/hlefe/ar_flutter_plugin_2/blob/main/examples/debug_options.dart) | -| Local & Online Objects | AR scene with buttons to place GLTF objects from the flutter asset folders, GLB objects from the internet, or a GLB object from the app's Documents directory at a given position, rotation and scale. Additional buttons allow to modify scale, position and orientation with regard to the world origin after objects have been placed. | [Local & Online Objects Code](https://github.com/hlefe/ar_flutter_plugin_2/blob/main/examples/local_and_web_objects.dart) | -| Objects & Anchors on Planes | AR Scene in which tapping on a plane creates an anchor with a 3D model attached to it | [Objects & Anchors on Planes Code](https://github.com/hlefe/ar_flutter_plugin_2/blob/main/examples/objects_on_planes.dart) | -| Object Transformation Gestures | Same as Objects & Anchors on Planes example, but objects can be panned and rotated using gestures after being placed | [Objects Gestures](https://github.com/hlefe/ar_flutter_plugin_2/blob/main/examples/object_gestures.dart) | -| Screenshots | Same as Objects & Anchors on Planes Example, but the snapshot function is used to take screenshots of the AR Scene | [Screenshots Code](https://github.com/hlefe/ar_flutter_plugin_2/blob/main/examples/screenshot.dart) | -| Cloud Anchors | AR Scene in which objects can be placed, uploaded and downloaded, thus creating an interactive AR experience that can be shared between multiple devices. Currently, the example allows to upload the last placed object along with its anchor and download all anchors within a radius of 100m along with all the attached objects (independent of which device originally placed the objects). As sharing the objects is done by using the Google Cloud Anchor Service and Firebase, this requires some additional setup, please read [Getting Started with cloud anchors](cloudAnchorSetup.md) | [Cloud Anchors Code](https://github.com/hlefe/ar_flutter_plugin_2/blob/main/examples/cloud_anchor.dart) | -| External Object Management | Similar to the Cloud Anchors example, but contains UI to choose between different models. Rather than being hard-coded, an external database (Firestore) is used to manage the available models. As sharing the objects is done by using the Google Cloud Anchor Service and Firebase, this requires some additional setup, please read [Getting Started with cloud anchors](cloudAnchorSetup.md). Also make sure that in your Firestore database, the collection "models" contains some entries with the fields "name", "image", and "uri", where "uri" points to the raw file of a model in GLB format | [External Model Management Code](https://github.com/hlefe/ar_flutter_plugin_2/blob/main/examples/external_model_management.dart) | +| Debug Options | Simple AR scene with toggles to visualize the world origin, feature points and tracked planes | [Debug Options Code](example/lib/demos/debug_options_demo.dart) | +| Local & Online Objects | AR scene with buttons to place GLTF objects from the flutter asset folders, GLB objects from the internet, or a GLB object from the app's Documents directory at a given position, rotation and scale. Additional buttons allow to modify scale, position and orientation with regard to the world origin after objects have been placed. | [Local & Online Objects Code](example/lib/demos/local_and_web_objects_demo.dart) | +| Objects & Anchors on Planes | AR Scene in which tapping on a plane creates an anchor with a 3D model attached to it | [Objects & Anchors on Planes Code](example/lib/demos/objects_on_planes_demo.dart) | +| Object Transformation Gestures | Same as Objects & Anchors on Planes example, but objects can be panned and rotated using gestures after being placed | [Objects Gestures](example/lib/demos/object_gestures_demo.dart) | +| Screenshots | Same as Objects & Anchors on Planes Example, but the snapshot function is used to take screenshots of the AR Scene | [Screenshots Code](example/lib/demos/screenshot_demo.dart) | +| Cloud Anchors | AR Scene in which objects can be placed, uploaded and downloaded, thus creating an interactive AR experience that can be shared between multiple devices. Currently, the example allows to upload the last placed object along with its anchor and download all anchors within a radius of 100m along with all the attached objects (independent of which device originally placed the objects). As sharing the objects is done by using the Google Cloud Anchor Service and Firebase, this requires some additional setup, please read [Getting Started with cloud anchors](cloudAnchorSetup.md) | [Cloud Anchors Code](example/lib/demos/cloud_anchor_demo.dart) | +| External Object Management | Similar to the Cloud Anchors example, but contains UI to choose between different models. Rather than being hard-coded, an external database (Firestore) is used to manage the available models. As sharing the objects is done by using the Google Cloud Anchor Service and Firebase, this requires some additional setup, please read [Getting Started with cloud anchors](cloudAnchorSetup.md). Also make sure that in your Firestore database, the collection "models" contains some entries with the fields "name", "image", and "uri", where "uri" points to the raw file of a model in GLB format | [External Model Management Code](example/lib/demos/external_model_demo.dart) | ## Plugin Architecture diff --git a/example/.gitignore b/example/.gitignore new file mode 100644 index 00000000..3820a95c --- /dev/null +++ b/example/.gitignore @@ -0,0 +1,45 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.build/ +.buildlog/ +.history +.svn/ +.swiftpm/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins-dependencies +.pub-cache/ +.pub/ +/build/ +/coverage/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/example/.metadata b/example/.metadata new file mode 100644 index 00000000..653119e6 --- /dev/null +++ b/example/.metadata @@ -0,0 +1,33 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "f94f4fc76b4d74543ed9b085bbd75341ef65de22" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: f94f4fc76b4d74543ed9b085bbd75341ef65de22 + base_revision: f94f4fc76b4d74543ed9b085bbd75341ef65de22 + - platform: android + create_revision: f94f4fc76b4d74543ed9b085bbd75341ef65de22 + base_revision: f94f4fc76b4d74543ed9b085bbd75341ef65de22 + - platform: ios + create_revision: f94f4fc76b4d74543ed9b085bbd75341ef65de22 + base_revision: f94f4fc76b4d74543ed9b085bbd75341ef65de22 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/example/README.md b/example/README.md new file mode 100644 index 00000000..f53dfa87 --- /dev/null +++ b/example/README.md @@ -0,0 +1,51 @@ +# ar_flutter_plugin_2 example + +A runnable demo app for the `ar_flutter_plugin_2` plugin (referenced via a +path dependency on `../`). + +## Requirements + +AR runs only on a **physical device** — ARCore on Android, ARKit on iOS. It +will not render in an emulator or simulator. Camera permission is requested at +runtime. + +- Android: `minSdk 28` (set in `android/app/build.gradle.kts`); the device must + support [ARCore](https://developers.google.com/ar/devices). +- iOS: an ARKit-capable device; `NSCameraUsageDescription` is set in + `ios/Runner/Info.plist`. + +## Run + +```bash +cd example +flutter pub get +flutter run # on a connected AR-capable device +``` + +## Demos + +| Screen | Feature exercised | Source | +| --- | --- | --- | +| Objects on planes | Plane detection, `addAnchor`, `addNode` on a plane anchor, `onNodeTap` | `lib/demos/objects_on_planes_demo.dart` | +| Object gestures | `handlePans`/`handleRotation`, `onPanEnd`/`onRotationEnd`, syncing `ARNode.transform` | `lib/demos/object_gestures_demo.dart` | +| Web object + updateNode | `addNode`/`removeNode` at the world origin and `updateNode` (programmatic rotate/scale) | `lib/demos/web_object_demo.dart` | +| Local & web objects | `localGLTF2` (bundled asset), `webGLB`, `fileSystemAppFolderGLB`, transform shuffle | `lib/demos/local_and_web_objects_demo.dart` | +| Screenshots | `ARSessionManager.snapshot()` | `lib/demos/screenshot_demo.dart` | +| Debug options | Live-toggling `showFeaturePoints` / `showPlanes` / `showWorldOrigin` | `lib/demos/debug_options_demo.dart` | +| Cloud anchors | `initGoogleCloudAnchorMode`, `uploadAnchor`/`downloadAnchor` + Firestore | `lib/demos/cloud_anchor_demo.dart` | +| External model management | Firestore-managed model list + cloud anchors | `lib/demos/external_model_demo.dart` | + +Most models load as `NodeType.webGLB` from a public Khronos sample URL. Bundled +assets are `assets/images/triangle.png` (plane texture for +`customPlaneTexturePath`) and a self-contained `assets/models/Duck.gltf` (for +the local-asset demo). + +### Cloud anchor demos (Firebase) + +The **Cloud anchors** and **External model management** screens need a +configured Firebase project and the Google Cloud Anchor service — see +[`cloudAnchorSetup.md`](../cloudAnchorSetup.md). Without a Firebase +configuration they show a "Firebase initialization failed" screen rather than +crashing, so the rest of the app still runs. These two demos are simplified +from the original snippets: they drop the discontinued `geoflutterfire2` +geo-radius query and download the most recently uploaded anchor instead. diff --git a/example/analysis_options.yaml b/example/analysis_options.yaml new file mode 100644 index 00000000..0d290213 --- /dev/null +++ b/example/analysis_options.yaml @@ -0,0 +1,28 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at https://dart.dev/lints. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/example/android/.gitignore b/example/android/.gitignore new file mode 100644 index 00000000..be3943c9 --- /dev/null +++ b/example/android/.gitignore @@ -0,0 +1,14 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java +.cxx/ + +# Remember to never publicly share your keystore. +# See https://flutter.dev/to/reference-keystore +key.properties +**/*.keystore +**/*.jks diff --git a/example/android/app/build.gradle.kts b/example/android/app/build.gradle.kts new file mode 100644 index 00000000..65058179 --- /dev/null +++ b/example/android/app/build.gradle.kts @@ -0,0 +1,46 @@ +plugins { + id("com.android.application") + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id("dev.flutter.flutter-gradle-plugin") +} + +android { + namespace = "com.example.ar_flutter_plugin_2_example" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId = "com.example.ar_flutter_plugin_2_example" + // You can update the following values to match your application needs. + // For more information, see: https://flutter.dev/to/review-gradle-config. + // ar_flutter_plugin_2 requires a minimum SDK of 28. + minSdk = 28 + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig = signingConfigs.getByName("debug") + } + } +} + +kotlin { + compilerOptions { + jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17 + } +} + +flutter { + source = "../.." +} diff --git a/example/android/app/src/debug/AndroidManifest.xml b/example/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 00000000..399f6981 --- /dev/null +++ b/example/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..62a40d6d --- /dev/null +++ b/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/example/android/app/src/main/kotlin/com/example/ar_flutter_plugin_2_example/MainActivity.kt b/example/android/app/src/main/kotlin/com/example/ar_flutter_plugin_2_example/MainActivity.kt new file mode 100644 index 00000000..e6bab2cb --- /dev/null +++ b/example/android/app/src/main/kotlin/com/example/ar_flutter_plugin_2_example/MainActivity.kt @@ -0,0 +1,5 @@ +package com.example.ar_flutter_plugin_2_example + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity : FlutterActivity() diff --git a/example/android/app/src/main/res/drawable-v21/launch_background.xml b/example/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 00000000..f74085f3 --- /dev/null +++ b/example/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/example/android/app/src/main/res/drawable/launch_background.xml b/example/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 00000000..304732f8 --- /dev/null +++ b/example/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..db77bb4b7b0906d62b1847e87f15cdcacf6a4f29 GIT binary patch literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ literal 0 HcmV?d00001 diff --git a/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..17987b79bb8a35cc66c3c1fd44f5a5526c1b78be GIT binary patch literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xx&nMcT!A!W`0S9QKQy;}1Cl^CgaH=;G9cpY;r$Q>i*pfB zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q03KywUtLX8Ua?`H+NMzkczFPK3lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l zytQ?X=U+MF$@3 zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+ yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@Uy!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ literal 0 HcmV?d00001 diff --git a/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..d5f1c8d34e7a88e3f88bea192c3a370d44689c3c GIT binary patch literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof literal 0 HcmV?d00001 diff --git a/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..4d6372eebdb28e45604e46eeda8dd24651419bc0 GIT binary patch literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` literal 0 HcmV?d00001 diff --git a/example/android/app/src/main/res/values-night/styles.xml b/example/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 00000000..06952be7 --- /dev/null +++ b/example/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/example/android/app/src/main/res/values/styles.xml b/example/android/app/src/main/res/values/styles.xml new file mode 100644 index 00000000..cb1ef880 --- /dev/null +++ b/example/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/example/android/app/src/profile/AndroidManifest.xml b/example/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 00000000..399f6981 --- /dev/null +++ b/example/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/example/android/build.gradle.kts b/example/android/build.gradle.kts new file mode 100644 index 00000000..dbee657b --- /dev/null +++ b/example/android/build.gradle.kts @@ -0,0 +1,24 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +val newBuildDir: Directory = + rootProject.layout.buildDirectory + .dir("../../build") + .get() +rootProject.layout.buildDirectory.value(newBuildDir) + +subprojects { + val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) + project.layout.buildDirectory.value(newSubprojectBuildDir) +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/example/android/gradle.properties b/example/android/gradle.properties new file mode 100644 index 00000000..e96108cf --- /dev/null +++ b/example/android/gradle.properties @@ -0,0 +1,6 @@ +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError +android.useAndroidX=true +# This newDsl flag was added by the Flutter template +android.newDsl=false +# This builtInKotlin flag was added by the Flutter template +android.builtInKotlin=false diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..2d428bfb --- /dev/null +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-all.zip diff --git a/example/android/settings.gradle.kts b/example/android/settings.gradle.kts new file mode 100644 index 00000000..c21f0c5b --- /dev/null +++ b/example/android/settings.gradle.kts @@ -0,0 +1,26 @@ +pluginManagement { + val flutterSdkPath = + run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "9.0.1" apply false + id("org.jetbrains.kotlin.android") version "2.3.20" apply false +} + +include(":app") diff --git a/example/assets/images/triangle.png b/example/assets/images/triangle.png new file mode 100644 index 0000000000000000000000000000000000000000..09dfe4c95e4653a10c17af406589c8c72c2f4e05 GIT binary patch literal 268 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=mpxq^Ln>~)y|9zF!9av1@Oyl# zwW$!J(4$QsKd$FAi#zMRbc)IzouBg=CiI`5#KEA^DelbR5V(hfiQ&|v>BQtVq`e}F%&4(|KEi{!QqcK z6NBR;c|isak@{{1hYdftnHU%!`*Sd`^x6wBaLDY}w>iMJ=Iv!(!_5zCf!<^AboFyt I=akR{0KmgnL;wH) literal 0 HcmV?d00001 diff --git a/example/assets/models/Duck.gltf b/example/assets/models/Duck.gltf new file mode 100644 index 00000000..7d137540 --- /dev/null +++ b/example/assets/models/Duck.gltf @@ -0,0 +1,219 @@ +{ + "asset": { + "generator": "COLLADA2GLTF", + "version": "2.0" + }, + "scene": 0, + "scenes": [ + { + "nodes": [ + 0 + ] + } + ], + "nodes": [ + { + "children": [ + 2, + 1 + ], + "matrix": [ + 0.009999999776482582, + 0.0, + 0.0, + 0.0, + 0.0, + 0.009999999776482582, + 0.0, + 0.0, + 0.0, + 0.0, + 0.009999999776482582, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + { + "matrix": [ + -0.7289686799049377, + 0.0, + -0.6845470666885376, + 0.0, + -0.4252049028873444, + 0.7836934328079224, + 0.4527972936630249, + 0.0, + 0.5364750623703003, + 0.6211478114128113, + -0.571287989616394, + 0.0, + 400.1130065917969, + 463.2640075683594, + -431.0780334472656, + 1.0 + ], + "camera": 0 + }, + { + "mesh": 0 + } + ], + "cameras": [ + { + "perspective": { + "aspectRatio": 1.5, + "yfov": 0.6605925559997559, + "zfar": 10000.0, + "znear": 1.0 + }, + "type": "perspective" + } + ], + "meshes": [ + { + "primitives": [ + { + "attributes": { + "NORMAL": 1, + "POSITION": 2, + "TEXCOORD_0": 3 + }, + "indices": 0, + "mode": 4, + "material": 0 + } + ], + "name": "LOD3spShape" + } + ], + "accessors": [ + { + "bufferView": 0, + "byteOffset": 0, + "componentType": 5123, + "count": 12636, + "max": [ + 2398 + ], + "min": [ + 0 + ], + "type": "SCALAR" + }, + { + "bufferView": 1, + "byteOffset": 0, + "componentType": 5126, + "count": 2399, + "max": [ + 0.9995989799499512, + 0.999580979347229, + 0.9984359741210938 + ], + "min": [ + -0.9990839958190918, + -1.0, + -0.9998319745063782 + ], + "type": "VEC3" + }, + { + "bufferView": 1, + "byteOffset": 28788, + "componentType": 5126, + "count": 2399, + "max": [ + 96.17990112304688, + 163.97000122070313, + 53.92519760131836 + ], + "min": [ + -69.29850006103516, + 9.929369926452637, + -61.32819747924805 + ], + "type": "VEC3" + }, + { + "bufferView": 2, + "byteOffset": 0, + "componentType": 5126, + "count": 2399, + "max": [ + 0.9833459854125976, + 0.9800369739532472 + ], + "min": [ + 0.026409000158309938, + 0.01996302604675293 + ], + "type": "VEC2" + } + ], + "materials": [ + { + "pbrMetallicRoughness": { + "baseColorTexture": { + "index": 0 + }, + "metallicFactor": 0.0 + }, + "emissiveFactor": [ + 0.0, + 0.0, + 0.0 + ], + "name": "blinn3-fx" + } + ], + "textures": [ + { + "sampler": 0, + "source": 0 + } + ], + "images": [ + { + "uri": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAMAAADDpiTIAAAAolBMVEX/2AD/fgD/yQD/vgD/1gD/uAD/0wAAAAD/////1wD/0AD/1QD/zwD/wgD/uwD/zQD/yAD/vQD/wwD/xAD/xgD/0gD/wAD/ywD/gwD/rgD/jAD/nAAZGRn//e84ODj/3Rvf399tbW3/7YXv7+//8qb/4DXQ0NCioqL/+db/9sJWVlb/5E6Hh4f//vj/6Gf/++K6urr5wAD1xwD0zwDwywDhvwC5yx0UAAA+x0lEQVR4XmIwNRnBYBSYAtilYxSGYRgKwxmVQxiDkMBCyB6a+5+tyVwCbZNA7LwPNAi06Z9e04PBa1qmB4PlLgEAAgAEAFm9sohZaS2tWitmIlxd89gBgDpLSUE7IhVh1wEDgDk7Swn6QmwV5JECAK3S6CdNqo4RAChb0B/CWAcIAN+nA4y13wAgVws6KKzmLgMA5UanaKzdBQAuQacJ8a4CADc6mfmDA8D7N+ZdBABqdBHT2wcAKkGXCdFOAphXn9v4Mie6VOJ85wDmbfZtB0PzN/tl16IgEAVQEIk7JSTbSk8xICNMhPr//922qXunZppW79hc0vOSZPRyzp0PDbOjL+wCsMX7+djxV/AWlGQUgDDNL7oB0bTwJtqGEEBU9RiAWMefgpJxA7gKJLPu/hT0JVoAwmYtoKzhzdRllABEWNbln4CShAAC2l8LqDREQVf0AOj61wSaE0Ti1BACmFF86uBzCyghIiUhgNCn/fQlH1mAgqgoOWMAdPM2HxaAPAMwLYAewAj1pARW/yTOcqYAnho31S87AamBAVrOEgBl4HePvEhgvf6R0FX4ACbI31lsejCCIAVwCadqgQltFTgAYfFo2mse3SOPDUwMgNHuIVtgg65mDMA/6C/tI/3b6QWI5yxz/0e0DBmAZ/Sn6EfwR57TYP8gxrFk/1iAPwC6frdjx9dFUXgSQFIHwwsxkqj3P5a3QQyA7N9y76O4Y7vtHzw9uNoy8+CXgAJ2qDABBNC/fYIrA89/Ygf/Xg+W6B9RgQO4t+8bdPR7e8xueDLYjABvEHwKECVwpC49AVD8u/VvkSzb/5J1n8hQQjYwPQNHAmkaK4FLDSypL9QABOLWj0M/cHV+7EiSY8/eQfaHuSOMS8BUnl6JVEB1AqacKmIAfv+ddmOiO/mJSZ7nCZZgF2EtBCMyMC4HvtPhci6ANlq6A6D4N9b8Xvp+mPfed55/P5JjBIndgnVAcDdwa+P+FV4M4hWggDHKHQDBP+rv3HfyTdkHg6/DARtA7AXBOBu4GihsNsWQwF0Fbz8ONsCahhoA+v9h7lybE+XhKD4jLY5FxBvyhrVaWm2tbf3+n24lUQ9JyA0g4cwzO91n99WeH/9rCJz992g/p5Zff4njeLlcxhui689xKYLADQOSDip61AlCeUAZUIr+BZIIBAIcbpg/foYNwM+HDgB7/9PS/UegX62WRPGGKuC12SxXkBgQxNJAzAmc91QgoM0RA/8FQHG4HM/703a7zW+6/njan4+XQ9FVGWAPwARC/L/ZT2L+ijofl+JtX1DNFjcFJCJQgQRAkEHJDQMgwDPA/09sFt0TMGlZAOwu59M2H0uVb0/ny659GWAPAOs+/L/+oye3qF+a/3joF7Or20HwMH3GaREQCOLlTXw8mIMCSYcAifVi3SLBCQDfbcw/7hnvFRTsj20g+G4AQH35R1P/fL0i9j+efN5u+C9AQDBgEEA4AAR8owi7xSFSCgKEAwYMBIM6AlBc9tuxlbb7S9N88PfaEoC7+6Tqn1PHYH8At/Ui+QDpgIkEc6Yw4CZGmDGyf0AJAALyRDCADhDu48l3wcC7NQBC+g9DMuK7Bv+7/yTyI9hbidQEVA8IkAvus6NELvJnqBVAgOKk2VASwAHPfhMGDo2TgD0A8J+3/573oSYMUAjKXIJIgF6xkgwyInGC8GAgZcaDUgD8dwDFEe431PZYNO0EAIBdAghTYv8IT3+9+8/P1/+ebSCAytIACFTmxzCfbRwhQkBaZcARANY7wB1Cfxvl9mHgjQPA3H8S/RP4v1zSh3/Bm8+oSUh4UFCGA5oNYDn7M/0daEjYTVL9yRHvI6AD7HeOwM9HIwAe/mfZ/Fb7xzTzw3iZZlYULBYIBVfFTFVwE7FeEEEAlQAI6B2ALzv7T+NOdbJD4IsFwM7/LCOdP5n2cQ//s0o2/iMd0OKgukSQa3QVAGAI6B2AX7vgP+5a+X5ntROwAAD+h2FK/F8T/2E/vO8KgAC6jQ05ADgOuNUSaRNdAjCxqQCLcz7uQfm5sKsDAYCp/yn8Lxs/2P9sJHv/AcCdAEiGACkEeQAiHgCPFSAq/66VHy3qQGsAysef+E/sN/cfMrVfBKAU6QokENxaAgCAEOAGgNe/psnfVynw92oHwBM98UP9p40/7DeVtf0b1IEEAAEBdIkaACIOAE8B4AfRvx/l5x+LEAAA9P6nKQkAZfcXw/9nK1nMAjZ3AQBlCGD7QBaAqFS/AeCf7ePvPwj8ewUApv5PyfAvvtv/bCvj5E9sZ1VXBtRXgNlje5wyAPgPAEfm8fddCbwBAK3/UUiff+p/AP8tpXn6mfafYeBWA+gffkMAfASAYj92pH1hFgKMASj9J8d+mvkPWRX/Acwn4gCA/RwAiQyACeQhABy2Y2faHoxCAADQJ4CXhPi/7M1/FACIAQwASzYEwP6KFAD4DgAI/97TAEKAIQDR3f/1cgP/uwMACiCUf0S30wL1Dz+kBMBnADiPHetsGgL0ADyFpf9k/A//G8l0AowEgCXxDYA51kK1kgLQm/+T179m6d9/IfD5qgRgchPd/4yI/6j/m0jhPMwX2wAcIKUEwH8jACIBANdbgOI09qCTnoBfEwCewpcp9X9J/e8cALjPz3/QAiIEIADUigKAE6ISAFyuAXfbsRdtd9qloAkAUUr9JwEA/vf0+CP7gwAmB+j8ZwFw4P93c//9E/CtAYAGAPraxyqG/93aLyIAoQqwAWDKAMANAZy9CgD/B0vAOwCQZoB0mhD/l6X/3TaAFfMlAPBt4EpRAIiDQAIA9gCOp8Dwf7gE/HvVAkADwBoBoEv/oYCrAqC7/dR/FQCZ4H9aORLo+iAI/B8yAb8AwCAABJ3lf6R+6jy04RGA/QQA5dNfBwD893ASrID/nrQt1GWgJgI8ReUGgAQA4n9XAMB/of2D0ASuHroCMNf5n0gCQC9HQdv1f/67wQ8AICkBaQW4QgLowP+b+7UVIISDANBa2P3jR3ETBAD8nAXfjwegvXoaCADq/I/Sael/mQE6mgDCf6YEkBIQLzkA5nOkfCrO/wQviAEA2N+tPtvNf/1PhT/VAIRpcgsAHU6AFjUK6lX6XyWgegAog1j/6aFwAICH3+3bYMfxQHRUjgJUAETIAOgAG6jGf3CgBgD2A4A5D4Do/wMAxn+nGeCQDwWA/KDKAQoAnsLwlgFiBIDWGeDmP4OAtATgCKguAk38jyL47ywDiA3AkFuBTwBQEwDChACAANBNDQgWpABUm0AWACQBwX5xDYjqrw99tC8A/ReCH/IIEN1LgDiY9bAElIcAZgxUbQTFg2CM+1PO/74DwNvACwDoqOwDpBngXgJsSvublwCW/vNzYEQBsgusSwKwn18Cwv8e9KUvAIZfBnxpACABoBsAYDzvv3IRgFkgtR8ACM0/tT+tXBHi5064n9N4YDr9SPcBAEBoAsMpAQA9YIf+L6qSLwIBwFLif0KE/Q9zP0ifAEx+zScA/nW2AAAlQMcAwH/JGGAjAgAEblMgxn/m7igy/RUAcHArrNsEgMvCLoddUewOF5MLxvJDIwDoUdAAGaCjOaDefxEAbhfI2o/kz94RBf8dNoGn3t0/8TfF7Y4nDQMnyxRAm4Bs1OUQAPMfTvBfngJIDzCC2NKffR8Y/vcYAT58dQD5uXbJuzurETg2BQAHQdoPgeE/I/ivqAGFK2WFW2RTpwDISoAi79n+otnNA3mhBwD+IwWsutsDLmSC/6wY/wEAZ79IAPzvEYB3LxXgSXnEY6fKPudmAGAR2LX/kNL/JfWfSjj6JxKAc2Be5sC73M8rP/pXkPKdRQoAADGtATsu/wL58w/Bf1wShewvEJCWYvzvE4BXSWe99zLPgS5yAvamEQCvBBEAEAG62wIH8gIAgv2Vq0OZC6RlADDHwJyugg/+TvjpzyEeGgEQBIvuA0Cg7ABgP3Uf/pcAoPmrASBlToG4XwWf/PmvJ+DUNAJ0HQACAkCgAKAy/4XIGAD+cwSkVPC/XwDeHQQAbQq3LUMOVgBEJQArWgPY26/0v/IrkTT3r6HHlbFaAOC/8xpw7zP/60eRezsAwpekKQAzXqz/MgDQ+bH+4xtDWP4KBCADwH/HNeAu97DRFfUjnUXtDACYsAAgBbSb/wMAhH4AwNtP/RcBwPpPBOBRA8J/BzWggwCgmOTaTqP3dgCkHQCw4Ko/OC95Dwi1v5gBMgUAWAbAf8erwCL3WwDoQ1FeWAEQAoDGAQC2yySkf+K+CoCM+C8SEFLBf8engY7Ot7nWG+mjCQC4HDrJ1g3eCZtZAQD3xUOArP9aAFIWAOe74P5ugS1UZtsEo61JEQgApi0BwNUvxgDAfxGA7CH47wmAL5c9IAJA+xBwMAYgogA0SAEzVnoA9P6jBKRKAICYA6I6/x3cDLT3XwHoq4C9DQDpS3ZbBrUbAcjNh/+1rwJC8B8AyEJAxPjvrAsscv8tgL4RyAsrAJL1qicAcBsgRO2H7sEfMwB8GUgRAiL47/I0yMXfDMCmIr2YFoHl58EIAORUeHP/LQBgyj/xWkD4z/eBkCMAvr1lgPY5wA6A+RWAoAUACx0AyP6M/xC1XwrA1AsAv44yACp3e21lOcASAKwDewFAX/6J/isASMPIBQBvLjPA3sZ2fUS6DA0A/jVQcQQsAKDIATwAzr4TvvdTAtgXAWeTIhAArCkAs4ZjoLYAwP8R47+qCHjqPwK8O5oC4ZG110WXUfQApC/ZnPaBVzUGwHAKyGcA0X8AgBMhAgCpJwB2495ksgi2mUvtrABYrfoBQBwC1gMwMgMACvFOcH/6crMHgGF6mSN5NBwFtwdA3wVuAkUEQAAQMwAIEAGYOADA5WHQohkAhaaoBACKKjCjt8Qv2gBguATQAJCZApC6AOBTXgIMH4AtD4A8B0zpu2HlOqjlJkC/BKqbAc+lAIAAXikyQH/6k49dhp8C8p0xAC/ZqK8IsOHEAIAhoNgDagGA/w4BuIwHXwRCF4sUMJoTACwmAVb+Q+wWSApAogUghP/96Z9k+zrkNhA6WwGw3gSeAGAuhDIFIA3hvwsAsHsb+iAIOpmlAHoqdHQHYNb4PBg+BISfBS3NAwBUCwDsdwEAasChj4KhrRYAHAum7wYFbQCANnL/Y0kFYA4AikC3AGATNPBlEJQXuhtCAAA5FtoUAPEKKCMA1uYA1L4h/OQUABRcQ18HQwczAJ4iBgB7AjTXQErOgqylGUAk4EVUuQ52CQAKrqEfCIEumhQAAKZJeShs0wyAhTkAMQsAVUMAIgcE/NkPgv0fCYOOugiA6+KzbL2KuwBAqADlg0ALAKa1APRPwJ99F+j/UCh0NgTgKUwy7AMbFwGwnQcgqAAAApQpQBcC0hKAMOoZgE9JxT3oY+HQvh4AiAVgFXfSBwIA0f+rDABIEj0AIVXPIeBLEm8H/WIIdNIAgLfDCADrVasQwPivAkC/CEgESe+JcggAWq5hvxoGbfURgCqaZtmoJQAgQMwAAQDAleBWACT1ASDsuRd81wDg/+XQjgB4yUajNcrAbgCABADgvzgJTmolBgCqyCsA/l8PbwcAvhycjEZzCgAIsAVgIZQAEAjoBIAQADg9Epb7vPLf/jXl3CAC4Mb4EQHAsA4kf0MZATYKAMTzwIYAIAA4yQGTNwUA/pfCl7wtALgxvgwB6yX5cKzRSpBAItsGqAFY8v5fZQlACPWbA36VAPi/JKodACAgJN8MWJEvxyIJ2AKwUPiPOUCsAGCkAQD+O8oB3zoA/F8T1z4CUABektG6BMBwIUD/ihkAlZ9L/5dL+I8awAKAkNXE4cuhY2jAF0VCxkVgmQMAAAjoHIBYA4CUgCn85+Ty9fDc66d/xCvi2qcAAEBvjKYV3MIIgJmwD5AAUPktAJCkACkBrP+OqsDXPzkAvi+L7hYA+uGgVWwFwEwPAAhACBg+ANCXHgD/18W3B+CpBCBBCNC3gjNOyu+C0RVhtRGUpgA5AVMvALwrB0H+PxjRdhCENiAlx8LufYD2A3IzGwLwOx0Ao6EB8KYAwOMnYzoHICIA0GEgLQOJWgEA06u/EQcB8N8oB4S8XN0QIQLg76NR7QGAHleGkxCwXgEABQEzUYpvgwYiAXwAeMgYgMgFAJNvzezd/2fjLNbByhxw/aedEgCWtAhYdAQAaoD/7J3dctMwEIUziSkksl3XpZMbmkwyNJTCFC54/2cj0to51W6ktQpVq5meV9A3Z3+9HgFg54HZb4JzOkB6Hbj7WJR20wEwq6MubQyYFATaM5KrwU8AgEQvcBoA+GU4k8n5eejPsgBgK2HRGHDjLKCzFtCQB/w7APTwbDbUDJvB/w2AWcaB8LeyAGBLoVECLsgCLABDLRgjoD0nvhjKAFiwgWAgC1BCAB4+DwB7thZelH4nAGBWZAEWgAYEtIk/Cl74YjlgBAB9HiQMAABkGwcdygLgkALAYAEAgAiY2gdii4ESADgAJ4AAUOtAXgOgDZAhC8QOZinSPw2DqBCkQuCYBVoAMBXSAAABobUw+AFbDD1XByhroRdCy6yb4ZuSANh8SgPgYrCAawIgNhhuJQFyLYj0hAD8LCQMwDwKAHN/FAG5ssCHkgB4mAwAdYNtM6imVsCgxRQArlgnQBKA9wcAjAC9G1z7u6AZUgDSY2l1oH4gQoqSAOcB646CgBMqAZ2AKwCANACCA4gY0E3qBZEBCJnqhQG4K64M0E/ESA0xwO6FdK4SbJo4ASz+EwY+AIyAoAUAgCgBzACgKksSgD28AhQ8EqVbAF2M6y0BDdKAVgHgijC4YkFAt4CAA8wlADXen6vKmQRsyswBdQBgAXPqBcQJOFMEIg0U6R/CwiQAyAQEABdCJgcBj6VOA+ShSN0CaDXMVgKWgEgx2HoiAAaxE6G+zrQCOgAQqwRFCZBvHlROM1g/FatbAO0FHBE42gAIUAAAAV4QcApEAeYAgWOxEIsAJl838PuLHovOdHjyOwDQCgH6UNQScP00CigEUCrACYAEAL0oAxIBMK+zFbQpKQWA9ioARADthq3JAlwqECCg9QUA/HaQQABpoGwGQwoAwgNMvo8DdiWlANAdAFC7QTWCgCXAvpxMBNsIAQCAiRUC4hvxSC+ovmEAmHyVwH1pnQB5ePT+zzQAKhcDLokAbgFtfBrgAAABBIAUCBCXwmJZ4CoAQA4L2Jc2D5LXRvYAQCNgtIAjAUNDwPWDSNpaKJ8ISMEA+l4BYC0ByG8BciS8KzEC/JgIAM2FaxBwnUAAWYBOAP4cj2GARsDqRgHAvMeAWASYAQCVgApBYMgEexcESNpiqLwYpR8L7FQAahhAiIDZewyIRIBpAICAS5+ABgRwC9BXgyQAOBMU7gSRYAAqAO91QKwGSAIAHjAAoBEgRoNRAvidsE4CwM/GryQAmT8RLG4v7OB3gRIBOBIwIkBPpRMARQiQh+K6eScAkH8PXSEC5M8C5TxgU1oX6DEZAOO2xC/RE7RpQAoBAgBshHoZgHv0CABrvP9rArC9ZfOAsuYA26kAgAC3HXTKBD5bAlAL0NM/g4Cx/DsJ/wvk0wAQUNdKAMh2Lw5pYFkp4NdZOgAmSABpCgFAAM8PAuAAJJ4EwgDOlQCZd8OWrBVQWBMgAQAQYCgPQDXgBkMAwBKQAgD6PyAAF+JOkYAHgBrLgAFlOhpb0l7QFzYI9ABYnl5bAgBVxlgTcATYpwEBJyUSgPcHARgBAAIQgGVQOIBWBbyvhUgDeGQA+PLeH6p8Aqgi7BtOQDu1EiAAuAWgBSwSQLSAwjWg4QBkuxZ0KKgG/LVlAGgCADQbHAlwCCANwOtHEODv348IjGWgAACvj/cPA2CyfSCy3JfzfcAD2wQAAGkE0IqYSwbXAQKAgPK1aAOBADkHnosWsAXASgVgBmWoBA/FGMDt9pkAeAQgF2xSPABj4UYQ0GMOIAAQ768DYGYvrX0pWcCOGQAASLcASUBPxaBUYDiEPTBhAcETQRgBKABkSQFgAUUUAigBYAC8DEyzANcRAAGNJOAD5YOhPBB9IMg/E8Trf7x/LATkmQVB+zI+EvspDUACUCUHgaElAAI8xe6G+NMgAQAIECOgURMAMBkAuLstoR2IJiAMQDSCltWoCArVUQgCLgq4lsB13wQICCQCC7EPIq4EMQLE++sAzDJoX8K5mG/MABgAIACKEuAQcACMBHwWBKA5rAOAhRBxKRAAiPeXAJjcAMjLwQ9vvwT8tZUAgAANgipAANUC0gQCRQFfCaBhgFgKZyEArx8AIHcOKHsBhzcYBL4chAEAAEaAYQykEYBDYm28L8AWhIcScFDAAmz9xwjIUASUfjROZoD3WwEAVBmnGAHVQIDxCLCpIPYDwrnAwMfiL3Nn0uQoDkRhBbgUYOEGF7a51DJub7WY7v//76aJHPGEUmoVeEzpHepSF4fz88tFiRiYvxV/yCQAr4sHAPM3AeETgTa6JPDR8lMAAMAJCDEAAjQCJZmAl4AHRkDqWQgmOQgou/gDAS8AyvwrZtI7SwIRJ4B38VcAcgUBAmcSMGeC2gRwr7jDAkAA6wFwGgQGzAxQmgCEuwCFDDCHTi3rBKLtANqTEwCIvjtmAwwAEKC7QTIBvFrAXwfQFCBEgFUBUvzHtIHd58/F/K1gto9wBowKMADAQkonAhYASALIAiCAm4AFgOfJoEEaqCprC5AACAyClA3BDAjkr8M68BDRgujLwaoAQwAISeIMcACQBYreAyrqBhkBDAAPAjVJzwIHDsBMQELfOw/8zCIsA1AAQJ8iCMBC+hEAAEgCnQYEbOrOA1ANcq13kHMcxKfBpZMA+TUhEcz1FplLnAVAdhRhAIQ0f1muWmDhIAB1gH7bLEqBAAAMAQLAXA+FB1itgJRRmAB/k9g1sgkAZoBhAHKJ9AoEuAAACIAJAIFRAKAOwFMiWAigdeCCGUAEBHxmERaC+4wngDAAQlkl9iQCVjtWDYYB0HUgZCcC0wCkjIYAngQOEcyDPg6uBBAGQEgU2WECCAEaCJgE0LWSqYZgHQDA3AupIRwMGnkAAERDADoBtAJxNQDoAMIA5NulB4EwASgE6IZ58gF6ODjgAMZimKENCdcEagKkjIuAUzviPb7zv20YI6AwAGKBVnsEAZII6PvBugYB/+krKYDEp8LGTBAlYExZ4FcWEwGIP84AwgCgDCAxEwgQsDUJMN8yQFqvw13AI9QBALEnQ6Ij4MgIiCj+RzEGACGLAgiECZA2ATQWxOWiuiugS8PCAHACKr4ZMgKAeZ4TeYuFAMQfBYAHgDABIQSUGiCgx8L6iPiPVlYqSP3hNzUEYHgwQB8tNgJOz4yASOL/fBIjARCyBAK3ENDfMg4TSNMQAM6xMGZC/k7wm/eEP9sshm4Q/R8mAGEAuAcQAjAB31RIORBogAAx0OeBDgACwiEGAOZBIKBYAoDIeoGfmaXDN0yE9iz+P8UEAITqCChcJqBCBCwHJtBJXzWPp8J2HvkdgNQQl8VEAsRdlR8zW9dvmv9C7VGMAwDdYFl6CFBeAngeGBKw0wD4GED8TQBgADQOLiYCIOdqBaDLrGeDT5fM1lFMBEDk29JpAmEC5LbQ7UB/wyyKAUTZeRqgL42FNnw7CDkgKgsQr++ZrfOMpeDLObP1/joaAGhZMhNwu4DiJkAdO5nAHw1s4LGTxQBeI+xYD6qwHaqhLABALBaAZnD+QgDpnzeA0wFYlKXbBEh/NQGTgIoIIA/Qx/6AgDhYUWngWQ/DIIgcoJgIgBJzEoA0ML/9I/7TARBb+sa/QIDqhTQABAZ3zRsJnqwAYtNgqwU0d0NwHhCVBYjT74zpPEM/+HHOmH6fxG0A5IWTACCg/ATQLfMoBVAJUHSdCFDk++eEBlshcAByJThABNMgKHcR0F7vbAJP1zZjejuJGwEQCiu5PgTUgAA+EyDRbLiT+RhYDwFU1/2P39oKwlpIp4nxl2rmLVGYwHw/f8T/ZgBEk6arTcIKARcCypBkDGAogCGvyYB2hJqnfxBQFkgBUQKAOoDrcrd24AXZn+X/aQDkctkktNbx0GldN65dPAWBAIaAZoD6AXbSW0NAAbcFDeIPAOAAcRUB6Aa5Dten+7g/in/W/00BQDZ1yl8MuktwOGAhAIUQSPqQbwyR3UP8CADb4R0DMIAYAQABXOc7dIT7fzJP/CcBIJvdg0dpXTXljQgkVU9AVW0s1fzhMLsDQAKIG4AcM8H7lgL7c+bU8VVMAGBR1Pjpu/RjvUpKvTU6BgEMiBPKAxThiv5WgIG7vzkDAgH4ENEBgJsDPC7w9L+ZP8LPzn/y8QCo5nH9ENaPusFh/DgEcLmYNngIDPCb4hIj/pQDYEOxAQD9evYjcN/wP/MFsDAAKtkh8we0TnerOimX4xHQD5LhKnBDvRXwf1H8QcByS4oZAHF6yzw63N4RvFwO/zJ3hr2pwlAYPhFpVjXlemfnF4XJYIoIeP//n7vVwo7rcQJFlj5+mFG3ZHkf3tMqwReEbP96CxC8LZfC74f3GsieCuAV5ta4uJu0ouJHvgaAZOrmsAAQJZgKrYEBDoR48NuMfyoAexXLpW+BN8Ea6GgAUwZoBW6YqJt2QQtBxj/SDADbGQC/SVz8HNTHebexq/4zHvyEIgboLcDaE0Lnb6MAaYE2D/DaMpRAP3ybf2CA+UvGelswh18lN8YAcaBnD4RG+iaHHHoLMF2JC74t3mq9kDYKXHcFgQLj1xhGmPnLL5hjZ4ZSuDEGKO/7XdipCTbhbo97ftv6pwKwN8zfFuGprYFNCxjoN3luJAja8peOLgEQXlYvbbyfT8dHFmzC4+lMwidUJfDeAsw8n+RvWQSoQAcH8HKzdeiLbwQIrX88/KXVEsClEkA+Ps/70+4YhuGmRt097k778ye2/sDDnwqwEJj/UAQq0A5uCRSzhgXyc/6I/afBzqwE7LGf/ihAk7/wn4O3ZjVdFMAmmElDAX2Hpm/g6rsAlHg7bvzbOAILAWYk/6G8LlT2aEDHIrgyozRNUJeENHG+AJA0KcaLv0hS4BYCSOE/HfG2CrQDJOzp9EETEAUo0oUCsCfNxso/S0FhIYDnj4P3Z3avBabKgOldEViN1HTJ3/0CoOSjKJDlAHYC/PNHQ6xqBRi5+Cg9g+i+CFQAyohnA7mvAMZvK4A/JmLCNKYBiuZn6+cGz4xfqvwdIE+KZ87+HMAxAZC/M1QAuaaPtC0R5VMGgH49uEEaV8+Jv4pTAIcF8L0Fa6A9YGhgSoJt8bVJsBagfjkHV4jKbHANFFkZAbgtgC8C1lcB+iyvn2WWAkjNnHNwBg5pnA2a/HjwuyyAL9aMdXYA14gGXINl0OdsgPq1lz8CbpHGdj1QYPrjCiA0g98YusFo+o6YX2DciNAuQKPKnF8A50jLpOo595MS0x9NAHEP306G5UQOUoAbgEK3AXs0DfSjTfwacJEoj5NDpyYoDkmcR4CMJYBop+9uQNorwAlwheu1gV4lGiLU4bMLc7zMObjI9f9JLxZsf9Sg2F6yTwHQ4rEEEJThDngBe3AWcd/4ORjowaCos25+kXzTCbhNlOZlnCRZdqiqraKqDlmWJHGZp9F/9s6gt0EYhsIW2cVrFZSpo///n65iUQ2O+9yQIe3g70IPFZf3YQUFeCScKUAGjCiQp+bZjfcMYAPqYWcA/X+YAGcLkAGjCixT+yaHGHDpEYCJ+ED6DygAAmSfUjnkQboBBS7nzADJ3xEgBPDD33JsGKQ6BUwHsAD9DjC1XXekCAE649cKrMceGb6u323lW68BogCDdbXVdEcmIQAIfa16KJCuBUK6S+sfmgK6yx6sBaxxYJedfpBFCOBc8z49i8Q8fZoKIAcAz/iVGUb+pgAhAM5/XIFsGqAdwDvGDFHhg7prLUAI4OZ/xhjId13/6e8U8WG2tRZMDSGAt+gbV6BoCcpsVwD7t4Vj+RsChADj8WvMs+wlWObNqyCNAsKQAOuf9602NE4I4PP6DE8HbqoCFH5u5MWNwXqASuhCiwu9RwhQhshQjmrAfJ2BAnizSDSQLtsmebn8V8xHwkOArAUo5/OrwKIa4Y1NfeCAwPWgML9gzQQIAST8lORn5e8VSNP8AEwBkcA3wZn+FUKEAD/snd2qhSAQhUFDOKYalfr+b3rQOTKo1hSdrmwB+4fN7mZ9zkjkGjSI9/XPBJjF2n4VoCkoU8qntBmA12b1i+y/620BPgAI/99iwCABNhFAMCDmVlPk4KQ9zOVQy34H+ABA99H/1xHgQACzWARQdB2gu0Inny4/KDZPNQkfAJX97yHAUZEAzkLoMXDy1H909YSEw6TaPNw85RMGJQCCDwDTAkDrgfMVARozgFTNAH36YyYzCIojhgoAiLMsvV+ZdNJCfv2+MCvFNCoAaNEF/33UbQoOODLGLHUEsETJKwwUHSIXiPTDXJwzzsmEMLRCa4/DrGFLavwW5DQgANcWvi91pxKc1hJfxkCqGgJqRjCt6D4s/7TeYSiV9sn8LIw629U0JACE+a0uNwPqwnsA2YqB5wQ4EPhvw7JpnqNw0fL2G2diJABIl3xfF/cD9KVXFnAcxFEvqIMhXes1vJXm538rG3YfW87laItxAEgEEJY/QoBEa6smgvULgasFHmfXXSOJsmGLFR/9J2U2N1QFIOynCOBPANBAAAv9VtC5RSDbsADReI9Sdon230xCN2wepwKc2a//RBFwHwC8+sqSeuHADQRIgkwIwKfjkLm4/MF+czvmyjrxM0QF4Fm/7J0BbuMqFEUlaCMlDZgAJev4+9/cr5+x74OEAK4zGmdyNHFMR0qk3tOLbZr6JnerGOsMkAX42zgxAQOuAwcG9HIeRMx/7R9AFqePf6UB5uitdQzLJKgY0C0ADDAikikAOg2Y7jBP+SP+dUg3fL12AyARhJ9gcavntCSYBJ0CZDOMvVUgN6DWAueR8SkO6AZzwoVK/P/seQEaYMwuxu/qUCMANMEaAdjdop0XDEgAcDhwPsWo4/hEo5lh+jcinNT6cxPCcHxJAaaI0PxNpHd9J4oGtORPKG+EQA+IK4AB4EQPYqBNTsz/czPC8JINIGUl/FoVhBm5UgBLOKvu3SoODBFEzlLHPrgKd9n6zx5+HV9MgP/G4idWOZAZIPsF4O+unBkdEKbmAN1AmAQoQss+Un9ujJbKieFwfB0BlgwcBOirgfDYgMohYGKf9d6bEcHJDQDn+8nT5iqMRf5ba+CGw6s0wFLBa7EqOS1cJ0B2Q/GyA3naI9gDwhgUwDPQ9vr1SgK4X2BV2YDKSWA++/gFI4zILKAjwzT/AmLMHwXwJLT/fhUB3C+xCgLIhgIoCuDMnL83RqAImARL0f/spaFjj14l6M+n404vIIBCAOux9ztANs0ADnjBpgHj0QLTnSQpZiTPDRDAj1j5+Sdwh7cAE0oFlZeAbBLAcYzwC8bgaOB6/j5dFxk4sxoRE29Br/pW/1bXhRYfexYA+f8aiwuDRF0AFADwQngOKUA9cCYBiKz4Y/K08S4SdHv4xGoHwuktQMTCgEfkMwDHGxgABwRIrxUKhjHeuwWpy3HHZ8SfG6A7S+D4FiBVoCd/63IDzGMDAARgP/vW0uauALqDHgnc134FQAIbYUOQobcAwJi2dw0KmPFB0KxP2AUldTn/7R0Ih70KgAi2VeABhfwhgDHO55g0eQpfUPYxfov46WhE6kr+2zpwOb0FYCgY0HEKAAO8gwLsugAXgE4RPBMgEpcnbhtAg2d4oE9vATihmH9dADIgzX9EGIRPGxLgdo2aXjwVQG9BjwFvAVyo5Y+3vhVAULRZBUyZkwIkg6cCKOQfpO7P/xJZp4C+frwFSKeBeD7AXWgUgAxgTMnTgwQY8cbDAOQ/bdcIcFlgX+hRQIrD3gSwVQH87wyIlH4ToCyAwbKAH7OOtS8Ig0PATIDxtQOh6/FP8V7mAeBf6GsBc9ifAA8TZy3bjQ2SK4BBkwBzCRjDrwlDgNmRQv7hUs8fxAFgY53xEpeGIYB7jgC4JMCQjQKwy/pmQXADCgLQK8e3ojmgGn7rp1w7FAjnPQlQ6Xw/wsfYaUKFhFYBYMCcPuIHbA6w1qIAIvpx/PKWjQzQ5mM3AjgizRjZRwF85oP37dVgVbsAyB8GmIi4AdMEE0AxAWRf/JAALkyD/olAfe9NAB5yzLkoAHC9BrSdBQpQCh+GEC5eA7IVAdD6bZ94xX6nAXLYqQDeQwAGws9ZrCnpMAbTJ4DgIP9p5fdKm5/9fBbgAqhApJktebZ/7h17MICx5xVCCJD8nFPB95D0Au02GfDwECBf7sOIIybSwwCcDGQVgDBDlerBQZsB5rgTAXjmawTgA0gBaJnmvgAOYI5J88bohrkC0AHzTKDmIFH8tfhrH4DnGrSUwM//mOMeBEDoG4AqycvANgmAZT8EPo9gQOpAthzsYIAMQVL8DeWP2qBncLcLdN0BrakDdiDAsyABgK0J4CNz4IAN818Gzg8EcEmAfV5N1vJXWEVglGeEhhrQxPXvF8ADYLZygGPrAqAAksTjYKAN4AZ4n68LLc1OiT3KX5WARTcaVK8LaOIy7FSAJxsAAeoFQEnH5yGl0AEogSnE2tGfekBxLqisEumIPO1IAIOVlxESwfy6GRyLBd/Q4ieCDM9/uMOZHokC9EGgfGXIjorBgHr+VjGshQJlB8oG6Bn19ZcL8D9357bbRgiEYYmuLC3ZdLd2bN6j7/9wFac5MkCaXtD8cvaArNzMxwwMY4BMW31I/R8asClevuoIcqfsAgDmtwCoPw1nCFACcCyYYkGkbqb7x+/iC33rJQpMAEBuXxuAa1a2N5gngJRsGAA0+n+x9pE+aVcIECDgooQTqCCkvj3s/knlGd6wzULASgqQ9MOxNgCBrK26dI/KTU4BABCkx3kGMAhU2Q4gOG5/Ie8P2BSoPRaUE9BHtmPP/CB8QzUdAZ0QUAJ+MgDi4TuPbWkAVMpVld1lKLQyASw2zBOQS3il/S+1OxBu/FTMz4ROAH0A1gnTasE7WS58vUv7K2kCFEIVAIJAtjxzAPErYWUAfrsZ2TEBxorXNUsAAvCo6tr/GOwMprwAMKBTkkWJARLxQSMQhgTgFfPP77f/HQBNgtPx4VMEiBygtD8d7/muDoqAg/lAvGBZKQOg3OiIf15GkhAJgCtmoF8/3NoAhODCJyFAGpwTAJAHnldAAjQAYH97z/DnEx6KfG3JABQvABJAMgCSOvYHb6FlDgWo6QUA77eVAQhJeehFV1yndTV8QSUCWzgBGP/t/k/NXy1et4a+MQTYlDAQUCUBdSuifIcWaf4iKw5YZ2e0aw/iN9zCAAQhh08OwRgJXIElHgWiWva3ABD7w+OZAIKAUy8UUgh6tc4aANsJKAbg+BntABIA97elAZjXCIP8KXL1npskAXIFUAUAfZZguqHADcB0IEeCk2aINQB8YKAhEE210ZgY2gj8KgBEuf2bABCynaZigmO/5YIZGnXC6YWnfxsbA8c+bwu8gD9oKHB0YogAaBo+KzNJmCNBsrwC4HXuqwJwSs2BEKamC7LloyrFXvGzX25/f4xOC1KBAAhg/sqYoID7wTs0zxMg48ArIpAsXwGoh2IAAWsDgF606OxHhKFL0ASwCZoq92L+3zxFViGA8wEyJRDkSYHNR6uYrQInIzmY/YAEIO6H/3HuSwNgO4KhX3DTYwSRQ2pU+3H/z+3/po6JZGEgQSDDgEBAA2Cr6wOAAJ1g5iXlCAAQsBoAsLAmVRwA34P1a8GBjQup+VX31wD0DgYtJwipOEABaIWBj746PuDePUslV6AQAO5xpOOXBOAgOpsshNPQDAUSCFXkH9D8uv8/pfW3rdz12bBR5iIRpIWmAeDTVz0MaBIgqsgYANflnksCUAbQ6Q9W2mcVLA6gjF9s5nY5rtZu8Dr+08OhN1BtVQT4TDILSqNU9SCL0fQDGgBBQAYgJT6T47stCIDnAl+QLihoYAqwa+uMnCjy7tnfa/sXo29UciwgVgnnEchBos/AmIB0h4LkqFcBIP/rsK0MAOrwXkaEA2XFg8kZJAKgza/9P5rfkAwEjICMHQJgMDBbDtMhoHXEHgHgcWX9fXHIvm23fysFgHYF+cqMDw+2ZghgLdr+z679932PF2zgQwG2TJzVB+CaVXMwIAG4KwDAAcQg8Ie2c1FuGwSiaKoozEjGkevIQXZ+o///bRWg1a58gQGCTz15uJ1pJvd4WRDItfl/v3/cfxyPx2NpwGMTwDfQdLkNedqLI2WIa7BVg6QN/HdT1uufwx8G/uiQ84GnyYAUYCMkQL0CNB8QBx79184AeiuumRZHa+eCw/unF+Dx4+L/82sWFkAy3mISwBPEFMNIH0AImmgyOjT/k/FT9IJ+49kAPQZmgz4FzL/OAFRg31pI7YAQgBh/JcDDKrA4WgmgbvTm29IC/+EYOTohmfIwpABMMPXE6UcEGBA5CpAD1AcIAeLLwnT9GijuBr/PdNHIyWA1cFzdLdCJyj5wOK8C3G38jQX4pwTWAnwbZjYB0UKFKVcDGz+ix9DyD8Zva6gQwD24GZSdIAvAReCwtZWDLywDMxYBEoC+sx5Q/ixAdQkYvt6tABZqAZoKgLAJ7EJKBGoZQ7PHNN6dMZo/CmAfkogB25IGnyLdBPAPFoCpd+B62OfkTNg2Dnw9CWBOVQLM54+7LwG7AEtjAZBbwIJwlyBHik0CMW1wSTyJQKrQxILiT4z/xJurAjASsAAKG0G4GhEe/bsCBdAAuZlonyPALQ+mvkqA69/VgK0CeAVeVgFQA0UiSCeCArAJHhvC0+QR9HDlw4Prf5HR/20lbsBmKQrQ7RkHmz9xS5oKBc5X8Q09B/e8MEafKgS4rGPA2gbefQl4tBPg5PHX2lQKGY7oFQH0QfP8kQYFzQhvCtq/N0e8BJAAbABxAQPoud2RjYJxgF/2yCyGAN//qBoBvmkiSAY0EgAAD2IcBoZc6KVP340Sjh/yRwE8qRKg8bKQzHUGATwsQEkRQHijiRBgcqgKAc5/P2kMsDQVAFF5JtykBiVQ8NH44/lvoYMAK6d+bwPTAuxL//YbHzrinSAqDLDhX2YSgPKvMmDovq77WtDi/7RpAnv6zYXJcAAZi8Dqn379vzH+ayGABdpAY6JjQJdNRg24Bu6xSockOP86AwZzmXkMsCwtBZBENFgfhS64TEvix9d/On8UgBcEYXdIJygXIF0DWIAZBXAKQP5TYSc4TKabv60A1AVaBdoIgJz8dddwOXAyxIeHWwR0wStC6ePmn3D9P+KfYwGwAuioAEXxc3eIBhwiP95s0++L9gXAmEkyls0G/buhiyZgWV4gAIoQbA6cAJ6EBX4C6T+RArzMDMTjx/yZfWmwRwNIAFp/RgEqSRtwFAC3PBPjUCLA6EvAthZECjQQgFqoJNFOkWpCGrGQgKFD/p54/mhATAA2INwGdM0NmFeid7yajmhVLMDZLwZR/G0EQOLVANkjK1pQcp/4acmJCOePYAlQUAKcARhh18oAzt9BX/HYH8pfF7UBN206+3bIdzbAOtBKACRdDSJlQWVxEx+RzPrPsAD+hyYBxtC+AKY2/uDJaCr8G4cDj675s/mDASWDgBpNZxeDnAEPp8DSWgCkH1LtQUKCehLzfwkOAu7fixJA+wLgrFAT2B9pwEywAMb47i8kgFYlAkxdN5/fP+/OgNcKgPQpYiNDTfaZ+aMBVtZhgCYAKkAaOiBfAhcB3GnSdVj85eHnvkgAWwL2S0IrrxUAyW8Ukaz0s6b/yOARAuAYkHV2yUisDTlcUlvNuPvXAQHGUZUIYLrL2gZ+ijYArgk3FaC9CDZnLg00l+TwOX58/acQArABkc2B+JLntA1Sq4D9mvI3Lu5QARjHvlAAux7MU8E2FYBX1AqpLgeUOwLxFwnQswDSgClhgMkhqyG0D/nifxZAYwFYUWUC2Pdh+ziUgF8LAL9KoKJNPOWrgOnL1DH/9BiQmAhimCabzK6QDaCrTCSABgHoAHyfK8BtnDp7rP5bjAFLCwGAwT5cX1VfDJBE4rHCf1jryy4BsX1BOBMwbQ3o2AAqCUYKoKECWFSBAMYKYBeDVtpXAITW2dt6IFQQcvQM558N//8wBrABIkxDY38J2QbQMiMLoEGAfRvcbSgQ4LIKYBeDyADqApsKgJRasD5y8Aog5fnzz5cSYBJZmgByy7I7qlzXEITyTwgw9gUCdO492A4CLC+sAOhBgQq0LkOfMxmYXwrABmgwAJI3puC8Y5fAiFsgGBaAfwiHFgKoEgHmr69VADbg9QIglfPGwWabSh07/9eUAAw/4yxL/l0wDN8YS+Z/NEB7xoIxQKlxmsw8rwJ87gIsj3YCtLcA2dMOVYdWAsBqMBmACky5GJCgA/B+SdwBih8CDVCZAty0LQEzC/Dz6grQqD1AegGf9UMqBICJoEUOwKUC4KFXVgAnFUcBfENBAowgwLYvJqsLOCml3aaQq10N/mgoQAOoOWgFR1orgIISoCcinv9+biF5zC1SCuApYyYqACDA9J+9M+xtHITB8OmOVCJw604bq6b+//954LpxwQaTNN1WiVdbV3Uq/fA+NSZgZyEgRJk+AOY0XpwD/iQAor4ZAB4L0sNOIKCrGyMAJ4D5mbW/As9JagW8RIDwCu4C0wFocRkYdbCdABwTAHEduMwB3wKATsJ90qzXCaDT4XnLEFn+8lMX38kRFgacievqYgbxOYA6YYaONMAAALAOSMuACQGI+mkAEAarUcC33JmVspVgg4Dym79YxaUgwAA4IQCeA4C43VRDmJ4IAJeCXt8jALQQ/LEA8HPb/QHgIQDM5CKJjIcfL5S61sqeewAA+ZkRsMBGzXBtBwBwJAABmJ4EAD4z/Nrde8ZYXiW4IFD0wPPHxfq2PJIgZAV1Ak4NAMh/CgGuAwDcEYYq0Wl6NgDIqWqWcN+4MgCBCMh7WaBWlbLx2aDRTZkBgGkg/+QUAZzVAQgEwJNFAK58ybDPiIuKGjFGAGneID4dNAHIPwSzTUaAngUYFwHwcDb8AsC0MwDPLzkEIANFQJftD6jleb0dypEpt54BgEL/WRLgjO0C4HhKxQG0DHh6AOzeAPA0EAmoC0qWaprl9/qj2DeVN0ArMBPjDwBgNADcAaaQ949/GAF2BuD5JcwBiAAYWbN/EcCSFaw0Cp7h8gADgJyHxwYA6SlFAAwBKgA+LgQ/4FwoRgDR/wFAQQA6KZlP0vofzHPgVspbyCBxBmDzz0oA5gTAn5dlCjgzAAYAjIAqAuR86GmDUTZPBAA0sURDyAAQgDYBJiUBBADtBw4AxJVgUkZA3gw1LO4HxX0+gMyAvx8AY60CAEwBcDIcc4DWHDAAMEUM4DqsU2D9cHyrvf4VgNCeAjoBcLgdBO3C+G7QAIAT4JCAQpTxbRGR1Oya7JMIgIIA3hrJAQANApxxDmsD6Erg+TwAuBXrHWqghcEWUS8MSflMUAEArvq0AOARoEGAWQDAzaBpAKATAAa6TsPxUSpZqkwHt9bmEPgLAOh1kPwnhQMmgUnKFJBufvSRAgCdCaoYPABIQl8V550uKZTwhWUOwOw7AQhdAMQPRADA/nEdQCeAgkANAa1UTYkFIUoiwC8AzN0AMP95BAizPyUAMAc4j+sATLZCgNAJ15X+XwuU8KmrNscpCBCS/DoA+CJPAo1VADAGloG/6UDIeUSAHgLQMxYJyPguyRQEiQDyPj4w+ZkHgG4AoD7wA1JABEDzeQBg0DDkgMmskYhAkQ2i7V4yG5ngAaADAHcDwIQpwACgTYBVa9S1OjWOgMkZCIEvCstve+AAlNcBtRQAAEi7Qad0HuCzcwYYAJCDiv+yykH4YEIUUAAQG2SD/zoA4QrANADoJsAKtrW85oVsKBkCKRMgcQD4978bADwXTBEg+j8A4FrZtsAqMvWRyhhQUdgFAAcAwKVg7TzQAKCTgQ3dcMqhynuWVk4dKP5rVwEQgBABeAUA0P8BwBoCcus217SWPIk7zmjw3gDMCACdCB0ASLIPlJAYOmG/GUM//uIzxX8NABdmj1NAFAWAAQCT/RJxAHCPGR3PACiThPgKAYA7wU0AjLkAkOoCwP8vA2AQUB+QCCAAoqTDxUhFeR6NdgLV28e7AwJwbROH/j8cgIFAczQigGUDdDMEwkC4SY6zthuAePewFxYABgAKAQ9mQSbg5gYJUoJ4kRIASBaywBgB3uDOQQOADj3EenlgtlFMJQYXl3v8bzJgXVQE4DUFgOT//gAMBHreWfm/1hE9LCoBcHQUTAVgPuJ9gyAA7AbAQGDFAJX/mFUAoPdJdBi0YwpIAKQ1AAWAAcC9CGwZQ3rZuKQOAtB+5r8OwAEA+Deh//cCMADYPFB8yl815YkhJwNA9lMC0A/A6e3lcwCwAwKbh+KNjBgBdNo0B2D5S3JrAIDd4L8TSwE3AvCfvTvsTRAGwgDMWLnkOBUCQ5j//4du7dK9CTTT1iZr473GxE/9co8nKSctAECV/0UHgL8FyF4AHSKo/4MAhvG9w2OiFUBhXeYAQO4MpGMQ6H7YbQPMF1wCKICi2gl6gBDJHoAcqh9Z/4aNvQZ0AFD/fwSgORaOMYEq5OqLbhA+IC+iAXgAn6UC0EAAiQgAiIQA4HTcR9emZRh/AGzFAlABNv7rbz96DE5CUv0BgE7t3OUGwE3mqADG+cqYHRUBgMj6A0Df2o3gW14AnJeAAmAOTA8TgvK7+kcAWPr1imvArADyIVABHBAAA7vDMZs4AIMDsGUG4NLkiQaTQgED+8Nxm1gAkwfwVioATQgAYpIBsJ0JnAGg2I0gzVFAev0RC2D4AACkfAAqwOzrH9912XwDqLYDqAAk9Xa0IXsvoOIOoAYYSQPQThYAGkDBADSMBAE0CQDGswdQVQdQAgEACavJabxefjeC7EsB1PXQMkZSVpO+9TuBKH4lAFRAYvkRBgC0gFcCoAOJ0q9T5ycCcSVYFwAlkL6QLOvZj4TW+BOgBp5cxdAwWQBWgHtvT+RWJQCVZITIiAgtGDVMyxd7d4yCQAyEYTSFzbDH8f53k6AwRALZUmfe18jW/yOFCxsA9J8ABIAAEAACQAAIAAEgAASAAIjvxxhtAiBm8f79PHbbH4CsDwAAtp9w7bE/AHni9wQAQMza7g9AZL0AAGB/AKLf/gDYHwD7AxBZv/0BOFzoF48aAACYM0asf/nduuB1lAiAufhyWddp+2L7A5Cz99ofgOze+GX3B2Ac18+uq978AIy7AK5a+wOQHQ7+2vMDsH53b5m+w/wAJIF911y/7PwAZHsCc/wG6wOwPwii7/heBo1fCwABIAAEgAAQAAJAAAgAASAABIAAEAACQAAIAAEgAASAABAAAkAACAABIAAEgAAQAAJAAAgAASAABIAAEAACQAAIAAEgAASAABAAAkAACAABIAAEgAAQAAJAAAgAASAAAHiOxuk5XjM1GcFgFJgCAJU/FGgcW25VAAAAAElFTkSuQmCC" + } + ], + "samplers": [ + { + "magFilter": 9729, + "minFilter": 9986, + "wrapS": 10497, + "wrapT": 10497 + } + ], + "bufferViews": [ + { + "buffer": 0, + "byteOffset": 76768, + "byteLength": 25272, + "target": 34963 + }, + { + "buffer": 0, + "byteOffset": 0, + "byteLength": 57576, + "byteStride": 12, + "target": 34962 + }, + { + "buffer": 0, + "byteOffset": 57576, + "byteLength": 19192, + "byteStride": 8, + "target": 34962 + } + ], + "buffers": [ + { + "byteLength": 102040, + "uri": "data:application/octet-stream;base64,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WwBcAFQAUwBdAF0AUwBeAF8AYABhAGEAYABiAGAAUwBiAGIAUwBVAFMAYABeAF4AYABjAGAAXwBjAGMAXwBkAGUAZgBkAGQAZgBjAGYAZwBjAGMAZwBeAGcAZgBoAGgAZgBpAGYAZQBpAGkAZQBqAGsAbABtAG0AbABuAG4AbABvAG8AbABwAGwAZQBwAHAAZQBkAGwAawBlAGUAawBqAHEAGAAjACMAGAAUABgAcQAZABkAcQByAHEAcwByAHIAcwB0AHMAcQAlACUAcQAjAHUAdgB3AHcAdgB4AHYAeQB4AHgAeQB6ACQAewAlACUAewB8AHsAfQB8AHwAfQB+AH0AewB/AH8AewCAAHsAJACAAIAAJAAmAHMAgQB0AHQAgQCCAIEAgwCCAIIAgwCEAIMAgQB+AH4AgQB8AIEAcwB8AHwAcwAlAIUAhgCHAIcAhgCIAHkAhQB6AHoAhQCHAIkAigCLAIsAigCMAI0AjgBNAE0AjgBMAI4AjwBMAEwAjwBBAJAAkQCSAJIAkQCTAJEAlACTAJMAlACVAJYAlwCYAJgAlwCZAJcAOwCZAJkAOwA9AJoAmwBJAEkAmwBHAJsAnABHAEcAnABIAJwAmwCWAJYAmwCXAJsAmgCXAJcAmgA7AEAAnQA9AD0AnQCZAJ0AngCZAJkAngCYAJ8AUgBGAEYAUgBFAEYASACfAJ8ASACgAKEAogBcAFwAogBaAKIAowBaAFoAowBZAKMAogCVAJUAogCTAKIAoQCTAJMAoQCSAKQApQCmAKYApQCnAKUAqACnAKcAqACpAKgApQBvAG8ApQBuAKUApABuAG4ApABtAKoAqwChAKEAqwCSAKwArQBoAGgArQBnAK0AXQBnAGcAXQBeAFsAqgBcAFwAqgChAHAArgBvAG8ArgCoAKgArgCpAKkArgCvAK4AXwCvAK8AXwBhAF8ArgBkAGQArgBwAJ4AsACYAJgAsACxALAAsgCxALEAsgCzALQAtQC2ALYAtQCgALUAtAC3ALcAtAC4ALQAuQC4ALgAuQC6ALkAtACWAJYAtAC2ALoAuQCzALMAuQCxALEAuQCYAJgAuQCWALUAuwCgAKAAuwCfALsAvACfAJ8AvABSALwAuwC9AL0AuwC+ALsAtQC+AL4AtQC3AL8AwAAPAA8AwAAOAMEAwgDDAMMAwgDEAMIAvwDEAMQAvwAPAMUAxgADAAMAxgACAMAAxwAOAA4AxwAbAMgAyQDEAMQAyQDDAMkAyADKAMoAyADLAMgACgDLAMsACgAMAAoAyAAPAA8AyADEAMYAzAACAAIAzAARAMwAzQARABEAzQAVAM4AzwDQANAAzwDRAM8A0gDRANEA0gDTANQA1QDWANYA1QDXANUA1ADYANgA1ADZANIA2gDTANMA2gDbANsA2gDcANwA2gDdAN4A3wDgAOAA3wDhAN8A1gDhAOEA1gDXAOIA4wDdAN0A4wDcAOMA4gDkAOQA4gDlAOYA5wDoAOgA5wDpAOcA3gDpAOkA3gDgAOoAmgDrAOsAmgBJAJoA6gA7ADsA6gA8AOoA7AA8ADwA7AA1AJwAtgBIAEgAtgCgALYAnACWAOwA7QA1ADUA7QA2AO0A7gA2ADYA7gAvAO4A7wAvAC8A7wAwADAA7wArACsA7wDwAPEAKgDwAPAAKgArACoA8QAfAB8A8QDyAPMA9ADLAMsA9ADKAPMAHQDyAPIAHQAfAB0A8wAMAAwA8wDLAM0A9QAVABUA9QAiAPUA9gAiACIA9gAmAPYA9wAmACYA9wCAAPcA+ACAAIAA+AB/APkA+gD7APsA+gD8APgA+QB/AH8A+QD7AP0A/gD6APoA/gD8AP4A/QD/AP8A/QCJAAABAQGGAIYAAQGIAAIBAwEAAQABAwEBAYsAjwCJAIkAjwD/AAQBQgCLAEIAQQCLAIsAQQCPAAUBBgH3APcABgH4AAcBCAEJAQkBCAEKAQsBBwEMAQwBBwEJAQ0BBQH2APYABQH3AA4BDwH5APkADwH6ABABEQESARIBEQETAQgBEAEKAQoBEAESAQYBDgH4APgADgH5APMAFAH0APQAFAEVARYBFwEYARgBFwEZARoBGwEcARwBGwEdARQB8wAeAR4B8wDyAB8BDQH1APUADQH2ACABCwEhASEBCwEMAfEAIgHyAPIAIgEeARwBHQEjASMBHQEkASMBJAElASUBJAEmASIB8QAnAScB8QDwAO8AKAHwAPAAKAEnASUBJgEpASkBJgEqASsBKQEsASwBKQEqAS0BKAHuAO4AKAHvAC4BLwHqAOoALwHsADABMQEyATIBMQEzATQBNQE2ATYBNQE3ATgBLgHrAOsALgHqADkBLQHtAO0ALQHuADoBKwE7ATsBKwEsATEBOgEzATMBOgE7AS8BOQHsAOwAOQHtAP0APAGJAIkAPAGKAD0BPgE/AT8BPgFAAT8BQAERAREBQAETATwB/QAPAQ8B/QD6AEEBQgE9AT0BQgE+AUMBRAFBAUEBRAFCAUUBRgF6AHoARgF4AHcAeABHAUcBeABGAUgBSQGIAIgASQGHAHoAhwBFAUUBhwBJAUoBzgBLAUsBzgDQANkATAHYANgATAFNAUcBTgF3AHcATgF1ANgATQHVANUATQFPAdUATwHXANcATwFQAdcAUAHhAOEAUAFRAeAA4QBSAVIB4QBRAVMBVAHoAOgAVAHmAOQA5QBVAVUB5QBWAVIBVwHgAOAAVwHpAOgA6QBTAVMB6QBXAVgBAQFZAVkBAQEDAUgBiABYAVgBiAABAVkBAwFaAVoBAwECAVoBAgFbAVsBAgFcAVwB5ABbAVsB5ABVAQABXQECAQIBXQFcAeMAXQHcANwAXQFeAV8BXgGFAIUAXgGGAF8BYAHbANsAYAHTAGEBYAF2AHYAYAF5AGEBYgHRANEAYgHQAGIBdQBjAWMBdQBOAWIBYwHQANAAYwFLAWQBIAFlAWUBIAEhAWYBZwEVARUBZwH0AGcBaAH0APQAaAHKAGkBaAHMAMwAaAHNAMkAaQHDAMMAaQFqAWsBagHFAMUAagHGABABCAFJAUkBCAFFAREBEAFIAUgBEAFJAQsBIAFHAUcBIAFOAQgBBwFFAUUBBwFGAQcBCwFGAUYBCwFHAVgBPwFIAUgBPwERAT8BWAE9AT0BWAFZASABZAFOAU4BZAFjARcBFgFlAWUBFgFkAU8BIwFQAVABIwElASMBTwEcARwBTwFNARgBSgEWARYBSgFLAUwBGgFNAU0BGgEcASkBUQElASUBUQFQASkBKwFRAVEBKwFSASsBOgFSAVIBOgFXAToBMQFXAVcBMQFTAUMBNAFEAUQBNAE2ATQBQwFVAVUBQwFbATEBMAFTAVMBMAFUATUBNAFWAVYBNAFVAVoBQQFZAVkBQQE9ARoAbAEcABwAbAFtAWwBGgBuAW4BGgAbACcAbwEoACgAbwFwAW8BJwBtAW0BJwAcAC0AcQEuAC4AcQFyAXEBLQBwAXABLQAoAHMBdAEzADMAdAE0AHIBcwEuAC4AcwEzAHUBdgE5ADkAdgE6AHQBdQE0ADQAdQE5AHcBeAE/AD8AeAFAAHYBdwE6ADoAdwE/AHkBegGdAJ0AegGeAJ0AQAB5AXkBQAB4AXsBfAGwALAAfAGyALAAngB7AXsBngB6AccAfQEbABsAfQFuAX4BUAC8ALwAUABSAFAAfgFRAFEAfgF/AX4BgAF/AX8BgAGBAX4BvACAAYABvAC9AIIBgwG9AL0AgwGAAYMBhAGAAYABhAGBAYQBgwGFAYUBgwGGAYMBggGGAYYBggGHAYgBiQG3ALcAiQG+AIkBggG+AL4AggG9AIIBiQGHAYcBiQGKAYkBiAGKAYoBiAGLAYwBiAG4ALgAiAG3AIgBjAGLAYsBjAGNAY0BjAGOAY4BjAGPAYwBuACPAY8BuAC6AI4BjwGQAZABjwGRAY8BugCRAZEBugCzALIAkgGzALMAkgGRAZEBkgGQAZABkgGTAXwBlAGyALIAlAGSAZQBlQGSAZIBlQGTAYsAjAAEAQQBjACWAQQB6wBCAEIA6wBJAJYBOAEEAQQBOAHrAGoBawHDAMMAawHBAGoBaQHGAMYAaQHMAMoAaAHJAMkAaAFpAWgBZwHNAM0AZwH1APUAZwEfAR8BZwFmAWMBZAFLAUsBZAEWAWIBYQF1AHUAYQF2AGABYQHTANMAYQHRAGABXwF5AHkAXwGFANwAXgHbANsAXgFfAYYAXgEAAQABXgFdAeQAXAHjAOMAXAFdAVsBQwFaAVoBQwFBAQgACQCXAZcBCQCYAQkAFwCYAZgBFwCZARcAGQCZAZkBGQCaAWwBmwFtAW0BmwGcAW4BnQFsAWwBnQGbAW8BngFwAXABngGfAW8BbQGeAZ4BbQGcAXEBoAFyAXIBoAGhAXABnwFxAXEBnwGgAXMBogF0AXQBogGjAXIBoQFzAXMBoQGiAXUBpAF2AXYBpAGlAXQBowF1AXUBowGkAXgBdwGmAaYBdwGnAXYBpQF3AXcBpQGnAagBqQGqAaoBqQGrAawBrQGoAagBrQGpAa4BrwGsAawBrwGtAVUAVgCwAbABVgCxAbIBswG0AbQBswG1AWEAYgC2AbYBYgC3AWIAVQC3AbcBVQCwARkAcgCaAZoBcgC4AbkBugG7AbsBugG8Ab0BvgG/Ab8BvgHAAaoBqwHBAcEBqwHCAXkBwwF6AXoBwwHEAXgBpgF5AXkBpgHDAcUBxgG1AbUBxgG0Ab8BwAHFAcUBwAHGAaYApwDHAccBpwDIAacAqQDIAcgBqQDJAakArwDJAckBrwDKAa8AYQDKAcoBYQC2AXsBywF8AXwBywHMAXoBxAF7AXsBxAHLAc0BzgGuAa4BzgGvAc8B0AHNAc0B0AHOAX0B0QFuAW4B0QGdAdIB0wHPAc8B0wHQAdQB1QHSAdIB1QHTAZUBlAHWAdYBlAHXAZQBfAHXAdcBfAHMAdgB2QHaAdoB2QHbAdwB2AHdAd0B2AHaAd4B3AHfAd8B3AHdAeAB3gHhAeEB3gHfAeIB4wHkAeQB4wHlAeMB5gHlAeUB5gHnAdkB2AHoAegB2AHpAdgB3AHpAekB3AHqAesB7AHqAeoB7AHpAewB7QHpAekB7QHoAdwB3gHqAeoB3gHuAd4B4AHuAe4B4AHvAfAB8QHvAe8B8QHuAfEB6wHuAe4B6wHqAeYB4wHyAfIB4wHzAeMB4gHzAfMB4gH0AfUB9gH3AfcB9gH4AfYB4gH4AfgB4gHkAe0B7AH5AfkB7AH6AewB6wH6AfoB6wH7AfwB/QH7AfsB/QH6Af0B/gH6AfoB/gH5AeIB9gH0AfQB9gH/AfYB9QH/Af8B9QEAAgEC9QECAgIC9QH3AQMCAQIEAgQCAQICAvUBAQIAAgACAQIFAgECAwIFAgUCAwIGAgcCCAIJAgkCCAIKAgoCAwIJAgkCAwIEAgMCCgIGAgYCCgILAggCDAIKAgoCDAILAg0CDgIPAg8CDgIQAggCBwIQAhACBwIPAgwCCAIRAhECCAIQAg4CEgIQAhACEgIRAhMCFAIVAhUCFAIWAg4CDQIWAhYCDQIVAhICDgIXAhcCDgIWAhQCGAIWAhYCGAIXAhkCGgIbAhsCGgIcAhoCHQIcAhwCHQIeAh8CIAIeAh4CIAIcAiACIQIcAhwCIQIbAiICIwIkAiQCIwIlAiMCJgIlAiUCJgInAh0CGgInAicCGgIlAhoCGQIlAiUCGQIkAicCJgIoAigCJgIpAicCKAIdAh0CKAIqAisCLAItAi0CLAIuAi8CMAIxAjECMAIyAjMCNAIyAjICNAIxAjUCKwI2AjYCKwItAjcCOAI5AjkCOAI6AiwCKwI6AjoCKwI5AisCNQI5AjkCNQI7AjwCNwI7AjsCNwI5Aj0CPAI+Aj4CPAI7AjUCPwI7AjsCPwI+Aj8CQAI+Aj4CQAJBAkICPQJBAkECPQI+AkMCRAJFAkUCRAJGAkYCRwJFAkUCRwJIAjwCPQJIAkgCPQJFAkICQwI9Aj0CQwJFAusB8QH7AfsB8QFJAvEB8AFJAkkC8AFKAksCTAJKAkoCTAJJAkwC/AFJAkkC/AH7AU0CTgJPAk8CTgJQAlECUgJQAlACUgJPAv0B/AFTAlMC/AFUAlUCVgJUAlQCVgJTAlYCVwJTAlMCVwJYAv4B/QFYAlgC/QFTAkwCSwJZAlkCSwJaAlsCXAJaAloCXAJZAlwCVQJZAlkCVQJUAvwBTAJUAlQCTAJZAl0CXgJfAl8CXgJgAlICUQJgAmACUQJfAmECYgJjAmMCYgJkAmUCIgJmAmYCIgIkAhkCZwIkAiQCZwJmAmgCaQJqAmoCaQJrAmwCbQJrAmsCbQJqAm4CbwJwAnACbwJxAhQCEwJxAnECEwJwAnICIQJzAnMCIQIgAh8CdAIgAiACdAJzAnQCbgJzAnMCbgJwAhMCcgJwAnACcgJzAhgCFAJ1AnUCFAJxAm8CdgJxAnECdgJ1AncCHgIqAioCHgIdAngCHwJ3AncCHwIeAnkCMwJ6AnoCMwIyAjACewIyAjICewJ6AnsCbAJ6AnoCbAJrAmkCeQJrAmsCeQJ6AnwCfQJ+An4CfQJ/AoACgQJ/An8CgQJ+AoECRwJ+An4CRwJGAkQCfAJGAkYCfAJ+AnkCaQKCAoICaQKDAkACPwKEAoQCPwKFAjUCNgI/Aj8CNgKFAjQCMwKCAoICMwJ5AkcCgQJIAkgCgQKGAoECgAKGAoYCgAKHAjgCNwKHAocCNwKGAjcCPAKGAoYCPAJIAnYCbwKIAogCbwKJAooCiwKJAokCiwKIAngCjAKNAo0CjAKOAowCjwKOAo4CjwKQApACkQKOAo4CkQKSApICbgKOAo4CbgKNApECigKSApICigKJAm8CbgKJAokCbgKSAowCeAKTApMCeAJ3AioClAJ3AncClAKTApQClQKTApMClQKWAo8CjAKWApYCjAKTAuYBlwLnAecBlwKYApkCmgKbApsCmgKcAucBmAKcApwCmAKbAtkBnQLbAdsBnQKeApcC5gGfAp8C5gHyAZoCoAKcApwCoAKhAqACogKhAqECogKjAuQB5QGjAqMC5QGhAuUB5wGhAqEC5wGcAp0C2QGkAqQC2QHoAe0BpQLoAegBpQKkAqYCpwKoAqgCpwKpAqoCqwKpAqkCqwKoAqwCrQKuAq4CrQKvAq0CsAKvAq8CsAKxAqsCqgKyArICqgKzArQCtQKzArMCtQKyArYCtwK4ArgCtwK5ArkCrAK4ArgCrAKuArUCtAK6AroCtAK7ArsCvAK6AroCvAK9Ar4CvwLAAsACvwLBArcCtgLBAsECtgLAAiECcgLCAsICcgLDAnICEwLDAsMCEwIVAg0CxAIVAhUCxALDAh8CeAJ0AnQCeAKNAo0CbgJ0AsQCDQLFAsUCDQIPAgcCxgIPAg8CxgLFAsYCBwLHAscCBwIJAgkCBALHAscCBALIAgQCAgLIAsgCAgLJAgIC9wHJAskC9wHKAqICywKjAqMCywLMAvcB+AHKAsoC+AHMAvgB5AHMAswC5AGjAqUC7QHNAs0C7QH5Af4BzgL5AfkBzgLNAs4C/gHPAs8C/gFYAlcC0AJYAlgC0ALPAtEC0gLTAtMC0gLUAtACVwLUAtQCVwLTAtEC1QLSAtIC1QLWAtUC1wLWAtYC1wJkAl0C2AJeAl4C2ALZAtoC2QLbAtsC2QLYAtcCZwJkAmQCZwJjAtwCYwIbAmMCZwIbAmcCGQIbAtAC3QLPAs8C3QLeAt8C4ALhAuEC4ALiAuMC5ALfAt8C5ALgAuUCzgLeAt4CzgLPAtIC5gLUAtQC5gLnAugC6QLqAuoC6QLrAuEC4gLoAugC4gLpAt0C0ALnAucC0ALUAswCywLsAuwCywLtAu4C7wLwAvAC7wLxAvIC8wL0AvQC8wL1AsoCzAL2AvYCzALsAs4C5QLNAs0C5QL3AvgC+QLjAuMC+QLkAskCygL6AvoCygL2AvMC+wL1AvUC+wL8AvsC/QL8AvwC/QL+AsgCyQL/Av8CyQL6AscCyAIAAwADyAL/Av0CAQP+Av4CAQMCAwMDBAMBAwEDBAMCAwUDxgIAAwADxgLHAsQCBgPDAsMCBgMHAwgDCQMKAwoDCQMLAwwDDQMOAw4DDQMPAxADwgIHAwcDwgLDAsYCBQPFAsUCBQMRAxIDEwMDAwMDEwMEAwoDCwMSAxIDCwMTAwYDxAIRAxEDxALFAtYCZAIUAxQDZAJiAhUDFgMXAxcDFgMYAxYD6gIYAxgD6gLrAtIC1gLmAuYC1gIUAxkDFQMaAxoDFQMXAxsDGQMcAxwDGQMaAx0DUQIeAx4DUQJQAh4DUAIfAx8DUAJOAiADXQIhAyEDXQJfAiEDXwIdAx0DXwJRAiIDIwOmAqYCIwOnArECsAIkAyQDsAIlAx8DTgImAyYDTgJNAicDJQOtAq0CJQOwAq0CrAInAycDrAIoAykDKAO5ArkCKAOsAikDuQIqAyoDuQK3AisDvwIsAywDvwK+Ai0DvQIuAy4DvQK8AioDtwIvAy8DtwLBAi8DwQIrAysDwQK/AjADMQPYAtgCMQPbAtgCXQIwAzADXQIgAzEDMgPbAtsCMgPaAjIDMwPaAtoCMwM0Ay4DvAIzAzMDvAI0A9kC2gI1AzUD2gI0A7QCNgO7ArsCNgM1A14CNgNgAmACNgM3A6oCOAOzArMCOAM3A1ICOANPAk8COAM5A6cCOgOpAqkCOgM5AyYDTQI7AzsDTQI6AyMDOwOnAqcCOwM6A/kC+AI8AzwD+AI9A8sCPgPtAu0CPgM/A6ICQAPLAssCQAM+A6UCQAOkAqQCQANBA6ACmgJBA0EDmgJCA50CQgOeAp4CQgNDAx0D4QIhAyED4QLoAuoCIAPoAugCIAMhA+MCHwP4AvgCHwMmA+ECHQPfAt8CHQMeAx8D4wIeAx4D4wLfAjADIAMWAxYDIAPqAjEDMAMVAxUDMAMWA/gCJgM9Az0DJgM7Az0D7gI8AzwD7gLwAicDKAP7AvsCKAP9AiUDJwPzAvMCJwP7AiMDIgPuAu4CIgPvAiQDJQPyAvICJQPzAigDKQP9Av0CKQMBAyoDAwMpAykDAwMBAwMDKgMSAxIDKgMvAysDCgMvAy8DCgMSAxsDHAMMAwwDHAMNAwwDLgMbAxsDLgMzAwoDKwMIAwgDKwMsAy4DDAMtAy0DDAMOAzIDMQMZAxkDMQMVA0QD4AFFA0UD4AHhAeABRAPvAe8BRANGA0cD8AFGA0YD8AHvAfMB9AGbAZsB9AGcAfIB8wGdAZ0B8wGbAf8BAAKeAZ4BAAKfAfQB/wGcAZwB/wGeAQYCoQEFAgUCoQGgAQACBQKfAZ8BBQKgAQwCowELAgsCowGiAaEBBgKiAaIBBgILAhICpQERAhECpQGkAaMBDAKkAaQBDAIRAhgCpgEXAhcCpgGnAaUBEgKnAacBEgIXAiMCIgKpAakBIgKrASYCIwKtAa0BIwKpASYCrQEpAikCrQGvASwCSAMuAi4CSANJA7QBMAKyAbIBMAIvAjgCSgM6AjoCSgNLA0gDLAJLA0sDLAI6AvABRwNKAkoCRwNMA7kBSwJMA0wDSwJKAksCuQFaAloCuQG7AU0DWwK7AbsBWwJaAmwCwAFtAm0CwAG+AasBIgLCAcIBIgJlAnYCxAF1AnUCxAHDAXUCwwEYAhgCwwGmAXsCMALGAcYBMAK0AWwCewLAAcABewLGAX0CTgN/An8CTgNPA1ADgAJPA08DgAJ/AoACUAOHAocCUANRA0oDOAJRA1EDOAKHAosCzAGIAogCzAHLAYgCywF2AnYCywHEASkCrwFSA1IDrwHOAdABUwPOAc4BUwNSA58C8gHRAdEB8gGdASoCKAKUApQCKAJUAygCKQJUA1QDKQJSA1MDVQNSA1IDVQNUA1UDlQJUA1QDlQKUAlMD0AFWA1YD0AHTAVcDVgPVAdUBVgPTAZUCVQNYA1gDVQNZA1UDUwNZA1kDUwNWA1cDWgNWA1YDWgNZA1sDWANaA1oDWANZA1wDjwJdA10DjwKWApYClQJdA10DlQJYA1sDXgNYA1gDXgNdA14DXwNdA10DXwNcA5ACjwJgA2ADjwJcA18DYQNcA1wDYQNgA2EDYgNgA2ADYgNjA5ECkAJjA2MDkAJgA2IDZANjA2MDZANlA4oCkQJlA2UDkQJjA4sCigJmA2YDigJlA2QDZwNlA2UDZwNmA8wBiwLXAdcBiwJmA2cD1gFmA2YD1gHXAWgDaQNqA2oDaQNrA2wDbQNoA2gDbQNpA24DbwNsA2wDbwNtA3ADcQNuA24DcQNvA3IDcwNwA3ADcwNxA3QDdQNyA3IDdQNzA3YDdwN0A3QDdwN1A3gDeQN2A3YDeQN3A3gDegN5A3kDegN7A3oDfAN7A3sDfAN9A34DfwN8A3wDfwN9A4ADgQN+A34DgQN/A4IDgwOEA4QDgwOFA2kDhgNrA2sDhgOHA20DiANpA2kDiAOGA28DiQNtA20DiQOIA3EDigNvA28DigOJA3MDiwNxA3EDiwOKA3UDjANzA3MDjAOLA3cDjQN1A3UDjQOMA3kDjgN3A3cDjgONA3kDewOOA44DewOPA3sDfQOPA48DfQOQA38DkQN9A30DkQOQA5IDgQOTA5MDgQOFA4YDlAOHA4cDlAOVA4gDlgOGA4YDlgOUA4kDlwOIA4gDlwOWA4oDmAOJA4kDmAOXA4sDmQOKA4oDmQOYA4wDmgOLA4sDmgOZA40DmwOMA4wDmwOaA44DnAONA40DnAObA44DjwOcA5wDjwOdA5ADngOPA48DngOdA5EDnwOQA5ADnwOeA6ADkgOhA6EDkgOTA5UDlAOiA6IDlAOjA5YDpAOUA5QDpAOjA5cDpQOWA5YDpQOkA5gDpgOXA5cDpgOlA5kDpwOYA5gDpwOmA5oDqAOZA5kDqAOnA5sDqQOaA5oDqQOoA5wDqgObA5sDqgOpA5wDnQOqA6oDnQOrA54DrAOdA50DrAOrA58DrQOeA54DrQOsA64DoAOvA68DoAOhA6IDowOwA7ADowOxA6QDsgOjA6MDsgOxA6UDswOkA6QDswOyA6YDtAOlA6UDtAOzA6cDtQOmA6YDtQO0A6gDtgOnA6cDtgO1A6kDtwOoA6gDtwO2A6oDuAOpA6kDuAO3A6oDqwO4A7gDqwO5A6wDugOrA6sDugO5A60DuwOsA6wDuwO6A7wDrgO9A70DrgOvA7ADsQO+A74DsQO/A7IDwAOxA7EDwAO/A7MDwQOyA7IDwQPAA7QDwgOzA7MDwgPBA7UDwwO0A7QDwwPCA7YDxAO1A7UDxAPDA7cDxQO2A7YDxQPEA7gDxgO3A7cDxgPFA7gDuQPGA8YDuQPHA7kDugPHA8cDugPIA7sDyQO6A7oDyQPIA4cBvAOGAYYBvAO9A74DvwPKA8oDvwPLA8ADzAO/A78DzAPLA8EDzQPAA8ADzQPMA8IDzgPBA8EDzgPNA8MDzwPCA8IDzwPOA8QD0APDA8MD0APPA8UD0QPEA8QD0QPQA8YD0gPFA8UD0gPRA8YDxwPSA9IDxwPTA8cDyAPTA9MDyAPUA8kD1QPIA8gD1QPUA8oDywPWA9YDywPXA8wD2APLA8sD2APXA80D2QPMA8wD2QPYA84D2gPNA80D2gPZA88D2wPOA84D2wPaA9AD3APPA88D3APbA9ED3QPQA9AD3QPcA9ID3gPRA9ED3gPdA9ID0wPeA94D0wPfA9MD1APfA98D1APgA9UD4QPUA9QD4QPgA9YD1wPiA+ID1wPjA9gD5APXA9cD5APjA9kD5QPYA9gD5QPkA9oD5gPZA9kD5gPlA9sD5wPaA9oD5wPmA9wD6APbA9sD6APnA90D6QPcA9wD6QPoA94D6gPdA90D6gPpA94D3wPqA+oD3wPrA98D4APrA+sD4APsA+ED7QPgA+AD7QPsA+ID4wPuA+4D4wPvA+QD8APjA+MD8APvA+UD8QPkA+QD8QPwA+YD8gPlA+UD8gPxA+cD8wPmA+YD8wPyA+gD9APnA+cD9APzA+kD9QPoA+gD9QP0A+kD6gP1A/UD6gP2A+oD6wP2A/YD6wP3A+sD7AP3A/cD7AP4A+wD7QP4A/gD7QP5A+4D7wP6A/oD7wP7A/AD/APvA+8D/AP7A/ED/QPwA/AD/QP8A/ID/gPxA/ED/gP9A/MD/wPyA/ID/wP+A/QDAATzA/MDAAT/A/UDAQT0A/QDAQQABPUD9gMBBAEE9gMCBPYD9wMCBAIE9wMDBPgDBAT3A/cDBAQDBPgD+QMEBAQE+QMFBPoD+wMGBAYE+wMHBPsD/AMHBAcE/AMIBPwD/QMIBAgE/QMJBP0D/gMJBAkE/gMKBP8DCwT+A/4DCwQKBAAEDAT/A/8DDAQLBAEEDQQABAAEDQQMBAEEAgQNBA0EAgQOBAMEDwQCBAIEDwQOBAQEEAQDBAMEEAQPBAUEEQQEBAQEEQQQBAYEBwQSBBIEBwQTBAcECAQTBBMECAQUBAgECQQUBBQECQQVBAwEDQQWBA4EFwQNBA0EFwQWBA8EGAQOBA4EGAQXBBAEGQQPBA8EGQQYBBEEGgQQBBAEGgQZBBIEEwQbBBsEEwQcBBMEFAQcBBwEFAQdBBsEHAQeBB4EHAQfBB0EIAQcBBwEIAQfBCEEIgQYBBgEIgQXBBkEIwQYBBgEIwQhBBoEJAQZBBkEJAQjBB4EHwQlBCUEHwQmBCAEJwQfBB8EJwQmBCgEIgQpBCkEIgQhBCEEIwQpBCkEIwQqBCQEKwQjBCMEKwQqBCUEJgQsBCwEJgQtBCYEJwQtBC0EJwQuBC8EMAQpBCkEMAQoBCkEKgQvBC8EKgQxBCsEMgQqBCoEMgQxBCwELQQzBDMELQQ0BC0ELgQ0BDQELgQ1BDAELwQ2BDYELwQ3BC8EMQQ3BDcEMQQ4BDEEMgQ4BDgEMgQ5BDIEOgQ5BDkEOgQ7BDwEOgQ9BD0EOgQ+BDMENAQ/BD8ENARABDQENQRABEAENQRBBEIEQwREBEQEQwRFBGgDagNGBGwDaANGBG4DbANGBHADbgNGBHIDcANGBHQDcgNGBHYDdANGBHgDdgNGBHoDeANGBHwDegNGBH4DfANGBH4DRgSAA4IDhANGBEcESARJBEkESARKBEkESwRHBEcESwRMBE0ETgRJBEkETgRLBEkESgRNBE0ESgRPBFAEUQRSBFIEUQRTBFIEVARQBFAEVARVBEcETARSBFIETARUBFIEUwRHBEcEUwRIBFYEVwRYBFgEVwRZBFgEWgRWBFYEWgRbBFAEVQRYBFgEVQRaBFgEWQRQBFAEWQRRBFwEXQReBF4EXQRfBF8EYAReBF4EYARhBFYEWwRfBF8EWwRgBF8EXQRWBFYEXQRXBGIEYwRkBGQEYwRlBGEEYgReBF4EYgRkBGQEZQRmBGYEZQRnBGgEaQRqBGoEaQRrBGwEbQRrBGsEbQRqBGMEbARlBGUEbARrBGkEZwRrBGsEZwRlBG4EbwRwBHAEbwRxBHIEcwRxBHEEcwRwBG0EcgRqBGoEcgRxBG8EaARxBHEEaARqBHQEdQR2BHYEdQR3BHgEeQR3BHcEeQR2BHMEeARwBHAEeAR3BHUEbgR3BHcEbgRwBHoEewR8BHwEewR9BH4EfwR9BH0EfwR8BHkEfgR2BHYEfgR9BHsEdAR9BH0EdAR2BE0ETwSABIAETwSBBIAEggRNBE0EggROBHwEfwSABIAEfwSCBIAEgQR8BHwEgQR6BHUEdARKBEoEdARPBIMEhASFBIUEhASGBIcEiASJBIkEiASGBIoEiwSMBIwEiwSNBI4EjwSQBJAEjwSNBJEEkgSQBJAEkgSTBJQElQSFBIUElQSTBJYElwSYBJgElwSJBJkEmgSbBJsEmgSXBJwEnQSbBJsEnQSeBJ8EngSgBKAEngShBKIEowSkBKQEowSlBKYEowSnBKcEowShBKgEqQSqBKoEqQSlBKsEqQSsBKwEqQStBK4ErwSwBLAErwStBLEErwSyBLIErwSzBLQEtQS2BLYEtQSzBLcEtQS4BLgEtQS5BLoEuwS8BLwEuwS5BL0EuwS+BL4EuwSMBFoEvwRbBFsEvwTABMEEWgTCBMIEWgRVBEsEwwRMBEwEwwTEBMUESwTGBMYESwROBFQExwRVBFUExwTIBMkEVATKBMoEVARMBGAEywRhBGEEywTMBM0EYATOBM4EYARbBIIEzwROBE4EzwTQBNEEggTSBNIEggR/BGMEYgTTBNMEYgTUBGIEYQTVBNUEYQTWBH8EfgTXBNcEfgTYBH4EeQTZBNkEeQTaBG0EbATbBNsEbATcBGwEYwTdBN0EYwTeBHkEeATfBN8EeATgBHgEcwThBOEEcwTiBHMEcgTjBOMEcgTkBHIEbQTlBOUEbQTmBOcEmgToBOgEmgSZBJoE6QSHBIcE6QTqBOsElQTsBOwElQSUBI4ElQTtBO0ElQTuBIcE7wSIBIgE7wTwBPEElATyBPIElASIBPMEnwT0BPQEnwSgBPUEmQT2BPYEmQSfBPcE+ASOBI4E+ASPBL4EjwT5BPkEjwT6BPsEogT8BPwEogSkBP0EoAT+BP4EoASiBP8EAAW+BL4EAAW9BLgEvQQBBQEFvQQCBQMFqwQEBQQFqwSsBAUFpAQGBQYFpASrBAcFCAW4BLgECAW3BLIEtwQJBQkFtwQKBbIECwWxBLEECwUMBQ0FrAQOBQ4FrASxBKYEDwWqBKoEDwUQBaYEpwQPBQ8FpwQRBagEEgWwBLAEEgUTBRIFqAQQBRAFqASqBJgEhAQUBRQFhAQVBYQEgwQVBRUFgwQWBbQEFwW8BLwEFwUYBRcFtAQZBRkFtAS2BJEEiwQaBRoFiwQbBRsFiwQcBRwFiwSKBIMEkgQWBRYFkgQdBZIEkQQdBR0FkQQaBZwElgQeBR4FlgQfBZYEmAQfBR8FmAQUBacEnQQRBREFnQQgBZ0EnAQgBSAFnAQeBa4EIQW2BLYEIQUZBSEFrgQTBRMFrgSwBLoEIgWKBIoEIgUcBSIFugQYBRgFugS8BCMFJAUPBQ8FJAUQBSUFIwURBREFIwUPBRIFJgUTBRMFJgUnBSYFEgUkBSQFEgUQBSgFKQUVBRUFKQUUBSoFKAUWBRYFKAUVBRcFKwUYBRgFKwUsBSsFFwUtBS0FFwUZBRsFLgUaBRoFLgUvBS4FGwUwBTAFGwUcBTEFKgUdBR0FKgUWBS8FMQUaBRoFMQUdBTIFMwUfBR8FMwUeBSkFMgUUBRQFMgUfBTQFJQUgBSAFJQURBTMFNAUeBR4FNAUgBSEFNQUZBRkFNQUtBTUFIQUnBScFIQUTBSIFNgUcBRwFNgUwBTYFIgUsBSwFIgUYBXsEegR0BHQEegRPBHoEgQRPBEgEUwRuBG4EUwRvBEoESAR1BHUESARuBFMEUQRvBG8EUQRoBF0EXARXBGcEVwRmBFcEXARmBFkEaQRRBFEEaQRoBGYEXARkBGQEXAReBFcEZwRZBFkEZwRpBCQFIwU3BTcFIwU4BSMFJQU4BTgFJQU2BCYFOQUnBScFOQU6BSgFFgQpBSkFFgQXBCgFKgUWBBYEKgUMBCsFLgQsBSwFLgQnBC0FNQQrBSsFNQQuBC8FLgUKBAoELgUVBC4FMAUVBBUEMAUdBDEFCwQqBSoFCwQMBDEFLwULBAsELwUKBDMFMgUoBCgEMgUiBDIFKQUiBCIEKQUXBDQFMwUwBDAEMwUoBC0FNQU1BDUENQVBBCcFOgU1BTUFOgVBBDAFNgUdBB0ENgUgBDYFLAUgBCAELAUnBCQFNwUmBSYFNwU5BR0EFAQVBBUECQQKBDQFMAQlBSUFMAQ2BDsFPAU9BTwFPgU/BT8FPgU9BUAFQQVCBUIFQQVDBUEFQAVEBUQFQAVFBUYFRwVABUAFRwVFBUgFSQVKBUoFSQVGBUYFQAVKBUoFQAVCBUsFTAVNBU0FTAVOBU8FTgVQBVAFTgVMBVEFUgVTBVMFUgVUBVUFVAVWBVYFVAVXBUwFWAVZBVkFWAVaBVgFWwVcBVwFWwVdBVsFWAVeBV4FWAVfBVgFTAVfBV8FTAVLBWAFYQViBWIFYQVjBU0FYwVLBUsFYwVhBWQFZQVmBWYFZQVnBWUFaAVnBWcFaAVpBWgFZQVqBWoFZQVrBWsFZQVkBWwFbQVTBVMFbQVuBW0FbAVvBW8FbAVwBWwFcQVwBXAFcQVyBXEFcwVyBXIFcwV0BXMFcQVVBVUFcQVUBXEFbAVUBVQFbAVTBXUFdgV3BXcFdgV4BXgFdgVgBWAFdgVhBXYFXwVhBWEFXwVLBXYFdQVfBV8FdQVeBWkFaAV5BXkFaAV6BXoFaAV7BXwFfQV+BX4FfQV/BX0FfAWABYAFfAWBBYIFgwWEBYQFgwWFBYUFgwWGBYYFgwWHBYMFfQWHBYcFfQWABYMFggV9BX0FggV/BYgFiQWKBYoFiQWLBYkFjAWLBYsFjAWNBY4FjwWQBZAFjwWRBY4FPAWPBY8FPAU7BZIFkwWQBZAFkwWOBY4FlAU8BTwFlAU+BZQFjgWVBZUFjgWTBZYFlwWYBZgFlwWZBZcFQQWZBZkFQQVEBUEFlwVDBUMFlwWaBZcFlgWaBZoFlgWbBWIFnAVgBWAFnAWdBZ4FnQWfBZ8FnQWcBaAFoQWiBaIFoQWjBaEFpAWjBaMFpAWlBaQFoQWRBZEFoQWQBaYFoAWnBacFoAWiBZMFkgWoBakFqAWSBakFpgV5BXkFpgWqBaYFpwWqBaoFpwWrBawFpAWtBa0FpAWRBaQFrAWlBaUFrAWuBawFrwWuBa4FrwWwBa8FrAWxBbEFrAWtBbIFswW0BbQFswW1BbYFtQW3BbcFtQWzBbgFuQW6BboFuQW7BbkFvAW7BbsFvAW9BbwFuQW+Bb4FuQW/BbkFuAW/Bb8FuAXABcEFwgXDBcMFwgXEBcIFxQXEBcQFxQWNBcIFuAXFBcUFuAW6BbgFwgXABcAFwgXBBcYFxwXIBcgFxwXJBccFygXJBckFygXLBcoFxwW2BbYFxwW1BccFxgW1BbUFxgW0BcwFvAXNBc0FvAW+BbwFzAW9Bb0FzAXOBcwFzwXOBc4FzwXQBc8FzAXRBdEFzAXNBbcF0gW2BbYF0gXKBdMFywXSBdIFywXKBdQF1QXWBdYF1QXXBdUF1AXQBdAF1AXOBc4F1AW9Bb0F1AW7BdQF1gW7BbsF1gW6BdgF2QVwBXAF2QVvBdkF2AXaBdoF2AXbBdwF3QXeBd4F3QXfBZMF4AWVBZUF4AXhBeIF4wXkBeQF4wXhBdgF5QXbBdsF5QXmBeUF5wXmBeYF5wXoBecF5QV0BXQF5QVyBeUF2AVyBXIF2AVwBekFlgXjBeMFlgWYBZYF6QWbBZsF6QXqBekF6wXqBeoF6wXsBesF6QXiBeIF6QXjBe0F7gXbBdsF7gXaBd0F7wXfBd8F7wXwBfEF4gXyBfIF4gXkBfMF9AXoBegF9AXmBfQF7QXmBeYF7QXbBesF9QXsBewF9QX2BfUF6wXxBfEF6wXiBe8FfAXwBfAFfAV+BYYFhwXzBfMFhwX0BYcFgAX0BfQFgAXtBfcF+AX5BfkF+AX6BfgF9wWeBZ4F9wWdBfcFeAWdBZ0FeAVgBXgF9wV3BXcF9wX5BfsF/AWwBbAF/AWuBfwF/QWuBa4F/QWlBf0F/AW+Bb4F/AXNBfwF+wXNBc0F+wXRBf4F/wXDBcMF/wUABv8FAQYABgAGAQarBZ8FAgaeBZ4FAgYDBrQFAwayBbIFAwYCBgQGBQbABcAFBQa/BQUG/QW/Bb8F/QW+Bf0FBQalBaUFBQajBQUGBAajBaMFBAaiBdMF0gWIBYgF0gWJBdIFtwWJBYkFtwWMBbcFswWMBYwFswUGBrMFsgUGBgYGsgX+BZ8FnAUBBgEGnAUHBpwFYgUHBgcGYgVpBWIFYwVpBWkFYwVnBWMFTQVnBWcFTQVmBQgGZAUJBgkGZAVmBQoGagVrBdwF2QXdBd0F2QXaBe4F7wXaBdoF7wXdBYEFfAXuBe4FfAXvBQsGWwUMBgwGWwUNBg0GWwUOBg4GWwVeBXUFDwZeBV4FDwYOBg8GdQUQBhAGdQV3BfkFEQZ3BXcFEQYQBvkF+gURBhEG+gUSBvoFEwYSBhIGEwYUBhMGyAUUBhQGyAUVBsgFyQUVBhUGyQUWBskFywUWBhYGywUXBssF0wUXBhcG0wUYBtMFiAUYBhgGiAUZBhoGGwaKBYoFGwYcBhsGGgYdBh0GGgbXBR4G1QUfBh8G1QXQBdUFHgbXBdcFHgYdBs8FIAbQBdAFIAYfBiAGzwUhBiEGzwXRBSIG+wUjBiMG+wWwBfsFIgbRBdEFIgYhBq8FJAawBbAFJAYjBiQGrwUlBiUGrwWxBUkFSAWxBbEFSAUlBoIFJgZ/BX8FJgYnBiYG9QUnBicG9QXxBfUFJgb2BfYFJgYoBiYGggUoBigGggWEBRkGiAUcBhwGiAWKBSkGqAXeBd4FqAUqBqgFKQaTBZMFKQbgBSkGKwbgBeAFKwYsBisGKQbfBd8FKQbeBQEGBwarBasFBwaqBaoFBwZ5BXkFBwZpBS0GKwbwBfAFKwbfBSsGLQYsBiwGLQYuBgQGLwaiBaIFLwanBacFLwarBasFLwYABi8GwQUABgAGwQXDBS8GBAbBBcEFBAbABTAGLQZ+BX4FLQbwBS0GMAYuBi4GMAbyBYwFBgaNBY0FBgbEBQYG/gXEBcQF/gXDBScGMAZ/BX8FMAZ+BRoGMQbXBdcFMQbWBTEGxQXWBdYFxQW6BcUFMQaNBY0FMQaLBTEGGgaLBYsFGgaKBYAFgQXtBe0FgQXuBU0FTgVmBWYFTgUyBnkFegWpBXoFKgapBagFqQUqBjMGSQWtBa0FSQWxBUkFMwZGBUYFMwZHBY8FMwaRBZEFMwatBfgFNAb6BfoFNAYTBjQGxgUTBhMGxgXIBcYFNAa0BbQFNAYDBjQG+AUDBgMG+AWeBbIFAgb+Bf4FAgb/BQIGnwX/Bf8FnwUBBpIFoAWpBakFoAWmBaEFoAWQBZAFoAWSBSwGLgbkBeQFLgbyBeAFLAbhBeEFLAbkBfIFMAbxBfEFMAYnBuMFmAXhBeEFmAWVBZkFlAWYBZgFlAWVBZQFmQU+BT4FmQVEBUQFRQU+BT4FRQU9BUcFOwVFBUUFOwU9BTMGjwVHBUcFjwU7BTUGNgY3BjcGNgY4BjkGNgY5BTkFNgZFBDkFRQQ6BToFRQRDBEAEQQRDBEMEQQQ6BT8EQARCBEIEQARDBDoGOwY8BjwGOwY9Bj4GOwY2BDYEOwY4BT8GQAZBBkEGQAZCBkMGRAZFBkUGRAY7BDoGOQY3BTcFOQY5BT8GPgY3BDcEPgY2BEYGRwZkBWQFRwZrBVMFbgVIBkgGbgVJBkoGQAY5BDkEQAY4BG4FawVLBksGawVMBjYGNQZFBEUENQZEBEQGQwZNBk0GQwZOBk8GNgZQBlAGNgY5BlEGOQZSBlIGOQY6BjgFOwY3BTcFOwY6BjsGPgZTBlMGPgZUBj4GPwZVBlUGPwZWBkAGPwY4BDgEPwY3BEAGSgZXBlcGSgZYBkoGRAZZBlkGRAZaBlsG3AUqBioG3AXeBdkF3AVvBW8F3AVbBm0FbwVcBlwGbwVbBlsGKgZ7BXsFKgZ6BVwGWwYKBgoGWwZ7BVwGCgZuBW4FCgZrBW4FbQVcBgoGewVqBWoFewVoBTkEOwRKBkoGOwREBoEDkgN/A38DkgORA5IDoAORA5EDoAOfA6ADrgOfA58DrgOtA64DvAOtA60DvAO7A7sDvAPJA8kDvAOHAYcBigHJA8kDigHVAysEPgQyBDIEPgQ6BGsDXQZqA2oDXQZeBl0GXwZeBl4GXwZgBl8GYQZgBmAGYQZiBmEGYwZiBmIGYwZkBmMGZQZkBmQGZQZmBmUGZwZmBmYGZwZoBmcGaQZoBmgGaQZqBmkGawZqBmoGawZsBmwGawZtBm0GawZuBm0GbgZvBm8GbgZwBnAGcQZvBm8GcQZyBnEGcwZyBnIGcwZ0BnMGdQZ0BnQGdQZ2BocDdwZrA2sDdwZdBncGeAZdBl0GeAZfBngGeQZfBl8GeQZhBnkGegZhBmEGegZjBnoGewZjBmMGewZlBnsGfAZlBmUGfAZnBnwGfQZnBmcGfQZpBn0GfgZpBmkGfgZrBmsGfgZuBm4GfgZ/Bm4GfwZwBnAGfwaABoAGgQZwBnAGgQZxBoIGgwZzBnMGgwZ1BpUDhAaHA4cDhAZ3BoQGhQZ3BncGhQZ4BoUGhgZ4BngGhgZ5BoYGhwZ5BnkGhwZ6BocGiAZ6BnoGiAZ7BogGiQZ7BnsGiQZ8BokGigZ8BnwGigZ9BooGiwZ9Bn0GiwZ+Bn4GiwZ/Bn8GiwaMBn8GjAaABoAGjAaNBoAGjQaBBoEGjQaOBo8GkAaCBoIGkAaDBpUDogOEBoQGogORBpEGkgaEBoQGkgaFBpIGkwaFBoUGkwaGBpMGlAaGBoYGlAaHBpQGlQaHBocGlQaIBpUGlgaIBogGlgaJBpYGlwaJBokGlwaKBpcGmAaKBooGmAaLBosGmAaMBowGmAaZBpkGmgaMBowGmgaNBo0GmgaOBo4GmgabBpwGnQaPBo8GnQaQBqIDsAORBpEGsAOeBp4GnwaRBpEGnwaSBp8GoAaSBpIGoAaTBqAGoQaTBpMGoQaUBqEGogaUBpQGogaVBqIGowaVBpUGowaWBqMGpAaWBpYGpAaXBqQGpQaXBpcGpQaYBpgGpQaZBpkGpQamBqYGpwaZBpkGpwaaBqcGqAaaBpoGqAabBqkGqgacBpwGqgadBrADvgOeBp4GvgOrBqsGrAaeBp4GrAafBqwGrQafBp8GrQagBq0GrgagBqAGrgahBq4GrwahBqEGrwaiBq8GsAaiBqIGsAajBrAGsQajBqMGsQakBrEGsgakBqQGsgalBqUGsgamBqYGsgazBrMGtAamBqYGtAanBrQGtQanBqcGtQaoBrYGqgbUAdQBqgbVAb4DygOrBqsGygO3BrcGuAarBqsGuAasBrgGuQasBqwGuQatBrkGugatBq0GugauBroGuwauBq4GuwavBrsGvAavBq8GvAawBrwGvQawBrAGvQaxBr0GvgaxBrEGvgayBrIGvgazBrMGvga/BrMGvwa0BrQGvwbABsAGwQa0BrQGwQa1BsoD1gO3BrcG1gPCBsIGwwa3BrcGwwa4BsMGxAa4BrgGxAa5BsQGxQa5BrkGxQa6BsUGxga6BroGxga7BsYGxwa7BrsGxwa8BscGyAa8BrwGyAa9BsgGyQa9Br0GyQa+Br4GyQa/Br8GyQbKBsoGywa/Br8GywbABssGzAbABsAGzAbBBtYD4gPCBsIG4gPNBs0GzgbCBsIGzgbDBs4GzwbDBsMGzwbEBs8G0AbEBsQG0AbFBtAG0QbFBsUG0QbGBtEG0gbGBsYG0gbHBtIG0wbHBscG0wbIBtMG1AbIBsgG1AbJBskG1AbKBsoG1AbVBtUG1gbKBsoG1gbLBtYG1wbLBssG1wbMBuID7gPNBs0G7gPYBtgG2QbNBs0G2QbOBtkG2gbOBs4G2gbPBtoG2wbPBs8G2wbQBtsG3AbQBtAG3AbRBtwG3QbRBtEG3QbSBt0G3gbSBtIG3gbTBt4G3wbTBtMG3wbUBtQG3wbVBtUG3wbgBtUG4AbWBtYG4AbhBtYG4QbXBtcG4QbiBu4D+gPYBtgG+gPjBuMG5AbYBtgG5AbZBuQG5QbZBtkG5QbaBuUG5gbaBtoG5gbbBuYG5wbbBtsG5wbcBucG6AbcBtwG6AbdBugG6QbdBt0G6QbeBt4G6QbfBt8G6QbqBt8G6gbgBuAG6gbrBuAG6wbhBuEG6wbsBuEG7AbiBuIG7AbtBvoDBgTjBuMGBgTuBuMG7gbkBuQG7gbvBuQG7wblBuUG7wbwBuUG8AbmBuYG8AbxBvEG8gbmBuYG8gbnBvIG8wbnBucG8wboBvMG9AboBugG9AbpBukG9AbqBuoG9Ab1BuoG9QbrBusG9Qb2BusG9gbsBuwG9gb3BuwG9wbtBu0G9wb4BgYEEgTuBu4GEgT5Bu4G+QbvBu8G+Qb6Bu8G+gbwBvAG+gb7BvMG/Ab0BvwG/Qb0BvQG/Qb1Bv0G/gb1BvUG/gb2Bv4G/wb2BvYG/wb3BvcG/wb4BvgG/wYABxIEGwT5BvkGGwQBB/kGAQf6BvoGAQcCBxsEHgQBBwEHHgQDBwMHBAcBBwEHBAcCBwUH/gYGBwYH/gb9BgUHBwf+Bv4GBwf/Bv8GBwcABwAHBwcIBx4EJQQDBwMHJQQJBwkHCgcDBwMHCgcEBwUHBgcLBwsHBgcMBwUHCwcHBwcHCwcNBwcHDQcIBwgHDQcOByUELAQJBwkHLAQPBwkHDwcKBwoHDwcQBxEHCwcSBxIHCwcMBwsHEQcNBw0HEQcTBw0HEwcOBw4HEwcUBywEMwQPBw8HMwQVBw8HFQcQBxAHFQcWBxcHEQcYBxgHEQcSBxEHFwcTBxMHFwcZBxMHGQcUBxQHGQcaBxQHGgcbBxsHGgccBxsHPAQdBx0HPAQ9BDMEPwQVBxUHPwQeBxUHHgcWBxYHHgcfB0IERAQgByAHRAQhB14GRgRqA2AGRgReBmIGRgRgBmQGRgRiBmYGRgRkBmgGRgRmBmoGRgRoBmwGRgRqBm0GRgRsBm8GRgRtBnIGRgRvBnIGdAZGBHYGRgR0BiIHIwckByQHIwclByMHIgcmByYHIgcnBygHIwcpBykHIwcmByMHKAclByUHKAcqBysHLActBy0HLAcuBywHKwcvBy8HKwcwByIHLAcnBycHLAcvBywHIgcuBy4HIgckBzEHMgczBzMHMgc0BzIHMQc1BzUHMQc2BysHMgcwBzAHMgc1BzIHKwc0BzQHKwctBzcHOAc5BzkHOAc6BzcHOQc7BzsHOQc8BzEHNwc2BzYHNwc7BzcHMQc4BzgHMQczBz0HPgc/Bz8HPgdABz8HQAc5BzkHQAc8Bz8HQQc9Bz0HQQdCB0MHRAdFB0UHRAdGB0UHRwdDB0MHRwdIB0MHSAc9Bz0HSAc+Bz0HQgdDB0MHQgdEB0kHSgdLB0sHSgdMB0sHTQdJB0kHTQdOB0kHTgdFB0UHTgdHB0UHRgdJB0kHRgdKB08HUAdRB1EHUAdSB1EHUwdPB08HUwdUB08HVAdLB0sHVAdNB0sHTAdPB08HTAdQB1UHVgdXB1cHVgdYB1cHWQdVB1UHWQdaB1UHWgdRB1EHWgdTB1EHUgdVB1UHUgdWBygHWwcqByoHWwdcB1sHKAddB10HKAcpB1cHWwdZB1kHWwddB1sHVwdcB1wHVwdYByoHUgclByUHUgdQB14HXwdgB2AHXwdhB2IHYwdkB2QHYwdhB2UHZgdnB2cHZgdoB2kHagdrB2sHagdoB2wHagdtB20HagduB28HXwdwB3AHXwduB3EHcgdzB3MHcgdjB3QHdQd2B3YHdQdzB3cHdQd4B3gHdQd5B3oHewd5B3kHewd8B30Hfgd/B38HfgeAB4EHggd/B38Hggd8B4MHhAeFB4UHhAeAB4YHhweFB4UHhweIB4kHigeLB4sHigeIB4wHjQeLB4sHjQeOB48HkAeRB5EHkAeOB5IHkweRB5EHkweUB5UHlgeXB5cHlgeUB5gHmQeXB5cHmQdmB5oHmwc2BzYHmwc1B5wHnQc1BzUHnQcwB54HnwcnBycHnwcmB6AHoQcmByYHoQcpB6IHowcwBzAHowcvB6QHpQcvBy8HpQcnB6YHpwc8BzwHpwc7B6gHqQc7BzsHqQc2B6oHqwcpBykHqwddB6wHrQddB10HrQdZBz4HrgdAB0AHrgevB7AHPAexB7EHPAdAB1kHsgdaB1oHsgezB7QHUwe1B7UHUwdaB0cHtgdIB0gHtge3B7gHPge5B7kHPgdIB1MHugdUB1QHuge7B7wHTQe9B70HTQdUB00HvgdOB04Hvge/B8AHRwfBB8EHRwdOB8IHwwd2B3YHwwd0B3YHYgfEB8QHYgfFB8YHxwdwB3AHxwdvB8gHcAfJB8kHcAdpB8oHywdkB2QHywdiB2QHbwfMB8wHbwfNB84Hzwd6B3oHzwd7B3oHdAfQB9AHdAfRB9IHaQfTB9MHaQdrB9QHawfVB9UHaweZB9YH1wd9B30H1wd+B30HewfYB9gHewfZB9oHmQfbB9sHmQeYB9wHmAfdB90HmAeTB94H3weGB4YH3weHB4YHfgfgB+AHfgfhB+IHkwfjB+MHkweSB+QHkgflB+UHkgeNB+YH5weMB4wH5weNB4wHhwfoB+gHhwfpB+oH6weEB4QH6weBB+wHggfrB+sHggeBB+0H7geKB4oH7geDB+4H6geDB4MH6geEB3IH7wdgB2AH7wfwB/EHXgfwB/AHXgdgB/IH8weWB5YH8wePB/MH9AePB48H9AeQB2wH9QdnB2cH9Qf2B/YH9wdnB2cH9wdlB14H8QdtB20H8Qf4B/UHbAf4B/gHbAdtB3cH+QdxB3EH+Qf6B+8Hcgf6B/oHcgdxB4IH7Ad4B3gH7Af7B/kHdwf7B/sHdwd4B/QH/AeQB5AH/AeJB/wH7QeJB4kH7QeKB/cH/QdlB2UH/QeVB/0H8geVB5UH8geWB+oH/gfrB+sH/gf/BwAI7Af/B/8H7AfrB+4H7QcBCAEI7QcCCOoH7gf+B/4H7gcBCO8HAwjwB/AHAwgECAUI8QcECAQI8QfwB/MH8gcGCAYI8gcHCPQH8wcICAgI8wcGCPYH9QcJCAkI9QcKCPcH9gcLCAsI9gcJCPEHBQj4B/gHBQgMCAoI9QcMCAwI9Qf4B/kHDQj6B/oHDQgOCAMI7wcOCA4I7wf6B+wHAAj7B/sHAAgPCA0I+QcPCA8I+Qf7B/wH9AcQCBAI9AcICO0H/AcCCAII/AcQCP0H9wcRCBEI9wcLCPIH/QcHCAcI/QcRCFYHUgdYB1IHKgdYByoHXAdYByQHTAcuBy4HTAdKByUHUAckByQHUAdMBy4HSgctBy0HSgdGBzgHMwc6B0IHQQczBzMHQQc6B0YHRActBy0HRAc0BzkHOgc/Bz8HOgdBBzMHNAdCB0IHNAdEB/4HEgj/B/8HEggTCP8HEwgACAAIEwgYBxQIFQgCCAIIFQgBCP0G/AYDCAMI/AYECAQI/AYFCAUI/AbzBgoHEAcHCAcIEAcGCBAHFgcGCAYIFgcICAoI8QYJCAkI8Qb7BgkI+wYLCAsI+wYCB/MG8gYFCAUI8gYMCAwI8gYKCAoI8gbxBg0IDAcOCA4IDAcGBw4IBgcDCAMIBgf9Bg8IEgcNCA0IEgcMBwgIFgcQCBAIFgcfBx8HFAgQCBAIFAgCCAsIAgcRCBEIAgcEBxEIBAcHCAcIBAcKBxUIEggBCAEIEgj+BwIH+wb6BvsG8QbwBg8IAAgSBxIHAAgYBxYIFwgYCBcIGQgYCBgIGQgWCBoIQgUbCBsIQgVDBRwIGggdCB0IGggbCBoIHAgeCB4IHAgfCEoFHghIBUgFHgggCEIFGghKBUoFGggeCCEIIggjCCMIIggkCCIIIQglCCUIIQgmCCcIKAgpCCkIKAgqCFUFKwgnCCcIKwgsCCIILQguCC4ILQgvCDAIMQgyCDIIMQguCDEIMwguCC4IMwg0CCQIIgg0CDQIIgguCDUINgg3CDcINgg4CCMIJAg1CDUIJAg2CDkIOgg7CDsIOgg8CD0IPgg8CDwIPgg7CD4IPwg7CD8IQAg7CDsIQAg5CEEIKQhCCEIIKQhDCEQIQQhFCEUIQQhCCEEIRAhGCEYIRAhHCHQFcwVHCEcIcwVGCHMFVQVGCEYIVQUnCCkIQQgnCCcIQQhGCEgISQhKCEoISQhLCEsIOAhKCEoIOAg2CCQINAg2CDYINAhKCDMISAg0CDQISAhKCD0ITAg+CD4ITAhNCE0ITgg+CE8IUAhRCFEIUAhSCFAIUwhSCFIIUwhUCFUIhAVWCFYIhAWFBYUFhgVWCFYIhgVXCFMIUAhXCFcIUAhWCE8IVQhQCFAIVQhWCFgIWQhaCFoIWQhbCFwIXQhbCFsIXQhaCF4IXwhgCGAIXwhhCGIIFghfCF8IFghhCGEIYwhgCGAIYwhkCBkIZQgWCBYIZQhhCGUIZghhCGEIZghjCGcIaAhpCGkIaAhqCGgIHQhqCGoIHQgbCBsIQwVqCGoIQwWaBZsFaQiaBZoFaQhqCDcIOAhrCGsIOAhsCGsIbAhtCG0IbAhuCG8IcAhxCHEIcAhyCHMIdAhyCHIIdAhxCHQIXghxCHEIXghgCHAIbwh1CHUIbwh2CGMIdwhkCHgIZAh3CHgITAh2CHYITAh5CHoIdQh5CHkIdQh2CF4IdAh7CHsIdAh8CHQIcwh8CHwIcwh9CH4Ifwh9CH0Ifwh8CH8IgAh8CHwIgAh7CIEIggiDCIMIggiECIIIgQiFCIUIgQiGCIcIiAiJCIkIiAiKCIsIjAiKCIoIjAiJCIwIjQiJCIkIjQiOCI8IhwiOCI4IhwiJCJAIkQiSCJIIkQiTCFwIlAiTCJMIlAiSCIgIhwiUCJQIhwiSCIcIjwiSCJIIjwiQCJUIlgiXCJcIlgiYCJkImgiYCJgImgiXCJoIhgiXCJcIhgiBCIMIlQiBCIEIlQiXCI0IjAibCJsIjAicCIwIiwicCJwIiwidCJ4InwidCJ0InwicCJ8IoAicCJwIoAibCIUIhgihCKEIhgiaCKIIoQiZCJkIoQiaCKMIpAilCKUIpAimCKQIngimCKYIngidCJ0IiwimCKYIiwiKCIgIpQiKCIoIpQimCKcIRAioCKgIRAhFCKkIpwiqCKoIpwioCKsIrAitCK0IrAiuCGMIZgivCK8IZgiwCLAIsQiyCLIIsQizCKcIqQi0CLQIqQi1COgF5wW1CLUI5wW0COcFdAW0CLQIdAVHCEQIpwhHCEcIpwi0CGcIaQixCLEIaQi2CGkImwW2CLYImwXqBewFtwjqBeoFtwi2CLcIswi2CLYIswixCLgIqQi5CLkIqQiqCKwIqwi6CLoIqwi7CLIIswi8CLwIswi9CPMF6AW+CL4I6AW1CKkIuAi1CLUIuAi+CLcI7AW/CL8I7AX2BbMItwi9CL0Itwi/CLoIuwhSCFIIuwhRCIYF8wVXCFcI8wW+CLgIUwi+CL4IUwhXCMAIwQjCCMIIwQjDCMEIbgjDCMMIbghsCDgISwhsCGwISwjDCEsISQjDCMMISQjCCMQIfgjFCMUIfgh9CHMIxgh9CH0IxgjFCMYIjQjFCMUIjQibCKAIxAibCJsIxAjFCMcIkQjICMgIkQjJCHoIygjJCMkIygjICG0IbgjLCMsIbgjMCIMIhAjMCMwIhAjLCM0IjwjOCM4IjwiOCI0IxgiOCI4IxgjOCMYIcwjOCM4IcwhyCHAIzQhyCHIIzQjOCKIIWAihCKEIWAhaCF0IhQhaCFoIhQihCIUIXQiCCIIIXQjPCMcIhAjPCM8IhAiCCG0IyghrCGsIygjQCD0INwjQCNAINwhrCDcIPQg1CDUIPQg8CDoIIwg8CDwIIwg1CDoIOQjRCNEIOQjSCNMIQAg/CK4IrAioCKgIrAiqCKwIugiqCKoIugi5CLoIUgi5CLkIUghUCNQIDQbVCNUIDQYxCA0GDgYxCDEIDgYzCA4GDwYzCDMIDwZICA8GEAZICEgIEAZJCBAGEQZJCEkIEQbCCBIGwAgRBhEGwAjCCMAIEgbWCNYIEgYUBhUGlggUBhQGlgjWCJYIFQaYCJgIFQYWBhcGmQgWBhYGmQiYCBgGoggXBhcGogiZCBkGWAgYBhgGWAiiCBwGGwZZCFkIGwbXCBsGHQbXCNcIHQajCB4GHwakCKQIHwaeCB0GHgajCKMIHgakCB8GIAaeCJ4IIAafCCAGIQafCJ8IIQagCCIGIwbECMQIIwZ+CCEGIgagCKAIIgbECCMGJAZ+CH4IJAZ/CCQGJQZ/CH8IJQaACCUGSAWACIAISAUgCFUITwjYCNgITwjZCL0IvwjZCNkIvwjYCL8I9gXYCNgI9gUoBoQFVQgoBigGVQjYCBkGHAZYCFgIHAZZCNoIdwitCK0IdwjbCHcIYwjbCNsIYwivCNwI3QivCK8I3QjbCN0IqwjbCNsIqwitCMoIegjQCNAIegh5CD0I0AhMCEwI0Ah5CKsI3Qi7CLsI3QjeCN0I3AjeCN4I3AjfCM0IcAjgCOAIcAh1CHUIegjgCOAIegjJCJEIkAjJCMkIkAjgCI8IzQiQCJAIzQjgCLsI3ghRCFEI3gjhCN8IvAjeCN4IvAjhCF0IXAjPCM8IXAiTCJEIxwiTCJMIxwjPCNkITwjhCOEITwhRCNcIowjiCOIIowilCIgIlAilCKUIlAjiCJQIXAjiCOIIXAhbCFkI1whbCFsI1wjiCFMIuAhUCFQIuAi5CCMIOgghCCEIOgjjCEwIeAhNCE0IeAjaCHcI2gh4CIAIIAh7CHsIIAjkCCAIHgjkCB4IHwjkCF8IXgjkCOQIXgh7CMEIwAjlCOUIwAjWCJYIlQjWCNYIlQjlCJUIgwjlCOUIgwjMCG4IwQjMCMwIwQjlCIQIxwjLCMsIxwjICMoIbQjICMgIbQjLCGQIeAhvCG8IeAh2CGQIbwhgCGAIbwhxCNwIsgjfCN8Isgi8CLII3AiwCLAI3AivCLwIvQjhCOEIvQjZCGYIZwiwCLAIZwixCGgIZwhlCGUIZwhmCGUIGQhoCGgIGQgdCBcIHAgZCBkIHAgdCB8IHAhiCGIIHAgXCOQIHwhfCF8IHwhiCOYI5wjoCOgI5wg1BiEH5wgVCBUI5wjpCBUIFAghByEHFAggBxQIHwcgByAHHwceBz8EQgQeBx4HQgQgB+oI6wjsCOwI6wjtCBgHEwjuCO4IEwjtCO8I8AjxCPEI8AjyCBwH8whFBkUG8whDBhUI6QgSCBII6QjsCBgH7ggXBxcH7gjyCDkIQAj0CPQIQAj1CCkI9ghDCEMI9gj3CBkH8AgaBxoH8Aj4CPkIQAj6CPoIQAhDCEQENQYhByEHNQbnCPsIQwb8CPwIQwbzCP0I/gjnCOcI/gjpCP8IAAnpCOkIAAnsCBMIEgjtCO0IEgjsCAEJ7ggCCQIJ7gjtCAMJ8ggECQQJ8gjuCBcH8ggZBxkH8gjwCAUJ+AgGCQYJ+AjwCAcJ8wgICQgJ8wj4CAkJ2giuCK4I2gitCAkJrghFCEUIrgioCAkJRQgKCQoJRQhCCE0I2ghOCE4I2ggJCU4ICQnTCNMICQkKCUAI0whDCEMI0wgKCUMICglCCD4ITgg/CD8ITgjTCBoH+AgcBxwH+AjzCIEGggZxBnEGggZzBo4GjwaBBoEGjwaCBpsGnAaOBo4GnAaPBqgGqQabBpsGqQacBqgGtQapBqkGtQZXA8EGWgO1BrUGWgNXAwgHHQdnAw4HFAcdBx0HFAcbB5IEgwSTBJMEgwSFBIQEmASGBIYEmASJBIgElASGBIYElASFBJUEjgSTBJMEjgSQBJoEhwSXBJcEhwSJBIsEkQSNBI0EkQSQBJYEnASXBJcEnASbBI8EvgSNBI0EvgSMBJ8EmQSeBJ4EmQSbBIoEjAS6BLoEjAS7BKcEoQSdBJ0EoQSeBLgEuQS9BL0EuQS7BKAEoQSiBKIEoQSjBLwEuQS0BLQEuQS1BKoEpQSmBKYEpQSjBLIEswS3BLcEswS1BKQEpQSrBKsEpQSpBLYEswSuBK4EswSvBLAErQSoBKgErQSpBKwErQSxBLEErQSvBGAHYQdyB3IHYQdjB20HbgdeB14HbgdfB2QHYQdvB28HYQdfB3YHcwdiB2IHcwdjB3AHbgdpB2kHbgdqB3EHcwd3B3cHcwd1B2cHaAdsB2wHaAdqB3oHeQd0B3QHeQd1B2sHaAeZB5kHaAdmB4IHeAd8B3wHeAd5B2UHlQdmB2YHlQeXB3sHfQd8B3wHfQd/B5MHmAeUB5QHmAeXB4QHgQeAB4AHgQd/B5YHjweUB5QHjweRB34HhgeAB4AHhgeFB40HkgeOB44HkgeRB4oHgweIB4gHgweFB5AHiQeOB44HiQeLB4cHjAeIB4gHjAeLB2MC3AJhAmEC3AILCSECwgIbAhsCwgLcAgsJ3AIQAxAD3ALCApoCmQJCA0IDmQJDA6QCQQOdAp0CQQNCA6ICoAJAA0ADoAJBA80CPgOlAqUCPgNAA80C9wI+Az4D9wI/A+4CPQMjAyMDPQM7A08COQNNAk0COQM6A6kCOQOqAqoCOQM4A2ACNwNSAlICNwM4A7MCNwO0ArQCNwM2A14C2QI2AzYD2QI1A7wCuwI0AzQDuwI1AxkDGwMyAzIDGwMzA+0G+AZhA2ED+AZiA+IG7QZfA18D7QZhA9cG4gZeA14D4gZfA8wG1wZbA1sD1wZeA2QDYgMABwAHYgP4BmcDZAMIBwgHZAMAB2cDHQfWAdYBHQc9BNYBPQSVAZUBPQQ+BFoDwQZbA1sDwQbMBgwJdgYNCQ0JdgZ1BlcD1QGpBqkG1QGqBg4JDQmDBoMGDQl1Bg8JDgmQBpAGDgmDBg8JkAYQCRAJkAadBrYGEAmqBqoGEAmdBrsBvAFNA00DvAERCXIAdAC4AbgBdAC6AREEkAEaBBoEkAGTAREEBQSQAZABBQSOAYEDgAOFA4UDgAOEA4UBhgESCRIJhgG9AxMJkwODA4MDkwOFAxQJoQMTCRMJoQOTAxUJrwMUCRQJrwOhAxIJvQMVCRUJvQOvA+ED1QOLAYsB1QOKAYsBjQHhA+EDjQHtA+0DjQH5A/kDjQGOAQUE+QOOAZUBPgQWCRYJkwGVARwHRQYbBxsHRQY8BDoEPAQ7BDsEPARFBgEAFwkDAAMAFwkYCQQAGQkBAAEAGQkXCQcAGgkEAAQAGgkZCQgAGwkHAAcAGwkaCcAAvwAcCRwJvwAdCcIAwQAeCR4JwQAfCb8AwgAdCR0JwgAeCQMAGAnFAMUAGAkgCccAwAAhCSEJwAAcCcUAIAlrAWsBIAkiCX0BxwAjCSMJxwAhCWsBIgnBAMEAIgkfCRsJCAAkCSQJCACXAX0BIwnRAdEBIwklCdoB2wEmCSYJ2wEnCd0B2gEoCSgJ2gEmCd8B3QEpCSkJ3QEoCd8BKQnhAeEBKQkqCZcCKwmYApgCKwksCZsCLQmZApkCLQkuCZgCLAmbApsCLAktCdsBngInCScJngIvCZ8CMAmXApcCMAkrCZ4CQwMvCS8JQwMxCeEBKglFA0UDKgkyCdEBJQmfAp8CJQkwCUMDmQIxCTEJmQIuCRgJFwkzCRcJGQkzCRkJGgkzCRoJGwkzCRwJHQkzCR4JHwkzCR0JHgkzCSAJGAkzCSEJHAkzCSIJIAkzCSMJIQkzCR8JIgkzCRsJJAkzCSQJMgkzCSUJIwkzCSYJJwkzCSgJJgkzCSkJKAkzCSoJKQkzCSwJKwkzCS4JLQkzCS0JLAkzCScJLwkzCSsJMAkzCS8JMQkzCTIJKgkzCTAJJQkzCTEJLgkzCT4EKwQWCRYJKwQkBBoEkwEkBCQEkwEWCQgHDgcdBzIJJAlFA0UDJAmXAVkANAlXAFcANAk1CUYDRAOZAZkBRAOYAUQDRQOYAZgBRQOXAUcDRgOaAZoBRgOZAUcDmgFMA0wDmgG4AUwDuAG5AbkBuAG6AXQAggC6AboBggC8AYIAhAC8AbwBhAARCU4DNglPA08DNgk3CU8DNwlQA1ADNwk4CVADOAlRA1EDOAk5CVEDOQlKA0oDOQk6CUsDSgM7CTsJSgM6CUgDSwM8CTwJSwM7CUgDPAlJA0kDPAk9CTQJWQA+CT4JWQCjAJUAPwmjAKMAPwk+CZQAQAmVAJUAQAk/CY0ATQDBAcEBTQCqAUsAqAFNAE0AqAGqAU4ArAFLAEsArAGoAU4AUQCsAawBUQCuAVEAfwGuAa4BfwHNAX8BgQHNAc0BgQHPAYQB0gGBAYEB0gHPAYUB1AGEAYQB1AHSARIJtgaFAYUBtgbUARUJEAkSCRIJEAm2BhUJFAkQCRAJFAkPCRQJEwkPCQ8JEwkOCRMJgwMOCQ4JgwMNCYMDggMNCQ0JggMMCUYEDAmCA3YGDAlGBEYEhAOAAz4BQQlAAUABQQlCCUQBQwlCAUIBQwlECUIBRAk+AT4BRAlBCQwBCQFFCUUJCQFGCQoBEgFHCUcJEgFICQkBCgFGCUYJCgFHCSEBDAFJCUkJDAFFCUABQgkTARMBQglKCRIBEwFICUgJEwFKCRsBFAEdAR0BFAEeAWUBSwkXARcBSwlMCRcBTAkZARkBTAlNCR0BHgEkASQBHgEiAWUBIQFLCUsJIQFJCSQBIgEmASYBIgEnASYBJwEqASoBJwEoASwBKgEtAS0BKgEoATsBLAE5ATkBLAEtATYBNwFOCU4JNwFPCTMBOwEvAS8BOwE5ATIBMwEuAS4BMwEvAUQBNgFDCUMJNgFOCRwDGgNQCVAJGgNRCRcDGANSCVIJGANTCRoDFwNRCVEJFwNSCeICVAnpAukCVAlVCeQCVgngAuACVglXCeACVwniAuICVwlUCfkCWAnkAuQCWAlWCRgD6wJTCVMJ6wJZCekCVQnrAusCVQlZCTwD8AJaCVoJ8AJbCfQC9QLsAuwC9QL2AvAC8QJbCVsJ8QJcCfUC/AL2AvYC/AL6AjwDWgn5AvkCWglYCfwC/gL6AvoC/gL/Av4CAgP/Av8CAgMAAwQDBQMCAwIDBQMAAxMDEQMEAwQDEQMFAwsDBgMTAxMDBgMRAw0DXQkPAw8DXQleCQkDBwMLAwsDBwMGAxwDUAkNAw0DUAldCWIIFwgWCD0FPAU/BQ==" + } + ] +} diff --git a/example/ios/.gitignore b/example/ios/.gitignore new file mode 100644 index 00000000..7a7f9873 --- /dev/null +++ b/example/ios/.gitignore @@ -0,0 +1,34 @@ +**/dgph +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/ephemeral/ +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 00000000..391a902b --- /dev/null +++ b/example/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + + diff --git a/example/ios/Flutter/Debug.xcconfig b/example/ios/Flutter/Debug.xcconfig new file mode 100644 index 00000000..ec97fc6f --- /dev/null +++ b/example/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/example/ios/Flutter/Release.xcconfig b/example/ios/Flutter/Release.xcconfig new file mode 100644 index 00000000..c4855bfe --- /dev/null +++ b/example/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/example/ios/Podfile b/example/ios/Podfile new file mode 100644 index 00000000..620e46eb --- /dev/null +++ b/example/ios/Podfile @@ -0,0 +1,43 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '13.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock new file mode 100644 index 00000000..4d20719c --- /dev/null +++ b/example/ios/Podfile.lock @@ -0,0 +1,164 @@ +PODS: + - ar_flutter_plugin_2 (0.6.2): + - ARCoreNanoPbUpdated/CloudAnchors (~> 1.46.0.2) + - Flutter + - GLTFSceneKit + - SwiftJWT + - ARCoreNanoPbUpdated/Base (1.46.0.2): + - GoogleDataTransport (~> 10.1.0) + - nanopb (~> 3.30910) + - ARCoreNanoPbUpdated/CloudAnchors (1.46.0.2): + - ARCoreNanoPbUpdated/Base (~> 1.46.0.2) + - ARCoreNanoPbUpdated/GARSession (~> 1.46.0.2) + - ARCoreNanoPbUpdated/TFShared (~> 1.46.0.2) + - GTMSessionFetcher/Core (< 4.1.0, >= 3.4) + - nanopb (~> 3.30910) + - ARCoreNanoPbUpdated/GARSession (1.46.0.2): + - ARCoreNanoPbUpdated/Base (~> 1.46.0.2) + - Firebase/RemoteConfig (~> 11.2) + - nanopb (~> 3.30910) + - ARCoreNanoPbUpdated/TFShared (1.46.0.2): + - ARCoreNanoPbUpdated/Base (~> 1.46.0.2) + - BlueCryptor (1.0.32) + - BlueECC (1.2.201) + - BlueRSA (1.0.200) + - Firebase/CoreOnly (11.15.0): + - FirebaseCore (~> 11.15.0) + - Firebase/RemoteConfig (11.15.0): + - Firebase/CoreOnly + - FirebaseRemoteConfig (~> 11.15.0) + - FirebaseABTesting (11.15.0): + - FirebaseCore (~> 11.15.0) + - FirebaseCore (11.15.0): + - FirebaseCoreInternal (~> 11.15.0) + - GoogleUtilities/Environment (~> 8.1) + - GoogleUtilities/Logger (~> 8.1) + - FirebaseCoreInternal (11.15.0): + - "GoogleUtilities/NSData+zlib (~> 8.1)" + - FirebaseInstallations (11.15.0): + - FirebaseCore (~> 11.15.0) + - GoogleUtilities/Environment (~> 8.1) + - GoogleUtilities/UserDefaults (~> 8.1) + - PromisesObjC (~> 2.4) + - FirebaseRemoteConfig (11.15.0): + - FirebaseABTesting (~> 11.0) + - FirebaseCore (~> 11.15.0) + - FirebaseInstallations (~> 11.0) + - FirebaseRemoteConfigInterop (~> 11.0) + - FirebaseSharedSwift (~> 11.0) + - GoogleUtilities/Environment (~> 8.1) + - "GoogleUtilities/NSData+zlib (~> 8.1)" + - FirebaseRemoteConfigInterop (11.15.0) + - FirebaseSharedSwift (11.15.0) + - Flutter (1.0.0) + - geolocator_apple (1.2.0): + - Flutter + - FlutterMacOS + - GLTFSceneKit (0.3.0) + - GoogleDataTransport (10.1.0): + - nanopb (~> 3.30910.0) + - PromisesObjC (~> 2.4) + - GoogleUtilities/Environment (8.1.1): + - GoogleUtilities/Privacy + - GoogleUtilities/Logger (8.1.1): + - GoogleUtilities/Environment + - GoogleUtilities/Privacy + - "GoogleUtilities/NSData+zlib (8.1.1)": + - GoogleUtilities/Privacy + - GoogleUtilities/Privacy (8.1.1) + - GoogleUtilities/UserDefaults (8.1.1): + - GoogleUtilities/Logger + - GoogleUtilities/Privacy + - GTMSessionFetcher/Core (4.0.0) + - KituraContracts (1.2.1): + - LoggerAPI (~> 1.7) + - LoggerAPI (1.9.200): + - Logging (~> 1.1) + - Logging (1.4.0) + - nanopb (3.30910.0): + - nanopb/decode (= 3.30910.0) + - nanopb/encode (= 3.30910.0) + - nanopb/decode (3.30910.0) + - nanopb/encode (3.30910.0) + - permission_handler_apple (9.4.8): + - Flutter + - PromisesObjC (2.4.1) + - SwiftJWT (3.6.200): + - BlueCryptor (~> 1.0) + - BlueECC (~> 1.1) + - BlueRSA (~> 1.0) + - KituraContracts (~> 1.2) + - LoggerAPI (~> 1.7) + +DEPENDENCIES: + - ar_flutter_plugin_2 (from `.symlinks/plugins/ar_flutter_plugin_2/ios`) + - Flutter (from `Flutter`) + - geolocator_apple (from `.symlinks/plugins/geolocator_apple/darwin`) + - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) + +SPEC REPOS: + trunk: + - ARCoreNanoPbUpdated + - BlueCryptor + - BlueECC + - BlueRSA + - Firebase + - FirebaseABTesting + - FirebaseCore + - FirebaseCoreInternal + - FirebaseInstallations + - FirebaseRemoteConfig + - FirebaseRemoteConfigInterop + - FirebaseSharedSwift + - GLTFSceneKit + - GoogleDataTransport + - GoogleUtilities + - GTMSessionFetcher + - KituraContracts + - LoggerAPI + - Logging + - nanopb + - PromisesObjC + - SwiftJWT + +EXTERNAL SOURCES: + ar_flutter_plugin_2: + :path: ".symlinks/plugins/ar_flutter_plugin_2/ios" + Flutter: + :path: Flutter + geolocator_apple: + :path: ".symlinks/plugins/geolocator_apple/darwin" + permission_handler_apple: + :path: ".symlinks/plugins/permission_handler_apple/ios" + +SPEC CHECKSUMS: + ar_flutter_plugin_2: 4897592337d4652aa1b3a69d10308754d4c00be9 + ARCoreNanoPbUpdated: 2fa532214834ff7073153227ee679a92075eed5c + BlueCryptor: b0aee3d9b8f367b49b30de11cda90e1735571c24 + BlueECC: c9662360a702839aa4d324f9f4cc8b899f6f7dd6 + BlueRSA: dfeef51db96bcc4edec654956c1581adbda4e6a3 + Firebase: d99ac19b909cd2c548339c2241ecd0d1599ab02e + FirebaseABTesting: 5e9d432834aebf27ab72100d37af44dfbe8d82f7 + FirebaseCore: efb3893e5b94f32b86e331e3bd6dadf18b66568e + FirebaseCoreInternal: 9afa45b1159304c963da48addb78275ef701c6b4 + FirebaseInstallations: 317270fec08a5d418fdbc8429282238cab3ac843 + FirebaseRemoteConfig: b496646b82855e174a7f1e354c65e0e913085168 + FirebaseRemoteConfigInterop: 1c6135e8a094cc6368949f5faeeca7ee8948b8aa + FirebaseSharedSwift: e17c654ef1f1a616b0b33054e663ad1035c8fd40 + Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 + geolocator_apple: ab36aa0e8b7d7a2d7639b3b4e48308394e8cef5e + GLTFSceneKit: d1b437c514ba2aed5555afb0fddd64e030612d57 + GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 + GoogleUtilities: 4f2618a4a1e762a1ee134a1e2323bba9843e06da + GTMSessionFetcher: 4e28ef1d6434633476ab4328d438d78713fff396 + KituraContracts: e845e60dc8627ad0a76fa55ef20a45451d8f830b + LoggerAPI: ad9c4a6f1e32f518fdb43a1347ac14d765ab5e3d + Logging: beeb016c9c80cf77042d62e83495816847ef108b + nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 + permission_handler_apple: 92d754bbaa7361d436db2d6c3c1c2a0fdcec462e + PromisesObjC: 752c3227f599e3467650e47ea36f433eeb10c273 + SwiftJWT: 88c412708f58c169d431d344c87bc79a87c830ae + +PODFILE CHECKSUM: 3c63482e143d1b91d2d2560aee9fb04ecc74ac7e + +COCOAPODS: 1.16.2 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..91dd06a6 --- /dev/null +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,753 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + A899468D8FE293BBFE0F3638 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DFA157668609656FA77AE5ED /* Pods_Runner.framework */; }; + E008E2CBB703962388FBFBB7 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0B7BFD7CCF33B6403B94F3DB /* Pods_RunnerTests.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 0B7BFD7CCF33B6403B94F3DB /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 16B04854529887EC93287C31 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 59B1BA24D3558B803DCC6F1D /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 5DF72C93F8189FEFDBEAC4F4 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 7001D885F4A9DFD4D8B981F0 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + DCDFC8692D9096558BBCDE56 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + DFA157668609656FA77AE5ED /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + FAD4389E33299F97468BD236 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + A899468D8FE293BBFE0F3638 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B1475B99471D2AB2CCF1519E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + E008E2CBB703962388FBFBB7 /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 34EDB0A689F1DF5A5D0C1B08 /* Pods */ = { + isa = PBXGroup; + children = ( + DCDFC8692D9096558BBCDE56 /* Pods-Runner.debug.xcconfig */, + 59B1BA24D3558B803DCC6F1D /* Pods-Runner.release.xcconfig */, + 5DF72C93F8189FEFDBEAC4F4 /* Pods-Runner.profile.xcconfig */, + 7001D885F4A9DFD4D8B981F0 /* Pods-RunnerTests.debug.xcconfig */, + FAD4389E33299F97468BD236 /* Pods-RunnerTests.release.xcconfig */, + 16B04854529887EC93287C31 /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + 7658582F45362B945DDD4E33 /* Frameworks */ = { + isa = PBXGroup; + children = ( + DFA157668609656FA77AE5ED /* Pods_Runner.framework */, + 0B7BFD7CCF33B6403B94F3DB /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + 331C8082294A63A400263BE5 /* RunnerTests */, + 34EDB0A689F1DF5A5D0C1B08 /* Pods */, + 7658582F45362B945DDD4E33 /* Frameworks */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 0B7A9FC036CD458B0DBD08B6 /* [CP] Check Pods Manifest.lock */, + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, + B1475B99471D2AB2CCF1519E /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + B9C726C0F687FE6B313990B1 /* [CP] Check Pods Manifest.lock */, + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + A65804B17AEACDC3DD74AF35 /* [CP] Embed Pods Frameworks */, + B53BD65304E93C6AD4650D7C /* [CP] Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 0B7A9FC036CD458B0DBD08B6 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; + A65804B17AEACDC3DD74AF35 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + B53BD65304E93C6AD4650D7C /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + B9C726C0F687FE6B313990B1 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + 7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 2324DZSF82; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.arFlutterPlugin2Example; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7001D885F4A9DFD4D8B981F0 /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.arFlutterPlugin2Example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = FAD4389E33299F97468BD236 /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.arFlutterPlugin2Example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 16B04854529887EC93287C31 /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.arFlutterPlugin2Example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 2324DZSF82; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.arFlutterPlugin2Example; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 2324DZSF82; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.arFlutterPlugin2Example; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..919434a6 --- /dev/null +++ b/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..e3773d42 --- /dev/null +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/example/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..21a3cc14 --- /dev/null +++ b/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/example/ios/Runner/AppDelegate.swift b/example/ios/Runner/AppDelegate.swift new file mode 100644 index 00000000..c30b367e --- /dev/null +++ b/example/ios/Runner/AppDelegate.swift @@ -0,0 +1,16 @@ +import Flutter +import UIKit + +@main +@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } + + func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) { + GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry) + } +} diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..d36b1fab --- /dev/null +++ b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..dc9ada4725e9b0ddb1deab583e5b5102493aa332 GIT binary patch literal 10932 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 literal 0 HcmV?d00001 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..797d452e458972bab9d994556c8305db4c827017 GIT binary patch literal 406 zcmV;H0crk;P))>cdjpWt&rLJgVp-t?DREyuq1A%0Z4)6_WsQ7{nzjN zo!X zGXV)2i3kcZIL~_j>uIKPK_zib+3T+Nt3Mb&Br)s)UIaA}@p{wDda>7=Q|mGRp7pqY zkJ!7E{MNz$9nOwoVqpFb)}$IP24Wn2JJ=Cw(!`OXJBr45rP>>AQr$6c7slJWvbpNW z@KTwna6d?PP>hvXCcp=4F;=GR@R4E7{4VU^0p4F>v^#A|>07*qoM6N<$f*5nx ACIA2c literal 0 HcmV?d00001 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..6ed2d933e1120817fe9182483a228007b18ab6ae GIT binary patch literal 450 zcmV;z0X_bSP)iGWQ_5NJQ_~rNh*z)}eT%KUb z`7gNk0#AwF^#0T0?hIa^`~Ck;!}#m+_uT050aTR(J!bU#|IzRL%^UsMS#KsYnTF*!YeDOytlP4VhV?b} z%rz_<=#CPc)tU1MZTq~*2=8~iZ!lSa<{9b@2Jl;?IEV8)=fG217*|@)CCYgFze-x? zIFODUIA>nWKpE+bn~n7;-89sa>#DR>TSlqWk*!2hSN6D~Qb#VqbP~4Fk&m`@1$JGr zXPIdeRE&b2Thd#{MtDK$px*d3-Wx``>!oimf%|A-&-q*6KAH)e$3|6JV%HX{Hig)k suLT-RhftRq8b9;(V=235Wa|I=027H2wCDra;{X5v07*qoM6N<$f;9x^2LJ#7 literal 0 HcmV?d00001 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..4cd7b0099ca80c806f8fe495613e8d6c69460d76 GIT binary patch literal 282 zcmV+#0p(^bcu7P-R4C8Q z&e;xxFbF_Vrezo%_kH*OKhshZ6BFpG-Y1e10`QXJKbND7AMQ&cMj60B5TNObaZxYybcN07*qoM6N<$g3m;S%K!iX literal 0 HcmV?d00001 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..fe730945a01f64a61e2235dbe3f45b08f7729182 GIT binary patch literal 462 zcmV;<0WtoGP)-}iV`2<;=$?g5M=KQbZ{F&YRNy7Nn@%_*5{gvDM0aKI4?ESmw z{NnZg)A0R`+4?NF_RZexyVB&^^ZvN!{I28tr{Vje;QNTz`dG&Jz0~Ek&f2;*Z7>B|cg}xYpxEFY+0YrKLF;^Q+-HreN0P{&i zK~zY`?b7ECf-n?@;d<&orQ*Q7KoR%4|C>{W^h6@&01>0SKS`dn{Q}GT%Qj_{PLZ_& zs`MFI#j-(>?bvdZ!8^xTwlY{qA)T4QLbY@j(!YJ7aXJervHy6HaG_2SB`6CC{He}f zHVw(fJWApwPq!6VY7r1w-Fs)@ox~N+q|w~e;JI~C4Vf^@d>Wvj=fl`^u9x9wd9 zR%3*Q+)t%S!MU_`id^@&Y{y7-r98lZX0?YrHlfmwb?#}^1b{8g&KzmkE(L>Z&)179 zp<)v6Y}pRl100G2FL_t(o!|l{-Q-VMg#&MKg7c{O0 z2wJImOS3Gy*Z2Qifdv~JYOp;v+U)a|nLoc7hNH;I$;lzDt$}rkaFw1mYK5_0Q(Sut zvbEloxON7$+HSOgC9Z8ltuC&0OSF!-mXv5caV>#bc3@hBPX@I$58-z}(ZZE!t-aOG zpjNkbau@>yEzH(5Yj4kZiMH32XI!4~gVXNnjAvRx;Sdg^`>2DpUEwoMhTs_st8pKG z(%SHyHdU&v%f36~uERh!bd`!T2dw;z6PrOTQ7Vt*#9F2uHlUVnb#ev_o^fh}Dzmq} zWtlk35}k=?xj28uO|5>>$yXadTUE@@IPpgH`gJ~Ro4>jd1IF|(+IX>8M4Ps{PNvmI zNj4D+XgN83gPt_Gm}`Ybv{;+&yu-C(Grdiahmo~BjG-l&mWM+{e5M1sm&=xduwgM9 z`8OEh`=F3r`^E{n_;%9weN{cf2%7=VzC@cYj+lg>+3|D|_1C@{hcU(DyQG_BvBWe? zvTv``=%b1zrol#=R`JB)>cdjpWt&rLJgVp-t?DREyuq1A%0Z4)6_WsQ7{nzjN zo!X zGXV)2i3kcZIL~_j>uIKPK_zib+3T+Nt3Mb&Br)s)UIaA}@p{wDda>7=Q|mGRp7pqY zkJ!7E{MNz$9nOwoVqpFb)}$IP24Wn2JJ=Cw(!`OXJBr45rP>>AQr$6c7slJWvbpNW z@KTwna6d?PP>hvXCcp=4F;=GR@R4E7{4VU^0p4F>v^#A|>07*qoM6N<$f*5nx ACIA2c literal 0 HcmV?d00001 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..502f463a9bc882b461c96aadf492d1729e49e725 GIT binary patch literal 586 zcmV-Q0=4~#P)+}#`wDE{8-2Mebf5<{{PqV{TgVcv*r8?UZ3{-|G?_}T*&y;@cqf{ z{Q*~+qr%%p!1pS*_Uicl#q9lc(D`!D`LN62sNwq{oYw(Wmhk)k<@f$!$@ng~_5)Ru z0Z)trIA5^j{DIW^c+vT2%lW+2<(RtE2wR;4O@)Tm`Xr*?A(qYoM}7i5Yxw>D(&6ou zxz!_Xr~yNF+waPe00049Nkl*;a!v6h%{rlvIH#gW3s8p;bFr=l}mRqpW2h zw=OA%hdyL~z+UHOzl0eKhEr$YYOL-c-%Y<)=j?(bzDweB7{b+%_ypvm_cG{SvM=DK zhv{K@m>#Bw>2W$eUI#iU)Wdgs8Y3U+A$Gd&{+j)d)BmGKx+43U_!tik_YlN)>$7G! zhkE!s;%oku3;IwG3U^2kw?z+HM)jB{@zFhK8P#KMSytSthr+4!c(5c%+^UBn`0X*2 zy3(k600_CSZj?O$Qu%&$;|TGUJrptR(HzyIx>5E(2r{eA(<6t3e3I0B)7d6s7?Z5J zZ!rtKvA{MiEBm&KFtoifx>5P^Z=vl)95XJn()aS5%ad(s?4-=Tkis9IGu{`Fy8r+H07*qoM6N<$f20Z)wqMt%V?S?~D#06};F zA3KcL`Wb+>5ObvgQIG&ig8(;V04hz?@cqy3{mSh8o!|U|)cI!1_+!fWH@o*8vh^CU z^ws0;(c$gI+2~q^tO#GDHf@=;DncUw00J^eL_t(&-tE|HQ`%4vfZ;WsBqu-$0nu1R zq^Vj;p$clf^?twn|KHO+IGt^q#a3X?w9dXC@*yxhv&l}F322(8Y1&=P&I}~G@#h6; z1CV9ecD9ZEe87{{NtI*)_aJ<`kJa z?5=RBtFF50s;jQLFil-`)m2wrb=6h(&brpj%nG_U&ut~$?8Rokzxi8zJoWr#2dto5 zOX_URcc<1`Iky+jc;A%Vzx}1QU{2$|cKPom2Vf1{8m`vja4{F>HS?^Nc^rp}xo+Nh zxd}eOm`fm3@MQC1< zIk&aCjb~Yh%5+Yq0`)D;q{#-Uqlv*o+Oor zE!I71Z@ASH3grl8&P^L0WpavHoP|UX4e?!igT`4?AZk$hu*@%6WJ;zDOGlw7kj@ zY5!B-0ft0f?Lgb>C;$Ke07*qoM6N<$f~t1N9smFU literal 0 HcmV?d00001 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0ec303439225b78712f49115768196d8d76f6790 GIT binary patch literal 862 zcmV-k1EKthP)20Z)wqMt%V?S?~D#06};F zA3KcL`Wb+>5ObvgQIG&ig8(;V04hz?@cqy3{mSh8o!|U|)cI!1_+!fWH@o*8vh^CU z^ws0;(c$gI+2~q^tO#GDHf@=;DncUw00J^eL_t(&-tE|HQ`%4vfZ;WsBqu-$0nu1R zq^Vj;p$clf^?twn|KHO+IGt^q#a3X?w9dXC@*yxhv&l}F322(8Y1&=P&I}~G@#h6; z1CV9ecD9ZEe87{{NtI*)_aJ<`kJa z?5=RBtFF50s;jQLFil-`)m2wrb=6h(&brpj%nG_U&ut~$?8Rokzxi8zJoWr#2dto5 zOX_URcc<1`Iky+jc;A%Vzx}1QU{2$|cKPom2Vf1{8m`vja4{F>HS?^Nc^rp}xo+Nh zxd}eOm`fm3@MQC1< zIk&aCjb~Yh%5+Yq0`)D;q{#-Uqlv*o+Oor zE!I71Z@ASH3grl8&P^L0WpavHoP|UX4e?!igT`4?AZk$hu*@%6WJ;zDOGlw7kj@ zY5!B-0ft0f?Lgb>C;$Ke07*qoM6N<$f~t1N9smFU literal 0 HcmV?d00001 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..e9f5fea27c705180eb716271f41b582e76dcbd90 GIT binary patch literal 1674 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 literal 0 HcmV?d00001 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0467bf12aa4d28f374bb26596605a46dcbb3e7c8 GIT binary patch literal 1418 zcmV;51$Fv~P)q zKfU)WzW*n(@|xWGCA9ScMt*e9`2kdxPQ&&>|-UCa7_51w+ zLUsW@ZzZSW0y$)Hp~e9%PvP|a03ks1`~K?q{u;6NC8*{AOqIUq{CL&;p56Lf$oQGq z^={4hPQv)y=I|4n+?>7Fim=dxt1 z2H+Dm+1+fh+IF>G0SjJMkQQre1x4|G*Z==(Ot&kCnUrL4I(rf(ucITwmuHf^hXiJT zkdTm&kdTm&kdTm&kdP`esgWG0BcWCVkVZ&2dUwN`cgM8QJb`Z7Z~e<&Yj2(}>Tmf` zm1{eLgw!b{bXkjWbF%dTkTZEJWyWOb##Lfw4EK2}<0d6%>AGS{po>WCOy&f$Tay_> z?NBlkpo@s-O;0V%Y_Xa-G#_O08q5LR*~F%&)}{}r&L%Sbs8AS4t7Y0NEx*{soY=0MZExqA5XHQkqi#4gW3 zqODM^iyZl;dvf)-bOXtOru(s)Uc7~BFx{w-FK;2{`VA?(g&@3z&bfLFyctOH!cVsF z7IL=fo-qBndRUm;kAdXR4e6>k-z|21AaN%ubeVrHl*<|s&Ax@W-t?LR(P-24A5=>a z*R9#QvjzF8n%@1Nw@?CG@6(%>+-0ASK~jEmCV|&a*7-GKT72W<(TbSjf)&Eme6nGE z>Gkj4Sq&2e+-G%|+NM8OOm5zVl9{Z8Dd8A5z3y8mZ=4Bv4%>as_{9cN#bm~;h>62( zdqY93Zy}v&c4n($Vv!UybR8ocs7#zbfX1IY-*w~)p}XyZ-SFC~4w>BvMVr`dFbelV{lLL0bx7@*ZZdebr3`sP;? zVImji)kG)(6Juv0lz@q`F!k1FE;CQ(D0iG$wchPbKZQELlsZ#~rt8#90Y_Xh&3U-< z{s<&cCV_1`^TD^ia9!*mQDq& zn2{r`j};V|uV%_wsP!zB?m%;FeaRe+X47K0e+KE!8C{gAWF8)lCd1u1%~|M!XNRvw zvtqy3iz0WSpWdhn6$hP8PaRBmp)q`#PCA`Vd#Tc$@f1tAcM>f_I@bC)hkI9|o(Iqv zo}Piadq!j76}004RBio<`)70k^`K1NK)q>w?p^C6J2ZC!+UppiK6&y3Kmbv&O!oYF z34$0Z;QO!JOY#!`qyGH<3Pd}Pt@q*A0V=3SVtWKRR8d8Z&@)3qLPA19LPA19LPEUC YUoZo%k(ykuW&i*H07*qoM6N<$f+CH{y8r+H literal 0 HcmV?d00001 diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 00000000..0bedcf2f --- /dev/null +++ b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 00000000..89c2725b --- /dev/null +++ b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/example/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 00000000..f2e259c7 --- /dev/null +++ b/example/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/ios/Runner/Base.lproj/Main.storyboard b/example/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 00000000..f3c28516 --- /dev/null +++ b/example/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist new file mode 100644 index 00000000..2a27ebc2 --- /dev/null +++ b/example/ios/Runner/Info.plist @@ -0,0 +1,72 @@ + + + + + CADisableMinimumFrameDurationOnPhone + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Ar Flutter Plugin 2 Example + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ar_flutter_plugin_2_example + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneClassName + UIWindowScene + UISceneConfigurationName + flutter + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + Main + + + + + UIApplicationSupportsIndirectInputEvents + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + NSCameraUsageDescription + This app needs camera access to display augmented reality content. + + diff --git a/example/ios/Runner/Runner-Bridging-Header.h b/example/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 00000000..308a2a56 --- /dev/null +++ b/example/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/example/ios/Runner/SceneDelegate.swift b/example/ios/Runner/SceneDelegate.swift new file mode 100644 index 00000000..b9ce8ea2 --- /dev/null +++ b/example/ios/Runner/SceneDelegate.swift @@ -0,0 +1,6 @@ +import Flutter +import UIKit + +class SceneDelegate: FlutterSceneDelegate { + +} diff --git a/example/ios/RunnerTests/RunnerTests.swift b/example/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..86a7c3b1 --- /dev/null +++ b/example/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/example/lib/demos/cloud_anchor_demo.dart b/example/lib/demos/cloud_anchor_demo.dart new file mode 100644 index 00000000..fd6eea9c --- /dev/null +++ b/example/lib/demos/cloud_anchor_demo.dart @@ -0,0 +1,311 @@ +import 'package:flutter/material.dart'; +import 'package:vector_math/vector_math_64.dart'; + +import 'package:ar_flutter_plugin_2/ar_flutter_plugin.dart'; +import 'package:ar_flutter_plugin_2/datatypes/config_planedetection.dart'; +import 'package:ar_flutter_plugin_2/datatypes/hittest_result_types.dart'; +import 'package:ar_flutter_plugin_2/datatypes/node_types.dart'; +import 'package:ar_flutter_plugin_2/managers/ar_anchor_manager.dart'; +import 'package:ar_flutter_plugin_2/managers/ar_location_manager.dart'; +import 'package:ar_flutter_plugin_2/managers/ar_object_manager.dart'; +import 'package:ar_flutter_plugin_2/managers/ar_session_manager.dart'; +import 'package:ar_flutter_plugin_2/models/ar_anchor.dart'; +import 'package:ar_flutter_plugin_2/models/ar_hittest_result.dart'; +import 'package:ar_flutter_plugin_2/models/ar_node.dart'; + +import '../firebase/firebase_manager.dart'; +import '../main.dart'; + +/// Places objects, hosts their anchor with the Google Cloud Anchor service, and +/// resolves it back so the scene can be shared across devices. +/// +/// Requires a configured Firebase project (see `cloudAnchorSetup.md`). Without +/// one this screen shows a friendly "initialization failed" message instead of +/// crashing. +class CloudAnchorDemo extends StatefulWidget { + const CloudAnchorDemo({super.key}); + + @override + State createState() => _CloudAnchorDemoState(); +} + +class _CloudAnchorDemoState extends State { + final FirebaseManager _firebase = FirebaseManager(); + bool _initialized = false; + bool _error = false; + + ARSessionManager? arSessionManager; + ARObjectManager? arObjectManager; + ARAnchorManager? arAnchorManager; + + final List nodes = []; + final List anchors = []; + final Map> _downloadsInProgress = {}; + + bool _readyToUpload = false; + bool _readyToDownload = true; + + @override + void initState() { + super.initState(); + _initFirebase(); + } + + Future _initFirebase() async { + final ok = await _firebase.initialize(); + if (!mounted) return; + setState(() { + _initialized = ok; + _error = !ok; + }); + } + + @override + void dispose() { + arSessionManager?.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + if (_error) { + return _MessageScaffold( + title: 'Cloud anchors', + message: 'Firebase initialization failed.\n' + 'Add a Firebase configuration to run this demo.', + onRetry: () { + setState(() => _error = false); + _initFirebase(); + }, + ); + } + if (!_initialized) { + return const _MessageScaffold( + title: 'Cloud anchors', + message: 'Initializing Firebase…', + showProgress: true, + ); + } + + return Scaffold( + appBar: AppBar(title: const Text('Cloud anchors')), + body: Stack( + children: [ + ARView( + onARViewCreated: _onARViewCreated, + planeDetectionConfig: PlaneDetectionConfig.horizontalAndVertical, + ), + Align( + alignment: Alignment.topCenter, + child: Padding( + padding: const EdgeInsets.all(12), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + if (_readyToUpload) + ElevatedButton( + onPressed: _upload, child: const Text('Upload')), + if (_readyToDownload) + ElevatedButton( + onPressed: _download, child: const Text('Download')), + ], + ), + ), + ), + Align( + alignment: Alignment.bottomCenter, + child: Padding( + padding: const EdgeInsets.all(12), + child: ElevatedButton.icon( + onPressed: _removeEverything, + icon: const Icon(Icons.delete_outline), + label: const Text('Remove everything'), + ), + ), + ), + ], + ), + ); + } + + void _onARViewCreated( + ARSessionManager sessionManager, + ARObjectManager objectManager, + ARAnchorManager anchorManager, + ARLocationManager locationManager, + ) { + arSessionManager = sessionManager; + arObjectManager = objectManager; + arAnchorManager = anchorManager; + + sessionManager.onInitialize( + showFeaturePoints: false, + showPlanes: true, + customPlaneTexturePath: kPlaneTextureAsset, + showWorldOrigin: true, + ); + objectManager.onInitialize(); + anchorManager.initGoogleCloudAnchorMode(); + + sessionManager.onPlaneOrPointTap = _onPlaneOrPointTapped; + objectManager.onNodeTap = _onNodeTapped; + anchorManager.onAnchorUploaded = _onAnchorUploaded; + anchorManager.onAnchorDownloaded = _onAnchorDownloaded; + } + + Future _onPlaneOrPointTapped(List hits) async { + final planeHits = + hits.where((h) => h.type == ARHitTestResultType.plane).toList(); + if (planeHits.isEmpty) return; + + final anchor = ARPlaneAnchor( + transformation: planeHits.first.worldTransform, ttl: 2); + if (await arAnchorManager!.addAnchor(anchor) != true) { + _snack('Adding anchor failed'); + return; + } + anchors.add(anchor); + + final node = ARNode( + type: NodeType.webGLB, + uri: kDuckGlbUrl, + scale: Vector3(0.2, 0.2, 0.2), + position: Vector3(0, 0, 0), + rotation: Vector4(1, 0, 0, 0), + data: {'onTapText': 'Ouch, that hurt!'}, + ); + if (await arObjectManager!.addNode(node, planeAnchor: anchor) == true) { + nodes.add(node); + setState(() => _readyToUpload = true); + } else { + _snack('Adding node failed'); + } + } + + void _onNodeTapped(List nodeNames) { + if (nodeNames.isEmpty) return; + ARNode? tapped; + for (final n in nodes) { + if (n.name == nodeNames.first) { + tapped = n; + break; + } + } + _snack(tapped?.data?['onTapText']?.toString() ?? 'Tapped a node'); + } + + Future _upload() async { + if (anchors.isEmpty) return; + await arAnchorManager!.uploadAnchor(anchors.last); + setState(() => _readyToUpload = false); + } + + void _onAnchorUploaded(ARAnchor anchor) { + _firebase.uploadAnchor(anchor); + if (anchor is ARPlaneAnchor) { + for (final nodeName in anchor.childNodes) { + for (final node in nodes) { + if (node.name == nodeName) { + _firebase.uploadObject(node); + break; + } + } + } + } + setState(() { + _readyToDownload = true; + _readyToUpload = false; + }); + _snack('Upload successful'); + } + + ARAnchor _onAnchorDownloaded(Map serializedAnchor) { + final cloudId = serializedAnchor['cloudanchorid']; + final raw = _downloadsInProgress.remove(cloudId) ?? serializedAnchor; + final anchor = ARPlaneAnchor.fromJson(raw); + anchors.add(anchor); + + _firebase.getObjectsFromAnchor(anchor, (snapshot) { + for (final doc in snapshot.docs) { + final node = ARNode.fromMap(doc.data()); + arObjectManager!.addNode(node, planeAnchor: anchor); + nodes.add(node); + } + }); + + return anchor; + } + + Future _download() async { + await _firebase.downloadLatestAnchor((snapshot) { + if (snapshot.docs.isEmpty) { + _snack('No uploaded anchors found'); + return; + } + final doc = snapshot.docs.first; + final data = doc.data(); + final cloudId = data['cloudanchorid'] as String?; + if (cloudId == null) return; + _downloadsInProgress[cloudId] = data; + arAnchorManager!.downloadAnchor(cloudId); + }); + setState(() => _readyToDownload = false); + } + + Future _removeEverything() async { + for (final anchor in anchors) { + arAnchorManager!.removeAnchor(anchor); + } + anchors.clear(); + nodes.clear(); + setState(() { + _readyToDownload = true; + _readyToUpload = false; + }); + } + + void _snack(String message) { + if (!mounted) return; + ScaffoldMessenger.of(context) + .showSnackBar(SnackBar(content: Text(message))); + } +} + +/// Simple scaffold for the loading / error states. +class _MessageScaffold extends StatelessWidget { + const _MessageScaffold({ + required this.title, + required this.message, + this.showProgress = false, + this.onRetry, + }); + + final String title; + final String message; + final bool showProgress; + final VoidCallback? onRetry; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: Text(title)), + body: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + if (showProgress) ...[ + const CircularProgressIndicator(), + const SizedBox(height: 16), + ], + Padding( + padding: const EdgeInsets.all(24), + child: Text(message, textAlign: TextAlign.center), + ), + if (onRetry != null) + ElevatedButton(onPressed: onRetry, child: const Text('Retry')), + ], + ), + ), + ); + } +} diff --git a/example/lib/demos/debug_options_demo.dart b/example/lib/demos/debug_options_demo.dart new file mode 100644 index 00000000..2e21a8e3 --- /dev/null +++ b/example/lib/demos/debug_options_demo.dart @@ -0,0 +1,107 @@ +import 'package:flutter/material.dart'; + +import 'package:ar_flutter_plugin_2/ar_flutter_plugin.dart'; +import 'package:ar_flutter_plugin_2/datatypes/config_planedetection.dart'; +import 'package:ar_flutter_plugin_2/managers/ar_anchor_manager.dart'; +import 'package:ar_flutter_plugin_2/managers/ar_location_manager.dart'; +import 'package:ar_flutter_plugin_2/managers/ar_object_manager.dart'; +import 'package:ar_flutter_plugin_2/managers/ar_session_manager.dart'; + +import '../main.dart'; + +/// Toggles the session's debug visualisations (feature points, planes, world +/// origin) live by re-calling [ARSessionManager.onInitialize]. +class DebugOptionsDemo extends StatefulWidget { + const DebugOptionsDemo({super.key}); + + @override + State createState() => _DebugOptionsDemoState(); +} + +class _DebugOptionsDemoState extends State { + ARSessionManager? arSessionManager; + ARObjectManager? arObjectManager; + + bool _showFeaturePoints = false; + bool _showPlanes = true; + bool _showWorldOrigin = false; + + @override + void dispose() { + arSessionManager?.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Debug options')), + body: Stack( + children: [ + ARView( + onARViewCreated: _onARViewCreated, + planeDetectionConfig: PlaneDetectionConfig.horizontalAndVertical, + showPlatformType: true, + ), + Align( + alignment: Alignment.bottomRight, + child: Container( + width: MediaQuery.of(context).size.width * 0.6, + color: Colors.white.withValues(alpha: 0.7), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SwitchListTile( + title: const Text('Feature points'), + value: _showFeaturePoints, + onChanged: (v) => setState(() { + _showFeaturePoints = v; + _applySettings(); + }), + ), + SwitchListTile( + title: const Text('Planes'), + value: _showPlanes, + onChanged: (v) => setState(() { + _showPlanes = v; + _applySettings(); + }), + ), + SwitchListTile( + title: const Text('World origin'), + value: _showWorldOrigin, + onChanged: (v) => setState(() { + _showWorldOrigin = v; + _applySettings(); + }), + ), + ], + ), + ), + ), + ], + ), + ); + } + + void _onARViewCreated( + ARSessionManager sessionManager, + ARObjectManager objectManager, + ARAnchorManager anchorManager, + ARLocationManager locationManager, + ) { + arSessionManager = sessionManager; + arObjectManager = objectManager; + objectManager.onInitialize(); + _applySettings(); + } + + void _applySettings() { + arSessionManager?.onInitialize( + showFeaturePoints: _showFeaturePoints, + showPlanes: _showPlanes, + customPlaneTexturePath: kPlaneTextureAsset, + showWorldOrigin: _showWorldOrigin, + ); + } +} diff --git a/example/lib/demos/external_model_demo.dart b/example/lib/demos/external_model_demo.dart new file mode 100644 index 00000000..a93688e2 --- /dev/null +++ b/example/lib/demos/external_model_demo.dart @@ -0,0 +1,295 @@ +import 'package:flutter/material.dart'; +import 'package:vector_math/vector_math_64.dart' hide Colors; + +import 'package:ar_flutter_plugin_2/ar_flutter_plugin.dart'; +import 'package:ar_flutter_plugin_2/datatypes/config_planedetection.dart'; +import 'package:ar_flutter_plugin_2/datatypes/hittest_result_types.dart'; +import 'package:ar_flutter_plugin_2/datatypes/node_types.dart'; +import 'package:ar_flutter_plugin_2/managers/ar_anchor_manager.dart'; +import 'package:ar_flutter_plugin_2/managers/ar_location_manager.dart'; +import 'package:ar_flutter_plugin_2/managers/ar_object_manager.dart'; +import 'package:ar_flutter_plugin_2/managers/ar_session_manager.dart'; +import 'package:ar_flutter_plugin_2/models/ar_anchor.dart'; +import 'package:ar_flutter_plugin_2/models/ar_hittest_result.dart'; +import 'package:ar_flutter_plugin_2/models/ar_node.dart'; + +import '../firebase/firebase_manager.dart'; +import '../main.dart'; + +/// Like the cloud-anchor demo, but the model to place is chosen from a list +/// managed in a Firestore `models` collection (fields: `name`, `image`, `uri`). +/// +/// Requires a configured Firebase project (see `cloudAnchorSetup.md`). +class ExternalModelDemo extends StatefulWidget { + const ExternalModelDemo({super.key}); + + @override + State createState() => _ExternalModelDemoState(); +} + +class _ExternalModelDemoState extends State { + final FirebaseManager _firebase = FirebaseManager(); + bool _initialized = false; + bool _error = false; + + ARSessionManager? arSessionManager; + ARObjectManager? arObjectManager; + ARAnchorManager? arAnchorManager; + + final List nodes = []; + final List anchors = []; + bool _modelChoiceActive = false; + + AvailableModel _selectedModel = + const AvailableModel('Duck', kDuckGlbUrl, ''); + + @override + void initState() { + super.initState(); + _initFirebase(); + } + + Future _initFirebase() async { + final ok = await _firebase.initialize(); + if (!mounted) return; + setState(() { + _initialized = ok; + _error = !ok; + }); + } + + @override + void dispose() { + arSessionManager?.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + if (_error) { + return Scaffold( + appBar: AppBar(title: const Text('External model management')), + body: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Padding( + padding: EdgeInsets.all(24), + child: Text( + 'Firebase initialization failed.\n' + 'Add a Firebase configuration to run this demo.', + textAlign: TextAlign.center, + ), + ), + ElevatedButton( + onPressed: () { + setState(() => _error = false); + _initFirebase(); + }, + child: const Text('Retry'), + ), + ], + ), + ), + ); + } + if (!_initialized) { + return Scaffold( + appBar: AppBar(title: const Text('External model management')), + body: const Center(child: CircularProgressIndicator()), + ); + } + + return Scaffold( + appBar: AppBar( + title: const Text('External model management'), + actions: [ + IconButton( + icon: const Icon(Icons.pets), + onPressed: () => + setState(() => _modelChoiceActive = !_modelChoiceActive), + ), + ], + ), + body: Stack( + children: [ + ARView( + onARViewCreated: _onARViewCreated, + planeDetectionConfig: PlaneDetectionConfig.horizontalAndVertical, + ), + Align( + alignment: Alignment.bottomCenter, + child: Padding( + padding: const EdgeInsets.all(12), + child: ElevatedButton.icon( + onPressed: _removeEverything, + icon: const Icon(Icons.delete_outline), + label: const Text('Remove everything'), + ), + ), + ), + if (_modelChoiceActive) + Align( + alignment: Alignment.centerLeft, + child: _ModelSelectionPanel( + firebase: _firebase, + onSelected: (model) => setState(() { + _selectedModel = model; + _modelChoiceActive = false; + }), + ), + ), + ], + ), + ); + } + + void _onARViewCreated( + ARSessionManager sessionManager, + ARObjectManager objectManager, + ARAnchorManager anchorManager, + ARLocationManager locationManager, + ) { + arSessionManager = sessionManager; + arObjectManager = objectManager; + arAnchorManager = anchorManager; + + sessionManager.onInitialize( + showFeaturePoints: false, + showPlanes: true, + customPlaneTexturePath: kPlaneTextureAsset, + showWorldOrigin: true, + ); + objectManager.onInitialize(); + anchorManager.initGoogleCloudAnchorMode(); + + sessionManager.onPlaneOrPointTap = _onPlaneOrPointTapped; + objectManager.onNodeTap = _onNodeTapped; + } + + Future _onPlaneOrPointTapped(List hits) async { + final planeHits = + hits.where((h) => h.type == ARHitTestResultType.plane).toList(); + if (planeHits.isEmpty) return; + + final anchor = ARPlaneAnchor( + transformation: planeHits.first.worldTransform, ttl: 2); + if (await arAnchorManager!.addAnchor(anchor) != true) { + _snack('Adding anchor failed'); + return; + } + anchors.add(anchor); + + final node = ARNode( + type: NodeType.webGLB, + uri: _selectedModel.uri, + scale: Vector3(0.2, 0.2, 0.2), + position: Vector3(0, 0, 0), + rotation: Vector4(1, 0, 0, 0), + data: {'onTapText': 'I am a ${_selectedModel.name}'}, + ); + if (await arObjectManager!.addNode(node, planeAnchor: anchor) == true) { + nodes.add(node); + } else { + _snack('Adding node failed'); + } + } + + void _onNodeTapped(List nodeNames) { + if (nodeNames.isEmpty) return; + for (final n in nodes) { + if (n.name == nodeNames.first) { + _snack(n.data?['onTapText']?.toString() ?? 'Tapped a node'); + return; + } + } + } + + Future _removeEverything() async { + for (final anchor in anchors) { + arAnchorManager!.removeAnchor(anchor); + } + anchors.clear(); + nodes.clear(); + } + + void _snack(String message) { + if (!mounted) return; + ScaffoldMessenger.of(context) + .showSnackBar(SnackBar(content: Text(message))); + } +} + +class _ModelSelectionPanel extends StatefulWidget { + const _ModelSelectionPanel({required this.firebase, required this.onSelected}); + + final FirebaseManager firebase; + final ValueChanged onSelected; + + @override + State<_ModelSelectionPanel> createState() => _ModelSelectionPanelState(); +} + +class _ModelSelectionPanelState extends State<_ModelSelectionPanel> { + final List _models = []; + + @override + void initState() { + super.initState(); + widget.firebase.downloadAvailableModels((snapshot) { + if (!mounted) return; + setState(() { + for (final doc in snapshot.docs) { + final data = doc.data(); + _models.add(AvailableModel( + (data['name'] ?? 'Model').toString(), + (data['uri'] ?? '').toString(), + _imageUrl(data['image']), + )); + } + }); + }); + } + + static String _imageUrl(dynamic image) { + if (image is String) return image; + if (image is List && image.isNotEmpty) { + final first = image.first; + if (first is Map && first['downloadURL'] != null) { + return first['downloadURL'].toString(); + } + return first.toString(); + } + return ''; + } + + @override + Widget build(BuildContext context) { + return Container( + width: MediaQuery.of(context).size.width * 0.5, + color: Colors.white.withValues(alpha: 0.85), + child: _models.isEmpty + ? const Center(child: Text('No models in Firestore')) + : ListView.builder( + itemCount: _models.length, + itemBuilder: (context, index) { + final model = _models[index]; + return Card( + child: ListTile( + leading: model.image.isEmpty + ? const Icon(Icons.view_in_ar) + : Image.network( + model.image, + width: 40, + errorBuilder: (_, _, _) => + const Icon(Icons.broken_image), + ), + title: Text(model.name), + onTap: () => widget.onSelected(model), + ), + ); + }, + ), + ); + } +} diff --git a/example/lib/demos/local_and_web_objects_demo.dart b/example/lib/demos/local_and_web_objects_demo.dart new file mode 100644 index 00000000..2748c1fd --- /dev/null +++ b/example/lib/demos/local_and_web_objects_demo.dart @@ -0,0 +1,212 @@ +import 'dart:io'; +import 'dart:math'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:vector_math/vector_math_64.dart'; + +import 'package:ar_flutter_plugin_2/ar_flutter_plugin.dart'; +import 'package:ar_flutter_plugin_2/datatypes/config_planedetection.dart'; +import 'package:ar_flutter_plugin_2/datatypes/node_types.dart'; +import 'package:ar_flutter_plugin_2/managers/ar_anchor_manager.dart'; +import 'package:ar_flutter_plugin_2/managers/ar_location_manager.dart'; +import 'package:ar_flutter_plugin_2/managers/ar_object_manager.dart'; +import 'package:ar_flutter_plugin_2/managers/ar_session_manager.dart'; +import 'package:ar_flutter_plugin_2/models/ar_node.dart'; + +import '../main.dart'; + +const String _localModelAsset = 'assets/models/Duck.gltf'; +const String _fileSystemModelName = 'Duck.glb'; + +/// Adds objects at the world origin from three sources — a bundled asset +/// (`localGLTF2`), the web (`webGLB`) and the app's documents directory +/// (`fileSystemAppFolderGLB`) — and shuffles their transforms. +class LocalAndWebObjectsDemo extends StatefulWidget { + const LocalAndWebObjectsDemo({super.key}); + + @override + State createState() => _LocalAndWebObjectsDemoState(); +} + +class _LocalAndWebObjectsDemoState extends State { + ARSessionManager? arSessionManager; + ARObjectManager? arObjectManager; + + ARNode? localNode; + ARNode? webNode; + ARNode? fileSystemNode; + bool _fileReady = false; + + @override + void dispose() { + arSessionManager?.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Local & web objects')), + body: Stack( + children: [ + ARView( + onARViewCreated: _onARViewCreated, + planeDetectionConfig: PlaneDetectionConfig.horizontalAndVertical, + ), + Align( + alignment: Alignment.bottomCenter, + child: Padding( + padding: const EdgeInsets.all(12), + child: Wrap( + spacing: 8, + runSpacing: 8, + alignment: WrapAlignment.center, + children: [ + ElevatedButton( + onPressed: _toggleLocal, + child: const Text('Local asset'), + ), + ElevatedButton( + onPressed: _toggleWeb, + child: const Text('Web'), + ), + ElevatedButton( + onPressed: _fileReady ? _toggleFileSystem : null, + child: const Text('File system'), + ), + ElevatedButton( + onPressed: localNode == null ? null : () => _shuffle(localNode!), + child: const Text('Shuffle local'), + ), + ElevatedButton( + onPressed: webNode == null ? null : () => _shuffle(webNode!), + child: const Text('Shuffle web'), + ), + ], + ), + ), + ), + ], + ), + ); + } + + void _onARViewCreated( + ARSessionManager sessionManager, + ARObjectManager objectManager, + ARAnchorManager anchorManager, + ARLocationManager locationManager, + ) { + arSessionManager = sessionManager; + arObjectManager = objectManager; + + sessionManager.onInitialize( + showFeaturePoints: false, + showPlanes: true, + customPlaneTexturePath: kPlaneTextureAsset, + showWorldOrigin: true, + handleTaps: false, + // Enabled so updateNode() (used by the shuffle buttons) is applied on + // Android, where transform sync is gated behind gesture handling. + handlePans: true, + handleRotation: true, + ); + objectManager.onInitialize(); + + // Download a GLB into the documents directory for the file-system demo. + _downloadFileSystemModel(); + } + + Future _downloadFileSystemModel() async { + try { + final client = HttpClient(); + final request = await client.getUrl(Uri.parse(kDuckGlbUrl)); + final response = await request.close(); + final bytes = await consolidateHttpClientResponseBytes(response); + final dir = (await getApplicationDocumentsDirectory()).path; + await File('$dir/$_fileSystemModelName').writeAsBytes(bytes); + client.close(); + if (mounted) setState(() => _fileReady = true); + } catch (e) { + debugPrint('File-system model download failed: $e'); + } + } + + Future _toggleLocal() async { + if (localNode != null) { + arObjectManager!.removeNode(localNode!); + setState(() => localNode = null); + return; + } + final node = ARNode( + type: NodeType.localGLTF2, + uri: _localModelAsset, + scale: Vector3(0.2, 0.2, 0.2), + ); + if (await arObjectManager!.addNode(node) == true) { + setState(() => localNode = node); + } else { + _snack('Adding local object failed'); + } + } + + Future _toggleWeb() async { + if (webNode != null) { + arObjectManager!.removeNode(webNode!); + setState(() => webNode = null); + return; + } + final node = ARNode( + type: NodeType.webGLB, + uri: kDuckGlbUrl, + scale: Vector3(0.2, 0.2, 0.2), + ); + if (await arObjectManager!.addNode(node) == true) { + setState(() => webNode = node); + } else { + _snack('Adding web object failed'); + } + } + + Future _toggleFileSystem() async { + if (fileSystemNode != null) { + arObjectManager!.removeNode(fileSystemNode!); + setState(() => fileSystemNode = null); + return; + } + final node = ARNode( + type: NodeType.fileSystemAppFolderGLB, + uri: _fileSystemModelName, + scale: Vector3(0.2, 0.2, 0.2), + ); + if (await arObjectManager!.addNode(node) == true) { + setState(() => fileSystemNode = node); + } else { + _snack('Adding file-system object failed'); + } + } + + void _shuffle(ARNode node) { + final random = Random(); + final scale = random.nextDouble() / 3 + 0.1; + final translation = Vector3.zero(); + translation[random.nextInt(3)] = random.nextDouble() / 3; + final axis = Vector3.zero(); + axis[random.nextInt(3)] = 1.0; + + final transform = Matrix4.identity() + ..setTranslation(translation) + ..rotate(axis, random.nextDouble()) + ..scaleByDouble(scale, scale, scale, 1); + node.transform = transform; + arObjectManager!.updateNode(node); + } + + void _snack(String message) { + if (!mounted) return; + ScaffoldMessenger.of(context) + .showSnackBar(SnackBar(content: Text(message))); + } +} diff --git a/example/lib/demos/object_gestures_demo.dart b/example/lib/demos/object_gestures_demo.dart new file mode 100644 index 00000000..f23049da --- /dev/null +++ b/example/lib/demos/object_gestures_demo.dart @@ -0,0 +1,158 @@ +import 'package:flutter/material.dart'; +import 'package:vector_math/vector_math_64.dart'; + +import 'package:ar_flutter_plugin_2/ar_flutter_plugin.dart'; +import 'package:ar_flutter_plugin_2/datatypes/config_planedetection.dart'; +import 'package:ar_flutter_plugin_2/datatypes/hittest_result_types.dart'; +import 'package:ar_flutter_plugin_2/datatypes/node_types.dart'; +import 'package:ar_flutter_plugin_2/managers/ar_anchor_manager.dart'; +import 'package:ar_flutter_plugin_2/managers/ar_location_manager.dart'; +import 'package:ar_flutter_plugin_2/managers/ar_object_manager.dart'; +import 'package:ar_flutter_plugin_2/managers/ar_session_manager.dart'; +import 'package:ar_flutter_plugin_2/models/ar_anchor.dart'; +import 'package:ar_flutter_plugin_2/models/ar_hittest_result.dart'; +import 'package:ar_flutter_plugin_2/models/ar_node.dart'; + +import '../main.dart'; + +/// Same as the objects-on-planes demo, but placed nodes can be panned and +/// rotated with gestures (enabled via `handlePans`/`handleRotation`). +class ObjectGesturesDemo extends StatefulWidget { + const ObjectGesturesDemo({super.key}); + + @override + State createState() => _ObjectGesturesDemoState(); +} + +class _ObjectGesturesDemoState extends State { + ARSessionManager? arSessionManager; + ARObjectManager? arObjectManager; + ARAnchorManager? arAnchorManager; + + final List nodes = []; + final List anchors = []; + + @override + void dispose() { + arSessionManager?.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Object gestures')), + body: Stack( + children: [ + ARView( + onARViewCreated: _onARViewCreated, + planeDetectionConfig: PlaneDetectionConfig.horizontalAndVertical, + ), + Align( + alignment: Alignment.bottomCenter, + child: Padding( + padding: const EdgeInsets.all(16), + child: ElevatedButton.icon( + onPressed: _removeEverything, + icon: const Icon(Icons.delete_outline), + label: const Text('Remove everything'), + ), + ), + ), + ], + ), + ); + } + + void _onARViewCreated( + ARSessionManager sessionManager, + ARObjectManager objectManager, + ARAnchorManager anchorManager, + ARLocationManager locationManager, + ) { + arSessionManager = sessionManager; + arObjectManager = objectManager; + arAnchorManager = anchorManager; + + sessionManager.onInitialize( + showFeaturePoints: false, + showPlanes: true, + customPlaneTexturePath: kPlaneTextureAsset, + showWorldOrigin: true, + handlePans: true, + handleRotation: true, + ); + objectManager.onInitialize(); + + sessionManager.onPlaneOrPointTap = _onPlaneOrPointTapped; + objectManager.onPanStart = (n) => debugPrint('Pan start: $n'); + objectManager.onPanChange = (n) => debugPrint('Pan change: $n'); + objectManager.onPanEnd = _onPanEnded; + objectManager.onRotationStart = (n) => debugPrint('Rotation start: $n'); + objectManager.onRotationChange = (n) => debugPrint('Rotation change: $n'); + objectManager.onRotationEnd = _onRotationEnded; + } + + Future _onPlaneOrPointTapped(List hits) async { + final planeHits = + hits.where((h) => h.type == ARHitTestResultType.plane).toList(); + if (planeHits.isEmpty) return; + + final anchor = ARPlaneAnchor(transformation: planeHits.first.worldTransform); + final didAddAnchor = await arAnchorManager!.addAnchor(anchor); + if (didAddAnchor != true) { + _snack('Adding anchor failed'); + return; + } + anchors.add(anchor); + + final node = ARNode( + type: NodeType.webGLB, + uri: kDuckGlbUrl, + scale: Vector3(0.2, 0.2, 0.2), + position: Vector3(0, 0, 0), + rotation: Vector4(1, 0, 0, 0), + ); + final didAddNode = await arObjectManager!.addNode(node, planeAnchor: anchor); + if (didAddNode == true) { + nodes.add(node); + } else { + _snack('Adding node failed'); + } + } + + // Keep the Flutter-side node transform in sync with the gesture result so the + // model's [ARNode.transform] stays authoritative (e.g. before serializing). + void _onPanEnded(String nodeName, Matrix4 newTransform) { + debugPrint('Pan end: $nodeName'); + _syncTransform(nodeName, newTransform); + } + + void _onRotationEnded(String nodeName, Matrix4 newTransform) { + debugPrint('Rotation end: $nodeName'); + _syncTransform(nodeName, newTransform); + } + + void _syncTransform(String nodeName, Matrix4 newTransform) { + for (final node in nodes) { + if (node.name == nodeName) { + node.transform = newTransform; + break; + } + } + } + + Future _removeEverything() async { + for (final anchor in anchors) { + arAnchorManager!.removeAnchor(anchor); + } + anchors.clear(); + nodes.clear(); + } + + void _snack(String message) { + if (!mounted) return; + ScaffoldMessenger.of(context) + .showSnackBar(SnackBar(content: Text(message))); + } +} diff --git a/example/lib/demos/objects_on_planes_demo.dart b/example/lib/demos/objects_on_planes_demo.dart new file mode 100644 index 00000000..bdbc55ef --- /dev/null +++ b/example/lib/demos/objects_on_planes_demo.dart @@ -0,0 +1,132 @@ +import 'package:flutter/material.dart'; +import 'package:vector_math/vector_math_64.dart'; + +import 'package:ar_flutter_plugin_2/ar_flutter_plugin.dart'; +import 'package:ar_flutter_plugin_2/datatypes/config_planedetection.dart'; +import 'package:ar_flutter_plugin_2/datatypes/hittest_result_types.dart'; +import 'package:ar_flutter_plugin_2/datatypes/node_types.dart'; +import 'package:ar_flutter_plugin_2/managers/ar_anchor_manager.dart'; +import 'package:ar_flutter_plugin_2/managers/ar_location_manager.dart'; +import 'package:ar_flutter_plugin_2/managers/ar_object_manager.dart'; +import 'package:ar_flutter_plugin_2/managers/ar_session_manager.dart'; +import 'package:ar_flutter_plugin_2/models/ar_anchor.dart'; +import 'package:ar_flutter_plugin_2/models/ar_hittest_result.dart'; +import 'package:ar_flutter_plugin_2/models/ar_node.dart'; + +import '../main.dart'; + +/// Tapping a detected plane creates an [ARPlaneAnchor] with a 3D model attached. +class ObjectsOnPlanesDemo extends StatefulWidget { + const ObjectsOnPlanesDemo({super.key}); + + @override + State createState() => _ObjectsOnPlanesDemoState(); +} + +class _ObjectsOnPlanesDemoState extends State { + ARSessionManager? arSessionManager; + ARObjectManager? arObjectManager; + ARAnchorManager? arAnchorManager; + + final List nodes = []; + final List anchors = []; + + @override + void dispose() { + arSessionManager?.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Objects on planes')), + body: Stack( + children: [ + ARView( + onARViewCreated: _onARViewCreated, + planeDetectionConfig: PlaneDetectionConfig.horizontalAndVertical, + ), + Align( + alignment: Alignment.bottomCenter, + child: Padding( + padding: const EdgeInsets.all(16), + child: ElevatedButton.icon( + onPressed: _removeEverything, + icon: const Icon(Icons.delete_outline), + label: const Text('Remove everything'), + ), + ), + ), + ], + ), + ); + } + + void _onARViewCreated( + ARSessionManager sessionManager, + ARObjectManager objectManager, + ARAnchorManager anchorManager, + ARLocationManager locationManager, + ) { + arSessionManager = sessionManager; + arObjectManager = objectManager; + arAnchorManager = anchorManager; + + sessionManager.onInitialize( + showFeaturePoints: false, + showPlanes: true, + customPlaneTexturePath: kPlaneTextureAsset, + showWorldOrigin: true, + ); + objectManager.onInitialize(); + + sessionManager.onPlaneOrPointTap = _onPlaneOrPointTapped; + objectManager.onNodeTap = _onNodeTapped; + } + + Future _onPlaneOrPointTapped(List hits) async { + final planeHits = + hits.where((h) => h.type == ARHitTestResultType.plane).toList(); + if (planeHits.isEmpty) return; + + final anchor = ARPlaneAnchor(transformation: planeHits.first.worldTransform); + final didAddAnchor = await arAnchorManager!.addAnchor(anchor); + if (didAddAnchor != true) { + _snack('Adding anchor failed'); + return; + } + anchors.add(anchor); + + final node = ARNode( + type: NodeType.webGLB, + uri: kDuckGlbUrl, + scale: Vector3(0.2, 0.2, 0.2), + position: Vector3(0, 0, 0), + rotation: Vector4(1, 0, 0, 0), + ); + final didAddNode = await arObjectManager!.addNode(node, planeAnchor: anchor); + if (didAddNode == true) { + nodes.add(node); + } else { + _snack('Adding node failed'); + } + } + + void _onNodeTapped(List tappedNodes) => + _snack('Tapped ${tappedNodes.length} node(s)'); + + Future _removeEverything() async { + for (final anchor in anchors) { + arAnchorManager!.removeAnchor(anchor); + } + anchors.clear(); + nodes.clear(); + } + + void _snack(String message) { + if (!mounted) return; + ScaffoldMessenger.of(context) + .showSnackBar(SnackBar(content: Text(message))); + } +} diff --git a/example/lib/demos/screenshot_demo.dart b/example/lib/demos/screenshot_demo.dart new file mode 100644 index 00000000..ad49be23 --- /dev/null +++ b/example/lib/demos/screenshot_demo.dart @@ -0,0 +1,155 @@ +import 'package:flutter/material.dart'; +import 'package:vector_math/vector_math_64.dart'; + +import 'package:ar_flutter_plugin_2/ar_flutter_plugin.dart'; +import 'package:ar_flutter_plugin_2/datatypes/config_planedetection.dart'; +import 'package:ar_flutter_plugin_2/datatypes/hittest_result_types.dart'; +import 'package:ar_flutter_plugin_2/datatypes/node_types.dart'; +import 'package:ar_flutter_plugin_2/managers/ar_anchor_manager.dart'; +import 'package:ar_flutter_plugin_2/managers/ar_location_manager.dart'; +import 'package:ar_flutter_plugin_2/managers/ar_object_manager.dart'; +import 'package:ar_flutter_plugin_2/managers/ar_session_manager.dart'; +import 'package:ar_flutter_plugin_2/models/ar_anchor.dart'; +import 'package:ar_flutter_plugin_2/models/ar_hittest_result.dart'; +import 'package:ar_flutter_plugin_2/models/ar_node.dart'; + +import '../main.dart'; + +/// Places models on planes and captures the AR scene with +/// [ARSessionManager.snapshot]. +class ScreenshotDemo extends StatefulWidget { + const ScreenshotDemo({super.key}); + + @override + State createState() => _ScreenshotDemoState(); +} + +class _ScreenshotDemoState extends State { + ARSessionManager? arSessionManager; + ARObjectManager? arObjectManager; + ARAnchorManager? arAnchorManager; + + final List nodes = []; + final List anchors = []; + + @override + void dispose() { + arSessionManager?.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Screenshots')), + body: Stack( + children: [ + ARView( + onARViewCreated: _onARViewCreated, + planeDetectionConfig: PlaneDetectionConfig.horizontalAndVertical, + ), + Align( + alignment: Alignment.bottomCenter, + child: Padding( + padding: const EdgeInsets.all(16), + child: Wrap( + spacing: 8, + alignment: WrapAlignment.center, + children: [ + ElevatedButton.icon( + onPressed: _removeEverything, + icon: const Icon(Icons.delete_outline), + label: const Text('Remove everything'), + ), + ElevatedButton.icon( + onPressed: _takeScreenshot, + icon: const Icon(Icons.camera_alt), + label: const Text('Take screenshot'), + ), + ], + ), + ), + ), + ], + ), + ); + } + + void _onARViewCreated( + ARSessionManager sessionManager, + ARObjectManager objectManager, + ARAnchorManager anchorManager, + ARLocationManager locationManager, + ) { + arSessionManager = sessionManager; + arObjectManager = objectManager; + arAnchorManager = anchorManager; + + sessionManager.onInitialize( + showFeaturePoints: false, + showPlanes: true, + customPlaneTexturePath: kPlaneTextureAsset, + showWorldOrigin: true, + ); + objectManager.onInitialize(); + + sessionManager.onPlaneOrPointTap = _onPlaneOrPointTapped; + } + + Future _takeScreenshot() async { + final image = await arSessionManager!.snapshot(); + if (!mounted) return; + await showDialog( + context: context, + builder: (_) => Dialog( + child: Container( + decoration: BoxDecoration( + image: DecorationImage(image: image, fit: BoxFit.cover), + ), + ), + ), + ); + } + + Future _onPlaneOrPointTapped(List hits) async { + final planeHits = + hits.where((h) => h.type == ARHitTestResultType.plane).toList(); + if (planeHits.isEmpty) return; + + final anchor = ARPlaneAnchor(transformation: planeHits.first.worldTransform); + final didAddAnchor = await arAnchorManager!.addAnchor(anchor); + if (didAddAnchor != true) { + _snack('Adding anchor failed'); + return; + } + anchors.add(anchor); + + final node = ARNode( + type: NodeType.webGLB, + uri: kDuckGlbUrl, + scale: Vector3(0.2, 0.2, 0.2), + position: Vector3(0, 0, 0), + rotation: Vector4(1, 0, 0, 0), + ); + final didAddNode = await arObjectManager!.addNode(node, planeAnchor: anchor); + if (didAddNode == true) { + nodes.add(node); + } else { + _snack('Adding node failed'); + } + } + + Future _removeEverything() async { + for (final anchor in anchors) { + arAnchorManager!.removeAnchor(anchor); + } + anchors.clear(); + nodes.clear(); + } + + void _snack(String message) { + if (!mounted) return; + ScaffoldMessenger.of(context) + .showSnackBar(SnackBar(content: Text(message))); + } +} diff --git a/example/lib/demos/web_object_demo.dart b/example/lib/demos/web_object_demo.dart new file mode 100644 index 00000000..86b72973 --- /dev/null +++ b/example/lib/demos/web_object_demo.dart @@ -0,0 +1,152 @@ +import 'dart:math' as math; + +import 'package:flutter/material.dart'; +import 'package:vector_math/vector_math_64.dart'; + +import 'package:ar_flutter_plugin_2/ar_flutter_plugin.dart'; +import 'package:ar_flutter_plugin_2/datatypes/config_planedetection.dart'; +import 'package:ar_flutter_plugin_2/datatypes/node_types.dart'; +import 'package:ar_flutter_plugin_2/managers/ar_anchor_manager.dart'; +import 'package:ar_flutter_plugin_2/managers/ar_location_manager.dart'; +import 'package:ar_flutter_plugin_2/managers/ar_object_manager.dart'; +import 'package:ar_flutter_plugin_2/managers/ar_session_manager.dart'; +import 'package:ar_flutter_plugin_2/models/ar_node.dart'; + +import '../main.dart'; + +/// Loads a GLB model from the web at the world origin, then demonstrates +/// [ARObjectManager.updateNode] by rotating and scaling it programmatically. +/// +/// Note: on Android the transform sync only takes effect when pan or rotation +/// handling is enabled, so this demo turns both on. +class WebObjectDemo extends StatefulWidget { + const WebObjectDemo({super.key}); + + @override + State createState() => _WebObjectDemoState(); +} + +class _WebObjectDemoState extends State { + ARSessionManager? arSessionManager; + ARObjectManager? arObjectManager; + + ARNode? _node; + double _scale = 0.2; + + @override + void dispose() { + arSessionManager?.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final hasNode = _node != null; + return Scaffold( + appBar: AppBar(title: const Text('Web object + updateNode')), + body: Stack( + children: [ + ARView( + onARViewCreated: _onARViewCreated, + planeDetectionConfig: PlaneDetectionConfig.horizontalAndVertical, + ), + Align( + alignment: Alignment.bottomCenter, + child: Padding( + padding: const EdgeInsets.all(16), + child: Wrap( + spacing: 8, + runSpacing: 8, + alignment: WrapAlignment.center, + children: [ + ElevatedButton.icon( + onPressed: hasNode ? null : _addNode, + icon: const Icon(Icons.add), + label: const Text('Add model'), + ), + ElevatedButton.icon( + onPressed: hasNode ? _rotate : null, + icon: const Icon(Icons.rotate_right), + label: const Text('Rotate 45°'), + ), + ElevatedButton.icon( + onPressed: hasNode ? _scaleUp : null, + icon: const Icon(Icons.zoom_in), + label: const Text('Scale up'), + ), + ElevatedButton.icon( + onPressed: hasNode ? _remove : null, + icon: const Icon(Icons.delete_outline), + label: const Text('Remove'), + ), + ], + ), + ), + ), + ], + ), + ); + } + + void _onARViewCreated( + ARSessionManager sessionManager, + ARObjectManager objectManager, + ARAnchorManager anchorManager, + ARLocationManager locationManager, + ) { + arSessionManager = sessionManager; + arObjectManager = objectManager; + + sessionManager.onInitialize( + showFeaturePoints: false, + showPlanes: true, + customPlaneTexturePath: kPlaneTextureAsset, + showWorldOrigin: true, + handlePans: true, + handleRotation: true, + ); + objectManager.onInitialize(); + } + + Future _addNode() async { + final node = ARNode( + type: NodeType.webGLB, + uri: kDuckGlbUrl, + scale: Vector3.all(_scale), + position: Vector3(0, 0, -1), // 1 metre in front of the world origin + ); + final didAdd = await arObjectManager!.addNode(node); + if (didAdd == true) { + setState(() => _node = node); + } else { + _snack('Adding node failed'); + } + } + + // Both handlers mutate the node's transform and push it to the native engine + // with updateNode — the method added for upstream issue #6. + void _rotate() { + final node = _node!; + final angles = node.eulerAngles; + node.eulerAngles = Vector3(angles.x, angles.y + math.pi / 4, angles.z); + arObjectManager!.updateNode(node); + } + + void _scaleUp() { + final node = _node!; + _scale = (_scale + 0.1).clamp(0.1, 1.0); + node.scale = Vector3.all(_scale); + arObjectManager!.updateNode(node); + } + + void _remove() { + arObjectManager!.removeNode(_node!); + setState(() => _node = null); + } + + void _snack(String message) { + if (!mounted) return; + ScaffoldMessenger.of(context) + .showSnackBar(SnackBar(content: Text(message))); + } +} diff --git a/example/lib/firebase/firebase_manager.dart b/example/lib/firebase/firebase_manager.dart new file mode 100644 index 00000000..f92376c1 --- /dev/null +++ b/example/lib/firebase/firebase_manager.dart @@ -0,0 +1,110 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:firebase_core/firebase_core.dart'; +import 'package:flutter/foundation.dart'; + +import 'package:ar_flutter_plugin_2/models/ar_anchor.dart'; +import 'package:ar_flutter_plugin_2/models/ar_node.dart'; + +/// A model entry the "external model management" demo lets the user pick from, +/// backed by a Firestore `models` collection. +class AvailableModel { + const AvailableModel(this.name, this.uri, this.image); + final String name; + final String uri; + final String image; +} + +typedef QueryListener = void Function( + QuerySnapshot> snapshot); + +/// Thin wrapper around Firestore used by the cloud-anchor demos. +/// +/// This is a simplified adaptation of the original `examples/` snippets: it +/// drops the `geoflutterfire2` geo-radius query (that package is unmaintained +/// and conflicts with current `cloud_firestore`) and downloads the most recent +/// anchor instead. Storing/serving anchors by geographic location is left as an +/// exercise — see the plugin docs and `cloudAnchorSetup.md`. +class FirebaseManager { + CollectionReference>? _anchors; + CollectionReference>? _objects; + CollectionReference>? _models; + + /// Returns true once Firebase is initialized. Returns false (rather than + /// throwing) when no Firebase configuration is present, so the demo can show + /// a friendly message instead of crashing. + Future initialize() async { + try { + await Firebase.initializeApp(); + final firestore = FirebaseFirestore.instance; + _anchors = firestore.collection('anchors'); + _objects = firestore.collection('objects'); + _models = firestore.collection('models'); + return true; + } catch (e) { + debugPrint('Firebase init failed: $e'); + return false; + } + } + + Future uploadAnchor(ARAnchor anchor) async { + final anchors = _anchors; + if (anchors == null) return; + final serialized = anchor.toJson(); + final ttl = (serialized['ttl'] as int?) ?? 1; + serialized['expirationTime'] = + DateTime.now().millisecondsSinceEpoch / 1000 + ttl * 24 * 60 * 60; + try { + await anchors.add(serialized); + } catch (e) { + debugPrint('Failed to add anchor: $e'); + } + } + + Future uploadObject(ARNode node) async { + final objects = _objects; + if (objects == null) return; + try { + await objects.add(node.toMap()); + } catch (e) { + debugPrint('Failed to add object: $e'); + } + } + + /// Downloads the most recently uploaded anchor document. + Future downloadLatestAnchor(QueryListener listener) async { + final anchors = _anchors; + if (anchors == null) return; + try { + final snapshot = + await anchors.orderBy('expirationTime').limitToLast(1).get(); + listener(snapshot); + } catch (e) { + debugPrint('Failed to download anchor: $e'); + } + } + + /// Downloads the object documents whose `name` is one of the anchor's children. + Future getObjectsFromAnchor( + ARPlaneAnchor anchor, QueryListener listener) async { + final objects = _objects; + if (objects == null || anchor.childNodes.isEmpty) return; + try { + final snapshot = + await objects.where('name', whereIn: anchor.childNodes).get(); + listener(snapshot); + } catch (e) { + debugPrint('Failed to download objects: $e'); + } + } + + /// Downloads every entry of the `models` collection. + Future downloadAvailableModels(QueryListener listener) async { + final models = _models; + if (models == null) return; + try { + listener(await models.get()); + } catch (e) { + debugPrint('Failed to download models: $e'); + } + } +} diff --git a/example/lib/main.dart b/example/lib/main.dart new file mode 100644 index 00000000..f4291a27 --- /dev/null +++ b/example/lib/main.dart @@ -0,0 +1,104 @@ +import 'package:flutter/material.dart'; + +import 'demos/cloud_anchor_demo.dart'; +import 'demos/debug_options_demo.dart'; +import 'demos/external_model_demo.dart'; +import 'demos/local_and_web_objects_demo.dart'; +import 'demos/object_gestures_demo.dart'; +import 'demos/objects_on_planes_demo.dart'; +import 'demos/screenshot_demo.dart'; +import 'demos/web_object_demo.dart'; + +/// A self-contained GLB model hosted by Khronos, used by the demos so no +/// binary asset needs to be bundled with this example. +const String kDuckGlbUrl = + 'https://github.com/KhronosGroup/glTF-Sample-Models/raw/refs/heads/main/2.0/Duck/glTF-Binary/Duck.glb'; + +/// Flutter asset key for the plane texture bundled with this example. +const String kPlaneTextureAsset = 'assets/images/triangle.png'; + +void main() => runApp(const ExampleApp()); + +class ExampleApp extends StatelessWidget { + const ExampleApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'AR Flutter Plugin Demo', + theme: ThemeData(colorSchemeSeed: Colors.indigo, useMaterial3: true), + home: const HomePage(), + ); + } +} + +class _Demo { + const _Demo(this.title, this.subtitle, this.builder); + final String title; + final String subtitle; + final WidgetBuilder builder; +} + +class HomePage extends StatelessWidget { + const HomePage({super.key}); + + static final List<_Demo> _demos = [ + _Demo('Objects on planes', 'Tap a detected plane to anchor a 3D model', + (_) => const ObjectsOnPlanesDemo()), + _Demo('Object gestures', 'Pan and rotate placed models with your fingers', + (_) => const ObjectGesturesDemo()), + _Demo('Web object + updateNode', + 'Place a web model, then rotate/scale it programmatically', + (_) => const WebObjectDemo()), + _Demo('Local & web objects', + 'Place bundled-asset, web and file-system models at the origin', + (_) => const LocalAndWebObjectsDemo()), + _Demo('Screenshots', 'Capture the current AR scene as an image', + (_) => const ScreenshotDemo()), + _Demo('Debug options', 'Toggle feature points, planes and world origin', + (_) => const DebugOptionsDemo()), + _Demo('Cloud anchors', 'Host & resolve anchors (needs Firebase setup)', + (_) => const CloudAnchorDemo()), + _Demo('External model management', + 'Choose Firestore-managed models to place (needs Firebase setup)', + (_) => const ExternalModelDemo()), + ]; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('AR Flutter Plugin')), + body: Column( + children: [ + const Padding( + padding: EdgeInsets.all(16), + child: Text( + 'These demos require a physical ARCore (Android) or ARKit (iOS) ' + 'device with camera access. They will not render in an emulator ' + 'or simulator.', + style: TextStyle(fontSize: 13, color: Colors.black54), + ), + ), + const Divider(height: 1), + Expanded( + child: ListView.separated( + itemCount: _demos.length, + separatorBuilder: (_, _) => const Divider(height: 1), + itemBuilder: (context, index) { + final demo = _demos[index]; + return ListTile( + leading: const Icon(Icons.view_in_ar), + title: Text(demo.title), + subtitle: Text(demo.subtitle), + trailing: const Icon(Icons.chevron_right), + onTap: () => Navigator.of(context) + .push(MaterialPageRoute(builder: demo.builder)), + ); + }, + ), + ), + ], + ), + ); + } +} diff --git a/example/pubspec.yaml b/example/pubspec.yaml new file mode 100644 index 00000000..ace8f177 --- /dev/null +++ b/example/pubspec.yaml @@ -0,0 +1,105 @@ +name: ar_flutter_plugin_2_example +description: "A new Flutter project." +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +# In Windows, build-name is used as the major, minor, and patch parts +# of the product and file versions while build-number is used as the build suffix. +version: 1.0.0+1 + +environment: + sdk: ^3.12.2 + +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. +dependencies: + flutter: + sdk: flutter + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.8 + + # The plugin under demonstration, referenced from the parent directory. + ar_flutter_plugin_2: + path: ../ + path_provider: ^2.1.5 + firebase_core: ^3.8.0 + cloud_firestore: ^5.6.0 + + # Used by the demos to build node transforms (Vector3/Vector4/Matrix4). + vector_math: ^2.1.1 + +dev_dependencies: + flutter_test: + sdk: flutter + + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # activated in the `analysis_options.yaml` file located at the root of your + # package. See that file for information about deactivating specific lint + # rules and activating additional ones. + flutter_lints: ^6.0.0 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # Plane texture used to demo ARSessionManager.onInitialize(customPlaneTexturePath:), + # and a self-contained (embedded) glTF model used by the local-object demo. + assets: + - assets/images/triangle.png + - assets/models/Duck.gltf + + # To add assets to your application, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/to/resolution-aware-images + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/to/asset-from-package + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/to/font-from-package diff --git a/example/test/widget_test.dart b/example/test/widget_test.dart new file mode 100644 index 00000000..2e8db255 --- /dev/null +++ b/example/test/widget_test.dart @@ -0,0 +1,25 @@ +// Smoke test for the example app's home menu. The AR demo screens require a +// physical device and are not driven here. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'package:ar_flutter_plugin_2_example/main.dart'; + +void main() { + testWidgets('home menu lists the demos', (WidgetTester tester) async { + await tester.pumpWidget(const ExampleApp()); + + // App bar and the first (on-screen) demo. + expect(find.text('AR Flutter Plugin'), findsOneWidget); + expect(find.text('Objects on planes'), findsOneWidget); + + // The list is lazy, so scroll the last entry into view to confirm it exists. + await tester.scrollUntilVisible( + find.text('External model management'), + 200, + scrollable: find.byType(Scrollable).last, + ); + expect(find.text('External model management'), findsOneWidget); + }); +} diff --git a/examples/README.md b/examples/README.md deleted file mode 100644 index 903e9a52..00000000 --- a/examples/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Examples -In this folder, you will find the custom codes to create in FlutterFlow to use the plugin's features. - - - -
- - - You can find a complete example running on FlutterFlow here :
-https://app.flutterflow.io/project/a-r-flutter-lib-ipqw3k -
- - diff --git a/examples/cloud_anchor.dart b/examples/cloud_anchor.dart deleted file mode 100644 index b4dc3a32..00000000 --- a/examples/cloud_anchor.dart +++ /dev/null @@ -1,557 +0,0 @@ -// Automatic FlutterFlow imports -import '/flutter_flow/flutter_flow_theme.dart'; -import '/flutter_flow/flutter_flow_util.dart'; -import 'index.dart'; // Imports other custom widgets -import 'package:flutter/material.dart'; -// Begin custom widget code -// DO NOT REMOVE OR MODIFY THE CODE ABOVE! - -//AR Flutter plugin -import 'package:ar_flutter_plugin_2/ar_flutter_plugin.dart'; -import 'package:ar_flutter_plugin_2/managers/ar_location_manager.dart'; -import 'package:ar_flutter_plugin_2/managers/ar_session_manager.dart'; -import 'package:ar_flutter_plugin_2/managers/ar_object_manager.dart'; -import 'package:ar_flutter_plugin_2/managers/ar_anchor_manager.dart'; -import 'package:ar_flutter_plugin_2/models/ar_anchor.dart'; -import 'package:ar_flutter_plugin_2/datatypes/config_planedetection.dart'; -import 'package:ar_flutter_plugin_2/datatypes/node_types.dart'; -import 'package:ar_flutter_plugin_2/datatypes/hittest_result_types.dart'; -import 'package:ar_flutter_plugin_2/models/ar_node.dart'; -import 'package:ar_flutter_plugin_2/models/ar_hittest_result.dart'; - -//Other custom imports -import 'dart:convert'; -import 'package:vector_math/vector_math_64.dart'; -import 'package:firebase_core/firebase_core.dart'; -import 'package:cloud_firestore/cloud_firestore.dart'; -import 'package:geolocator/geolocator.dart'; -import 'package:geoflutterfire2/geoflutterfire2.dart'; - -class CloudAnchor extends StatefulWidget { - const CloudAnchor({ - super.key, - this.width, - this.height, - }); - - final double? width; - final double? height; - - @override - State createState() => _CloudAnchorState(); -} - -class _CloudAnchorState extends State { - // Firebase stuff - bool _initialized = false; - bool _error = false; - FirebaseManager firebaseManager = FirebaseManager(); - Map anchorsInDownloadProgress = Map(); - - ARSessionManager? arSessionManager; - ARObjectManager? arObjectManager; - ARAnchorManager? arAnchorManager; - ARLocationManager? arLocationManager; - - List nodes = []; - List anchors = []; - String lastUploadedAnchor = ""; - - bool readyToUpload = false; - bool readyToDownload = true; - - @override - void initState() { - firebaseManager.initializeFlutterFire().then((value) => setState(() { - _initialized = value; - _error = !value; - })); - - super.initState(); - } - - @override - void dispose() { - super.dispose(); - arSessionManager!.dispose(); - } - - @override - Widget build(BuildContext context) { - // Show error message if initialization failed - if (_error) { - return Scaffold( - appBar: AppBar( - title: const Text('Cloud Anchors'), - ), - body: Container( - child: Center( - child: Column( - children: [ - Text("Firebase initialization failed"), - ElevatedButton( - child: Text("Retry"), onPressed: () => {initState()}) - ], - )))); - } - - // Show a loader until FlutterFire is initialized - if (!_initialized) { - return Scaffold( - appBar: AppBar( - title: const Text('Cloud Anchors'), - ), - body: Container( - child: Center( - child: Column(children: [ - CircularProgressIndicator(), - Text("Initializing Firebase") - ])))); - } - - return Scaffold( - appBar: AppBar( - title: const Text('Cloud Anchors'), - ), - body: Container( - child: Stack(children: [ - ARView( - onARViewCreated: onARViewCreated, - planeDetectionConfig: PlaneDetectionConfig.horizontalAndVertical, - ), - Align( - alignment: FractionalOffset.bottomCenter, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - ElevatedButton( - onPressed: onRemoveEverything, - child: Text("Remove Everything")), - ]), - ), - Align( - alignment: FractionalOffset.topCenter, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Visibility( - visible: readyToUpload, - child: ElevatedButton( - onPressed: onUploadButtonPressed, - child: Text("Upload"))), - Visibility( - visible: readyToDownload, - child: ElevatedButton( - onPressed: onDownloadButtonPressed, - child: Text("Download"))), - ]), - ) - ]))); - } - - void onARViewCreated( - ARSessionManager arSessionManager, - ARObjectManager arObjectManager, - ARAnchorManager arAnchorManager, - ARLocationManager arLocationManager) { - this.arSessionManager = arSessionManager; - this.arObjectManager = arObjectManager; - this.arAnchorManager = arAnchorManager; - this.arLocationManager = arLocationManager; - - this.arSessionManager!.onInitialize( - showFeaturePoints: false, - showPlanes: true, - customPlaneTexturePath: "Images/triangle.png", - showWorldOrigin: true, - ); - this.arObjectManager!.onInitialize(); - this.arAnchorManager!.initGoogleCloudAnchorMode(); - - this.arSessionManager!.onPlaneOrPointTap = onPlaneOrPointTapped; - this.arObjectManager!.onNodeTap = onNodeTapped; - this.arAnchorManager!.onAnchorUploaded = onAnchorUploaded; - this.arAnchorManager!.onAnchorDownloaded = onAnchorDownloaded; - - this.arSessionManager!.onError = (String error) { - Map errorTranslations = getErrorTranslations(); - String translatedError = error; - errorTranslations.forEach((key, value) { - if (error.contains(key)) { - translatedError = value; - } - }); - AlertDialog( - title: Text("Error"), - content: Text(translatedError), - ); - }; - - this - .arLocationManager! - .startLocationUpdates() - .then((value) => null) - .onError((error, stackTrace) { - switch (error.toString()) { - case 'Location services disabled': - { - showAlertDialog( - context, - "Action Required", - "To use cloud anchor functionality, please enable your location services", - "Settings", - this.arLocationManager!.openLocationServicesSettings, - "Cancel"); - break; - } - - case 'Location permissions denied': - { - showAlertDialog( - context, - "Action Required", - "To use cloud anchor functionality, please allow the app to access your device's location", - "Retry", - this.arLocationManager!.startLocationUpdates, - "Cancel"); - break; - } - - case 'Location permissions permanently denied': - { - showAlertDialog( - context, - "Action Required", - "To use cloud anchor functionality, please allow the app to access your device's location", - "Settings", - this.arLocationManager!.openAppPermissionSettings, - "Cancel"); - break; - } - - default: - { - AlertDialog( - title: Text("Error"), - content: Text(error.toString()), - ); - break; - } - } - }); - } - - Future onRemoveEverything() async { - anchors.forEach((anchor) { - this.arAnchorManager!.removeAnchor(anchor); - }); - anchors = []; - if (lastUploadedAnchor != "") { - setState(() { - readyToDownload = true; - readyToUpload = false; - }); - } else { - setState(() { - readyToDownload = true; - readyToUpload = false; - }); - } - } - - Future onNodeTapped(List nodeNames) async { - var foregroundNode = - nodes.firstWhere((element) => element.name == nodeNames.first); - AlertDialog( - title: Text("Information"), - content: Text(foregroundNode.data!["onTapText"]), - ); - } - - Future onPlaneOrPointTapped( - List hitTestResults) async { - var singleHitTestResult = hitTestResults.firstWhere( - (hitTestResult) => hitTestResult.type == ARHitTestResultType.plane); - if (singleHitTestResult != null) { - var newAnchor = ARPlaneAnchor( - transformation: singleHitTestResult.worldTransform, ttl: 2); - bool? didAddAnchor = await this.arAnchorManager!.addAnchor(newAnchor); - if (didAddAnchor ?? false) { - this.anchors.add(newAnchor); - // Add note to anchor - var newNode = ARNode( - type: NodeType.webGLB, - uri: - "https://github.com/KhronosGroup/glTF-Sample-Models/raw/refs/heads/main/2.0/Duck/glTF-Binary/Duck.glb", - scale: Vector3(0.2, 0.2, 0.2), - position: Vector3(0.0, 0.0, 0.0), - rotation: Vector4(1.0, 0.0, 0.0, 0.0), - data: {"onTapText": "Ouch, that hurt!"}); - bool? didAddNodeToAnchor = await this - .arObjectManager! - .addNode(newNode, planeAnchor: newAnchor); - if (didAddNodeToAnchor ?? false) { - this.nodes.add(newNode); - setState(() { - readyToUpload = true; - }); - } else { - AlertDialog( - title: Text("Information"), - content: Text("Adding Node to Anchor failed"), - ); - } - } else { - AlertDialog( - title: Text("Information"), - content: Text("Adding Anchor failed"), - ); - } - } - } - - Future onUploadButtonPressed() async { - this.arAnchorManager!.uploadAnchor(this.anchors.last); - setState(() { - readyToUpload = false; - }); - } - - onAnchorUploaded(ARAnchor anchor) { - // Upload anchor information to firebase - firebaseManager.uploadAnchor(anchor, - currentLocation: this.arLocationManager!.currentLocation); - // Upload child nodes to firebase - if (anchor is ARPlaneAnchor) { - anchor.childNodes.forEach((nodeName) => firebaseManager.uploadObject( - nodes.firstWhere((element) => element.name == nodeName))); - } - setState(() { - readyToDownload = true; - readyToUpload = false; - }); - AlertDialog( - title: Text("Information"), - content: Text("Upload successful"), - ); - } - - ARAnchor onAnchorDownloaded(Map serializedAnchor) { - final anchor = ARPlaneAnchor.fromJson( - anchorsInDownloadProgress[serializedAnchor["cloudanchorid"]] - as Map); - anchorsInDownloadProgress.remove(anchor.cloudanchorid); - this.anchors.add(anchor); - - // Download nodes attached to this anchor - firebaseManager.getObjectsFromAnchor(anchor, (snapshot) { - snapshot.docs.forEach((objectDoc) { - ARNode object = - ARNode.fromMap(objectDoc.data() as Map); - arObjectManager!.addNode(object, planeAnchor: anchor); - this.nodes.add(object); - }); - }); - - return anchor; - } - - Future onDownloadButtonPressed() async { - if (this.arLocationManager!.currentLocation != null) { - firebaseManager.downloadAnchorsByLocation((snapshot) { - final cloudAnchorId = snapshot.get("cloudanchorid"); - anchorsInDownloadProgress[cloudAnchorId] = - snapshot.data() as Map; - arAnchorManager!.downloadAnchor(cloudAnchorId); - }, this.arLocationManager!.currentLocation, 0.1); - setState(() { - readyToDownload = false; - }); - } else { - AlertDialog( - title: Text("Information"), - content: Text("Location updates not running, can't download anchors"), - ); - } - } - - void showAlertDialog(BuildContext context, String title, String content, - String buttonText, Function buttonFunction, String cancelButtonText) { - // set up the buttons - Widget cancelButton = ElevatedButton( - child: Text(cancelButtonText), - onPressed: () { - Navigator.of(context).pop(); - }, - ); - Widget actionButton = ElevatedButton( - child: Text(buttonText), - onPressed: () { - buttonFunction(); - Navigator.of(context).pop(); - }, - ); - - // set up the AlertDialog - AlertDialog alert = AlertDialog( - title: Text(title), - content: Text(content), - actions: [ - cancelButton, - actionButton, - ], - ); - - // show the dialog - showDialog( - context: context, - builder: (BuildContext context) { - return alert; - }, - ); - } -} - -// Class for managing interaction with Firebase (in your own app, this can be put in a separate file to keep everything clean and tidy) -typedef FirebaseListener = void Function(QuerySnapshot snapshot); -typedef FirebaseDocumentStreamListener = void Function( - DocumentSnapshot snapshot); - -class FirebaseManager { - FirebaseFirestore? firestore; - GeoFlutterFire? geo; - CollectionReference? anchorCollection; - CollectionReference? objectCollection; - - // Firebase initialization function - Future initializeFlutterFire() async { - try { - // Wait for Firebase to initialize - await Firebase.initializeApp(); - geo = GeoFlutterFire(); - firestore = FirebaseFirestore.instance; - anchorCollection = FirebaseFirestore.instance.collection('anchors'); - objectCollection = FirebaseFirestore.instance.collection('objects'); - return true; - } catch (e) { - return false; - } - } - - void uploadAnchor(ARAnchor anchor, {Position? currentLocation}) { - if (firestore == null) return; - - var serializedAnchor = anchor.toJson(); - var expirationTime = DateTime.now().millisecondsSinceEpoch / 1000 + - serializedAnchor["ttl"] * 24 * 60 * 60; - serializedAnchor["expirationTime"] = expirationTime; - // Add location - if (currentLocation != null) { - GeoFirePoint myLocation = geo!.point( - latitude: currentLocation.latitude, - longitude: currentLocation.longitude); - serializedAnchor["position"] = myLocation.data; - } - - anchorCollection! - .add(serializedAnchor) - .then((value) => - print("Successfully added anchor: " + serializedAnchor["name"])) - .catchError((error) => print("Failed to add anchor: $error")); - } - - void uploadObject(ARNode node) { - if (firestore == null) return; - - var serializedNode = node.toMap(); - - objectCollection! - .add(serializedNode) - .then((value) => - print("Successfully added object: " + serializedNode["name"])) - .catchError((error) => print("Failed to add object: $error")); - } - - void downloadLatestAnchor(FirebaseListener listener) { - anchorCollection! - .orderBy("expirationTime", descending: false) - .limitToLast(1) - .get() - .then((value) => listener(value)) - .catchError( - (error) => (error) => print("Failed to download anchor: $error")); - } - - void downloadAnchorsByLocation(FirebaseDocumentStreamListener listener, - Position location, double radius) { - GeoFirePoint center = - geo!.point(latitude: location.latitude, longitude: location.longitude); - - Stream> stream = geo! - .collection(collectionRef: anchorCollection!) - .within(center: center, radius: radius, field: 'position'); - - stream.listen((List documentList) { - documentList.forEach((element) { - listener(element); - }); - }); - } - - void downloadAnchorsByChannel() {} - - void getObjectsFromAnchor(ARPlaneAnchor anchor, FirebaseListener listener) { - objectCollection! - .where("name", whereIn: anchor.childNodes) - .get() - .then((value) => listener(value)) - .catchError((error) => print("Failed to download objects: $error")); - } - - void deleteExpiredDatabaseEntries() { - WriteBatch batch = FirebaseFirestore.instance.batch(); - anchorCollection! - .where("expirationTime", - isLessThan: DateTime.now().millisecondsSinceEpoch / 1000) - .get() - .then((anchorSnapshot) => anchorSnapshot.docs.forEach((anchorDoc) { - // Delete all objects attached to the expired anchor - objectCollection! - .where("name", arrayContainsAny: anchorDoc.get("childNodes")) - .get() - .then((objectSnapshot) => objectSnapshot.docs.forEach( - (objectDoc) => batch.delete(objectDoc.reference))); - // Delete the expired anchor - batch.delete(anchorDoc.reference); - })); - batch.commit(); - } -} - -Map getErrorTranslations() { - return { - "Cloud anchor id not found": "ID d'ancre cloud non trouvé", - "Dataset processing failed, feature map insufficient": - "On n'a pas assez d'infos sur ton environnement, fais le tour de la pièce avec ta caméra afin qu'on puisse analyser les surfaces autour de toi, puis repositionne l'indice.", - "Hosting service unavailable": - "Problème de connexion : les serveurs Eskape sont inaccessibles. Réessaie ou contacte-nous pour débloquer la situation.", - "Internal error": - "Erreur interne. Réessaie ou contacte-nous pour débloquer la situation.", - "Authentication failed: Not Authorized": - "Échec de l'authentification : déconnecte-toi puis reconnecte-toi. Si la situation persiste, contacte-nous.", - "Resolving Sdk version too new": - "Version du SDK trop récente. Contacte-nous pour débloquer la situation.", - "Resolving Sdk version too old": - "Version du SDK trop ancienne. Contacte-nous pour débloquer la situation.", - "Resource exhausted": - "Ressource épuisée : Contacte-nous pour débloquer la situation.", - "Empty state": "État vide : Contacte-nous pour débloquer la situation.", - "Task in progress": "Tâche en cours", - "Success": "Succès", - "Cloud Anchor Service unavailable": - "Service d'Ancre Cloud indisponible : Contacte-nous pour débloquer la situation.", - "No match": - "Aucune correspondance : Contacte-nous pour débloquer la situation.", - "Unknown": "Erreure inconnue : Contacte-nous pour débloquer la situation." - }; -} diff --git a/examples/debug_options.dart b/examples/debug_options.dart deleted file mode 100644 index 9f68e750..00000000 --- a/examples/debug_options.dart +++ /dev/null @@ -1,133 +0,0 @@ -// Automatic FlutterFlow imports -import '/flutter_flow/flutter_flow_theme.dart'; -import '/flutter_flow/flutter_flow_util.dart'; -import 'index.dart'; // Imports other custom widgets -import 'package:flutter/material.dart'; -// Begin custom widget code -// DO NOT REMOVE OR MODIFY THE CODE ABOVE! - -//AR Flutter Plugin -import 'package:ar_flutter_plugin_2/ar_flutter_plugin.dart'; -import 'package:ar_flutter_plugin_2/managers/ar_location_manager.dart'; -import 'package:ar_flutter_plugin_2/managers/ar_session_manager.dart'; -import 'package:ar_flutter_plugin_2/managers/ar_object_manager.dart'; -import 'package:ar_flutter_plugin_2/managers/ar_anchor_manager.dart'; -import 'package:ar_flutter_plugin_2/datatypes/config_planedetection.dart'; - -class DebugOptions extends StatefulWidget { - const DebugOptions({ - super.key, - this.width, - this.height, - }); - - final double? width; - final double? height; - - @override - State createState() => _DebugOptionsState(); -} - -class _DebugOptionsState extends State { - ARSessionManager? arSessionManager; - ARObjectManager? arObjectManager; - bool _showFeaturePoints = false; - bool _showPlanes = false; - bool _showWorldOrigin = false; - bool _showAnimatedGuide = true; - String _planeTexturePath = "Images/triangle.png"; - bool _handleTaps = false; - - @override - void dispose() { - super.dispose(); - arSessionManager!.dispose(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Debug Options'), - ), - body: Container( - child: Stack(children: [ - ARView( - onARViewCreated: onARViewCreated, - planeDetectionConfig: PlaneDetectionConfig.horizontalAndVertical, - showPlatformType: true, - ), - Align( - alignment: FractionalOffset.bottomRight, - child: Container( - width: MediaQuery.of(context).size.width * 0.5, - color: Color(0xFFFFFFF).withOpacity(0.5), - child: Column( - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisSize: MainAxisSize.min, - children: [ - SwitchListTile( - title: const Text('Feature Points'), - value: _showFeaturePoints, - onChanged: (bool value) { - setState(() { - _showFeaturePoints = value; - updateSessionSettings(); - }); - }, - ), - SwitchListTile( - title: const Text('Planes'), - value: _showPlanes, - onChanged: (bool value) { - setState(() { - _showPlanes = value; - updateSessionSettings(); - }); - }, - ), - SwitchListTile( - title: const Text('World Origin'), - value: _showWorldOrigin, - onChanged: (bool value) { - setState(() { - _showWorldOrigin = value; - updateSessionSettings(); - }); - }, - ), - ], - ), - ), - ), - ]))); - } - - void onARViewCreated( - ARSessionManager arSessionManager, - ARObjectManager arObjectManager, - ARAnchorManager arAnchorManager, - ARLocationManager arLocationManager) { - this.arSessionManager = arSessionManager; - this.arObjectManager = arObjectManager; - - this.arSessionManager!.onInitialize( - showFeaturePoints: _showFeaturePoints, - showPlanes: _showPlanes, - customPlaneTexturePath: _planeTexturePath, - showWorldOrigin: _showWorldOrigin, - showAnimatedGuide: _showAnimatedGuide, - handleTaps: _handleTaps, - ); - this.arObjectManager!.onInitialize(); - } - - void updateSessionSettings() { - this.arSessionManager!.onInitialize( - showFeaturePoints: _showFeaturePoints, - showPlanes: _showPlanes, - customPlaneTexturePath: _planeTexturePath, - showWorldOrigin: _showWorldOrigin, - ); - } -} diff --git a/examples/external_model_management.dart b/examples/external_model_management.dart deleted file mode 100644 index 49360d2f..00000000 --- a/examples/external_model_management.dart +++ /dev/null @@ -1,668 +0,0 @@ -// Automatic FlutterFlow imports -import '/flutter_flow/flutter_flow_theme.dart'; -import '/flutter_flow/flutter_flow_util.dart'; -import 'index.dart'; // Imports other custom widgets -import 'package:flutter/material.dart'; -// Begin custom widget code -// DO NOT REMOVE OR MODIFY THE CODE ABOVE! - -//AR Flutter Plugin -import 'package:ar_flutter_plugin_2/managers/ar_location_manager.dart'; -import 'package:ar_flutter_plugin_2/managers/ar_session_manager.dart'; -import 'package:ar_flutter_plugin_2/managers/ar_object_manager.dart'; -import 'package:ar_flutter_plugin_2/managers/ar_anchor_manager.dart'; -import 'package:ar_flutter_plugin_2/models/ar_anchor.dart'; -import 'package:ar_flutter_plugin_2/ar_flutter_plugin.dart'; -import 'package:ar_flutter_plugin_2/datatypes/config_planedetection.dart'; -import 'package:ar_flutter_plugin_2/datatypes/node_types.dart'; -import 'package:ar_flutter_plugin_2/datatypes/hittest_result_types.dart'; -import 'package:ar_flutter_plugin_2/models/ar_node.dart'; -import 'package:ar_flutter_plugin_2/models/ar_hittest_result.dart'; - -//Other custom imports -import 'dart:convert'; -import 'package:vector_math/vector_math_64.dart' as VectorMath; -import 'package:firebase_core/firebase_core.dart'; -import 'package:cloud_firestore/cloud_firestore.dart'; -import 'package:geoflutterfire2/geoflutterfire2.dart'; -import 'package:geolocator/geolocator.dart'; - -class ExternalModelManagement extends StatefulWidget { - const ExternalModelManagement({ - super.key, - this.width, - this.height, - }); - - final double? width; - final double? height; - - @override - State createState() => - _ExternalModelManagementState(); -} - -class _ExternalModelManagementState extends State { - // Firebase stuff - bool _initialized = false; - bool _error = false; - FirebaseManager firebaseManager = FirebaseManager(); - Map anchorsInDownloadProgress = Map(); - - ARSessionManager? arSessionManager; - ARObjectManager? arObjectManager; - ARAnchorManager? arAnchorManager; - ARLocationManager? arLocationManager; - - List nodes = []; - List anchors = []; - String lastUploadedAnchor = ""; - AvailableModel selectedModel = AvailableModel( - "Duck", - "https://github.com/KhronosGroup/glTF-Sample-Models/raw/refs/heads/main/2.0/Duck/glTF-Binary/Duck.glb", - ""); - - bool readyToUpload = false; - bool readyToDownload = true; - bool modelChoiceActive = false; - - @override - void initState() { - firebaseManager.initializeFlutterFire().then((value) => setState(() { - _initialized = value; - _error = !value; - })); - - super.initState(); - } - - @override - void dispose() { - super.dispose(); - arSessionManager!.dispose(); - } - - @override - Widget build(BuildContext context) { - // Show error message if initialization failed - if (_error) { - return Scaffold( - appBar: AppBar( - title: const Text('External Model Management'), - ), - body: Container( - child: Center( - child: Column( - children: [ - Text("Firebase initialization failed"), - ElevatedButton( - child: Text("Retry"), onPressed: () => {initState()}) - ], - )))); - } - - // Show a loader until FlutterFire is initialized - if (!_initialized) { - return Scaffold( - appBar: AppBar( - title: const Text('External Model Management'), - ), - body: Container( - child: Center( - child: Column(children: [ - CircularProgressIndicator(), - Text("Initializing Firebase") - ])))); - } - - return Scaffold( - appBar: AppBar( - title: const Text('External Model Management'), - actions: [ - IconButton( - icon: Icon(Icons.pets), - onPressed: () { - setState(() { - modelChoiceActive = !modelChoiceActive; - }); - }, - ), - ]), - body: Container( - child: Stack(children: [ - ARView( - onARViewCreated: onARViewCreated, - planeDetectionConfig: PlaneDetectionConfig.horizontalAndVertical, - ), - Align( - alignment: FractionalOffset.bottomCenter, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - ElevatedButton( - onPressed: onRemoveEverything, - child: Text("Remove Everything")), - ]), - ), - Align( - alignment: FractionalOffset.topCenter, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Visibility( - visible: readyToUpload, - child: ElevatedButton( - onPressed: onUploadButtonPressed, - child: Text("Upload"))), - Visibility( - visible: readyToDownload, - child: ElevatedButton( - onPressed: onDownloadButtonPressed, - child: Text("Download"))), - ]), - ), - Align( - alignment: FractionalOffset.centerLeft, - child: Visibility( - visible: modelChoiceActive, - child: ModelSelectionWidget( - onTap: onModelSelected, - firebaseManager: this.firebaseManager))) - ]))); - } - - void onARViewCreated( - ARSessionManager arSessionManager, - ARObjectManager arObjectManager, - ARAnchorManager arAnchorManager, - ARLocationManager arLocationManager) { - this.arSessionManager = arSessionManager; - this.arObjectManager = arObjectManager; - this.arAnchorManager = arAnchorManager; - this.arLocationManager = arLocationManager; - - this.arSessionManager!.onInitialize( - showFeaturePoints: false, - showPlanes: true, - customPlaneTexturePath: "Images/triangle.png", - showWorldOrigin: true, - ); - this.arObjectManager!.onInitialize(); - this.arAnchorManager!.initGoogleCloudAnchorMode(); - - this.arSessionManager!.onPlaneOrPointTap = onPlaneOrPointTapped; - this.arObjectManager!.onNodeTap = onNodeTapped; - this.arAnchorManager!.onAnchorUploaded = onAnchorUploaded; - this.arAnchorManager!.onAnchorDownloaded = onAnchorDownloaded; - - this - .arLocationManager! - .startLocationUpdates() - .then((value) => null) - .onError((error, stackTrace) { - switch (error.toString()) { - case 'Location services disabled': - { - showAlertDialog( - context, - "Action Required", - "To use cloud anchor functionality, please enable your location services", - "Settings", - this.arLocationManager!.openLocationServicesSettings, - "Cancel"); - break; - } - - case 'Location permissions denied': - { - showAlertDialog( - context, - "Action Required", - "To use cloud anchor functionality, please allow the app to access your device's location", - "Retry", - this.arLocationManager!.startLocationUpdates, - "Cancel"); - break; - } - - case 'Location permissions permanently denied': - { - showAlertDialog( - context, - "Action Required", - "To use cloud anchor functionality, please allow the app to access your device's location", - "Settings", - this.arLocationManager!.openAppPermissionSettings, - "Cancel"); - break; - } - - default: - { - AlertDialog( - title: Text("Error"), - content: Text(error.toString()), - ); - break; - } - } - }); - } - - void onModelSelected(AvailableModel model) { - this.selectedModel = model; - AlertDialog( - title: Text("Information"), - content: Text(model.name + " selected"), - ); - - setState(() { - modelChoiceActive = false; - }); - } - - Future onRemoveEverything() async { - anchors.forEach((anchor) { - this.arAnchorManager!.removeAnchor(anchor); - }); - anchors = []; - if (lastUploadedAnchor != "") { - setState(() { - readyToDownload = true; - readyToUpload = false; - }); - } else { - setState(() { - readyToDownload = true; - readyToUpload = false; - }); - } - } - - Future onNodeTapped(List nodeNames) async { - var foregroundNode = - nodes.firstWhere((element) => element.name == nodeNames.first); - AlertDialog( - title: Text("Information"), - content: Text(foregroundNode.data!["onTapText"]), - ); - } - - Future onPlaneOrPointTapped( - List hitTestResults) async { - var singleHitTestResult = hitTestResults.firstWhere( - (hitTestResult) => hitTestResult.type == ARHitTestResultType.plane); - if (singleHitTestResult != null) { - var newAnchor = ARPlaneAnchor( - transformation: singleHitTestResult.worldTransform, ttl: 2); - bool? didAddAnchor = await this.arAnchorManager!.addAnchor(newAnchor); - if (didAddAnchor!) { - this.anchors.add(newAnchor); - // Add note to anchor - var newNode = ARNode( - type: NodeType.webGLB, - uri: this.selectedModel.uri, - scale: VectorMath.Vector3(0.2, 0.2, 0.2), - position: VectorMath.Vector3(0.0, 0.0, 0.0), - rotation: VectorMath.Vector4(1.0, 0.0, 0.0, 0.0), - data: {"onTapText": "I am a " + this.selectedModel.name}); - bool? didAddNodeToAnchor = await this - .arObjectManager! - .addNode(newNode, planeAnchor: newAnchor); - if (didAddNodeToAnchor!) { - this.nodes.add(newNode); - setState(() { - readyToUpload = true; - }); - } else { - AlertDialog( - title: Text("Error"), - content: Text("Adding Node to Anchor failed"), - ); - } - } else { - AlertDialog( - title: Text("Error"), - content: Text("Adding Anchor failed"), - ); - } - } - } - - Future onUploadButtonPressed() async { - this.arAnchorManager!.uploadAnchor(this.anchors.last); - setState(() { - readyToUpload = false; - }); - } - - onAnchorUploaded(ARAnchor anchor) { - // Upload anchor information to firebase - firebaseManager.uploadAnchor(anchor, - currentLocation: this.arLocationManager!.currentLocation); - // Upload child nodes to firebase - if (anchor is ARPlaneAnchor) { - anchor.childNodes.forEach((nodeName) => firebaseManager.uploadObject( - nodes.firstWhere((element) => element.name == nodeName))); - } - setState(() { - readyToDownload = true; - readyToUpload = false; - }); - AlertDialog( - title: Text("Information"), - content: Text("Upload successful"), - ); - } - - ARAnchor onAnchorDownloaded(Map serializedAnchor) { - final anchor = ARPlaneAnchor.fromJson( - anchorsInDownloadProgress[serializedAnchor["cloudanchorid"]] - as Map); - anchorsInDownloadProgress.remove(anchor.cloudanchorid); - this.anchors.add(anchor); - - // Download nodes attached to this anchor - firebaseManager.getObjectsFromAnchor(anchor, (snapshot) { - snapshot.docs.forEach((objectDoc) { - ARNode object = - ARNode.fromMap(objectDoc.data() as Map); - arObjectManager!.addNode(object, planeAnchor: anchor); - this.nodes.add(object); - }); - }); - - return anchor; - } - - Future onDownloadButtonPressed() async { - //this.arAnchorManager.downloadAnchor(lastUploadedAnchor); - //firebaseManager.downloadLatestAnchor((snapshot) { - // final cloudAnchorId = snapshot.docs.first.get("cloudanchorid"); - // anchorsInDownloadProgress[cloudAnchorId] = snapshot.docs.first.data(); - // arAnchorManager.downloadAnchor(cloudAnchorId); - //}); - - // Get anchors within a radius of 100m of the current device's location - if (this.arLocationManager!.currentLocation != null) { - firebaseManager.downloadAnchorsByLocation((snapshot) { - final cloudAnchorId = snapshot.get("cloudanchorid"); - anchorsInDownloadProgress[cloudAnchorId] = - snapshot.data() as Map; - arAnchorManager!.downloadAnchor(cloudAnchorId); - }, this.arLocationManager!.currentLocation, 0.1); - setState(() { - readyToDownload = false; - }); - } else { - AlertDialog( - title: Text("Error"), - content: Text("Location updates not running, can't download anchors"), - ); - } - } - - void showAlertDialog(BuildContext context, String title, String content, - String buttonText, Function buttonFunction, String cancelButtonText) { - // set up the buttons - Widget cancelButton = ElevatedButton( - child: Text(cancelButtonText), - onPressed: () { - Navigator.of(context).pop(); - }, - ); - Widget actionButton = ElevatedButton( - child: Text(buttonText), - onPressed: () { - buttonFunction(); - Navigator.of(context).pop(); - }, - ); - - // set up the AlertDialog - AlertDialog alert = AlertDialog( - title: Text(title), - content: Text(content), - actions: [ - cancelButton, - actionButton, - ], - ); - - // show the dialog - showDialog( - context: context, - builder: (BuildContext context) { - return alert; - }, - ); - } -} - -// Class for managing interaction with Firebase (in your own app, this can be put in a separate file to keep everything clean and tidy) -typedef FirebaseListener = void Function(QuerySnapshot snapshot); -typedef FirebaseDocumentStreamListener = void Function( - DocumentSnapshot snapshot); - -class FirebaseManager { - FirebaseFirestore? firestore; - GeoFlutterFire? geo; - CollectionReference? anchorCollection; - CollectionReference? objectCollection; - CollectionReference? modelCollection; - - // Firebase initialization function - Future initializeFlutterFire() async { - try { - // Wait for Firebase to initialize - await Firebase.initializeApp(); - geo = GeoFlutterFire(); - firestore = FirebaseFirestore.instance; - anchorCollection = FirebaseFirestore.instance.collection('anchors'); - objectCollection = FirebaseFirestore.instance.collection('objects'); - modelCollection = FirebaseFirestore.instance.collection('models'); - return true; - } catch (e) { - return false; - } - } - - void uploadAnchor(ARAnchor anchor, {Position? currentLocation}) { - if (firestore == null) return; - - var serializedAnchor = anchor.toJson(); - var expirationTime = DateTime.now().millisecondsSinceEpoch / 1000 + - serializedAnchor["ttl"] * 24 * 60 * 60; - serializedAnchor["expirationTime"] = expirationTime; - // Add location - if (currentLocation != null) { - GeoFirePoint myLocation = geo!.point( - latitude: currentLocation.latitude, - longitude: currentLocation.longitude); - serializedAnchor["position"] = myLocation.data; - } - - anchorCollection! - .add(serializedAnchor) - .then((value) => - print("Successfully added anchor: " + serializedAnchor["name"])) - .catchError((error) => print("Failed to add anchor: $error")); - } - - void uploadObject(ARNode node) { - if (firestore == null) return; - - var serializedNode = node.toMap(); - - objectCollection! - .add(serializedNode) - .then((value) => - print("Successfully added object: " + serializedNode["name"])) - .catchError((error) => print("Failed to add object: $error")); - } - - void downloadLatestAnchor(FirebaseListener listener) { - anchorCollection! - .orderBy("expirationTime", descending: false) - .limitToLast(1) - .get() - .then((value) => listener(value)) - .catchError( - (error) => (error) => print("Failed to download anchor: $error")); - } - - void downloadAnchorsByLocation(FirebaseDocumentStreamListener listener, - Position location, double radius) { - GeoFirePoint center = - geo!.point(latitude: location.latitude, longitude: location.longitude); - - Stream> stream = geo! - .collection(collectionRef: anchorCollection!) - .within(center: center, radius: radius, field: 'position'); - - stream.listen((List documentList) { - documentList.forEach((element) { - listener(element); - }); - }); - } - - void downloadAnchorsByChannel() {} - - void getObjectsFromAnchor(ARPlaneAnchor anchor, FirebaseListener listener) { - objectCollection! - .where("name", whereIn: anchor.childNodes) - .get() - .then((value) => listener(value)) - .catchError((error) => print("Failed to download objects: $error")); - } - - void deleteExpiredDatabaseEntries() { - WriteBatch batch = FirebaseFirestore.instance.batch(); - anchorCollection! - .where("expirationTime", - isLessThan: DateTime.now().millisecondsSinceEpoch / 1000) - .get() - .then((anchorSnapshot) => anchorSnapshot.docs.forEach((anchorDoc) { - // Delete all objects attached to the expired anchor - objectCollection! - .where("name", arrayContainsAny: anchorDoc.get("childNodes")) - .get() - .then((objectSnapshot) => objectSnapshot.docs.forEach( - (objectDoc) => batch.delete(objectDoc.reference))); - // Delete the expired anchor - batch.delete(anchorDoc.reference); - })); - batch.commit(); - } - - void downloadAvailableModels(FirebaseListener listener) { - modelCollection! - .get() - .then((value) => listener(value)) - .catchError((error) => print("Failed to download objects: $error")); - } -} - -class AvailableModel { - String name; - String uri; - String image; - AvailableModel(this.name, this.uri, this.image); -} - -class ModelSelectionWidget extends StatefulWidget { - final Function onTap; - final FirebaseManager firebaseManager; - - ModelSelectionWidget({required this.onTap, required this.firebaseManager}); - - @override - _ModelSelectionWidgetState createState() => _ModelSelectionWidgetState(); -} - -class _ModelSelectionWidgetState extends State { - List models = []; - - String? selected; - - @override - void initState() { - super.initState(); - widget.firebaseManager.downloadAvailableModels((snapshot) { - snapshot.docs.forEach((element) { - setState(() { - models.add(AvailableModel(element.get("name"), element.get("uri"), - element.get("image").first["downloadURL"])); - }); - }); - }); - } - - @override - Widget build(BuildContext context) { - return Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - DecoratedBox( - decoration: BoxDecoration( - color: Colors.white, - border: Border.all( - color: Colors.white, - style: BorderStyle.solid, - width: 4.0, - ), - borderRadius: BorderRadius.all(Radius.circular(5)), - shape: BoxShape.rectangle, - boxShadow: const [ - BoxShadow( - color: Color(0x66000000), - blurRadius: 10.0, - spreadRadius: 4.0, - ) - ], - ), - child: Text('Choose a Model', - style: DefaultTextStyle.of(context) - .style - .apply(fontSizeFactor: 2.0)), - ), - Container( - height: MediaQuery.of(context).size.width * 0.65, - child: ListView.builder( - itemCount: models.length, - scrollDirection: Axis.horizontal, - itemBuilder: (context, index) { - return GestureDetector( - onTap: () { - widget.onTap(models[index]); - }, - child: Card( - elevation: 4.0, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.all( - Radius.circular(5), - ), - ), - child: Column( - children: [ - Padding( - padding: EdgeInsets.all(20), - child: Image.network(models[index].image)), - Text( - models[index].name, - style: DefaultTextStyle.of(context) - .style - .apply(fontSizeFactor: 2.0), - ) - ], - ), - ), - ); - }, - ), - ) - ]); - } -} diff --git a/examples/local_and_web_objects.dart b/examples/local_and_web_objects.dart deleted file mode 100644 index 5c6397b9..00000000 --- a/examples/local_and_web_objects.dart +++ /dev/null @@ -1,259 +0,0 @@ -// Automatic FlutterFlow imports -import '/flutter_flow/flutter_flow_theme.dart'; -import '/flutter_flow/flutter_flow_util.dart'; -import 'index.dart'; // Imports other custom widgets -import 'package:flutter/material.dart'; -// Begin custom widget code -// DO NOT REMOVE OR MODIFY THE CODE ABOVE! - -//AR Flutter Plugin -import 'package:ar_flutter_plugin_2/managers/ar_location_manager.dart'; -import 'package:ar_flutter_plugin_2/managers/ar_session_manager.dart'; -import 'package:ar_flutter_plugin_2/managers/ar_object_manager.dart'; -import 'package:ar_flutter_plugin_2/managers/ar_anchor_manager.dart'; -import 'package:ar_flutter_plugin_2/ar_flutter_plugin.dart'; -import 'package:ar_flutter_plugin_2/datatypes/config_planedetection.dart'; -import 'package:ar_flutter_plugin_2/datatypes/node_types.dart'; -import 'package:ar_flutter_plugin_2/models/ar_node.dart'; - -//Other custom imports -import 'dart:io'; -import 'package:flutter/services.dart'; -import 'package:vector_math/vector_math_64.dart'; -import 'dart:math'; -import 'package:path_provider/path_provider.dart'; -import 'package:flutter_archive/flutter_archive.dart'; -import 'package:flutter/foundation.dart'; - -class LocalAndWebObjects extends StatefulWidget { - const LocalAndWebObjects({ - super.key, - this.width, - this.height, - }); - - final double? width; - final double? height; - - @override - State createState() => _LocalAndWebObjectsState(); -} - -class _LocalAndWebObjectsState extends State { - ARSessionManager? arSessionManager; - ARObjectManager? arObjectManager; - //String localObjectReference; - ARNode? localObjectNode; - //String webObjectReference; - ARNode? webObjectNode; - ARNode? fileSystemNode; - HttpClient? httpClient; - - @override - void dispose() { - super.dispose(); - arSessionManager!.dispose(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Local & Web Objects'), - ), - body: Container( - child: Stack(children: [ - ARView( - onARViewCreated: onARViewCreated, - planeDetectionConfig: PlaneDetectionConfig.horizontalAndVertical, - ), - Align( - alignment: FractionalOffset.bottomCenter, - child: - Column(mainAxisAlignment: MainAxisAlignment.end, children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - ElevatedButton( - onPressed: onFileSystemObjectAtOriginButtonPressed, - child: Text("Add/Remove Filesystem\nObject at Origin")), - ], - ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - ElevatedButton( - onPressed: onLocalObjectAtOriginButtonPressed, - child: Text("Add/Remove Local\nObject at Origin")), - ElevatedButton( - onPressed: onWebObjectAtOriginButtonPressed, - child: Text("Add/Remove Web\nObject at Origin")), - ], - ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - ElevatedButton( - onPressed: onLocalObjectShuffleButtonPressed, - child: Text("Shuffle Local\nobject at Origin")), - ElevatedButton( - onPressed: onWebObjectShuffleButtonPressed, - child: Text("Shuffle Web\nObject at Origin")), - ], - ) - ])) - ]))); - } - - void onARViewCreated( - ARSessionManager arSessionManager, - ARObjectManager arObjectManager, - ARAnchorManager arAnchorManager, - ARLocationManager arLocationManager) { - this.arSessionManager = arSessionManager; - this.arObjectManager = arObjectManager; - - this.arSessionManager!.onInitialize( - showFeaturePoints: false, - showPlanes: true, - customPlaneTexturePath: "Images/triangle.png", - showWorldOrigin: true, - handleTaps: false, - ); - this.arObjectManager!.onInitialize(); - - //Download model to file system - httpClient = new HttpClient(); - _downloadFile( - "https://github.com/KhronosGroup/glTF-Sample-Models/raw/refs/heads/main/2.0/Duck/glTF-Binary/Duck.glb", - "LocalDuck.glb"); - // Alternative to use type fileSystemAppFolderGLTF2: - //_downloadAndUnpack( - // "https://drive.google.com/uc?export=download&id=1fng7yiK0DIR0uem7XkV2nlPSGH9PysUs", - // "Chicken_01.zip"); - } - - Future _downloadFile(String url, String filename) async { - var request = await httpClient!.getUrl(Uri.parse(url)); - var response = await request.close(); - var bytes = await consolidateHttpClientResponseBytes(response); - String dir = (await getApplicationDocumentsDirectory()).path; - File file = new File('$dir/$filename'); - await file.writeAsBytes(bytes); - print("Downloading finished, path: " + '$dir/$filename'); - return file; - } - - Future _downloadAndUnpack(String url, String filename) async { - var request = await httpClient!.getUrl(Uri.parse(url)); - var response = await request.close(); - var bytes = await consolidateHttpClientResponseBytes(response); - String dir = (await getApplicationDocumentsDirectory()).path; - File file = new File('$dir/$filename'); - await file.writeAsBytes(bytes); - print("Downloading finished, path: " + '$dir/$filename'); - - // To print all files in the directory: print(Directory(dir).listSync()); - try { - await ZipFile.extractToDirectory( - zipFile: File('$dir/$filename'), destinationDir: Directory(dir)); - print("Unzipping successful"); - } catch (e) { - print("Unzipping failed: " + e.toString()); - } - } - - Future onLocalObjectAtOriginButtonPressed() async { - if (this.localObjectNode != null) { - this.arObjectManager!.removeNode(this.localObjectNode!); - this.localObjectNode = null; - } else { - var newNode = ARNode( - type: NodeType.localGLTF2, - uri: "Models/Chicken_01/Chicken_01.gltf", - scale: Vector3(0.2, 0.2, 0.2), - position: Vector3(0.0, 0.0, 0.0), - rotation: Vector4(1.0, 0.0, 0.0, 0.0)); - bool? didAddLocalNode = await this.arObjectManager!.addNode(newNode); - this.localObjectNode = (didAddLocalNode!) ? newNode : null; - } - } - - Future onWebObjectAtOriginButtonPressed() async { - if (this.webObjectNode != null) { - this.arObjectManager!.removeNode(this.webObjectNode!); - this.webObjectNode = null; - } else { - var newNode = ARNode( - type: NodeType.webGLB, - uri: - "https://github.com/KhronosGroup/glTF-Sample-Models/raw/refs/heads/main/2.0/Duck/glTF-Binary/Duck.glb", - scale: Vector3(0.2, 0.2, 0.2)); - bool? didAddWebNode = await this.arObjectManager!.addNode(newNode); - this.webObjectNode = (didAddWebNode!) ? newNode : null; - } - } - - Future onFileSystemObjectAtOriginButtonPressed() async { - if (this.fileSystemNode != null) { - this.arObjectManager!.removeNode(this.fileSystemNode!); - this.fileSystemNode = null; - } else { - var newNode = ARNode( - type: NodeType.fileSystemAppFolderGLB, - uri: "LocalDuck.glb", - scale: Vector3(0.2, 0.2, 0.2)); - //Alternative to use type fileSystemAppFolderGLTF2: - //var newNode = ARNode( - // type: NodeType.fileSystemAppFolderGLTF2, - // uri: "Chicken_01.gltf", - // scale: Vector3(0.2, 0.2, 0.2)); - bool? didAddFileSystemNode = await this.arObjectManager!.addNode(newNode); - this.fileSystemNode = (didAddFileSystemNode!) ? newNode : null; - } - } - - Future onLocalObjectShuffleButtonPressed() async { - if (this.localObjectNode != null) { - var newScale = Random().nextDouble() / 3; - var newTranslationAxis = Random().nextInt(3); - var newTranslationAmount = Random().nextDouble() / 3; - var newTranslation = Vector3(0, 0, 0); - newTranslation[newTranslationAxis] = newTranslationAmount; - var newRotationAxisIndex = Random().nextInt(3); - var newRotationAmount = Random().nextDouble(); - var newRotationAxis = Vector3(0, 0, 0); - newRotationAxis[newRotationAxisIndex] = 1.0; - - final newTransform = Matrix4.identity(); - - newTransform.setTranslation(newTranslation); - newTransform.rotate(newRotationAxis, newRotationAmount); - newTransform.scale(newScale); - - this.localObjectNode!.transform = newTransform; - } - } - - Future onWebObjectShuffleButtonPressed() async { - if (this.webObjectNode != null) { - var newScale = Random().nextDouble() / 3; - var newTranslationAxis = Random().nextInt(3); - var newTranslationAmount = Random().nextDouble() / 3; - var newTranslation = Vector3(0, 0, 0); - newTranslation[newTranslationAxis] = newTranslationAmount; - var newRotationAxisIndex = Random().nextInt(3); - var newRotationAmount = Random().nextDouble(); - var newRotationAxis = Vector3(0, 0, 0); - newRotationAxis[newRotationAxisIndex] = 1.0; - - final newTransform = Matrix4.identity(); - - newTransform.setTranslation(newTranslation); - newTransform.rotate(newRotationAxis, newRotationAmount); - newTransform.scale(newScale); - - this.webObjectNode!.transform = newTransform; - } - } -} diff --git a/examples/object_gestures.dart b/examples/object_gestures.dart deleted file mode 100644 index c0143207..00000000 --- a/examples/object_gestures.dart +++ /dev/null @@ -1,195 +0,0 @@ -// Automatic FlutterFlow imports -import '/flutter_flow/flutter_flow_theme.dart'; -import '/flutter_flow/flutter_flow_util.dart'; -import 'index.dart'; // Imports other custom widgets -import 'package:flutter/material.dart'; -// Begin custom widget code -// DO NOT REMOVE OR MODIFY THE CODE ABOVE! - -//AR Flutter Plugin -import 'package:ar_flutter_plugin_2/managers/ar_location_manager.dart'; -import 'package:ar_flutter_plugin_2/managers/ar_session_manager.dart'; -import 'package:ar_flutter_plugin_2/managers/ar_object_manager.dart'; -import 'package:ar_flutter_plugin_2/managers/ar_anchor_manager.dart'; -import 'package:ar_flutter_plugin_2/models/ar_anchor.dart'; -import 'package:ar_flutter_plugin_2/ar_flutter_plugin.dart'; -import 'package:ar_flutter_plugin_2/datatypes/config_planedetection.dart'; -import 'package:ar_flutter_plugin_2/datatypes/node_types.dart'; -import 'package:ar_flutter_plugin_2/datatypes/hittest_result_types.dart'; -import 'package:ar_flutter_plugin_2/models/ar_node.dart'; -import 'package:ar_flutter_plugin_2/models/ar_hittest_result.dart'; - -//Other custom imports -import 'package:flutter/services.dart'; -import 'package:vector_math/vector_math_64.dart'; -import 'dart:math'; - -class ObjectGestures extends StatefulWidget { - const ObjectGestures({ - super.key, - this.width, - this.height, - }); - - final double? width; - final double? height; - - @override - State createState() => _ObjectGesturesState(); -} - -class _ObjectGesturesState extends State { - ARSessionManager? arSessionManager; - ARObjectManager? arObjectManager; - ARAnchorManager? arAnchorManager; - - List nodes = []; - List anchors = []; - - @override - void dispose() { - super.dispose(); - arSessionManager!.dispose(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Object Transformation Gestures'), - ), - body: Container( - child: Stack(children: [ - ARView( - onARViewCreated: onARViewCreated, - planeDetectionConfig: PlaneDetectionConfig.horizontalAndVertical, - ), - Align( - alignment: FractionalOffset.bottomCenter, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - ElevatedButton( - onPressed: onRemoveEverything, - child: Text("Remove Everything")), - ]), - ) - ]))); - } - - void onARViewCreated( - ARSessionManager arSessionManager, - ARObjectManager arObjectManager, - ARAnchorManager arAnchorManager, - ARLocationManager arLocationManager) { - this.arSessionManager = arSessionManager; - this.arObjectManager = arObjectManager; - this.arAnchorManager = arAnchorManager; - - this.arSessionManager!.onInitialize( - showFeaturePoints: false, - showPlanes: true, - customPlaneTexturePath: "Images/triangle.png", - showWorldOrigin: true, - handlePans: true, - handleRotation: true, - ); - this.arObjectManager!.onInitialize(); - - this.arSessionManager!.onPlaneOrPointTap = onPlaneOrPointTapped; - this.arObjectManager!.onPanStart = onPanStarted; - this.arObjectManager!.onPanChange = onPanChanged; - this.arObjectManager!.onPanEnd = onPanEnded; - this.arObjectManager!.onRotationStart = onRotationStarted; - this.arObjectManager!.onRotationChange = onRotationChanged; - this.arObjectManager!.onRotationEnd = onRotationEnded; - } - - Future onRemoveEverything() async { - /*nodes.forEach((node) { - this.arObjectManager.removeNode(node); - });*/ - anchors.forEach((anchor) { - this.arAnchorManager!.removeAnchor(anchor); - }); - anchors = []; - } - - Future onPlaneOrPointTapped( - List hitTestResults) async { - var singleHitTestResult = hitTestResults.firstWhere( - (hitTestResult) => hitTestResult.type == ARHitTestResultType.plane); - if (singleHitTestResult != null) { - var newAnchor = - ARPlaneAnchor(transformation: singleHitTestResult.worldTransform); - bool? didAddAnchor = await this.arAnchorManager!.addAnchor(newAnchor); - if (didAddAnchor!) { - this.anchors.add(newAnchor); - // Add note to anchor - var newNode = ARNode( - type: NodeType.webGLB, - uri: - "https://github.com/KhronosGroup/glTF-Sample-Models/raw/refs/heads/main/2.0/Duck/glTF-Binary/Duck.glb", - scale: Vector3(0.2, 0.2, 0.2), - position: Vector3(0.0, 0.0, 0.0), - rotation: Vector4(1.0, 0.0, 0.0, 0.0)); - bool? didAddNodeToAnchor = await this - .arObjectManager! - .addNode(newNode, planeAnchor: newAnchor); - if (didAddNodeToAnchor!) { - this.nodes.add(newNode); - } else { - AlertDialog( - title: Text("Error"), - content: Text("Adding Node to Anchor failed"), - ); - } - } else { - AlertDialog( - title: Text("Error"), - content: Text("Adding Anchor failed"), - ); - } - } - } - - onPanStarted(String nodeName) { - print("Started panning node " + nodeName); - } - - onPanChanged(String nodeName) { - print("Continued panning node " + nodeName); - } - - onPanEnded(String nodeName, Matrix4 newTransform) { - print("Ended panning node " + nodeName); - final pannedNode = - this.nodes.firstWhere((element) => element.name == nodeName); - - /* - * Uncomment the following command if you want to keep the transformations of the Flutter representations of the nodes up to date - * (e.g. if you intend to share the nodes through the cloud) - */ - //pannedNode.transform = newTransform; - } - - onRotationStarted(String nodeName) { - print("Started rotating node " + nodeName); - } - - onRotationChanged(String nodeName) { - print("Continued rotating node " + nodeName); - } - - onRotationEnded(String nodeName, Matrix4 newTransform) { - print("Ended rotating node " + nodeName); - final rotatedNode = - this.nodes.firstWhere((element) => element.name == nodeName); - - /* - * Uncomment the following command if you want to keep the transformations of the Flutter representations of the nodes up to date - * (e.g. if you intend to share the nodes through the cloud) - */ - //rotatedNode.transform = newTransform; - } -} diff --git a/examples/objects_on_planes.dart b/examples/objects_on_planes.dart deleted file mode 100644 index 4b313252..00000000 --- a/examples/objects_on_planes.dart +++ /dev/null @@ -1,167 +0,0 @@ -// Automatic FlutterFlow imports -import '/flutter_flow/flutter_flow_theme.dart'; -import '/flutter_flow/flutter_flow_util.dart'; -import 'index.dart'; // Imports other custom widgets -import 'package:flutter/material.dart'; -// Begin custom widget code -// DO NOT REMOVE OR MODIFY THE CODE ABOVE! - -//AR Flutter Plugin -import 'package:ar_flutter_plugin_2/managers/ar_location_manager.dart'; -import 'package:ar_flutter_plugin_2/managers/ar_session_manager.dart'; -import 'package:ar_flutter_plugin_2/managers/ar_object_manager.dart'; -import 'package:ar_flutter_plugin_2/managers/ar_anchor_manager.dart'; -import 'package:ar_flutter_plugin_2/models/ar_anchor.dart'; -import 'package:ar_flutter_plugin_2/ar_flutter_plugin.dart'; -import 'package:ar_flutter_plugin_2/datatypes/config_planedetection.dart'; -import 'package:ar_flutter_plugin_2/datatypes/node_types.dart'; -import 'package:ar_flutter_plugin_2/datatypes/hittest_result_types.dart'; -import 'package:ar_flutter_plugin_2/models/ar_node.dart'; -import 'package:ar_flutter_plugin_2/models/ar_hittest_result.dart'; - -//Other custom imports -import 'package:flutter/services.dart'; -import 'package:vector_math/vector_math_64.dart'; -import 'dart:math'; - -class ObjectsOnPlanes extends StatefulWidget { - const ObjectsOnPlanes({ - super.key, - this.width, - this.height, - }); - - final double? width; - final double? height; - - @override - State createState() => _ObjectsOnPlanesState(); -} - -class _ObjectsOnPlanesState extends State { - ARSessionManager? arSessionManager; - ARObjectManager? arObjectManager; - ARAnchorManager? arAnchorManager; - - List nodes = []; - List anchors = []; - - @override - void dispose() { - super.dispose(); - arSessionManager!.dispose(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Anchors & Objects on Planes'), - ), - body: Container( - child: Stack(children: [ - ARView( - onARViewCreated: onARViewCreated, - planeDetectionConfig: PlaneDetectionConfig.horizontalAndVertical, - ), - Align( - alignment: FractionalOffset.bottomCenter, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - ElevatedButton( - onPressed: onRemoveEverything, - child: Text("Remove Everything")), - ]), - ) - ]))); - } - - void onARViewCreated( - ARSessionManager arSessionManager, - ARObjectManager arObjectManager, - ARAnchorManager arAnchorManager, - ARLocationManager arLocationManager) { - this.arSessionManager = arSessionManager; - this.arObjectManager = arObjectManager; - this.arAnchorManager = arAnchorManager; - - this.arSessionManager!.onInitialize( - showFeaturePoints: false, - showPlanes: true, - customPlaneTexturePath: "Images/triangle.png", - showWorldOrigin: true, - ); - this.arObjectManager!.onInitialize(); - - this.arSessionManager!.onPlaneOrPointTap = onPlaneOrPointTapped; - this.arObjectManager!.onNodeTap = onNodeTapped; - } - - Future onRemoveEverything() async { - /*nodes.forEach((node) { - this.arObjectManager.removeNode(node); - });*/ - anchors.forEach((anchor) { - this.arAnchorManager!.removeAnchor(anchor); - }); - anchors = []; - } - - Future onNodeTapped(List nodes) async { - var number = nodes.length; - AlertDialog( - title: Text("Information"), - content: Text("Tapped $number node(s)"), - ); - } - - Future onPlaneOrPointTapped( - List hitTestResults) async { - var singleHitTestResult = hitTestResults.firstWhere( - (hitTestResult) => hitTestResult.type == ARHitTestResultType.plane); - if (singleHitTestResult != null) { - var newAnchor = - ARPlaneAnchor(transformation: singleHitTestResult.worldTransform); - bool? didAddAnchor = await this.arAnchorManager!.addAnchor(newAnchor); - if (didAddAnchor!) { - this.anchors.add(newAnchor); - // Add note to anchor - var newNode = ARNode( - type: NodeType.webGLB, - uri: - "https://github.com/KhronosGroup/glTF-Sample-Models/raw/refs/heads/main/2.0/Duck/glTF-Binary/Duck.glb", - scale: Vector3(0.2, 0.2, 0.2), - position: Vector3(0.0, 0.0, 0.0), - rotation: Vector4(1.0, 0.0, 0.0, 0.0)); - bool? didAddNodeToAnchor = await this - .arObjectManager! - .addNode(newNode, planeAnchor: newAnchor); - if (didAddNodeToAnchor!) { - this.nodes.add(newNode); - } else { - AlertDialog( - title: Text("Error"), - content: Text("Adding Node to Anchor failed"), - ); - } - } else { - AlertDialog( - title: Text("Error"), - content: Text("Adding Anchor failed"), - ); - } - /* - // To add a node to the tapped position without creating an anchor, use the following code (Please mind: the function onRemoveEverything has to be adapted accordingly!): - var newNode = ARNode( - type: NodeType.localGLTF2, - uri: "Models/Chicken_01/Chicken_01.gltf", - scale: Vector3(0.2, 0.2, 0.2), - transformation: singleHitTestResult.worldTransform); - bool didAddWebNode = await this.arObjectManager.addNode(newNode); - if (didAddWebNode) { - this.nodes.add(newNode); - }*/ - } - } -} diff --git a/examples/screenshot.dart b/examples/screenshot.dart deleted file mode 100644 index 01301994..00000000 --- a/examples/screenshot.dart +++ /dev/null @@ -1,182 +0,0 @@ -// Automatic FlutterFlow imports -import '/flutter_flow/flutter_flow_theme.dart'; -import '/flutter_flow/flutter_flow_util.dart'; -import 'index.dart'; // Imports other custom widgets -import 'package:flutter/material.dart'; -// Begin custom widget code -// DO NOT REMOVE OR MODIFY THE CODE ABOVE! - -//AR Flutter Plugin -import 'package:ar_flutter_plugin_2/managers/ar_location_manager.dart'; -import 'package:ar_flutter_plugin_2/managers/ar_session_manager.dart'; -import 'package:ar_flutter_plugin_2/managers/ar_object_manager.dart'; -import 'package:ar_flutter_plugin_2/managers/ar_anchor_manager.dart'; -import 'package:ar_flutter_plugin_2/models/ar_anchor.dart'; -import 'package:ar_flutter_plugin_2/ar_flutter_plugin.dart'; -import 'package:ar_flutter_plugin_2/datatypes/config_planedetection.dart'; -import 'package:ar_flutter_plugin_2/datatypes/node_types.dart'; -import 'package:ar_flutter_plugin_2/datatypes/hittest_result_types.dart'; -import 'package:ar_flutter_plugin_2/models/ar_node.dart'; -import 'package:ar_flutter_plugin_2/models/ar_hittest_result.dart'; - -//Other custom imports -import 'package:vector_math/vector_math_64.dart'; - -class Screenshot extends StatefulWidget { - const Screenshot({ - super.key, - this.width, - this.height, - }); - - final double? width; - final double? height; - - @override - State createState() => _ScreenshotState(); -} - -class _ScreenshotState extends State { - ARSessionManager? arSessionManager; - ARObjectManager? arObjectManager; - ARAnchorManager? arAnchorManager; - - List nodes = []; - List anchors = []; - - @override - void dispose() { - super.dispose(); - arSessionManager!.dispose(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Screenshots'), - ), - body: Container( - child: Stack(children: [ - ARView( - onARViewCreated: onARViewCreated, - planeDetectionConfig: PlaneDetectionConfig.horizontalAndVertical, - ), - Align( - alignment: FractionalOffset.bottomCenter, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - ElevatedButton( - onPressed: onRemoveEverything, - child: const Text("Remove Everything")), - ElevatedButton( - onPressed: onTakeScreenshot, - child: const Text("Take Screenshot")), - ]), - ) - ]))); - } - - void onARViewCreated( - ARSessionManager arSessionManager, - ARObjectManager arObjectManager, - ARAnchorManager arAnchorManager, - ARLocationManager arLocationManager) { - this.arSessionManager = arSessionManager; - this.arObjectManager = arObjectManager; - this.arAnchorManager = arAnchorManager; - - this.arSessionManager!.onInitialize( - showFeaturePoints: false, - showPlanes: true, - customPlaneTexturePath: "Images/triangle.png", - showWorldOrigin: true, - ); - this.arObjectManager!.onInitialize(); - - this.arSessionManager!.onPlaneOrPointTap = onPlaneOrPointTapped; - this.arObjectManager!.onNodeTap = onNodeTapped; - } - - Future onRemoveEverything() async { - /*nodes.forEach((node) { - this.arObjectManager.removeNode(node); - });*/ - // anchors.forEach((anchor) - for (var anchor in anchors) { - arAnchorManager!.removeAnchor(anchor); - } - ; - anchors = []; - } - - Future onTakeScreenshot() async { - var image = await arSessionManager!.snapshot(); - await showDialog( - context: context, - builder: (_) => Dialog( - child: Container( - decoration: BoxDecoration( - image: DecorationImage(image: image, fit: BoxFit.cover)), - ), - )); - } - - Future onNodeTapped(List nodes) async { - var number = nodes.length; - AlertDialog( - title: Text("Information"), - content: Text("Tapped $number node(s)"), - ); - } - - Future onPlaneOrPointTapped( - List hitTestResults) async { - var singleHitTestResult = hitTestResults.firstWhere( - (hitTestResult) => hitTestResult.type == ARHitTestResultType.plane); - if (singleHitTestResult != null) { - var newAnchor = - ARPlaneAnchor(transformation: singleHitTestResult.worldTransform); - bool? didAddAnchor = await arAnchorManager!.addAnchor(newAnchor); - if (didAddAnchor != null && didAddAnchor) { - anchors.add(newAnchor); - // Add note to anchor - var newNode = ARNode( - type: NodeType.webGLB, - uri: - "https://github.com/KhronosGroup/glTF-Sample-Models/raw/refs/heads/main/2.0/Duck/glTF-Binary/Duck.glb", - scale: Vector3(0.2, 0.2, 0.2), - position: Vector3(0.0, 0.0, 0.0), - rotation: Vector4(1.0, 0.0, 0.0, 0.0)); - bool? didAddNodeToAnchor = - await arObjectManager!.addNode(newNode, planeAnchor: newAnchor); - - if (didAddNodeToAnchor != null && didAddNodeToAnchor) { - nodes.add(newNode); - } else { - AlertDialog( - title: Text("Error"), - content: Text("Adding Node to Anchor failed"), - ); - } - } else { - AlertDialog( - title: Text("Error"), - content: Text("Adding Anchor failed"), - ); - } - /* - // To add a node to the tapped position without creating an anchor, use the following code (Please mind: the function onRemoveEverything has to be adapted accordingly!): - var newNode = ARNode( - type: NodeType.localGLTF2, - uri: "Models/Chicken_01/Chicken_01.gltf", - scale: Vector3(0.2, 0.2, 0.2), - transformation: singleHitTestResult.worldTransform); - bool didAddWebNode = await this.arObjectManager.addNode(newNode); - if (didAddWebNode) { - this.nodes.add(newNode); - }*/ - } - } -}