[
  {
    "path": "CNAME",
    "content": "gopl.io\n"
  },
  {
    "path": "README.md",
    "content": "# The Go Programming Language\n\nThis repository provides the downloadable example programs\nfor the book, \"The Go Programming Language\"; see http://www.gopl.io.\n\nThese example programs are licensed under a <a rel=\"license\" href=\"http://creativecommons.org/licenses/by-nc-sa/4.0/\">Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License</a>.<br/>\n<a rel=\"license\" href=\"http://creativecommons.org/licenses/by-nc-sa/4.0/\"><img alt=\"Creative Commons License\" style=\"border-width:0\" src=\"https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png\"/></a>\n\nYou can download, build, and run the programs with the following commands:\n\n\t$ export GOPATH=$HOME/gobook            # choose workspace directory\n\t$ go get gopl.io/ch1/helloworld         # fetch, build, install\n\t$ $GOPATH/bin/helloworld                # run\n\tHello, 世界\n\nMany of the programs contain comments of the form `//!+` and `//!-`.\nThese comments bracket the parts of the programs that are excerpted in the\nbook; you can safely ignore them.  In a few cases, programs\nhave been reformatted in an unnatural way so that they can be presented\nin stages in the book.\n\n"
  },
  {
    "path": "ch1/dup1/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 8.\n//!+\n\n// Dup1 prints the text of each line that appears more than\n// once in the standard input, preceded by its count.\npackage main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"os\"\n)\n\nfunc main() {\n\tcounts := make(map[string]int)\n\tinput := bufio.NewScanner(os.Stdin)\n\tfor input.Scan() {\n\t\tcounts[input.Text()]++\n\t}\n\t// NOTE: ignoring potential errors from input.Err()\n\tfor line, n := range counts {\n\t\tif n > 1 {\n\t\t\tfmt.Printf(\"%d\\t%s\\n\", n, line)\n\t\t}\n\t}\n}\n\n//!-\n"
  },
  {
    "path": "ch1/dup2/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 10.\n//!+\n\n// Dup2 prints the count and text of lines that appear more than once\n// in the input.  It reads from stdin or from a list of named files.\npackage main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"os\"\n)\n\nfunc main() {\n\tcounts := make(map[string]int)\n\tfiles := os.Args[1:]\n\tif len(files) == 0 {\n\t\tcountLines(os.Stdin, counts)\n\t} else {\n\t\tfor _, arg := range files {\n\t\t\tf, err := os.Open(arg)\n\t\t\tif err != nil {\n\t\t\t\tfmt.Fprintf(os.Stderr, \"dup2: %v\\n\", err)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tcountLines(f, counts)\n\t\t\tf.Close()\n\t\t}\n\t}\n\tfor line, n := range counts {\n\t\tif n > 1 {\n\t\t\tfmt.Printf(\"%d\\t%s\\n\", n, line)\n\t\t}\n\t}\n}\n\nfunc countLines(f *os.File, counts map[string]int) {\n\tinput := bufio.NewScanner(f)\n\tfor input.Scan() {\n\t\tcounts[input.Text()]++\n\t}\n\t// NOTE: ignoring potential errors from input.Err()\n}\n\n//!-\n"
  },
  {
    "path": "ch1/dup3/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 12.\n\n//!+\n\n// Dup3 prints the count and text of lines that\n// appear more than once in the named input files.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\tcounts := make(map[string]int)\n\tfor _, filename := range os.Args[1:] {\n\t\tdata, err := ioutil.ReadFile(filename)\n\t\tif err != nil {\n\t\t\tfmt.Fprintf(os.Stderr, \"dup3: %v\\n\", err)\n\t\t\tcontinue\n\t\t}\n\t\tfor _, line := range strings.Split(string(data), \"\\n\") {\n\t\t\tcounts[line]++\n\t\t}\n\t}\n\tfor line, n := range counts {\n\t\tif n > 1 {\n\t\t\tfmt.Printf(\"%d\\t%s\\n\", n, line)\n\t\t}\n\t}\n}\n\n//!-\n"
  },
  {
    "path": "ch1/echo1/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 4.\n//!+\n\n// Echo1 prints its command-line arguments.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n)\n\nfunc main() {\n\tvar s, sep string\n\tfor i := 1; i < len(os.Args); i++ {\n\t\ts += sep + os.Args[i]\n\t\tsep = \" \"\n\t}\n\tfmt.Println(s)\n}\n\n//!-\n"
  },
  {
    "path": "ch1/echo2/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 6.\n//!+\n\n// Echo2 prints its command-line arguments.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n)\n\nfunc main() {\n\ts, sep := \"\", \"\"\n\tfor _, arg := range os.Args[1:] {\n\t\ts += sep + arg\n\t\tsep = \" \"\n\t}\n\tfmt.Println(s)\n}\n\n//!-\n"
  },
  {
    "path": "ch1/echo3/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 8.\n\n// Echo3 prints its command-line arguments.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n)\n\n//!+\nfunc main() {\n\tfmt.Println(strings.Join(os.Args[1:], \" \"))\n}\n\n//!-\n"
  },
  {
    "path": "ch1/fetch/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 16.\n//!+\n\n// Fetch prints the content found at each specified URL.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\tfor _, url := range os.Args[1:] {\n\t\tresp, err := http.Get(url)\n\t\tif err != nil {\n\t\t\tfmt.Fprintf(os.Stderr, \"fetch: %v\\n\", err)\n\t\t\tos.Exit(1)\n\t\t}\n\t\tb, err := ioutil.ReadAll(resp.Body)\n\t\tresp.Body.Close()\n\t\tif err != nil {\n\t\t\tfmt.Fprintf(os.Stderr, \"fetch: reading %s: %v\\n\", url, err)\n\t\t\tos.Exit(1)\n\t\t}\n\t\tfmt.Printf(\"%s\", b)\n\t}\n}\n\n//!-\n"
  },
  {
    "path": "ch1/fetchall/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 17.\n//!+\n\n// Fetchall fetches URLs in parallel and reports their times and sizes.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"os\"\n\t\"time\"\n)\n\nfunc main() {\n\tstart := time.Now()\n\tch := make(chan string)\n\tfor _, url := range os.Args[1:] {\n\t\tgo fetch(url, ch) // start a goroutine\n\t}\n\tfor range os.Args[1:] {\n\t\tfmt.Println(<-ch) // receive from channel ch\n\t}\n\tfmt.Printf(\"%.2fs elapsed\\n\", time.Since(start).Seconds())\n}\n\nfunc fetch(url string, ch chan<- string) {\n\tstart := time.Now()\n\tresp, err := http.Get(url)\n\tif err != nil {\n\t\tch <- fmt.Sprint(err) // send to channel ch\n\t\treturn\n\t}\n\n\tnbytes, err := io.Copy(ioutil.Discard, resp.Body)\n\tresp.Body.Close() // don't leak resources\n\tif err != nil {\n\t\tch <- fmt.Sprintf(\"while reading %s: %v\", url, err)\n\t\treturn\n\t}\n\tsecs := time.Since(start).Seconds()\n\tch <- fmt.Sprintf(\"%.2fs  %7d  %s\", secs, nbytes, url)\n}\n\n//!-\n"
  },
  {
    "path": "ch1/helloworld/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 1.\n\n// Helloworld is our first Go program.\n//!+\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Println(\"Hello, 世界\")\n}\n\n//!-\n"
  },
  {
    "path": "ch1/lissajous/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// Run with \"web\" command-line argument for web server.\n// See page 13.\n//!+main\n\n// Lissajous generates GIF animations of random Lissajous figures.\npackage main\n\nimport (\n\t\"image\"\n\t\"image/color\"\n\t\"image/gif\"\n\t\"io\"\n\t\"math\"\n\t\"math/rand\"\n\t\"os\"\n)\n\n//!-main\n// Packages not needed by version in book.\nimport (\n\t\"log\"\n\t\"net/http\"\n\t\"time\"\n)\n\n//!+main\n\nvar palette = []color.Color{color.White, color.Black}\n\nconst (\n\twhiteIndex = 0 // first color in palette\n\tblackIndex = 1 // next color in palette\n)\n\nfunc main() {\n\t//!-main\n\t// The sequence of images is deterministic unless we seed\n\t// the pseudo-random number generator using the current time.\n\t// Thanks to Randall McPherson for pointing out the omission.\n\trand.Seed(time.Now().UTC().UnixNano())\n\n\tif len(os.Args) > 1 && os.Args[1] == \"web\" {\n\t\t//!+http\n\t\thandler := func(w http.ResponseWriter, r *http.Request) {\n\t\t\tlissajous(w)\n\t\t}\n\t\thttp.HandleFunc(\"/\", handler)\n\t\t//!-http\n\t\tlog.Fatal(http.ListenAndServe(\"localhost:8000\", nil))\n\t\treturn\n\t}\n\t//!+main\n\tlissajous(os.Stdout)\n}\n\nfunc lissajous(out io.Writer) {\n\tconst (\n\t\tcycles  = 5     // number of complete x oscillator revolutions\n\t\tres     = 0.001 // angular resolution\n\t\tsize    = 100   // image canvas covers [-size..+size]\n\t\tnframes = 64    // number of animation frames\n\t\tdelay   = 8     // delay between frames in 10ms units\n\t)\n\tfreq := rand.Float64() * 3.0 // relative frequency of y oscillator\n\tanim := gif.GIF{LoopCount: nframes}\n\tphase := 0.0 // phase difference\n\tfor i := 0; i < nframes; i++ {\n\t\trect := image.Rect(0, 0, 2*size+1, 2*size+1)\n\t\timg := image.NewPaletted(rect, palette)\n\t\tfor t := 0.0; t < cycles*2*math.Pi; t += res {\n\t\t\tx := math.Sin(t)\n\t\t\ty := math.Sin(t*freq + phase)\n\t\t\timg.SetColorIndex(size+int(x*size+0.5), size+int(y*size+0.5),\n\t\t\t\tblackIndex)\n\t\t}\n\t\tphase += 0.1\n\t\tanim.Delay = append(anim.Delay, delay)\n\t\tanim.Image = append(anim.Image, img)\n\t}\n\tgif.EncodeAll(out, &anim) // NOTE: ignoring encoding errors\n}\n\n//!-main\n"
  },
  {
    "path": "ch1/server1/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 19.\n//!+\n\n// Server1 is a minimal \"echo\" server.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n)\n\nfunc main() {\n\thttp.HandleFunc(\"/\", handler) // each request calls handler\n\tlog.Fatal(http.ListenAndServe(\"localhost:8000\", nil))\n}\n\n// handler echoes the Path component of the requested URL.\nfunc handler(w http.ResponseWriter, r *http.Request) {\n\tfmt.Fprintf(w, \"URL.Path = %q\\n\", r.URL.Path)\n}\n\n//!-\n"
  },
  {
    "path": "ch1/server2/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 20.\n//!+\n\n// Server2 is a minimal \"echo\" and counter server.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\t\"sync\"\n)\n\nvar mu sync.Mutex\nvar count int\n\nfunc main() {\n\thttp.HandleFunc(\"/\", handler)\n\thttp.HandleFunc(\"/count\", counter)\n\tlog.Fatal(http.ListenAndServe(\"localhost:8000\", nil))\n}\n\n// handler echoes the Path component of the requested URL.\nfunc handler(w http.ResponseWriter, r *http.Request) {\n\tmu.Lock()\n\tcount++\n\tmu.Unlock()\n\tfmt.Fprintf(w, \"URL.Path = %q\\n\", r.URL.Path)\n}\n\n// counter echoes the number of calls so far.\nfunc counter(w http.ResponseWriter, r *http.Request) {\n\tmu.Lock()\n\tfmt.Fprintf(w, \"Count %d\\n\", count)\n\tmu.Unlock()\n}\n\n//!-\n"
  },
  {
    "path": "ch1/server3/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 21.\n\n// Server3 is an \"echo\" server that displays request parameters.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n)\n\nfunc main() {\n\thttp.HandleFunc(\"/\", handler)\n\tlog.Fatal(http.ListenAndServe(\"localhost:8000\", nil))\n}\n\n//!+handler\n// handler echoes the HTTP request.\nfunc handler(w http.ResponseWriter, r *http.Request) {\n\tfmt.Fprintf(w, \"%s %s %s\\n\", r.Method, r.URL, r.Proto)\n\tfor k, v := range r.Header {\n\t\tfmt.Fprintf(w, \"Header[%q] = %q\\n\", k, v)\n\t}\n\tfmt.Fprintf(w, \"Host = %q\\n\", r.Host)\n\tfmt.Fprintf(w, \"RemoteAddr = %q\\n\", r.RemoteAddr)\n\tif err := r.ParseForm(); err != nil {\n\t\tlog.Print(err)\n\t}\n\tfor k, v := range r.Form {\n\t\tfmt.Fprintf(w, \"Form[%q] = %q\\n\", k, v)\n\t}\n}\n\n//!-handler\n"
  },
  {
    "path": "ch10/cross/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 295.\n\n// The cross command prints the values of GOOS and GOARCH for this target.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"runtime\"\n)\n\n//!+\nfunc main() {\n\tfmt.Println(runtime.GOOS, runtime.GOARCH)\n}\n\n//!-\n"
  },
  {
    "path": "ch10/jpeg/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 287.\n\n//!+main\n\n// The jpeg command reads a PNG image from the standard input\n// and writes it as a JPEG image to the standard output.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"image\"\n\t\"image/jpeg\"\n\t_ \"image/png\" // register PNG decoder\n\t\"io\"\n\t\"os\"\n)\n\nfunc main() {\n\tif err := toJPEG(os.Stdin, os.Stdout); err != nil {\n\t\tfmt.Fprintf(os.Stderr, \"jpeg: %v\\n\", err)\n\t\tos.Exit(1)\n\t}\n}\n\nfunc toJPEG(in io.Reader, out io.Writer) error {\n\timg, kind, err := image.Decode(in)\n\tif err != nil {\n\t\treturn err\n\t}\n\tfmt.Fprintln(os.Stderr, \"Input format =\", kind)\n\treturn jpeg.Encode(out, img, &jpeg.Options{Quality: 95})\n}\n\n//!-main\n\n/*\n//!+with\n$ go build gopl.io/ch3/mandelbrot\n$ go build gopl.io/ch10/jpeg\n$ ./mandelbrot | ./jpeg >mandelbrot.jpg\nInput format = png\n//!-with\n\n//!+without\n$ go build gopl.io/ch10/jpeg\n$ ./mandelbrot | ./jpeg >mandelbrot.jpg\njpeg: image: unknown format\n//!-without\n*/\n"
  },
  {
    "path": "ch11/echo/echo.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 308.\n//!+\n\n// Echo prints its command-line arguments.\npackage main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"strings\"\n)\n\nvar (\n\tn = flag.Bool(\"n\", false, \"omit trailing newline\")\n\ts = flag.String(\"s\", \" \", \"separator\")\n)\n\nvar out io.Writer = os.Stdout // modified during testing\n\nfunc main() {\n\tflag.Parse()\n\tif err := echo(!*n, *s, flag.Args()); err != nil {\n\t\tfmt.Fprintf(os.Stderr, \"echo: %v\\n\", err)\n\t\tos.Exit(1)\n\t}\n}\n\nfunc echo(newline bool, sep string, args []string) error {\n\tfmt.Fprint(out, strings.Join(args, sep))\n\tif newline {\n\t\tfmt.Fprintln(out)\n\t}\n\treturn nil\n}\n\n//!-\n"
  },
  {
    "path": "ch11/echo/echo_test.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// Test of echo command.  Run with: go test gopl.io/ch11/echo\n\n//!+\npackage main\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"testing\"\n)\n\nfunc TestEcho(t *testing.T) {\n\tvar tests = []struct {\n\t\tnewline bool\n\t\tsep     string\n\t\targs    []string\n\t\twant    string\n\t}{\n\t\t{true, \"\", []string{}, \"\\n\"},\n\t\t{false, \"\", []string{}, \"\"},\n\t\t{true, \"\\t\", []string{\"one\", \"two\", \"three\"}, \"one\\ttwo\\tthree\\n\"},\n\t\t{true, \",\", []string{\"a\", \"b\", \"c\"}, \"a,b,c\\n\"},\n\t\t{false, \":\", []string{\"1\", \"2\", \"3\"}, \"1:2:3\"},\n\t}\n\n\tfor _, test := range tests {\n\t\tdescr := fmt.Sprintf(\"echo(%v, %q, %q)\",\n\t\t\ttest.newline, test.sep, test.args)\n\n\t\tout = new(bytes.Buffer) // captured output\n\t\tif err := echo(test.newline, test.sep, test.args); err != nil {\n\t\t\tt.Errorf(\"%s failed: %v\", descr, err)\n\t\t\tcontinue\n\t\t}\n\t\tgot := out.(*bytes.Buffer).String()\n\t\tif got != test.want {\n\t\t\tt.Errorf(\"%s = %q, want %q\", descr, got, test.want)\n\t\t}\n\t}\n}\n\n//!-\n"
  },
  {
    "path": "ch11/storage1/storage.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 311.\n\n// Package storage is part of a hypothetical cloud storage server.\n//!+main\npackage storage\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/smtp\"\n)\n\nvar usage = make(map[string]int64)\n\nfunc bytesInUse(username string) int64 { return usage[username] }\n\n// Email sender configuration.\n// NOTE: never put passwords in source code!\nconst sender = \"notifications@example.com\"\nconst password = \"correcthorsebatterystaple\"\nconst hostname = \"smtp.example.com\"\n\nconst template = `Warning: you are using %d bytes of storage,\n%d%% of your quota.`\n\nfunc CheckQuota(username string) {\n\tused := bytesInUse(username)\n\tconst quota = 1000000000 // 1GB\n\tpercent := 100 * used / quota\n\tif percent < 90 {\n\t\treturn // OK\n\t}\n\tmsg := fmt.Sprintf(template, used, percent)\n\tauth := smtp.PlainAuth(\"\", sender, password, hostname)\n\terr := smtp.SendMail(hostname+\":587\", auth, sender,\n\t\t[]string{username}, []byte(msg))\n\tif err != nil {\n\t\tlog.Printf(\"smtp.SendMail(%s) failed: %s\", username, err)\n\t}\n}\n\n//!-main\n"
  },
  {
    "path": "ch11/storage2/quota_test.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n//!+test\npackage storage\n\nimport (\n\t\"strings\"\n\t\"testing\"\n)\n\nfunc TestCheckQuotaNotifiesUser(t *testing.T) {\n\tvar notifiedUser, notifiedMsg string\n\tnotifyUser = func(user, msg string) {\n\t\tnotifiedUser, notifiedMsg = user, msg\n\t}\n\n\tconst user = \"joe@example.org\"\n\tusage[user] = 980000000 // simulate a 980MB-used condition\n\n\tCheckQuota(user)\n\tif notifiedUser == \"\" && notifiedMsg == \"\" {\n\t\tt.Fatalf(\"notifyUser not called\")\n\t}\n\tif notifiedUser != user {\n\t\tt.Errorf(\"wrong user (%s) notified, want %s\",\n\t\t\tnotifiedUser, user)\n\t}\n\tconst wantSubstring = \"98% of your quota\"\n\tif !strings.Contains(notifiedMsg, wantSubstring) {\n\t\tt.Errorf(\"unexpected notification message <<%s>>, \"+\n\t\t\t\"want substring %q\", notifiedMsg, wantSubstring)\n\t}\n}\n\n//!-test\n\n/*\n//!+defer\nfunc TestCheckQuotaNotifiesUser(t *testing.T) {\n\t// Save and restore original notifyUser.\n\tsaved := notifyUser\n\tdefer func() { notifyUser = saved }()\n\n\t// Install the test's fake notifyUser.\n\tvar notifiedUser, notifiedMsg string\n\tnotifyUser = func(user, msg string) {\n\t\tnotifiedUser, notifiedMsg = user, msg\n\t}\n\t// ...rest of test...\n}\n//!-defer\n*/\n"
  },
  {
    "path": "ch11/storage2/storage.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 312.\n\n// Package storage is part of a hypothetical cloud storage server.\npackage storage\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/smtp\"\n)\n\nvar usage = make(map[string]int64)\n\nfunc bytesInUse(username string) int64 { return usage[username] }\n\n// E-mail sender configuration.\n// NOTE: never put passwords in source code!\nconst sender = \"notifications@example.com\"\nconst password = \"correcthorsebatterystaple\"\nconst hostname = \"smtp.example.com\"\n\nconst template = `Warning: you are using %d bytes of storage,\n%d%% of your quota.`\n\n//!+factored\nvar notifyUser = func(username, msg string) {\n\tauth := smtp.PlainAuth(\"\", sender, password, hostname)\n\terr := smtp.SendMail(hostname+\":587\", auth, sender,\n\t\t[]string{username}, []byte(msg))\n\tif err != nil {\n\t\tlog.Printf(\"smtp.SendMail(%s) failed: %s\", username, err)\n\t}\n}\n\nfunc CheckQuota(username string) {\n\tused := bytesInUse(username)\n\tconst quota = 1000000000 // 1GB\n\tpercent := 100 * used / quota\n\tif percent < 90 {\n\t\treturn // OK\n\t}\n\tmsg := fmt.Sprintf(template, used, percent)\n\tnotifyUser(username, msg)\n}\n\n//!-factored\n"
  },
  {
    "path": "ch11/word1/word.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 303.\n//!+\n\n// Package word provides utilities for word games.\npackage word\n\n// IsPalindrome reports whether s reads the same forward and backward.\n// (Our first attempt.)\nfunc IsPalindrome(s string) bool {\n\tfor i := range s {\n\t\tif s[i] != s[len(s)-1-i] {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n//!-\n"
  },
  {
    "path": "ch11/word1/word_test.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n//!+test\npackage word\n\nimport \"testing\"\n\nfunc TestPalindrome(t *testing.T) {\n\tif !IsPalindrome(\"detartrated\") {\n\t\tt.Error(`IsPalindrome(\"detartrated\") = false`)\n\t}\n\tif !IsPalindrome(\"kayak\") {\n\t\tt.Error(`IsPalindrome(\"kayak\") = false`)\n\t}\n}\n\nfunc TestNonPalindrome(t *testing.T) {\n\tif IsPalindrome(\"palindrome\") {\n\t\tt.Error(`IsPalindrome(\"palindrome\") = true`)\n\t}\n}\n\n//!-test\n\n// The tests below are expected to fail.\n// See package gopl.io/ch11/word2 for the fix.\n\n//!+more\nfunc TestFrenchPalindrome(t *testing.T) {\n\tif !IsPalindrome(\"été\") {\n\t\tt.Error(`IsPalindrome(\"été\") = false`)\n\t}\n}\n\nfunc TestCanalPalindrome(t *testing.T) {\n\tinput := \"A man, a plan, a canal: Panama\"\n\tif !IsPalindrome(input) {\n\t\tt.Errorf(`IsPalindrome(%q) = false`, input)\n\t}\n}\n\n//!-more\n"
  },
  {
    "path": "ch11/word2/word.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 305.\n//!+\n\n// Package word provides utilities for word games.\npackage word\n\nimport \"unicode\"\n\n// IsPalindrome reports whether s reads the same forward and backward.\n// Letter case is ignored, as are non-letters.\nfunc IsPalindrome(s string) bool {\n\tvar letters []rune\n\tfor _, r := range s {\n\t\tif unicode.IsLetter(r) {\n\t\t\tletters = append(letters, unicode.ToLower(r))\n\t\t}\n\t}\n\tfor i := range letters {\n\t\tif letters[i] != letters[len(letters)-1-i] {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n//!-\n"
  },
  {
    "path": "ch11/word2/word_test.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\npackage word\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"time\"\n)\n\n//!+bench\n\nimport \"testing\"\n\n//!-bench\n\n//!+test\nfunc TestIsPalindrome(t *testing.T) {\n\tvar tests = []struct {\n\t\tinput string\n\t\twant  bool\n\t}{\n\t\t{\"\", true},\n\t\t{\"a\", true},\n\t\t{\"aa\", true},\n\t\t{\"ab\", false},\n\t\t{\"kayak\", true},\n\t\t{\"detartrated\", true},\n\t\t{\"A man, a plan, a canal: Panama\", true},\n\t\t{\"Evil I did dwell; lewd did I live.\", true},\n\t\t{\"Able was I ere I saw Elba\", true},\n\t\t{\"été\", true},\n\t\t{\"Et se resservir, ivresse reste.\", true},\n\t\t{\"palindrome\", false}, // non-palindrome\n\t\t{\"desserts\", false},   // semi-palindrome\n\t}\n\tfor _, test := range tests {\n\t\tif got := IsPalindrome(test.input); got != test.want {\n\t\t\tt.Errorf(\"IsPalindrome(%q) = %v\", test.input, got)\n\t\t}\n\t}\n}\n\n//!-test\n\n//!+bench\nfunc BenchmarkIsPalindrome(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tIsPalindrome(\"A man, a plan, a canal: Panama\")\n\t}\n}\n\n//!-bench\n\n//!+example\n\nfunc ExampleIsPalindrome() {\n\tfmt.Println(IsPalindrome(\"A man, a plan, a canal: Panama\"))\n\tfmt.Println(IsPalindrome(\"palindrome\"))\n\t// Output:\n\t// true\n\t// false\n}\n\n//!-example\n\n/*\n//!+random\nimport \"math/rand\"\n\n//!-random\n*/\n\n//!+random\n// randomPalindrome returns a palindrome whose length and contents\n// are derived from the pseudo-random number generator rng.\nfunc randomPalindrome(rng *rand.Rand) string {\n\tn := rng.Intn(25) // random length up to 24\n\trunes := make([]rune, n)\n\tfor i := 0; i < (n+1)/2; i++ {\n\t\tr := rune(rng.Intn(0x1000)) // random rune up to '\\u0999'\n\t\trunes[i] = r\n\t\trunes[n-1-i] = r\n\t}\n\treturn string(runes)\n}\n\nfunc TestRandomPalindromes(t *testing.T) {\n\t// Initialize a pseudo-random number generator.\n\tseed := time.Now().UTC().UnixNano()\n\tt.Logf(\"Random seed: %d\", seed)\n\trng := rand.New(rand.NewSource(seed))\n\n\tfor i := 0; i < 1000; i++ {\n\t\tp := randomPalindrome(rng)\n\t\tif !IsPalindrome(p) {\n\t\t\tt.Errorf(\"IsPalindrome(%q) = false\", p)\n\t\t}\n\t}\n}\n\n//!-random\n\n/*\n// Answer for Exercicse 11.1: Modify randomPalindrome to exercise\n// IsPalindrome's handling of punctuation and spaces.\n\n// WARNING: the conversion r -> upper -> lower doesn't preserve\n// the value of r in some cases, e.g., µ Μ, ſ S, ı I\n\n// randomPalindrome returns a palindrome whose length and contents\n// are derived from the pseudo-random number generator rng.\nfunc randomNoisyPalindrome(rng *rand.Rand) string {\n\tn := rng.Intn(25) // random length up to 24\n\trunes := make([]rune, n)\n\tfor i := 0; i < (n+1)/2; i++ {\n\t\tr := rune(rng.Intn(0x200)) // random rune up to \\u99\n\t\trunes[i] = r\n\t\tr1 := r\n\t\tif unicode.IsLetter(r) && unicode.IsLower(r) {\n\t\t\tr = unicode.ToUpper(r)\n\t\t\tif unicode.ToLower(r) != r1 {\n\t\t\t\tfmt.Printf(\"cap? %c %c\\n\", r1, r)\n\t\t\t}\n\t\t}\n\t\trunes[n-1-i] = r\n\t}\n\treturn \"?\" + string(runes) + \"!\"\n}\n\nfunc TestRandomNoisyPalindromes(t *testing.T) {\n\t// Initialize a pseudo-random number generator.\n\tseed := time.Now().UTC().UnixNano()\n\tt.Logf(\"Random seed: %d\", seed)\n\trng := rand.New(rand.NewSource(seed))\n\n\tn := 0\n\tfor i := 0; i < 1000; i++ {\n\t\tp := randomNoisyPalindrome(rng)\n\t\tif !IsPalindrome(p) {\n\t\t\tt.Errorf(\"IsNoisyPalindrome(%q) = false\", p)\n\t\t\tn++\n\t\t}\n\t}\n\tfmt.Fprintf(os.Stderr, \"fail = %d\\n\", n)\n}\n*/\n"
  },
  {
    "path": "ch12/display/display.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 333.\n\n// Package display provides a means to display structured data.\npackage display\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"strconv\"\n)\n\n//!+Display\n\nfunc Display(name string, x interface{}) {\n\tfmt.Printf(\"Display %s (%T):\\n\", name, x)\n\tdisplay(name, reflect.ValueOf(x))\n}\n\n//!-Display\n\n// formatAtom formats a value without inspecting its internal structure.\n// It is a copy of the the function in gopl.io/ch11/format.\nfunc formatAtom(v reflect.Value) string {\n\tswitch v.Kind() {\n\tcase reflect.Invalid:\n\t\treturn \"invalid\"\n\tcase reflect.Int, reflect.Int8, reflect.Int16,\n\t\treflect.Int32, reflect.Int64:\n\t\treturn strconv.FormatInt(v.Int(), 10)\n\tcase reflect.Uint, reflect.Uint8, reflect.Uint16,\n\t\treflect.Uint32, reflect.Uint64, reflect.Uintptr:\n\t\treturn strconv.FormatUint(v.Uint(), 10)\n\t// ...floating-point and complex cases omitted for brevity...\n\tcase reflect.Bool:\n\t\tif v.Bool() {\n\t\t\treturn \"true\"\n\t\t}\n\t\treturn \"false\"\n\tcase reflect.String:\n\t\treturn strconv.Quote(v.String())\n\tcase reflect.Chan, reflect.Func, reflect.Ptr,\n\t\treflect.Slice, reflect.Map:\n\t\treturn v.Type().String() + \" 0x\" +\n\t\t\tstrconv.FormatUint(uint64(v.Pointer()), 16)\n\tdefault: // reflect.Array, reflect.Struct, reflect.Interface\n\t\treturn v.Type().String() + \" value\"\n\t}\n}\n\n//!+display\nfunc display(path string, v reflect.Value) {\n\tswitch v.Kind() {\n\tcase reflect.Invalid:\n\t\tfmt.Printf(\"%s = invalid\\n\", path)\n\tcase reflect.Slice, reflect.Array:\n\t\tfor i := 0; i < v.Len(); i++ {\n\t\t\tdisplay(fmt.Sprintf(\"%s[%d]\", path, i), v.Index(i))\n\t\t}\n\tcase reflect.Struct:\n\t\tfor i := 0; i < v.NumField(); i++ {\n\t\t\tfieldPath := fmt.Sprintf(\"%s.%s\", path, v.Type().Field(i).Name)\n\t\t\tdisplay(fieldPath, v.Field(i))\n\t\t}\n\tcase reflect.Map:\n\t\tfor _, key := range v.MapKeys() {\n\t\t\tdisplay(fmt.Sprintf(\"%s[%s]\", path,\n\t\t\t\tformatAtom(key)), v.MapIndex(key))\n\t\t}\n\tcase reflect.Ptr:\n\t\tif v.IsNil() {\n\t\t\tfmt.Printf(\"%s = nil\\n\", path)\n\t\t} else {\n\t\t\tdisplay(fmt.Sprintf(\"(*%s)\", path), v.Elem())\n\t\t}\n\tcase reflect.Interface:\n\t\tif v.IsNil() {\n\t\t\tfmt.Printf(\"%s = nil\\n\", path)\n\t\t} else {\n\t\t\tfmt.Printf(\"%s.type = %s\\n\", path, v.Elem().Type())\n\t\t\tdisplay(path+\".value\", v.Elem())\n\t\t}\n\tdefault: // basic types, channels, funcs\n\t\tfmt.Printf(\"%s = %s\\n\", path, formatAtom(v))\n\t}\n}\n\n//!-display\n"
  },
  {
    "path": "ch12/display/display_test.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\npackage display\n\nimport (\n\t\"io\"\n\t\"net\"\n\t\"os\"\n\t\"reflect\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"gopl.io/ch7/eval\"\n)\n\n// NOTE: we can't use !+..!- comments to excerpt these tests\n// into the book because it defeats the Example mechanism,\n// which requires the // Output comment to be at the end\n// of the function.\n\nfunc Example_expr() {\n\te, _ := eval.Parse(\"sqrt(A / pi)\")\n\tDisplay(\"e\", e)\n\t// Output:\n\t// Display e (eval.call):\n\t// e.fn = \"sqrt\"\n\t// e.args[0].type = eval.binary\n\t// e.args[0].value.op = 47\n\t// e.args[0].value.x.type = eval.Var\n\t// e.args[0].value.x.value = \"A\"\n\t// e.args[0].value.y.type = eval.Var\n\t// e.args[0].value.y.value = \"pi\"\n}\n\nfunc Example_slice() {\n\tDisplay(\"slice\", []*int{new(int), nil})\n\t// Output:\n\t// Display slice ([]*int):\n\t// (*slice[0]) = 0\n\t// slice[1] = nil\n}\n\nfunc Example_nilInterface() {\n\tvar w io.Writer\n\tDisplay(\"w\", w)\n\t// Output:\n\t// Display w (<nil>):\n\t// w = invalid\n}\n\nfunc Example_ptrToInterface() {\n\tvar w io.Writer\n\tDisplay(\"&w\", &w)\n\t// Output:\n\t// Display &w (*io.Writer):\n\t// (*&w) = nil\n}\n\nfunc Example_struct() {\n\tDisplay(\"x\", struct{ x interface{} }{3})\n\t// Output:\n\t// Display x (struct { x interface {} }):\n\t// x.x.type = int\n\t// x.x.value = 3\n}\n\nfunc Example_interface() {\n\tvar i interface{} = 3\n\tDisplay(\"i\", i)\n\t// Output:\n\t// Display i (int):\n\t// i = 3\n}\n\nfunc Example_ptrToInterface2() {\n\tvar i interface{} = 3\n\tDisplay(\"&i\", &i)\n\t// Output:\n\t// Display &i (*interface {}):\n\t// (*&i).type = int\n\t// (*&i).value = 3\n}\n\nfunc Example_array() {\n\tDisplay(\"x\", [1]interface{}{3})\n\t// Output:\n\t// Display x ([1]interface {}):\n\t// x[0].type = int\n\t// x[0].value = 3\n}\n\nfunc Example_movie() {\n\t//!+movie\n\ttype Movie struct {\n\t\tTitle, Subtitle string\n\t\tYear            int\n\t\tColor           bool\n\t\tActor           map[string]string\n\t\tOscars          []string\n\t\tSequel          *string\n\t}\n\t//!-movie\n\t//!+strangelove\n\tstrangelove := Movie{\n\t\tTitle:    \"Dr. Strangelove\",\n\t\tSubtitle: \"How I Learned to Stop Worrying and Love the Bomb\",\n\t\tYear:     1964,\n\t\tColor:    false,\n\t\tActor: map[string]string{\n\t\t\t\"Dr. Strangelove\":            \"Peter Sellers\",\n\t\t\t\"Grp. Capt. Lionel Mandrake\": \"Peter Sellers\",\n\t\t\t\"Pres. Merkin Muffley\":       \"Peter Sellers\",\n\t\t\t\"Gen. Buck Turgidson\":        \"George C. Scott\",\n\t\t\t\"Brig. Gen. Jack D. Ripper\":  \"Sterling Hayden\",\n\t\t\t`Maj. T.J. \"King\" Kong`:      \"Slim Pickens\",\n\t\t},\n\n\t\tOscars: []string{\n\t\t\t\"Best Actor (Nomin.)\",\n\t\t\t\"Best Adapted Screenplay (Nomin.)\",\n\t\t\t\"Best Director (Nomin.)\",\n\t\t\t\"Best Picture (Nomin.)\",\n\t\t},\n\t}\n\t//!-strangelove\n\tDisplay(\"strangelove\", strangelove)\n\n\t// We don't use an Output: comment since displaying\n\t// a map is nondeterministic.\n\t/*\n\t\t//!+output\n\t\tDisplay strangelove (display.Movie):\n\t\tstrangelove.Title = \"Dr. Strangelove\"\n\t\tstrangelove.Subtitle = \"How I Learned to Stop Worrying and Love the Bomb\"\n\t\tstrangelove.Year = 1964\n\t\tstrangelove.Color = false\n\t\tstrangelove.Actor[\"Gen. Buck Turgidson\"] = \"George C. Scott\"\n\t\tstrangelove.Actor[\"Brig. Gen. Jack D. Ripper\"] = \"Sterling Hayden\"\n\t\tstrangelove.Actor[\"Maj. T.J. \\\"King\\\" Kong\"] = \"Slim Pickens\"\n\t\tstrangelove.Actor[\"Dr. Strangelove\"] = \"Peter Sellers\"\n\t\tstrangelove.Actor[\"Grp. Capt. Lionel Mandrake\"] = \"Peter Sellers\"\n\t\tstrangelove.Actor[\"Pres. Merkin Muffley\"] = \"Peter Sellers\"\n\t\tstrangelove.Oscars[0] = \"Best Actor (Nomin.)\"\n\t\tstrangelove.Oscars[1] = \"Best Adapted Screenplay (Nomin.)\"\n\t\tstrangelove.Oscars[2] = \"Best Director (Nomin.)\"\n\t\tstrangelove.Oscars[3] = \"Best Picture (Nomin.)\"\n\t\tstrangelove.Sequel = nil\n\t\t//!-output\n\t*/\n}\n\n// This test ensures that the program terminates without crashing.\nfunc Test(t *testing.T) {\n\t// Some other values (YMMV)\n\tDisplay(\"os.Stderr\", os.Stderr)\n\t// Output:\n\t// Display os.Stderr (*os.File):\n\t// (*(*os.Stderr).file).fd = 2\n\t// (*(*os.Stderr).file).name = \"/dev/stderr\"\n\t// (*(*os.Stderr).file).nepipe = 0\n\n\tvar w io.Writer = os.Stderr\n\tDisplay(\"&w\", &w)\n\t// Output:\n\t// Display &w (*io.Writer):\n\t// (*&w).type = *os.File\n\t// (*(*(*&w).value).file).fd = 2\n\t// (*(*(*&w).value).file).name = \"/dev/stderr\"\n\t// (*(*(*&w).value).file).nepipe = 0\n\n\tvar locker sync.Locker = new(sync.Mutex)\n\tDisplay(\"(&locker)\", &locker)\n\t// Output:\n\t// Display (&locker) (*sync.Locker):\n\t// (*(&locker)).type = *sync.Mutex\n\t// (*(*(&locker)).value).state = 0\n\t// (*(*(&locker)).value).sema = 0\n\n\tDisplay(\"locker\", locker)\n\t// Output:\n\t// Display locker (*sync.Mutex):\n\t// (*locker).state = 0\n\t// (*locker).sema = 0\n\t// (*(&locker)) = nil\n\n\tlocker = nil\n\tDisplay(\"(&locker)\", &locker)\n\t// Output:\n\t// Display (&locker) (*sync.Locker):\n\t// (*(&locker)) = nil\n\n\tips, _ := net.LookupHost(\"golang.org\")\n\tDisplay(\"ips\", ips)\n\t// Output:\n\t// Display ips ([]string):\n\t// ips[0] = \"173.194.68.141\"\n\t// ips[1] = \"2607:f8b0:400d:c06::8d\"\n\n\t// Even metarecursion!  (YMMV)\n\tDisplay(\"rV\", reflect.ValueOf(os.Stderr))\n\t// Output:\n\t// Display rV (reflect.Value):\n\t// (*rV.typ).size = 8\n\t// (*rV.typ).ptrdata = 8\n\t// (*rV.typ).hash = 871609668\n\t// (*rV.typ)._ = 0\n\t// ...\n\n\t// a pointer that points to itself\n\ttype P *P\n\tvar p P\n\tp = &p\n\tif false {\n\t\tDisplay(\"p\", p)\n\t\t// Output:\n\t\t// Display p (display.P):\n\t\t// ...stuck, no output...\n\t}\n\n\t// a map that contains itself\n\ttype M map[string]M\n\tm := make(M)\n\tm[\"\"] = m\n\tif false {\n\t\tDisplay(\"m\", m)\n\t\t// Output:\n\t\t// Display m (display.M):\n\t\t// ...stuck, no output...\n\t}\n\n\t// a slice that contains itself\n\ttype S []S\n\ts := make(S, 1)\n\ts[0] = s\n\tif false {\n\t\tDisplay(\"s\", s)\n\t\t// Output:\n\t\t// Display s (display.S):\n\t\t// ...stuck, no output...\n\t}\n\n\t// a linked list that eats its own tail\n\ttype Cycle struct {\n\t\tValue int\n\t\tTail  *Cycle\n\t}\n\tvar c Cycle\n\tc = Cycle{42, &c}\n\tif false {\n\t\tDisplay(\"c\", c)\n\t\t// Output:\n\t\t// Display c (display.Cycle):\n\t\t// c.Value = 42\n\t\t// (*c.Tail).Value = 42\n\t\t// (*(*c.Tail).Tail).Value = 42\n\t\t// ...ad infinitum...\n\t}\n}\n"
  },
  {
    "path": "ch12/format/format.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 332.\n\n// Package format provides an Any function that can format any value.\n//!+\npackage format\n\nimport (\n\t\"reflect\"\n\t\"strconv\"\n)\n\n// Any formats any value as a string.\nfunc Any(value interface{}) string {\n\treturn formatAtom(reflect.ValueOf(value))\n}\n\n// formatAtom formats a value without inspecting its internal structure.\nfunc formatAtom(v reflect.Value) string {\n\tswitch v.Kind() {\n\tcase reflect.Invalid:\n\t\treturn \"invalid\"\n\tcase reflect.Int, reflect.Int8, reflect.Int16,\n\t\treflect.Int32, reflect.Int64:\n\t\treturn strconv.FormatInt(v.Int(), 10)\n\tcase reflect.Uint, reflect.Uint8, reflect.Uint16,\n\t\treflect.Uint32, reflect.Uint64, reflect.Uintptr:\n\t\treturn strconv.FormatUint(v.Uint(), 10)\n\t// ...floating-point and complex cases omitted for brevity...\n\tcase reflect.Bool:\n\t\treturn strconv.FormatBool(v.Bool())\n\tcase reflect.String:\n\t\treturn strconv.Quote(v.String())\n\tcase reflect.Chan, reflect.Func, reflect.Ptr, reflect.Slice, reflect.Map:\n\t\treturn v.Type().String() + \" 0x\" +\n\t\t\tstrconv.FormatUint(uint64(v.Pointer()), 16)\n\tdefault: // reflect.Array, reflect.Struct, reflect.Interface\n\t\treturn v.Type().String() + \" value\"\n\t}\n}\n\n//!-\n"
  },
  {
    "path": "ch12/format/format_test.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\npackage format_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"gopl.io/ch12/format\"\n)\n\nfunc Test(t *testing.T) {\n\t// The pointer values are just examples, and may vary from run to run.\n\t//!+time\n\tvar x int64 = 1\n\tvar d time.Duration = 1 * time.Nanosecond\n\tfmt.Println(format.Any(x))                  // \"1\"\n\tfmt.Println(format.Any(d))                  // \"1\"\n\tfmt.Println(format.Any([]int64{x}))         // \"[]int64 0x8202b87b0\"\n\tfmt.Println(format.Any([]time.Duration{d})) // \"[]time.Duration 0x8202b87e0\"\n\t//!-time\n}\n"
  },
  {
    "path": "ch12/methods/methods.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 351.\n\n// Package methods provides a function to print the methods of any value.\npackage methods\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n)\n\n//!+print\n// Print prints the method set of the value x.\nfunc Print(x interface{}) {\n\tv := reflect.ValueOf(x)\n\tt := v.Type()\n\tfmt.Printf(\"type %s\\n\", t)\n\n\tfor i := 0; i < v.NumMethod(); i++ {\n\t\tmethType := v.Method(i).Type()\n\t\tfmt.Printf(\"func (%s) %s%s\\n\", t, t.Method(i).Name,\n\t\t\tstrings.TrimPrefix(methType.String(), \"func\"))\n\t}\n}\n\n//!-print\n"
  },
  {
    "path": "ch12/methods/methods_test.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\npackage methods_test\n\nimport (\n\t\"strings\"\n\t\"time\"\n\n\t\"gopl.io/ch12/methods\"\n)\n\nfunc ExamplePrintDuration() {\n\tmethods.Print(time.Hour)\n\t// Output:\n\t// type time.Duration\n\t// func (time.Duration) Hours() float64\n\t// func (time.Duration) Minutes() float64\n\t// func (time.Duration) Nanoseconds() int64\n\t// func (time.Duration) Seconds() float64\n\t// func (time.Duration) String() string\n}\n\nfunc ExamplePrintReplacer() {\n\tmethods.Print(new(strings.Replacer))\n\t// Output:\n\t// type *strings.Replacer\n\t// func (*strings.Replacer) Replace(string) string\n\t// func (*strings.Replacer) WriteString(io.Writer, string) (int, error)\n}\n\n/*\n//!+output\nmethods.Print(time.Hour)\n// Output:\n// type time.Duration\n// func (time.Duration) Hours() float64\n// func (time.Duration) Minutes() float64\n// func (time.Duration) Nanoseconds() int64\n// func (time.Duration) Seconds() float64\n// func (time.Duration) String() string\n\nmethods.Print(new(strings.Replacer))\n// Output:\n// type *strings.Replacer\n// func (*strings.Replacer) Replace(string) string\n// func (*strings.Replacer) WriteString(io.Writer, string) (int, error)\n//!-output\n*/\n"
  },
  {
    "path": "ch12/params/params.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 349.\n\n// Package params provides a reflection-based parser for URL parameters.\npackage params\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n)\n\n//!+Unpack\n\n// Unpack populates the fields of the struct pointed to by ptr\n// from the HTTP request parameters in req.\nfunc Unpack(req *http.Request, ptr interface{}) error {\n\tif err := req.ParseForm(); err != nil {\n\t\treturn err\n\t}\n\n\t// Build map of fields keyed by effective name.\n\tfields := make(map[string]reflect.Value)\n\tv := reflect.ValueOf(ptr).Elem() // the struct variable\n\tfor i := 0; i < v.NumField(); i++ {\n\t\tfieldInfo := v.Type().Field(i) // a reflect.StructField\n\t\ttag := fieldInfo.Tag           // a reflect.StructTag\n\t\tname := tag.Get(\"http\")\n\t\tif name == \"\" {\n\t\t\tname = strings.ToLower(fieldInfo.Name)\n\t\t}\n\t\tfields[name] = v.Field(i)\n\t}\n\n\t// Update struct field for each parameter in the request.\n\tfor name, values := range req.Form {\n\t\tf := fields[name]\n\t\tif !f.IsValid() {\n\t\t\tcontinue // ignore unrecognized HTTP parameters\n\t\t}\n\t\tfor _, value := range values {\n\t\t\tif f.Kind() == reflect.Slice {\n\t\t\t\telem := reflect.New(f.Type().Elem()).Elem()\n\t\t\t\tif err := populate(elem, value); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"%s: %v\", name, err)\n\t\t\t\t}\n\t\t\t\tf.Set(reflect.Append(f, elem))\n\t\t\t} else {\n\t\t\t\tif err := populate(f, value); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"%s: %v\", name, err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n//!-Unpack\n\n//!+populate\nfunc populate(v reflect.Value, value string) error {\n\tswitch v.Kind() {\n\tcase reflect.String:\n\t\tv.SetString(value)\n\n\tcase reflect.Int:\n\t\ti, err := strconv.ParseInt(value, 10, 64)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tv.SetInt(i)\n\n\tcase reflect.Bool:\n\t\tb, err := strconv.ParseBool(value)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tv.SetBool(b)\n\n\tdefault:\n\t\treturn fmt.Errorf(\"unsupported kind %s\", v.Type())\n\t}\n\treturn nil\n}\n\n//!-populate\n"
  },
  {
    "path": "ch12/search/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 348.\n\n// Search is a demo of the params.Unpack function.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n)\n\n//!+\n\nimport \"gopl.io/ch12/params\"\n\n// search implements the /search URL endpoint.\nfunc search(resp http.ResponseWriter, req *http.Request) {\n\tvar data struct {\n\t\tLabels     []string `http:\"l\"`\n\t\tMaxResults int      `http:\"max\"`\n\t\tExact      bool     `http:\"x\"`\n\t}\n\tdata.MaxResults = 10 // set default\n\tif err := params.Unpack(req, &data); err != nil {\n\t\thttp.Error(resp, err.Error(), http.StatusBadRequest) // 400\n\t\treturn\n\t}\n\n\t// ...rest of handler...\n\tfmt.Fprintf(resp, \"Search: %+v\\n\", data)\n}\n\n//!-\n\nfunc main() {\n\thttp.HandleFunc(\"/search\", search)\n\tlog.Fatal(http.ListenAndServe(\":12345\", nil))\n}\n\n/*\n//!+output\n$ go build gopl.io/ch12/search\n$ ./search &\n$ ./fetch 'http://localhost:12345/search'\nSearch: {Labels:[] MaxResults:10 Exact:false}\n$ ./fetch 'http://localhost:12345/search?l=golang&l=programming'\nSearch: {Labels:[golang programming] MaxResults:10 Exact:false}\n$ ./fetch 'http://localhost:12345/search?l=golang&l=programming&max=100'\nSearch: {Labels:[golang programming] MaxResults:100 Exact:false}\n$ ./fetch 'http://localhost:12345/search?x=true&l=golang&l=programming'\nSearch: {Labels:[golang programming] MaxResults:10 Exact:true}\n$ ./fetch 'http://localhost:12345/search?q=hello&x=123'\nx: strconv.ParseBool: parsing \"123\": invalid syntax\n$ ./fetch 'http://localhost:12345/search?q=hello&max=lots'\nmax: strconv.ParseInt: parsing \"lots\": invalid syntax\n//!-output\n*/\n"
  },
  {
    "path": "ch12/sexpr/decode.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 344.\n\n// Package sexpr provides a means for converting Go objects to and\n// from S-expressions.\npackage sexpr\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"text/scanner\"\n)\n\n//!+Unmarshal\n// Unmarshal parses S-expression data and populates the variable\n// whose address is in the non-nil pointer out.\nfunc Unmarshal(data []byte, out interface{}) (err error) {\n\tlex := &lexer{scan: scanner.Scanner{Mode: scanner.GoTokens}}\n\tlex.scan.Init(bytes.NewReader(data))\n\tlex.next() // get the first token\n\tdefer func() {\n\t\t// NOTE: this is not an example of ideal error handling.\n\t\tif x := recover(); x != nil {\n\t\t\terr = fmt.Errorf(\"error at %s: %v\", lex.scan.Position, x)\n\t\t}\n\t}()\n\tread(lex, reflect.ValueOf(out).Elem())\n\treturn nil\n}\n\n//!-Unmarshal\n\n//!+lexer\ntype lexer struct {\n\tscan  scanner.Scanner\n\ttoken rune // the current token\n}\n\nfunc (lex *lexer) next()        { lex.token = lex.scan.Scan() }\nfunc (lex *lexer) text() string { return lex.scan.TokenText() }\n\nfunc (lex *lexer) consume(want rune) {\n\tif lex.token != want { // NOTE: Not an example of good error handling.\n\t\tpanic(fmt.Sprintf(\"got %q, want %q\", lex.text(), want))\n\t}\n\tlex.next()\n}\n\n//!-lexer\n\n// The read function is a decoder for a small subset of well-formed\n// S-expressions.  For brevity of our example, it takes many dubious\n// shortcuts.\n//\n// The parser assumes\n// - that the S-expression input is well-formed; it does no error checking.\n// - that the S-expression input corresponds to the type of the variable.\n// - that all numbers in the input are non-negative decimal integers.\n// - that all keys in ((key value) ...) struct syntax are unquoted symbols.\n// - that the input does not contain dotted lists such as (1 2 . 3).\n// - that the input does not contain Lisp reader macros such 'x and #'x.\n//\n// The reflection logic assumes\n// - that v is always a variable of the appropriate type for the\n//   S-expression value.  For example, v must not be a boolean,\n//   interface, channel, or function, and if v is an array, the input\n//   must have the correct number of elements.\n// - that v in the top-level call to read has the zero value of its\n//   type and doesn't need clearing.\n// - that if v is a numeric variable, it is a signed integer.\n\n//!+read\nfunc read(lex *lexer, v reflect.Value) {\n\tswitch lex.token {\n\tcase scanner.Ident:\n\t\t// The only valid identifiers are\n\t\t// \"nil\" and struct field names.\n\t\tif lex.text() == \"nil\" {\n\t\t\tv.Set(reflect.Zero(v.Type()))\n\t\t\tlex.next()\n\t\t\treturn\n\t\t}\n\tcase scanner.String:\n\t\ts, _ := strconv.Unquote(lex.text()) // NOTE: ignoring errors\n\t\tv.SetString(s)\n\t\tlex.next()\n\t\treturn\n\tcase scanner.Int:\n\t\ti, _ := strconv.Atoi(lex.text()) // NOTE: ignoring errors\n\t\tv.SetInt(int64(i))\n\t\tlex.next()\n\t\treturn\n\tcase '(':\n\t\tlex.next()\n\t\treadList(lex, v)\n\t\tlex.next() // consume ')'\n\t\treturn\n\t}\n\tpanic(fmt.Sprintf(\"unexpected token %q\", lex.text()))\n}\n\n//!-read\n\n//!+readlist\nfunc readList(lex *lexer, v reflect.Value) {\n\tswitch v.Kind() {\n\tcase reflect.Array: // (item ...)\n\t\tfor i := 0; !endList(lex); i++ {\n\t\t\tread(lex, v.Index(i))\n\t\t}\n\n\tcase reflect.Slice: // (item ...)\n\t\tfor !endList(lex) {\n\t\t\titem := reflect.New(v.Type().Elem()).Elem()\n\t\t\tread(lex, item)\n\t\t\tv.Set(reflect.Append(v, item))\n\t\t}\n\n\tcase reflect.Struct: // ((name value) ...)\n\t\tfor !endList(lex) {\n\t\t\tlex.consume('(')\n\t\t\tif lex.token != scanner.Ident {\n\t\t\t\tpanic(fmt.Sprintf(\"got token %q, want field name\", lex.text()))\n\t\t\t}\n\t\t\tname := lex.text()\n\t\t\tlex.next()\n\t\t\tread(lex, v.FieldByName(name))\n\t\t\tlex.consume(')')\n\t\t}\n\n\tcase reflect.Map: // ((key value) ...)\n\t\tv.Set(reflect.MakeMap(v.Type()))\n\t\tfor !endList(lex) {\n\t\t\tlex.consume('(')\n\t\t\tkey := reflect.New(v.Type().Key()).Elem()\n\t\t\tread(lex, key)\n\t\t\tvalue := reflect.New(v.Type().Elem()).Elem()\n\t\t\tread(lex, value)\n\t\t\tv.SetMapIndex(key, value)\n\t\t\tlex.consume(')')\n\t\t}\n\n\tdefault:\n\t\tpanic(fmt.Sprintf(\"cannot decode list into %v\", v.Type()))\n\t}\n}\n\nfunc endList(lex *lexer) bool {\n\tswitch lex.token {\n\tcase scanner.EOF:\n\t\tpanic(\"end of file\")\n\tcase ')':\n\t\treturn true\n\t}\n\treturn false\n}\n\n//!-readlist\n"
  },
  {
    "path": "ch12/sexpr/encode.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 339.\n\npackage sexpr\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"reflect\"\n)\n\n//!+Marshal\n// Marshal encodes a Go value in S-expression form.\nfunc Marshal(v interface{}) ([]byte, error) {\n\tvar buf bytes.Buffer\n\tif err := encode(&buf, reflect.ValueOf(v)); err != nil {\n\t\treturn nil, err\n\t}\n\treturn buf.Bytes(), nil\n}\n\n//!-Marshal\n\n// encode writes to buf an S-expression representation of v.\n//!+encode\nfunc encode(buf *bytes.Buffer, v reflect.Value) error {\n\tswitch v.Kind() {\n\tcase reflect.Invalid:\n\t\tbuf.WriteString(\"nil\")\n\n\tcase reflect.Int, reflect.Int8, reflect.Int16,\n\t\treflect.Int32, reflect.Int64:\n\t\tfmt.Fprintf(buf, \"%d\", v.Int())\n\n\tcase reflect.Uint, reflect.Uint8, reflect.Uint16,\n\t\treflect.Uint32, reflect.Uint64, reflect.Uintptr:\n\t\tfmt.Fprintf(buf, \"%d\", v.Uint())\n\n\tcase reflect.String:\n\t\tfmt.Fprintf(buf, \"%q\", v.String())\n\n\tcase reflect.Ptr:\n\t\treturn encode(buf, v.Elem())\n\n\tcase reflect.Array, reflect.Slice: // (value ...)\n\t\tbuf.WriteByte('(')\n\t\tfor i := 0; i < v.Len(); i++ {\n\t\t\tif i > 0 {\n\t\t\t\tbuf.WriteByte(' ')\n\t\t\t}\n\t\t\tif err := encode(buf, v.Index(i)); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tbuf.WriteByte(')')\n\n\tcase reflect.Struct: // ((name value) ...)\n\t\tbuf.WriteByte('(')\n\t\tfor i := 0; i < v.NumField(); i++ {\n\t\t\tif i > 0 {\n\t\t\t\tbuf.WriteByte(' ')\n\t\t\t}\n\t\t\tfmt.Fprintf(buf, \"(%s \", v.Type().Field(i).Name)\n\t\t\tif err := encode(buf, v.Field(i)); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tbuf.WriteByte(')')\n\t\t}\n\t\tbuf.WriteByte(')')\n\n\tcase reflect.Map: // ((key value) ...)\n\t\tbuf.WriteByte('(')\n\t\tfor i, key := range v.MapKeys() {\n\t\t\tif i > 0 {\n\t\t\t\tbuf.WriteByte(' ')\n\t\t\t}\n\t\t\tbuf.WriteByte('(')\n\t\t\tif err := encode(buf, key); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tbuf.WriteByte(' ')\n\t\t\tif err := encode(buf, v.MapIndex(key)); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tbuf.WriteByte(')')\n\t\t}\n\t\tbuf.WriteByte(')')\n\n\tdefault: // float, complex, bool, chan, func, interface\n\t\treturn fmt.Errorf(\"unsupported type: %s\", v.Type())\n\t}\n\treturn nil\n}\n\n//!-encode\n"
  },
  {
    "path": "ch12/sexpr/pretty.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\npackage sexpr\n\n// This file implements the algorithm described in Derek C. Oppen's\n// 1979 Stanford technical report, \"Pretty Printing\".\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"reflect\"\n)\n\nfunc MarshalIndent(v interface{}) ([]byte, error) {\n\tp := printer{width: margin}\n\tif err := pretty(&p, reflect.ValueOf(v)); err != nil {\n\t\treturn nil, err\n\t}\n\treturn p.Bytes(), nil\n}\n\nconst margin = 80\n\ntype token struct {\n\tkind rune // one of \"s ()\" (string, blank, start, end)\n\tstr  string\n\tsize int\n}\n\ntype printer struct {\n\ttokens []*token // FIFO buffer\n\tstack  []*token // stack of open ' ' and '(' tokens\n\trtotal int      // total number of spaces needed to print stream\n\n\tbytes.Buffer\n\tindents []int\n\twidth   int // remaining space\n}\n\nfunc (p *printer) string(str string) {\n\ttok := &token{kind: 's', str: str, size: len(str)}\n\tif len(p.stack) == 0 {\n\t\tp.print(tok)\n\t} else {\n\t\tp.tokens = append(p.tokens, tok)\n\t\tp.rtotal += len(str)\n\t}\n}\nfunc (p *printer) pop() (top *token) {\n\tlast := len(p.stack) - 1\n\ttop, p.stack = p.stack[last], p.stack[:last]\n\treturn\n}\nfunc (p *printer) begin() {\n\tif len(p.stack) == 0 {\n\t\tp.rtotal = 1\n\t}\n\tt := &token{kind: '(', size: -p.rtotal}\n\tp.tokens = append(p.tokens, t)\n\tp.stack = append(p.stack, t) // push\n\tp.string(\"(\")\n}\nfunc (p *printer) end() {\n\tp.string(\")\")\n\tp.tokens = append(p.tokens, &token{kind: ')'})\n\tx := p.pop()\n\tx.size += p.rtotal\n\tif x.kind == ' ' {\n\t\tp.pop().size += p.rtotal\n\t}\n\tif len(p.stack) == 0 {\n\t\tfor _, tok := range p.tokens {\n\t\t\tp.print(tok)\n\t\t}\n\t\tp.tokens = nil\n\t}\n}\nfunc (p *printer) space() {\n\tlast := len(p.stack) - 1\n\tx := p.stack[last]\n\tif x.kind == ' ' {\n\t\tx.size += p.rtotal\n\t\tp.stack = p.stack[:last] // pop\n\t}\n\tt := &token{kind: ' ', size: -p.rtotal}\n\tp.tokens = append(p.tokens, t)\n\tp.stack = append(p.stack, t)\n\tp.rtotal++\n}\nfunc (p *printer) print(t *token) {\n\tswitch t.kind {\n\tcase 's':\n\t\tp.WriteString(t.str)\n\t\tp.width -= len(t.str)\n\tcase '(':\n\t\tp.indents = append(p.indents, p.width)\n\tcase ')':\n\t\tp.indents = p.indents[:len(p.indents)-1] // pop\n\tcase ' ':\n\t\tif t.size > p.width {\n\t\t\tp.width = p.indents[len(p.indents)-1] - 1\n\t\t\tfmt.Fprintf(&p.Buffer, \"\\n%*s\", margin-p.width, \"\")\n\t\t} else {\n\t\t\tp.WriteByte(' ')\n\t\t\tp.width--\n\t\t}\n\t}\n}\nfunc (p *printer) stringf(format string, args ...interface{}) {\n\tp.string(fmt.Sprintf(format, args...))\n}\n\nfunc pretty(p *printer, v reflect.Value) error {\n\tswitch v.Kind() {\n\tcase reflect.Invalid:\n\t\tp.string(\"nil\")\n\n\tcase reflect.Int, reflect.Int8, reflect.Int16,\n\t\treflect.Int32, reflect.Int64:\n\t\tp.stringf(\"%d\", v.Int())\n\n\tcase reflect.Uint, reflect.Uint8, reflect.Uint16,\n\t\treflect.Uint32, reflect.Uint64, reflect.Uintptr:\n\t\tp.stringf(\"%d\", v.Uint())\n\n\tcase reflect.String:\n\t\tp.stringf(\"%q\", v.String())\n\n\tcase reflect.Array, reflect.Slice: // (value ...)\n\t\tp.begin()\n\t\tfor i := 0; i < v.Len(); i++ {\n\t\t\tif i > 0 {\n\t\t\t\tp.space()\n\t\t\t}\n\t\t\tif err := pretty(p, v.Index(i)); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tp.end()\n\n\tcase reflect.Struct: // ((name value ...)\n\t\tp.begin()\n\t\tfor i := 0; i < v.NumField(); i++ {\n\t\t\tif i > 0 {\n\t\t\t\tp.space()\n\t\t\t}\n\t\t\tp.begin()\n\t\t\tp.string(v.Type().Field(i).Name)\n\t\t\tp.space()\n\t\t\tif err := pretty(p, v.Field(i)); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tp.end()\n\t\t}\n\t\tp.end()\n\n\tcase reflect.Map: // ((key value ...)\n\t\tp.begin()\n\t\tfor i, key := range v.MapKeys() {\n\t\t\tif i > 0 {\n\t\t\t\tp.space()\n\t\t\t}\n\t\t\tp.begin()\n\t\t\tif err := pretty(p, key); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tp.space()\n\t\t\tif err := pretty(p, v.MapIndex(key)); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tp.end()\n\t\t}\n\t\tp.end()\n\n\tcase reflect.Ptr:\n\t\treturn pretty(p, v.Elem())\n\n\tdefault: // float, complex, bool, chan, func, interface\n\t\treturn fmt.Errorf(\"unsupported type: %s\", v.Type())\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "ch12/sexpr/sexpr_test.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\npackage sexpr\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n)\n\n// Test verifies that encoding and decoding a complex data value\n// produces an equal result.\n//\n// The test does not make direct assertions about the encoded output\n// because the output depends on map iteration order, which is\n// nondeterministic.  The output of the t.Log statements can be\n// inspected by running the test with the -v flag:\n//\n// \t$ go test -v gopl.io/ch12/sexpr\n//\nfunc Test(t *testing.T) {\n\ttype Movie struct {\n\t\tTitle, Subtitle string\n\t\tYear            int\n\t\tActor           map[string]string\n\t\tOscars          []string\n\t\tSequel          *string\n\t}\n\tstrangelove := Movie{\n\t\tTitle:    \"Dr. Strangelove\",\n\t\tSubtitle: \"How I Learned to Stop Worrying and Love the Bomb\",\n\t\tYear:     1964,\n\t\tActor: map[string]string{\n\t\t\t\"Dr. Strangelove\":            \"Peter Sellers\",\n\t\t\t\"Grp. Capt. Lionel Mandrake\": \"Peter Sellers\",\n\t\t\t\"Pres. Merkin Muffley\":       \"Peter Sellers\",\n\t\t\t\"Gen. Buck Turgidson\":        \"George C. Scott\",\n\t\t\t\"Brig. Gen. Jack D. Ripper\":  \"Sterling Hayden\",\n\t\t\t`Maj. T.J. \"King\" Kong`:      \"Slim Pickens\",\n\t\t},\n\t\tOscars: []string{\n\t\t\t\"Best Actor (Nomin.)\",\n\t\t\t\"Best Adapted Screenplay (Nomin.)\",\n\t\t\t\"Best Director (Nomin.)\",\n\t\t\t\"Best Picture (Nomin.)\",\n\t\t},\n\t}\n\n\t// Encode it\n\tdata, err := Marshal(strangelove)\n\tif err != nil {\n\t\tt.Fatalf(\"Marshal failed: %v\", err)\n\t}\n\tt.Logf(\"Marshal() = %s\\n\", data)\n\n\t// Decode it\n\tvar movie Movie\n\tif err := Unmarshal(data, &movie); err != nil {\n\t\tt.Fatalf(\"Unmarshal failed: %v\", err)\n\t}\n\tt.Logf(\"Unmarshal() = %+v\\n\", movie)\n\n\t// Check equality.\n\tif !reflect.DeepEqual(movie, strangelove) {\n\t\tt.Fatal(\"not equal\")\n\t}\n\n\t// Pretty-print it:\n\tdata, err = MarshalIndent(strangelove)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tt.Logf(\"MarshalIdent() = %s\\n\", data)\n}\n"
  },
  {
    "path": "ch13/bzip/bzip2.c",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 362.\n//\n// The version of this program that appeared in the first and second\n// printings did not comply with the proposed rules for passing\n// pointers between Go and C, described here:\n// https://github.com/golang/proposal/blob/master/design/12416-cgo-pointers.md\n//\n// The version below, which appears in the third printing,\n// has been corrected.  See bzip2.go for explanation.\n\n//!+\n/* This file is gopl.io/ch13/bzip/bzip2.c,         */\n/* a simple wrapper for libbzip2 suitable for cgo. */\n#include <bzlib.h>\n\nint bz2compress(bz_stream *s, int action,\n                char *in, unsigned *inlen, char *out, unsigned *outlen) {\n  s->next_in = in;\n  s->avail_in = *inlen;\n  s->next_out = out;\n  s->avail_out = *outlen;\n  int r = BZ2_bzCompress(s, action);\n  *inlen -= s->avail_in;\n  *outlen -= s->avail_out;\n  s->next_in = s->next_out = NULL;\n  return r;\n}\n\n//!-\n"
  },
  {
    "path": "ch13/bzip/bzip2.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 362.\n//\n// The version of this program that appeared in the first and second\n// printings did not comply with the proposed rules for passing\n// pointers between Go and C, described here:\n// https://github.com/golang/proposal/blob/master/design/12416-cgo-pointers.md\n//\n// The rules forbid a C function like bz2compress from storing 'in'\n// and 'out' (pointers to variables allocated by Go) into the Go\n// variable 's', even temporarily.\n//\n// The version below, which appears in the third printing, has been\n// corrected.  To comply with the rules, the bz_stream variable must\n// be allocated by C code.  We have introduced two C functions,\n// bz2alloc and bz2free, to allocate and free instances of the\n// bz_stream type.  Also, we have changed bz2compress so that before\n// it returns, it clears the fields of the bz_stream that contain\n// pointers to Go variables.\n\n//!+\n\n// Package bzip provides a writer that uses bzip2 compression (bzip.org).\npackage bzip\n\n/*\n#cgo CFLAGS: -I/usr/include\n#cgo LDFLAGS: -L/usr/lib -lbz2\n#include <bzlib.h>\n#include <stdlib.h>\nbz_stream* bz2alloc() { return calloc(1, sizeof(bz_stream)); }\nint bz2compress(bz_stream *s, int action,\n                char *in, unsigned *inlen, char *out, unsigned *outlen);\nvoid bz2free(bz_stream* s) { free(s); }\n*/\nimport \"C\"\n\nimport (\n\t\"io\"\n\t\"unsafe\"\n)\n\ntype writer struct {\n\tw      io.Writer // underlying output stream\n\tstream *C.bz_stream\n\toutbuf [64 * 1024]byte\n}\n\n// NewWriter returns a writer for bzip2-compressed streams.\nfunc NewWriter(out io.Writer) io.WriteCloser {\n\tconst blockSize = 9\n\tconst verbosity = 0\n\tconst workFactor = 30\n\tw := &writer{w: out, stream: C.bz2alloc()}\n\tC.BZ2_bzCompressInit(w.stream, blockSize, verbosity, workFactor)\n\treturn w\n}\n\n//!-\n\n//!+write\nfunc (w *writer) Write(data []byte) (int, error) {\n\tif w.stream == nil {\n\t\tpanic(\"closed\")\n\t}\n\tvar total int // uncompressed bytes written\n\n\tfor len(data) > 0 {\n\t\tinlen, outlen := C.uint(len(data)), C.uint(cap(w.outbuf))\n\t\tC.bz2compress(w.stream, C.BZ_RUN,\n\t\t\t(*C.char)(unsafe.Pointer(&data[0])), &inlen,\n\t\t\t(*C.char)(unsafe.Pointer(&w.outbuf)), &outlen)\n\t\ttotal += int(inlen)\n\t\tdata = data[inlen:]\n\t\tif _, err := w.w.Write(w.outbuf[:outlen]); err != nil {\n\t\t\treturn total, err\n\t\t}\n\t}\n\treturn total, nil\n}\n\n//!-write\n\n//!+close\n// Close flushes the compressed data and closes the stream.\n// It does not close the underlying io.Writer.\nfunc (w *writer) Close() error {\n\tif w.stream == nil {\n\t\tpanic(\"closed\")\n\t}\n\tdefer func() {\n\t\tC.BZ2_bzCompressEnd(w.stream)\n\t\tC.bz2free(w.stream)\n\t\tw.stream = nil\n\t}()\n\tfor {\n\t\tinlen, outlen := C.uint(0), C.uint(cap(w.outbuf))\n\t\tr := C.bz2compress(w.stream, C.BZ_FINISH, nil, &inlen,\n\t\t\t(*C.char)(unsafe.Pointer(&w.outbuf)), &outlen)\n\t\tif _, err := w.w.Write(w.outbuf[:outlen]); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif r == C.BZ_STREAM_END {\n\t\t\treturn nil\n\t\t}\n\t}\n}\n\n//!-close\n"
  },
  {
    "path": "ch13/bzip/bzip2_test.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\npackage bzip_test\n\nimport (\n\t\"bytes\"\n\t\"compress/bzip2\" // reader\n\t\"io\"\n\t\"testing\"\n\n\t\"gopl.io/ch13/bzip\" // writer\n)\n\nfunc TestBzip2(t *testing.T) {\n\tvar compressed, uncompressed bytes.Buffer\n\tw := bzip.NewWriter(&compressed)\n\n\t// Write a repetitive message in a million pieces,\n\t// compressing one copy but not the other.\n\ttee := io.MultiWriter(w, &uncompressed)\n\tfor i := 0; i < 1000000; i++ {\n\t\tio.WriteString(tee, \"hello\")\n\t}\n\tif err := w.Close(); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// Check the size of the compressed stream.\n\tif got, want := compressed.Len(), 255; got != want {\n\t\tt.Errorf(\"1 million hellos compressed to %d bytes, want %d\", got, want)\n\t}\n\n\t// Decompress and compare with original.\n\tvar decompressed bytes.Buffer\n\tio.Copy(&decompressed, bzip2.NewReader(&compressed))\n\tif !bytes.Equal(uncompressed.Bytes(), decompressed.Bytes()) {\n\t\tt.Error(\"decompression yielded a different message\")\n\t}\n}\n"
  },
  {
    "path": "ch13/bzip-print/bzip2.c",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 362.\n// This is the version that appears in print,\n// but it does not comply with the proposed\n// rules for passing pointers between Go and C.\n// (https://github.com/golang/proposal/blob/master/design/12416-cgo-pointers.md)\n// See gopl.io/ch13/bzip for an updated version.\n\n//!+\n/* This file is gopl.io/ch13/bzip/bzip2.c,         */\n/* a simple wrapper for libbzip2 suitable for cgo. */\n#include <bzlib.h>\n\nint bz2compress(bz_stream *s, int action,\n                char *in, unsigned *inlen, char *out, unsigned *outlen) {\n  s->next_in = in;\n  s->avail_in = *inlen;\n  s->next_out = out;\n  s->avail_out = *outlen;\n  int r = BZ2_bzCompress(s, action);\n  *inlen -= s->avail_in;\n  *outlen -= s->avail_out;\n  return r;\n}\n\n//!-\n"
  },
  {
    "path": "ch13/bzip-print/bzip2.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 362.\n// This is the version that appears in print,\n// but it does not comply with the proposed\n// rules for passing pointers between Go and C.\n// (https://github.com/golang/proposal/blob/master/design/12416-cgo-pointers.md)\n// See gopl.io/ch13/bzip for an updated version.\n//!+\n\n// Package bzip provides a writer that uses bzip2 compression (bzip.org).\npackage bzip\n\n/*\n#cgo CFLAGS: -I/usr/include\n#cgo LDFLAGS: -L/usr/lib -lbz2\n#include <bzlib.h>\nint bz2compress(bz_stream *s, int action,\n                char *in, unsigned *inlen, char *out, unsigned *outlen);\n*/\nimport \"C\"\n\nimport (\n\t\"io\"\n\t\"unsafe\"\n)\n\ntype writer struct {\n\tw      io.Writer // underlying output stream\n\tstream *C.bz_stream\n\toutbuf [64 * 1024]byte\n}\n\n// NewWriter returns a writer for bzip2-compressed streams.\nfunc NewWriter(out io.Writer) io.WriteCloser {\n\tconst (\n\t\tblockSize  = 9\n\t\tverbosity  = 0\n\t\tworkFactor = 30\n\t)\n\tw := &writer{w: out, stream: new(C.bz_stream)}\n\tC.BZ2_bzCompressInit(w.stream, blockSize, verbosity, workFactor)\n\treturn w\n}\n\n//!-\n\n//!+write\nfunc (w *writer) Write(data []byte) (int, error) {\n\tif w.stream == nil {\n\t\tpanic(\"closed\")\n\t}\n\tvar total int // uncompressed bytes written\n\n\tfor len(data) > 0 {\n\t\tinlen, outlen := C.uint(len(data)), C.uint(cap(w.outbuf))\n\t\tC.bz2compress(w.stream, C.BZ_RUN,\n\t\t\t(*C.char)(unsafe.Pointer(&data[0])), &inlen,\n\t\t\t(*C.char)(unsafe.Pointer(&w.outbuf)), &outlen)\n\t\ttotal += int(inlen)\n\t\tdata = data[inlen:]\n\t\tif _, err := w.w.Write(w.outbuf[:outlen]); err != nil {\n\t\t\treturn total, err\n\t\t}\n\t}\n\treturn total, nil\n}\n\n//!-write\n\n//!+close\n// Close flushes the compressed data and closes the stream.\n// It does not close the underlying io.Writer.\nfunc (w *writer) Close() error {\n\tif w.stream == nil {\n\t\tpanic(\"closed\")\n\t}\n\tdefer func() {\n\t\tC.BZ2_bzCompressEnd(w.stream)\n\t\tw.stream = nil\n\t}()\n\tfor {\n\t\tinlen, outlen := C.uint(0), C.uint(cap(w.outbuf))\n\t\tr := C.bz2compress(w.stream, C.BZ_FINISH, nil, &inlen,\n\t\t\t(*C.char)(unsafe.Pointer(&w.outbuf)), &outlen)\n\t\tif _, err := w.w.Write(w.outbuf[:outlen]); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif r == C.BZ_STREAM_END {\n\t\t\treturn nil\n\t\t}\n\t}\n}\n\n//!-close\n"
  },
  {
    "path": "ch13/bzip-print/bzip2_test.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\npackage bzip_test\n\nimport (\n\t\"bytes\"\n\t\"compress/bzip2\" // reader\n\t\"io\"\n\t\"testing\"\n\n\t\"gopl.io/ch13/bzip\" // writer\n)\n\nfunc TestBzip2(t *testing.T) {\n\tvar compressed, uncompressed bytes.Buffer\n\tw := bzip.NewWriter(&compressed)\n\n\t// Write a repetitive message in a million pieces,\n\t// compressing one copy but not the other.\n\ttee := io.MultiWriter(w, &uncompressed)\n\tfor i := 0; i < 1000000; i++ {\n\t\tio.WriteString(tee, \"hello\")\n\t}\n\tif err := w.Close(); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// Check the size of the compressed stream.\n\tif got, want := compressed.Len(), 255; got != want {\n\t\tt.Errorf(\"1 million hellos compressed to %d bytes, want %d\", got, want)\n\t}\n\n\t// Decompress and compare with original.\n\tvar decompressed bytes.Buffer\n\tio.Copy(&decompressed, bzip2.NewReader(&compressed))\n\tif !bytes.Equal(uncompressed.Bytes(), decompressed.Bytes()) {\n\t\tt.Error(\"decompression yielded a different message\")\n\t}\n}\n"
  },
  {
    "path": "ch13/bzipper/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 365.\n\n//!+\n\n// Bzipper reads input, bzip2-compresses it, and writes it out.\npackage main\n\nimport (\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\n\t\"gopl.io/ch13/bzip\"\n)\n\nfunc main() {\n\tw := bzip.NewWriter(os.Stdout)\n\tif _, err := io.Copy(w, os.Stdin); err != nil {\n\t\tlog.Fatalf(\"bzipper: %v\\n\", err)\n\t}\n\tif err := w.Close(); err != nil {\n\t\tlog.Fatalf(\"bzipper: close: %v\\n\", err)\n\t}\n}\n\n//!-\n"
  },
  {
    "path": "ch13/equal/equal.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 359.\n\n// Package equal provides a deep equivalence relation for arbitrary values.\npackage equal\n\nimport (\n\t\"reflect\"\n\t\"unsafe\"\n)\n\n//!+\nfunc equal(x, y reflect.Value, seen map[comparison]bool) bool {\n\tif !x.IsValid() || !y.IsValid() {\n\t\treturn x.IsValid() == y.IsValid()\n\t}\n\tif x.Type() != y.Type() {\n\t\treturn false\n\t}\n\n\t// ...cycle check omitted (shown later)...\n\n\t//!-\n\t//!+cyclecheck\n\t// cycle check\n\tif x.CanAddr() && y.CanAddr() {\n\t\txptr := unsafe.Pointer(x.UnsafeAddr())\n\t\typtr := unsafe.Pointer(y.UnsafeAddr())\n\t\tif xptr == yptr {\n\t\t\treturn true // identical references\n\t\t}\n\t\tc := comparison{xptr, yptr, x.Type()}\n\t\tif seen[c] {\n\t\t\treturn true // already seen\n\t\t}\n\t\tseen[c] = true\n\t}\n\t//!-cyclecheck\n\t//!+\n\tswitch x.Kind() {\n\tcase reflect.Bool:\n\t\treturn x.Bool() == y.Bool()\n\n\tcase reflect.String:\n\t\treturn x.String() == y.String()\n\n\t// ...numeric cases omitted for brevity...\n\n\t//!-\n\tcase reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,\n\t\treflect.Int64:\n\t\treturn x.Int() == y.Int()\n\n\tcase reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,\n\t\treflect.Uint64, reflect.Uintptr:\n\t\treturn x.Uint() == y.Uint()\n\n\tcase reflect.Float32, reflect.Float64:\n\t\treturn x.Float() == y.Float()\n\n\tcase reflect.Complex64, reflect.Complex128:\n\t\treturn x.Complex() == y.Complex()\n\t//!+\n\tcase reflect.Chan, reflect.UnsafePointer, reflect.Func:\n\t\treturn x.Pointer() == y.Pointer()\n\n\tcase reflect.Ptr, reflect.Interface:\n\t\treturn equal(x.Elem(), y.Elem(), seen)\n\n\tcase reflect.Array, reflect.Slice:\n\t\tif x.Len() != y.Len() {\n\t\t\treturn false\n\t\t}\n\t\tfor i := 0; i < x.Len(); i++ {\n\t\t\tif !equal(x.Index(i), y.Index(i), seen) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\treturn true\n\n\t// ...struct and map cases omitted for brevity...\n\t//!-\n\tcase reflect.Struct:\n\t\tfor i, n := 0, x.NumField(); i < n; i++ {\n\t\t\tif !equal(x.Field(i), y.Field(i), seen) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\treturn true\n\n\tcase reflect.Map:\n\t\tif x.Len() != y.Len() {\n\t\t\treturn false\n\t\t}\n\t\tfor _, k := range x.MapKeys() {\n\t\t\tif !equal(x.MapIndex(k), y.MapIndex(k), seen) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\treturn true\n\t\t//!+\n\t}\n\tpanic(\"unreachable\")\n}\n\n//!-\n\n//!+comparison\n// Equal reports whether x and y are deeply equal.\n//!-comparison\n//\n// Map keys are always compared with ==, not deeply.\n// (This matters for keys containing pointers or interfaces.)\n//!+comparison\nfunc Equal(x, y interface{}) bool {\n\tseen := make(map[comparison]bool)\n\treturn equal(reflect.ValueOf(x), reflect.ValueOf(y), seen)\n}\n\ntype comparison struct {\n\tx, y unsafe.Pointer\n\tt    reflect.Type\n}\n\n//!-comparison\n"
  },
  {
    "path": "ch13/equal/equal_test.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\npackage equal\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"testing\"\n)\n\nfunc TestEqual(t *testing.T) {\n\tone, oneAgain, two := 1, 1, 2\n\n\ttype CyclePtr *CyclePtr\n\tvar cyclePtr1, cyclePtr2 CyclePtr\n\tcyclePtr1 = &cyclePtr1\n\tcyclePtr2 = &cyclePtr2\n\n\ttype CycleSlice []CycleSlice\n\tvar cycleSlice = make(CycleSlice, 1)\n\tcycleSlice[0] = cycleSlice\n\n\tch1, ch2 := make(chan int), make(chan int)\n\tvar ch1ro <-chan int = ch1\n\n\ttype mystring string\n\n\tvar iface1, iface1Again, iface2 interface{} = &one, &oneAgain, &two\n\n\tfor _, test := range []struct {\n\t\tx, y interface{}\n\t\twant bool\n\t}{\n\t\t// basic types\n\t\t{1, 1, true},\n\t\t{1, 2, false},   // different values\n\t\t{1, 1.0, false}, // different types\n\t\t{\"foo\", \"foo\", true},\n\t\t{\"foo\", \"bar\", false},\n\t\t{mystring(\"foo\"), \"foo\", false}, // different types\n\t\t// slices\n\t\t{[]string{\"foo\"}, []string{\"foo\"}, true},\n\t\t{[]string{\"foo\"}, []string{\"bar\"}, false},\n\t\t{[]string{}, []string(nil), true},\n\t\t// slice cycles\n\t\t{cycleSlice, cycleSlice, true},\n\t\t// maps\n\t\t{\n\t\t\tmap[string][]int{\"foo\": {1, 2, 3}},\n\t\t\tmap[string][]int{\"foo\": {1, 2, 3}},\n\t\t\ttrue,\n\t\t},\n\t\t{\n\t\t\tmap[string][]int{\"foo\": {1, 2, 3}},\n\t\t\tmap[string][]int{\"foo\": {1, 2, 3, 4}},\n\t\t\tfalse,\n\t\t},\n\t\t{\n\t\t\tmap[string][]int{},\n\t\t\tmap[string][]int(nil),\n\t\t\ttrue,\n\t\t},\n\t\t// pointers\n\t\t{&one, &one, true},\n\t\t{&one, &two, false},\n\t\t{&one, &oneAgain, true},\n\t\t{new(bytes.Buffer), new(bytes.Buffer), true},\n\t\t// pointer cycles\n\t\t{cyclePtr1, cyclePtr1, true},\n\t\t{cyclePtr2, cyclePtr2, true},\n\t\t{cyclePtr1, cyclePtr2, true}, // they're deeply equal\n\t\t// functions\n\t\t{(func())(nil), (func())(nil), true},\n\t\t{(func())(nil), func() {}, false},\n\t\t{func() {}, func() {}, false},\n\t\t// arrays\n\t\t{[...]int{1, 2, 3}, [...]int{1, 2, 3}, true},\n\t\t{[...]int{1, 2, 3}, [...]int{1, 2, 4}, false},\n\t\t// channels\n\t\t{ch1, ch1, true},\n\t\t{ch1, ch2, false},\n\t\t{ch1ro, ch1, false}, // NOTE: not equal\n\t\t// interfaces\n\t\t{&iface1, &iface1, true},\n\t\t{&iface1, &iface2, false},\n\t\t{&iface1Again, &iface1, true},\n\t} {\n\t\tif Equal(test.x, test.y) != test.want {\n\t\t\tt.Errorf(\"Equal(%v, %v) = %t\",\n\t\t\t\ttest.x, test.y, !test.want)\n\t\t}\n\t}\n}\n\nfunc Example_equal() {\n\t//!+\n\tfmt.Println(Equal([]int{1, 2, 3}, []int{1, 2, 3}))        // \"true\"\n\tfmt.Println(Equal([]string{\"foo\"}, []string{\"bar\"}))      // \"false\"\n\tfmt.Println(Equal([]string(nil), []string{}))             // \"true\"\n\tfmt.Println(Equal(map[string]int(nil), map[string]int{})) // \"true\"\n\t//!-\n\n\t// Output:\n\t// true\n\t// false\n\t// true\n\t// true\n}\n\nfunc Example_equalCycle() {\n\t//!+cycle\n\t// Circular linked lists a -> b -> a and c -> c.\n\ttype link struct {\n\t\tvalue string\n\t\ttail  *link\n\t}\n\ta, b, c := &link{value: \"a\"}, &link{value: \"b\"}, &link{value: \"c\"}\n\ta.tail, b.tail, c.tail = b, a, c\n\tfmt.Println(Equal(a, a)) // \"true\"\n\tfmt.Println(Equal(b, b)) // \"true\"\n\tfmt.Println(Equal(c, c)) // \"true\"\n\tfmt.Println(Equal(a, b)) // \"false\"\n\tfmt.Println(Equal(a, c)) // \"false\"\n\t//!-cycle\n\n\t// Output:\n\t// true\n\t// true\n\t// true\n\t// false\n\t// false\n}\n"
  },
  {
    "path": "ch13/unsafeptr/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 357.\n\n// Package unsafeptr demonstrates basic use of unsafe.Pointer.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"unsafe\"\n)\n\nfunc main() {\n\t//!+main\n\tvar x struct {\n\t\ta bool\n\t\tb int16\n\t\tc []int\n\t}\n\n\t// equivalent to pb := &x.b\n\tpb := (*int16)(unsafe.Pointer(\n\t\tuintptr(unsafe.Pointer(&x)) + unsafe.Offsetof(x.b)))\n\t*pb = 42\n\n\tfmt.Println(x.b) // \"42\"\n\t//!-main\n}\n\n/*\n//!+wrong\n\t// NOTE: subtly incorrect!\n\ttmp := uintptr(unsafe.Pointer(&x)) + unsafe.Offsetof(x.b)\n\tpb := (*int16)(unsafe.Pointer(tmp))\n\t*pb = 42\n//!-wrong\n*/\n"
  },
  {
    "path": "ch2/boiling/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 29.\n//!+\n\n// Boiling prints the boiling point of water.\npackage main\n\nimport \"fmt\"\n\nconst boilingF = 212.0\n\nfunc main() {\n\tvar f = boilingF\n\tvar c = (f - 32) * 5 / 9\n\tfmt.Printf(\"boiling point = %g°F or %g°C\\n\", f, c)\n\t// Output:\n\t// boiling point = 212°F or 100°C\n}\n\n//!-\n"
  },
  {
    "path": "ch2/cf/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 43.\n//!+\n\n// Cf converts its numeric argument to Celsius and Fahrenheit.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"strconv\"\n\n\t\"gopl.io/ch2/tempconv\"\n)\n\nfunc main() {\n\tfor _, arg := range os.Args[1:] {\n\t\tt, err := strconv.ParseFloat(arg, 64)\n\t\tif err != nil {\n\t\t\tfmt.Fprintf(os.Stderr, \"cf: %v\\n\", err)\n\t\t\tos.Exit(1)\n\t\t}\n\t\tf := tempconv.Fahrenheit(t)\n\t\tc := tempconv.Celsius(t)\n\t\tfmt.Printf(\"%s = %s, %s = %s\\n\",\n\t\t\tf, tempconv.FToC(f), c, tempconv.CToF(c))\n\t}\n}\n\n//!-\n"
  },
  {
    "path": "ch2/echo4/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 33.\n//!+\n\n// Echo4 prints its command-line arguments.\npackage main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"strings\"\n)\n\nvar n = flag.Bool(\"n\", false, \"omit trailing newline\")\nvar sep = flag.String(\"s\", \" \", \"separator\")\n\nfunc main() {\n\tflag.Parse()\n\tfmt.Print(strings.Join(flag.Args(), *sep))\n\tif !*n {\n\t\tfmt.Println()\n\t}\n}\n\n//!-\n"
  },
  {
    "path": "ch2/ftoc/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 29.\n//!+\n\n// Ftoc prints two Fahrenheit-to-Celsius conversions.\npackage main\n\nimport \"fmt\"\n\nfunc main() {\n\tconst freezingF, boilingF = 32.0, 212.0\n\tfmt.Printf(\"%g°F = %g°C\\n\", freezingF, fToC(freezingF)) // \"32°F = 0°C\"\n\tfmt.Printf(\"%g°F = %g°C\\n\", boilingF, fToC(boilingF))   // \"212°F = 100°C\"\n}\n\nfunc fToC(f float64) float64 {\n\treturn (f - 32) * 5 / 9\n}\n\n//!-\n"
  },
  {
    "path": "ch2/popcount/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 45.\n\n// (Package doc comment intentionally malformed to demonstrate golint.)\n//!+\npackage popcount\n\n// pc[i] is the population count of i.\nvar pc [256]byte\n\nfunc init() {\n\tfor i := range pc {\n\t\tpc[i] = pc[i/2] + byte(i&1)\n\t}\n}\n\n// PopCount returns the population count (number of set bits) of x.\nfunc PopCount(x uint64) int {\n\treturn int(pc[byte(x>>(0*8))] +\n\t\tpc[byte(x>>(1*8))] +\n\t\tpc[byte(x>>(2*8))] +\n\t\tpc[byte(x>>(3*8))] +\n\t\tpc[byte(x>>(4*8))] +\n\t\tpc[byte(x>>(5*8))] +\n\t\tpc[byte(x>>(6*8))] +\n\t\tpc[byte(x>>(7*8))])\n}\n\n//!-\n"
  },
  {
    "path": "ch2/popcount/popcount_test.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\npackage popcount_test\n\nimport (\n\t\"testing\"\n\n\t\"gopl.io/ch2/popcount\"\n)\n\n// -- Alternative implementations --\n\nfunc BitCount(x uint64) int {\n\t// Hacker's Delight, Figure 5-2.\n\tx = x - ((x >> 1) & 0x5555555555555555)\n\tx = (x & 0x3333333333333333) + ((x >> 2) & 0x3333333333333333)\n\tx = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f\n\tx = x + (x >> 8)\n\tx = x + (x >> 16)\n\tx = x + (x >> 32)\n\treturn int(x & 0x7f)\n}\n\nfunc PopCountByClearing(x uint64) int {\n\tn := 0\n\tfor x != 0 {\n\t\tx = x & (x - 1) // clear rightmost non-zero bit\n\t\tn++\n\t}\n\treturn n\n}\n\nfunc PopCountByShifting(x uint64) int {\n\tn := 0\n\tfor i := uint(0); i < 64; i++ {\n\t\tif x&(1<<i) != 0 {\n\t\t\tn++\n\t\t}\n\t}\n\treturn n\n}\n\n// -- Benchmarks --\n\nfunc BenchmarkPopCount(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tpopcount.PopCount(0x1234567890ABCDEF)\n\t}\n}\n\nfunc BenchmarkBitCount(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tBitCount(0x1234567890ABCDEF)\n\t}\n}\n\nfunc BenchmarkPopCountByClearing(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tPopCountByClearing(0x1234567890ABCDEF)\n\t}\n}\n\nfunc BenchmarkPopCountByShifting(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tPopCountByShifting(0x1234567890ABCDEF)\n\t}\n}\n\n// Go 1.6, 2.67GHz Xeon\n// $ go test -cpu=4 -bench=. gopl.io/ch2/popcount\n// BenchmarkPopCount-4                  200000000         6.30 ns/op\n// BenchmarkBitCount-4                  300000000         4.15 ns/op\n// BenchmarkPopCountByClearing-4        30000000         45.2 ns/op\n// BenchmarkPopCountByShifting-4        10000000        153 ns/op\n//\n// Go 1.6, 2.5GHz Intel Core i5\n// $ go test -cpu=4 -bench=. gopl.io/ch2/popcount\n// BenchmarkPopCount-4                  200000000         7.52 ns/op\n// BenchmarkBitCount-4                  500000000         3.36 ns/op\n// BenchmarkPopCountByClearing-4        50000000         34.3 ns/op\n// BenchmarkPopCountByShifting-4        20000000        108 ns/op\n//\n// Go 1.7, 3.5GHz Xeon\n// $ go test -cpu=4 -bench=. gopl.io/ch2/popcount\n// BenchmarkPopCount-12                 2000000000        0.28 ns/op\n// BenchmarkBitCount-12                 2000000000        0.27 ns/op\n// BenchmarkPopCountByClearing-12       100000000        18.5 ns/op\n// BenchmarkPopCountByShifting-12       20000000         70.1 ns/op\n"
  },
  {
    "path": "ch2/tempconv/conv.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 41.\n\n//!+\n\npackage tempconv\n\n// CToF converts a Celsius temperature to Fahrenheit.\nfunc CToF(c Celsius) Fahrenheit { return Fahrenheit(c*9/5 + 32) }\n\n// FToC converts a Fahrenheit temperature to Celsius.\nfunc FToC(f Fahrenheit) Celsius { return Celsius((f - 32) * 5 / 9) }\n\n//!-\n"
  },
  {
    "path": "ch2/tempconv/tempconv.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n//!+\n\n// Package tempconv performs Celsius and Fahrenheit conversions.\npackage tempconv\n\nimport \"fmt\"\n\ntype Celsius float64\ntype Fahrenheit float64\n\nconst (\n\tAbsoluteZeroC Celsius = -273.15\n\tFreezingC     Celsius = 0\n\tBoilingC      Celsius = 100\n)\n\nfunc (c Celsius) String() string    { return fmt.Sprintf(\"%g°C\", c) }\nfunc (f Fahrenheit) String() string { return fmt.Sprintf(\"%g°F\", f) }\n\n//!-\n"
  },
  {
    "path": "ch2/tempconv0/celsius.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 39.\n//!+\n\n// Package tempconv performs Celsius and Fahrenheit temperature computations.\npackage tempconv\n\nimport \"fmt\"\n\ntype Celsius float64\ntype Fahrenheit float64\n\nconst (\n\tAbsoluteZeroC Celsius = -273.15\n\tFreezingC     Celsius = 0\n\tBoilingC      Celsius = 100\n)\n\nfunc CToF(c Celsius) Fahrenheit { return Fahrenheit(c*9/5 + 32) }\n\nfunc FToC(f Fahrenheit) Celsius { return Celsius((f - 32) * 5 / 9) }\n\n//!-\n\nfunc (c Celsius) String() string { return fmt.Sprintf(\"%g°C\", c) }\n"
  },
  {
    "path": "ch2/tempconv0/tempconv_test.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\npackage tempconv\n\nimport \"fmt\"\n\nfunc Example_one() {\n\t{\n\t\t//!+arith\n\t\tfmt.Printf(\"%g\\n\", BoilingC-FreezingC) // \"100\" °C\n\t\tboilingF := CToF(BoilingC)\n\t\tfmt.Printf(\"%g\\n\", boilingF-CToF(FreezingC)) // \"180\" °F\n\t\t//!-arith\n\t}\n\t/*\n\t\t//!+arith\n\t\tfmt.Printf(\"%g\\n\", boilingF-FreezingC)       // compile error: type mismatch\n\t\t//!-arith\n\t*/\n\n\t// Output:\n\t// 100\n\t// 180\n}\n\nfunc Example_two() {\n\t//!+printf\n\tc := FToC(212.0)\n\tfmt.Println(c.String()) // \"100°C\"\n\tfmt.Printf(\"%v\\n\", c)   // \"100°C\"; no need to call String explicitly\n\tfmt.Printf(\"%s\\n\", c)   // \"100°C\"\n\tfmt.Println(c)          // \"100°C\"\n\tfmt.Printf(\"%g\\n\", c)   // \"100\"; does not call String\n\tfmt.Println(float64(c)) // \"100\"; does not call String\n\t//!-printf\n\n\t// Output:\n\t// 100°C\n\t// 100°C\n\t// 100°C\n\t// 100°C\n\t// 100\n\t// 100\n}\n"
  },
  {
    "path": "ch3/basename1/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 72.\n\n// Basename1 reads file names from stdin and prints the base name of each one.\npackage main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"os\"\n)\n\nfunc main() {\n\tinput := bufio.NewScanner(os.Stdin)\n\tfor input.Scan() {\n\t\tfmt.Println(basename(input.Text()))\n\t}\n\t// NOTE: ignoring potential errors from input.Err()\n}\n\n//!+\n// basename removes directory components and a .suffix.\n// e.g., a => a, a.go => a, a/b/c.go => c, a/b.c.go => b.c\nfunc basename(s string) string {\n\t// Discard last '/' and everything before.\n\tfor i := len(s) - 1; i >= 0; i-- {\n\t\tif s[i] == '/' {\n\t\t\ts = s[i+1:]\n\t\t\tbreak\n\t\t}\n\t}\n\t// Preserve everything before last '.'.\n\tfor i := len(s) - 1; i >= 0; i-- {\n\t\tif s[i] == '.' {\n\t\t\ts = s[:i]\n\t\t\tbreak\n\t\t}\n\t}\n\treturn s\n}\n\n//!-\n"
  },
  {
    "path": "ch3/basename2/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 72.\n\n// Basename2 reads file names from stdin and prints the base name of each one.\npackage main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\tinput := bufio.NewScanner(os.Stdin)\n\tfor input.Scan() {\n\t\tfmt.Println(basename(input.Text()))\n\t}\n\t// NOTE: ignoring potential errors from input.Err()\n}\n\n// basename removes directory components and a trailing .suffix.\n// e.g., a => a, a.go => a, a/b/c.go => c, a/b.c.go => b.c\n//!+\nfunc basename(s string) string {\n\tslash := strings.LastIndex(s, \"/\") // -1 if \"/\" not found\n\ts = s[slash+1:]\n\tif dot := strings.LastIndex(s, \".\"); dot >= 0 {\n\t\ts = s[:dot]\n\t}\n\treturn s\n}\n\n//!-\n"
  },
  {
    "path": "ch3/comma/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 73.\n\n// Comma prints its argument numbers with a comma at each power of 1000.\n//\n// Example:\n// \t$ go build gopl.io/ch3/comma\n//\t$ ./comma 1 12 123 1234 1234567890\n// \t1\n// \t12\n// \t123\n// \t1,234\n// \t1,234,567,890\n//\npackage main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n)\n\nfunc main() {\n\tfor i := 1; i < len(os.Args); i++ {\n\t\tfmt.Printf(\"  %s\\n\", comma(os.Args[i]))\n\t}\n}\n\n//!+\n// comma inserts commas in a non-negative decimal integer string.\nfunc comma(s string) string {\n\tn := len(s)\n\tif n <= 3 {\n\t\treturn s\n\t}\n\treturn comma(s[:n-3]) + \",\" + s[n-3:]\n}\n\n//!-\n"
  },
  {
    "path": "ch3/mandelbrot/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 61.\n//!+\n\n// Mandelbrot emits a PNG image of the Mandelbrot fractal.\npackage main\n\nimport (\n\t\"image\"\n\t\"image/color\"\n\t\"image/png\"\n\t\"math/cmplx\"\n\t\"os\"\n)\n\nfunc main() {\n\tconst (\n\t\txmin, ymin, xmax, ymax = -2, -2, +2, +2\n\t\twidth, height          = 1024, 1024\n\t)\n\n\timg := image.NewRGBA(image.Rect(0, 0, width, height))\n\tfor py := 0; py < height; py++ {\n\t\ty := float64(py)/height*(ymax-ymin) + ymin\n\t\tfor px := 0; px < width; px++ {\n\t\t\tx := float64(px)/width*(xmax-xmin) + xmin\n\t\t\tz := complex(x, y)\n\t\t\t// Image point (px, py) represents complex value z.\n\t\t\timg.Set(px, py, mandelbrot(z))\n\t\t}\n\t}\n\tpng.Encode(os.Stdout, img) // NOTE: ignoring errors\n}\n\nfunc mandelbrot(z complex128) color.Color {\n\tconst iterations = 200\n\tconst contrast = 15\n\n\tvar v complex128\n\tfor n := uint8(0); n < iterations; n++ {\n\t\tv = v*v + z\n\t\tif cmplx.Abs(v) > 2 {\n\t\t\treturn color.Gray{255 - contrast*n}\n\t\t}\n\t}\n\treturn color.Black\n}\n\n//!-\n\n// Some other interesting functions:\n\nfunc acos(z complex128) color.Color {\n\tv := cmplx.Acos(z)\n\tblue := uint8(real(v)*128) + 127\n\tred := uint8(imag(v)*128) + 127\n\treturn color.YCbCr{192, blue, red}\n}\n\nfunc sqrt(z complex128) color.Color {\n\tv := cmplx.Sqrt(z)\n\tblue := uint8(real(v)*128) + 127\n\tred := uint8(imag(v)*128) + 127\n\treturn color.YCbCr{128, blue, red}\n}\n\n// f(x) = x^4 - 1\n//\n// z' = z - f(z)/f'(z)\n//    = z - (z^4 - 1) / (4 * z^3)\n//    = z - (z - 1/z^3) / 4\nfunc newton(z complex128) color.Color {\n\tconst iterations = 37\n\tconst contrast = 7\n\tfor i := uint8(0); i < iterations; i++ {\n\t\tz -= (z - 1/(z*z*z)) / 4\n\t\tif cmplx.Abs(z*z*z*z-1) < 1e-6 {\n\t\t\treturn color.Gray{255 - contrast*i}\n\t\t}\n\t}\n\treturn color.Black\n}\n"
  },
  {
    "path": "ch3/netflag/netflag.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 77.\n\n// Netflag demonstrates an integer type used as a bit field.\npackage main\n\nimport (\n\t\"fmt\"\n\t. \"net\"\n)\n\n//!+\nfunc IsUp(v Flags) bool     { return v&FlagUp == FlagUp }\nfunc TurnDown(v *Flags)     { *v &^= FlagUp }\nfunc SetBroadcast(v *Flags) { *v |= FlagBroadcast }\nfunc IsCast(v Flags) bool   { return v&(FlagBroadcast|FlagMulticast) != 0 }\n\nfunc main() {\n\tvar v Flags = FlagMulticast | FlagUp\n\tfmt.Printf(\"%b %t\\n\", v, IsUp(v)) // \"10001 true\"\n\tTurnDown(&v)\n\tfmt.Printf(\"%b %t\\n\", v, IsUp(v)) // \"10000 false\"\n\tSetBroadcast(&v)\n\tfmt.Printf(\"%b %t\\n\", v, IsUp(v))   // \"10010 false\"\n\tfmt.Printf(\"%b %t\\n\", v, IsCast(v)) // \"10010 true\"\n}\n\n//!-\n"
  },
  {
    "path": "ch3/printints/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 74.\n\n// Printints demonstrates the use of bytes.Buffer to format a string.\npackage main\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n)\n\n//!+\n// intsToString is like fmt.Sprint(values) but adds commas.\nfunc intsToString(values []int) string {\n\tvar buf bytes.Buffer\n\tbuf.WriteByte('[')\n\tfor i, v := range values {\n\t\tif i > 0 {\n\t\t\tbuf.WriteString(\", \")\n\t\t}\n\t\tfmt.Fprintf(&buf, \"%d\", v)\n\t}\n\tbuf.WriteByte(']')\n\treturn buf.String()\n}\n\nfunc main() {\n\tfmt.Println(intsToString([]int{1, 2, 3})) // \"[1, 2, 3]\"\n}\n\n//!-\n"
  },
  {
    "path": "ch3/surface/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 58.\n//!+\n\n// Surface computes an SVG rendering of a 3-D surface function.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"math\"\n)\n\nconst (\n\twidth, height = 600, 320            // canvas size in pixels\n\tcells         = 100                 // number of grid cells\n\txyrange       = 30.0                // axis ranges (-xyrange..+xyrange)\n\txyscale       = width / 2 / xyrange // pixels per x or y unit\n\tzscale        = height * 0.4        // pixels per z unit\n\tangle         = math.Pi / 6         // angle of x, y axes (=30°)\n)\n\nvar sin30, cos30 = math.Sin(angle), math.Cos(angle) // sin(30°), cos(30°)\n\nfunc main() {\n\tfmt.Printf(\"<svg xmlns='http://www.w3.org/2000/svg' \"+\n\t\t\"style='stroke: grey; fill: white; stroke-width: 0.7' \"+\n\t\t\"width='%d' height='%d'>\", width, height)\n\tfor i := 0; i < cells; i++ {\n\t\tfor j := 0; j < cells; j++ {\n\t\t\tax, ay := corner(i+1, j)\n\t\t\tbx, by := corner(i, j)\n\t\t\tcx, cy := corner(i, j+1)\n\t\t\tdx, dy := corner(i+1, j+1)\n\t\t\tfmt.Printf(\"<polygon points='%g,%g %g,%g %g,%g %g,%g'/>\\n\",\n\t\t\t\tax, ay, bx, by, cx, cy, dx, dy)\n\t\t}\n\t}\n\tfmt.Println(\"</svg>\")\n}\n\nfunc corner(i, j int) (float64, float64) {\n\t// Find point (x,y) at corner of cell (i,j).\n\tx := xyrange * (float64(i)/cells - 0.5)\n\ty := xyrange * (float64(j)/cells - 0.5)\n\n\t// Compute surface height z.\n\tz := f(x, y)\n\n\t// Project (x,y,z) isometrically onto 2-D SVG canvas (sx,sy).\n\tsx := width/2 + (x-y)*cos30*xyscale\n\tsy := height/2 + (x+y)*sin30*xyscale - z*zscale\n\treturn sx, sy\n}\n\nfunc f(x, y float64) float64 {\n\tr := math.Hypot(x, y) // distance from (0,0)\n\treturn math.Sin(r) / r\n}\n\n//!-\n"
  },
  {
    "path": "ch4/append/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 88.\n\n// Append illustrates the behavior of the built-in append function.\npackage main\n\nimport \"fmt\"\n\nfunc appendslice(x []int, y ...int) []int {\n\tvar z []int\n\tzlen := len(x) + len(y)\n\tif zlen <= cap(x) {\n\t\t// There is room to expand the slice.\n\t\tz = x[:zlen]\n\t} else {\n\t\t// There is insufficient space.\n\t\t// Grow by doubling, for amortized linear complexity.\n\t\tzcap := zlen\n\t\tif zcap < 2*len(x) {\n\t\t\tzcap = 2 * len(x)\n\t\t}\n\t\tz = make([]int, zlen, zcap)\n\t\tcopy(z, x)\n\t}\n\tcopy(z[len(x):], y)\n\treturn z\n}\n\n//!+append\nfunc appendInt(x []int, y int) []int {\n\tvar z []int\n\tzlen := len(x) + 1\n\tif zlen <= cap(x) {\n\t\t// There is room to grow.  Extend the slice.\n\t\tz = x[:zlen]\n\t} else {\n\t\t// There is insufficient space.  Allocate a new array.\n\t\t// Grow by doubling, for amortized linear complexity.\n\t\tzcap := zlen\n\t\tif zcap < 2*len(x) {\n\t\t\tzcap = 2 * len(x)\n\t\t}\n\t\tz = make([]int, zlen, zcap)\n\t\tcopy(z, x) // a built-in function; see text\n\t}\n\tz[len(x)] = y\n\treturn z\n}\n\n//!-append\n\n//!+growth\nfunc main() {\n\tvar x, y []int\n\tfor i := 0; i < 10; i++ {\n\t\ty = appendInt(x, i)\n\t\tfmt.Printf(\"%d  cap=%d\\t%v\\n\", i, cap(y), y)\n\t\tx = y\n\t}\n}\n\n//!-growth\n\n/*\n//!+output\n0  cap=1   [0]\n1  cap=2   [0 1]\n2  cap=4   [0 1 2]\n3  cap=4   [0 1 2 3]\n4  cap=8   [0 1 2 3 4]\n5  cap=8   [0 1 2 3 4 5]\n6  cap=8   [0 1 2 3 4 5 6]\n7  cap=8   [0 1 2 3 4 5 6 7]\n8  cap=16  [0 1 2 3 4 5 6 7 8]\n9  cap=16  [0 1 2 3 4 5 6 7 8 9]\n//!-output\n*/\n"
  },
  {
    "path": "ch4/autoescape/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 117.\n\n// Autoescape demonstrates automatic HTML escaping in html/template.\npackage main\n\nimport (\n\t\"html/template\"\n\t\"log\"\n\t\"os\"\n)\n\n//!+\nfunc main() {\n\tconst templ = `<p>A: {{.A}}</p><p>B: {{.B}}</p>`\n\tt := template.Must(template.New(\"escape\").Parse(templ))\n\tvar data struct {\n\t\tA string        // untrusted plain text\n\t\tB template.HTML // trusted HTML\n\t}\n\tdata.A = \"<b>Hello!</b>\"\n\tdata.B = \"<b>Hello!</b>\"\n\tif err := t.Execute(os.Stdout, data); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n\n//!-\n"
  },
  {
    "path": "ch4/charcount/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 97.\n//!+\n\n// Charcount computes counts of Unicode characters.\npackage main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"unicode\"\n\t\"unicode/utf8\"\n)\n\nfunc main() {\n\tcounts := make(map[rune]int)    // counts of Unicode characters\n\tvar utflen [utf8.UTFMax + 1]int // count of lengths of UTF-8 encodings\n\tinvalid := 0                    // count of invalid UTF-8 characters\n\n\tin := bufio.NewReader(os.Stdin)\n\tfor {\n\t\tr, n, err := in.ReadRune() // returns rune, nbytes, error\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t}\n\t\tif err != nil {\n\t\t\tfmt.Fprintf(os.Stderr, \"charcount: %v\\n\", err)\n\t\t\tos.Exit(1)\n\t\t}\n\t\tif r == unicode.ReplacementChar && n == 1 {\n\t\t\tinvalid++\n\t\t\tcontinue\n\t\t}\n\t\tcounts[r]++\n\t\tutflen[n]++\n\t}\n\tfmt.Printf(\"rune\\tcount\\n\")\n\tfor c, n := range counts {\n\t\tfmt.Printf(\"%q\\t%d\\n\", c, n)\n\t}\n\tfmt.Print(\"\\nlen\\tcount\\n\")\n\tfor i, n := range utflen {\n\t\tif i > 0 {\n\t\t\tfmt.Printf(\"%d\\t%d\\n\", i, n)\n\t\t}\n\t}\n\tif invalid > 0 {\n\t\tfmt.Printf(\"\\n%d invalid UTF-8 characters\\n\", invalid)\n\t}\n}\n\n//!-\n"
  },
  {
    "path": "ch4/dedup/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 96.\n\n// Dedup prints only one instance of each line; duplicates are removed.\npackage main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"os\"\n)\n\n//!+\nfunc main() {\n\tseen := make(map[string]bool) // a set of strings\n\tinput := bufio.NewScanner(os.Stdin)\n\tfor input.Scan() {\n\t\tline := input.Text()\n\t\tif !seen[line] {\n\t\t\tseen[line] = true\n\t\t\tfmt.Println(line)\n\t\t}\n\t}\n\n\tif err := input.Err(); err != nil {\n\t\tfmt.Fprintf(os.Stderr, \"dedup: %v\\n\", err)\n\t\tos.Exit(1)\n\t}\n}\n\n//!-\n"
  },
  {
    "path": "ch4/embed/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 106.\n\n// Embed demonstrates basic struct embedding.\npackage main\n\nimport \"fmt\"\n\ntype Point struct{ X, Y int }\n\ntype Circle struct {\n\tPoint\n\tRadius int\n}\n\ntype Wheel struct {\n\tCircle\n\tSpokes int\n}\n\nfunc main() {\n\tvar w Wheel\n\t//!+\n\tw = Wheel{Circle{Point{8, 8}, 5}, 20}\n\n\tw = Wheel{\n\t\tCircle: Circle{\n\t\t\tPoint:  Point{X: 8, Y: 8},\n\t\t\tRadius: 5,\n\t\t},\n\t\tSpokes: 20, // NOTE: trailing comma necessary here (and at Radius)\n\t}\n\n\tfmt.Printf(\"%#v\\n\", w)\n\t// Output:\n\t// Wheel{Circle:Circle{Point:Point{X:8, Y:8}, Radius:5}, Spokes:20}\n\n\tw.X = 42\n\n\tfmt.Printf(\"%#v\\n\", w)\n\t// Output:\n\t// Wheel{Circle:Circle{Point:Point{X:42, Y:8}, Radius:5}, Spokes:20}\n\t//!-\n}\n"
  },
  {
    "path": "ch4/github/github.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 110.\n//!+\n\n// Package github provides a Go API for the GitHub issue tracker.\n// See https://developer.github.com/v3/search/#search-issues.\npackage github\n\nimport \"time\"\n\nconst IssuesURL = \"https://api.github.com/search/issues\"\n\ntype IssuesSearchResult struct {\n\tTotalCount int `json:\"total_count\"`\n\tItems      []*Issue\n}\n\ntype Issue struct {\n\tNumber    int\n\tHTMLURL   string `json:\"html_url\"`\n\tTitle     string\n\tState     string\n\tUser      *User\n\tCreatedAt time.Time `json:\"created_at\"`\n\tBody      string    // in Markdown format\n}\n\ntype User struct {\n\tLogin   string\n\tHTMLURL string `json:\"html_url\"`\n}\n\n//!-\n"
  },
  {
    "path": "ch4/github/search.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n//!+\n\npackage github\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n)\n\n// SearchIssues queries the GitHub issue tracker.\nfunc SearchIssues(terms []string) (*IssuesSearchResult, error) {\n\tq := url.QueryEscape(strings.Join(terms, \" \"))\n\tresp, err := http.Get(IssuesURL + \"?q=\" + q)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t//!-\n\t// For long-term stability, instead of http.Get, use the\n\t// variant below which adds an HTTP request header indicating\n\t// that only version 3 of the GitHub API is acceptable.\n\t//\n\t//   req, err := http.NewRequest(\"GET\", IssuesURL+\"?q=\"+q, nil)\n\t//   if err != nil {\n\t//       return nil, err\n\t//   }\n\t//   req.Header.Set(\n\t//       \"Accept\", \"application/vnd.github.v3.text-match+json\")\n\t//   resp, err := http.DefaultClient.Do(req)\n\t//!+\n\n\t// We must close resp.Body on all execution paths.\n\t// (Chapter 5 presents 'defer', which makes this simpler.)\n\tif resp.StatusCode != http.StatusOK {\n\t\tresp.Body.Close()\n\t\treturn nil, fmt.Errorf(\"search query failed: %s\", resp.Status)\n\t}\n\n\tvar result IssuesSearchResult\n\tif err := json.NewDecoder(resp.Body).Decode(&result); err != nil {\n\t\tresp.Body.Close()\n\t\treturn nil, err\n\t}\n\tresp.Body.Close()\n\treturn &result, nil\n}\n\n//!-\n"
  },
  {
    "path": "ch4/graph/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 99.\n\n// Graph shows how to use a map of maps to represent a directed graph.\npackage main\n\nimport \"fmt\"\n\n//!+\nvar graph = make(map[string]map[string]bool)\n\nfunc addEdge(from, to string) {\n\tedges := graph[from]\n\tif edges == nil {\n\t\tedges = make(map[string]bool)\n\t\tgraph[from] = edges\n\t}\n\tedges[to] = true\n}\n\nfunc hasEdge(from, to string) bool {\n\treturn graph[from][to]\n}\n\n//!-\n\nfunc main() {\n\taddEdge(\"a\", \"b\")\n\taddEdge(\"c\", \"d\")\n\taddEdge(\"a\", \"d\")\n\taddEdge(\"d\", \"a\")\n\tfmt.Println(hasEdge(\"a\", \"b\"))\n\tfmt.Println(hasEdge(\"c\", \"d\"))\n\tfmt.Println(hasEdge(\"a\", \"d\"))\n\tfmt.Println(hasEdge(\"d\", \"a\"))\n\tfmt.Println(hasEdge(\"x\", \"b\"))\n\tfmt.Println(hasEdge(\"c\", \"d\"))\n\tfmt.Println(hasEdge(\"x\", \"d\"))\n\tfmt.Println(hasEdge(\"d\", \"x\"))\n\n}\n"
  },
  {
    "path": "ch4/issues/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 112.\n//!+\n\n// Issues prints a table of GitHub issues matching the search terms.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\t\"gopl.io/ch4/github\"\n)\n\n//!+\nfunc main() {\n\tresult, err := github.SearchIssues(os.Args[1:])\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tfmt.Printf(\"%d issues:\\n\", result.TotalCount)\n\tfor _, item := range result.Items {\n\t\tfmt.Printf(\"#%-5d %9.9s %.55s\\n\",\n\t\t\titem.Number, item.User.Login, item.Title)\n\t}\n}\n\n//!-\n\n/*\n//!+textoutput\n$ go build gopl.io/ch4/issues\n$ ./issues repo:golang/go is:open json decoder\n13 issues:\n#5680    eaigner encoding/json: set key converter on en/decoder\n#6050  gopherbot encoding/json: provide tokenizer\n#8658  gopherbot encoding/json: use bufio\n#8462  kortschak encoding/json: UnmarshalText confuses json.Unmarshal\n#5901        rsc encoding/json: allow override type marshaling\n#9812  klauspost encoding/json: string tag not symmetric\n#7872  extempora encoding/json: Encoder internally buffers full output\n#9650    cespare encoding/json: Decoding gives errPhase when unmarshalin\n#6716  gopherbot encoding/json: include field name in unmarshal error me\n#6901  lukescott encoding/json, encoding/xml: option to treat unknown fi\n#6384    joeshaw encoding/json: encode precise floating point integers u\n#6647    btracey x/tools/cmd/godoc: display type kind of each named type\n#4237  gjemiller encoding/base64: URLEncoding padding is optional\n//!-textoutput\n*/\n"
  },
  {
    "path": "ch4/issueshtml/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 115.\n\n// Issueshtml prints an HTML table of issues matching the search terms.\npackage main\n\nimport (\n\t\"log\"\n\t\"os\"\n\n\t\"gopl.io/ch4/github\"\n)\n\n//!+template\nimport \"html/template\"\n\nvar issueList = template.Must(template.New(\"issuelist\").Parse(`\n<h1>{{.TotalCount}} issues</h1>\n<table>\n<tr style='text-align: left'>\n  <th>#</th>\n  <th>State</th>\n  <th>User</th>\n  <th>Title</th>\n</tr>\n{{range .Items}}\n<tr>\n  <td><a href='{{.HTMLURL}}'>{{.Number}}</a></td>\n  <td>{{.State}}</td>\n  <td><a href='{{.User.HTMLURL}}'>{{.User.Login}}</a></td>\n  <td><a href='{{.HTMLURL}}'>{{.Title}}</a></td>\n</tr>\n{{end}}\n</table>\n`))\n\n//!-template\n\n//!+\nfunc main() {\n\tresult, err := github.SearchIssues(os.Args[1:])\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tif err := issueList.Execute(os.Stdout, result); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n\n//!-\n"
  },
  {
    "path": "ch4/issuesreport/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 113.\n\n// Issuesreport prints a report of issues matching the search terms.\npackage main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"text/template\"\n\t\"time\"\n\n\t\"gopl.io/ch4/github\"\n)\n\n//!+template\nconst templ = `{{.TotalCount}} issues:\n{{range .Items}}----------------------------------------\nNumber: {{.Number}}\nUser:   {{.User.Login}}\nTitle:  {{.Title | printf \"%.64s\"}}\nAge:    {{.CreatedAt | daysAgo}} days\n{{end}}`\n\n//!-template\n\n//!+daysAgo\nfunc daysAgo(t time.Time) int {\n\treturn int(time.Since(t).Hours() / 24)\n}\n\n//!-daysAgo\n\n//!+exec\nvar report = template.Must(template.New(\"issuelist\").\n\tFuncs(template.FuncMap{\"daysAgo\": daysAgo}).\n\tParse(templ))\n\nfunc main() {\n\tresult, err := github.SearchIssues(os.Args[1:])\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tif err := report.Execute(os.Stdout, result); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n\n//!-exec\n\nfunc noMust() {\n\t//!+parse\n\treport, err := template.New(\"report\").\n\t\tFuncs(template.FuncMap{\"daysAgo\": daysAgo}).\n\t\tParse(templ)\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\t//!-parse\n\tresult, err := github.SearchIssues(os.Args[1:])\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tif err := report.Execute(os.Stdout, result); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n\n/*\n//!+output\n$ go build gopl.io/ch4/issuesreport\n$ ./issuesreport repo:golang/go is:open json decoder\n13 issues:\n----------------------------------------\nNumber: 5680\nUser:   eaigner\nTitle:  encoding/json: set key converter on en/decoder\nAge:    750 days\n----------------------------------------\nNumber: 6050\nUser:   gopherbot\nTitle:  encoding/json: provide tokenizer\nAge:    695 days\n----------------------------------------\n...\n//!-output\n*/\n"
  },
  {
    "path": "ch4/movie/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 108.\n\n// Movie prints Movies as JSON.\npackage main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"log\"\n)\n\n//!+\ntype Movie struct {\n\tTitle  string\n\tYear   int  `json:\"released\"`\n\tColor  bool `json:\"color,omitempty\"`\n\tActors []string\n}\n\nvar movies = []Movie{\n\t{Title: \"Casablanca\", Year: 1942, Color: false,\n\t\tActors: []string{\"Humphrey Bogart\", \"Ingrid Bergman\"}},\n\t{Title: \"Cool Hand Luke\", Year: 1967, Color: true,\n\t\tActors: []string{\"Paul Newman\"}},\n\t{Title: \"Bullitt\", Year: 1968, Color: true,\n\t\tActors: []string{\"Steve McQueen\", \"Jacqueline Bisset\"}},\n\t// ...\n}\n\n//!-\n\nfunc main() {\n\t{\n\t\t//!+Marshal\n\t\tdata, err := json.Marshal(movies)\n\t\tif err != nil {\n\t\t\tlog.Fatalf(\"JSON marshaling failed: %s\", err)\n\t\t}\n\t\tfmt.Printf(\"%s\\n\", data)\n\t\t//!-Marshal\n\t}\n\n\t{\n\t\t//!+MarshalIndent\n\t\tdata, err := json.MarshalIndent(movies, \"\", \"    \")\n\t\tif err != nil {\n\t\t\tlog.Fatalf(\"JSON marshaling failed: %s\", err)\n\t\t}\n\t\tfmt.Printf(\"%s\\n\", data)\n\t\t//!-MarshalIndent\n\n\t\t//!+Unmarshal\n\t\tvar titles []struct{ Title string }\n\t\tif err := json.Unmarshal(data, &titles); err != nil {\n\t\t\tlog.Fatalf(\"JSON unmarshaling failed: %s\", err)\n\t\t}\n\t\tfmt.Println(titles) // \"[{Casablanca} {Cool Hand Luke} {Bullitt}]\"\n\t\t//!-Unmarshal\n\t}\n}\n\n/*\n//!+output\n[{\"Title\":\"Casablanca\",\"released\":1942,\"Actors\":[\"Humphrey Bogart\",\"Ingr\nid Bergman\"]},{\"Title\":\"Cool Hand Luke\",\"released\":1967,\"color\":true,\"Ac\ntors\":[\"Paul Newman\"]},{\"Title\":\"Bullitt\",\"released\":1968,\"color\":true,\"\nActors\":[\"Steve McQueen\",\"Jacqueline Bisset\"]}]\n//!-output\n*/\n\n/*\n//!+indented\n[\n    {\n        \"Title\": \"Casablanca\",\n        \"released\": 1942,\n        \"Actors\": [\n            \"Humphrey Bogart\",\n            \"Ingrid Bergman\"\n        ]\n    },\n    {\n        \"Title\": \"Cool Hand Luke\",\n        \"released\": 1967,\n        \"color\": true,\n        \"Actors\": [\n            \"Paul Newman\"\n        ]\n    },\n    {\n        \"Title\": \"Bullitt\",\n        \"released\": 1968,\n        \"color\": true,\n        \"Actors\": [\n            \"Steve McQueen\",\n            \"Jacqueline Bisset\"\n        ]\n    }\n]\n//!-indented\n*/\n"
  },
  {
    "path": "ch4/nonempty/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 91.\n\n//!+nonempty\n\n// Nonempty is an example of an in-place slice algorithm.\npackage main\n\nimport \"fmt\"\n\n// nonempty returns a slice holding only the non-empty strings.\n// The underlying array is modified during the call.\nfunc nonempty(strings []string) []string {\n\ti := 0\n\tfor _, s := range strings {\n\t\tif s != \"\" {\n\t\t\tstrings[i] = s\n\t\t\ti++\n\t\t}\n\t}\n\treturn strings[:i]\n}\n\n//!-nonempty\n\nfunc main() {\n\t//!+main\n\tdata := []string{\"one\", \"\", \"three\"}\n\tfmt.Printf(\"%q\\n\", nonempty(data)) // `[\"one\" \"three\"]`\n\tfmt.Printf(\"%q\\n\", data)           // `[\"one\" \"three\" \"three\"]`\n\t//!-main\n}\n\n//!+alt\nfunc nonempty2(strings []string) []string {\n\tout := strings[:0] // zero-length slice of original\n\tfor _, s := range strings {\n\t\tif s != \"\" {\n\t\t\tout = append(out, s)\n\t\t}\n\t}\n\treturn out\n}\n\n//!-alt\n"
  },
  {
    "path": "ch4/rev/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 86.\n\n// Rev reverses a slice.\npackage main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n)\n\nfunc main() {\n\t//!+array\n\ta := [...]int{0, 1, 2, 3, 4, 5}\n\treverse(a[:])\n\tfmt.Println(a) // \"[5 4 3 2 1 0]\"\n\t//!-array\n\n\t//!+slice\n\ts := []int{0, 1, 2, 3, 4, 5}\n\t// Rotate s left by two positions.\n\treverse(s[:2])\n\treverse(s[2:])\n\treverse(s)\n\tfmt.Println(s) // \"[2 3 4 5 0 1]\"\n\t//!-slice\n\n\t// Interactive test of reverse.\n\tinput := bufio.NewScanner(os.Stdin)\nouter:\n\tfor input.Scan() {\n\t\tvar ints []int\n\t\tfor _, s := range strings.Fields(input.Text()) {\n\t\t\tx, err := strconv.ParseInt(s, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\tfmt.Fprintln(os.Stderr, err)\n\t\t\t\tcontinue outer\n\t\t\t}\n\t\t\tints = append(ints, int(x))\n\t\t}\n\t\treverse(ints)\n\t\tfmt.Printf(\"%v\\n\", ints)\n\t}\n\t// NOTE: ignoring potential errors from input.Err()\n}\n\n//!+rev\n// reverse reverses a slice of ints in place.\nfunc reverse(s []int) {\n\tfor i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {\n\t\ts[i], s[j] = s[j], s[i]\n\t}\n}\n\n//!-rev\n"
  },
  {
    "path": "ch4/sha256/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 83.\n\n// The sha256 command computes the SHA256 hash (an array) of a string.\npackage main\n\nimport \"fmt\"\n\n//!+\nimport \"crypto/sha256\"\n\nfunc main() {\n\tc1 := sha256.Sum256([]byte(\"x\"))\n\tc2 := sha256.Sum256([]byte(\"X\"))\n\tfmt.Printf(\"%x\\n%x\\n%t\\n%T\\n\", c1, c2, c1 == c2, c1)\n\t// Output:\n\t// 2d711642b726b04401627ca9fbac32f5c8530fb1903cc4db02258717921a4881\n\t// 4b68ab3847feda7d6c62c1fbcbeebfa35eab7351ed5e78f4ddadea5df64b8015\n\t// false\n\t// [32]uint8\n}\n\n//!-\n"
  },
  {
    "path": "ch4/treesort/sort.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 101.\n\n// Package treesort provides insertion sort using an unbalanced binary tree.\npackage treesort\n\n//!+\ntype tree struct {\n\tvalue       int\n\tleft, right *tree\n}\n\n// Sort sorts values in place.\nfunc Sort(values []int) {\n\tvar root *tree\n\tfor _, v := range values {\n\t\troot = add(root, v)\n\t}\n\tappendValues(values[:0], root)\n}\n\n// appendValues appends the elements of t to values in order\n// and returns the resulting slice.\nfunc appendValues(values []int, t *tree) []int {\n\tif t != nil {\n\t\tvalues = appendValues(values, t.left)\n\t\tvalues = append(values, t.value)\n\t\tvalues = appendValues(values, t.right)\n\t}\n\treturn values\n}\n\nfunc add(t *tree, value int) *tree {\n\tif t == nil {\n\t\t// Equivalent to return &tree{value: value}.\n\t\tt = new(tree)\n\t\tt.value = value\n\t\treturn t\n\t}\n\tif value < t.value {\n\t\tt.left = add(t.left, value)\n\t} else {\n\t\tt.right = add(t.right, value)\n\t}\n\treturn t\n}\n\n//!-\n"
  },
  {
    "path": "ch4/treesort/sort_test.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\npackage treesort_test\n\nimport (\n\t\"math/rand\"\n\t\"sort\"\n\t\"testing\"\n\n\t\"gopl.io/ch4/treesort\"\n)\n\nfunc TestSort(t *testing.T) {\n\tdata := make([]int, 50)\n\tfor i := range data {\n\t\tdata[i] = rand.Int() % 50\n\t}\n\ttreesort.Sort(data)\n\tif !sort.IntsAreSorted(data) {\n\t\tt.Errorf(\"not sorted: %v\", data)\n\t}\n}\n"
  },
  {
    "path": "ch5/defer1/defer.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 150.\n\n// Defer1 demonstrates a deferred call being invoked during a panic.\npackage main\n\nimport \"fmt\"\n\n//!+f\nfunc main() {\n\tf(3)\n}\n\nfunc f(x int) {\n\tfmt.Printf(\"f(%d)\\n\", x+0/x) // panics if x == 0\n\tdefer fmt.Printf(\"defer %d\\n\", x)\n\tf(x - 1)\n}\n\n//!-f\n\n/*\n//!+stdout\nf(3)\nf(2)\nf(1)\ndefer 1\ndefer 2\ndefer 3\n//!-stdout\n\n//!+stderr\npanic: runtime error: integer divide by zero\nmain.f(0)\n        src/gopl.io/ch5/defer1/defer.go:14\nmain.f(1)\n        src/gopl.io/ch5/defer1/defer.go:16\nmain.f(2)\n        src/gopl.io/ch5/defer1/defer.go:16\n\nmain.f(3)\n        src/gopl.io/ch5/defer1/defer.go:16\nmain.main()\n        src/gopl.io/ch5/defer1/defer.go:10\n//!-stderr\n*/\n"
  },
  {
    "path": "ch5/defer2/defer.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 151.\n\n// Defer2 demonstrates a deferred call to runtime.Stack during a panic.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"runtime\"\n)\n\n//!+\nfunc main() {\n\tdefer printStack()\n\tf(3)\n}\n\nfunc printStack() {\n\tvar buf [4096]byte\n\tn := runtime.Stack(buf[:], false)\n\tos.Stdout.Write(buf[:n])\n}\n\n//!-\n\nfunc f(x int) {\n\tfmt.Printf(\"f(%d)\\n\", x+0/x) // panics if x == 0\n\tdefer fmt.Printf(\"defer %d\\n\", x)\n\tf(x - 1)\n}\n\n/*\n//!+printstack\ngoroutine 1 [running]:\nmain.printStack()\n\tsrc/gopl.io/ch5/defer2/defer.go:20\nmain.f(0)\n\tsrc/gopl.io/ch5/defer2/defer.go:27\nmain.f(1)\n\tsrc/gopl.io/ch5/defer2/defer.go:29\nmain.f(2)\n\tsrc/gopl.io/ch5/defer2/defer.go:29\nmain.f(3)\n\tsrc/gopl.io/ch5/defer2/defer.go:29\nmain.main()\n\tsrc/gopl.io/ch5/defer2/defer.go:15\n//!-printstack\n*/\n"
  },
  {
    "path": "ch5/fetch/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 148.\n\n// Fetch saves the contents of a URL into a local file.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"path\"\n)\n\n//!+\n// Fetch downloads the URL and returns the\n// name and length of the local file.\nfunc fetch(url string) (filename string, n int64, err error) {\n\tresp, err := http.Get(url)\n\tif err != nil {\n\t\treturn \"\", 0, err\n\t}\n\tdefer resp.Body.Close()\n\n\tlocal := path.Base(resp.Request.URL.Path)\n\tif local == \"/\" {\n\t\tlocal = \"index.html\"\n\t}\n\tf, err := os.Create(local)\n\tif err != nil {\n\t\treturn \"\", 0, err\n\t}\n\tn, err = io.Copy(f, resp.Body)\n\t// Close file, but prefer error from Copy, if any.\n\tif closeErr := f.Close(); err == nil {\n\t\terr = closeErr\n\t}\n\treturn local, n, err\n}\n\n//!-\n\nfunc main() {\n\tfor _, url := range os.Args[1:] {\n\t\tlocal, n, err := fetch(url)\n\t\tif err != nil {\n\t\t\tfmt.Fprintf(os.Stderr, \"fetch %s: %v\\n\", url, err)\n\t\t\tcontinue\n\t\t}\n\t\tfmt.Fprintf(os.Stderr, \"%s => %s (%d bytes).\\n\", url, local, n)\n\t}\n}\n"
  },
  {
    "path": "ch5/findlinks1/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 122.\n//!+main\n\n// Findlinks1 prints the links in an HTML document read from standard input.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"golang.org/x/net/html\"\n)\n\nfunc main() {\n\tdoc, err := html.Parse(os.Stdin)\n\tif err != nil {\n\t\tfmt.Fprintf(os.Stderr, \"findlinks1: %v\\n\", err)\n\t\tos.Exit(1)\n\t}\n\tfor _, link := range visit(nil, doc) {\n\t\tfmt.Println(link)\n\t}\n}\n\n//!-main\n\n//!+visit\n// visit appends to links each link found in n and returns the result.\nfunc visit(links []string, n *html.Node) []string {\n\tif n.Type == html.ElementNode && n.Data == \"a\" {\n\t\tfor _, a := range n.Attr {\n\t\t\tif a.Key == \"href\" {\n\t\t\t\tlinks = append(links, a.Val)\n\t\t\t}\n\t\t}\n\t}\n\tfor c := n.FirstChild; c != nil; c = c.NextSibling {\n\t\tlinks = visit(links, c)\n\t}\n\treturn links\n}\n\n//!-visit\n\n/*\n//!+html\npackage html\n\ntype Node struct {\n\tType                    NodeType\n\tData                    string\n\tAttr                    []Attribute\n\tFirstChild, NextSibling *Node\n}\n\ntype NodeType int32\n\nconst (\n\tErrorNode NodeType = iota\n\tTextNode\n\tDocumentNode\n\tElementNode\n\tCommentNode\n\tDoctypeNode\n)\n\ntype Attribute struct {\n\tKey, Val string\n}\n\nfunc Parse(r io.Reader) (*Node, error)\n//!-html\n*/\n"
  },
  {
    "path": "ch5/findlinks2/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 125.\n\n// Findlinks2 does an HTTP GET on each URL, parses the\n// result as HTML, and prints the links within it.\n//\n// Usage:\n//\tfindlinks url ...\npackage main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"os\"\n\n\t\"golang.org/x/net/html\"\n)\n\n// visit appends to links each link found in n, and returns the result.\nfunc visit(links []string, n *html.Node) []string {\n\tif n.Type == html.ElementNode && n.Data == \"a\" {\n\t\tfor _, a := range n.Attr {\n\t\t\tif a.Key == \"href\" {\n\t\t\t\tlinks = append(links, a.Val)\n\t\t\t}\n\t\t}\n\t}\n\tfor c := n.FirstChild; c != nil; c = c.NextSibling {\n\t\tlinks = visit(links, c)\n\t}\n\treturn links\n}\n\n//!+\nfunc main() {\n\tfor _, url := range os.Args[1:] {\n\t\tlinks, err := findLinks(url)\n\t\tif err != nil {\n\t\t\tfmt.Fprintf(os.Stderr, \"findlinks2: %v\\n\", err)\n\t\t\tcontinue\n\t\t}\n\t\tfor _, link := range links {\n\t\t\tfmt.Println(link)\n\t\t}\n\t}\n}\n\n// findLinks performs an HTTP GET request for url, parses the\n// response as HTML, and extracts and returns the links.\nfunc findLinks(url string) ([]string, error) {\n\tresp, err := http.Get(url)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif resp.StatusCode != http.StatusOK {\n\t\tresp.Body.Close()\n\t\treturn nil, fmt.Errorf(\"getting %s: %s\", url, resp.Status)\n\t}\n\tdoc, err := html.Parse(resp.Body)\n\tresp.Body.Close()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"parsing %s as HTML: %v\", url, err)\n\t}\n\treturn visit(nil, doc), nil\n}\n\n//!-\n"
  },
  {
    "path": "ch5/findlinks3/findlinks.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 139.\n\n// Findlinks3 crawls the web, starting with the URLs on the command line.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\t\"gopl.io/ch5/links\"\n)\n\n//!+breadthFirst\n// breadthFirst calls f for each item in the worklist.\n// Any items returned by f are added to the worklist.\n// f is called at most once for each item.\nfunc breadthFirst(f func(item string) []string, worklist []string) {\n\tseen := make(map[string]bool)\n\tfor len(worklist) > 0 {\n\t\titems := worklist\n\t\tworklist = nil\n\t\tfor _, item := range items {\n\t\t\tif !seen[item] {\n\t\t\t\tseen[item] = true\n\t\t\t\tworklist = append(worklist, f(item)...)\n\t\t\t}\n\t\t}\n\t}\n}\n\n//!-breadthFirst\n\n//!+crawl\nfunc crawl(url string) []string {\n\tfmt.Println(url)\n\tlist, err := links.Extract(url)\n\tif err != nil {\n\t\tlog.Print(err)\n\t}\n\treturn list\n}\n\n//!-crawl\n\n//!+main\nfunc main() {\n\t// Crawl the web breadth-first,\n\t// starting from the command-line arguments.\n\tbreadthFirst(crawl, os.Args[1:])\n}\n\n//!-main\n"
  },
  {
    "path": "ch5/links/links.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 138.\n//!+Extract\n\n// Package links provides a link-extraction function.\npackage links\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"golang.org/x/net/html\"\n)\n\n// Extract makes an HTTP GET request to the specified URL, parses\n// the response as HTML, and returns the links in the HTML document.\nfunc Extract(url string) ([]string, error) {\n\tresp, err := http.Get(url)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif resp.StatusCode != http.StatusOK {\n\t\tresp.Body.Close()\n\t\treturn nil, fmt.Errorf(\"getting %s: %s\", url, resp.Status)\n\t}\n\n\tdoc, err := html.Parse(resp.Body)\n\tresp.Body.Close()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"parsing %s as HTML: %v\", url, err)\n\t}\n\n\tvar links []string\n\tvisitNode := func(n *html.Node) {\n\t\tif n.Type == html.ElementNode && n.Data == \"a\" {\n\t\t\tfor _, a := range n.Attr {\n\t\t\t\tif a.Key != \"href\" {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tlink, err := resp.Request.URL.Parse(a.Val)\n\t\t\t\tif err != nil {\n\t\t\t\t\tcontinue // ignore bad URLs\n\t\t\t\t}\n\t\t\t\tlinks = append(links, link.String())\n\t\t\t}\n\t\t}\n\t}\n\tforEachNode(doc, visitNode, nil)\n\treturn links, nil\n}\n\n//!-Extract\n\n// Copied from gopl.io/ch5/outline2.\nfunc forEachNode(n *html.Node, pre, post func(n *html.Node)) {\n\tif pre != nil {\n\t\tpre(n)\n\t}\n\tfor c := n.FirstChild; c != nil; c = c.NextSibling {\n\t\tforEachNode(c, pre, post)\n\t}\n\tif post != nil {\n\t\tpost(n)\n\t}\n}\n"
  },
  {
    "path": "ch5/outline/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 123.\n\n// Outline prints the outline of an HTML document tree.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"golang.org/x/net/html\"\n)\n\n//!+\nfunc main() {\n\tdoc, err := html.Parse(os.Stdin)\n\tif err != nil {\n\t\tfmt.Fprintf(os.Stderr, \"outline: %v\\n\", err)\n\t\tos.Exit(1)\n\t}\n\toutline(nil, doc)\n}\n\nfunc outline(stack []string, n *html.Node) {\n\tif n.Type == html.ElementNode {\n\t\tstack = append(stack, n.Data) // push tag\n\t\tfmt.Println(stack)\n\t}\n\tfor c := n.FirstChild; c != nil; c = c.NextSibling {\n\t\toutline(stack, c)\n\t}\n}\n\n//!-\n"
  },
  {
    "path": "ch5/outline2/outline.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 133.\n\n// Outline prints the outline of an HTML document tree.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"os\"\n\n\t\"golang.org/x/net/html\"\n)\n\nfunc main() {\n\tfor _, url := range os.Args[1:] {\n\t\toutline(url)\n\t}\n}\n\nfunc outline(url string) error {\n\tresp, err := http.Get(url)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer resp.Body.Close()\n\n\tdoc, err := html.Parse(resp.Body)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t//!+call\n\tforEachNode(doc, startElement, endElement)\n\t//!-call\n\n\treturn nil\n}\n\n//!+forEachNode\n// forEachNode calls the functions pre(x) and post(x) for each node\n// x in the tree rooted at n. Both functions are optional.\n// pre is called before the children are visited (preorder) and\n// post is called after (postorder).\nfunc forEachNode(n *html.Node, pre, post func(n *html.Node)) {\n\tif pre != nil {\n\t\tpre(n)\n\t}\n\n\tfor c := n.FirstChild; c != nil; c = c.NextSibling {\n\t\tforEachNode(c, pre, post)\n\t}\n\n\tif post != nil {\n\t\tpost(n)\n\t}\n}\n\n//!-forEachNode\n\n//!+startend\nvar depth int\n\nfunc startElement(n *html.Node) {\n\tif n.Type == html.ElementNode {\n\t\tfmt.Printf(\"%*s<%s>\\n\", depth*2, \"\", n.Data)\n\t\tdepth++\n\t}\n}\n\nfunc endElement(n *html.Node) {\n\tif n.Type == html.ElementNode {\n\t\tdepth--\n\t\tfmt.Printf(\"%*s</%s>\\n\", depth*2, \"\", n.Data)\n\t}\n}\n\n//!-startend\n"
  },
  {
    "path": "ch5/squares/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 135.\n\n// The squares program demonstrates a function value with state.\npackage main\n\nimport \"fmt\"\n\n//!+\n// squares returns a function that returns\n// the next square number each time it is called.\nfunc squares() func() int {\n\tvar x int\n\treturn func() int {\n\t\tx++\n\t\treturn x * x\n\t}\n}\n\nfunc main() {\n\tf := squares()\n\tfmt.Println(f()) // \"1\"\n\tfmt.Println(f()) // \"4\"\n\tfmt.Println(f()) // \"9\"\n\tfmt.Println(f()) // \"16\"\n}\n\n//!-\n"
  },
  {
    "path": "ch5/sum/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 142.\n\n// The sum program demonstrates a variadic function.\npackage main\n\nimport \"fmt\"\n\n//!+\nfunc sum(vals ...int) int {\n\ttotal := 0\n\tfor _, val := range vals {\n\t\ttotal += val\n\t}\n\treturn total\n}\n\n//!-\n\nfunc main() {\n\t//!+main\n\tfmt.Println(sum())           //  \"0\"\n\tfmt.Println(sum(3))          //  \"3\"\n\tfmt.Println(sum(1, 2, 3, 4)) //  \"10\"\n\t//!-main\n\n\t//!+slice\n\tvalues := []int{1, 2, 3, 4}\n\tfmt.Println(sum(values...)) // \"10\"\n\t//!-slice\n}\n"
  },
  {
    "path": "ch5/title1/title.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 144.\n\n// Title1 prints the title of an HTML document specified by a URL.\npackage main\n\n/*\n//!+output\n$ go build gopl.io/ch5/title1\n$ ./title1 http://gopl.io\nThe Go Programming Language\n$ ./title1 https://golang.org/doc/effective_go.html\nEffective Go - The Go Programming Language\n$ ./title1 https://golang.org/doc/gopher/frontpage.png\ntitle: https://golang.org/doc/gopher/frontpage.png\n    has type image/png, not text/html\n//!-output\n*/\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n\n\t\"golang.org/x/net/html\"\n)\n\n// Copied from gopl.io/ch5/outline2.\nfunc forEachNode(n *html.Node, pre, post func(n *html.Node)) {\n\tif pre != nil {\n\t\tpre(n)\n\t}\n\tfor c := n.FirstChild; c != nil; c = c.NextSibling {\n\t\tforEachNode(c, pre, post)\n\t}\n\tif post != nil {\n\t\tpost(n)\n\t}\n}\n\n//!+\nfunc title(url string) error {\n\tresp, err := http.Get(url)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Check Content-Type is HTML (e.g., \"text/html; charset=utf-8\").\n\tct := resp.Header.Get(\"Content-Type\")\n\tif ct != \"text/html\" && !strings.HasPrefix(ct, \"text/html;\") {\n\t\tresp.Body.Close()\n\t\treturn fmt.Errorf(\"%s has type %s, not text/html\", url, ct)\n\t}\n\n\tdoc, err := html.Parse(resp.Body)\n\tresp.Body.Close()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"parsing %s as HTML: %v\", url, err)\n\t}\n\n\tvisitNode := func(n *html.Node) {\n\t\tif n.Type == html.ElementNode && n.Data == \"title\" &&\n\t\t\tn.FirstChild != nil {\n\t\t\tfmt.Println(n.FirstChild.Data)\n\t\t}\n\t}\n\tforEachNode(doc, visitNode, nil)\n\treturn nil\n}\n\n//!-\n\nfunc main() {\n\tfor _, arg := range os.Args[1:] {\n\t\tif err := title(arg); err != nil {\n\t\t\tfmt.Fprintf(os.Stderr, \"title: %v\\n\", err)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "ch5/title2/title.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 145.\n\n// Title2 prints the title of an HTML document specified by a URL.\n// It uses defer to simplify closing the response body stream.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n\n\t\"golang.org/x/net/html\"\n)\n\n// Copied from gopl.io/ch5/outline2.\nfunc forEachNode(n *html.Node, pre, post func(n *html.Node)) {\n\tif pre != nil {\n\t\tpre(n)\n\t}\n\tfor c := n.FirstChild; c != nil; c = c.NextSibling {\n\t\tforEachNode(c, pre, post)\n\t}\n\tif post != nil {\n\t\tpost(n)\n\t}\n}\n\n//!+\nfunc title(url string) error {\n\tresp, err := http.Get(url)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer resp.Body.Close()\n\n\tct := resp.Header.Get(\"Content-Type\")\n\tif ct != \"text/html\" && !strings.HasPrefix(ct, \"text/html;\") {\n\t\treturn fmt.Errorf(\"%s has type %s, not text/html\", url, ct)\n\t}\n\n\tdoc, err := html.Parse(resp.Body)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"parsing %s as HTML: %v\", url, err)\n\t}\n\n\t// ...print doc's title element...\n\t//!-\n\tvisitNode := func(n *html.Node) {\n\t\tif n.Type == html.ElementNode && n.Data == \"title\" &&\n\t\t\tn.FirstChild != nil {\n\t\t\tfmt.Println(n.FirstChild.Data)\n\t\t}\n\t}\n\tforEachNode(doc, visitNode, nil)\n\t//!+\n\n\treturn nil\n}\n\n//!-\n\nfunc main() {\n\tfor _, arg := range os.Args[1:] {\n\t\tif err := title(arg); err != nil {\n\t\t\tfmt.Fprintf(os.Stderr, \"title: %v\\n\", err)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "ch5/title3/title.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 153.\n\n// Title3 prints the title of an HTML document specified by a URL.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n\n\t\"golang.org/x/net/html\"\n)\n\n// Copied from gopl.io/ch5/outline2.\nfunc forEachNode(n *html.Node, pre, post func(n *html.Node)) {\n\tif pre != nil {\n\t\tpre(n)\n\t}\n\tfor c := n.FirstChild; c != nil; c = c.NextSibling {\n\t\tforEachNode(c, pre, post)\n\t}\n\tif post != nil {\n\t\tpost(n)\n\t}\n}\n\n//!+\n// soleTitle returns the text of the first non-empty title element\n// in doc, and an error if there was not exactly one.\nfunc soleTitle(doc *html.Node) (title string, err error) {\n\ttype bailout struct{}\n\n\tdefer func() {\n\t\tswitch p := recover(); p {\n\t\tcase nil:\n\t\t\t// no panic\n\t\tcase bailout{}:\n\t\t\t// \"expected\" panic\n\t\t\terr = fmt.Errorf(\"multiple title elements\")\n\t\tdefault:\n\t\t\tpanic(p) // unexpected panic; carry on panicking\n\t\t}\n\t}()\n\n\t// Bail out of recursion if we find more than one non-empty title.\n\tforEachNode(doc, func(n *html.Node) {\n\t\tif n.Type == html.ElementNode && n.Data == \"title\" &&\n\t\t\tn.FirstChild != nil {\n\t\t\tif title != \"\" {\n\t\t\t\tpanic(bailout{}) // multiple title elements\n\t\t\t}\n\t\t\ttitle = n.FirstChild.Data\n\t\t}\n\t}, nil)\n\tif title == \"\" {\n\t\treturn \"\", fmt.Errorf(\"no title element\")\n\t}\n\treturn title, nil\n}\n\n//!-\n\nfunc title(url string) error {\n\tresp, err := http.Get(url)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Check Content-Type is HTML (e.g., \"text/html; charset=utf-8\").\n\tct := resp.Header.Get(\"Content-Type\")\n\tif ct != \"text/html\" && !strings.HasPrefix(ct, \"text/html;\") {\n\t\tresp.Body.Close()\n\t\treturn fmt.Errorf(\"%s has type %s, not text/html\", url, ct)\n\t}\n\n\tdoc, err := html.Parse(resp.Body)\n\tresp.Body.Close()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"parsing %s as HTML: %v\", url, err)\n\t}\n\ttitle, err := soleTitle(doc)\n\tif err != nil {\n\t\treturn err\n\t}\n\tfmt.Println(title)\n\treturn nil\n}\n\nfunc main() {\n\tfor _, arg := range os.Args[1:] {\n\t\tif err := title(arg); err != nil {\n\t\t\tfmt.Fprintf(os.Stderr, \"title: %v\\n\", err)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "ch5/toposort/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 136.\n\n// The toposort program prints the nodes of a DAG in topological order.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n)\n\n//!+table\n// prereqs maps computer science courses to their prerequisites.\nvar prereqs = map[string][]string{\n\t\"algorithms\": {\"data structures\"},\n\t\"calculus\":   {\"linear algebra\"},\n\n\t\"compilers\": {\n\t\t\"data structures\",\n\t\t\"formal languages\",\n\t\t\"computer organization\",\n\t},\n\n\t\"data structures\":       {\"discrete math\"},\n\t\"databases\":             {\"data structures\"},\n\t\"discrete math\":         {\"intro to programming\"},\n\t\"formal languages\":      {\"discrete math\"},\n\t\"networks\":              {\"operating systems\"},\n\t\"operating systems\":     {\"data structures\", \"computer organization\"},\n\t\"programming languages\": {\"data structures\", \"computer organization\"},\n}\n\n//!-table\n\n//!+main\nfunc main() {\n\tfor i, course := range topoSort(prereqs) {\n\t\tfmt.Printf(\"%d:\\t%s\\n\", i+1, course)\n\t}\n}\n\nfunc topoSort(m map[string][]string) []string {\n\tvar order []string\n\tseen := make(map[string]bool)\n\tvar visitAll func(items []string)\n\n\tvisitAll = func(items []string) {\n\t\tfor _, item := range items {\n\t\t\tif !seen[item] {\n\t\t\t\tseen[item] = true\n\t\t\t\tvisitAll(m[item])\n\t\t\t\torder = append(order, item)\n\t\t\t}\n\t\t}\n\t}\n\n\tvar keys []string\n\tfor key := range m {\n\t\tkeys = append(keys, key)\n\t}\n\n\tsort.Strings(keys)\n\tvisitAll(keys)\n\treturn order\n}\n\n//!-main\n"
  },
  {
    "path": "ch5/trace/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 146.\n\n// The trace program uses defer to add entry/exit diagnostics to a function.\npackage main\n\nimport (\n\t\"log\"\n\t\"time\"\n)\n\n//!+main\nfunc bigSlowOperation() {\n\tdefer trace(\"bigSlowOperation\")() // don't forget the extra parentheses\n\t// ...lots of work...\n\ttime.Sleep(10 * time.Second) // simulate slow operation by sleeping\n}\n\nfunc trace(msg string) func() {\n\tstart := time.Now()\n\tlog.Printf(\"enter %s\", msg)\n\treturn func() { log.Printf(\"exit %s (%s)\", msg, time.Since(start)) }\n}\n\n//!-main\n\nfunc main() {\n\tbigSlowOperation()\n}\n\n/*\n!+output\n$ go build gopl.io/ch5/trace\n$ ./trace\n2015/11/18 09:53:26 enter bigSlowOperation\n2015/11/18 09:53:36 exit bigSlowOperation (10.000589217s)\n!-output\n*/\n"
  },
  {
    "path": "ch5/wait/wait.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 130.\n\n// The wait program waits for an HTTP server to start responding.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\t\"os\"\n\t\"time\"\n)\n\n//!+\n// WaitForServer attempts to contact the server of a URL.\n// It tries for one minute using exponential back-off.\n// It reports an error if all attempts fail.\nfunc WaitForServer(url string) error {\n\tconst timeout = 1 * time.Minute\n\tdeadline := time.Now().Add(timeout)\n\tfor tries := 0; time.Now().Before(deadline); tries++ {\n\t\t_, err := http.Head(url)\n\t\tif err == nil {\n\t\t\treturn nil // success\n\t\t}\n\t\tlog.Printf(\"server not responding (%s); retrying...\", err)\n\t\ttime.Sleep(time.Second << uint(tries)) // exponential back-off\n\t}\n\treturn fmt.Errorf(\"server %s failed to respond after %s\", url, timeout)\n}\n\n//!-\n\nfunc main() {\n\tif len(os.Args) != 2 {\n\t\tfmt.Fprintf(os.Stderr, \"usage: wait url\\n\")\n\t\tos.Exit(1)\n\t}\n\turl := os.Args[1]\n\t//!+main\n\t// (In function main.)\n\tif err := WaitForServer(url); err != nil {\n\t\tfmt.Fprintf(os.Stderr, \"Site is down: %v\\n\", err)\n\t\tos.Exit(1)\n\t}\n\t//!-main\n}\n"
  },
  {
    "path": "ch6/coloredpoint/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 161.\n\n// Coloredpoint demonstrates struct embedding.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"math\"\n)\n\n//!+decl\nimport \"image/color\"\n\ntype Point struct{ X, Y float64 }\n\ntype ColoredPoint struct {\n\tPoint\n\tColor color.RGBA\n}\n\n//!-decl\n\nfunc (p Point) Distance(q Point) float64 {\n\tdX := q.X - p.X\n\tdY := q.Y - p.Y\n\treturn math.Sqrt(dX*dX + dY*dY)\n}\n\nfunc (p *Point) ScaleBy(factor float64) {\n\tp.X *= factor\n\tp.Y *= factor\n}\n\nfunc main() {\n\t//!+main\n\tred := color.RGBA{255, 0, 0, 255}\n\tblue := color.RGBA{0, 0, 255, 255}\n\tvar p = ColoredPoint{Point{1, 1}, red}\n\tvar q = ColoredPoint{Point{5, 4}, blue}\n\tfmt.Println(p.Distance(q.Point)) // \"5\"\n\tp.ScaleBy(2)\n\tq.ScaleBy(2)\n\tfmt.Println(p.Distance(q.Point)) // \"10\"\n\t//!-main\n}\n\n/*\n//!+error\n\tp.Distance(q) // compile error: cannot use q (ColoredPoint) as Point\n//!-error\n*/\n\nfunc init() {\n\t//!+methodexpr\n\tp := Point{1, 2}\n\tq := Point{4, 6}\n\n\tdistance := Point.Distance   // method expression\n\tfmt.Println(distance(p, q))  // \"5\"\n\tfmt.Printf(\"%T\\n\", distance) // \"func(Point, Point) float64\"\n\n\tscale := (*Point).ScaleBy\n\tscale(&p, 2)\n\tfmt.Println(p)            // \"{2 4}\"\n\tfmt.Printf(\"%T\\n\", scale) // \"func(*Point, float64)\"\n\t//!-methodexpr\n}\n\nfunc init() {\n\tred := color.RGBA{255, 0, 0, 255}\n\tblue := color.RGBA{0, 0, 255, 255}\n\n\t//!+indirect\n\ttype ColoredPoint struct {\n\t\t*Point\n\t\tColor color.RGBA\n\t}\n\n\tp := ColoredPoint{&Point{1, 1}, red}\n\tq := ColoredPoint{&Point{5, 4}, blue}\n\tfmt.Println(p.Distance(*q.Point)) // \"5\"\n\tq.Point = p.Point                 // p and q now share the same Point\n\tp.ScaleBy(2)\n\tfmt.Println(*p.Point, *q.Point) // \"{2 2} {2 2}\"\n\t//!-indirect\n}\n"
  },
  {
    "path": "ch6/geometry/geometry.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 156.\n\n// Package geometry defines simple types for plane geometry.\n//!+point\npackage geometry\n\nimport \"math\"\n\ntype Point struct{ X, Y float64 }\n\n// traditional function\nfunc Distance(p, q Point) float64 {\n\treturn math.Hypot(q.X-p.X, q.Y-p.Y)\n}\n\n// same thing, but as a method of the Point type\nfunc (p Point) Distance(q Point) float64 {\n\treturn math.Hypot(q.X-p.X, q.Y-p.Y)\n}\n\n//!-point\n\n//!+path\n\n// A Path is a journey connecting the points with straight lines.\ntype Path []Point\n\n// Distance returns the distance traveled along the path.\nfunc (path Path) Distance() float64 {\n\tsum := 0.0\n\tfor i := range path {\n\t\tif i > 0 {\n\t\t\tsum += path[i-1].Distance(path[i])\n\t\t}\n\t}\n\treturn sum\n}\n\n//!-path\n"
  },
  {
    "path": "ch6/intset/intset.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 165.\n\n// Package intset provides a set of integers based on a bit vector.\npackage intset\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n)\n\n//!+intset\n\n// An IntSet is a set of small non-negative integers.\n// Its zero value represents the empty set.\ntype IntSet struct {\n\twords []uint64\n}\n\n// Has reports whether the set contains the non-negative value x.\nfunc (s *IntSet) Has(x int) bool {\n\tword, bit := x/64, uint(x%64)\n\treturn word < len(s.words) && s.words[word]&(1<<bit) != 0\n}\n\n// Add adds the non-negative value x to the set.\nfunc (s *IntSet) Add(x int) {\n\tword, bit := x/64, uint(x%64)\n\tfor word >= len(s.words) {\n\t\ts.words = append(s.words, 0)\n\t}\n\ts.words[word] |= 1 << bit\n}\n\n// UnionWith sets s to the union of s and t.\nfunc (s *IntSet) UnionWith(t *IntSet) {\n\tfor i, tword := range t.words {\n\t\tif i < len(s.words) {\n\t\t\ts.words[i] |= tword\n\t\t} else {\n\t\t\ts.words = append(s.words, tword)\n\t\t}\n\t}\n}\n\n//!-intset\n\n//!+string\n\n// String returns the set as a string of the form \"{1 2 3}\".\nfunc (s *IntSet) String() string {\n\tvar buf bytes.Buffer\n\tbuf.WriteByte('{')\n\tfor i, word := range s.words {\n\t\tif word == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tfor j := 0; j < 64; j++ {\n\t\t\tif word&(1<<uint(j)) != 0 {\n\t\t\t\tif buf.Len() > len(\"{\") {\n\t\t\t\t\tbuf.WriteByte(' ')\n\t\t\t\t}\n\t\t\t\tfmt.Fprintf(&buf, \"%d\", 64*i+j)\n\t\t\t}\n\t\t}\n\t}\n\tbuf.WriteByte('}')\n\treturn buf.String()\n}\n\n//!-string\n"
  },
  {
    "path": "ch6/intset/intset_test.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\npackage intset\n\nimport \"fmt\"\n\nfunc Example_one() {\n\t//!+main\n\tvar x, y IntSet\n\tx.Add(1)\n\tx.Add(144)\n\tx.Add(9)\n\tfmt.Println(x.String()) // \"{1 9 144}\"\n\n\ty.Add(9)\n\ty.Add(42)\n\tfmt.Println(y.String()) // \"{9 42}\"\n\n\tx.UnionWith(&y)\n\tfmt.Println(x.String()) // \"{1 9 42 144}\"\n\n\tfmt.Println(x.Has(9), x.Has(123)) // \"true false\"\n\t//!-main\n\n\t// Output:\n\t// {1 9 144}\n\t// {9 42}\n\t// {1 9 42 144}\n\t// true false\n}\n\nfunc Example_two() {\n\tvar x IntSet\n\tx.Add(1)\n\tx.Add(144)\n\tx.Add(9)\n\tx.Add(42)\n\n\t//!+note\n\tfmt.Println(&x)         // \"{1 9 42 144}\"\n\tfmt.Println(x.String()) // \"{1 9 42 144}\"\n\tfmt.Println(x)          // \"{[4398046511618 0 65536]}\"\n\t//!-note\n\n\t// Output:\n\t// {1 9 42 144}\n\t// {1 9 42 144}\n\t// {[4398046511618 0 65536]}\n}\n"
  },
  {
    "path": "ch6/urlvalues/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 160.\n\n// The urlvalues command demonstrates a map type with methods.\npackage main\n\n/*\n//!+values\npackage url\n\n// Values maps a string key to a list of values.\ntype Values map[string][]string\n\n// Get returns the first value associated with the given key,\n// or \"\" if there are none.\nfunc (v Values) Get(key string) string {\n\tif vs := v[key]; len(vs) > 0 {\n\t\treturn vs[0]\n\t}\n\treturn \"\"\n}\n\n// Add adds the value to key.\n// It appends to any existing values associated with key.\nfunc (v Values) Add(key, value string) {\n\tv[key] = append(v[key], value)\n}\n//!-values\n*/\n\nimport (\n\t\"fmt\"\n\t\"net/url\"\n)\n\nfunc main() {\n\t//!+main\n\tm := url.Values{\"lang\": {\"en\"}} // direct construction\n\tm.Add(\"item\", \"1\")\n\tm.Add(\"item\", \"2\")\n\n\tfmt.Println(m.Get(\"lang\")) // \"en\"\n\tfmt.Println(m.Get(\"q\"))    // \"\"\n\tfmt.Println(m.Get(\"item\")) // \"1\"      (first value)\n\tfmt.Println(m[\"item\"])     // \"[1 2]\"  (direct map access)\n\n\tm = nil\n\tfmt.Println(m.Get(\"item\")) // \"\"\n\tm.Add(\"item\", \"3\")         // panic: assignment to entry in nil map\n\t//!-main\n}\n"
  },
  {
    "path": "ch7/bytecounter/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 173.\n\n// Bytecounter demonstrates an implementation of io.Writer that counts bytes.\npackage main\n\nimport (\n\t\"fmt\"\n)\n\n//!+bytecounter\n\ntype ByteCounter int\n\nfunc (c *ByteCounter) Write(p []byte) (int, error) {\n\t*c += ByteCounter(len(p)) // convert int to ByteCounter\n\treturn len(p), nil\n}\n\n//!-bytecounter\n\nfunc main() {\n\t//!+main\n\tvar c ByteCounter\n\tc.Write([]byte(\"hello\"))\n\tfmt.Println(c) // \"5\", = len(\"hello\")\n\n\tc = 0 // reset the counter\n\tvar name = \"Dolly\"\n\tfmt.Fprintf(&c, \"hello, %s\", name)\n\tfmt.Println(c) // \"12\", = len(\"hello, Dolly\")\n\t//!-main\n}\n"
  },
  {
    "path": "ch7/eval/ast.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\npackage eval\n\n// An Expr is an arithmetic expression.\ntype Expr interface {\n\t// Eval returns the value of this Expr in the environment env.\n\tEval(env Env) float64\n\t// Check reports errors in this Expr and adds its Vars to the set.\n\tCheck(vars map[Var]bool) error\n}\n\n//!+ast\n\n// A Var identifies a variable, e.g., x.\ntype Var string\n\n// A literal is a numeric constant, e.g., 3.141.\ntype literal float64\n\n// A unary represents a unary operator expression, e.g., -x.\ntype unary struct {\n\top rune // one of '+', '-'\n\tx  Expr\n}\n\n// A binary represents a binary operator expression, e.g., x+y.\ntype binary struct {\n\top   rune // one of '+', '-', '*', '/'\n\tx, y Expr\n}\n\n// A call represents a function call expression, e.g., sin(x).\ntype call struct {\n\tfn   string // one of \"pow\", \"sin\", \"sqrt\"\n\targs []Expr\n}\n\n//!-ast\n"
  },
  {
    "path": "ch7/eval/check.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\npackage eval\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\n//!+Check\n\nfunc (v Var) Check(vars map[Var]bool) error {\n\tvars[v] = true\n\treturn nil\n}\n\nfunc (literal) Check(vars map[Var]bool) error {\n\treturn nil\n}\n\nfunc (u unary) Check(vars map[Var]bool) error {\n\tif !strings.ContainsRune(\"+-\", u.op) {\n\t\treturn fmt.Errorf(\"unexpected unary op %q\", u.op)\n\t}\n\treturn u.x.Check(vars)\n}\n\nfunc (b binary) Check(vars map[Var]bool) error {\n\tif !strings.ContainsRune(\"+-*/\", b.op) {\n\t\treturn fmt.Errorf(\"unexpected binary op %q\", b.op)\n\t}\n\tif err := b.x.Check(vars); err != nil {\n\t\treturn err\n\t}\n\treturn b.y.Check(vars)\n}\n\nfunc (c call) Check(vars map[Var]bool) error {\n\tarity, ok := numParams[c.fn]\n\tif !ok {\n\t\treturn fmt.Errorf(\"unknown function %q\", c.fn)\n\t}\n\tif len(c.args) != arity {\n\t\treturn fmt.Errorf(\"call to %s has %d args, want %d\",\n\t\t\tc.fn, len(c.args), arity)\n\t}\n\tfor _, arg := range c.args {\n\t\tif err := arg.Check(vars); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nvar numParams = map[string]int{\"pow\": 2, \"sin\": 1, \"sqrt\": 1}\n\n//!-Check\n"
  },
  {
    "path": "ch7/eval/coverage_test.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\npackage eval\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"testing\"\n)\n\n//!+TestCoverage\nfunc TestCoverage(t *testing.T) {\n\tvar tests = []struct {\n\t\tinput string\n\t\tenv   Env\n\t\twant  string // expected error from Parse/Check or result from Eval\n\t}{\n\t\t{\"x % 2\", nil, \"unexpected '%'\"},\n\t\t{\"!true\", nil, \"unexpected '!'\"},\n\t\t{\"log(10)\", nil, `unknown function \"log\"`},\n\t\t{\"sqrt(1, 2)\", nil, \"call to sqrt has 2 args, want 1\"},\n\t\t{\"sqrt(A / pi)\", Env{\"A\": 87616, \"pi\": math.Pi}, \"167\"},\n\t\t{\"pow(x, 3) + pow(y, 3)\", Env{\"x\": 9, \"y\": 10}, \"1729\"},\n\t\t{\"5 / 9 * (F - 32)\", Env{\"F\": -40}, \"-40\"},\n\t}\n\n\tfor _, test := range tests {\n\t\texpr, err := Parse(test.input)\n\t\tif err == nil {\n\t\t\terr = expr.Check(map[Var]bool{})\n\t\t}\n\t\tif err != nil {\n\t\t\tif err.Error() != test.want {\n\t\t\t\tt.Errorf(\"%s: got %q, want %q\", test.input, err, test.want)\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tgot := fmt.Sprintf(\"%.6g\", expr.Eval(test.env))\n\t\tif got != test.want {\n\t\t\tt.Errorf(\"%s: %v => %s, want %s\",\n\t\t\t\ttest.input, test.env, got, test.want)\n\t\t}\n\t}\n}\n\n//!-TestCoverage\n"
  },
  {
    "path": "ch7/eval/eval.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 198.\n\n// Package eval provides an expression evaluator.\npackage eval\n\nimport (\n\t\"fmt\"\n\t\"math\"\n)\n\n//!+env\n\ntype Env map[Var]float64\n\n//!-env\n\n//!+Eval1\n\nfunc (v Var) Eval(env Env) float64 {\n\treturn env[v]\n}\n\nfunc (l literal) Eval(_ Env) float64 {\n\treturn float64(l)\n}\n\n//!-Eval1\n\n//!+Eval2\n\nfunc (u unary) Eval(env Env) float64 {\n\tswitch u.op {\n\tcase '+':\n\t\treturn +u.x.Eval(env)\n\tcase '-':\n\t\treturn -u.x.Eval(env)\n\t}\n\tpanic(fmt.Sprintf(\"unsupported unary operator: %q\", u.op))\n}\n\nfunc (b binary) Eval(env Env) float64 {\n\tswitch b.op {\n\tcase '+':\n\t\treturn b.x.Eval(env) + b.y.Eval(env)\n\tcase '-':\n\t\treturn b.x.Eval(env) - b.y.Eval(env)\n\tcase '*':\n\t\treturn b.x.Eval(env) * b.y.Eval(env)\n\tcase '/':\n\t\treturn b.x.Eval(env) / b.y.Eval(env)\n\t}\n\tpanic(fmt.Sprintf(\"unsupported binary operator: %q\", b.op))\n}\n\nfunc (c call) Eval(env Env) float64 {\n\tswitch c.fn {\n\tcase \"pow\":\n\t\treturn math.Pow(c.args[0].Eval(env), c.args[1].Eval(env))\n\tcase \"sin\":\n\t\treturn math.Sin(c.args[0].Eval(env))\n\tcase \"sqrt\":\n\t\treturn math.Sqrt(c.args[0].Eval(env))\n\t}\n\tpanic(fmt.Sprintf(\"unsupported function call: %s\", c.fn))\n}\n\n//!-Eval2\n"
  },
  {
    "path": "ch7/eval/eval_test.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\npackage eval\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"testing\"\n)\n\n//!+Eval\nfunc TestEval(t *testing.T) {\n\ttests := []struct {\n\t\texpr string\n\t\tenv  Env\n\t\twant string\n\t}{\n\t\t{\"sqrt(A / pi)\", Env{\"A\": 87616, \"pi\": math.Pi}, \"167\"},\n\t\t{\"pow(x, 3) + pow(y, 3)\", Env{\"x\": 12, \"y\": 1}, \"1729\"},\n\t\t{\"pow(x, 3) + pow(y, 3)\", Env{\"x\": 9, \"y\": 10}, \"1729\"},\n\t\t{\"5 / 9 * (F - 32)\", Env{\"F\": -40}, \"-40\"},\n\t\t{\"5 / 9 * (F - 32)\", Env{\"F\": 32}, \"0\"},\n\t\t{\"5 / 9 * (F - 32)\", Env{\"F\": 212}, \"100\"},\n\t\t//!-Eval\n\t\t// additional tests that don't appear in the book\n\t\t{\"-1 + -x\", Env{\"x\": 1}, \"-2\"},\n\t\t{\"-1 - x\", Env{\"x\": 1}, \"-2\"},\n\t\t//!+Eval\n\t}\n\tvar prevExpr string\n\tfor _, test := range tests {\n\t\t// Print expr only when it changes.\n\t\tif test.expr != prevExpr {\n\t\t\tfmt.Printf(\"\\n%s\\n\", test.expr)\n\t\t\tprevExpr = test.expr\n\t\t}\n\t\texpr, err := Parse(test.expr)\n\t\tif err != nil {\n\t\t\tt.Error(err) // parse error\n\t\t\tcontinue\n\t\t}\n\t\tgot := fmt.Sprintf(\"%.6g\", expr.Eval(test.env))\n\t\tfmt.Printf(\"\\t%v => %s\\n\", test.env, got)\n\t\tif got != test.want {\n\t\t\tt.Errorf(\"%s.Eval() in %v = %q, want %q\\n\",\n\t\t\t\ttest.expr, test.env, got, test.want)\n\t\t}\n\t}\n}\n\n//!-Eval\n\n/*\n//!+output\nsqrt(A / pi)\n\tmap[A:87616 pi:3.141592653589793] => 167\n\npow(x, 3) + pow(y, 3)\n\tmap[x:12 y:1] => 1729\n\tmap[x:9 y:10] => 1729\n\n5 / 9 * (F - 32)\n\tmap[F:-40] => -40\n\tmap[F:32] => 0\n\tmap[F:212] => 100\n//!-output\n\n// Additional outputs that don't appear in the book.\n\n-1 - x\n\tmap[x:1] => -2\n\n-1 + -x\n\tmap[x:1] => -2\n*/\n\nfunc TestErrors(t *testing.T) {\n\tfor _, test := range []struct{ expr, wantErr string }{\n\t\t{\"x % 2\", \"unexpected '%'\"},\n\t\t{\"math.Pi\", \"unexpected '.'\"},\n\t\t{\"!true\", \"unexpected '!'\"},\n\t\t{`\"hello\"`, \"unexpected '\\\"'\"},\n\t\t{\"log(10)\", `unknown function \"log\"`},\n\t\t{\"sqrt(1, 2)\", \"call to sqrt has 2 args, want 1\"},\n\t} {\n\t\texpr, err := Parse(test.expr)\n\t\tif err == nil {\n\t\t\tvars := make(map[Var]bool)\n\t\t\terr = expr.Check(vars)\n\t\t\tif err == nil {\n\t\t\t\tt.Errorf(\"unexpected success: %s\", test.expr)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\tfmt.Printf(\"%-20s%v\\n\", test.expr, err) // (for book)\n\t\tif err.Error() != test.wantErr {\n\t\t\tt.Errorf(\"got error %s, want %s\", err, test.wantErr)\n\t\t}\n\t}\n}\n\n/*\n//!+errors\nx % 2               unexpected '%'\nmath.Pi             unexpected '.'\n!true               unexpected '!'\n\"hello\"             unexpected '\"'\n\nlog(10)             unknown function \"log\"\nsqrt(1, 2)          call to sqrt has 2 args, want 1\n//!-errors\n*/\n"
  },
  {
    "path": "ch7/eval/parse.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\npackage eval\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"text/scanner\"\n)\n\n// ---- lexer ----\n\n// This lexer is similar to the one described in Chapter 13.\ntype lexer struct {\n\tscan  scanner.Scanner\n\ttoken rune // current lookahead token\n}\n\nfunc (lex *lexer) next()        { lex.token = lex.scan.Scan() }\nfunc (lex *lexer) text() string { return lex.scan.TokenText() }\n\ntype lexPanic string\n\n// describe returns a string describing the current token, for use in errors.\nfunc (lex *lexer) describe() string {\n\tswitch lex.token {\n\tcase scanner.EOF:\n\t\treturn \"end of file\"\n\tcase scanner.Ident:\n\t\treturn fmt.Sprintf(\"identifier %s\", lex.text())\n\tcase scanner.Int, scanner.Float:\n\t\treturn fmt.Sprintf(\"number %s\", lex.text())\n\t}\n\treturn fmt.Sprintf(\"%q\", rune(lex.token)) // any other rune\n}\n\nfunc precedence(op rune) int {\n\tswitch op {\n\tcase '*', '/':\n\t\treturn 2\n\tcase '+', '-':\n\t\treturn 1\n\t}\n\treturn 0\n}\n\n// ---- parser ----\n\n// Parse parses the input string as an arithmetic expression.\n//\n//   expr = num                         a literal number, e.g., 3.14159\n//        | id                          a variable name, e.g., x\n//        | id '(' expr ',' ... ')'     a function call\n//        | '-' expr                    a unary operator (+-)\n//        | expr '+' expr               a binary operator (+-*/)\n//\nfunc Parse(input string) (_ Expr, err error) {\n\tdefer func() {\n\t\tswitch x := recover().(type) {\n\t\tcase nil:\n\t\t\t// no panic\n\t\tcase lexPanic:\n\t\t\terr = fmt.Errorf(\"%s\", x)\n\t\tdefault:\n\t\t\t// unexpected panic: resume state of panic.\n\t\t\tpanic(x)\n\t\t}\n\t}()\n\tlex := new(lexer)\n\tlex.scan.Init(strings.NewReader(input))\n\tlex.scan.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanFloats\n\tlex.next() // initial lookahead\n\te := parseExpr(lex)\n\tif lex.token != scanner.EOF {\n\t\treturn nil, fmt.Errorf(\"unexpected %s\", lex.describe())\n\t}\n\treturn e, nil\n}\n\nfunc parseExpr(lex *lexer) Expr { return parseBinary(lex, 1) }\n\n// binary = unary ('+' binary)*\n// parseBinary stops when it encounters an\n// operator of lower precedence than prec1.\nfunc parseBinary(lex *lexer, prec1 int) Expr {\n\tlhs := parseUnary(lex)\n\tfor prec := precedence(lex.token); prec >= prec1; prec-- {\n\t\tfor precedence(lex.token) == prec {\n\t\t\top := lex.token\n\t\t\tlex.next() // consume operator\n\t\t\trhs := parseBinary(lex, prec+1)\n\t\t\tlhs = binary{op, lhs, rhs}\n\t\t}\n\t}\n\treturn lhs\n}\n\n// unary = '+' expr | primary\nfunc parseUnary(lex *lexer) Expr {\n\tif lex.token == '+' || lex.token == '-' {\n\t\top := lex.token\n\t\tlex.next() // consume '+' or '-'\n\t\treturn unary{op, parseUnary(lex)}\n\t}\n\treturn parsePrimary(lex)\n}\n\n// primary = id\n//         | id '(' expr ',' ... ',' expr ')'\n//         | num\n//         | '(' expr ')'\nfunc parsePrimary(lex *lexer) Expr {\n\tswitch lex.token {\n\tcase scanner.Ident:\n\t\tid := lex.text()\n\t\tlex.next() // consume Ident\n\t\tif lex.token != '(' {\n\t\t\treturn Var(id)\n\t\t}\n\t\tlex.next() // consume '('\n\t\tvar args []Expr\n\t\tif lex.token != ')' {\n\t\t\tfor {\n\t\t\t\targs = append(args, parseExpr(lex))\n\t\t\t\tif lex.token != ',' {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tlex.next() // consume ','\n\t\t\t}\n\t\t\tif lex.token != ')' {\n\t\t\t\tmsg := fmt.Sprintf(\"got %s, want ')'\", lex.describe())\n\t\t\t\tpanic(lexPanic(msg))\n\t\t\t}\n\t\t}\n\t\tlex.next() // consume ')'\n\t\treturn call{id, args}\n\n\tcase scanner.Int, scanner.Float:\n\t\tf, err := strconv.ParseFloat(lex.text(), 64)\n\t\tif err != nil {\n\t\t\tpanic(lexPanic(err.Error()))\n\t\t}\n\t\tlex.next() // consume number\n\t\treturn literal(f)\n\n\tcase '(':\n\t\tlex.next() // consume '('\n\t\te := parseExpr(lex)\n\t\tif lex.token != ')' {\n\t\t\tmsg := fmt.Sprintf(\"got %s, want ')'\", lex.describe())\n\t\t\tpanic(lexPanic(msg))\n\t\t}\n\t\tlex.next() // consume ')'\n\t\treturn e\n\t}\n\tmsg := fmt.Sprintf(\"unexpected %s\", lex.describe())\n\tpanic(lexPanic(msg))\n}\n"
  },
  {
    "path": "ch7/eval/print.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\npackage eval\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n)\n\n// Format formats an expression as a string.\n// It does not attempt to remove unnecessary parens.\nfunc Format(e Expr) string {\n\tvar buf bytes.Buffer\n\twrite(&buf, e)\n\treturn buf.String()\n}\n\nfunc write(buf *bytes.Buffer, e Expr) {\n\tswitch e := e.(type) {\n\tcase literal:\n\t\tfmt.Fprintf(buf, \"%g\", e)\n\n\tcase Var:\n\t\tfmt.Fprintf(buf, \"%s\", e)\n\n\tcase unary:\n\t\tfmt.Fprintf(buf, \"(%c\", e.op)\n\t\twrite(buf, e.x)\n\t\tbuf.WriteByte(')')\n\n\tcase binary:\n\t\tbuf.WriteByte('(')\n\t\twrite(buf, e.x)\n\t\tfmt.Fprintf(buf, \" %c \", e.op)\n\t\twrite(buf, e.y)\n\t\tbuf.WriteByte(')')\n\n\tcase call:\n\t\tfmt.Fprintf(buf, \"%s(\", e.fn)\n\t\tfor i, arg := range e.args {\n\t\t\tif i > 0 {\n\t\t\t\tbuf.WriteString(\", \")\n\t\t\t}\n\t\t\twrite(buf, arg)\n\t\t}\n\t\tbuf.WriteByte(')')\n\n\tdefault:\n\t\tpanic(fmt.Sprintf(\"unknown Expr: %T\", e))\n\t}\n}\n"
  },
  {
    "path": "ch7/http1/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 191.\n\n// Http1 is a rudimentary e-commerce server.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n)\n\n//!+main\n\nfunc main() {\n\tdb := database{\"shoes\": 50, \"socks\": 5}\n\tlog.Fatal(http.ListenAndServe(\"localhost:8000\", db))\n}\n\ntype dollars float32\n\nfunc (d dollars) String() string { return fmt.Sprintf(\"$%.2f\", d) }\n\ntype database map[string]dollars\n\nfunc (db database) ServeHTTP(w http.ResponseWriter, req *http.Request) {\n\tfor item, price := range db {\n\t\tfmt.Fprintf(w, \"%s: %s\\n\", item, price)\n\t}\n}\n\n//!-main\n\n/*\n//!+handler\npackage http\n\ntype Handler interface {\n\tServeHTTP(w ResponseWriter, r *Request)\n}\n\nfunc ListenAndServe(address string, h Handler) error\n//!-handler\n*/\n"
  },
  {
    "path": "ch7/http2/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 192.\n\n// Http2 is an e-commerce server with /list and /price endpoints.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n)\n\nfunc main() {\n\tdb := database{\"shoes\": 50, \"socks\": 5}\n\tlog.Fatal(http.ListenAndServe(\"localhost:8000\", db))\n}\n\ntype dollars float32\n\nfunc (d dollars) String() string { return fmt.Sprintf(\"$%.2f\", d) }\n\ntype database map[string]dollars\n\n//!+handler\nfunc (db database) ServeHTTP(w http.ResponseWriter, req *http.Request) {\n\tswitch req.URL.Path {\n\tcase \"/list\":\n\t\tfor item, price := range db {\n\t\t\tfmt.Fprintf(w, \"%s: %s\\n\", item, price)\n\t\t}\n\tcase \"/price\":\n\t\titem := req.URL.Query().Get(\"item\")\n\t\tprice, ok := db[item]\n\t\tif !ok {\n\t\t\tw.WriteHeader(http.StatusNotFound) // 404\n\t\t\tfmt.Fprintf(w, \"no such item: %q\\n\", item)\n\t\t\treturn\n\t\t}\n\t\tfmt.Fprintf(w, \"%s\\n\", price)\n\tdefault:\n\t\tw.WriteHeader(http.StatusNotFound) // 404\n\t\tfmt.Fprintf(w, \"no such page: %s\\n\", req.URL)\n\t}\n}\n\n//!-handler\n"
  },
  {
    "path": "ch7/http3/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 194.\n\n// Http3 is an e-commerce server that registers the /list and /price\n// endpoints by calling (*http.ServeMux).Handle.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n)\n\ntype dollars float32\n\nfunc (d dollars) String() string { return fmt.Sprintf(\"$%.2f\", d) }\n\n//!+main\n\nfunc main() {\n\tdb := database{\"shoes\": 50, \"socks\": 5}\n\tmux := http.NewServeMux()\n\tmux.Handle(\"/list\", http.HandlerFunc(db.list))\n\tmux.Handle(\"/price\", http.HandlerFunc(db.price))\n\tlog.Fatal(http.ListenAndServe(\"localhost:8000\", mux))\n}\n\ntype database map[string]dollars\n\nfunc (db database) list(w http.ResponseWriter, req *http.Request) {\n\tfor item, price := range db {\n\t\tfmt.Fprintf(w, \"%s: %s\\n\", item, price)\n\t}\n}\n\nfunc (db database) price(w http.ResponseWriter, req *http.Request) {\n\titem := req.URL.Query().Get(\"item\")\n\tprice, ok := db[item]\n\tif !ok {\n\t\tw.WriteHeader(http.StatusNotFound) // 404\n\t\tfmt.Fprintf(w, \"no such item: %q\\n\", item)\n\t\treturn\n\t}\n\tfmt.Fprintf(w, \"%s\\n\", price)\n}\n\n//!-main\n\n/*\n//!+handlerfunc\npackage http\n\ntype HandlerFunc func(w ResponseWriter, r *Request)\n\nfunc (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {\n\tf(w, r)\n}\n//!-handlerfunc\n*/\n"
  },
  {
    "path": "ch7/http3a/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 195.\n\n// Http3a is an e-commerce server that registers the /list and /price\n// endpoints by calling (*http.ServeMux).HandleFunc.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n)\n\nfunc main() {\n\tdb := database{\"shoes\": 50, \"socks\": 5}\n\tmux := http.NewServeMux()\n\t//!+main\n\tmux.HandleFunc(\"/list\", db.list)\n\tmux.HandleFunc(\"/price\", db.price)\n\t//!-main\n\tlog.Fatal(http.ListenAndServe(\"localhost:8000\", mux))\n}\n\ntype database map[string]int\n\nfunc (db database) list(w http.ResponseWriter, req *http.Request) {\n\tfor item, price := range db {\n\t\tfmt.Fprintf(w, \"%s: $%d\\n\", item, price)\n\t}\n}\n\nfunc (db database) price(w http.ResponseWriter, req *http.Request) {\n\titem := req.URL.Query().Get(\"item\")\n\tif price, ok := db[item]; ok {\n\t\tfmt.Fprintf(w, \"$%d\\n\", price)\n\t} else {\n\t\tw.WriteHeader(http.StatusNotFound) // 404\n\t\tfmt.Fprintf(w, \"no such item: %q\\n\", item)\n\t}\n}\n\n/*\n//!+handlerfunc\npackage http\n\ntype HandlerFunc func(w ResponseWriter, r *Request)\n\nfunc (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {\n\tf(w, r)\n}\n//!-handlerfunc\n*/\n"
  },
  {
    "path": "ch7/http4/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 195.\n\n// Http4 is an e-commerce server that registers the /list and /price\n// endpoint by calling http.HandleFunc.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n)\n\n//!+main\n\nfunc main() {\n\tdb := database{\"shoes\": 50, \"socks\": 5}\n\thttp.HandleFunc(\"/list\", db.list)\n\thttp.HandleFunc(\"/price\", db.price)\n\tlog.Fatal(http.ListenAndServe(\"localhost:8000\", nil))\n}\n\n//!-main\n\ntype dollars float32\n\nfunc (d dollars) String() string { return fmt.Sprintf(\"$%.2f\", d) }\n\ntype database map[string]dollars\n\nfunc (db database) list(w http.ResponseWriter, req *http.Request) {\n\tfor item, price := range db {\n\t\tfmt.Fprintf(w, \"%s: %s\\n\", item, price)\n\t}\n}\n\nfunc (db database) price(w http.ResponseWriter, req *http.Request) {\n\titem := req.URL.Query().Get(\"item\")\n\tif price, ok := db[item]; ok {\n\t\tfmt.Fprintf(w, \"%s\\n\", price)\n\t} else {\n\t\tw.WriteHeader(http.StatusNotFound) // 404\n\t\tfmt.Fprintf(w, \"no such item: %q\\n\", item)\n\t}\n}\n"
  },
  {
    "path": "ch7/sleep/sleep.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 179.\n\n// The sleep program sleeps for a specified period of time.\npackage main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"time\"\n)\n\n//!+sleep\nvar period = flag.Duration(\"period\", 1*time.Second, \"sleep period\")\n\nfunc main() {\n\tflag.Parse()\n\tfmt.Printf(\"Sleeping for %v...\", *period)\n\ttime.Sleep(*period)\n\tfmt.Println()\n}\n\n//!-sleep\n"
  },
  {
    "path": "ch7/sorting/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 187.\n\n// Sorting sorts a music playlist into a variety of orders.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"sort\"\n\t\"text/tabwriter\"\n\t\"time\"\n)\n\n//!+main\ntype Track struct {\n\tTitle  string\n\tArtist string\n\tAlbum  string\n\tYear   int\n\tLength time.Duration\n}\n\nvar tracks = []*Track{\n\t{\"Go\", \"Delilah\", \"From the Roots Up\", 2012, length(\"3m38s\")},\n\t{\"Go\", \"Moby\", \"Moby\", 1992, length(\"3m37s\")},\n\t{\"Go Ahead\", \"Alicia Keys\", \"As I Am\", 2007, length(\"4m36s\")},\n\t{\"Ready 2 Go\", \"Martin Solveig\", \"Smash\", 2011, length(\"4m24s\")},\n}\n\nfunc length(s string) time.Duration {\n\td, err := time.ParseDuration(s)\n\tif err != nil {\n\t\tpanic(s)\n\t}\n\treturn d\n}\n\n//!-main\n\n//!+printTracks\nfunc printTracks(tracks []*Track) {\n\tconst format = \"%v\\t%v\\t%v\\t%v\\t%v\\t\\n\"\n\ttw := new(tabwriter.Writer).Init(os.Stdout, 0, 8, 2, ' ', 0)\n\tfmt.Fprintf(tw, format, \"Title\", \"Artist\", \"Album\", \"Year\", \"Length\")\n\tfmt.Fprintf(tw, format, \"-----\", \"------\", \"-----\", \"----\", \"------\")\n\tfor _, t := range tracks {\n\t\tfmt.Fprintf(tw, format, t.Title, t.Artist, t.Album, t.Year, t.Length)\n\t}\n\ttw.Flush() // calculate column widths and print table\n}\n\n//!-printTracks\n\n//!+artistcode\ntype byArtist []*Track\n\nfunc (x byArtist) Len() int           { return len(x) }\nfunc (x byArtist) Less(i, j int) bool { return x[i].Artist < x[j].Artist }\nfunc (x byArtist) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }\n\n//!-artistcode\n\n//!+yearcode\ntype byYear []*Track\n\nfunc (x byYear) Len() int           { return len(x) }\nfunc (x byYear) Less(i, j int) bool { return x[i].Year < x[j].Year }\nfunc (x byYear) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }\n\n//!-yearcode\n\nfunc main() {\n\tfmt.Println(\"byArtist:\")\n\tsort.Sort(byArtist(tracks))\n\tprintTracks(tracks)\n\n\tfmt.Println(\"\\nReverse(byArtist):\")\n\tsort.Sort(sort.Reverse(byArtist(tracks)))\n\tprintTracks(tracks)\n\n\tfmt.Println(\"\\nbyYear:\")\n\tsort.Sort(byYear(tracks))\n\tprintTracks(tracks)\n\n\tfmt.Println(\"\\nCustom:\")\n\t//!+customcall\n\tsort.Sort(customSort{tracks, func(x, y *Track) bool {\n\t\tif x.Title != y.Title {\n\t\t\treturn x.Title < y.Title\n\t\t}\n\t\tif x.Year != y.Year {\n\t\t\treturn x.Year < y.Year\n\t\t}\n\t\tif x.Length != y.Length {\n\t\t\treturn x.Length < y.Length\n\t\t}\n\t\treturn false\n\t}})\n\t//!-customcall\n\tprintTracks(tracks)\n}\n\n/*\n//!+artistoutput\nTitle       Artist          Album              Year  Length\n-----       ------          -----              ----  ------\nGo Ahead    Alicia Keys     As I Am            2007  4m36s\nGo          Delilah         From the Roots Up  2012  3m38s\nReady 2 Go  Martin Solveig  Smash              2011  4m24s\nGo          Moby            Moby               1992  3m37s\n//!-artistoutput\n\n//!+artistrevoutput\nTitle       Artist          Album              Year  Length\n-----       ------          -----              ----  ------\nGo          Moby            Moby               1992  3m37s\nReady 2 Go  Martin Solveig  Smash              2011  4m24s\nGo          Delilah         From the Roots Up  2012  3m38s\nGo Ahead    Alicia Keys     As I Am            2007  4m36s\n//!-artistrevoutput\n\n//!+yearoutput\nTitle       Artist          Album              Year  Length\n-----       ------          -----              ----  ------\nGo          Moby            Moby               1992  3m37s\nGo Ahead    Alicia Keys     As I Am            2007  4m36s\nReady 2 Go  Martin Solveig  Smash              2011  4m24s\nGo          Delilah         From the Roots Up  2012  3m38s\n//!-yearoutput\n\n//!+customout\nTitle       Artist          Album              Year  Length\n-----       ------          -----              ----  ------\nGo          Moby            Moby               1992  3m37s\nGo          Delilah         From the Roots Up  2012  3m38s\nGo Ahead    Alicia Keys     As I Am            2007  4m36s\nReady 2 Go  Martin Solveig  Smash              2011  4m24s\n//!-customout\n*/\n\n//!+customcode\ntype customSort struct {\n\tt    []*Track\n\tless func(x, y *Track) bool\n}\n\nfunc (x customSort) Len() int           { return len(x.t) }\nfunc (x customSort) Less(i, j int) bool { return x.less(x.t[i], x.t[j]) }\nfunc (x customSort) Swap(i, j int)      { x.t[i], x.t[j] = x.t[j], x.t[i] }\n\n//!-customcode\n\nfunc init() {\n\t//!+ints\n\tvalues := []int{3, 1, 4, 1}\n\tfmt.Println(sort.IntsAreSorted(values)) // \"false\"\n\tsort.Ints(values)\n\tfmt.Println(values)                     // \"[1 1 3 4]\"\n\tfmt.Println(sort.IntsAreSorted(values)) // \"true\"\n\tsort.Sort(sort.Reverse(sort.IntSlice(values)))\n\tfmt.Println(values)                     // \"[4 3 1 1]\"\n\tfmt.Println(sort.IntsAreSorted(values)) // \"false\"\n\t//!-ints\n}\n"
  },
  {
    "path": "ch7/surface/surface.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 203.\n\n// The surface program plots the 3-D surface of a user-provided function.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"math\"\n\t\"net/http\"\n)\n\n//!+parseAndCheck\nimport \"gopl.io/ch7/eval\"\n\n//!-parseAndCheck\n\n// -- copied from gopl.io/ch3/surface --\n\nconst (\n\twidth, height = 600, 320            // canvas size in pixels\n\tcells         = 100                 // number of grid cells\n\txyrange       = 30.0                // x, y axis range (-xyrange..+xyrange)\n\txyscale       = width / 2 / xyrange // pixels per x or y unit\n\tzscale        = height * 0.4        // pixels per z unit\n)\n\nvar sin30, cos30 = 0.5, math.Sqrt(3.0 / 4.0) // sin(30°), cos(30°)\n\nfunc corner(f func(x, y float64) float64, i, j int) (float64, float64) {\n\t// find point (x,y) at corner of cell (i,j)\n\tx := xyrange * (float64(i)/cells - 0.5)\n\ty := xyrange * (float64(j)/cells - 0.5)\n\n\tz := f(x, y) // compute surface height z\n\n\t// project (x,y,z) isometrically onto 2-D SVG canvas (sx,sy)\n\tsx := width/2 + (x-y)*cos30*xyscale\n\tsy := height/2 + (x+y)*sin30*xyscale - z*zscale\n\treturn sx, sy\n}\n\nfunc surface(w io.Writer, f func(x, y float64) float64) {\n\tfmt.Fprintf(w, \"<svg xmlns='http://www.w3.org/2000/svg' \"+\n\t\t\"style='stroke: grey; fill: white; stroke-width: 0.7' \"+\n\t\t\"width='%d' height='%d'>\", width, height)\n\tfor i := 0; i < cells; i++ {\n\t\tfor j := 0; j < cells; j++ {\n\t\t\tax, ay := corner(f, i+1, j)\n\t\t\tbx, by := corner(f, i, j)\n\t\t\tcx, cy := corner(f, i, j+1)\n\t\t\tdx, dy := corner(f, i+1, j+1)\n\t\t\tfmt.Fprintf(w, \"<polygon points='%g,%g %g,%g %g,%g %g,%g'/>\\n\",\n\t\t\t\tax, ay, bx, by, cx, cy, dx, dy)\n\t\t}\n\t}\n\tfmt.Fprintln(w, \"</svg>\")\n}\n\n// -- main code for gopl.io/ch7/surface --\n\n//!+parseAndCheck\nfunc parseAndCheck(s string) (eval.Expr, error) {\n\tif s == \"\" {\n\t\treturn nil, fmt.Errorf(\"empty expression\")\n\t}\n\texpr, err := eval.Parse(s)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvars := make(map[eval.Var]bool)\n\tif err := expr.Check(vars); err != nil {\n\t\treturn nil, err\n\t}\n\tfor v := range vars {\n\t\tif v != \"x\" && v != \"y\" && v != \"r\" {\n\t\t\treturn nil, fmt.Errorf(\"undefined variable: %s\", v)\n\t\t}\n\t}\n\treturn expr, nil\n}\n\n//!-parseAndCheck\n\n//!+plot\nfunc plot(w http.ResponseWriter, r *http.Request) {\n\tr.ParseForm()\n\texpr, err := parseAndCheck(r.Form.Get(\"expr\"))\n\tif err != nil {\n\t\thttp.Error(w, \"bad expr: \"+err.Error(), http.StatusBadRequest)\n\t\treturn\n\t}\n\tw.Header().Set(\"Content-Type\", \"image/svg+xml\")\n\tsurface(w, func(x, y float64) float64 {\n\t\tr := math.Hypot(x, y) // distance from (0,0)\n\t\treturn expr.Eval(eval.Env{\"x\": x, \"y\": y, \"r\": r})\n\t})\n}\n\n//!-plot\n\n//!+main\nfunc main() {\n\thttp.HandleFunc(\"/plot\", plot)\n\tlog.Fatal(http.ListenAndServe(\"localhost:8000\", nil))\n}\n\n//!-main\n"
  },
  {
    "path": "ch7/tempconv/tempconv.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 180.\n\n// Package tempconv performs Celsius and Fahrenheit temperature computations.\npackage tempconv\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n)\n\ntype Celsius float64\ntype Fahrenheit float64\n\nfunc CToF(c Celsius) Fahrenheit { return Fahrenheit(c*9.0/5.0 + 32.0) }\nfunc FToC(f Fahrenheit) Celsius { return Celsius((f - 32.0) * 5.0 / 9.0) }\n\nfunc (c Celsius) String() string { return fmt.Sprintf(\"%g°C\", c) }\n\n/*\n//!+flagvalue\npackage flag\n\n// Value is the interface to the value stored in a flag.\ntype Value interface {\n\tString() string\n\tSet(string) error\n}\n//!-flagvalue\n*/\n\n//!+celsiusFlag\n// *celsiusFlag satisfies the flag.Value interface.\ntype celsiusFlag struct{ Celsius }\n\nfunc (f *celsiusFlag) Set(s string) error {\n\tvar unit string\n\tvar value float64\n\tfmt.Sscanf(s, \"%f%s\", &value, &unit) // no error check needed\n\tswitch unit {\n\tcase \"C\", \"°C\":\n\t\tf.Celsius = Celsius(value)\n\t\treturn nil\n\tcase \"F\", \"°F\":\n\t\tf.Celsius = FToC(Fahrenheit(value))\n\t\treturn nil\n\t}\n\treturn fmt.Errorf(\"invalid temperature %q\", s)\n}\n\n//!-celsiusFlag\n\n//!+CelsiusFlag\n\n// CelsiusFlag defines a Celsius flag with the specified name,\n// default value, and usage, and returns the address of the flag variable.\n// The flag argument must have a quantity and a unit, e.g., \"100C\".\nfunc CelsiusFlag(name string, value Celsius, usage string) *Celsius {\n\tf := celsiusFlag{value}\n\tflag.CommandLine.Var(&f, name, usage)\n\treturn &f.Celsius\n}\n\n//!-CelsiusFlag\n"
  },
  {
    "path": "ch7/tempconv/tempconv.go.~master~",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n\n// Package tempconv performs Celsius and Fahrenheit temperature computations.\npackage tempconv\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n)\n\ntype Celsius float64\ntype Fahrenheit float64\n\nfunc CToF(c Celsius) Fahrenheit { return Fahrenheit(c*9.0/5.0 + 32.0) }\nfunc FToC(f Fahrenheit) Celsius { return Celsius((f - 32.0) * 5.0 / 9.0) }\n\nfunc (c Celsius) String() string { return fmt.Sprintf(\"%g°C\", c) }\n\n/*\n//!+flagvalue\npackage flag\n\n// Value is the interface to the value stored in a flag.\ntype Value interface {\n\tString() string\n\tSet(string) error\n}\n//!-flagvalue\n*/\n\n//!+celsiusflag\n// *celsiusFlag satisfies the flag.Value interface.\ntype celsiusFlag struct{ Celsius }\n\nfunc (f *celsiusFlag) Set(s string) error {\n\tvar unit string\n\tvar value float64\n\tfmt.Sscanf(s, \"%f%s\", &value, &unit) // no error check needed\n\tswitch unit {\n\tcase \"C\", \"°C\":\n\t\tf.Celsius = Celsius(value)\n\t\treturn nil\n\tcase \"F\", \"°F\":\n\t\tf.Celsius = FToC(Fahrenheit(value))\n\t\treturn nil\n\t}\n\treturn fmt.Errorf(\"invalid temperature %q\", s)\n}\n\n//!-celsiusflag\n\n//!+Celsiusflag\n// CelsiusFlag defines a Celsius flag with the specified name,\n// default value, and usage, and returns the address of the flag variable.\n// The flag argument must have a quantity and a unit, e.g., \"100C\".\nfunc CelsiusFlag(name string, value Celsius, usage string) *Celsius {\n\tf := celsiusFlag{value}\n\tflag.CommandLine.Var(&f, name, usage)\n\treturn &f.Celsius\n}\n\n//!-Celsiusflag\n"
  },
  {
    "path": "ch7/tempflag/tempflag.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 181.\n\n// Tempflag prints the value of its -temp (temperature) flag.\npackage main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\n\t\"gopl.io/ch7/tempconv\"\n)\n\n//!+\nvar temp = tempconv.CelsiusFlag(\"temp\", 20.0, \"the temperature\")\n\nfunc main() {\n\tflag.Parse()\n\tfmt.Println(*temp)\n}\n\n//!-\n"
  },
  {
    "path": "ch7/xmlselect/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 214.\n//!+\n\n// Xmlselect prints the text of selected elements of an XML document.\npackage main\n\nimport (\n\t\"encoding/xml\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\tdec := xml.NewDecoder(os.Stdin)\n\tvar stack []string // stack of element names\n\tfor {\n\t\ttok, err := dec.Token()\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t} else if err != nil {\n\t\t\tfmt.Fprintf(os.Stderr, \"xmlselect: %v\\n\", err)\n\t\t\tos.Exit(1)\n\t\t}\n\t\tswitch tok := tok.(type) {\n\t\tcase xml.StartElement:\n\t\t\tstack = append(stack, tok.Name.Local) // push\n\t\tcase xml.EndElement:\n\t\t\tstack = stack[:len(stack)-1] // pop\n\t\tcase xml.CharData:\n\t\t\tif containsAll(stack, os.Args[1:]) {\n\t\t\t\tfmt.Printf(\"%s: %s\\n\", strings.Join(stack, \" \"), tok)\n\t\t\t}\n\t\t}\n\t}\n}\n\n// containsAll reports whether x contains the elements of y, in order.\nfunc containsAll(x, y []string) bool {\n\tfor len(y) <= len(x) {\n\t\tif len(y) == 0 {\n\t\t\treturn true\n\t\t}\n\t\tif x[0] == y[0] {\n\t\t\ty = y[1:]\n\t\t}\n\t\tx = x[1:]\n\t}\n\treturn false\n}\n\n//!-\n"
  },
  {
    "path": "ch8/cake/cake.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 234.\n\n// Package cake provides a simulation of\n// a concurrent cake shop with numerous parameters.\n//\n// Use this command to run the benchmarks:\n// \t$ go test -bench=. gopl.io/ch8/cake\npackage cake\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"time\"\n)\n\ntype Shop struct {\n\tVerbose        bool\n\tCakes          int           // number of cakes to bake\n\tBakeTime       time.Duration // time to bake one cake\n\tBakeStdDev     time.Duration // standard deviation of baking time\n\tBakeBuf        int           // buffer slots between baking and icing\n\tNumIcers       int           // number of cooks doing icing\n\tIceTime        time.Duration // time to ice one cake\n\tIceStdDev      time.Duration // standard deviation of icing time\n\tIceBuf         int           // buffer slots between icing and inscribing\n\tInscribeTime   time.Duration // time to inscribe one cake\n\tInscribeStdDev time.Duration // standard deviation of inscribing time\n}\n\ntype cake int\n\nfunc (s *Shop) baker(baked chan<- cake) {\n\tfor i := 0; i < s.Cakes; i++ {\n\t\tc := cake(i)\n\t\tif s.Verbose {\n\t\t\tfmt.Println(\"baking\", c)\n\t\t}\n\t\twork(s.BakeTime, s.BakeStdDev)\n\t\tbaked <- c\n\t}\n\tclose(baked)\n}\n\nfunc (s *Shop) icer(iced chan<- cake, baked <-chan cake) {\n\tfor c := range baked {\n\t\tif s.Verbose {\n\t\t\tfmt.Println(\"icing\", c)\n\t\t}\n\t\twork(s.IceTime, s.IceStdDev)\n\t\ticed <- c\n\t}\n}\n\nfunc (s *Shop) inscriber(iced <-chan cake) {\n\tfor i := 0; i < s.Cakes; i++ {\n\t\tc := <-iced\n\t\tif s.Verbose {\n\t\t\tfmt.Println(\"inscribing\", c)\n\t\t}\n\t\twork(s.InscribeTime, s.InscribeStdDev)\n\t\tif s.Verbose {\n\t\t\tfmt.Println(\"finished\", c)\n\t\t}\n\t}\n}\n\n// Work runs the simulation 'runs' times.\nfunc (s *Shop) Work(runs int) {\n\tfor run := 0; run < runs; run++ {\n\t\tbaked := make(chan cake, s.BakeBuf)\n\t\ticed := make(chan cake, s.IceBuf)\n\t\tgo s.baker(baked)\n\t\tfor i := 0; i < s.NumIcers; i++ {\n\t\t\tgo s.icer(iced, baked)\n\t\t}\n\t\ts.inscriber(iced)\n\t}\n}\n\n// work blocks the calling goroutine for a period of time\n// that is normally distributed around d\n// with a standard deviation of stddev.\nfunc work(d, stddev time.Duration) {\n\tdelay := d + time.Duration(rand.NormFloat64()*float64(stddev))\n\ttime.Sleep(delay)\n}\n"
  },
  {
    "path": "ch8/cake/cake_test.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\npackage cake_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"gopl.io/ch8/cake\"\n)\n\nvar defaults = cake.Shop{\n\tVerbose:      testing.Verbose(),\n\tCakes:        20,\n\tBakeTime:     10 * time.Millisecond,\n\tNumIcers:     1,\n\tIceTime:      10 * time.Millisecond,\n\tInscribeTime: 10 * time.Millisecond,\n}\n\nfunc Benchmark(b *testing.B) {\n\t// Baseline: one baker, one icer, one inscriber.\n\t// Each step takes exactly 10ms.  No buffers.\n\tcakeshop := defaults\n\tcakeshop.Work(b.N) // 224 ms\n}\n\nfunc BenchmarkBuffers(b *testing.B) {\n\t// Adding buffers has no effect.\n\tcakeshop := defaults\n\tcakeshop.BakeBuf = 10\n\tcakeshop.IceBuf = 10\n\tcakeshop.Work(b.N) // 224 ms\n}\n\nfunc BenchmarkVariable(b *testing.B) {\n\t// Adding variability to rate of each step\n\t// increases total time due to channel delays.\n\tcakeshop := defaults\n\tcakeshop.BakeStdDev = cakeshop.BakeTime / 4\n\tcakeshop.IceStdDev = cakeshop.IceTime / 4\n\tcakeshop.InscribeStdDev = cakeshop.InscribeTime / 4\n\tcakeshop.Work(b.N) // 259 ms\n}\n\nfunc BenchmarkVariableBuffers(b *testing.B) {\n\t// Adding channel buffers reduces\n\t// delays resulting from variability.\n\tcakeshop := defaults\n\tcakeshop.BakeStdDev = cakeshop.BakeTime / 4\n\tcakeshop.IceStdDev = cakeshop.IceTime / 4\n\tcakeshop.InscribeStdDev = cakeshop.InscribeTime / 4\n\tcakeshop.BakeBuf = 10\n\tcakeshop.IceBuf = 10\n\tcakeshop.Work(b.N) // 244 ms\n}\n\nfunc BenchmarkSlowIcing(b *testing.B) {\n\t// Making the middle stage slower\n\t// adds directly to the critical path.\n\tcakeshop := defaults\n\tcakeshop.IceTime = 50 * time.Millisecond\n\tcakeshop.Work(b.N) // 1.032 s\n}\n\nfunc BenchmarkSlowIcingManyIcers(b *testing.B) {\n\t// Adding more icing cooks reduces the cost of icing\n\t// to its sequential component, following Amdahl's Law.\n\tcakeshop := defaults\n\tcakeshop.IceTime = 50 * time.Millisecond\n\tcakeshop.NumIcers = 5\n\tcakeshop.Work(b.N) // 288ms\n}\n"
  },
  {
    "path": "ch8/chat/chat.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 254.\n//!+\n\n// Chat is a server that lets clients chat with each other.\npackage main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n)\n\n//!+broadcaster\ntype client chan<- string // an outgoing message channel\n\nvar (\n\tentering = make(chan client)\n\tleaving  = make(chan client)\n\tmessages = make(chan string) // all incoming client messages\n)\n\nfunc broadcaster() {\n\tclients := make(map[client]bool) // all connected clients\n\tfor {\n\t\tselect {\n\t\tcase msg := <-messages:\n\t\t\t// Broadcast incoming message to all\n\t\t\t// clients' outgoing message channels.\n\t\t\tfor cli := range clients {\n\t\t\t\tcli <- msg\n\t\t\t}\n\n\t\tcase cli := <-entering:\n\t\t\tclients[cli] = true\n\n\t\tcase cli := <-leaving:\n\t\t\tdelete(clients, cli)\n\t\t\tclose(cli)\n\t\t}\n\t}\n}\n\n//!-broadcaster\n\n//!+handleConn\nfunc handleConn(conn net.Conn) {\n\tch := make(chan string) // outgoing client messages\n\tgo clientWriter(conn, ch)\n\n\twho := conn.RemoteAddr().String()\n\tch <- \"You are \" + who\n\tmessages <- who + \" has arrived\"\n\tentering <- ch\n\n\tinput := bufio.NewScanner(conn)\n\tfor input.Scan() {\n\t\tmessages <- who + \": \" + input.Text()\n\t}\n\t// NOTE: ignoring potential errors from input.Err()\n\n\tleaving <- ch\n\tmessages <- who + \" has left\"\n\tconn.Close()\n}\n\nfunc clientWriter(conn net.Conn, ch <-chan string) {\n\tfor msg := range ch {\n\t\tfmt.Fprintln(conn, msg) // NOTE: ignoring network errors\n\t}\n}\n\n//!-handleConn\n\n//!+main\nfunc main() {\n\tlistener, err := net.Listen(\"tcp\", \"localhost:8000\")\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\tgo broadcaster()\n\tfor {\n\t\tconn, err := listener.Accept()\n\t\tif err != nil {\n\t\t\tlog.Print(err)\n\t\t\tcontinue\n\t\t}\n\t\tgo handleConn(conn)\n\t}\n}\n\n//!-main\n"
  },
  {
    "path": "ch8/chat/chat.go.~master~",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n//!+\n\n// Chat is a server that lets clients chat with each other.\npackage main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n)\n\n//!+broadcaster\ntype client chan<- string // an outgoing message channel\n\nvar (\n\tentering = make(chan client)\n\tleaving  = make(chan client)\n\tmessages = make(chan string) // all incoming client messages\n)\n\nfunc broadcaster() {\n\tclients := make(map[client]bool) // all connected clients\n\tfor {\n\t\tselect {\n\t\tcase msg := <-messages:\n\t\t\t// Broadcast incoming message to all\n\t\t\t// clients' outgoing message channels.\n\t\t\tfor cli := range clients {\n\t\t\t\tcli <- msg\n\t\t\t}\n\t\tcase cli := <-entering:\n\t\t\tclients[cli] = true\n\t\tcase cli := <-leaving:\n\t\t\tdelete(clients, cli)\n\t\t\tclose(cli)\n\t\t}\n\t}\n}\n\n//!-broadcaster\n\n//!+handleConn\nfunc handleConn(conn net.Conn) {\n\tch := make(chan string) // outgoing client messages\n\tgo clientWriter(conn, ch)\n\n\twho := conn.RemoteAddr().String()\n\tentering <- ch\n\tmessages <- who + \" has arrived\"\n\tinput := bufio.NewScanner(conn)\n\tfor input.Scan() {\n\t\tmessages <- who + \": \" + input.Text()\n\t}\n\tmessages <- who + \" has left\"\n\tleaving <- ch\n\tconn.Close()\n}\n\nfunc clientWriter(conn net.Conn, ch <-chan string) {\n\tfor msg := range ch {\n\t\tfmt.Fprintln(conn, msg)\n\t}\n}\n\n//!-handleConn\n\n//!+main\nfunc main() {\n\tlistener, err := net.Listen(\"tcp\", \"localhost:8000\")\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\tgo broadcaster()\n\tfor {\n\t\tconn, err := listener.Accept()\n\t\tif err != nil {\n\t\t\tlog.Print(err)\n\t\t\tcontinue\n\t\t}\n\t\tgo handleConn(conn)\n\t}\n}\n\n//!-main\n"
  },
  {
    "path": "ch8/clock1/clock.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 219.\n//!+\n\n// Clock1 is a TCP server that periodically writes the time.\npackage main\n\nimport (\n\t\"io\"\n\t\"log\"\n\t\"net\"\n\t\"time\"\n)\n\nfunc main() {\n\tlistener, err := net.Listen(\"tcp\", \"localhost:8000\")\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tfor {\n\t\tconn, err := listener.Accept()\n\t\tif err != nil {\n\t\t\tlog.Print(err) // e.g., connection aborted\n\t\t\tcontinue\n\t\t}\n\t\thandleConn(conn) // handle one connection at a time\n\t}\n}\n\nfunc handleConn(c net.Conn) {\n\tdefer c.Close()\n\tfor {\n\t\t_, err := io.WriteString(c, time.Now().Format(\"15:04:05\\n\"))\n\t\tif err != nil {\n\t\t\treturn // e.g., client disconnected\n\t\t}\n\t\ttime.Sleep(1 * time.Second)\n\t}\n}\n\n//!-\n"
  },
  {
    "path": "ch8/clock2/clock.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 222.\n\n// Clock is a TCP server that periodically writes the time.\npackage main\n\nimport (\n\t\"io\"\n\t\"log\"\n\t\"net\"\n\t\"time\"\n)\n\nfunc handleConn(c net.Conn) {\n\tdefer c.Close()\n\tfor {\n\t\t_, err := io.WriteString(c, time.Now().Format(\"15:04:05\\n\"))\n\t\tif err != nil {\n\t\t\treturn // e.g., client disconnected\n\t\t}\n\t\ttime.Sleep(1 * time.Second)\n\t}\n}\n\nfunc main() {\n\tlistener, err := net.Listen(\"tcp\", \"localhost:8000\")\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\t//!+\n\tfor {\n\t\tconn, err := listener.Accept()\n\t\tif err != nil {\n\t\t\tlog.Print(err) // e.g., connection aborted\n\t\t\tcontinue\n\t\t}\n\t\tgo handleConn(conn) // handle connections concurrently\n\t}\n\t//!-\n}\n"
  },
  {
    "path": "ch8/countdown1/countdown.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 244.\n\n// Countdown implements the countdown for a rocket launch.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"time\"\n)\n\n//!+\nfunc main() {\n\tfmt.Println(\"Commencing countdown.\")\n\ttick := time.Tick(1 * time.Second)\n\tfor countdown := 10; countdown > 0; countdown-- {\n\t\tfmt.Println(countdown)\n\t\t<-tick\n\t}\n\tlaunch()\n}\n\n//!-\n\nfunc launch() {\n\tfmt.Println(\"Lift off!\")\n}\n"
  },
  {
    "path": "ch8/countdown2/countdown.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 244.\n\n// Countdown implements the countdown for a rocket launch.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"time\"\n)\n\n//!+\n\nfunc main() {\n\t// ...create abort channel...\n\n\t//!-\n\n\t//!+abort\n\tabort := make(chan struct{})\n\tgo func() {\n\t\tos.Stdin.Read(make([]byte, 1)) // read a single byte\n\t\tabort <- struct{}{}\n\t}()\n\t//!-abort\n\n\t//!+\n\tfmt.Println(\"Commencing countdown.  Press return to abort.\")\n\tselect {\n\tcase <-time.After(10 * time.Second):\n\t\t// Do nothing.\n\tcase <-abort:\n\t\tfmt.Println(\"Launch aborted!\")\n\t\treturn\n\t}\n\tlaunch()\n}\n\n//!-\n\nfunc launch() {\n\tfmt.Println(\"Lift off!\")\n}\n"
  },
  {
    "path": "ch8/countdown3/countdown.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 246.\n\n// Countdown implements the countdown for a rocket launch.\npackage main\n\n// NOTE: the ticker goroutine never terminates if the launch is aborted.\n// This is a \"goroutine leak\".\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"time\"\n)\n\n//!+\n\nfunc main() {\n\t// ...create abort channel...\n\n\t//!-\n\n\tabort := make(chan struct{})\n\tgo func() {\n\t\tos.Stdin.Read(make([]byte, 1)) // read a single byte\n\t\tabort <- struct{}{}\n\t}()\n\n\t//!+\n\tfmt.Println(\"Commencing countdown.  Press return to abort.\")\n\ttick := time.Tick(1 * time.Second)\n\tfor countdown := 10; countdown > 0; countdown-- {\n\t\tfmt.Println(countdown)\n\t\tselect {\n\t\tcase <-tick:\n\t\t\t// Do nothing.\n\t\tcase <-abort:\n\t\t\tfmt.Println(\"Launch aborted!\")\n\t\t\treturn\n\t\t}\n\t}\n\tlaunch()\n}\n\n//!-\n\nfunc launch() {\n\tfmt.Println(\"Lift off!\")\n}\n"
  },
  {
    "path": "ch8/crawl1/findlinks.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 240.\n\n// Crawl1 crawls web links starting with the command-line arguments.\n//\n// This version quickly exhausts available file descriptors\n// due to excessive concurrent calls to links.Extract.\n//\n// Also, it never terminates because the worklist is never closed.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\t\"gopl.io/ch5/links\"\n)\n\n//!+crawl\nfunc crawl(url string) []string {\n\tfmt.Println(url)\n\tlist, err := links.Extract(url)\n\tif err != nil {\n\t\tlog.Print(err)\n\t}\n\treturn list\n}\n\n//!-crawl\n\n//!+main\nfunc main() {\n\tworklist := make(chan []string)\n\n\t// Start with the command-line arguments.\n\tgo func() { worklist <- os.Args[1:] }()\n\n\t// Crawl the web concurrently.\n\tseen := make(map[string]bool)\n\tfor list := range worklist {\n\t\tfor _, link := range list {\n\t\t\tif !seen[link] {\n\t\t\t\tseen[link] = true\n\t\t\t\tgo func(link string) {\n\t\t\t\t\tworklist <- crawl(link)\n\t\t\t\t}(link)\n\t\t\t}\n\t\t}\n\t}\n}\n\n//!-main\n\n/*\n//!+output\n$ go build gopl.io/ch8/crawl1\n$ ./crawl1 http://gopl.io/\nhttp://gopl.io/\nhttps://golang.org/help/\n\nhttps://golang.org/doc/\nhttps://golang.org/blog/\n...\n2015/07/15 18:22:12 Get ...: dial tcp: lookup blog.golang.org: no such host\n2015/07/15 18:22:12 Get ...: dial tcp 23.21.222.120:443: socket:\n                                                        too many open files\n...\n//!-output\n*/\n"
  },
  {
    "path": "ch8/crawl2/findlinks.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 241.\n\n// Crawl2 crawls web links starting with the command-line arguments.\n//\n// This version uses a buffered channel as a counting semaphore\n// to limit the number of concurrent calls to links.Extract.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\t\"gopl.io/ch5/links\"\n)\n\n//!+sema\n// tokens is a counting semaphore used to\n// enforce a limit of 20 concurrent requests.\nvar tokens = make(chan struct{}, 20)\n\nfunc crawl(url string) []string {\n\tfmt.Println(url)\n\ttokens <- struct{}{} // acquire a token\n\tlist, err := links.Extract(url)\n\t<-tokens // release the token\n\n\tif err != nil {\n\t\tlog.Print(err)\n\t}\n\treturn list\n}\n\n//!-sema\n\n//!+\nfunc main() {\n\tworklist := make(chan []string)\n\tvar n int // number of pending sends to worklist\n\n\t// Start with the command-line arguments.\n\tn++\n\tgo func() { worklist <- os.Args[1:] }()\n\n\t// Crawl the web concurrently.\n\tseen := make(map[string]bool)\n\tfor ; n > 0; n-- {\n\t\tlist := <-worklist\n\t\tfor _, link := range list {\n\t\t\tif !seen[link] {\n\t\t\t\tseen[link] = true\n\t\t\t\tn++\n\t\t\t\tgo func(link string) {\n\t\t\t\t\tworklist <- crawl(link)\n\t\t\t\t}(link)\n\t\t\t}\n\t\t}\n\t}\n}\n\n//!-\n"
  },
  {
    "path": "ch8/crawl3/findlinks.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 243.\n\n// Crawl3 crawls web links starting with the command-line arguments.\n//\n// This version uses bounded parallelism.\n// For simplicity, it does not address the termination problem.\n//\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\t\"gopl.io/ch5/links\"\n)\n\nfunc crawl(url string) []string {\n\tfmt.Println(url)\n\tlist, err := links.Extract(url)\n\tif err != nil {\n\t\tlog.Print(err)\n\t}\n\treturn list\n}\n\n//!+\nfunc main() {\n\tworklist := make(chan []string)  // lists of URLs, may have duplicates\n\tunseenLinks := make(chan string) // de-duplicated URLs\n\n\t// Add command-line arguments to worklist.\n\tgo func() { worklist <- os.Args[1:] }()\n\n\t// Create 20 crawler goroutines to fetch each unseen link.\n\tfor i := 0; i < 20; i++ {\n\t\tgo func() {\n\t\t\tfor link := range unseenLinks {\n\t\t\t\tfoundLinks := crawl(link)\n\t\t\t\tgo func() { worklist <- foundLinks }()\n\t\t\t}\n\t\t}()\n\t}\n\n\t// The main goroutine de-duplicates worklist items\n\t// and sends the unseen ones to the crawlers.\n\tseen := make(map[string]bool)\n\tfor list := range worklist {\n\t\tfor _, link := range list {\n\t\t\tif !seen[link] {\n\t\t\t\tseen[link] = true\n\t\t\t\tunseenLinks <- link\n\t\t\t}\n\t\t}\n\t}\n}\n\n//!-\n"
  },
  {
    "path": "ch8/du1/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 247.\n\n//!+main\n\n// The du1 command computes the disk usage of the files in a directory.\npackage main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"path/filepath\"\n)\n\nfunc main() {\n\t// Determine the initial directories.\n\tflag.Parse()\n\troots := flag.Args()\n\tif len(roots) == 0 {\n\t\troots = []string{\".\"}\n\t}\n\n\t// Traverse the file tree.\n\tfileSizes := make(chan int64)\n\tgo func() {\n\t\tfor _, root := range roots {\n\t\t\twalkDir(root, fileSizes)\n\t\t}\n\t\tclose(fileSizes)\n\t}()\n\n\t// Print the results.\n\tvar nfiles, nbytes int64\n\tfor size := range fileSizes {\n\t\tnfiles++\n\t\tnbytes += size\n\t}\n\tprintDiskUsage(nfiles, nbytes)\n}\n\nfunc printDiskUsage(nfiles, nbytes int64) {\n\tfmt.Printf(\"%d files  %.1f GB\\n\", nfiles, float64(nbytes)/1e9)\n}\n\n//!-main\n\n//!+walkDir\n\n// walkDir recursively walks the file tree rooted at dir\n// and sends the size of each found file on fileSizes.\nfunc walkDir(dir string, fileSizes chan<- int64) {\n\tfor _, entry := range dirents(dir) {\n\t\tif entry.IsDir() {\n\t\t\tsubdir := filepath.Join(dir, entry.Name())\n\t\t\twalkDir(subdir, fileSizes)\n\t\t} else {\n\t\t\tfileSizes <- entry.Size()\n\t\t}\n\t}\n}\n\n// dirents returns the entries of directory dir.\nfunc dirents(dir string) []os.FileInfo {\n\tentries, err := ioutil.ReadDir(dir)\n\tif err != nil {\n\t\tfmt.Fprintf(os.Stderr, \"du1: %v\\n\", err)\n\t\treturn nil\n\t}\n\treturn entries\n}\n\n//!-walkDir\n\n// The du1 variant uses two goroutines and\n// prints the total after every file is found.\n"
  },
  {
    "path": "ch8/du2/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 249.\n\n// The du2 command computes the disk usage of the files in a directory.\npackage main\n\n// The du2 variant uses select and a time.Ticker\n// to print the totals periodically if -v is set.\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"time\"\n)\n\n//!+\nvar verbose = flag.Bool(\"v\", false, \"show verbose progress messages\")\n\nfunc main() {\n\t// ...start background goroutine...\n\n\t//!-\n\t// Determine the initial directories.\n\tflag.Parse()\n\troots := flag.Args()\n\tif len(roots) == 0 {\n\t\troots = []string{\".\"}\n\t}\n\n\t// Traverse the file tree.\n\tfileSizes := make(chan int64)\n\tgo func() {\n\t\tfor _, root := range roots {\n\t\t\twalkDir(root, fileSizes)\n\t\t}\n\t\tclose(fileSizes)\n\t}()\n\n\t//!+\n\t// Print the results periodically.\n\tvar tick <-chan time.Time\n\tif *verbose {\n\t\ttick = time.Tick(500 * time.Millisecond)\n\t}\n\tvar nfiles, nbytes int64\nloop:\n\tfor {\n\t\tselect {\n\t\tcase size, ok := <-fileSizes:\n\t\t\tif !ok {\n\t\t\t\tbreak loop // fileSizes was closed\n\t\t\t}\n\t\t\tnfiles++\n\t\t\tnbytes += size\n\t\tcase <-tick:\n\t\t\tprintDiskUsage(nfiles, nbytes)\n\t\t}\n\t}\n\tprintDiskUsage(nfiles, nbytes) // final totals\n}\n\n//!-\n\nfunc printDiskUsage(nfiles, nbytes int64) {\n\tfmt.Printf(\"%d files  %.1f GB\\n\", nfiles, float64(nbytes)/1e9)\n}\n\n// walkDir recursively walks the file tree rooted at dir\n// and sends the size of each found file on fileSizes.\nfunc walkDir(dir string, fileSizes chan<- int64) {\n\tfor _, entry := range dirents(dir) {\n\t\tif entry.IsDir() {\n\t\t\tsubdir := filepath.Join(dir, entry.Name())\n\t\t\twalkDir(subdir, fileSizes)\n\t\t} else {\n\t\t\tfileSizes <- entry.Size()\n\t\t}\n\t}\n}\n\n// dirents returns the entries of directory dir.\nfunc dirents(dir string) []os.FileInfo {\n\tentries, err := ioutil.ReadDir(dir)\n\tif err != nil {\n\t\tfmt.Fprintf(os.Stderr, \"du: %v\\n\", err)\n\t\treturn nil\n\t}\n\treturn entries\n}\n"
  },
  {
    "path": "ch8/du3/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 250.\n\n// The du3 command computes the disk usage of the files in a directory.\npackage main\n\n// The du3 variant traverses all directories in parallel.\n// It uses a concurrency-limiting counting semaphore\n// to avoid opening too many files at once.\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sync\"\n\t\"time\"\n)\n\nvar vFlag = flag.Bool(\"v\", false, \"show verbose progress messages\")\n\n//!+\nfunc main() {\n\t// ...determine roots...\n\n\t//!-\n\tflag.Parse()\n\n\t// Determine the initial directories.\n\troots := flag.Args()\n\tif len(roots) == 0 {\n\t\troots = []string{\".\"}\n\t}\n\n\t//!+\n\t// Traverse each root of the file tree in parallel.\n\tfileSizes := make(chan int64)\n\tvar n sync.WaitGroup\n\tfor _, root := range roots {\n\t\tn.Add(1)\n\t\tgo walkDir(root, &n, fileSizes)\n\t}\n\tgo func() {\n\t\tn.Wait()\n\t\tclose(fileSizes)\n\t}()\n\t//!-\n\n\t// Print the results periodically.\n\tvar tick <-chan time.Time\n\tif *vFlag {\n\t\ttick = time.Tick(500 * time.Millisecond)\n\t}\n\tvar nfiles, nbytes int64\nloop:\n\tfor {\n\t\tselect {\n\t\tcase size, ok := <-fileSizes:\n\t\t\tif !ok {\n\t\t\t\tbreak loop // fileSizes was closed\n\t\t\t}\n\t\t\tnfiles++\n\t\t\tnbytes += size\n\t\tcase <-tick:\n\t\t\tprintDiskUsage(nfiles, nbytes)\n\t\t}\n\t}\n\n\tprintDiskUsage(nfiles, nbytes) // final totals\n\t//!+\n\t// ...select loop...\n}\n\n//!-\n\nfunc printDiskUsage(nfiles, nbytes int64) {\n\tfmt.Printf(\"%d files  %.1f GB\\n\", nfiles, float64(nbytes)/1e9)\n}\n\n// walkDir recursively walks the file tree rooted at dir\n// and sends the size of each found file on fileSizes.\n//!+walkDir\nfunc walkDir(dir string, n *sync.WaitGroup, fileSizes chan<- int64) {\n\tdefer n.Done()\n\tfor _, entry := range dirents(dir) {\n\t\tif entry.IsDir() {\n\t\t\tn.Add(1)\n\t\t\tsubdir := filepath.Join(dir, entry.Name())\n\t\t\tgo walkDir(subdir, n, fileSizes)\n\t\t} else {\n\t\t\tfileSizes <- entry.Size()\n\t\t}\n\t}\n}\n\n//!-walkDir\n\n//!+sema\n// sema is a counting semaphore for limiting concurrency in dirents.\nvar sema = make(chan struct{}, 20)\n\n// dirents returns the entries of directory dir.\nfunc dirents(dir string) []os.FileInfo {\n\tsema <- struct{}{}        // acquire token\n\tdefer func() { <-sema }() // release token\n\t// ...\n\t//!-sema\n\n\tentries, err := ioutil.ReadDir(dir)\n\tif err != nil {\n\t\tfmt.Fprintf(os.Stderr, \"du: %v\\n\", err)\n\t\treturn nil\n\t}\n\treturn entries\n}\n"
  },
  {
    "path": "ch8/du4/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 251.\n\n// The du4 command computes the disk usage of the files in a directory.\npackage main\n\n// The du4 variant includes cancellation:\n// it terminates quickly when the user hits return.\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sync\"\n\t\"time\"\n)\n\n//!+1\nvar done = make(chan struct{})\n\nfunc cancelled() bool {\n\tselect {\n\tcase <-done:\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n\n//!-1\n\nfunc main() {\n\t// Determine the initial directories.\n\troots := os.Args[1:]\n\tif len(roots) == 0 {\n\t\troots = []string{\".\"}\n\t}\n\n\t//!+2\n\t// Cancel traversal when input is detected.\n\tgo func() {\n\t\tos.Stdin.Read(make([]byte, 1)) // read a single byte\n\t\tclose(done)\n\t}()\n\t//!-2\n\n\t// Traverse each root of the file tree in parallel.\n\tfileSizes := make(chan int64)\n\tvar n sync.WaitGroup\n\tfor _, root := range roots {\n\t\tn.Add(1)\n\t\tgo walkDir(root, &n, fileSizes)\n\t}\n\tgo func() {\n\t\tn.Wait()\n\t\tclose(fileSizes)\n\t}()\n\n\t// Print the results periodically.\n\ttick := time.Tick(500 * time.Millisecond)\n\tvar nfiles, nbytes int64\nloop:\n\t//!+3\n\tfor {\n\t\tselect {\n\t\tcase <-done:\n\t\t\t// Drain fileSizes to allow existing goroutines to finish.\n\t\t\tfor range fileSizes {\n\t\t\t\t// Do nothing.\n\t\t\t}\n\t\t\treturn\n\t\tcase size, ok := <-fileSizes:\n\t\t\t// ...\n\t\t\t//!-3\n\t\t\tif !ok {\n\t\t\t\tbreak loop // fileSizes was closed\n\t\t\t}\n\t\t\tnfiles++\n\t\t\tnbytes += size\n\t\tcase <-tick:\n\t\t\tprintDiskUsage(nfiles, nbytes)\n\t\t}\n\t}\n\tprintDiskUsage(nfiles, nbytes) // final totals\n}\n\nfunc printDiskUsage(nfiles, nbytes int64) {\n\tfmt.Printf(\"%d files  %.1f GB\\n\", nfiles, float64(nbytes)/1e9)\n}\n\n// walkDir recursively walks the file tree rooted at dir\n// and sends the size of each found file on fileSizes.\n//!+4\nfunc walkDir(dir string, n *sync.WaitGroup, fileSizes chan<- int64) {\n\tdefer n.Done()\n\tif cancelled() {\n\t\treturn\n\t}\n\tfor _, entry := range dirents(dir) {\n\t\t// ...\n\t\t//!-4\n\t\tif entry.IsDir() {\n\t\t\tn.Add(1)\n\t\t\tsubdir := filepath.Join(dir, entry.Name())\n\t\t\tgo walkDir(subdir, n, fileSizes)\n\t\t} else {\n\t\t\tfileSizes <- entry.Size()\n\t\t}\n\t\t//!+4\n\t}\n}\n\n//!-4\n\nvar sema = make(chan struct{}, 20) // concurrency-limiting counting semaphore\n\n// dirents returns the entries of directory dir.\n//!+5\nfunc dirents(dir string) []os.FileInfo {\n\tselect {\n\tcase sema <- struct{}{}: // acquire token\n\tcase <-done:\n\t\treturn nil // cancelled\n\t}\n\tdefer func() { <-sema }() // release token\n\n\t// ...read directory...\n\t//!-5\n\n\tf, err := os.Open(dir)\n\tif err != nil {\n\t\tfmt.Fprintf(os.Stderr, \"du: %v\\n\", err)\n\t\treturn nil\n\t}\n\tdefer f.Close()\n\n\tentries, err := f.Readdir(0) // 0 => no limit; read all entries\n\tif err != nil {\n\t\tfmt.Fprintf(os.Stderr, \"du: %v\\n\", err)\n\t\t// Don't return: Readdir may return partial results.\n\t}\n\treturn entries\n}\n"
  },
  {
    "path": "ch8/netcat1/netcat.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 221.\n//!+\n\n// Netcat1 is a read-only TCP client.\npackage main\n\nimport (\n\t\"io\"\n\t\"log\"\n\t\"net\"\n\t\"os\"\n)\n\nfunc main() {\n\tconn, err := net.Dial(\"tcp\", \"localhost:8000\")\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tdefer conn.Close()\n\tmustCopy(os.Stdout, conn)\n}\n\nfunc mustCopy(dst io.Writer, src io.Reader) {\n\tif _, err := io.Copy(dst, src); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n\n//!-\n"
  },
  {
    "path": "ch8/netcat2/netcat.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 223.\n\n// Netcat is a simple read/write client for TCP servers.\npackage main\n\nimport (\n\t\"io\"\n\t\"log\"\n\t\"net\"\n\t\"os\"\n)\n\n//!+\nfunc main() {\n\tconn, err := net.Dial(\"tcp\", \"localhost:8000\")\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tdefer conn.Close()\n\tgo mustCopy(os.Stdout, conn)\n\tmustCopy(conn, os.Stdin)\n}\n\n//!-\n\nfunc mustCopy(dst io.Writer, src io.Reader) {\n\tif _, err := io.Copy(dst, src); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n"
  },
  {
    "path": "ch8/netcat3/netcat.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 227.\n\n// Netcat is a simple read/write client for TCP servers.\npackage main\n\nimport (\n\t\"io\"\n\t\"log\"\n\t\"net\"\n\t\"os\"\n)\n\n//!+\nfunc main() {\n\tconn, err := net.Dial(\"tcp\", \"localhost:8000\")\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tdone := make(chan struct{})\n\tgo func() {\n\t\tio.Copy(os.Stdout, conn) // NOTE: ignoring errors\n\t\tlog.Println(\"done\")\n\t\tdone <- struct{}{} // signal the main goroutine\n\t}()\n\tmustCopy(conn, os.Stdin)\n\tconn.Close()\n\t<-done // wait for background goroutine to finish\n}\n\n//!-\n\nfunc mustCopy(dst io.Writer, src io.Reader) {\n\tif _, err := io.Copy(dst, src); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n"
  },
  {
    "path": "ch8/pipeline1/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 228.\n\n// Pipeline1 demonstrates an infinite 3-stage pipeline.\npackage main\n\nimport \"fmt\"\n\n//!+\nfunc main() {\n\tnaturals := make(chan int)\n\tsquares := make(chan int)\n\n\t// Counter\n\tgo func() {\n\t\tfor x := 0; ; x++ {\n\t\t\tnaturals <- x\n\t\t}\n\t}()\n\n\t// Squarer\n\tgo func() {\n\t\tfor {\n\t\t\tx := <-naturals\n\t\t\tsquares <- x * x\n\t\t}\n\t}()\n\n\t// Printer (in main goroutine)\n\tfor {\n\t\tfmt.Println(<-squares)\n\t}\n}\n\n//!-\n"
  },
  {
    "path": "ch8/pipeline2/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 229.\n\n// Pipeline2 demonstrates a finite 3-stage pipeline.\npackage main\n\nimport \"fmt\"\n\n//!+\nfunc main() {\n\tnaturals := make(chan int)\n\tsquares := make(chan int)\n\n\t// Counter\n\tgo func() {\n\t\tfor x := 0; x < 100; x++ {\n\t\t\tnaturals <- x\n\t\t}\n\t\tclose(naturals)\n\t}()\n\n\t// Squarer\n\tgo func() {\n\t\tfor x := range naturals {\n\t\t\tsquares <- x * x\n\t\t}\n\t\tclose(squares)\n\t}()\n\n\t// Printer (in main goroutine)\n\tfor x := range squares {\n\t\tfmt.Println(x)\n\t}\n}\n\n//!-\n"
  },
  {
    "path": "ch8/pipeline3/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 231.\n\n// Pipeline3 demonstrates a finite 3-stage pipeline\n// with range, close, and unidirectional channel types.\npackage main\n\nimport \"fmt\"\n\n//!+\nfunc counter(out chan<- int) {\n\tfor x := 0; x < 100; x++ {\n\t\tout <- x\n\t}\n\tclose(out)\n}\n\nfunc squarer(out chan<- int, in <-chan int) {\n\tfor v := range in {\n\t\tout <- v * v\n\t}\n\tclose(out)\n}\n\nfunc printer(in <-chan int) {\n\tfor v := range in {\n\t\tfmt.Println(v)\n\t}\n}\n\nfunc main() {\n\tnaturals := make(chan int)\n\tsquares := make(chan int)\n\n\tgo counter(naturals)\n\tgo squarer(squares, naturals)\n\tprinter(squares)\n}\n\n//!-\n"
  },
  {
    "path": "ch8/reverb1/reverb.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 223.\n\n// Reverb1 is a TCP server that simulates an echo.\npackage main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"strings\"\n\t\"time\"\n)\n\n//!+\nfunc echo(c net.Conn, shout string, delay time.Duration) {\n\tfmt.Fprintln(c, \"\\t\", strings.ToUpper(shout))\n\ttime.Sleep(delay)\n\tfmt.Fprintln(c, \"\\t\", shout)\n\ttime.Sleep(delay)\n\tfmt.Fprintln(c, \"\\t\", strings.ToLower(shout))\n}\n\nfunc handleConn(c net.Conn) {\n\tinput := bufio.NewScanner(c)\n\tfor input.Scan() {\n\t\techo(c, input.Text(), 1*time.Second)\n\t}\n\t// NOTE: ignoring potential errors from input.Err()\n\tc.Close()\n}\n\n//!-\n\nfunc main() {\n\tl, err := net.Listen(\"tcp\", \"localhost:8000\")\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tfor {\n\t\tconn, err := l.Accept()\n\t\tif err != nil {\n\t\t\tlog.Print(err) // e.g., connection aborted\n\t\t\tcontinue\n\t\t}\n\t\tgo handleConn(conn)\n\t}\n}\n"
  },
  {
    "path": "ch8/reverb2/reverb.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 224.\n\n// Reverb2 is a TCP server that simulates an echo.\npackage main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"strings\"\n\t\"time\"\n)\n\nfunc echo(c net.Conn, shout string, delay time.Duration) {\n\tfmt.Fprintln(c, \"\\t\", strings.ToUpper(shout))\n\ttime.Sleep(delay)\n\tfmt.Fprintln(c, \"\\t\", shout)\n\ttime.Sleep(delay)\n\tfmt.Fprintln(c, \"\\t\", strings.ToLower(shout))\n}\n\n//!+\nfunc handleConn(c net.Conn) {\n\tinput := bufio.NewScanner(c)\n\tfor input.Scan() {\n\t\tgo echo(c, input.Text(), 1*time.Second)\n\t}\n\t// NOTE: ignoring potential errors from input.Err()\n\tc.Close()\n}\n\n//!-\n\nfunc main() {\n\tl, err := net.Listen(\"tcp\", \"localhost:8000\")\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tfor {\n\t\tconn, err := l.Accept()\n\t\tif err != nil {\n\t\t\tlog.Print(err) // e.g., connection aborted\n\t\t\tcontinue\n\t\t}\n\t\tgo handleConn(conn)\n\t}\n}\n"
  },
  {
    "path": "ch8/spinner/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 218.\n\n// Spinner displays an animation while computing the 45th Fibonacci number.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"time\"\n)\n\n//!+\nfunc main() {\n\tgo spinner(100 * time.Millisecond)\n\tconst n = 45\n\tfibN := fib(n) // slow\n\tfmt.Printf(\"\\rFibonacci(%d) = %d\\n\", n, fibN)\n}\n\nfunc spinner(delay time.Duration) {\n\tfor {\n\t\tfor _, r := range `-\\|/` {\n\t\t\tfmt.Printf(\"\\r%c\", r)\n\t\t\ttime.Sleep(delay)\n\t\t}\n\t}\n}\n\nfunc fib(x int) int {\n\tif x < 2 {\n\t\treturn x\n\t}\n\treturn fib(x-1) + fib(x-2)\n}\n\n//!-\n"
  },
  {
    "path": "ch8/thumbnail/main.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// +build ignore\n\n// The thumbnail command produces thumbnails of JPEG files\n// whose names are provided on each line of the standard input.\n//\n// The \"+build ignore\" tag (see p.295) excludes this file from the\n// thumbnail package, but it can be compiled as a command and run like\n// this:\n//\n// Run with:\n//   $ go run $GOPATH/src/gopl.io/ch8/thumbnail/main.go\n//   foo.jpeg\n//   ^D\n//\npackage main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\t\"gopl.io/ch8/thumbnail\"\n)\n\nfunc main() {\n\tinput := bufio.NewScanner(os.Stdin)\n\tfor input.Scan() {\n\t\tthumb, err := thumbnail.ImageFile(input.Text())\n\t\tif err != nil {\n\t\t\tlog.Print(err)\n\t\t\tcontinue\n\t\t}\n\t\tfmt.Println(thumb)\n\t}\n\tif err := input.Err(); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n"
  },
  {
    "path": "ch8/thumbnail/thumbnail.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 234.\n\n// The thumbnail package produces thumbnail-size images from\n// larger images.  Only JPEG images are currently supported.\npackage thumbnail\n\nimport (\n\t\"fmt\"\n\t\"image\"\n\t\"image/jpeg\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n)\n\n// Image returns a thumbnail-size version of src.\nfunc Image(src image.Image) image.Image {\n\t// Compute thumbnail size, preserving aspect ratio.\n\txs := src.Bounds().Size().X\n\tys := src.Bounds().Size().Y\n\twidth, height := 128, 128\n\tif aspect := float64(xs) / float64(ys); aspect < 1.0 {\n\t\twidth = int(128 * aspect) // portrait\n\t} else {\n\t\theight = int(128 / aspect) // landscape\n\t}\n\txscale := float64(xs) / float64(width)\n\tyscale := float64(ys) / float64(height)\n\n\tdst := image.NewRGBA(image.Rect(0, 0, width, height))\n\n\t// a very crude scaling algorithm\n\tfor x := 0; x < width; x++ {\n\t\tfor y := 0; y < height; y++ {\n\t\t\tsrcx := int(float64(x) * xscale)\n\t\t\tsrcy := int(float64(y) * yscale)\n\t\t\tdst.Set(x, y, src.At(srcx, srcy))\n\t\t}\n\t}\n\treturn dst\n}\n\n// ImageStream reads an image from r and\n// writes a thumbnail-size version of it to w.\nfunc ImageStream(w io.Writer, r io.Reader) error {\n\tsrc, _, err := image.Decode(r)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdst := Image(src)\n\treturn jpeg.Encode(w, dst, nil)\n}\n\n// ImageFile2 reads an image from infile and writes\n// a thumbnail-size version of it to outfile.\nfunc ImageFile2(outfile, infile string) (err error) {\n\tin, err := os.Open(infile)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer in.Close()\n\n\tout, err := os.Create(outfile)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err := ImageStream(out, in); err != nil {\n\t\tout.Close()\n\t\treturn fmt.Errorf(\"scaling %s to %s: %s\", infile, outfile, err)\n\t}\n\treturn out.Close()\n}\n\n// ImageFile reads an image from infile and writes\n// a thumbnail-size version of it in the same directory.\n// It returns the generated file name, e.g. \"foo.thumb.jpeg\".\nfunc ImageFile(infile string) (string, error) {\n\text := filepath.Ext(infile) // e.g., \".jpg\", \".JPEG\"\n\toutfile := strings.TrimSuffix(infile, ext) + \".thumb\" + ext\n\treturn outfile, ImageFile2(outfile, infile)\n}\n"
  },
  {
    "path": "ch8/thumbnail/thumbnail_test.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// This file is just a place to put example code from the book.\n// It does not actually run any code in gopl.io/ch8/thumbnail.\n\npackage thumbnail_test\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"sync\"\n\n\t\"gopl.io/ch8/thumbnail\"\n)\n\n//!+1\n// makeThumbnails makes thumbnails of the specified files.\nfunc makeThumbnails(filenames []string) {\n\tfor _, f := range filenames {\n\t\tif _, err := thumbnail.ImageFile(f); err != nil {\n\t\t\tlog.Println(err)\n\t\t}\n\t}\n}\n\n//!-1\n\n//!+2\n// NOTE: incorrect!\nfunc makeThumbnails2(filenames []string) {\n\tfor _, f := range filenames {\n\t\tgo thumbnail.ImageFile(f) // NOTE: ignoring errors\n\t}\n}\n\n//!-2\n\n//!+3\n// makeThumbnails3 makes thumbnails of the specified files in parallel.\nfunc makeThumbnails3(filenames []string) {\n\tch := make(chan struct{})\n\tfor _, f := range filenames {\n\t\tgo func(f string) {\n\t\t\tthumbnail.ImageFile(f) // NOTE: ignoring errors\n\t\t\tch <- struct{}{}\n\t\t}(f)\n\t}\n\n\t// Wait for goroutines to complete.\n\tfor range filenames {\n\t\t<-ch\n\t}\n}\n\n//!-3\n\n//!+4\n// makeThumbnails4 makes thumbnails for the specified files in parallel.\n// It returns an error if any step failed.\nfunc makeThumbnails4(filenames []string) error {\n\terrors := make(chan error)\n\n\tfor _, f := range filenames {\n\t\tgo func(f string) {\n\t\t\t_, err := thumbnail.ImageFile(f)\n\t\t\terrors <- err\n\t\t}(f)\n\t}\n\n\tfor range filenames {\n\t\tif err := <-errors; err != nil {\n\t\t\treturn err // NOTE: incorrect: goroutine leak!\n\t\t}\n\t}\n\n\treturn nil\n}\n\n//!-4\n\n//!+5\n// makeThumbnails5 makes thumbnails for the specified files in parallel.\n// It returns the generated file names in an arbitrary order,\n// or an error if any step failed.\nfunc makeThumbnails5(filenames []string) (thumbfiles []string, err error) {\n\ttype item struct {\n\t\tthumbfile string\n\t\terr       error\n\t}\n\n\tch := make(chan item, len(filenames))\n\tfor _, f := range filenames {\n\t\tgo func(f string) {\n\t\t\tvar it item\n\t\t\tit.thumbfile, it.err = thumbnail.ImageFile(f)\n\t\t\tch <- it\n\t\t}(f)\n\t}\n\n\tfor range filenames {\n\t\tit := <-ch\n\t\tif it.err != nil {\n\t\t\treturn nil, it.err\n\t\t}\n\t\tthumbfiles = append(thumbfiles, it.thumbfile)\n\t}\n\n\treturn thumbfiles, nil\n}\n\n//!-5\n\n//!+6\n// makeThumbnails6 makes thumbnails for each file received from the channel.\n// It returns the number of bytes occupied by the files it creates.\nfunc makeThumbnails6(filenames <-chan string) int64 {\n\tsizes := make(chan int64)\n\tvar wg sync.WaitGroup // number of working goroutines\n\tfor f := range filenames {\n\t\twg.Add(1)\n\t\t// worker\n\t\tgo func(f string) {\n\t\t\tdefer wg.Done()\n\t\t\tthumb, err := thumbnail.ImageFile(f)\n\t\t\tif err != nil {\n\t\t\t\tlog.Println(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tinfo, _ := os.Stat(thumb) // OK to ignore error\n\t\t\tsizes <- info.Size()\n\t\t}(f)\n\t}\n\n\t// closer\n\tgo func() {\n\t\twg.Wait()\n\t\tclose(sizes)\n\t}()\n\n\tvar total int64\n\tfor size := range sizes {\n\t\ttotal += size\n\t}\n\treturn total\n}\n\n//!-6\n"
  },
  {
    "path": "ch9/bank1/bank.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 261.\n//!+\n\n// Package bank provides a concurrency-safe bank with one account.\npackage bank\n\nvar deposits = make(chan int) // send amount to deposit\nvar balances = make(chan int) // receive balance\n\nfunc Deposit(amount int) { deposits <- amount }\nfunc Balance() int       { return <-balances }\n\nfunc teller() {\n\tvar balance int // balance is confined to teller goroutine\n\tfor {\n\t\tselect {\n\t\tcase amount := <-deposits:\n\t\t\tbalance += amount\n\t\tcase balances <- balance:\n\t\t}\n\t}\n}\n\nfunc init() {\n\tgo teller() // start the monitor goroutine\n}\n\n//!-\n"
  },
  {
    "path": "ch9/bank1/bank_test.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\npackage bank_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"gopl.io/ch9/bank1\"\n)\n\nfunc TestBank(t *testing.T) {\n\tdone := make(chan struct{})\n\n\t// Alice\n\tgo func() {\n\t\tbank.Deposit(200)\n\t\tfmt.Println(\"=\", bank.Balance())\n\t\tdone <- struct{}{}\n\t}()\n\n\t// Bob\n\tgo func() {\n\t\tbank.Deposit(100)\n\t\tdone <- struct{}{}\n\t}()\n\n\t// Wait for both transactions.\n\t<-done\n\t<-done\n\n\tif got, want := bank.Balance(), 300; got != want {\n\t\tt.Errorf(\"Balance = %d, want %d\", got, want)\n\t}\n}\n"
  },
  {
    "path": "ch9/bank2/bank.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 262.\n\n// Package bank provides a concurrency-safe bank with one account.\npackage bank\n\n//!+\nvar (\n\tsema    = make(chan struct{}, 1) // a binary semaphore guarding balance\n\tbalance int\n)\n\nfunc Deposit(amount int) {\n\tsema <- struct{}{} // acquire token\n\tbalance = balance + amount\n\t<-sema // release token\n}\n\nfunc Balance() int {\n\tsema <- struct{}{} // acquire token\n\tb := balance\n\t<-sema // release token\n\treturn b\n}\n\n//!-\n"
  },
  {
    "path": "ch9/bank2/bank_test.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\npackage bank_test\n\nimport (\n\t\"sync\"\n\t\"testing\"\n\n\t\"gopl.io/ch9/bank2\"\n)\n\nfunc TestBank(t *testing.T) {\n\t// Deposit [1..1000] concurrently.\n\tvar n sync.WaitGroup\n\tfor i := 1; i <= 1000; i++ {\n\t\tn.Add(1)\n\t\tgo func(amount int) {\n\t\t\tbank.Deposit(amount)\n\t\t\tn.Done()\n\t\t}(i)\n\t}\n\tn.Wait()\n\n\tif got, want := bank.Balance(), (1000+1)*1000/2; got != want {\n\t\tt.Errorf(\"Balance = %d, want %d\", got, want)\n\t}\n}\n"
  },
  {
    "path": "ch9/bank3/bank.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 263.\n\n// Package bank provides a concurrency-safe single-account bank.\npackage bank\n\n//!+\nimport \"sync\"\n\nvar (\n\tmu      sync.Mutex // guards balance\n\tbalance int\n)\n\nfunc Deposit(amount int) {\n\tmu.Lock()\n\tbalance = balance + amount\n\tmu.Unlock()\n}\n\nfunc Balance() int {\n\tmu.Lock()\n\tb := balance\n\tmu.Unlock()\n\treturn b\n}\n\n//!-\n"
  },
  {
    "path": "ch9/bank3/bank_test.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\npackage bank_test\n\nimport (\n\t\"sync\"\n\t\"testing\"\n\n\t\"gopl.io/ch9/bank3\"\n)\n\nfunc TestBank(t *testing.T) {\n\t// Deposit [1..1000] concurrently.\n\tvar n sync.WaitGroup\n\tfor i := 1; i <= 1000; i++ {\n\t\tn.Add(1)\n\t\tgo func(amount int) {\n\t\t\tbank.Deposit(amount)\n\t\t\tn.Done()\n\t\t}(i)\n\t}\n\tn.Wait()\n\n\tif got, want := bank.Balance(), (1000+1)*1000/2; got != want {\n\t\tt.Errorf(\"Balance = %d, want %d\", got, want)\n\t}\n}\n"
  },
  {
    "path": "ch9/memo1/memo.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 272.\n\n//!+\n\n// Package memo provides a concurrency-unsafe\n// memoization of a function of type Func.\npackage memo\n\n// A Memo caches the results of calling a Func.\ntype Memo struct {\n\tf     Func\n\tcache map[string]result\n}\n\n// Func is the type of the function to memoize.\ntype Func func(key string) (interface{}, error)\n\ntype result struct {\n\tvalue interface{}\n\terr   error\n}\n\nfunc New(f Func) *Memo {\n\treturn &Memo{f: f, cache: make(map[string]result)}\n}\n\n// NOTE: not concurrency-safe!\nfunc (memo *Memo) Get(key string) (interface{}, error) {\n\tres, ok := memo.cache[key]\n\tif !ok {\n\t\tres.value, res.err = memo.f(key)\n\t\tmemo.cache[key] = res\n\t}\n\treturn res.value, res.err\n}\n\n//!-\n"
  },
  {
    "path": "ch9/memo1/memo_test.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\npackage memo_test\n\nimport (\n\t\"testing\"\n\n\t\"gopl.io/ch9/memo1\"\n\t\"gopl.io/ch9/memotest\"\n)\n\nvar httpGetBody = memotest.HTTPGetBody\n\nfunc Test(t *testing.T) {\n\tm := memo.New(httpGetBody)\n\tmemotest.Sequential(t, m)\n}\n\n// NOTE: not concurrency-safe!  Test fails.\nfunc TestConcurrent(t *testing.T) {\n\tm := memo.New(httpGetBody)\n\tmemotest.Concurrent(t, m)\n}\n\n/*\n//!+output\n$ go test -v gopl.io/ch9/memo1\n=== RUN   Test\nhttps://golang.org, 175.026418ms, 7537 bytes\nhttps://godoc.org, 172.686825ms, 6878 bytes\nhttps://play.golang.org, 115.762377ms, 5767 bytes\nhttp://gopl.io, 749.887242ms, 2856 bytes\n\nhttps://golang.org, 721ns, 7537 bytes\nhttps://godoc.org, 152ns, 6878 bytes\nhttps://play.golang.org, 205ns, 5767 bytes\nhttp://gopl.io, 326ns, 2856 bytes\n--- PASS: Test (1.21s)\nPASS\nok  gopl.io/ch9/memo1\t1.257s\n//!-output\n*/\n\n/*\n//!+race\n$ go test -run=TestConcurrent -race -v gopl.io/ch9/memo1\n=== RUN   TestConcurrent\n...\nWARNING: DATA RACE\nWrite by goroutine 36:\n  runtime.mapassign1()\n      ~/go/src/runtime/hashmap.go:411 +0x0\n  gopl.io/ch9/memo1.(*Memo).Get()\n      ~/gobook2/src/gopl.io/ch9/memo1/memo.go:32 +0x205\n  ...\n\nPrevious write by goroutine 35:\n  runtime.mapassign1()\n      ~/go/src/runtime/hashmap.go:411 +0x0\n  gopl.io/ch9/memo1.(*Memo).Get()\n      ~/gobook2/src/gopl.io/ch9/memo1/memo.go:32 +0x205\n...\nFound 1 data race(s)\nFAIL\tgopl.io/ch9/memo1\t2.393s\n//!-race\n*/\n"
  },
  {
    "path": "ch9/memo2/memo.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 275.\n\n// Package memo provides a concurrency-safe memoization a function of\n// type Func.  Concurrent requests are serialized by a Mutex.\npackage memo\n\nimport \"sync\"\n\n// Func is the type of the function to memoize.\ntype Func func(string) (interface{}, error)\n\ntype result struct {\n\tvalue interface{}\n\terr   error\n}\n\nfunc New(f Func) *Memo {\n\treturn &Memo{f: f, cache: make(map[string]result)}\n}\n\n//!+\n\ntype Memo struct {\n\tf     Func\n\tmu    sync.Mutex // guards cache\n\tcache map[string]result\n}\n\n// Get is concurrency-safe.\nfunc (memo *Memo) Get(key string) (value interface{}, err error) {\n\tmemo.mu.Lock()\n\tres, ok := memo.cache[key]\n\tif !ok {\n\t\tres.value, res.err = memo.f(key)\n\t\tmemo.cache[key] = res\n\t}\n\tmemo.mu.Unlock()\n\treturn res.value, res.err\n}\n\n//!-\n"
  },
  {
    "path": "ch9/memo2/memo_test.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\npackage memo_test\n\nimport (\n\t\"testing\"\n\n\t\"gopl.io/ch9/memo2\"\n\t\"gopl.io/ch9/memotest\"\n)\n\nvar httpGetBody = memotest.HTTPGetBody\n\nfunc Test(t *testing.T) {\n\tm := memo.New(httpGetBody)\n\tmemotest.Sequential(t, m)\n}\n\nfunc TestConcurrent(t *testing.T) {\n\tm := memo.New(httpGetBody)\n\tmemotest.Concurrent(t, m)\n}\n"
  },
  {
    "path": "ch9/memo3/memo.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 276.\n\n// Package memo provides a concurrency-safe memoization a function of\n// type Func.  Requests for different keys run concurrently.\n// Concurrent requests for the same key result in duplicate work.\npackage memo\n\nimport \"sync\"\n\ntype Memo struct {\n\tf     Func\n\tmu    sync.Mutex // guards cache\n\tcache map[string]result\n}\n\ntype Func func(string) (interface{}, error)\n\ntype result struct {\n\tvalue interface{}\n\terr   error\n}\n\nfunc New(f Func) *Memo {\n\treturn &Memo{f: f, cache: make(map[string]result)}\n}\n\n//!+\n\nfunc (memo *Memo) Get(key string) (value interface{}, err error) {\n\tmemo.mu.Lock()\n\tres, ok := memo.cache[key]\n\tmemo.mu.Unlock()\n\tif !ok {\n\t\tres.value, res.err = memo.f(key)\n\n\t\t// Between the two critical sections, several goroutines\n\t\t// may race to compute f(key) and update the map.\n\t\tmemo.mu.Lock()\n\t\tmemo.cache[key] = res\n\t\tmemo.mu.Unlock()\n\t}\n\treturn res.value, res.err\n}\n\n//!-\n"
  },
  {
    "path": "ch9/memo3/memo_test.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\npackage memo_test\n\nimport (\n\t\"testing\"\n\n\t\"gopl.io/ch9/memo3\"\n\t\"gopl.io/ch9/memotest\"\n)\n\nvar httpGetBody = memotest.HTTPGetBody\n\nfunc Test(t *testing.T) {\n\tm := memo.New(httpGetBody)\n\tmemotest.Sequential(t, m)\n}\n\nfunc TestConcurrent(t *testing.T) {\n\tm := memo.New(httpGetBody)\n\tmemotest.Concurrent(t, m)\n}\n"
  },
  {
    "path": "ch9/memo4/memo.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 276.\n\n// Package memo provides a concurrency-safe memoization a function of\n// a function.  Requests for different keys proceed in parallel.\n// Concurrent requests for the same key block until the first completes.\n// This implementation uses a Mutex.\npackage memo\n\nimport \"sync\"\n\n// Func is the type of the function to memoize.\ntype Func func(string) (interface{}, error)\n\ntype result struct {\n\tvalue interface{}\n\terr   error\n}\n\n//!+\ntype entry struct {\n\tres   result\n\tready chan struct{} // closed when res is ready\n}\n\nfunc New(f Func) *Memo {\n\treturn &Memo{f: f, cache: make(map[string]*entry)}\n}\n\ntype Memo struct {\n\tf     Func\n\tmu    sync.Mutex // guards cache\n\tcache map[string]*entry\n}\n\nfunc (memo *Memo) Get(key string) (value interface{}, err error) {\n\tmemo.mu.Lock()\n\te := memo.cache[key]\n\tif e == nil {\n\t\t// This is the first request for this key.\n\t\t// This goroutine becomes responsible for computing\n\t\t// the value and broadcasting the ready condition.\n\t\te = &entry{ready: make(chan struct{})}\n\t\tmemo.cache[key] = e\n\t\tmemo.mu.Unlock()\n\n\t\te.res.value, e.res.err = memo.f(key)\n\n\t\tclose(e.ready) // broadcast ready condition\n\t} else {\n\t\t// This is a repeat request for this key.\n\t\tmemo.mu.Unlock()\n\n\t\t<-e.ready // wait for ready condition\n\t}\n\treturn e.res.value, e.res.err\n}\n\n//!-\n"
  },
  {
    "path": "ch9/memo4/memo_test.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\npackage memo_test\n\nimport (\n\t\"testing\"\n\n\t\"gopl.io/ch9/memo4\"\n\t\"gopl.io/ch9/memotest\"\n)\n\nvar httpGetBody = memotest.HTTPGetBody\n\nfunc Test(t *testing.T) {\n\tm := memo.New(httpGetBody)\n\tmemotest.Sequential(t, m)\n}\n\nfunc TestConcurrent(t *testing.T) {\n\tm := memo.New(httpGetBody)\n\tmemotest.Concurrent(t, m)\n}\n"
  },
  {
    "path": "ch9/memo5/memo.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 278.\n\n// Package memo provides a concurrency-safe non-blocking memoization\n// of a function.  Requests for different keys proceed in parallel.\n// Concurrent requests for the same key block until the first completes.\n// This implementation uses a monitor goroutine.\npackage memo\n\n//!+Func\n\n// Func is the type of the function to memoize.\ntype Func func(key string) (interface{}, error)\n\n// A result is the result of calling a Func.\ntype result struct {\n\tvalue interface{}\n\terr   error\n}\n\ntype entry struct {\n\tres   result\n\tready chan struct{} // closed when res is ready\n}\n\n//!-Func\n\n//!+get\n\n// A request is a message requesting that the Func be applied to key.\ntype request struct {\n\tkey      string\n\tresponse chan<- result // the client wants a single result\n}\n\ntype Memo struct{ requests chan request }\n\n// New returns a memoization of f.  Clients must subsequently call Close.\nfunc New(f Func) *Memo {\n\tmemo := &Memo{requests: make(chan request)}\n\tgo memo.server(f)\n\treturn memo\n}\n\nfunc (memo *Memo) Get(key string) (interface{}, error) {\n\tresponse := make(chan result)\n\tmemo.requests <- request{key, response}\n\tres := <-response\n\treturn res.value, res.err\n}\n\nfunc (memo *Memo) Close() { close(memo.requests) }\n\n//!-get\n\n//!+monitor\n\nfunc (memo *Memo) server(f Func) {\n\tcache := make(map[string]*entry)\n\tfor req := range memo.requests {\n\t\te := cache[req.key]\n\t\tif e == nil {\n\t\t\t// This is the first request for this key.\n\t\t\te = &entry{ready: make(chan struct{})}\n\t\t\tcache[req.key] = e\n\t\t\tgo e.call(f, req.key) // call f(key)\n\t\t}\n\t\tgo e.deliver(req.response)\n\t}\n}\n\nfunc (e *entry) call(f Func, key string) {\n\t// Evaluate the function.\n\te.res.value, e.res.err = f(key)\n\t// Broadcast the ready condition.\n\tclose(e.ready)\n}\n\nfunc (e *entry) deliver(response chan<- result) {\n\t// Wait for the ready condition.\n\t<-e.ready\n\t// Send the result to the client.\n\tresponse <- e.res\n}\n\n//!-monitor\n"
  },
  {
    "path": "ch9/memo5/memo_test.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\npackage memo_test\n\nimport (\n\t\"testing\"\n\n\t\"gopl.io/ch9/memo5\"\n\t\"gopl.io/ch9/memotest\"\n)\n\nvar httpGetBody = memotest.HTTPGetBody\n\nfunc Test(t *testing.T) {\n\tm := memo.New(httpGetBody)\n\tdefer m.Close()\n\tmemotest.Sequential(t, m)\n}\n\nfunc TestConcurrent(t *testing.T) {\n\tm := memo.New(httpGetBody)\n\tdefer m.Close()\n\tmemotest.Concurrent(t, m)\n}\n"
  },
  {
    "path": "ch9/memotest/memotest.go",
    "content": "// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.\n// License: https://creativecommons.org/licenses/by-nc-sa/4.0/\n\n// See page 272.\n\n// Package memotest provides common functions for\n// testing various designs of the memo package.\npackage memotest\n\nimport (\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"net/http\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n)\n\n//!+httpRequestBody\nfunc httpGetBody(url string) (interface{}, error) {\n\tresp, err := http.Get(url)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer resp.Body.Close()\n\treturn ioutil.ReadAll(resp.Body)\n}\n\n//!-httpRequestBody\n\nvar HTTPGetBody = httpGetBody\n\nfunc incomingURLs() <-chan string {\n\tch := make(chan string)\n\tgo func() {\n\t\tfor _, url := range []string{\n\t\t\t\"https://golang.org\",\n\t\t\t\"https://godoc.org\",\n\t\t\t\"https://play.golang.org\",\n\t\t\t\"http://gopl.io\",\n\t\t\t\"https://golang.org\",\n\t\t\t\"https://godoc.org\",\n\t\t\t\"https://play.golang.org\",\n\t\t\t\"http://gopl.io\",\n\t\t} {\n\t\t\tch <- url\n\t\t}\n\t\tclose(ch)\n\t}()\n\treturn ch\n}\n\ntype M interface {\n\tGet(key string) (interface{}, error)\n}\n\n/*\n//!+seq\n\tm := memo.New(httpGetBody)\n//!-seq\n*/\n\nfunc Sequential(t *testing.T, m M) {\n\t//!+seq\n\tfor url := range incomingURLs() {\n\t\tstart := time.Now()\n\t\tvalue, err := m.Get(url)\n\t\tif err != nil {\n\t\t\tlog.Print(err)\n\t\t\tcontinue\n\t\t}\n\t\tfmt.Printf(\"%s, %s, %d bytes\\n\",\n\t\t\turl, time.Since(start), len(value.([]byte)))\n\t}\n\t//!-seq\n}\n\n/*\n//!+conc\n\tm := memo.New(httpGetBody)\n//!-conc\n*/\n\nfunc Concurrent(t *testing.T, m M) {\n\t//!+conc\n\tvar n sync.WaitGroup\n\tfor url := range incomingURLs() {\n\t\tn.Add(1)\n\t\tgo func(url string) {\n\t\t\tdefer n.Done()\n\t\t\tstart := time.Now()\n\t\t\tvalue, err := m.Get(url)\n\t\t\tif err != nil {\n\t\t\t\tlog.Print(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tfmt.Printf(\"%s, %s, %d bytes\\n\",\n\t\t\t\turl, time.Since(start), len(value.([]byte)))\n\t\t}(url)\n\t}\n\tn.Wait()\n\t//!-conc\n}\n"
  },
  {
    "path": "go.mod",
    "content": "module gopl.io\n\ngo 1.16\n\nrequire golang.org/x/net v0.0.0-20210929193557-e81a3d93ecf6\n"
  },
  {
    "path": "go.sum",
    "content": "golang.org/x/net v0.0.0-20210929193557-e81a3d93ecf6 h1:Z04ewVs7JhXaYkmDhBERPi41gnltfQpMWDnTnQbaCqk=\ngolang.org/x/net v0.0.0-20210929193557-e81a3d93ecf6/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\n"
  }
]