From 3871509d1ad06a64c6d0ed6f7f4874cd90596cf7 Mon Sep 17 00:00:00 2001
From: Kevin Moore <kevmoo@google.com>
Date: Sat, 17 Oct 2015 11:50:04 -0700
Subject: [PATCH] Migrate server-appengine sample to use pkg/shelf

---
 CHANGELOG.md                                  |   2 +-
 lib/generators/server_appengine_data.dart     | 155 ++++++++----------
 templates/server-appengine/.gitignore         |   4 -
 templates/server-appengine/app.yaml           |   7 +-
 templates/server-appengine/bin/server.dart    | 130 ++++++++-------
 .../build/web/{usage.html => index.html}      |   0
 templates/server-appengine/lib/memcache.dart  |  31 ++--
 templates/server-appengine/pubspec.yaml       |   2 +
 8 files changed, 163 insertions(+), 168 deletions(-)
 rename templates/server-appengine/build/web/{usage.html => index.html} (100%)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 68a7ab4..492f65d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,7 +1,7 @@
 # CHANGELOG
 
 ## 0.2.4
-- Improved layout of `server-appengine`
+- Migrated `server-appengine` to use `shelf`.
 
 ## 0.2.3+1
 - Fixed an issue with the Polymer template
diff --git a/lib/generators/server_appengine_data.dart b/lib/generators/server_appengine_data.dart
index 62a520b..9bce3bb 100644
--- a/lib/generators/server_appengine_data.dart
+++ b/lib/generators/server_appengine_data.dart
@@ -5,8 +5,7 @@
 const List<String> data = const [
   ".gitignore",
   "text",
-  """LmJ1aWxkbG9nCi5EU19TdG9yZQouaWRlYQoucGFja2FnZXMKLnB1Yi8KYnVpbGQvCnBhY2thZ2Vz
-CnB1YnNwZWMubG9jawo=""",
+  "LnBhY2thZ2VzCi5wdWIvCnBhY2thZ2VzCnB1YnNwZWMubG9jawo=",
   "CHANGELOG.md",
   "text",
   """IyBDaGFuZ2Vsb2cKCiMjIDAuMC4xCgotIEluaXRpYWwgdmVyc2lvbiwgY3JlYXRlZCBieSBTdGFn
@@ -51,63 +50,54 @@ bmQgaG93IHRvIHVzZSB0aGUgcHJlY29uZmlndXJlZCBBcHAgRW5naW5lIG1lbWNhY2hlIEFQSSBz
 ZXJ2aWNlLgo=""",
   "app.yaml",
   "text",
-  """dmVyc2lvbjogdjEKcnVudGltZTogY3VzdG9tCnZtOiB0cnVlCmFwaV92ZXJzaW9uOiAxCnRocmVh
-ZHNhZmU6IHRydWUKCm1hbnVhbF9zY2FsaW5nOgogIGluc3RhbmNlczogMQo=""",
+  """IyBJbmZvcm1hdGlvbiBvbiBjb25maWd1cmluZyBhcHAueWFtbAojIGh0dHBzOi8vY2xvdWQuZ29v
+Z2xlLmNvbS9hcHBlbmdpbmUvZG9jcy9tYW5hZ2VkLXZtcy9jb25maWcKcnVudGltZTogY3VzdG9t
+CnZtOiB0cnVlCmFwaV92ZXJzaW9uOiAxCg==""",
   "bin/server.dart",
   "text",
   """Ly8gQ29weXJpZ2h0IChjKSB7e3llYXJ9fSwge3thdXRob3J9fS4gQWxsIHJpZ2h0cyByZXNlcnZl
 ZC4gVXNlIG9mIHRoaXMgc291cmNlIGNvZGUKLy8gaXMgZ292ZXJuZWQgYnkgYSBCU0Qtc3R5bGUg
 bGljZW5zZSB0aGF0IGNhbiBiZSBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlLgoKaW1wb3J0ICdk
-YXJ0OmFzeW5jJzsKaW1wb3J0ICdkYXJ0OmlvJzsKCmltcG9ydCAncGFja2FnZTphcHBlbmdpbmUv
-YXBwZW5naW5lLmRhcnQnOwppbXBvcnQgJ3BhY2thZ2U6e3twcm9qZWN0TmFtZX19L21lbWNhY2hl
-LmRhcnQnIGFzIGNhY2hlOwoKLy8vIEFwcGxpY2F0aW9uIGVudHJ5cG9pbnQgY2FsbGVkIGJ5IEFw
-cEVuZ2luZSBhdCBzdGFydHVwLgptYWluKCkgewogIC8vIFNldHVwIEFwcEVuZ2luZSBhbmQgcmVn
-aXN0ZXIgYW4gSFRUUCByZXF1ZXN0IGhhbmRsZXIuCiAgcnVuQXBwRW5naW5lKHJlcXVlc3RIYW5k
-bGVyKTsKfQoKLy8vIFRoZSBtYWluIEhUVFAgcmVxdWVzdCBoYW5kbGVyLgp2b2lkIHJlcXVlc3RI
-YW5kbGVyKEh0dHBSZXF1ZXN0IHJlcXVlc3QpIHsKICAvLyBJbml0aWFsaXplIHRoZSBhcHBsaWNh
-dGlvbi4gVGhpcyBpcyBkb25lIGhlcmUgc2luY2Ugd2UgY2FuIG9ubHkgYWNjZXNzCiAgLy8gdGhl
-IEFwcEVuZ2luZSBBUElzIHdoZW4gaW4gdGhlIGNvbnRleHQgb2YgYSByZXF1ZXN0LiBUbyBhdm9p
-ZCBpbml0aWFsaXppbmcKICAvLyBhbiBhbHJlYWR5IGluaXRpYWxpemVkIGFwcCBpdCBpcyBndWFy
-ZGVkIGJ5IHRoZSBbY2FjaGVJbml0aWFsaXplZF0gYm9vbC4KICB2YXIgaW5pdGlhbGl6ZWQgPSBu
-ZXcgRnV0dXJlLnN5bmMoY2FjaGUuaW5pdGlhbGl6ZSk7CgogIGluaXRpYWxpemVkLnRoZW4oKF8p
-IHsKICAgIC8vIFdlIG9ubHkgaGFuZGxlIEdFVCByZXF1ZXN0cyBpbiB0aGlzIHNpbXBsZSBleGFt
-cGxlLgogICAgaWYgKHJlcXVlc3QubWV0aG9kID09ICdHRVQnKSB7CiAgICAgIGhhbmRsZUdldFJl
-cXVlc3QocmVxdWVzdCk7CiAgICB9IGVsc2UgewogICAgICByZXF1ZXN0LnJlc3BvbnNlCiAgICAg
-ICAgLi5zdGF0dXNDb2RlID0gSHR0cFN0YXR1cy5NRVRIT0RfTk9UX0FMTE9XRUQKICAgICAgICAu
-LndyaXRlKCdVbnN1cHBvcnRlZCBIVFRQIHJlcXVlc3QgbWV0aG9kOiAke3JlcXVlc3QubWV0aG9k
-fS4nKQogICAgICAgIC4uY2xvc2UoKTsKICAgIH0KICB9KS5jYXRjaEVycm9yKChfKSA9PiByZXF1
-ZXN0LnJlc3BvbnNlCiAgICAuLndyaXRlKCdGYWlsZWQgaGFuZGxpbmcgcmVxdWVzdDogJHtyZXF1
-ZXN0LnRvU3RyaW5nKCl9LicpCiAgICAuLmNsb3NlKCkpOwp9CgovLy8gR0VUIHJlcXVlc3QgaGFu
-ZGxlci4KLy8vCi8vLyBQYXJzZXMgdGhlIHVybCB0byBkZXRlcm1pbmUgd2hhdCBjb21tYW5kIHRv
-IHJ1biBhbmQgdGhlIGNvcnJlc3BvbmRpbmcKLy8vIGlucHV0IGRhdGEuCmhhbmRsZUdldFJlcXVl
-c3QoSHR0cFJlcXVlc3QgcmVxdWVzdCkgewogIEh0dHBSZXNwb25zZSByZXNwb25zZSA9IHJlcXVl
-c3QucmVzcG9uc2U7CiAgLy8gRGV0ZXJtaW5lIGNvbW1hbmQuCiAgaWYgKHJlcXVlc3QudXJpLnBh
-dGggPT0gJy93cml0ZV9jYWNoZScpIHsKICAgIC8vIEdldCB0aGUgcGFyc2VkIHF1ZXJ5IHN0cmlu
-Zy4KICAgIE1hcDxTdHJpbmcsIFN0cmluZz4gcXVlcnlNYXAgPSByZXF1ZXN0LnVyaS5xdWVyeVBh
-cmFtZXRlcnM7CiAgICAvLyBVcGRhdGUgdGhlIGNhY2hlIHdpdGggdGhlIGdpdmVuIGtleS92YWx1
-ZSBwYWlycy4KICAgIHJlc3BvbnNlLndyaXRlbG4oJ1VwZGF0aW5nIGNhY2hlIHdpdGggJHtxdWVy
-eU1hcC5sZW5ndGh9IHZhbHVlKHMpLicpOwogICAgcmVzcG9uc2Uud3JpdGVsbignJyk7CiAgICBj
-YWNoZS53cml0ZShyZXNwb25zZSwgcXVlcnlNYXApOwogIH0gZWxzZSBpZiAocmVxdWVzdC51cmku
-cGF0aCA9PSAnL3JlYWRfY2FjaGUnKSB7CiAgICAvLyBJZiBubyBxdWVyeSBzdHJpbmcgaXMgZ2l2
-ZW4gcmV0dXJuIHRoZSBkZWZhdWx0IGtleSdzIHZhbHVlLgogICAgaWYgKCFyZXF1ZXN0LnVyaS5o
-YXNRdWVyeSkgewogICAgICByZXNwb25zZS53cml0ZWxuKCdSZWFkaW5nIGRlZmF1bHQgdmFsdWUs
-IHNpbmNlIG5vIGtleXMgcHJvdmlkZWQuJyk7CiAgICAgIHJlc3BvbnNlLndyaXRlbG4oJycpOwog
-ICAgICBjYWNoZS5yZWFkKHJlc3BvbnNlLCBbY2FjaGUuREVGQVVMVF9LRVldKTsKICAgICAgcmV0
-dXJuOwogICAgfQogICAgLy8gR2V0IHRoZSBwYXJzZWQgcXVlcnkgc3RyaW5nLgogICAgTWFwPFN0
-cmluZywgU3RyaW5nPiBxdWVyeU1hcCA9IHJlcXVlc3QudXJpLnF1ZXJ5UGFyYW1ldGVyczsKICAg
-IC8vIFJlYWQgb3V0IHRoZSB2YWx1ZXMgY29ycmVzcG9uZGluZyB0byB0aGUga2V5cyBpbiB0aGUg
-cXVlcnkgc3RyaW5nLgogICAgcmVzcG9uc2Uud3JpdGVsbignUmVhZGluZyAke3F1ZXJ5TWFwLmxl
-bmd0aH0gdmFsdWUocykgZnJvbSBjYWNoZS4nKTsKICAgIHJlc3BvbnNlLndyaXRlbG4oJycpOwog
-ICAgY2FjaGUucmVhZChyZXNwb25zZSwgcXVlcnlNYXAua2V5cyk7CiAgfSBlbHNlIGlmIChyZXF1
-ZXN0LnVyaS5wYXRoID09ICcvY2xlYXJfY2FjaGUnKSB7CiAgICAvLyBSZWludGlhbGl6ZSB0aGUg
-Y2FjaGUuIFRoaXMgY2xlYXJzIGFsbCB2YWx1ZXMgYW5kIHJlc2V0cyB0aGUgZGVmYXVsdC4KICAg
-IGNhY2hlCiAgICAgICAgLmNsZWFyKCkKICAgICAgICAudGhlbigoXykgPT4gcmVzcG9uc2Uud3Jp
-dGVsbignQ2xlYXJlZCBjYWNoZSEnKSkKICAgICAgICAud2hlbkNvbXBsZXRlKHJlc3BvbnNlLmNs
-b3NlKTsKICB9IGVsc2UgewogICAgLy8gU2VydmUgc29tZSBzdGF0aWMgY29udGVudC4gVGhpcyBt
-dXN0IGJlIGxvY2F0ZWQgaW4gJ2J1aWxkL3dlYicgb3Igc29tZQogICAgLy8gc3ViZGlyZWN0b3J5
-IG9mICdidWlsZC93ZWInLgogICAgY29udGV4dC5hc3NldHMuc2VydmUoJy91c2FnZS5odG1sJyk7
-CiAgfQp9Cg==""",
-  "build/web/usage.html",
+YXJ0OmFzeW5jJzsKCmltcG9ydCAncGFja2FnZTpzaGVsZi9zaGVsZi5kYXJ0JzsKaW1wb3J0ICdw
+YWNrYWdlOnNoZWxmX2FwcGVuZ2luZS9zaGVsZl9hcHBlbmdpbmUuZGFydCcgYXMgc2hlbGZfYWU7
+CmltcG9ydCAncGFja2FnZTp7e3Byb2plY3ROYW1lfX0vbWVtY2FjaGUuZGFydCcgYXMgY2FjaGU7
+CgovLy8gQXBwbGljYXRpb24gZW50cnkgcG9pbnQgY2FsbGVkIGJ5IEFwcEVuZ2luZSBhdCBzdGFy
+dHVwLgptYWluKExpc3Q8U3RyaW5nPiBhcmdzKSBhc3luYyB7CiAgdmFyIHBvcnRBcmdzID0gYXJn
+cy53aGVyZSgoYSkgPT4gYS5zdGFydHNXaXRoKCctLXBvcnQ9JykpLnRvTGlzdCgpOwoKICBpbnQg
+cG9ydCA9IDgwODA7CiAgaWYgKHBvcnRBcmdzLmxlbmd0aCA9PSAxKSB7CiAgICB2YXIgcG9ydEFy
+ZyA9IHBvcnRBcmdzLnNpbmdsZS5zdWJzdHJpbmcoNyk7CiAgICBwb3J0ID0gaW50LnBhcnNlKHBv
+cnRBcmcpOwogIH0KCiAgdmFyIGNhc2NhZGUgPSBuZXcgQ2FzY2FkZSgpLmFkZChfaGFuZGxlciku
+YWRkKHNoZWxmX2FlLmFzc2V0SGFuZGxlcigKICAgICAgZGlyZWN0b3J5SW5kZXhTZXJ2ZU1vZGU6
+IHNoZWxmX2FlLkRpcmVjdG9yeUluZGV4U2VydmVNb2RlLlNFUlZFKSk7CgogIGF3YWl0IHNoZWxm
+X2FlLnNlcnZlKGNhc2NhZGUuaGFuZGxlciwgcG9ydDogcG9ydCk7Cn0KCkZ1dHVyZTxSZXNwb25z
+ZT4gX2hhbmRsZXIoUmVxdWVzdCByZXF1ZXN0KSBhc3luYyB7CiAgYXdhaXQgY2FjaGUuaW5pdGlh
+bGl6ZSgpOwoKICBpZiAocmVxdWVzdC5tZXRob2QgIT0gIkdFVCIpIHsKICAgIHJldHVybiBuZXcg
+UmVzcG9uc2UuZm9yYmlkZGVuKAogICAgICAgICdVbnN1cHBvcnRlZCBIVFRQIHJlcXVlc3QgbWV0
+aG9kOiAke3JlcXVlc3QubWV0aG9kfScpOwogIH0KCiAgaWYgKHJlcXVlc3QudXJsLnBhdGhTZWdt
+ZW50cy5sZW5ndGggPT0gMSkgewogICAgc3dpdGNoIChyZXF1ZXN0LnVybC5wYXRoU2VnbWVudHMu
+c2luZ2xlKSB7CiAgICAgIGNhc2UgJ3dyaXRlX2NhY2hlJzoKICAgICAgICByZXR1cm4gX3dyaXRl
+Q2FjaGUocmVxdWVzdC51cmwucXVlcnlQYXJhbWV0ZXJzKTsKICAgICAgY2FzZSAncmVhZF9jYWNo
+ZSc6CiAgICAgICAgcmV0dXJuIF9yZWFkQ2FjaGUocmVxdWVzdC51cmwucXVlcnlQYXJhbWV0ZXJz
+KTsKICAgICAgY2FzZSAnY2xlYXJfY2FjaGUnOgogICAgICAgIHJldHVybiBfY2xlYXIoKTsKICAg
+IH0KICB9CgogIHJldHVybiBuZXcgUmVzcG9uc2Uubm90Rm91bmQoJ3NvcnJ5Li4uJyk7Cn0KCkZ1
+dHVyZTxSZXNwb25zZT4gX3JlYWRDYWNoZShNYXA8U3RyaW5nLCBTdHJpbmc+IHBhcmFtZXRlcnMp
+IGFzeW5jIHsKICB2YXIga2V5cyA9IHBhcmFtZXRlcnMua2V5cy50b0xpc3QoKTsKCiAgdmFyIG91
+dHB1dCA9IG5ldyBTdHJpbmdCdWZmZXIoKTsKCiAgaWYgKGtleXMuaXNFbXB0eSkgewogICAgb3V0
+cHV0LndyaXRlbG4oCiAgICAgICAgJ1JlYWRpbmcgZGVmYXVsdCBrZXkgKCR7Y2FjaGUuREVGQVVM
+VF9LRVl9KSwgc2luY2Ugbm8ga2V5cyBwcm92aWRlZC4nKTsKICAgIG91dHB1dC53cml0ZWxuKCcn
+KTsKICAgIGtleXMgPSBjb25zdCBbY2FjaGUuREVGQVVMVF9LRVldOwogIH0gZWxzZSB7CiAgICBv
+dXRwdXQud3JpdGVsbignUmVhZGluZyAke3BhcmFtZXRlcnMubGVuZ3RofSB2YWx1ZShzKSBmcm9t
+IGNhY2hlLicpOwogICAgb3V0cHV0LndyaXRlbG4oJycpOwogIH0KCiAgYXdhaXQgY2FjaGUucmVh
+ZChrZXlzLCBvdXRwdXQpOwoKICByZXR1cm4gbmV3IFJlc3BvbnNlLm9rKG91dHB1dC50b1N0cmlu
+ZygpKTsKfQoKRnV0dXJlPFJlc3BvbnNlPiBfd3JpdGVDYWNoZShNYXA8U3RyaW5nLCBTdHJpbmc+
+IHBhcmFtZXRlcnMpIGFzeW5jIHsKICB2YXIgb3V0cHV0ID0gbmV3IFN0cmluZ0J1ZmZlcigpOwoK
+ICAvLyBVcGRhdGUgdGhlIGNhY2hlIHdpdGggdGhlIGdpdmVuIGtleS92YWx1ZSBwYWlycy4KICBv
+dXRwdXQud3JpdGVsbignVXBkYXRpbmcgY2FjaGUgd2l0aCAke3BhcmFtZXRlcnMubGVuZ3RofSB2
+YWx1ZShzKS4nKTsKICBvdXRwdXQud3JpdGVsbignJyk7CgogIGF3YWl0IGNhY2hlLndyaXRlKHBh
+cmFtZXRlcnMsIG91dHB1dCk7CgogIHJldHVybiBuZXcgUmVzcG9uc2Uub2sob3V0cHV0LnRvU3Ry
+aW5nKCkpOwp9CgpGdXR1cmU8UmVzcG9uc2U+IF9jbGVhcigpIGFzeW5jIHsKICBhd2FpdCBjYWNo
+ZS5jbGVhcigpOwogIHJldHVybiBuZXcgUmVzcG9uc2Uub2soJ0NsZWFyZWQgY2FjaGUhJyk7Cn0K""",
+  "build/web/index.html",
   "text",
   """PCFET0NUWVBFIGh0bWw+Cgo8aHRtbD4KICA8aGVhZD4KICAJPG1ldGEgY2hhcnNldD0idXRmLTgi
 PgogICAgPHRpdGxlPnt7cHJvamVjdE5hbWV9fTwvdGl0bGU+CiAgPC9oZWFkPgoKICA8Ym9keT4K
@@ -126,39 +116,38 @@ aW5pdGlhbCBrZXkvdmFsdWUgcGFpci4KICAgIDwvcHJlPgogIDwvYm9keT4KPC9odG1sPgo=""",
   """Ly8gQ29weXJpZ2h0IChjKSB7e3llYXJ9fSwge3thdXRob3J9fS4gQWxsIHJpZ2h0cyByZXNlcnZl
 ZC4gVXNlIG9mIHRoaXMgc291cmNlIGNvZGUKLy8gaXMgZ292ZXJuZWQgYnkgYSBCU0Qtc3R5bGUg
 bGljZW5zZSB0aGF0IGNhbiBiZSBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlLgoKbGlicmFyeSB7
-e3Byb2plY3ROYW1lfX0ubWVtY2FjaGU7CgppbXBvcnQgJ2RhcnQ6YXN5bmMnOwppbXBvcnQgJ2Rh
-cnQ6aW8nOwoKaW1wb3J0ICdwYWNrYWdlOmFwcGVuZ2luZS9hcHBlbmdpbmUuZGFydCc7Cgpjb25z
-dCBTdHJpbmcgREVGQVVMVF9LRVkgPSAnaGVsbG8nOwpib29sIGNhY2hlSW5pdGlhbGl6ZWQgPSBm
-YWxzZTsKCi8vLyBJbml0aWFsaXplIHRoZSBjYWNoZS4KRnV0dXJlIGluaXRpYWxpemUoKSBhc3lu
-YyB7CiAgLy8gSWYgdGhlIGNhY2hlIGlzIGFscmVhZHkgaW5pdGlhbGl6ZWQsIGp1c3QgcmV0dXJu
-LgogIGlmIChjYWNoZUluaXRpYWxpemVkKSByZXR1cm47CgogIC8vIFRoZSBBcHBFbmdpbmUgZW52
-aXJvbm1lbnQgaGFzIGEgcHJlY29uZmlndXJlZCAnY29udGV4dCcgd2hpY2ggcHJvdmlkZXMKICAv
-LyBhdXRob3JpemVkIGFjY2VzcyB0byB0aGUgZGVmYXVsdCBhcGkgc2VydmljZXMuCiAgdmFyIG1l
-bWNhY2hlID0gY29udGV4dC5zZXJ2aWNlcy5tZW1jYWNoZTsKCiAgLy8gSW5pdGlhbGl6ZSB0aGUg
-Y2FjaGUgYW5kIHNldCB0aGUgZGVmYXVsdCB2YWx1ZS4KICBhd2FpdCBtZW1jYWNoZS5jbGVhcigp
-OwogIGF3YWl0IG1lbWNhY2hlLnNldChERUZBVUxUX0tFWSwgJ3RoZXJlIScpOwogIGNhY2hlSW5p
-dGlhbGl6ZWQgPSB0cnVlOwp9CgovLy8gQ2xlYXJzIHRoZSBjYWNoZSBhbmQgcmVzZXRzIHRoZSBk
-ZWZhdWx0LgpGdXR1cmUgY2xlYXIoKSBhc3luYyB7CiAgY2FjaGVJbml0aWFsaXplZCA9IGZhbHNl
-OwogIGF3YWl0IGluaXRpYWxpemUoKTsKfQoKLy8vIEhlbHBlciBtZXRob2QgdG8gd3JpdGUgYSBz
-ZXQgb2Yga2V5L3ZhbHVlIHBhaXJzIHRvIHRoZSBtZW1jYWNoZS4Kdm9pZCB3cml0ZShIdHRwUmVz
-cG9uc2UgcmVzcG9uc2UsIE1hcDxTdHJpbmcsIFN0cmluZz4gdmFsdWVNYXApIHsKICB2YXIgbWVt
-Y2FjaGUgPSBjb250ZXh0LnNlcnZpY2VzLm1lbWNhY2hlOwogIEZ1dHVyZS5mb3JFYWNoKHZhbHVl
-TWFwLmtleXMsIChrZXkpIHsKICAgIHZhciB2YWx1ZSA9IHZhbHVlTWFwW2tleV07CiAgICByZXR1
-cm4gbWVtY2FjaGUKICAgICAgICAuc2V0KGtleSwgdmFsdWUpCiAgICAgICAgLnRoZW4oKF8pID0+
-IHJlc3BvbnNlLndyaXRlbG4oJyIke2tleX0iOiAiJHt2YWx1ZX0iJykpOwogIH0pLndoZW5Db21w
-bGV0ZShyZXNwb25zZS5jbG9zZSk7Cn0KCi8vLyBIZWxwZXIgbWV0aG9kIHRvIHJlYWQgYSBzZXQg
-b2YgdmFsdWVzIGZyb20gdGhlIG1lbWNhY2hlLgp2b2lkIHJlYWQoSHR0cFJlc3BvbnNlIHJlc3Bv
-bnNlLCBJdGVyYWJsZTxTdHJpbmc+IGtleXMpIHsKICB2YXIgbWVtY2FjaGUgPSBjb250ZXh0LnNl
-cnZpY2VzLm1lbWNhY2hlOwogIHZhciBoYW5kbGVLZXkgPSAoa2V5KSA9PiBtZW1jYWNoZQogICAg
-ICAuZ2V0KGtleSkKICAgICAgLnRoZW4oKHZhbHVlKSA9PiByZXNwb25zZS53cml0ZWxuKCciJHtr
-ZXl9IjogIiR7dmFsdWV9IicpKQogICAgICAuY2F0Y2hFcnJvcigoXykgPT4gcmVzcG9uc2Uud3Jp
-dGVsbignIiR7a2V5fSI6IHZhbHVlIG5vdCBmb3VuZCEnKSk7CiAgRnV0dXJlLmZvckVhY2goa2V5
-cywgaGFuZGxlS2V5KS53aGVuQ29tcGxldGUocmVzcG9uc2UuY2xvc2UpOwp9Cg==""",
+e3Byb2plY3ROYW1lfX0ubWVtY2FjaGU7CgppbXBvcnQgJ2RhcnQ6YXN5bmMnOwoKaW1wb3J0ICdw
+YWNrYWdlOmFwcGVuZ2luZS9hcHBlbmdpbmUuZGFydCc7Cgpjb25zdCBTdHJpbmcgREVGQVVMVF9L
+RVkgPSAnaGVsbG8nOwpib29sIGNhY2hlSW5pdGlhbGl6ZWQgPSBmYWxzZTsKCi8vLyBJbml0aWFs
+aXplIHRoZSBjYWNoZS4KRnV0dXJlIGluaXRpYWxpemUoKSBhc3luYyB7CiAgLy8gSWYgdGhlIGNh
+Y2hlIGlzIGFscmVhZHkgaW5pdGlhbGl6ZWQsIGp1c3QgcmV0dXJuLgogIGlmIChjYWNoZUluaXRp
+YWxpemVkKSByZXR1cm47CgogIC8vIFRoZSBBcHBFbmdpbmUgZW52aXJvbm1lbnQgaGFzIGEgcHJl
+Y29uZmlndXJlZCAnY29udGV4dCcgd2hpY2ggcHJvdmlkZXMKICAvLyBhdXRob3JpemVkIGFjY2Vz
+cyB0byB0aGUgZGVmYXVsdCBhcGkgc2VydmljZXMuCiAgdmFyIG1lbWNhY2hlID0gY29udGV4dC5z
+ZXJ2aWNlcy5tZW1jYWNoZTsKCiAgLy8gSW5pdGlhbGl6ZSB0aGUgY2FjaGUgYW5kIHNldCB0aGUg
+ZGVmYXVsdCB2YWx1ZS4KICBhd2FpdCBtZW1jYWNoZS5jbGVhcigpOwogIGF3YWl0IG1lbWNhY2hl
+LnNldChERUZBVUxUX0tFWSwgJ3RoZXJlIScpOwogIGNhY2hlSW5pdGlhbGl6ZWQgPSB0cnVlOwp9
+CgovLy8gQ2xlYXJzIHRoZSBjYWNoZSBhbmQgcmVzZXRzIHRoZSBkZWZhdWx0LgpGdXR1cmUgY2xl
+YXIoKSBhc3luYyB7CiAgY2FjaGVJbml0aWFsaXplZCA9IGZhbHNlOwogIGF3YWl0IGluaXRpYWxp
+emUoKTsKfQoKLy8vIEhlbHBlciBtZXRob2QgdG8gd3JpdGUgYSBzZXQgb2Yga2V5L3ZhbHVlIHBh
+aXJzIHRvIHRoZSBtZW1jYWNoZS4KRnV0dXJlIHdyaXRlKE1hcDxTdHJpbmcsIFN0cmluZz4gdmFs
+dWVNYXAsIFN0cmluZ1NpbmsgYnVmZmVyKSBhc3luYyB7CiAgdmFyIG1lbWNhY2hlID0gY29udGV4
+dC5zZXJ2aWNlcy5tZW1jYWNoZTsKCiAgZm9yICh2YXIga2V5IGluIHZhbHVlTWFwLmtleXMpIHsK
+ICAgIHZhciB2YWx1ZSA9IHZhbHVlTWFwW2tleV07CgogICAgYXdhaXQgbWVtY2FjaGUuc2V0KGtl
+eSwgdmFsdWUpOwoKICAgIGJ1ZmZlci53cml0ZWxuKCcke2tleX06ICR7RXJyb3Iuc2FmZVRvU3Ry
+aW5nKHZhbHVlKX0nKTsKICB9Cn0KCi8vLyBIZWxwZXIgbWV0aG9kIHRvIHJlYWQgYSBzZXQgb2Yg
+dmFsdWVzIGZyb20gdGhlIG1lbWNhY2hlLgpGdXR1cmUgcmVhZChJdGVyYWJsZTxTdHJpbmc+IGtl
+eXMsIFN0cmluZ1NpbmsgYnVmZmVyICkgYXN5bmMgewogIHZhciBtZW1jYWNoZSA9IGNvbnRleHQu
+c2VydmljZXMubWVtY2FjaGU7CgogIGZvciAodmFyIGtleSBpbiBrZXlzKSB7CiAgICB0cnkgewog
+ICAgICB2YXIgdmFsdWUgPSBhd2FpdCBtZW1jYWNoZS5nZXQoa2V5KTsKICAgICAgYnVmZmVyLndy
+aXRlbG4oJyR7a2V5fTogJHtFcnJvci5zYWZlVG9TdHJpbmcodmFsdWUpfScpOwogICAgfSBjYXRj
+aCAoXykgewogICAgICBidWZmZXIud3JpdGVsbignIiR7a2V5fSI6IGVycm9yIHJlYWRpbmcga2V5
+IScpOwogICAgfQogIH0KfQo=""",
   "pubspec.yaml",
   "text",
   """bmFtZToge3twcm9qZWN0TmFtZX19CnZlcnNpb246IDAuMC4xCmRlc2NyaXB0aW9uOiBBIHNpbXBs
 ZSBBcHAgRW5naW5lIGFwcGxpY2F0aW9uLgojYXV0aG9yOiB7e2F1dGhvcn19IDxlbWFpbEBleGFt
 cGxlLmNvbT4KI2hvbWVwYWdlOiBodHRwczovL3d3dy5leGFtcGxlLmNvbQoKZW52aXJvbm1lbnQ6
 CiAgc2RrOiAnPj0xLjkuMCA8Mi4wLjAnCgpkZXBlbmRlbmNpZXM6CiAgYXBwZW5naW5lOiAnPj0w
-LjMuMCA8MC40LjAnCg=="""
+LjMuMCA8MC40LjAnCiAgc2hlbGY6IF4wLjYuMAogIHNoZWxmX2FwcGVuZ2luZTogXjAuMi4zCg=="""
 ];
diff --git a/templates/server-appengine/.gitignore b/templates/server-appengine/.gitignore
index 8afd37e..4232a2f 100644
--- a/templates/server-appengine/.gitignore
+++ b/templates/server-appengine/.gitignore
@@ -1,8 +1,4 @@
-.buildlog
-.DS_Store
-.idea
 .packages
 .pub/
-build/
 packages
 pubspec.lock
diff --git a/templates/server-appengine/app.yaml b/templates/server-appengine/app.yaml
index 7c562fb..63f4d16 100644
--- a/templates/server-appengine/app.yaml
+++ b/templates/server-appengine/app.yaml
@@ -1,8 +1,5 @@
-version: v1
+# Information on configuring app.yaml
+# https://cloud.google.com/appengine/docs/managed-vms/config
 runtime: custom
 vm: true
 api_version: 1
-threadsafe: true
-
-manual_scaling:
-  instances: 1
diff --git a/templates/server-appengine/bin/server.dart b/templates/server-appengine/bin/server.dart
index a2557f2..ebc5908 100644
--- a/templates/server-appengine/bin/server.dart
+++ b/templates/server-appengine/bin/server.dart
@@ -2,76 +2,82 @@
 // is governed by a BSD-style license that can be found in the LICENSE file.
 
 import 'dart:async';
-import 'dart:io';
 
-import 'package:appengine/appengine.dart';
+import 'package:shelf/shelf.dart';
+import 'package:shelf_appengine/shelf_appengine.dart' as shelf_ae;
 import 'package:{{projectName}}/memcache.dart' as cache;
 
-/// Application entrypoint called by AppEngine at startup.
-main() {
-  // Setup AppEngine and register an HTTP request handler.
-  runAppEngine(requestHandler);
+/// Application entry point called by AppEngine at startup.
+main(List<String> args) async {
+  var portArgs = args.where((a) => a.startsWith('--port=')).toList();
+
+  int port = 8080;
+  if (portArgs.length == 1) {
+    var portArg = portArgs.single.substring(7);
+    port = int.parse(portArg);
+  }
+
+  var cascade = new Cascade().add(_handler).add(shelf_ae.assetHandler(
+      directoryIndexServeMode: shelf_ae.DirectoryIndexServeMode.SERVE));
+
+  await shelf_ae.serve(cascade.handler, port: port);
 }
 
-/// The main HTTP request handler.
-void requestHandler(HttpRequest request) {
-  // Initialize the application. This is done here since we can only access
-  // the AppEngine APIs when in the context of a request. To avoid initializing
-  // an already initialized app it is guarded by the [cacheInitialized] bool.
-  var initialized = new Future.sync(cache.initialize);
-
-  initialized.then((_) {
-    // We only handle GET requests in this simple example.
-    if (request.method == 'GET') {
-      handleGetRequest(request);
-    } else {
-      request.response
-        ..statusCode = HttpStatus.METHOD_NOT_ALLOWED
-        ..write('Unsupported HTTP request method: ${request.method}.')
-        ..close();
+Future<Response> _handler(Request request) async {
+  await cache.initialize();
+
+  if (request.method != "GET") {
+    return new Response.forbidden(
+        'Unsupported HTTP request method: ${request.method}');
+  }
+
+  if (request.url.pathSegments.length == 1) {
+    switch (request.url.pathSegments.single) {
+      case 'write_cache':
+        return _writeCache(request.url.queryParameters);
+      case 'read_cache':
+        return _readCache(request.url.queryParameters);
+      case 'clear_cache':
+        return _clear();
     }
-  }).catchError((_) => request.response
-    ..write('Failed handling request: ${request.toString()}.')
-    ..close());
+  }
+
+  return new Response.notFound('sorry...');
 }
 
-/// GET request handler.
-///
-/// Parses the url to determine what command to run and the corresponding
-/// input data.
-handleGetRequest(HttpRequest request) {
-  HttpResponse response = request.response;
-  // Determine command.
-  if (request.uri.path == '/write_cache') {
-    // Get the parsed query string.
-    Map<String, String> queryMap = request.uri.queryParameters;
-    // Update the cache with the given key/value pairs.
-    response.writeln('Updating cache with ${queryMap.length} value(s).');
-    response.writeln('');
-    cache.write(response, queryMap);
-  } else if (request.uri.path == '/read_cache') {
-    // If no query string is given return the default key's value.
-    if (!request.uri.hasQuery) {
-      response.writeln('Reading default value, since no keys provided.');
-      response.writeln('');
-      cache.read(response, [cache.DEFAULT_KEY]);
-      return;
-    }
-    // Get the parsed query string.
-    Map<String, String> queryMap = request.uri.queryParameters;
-    // Read out the values corresponding to the keys in the query string.
-    response.writeln('Reading ${queryMap.length} value(s) from cache.');
-    response.writeln('');
-    cache.read(response, queryMap.keys);
-  } else if (request.uri.path == '/clear_cache') {
-    // Reintialize the cache. This clears all values and resets the default.
-    cache
-        .clear()
-        .then((_) => response.writeln('Cleared cache!'))
-        .whenComplete(response.close);
+Future<Response> _readCache(Map<String, String> parameters) async {
+  var keys = parameters.keys.toList();
+
+  var output = new StringBuffer();
+
+  if (keys.isEmpty) {
+    output.writeln(
+        'Reading default key (${cache.DEFAULT_KEY}), since no keys provided.');
+    output.writeln('');
+    keys = const [cache.DEFAULT_KEY];
   } else {
-    // Serve some static content. This must be located in 'build/web' or some
-    // subdirectory of 'build/web'.
-    context.assets.serve('/usage.html');
+    output.writeln('Reading ${parameters.length} value(s) from cache.');
+    output.writeln('');
   }
+
+  await cache.read(keys, output);
+
+  return new Response.ok(output.toString());
+}
+
+Future<Response> _writeCache(Map<String, String> parameters) async {
+  var output = new StringBuffer();
+
+  // Update the cache with the given key/value pairs.
+  output.writeln('Updating cache with ${parameters.length} value(s).');
+  output.writeln('');
+
+  await cache.write(parameters, output);
+
+  return new Response.ok(output.toString());
+}
+
+Future<Response> _clear() async {
+  await cache.clear();
+  return new Response.ok('Cleared cache!');
 }
diff --git a/templates/server-appengine/build/web/usage.html b/templates/server-appengine/build/web/index.html
similarity index 100%
rename from templates/server-appengine/build/web/usage.html
rename to templates/server-appengine/build/web/index.html
diff --git a/templates/server-appengine/lib/memcache.dart b/templates/server-appengine/lib/memcache.dart
index 4e97eae..e9574d7 100644
--- a/templates/server-appengine/lib/memcache.dart
+++ b/templates/server-appengine/lib/memcache.dart
@@ -4,7 +4,6 @@
 library {{projectName}}.memcache;
 
 import 'dart:async';
-import 'dart:io';
 
 import 'package:appengine/appengine.dart';
 
@@ -33,22 +32,28 @@ Future clear() async {
 }
 
 /// Helper method to write a set of key/value pairs to the memcache.
-void write(HttpResponse response, Map<String, String> valueMap) {
+Future write(Map<String, String> valueMap, StringSink buffer) async {
   var memcache = context.services.memcache;
-  Future.forEach(valueMap.keys, (key) {
+
+  for (var key in valueMap.keys) {
     var value = valueMap[key];
-    return memcache
-        .set(key, value)
-        .then((_) => response.writeln('"${key}": "${value}"'));
-  }).whenComplete(response.close);
+
+    await memcache.set(key, value);
+
+    buffer.writeln('${key}: ${Error.safeToString(value)}');
+  }
 }
 
 /// Helper method to read a set of values from the memcache.
-void read(HttpResponse response, Iterable<String> keys) {
+Future read(Iterable<String> keys, StringSink buffer ) async {
   var memcache = context.services.memcache;
-  var handleKey = (key) => memcache
-      .get(key)
-      .then((value) => response.writeln('"${key}": "${value}"'))
-      .catchError((_) => response.writeln('"${key}": value not found!'));
-  Future.forEach(keys, handleKey).whenComplete(response.close);
+
+  for (var key in keys) {
+    try {
+      var value = await memcache.get(key);
+      buffer.writeln('${key}: ${Error.safeToString(value)}');
+    } catch (_) {
+      buffer.writeln('"${key}": error reading key!');
+    }
+  }
 }
diff --git a/templates/server-appengine/pubspec.yaml b/templates/server-appengine/pubspec.yaml
index 260abc4..f8922e1 100644
--- a/templates/server-appengine/pubspec.yaml
+++ b/templates/server-appengine/pubspec.yaml
@@ -9,3 +9,5 @@ environment:
 
 dependencies:
   appengine: '>=0.3.0 <0.4.0'
+  shelf: ^0.6.0
+  shelf_appengine: ^0.2.3
-- 
GitLab