Merge "veyron/services/mgmt/debug: Add debug server"
diff --git a/examples/bank/schema/schema.vdl b/examples/bank/schema/schema.vdl
index 0a34090..2614d00 100644
--- a/examples/bank/schema/schema.vdl
+++ b/examples/bank/schema/schema.vdl
@@ -1,13 +1,9 @@
 package schema
 
 // Dir is used to represent directories.
-type Dir struct{
-	// TODO(jyh): The IDL does not recognize empty structs.  Fix it and remove this
-	// useless field.
-	X byte
-}
+type Dir struct{}
 
 // Bank is used to represent the information stored in a bank.
 type Bank struct {
-        Accounts map[string]int64
+	Accounts map[string]int64
 }
diff --git a/examples/bank/schema/schema.vdl.go b/examples/bank/schema/schema.vdl.go
index 8d51fc8..78fd25d 100644
--- a/examples/bank/schema/schema.vdl.go
+++ b/examples/bank/schema/schema.vdl.go
@@ -5,9 +5,6 @@
 
 // Dir is used to represent directories.
 type Dir struct {
-	// TODO(jyh): The IDL does not recognize empty structs.  Fix it and remove this
-	// useless field.
-	X byte
 }
 
 // Bank is used to represent the information stored in a bank.
diff --git a/examples/mdb/schema/schema.vdl b/examples/mdb/schema/schema.vdl
index 5862583..01e96dc 100644
--- a/examples/mdb/schema/schema.vdl
+++ b/examples/mdb/schema/schema.vdl
@@ -5,11 +5,7 @@
 )
 
 // Dir is used to represent directories.
-type Dir struct{
-	// TODO(jyh): The IDL does not recognize empty structs.  Fix it and remove this
-	// useless field.
-	X byte
-}
+type Dir struct{}
 
 // Movie represents a movie.
 type Movie struct {
diff --git a/examples/mdb/schema/schema.vdl.go b/examples/mdb/schema/schema.vdl.go
index 860e75c..f270d44 100644
--- a/examples/mdb/schema/schema.vdl.go
+++ b/examples/mdb/schema/schema.vdl.go
@@ -9,9 +9,6 @@
 
 // Dir is used to represent directories.
 type Dir struct {
-	// TODO(jyh): The IDL does not recognize empty structs.  Fix it and remove this
-	// useless field.
-	X byte
 }
 
 // Movie represents a movie.
diff --git a/examples/mdb/templates/contents.json b/examples/mdb/templates/contents.json
index 7db56dd..9d72b6b 100644
--- a/examples/mdb/templates/contents.json
+++ b/examples/mdb/templates/contents.json
@@ -1,72 +1,89 @@
 {
   "People": {
-    "P1": { "Name": "Catherine Deneuve",
+    "P1": {
+	    "Name": "Catherine Deneuve",
 	    "BirthDate": "22/10/1943",
 	    "Image": "http://upload.wikimedia.org/wikipedia/commons/thumb/b/bc/Catherine_Deneuve_1995.jpg/388px-Catherine_Deneuve_1995.jpg"
 	  },
-    "P2": { "Name": "Nino Castelnuovo",
+    "P2": {
+	    "Name": "Nino Castelnuovo",
 	    "BirthDate": "28/10/1936",
 	    "Image": "http://upload.wikimedia.org/wikipedia/commons/4/4f/Quella_et%C3%A0_maliziosa.png"
 	  },
-    "P3": { "Name": "Anne Vernon",
+    "P3": {
+	    "Name": "Anne Vernon",
 	    "BirthDate": "24/1/1925",
 	    "Image": "http://upload.wikimedia.org/wikipedia/commons/6/6e/Anne_Vernon_1957.jpg"
 	  },
-    "P4": { "Name": "Marc Michel",
+    "P4": {
+	    "Name": "Marc Michel",
 	    "BirthDate": "4/12/1932"
 	  },
-    "P5": { "Name": "Leonardo DiCaprio",
+    "P5": {
+	    "Name": "Leonardo DiCaprio",
 	    "BirthDate": "11/11/1974",
 	    "Image": "http://upload.wikimedia.org/wikipedia/commons/thumb/4/4b/Leonardo_DiCaprio_%28Berlin_Film_Festival_2010%29_2_%28cropped%29.jpg/711px-Leonardo_DiCaprio_%28Berlin_Film_Festival_2010%29_2_%28cropped%29.jpg"
 	  },
-    "P6": { "Name": "Claire Danes",
+    "P6": {
+	    "Name": "Claire Danes",
 	    "BirthDate": "4/12/1979",
 	    "Image": "http://upload.wikimedia.org/wikipedia/commons/thumb/3/32/Claire_Danes_2012_Shankbone.JPG/479px-Claire_Danes_2012_Shankbone.JPG"
 	  },
-    "P7": { "Name": "John Leguizamo",
+    "P7": {
+	    "Name": "John Leguizamo",
 	    "BirthDate": "6/22/1964",
 	    "Image": "http://upload.wikimedia.org/wikipedia/commons/7/7c/John_Leguizamo_by_Gage_Skidmore.jpg"
 	  },
-    "P8": { "Name": "Harold Perrineau",
+    "P8": {
+	    "Name": "Harold Perrineau",
 	    "BirthDate": "8/7/1963",
 	    "Image": "http://upload.wikimedia.org/wikipedia/commons/thumb/3/3c/Harold_Perrineau%2C_Jr.jpg/549px-Harold_Perrineau%2C_Jr.jpg"
 	  },
-    "P9": { "Name": "Joseph Gordon-Levitt",
+    "P9": {
+	    "Name": "Joseph Gordon-Levitt",
 	    "BirthDate": "17/2/1981",
 	    "Image": "http://upload.wikimedia.org/wikipedia/commons/thumb/d/d3/Joseph_Gordon-Levitt.jpg/480px-Joseph_Gordon-Levitt.jpg"
 	  },
-    "P10": { "Name": "Ellen Page",
-	     "BirthDate": "21/2/1987",
-	     "Image": "http://upload.wikimedia.org/wikipedia/commons/thumb/0/07/Ellen_Page_at_TIFF_2009_cropped.jpg/449px-Ellen_Page_at_TIFF_2009_cropped.jpg"
-	   },
-    "P11": { "Name": "Michael Caine",
-	     "BirthDate": "14/3/1933",
-	     "Image": "http://upload.wikimedia.org/wikipedia/commons/thumb/e/e6/Michael_Caine_-_Viennale_2012_a.jpg/400px-Michael_Caine_-_Viennale_2012_a.jpg"
-	   },
-    "P12": { "Name": "Jacques Demy",
-	     "BirthDate": "5/6/1931",
-	     "Image": "http://upload.wikimedia.org/wikipedia/en/3/3a/Jacques_Demy.jpg"
-	   },
-    "P13": { "Name": "Baz Luhrmann",
-	     "BirthDate": "17/9/1962",
-	     "Image": "http://upload.wikimedia.org/wikipedia/commons/thumb/5/56/Baz_Luhrmann.jpg/399px-Baz_Luhrmann.jpg"
-	   },
-    "P14": { "Name": "Christopher Nolan",
-	     "BirthDate": "30/7/1970",
-	     "Image": "http://upload.wikimedia.org/wikipedia/commons/thumb/c/c4/Christopher_Nolan%2C_London%2C_2013_%28crop%29.jpg/409px-Christopher_Nolan%2C_London%2C_2013_%28crop%29.jpg"
-	   },
-    "P15": { "Name": "Jason Reitman",
-	     "BirthDate": "19/10/1977",
-	     "Image": "http://upload.wikimedia.org/wikipedia/commons/thumb/a/a8/Jason_Reitman_2013_TIFF.jpg/428px-Jason_Reitman_2013_TIFF.jpg"
-	   },
-    "P16": { "Name": "John Lasseter",
-	     "BirthDate": "12/1/1957",
-	     "Image": "http://upload.wikimedia.org/wikipedia/commons/thumb/b/b0/JohnLasseterOct2011.jpg/512px-JohnLasseterOct2011.jpg"
-	   }
+    "P10": {
+	    "Name": "Ellen Page",
+	    "BirthDate": "21/2/1987",
+	    "Image": "http://upload.wikimedia.org/wikipedia/commons/thumb/0/07/Ellen_Page_at_TIFF_2009_cropped.jpg/449px-Ellen_Page_at_TIFF_2009_cropped.jpg"
+	  },
+    "P11": {
+	    "Name": "Michael Caine",
+	    "BirthDate": "14/3/1933",
+	    "Image": "http://upload.wikimedia.org/wikipedia/commons/thumb/e/e6/Michael_Caine_-_Viennale_2012_a.jpg/400px-Michael_Caine_-_Viennale_2012_a.jpg"
+	  },
+    "P12": {
+	    "Name": "Jacques Demy",
+	    "BirthDate": "5/6/1931",
+	    "Image": "http://upload.wikimedia.org/wikipedia/en/3/3a/Jacques_Demy.jpg"
+	  },
+    "P13": {
+	    "Name": "Baz Luhrmann",
+	    "BirthDate": "17/9/1962",
+	    "Image": "http://upload.wikimedia.org/wikipedia/commons/thumb/5/56/Baz_Luhrmann.jpg/399px-Baz_Luhrmann.jpg"
+	  },
+    "P14": {
+	    "Name": "Christopher Nolan",
+	    "BirthDate": "30/7/1970",
+	    "Image": "http://upload.wikimedia.org/wikipedia/commons/thumb/c/c4/Christopher_Nolan%2C_London%2C_2013_%28crop%29.jpg/409px-Christopher_Nolan%2C_London%2C_2013_%28crop%29.jpg"
+	  },
+    "P15": {
+	    "Name": "Jason Reitman",
+	    "BirthDate": "19/10/1977",
+	    "Image": "http://upload.wikimedia.org/wikipedia/commons/thumb/a/a8/Jason_Reitman_2013_TIFF.jpg/428px-Jason_Reitman_2013_TIFF.jpg"
+	  },
+    "P16": {
+	    "Name": "John Lasseter",
+	    "BirthDate": "12/1/1957",
+	    "Image": "http://upload.wikimedia.org/wikipedia/commons/thumb/b/b0/JohnLasseterOct2011.jpg/512px-JohnLasseterOct2011.jpg"
+	  }
   },
 
   "Movies": {
-    "M1": { "Title": "The Umbrellas of Cherbourg",
+    "M1": {
+      "Title": "The Umbrellas of Cherbourg",
 	    "Image": "http://upload.wikimedia.org/wikipedia/en/3/39/ParapluiePoster.jpg",
 	    "Summary": "A young girl separated from her lover by war faces a life altering decision.",
 	    "Language": "French",
@@ -75,7 +92,8 @@
 	    "Genre": "musical",
 	    "Director": "P12"
 	  },
-    "M2": { "Title": "Romeo + Juliet",
+    "M2": {
+      "Title": "Romeo + Juliet",
 	    "Image": "http://upload.wikimedia.org/wikipedia/en/b/b4/William_shakespeares_romeo_and_juliet_movie_poster.jpg",
 	    "Summary": "Shakespeare's famous play is updated to the hip modern suburb of Verona still retaining its original dialogue.",
 	    "Language": "English",
@@ -84,7 +102,8 @@
 	    "Genre": "drama",
 	    "Director": "P13"
 	  },
-    "M3": { "Title": "Inception",
+    "M3": {
+      "Title": "Inception",
 	    "Image": "http://upload.wikimedia.org/wikipedia/en/7/7f/Inception_ver3.jpg",
 	    "Summary": "A skilled extractor is offered a chance to regain his old life as payment for a task considered to be impossible.",
 	    "Language": "English",
@@ -93,7 +112,8 @@
 	    "Genre": "action",
 	    "Director": "P14"
 	  },
-    "M4": { "Title": "Juno",
+    "M4": {
+      "Title": "Juno",
 	    "Image": "http://upload.wikimedia.org/wikipedia/en/e/ec/Junoposter2007.jpg",
 	    "Summary": "Faced with an unplanned pregnancy, an offbeat young woman makes an unusual decision regarding her unborn child.",
 	    "Language": "English",
@@ -102,7 +122,8 @@
 	    "Genre": "comedy",
 	    "Director": "P15"
 	  },
-    "M5": { "Title": "Cars 2",
+    "M5": {
+      "Title": "Cars 2",
 	    "Image": "http://upload.wikimedia.org/wikipedia/en/7/7f/Cars_2_Poster.jpg",
 	    "Summary": "Star race car Lightning McQueen and his pal Mater head overseas to compete in the World Grand Prix race. But the road to the championship becomes rocky as Mater gets caught up in an intriguing adventure of his own: international espionage.",
 	    "Language": "English",
diff --git a/examples/mdb/templates/css/movie.css b/examples/mdb/templates/css/movie.css
index eeb3043..dff45e5 100644
--- a/examples/mdb/templates/css/movie.css
+++ b/examples/mdb/templates/css/movie.css
@@ -1,83 +1,83 @@
 body {
-    font-family: sans-serif;
+  font-family: sans-serif;
 }
 .title {
-    font-weight: bolder;
-    font-size: 5em;
-    font-family: Gill Sans Extrabold, sans-serif;
-    font-style: oblique;
+  font-weight: bolder;
+  font-size: 5em;
+  font-family: Gill Sans Extrabold, sans-serif;
+  font-style: oblique;
 }
 .genre {
-    font-family: sans-serif;
-    font-style: oblique;
+  font-family: sans-serif;
+  font-style: oblique;
 }
 .debug {
-    font-style: oblique;
-    color: gray;
+  font-style: oblique;
+  color: gray;
 }
 .castbox {
-    border: 1px solid #bbb;
-    border-radius: 10px;
-    background-color: #fbfbfb;
-    width: 95%;
+  border: 1px solid #bbb;
+  border-radius: 10px;
+  background-color: #fbfbfb;
+  width: 95%;
 }
 .cast {
-    border-collapse: collapse;
-    background-color: white;
-    margin: 5px;
-    width: 98%;
+  border-collapse: collapse;
+  background-color: white;
+  margin: 5px;
+  width: 98%;
 }
 .cast tr {
-    margin: 5px;
-    height: 32px;
+  margin: 5px;
+  height: 32px;
 }
 .cast tr:nth-child(even) {
-    background-color: #f6f6f5;
+  background-color: #f6f6f5;
 }
 .cast tr:nth-child(odd) {
-    background-color: #f2f2f8;
+  background-color: #f2f2f8;
 }
 .castchar {
-    width: 200px;
+  width: 200px;
 }
 .reviewbox {
-    border: 1px solid #bbb;
-    border-radius: 4px;
-    background-color: #fbfbfb;
-    margin: 5px;
-    width: 95%;
+  border: 1px solid #bbb;
+  border-radius: 4px;
+  background-color: #fbfbfb;
+  margin: 5px;
+  width: 95%;
 }
 .rating {
-    font-weight: bolder;
+  font-weight: bolder;
 }
 .reviewtext {
 }
 .moviesbox {
-    border: 1px solid #bbb;
-    border-radius: 10px;
-    background-color: #fbfbfb;
-    width: 95%;
+  border: 1px solid #bbb;
+  border-radius: 10px;
+  background-color: #fbfbfb;
+  width: 95%;
 }
 .moviestable {
-    border-collapse: collapse;
-    background-color: white;
-    margin: 5px;
-    width: 98%;
+  border-collapse: collapse;
+  background-color: white;
+  margin: 5px;
+  width: 98%;
 }
 .moviestable tr {
-    margin: 5px;
-    height: 32px;
+  margin: 5px;
+  height: 32px;
 }
 .moviestable tr:nth-child(even) {
-    background-color: #f6f6f5;
+  background-color: #f6f6f5;
 }
 .moviestable tr:nth-child(odd) {
-    background-color: #f2f2f8;
+  background-color: #f2f2f8;
 }
 .moviesentry {
 }
 .peoplebox {
-    background-color: #fbfbfb;
-    margin: 5px;
-    width: 95%;
+  background-color: #fbfbfb;
+  margin: 5px;
+  width: 95%;
 }
diff --git a/examples/mdb/templates/veyron/examples/mdb/schema/Dir.tmpl b/examples/mdb/templates/veyron/examples/mdb/schema/Dir.tmpl
index 224e03c..51bec6b 100644
--- a/examples/mdb/templates/veyron/examples/mdb/schema/Dir.tmpl
+++ b/examples/mdb/templates/veyron/examples/mdb/schema/Dir.tmpl
@@ -1,37 +1,38 @@
+<!DOCTYPE html>
 <html>
-<head>
-<title>{{.Name}}</title>
-<link rel="stylesheet" href="/css/movie.css">
-</head>
-<body>
-<p><a href="/">Home</a></p>
-{{$value := .}}
+  <head>
+    <title>{{.Name}}</title>
+    <link rel="stylesheet" href="/css/movie.css">
+  </head>
+  <body>
+    <p><a href="/">Home</a></p>
+    {{$value := .}}
 
-<!-- Movie listing -->
-{{with $value.Glob "movies/*"}}
-<div class="moviesbox">
-<h2>Movies<h2>
-<table class="moviestable">
-{{range .}}
-<tr>
-<td class="movieentry"><a href="{{.}}">{{$value.Base .}}</a>
-</tr>
-{{end}}
-</table>
-</div>
-{{end}}
+    <!-- Movie listing -->
+    {{with $value.Glob "movies/*"}}
+    <div class="moviesbox">
+      <h2>Movies</h2>
+      <table class="moviestable">
+        {{range .}}
+        <tr>
+          <td class="movieentry"><a href="{{.}}">{{$value.Base .}}</a>
+        </tr>
+        {{end}}
+      </table>
+    </div>
+    {{end}}
 
-<!-- People listing -->
-{{with $value.Glob "people/*"}}
-<h2>People</h2>
-{{range .}}
-<div class="peoplebox">
-<p><a href="{{.}}">{{$value.Base .}}</a></p>
-</div>
-{{end}}
-{{end}}
+    <!-- People listing -->
+    {{with $value.Glob "people/*"}}
+    <h2>People</h2>
+    {{range .}}
+    <div class="peoplebox">
+      <p><a href="{{.}}">{{$value.Base .}}</a></p>
+    </div>
+    {{end}}
+    {{end}}
 
-<!-- Debugging -->
-<span class="debug">{{.Name}} <a href="?raw">Raw</a></span>
-</body>
+    <!-- Debugging -->
+    <span class="debug">{{.Name}} <a href="?raw">Raw</a></span>
+  </body>
 </html>
diff --git a/examples/mdb/templates/veyron/examples/mdb/schema/Movie.tmpl b/examples/mdb/templates/veyron/examples/mdb/schema/Movie.tmpl
index a836944..7bc80e7 100644
--- a/examples/mdb/templates/veyron/examples/mdb/schema/Movie.tmpl
+++ b/examples/mdb/templates/veyron/examples/mdb/schema/Movie.tmpl
@@ -1,67 +1,69 @@
+<!DOCTYPE html>
 <html>
-<head>
-{{$title := .Value.Title}}
-{{$value := .}}
-{{$prefix := $value.Join "/movies/" $title}}
-<title>{{$title}}</title>
-<link rel="stylesheet" href="/css/movie.css">
-</head>
-<body>
-<p><a href="/">Home</a></p>
-{{$releaseDate := $value.Date .Value.ReleaseDate}}
-<p>
-<table>
-<tr>
-<td valign="top">
-<img src="{{.Value.Image}}" align="bottom">
-<td valign="top">
-<div>
-<span class="title">{{$title}}</span>
-<span class="date">({{$releaseDate.Year}})</span>
-<span class="genre">{{.Value.Genre}}</span>
-<p>
-{{$directorName := $value.Join $value.Name "Director"}}
-{{$director := $value.Get $directorName}}
-Director: <a href="{{$directorName}}">{{$director.Name}}</a>
-</div>
-</tr>
-</table>
+  <head>
+    {{$title := .Value.Title}}
+    {{$value := .}}
+    {{$prefix := $value.Join "/movies/" $title}}
+    <title>{{$title}}</title>
+    <link rel="stylesheet" href="/css/movie.css">
+  </head>
+  <body>
+    <p><a href="/">Home</a></p>
+    {{$releaseDate := $value.Date .Value.ReleaseDate}}
+    <table>
+      <tr>
+        <td valign="top">
+          <img src="{{.Value.Image}}" align="bottom">
+        </td>
+        <td valign="top">
+          <div>
+            <span class="title">{{$title}}</span>
+            <span class="date">({{$releaseDate.Year}})</span>
+            <span class="genre">{{.Value.Genre}}</span>
+            <p>
+              {{$director := $value.Get "Director"}}
+              {{$path := $value.Join $value.Name "Director"}}
+              Director: <a href="{{$path}}">{{$director.Name}}</a>
+            </p>
+          </div>
+        </td>
+      </tr>
+    </table>
 
-<!-- Table to display the cast -->
-{{with $value.Glob "Cast/*"}}
-<div class="castbox">
-<h2>Cast<h2>
-<table class="cast">
-{{range .}}
-<tr> <!-- . = /Cast/pXX -->
-{{$name := $value.Join $prefix .}}
-{{$part := $value.Get $name}}
-{{$actorName := $value.Join $name "Actor"}}
-{{$actor := $value.Get $actorName}}
-{{$path := $value.Join "/people/" $actor.Name}}
-<td class="castactor"><a href="{{$path}}">{{$actor.Name}}</a>
-<td class="castchar">{{$part.Character}}
-</tr>
-{{end}}
-</table>
-</div>
-{{end}}
+    <!-- Table to display the cast -->
+    {{with $value.Glob "Cast/*"}}
+    <div class="castbox">
+      <h2>Cast</h2>
+      <table class="cast">
+        {{range .}}
+        <tr> <!-- . = /Cast/pXX -->
+          {{$part := $value.Get .}}
+          {{$actorRelativePath := $value.Join . "Actor"}}
+          {{$actor := $value.Get $actorRelativePath}}
+          {{$path := $value.Join "/people/" $actor.Name}}
+          <td class="castactor">
+            <a href="{{$path}}">{{$actor.Name}}</a>
+          </td>
+          <td class="castchar">{{$part.Character}}</td>
+        </tr>
+        {{end}}
+      </table>
+    </div>
+    {{end}}
 
-<!-- Reviews -->
-{{with $value.Glob "Reviews/*"}}
-<h2>Reviews</h2>
-{{range .}}
-{{$reviewPath := $value.Join $prefix .}}
-{{$review := $value.Get $reviewPath}}
-<div class="reviewbox">
-<span class="rating">Rating: {{$review.Rating}}/10</span>
-<p>
-<span class="reviewtext">{{$review.Text}}</span>
-</div>
-{{end}}
-{{end}}
+    <!-- Reviews -->
+    {{with $value.Glob "Reviews/*"}}
+    <h2>Reviews</h2>
+    {{range .}}
+    {{$review := $value.Get .}}
+    <div class="reviewbox">
+      <p><span class="rating">Rating: {{$review.Rating}}/10</span></p>
+      <p><span class="reviewtext">{{$review.Text}}</span></p>
+    </div>
+    {{end}}
+    {{end}}
 
-<!-- Debugging -->
-<span class="debug">{{.Name}} <a href="?raw">Raw</a></span>
-</body>
+    <!-- Debugging -->
+    <span class="debug">{{.Name}} <a href="?raw">Raw</a></span>
+  </body>
 </html>
diff --git a/examples/mdb/templates/veyron/examples/mdb/schema/Person.tmpl b/examples/mdb/templates/veyron/examples/mdb/schema/Person.tmpl
index fed0a2b..b1bd7ab 100644
--- a/examples/mdb/templates/veyron/examples/mdb/schema/Person.tmpl
+++ b/examples/mdb/templates/veyron/examples/mdb/schema/Person.tmpl
@@ -1,29 +1,34 @@
+<!DOCTYPE html>
 <html>
-<head>
-<title>{{.Value.Name}}</title>
-<link rel="stylesheet" href="/css/movie.css">
-</head>
-<body>
-<p><a href="/">Home</a></p>
-{{$value := .}}
-<p>
-<table>
-<tr>
-<td valign="top">
-<img src="{{.Value.Image}}" align="bottom">
-<td valign="top">
-<div>
-<span class="title">{{.Value.Name}}</span>
-</div>
-</tr>
-</table>
+  <head>
+    <title>{{.Value.Name}}</title>
+    <link rel="stylesheet" href="/css/movie.css">
+  </head>
+  <body>
+    <p><a href="/">Home</a></p>
+    {{$value := .}}
+    <table>
+      <tr>
+        <td valign="top">
+          <img src="{{.Value.Image}}" align="bottom">
+        </td>
+        <td valign="top">
+          <div>
+            <span class="title">{{.Value.Name}}</span>
+          </div>
+        </td>
+      </tr>
+    </table>
 
-<p>
-{{$date := $value.Date .Value.BirthDate}}
-Born: <span class="date">{{$date.Month}} {{$date.Day}}, {{$date.Year}}</span>
-</p>
+    <p>
+      {{$date := $value.Date .Value.BirthDate}}
+      Born:
+      <span class="date">
+        {{$date.Month}} {{$date.Day}}, {{$date.Year}}
+      </span>
+    </p>
 
-<!-- Debugging -->
-<span class="debug">{{.Name}} <a href="?raw">Raw</a></span>
-</body>
+    <!-- Debugging -->
+    <span class="debug">{{.Name}} <a href="?raw">Raw</a></span>
+  </body>
 </html>
diff --git a/examples/todos/schema/schema.vdl b/examples/todos/schema/schema.vdl
index 049daff..9072515 100644
--- a/examples/todos/schema/schema.vdl
+++ b/examples/todos/schema/schema.vdl
@@ -1,11 +1,7 @@
 package schema
 
 // Dir represents a directory.
-type Dir struct{
-	// TODO(jyh): The IDL does not recognize empty structs. Fix it and remove this
-	// useless field.
-	X byte
-}
+type Dir struct{}
 
 // List is a list of items.
 type List struct {
diff --git a/examples/todos/schema/schema.vdl.go b/examples/todos/schema/schema.vdl.go
index 7a9b9e1..53cc709 100644
--- a/examples/todos/schema/schema.vdl.go
+++ b/examples/todos/schema/schema.vdl.go
@@ -5,9 +5,6 @@
 
 // Dir represents a directory.
 type Dir struct {
-	// TODO(jyh): The IDL does not recognize empty structs. Fix it and remove this
-	// useless field.
-	X byte
 }
 
 // List is a list of items.
diff --git a/services/store/viewer/entry.go b/services/store/viewer/entry.go
new file mode 100644
index 0000000..119c53f
--- /dev/null
+++ b/services/store/viewer/entry.go
@@ -0,0 +1,74 @@
+package viewer
+
+import (
+	"path/filepath"
+	"sort"
+	"time"
+
+	"veyron2/context"
+	"veyron2/naming"
+	"veyron2/storage"
+)
+
+// Entry is the type used to pass store values to user-defined templates.
+type Entry struct {
+	ctx       context.T
+	storeRoot string
+	store     storage.Store
+	Name      string
+	Value     interface{}
+}
+
+// EntryForRawTemplate is the type used to pass store values to the "raw"
+// template defined in viewer.go.
+type EntryForRawTemplate struct {
+	*Entry
+	Subdirs    []string // relative names
+	RawSubdirs bool     // whether to add "?raw" to subdir hrefs
+}
+
+// abspath returns the absolute path from a path relative to this value.
+func (e *Entry) abspath(path string) string {
+	return naming.Join(e.storeRoot, e.Name, path)
+}
+
+// Date performs a Time conversion, given an integer argument that represents a
+// time in nanoseconds since the Unix epoch.
+func (e *Entry) Date(ns int64) time.Time {
+	return time.Unix(0, ns)
+}
+
+// Join joins the path elements.
+func (e *Entry) Join(elem ...string) string {
+	return filepath.ToSlash(filepath.Join(elem...))
+}
+
+// Base returns the last element of the path.
+func (e *Entry) Base(path string) string {
+	return filepath.Base(path)
+}
+
+// Glob performs a glob expansion of the pattern.  The results are sorted.
+func (e *Entry) Glob(pattern string) ([]string, error) {
+	results := e.store.Bind(e.abspath("")).Glob(e.ctx, pattern)
+	names := []string{}
+	rStream := results.RecvStream()
+	for rStream.Advance() {
+		names = append(names, rStream.Value())
+	}
+	if err := rStream.Err(); err != nil {
+		return nil, err
+	}
+	sort.Strings(names)
+	return names, nil
+}
+
+// Get fetches a value from the store, where path is relative to this value.
+// The result is nil if the value does not exist.
+func (e *Entry) Get(path string) interface{} {
+	en, err := e.store.Bind(e.abspath(path)).Get(e.ctx)
+	if err != nil {
+		return nil
+	}
+	return en.Value
+}
diff --git a/services/store/viewer/value.go b/services/store/viewer/value.go
deleted file mode 100644
index 2efbd29..0000000
--- a/services/store/viewer/value.go
+++ /dev/null
@@ -1,76 +0,0 @@
-package viewer
-
-import (
-	"path/filepath"
-	"sort"
-	"time"
-
-	"veyron2/context"
-	"veyron2/storage"
-)
-
-// Value is the type used to pass store values to the template.  The Value
-// contains the name of the value, the actual value, and a list of
-// subdirectories.
-type Value struct {
-	ctx     context.T
-	store   storage.Store
-	Name    string
-	Value   interface{}
-	Subdirs []string
-}
-
-// glob performs a glob expansion of the pattern.  The results are sorted.
-func glob(ctx context.T, st storage.Store, path, pattern string) ([]string, error) {
-	results := st.Bind(path).Glob(ctx, pattern)
-	names := []string{}
-	rStream := results.RecvStream()
-	for rStream.Advance() {
-		names = append(names, "/"+rStream.Value())
-	}
-	if err := rStream.Err(); err != nil {
-		return nil, err
-	}
-	sort.Strings(names)
-	return names, nil
-}
-
-// fullpath returns the absolute path from a relative path.
-func (v *Value) fullpath(path string) string {
-	if len(path) == 0 || path[0] != '/' {
-		return v.Name + "/" + path
-	}
-	return path
-}
-
-// Date performs a Time conversion, given an integer argument that represents a
-// time in nanoseconds since the Unix epoch.
-func (v *Value) Date(ns int64) time.Time {
-	return time.Unix(0, ns)
-}
-
-// Join joins the path elements.
-func (v *Value) Join(elem ...string) string {
-	return filepath.ToSlash(filepath.Join(elem...))
-}
-
-// Base returns the last element of the path.
-func (v *Value) Base(path string) string {
-	return filepath.Base(path)
-}
-
-// Glob performs a glob expansion of a pattern.
-func (v *Value) Glob(pattern string) ([]string, error) {
-	return glob(v.ctx, v.store, v.Name, pattern)
-}
-
-// Get fetches a value from the store.  The result is nil if the value does not
-// exist.
-func (v *Value) Get(path string) interface{} {
-	path = v.fullpath(path)
-	e, err := v.store.Bind(path).Get(v.ctx)
-	if err != nil {
-		return nil
-	}
-	return e.Value
-}
diff --git a/services/store/viewer/viewer.go b/services/store/viewer/viewer.go
index c4d091b..0a15e9a 100644
--- a/services/store/viewer/viewer.go
+++ b/services/store/viewer/viewer.go
@@ -44,8 +44,11 @@
 
 const (
 	// rawTemplateText is used to format the output in a raw textual form.
-	rawTemplateText = `<html>
-{{$value := .}}
+	rawTemplateText = `<!DOCTYPE html>
+<html>
+{{$entry := .}}
+{{$prefix := $entry.Name}}
+{{$rawSubdirs := $entry.RawSubdirs}}
 <head>
 <title>{{.Name}}</title>
 </head>
@@ -55,7 +58,8 @@
 {{with .Subdirs}}
 <h3>Subdirectories</h3>
 {{range .}}
-<p><a href="{{.}}">{{$value.Base .}}</a></p>
+{{$name := $entry.Join $prefix .}}
+<p><a href="{{$name}}{{if $rawSubdirs}}?raw{{end}}">{{.}}</a></p>
 {{end}}
 {{end}}
 </body>
@@ -75,15 +79,20 @@
 	return tmpl
 }
 
+// abspath returns the absolute path from a path relative to the store root.
+func (s *server) abspath(path string) string {
+	return naming.Join(s.storeRoot, path)
+}
+
 // loadTemplate fetches the template for the value from the store.  The template
 // is based on the type of the value, under /template/<pkgPath>/<typeName>.
 func (s *server) loadTemplate(ctx context.T, v interface{}) *template.Template {
-	path := naming.Join(s.storeRoot, templatePath(v))
-	e, err := s.store.Bind(path).Get(ctx)
+	path := templatePath(v)
+	en, err := s.store.Bind(s.abspath(path)).Get(ctx)
 	if err != nil {
 		return nil
 	}
-	str, ok := e.Value.(string)
+	str, ok := en.Value.(string)
 	if !ok {
 		return nil
 	}
@@ -96,11 +105,11 @@
 }
 
 // printRawValuePage prints the value in raw format.
-func (s *server) printRawValuePage(ctx context.T, w http.ResponseWriter, path string, v interface{}) {
+func (s *server) printRawValuePage(ctx context.T, w http.ResponseWriter, path string, v interface{}, rawSubdirs bool) {
 	var p printer
 	p.print(v)
-	subdirs, _ := glob(ctx, s.store, path, "*")
-	x := &Value{ctx: ctx, Name: path, Value: p.String(), Subdirs: subdirs}
+	x := &EntryForRawTemplate{&Entry{ctx: ctx, storeRoot: s.storeRoot, store: s.store, Name: path, Value: p.String()}, []string{}, rawSubdirs}
+	x.Subdirs, _ = x.Glob("*")
 	if err := rawTemplate.Execute(w, x); err != nil {
 		w.Write([]byte(html.EscapeString(err.Error())))
 	}
@@ -110,12 +119,13 @@
 // is not found, the value is printed in raw format instead.
 func (s *server) printValuePage(ctx context.T, w http.ResponseWriter, path string, v interface{}) {
 	if tmpl := s.loadTemplate(ctx, v); tmpl != nil {
-		if err := tmpl.Execute(w, &Value{ctx: ctx, store: s.store, Name: path, Value: v}); err != nil {
+		x := &Entry{ctx: ctx, storeRoot: s.storeRoot, store: s.store, Name: path, Value: v}
+		if err := tmpl.Execute(w, x); err != nil {
 			w.Write([]byte(html.EscapeString(err.Error())))
 		}
 		return
 	}
-	s.printRawValuePage(ctx, w, path, v)
+	s.printRawValuePage(ctx, w, path, v, false)
 }
 
 // printRawPage prints a string value directly, without processing.
@@ -130,11 +140,12 @@
 
 // ServeHTTP is the main HTTP handler.
 func (s *server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
-	path := naming.Join(s.storeRoot, req.URL.Path)
+	path := req.URL.Path
 	ctx := s.runtime.NewContext()
-	e, err := s.store.Bind(path).Get(ctx)
+	en, err := s.store.Bind(s.abspath(path)).Get(ctx)
 	if err != nil {
-		msg := fmt.Sprintf("<html><body><h1>%s</h1><h2>Error: %s</h2></body></html>",
+		msg := fmt.Sprintf(
+			"<html><body><h1>%s</h1><h2>Error: %s</h2></body></html>",
 			html.EscapeString(path),
 			html.EscapeString(err.Error()))
 		w.WriteHeader(http.StatusNotFound)
@@ -145,12 +156,14 @@
 	q := req.URL.Query()
 	switch filepath.Ext(path) {
 	case ".css":
-		s.printRawPage(w, e.Value)
+		w.Header().Set("Content-Type", "text/css; charset=utf-8")
+		s.printRawPage(w, en.Value)
 	default:
+		w.Header().Set("Content-Type", "text/html; charset=utf-8")
 		if q["raw"] != nil {
-			s.printRawValuePage(ctx, w, path, e.Value)
+			s.printRawValuePage(ctx, w, path, en.Value, true)
 		} else {
-			s.printValuePage(ctx, w, path, e.Value)
+			s.printValuePage(ctx, w, path, en.Value)
 		}
 	}
 }