[
  {
    "path": ".gitignore",
    "content": "# Compiled Object files, Static and Dynamic libs (Shared Objects)\n*.o\n*.a\n*.so\n\n# Folders\n_obj\n_test\n\n# Architecture specific extensions/prefixes\n*.[568vq]\n[568vq].out\n\n*.cgo1.go\n*.cgo2.c\n_cgo_defun.c\n_cgo_gotypes.go\n_cgo_export.*\n\n_testmain.go\n\nlogs.txt\n*.exe\n*.test\n*.prof\n*.txt\ndebug\n.vscode"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2016 Shiju Varghese\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Go Recipes\nCode examples for the book \"Go Recipes\" by Apress.\n\n# gokit\nCheck out [github.com/shijuvar/gokit](https://github.com/shijuvar/gokit) for further examples on Go. \n\n## Articles \n* [Building High Performance APIs In Go Using gRPC And Protocol Buffers](https://medium.com/@shijuvar/building-high-performance-apis-in-go-using-grpc-and-protocol-buffers-2eda5b80771b) \n* [Using Binary-Only Packages In Go](https://medium.com/@shijuvar/using-binary-only-packages-in-go-667bd7b123c8)\n\n"
  },
  {
    "path": "binarypkg/src/github.com/shijuvar/binarypkg/utils.go",
    "content": "//go:binary-only-package\n\npackage binarypkg\n"
  },
  {
    "path": "binarypkg/utils.go",
    "content": "package binarypkg\n\nimport \"strings\"\n\n// ToUpperCase returns the string changed with upper case.\nfunc ToUpperCase(s string) string {\n\treturn strings.ToUpper(s)\n}\n\n// ToLowerCase returns the string changed with lower case.\nfunc ToLowerCase(s string) string {\n\treturn strings.ToLower(s)\n}\n"
  },
  {
    "path": "binarypkgdemo/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/shijuvar/go-recipes/binarypkg\"\n)\n\nfunc main() {\n\tstr := \"Golang\"\n\t// Convert to upper case\n\tfmt.Println(\"To Upper Case:\", binarypkg.ToUpperCase(str))\n\n\t// Convert to lower case\n\tfmt.Println(\"To Lower Case:\", binarypkg.ToLowerCase(str))\n\n}\n"
  },
  {
    "path": "ch01/declarations/enum.go",
    "content": "package main\n\nimport \"fmt\"\n\nconst (\n\t// UNSPECIFIED logs nothing\n\tUNSPECIFIED Level = iota // 0 :\n\t// TRACE logs everything\n\tTRACE // 1\n\t// INFO logs Info, Warnings and Errors\n\tINFO // 2\n\t// WARNING logs Warning and Errors\n\tWARNING // 3\n\t// ERROR just logs Errors\n\tERROR // 4\n)\n\n// Level holds the log level.\ntype Level int\n\n// levels provides the string name of Level\nvar levels = [...]string{\n\t\"UNSPECIFIED\",\n\t\"TRACE\",\n\t\"INFO\",\n\t\"WARNING\",\n\t\"ERROR\",\n}\n\n// String returns the string value of level\nfunc (l Level) String() string {\n\treturn levels[l]\n}\n\nfunc main() {\n\tlevel := TRACE\n\tif level == TRACE {\n\t\tfmt.Println(\"TRACE\")\n\t}\n\tlevel = INFO\n\tfmt.Println(level.String())\n}\n"
  },
  {
    "path": "ch01/declarations/main.go",
    "content": "package main\n\nimport \"fmt\"\n\n// Declare constant\nconst Title = \"Person Details\"\n\n// Declare package variable\nvar Country = \"USA\"\n\nfunc main() {\n\tfname, lname := \"Shiju\", \"Varghese\"\n\tage := 35\n\t// Print constant variable\n\tfmt.Println(Title)\n\t// Print local variables\n\tfmt.Println(\"First Name:\", fname)\n\tfmt.Println(\"Last Name:\", lname)\n\tfmt.Println(\"Age:\", age)\n\t// Print package variable\n\tfmt.Println(\"Country:\", Country)\n}\n"
  },
  {
    "path": "ch01/declarations/main1.go",
    "content": "package main\n\nimport \"fmt\"\n\n// Declare constant\nconst Title string = \"Person Details\"\n\n// Declare package variable\nvar Country string = \"USA\"\n\nfunc main() {\n\tvar fname, lname string = \"Shiju\", \"Varghese\"\n\tvar age int = 35\n\t// Print constant variable\n\tfmt.Println(Title)\n\t// Print local variables\n\tfmt.Println(\"First Name:\", fname)\n\tfmt.Println(\"Last Name:\", lname)\n\tfmt.Println(\"Age:\", age)\n\t// Print package variable\n\tfmt.Println(\"Country:\", Country)\n}\n"
  },
  {
    "path": "ch01/favorites/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\n\tfav \"github.com/shijuvar/go-recipes/ch01/lib\"\n)\n\nfunc main() {\n\t// Print default favorite packages\n\tfmt.Println(\"****** Default favorite packages ******\\n\")\n\tfav.PrintFavorites()\n\t// Add couple of favorites\n\tfav.Add(\"github.com/dgrijalva/jwt-go\")\n\tfav.Add(\"github.com/onsi/ginkgo\")\n\tfmt.Println(\"\\n****** All favorite packages ******\\n\")\n\tfav.PrintFavorites()\n\tcount := len(fav.GetAll())\n\tfmt.Printf(\"Total packages in the favorite list:%d\", count)\n}\n"
  },
  {
    "path": "ch01/hello/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Println(\"Hello, World\")\n}\n"
  },
  {
    "path": "ch01/lib/favorites.go",
    "content": "package lib\n\n// Stores favorites\nvar favorites []string\n\n// Initialization logic for the package\nfunc init() {\n\tfavorites = make([]string, 3)\n\tfavorites[0] = \"github.com/gorilla/mux\"\n\tfavorites[1] = \"github.com/codegangsta/negroni\"\n\tfavorites[2] = \"gopkg.in/mgo.v2\"\n}\n\n// Add a favorite into the in-memory collection\nfunc Add(favorite string) {\n\tfavorites = append(favorites, favorite)\n}\n\n// Returns all favorite\nfunc GetAll() []string {\n\treturn favorites\n}\n"
  },
  {
    "path": "ch01/lib/utils.go",
    "content": "package lib\n\nimport (\n\t\"fmt\"\n)\n\n// Print all favorites\nfunc PrintFavorites() {\n\tfor _, v := range favorites {\n\t\tfmt.Println(v)\n\t}\n}\n"
  },
  {
    "path": "ch01/loop/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tsum()\n\tsum1()\n}\nfunc sum() {\n\tsum := 0\n\tfor i := 0; i < 10; i++ {\n\t\tsum += i\n\t}\n\tfmt.Println(sum)\n}\nfunc sum1() {\n\tsum := 1\n\tfor sum < 50 {\n\t\tsum += sum\n\t}\n\tfmt.Println(sum)\n}\n"
  },
  {
    "path": "ch01/strutils/utils.go",
    "content": "// Package strutils provides string utility functions\npackage strutils\n\nimport (\n\t\"strings\"\n\t\"unicode\"\n)\n\n// Returns the string changed with upper case.\nfunc ToUpperCase(s string) string {\n\treturn strings.ToUpper(s)\n}\n\n// Returns the string changed with lower case.\nfunc ToLowerCase(s string) string {\n\treturn strings.ToLower(s)\n}\n\n// Returns the string changed to upper case for its first letter.\nfunc ToFirstUpper(s string) string {\n\tif len(s) < 1 { // if the empty string\n\t\treturn s\n\t}\n\t// Trim the string\n\tt := strings.Trim(s, \" \")\n\t// Convert all letters to lower case\n\tt = strings.ToLower(t)\n\tres := []rune(t)\n\t// Convert first letter to upper case\n\tres[0] = unicode.ToUpper(res[0])\n\treturn string(res)\n}\n"
  },
  {
    "path": "ch01/strutilsdemo/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/shijuvar/go-recipes/ch01/strutils\"\n)\n\nfunc main() {\n\tstr1, str2 := \"Golang\", \"gopher\"\n\t// Convert to upper case\n\tfmt.Println(\"To Upper Case:\", strutils.ToUpperCase(str1))\n\n\t// Convert to lower case\n\tfmt.Println(\"To Lower Case:\", strutils.ToLowerCase(str1))\n\n\t// Convert first letter to upper case\n\tfmt.Println(\"To First Upper:\", strutils.ToFirstUpper(str2))\n}\n"
  },
  {
    "path": "ch01/typeconv/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n)\n\nfunc main() {\n\t// type conversion: dealing with a type\n\t// The expression T(v) converts the value v to the type T\n\ti := 100\n\tf := float64(i)\n\tfmt.Println(reflect.TypeOf(f))\n\t// type assertion: dealing with an interface\n\t// A type assertion provides access to an interface value's underlying concrete value\n\tvar x interface{} = 100 //float64(100)\n\ty := x.(float64)\n\tfmt.Println(reflect.TypeOf(y))\n}\n"
  },
  {
    "path": "ch01/vetting/main.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfloatValue:=4.99\n\tfmt.Printf(\"The value is: %d\",floatValue)\n}\n"
  },
  {
    "path": "ch02/arrays/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\t// Declare arrays\n\tvar x [5]int\n\t// Assign values at specific index\n\tx[0] = 5\n\tx[4] = 25\n\tfmt.Println(\"Value of x:\", x)\n\n\tx[1] = 10\n\tx[2] = 15\n\tx[3] = 20\n\tfmt.Println(\"Value of x:\", x)\n\n\t// Declare and initialize array with array literal\n\ty := [5]int{10, 20, 30, 40, 50}\n\tfmt.Println(\"Value of y:\", y)\n\tfmt.Println(\"Length of y:\", len(y))\n\n\t// Array literal with ...\n\tz := [...]int{10, 20, 30, 40, 50}\n\tfmt.Println(\"Value of z:\", z)\n\tfmt.Println(\"Length of z:\", len(z))\n\n\t// Initialize values at specific index with array literal\n\tlangs := [4]string{0: \"Go\", 3: \"Julia\"}\n\tfmt.Println(\"Value of langs:\", langs)\n\t// Assign values to remain positions\n\tlangs[1] = \"Rust\"\n\tlangs[2] = \"Scala\"\n\n\t// Iterate over the elements of array\n\tfmt.Println(\"Value of langs:\", langs)\n\tfmt.Println(\"\\nIterate over arrays\\n\")\n\tfor i := 0; i < len(langs); i++ {\n\t\tfmt.Printf(\"langs[%d]:%s \\n\", i, langs[i])\n\t}\n\tfmt.Println(\"\\n\")\n\n\t// Iterate over the elements of array using range\n\tfor k, v := range langs {\n\t\tfmt.Printf(\"langs[%d]:%s \\n\", k, v)\n\t}\n\tfor k := range langs {\n\t\tfmt.Printf(\"Index:%d \\n\", k)\n\t}\n\tfor _, v := range langs {\n\t\tfmt.Printf(\"Value:%s \\n\", v)\n\t}\n}\n"
  },
  {
    "path": "ch02/defer/deferfunc.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"os\"\n)\n\nfunc ReadFile(filename string) ([]byte, error) {\n\tf, err := os.Open(filename)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer f.Close()\n\treturn ioutil.ReadAll(f)\n}\n\nfunc main() {\n\tf, _ := ReadFile(\"test.txt\")\n\tfmt.Println(\"%s\", f)\n\tfmt.Println(string(f))\n}\n"
  },
  {
    "path": "ch02/defer/panicrecover.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc panicRecover() {\n\n\tdefer fmt.Println(\"Deferred call - 1\")\n\tdefer func() {\n\t\tfmt.Println(\"Deferred call - 2\")\n\t\tif e := recover(); e != nil {\n\t\t\t// e is the value passed to panic()\n\t\t\tfmt.Println(\"Recover with: \", e)\n\t\t}\n\t}()\n\tpanic(\"Just panicking for the sake of example\")\n\tfmt.Println(\"This will never be called\")\n}\n\nfunc main() {\n\tfmt.Println(\"Starting to panic\")\n\tpanicRecover()\n\tfmt.Println(\"Program regains control after the panic recovery\")\n}\n"
  },
  {
    "path": "ch02/functions/calc.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc Add(x, y int) int {\n\treturn x + y\n}\n\nfunc Subtract(x, y int) int {\n\treturn x - y\n}\n\nfunc main() {\n\tx, y := 20, 10\n\n\tresult := Add(x, y)\n\tfmt.Println(\"[Add]:\", result)\n\n\tresult = Subtract(x, y)\n\tfmt.Println(\"[Subtract]:\", result)\n}\n"
  },
  {
    "path": "ch02/functions/closures.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc SplitValues(f func(sum int) (int, int)) {\n\tx, y := f(35)\n\tfmt.Println(x, y)\n\n\tx, y = f(50)\n\tfmt.Println(x, y)\n}\n\nfunc main() {\n\ta, b := 5, 8\n\tfn := func(sum int) (int, int) {\n\t\tx := sum * a / b\n\t\ty := sum - x\n\t\treturn x, y\n\t}\n\n\t// Passing function value as an argument to another function\n\tSplitValues(fn)\n\n\t// Calling the function value by providing argument\n\tx, y := fn(20)\n\tfmt.Println(x, y)\n}\n"
  },
  {
    "path": "ch02/functions/swap.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc Swap(x, y string) (string, string) {\n\treturn y, x\n}\n\nfunc main() {\n\tx, y := \"Shiju\", \"Varghese\"\n\tfmt.Println(\"Before Swap:\", x, y)\n\n\tx, y = Swap(x, y)\n\tfmt.Println(\"After Swap:\", x, y)\n}\n"
  },
  {
    "path": "ch02/functions/variadic.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc Sum(nums ...int) int {\n\ttotal := 0\n\tfor _, num := range nums {\n\t\ttotal += num\n\t}\n\treturn total\n}\n\nfunc main() {\n\t// Providing four arguments\n\ttotal := Sum(1, 2, 3, 4)\n\tfmt.Println(\"The Sum is:\", total)\n\n\t// Providing three arguments\n\ttotal = Sum(5, 7, 8)\n\tfmt.Println(\"The Sum is:\", total)\n\n\t// Providing a Slice as an argument\n\tnums := []int{1, 2, 3, 4, 5}\n\ttotal = Sum(nums...)\n\tfmt.Println(\"The Sum is:\", total)\n}\n"
  },
  {
    "path": "ch02/maps/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\t// Declares a nil map\n\tvar chapts map[int]string\n\n\t// Initialize map with make function\n\tchapts = make(map[int]string)\n\n\t// Add data as key/value pairs\n\tchapts[1] = \"Beginning Go\"\n\tchapts[2] = \"Go Fundamentals\"\n\tchapts[3] = \"Structs and Interfaces\"\n\n\t// Iterate over the elements of map using range\n\tfor k, v := range chapts {\n\t\tfmt.Printf(\"Key: %d Value: %s\\n\", k, v)\n\t}\n\n\t// Declare and initialize map using map literal\n\tlangs := map[string]string{\n\t\t\"EL\": \"Greek\",\n\t\t\"EN\": \"English\",\n\t\t\"ES\": \"Spanish\",\n\t\t\"FR\": \"French\",\n\t\t\"HI\": \"Hindi\",\n\t}\n\n\t// Delete an element\n\tdelete(langs, \"EL\")\n\n\t// Lookout an element with key\n\tif lan, ok := langs[\"EL\"]; ok {\n\t\tfmt.Println(lan)\n\t} else {\n\t\tfmt.Println(\"\\nKey doesn't exists\")\n\t}\n\t// Passing a map to function doesn't make a copy\n\tremoveLan(langs, \"HI\")\n\tfor k, v := range langs {\n\t\tfmt.Printf(\"Key: %s Value: %s\\n\", k, v)\n\t}\n}\nfunc removeLan(langs map[string]string, key string) {\n\tdelete(langs, key)\n}\n"
  },
  {
    "path": "ch02/maps/sort_map.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n)\n\nfunc main() {\n\t// Initialize map with make function\n\tchapts := make(map[int]string)\n\n\t// Add data as key/value pairs\n\tchapts[1] = \"Beginning Go\"\n\tchapts[2] = \"Go Fundamentals\"\n\tchapts[3] = \"Structs and Interfaces\"\n\tfor k, v := range chapts {\n\t\tfmt.Println(k, v)\n\t}\n\n\t// Slice for specifying the order of the map\n\tvar keys []int\n\t// Appending keys of the map\n\tfor k := range chapts {\n\t\tkeys = append(keys, k)\n\t}\n\t// Ints sorts a slice of ints in increasing order.\n\tsort.Ints(keys)\n\t// Iterate over the map with an order\n\tfor _, k := range keys {\n\t\tfmt.Println(\"Key:\", k, \"Value:\", chapts[k])\n\t}\n}\n"
  },
  {
    "path": "ch02/slices/append.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\tx := make([]int, 2, 5)\n\tx[0] = 10\n\tx[1] = 20\n\tfmt.Println(\"Slice x:\", x)\n\tfmt.Printf(\"Length is %d Capacity is %d\\n\", len(x), cap(x))\n\t// Create a bigger slice\n\tx = append(x, 30, 40, 50)\n\tfmt.Println(\"Slice x after appending data:\", x)\n\tfmt.Printf(\"Length is %d Capacity is %d\\n\", len(x), cap(x))\n\n\tx = append(x, 60, 70, 80)\n\tfmt.Println(\"Slice x after appending data for the second time:\", x)\n\tfmt.Printf(\"Length is %d Capacity is %d\\n\", len(x), cap(x))\n\n}\n"
  },
  {
    "path": "ch02/slices/append_nilslice.go",
    "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\t// Declare a nil slice\n\tvar x []int\n\tfmt.Println(x, len(x), cap(x))\n\tx = append(x, 10, 20, 30)\n\tfmt.Println(\"Slice x after appending data:\", x)\n}\n"
  },
  {
    "path": "ch02/slices/copy.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\tx := []int{10, 20, 30}\n\tfmt.Printf(\"[Slice:x] Length is %d Capacity is %d\\n\", len(x), cap(x))\n\t// Create a bigger slice\n\ty := make([]int, 5, 10)\n\tcopy(y, x)\n\tfmt.Printf(\"[Slice:y] Length is %d Capacity is %d\\n\", len(y), cap(y))\n\tfmt.Println(\"Slice y after copying:\", y)\n\ty[3] = 40\n\ty[4] = 50\n\tfmt.Println(\"Slice y after adding elements:\", y)\n}\n"
  },
  {
    "path": "ch02/slices/iterate.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\tx := []int{10, 20, 30, 40, 50}\n\tfor k, v := range x {\n\t\tfmt.Printf(\"x[%d]: %d\\n\", k, v)\n\t}\n}\n"
  },
  {
    "path": "ch02/slices/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\tx := make([]int, 3, 5)\n\tx[0] = 10\n\tx[1] = 20\n\tx[2] = 30\n\tfmt.Println(x)\n\tfmt.Println(len(x))\n\tfmt.Println(cap(x))\n\n\ty := make([]int, 3)\n\ty[0] = 10\n\ty[1] = 20\n\ty[2] = 30\n\tfmt.Println(y)\n\tfmt.Println(len(y))\n\tfmt.Println(cap(y))\n\n\tz := []int{10, 20, 30}\n\tfmt.Println(len(z))\n\tfmt.Println(cap(z))\n\n\tz1 := []int{0: 10, 2: 30}\n\tfmt.Println(len(z1))\n\tfmt.Println(cap(z1))\n\n\tx1 := []int{10, 20, 30}\n\ty1 := append(x1, 40, 50)\n\tfmt.Println(x1, y1)\n}\n"
  },
  {
    "path": "ch02/slices/slicing.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\tx := []int{10, 20, 30, 40, 50}\n\ty := x[1:3]\n\tfmt.Println(\"y:\", y)\n\tfmt.Println(len(y))\n\tfmt.Println(cap(y))\n\n\tz := x[:3]\n\tfmt.Println(\"z:\", z)\n\tfmt.Println(len(z))\n\tfmt.Println(cap(z))\n\tx1 := x[:]\n\tfmt.Println(\"x1:\", x1)\n\tfmt.Println(len(x1))\n\tfmt.Println(cap(x1))\n\n\tx1[4] = 75\n\tfmt.Println(\"x:\", x)\n\tfmt.Println(\"x1:\", x1)\n\n}\n"
  },
  {
    "path": "ch03/ecommerce/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"time\"\n)\n\nfunc main() {\n\torder := &Order{\n\t\tId: 1001,\n\t\tCustomer: Customer{\n\t\t\tFirstName: \"Alex\",\n\t\t\tLastName:  \"John\",\n\t\t\tEmail:     \"alex@email.com\",\n\t\t\tPhone:     \"732-757-2923\",\n\t\t\tAddresses: []Address{\n\t\t\t\tAddress{\n\t\t\t\t\tStreet:            \"1 Mission Street\",\n\t\t\t\t\tCity:              \"San Francisco\",\n\t\t\t\t\tState:             \"CA\",\n\t\t\t\t\tZip:               \"94105\",\n\t\t\t\t\tIsShippingAddress: true,\n\t\t\t\t},\n\t\t\t\tAddress{\n\t\t\t\t\tStreet: \"49 Stevenson Street\",\n\t\t\t\t\tCity:   \"San Francisco\",\n\t\t\t\t\tState:  \"CA\",\n\t\t\t\t\tZip:    \"94105\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tStatus:   \"Placed\",\n\t\tPlacedOn: time.Date(2016, time.April, 10, 0, 0, 0, 0, time.UTC),\n\t\tOrderItems: []OrderItem{\n\t\t\tOrderItem{\n\t\t\t\tProduct: Product{\n\t\t\t\t\tCode:        \"knd100\",\n\t\t\t\t\tName:        \"Kindle Voyage\",\n\t\t\t\t\tDescription: \"Kindle Voyage Wifi, 6 High-Resolution Display\",\n\t\t\t\t\tUnitPrice:   220,\n\t\t\t\t},\n\t\t\t\tQuantity: 1,\n\t\t\t},\n\t\t\tOrderItem{\n\t\t\t\tProduct: Product{\n\t\t\t\t\tCode:        \"fint101\",\n\t\t\t\t\tName:        \"Kindle Case\",\n\t\t\t\t\tDescription: \"Fintie Kindle Voyage SmartShell Case\",\n\t\t\t\t\tUnitPrice:   10,\n\t\t\t\t},\n\t\t\t\tQuantity: 2,\n\t\t\t},\n\t\t},\n\t}\n\n\tfmt.Println(order.ToString())\n\t// Change Order status\n\torder.ChangeStatus(\"Processing\")\n\tfmt.Println(\"\\n\")\n\tfmt.Println(order.ToString())\n}\n"
  },
  {
    "path": "ch03/ecommerce/models.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"time\"\n)\n\ntype Address struct {\n\tStreet, City, State, Zip string\n\tIsShippingAddress        bool\n}\n\ntype Customer struct {\n\tFirstName, LastName, Email, Phone string\n\tAddresses                         []Address\n}\n\nfunc (c Customer) ToString() string {\n\treturn fmt.Sprintf(\"Customer: %s %s, Email:%s\", c.FirstName, c.LastName, c.Email)\n}\nfunc (c Customer) ShippingAddress() string {\n\tfor _, v := range c.Addresses {\n\t\tif v.IsShippingAddress == true {\n\t\t\treturn fmt.Sprintf(\"%s, %s, %s, Zip - %s\", v.Street, v.City, v.State, v.Zip)\n\t\t}\n\t}\n\treturn \"\"\n}\n\ntype Order struct {\n\tId int\n\tCustomer\n\tPlacedOn   time.Time\n\tStatus     string\n\tOrderItems []OrderItem\n}\n\nfunc (o *Order) GrandTotal() float64 {\n\tvar total float64\n\tfor _, v := range o.OrderItems {\n\t\ttotal += v.Total()\n\t}\n\treturn total\n}\nfunc (o *Order) ToString() string {\n\tvar orderStr string\n\torderStr = fmt.Sprintf(\"Order#:%d, OrderDate:%s, Status:%s, Grand Total:%f\\n\", o.Id, o.PlacedOn, o.Status, o.GrandTotal())\n\torderStr += o.Customer.ToString()\n\torderStr += fmt.Sprintf(\"\\nOrder Items:\")\n\tfor _, v := range o.OrderItems {\n\t\torderStr += fmt.Sprintf(\"\\n\")\n\t\torderStr += v.ToString()\n\t}\n\torderStr += fmt.Sprintf(\"\\nShipping Address:\")\n\torderStr += o.Customer.ShippingAddress()\n\treturn orderStr\n}\nfunc (o *Order) ChangeStatus(newStatus string) {\n\to.Status = newStatus\n}\n\ntype OrderItem struct {\n\tProduct\n\tQuantity int\n}\n\nfunc (item OrderItem) Total() float64 {\n\treturn float64(item.Quantity) * item.Product.UnitPrice\n}\nfunc (item OrderItem) ToString() string {\n\titemStr := fmt.Sprintf(\"Code:%s, Product:%s -- %s, UnitPrice:%f, Quantity:%d, Total:%f\",\n\t\titem.Product.Code, item.Product.Name, item.Product.Description, item.Product.UnitPrice, item.Quantity, item.Total())\n\treturn itemStr\n\n}\n\ntype Product struct {\n\tCode, Name, Description string\n\tUnitPrice               float64\n}\n"
  },
  {
    "path": "ch03/employee/employee.go",
    "content": "// Example program with Interface, Composition and Method Overriding\npackage main\n\nimport (\n\t\"fmt\"\n\t\"time\"\n)\n\ntype TeamMember interface {\n\tPrintName()\n\tPrintDetails()\n}\n\ntype Employee struct {\n\tFirstName, LastName string\n\tDob                 time.Time\n\tJobTitle, Location  string\n}\n\nfunc (e Employee) PrintName() {\n\tfmt.Printf(\"\\n%s %s\\n\", e.FirstName, e.LastName)\n}\n\nfunc (e Employee) PrintDetails() {\n\tfmt.Printf(\"Date of Birth: %s, Job: %s, Location: %s\\n\", e.Dob.String(), e.JobTitle, e.Location)\n}\n\ntype Developer struct {\n\tEmployee //type embedding for composition\n\tSkills   []string\n}\n\n// Overrides the PrintDetails\nfunc (d Developer) PrintDetails() {\n\t// Call Employee PrintDetails\n\td.Employee.PrintDetails()\n\tfmt.Println(\"Technical Skills:\")\n\tfor _, v := range d.Skills {\n\t\tfmt.Println(v)\n\t}\n}\n\ntype Manager struct {\n\tEmployee  //type embedding for composition\n\tProjects  []string\n\tLocations []string\n}\n\n// Overrides the PrintDetails\nfunc (m Manager) PrintDetails() {\n\t// Call Employee PrintDetails\n\tm.Employee.PrintDetails()\n\tfmt.Println(\"Projects:\")\n\tfor _, v := range m.Projects {\n\t\tfmt.Println(v)\n\t}\n\tfmt.Println(\"Managing teams for the locations:\")\n\tfor _, v := range m.Locations {\n\t\tfmt.Println(v)\n\t}\n}\n\ntype Team struct {\n\tName, Description string\n\tTeamMembers       []TeamMember\n}\n\nfunc (t Team) PrintTeamDetails() {\n\tfmt.Printf(\"Team: %s  - %s\\n\", t.Name, t.Description)\n\tfmt.Println(\"Details of the team members:\")\n\tfor _, v := range t.TeamMembers {\n\t\tv.PrintName()\n\t\tv.PrintDetails()\n\t}\n}\n\nfunc main() {\n\tsteve := Developer{\n\t\tEmployee: Employee{\n\t\t\tFirstName: \"Steve\",\n\t\t\tLastName:  \"John\",\n\t\t\tDob:       time.Date(1990, time.February, 17, 0, 0, 0, 0, time.UTC),\n\t\t\tJobTitle:  \"Software Engineer\",\n\t\t\tLocation:  \"San Fancisco\",\n\t\t},\n\t\tSkills: []string{\"Go\", \"Docker\", \"Kubernetes\"},\n\t}\n\tirene := Developer{\n\t\tEmployee: Employee{\n\t\t\tFirstName: \"Irene\",\n\t\t\tLastName:  \"Rose\",\n\t\t\tDob:       time.Date(1991, time.January, 13, 0, 0, 0, 0, time.UTC),\n\t\t\tJobTitle:  \"Software Engineer\",\n\t\t\tLocation:  \"Santa Clara\",\n\t\t},\n\t\tSkills: []string{\"Go\", \"MongoDB\"},\n\t}\n\talex := Manager{\n\t\tEmployee: Employee{\n\t\t\tFirstName: \"Alex\",\n\t\t\tLastName:  \"Williams\",\n\t\t\tDob:       time.Date(1979, time.February, 17, 0, 0, 0, 0, time.UTC),\n\t\t\tJobTitle:  \"Program Manger\",\n\t\t\tLocation:  \"Santa Clara\",\n\t\t},\n\t\tProjects:  []string{\"CRM\", \"e-Commerce\"},\n\t\tLocations: []string{\"San Fancisco\", \"Santa Clara\"},\n\t}\n\n\t// Create team\n\tteam := Team{\n\t\t\"Go\",\n\t\t\"Golang Engineering Team\",\n\t\t[]TeamMember{steve, irene, alex},\n\t}\n\t// Get details of Team\n\tteam.PrintTeamDetails()\n}\n"
  },
  {
    "path": "ch03/person.go",
    "content": "// Person struct with methods of pointer receiver\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"time\"\n)\n\n// Person struct\ntype Person struct {\n\tFirstName, LastName string\n\tDob                 time.Time\n\tEmail, Location     string\n}\n\n// PrintName prints the name of the Person\nfunc (p Person) PrintName() {\n\tfmt.Printf(\"\\n%s %s\\n\", p.FirstName, p.LastName)\n}\n\n// PrintDetails prints the details of Person\nfunc (p Person) PrintDetails() {\n\tfmt.Printf(\"[Date of Birth: %s, Email: %s, Location: %s ]\\n\", p.Dob.String(), p.Email, p.Location)\n}\n\nfunc main() {\n\t/*\n\t\t       // Declare a Person variable using var\n\t\t\t\tvar p Person\n\t\t\t\t// Assign values to fields\n\t\t\t\tp.FirstName=\"Shiju\"\n\t\t\t\tp.LastName=\"Varghese\"\n\t\t\t\tp.Dob= time.Date(1979, time.February, 17, 0, 0, 0, 0, time.UTC)\n\t\t\t\tp.Email=\"shiju@email.com\"\n\t\t\t\tp.Location= \"Kochi\"\n\n\t\t\t\t// Declare a Person variable and initialize values using Struct literal\n\t\t\t\tp := Person{\n\t\t\t\t\t\"Shiju\",\n\t\t\t\t\t\"Varghese\",\n\t\t\t\t\ttime.Date(1979, time.February, 17, 0, 0, 0, 0, time.UTC),\n\t\t\t\t\t\"shiju@email.com\",\n\t\t\t\t\t\"Kochi\",\n\t\t\t\t}\n\n\t*/\n\tp := Person{\n\t\tFirstName: \"Shiju\",\n\t\tLastName:  \"Varghese\",\n\t\tDob:       time.Date(1979, time.February, 17, 0, 0, 0, 0, time.UTC),\n\t\tEmail:     \"shiju@email.com\",\n\t\tLocation:  \"Kochi\",\n\t}\n\tp.PrintName()\n\tp.PrintDetails()\n\n}\n"
  },
  {
    "path": "ch03/pointer/main.go",
    "content": "// Person struct with methods of pointer receiver\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"time\"\n)\n\ntype Person struct {\n\tFirstName, LastName string\n\tDob                 time.Time\n\tEmail, Location     string\n}\n\n//A person method with pointer receiver\nfunc (p *Person) PrintName() {\n\tfmt.Printf(\"\\n%s %s\\n\", p.FirstName, p.LastName)\n}\n\n//A person method with pointer receiver\nfunc (p *Person) PrintDetails() {\n\tfmt.Printf(\"[Date of Birth: %s, Email: %s, Location: %s ]\\n\", p.Dob.String(), p.Email, p.Location)\n}\n\n//A person method with pointer receiver\nfunc (p *Person) ChangeLocation(newLocation string) {\n\tp.Location = newLocation\n}\nfunc main() {\n\tp := &Person{\n\t\t\"Shiju\",\n\t\t\"Varghese\",\n\t\ttime.Date(1979, time.February, 17, 0, 0, 0, 0, time.UTC),\n\t\t\"shiju@email.com\",\n\t\t\"Kochi\",\n\t}\n\tp.ChangeLocation(\"Santa Clara\")\n\tp.PrintName()\n\tp.PrintDetails()\n\n}\n"
  },
  {
    "path": "ch04/channels/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\t// Declare a unbuffered channel\n\tcounter := make(chan int)\n\t// Creates a buffered channel with capacity of 3\n\tnums := make(chan int, 3)\n\tgo func() {\n\t\t// Send value to the unbuffered channel\n\t\tcounter <- 1\n\t\tclose(counter) // Closes the channel\n\t}()\n\n\tgo func() {\n\t\t// Send values to the buffered channel\n\t\tnums <- 10\n\t\tnums <- 30\n\t\tnums <- 50\n\t}()\n\t// Read the value from unbuffered channel\n\tfmt.Println(<-counter)\n\tval, ok := <-counter // Trying to read from closed channel\n\tif ok {\n\t\tfmt.Println(val) // This won't execute\n\t}\n\t// Read the 3 buffered values from the buffered channel\n\tfmt.Println(<-nums)\n\tfmt.Println(<-nums)\n\tfmt.Println(<-nums)\n\tclose(nums) // Closes the channel\n}\n"
  },
  {
    "path": "ch04/deadlock/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\t// Declare a unbuffered channel\n\tcounter := make(chan int)\n\t// Perform send operation by launching new goroutine\n\tgo func() {\n\t\tcounter <- 10\n\t}()\n\tfmt.Println(<-counter) // Receive operation from the channel\n}\n"
  },
  {
    "path": "ch04/deadlock/main_deadlock.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\t// Declare a unbuffered channel\n\tcounter := make(chan int)\n\t// This will create a deadlock\n\tcounter <- 10          // Send operation to a channel from main goroutine\n\tfmt.Println(<-counter) // Receive operation from the channel\n}\n"
  },
  {
    "path": "ch04/mathtable/main.go",
    "content": "// This sample program demonstrates how to create goroutines\npackage main\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"sync\"\n\t\"time\"\n)\n\n// WaitGroup is used to wait for the program to finish goroutines.\nvar wg sync.WaitGroup\n\nfunc main() {\n\n\t// Add a count of two, one for each goroutine.\n\twg.Add(2)\n\n\tfmt.Println(\"Start Goroutines\")\n\t// Launch functions as goroutines\n\tgo addTable()\n\tgo multiTable()\n\t// Wait for the goroutines to finish.\n\tfmt.Println(\"Waiting To Finish\")\n\twg.Wait()\n\tfmt.Println(\"\\nTerminating Program\")\n}\n\nfunc addTable() {\n\t// Schedule the call to WaitGroup's Done to tell goroutine is completed.\n\tdefer wg.Done()\n\tfor i := 1; i <= 10; i++ {\n\t\tsleep := rand.Int63n(1000)\n\t\ttime.Sleep(time.Duration(sleep) * time.Millisecond)\n\t\tfmt.Println(\"Addition Table for:\", i)\n\t\tfor j := 1; j <= 10; j++ {\n\t\t\t//res = i + j\n\t\t\tfmt.Printf(\"%d+%d=%d\\t\", i, j, i+j)\n\t\t}\n\t\tfmt.Println(\"\\n\")\n\t}\n}\nfunc multiTable() {\n\t// Schedule the call to WaitGroup's Done to tell goroutine is completed.\n\tdefer wg.Done()\n\tfor i := 1; i <= 10; i++ {\n\t\tsleep := rand.Int63n(1000)\n\t\ttime.Sleep(time.Duration(sleep) * time.Millisecond)\n\t\tfmt.Println(\"Multiplication Table for:\", i)\n\t\tfor j := 1; j <= 10; j++ {\n\t\t\t//res = i + j\n\t\t\tfmt.Printf(\"%d*%d=%d\\t\", i, j, i*j)\n\t\t}\n\t\tfmt.Println(\"\\n\")\n\t}\n}\n"
  },
  {
    "path": "ch04/pipeline/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"math/rand\"\n\t\"sync\"\n)\n\ntype fibvalue struct {\n\tinput, value int\n}\n\nvar wg sync.WaitGroup\n\nfunc randomCounter(out chan<- int) {\n\tdefer wg.Done()\n\tvar random int\n\tfor x := 0; x < 10; x++ {\n\t\trandom = rand.Intn(50)\n\t\tout <- random\n\t}\n\tclose(out)\n}\n\nfunc generateFibonacci(out chan<- fibvalue, in <-chan int) {\n\tdefer wg.Done()\n\tvar input float64\n\tfor v := range in {\n\t\tinput = float64(v)\n\t\t// Fibonacci using Binet's formula\n\t\tPhi := (1 + math.Sqrt(5)) / 2\n\t\tphi := (1 - math.Sqrt(5)) / 2\n\t\tresult := (math.Pow(Phi, input) - math.Pow(phi, input)) / math.Sqrt(5)\n\t\tout <- fibvalue{\n\t\t\tinput: v,\n\t\t\tvalue: int(result),\n\t\t}\n\t}\n\tclose(out)\n}\n\nfunc printFibonacci(in <-chan fibvalue) {\n\tdefer wg.Done()\n\tfor v := range in {\n\t\tfmt.Printf(\"Fibonacci value of %d is %d\\n\", v.input, v.value)\n\t}\n}\n\nfunc main() {\n\t// Add 3 into WaitGroup Counter\n\twg.Add(3)\n\t// Declare Channels\n\trandoms := make(chan int)\n\tfibs := make(chan fibvalue)\n\t// Launching 3 goroutines\n\tgo randomCounter(randoms)\n\tgo generateFibonacci(fibs, randoms)\n\tgo printFibonacci(fibs)\n\t// Wait for completing all goroutines\n\twg.Wait()\n}\n"
  },
  {
    "path": "ch04/pipeline/main1.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"math/rand\"\n\t\"sync\"\n)\n\ntype fibvalue struct {\n\tinput, value int\n}\n\nvar wg sync.WaitGroup\n\n// Generates random values\nfunc randomCounter(out chan int) {\n\tdefer wg.Done()\n\tvar random int\n\tfor x := 0; x < 10; x++ {\n\t\trandom = rand.Intn(50)\n\t\tout <- random\n\t}\n\tclose(out)\n}\n\n// Produces fibonacci values of inputs provided by randomCounter\nfunc generateFibonacci(out chan fibvalue, in chan int) {\n\tdefer wg.Done()\n\tvar input float64\n\tfor v := range in {\n\t\tinput = float64(v)\n\t\t// Fibonacci using Binet's formula\n\t\tPhi := (1 + math.Sqrt(5)) / 2\n\t\tphi := (1 - math.Sqrt(5)) / 2\n\t\tresult := (math.Pow(Phi, input) - math.Pow(phi, input)) / math.Sqrt(5)\n\t\tout <- fibvalue{\n\t\t\tinput: v,\n\t\t\tvalue: int(result),\n\t\t}\n\t}\n\tclose(out)\n}\n\n// Print fibonacci values generated by generateFibonacci\nfunc printFibonacci(in chan fibvalue) {\n\tdefer wg.Done()\n\tfor v := range in {\n\t\tfmt.Printf(\"Fibonacci value of %d is %d\\n\", v.input, v.value)\n\t}\n}\n\nfunc main() {\n\t// Add 3 into WaitGroup Counter\n\twg.Add(3)\n\t// Declare Channels\n\trandoms := make(chan int)\n\tfibs := make(chan fibvalue)\n\t// Launching 3 goroutines\n\tgo randomCounter(randoms)           // First stage of pipeline\n\tgo generateFibonacci(fibs, randoms) // Second stage of pipeline\n\tgo printFibonacci(fibs)             // Third stage of pipeline\n\t// Wait for completing all goroutines\n\twg.Wait()\n}\n"
  },
  {
    "path": "ch04/select/context.go",
    "content": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n)\n\nfunc generateValues(ctx context.Context, counter chan int) {\n\tn := 1\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn\n\t\tcase counter <- n:\n\t\t\tn++\n\t\t}\n\t}\n}\n\nfunc main() {\n\t// WithCancel returns a copy of parent with a new Done channel. The returned\n\t// context's Done channel is closed when the returned cancel function is called\n\t// or when the parent context's Done channel is closed, whichever happens first.\n\t//\n\t// Canceling this context releases resources associated with it, so code should\n\t// call cancel as soon as the operations running in this Context complete.\n\tctx, cancel := context.WithCancel(context.Background())\n\t// ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)\n\tcounter := make(chan int)\n\tdefer cancel()\n\tgo generateValues(ctx, counter)\n\tfor n := range counter {\n\t\tfmt.Println(n)\n\t\tif n == 10 {\n\t\t\tcancel()\n\t\t\tbreak\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "ch04/select/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"math/rand\"\n\t\"sync\"\n)\n\ntype (\n\tfibvalue struct {\n\t\tinput, value int\n\t}\n\tsquarevalue struct {\n\t\tinput, value int\n\t}\n)\n\nfunc generateSquare(sqrs chan<- squarevalue) {\n\tdefer wg.Done()\n\tfor i := 1; i <= 10; i++ {\n\t\tnum := rand.Intn(50)\n\t\tsqrs <- squarevalue{\n\t\t\tinput: num,\n\t\t\tvalue: num * num,\n\t\t}\n\t}\n}\nfunc generateFibonacci(fibs chan<- fibvalue) {\n\tdefer wg.Done()\n\tfor i := 1; i <= 10; i++ {\n\t\tnum := float64(rand.Intn(50))\n\t\t// Fibonacci using Binet's formula\n\t\tPhi := (1 + math.Sqrt(5)) / 2\n\t\tphi := (1 - math.Sqrt(5)) / 2\n\t\tresult := (math.Pow(Phi, num) - math.Pow(phi, num)) / math.Sqrt(5)\n\t\tfibs <- fibvalue{\n\t\t\tinput: int(num),\n\t\t\tvalue: int(result),\n\t\t}\n\t}\n}\nfunc printValues(fibs <-chan fibvalue, sqrs <-chan squarevalue) {\n\tdefer wg.Done()\n\tfor i := 1; i <= 20; i++ {\n\t\tselect {\n\t\tcase fib := <-fibs:\n\t\t\tfmt.Printf(\"Fibonacci value of %d is %d\\n\", fib.input, fib.value)\n\t\tcase sqr := <-sqrs:\n\t\t\tfmt.Printf(\"Square value of %d is %d\\n\", sqr.input, sqr.value)\n\t\t}\n\t}\n}\n\n// wg is used to wait for the program to finish.\nvar wg sync.WaitGroup\n\nfunc main() {\n\twg.Add(3)\n\t// Create Channels\n\tfibs := make(chan fibvalue)\n\tsqrs := make(chan squarevalue)\n\t// Launching 3 goroutines\n\tgo generateFibonacci(fibs)\n\tgo generateSquare(sqrs)\n\tgo printValues(fibs, sqrs)\n\t// Wait for completing all goroutines\n\twg.Wait()\n}\n"
  },
  {
    "path": "ch04/unbuffercounter/main.go",
    "content": "// Example program with unbuffered channel\npackage main\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n)\n\n// wg is used to wait for the program to finish.\nvar wg sync.WaitGroup\n\nfunc main() {\n\n\tcount := make(chan int)\n\t// Add a count of two, one for each goroutine.\n\twg.Add(2)\n\n\tfmt.Println(\"Start Goroutines\")\n\t// Launch a goroutine with label \"Goroutine-1\"\n\tgo printCounts(\"Goroutine-1\", count)\n\t// Launch a goroutine with label \"Goroutine-2\"\n\tgo printCounts(\"Goroutine-2\", count)\n\tfmt.Println(\"Communication of channel begins\")\n\tcount <- 1\n\t// Wait for the goroutines to finish.\n\tfmt.Println(\"Waiting To Finish\")\n\twg.Wait()\n\tfmt.Println(\"\\nTerminating the Program\")\n}\n\nfunc printCounts(label string, count chan int) {\n\t// Schedule the call to WaitGroup's Done to tell goroutine is completed.\n\tdefer wg.Done()\n\tfor val := range count {\n\t\tfmt.Printf(\"Count: %d received from %s \\n\", val, label)\n\t\tif val == 10 {\n\t\t\tfmt.Printf(\"Channel Closed from %s \\n\", label)\n\t\t\t// Close the channel\n\t\t\tclose(count)\n\t\t\treturn\n\t\t}\n\t\tval++\n\t\t// Send count back to the other goroutine.\n\t\tcount <- val\n\t}\n}\n"
  },
  {
    "path": "ch04/unbuffercounter/main1.go",
    "content": "// Example program with unbuffered channel\npackage main\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n)\n\n// wg is used to wait for the program to finish.\nvar wg sync.WaitGroup\n\nfunc main() {\n\n\tcount := make(chan int)\n\t// Add a count of two, one for each goroutine.\n\twg.Add(2)\n\n\tfmt.Println(\"Start Goroutines\")\n\t// Launch a goroutine with label \"Goroutine-1\"\n\tgo printCounts(\"Goroutine-1\", count)\n\t// Launch a goroutine with label \"Goroutine-2\"\n\tgo printCounts(\"Goroutine-2\", count)\n\tfmt.Println(\"Communication of channel begins\")\n\tcount <- 1\n\t// Wait for the goroutines to finish.\n\tfmt.Println(\"Waiting To Finish\")\n\twg.Wait()\n\tfmt.Println(\"\\nTerminating the Program\")\n}\n\nfunc printCounts(label string, count chan int) {\n\t// Schedule the call to WaitGroup's Done to tell goroutine is completed.\n\tdefer wg.Done()\n\tfor {\n\t\t// Receives message from Channel\n\t\tval, ok := <-count\n\t\tif !ok {\n\t\t\tfmt.Println(\"Channel was closed\")\n\t\t\treturn\n\t\t}\n\t\tfmt.Printf(\"Count: %d received from %s \\n\", val, label)\n\t\tif val == 10 {\n\t\t\tfmt.Printf(\"Channel Closed from %s \\n\", label)\n\t\t\t// Close the channel\n\t\t\tclose(count)\n\t\t\treturn\n\t\t}\n\t\tval++\n\t\t// Send count back to the other goroutine.\n\t\tcount <- val\n\t}\n}\n"
  },
  {
    "path": "ch04/worker/main.go",
    "content": "// This sample program demonstrates how to use a buffered\n// channel to work on multiple tasks with a predefined number\n// of goroutines.\npackage main\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"sync\"\n\t\"time\"\n)\n\ntype Task struct {\n\tId        int\n\tJobId     int\n\tStatus    string\n\tCreatedOn time.Time\n}\n\nfunc (t *Task) Run() {\n\n\tsleep := rand.Int63n(1000)\n\t// Delaying the execution for the sake of example\n\ttime.Sleep(time.Duration(sleep) * time.Millisecond)\n\tt.Status = \"Completed\"\n}\n\n// wg is used to wait for the program to finish.\nvar wg sync.WaitGroup\n\nconst noOfWorkers = 3\n\n// main is the entry point for all Go programs.\nfunc main() {\n\t// Create a buffered channel to manage the task queue.\n\ttaskQueue := make(chan *Task, 10)\n\n\t// Launch goroutines to handle the work.\n\t// The worker process is distributing with the value of noOfWorkers.\n\twg.Add(noOfWorkers)\n\tfor gr := 1; gr <= noOfWorkers; gr++ {\n\t\tgo worker(taskQueue, gr)\n\t}\n\n\t// Add Tasks into Buffered channel.\n\tfor i := 1; i <= 10; i++ {\n\t\ttaskQueue <- &Task{\n\t\t\tId:        i,\n\t\t\tJobId:     100 + i,\n\t\t\tCreatedOn: time.Now(),\n\t\t}\n\t}\n\n\t// Close the channel\n\tclose(taskQueue)\n\n\t// Wait for all the work to get done.\n\twg.Wait()\n}\n\n// worker is launched as a goroutine to process Tasks from\n// the buffered channel.\nfunc worker(taskQueue <-chan *Task, workerId int) {\n\t// Schedule the call to Done method of WaitGroup.\n\tdefer wg.Done()\n\tfor v := range taskQueue {\n\t\tfmt.Printf(\"Worker%d: received request for Task:%d - Job:%d\\n\", workerId, v.Id, v.JobId)\n\t\tv.Run()\n\t\t// Display we finished the work.\n\t\tfmt.Printf(\"Worker%d: Status:%s for Task:%d - Job:%d\\n\", workerId, v.Status, v.Id, v.JobId)\n\t}\n}\n"
  },
  {
    "path": "ch05/archivetar/main.go",
    "content": "package main\n\nimport (\n\t\"archive/tar\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n)\n\n// addToArchive writes a given file into a .tar file\n// Returns nill if the operation is succeeded\nfunc addToArchive(filename string, tw *tar.Writer) error {\n\t// Open the file to archive into tar file.\n\tfile, err := os.Open(filename)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer file.Close()\n\t// Get the FileInfo struct that describe the file.\n\tfileinfo, err := file.Stat()\n\t// Create a pointer to tar.Header struct\n\thdr := &tar.Header{\n\t\tModTime: fileinfo.ModTime(),            // modified time\n\t\tName:    filename,                      // name of header\n\t\tSize:    fileinfo.Size(),               // length in bytes\n\t\tMode:    int64(fileinfo.Mode().Perm()), // permission and mode bits\n\t}\n\t// WriteHeader writes tar.Header and prepares to accept the file's contents.\n\tif err := tw.WriteHeader(hdr); err != nil {\n\t\treturn err\n\t}\n\t// Write the file contents to the tar file.\n\tcopied, err := io.Copy(tw, file)\n\tif err != nil {\n\t\treturn err\n\t}\n\t// Check the size of copied file with the source file.\n\tif copied < fileinfo.Size() {\n\t\treturn fmt.Errorf(\"Size of the copied file doesn't match with source file %s: %s\", filename, err)\n\t}\n\treturn nil\n}\n\n// archiveFiles archives a group of given files into a tar file.\nfunc archiveFiles(files []string, archive string) error {\n\t// Flags for open the tar file.\n\tflags := os.O_WRONLY | os.O_CREATE | os.O_TRUNC\n\t// Open the tar file\n\tfile, err := os.OpenFile(archive, flags, 0644)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer file.Close()\n\t// Create a new Writer writing to given file object.\n\t// Writer provides sequential writing of a tar archive in POSIX.1 format.\n\ttw := tar.NewWriter(file)\n\tdefer tw.Close()\n\t// Iterate through the files to write each file into the tar file.\n\tfor _, filename := range files {\n\t\t// Write the file into tar file.\n\t\tif err := addToArchive(filename, tw); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// readArchive reads the file contents from tar file.\nfunc readArchive(archive string) error {\n\t// Open the tar archive file.\n\tfile, err := os.Open(archive)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer file.Close()\n\t// Create the tar.Reader to read the tar archive.\n\t// A Reader provides sequential access to the contents of a tar archive.\n\ttr := tar.NewReader(file)\n\t// Iterate through the files in the tar archive.\n\tfor {\n\t\thdr, err := tr.Next()\n\t\tif err == io.EOF {\n\t\t\t// End of tar archive\n\t\t\tfmt.Println(\"end\")\n\t\t\tbreak\n\t\t}\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tsize := hdr.Size\n\t\tcontents := make([]byte, size)\n\t\tread, err := io.ReadFull(tr, contents)\n\t\t// Check the size of file contents\n\t\tif int64(read) != size {\n\t\t\treturn fmt.Errorf(\"Size of the opened file doesn't match with the file %s\", hdr.Name)\n\t\t}\n\t\t// hdr.Name returns the file name.\n\t\tfmt.Printf(\"Contents of the file %s:\\n\", hdr.Name)\n\t\t// Writing the file contents into Stdout.\n\t\tfmt.Fprintf(os.Stdout, \"\\n%s\", contents)\n\t}\n\treturn nil\n}\n\nfunc main() {\n\t// Name of the tar file\n\tarchive := \"source.tar\"\n\t// Files to be archived in tar format\n\tfiles := []string{\"main.go\", \"readme.txt\"}\n\t// Archive files into tar format\n\terr := archiveFiles(files, archive)\n\tif err != nil {\n\t\tlog.Fatalf(\"Error while writing to tar file:%s\", err)\n\t}\n\t// Archiving is sucsess.\n\tfmt.Println(\"The tar file source.tar has been created\")\n\t// Read the file contents of tar file\n\terr = readArchive(archive)\n\tif err != nil {\n\t\tlog.Fatalf(\"Error while reading the tar file:%s\", err)\n\t}\n}\n"
  },
  {
    "path": "ch05/archivezip/main.go",
    "content": "package main\n\nimport (\n\t\"archive/zip\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n)\n\n// addToArchive writes a given file into a zip file.\nfunc addToArchive(filename string, zw *zip.Writer) error {\n\t// Open the given file to archive into a zip file.\n\tfile, err := os.Open(filename)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer file.Close()\n\t// Create adds a file to the zip file using the given name/\n\t// Create returns a io.Writer to which the file contents should be written.\n\twr, err := zw.Create(filename)\n\tif err != nil {\n\t\treturn err\n\t}\n\t// Write the file contents to the zip file.\n\tif _, err := io.Copy(wr, file); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// archiveFiles archives a group of given files into a zip file.\nfunc archiveFiles(files []string, archive string) error {\n\tflags := os.O_WRONLY | os.O_CREATE | os.O_TRUNC\n\t// Open the tar file\n\tfile, err := os.OpenFile(archive, flags, 0644)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer file.Close()\n\t// Create zip.Writer that implements a zip file writer.\n\tzw := zip.NewWriter(file)\n\tdefer zw.Close()\n\t// Iterate through the files to write each file into the zip file.\n\tfor _, filename := range files {\n\t\t// Write the file into tar file.\n\t\tif err := addToArchive(filename, zw); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// readArchive reads the file contents from tar file.\nfunc readArchive(archive string) error {\n\t// Open the zip file specified by name and return a ReadCloser.\n\trc, err := zip.OpenReader(archive)\t\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer rc.Close()\n\t// Iterate through the files in the zip file to read the file contents.\n\tfor _, file := range rc.File {\n\t\tfrc, err := file.Open()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdefer frc.Close()\n\t\tfmt.Fprintf(os.Stdout, \"Contents of the file %s:\\n\", file.Name)\n\t\t// Write the contents into Stdout\n\t\tcopied, err := io.Copy(os.Stdout, frc)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\t// Check the size of the file.\n\t\tif uint64(copied) != file.UncompressedSize64 {\n\t\t\treturn fmt.Errorf(\"Length of the file contents doesn't match with the file %s\", file.Name)\n\t\t}\n\t\tfmt.Println()\n\t}\n\treturn nil\n}\n\nfunc main() {\n\t// Name of the zip file\n\tarchive := \"source.zip\"\n\t// Files to be archived in zip format.\n\tfiles := []string{\"main.go\", \"readme.txt\"}\n\t// Archive files into zip format.\n\terr := archiveFiles(files, archive)\n\tif err != nil {\n\t\tlog.Fatalf(\"Error while writing to zip file:%s\\n\", err)\n\t}\n\t// Read the file contents of tar file.\n\terr = readArchive(archive)\n\tif err != nil {\n\t\tlog.Fatalf(\"Error while reading the zip file:%s\\n\", err)\n\n\t}\n}\n"
  },
  {
    "path": "ch05/cmdflags/main.go",
    "content": "package main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n)\n\nfunc main() {\n\n\tfileName := flag.String(\"filename\", \"logfile\", \"File name for the log file\")\n\tlogLevel := flag.Int(\"loglevel\", 0, \"An integer value for Level (0-4)\")\n\tisEnable := flag.Bool(\"enable\", false, \"A boolean value for enabling log options\")\n\tvar num int\n\t// Bind the flag to a variable.\n\tflag.IntVar(&num, \"num\", 25, \"An integer value\")\n\n\t// Parse parses flag definitions from the argument list.\n\tflag.Parse()\n\t// Get the values from pointers\n\tfmt.Println(\"filename:\", *fileName)\n\tfmt.Println(\"loglevel:\", *logLevel)\n\tfmt.Println(\"enable:\", *isEnable)\n\t// Get the value from a variable\n\tfmt.Println(\"num:\", num)\n\t// Args returns the non-flag command-line arguments.\n\targs := flag.Args()\n\tif len(args) > 0 {\n\t\tfmt.Println(\"The non-flag command-line arguments are:\")\n\t\t// Print the arguments\n\t\tfor _, v := range args {\n\t\t\tfmt.Println(v)\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "ch05/flag/main.go",
    "content": "package main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n)\n\nfunc main() {\n\n\tstrPtr := flag.String(\"name\", \"Shiju\", \"a string\")\n\tnumbPtr := flag.Int(\"num\", 25, \"an int\")\n\tboolPtr := flag.Bool(\"enable\", false, \"a bool\")\n\tvar num int\n\tflag.IntVar(&num, \"num\", 30, \"an int\")\t\n\t// Parse parses flag definitions from the argument list.\n\tflag.Parse()\n\t// Get the values for pointers\n\tfmt.Println(\"name:\", *strPtr)\n\tfmt.Println(\"num:\", *numbPtr)\n\tfmt.Println(\"enable:\", *boolPtr)\n\t// Get the value from a variable\n\tfmt.Println(\"num:\", num)\n\t// Args returns the non-flag command-line arguments.\n\tfmt.Println(\"arguments:\", flag.Args())\n}\n"
  },
  {
    "path": "ch05/json/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n)\n\n// Employee struct\ntype Employee struct {\n\tID                            int\n\tFirstName, LastName, JobTitle string\n}\n\nfunc main() {\n\temp := Employee{\n\t\tID:        100,\n\t\tFirstName: \"Shiju\",\n\t\tLastName:  \"Varghese\",\n\t\tJobTitle:  \"Architect\",\n\t}\n\t// Encoding to JSON\n\tdata, err := json.Marshal(emp)\n\tif err != nil {\n\t\tfmt.Println(err.Error())\n\t\treturn\n\t}\n\tjsonStr := string(data)\n\tfmt.Println(\"The JSON data is:\")\n\tfmt.Println(jsonStr)\n\n\tb := []byte(`{\"ID\":101,\"FirstName\":\"Irene\",\"LastName\":\"Rose\",\"JobTitle\":\"Developer\"}`)\n\tvar emp1 Employee\n\t// Decoding JSON data to a value of struct type\n\terr = json.Unmarshal(b, &emp1)\n\tif err != nil {\n\t\tfmt.Println(err.Error())\n\t\treturn\n\t}\n\tfmt.Println(\"The Employee value is:\")\n\tfmt.Printf(\"ID:%d, Name:%s %s, JobTitle:%s\", emp1.ID, emp1.FirstName, emp1.LastName, emp1.JobTitle)\n}\n"
  },
  {
    "path": "ch05/jsontag/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n)\n\n// Employee struct with struct tags\ntype Employee struct {\n\tID        int    `json:\"id,omitempty\"`\n\tFirstName string `json:\"firstname\"`\n\tLastName  string `json:\"lastname\"`\n\tJobTitle  string `json:\"job\"`\n}\n\nfunc main() {\n\temp := Employee{\n\t\tFirstName: \"Shiju\",\n\t\tLastName:  \"Varghese\",\n\t\tJobTitle:  \"Architect\",\n\t}\n\t// Encoding to JSON\n\tdata, err := json.Marshal(emp)\n\tif err != nil {\n\t\tfmt.Println(err.Error())\n\t\treturn\n\t}\n\tjsonStr := string(data)\n\tfmt.Println(\"The JSON data is:\")\n\tfmt.Println(jsonStr)\n\n\tb := []byte(`{\"id\":101,\"firstname\":\"Irene\",\"lastname\":\"Rose\",\"job\":\"Developer\"}`)\n\tvar emp1 Employee\n\t// Decoding JSON to a struct type\n\terr = json.Unmarshal(b, &emp1)\n\tif err != nil {\n\t\tfmt.Println(err.Error())\n\t\treturn\n\t}\n\tfmt.Println(\"The Employee value is:\")\n\tfmt.Printf(\"ID:%d, Name:%s %s, JobTitle:%s\", emp1.ID, emp1.FirstName, emp1.LastName, emp1.JobTitle)\n}\n"
  },
  {
    "path": "ch05/log/logger.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"os\"\n)\n\nconst (\n\t// UNSPECIFIED logs nothing\n\tUNSPECIFIED Level = iota // 0 :\n\t// TRACE logs everything\n\tTRACE // 1\n\t// INFO logs Info, Warnings and Errors\n\tINFO // 2\n\t// WARNING logs Warning and Errors\n\tWARNING // 3\n\t// ERROR just logs Errors\n\tERROR // 4\n)\n\n// Level holds the log level.\ntype Level int\n\n// Package level variables, which are pointer to log.Logger.\nvar (\n\tTrace   *log.Logger\n\tInfo    *log.Logger\n\tWarning *log.Logger\n\tError   *log.Logger\n)\n\n// initLog initializes log.Logger objects\nfunc initLog(\n\ttraceHandle io.Writer,\n\tinfoHandle io.Writer,\n\twarningHandle io.Writer,\n\terrorHandle io.Writer,\n\tisFlag bool) {\n\n\t// Flags for defines the logging properties, to log.New\n\tflag := 0\n\tif isFlag {\n\t\tflag = log.Ldate | log.Ltime | log.Lshortfile\n\t}\n\n\t// Create log.Logger objects.\n\tTrace = log.New(traceHandle, \"TRACE: \", flag)\n\tInfo = log.New(infoHandle, \"INFO: \", flag)\n\tWarning = log.New(warningHandle, \"WARNING: \", flag)\n\tError = log.New(errorHandle, \"ERROR: \", flag)\n\n}\n\n// SetLogLevel sets the logging level preference\nfunc SetLogLevel(level Level) {\n\n\t// Creates os.*File, which has implemented io.Writer intreface\n\tf, err := os.OpenFile(\"logs.txt\", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)\n\tif err != nil {\n\t\tlog.Fatalf(\"Error opening log file: %s\", err.Error())\n\t}\n\n\t// Calls function initLog by specifying log level preference.\n\tswitch level {\n\tcase TRACE:\n\t\tinitLog(f, f, f, f, true)\n\t\treturn\n\n\tcase INFO:\n\t\tinitLog(ioutil.Discard, f, f, f, true)\n\t\treturn\n\n\tcase WARNING:\n\t\tinitLog(ioutil.Discard, ioutil.Discard, f, f, true)\n\t\treturn\n\tcase ERROR:\n\t\tinitLog(ioutil.Discard, ioutil.Discard, ioutil.Discard, f, true)\n\t\treturn\n\n\tdefault:\n\t\tinitLog(ioutil.Discard, ioutil.Discard, ioutil.Discard, ioutil.Discard, false)\n\t\tf.Close()\n\t\treturn\n\n\t}\n}\n"
  },
  {
    "path": "ch05/log/main.go",
    "content": "package main\n\nimport (\n\t\"errors\"\n\t\"flag\"\n)\n\nfunc main() {\n\t// Parse log level from command line\n\tlogLevel := flag.Int(\"loglevel\", 0, \"an integer value (0-4)\")\n\tflag.Parse()\n\t// Calling the SetLogLevel with the command-line argument\n\tSetLogLevel(Level(*logLevel))\n\tTrace.Println(\"Main started\")\n\tloop()\n\terr := errors.New(\"Sample Error\")\n\tError.Println(err.Error())\n\tTrace.Println(\"Main completed\")\n}\n\n// A simple function for the logging demo\nfunc loop() {\n\tTrace.Println(\"Loop started\")\n\tfor i := 0; i < 10; i++ {\n\t\tInfo.Println(\"Counter value is:\", i)\n\t}\n\tWarning.Println(\"The counter variable is not being used\")\n\tTrace.Println(\"Loop completed\")\n}\n"
  },
  {
    "path": "ch05/simplelog/main.go",
    "content": "package main\n\nimport (\n\t\"errors\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"os\"\n)\n\n// Package level variables, which are pointer to log.Logger.\nvar (\n\tTrace   *log.Logger\n\tInfo    *log.Logger\n\tWarning *log.Logger\n\tError   *log.Logger\n)\n\n// initLog initializes log.Logger objects\nfunc initLog(\n\ttraceHandle io.Writer,\n\tinfoHandle io.Writer,\n\twarningHandle io.Writer,\n\terrorHandle io.Writer) {\n\n\t// Flags for defines the logging properties, to log.New\n\tflag := log.Ldate | log.Ltime | log.Lshortfile\n\n\t// Create log.Logger objects\n\tTrace = log.New(traceHandle, \"TRACE: \", flag)\n\tInfo = log.New(infoHandle, \"INFO: \", flag)\n\tWarning = log.New(warningHandle, \"WARNING: \", flag)\n\tError = log.New(errorHandle, \"ERROR: \", flag)\n\n}\n\nfunc main() {\n\tinitLog(ioutil.Discard, os.Stdout, os.Stdout, os.Stderr)\n\tTrace.Println(\"Main started\")\n\tloop()\n\terr := errors.New(\"Sample Error\")\n\tError.Println(err.Error())\n\tTrace.Println(\"Main completed\")\n}\nfunc loop() {\n\tTrace.Println(\"Loop started\")\n\tfor i := 0; i < 10; i++ {\n\t\tInfo.Println(\"Counter value is:\", i)\n\t}\n\tWarning.Println(\"The counter variable is not being used\")\n\tTrace.Println(\"Loop completed\")\n}\n"
  },
  {
    "path": "ch06/influx/main.go",
    "content": "// Example demo for working with InfluxDB\npackage main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"log\"\n\t\"math/rand\"\n\t\"time\"\n\n\tclient \"github.com/influxdata/influxdb/client/v2\"\n)\n\nconst (\n\t// DB provides the database name of the InfluxDB\n\tDB       = \"metricsdb\"\n\tusername = \"opsadmin\"\n\tpassword = \"pass123\"\n)\n\nfunc main() {\n\t// Create client\n\tc := influxDBClient()\n\t// Write operations\n\t// Create metrics data for measurement \"cpu\"\n\tcreateMetrics(c)\n\t// Read operations\n\t// Read with limit of 10\n\treadWithLimit(c, 10)\n\t// Read mean value of \"cpu_usage\" for a region\n\tmeanCPUUsage(c, \"us-west\")\n\t// Read count of records for a region\n\tcountRegion(c, \"us-west\")\n\n}\n\n// influxDBClient returns InfluxDB Client\nfunc influxDBClient() client.Client {\n\tc, err := client.NewHTTPClient(client.HTTPConfig{\n\t\tAddr:     \"http://localhost:8086\",\n\t\tUsername: username,\n\t\tPassword: password,\n\t})\n\tif err != nil {\n\t\tlog.Fatalln(\"Error: \", err)\n\t}\n\treturn c\n}\n\n// createMetrics write batch points to create the metrics data\nfunc createMetrics(clnt client.Client) {\n\tbatchCount := 100\n\trand.Seed(42)\n\n\t// Create BatchPoints by giving config for InfluxDB\n\tbp, _ := client.NewBatchPoints(client.BatchPointsConfig{\n\t\tDatabase:  DB,\n\t\tPrecision: \"s\",\n\t})\n\t// Batch update to adds Points\n\tfor i := 0; i < batchCount; i++ {\n\t\tregions := []string{\"us-west\", \"us-central\", \"us-north\", \"us-east\"}\n\t\t// tagset – “host” and “region”\n\t\ttags := map[string]string{\n\t\t\t\"host\":   fmt.Sprintf(\"192.168.%d.%d\", rand.Intn(100), rand.Intn(100)),\n\t\t\t\"region\": regions[rand.Intn(len(regions))],\n\t\t}\n\n\t\tvalue := rand.Float64() * 100.0\n\t\t// field - \"cpu_usage\"\n\t\tfields := map[string]interface{}{\n\t\t\t\"cpu_usage\": value,\n\t\t}\n\n\t\tpt, err := client.NewPoint(\"cpu\", tags, fields, time.Now())\n\n\t\tif err != nil {\n\t\t\tlog.Fatalln(\"Error: \", err)\n\t\t}\n\t\t// Add a Point\n\t\tbp.AddPoint(pt)\n\n\t}\n\t// Writes the batch update to add points to measurement \"cpu\"\n\terr := clnt.Write(bp)\n\tif err != nil {\n\t\tlog.Fatalln(\"Error: \", err)\n\t}\n}\n\n// queryDB query the database\nfunc queryDB(clnt client.Client, command string) (res []client.Result, err error) {\n\t// Create the query\n\tq := client.Query{\n\t\tCommand:  command,\n\t\tDatabase: DB,\n\t}\n\t// Query the Database\n\tif response, err := clnt.Query(q); err == nil {\n\t\tif response.Error() != nil {\n\t\t\treturn res, response.Error()\n\t\t}\n\t\tres = response.Results\n\t} else {\n\t\treturn res, err\n\t}\n\treturn res, nil\n}\n\n// readWithLimit reads records with a given limit\nfunc readWithLimit(clnt client.Client, limit int) {\n\tq := fmt.Sprintf(\"SELECT * FROM %s LIMIT %d\", \"cpu\", limit)\n\tres, err := queryDB(clnt, q)\n\tif err != nil {\n\t\tlog.Fatalln(\"Error: \", err)\n\t}\n\n\tfor i, row := range res[0].Series[0].Values {\n\t\tt, err := time.Parse(time.RFC3339, row[0].(string))\n\t\tif err != nil {\n\t\t\tlog.Fatalln(\"Error: \", err)\n\t\t}\n\t\tval, err := row[1].(json.Number).Float64()\n\t\tfmt.Printf(\"[%2d] %s: %f\\n\", i, t.Format(time.Stamp), val)\n\t}\n}\n\n// meanCPUUsage reads the mean value of cpu_usage\nfunc meanCPUUsage(clnt client.Client, region string) {\n\tq := fmt.Sprintf(\"select mean(%s) from %s where region = '%s'\", \"cpu_usage\", \"cpu\", region)\n\tres, err := queryDB(clnt, q)\n\tif err != nil {\n\t\tlog.Fatalln(\"Error: \", err)\n\t}\n\tvalue, err := res[0].Series[0].Values[0][1].(json.Number).Float64()\n\tif err != nil {\n\t\tlog.Fatalln(\"Error: \", err)\n\t}\n\n\tfmt.Printf(\"Mean value of cpu_usage for region '%s':%f\\n\", region, value)\n}\n\n// countRegion reads the count of records for a given region\nfunc countRegion(clnt client.Client, region string) {\n\tq := fmt.Sprintf(\"SELECT count(%s) FROM %s where region = '%s'\", \"cpu_usage\", \"cpu\", region)\n\tres, err := queryDB(clnt, q)\n\tif err != nil {\n\t\tlog.Fatalln(\"Error: \", err)\n\t}\n\tcount := res[0].Series[0].Values[0][1]\n\tfmt.Printf(\"Found a total of %v records for region '%s'\\n\", count, region)\n}\n"
  },
  {
    "path": "ch06/mongo/bookmark_store.go",
    "content": "package main\n\nimport (\n\t\"time\"\n\n\t\"gopkg.in/mgo.v2\"\n\t\"gopkg.in/mgo.v2/bson\"\n)\n\n// Bookmark type reperesents the metadata of a bookmark.\ntype Bookmark struct {\n\tID                          bson.ObjectId `bson:\"_id,omitempty\"`\n\tName, Description, Location string\n\tPriority                    int // Priority (1 -5)\n\tCreatedOn                   time.Time\n\tTags                        []string\n}\n\n// BookmarkStore provides CRUD operations against the collection \"bookmarks\".\ntype BookmarkStore struct {\n\tC *mgo.Collection\n}\n\n// Create inserts the value of struct Bookmark into collection.\nfunc (store BookmarkStore) Create(b *Bookmark) error {\n\t// Assign a new bson.ObjectId\n\tb.ID = bson.NewObjectId()\n\terr := store.C.Insert(b)\n\treturn err\n}\n\n//Update modifies an existing value of a collection.\nfunc (store BookmarkStore) Update(b Bookmark) error {\n\t// partial update on MogoDB\n\terr := store.C.Update(bson.M{\"_id\": b.ID},\n\t\tbson.M{\"$set\": bson.M{\n\t\t\t\"name\":        b.Name,\n\t\t\t\"description\": b.Description,\n\t\t\t\"location\":    b.Location,\n\t\t\t\"priority\":    b.Priority,\n\t\t\t\"tags\":        b.Tags,\n\t\t}})\n\treturn err\n}\n\n// Delete removes an existing value from the collection.\nfunc (store BookmarkStore) Delete(id string) error {\n\terr := store.C.Remove(bson.M{\"_id\": bson.ObjectIdHex(id)})\n\treturn err\n}\n\n// GetAll returns all documents from the collection.\nfunc (store BookmarkStore) GetAll() []Bookmark {\n\tvar b []Bookmark\n\titer := store.C.Find(nil).Sort(\"priority\", \"-createdon\").Iter()\n\tresult := Bookmark{}\n\tfor iter.Next(&result) {\n\t\tb = append(b, result)\n\t}\n\treturn b\n}\n\n// GetByID returns single document from the collection.\nfunc (store BookmarkStore) GetByID(id string) (Bookmark, error) {\n\tvar b Bookmark\n\terr := store.C.FindId(bson.ObjectIdHex(id)).One(&b)\n\treturn b, err\n}\n\n// GetByTag returns all documents from the collection filtering by tags.\nfunc (store BookmarkStore) GetByTag(tags []string) []Bookmark {\n\tvar b []Bookmark\n\titer := store.C.Find(bson.M{\"tags\": bson.M{\"$in\": tags}}).Sort(\"priority\", \"-createdon\").Iter()\n\tresult := Bookmark{}\n\tfor iter.Next(&result) {\n\t\tb = append(b, result)\n\t}\n\treturn b\n}\n"
  },
  {
    "path": "ch06/mongo/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"time\"\n\n\t\"gopkg.in/mgo.v2\"\n)\n\nvar store BookmarkStore\nvar id string\n\n// init will invoke before the function main.\nfunc init() {\n\tsession, err := mgo.DialWithInfo(&mgo.DialInfo{\n\t\tAddrs:   []string{\"127.0.0.1\"},\n\t\tTimeout: 60 * time.Second,\n\t})\n\tif err != nil {\n\t\tlog.Fatalf(\"[MongoDB Session]: %s\\n\", err)\n\t}\n\tcollection := session.DB(\"bookmarkdb\").C(\"bookmarks\")\n\tcollection.RemoveAll(nil)\n\tstore = BookmarkStore{\n\t\tC: collection,\n\t}\n}\n\n// Create and update documents.\nfunc createUpdate() {\n\tbookmark := Bookmark{\n\t\tName:        \"mgo\",\n\t\tDescription: \"Go driver for MongoDB\",\n\t\tLocation:    \"https://github.com/go-mgo/mgo\",\n\t\tPriority:    2,\n\t\tCreatedOn:   time.Now(),\n\t\tTags:        []string{\"go\", \"nosql\", \"mongodb\"},\n\t}\n\t// Insert a new document.\n\tif err := store.Create(&bookmark); err != nil {\n\t\tlog.Fatalf(\"[Create]: %s\\n\", err)\n\t}\n\tid = bookmark.ID.Hex()\n\tfmt.Printf(\"New bookmark has been inserted with ID: %s\\n\", id)\n\t// Update an existing document.\n\tbookmark.Priority = 1\n\tif err := store.Update(bookmark); err != nil {\n\t\tlog.Fatalf(\"[Update]: %s\\n\", err)\n\t}\n\tfmt.Println(\"The value after update:\")\n\t// Retrieve the updated document.\n\tgetByID(id)\n\n\tbookmark = Bookmark{\n\t\tName:        \"gorethink\",\n\t\tDescription: \"Go driver for RethinkDB\",\n\t\tLocation:    \"https://github.com/dancannon/gorethink\",\n\t\tPriority:    3,\n\t\tCreatedOn:   time.Now(),\n\t\tTags:        []string{\"go\", \"nosql\", \"rethinkdb\"},\n\t}\n\t// Insert a new document.\n\tif err := store.Create(&bookmark); err != nil {\n\t\tlog.Fatalf(\"[Create]: %s\\n\", err)\n\t}\n\tid = bookmark.ID.Hex()\n\tfmt.Printf(\"New bookmark has been inserted with ID: %s\\n\", id)\n\n}\n\n// Get a document by given id.\nfunc getByID(id string) {\n\tbookmark, err := store.GetByID(id)\n\tif err != nil {\n\t\tlog.Fatalf(\"[GetByID]: %s\\n\", err)\n\t}\n\tfmt.Printf(\"Name:%s, Description:%s, Priority:%d\\n\",\n\t\tbookmark.Name, bookmark.Description, bookmark.Priority)\n}\n\n// Get all documents from the collection.\nfunc getAll() {\n\t// Layout for formatting dates.\n\tlayout := \"2006-01-02 15:04:05\"\n\t// Retrieve all documents.\n\tbookmarks := store.GetAll()\n\tfmt.Println(\"Read all documents\")\n\tfor _, v := range bookmarks {\n\t\tfmt.Printf(\"Name:%s, Description:%s, Priority:%d, CreatedOn:%s\\n\",\n\t\t\tv.Name, v.Description, v.Priority, v.CreatedOn.Format(layout))\n\t}\n}\n\n// Get documents by tags.\nfunc getByTags() {\n\tlayout := \"2006-01-02 15:04:05\"\n\tfmt.Println(\"Query with Tags - 'go, nosql'\")\n\tbookmarks := store.GetByTag([]string{\"go\", \"nosql\"})\n\tfor _, v := range bookmarks {\n\t\tfmt.Printf(\"Name:%s, Description:%s, Priority:%d, CreatedOn:%s\\n\",\n\t\t\tv.Name, v.Description, v.Priority, v.CreatedOn.Format(layout))\n\t}\n\tfmt.Println(\"Query with Tags - 'mongodb'\")\n\tbookmarks = store.GetByTag([]string{\"mongodb\"})\n\tfor _, v := range bookmarks {\n\t\tfmt.Printf(\"Name:%s, Description:%s, Priority:%d, CreatedOn:%s\\n\",\n\t\t\tv.Name, v.Description, v.Priority, v.CreatedOn.Format(layout))\n\t}\n}\n\n// Delete an existing document from the collection.\nfunc delete() {\n\tif err := store.Delete(id); err != nil {\n\t\tlog.Fatalf(\"[Delete]: %s\\n\", err)\n\t}\n\tbookmarks := store.GetAll()\n\tfmt.Printf(\"Number of documents in the collection after delete:%d\\n\", len(bookmarks))\n}\n\n// main - entry point of the program.\nfunc main() {\n\tcreateUpdate()\n\tgetAll()\n\tgetByTags()\n\tdelete()\n}\n"
  },
  {
    "path": "ch06/postgres/main.go",
    "content": "package main\n\nimport (\n\t\"database/sql\"\n\t\"fmt\"\n\t\"log\"\n\n\t_ \"github.com/lib/pq\"\n)\n\n// Product struct provides the data model for productstore\ntype Product struct {\n\tID          int\n\tTitle       string\n\tDescription string\n\tPrice       float32\n}\n\nvar db *sql.DB\n\nfunc init() {\n\tvar err error\n\tdb, err = sql.Open(\"postgres\", \"postgres://user:pass@localhost/productstore\")\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\nfunc main() {\n\tproduct := Product{\n\t\tTitle:       \"Amazon Echo\",\n\t\tDescription: \"Amazon Echo - Black\",\n\t\tPrice:       179.99,\n\t}\n\t// Insert a product\n\tcreateProduct(product)\n\t// Read all product records\n\tgetProducts()\n\t// Read a product by given id\n\tgetProductByID(1)\n}\n\n// createProduct inserts product values into product table\nfunc createProduct(prd Product) {\n\tresult, err := db.Exec(\"INSERT INTO products(title, description, price) VALUES($1, $2, $3)\", prd.Title, prd.Description, prd.Price)\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\tlastInsertID, err := result.LastInsertId()\n\trowsAffected, err := result.RowsAffected()\n\tfmt.Printf(\"Product with id=%d created successfully (%d row affected)\\n\", lastInsertID, rowsAffected)\n}\n\n// getProducts reads all records from the product table\nfunc getProducts() {\n\trows, err := db.Query(\"SELECT * FROM products\")\n\tif err != nil {\n\t\tif err == sql.ErrNoRows {\n\t\t\tfmt.Println(\"No Records Found\")\n\t\t\treturn\n\t\t}\n\t\tlog.Fatal(err)\n\t}\n\tdefer rows.Close()\n\n\tvar products []*Product\n\tfor rows.Next() {\n\t\tprd := &Product{}\n\t\terr := rows.Scan(&prd.Title, &prd.Description, &prd.Price)\n\t\tif err != nil {\n\t\t\tlog.Fatal(err)\n\t\t}\n\t\tproducts = append(products, prd)\n\t}\n\tif err = rows.Err(); err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\tfor _, pr := range products {\n\t\tfmt.Printf(\"%s, %s, $%.2f\\n\", pr.Title, pr.Description, pr.Price)\n\t}\n}\n\nfunc getProductByID(id int) {\n\tvar product string\n\terr := db.QueryRow(\"SELECT title FROM products WHERE id=$1\", id).Scan(&product)\n\tswitch {\n\tcase err == sql.ErrNoRows:\n\t\tlog.Printf(\"No product with that ID.\")\n\tcase err != nil:\n\t\tlog.Fatal(err)\n\tdefault:\n\t\tfmt.Printf(\"Product is %s\\n\", product)\n\t}\n}\n"
  },
  {
    "path": "ch06/rethink/bookmark_store.go",
    "content": "package main\n\nimport (\n\t\"time\"\n\n\tr \"github.com/dancannon/gorethink\"\n)\n\n// Bookmark type reperesents the metadata of a bookmark.\ntype Bookmark struct {\n\tID                          string `gorethink:\"id,omitempty\" json:\"id\"`\n\tName, Description, Location string\n\tPriority                    int // Priority (1 -5)\n\tCreatedOn                   time.Time\n\tTags                        []string\n}\n\n// BookmarkStore provides CRUD operations against the Table \"bookmarks\".\ntype BookmarkStore struct {\n\tSession *r.Session\n}\n\n// Create inserts the value of struct Bookmark into Table.\nfunc (store BookmarkStore) Create(b *Bookmark) error {\n\n\tresp, err := r.Table(\"bookmarks\").Insert(b).RunWrite(store.Session)\n\tif err == nil {\n\t\tb.ID = resp.GeneratedKeys[0]\n\t}\n\n\treturn err\n}\n\n// Update modifies an existing value of a Table.\nfunc (store BookmarkStore) Update(b Bookmark) error {\n\n\tvar data = map[string]interface{}{\n\t\t\"description\": b.Description,\n\t\t\"location\":    b.Location,\n\t\t\"priority\":    b.Priority,\n\t\t\"tags\":        b.Tags,\n\t}\n\t// partial update on RethinkDB\n\t_, err := r.Table(\"bookmarks\").Get(b.ID).Update(data).RunWrite(store.Session)\n\treturn err\n}\n\n// Delete removes an existing value from the Table.\nfunc (store BookmarkStore) Delete(id string) error {\n\t_, err := r.Table(\"bookmarks\").Get(id).Delete().RunWrite(store.Session)\n\treturn err\n}\n\n// GetAll returns all documents from the Table.\nfunc (store BookmarkStore) GetAll() ([]Bookmark, error) {\n\tbookmarks := []Bookmark{}\n\n\tres, err := r.Table(\"bookmarks\").OrderBy(\"priority\", r.Desc(\"createdon\")).Run(store.Session)\n\terr = res.All(&bookmarks)\n\treturn bookmarks, err\n}\n\n// GetByID returns single document from the Table.\nfunc (store BookmarkStore) GetByID(id string) (Bookmark, error) {\n\tvar b Bookmark\n\tres, err := r.Table(\"bookmarks\").Get(id).Run(store.Session)\n\tres.One(&b)\n\treturn b, err\n}\n\n// // GetByTag returns all documents from the collection filtering by tags.\n// func (store BookmarkStore) GetByTag(tags []string) ([]Bookmark, error) {\n// \tbookmarks := []Bookmark{}\n// \tres, err := r.Table(\"bookmarks\").Filter(func(row r.Term) r.Term {\n// \t\treturn r.Expr(tags).Contains(row.Field(\"tags\"))\n// \t}).Run(store.Session)\n// \terr = res.All(&bookmarks)\n// \treturn bookmarks, err\n// }\n"
  },
  {
    "path": "ch06/rethink/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"time\"\n\n\tr \"github.com/dancannon/gorethink\"\n)\n\nvar store BookmarkStore\nvar id string\n\n// initDB creates new database and\nfunc initDB(session *r.Session) {\n\tvar err error\n\t// Create Database\n\t_, err = r.DBCreate(\"bookmarkdb\").RunWrite(session)\n\tif err != nil {\n\t\tlog.Fatalf(\"[initDB]: %s\\n\", err)\n\t}\n\t// Create Table\n\t_, err = r.DB(\"bookmarkdb\").TableCreate(\"bookmarks\").RunWrite(session)\n\tif err != nil {\n\t\tlog.Fatalf(\"[initDB]: %s\\n\", err)\n\t}\n}\n\n// changeFeeds subscribes real-time updates on table bookmarks.\nfunc changeFeeds(session *r.Session) {\n\tbookmarks, err := r.Table(\"bookmarks\").Changes().Field(\"new_val\").Run(session)\n\tif err != nil {\n\t\tlog.Fatalf(\"[changeFeeds]: %s\\n\", err)\n\t}\n\t// Luanch a goroutine to print real-time updates.\n\tgo func() {\n\t\tvar bookmark Bookmark\n\t\tfor bookmarks.Next(&bookmark) {\n\t\t\tif bookmark.ID == \"\" { // for delete, new_val will be null.\n\t\t\t\tfmt.Println(\"Real-time update: Document has been deleted\")\n\t\t\t} else {\n\t\t\t\tfmt.Printf(\"Real-time update: Name:%s, Description:%s, Priority:%d\\n\",\n\t\t\t\t\tbookmark.Name, bookmark.Description, bookmark.Priority)\n\t\t\t}\n\t\t}\n\t}()\n}\n\n// init will invoke before the function main.\nfunc init() {\n\tsession, err := r.Connect(r.ConnectOpts{\n\t\tAddress:  \"localhost:28015\",\n\t\tDatabase: \"bookmarkdb\",\n\t\tMaxIdle:  10,\n\t\tMaxOpen:  10,\n\t})\n\n\tif err != nil {\n\t\tlog.Fatalf(\"[RethinkDB Session]: %s\\n\", err)\n\t}\n\tr.Table(\"bookmarks\").Delete().Run(session)\n\t// Create Database and Table.\n\t//initDB(session)\n\tstore = BookmarkStore{\n\t\tSession: session,\n\t}\n\t// Subscribe real-time changes\n\tchangeFeeds(session)\n}\n\n// Create and update documents.\nfunc createUpdate() {\n\tbookmark := Bookmark{\n\t\tName:        \"mgo\",\n\t\tDescription: \"Go driver for MongoDB\",\n\t\tLocation:    \"https://github.com/go-mgo/mgo\",\n\t\tPriority:    1,\n\t\tCreatedOn:   time.Now(),\n\t\tTags:        []string{\"go\", \"nosql\", \"mongodb\"},\n\t}\n\t// Insert a new document.\n\tif err := store.Create(&bookmark); err != nil {\n\t\tlog.Fatalf(\"[Create]: %s\\n\", err)\n\t}\n\tid = bookmark.ID\n\tfmt.Printf(\"New bookmark has been inserted with ID: %s\\n\", id)\n\t// Retrieve the updated document.\n\tbookmark.Priority = 2\n\tif err := store.Update(bookmark); err != nil {\n\t\tlog.Fatalf(\"[Update]: %s\\n\", err)\n\t}\n\tfmt.Println(\"The value after update:\")\n\t// Retrieve an existing document by id.\n\tgetByID(id)\n\tbookmark = Bookmark{\n\t\tName:        \"gorethink\",\n\t\tDescription: \"Go driver for RethinkDB\",\n\t\tLocation:    \"https://github.com/dancannon/gorethink\",\n\t\tPriority:    1,\n\t\tCreatedOn:   time.Now(),\n\t\tTags:        []string{\"go\", \"nosql\", \"rethinkdb\"},\n\t}\n\t// Insert a new document.\n\tif err := store.Create(&bookmark); err != nil {\n\t\tlog.Fatalf(\"[Create]: %s\\n\", err)\n\t}\n\tid = bookmark.ID\n\tfmt.Printf(\"New bookmark has been inserted with ID: %s\\n\", id)\n\n}\n\n// Get a document by given id.\nfunc getByID(id string) {\n\tbookmark, err := store.GetByID(id)\n\tif err != nil {\n\t\tlog.Fatalf(\"[GetByID]: %s\\n\", err)\n\t}\n\tfmt.Printf(\"Name:%s, Description:%s, Priority:%d\\n\", bookmark.Name, bookmark.Description, bookmark.Priority)\n}\n\n// Get all documents from bookmarks table.\nfunc getAll() {\n\t// Layout for formatting dates.\n\tlayout := \"2006-01-02 15:04:05\"\n\t// Retrieve all documents.\n\tbookmarks, err := store.GetAll()\n\tif err != nil {\n\t\tlog.Fatalf(\"[GetAll]: %s\\n\", err)\n\t}\n\tfmt.Println(\"Read all documents\")\n\tfor _, v := range bookmarks {\n\t\tfmt.Printf(\"Name:%s, Description:%s, Priority:%d, CreatedOn:%s\\n\", v.Name, v.Description, v.Priority, v.CreatedOn.Format(layout))\n\t}\n\n}\n\n// Delete an existing document from bookmarks table.\nfunc delete() {\n\tif err := store.Delete(id); err != nil {\n\t\tlog.Fatalf(\"[Delete]: %s\\n\", err)\n\t}\n\tbookmarks, err := store.GetAll()\n\tif err != nil {\n\t\tlog.Fatalf(\"[GetAll]: %s\\n\", err)\n\t}\n\tfmt.Printf(\"Number of documents in the table after delete:%d\\n\", len(bookmarks))\n}\n\n// main - entry point of the program\nfunc main() {\n\tcreateUpdate()\n\tgetAll()\n\tdelete()\n}\n"
  },
  {
    "path": "ch07/bookmarkapi/common/auth.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"crypto/rsa\"\n\t\"errors\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"net/http\"\n\t\"strings\"\n\t\"time\"\n\n\tjwt \"github.com/dgrijalva/jwt-go\"\n\t\"github.com/dgrijalva/jwt-go/request\"\n)\n\n// AppClaims provides custom claim for JWT\ntype AppClaims struct {\n\tUserName string `json:\"username\"`\n\tRole     string `json:\"role\"`\n\tjwt.StandardClaims\n}\n\n// using asymmetric crypto/RSA keys\n// location of private/public key files\nconst (\n\t// openssl genrsa -out app.rsa 1024\n\tprivKeyPath = \"keys/app.rsa\"\n\t// openssl rsa -in app.rsa -pubout > app.rsa.pub\n\tpubKeyPath = \"keys/app.rsa.pub\"\n)\n\n// Private key for signing and public key for verification\nvar (\n\t//verifyKey, signKey []byte\n\tverifyKey *rsa.PublicKey\n\tsignKey   *rsa.PrivateKey\n)\n\n// Read the key files before starting http handlers\nfunc initKeys() {\n\n\tsignBytes, err := ioutil.ReadFile(privKeyPath)\n\tif err != nil {\n\t\tlog.Fatalf(\"[initKeys]: %s\\n\", err)\n\t}\n\n\tsignKey, err = jwt.ParseRSAPrivateKeyFromPEM(signBytes)\n\tif err != nil {\n\t\tlog.Fatalf(\"[initKeys]: %s\\n\", err)\n\t}\n\n\tverifyBytes, err := ioutil.ReadFile(pubKeyPath)\n\tif err != nil {\n\t\tlog.Fatalf(\"[initKeys]: %s\\n\", err)\n\t}\n\n\tverifyKey, err = jwt.ParseRSAPublicKeyFromPEM(verifyBytes)\n\tif err != nil {\n\t\tlog.Fatalf(\"[initKeys]: %s\\n\", err)\n\t}\n}\n\n// GenerateJWT generates a new JWT token for authenticated user.\nfunc GenerateJWT(name, role string) (string, error) {\n\t// Create the Claims\n\tclaims := AppClaims{\n\t\tUserName: name,\n\t\tRole:     role,\n\t\tStandardClaims: jwt.StandardClaims{\n\t\t\tExpiresAt: time.Now().Add(time.Minute * 20).Unix(),\n\t\t\tIssuer:    \"admin\",\n\t\t},\n\t}\n\ttoken := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)\n\tss, err := token.SignedString(signKey)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn ss, nil\n}\n\n// AuthorizeRequest Middleware validates JWT tokens from incoming HTTP requests.\nfunc AuthorizeRequest(next http.Handler) http.Handler {\n\treturn http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t// Get token from request\n\t\ttoken, err := request.ParseFromRequestWithClaims(r, request.OAuth2Extractor, &AppClaims{}, func(token *jwt.Token) (interface{}, error) {\n\t\t\t// since we only use the one private key to sign the tokens,\n\t\t\t// we also only use its public counter part to verify\n\t\t\treturn verifyKey, nil\n\t\t})\n\n\t\tif err != nil {\n\t\t\tswitch err.(type) {\n\n\t\t\tcase *jwt.ValidationError: // JWT validation error\n\t\t\t\tvErr := err.(*jwt.ValidationError)\n\n\t\t\t\tswitch vErr.Errors {\n\t\t\t\tcase jwt.ValidationErrorExpired: //JWT expired\n\t\t\t\t\tDisplayAppError(\n\t\t\t\t\t\tw,\n\t\t\t\t\t\terr,\n\t\t\t\t\t\t\"Access Token is expired, get a new Token\",\n\t\t\t\t\t\t401,\n\t\t\t\t\t)\n\t\t\t\t\treturn\n\n\t\t\t\tdefault:\n\t\t\t\t\tDisplayAppError(w,\n\t\t\t\t\t\terr,\n\t\t\t\t\t\t\"Error while parsing the Access Token!\",\n\t\t\t\t\t\t500,\n\t\t\t\t\t)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tDisplayAppError(w,\n\t\t\t\t\terr,\n\t\t\t\t\t\"Error while parsing Access Token!\",\n\t\t\t\t\t500)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t}\n\t\tif token.Valid {\n\t\t\t// Create a Context by setting the user name\n\t\t\tctx := context.WithValue(r.Context(), \"user\", token.Claims.(*AppClaims).UserName)\n\t\t\t// Calls the next handler by providing the Context\n\t\t\tnext.ServeHTTP(w, r.WithContext(ctx))\n\t\t} else {\n\t\t\tDisplayAppError(\n\t\t\t\tw,\n\t\t\t\terr,\n\t\t\t\t\"Invalid Access Token\",\n\t\t\t\t401,\n\t\t\t)\n\t\t}\n\t})\n}\n\n// AuthorizeRequestWithNegroni is a Negroni Middleware that validates JWT tokens\nfunc AuthorizeRequestWithNegroni(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {\n\n\t// Get token from request\n\ttoken, err := request.ParseFromRequestWithClaims(r, request.OAuth2Extractor, &AppClaims{}, func(token *jwt.Token) (interface{}, error) {\n\t\t// since we only use the one private key to sign the tokens,\n\t\t// we also only use its public counter part to verify\n\t\treturn verifyKey, nil\n\t})\n\n\tif err != nil {\n\t\tswitch err.(type) {\n\n\t\tcase *jwt.ValidationError: // JWT validation error\n\t\t\tvErr := err.(*jwt.ValidationError)\n\n\t\t\tswitch vErr.Errors {\n\t\t\tcase jwt.ValidationErrorExpired: //JWT expired\n\t\t\t\tDisplayAppError(\n\t\t\t\t\tw,\n\t\t\t\t\terr,\n\t\t\t\t\t\"Access Token is expired, get a new Token\",\n\t\t\t\t\t401,\n\t\t\t\t)\n\t\t\t\treturn\n\n\t\t\tdefault:\n\t\t\t\tDisplayAppError(w,\n\t\t\t\t\terr,\n\t\t\t\t\t\"Error while parsing the Access Token!\",\n\t\t\t\t\t500,\n\t\t\t\t)\n\t\t\t\treturn\n\t\t\t}\n\n\t\tdefault:\n\t\t\tDisplayAppError(w,\n\t\t\t\terr,\n\t\t\t\t\"Error while parsing Access Token!\",\n\t\t\t\t500)\n\t\t\treturn\n\t\t}\n\n\t}\n\tif token.Valid {\n\t\tctx := context.WithValue(r.Context(), \"user\", token.Claims.(*AppClaims).UserName)\n\t\tnext(w, r.WithContext(ctx))\n\t} else {\n\t\tDisplayAppError(\n\t\t\tw,\n\t\t\terr,\n\t\t\t\"Invalid Access Token\",\n\t\t\t401,\n\t\t)\n\t}\n}\n\n// TokenFromAuthHeader is a \"TokenExtractor\" that takes a given request and extracts\n// the JWT token from the Authorization header.\nfunc TokenFromAuthHeader(r *http.Request) (string, error) {\n\t// Look for an Authorization header\n\tif ah := r.Header.Get(\"Authorization\"); ah != \"\" {\n\t\t// Should be a bearer token\n\t\tif len(ah) > 6 && strings.ToUpper(ah[0:6]) == \"BEARER\" {\n\t\t\treturn ah[7:], nil\n\t\t}\n\t}\n\treturn \"\", errors.New(\"No token in the HTTP request\")\n}\n"
  },
  {
    "path": "ch07/bookmarkapi/common/bootstrapper.go",
    "content": "package common\n\n// StartUp bootstrapps the application\nfunc StartUp() {\n\t// Initialize AppConfig variable\n\tinitConfig()\n\t// Initialize private/public keys for JWT authentication\n\tinitKeys()\n\t// Initialize Logger objects with Log Level\n\tsetLogLevel(Level(AppConfig.LogLevel))\n\t// Start a MongoDB session\n\tcreateDBSession()\n\t// Add indexes into MongoDB\n\taddIndexes()\n}\n"
  },
  {
    "path": "ch07/bookmarkapi/common/config.json",
    "content": "{\n  \"Server\"      : \"0.0.0.0:8080\",\n  \"MongoDBHost\" : \"127.0.0.1\",\n  \"MongoDBUser\"\t: \"\",\n  \"MongoDBPwd\"\t: \"\",\n  \"Database\"    : \"bookmarkdb\",\n  \"LogLevel\"    : 4\n}\n"
  },
  {
    "path": "ch07/bookmarkapi/common/logger.go",
    "content": "package common\n\nimport (\n\t\"io\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"os\"\n)\n\nconst (\n\t// UNSPECIFIED logs nothing\n\tUNSPECIFIED Level = iota // 0 :\n\t// TRACE logs everything\n\tTRACE // 1\n\t// INFO logs Info, Warnings and Errors\n\tINFO // 2\n\t// WARNING logs Warning and Errors\n\tWARNING // 3\n\t// ERROR just logs Errors\n\tERROR // 4\n)\n\n// Level holds the log level.\ntype Level int\n\n// Package level variables, which are pointer to log.Logger.\nvar (\n\tTrace   *log.Logger\n\tInfo    *log.Logger\n\tWarning *log.Logger\n\tError   *log.Logger\n)\n\n// initLog initializes log.Logger objects\nfunc initLog(\n\ttraceHandle io.Writer,\n\tinfoHandle io.Writer,\n\twarningHandle io.Writer,\n\terrorHandle io.Writer,\n\tisFlag bool) {\n\n\t// Flags for defines the logging properties, to log.New\n\tflag := 0\n\tif isFlag {\n\t\tflag = log.Ldate | log.Ltime | log.Lshortfile\n\t}\n\n\t// Create log.Logger objects.\n\tTrace = log.New(traceHandle, \"TRACE: \", flag)\n\tInfo = log.New(infoHandle, \"INFO: \", flag)\n\tWarning = log.New(warningHandle, \"WARNING: \", flag)\n\tError = log.New(errorHandle, \"ERROR: \", flag)\n\n}\n\n// SetLogLevel sets the logging level preference\nfunc setLogLevel(level Level) {\n\n\t// Creates os.*File, which has implemented io.Writer intreface\n\tf, err := os.OpenFile(\"logs.txt\", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)\n\tif err != nil {\n\t\tlog.Fatalf(\"Error opening log file: %s\", err.Error())\n\t}\n\n\t// Calls function initLog by specifying log level preference.\n\tswitch level {\n\tcase TRACE:\n\t\tinitLog(f, f, f, f, true)\n\t\treturn\n\n\tcase INFO:\n\t\tinitLog(ioutil.Discard, f, f, f, true)\n\t\treturn\n\n\tcase WARNING:\n\t\tinitLog(ioutil.Discard, ioutil.Discard, f, f, true)\n\t\treturn\n\tcase ERROR:\n\t\tinitLog(ioutil.Discard, ioutil.Discard, ioutil.Discard, f, true)\n\t\treturn\n\n\tdefault:\n\t\tinitLog(ioutil.Discard, ioutil.Discard, ioutil.Discard, ioutil.Discard, false)\n\t\tf.Close()\n\t\treturn\n\n\t}\n}\n"
  },
  {
    "path": "ch07/bookmarkapi/common/mongo_utils.go",
    "content": "package common\n\nimport (\n\t\"log\"\n\t\"time\"\n\n\t\"gopkg.in/mgo.v2\"\n)\n\nvar session *mgo.Session\n\n// GetSession returns a MongoDB Session\nfunc getSession() *mgo.Session {\n\tif session == nil {\n\t\tvar err error\n\t\tsession, err = mgo.DialWithInfo(&mgo.DialInfo{\n\t\t\tAddrs:    []string{AppConfig.MongoDBHost},\n\t\t\tUsername: AppConfig.DBUser,\n\t\t\tPassword: AppConfig.DBPwd,\n\t\t\tTimeout:  60 * time.Second,\n\t\t})\n\t\tif err != nil {\n\t\t\tlog.Fatalf(\"[GetSession]: %s\\n\", err)\n\t\t}\n\t}\n\treturn session\n}\nfunc createDBSession() {\n\tvar err error\n\tsession, err = mgo.DialWithInfo(&mgo.DialInfo{\n\t\tAddrs:    []string{AppConfig.MongoDBHost},\n\t\tUsername: AppConfig.DBUser,\n\t\tPassword: AppConfig.DBPwd,\n\t\tTimeout:  60 * time.Second,\n\t})\n\tif err != nil {\n\t\tlog.Fatalf(\"[createDbSession]: %s\\n\", err)\n\t}\n}\n\n// Add indexes into MongoDB\nfunc addIndexes() {\n\tvar err error\n\tuserIndex := mgo.Index{\n\t\tKey:        []string{\"email\"},\n\t\tUnique:     true,\n\t\tBackground: true,\n\t\tSparse:     true,\n\t}\n\t// Add indexes into MongoDB\n\tsession := getSession().Copy()\n\tdefer session.Close()\n\tuserCol := session.DB(AppConfig.Database).C(\"users\")\n\n\terr = userCol.EnsureIndex(userIndex)\n\tif err != nil {\n\t\tlog.Fatalf(\"[addIndexes]: %s\\n\", err)\n\t}\n}\n\n// DataStore for MongoDB\ntype DataStore struct {\n\tMongoSession *mgo.Session\n}\n\n// Close closes a mgo.Session value.\n// Used to add defer statements for closing the copied session.\nfunc (ds *DataStore) Close() {\n\tds.MongoSession.Close()\n}\n\n// Collection returns mgo.collection for the given name\nfunc (ds *DataStore) Collection(name string) *mgo.Collection {\n\treturn ds.MongoSession.DB(AppConfig.Database).C(name)\n}\n\n// NewDataStore creates a new DataStore object to be used for each HTTP request.\nfunc NewDataStore() *DataStore {\n\tsession := getSession().Copy()\n\tdataStore := &DataStore{\n\t\tMongoSession: session,\n\t}\n\treturn dataStore\n}\n"
  },
  {
    "path": "ch07/bookmarkapi/common/utils.go",
    "content": "package common\n\nimport (\n\t\"encoding/json\"\n\t\"log\"\n\t\"net/http\"\n\t\"os\"\n)\n\ntype (\n\tappError struct {\n\t\tError      string `json:\"error\"`\n\t\tMessage    string `json:\"message\"`\n\t\tHTTPStatus int    `json:\"status\"`\n\t}\n\terrorResource struct {\n\t\tData appError `json:\"data\"`\n\t}\n\tconfiguration struct {\n\t\tServer, MongoDBHost, DBUser, DBPwd, Database string\n\t\tLogLevel                                     int\n\t}\n)\n\n// DisplayAppError provides app specific error in JSON\nfunc DisplayAppError(w http.ResponseWriter, handlerError error, message string, code int) {\n\terrObj := appError{\n\t\tError:      handlerError.Error(),\n\t\tMessage:    message,\n\t\tHTTPStatus: code,\n\t}\n\t//log.Printf(\"AppError]: %s\\n\", handlerError)\n\tError.Printf(\"AppError]: %s\\n\", handlerError)\n\tw.Header().Set(\"Content-Type\", \"application/json; charset=utf-8\")\n\tw.WriteHeader(code)\n\tif j, err := json.Marshal(errorResource{Data: errObj}); err == nil {\n\t\tw.Write(j)\n\t}\n}\n\n// AppConfig holds the configuration values from config.json file\nvar AppConfig configuration\n\n// Initialize AppConfig\nfunc initConfig() {\n\tloadAppConfig()\n}\n\n// Reads config.json and decode into AppConfig\nfunc loadAppConfig() {\n\tfile, err := os.Open(\"common/config.json\")\n\tdefer file.Close()\n\tif err != nil {\n\t\tlog.Fatalf(\"[loadConfig]: %s\\n\", err)\n\t}\n\tdecoder := json.NewDecoder(file)\n\tAppConfig = configuration{}\n\terr = decoder.Decode(&AppConfig)\n\tif err != nil {\n\t\tlog.Fatalf(\"[loadAppConfig]: %s\\n\", err)\n\t}\n}\n"
  },
  {
    "path": "ch07/bookmarkapi/controllers/bookmark_controller.go",
    "content": "package controllers\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\n\t\"github.com/gorilla/mux\"\n\t\"gopkg.in/mgo.v2\"\n\t\"gopkg.in/mgo.v2/bson\"\n\n\t\"github.com/shijuvar/go-recipes/ch07/bookmarkapi/common\"\n\t\"github.com/shijuvar/go-recipes/ch07/bookmarkapi/store\"\n)\n\n// CreateBookmark insert a new Bookmark.\n// Handler for HTTP Post - \"/bookmarks\nfunc CreateBookmark(w http.ResponseWriter, r *http.Request) {\n\tvar dataResource BookmarkResource\n\t// Decode the incoming Bookmark json\n\terr := json.NewDecoder(r.Body).Decode(&dataResource)\n\tif err != nil {\n\t\tcommon.DisplayAppError(\n\t\t\tw,\n\t\t\terr,\n\t\t\t\"Invalid Bookmark data\",\n\t\t\t500,\n\t\t)\n\t\treturn\n\t}\n\tbookmark := &dataResource.Data\n\t// Creates a new DatStore value to working with MongoDB store.\n\tdataStore := common.NewDataStore()\n\t// Add to the mgo.Session.Close()\n\tdefer dataStore.Close()\n\t// Get the mgo.Collection for \"bookmarks\"\n\tcol := dataStore.Collection(\"bookmarks\")\n\t// Creates an instance of BookmarkStore\n\tbookmarkStore := store.BookmarkStore{C: col}\n\t// Takes user name from Context\n\tuser := r.Context().Value(\"user\")\n\tif user != nil {\n\t\tbookmark.CreatedBy = user.(string)\n\t}\n\t// Insert a bookmark document\n\terr = bookmarkStore.Create(bookmark)\n\tif err != nil {\n\t\tcommon.DisplayAppError(\n\t\t\tw,\n\t\t\terr,\n\t\t\t\"Invalid Bookmark data\",\n\t\t\t500,\n\t\t)\n\t\treturn\n\t}\n\tj, err := json.Marshal(BookmarkResource{Data: *bookmark})\n\t// If error is occured,\n\t// Send JSON response using helper function common.DisplayAppError\n\tif err != nil {\n\t\tcommon.DisplayAppError(\n\t\t\tw,\n\t\t\terr,\n\t\t\t\"An unexpected error has occurred\",\n\t\t\t500,\n\t\t)\n\t\treturn\n\t}\n\tw.Header().Set(\"Content-Type\", \"application/json\")\n\tw.WriteHeader(http.StatusCreated)\n\t// Write the JSON data to the ResponseWriter\n\tw.Write(j)\n\n}\n\n// GetBookmarks returns all Bookmark documents\n// Handler for HTTP Get - \"/Bookmarks\"\nfunc GetBookmarks(w http.ResponseWriter, r *http.Request) {\n\tdataStore := common.NewDataStore()\n\tdefer dataStore.Close()\n\tcol := dataStore.Collection(\"bookmarks\")\n\tbookmarkStore := store.BookmarkStore{C: col}\n\tbookmarks := bookmarkStore.GetAll()\n\tj, err := json.Marshal(BookmarksResource{Data: bookmarks})\n\tif err != nil {\n\t\tcommon.DisplayAppError(\n\t\t\tw,\n\t\t\terr,\n\t\t\t\"An unexpected error has occurred\",\n\t\t\t500,\n\t\t)\n\t\treturn\n\t}\n\tw.WriteHeader(http.StatusOK)\n\tw.Header().Set(\"Content-Type\", \"application/json\")\n\tw.Write(j)\n}\n\n// GetBookmarkByID returns a single bookmark document by id\n// Handler for HTTP Get - \"/Bookmarks/{id}\"\nfunc GetBookmarkByID(w http.ResponseWriter, r *http.Request) {\n\t// Get id from the incoming url\n\tvars := mux.Vars(r)\n\tid := vars[\"id\"]\n\n\tdataStore := common.NewDataStore()\n\tdefer dataStore.Close()\n\tcol := dataStore.Collection(\"bookmarks\")\n\tbookmarkStore := store.BookmarkStore{C: col}\n\n\tbookmark, err := bookmarkStore.GetByID(id)\n\tif err != nil {\n\t\tif err == mgo.ErrNotFound {\n\t\t\tw.WriteHeader(http.StatusNoContent)\n\n\t\t} else {\n\t\t\tcommon.DisplayAppError(\n\t\t\t\tw,\n\t\t\t\terr,\n\t\t\t\t\"An unexpected error has occurred\",\n\t\t\t\t500,\n\t\t\t)\n\n\t\t}\n\t\treturn\n\t}\n\tj, err := json.Marshal(bookmark)\n\tif err != nil {\n\t\tcommon.DisplayAppError(\n\t\t\tw,\n\t\t\terr,\n\t\t\t\"An unexpected error has occurred\",\n\t\t\t500,\n\t\t)\n\t\treturn\n\t}\n\tw.Header().Set(\"Content-Type\", \"application/json\")\n\tw.WriteHeader(http.StatusOK)\n\tw.Write(j)\n}\n\n// GetBookmarksByUser returns all Bookmarks created by a User\n// Handler for HTTP Get - \"/Bookmarks/users/{id}\"\nfunc GetBookmarksByUser(w http.ResponseWriter, r *http.Request) {\n\t// Get id from the incoming url\n\tvars := mux.Vars(r)\n\tuser := vars[\"id\"]\n\tdataStore := common.NewDataStore()\n\tdefer dataStore.Close()\n\tcol := dataStore.Collection(\"bookmarks\")\n\tbookmarkStore := store.BookmarkStore{C: col}\n\tbookmarks := bookmarkStore.GetByUser(user)\n\tj, err := json.Marshal(BookmarksResource{Data: bookmarks})\n\tif err != nil {\n\t\tcommon.DisplayAppError(\n\t\t\tw,\n\t\t\terr,\n\t\t\t\"An unexpected error has occurred\",\n\t\t\t500,\n\t\t)\n\t\treturn\n\t}\n\tw.WriteHeader(http.StatusOK)\n\tw.Header().Set(\"Content-Type\", \"application/json\")\n\tw.Write(j)\n}\n\n// UpdateBookmark update an existing Bookmark document\n// Handler for HTTP Put - \"/Bookmarks/{id}\"\nfunc UpdateBookmark(w http.ResponseWriter, r *http.Request) {\n\t// Get id from the incoming url\n\tvars := mux.Vars(r)\n\tid := bson.ObjectIdHex(vars[\"id\"])\n\tvar dataResource BookmarkResource\n\t// Decode the incoming Bookmark json\n\terr := json.NewDecoder(r.Body).Decode(&dataResource)\n\tif err != nil {\n\t\tcommon.DisplayAppError(\n\t\t\tw,\n\t\t\terr,\n\t\t\t\"Invalid Bookmark data\",\n\t\t\t500,\n\t\t)\n\t\treturn\n\t}\n\tbookmark := dataResource.Data\n\tbookmark.ID = id\n\tdataStore := common.NewDataStore()\n\tdefer dataStore.Close()\n\tcol := dataStore.Collection(\"bookmarks\")\n\tbookmarkStore := store.BookmarkStore{C: col}\n\t// Update an existing Bookmark document\n\tif err := bookmarkStore.Update(bookmark); err != nil {\n\t\tcommon.DisplayAppError(\n\t\t\tw,\n\t\t\terr,\n\t\t\t\"An unexpected error has occurred\",\n\t\t\t500,\n\t\t)\n\t\treturn\n\t}\n\tw.WriteHeader(http.StatusNoContent)\n\n}\n\n// DeleteBookmark deletes an existing Bookmark document\n// Handler for HTTP Delete - \"/Bookmarks/{id}\"\nfunc DeleteBookmark(w http.ResponseWriter, r *http.Request) {\n\tvars := mux.Vars(r)\n\tid := vars[\"id\"]\n\tdataStore := common.NewDataStore()\n\tdefer dataStore.Close()\n\tcol := dataStore.Collection(\"bookmarks\")\n\tbookmarkStore := store.BookmarkStore{C: col}\n\t// Delete an existing Bookmark document\n\terr := bookmarkStore.Delete(id)\n\tif err != nil {\n\t\tcommon.DisplayAppError(\n\t\t\tw,\n\t\t\terr,\n\t\t\t\"An unexpected error has occurred\",\n\t\t\t500,\n\t\t)\n\t\treturn\n\t}\n\tw.WriteHeader(http.StatusNoContent)\n}\n"
  },
  {
    "path": "ch07/bookmarkapi/controllers/resources.go",
    "content": "package controllers\n\nimport (\n\t\"github.com/shijuvar/go-recipes/ch07/bookmarkapi/model\"\n)\n\n//Models for JSON resources\ntype (\n\t// UserResource For Post - /user/register\n\tUserResource struct {\n\t\tData UserModel `json:\"data\"`\n\t}\n\t// AuthUserResource Response for authorized user Post - /user/login\n\tAuthUserResource struct {\n\t\tData AuthUserModel `json:\"data\"`\n\t}\n\t// BookmarkResource For Post/Put - /bookmarks\n\t// For Get - /bookmarks/id\n\tBookmarkResource struct {\n\t\tData model.Bookmark `json:\"data\"`\n\t}\n\t// BookmarksResource for Get - /bookmarks\n\tBookmarksResource struct {\n\t\tData []model.Bookmark `json:\"data\"`\n\t}\n\n\t// UserModel reperesents a user\n\tUserModel struct {\n\t\tFirstName string `json:\"firstname\"`\n\t\tLastName  string `json:\"lastname\"`\n\t\tEmail     string `json:\"email\"`\n\t\tPassword  string `json:\"password\"`\n\t}\n\t// AuthUserModel for authorized user with access token\n\tAuthUserModel struct {\n\t\tUser  model.User `json:\"user\"`\n\t\tToken string     `json:\"token\"`\n\t}\n)\n"
  },
  {
    "path": "ch07/bookmarkapi/controllers/user_controller.go",
    "content": "package controllers\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\n\t\"github.com/shijuvar/go-recipes/ch07/bookmarkapi/common\"\n\t\"github.com/shijuvar/go-recipes/ch07/bookmarkapi/model\"\n\t\"github.com/shijuvar/go-recipes/ch07/bookmarkapi/store\"\n)\n\n// Register add a new User document\n// Handler for HTTP Post - \"/users/register\"\nfunc Register(w http.ResponseWriter, r *http.Request) {\n\tvar dataResource UserResource\n\t// Decode the incoming User json\n\terr := json.NewDecoder(r.Body).Decode(&dataResource)\n\tif err != nil {\n\t\tcommon.DisplayAppError(\n\t\t\tw,\n\t\t\terr,\n\t\t\t\"Invalid User data\",\n\t\t\t500,\n\t\t)\n\t\treturn\n\t}\n\tuserModel := dataResource.Data\n\tdataStore := common.NewDataStore()\n\tdefer dataStore.Close()\n\tcol := dataStore.Collection(\"users\")\n\tuserStore := store.UserStore{C: col}\n\tuser := model.User{\n\t\tFirstName: userModel.FirstName,\n\t\tLastName:  userModel.LastName,\n\t\tEmail:     userModel.Email,\n\t}\n\t// Insert User document\n\tuserStore.Create(user, userModel.Password)\n\tw.Header().Set(\"Content-Type\", \"application/json\")\n\tw.WriteHeader(http.StatusCreated)\n}\n\n// Login authenticates the HTTP request with username and apssword\n// Handler for HTTP Post - \"/users/login\"\nfunc Login(w http.ResponseWriter, r *http.Request) {\n\tvar dataResource UserResource\n\tvar token string\n\t// Decode the incoming Login json\n\terr := json.NewDecoder(r.Body).Decode(&dataResource)\n\tif err != nil {\n\t\tcommon.DisplayAppError(\n\t\t\tw,\n\t\t\terr,\n\t\t\t\"Invalid Login data\",\n\t\t\t500,\n\t\t)\n\t\treturn\n\t}\n\tloginUser := dataResource.Data\n\tdataStore := common.NewDataStore()\n\tdefer dataStore.Close()\n\tcol := dataStore.Collection(\"users\")\n\tuserStore := store.UserStore{C: col}\n\t// Authenticate the login user\n\tuser, err := userStore.Login(loginUser.Email, loginUser.Password)\n\tif err != nil {\n\t\tcommon.DisplayAppError(\n\t\t\tw,\n\t\t\terr,\n\t\t\t\"Invalid login credentials\",\n\t\t\t401,\n\t\t)\n\t\treturn\n\t}\n\t// Generate JWT token\n\ttoken, err = common.GenerateJWT(user.Email, \"member\")\n\tif err != nil {\n\t\tcommon.DisplayAppError(\n\t\t\tw,\n\t\t\terr,\n\t\t\t\"Eror while generating the access token\",\n\t\t\t500,\n\t\t)\n\t\treturn\n\t}\n\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t// Clean-up the hashpassword to eliminate it from response JSON\n\tuser.HashPassword = nil\n\tauthUser := AuthUserModel{\n\t\tUser:  user,\n\t\tToken: token,\n\t}\n\tj, err := json.Marshal(AuthUserResource{Data: authUser})\n\tif err != nil {\n\t\tcommon.DisplayAppError(\n\t\t\tw,\n\t\t\terr,\n\t\t\t\"An unexpected error has occurred\",\n\t\t\t500,\n\t\t)\n\t\treturn\n\t}\n\tw.WriteHeader(http.StatusOK)\n\tw.Write(j)\n}\n"
  },
  {
    "path": "ch07/bookmarkapi/keys/app.rsa",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nMIICWwIBAAKBgQDPSMNALgfEMEDbS3kCLiTlpx0S4tZH1jZLcGF5Pjhc9IuEIf7p\n6obYT1W7urDPWM8JGO1mdx+GnJCnPcvFSsX8FjGwDqIp7afTdislYCJwQLXL7qPz\nwvG7ZlrtXrC9+0xkDGNxB+5Cui++8gWGbfTpTZiCiP413esxVQ30btKk2QIDAQAB\nAoGACfj1M9RDGWQ86pAB/WHc8pOMqYjySDh9GjoI5n1g1tAJGk1MZ1KaNDP06vg7\nY25hX42sdj6K7L4Bk5o8gHxtc/IsheSeUFbdqbFdiAzTxgHq2zi1ZRPaxtNuw1Wk\nKPxcehMpXl/eKCY50+bkVUTvBtfPjRat0fSZnQ4X24zHcAECQQDtU1S/Lu/7vfKI\nBR9P2VoCfJvGuwpMcoaXcJuH9oEbeGKnSd7cKVeZdtuapHFjAm/yPWveOYmjrg6a\nCiPIgWoBAkEA35hIN/f6wzpLiKPB1TERO/YH1qrRKoM17Y7qcqh8pjmfgY/8we6m\naGrFPd2eUVEpo5XMhQVpsluHmG8ZbXvK2QJAUlfueKM9ixg91WoJkjf03hYEKrDt\nAtdd0Z+1pzglVbWwbSDZXYROq6WsznwuB09qLh+XlLRcCFm1IUdRYRleAQJAWQI9\nFZKxD5CgSwetfNnom28IlcswMvVCvYvcBsLNxDpCJgiUvPrs4bpHRKZ5hLODmOxk\nGzwZZHgNVYA8phnWmQJAER8blPRwsHaEUdPLKWPffvlGPh8RJwpWtaneBOhkyylh\nHbPOBvC2WGJ7uXYTiXPHwOeLyRtUYx2GaoKQImi3sw==\n-----END RSA PRIVATE KEY-----\n"
  },
  {
    "path": "ch07/bookmarkapi/keys/app.rsa.pub",
    "content": "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDPSMNALgfEMEDbS3kCLiTlpx0S\n4tZH1jZLcGF5Pjhc9IuEIf7p6obYT1W7urDPWM8JGO1mdx+GnJCnPcvFSsX8FjGw\nDqIp7afTdislYCJwQLXL7qPzwvG7ZlrtXrC9+0xkDGNxB+5Cui++8gWGbfTpTZiC\niP413esxVQ30btKk2QIDAQAB\n-----END PUBLIC KEY-----\n"
  },
  {
    "path": "ch07/bookmarkapi/main.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\t\"net/http\"\n\n\t\"github.com/shijuvar/go-recipes/ch07/bookmarkapi/common\"\n\t\"github.com/shijuvar/go-recipes/ch07/bookmarkapi/routers\"\n)\n\n// Entry point of the program\nfunc main() {\n\n\t// Calls startup logic\n\tcommon.StartUp()\n\t// Get the mux router object\n\trouter := routers.InitRoutes()\n\t// Create the Server\n\tserver := &http.Server{\n\t\tAddr:    common.AppConfig.Server,\n\t\tHandler: router,\n\t}\n\tlog.Println(\"Listening...\")\n\t// Running the HTTP Server\n\tserver.ListenAndServe()\n}\n"
  },
  {
    "path": "ch07/bookmarkapi/model/models.go",
    "content": "package model\n\nimport (\n\t\"time\"\n\n\t\"gopkg.in/mgo.v2/bson\"\n)\n\ntype (\n\t// User type represents the registered user.\n\tUser struct {\n\t\tID           bson.ObjectId `bson:\"_id,omitempty\" json:\"id\"`\n\t\tFirstName    string        `json:\"firstname\"`\n\t\tLastName     string        `json:\"lastname\"`\n\t\tEmail        string        `json:\"email\"`\n\t\tHashPassword []byte        `json:\"hashpassword,omitempty\"`\n\t}\n\t// Bookmark type represents the metadata of a bookmark.\n\tBookmark struct {\n\t\tID          bson.ObjectId `bson:\"_id,omitempty\"`\n\t\tName        string        `json:\"name\"`\n\t\tDescription string        `json:\"description\"`\n\t\tLocation    string        `json:\"location\"`\n\t\tPriority    int           `json:\"priority\"` // Priority (1 -5)\n\t\tCreatedBy   string        `json:\"createdby\"`\n\t\tCreatedOn   time.Time     `json:\"createdon,omitempty\"`\n\t\tTags        []string      `json:\"tags,omitempty\"`\n\t}\n)\n"
  },
  {
    "path": "ch07/bookmarkapi/routers/bookmark.go",
    "content": "package routers\n\nimport (\n\t\"github.com/gorilla/mux\"\n\n\t\"github.com/shijuvar/go-recipes/ch07/bookmarkapi/common\"\n\t\"github.com/shijuvar/go-recipes/ch07/bookmarkapi/controllers\"\n)\n\n// SetBookmarkRoutes registers routes for bookmark entity.\nfunc SetBookmarkRoutes(router *mux.Router) *mux.Router {\n\tbookmarkRouter := mux.NewRouter()\n\tbookmarkRouter.HandleFunc(\"/bookmarks\", controllers.CreateBookmark).Methods(\"POST\")\n\tbookmarkRouter.HandleFunc(\"/bookmarks/{id}\", controllers.UpdateBookmark).Methods(\"PUT\")\n\tbookmarkRouter.HandleFunc(\"/bookmarks\", controllers.GetBookmarks).Methods(\"GET\")\n\tbookmarkRouter.HandleFunc(\"/bookmarks/{id}\", controllers.GetBookmarkByID).Methods(\"GET\")\n\tbookmarkRouter.HandleFunc(\"/bookmarks/users/{id}\", controllers.GetBookmarksByUser).Methods(\"GET\")\n\tbookmarkRouter.HandleFunc(\"/bookmarks/{id}\", controllers.DeleteBookmark).Methods(\"DELETE\")\n\trouter.PathPrefix(\"/bookmarks\").Handler(common.AuthorizeRequest(bookmarkRouter))\n\treturn router\n}\n"
  },
  {
    "path": "ch07/bookmarkapi/routers/routers.go",
    "content": "package routers\n\nimport (\n\t\"github.com/gorilla/mux\"\n)\n\n// InitRoutes registers all routes for the application.\nfunc InitRoutes() *mux.Router {\n\trouter := mux.NewRouter().StrictSlash(false)\n\t// Routes for the User entity\n\trouter = SetUserRoutes(router)\n\t// Routes for the Bookmark entity\n\trouter = SetBookmarkRoutes(router)\n\treturn router\n}\n"
  },
  {
    "path": "ch07/bookmarkapi/routers/user.go",
    "content": "package routers\n\nimport (\n\t\"github.com/shijuvar/go-recipes/ch07/bookmarkapi/controllers\"\n\n\t\"github.com/gorilla/mux\"\n)\n\n// SetUserRoutes registers routes for user entity\nfunc SetUserRoutes(router *mux.Router) *mux.Router {\n\trouter.HandleFunc(\"/users\", controllers.Register).Methods(\"POST\")\n\trouter.HandleFunc(\"/users/login\", controllers.Login).Methods(\"POST\")\n\treturn router\n}\n"
  },
  {
    "path": "ch07/bookmarkapi/store/bookmark_store.go",
    "content": "package store\n\nimport (\n\t\"time\"\n\n\t\"gopkg.in/mgo.v2\"\n\t\"gopkg.in/mgo.v2/bson\"\n\n\t\"github.com/shijuvar/go-recipes/ch07/bookmarkapi/model\"\n)\n\n// BookmarkStore provides CRUD operations against the collection \"bookmarks\".\ntype BookmarkStore struct {\n\tC *mgo.Collection\n}\n\n// Create inserts the value of struct Bookmark into collection.\nfunc (store BookmarkStore) Create(b *model.Bookmark) error {\n\t// Assign a new bson.ObjectId\n\tb.ID = bson.NewObjectId()\n\tb.CreatedOn = time.Now()\n\terr := store.C.Insert(b)\n\treturn err\n}\n\n// Update modifies an existing document of a collection.\nfunc (store BookmarkStore) Update(b model.Bookmark) error {\n\t// partial update on MogoDB\n\terr := store.C.Update(bson.M{\"_id\": b.ID},\n\t\tbson.M{\"$set\": bson.M{\n\t\t\t\"name\":        b.Name,\n\t\t\t\"description\": b.Description,\n\t\t\t\"location\":    b.Location,\n\t\t\t\"priority\":    b.Priority,\n\t\t\t\"tags\":        b.Tags,\n\t\t}})\n\treturn err\n}\n\n// Delete removes an existing document from the collection.\nfunc (store BookmarkStore) Delete(id string) error {\n\terr := store.C.Remove(bson.M{\"_id\": bson.ObjectIdHex(id)})\n\treturn err\n}\n\n// GetAll returns all documents from the collection.\nfunc (store BookmarkStore) GetAll() []model.Bookmark {\n\tvar b []model.Bookmark\n\titer := store.C.Find(nil).Sort(\"priority\", \"-createdon\").Iter()\n\tresult := model.Bookmark{}\n\tfor iter.Next(&result) {\n\t\tb = append(b, result)\n\t}\n\treturn b\n}\n\n// GetByUser returns all documents from the collection.\nfunc (store BookmarkStore) GetByUser(user string) []model.Bookmark {\n\tvar b []model.Bookmark\n\titer := store.C.Find(bson.M{\"createdby\": user}).Sort(\"priority\", \"-createdon\").Iter()\n\tresult := model.Bookmark{}\n\tfor iter.Next(&result) {\n\t\tb = append(b, result)\n\t}\n\treturn b\n}\n\n// GetByID returns a single document from the collection.\nfunc (store BookmarkStore) GetByID(id string) (model.Bookmark, error) {\n\tvar b model.Bookmark\n\terr := store.C.FindId(bson.ObjectIdHex(id)).One(&b)\n\treturn b, err\n}\n\n// GetByTag returns all documents from the collection filtering by tags.\nfunc (store BookmarkStore) GetByTag(tags []string) []model.Bookmark {\n\tvar b []model.Bookmark\n\titer := store.C.Find(bson.M{\"tags\": bson.M{\"$in\": tags}}).Sort(\"priority\", \"-createdon\").Iter()\n\tresult := model.Bookmark{}\n\tfor iter.Next(&result) {\n\t\tb = append(b, result)\n\t}\n\treturn b\n}\n"
  },
  {
    "path": "ch07/bookmarkapi/store/user_store.go",
    "content": "package store\n\nimport (\n\t\"golang.org/x/crypto/bcrypt\"\n\t\"gopkg.in/mgo.v2\"\n\t\"gopkg.in/mgo.v2/bson\"\n\n\t\"github.com/shijuvar/go-recipes/ch07/bookmarkapi/model\"\n)\n\n// UserStore provides persistence logic for \"users\" collection.\ntype UserStore struct {\n\tC *mgo.Collection\n}\n\n// Create insert new User\nfunc (store UserStore) Create(user model.User, password string) error {\n\n\tuser.ID = bson.NewObjectId()\n\thpass, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)\n\tif err != nil {\n\t\treturn err\n\t}\n\tuser.HashPassword = hpass\n\terr = store.C.Insert(user)\n\treturn err\n}\n\n// Login authenticates the User\nfunc (store UserStore) Login(email, password string) (model.User, error) {\n\tvar user model.User\n\terr := store.C.Find(bson.M{\"email\": email}).One(&user)\n\tif err != nil {\n\t\treturn model.User{}, err\n\t}\n\t// Validate password\n\terr = bcrypt.CompareHashAndPassword(user.HashPassword, []byte(password))\n\tif err != nil {\n\t\treturn model.User{}, err\n\t}\n\treturn user, nil\n}\n"
  },
  {
    "path": "ch07/customhandler/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n)\n\ntype textHandler struct {\n\tresponseText string\n}\n\nfunc (th *textHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {\n\tfmt.Fprintf(w, th.responseText)\n}\n\ntype indexHandler struct {\n}\n\nfunc (ih *indexHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {\n\tw.Header().Set(\n\t\t\"Content-Type\",\n\t\t\"text/html\",\n\t)\n\thtml :=\n\t\t`<doctype html>\n        <html>\n\t<head>\n\t\t<title>Hello Gopher</title>\n\t</head>\n\t<body>\n\t\t<b>Hello Gopher!</b>\n        <p>\n          <a href=\"/welcome\">Welcome</a> |  <a href=\"/message\">Message</a>\n        </p>\n\t</body>\n</html>`\n\tfmt.Fprintf(w, html)\n\n}\n\nfunc main() {\n\tmux := http.NewServeMux()\n\tmux.Handle(\"/\", &indexHandler{})\n\n\tthWelcome := &textHandler{\"Welcome to Go Web Programming\"}\n\tmux.Handle(\"/welcome\", thWelcome)\n\n\tthMessage := &textHandler{\"net/http package is used to build web apps\"}\n\tmux.Handle(\"/message\", thMessage)\n\n\tlog.Println(\"Listening...\")\n\thttp.ListenAndServe(\":8080\", mux)\n}\n"
  },
  {
    "path": "ch07/defaultservemux/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n)\n\nfunc index(w http.ResponseWriter, r *http.Request) {\n\tw.Header().Set(\n\t\t\"Content-Type\",\n\t\t\"text/html\",\n\t)\n\thtml :=\n\t\t`<doctype html>\n        <html>\n\t<head>\n\t\t<title>Hello Gopher</title>\n\t</head>\n\t<body>\n\t\t<b>Hello Gopher!</b>\n        <p>\n            <a href=\"/welcome\">Welcome</a> |  <a href=\"/message\">Message</a>\n        </p>\n\t</body>\n</html>`\n\tfmt.Fprintf(w, html)\n}\n\nfunc welcome(w http.ResponseWriter, r *http.Request) {\n\tfmt.Fprintf(w, \"Welcome to Go Web Programming\")\n}\nfunc message(w http.ResponseWriter, r *http.Request) {\n\tfmt.Fprintf(w, \"net/http package is used to build web apps\")\n}\n\nfunc main() {\n\thttp.HandleFunc(\"/\", index)\n\thttp.HandleFunc(\"/welcome\", welcome)\n\thttp.HandleFunc(\"/message\", message)\n\tlog.Println(\"Listening...\")\n\thttp.ListenAndServe(\":8080\", nil)\n}\n"
  },
  {
    "path": "ch07/handlefunc/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n)\n\nfunc index(w http.ResponseWriter, r *http.Request) {\n\tw.Header().Set(\n\t\t\"Content-Type\",\n\t\t\"text/html\",\n\t)\n\thtml :=\n\t\t`<doctype html>\n        <html>\n\t<head>\n\t\t<title>Hello Gopher</title>\n\t</head>\n\t<body>\n\t\t<b>Hello Gopher!</b>\n        <p>\n            <a href=\"/welcome\">Welcome</a> |  <a href=\"/message\">Message</a>\n        </p>\n\t</body>\n</html>`\n\tfmt.Fprintf(w, html)\n}\n\nfunc welcome(w http.ResponseWriter, r *http.Request) {\n\tfmt.Fprintf(w, \"Welcome to Go Web Programming\")\n}\nfunc message(w http.ResponseWriter, r *http.Request) {\n\tfmt.Fprintf(w, \"net/http package is used to build web apps\")\n}\n\nfunc main() {\n\tmux := http.NewServeMux()\n\tmux.HandleFunc(\"/\", index)\n\tmux.HandleFunc(\"/welcome\", welcome)\n\tmux.HandleFunc(\"/message\", message)\n\tlog.Println(\"Listening...\")\n\thttp.ListenAndServe(\":8080\", mux)\n}\n"
  },
  {
    "path": "ch07/handlerfunc/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n)\n\nfunc textResponseHandler(resposeText string) http.Handler {\n\treturn http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tfmt.Fprintf(w, resposeText)\n\t})\n}\nfunc index(w http.ResponseWriter, r *http.Request) {\n\tw.Header().Set(\n\t\t\"Content-Type\",\n\t\t\"text/html\",\n\t)\n\thtml :=\n\t\t`<doctype html>\n        <html>\n\t<head>\n\t\t<title>Hello Gopher</title>\n\t</head>\n\t<body>\n\t\t<b>Hello Gopher!</b>\n        <p>\n            <a href=\"/welcome\">Welcome</a> |  <a href=\"/message\">Message</a>\n        </p>\n\t</body>\n</html>`\n\tfmt.Fprintf(w, html)\n}\n\nfunc welcome(w http.ResponseWriter, r *http.Request) {\n\tfmt.Fprintf(w, \"Welcome to Go Web Programming\")\n}\nfunc message(w http.ResponseWriter, r *http.Request) {\n\tfmt.Fprintf(w, \"net/http package is used to build web apps\")\n}\n\nfunc main() {\n\tmux := http.NewServeMux()\n\tmux.Handle(\"/\", http.HandlerFunc(index))\n\tmux.Handle(\"/welcome\", http.HandlerFunc(welcome))\n\tmux.Handle(\"/message\", http.HandlerFunc(message))\n\t//mux.Handle(\"/welcome\", textResponseHandler(\"Welcome to Go Web Programming\"))\n\t//mux.Handle(\"/message\", textResponseHandler(\"net/http package is used to build web apps\"))\n\n\tlog.Println(\"Listening...\")\n\thttp.ListenAndServe(\":8080\", mux)\n}\n"
  },
  {
    "path": "ch07/httpserver/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n)\n\nfunc handler(w http.ResponseWriter, r *http.Request) {\n\tfmt.Fprint(w, \"Hello, world!\")\n}\n\nfunc main() {\n\thttp.HandleFunc(\"/\", handler)\n\thttp.ListenAndServe(\":8080\", nil)\n}\n"
  },
  {
    "path": "ch07/middleware/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\t\"time\"\n)\n\n// loggingHandler is an HTTP Middleware that logs HTTP requests.\nfunc loggingHandler(next http.Handler) http.Handler {\n\treturn http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t// Middleware logic before executing given Handler\n\t\tstart := time.Now()\n\t\tlog.Printf(\"Started %s %s\", r.Method, r.URL.Path)\n\t\tnext.ServeHTTP(w, r)\n\t\t// Middleware logic after executing given Handler\n\t\tlog.Printf(\"Completed %s in %v\", r.URL.Path, time.Since(start))\n\t})\n}\n\nfunc index(w http.ResponseWriter, r *http.Request) {\n\tw.Header().Set(\n\t\t\"Content-Type\",\n\t\t\"text/html\",\n\t)\n\thtml :=\n\t\t`<doctype html>\n        <html>\n\t<head>\n\t\t<title>Hello Gopher</title>\n\t</head>\n\t<body>\n\t\t<b>Hello Gopher!</b>\n        <p>\n            <a href=\"/welcome\">Welcome</a> |  <a href=\"/message\">Message</a>\n        </p>\n\t</body>\n</html>`\n\tfmt.Fprintf(w, html)\n}\n\nfunc welcome(w http.ResponseWriter, r *http.Request) {\n\tfmt.Fprintf(w, \"Welcome to Go Web Programming\")\n}\nfunc message(w http.ResponseWriter, r *http.Request) {\n\tfmt.Fprintf(w, \"net/http package is used to build web apps\")\n}\nfunc favicon(w http.ResponseWriter, r *http.Request) {\n}\n\nfunc main() {\n\thttp.HandleFunc(\"/favicon.ico\", favicon)\n\thttp.Handle(\"/\", loggingHandler(http.HandlerFunc(index)))\n\thttp.Handle(\"/welcome\", loggingHandler(http.HandlerFunc(welcome)))\n\thttp.Handle(\"/message\", loggingHandler(http.HandlerFunc(message)))\n\tlog.Println(\"Listening...\")\n\thttp.ListenAndServe(\":8080\", nil)\n}\n"
  },
  {
    "path": "ch07/server/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\t\"time\"\n)\n\nfunc index(w http.ResponseWriter, r *http.Request) {\n\tfmt.Fprintf(w, \"Welcome to Go Web Programming\")\n}\n\nfunc main() {\n\n\thttp.HandleFunc(\"/\", index)\n\n\tserver := &http.Server{\n\t\tAddr:         \":8080\",\n\t\tReadTimeout:  60 * time.Second,\n\t\tWriteTimeout: 60 * time.Second,\n\t}\n\n\tlog.Println(\"Listening...\")\n\tserver.ListenAndServe()\n}\n"
  },
  {
    "path": "ch08/calc/calc.go",
    "content": "// Package calc provides a simple calculator\npackage calc\n\nimport \"math\"\n\n// Sum returns sum of integer values\nfunc Sum(nums ...int) int {\n\tresult := 0\n\tfor _, v := range nums {\n\t\tresult += v\n\t}\n\treturn result\n}\n\n// Average returns average of integer values\n// The output provides a float64 value in two decimal points\nfunc Average(nums ...int) float64 {\n\tsum := 0\n\tfor _, v := range nums {\n\t\tsum += v\n\t}\n\tresult := float64(sum) / float64(len(nums))\n\tpow := math.Pow(10, float64(2))\n\tdigit := pow * result\n\tround := math.Floor(digit)\n\treturn round / pow\n\n}\n"
  },
  {
    "path": "ch08/calc/calc_test.go",
    "content": "package calc\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n)\n\n// Test case for the function Sum\nfunc TestSum(t *testing.T) {\n\tinput, expected := []int{7, 8, 10}, 25\n\tresult := Sum(input...)\n\tif result != expected {\n\n\t\tt.Errorf(\"Result: %d, Expected: %d\", result, expected)\n\t}\n\n}\n\n// Test case for function Average\nfunc TestAverage(t *testing.T) {\n\tinput, expected := []int{7, 8, 10}, 8.33\n\tresult := Average(input...)\n\tif result != expected {\n\n\t\tt.Errorf(\"Result: %f, Expected: %f\", result, expected)\n\t}\n}\n\n// Benchmark for function Sum\nfunc BenchmarkSum(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tSum(7, 8, 10)\n\t}\n}\n\n// Benchmark for function Average\nfunc BenchmarkAverage(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tAverage(7, 8, 10)\n\t}\n}\n\nfunc TestLongRun(t *testing.T) {\n\t// Checks whether the short flag is provided\n\tif testing.Short() {\n\t\tt.Skip(\"Skipping test in short mode\")\n\t}\n\t// Long running implementation goes here\n\ttime.Sleep(5 * time.Second)\n}\n\n// Test case for the function Sum to be executed in parallel\nfunc TestSumInParallel(t *testing.T) {\n\tt.Parallel()\n\t// Delaying 1 second for the sake of demonstration\n\ttime.Sleep(1 * time.Second)\n\tinput, expected := []int{7, 8, 10}, 25\n\tresult := Sum(input...)\n\tif result != expected {\n\n\t\tt.Errorf(\"Result: %d, Expected: %d\", result, expected)\n\t}\n\n}\n\n// Test case for the function Sum to be executed in parallel\nfunc TestAverageInParallel(t *testing.T) {\n\tt.Parallel()\n\t// Delaying 1 second for the sake of demonstration\n\ttime.Sleep(2 * time.Second)\n\tinput, expected := []int{7, 8, 10}, 8.33\n\tresult := Average(input...)\n\tif result != expected {\n\n\t\tt.Errorf(\"Result: %f, Expected: %f\", result, expected)\n\t}\n}\n\n// Example code for function Sum\nfunc ExampleSum() {\n\tfmt.Println(Sum(7, 8, 10))\n\t// Output: 25\n}\n\n// Example code for function Average\nfunc ExampleAverage() {\n\tfmt.Println(Average(7, 8, 10))\n\t// Output: 8.33\n}\n"
  },
  {
    "path": "ch08/httpbdd/controllers/controllers_suite_test.go",
    "content": "package controllers_test\n\nimport (\n\t. \"github.com/onsi/ginkgo\"\n\t. \"github.com/onsi/gomega\"\n\n\t\"testing\"\n)\n\nfunc TestControllers(t *testing.T) {\n\tRegisterFailHandler(Fail)\n\tRunSpecs(t, \"Controllers Suite\")\n}\n"
  },
  {
    "path": "ch08/httpbdd/controllers/user_controller.go",
    "content": "package controllers\n\nimport (\n\t\"encoding/json\"\n\t\"log\"\n\t\"net/http\"\n\n\t\"github.com/shijuvar/go-recipes/ch08/httpbdd/model\"\n)\n\n// GetUsers serves requests for Http Get to \"/users\"\nfunc GetUsers(store model.UserStore) http.Handler {\n\treturn http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tdata := store.GetUsers()\n\t\tusers, err := json.Marshal(data)\n\t\tif err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\treturn\n\t\t}\n\t\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t\tw.WriteHeader(http.StatusOK)\n\t\tw.Write(users)\n\t})\n\n}\n\n// CreateUser serves requests for Http Post to \"/users\"\nfunc CreateUser(store model.UserStore) http.Handler {\n\treturn http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tvar user model.User\n\t\t// Decode the incoming User json\n\t\terr := json.NewDecoder(r.Body).Decode(&user)\n\t\tif err != nil {\n\t\t\tlog.Fatalf(\"[Controllers.CreateUser]: %s\\n\", err)\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\treturn\n\t\t}\n\t\t// Insert User entity into User Store\n\t\terr = store.AddUser(user)\n\t\tif err != nil {\n\t\t\tif err == model.ErrorEmailExists {\n\t\t\t\tw.WriteHeader(http.StatusBadRequest)\n\t\t\t} else {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tw.WriteHeader(http.StatusCreated)\n\t})\n}\n"
  },
  {
    "path": "ch08/httpbdd/controllers/user_controller_test.go",
    "content": "package controllers_test\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"strings\"\n\n\t\"github.com/shijuvar/go-recipes/ch08/httpbdd/controllers\"\n\t\"github.com/shijuvar/go-recipes/ch08/httpbdd/model\"\n\n\t\"github.com/gorilla/mux\"\n\t. \"github.com/onsi/ginkgo\"\n\t. \"github.com/onsi/gomega\"\n)\n\nvar _ = Describe(\"UserController\", func() {\n\tvar r *mux.Router\n\tvar w *httptest.ResponseRecorder\n\tvar store *FakeUserStore\n\tBeforeEach(func() {\n\t\tr = mux.NewRouter()\n\t\tstore = newFakeUserStore()\n\t})\n\n\t// Specs for HTTP Get to \"/users\"\n\tDescribe(\"Get list of Users\", func() {\n\t\tContext(\"Get all Users from data store\", func() {\n\t\t\tIt(\"Should get list of Users\", func() {\n\t\t\t\tr.Handle(\"/users\", controllers.GetUsers(store)).Methods(\"GET\")\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/users\", nil)\n\t\t\t\tExpect(err).NotTo(HaveOccurred())\n\t\t\t\tw = httptest.NewRecorder()\n\t\t\t\tr.ServeHTTP(w, req)\n\t\t\t\tExpect(w.Code).To(Equal(200))\n\t\t\t\tvar users []model.User\n\t\t\t\tjson.Unmarshal(w.Body.Bytes(), &users)\n\t\t\t\t// Verifying mocked data of 2 users\n\t\t\t\tExpect(len(users)).To(Equal(2))\n\t\t\t})\n\t\t})\n\t})\n\n\t// Specs for HTTP Post to \"/users\"\n\tDescribe(\"Post a new User\", func() {\n\t\tContext(\"Provide a valid User data\", func() {\n\t\t\tIt(\"Should create a new User and get HTTP Status: 201\", func() {\n\t\t\t\tr.Handle(\"/users\", controllers.CreateUser(store)).Methods(\"POST\")\n\t\t\t\tuserJson := `{\"firstname\": \"Alex\", \"lastname\": \"John\", \"email\": \"alex@xyz.com\"}`\n\n\t\t\t\treq, err := http.NewRequest(\n\t\t\t\t\t\"POST\",\n\t\t\t\t\t\"/users\",\n\t\t\t\t\tstrings.NewReader(userJson),\n\t\t\t\t)\n\t\t\t\tExpect(err).NotTo(HaveOccurred())\n\t\t\t\tw = httptest.NewRecorder()\n\t\t\t\tr.ServeHTTP(w, req)\n\t\t\t\tExpect(w.Code).To(Equal(201))\n\t\t\t})\n\t\t})\n\t\tContext(\"Provide a User data that contains duplicate email id\", func() {\n\t\t\tIt(\"Should get HTTP Status: 400\", func() {\n\t\t\t\tr.Handle(\"/users\", controllers.CreateUser(store)).Methods(\"POST\")\n\t\t\t\tuserJson := `{\"firstname\": \"Shiju\", \"lastname\": \"Varghese\", \"email\": \"shiju@xyz.com\"}`\n\n\t\t\t\treq, err := http.NewRequest(\n\t\t\t\t\t\"POST\",\n\t\t\t\t\t\"/users\",\n\t\t\t\t\tstrings.NewReader(userJson),\n\t\t\t\t)\n\t\t\t\tExpect(err).NotTo(HaveOccurred())\n\t\t\t\tw = httptest.NewRecorder()\n\t\t\t\tr.ServeHTTP(w, req)\n\t\t\t\tExpect(w.Code).To(Equal(400))\n\t\t\t})\n\t\t})\n\t})\n})\n\n// FakeUserStore provides a mocked implementation of interface model.UserStore\ntype FakeUserStore struct {\n\tuserStore []model.User\n}\n\n// GetUsers returns all users\nfunc (store *FakeUserStore) GetUsers() []model.User {\n\treturn store.userStore\n}\n\n// AddUser inserts a User\nfunc (store *FakeUserStore) AddUser(user model.User) error {\n\t// Check whether email is exists\n\tfor _, u := range store.userStore {\n\t\tif u.Email == user.Email {\n\t\t\treturn model.ErrorEmailExists\n\t\t}\n\t}\n\tstore.userStore = append(store.userStore, user)\n\treturn nil\n}\n\n// newFakeUserStore provides two dummy data for Users\nfunc newFakeUserStore() *FakeUserStore {\n\tstore := &FakeUserStore{}\n\tstore.AddUser(model.User{\n\t\tFirstName: \"Shiju\",\n\t\tLastName:  \"Varghese\",\n\t\tEmail:     \"shiju@xyz.com\",\n\t})\n\n\tstore.AddUser(model.User{\n\t\tFirstName: \"Irene\",\n\t\tLastName:  \"Rose\",\n\t\tEmail:     \"irene@xyz.com\",\n\t})\n\treturn store\n}\n"
  },
  {
    "path": "ch08/httpbdd/main.go",
    "content": "package main\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/gorilla/mux\"\n\n\t\"github.com/shijuvar/go-recipes/ch08/httpbdd/controllers\"\n\t\"github.com/shijuvar/go-recipes/ch08/httpbdd/store\"\n)\n\nfunc setUserRoutes() *mux.Router {\n\tr := mux.NewRouter()\n\tuserStore := &store.MongoUserStore{}\n\tr.Handle(\"/users\", controllers.CreateUser(userStore)).Methods(\"POST\")\n\tr.Handle(\"/users\", controllers.GetUsers(userStore)).Methods(\"GET\")\n\treturn r\n}\n\nfunc main() {\n\thttp.ListenAndServe(\":8080\", setUserRoutes())\n}\n"
  },
  {
    "path": "ch08/httpbdd/model/user.go",
    "content": "package model\n\nimport \"errors\"\n\n// ErrorEmailExists is an error value for duplicate email id\nvar ErrorEmailExists = errors.New(\"Email Id is exists\")\n\n// User model\ntype User struct {\n\tFirstName string `json:\"firstname\"`\n\tLastName  string `json:\"lastname\"`\n\tEmail     string `json:\"email\"`\n}\n\n// UserStore provides a contract for Data Store for User entity\ntype UserStore interface {\n\tGetUsers() []User\n\tAddUser(User) error\n}\n"
  },
  {
    "path": "ch08/httpbdd/store/user_store.go",
    "content": "package store\n\nimport (\n\t\"log\"\n\t\"time\"\n\n\t\"gopkg.in/mgo.v2\"\n\t\"gopkg.in/mgo.v2/bson\"\n\n\t\"github.com/shijuvar/go-recipes/ch08/httpbdd/model\"\n)\n\n// MongoDB Session\nvar mgoSession *mgo.Session\n\n// Create a MongoDB Session\nfunc createDBSession() {\n\tvar err error\n\tmgoSession, err = mgo.DialWithInfo(&mgo.DialInfo{\n\t\tAddrs:   []string{\"127.0.0.1\"},\n\t\tTimeout: 60 * time.Second,\n\t})\n\tif err != nil {\n\t\tlog.Fatalf(\"[createDbSession]: %s\\n\", err)\n\t}\n}\n\n// Initializes the MongoDB Session\nfunc init() {\n\tcreateDBSession()\n}\n\n// MongoUserStore provides persistence logic for \"users\" collection.\ntype MongoUserStore struct{}\n\n// AddUser insert new User\nfunc (store *MongoUserStore) AddUser(user model.User) error {\n\tsession := mgoSession.Copy()\n\tdefer session.Close()\n\tuserCol := session.DB(\"userdb\").C(\"users\")\n\t// Check whether email id is exists or not\n\tvar existUser model.User\n\terr := userCol.Find(bson.M{\"email\": user.Email}).One(&existUser)\n\tif err != nil {\n\t\tif err == mgo.ErrNotFound { // Email is unique, no records found\n\t\t}\n\t}\n\tif (model.User{}) != existUser { // there is a user\n\t\treturn model.ErrorEmailExists\n\t}\n\terr = userCol.Insert(user)\n\treturn err\n}\n\n// GetUsers returns all documents from the collection.\nfunc (store *MongoUserStore) GetUsers() []model.User {\n\tsession := mgoSession.Copy()\n\tdefer session.Close()\n\tuserCol := session.DB(\"userdb\").C(\"users\")\n\tvar users []model.User\n\titer := userCol.Find(nil).Iter()\n\tresult := model.User{}\n\tfor iter.Next(&result) {\n\t\tusers = append(users, result)\n\t}\n\treturn users\n}\n"
  },
  {
    "path": "ch08/httptest/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\n\t\"github.com/gorilla/mux\"\n)\n\n// User model\ntype User struct {\n\tFirstName string `json:\"firstname\"`\n\tLastName  string `json:\"lastname\"`\n\tEmail     string `json:\"email\"`\n}\n\n// getUsers serves requests for Http Get to \"/users\"\nfunc getUsers(w http.ResponseWriter, r *http.Request) {\n\tdata := []User{\n\t\tUser{\n\t\t\tFirstName: \"Shiju\",\n\t\t\tLastName:  \"Varghese\",\n\t\t\tEmail:     \"shiju@xyz.com\",\n\t\t},\n\n\t\tUser{\n\t\t\tFirstName: \"Irene\",\n\t\t\tLastName:  \"Rose\",\n\t\t\tEmail:     \"irene@xyz.com\",\n\t\t},\n\t}\n\tusers, err := json.Marshal(data)\n\tif err != nil {\n\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\treturn\n\t}\n\tw.Header().Set(\"Content-Type\", \"application/json\")\n\tw.WriteHeader(http.StatusOK)\n\tw.Write(users)\n}\n\nfunc main() {\n\tr := mux.NewRouter()\n\tr.HandleFunc(\"/users\", getUsers).Methods(\"GET\")\n\thttp.ListenAndServe(\":8080\", r)\n}\n"
  },
  {
    "path": "ch08/httptest/main_test.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/gorilla/mux\"\n)\n\n// TestGetUsers test HTTP Get to \"/users\" using ResponseRecorder\nfunc TestGetUsers(t *testing.T) {\n\tr := mux.NewRouter()\n\tr.HandleFunc(\"/users\", getUsers).Methods(\"GET\")\n\treq, err := http.NewRequest(\"GET\", \"/users\", nil)\n\tif err != nil {\n\t\tt.Error(err)\n\t}\n\tw := httptest.NewRecorder()\n\n\tr.ServeHTTP(w, req)\n\tif w.Code != 200 {\n\t\tt.Errorf(\"HTTP Status expected: 200, got: %d\", w.Code)\n\t}\n}\n\n// TestGetUsersWithServer test HTTP Get to \"/users\" using Server\nfunc TestGetUsersWithServer(t *testing.T) {\n\tr := mux.NewRouter()\n\tr.HandleFunc(\"/users\", getUsers).Methods(\"GET\")\n\tserver := httptest.NewServer(r)\n\tdefer server.Close()\n\tusersURL := fmt.Sprintf(\"%s/users\", server.URL)\n\trequest, err := http.NewRequest(\"GET\", usersURL, nil)\n\n\tres, err := http.DefaultClient.Do(request)\n\n\tif err != nil {\n\t\tt.Error(err)\n\t}\n\n\tif res.StatusCode != 200 {\n\t\tt.Errorf(\"HTTP Status expected: 200, got: %d\", res.StatusCode)\n\t}\n}\n"
  },
  {
    "path": "grpc/client/main.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"log\"\n\n\t\"golang.org/x/net/context\"\n\t\"google.golang.org/grpc\"\n\n\tpb \"github.com/shijuvar/go-recipes/grpc/customer\"\n)\n\nconst (\n\taddress = \"localhost:50051\"\n)\n\n// createCustomer calls the RPC method CreateCustomer of CustomerServer\nfunc createCustomer(client pb.CustomerClient, customer *pb.CustomerRequest) {\n\tresp, err := client.CreateCustomer(context.Background(), customer)\n\tif err != nil {\n\t\tlog.Fatalf(\"Could not create Customer: %v\", err)\n\t}\n\tif resp.Success {\n\t\tlog.Printf(\"A new Customer has been added with id: %d\", resp.Id)\n\t}\n}\n\n// getCustomers calls the RPC method GetCustomers of CustomerServer\nfunc getCustomers(client pb.CustomerClient, filter *pb.CustomerFilter) {\n\t// calling the streaming API\n\tstream, err := client.GetCustomers(context.Background(), filter)\n\tif err != nil {\n\t\tlog.Fatalf(\"Error on get customers: %v\", err)\n\t}\n\tfor {\n\t\t// Receiving the stream of data \n\t\tcustomer, err := stream.Recv()\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t}\n\t\tif err != nil {\n\t\t\tlog.Fatalf(\"%v.GetCustomers(_) = _, %v\", client, err)\n\t\t}\n\t\tlog.Printf(\"Customer: %v\", customer)\n\t}\n}\nfunc main() {\n\t// Set up a connection to the gRPC server.\n\tconn, err := grpc.Dial(address, grpc.WithInsecure())\n\tif err != nil {\n\t\tlog.Fatalf(\"did not connect: %v\", err)\n\t}\n\tdefer conn.Close()\n\t// Creates a new CustomerClient\n\tclient := pb.NewCustomerClient(conn)\n\n\tcustomer := &pb.CustomerRequest{\n\t\tId:    101,\n\t\tName:  \"Shiju Varghese\",\n\t\tEmail: \"shiju@xyz.com\",\n\t\tPhone: \"732-757-2923\",\n\t\tAddresses: []*pb.CustomerRequest_Address{\n\t\t\t&pb.CustomerRequest_Address{\n\t\t\t\tStreet:            \"1 Mission Street\",\n\t\t\t\tCity:              \"San Francisco\",\n\t\t\t\tState:             \"CA\",\n\t\t\t\tZip:               \"94105\",\n\t\t\t\tIsShippingAddress: false,\n\t\t\t},\n\t\t\t&pb.CustomerRequest_Address{\n\t\t\t\tStreet:            \"Greenfield\",\n\t\t\t\tCity:              \"Kochi\",\n\t\t\t\tState:             \"KL\",\n\t\t\t\tZip:               \"68356\",\n\t\t\t\tIsShippingAddress: true,\n\t\t\t},\n\t\t},\n\t}\n\n\t// Create a new customer\n\tcreateCustomer(client, customer)\n\n\tcustomer = &pb.CustomerRequest{\n\t\tId:    102,\n\t\tName:  \"Irene Rose\",\n\t\tEmail: \"irene@xyz.com\",\n\t\tPhone: \"732-757-2924\",\n\t\tAddresses: []*pb.CustomerRequest_Address{\n\t\t\t&pb.CustomerRequest_Address{\n\t\t\t\tStreet:            \"1 Mission Street\",\n\t\t\t\tCity:              \"San Francisco\",\n\t\t\t\tState:             \"CA\",\n\t\t\t\tZip:               \"94105\",\n\t\t\t\tIsShippingAddress: true,\n\t\t\t},\n\t\t},\n\t}\n\n\t// Create a new customer\n\tcreateCustomer(client, customer)\n\t// Filter with an empty Keyword\n\tfilter := &pb.CustomerFilter{Keyword: \"\"}\n\tgetCustomers(client, filter)\n}\n"
  },
  {
    "path": "grpc/customer/customer.pb.go",
    "content": "// Code generated by protoc-gen-go.\n// source: customer.proto\n// DO NOT EDIT!\n\n/*\nPackage customer is a generated protocol buffer package.\n\nIt is generated from these files:\n\tcustomer.proto\n\nIt has these top-level messages:\n\tCustomerRequest\n\tCustomerResponse\n\tCustomerFilter\n*/\npackage customer\n\nimport proto \"github.com/golang/protobuf/proto\"\nimport fmt \"fmt\"\nimport math \"math\"\n\nimport (\n\tcontext \"golang.org/x/net/context\"\n\tgrpc \"google.golang.org/grpc\"\n)\n\n// Reference imports to suppress errors if they are not otherwise used.\nvar _ = proto.Marshal\nvar _ = fmt.Errorf\nvar _ = math.Inf\n\n// This is a compile-time assertion to ensure that this generated file\n// is compatible with the proto package it is being compiled against.\n// A compilation error at this line likely means your copy of the\n// proto package needs to be updated.\nconst _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package\n\n// Request message for creating a new customer\ntype CustomerRequest struct {\n\tId        int32                      `protobuf:\"varint,1,opt,name=id\" json:\"id,omitempty\"`\n\tName      string                     `protobuf:\"bytes,2,opt,name=name\" json:\"name,omitempty\"`\n\tEmail     string                     `protobuf:\"bytes,3,opt,name=email\" json:\"email,omitempty\"`\n\tPhone     string                     `protobuf:\"bytes,4,opt,name=phone\" json:\"phone,omitempty\"`\n\tAddresses []*CustomerRequest_Address `protobuf:\"bytes,5,rep,name=addresses\" json:\"addresses,omitempty\"`\n}\n\nfunc (m *CustomerRequest) Reset()                    { *m = CustomerRequest{} }\nfunc (m *CustomerRequest) String() string            { return proto.CompactTextString(m) }\nfunc (*CustomerRequest) ProtoMessage()               {}\nfunc (*CustomerRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }\n\nfunc (m *CustomerRequest) GetAddresses() []*CustomerRequest_Address {\n\tif m != nil {\n\t\treturn m.Addresses\n\t}\n\treturn nil\n}\n\ntype CustomerRequest_Address struct {\n\tStreet            string `protobuf:\"bytes,1,opt,name=street\" json:\"street,omitempty\"`\n\tCity              string `protobuf:\"bytes,2,opt,name=city\" json:\"city,omitempty\"`\n\tState             string `protobuf:\"bytes,3,opt,name=state\" json:\"state,omitempty\"`\n\tZip               string `protobuf:\"bytes,4,opt,name=zip\" json:\"zip,omitempty\"`\n\tIsShippingAddress bool   `protobuf:\"varint,5,opt,name=isShippingAddress\" json:\"isShippingAddress,omitempty\"`\n}\n\nfunc (m *CustomerRequest_Address) Reset()                    { *m = CustomerRequest_Address{} }\nfunc (m *CustomerRequest_Address) String() string            { return proto.CompactTextString(m) }\nfunc (*CustomerRequest_Address) ProtoMessage()               {}\nfunc (*CustomerRequest_Address) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0, 0} }\n\ntype CustomerResponse struct {\n\tId      int32 `protobuf:\"varint,1,opt,name=id\" json:\"id,omitempty\"`\n\tSuccess bool  `protobuf:\"varint,2,opt,name=success\" json:\"success,omitempty\"`\n}\n\nfunc (m *CustomerResponse) Reset()                    { *m = CustomerResponse{} }\nfunc (m *CustomerResponse) String() string            { return proto.CompactTextString(m) }\nfunc (*CustomerResponse) ProtoMessage()               {}\nfunc (*CustomerResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }\n\ntype CustomerFilter struct {\n\tKeyword string `protobuf:\"bytes,1,opt,name=keyword\" json:\"keyword,omitempty\"`\n}\n\nfunc (m *CustomerFilter) Reset()                    { *m = CustomerFilter{} }\nfunc (m *CustomerFilter) String() string            { return proto.CompactTextString(m) }\nfunc (*CustomerFilter) ProtoMessage()               {}\nfunc (*CustomerFilter) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }\n\nfunc init() {\n\tproto.RegisterType((*CustomerRequest)(nil), \"customer.CustomerRequest\")\n\tproto.RegisterType((*CustomerRequest_Address)(nil), \"customer.CustomerRequest.Address\")\n\tproto.RegisterType((*CustomerResponse)(nil), \"customer.CustomerResponse\")\n\tproto.RegisterType((*CustomerFilter)(nil), \"customer.CustomerFilter\")\n}\n\n// Reference imports to suppress errors if they are not otherwise used.\nvar _ context.Context\nvar _ grpc.ClientConn\n\n// This is a compile-time assertion to ensure that this generated file\n// is compatible with the grpc package it is being compiled against.\nconst _ = grpc.SupportPackageIsVersion3\n\n// Client API for Customer service\n\ntype CustomerClient interface {\n\t// Get all Customers with filter - A server-to-client streaming RPC.\n\tGetCustomers(ctx context.Context, in *CustomerFilter, opts ...grpc.CallOption) (Customer_GetCustomersClient, error)\n\t// Create a new Customer - A simple RPC\n\tCreateCustomer(ctx context.Context, in *CustomerRequest, opts ...grpc.CallOption) (*CustomerResponse, error)\n}\n\ntype customerClient struct {\n\tcc *grpc.ClientConn\n}\n\nfunc NewCustomerClient(cc *grpc.ClientConn) CustomerClient {\n\treturn &customerClient{cc}\n}\n\nfunc (c *customerClient) GetCustomers(ctx context.Context, in *CustomerFilter, opts ...grpc.CallOption) (Customer_GetCustomersClient, error) {\n\tstream, err := grpc.NewClientStream(ctx, &_Customer_serviceDesc.Streams[0], c.cc, \"/customer.Customer/GetCustomers\", opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx := &customerGetCustomersClient{stream}\n\tif err := x.ClientStream.SendMsg(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := x.ClientStream.CloseSend(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn x, nil\n}\n\ntype Customer_GetCustomersClient interface {\n\tRecv() (*CustomerRequest, error)\n\tgrpc.ClientStream\n}\n\ntype customerGetCustomersClient struct {\n\tgrpc.ClientStream\n}\n\nfunc (x *customerGetCustomersClient) Recv() (*CustomerRequest, error) {\n\tm := new(CustomerRequest)\n\tif err := x.ClientStream.RecvMsg(m); err != nil {\n\t\treturn nil, err\n\t}\n\treturn m, nil\n}\n\nfunc (c *customerClient) CreateCustomer(ctx context.Context, in *CustomerRequest, opts ...grpc.CallOption) (*CustomerResponse, error) {\n\tout := new(CustomerResponse)\n\terr := grpc.Invoke(ctx, \"/customer.Customer/CreateCustomer\", in, out, c.cc, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\n// Server API for Customer service\n\ntype CustomerServer interface {\n\t// Get all Customers with filter - A server-to-client streaming RPC.\n\tGetCustomers(*CustomerFilter, Customer_GetCustomersServer) error\n\t// Create a new Customer - A simple RPC\n\tCreateCustomer(context.Context, *CustomerRequest) (*CustomerResponse, error)\n}\n\nfunc RegisterCustomerServer(s *grpc.Server, srv CustomerServer) {\n\ts.RegisterService(&_Customer_serviceDesc, srv)\n}\n\nfunc _Customer_GetCustomers_Handler(srv interface{}, stream grpc.ServerStream) error {\n\tm := new(CustomerFilter)\n\tif err := stream.RecvMsg(m); err != nil {\n\t\treturn err\n\t}\n\treturn srv.(CustomerServer).GetCustomers(m, &customerGetCustomersServer{stream})\n}\n\ntype Customer_GetCustomersServer interface {\n\tSend(*CustomerRequest) error\n\tgrpc.ServerStream\n}\n\ntype customerGetCustomersServer struct {\n\tgrpc.ServerStream\n}\n\nfunc (x *customerGetCustomersServer) Send(m *CustomerRequest) error {\n\treturn x.ServerStream.SendMsg(m)\n}\n\nfunc _Customer_CreateCustomer_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(CustomerRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(CustomerServer).CreateCustomer(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/customer.Customer/CreateCustomer\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(CustomerServer).CreateCustomer(ctx, req.(*CustomerRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nvar _Customer_serviceDesc = grpc.ServiceDesc{\n\tServiceName: \"customer.Customer\",\n\tHandlerType: (*CustomerServer)(nil),\n\tMethods: []grpc.MethodDesc{\n\t\t{\n\t\t\tMethodName: \"CreateCustomer\",\n\t\t\tHandler:    _Customer_CreateCustomer_Handler,\n\t\t},\n\t},\n\tStreams: []grpc.StreamDesc{\n\t\t{\n\t\t\tStreamName:    \"GetCustomers\",\n\t\t\tHandler:       _Customer_GetCustomers_Handler,\n\t\t\tServerStreams: true,\n\t\t},\n\t},\n\tMetadata: fileDescriptor0,\n}\n\nfunc init() { proto.RegisterFile(\"customer.proto\", fileDescriptor0) }\n\nvar fileDescriptor0 = []byte{\n\t// 326 bytes of a gzipped FileDescriptorProto\n\t0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x74, 0x92, 0xef, 0x4a, 0xc3, 0x30,\n\t0x10, 0xc0, 0x97, 0x6e, 0xdd, 0x9f, 0x53, 0xea, 0x0c, 0x22, 0xb1, 0x9f, 0x6a, 0x3f, 0x15, 0x91,\n\t0x21, 0xf3, 0xab, 0x20, 0x32, 0x70, 0xf8, 0xb5, 0x3e, 0x41, 0x6d, 0x0f, 0x17, 0xdc, 0xda, 0x9a,\n\t0xcb, 0x90, 0xf9, 0x0a, 0xbe, 0x83, 0xcf, 0xe0, 0x23, 0x4a, 0xd2, 0x66, 0x03, 0xe7, 0xbe, 0xdd,\n\t0xef, 0x72, 0x77, 0xf9, 0xe5, 0x08, 0x04, 0xf9, 0x9a, 0x74, 0xb5, 0x42, 0x35, 0xa9, 0x55, 0xa5,\n\t0x2b, 0x3e, 0x74, 0x1c, 0xff, 0x78, 0x70, 0x32, 0x6b, 0x21, 0xc5, 0xf7, 0x35, 0x92, 0xe6, 0x01,\n\t0x78, 0xb2, 0x10, 0x2c, 0x62, 0x89, 0x9f, 0x7a, 0xb2, 0xe0, 0x1c, 0x7a, 0x65, 0xb6, 0x42, 0xe1,\n\t0x45, 0x2c, 0x19, 0xa5, 0x36, 0xe6, 0x67, 0xe0, 0xe3, 0x2a, 0x93, 0x4b, 0xd1, 0xb5, 0xc9, 0x06,\n\t0x4c, 0xb6, 0x5e, 0x54, 0x25, 0x8a, 0x5e, 0x93, 0xb5, 0xc0, 0xef, 0x61, 0x94, 0x15, 0x85, 0x42,\n\t0x22, 0x24, 0xe1, 0x47, 0xdd, 0xe4, 0x68, 0x7a, 0x39, 0xd9, 0x1a, 0xfd, 0xb9, 0x7d, 0xf2, 0xd0,\n\t0x94, 0xa6, 0xbb, 0x9e, 0xf0, 0x8b, 0xc1, 0xa0, 0x4d, 0xf3, 0x73, 0xe8, 0x93, 0x56, 0x88, 0xda,\n\t0x0a, 0x8e, 0xd2, 0x96, 0x8c, 0x64, 0x2e, 0xf5, 0xc6, 0x49, 0x9a, 0xd8, 0xe8, 0x90, 0xce, 0x34,\n\t0x3a, 0x49, 0x0b, 0x7c, 0x0c, 0xdd, 0x4f, 0x59, 0xb7, 0x8a, 0x26, 0xe4, 0xd7, 0x70, 0x2a, 0xe9,\n\t0x79, 0x21, 0xeb, 0x5a, 0x96, 0xaf, 0xed, 0x45, 0xc2, 0x8f, 0x58, 0x32, 0x4c, 0xf7, 0x0f, 0xe2,\n\t0x3b, 0x18, 0xef, 0x9c, 0xa9, 0xae, 0x4a, 0xc2, 0xbd, 0x95, 0x09, 0x18, 0xd0, 0x3a, 0xcf, 0xcd,\n\t0x1c, 0xcf, 0xce, 0x71, 0x18, 0x5f, 0x41, 0xe0, 0xba, 0x1f, 0xe5, 0x52, 0xa3, 0x32, 0xb5, 0x6f,\n\t0xb8, 0xf9, 0xa8, 0x54, 0xd1, 0x3e, 0xc9, 0xe1, 0xf4, 0x9b, 0xc1, 0xd0, 0x15, 0xf3, 0x39, 0x1c,\n\t0xcf, 0x51, 0x3b, 0x24, 0x2e, 0xf6, 0x57, 0xd8, 0x0c, 0x0c, 0x2f, 0x0e, 0x2e, 0x37, 0xee, 0xdc,\n\t0x30, 0xfe, 0x04, 0xc1, 0x4c, 0x61, 0xa6, 0x71, 0x3b, 0xfa, 0x70, 0x43, 0x18, 0xfe, 0x77, 0xd4,\n\t0x3c, 0x3a, 0xee, 0xbc, 0xf4, 0xed, 0x77, 0xba, 0xfd, 0x0d, 0x00, 0x00, 0xff, 0xff, 0xde, 0x91,\n\t0xd3, 0x62, 0x60, 0x02, 0x00, 0x00,\n}\n"
  },
  {
    "path": "grpc/customer/customer.proto",
    "content": "syntax = \"proto3\";\npackage customer;\n\n\n// The Customer service definition.\nservice Customer {   \n  // Get all Customers with filter - A server-to-client streaming RPC.\n  rpc GetCustomers(CustomerFilter) returns (stream CustomerRequest) {}\n  // Create a new Customer - A simple RPC \n  rpc CreateCustomer (CustomerRequest) returns (CustomerResponse) {}\n}\n\n// Request message for creating a new customer\nmessage CustomerRequest {\n  int32 id = 1;  // Unique ID number for a Customer.\n  string name = 2;\n  string email = 3;\n  string phone= 4;\n  \n  message Address {\n    string street = 1;\n    string city = 2;\n    string state = 3;\n    string zip = 4;\n    bool isShippingAddress = 5; \n  }\n\n  repeated Address addresses = 5;\n}\n\nmessage CustomerResponse {\n  int32 id = 1;\n  bool success = 2;\n}\nmessage CustomerFilter {    \n  string keyword = 1;\n}"
  },
  {
    "path": "grpc/server/main.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\t\"net\"\n\t\"strings\"\n\n\t\"golang.org/x/net/context\"\n\t\"google.golang.org/grpc\"\n\n\tpb \"github.com/shijuvar/go-recipes/grpc/customer\"\n)\n\nconst (\n\tport = \":50051\"\n)\n\n// server is used to implement customer.CustomerServer.\ntype server struct {\n\tsavedCustomers []*pb.CustomerRequest\n}\n\n// CreateCustomer creates a new Customer\nfunc (s *server) CreateCustomer(ctx context.Context, in *pb.CustomerRequest) (*pb.CustomerResponse, error) {\n\ts.savedCustomers = append(s.savedCustomers, in)\n\treturn &pb.CustomerResponse{Id: in.Id, Success: true}, nil\n}\n\n// GetCustomers returns all customers by given filter\nfunc (s *server) GetCustomers(filter *pb.CustomerFilter, stream pb.Customer_GetCustomersServer) error {\n\tfor _, customer := range s.savedCustomers {\n\t\tif filter.Keyword != \"\" {\n\t\t\tif !strings.Contains(customer.Name, filter.Keyword) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\tif err := stream.Send(customer); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc main() {\n\tlis, err := net.Listen(\"tcp\", port)\n\tif err != nil {\n\t\tlog.Fatalf(\"failed to listen: %v\", err)\n\t}\n\t// Creates a new gRPC server\n\ts := grpc.NewServer()\n\tpb.RegisterCustomerServer(s, &server{})\n\ts.Serve(lis)\n}\n"
  }
]