go.talks: add "Go for Gophers" slides

LGTM=r
R=r, robert.hencke
CC=golang-codereviews
https://golang.org/cl/97780044
diff --git a/2014/go4gophers.slide b/2014/go4gophers.slide
new file mode 100644
index 0000000..55d87d0
--- /dev/null
+++ b/2014/go4gophers.slide
@@ -0,0 +1,827 @@
+Go for gophers
+GopherCon closing keynote
+25 Apr 2014
+
+Andrew Gerrand
+adg@golang.org
+
+
+* About me
+
+.image go4gophers/gopherswim.jpg
+
+I joined Google and the Go team in February 2010.
+
+Had to re-think some of my preconceptions about programming.
+
+Let me share what I have learned since.
+
+
+* Interfaces
+
+
+* Interfaces: first impressions
+
+I used to think about classes and types.
+
+Go resists this:
+
+- No inheritance.
+- No subtype polymorphism.
+- No generics.
+
+It instead emphasizes _interfaces_.
+
+
+* Interfaces: the Go way
+
+Go interfaces are small.
+
+	type Stringer interface {
+		String() string
+	}
+
+A `Stringer` can pretty print itself.
+Anything that implements `String` is a `Stringer`.
+
+
+* An interface example
+
+An `io.Reader` value emits a stream of binary data.
+
+	type Reader interface {
+		Read([]byte) (int, error)
+	}
+
+Like a UNIX pipe.
+
+
+* Implementing interfaces
+
+.code go4gophers/reader.go /ByteReader/,/^}/
+
+
+* Wrapping interfaces
+
+.code go4gophers/reader.go /LogReader/,/STOP/
+
+Wrapping a `ByteReader` with a `LogReader`:
+
+.play go4gophers/reader.go /START/,/STOP/
+
+By wrapping we compose interface _values_.
+
+
+* Chaining interfaces
+
+Wrapping wrappers to build chains:
+
+.code go4gophers/chain.go /START/,/STOP/
+
+More succinctly:
+
+.play go4gophers/chain.go /LogReader{io/
+
+Implement complex behavior by composing small pieces.
+
+
+* Programming with interfaces
+
+Interfaces separate data from behavior.
+
+With interfaces, functions can operate on _behavior:_
+
+	// Copy copies from src to dst until either EOF is reached
+	// on src or an error occurs.  It returns the number of bytes
+	// copied and the first error encountered while copying, if any.
+	func Copy(dst Writer, src Reader) (written int64, err error) {
+
+.play go4gophers/chain.go /LogReader{io/
+
+`Copy` can't know about the underlying data structures.
+
+
+* A larger interface
+
+`sort.Interface` describes the operations required to sort a collection:
+
+	type Interface interface {
+	    Len() int
+	    Less(i, j int) bool
+	    Swap(i, j int)
+	}
+
+`IntSlice` can sort a slice of ints:
+
+	type IntSlice []int
+
+	func (p IntSlice) Len() int           { return len(p) }
+	func (p IntSlice) Less(i, j int) bool { return p[i] < p[j] }
+	func (p IntSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
+
+`sort.Sort` uses can sort a `[]int` with `IntSlice`:
+
+.play go4gophers/sort.go /START/,/STOP/
+
+
+* Another interface example
+
+The `Organ` type describes a body part and can print itself:
+
+.play go4gophers/organs.go /type Organ/,$
+
+
+* Sorting organs
+
+The `Organs` type knows how to describe and mutate a slice of organs:
+
+.code go4gophers/organs2.go /PART1/,/PART2/
+
+The `ByName` and `ByWeight` types embed `Organs` to sort by different fields:
+
+.code go4gophers/organs2.go /PART2/,/PART3/
+
+With embedding we compose _types_.
+
+
+* Sorting organs (continued)
+
+To sort a `[]*Organ`, wrap it with `ByName` or `ByWeight` and pass it to `sort.Sort`:
+
+.play go4gophers/organs2.go /START/,/STOP/
+
+
+* Another wrapper
+
+The `Reverse` function takes a `sort.Interface` and
+returns a `sort.Interface` with an inverted `Less` method:
+
+.code go4gophers/organs3.go /func Reverse/,$
+
+To sort the organs in descending order, compose our sort types with `Reverse`:
+
+.play go4gophers/organs3.go /START/,/STOP/
+
+
+* Interfaces: why they work
+
+These are not just cool tricks.
+
+This is how we structure programs in Go.
+
+
+* Interfaces: Sigourney
+
+Sigourney is a modular audio synthesizer I wrote in Go.
+
+.image go4gophers/sigourney.png
+
+Audio is generated by a chain of `Processors`:
+
+	type Processor interface {
+		Process(buffer []Sample)
+	}
+
+([[https://github.com/nf/sigourney][github.com/nf/sigourney]])
+
+
+* Interfaces: Roshi
+
+Roshi is a time-series event store written by Peter Bourgon. It provides this API:
+	
+	Insert(key, timestamp, value)
+	Delete(key, timestamp, value)
+	Select(key, offset, limit) []TimestampValue
+
+The same API is implemented by the `farm` and `cluster` parts of the system.
+
+.image go4gophers/roshi.png
+
+An elegant design that exhibits composition.
+([[https://github.com/soundcloud/roshi][github.com/soundcloud/roshi]])
+
+
+* Interfaces: why they work (continued)
+
+Interfaces are _the_ generic programming mechanism.
+
+This gives all Go code a familiar shape.
+
+Less is more.
+
+
+* Interfaces: why they work (continued)
+
+It's all about composition.
+
+Interfaces—by design and convention—encourage us to write composable code.
+
+
+* Interfaces: why they work (continued)
+
+Interfaces types are just types
+and interface values are just values.
+
+They are orthogonal to the rest of the language.
+
+
+* Interfaces: why they work (continued)
+
+Interfaces separate data from behavior. (Classes conflate them.)
+
+	type HandlerFunc func(ResponseWriter, *Request)
+
+	func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
+		f(w, r)
+	}
+
+
+* Interfaces: what I learned
+
+Think about composition.
+
+Better to have many small simple things than one big complex thing.
+
+Also: what I thought of as small is pretty big.
+
+Some repetition in the small is okay when it benefits "the large".
+
+
+* Concurrency
+
+
+* Concurrency: first impressions
+
+My first exposure to concurrency was in C, Java, and Python.
+Later: event-driven models in Python and JavaScript.
+
+When I saw Go I saw:
+
+"The performance of an event-driven model without callback hell."
+
+But I had questions: "Why can't I wait on or kill a goroutine?"
+
+
+* Concurrency: the Go way
+
+Goroutines provide concurrent execution.
+
+Channels express the communication and synchronization of independent processes.
+
+Select enables computation on channel operations.
+
+.image go4gophers/gopherflag.png
+
+
+* A concurrency example
+
+The binary tree comparison exercise from the Go Tour.
+
+"Implement a function
+
+        func Same(t1, t2 *tree.Tree) bool
+
+that compares the contents of two binary trees."
+
+.image go4gophers/tree.png
+
+
+* Walking a tree
+
+	type Tree struct {
+		Left, Right *Tree
+		Value int
+	}
+
+A simple depth-first tree traversal:
+
+.play go4gophers/tree-walk.go /func Walk/,$
+
+
+* Comparing trees (1/2)
+
+A concurrent walker:
+
+.code go4gophers/tree-thread.go /func Walk/,/STOP/
+
+
+* Comparing trees (2/2)
+
+Walking two trees concurrently:
+
+.play go4gophers/tree-thread.go /func Same/,$
+
+
+* Comparing trees without channels (1/3)
+
+.code go4gophers/tree-nothread.go /func Same/,/^}/
+
+The `Walk` function has nearly the same signature:
+
+.code go4gophers/tree-nothread.go /func Walk/
+.code go4gophers/tree-nothread.go /func.+Next/
+
+(We call `Next` instead of the channel receive.)
+
+
+* Comparing trees without channels (2/3)
+
+But the implementation is much more complex:
+
+.code go4gophers/tree-nothread.go /func Walk/,/CUT/
+
+
+* Comparing trees without channels (3/3)
+
+.code go4gophers/tree-nothread.go /CUT/,/STOP/
+
+
+* Another look at the channel version
+
+.code go4gophers/tree-thread.go /func Walk/,/STOP/
+
+But there's a problem: when an inequality is found,
+a goroutine might be left blocked sending to `ch`.
+
+
+* Stopping early
+
+Add a `quit` channel to the walker so we can stop it mid-stride.
+
+.code go4gophers/tree-select.go /func Walk/,/STOP/
+
+
+* Stopping early (continued)
+
+Create a `quit` channel and pass it to each walker.
+By closing `quit` when the `Same` exits, any running walkers are terminated.
+
+.code go4gophers/tree-select.go /func Same/,/^}/
+
+
+* Why not just kill the goroutines?
+
+Goroutines are invisible to Go code. They can't be killed or waited on.
+
+You have to build that yourself.
+
+There's a reason:
+
+As soon as Go code knows in which thread it runs you get thread-locality.
+
+Thread-locality defeats the concurrency model.
+
+
+* Concurrency: why it works
+
+The model makes concurrent code easy to read and write.
+(Makes concurrency is *accessible*.)
+
+This encourages the decomposition of independent computations.
+
+
+* Concurrency: why it works (continued)
+
+The simplicity of the concurrency model makes it flexible.
+
+Channels are just values; they fit right into the type system.
+
+Goroutines are invisible to Go code; this gives you concurrency anywhere.
+
+Less is more.
+
+
+* Concurrency: what I learned
+
+Concurrency is not just for doing more things faster.
+
+It's for writing better code.
+
+
+* Syntax
+
+
+* Syntax: first impressions
+
+At first, Go syntax felt a bit inflexible and verbose.
+
+It affords few of the conveniences to which I was accustomed.
+
+For instance:
+
+- No getters/setters on fields.
+- No map/filter/reduce/zip.
+- No optional arguments.
+
+
+* Syntax: the Go way
+
+Favor readability above all.
+
+Offer enough sugar to be productive, but not too much.
+
+
+* Getters and setters (or "properties")
+
+Getters and setters turn assignments and reads into function calls.
+This leads to surprising hidden behavior.
+
+In Go, just write (and call) the methods.
+
+The control flow cannot be obscured.
+
+
+* Map/filter/reduce/zip
+
+Map/filter/reduce/zip are useful  in Python.
+
+	a = [1, 2, 3, 4]
+	b = map(lambda x: x+1, a)
+
+In Go, you just write the loops.
+
+	a := []int{1, 2, 3, 4}
+	b := make([]int, len(a))
+	for i, x := range a {
+		b[i] = x+1
+	}
+
+This is a little more verbose,
+but makes the performance characteristics obvious.
+
+It's easy code to write, and you get more control.
+
+
+* Optional arguments
+
+Go functions can't have optional arguments.
+
+Instead, use variations of the function:
+
+	func NewWriter(w io.Writer) *Writer
+	func NewWriterLevel(w io.Writer, level int) (*Writer, error)
+
+Or an options struct:
+
+	func New(o *Options) (*Jar, error)
+
+	type Options struct {
+		PublicSuffixList PublicSuffixList
+	}
+
+Or a variadic list of options.
+
+Create many small simple things, not one big complex thing.
+
+
+* Syntax: why it works
+
+The language resists convoluted code.
+
+With obvious control flow, it's easy to navigate unfamiliar code.
+
+Instead we create more small things that are easy to document and understand.
+
+So Go code is easy to read.
+
+(And with gofmt, it's easy to write readable code.)
+
+
+* Syntax: what I learned
+
+I was often too clever for my own good.
+
+I appreciate the consistency, clarity, and _transparency_ of Go code.
+
+I sometimes miss the conveniences, but rarely.
+
+
+* Error handling
+
+
+* Error handling: first impressions
+
+I had previously used exceptions to handle errors.
+
+Go's error handling model felt verbose by comparison.
+
+I was immediately tired of typing this:
+
+	if err != nil {
+		return err
+	}
+
+
+* Error handling: the Go way
+
+Go codifies errors with the built-in `error` interface:
+
+	type error interface {
+		Error() string
+	}
+
+Error values are used just like any other value.
+
+	func doSomething() error
+
+	err := doSomething()
+	if err != nil {
+		log.Println("An error occurred:", err)
+	}
+
+Error handling code is just code.
+
+(Started as a convention (`os.Error`). We made it built in for Go 1.)
+
+
+* Error handling: why it works
+
+Error handling is important.
+
+Go makes error handling as important as any other code.
+
+
+* Error handling: why it works (continued)
+
+Errors are just values; they fit easily into the rest of the language
+(interfaces, channels, and so on).
+
+Result: Go code handles errors correctly and elegantly.
+
+
+* Error handling: why it works (continued)
+
+We use the same language for errors as everything else.
+
+Lack of hidden control flow (throw/try/catch/finally) improves readability.
+
+Less is more.
+
+
+
+* Error handling: what I learned
+
+To write good code we must think about errors.
+
+Exceptions make it easy to avoid thinking about errors.
+(Errors shouldn't be "exceptional!")
+
+Go encourages us to consider every error condition.
+
+My Go programs are far more robust than my programs in other languages.
+
+I don't miss exceptions at all.
+
+
+* Packages
+
+
+* Packages: first impressions
+
+I found the capital-letter-visibility rule weird;
+"Let me use my own naming scheme!"
+
+I didn't like "package per directory";
+"Let me use my own structure!"
+
+I was disappointed by lack of monkey patching.
+
+
+* Packages: the Go way
+
+Go packages are a name space for types, functions, variables, and constants.
+
+
+* Visibility
+
+Visibility is at the package level.
+Names are "exported" when they begin with a capital letter.
+
+	package zip
+
+	func NewReader(r io.ReaderAt, size int64) (*Reader, error) // exported
+
+	type Reader struct {    // exported
+		File    []*File     // exported
+		Comment string      // exported
+		r       io.ReaderAt // unexported
+	}
+
+	func (f *File) Open() (rc io.ReadCloser, err error)   // exported
+
+	func (f *File) findBodyOffset() (int64, error)        // unexported
+
+	func readDirectoryHeader(f *File, r io.Reader) error  // unexported
+
+Good for readability: easy to see whether a name is part of the public interface.
+Good for design: couples naming decisions with interface decisions.
+
+
+* Package structure
+
+Packages can be spread across multiple files.
+
+Permits shared private implementation and informal code organization.
+
+Packages files must live in a directory unique to the package.
+
+The path to that directory determines the package's import path.
+
+The build system locates dependencies from the source alone.
+
+
+* "Monkey patching"
+
+Go forbids modifying package declarations from outside the package.
+
+But we can get similar behavior using global variables:
+
+	package flag
+
+	var Usage = func() {
+		fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
+		PrintDefaults()
+	}
+
+Or registration functions:
+
+	package http
+
+	func Handle(pattern string, handler Handler)
+
+This gives the flexibility of monkey patching but on the package author's terms.
+
+(This depends on Go's initialization semantics.)
+
+
+* Packages: why they work
+
+The loose organization of packages lets us write and refactor code quickly.
+
+But packages encourage the programmer to consider the public interface.
+
+This leads to good names and simpler interfaces.
+
+With the source as the single source of truth,
+there are no makefiles to get out of sync.
+
+(This design enables great tools like [[http://godoc.org][godoc.org]] and goimports.)
+
+Predictable semantics make packages easy to read, understand, and use.
+
+
+* Packages: what I learned
+
+Go's package system taught me to prioritize the consumer of my code.
+(Even if that consumer is me.)
+
+It also stopped me from doing gross stuff.
+
+Packages are rigid where it matters, and loose where it doesn't.
+It just feels right.
+
+Probably my favorite part of the language.
+
+
+* Documentation
+
+
+* Documentation: first impressions
+
+Godoc reads documentation from Go source code, like `pydoc` or `javadoc`.
+
+But unlike those two, it doesn't support complex formatting or other meta data.
+Why?
+
+
+* Documentation: the Go way
+
+Godoc comments precede the declaration of an exported identifier:
+
+	// Join concatenates the elements of a to create a single string.
+	// The separator string sep is placed between elements in the resulting string.
+	func Join(a []string, sep string) string {
+
+It extracts the comments and presents them:
+
+	$ godoc strings Join
+	func Join(a []string, sep string) string
+	    Join concatenates the elements of a to create a single string. The
+	    separator string sep is placed between elements in the resulting string.
+
+Also integrated with the testing framework to provide testable example functions.
+
+	func ExampleJoin() {
+		s := []string{"foo", "bar", "baz"}
+		fmt.Println(strings.Join(s, ", "))
+		// Output: foo, bar, baz
+	}
+
+
+* Documentation: the Go way (continued)
+
+.image go4gophers/godoc.png
+
+
+* Documentation: why it works
+
+Godoc wants you to write good comments, so the source looks great:
+
+	// ValidMove reports whether the specified move is valid.
+	func ValidMove(from, to Position) bool
+
+Javadoc just wants to produce pretty documentation, so the source is hideous:
+
+	/**
+	 * Validates a chess move.
+	 *
+	 * @param fromPos  position from which a piece is being moved
+	 * @param toPos    position to which a piece is being moved
+	 * @return         true if the move is valid, otherwise false
+	 */
+	boolean isValidMove(Position fromPos, Position toPos)
+
+(Also a grep for `"ValidMove"` will return the first line of documentation.)
+
+
+* Documentation: what I learned
+
+Godoc taught me to write documentation _as_I_code._
+
+Writing documentation _improves_the_code_ I write.
+
+
+* More
+
+There are many more examples.
+
+The overriding theme:
+
+- At first, something seemed weird or lacking.
+- I realized it was a design decision.
+
+Those decisions make the language—and Go code—better.
+
+Sometimes you have to live with the language a while to see it.
+
+
+* Lessons
+
+
+* Code is communication
+
+Be articulate:
+
+- Choose good names.
+- Design simple interfaces.
+- Write precise documentation.
+- Don't be too clever.
+
+
+* Less is exponentially more
+
+New features can weaken existing features.
+
+Features multiply complexity.
+
+Complexity defeats orthogonality.
+
+Orthogonality is vital: it enables composition.
+
+
+* Composition is key
+
+Don't solve problems by building _a_ thing.
+
+Instead, combine simple tools and compose them.
+
+
+* Design good interfaces
+
+.image go4gophers/gophertraining.png
+
+.html go4gophers/gophertraining.html
+
+
+* Simplicity is hard
+
+Invest the time to find the simple solution.
+
+
+* Go's effect on me
+
+These lessons were all things I already "knew".
+
+Go helped me internalize them.
+
+.image go4gophers/gopherhat.jpg
+
+Go made me a better programmer.
+
+
+* A message for gophers everywhere
+
+Let's build small, simple, and beautiful things together.
+
+.image go4gophers/gopherswrench.jpg
+
diff --git a/2014/go4gophers/chain.go b/2014/go4gophers/chain.go
new file mode 100644
index 0000000..1e1c5f0
--- /dev/null
+++ b/2014/go4gophers/chain.go
@@ -0,0 +1,39 @@
+package main
+
+import (
+	"io"
+	"io/ioutil"
+	"log"
+)
+
+// ByteReader implements an io.Reader that emits a stream of its byte value.
+type ByteReader byte
+
+func (b ByteReader) Read(buf []byte) (int, error) {
+	for i := range buf {
+		buf[i] = byte(b)
+	}
+	return len(buf), nil
+}
+
+type LogReader struct {
+	io.Reader
+}
+
+func (r LogReader) Read(b []byte) (int, error) {
+	n, err := r.Reader.Read(b)
+	log.Printf("read %d bytes, error: %v", n, err)
+	return n, err
+}
+
+func main() {
+	// START OMIT
+	var r io.Reader = ByteReader('A')
+	r = io.LimitReader(r, 1e6)
+	r = LogReader{r}
+	io.Copy(ioutil.Discard, r)
+	// STOP OMIT
+
+	return
+	io.Copy(ioutil.Discard, LogReader{io.LimitReader(ByteReader('A'), 1e6)})
+}
diff --git a/2014/go4gophers/copy.go b/2014/go4gophers/copy.go
new file mode 100644
index 0000000..ee671ad
--- /dev/null
+++ b/2014/go4gophers/copy.go
@@ -0,0 +1,32 @@
+package main
+
+import (
+	"io"
+	"io/ioutil"
+	"log"
+)
+
+// ByteReader implements an io.Reader that emits a stream of its byte value.
+type ByteReader byte
+
+func (b ByteReader) Read(buf []byte) (int, error) {
+	for i := range buf {
+		buf[i] = byte(b)
+	}
+	return len(buf), nil
+}
+
+type LogReader struct {
+	io.Reader
+}
+
+func (r LogReader) Read(b []byte) (int, error) {
+	n, err := r.Reader.Read(b)
+	log.Printf("read %d bytes, error: %v", n, err)
+	return n, err
+}
+
+func main() {
+	r := LogReader{ByteReader('A')}
+	io.CopyN(ioutil.Discard, r, 1e6)
+}
diff --git a/2014/go4gophers/godoc.png b/2014/go4gophers/godoc.png
new file mode 100644
index 0000000..3ef664e
--- /dev/null
+++ b/2014/go4gophers/godoc.png
Binary files differ
diff --git a/2014/go4gophers/gopherflag.png b/2014/go4gophers/gopherflag.png
new file mode 100644
index 0000000..230628c
--- /dev/null
+++ b/2014/go4gophers/gopherflag.png
Binary files differ
diff --git a/2014/go4gophers/gopherhat.jpg b/2014/go4gophers/gopherhat.jpg
new file mode 100644
index 0000000..ad770d9
--- /dev/null
+++ b/2014/go4gophers/gopherhat.jpg
Binary files differ
diff --git a/2014/go4gophers/gopherswim.jpg b/2014/go4gophers/gopherswim.jpg
new file mode 100644
index 0000000..8f80192
--- /dev/null
+++ b/2014/go4gophers/gopherswim.jpg
Binary files differ
diff --git a/2014/go4gophers/gopherswrench.jpg b/2014/go4gophers/gopherswrench.jpg
new file mode 100644
index 0000000..690fdb0
--- /dev/null
+++ b/2014/go4gophers/gopherswrench.jpg
Binary files differ
diff --git a/2014/go4gophers/gophertraining.html b/2014/go4gophers/gophertraining.html
new file mode 100644
index 0000000..42d1bc5
--- /dev/null
+++ b/2014/go4gophers/gophertraining.html
@@ -0,0 +1,5 @@
+<div style="width: 700px; margin-left: 50%; left: -350px; position: relative">
+<div style="float:left">Don't over-specify.</div>
+<div style="float:right">Don't under-specify.</div>
+<div style="clear:both; text-align: center"><br>Find the sweet spot.</div>
+</div>
diff --git a/2014/go4gophers/gophertraining.png b/2014/go4gophers/gophertraining.png
new file mode 100644
index 0000000..b4d4538
--- /dev/null
+++ b/2014/go4gophers/gophertraining.png
Binary files differ
diff --git a/2014/go4gophers/organs.go b/2014/go4gophers/organs.go
new file mode 100644
index 0000000..e84b672
--- /dev/null
+++ b/2014/go4gophers/organs.go
@@ -0,0 +1,23 @@
+package main
+
+import "fmt"
+
+type Organ struct {
+	Name   string
+	Weight Grams
+}
+
+func (o *Organ) String() string { return fmt.Sprintf("%v (%v)", o.Name, o.Weight) }
+
+type Grams int
+
+func (g Grams) String() string { return fmt.Sprintf("%dg", int(g)) }
+
+func main() {
+	s := []*Organ{{"brain", 1340}, {"heart", 290},
+		{"liver", 1494}, {"pancreas", 131}, {"spleen", 162}}
+
+	for _, o := range s {
+		fmt.Println(o)
+	}
+}
diff --git a/2014/go4gophers/organs2.go b/2014/go4gophers/organs2.go
new file mode 100644
index 0000000..0a25b58
--- /dev/null
+++ b/2014/go4gophers/organs2.go
@@ -0,0 +1,61 @@
+package main
+
+import (
+	"fmt"
+	"sort"
+)
+
+type Organ struct {
+	Name   string
+	Weight Grams
+}
+
+func (o *Organ) String() string { return fmt.Sprintf("%v (%v)", o.Name, o.Weight) }
+
+type Grams int
+
+func (g Grams) String() string { return fmt.Sprintf("%dg", int(g)) }
+
+// PART1 OMIT
+
+type Organs []*Organ
+
+func (s Organs) Len() int      { return len(s) }
+func (s Organs) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+
+// PART2 OMIT
+
+type ByName struct{ Organs }
+
+func (s ByName) Less(i, j int) bool { return s.Organs[i].Name < s.Organs[j].Name }
+
+type ByWeight struct{ Organs }
+
+func (s ByWeight) Less(i, j int) bool { return s.Organs[i].Weight < s.Organs[j].Weight }
+
+// PART3 OMIT
+
+func main() {
+	// START OMIT
+	s := []*Organ{
+		{"brain", 1340},
+		{"heart", 290},
+		{"liver", 1494},
+		{"pancreas", 131},
+		{"spleen", 162},
+	}
+
+	sort.Sort(ByWeight{s}) // HL
+	printOrgans("Organs by weight", s)
+
+	sort.Sort(ByName{s}) // HL
+	printOrgans("Organs by name", s)
+	// STOP OMIT
+}
+
+func printOrgans(t string, s []*Organ) {
+	fmt.Printf("%s:\n", t)
+	for _, o := range s {
+		fmt.Printf("  %v\n", o)
+	}
+}
diff --git a/2014/go4gophers/organs3.go b/2014/go4gophers/organs3.go
new file mode 100644
index 0000000..9216886
--- /dev/null
+++ b/2014/go4gophers/organs3.go
@@ -0,0 +1,65 @@
+package main
+
+import (
+	"fmt"
+	"sort"
+)
+
+type Organ struct {
+	Name   string
+	Weight Grams
+}
+
+func (o *Organ) String() string { return fmt.Sprintf("%v (%v)", o.Name, o.Weight) }
+
+type Grams int
+
+func (g Grams) String() string { return fmt.Sprintf("%dg", int(g)) }
+
+type Organs []*Organ
+
+func (s Organs) Len() int      { return len(s) }
+func (s Organs) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+
+type ByName struct{ Organs }
+
+func (s ByName) Less(i, j int) bool { return s.Organs[i].Name < s.Organs[j].Name }
+
+type ByWeight struct{ Organs }
+
+func (s ByWeight) Less(i, j int) bool { return s.Organs[i].Weight < s.Organs[j].Weight }
+
+func main() {
+	s := []*Organ{
+		{"brain", 1340},
+		{"heart", 290},
+		{"liver", 1494},
+		{"pancreas", 131},
+		{"spleen", 162},
+	}
+
+	// START OMIT
+	sort.Sort(Reverse(ByWeight{s})) // HL
+	printOrgans("Organs by weight (descending)", s)
+
+	sort.Sort(Reverse(ByName{s})) // HL
+	printOrgans("Organs by name (descending)", s)
+	// STOP OMIT
+}
+
+func printOrgans(t string, s []*Organ) {
+	fmt.Printf("%s:\n", t)
+	for _, o := range s {
+		fmt.Printf("  %v\n", o)
+	}
+}
+
+func Reverse(data sort.Interface) sort.Interface {
+	return &reverse{data}
+}
+
+type reverse struct{ sort.Interface }
+
+func (r reverse) Less(i, j int) bool {
+	return r.Interface.Less(j, i) // HL
+}
diff --git a/2014/go4gophers/reader.go b/2014/go4gophers/reader.go
new file mode 100644
index 0000000..78d3281
--- /dev/null
+++ b/2014/go4gophers/reader.go
@@ -0,0 +1,38 @@
+package main
+
+import (
+	"fmt"
+	"io"
+	"log"
+)
+
+// ByteReader implements an io.Reader that emits a stream of its byte value.
+type ByteReader byte
+
+func (b ByteReader) Read(buf []byte) (int, error) {
+	for i := range buf {
+		buf[i] = byte(b)
+	}
+	return len(buf), nil
+}
+
+type LogReader struct {
+	io.Reader
+}
+
+func (r LogReader) Read(b []byte) (int, error) {
+	n, err := r.Reader.Read(b)
+	log.Printf("read %d bytes, error: %v", n, err)
+	return n, err
+}
+
+// STOP OMIT
+
+func main() {
+	// START OMIT
+	r := LogReader{ByteReader('A')}
+	b := make([]byte, 10)
+	r.Read(b)
+	fmt.Printf("b: %q", b)
+	// STOP OMIT
+}
diff --git a/2014/go4gophers/reverse.go b/2014/go4gophers/reverse.go
new file mode 100644
index 0000000..7b65730
--- /dev/null
+++ b/2014/go4gophers/reverse.go
@@ -0,0 +1,13 @@
+package main
+
+import "sort"
+
+func Reverse(data sort.Interface) sort.Interface {
+	return &reverse{data}
+}
+
+type reverse struct{ sort.Interface }
+
+func (r reverse) Less(i, j int) bool {
+	return r.Interface.Less(j, i) // HL
+}
diff --git a/2014/go4gophers/roshi.png b/2014/go4gophers/roshi.png
new file mode 100644
index 0000000..3bfbf5f
--- /dev/null
+++ b/2014/go4gophers/roshi.png
Binary files differ
diff --git a/2014/go4gophers/select.go b/2014/go4gophers/select.go
new file mode 100644
index 0000000..e552405
--- /dev/null
+++ b/2014/go4gophers/select.go
@@ -0,0 +1,34 @@
+package main
+
+import (
+	"net/http"
+	"text/template"
+	"time"
+)
+
+type Result struct{}
+
+func WebSearch(q string) *Result   { return nil }
+func ImageSearch(q string) *Result { return nil }
+
+var searchTemplate *template.Template
+
+func searchHandler(w http.ResponseWriter, r *http.Request) {
+	var (
+		results []*Result
+		ch      = make(chan *Result)
+		timeout = time.After(20 * time.Millisecond)
+	)
+	go func() { ch <- WebSearch(r) }()
+	go func() { ch <- ImageSearch(r) }()
+loop:
+	for i := 0; i < 2; i++ {
+		select { // HL
+		case r := <-ch: // HL
+			results = append(results, r)
+		case <-timeout: // HL
+			break loop
+		}
+	}
+	searchTemplate.Execute(w, results)
+}
diff --git a/2014/go4gophers/sigourney.png b/2014/go4gophers/sigourney.png
new file mode 100644
index 0000000..5bd8403
--- /dev/null
+++ b/2014/go4gophers/sigourney.png
Binary files differ
diff --git a/2014/go4gophers/sort.go b/2014/go4gophers/sort.go
new file mode 100644
index 0000000..1397887
--- /dev/null
+++ b/2014/go4gophers/sort.go
@@ -0,0 +1,20 @@
+package main
+
+import (
+	"fmt"
+	"sort"
+)
+
+type IntSlice []int
+
+func (p IntSlice) Len() int           { return len(p) }
+func (p IntSlice) Less(i, j int) bool { return p[i] < p[j] }
+func (p IntSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
+
+func main() {
+	// START OMIT
+	s := []int{7, 5, 3, 11, 2}
+	sort.Sort(IntSlice(s))
+	fmt.Println(s)
+	// STOP OMIT
+}
diff --git a/2014/go4gophers/spin.go b/2014/go4gophers/spin.go
new file mode 100644
index 0000000..0d21283
--- /dev/null
+++ b/2014/go4gophers/spin.go
@@ -0,0 +1,57 @@
+package main
+
+import (
+	"fmt"
+	"io"
+	"io/ioutil"
+	"time"
+)
+
+type Zero struct{}
+
+func (Zero) Read(b []byte) (int, error) {
+	for i := range b {
+		b[i] = 0
+	}
+	return len(b), nil
+}
+
+type SleepReader struct {
+	r io.Reader
+	d time.Duration
+}
+
+func (r SleepReader) Read(b []byte) (int, error) {
+	time.Sleep(r.d)
+	return r.r.Read(b)
+}
+
+// END OMIT
+
+type Spinner int
+
+var spinBytes = []byte{'-', '/', '|', '\\'}
+
+func (s *Spinner) Tick() {
+	*s = (*s + 1) % 4
+	fmt.Printf("\x0cReading...%c", spinBytes[*s])
+}
+
+type SpinReader struct {
+	r io.Reader
+	s Spinner
+}
+
+func (r *SpinReader) Read(b []byte) (int, error) {
+	r.s.Tick()
+	return r.r.Read(b)
+}
+
+func main() {
+	var r io.Reader = Zero{}
+	r = io.LimitReader(r, 1e6)
+	r = SleepReader{r, 20 * time.Millisecond}
+	r = &SpinReader{r: r}
+	n, _ := io.Copy(ioutil.Discard, r)
+	fmt.Print("\x0c", n, " bytes read.")
+}
diff --git a/2014/go4gophers/time.go b/2014/go4gophers/time.go
new file mode 100644
index 0000000..297a83f
--- /dev/null
+++ b/2014/go4gophers/time.go
@@ -0,0 +1,23 @@
+package main
+
+import "time"
+
+var now = time.Now
+
+type timeImpl interface {
+	Now() time.Time
+}
+
+type systemTime struct{}
+
+func (systemTime) Now() time.Time        { return time.Now() }
+func (systemTime) Sleep(d time.Duration) { time.Sleep(d) }
+
+type fakeTime time.Time
+
+func (t *fakeTime) Now() time.Time        { return time.Time(*t) }
+func (t *fakeTime) Sleep(d time.Duration) { *t = fakeTime(time.Time(*t).Add(d)) }
+
+func Sleeper() {
+
+}
diff --git a/2014/go4gophers/tree-nothread.go b/2014/go4gophers/tree-nothread.go
new file mode 100644
index 0000000..c3cb6d7
--- /dev/null
+++ b/2014/go4gophers/tree-nothread.go
@@ -0,0 +1,71 @@
+package main
+
+import (
+	"fmt"
+
+	"code.google.com/p/go-tour/tree"
+)
+
+func Walk(root *tree.Tree) *Walker {
+	return &Walker{stack: []*frame{{t: root}}}
+}
+
+type Walker struct {
+	stack []*frame
+}
+
+type frame struct {
+	t  *tree.Tree
+	pc int
+}
+
+func (w *Walker) Next() (int, bool) {
+	if len(w.stack) == 0 {
+		return 0, false
+	}
+
+	// continued next slide ...
+	// CUT OMIT
+	f := w.stack[len(w.stack)-1]
+	if f.pc == 0 {
+		f.pc++
+		if l := f.t.Left; l != nil {
+			w.stack = append(w.stack, &frame{t: l})
+			return w.Next()
+		}
+	}
+	if f.pc == 1 {
+		f.pc++
+		return f.t.Value, true
+	}
+	if f.pc == 2 {
+		f.pc++
+		if r := f.t.Right; r != nil {
+			w.stack = append(w.stack, &frame{t: r})
+			return w.Next()
+		}
+	}
+	w.stack = w.stack[:len(w.stack)-1]
+	return w.Next()
+}
+
+// STOP OMIT
+
+func Same(t1, t2 *tree.Tree) bool {
+	w1, w2 := Walk(t1), Walk(t2)
+	for {
+		v1, ok1 := w1.Next()
+		v2, ok2 := w2.Next()
+		if v1 != v2 || ok1 != ok2 {
+			return false
+		}
+		if !ok1 {
+			return true
+		}
+	}
+}
+
+func main() {
+	fmt.Println(Same(tree.New(3), tree.New(3)))
+	fmt.Println(Same(tree.New(1), tree.New(2)))
+}
diff --git a/2014/go4gophers/tree-select.go b/2014/go4gophers/tree-select.go
new file mode 100644
index 0000000..1623ec3
--- /dev/null
+++ b/2014/go4gophers/tree-select.go
@@ -0,0 +1,53 @@
+package main
+
+import (
+	"fmt"
+
+	"code.google.com/p/go-tour/tree"
+)
+
+func Walk(root *tree.Tree, quit chan struct{}) chan int {
+	ch := make(chan int)
+	go func() {
+		walk(root, ch, quit)
+		close(ch)
+	}()
+	return ch
+}
+
+func walk(t *tree.Tree, ch chan int, quit chan struct{}) {
+	if t.Left != nil {
+		walk(t.Left, ch, quit)
+	}
+	select { // HL
+	case ch <- t.Value: // HL
+	case <-quit: // HL
+		return // HL
+	} // HL
+	if t.Right != nil {
+		walk(t.Right, ch, quit)
+	}
+}
+
+// STOP OMIT
+
+func Same(t1, t2 *tree.Tree) bool {
+	quit := make(chan struct{}) // HL
+	defer close(quit)           // HL
+	w1, w2 := Walk(t1, quit), Walk(t2, quit)
+	for {
+		v1, ok1 := <-w1
+		v2, ok2 := <-w2
+		if v1 != v2 || ok1 != ok2 {
+			return false
+		}
+		if !ok1 {
+			return true
+		}
+	}
+}
+
+func main() {
+	fmt.Println(Same(tree.New(3), tree.New(3)))
+	fmt.Println(Same(tree.New(1), tree.New(2)))
+}
diff --git a/2014/go4gophers/tree-thread.go b/2014/go4gophers/tree-thread.go
new file mode 100644
index 0000000..bf1db5c
--- /dev/null
+++ b/2014/go4gophers/tree-thread.go
@@ -0,0 +1,47 @@
+package main
+
+import (
+	"fmt"
+
+	"code.google.com/p/go-tour/tree"
+)
+
+func Walk(root *tree.Tree) chan int {
+	ch := make(chan int)
+	go func() {
+		walk(root, ch)
+		close(ch)
+	}()
+	return ch
+}
+
+func walk(t *tree.Tree, ch chan int) {
+	if t.Left != nil {
+		walk(t.Left, ch)
+	}
+	ch <- t.Value
+	if t.Right != nil {
+		walk(t.Right, ch)
+	}
+}
+
+// STOP OMIT
+
+func Same(t1, t2 *tree.Tree) bool {
+	w1, w2 := Walk(t1), Walk(t2)
+	for {
+		v1, ok1 := <-w1
+		v2, ok2 := <-w2
+		if v1 != v2 || ok1 != ok2 {
+			return false
+		}
+		if !ok1 {
+			return true
+		}
+	}
+}
+
+func main() {
+	fmt.Println(Same(tree.New(3), tree.New(3)))
+	fmt.Println(Same(tree.New(1), tree.New(2)))
+}
diff --git a/2014/go4gophers/tree-walk.go b/2014/go4gophers/tree-walk.go
new file mode 100644
index 0000000..c4c7ea0
--- /dev/null
+++ b/2014/go4gophers/tree-walk.go
@@ -0,0 +1,21 @@
+package main
+
+import (
+	"fmt"
+
+	"code.google.com/p/go-tour/tree"
+)
+
+func Walk(t *tree.Tree) {
+	if t.Left != nil {
+		Walk(t.Left)
+	}
+	fmt.Println(t.Value)
+	if t.Right != nil {
+		Walk(t.Right)
+	}
+}
+
+func main() {
+	Walk(tree.New(1))
+}
diff --git a/2014/go4gophers/tree.png b/2014/go4gophers/tree.png
new file mode 100644
index 0000000..a140421
--- /dev/null
+++ b/2014/go4gophers/tree.png
Binary files differ