godoc: specify HTML page metadata with a JSON blob

This allows HTML pages to specify arbitrary data in a header:

<!--{
        "Title": "The page title",
        ...
}-->

replacing the old style comments:

<!-- title The page title -->

R=gri, rsc, r, bradfitz, dsymonds
CC=golang-dev
https://golang.org/cl/5532093
diff --git a/doc/articles/defer_panic_recover.html b/doc/articles/defer_panic_recover.html
index b78258d..18c0de2 100644
--- a/doc/articles/defer_panic_recover.html
+++ b/doc/articles/defer_panic_recover.html
@@ -1,4 +1,6 @@
-<!-- Defer, Panic, and Recover -->
+<!--{
+	"Title": "Defer, Panic, and Recover"
+}-->
 <!--
   DO NOT EDIT: created by
     tmpltohtml articles/defer_panic_recover.tmpl
diff --git a/doc/articles/defer_panic_recover.tmpl b/doc/articles/defer_panic_recover.tmpl
index 780040a..60c8eeb 100644
--- a/doc/articles/defer_panic_recover.tmpl
+++ b/doc/articles/defer_panic_recover.tmpl
@@ -1,4 +1,6 @@
-<!-- Defer, Panic, and Recover -->
+<!--{
+	"Title": "Defer, Panic, and Recover"
+}-->
 {{donotedit}}
 <p>
 Go has the usual mechanisms for control flow: if, for, switch, goto.  It also
diff --git a/doc/articles/error_handling.html b/doc/articles/error_handling.html
index 89f2998..b9393a2 100644
--- a/doc/articles/error_handling.html
+++ b/doc/articles/error_handling.html
@@ -1,4 +1,6 @@
-<!-- Error Handling and Go -->
+<!--{
+	"Title": "Error Handling and Go"
+}-->
 <!--
   DO NOT EDIT: created by
     tmpltohtml articles/error_handling.tmpl
diff --git a/doc/articles/error_handling.tmpl b/doc/articles/error_handling.tmpl
index 508885a..141b4a5 100644
--- a/doc/articles/error_handling.tmpl
+++ b/doc/articles/error_handling.tmpl
@@ -1,4 +1,6 @@
-<!-- Error Handling and Go -->
+<!--{
+	"Title": "Error Handling and Go"
+}-->
 {{donotedit}}
 <p>
 If you have written any Go code you have probably encountered the built-in
diff --git a/doc/articles/slices_usage_and_internals.html b/doc/articles/slices_usage_and_internals.html
index 66ca4a2..c10dfe0 100644
--- a/doc/articles/slices_usage_and_internals.html
+++ b/doc/articles/slices_usage_and_internals.html
@@ -1,4 +1,6 @@
-<!-- Slices: usage and internals -->
+<!--{
+	"Title": "Slices: usage and internals"
+}-->
 <!--
   DO NOT EDIT: created by
     tmpltohtml articles/slices_usage_and_internals.tmpl
diff --git a/doc/articles/slices_usage_and_internals.tmpl b/doc/articles/slices_usage_and_internals.tmpl
index 9492981..d2f8fb7 100644
--- a/doc/articles/slices_usage_and_internals.tmpl
+++ b/doc/articles/slices_usage_and_internals.tmpl
@@ -1,4 +1,6 @@
-<!-- Slices: usage and internals -->
+<!--{
+	"Title": "Slices: usage and internals"
+}-->
 {{donotedit}}
 
 <p>
diff --git a/doc/code.html b/doc/code.html
index 4737a38..76d25e1 100644
--- a/doc/code.html
+++ b/doc/code.html
@@ -1,4 +1,6 @@
-<!-- How to Write Go Code -->
+<!--{
+	"Title": "How to Write Go Code"
+}-->
 
 <h2 id="Introduction">Introduction</h2>
 
diff --git a/doc/codereview_with_mq.html b/doc/codereview_with_mq.html
index 33f415f..38ecbda 100644
--- a/doc/codereview_with_mq.html
+++ b/doc/codereview_with_mq.html
@@ -1,4 +1,6 @@
-<!-- Using Mercurial Queues with Codereview -->
+<!--{
+	"Title": "Using Mercurial Queues with Codereview"
+}-->
 
 <h2 id="Introduction">Introduction</h2>
 
diff --git a/doc/community.html b/doc/community.html
index c3b16ca..aee731e 100644
--- a/doc/community.html
+++ b/doc/community.html
@@ -1,4 +1,6 @@
-<!-- title Community -->
+<!--{
+	"Title": "Community"
+}-->
 
 <div class="left-column">
 
diff --git a/doc/contrib.html b/doc/contrib.html
index 5e00345..3ef7d56 100644
--- a/doc/contrib.html
+++ b/doc/contrib.html
@@ -1,4 +1,6 @@
-<!-- title Contributing -->
+<!--{
+	"Title": "Contributing"
+}-->
 
 <div class="left-column">
 
diff --git a/doc/contribute.html b/doc/contribute.html
index a5beb54..5af9af4 100644
--- a/doc/contribute.html
+++ b/doc/contribute.html
@@ -1,4 +1,6 @@
-<!-- Contribution Guidelines -->
+<!--{
+	"Title": "Contribution Guidelines"
+}-->
 
 <h2 id="Introduction">Introduction</h2>
 
diff --git a/doc/debugging_with_gdb.html b/doc/debugging_with_gdb.html
index 874c468..d5c1a88 100644
--- a/doc/debugging_with_gdb.html
+++ b/doc/debugging_with_gdb.html
@@ -1,4 +1,6 @@
-<!-- title Debugging Go Code with GDB -->
+<!--{
+	"Title": "Debugging Go Code with GDB"
+}-->
 
 <p><i>
 This applies to the 6g toolchain. Gccgo has native gdb support. Besides this
diff --git a/doc/docs.html b/doc/docs.html
index 5a5c8ee..c0ced98 100644
--- a/doc/docs.html
+++ b/doc/docs.html
@@ -1,4 +1,6 @@
-<!-- title Documentation -->
+<!--{
+	"Title": "Documentation"
+}-->
 
 <div class="left-column">
 
diff --git a/doc/effective_go.html b/doc/effective_go.html
index 3c16e10..4ecbe19 100644
--- a/doc/effective_go.html
+++ b/doc/effective_go.html
@@ -1,4 +1,6 @@
-<!-- Effective Go -->
+<!--{
+	"Title": "Effective Go"
+}-->
 <!--
   DO NOT EDIT: created by
     tmpltohtml effective_go.tmpl
diff --git a/doc/effective_go.tmpl b/doc/effective_go.tmpl
index af1bc1e..782c700 100644
--- a/doc/effective_go.tmpl
+++ b/doc/effective_go.tmpl
@@ -1,4 +1,6 @@
-<!-- Effective Go -->
+<!--{
+	"Title": "Effective Go"
+}-->
 {{donotedit}}
 
 <h2 id="introduction">Introduction</h2>
diff --git a/doc/gccgo_contribute.html b/doc/gccgo_contribute.html
index 8eeb3a5..b641c1a 100644
--- a/doc/gccgo_contribute.html
+++ b/doc/gccgo_contribute.html
@@ -1,4 +1,6 @@
-<!-- Contributing to the gccgo frontend -->
+<!--{
+	"Title": "Contributing to the gccgo frontend"
+}-->
 
 <h2>Introduction</h2>
 
diff --git a/doc/gccgo_install.html b/doc/gccgo_install.html
index 38a30e9..1aaf64e 100644
--- a/doc/gccgo_install.html
+++ b/doc/gccgo_install.html
@@ -1,4 +1,6 @@
-<!-- Setting up and using gccgo -->
+<!--{
+	"Title": "Setting up and using gccgo"
+}-->
 
 <p>
 This document explains how to use <code>gccgo</code>, a compiler for
diff --git a/doc/go1.html b/doc/go1.html
index 4b98507..f116ee2 100644
--- a/doc/go1.html
+++ b/doc/go1.html
@@ -1,4 +1,6 @@
-<!-- Go 1 Release Notes -->
+<!--{
+	"Title": "Go 1 Release Notes"
+}-->
 <!--
   DO NOT EDIT: created by
     tmpltohtml go1.tmpl
diff --git a/doc/go1.tmpl b/doc/go1.tmpl
index 8d295d6e..41d5998 100644
--- a/doc/go1.tmpl
+++ b/doc/go1.tmpl
@@ -1,4 +1,6 @@
-<!-- Go 1 Release Notes -->
+<!--{
+	"Title": "Go 1 Release Notes"
+}-->
 {{donotedit}}
 
 <h2 id="introduction">Introduction to Go 1</h2>
diff --git a/doc/go_faq.html b/doc/go_faq.html
index e68b4e2..6a8199f 100644
--- a/doc/go_faq.html
+++ b/doc/go_faq.html
@@ -1,4 +1,6 @@
-<!-- FAQ -->
+<!--{
+	"Title": "FAQ"
+}-->
 
 <h2 id="Origins">Origins</h2>
 
diff --git a/doc/go_for_cpp_programmers.html b/doc/go_for_cpp_programmers.html
index 7168f1d..7edb880 100644
--- a/doc/go_for_cpp_programmers.html
+++ b/doc/go_for_cpp_programmers.html
@@ -1,4 +1,6 @@
-<!-- Go For C++ Programmers -->
+<!--{
+	"Title": "Go For C++ Programmers"
+}-->
 
 <p>
 Go is a systems programming language intended to be a general-purpose
diff --git a/doc/go_mem.html b/doc/go_mem.html
index 45ee0f5..2e34177 100644
--- a/doc/go_mem.html
+++ b/doc/go_mem.html
@@ -1,5 +1,7 @@
-<!-- The Go Memory Model -->
-<!-- subtitle Version of June 10, 2011 -->
+<!--{
+	"Title": "The Go Memory Model",
+	"Subtitle": "Version of June 10, 2011"
+}-->
 
 <style>
 p.rule {
diff --git a/doc/go_spec.html b/doc/go_spec.html
index 90be6d5..8bf6c21 100644
--- a/doc/go_spec.html
+++ b/doc/go_spec.html
@@ -1,5 +1,7 @@
-<!-- title The Go Programming Language Specification -->
-<!-- subtitle Version of January 13, 2012 -->
+<!--{
+	"Title": "The Go Programming Language Specification",
+	"Subtitle": "Version of January 13, 2012"
+}-->
 
 <!--
 TODO
diff --git a/doc/go_tutorial.html b/doc/go_tutorial.html
index 071ca1a..eaa989a 100644
--- a/doc/go_tutorial.html
+++ b/doc/go_tutorial.html
@@ -1,4 +1,6 @@
-<!-- A Tutorial for the Go Programming Language -->
+<!--{
+	"Title": "A Tutorial for the Go Programming Language"
+}-->
 <!--
   DO NOT EDIT: created by
     tmpltohtml go_tutorial.tmpl
diff --git a/doc/go_tutorial.tmpl b/doc/go_tutorial.tmpl
index ff3057b..bde724c 100644
--- a/doc/go_tutorial.tmpl
+++ b/doc/go_tutorial.tmpl
@@ -1,4 +1,6 @@
-<!-- A Tutorial for the Go Programming Language -->
+<!--{
+	"Title": "A Tutorial for the Go Programming Language"
+}-->
 {{donotedit}}
 
 <h2>Introduction</h2>
diff --git a/doc/install.html b/doc/install.html
index 70dfe81..61a90da 100644
--- a/doc/install.html
+++ b/doc/install.html
@@ -1,4 +1,6 @@
-<!-- Getting Started -->
+<!--{
+	"Title": "Getting Started"
+}-->
 
 <h2 id="introduction">Introduction</h2>
 
diff --git a/doc/playground.html b/doc/playground.html
index 01d3adc..746b29c 100644
--- a/doc/playground.html
+++ b/doc/playground.html
@@ -1,4 +1,6 @@
-<!-- About the Go Playground -->
+<!--{
+	"Title": "About the Go Playground"
+}-->
 
 <div class="left-column">
 <p>
diff --git a/src/cmd/godoc/godoc.go b/src/cmd/godoc/godoc.go
index 92273cea..61a3142 100644
--- a/src/cmd/godoc/godoc.go
+++ b/src/cmd/godoc/godoc.go
@@ -6,6 +6,7 @@
 
 import (
 	"bytes"
+	"encoding/json"
 	"flag"
 	"fmt"
 	"go/ast"
@@ -692,17 +693,14 @@
 // Files
 
 var (
-	titleRx        = regexp.MustCompile(`<!-- title ([^\-]*)-->`)
-	subtitleRx     = regexp.MustCompile(`<!-- subtitle ([^\-]*)-->`)
-	firstCommentRx = regexp.MustCompile(`<!--([^\-]*)-->`)
+	doctype   = []byte("<!DOCTYPE ")
+	jsonStart = []byte("<!--{")
+	jsonEnd   = []byte("}-->")
 )
 
-func extractString(src []byte, rx *regexp.Regexp) (s string) {
-	m := rx.FindSubmatch(src)
-	if m != nil {
-		s = strings.TrimSpace(string(m[1]))
-	}
-	return
+type Metadata struct {
+	Title    string
+	Subtitle string
 }
 
 func serveHTMLDoc(w http.ResponseWriter, r *http.Request, abspath, relpath string) {
@@ -716,11 +714,23 @@
 
 	// if it begins with "<!DOCTYPE " assume it is standalone
 	// html that doesn't need the template wrapping.
-	if bytes.HasPrefix(src, []byte("<!DOCTYPE ")) {
+	if bytes.HasPrefix(src, doctype) {
 		w.Write(src)
 		return
 	}
 
+	// if it begins with a JSON blob, read in the metadata.
+	var meta Metadata
+	if bytes.HasPrefix(src, jsonStart) {
+		if end := bytes.Index(src, jsonEnd); end > -1 {
+			b := src[len(jsonStart)-1 : end+1] // drop leading <!-- and include trailing }
+			if err := json.Unmarshal(b, &meta); err != nil {
+				log.Printf("decoding metadata for %s: %v", relpath, err)
+			}
+			src = src[end+len(jsonEnd):]
+		}
+	}
+
 	// if it's the language spec, add tags to EBNF productions
 	if strings.HasSuffix(abspath, "go_spec.html") {
 		var buf bytes.Buffer
@@ -728,15 +738,7 @@
 		src = buf.Bytes()
 	}
 
-	// get title and subtitle, if any
-	title := extractString(src, titleRx)
-	if title == "" {
-		// no title found; try first comment for backward-compatibility
-		title = extractString(src, firstCommentRx)
-	}
-	subtitle := extractString(src, subtitleRx)
-
-	servePage(w, title, subtitle, "", src)
+	servePage(w, meta.Title, meta.Subtitle, "", src)
 }
 
 func applyTemplate(t *template.Template, name string, data interface{}) []byte {