Merge changes Ib91e4d3b,I5d41fa12,I839863a8

* changes:
  hackdoc: render TOC inline
  hackdoc: fix pub_listen flag in readme
  hackdoc: do not add ?ref= to intra-links unless necessary
diff --git a/devtools/hackdoc/README.md b/devtools/hackdoc/README.md
index 3226cf2..7bf556a 100644
--- a/devtools/hackdoc/README.md
+++ b/devtools/hackdoc/README.md
@@ -13,6 +13,16 @@
 - https://hackdoc.hackerspace.pl/?ref=master for the `master` branch
 - https://hackdoc.hackerspace.pl/?ref=change/249 for the the source code at change '249'
 
+Special Markdown
+----------------
+
+We should be accepting a Somewhat Standard Subset Of Markdown. For reference, we're using the [blackfriday](https://godoc.org/gopkg.in/russross/blackfriday.v2) library with [CommonExtensions](https://godoc.org/gopkg.in/russross/blackfriday.v2#CommonExtensions) enabled.
+
+In addition, we also support Table of Contents autorendering, just place the following anywhere in your document to render a TOC:
+
+    [TOC]
+
+
 Local Rendering
 ---------------
 
@@ -20,4 +30,4 @@
 
      bazel run //devtools/hackdoc  -- -hspki_disable -docroot /path/to/hscloud
 
-The output log should tell you where hackdoc just started listening at. Currently this is `127.0.0.1:8080` by default. You can change this by passing a `-listen` flag, eg. `-listen 127.0.0.1:4242`.
+The output log should tell you where hackdoc just started listening at. Currently this is `127.0.0.1:8080` by default. You can change this by passing a `-pub_listen` flag, eg. `-pub_listen 127.0.0.1:4242`.
diff --git a/devtools/hackdoc/markdown.go b/devtools/hackdoc/markdown.go
index eaed905..5004642 100644
--- a/devtools/hackdoc/markdown.go
+++ b/devtools/hackdoc/markdown.go
@@ -19,14 +19,27 @@
 		Flags: blackfriday.CommonHTMLFlags | blackfriday.TOC,
 	})
 
+	// master is the default branch - do not make special links for that, as
+	// that makes them kinda ugly.
+	if ref == "master" {
+		ref = ""
+	}
+
 	parser := blackfriday.New(blackfriday.WithRenderer(r), blackfriday.WithExtensions(blackfriday.CommonExtensions))
 	ast := parser.Parse(input)
 
+	// Render table of contents (raw HTML) into bytes.
+	var tocB bytes.Buffer
+	tocB.Write([]byte(`<div class="toc">`))
+	r.RenderHeader(&tocB, ast)
+	tocB.Write([]byte(`</div>`))
+	toc := tocB.Bytes()
+
 	var buf bytes.Buffer
-	buf.Write([]byte(`<div class="toc"><h1>Page Contents</h1>`))
-	r.RenderHeader(&buf, ast)
-	buf.Write([]byte(`</div><div class="content">`))
+	buf.Write([]byte(`<div class="content">`))
+	// Render Markdown with some custom behaviour.
 	ast.Walk(func(node *blackfriday.Node, entering bool) blackfriday.WalkStatus {
+		// Fix intra-hackdoc links to contain ?ref=
 		if ref != "" && entering && node.Type == blackfriday.Link || node.Type == blackfriday.Image {
 			dest := string(node.Destination)
 			u, err := url.Parse(dest)
@@ -35,9 +48,14 @@
 				q["ref"] = []string{ref}
 				u.RawQuery = q.Encode()
 				node.Destination = []byte(u.String())
-				glog.Infof("link fix %q -> %q", dest, u.String())
+				glog.V(10).Infof("link fix %q -> %q", dest, u.String())
 			}
 		}
+		// Replace [TOC] anchor with a rendered TOC.
+		if entering && node.Type == blackfriday.Text && string(node.Literal) == "[TOC]" {
+			buf.Write(toc)
+			return blackfriday.GoToNext
+		}
 		return r.RenderNode(&buf, node, entering)
 	})
 	buf.Write([]byte(`</div>`))
diff --git a/devtools/hackdoc/tpl/default.html b/devtools/hackdoc/tpl/default.html
index e6280db..6211e38 100644
--- a/devtools/hackdoc/tpl/default.html
+++ b/devtools/hackdoc/tpl/default.html
@@ -169,7 +169,7 @@
     line-height: 1.5em;
 }
 
-.content ul {
+.content :not(li) > ul {
     padding-top: 0.5em;
     line-height: 1.5em;
 }
@@ -178,12 +178,20 @@
     padding-left: 1em;
 }
 
-.content ul li::before {
+.content :not(li) > ul > li::before {
     content: "•";
     color: #333;;
     display: inline-block;
     width: 1em;
-    margin-left: -1em;
+    margin-left: -0.5em;
+}
+
+.content li > ul > li::before {
+    content: "◦";
+    color: #333;;
+    display: inline-block;
+    width: 1em;
+    margin-left: -0.5em;
 }
 
 .content img {
@@ -193,37 +201,19 @@
 }
 
 .toc {
-    float: right;
-    padding: 1em 1em 1em 1em;
+    padding: .5em;
     border: 1px solid #ddd;
     background-color: #f8f8f8;
     margin: 2em;
     max-width: 30%;
-}
-
-.toc h1 {
-    font-size: 1.2em;
-    padding-bottom: 0.5em;
+    font-size: 1em;
+    font-family: sans-serif;
 }
 
 .toc a {
     text-decoration: none;
 }
 
-.toc li {
-    padding-left: 0.5em;
-}
-
-.toc ul {
-    list-style-type: disc;
-    padding-left: 1em;
-}
-
-.toc ul ul {
-    list-style-type: circle;
-}
-
-
 </style>
 {{ end }}
 {{ define "body" }}
diff --git a/doc/codelabs/getting-started/your-first-change.md b/doc/codelabs/getting-started/your-first-change.md
index ef94ff8..93990d0 100644
--- a/doc/codelabs/getting-started/your-first-change.md
+++ b/doc/codelabs/getting-started/your-first-change.md
@@ -3,6 +3,8 @@
 
 This codelab will teach you how to send your first change to hscloud. We'll be modifying some files in your personal directory, so you won't bother anyone or break anything.
 
+[TOC]
+
 Prerequisites
 -------------
 
@@ -190,3 +192,4 @@
  - If you need a **Git refresher** - we highly recommend the [Git Visual Reference](https://marklodato.github.io/visual-git-guide/index-en.html)
  - While this codelab showed you how to create and submit CRs, you didn't see anything about code review. Watch this space for a codelab about that.
  - You should now be able to commit and change code. Watch this space for a link to a codelab on using Bazel or writing a simple microservice in Go.
+