2015: add "Stupid Gopher Tricks" slides

Change-Id: Ic0078d0fa166e266ee56ccc83d2c32e3c3a9f18d
Reviewed-on: https://go-review.googlesource.com/13775
Reviewed-by: Andrew Gerrand <adg@golang.org>
diff --git a/2015/tricks.slide b/2015/tricks.slide
new file mode 100644
index 0000000..f7fcfba
--- /dev/null
+++ b/2015/tricks.slide
@@ -0,0 +1,779 @@
+Stupid Gopher Tricks
+GolangUK
+21 Aug 2015
+
+Andrew Gerrand
+adg@golang.org
+
+* This talk
+
+This talk is about things you might not know about Go.
+
+Some of this stuff you can add to your Go vocabulary.
+
+Other things are probably best left for special occasions.
+
+
+* Language
+
+
+* Type literals (1/2)
+
+Here's a familiar type declaration:
+
+	type Foo struct {
+		i int
+		s string
+	}
+
+The latter part of a type declaration is the *type*literal*:
+
+	struct {
+		i int
+		s string
+	}
+
+Other examples of type literals are `int` and `[]string`,
+which can also be declared as named types:
+
+	type Bar int
+	type Qux []string
+
+
+* Type literals (2/2)
+
+While we commonly use `int` and `[]string` in variable declarations:
+
+	var i int
+	var s []string
+
+It is less common (but equally valid) to do the same with structs:
+
+	var t struct {
+		i int
+		s string
+	}
+
+An unnamed struct literal is often called an *anonymous*struct*.
+
+
+* Anonymous structs: template data
+
+A common use is providing data to templates:
+
+.play tricks/template.go /BEGIN/,/END/
+
+You could also use `map[string]interface{}`,
+but then you sacrifice performance and type safety.
+
+
+* Anonymous structs: JSON (1/2)
+
+The same technique can be used for encoding JSON objects:
+
+.play tricks/json-encode.go /Marshal/,/Print/
+
+And also decoding:
+
+.play tricks/json-decode.go /data/,/Print/
+
+
+* Anonymous structs: JSON (2/2)
+
+Structs can be nested to describe more complex JSON objects:
+
+.play tricks/json-nest.go /data/,/Print/
+
+
+* Repeated literals and struct names
+
+In repeated literals like slices and maps, Go lets you omit the inner type name:
+
+.code tricks/repeated.go /BEGIN/,/END/
+
+
+* Repeated literals and anonymous structs
+
+Combined with anonymous structs, this convenience shortens the code dramatically:
+
+.code tricks/repeated2.go /BEGIN/,/END/
+
+
+* Anonymous structs: test cases (1/2)
+
+These properties enable a nice way to express test cases:
+
+.code tricks/string_test.go /TestIndex/,/^}/
+
+
+* Anonymous structs: test cases (2/2)
+
+You can go a step further and put the composite literal in the range statement itself:
+
+.code tricks/string_test2.go /TestIndex/,/^}/
+
+But this is harder to read.
+
+
+* Embedded fields
+
+A struct field that has no name is an *embedded*field*.
+The embedded type's methods (and fields, if it is a struct)
+are accessible as if they are part of the embedding struct.
+
+.play tricks/embed.go /BEGIN/,$
+
+
+* Anonymous structs: embedded mutex
+
+Of course, you can embed fields in an anonymous struct.
+
+It's common to protect a global variable with a mutex variable:
+
+	var (
+		viewCount   int64
+		viewCountMu sync.Mutex
+	)
+
+By embedding a mutex in an anonymous struct, we can group the related values:
+
+	var viewCount struct {
+		sync.Mutex
+		n int64
+	}
+
+Users of `viewCount` access it like this:
+
+	viewCount.Lock()
+	viewCount.n++
+	viewCount.Unlock()
+
+
+
+* Anonymous structs: implementing interfaces
+
+And you can embed interfaces, too.
+
+Here's a real example from [[https://camlistore.org/][Camlistore]]:
+
+The function is expected to return a `ReadSeekCloser`,
+but the programmer only had a string.
+
+Anonymous struct (and its standard library friends) to the rescue!
+
+	return struct {
+		io.ReadSeeker
+		io.Closer
+	}{
+		io.NewSectionReader(strings.NewReader(s), 0, int64(len(s))),
+		ioutil.NopCloser(nil),
+	}
+
+
+* Anonymous interfaces
+
+Interfaces can be anonymous, the most common being `interface{}`.
+
+But the interface needn't be empty:
+
+.play tricks/anon-interface.go /var s/,/Println/
+
+Useful for a sly type assertion (from `src/os/exec/exec_test.go`):
+
+	// Check that we can access methods of the underlying os.File.
+	if _, ok := stdin.(interface {
+		Fd() uintptr
+	}); !ok {
+		t.Error("can't access methods of underlying *os.File")
+	}
+
+
+* Method values
+
+A "method value" is what you get when you evaluate a method as an expression.
+The result is a function value.
+
+Evaluating a method from a _type_ yields a function:
+
+.play tricks/method-values-1.go /var f/,/Stdout/
+
+Evaluating a method from a _value_ creates a closure that holds that value:
+
+.play tricks/method-values-2.go /var /,/Stdout/
+
+
+* Method values: sync.Once
+
+The `sync.Once` type is used to perform a task once with concurrency safety.
+
+	// Once is an object that will perform exactly one action.
+	type Once struct { /* Has unexported fields. */ }
+
+	func (o *Once) Do(f func())
+	
+This `LazyPrimes` type computes a slice of prime numbers the first time it is used:
+
+.code tricks/method-once.go /type/,$
+
+
+* Method values: HTTP handlers
+
+You can use method values to implement multiple HTTP handlers with one type:
+
+.code tricks/method-http.go /type Server/,$
+
+
+* Method values: another example
+
+In package `os/exec`, the `Cmd` type implements methods to set up
+standard input, output, and error:
+
+	func (c *Cmd) stdin() (f *os.File, err error)
+	func (c *Cmd) stdout() (f *os.File, err error)
+	func (c *Cmd) stderr() (f *os.File, err error)
+
+The caller handles each in the same way,
+so it iterates over a slice of method values:
+
+	type F func(*Cmd) (*os.File, error)
+	for _, setupFd := range []F{(*Cmd).stdin, (*Cmd).stdout, (*Cmd).stderr} {
+		fd, err := setupFd(c)
+		if err != nil {
+			c.closeDescriptors(c.closeAfterStart)
+			c.closeDescriptors(c.closeAfterWait)
+			return err
+		}
+		c.childFiles = append(c.childFiles, fd)
+	}
+
+
+* Comparable types
+
+The Go spec defines a set of types as "comparable";
+they may be compared with == and !=.
+
+Bools, ints, floats, complex numbers, strings, pointers,
+channels, *structs*, and *interfaces* are comparable.
+
+.play tricks/compare.go /BEGIN/,/END/
+
+A struct is comparable only if its fields are comparable:
+
+.play tricks/compare2.go /BEGIN/,/END/
+
+
+* Comparable types and map keys
+
+Any comparable type may be used as a map key.
+
+.code tricks/compare-map.go /BEGIN/,/END/
+
+
+* Structs as map keys
+
+An example from the Go continuous build infrastructure:
+
+	type builderRev struct {
+		builder, rev string
+	}
+
+	var br = builderRev{"linux-amd64", "0cd299"}
+
+We track in-flight builds in a map.
+The pre-Go 1 way was to flatten the data to a string first:
+
+	inflight := map[string]bool{}
+
+	inflight[br.builder + "-" + br.rev] = true
+
+But with struct keys, you can avoid the allocation and have cleaner code:
+
+	inflight := map[builderRev]bool{}
+
+	inflight[br] = true
+
+
+* Interfaces as map keys
+
+An example of interface map keys from Docker's `broadcastwriter` package:
+
+.code tricks/broadcastwriter/broadcastwriter.go /type/,/END/
+
+
+* Structs and interfaces together as map keys
+
+A (very) contrived example: (Don't do this! Ever!)
+
+.play tricks/cons.go /type/,$
+
+
+* Libraries
+
+* sync/atomic
+
+For a simple counter, you can use the `sync/atomic` package's
+functions to make atomic updates without the lock.
+
+	func AddInt64(addr *int64, delta int64) (new int64)
+	func CompareAndSwapInt64(addr *int64, old, new int64) (swapped bool)
+	func LoadInt64(addr *int64) (val int64)
+	func StoreInt64(addr *int64, val int64)
+	func SwapInt64(addr *int64, new int64) (old int64)
+
+First, define the global variable (appropriately documented!):
+
+	// viewCount must be updated atomically.
+	var viewCount int64
+
+Then increment it with `AddInt64`:
+
+	count := atomic.AddInt64(&viewCount, 1)
+
+The set are available for `Int32`, `Uint32`, `Int64`, `Uint64`, `Pointer`, and `Uintptr`.
+
+
+* sync/atomic.Value
+
+Another option for sharing state is `atomic.Value`.
+
+For instance, to share configuration between many goroutines:
+
+	type Config struct {
+		Timeout time.Duration
+	}
+
+	var config atomic.Value
+
+To set or update, use the `Store` method:
+	
+	config.Store(&Config{Timeout: 2*time.Second})
+
+To read, each goroutine calls the `Load` method:
+
+	cfg := config.Load().(*Config)
+
+Note that storing different types in the same `Value` will cause a panic.
+
+
+* sync/atomic.Value: how it works (1/5)
+
+The `atomic.Value` primitive is the size of a single interface value:
+
+	package atomic
+
+	type Value struct {
+		v interface{}
+	}
+
+An interface value is represented by the runtime as two pointers:
+one for the type, and one for the value.
+
+	// ifaceWords is interface{} internal representation.
+	type ifaceWords struct {
+		typ  unsafe.Pointer
+		data unsafe.Pointer
+	}
+
+To load and store an interface value atomically, it operates on the parts of the interface value with `atomic.LoadPointer` and `atomic.StorePointer`.
+
+
+* sync/atomic.Value: how it works (2/5)
+
+The `Store` method first validates the input:
+
+	func (v *Value) Store(x interface{}) {
+		if x == nil {
+			panic("sync/atomic: store of nil value into Value")
+		}
+
+Then uses `unsafe` to cast the current and new `interface{}` values to `ifaceWords`:
+
+	// ...
+		vp := (*ifaceWords)(unsafe.Pointer(v))
+		xp := (*ifaceWords)(unsafe.Pointer(&x))
+
+(This allows us to get at the internals of those interface values.)
+
+
+* sync/atomic.Value: how it works (3/5)
+
+Spin while loading the type field:
+
+	// ...
+		for {
+			typ := LoadPointer(&vp.typ)
+
+If it's `nil` the this is the first time the value has been stored.
+Put a sentinel value (max uintptr) in the type field to "lock" it while we work with it:
+
+	// ...
+			if typ == nil {
+				if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(^uintptr(0))) {
+					continue // Someone beat us to it. Wait.
+				}
+
+Store the data field, then the type field, and we're done!
+
+	// ...
+				StorePointer(&vp.data, xp.data)
+				StorePointer(&vp.typ, xp.typ)
+				return
+			}
+
+* sync/atomic.Value: how it works (4/5)
+
+If this isn't the first store, check whether a store is already happening:
+
+	// ...
+			if uintptr(typ) == ^uintptr(0) {
+				continue // First store in progress. Wait.
+			}
+
+Sanity check whether the type changed:
+
+	// ...
+			if typ != xp.typ {
+				panic("sync/atomic: store of inconsistently typed value into Value")
+			}
+
+If the type field is what we expect, go ahead and atomically store the value:
+
+	// ...
+			StorePointer(&vp.data, xp.data)
+			return
+		}
+	}
+
+* sync/atomic.Value: how it works (5/5)
+
+The `Load` method first loads the interface's type field:
+
+	func (v *Value) Load() (x interface{}) {
+		vp := (*ifaceWords)(unsafe.Pointer(v))
+		typ := LoadPointer(&vp.typ)
+
+Then, check whether a store has happened, or is happening:
+
+	// ...
+		if typ == nil || uintptr(typ) == ^uintptr(0) {
+			return nil
+		}
+
+Otherwise, load the data field and return both type and data as a new interface value:
+
+	// ...
+		data := LoadPointer(&vp.data)
+		xp := (*ifaceWords)(unsafe.Pointer(&x))
+		xp.typ = typ
+		xp.data = data
+		return
+	}
+
+
+* A note on sync/atomic
+
+Usually you don't want or need the stuff in this package.
+
+Try channels or the `sync` package first.
+
+You almost certainly shouldn't write code like the `atomic.Value` implementation.
+(And I didn't show all of it; the real code has hooks into the runtime.)
+
+
+* Tools
+
+
+* Testing
+
+* Subprocess tests
+
+Sometimes you need to test the behavior of a process, not just a function.
+
+.code tricks/subprocess/subprocess.go /func Crasher/,/^}/
+
+To test this code, we invoke the test binary itself as a subprocess:
+
+.code tricks/subprocess/subprocess_test.go /func TestCrasher/,/^}/
+
+
+* Subprocess benchmarks (1/2)
+
+Go's CPU and memory profilers report data for an entire process.
+To profile just one side of a concurrent operation, you can use a sub-process.
+
+This benchmark from the `net/http` package spawns a child process to make
+requests to a server running in the main process.
+
+	func BenchmarkServer(b *testing.B) {
+		b.ReportAllocs()
+		// Child process mode;
+		if url := os.Getenv("TEST_BENCH_SERVER_URL"); url != "" {
+			n, err := strconv.Atoi(os.Getenv("TEST_BENCH_CLIENT_N"))
+			if err != nil {
+				panic(err)
+			}
+			for i := 0; i < n; i++ {
+				res, err := Get(url)
+				// ...
+			}
+			os.Exit(0)
+			return
+		}
+	// ...
+
+* Subprocess benchmarks (2/2)
+
+	// ...
+		res := []byte("Hello world.\n")
+		ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, r *Request) {
+			rw.Header().Set("Content-Type", "text/html; charset=utf-8")
+			rw.Write(res)
+		}))
+		defer ts.Close()
+
+		cmd := exec.Command(os.Args[0], "-test.run=XXXX", "-test.bench=BenchmarkServer$")
+		cmd.Env = append([]string{
+			fmt.Sprintf("TEST_BENCH_CLIENT_N=%d", b.N),
+			fmt.Sprintf("TEST_BENCH_SERVER_URL=%s", ts.URL),
+		}, os.Environ()...)
+		if out, err := cmd.CombinedOutput(); err != nil {
+			b.Errorf("Test failure: %v, with output: %s", err, out)
+		}
+	}
+
+To run:
+
+	$ go test -run=XX -bench=BenchmarkServer -benchtime=15s -cpuprofile=http.prof
+	$ go tool pprof http.test http.prof
+
+
+* go list
+
+* go list
+
+	$ go help list
+	usage: go list [-e] [-f format] [-json] [build flags] [packages]
+
+	List lists the packages named by the import paths, one per line.
+
+Show the packages under a path:
+
+	$ go list golang.org/x/oauth2/...
+	golang.org/x/oauth2
+	...
+	golang.org/x/oauth2/vk
+
+Show the standard library:
+
+	$ go list std
+	archive/tar
+	...
+	unsafe
+
+Show all packages:
+
+	$ go list all
+
+* go list -json
+
+The `-json` flag tells you everything the go tool knows about a package:
+
+	$ go list -json bytes
+	{
+		"Dir": "/Users/adg/go/src/bytes",
+		"ImportPath": "bytes",
+		"Name": "bytes",
+		"Doc": "Package bytes implements functions for the manipulation of byte slices.",
+		"Target": "/Users/adg/go/pkg/darwin_amd64/bytes.a",
+		"Goroot": true,
+		"Standard": true,
+		"Stale": true,
+		"Root": "/Users/adg/go",
+		"GoFiles": [
+			"buffer.go",
+			"bytes.go",
+			"bytes_decl.go",
+			"reader.go"
+		],
+		...
+	}
+
+It's easy to write programs that consume this data.
+
+* go list's Package struct (1/3)
+
+The go tool's documented `Package` struct describes all the possible fields:
+
+	type Package struct {
+		Dir           string // directory containing package sources
+		ImportPath    string // import path of package in dir
+		ImportComment string // path in import comment on package statement
+		Name          string // package name
+		Doc           string // package documentation string
+		Target        string // install path
+		Shlib         string // the shared library that contains this package (only set when -linkshared)
+		Goroot        bool   // is this package in the Go root?
+		Standard      bool   // is this package part of the standard Go library?
+		Stale         bool   // would 'go install' do anything for this package?
+		Root          string // Go root or Go path dir containing this package
+
+		// (more fields on next slide)
+	}
+
+* go list's Package struct (2/3)
+
+	type Package struct {
+		// (more fields on previous slide)
+
+		// Source files
+		GoFiles        []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
+		CgoFiles       []string // .go sources files that import "C"
+		IgnoredGoFiles []string // .go sources ignored due to build constraints
+		CFiles         []string // .c source files
+		CXXFiles       []string // .cc, .cxx and .cpp source files
+		MFiles         []string // .m source files
+		HFiles         []string // .h, .hh, .hpp and .hxx source files
+		SFiles         []string // .s source files
+		SwigFiles      []string // .swig files
+		SwigCXXFiles   []string // .swigcxx files
+		SysoFiles      []string // .syso object files to add to archive
+
+		// (more fields on next slide)
+	}
+
+* go list's Package struct (3/3)
+
+	type Package struct {
+		// (more fields on previous slide)
+
+		// Cgo directives
+		CgoCFLAGS    []string // cgo: flags for C compiler
+		CgoCPPFLAGS  []string // cgo: flags for C preprocessor
+		CgoCXXFLAGS  []string // cgo: flags for C++ compiler
+		CgoLDFLAGS   []string // cgo: flags for linker
+		CgoPkgConfig []string // cgo: pkg-config names
+
+		// Dependency information
+		Imports []string // import paths used by this package
+		Deps    []string // all (recursively) imported dependencies
+
+		// Error information
+		Incomplete bool            // this package or a dependency has an error
+		Error      *PackageError   // error loading package
+		DepsErrors []*PackageError // errors loading dependencies
+
+		TestGoFiles  []string // _test.go files in package
+		TestImports  []string // imports from TestGoFiles
+		XTestGoFiles []string // _test.go files outside package
+		XTestImports []string // imports from XTestGoFiles
+	}
+
+* go list -f (1/2)
+
+That's a ton of information, so what can we do with it?
+
+The `-f` flag lets you use Go's `text/template` package to format the ouput.
+
+Show package doc strings:
+
+	$ go list -f '{{.Doc}}' golang.org/x/oauth2/...
+	Package oauth2 provides support for making OAuth2 authorized and authenticated HTTP requests.
+	Package jwt implements the OAuth 2.0 JSON Web Token flow, commonly known as "two-legged OAuth 2.0".
+	...
+
+Show the Go files in a package:
+
+	$ go list -f '{{.GoFiles}}' bytes
+	[buffer.go bytes.go bytes_decl.go reader.go]
+
+Make the output cleaner with a `join`:
+
+	$ go list -f '{{join .GoFiles " "}}' bytes
+	buffer.go bytes.go bytes_decl.go reader.go 
+
+* go list -f (2/2)
+
+With template logic we can test packages for certain conditions.
+
+Find standard libraries that lack documentation:
+
+	$ go list -f '{{if not .Doc}}{{.ImportPath}}{{end}}' std
+	internal/format
+	internal/trace
+
+Find packages that depend (directly or indirectly) on a given package:
+
+	$ go list -f '{{range .Deps}}{{if eq . "golang.org/x/oauth2"}}{{$.ImportPath}}{{end}}{{end}}' all
+	golang.org/x/build/auth
+	golang.org/x/build/buildlet
+	golang.org/x/build/cmd/buildlet
+	...
+
+Find packages that are broken somehow (note `-e`):
+
+	$ go list -e -f '{{with .Error}}{{.}}{{end}}' all
+	package github.com/golang/oauth2: code in directory /Users/adg/src/github.com/golang/oauth2
+		expects import "golang.org/x/oauth2"
+	...
+
+* go list and the shell
+
+Things get interesting once we start using the shell.
+
+For instance, we can use `go` `list` output as input to the go tool.
+
+Test all packages except vendored packages:
+
+	$ go test $(go list ./... | grep -v '/vendor/')
+
+Test the dependencies of a specific package:
+
+	$ go test $(go list -f '{{join .Deps " "}}' golang.org/x/oauth2)
+
+The same, but don't test the standard library:
+
+	$ go test $(
+		go list -f '{{if (not .Goroot)}}{{.ImportPath}}{{end}}' $(
+			go list -f '{{join .Deps " "}}' golang.org/x/oauth2
+		)
+	)
+
+* go list printing line counts
+
+	for pkg in $(go list golang.org/x/oauth2/...); do
+		wc -l $(go list -f '{{range .GoFiles}}{{$.Dir}}/{{.}} {{end}}' $pkg) | \
+			tail -1 | awk '{ print $1 " '$pkg'" }'
+	done | sort -nr
+
+The output:
+
+	617 golang.org/x/oauth2/google
+	600 golang.org/x/oauth2
+	357 golang.org/x/oauth2/internal
+	160 golang.org/x/oauth2/jws
+	147 golang.org/x/oauth2/jwt
+	112 golang.org/x/oauth2/clientcredentials
+	22 golang.org/x/oauth2/paypal
+	16 golang.org/x/oauth2/vk
+	16 golang.org/x/oauth2/odnoklassniki
+	16 golang.org/x/oauth2/linkedin
+	16 golang.org/x/oauth2/github
+	16 golang.org/x/oauth2/facebook
+
+* go list generating dependency graphs
+
+	(   echo "digraph G {"
+		go list -f '{{range .Imports}}{{printf "\t%q -> %q;\n" $.ImportPath .}}{{end}}' \
+			$(go list -f '{{join .Deps " "}}' time) time
+		echo "}"
+	) | dot -Tsvg -o time-deps.svg
+
+.image tricks/time-deps.png 400 _
+
+
+* And there's more!
+
+There are many more fun corners of Go.
+Can you find them all? :-)
+
+Read the docs, explore, and have fun!
diff --git a/2015/tricks/anon-interface.go b/2015/tricks/anon-interface.go
new file mode 100644
index 0000000..676fd71
--- /dev/null
+++ b/2015/tricks/anon-interface.go
@@ -0,0 +1,13 @@
+package main
+
+import (
+	"bytes"
+	"fmt"
+)
+
+func main() {
+	var s interface {
+		String() string
+	} = bytes.NewBufferString("I'm secretly a fmt.Stringer!")
+	fmt.Println(s.String())
+}
diff --git a/2015/tricks/broadcastwriter/broadcastwriter.go b/2015/tricks/broadcastwriter/broadcastwriter.go
new file mode 100644
index 0000000..2e039c7
--- /dev/null
+++ b/2015/tricks/broadcastwriter/broadcastwriter.go
@@ -0,0 +1,46 @@
+package broadcastwriter
+
+import (
+	"io"
+	"sync"
+)
+
+type BroadcastWriter struct {
+	sync.Mutex
+	writers map[io.WriteCloser]struct{}
+}
+
+func (w *BroadcastWriter) AddWriter(writer io.WriteCloser) {
+	w.Lock()
+	w.writers[writer] = struct{}{}
+	w.Unlock()
+}
+
+func (w *BroadcastWriter) Write(p []byte) (n int, err error) {
+	w.Lock()
+	for sw := range w.writers {
+		if n, err := sw.Write(p); err != nil || n != len(p) {
+			delete(w.writers, sw)
+		}
+	}
+	w.Unlock()
+	return len(p), nil
+}
+
+// END OMIT
+
+func (w *BroadcastWriter) Clean() error {
+	w.Lock()
+	for w := range w.writers {
+		w.Close()
+	}
+	w.writers = make(map[io.WriteCloser]struct{})
+	w.Unlock()
+	return nil
+}
+
+func New() *BroadcastWriter {
+	return &BroadcastWriter{
+		writers: make(map[io.WriteCloser]struct{}),
+	}
+}
diff --git a/2015/tricks/compare-map.go b/2015/tricks/compare-map.go
new file mode 100644
index 0000000..e95e133
--- /dev/null
+++ b/2015/tricks/compare-map.go
@@ -0,0 +1,27 @@
+package main
+
+import "io/ioutil"
+
+func main() {
+	// BEGIN OMIT
+	a := map[int]bool{}
+	a[42] = true
+
+	type T struct {
+		i int
+		s string
+	}
+
+	b := map[*T]bool{}
+	b[&T{}] = true
+
+	c := map[T]bool{}
+	c[T{37, "hello!"}] = true
+
+	d := map[interface{}]bool{}
+	d[42] = true
+	d[&T{}] = true
+	d[T{123, "four five six"}] = true
+	d[ioutil.Discard] = true
+	// END OMIT
+}
diff --git a/2015/tricks/compare.go b/2015/tricks/compare.go
new file mode 100644
index 0000000..8a9162a
--- /dev/null
+++ b/2015/tricks/compare.go
@@ -0,0 +1,17 @@
+package main
+
+import "fmt"
+
+func main() {
+	// BEGIN OMIT
+	var a, b int = 42, 42
+	fmt.Println(a == b)
+
+	var i, j interface{} = a, b
+	fmt.Println(i == j)
+
+	var s, t struct{ i interface{} }
+	s.i, t.i = a, b
+	fmt.Println(s == t)
+	// END OMIT
+}
diff --git a/2015/tricks/compare2.go b/2015/tricks/compare2.go
new file mode 100644
index 0000000..6687f34
--- /dev/null
+++ b/2015/tricks/compare2.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+func main() {
+	// BEGIN OMIT
+	var q, r struct{ s []string }
+	fmt.Println(q == r)
+	// END OMIT
+}
diff --git a/2015/tricks/cons.go b/2015/tricks/cons.go
new file mode 100644
index 0000000..6a79e0a
--- /dev/null
+++ b/2015/tricks/cons.go
@@ -0,0 +1,25 @@
+package main
+
+import "fmt"
+
+type cons struct {
+	car string
+	cdr interface{}
+}
+
+func (c cons) String() string {
+	if c.cdr == nil || c.cdr == (cons{}) {
+		return c.car
+	}
+	return fmt.Sprintf("%v %v", c.car, c.cdr)
+}
+
+func main() {
+	m := map[cons]string{}
+	c := cons{}
+	for _, s := range []string{"life?", "with my", "I doing", "What am"} {
+		c = cons{s, c}
+	}
+	m[c] = "No idea."
+	fmt.Println(c, m[c])
+}
diff --git a/2015/tricks/embed.go b/2015/tricks/embed.go
new file mode 100644
index 0000000..a987d69
--- /dev/null
+++ b/2015/tricks/embed.go
@@ -0,0 +1,22 @@
+package main
+
+import "fmt"
+
+// BEGIN OMIT
+type A struct {
+	s string
+}
+
+func (a A) String() string {
+	return fmt.Sprintf("A's String method called: %v", a.s)
+}
+
+type B struct {
+	A
+}
+
+func main() {
+	b := B{}
+	b.s = "some value"
+	fmt.Println(b)
+}
diff --git a/2015/tricks/json-decode.go b/2015/tricks/json-decode.go
new file mode 100644
index 0000000..4cb20e5
--- /dev/null
+++ b/2015/tricks/json-decode.go
@@ -0,0 +1,19 @@
+package main
+
+import (
+	"encoding/json"
+	"fmt"
+	"log"
+)
+
+func main() {
+	var data struct {
+		ID   int
+		Name string
+	}
+	err := json.Unmarshal([]byte(`{"ID": 42, "Name": "The answer"}`), &data)
+	if err != nil {
+		log.Fatal(err)
+	}
+	fmt.Println(data.ID, data.Name)
+}
diff --git a/2015/tricks/json-encode.go b/2015/tricks/json-encode.go
new file mode 100644
index 0000000..106c5a9
--- /dev/null
+++ b/2015/tricks/json-encode.go
@@ -0,0 +1,18 @@
+package main
+
+import (
+	"encoding/json"
+	"fmt"
+	"log"
+)
+
+func main() {
+	b, err := json.Marshal(struct {
+		ID   int
+		Name string
+	}{42, "The answer"})
+	if err != nil {
+		log.Fatal(err)
+	}
+	fmt.Printf("%s\n", b)
+}
diff --git a/2015/tricks/json-nest.go b/2015/tricks/json-nest.go
new file mode 100644
index 0000000..90c68df
--- /dev/null
+++ b/2015/tricks/json-nest.go
@@ -0,0 +1,23 @@
+package main
+
+import (
+	"encoding/json"
+	"fmt"
+	"log"
+)
+
+func main() {
+	var data struct {
+		ID     int
+		Person struct {
+			Name string
+			Job  string
+		}
+	}
+	const s = `{"ID":42,"Person":{"Name":"George Costanza","Job":"Architect"}}`
+	err := json.Unmarshal([]byte(s), &data)
+	if err != nil {
+		log.Fatal(err)
+	}
+	fmt.Println(data.ID, data.Person.Name, data.Person.Job)
+}
diff --git a/2015/tricks/method-http.go b/2015/tricks/method-http.go
new file mode 100644
index 0000000..eeb7f26
--- /dev/null
+++ b/2015/tricks/method-http.go
@@ -0,0 +1,19 @@
+package main
+
+import "net/http"
+
+func main() {}
+
+type Server struct {
+	// Server state.
+}
+
+func (s *Server) index(w http.ResponseWriter, r *http.Request)  { /* Implementation. */ }
+func (s *Server) edit(w http.ResponseWriter, r *http.Request)   { /* Implementation. */ }
+func (s *Server) delete(w http.ResponseWriter, r *http.Request) { /* Implementation. */ }
+
+func (s *Server) Register(mux *http.ServeMux) {
+	mux.HandleFunc("/", s.index)
+	mux.HandleFunc("/edit/", s.edit)
+	mux.HandleFunc("/delete/", s.delete)
+}
diff --git a/2015/tricks/method-once.go b/2015/tricks/method-once.go
new file mode 100644
index 0000000..186296d
--- /dev/null
+++ b/2015/tricks/method-once.go
@@ -0,0 +1,17 @@
+package main
+
+import "sync"
+
+type LazyPrimes struct {
+	once   sync.Once // Guards the primes slice.
+	primes []int
+}
+
+func (p *LazyPrimes) init() {
+	// Populate p.primes with prime numbers.
+}
+
+func (p *LazyPrimes) Primes() []int {
+	p.once.Do(p.init)
+	return p.primes
+}
diff --git a/2015/tricks/method-values-1.go b/2015/tricks/method-values-1.go
new file mode 100644
index 0000000..99044f1
--- /dev/null
+++ b/2015/tricks/method-values-1.go
@@ -0,0 +1,14 @@
+package main
+
+import (
+	"bytes"
+	"os"
+)
+
+func main() {
+	var f func(*bytes.Buffer, string) (int, error)
+	var buf bytes.Buffer
+	f = (*bytes.Buffer).WriteString
+	f(&buf, "y u no buf.WriteString?")
+	buf.WriteTo(os.Stdout)
+}
diff --git a/2015/tricks/method-values-2.go b/2015/tricks/method-values-2.go
new file mode 100644
index 0000000..14c41a5
--- /dev/null
+++ b/2015/tricks/method-values-2.go
@@ -0,0 +1,15 @@
+package main
+
+import (
+	"bytes"
+	"os"
+)
+
+func main() {
+	var f func(string) (int, error)
+	var buf bytes.Buffer
+	f = buf.WriteString
+	f("Hey... ")
+	f("this *is* cute.")
+	buf.WriteTo(os.Stdout)
+}
diff --git a/2015/tricks/repeated.go b/2015/tricks/repeated.go
new file mode 100644
index 0000000..3b86e97
--- /dev/null
+++ b/2015/tricks/repeated.go
@@ -0,0 +1,21 @@
+package main
+
+// BEGIN OMIT
+type Foo struct {
+	i int
+	s string
+}
+
+var s = []Foo{
+	{6 * 9, "Question"},
+	{42, "Answer"},
+}
+
+var m = map[int]Foo{
+	7: {6 * 9, "Question"},
+	3: {42, "Answer"},
+}
+
+// END OMIT
+
+func main() {}
diff --git a/2015/tricks/repeated2.go b/2015/tricks/repeated2.go
new file mode 100644
index 0000000..4d11e40
--- /dev/null
+++ b/2015/tricks/repeated2.go
@@ -0,0 +1,28 @@
+package main
+
+// BEGIN1 OMIT
+var s = []struct {
+	i int
+	s string
+}{
+	struct {
+		i int
+		s string
+	}{6 * 9, "Question"},
+	struct {
+		i int
+		s string
+	}{42, "Answer"},
+}
+
+var t = []struct {
+	i int
+	s string
+}{
+	{6 * 9, "Question"},
+	{42, "Answer"},
+}
+
+// END OMIT
+
+func main() {}
diff --git a/2015/tricks/string_test.go b/2015/tricks/string_test.go
new file mode 100644
index 0000000..76a739f
--- /dev/null
+++ b/2015/tricks/string_test.go
@@ -0,0 +1,27 @@
+package strings_test
+
+import (
+	"strings"
+	"testing"
+)
+
+func TestIndex(t *testing.T) {
+	var tests = []struct {
+		s   string
+		sep string
+		out int
+	}{
+		{"", "", 0},
+		{"", "a", -1},
+		{"fo", "foo", -1},
+		{"foo", "foo", 0},
+		{"oofofoofooo", "f", 2},
+		// etc
+	}
+	for _, test := range tests {
+		actual := strings.Index(test.s, test.sep)
+		if actual != test.out {
+			t.Errorf("Index(%q,%q) = %v; want %v", test.s, test.sep, actual, test.out)
+		}
+	}
+}
diff --git a/2015/tricks/string_test2.go b/2015/tricks/string_test2.go
new file mode 100644
index 0000000..3afb4e9
--- /dev/null
+++ b/2015/tricks/string_test2.go
@@ -0,0 +1,26 @@
+package strings_test
+
+import (
+	"strings"
+	"testing"
+)
+
+func TestIndex(t *testing.T) {
+	for _, test := range []struct {
+		s   string
+		sep string
+		out int
+	}{
+		{"", "", 0},
+		{"", "a", -1},
+		{"fo", "foo", -1},
+		{"foo", "foo", 0},
+		{"oofofoofooo", "f", 2},
+		// etc
+	} {
+		actual := strings.Index(test.s, test.sep)
+		if actual != test.out {
+			t.Errorf("Index(%q,%q) = %v; want %v", test.s, test.sep, actual, test.out)
+		}
+	}
+}
diff --git a/2015/tricks/subprocess/subprocess.go b/2015/tricks/subprocess/subprocess.go
new file mode 100644
index 0000000..8fb8fc0
--- /dev/null
+++ b/2015/tricks/subprocess/subprocess.go
@@ -0,0 +1,11 @@
+package subprocess
+
+import (
+	"fmt"
+	"os"
+)
+
+func Crasher() {
+	fmt.Println("Going down in flames!")
+	os.Exit(1)
+}
diff --git a/2015/tricks/subprocess/subprocess_test.go b/2015/tricks/subprocess/subprocess_test.go
new file mode 100644
index 0000000..fbdcecc
--- /dev/null
+++ b/2015/tricks/subprocess/subprocess_test.go
@@ -0,0 +1,21 @@
+package subprocess
+
+import (
+	"os"
+	"os/exec"
+	"testing"
+)
+
+func TestCrasher(t *testing.T) {
+	if os.Getenv("BE_CRASHER") == "1" {
+		Crasher()
+		return
+	}
+	cmd := exec.Command(os.Args[0], "-test.run=TestCrasher")
+	cmd.Env = append(os.Environ(), "BE_CRASHER=1")
+	err := cmd.Run()
+	if e, ok := err.(*exec.ExitError); ok && !e.Success() {
+		return
+	}
+	t.Fatalf("process ran with err %q, want exit status 1", err)
+}
diff --git a/2015/tricks/template.go b/2015/tricks/template.go
new file mode 100644
index 0000000..e6b79fe
--- /dev/null
+++ b/2015/tricks/template.go
@@ -0,0 +1,32 @@
+package main
+
+import (
+	"log"
+	"os"
+	"strings"
+	"text/template"
+)
+
+func main() {
+	tmpl := template.Must(template.New("").Parse(strings.TrimSpace(`
+Dear {{.Title}} {{.Lastname}},
+
+Congratulations on reaching Level {{.Rank}}!
+I'm sure your parents would say "Great job, {{.Firstname}}!"
+
+Sincerely,
+Rear Admiral Gopher
+	`)))
+	// BEGIN OMIT
+	data := struct {
+		Title               string
+		Firstname, Lastname string
+		Rank                int
+	}{
+		"Dr", "Carl", "Sagan", 7,
+	}
+	if err := tmpl.Execute(os.Stdout, data); err != nil {
+		log.Fatal(err)
+	}
+	// END OMIT
+}
diff --git a/2015/tricks/time-deps.png b/2015/tricks/time-deps.png
new file mode 100644
index 0000000..93ee00b
--- /dev/null
+++ b/2015/tricks/time-deps.png
Binary files differ