refactor(mdtest examples): refactor mdtest file structure and add two
examples for mdtest

Restructure the original mdtest and split the mdtest driver api with the
mdtest_tools to make things more clear.  Add a examples folder that
contains a chat app and a shared-counter app where both apps can be
automated by mdtest.  After this refactoring, mdtest can be easily
published on pub.

Change-Id: Id256b86a47f97662c3786b291de949c1c8059d80
diff --git a/Makefile b/Makefile
index 7f7536b..cc369bc 100644
--- a/Makefile
+++ b/Makefile
@@ -29,24 +29,25 @@
 	@rm -rf deps/flutter
 
 .PHONY: packages
-packages: examples/todos/packages mdtest/packages
+packages: examples/todos/packages mdtest/dart-packages/mdtest_tools/packages
 
 examples/todos/packages: examples/todos/pubspec.yaml deps/flutter
 	cd examples/todos && pub get
 	@touch $@
 
-mdtest/packages: mdtest/pubspec.yaml deps/flutter
-	cd mdtest && pub get
+mdtest/dart-packages/mdtest_tools/packages: mdtest/dart-packages/mdtest_tools/pubspec.yaml deps/flutter
+	cd mdtest/dart-packages/mdtest_tools && pub get
 	@touch $@
 
 .PHONY: analyze
 analyze: deps/flutter packages
-	cd examples/todos/ && flutter analyze
+#	cd examples/todos/ && flutter analyze
+	@true
 
 .PHONY: test
 test: packages analyze deps/flutter
 	cd examples/todos/ && flutter test
-	cd mdtest && pub run test
+	cd mdtest/dart-packages/mdtest_tools && pub run test
 
 .PHONY: fmt
 fmt: packages deps/flutter
diff --git a/examples/todos/pubspec.lock b/examples/todos/pubspec.lock
index 8f098e5..c120c35 100644
--- a/examples/todos/pubspec.lock
+++ b/examples/todos/pubspec.lock
@@ -6,7 +6,7 @@
       name: analyzer
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.27.4-alpha.6"
+    version: "0.27.4-alpha.19"
   args:
     description:
       name: args
@@ -42,7 +42,7 @@
       name: collection
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.7.0"
+    version: "1.9.0"
   convert:
     description:
       name: convert
@@ -54,7 +54,7 @@
       name: crypto
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.9.2"
+    version: "2.0.1"
   csslib:
     description:
       name: csslib
@@ -115,6 +115,12 @@
       url: "https://pub.dartlang.org"
     source: hosted
     version: "0.12.7+1"
+  isolate:
+    description:
+      name: isolate
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.2.2"
   json_rpc_2:
     description:
       name: json_rpc_2
@@ -150,25 +156,25 @@
       name: mojo
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.4.20"
+    version: "0.4.27"
   mojo_sdk:
     description:
       name: mojo_sdk
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.2.24"
+    version: "0.2.31"
   mojo_services:
     description:
       name: mojo_services
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.4.27"
+    version: "0.4.34"
   package_config:
     description:
       name: package_config
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.1.3"
+    version: "0.1.5"
   path:
     description:
       name: path
@@ -276,7 +282,7 @@
       name: test
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.12.13+4"
+    version: "0.12.15+1"
   typed_data:
     description:
       name: typed_data
@@ -294,7 +300,7 @@
       name: uuid
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.5.0"
+    version: "0.5.3"
   vector_math:
     description:
       name: vector_math
@@ -318,11 +324,11 @@
       name: web_socket_channel
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.0.3"
+    version: "1.0.4"
   yaml:
     description:
       name: yaml
       url: "https://pub.dartlang.org"
     source: hosted
     version: "2.1.9"
-sdk: ">=1.16.0 <1.18.0"
+sdk: ">=1.16.0 <1.20.0"
diff --git a/examples/todos/pubspec.yaml b/examples/todos/pubspec.yaml
index 566407c..a0e41cb 100644
--- a/examples/todos/pubspec.yaml
+++ b/examples/todos/pubspec.yaml
@@ -1,7 +1,7 @@
 name: todos
 description: A Baku example project.
 dependencies:
-  uuid: 0.5.0
+  uuid: ^0.5.0
   flutter:
     path: ../../deps/flutter/packages/flutter
 dev_dependencies:
diff --git a/mdtest/bin/mdtest b/mdtest/bin/mdtest
index 574e1f4..71f01d2 100755
--- a/mdtest/bin/mdtest
+++ b/mdtest/bin/mdtest
@@ -20,11 +20,12 @@
 
 PROG_NAME="$(follow_links "$BASH_SOURCE")"
 BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
-export MDTEST_TOOL="$(cd "${BIN_DIR}/.." ; pwd -P)"
+export MDTEST_ROOT="$(cd "${BIN_DIR}/.." ; pwd -P)"
 
-SNAPSHOT_PATH="$MDTEST_TOOL/bin/cache/mdtest.snapshot"
-STAMP_PATH="$MDTEST_TOOL/bin/cache/mdtest.stamp"
-SCRIPT_PATH="$MDTEST_TOOL/bin/mdtest.dart"
+MDTEST_TOOLS_DIR="$MDTEST_ROOT/dart-packages/mdtest_tools"
+SNAPSHOT_PATH="$MDTEST_ROOT/bin/cache/mdtest.snapshot"
+STAMP_PATH="$MDTEST_ROOT/bin/cache/mdtest.stamp"
+SCRIPT_PATH="$MDTEST_TOOLS_DIR/bin/mdtest.dart"
 DART="$(which dart)"
 PUB="$(which pub)"
 
@@ -38,19 +39,19 @@
   exit 0
 fi
 
-mkdir -p "$MDTEST_TOOL/bin/cache"
+mkdir -p "$MDTEST_ROOT/bin/cache"
 
-REVISION=`(cd "$MDTEST_TOOL"; git rev-parse HEAD)`
-if [ ! -f "$SNAPSHOT_PATH" ] || [ ! -f "$STAMP_PATH" ] || [ `cat "$STAMP_PATH"` != "$REVISION" ] || [ "$MDTEST_TOOL/pubspec.yaml" -nt "$MDTEST_TOOL/pubspec.lock" ]; then
+REVISION=`(cd "$MDTEST_ROOT"; git rev-parse HEAD)`
+if [ ! -f "$SNAPSHOT_PATH" ] || [ ! -f "$STAMP_PATH" ] || [ `cat "$STAMP_PATH"` != "$REVISION" ] || [ "$MDTEST_TOOLS_DIR/pubspec.yaml" -nt "$MDTEST_TOOLS_DIR/pubspec.lock" ]; then
   echo Building mdtest ...
-  (cd "$MDTEST_TOOL"; "$PUB" get --verbosity=warning)
-  "$DART" --snapshot="$SNAPSHOT_PATH" --packages="$MDTEST_TOOL/.packages" "$SCRIPT_PATH"
+  (cd "$MDTEST_TOOLS_DIR"; "$PUB" get --verbosity=warning)
+  "$DART" --snapshot="$SNAPSHOT_PATH" --packages="$MDTEST_TOOLS_DIR/.packages" "$SCRIPT_PATH"
   echo $REVISION > "$STAMP_PATH"
   echo Build Success
 fi
 
 if [ $MDTEST_DEV ]; then
-  "$DART" --packages="$MDTEST_TOOL/.packages" -c "$SCRIPT_PATH" "$@"
+  "$DART" --packages="$MDTEST_TOOLS_DIR/.packages" -c "$SCRIPT_PATH" "$@"
 else
   set +e
   "$DART" "$SNAPSHOT_PATH" "$@"
@@ -61,6 +62,6 @@
   fi
 
   set -e
-  "$DART" --snapshot="$SNAPSHOT_PATH" --package="$MDTEST_TOOL/.package" "$SCRIPT_PATH"
+  "$DART" --snapshot="$SNAPSHOT_PATH" --package="$MDTEST_TOOLS_DIR/.package" "$SCRIPT_PATH"
   "$DART" "$SNAPSHOT_PATH" "$@"
 fi
diff --git a/mdtest/lib/driver_util.dart b/mdtest/dart-packages/mdtest_api/lib/driver_util.dart
similarity index 84%
rename from mdtest/lib/driver_util.dart
rename to mdtest/dart-packages/mdtest_api/lib/driver_util.dart
index c53c0b6..dc9e55e 100644
--- a/mdtest/lib/driver_util.dart
+++ b/mdtest/dart-packages/mdtest_api/lib/driver_util.dart
@@ -3,4 +3,4 @@
 // license that can be found in the LICENSE file.
 library driver_util;
 
-export 'src/api/driver_map.dart';
+export 'src/driver_map.dart';
diff --git a/mdtest/lib/driver_util.dart b/mdtest/dart-packages/mdtest_api/lib/src/common.dart
similarity index 74%
copy from mdtest/lib/driver_util.dart
copy to mdtest/dart-packages/mdtest_api/lib/src/common.dart
index c53c0b6..84dfc97 100644
--- a/mdtest/lib/driver_util.dart
+++ b/mdtest/dart-packages/mdtest_api/lib/src/common.dart
@@ -1,6 +1,5 @@
 // Copyright 2016 The Vanadium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
-library driver_util;
 
-export 'src/api/driver_map.dart';
+const String defaultTempSpecsName = 'tmp.spec';
diff --git a/mdtest/lib/src/api/driver_map.dart b/mdtest/dart-packages/mdtest_api/lib/src/driver_map.dart
similarity index 98%
rename from mdtest/lib/src/api/driver_map.dart
rename to mdtest/dart-packages/mdtest_api/lib/src/driver_map.dart
index 08e1de0..5378e6d 100644
--- a/mdtest/lib/src/api/driver_map.dart
+++ b/mdtest/dart-packages/mdtest_api/lib/src/driver_map.dart
@@ -9,7 +9,7 @@
 
 import 'package:flutter_driver/flutter_driver.dart';
 
-import '../base/common.dart';
+import 'common.dart';
 
 /// Singleton pattern is used to load config data only once.
 class Meta {
diff --git a/mdtest/dart-packages/mdtest_api/pubspec.yaml b/mdtest/dart-packages/mdtest_api/pubspec.yaml
new file mode 100644
index 0000000..36fae65
--- /dev/null
+++ b/mdtest/dart-packages/mdtest_api/pubspec.yaml
@@ -0,0 +1,6 @@
+name: mdtest_api
+description: mdtest API that helps write test scripts for multi-device applications
+
+dependencies:
+  flutter_driver:
+    path: ../../../deps/flutter/packages/flutter_driver
diff --git a/mdtest/bin/mdtest.dart b/mdtest/dart-packages/mdtest_tools/bin/mdtest.dart
similarity index 78%
rename from mdtest/bin/mdtest.dart
rename to mdtest/dart-packages/mdtest_tools/bin/mdtest.dart
index ad43745..0859ee6 100644
--- a/mdtest/bin/mdtest.dart
+++ b/mdtest/dart-packages/mdtest_tools/bin/mdtest.dart
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-import 'package:mdtest/executable.dart' as executable;
+import 'package:mdtest_tools/executable.dart' as executable;
 
 void main(List<String> args) {
   executable.main(args);
diff --git a/mdtest/lib/assets/emerald.png b/mdtest/dart-packages/mdtest_tools/lib/assets/emerald.png
similarity index 100%
rename from mdtest/lib/assets/emerald.png
rename to mdtest/dart-packages/mdtest_tools/lib/assets/emerald.png
Binary files differ
diff --git a/mdtest/lib/assets/report.css b/mdtest/dart-packages/mdtest_tools/lib/assets/report.css
similarity index 100%
rename from mdtest/lib/assets/report.css
rename to mdtest/dart-packages/mdtest_tools/lib/assets/report.css
diff --git a/mdtest/lib/assets/ruby.png b/mdtest/dart-packages/mdtest_tools/lib/assets/ruby.png
similarity index 100%
rename from mdtest/lib/assets/ruby.png
rename to mdtest/dart-packages/mdtest_tools/lib/assets/ruby.png
Binary files differ
diff --git a/mdtest/lib/executable.dart b/mdtest/dart-packages/mdtest_tools/lib/executable.dart
similarity index 100%
rename from mdtest/lib/executable.dart
rename to mdtest/dart-packages/mdtest_tools/lib/executable.dart
diff --git a/mdtest/lib/src/algorithms/coverage.dart b/mdtest/dart-packages/mdtest_tools/lib/src/algorithms/coverage.dart
similarity index 100%
rename from mdtest/lib/src/algorithms/coverage.dart
rename to mdtest/dart-packages/mdtest_tools/lib/src/algorithms/coverage.dart
diff --git a/mdtest/lib/src/algorithms/matching.dart b/mdtest/dart-packages/mdtest_tools/lib/src/algorithms/matching.dart
similarity index 100%
rename from mdtest/lib/src/algorithms/matching.dart
rename to mdtest/dart-packages/mdtest_tools/lib/src/algorithms/matching.dart
diff --git a/mdtest/lib/src/base/common.dart b/mdtest/dart-packages/mdtest_tools/lib/src/base/common.dart
similarity index 100%
rename from mdtest/lib/src/base/common.dart
rename to mdtest/dart-packages/mdtest_tools/lib/src/base/common.dart
diff --git a/mdtest/lib/src/base/logger.dart b/mdtest/dart-packages/mdtest_tools/lib/src/base/logger.dart
similarity index 100%
rename from mdtest/lib/src/base/logger.dart
rename to mdtest/dart-packages/mdtest_tools/lib/src/base/logger.dart
diff --git a/mdtest/lib/src/commands/auto.dart b/mdtest/dart-packages/mdtest_tools/lib/src/commands/auto.dart
similarity index 100%
rename from mdtest/lib/src/commands/auto.dart
rename to mdtest/dart-packages/mdtest_tools/lib/src/commands/auto.dart
diff --git a/mdtest/lib/src/commands/create.dart b/mdtest/dart-packages/mdtest_tools/lib/src/commands/create.dart
similarity index 100%
rename from mdtest/lib/src/commands/create.dart
rename to mdtest/dart-packages/mdtest_tools/lib/src/commands/create.dart
diff --git a/mdtest/lib/src/commands/doctor.dart b/mdtest/dart-packages/mdtest_tools/lib/src/commands/doctor.dart
similarity index 100%
rename from mdtest/lib/src/commands/doctor.dart
rename to mdtest/dart-packages/mdtest_tools/lib/src/commands/doctor.dart
diff --git a/mdtest/lib/src/commands/generate.dart b/mdtest/dart-packages/mdtest_tools/lib/src/commands/generate.dart
similarity index 100%
rename from mdtest/lib/src/commands/generate.dart
rename to mdtest/dart-packages/mdtest_tools/lib/src/commands/generate.dart
diff --git a/mdtest/lib/src/commands/helper.dart b/mdtest/dart-packages/mdtest_tools/lib/src/commands/helper.dart
similarity index 100%
rename from mdtest/lib/src/commands/helper.dart
rename to mdtest/dart-packages/mdtest_tools/lib/src/commands/helper.dart
diff --git a/mdtest/lib/src/commands/run.dart b/mdtest/dart-packages/mdtest_tools/lib/src/commands/run.dart
similarity index 100%
rename from mdtest/lib/src/commands/run.dart
rename to mdtest/dart-packages/mdtest_tools/lib/src/commands/run.dart
diff --git a/mdtest/lib/src/globals.dart b/mdtest/dart-packages/mdtest_tools/lib/src/globals.dart
similarity index 100%
rename from mdtest/lib/src/globals.dart
rename to mdtest/dart-packages/mdtest_tools/lib/src/globals.dart
diff --git a/mdtest/lib/src/mobile/android.dart b/mdtest/dart-packages/mdtest_tools/lib/src/mobile/android.dart
similarity index 100%
rename from mdtest/lib/src/mobile/android.dart
rename to mdtest/dart-packages/mdtest_tools/lib/src/mobile/android.dart
diff --git a/mdtest/lib/src/mobile/device.dart b/mdtest/dart-packages/mdtest_tools/lib/src/mobile/device.dart
similarity index 100%
rename from mdtest/lib/src/mobile/device.dart
rename to mdtest/dart-packages/mdtest_tools/lib/src/mobile/device.dart
diff --git a/mdtest/lib/src/mobile/device_spec.dart b/mdtest/dart-packages/mdtest_tools/lib/src/mobile/device_spec.dart
similarity index 100%
rename from mdtest/lib/src/mobile/device_spec.dart
rename to mdtest/dart-packages/mdtest_tools/lib/src/mobile/device_spec.dart
diff --git a/mdtest/lib/src/mobile/ios.dart b/mdtest/dart-packages/mdtest_tools/lib/src/mobile/ios.dart
similarity index 100%
rename from mdtest/lib/src/mobile/ios.dart
rename to mdtest/dart-packages/mdtest_tools/lib/src/mobile/ios.dart
diff --git a/mdtest/lib/src/mobile/key_provider.dart b/mdtest/dart-packages/mdtest_tools/lib/src/mobile/key_provider.dart
similarity index 100%
rename from mdtest/lib/src/mobile/key_provider.dart
rename to mdtest/dart-packages/mdtest_tools/lib/src/mobile/key_provider.dart
diff --git a/mdtest/lib/src/report/coverage_report.dart b/mdtest/dart-packages/mdtest_tools/lib/src/report/coverage_report.dart
similarity index 100%
rename from mdtest/lib/src/report/coverage_report.dart
rename to mdtest/dart-packages/mdtest_tools/lib/src/report/coverage_report.dart
diff --git a/mdtest/dart-packages/mdtest_tools/lib/src/report/locator.dart b/mdtest/dart-packages/mdtest_tools/lib/src/report/locator.dart
new file mode 100644
index 0000000..cbbb181
--- /dev/null
+++ b/mdtest/dart-packages/mdtest_tools/lib/src/report/locator.dart
@@ -0,0 +1,22 @@
+// Copyright 2016 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import '../util.dart';
+
+// Provide paths which point to the assets directory
+String mdtestScriptPath = Platform.script.toFilePath();
+int mdtestStart = mdtestScriptPath.lastIndexOf('/mdtest/');
+String mdtestRootPath = mdtestScriptPath.substring(0, mdtestStart);
+String assetsPath = normalizePath(
+  mdtestRootPath,
+  'mdtest/dart-packages/mdtest_tools/lib/assets'
+);
+
+List<String> get assetItemPaths => <String>[
+  normalizePath(assetsPath, 'emerald.png'),
+  normalizePath(assetsPath, 'ruby.png'),
+  normalizePath(assetsPath, 'report.css')
+];
diff --git a/mdtest/lib/src/report/report.dart b/mdtest/dart-packages/mdtest_tools/lib/src/report/report.dart
similarity index 100%
rename from mdtest/lib/src/report/report.dart
rename to mdtest/dart-packages/mdtest_tools/lib/src/report/report.dart
diff --git a/mdtest/lib/src/report/test_report.dart b/mdtest/dart-packages/mdtest_tools/lib/src/report/test_report.dart
similarity index 99%
rename from mdtest/lib/src/report/test_report.dart
rename to mdtest/dart-packages/mdtest_tools/lib/src/report/test_report.dart
index 9a3a43d..6377c81 100644
--- a/mdtest/lib/src/report/test_report.dart
+++ b/mdtest/dart-packages/mdtest_tools/lib/src/report/test_report.dart
@@ -54,7 +54,7 @@
       normalizePath(outputDirectory.path, 'index.html')
     );
     indexHTML.writeAsStringSync(toHTML());
-    relatedPaths.forEach(
+    assetItemPaths.forEach(
       (String imagePath) => copyPathToDirectory(imagePath, outputDirectory.path)
     );
   }
diff --git a/mdtest/lib/src/runner/mdtest_command.dart b/mdtest/dart-packages/mdtest_tools/lib/src/runner/mdtest_command.dart
similarity index 100%
rename from mdtest/lib/src/runner/mdtest_command.dart
rename to mdtest/dart-packages/mdtest_tools/lib/src/runner/mdtest_command.dart
diff --git a/mdtest/lib/src/runner/mdtest_command_runner.dart b/mdtest/dart-packages/mdtest_tools/lib/src/runner/mdtest_command_runner.dart
similarity index 100%
rename from mdtest/lib/src/runner/mdtest_command_runner.dart
rename to mdtest/dart-packages/mdtest_tools/lib/src/runner/mdtest_command_runner.dart
diff --git a/mdtest/lib/src/test/coverage_collector.dart b/mdtest/dart-packages/mdtest_tools/lib/src/test/coverage_collector.dart
similarity index 100%
rename from mdtest/lib/src/test/coverage_collector.dart
rename to mdtest/dart-packages/mdtest_tools/lib/src/test/coverage_collector.dart
diff --git a/mdtest/lib/src/test/reporter.dart b/mdtest/dart-packages/mdtest_tools/lib/src/test/reporter.dart
similarity index 100%
rename from mdtest/lib/src/test/reporter.dart
rename to mdtest/dart-packages/mdtest_tools/lib/src/test/reporter.dart
diff --git a/mdtest/lib/src/test/test_result.dart b/mdtest/dart-packages/mdtest_tools/lib/src/test/test_result.dart
similarity index 100%
rename from mdtest/lib/src/test/test_result.dart
rename to mdtest/dart-packages/mdtest_tools/lib/src/test/test_result.dart
diff --git a/mdtest/lib/src/util.dart b/mdtest/dart-packages/mdtest_tools/lib/src/util.dart
similarity index 100%
rename from mdtest/lib/src/util.dart
rename to mdtest/dart-packages/mdtest_tools/lib/src/util.dart
diff --git a/mdtest/pubspec.yaml b/mdtest/dart-packages/mdtest_tools/pubspec.yaml
similarity index 76%
rename from mdtest/pubspec.yaml
rename to mdtest/dart-packages/mdtest_tools/pubspec.yaml
index 6f1340c..83517d2 100644
--- a/mdtest/pubspec.yaml
+++ b/mdtest/dart-packages/mdtest_tools/pubspec.yaml
@@ -1,4 +1,4 @@
-name: mdtest
+name: mdtest_tools
 description: A multi-device app testing framework for Android and iOS
 
 dependencies:
@@ -9,8 +9,6 @@
   intl: ">=0.12.4+2"
   pub_semver: 1.3.0
   dlog: ^0.0.5
-  flutter_driver:
-    path: ../deps/flutter/packages/flutter_driver
 dev_dependencies:
    test: ^0.12.13
    mockito: 1.0.0
diff --git a/mdtest/test/coverage_test.dart b/mdtest/dart-packages/mdtest_tools/test/coverage_test.dart
similarity index 97%
rename from mdtest/test/coverage_test.dart
rename to mdtest/dart-packages/mdtest_tools/test/coverage_test.dart
index 974fd18..c1764a7 100644
--- a/mdtest/test/coverage_test.dart
+++ b/mdtest/dart-packages/mdtest_tools/test/coverage_test.dart
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-import 'package:mdtest/src/mobile/device_spec.dart';
-import 'package:mdtest/src/mobile/device.dart';
-import 'package:mdtest/src/mobile/key_provider.dart';
-import 'package:mdtest/src/algorithms/coverage.dart';
-import 'package:mdtest/src/algorithms/matching.dart';
+import 'package:mdtest_tools/src/mobile/device_spec.dart';
+import 'package:mdtest_tools/src/mobile/device.dart';
+import 'package:mdtest_tools/src/mobile/key_provider.dart';
+import 'package:mdtest_tools/src/algorithms/coverage.dart';
+import 'package:mdtest_tools/src/algorithms/matching.dart';
 
 import 'package:test/test.dart';
 import 'package:mockito/mockito.dart';
diff --git a/mdtest/test/device_spec_test.dart b/mdtest/dart-packages/mdtest_tools/test/device_spec_test.dart
similarity index 96%
rename from mdtest/test/device_spec_test.dart
rename to mdtest/dart-packages/mdtest_tools/test/device_spec_test.dart
index 1fa1016..3207e07 100644
--- a/mdtest/test/device_spec_test.dart
+++ b/mdtest/dart-packages/mdtest_tools/test/device_spec_test.dart
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-import 'package:mdtest/src/mobile/device_spec.dart';
-import 'package:mdtest/src/mobile/device.dart';
+import 'package:mdtest_tools/src/mobile/device_spec.dart';
+import 'package:mdtest_tools/src/mobile/device.dart';
 
 import 'package:test/test.dart';
 
diff --git a/mdtest/test/group_test.dart b/mdtest/dart-packages/mdtest_tools/test/group_test.dart
similarity index 97%
rename from mdtest/test/group_test.dart
rename to mdtest/dart-packages/mdtest_tools/test/group_test.dart
index d7347cd..c95458c 100644
--- a/mdtest/test/group_test.dart
+++ b/mdtest/dart-packages/mdtest_tools/test/group_test.dart
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-import 'package:mdtest/src/mobile/device_spec.dart';
-import 'package:mdtest/src/mobile/device.dart';
-import 'package:mdtest/src/mobile/key_provider.dart';
+import 'package:mdtest_tools/src/mobile/device_spec.dart';
+import 'package:mdtest_tools/src/mobile/device.dart';
+import 'package:mdtest_tools/src/mobile/key_provider.dart';
 
 import 'package:test/test.dart';
 
diff --git a/mdtest/test/matching_test.dart b/mdtest/dart-packages/mdtest_tools/test/matching_test.dart
similarity index 98%
rename from mdtest/test/matching_test.dart
rename to mdtest/dart-packages/mdtest_tools/test/matching_test.dart
index 7f00acc..e3088e0 100644
--- a/mdtest/test/matching_test.dart
+++ b/mdtest/dart-packages/mdtest_tools/test/matching_test.dart
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-import 'package:mdtest/src/mobile/device_spec.dart';
-import 'package:mdtest/src/mobile/device.dart';
-import 'package:mdtest/src/algorithms/matching.dart';
+import 'package:mdtest_tools/src/mobile/device_spec.dart';
+import 'package:mdtest_tools/src/mobile/device.dart';
+import 'package:mdtest_tools/src/algorithms/matching.dart';
 
 import 'package:test/test.dart';
 
diff --git a/mdtest/test/src/mocks.dart b/mdtest/dart-packages/mdtest_tools/test/src/mocks.dart
similarity index 81%
rename from mdtest/test/src/mocks.dart
rename to mdtest/dart-packages/mdtest_tools/test/src/mocks.dart
index 2db8a4c..058bb0f 100644
--- a/mdtest/test/src/mocks.dart
+++ b/mdtest/dart-packages/mdtest_tools/test/src/mocks.dart
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-import 'package:mdtest/src/algorithms/coverage.dart';
+import 'package:mdtest_tools/src/algorithms/coverage.dart';
 import 'package:mockito/mockito.dart';
 
 class MockCoverageMatrix extends Mock implements CoverageMatrix {
diff --git a/mdtest/examples/chat/README.md b/mdtest/examples/chat/README.md
new file mode 100644
index 0000000..5c256e9
--- /dev/null
+++ b/mdtest/examples/chat/README.md
@@ -0,0 +1,40 @@
+Assume your current directory is the chat folder.  To run `mdtest` for this chat
+app, first plugin two Android/iOS devices and just run
+
+```
+mdtest auto --format tap \
+            --coverage \
+            --save-report-data chat-test-report.json \
+            --groupby os-version \
+            --spec mdtest/chat.spec \
+            mdtest/chat_test.dart
+```
+
+The above command tells `mdtest` to run in auto mode, print test output in TAP
+format, collect coverage information, save report data to chat-test-report.json,
+group all devices by their OS version, use the test spec located at
+mdtest/chat.spec and run the test script mdtest/chat_test.dart.
+
+The above command will produce the coverage information in
+coverage/cov_auto_01.lcov, you can generate the code coverage report by running
+
+```
+mdtest generate --report-type coverage \
+                --load-report-data coverage/cov_auto_01.lcov \
+                --lib lib \
+                --output coverage_report
+```
+
+and mdtest will invoke lcov to generate a coverage report under coverage_report
+folder.
+
+To generate a test report, you can run
+
+```
+mdtest generate --report-type test \
+                --load-report-data chat-test-report.json \
+                --output test_report
+```
+
+and mdtest will generate the test report using the data in chat-test-report.json
+and write the HTML report under test_report folder.
diff --git a/mdtest/examples/chat/android/AndroidManifest.xml b/mdtest/examples/chat/android/AndroidManifest.xml
new file mode 100644
index 0000000..aa24b61
--- /dev/null
+++ b/mdtest/examples/chat/android/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.google.chat"
+    android:versionCode="1"
+    android:versionName="0.0.1">
+
+    <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="21" />
+    <uses-permission android:name="android.permission.INTERNET"/>
+
+    <application android:name="org.domokit.sky.shell.SkyApplication" android:label="chat" android:icon="@mipmap/ic_launcher">
+        <activity android:name="org.domokit.sky.shell.SkyActivity"
+                  android:launchMode="singleTop"
+                  android:theme="@android:style/Theme.Black.NoTitleBar"
+                  android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection"
+                  android:hardwareAccelerated="true"
+                  android:windowSoftInputMode="adjustResize">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/mdtest/examples/chat/android/res/mipmap-hdpi/ic_launcher.png b/mdtest/examples/chat/android/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..f0a55cd
--- /dev/null
+++ b/mdtest/examples/chat/android/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/mdtest/examples/chat/android/res/mipmap-mdpi/ic_launcher.png b/mdtest/examples/chat/android/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..eb98dc4
--- /dev/null
+++ b/mdtest/examples/chat/android/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/mdtest/examples/chat/android/res/mipmap-xhdpi/ic_launcher.png b/mdtest/examples/chat/android/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..f1783db
--- /dev/null
+++ b/mdtest/examples/chat/android/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/mdtest/examples/chat/android/res/mipmap-xxhdpi/ic_launcher.png b/mdtest/examples/chat/android/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..46828a2
--- /dev/null
+++ b/mdtest/examples/chat/android/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/mdtest/examples/chat/android/res/mipmap-xxxhdpi/ic_launcher.png b/mdtest/examples/chat/android/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..a527671
--- /dev/null
+++ b/mdtest/examples/chat/android/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/mdtest/examples/chat/flutter.yaml b/mdtest/examples/chat/flutter.yaml
new file mode 100644
index 0000000..71c460c
--- /dev/null
+++ b/mdtest/examples/chat/flutter.yaml
@@ -0,0 +1,2 @@
+name: chat
+uses-material-design: true
diff --git a/mdtest/examples/chat/ios/.gitignore b/mdtest/examples/chat/ios/.gitignore
new file mode 100644
index 0000000..fc39465
--- /dev/null
+++ b/mdtest/examples/chat/ios/.gitignore
@@ -0,0 +1,38 @@
+.idea/
+.vagrant/
+.sconsign.dblite
+.svn/
+
+.DS_Store
+*.swp
+*.lock
+profile
+
+DerivedData/
+build/
+
+*.pbxuser
+*.mode1v3
+*.mode2v3
+*.perspectivev3
+
+!default.pbxuser
+!default.mode1v3
+!default.mode2v3
+!default.perspectivev3
+
+xcuserdata
+
+*.moved-aside
+
+*.pyc
+*sync/
+Icon?
+.tags*
+
+/Flutter/app.flx
+/Flutter/app.dylib
+/Flutter/app.zip
+/Flutter/Flutter.framework
+/Flutter/Generated.xcconfig
+/ServiceDefinitions.json
diff --git a/mdtest/examples/chat/ios/Flutter/Flutter.xcconfig b/mdtest/examples/chat/ios/Flutter/Flutter.xcconfig
new file mode 100644
index 0000000..592ceee
--- /dev/null
+++ b/mdtest/examples/chat/ios/Flutter/Flutter.xcconfig
@@ -0,0 +1 @@
+#include "Generated.xcconfig"
diff --git a/mdtest/examples/chat/ios/Runner.xcodeproj/project.pbxproj b/mdtest/examples/chat/ios/Runner.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..391f2ab
--- /dev/null
+++ b/mdtest/examples/chat/ios/Runner.xcodeproj/project.pbxproj
@@ -0,0 +1,394 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 46;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		9705A1C51CF9049000538489 /* app.dylib in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEB81CF902C7004384FC /* app.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
+		9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
+		9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+		9740EEB41CF90195004384FC /* Flutter.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Flutter.xcconfig */; };
+		9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB31CF90195004384FC /* Generated.xcconfig */; };
+		9740EEBB1CF902C7004384FC /* app.flx in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB71CF902C7004384FC /* app.flx */; };
+		978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
+		97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
+		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 */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+		9705A1C41CF9048500538489 /* Embed Frameworks */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 2147483647;
+			dstPath = "";
+			dstSubfolderSpec = 10;
+			files = (
+				9705A1C51CF9049000538489 /* app.dylib in Embed Frameworks */,
+				9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
+			);
+			name = "Embed Frameworks";
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+		7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
+		7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
+		9740EEB21CF90195004384FC /* Flutter.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Flutter.xcconfig; path = Flutter/Flutter.xcconfig; sourceTree = "<group>"; };
+		9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
+		9740EEB71CF902C7004384FC /* app.flx */ = {isa = PBXFileReference; lastKnownFileType = file; name = app.flx; path = Flutter/app.flx; sourceTree = "<group>"; };
+		9740EEB81CF902C7004384FC /* app.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = app.dylib; path = Flutter/app.dylib; sourceTree = "<group>"; };
+		9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = "<group>"; };
+		97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
+		97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+		97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
+		97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
+		97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
+		97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		97C146EB1CF9000F007C117D /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		9740EEB11CF90186004384FC /* Flutter */ = {
+			isa = PBXGroup;
+			children = (
+				9740EEB71CF902C7004384FC /* app.flx */,
+				9740EEB81CF902C7004384FC /* app.dylib */,
+				9740EEBA1CF902C7004384FC /* Flutter.framework */,
+				9740EEB21CF90195004384FC /* Flutter.xcconfig */,
+				9740EEB31CF90195004384FC /* Generated.xcconfig */,
+			);
+			name = Flutter;
+			sourceTree = "<group>";
+		};
+		97C146E51CF9000F007C117D = {
+			isa = PBXGroup;
+			children = (
+				9740EEB11CF90186004384FC /* Flutter */,
+				97C146F01CF9000F007C117D /* Runner */,
+				97C146EF1CF9000F007C117D /* Products */,
+			);
+			sourceTree = "<group>";
+		};
+		97C146EF1CF9000F007C117D /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				97C146EE1CF9000F007C117D /* Runner.app */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		97C146F01CF9000F007C117D /* Runner */ = {
+			isa = PBXGroup;
+			children = (
+				7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */,
+				7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */,
+				97C146FA1CF9000F007C117D /* Main.storyboard */,
+				97C146FD1CF9000F007C117D /* Assets.xcassets */,
+				97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
+				97C147021CF9000F007C117D /* Info.plist */,
+				97C146F11CF9000F007C117D /* Supporting Files */,
+			);
+			path = Runner;
+			sourceTree = "<group>";
+		};
+		97C146F11CF9000F007C117D /* Supporting Files */ = {
+			isa = PBXGroup;
+			children = (
+				97C146F21CF9000F007C117D /* main.m */,
+			);
+			name = "Supporting Files";
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+		97C146ED1CF9000F007C117D /* Runner */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
+			buildPhases = (
+				9740EEB61CF901F6004384FC /* ShellScript */,
+				97C146EA1CF9000F007C117D /* Sources */,
+				97C146EB1CF9000F007C117D /* Frameworks */,
+				97C146EC1CF9000F007C117D /* Resources */,
+				9705A1C41CF9048500538489 /* Embed Frameworks */,
+			);
+			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 = {
+				LastUpgradeCheck = 0730;
+				ORGANIZATIONNAME = "The Chromium Authors";
+				TargetAttributes = {
+					97C146ED1CF9000F007C117D = {
+						CreatedOnToolsVersion = 7.3.1;
+						DevelopmentTeam = MM2NW8A7DV;
+					};
+				};
+			};
+			buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
+			compatibilityVersion = "Xcode 3.2";
+			developmentRegion = English;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+				Base,
+			);
+			mainGroup = 97C146E51CF9000F007C117D;
+			productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				97C146ED1CF9000F007C117D /* Runner */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+		97C146EC1CF9000F007C117D /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				9740EEBB1CF902C7004384FC /* app.flx in Resources */,
+				97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
+				9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */,
+				9740EEB41CF90195004384FC /* Flutter.xcconfig in Resources */,
+				97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
+				97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+		9740EEB61CF901F6004384FC /* ShellScript */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "/bin/sh $FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh";
+		};
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+		97C146EA1CF9000F007C117D /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */,
+				97C146F31CF9000F007C117D /* main.m in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+		97C146FA1CF9000F007C117D /* Main.storyboard */ = {
+			isa = PBXVariantGroup;
+			children = (
+				97C146FB1CF9000F007C117D /* Base */,
+			);
+			name = Main.storyboard;
+			sourceTree = "<group>";
+		};
+		97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
+			isa = PBXVariantGroup;
+			children = (
+				97C147001CF9000F007C117D /* Base */,
+			);
+			name = LaunchScreen.storyboard;
+			sourceTree = "<group>";
+		};
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+		97C147031CF9000F007C117D /* Debug */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 9740EEB21CF90195004384FC /* Flutter.xcconfig */;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				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_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				CODE_SIGN_IDENTITY = "iPhone Developer: Google Development (3F4Y5873JF)";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				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 = 9.3;
+				MTL_ENABLE_DEBUG_INFO = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				SDKROOT = iphoneos;
+				TARGETED_DEVICE_FAMILY = "1,2";
+			};
+			name = Debug;
+		};
+		97C147041CF9000F007C117D /* Release */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 9740EEB21CF90195004384FC /* Flutter.xcconfig */;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				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_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				CODE_SIGN_IDENTITY = "iPhone Developer: Google Development (3F4Y5873JF)";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				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 = 9.3;
+				MTL_ENABLE_DEBUG_INFO = NO;
+				SDKROOT = iphoneos;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VALIDATE_PRODUCT = YES;
+			};
+			name = Release;
+		};
+		97C147061CF9000F007C117D /* Debug */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 9740EEB21CF90195004384FC /* Flutter.xcconfig */;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				ENABLE_BITCODE = NO;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Flutter",
+				);
+				INFOPLIST_FILE = Runner/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Flutter",
+				);
+				PRODUCT_BUNDLE_IDENTIFIER = com.google.chat;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				PROVISIONING_PROFILE = "";
+			};
+			name = Debug;
+		};
+		97C147071CF9000F007C117D /* Release */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 9740EEB21CF90195004384FC /* Flutter.xcconfig */;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				ENABLE_BITCODE = NO;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Flutter",
+				);
+				INFOPLIST_FILE = Runner/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Flutter",
+				);
+				PRODUCT_BUNDLE_IDENTIFIER = com.google.chat;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				PROVISIONING_PROFILE = "";
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				97C147031CF9000F007C117D /* Debug */,
+				97C147041CF9000F007C117D /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				97C147061CF9000F007C117D /* Debug */,
+				97C147071CF9000F007C117D /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = 97C146E61CF9000F007C117D /* Project object */;
+}
diff --git a/mdtest/examples/chat/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/mdtest/examples/chat/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..6cec59c
--- /dev/null
+++ b/mdtest/examples/chat/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+   version = "1.0">
+   <FileRef
+      location = "self:Runner.xcodeproj">
+   </FileRef>
+</Workspace>
diff --git a/mdtest/examples/chat/ios/Runner/AppDelegate.h b/mdtest/examples/chat/ios/Runner/AppDelegate.h
new file mode 100644
index 0000000..8ef937e
--- /dev/null
+++ b/mdtest/examples/chat/ios/Runner/AppDelegate.h
@@ -0,0 +1,11 @@
+// Copyright 2016 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#import <UIKit/UIKit.h>
+
+@interface AppDelegate : UIResponder <UIApplicationDelegate>
+
+@property (strong, nonatomic) UIWindow *window;
+
+@end
diff --git a/mdtest/examples/chat/ios/Runner/AppDelegate.m b/mdtest/examples/chat/ios/Runner/AppDelegate.m
new file mode 100644
index 0000000..d4cfa3a
--- /dev/null
+++ b/mdtest/examples/chat/ios/Runner/AppDelegate.m
@@ -0,0 +1,33 @@
+#import <Flutter/Flutter.h>
+#include "AppDelegate.h"
+
+@implementation AppDelegate
+
+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+    // Override point for customization after application launch.
+    return YES;
+}
+
+- (void)applicationWillResignActive:(UIApplication *)application {
+    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
+    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
+}
+
+- (void)applicationDidEnterBackground:(UIApplication *)application {
+    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
+    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
+}
+
+- (void)applicationWillEnterForeground:(UIApplication *)application {
+    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
+}
+
+- (void)applicationDidBecomeActive:(UIApplication *)application {
+    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
+}
+
+- (void)applicationWillTerminate:(UIApplication *)application {
+    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
+}
+
+@end
diff --git a/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000..363d1c4
--- /dev/null
+++ b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,142 @@
+{
+  "images" : [
+    {
+      "size" : "29x29",
+      "idiom" : "iphone",
+      "filename" : "Icon-Small@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "iphone",
+      "filename" : "Icon-Small@3x.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "iphone",
+      "filename" : "Icon-Small-40@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "iphone",
+      "filename" : "Icon-Small-40@3x.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "60x60",
+      "idiom" : "iphone",
+      "filename" : "Icon-60@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "60x60",
+      "idiom" : "iphone",
+      "filename" : "Icon-60@3x.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "ipad",
+      "filename" : "Icon-Small.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "ipad",
+      "filename" : "Icon-Small@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "ipad",
+      "filename" : "Icon-Small-40.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "ipad",
+      "filename" : "Icon-Small-40@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "76x76",
+      "idiom" : "ipad",
+      "filename" : "Icon-76.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "76x76",
+      "idiom" : "ipad",
+      "filename" : "Icon-76@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "83.5x83.5",
+      "idiom" : "ipad",
+      "filename" : "Icon-83.5@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "16x16",
+      "idiom" : "mac",
+      "filename" : "icon_16x16.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "16x16",
+      "idiom" : "mac",
+      "filename" : "icon_16x16@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "32x32",
+      "idiom" : "mac",
+      "filename" : "icon_32x32.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "32x32",
+      "idiom" : "mac",
+      "filename" : "icon_32x32@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "128x128",
+      "idiom" : "mac",
+      "filename" : "icon_128x128.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "128x128",
+      "idiom" : "mac",
+      "filename" : "icon_128x128@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "256x256",
+      "idiom" : "mac",
+      "filename" : "icon_256x256.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "256x256",
+      "idiom" : "mac",
+      "filename" : "icon_256x256@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "512x512",
+      "idiom" : "mac",
+      "filename" : "icon_512x512.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "512x512",
+      "idiom" : "mac",
+      "filename" : "icon_512x512@2x.png",
+      "scale" : "2x"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png
new file mode 100644
index 0000000..9996f5e
--- /dev/null
+++ b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png
Binary files differ
diff --git a/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png
new file mode 100644
index 0000000..7a543ed
--- /dev/null
+++ b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png
Binary files differ
diff --git a/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-76.png b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-76.png
new file mode 100644
index 0000000..05a8268
--- /dev/null
+++ b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-76.png
Binary files differ
diff --git a/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png
new file mode 100644
index 0000000..bfbca28
--- /dev/null
+++ b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png
Binary files differ
diff --git a/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png
new file mode 100644
index 0000000..c924b8e
--- /dev/null
+++ b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png
Binary files differ
diff --git a/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small-40.png b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small-40.png
new file mode 100644
index 0000000..3006f1d
--- /dev/null
+++ b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small-40.png
Binary files differ
diff --git a/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png
new file mode 100644
index 0000000..5f7d22d
--- /dev/null
+++ b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png
Binary files differ
diff --git a/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png
new file mode 100644
index 0000000..9996f5e
--- /dev/null
+++ b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png
Binary files differ
diff --git a/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small.png b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small.png
new file mode 100644
index 0000000..3433da1
--- /dev/null
+++ b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small.png
Binary files differ
diff --git a/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png
new file mode 100644
index 0000000..f7f9f16
--- /dev/null
+++ b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png
Binary files differ
diff --git a/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png
new file mode 100644
index 0000000..e9c2360
--- /dev/null
+++ b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png
Binary files differ
diff --git a/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_128x128.png b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_128x128.png
new file mode 100644
index 0000000..dd5fccb
--- /dev/null
+++ b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_128x128.png
Binary files differ
diff --git a/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png
new file mode 100644
index 0000000..1909e27
--- /dev/null
+++ b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png
Binary files differ
diff --git a/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_16x16.png b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_16x16.png
new file mode 100644
index 0000000..40a701b
--- /dev/null
+++ b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_16x16.png
Binary files differ
diff --git a/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png
new file mode 100644
index 0000000..06c1a80
--- /dev/null
+++ b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png
Binary files differ
diff --git a/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_256x256.png b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_256x256.png
new file mode 100644
index 0000000..1909e27
--- /dev/null
+++ b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_256x256.png
Binary files differ
diff --git a/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png
new file mode 100644
index 0000000..69c96ef
--- /dev/null
+++ b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png
Binary files differ
diff --git a/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_32x32.png b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_32x32.png
new file mode 100644
index 0000000..06c1a80
--- /dev/null
+++ b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_32x32.png
Binary files differ
diff --git a/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png
new file mode 100644
index 0000000..0f94371
--- /dev/null
+++ b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png
Binary files differ
diff --git a/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_512x512.png b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_512x512.png
new file mode 100644
index 0000000..69c96ef
--- /dev/null
+++ b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_512x512.png
Binary files differ
diff --git a/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png
new file mode 100644
index 0000000..1d6355f
--- /dev/null
+++ b/mdtest/examples/chat/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png
Binary files differ
diff --git a/mdtest/examples/chat/ios/Runner/Base.lproj/LaunchScreen.storyboard b/mdtest/examples/chat/ios/Runner/Base.lproj/LaunchScreen.storyboard
new file mode 100644
index 0000000..ebf48f6
--- /dev/null
+++ b/mdtest/examples/chat/ios/Runner/Base.lproj/LaunchScreen.storyboard
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" initialViewController="01J-lp-oVM">
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
+    </dependencies>
+    <scenes>
+        <!--View Controller-->
+        <scene sceneID="EHf-IW-A2E">
+            <objects>
+                <viewController id="01J-lp-oVM" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
+                        <viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
+                        <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+                    </view>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="53" y="375"/>
+        </scene>
+    </scenes>
+</document>
diff --git a/mdtest/examples/chat/ios/Runner/Base.lproj/Main.storyboard b/mdtest/examples/chat/ios/Runner/Base.lproj/Main.storyboard
new file mode 100644
index 0000000..f3c2851
--- /dev/null
+++ b/mdtest/examples/chat/ios/Runner/Base.lproj/Main.storyboard
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
+    </dependencies>
+    <scenes>
+        <!--Flutter View Controller-->
+        <scene sceneID="tne-QT-ifu">
+            <objects>
+                <viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
+                        <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
+                        <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+                    </view>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
+            </objects>
+        </scene>
+    </scenes>
+</document>
diff --git a/mdtest/examples/chat/ios/Runner/Info.plist b/mdtest/examples/chat/ios/Runner/Info.plist
new file mode 100644
index 0000000..f964916
--- /dev/null
+++ b/mdtest/examples/chat/ios/Runner/Info.plist
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>en</string>
+	<key>CFBundleExecutable</key>
+	<string>$(EXECUTABLE_NAME)</string>
+	<key>CFBundleIdentifier</key>
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>chat</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>1.0</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>1</string>
+	<key>LSRequiresIPhoneOS</key>
+	<true/>
+	<key>NSAppTransportSecurity</key>
+	<dict>
+		<key>NSAllowsArbitraryLoads</key>
+		<true/>
+	</dict>
+	<key>UILaunchStoryboardName</key>
+	<string>LaunchScreen</string>
+	<key>UIMainStoryboardFile</key>
+	<string>Main</string>
+	<key>UIRequiredDeviceCapabilities</key>
+	<array>
+		<string>arm64</string>
+	</array>
+	<key>UISupportedInterfaceOrientations</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+		<string>UIInterfaceOrientationLandscapeLeft</string>
+		<string>UIInterfaceOrientationLandscapeRight</string>
+	</array>
+	<key>UISupportedInterfaceOrientations~ipad</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+		<string>UIInterfaceOrientationPortraitUpsideDown</string>
+		<string>UIInterfaceOrientationLandscapeLeft</string>
+		<string>UIInterfaceOrientationLandscapeRight</string>
+	</array>
+	<key>UIViewControllerBasedStatusBarAppearance</key>
+	<false/>
+</dict>
+</plist>
diff --git a/mdtest/examples/chat/ios/Runner/main.m b/mdtest/examples/chat/ios/Runner/main.m
new file mode 100644
index 0000000..7e0fe2c
--- /dev/null
+++ b/mdtest/examples/chat/ios/Runner/main.m
@@ -0,0 +1,11 @@
+#import <UIKit/UIKit.h>
+#import <Flutter/Flutter.h>
+#import "AppDelegate.h"
+
+int main(int argc, char * argv[]) {
+    FlutterInit(argc, (const char**)argv);
+    @autoreleasepool {
+        return UIApplicationMain(argc, argv, nil,
+                                 NSStringFromClass([AppDelegate class]));
+    }
+}
diff --git a/mdtest/lib/driver_util.dart b/mdtest/examples/chat/lib/keys.dart
similarity index 72%
copy from mdtest/lib/driver_util.dart
copy to mdtest/examples/chat/lib/keys.dart
index c53c0b6..6ca95aa 100644
--- a/mdtest/lib/driver_util.dart
+++ b/mdtest/examples/chat/lib/keys.dart
@@ -1,6 +1,6 @@
 // Copyright 2016 The Vanadium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
-library driver_util;
 
-export 'src/api/driver_map.dart';
+String inputKey = 'inputKey';
+String buttonKey = 'buttonKey';
diff --git a/mdtest/examples/chat/lib/main.dart b/mdtest/examples/chat/lib/main.dart
new file mode 100644
index 0000000..5bc9445
--- /dev/null
+++ b/mdtest/examples/chat/lib/main.dart
@@ -0,0 +1,322 @@
+// Copyright 2016 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:convert';
+
+import 'package:flutter/material.dart';
+import 'package:flutter/http.dart' as http;
+
+import 'keys.dart';
+
+const String setMessageUrl = 'http://baku-flutter-chat.appspot.com/set_message';
+const String getHistoryUrl = 'http://baku-flutter-chat.appspot.com/get_history';
+
+String myname;
+int myColor;
+
+void start(String name, int color) {
+  myname = name;
+  myColor = color;
+  runApp(
+    new MaterialApp(
+      title: 'Chat Demo',
+      theme: new ThemeData(
+        primarySwatch: Colors.primaries[myColor],
+        accentColor: Colors.orangeAccent[400]
+      ),
+      home: new ChatScreen()
+    )
+  );
+}
+
+class ChatScreen extends StatefulWidget {
+  ChatScreen({ Key key }) : super(key: key);
+
+  @override
+  State createState() => new ChatScreenState();
+}
+
+class ChatScreenState extends State<ChatScreen> {
+  String _name = myname;
+  InputValue _currentMessage = InputValue.empty;
+  bool get _isComposing => _currentMessage.text.isNotEmpty;
+
+  int _color = myColor;
+  List<ChatMessage> _messages = <ChatMessage>[];
+
+  @override
+  void initState() {
+    super.initState();
+    listenToHistory();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return new Scaffold(
+      appBar: new AppBar(
+        title: new Text('Chatting as $_name')
+      ),
+      body: new Column(
+        children: <Widget>[
+          new Flexible(
+            child: new Block(
+              padding: new EdgeInsets.symmetric(horizontal: 8.0),
+              scrollAnchor: ViewportAnchor.end,
+              children: _messages.map((m) => new ChatMessageListItem(m)).toList()
+            )
+          ),
+          _buildTextComposer()
+        ]
+      )
+    );
+  }
+
+  Widget _buildTextComposer() {
+    ThemeData themeData = Theme.of(context);
+    return new Row(
+      children: <Widget>[
+        new Flexible(
+          child: new Input(
+            key: new ValueKey(inputKey),
+            value: _currentMessage,
+            hintText: 'Enter message',
+            onSubmitted: _handleMessageAdded,
+            onChanged: _handleMessageChanged
+          )
+        ),
+        new Container(
+          margin: new EdgeInsets.symmetric(horizontal: 4.0),
+          child: new IconButton(
+            key: new ValueKey(buttonKey),
+            icon: new Icon(Icons.send),
+            onPressed: _isComposing ? () => _handleMessageAdded(_currentMessage) : null,
+            color: themeData.accentColor
+          )
+        )
+      ]
+    );
+  }
+
+  Future<Null> listenToHistory() async {
+    while (true) {
+      getMessages();
+      await new Future<Null>.delayed(new Duration(milliseconds: 500));
+    }
+  }
+
+  void postMessage(ChatMessage message) {
+    ChatUser user = message.sender;
+    Map<String, String> headers = {
+      'Content-type': 'application/json',
+      'Accept': 'application/json'
+    };
+    Map<String, String> body = <String, String>{
+      'user': user.name,
+      'color': '${user.color}',
+      'text': message.text
+    };
+
+    http.post(
+      setMessageUrl,
+      headers: headers,
+      body: JSON.encode(body)
+    ).then((http.Response response) {
+      String json = response.body;
+      if (json == null) {
+        print('Fail to post $message to $setMessageUrl');
+        return;
+      }
+      JsonDecoder decoder = new JsonDecoder();
+      dynamic result = decoder.convert(json);
+      print('Response: ${result["answer"]}');
+    });
+  }
+
+  void getMessages() {
+    http.get(getHistoryUrl).then((http.Response response) {
+      String json = response.body;
+      if (json == null) {
+        print('Fail to get message history from $getHistoryUrl');
+        return;
+      }
+      JsonDecoder decoder = new JsonDecoder();
+      dynamic result = decoder.convert(json);
+      List<ChatMessage> history = new List.from(
+        result['history'].map(
+          (message) {
+            return new ChatMessage(
+              sender: new ChatUser(
+                name: message['user'],
+                color: int.parse(message['color'])
+              ),
+              text: message['text'],
+              animationController: new AnimationController(
+                duration: new Duration(milliseconds: 700)
+              )
+            );
+          }
+        )
+      );
+      if (_messages.length > history.length) {
+        print('Local messages size is greater than the remote messages size!');
+        setState(() {
+          _messages.clear();
+        });
+      }
+      if (_messages.length == history.length) {
+        return;
+      }
+      for (int i = _messages.length; i < history.length; i++) {
+        setState(() {
+          _messages.add(history[i]);
+        });
+        history[i].animationController.forward();
+      }
+    });
+  }
+
+  void _addMessage({ String name, int color, String text }) {
+    AnimationController animationController = new AnimationController(
+      duration: new Duration(milliseconds: 700)
+    );
+    ChatUser sender = new ChatUser(name: name, color: color);
+    ChatMessage message = new ChatMessage(
+      sender: sender,
+      text: text,
+      animationController: animationController
+    );
+    postMessage(message);
+  }
+
+  void _handleMessageChanged(InputValue value) {
+    setState(() {
+      _currentMessage = value;
+    });
+  }
+
+  void _handleMessageAdded(InputValue value) {
+    setState(() {
+      _currentMessage = InputValue.empty;
+    });
+    _addMessage(name: _name, color: _color, text: value.text);
+  }
+
+  @override
+  void dispose() {
+    for (ChatMessage message in _messages) {
+      message.animationController.dispose();
+    }
+    super.dispose();
+  }
+}
+
+class ChatMessageListItem extends StatelessWidget {
+  ChatMessageListItem(this.message);
+  final ChatMessage message;
+
+  Widget build(BuildContext context) {
+    ListItem item;
+    if (message.sender.name == myname) {
+      item = new ListItem(
+        dense: true,
+        trailing: new CircleAvatar(
+          child: new Text(message.sender.name[0]),
+          backgroundColor: Colors.accents[message.sender.color][700]
+        ),
+        title: new Align(
+          alignment: FractionalOffset.centerRight,
+          child: new Text(
+            message.sender.name,
+            textAlign: TextAlign.center
+          )
+        ),
+        subtitle: new Align(
+          alignment: FractionalOffset.centerRight,
+          child: new Text(
+            message.text,
+            textAlign: TextAlign.center
+          )
+        )
+      );
+    } else {
+      item = new ListItem(
+        dense: true,
+        leading: new CircleAvatar(
+          child: new Text(message.sender.name[0]),
+          backgroundColor: Colors.accents[message.sender.color][700]
+        ),
+        title: new Align(
+          alignment: FractionalOffset.centerLeft,
+          child: new Text(
+            message.sender.name,
+            textAlign: TextAlign.center
+          )
+        ),
+        subtitle: new Align(
+          alignment: FractionalOffset.centerLeft,
+          child: new Text(
+            message.text,
+            textAlign: TextAlign.center
+          )
+        )
+      );
+    }
+    return new SizeTransition(
+      sizeFactor: new CurvedAnimation(
+        parent: message.animationController,
+        curve: Curves.easeOut
+      ),
+      axisAlignment: 0.0,
+      child: item
+    );
+  }
+}
+
+class ChatUser {
+  ChatUser({ this.name, this.color });
+  final String name;
+  final int color;
+
+  @override
+  bool operator ==(other) {
+    if (other is! ChatUser) return false;
+    ChatUser user = other;
+    return user.name == name && user.color == color;
+  }
+
+  @override
+  int get hashCode {
+    return hashValues(name, color);
+  }
+
+  @override
+  String toString() {
+    return 'username: $name, color: $color';
+  }
+}
+
+class ChatMessage {
+  ChatMessage({ this.sender, this.text, this.animationController });
+  final ChatUser sender;
+  final String text;
+  final AnimationController animationController;
+
+  @override
+  bool operator ==(other) {
+    if (other is! ChatMessage) return false;
+    ChatMessage message = other;
+    return message.sender == sender && message.text == text;
+  }
+
+  @override
+  int get hashCode {
+    return hashValues(sender, text);
+  }
+
+  @override
+  String toString() {
+    return '<${sender.toString()}, text: $text>';
+  }
+}
diff --git a/mdtest/examples/chat/mdtest/chat.spec b/mdtest/examples/chat/mdtest/chat.spec
new file mode 100644
index 0000000..ba0fd1e
--- /dev/null
+++ b/mdtest/examples/chat/mdtest/chat.spec
@@ -0,0 +1,12 @@
+{
+  "devices": {
+    "Bot1": {
+      "app-root": "..",
+      "app-path": "test_driver/chat_alice.dart"
+    },
+    "Bot2": {
+      "app-root": "..",
+      "app-path": "test_driver/chat_bob.dart"
+    }
+  }
+}
diff --git a/mdtest/examples/chat/mdtest/chat_test.dart b/mdtest/examples/chat/mdtest/chat_test.dart
new file mode 100644
index 0000000..4b9e0c6
--- /dev/null
+++ b/mdtest/examples/chat/mdtest/chat_test.dart
@@ -0,0 +1,168 @@
+// Copyright 2016 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:flutter_driver/flutter_driver.dart';
+import 'package:test/test.dart';
+import 'package:mdtest_api/driver_util.dart';
+
+import '../lib/keys.dart';
+
+const String clearHistoryUrl = 'http://baku-flutter-chat.appspot.com/clear_history';
+
+Future<Null> clearChatHistory() async {
+  HttpClient client = new HttpClient();
+  HttpClientRequest request = await client.getUrl(Uri.parse(clearHistoryUrl));
+  await request.close();
+}
+
+int waitingTime = 2000;
+
+void main() {
+  group('Chat App Test 1', () {
+    DriverMap driverMap;
+
+    setUpAll(() async {
+      driverMap = new DriverMap();
+    });
+
+    setUp(() async {
+      await clearChatHistory();
+    });
+
+    tearDownAll(() async {
+      if (driverMap != null) {
+        driverMap.closeAll();
+      }
+    });
+
+    test('Greeting', () async {
+      FlutterDriver bot1 = await driverMap['Bot1'];
+      FlutterDriver bot2 = await driverMap['Bot2'];
+      String textToSend = 'Hi, my name is Steve.  It\'s nice to meet you.';
+      await new Future<Null>.delayed(new Duration(milliseconds: waitingTime));
+      await bot1.setInputText(find.byValueKey(inputKey), textToSend);
+      await new Future<Null>.delayed(new Duration(milliseconds: waitingTime));
+      await bot1.tap(find.byValueKey(buttonKey));
+      await new Future<Null>.delayed(new Duration(milliseconds: waitingTime));
+      String textBot1 = await bot1.getText(find.text(textToSend));
+      print('Bot 1: $textBot1');
+      String textBot2 = await bot2.getText(find.text(textToSend));
+      print('Bot 2: $textBot2');
+      expect(textBot1, equals(textBot2));
+
+      textToSend = 'I\'m Jack. It\'s a pleasure to meet you, Steve.';
+      await bot2.setInputText(find.byValueKey(inputKey), textToSend);
+      await new Future<Null>.delayed(new Duration(milliseconds: waitingTime));
+      await bot2.tap(find.byValueKey(buttonKey));
+      await new Future<Null>.delayed(new Duration(milliseconds: waitingTime));
+      textBot1 = await bot1.getText(find.text(textToSend));
+      print('Bot 1: $textBot1');
+      textBot2 = await bot2.getText(find.text(textToSend));
+      print('Bot 2: $textBot2');
+      expect(textBot1, equals(textBot2));
+
+      textToSend = 'What do you do for a living Jack?';
+      await new Future<Null>.delayed(new Duration(milliseconds: waitingTime));
+      await bot1.setInputText(find.byValueKey(inputKey), textToSend);
+      await new Future<Null>.delayed(new Duration(milliseconds: waitingTime));
+      await bot1.tap(find.byValueKey(buttonKey));
+      await new Future<Null>.delayed(new Duration(milliseconds: waitingTime));
+      textBot1 = await bot1.getText(find.text(textToSend));
+      print('Bot 1: $textBot1');
+      textBot2 = await bot2.getText(find.text(textToSend));
+      print('Bot 2: $textBot2');
+      expect(textBot1, equals(textBot2));
+
+      textToSend = 'I work at the bank.';
+      await bot2.setInputText(find.byValueKey(inputKey), textToSend);
+      await new Future<Null>.delayed(new Duration(milliseconds: waitingTime));
+      await bot2.tap(find.byValueKey(buttonKey));
+      await new Future<Null>.delayed(new Duration(milliseconds: waitingTime));
+      textBot1 = await bot1.getText(find.text(textToSend));
+      print('Bot 1: $textBot1');
+      textBot2 = await bot2.getText(find.text(textToSend));
+      print('Bot 2: $textBot2');
+      expect(textBot1, equals(textBot2));
+    }, timeout: new Timeout(new Duration(seconds: 60)));
+
+    test('Joking', () async {
+      FlutterDriver bot1 = await driverMap['Bot1'];
+      FlutterDriver bot2 = await driverMap['Bot2'];
+      String textToSend = 'Name some countries?';
+      await new Future<Null>.delayed(new Duration(milliseconds: waitingTime));
+      await bot2.setInputText(find.byValueKey(inputKey), textToSend);
+      await new Future<Null>.delayed(new Duration(milliseconds: waitingTime));
+      await bot2.tap(find.byValueKey(buttonKey));
+      await new Future<Null>.delayed(new Duration(milliseconds: waitingTime));
+      String textBot1 = await bot1.getText(find.text(textToSend));
+      print('Bot 1: $textBot1');
+      String textBot2 = await bot2.getText(find.text(textToSend));
+      print('Bot 2: $textBot2');
+      expect(textBot1, equals(textBot2));
+
+      textToSend = 'US.';
+      await new Future<Null>.delayed(new Duration(milliseconds: waitingTime));
+      await bot1.setInputText(find.byValueKey(inputKey), textToSend);
+      await new Future<Null>.delayed(new Duration(milliseconds: waitingTime));
+      await bot1.tap(find.byValueKey(buttonKey));
+      await new Future<Null>.delayed(new Duration(milliseconds: waitingTime));
+      textBot1 = await bot1.getText(find.text(textToSend));
+      print('Bot 1: $textBot1');
+      textBot2 = await bot2.getText(find.text(textToSend));
+      print('Bot 2: $textBot2');
+      expect(textBot1, equals(textBot2));
+
+      textToSend = 'That is it?';
+      await new Future<Null>.delayed(new Duration(milliseconds: waitingTime));
+      await bot2.setInputText(find.byValueKey(inputKey), textToSend);
+      await new Future<Null>.delayed(new Duration(milliseconds: waitingTime));
+      await bot2.tap(find.byValueKey(buttonKey));
+      await new Future<Null>.delayed(new Duration(milliseconds: waitingTime));
+      textBot1 = await bot1.getText(find.text(textToSend));
+      print('Bot 1: $textBot1');
+      textBot2 = await bot2.getText(find.text(textToSend));
+      print('Bot 2: $textBot2');
+      expect(textBot1, equals(textBot2));
+
+      textToSend = 'Yes.';
+      await new Future<Null>.delayed(new Duration(milliseconds: waitingTime));
+      await bot1.setInputText(find.byValueKey(inputKey), textToSend);
+      await new Future<Null>.delayed(new Duration(milliseconds: waitingTime));
+      await bot1.tap(find.byValueKey(buttonKey));
+      await new Future<Null>.delayed(new Duration(milliseconds: waitingTime));
+      textBot1 = await bot1.getText(find.text(textToSend));
+      print('Bot 1: $textBot1');
+      textBot2 = await bot2.getText(find.text(textToSend));
+      print('Bot 2: $textBot2');
+      expect(textBot1, equals(textBot2));
+
+      textToSend = 'Aren\'t UK, India, Singapore, Europe countries?';
+      await new Future<Null>.delayed(new Duration(milliseconds: waitingTime));
+      await bot2.setInputText(find.byValueKey(inputKey), textToSend);
+      await new Future<Null>.delayed(new Duration(milliseconds: waitingTime));
+      await bot2.tap(find.byValueKey(buttonKey));
+      await new Future<Null>.delayed(new Duration(milliseconds: waitingTime));
+      textBot1 = await bot1.getText(find.text(textToSend));
+      print('Bot 1: $textBot1');
+      textBot2 = await bot2.getText(find.text(textToSend));
+      print('Bot 2: $textBot2');
+      expect(textBot1, equals(textBot2));
+
+      textToSend = 'Nope, they are not countries, they are Foreign countries...';
+      await new Future<Null>.delayed(new Duration(milliseconds: waitingTime));
+      await bot1.setInputText(find.byValueKey(inputKey), textToSend);
+      await new Future<Null>.delayed(new Duration(milliseconds: waitingTime));
+      await bot1.tap(find.byValueKey(buttonKey));
+      await new Future<Null>.delayed(new Duration(milliseconds: waitingTime));
+      textBot1 = await bot1.getText(find.text(textToSend));
+      print('Bot 1: $textBot1');
+      textBot2 = await bot2.getText(find.text(textToSend));
+      print('Bot 2: $textBot2');
+      expect(textBot1, equals(textBot2));
+    }, timeout: new Timeout(new Duration(seconds: 60)));
+  });
+}
diff --git a/mdtest/examples/chat/pubspec.yaml b/mdtest/examples/chat/pubspec.yaml
new file mode 100644
index 0000000..17c7964
--- /dev/null
+++ b/mdtest/examples/chat/pubspec.yaml
@@ -0,0 +1,14 @@
+name: chat
+description: A new flutter project.
+dependencies:
+  flutter:
+    path: ../../../deps/flutter/packages/flutter
+  flutter_test:
+    path: ../../../deps/flutter/packages/flutter_test
+  flutter_driver:
+    path: ../../../deps/flutter/packages/flutter_driver
+  mdtest_api:
+    path: ../../dart-packages/mdtest_api
+
+dev_dependencies:
+  test: 0.12.15+1
diff --git a/mdtest/examples/chat/test_driver/chat_alice.dart b/mdtest/examples/chat/test_driver/chat_alice.dart
new file mode 100644
index 0000000..2d45499
--- /dev/null
+++ b/mdtest/examples/chat/test_driver/chat_alice.dart
@@ -0,0 +1,11 @@
+// Copyright 2016 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+import 'package:flutter_driver/driver_extension.dart';
+import 'package:chat/main.dart' as chatapp;
+
+void main() {
+  enableFlutterDriverExtension();
+  chatapp.start('Alice', 0);
+}
diff --git a/mdtest/examples/chat/test_driver/chat_bob.dart b/mdtest/examples/chat/test_driver/chat_bob.dart
new file mode 100644
index 0000000..b101a9e
--- /dev/null
+++ b/mdtest/examples/chat/test_driver/chat_bob.dart
@@ -0,0 +1,11 @@
+// Copyright 2016 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+import 'package:flutter_driver/driver_extension.dart';
+import 'package:chat/main.dart' as chatapp;
+
+void main() {
+  enableFlutterDriverExtension();
+  chatapp.start('Bob', 9);
+}
diff --git a/mdtest/examples/shared-counter/README.md b/mdtest/examples/shared-counter/README.md
new file mode 100644
index 0000000..f6070c8
--- /dev/null
+++ b/mdtest/examples/shared-counter/README.md
@@ -0,0 +1,30 @@
+Assume your current directory is the shared_counter_test folder.  To run
+`mdtest` for this shared-counter example, first plugin at least two Android/iOS devices and just run
+
+```
+mdtest run --brief \
+           --format none \
+           --coverage \
+           --spec shared_counter.spec \
+           shared_counter_test_1.dart shared_counter_test_2.dart
+```
+
+The above command tells `mdtest` to run in run mode, only spit out test result
+and print test output using the dart test default format, collect coverage
+information, use the test spec located at shared_counter.spec and run the test
+scripts shared_counter_test_1.dart and shared_counter_test_2.dart.
+
+The above command will produce the coverage information in both
+plus/coverage/cov_run_01.lcov and minus/coverage/cov_run_01.lcov, you can
+generate the code coverage report by running (assuming your current directory is
+either plus or minus folder)
+
+```
+mdtest generate --report-type coverage \
+                --load-report-data coverage/cov_run_01.lcov \
+                --lib lib \
+                --output coverage_report
+```
+
+and mdtest will invoke lcov to generate a coverage report under coverage_report
+folder.
diff --git a/mdtest/examples/shared-counter/minus/README.md b/mdtest/examples/shared-counter/minus/README.md
new file mode 100644
index 0000000..65ff3a1
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/README.md
@@ -0,0 +1,8 @@
+# minus
+
+A new flutter project.
+
+## Getting Started
+
+For help getting started with Flutter, view our online
+[documentation](http://flutter.io/).
diff --git a/mdtest/examples/shared-counter/minus/android/AndroidManifest.xml b/mdtest/examples/shared-counter/minus/android/AndroidManifest.xml
new file mode 100644
index 0000000..62bf41e
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/android/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.google.minus"
+    android:versionCode="1"
+    android:versionName="0.0.1">
+
+    <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="21" />
+    <uses-permission android:name="android.permission.INTERNET"/>
+
+    <application android:name="org.domokit.sky.shell.SkyApplication" android:label="minus" android:icon="@mipmap/ic_launcher">
+        <activity android:name="org.domokit.sky.shell.SkyActivity"
+                  android:launchMode="singleTop"
+                  android:theme="@android:style/Theme.Black.NoTitleBar"
+                  android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection"
+                  android:hardwareAccelerated="true"
+                  android:windowSoftInputMode="adjustResize">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/mdtest/examples/shared-counter/minus/android/res/mipmap-hdpi/ic_launcher.png b/mdtest/examples/shared-counter/minus/android/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..f0a55cd
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/android/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/minus/android/res/mipmap-mdpi/ic_launcher.png b/mdtest/examples/shared-counter/minus/android/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..eb98dc4
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/android/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/minus/android/res/mipmap-xhdpi/ic_launcher.png b/mdtest/examples/shared-counter/minus/android/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..f1783db
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/android/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/minus/android/res/mipmap-xxhdpi/ic_launcher.png b/mdtest/examples/shared-counter/minus/android/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..46828a2
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/android/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/minus/android/res/mipmap-xxxhdpi/ic_launcher.png b/mdtest/examples/shared-counter/minus/android/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..a527671
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/android/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/minus/flutter.yaml b/mdtest/examples/shared-counter/minus/flutter.yaml
new file mode 100644
index 0000000..d5a43a7
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/flutter.yaml
@@ -0,0 +1,2 @@
+name: minus
+uses-material-design: true
diff --git a/mdtest/examples/shared-counter/minus/ios/.gitignore b/mdtest/examples/shared-counter/minus/ios/.gitignore
new file mode 100644
index 0000000..fc39465
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/ios/.gitignore
@@ -0,0 +1,38 @@
+.idea/
+.vagrant/
+.sconsign.dblite
+.svn/
+
+.DS_Store
+*.swp
+*.lock
+profile
+
+DerivedData/
+build/
+
+*.pbxuser
+*.mode1v3
+*.mode2v3
+*.perspectivev3
+
+!default.pbxuser
+!default.mode1v3
+!default.mode2v3
+!default.perspectivev3
+
+xcuserdata
+
+*.moved-aside
+
+*.pyc
+*sync/
+Icon?
+.tags*
+
+/Flutter/app.flx
+/Flutter/app.dylib
+/Flutter/app.zip
+/Flutter/Flutter.framework
+/Flutter/Generated.xcconfig
+/ServiceDefinitions.json
diff --git a/mdtest/examples/shared-counter/minus/ios/Flutter/Flutter.xcconfig b/mdtest/examples/shared-counter/minus/ios/Flutter/Flutter.xcconfig
new file mode 100644
index 0000000..592ceee
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/ios/Flutter/Flutter.xcconfig
@@ -0,0 +1 @@
+#include "Generated.xcconfig"
diff --git a/mdtest/examples/shared-counter/minus/ios/Runner.xcodeproj/project.pbxproj b/mdtest/examples/shared-counter/minus/ios/Runner.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..3374b0a
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/ios/Runner.xcodeproj/project.pbxproj
@@ -0,0 +1,394 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 46;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		9705A1C51CF9049000538489 /* app.dylib in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEB81CF902C7004384FC /* app.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
+		9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
+		9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+		9740EEB41CF90195004384FC /* Flutter.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Flutter.xcconfig */; };
+		9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB31CF90195004384FC /* Generated.xcconfig */; };
+		9740EEBB1CF902C7004384FC /* app.flx in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB71CF902C7004384FC /* app.flx */; };
+		978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
+		97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
+		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 */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+		9705A1C41CF9048500538489 /* Embed Frameworks */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 2147483647;
+			dstPath = "";
+			dstSubfolderSpec = 10;
+			files = (
+				9705A1C51CF9049000538489 /* app.dylib in Embed Frameworks */,
+				9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
+			);
+			name = "Embed Frameworks";
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+		7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
+		7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
+		9740EEB21CF90195004384FC /* Flutter.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Flutter.xcconfig; path = Flutter/Flutter.xcconfig; sourceTree = "<group>"; };
+		9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
+		9740EEB71CF902C7004384FC /* app.flx */ = {isa = PBXFileReference; lastKnownFileType = file; name = app.flx; path = Flutter/app.flx; sourceTree = "<group>"; };
+		9740EEB81CF902C7004384FC /* app.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = app.dylib; path = Flutter/app.dylib; sourceTree = "<group>"; };
+		9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = "<group>"; };
+		97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
+		97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+		97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
+		97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
+		97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
+		97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		97C146EB1CF9000F007C117D /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		9740EEB11CF90186004384FC /* Flutter */ = {
+			isa = PBXGroup;
+			children = (
+				9740EEB71CF902C7004384FC /* app.flx */,
+				9740EEB81CF902C7004384FC /* app.dylib */,
+				9740EEBA1CF902C7004384FC /* Flutter.framework */,
+				9740EEB21CF90195004384FC /* Flutter.xcconfig */,
+				9740EEB31CF90195004384FC /* Generated.xcconfig */,
+			);
+			name = Flutter;
+			sourceTree = "<group>";
+		};
+		97C146E51CF9000F007C117D = {
+			isa = PBXGroup;
+			children = (
+				9740EEB11CF90186004384FC /* Flutter */,
+				97C146F01CF9000F007C117D /* Runner */,
+				97C146EF1CF9000F007C117D /* Products */,
+			);
+			sourceTree = "<group>";
+		};
+		97C146EF1CF9000F007C117D /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				97C146EE1CF9000F007C117D /* Runner.app */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		97C146F01CF9000F007C117D /* Runner */ = {
+			isa = PBXGroup;
+			children = (
+				7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */,
+				7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */,
+				97C146FA1CF9000F007C117D /* Main.storyboard */,
+				97C146FD1CF9000F007C117D /* Assets.xcassets */,
+				97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
+				97C147021CF9000F007C117D /* Info.plist */,
+				97C146F11CF9000F007C117D /* Supporting Files */,
+			);
+			path = Runner;
+			sourceTree = "<group>";
+		};
+		97C146F11CF9000F007C117D /* Supporting Files */ = {
+			isa = PBXGroup;
+			children = (
+				97C146F21CF9000F007C117D /* main.m */,
+			);
+			name = "Supporting Files";
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+		97C146ED1CF9000F007C117D /* Runner */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
+			buildPhases = (
+				9740EEB61CF901F6004384FC /* ShellScript */,
+				97C146EA1CF9000F007C117D /* Sources */,
+				97C146EB1CF9000F007C117D /* Frameworks */,
+				97C146EC1CF9000F007C117D /* Resources */,
+				9705A1C41CF9048500538489 /* Embed Frameworks */,
+			);
+			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 = {
+				LastUpgradeCheck = 0730;
+				ORGANIZATIONNAME = "The Chromium Authors";
+				TargetAttributes = {
+					97C146ED1CF9000F007C117D = {
+						CreatedOnToolsVersion = 7.3.1;
+						DevelopmentTeam = MM2NW8A7DV;
+					};
+				};
+			};
+			buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
+			compatibilityVersion = "Xcode 3.2";
+			developmentRegion = English;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+				Base,
+			);
+			mainGroup = 97C146E51CF9000F007C117D;
+			productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				97C146ED1CF9000F007C117D /* Runner */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+		97C146EC1CF9000F007C117D /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				9740EEBB1CF902C7004384FC /* app.flx in Resources */,
+				97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
+				9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */,
+				9740EEB41CF90195004384FC /* Flutter.xcconfig in Resources */,
+				97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
+				97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+		9740EEB61CF901F6004384FC /* ShellScript */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "/bin/sh $FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh";
+		};
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+		97C146EA1CF9000F007C117D /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */,
+				97C146F31CF9000F007C117D /* main.m in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+		97C146FA1CF9000F007C117D /* Main.storyboard */ = {
+			isa = PBXVariantGroup;
+			children = (
+				97C146FB1CF9000F007C117D /* Base */,
+			);
+			name = Main.storyboard;
+			sourceTree = "<group>";
+		};
+		97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
+			isa = PBXVariantGroup;
+			children = (
+				97C147001CF9000F007C117D /* Base */,
+			);
+			name = LaunchScreen.storyboard;
+			sourceTree = "<group>";
+		};
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+		97C147031CF9000F007C117D /* Debug */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 9740EEB21CF90195004384FC /* Flutter.xcconfig */;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				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_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				CODE_SIGN_IDENTITY = "iPhone Developer: Google Development (3F4Y5873JF)";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				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 = 9.3;
+				MTL_ENABLE_DEBUG_INFO = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				SDKROOT = iphoneos;
+				TARGETED_DEVICE_FAMILY = "1,2";
+			};
+			name = Debug;
+		};
+		97C147041CF9000F007C117D /* Release */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 9740EEB21CF90195004384FC /* Flutter.xcconfig */;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				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_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				CODE_SIGN_IDENTITY = "iPhone Developer: Google Development (3F4Y5873JF)";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				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 = 9.3;
+				MTL_ENABLE_DEBUG_INFO = NO;
+				SDKROOT = iphoneos;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VALIDATE_PRODUCT = YES;
+			};
+			name = Release;
+		};
+		97C147061CF9000F007C117D /* Debug */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 9740EEB21CF90195004384FC /* Flutter.xcconfig */;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				ENABLE_BITCODE = NO;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Flutter",
+				);
+				INFOPLIST_FILE = Runner/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Flutter",
+				);
+				PRODUCT_BUNDLE_IDENTIFIER = com.google.minus;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				PROVISIONING_PROFILE = "";
+			};
+			name = Debug;
+		};
+		97C147071CF9000F007C117D /* Release */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 9740EEB21CF90195004384FC /* Flutter.xcconfig */;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				ENABLE_BITCODE = NO;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Flutter",
+				);
+				INFOPLIST_FILE = Runner/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Flutter",
+				);
+				PRODUCT_BUNDLE_IDENTIFIER = com.google.minus;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				PROVISIONING_PROFILE = "";
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				97C147031CF9000F007C117D /* Debug */,
+				97C147041CF9000F007C117D /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				97C147061CF9000F007C117D /* Debug */,
+				97C147071CF9000F007C117D /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = 97C146E61CF9000F007C117D /* Project object */;
+}
diff --git a/mdtest/examples/shared-counter/minus/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/mdtest/examples/shared-counter/minus/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..6cec59c
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+   version = "1.0">
+   <FileRef
+      location = "self:Runner.xcodeproj">
+   </FileRef>
+</Workspace>
diff --git a/mdtest/examples/shared-counter/minus/ios/Runner/AppDelegate.h b/mdtest/examples/shared-counter/minus/ios/Runner/AppDelegate.h
new file mode 100644
index 0000000..8ef937e
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/ios/Runner/AppDelegate.h
@@ -0,0 +1,11 @@
+// Copyright 2016 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#import <UIKit/UIKit.h>
+
+@interface AppDelegate : UIResponder <UIApplicationDelegate>
+
+@property (strong, nonatomic) UIWindow *window;
+
+@end
diff --git a/mdtest/examples/shared-counter/minus/ios/Runner/AppDelegate.m b/mdtest/examples/shared-counter/minus/ios/Runner/AppDelegate.m
new file mode 100644
index 0000000..d4cfa3a
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/ios/Runner/AppDelegate.m
@@ -0,0 +1,33 @@
+#import <Flutter/Flutter.h>
+#include "AppDelegate.h"
+
+@implementation AppDelegate
+
+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+    // Override point for customization after application launch.
+    return YES;
+}
+
+- (void)applicationWillResignActive:(UIApplication *)application {
+    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
+    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
+}
+
+- (void)applicationDidEnterBackground:(UIApplication *)application {
+    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
+    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
+}
+
+- (void)applicationWillEnterForeground:(UIApplication *)application {
+    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
+}
+
+- (void)applicationDidBecomeActive:(UIApplication *)application {
+    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
+}
+
+- (void)applicationWillTerminate:(UIApplication *)application {
+    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
+}
+
+@end
diff --git a/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000..363d1c4
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,142 @@
+{
+  "images" : [
+    {
+      "size" : "29x29",
+      "idiom" : "iphone",
+      "filename" : "Icon-Small@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "iphone",
+      "filename" : "Icon-Small@3x.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "iphone",
+      "filename" : "Icon-Small-40@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "iphone",
+      "filename" : "Icon-Small-40@3x.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "60x60",
+      "idiom" : "iphone",
+      "filename" : "Icon-60@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "60x60",
+      "idiom" : "iphone",
+      "filename" : "Icon-60@3x.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "ipad",
+      "filename" : "Icon-Small.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "ipad",
+      "filename" : "Icon-Small@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "ipad",
+      "filename" : "Icon-Small-40.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "ipad",
+      "filename" : "Icon-Small-40@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "76x76",
+      "idiom" : "ipad",
+      "filename" : "Icon-76.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "76x76",
+      "idiom" : "ipad",
+      "filename" : "Icon-76@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "83.5x83.5",
+      "idiom" : "ipad",
+      "filename" : "Icon-83.5@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "16x16",
+      "idiom" : "mac",
+      "filename" : "icon_16x16.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "16x16",
+      "idiom" : "mac",
+      "filename" : "icon_16x16@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "32x32",
+      "idiom" : "mac",
+      "filename" : "icon_32x32.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "32x32",
+      "idiom" : "mac",
+      "filename" : "icon_32x32@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "128x128",
+      "idiom" : "mac",
+      "filename" : "icon_128x128.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "128x128",
+      "idiom" : "mac",
+      "filename" : "icon_128x128@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "256x256",
+      "idiom" : "mac",
+      "filename" : "icon_256x256.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "256x256",
+      "idiom" : "mac",
+      "filename" : "icon_256x256@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "512x512",
+      "idiom" : "mac",
+      "filename" : "icon_512x512.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "512x512",
+      "idiom" : "mac",
+      "filename" : "icon_512x512@2x.png",
+      "scale" : "2x"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png
new file mode 100644
index 0000000..9996f5e
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png
new file mode 100644
index 0000000..7a543ed
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-76.png b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-76.png
new file mode 100644
index 0000000..05a8268
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-76.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png
new file mode 100644
index 0000000..bfbca28
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png
new file mode 100644
index 0000000..c924b8e
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small-40.png b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small-40.png
new file mode 100644
index 0000000..3006f1d
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small-40.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png
new file mode 100644
index 0000000..5f7d22d
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png
new file mode 100644
index 0000000..9996f5e
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small.png b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small.png
new file mode 100644
index 0000000..3433da1
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png
new file mode 100644
index 0000000..f7f9f16
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png
new file mode 100644
index 0000000..e9c2360
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_128x128.png b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_128x128.png
new file mode 100644
index 0000000..dd5fccb
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_128x128.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png
new file mode 100644
index 0000000..1909e27
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_16x16.png b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_16x16.png
new file mode 100644
index 0000000..40a701b
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_16x16.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png
new file mode 100644
index 0000000..06c1a80
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_256x256.png b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_256x256.png
new file mode 100644
index 0000000..1909e27
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_256x256.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png
new file mode 100644
index 0000000..69c96ef
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_32x32.png b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_32x32.png
new file mode 100644
index 0000000..06c1a80
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_32x32.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png
new file mode 100644
index 0000000..0f94371
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_512x512.png b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_512x512.png
new file mode 100644
index 0000000..69c96ef
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_512x512.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png
new file mode 100644
index 0000000..1d6355f
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/minus/ios/Runner/Base.lproj/LaunchScreen.storyboard b/mdtest/examples/shared-counter/minus/ios/Runner/Base.lproj/LaunchScreen.storyboard
new file mode 100644
index 0000000..ebf48f6
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/ios/Runner/Base.lproj/LaunchScreen.storyboard
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" initialViewController="01J-lp-oVM">
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
+    </dependencies>
+    <scenes>
+        <!--View Controller-->
+        <scene sceneID="EHf-IW-A2E">
+            <objects>
+                <viewController id="01J-lp-oVM" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
+                        <viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
+                        <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+                    </view>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="53" y="375"/>
+        </scene>
+    </scenes>
+</document>
diff --git a/mdtest/examples/shared-counter/minus/ios/Runner/Base.lproj/Main.storyboard b/mdtest/examples/shared-counter/minus/ios/Runner/Base.lproj/Main.storyboard
new file mode 100644
index 0000000..f3c2851
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/ios/Runner/Base.lproj/Main.storyboard
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
+    </dependencies>
+    <scenes>
+        <!--Flutter View Controller-->
+        <scene sceneID="tne-QT-ifu">
+            <objects>
+                <viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
+                        <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
+                        <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+                    </view>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
+            </objects>
+        </scene>
+    </scenes>
+</document>
diff --git a/mdtest/examples/shared-counter/minus/ios/Runner/Info.plist b/mdtest/examples/shared-counter/minus/ios/Runner/Info.plist
new file mode 100644
index 0000000..e27f192
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/ios/Runner/Info.plist
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>en</string>
+	<key>CFBundleExecutable</key>
+	<string>$(EXECUTABLE_NAME)</string>
+	<key>CFBundleIdentifier</key>
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>minus</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>1.0</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>1</string>
+	<key>LSRequiresIPhoneOS</key>
+	<true/>
+	<key>UILaunchStoryboardName</key>
+	<string>LaunchScreen</string>
+	<key>UIMainStoryboardFile</key>
+	<string>Main</string>
+	<key>UIRequiredDeviceCapabilities</key>
+	<array>
+		<string>arm64</string>
+	</array>
+	<key>UISupportedInterfaceOrientations</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+		<string>UIInterfaceOrientationLandscapeLeft</string>
+		<string>UIInterfaceOrientationLandscapeRight</string>
+	</array>
+	<key>UISupportedInterfaceOrientations~ipad</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+		<string>UIInterfaceOrientationPortraitUpsideDown</string>
+		<string>UIInterfaceOrientationLandscapeLeft</string>
+		<string>UIInterfaceOrientationLandscapeRight</string>
+	</array>
+	<key>UIViewControllerBasedStatusBarAppearance</key>
+	<false/>
+</dict>
+</plist>
diff --git a/mdtest/examples/shared-counter/minus/ios/Runner/main.m b/mdtest/examples/shared-counter/minus/ios/Runner/main.m
new file mode 100644
index 0000000..7e0fe2c
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/ios/Runner/main.m
@@ -0,0 +1,11 @@
+#import <UIKit/UIKit.h>
+#import <Flutter/Flutter.h>
+#import "AppDelegate.h"
+
+int main(int argc, char * argv[]) {
+    FlutterInit(argc, (const char**)argv);
+    @autoreleasepool {
+        return UIApplicationMain(argc, argv, nil,
+                                 NSStringFromClass([AppDelegate class]));
+    }
+}
diff --git a/mdtest/lib/driver_util.dart b/mdtest/examples/shared-counter/minus/lib/keys.dart
similarity index 74%
copy from mdtest/lib/driver_util.dart
copy to mdtest/examples/shared-counter/minus/lib/keys.dart
index c53c0b6..7b7f6e9 100644
--- a/mdtest/lib/driver_util.dart
+++ b/mdtest/examples/shared-counter/minus/lib/keys.dart
@@ -1,6 +1,6 @@
 // Copyright 2016 The Vanadium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
-library driver_util;
 
-export 'src/api/driver_map.dart';
+String buttonKey = 'button';
+String textKey = 'text';
diff --git a/mdtest/examples/shared-counter/minus/lib/main.dart b/mdtest/examples/shared-counter/minus/lib/main.dart
new file mode 100644
index 0000000..aeff90a
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/lib/main.dart
@@ -0,0 +1,94 @@
+// Copyright 2016 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:flutter/material.dart';
+
+import 'keys.dart';
+
+const String getCounterUrl = 'http://baku-shared-counter.appspot.com/get_count';
+const String decreaseCounterUrl = 'http://baku-shared-counter.appspot.com/dec_count';
+
+void main() {
+  runApp(
+    new MaterialApp(
+      title: 'Decrease Counter',
+      theme: new ThemeData(
+        primarySwatch: Colors.blue
+      ),
+      home: new MultiCounter()
+    )
+  );
+}
+
+class MultiCounter extends StatefulWidget {
+  MultiCounter({ Key key }) : super(key: key);
+
+  @override
+  _MultiCounterState createState() => new _MultiCounterState();
+}
+
+class _MultiCounterState extends State<MultiCounter> {
+  int _counter = 0;
+
+  @override
+  void initState() {
+    super.initState();
+    listenToGetCounter();
+  }
+
+  Future<Null> listenToGetCounter() async {
+    while (true) {
+      pingUrlAsync(getCounterUrl);
+      await new Future<Null>.delayed(new Duration(milliseconds: 500));
+    }
+  }
+
+  Future<Null> pingUrlAsync(String url) async {
+    HttpClient client = new HttpClient();
+    HttpClientRequest request = await client.getUrl(Uri.parse(url));
+    HttpClientResponse response = await request.close();
+    response.transform(new Utf8Decoder()).listen((String body) {
+      updateCounter(JSON.decode(body)['count']);
+    });
+  }
+
+  void updateCounter(int counter) {
+    setState(() {
+      _counter = counter;
+    });
+  }
+
+  void _decreaseCounter() {
+    setState(() {
+      pingUrlAsync(decreaseCounterUrl);
+    });
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    final TextTheme textTheme = Theme.of(context).textTheme;
+    return new Scaffold(
+      appBar: new AppBar(
+        title: new Text('Multi Counter')
+      ),
+      body: new Center(
+        child: new Text(
+          'Button tapped $_counter time${ _counter >= -1 && _counter <=1 ? '' : 's' }.',
+          style: textTheme.display3,
+          key: new ValueKey(textKey)
+        )
+      ),
+      floatingActionButton: new FloatingActionButton(
+        key: new ValueKey(buttonKey),
+        onPressed: _decreaseCounter,
+        tooltip: 'Decrement',
+        child: new Icon(Icons.cancel)
+      )
+    );
+  }
+}
diff --git a/mdtest/examples/shared-counter/minus/pubspec.yaml b/mdtest/examples/shared-counter/minus/pubspec.yaml
new file mode 100644
index 0000000..d71293a
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/pubspec.yaml
@@ -0,0 +1,9 @@
+name: minus
+description: A minus counter flutter project.
+dependencies:
+  flutter:
+    path: ../../../../deps/flutter/packages/flutter
+  flutter_test:
+    path: ../../../../deps/flutter/packages/flutter_test
+  flutter_driver:
+    path: ../../../../deps/flutter/packages/flutter_driver
diff --git a/mdtest/examples/shared-counter/minus/test_driver/minus_inst.dart b/mdtest/examples/shared-counter/minus/test_driver/minus_inst.dart
new file mode 100644
index 0000000..6999253
--- /dev/null
+++ b/mdtest/examples/shared-counter/minus/test_driver/minus_inst.dart
@@ -0,0 +1,11 @@
+// Copyright 2016 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+import 'package:flutter_driver/driver_extension.dart';
+import 'package:minus/main.dart' as minusapp;
+
+void main() {
+  enableFlutterDriverExtension();
+  minusapp.main();
+}
diff --git a/mdtest/examples/shared-counter/plus/README.md b/mdtest/examples/shared-counter/plus/README.md
new file mode 100644
index 0000000..14f40ed
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/README.md
@@ -0,0 +1,8 @@
+# plus
+
+A new flutter project.
+
+## Getting Started
+
+For help getting started with Flutter, view our online
+[documentation](http://flutter.io/).
diff --git a/mdtest/examples/shared-counter/plus/android/AndroidManifest.xml b/mdtest/examples/shared-counter/plus/android/AndroidManifest.xml
new file mode 100644
index 0000000..7ecdf69
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/android/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.google.plus"
+    android:versionCode="1"
+    android:versionName="0.0.1">
+
+    <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="21" />
+    <uses-permission android:name="android.permission.INTERNET"/>
+
+    <application android:name="org.domokit.sky.shell.SkyApplication" android:label="plus" android:icon="@mipmap/ic_launcher">
+        <activity android:name="org.domokit.sky.shell.SkyActivity"
+                  android:launchMode="singleTop"
+                  android:theme="@android:style/Theme.Black.NoTitleBar"
+                  android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection"
+                  android:hardwareAccelerated="true"
+                  android:windowSoftInputMode="adjustResize">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/mdtest/examples/shared-counter/plus/android/res/mipmap-hdpi/ic_launcher.png b/mdtest/examples/shared-counter/plus/android/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..f0a55cd
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/android/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/plus/android/res/mipmap-mdpi/ic_launcher.png b/mdtest/examples/shared-counter/plus/android/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..eb98dc4
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/android/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/plus/android/res/mipmap-xhdpi/ic_launcher.png b/mdtest/examples/shared-counter/plus/android/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..f1783db
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/android/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/plus/android/res/mipmap-xxhdpi/ic_launcher.png b/mdtest/examples/shared-counter/plus/android/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..46828a2
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/android/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/plus/android/res/mipmap-xxxhdpi/ic_launcher.png b/mdtest/examples/shared-counter/plus/android/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..a527671
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/android/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/plus/flutter.yaml b/mdtest/examples/shared-counter/plus/flutter.yaml
new file mode 100644
index 0000000..edd9ae2
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/flutter.yaml
@@ -0,0 +1,2 @@
+name: plus
+uses-material-design: true
diff --git a/mdtest/examples/shared-counter/plus/ios/.gitignore b/mdtest/examples/shared-counter/plus/ios/.gitignore
new file mode 100644
index 0000000..fc39465
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/ios/.gitignore
@@ -0,0 +1,38 @@
+.idea/
+.vagrant/
+.sconsign.dblite
+.svn/
+
+.DS_Store
+*.swp
+*.lock
+profile
+
+DerivedData/
+build/
+
+*.pbxuser
+*.mode1v3
+*.mode2v3
+*.perspectivev3
+
+!default.pbxuser
+!default.mode1v3
+!default.mode2v3
+!default.perspectivev3
+
+xcuserdata
+
+*.moved-aside
+
+*.pyc
+*sync/
+Icon?
+.tags*
+
+/Flutter/app.flx
+/Flutter/app.dylib
+/Flutter/app.zip
+/Flutter/Flutter.framework
+/Flutter/Generated.xcconfig
+/ServiceDefinitions.json
diff --git a/mdtest/examples/shared-counter/plus/ios/Flutter/Flutter.xcconfig b/mdtest/examples/shared-counter/plus/ios/Flutter/Flutter.xcconfig
new file mode 100644
index 0000000..592ceee
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/ios/Flutter/Flutter.xcconfig
@@ -0,0 +1 @@
+#include "Generated.xcconfig"
diff --git a/mdtest/examples/shared-counter/plus/ios/Runner.xcodeproj/project.pbxproj b/mdtest/examples/shared-counter/plus/ios/Runner.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..add6581
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/ios/Runner.xcodeproj/project.pbxproj
@@ -0,0 +1,394 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 46;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		9705A1C51CF9049000538489 /* app.dylib in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEB81CF902C7004384FC /* app.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
+		9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
+		9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+		9740EEB41CF90195004384FC /* Flutter.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Flutter.xcconfig */; };
+		9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB31CF90195004384FC /* Generated.xcconfig */; };
+		9740EEBB1CF902C7004384FC /* app.flx in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB71CF902C7004384FC /* app.flx */; };
+		978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
+		97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
+		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 */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+		9705A1C41CF9048500538489 /* Embed Frameworks */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 2147483647;
+			dstPath = "";
+			dstSubfolderSpec = 10;
+			files = (
+				9705A1C51CF9049000538489 /* app.dylib in Embed Frameworks */,
+				9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
+			);
+			name = "Embed Frameworks";
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+		7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
+		7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
+		9740EEB21CF90195004384FC /* Flutter.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Flutter.xcconfig; path = Flutter/Flutter.xcconfig; sourceTree = "<group>"; };
+		9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
+		9740EEB71CF902C7004384FC /* app.flx */ = {isa = PBXFileReference; lastKnownFileType = file; name = app.flx; path = Flutter/app.flx; sourceTree = "<group>"; };
+		9740EEB81CF902C7004384FC /* app.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = app.dylib; path = Flutter/app.dylib; sourceTree = "<group>"; };
+		9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = "<group>"; };
+		97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
+		97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+		97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
+		97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
+		97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
+		97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		97C146EB1CF9000F007C117D /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		9740EEB11CF90186004384FC /* Flutter */ = {
+			isa = PBXGroup;
+			children = (
+				9740EEB71CF902C7004384FC /* app.flx */,
+				9740EEB81CF902C7004384FC /* app.dylib */,
+				9740EEBA1CF902C7004384FC /* Flutter.framework */,
+				9740EEB21CF90195004384FC /* Flutter.xcconfig */,
+				9740EEB31CF90195004384FC /* Generated.xcconfig */,
+			);
+			name = Flutter;
+			sourceTree = "<group>";
+		};
+		97C146E51CF9000F007C117D = {
+			isa = PBXGroup;
+			children = (
+				9740EEB11CF90186004384FC /* Flutter */,
+				97C146F01CF9000F007C117D /* Runner */,
+				97C146EF1CF9000F007C117D /* Products */,
+			);
+			sourceTree = "<group>";
+		};
+		97C146EF1CF9000F007C117D /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				97C146EE1CF9000F007C117D /* Runner.app */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		97C146F01CF9000F007C117D /* Runner */ = {
+			isa = PBXGroup;
+			children = (
+				7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */,
+				7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */,
+				97C146FA1CF9000F007C117D /* Main.storyboard */,
+				97C146FD1CF9000F007C117D /* Assets.xcassets */,
+				97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
+				97C147021CF9000F007C117D /* Info.plist */,
+				97C146F11CF9000F007C117D /* Supporting Files */,
+			);
+			path = Runner;
+			sourceTree = "<group>";
+		};
+		97C146F11CF9000F007C117D /* Supporting Files */ = {
+			isa = PBXGroup;
+			children = (
+				97C146F21CF9000F007C117D /* main.m */,
+			);
+			name = "Supporting Files";
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+		97C146ED1CF9000F007C117D /* Runner */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
+			buildPhases = (
+				9740EEB61CF901F6004384FC /* ShellScript */,
+				97C146EA1CF9000F007C117D /* Sources */,
+				97C146EB1CF9000F007C117D /* Frameworks */,
+				97C146EC1CF9000F007C117D /* Resources */,
+				9705A1C41CF9048500538489 /* Embed Frameworks */,
+			);
+			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 = {
+				LastUpgradeCheck = 0730;
+				ORGANIZATIONNAME = "The Chromium Authors";
+				TargetAttributes = {
+					97C146ED1CF9000F007C117D = {
+						CreatedOnToolsVersion = 7.3.1;
+						DevelopmentTeam = MM2NW8A7DV;
+					};
+				};
+			};
+			buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
+			compatibilityVersion = "Xcode 3.2";
+			developmentRegion = English;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+				Base,
+			);
+			mainGroup = 97C146E51CF9000F007C117D;
+			productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				97C146ED1CF9000F007C117D /* Runner */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+		97C146EC1CF9000F007C117D /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				9740EEBB1CF902C7004384FC /* app.flx in Resources */,
+				97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
+				9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */,
+				9740EEB41CF90195004384FC /* Flutter.xcconfig in Resources */,
+				97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
+				97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+		9740EEB61CF901F6004384FC /* ShellScript */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "/bin/sh $FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh";
+		};
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+		97C146EA1CF9000F007C117D /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */,
+				97C146F31CF9000F007C117D /* main.m in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+		97C146FA1CF9000F007C117D /* Main.storyboard */ = {
+			isa = PBXVariantGroup;
+			children = (
+				97C146FB1CF9000F007C117D /* Base */,
+			);
+			name = Main.storyboard;
+			sourceTree = "<group>";
+		};
+		97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
+			isa = PBXVariantGroup;
+			children = (
+				97C147001CF9000F007C117D /* Base */,
+			);
+			name = LaunchScreen.storyboard;
+			sourceTree = "<group>";
+		};
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+		97C147031CF9000F007C117D /* Debug */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 9740EEB21CF90195004384FC /* Flutter.xcconfig */;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				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_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				CODE_SIGN_IDENTITY = "iPhone Developer: Google Development (3F4Y5873JF)";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				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 = 9.3;
+				MTL_ENABLE_DEBUG_INFO = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				SDKROOT = iphoneos;
+				TARGETED_DEVICE_FAMILY = "1,2";
+			};
+			name = Debug;
+		};
+		97C147041CF9000F007C117D /* Release */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 9740EEB21CF90195004384FC /* Flutter.xcconfig */;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				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_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				CODE_SIGN_IDENTITY = "iPhone Developer: Google Development (3F4Y5873JF)";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				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 = 9.3;
+				MTL_ENABLE_DEBUG_INFO = NO;
+				SDKROOT = iphoneos;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VALIDATE_PRODUCT = YES;
+			};
+			name = Release;
+		};
+		97C147061CF9000F007C117D /* Debug */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 9740EEB21CF90195004384FC /* Flutter.xcconfig */;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				ENABLE_BITCODE = NO;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Flutter",
+				);
+				INFOPLIST_FILE = Runner/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Flutter",
+				);
+				PRODUCT_BUNDLE_IDENTIFIER = com.google.plusCounter;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				PROVISIONING_PROFILE = "";
+			};
+			name = Debug;
+		};
+		97C147071CF9000F007C117D /* Release */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 9740EEB21CF90195004384FC /* Flutter.xcconfig */;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				ENABLE_BITCODE = NO;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Flutter",
+				);
+				INFOPLIST_FILE = Runner/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Flutter",
+				);
+				PRODUCT_BUNDLE_IDENTIFIER = com.google.plusCounter;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				PROVISIONING_PROFILE = "";
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				97C147031CF9000F007C117D /* Debug */,
+				97C147041CF9000F007C117D /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				97C147061CF9000F007C117D /* Debug */,
+				97C147071CF9000F007C117D /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = 97C146E61CF9000F007C117D /* Project object */;
+}
diff --git a/mdtest/examples/shared-counter/plus/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/mdtest/examples/shared-counter/plus/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..6cec59c
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+   version = "1.0">
+   <FileRef
+      location = "self:Runner.xcodeproj">
+   </FileRef>
+</Workspace>
diff --git a/mdtest/examples/shared-counter/plus/ios/Runner/AppDelegate.h b/mdtest/examples/shared-counter/plus/ios/Runner/AppDelegate.h
new file mode 100644
index 0000000..8ef937e
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/ios/Runner/AppDelegate.h
@@ -0,0 +1,11 @@
+// Copyright 2016 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#import <UIKit/UIKit.h>
+
+@interface AppDelegate : UIResponder <UIApplicationDelegate>
+
+@property (strong, nonatomic) UIWindow *window;
+
+@end
diff --git a/mdtest/examples/shared-counter/plus/ios/Runner/AppDelegate.m b/mdtest/examples/shared-counter/plus/ios/Runner/AppDelegate.m
new file mode 100644
index 0000000..d4cfa3a
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/ios/Runner/AppDelegate.m
@@ -0,0 +1,33 @@
+#import <Flutter/Flutter.h>
+#include "AppDelegate.h"
+
+@implementation AppDelegate
+
+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+    // Override point for customization after application launch.
+    return YES;
+}
+
+- (void)applicationWillResignActive:(UIApplication *)application {
+    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
+    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
+}
+
+- (void)applicationDidEnterBackground:(UIApplication *)application {
+    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
+    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
+}
+
+- (void)applicationWillEnterForeground:(UIApplication *)application {
+    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
+}
+
+- (void)applicationDidBecomeActive:(UIApplication *)application {
+    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
+}
+
+- (void)applicationWillTerminate:(UIApplication *)application {
+    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
+}
+
+@end
diff --git a/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000..363d1c4
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,142 @@
+{
+  "images" : [
+    {
+      "size" : "29x29",
+      "idiom" : "iphone",
+      "filename" : "Icon-Small@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "iphone",
+      "filename" : "Icon-Small@3x.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "iphone",
+      "filename" : "Icon-Small-40@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "iphone",
+      "filename" : "Icon-Small-40@3x.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "60x60",
+      "idiom" : "iphone",
+      "filename" : "Icon-60@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "60x60",
+      "idiom" : "iphone",
+      "filename" : "Icon-60@3x.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "ipad",
+      "filename" : "Icon-Small.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "ipad",
+      "filename" : "Icon-Small@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "ipad",
+      "filename" : "Icon-Small-40.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "ipad",
+      "filename" : "Icon-Small-40@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "76x76",
+      "idiom" : "ipad",
+      "filename" : "Icon-76.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "76x76",
+      "idiom" : "ipad",
+      "filename" : "Icon-76@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "83.5x83.5",
+      "idiom" : "ipad",
+      "filename" : "Icon-83.5@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "16x16",
+      "idiom" : "mac",
+      "filename" : "icon_16x16.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "16x16",
+      "idiom" : "mac",
+      "filename" : "icon_16x16@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "32x32",
+      "idiom" : "mac",
+      "filename" : "icon_32x32.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "32x32",
+      "idiom" : "mac",
+      "filename" : "icon_32x32@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "128x128",
+      "idiom" : "mac",
+      "filename" : "icon_128x128.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "128x128",
+      "idiom" : "mac",
+      "filename" : "icon_128x128@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "256x256",
+      "idiom" : "mac",
+      "filename" : "icon_256x256.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "256x256",
+      "idiom" : "mac",
+      "filename" : "icon_256x256@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "512x512",
+      "idiom" : "mac",
+      "filename" : "icon_512x512.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "512x512",
+      "idiom" : "mac",
+      "filename" : "icon_512x512@2x.png",
+      "scale" : "2x"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png
new file mode 100644
index 0000000..9996f5e
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png
new file mode 100644
index 0000000..7a543ed
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-76.png b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-76.png
new file mode 100644
index 0000000..05a8268
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-76.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png
new file mode 100644
index 0000000..bfbca28
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png
new file mode 100644
index 0000000..c924b8e
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small-40.png b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small-40.png
new file mode 100644
index 0000000..3006f1d
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small-40.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png
new file mode 100644
index 0000000..5f7d22d
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png
new file mode 100644
index 0000000..9996f5e
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small.png b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small.png
new file mode 100644
index 0000000..3433da1
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png
new file mode 100644
index 0000000..f7f9f16
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png
new file mode 100644
index 0000000..e9c2360
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_128x128.png b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_128x128.png
new file mode 100644
index 0000000..dd5fccb
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_128x128.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png
new file mode 100644
index 0000000..1909e27
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_16x16.png b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_16x16.png
new file mode 100644
index 0000000..40a701b
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_16x16.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png
new file mode 100644
index 0000000..06c1a80
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_256x256.png b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_256x256.png
new file mode 100644
index 0000000..1909e27
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_256x256.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png
new file mode 100644
index 0000000..69c96ef
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_32x32.png b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_32x32.png
new file mode 100644
index 0000000..06c1a80
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_32x32.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png
new file mode 100644
index 0000000..0f94371
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_512x512.png b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_512x512.png
new file mode 100644
index 0000000..69c96ef
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_512x512.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png
new file mode 100644
index 0000000..1d6355f
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png
Binary files differ
diff --git a/mdtest/examples/shared-counter/plus/ios/Runner/Base.lproj/LaunchScreen.storyboard b/mdtest/examples/shared-counter/plus/ios/Runner/Base.lproj/LaunchScreen.storyboard
new file mode 100644
index 0000000..ebf48f6
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/ios/Runner/Base.lproj/LaunchScreen.storyboard
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" initialViewController="01J-lp-oVM">
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
+    </dependencies>
+    <scenes>
+        <!--View Controller-->
+        <scene sceneID="EHf-IW-A2E">
+            <objects>
+                <viewController id="01J-lp-oVM" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
+                        <viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
+                        <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+                    </view>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="53" y="375"/>
+        </scene>
+    </scenes>
+</document>
diff --git a/mdtest/examples/shared-counter/plus/ios/Runner/Base.lproj/Main.storyboard b/mdtest/examples/shared-counter/plus/ios/Runner/Base.lproj/Main.storyboard
new file mode 100644
index 0000000..f3c2851
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/ios/Runner/Base.lproj/Main.storyboard
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
+    </dependencies>
+    <scenes>
+        <!--Flutter View Controller-->
+        <scene sceneID="tne-QT-ifu">
+            <objects>
+                <viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
+                        <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
+                        <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+                    </view>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
+            </objects>
+        </scene>
+    </scenes>
+</document>
diff --git a/mdtest/examples/shared-counter/plus/ios/Runner/Info.plist b/mdtest/examples/shared-counter/plus/ios/Runner/Info.plist
new file mode 100644
index 0000000..ce64fce
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/ios/Runner/Info.plist
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>en</string>
+	<key>CFBundleExecutable</key>
+	<string>$(EXECUTABLE_NAME)</string>
+	<key>CFBundleIdentifier</key>
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>plus</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>1.0</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>1</string>
+	<key>LSRequiresIPhoneOS</key>
+	<true/>
+	<key>UILaunchStoryboardName</key>
+	<string>LaunchScreen</string>
+	<key>UIMainStoryboardFile</key>
+	<string>Main</string>
+	<key>UIRequiredDeviceCapabilities</key>
+	<array>
+		<string>arm64</string>
+	</array>
+	<key>UISupportedInterfaceOrientations</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+		<string>UIInterfaceOrientationLandscapeLeft</string>
+		<string>UIInterfaceOrientationLandscapeRight</string>
+	</array>
+	<key>UISupportedInterfaceOrientations~ipad</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+		<string>UIInterfaceOrientationPortraitUpsideDown</string>
+		<string>UIInterfaceOrientationLandscapeLeft</string>
+		<string>UIInterfaceOrientationLandscapeRight</string>
+	</array>
+	<key>UIViewControllerBasedStatusBarAppearance</key>
+	<false/>
+</dict>
+</plist>
diff --git a/mdtest/examples/shared-counter/plus/ios/Runner/main.m b/mdtest/examples/shared-counter/plus/ios/Runner/main.m
new file mode 100644
index 0000000..7e0fe2c
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/ios/Runner/main.m
@@ -0,0 +1,11 @@
+#import <UIKit/UIKit.h>
+#import <Flutter/Flutter.h>
+#import "AppDelegate.h"
+
+int main(int argc, char * argv[]) {
+    FlutterInit(argc, (const char**)argv);
+    @autoreleasepool {
+        return UIApplicationMain(argc, argv, nil,
+                                 NSStringFromClass([AppDelegate class]));
+    }
+}
diff --git a/mdtest/lib/driver_util.dart b/mdtest/examples/shared-counter/plus/lib/keys.dart
similarity index 74%
copy from mdtest/lib/driver_util.dart
copy to mdtest/examples/shared-counter/plus/lib/keys.dart
index c53c0b6..7b7f6e9 100644
--- a/mdtest/lib/driver_util.dart
+++ b/mdtest/examples/shared-counter/plus/lib/keys.dart
@@ -1,6 +1,6 @@
 // Copyright 2016 The Vanadium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
-library driver_util;
 
-export 'src/api/driver_map.dart';
+String buttonKey = 'button';
+String textKey = 'text';
diff --git a/mdtest/examples/shared-counter/plus/lib/main.dart b/mdtest/examples/shared-counter/plus/lib/main.dart
new file mode 100644
index 0000000..6f0680d
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/lib/main.dart
@@ -0,0 +1,94 @@
+// Copyright 2016 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:convert';
+
+import 'package:flutter/material.dart';
+import 'dart:io';
+
+import 'keys.dart';
+
+const String getCounterUrl = 'http://baku-shared-counter.appspot.com/get_count';
+const String increaseCounterUrl = 'http://baku-shared-counter.appspot.com/inc_count';
+
+void main() {
+  runApp(
+    new MaterialApp(
+      title: 'Decrease Counter',
+      theme: new ThemeData(
+        primarySwatch: Colors.blue
+      ),
+      home: new MultiCounter()
+    )
+  );
+}
+
+class MultiCounter extends StatefulWidget {
+  MultiCounter({ Key key }) : super(key: key);
+
+  @override
+  _MultiCounterState createState() => new _MultiCounterState();
+}
+
+class _MultiCounterState extends State<MultiCounter> {
+  int _counter = 0;
+
+  @override
+  void initState() {
+    super.initState();
+    listenToGetCounter();
+  }
+
+  Future<Null> listenToGetCounter() async {
+    while (true) {
+      pingUrlAsync(getCounterUrl);
+      await new Future<Null>.delayed(new Duration(milliseconds: 500));
+    }
+  }
+
+  Future<Null> pingUrlAsync(String url) async {
+    HttpClient client = new HttpClient();
+    HttpClientRequest request = await client.getUrl(Uri.parse(url));
+    HttpClientResponse response = await request.close();
+    response.transform(new Utf8Decoder()).listen((String body) {
+      updateCounter(JSON.decode(body)['count']);
+    });
+  }
+
+  void updateCounter(int counter) {
+    setState(() {
+      _counter = counter;
+    });
+  }
+
+  void _decreaseCounter() {
+    setState(() {
+      pingUrlAsync(increaseCounterUrl);
+    });
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    final TextTheme textTheme = Theme.of(context).textTheme;
+    return new Scaffold(
+      appBar: new AppBar(
+        title: new Text('Multi Counter')
+      ),
+      body: new Center(
+        child: new Text(
+          'Button tapped $_counter time${ _counter >= -1 && _counter <=1 ? '' : 's' }.',
+          style: textTheme.display3,
+          key: new ValueKey(textKey)
+        )
+      ),
+      floatingActionButton: new FloatingActionButton(
+        key: new ValueKey(buttonKey),
+        onPressed: _decreaseCounter,
+        tooltip: 'Decrement',
+        child: new Icon(Icons.add)
+      )
+    );
+  }
+}
diff --git a/mdtest/examples/shared-counter/plus/pubspec.yaml b/mdtest/examples/shared-counter/plus/pubspec.yaml
new file mode 100644
index 0000000..d74f35d
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/pubspec.yaml
@@ -0,0 +1,9 @@
+name: plus
+description: A plus counter flutter project.
+dependencies:
+  flutter:
+    path: ../../../../deps/flutter/packages/flutter
+  flutter_test:
+    path: ../../../../deps/flutter/packages/flutter_test
+  flutter_driver:
+    path: ../../../../deps/flutter/packages/flutter_driver
diff --git a/mdtest/examples/shared-counter/plus/test_driver/plus_inst.dart b/mdtest/examples/shared-counter/plus/test_driver/plus_inst.dart
new file mode 100644
index 0000000..845959e
--- /dev/null
+++ b/mdtest/examples/shared-counter/plus/test_driver/plus_inst.dart
@@ -0,0 +1,11 @@
+// Copyright 2016 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+import 'package:flutter_driver/driver_extension.dart';
+import 'package:plus/main.dart' as plusapp;
+
+void main() {
+  enableFlutterDriverExtension();
+  plusapp.main();
+}
diff --git a/mdtest/lib/driver_util.dart b/mdtest/examples/shared-counter/shared_counter_test/keys.dart
similarity index 74%
copy from mdtest/lib/driver_util.dart
copy to mdtest/examples/shared-counter/shared_counter_test/keys.dart
index c53c0b6..7b7f6e9 100644
--- a/mdtest/lib/driver_util.dart
+++ b/mdtest/examples/shared-counter/shared_counter_test/keys.dart
@@ -1,6 +1,6 @@
 // Copyright 2016 The Vanadium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
-library driver_util;
 
-export 'src/api/driver_map.dart';
+String buttonKey = 'button';
+String textKey = 'text';
diff --git a/mdtest/examples/shared-counter/shared_counter_test/pubspec.yaml b/mdtest/examples/shared-counter/shared_counter_test/pubspec.yaml
new file mode 100644
index 0000000..fcf731a
--- /dev/null
+++ b/mdtest/examples/shared-counter/shared_counter_test/pubspec.yaml
@@ -0,0 +1,12 @@
+name: shared_counter_test
+description: shared-counter flutter driver tests.
+dependencies:
+  flutter:
+    path: ../../../../deps/flutter/packages/flutter
+  flutter_test:
+    path: ../../../../deps/flutter/packages/flutter_test
+  mdtest_api:
+    path: ../../../dart-packages/mdtest_api
+
+dev_dependencies:
+  test: 0.12.15+1
diff --git a/mdtest/examples/shared-counter/shared_counter_test/shared_counter.spec b/mdtest/examples/shared-counter/shared_counter_test/shared_counter.spec
new file mode 100644
index 0000000..46116c1
--- /dev/null
+++ b/mdtest/examples/shared-counter/shared_counter_test/shared_counter.spec
@@ -0,0 +1,12 @@
+{
+  "devices": {
+    "Alice": {
+      "app-root": "../plus",
+      "app-path": "test_driver/plus_inst.dart"
+    },
+    "Bob": {
+      "app-root": "../minus",
+      "app-path": "test_driver/minus_inst.dart"
+    }
+  }
+}
diff --git a/mdtest/examples/shared-counter/shared_counter_test/shared_counter_test_1.dart b/mdtest/examples/shared-counter/shared_counter_test/shared_counter_test_1.dart
new file mode 100644
index 0000000..c309094
--- /dev/null
+++ b/mdtest/examples/shared-counter/shared_counter_test/shared_counter_test_1.dart
@@ -0,0 +1,123 @@
+// Copyright 2016 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:flutter_driver/flutter_driver.dart';
+import 'package:test/test.dart';
+import 'package:mdtest_api/driver_util.dart';
+
+import 'keys.dart';
+import 'utils.dart' as utils;
+
+void main() {
+  group('Count Test 1', () {
+    DriverMap driverMap;
+
+    setUpAll(() async {
+      await utils.resetCounter();
+      driverMap = new DriverMap();
+    });
+
+    tearDownAll(() async {
+      if (driverMap != null) {
+        driverMap.closeAll();
+      }
+    });
+
+    test('all tap 1 time', () async {
+      List<FlutterDriver> drivers = await Future.wait(driverMap.values);
+      await new Future<Null>.delayed(new Duration(milliseconds: 5000));
+      await Future.forEach(drivers, (FlutterDriver driver) {
+        driver.tap(find.byValueKey(buttonKey));
+      });
+
+      await new Future<Null>.delayed(new Duration(milliseconds: 3000));
+      await Future.forEach(drivers, (FlutterDriver driver) async {
+        String result = await driver.getText(find.byValueKey(textKey));
+        expect(result, equals('Button tapped 0 time.'));
+      });
+    });
+
+    test('tap increase 2 times', () async {
+      FlutterDriver alice = await driverMap['Alice'];
+      FlutterDriver bob = await driverMap['Bob'];
+      await new Future<Null>.delayed(new Duration(milliseconds: 3000));
+      for(int i = 0; i < 2; i++) {
+        await alice.tap(find.byValueKey(buttonKey));
+        await new Future<Null>.delayed(new Duration(milliseconds: 2000));
+        print('Driver 1: ${await alice.getText(find.byValueKey(textKey))}');
+        print('Driver 2: ${await bob.getText(find.byValueKey(textKey))}');
+      }
+      String result1 = await alice.getText(find.byValueKey(textKey));
+      expect(result1, equals('Button tapped 2 times.'));
+      String result2 = await bob.getText(find.byValueKey(textKey));
+      expect(result2, equals('Button tapped 2 times.'));
+    });
+
+    test('tap decrease 2 times', () async {
+      FlutterDriver alice = await driverMap['Alice'];
+      FlutterDriver bob = await driverMap['Bob'];
+      await new Future<Null>.delayed(new Duration(milliseconds: 1000));
+      for(int i = 0; i < 2; i++) {
+        await bob.tap(find.byValueKey(buttonKey));
+        await new Future<Null>.delayed(new Duration(milliseconds: 2000));
+        print('Driver 2: ${await bob.getText(find.byValueKey(textKey))}');
+        print('Driver 1: ${await alice.getText(find.byValueKey(textKey))}');
+      }
+      String result1 = await alice.getText(find.byValueKey(textKey));
+      expect(result1, equals('Button tapped 0 time.'));
+      String result2 = await bob.getText(find.byValueKey(textKey));
+      expect(result2, equals('Button tapped 0 time.'));
+      // fail('No reason failure.');
+    });
+  });
+
+  group('Count Test 2', () {
+    DriverMap driverMap;
+
+    setUpAll(() async {
+      await utils.resetCounter();
+      driverMap = new DriverMap();
+    });
+
+    tearDownAll(() async {
+      if (driverMap != null) {
+        driverMap.closeAll();
+      }
+    });
+
+    test('tap decrease 1 times', () async {
+      FlutterDriver alice = await driverMap['Alice'];
+      FlutterDriver bob = await driverMap['Bob'];
+      await new Future<Null>.delayed(new Duration(milliseconds: 3000));
+      for(int i = 0; i < 1; i++) {
+        await bob.tap(find.byValueKey(buttonKey));
+        await new Future<Null>.delayed(new Duration(milliseconds: 2000));
+        print('Driver 2: ${await bob.getText(find.byValueKey(textKey))}');
+        print('Driver 1: ${await alice.getText(find.byValueKey(textKey))}');
+      }
+      String result1 = await alice.getText(find.byValueKey(textKey));
+      expect(result1, equals('Button tapped -1 time.'));
+      String result2 = await bob.getText(find.byValueKey(textKey));
+      expect(result2, equals('Button tapped -1 time.'));
+    });
+
+    test('tap increase 1 times', () async {
+      FlutterDriver alice = await driverMap['Alice'];
+      FlutterDriver bob = await driverMap['Bob'];
+      await new Future<Null>.delayed(new Duration(milliseconds: 1000));
+      for(int i = 0; i < 1; i++) {
+        await alice.tap(find.byValueKey(buttonKey));
+        await new Future<Null>.delayed(new Duration(milliseconds: 2000));
+        print('Driver 1: ${await alice.getText(find.byValueKey(textKey))}');
+        print('Driver 2: ${await bob.getText(find.byValueKey(textKey))}');
+      }
+      String result1 = await alice.getText(find.byValueKey(textKey));
+      expect(result1, equals('Button tapped 0 time.'));
+      String result2 = await bob.getText(find.byValueKey(textKey));
+      expect(result2, equals('Button tapped 0 time.'));
+    });
+  });
+}
diff --git a/mdtest/examples/shared-counter/shared_counter_test/shared_counter_test_2.dart b/mdtest/examples/shared-counter/shared_counter_test/shared_counter_test_2.dart
new file mode 100644
index 0000000..a226dda
--- /dev/null
+++ b/mdtest/examples/shared-counter/shared_counter_test/shared_counter_test_2.dart
@@ -0,0 +1,61 @@
+// Copyright 2016 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:flutter_driver/flutter_driver.dart';
+import 'package:test/test.dart';
+import 'package:mdtest_api/driver_util.dart';
+
+import 'keys.dart';
+import 'utils.dart' as utils;
+
+void main() {
+  group('Count Test 3', () {
+    DriverMap driverMap;
+
+    setUpAll(() async {
+      await utils.resetCounter();
+      driverMap = new DriverMap();
+    });
+
+    tearDownAll(() async {
+      if (driverMap != null) {
+        driverMap.closeAll();
+      }
+    });
+
+    test('tap increase 3 times', () async {
+      FlutterDriver alice = await driverMap['Alice'];
+      FlutterDriver bob = await driverMap['Bob'];
+      await new Future<Null>.delayed(new Duration(milliseconds: 3000));
+      for(int i = 0; i < 3; i++) {
+        await alice.tap(find.byValueKey(buttonKey));
+        await new Future<Null>.delayed(new Duration(milliseconds: 2000));
+        print('Driver 1: ${await alice.getText(find.byValueKey(textKey))}');
+        print('Driver 2: ${await bob.getText(find.byValueKey(textKey))}');
+      }
+      String result1 = await alice.getText(find.byValueKey(textKey));
+      expect(result1, equals('Button tapped 3 times.'));
+      String result2 = await bob.getText(find.byValueKey(textKey));
+      expect(result2, equals('Button tapped 3 times.'));
+    });
+
+    test('tap decrese 3 times', () async {
+      FlutterDriver alice = await driverMap['Alice'];
+      FlutterDriver bob = await driverMap['Bob'];
+      await new Future<Null>.delayed(new Duration(milliseconds: 1000));
+      for(int i = 0; i < 3; i++) {
+        await bob.tap(find.byValueKey(buttonKey));
+        await new Future<Null>.delayed(new Duration(milliseconds: 2000));
+        print('Driver 2: ${await bob.getText(find.byValueKey(textKey))}');
+        print('Driver 1: ${await alice.getText(find.byValueKey(textKey))}');
+      }
+      String result1 = await alice.getText(find.byValueKey(textKey));
+      expect(result1, equals('Button tapped 0 time.'));
+      String result2 = await bob.getText(find.byValueKey(textKey));
+      expect(result2, equals('Button tapped 0 time.'));
+    });
+  });
+}
diff --git a/mdtest/examples/shared-counter/shared_counter_test/utils.dart b/mdtest/examples/shared-counter/shared_counter_test/utils.dart
new file mode 100644
index 0000000..4382e59
--- /dev/null
+++ b/mdtest/examples/shared-counter/shared_counter_test/utils.dart
@@ -0,0 +1,15 @@
+// Copyright 2016 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'dart:io';
+
+const String resetCounterUrl = 'http://baku-shared-counter.appspot.com/cleanup_count';
+
+Future<Null> resetCounter() async {
+  HttpClient client = new HttpClient();
+  HttpClientRequest request = await client.getUrl(Uri.parse(resetCounterUrl));
+  await request.close();
+}
diff --git a/mdtest/lib/src/report/locator.dart b/mdtest/lib/src/report/locator.dart
deleted file mode 100644
index a75a290..0000000
--- a/mdtest/lib/src/report/locator.dart
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2016 The Vanadium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-import 'dart:io';
-
-import 'package:mdtest/src/util.dart';
-
-// Provide paths which point to the assets directory
-String mdtestScriptPath = Platform.script.toFilePath();
-int binStart = mdtestScriptPath.lastIndexOf('bin');
-String mdtestRootPath = mdtestScriptPath.substring(0, binStart);
-String libPath = normalizePath(mdtestRootPath, 'lib');
-String assetsPath = normalizePath(libPath, 'assets');
-
-List<String> get relatedPaths => <String>[
-  normalizePath(assetsPath, 'emerald.png'),
-  normalizePath(assetsPath, 'ruby.png'),
-  normalizePath(assetsPath, 'report.css')
-];