playground: add examples to demonstrate tricks

As a way to document the playground's tricks, this change adds
a dropdown of examples to the right of the "Share" button. They
are as follows:

    - Hello, playground (default)
    - Tests
    - Multiple files
    - Display image
    - Sleep
    - Clear

Fixes golang/go#32294.

Change-Id: I6cdd54714d5638a932b2d392db1ea888468f5cec
Reviewed-on: https://go-review.googlesource.com/c/playground/+/216359
Run-TryBot: Andrew Bonventre <andybons@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Andrew Bonventre <andybons@golang.org>
diff --git a/Dockerfile b/Dockerfile
index 063f9a5..dafa0d4 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -121,6 +121,7 @@
 COPY --from=build /go/bin/playground /app
 COPY edit.html /app
 COPY static /app/static
+COPY examples /app/examples
 WORKDIR /app
 
 # Whether we allow third-party imports via proxy.golang.org:
diff --git a/edit.html b/edit.html
index 2b5ded8..719edab 100644
--- a/edit.html
+++ b/edit.html
@@ -31,7 +31,8 @@
 				{{end}}
 				'enableHistory': true,
 				'enableShortcuts': true,
-				'enableVet': true
+				'enableVet': true,
+				'toysEl': '.js-playgroundToysEl'
 			});
 			playgroundEmbed({
 				'codeEl':       '#code',
@@ -120,6 +121,14 @@
 					embed
 				</label>
 				{{end}}
+				<select class="js-playgroundToysEl">
+					<option value="hello.txt">Hello, playground</option>
+					<option value="test.txt">Tests</option>
+					<option value="multi.txt">Multiple files</option>
+					<option value="image.txt">Display image</option>
+					<option value="sleep.txt">Sleep</option>
+					<option value="clear.txt">Clear</option>
+				</select>
 			</div>
 			<div id="aboutControls">
 				<input type="button" value="About" id="aboutButton">
diff --git a/examples/clear.txt b/examples/clear.txt
new file mode 100644
index 0000000..c5381d7
--- /dev/null
+++ b/examples/clear.txt
@@ -0,0 +1,18 @@
+package main
+
+import (
+	"fmt"
+	"strings"
+	"time"
+)
+
+func main() {
+	const col = 30
+	// Clear the screen by printing \x0c.
+	bar := fmt.Sprintf("\x0c[%%-%vs]", col)
+	for i := 0; i < col; i++ {
+		fmt.Printf(bar, strings.Repeat("=", i)+">")
+		time.Sleep(100 * time.Millisecond)
+	}
+	fmt.Printf(bar+" Done!", strings.Repeat("=", col))
+}
diff --git a/examples/hello.txt b/examples/hello.txt
new file mode 100644
index 0000000..8fd43ed
--- /dev/null
+++ b/examples/hello.txt
@@ -0,0 +1,9 @@
+package main
+
+import (
+	"fmt"
+)
+
+func main() {
+	fmt.Println("Hello, playground")
+}
diff --git a/examples/image.txt b/examples/image.txt
new file mode 100644
index 0000000..4180a45
--- /dev/null
+++ b/examples/image.txt
@@ -0,0 +1,40 @@
+package main
+
+import (
+	"bytes"
+	"encoding/base64"
+	"fmt"
+	"image"
+	"image/png"
+)
+
+var favicon = []byte{
+	0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00,
+	0x10, 0x00, 0x00, 0x00, 0x0f, 0x04, 0x03, 0x00, 0x00, 0x00, 0x1f, 0x5d, 0x52, 0x1c, 0x00, 0x00, 0x00, 0x0f, 0x50,
+	0x4c, 0x54, 0x45, 0x7a, 0xdf, 0xfd, 0xfd, 0xff, 0xfc, 0x39, 0x4d, 0x52, 0x19, 0x16, 0x15, 0xc3, 0x8d, 0x76, 0xc7,
+	0x36, 0x2c, 0xf5, 0x00, 0x00, 0x00, 0x40, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x95, 0xc9, 0xd1, 0x0d, 0xc0, 0x20,
+	0x0c, 0x03, 0xd1, 0x23, 0x5d, 0xa0, 0x49, 0x17, 0x20, 0x4c, 0xc0, 0x10, 0xec, 0x3f, 0x53, 0x8d, 0xc2, 0x02, 0x9c,
+	0xfc, 0xf1, 0x24, 0xe3, 0x31, 0x54, 0x3a, 0xd1, 0x51, 0x96, 0x74, 0x1c, 0xcd, 0x18, 0xed, 0x9b, 0x9a, 0x11, 0x85,
+	0x24, 0xea, 0xda, 0xe0, 0x99, 0x14, 0xd6, 0x3a, 0x68, 0x6f, 0x41, 0xdd, 0xe2, 0x07, 0xdb, 0xb5, 0x05, 0xca, 0xdb,
+	0xb2, 0x9a, 0xdd, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
+}
+
+// displayImage renders an image to the playground's console by
+// base64-encoding the encoded image and printing it to stdout
+// with the prefix "IMAGE:".
+func displayImage(m image.Image) {
+	var buf bytes.Buffer
+	err := png.Encode(&buf, m)
+	if err != nil {
+		panic(err)
+	}
+	fmt.Println("IMAGE:" + base64.StdEncoding.EncodeToString(buf.Bytes()))
+}
+
+func main() {
+	m, err := png.Decode(bytes.NewReader(favicon))
+	if err != nil {
+		panic(err)
+	}
+	displayImage(m)
+}
diff --git a/examples/multi.txt b/examples/multi.txt
new file mode 100644
index 0000000..ad41446
--- /dev/null
+++ b/examples/multi.txt
@@ -0,0 +1,21 @@
+package main
+
+import (
+	"play.ground/foo"
+)
+
+func main() {
+	foo.Bar()
+}
+
+-- go.mod --
+module play.ground
+
+-- foo/foo.go --
+package foo
+
+import "fmt"
+
+func Bar() {
+	fmt.Println("This function lives in an another file!")
+}
diff --git a/examples/sleep.txt b/examples/sleep.txt
new file mode 100644
index 0000000..d68a3d8
--- /dev/null
+++ b/examples/sleep.txt
@@ -0,0 +1,17 @@
+package main
+
+import (
+	"fmt"
+	"math/rand"
+	"time"
+)
+
+func main() {
+	for i := 0; i < 10; i++ {
+		dur := time.Duration(rand.Intn(1000)) * time.Millisecond
+		fmt.Printf("Sleeping for %v\n", dur)
+		// Sleep for a random duration between 0-1000ms
+		time.Sleep(dur)
+	}
+	fmt.Println("Done!")
+}
diff --git a/examples/test.txt b/examples/test.txt
new file mode 100644
index 0000000..4bf86e9
--- /dev/null
+++ b/examples/test.txt
@@ -0,0 +1,37 @@
+package main
+
+import (
+	"testing"
+)
+
+// LastIndex returns the index of the last instance of x in list, or
+// -1 if x is not present. The loop condition has a fault that
+// causes somes tests to fail. Change it to i >= 0 to see them pass.
+func LastIndex(list []int, x int) int {
+	for i := len(list) - 1; i > 0; i-- {
+		if list[i] == x {
+			return i
+		}
+	}
+	return -1
+}
+
+func TestLastIndex(t *testing.T) {
+	tests := []struct {
+		list []int
+		x    int
+		want int
+	}{
+		{list: []int{1}, x: 1, want: 0},
+		{list: []int{1, 1}, x: 1, want: 1},
+		{list: []int{2, 1}, x: 2, want: 0},
+		{list: []int{1, 2, 1, 1}, x: 2, want: 1},
+		{list: []int{1, 1, 1, 2, 2, 1}, x: 3, want: -1},
+		{list: []int{3, 1, 2, 2, 1, 1}, x: 3, want: 0},
+	}
+	for _, tt := range tests {
+		if got := LastIndex(tt.list, tt.x); got != tt.want {
+			t.Errorf("LastIndex(%v, %v) = %v, want %v", tt.list, tt.x, got, tt.want)
+		}
+	}
+}
diff --git a/server.go b/server.go
index d3a491b..f091933 100644
--- a/server.go
+++ b/server.go
@@ -59,6 +59,9 @@
 
 	staticHandler := http.StripPrefix("/static/", http.FileServer(http.Dir("./static")))
 	s.mux.Handle("/static/", staticHandler)
+
+	examplesHandler := http.StripPrefix("/doc/play/", http.FileServer(http.Dir("./examples")))
+	s.mux.Handle("/doc/play/", examplesHandler)
 }
 
 func (s *server) handlePlaygroundJS(w http.ResponseWriter, r *http.Request) {
diff --git a/static/style.css b/static/style.css
index 1cd00e8..ac93cf0 100644
--- a/static/style.css
+++ b/static/style.css
@@ -174,3 +174,9 @@
 	top: 10px;
 	right: 10px;
 }
+
+#controls select {
+	font-size: 0.875rem;
+	border: 0.0625rem solid #375EAB;
+	margin: 0;
+}
\ No newline at end of file