習題解答: 第一章 入門
-練習 1.1: 脩改echo程序,使其能夠打印os.Args[0]。
-TODO
-練習 1.2: 脩改echo程序,使其打印value和index,每個value和index顯示一行。
-練習 1.3: 上手實踐前麫提到的strings.Join和直接Println,併觀察輸齣結果的區彆。
-練習 1.4: 脩改dup2,使其可以打印重復的行分彆齣現在哪些文件。
-練習 1.5: 脩改前麫的Lissajous程序裏的調色闆,由緑色改為黑色。我們可以用color.RGBA{0xRR, 0xGG, 0xBB}來得到#RRGGBB這個色值,三個十六進製的字符串分彆代錶紅、緑、藍像素。
-練習 1.6: 脩改Lissajous程序,脩改其調色闆來生成更豐富的顔色,然後脩改SetColorIndex的第三個參數,看看顯示結果吧。
-練習 1.7: 函數調用io.Copy(dst, src)會從src中讀取內容,併將讀到的結果寫入到dst中,使用這個函數替代掉例子中的ioutil.ReadAll來拷貝響應結構體到os.Stdout,避免申請一個緩衝區(例子中的b)來存儲。記得處理io.Copy返迴結果中的錯誤。
-練習 1.8: 脩改fetch這個範例,如果輸入的url參數沒有http://前綴的話,為這個url加上該前綴。你可能會用到strings.HasPrefix這個函數。
-練習 1.9: 脩改fetch打印齣HTTP協議的狀態碼,可以從resp.Status變量得到該狀態碼。
-練習 1.10: 找一個數據量比較大的網站,用本小節中的程序調研網站的緩存策略,對每個URL執行兩遍請求,査看兩次時間是否有較大的差彆,併且每次穫取到的響應內容是否一緻,脩改本節中的程序,將響應結果輸齣,以便於進行對比。
-練習 1.11: Try fetchall with longer argument lists, such as samples from the top million web sites available at alexa.com. How does the program behave if a web site just doesn’t respond? (Section 8.9 describes mechanisms for coping in such cases.)
-練習 1.12: 脩改Lissajour服務,從URL讀取變量,比如你可以訪問http://localhost:8000/?cycles=20這個URL,這樣訪問可以將程序裏的cycles默認的5脩改為20。字符串轉換為數字可以調用strconv.Atoi函數。你可以在dodoc裏査看strconv.Atoi的詳細說明。
- - -
-
-You can download, build, and run the programs with the following commands:
-
- $ export GOPATH=$HOME/gobook # choose workspace directory
- $ go get gopl.io/ch1/helloworld # fetch, build, install
- $ $GOPATH/bin/helloworld # run
- Hello, 世界
-
-Many of the programs contain comments of the form `//!+` and `//!-`.
-These comments bracket the parts of the programs that are excerpted in the
-book; you can safely ignore them. In a few cases, programs
-have been reformatted in an unnatural way so that they can be presented
-in stages in the book.
-
diff --git a/vendor/gopl.io/ch1/dup1/main.go b/vendor/gopl.io/ch1/dup1/main.go
deleted file mode 100644
index f476741..0000000
--- a/vendor/gopl.io/ch1/dup1/main.go
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
-// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
-
-// See page 8.
-//!+
-
-// Dup1 prints the text of each line that appears more than
-// once in the standard input, preceded by its count.
-package main
-
-import (
- "bufio"
- "fmt"
- "os"
-)
-
-func main() {
- counts := make(map[string]int)
- input := bufio.NewScanner(os.Stdin)
- for input.Scan() {
- counts[input.Text()]++
- }
- // NOTE: ignoring potential errors from input.Err()
- for line, n := range counts {
- if n > 1 {
- fmt.Printf("%d\t%s\n", n, line)
- }
- }
-}
-
-//!-
diff --git a/vendor/gopl.io/ch1/dup2/main.go b/vendor/gopl.io/ch1/dup2/main.go
deleted file mode 100644
index e894f84..0000000
--- a/vendor/gopl.io/ch1/dup2/main.go
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
-// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
-
-// See page 10.
-//!+
-
-// Dup2 prints the count and text of lines that appear more than once
-// in the input. It reads from stdin or from a list of named files.
-package main
-
-import (
- "bufio"
- "fmt"
- "os"
-)
-
-func main() {
- counts := make(map[string]int)
- files := os.Args[1:]
- if len(files) == 0 {
- countLines(os.Stdin, counts)
- } else {
- for _, arg := range files {
- f, err := os.Open(arg)
- if err != nil {
- fmt.Fprintf(os.Stderr, "dup2: %v\n", err)
- continue
- }
- countLines(f, counts)
- f.Close()
- }
- }
- for line, n := range counts {
- if n > 1 {
- fmt.Printf("%d\t%s\n", n, line)
- }
- }
-}
-
-func countLines(f *os.File, counts map[string]int) {
- input := bufio.NewScanner(f)
- for input.Scan() {
- counts[input.Text()]++
- }
- // NOTE: ignoring potential errors from input.Err()
-}
-
-//!-
diff --git a/vendor/gopl.io/ch1/dup3/main.go b/vendor/gopl.io/ch1/dup3/main.go
deleted file mode 100644
index 50434d8..0000000
--- a/vendor/gopl.io/ch1/dup3/main.go
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
-// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
-
-// See page 12.
-
-//!+
-
-// Dup3 prints the count and text of lines that
-// appear more than once in the named input files.
-package main
-
-import (
- "fmt"
- "io/ioutil"
- "os"
- "strings"
-)
-
-func main() {
- counts := make(map[string]int)
- for _, filename := range os.Args[1:] {
- data, err := ioutil.ReadFile(filename)
- if err != nil {
- fmt.Fprintf(os.Stderr, "dup3: %v\n", err)
- continue
- }
- for _, line := range strings.Split(string(data), "\n") {
- counts[line]++
- }
- }
- for line, n := range counts {
- if n > 1 {
- fmt.Printf("%d\t%s\n", n, line)
- }
- }
-}
-
-//!-
diff --git a/vendor/gopl.io/ch1/echo1/main.go b/vendor/gopl.io/ch1/echo1/main.go
deleted file mode 100644
index e8f8969..0000000
--- a/vendor/gopl.io/ch1/echo1/main.go
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
-// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
-
-// See page 4.
-//!+
-
-// Echo1 prints its command-line arguments.
-package main
-
-import (
- "fmt"
- "os"
-)
-
-func main() {
- var s, sep string
- for i := 1; i < len(os.Args); i++ {
- s += sep + os.Args[i]
- sep = " "
- }
- fmt.Println(s)
-}
-
-//!-
diff --git a/vendor/gopl.io/ch1/echo2/main.go b/vendor/gopl.io/ch1/echo2/main.go
deleted file mode 100644
index 82d312c..0000000
--- a/vendor/gopl.io/ch1/echo2/main.go
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
-// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
-
-// See page 6.
-//!+
-
-// Echo2 prints its command-line arguments.
-package main
-
-import (
- "fmt"
- "os"
-)
-
-func main() {
- s, sep := "", ""
- for _, arg := range os.Args[1:] {
- s += sep + arg
- sep = " "
- }
- fmt.Println(s)
-}
-
-//!-
diff --git a/vendor/gopl.io/ch1/echo3/main.go b/vendor/gopl.io/ch1/echo3/main.go
deleted file mode 100644
index 031a650..0000000
--- a/vendor/gopl.io/ch1/echo3/main.go
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
-// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
-
-// See page 8.
-
-// Echo3 prints its command-line arguments.
-package main
-
-import (
- "fmt"
- "os"
- "strings"
-)
-
-//!+
-func main() {
- fmt.Println(strings.Join(os.Args[1:], " "))
-}
-
-//!-
diff --git a/vendor/gopl.io/ch1/fetch/main.go b/vendor/gopl.io/ch1/fetch/main.go
deleted file mode 100644
index e704ae6..0000000
--- a/vendor/gopl.io/ch1/fetch/main.go
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
-// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
-
-// See page 16.
-//!+
-
-// Fetch prints the content found at each specified URL.
-package main
-
-import (
- "fmt"
- "io/ioutil"
- "net/http"
- "os"
-)
-
-func main() {
- for _, url := range os.Args[1:] {
- resp, err := http.Get(url)
- if err != nil {
- fmt.Fprintf(os.Stderr, "fetch: %v\n", err)
- os.Exit(1)
- }
- b, err := ioutil.ReadAll(resp.Body)
- resp.Body.Close()
- if err != nil {
- fmt.Fprintf(os.Stderr, "fetch: reading %s: %v\n", url, err)
- os.Exit(1)
- }
- fmt.Printf("%s", b)
- }
-}
-
-//!-
diff --git a/vendor/gopl.io/ch1/fetchall/main.go b/vendor/gopl.io/ch1/fetchall/main.go
deleted file mode 100644
index ad32109..0000000
--- a/vendor/gopl.io/ch1/fetchall/main.go
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
-// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
-
-// See page 17.
-//!+
-
-// Fetchall fetches URLs in parallel and reports their times and sizes.
-package main
-
-import (
- "fmt"
- "io"
- "io/ioutil"
- "net/http"
- "os"
- "time"
-)
-
-func main() {
- start := time.Now()
- ch := make(chan string)
- for _, url := range os.Args[1:] {
- go fetch(url, ch) // start a goroutine
- }
- for range os.Args[1:] {
- fmt.Println(<-ch) // receive from channel ch
- }
- fmt.Printf("%.2fs elapsed\n", time.Since(start).Seconds())
-}
-
-func fetch(url string, ch chan<- string) {
- start := time.Now()
- resp, err := http.Get(url)
- if err != nil {
- ch <- fmt.Sprint(err) // send to channel ch
- return
- }
-
- nbytes, err := io.Copy(ioutil.Discard, resp.Body)
- resp.Body.Close() // don't leak resources
- if err != nil {
- ch <- fmt.Sprintf("while reading %s: %v", url, err)
- return
- }
- secs := time.Since(start).Seconds()
- ch <- fmt.Sprintf("%.2fs %7d %s", secs, nbytes, url)
-}
-
-//!-
diff --git a/vendor/gopl.io/ch1/helloworld/main.go b/vendor/gopl.io/ch1/helloworld/main.go
deleted file mode 100644
index cd5e0ab..0000000
--- a/vendor/gopl.io/ch1/helloworld/main.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
-// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
-
-// See page 1.
-
-// Helloworld is our first Go program.
-//!+
-package main
-
-import "fmt"
-
-func main() {
- fmt.Println("Hello, 世界")
-}
-
-//!-
diff --git a/vendor/gopl.io/ch1/lissajous/main.go b/vendor/gopl.io/ch1/lissajous/main.go
deleted file mode 100644
index be50e70..0000000
--- a/vendor/gopl.io/ch1/lissajous/main.go
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
-// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
-
-// Run with "web" command-line argument for web server.
-// See page 13.
-//!+main
-
-// Lissajous generates GIF animations of random Lissajous figures.
-package main
-
-import (
- "image"
- "image/color"
- "image/gif"
- "io"
- "math"
- "math/rand"
- "os"
-)
-
-//!-main
-// Packages not needed by version in book.
-import (
- "log"
- "net/http"
- "time"
-)
-
-//!+main
-
-var palette = []color.Color{color.White, color.Black}
-
-const (
- whiteIndex = 0 // first color in palette
- blackIndex = 1 // next color in palette
-)
-
-func main() {
- //!-main
- // The sequence of images is deterministic unless we seed
- // the pseudo-random number generator using the current time.
- // Thanks to Randall McPherson for pointing out the omission.
- rand.Seed(time.Now().UTC().UnixNano())
-
- if len(os.Args) > 1 && os.Args[1] == "web" {
- //!+http
- handler := func(w http.ResponseWriter, r *http.Request) {
- lissajous(w)
- }
- http.HandleFunc("/", handler)
- //!-http
- log.Fatal(http.ListenAndServe("localhost:8000", nil))
- return
- }
- //!+main
- lissajous(os.Stdout)
-}
-
-func lissajous(out io.Writer) {
- const (
- cycles = 5 // number of complete x oscillator revolutions
- res = 0.001 // angular resolution
- size = 100 // image canvas covers [-size..+size]
- nframes = 64 // number of animation frames
- delay = 8 // delay between frames in 10ms units
- )
- freq := rand.Float64() * 3.0 // relative frequency of y oscillator
- anim := gif.GIF{LoopCount: nframes}
- phase := 0.0 // phase difference
- for i := 0; i < nframes; i++ {
- rect := image.Rect(0, 0, 2*size+1, 2*size+1)
- img := image.NewPaletted(rect, palette)
- for t := 0.0; t < cycles*2*math.Pi; t += res {
- x := math.Sin(t)
- y := math.Sin(t*freq + phase)
- img.SetColorIndex(size+int(x*size+0.5), size+int(y*size+0.5),
- blackIndex)
- }
- phase += 0.1
- anim.Delay = append(anim.Delay, delay)
- anim.Image = append(anim.Image, img)
- }
- gif.EncodeAll(out, &anim) // NOTE: ignoring encoding errors
-}
-
-//!-main
diff --git a/vendor/gopl.io/ch1/server1/main.go b/vendor/gopl.io/ch1/server1/main.go
deleted file mode 100644
index 600e92c..0000000
--- a/vendor/gopl.io/ch1/server1/main.go
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
-// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
-
-// See page 19.
-//!+
-
-// Server1 is a minimal "echo" server.
-package main
-
-import (
- "fmt"
- "log"
- "net/http"
-)
-
-func main() {
- http.HandleFunc("/", handler) // each request calls handler
- log.Fatal(http.ListenAndServe("localhost:8000", nil))
-}
-
-// handler echoes the Path component of the requested URL.
-func handler(w http.ResponseWriter, r *http.Request) {
- fmt.Fprintf(w, "URL.Path = %q\n", r.URL.Path)
-}
-
-//!-
diff --git a/vendor/gopl.io/ch1/server2/main.go b/vendor/gopl.io/ch1/server2/main.go
deleted file mode 100644
index dd8ec57..0000000
--- a/vendor/gopl.io/ch1/server2/main.go
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
-// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
-
-// See page 20.
-//!+
-
-// Server2 is a minimal "echo" and counter server.
-package main
-
-import (
- "fmt"
- "log"
- "net/http"
- "sync"
-)
-
-var mu sync.Mutex
-var count int
-
-func main() {
- http.HandleFunc("/", handler)
- http.HandleFunc("/count", counter)
- log.Fatal(http.ListenAndServe("localhost:8000", nil))
-}
-
-// handler echoes the Path component of the requested URL.
-func handler(w http.ResponseWriter, r *http.Request) {
- mu.Lock()
- count++
- mu.Unlock()
- fmt.Fprintf(w, "URL.Path = %q\n", r.URL.Path)
-}
-
-// counter echoes the number of calls so far.
-func counter(w http.ResponseWriter, r *http.Request) {
- mu.Lock()
- fmt.Fprintf(w, "Count %d\n", count)
- mu.Unlock()
-}
-
-//!-
diff --git a/vendor/gopl.io/ch1/server3/main.go b/vendor/gopl.io/ch1/server3/main.go
deleted file mode 100644
index 88c4ad5..0000000
--- a/vendor/gopl.io/ch1/server3/main.go
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
-// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
-
-// See page 21.
-
-// Server3 is an "echo" server that displays request parameters.
-package main
-
-import (
- "fmt"
- "log"
- "net/http"
-)
-
-func main() {
- http.HandleFunc("/", handler)
- log.Fatal(http.ListenAndServe("localhost:8000", nil))
-}
-
-//!+handler
-// handler echoes the HTTP request.
-func handler(w http.ResponseWriter, r *http.Request) {
- fmt.Fprintf(w, "%s %s %s\n", r.Method, r.URL, r.Proto)
- for k, v := range r.Header {
- fmt.Fprintf(w, "Header[%q] = %q\n", k, v)
- }
- fmt.Fprintf(w, "Host = %q\n", r.Host)
- fmt.Fprintf(w, "RemoteAddr = %q\n", r.RemoteAddr)
- if err := r.ParseForm(); err != nil {
- log.Print(err)
- }
- for k, v := range r.Form {
- fmt.Fprintf(w, "Form[%q] = %q\n", k, v)
- }
-}
-
-//!-handler
diff --git a/vendor/gopl.io/ch10/cross/main.go b/vendor/gopl.io/ch10/cross/main.go
deleted file mode 100644
index 1de5cf5..0000000
--- a/vendor/gopl.io/ch10/cross/main.go
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
-// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
-
-// See page 295.
-
-// The cross command prints the values of GOOS and GOARCH for this target.
-package main
-
-import (
- "fmt"
- "runtime"
-)
-
-//!+
-func main() {
- fmt.Println(runtime.GOOS, runtime.GOARCH)
-}
-
-//!-
diff --git a/vendor/gopl.io/ch10/jpeg/main.go b/vendor/gopl.io/ch10/jpeg/main.go
deleted file mode 100644
index ca84efb..0000000
--- a/vendor/gopl.io/ch10/jpeg/main.go
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
-// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
-
-// See page 287.
-
-//!+main
-
-// The jpeg command reads a PNG image from the standard input
-// and writes it as a JPEG image to the standard output.
-package main
-
-import (
- "fmt"
- "image"
- "image/jpeg"
- _ "image/png" // register PNG decoder
- "io"
- "os"
-)
-
-func main() {
- if err := toJPEG(os.Stdin, os.Stdout); err != nil {
- fmt.Fprintf(os.Stderr, "jpeg: %v\n", err)
- os.Exit(1)
- }
-}
-
-func toJPEG(in io.Reader, out io.Writer) error {
- img, kind, err := image.Decode(in)
- if err != nil {
- return err
- }
- fmt.Fprintln(os.Stderr, "Input format =", kind)
- return jpeg.Encode(out, img, &jpeg.Options{Quality: 95})
-}
-
-//!-main
-
-/*
-//!+with
-$ go build gopl.io/ch3/mandelbrot
-$ go build gopl.io/ch10/jpeg
-$ ./mandelbrot | ./jpeg >mandelbrot.jpg
-Input format = png
-//!-with
-
-//!+without
-$ go build gopl.io/ch10/jpeg
-$ ./mandelbrot | ./jpeg >mandelbrot.jpg
-jpeg: image: unknown format
-//!-without
-*/
diff --git a/vendor/gopl.io/ch11/echo/echo.go b/vendor/gopl.io/ch11/echo/echo.go
deleted file mode 100644
index 82b5a3e..0000000
--- a/vendor/gopl.io/ch11/echo/echo.go
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
-// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
-
-// See page 308.
-//!+
-
-// Echo prints its command-line arguments.
-package main
-
-import (
- "flag"
- "fmt"
- "io"
- "os"
- "strings"
-)
-
-var (
- n = flag.Bool("n", false, "omit trailing newline")
- s = flag.String("s", " ", "separator")
-)
-
-var out io.Writer = os.Stdout // modified during testing
-
-func main() {
- flag.Parse()
- if err := echo(!*n, *s, flag.Args()); err != nil {
- fmt.Fprintf(os.Stderr, "echo: %v\n", err)
- os.Exit(1)
- }
-}
-
-func echo(newline bool, sep string, args []string) error {
- fmt.Fprint(out, strings.Join(args, sep))
- if newline {
- fmt.Fprintln(out)
- }
- return nil
-}
-
-//!-
diff --git a/vendor/gopl.io/ch11/echo/echo_test.go b/vendor/gopl.io/ch11/echo/echo_test.go
deleted file mode 100644
index 7d2f47a..0000000
--- a/vendor/gopl.io/ch11/echo/echo_test.go
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
-// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
-
-// Test of echo command. Run with: go test gopl.io/ch11/echo
-
-//!+
-package main
-
-import (
- "bytes"
- "fmt"
- "testing"
-)
-
-func TestEcho(t *testing.T) {
- var tests = []struct {
- newline bool
- sep string
- args []string
- want string
- }{
- {true, "", []string{}, "\n"},
- {false, "", []string{}, ""},
- {true, "\t", []string{"one", "two", "three"}, "one\ttwo\tthree\n"},
- {true, ",", []string{"a", "b", "c"}, "a,b,c\n"},
- {false, ":", []string{"1", "2", "3"}, "1:2:3"},
- }
-
- for _, test := range tests {
- descr := fmt.Sprintf("echo(%v, %q, %q)",
- test.newline, test.sep, test.args)
-
- out = new(bytes.Buffer) // captured output
- if err := echo(test.newline, test.sep, test.args); err != nil {
- t.Errorf("%s failed: %v", descr, err)
- continue
- }
- got := out.(*bytes.Buffer).String()
- if got != test.want {
- t.Errorf("%s = %q, want %q", descr, got, test.want)
- }
- }
-}
-
-//!-
diff --git a/vendor/gopl.io/ch11/storage1/storage.go b/vendor/gopl.io/ch11/storage1/storage.go
deleted file mode 100644
index ed8982c..0000000
--- a/vendor/gopl.io/ch11/storage1/storage.go
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
-// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
-
-// See page 311.
-
-// Package storage is part of a hypothetical cloud storage server.
-//!+main
-package storage
-
-import (
- "fmt"
- "log"
- "net/smtp"
-)
-
-var usage = make(map[string]int64)
-
-func bytesInUse(username string) int64 { return usage[username] }
-
-// Email sender configuration.
-// NOTE: never put passwords in source code!
-const sender = "notifications@example.com"
-const password = "correcthorsebatterystaple"
-const hostname = "smtp.example.com"
-
-const template = `Warning: you are using %d bytes of storage,
-%d%% of your quota.`
-
-func CheckQuota(username string) {
- used := bytesInUse(username)
- const quota = 1000000000 // 1GB
- percent := 100 * used / quota
- if percent < 90 {
- return // OK
- }
- msg := fmt.Sprintf(template, used, percent)
- auth := smtp.PlainAuth("", sender, password, hostname)
- err := smtp.SendMail(hostname+":587", auth, sender,
- []string{username}, []byte(msg))
- if err != nil {
- log.Printf("smtp.SendMail(%s) failed: %s", username, err)
- }
-}
-
-//!-main
diff --git a/vendor/gopl.io/ch11/storage2/quota_test.go b/vendor/gopl.io/ch11/storage2/quota_test.go
deleted file mode 100644
index 2dcd045..0000000
--- a/vendor/gopl.io/ch11/storage2/quota_test.go
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
-// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
-
-//!+test
-package storage
-
-import (
- "strings"
- "testing"
-)
-
-func TestCheckQuotaNotifiesUser(t *testing.T) {
- var notifiedUser, notifiedMsg string
- notifyUser = func(user, msg string) {
- notifiedUser, notifiedMsg = user, msg
- }
-
- const user = "joe@example.org"
- usage[user] = 980000000 // simulate a 980MB-used condition
-
- CheckQuota(user)
- if notifiedUser == "" && notifiedMsg == "" {
- t.Fatalf("notifyUser not called")
- }
- if notifiedUser != user {
- t.Errorf("wrong user (%s) notified, want %s",
- notifiedUser, user)
- }
- const wantSubstring = "98% of your quota"
- if !strings.Contains(notifiedMsg, wantSubstring) {
- t.Errorf("unexpected notification message <<%s>>, "+
- "want substring %q", notifiedMsg, wantSubstring)
- }
-}
-
-//!-test
-
-/*
-//!+defer
-func TestCheckQuotaNotifiesUser(t *testing.T) {
- // Save and restore original notifyUser.
- saved := notifyUser
- defer func() { notifyUser = saved }()
-
- // Install the test's fake notifyUser.
- var notifiedUser, notifiedMsg string
- notifyUser = func(user, msg string) {
- notifiedUser, notifiedMsg = user, msg
- }
- // ...rest of test...
-}
-//!-defer
-*/
diff --git a/vendor/gopl.io/ch11/storage2/storage.go b/vendor/gopl.io/ch11/storage2/storage.go
deleted file mode 100644
index f103fbb..0000000
--- a/vendor/gopl.io/ch11/storage2/storage.go
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
-// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
-
-// See page 312.
-
-// Package storage is part of a hypothetical cloud storage server.
-package storage
-
-import (
- "fmt"
- "log"
- "net/smtp"
-)
-
-var usage = make(map[string]int64)
-
-func bytesInUse(username string) int64 { return usage[username] }
-
-// E-mail sender configuration.
-// NOTE: never put passwords in source code!
-const sender = "notifications@example.com"
-const password = "correcthorsebatterystaple"
-const hostname = "smtp.example.com"
-
-const template = `Warning: you are using %d bytes of storage,
-%d%% of your quota.`
-
-//!+factored
-var notifyUser = func(username, msg string) {
- auth := smtp.PlainAuth("", sender, password, hostname)
- err := smtp.SendMail(hostname+":587", auth, sender,
- []string{username}, []byte(msg))
- if err != nil {
- log.Printf("smtp.SendEmail(%s) failed: %s", username, err)
- }
-}
-
-func CheckQuota(username string) {
- used := bytesInUse(username)
- const quota = 1000000000 // 1GB
- percent := 100 * used / quota
- if percent < 90 {
- return // OK
- }
- msg := fmt.Sprintf(template, used, percent)
- notifyUser(username, msg)
-}
-
-//!-factored
diff --git a/vendor/gopl.io/ch11/word1/word.go b/vendor/gopl.io/ch11/word1/word.go
deleted file mode 100644
index 048abc9..0000000
--- a/vendor/gopl.io/ch11/word1/word.go
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
-// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
-
-// See page 303.
-//!+
-
-// Package word provides utilities for word games.
-package word
-
-// IsPalindrome reports whether s reads the same forward and backward.
-// (Our first attempt.)
-func IsPalindrome(s string) bool {
- for i := range s {
- if s[i] != s[len(s)-1-i] {
- return false
- }
- }
- return true
-}
-
-//!-
diff --git a/vendor/gopl.io/ch11/word1/word_test.go b/vendor/gopl.io/ch11/word1/word_test.go
deleted file mode 100644
index bb53404..0000000
--- a/vendor/gopl.io/ch11/word1/word_test.go
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
-// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
-
-//!+test
-package word
-
-import "testing"
-
-func TestPalindrome(t *testing.T) {
- if !IsPalindrome("detartrated") {
- t.Error(`IsPalindrome("detartrated") = false`)
- }
- if !IsPalindrome("kayak") {
- t.Error(`IsPalindrome("kayak") = false`)
- }
-}
-
-func TestNonPalindrome(t *testing.T) {
- if IsPalindrome("palindrome") {
- t.Error(`IsPalindrome("palindrome") = true`)
- }
-}
-
-//!-test
-
-// The tests below are expected to fail.
-// See package gopl.io/ch11/word2 for the fix.
-
-//!+more
-func TestFrenchPalindrome(t *testing.T) {
- if !IsPalindrome("été") {
- t.Error(`IsPalindrome("été") = false`)
- }
-}
-
-func TestCanalPalindrome(t *testing.T) {
- input := "A man, a plan, a canal: Panama"
- if !IsPalindrome(input) {
- t.Errorf(`IsPalindrome(%q) = false`, input)
- }
-}
-
-//!-more
diff --git a/vendor/gopl.io/ch11/word2/word.go b/vendor/gopl.io/ch11/word2/word.go
deleted file mode 100644
index 846c8d2..0000000
--- a/vendor/gopl.io/ch11/word2/word.go
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
-// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
-
-// See page 305.
-//!+
-
-// Package word provides utilities for word games.
-package word
-
-import "unicode"
-
-// IsPalindrome reports whether s reads the same forward and backward.
-// Letter case is ignored, as are non-letters.
-func IsPalindrome(s string) bool {
- var letters []rune
- for _, r := range s {
- if unicode.IsLetter(r) {
- letters = append(letters, unicode.ToLower(r))
- }
- }
- for i := range letters {
- if letters[i] != letters[len(letters)-1-i] {
- return false
- }
- }
- return true
-}
-
-//!-
diff --git a/vendor/gopl.io/ch11/word2/word_test.go b/vendor/gopl.io/ch11/word2/word_test.go
deleted file mode 100644
index 4b17337..0000000
--- a/vendor/gopl.io/ch11/word2/word_test.go
+++ /dev/null
@@ -1,148 +0,0 @@
-// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
-// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
-
-package word
-
-import (
- "fmt"
- "math/rand"
- "time"
-)
-
-//!+bench
-
-import "testing"
-
-//!-bench
-
-//!+test
-func TestIsPalindrome(t *testing.T) {
- var tests = []struct {
- input string
- want bool
- }{
- {"", true},
- {"a", true},
- {"aa", true},
- {"ab", false},
- {"kayak", true},
- {"detartrated", true},
- {"A man, a plan, a canal: Panama", true},
- {"Evil I did dwell; lewd did I live.", true},
- {"Able was I ere I saw Elba", true},
- {"été", true},
- {"Et se resservir, ivresse reste.", true},
- {"palindrome", false}, // non-palindrome
- {"desserts", false}, // semi-palindrome
- }
- for _, test := range tests {
- if got := IsPalindrome(test.input); got != test.want {
- t.Errorf("IsPalindrome(%q) = %v", test.input, got)
- }
- }
-}
-
-//!-test
-
-//!+bench
-func BenchmarkIsPalindrome(b *testing.B) {
- for i := 0; i < b.N; i++ {
- IsPalindrome("A man, a plan, a canal: Panama")
- }
-}
-
-//!-bench
-
-//!+example
-
-func ExampleIsPalindrome() {
- fmt.Println(IsPalindrome("A man, a plan, a canal: Panama"))
- fmt.Println(IsPalindrome("palindrome"))
- // Output:
- // true
- // false
-}
-
-//!-example
-
-/*
-//!+random
-import "math/rand"
-
-//!-random
-*/
-
-//!+random
-// randomPalindrome returns a palindrome whose length and contents
-// are derived from the pseudo-random number generator rng.
-func randomPalindrome(rng *rand.Rand) string {
- n := rng.Intn(25) // random length up to 24
- runes := make([]rune, n)
- for i := 0; i < (n+1)/2; i++ {
- r := rune(rng.Intn(0x1000)) // random rune up to '\u0999'
- runes[i] = r
- runes[n-1-i] = r
- }
- return string(runes)
-}
-
-func TestRandomPalindromes(t *testing.T) {
- // Initialize a pseudo-random number generator.
- seed := time.Now().UTC().UnixNano()
- t.Logf("Random seed: %d", seed)
- rng := rand.New(rand.NewSource(seed))
-
- for i := 0; i < 1000; i++ {
- p := randomPalindrome(rng)
- if !IsPalindrome(p) {
- t.Errorf("IsPalindrome(%q) = false", p)
- }
- }
-}
-
-//!-random
-
-/*
-// Answer for Exercicse 11.1: Modify randomPalindrome to exercise
-// IsPalindrome's handling of punctuation and spaces.
-
-// WARNING: the conversion r -> upper -> lower doesn't preserve
-// the value of r in some cases, e.g., µ Μ, ſ S, ı I
-
-// randomPalindrome returns a palindrome whose length and contents
-// are derived from the pseudo-random number generator rng.
-func randomNoisyPalindrome(rng *rand.Rand) string {
- n := rng.Intn(25) // random length up to 24
- runes := make([]rune, n)
- for i := 0; i < (n+1)/2; i++ {
- r := rune(rng.Intn(0x200)) // random rune up to \u99
- runes[i] = r
- r1 := r
- if unicode.IsLetter(r) && unicode.IsLower(r) {
- r = unicode.ToUpper(r)
- if unicode.ToLower(r) != r1 {
- fmt.Printf("cap? %c %c\n", r1, r)
- }
- }
- runes[n-1-i] = r
- }
- return "?" + string(runes) + "!"
-}
-
-func TestRandomNoisyPalindromes(t *testing.T) {
- // Initialize a pseudo-random number generator.
- seed := time.Now().UTC().UnixNano()
- t.Logf("Random seed: %d", seed)
- rng := rand.New(rand.NewSource(seed))
-
- n := 0
- for i := 0; i < 1000; i++ {
- p := randomNoisyPalindrome(rng)
- if !IsPalindrome(p) {
- t.Errorf("IsNoisyPalindrome(%q) = false", p)
- n++
- }
- }
- fmt.Fprintf(os.Stderr, "fail = %d\n", n)
-}
-*/
diff --git a/vendor/gopl.io/ch12/display/display.go b/vendor/gopl.io/ch12/display/display.go
deleted file mode 100644
index 933a5b0..0000000
--- a/vendor/gopl.io/ch12/display/display.go
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
-// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
-
-// See page 333.
-
-// Package display provides a means to display structured data.
-package display
-
-import (
- "fmt"
- "reflect"
- "strconv"
-)
-
-//!+Display
-
-func Display(name string, x interface{}) {
- fmt.Printf("Display %s (%T):\n", name, x)
- display(name, reflect.ValueOf(x))
-}
-
-//!-Display
-
-// formatAtom formats a value without inspecting its internal structure.
-// It is a copy of the the function in gopl.io/ch11/format.
-func formatAtom(v reflect.Value) string {
- switch v.Kind() {
- case reflect.Invalid:
- return "invalid"
- case reflect.Int, reflect.Int8, reflect.Int16,
- reflect.Int32, reflect.Int64:
- return strconv.FormatInt(v.Int(), 10)
- case reflect.Uint, reflect.Uint8, reflect.Uint16,
- reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- return strconv.FormatUint(v.Uint(), 10)
- // ...floating-point and complex cases omitted for brevity...
- case reflect.Bool:
- if v.Bool() {
- return "true"
- }
- return "false"
- case reflect.String:
- return strconv.Quote(v.String())
- case reflect.Chan, reflect.Func, reflect.Ptr,
- reflect.Slice, reflect.Map:
- return v.Type().String() + " 0x" +
- strconv.FormatUint(uint64(v.Pointer()), 16)
- default: // reflect.Array, reflect.Struct, reflect.Interface
- return v.Type().String() + " value"
- }
-}
-
-//!+display
-func display(path string, v reflect.Value) {
- switch v.Kind() {
- case reflect.Invalid:
- fmt.Printf("%s = invalid\n", path)
- case reflect.Slice, reflect.Array:
- for i := 0; i < v.Len(); i++ {
- display(fmt.Sprintf("%s[%d]", path, i), v.Index(i))
- }
- case reflect.Struct:
- for i := 0; i < v.NumField(); i++ {
- fieldPath := fmt.Sprintf("%s.%s", path, v.Type().Field(i).Name)
- display(fieldPath, v.Field(i))
- }
- case reflect.Map:
- for _, key := range v.MapKeys() {
- display(fmt.Sprintf("%s[%s]", path,
- formatAtom(key)), v.MapIndex(key))
- }
- case reflect.Ptr:
- if v.IsNil() {
- fmt.Printf("%s = nil\n", path)
- } else {
- display(fmt.Sprintf("(*%s)", path), v.Elem())
- }
- case reflect.Interface:
- if v.IsNil() {
- fmt.Printf("%s = nil\n", path)
- } else {
- fmt.Printf("%s.type = %s\n", path, v.Elem().Type())
- display(path+".value", v.Elem())
- }
- default: // basic types, channels, funcs
- fmt.Printf("%s = %s\n", path, formatAtom(v))
- }
-}
-
-//!-display
diff --git a/vendor/gopl.io/ch12/display/display_test.go b/vendor/gopl.io/ch12/display/display_test.go
deleted file mode 100644
index bc847ce..0000000
--- a/vendor/gopl.io/ch12/display/display_test.go
+++ /dev/null
@@ -1,259 +0,0 @@
-// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
-// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
-
-package display
-
-import (
- "io"
- "net"
- "os"
- "reflect"
- "sync"
- "testing"
-
- "gopl.io/ch7/eval"
-)
-
-// NOTE: we can't use !+..!- comments to excerpt these tests
-// into the book because it defeats the Example mechanism,
-// which requires the // Output comment to be at the end
-// of the function.
-
-func Example_expr() {
- e, _ := eval.Parse("sqrt(A / pi)")
- Display("e", e)
- // Output:
- // Display e (eval.call):
- // e.fn = "sqrt"
- // e.args[0].type = eval.binary
- // e.args[0].value.op = 47
- // e.args[0].value.x.type = eval.Var
- // e.args[0].value.x.value = "A"
- // e.args[0].value.y.type = eval.Var
- // e.args[0].value.y.value = "pi"
-}
-
-func Example_slice() {
- Display("slice", []*int{new(int), nil})
- // Output:
- // Display slice ([]*int):
- // (*slice[0]) = 0
- // slice[1] = nil
-}
-
-func Example_nilInterface() {
- var w io.Writer
- Display("w", w)
- // Output:
- // Display w (