talks: Go for Java Programmers, to be presented at NYJavaSIG on April 23.

Threw out much of the previous version, replaced it with a Google Search
frontend server adapted from blog.golang.org/context.  Restored the
Google Search concurrency example.  Tightened up several slides.

Down to 49 slides, which is doable, but would be better to cut it down more.

Change-Id: If5427383e946420f41be929256c85ea24b9be4e0
Reviewed-on: https://go-review.googlesource.com/9071
Reviewed-by: Minux Ma <minux@golang.org>
diff --git a/2015/go-for-java-programmers.slide b/2015/go-for-java-programmers.slide
new file mode 100644
index 0000000..27aeabf
--- /dev/null
+++ b/2015/go-for-java-programmers.slide
@@ -0,0 +1,448 @@
+Go for Java Programmers
+
+Sameer Ajmani
+Tech Lead Manager, Go team
+Google
+@Sajma
+sameer@golang.org
+
+* Outline
+
+1. What is Go, and who uses it?
+2. Comparing Go and Java
+3. Examples
+4. Concurrency
+5. Tools
+
+# The next several slides are from rsc's 2013/distsys and 2015/mit talks.
+
+* What is Go?
+
+"Go is an open source programming language that makes it easy to build simple, reliable, and efficient software."
+
+.link http://golang.org
+
+* History
+
+Design began in late 2007.
+
+- Robert Griesemer, Rob Pike, and Ken Thompson.
+- Ian Lance Taylor and Russ Cox.
+
+Open source since 2009 with a very active community.
+
+Language stable as of Go 1, early 2012.
+
+* Why Go?
+
+Go is an answer to problems of scale at Google.
+
+.image ../2012/splash/datacenter.jpg 500 _
+
+* System Scale
+
+- designed to scale to 10⁶⁺ machines
+- everyday jobs run on 1000s of machines
+- jobs coordinate, interact with others in the system
+- lots going on at once
+
+Solution: great support for concurrency
+
+.image ../2012/waza/gophercomplex6.jpg
+
+* A Second Problem: Engineering Scale
+
+In 2011:
+
+- 5000+ developers across 40+ offices
+- 20+ changes per minute
+- 50% of code base changes every month
+- 50 million test cases executed per day
+- single code tree
+
+Solution: design the language for large code bases
+
+* Who uses Go at Google?
+
+Lots of projects. Thousands of Go programmers. Millions of lines of Go code.
+
+Public examples:
+
+- SPDY proxy for Chrome on mobile devices
+
+.image go-for-java-programmers/spdy.png 400 _
+
+* Who uses Go at Google?
+
+Lots of projects. Thousands of Go programmers. Millions of lines of Go code.
+
+Public examples:
+
+- SPDY proxy for Chrome on mobile devices
+- Download server for Chrome, ChromeOS, Android SDK, Earth, etc.
+- YouTube Vitess MySQL balancer
+
+The target is networked servers, but it's a great general-purpose language.
+
+* Who uses Go besides Google?
+
+.link http://golang.org/wiki/GoUsers
+
+Apcera, Bitbucket, bitly, Canonical, CloudFlare, Core OS, Digital Ocean, Docker, Dropbox, Facebook, Getty Images, GitHub, Heroku, Iron.io, Kubernetes, Medium, MongoDB services, Mozilla services, New York Times, pool.ntp.org, Secret, SmugMug, SoundCloud, Stripe, Square, Thomson Reuters, Tumblr, ...
+
+.image ../2014/state-of-go/bus.jpg 300 _
+
+* Comparing Go and Java
+
+* Go and Java have much in common
+
+- C family (imperative, braces)
+- Statically typed
+- Garbage collected
+- Memory safe (nil references, runtime bounds checks)
+- Variables are always initialized (zero/nil/false)
+- Methods
+- Interfaces
+- Type assertions (`instanceof`)
+- Reflection
+
+* Go differs from Java in several ways
+
+- Programs compile to machine code.  There's no VM.
+- Statically linked binaries
+- Control over memory layout
+- Function values and lexical closures
+- Built-in strings (UTF-8)
+- Built-in generic maps and arrays/slices
+- Built-in concurrency
+
+* Go intentionally leaves out many features
+
+- No classes
+- No constructors
+- No inheritance
+- No `final`
+- No exceptions
+- No annotations
+- No user-defined generics
+
+* Why does Go leave out those features?
+
+Clarity is critical.
+
+When reading code, it should be clear what the program will do.
+
+When writing code, it should be clear how to make the program do what you want.
+
+Sometimes this means writing out a loop instead of invoking an obscure function.
+
+(Don't DRY out.)
+
+For more background on design:
+
+- [[http://commandcenter.blogspot.com/2012/06/less-is-exponentially-more.html][Less is exponentially more (Pike, 2012)]]
+- [[http://talks.golang.org/2012/splash.article][Go at Google: Language Design in the Service of Software Engineering (Pike, 2012)]]
+
+* Examples
+
+* Go looks familiar to Java programmers
+
+Main.java
+
+.code go-for-java-programmers/hello/Main.java
+
+hello.go
+
+.play go-for-java-programmers/hello/hello.go
+
+* Hello, web server
+
+.play go-for-java-programmers/hello/server.go
+
+Types follow names in declarations.
+Exported names are Capitalized.  Unexported names are not.
+
+* Example: Google Search frontend
+
+.image go-for-java-programmers/frontend-screenshot.png _ 1000
+
+.play go-for-java-programmers/frontend.go /func main/,/func handleSearch/
+
+* Validate the query
+
+.code go-for-java-programmers/frontend.go /func handleSearch/,/ENDQUERY/
+
+`FormValue` is a method on the type `*http.Request`:
+
+  package http
+  type Request struct {...}
+  func (r *Request) FormValue(key string) string {...}
+
+`query`:=`req.FormValue("q")` initializes a new variable `query` with
+the type of the expression on the right hand side, `string`.
+
+* Fetch the search results
+
+.code go-for-java-programmers/frontend.go /Run the Google search/,/ENDSEARCH/
+
+`Search` returns two values, a slice of results and an error.
+
+  func Search(query string) ([]Result, error) {...}
+
+The results are valid only if the error is nil.
+
+  type error interface {
+      Error() string // a useful human-readable error message
+  }
+
+Errors may contain additional information, accessed via type assertions.
+
+* Render the search results
+
+.code go-for-java-programmers/frontend.go /Render the/,/ENDRENDER/
+
+`resultsTemplate.Execute` generates HTML and writes it to an `io.Writer`:
+
+  type Writer interface {
+          Write(p []byte) (n int, err error)
+  }
+
+`http.ResponseWriter` implements the `io.Writer` interface.
+
+* HTML templates operate on Go values
+
+.play go-for-java-programmers/frontend.go /A Result contains/,/\)\)/
+
+* Issue the query to the Google Search API
+
+.code go-for-java-programmers/frontend.go /func Search/,/resp.Body.Close/
+
+The `defer` statement arranges for `resp.Body.Close` to run when `Search` returns.
+
+* Parse the JSON response into a Go struct
+
+.link https://developers.google.com/web-search/docs/#fonje
+
+.code go-for-java-programmers/frontend.go /var jsonResponse/,/^}/
+
+* That's it for the frontend
+
+All the packages are from the standard library:
+
+  import (
+  	"encoding/json"
+  	"fmt"
+  	"html/template"
+  	"log"
+  	"net/http"
+  	"net/url"
+  	"time"
+  )
+
+Go servers scale well: each request runs in its own _goroutine_.
+
+Let's talk about concurrency.
+
+* Communicating Sequential Processes (Hoare, 1978)
+
+Concurrent programs are structured as independent processes that
+execute sequentially and communicate by passing messages.
+
+Sequential execution is easy to understand.  Async callbacks are not.
+
+"Don't communicate by sharing memory, share memory by communicating."
+
+*Go*primitives:* goroutines, channels, and the `select` statement.
+
+* Goroutines
+
+Goroutines are like lightweight threads.
+
+They start with tiny stacks and resize as needed.
+
+Go programs can have hundreds of thousands of them.
+
+Start a goroutine using the `go` statement:
+
+  go f(args)
+
+The Go runtime schedules goroutines onto OS threads.
+
+Blocked goroutines don't use a thread.
+
+* Channels
+
+Channels provide communication between goroutines.
+
+  c := make(chan string)
+
+  // goroutine 1
+  c <- "hello!"
+
+  // goroutine 2
+  s := <-c
+  fmt.Println(s) // "hello!"
+
+* Select
+
+A `select` statement blocks until communication can proceed.
+
+  select {
+  case n := <-in:
+    fmt.Println("received", n)
+  case out <- v:
+    fmt.Println("sent", v)
+  }
+
+Only the selected case runs.
+
+* Example: Google Search (backend)
+
+Q: What does Google search do?
+
+A: Given a query, return a page of search results (and some ads).
+
+Q: How do we get the search results?
+
+A: Send the query to Web search, Image search, YouTube, Maps, News, etc., then mix the results.
+
+How do we implement this?
+
+* Google Search: A fake framework
+
+We can simulate a Search function with a random timeout up to 100ms.
+
+.code go-for-java-programmers/google-serial.go /START2/,/STOP2/
+
+* Google Search: Test the framework
+
+.play go-for-java-programmers/google-serial.go /func.main/,/}/
+
+* Google Search (serial)
+
+The Google function takes a query and returns a slice of Results (which are just strings).
+
+Google invokes Web, Image, and Video searches serially, appending them to the results slice.
+
+.play go-for-java-programmers/google-serial.go /START1/,/STOP1/
+
+* Google Search (parallel)
+
+Run the Web, Image, and Video searches concurrently, and wait for all results.
+
+The `func` literals are closures over `query` and `c`.
+
+.play go-for-java-programmers/google-parallel.go /Google/,/^}/
+
+* Google Search (timeout)
+
+Don't wait for slow servers.
+
+No locks.  No condition variables.  No callbacks.
+
+.play go-for-java-programmers/google-timeout.go /START/,/STOP/
+
+* Avoid timeout
+
+Q: How do we avoid discarding results from slow servers?
+
+A: Replicate the servers.  Send requests to multiple replicas, and use the first response.
+
+.code go-for-java-programmers/first.go /START1/,/STOP1/
+
+* Using the First function
+
+.play go-for-java-programmers/first.go /START2/,/STOP2/
+
+* Google Search (replicated)
+
+Reduce tail latency using replicated search servers.
+
+.play go-for-java-programmers/google-first.go /START/,/STOP/
+
+* And still…
+
+No locks.  No condition variables.  No callbacks.
+
+* Summary
+
+In just a few simple transformations we used Go's concurrency primitives to convert a
+
+- slow
+- sequential
+- failure-sensitive
+
+program into one that is
+
+- fast
+- concurrent
+- replicated
+- robust.
+
+* Tools
+
+* Go has great tools
+
+- gofmt and goimports
+- the go tool
+- godoc
+- IDE and editor support
+
+The language is designed for tooling.
+
+* gofmt and goimports
+
+Gofmt formats code is formatted automatically.  No options.
+
+Goimports updates import statements based on your workspace.
+
+Most people run these tools on save.
+
+.link http://play.golang.org/p/GPqra77cBK
+
+* The go tool
+
+The go tool builds Go programs from source in a conventional directory layout.
+No Makefiles or other configs.
+
+Fetch the `present` tool and its dependencies, build it, and install it:
+
+  % go get golang.org/x/tools/cmd/present
+
+Run it:
+
+  % present
+
+* godoc
+
+Generated documentation for the world's open-source Go code:
+
+.link http://godoc.org
+
+* IDE and editor support
+
+Eclipse, IntelliJ, emacs, vim, many others.
+
+- `gofmt`
+- `goimports`
+- `godoc` lookups
+- code completion
+- code navigation
+
+There's no "Go IDE".
+
+Go tools meet you where you are.
+
+* Where to Go next
+
+Take the Go Tour online.
+
+.link http://tour.golang.org
+
+Lots more material.
+
+.link http://golang.org/wiki/Learn
+
+Great community.
+
+.link http://golang.org/project
diff --git a/2015/go-for-java-programmers/builtin.go b/2015/go-for-java-programmers/builtin.go
new file mode 100644
index 0000000..fa84ac1
--- /dev/null
+++ b/2015/go-for-java-programmers/builtin.go
@@ -0,0 +1,22 @@
+package main
+
+import (
+	"fmt"
+	"sort"
+)
+
+func main() {
+	hellos := map[string]string{ // HLbuiltin
+		"English":  "Hello",   // HLstrings
+		"Mandarin": "您好",      // HLstrings
+		"Hindi":    "नमस्कार", // HLstrings
+	}
+	fmt.Println(hellos)               // HLfmt
+	var langs []string                // HLbuiltin
+	for lang, hello := range hellos { // HLbuiltin
+		fmt.Println(lang, ":", hello, "world!") // HLfmt
+		langs = append(langs, lang)             // HLbuiltin
+	}
+	sort.Strings(langs)                           // HLstrings
+	fmt.Printf("len(%v) = %d", langs, len(langs)) // HLfmt
+}
diff --git a/2015/go-for-java-programmers/channel.go b/2015/go-for-java-programmers/channel.go
new file mode 100644
index 0000000..d155504
--- /dev/null
+++ b/2015/go-for-java-programmers/channel.go
@@ -0,0 +1,32 @@
+// +build OMIT
+
+package main
+
+import (
+	"fmt"
+	"time"
+)
+
+// STARTMAIN1 OMIT
+type Ball struct{ hits int }
+
+func main() {
+	table := make(chan *Ball) // HL
+	go player("ping", table)
+
+	table <- new(Ball) // game on; toss the ball
+	time.Sleep(1 * time.Second)
+	<-table // game over; grab the ball
+}
+
+func player(name string, table chan *Ball) {
+	for i := 0; ; i++ {
+		ball := <-table // HL
+		ball.hits++
+		fmt.Println(name, i, "hit", ball.hits)
+		time.Sleep(100 * time.Millisecond)
+		table <- ball // HL
+	}
+}
+
+// STOPMAIN1 OMIT
diff --git a/2015/go-for-java-programmers/closure.go b/2015/go-for-java-programmers/closure.go
new file mode 100644
index 0000000..cf8ddc1
--- /dev/null
+++ b/2015/go-for-java-programmers/closure.go
@@ -0,0 +1,28 @@
+package main
+
+import "fmt"
+
+func div(n, d int) (q, r int, err error) {
+	if d == 0 {
+		err = fmt.Errorf("%d/%d: divide by zero", n, d)
+		return
+	}
+	return n / d, n % d, nil
+}
+
+func main() {
+	var failures int
+
+	f := func(n, d int) { // HL
+		if q, r, err := div(n, d); err != nil {
+			fmt.Println(err)
+			failures++ // HL
+		} else {
+			fmt.Printf("%d/%d = %d leaving %d\n", n, d, q, r)
+		}
+	}
+
+	f(4, 3)
+	f(3, 0)
+	fmt.Println("failures:", failures)
+}
diff --git a/2015/go-for-java-programmers/error.go b/2015/go-for-java-programmers/error.go
new file mode 100644
index 0000000..6475a38
--- /dev/null
+++ b/2015/go-for-java-programmers/error.go
@@ -0,0 +1,21 @@
+package main
+
+import (
+	"errors"
+	"fmt"
+)
+
+// div divides n by d and returns the quotient and remainder.
+// It returns an error if d is zero.
+func div(n, d int) (q, r int, err error) { // HL
+	if d == 0 {
+		err = errors.New("divide by zero") // HL
+		return
+	}
+	return n / d, n % d, nil // HL
+}
+
+func main() {
+	fmt.Println(div(4, 3))
+	fmt.Println(div(3, 0))
+}
diff --git a/2015/go-for-java-programmers/first.go b/2015/go-for-java-programmers/first.go
new file mode 100644
index 0000000..590aa7e
--- /dev/null
+++ b/2015/go-for-java-programmers/first.go
@@ -0,0 +1,48 @@
+// +build OMIT
+
+package main
+
+import (
+	"fmt"
+	"math/rand"
+	"time"
+)
+
+type Result string
+type Search func(query string) Result
+
+// START1 OMIT
+func First(query string, replicas ...Search) Result {
+	c := make(chan Result, len(replicas))
+	searchReplica := func(i int) { c <- replicas[i](query) }
+	for i := range replicas {
+		go searchReplica(i)
+	}
+	return <-c
+}
+
+// STOP1 OMIT
+
+func init() {
+	rand.Seed(time.Now().UnixNano())
+}
+
+// START2 OMIT
+func main() {
+	start := time.Now()
+	result := First("golang", // HL
+		fakeSearch("replica 1"), // HL
+		fakeSearch("replica 2")) // HL
+	elapsed := time.Since(start)
+	fmt.Println(result)
+	fmt.Println(elapsed)
+}
+
+// STOP2 OMIT
+
+func fakeSearch(kind string) Search {
+	return func(query string) Result {
+		time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
+		return Result(fmt.Sprintf("%s result for %q\n", kind, query))
+	}
+}
diff --git a/2015/go-for-java-programmers/frontend-screenshot.png b/2015/go-for-java-programmers/frontend-screenshot.png
new file mode 100644
index 0000000..fa5259d
--- /dev/null
+++ b/2015/go-for-java-programmers/frontend-screenshot.png
Binary files differ
diff --git a/2015/go-for-java-programmers/frontend.go b/2015/go-for-java-programmers/frontend.go
new file mode 100644
index 0000000..9d20788
--- /dev/null
+++ b/2015/go-for-java-programmers/frontend.go
@@ -0,0 +1,120 @@
+// The server program issues Google search requests. It serves on port 8080.
+//
+// The /search endpoint accepts these query params:
+//   q=the Google search query
+//
+// For example, http://localhost:8080/search?q=golang serves the first
+// few Google search results for "golang".
+package main
+
+import (
+	"encoding/json"
+	"fmt"
+	"html/template"
+	"log"
+	"net/http"
+	"net/url"
+	"time"
+)
+
+func main() {
+	http.HandleFunc("/search", handleSearch) // HL
+	fmt.Println("serving on http://localhost:8080/search")
+	log.Fatal(http.ListenAndServe("localhost:8080", nil))
+}
+
+// handleSearch handles URLs like "/search?q=golang" by running a
+// Google search for "golang" and writing the results as HTML to w.
+func handleSearch(w http.ResponseWriter, req *http.Request) {
+	log.Println("serving", req.URL)
+
+	// Check the search query.
+	query := req.FormValue("q") // HL
+	if query == "" {
+		http.Error(w, `missing "q" URL parameter`, http.StatusBadRequest)
+		return
+	}
+	// ENDQUERY OMIT
+
+	// Run the Google search.
+	start := time.Now()
+	results, err := Search(query) // HL
+	elapsed := time.Since(start)
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+	// ENDSEARCH OMIT
+
+	// Render the results.
+	type templateData struct {
+		Results []Result
+		Elapsed time.Duration
+	}
+	if err := resultsTemplate.Execute(w, templateData{ // HL
+		Results: results,
+		Elapsed: elapsed,
+	}); err != nil {
+		log.Print(err)
+		return
+	}
+	// ENDRENDER OMIT
+}
+
+// A Result contains the title and URL of a search result.
+type Result struct { // HL
+	Title, URL string // HL
+} // HL
+
+var resultsTemplate = template.Must(template.New("results").Parse(`
+<html>
+<head/>
+<body>
+  <ol>
+  {{range .Results}}
+    <li>{{.Title}} - <a href="{{.URL}}">{{.URL}}</a></li>
+  {{end}}
+  </ol>
+  <p>{{len .Results}} results in {{.Elapsed}}</p>
+</body>
+</html>
+`))
+
+// Search sends query to Google search and returns the results.
+func Search(query string) ([]Result, error) {
+	// Prepare the Google Search API request.
+	u, err := url.Parse("https://ajax.googleapis.com/ajax/services/search/web?v=1.0")
+	if err != nil {
+		return nil, err
+	}
+	q := u.Query()
+	q.Set("q", query) // HL
+	u.RawQuery = q.Encode()
+
+	// Issue the HTTP request and handle the response.
+	resp, err := http.Get(u.String()) // HL
+	if err != nil {
+		return nil, err
+	}
+	defer resp.Body.Close() // HL
+
+	// Parse the JSON search result.
+	// https://developers.google.com/web-search/docs/#fonje
+	var jsonResponse struct {
+		ResponseData struct {
+			Results []struct {
+				TitleNoFormatting, URL string
+			}
+		}
+	}
+	if err := json.NewDecoder(resp.Body).Decode(&jsonResponse); err != nil { // HL
+		return nil, err
+	}
+
+	// Extract the Results from jsonResponse and return them.
+	var results []Result
+	for _, r := range jsonResponse.ResponseData.Results { // HL
+		results = append(results, Result{Title: r.TitleNoFormatting, URL: r.URL})
+	}
+	return results, nil
+}
diff --git a/2015/go-for-java-programmers/func.go b/2015/go-for-java-programmers/func.go
new file mode 100644
index 0000000..3c7a11f
--- /dev/null
+++ b/2015/go-for-java-programmers/func.go
@@ -0,0 +1,13 @@
+package main
+
+import "fmt"
+
+// div divides n by d and returns the quotient and remainder.
+func div(n, d int) (q, r int) { // HL
+	return n / d, n % d
+}
+
+func main() {
+	quot, rem := div(4, 3)
+	fmt.Println(quot, rem)
+}
diff --git a/2015/go-for-java-programmers/gofmt-after.go b/2015/go-for-java-programmers/gofmt-after.go
new file mode 100644
index 0000000..41a1407
--- /dev/null
+++ b/2015/go-for-java-programmers/gofmt-after.go
@@ -0,0 +1,9 @@
+package main
+
+import "fmt"
+
+func main() {
+	for i := 0; i < 3; i++ {
+		fmt.Println("Hello, world")
+	}
+}
diff --git a/2015/go-for-java-programmers/goimports-after.go b/2015/go-for-java-programmers/goimports-after.go
new file mode 100644
index 0000000..d31d69c
--- /dev/null
+++ b/2015/go-for-java-programmers/goimports-after.go
@@ -0,0 +1,11 @@
+package main
+
+import (
+	"fmt"
+
+	"golang.org/x/tools/present"
+)
+
+func main() {
+	fmt.Println(present.Image{})
+}
diff --git a/2015/go-for-java-programmers/goimports-before.go b/2015/go-for-java-programmers/goimports-before.go
new file mode 100644
index 0000000..cec4f48
--- /dev/null
+++ b/2015/go-for-java-programmers/goimports-before.go
@@ -0,0 +1,5 @@
+package main
+
+func main() {
+	fmt.Println(present.Image{})
+}
diff --git a/2015/go-for-java-programmers/google-first.go b/2015/go-for-java-programmers/google-first.go
new file mode 100644
index 0000000..78f5ac4
--- /dev/null
+++ b/2015/go-for-java-programmers/google-first.go
@@ -0,0 +1,71 @@
+// +build OMIT
+
+package main
+
+import (
+	"fmt"
+	"math/rand"
+	"time"
+)
+
+type Result string
+type Search func(query string) Result
+
+var (
+	Web1   = fakeSearch("web1")
+	Web2   = fakeSearch("web2")
+	Image1 = fakeSearch("image1")
+	Image2 = fakeSearch("image2")
+	Video1 = fakeSearch("video1")
+	Video2 = fakeSearch("video2")
+)
+
+func Google(query string) (results []Result) {
+	// START OMIT
+	c := make(chan Result, 3)
+	go func() { c <- First(query, Web1, Web2) }()     // HL
+	go func() { c <- First(query, Image1, Image2) }() // HL
+	go func() { c <- First(query, Video1, Video2) }() // HL
+	timeout := time.After(80 * time.Millisecond)
+	for i := 0; i < 3; i++ {
+		select {
+		case result := <-c:
+			results = append(results, result)
+		case <-timeout:
+			fmt.Println("timed out")
+			return
+		}
+	}
+	return
+	// STOP OMIT
+}
+
+func First(query string, replicas ...Search) Result {
+	c := make(chan Result, len(replicas))
+	searchReplica := func(i int) {
+		c <- replicas[i](query)
+	}
+	for i := range replicas {
+		go searchReplica(i)
+	}
+	return <-c
+}
+
+func fakeSearch(kind string) Search {
+	return func(query string) Result {
+		time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
+		return Result(fmt.Sprintf("%s result for %q\n", kind, query))
+	}
+}
+
+func init() {
+	rand.Seed(time.Now().UnixNano())
+}
+
+func main() {
+	start := time.Now()
+	results := Google("golang")
+	elapsed := time.Since(start)
+	fmt.Println(results)
+	fmt.Println(elapsed)
+}
diff --git a/2015/go-for-java-programmers/google-parallel.go b/2015/go-for-java-programmers/google-parallel.go
new file mode 100644
index 0000000..be3918b
--- /dev/null
+++ b/2015/go-for-java-programmers/google-parallel.go
@@ -0,0 +1,50 @@
+// +build OMIT
+
+package main
+
+import (
+	"fmt"
+	"math/rand"
+	"time"
+)
+
+type Result string
+type Search func(query string) Result
+
+var (
+	Web   = fakeSearch("web")
+	Image = fakeSearch("image")
+	Video = fakeSearch("video")
+)
+
+func Google(query string) (results []Result) {
+	c := make(chan Result)
+	go func() { c <- Web(query) }()
+	go func() { c <- Image(query) }()
+	go func() { c <- Video(query) }()
+
+	for i := 0; i < 3; i++ {
+		result := <-c
+		results = append(results, result)
+	}
+	return
+}
+
+func fakeSearch(kind string) Search {
+	return func(query string) Result {
+		time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
+		return Result(fmt.Sprintf("%s result for %q\n", kind, query))
+	}
+}
+
+func init() {
+	rand.Seed(time.Now().UnixNano())
+}
+
+func main() {
+	start := time.Now()
+	results := Google("golang")
+	elapsed := time.Since(start)
+	fmt.Println(results)
+	fmt.Println(elapsed)
+}
diff --git a/2015/go-for-java-programmers/google-serial.go b/2015/go-for-java-programmers/google-serial.go
new file mode 100644
index 0000000..f512e66
--- /dev/null
+++ b/2015/go-for-java-programmers/google-serial.go
@@ -0,0 +1,51 @@
+// +build OMIT
+
+package main
+
+import (
+	"fmt"
+	"math/rand"
+	"time"
+)
+
+type Result string
+
+// START1 OMIT
+func Google(query string) (results []Result) {
+	results = append(results, Web(query))
+	results = append(results, Image(query))
+	results = append(results, Video(query))
+	return
+}
+
+// STOP1 OMIT
+
+// START2 OMIT
+var (
+	Web   = fakeSearch("web")
+	Image = fakeSearch("image")
+	Video = fakeSearch("video")
+)
+
+type Search func(query string) Result // HL
+
+func fakeSearch(kind string) Search {
+	return func(query string) Result {
+		time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
+		return Result(fmt.Sprintf("%s result for %q\n", kind, query))
+	}
+}
+
+// STOP2 OMIT
+
+func init() {
+	rand.Seed(time.Now().UnixNano())
+}
+
+func main() {
+	start := time.Now()
+	results := Google("golang") // HL
+	elapsed := time.Since(start)
+	fmt.Println(results)
+	fmt.Println(elapsed)
+}
diff --git a/2015/go-for-java-programmers/google-timeout.go b/2015/go-for-java-programmers/google-timeout.go
new file mode 100644
index 0000000..a891f0f
--- /dev/null
+++ b/2015/go-for-java-programmers/google-timeout.go
@@ -0,0 +1,58 @@
+// +build OMIT
+
+package main
+
+import (
+	"fmt"
+	"math/rand"
+	"time"
+)
+
+type Result string
+type Search func(query string) Result
+
+var (
+	Web   = fakeSearch("web")
+	Image = fakeSearch("image")
+	Video = fakeSearch("video")
+)
+
+func Google(query string) (results []Result) {
+	// START OMIT
+	c := make(chan Result, 3)
+	go func() { c <- Web(query) }()
+	go func() { c <- Image(query) }()
+	go func() { c <- Video(query) }()
+
+	timeout := time.After(80 * time.Millisecond)
+	for i := 0; i < 3; i++ {
+		select { // HL
+		case result := <-c: // HL
+			results = append(results, result)
+		case <-timeout: // HL
+			fmt.Println("timed out")
+			return
+		}
+	}
+	return
+	// STOP OMIT
+}
+
+func fakeSearch(kind string) Search {
+	return func(query string) Result {
+		time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
+		return Result(fmt.Sprintf("%s result for %q\n", kind, query))
+	}
+}
+
+func init() {
+	rand.Seed(time.Now().UnixNano())
+}
+
+func main() {
+	start := time.Now()
+	results := Google("golang")
+	elapsed := time.Since(start)
+	fmt.Println(results)
+	fmt.Println(elapsed)
+}
diff --git a/2015/go-for-java-programmers/google1.jpg b/2015/go-for-java-programmers/google1.jpg
new file mode 100644
index 0000000..e52e5f0
--- /dev/null
+++ b/2015/go-for-java-programmers/google1.jpg
Binary files differ
diff --git a/2015/go-for-java-programmers/google14.jpg b/2015/go-for-java-programmers/google14.jpg
new file mode 100644
index 0000000..f83bb9b
--- /dev/null
+++ b/2015/go-for-java-programmers/google14.jpg
Binary files differ
diff --git a/2015/go-for-java-programmers/google17.jpg b/2015/go-for-java-programmers/google17.jpg
new file mode 100644
index 0000000..909b579
--- /dev/null
+++ b/2015/go-for-java-programmers/google17.jpg
Binary files differ
diff --git a/2015/go-for-java-programmers/google20.jpg b/2015/go-for-java-programmers/google20.jpg
new file mode 100644
index 0000000..1ba9213
--- /dev/null
+++ b/2015/go-for-java-programmers/google20.jpg
Binary files differ
diff --git a/2015/go-for-java-programmers/goroutine.go b/2015/go-for-java-programmers/goroutine.go
new file mode 100644
index 0000000..9e9dab7
--- /dev/null
+++ b/2015/go-for-java-programmers/goroutine.go
@@ -0,0 +1,26 @@
+// +build OMIT
+
+package main
+
+import (
+	"fmt"
+	"time"
+)
+
+// STARTMAIN1 OMIT
+type Ball struct{ hits int }
+
+func main() {
+	go player("ping", new(Ball)) // HL
+	time.Sleep(1 * time.Second)
+}
+
+func player(name string, ball *Ball) {
+	for i := 0; ; i++ {
+		ball.hits++
+		fmt.Println(name, i, "hit", ball.hits)
+		time.Sleep(100 * time.Millisecond)
+	}
+}
+
+// STOPMAIN1 OMIT
diff --git a/2015/go-for-java-programmers/hello/Main.class b/2015/go-for-java-programmers/hello/Main.class
new file mode 100644
index 0000000..cccf827
--- /dev/null
+++ b/2015/go-for-java-programmers/hello/Main.class
Binary files differ
diff --git a/2015/go-for-java-programmers/hello/Main.java b/2015/go-for-java-programmers/hello/Main.java
new file mode 100644
index 0000000..73a4d22
--- /dev/null
+++ b/2015/go-for-java-programmers/hello/Main.java
@@ -0,0 +1,5 @@
+public class Main {
+    public static void main(String[] args) {
+        System.out.println("Hello, world!");
+    }
+}
diff --git a/2015/go-for-java-programmers/hello/hello.go b/2015/go-for-java-programmers/hello/hello.go
new file mode 100644
index 0000000..429f248
--- /dev/null
+++ b/2015/go-for-java-programmers/hello/hello.go
@@ -0,0 +1,7 @@
+package main
+
+import "fmt"
+
+func main() {
+	fmt.Println("Hello, 世界!")
+}
diff --git a/2015/go-for-java-programmers/hello/server.go b/2015/go-for-java-programmers/hello/server.go
new file mode 100644
index 0000000..e768548
--- /dev/null
+++ b/2015/go-for-java-programmers/hello/server.go
@@ -0,0 +1,18 @@
+package main
+
+import (
+	"fmt"
+	"log"
+	"net/http"
+)
+
+func main() {
+	http.HandleFunc("/hello", handleHello) // HL
+	fmt.Println("serving on http://localhost:7777/hello")
+	log.Fatal(http.ListenAndServe("localhost:7777", nil))
+}
+
+func handleHello(w http.ResponseWriter, req *http.Request) {
+	log.Println("serving", req.URL)
+	fmt.Fprintln(w, "Hello, 世界!") // HL
+}
diff --git a/2015/go-for-java-programmers/interface.go b/2015/go-for-java-programmers/interface.go
new file mode 100644
index 0000000..c82cf28
--- /dev/null
+++ b/2015/go-for-java-programmers/interface.go
@@ -0,0 +1,31 @@
+package main
+
+import (
+	"bytes"
+	"fmt"
+)
+
+type Point struct {
+	X, Y int
+}
+
+type Rectangle struct {
+	Min, Max Point
+}
+
+func (r Rectangle) String() string {
+	var buf bytes.Buffer
+	for h := 0; h < r.Max.Y-r.Min.Y; h++ {
+		for w := 0; w < r.Max.X-r.Min.X; w++ {
+			buf.WriteString("#")
+		}
+		buf.WriteString("\n")
+	}
+	return buf.String()
+}
+
+func main() {
+	fmt.Println(Rectangle{Max: Point{20, 5}})
+}
+
+// EOF OMIT
diff --git a/2015/go-for-java-programmers/method.go b/2015/go-for-java-programmers/method.go
new file mode 100644
index 0000000..5dc4ca4
--- /dev/null
+++ b/2015/go-for-java-programmers/method.go
@@ -0,0 +1,33 @@
+package main
+
+import (
+	"bytes"
+	"fmt"
+)
+
+type Point struct {
+	X, Y int
+}
+
+type Rectangle struct {
+	Min, Max Point
+}
+
+func (r Rectangle) String() string { // HL
+	var buf bytes.Buffer
+	for h := 0; h < r.Max.Y-r.Min.Y; h++ {
+		for w := 0; w < r.Max.X-r.Min.X; w++ {
+			buf.WriteString("#")
+		}
+		buf.WriteString("\n")
+	}
+	return buf.String()
+}
+
+func main() {
+	r := Rectangle{Max: Point{20, 5}}
+	s := r.String() // HL
+	fmt.Println(s)
+}
+
+// EOF OMIT
diff --git a/2015/go-for-java-programmers/panic.go b/2015/go-for-java-programmers/panic.go
new file mode 100644
index 0000000..f9f0a21
--- /dev/null
+++ b/2015/go-for-java-programmers/panic.go
@@ -0,0 +1,13 @@
+package main
+
+import "fmt"
+
+// div divides n by d and returns the quotient and remainder.
+func div(n, d int) (q, r int) {
+	return n / d, n % d
+}
+
+func main() {
+	quot, rem := div(4, 0) // HL
+	fmt.Println(quot, rem)
+}
diff --git a/2015/go-for-java-programmers/pingpipe.go b/2015/go-for-java-programmers/pingpipe.go
new file mode 100644
index 0000000..df3c563
--- /dev/null
+++ b/2015/go-for-java-programmers/pingpipe.go
@@ -0,0 +1,38 @@
+// +build OMIT
+
+package main
+
+import (
+	"fmt"
+	"time"
+)
+
+// STARTMAIN1 OMIT
+type Ball struct{ hits int }
+
+func main() {
+	in, out := make(chan *Ball), make(chan *Ball) // HL
+	go player("ping", in, out)
+	go player("pong", in, out)
+
+	go func() {
+		for i := 0; i < 8; i++ {
+			in <- new(Ball) // feed the pipeline // HL
+		}
+	}()
+	for i := 0; i < 8; i++ {
+		<-out // drain the pipeline // HL
+	}
+}
+
+func player(name string, in <-chan *Ball, out chan<- *Ball) { // HL
+	for i := 0; ; i++ {
+		ball := <-in // HL
+		ball.hits++
+		fmt.Println(name, i, "hit", ball.hits)
+		time.Sleep(100 * time.Millisecond)
+		out <- ball // HL
+	}
+}
+
+// STOPMAIN1 OMIT
diff --git a/2015/go-for-java-programmers/pingpong.go b/2015/go-for-java-programmers/pingpong.go
new file mode 100644
index 0000000..4ee3f6b
--- /dev/null
+++ b/2015/go-for-java-programmers/pingpong.go
@@ -0,0 +1,33 @@
+// +build OMIT
+
+package main
+
+import (
+	"fmt"
+	"time"
+)
+
+// STARTMAIN1 OMIT
+type Ball struct{ hits int }
+
+func main() {
+	table := make(chan *Ball)
+	go player("ping", table)
+	go player("pong", table) // HL
+
+	table <- new(Ball) // game on; toss the ball
+	time.Sleep(1 * time.Second)
+	<-table // game over; grab the ball
+}
+
+func player(name string, table chan *Ball) {
+	for i := 0; ; i++ {
+		ball := <-table
+		ball.hits++
+		fmt.Println(name, i, "hit", ball.hits)
+		time.Sleep(100 * time.Millisecond)
+		table <- ball
+	}
+}
+
+// STOPMAIN1 OMIT
diff --git a/2015/go-for-java-programmers/pingselect.go b/2015/go-for-java-programmers/pingselect.go
new file mode 100644
index 0000000..b274e41
--- /dev/null
+++ b/2015/go-for-java-programmers/pingselect.go
@@ -0,0 +1,37 @@
+// +build OMIT
+
+package main
+
+import (
+	"fmt"
+	"time"
+)
+
+// STARTMAIN1 OMIT
+type Ball struct{ hits int }
+
+func main() {
+	in, out := make(chan *Ball), make(chan *Ball)
+	go player("ping", in, out)
+	go player("pong", in, out)
+
+	for i := 0; i < 8; {
+		select { // HL
+		case in <- new(Ball): // feed the pipeline // HL
+		case <-out: // drain the pipeline // HL
+			i++ // HL
+		} // HL
+	}
+}
+
+func player(name string, in <-chan *Ball, out chan<- *Ball) {
+	for i := 0; ; i++ {
+		ball := <-in
+		ball.hits++
+		fmt.Println(name, i, "hit", ball.hits)
+		time.Sleep(100 * time.Millisecond)
+		out <- ball
+	}
+}
+
+// STOPMAIN1 OMIT
diff --git a/2015/go-for-java-programmers/player.go b/2015/go-for-java-programmers/player.go
new file mode 100644
index 0000000..e66e567
--- /dev/null
+++ b/2015/go-for-java-programmers/player.go
@@ -0,0 +1,25 @@
+// +build OMIT
+
+package main
+
+import (
+	"fmt"
+	"time"
+)
+
+// STARTMAIN1 OMIT
+type Ball struct{ hits int }
+
+func main() {
+	player("ping", new(Ball))
+}
+
+func player(name string, ball *Ball) {
+	for i := 0; ; i++ {
+		ball.hits++
+		fmt.Println(name, i, "hit", ball.hits)
+		time.Sleep(100 * time.Millisecond)
+	}
+}
+
+// STOPMAIN1 OMIT
diff --git a/2015/go-for-java-programmers/pointer.go b/2015/go-for-java-programmers/pointer.go
new file mode 100644
index 0000000..e273125
--- /dev/null
+++ b/2015/go-for-java-programmers/pointer.go
@@ -0,0 +1,34 @@
+package main
+
+import "fmt"
+
+// START TYPES OMIT
+type Point struct {
+	X, Y int
+}
+
+type Rectangle struct {
+	Min, Max Point
+}
+
+// END TYPES OMIT
+
+func main() {
+	var r0 Rectangle
+
+	r1 := r0 // struct copy
+
+	r1.Min.X, r1.Min.Y = -1, -1
+	r1.Max = Point{X: 2}
+
+	fmt.Printf("r0 is %+v\n", r0)
+	fmt.Printf("r1 is %v\n", r1)
+
+	y := &r1.Max.Y // y is a *int // HL
+	*y = 5         // HL
+	fmt.Println(y, "points to", *y)
+
+	min := &r1.Min // min is a *Point // HL
+	min.X = 7      // HL
+	fmt.Printf("r1 is %v\n", r1)
+}
diff --git a/2015/go-for-java-programmers/safe.go b/2015/go-for-java-programmers/safe.go
new file mode 100644
index 0000000..4186f42
--- /dev/null
+++ b/2015/go-for-java-programmers/safe.go
@@ -0,0 +1,18 @@
+package main
+
+import "fmt"
+
+func newInt(v int) *int {
+	var n = v
+	return &n // HL
+}
+
+func inc(p *int) {
+	*p++ // try removing * // HL
+}
+
+func main() {
+	p := newInt(3)
+	inc(p)
+	fmt.Println(p, "points to", *p)
+}
diff --git a/2015/go-for-java-programmers/spdy.png b/2015/go-for-java-programmers/spdy.png
new file mode 100644
index 0000000..bbc0650
--- /dev/null
+++ b/2015/go-for-java-programmers/spdy.png
Binary files differ
diff --git a/2015/go-for-java-programmers/struct.go b/2015/go-for-java-programmers/struct.go
new file mode 100644
index 0000000..4abbff4
--- /dev/null
+++ b/2015/go-for-java-programmers/struct.go
@@ -0,0 +1,34 @@
+package main
+
+import "fmt"
+
+// START SLICES OMIT
+var arr [8]Rectangle
+
+var (
+	rects  = arr[2:4]
+	rects2 = []Rectangle{rects[0], rects[1]}
+)
+
+// START TYPES OMIT
+type Point struct {
+	X, Y int
+}
+
+type Rectangle struct {
+	Min, Max Point
+}
+
+// END TYPES OMIT
+
+func main() {
+	var r0 Rectangle
+
+	r1 := r0 // struct copy
+
+	r1.Min.X, r1.Min.Y = -1, -1
+	r1.Max = Point{X: 2}
+
+	fmt.Printf("r0 is %+v\n", r0)
+	fmt.Printf("r1 is %v\n", r1)
+}