├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── exercises.tar.gz ├── resources ├── gopher.gif ├── gopher.png └── gordon_golang.png └── workspaces ├── README.md ├── aidylewis └── chapter1 │ ├── 1-1 │ └── main.go │ ├── 1-2 │ └── main.go │ ├── 1-3 │ └── main.go │ ├── 1-4 │ ├── 1.txt │ ├── 2.txt │ ├── 3.txt │ └── main.go │ ├── 1-7 │ └── main.go │ ├── 1-8 │ └── main.go │ └── 1-9 │ └── main.go ├── bbcmgdm └── exercises │ ├── 01_tutorial │ └── README.md │ ├── 02_program_structure │ └── README.md │ ├── 03_basic_data_types │ └── README.md │ ├── 04_composite_types │ └── README.md │ ├── 05_functions │ └── README.md │ ├── 06_methods │ └── README.md │ ├── 07_interfaces │ └── README.md │ ├── 08_goroutines_and_channels │ └── README.md │ ├── 09_concurrency_with_shared_variables │ └── README.md │ ├── 10_packages_and_the_go_tool │ └── README.md │ ├── 11_testing │ └── README.md │ ├── 12_reflection │ └── README.md │ └── 13_low_level_programming │ └── README.md ├── betandr ├── bin │ ├── echo3 │ └── helloworld ├── exercises │ ├── 01_tutorial │ │ └── README.md │ ├── 02_program_structure │ │ └── README.md │ ├── 03_basic_data_types │ │ └── README.md │ ├── 04_composite_types │ │ └── README.md │ ├── 05_functions │ │ └── README.md │ ├── 06_methods │ │ └── README.md │ ├── 07_interfaces │ │ └── README.md │ ├── 08_goroutines_and_channels │ │ └── README.md │ ├── 09_concurrency_with_shared_variables │ │ └── README.md │ ├── 10_packages_and_the_go_tool │ │ └── README.md │ ├── 11_testing │ │ └── README.md │ ├── 12_reflection │ │ └── README.md │ └── 13_low_level_programming │ │ └── README.md └── src │ └── andr.io │ ├── ch1 │ ├── ex1_1 │ │ └── main.go │ ├── ex1_10 │ │ └── main.go │ ├── ex1_12 │ │ └── main.go │ ├── ex1_2 │ │ └── main.go │ ├── ex1_3 │ │ └── main.go │ ├── ex1_4 │ │ ├── file1.txt │ │ ├── file2.txt │ │ └── main.go │ ├── ex1_5 │ │ ├── main.go │ │ └── out.gif │ ├── ex1_6 │ │ ├── main.go │ │ └── out.gif │ ├── ex1_7 │ │ └── main.go │ ├── ex1_8 │ │ └── main.go │ └── ex1_9 │ │ └── main.go │ ├── ch2 │ ├── ex2_1 │ │ ├── conv.go │ │ └── tempconv.go │ ├── ex2_2 │ │ ├── main.go │ │ └── weightconv │ │ │ ├── conv.go │ │ │ └── weightconv.go │ ├── ex2_3 │ │ ├── main.go │ │ └── popcount │ │ │ ├── main.go │ │ │ └── popcount_test.go │ ├── ex2_4 │ │ ├── main.go │ │ └── popcount │ │ │ ├── main.go │ │ │ └── popcount_test.go │ └── ex2_5 │ │ ├── main.go │ │ └── popcount │ │ ├── main.go │ │ └── popcount_test.go │ ├── ch3 │ ├── ex3_1 │ │ ├── main.go │ │ └── plot.svg │ ├── ex3_10 │ │ └── main.go │ ├── ex3_11 │ │ └── main.go │ ├── ex3_12 │ │ └── main.go │ ├── ex3_13 │ │ └── main.go │ ├── ex3_2 │ │ ├── main.go │ │ └── plot.svg │ ├── ex3_3 │ │ ├── main.go │ │ └── plot.svg │ ├── ex3_4 │ │ └── main.go │ ├── ex3_5 │ │ ├── main.go │ │ └── mandelbrot.png │ ├── ex3_6 │ │ ├── main.go │ │ └── mandelbrot_supersampled.png │ ├── ex3_7 │ │ ├── main.go │ │ └── newton.png │ ├── ex3_8 │ │ ├── main.go │ │ ├── mandelbrot.png │ │ └── mandelbrot │ │ │ ├── main.go │ │ │ └── mandelbrot_test.go │ └── ex3_9 │ │ ├── curl.sh │ │ └── main.go │ ├── ch4 │ ├── ex4_1 │ │ ├── main.go │ │ └── popcount │ │ │ └── main.go │ ├── ex4_10 │ │ ├── github │ │ │ ├── github.go │ │ │ └── search.go │ │ └── main.go │ ├── ex4_11 │ │ ├── github │ │ │ ├── github.go │ │ │ └── pull_requests.go │ │ └── main.go │ ├── ex4_12 │ │ ├── download.sh │ │ └── main.go │ ├── ex4_13 │ │ └── main.go │ ├── ex4_14 │ │ ├── github │ │ │ ├── github.go │ │ │ └── search.go │ │ └── main.go │ ├── ex4_2 │ │ └── main.go │ ├── ex4_3 │ │ └── main.go │ ├── ex4_4 │ │ └── main.go │ ├── ex4_5 │ │ └── main.go │ ├── ex4_6 │ │ └── main.go │ ├── ex4_7 │ │ └── main.go │ ├── ex4_8 │ │ └── main.go │ └── ex4_9 │ │ └── main.go │ ├── ch5 │ ├── ex5_1 │ │ └── main.go │ ├── ex5_10 │ │ ├── main.go │ │ ├── prereqs.dot │ │ └── prereqs.png │ ├── ex5_11 │ │ ├── main.go │ │ ├── prereqs.dot │ │ └── prereqs.png │ ├── ex5_12 │ │ └── main.go │ ├── ex5_13 │ │ └── main.go │ ├── ex5_14 │ │ └── main.go │ ├── ex5_15 │ │ └── main.go │ ├── ex5_16 │ │ └── main.go │ ├── ex5_17 │ │ └── main.go │ ├── ex5_18 │ │ └── main.go │ ├── ex5_19 │ │ └── main.go │ ├── ex5_2 │ │ └── main.go │ ├── ex5_3 │ │ └── main.go │ ├── ex5_4 │ │ └── main.go │ ├── ex5_5 │ │ └── main.go │ ├── ex5_6 │ │ └── main.go │ ├── ex5_7 │ │ └── main.go │ ├── ex5_8 │ │ └── main.go │ └── ex5_9 │ │ └── main.go │ ├── ch6 │ ├── ex6_1 │ │ └── main.go │ ├── ex6_2 │ │ └── main.go │ ├── ex6_3 │ │ └── main.go │ ├── ex6_4 │ │ └── main.go │ └── ex6_5 │ │ └── main.go │ ├── ch7 │ ├── ex7_1 │ │ └── main.go │ ├── ex7_10 │ │ └── main.go │ ├── ex7_11 │ │ └── main.go │ ├── ex7_12 │ │ └── main.go │ ├── ex7_13 │ │ ├── ast.go │ │ ├── check.go │ │ ├── coverage_test.go │ │ ├── eval.go │ │ ├── eval │ │ │ ├── ast.go │ │ │ ├── brace.go │ │ │ ├── check.go │ │ │ ├── coverage_test.go │ │ │ ├── eval.go │ │ │ ├── eval_test.go │ │ │ ├── parse.go │ │ │ ├── print.go │ │ │ ├── string.go │ │ │ └── string_test.go │ │ ├── eval_test.go │ │ ├── parse.go │ │ ├── print.go │ │ └── string.go │ ├── ex7_14 │ │ └── eval │ │ │ ├── ast.go │ │ │ ├── brace.go │ │ │ ├── check.go │ │ │ ├── coverage_test.go │ │ │ ├── eval.go │ │ │ ├── eval_test.go │ │ │ ├── min_test.go │ │ │ ├── parse.go │ │ │ ├── print.go │ │ │ ├── string.go │ │ │ └── string_test.go │ ├── ex7_15 │ │ ├── eval │ │ │ ├── ast.go │ │ │ ├── brace.go │ │ │ ├── check.go │ │ │ ├── coverage_test.go │ │ │ ├── eval.go │ │ │ ├── eval_test.go │ │ │ ├── min_test.go │ │ │ ├── parse.go │ │ │ ├── print.go │ │ │ ├── string.go │ │ │ ├── string_test.go │ │ │ └── vars.go │ │ └── main.go │ ├── ex7_16 │ │ ├── main.go │ │ └── templates │ │ │ └── index.html │ ├── ex7_17 │ │ └── main.go │ ├── ex7_18 │ │ └── main.go │ ├── ex7_2 │ │ └── main.go │ ├── ex7_3 │ │ ├── main.go │ │ └── treesort │ │ │ └── sort.go │ ├── ex7_4 │ │ └── main.go │ ├── ex7_5 │ │ └── main.go │ ├── ex7_6 │ │ ├── main.go │ │ └── tempconv │ │ │ └── tempconv.go │ ├── ex7_8 │ │ ├── main.go │ │ └── music │ │ │ └── sort.go │ └── ex7_9 │ │ ├── css │ │ ├── main.css │ │ └── util.css │ │ ├── fonts │ │ ├── Lato │ │ │ ├── Lato-Black.ttf │ │ │ ├── Lato-BlackItalic.ttf │ │ │ ├── Lato-Bold.ttf │ │ │ ├── Lato-BoldItalic.ttf │ │ │ ├── Lato-Hairline.ttf │ │ │ ├── Lato-HairlineItalic.ttf │ │ │ ├── Lato-Italic.ttf │ │ │ ├── Lato-Light.ttf │ │ │ ├── Lato-LightItalic.ttf │ │ │ ├── Lato-Regular.ttf │ │ │ └── OFL.txt │ │ ├── OpenSans │ │ │ ├── OpenSans-Bold.ttf │ │ │ ├── OpenSans-BoldItalic.ttf │ │ │ ├── OpenSans-ExtraBold.ttf │ │ │ ├── OpenSans-ExtraBoldItalic.ttf │ │ │ ├── OpenSans-Italic.ttf │ │ │ ├── OpenSans-Light.ttf │ │ │ ├── OpenSans-LightItalic.ttf │ │ │ ├── OpenSans-Regular.otf │ │ │ ├── OpenSans-Regular.ttf │ │ │ ├── OpenSans-SemiBold.ttf │ │ │ └── OpenSans-SemiBoldItalic.ttf │ │ ├── font-awesome-4.7.0 │ │ │ ├── HELP-US-OUT.txt │ │ │ ├── css │ │ │ │ ├── font-awesome.css │ │ │ │ └── font-awesome.min.css │ │ │ ├── fonts │ │ │ │ ├── FontAwesome.otf │ │ │ │ ├── fontawesome-webfont.eot │ │ │ │ ├── fontawesome-webfont.svg │ │ │ │ ├── fontawesome-webfont.ttf │ │ │ │ ├── fontawesome-webfont.woff │ │ │ │ └── fontawesome-webfont.woff2 │ │ │ ├── less │ │ │ │ ├── animated.less │ │ │ │ ├── bordered-pulled.less │ │ │ │ ├── core.less │ │ │ │ ├── fixed-width.less │ │ │ │ ├── font-awesome.less │ │ │ │ ├── icons.less │ │ │ │ ├── larger.less │ │ │ │ ├── list.less │ │ │ │ ├── mixins.less │ │ │ │ ├── path.less │ │ │ │ ├── rotated-flipped.less │ │ │ │ ├── screen-reader.less │ │ │ │ ├── stacked.less │ │ │ │ └── variables.less │ │ │ └── scss │ │ │ │ ├── _animated.scss │ │ │ │ ├── _bordered-pulled.scss │ │ │ │ ├── _core.scss │ │ │ │ ├── _fixed-width.scss │ │ │ │ ├── _icons.scss │ │ │ │ ├── _larger.scss │ │ │ │ ├── _list.scss │ │ │ │ ├── _mixins.scss │ │ │ │ ├── _path.scss │ │ │ │ ├── _rotated-flipped.scss │ │ │ │ ├── _screen-reader.scss │ │ │ │ ├── _stacked.scss │ │ │ │ ├── _variables.scss │ │ │ │ └── font-awesome.scss │ │ └── montserrat │ │ │ ├── Montserrat-Black.ttf │ │ │ ├── Montserrat-BlackItalic.ttf │ │ │ ├── Montserrat-Bold.ttf │ │ │ ├── Montserrat-BoldItalic.ttf │ │ │ ├── Montserrat-ExtraBold.ttf │ │ │ ├── Montserrat-ExtraBoldItalic.ttf │ │ │ ├── Montserrat-ExtraLight.ttf │ │ │ ├── Montserrat-ExtraLightItalic.ttf │ │ │ ├── Montserrat-Italic.ttf │ │ │ ├── Montserrat-Light.ttf │ │ │ ├── Montserrat-LightItalic.ttf │ │ │ ├── Montserrat-Medium.ttf │ │ │ ├── Montserrat-MediumItalic.ttf │ │ │ ├── Montserrat-Regular.ttf │ │ │ ├── Montserrat-SemiBold.ttf │ │ │ ├── Montserrat-SemiBoldItalic.ttf │ │ │ ├── Montserrat-Thin.ttf │ │ │ ├── Montserrat-ThinItalic.ttf │ │ │ └── OFL.txt │ │ ├── images │ │ └── icons │ │ │ └── favicon.ico │ │ ├── js │ │ └── main.js │ │ ├── main.go │ │ ├── music │ │ └── sort.go │ │ ├── templates │ │ └── index.html │ │ └── vendor │ │ ├── animate │ │ └── animate.css │ │ ├── bootstrap │ │ ├── css │ │ │ ├── bootstrap-grid.css │ │ │ ├── bootstrap-grid.css.map │ │ │ ├── bootstrap-grid.min.css │ │ │ ├── bootstrap-grid.min.css.map │ │ │ ├── bootstrap-reboot.css │ │ │ ├── bootstrap-reboot.css.map │ │ │ ├── bootstrap-reboot.min.css │ │ │ ├── bootstrap-reboot.min.css.map │ │ │ ├── bootstrap.css │ │ │ ├── bootstrap.css.map │ │ │ ├── bootstrap.min.css │ │ │ └── bootstrap.min.css.map │ │ └── js │ │ │ ├── bootstrap.js │ │ │ ├── bootstrap.min.js │ │ │ ├── popper.js │ │ │ ├── popper.min.js │ │ │ └── tooltip.js │ │ ├── jquery │ │ └── jquery-3.2.1.min.js │ │ ├── perfect-scrollbar │ │ ├── perfect-scrollbar.css │ │ └── perfect-scrollbar.min.js │ │ └── select2 │ │ ├── select2.css │ │ ├── select2.js │ │ ├── select2.min.css │ │ └── select2.min.js │ └── ch8 │ ├── ex8_1 │ ├── clock2 │ │ └── main.go │ └── clockwall │ │ └── main.go │ ├── ex8_2 │ └── main.go │ ├── ex8_3 │ └── main.go │ └── ex8_4 │ └── main.go ├── garymacindoe ├── bin │ └── .keep ├── exercises │ ├── 01_tutorial │ │ └── README.md │ ├── 02_program_structure │ │ └── README.md │ ├── 03_basic_data_types │ │ └── README.md │ ├── 04_composite_types │ │ └── README.md │ ├── 05_functions │ │ └── README.md │ ├── 06_methods │ │ └── README.md │ ├── 07_interfaces │ │ └── README.md │ ├── 08_goroutines_and_channels │ │ └── README.md │ ├── 09_concurrency_with_shared_variables │ │ └── README.md │ ├── 10_packages_and_the_go_tool │ │ └── README.md │ ├── 11_testing │ │ └── README.md │ ├── 12_reflection │ │ └── README.md │ └── 13_low_level_programming │ │ └── README.md └── src │ └── garymacindoe.co.uk │ ├── ch1 │ ├── ex1_1 │ │ └── main.go │ ├── ex1_10 │ │ └── main.go │ ├── ex1_2 │ │ └── main.go │ ├── ex1_3 │ │ └── main.go │ ├── ex1_4 │ │ └── main.go │ ├── ex1_5 │ │ └── main.go │ ├── ex1_6 │ │ └── main.go │ ├── ex1_7 │ │ └── main.go │ ├── ex1_8 │ │ └── main.go │ └── ex1_9 │ │ └── main.go │ ├── ch2 │ ├── cf │ │ └── main.go │ ├── lengthconv │ │ ├── conv.go │ │ └── lengthconv.go │ ├── popcount │ │ ├── main.go │ │ └── popcount_test.go │ ├── tempconv │ │ ├── conv.go │ │ └── tempconv.go │ └── weightconv │ │ ├── conv.go │ │ └── weightconv.go │ ├── ch3 │ └── surface │ │ └── main.go │ └── mandelbrot │ └── main.go └── kodjobaah └── src ├── chapter1 ├── 4 │ └── dup2.go ├── 12 │ └── server4.go ├── 1-3 │ ├── exercise11.go │ ├── exercise12.go │ └── exercise13.go ├── 10-11 │ └── fetchall-10.go ├── 5-6 │ ├── lissajous-5.go │ └── lissajous-6.go └── 7-9 │ ├── fetch-7.go │ ├── fetch-8.go │ └── fetch-9.go ├── chapter2 ├── ex1 │ └── tempConv │ │ ├── conv.go │ │ └── tempconv.go ├── ex2 │ ├── conversion │ │ ├── conversion.go │ │ └── conversion_test.go │ ├── file1 │ └── unitConversion.go └── ex3_5 │ ├── README.md │ ├── popcount │ └── popcount.go │ └── popcount_test.go ├── chapter3 ├── ex1 │ ├── mesh.svg │ ├── results.svg │ ├── surface │ └── surface.go ├── ex10 │ └── comma.go ├── ex11 │ └── comma.go ├── ex12 │ └── anagram.go ├── ex13 │ └── const.go ├── ex4 │ ├── server4 │ ├── server4.go │ └── surface.go └── ex5 │ ├── mandelbrot │ └── mandelbrot.go └── chapter4 ├── append └── append.go ├── charcount └── charcount.go ├── dup └── dup.go ├── embed └── embed.go ├── ex1 └── countSha356.go ├── ex10 └── main.go ├── ex2 └── sha256.go ├── ex3 ├── reverse.go ├── test.go ├── test1.go └── test2.go ├── ex4 └── rotate.go ├── ex5 └── inplace.go ├── ex6 └── squash.go ├── ex7 ├── reverse.go └── squash.go ├── ex8 └── charcount.go ├── ex9 ├── file.txt └── wordfreq.go ├── github └── github.go ├── issues └── issues.go ├── movie └── movie.go ├── nonempty └── nonempty.go ├── remove └── remove.go ├── rev └── rev.go ├── sha256 └── sha256.go └── treesort └── treesort.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | pkg/ 9 | 10 | # Test binary, build with `go test -c` 11 | *.test 12 | 13 | # Output of the go coverage tool, specifically when used with LiteIDE 14 | *.out 15 | 16 | *.DS_Store 17 | 18 | workspaces/betandr/bin 19 | workspaces/betandr/src/github.com 20 | workspaces/betandr/src/gopl.io 21 | workspaces/betandr/src/golang.org 22 | workspaces/betandr/src/andr.io/ch4/ex4_12/index 23 | 24 | workspaces/garymacindoe/bin/* 25 | !workspaces/garymacindoe/bin/.keep 26 | workspaces/garymacindoe/src/* 27 | !workspaces/garymacindoe/src/garymacindoe.co.uk 28 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "path_to_submodule"] 2 | path = workspaces/betandr/src/gopl.io 3 | url = https://github.com/adonovan/gopl.io.git 4 | -------------------------------------------------------------------------------- /exercises.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bbc/eng-golang-workshop/94c99f4a002654404c945c3c94f437c720039b83/exercises.tar.gz -------------------------------------------------------------------------------- /resources/gopher.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bbc/eng-golang-workshop/94c99f4a002654404c945c3c94f437c720039b83/resources/gopher.gif -------------------------------------------------------------------------------- /resources/gopher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bbc/eng-golang-workshop/94c99f4a002654404c945c3c94f437c720039b83/resources/gopher.png -------------------------------------------------------------------------------- /resources/gordon_golang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bbc/eng-golang-workshop/94c99f4a002654404c945c3c94f437c720039b83/resources/gordon_golang.png -------------------------------------------------------------------------------- /workspaces/README.md: -------------------------------------------------------------------------------- 1 | Add your workspaces here. 2 | -------------------------------------------------------------------------------- /workspaces/aidylewis/chapter1/1-1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strings" 7 | ) 8 | 9 | func main() { 10 | fmt.Println(strings.Join(os.Args, " ")) 11 | } 12 | -------------------------------------------------------------------------------- /workspaces/aidylewis/chapter1/1-2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | func main() { 9 | for ind, arg := range os.Args[1:] { 10 | fmt.Println(ind, " ", arg) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /workspaces/aidylewis/chapter1/1-3/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Usage: 4 | // go run main.go {1..19300} 5 | 6 | import ( 7 | "fmt" 8 | "os" 9 | "strings" 10 | "time" 11 | ) 12 | 13 | func inefficient() { 14 | s, sep := "", "" 15 | for _, arg := range os.Args[1:] { 16 | s += sep + arg 17 | sep = " " 18 | } 19 | } 20 | 21 | func efficient() { 22 | strings.Join(os.Args[1:], " ") 23 | } 24 | 25 | func main() { 26 | startIneff := time.Now() 27 | inefficient() 28 | secsIneff := time.Since(startIneff).Seconds() 29 | startEff := time.Now() 30 | efficient() 31 | secsEff := time.Since(startEff).Seconds() 32 | fmt.Println(secsIneff) 33 | fmt.Println(secsEff) 34 | } 35 | -------------------------------------------------------------------------------- /workspaces/aidylewis/chapter1/1-4/1.txt: -------------------------------------------------------------------------------- 1 | aidy 2 | -------------------------------------------------------------------------------- /workspaces/aidylewis/chapter1/1-4/2.txt: -------------------------------------------------------------------------------- 1 | aidy 2 | adie 3 | ad 4 | -------------------------------------------------------------------------------- /workspaces/aidylewis/chapter1/1-4/3.txt: -------------------------------------------------------------------------------- 1 | lewis 2 | -------------------------------------------------------------------------------- /workspaces/aidylewis/chapter1/1-4/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Usage: 4 | // go run main.go 1.txt 2.txt 3.txt 5 | 6 | import ( 7 | "bufio" 8 | "fmt" 9 | "os" 10 | ) 11 | 12 | func main() { 13 | counts := make(map[string]map[string]int) 14 | files := os.Args[1:] 15 | 16 | if len(files) == 0 { 17 | countLines(os.Stdin, counts) 18 | } else { 19 | for _, arg := range files { 20 | f, err := os.Open(arg) 21 | if err != nil { 22 | continue 23 | } 24 | countLines(f, counts) 25 | f.Close() 26 | } 27 | } 28 | 29 | for line, fileMap := range counts { 30 | total := 0 31 | for _, n := range fileMap { 32 | total += n 33 | } 34 | 35 | if total > 1 { 36 | fmt.Printf("%d %s\n", total, line) 37 | 38 | for file, n := range fileMap { 39 | fmt.Printf("%d %s\n", n, file) 40 | } 41 | } 42 | } 43 | } 44 | 45 | func countLines(f *os.File, counts map[string]map[string]int) { 46 | input := bufio.NewScanner(f) 47 | for input.Scan() { 48 | line := input.Text() 49 | 50 | if counts[line] == nil { 51 | m := make(map[string]int) 52 | counts[line] = m 53 | } 54 | 55 | counts[line][f.Name()]++ 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /workspaces/aidylewis/chapter1/1-7/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "net/http" 7 | "os" 8 | ) 9 | 10 | func main() { 11 | for _, url := range os.Args[1:] { 12 | resp, err := http.Get(url) 13 | if err != nil { 14 | fmt.Fprintf(os.Stderr, "fetch: %v\n", err) 15 | os.Exit(1) 16 | } 17 | _, err = io.Copy(os.Stdout, resp.Body) 18 | resp.Body.Close() 19 | if err != nil { 20 | fmt.Fprintf(os.Stderr, "fetch: reading %s: %v\n", url, err) 21 | os.Exit(1) 22 | } 23 | 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /workspaces/aidylewis/chapter1/1-8/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "net/http" 7 | "os" 8 | "strings" 9 | ) 10 | 11 | func main() { 12 | const protocol = "http://" 13 | for _, url := range os.Args[1:] { 14 | if !strings.HasPrefix(url, protocol) { 15 | url = protocol + url 16 | } 17 | resp, err := http.Get(url) 18 | if err != nil { 19 | fmt.Fprintf(os.Stderr, "fetch: %v\n", err) 20 | os.Exit(1) 21 | } 22 | _, err = io.Copy(os.Stdout, resp.Body) 23 | resp.Body.Close() 24 | if err != nil { 25 | fmt.Fprintf(os.Stderr, "fetch: reading %s: %v\n", url, err) 26 | os.Exit(1) 27 | } 28 | 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /workspaces/aidylewis/chapter1/1-9/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "net/http" 7 | "os" 8 | "strings" 9 | ) 10 | 11 | func main() { 12 | const protocol = "http://" 13 | for _, url := range os.Args[1:] { 14 | if !strings.HasPrefix(url, protocol) { 15 | url = protocol + url 16 | } 17 | resp, err := http.Get(url) 18 | if err != nil { 19 | fmt.Fprintf(os.Stderr, "fetch: %v\n", err) 20 | os.Exit(1) 21 | } 22 | _, err = io.Copy(os.Stdout, resp.Body) 23 | resp.Body.Close() 24 | if err != nil { 25 | fmt.Fprintf(os.Stderr, "fetch: reading %s: %v\n", url, err) 26 | os.Exit(1) 27 | } 28 | 29 | fmt.Printf("\nStatus code: %s\n", resp.Status) 30 | 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /workspaces/bbcmgdm/exercises/02_program_structure/README.md: -------------------------------------------------------------------------------- 1 | # Chapter 2 - Program Structure 2 | 3 | ## Packages and Files 4 | 5 | ### Exercise 2.1 6 | Add types, constants, and functions to `tempconv` for processing temperatures 7 | in the Kelvin scale, where Kelvin is -273.15°C and a difference of 1K 8 | has the same magnitude as 1°C. 9 | 10 | ## Imports 11 | 12 | ### Exercise 2.2 13 | Write a general purpose unit-conversion program analogous to `cf` that reads 14 | numbers from its command-line arguments or from the standard imput if there are 15 | no arguments, and converts each nunber into units like temperature in Celsius 16 | and Fahrenheit, length in feet and meters, weight in pounds, kilograms, and the 17 | like. 18 | 19 | ## Package Initialization 20 | 21 | ### Exercise 2.3 22 | Rewrite `PopCount` to use a loop instead of a single expression. Compare the 23 | performance of the two versions. (Section 11.4 shows how to compare the 24 | performance of different implementations systematically.) 25 | 26 | ### Exercise 2.4 27 | Write a version of `PopCount` that counts bits by shifting its argument through 28 | 64 bit positions, testing the rightmost bit each time. Compare its performance 29 | to the table-lookup version. 30 | 31 | ### Exercise 2.5 32 | The expression `x&(x-1)` clears the rightmost non-zero bit of x. Write a version 33 | of `PopCount` that counts bits by using this fact, and assess its performance. 34 | -------------------------------------------------------------------------------- /workspaces/bbcmgdm/exercises/06_methods/README.md: -------------------------------------------------------------------------------- 1 | # Chapter 6 - Methods 2 | 3 | ## Example: Bit Vector Type 4 | 5 | #### Exercise 6.1 6 | Implement these additional methods: 7 | ``` 8 | func (*IntSet) Len() int // return the number of elements 9 | func (*IntSet) Remove(x int) // remove x from the set 10 | func (*IntSet) Clear() // remove all elements from the set 11 | func (*IntSet) Copy() *IntSet // return a copy of the set 12 | ``` 13 | 14 | ### Exercise 6.2 15 | Define a varadic `(*IntSet).AddAll(...int)` method that allows a list of values 16 | to be added, such as `s.AddAll(1, 2, 3)`. 17 | 18 | ### Exercise 6.3 19 | `(*IntSet).UnionWith` computes the union of two sets using `|`, the 20 | word-parallel bitwise OR operator. Implement methods for 21 | `IntersectionWith,DifferenceWith`, and `SymmetricDifference` for the 22 | corresponding set operations. (The symmetric difference of two sets contains the 23 | elements present in one set or the other but not both.) 24 | 25 | ### Exercise 6.5 26 | The type of each word used by `IntSet` is `uint64`, but 64-bit arithmetic may be 27 | inefficient on a 32-bit platform. Modify the program to use the `uint` type, 28 | which is the most efficient unsigned integer type for the platform. Instead of 29 | dividing by 64, define a constant holding the effective size of `uint` in bits, 30 | 32 or 64. You can use the perhaps too-clever expression `32 << (^uint(0) >> 63)` 31 | for this purpose. 32 | -------------------------------------------------------------------------------- /workspaces/bbcmgdm/exercises/10_packages_and_the_go_tool/README.md: -------------------------------------------------------------------------------- 1 | # Chapter 10 - Packages and the Go Tool 2 | 3 | ## Blank Imports 4 | 5 | ### Exercise 10.1 6 | Extend the `jpeg` program so that it converts any supported input format to any 7 | output format, using `image.Decode` to detect the input format and a flag to 8 | select the output format. 9 | 10 | #### Exercise 10.2 11 | Define a generic archive file-reading function capable of reading ZIP files 12 | (`archive/zip`) and POSIX tar files (`archive/tar`). Use a registration 13 | mechanism similar to the one described above so that support for each file 14 | format can be plugged in using blank imports. 15 | 16 | ## Downloading Packages 17 | 18 | ### Exercise 10.3 19 | Using `fetch http://gopl.io/ch1/helloworld?go-get=1`, find out which service 20 | hosts the code samples for this book. (HTTP reqests from `go get` include the 21 | `go-get` parameter so that servers can distinguish them from ordinary browser 22 | requests.) 23 | 24 | ## Querying Packages 25 | 26 | ### Exercise 10.4 27 | Construct a tool that reports the set of all packages in the workspace that 28 | transitively depend on the packages specified by the arguments. Hint: you will 29 | need to run `go list` twice, once for the initial packages and once for all 30 | packages. You may want to parse its JSON output using the `encoding/json` 31 | package (§4.5). 32 | -------------------------------------------------------------------------------- /workspaces/bbcmgdm/exercises/11_testing/README.md: -------------------------------------------------------------------------------- 1 | # Chapter 11 - Testing 2 | 3 | ### Test Functions 4 | 5 | ### Exercise 11.1 6 | Write tests for the `charcount` program in Section 4.3 7 | 8 | ### Exercise 11.2 9 | Write a set of tests of `IntSet` (§6.5) that checks that its behaviour after 10 | each operation if equivalent to a set based on built-in maps. Save your 11 | implementation for benchmarking in Exercise 11.7 12 | 13 | ## Randomized Testing 14 | 15 | ### Exercise 11.3 16 | `TestRandomPalindromes` only tests palindromes. Write a randomized test that 17 | generates and verifies _non_-palindromes. 18 | 19 | ### Exercise 11.4 20 | Modify `randomPalindrome` to exercise `IsPalindrome`'s handling of punctuation 21 | and spaces. 22 | 23 | ## Writing Effective Tests 24 | 25 | ### Exercise 11.5 26 | Extend `TestSplit` to use a table of inputs and expected outputs. 27 | 28 | ## Benchmark Functions 29 | 30 | ### Exercise 11.6 31 | Write benchmarks to compare the `PopCount` implementation in Section 2.6.2 with 32 | your solutions to Exercise 2.4 and Exercise 2.5. At what point does the table- 33 | based approach break even? 34 | 35 | ### Exercise 11.7 36 | Write benchmarks for `Add`, `UnionWith`, and other methods of `*IntSet` (§6.5) 37 | using large pseudo-random inputs. How fast can you make these methods run? How 38 | does the choice or word size affect performance? How fast is `IntSet` compared 39 | to a set implementation based on the built-in `map` type? 40 | -------------------------------------------------------------------------------- /workspaces/bbcmgdm/exercises/13_low_level_programming/README.md: -------------------------------------------------------------------------------- 1 | # Chapter 13 - Low-Level Programming 2 | 3 | ## Example: Deep Equivalence 4 | 5 | #### Exercise 13.1 6 | Define a deep comparison function that considers numbers (of any type) equal if 7 | they differ by less than one part in a billion. 8 | 9 | ### Exercise 13.3 10 | Write a function that reports whether its argument is a cyclic data structure. 11 | 12 | #### Exercise 13.4 13 | Use `sync.Mutex` to make `bzip2.Writer` safe for concurrent use by multiple 14 | goroutines. 15 | 16 | ### Exercise 13.5 17 | Depending on C libraries has its drawbacks. Provide an alternative pure-Go 18 | implementation of `bzip.NewWriter` that uses the `os/exec` package to run 19 | `/bin/bzip2` as a subprocess. 20 | -------------------------------------------------------------------------------- /workspaces/betandr/bin/echo3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bbc/eng-golang-workshop/94c99f4a002654404c945c3c94f437c720039b83/workspaces/betandr/bin/echo3 -------------------------------------------------------------------------------- /workspaces/betandr/bin/helloworld: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bbc/eng-golang-workshop/94c99f4a002654404c945c3c94f437c720039b83/workspaces/betandr/bin/helloworld -------------------------------------------------------------------------------- /workspaces/betandr/exercises/02_program_structure/README.md: -------------------------------------------------------------------------------- 1 | # Chapter 2 - Program Structure 2 | 3 | ## Packages and Files 4 | 5 | ### Exercise 2.1 6 | Add types, constants, and functions to `tempconv` for processing temperatures 7 | in the Kelvin scale, where Kelvin is -273.15°C and a difference of 1K 8 | has the same magnitude as 1°C. 9 | 10 | ## Imports 11 | 12 | ### Exercise 2.2 13 | Write a general purpose unit-conversion program analogous to `cf` that reads 14 | numbers from its command-line arguments or from the standard imput if there are 15 | no arguments, and converts each nunber into units like temperature in Celsius 16 | and Fahrenheit, length in feet and meters, weight in pounds, kilograms, and the 17 | like. 18 | 19 | ## Package Initialization 20 | 21 | ### Exercise 2.3 22 | Rewrite `PopCount` to use a loop instead of a single expression. Compare the 23 | performance of the two versions. (Section 11.4 shows how to compare the 24 | performance of different implementations systematically.) 25 | 26 | ### Exercise 2.4 27 | Write a version of `PopCount` that counts bits by shifting its argument through 28 | 64 bit positions, testing the rightmost bit each time. Compare its performance 29 | to the table-lookup version. 30 | 31 | ### Exercise 2.5 32 | The expression `x&(x-1)` clears the rightmost non-zero bit of x. Write a version 33 | of `PopCount` that counts bits by using this fact, and assess its performance. 34 | -------------------------------------------------------------------------------- /workspaces/betandr/exercises/06_methods/README.md: -------------------------------------------------------------------------------- 1 | # Chapter 6 - Methods 2 | 3 | ## Example: Bit Vector Type 4 | 5 | ### Exercise 6.1 6 | Implement these additional methods: 7 | ``` 8 | func (*IntSet) Len() int // return the number of elements 9 | func (*IntSet) Remove(x int) // remove x from the set 10 | func (*IntSet) Clear() // remove all elements from the set 11 | func (*IntSet) Copy() *IntSet // return a copy of the set 12 | ``` 13 | 14 | ### Exercise 6.2 15 | Define a variadic `(*IntSet).AddAll(...int)` method that allows a list of values 16 | to be added, such as `s.AddAll(1, 2, 3)`. 17 | 18 | ### Exercise 6.3 19 | `(*IntSet).UnionWith` computes the union of two sets using `|`, the 20 | word-parallel bitwise OR operator. Implement methods for 21 | `IntersectionWith,DifferenceWith`, and `SymmetricDifference` for the 22 | corresponding set operations. (The symmetric difference of two sets contains the 23 | elements present in one set or the other but not both.) 24 | 25 | ### Exercise 6.4 26 | Add a method `Elems` that returns a slice containing the elements of the set, suit- 27 | able for iterating over with a `range` loop. 28 | 29 | ### Exercise 6.5 30 | The type of each word used by `IntSet` is `uint64`, but 64-bit arithmetic may be 31 | inefficient on a 32-bit platform. Modify the program to use the `uint` type, 32 | which is the most efficient unsigned integer type for the platform. Instead of 33 | dividing by 64, define a constant holding the effective size of `uint` in bits, 34 | 32 or 64. You can use the perhaps too-clever expression `32 << (^uint(0) >> 63)` 35 | for this purpose. 36 | -------------------------------------------------------------------------------- /workspaces/betandr/exercises/10_packages_and_the_go_tool/README.md: -------------------------------------------------------------------------------- 1 | # Chapter 10 - Packages and the Go Tool 2 | 3 | ## Blank Imports 4 | 5 | ### Exercise 10.1 6 | Extend the `jpeg` program so that it converts any supported input format to any 7 | output format, using `image.Decode` to detect the input format and a flag to 8 | select the output format. 9 | 10 | ### Exercise 10.2 11 | Define a generic archive file-reading function capable of reading ZIP files 12 | (`archive/zip`) and POSIX tar files (`archive/tar`). Use a registration 13 | mechanism similar to the one described above so that support for each file 14 | format can be plugged in using blank imports. 15 | 16 | ## Downloading Packages 17 | 18 | ### Exercise 10.3 19 | Using `fetch http://gopl.io/ch1/helloworld?go-get=1`, find out which service 20 | hosts the code samples for this book. (HTTP reqests from `go get` include the 21 | `go-get` parameter so that servers can distinguish them from ordinary browser 22 | requests.) 23 | 24 | ## Querying Packages 25 | 26 | ### Exercise 10.4 27 | Construct a tool that reports the set of all packages in the workspace that 28 | transitively depend on the packages specified by the arguments. Hint: you will 29 | need to run `go list` twice, once for the initial packages and once for all 30 | packages. You may want to parse its JSON output using the `encoding/json` 31 | package (§4.5). 32 | -------------------------------------------------------------------------------- /workspaces/betandr/exercises/11_testing/README.md: -------------------------------------------------------------------------------- 1 | # Chapter 11 - Testing 2 | 3 | ## Test Functions 4 | 5 | ### Exercise 11.1 6 | Write tests for the `charcount` program in Section 4.3 7 | 8 | ### Exercise 11.2 9 | Write a set of tests of `IntSet` (§6.5) that checks that its behaviour after 10 | each operation if equivalent to a set based on built-in maps. Save your 11 | implementation for benchmarking in Exercise 11.7 12 | 13 | ## Randomized Testing 14 | 15 | ### Exercise 11.3 16 | `TestRandomPalindromes` only tests palindromes. Write a randomized test that 17 | generates and verifies _non_-palindromes. 18 | 19 | ### Exercise 11.4 20 | Modify `randomPalindrome` to exercise `IsPalindrome`'s handling of punctuation 21 | and spaces. 22 | 23 | ## Writing Effective Tests 24 | 25 | ### Exercise 11.5 26 | Extend `TestSplit` to use a table of inputs and expected outputs. 27 | 28 | ## Benchmark Functions 29 | 30 | ### Exercise 11.6 31 | Write benchmarks to compare the `PopCount` implementation in Section 2.6.2 with 32 | your solutions to Exercise 2.4 and Exercise 2.5. At what point does the table- 33 | based approach break even? 34 | 35 | ### Exercise 11.7 36 | Write benchmarks for `Add`, `UnionWith`, and other methods of `*IntSet` (§6.5) 37 | using large pseudo-random inputs. How fast can you make these methods run? How 38 | does the choice or word size affect performance? How fast is `IntSet` compared 39 | to a set implementation based on the built-in `map` type? 40 | -------------------------------------------------------------------------------- /workspaces/betandr/exercises/13_low_level_programming/README.md: -------------------------------------------------------------------------------- 1 | # Chapter 13 - Low-Level Programming 2 | 3 | ## Example: Deep Equivalence 4 | 5 | ### Exercise 13.1 6 | Define a deep comparison function that considers numbers (of any type) equal if 7 | they differ by less than one part in a billion. 8 | 9 | ### Exercise 13.3 10 | Write a function that reports whether its argument is a cyclic data structure. 11 | 12 | ### Exercise 13.4 13 | Use `sync.Mutex` to make `bzip2.Writer` safe for concurrent use by multiple 14 | goroutines. 15 | 16 | ### Exercise 13.5 17 | Depending on C libraries has its drawbacks. Provide an alternative pure-Go 18 | implementation of `bzip.NewWriter` that uses the `os/exec` package to run 19 | `/bin/bzip2` as a subprocess. 20 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch1/ex1_1/main.go: -------------------------------------------------------------------------------- 1 | // Modify the `echo` program to also allow print `os.Args[0]`, the name of the 2 | // command that invoked it. 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | "os" 8 | ) 9 | 10 | func main() { 11 | s, sep := "", "" 12 | for _, arg := range os.Args[1:] { 13 | s += sep + arg 14 | sep = " " 15 | } 16 | fmt.Println(os.Args[0] + " " + s) 17 | } 18 | 19 | //!- 20 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch1/ex1_2/main.go: -------------------------------------------------------------------------------- 1 | // Modify the `echo` program to print the index and value of each of its arguments, 2 | // one per line. 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | "os" 8 | "strconv" 9 | ) 10 | 11 | func main() { 12 | s := "" 13 | for idx, arg := range os.Args[1:] { 14 | s += strconv.Itoa(idx) + " " + arg + "\n" 15 | } 16 | fmt.Println(s) 17 | } 18 | 19 | //!- 20 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch1/ex1_3/main.go: -------------------------------------------------------------------------------- 1 | // Experiment to measure the difference in running time between our potentially 2 | // inefficient versions and the one that uses `strings.Join`. (Section 1.6 3 | // illustrates part of the `time` package, and Section 11.4 shows how to write 4 | // benchmark tests for systematic performance evaluation.) 5 | package main 6 | 7 | import ( 8 | "fmt" 9 | "os" 10 | "strings" 11 | "time" 12 | ) 13 | 14 | func main() { 15 | forStart := time.Now() 16 | s, sep := "", "" 17 | for _, arg := range os.Args[1:] { 18 | s += sep + arg 19 | sep = " " 20 | } 21 | fmt.Printf("for loop took: %dms\n", int64(time.Since(forStart))) 22 | 23 | joinStart := time.Now() 24 | strings.Join(os.Args[1:], " ") 25 | fmt.Printf("join took: %dms\n", time.Since(joinStart)) 26 | } 27 | 28 | //!- 29 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch1/ex1_4/file1.txt: -------------------------------------------------------------------------------- 1 | Morbi lectus turpis, ultricies sit amet tortor quis, accumsan posuere dui. 2 | Quisque dictum scelerisque purus, sit amet euismod ligula finibus ac. 3 | Vestibulum lacinia tincidunt risus quis commodo. 4 | Nam eu dolor quis dolor aliquet pharetra sed ut lacus. 5 | Nunc risus nulla, blandit nec vehicula eu, iaculis sed dolor. 6 | Aenean et purus sit amet urna congue fermentum quis a sapien. 7 | Aliquam fringilla tempus sapien ac interdum. 8 | Integer lorem turpis, egestas id pellentesque sed, suscipit eget nisl. 9 | Vestibulum at augue interdum, faucibus mi eget, interdum libero. 10 | Vestibulum at augue interdum, faucibus mi eget, interdum libero. 11 | Vestibulum at augue interdum, faucibus mi eget, interdum libero. 12 | Vestibulum at augue interdum, faucibus mi eget, interdum libero. 13 | Suspendisse commodo id diam ut laoreet. 14 | Aliquam quis hendrerit massa, eu dapibus tortor. 15 | Aliquam aliquet sapien mollis, venenatis magna ac, bibendum ligula. 16 | Aliquam erat volutpat. 17 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch1/ex1_4/file2.txt: -------------------------------------------------------------------------------- 1 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. 2 | Vestibulum placerat nisi ac arcu consectetur, vitae volutpat est interdum. 3 | Cras maximus purus urna, id venenatis magna convallis nec. 4 | Duis ipsum libero, mollis at sapien in, dapibus dignissim justo. 5 | Sed fermentum sapien a vestibulum bibendum. 6 | Integer nec dui neque. 7 | Suspendisse at luctus lacus, ut hendrerit lacus. 8 | Aenean maximus consequat libero, eu ornare eros porttitor ac. 9 | Maecenas vel arcu commodo, viverra ipsum quis, sagittis sapien. 10 | Nulla convallis posuere mauris. 11 | Duis dapibus, massa eleifend placerat vestibulum, est lorem pretium felis, sed euismod nisi velit eu purus. 12 | Sed erat dui, tristique sit amet orci sit amet, fringilla cursus metus. 13 | Integer ac urna convallis, imperdiet dui imperdiet, aliquet augue. 14 | Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. 15 | Praesent aliquet nibh ligula, vulputate eleifend ligula hendrerit at. 16 | Morbi aliquet imperdiet justo eget suscipit. 17 | Aliquam erat volutpat. 18 | Aliquam erat volutpat. 19 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch1/ex1_4/main.go: -------------------------------------------------------------------------------- 1 | // Modify `dup2` to print the names of all files in which each duplicated line 2 | // occurs. 3 | package main 4 | 5 | import ( 6 | "bufio" 7 | "fmt" 8 | "os" 9 | ) 10 | 11 | func main() { 12 | counts := make(map[string]int) 13 | locations := make(map[string][]string) 14 | done := make(map[string]bool) 15 | 16 | files := os.Args[1:] 17 | if len(files) == 0 { 18 | countLines(os.Stdin, counts, locations, done) 19 | } else { 20 | for _, arg := range files { 21 | f, err := os.Open(arg) 22 | if err != nil { 23 | fmt.Fprintf(os.Stderr, "dup2: %v\n", err) 24 | continue 25 | } 26 | countLines(f, counts, locations, done) 27 | f.Close() 28 | } 29 | } 30 | for line, n := range counts { 31 | if n > 1 { 32 | fmt.Printf("%d\t%s\t%v\n", n, line, locations[line]) 33 | } 34 | } 35 | } 36 | 37 | func countLines(f *os.File, counts map[string]int, locations map[string][]string, done map[string]bool) { 38 | input := bufio.NewScanner(f) 39 | for input.Scan() { 40 | line := input.Text() 41 | file := f.Name() 42 | 43 | counts[line]++ 44 | if !done[line+file] { 45 | locations[line] = append(locations[line], file) 46 | done[line+file] = true 47 | } 48 | } 49 | // NOTE: ignoring potential errors from input.Err() 50 | } 51 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch1/ex1_5/out.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bbc/eng-golang-workshop/94c99f4a002654404c945c3c94f437c720039b83/workspaces/betandr/src/andr.io/ch1/ex1_5/out.gif -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch1/ex1_6/out.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bbc/eng-golang-workshop/94c99f4a002654404c945c3c94f437c720039b83/workspaces/betandr/src/andr.io/ch1/ex1_6/out.gif -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch1/ex1_7/main.go: -------------------------------------------------------------------------------- 1 | // The function call `io.Copy(dst, src)` reads from `src` and writes to `dst`. Use 2 | // it instead of `ioutil.ReadAll` to copy the response body to `os.Stdout` without 3 | // requiring a buffer large enough to hold the entire stream. Be sure to check the 4 | // error result of `io.Copy`. 5 | package main 6 | 7 | import ( 8 | "fmt" 9 | "io" 10 | "log" 11 | "net/http" 12 | "os" 13 | ) 14 | 15 | func main() { 16 | for _, url := range os.Args[1:] { 17 | resp, err := http.Get(url) 18 | if err != nil { 19 | fmt.Fprintf(os.Stderr, "fetch: %v\n", err) 20 | os.Exit(1) 21 | } 22 | 23 | if _, err := io.Copy(os.Stdout, resp.Body); err != nil { 24 | log.Fatal(err) 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch1/ex1_8/main.go: -------------------------------------------------------------------------------- 1 | // Modify `fetch` to add the prefix `http://` to each argument URL, if it is 2 | // missing. You might want to use `strings.HasPrefix`. 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | "io" 8 | "log" 9 | "net/http" 10 | "os" 11 | "strings" 12 | ) 13 | 14 | func main() { 15 | for _, url := range os.Args[1:] { 16 | if !strings.HasPrefix(url, "http://") { // ignoring https ;) 17 | url = "http://" + url 18 | } 19 | resp, err := http.Get(url) 20 | if err != nil { 21 | fmt.Fprintf(os.Stderr, "fetch: %v\n", err) 22 | os.Exit(1) 23 | } 24 | 25 | if _, err := io.Copy(os.Stdout, resp.Body); err != nil { 26 | log.Fatal(err) 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch1/ex1_9/main.go: -------------------------------------------------------------------------------- 1 | // Modify `fetch` to also print the HTTP status code, found in `resp.Status`. 2 | package main 3 | 4 | import ( 5 | "fmt" 6 | "io" 7 | "log" 8 | "net/http" 9 | "os" 10 | "strings" 11 | ) 12 | 13 | func main() { 14 | for _, url := range os.Args[1:] { 15 | if !strings.HasPrefix(url, "http://") { // ignoring https ;) 16 | url = "http://" + url 17 | } 18 | resp, err := http.Get(url) 19 | if err != nil { 20 | fmt.Fprintf(os.Stderr, "fetch: %v\n", err) 21 | os.Exit(1) 22 | } 23 | 24 | fmt.Println("GET finished with status: " + resp.Status) 25 | 26 | if _, err := io.Copy(os.Stdout, resp.Body); err != nil { 27 | log.Fatal(err) 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch2/ex2_1/conv.go: -------------------------------------------------------------------------------- 1 | // Add types, constants, and functions to `tempconv` for processing temperatures 2 | // in the Kelvin scale, where Kelvin is -273.15°C and a difference of 1K 3 | // has the same magnitude as 1°C. 4 | package tempconv 5 | 6 | // CToF converts a Celsius temperature to Fahrenheit. 7 | func CToF(c Celsius) Fahrenheit { return Fahrenheit(c*9/5 + 32) } 8 | 9 | // FToC converts a Fahrenheit temperature to Celsius. 10 | func FToC(f Fahrenheit) Celsius { return Celsius((f - 32) * 5 / 9) } 11 | 12 | // CToK converts a Celsius temperature to Kelvin. 13 | func CToK(c Celsius) Kelvin { return Kelvin(c + CelsiusK) } 14 | 15 | // KToC converts a Kelvin temperature to Celsius. 16 | func KToC(k Kelvin) Celsius { return Celsius(k - KelvinC) } 17 | 18 | // FToK converts a Fahrenheit temperature to Kelvin. 19 | func FToK(f Fahrenheit) Kelvin { return Kelvin((f + FahrenheitK) * 5 / 9) } 20 | 21 | // KToF converts a Kelvin temperature to Fahrenheit. 22 | func KToF(k Kelvin) Fahrenheit { return Fahrenheit(k*9/5 - KelvinF) } 23 | 24 | //!- 25 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch2/ex2_1/tempconv.go: -------------------------------------------------------------------------------- 1 | // Add types, constants, and functions to `tempconv` for processing temperatures 2 | // in the Kelvin scale, where Kelvin is -273.15°C and a difference of 1K 3 | // has the same magnitude as 1°C. 4 | package tempconv 5 | 6 | import "fmt" 7 | 8 | // Celsius temperature type 9 | type Celsius float64 10 | 11 | // Fahrenheit temperature type 12 | type Fahrenheit float64 13 | 14 | // Kelvin temperature type 15 | type Kelvin float64 16 | 17 | // Conversion constants (some could be more generic to support two types) 18 | const ( 19 | AbsoluteZeroC Celsius = -273.15 20 | FreezingC Celsius = 0 21 | BoilingC Celsius = 100 22 | CelsiusK Celsius = 273.15 23 | KelvinC Kelvin = 273.15 24 | KelvinF Kelvin = 459.67 25 | FahrenheitK Fahrenheit = 459.67 26 | ) 27 | 28 | // Adds custom String() formatting to Celsius 29 | func (c Celsius) String() string { return fmt.Sprintf("%g°C", c) } 30 | 31 | // Adds custom String() formatting to Fahrenheit 32 | func (f Fahrenheit) String() string { return fmt.Sprintf("%g°F", f) } 33 | 34 | // Adds custom String() formatting to Kelvin 35 | func (f Kelvin) String() string { return fmt.Sprintf("%g K", f) } 36 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch2/ex2_2/main.go: -------------------------------------------------------------------------------- 1 | // Write a general purpose unit-conversion program analogous to `cf` that reads 2 | // numbers from its command-line arguments or from the standard imput if there are 3 | // no arguments, and converts each nunber into units like temperature in Celsius 4 | // and Fahrenheit, length in feet and meters, weight in pounds, kilograms, and the 5 | // like. 6 | package main 7 | 8 | import ( 9 | "fmt" 10 | "os" 11 | "strconv" 12 | 13 | t "andr.io/ch2/ex2_1" 14 | w "andr.io/ch2/ex2_2/weightconv" 15 | ) 16 | 17 | func main() { 18 | 19 | for _, arg := range os.Args[1:] { 20 | n, _ := strconv.Atoi(arg) 21 | fmt.Printf("-= converting %d =- \n", n) 22 | 23 | c := t.Celsius(n) 24 | fmt.Printf("%s is %s\n", c, t.CToF(c)) 25 | 26 | f := t.Fahrenheit(n) 27 | fmt.Printf("%s is %s\n", f, t.FToC(f)) 28 | 29 | k := t.Kelvin(n) 30 | fmt.Printf("%s is %s\n", k, t.KToF(k)) 31 | 32 | g := w.Kilo(n) 33 | fmt.Printf("%s is %s\n", g, w.KToP(g)) 34 | 35 | l := w.Pound(n) 36 | fmt.Printf("%s is %s\n", l, w.PToS(l)) 37 | 38 | s := w.Stone(n) 39 | fmt.Printf("%s is %s\n", s, w.SToP(s)) 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch2/ex2_2/weightconv/conv.go: -------------------------------------------------------------------------------- 1 | // Write a general purpose unit-conversion program analogous to `cf` that reads 2 | // numbers from its command-line arguments or from the standard imput if there are 3 | // no arguments, and converts each nunber into units like temperature in Celsius 4 | // and Fahrenheit, length in feet and meters, weight in pounds, kilograms, and the 5 | // like. 6 | package weightconv 7 | 8 | // KToP converts a Kilo weight to Pounds. 9 | func KToP(k Kilo) Pound { return Pound(k * KiloP) } 10 | 11 | // KToS converts a Kilo temperature to Stone. 12 | func KToS(k Kilo) Stone { return Stone(k / KiloS) } 13 | 14 | // PToK converts a Pound weight to Kilo. 15 | func PToK(p Pound) Kilo { return Kilo(p * PoundK) } 16 | 17 | // PToS converts a Pound temperature to Stone. 18 | func PToS(p Pound) Stone { return Stone(p * PoundS) } 19 | 20 | // SToK converts a Stone weight to Kilo. 21 | func SToK(s Stone) Kilo { return Kilo(s / StoneK) } 22 | 23 | // SToP converts a Stone temperature to Pound. 24 | func SToP(s Stone) Pound { return Pound(s * StoneP) } 25 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch2/ex2_2/weightconv/weightconv.go: -------------------------------------------------------------------------------- 1 | // Write a general purpose unit-conversion program analogous to `cf` that reads 2 | // numbers from its command-line arguments or from the standard imput if there are 3 | // no arguments, and converts each nunber into units like temperature in Celsius 4 | // and Fahrenheit, length in feet and meters, weight in pounds, kilograms, and the 5 | // like. 6 | package weightconv 7 | 8 | import "fmt" 9 | 10 | // Kilo weight type 11 | type Kilo float64 12 | 13 | // Stone weight type 14 | type Stone float64 15 | 16 | // Pound weight type 17 | type Pound float64 18 | 19 | // Conversion constants 20 | const ( 21 | KiloP Kilo = 2.2046226218 22 | KiloS Kilo = 6.35029318 23 | 24 | PoundK Pound = 0.453592 25 | PoundS Pound = 0.0714286 26 | 27 | StoneK Stone = 0.15747 28 | StoneP Stone = 14 29 | ) 30 | 31 | // Adds custom String() formatting to Kilo 32 | func (f Kilo) String() string { return fmt.Sprintf("%gkg", f) } 33 | 34 | // Adds custom String() formatting to Stone 35 | func (f Stone) String() string { return fmt.Sprintf("%gst", f) } 36 | 37 | // Adds custom String() formatting to Pound 38 | func (f Pound) String() string { return fmt.Sprintf("%glb", f) } 39 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch2/ex2_3/main.go: -------------------------------------------------------------------------------- 1 | // Rewrite `PopCount` to use a loop instead of a single expression. Compare the 2 | // performance of the two versions. (Section 11.4 shows how to compare the 3 | // performance of different implementations systematically.) 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | 9 | "andr.io/ch2/ex2_3/popcount" 10 | ) 11 | 12 | func main() { 13 | 14 | i := uint64(240) 15 | populationCount := popcount.PopCount(i) 16 | fmt.Printf("population count of %b is %d\n", i, populationCount) 17 | } 18 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch2/ex2_3/popcount/main.go: -------------------------------------------------------------------------------- 1 | // Rewrite `PopCount` to use a loop instead of a single expression. Compare the 2 | // performance of the two versions. (Section 11.4 shows how to compare the 3 | // performance of different implementations systematically.) 4 | package popcount 5 | 6 | // pc[i] is the population count of i. 7 | var pc [256]byte 8 | 9 | func init() { 10 | for i := range pc { 11 | pc[i] = pc[i/2] + byte(i&1) 12 | } 13 | } 14 | 15 | // PopCount returns the population count (number of set bits) of x. 16 | func PopCount(x uint64) int { 17 | result := 0 18 | for i := uint(0); i < 8; i++ { 19 | result += int(pc[byte(x>>(i*8))]) 20 | } 21 | 22 | return result 23 | } 24 | 25 | //!- 26 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch2/ex2_4/main.go: -------------------------------------------------------------------------------- 1 | // Write a version of `PopCount` that counts bits by shifting its argument through 2 | // 64 bit positions, testing the rightmost bit each time. Compare its performance 3 | // to the table-lookup version. 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | 9 | "andr.io/ch2/ex2_4/popcount" 10 | ) 11 | 12 | func main() { 13 | i := uint64(240) 14 | populationCount := popcount.ByLookup(i) 15 | fmt.Printf("population count of %b by lookup is %d\n", i, populationCount) 16 | 17 | populationCount = popcount.ByShifting(i) 18 | fmt.Printf("population count of %b by shifting is %d\n", i, populationCount) 19 | } 20 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch2/ex2_4/popcount/main.go: -------------------------------------------------------------------------------- 1 | // Write a version of `PopCount` that counts bits by shifting its argument through 2 | // 64 bit positions, testing the rightmost bit each time. Compare its performance 3 | // to the table-lookup version. 4 | package popcount 5 | 6 | // pc[i] is the population count of i. 7 | var pc [256]byte 8 | 9 | func init() { 10 | for i := range pc { 11 | pc[i] = pc[i/2] + byte(i&1) 12 | } 13 | } 14 | 15 | // ByLookup returns the population count (number of set bits) of x. 16 | func ByLookup(x uint64) int { 17 | result := 0 18 | for i := uint(0); i < 8; i++ { 19 | result += int(pc[byte(x>>(i*8))]) 20 | } 21 | 22 | return result 23 | } 24 | 25 | // ByShifting returns the population count (number of set bits) of x by shifting. 26 | func ByShifting(x uint64) int { 27 | result := 0 28 | for i := uint(0); i < 64; i++ { 29 | if x&(1<>(i*8))]) 19 | } 20 | 21 | return result 22 | } 23 | 24 | // ByShifting returns the population count (number of set bits) of x by shifting. 25 | func ByShifting(x uint64) int { 26 | result := 0 27 | for i := uint(0); i < 64; i++ { 28 | if x&(1< 0 { 30 | buf.WriteString(",") 31 | } 32 | buf.WriteString(s[i : i+3]) 33 | } 34 | 35 | return buf.String() 36 | } 37 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch3/ex3_11/main.go: -------------------------------------------------------------------------------- 1 | // Enhance `comma` so it deals correctly with floating-point numbers and an 2 | // optional sign. 3 | package main 4 | 5 | import ( 6 | "bytes" 7 | "fmt" 8 | "os" 9 | "strings" 10 | ) 11 | 12 | func main() { 13 | for i := 1; i < len(os.Args); i++ { 14 | fmt.Printf(" %s\n", comma(os.Args[i])) 15 | } 16 | } 17 | 18 | // comma inserts commas in a non-negative decimal integer string. 19 | func comma(s string) string { 20 | var buf bytes.Buffer 21 | 22 | point := strings.LastIndex(s, ".") 23 | digits := s[point:] 24 | s = s[:point] 25 | 26 | if strings.HasPrefix(s, "-") { 27 | buf.WriteString("-") 28 | s = s[1:] 29 | } 30 | 31 | if len(s) < 4 { 32 | return s 33 | } 34 | 35 | idx := len(s) % 3 36 | buf.WriteString(s[:idx]) 37 | 38 | for i := idx; i < len(s); i += 3 { 39 | buf.WriteString("," + s[i:i+3]) 40 | } 41 | 42 | return buf.String() + digits 43 | } 44 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch3/ex3_12/main.go: -------------------------------------------------------------------------------- 1 | // Write a function that reports whether two strings are anagrams of each other, 2 | // that is, they contain the same letters in a different order. 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | "os" 8 | "sort" 9 | ) 10 | 11 | func main() { 12 | if len(os.Args) > 2 { 13 | res := "NOT " 14 | if anagrams(os.Args[1], os.Args[2]) { 15 | res = "" 16 | } 17 | fmt.Printf("%s and %s are %sanagrams\n", os.Args[1], os.Args[2], res) 18 | } 19 | } 20 | 21 | // sortableRunes is a type which implements `Less`, `Swap`, and `Len` to use 22 | // func Sort(data Interface) https://golang.org/pkg/sort/#Sort 23 | type sortableRunes []rune 24 | 25 | func (s sortableRunes) Less(i, j int) bool { 26 | return s[i] < s[j] 27 | } 28 | 29 | func (s sortableRunes) Swap(i, j int) { 30 | s[i], s[j] = s[j], s[i] 31 | } 32 | 33 | func (s sortableRunes) Len() int { 34 | return len(s) 35 | } 36 | 37 | // anagrams checks if two strings are anagrams of each other 38 | // n log n complexity due to two `sort.Sort`s which use quick sort. 39 | func anagrams(s1 string, s2 string) bool { 40 | r1 := []rune(s1) 41 | r2 := []rune(s2) 42 | sort.Sort(sortableRunes(r1)) 43 | sort.Sort(sortableRunes(r2)) 44 | 45 | if string(r1) == string(r2) { 46 | return true 47 | } 48 | 49 | return false 50 | } 51 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch3/ex3_13/main.go: -------------------------------------------------------------------------------- 1 | // Write const declarations for KB, MB, up through YB as compactly as you can. 2 | package main 3 | 4 | import "fmt" 5 | 6 | const ( 7 | _ = 1 << (10 * iota) 8 | KiB // 2^10 9 | MiB // 2^20 10 | GiB // 2^30 11 | TiB // 2^40 12 | PiB // 2^50 13 | EiB // 2^60 14 | ZiB // 2^70 15 | YiB // 2^80 16 | ) 17 | 18 | const ( 19 | KB = 1000 // 10^3 20 | MB = KB * 1000 // 10^6 21 | GB = MB * 1000 // 10^9 22 | TB = GB * 1000 // 10^12 23 | PB = TB * 1000 // 10^15 24 | EB = PB * 1000 // 10^18 25 | ZB = EB * 1000 // 10^21 26 | YB = ZB * 1000 // 10^24 27 | ) 28 | 29 | func main() { 30 | fmt.Printf("%d\n", EiB) 31 | fmt.Printf("%d\n", EB) 32 | } 33 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch3/ex3_5/main.go: -------------------------------------------------------------------------------- 1 | // Implement a full-color Mandelbrot set using the function `image.NewRBA` and the 2 | // type `color.RGBA` or `color.YCbCr`. 3 | package main 4 | 5 | import ( 6 | "image" 7 | "image/color" 8 | "image/color/palette" 9 | "image/png" 10 | "math/cmplx" 11 | "os" 12 | ) 13 | 14 | func main() { 15 | const ( 16 | xmin, ymin, xmax, ymax = -2, -2, +2, +2 17 | width, height = 1024, 1024 18 | ) 19 | 20 | img := image.NewRGBA(image.Rect(0, 0, width, height)) 21 | for py := 0; py < height; py++ { 22 | y := float64(py)/height*(ymax-ymin) + ymin 23 | for px := 0; px < width; px++ { 24 | x := float64(px)/width*(xmax-xmin) + xmin 25 | z := complex(x, y) 26 | // Image point (px, py) represents complex value z. 27 | img.Set(px, py, mandelbrot(z)) 28 | } 29 | } 30 | png.Encode(os.Stdout, img) // NOTE: ignoring errors 31 | } 32 | 33 | func mandelbrot(z complex128) color.Color { 34 | const iterations = 200 35 | const contrast = 15 36 | 37 | var v complex128 38 | for n := uint8(0); n < iterations; n++ { 39 | v = v*v + z 40 | if cmplx.Abs(v) > 2 { 41 | return palette.Plan9[255-contrast*n] 42 | } 43 | } 44 | return color.Black 45 | } 46 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch3/ex3_5/mandelbrot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bbc/eng-golang-workshop/94c99f4a002654404c945c3c94f437c720039b83/workspaces/betandr/src/andr.io/ch3/ex3_5/mandelbrot.png -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch3/ex3_6/mandelbrot_supersampled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bbc/eng-golang-workshop/94c99f4a002654404c945c3c94f437c720039b83/workspaces/betandr/src/andr.io/ch3/ex3_6/mandelbrot_supersampled.png -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch3/ex3_7/newton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bbc/eng-golang-workshop/94c99f4a002654404c945c3c94f437c720039b83/workspaces/betandr/src/andr.io/ch3/ex3_7/newton.png -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch3/ex3_8/main.go: -------------------------------------------------------------------------------- 1 | // Rendering fractals at high zoom levels demands great arithmetic precision. 2 | // Implement the same fractal using four different representations of numbers: 3 | // `complex64`, `complex128`, `big.Float`, and `big.Rat`. (The latter two types 4 | // are found in the `math/big` package. `Float` uses arbitrary but 5 | // bounded-precision floating-point; `Rat` uses unbounded-precision rational 6 | // numbers.) How do they compare in performance and memory usage? At what zoom 7 | // levels do rendering artefacts become visible? 8 | package main 9 | 10 | import ( 11 | "os" 12 | 13 | "andr.io/ch3/ex3_8/mandelbrot" 14 | ) 15 | 16 | func main() { 17 | mandelbrot.Generate128(os.Stdout) 18 | } 19 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch3/ex3_8/mandelbrot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bbc/eng-golang-workshop/94c99f4a002654404c945c3c94f437c720039b83/workspaces/betandr/src/andr.io/ch3/ex3_8/mandelbrot.png -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch3/ex3_8/mandelbrot/mandelbrot_test.go: -------------------------------------------------------------------------------- 1 | // Rendering fractals at high zoom levels demands great arithmetic precision. 2 | // Implement the same fractal using four different representations of numbers: 3 | // `complex64`, `complex128`, `big.Float`, and `big.Rat`. (The latter two types 4 | // are found in the `math/big` package. `Float` uses arbitrary but 5 | // bounded-precision floating-point; `Rat` uses unbounded-precision rational 6 | // numbers.) How do they compare in performance and memory usage? At what zoom 7 | // levels do rendering artefacts become visible? 8 | package mandelbrot_test 9 | 10 | import ( 11 | "io/ioutil" 12 | "testing" 13 | 14 | "andr.io/ch3/ex3_8/mandelbrot" 15 | ) 16 | 17 | // -- Benchmarks -- 18 | 19 | func BenchmarkGenerate64(b *testing.B) { 20 | for i := 0; i < b.N; i++ { 21 | mandelbrot.Generate64(ioutil.Discard) 22 | } 23 | } 24 | 25 | func BenchmarkGenerate128(b *testing.B) { 26 | for i := 0; i < b.N; i++ { 27 | mandelbrot.Generate128(ioutil.Discard) 28 | } 29 | } 30 | 31 | // $ go test -cpu=2 -bench=. andr.io/ch3/ex3_8/mandelbrot 32 | // goos: darwin 33 | // goarch: amd64 34 | // pkg: andr.io/ch3/ex3_8/mandelbrot 35 | // BenchmarkGenerate64-2 3 365219698 ns/op 36 | // BenchmarkGenerate128-2 5 290191841 ns/op 37 | // PASS 38 | // ok andr.io/ch3/ex3_8/mandelbrot 4.815s 39 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch3/ex3_9/curl.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | for i in {1..100}; do 3 | printf -v url "http://localhost:8000/?xmax=-1.444&xmin=-2.444&ymax=3&ymin=2&zoom=$i" 4 | printf -v file "./pngs/%010d.png" $i 5 | curl $url > $file 6 | done 7 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch4/ex4_1/main.go: -------------------------------------------------------------------------------- 1 | // Write a function that counts the number of bits that are different in two 2 | // SHA256 hashes. (see Popcount from Section 2.6.2) 3 | package main 4 | 5 | import ( 6 | "crypto/sha256" 7 | "fmt" 8 | "os" 9 | 10 | "andr.io/ch4/ex4_1/popcount" 11 | ) 12 | 13 | func main() { 14 | if len(os.Args) != 3 { 15 | fmt.Println("Usage: shapc {string} {string}") 16 | os.Exit(0) 17 | } 18 | 19 | s1 := sha256.Sum256([]byte(os.Args[1])) 20 | s2 := sha256.Sum256([]byte(os.Args[2])) 21 | 22 | diffCount := 0 23 | 24 | for _, n := range s1 { 25 | diffCount += popcount.Count(uint64(n)) 26 | } 27 | 28 | for _, n := range s2 { 29 | diffCount -= popcount.Count(uint64(n)) 30 | } 31 | 32 | fmt.Printf("%d bits different\n", abs(diffCount)) 33 | 34 | } 35 | 36 | func abs(x int) int { 37 | if x < 0 { 38 | return -x 39 | } 40 | return x 41 | } 42 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch4/ex4_1/popcount/main.go: -------------------------------------------------------------------------------- 1 | // Write a function that counts the number of bits that are different in two 2 | // SHA256 hashes. (see Popcount from Section 2.6.2) 3 | package popcount 4 | 5 | // Count returns the population count (number of set bits) of x by clearing. 6 | func Count(x uint64) int { 7 | result := 0 8 | for x != 0 { 9 | x = x & (x - 1) // clear rightmost non-zero bit 10 | result++ 11 | } 12 | return result 13 | } 14 | 15 | //!- 16 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch4/ex4_10/github/github.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan. 2 | // License: https://creativecommons.org/licenses/by-nc-sa/4.0/ 3 | 4 | // See page 110. 5 | //!+ 6 | 7 | // Package github provides a Go API for the GitHub issue tracker. 8 | // See https://developer.github.com/v3/search/#search-issues. 9 | package github 10 | 11 | import "time" 12 | 13 | const IssuesURL = "https://api.github.com/search/issues" 14 | 15 | type IssuesSearchResult struct { 16 | TotalCount int `json:"total_count"` 17 | Items []*Issue 18 | } 19 | 20 | type Issue struct { 21 | Number int 22 | HTMLURL string `json:"html_url"` 23 | Title string 24 | State string 25 | User *User 26 | CreatedAt time.Time `json:"created_at"` 27 | Body string // in Markdown format 28 | } 29 | 30 | type User struct { 31 | Login string 32 | HTMLURL string `json:"html_url"` 33 | } 34 | 35 | //!- 36 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch4/ex4_10/github/search.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan. 2 | // License: https://creativecommons.org/licenses/by-nc-sa/4.0/ 3 | 4 | //!+ 5 | 6 | package github 7 | 8 | import ( 9 | "encoding/json" 10 | "fmt" 11 | "net/http" 12 | "net/url" 13 | "strings" 14 | ) 15 | 16 | // SearchIssues queries the GitHub issue tracker. 17 | func SearchIssues(terms []string) (*IssuesSearchResult, error) { 18 | q := url.QueryEscape(strings.Join(terms, " ")) 19 | resp, err := http.Get(IssuesURL + "?q=" + q) 20 | if err != nil { 21 | return nil, err 22 | } 23 | //!- 24 | // For long-term stability, instead of http.Get, use the 25 | // variant below which adds an HTTP request header indicating 26 | // that only version 3 of the GitHub API is acceptable. 27 | // 28 | // req, err := http.NewRequest("GET", IssuesURL+"?q="+q, nil) 29 | // if err != nil { 30 | // return nil, err 31 | // } 32 | // req.Header.Set( 33 | // "Accept", "application/vnd.github.v3.text-match+json") 34 | // resp, err := http.DefaultClient.Do(req) 35 | //!+ 36 | 37 | // We must close resp.Body on all execution paths. 38 | // (Chapter 5 presents 'defer', which makes this simpler.) 39 | if resp.StatusCode != http.StatusOK { 40 | resp.Body.Close() 41 | return nil, fmt.Errorf("search query failed: %s", resp.Status) 42 | } 43 | 44 | var result IssuesSearchResult 45 | if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { 46 | resp.Body.Close() 47 | return nil, err 48 | } 49 | resp.Body.Close() 50 | return &result, nil 51 | } 52 | 53 | //!- 54 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch4/ex4_12/download.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | for i in {1..2083} 3 | do 4 | curl -H "Accept: application/json" "https://xkcd.com/$i/info.0.json" > ./index/$i.json 5 | sleep 0.5 6 | done 7 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch4/ex4_14/github/github.go: -------------------------------------------------------------------------------- 1 | package github 2 | 3 | import "time" 4 | 5 | // IssuesURL is the GitHub API URL for bug reports / issues 6 | const IssuesURL = "https://api.github.com/search/issues" 7 | 8 | type IssuesSearchResult struct { 9 | TotalCount int `json:"total_count"` 10 | Items []*Issue 11 | } 12 | 13 | type Milestone struct { 14 | Number int 15 | Title string 16 | HTMLURL string `json:"html_url"` 17 | } 18 | 19 | type Issue struct { 20 | Number int 21 | HTMLURL string `json:"html_url"` 22 | Title string 23 | State string 24 | User *User 25 | CreatedAt time.Time `json:"created_at"` 26 | Body string 27 | Milestone Milestone 28 | } 29 | 30 | type User struct { 31 | Login string 32 | HTMLURL string `json:"html_url"` 33 | } 34 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch4/ex4_14/github/search.go: -------------------------------------------------------------------------------- 1 | package github 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "net/http" 7 | "net/url" 8 | "strings" 9 | ) 10 | 11 | // SearchIssues queries the GitHub issue tracker. 12 | func SearchIssues(terms []string) (*IssuesSearchResult, error) { 13 | q := url.QueryEscape(strings.Join(terms, " ")) 14 | 15 | reqURL := IssuesURL + "?q=" + q 16 | 17 | req, err := http.NewRequest("GET", reqURL, nil) 18 | req.Header.Set("Content-Type", "application/json") 19 | if err != nil { 20 | return nil, err 21 | } 22 | 23 | acceptHeaders := []string{"application/vnd.github.symmetra-preview+json", "application/vnd.github.sailor-v-preview+json"} 24 | req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) 25 | 26 | res, err := http.DefaultClient.Do(req) 27 | if err != nil { 28 | return nil, err 29 | } 30 | 31 | if res.StatusCode != http.StatusOK { 32 | res.Body.Close() 33 | return nil, fmt.Errorf("Error: %s", res.Status) 34 | } 35 | 36 | var result IssuesSearchResult 37 | if err := json.NewDecoder(res.Body).Decode(&result); err != nil { 38 | res.Body.Close() 39 | return nil, err 40 | } 41 | 42 | res.Body.Close() 43 | return &result, nil 44 | } 45 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch4/ex4_2/main.go: -------------------------------------------------------------------------------- 1 | // Write a program that prints the SHA256 hash of it standard input by default 2 | // but supports a command-line flag to print the SHA384 or SHA512 hash instead. 3 | package main 4 | 5 | import ( 6 | "crypto/sha256" 7 | "crypto/sha512" 8 | "flag" 9 | "fmt" 10 | "io/ioutil" 11 | "os" 12 | ) 13 | 14 | var shaType = flag.String("a", "sha256", "The algorithm to use: sha256/sha384/sha512") 15 | 16 | func main() { 17 | flag.Parse() 18 | input, err := ioutil.ReadAll(os.Stdin) 19 | if err != nil { 20 | fmt.Fprintf(os.Stderr, "error: %s\n", err) 21 | } 22 | 23 | if *shaType == "sha256" { 24 | fmt.Printf("%x\n", sha256.Sum256(input)) 25 | 26 | } else if *shaType == "sha384" { 27 | fmt.Printf("%x\n", sha512.Sum384(input)) 28 | 29 | } else if *shaType == "sha512" { 30 | fmt.Printf("%x\n", sha512.Sum512(input)) 31 | 32 | } else { 33 | fmt.Printf("unknown algorithm: %s\n", *shaType) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch4/ex4_3/main.go: -------------------------------------------------------------------------------- 1 | // Rewrite `reverse` to use an array pointer instead of a slice 2 | 3 | package main 4 | 5 | import "fmt" 6 | 7 | func rotate(pos int, a *[10]int) { 8 | 9 | for i, j := 0, pos-1; i <= j; i, j = i+1, j-1 { 10 | a[i], a[j] = a[j], a[i] 11 | } 12 | 13 | for i, j := pos, len(a)-1; i <= j; i, j = i+1, j-1 { 14 | a[i], a[j] = a[j], a[i] 15 | } 16 | 17 | for i, j := 0, len(a)-1; i <= j; i, j = i+1, j-1 { 18 | a[i], a[j] = a[j], a[i] 19 | } 20 | } 21 | 22 | func main() { 23 | a := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} 24 | rotate(3, &a) 25 | fmt.Println(a) 26 | } 27 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch4/ex4_4/main.go: -------------------------------------------------------------------------------- 1 | // Write a version of `rotate` that operates in a single pass 2 | 3 | package main 4 | 5 | import "fmt" 6 | 7 | // Rotate rotates a slice of integers `s` at the position `pos` with a single pass 8 | // through the array, swapping from the last position to the first position 9 | // until all items are in order, running in O(n) time and using O(n) space. 10 | func Rotate(pos int, s []int) { 11 | k := len(s) - pos 12 | stop := 0 13 | if len(s)%2 == 0 { 14 | stop = 1 15 | } 16 | 17 | for i, j := len(s)-1, pos; i > stop; i, j = i-1, j-1 { 18 | if j <= 0 { 19 | j = pos 20 | k = k - pos 21 | } 22 | l := i - k 23 | if i <= 2 { 24 | l = 0 25 | } 26 | s[l], s[i] = s[i], s[l] 27 | } 28 | } 29 | 30 | func main() { 31 | even := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} 32 | Rotate(4, even[:]) 33 | fmt.Println(even) 34 | 35 | odd := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10} 36 | Rotate(4, odd[:]) 37 | fmt.Println(odd) 38 | } 39 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch4/ex4_5/main.go: -------------------------------------------------------------------------------- 1 | // Write an in-place function to eliminate adjacent duplicates in a []string slice. 2 | package main 3 | 4 | import "fmt" 5 | 6 | func removeAdjacentDupes(strings []string) []string { 7 | curr := "" 8 | idx := 0 9 | for _, str := range strings { 10 | if str != curr { 11 | curr = str 12 | strings[idx] = str 13 | idx++ 14 | } 15 | } 16 | return strings[:idx] 17 | } 18 | 19 | func main() { 20 | s := []string{"Finally", "as", "as", "as", "the", "the", "sky", "began", "to", "to", "grow", "light"} 21 | deDuped := removeAdjacentDupes(s) 22 | fmt.Println(deDuped) 23 | } 24 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch4/ex4_6/main.go: -------------------------------------------------------------------------------- 1 | // Write an in-place function that squashes each run of adjacent Unicode spaces 2 | // (see `unicode.IsSpace`) in a UTF-8-encoded `[]byte` slice into a single ASCII space. 3 | 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "unicode" 9 | ) 10 | 11 | // squashAdjacentSpaces removes extra spaces from a byte slice, for example the 12 | // string "hello, world" would be squashed to "hello, world" 13 | func squashAdjacentSpaces(phrase []byte) []byte { 14 | runes := []rune(string(phrase)) // it's easier to handle runes! 15 | i := 0 16 | notSpace := true 17 | for _, c := range runes { 18 | if unicode.IsSpace(c) { 19 | if notSpace { 20 | runes[i] = c 21 | i++ 22 | notSpace = false 23 | } 24 | } else { 25 | runes[i] = c 26 | i++ 27 | notSpace = true 28 | } 29 | } 30 | 31 | return []byte(string(runes[:i])) // turn back into a byte array, as that's requested 32 | } 33 | 34 | func main() { 35 | phrase := []byte("Finally, as the sky began to grow light") 36 | unspaced := squashAdjacentSpaces(phrase) 37 | fmt.Println(string(unspaced)) 38 | } 39 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch4/ex4_7/main.go: -------------------------------------------------------------------------------- 1 | // Modify reverse to reverse the characters of a []byte slice that represents a 2 | // UTF-8-encoded string, in place. Can you do it without allocating new memory? 3 | 4 | package main 5 | 6 | import "fmt" 7 | 8 | func reverse(phrase []byte) []byte { 9 | runes := []rune(string(phrase)) 10 | for i, j := 0, len(runes)-1; i < len(runes)/2; i, j = i+1, j-1 { 11 | runes[i], runes[j] = runes[j], runes[i] 12 | } 13 | 14 | return []byte(string(runes)) 15 | } 16 | 17 | func main() { 18 | phrase := []byte("thgil worg ot nageb yks eht sa ,yllaniF") 19 | reversed := reverse(phrase) 20 | fmt.Println(string(reversed)) 21 | } 22 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch4/ex4_9/main.go: -------------------------------------------------------------------------------- 1 | // Write a program `wordfreq` to report the frequency of each word in an input 2 | // text file. Call `input.Split(bufio.ScanWords)` before the first call to 3 | // `Scan` to break the input into words instead of lines. 4 | 5 | package main 6 | 7 | import ( 8 | "bufio" 9 | "fmt" 10 | "log" 11 | "os" 12 | ) 13 | 14 | func main() { 15 | 16 | file, err := os.Open(os.Args[1]) 17 | if err != nil { 18 | log.Fatal(err) 19 | } 20 | 21 | scanner := bufio.NewScanner(file) 22 | 23 | scanner.Split(bufio.ScanWords) 24 | 25 | freqs := make(map[string]int) 26 | 27 | for scanner.Scan() { 28 | freqs[scanner.Text()]++ 29 | } 30 | 31 | fmt.Print("\nfreq\tword\n") 32 | for i, f := range freqs { 33 | fmt.Printf("%d\t%s\n", f, i) 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch5/ex5_1/main.go: -------------------------------------------------------------------------------- 1 | // Change the findlinks program to traverse the `n.FirstChild` linked list using 2 | // recursive calls to `visit` instead of a loop. 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | "os" 8 | 9 | "golang.org/x/net/html" 10 | ) 11 | 12 | func main() { 13 | doc, err := html.Parse(os.Stdin) 14 | if err != nil { 15 | fmt.Fprintf(os.Stderr, "findlinks: %v\n", err) 16 | os.Exit(1) 17 | } 18 | 19 | for _, link := range visit(nil, doc) { 20 | fmt.Println(link) 21 | } 22 | } 23 | 24 | func visit(links []string, n *html.Node) []string { 25 | // todo - write it out on the whiteboard 26 | if n.Type == html.ElementNode && n.Data == "a" { 27 | for _, a := range n.Attr { 28 | if a.Key == "href" { 29 | links = append(links, a.Val) 30 | } 31 | } 32 | } 33 | 34 | if n.FirstChild != nil { 35 | links = visit(links, n.FirstChild) 36 | } 37 | 38 | if n.NextSibling != nil { 39 | links = visit(links, n.NextSibling) 40 | } 41 | 42 | return links 43 | } 44 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch5/ex5_10/prereqs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bbc/eng-golang-workshop/94c99f4a002654404c945c3c94f437c720039b83/workspaces/betandr/src/andr.io/ch5/ex5_10/prereqs.png -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch5/ex5_11/prereqs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bbc/eng-golang-workshop/94c99f4a002654404c945c3c94f437c720039b83/workspaces/betandr/src/andr.io/ch5/ex5_11/prereqs.png -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch5/ex5_16/main.go: -------------------------------------------------------------------------------- 1 | // Write a variadic version of `strings.Join`. 2 | package main 3 | 4 | import ( 5 | "fmt" 6 | "strings" 7 | ) 8 | 9 | // join appends the supplied strings in `strs`. It uses `strings.Join` 10 | // which is an efficient way to append strings if you already know them but 11 | // we still have a variadic interface! ;) 12 | func join(strs ...string) (result string) { 13 | return strings.Join(strs, "") 14 | } 15 | 16 | func main() { 17 | fmt.Println(join("Hello", ",", " ", "World", "!")) 18 | } 19 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch5/ex5_18/main.go: -------------------------------------------------------------------------------- 1 | // Without changing its behavior, rewrite the fetch function to use defer to 2 | // close the writable file. 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | "io" 8 | "net/http" 9 | "os" 10 | "path" 11 | ) 12 | 13 | // Fetch downloads the URL and returns the 14 | // name and length of the local file. 15 | func fetch(url string) (filename string, n int64, err error) { 16 | resp, err := http.Get(url) 17 | if err != nil { 18 | return "", 0, err 19 | } 20 | defer resp.Body.Close() 21 | 22 | local := path.Base(resp.Request.URL.Path) 23 | if local == "/" { 24 | local = "index.html" 25 | } 26 | f, err := os.Create(local) 27 | if err != nil { 28 | return "", 0, err 29 | } 30 | n, err = io.Copy(f, resp.Body) 31 | defer func() { // defer closing the file but preserve error checking 32 | if closeErr := f.Close(); err == nil { 33 | err = closeErr 34 | } 35 | }() 36 | 37 | return local, n, err 38 | } 39 | 40 | func main() { 41 | for _, url := range os.Args[1:] { 42 | local, n, err := fetch(url) 43 | if err != nil { 44 | fmt.Fprintf(os.Stderr, "fetch %s: %v\n", url, err) 45 | continue 46 | } 47 | fmt.Fprintf(os.Stderr, "%s => %s (%d bytes).\n", url, local, n) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch5/ex5_19/main.go: -------------------------------------------------------------------------------- 1 | // Use `panic` and `recover` to write a function that contains no return 2 | // statement yet returns a non-zero value. 3 | package main 4 | 5 | import "fmt" 6 | 7 | func dontPanic() (foo int) { 8 | defer func() { 9 | if p := recover(); p != nil { 10 | foo = 42 11 | } 12 | }() 13 | 14 | panic("Don't panic") 15 | } 16 | 17 | func main() { 18 | fmt.Printf("The answer is %d.\n", dontPanic()) 19 | } 20 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch5/ex5_2/main.go: -------------------------------------------------------------------------------- 1 | // Change the findlinks program to traverse the `n.FirstChild` linked list using 2 | // recursive calls to `visit` instead of a loop. 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | "os" 8 | 9 | "golang.org/x/net/html" 10 | ) 11 | 12 | func main() { 13 | doc, err := html.Parse(os.Stdin) 14 | if err != nil { 15 | fmt.Fprintf(os.Stderr, "findlinks: %v\n", err) 16 | os.Exit(1) 17 | } 18 | 19 | for element, count := range visit(nil, doc) { 20 | fmt.Printf("%s %d\n", element, count) 21 | } 22 | } 23 | 24 | func visit(elements map[string]int, n *html.Node) map[string]int { 25 | if elements == nil { 26 | elements = make(map[string]int) 27 | } 28 | 29 | if n.Type == html.ElementNode { 30 | elements[n.Data]++ 31 | } 32 | 33 | for c := n.FirstChild; c != nil; c = c.NextSibling { 34 | elements = visit(elements, c) 35 | } 36 | return elements 37 | } 38 | -------------------------------------------------------------------------------- /workspaces/betandr/src/andr.io/ch5/ex5_3/main.go: -------------------------------------------------------------------------------- 1 | // Write a function to print the contents of all text nodes in an HTML document 2 | // tree. Do not descend into `