[
  {
    "path": ".gitignore",
    "content": "# Created by .ignore support plugin (hsz.mobi)\n### Go template\n# Binaries for programs and plugins\n*.exe\n*.exe~\n*.dll\n*.so\n*.dylib\n\n# Test binary, build with `go test -c`\n*.test\n\n# Output of the go coverage tool, specifically when used with LiteIDE\n*.out\n\nconfig.json\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018 Packt\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": "\n\n\n# Hands-On Dependency Injection in Go\r\n\r\n<a href=\"https://www.packtpub.com/application-development/hands-dependency-injection-go?utm_source=github&utm_medium=repository&utm_campaign=9781789132762 \"><img src=\"https://d255esdrn735hr.cloudfront.net/sites/default/files/imagecache/ppv4_main_book_cover/B10763_MockupCover_new.png\" alt=\"Hands-On Dependency Injection in Go\" height=\"256px\" align=\"right\"></a>\r\n\r\nThis is the code repository for [Hands-On Dependency Injection in Go](https://www.packtpub.com/application-development/hands-dependency-injection-go?utm_source=github&utm_medium=repository&utm_campaign=9781789132762 ), published by Packt.\r\n\r\n**Develop clean Go code that is easier to read, maintain, and test**\r\n\r\n## What is this book about?\r\nHands-On Dependency Injection in Go takes you on a journey, refactoring existing code to adopt dependency injection (DI) using various methods available in Go.\r\n\r\nThis book covers the following exciting features:\r\n* Understand the benefits of dependency injection \r\n* Explore SOLID design principles and how they relate to Go \r\n* Analyze various dependency injection patterns available in Go \r\n* Leverage DI to produce high quality, loosely coupled Go code \r\n* Refactor existing Go code to adopt dependency injection \r\n* Discover tools to improve your code's testability and test coverage \r\n* Generate and interpret Go dependency graphs \r\n\r\nIf you feel this book is for you, get your [copy](https://www.amazon.com/dp/1789132762) today!\r\n\r\n<a href=\"https://www.packtpub.com/?utm_source=github&utm_medium=banner&utm_campaign=GitHubBanner\"><img src=\"https://raw.githubusercontent.com/PacktPublishing/GitHub/master/GitHub.png\" \r\nalt=\"https://www.packtpub.com/\" border=\"5\" /></a>\r\n\r\n## Instructions and Navigations\r\nAll of the code is organized into folders. For example, ch02.\r\n\r\nThe code will look like the following:\r\n```\r\nhtml, body, #map {\r\n height: 100%; \r\n margin: 0;\r\n padding: 0\r\n}\r\n```\r\n\r\n**Following is what you need for this book:**\r\nHands-On Dependency Injection in Go is for programmers with a few year s experience in any language and a basic understanding of Go. If you wish to produce clean, loosely coupled code that is inherently easier to test, this book is for you.\r\n\r\n## Getting the source\r\n\r\nThe easiest way to obtain the source code is to use `go get`.  \r\nThis will ensure that the code is placed in the correct directory and should be then runnable and testable.\r\n\r\nTo download this repo use `go get github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/...`\r\n\r\n## Code Organization\r\n\r\nIn this repository, there is 1 folder for every chapter of the book, named chXX where XX is the chapter number.\r\n\r\nThe code provided are expanded versions of the code presented in the book.  While it will compile and typically\r\nwill not throw an error when passed into `go test` it is not designed to be executed.\r\n\r\nFrom chapter 4 onwards, there is an `acme` directory included with the code that chapter.\r\nThe `acme` directory is the code for the sample service presented in the book with the changes discussed in that chapter\r\nalready applied.\r\n\r\nYou will also find 2 additional directories in the root of the repository:\r\n \r\n * **resources** - this directory contains an SQL file that should be used to populate a MySQL database.  This database\r\n is used by the sample service \r\n * **vendor** - this is standard go vendor directory which contains the external packages required by the sample service\r\n\r\n## Setting up the MySQL database\r\n\r\nThe easiest way to create and populate the database required by the sample service is by running the following:\r\n\r\n`mysql < ./resources/create.sql`\r\n\r\nDepending on your settings you may want to provide a username and password like this:\r\n\r\n`mysql -u [your username] -p < ./resources/create.sql`\r\n\r\nThis will create a database called `acme` with 1 table and 4 records.\r\n\r\n## Creating a free account on CurrencyLayer\r\n\r\nThe sample service uses a free currency conversion service.  In order to successfully run all the examples, you will need\r\nto sign up [here](https://currencylayer.com/) and obtain an API Key.\r\n\r\n## Configuring the sample service\r\n\r\nNow that you have your MySQL and CurrencyLayer credentials you can create a config for the sample service.\r\n\r\n1. Copy `default-config.json` (found next to this file) to `config.json`\r\n1. Open `config.json` in your favorite editor\r\n1. Add your database credentials to the `\"dsn\"` setting.  Should be in the form: \r\n`\"[username]:[password]@tcp(localhost:3306)/[database name]?autocommit=true\"`\r\n1. Add your API Key to the `\"exchangeRateAPIKey\"` setting.  Should be in the form: `\"1234567890abcdef1234567890abcdef\"`\r\n\r\n## Running the sample service for a particular chapter\r\n\r\nTo run sample service for a particular chapter:\r\n \r\n1. First make sure you are in the base of this repository:\r\n`cd $GOPATH/src/github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/` \r\n1. Use a command similar to the following (which is for ch04):\r\n`ACME_CONFIG=$GOPATH/src/github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/config.json go run ./ch04/acme/main.go` \r\n\r\n### Special instructions for chapters 10-12\r\n\r\nAs we have multiple files and tests in the `main` package, we cannot use the standard `go run ./ch10/acme/main.go` to run the service.\r\n\r\nInstead we need to modify the command to `go run ./ch10/acme/main.go ./ch10/acme/wire_gen.go`\r\n\r\n## Running tests for a chapter\r\n\r\nTo run sample service for a particular chapter you can use a command similar to the follow (which is for ch04):\r\n\r\n1. First make sure you are in the base of this repository:\r\n`cd $GOPATH/src/github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/` \r\n1. Use a command similar to the following (which is for ch04):\r\n`ACME_CONFIG=$GOPATH/src/github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/config.json go test ./ch04/...` \r\n\r\nWith the following software and hardware list you can run all code files present in the book (Chapter 1-12).\r\n### Software and Hardware List\r\n| Chapter  | Software required                    | OS required                        |\r\n| -------- | ------------------------------------ | -----------------------------------|\r\n| 1-12     | Go 1.10.x+                           | Windows, Mac OS X, and Linux (Any) |\r\n| 4-12     | MySQL 5.7.x+                         | Windows, Mac OS X, and Linux (Any) |\r\n| 4-12     | CurrencyLayer                        | Windows, Mac OS X, and Linux (Any) |\r\n\r\n### Related products\r\n* Mastering Go [[Packt]](https://www.packtpub.com/networking-and-servers/mastering-go?utm_source=github&utm_medium=repository&utm_campaign=9781788626545 ) [[Amazon]](https://www.amazon.com/dp/1788626540)\r\n\r\n* Go Standard Library Cookbook [[Packt]](https://www.packtpub.com/application-development/go-standard-library-cookbook?utm_source=github&utm_medium=repository&utm_campaign=9781788475273 ) [[Amazon]](https://www.amazon.com/dp/1788475275)\r\n\r\n\r\n## Get to Know the Author\r\n**Corey Scott**\r\nis a senior software engineer currently living in Melbourne, Australia. He’s been programming professionally since 2000, with the last 5 years spent building large-scale distributed services in Go.\r\nAn occasional technical speaker and blogger on a variety of software-related topics, he is passionate about designing and building quality software. He believes that software engineering is a craft that should be honed, debated, and continuously improved. He takes a pragmatic, non-zealot approach to coding and is always up for a good debate about software engineering, continuous delivery, testing, or clean coding.\r\n\r\n\r\n## Other books by the authors\r\n\r\n\r\n### Suggestions and Feedback\r\n[Click here](https://docs.google.com/forms/d/e/1FAIpQLSdy7dATC6QmEL81FIUuymZ0Wy9vH1jHkvpY57OiMeKGqib_Ow/viewform) if you have any feedback or suggestions.\r\n\r\n\r\n### Download a free PDF\n\n <i>If you have already purchased a print or Kindle version of this book, you can get a DRM-free PDF version at no cost.<br>Simply click on the link to claim your free PDF.</i>\n<p align=\"center\"> <a href=\"https://packt.link/free-ebook/9781789132762\">https://packt.link/free-ebook/9781789132762 </a> </p>"
  },
  {
    "path": "ch01/01_defining_depenency_injection/01_interface.go",
    "content": "package defining_depenency_injection\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n)\n\n// Saver persists the supplied bytes\ntype Saver interface {\n\tSave(data []byte) error\n}\n\n// SavePerson will validate and persist the supplied person\nfunc SavePerson(person *Person, saver Saver) error {\n\t// validate the inputs\n\terr := person.validate()\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// encode person to bytes\n\tbytes, err := person.encode()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// save the person and return the result\n\treturn saver.Save(bytes)\n}\n\n// Person data object\ntype Person struct {\n\tName  string\n\tPhone string\n}\n\n// validate the person object\nfunc (p *Person) validate() error {\n\tif p.Name == \"\" {\n\t\treturn errors.New(\"name missing\")\n\t}\n\n\tif p.Phone == \"\" {\n\t\treturn errors.New(\"phone missing\")\n\t}\n\n\treturn nil\n}\n\n// convert the person into bytes\nfunc (p *Person) encode() ([]byte, error) {\n\treturn json.Marshal(p)\n}\n"
  },
  {
    "path": "ch01/01_defining_depenency_injection/02_function_literal.go",
    "content": "package defining_depenency_injection\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n)\n\n// LoadPerson will load the requested person by ID.\n// Errors include: invalid ID, missing person and failure to load or decode.\nfunc LoadPerson(ID int, decodePerson func(data []byte) *Person) (*Person, error) {\n\t// validate the input\n\tif ID <= 0 {\n\t\treturn nil, fmt.Errorf(\"invalid ID '%d' supplied\", ID)\n\t}\n\n\t// load from storage\n\tbytes, err := loadPerson(ID)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// decode bytes and return\n\treturn decodePerson(bytes), nil\n}\n\n// load person as bytes from storage\nfunc loadPerson(ID int) ([]byte, error) {\n\t// TODO: implement\n\treturn nil, errors.New(\"not implemented\")\n}\n"
  },
  {
    "path": "ch01/01_defining_depenency_injection/03_test_without_nfs_test.go",
    "content": "package defining_depenency_injection\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\nfunc TestSavePerson_happyPath(t *testing.T) {\n\t// input\n\tin := &Person{\n\t\tName:  \"Sophia\",\n\t\tPhone: \"0123456789\",\n\t}\n\n\t// mock the NFS\n\tmockNFS := &mockSaver{}\n\tmockNFS.On(\"Save\", mock.Anything).Return(nil).Once()\n\n\t// Call Save\n\tresultErr := SavePerson(in, mockNFS)\n\n\t// validate result\n\tassert.NoError(t, resultErr)\n\tassert.True(t, mockNFS.AssertExpectations(t))\n}\n\n// mock implementation of Saver\ntype mockSaver struct {\n\tmock.Mock\n}\n\n// Save implements Saver\nfunc (m *mockSaver) Save(data []byte) error {\n\toutputs := m.Mock.Called(data)\n\n\treturn outputs.Error(0)\n}\n"
  },
  {
    "path": "ch01/01_defining_depenency_injection/04_fail_test_without_nfs_test.go",
    "content": "package defining_depenency_injection\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\nfunc TestSavePerson_nfsAlwaysFails(t *testing.T) {\n\t// input\n\tin := &Person{\n\t\tName:  \"Sophia\",\n\t\tPhone: \"0123456789\",\n\t}\n\n\t// mock the NFS\n\tmockNFS := &mockSaver{}\n\tmockNFS.On(\"Save\", mock.Anything).Return(errors.New(\"save failed\")).Once()\n\n\t// Call Save\n\tresultErr := SavePerson(in, mockNFS)\n\n\t// validate result\n\tassert.Error(t, resultErr)\n\tassert.True(t, mockNFS.AssertExpectations(t))\n}\n"
  },
  {
    "path": "ch01/02_code_smells/01_code_bloat/01_switch_type.go",
    "content": "package code_bloat\n\nimport (\n\t\"strconv\"\n)\n\nfunc AppendValue(buffer []byte, in interface{}) []byte {\n\tvar value []byte\n\n\t// convert input to []byte\n\tswitch concrete := in.(type) {\n\tcase []byte:\n\t\tvalue = concrete\n\n\tcase string:\n\t\tvalue = []byte(concrete)\n\n\tcase int64:\n\t\tvalue = []byte(strconv.FormatInt(concrete, 10))\n\n\tcase bool:\n\t\tvalue = []byte(strconv.FormatBool(concrete))\n\n\tcase float64:\n\t\tvalue = []byte(strconv.FormatFloat(concrete, 'e', 3, 64))\n\t}\n\n\tbuffer = append(buffer, value...)\n\treturn buffer\n}\n"
  },
  {
    "path": "ch01/02_code_smells/02_resistance_to_change/01_shotgun_surgey.go",
    "content": "package _2_resistance_to_change\n\nimport (\n\t\"database/sql\"\n\t\"io\"\n)\n\n// Renderer will render a person to the supplied writer\ntype Renderer struct{}\n\nfunc (r Renderer) render(name, phone string, output io.Writer) {\n\t// output the person\n}\n\n// Validator will validate the supplied person has all the required fields\ntype Validator struct{}\n\nfunc (v Validator) validate(name, phone string) error {\n\t// validate the person\n\treturn nil\n}\n\n// Saver will save the supplied person to the DB\ntype Saver struct{}\n\nfunc (s *Saver) Save(db *sql.DB, name, phone string) {\n\t// save the person to db\n}\n"
  },
  {
    "path": "ch01/02_code_smells/03_wasted_effort/01_excessive_comments.go",
    "content": "package wasted_effort\n\n// Excessive comments\nfunc outputOrderedPeopleA(in []*Person) {\n\t// This code orders people by name.\n\t// In cases where the name is the same, it will order by phone number.\n\t// The sort algorithm used is a bubble sort\n\t// WARNING: this sort will change the items of the input array\n\tfor range in {\n\t\t// ... sort code removed ...\n\t}\n\n\toutputPeople(in)\n}\n\n// Comments replaced with descriptive names\nfunc outputOrderedPeopleB(in []*Person) {\n\tsortPeople(in)\n\toutputPeople(in)\n}\n\nfunc outputPeople(in []*Person) {\n\t// TODO: implement\n}\n\n// any special instructions that MUST be documented relating to the sort should go here\nfunc sortPeople(in []*Person) {\n\t// TODO: implement\n}\n\n// Person data object\ntype Person struct {\n\tName  string\n\tPhone string\n}\n"
  },
  {
    "path": "ch01/02_code_smells/03_wasted_effort/02_complicated_go.go",
    "content": "package wasted_effort\n\nimport (\n\t\"image\"\n\t\"image/color\"\n\t\"math\"\n)\n\nfunc d(r, v float64, i *image.RGBA, c color.Color) {\n\tfor a := float64(0); a < 360; a++ {\n\t\tra := math.Pi * 2 * a / 360\n\t\tx := r*math.Sin(ra) + v\n\t\ty := r*math.Cos(ra) + v\n\t\ti.Set(int(x), int(y), c)\n\t}\n}\n"
  },
  {
    "path": "ch01/02_code_smells/04_tight_coupling/01_circular_dependencies/config/config.go",
    "content": "// +build bad\n\npackage config\n\nimport (\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch01/02_code_smells/04_tight_coupling/01_circular_dependencies/payment\"\n)\n\n// Config defines the JSON format of the config file\ntype Config struct {\n\t// Address is the host and port to bind to.\n\t// Default 0.0.0.0:8080\n\tAddress string\n\n\t// DefaultCurrency is the default currency of the system\n\tDefaultCurrency payment.Currency\n}\n\n// Load will load the JSON config from the file supplied\nfunc Load(filename string) (*Config, error) {\n\t// TODO: load currency from file\n\treturn nil, errors.New(\"not implemented yet\")\n}\n"
  },
  {
    "path": "ch01/02_code_smells/04_tight_coupling/01_circular_dependencies/payment/currency.go",
    "content": "// +build bad\n\npackage payment\n\nimport (\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch01/02_code_smells/04_tight_coupling/01_circular_dependencies/config\"\n)\n\n// Currency is custom type for currency\ntype Currency string\n\n// Processor processes payments\ntype Processor struct {\n\tConfig *config.Config\n}\n\n// Pay makes a payment in the default currency\nfunc (p *Processor) Pay(amount float64) error {\n\t// TODO: implement me\n\treturn errors.New(\"not implemented yet\")\n}\n"
  },
  {
    "path": "ch01/02_code_smells/04_tight_coupling/02_object_orgy.go",
    "content": "package _4_tight_coupling\n\nimport (\n\t\"errors\"\n\t\"io/ioutil\"\n\t\"net/http\"\n)\n\ntype PageLoader struct {\n}\n\nfunc (o *PageLoader) LoadPage(url string) ([]byte, error) {\n\tb := newFetcher()\n\n\t// check cache\n\tpayload, err := b.cache.Get(url)\n\tif err == nil {\n\t\t// found in cache\n\t\treturn payload, nil\n\t}\n\n\t// call upstream\n\tresp, err := b.httpClient.Get(url)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer resp.Body.Close()\n\n\t// extract data from HTTP response\n\tpayload, err = ioutil.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// save to cache asynchronously\n\tgo func(key string, value []byte) {\n\t\tb.cache.Set(key, value)\n\t}(url, payload)\n\n\t// return\n\treturn payload, nil\n}\n\ntype Fetcher struct {\n\thttpClient http.Client\n\tcache      *Cache\n}\n\nfunc newFetcher() *Fetcher {\n\treturn &Fetcher{}\n}\n\ntype Cache struct {\n\t// not implemented\n}\n\nfunc (c *Cache) Get(key string) ([]byte, error) {\n\t// not implemented\n\treturn nil, errors.New(\"not implemented\")\n}\n\nfunc (c *Cache) Set(key string, data []byte) error {\n\t// not implemented\n\treturn errors.New(\"not implemented\")\n}\n"
  },
  {
    "path": "ch01/02_code_smells/04_tight_coupling/03_feature_envy.go",
    "content": "package _4_tight_coupling\n\nimport (\n\t\"errors\"\n\t\"time\"\n)\n\ntype searchRequest struct {\n\tquery string\n\tstart time.Time\n\tend   time.Time\n}\n\nfunc (request searchRequest) validate() error {\n\tif request.query == \"\" {\n\t\treturn errors.New(\"search term is missing\")\n\t}\n\tif request.start.IsZero() || request.start.After(time.Now()) {\n\t\treturn errors.New(\"start time is missing or invalid\")\n\t}\n\tif request.end.IsZero() || request.end.Before(request.start) {\n\t\treturn errors.New(\"end time is missing or invalid\")\n\t}\n\n\treturn nil\n}\n\ntype searchResults struct {\n\tresult string\n}\n\nfunc doSearchWithEnvy(request searchRequest) ([]searchResults, error) {\n\t// validate request\n\tif request.query == \"\" {\n\t\treturn nil, errors.New(\"search term is missing\")\n\t}\n\tif request.start.IsZero() || request.start.After(time.Now()) {\n\t\treturn nil, errors.New(\"start time is missing or invalid\")\n\t}\n\tif request.end.IsZero() || request.end.Before(request.start) {\n\t\treturn nil, errors.New(\"end time is missing or invalid\")\n\t}\n\n\treturn performSearch(request)\n}\n\nfunc doSearchWithoutEnvy(request searchRequest) ([]searchResults, error) {\n\terr := request.validate()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn performSearch(request)\n}\n\nfunc performSearch(request searchRequest) ([]searchResults, error) {\n\t// TODO: implement\n\treturn nil, errors.New(\"not implemented\")\n}\n"
  },
  {
    "path": "ch02/01_single_responsibility_principle/01_responsibility_vs_change.go",
    "content": "package srp\n\nimport (\n\t\"fmt\"\n\t\"io\"\n)\n\n// CalculatorV1 calculates the test coverage for a directory and it's sub-directories\ntype CalculatorV1 struct {\n\t// coverage data populated by `Calculate()` method\n\tdata map[string]float64\n}\n\n// Calculate will calculate the coverage\nfunc (c *CalculatorV1) Calculate(path string) error {\n\t// run `go test -cover ./[path]/...` and store the results\n\treturn nil\n}\n\n// Output will print the coverage data to the supplied writer\nfunc (c *CalculatorV1) Output(writer io.Writer) {\n\tfor path, result := range c.data {\n\t\tfmt.Fprintf(writer, \"%s -> %.1f\\n\", path, result)\n\t}\n}\n"
  },
  {
    "path": "ch02/01_single_responsibility_principle/02_responsibility_vs_change.go",
    "content": "package srp\n\nimport (\n\t\"fmt\"\n\t\"io\"\n)\n\n// CalculatorV2 calculates the test coverage for a directory and it's sub-directories\ntype CalculatorV2 struct {\n\t// coverage data populated by `Calculate()` method\n\tdata map[string]float64\n}\n\n// Calculate will calculate the coverage\nfunc (c *CalculatorV2) Calculate(path string) error {\n\t// run `go test -cover ./[path]/...` and store the results\n\treturn nil\n}\n\n// Output will print the coverage data to the supplied writer\nfunc (c CalculatorV2) Output(writer io.Writer) {\n\tfor path, result := range c.data {\n\t\tfmt.Fprintf(writer, \"%s -> %.1f\\n\", path, result)\n\t}\n}\n\n// OutputCSV will print the coverage data to the supplied writer\nfunc (c CalculatorV2) OutputCSV(writer io.Writer) {\n\tfor path, result := range c.data {\n\t\tfmt.Fprintf(writer, \"%s,%.1f\\n\", path, result)\n\t}\n}\n"
  },
  {
    "path": "ch02/01_single_responsibility_principle/03_responsibility_vs_change.go",
    "content": "package srp\n\nimport (\n\t\"fmt\"\n\t\"io\"\n)\n\n// CalculatorV3 calculates the test coverage for a directory and it's sub-directories\ntype CalculatorV3 struct {\n\t// coverage data populated by `Calculate()` method\n\tdata map[string]float64\n}\n\n// Calculate will calculate the coverage\nfunc (c *CalculatorV3) Calculate(path string) error {\n\t// run `go test -cover ./[path]/...` and store the results\n\treturn nil\n}\n\nfunc (c *CalculatorV3) getData() map[string]float64 {\n\t// copy and return the map\n\treturn nil\n}\n\ntype Printer interface {\n\tOutput(data map[string]float64)\n}\n\ntype DefaultPrinter struct {\n\tWriter io.Writer\n}\n\n// Output implements Printer\nfunc (d *DefaultPrinter) Output(data map[string]float64) {\n\tfor path, result := range data {\n\t\tfmt.Fprintf(d.Writer, \"%s -> %.1f\\n\", path, result)\n\t}\n}\n\ntype CSVPrinter struct {\n\tWriter io.Writer\n}\n\n// Output implements Printer\nfunc (d *CSVPrinter) Output(data map[string]float64) {\n\tfor path, result := range data {\n\t\tfmt.Fprintf(d.Writer, \"%s,%.1f\\n\", path, result)\n\t}\n}\n"
  },
  {
    "path": "ch02/01_single_responsibility_principle/04_long_method.go",
    "content": "package srp\n\nimport (\n\t\"database/sql\"\n\t\"encoding/json\"\n\t\"net/http\"\n\t\"strconv\"\n)\n\nfunc loadUserHandlerLong(resp http.ResponseWriter, req *http.Request) {\n\terr := req.ParseForm()\n\tif err != nil {\n\t\tresp.WriteHeader(http.StatusInternalServerError)\n\t\treturn\n\t}\n\tuserID, err := strconv.ParseInt(req.Form.Get(\"UserID\"), 10, 64)\n\tif err != nil {\n\t\tresp.WriteHeader(http.StatusPreconditionFailed)\n\t\treturn\n\t}\n\n\trow := DB.QueryRow(\"SELECT * FROM Users WHERE ID = ?\", userID)\n\n\tperson := &Person{}\n\terr = row.Scan(&person.ID, &person.Name, &person.Phone)\n\tif err != nil {\n\t\tresp.WriteHeader(http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tencoder := json.NewEncoder(resp)\n\terr = encoder.Encode(person)\n\tif err != nil {\n\t\tresp.WriteHeader(http.StatusInternalServerError)\n\t\treturn\n\t}\n}\n\nvar DB *sql.DB\n\ntype Person struct {\n\tID    int64\n\tName  string\n\tPhone string\n}\n"
  },
  {
    "path": "ch02/01_single_responsibility_principle/04_long_method_test.go",
    "content": "package srp\n\nimport (\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/DATA-DOG/go-sqlmock\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestLoadUserHandler(t *testing.T) {\n\t// build request\n\treq := &http.Request{\n\t\tForm: url.Values{},\n\t}\n\treq.Form.Add(\"UserID\", \"1234\")\n\n\t// call function under test\n\tresp := httptest.NewRecorder()\n\tloadUserHandlerLong(resp, req)\n\n\t// validate result\n\tassert.Equal(t, http.StatusOK, resp.Code)\n\n\texpectedBody := `{\"ID\":1,\"Name\":\"Bob\",\"Phone\":\"0123456789\"}` + \"\\n\"\n\tassert.Equal(t, expectedBody, resp.Body.String())\n}\n\nfunc TestMain(m *testing.M) {\n\t// create fake DB for this test\n\tvar mock sqlmock.Sqlmock\n\tDB, mock, _ = sqlmock.New()\n\n\t// config fake response\n\tmock.ExpectQuery(\".*\").WillReturnRows(\n\t\tsqlmock.NewRows([]string{\"ID\", \"Name\", \"Phone\"}).AddRow(\n\t\t\t1, \"Bob\", \"0123456789\"))\n\n\tos.Exit(m.Run())\n}\n"
  },
  {
    "path": "ch02/01_single_responsibility_principle/05_srp_method.go",
    "content": "package srp\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\t\"strconv\"\n)\n\nfunc loadUserHandlerSRP(resp http.ResponseWriter, req *http.Request) {\n\tuserID, err := extractIDFromRequest(req)\n\tif err != nil {\n\t\tresp.WriteHeader(http.StatusPreconditionFailed)\n\t\treturn\n\t}\n\n\tperson, err := loadPersonByID(userID)\n\tif err != nil {\n\t\tresp.WriteHeader(http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\toutputPerson(resp, person)\n}\n\nfunc extractIDFromRequest(req *http.Request) (int64, error) {\n\terr := req.ParseForm()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn strconv.ParseInt(req.Form.Get(\"UserID\"), 10, 64)\n}\n\nfunc loadPersonByID(userID int64) (*Person, error) {\n\trow := DB.QueryRow(\"SELECT * FROM Users WHERE userID = ?\", userID)\n\n\tperson := &Person{}\n\terr := row.Scan(person.ID, person.Name, person.Phone)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn person, nil\n}\n\nfunc outputPerson(resp http.ResponseWriter, person *Person) {\n\tencoder := json.NewEncoder(resp)\n\terr := encoder.Encode(person)\n\tif err != nil {\n\t\tresp.WriteHeader(http.StatusInternalServerError)\n\t\treturn\n\t}\n}\n"
  },
  {
    "path": "ch02/02_open_closed_principle/01_open_closed_failure.go",
    "content": "package ocp\n\nimport (\n\t\"io\"\n\t\"net/http\"\n)\n\nfunc BuildOutputOCPFail(response http.ResponseWriter, format string, person Person) {\n\tvar err error\n\n\tswitch format {\n\tcase \"csv\":\n\t\terr = outputCSV(response, person)\n\n\tcase \"json\":\n\t\terr = outputJSON(response, person)\n\t}\n\n\tif err != nil {\n\t\t// output a server error and quit\n\t\tresponse.WriteHeader(http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tresponse.WriteHeader(http.StatusOK)\n}\n\n// output the person as CSV and return error when failing to do so\nfunc outputCSV(writer io.Writer, person Person) error {\n\t// TODO: implement\n\treturn nil\n}\n\n// output the person as JSON and return error when failing to do so\nfunc outputJSON(writer io.Writer, person Person) error {\n\t// TODO: implement\n\treturn nil\n}\n\n// A data transfer object that represents a person\ntype Person struct {\n\tName  string\n\tEmail string\n}\n"
  },
  {
    "path": "ch02/02_open_closed_principle/02_open_closed_success.go",
    "content": "package ocp\n\nimport (\n\t\"io\"\n\t\"net/http\"\n)\n\nfunc BuildOutputOCPSuccess(response http.ResponseWriter, formatter PersonFormatter, person Person) {\n\terr := formatter.Format(response, person)\n\tif err != nil {\n\t\t// output a server error and quit\n\t\tresponse.WriteHeader(http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tresponse.WriteHeader(http.StatusOK)\n}\n\ntype PersonFormatter interface {\n\tFormat(writer io.Writer, person Person) error\n}\n\n// output the person as CSV\ntype CSVPersonFormatter struct{}\n\n// Format implements the PersonFormatter interface\nfunc (c *CSVPersonFormatter) Format(writer io.Writer, person Person) error {\n\t// TODO: implement\n\treturn nil\n}\n\n// output the person as JSON\ntype JSONPersonFormatter struct{}\n\n// Format implements the PersonFormatter interface\nfunc (j *JSONPersonFormatter) Format(writer io.Writer, person Person) error {\n\t// TODO: implement\n\treturn nil\n}\n"
  },
  {
    "path": "ch02/02_open_closed_principle/03_shotgun_surgery.go",
    "content": "package ocp\n\nimport (\n\t\"net/http\"\n\t\"strconv\"\n)\n\nfunc GetUserHandlerV1(resp http.ResponseWriter, req *http.Request) {\n\t// validate inputs\n\terr := req.ParseForm()\n\tif err != nil {\n\t\tresp.WriteHeader(http.StatusInternalServerError)\n\t\treturn\n\t}\n\tuserID, err := strconv.ParseInt(req.Form.Get(\"UserID\"), 10, 64)\n\tif err != nil {\n\t\tresp.WriteHeader(http.StatusPreconditionFailed)\n\t\treturn\n\t}\n\n\tuser := loadUser(userID)\n\toutputUser(resp, user)\n}\n\nfunc DeleteUserHandlerV1(resp http.ResponseWriter, req *http.Request) {\n\t// validate inputs\n\terr := req.ParseForm()\n\tif err != nil {\n\t\tresp.WriteHeader(http.StatusInternalServerError)\n\t\treturn\n\t}\n\tuserID, err := strconv.ParseInt(req.Form.Get(\"UserID\"), 10, 64)\n\tif err != nil {\n\t\tresp.WriteHeader(http.StatusPreconditionFailed)\n\t\treturn\n\t}\n\n\tdeleteUser(userID)\n}\n\nfunc loadUser(userID int64) interface{} {\n\t// TODO: implement\n\treturn nil\n}\n\nfunc deleteUser(userID int64) {\n\t// TODO: implement\n}\n\nfunc outputUser(resp http.ResponseWriter, user interface{}) {\n\t// TODO: implement\n}\n"
  },
  {
    "path": "ch02/02_open_closed_principle/04_after_shotgun_surgery.go",
    "content": "package ocp\n\nimport (\n\t\"errors\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strconv\"\n)\n\nfunc GetUserHandlerV2(resp http.ResponseWriter, req *http.Request) {\n\t// validate inputs\n\terr := req.ParseForm()\n\tif err != nil {\n\t\tresp.WriteHeader(http.StatusInternalServerError)\n\t\treturn\n\t}\n\tuserID, err := extractUserID(req.Form)\n\tif err != nil {\n\t\tresp.WriteHeader(http.StatusPreconditionFailed)\n\t\treturn\n\t}\n\n\tuser := loadUser(userID)\n\toutputUser(resp, user)\n}\n\nfunc DeleteUserHandlerV2(resp http.ResponseWriter, req *http.Request) {\n\t// validate inputs\n\terr := req.ParseForm()\n\tif err != nil {\n\t\tresp.WriteHeader(http.StatusInternalServerError)\n\t\treturn\n\t}\n\tuserID, err := extractUserID(req.Form)\n\tif err != nil {\n\t\tresp.WriteHeader(http.StatusPreconditionFailed)\n\t\treturn\n\t}\n\n\tdeleteUser(userID)\n}\n\nfunc extractUserID(values url.Values) (int64, error) {\n\tuserID, err := strconv.ParseInt(values.Get(\"UserID\"), 10, 64)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tif userID <= 0 {\n\t\treturn 0, errors.New(\"userID must be positive\")\n\t}\n\n\treturn userID, nil\n}\n"
  },
  {
    "path": "ch02/02_open_closed_principle/05_composition.go",
    "content": "package ocp\n\nimport (\n\t\"database/sql\"\n)\n\ntype rowConverter struct {\n}\n\n// populate the supplied Person from *sql.Row or *sql.Rows object\nfunc (d *rowConverter) populate(in *Person, scan func(dest ...interface{}) error) error {\n\treturn scan(in.Name, in.Email)\n}\n\ntype LoadPerson struct {\n\t// compose the row converter into this loader\n\trowConverter\n}\n\nfunc (loader *LoadPerson) ByID(id int) (Person, error) {\n\trow := loader.loadFromDB(id)\n\n\tperson := Person{}\n\t// call the composed \"abstract class\"\n\terr := loader.populate(&person, row.Scan)\n\n\treturn person, err\n}\n\nfunc (loader *LoadPerson) loadFromDB(id int) *sql.Row {\n\t// TODO: implement\n\treturn nil\n}\n\ntype LoadAll struct {\n\t// compose the row converter into this loader\n\trowConverter\n}\n\nfunc (loader *LoadPerson) All() ([]Person, error) {\n\trows := loader.loadAllFromDB()\n\tdefer rows.Close()\n\n\tvar output []Person\n\tfor rows.Next() {\n\t\tperson := Person{}\n\n\t\t// call the composed \"abstract class\"\n\t\terr := loader.populate(&person, rows.Scan)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn output, nil\n}\n\nfunc (loader *LoadPerson) loadAllFromDB() *sql.Rows {\n\t// TODO: implement\n\treturn nil\n}\n"
  },
  {
    "path": "ch02/02_open_closed_principle/06_handler_struct.go",
    "content": "package ocp\n\nimport (\n\t\"net/http\"\n)\n\n// a HTTP health check handler in long form\ntype healthCheckLong struct {\n}\n\nfunc (h *healthCheckLong) ServeHTTP(resp http.ResponseWriter, _ *http.Request) {\n\tresp.WriteHeader(http.StatusNoContent)\n}\n\nfunc healthCheckLongUsage() {\n\thttp.Handle(\"/health\", &healthCheckLong{})\n}\n"
  },
  {
    "path": "ch02/02_open_closed_principle/07_handler_func.go",
    "content": "package ocp\n\nimport (\n\t\"net/http\"\n)\n\n// a HTTP health check handler in short form\nfunc healthCheckShort(resp http.ResponseWriter, _ *http.Request) {\n\tresp.WriteHeader(http.StatusNoContent)\n}\n\nfunc healthCheckShortUsage() {\n\thttp.Handle(\"/health\", http.HandlerFunc(healthCheckShort))\n}\n"
  },
  {
    "path": "ch02/03_liskov_substitution_principle/01_violation/example.go",
    "content": "package lsp_violation\n\nfunc Go(vehicle actions) {\n\tif sled, ok := vehicle.(*Sled); ok {\n\t\tsled.pushStart()\n\t} else {\n\t\tvehicle.startEngine()\n\t}\n\n\tvehicle.drive()\n}\n\ntype actions interface {\n\tdrive()\n\tstartEngine()\n}\n\ntype Vehicle struct {\n}\n\nfunc (v Vehicle) drive() {\n\t// TODO: implement\n}\n\nfunc (v Vehicle) startEngine() {\n\t// TODO: implement\n}\n\nfunc (v Vehicle) stopEngine() {\n\t// TODO: implement\n}\n\ntype Car struct {\n\tVehicle\n}\n\ntype Sled struct {\n\tVehicle\n}\n\nfunc (s Sled) startEngine() {\n\t// override so that is does nothing\n}\n\nfunc (s Sled) stopEngine() {\n\t// override so that is does nothing\n}\n\nfunc (s Sled) pushStart() {\n\t// TODO: implement\n}\n"
  },
  {
    "path": "ch02/03_liskov_substitution_principle/02_fixed/example.go",
    "content": "package fixedv1\n\nfunc Go(vehicle actions) {\n\tswitch concrete := vehicle.(type) {\n\tcase poweredActions:\n\t\tconcrete.startEngine()\n\n\tcase unpoweredActions:\n\t\tconcrete.pushStart()\n\t}\n\n\tvehicle.drive()\n}\n\ntype actions interface {\n\tdrive()\n}\n\ntype poweredActions interface {\n\tactions\n\tstartEngine()\n\tstopEngine()\n}\n\ntype unpoweredActions interface {\n\tactions\n\tpushStart()\n}\n\ntype Vehicle struct {\n}\n\nfunc (v Vehicle) drive() {\n\t// TODO: implement\n}\n\ntype PoweredVehicle struct {\n\tVehicle\n}\n\nfunc (v PoweredVehicle) startEngine() {\n\t// common engine start code\n}\n\ntype Car struct {\n\tPoweredVehicle\n}\n\ntype Sled struct {\n\tVehicle\n}\n\nfunc (s Sled) pushStart() {\n\t// do nothing\n}\n"
  },
  {
    "path": "ch02/03_liskov_substitution_principle/03_fixed/example.go",
    "content": "package fixedv2\n\nfunc Go(vehicle actions) {\n\tvehicle.start()\n\tvehicle.drive()\n}\n\ntype actions interface {\n\tstart()\n\tdrive()\n}\n\ntype Car struct {\n\tpoweredVehicle\n}\n\nfunc (c Car) start() {\n\tc.poweredVehicle.startEngine()\n}\n\nfunc (c Car) drive() {\n\t// TODO: implement\n}\n\ntype poweredVehicle struct {\n}\n\nfunc (p poweredVehicle) startEngine() {\n\t// common engine start code\n}\n\ntype Sled struct {\n}\n\nfunc (s Sled) start() {\n\t// push start\n}\n\nfunc (s Sled) drive() {\n\t// TODO: implement\n}\n"
  },
  {
    "path": "ch02/03_liskov_substitution_principle/04_behaviour.go",
    "content": "package lsp\n\ntype Collection interface {\n\tAdd(item interface{})\n\tGet(index int) interface{}\n}\n\ntype CollectionImpl struct {\n\titems []interface{}\n}\n\nfunc (c *CollectionImpl) Add(item interface{}) {\n\tc.items = append(c.items, item)\n}\n\nfunc (c *CollectionImpl) Get(index int) interface{} {\n\treturn c.items[index]\n}\n\ntype ReadOnlyCollection struct {\n\tCollectionImpl\n}\n\nfunc (ro *ReadOnlyCollection) Add(item interface{}) {\n\t// intentionally does nothing\n}\n"
  },
  {
    "path": "ch02/03_liskov_substitution_principle/05_behaviour_fixed.go",
    "content": "package lsp\n\ntype ImmutableCollection interface {\n\tGet(index int) interface{}\n}\n\ntype MutableCollection interface {\n\tImmutableCollection\n\tAdd(item interface{})\n}\n\ntype ReadOnlyCollectionV2 struct {\n\titems []interface{}\n}\n\nfunc (ro *ReadOnlyCollectionV2) Get(index int) interface{} {\n\treturn ro.items[index]\n}\n\ntype CollectionImplV2 struct {\n\tReadOnlyCollectionV2\n}\n\nfunc (c *CollectionImplV2) Add(item interface{}) {\n\tc.items = append(c.items, item)\n}\n"
  },
  {
    "path": "ch02/04_interface_segregation_principle/01_fat_interface.go",
    "content": "package isp\n\nimport (\n\t\"context\"\n)\n\ntype Item struct {\n\tKey     string\n\tPayload []byte\n}\n\ntype FatDbInterface interface {\n\tBatchGetItem(IDs ...int) ([]Item, error)\n\tBatchGetItemWithContext(ctx context.Context, IDs ...int) ([]Item, error)\n\n\tBatchPutItem(items ...Item) error\n\tBatchPutItemWithContext(ctx context.Context, items ...Item) error\n\n\tDeleteItem(ID int) error\n\tDeleteItemWithContext(ctx context.Context, item Item) error\n\n\tGetItem(ID int) (Item, error)\n\tGetItemWithContext(ctx context.Context, ID int) (Item, error)\n\n\tPutItem(item Item) error\n\tPutItemWithContext(ctx context.Context, item Item) error\n\n\tQuery(query string, args ...interface{}) ([]Item, error)\n\tQueryWithContext(ctx context.Context, query string, args ...interface{}) ([]Item, error)\n\n\tUpdateItem(item Item) error\n\tUpdateItemWithContext(ctx context.Context, item Item) error\n}\n\ntype Cache struct {\n\tdb FatDbInterface\n}\n\nfunc (c *Cache) Get(key string) interface{} {\n\t// code removed\n\n\t// load from DB\n\t_, _ = c.db.GetItem(42)\n\n\t// code removed\n\treturn nil\n}\n\nfunc (c *Cache) Set(key string, value interface{}) {\n\t// code removed\n\n\t// save to DB\n\t_ = c.db.PutItem(Item{})\n\n\t// code removed\n}\n"
  },
  {
    "path": "ch02/04_interface_segregation_principle/02_thin_interface.go",
    "content": "package isp\n\ntype myDB interface {\n\tGetItem(ID int) (Item, error)\n\tPutItem(item Item) error\n}\n\ntype CacheV2 struct {\n\tdb myDB\n}\n\nfunc (c *CacheV2) Get(key string) interface{} {\n\t// code removed\n\n\t// load from DB\n\t_, _ = c.db.GetItem(42)\n\n\t// code removed\n\treturn nil\n}\n\nfunc (c *CacheV2) Set(key string, value interface{}) {\n\t// code removed\n\n\t// save from DB\n\t_ = c.db.PutItem(Item{})\n\n\t// code removed\n}\n"
  },
  {
    "path": "ch02/04_interface_segregation_principle/03_repeated_inputs.go",
    "content": "package isp\n\nimport (\n\t\"context\"\n\t\"errors\"\n)\n\nfunc Encrypt(ctx context.Context, data []byte) ([]byte, error) {\n\t// As this operation make take too long, we need to be able to kill it\n\tstop := ctx.Done()\n\tresult := make(chan []byte, 1)\n\n\tgo func() {\n\t\tdefer close(result)\n\n\t\t// pull the encryption key from context\n\t\tkeyRaw := ctx.Value(\"encryption-key\")\n\t\tif keyRaw == nil {\n\t\t\tpanic(\"encryption key not found in context\")\n\t\t}\n\t\tkey := keyRaw.([]byte)\n\n\t\t// perform encryption\n\t\tciperText := performEncryption(key, data)\n\n\t\t// signal complete by sending the result\n\t\tresult <- ciperText\n\t}()\n\n\tselect {\n\tcase ciperText := <-result:\n\t\t// happy path\n\t\treturn ciperText, nil\n\n\tcase <-stop:\n\t\t// cancelled\n\t\treturn nil, errors.New(\"operation cancelled\")\n\t}\n}\n\nfunc performEncryption(key []byte, data []byte) []byte {\n\t// TODO: implement\n\treturn nil\n}\n"
  },
  {
    "path": "ch02/04_interface_segregation_principle/04_repeated_inputs.go",
    "content": "package isp\n\nimport (\n\t\"errors\"\n)\n\ntype Value interface {\n\tValue(key interface{}) interface{}\n}\n\ntype Monitor interface {\n\tDone() <-chan struct{}\n}\n\nfunc EncryptV2(keyValue Value, monitor Monitor, data []byte) ([]byte, error) {\n\t// As this operation make take too long, we need to be able to kill it\n\tstop := monitor.Done()\n\tresult := make(chan []byte, 1)\n\n\tgo func() {\n\t\tdefer close(result)\n\n\t\t// pull the encryption key from Value\n\t\tkeyRaw := keyValue.Value(\"encryption-key\")\n\t\tif keyRaw == nil {\n\t\t\tpanic(\"encryption key not found in context\")\n\t\t}\n\t\tkey := keyRaw.([]byte)\n\n\t\t// perform encryption\n\t\tciperText := performEncryption(key, data)\n\n\t\t// signal complete by sending the result\n\t\tresult <- ciperText\n\t}()\n\n\tselect {\n\tcase ciperText := <-result:\n\t\t// happy path\n\t\treturn ciperText, nil\n\n\tcase <-stop:\n\t\t// cancelled\n\t\treturn nil, errors.New(\"operation cancelled\")\n\t}\n}\n"
  },
  {
    "path": "ch02/04_interface_segregation_principle/05_repeated_inputs.go",
    "content": "package isp\n\nimport (\n\t\"context\"\n)\n\nfunc UseEncryptV2() {\n\t// create a context\n\tctx, cancel := context.WithCancel(context.Background())\n\tdefer cancel()\n\n\t// store the key\n\tctx = context.WithValue(ctx, \"encryption-key\", \"-secret-\")\n\n\t// call the function\n\t_, _ = EncryptV2(ctx, ctx, []byte(\"my data\"))\n}\n"
  },
  {
    "path": "ch02/04_interface_segregation_principle/06_implicit_interfaces.go",
    "content": "package isp\n\nimport (\n\t\"fmt\"\n)\n\ntype Talker interface {\n\tSayHello() string\n}\n\ntype Dog struct{}\n\n// The method implicitly implements the Talker interface\nfunc (d Dog) SayHello() string {\n\treturn \"Woof!\"\n}\n\nfunc Speak() {\n\tvar talker Talker\n\ttalker = Dog{}\n\n\tfmt.Print(talker.SayHello())\n}\n"
  },
  {
    "path": "ch03/01_optimizing_for_humans/01_not_so_simple.go",
    "content": "package humans\n\nimport (\n\t\"bytes\"\n\t\"strconv\"\n\t\"strings\"\n)\n\nfunc NotSoSimple(ID int64, name string, age int, registered bool) string {\n\tout := &bytes.Buffer{}\n\tout.WriteString(strconv.FormatInt(ID, 10))\n\tout.WriteString(\"-\")\n\tout.WriteString(strings.Replace(name, \" \", \"_\", -1))\n\tout.WriteString(\"-\")\n\tout.WriteString(strconv.Itoa(age))\n\tout.WriteString(\"-\")\n\tout.WriteString(strconv.FormatBool(registered))\n\treturn out.String()\n}\n"
  },
  {
    "path": "ch03/01_optimizing_for_humans/02_start_simple.go",
    "content": "package humans\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\nfunc Simpler(ID int64, name string, age int, registered bool) string {\n\tnameWithNoSpaces := strings.Replace(name, \" \", \"_\", -1)\n\treturn fmt.Sprintf(\"%d-%s-%d-%t\", ID, nameWithNoSpaces, age, registered)\n}\n"
  },
  {
    "path": "ch03/01_optimizing_for_humans/03_too_abstract.go",
    "content": "package humans\n\nimport (\n\t\"io/ioutil\"\n\t\"net/http\"\n)\n\ntype myGetter interface {\n\tGet(url string) (*http.Response, error)\n}\n\nfunc TooAbstract(getter myGetter, url string) ([]byte, error) {\n\tresp, err := getter.Get(url)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer resp.Body.Close()\n\n\treturn ioutil.ReadAll(resp.Body)\n}\n"
  },
  {
    "path": "ch03/01_optimizing_for_humans/04_common_concept.go",
    "content": "package humans\n\nimport (\n\t\"io/ioutil\"\n\t\"net/http\"\n)\n\nfunc CommonConcept(url string) ([]byte, error) {\n\tresp, err := http.Get(url)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer resp.Body.Close()\n\n\treturn ioutil.ReadAll(resp.Body)\n}\n"
  },
  {
    "path": "ch03/01_optimizing_for_humans/05_boolean_param.go",
    "content": "package humans\n\nimport (\n\t\"time\"\n)\n\ntype Pet struct {\n\tName string\n\tDog  bool\n\tBorn time.Time\n}\n\nfunc NewPet(name string, isDog bool) Pet {\n\treturn Pet{\n\t\tName: name,\n\t\tDog:  isDog,\n\t\tBorn: time.Now(),\n\t}\n}\n\nfunc CreatePetsV1() {\n\tNewPet(\"Fido\", true)\n}\n"
  },
  {
    "path": "ch03/01_optimizing_for_humans/06_hidden_boolean.go",
    "content": "package humans\n\nconst (\n\tisDog = true\n\tisCat = false\n)\n\nfunc NewDog(name string) Pet {\n\treturn NewPet(name, isDog)\n}\n\nfunc NewCat(name string) Pet {\n\treturn NewPet(name, isCat)\n}\n\nfunc CreatePetsV2() {\n\tNewDog(\"Fido\")\n}\n"
  },
  {
    "path": "ch03/01_optimizing_for_humans/07_wide_formatter.go",
    "content": "package humans\n\ntype WideFormatter interface {\n\tToCSV(pets []Pet) ([]byte, error)\n\tToGOB(pets []Pet) ([]byte, error)\n\tToJSON(pets []Pet) ([]byte, error)\n}\n"
  },
  {
    "path": "ch03/01_optimizing_for_humans/08_thin_formatters.go",
    "content": "package humans\n\ntype ThinFormatter interface {\n\tFormat(pets []Pet) ([]byte, error)\n}\n\ntype CSVFormatter struct{}\n\nfunc (f CSVFormatter) Format(pets []Pet) ([]byte, error) {\n\t// convert slice of pets to CSV\n\treturn nil, nil\n}\n\ntype GOBFormatter struct{}\n\nfunc (f GOBFormatter) Format(pets []Pet) ([]byte, error) {\n\t// convert slice of pets to GOB\n\treturn nil, nil\n}\n\ntype JSONFormatter struct{}\n\nfunc (f JSONFormatter) Format(pets []Pet) ([]byte, error) {\n\t// convert slice of pets to JSON\n\treturn nil, nil\n}\n"
  },
  {
    "path": "ch03/01_optimizing_for_humans/09_extra_config.go",
    "content": "package humans\n\n// PetFetcher searches the data store for pets whos name matches the search string.\n// Limit is optional (default is 100).  Offset is optional (default 0).\n// sortBy is optional (default name).  sortAscending is optional\nfunc PetFetcher(search string, limit int, offset int, sortBy string, sortAscending bool) []Pet {\n\treturn []Pet{}\n}\n\nfunc PetFetcherTypicalUsage() {\n\t_ = PetFetcher(\"Fido\", 0, 0, \"\", true)\n}\n"
  },
  {
    "path": "ch03/02_unit_tests/01_loader.go",
    "content": "package unit_tests\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\ntype Loader interface {\n\tLoad(ID int) (*Pet, error)\n}\n\nfunc TestLoadAndPrint_happyPath(t *testing.T) {\n\tresult := &bytes.Buffer{}\n\tLoadAndPrint(&happyPathLoader{}, 1, result)\n\tassert.Contains(t, result.String(), \"Pet named\")\n}\n\nfunc TestLoadAndPrint_notFound(t *testing.T) {\n\tresult := &bytes.Buffer{}\n\tLoadAndPrint(&missingLoader{}, 1, result)\n\tassert.Contains(t, result.String(), \"no such pet\")\n}\n\nfunc TestLoadAndPrint_error(t *testing.T) {\n\tresult := &bytes.Buffer{}\n\tLoadAndPrint(&errorLoader{}, 1, result)\n\tassert.Contains(t, result.String(), \"failed to load\")\n}\n\nfunc LoadAndPrint(loader Loader, ID int, dest io.Writer) {\n\tloadedPet, err := loader.Load(ID)\n\tif err != nil {\n\t\tfmt.Fprintf(dest, \"failed to load pet with ID %d with error: %s\", ID, err)\n\t\treturn\n\t}\n\n\tif loadedPet == nil {\n\t\tfmt.Fprintf(dest, \"no such pet found\")\n\t\treturn\n\t}\n\n\tfmt.Fprintf(dest, \"Pet named %s loaded\", loadedPet.Name)\n}\n\n// implements Loader\ntype happyPathLoader struct {\n}\n\nfunc (l *happyPathLoader) Load(ID int) (*Pet, error) {\n\treturn &Pet{}, nil\n}\n\n// implements Loader\ntype missingLoader struct {\n}\n\nfunc (l *missingLoader) Load(ID int) (*Pet, error) {\n\treturn nil, nil\n}\n\n// implements Loader\ntype errorLoader struct {\n}\n\nfunc (l *errorLoader) Load(ID int) (*Pet, error) {\n\treturn nil, errors.New(\"failed\")\n}\n"
  },
  {
    "path": "ch03/02_unit_tests/02_language_feature.go",
    "content": "package unit_tests\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\ntype Pet struct {\n\tName string\n}\n\nfunc NewPet(name string) *Pet {\n\treturn &Pet{\n\t\tName: name,\n\t}\n}\n\nfunc TestLanguageFeatures(t *testing.T) {\n\tpetFish := NewPet(\"Goldie\")\n\tassert.IsType(t, &Pet{}, petFish)\n}\n"
  },
  {
    "path": "ch03/02_unit_tests/03_simple_test.go",
    "content": "package unit_tests\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc concat(a, b string) string {\n\treturn a + b\n}\n\nfunc TestTooSimple(t *testing.T) {\n\ta := \"Hello \"\n\tb := \"World\"\n\texpected := \"Hello World\"\n\n\tassert.Equal(t, expected, concat(a, b))\n}\n"
  },
  {
    "path": "ch03/02_unit_tests/04_test_from_api.go",
    "content": "package unit_tests\n\nimport (\n\t\"database/sql\"\n)\n\ntype PetSaver struct{}\n\n// save the supplied pet and return the ID\nfunc (p PetSaver) Save(pet Pet) (int, error) {\n\terr := p.validate(pet)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tresult, err := p.save(pet)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn p.extractID(result)\n}\n\n// ensure the pet record is complete\nfunc (p PetSaver) validate(pet Pet) error {\n\treturn nil\n}\n\n// save to the datastore\nfunc (p PetSaver) save(pet Pet) (sql.Result, error) {\n\treturn nil, nil\n}\n\n// extract the ID from the result\nfunc (p PetSaver) extractID(result sql.Result) (int, error) {\n\treturn 0, nil\n}\n"
  },
  {
    "path": "ch03/02_unit_tests/05_repeated_code.go",
    "content": "package unit_tests\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\n// Round the supplied number to the nearest integer\nfunc Round(in float64) int {\n\treturn 0\n}\n\nfunc TestRound_down(t *testing.T) {\n\tin := float64(1.1)\n\texpected := 1\n\n\tresult := Round(in)\n\tassert.Equal(t, expected, result)\n}\n\nfunc TestRound_up(t *testing.T) {\n\tin := float64(3.7)\n\texpected := 4\n\n\tresult := Round(in)\n\tassert.Equal(t, expected, result)\n}\n\nfunc TestRound_noChange(t *testing.T) {\n\tin := float64(6.0)\n\texpected := 6\n\n\tresult := Round(in)\n\tassert.Equal(t, expected, result)\n}\n"
  },
  {
    "path": "ch03/02_unit_tests/06_tdt.go",
    "content": "package unit_tests\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestRound(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc     string\n\t\tin       float64\n\t\texpected int\n\t}{\n\t\t{\n\t\t\tdesc:     \"round down\",\n\t\t\tin:       1.1,\n\t\t\texpected: 1,\n\t\t},\n\t\t{\n\t\t\tdesc:     \"round up\",\n\t\t\tin:       3.7,\n\t\t\texpected: 4,\n\t\t},\n\t\t{\n\t\t\tdesc:     \"unchanged\",\n\t\t\tin:       6.0,\n\t\t\texpected: 6,\n\t\t},\n\t}\n\n\tfor _, scenario := range scenarios {\n\t\tin := scenario.in\n\n\t\tresult := Round(in)\n\t\tassert.Equal(t, scenario.expected, result)\n\t}\n}\n"
  },
  {
    "path": "ch03/02_unit_tests/07_person_loader.go",
    "content": "package unit_tests\n\nimport (\n\t\"errors\"\n)\n\nvar ErrNotFound = errors.New(\"person not found\")\n\ntype Person struct {\n\tName string\n}\n\n//go:generate mockery -name PersonLoader -testonly -inpkg -case=underscore\ntype PersonLoader interface {\n\tLoad(ID int) (*Person, error)\n}\n\nfunc LoadPersonName(loader PersonLoader, ID int) (string, error) {\n\tperson, err := loader.Load(ID)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn person.Name, nil\n}\n"
  },
  {
    "path": "ch03/02_unit_tests/08_stub.go",
    "content": "package unit_tests\n\n// Stubbed implementation of PersonLoader\ntype PersonLoaderStub struct {\n\tPerson *Person\n\tError  error\n}\n\nfunc (p *PersonLoaderStub) Load(ID int) (*Person, error) {\n\treturn p.Person, p.Error\n}\n"
  },
  {
    "path": "ch03/02_unit_tests/09_stub_tdt.go",
    "content": "package unit_tests\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestLoadPersonNameStubs(t *testing.T) {\n\t// this value does not matter as the stub ignores it\n\tfakeID := 1\n\n\tscenarios := []struct {\n\t\tdesc         string\n\t\tloaderStub   *PersonLoaderStub\n\t\texpectedName string\n\t\texpectErr    bool\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tloaderStub: &PersonLoaderStub{\n\t\t\t\tPerson: &Person{Name: \"Sophia\"},\n\t\t\t},\n\t\t\texpectedName: \"Sophia\",\n\t\t\texpectErr:    false,\n\t\t},\n\t\t{\n\t\t\tdesc: \"input error\",\n\t\t\tloaderStub: &PersonLoaderStub{\n\t\t\t\tError: ErrNotFound,\n\t\t\t},\n\t\t\texpectedName: \"\",\n\t\t\texpectErr:    true,\n\t\t},\n\t\t{\n\t\t\tdesc: \"system error path\",\n\t\t\tloaderStub: &PersonLoaderStub{\n\t\t\t\tError: errors.New(\"something failed\"),\n\t\t\t},\n\t\t\texpectedName: \"\",\n\t\t\texpectErr:    true,\n\t\t},\n\t}\n\n\tfor _, scenario := range scenarios {\n\t\tresult, resultErr := LoadPersonName(scenario.loaderStub, fakeID)\n\n\t\tassert.Equal(t, scenario.expectedName, result, scenario.desc)\n\t\tassert.Equal(t, scenario.expectErr, resultErr != nil, scenario.desc)\n\t}\n}\n"
  },
  {
    "path": "ch03/02_unit_tests/10_mocks.go",
    "content": "package unit_tests\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\nfunc TestLoadPersonName(t *testing.T) {\n\t// this value does not matter as the stub ignores it\n\tfakeID := 1\n\n\tscenarios := []struct {\n\t\tdesc          string\n\t\tconfigureMock func(stub *PersonLoaderMock)\n\t\texpectedName  string\n\t\texpectErr     bool\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tconfigureMock: func(loaderMock *PersonLoaderMock) {\n\t\t\t\tloaderMock.On(\"Load\", mock.Anything).\n\t\t\t\t\tReturn(&Person{Name: \"Sophia\"}, nil).\n\t\t\t\t\tOnce()\n\t\t\t},\n\t\t\texpectedName: \"Sophia\",\n\t\t\texpectErr:    false,\n\t\t},\n\t\t{\n\t\t\tdesc: \"input error\",\n\t\t\tconfigureMock: func(loaderMock *PersonLoaderMock) {\n\t\t\t\tloaderMock.On(\"Load\", mock.Anything).\n\t\t\t\t\tReturn(nil, ErrNotFound).\n\t\t\t\t\tOnce()\n\t\t\t},\n\t\t\texpectedName: \"\",\n\t\t\texpectErr:    true,\n\t\t},\n\t\t{\n\t\t\tdesc: \"system error path\",\n\t\t\tconfigureMock: func(loaderMock *PersonLoaderMock) {\n\t\t\t\tloaderMock.On(\"Load\", mock.Anything).\n\t\t\t\t\tReturn(nil, errors.New(\"something failed\")).\n\t\t\t\t\tOnce()\n\t\t\t},\n\t\t\texpectedName: \"\",\n\t\t\texpectErr:    true,\n\t\t},\n\t}\n\n\tfor _, scenario := range scenarios {\n\t\tmockLoader := &PersonLoaderMock{}\n\t\tscenario.configureMock(mockLoader)\n\n\t\tresult, resultErr := LoadPersonName(mockLoader, fakeID)\n\n\t\tassert.Equal(t, scenario.expectedName, result, scenario.desc)\n\t\tassert.Equal(t, scenario.expectErr, resultErr != nil, scenario.desc)\n\t\tassert.True(t, mockLoader.AssertExpectations(t), scenario.desc)\n\t}\n}\n\n// Mocked implementation of PersonLoader\ntype PersonLoaderMock struct {\n\tmock.Mock\n}\n\nfunc (p *PersonLoaderMock) Load(ID int) (*Person, error) {\n\toutputs := p.Mock.Called(ID)\n\n\tperson := outputs.Get(0)\n\terr := outputs.Error(1)\n\n\tif person != nil {\n\t\treturn person.(*Person), err\n\t}\n\n\treturn nil, err\n}\n"
  },
  {
    "path": "ch03/03_test_induced_damage/01_io_closer.go",
    "content": "package test_damage\n\nimport (\n\t\"io\"\n)\n\nfunc WriteAndClose(destination io.WriteCloser, contents string) error {\n\tdefer destination.Close()\n\n\t_, err := destination.Write([]byte(contents))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "ch03/03_test_induced_damage/02_json.go",
    "content": "package test_damage\n\nimport (\n\t\"encoding/json\"\n\t\"io\"\n)\n\nfunc PrintAsJSON(destination io.Writer, plant Plant) error {\n\tbytes, err := json.Marshal(plant)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdestination.Write(bytes)\n\treturn nil\n}\n\ntype Plant struct {\n\tName string\n}\n"
  },
  {
    "path": "ch03/04_visualizing_dependencies/depgraph.sh",
    "content": "#!/usr/bin/env bash\n\n# Note:\n# This script should be run in the base directory of the project/service\n\n# Inputs\n#\n# This cuts down on typing by allowing you to enter only the sub-directory you wish to graph; instead of the entire\n# package\nprefix=\"./\"\nPKG=${1#$prefix}\n\n# Constants\n#\n# Save the file on the desktop (so it's easy to find)\nDEST_FILE=~/Desktop/depgraph.png\n\n# Calculate the package in the current directory and assume this is the base or project package\nBASE_PKG=$(go list)\nEXCLUSIONS=\"$BASE_PKG/vendor\"\nBASE_PKG_DELIMITED=$(echo $BASE_PKG | sed 's/\\//\\\\\\//g')\n\n# Generate\ngodepgraph -s \\\n        -o \"$BASE_PKG\" \\\n        -p \"$EXCLUSIONS\" \\\n        $BASE_PKG/${PKG} |\n        sed \"s/$BASE_PKG_DELIMITED//g\" | dot -Tpng -o $DEST_FILE\n\n# Open\nopen $DEST_FILE\n"
  },
  {
    "path": "ch03/fake.go",
    "content": "package Hands_On_Dependency_Injection_in_Go\n\nfunc init() {\n\t// This file is included so that Go tools (like `go list`) will find Go code in this directory and not error\n}\n"
  },
  {
    "path": "ch04/01_welcome/01_bad_names.go",
    "content": "package welcome\n\ntype HouseV1 struct {\n\ta string\n\tb int\n\tt int\n\tp float64\n}\n"
  },
  {
    "path": "ch04/01_welcome/02_improved_names.go",
    "content": "package welcome\n\ntype HouseV2 struct {\n\taddress  string\n\tbedrooms int\n\ttoilets  int\n\tprice    float64\n}\n"
  },
  {
    "path": "ch04/01_welcome/03_long_method.go",
    "content": "package welcome\n\nimport (\n\t\"database/sql\"\n\t\"encoding/json\"\n\t\"net/http\"\n\t\"strconv\"\n)\n\nfunc longMethod(resp http.ResponseWriter, req *http.Request) {\n\terr := req.ParseForm()\n\tif err != nil {\n\t\tresp.WriteHeader(http.StatusPreconditionFailed)\n\t\treturn\n\t}\n\tuserID, err := strconv.ParseInt(req.Form.Get(\"UserID\"), 10, 64)\n\tif err != nil {\n\t\tresp.WriteHeader(http.StatusPreconditionFailed)\n\t\treturn\n\t}\n\n\trow := DB.QueryRow(\"SELECT * FROM people WHERE ID = ?\", userID)\n\n\tperson := &Person{}\n\terr = row.Scan(&person.ID, &person.Name, &person.Phone)\n\tif err != nil {\n\t\tresp.WriteHeader(http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tencoder := json.NewEncoder(resp)\n\terr = encoder.Encode(person)\n\tif err != nil {\n\t\tresp.WriteHeader(http.StatusInternalServerError)\n\t\treturn\n\t}\n}\n\nvar DB *sql.DB\n\ntype Person struct {\n\tID    int64\n\tName  string\n\tPhone string\n}\n"
  },
  {
    "path": "ch04/01_welcome/04_long_method_test.go",
    "content": "package welcome\n\nimport (\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/DATA-DOG/go-sqlmock\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestLongMethod_happyPath(t *testing.T) {\n\t// build request\n\trequest := &http.Request{}\n\trequest.PostForm = url.Values{}\n\trequest.PostForm.Add(\"UserID\", \"123\")\n\n\t// mock the database\n\tvar mockDB sqlmock.Sqlmock\n\tvar err error\n\n\tDB, mockDB, err = sqlmock.New()\n\trequire.NoError(t, err)\n\tmockDB.ExpectQuery(\"SELECT .* FROM people WHERE ID = ?\").\n\t\tWithArgs(123).\n\t\tWillReturnRows(sqlmock.NewRows([]string{\"ID\", \"Name\", \"Phone\"}).AddRow(123, \"May\", \"0123456789\"))\n\n\t// build response\n\tresponse := httptest.NewRecorder()\n\n\t// call method\n\tlongMethod(response, request)\n\n\t// validate response\n\trequire.Equal(t, http.StatusOK, response.Code)\n\n\t// validate the JSON\n\tresponseBytes, err := ioutil.ReadAll(response.Body)\n\trequire.NoError(t, err)\n\n\texpectedJSON := `{\"ID\":123,\"Name\":\"May\",\"Phone\":\"0123456789\"}` + \"\\n\"\n\tassert.Equal(t, expectedJSON, string(responseBytes))\n}\n"
  },
  {
    "path": "ch04/01_welcome/05_short_methods.go",
    "content": "package welcome\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\t\"strconv\"\n)\n\nfunc shortMethods(resp http.ResponseWriter, req *http.Request) {\n\tuserID, err := extractUserID(req)\n\tif err != nil {\n\t\tresp.WriteHeader(http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tperson, err := loadPerson(userID)\n\tif err != nil {\n\t\tresp.WriteHeader(http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\toutputPerson(resp, person)\n}\n\nfunc extractUserID(req *http.Request) (int64, error) {\n\terr := req.ParseForm()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn strconv.ParseInt(req.Form.Get(\"UserID\"), 10, 64)\n}\n\nfunc loadPerson(userID int64) (*Person, error) {\n\trow := DB.QueryRow(\"SELECT * FROM people WHERE ID = ?\", userID)\n\n\tperson := &Person{}\n\terr := row.Scan(&person.ID, &person.Name, &person.Phone)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn person, nil\n}\n\nfunc outputPerson(resp http.ResponseWriter, person *Person) {\n\tencoder := json.NewEncoder(resp)\n\terr := encoder.Encode(person)\n\tif err != nil {\n\t\tresp.WriteHeader(http.StatusInternalServerError)\n\t\treturn\n\t}\n}\n"
  },
  {
    "path": "ch04/03_known_issues/01_data_and_rest/get_example.go",
    "content": "//+build ignore\n\npackage data_and_rest\n\nimport (\n\t\"encoding/json\"\n\t\"io\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/03_applying/01/data\"\n)\n\n// output the supplied person as JSON\nfunc (h *GetHandler) writeJSON(writer io.Writer, person *data.Person) error {\n\t// call to http.ResponseWriter.Write() will cause HTTP OK (200) to be output as well\n\treturn json.NewEncoder(writer).Encode(person)\n}\n"
  },
  {
    "path": "ch04/03_known_issues/02_config_coupling/config.go",
    "content": "package config_coupling\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch04/03_known_issues/02_config_coupling/currency\"\n)\n\ntype Config struct {\n\tDefaultCurrency currency.Currency `json:\"default_currency\"`\n}\n"
  },
  {
    "path": "ch04/03_known_issues/02_config_coupling/currency/currency.go",
    "content": "package currency\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n)\n\n// Currency is a custom type; used for convenience and code readability\ntype Currency string\n\n// UnmarshalJSON implements json.Unmarshaler\nfunc (c *Currency) UnmarshalJSON(in []byte) error {\n\tvar s string\n\terr := json.Unmarshal(in, &s)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tcurrency, valid := validCurrencies[s]\n\tif !valid {\n\t\treturn fmt.Errorf(\"'%s' is not a valid currency\", s)\n\t}\n\n\t*c = currency\n\n\treturn nil\n}\n\nconst (\n\tAUD = Currency(\"AUD\")\n\tCNY = Currency(\"CNY\")\n\tEUR = Currency(\"EUR\")\n\tUSD = Currency(\"USD\")\n)\n\n// a map of valid currencies\nvar validCurrencies = map[string]Currency{\n\tstring(AUD): AUD,\n\tstring(CNY): CNY,\n\tstring(EUR): EUR,\n\tstring(USD): USD,\n}\n"
  },
  {
    "path": "ch04/acme/internal/config/config.go",
    "content": "package config\n\nimport (\n\t\"encoding/json\"\n\t\"io/ioutil\"\n\t\"os\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch04/acme/internal/logging\"\n)\n\n// DefaultEnvVar is the default environment variable the points to the config file\nconst DefaultEnvVar = \"ACME_CONFIG\"\n\n// App is the application config\nvar App *Config\n\n// Config defines the JSON format for the config file\ntype Config struct {\n\t// DSN is the data source name (format: https://github.com/go-sql-driver/mysql/#dsn-data-source-name)\n\tDSN string\n\n\t// Address is the IP address and port to bind this rest to\n\tAddress string\n\n\t// BasePrice is the price of registration\n\tBasePrice float64\n\n\t// ExchangeRateBaseURL is the server and protocol part of the URL from which to load the exchange rate\n\tExchangeRateBaseURL string\n\n\t// ExchangeRateAPIKey is the API for the exchange rate API\n\tExchangeRateAPIKey string\n}\n\n// Load returns the config loaded from environment\nfunc init() {\n\tfilename, found := os.LookupEnv(DefaultEnvVar)\n\tif !found {\n\t\tlogging.L.Error(\"failed to locate file specified by %s\", DefaultEnvVar)\n\t\treturn\n\t}\n\n\t_ = load(filename)\n}\n\nfunc load(filename string) error {\n\tApp = &Config{}\n\tbytes, err := ioutil.ReadFile(filename)\n\tif err != nil {\n\t\tlogging.L.Error(\"failed to read config file. err: %s\", err)\n\t\treturn err\n\t}\n\n\terr = json.Unmarshal(bytes, App)\n\tif err != nil {\n\t\tlogging.L.Error(\"failed to parse config file. err : %s\", err)\n\t\treturn err\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "ch04/acme/internal/config/config_test.go",
    "content": "package config\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestLoad(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc           string\n\t\tin             string\n\t\texpectedConfig *Config\n\t\texpectError    bool\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tin:   \"../../../../default-config.json\",\n\t\t\texpectedConfig: &Config{\n\t\t\t\tDSN:                 \"[insert your db config here]\",\n\t\t\t\tAddress:             \"0.0.0.0:8080\",\n\t\t\t\tBasePrice:           100.00,\n\t\t\t\tExchangeRateBaseURL: \"http://apilayer.net\",\n\t\t\t\tExchangeRateAPIKey:  \"[insert your API key here]\",\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tdesc:           \"invalid path\",\n\t\t\tin:             \"invalid.json\",\n\t\t\texpectedConfig: &Config{},\n\t\t\texpectError:    true,\n\t\t},\n\t}\n\n\tfor _, s := range scenarios {\n\t\tscenario := s\n\t\tt.Run(scenario.desc, func(t *testing.T) {\n\t\t\tresultErr := load(scenario.in)\n\t\t\trequire.Equal(t, scenario.expectError, resultErr != nil, \"err: %s\", resultErr)\n\t\t\tassert.Equal(t, scenario.expectedConfig, App, scenario.desc)\n\t\t})\n\t}\n\n}\n"
  },
  {
    "path": "ch04/acme/internal/logging/logging.go",
    "content": "package logging\n\nimport (\n\t\"fmt\"\n)\n\n// L is the global instance of the logger\nvar L = &LoggerStdOut{}\n\n// LoggerStdOut logs to std out\ntype LoggerStdOut struct{}\n\n// Debug logs messages at DEBUG level\nfunc (l LoggerStdOut) Debug(message string, args ...interface{}) {\n\tfmt.Printf(\"[DEBUG] \"+message, args...)\n}\n\n// Info logs messages at INFO level\nfunc (l LoggerStdOut) Info(message string, args ...interface{}) {\n\tfmt.Printf(\"[INFO] \"+message, args...)\n}\n\n// Warn logs messages at WARN level\nfunc (l LoggerStdOut) Warn(message string, args ...interface{}) {\n\tfmt.Printf(\"[WARN] \"+message, args...)\n}\n\n// Error logs messages at ERROR level\nfunc (l LoggerStdOut) Error(message string, args ...interface{}) {\n\tfmt.Printf(\"[ERROR] \"+message, args...)\n}\n"
  },
  {
    "path": "ch04/acme/internal/modules/data/data.go",
    "content": "package data\n\nimport (\n\t\"database/sql\"\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch04/acme/internal/config\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch04/acme/internal/logging\"\n\t// import the MySQL Driver\n\t_ \"github.com/go-sql-driver/mysql\"\n)\n\nconst (\n\t// default person id (returned on error)\n\tdefaultPersonID = 0\n)\n\nvar (\n\tdb *sql.DB\n\n\t// ErrNotFound is returned when the no records where matched by the query\n\tErrNotFound = errors.New(\"not found\")\n)\n\nfunc getDB() (*sql.DB, error) {\n\tif db == nil {\n\t\tif config.App == nil {\n\t\t\treturn nil, errors.New(\"config is not initialized\")\n\t\t}\n\n\t\tvar err error\n\t\tdb, err = sql.Open(\"mysql\", config.App.DSN)\n\t\tif err != nil {\n\t\t\t// if the DB cannot be accessed we are dead\n\t\t\tpanic(err.Error())\n\t\t}\n\t}\n\n\treturn db, nil\n}\n\n// Person is the data transfer object (DTO) for this package\ntype Person struct {\n\t// ID is the unique ID for this person\n\tID int\n\t// FullName is the name of this person\n\tFullName string\n\t// Phone is the phone for this person\n\tPhone string\n\t// Currency is the currency this person has paid in\n\tCurrency string\n\t// Price is the amount (in the above currency) paid by this person\n\tPrice float64\n}\n\n// Save will save the supplied person and return the ID of the newly created person or an error.\n// Errors returned are caused by the underlying database or our connection to it.\nfunc Save(in *Person) (int, error) {\n\tdb, err := getDB()\n\tif err != nil {\n\t\tlogging.L.Error(\"failed to get DB connection. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\t// perform DB insert\n\tquery := \"INSERT INTO person (fullname, phone, currency, price) VALUES (?, ?, ?, ?)\"\n\tresult, err := db.Exec(query, in.FullName, in.Phone, in.Currency, in.Price)\n\tif err != nil {\n\t\tlogging.L.Error(\"failed to save person into DB. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\t// retrieve and return the ID of the person created\n\tid, err := result.LastInsertId()\n\tif err != nil {\n\t\tlogging.L.Error(\"failed to retrieve id of last saved person. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\treturn int(id), nil\n}\n\n// LoadAll will attempt to load all people in the database\n// It will return ErrNotFound when there are not people in the database\n// Any other errors returned are caused by the underlying database or our connection to it.\nfunc LoadAll() ([]*Person, error) {\n\tdb, err := getDB()\n\tif err != nil {\n\t\tlogging.L.Error(\"failed to get DB connection. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// perform DB select\n\tquery := \"SELECT id, fullname, phone, currency, price FROM person\"\n\trows, err := db.Query(query)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer func() {\n\t\t_ = rows.Close()\n\t}()\n\n\tvar out []*Person\n\n\tfor rows.Next() {\n\t\t// retrieve columns and populate the person object\n\t\trecord, err := populatePerson(rows.Scan)\n\t\tif err != nil {\n\t\t\tlogging.L.Error(\"failed to convert query result. err: %s\", err)\n\t\t\treturn nil, err\n\t\t}\n\n\t\tout = append(out, record)\n\t}\n\n\tif len(out) == 0 {\n\t\tlogging.L.Warn(\"no people found in the database.\")\n\t\treturn nil, ErrNotFound\n\t}\n\n\treturn out, nil\n}\n\n// Load will attempt to load and return a person.\n// It will return ErrNotFound when the requested person does not exist.\n// Any other errors returned are caused by the underlying database or our connection to it.\nfunc Load(ID int) (*Person, error) {\n\tdb, err := getDB()\n\tif err != nil {\n\t\tlogging.L.Error(\"failed to get DB connection. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// perform DB select\n\tquery := \"SELECT id, fullname, phone, currency, price FROM person WHERE id = ? LIMIT 1\"\n\trow := db.QueryRow(query, ID)\n\n\t// retrieve columns and populate the person object\n\tout, err := populatePerson(row.Scan)\n\tif err != nil {\n\t\tif err == sql.ErrNoRows {\n\t\t\tlogging.L.Warn(\"failed to load requested person '%d'. err: %s\", ID, err)\n\t\t\treturn nil, ErrNotFound\n\t\t}\n\n\t\tlogging.L.Error(\"failed to convert query result. err: %s\", err)\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\n// custom type so we can convert sql results to easily\ntype scanner func(dest ...interface{}) error\n\n// reduce the duplication (and maintenance) between sql.Row and sql.Rows usage\nfunc populatePerson(scanner scanner) (*Person, error) {\n\tout := &Person{}\n\terr := scanner(&out.ID, &out.FullName, &out.Phone, &out.Currency, &out.Price)\n\treturn out, err\n}\n"
  },
  {
    "path": "ch04/acme/internal/modules/data/data_test.go",
    "content": "package data\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestData_happyPath(t *testing.T) {\n\tin := &Person{\n\t\tFullName: \"Jake Blues\",\n\t\tPhone:    \"01234567890\",\n\t\tCurrency: \"AUD\",\n\t\tPrice:    123.45,\n\t}\n\n\t// save\n\tresultID, err := Save(in)\n\trequire.Nil(t, err)\n\tassert.True(t, resultID > 0)\n\n\t// load\n\treturned, err := Load(resultID)\n\trequire.NoError(t, err)\n\n\tin.ID = resultID\n\tassert.Equal(t, in, returned)\n\n\t// load all\n\tall, err := LoadAll()\n\trequire.NoError(t, err)\n\tassert.True(t, len(all) > 0)\n}\n"
  },
  {
    "path": "ch04/acme/internal/modules/exchange/converter.go",
    "content": "package exchange\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"math\"\n\t\"net/http\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch04/acme/internal/config\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch04/acme/internal/logging\"\n)\n\nconst (\n\t// request URL for the exchange rate API\n\turlFormat = \"%s/api/historical?access_key=%s&date=2018-06-20&currencies=%s\"\n\n\t// default price that is sent when an error occurs\n\tdefaultPrice = 0.0\n)\n\n// Converter will convert the base price to the currency supplied\n// Note: we are expecting sane inputs and therefore skipping input validation\ntype Converter struct{}\n\n// Do will perform the conversion\nfunc (c *Converter) Do(basePrice float64, currency string) (float64, error) {\n\t// load rate from the external API\n\tresponse, err := c.loadRateFromServer(currency)\n\tif err != nil {\n\t\treturn defaultPrice, err\n\t}\n\n\t// extract rate from response\n\trate, err := c.extractRate(response, currency)\n\tif err != nil {\n\t\treturn defaultPrice, err\n\t}\n\n\t// apply rate and round to 2 decimal places\n\treturn math.Floor((basePrice/rate)*100) / 100, nil\n}\n\n// load rate from the external API\nfunc (c *Converter) loadRateFromServer(currency string) (*http.Response, error) {\n\t// build the request\n\turl := fmt.Sprintf(urlFormat,\n\t\tconfig.App.ExchangeRateBaseURL,\n\t\tconfig.App.ExchangeRateAPIKey,\n\t\tcurrency)\n\n\t// perform request\n\tresponse, err := http.Get(url)\n\tif err != nil {\n\t\tlogging.L.Warn(\"[exchange] failed to load. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\tif response.StatusCode != http.StatusOK {\n\t\terr = fmt.Errorf(\"request failed with code %d\", response.StatusCode)\n\t\tlogging.L.Warn(\"[exchange] %s\", err)\n\t\treturn nil, err\n\t}\n\n\treturn response, nil\n}\n\nfunc (c *Converter) extractRate(response *http.Response, currency string) (float64, error) {\n\tdefer func() {\n\t\t_ = response.Body.Close()\n\t}()\n\n\t// extract data from response\n\tdata, err := c.extractResponse(response)\n\tif err != nil {\n\t\treturn defaultPrice, err\n\t}\n\n\t// pull rate from response data\n\trate, found := data.Quotes[\"USD\"+currency]\n\tif !found {\n\t\terr = fmt.Errorf(\"response did not include expected currency '%s'\", currency)\n\t\tlogging.L.Error(\"[exchange] %s\", err)\n\t\treturn defaultPrice, err\n\t}\n\n\t// happy path\n\treturn rate, nil\n}\n\nfunc (c *Converter) extractResponse(response *http.Response) (*apiResponseFormat, error) {\n\tpayload, err := ioutil.ReadAll(response.Body)\n\tif err != nil {\n\t\tlogging.L.Error(\"[exchange] failed to ready response body. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\tdata := &apiResponseFormat{}\n\terr = json.Unmarshal(payload, data)\n\tif err != nil {\n\t\tlogging.L.Error(\"[exchange] error converting response. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// happy path\n\treturn data, nil\n}\n\n// the response format from the exchange rate API\ntype apiResponseFormat struct {\n\tQuotes map[string]float64 `json:\"quotes\"`\n}\n"
  },
  {
    "path": "ch04/acme/internal/modules/get/get.go",
    "content": "package get\n\nimport (\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch04/acme/internal/modules/data\"\n)\n\nvar (\n\t// error thrown when the requested person is not in the database\n\terrPersonNotFound = errors.New(\"person not found\")\n)\n\n// Getter will attempt to load a person.\n// It can return an error caused by the data layer or when the requested person is not found\ntype Getter struct {\n}\n\n// Do will perform the get\nfunc (g *Getter) Do(ID int) (*data.Person, error) {\n\t// load person from the data layer\n\tperson, err := data.Load(ID)\n\tif err != nil {\n\t\tif err == data.ErrNotFound {\n\t\t\t// By converting the error we are encapsulating the implementation details from our users.\n\t\t\treturn nil, errPersonNotFound\n\t\t}\n\t\treturn nil, err\n\t}\n\n\treturn person, err\n}\n"
  },
  {
    "path": "ch04/acme/internal/modules/get/go_test.go",
    "content": "package get\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestGetter_Do(t *testing.T) {\n\t// inputs\n\tID := 1\n\tname := \"John\"\n\n\t// call method\n\tgetter := &Getter{}\n\tperson, err := getter.Do(ID)\n\n\t// validate expectations\n\trequire.NoError(t, err)\n\tassert.Equal(t, ID, person.ID)\n\tassert.Equal(t, name, person.FullName)\n}\n"
  },
  {
    "path": "ch04/acme/internal/modules/list/list.go",
    "content": "package list\n\nimport (\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch04/acme/internal/modules/data\"\n)\n\nvar (\n\t// error thrown when there are no people in the database\n\terrPeopleNotFound = errors.New(\"no people found\")\n)\n\n// Lister will attempt to load all people in the database.\n// It can return an error caused by the data layer\ntype Lister struct {\n}\n\n// Do will load the people from the data layer\nfunc (l *Lister) Do() ([]*data.Person, error) {\n\t// load all people\n\tpeople, err := l.load()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(people) == 0 {\n\t\t// special processing for 0 people returned\n\t\treturn nil, errPeopleNotFound\n\t}\n\n\treturn people, nil\n}\n\n// load all people\nfunc (l *Lister) load() ([]*data.Person, error) {\n\tpeople, err := data.LoadAll()\n\tif err != nil {\n\t\tif err == data.ErrNotFound {\n\t\t\t// By converting the error we are encapsulating the implementation details from our users.\n\t\t\treturn nil, errPeopleNotFound\n\t\t}\n\t\treturn nil, err\n\t}\n\n\treturn people, nil\n}\n"
  },
  {
    "path": "ch04/acme/internal/modules/list/list_test.go",
    "content": "package list\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestLister_Do(t *testing.T) {\n\t// call method\n\tlister := &Lister{}\n\tpersons, err := lister.load()\n\n\t// validate expectations\n\trequire.NoError(t, err)\n\tassert.True(t, len(persons) >= 4)\n}\n"
  },
  {
    "path": "ch04/acme/internal/modules/register/register.go",
    "content": "package register\n\nimport (\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch04/acme/internal/config\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch04/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch04/acme/internal/modules/data\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch04/acme/internal/modules/exchange\"\n)\n\nconst (\n\t// default person id (returned on error)\n\tdefaultPersonID = 0\n)\n\nvar (\n\t// validation errors\n\terrNameMissing     = errors.New(\"name is missing\")\n\terrPhoneMissing    = errors.New(\"phone is missing\")\n\terrCurrencyMissing = errors.New(\"currency is missing\")\n\terrInvalidCurrency = errors.New(\"currency is invalid, supported types are AUD, CNY, EUR, GBP, JPY, MYR, SGD, USD\")\n\n\t// a little trick to make checking for supported currencies easier\n\tsupportedCurrencies = map[string]struct{}{\n\t\t\"AUD\": {},\n\t\t\"CNY\": {},\n\t\t\"EUR\": {},\n\t\t\"GBP\": {},\n\t\t\"JPY\": {},\n\t\t\"MYR\": {},\n\t\t\"SGD\": {},\n\t\t\"USD\": {},\n\t}\n)\n\n// Registerer validates the supplied person, calculates the price in the requested currency and saves the result.\n// It will return an error when:\n// -the person object does not include all the fields\n// -the currency is invalid\n// -the exchange rate cannot be loaded\n// -the data layer throws an error.\ntype Registerer struct {\n}\n\n// Do is API for this struct\nfunc (r *Registerer) Do(in *data.Person) (int, error) {\n\t// validate the request\n\terr := r.validateInput(in)\n\tif err != nil {\n\t\tlogging.L.Warn(\"input validation failed with err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\t// get price in the requested currency\n\tprice, err := r.getPrice(in.Currency)\n\tif err != nil {\n\t\treturn defaultPersonID, err\n\t}\n\n\t// save registration\n\tid, err := r.save(in, price)\n\tif err != nil {\n\t\t// no need to log here as we expect the data layer to do so\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn id, nil\n}\n\n// validate input and return error on fail\nfunc (r *Registerer) validateInput(in *data.Person) error {\n\tif in.FullName == \"\" {\n\t\treturn errNameMissing\n\t}\n\tif in.Phone == \"\" {\n\t\treturn errPhoneMissing\n\t}\n\tif in.Currency == \"\" {\n\t\treturn errCurrencyMissing\n\t}\n\n\tif _, found := supportedCurrencies[in.Currency]; !found {\n\t\treturn errInvalidCurrency\n\t}\n\n\t// happy path\n\treturn nil\n}\n\n// get price in the requested currency\nfunc (r *Registerer) getPrice(currency string) (float64, error) {\n\tconverter := &exchange.Converter{}\n\tprice, err := converter.Do(config.App.BasePrice, currency)\n\tif err != nil {\n\t\tlogging.L.Warn(\"failed to convert the price. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn price, nil\n}\n\n// save the registration\nfunc (r *Registerer) save(in *data.Person, price float64) (int, error) {\n\tperson := &data.Person{\n\t\tFullName: in.FullName,\n\t\tPhone:    in.Phone,\n\t\tCurrency: in.Currency,\n\t\tPrice:    price,\n\t}\n\treturn data.Save(person)\n}\n"
  },
  {
    "path": "ch04/acme/internal/modules/register/register_test.go",
    "content": "package register\n\nimport (\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch04/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestRegisterer_Do(t *testing.T) {\n\t// inputs\n\tin := &data.Person{\n\t\tFullName: \"Chang\",\n\t\tPhone:    \"11122233345\",\n\t\tCurrency: \"CNY\",\n\t}\n\n\t// call method\n\tregisterer := &Registerer{}\n\tID, err := registerer.Do(in)\n\n\t// validate expectations\n\trequire.NoError(t, err)\n\tassert.True(t, ID > 0)\n}\n"
  },
  {
    "path": "ch04/acme/internal/rest/common_test.go",
    "content": "package rest\n\nimport (\n\t\"context\"\n\t\"net\"\n)\n\nfunc getOpenPort() (string, error) {\n\tlistener, err := net.Listen(\"tcp\", \"127.0.0.1:0\")\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\taddress := listener.Addr().String()\n\tlistener.Close()\n\n\treturn address, nil\n}\n\nfunc startServer(ctx context.Context) (string, error) {\n\t// get open port\n\taddress, err := getOpenPort()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\t// start a server\n\tserver := New(address)\n\tgo server.Listen(ctx.Done())\n\n\t// wait for server to be ready\n\tdialer := &net.Dialer{}\n\tfor {\n\t\tconn, _ := dialer.DialContext(ctx, \"tcp\", address)\n\t\tif conn != nil {\n\t\t\tdefer conn.Close()\n\n\t\t\treturn address, nil\n\t\t}\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn \"\", ctx.Err()\n\n\t\tdefault:\n\t\t\t// try again\n\t\t}\n\t}\n\n\treturn address, nil\n}\n"
  },
  {
    "path": "ch04/acme/internal/rest/get.go",
    "content": "package rest\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch04/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch04/acme/internal/modules/data\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch04/acme/internal/modules/get\"\n\t\"github.com/gorilla/mux\"\n)\n\nconst (\n\t// default person id (returned on error)\n\tdefaultPersonID = 0\n)\n\n// GetHandler is the HTTP handler for the \"Get Person\" endpoint\n// In this simplified example we are assuming all possible errors are user errors and returning \"bad request\" HTTP 400\n// or \"not found\" HTTP 404\n// There are some programmer errors possible but hopefully these will be caught in testing.\ntype GetHandler struct {\n}\n\n// ServeHTTP implements http.Handler\nfunc (h *GetHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\t// extract person id from request\n\tid, err := h.extractID(request)\n\tif err != nil {\n\t\t// output error\n\t\tresponse.WriteHeader(http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// attempt get\n\tgetter := get.Getter{}\n\tperson, err := getter.Do(id)\n\tif err != nil {\n\t\t// not need to log here as we can expect other layers to do so\n\t\tresponse.WriteHeader(http.StatusNotFound)\n\t\treturn\n\t}\n\n\t// happy path\n\terr = h.writeJSON(response, person)\n\tif err != nil {\n\t\t// this error should not happen but if it does there is nothing we can do to recover\n\t\tresponse.WriteHeader(http.StatusInternalServerError)\n\t}\n}\n\n// extract the person ID from the request\nfunc (h *GetHandler) extractID(request *http.Request) (int, error) {\n\t// ID is part of the URL, so we extract it from there\n\tvars := mux.Vars(request)\n\tidAsString, exists := vars[\"id\"]\n\tif !exists {\n\t\t// log and return error\n\t\terr := errors.New(\"[get] person id missing from request\")\n\t\tlogging.L.Warn(err.Error())\n\t\treturn defaultPersonID, err\n\t}\n\n\t// convert ID to int\n\tid, err := strconv.Atoi(idAsString)\n\tif err != nil {\n\t\t// log and return error\n\t\terr = fmt.Errorf(\"[get] failed to convert person id into a number. err: %s\", err)\n\t\tlogging.L.Error(err.Error())\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn id, nil\n}\n\n// output the supplied person as JSON\nfunc (h *GetHandler) writeJSON(writer io.Writer, person *data.Person) error {\n\toutput := &getResponseFormat{\n\t\tID:       person.ID,\n\t\tFullName: person.FullName,\n\t\tPhone:    person.Phone,\n\t\tCurrency: person.Currency,\n\t\tPrice:    person.Price,\n\t}\n\n\t// call to http.ResponseWriter.Write() will cause HTTP OK (200) to be output as well\n\treturn json.NewEncoder(writer).Encode(output)\n}\n\n// the JSON response format\ntype getResponseFormat struct {\n\tID       int     `json:\"id\"`\n\tFullName string  `json:\"name\"`\n\tPhone    string  `json:\"phone\"`\n\tCurrency string  `json:\"currency\"`\n\tPrice    float64 `json:\"price\"`\n}\n"
  },
  {
    "path": "ch04/acme/internal/rest/get_test.go",
    "content": "package rest\n\nimport (\n\t\"context\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestGetHandler_ServeHTTP(t *testing.T) {\n\t// ensure the test always fails by giving it a timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n\tdefer cancel()\n\n\t// Create and start a server\n\t// With out current implementation, we cannot test this handler without a full server as we need the mux.\n\taddress, err := startServer(ctx)\n\trequire.NoError(t, err)\n\n\t// build inputs\n\tresponse, err := http.Get(\"http://\" + address + \"/person/1/\")\n\n\t// validate outputs\n\trequire.NoError(t, err)\n\trequire.Equal(t, http.StatusOK, response.StatusCode)\n\n\texpectedPayload := []byte(`{\"id\":1,\"name\":\"John\",\"phone\":\"0123456780\",\"currency\":\"USD\",\"price\":100}` + \"\\n\")\n\tpayload, _ := ioutil.ReadAll(response.Body)\n\tdefer response.Body.Close()\n\n\tassert.Equal(t, expectedPayload, payload)\n}\n"
  },
  {
    "path": "ch04/acme/internal/rest/list.go",
    "content": "package rest\n\nimport (\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch04/acme/internal/modules/data\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch04/acme/internal/modules/list\"\n)\n\n// ListHandler is the HTTP handler for the \"List Do people\" endpoint\n// In this simplified example we are assuming all possible errors are system errors (HTTP 500)\ntype ListHandler struct {\n}\n\n// ServeHTTP implements http.Handler\nfunc (h *ListHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\t// attempt loadAll\n\tlister := list.Lister{}\n\tpeople, err := lister.Do()\n\tif err != nil {\n\t\t// not need to log here as we can expect other layers to do so\n\t\tresponse.WriteHeader(http.StatusNotFound)\n\t\treturn\n\t}\n\n\t// happy path\n\terr = h.writeJSON(response, people)\n\tif err != nil {\n\t\t// this error should not happen but if it does there is nothing we can do to recover\n\t\tresponse.WriteHeader(http.StatusInternalServerError)\n\t}\n}\n\n// output the result as JSON\nfunc (h *ListHandler) writeJSON(writer io.Writer, people []*data.Person) error {\n\toutput := &listResponseFormat{\n\t\tPeople: make([]*listResponseItemFormat, len(people)),\n\t}\n\n\tfor index, record := range people {\n\t\toutput.People[index] = &listResponseItemFormat{\n\t\t\tID:       record.ID,\n\t\t\tFullName: record.FullName,\n\t\t\tPhone:    record.Phone,\n\t\t}\n\t}\n\n\t// call to http.ResponseWriter.Write() will cause HTTP OK (200) to be output as well\n\treturn json.NewEncoder(writer).Encode(output)\n}\n\ntype listResponseFormat struct {\n\tPeople []*listResponseItemFormat `json:\"people\"`\n}\n\ntype listResponseItemFormat struct {\n\tID       int    `json:\"id\"`\n\tFullName string `json:\"name\"`\n\tPhone    string `json:\"phone\"`\n}\n"
  },
  {
    "path": "ch04/acme/internal/rest/list_test.go",
    "content": "package rest\n\nimport (\n\t\"context\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestListHandler_ServeHTTP(t *testing.T) {\n\t// ensure the test always fails by giving it a timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n\tdefer cancel()\n\n\t// Create and start a server\n\t// With out current implementation, we cannot test this handler without a full server as we need the mux.\n\taddress, err := startServer(ctx)\n\trequire.NoError(t, err)\n\n\t// build inputs\n\tresponse, err := http.Get(\"http://\" + address + \"/person/list\")\n\n\t// validate outputs\n\trequire.NoError(t, err)\n\trequire.Equal(t, http.StatusOK, response.StatusCode)\n\n\texpectedPayload := []byte(`{\"people\":[{\"id\":1,\"name\":\"John\",\"phone\":\"0123456780\"},{\"id\":2,\"name\":\"Paul\",\"phone\":\"0123456781\"},{\"id\":3,\"name\":\"George\",\"phone\":\"0123456782\"},{\"id\":4,\"name\":\"Ringo\",\"phone\":\"0123456783\"}`)\n\tpayload, _ := ioutil.ReadAll(response.Body)\n\tdefer response.Body.Close()\n\n\t// we have to use contains because other tests add more records\n\tassert.Contains(t, string(payload), string(expectedPayload))\n}\n"
  },
  {
    "path": "ch04/acme/internal/rest/not_found.go",
    "content": "package rest\n\nimport (\n\t\"net/http\"\n)\n\nfunc notFoundHandler(response http.ResponseWriter, _ *http.Request) {\n\tresponse.WriteHeader(http.StatusNotFound)\n\t_, _ = response.Write([]byte(`Not found`))\n}\n"
  },
  {
    "path": "ch04/acme/internal/rest/not_found_test.go",
    "content": "package rest\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestNotFoundHandler_ServeHTTP(t *testing.T) {\n\t// ensure the test always fails by giving it a timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n\tdefer cancel()\n\n\t// Create and start a server\n\t// With out current implementation, we cannot test this handler without a full server as we need the mux.\n\taddress, err := startServer(ctx)\n\trequire.NoError(t, err)\n\n\t// build inputs\n\tresponse, err := http.Get(\"http://\" + address + \"/some-bad-address\")\n\n\t// validate outputs\n\trequire.NoError(t, err)\n\trequire.Equal(t, http.StatusNotFound, response.StatusCode)\n}\n"
  },
  {
    "path": "ch04/acme/internal/rest/register.go",
    "content": "package rest\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch04/acme/internal/modules/data\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch04/acme/internal/modules/register\"\n)\n\n// RegisterHandler is the HTTP handler for the \"Register\" endpoint\n// In this simplified example we are assuming all possible errors are user errors and returning \"bad request\" HTTP 400.\n// There are some programmer errors possible but hopefully these will be caught in testing.\ntype RegisterHandler struct {\n}\n\n// ServeHTTP implements http.Handler\nfunc (h *RegisterHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\t// extract payload from request\n\trequestPayload, err := h.extractPayload(request)\n\tif err != nil {\n\t\t// output error\n\t\tresponse.WriteHeader(http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// register person\n\tid, err := h.register(requestPayload)\n\tif err != nil {\n\t\t// not need to log here as we can expect other layers to do so\n\t\tresponse.WriteHeader(http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// happy path\n\tresponse.Header().Add(\"Location\", fmt.Sprintf(\"/person/%d/\", id))\n\tresponse.WriteHeader(http.StatusCreated)\n}\n\n// extract payload from request\nfunc (h *RegisterHandler) extractPayload(request *http.Request) (*registerRequest, error) {\n\trequestPayload := &registerRequest{}\n\n\tdecoder := json.NewDecoder(request.Body)\n\terr := decoder.Decode(requestPayload)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn requestPayload, nil\n}\n\n// call the logic layer\nfunc (h *RegisterHandler) register(requestPayload *registerRequest) (int, error) {\n\tperson := &data.Person{\n\t\tFullName: requestPayload.FullName,\n\t\tPhone:    requestPayload.Phone,\n\t\tCurrency: requestPayload.Currency,\n\t}\n\n\tregisterer := &register.Registerer{}\n\treturn registerer.Do(person)\n}\n\n// register endpoint request format\ntype registerRequest struct {\n\t// FullName of the person\n\tFullName string `json:\"fullName\"`\n\t// Phone of the person\n\tPhone string `json:\"phone\"`\n\t// Currency the wish to register in\n\tCurrency string `json:\"currency\"`\n}\n"
  },
  {
    "path": "ch04/acme/internal/rest/register_test.go",
    "content": "package rest\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestRegisterHandler_ServeHTTP(t *testing.T) {\n\t// ensure the test always fails by giving it a timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n\tdefer cancel()\n\n\t// Create and start a server\n\t// With out current implementation, we cannot test this handler without a full server as we need the mux.\n\taddress, err := startServer(ctx)\n\trequire.NoError(t, err)\n\n\t// build inputs\n\tvalidRequest := buildValidRequest()\n\tresponse, err := http.Post(\"http://\"+address+\"/person/register\", \"application/json\", validRequest)\n\n\t// validate outputs\n\trequire.NoError(t, err)\n\trequire.Equal(t, http.StatusCreated, response.StatusCode)\n\tdefer response.Body.Close()\n\n\t// call should output the location to the new person\n\theaderLocation := response.Header.Get(\"Location\")\n\tassert.Contains(t, headerLocation, \"/person/\")\n}\n\nfunc buildValidRequest() io.Reader {\n\trequestData := &registerRequest{\n\t\tFullName: \"Joan Smith\",\n\t\tCurrency: \"AUD\",\n\t\tPhone:    \"01234567890\",\n\t}\n\n\tdata, _ := json.Marshal(requestData)\n\treturn bytes.NewBuffer(data)\n}\n"
  },
  {
    "path": "ch04/acme/internal/rest/server.go",
    "content": "package rest\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/gorilla/mux\"\n)\n\n// New will create and initialize the server\nfunc New(address string) *Server {\n\treturn &Server{\n\t\taddress:         address,\n\t\thandlerGet:      &GetHandler{},\n\t\thandlerList:     &ListHandler{},\n\t\thandlerNotFound: notFoundHandler,\n\t\thandlerRegister: &RegisterHandler{},\n\t}\n}\n\n// Server is the HTTP REST server\ntype Server struct {\n\taddress string\n\tserver  *http.Server\n\n\thandlerGet      http.Handler\n\thandlerList     http.Handler\n\thandlerNotFound http.HandlerFunc\n\thandlerRegister http.Handler\n}\n\n// Listen will start a HTTP rest for this service\nfunc (s *Server) Listen(stop <-chan struct{}) {\n\trouter := s.buildRouter()\n\n\t// create the HTTP server\n\ts.server = &http.Server{\n\t\tHandler: router,\n\t\tAddr:    s.address,\n\t}\n\n\t// listen for shutdown\n\tgo func() {\n\t\t// wait for shutdown signal\n\t\t<-stop\n\n\t\t_ = s.server.Close()\n\t}()\n\n\t// start the HTTP server\n\t_ = s.server.ListenAndServe()\n}\n\n// configure the endpoints to handlers\nfunc (s *Server) buildRouter() http.Handler {\n\trouter := mux.NewRouter()\n\n\t// map URL endpoints to HTTP handlers\n\trouter.Handle(\"/person/{id}/\", s.handlerGet).Methods(\"GET\")\n\trouter.Handle(\"/person/list\", s.handlerList).Methods(\"GET\")\n\trouter.Handle(\"/person/register\", s.handlerRegister).Methods(\"POST\")\n\n\t// convert a \"catch all\" not found handler\n\trouter.NotFoundHandler = s.handlerNotFound\n\n\treturn router\n}\n"
  },
  {
    "path": "ch04/acme/main.go",
    "content": "package main\n\nimport (\n\t\"context\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch04/acme/internal/config\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch04/acme/internal/rest\"\n)\n\nfunc main() {\n\t// bind stop channel to context\n\tctx := context.Background()\n\n\t// start REST server\n\tserver := rest.New(config.App.Address)\n\tserver.Listen(ctx.Done())\n}\n"
  },
  {
    "path": "ch04/fake.go",
    "content": "package ch04\n\nfunc init() {\n\t// This file is included so that Go tools (like `go list`) will find Go code in this directory and not error\n}\n"
  },
  {
    "path": "ch05/02_advantages/01_function.go",
    "content": "package advantages\n\nimport (\n\t\"encoding/json\"\n\t\"io/ioutil\"\n\t\"log\"\n)\n\nfunc SaveConfig(filename string, cfg *Config) error {\n\t// convert to JSON\n\tdata, err := json.Marshal(cfg)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// save file\n\terr = ioutil.WriteFile(filename, data, 0666)\n\tif err != nil {\n\t\tlog.Printf(\"failed to save file '%s' with err: %s\", filename, err)\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\ntype Config struct {\n\tHost string\n\tPort int\n}\n"
  },
  {
    "path": "ch05/02_advantages/02_monkey_patched.go",
    "content": "package advantages\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"log\"\n)\n\nfunc SaveConfigPatched(filename string, cfg *Config) error {\n\t// convert to JSON\n\tdata, err := json.Marshal(cfg)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// save file\n\terr = writeFile(filename, data, 0666)\n\tif err != nil {\n\t\tlog.Printf(\"failed to save file '%s' with err: %s\", filename, err)\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// Custom type that allows us to Monkey Patch\nvar writeFile = ioutil.WriteFile\n\n// Usage\nfunc SaveConfigPatchedUsage() {\n\tcfg := &Config{\n\t\t// build the config\n\t}\n\n\terr := SaveConfigPatched(\"myfile.json\", cfg)\n\tif err != nil {\n\t\tfmt.Printf(\"failed with err: %s\", err)\n\t}\n}\n"
  },
  {
    "path": "ch05/02_advantages/03_injected_lambda.go",
    "content": "package advantages\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc SaveConfigInjected(writer fileWriter, filename string, cfg *Config) error {\n\t// convert to JSON\n\tdata, err := json.Marshal(cfg)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// save file\n\terr = writer(filename, data, 0666)\n\tif err != nil {\n\t\tlog.Printf(\"failed to save file '%s' with err: %s\", filename, err)\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// This custom type is not strictly needed but it does make the function\n// signature a little cleaner\ntype fileWriter func(filename string, data []byte, perm os.FileMode) error\n\n// Usage\nfunc SaveConfigInjectedUsage() {\n\tcfg := &Config{\n\t\t// build the config\n\t}\n\n\terr := SaveConfigInjected(ioutil.WriteFile, \"myfile.json\", cfg)\n\tif err != nil {\n\t\tfmt.Printf(\"failed with err: %s\", err)\n\t}\n}\n"
  },
  {
    "path": "ch05/02_advantages/04_as_object.go",
    "content": "package advantages\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"os\"\n)\n\ntype ConfigSaver struct {\n\tFileWriter func(filename string, data []byte, perm os.FileMode) error\n}\n\nfunc (c ConfigSaver) Save(filename string, cfg *Config) error {\n\t// convert to JSON\n\tdata, err := json.Marshal(cfg)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// save file\n\terr = c.FileWriter(filename, data, 0666)\n\tif err != nil {\n\t\tlog.Printf(\"failed to save file '%s' with err: %s\", filename, err)\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// Usage\nfunc ConfigSaverUsage() {\n\tcfg := &Config{\n\t\t// build the config\n\t}\n\n\tsaver := &ConfigSaver{\n\t\tFileWriter: ioutil.WriteFile,\n\t}\n\n\terr := saver.Save(\"myfile.json\", cfg)\n\tif err != nil {\n\t\tfmt.Printf(\"failed with err: %s\", err)\n\t}\n}\n"
  },
  {
    "path": "ch05/02_advantages/05_math_rand.go",
    "content": "package advantages\n\n// A Rand is a source of random numbers.\ntype Rand struct {\n\tsrc Source\n\n\t// code removed\n}\n\n// Int returns a non-negative pseudo-random int.\nfunc (r *Rand) Int() int {\n\t// code changed for brevity\n\tvalue := r.src.Int63()\n\treturn int(value)\n}\n\n/*\n * Top-level convenience functions\n */\n\nvar globalRand = New(&lockedSource{})\n\n// Int returns a non-negative pseudo-random int from the default Source.\nfunc Int() int { return globalRand.Int() }\n\n/*\n * Code below here has been modified so that it compiles but does nothing.\n * The original code is: https://golang.org/src/math/rand/rand.go\n */\n\n// New returns a new Rand that uses random values from src\n// to generate other random values.\nfunc New(src Source) *Rand {\n\t// code changed for brevity\n\treturn &Rand{\n\t\tsrc: src,\n\t}\n}\n\ntype lockedSource struct {\n\t// code removed\n}\n\nfunc (l *lockedSource) Int63() int64 {\n\t// code removed\n\treturn 0\n}\n\n// A Source represents a source of uniformly-distributed\n// pseudo-random int64 values in the range [0, 1<<63).\ntype Source interface {\n\tInt63() int64\n\n\t// code removed\n}\n"
  },
  {
    "path": "ch05/02_advantages/06_math_rand_test.go",
    "content": "package advantages\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestInt(t *testing.T) {\n\t// monkey patch\n\tdefer func(original *Rand) {\n\t\t// restore patch after use\n\t\tglobalRand = original\n\t}(globalRand)\n\n\t// swap out for a predictable outcome\n\tglobalRand = New(&stubSource{})\n\t// end monkey patch\n\n\t// call the function\n\tresult := Int()\n\tassert.Equal(t, 234, result)\n}\n\n// this is a stubbed implementation of Source that returns a predictable value\ntype stubSource struct {\n}\n\nfunc (s *stubSource) Int63() int64 {\n\treturn 234\n}\n"
  },
  {
    "path": "ch05/03_applying/01_simple_sqlmock_test.go",
    "content": "package applying\n\nimport (\n\t\"database/sql\"\n\t\"testing\"\n\n\t\"github.com/DATA-DOG/go-sqlmock\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestSave_happyPath(t *testing.T) {\n\t// define a mock db\n\ttestDb, dbMock, err := sqlmock.New()\n\trequire.NoError(t, err)\n\n\t// clean up afterwards\n\tdefer testDb.Close()\n\n\t// define the query we are expecting as regular expression\n\tqueryRegex := `\\QINSERT INTO person (fullname, phone, currency, price) VALUES (?, ?, ?, ?)\\E`\n\n\t// configure the mock db\n\tdbMock.ExpectExec(queryRegex).WillReturnResult(sqlmock.NewResult(2, 1))\n\n\t// inputs\n\tperson := &Person{\n\t\tFullName: \"Jake Blues\",\n\t\tPhone:    \"01234567890\",\n\t\tCurrency: \"AUD\",\n\t\tPrice:    123.45,\n\t}\n\n\t// call function\n\tresultID, err := SavePerson(testDb, person)\n\n\t// validate result\n\trequire.NoError(t, err)\n\tassert.Equal(t, 2, resultID)\n\tassert.NoError(t, dbMock.ExpectationsWereMet())\n}\n\nfunc SavePerson(db *sql.DB, in *Person) (int, error) {\n\t// perform DB insert\n\tquery := \"INSERT INTO person (fullname, phone, currency, price) VALUES (?, ?, ?, ?)\"\n\tresult, err := db.Exec(query, in.FullName, in.Phone, in.Currency, in.Price)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\t// retrieve and return the ID of the person created\n\tid, err := result.LastInsertId()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn int(id), nil\n}\n"
  },
  {
    "path": "ch05/03_applying/02_load.go",
    "content": "package applying\n\nimport (\n\t\"database/sql\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/DATA-DOG/go-sqlmock\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nconst (\n\t// SQL statements as constants (to reduce duplication and maintenance in tests)\n\tsqlAllColumns = \"id, fullname, phone, currency, price\"\n\tsqlLoadByID   = \"SELECT \" + sqlAllColumns + \" FROM person WHERE id = ? LIMIT 1\"\n)\n\nfunc TestLoad_happyPath(t *testing.T) {\n\texpectedResult := &Person{\n\t\tID:       2,\n\t\tFullName: \"Paul\",\n\t\tPhone:    \"0123456789\",\n\t\tCurrency: \"CAD\",\n\t\tPrice:    23.45,\n\t}\n\n\t// define a mock db\n\ttestDb, dbMock, err := sqlmock.New()\n\trequire.NoError(t, err)\n\n\t// configure the mock db\n\tqueryRegex := convertSQLToRegex(sqlLoadByID)\n\tdbMock.ExpectQuery(queryRegex).WillReturnRows(\n\t\tsqlmock.NewRows(strings.Split(sqlAllColumns, \", \")).\n\t\t\tAddRow(2, \"Paul\", \"0123456789\", \"CAD\", 23.45))\n\n\t// monkey patching the database\n\tdefer func(original sql.DB) {\n\t\t// restore original DB (after test)\n\t\tdb = &original\n\t}(*db)\n\n\tdb = testDb\n\t// end of monkey patch\n\n\t// call function\n\tresult, err := Load(2)\n\n\t// validate results\n\tassert.Equal(t, expectedResult, result)\n\tassert.NoError(t, err)\n\tassert.NoError(t, dbMock.ExpectationsWereMet())\n}\n\n// convert SQL string to regex by treating the entire query as a literal\nfunc convertSQLToRegex(in string) string {\n\treturn `\\Q` + in + `\\E`\n}\n\n// Load will attempt to load and return a person.\n// It will return ErrNotFound when the requested person does not exist.\n// Any other errors returned are caused by the underlying database or our connection to it.\nfunc Load(ID int) (*Person, error) {\n\t// code removed/faked for brevity\n\treturn &Person{\n\t\tID:       2,\n\t\tFullName: \"Paul\",\n\t\tPhone:    \"0123456789\",\n\t\tCurrency: \"CAD\",\n\t\tPrice:    23.45,\n\t}, nil\n}\n\n// code removed for brevity\nvar db = &sql.DB{}\n\n// Person is the data transfer object (DTO) for this package\ntype Person struct {\n\t// ID is the unique ID for this person\n\tID int\n\t// FullName is the name of this person\n\tFullName string\n\t// Phone is the phone for this person\n\tPhone string\n\t// Currency is the currency this person has paid in\n\tCurrency string\n\t// Price is the amount (in the above currency) paid by this person\n\tPrice float64\n}\n"
  },
  {
    "path": "ch05/04_disadvantages/01_verbose.go",
    "content": "package disadvantages\n\nimport (\n\t\"encoding/json\"\n\t\"io/ioutil\"\n\t\"log\"\n)\n\nfunc SaveConfig(filename string, cfg *Config) error {\n\t// convert to JSON\n\tdata, err := json.Marshal(cfg)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// save file\n\terr = writeFile(filename, data, 0666)\n\tif err != nil {\n\t\tlog.Printf(\"failed to save file '%s' with err: %s\", filename, err)\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// Custom type that allows\nvar writeFile = ioutil.WriteFile\n\ntype Config struct {\n\tHost string\n\tPort int\n}\n"
  },
  {
    "path": "ch05/04_disadvantages/02_verbose_test.go",
    "content": "package disadvantages\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestSaveConfig(t *testing.T) {\n\t// inputs\n\tfilename := \"my-config.json\"\n\tcfg := &Config{\n\t\tHost: \"localhost\",\n\t\tPort: 1234,\n\t}\n\n\t// monkey patch the file writer\n\tdefer func(original func(filename string, data []byte, perm os.FileMode) error) {\n\t\t// restore the original\n\t\twriteFile = original\n\t}(writeFile)\n\n\twriteFile = func(filename string, data []byte, perm os.FileMode) error {\n\t\t// output error\n\t\treturn nil\n\t}\n\n\t// call the function\n\terr := SaveConfig(filename, cfg)\n\n\t// validate the result\n\tassert.NoError(t, err)\n}\n"
  },
  {
    "path": "ch05/04_disadvantages/03_refactored_test.go",
    "content": "package disadvantages\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestSaveConfig_refactored(t *testing.T) {\n\t// inputs\n\tfilename := \"my-config.json\"\n\tcfg := &Config{\n\t\tHost: \"localhost\",\n\t\tPort: 1234,\n\t}\n\n\t// monkey patch the file writer\n\tdefer restoreWriteFile(writeFile)\n\n\twriteFile = mockWriteFile(nil)\n\n\t// call the function\n\terr := SaveConfig(filename, cfg)\n\n\t// validate the result\n\tassert.NoError(t, err)\n}\n\nfunc mockWriteFile(result error) func(filename string, data []byte, perm os.FileMode) error {\n\treturn func(filename string, data []byte, perm os.FileMode) error {\n\t\treturn result\n\t}\n}\n\n// remove the restore function to reduce from 3 lines to 1\nfunc restoreWriteFile(original func(filename string, data []byte, perm os.FileMode) error) {\n\t// restore the original\n\twriteFile = original\n}\n"
  },
  {
    "path": "ch05/acme/internal/config/config.go",
    "content": "package config\n\nimport (\n\t\"encoding/json\"\n\t\"io/ioutil\"\n\t\"os\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch05/acme/internal/logging\"\n)\n\n// DefaultEnvVar is the default environment variable the points to the config file\nconst DefaultEnvVar = \"ACME_CONFIG\"\n\n// App is the application config\nvar App *Config\n\n// Config defines the JSON format for the config file\ntype Config struct {\n\t// DSN is the data source name (format: https://github.com/go-sql-driver/mysql/#dsn-data-source-name)\n\tDSN string\n\n\t// Address is the IP address and port to bind this rest to\n\tAddress string\n\n\t// BasePrice is the price of registration\n\tBasePrice float64\n\n\t// ExchangeRateBaseURL is the server and protocol part of the URL from which to load the exchange rate\n\tExchangeRateBaseURL string\n\n\t// ExchangeRateAPIKey is the API for the exchange rate API\n\tExchangeRateAPIKey string\n}\n\n// Load returns the config loaded from environment\nfunc init() {\n\tfilename, found := os.LookupEnv(DefaultEnvVar)\n\tif !found {\n\t\tlogging.L.Error(\"failed to locate file specified by %s\", DefaultEnvVar)\n\t\treturn\n\t}\n\n\t_ = load(filename)\n}\n\nfunc load(filename string) error {\n\tApp = &Config{}\n\tbytes, err := ioutil.ReadFile(filename)\n\tif err != nil {\n\t\tlogging.L.Error(\"failed to read config file. err: %s\", err)\n\t\treturn err\n\t}\n\n\terr = json.Unmarshal(bytes, App)\n\tif err != nil {\n\t\tlogging.L.Error(\"failed to parse config file. err : %s\", err)\n\t\treturn err\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "ch05/acme/internal/config/config_test.go",
    "content": "package config\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestLoad(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc           string\n\t\tin             string\n\t\texpectedConfig *Config\n\t\texpectError    bool\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tin:   \"../../../../default-config.json\",\n\t\t\texpectedConfig: &Config{\n\t\t\t\tDSN:                 \"[insert your db config here]\",\n\t\t\t\tAddress:             \"0.0.0.0:8080\",\n\t\t\t\tBasePrice:           100.00,\n\t\t\t\tExchangeRateBaseURL: \"http://apilayer.net\",\n\t\t\t\tExchangeRateAPIKey:  \"[insert your API key here]\",\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tdesc:           \"invalid path\",\n\t\t\tin:             \"invalid.json\",\n\t\t\texpectedConfig: &Config{},\n\t\t\texpectError:    true,\n\t\t},\n\t}\n\n\tfor _, s := range scenarios {\n\t\tscenario := s\n\t\tt.Run(scenario.desc, func(t *testing.T) {\n\t\t\tresultErr := load(scenario.in)\n\t\t\trequire.Equal(t, scenario.expectError, resultErr != nil, \"err: %s\", resultErr)\n\t\t\tassert.Equal(t, scenario.expectedConfig, App, scenario.desc)\n\t\t})\n\t}\n\n}\n"
  },
  {
    "path": "ch05/acme/internal/logging/logging.go",
    "content": "package logging\n\nimport (\n\t\"fmt\"\n)\n\n// L is the global instance of the logger\nvar L = &LoggerStdOut{}\n\n// LoggerStdOut logs to std out\ntype LoggerStdOut struct{}\n\n// Debug logs messages at DEBUG level\nfunc (l LoggerStdOut) Debug(message string, args ...interface{}) {\n\tfmt.Printf(\"[DEBUG] \"+message, args...)\n}\n\n// Info logs messages at INFO level\nfunc (l LoggerStdOut) Info(message string, args ...interface{}) {\n\tfmt.Printf(\"[INFO] \"+message, args...)\n}\n\n// Warn logs messages at WARN level\nfunc (l LoggerStdOut) Warn(message string, args ...interface{}) {\n\tfmt.Printf(\"[WARN] \"+message, args...)\n}\n\n// Error logs messages at ERROR level\nfunc (l LoggerStdOut) Error(message string, args ...interface{}) {\n\tfmt.Printf(\"[ERROR] \"+message, args...)\n}\n"
  },
  {
    "path": "ch05/acme/internal/modules/data/data.go",
    "content": "package data\n\nimport (\n\t\"database/sql\"\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch05/acme/internal/config\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch05/acme/internal/logging\"\n\t// import the MySQL Driver\n\t_ \"github.com/go-sql-driver/mysql\"\n)\n\nconst (\n\t// default person id (returned on error)\n\tdefaultPersonID = 0\n\n\t// SQL statements as constants (to reduce duplication and maintenance in tests)\n\tsqlAllColumns = \"id, fullname, phone, currency, price\"\n\tsqlInsert     = \"INSERT INTO person (fullname, phone, currency, price) VALUES (?, ?, ?, ?)\"\n\tsqlLoadAll    = \"SELECT \" + sqlAllColumns + \" FROM person\"\n\tsqlLoadByID   = \"SELECT \" + sqlAllColumns + \" FROM person WHERE id = ? LIMIT 1\"\n)\n\nvar (\n\tdb *sql.DB\n\n\t// ErrNotFound is returned when the no records where matched by the query\n\tErrNotFound = errors.New(\"not found\")\n)\n\nvar getDB = func() (*sql.DB, error) {\n\tif db == nil {\n\t\tif config.App == nil {\n\t\t\treturn nil, errors.New(\"config is not initialized\")\n\t\t}\n\n\t\tvar err error\n\t\tdb, err = sql.Open(\"mysql\", config.App.DSN)\n\t\tif err != nil {\n\t\t\t// if the DB cannot be accessed we are dead\n\t\t\tpanic(err.Error())\n\t\t}\n\t}\n\n\treturn db, nil\n}\n\n// Person is the data transfer object (DTO) for this package\ntype Person struct {\n\t// ID is the unique ID for this person\n\tID int\n\t// FullName is the name of this person\n\tFullName string\n\t// Phone is the phone for this person\n\tPhone string\n\t// Currency is the currency this person has paid in\n\tCurrency string\n\t// Price is the amount (in the above currency) paid by this person\n\tPrice float64\n}\n\n// Save will save the supplied person and return the ID of the newly created person or an error.\n// Errors returned are caused by the underlying database or our connection to it.\nfunc Save(in *Person) (int, error) {\n\tdb, err := getDB()\n\tif err != nil {\n\t\tlogging.L.Error(\"failed to get DB connection. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\t// perform DB insert\n\tresult, err := db.Exec(sqlInsert, in.FullName, in.Phone, in.Currency, in.Price)\n\tif err != nil {\n\t\tlogging.L.Error(\"failed to save person into DB. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\t// retrieve and return the ID of the person created\n\tid, err := result.LastInsertId()\n\tif err != nil {\n\t\tlogging.L.Error(\"failed to retrieve id of last saved person. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn int(id), nil\n}\n\n// LoadAll will attempt to load all people in the database\n// It will return ErrNotFound when there are not people in the database\n// Any other errors returned are caused by the underlying database or our connection to it.\nfunc LoadAll() ([]*Person, error) {\n\tdb, err := getDB()\n\tif err != nil {\n\t\tlogging.L.Error(\"failed to get DB connection. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// perform DB select\n\trows, err := db.Query(sqlLoadAll)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer func() {\n\t\t_ = rows.Close()\n\t}()\n\n\tvar out []*Person\n\n\tfor rows.Next() {\n\t\t// retrieve columns and populate the person object\n\t\trecord, err := populatePerson(rows.Scan)\n\t\tif err != nil {\n\t\t\tlogging.L.Error(\"failed to convert query result. err: %s\", err)\n\t\t\treturn nil, err\n\t\t}\n\n\t\tout = append(out, record)\n\t}\n\n\tif len(out) == 0 {\n\t\tlogging.L.Warn(\"no people found in the database.\")\n\t\treturn nil, ErrNotFound\n\t}\n\n\treturn out, nil\n}\n\n// Load will attempt to load and return a person.\n// It will return ErrNotFound when the requested person does not exist.\n// Any other errors returned are caused by the underlying database or our connection to it.\nfunc Load(ID int) (*Person, error) {\n\tdb, err := getDB()\n\tif err != nil {\n\t\tlogging.L.Error(\"failed to get DB connection. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// perform DB select\n\trow := db.QueryRow(sqlLoadByID, ID)\n\n\t// retrieve columns and populate the person object\n\tout, err := populatePerson(row.Scan)\n\tif err != nil {\n\t\tif err == sql.ErrNoRows {\n\t\t\tlogging.L.Warn(\"failed to load requested person '%d'. err: %s\", ID, err)\n\t\t\treturn nil, ErrNotFound\n\t\t}\n\n\t\tlogging.L.Error(\"failed to convert query result. err: %s\", err)\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\n// custom type so we can convert sql results to easily\ntype scanner func(dest ...interface{}) error\n\n// reduce the duplication (and maintenance) between sql.Row and sql.Rows usage\nfunc populatePerson(scanner scanner) (*Person, error) {\n\tout := &Person{}\n\terr := scanner(&out.ID, &out.FullName, &out.Phone, &out.Currency, &out.Price)\n\treturn out, err\n}\n\nfunc init() {\n\t// ensure the config is loaded and the db initialized\n\t_, _ = getDB()\n}\n"
  },
  {
    "path": "ch05/acme/internal/modules/data/data_test.go",
    "content": "package data\n\nimport (\n\t\"database/sql\"\n\t\"errors\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/DATA-DOG/go-sqlmock\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestSave_happyPath(t *testing.T) {\n\t// define a mock db\n\ttestDb, dbMock, err := sqlmock.New()\n\tdefer testDb.Close()\n\trequire.NoError(t, err)\n\n\t// configure the mock db\n\tqueryRegex := convertSQLToRegex(sqlInsert)\n\tdbMock.ExpectExec(queryRegex).WillReturnResult(sqlmock.NewResult(2, 1))\n\n\t// monkey patching starts here\n\tdefer func(original sql.DB) {\n\t\t// restore original DB (after test)\n\t\tdb = &original\n\t}(*db)\n\n\t// replace db for this test\n\tdb = testDb\n\t// end of monkey patch\n\n\t// inputs\n\tin := &Person{\n\t\tFullName: \"Jake Blues\",\n\t\tPhone:    \"01234567890\",\n\t\tCurrency: \"AUD\",\n\t\tPrice:    123.45,\n\t}\n\n\t// call function\n\tresultID, err := Save(in)\n\n\t// validate result\n\trequire.NoError(t, err)\n\tassert.Equal(t, 2, resultID)\n\tassert.NoError(t, dbMock.ExpectationsWereMet())\n}\n\nfunc TestSave_insertError(t *testing.T) {\n\t// define a mock db\n\ttestDb, dbMock, err := sqlmock.New()\n\tdefer testDb.Close()\n\n\trequire.NoError(t, err)\n\n\t// configure the mock db\n\tqueryRegex := convertSQLToRegex(sqlInsert)\n\tdbMock.ExpectExec(queryRegex).WillReturnError(errors.New(\"failed to insert\"))\n\n\t// monkey patching starts here\n\tdefer func(original sql.DB) {\n\t\t// restore original DB (after test)\n\t\tdb = &original\n\t}(*db)\n\n\t// replace db for this test\n\tdb = testDb\n\t// end of monkey patch\n\n\t// inputs\n\tin := &Person{\n\t\tFullName: \"Jake Blues\",\n\t\tPhone:    \"01234567890\",\n\t\tCurrency: \"AUD\",\n\t\tPrice:    123.45,\n\t}\n\n\t// call function\n\tresultID, err := Save(in)\n\n\t// validate result\n\trequire.Error(t, err)\n\tassert.Equal(t, defaultPersonID, resultID)\n\tassert.NoError(t, dbMock.ExpectationsWereMet())\n}\n\nfunc TestSave_getDBError(t *testing.T) {\n\t// monkey patching starts here\n\tdefer func(original func() (*sql.DB, error)) {\n\t\t// restore original DB (after test)\n\t\tgetDB = original\n\t}(getDB)\n\n\t// replace getDB() function for this test\n\tgetDB = func() (*sql.DB, error) {\n\t\treturn nil, errors.New(\"getDB() failed\")\n\t}\n\t// end of monkey patch\n\n\t// inputs\n\tin := &Person{\n\t\tFullName: \"Jake Blues\",\n\t\tPhone:    \"01234567890\",\n\t\tCurrency: \"AUD\",\n\t\tPrice:    123.45,\n\t}\n\n\t// call function\n\tresultID, err := Save(in)\n\trequire.Error(t, err)\n\tassert.Equal(t, defaultPersonID, resultID)\n}\n\nfunc TestLoadAll_tableDrivenTest(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc            string\n\t\tconfigureMockDB func(sqlmock.Sqlmock)\n\t\texpectedResults []*Person\n\t\texpectError     bool\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tconfigureMockDB: func(dbMock sqlmock.Sqlmock) {\n\t\t\t\tqueryRegex := convertSQLToRegex(sqlLoadAll)\n\t\t\t\tdbMock.ExpectQuery(queryRegex).WillReturnRows(\n\t\t\t\t\tsqlmock.NewRows(strings.Split(sqlAllColumns, \", \")).\n\t\t\t\t\t\tAddRow(1, \"John\", \"0123456789\", \"AUD\", 12.34))\n\t\t\t},\n\t\t\texpectedResults: []*Person{\n\t\t\t\t{\n\t\t\t\t\tID:       1,\n\t\t\t\t\tFullName: \"John\",\n\t\t\t\t\tPhone:    \"0123456789\",\n\t\t\t\t\tCurrency: \"AUD\",\n\t\t\t\t\tPrice:    12.34,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tdesc: \"load error\",\n\t\t\tconfigureMockDB: func(dbMock sqlmock.Sqlmock) {\n\t\t\t\tqueryRegex := convertSQLToRegex(sqlLoadAll)\n\t\t\t\tdbMock.ExpectQuery(queryRegex).WillReturnError(errors.New(\"something failed\"))\n\t\t\t},\n\t\t\texpectedResults: nil,\n\t\t\texpectError:     true,\n\t\t},\n\t}\n\n\tfor _, scenario := range scenarios {\n\t\t// define a mock db\n\t\ttestDb, dbMock, err := sqlmock.New()\n\t\trequire.NoError(t, err)\n\n\t\t// configure the mock db\n\t\tscenario.configureMockDB(dbMock)\n\n\t\t// monkey patch the db for this test\n\t\toriginal := *db\n\t\tdb = testDb\n\n\t\t// call function\n\t\tresults, err := LoadAll()\n\n\t\t// validate results\n\t\tassert.Equal(t, scenario.expectedResults, results, scenario.desc)\n\t\tassert.Equal(t, scenario.expectError, err != nil, scenario.desc)\n\t\tassert.NoError(t, dbMock.ExpectationsWereMet())\n\n\t\t// restore original DB (after test)\n\t\tdb = &original\n\t\ttestDb.Close()\n\t}\n}\n\nfunc TestLoad_tableDrivenTest(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc            string\n\t\tconfigureMockDB func(sqlmock.Sqlmock)\n\t\texpectedResult  *Person\n\t\texpectError     bool\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tconfigureMockDB: func(dbMock sqlmock.Sqlmock) {\n\t\t\t\tqueryRegex := convertSQLToRegex(sqlLoadAll)\n\t\t\t\tdbMock.ExpectQuery(queryRegex).WillReturnRows(\n\t\t\t\t\tsqlmock.NewRows(strings.Split(sqlAllColumns, \", \")).\n\t\t\t\t\t\tAddRow(2, \"Paul\", \"0123456789\", \"CAD\", 23.45))\n\t\t\t},\n\t\t\texpectedResult: &Person{\n\t\t\t\tID:       2,\n\t\t\t\tFullName: \"Paul\",\n\t\t\t\tPhone:    \"0123456789\",\n\t\t\t\tCurrency: \"CAD\",\n\t\t\t\tPrice:    23.45,\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tdesc: \"load error\",\n\t\t\tconfigureMockDB: func(dbMock sqlmock.Sqlmock) {\n\t\t\t\tqueryRegex := convertSQLToRegex(sqlLoadAll)\n\t\t\t\tdbMock.ExpectQuery(queryRegex).WillReturnError(errors.New(\"something failed\"))\n\t\t\t},\n\t\t\texpectedResult: nil,\n\t\t\texpectError:    true,\n\t\t},\n\t}\n\n\tfor _, scenario := range scenarios {\n\t\t// define a mock db\n\t\ttestDb, dbMock, err := sqlmock.New()\n\t\trequire.NoError(t, err)\n\n\t\t// configure the mock db\n\t\tscenario.configureMockDB(dbMock)\n\n\t\t// monkey db for this test\n\t\toriginal := *db\n\t\tdb = testDb\n\n\t\t// call function\n\t\tresult, err := Load(2)\n\n\t\t// validate results\n\t\tassert.Equal(t, scenario.expectedResult, result, scenario.desc)\n\t\tassert.Equal(t, scenario.expectError, err != nil, scenario.desc)\n\t\tassert.NoError(t, dbMock.ExpectationsWereMet())\n\n\t\t// restore original DB (after test)\n\t\tdb = &original\n\t\ttestDb.Close()\n\t}\n}\n\n// convert SQL string to regex by treating the entire query as a literal\nfunc convertSQLToRegex(in string) string {\n\treturn `\\Q` + in + `\\E`\n}\n"
  },
  {
    "path": "ch05/acme/internal/modules/exchange/converter.go",
    "content": "package exchange\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"math\"\n\t\"net/http\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch05/acme/internal/config\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch05/acme/internal/logging\"\n)\n\nconst (\n\t// request URL for the exchange rate API\n\turlFormat = \"%s/api/historical?access_key=%s&date=2018-06-20&currencies=%s\"\n\n\t// default price that is sent when an error occurs\n\tdefaultPrice = 0.0\n)\n\n// Converter will convert the base price to the currency supplied\n// Note: we are expecting sane inputs and therefore skipping input validation\ntype Converter struct{}\n\n// Do will perform the conversion\nfunc (c *Converter) Do(basePrice float64, currency string) (float64, error) {\n\t// load rate from the external API\n\tresponse, err := c.loadRateFromServer(currency)\n\tif err != nil {\n\t\treturn defaultPrice, err\n\t}\n\n\t// extract rate from response\n\trate, err := c.extractRate(response, currency)\n\tif err != nil {\n\t\treturn defaultPrice, err\n\t}\n\n\t// apply rate and round to 2 decimal places\n\treturn math.Floor((basePrice/rate)*100) / 100, nil\n}\n\n// load rate from the external API\nfunc (c *Converter) loadRateFromServer(currency string) (*http.Response, error) {\n\t// build the request\n\turl := fmt.Sprintf(urlFormat,\n\t\tconfig.App.ExchangeRateBaseURL,\n\t\tconfig.App.ExchangeRateAPIKey,\n\t\tcurrency)\n\n\t// perform request\n\tresponse, err := http.Get(url)\n\tif err != nil {\n\t\tlogging.L.Warn(\"[exchange] failed to load. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\tif response.StatusCode != http.StatusOK {\n\t\terr = fmt.Errorf(\"request failed with code %d\", response.StatusCode)\n\t\tlogging.L.Warn(\"[exchange] %s\", err)\n\t\treturn nil, err\n\t}\n\n\treturn response, nil\n}\n\nfunc (c *Converter) extractRate(response *http.Response, currency string) (float64, error) {\n\tdefer func() {\n\t\t_ = response.Body.Close()\n\t}()\n\n\t// extract data from response\n\tdata, err := c.extractResponse(response)\n\tif err != nil {\n\t\treturn defaultPrice, err\n\t}\n\n\t// pull rate from response data\n\trate, found := data.Quotes[\"USD\"+currency]\n\tif !found {\n\t\terr = fmt.Errorf(\"response did not include expected currency '%s'\", currency)\n\t\tlogging.L.Error(\"[exchange] %s\", err)\n\t\treturn defaultPrice, err\n\t}\n\n\t// happy path\n\treturn rate, nil\n}\n\nfunc (c *Converter) extractResponse(response *http.Response) (*apiResponseFormat, error) {\n\tpayload, err := ioutil.ReadAll(response.Body)\n\tif err != nil {\n\t\tlogging.L.Error(\"[exchange] failed to ready response body. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\tdata := &apiResponseFormat{}\n\terr = json.Unmarshal(payload, data)\n\tif err != nil {\n\t\tlogging.L.Error(\"[exchange] error converting response. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// happy path\n\treturn data, nil\n}\n\n// the response format from the exchange rate API\ntype apiResponseFormat struct {\n\tQuotes map[string]float64 `json:\"quotes\"`\n}\n"
  },
  {
    "path": "ch05/acme/internal/modules/get/get.go",
    "content": "package get\n\nimport (\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch05/acme/internal/modules/data\"\n)\n\nvar (\n\t// error thrown when the requested person is not in the database\n\terrPersonNotFound = errors.New(\"person not found\")\n)\n\n// Getter will attempt to load a person.\n// It can return an error caused by the data layer or when the requested person is not found\ntype Getter struct {\n}\n\n// Do will perform the get\nfunc (g *Getter) Do(ID int) (*data.Person, error) {\n\t// load person from the data layer\n\tperson, err := loader(ID)\n\tif err != nil {\n\t\tif err == data.ErrNotFound {\n\t\t\t// By converting the error we are hiding the implementation details from our users.\n\t\t\treturn nil, errPersonNotFound\n\t\t}\n\t\treturn nil, err\n\t}\n\n\treturn person, err\n}\n\n// this function as a variable allows us to Monkey Patch during testing\nvar loader = data.Load\n"
  },
  {
    "path": "ch05/acme/internal/modules/get/go_test.go",
    "content": "package get\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch05/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestGetter_Do_happyPath(t *testing.T) {\n\t// inputs\n\tID := 1234\n\n\t// monkey patch calls to the data package\n\tdefer func(original func(ID int) (*data.Person, error)) {\n\t\t// restore original\n\t\tloader = original\n\t}(loader)\n\n\t// replace method\n\tloader = func(ID int) (*data.Person, error) {\n\t\tresult := &data.Person{\n\t\t\tID:       1234,\n\t\t\tFullName: \"Doug\",\n\t\t}\n\t\tvar resultErr error\n\n\t\treturn result, resultErr\n\t}\n\t// end of monkey patch\n\n\t// call method\n\tgetter := &Getter{}\n\tperson, err := getter.Do(ID)\n\n\t// validate expectations\n\trequire.NoError(t, err)\n\tassert.Equal(t, ID, person.ID)\n\tassert.Equal(t, \"Doug\", person.FullName)\n}\n\nfunc TestGetter_Do_noSuchPerson(t *testing.T) {\n\t// inputs\n\tID := 5678\n\n\t// monkey patch calls to the data package\n\tdefer func(original func(ID int) (*data.Person, error)) {\n\t\t// restore original\n\t\tloader = original\n\t}(loader)\n\n\t// replace method\n\tloader = func(ID int) (*data.Person, error) {\n\t\tvar result *data.Person\n\t\tresultErr := data.ErrNotFound\n\n\t\treturn result, resultErr\n\t}\n\t// end of monkey patch\n\n\t// call method\n\tgetter := &Getter{}\n\tperson, err := getter.Do(ID)\n\n\t// validate expectations\n\trequire.Equal(t, errPersonNotFound, err)\n\tassert.Nil(t, person)\n}\n\nfunc TestGetter_Do_error(t *testing.T) {\n\t// inputs\n\tID := 1234\n\n\t// monkey patch calls to the data package\n\tdefer func(original func(ID int) (*data.Person, error)) {\n\t\t// restore original\n\t\tloader = original\n\t}(loader)\n\n\t// replace method\n\tloader = func(ID int) (*data.Person, error) {\n\t\tvar result *data.Person\n\t\tresultErr := errors.New(\"failed to load person\")\n\n\t\treturn result, resultErr\n\t}\n\t// end of monkey patch\n\n\t// call method\n\tgetter := &Getter{}\n\tperson, err := getter.Do(ID)\n\n\t// validate expectations\n\trequire.Error(t, err)\n\tassert.Nil(t, person)\n}\n"
  },
  {
    "path": "ch05/acme/internal/modules/list/list.go",
    "content": "package list\n\nimport (\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch05/acme/internal/modules/data\"\n)\n\nvar (\n\t// error thrown when there are no people in the database\n\terrPeopleNotFound = errors.New(\"no people found\")\n)\n\n// Lister will attempt to load all people in the database.\n// It can return an error caused by the data layer\ntype Lister struct {\n}\n\n// Do will load the people from the data layer\nfunc (l *Lister) Do() ([]*data.Person, error) {\n\t// load all people\n\tpeople, err := l.load()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(people) == 0 {\n\t\t// special processing for 0 people returned\n\t\treturn nil, errPeopleNotFound\n\t}\n\n\treturn people, nil\n}\n\n// load all people\nfunc (l *Lister) load() ([]*data.Person, error) {\n\tpeople, err := loader()\n\tif err != nil {\n\t\tif err == data.ErrNotFound {\n\t\t\t// By converting the error we are encapsulating the implementation details from our users.\n\t\t\treturn nil, errPeopleNotFound\n\t\t}\n\t\treturn nil, err\n\t}\n\n\treturn people, nil\n}\n\n// this function as a variable allows us to Monkey Patch during testing\nvar loader = data.LoadAll\n"
  },
  {
    "path": "ch05/acme/internal/modules/list/list_test.go",
    "content": "package list\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch05/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestLister_Do_happyPath(t *testing.T) {\n\t// monkey patch calls to the data package\n\tdefer func(original func() ([]*data.Person, error)) {\n\t\t// restore original\n\t\tloader = original\n\t}(loader)\n\n\t// replace method\n\tloader = func() ([]*data.Person, error) {\n\t\tresult := []*data.Person{\n\t\t\t{\n\t\t\t\tID:       1234,\n\t\t\t\tFullName: \"Sally\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tID:       5678,\n\t\t\t\tFullName: \"Jane\",\n\t\t\t},\n\t\t}\n\t\tvar resultErr error\n\n\t\treturn result, resultErr\n\t}\n\t// end of monkey patch\n\n\t// call method\n\tlister := &Lister{}\n\tpersons, err := lister.load()\n\n\t// validate expectations\n\trequire.NoError(t, err)\n\tassert.Equal(t, 2, len(persons))\n}\n\nfunc TestLister_Do_noResults(t *testing.T) {\n\t// monkey patch calls to the data package\n\tdefer func(original func() ([]*data.Person, error)) {\n\t\t// restore original\n\t\tloader = original\n\t}(loader)\n\n\t// replace method\n\tloader = func() ([]*data.Person, error) {\n\t\tvar result []*data.Person\n\t\tresultErr := data.ErrNotFound\n\n\t\treturn result, resultErr\n\t}\n\t// end of monkey patch\n\n\t// call method\n\tlister := &Lister{}\n\tpersons, err := lister.load()\n\n\t// validate expectations\n\trequire.Equal(t, errPeopleNotFound, err)\n\tassert.Equal(t, 0, len(persons))\n}\n\nfunc TestLister_Do_error(t *testing.T) {\n\t// monkey patch calls to the data package\n\tdefer func(original func() ([]*data.Person, error)) {\n\t\t// restore original\n\t\tloader = original\n\t}(loader)\n\n\t// replace method\n\tloader = func() ([]*data.Person, error) {\n\t\tvar result []*data.Person\n\t\tresultErr := errors.New(\"failed to load people\")\n\n\t\treturn result, resultErr\n\t}\n\t// end of monkey patch\n\n\t// call method\n\tlister := &Lister{}\n\tpersons, err := lister.load()\n\n\t// validate expectations\n\trequire.Error(t, err)\n\tassert.Equal(t, 0, len(persons))\n}\n"
  },
  {
    "path": "ch05/acme/internal/modules/register/register.go",
    "content": "package register\n\nimport (\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch05/acme/internal/config\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch05/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch05/acme/internal/modules/data\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch05/acme/internal/modules/exchange\"\n)\n\nconst (\n\t// default person id (returned on error)\n\tdefaultPersonID = 0\n)\n\nvar (\n\t// validation errors\n\terrNameMissing     = errors.New(\"name is missing\")\n\terrPhoneMissing    = errors.New(\"phone is missing\")\n\terrCurrencyMissing = errors.New(\"currency is missing\")\n\terrInvalidCurrency = errors.New(\"currency is invalid, supported types are AUD, CNY, EUR, GBP, JPY, MYR, SGD, USD\")\n\n\t// a little trick to make checking for supported currencies easier\n\tsupportedCurrencies = map[string]struct{}{\n\t\t\"AUD\": {},\n\t\t\"CNY\": {},\n\t\t\"EUR\": {},\n\t\t\"GBP\": {},\n\t\t\"JPY\": {},\n\t\t\"MYR\": {},\n\t\t\"SGD\": {},\n\t\t\"USD\": {},\n\t}\n)\n\n// Registerer validates the supplied person, calculates the price in the requested currency and saves the result.\n// It will return an error when:\n// -the person object does not include all the fields\n// -the currency is invalid\n// -the exchange rate cannot be loaded\n// -the data layer throws an error.\ntype Registerer struct {\n}\n\n// Do is API for this struct\nfunc (r *Registerer) Do(in *data.Person) (int, error) {\n\t// validate the request\n\terr := r.validateInput(in)\n\tif err != nil {\n\t\tlogging.L.Warn(\"input validation failed with err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\t// get price in the requested currency\n\tprice, err := r.getPrice(in.Currency)\n\tif err != nil {\n\t\treturn defaultPersonID, err\n\t}\n\n\t// save registration\n\tid, err := r.save(in, price)\n\tif err != nil {\n\t\t// no need to log here as we expect the data layer to do so\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn id, nil\n}\n\n// validate input and return error on fail\nfunc (r *Registerer) validateInput(in *data.Person) error {\n\tif in.FullName == \"\" {\n\t\treturn errNameMissing\n\t}\n\tif in.Phone == \"\" {\n\t\treturn errPhoneMissing\n\t}\n\tif in.Currency == \"\" {\n\t\treturn errCurrencyMissing\n\t}\n\n\tif _, found := supportedCurrencies[in.Currency]; !found {\n\t\treturn errInvalidCurrency\n\t}\n\n\t// happy path\n\treturn nil\n}\n\n// get price in the requested currency\nfunc (r *Registerer) getPrice(currency string) (float64, error) {\n\tconverter := &exchange.Converter{}\n\tprice, err := converter.Do(config.App.BasePrice, currency)\n\tif err != nil {\n\t\tlogging.L.Warn(\"failed to convert the price. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn price, nil\n}\n\n// save the registration\nfunc (r *Registerer) save(in *data.Person, price float64) (int, error) {\n\tperson := &data.Person{\n\t\tFullName: in.FullName,\n\t\tPhone:    in.Phone,\n\t\tCurrency: in.Currency,\n\t\tPrice:    price,\n\t}\n\treturn saver(person)\n}\n\n// this function as a variable allows us to Monkey Patch during testing\nvar saver = data.Save\n"
  },
  {
    "path": "ch05/acme/internal/modules/register/register_test.go",
    "content": "package register\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch05/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestRegisterer_Do_happyPath(t *testing.T) {\n\t// monkey patch calls to the data package\n\tdefer func(original func(in *data.Person) (int, error)) {\n\t\t// restore original\n\t\tsaver = original\n\t}(saver)\n\n\t// replace method\n\tsaver = func(in *data.Person) (int, error) {\n\t\tresult := 888\n\t\tvar resultErr error\n\n\t\treturn result, resultErr\n\t}\n\t// end of monkey patch\n\n\t// inputs\n\tin := &data.Person{\n\t\tFullName: \"Chang\",\n\t\tPhone:    \"11122233355\",\n\t\tCurrency: \"CNY\",\n\t}\n\n\t// call method\n\tregisterer := &Registerer{}\n\tID, err := registerer.Do(in)\n\n\t// validate expectations\n\trequire.NoError(t, err)\n\tassert.Equal(t, 888, ID)\n}\n\nfunc TestRegisterer_Do_error(t *testing.T) {\n\t// monkey patch calls to the data package\n\tdefer func(original func(in *data.Person) (int, error)) {\n\t\t// restore original\n\t\tsaver = original\n\t}(saver)\n\n\t// replace method\n\tsaver = func(in *data.Person) (int, error) {\n\t\tvar result int\n\t\tresultErr := errors.New(\"failed to save\")\n\n\t\treturn result, resultErr\n\t}\n\t// end of monkey patch\n\n\t// inputs\n\tin := &data.Person{\n\t\tFullName: \"Chang\",\n\t\tPhone:    \"11122233355\",\n\t\tCurrency: \"CNY\",\n\t}\n\n\t// call method\n\tregisterer := &Registerer{}\n\tID, err := registerer.Do(in)\n\n\t// validate expectations\n\trequire.Error(t, err)\n\tassert.Equal(t, 0, ID)\n}\n"
  },
  {
    "path": "ch05/acme/internal/rest/common_test.go",
    "content": "package rest\n\nimport (\n\t\"context\"\n\t\"net\"\n)\n\nfunc getOpenPort() (string, error) {\n\tlistener, err := net.Listen(\"tcp\", \"127.0.0.1:0\")\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\taddress := listener.Addr().String()\n\tlistener.Close()\n\n\treturn address, nil\n}\n\nfunc startServer(ctx context.Context) (string, error) {\n\t// get open port\n\taddress, err := getOpenPort()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\t// start a server\n\tserver := New(address)\n\tgo server.Listen(ctx.Done())\n\n\t// wait for server to be ready\n\tdialer := &net.Dialer{}\n\tfor {\n\t\tconn, _ := dialer.DialContext(ctx, \"tcp\", address)\n\t\tif conn != nil {\n\t\t\tdefer conn.Close()\n\n\t\t\treturn address, nil\n\t\t}\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn \"\", ctx.Err()\n\n\t\tdefault:\n\t\t\t// try again\n\t\t}\n\t}\n\n\treturn address, nil\n}\n"
  },
  {
    "path": "ch05/acme/internal/rest/get.go",
    "content": "package rest\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch05/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch05/acme/internal/modules/data\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch05/acme/internal/modules/get\"\n\t\"github.com/gorilla/mux\"\n)\n\nconst (\n\t// default person id (returned on error)\n\tdefaultPersonID = 0\n)\n\n// GetHandler is the HTTP handler for the \"Get Person\" endpoint\n// In this simplified example we are assuming all possible errors are user errors and returning \"bad request\" HTTP 400\n// or \"not found\" HTTP 404\n// There are some programmer errors possible but hopefully these will be caught in testing.\ntype GetHandler struct {\n}\n\n// ServeHTTP implements http.Handler\nfunc (h *GetHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\t// extract person id from request\n\tid, err := h.extractID(request)\n\tif err != nil {\n\t\t// output error\n\t\tresponse.WriteHeader(http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// attempt get\n\tgetter := get.Getter{}\n\tperson, err := getter.Do(id)\n\tif err != nil {\n\t\t// not need to log here as we can expect other layers to do so\n\t\tresponse.WriteHeader(http.StatusNotFound)\n\t\treturn\n\t}\n\n\t// happy path\n\terr = h.writeJSON(response, person)\n\tif err != nil {\n\t\t// this error should not happen but if it does there is nothing we can do to recover\n\t\tresponse.WriteHeader(http.StatusInternalServerError)\n\t}\n}\n\n// extract the person ID from the request\nfunc (h *GetHandler) extractID(request *http.Request) (int, error) {\n\t// ID is part of the URL, so we extract it from there\n\tvars := mux.Vars(request)\n\tidAsString, exists := vars[\"id\"]\n\tif !exists {\n\t\t// log and return error\n\t\terr := errors.New(\"[get] person id missing from request\")\n\t\tlogging.L.Warn(err.Error())\n\t\treturn defaultPersonID, err\n\t}\n\n\t// convert ID to int\n\tid, err := strconv.Atoi(idAsString)\n\tif err != nil {\n\t\t// log and return error\n\t\terr = fmt.Errorf(\"[get] failed to convert person id into a number. err: %s\", err)\n\t\tlogging.L.Error(err.Error())\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn id, nil\n}\n\n// output the supplied person as JSON\nfunc (h *GetHandler) writeJSON(writer io.Writer, person *data.Person) error {\n\toutput := &getResponseFormat{\n\t\tID:       person.ID,\n\t\tFullName: person.FullName,\n\t\tPhone:    person.Phone,\n\t\tCurrency: person.Currency,\n\t\tPrice:    person.Price,\n\t}\n\n\t// call to http.ResponseWriter.Write() will cause HTTP OK (200) to be output as well\n\treturn json.NewEncoder(writer).Encode(output)\n}\n\n// the JSON response format\ntype getResponseFormat struct {\n\tID       int     `json:\"id\"`\n\tFullName string  `json:\"name\"`\n\tPhone    string  `json:\"phone\"`\n\tCurrency string  `json:\"currency\"`\n\tPrice    float64 `json:\"price\"`\n}\n"
  },
  {
    "path": "ch05/acme/internal/rest/get_test.go",
    "content": "package rest\n\nimport (\n\t\"context\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestGetHandler_ServeHTTP(t *testing.T) {\n\t// ensure the test always fails by giving it a timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n\tdefer cancel()\n\n\t// Create and start a server\n\t// With out current implementation, we cannot test this handler without a full server as we need the mux.\n\taddress, err := startServer(ctx)\n\trequire.NoError(t, err)\n\n\t// build inputs\n\tresponse, err := http.Get(\"http://\" + address + \"/person/1/\")\n\n\t// validate outputs\n\trequire.NoError(t, err)\n\trequire.Equal(t, http.StatusOK, response.StatusCode)\n\n\texpectedPayload := []byte(`{\"id\":1,\"name\":\"John\",\"phone\":\"0123456780\",\"currency\":\"USD\",\"price\":100}` + \"\\n\")\n\tpayload, _ := ioutil.ReadAll(response.Body)\n\tdefer response.Body.Close()\n\n\tassert.Equal(t, expectedPayload, payload)\n}\n"
  },
  {
    "path": "ch05/acme/internal/rest/list.go",
    "content": "package rest\n\nimport (\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch05/acme/internal/modules/data\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch05/acme/internal/modules/list\"\n)\n\n// ListHandler is the HTTP handler for the \"List Do people\" endpoint\n// In this simplified example we are assuming all possible errors are system errors (HTTP 500)\ntype ListHandler struct {\n}\n\n// ServeHTTP implements http.Handler\nfunc (h *ListHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\t// attempt loadAll\n\tlister := list.Lister{}\n\tpeople, err := lister.Do()\n\tif err != nil {\n\t\t// not need to log here as we can expect other layers to do so\n\t\tresponse.WriteHeader(http.StatusNotFound)\n\t\treturn\n\t}\n\n\t// happy path\n\terr = h.writeJSON(response, people)\n\tif err != nil {\n\t\t// this error should not happen but if it does there is nothing we can do to recover\n\t\tresponse.WriteHeader(http.StatusInternalServerError)\n\t}\n}\n\n// output the result as JSON\nfunc (h *ListHandler) writeJSON(writer io.Writer, people []*data.Person) error {\n\toutput := &listResponseFormat{\n\t\tPeople: make([]*listResponseItemFormat, len(people)),\n\t}\n\n\tfor index, record := range people {\n\t\toutput.People[index] = &listResponseItemFormat{\n\t\t\tID:       record.ID,\n\t\t\tFullName: record.FullName,\n\t\t\tPhone:    record.Phone,\n\t\t}\n\t}\n\n\t// call to http.ResponseWriter.Write() will cause HTTP OK (200) to be output as well\n\treturn json.NewEncoder(writer).Encode(output)\n}\n\ntype listResponseFormat struct {\n\tPeople []*listResponseItemFormat `json:\"people\"`\n}\n\ntype listResponseItemFormat struct {\n\tID       int    `json:\"id\"`\n\tFullName string `json:\"name\"`\n\tPhone    string `json:\"phone\"`\n}\n"
  },
  {
    "path": "ch05/acme/internal/rest/list_test.go",
    "content": "package rest\n\nimport (\n\t\"context\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestListHandler_ServeHTTP(t *testing.T) {\n\t// ensure the test always fails by giving it a timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n\tdefer cancel()\n\n\t// Create and start a server\n\t// With out current implementation, we cannot test this handler without a full server as we need the mux.\n\taddress, err := startServer(ctx)\n\trequire.NoError(t, err)\n\n\t// build inputs\n\tresponse, err := http.Get(\"http://\" + address + \"/person/list\")\n\n\t// validate outputs\n\trequire.NoError(t, err)\n\trequire.Equal(t, http.StatusOK, response.StatusCode)\n\n\texpectedPayload := []byte(`{\"people\":[{\"id\":1,\"name\":\"John\",\"phone\":\"0123456780\"},{\"id\":2,\"name\":\"Paul\",\"phone\":\"0123456781\"},{\"id\":3,\"name\":\"George\",\"phone\":\"0123456782\"},{\"id\":4,\"name\":\"Ringo\",\"phone\":\"0123456783\"}`)\n\tpayload, _ := ioutil.ReadAll(response.Body)\n\tdefer response.Body.Close()\n\n\t// we have to use contains because other tests add more records\n\tassert.Contains(t, string(payload), string(expectedPayload))\n}\n"
  },
  {
    "path": "ch05/acme/internal/rest/not_found.go",
    "content": "package rest\n\nimport (\n\t\"net/http\"\n)\n\nfunc notFoundHandler(response http.ResponseWriter, _ *http.Request) {\n\tresponse.WriteHeader(http.StatusNotFound)\n\t_, _ = response.Write([]byte(`Not found`))\n}\n"
  },
  {
    "path": "ch05/acme/internal/rest/not_found_test.go",
    "content": "package rest\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestNotFoundHandler_ServeHTTP(t *testing.T) {\n\t// ensure the test always fails by giving it a timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n\tdefer cancel()\n\n\t// Create and start a server\n\t// With out current implementation, we cannot test this handler without a full server as we need the mux.\n\taddress, err := startServer(ctx)\n\trequire.NoError(t, err)\n\n\t// build inputs\n\tresponse, err := http.Get(\"http://\" + address + \"/some-bad-address\")\n\n\t// validate outputs\n\trequire.NoError(t, err)\n\trequire.Equal(t, http.StatusNotFound, response.StatusCode)\n}\n"
  },
  {
    "path": "ch05/acme/internal/rest/register.go",
    "content": "package rest\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch05/acme/internal/modules/data\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch05/acme/internal/modules/register\"\n)\n\n// RegisterHandler is the HTTP handler for the \"Register\" endpoint\n// In this simplified example we are assuming all possible errors are user errors and returning \"bad request\" HTTP 400.\n// There are some programmer errors possible but hopefully these will be caught in testing.\ntype RegisterHandler struct {\n}\n\n// ServeHTTP implements http.Handler\nfunc (h *RegisterHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\t// extract payload from request\n\trequestPayload, err := h.extractPayload(request)\n\tif err != nil {\n\t\t// output error\n\t\tresponse.WriteHeader(http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// register person\n\tid, err := h.register(requestPayload)\n\tif err != nil {\n\t\t// not need to log here as we can expect other layers to do so\n\t\tresponse.WriteHeader(http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// happy path\n\tresponse.Header().Add(\"Location\", fmt.Sprintf(\"/person/%d/\", id))\n\tresponse.WriteHeader(http.StatusCreated)\n}\n\n// extract payload from request\nfunc (h *RegisterHandler) extractPayload(request *http.Request) (*registerRequest, error) {\n\trequestPayload := &registerRequest{}\n\n\tdecoder := json.NewDecoder(request.Body)\n\terr := decoder.Decode(requestPayload)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn requestPayload, nil\n}\n\n// call the logic layer\nfunc (h *RegisterHandler) register(requestPayload *registerRequest) (int, error) {\n\tperson := &data.Person{\n\t\tFullName: requestPayload.FullName,\n\t\tPhone:    requestPayload.Phone,\n\t\tCurrency: requestPayload.Currency,\n\t}\n\n\tregisterer := &register.Registerer{}\n\treturn registerer.Do(person)\n}\n\n// register endpoint request format\ntype registerRequest struct {\n\t// FullName of the person\n\tFullName string `json:\"fullName\"`\n\t// Phone of the person\n\tPhone string `json:\"phone\"`\n\t// Currency the wish to register in\n\tCurrency string `json:\"currency\"`\n}\n"
  },
  {
    "path": "ch05/acme/internal/rest/register_test.go",
    "content": "package rest\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestRegisterHandler_ServeHTTP(t *testing.T) {\n\t// ensure the test always fails by giving it a timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n\tdefer cancel()\n\n\t// Create and start a server\n\t// With out current implementation, we cannot test this handler without a full server as we need the mux.\n\taddress, err := startServer(ctx)\n\trequire.NoError(t, err)\n\n\t// build inputs\n\tvalidRequest := buildValidRequest()\n\tresponse, err := http.Post(\"http://\"+address+\"/person/register\", \"application/json\", validRequest)\n\n\t// validate outputs\n\trequire.NoError(t, err)\n\trequire.Equal(t, http.StatusCreated, response.StatusCode)\n\tdefer response.Body.Close()\n\n\t// call should output the location to the new person\n\theaderLocation := response.Header.Get(\"Location\")\n\tassert.Contains(t, headerLocation, \"/person/\")\n}\n\nfunc buildValidRequest() io.Reader {\n\trequestData := &registerRequest{\n\t\tFullName: \"Joan Smith\",\n\t\tCurrency: \"AUD\",\n\t\tPhone:    \"01234567890\",\n\t}\n\n\tdata, _ := json.Marshal(requestData)\n\treturn bytes.NewBuffer(data)\n}\n"
  },
  {
    "path": "ch05/acme/internal/rest/server.go",
    "content": "package rest\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/gorilla/mux\"\n)\n\n// New will create and initialize the server\nfunc New(address string) *Server {\n\treturn &Server{\n\t\taddress:         address,\n\t\thandlerGet:      &GetHandler{},\n\t\thandlerList:     &ListHandler{},\n\t\thandlerNotFound: notFoundHandler,\n\t\thandlerRegister: &RegisterHandler{},\n\t}\n}\n\n// Server is the HTTP REST server\ntype Server struct {\n\taddress string\n\tserver  *http.Server\n\n\thandlerGet      http.Handler\n\thandlerList     http.Handler\n\thandlerNotFound http.HandlerFunc\n\thandlerRegister http.Handler\n}\n\n// Listen will start a HTTP rest for this service\nfunc (s *Server) Listen(stop <-chan struct{}) {\n\trouter := s.buildRouter()\n\n\t// create the HTTP server\n\ts.server = &http.Server{\n\t\tHandler: router,\n\t\tAddr:    s.address,\n\t}\n\n\t// listen for shutdown\n\tgo func() {\n\t\t// wait for shutdown signal\n\t\t<-stop\n\n\t\t_ = s.server.Close()\n\t}()\n\n\t// start the HTTP server\n\t_ = s.server.ListenAndServe()\n}\n\n// configure the endpoints to handlers\nfunc (s *Server) buildRouter() http.Handler {\n\trouter := mux.NewRouter()\n\n\t// map URL endpoints to HTTP handlers\n\trouter.Handle(\"/person/{id}/\", s.handlerGet).Methods(\"GET\")\n\trouter.Handle(\"/person/list\", s.handlerList).Methods(\"GET\")\n\trouter.Handle(\"/person/register\", s.handlerRegister).Methods(\"POST\")\n\n\t// convert a \"catch all\" not found handler\n\trouter.NotFoundHandler = s.handlerNotFound\n\n\treturn router\n}\n"
  },
  {
    "path": "ch05/acme/main.go",
    "content": "package main\n\nimport (\n\t\"context\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch05/acme/internal/config\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch05/acme/internal/rest\"\n)\n\nfunc main() {\n\t// bind stop channel to context\n\tctx := context.Background()\n\n\t// start REST server\n\tserver := rest.New(config.App.Address)\n\tserver.Listen(ctx.Done())\n}\n"
  },
  {
    "path": "ch05/fake.go",
    "content": "package ch05\n\nfunc init() {\n\t// This file is included so that Go tools (like `go list`) will find Go code in this directory and not error\n}\n"
  },
  {
    "path": "ch06/01_constructor_injection/01_welcome_email.go",
    "content": "package constructor_injection\n\nimport (\n\t\"errors\"\n)\n\nfunc NewWelcomeSender(in *Mailer) (*WelcomeSender, error) {\n\t// guard clause\n\tif in == nil {\n\t\treturn nil, errors.New(\"programmer error: mailer must not provided\")\n\t}\n\n\treturn &WelcomeSender{\n\t\tmailer: in,\n\t}, nil\n}\n\nfunc NewWelcomeSenderNoGuard(in *Mailer) *WelcomeSender {\n\treturn &WelcomeSender{\n\t\tmailer: in,\n\t}\n}\n\n// WelcomeSender sends a Welcome email to new users\ntype WelcomeSender struct {\n\tmailer *Mailer\n}\n\nfunc (w *WelcomeSender) Send(to string) error {\n\tbody := w.buildMessage()\n\n\treturn w.mailer.Send(to, body)\n}\n\n// build and return the message body\nfunc (w *WelcomeSender) buildMessage() string {\n\treturn \"\"\n}\n\n// Mailer sends and receives emails\ntype Mailer struct {\n\tHost     string\n\tPort     string\n\tUsername string\n\tPassword string\n}\n\nfunc (m *Mailer) Send(to string, body string) error {\n\t// send email\n\treturn nil\n}\n\nfunc (m *Mailer) Receive(address string) (string, error) {\n\t// receive email\n\treturn \"\", nil\n}\n"
  },
  {
    "path": "ch06/01_constructor_injection/01_welcome_email_test.go",
    "content": "package constructor_injection\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestNewWelcomeSender_happyPath(t *testing.T) {\n\tsender, err := NewWelcomeSender(&Mailer{})\n\tassert.NotNil(t, sender)\n\tassert.NoError(t, err)\n}\n\nfunc TestNewWelcomeSender_guardClause(t *testing.T) {\n\tsender, err := NewWelcomeSender(nil)\n\tassert.Nil(t, sender)\n\tassert.Error(t, err)\n}\n\nfunc TestNewWelcomeSenderNoGuard_happyPath(t *testing.T) {\n\tsender := NewWelcomeSenderNoGuard(&Mailer{})\n\tassert.NotNil(t, sender)\n}\n"
  },
  {
    "path": "ch06/01_constructor_injection/02_mailer_interface.go",
    "content": "package constructor_injection\n\n// Mailer sends and receives emails\ntype MailerInterface interface {\n\tSend(to string, body string) error\n\tReceive(address string) (string, error)\n}\n"
  },
  {
    "path": "ch06/01_constructor_injection/03_sender_interface.go",
    "content": "package constructor_injection\n\ntype Sender interface {\n\tSend(to string, body string) error\n}\n\nfunc NewWelcomeSenderV2(in Sender) *WelcomeSenderV2 {\n\treturn &WelcomeSenderV2{\n\t\tsender: in,\n\t}\n}\n\n// WelcomeSenderV2 sends a Welcome email to new users\ntype WelcomeSenderV2 struct {\n\tsender Sender\n}\n\nfunc (w *WelcomeSenderV2) Send(to string) error {\n\tbody := w.buildMessage()\n\n\treturn w.sender.Send(to, body)\n}\n\n// build and return the message body\nfunc (w *WelcomeSenderV2) buildMessage() string {\n\treturn \"\"\n}\n"
  },
  {
    "path": "ch06/01_constructor_injection/05_duck_typing.go",
    "content": "package constructor_injection\n\nimport (\n\t\"fmt\"\n)\n\ntype Talker interface {\n\tSpeak() string\n\tShout() string\n}\n\ntype Dog struct{}\n\nfunc (d Dog) Speak() string {\n\treturn \"Woof!\"\n}\n\nfunc (d Dog) Shout() string {\n\treturn \"WOOF!\"\n}\n\nfunc SpeakExample() {\n\tvar talker Talker\n\ttalker = Dog{}\n\n\tfmt.Print(talker.Speak())\n}\n"
  },
  {
    "path": "ch06/02_advantages/01_easy_to_implement.go",
    "content": "package advantages\n\n// WelcomeSender sends a Welcome email to new users\ntype WelcomeSender struct {\n\tMailer *Mailer\n}\n\nfunc (w *WelcomeSender) Send(to string) error {\n\tbody := w.buildMessage()\n\n\treturn w.Mailer.Send(to, body)\n}\n\n// build and return the message body\nfunc (w *WelcomeSender) buildMessage() string {\n\treturn \"\"\n}\n\n// Mailer will send an email\ntype Mailer struct{}\n\nfunc (m *Mailer) Send(to string, body string) error {\n\t// send email\n\treturn nil\n}\n"
  },
  {
    "path": "ch06/02_advantages/01_easy_to_implement_example_test.go",
    "content": "package advantages_test\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/02_advantages\"\n)\n\nfunc ExampleWelcomeSender_Send() {\n\twelcomeSender := &advantages.WelcomeSender{\n\t\tMailer: &advantages.Mailer{},\n\t}\n\twelcomeSender.Send(\"me@home.com\")\n}\n"
  },
  {
    "path": "ch06/02_advantages/02_easy_to_implement.go",
    "content": "package advantages\n\nfunc NewWelcomeSenderV2(mailer *Mailer) *WelcomeSenderV2 {\n\treturn &WelcomeSenderV2{\n\t\tmailer: mailer,\n\t}\n}\n\n// WelcomeSenderV2 sends a Welcome email to new users\ntype WelcomeSenderV2 struct {\n\tmailer *Mailer\n}\n\nfunc (w *WelcomeSenderV2) Send(to string) error {\n\tbody := w.buildMessage()\n\n\treturn w.mailer.Send(to, body)\n}\n\n// build and return the message body\nfunc (w *WelcomeSenderV2) buildMessage() string {\n\treturn \"\"\n}\n"
  },
  {
    "path": "ch06/02_advantages/02_easy_to_implement_example_test.go",
    "content": "package advantages_test\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/02_advantages\"\n)\n\nfunc ExampleWelcomeSenderV2_Send() {\n\twelcomeSender := advantages.NewWelcomeSenderV2(&advantages.Mailer{})\n\twelcomeSender.Send(\"me@home.com\")\n}\n"
  },
  {
    "path": "ch06/02_advantages/03_predictable.go",
    "content": "package advantages\n\nimport (\n\t\"errors\"\n)\n\ntype Engine interface {\n\tStart()\n\tIncreasePower()\n\tDecreasePower()\n\tStop()\n\tIsRunning() bool\n}\n\ntype Car struct {\n\tEngine Engine\n}\n\nfunc (c *Car) Drive() error {\n\tif c.Engine == nil {\n\t\treturn errors.New(\"engine ie missing\")\n\t}\n\n\t// use the engine\n\tc.Engine.Start()\n\tc.Engine.IncreasePower()\n\n\treturn nil\n}\n\nfunc (c *Car) Stop() error {\n\tif c.Engine == nil {\n\t\treturn errors.New(\"engine ie missing\")\n\t}\n\n\t// use the engine\n\tc.Engine.DecreasePower()\n\tc.Engine.Stop()\n\n\treturn nil\n}\n"
  },
  {
    "path": "ch06/02_advantages/04_predictable.go",
    "content": "package advantages\n\nimport (\n\t\"errors\"\n)\n\nfunc NewCarV2(engine Engine) (*CarV2, error) {\n\tif engine == nil {\n\t\treturn nil, errors.New(\"invalid engine supplied\")\n\t}\n\n\treturn &CarV2{\n\t\tengine: engine,\n\t}, nil\n}\n\ntype CarV2 struct {\n\tengine Engine\n}\n\nfunc (c *CarV2) Drive() error {\n\t// use the engine\n\tc.engine.Start()\n\tc.engine.IncreasePower()\n\n\treturn nil\n}\n\nfunc (c *CarV2) Stop() error {\n\t// use the engine\n\tc.engine.DecreasePower()\n\tc.engine.Stop()\n\n\treturn nil\n}\n"
  },
  {
    "path": "ch06/02_advantages/05_encapsulation.go",
    "content": "package advantages\n\nimport (\n\t\"errors\"\n)\n\nfunc (c *CarV2) FillPetrolTank() error {\n\t// use the engine\n\tif c.engine.IsRunning() {\n\t\treturn errors.New(\"cannot fill the tank while the engine is running\")\n\t}\n\n\t// fill the tank!\n\treturn c.fill()\n}\n\nfunc (c CarV2) fill() error {\n\t// TODO: implement\n\treturn nil\n}\n"
  },
  {
    "path": "ch06/02_advantages/06_encapsulation.go",
    "content": "package advantages\n\nimport (\n\t\"errors\"\n)\n\nfunc (c *CarV2) FillPetrolTankV2(engine Engine) error {\n\t// use the engine\n\tif engine.IsRunning() {\n\t\treturn errors.New(\"cannot fill the tank while the engine is running\")\n\t}\n\n\t// fill the tank!\n\treturn c.fill()\n}\n"
  },
  {
    "path": "ch06/03_applying/01/01_register_handler_before.go",
    "content": "package rest\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/03_applying/01/data\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/03_applying/01/register\"\n)\n\n// RegisterHandler is the HTTP handler for the \"Register\" endpoint\n// In this simplified example we are assuming all possible errors are user errors and returning \"bad request\" HTTP 400.\n// There are some programmer errors possible but hopefully these will be caught in testing.\ntype RegisterHandler struct {\n}\n\n// ServeHTTP implements http.Handler\nfunc (h *RegisterHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\t// extract payload from request\n\trequestPayload, err := h.extractPayload(request)\n\tif err != nil {\n\t\t// output error\n\t\tresponse.WriteHeader(http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// register person\n\tid, err := h.register(requestPayload)\n\tif err != nil {\n\t\t// not need to log here as we can expect other layers to do so\n\t\tresponse.WriteHeader(http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// happy path\n\tresponse.Header().Add(\"Location\", fmt.Sprintf(\"/person/%d/\", id))\n\tresponse.WriteHeader(http.StatusCreated)\n}\n\n// extract payload from request\nfunc (h *RegisterHandler) extractPayload(request *http.Request) (*registerRequest, error) {\n\trequestPayload := &registerRequest{}\n\n\tdecoder := json.NewDecoder(request.Body)\n\terr := decoder.Decode(requestPayload)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn requestPayload, nil\n}\n\n// call the logic layer\nfunc (h *RegisterHandler) register(requestPayload *registerRequest) (int, error) {\n\tperson := &data.Person{\n\t\tFullName: requestPayload.FullName,\n\t\tPhone:    requestPayload.Phone,\n\t\tCurrency: requestPayload.Currency,\n\t}\n\n\tregisterer := &register.Registerer{}\n\treturn registerer.Do(person)\n}\n\n// register endpoint request format\ntype registerRequest struct {\n\t// FullName of the person\n\tFullName string `json:\"fullName\"`\n\t// Phone of the person\n\tPhone string `json:\"phone\"`\n\t// Currency the wish to register in\n\tCurrency string `json:\"currency\"`\n}\n"
  },
  {
    "path": "ch06/03_applying/01/data/person.go",
    "content": "package data\n\n// Person is the data transfer object (DTO) for this package\ntype Person struct {\n\t// ID is the unique ID for this person\n\tID int\n\t// FullName is the name of this person\n\tFullName string\n\t// Phone is the phone for this person\n\tPhone string\n\t// Currency is the currency this person has paid in\n\tCurrency string\n\t// Price is the amount (in the above currency) paid by this person\n\tPrice float64\n}\n"
  },
  {
    "path": "ch06/03_applying/01/register/register.go",
    "content": "package register\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/03_applying/01/data\"\n)\n\n// Registerer validates the supplied person, calculates the price in the requested currency and saves the result.\n// It will return an error when:\n// -the person object does not include all the fields\n// -the currency is invalid\n// -the exchange rate cannot be loaded\n// -the data layer throws an error.\ntype Registerer struct {\n}\n\n// Do is API for this struct\nfunc (r *Registerer) Do(in *data.Person) (int, error) {\n\t// fake implementation\n\treturn 0, nil\n}\n"
  },
  {
    "path": "ch06/03_applying/02/01_register_handler.go",
    "content": "package rest\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/03_applying/02/register\"\n)\n\n// RegisterHandler is the HTTP handler for the \"Register\" endpoint\n// In this simplified example we are assuming all possible errors are user errors and returning \"bad request\" HTTP 400.\n// There are some programmer errors possible but hopefully these will be caught in testing.\ntype RegisterHandler struct {\n\tregisterer *register.Registerer\n}\n"
  },
  {
    "path": "ch06/03_applying/02/data/person.go",
    "content": "package data\n\n// Person is the data transfer object (DTO) for this package\ntype Person struct {\n\t// ID is the unique ID for this person\n\tID int\n\t// FullName is the name of this person\n\tFullName string\n\t// Phone is the phone for this person\n\tPhone string\n\t// Currency is the currency this person has paid in\n\tCurrency string\n\t// Price is the amount (in the above currency) paid by this person\n\tPrice float64\n}\n"
  },
  {
    "path": "ch06/03_applying/02/register/register.go",
    "content": "package register\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/03_applying/01/data\"\n)\n\n// Registerer validates the supplied person, calculates the price in the requested currency and saves the result.\n// It will return an error when:\n// -the person object does not include all the fields\n// -the currency is invalid\n// -the exchange rate cannot be loaded\n// -the data layer throws an error.\ntype Registerer struct {\n}\n\n// Do is API for this struct\nfunc (r *Registerer) Do(in *data.Person) (int, error) {\n\t// fake implementation\n\treturn 0, nil\n}\n"
  },
  {
    "path": "ch06/03_applying/03/data/person.go",
    "content": "package data\n\n// Person is the data transfer object (DTO) for this package\ntype Person struct {\n\t// ID is the unique ID for this person\n\tID int\n\t// FullName is the name of this person\n\tFullName string\n\t// Phone is the phone for this person\n\tPhone string\n\t// Currency is the currency this person has paid in\n\tCurrency string\n\t// Price is the amount (in the above currency) paid by this person\n\tPrice float64\n}\n"
  },
  {
    "path": "ch06/03_applying/03/mock_register_model_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage rest\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/03_applying/03/data\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// MockRegisterModel is an autogenerated mock type for the RegisterModel type\ntype MockRegisterModel struct {\n\tmock.Mock\n}\n\n// Do provides a mock function with given fields: in\nfunc (_m *MockRegisterModel) Do(in *data.Person) (int, error) {\n\tret := _m.Called(in)\n\n\tvar r0 int\n\tif rf, ok := ret.Get(0).(func(*data.Person) int); ok {\n\t\tr0 = rf(in)\n\t} else {\n\t\tr0 = ret.Get(0).(int)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(*data.Person) error); ok {\n\t\tr1 = rf(in)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch06/03_applying/03/register_test.go",
    "content": "package rest\n\nimport (\n\t\"net/http\"\n\t\"testing\"\n)\n\nfunc TestRegisterHandler_ServeHTTP(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc           string\n\t\tinRequest      func() *http.Request\n\t\tinModelMock    func() *MockRegisterModel\n\t\texpectedStatus int\n\t\texpectedHeader string\n\t}{\n\t\t// scenarios go here\n\t}\n\n\tfor _, s := range scenarios {\n\t\tscenario := s\n\t\tt.Run(scenario.desc, func(t *testing.T) {\n\t\t\t// test goes here\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "ch06/03_applying/04/data/person.go",
    "content": "package data\n\n// Person is the data transfer object (DTO) for this package\ntype Person struct {\n\t// ID is the unique ID for this person\n\tID int\n\t// FullName is the name of this person\n\tFullName string\n\t// Phone is the phone for this person\n\tPhone string\n\t// Currency is the currency this person has paid in\n\tCurrency string\n\t// Price is the amount (in the above currency) paid by this person\n\tPrice float64\n}\n"
  },
  {
    "path": "ch06/03_applying/04/mock_register_model_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage rest\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/03_applying/04/data\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// MockRegisterModel is an autogenerated mock type for the RegisterModel type\ntype MockRegisterModel struct {\n\tmock.Mock\n}\n\n// Do provides a mock function with given fields: in\nfunc (_m *MockRegisterModel) Do(in *data.Person) (int, error) {\n\tret := _m.Called(in)\n\n\tvar r0 int\n\tif rf, ok := ret.Get(0).(func(*data.Person) int); ok {\n\t\tr0 = rf(in)\n\t} else {\n\t\tr0 = ret.Get(0).(int)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(*data.Person) error); ok {\n\t\tr1 = rf(in)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch06/03_applying/04/register.go",
    "content": "package rest\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/03_applying/04/data\"\n)\n\n// RegisterModel will validate and save a registration\ntype RegisterModel interface {\n\tDo(in *data.Person) (int, error)\n}\n\n// RegisterHandler is the HTTP handler for the \"Register\" endpoint\n// In this simplified example we are assuming all possible errors are user errors and returning \"bad request\" HTTP 400.\n// There are some programmer errors possible but hopefully these will be caught in testing.\ntype RegisterHandler struct {\n\tregisterer RegisterModel\n}\n\n// ServeHTTP implements http.Handler\nfunc (h *RegisterHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\t// implementation goes here\n}\n\n// register endpoint request format\ntype registerRequest struct {\n\t// FullName of the person\n\tFullName string `json:\"fullName\"`\n\t// Phone of the person\n\tPhone string `json:\"phone\"`\n\t// Currency the wish to register in\n\tCurrency string `json:\"currency\"`\n}\n"
  },
  {
    "path": "ch06/03_applying/04/register_test.go",
    "content": "package rest\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestRegisterHandler_ServeHTTP(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc           string\n\t\tinRequest      func() *http.Request\n\t\tinModelMock    func() *MockRegisterModel\n\t\texpectedStatus int\n\t\texpectedHeader string\n\t}{\n\t\t// scenarios go here\n\t}\n\n\tfor _, s := range scenarios {\n\t\tscenario := s\n\t\tt.Run(scenario.desc, func(t *testing.T) {\n\t\t\t// define model layer mock\n\t\t\tmockRegisterModel := scenario.inModelMock()\n\n\t\t\t// build handler\n\t\t\thandler := &RegisterHandler{\n\t\t\t\tregisterer: mockRegisterModel,\n\t\t\t}\n\n\t\t\t// perform request\n\t\t\tresponse := httptest.NewRecorder()\n\t\t\thandler.ServeHTTP(response, scenario.inRequest())\n\n\t\t\t// validate outputs\n\t\t\trequire.Equal(t, scenario.expectedStatus, response.Code)\n\n\t\t\t// call should output the location to the new person\n\t\t\tresultHeader := response.Header().Get(\"Location\")\n\t\t\tassert.Equal(t, scenario.expectedHeader, resultHeader)\n\n\t\t\t// validate the mock was used as we expected\n\t\t\tassert.True(t, mockRegisterModel.AssertExpectations(t))\n\t\t})\n\t}\n}\n\nfunc buildValidRequest() io.Reader {\n\trequestData := &registerRequest{\n\t\tFullName: \"Joan Smith\",\n\t\tCurrency: \"AUD\",\n\t\tPhone:    \"01234567890\",\n\t}\n\n\tdata, _ := json.Marshal(requestData)\n\treturn bytes.NewBuffer(data)\n}\n"
  },
  {
    "path": "ch06/03_applying/05/data/person.go",
    "content": "package data\n\n// Person is the data transfer object (DTO) for this package\ntype Person struct {\n\t// ID is the unique ID for this person\n\tID int\n\t// FullName is the name of this person\n\tFullName string\n\t// Phone is the phone for this person\n\tPhone string\n\t// Currency is the currency this person has paid in\n\tCurrency string\n\t// Price is the amount (in the above currency) paid by this person\n\tPrice float64\n}\n"
  },
  {
    "path": "ch06/03_applying/05/fakes.go",
    "content": "package reset\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/03_applying/05/data\"\n)\n\nfunc notFoundHandler(response http.ResponseWriter, _ *http.Request) {\n\tresponse.WriteHeader(http.StatusNotFound)\n\t_, _ = response.Write([]byte(`Not found`))\n}\n\n// Fake/Stub implementations to make the compiler happy\n\ntype Server struct {\n\taddress string\n\n\thandlerGet      http.Handler\n\thandlerList     http.Handler\n\thandlerNotFound http.HandlerFunc\n\thandlerRegister http.Handler\n}\n\nfunc NewGetHandler(_ GetModel) *GetHandler {\n\treturn &GetHandler{}\n}\n\ntype GetModel interface {\n\tDo(ID int) (*data.Person, error)\n}\n\ntype GetHandler struct{}\n\nfunc (g *GetHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {}\n\nfunc NewListHandler(_ ListModel) *ListHandler {\n\treturn &ListHandler{}\n}\n\ntype ListModel interface {\n\tDo() ([]*data.Person, error)\n}\n\ntype ListHandler struct {\n}\n\nfunc (l *ListHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {}\n\nfunc NewRegisterHandler(_ RegisterModel) *RegisterHandler {\n\treturn &RegisterHandler{}\n}\n\ntype RegisterModel interface {\n\tDo(in *data.Person) (int, error)\n}\n\ntype RegisterHandler struct {\n}\n\nfunc (r *RegisterHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {}\n"
  },
  {
    "path": "ch06/03_applying/05/get/getter.go",
    "content": "package get\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/03_applying/05/data\"\n)\n\n// Stub implementation so that the example compiles\ntype Getter struct{}\n\nfunc (g *Getter) Do(ID int) (*data.Person, error) {\n\treturn nil, nil\n}\n"
  },
  {
    "path": "ch06/03_applying/05/list/lister.go",
    "content": "package list\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/03_applying/05/data\"\n)\n\n// Stub implementation so that the example compiles\ntype Lister struct{}\n\nfunc (l *Lister) Do() ([]*data.Person, error) {\n\treturn nil, nil\n}\n"
  },
  {
    "path": "ch06/03_applying/05/register/registerer.go",
    "content": "package register\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/03_applying/05/data\"\n)\n\n// Stub implementation so that the example compiles\ntype Registerer struct{}\n\nfunc (r *Registerer) Do(in *data.Person) (int, error) {\n\treturn 0, nil\n}\n"
  },
  {
    "path": "ch06/03_applying/05/server.go",
    "content": "package reset\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/03_applying/05/get\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/03_applying/05/list\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/03_applying/05/register\"\n)\n\n// New will create and initialize the server\nfunc New(address string) *Server {\n\treturn &Server{\n\t\taddress:         address,\n\t\thandlerGet:      NewGetHandler(&get.Getter{}),\n\t\thandlerList:     NewListHandler(&list.Lister{}),\n\t\thandlerNotFound: notFoundHandler,\n\t\thandlerRegister: NewRegisterHandler(&register.Registerer{}),\n\t}\n}\n"
  },
  {
    "path": "ch06/04_disadvantages/01_lots_of_changes.go",
    "content": "package disadvantages\n\n// Dealer will shuffle a deck of cards and deal them to the players\nfunc DealCards() (player1 []Card, player2 []Card) {\n\t// create a new deck of cards\n\tcards := newDeck()\n\n\t// shuffle the cards\n\tshuffler := &myShuffler{}\n\tshuffler.Shuffle(cards)\n\n\t// deal\n\tplayer1 = append(player1, cards[0])\n\tplayer2 = append(player2, cards[1])\n\n\tplayer1 = append(player1, cards[2])\n\tplayer2 = append(player2, cards[3])\n\treturn\n}\n\n// returns a new deck of cards\nfunc newDeck() []Card {\n\treturn []Card{\n\t\t// code removed\n\t}\n}\n\n// Shuffler will shuffle (randomize) the supplied cards\ntype Shuffler interface {\n\tShuffle(cards []Card)\n}\n\n// Card is single Playing Card\ntype Card struct {\n\tSuit  string\n\tValue string\n}\n\n// implements Shuffler\ntype myShuffler struct{}\n\n// Shuffle implements shuffler\nfunc (m *myShuffler) Shuffle(cards []Card) {\n\t// randomize the cards\n}\n"
  },
  {
    "path": "ch06/04_disadvantages/02_overuse.go",
    "content": "package disadvantages\n\nimport (\n\t\"encoding/json\"\n\t\"io/ioutil\"\n\t\"net/http\"\n)\n\nconst downstreamServer = \"http://www.example.com\"\n\n// FetchRates rates from downstream service\ntype FetchRates struct{}\n\nfunc (f *FetchRates) Fetch() ([]Rate, error) {\n\t// build the URL from which to fetch the rates\n\turl := downstreamServer + \"/rates\"\n\n\t// build request\n\trequest, err := http.NewRequest(\"GET\", url, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// fetch rates\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer response.Body.Close()\n\n\t// read the content of the response\n\tdata, err := ioutil.ReadAll(response.Body)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// convert JSON bytes to Go structs\n\tout := &downstreamResponse{}\n\terr = json.Unmarshal(data, out)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn out.Rates, nil\n}\n\n// response format from the downstream service\ntype downstreamResponse struct {\n\tRates []Rate `json:\"rates\"`\n}\n\ntype Rate struct {\n\tCode  string\n\tValue float64\n}\n"
  },
  {
    "path": "ch06/04_disadvantages/03_non_obvious.go",
    "content": "package disadvantages\n\nimport (\n\t\"errors\"\n)\n\n// NewClient creates and initialises the client\nfunc NewClient(service DepService) Client {\n\treturn &clientImpl{\n\t\tservice: service,\n\t}\n}\n\n// Client is the exported API\ntype Client interface {\n\tDoSomethingUseful() (bool, error)\n}\n\n// implement Client\ntype clientImpl struct {\n\tservice DepService\n}\n\nfunc (c *clientImpl) DoSomethingUseful() (bool, error) {\n\t// this function does something useful\n\treturn false, errors.New(\"not implemented\")\n}\n\ntype DepService interface {\n\tDoSomethingElse()\n}\n"
  },
  {
    "path": "ch06/04_disadvantages/04_non_obvious_example_test.go",
    "content": "package disadvantages_test\n\nfunc Example() {\n\n}\n\n// StubClient is a stub implementation of disadvantages.Client interface\ntype StubClient struct{}\n\n// DoSomethingUseful implements disadvantages.Client\nfunc (s *StubClient) DoSomethingUseful() (bool, error) {\n\treturn true, nil\n}\n"
  },
  {
    "path": "ch06/04_disadvantages/05_constructors.go",
    "content": "package disadvantages\n\ntype InnerService struct {\n\tinnerDep Dependency\n}\n\nfunc NewInnerService(innerDep Dependency) *InnerService {\n\treturn &InnerService{\n\t\tinnerDep: innerDep,\n\t}\n}\n\ntype OuterService struct {\n\t// composition\n\tinnerService *InnerService\n\n\touterDep Dependency\n}\n\nfunc NewOuterService(outerDep Dependency, innerDep Dependency) *OuterService {\n\treturn &OuterService{\n\t\tinnerService: NewInnerService(innerDep),\n\t\touterDep:     outerDep,\n\t}\n}\n\n// fake type to satisfy the compiler\ntype Dependency interface {\n}\n"
  },
  {
    "path": "ch06/acme/internal/config/config.go",
    "content": "package config\n\nimport (\n\t\"encoding/json\"\n\t\"io/ioutil\"\n\t\"os\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/acme/internal/logging\"\n)\n\n// DefaultEnvVar is the default environment variable the points to the config file\nconst DefaultEnvVar = \"ACME_CONFIG\"\n\n// App is the application config\nvar App *Config\n\n// Config defines the JSON format for the config file\ntype Config struct {\n\t// DSN is the data source name (format: https://github.com/go-sql-driver/mysql/#dsn-data-source-name)\n\tDSN string\n\n\t// Address is the IP address and port to bind this rest to\n\tAddress string\n\n\t// BasePrice is the price of registration\n\tBasePrice float64\n\n\t// ExchangeRateBaseURL is the server and protocol part of the URL from which to load the exchange rate\n\tExchangeRateBaseURL string\n\n\t// ExchangeRateAPIKey is the API for the exchange rate API\n\tExchangeRateAPIKey string\n}\n\n// Load returns the config loaded from environment\nfunc init() {\n\tfilename, found := os.LookupEnv(DefaultEnvVar)\n\tif !found {\n\t\tlogging.L.Error(\"failed to locate file specified by %s\", DefaultEnvVar)\n\t\treturn\n\t}\n\n\t_ = load(filename)\n}\n\nfunc load(filename string) error {\n\tApp = &Config{}\n\tbytes, err := ioutil.ReadFile(filename)\n\tif err != nil {\n\t\tlogging.L.Error(\"failed to read config file. err: %s\", err)\n\t\treturn err\n\t}\n\n\terr = json.Unmarshal(bytes, App)\n\tif err != nil {\n\t\tlogging.L.Error(\"failed to parse config file. err : %s\", err)\n\t\treturn err\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "ch06/acme/internal/config/config_test.go",
    "content": "package config\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestLoad(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc           string\n\t\tin             string\n\t\texpectedConfig *Config\n\t\texpectError    bool\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tin:   \"../../../../default-config.json\",\n\t\t\texpectedConfig: &Config{\n\t\t\t\tDSN:                 \"[insert your db config here]\",\n\t\t\t\tAddress:             \"0.0.0.0:8080\",\n\t\t\t\tBasePrice:           100.00,\n\t\t\t\tExchangeRateBaseURL: \"http://apilayer.net\",\n\t\t\t\tExchangeRateAPIKey:  \"[insert your API key here]\",\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tdesc:           \"invalid path\",\n\t\t\tin:             \"invalid.json\",\n\t\t\texpectedConfig: &Config{},\n\t\t\texpectError:    true,\n\t\t},\n\t}\n\n\tfor _, s := range scenarios {\n\t\tscenario := s\n\t\tt.Run(scenario.desc, func(t *testing.T) {\n\t\t\tresultErr := load(scenario.in)\n\t\t\trequire.Equal(t, scenario.expectError, resultErr != nil, \"err: %s\", resultErr)\n\t\t\tassert.Equal(t, scenario.expectedConfig, App, scenario.desc)\n\t\t})\n\t}\n\n}\n"
  },
  {
    "path": "ch06/acme/internal/logging/logging.go",
    "content": "package logging\n\nimport (\n\t\"fmt\"\n)\n\n// L is the global instance of the logger\nvar L = &LoggerStdOut{}\n\n// LoggerStdOut logs to std out\ntype LoggerStdOut struct{}\n\n// Debug logs messages at DEBUG level\nfunc (l LoggerStdOut) Debug(message string, args ...interface{}) {\n\tfmt.Printf(\"[DEBUG] \"+message, args...)\n}\n\n// Info logs messages at INFO level\nfunc (l LoggerStdOut) Info(message string, args ...interface{}) {\n\tfmt.Printf(\"[INFO] \"+message, args...)\n}\n\n// Warn logs messages at WARN level\nfunc (l LoggerStdOut) Warn(message string, args ...interface{}) {\n\tfmt.Printf(\"[WARN] \"+message, args...)\n}\n\n// Error logs messages at ERROR level\nfunc (l LoggerStdOut) Error(message string, args ...interface{}) {\n\tfmt.Printf(\"[ERROR] \"+message, args...)\n}\n"
  },
  {
    "path": "ch06/acme/internal/modules/data/data.go",
    "content": "package data\n\nimport (\n\t\"database/sql\"\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/acme/internal/config\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/acme/internal/logging\"\n\t// import the MySQL Driver\n\t_ \"github.com/go-sql-driver/mysql\"\n)\n\nconst (\n\t// default person id (returned on error)\n\tdefaultPersonID = 0\n\n\t// SQL statements as constants (to reduce duplication and maintenance in tests)\n\tsqlAllColumns = \"id, fullname, phone, currency, price\"\n\tsqlInsert     = \"INSERT INTO person (fullname, phone, currency, price) VALUES (?, ?, ?, ?)\"\n\tsqlLoadAll    = \"SELECT \" + sqlAllColumns + \" FROM person\"\n\tsqlLoadByID   = \"SELECT \" + sqlAllColumns + \" FROM person WHERE id = ? LIMIT 1\"\n)\n\nvar (\n\tdb *sql.DB\n\n\t// ErrNotFound is returned when the no records where matched by the query\n\tErrNotFound = errors.New(\"not found\")\n)\n\nvar getDB = func() (*sql.DB, error) {\n\tif db == nil {\n\t\tif config.App == nil {\n\t\t\treturn nil, errors.New(\"config is not initialized\")\n\t\t}\n\n\t\tvar err error\n\t\tdb, err = sql.Open(\"mysql\", config.App.DSN)\n\t\tif err != nil {\n\t\t\t// if the DB cannot be accessed we are dead\n\t\t\tpanic(err.Error())\n\t\t}\n\t}\n\n\treturn db, nil\n}\n\n// Person is the data transfer object (DTO) for this package\ntype Person struct {\n\t// ID is the unique ID for this person\n\tID int\n\t// FullName is the name of this person\n\tFullName string\n\t// Phone is the phone for this person\n\tPhone string\n\t// Currency is the currency this person has paid in\n\tCurrency string\n\t// Price is the amount (in the above currency) paid by this person\n\tPrice float64\n}\n\n// Save will save the supplied person and return the ID of the newly created person or an error.\n// Errors returned are caused by the underlying database or our connection to it.\nfunc Save(in *Person) (int, error) {\n\tdb, err := getDB()\n\tif err != nil {\n\t\tlogging.L.Error(\"failed to get DB connection. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\t// perform DB insert\n\tresult, err := db.Exec(sqlInsert, in.FullName, in.Phone, in.Currency, in.Price)\n\tif err != nil {\n\t\tlogging.L.Error(\"failed to save person into DB. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\t// retrieve and return the ID of the person created\n\tid, err := result.LastInsertId()\n\tif err != nil {\n\t\tlogging.L.Error(\"failed to retrieve id of last saved person. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn int(id), nil\n}\n\n// LoadAll will attempt to load all people in the database\n// It will return ErrNotFound when there are not people in the database\n// Any other errors returned are caused by the underlying database or our connection to it.\nfunc LoadAll() ([]*Person, error) {\n\tdb, err := getDB()\n\tif err != nil {\n\t\tlogging.L.Error(\"failed to get DB connection. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// perform DB select\n\trows, err := db.Query(sqlLoadAll)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer func() {\n\t\t_ = rows.Close()\n\t}()\n\n\tvar out []*Person\n\n\tfor rows.Next() {\n\t\t// retrieve columns and populate the person object\n\t\trecord, err := populatePerson(rows.Scan)\n\t\tif err != nil {\n\t\t\tlogging.L.Error(\"failed to convert query result. err: %s\", err)\n\t\t\treturn nil, err\n\t\t}\n\n\t\tout = append(out, record)\n\t}\n\n\tif len(out) == 0 {\n\t\tlogging.L.Warn(\"no people found in the database.\")\n\t\treturn nil, ErrNotFound\n\t}\n\n\treturn out, nil\n}\n\n// Load will attempt to load and return a person.\n// It will return ErrNotFound when the requested person does not exist.\n// Any other errors returned are caused by the underlying database or our connection to it.\nfunc Load(ID int) (*Person, error) {\n\tdb, err := getDB()\n\tif err != nil {\n\t\tlogging.L.Error(\"failed to get DB connection. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// perform DB select\n\trow := db.QueryRow(sqlLoadByID, ID)\n\n\t// retrieve columns and populate the person object\n\tout, err := populatePerson(row.Scan)\n\tif err != nil {\n\t\tif err == sql.ErrNoRows {\n\t\t\tlogging.L.Warn(\"failed to load requested person '%d'. err: %s\", ID, err)\n\t\t\treturn nil, ErrNotFound\n\t\t}\n\n\t\tlogging.L.Error(\"failed to convert query result. err: %s\", err)\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\n// custom type so we can convert sql results to easily\ntype scanner func(dest ...interface{}) error\n\n// reduce the duplication (and maintenance) between sql.Row and sql.Rows usage\nfunc populatePerson(scanner scanner) (*Person, error) {\n\tout := &Person{}\n\terr := scanner(&out.ID, &out.FullName, &out.Phone, &out.Currency, &out.Price)\n\treturn out, err\n}\n\nfunc init() {\n\t// ensure the config is loaded and the db initialized\n\t_, _ = getDB()\n}\n"
  },
  {
    "path": "ch06/acme/internal/modules/data/data_test.go",
    "content": "package data\n\nimport (\n\t\"database/sql\"\n\t\"errors\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/DATA-DOG/go-sqlmock\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestSave_happyPath(t *testing.T) {\n\t// define a mock db\n\ttestDb, dbMock, err := sqlmock.New()\n\tdefer testDb.Close()\n\trequire.NoError(t, err)\n\n\t// configure the mock db\n\tqueryRegex := convertSQLToRegex(sqlInsert)\n\tdbMock.ExpectExec(queryRegex).WillReturnResult(sqlmock.NewResult(2, 1))\n\n\t// monkey patching starts here\n\tdefer func(original sql.DB) {\n\t\t// restore original DB (after test)\n\t\tdb = &original\n\t}(*db)\n\n\t// replace db for this test\n\tdb = testDb\n\t// end of monkey patch\n\n\t// inputs\n\tin := &Person{\n\t\tFullName: \"Jake Blues\",\n\t\tPhone:    \"01234567890\",\n\t\tCurrency: \"AUD\",\n\t\tPrice:    123.45,\n\t}\n\n\t// call function\n\tresultID, err := Save(in)\n\n\t// validate result\n\trequire.NoError(t, err)\n\tassert.Equal(t, 2, resultID)\n\tassert.NoError(t, dbMock.ExpectationsWereMet())\n}\n\nfunc TestSave_insertError(t *testing.T) {\n\t// define a mock db\n\ttestDb, dbMock, err := sqlmock.New()\n\tdefer testDb.Close()\n\n\trequire.NoError(t, err)\n\n\t// configure the mock db\n\tqueryRegex := convertSQLToRegex(sqlInsert)\n\tdbMock.ExpectExec(queryRegex).WillReturnError(errors.New(\"failed to insert\"))\n\n\t// monkey patching starts here\n\tdefer func(original sql.DB) {\n\t\t// restore original DB (after test)\n\t\tdb = &original\n\t}(*db)\n\n\t// replace db for this test\n\tdb = testDb\n\t// end of monkey patch\n\n\t// inputs\n\tin := &Person{\n\t\tFullName: \"Jake Blues\",\n\t\tPhone:    \"01234567890\",\n\t\tCurrency: \"AUD\",\n\t\tPrice:    123.45,\n\t}\n\n\t// call function\n\tresultID, err := Save(in)\n\n\t// validate result\n\trequire.Error(t, err)\n\tassert.Equal(t, defaultPersonID, resultID)\n\tassert.NoError(t, dbMock.ExpectationsWereMet())\n}\n\nfunc TestSave_getDBError(t *testing.T) {\n\t// monkey patching starts here\n\tdefer func(original func() (*sql.DB, error)) {\n\t\t// restore original DB (after test)\n\t\tgetDB = original\n\t}(getDB)\n\n\t// replace getDB() function for this test\n\tgetDB = func() (*sql.DB, error) {\n\t\treturn nil, errors.New(\"getDB() failed\")\n\t}\n\t// end of monkey patch\n\n\t// inputs\n\tin := &Person{\n\t\tFullName: \"Jake Blues\",\n\t\tPhone:    \"01234567890\",\n\t\tCurrency: \"AUD\",\n\t\tPrice:    123.45,\n\t}\n\n\t// call function\n\tresultID, err := Save(in)\n\trequire.Error(t, err)\n\tassert.Equal(t, defaultPersonID, resultID)\n}\n\nfunc TestLoadAll_tableDrivenTest(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc            string\n\t\tconfigureMockDB func(sqlmock.Sqlmock)\n\t\texpectedResults []*Person\n\t\texpectError     bool\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tconfigureMockDB: func(dbMock sqlmock.Sqlmock) {\n\t\t\t\tqueryRegex := convertSQLToRegex(sqlLoadAll)\n\t\t\t\tdbMock.ExpectQuery(queryRegex).WillReturnRows(\n\t\t\t\t\tsqlmock.NewRows(strings.Split(sqlAllColumns, \", \")).\n\t\t\t\t\t\tAddRow(1, \"John\", \"0123456789\", \"AUD\", 12.34))\n\t\t\t},\n\t\t\texpectedResults: []*Person{\n\t\t\t\t{\n\t\t\t\t\tID:       1,\n\t\t\t\t\tFullName: \"John\",\n\t\t\t\t\tPhone:    \"0123456789\",\n\t\t\t\t\tCurrency: \"AUD\",\n\t\t\t\t\tPrice:    12.34,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tdesc: \"load error\",\n\t\t\tconfigureMockDB: func(dbMock sqlmock.Sqlmock) {\n\t\t\t\tqueryRegex := convertSQLToRegex(sqlLoadAll)\n\t\t\t\tdbMock.ExpectQuery(queryRegex).WillReturnError(errors.New(\"something failed\"))\n\t\t\t},\n\t\t\texpectedResults: nil,\n\t\t\texpectError:     true,\n\t\t},\n\t}\n\n\tfor _, scenario := range scenarios {\n\t\t// define a mock db\n\t\ttestDb, dbMock, err := sqlmock.New()\n\t\trequire.NoError(t, err)\n\n\t\t// configure the mock db\n\t\tscenario.configureMockDB(dbMock)\n\n\t\t// monkey patch the db for this test\n\t\toriginal := *db\n\t\tdb = testDb\n\n\t\t// call function\n\t\tresults, err := LoadAll()\n\n\t\t// validate results\n\t\tassert.Equal(t, scenario.expectedResults, results, scenario.desc)\n\t\tassert.Equal(t, scenario.expectError, err != nil, scenario.desc)\n\t\tassert.NoError(t, dbMock.ExpectationsWereMet())\n\n\t\t// restore original DB (after test)\n\t\tdb = &original\n\t\ttestDb.Close()\n\t}\n}\n\nfunc TestLoad_tableDrivenTest(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc            string\n\t\tconfigureMockDB func(sqlmock.Sqlmock)\n\t\texpectedResult  *Person\n\t\texpectError     bool\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tconfigureMockDB: func(dbMock sqlmock.Sqlmock) {\n\t\t\t\tqueryRegex := convertSQLToRegex(sqlLoadAll)\n\t\t\t\tdbMock.ExpectQuery(queryRegex).WillReturnRows(\n\t\t\t\t\tsqlmock.NewRows(strings.Split(sqlAllColumns, \", \")).\n\t\t\t\t\t\tAddRow(2, \"Paul\", \"0123456789\", \"CAD\", 23.45))\n\t\t\t},\n\t\t\texpectedResult: &Person{\n\t\t\t\tID:       2,\n\t\t\t\tFullName: \"Paul\",\n\t\t\t\tPhone:    \"0123456789\",\n\t\t\t\tCurrency: \"CAD\",\n\t\t\t\tPrice:    23.45,\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tdesc: \"load error\",\n\t\t\tconfigureMockDB: func(dbMock sqlmock.Sqlmock) {\n\t\t\t\tqueryRegex := convertSQLToRegex(sqlLoadAll)\n\t\t\t\tdbMock.ExpectQuery(queryRegex).WillReturnError(errors.New(\"something failed\"))\n\t\t\t},\n\t\t\texpectedResult: nil,\n\t\t\texpectError:    true,\n\t\t},\n\t}\n\n\tfor _, scenario := range scenarios {\n\t\t// define a mock db\n\t\ttestDb, dbMock, err := sqlmock.New()\n\t\trequire.NoError(t, err)\n\n\t\t// configure the mock db\n\t\tscenario.configureMockDB(dbMock)\n\n\t\t// monkey db for this test\n\t\toriginal := *db\n\t\tdb = testDb\n\n\t\t// call function\n\t\tresult, err := Load(2)\n\n\t\t// validate results\n\t\tassert.Equal(t, scenario.expectedResult, result, scenario.desc)\n\t\tassert.Equal(t, scenario.expectError, err != nil, scenario.desc)\n\t\tassert.NoError(t, dbMock.ExpectationsWereMet())\n\n\t\t// restore original DB (after test)\n\t\tdb = &original\n\t\ttestDb.Close()\n\t}\n}\n\n// convert SQL string to regex by treating the entire query as a literal\nfunc convertSQLToRegex(in string) string {\n\treturn `\\Q` + in + `\\E`\n}\n"
  },
  {
    "path": "ch06/acme/internal/modules/exchange/converter.go",
    "content": "package exchange\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"math\"\n\t\"net/http\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/acme/internal/config\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/acme/internal/logging\"\n)\n\nconst (\n\t// request URL for the exchange rate API\n\turlFormat = \"%s/api/historical?access_key=%s&date=2018-06-20&currencies=%s\"\n\n\t// default price that is sent when an error occurs\n\tdefaultPrice = 0.0\n)\n\n// Converter will convert the base price to the currency supplied\n// Note: we are expecting sane inputs and therefore skipping input validation\ntype Converter struct{}\n\n// Do will perform the conversion\nfunc (c *Converter) Do(basePrice float64, currency string) (float64, error) {\n\t// load rate from the external API\n\tresponse, err := c.loadRateFromServer(currency)\n\tif err != nil {\n\t\treturn defaultPrice, err\n\t}\n\n\t// extract rate from response\n\trate, err := c.extractRate(response, currency)\n\tif err != nil {\n\t\treturn defaultPrice, err\n\t}\n\n\t// apply rate and round to 2 decimal places\n\treturn math.Floor((basePrice/rate)*100) / 100, nil\n}\n\n// load rate from the external API\nfunc (c *Converter) loadRateFromServer(currency string) (*http.Response, error) {\n\t// build the request\n\turl := fmt.Sprintf(urlFormat,\n\t\tconfig.App.ExchangeRateBaseURL,\n\t\tconfig.App.ExchangeRateAPIKey,\n\t\tcurrency)\n\n\t// perform request\n\tresponse, err := http.Get(url)\n\tif err != nil {\n\t\tlogging.L.Warn(\"[exchange] failed to load. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\tif response.StatusCode != http.StatusOK {\n\t\terr = fmt.Errorf(\"request failed with code %d\", response.StatusCode)\n\t\tlogging.L.Warn(\"[exchange] %s\", err)\n\t\treturn nil, err\n\t}\n\n\treturn response, nil\n}\n\nfunc (c *Converter) extractRate(response *http.Response, currency string) (float64, error) {\n\tdefer func() {\n\t\t_ = response.Body.Close()\n\t}()\n\n\t// extract data from response\n\tdata, err := c.extractResponse(response)\n\tif err != nil {\n\t\treturn defaultPrice, err\n\t}\n\n\t// pull rate from response data\n\trate, found := data.Quotes[\"USD\"+currency]\n\tif !found {\n\t\terr = fmt.Errorf(\"response did not include expected currency '%s'\", currency)\n\t\tlogging.L.Error(\"[exchange] %s\", err)\n\t\treturn defaultPrice, err\n\t}\n\n\t// happy path\n\treturn rate, nil\n}\n\nfunc (c *Converter) extractResponse(response *http.Response) (*apiResponseFormat, error) {\n\tpayload, err := ioutil.ReadAll(response.Body)\n\tif err != nil {\n\t\tlogging.L.Error(\"[exchange] failed to ready response body. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\tdata := &apiResponseFormat{}\n\terr = json.Unmarshal(payload, data)\n\tif err != nil {\n\t\tlogging.L.Error(\"[exchange] error converting response. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// happy path\n\treturn data, nil\n}\n\n// the response format from the exchange rate API\ntype apiResponseFormat struct {\n\tQuotes map[string]float64 `json:\"quotes\"`\n}\n"
  },
  {
    "path": "ch06/acme/internal/modules/get/get.go",
    "content": "package get\n\nimport (\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/acme/internal/modules/data\"\n)\n\nvar (\n\t// error thrown when the requested person is not in the database\n\terrPersonNotFound = errors.New(\"person not found\")\n)\n\n// Getter will attempt to load a person.\n// It can return an error caused by the data layer or when the requested person is not found\ntype Getter struct {\n}\n\n// Do will perform the get\nfunc (g *Getter) Do(ID int) (*data.Person, error) {\n\t// load person from the data layer\n\tperson, err := loader(ID)\n\tif err != nil {\n\t\tif err == data.ErrNotFound {\n\t\t\t// By converting the error we are hiding the implementation details from our users.\n\t\t\treturn nil, errPersonNotFound\n\t\t}\n\t\treturn nil, err\n\t}\n\n\treturn person, err\n}\n\n// this function as a variable allows us to Monkey Patch during testing\nvar loader = data.Load\n"
  },
  {
    "path": "ch06/acme/internal/modules/get/go_test.go",
    "content": "package get\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestGetter_Do_happyPath(t *testing.T) {\n\t// inputs\n\tID := 1234\n\n\t// monkey patch calls to the data package\n\tdefer func(original func(ID int) (*data.Person, error)) {\n\t\t// restore original\n\t\tloader = original\n\t}(loader)\n\n\t// replace method\n\tloader = func(ID int) (*data.Person, error) {\n\t\tresult := &data.Person{\n\t\t\tID:       1234,\n\t\t\tFullName: \"Doug\",\n\t\t}\n\t\tvar resultErr error\n\n\t\treturn result, resultErr\n\t}\n\t// end of monkey patch\n\n\t// call method\n\tgetter := &Getter{}\n\tperson, err := getter.Do(ID)\n\n\t// validate expectations\n\trequire.NoError(t, err)\n\tassert.Equal(t, ID, person.ID)\n\tassert.Equal(t, \"Doug\", person.FullName)\n}\n\nfunc TestGetter_Do_noSuchPerson(t *testing.T) {\n\t// inputs\n\tID := 5678\n\n\t// monkey patch calls to the data package\n\tdefer func(original func(ID int) (*data.Person, error)) {\n\t\t// restore original\n\t\tloader = original\n\t}(loader)\n\n\t// replace method\n\tloader = func(ID int) (*data.Person, error) {\n\t\tvar result *data.Person\n\t\tresultErr := data.ErrNotFound\n\n\t\treturn result, resultErr\n\t}\n\t// end of monkey patch\n\n\t// call method\n\tgetter := &Getter{}\n\tperson, err := getter.Do(ID)\n\n\t// validate expectations\n\trequire.Equal(t, errPersonNotFound, err)\n\tassert.Nil(t, person)\n}\n\nfunc TestGetter_Do_error(t *testing.T) {\n\t// inputs\n\tID := 1234\n\n\t// monkey patch calls to the data package\n\tdefer func(original func(ID int) (*data.Person, error)) {\n\t\t// restore original\n\t\tloader = original\n\t}(loader)\n\n\t// replace method\n\tloader = func(ID int) (*data.Person, error) {\n\t\tvar result *data.Person\n\t\tresultErr := errors.New(\"failed to load person\")\n\n\t\treturn result, resultErr\n\t}\n\t// end of monkey patch\n\n\t// call method\n\tgetter := &Getter{}\n\tperson, err := getter.Do(ID)\n\n\t// validate expectations\n\trequire.Error(t, err)\n\tassert.Nil(t, person)\n}\n"
  },
  {
    "path": "ch06/acme/internal/modules/list/list.go",
    "content": "package list\n\nimport (\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/acme/internal/modules/data\"\n)\n\nvar (\n\t// error thrown when there are no people in the database\n\terrPeopleNotFound = errors.New(\"no people found\")\n)\n\n// Lister will attempt to load all people in the database.\n// It can return an error caused by the data layer\ntype Lister struct {\n}\n\n// Do will load the people from the data layer\nfunc (l *Lister) Do() ([]*data.Person, error) {\n\t// load all people\n\tpeople, err := l.load()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(people) == 0 {\n\t\t// special processing for 0 people returned\n\t\treturn nil, errPeopleNotFound\n\t}\n\n\treturn people, nil\n}\n\n// load all people\nfunc (l *Lister) load() ([]*data.Person, error) {\n\tpeople, err := loader()\n\tif err != nil {\n\t\tif err == data.ErrNotFound {\n\t\t\t// By converting the error we are encapsulating the implementation details from our users.\n\t\t\treturn nil, errPeopleNotFound\n\t\t}\n\t\treturn nil, err\n\t}\n\n\treturn people, nil\n}\n\n// this function as a variable allows us to Monkey Patch during testing\nvar loader = data.LoadAll\n"
  },
  {
    "path": "ch06/acme/internal/modules/list/list_test.go",
    "content": "package list\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestLister_Do_happyPath(t *testing.T) {\n\t// monkey patch calls to the data package\n\tdefer func(original func() ([]*data.Person, error)) {\n\t\t// restore original\n\t\tloader = original\n\t}(loader)\n\n\t// replace method\n\tloader = func() ([]*data.Person, error) {\n\t\tresult := []*data.Person{\n\t\t\t{\n\t\t\t\tID:       1234,\n\t\t\t\tFullName: \"Sally\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tID:       5678,\n\t\t\t\tFullName: \"Jane\",\n\t\t\t},\n\t\t}\n\t\tvar resultErr error\n\n\t\treturn result, resultErr\n\t}\n\t// end of monkey patch\n\n\t// call method\n\tlister := &Lister{}\n\tpersons, err := lister.load()\n\n\t// validate expectations\n\trequire.NoError(t, err)\n\tassert.Equal(t, 2, len(persons))\n}\n\nfunc TestLister_Do_noResults(t *testing.T) {\n\t// monkey patch calls to the data package\n\tdefer func(original func() ([]*data.Person, error)) {\n\t\t// restore original\n\t\tloader = original\n\t}(loader)\n\n\t// replace method\n\tloader = func() ([]*data.Person, error) {\n\t\tvar result []*data.Person\n\t\tresultErr := data.ErrNotFound\n\n\t\treturn result, resultErr\n\t}\n\t// end of monkey patch\n\n\t// call method\n\tlister := &Lister{}\n\tpersons, err := lister.load()\n\n\t// validate expectations\n\trequire.Equal(t, errPeopleNotFound, err)\n\tassert.Equal(t, 0, len(persons))\n}\n\nfunc TestLister_Do_error(t *testing.T) {\n\t// monkey patch calls to the data package\n\tdefer func(original func() ([]*data.Person, error)) {\n\t\t// restore original\n\t\tloader = original\n\t}(loader)\n\n\t// replace method\n\tloader = func() ([]*data.Person, error) {\n\t\tvar result []*data.Person\n\t\tresultErr := errors.New(\"failed to load people\")\n\n\t\treturn result, resultErr\n\t}\n\t// end of monkey patch\n\n\t// call method\n\tlister := &Lister{}\n\tpersons, err := lister.load()\n\n\t// validate expectations\n\trequire.Error(t, err)\n\tassert.Equal(t, 0, len(persons))\n}\n"
  },
  {
    "path": "ch06/acme/internal/modules/register/register.go",
    "content": "package register\n\nimport (\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/acme/internal/config\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/acme/internal/modules/data\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/acme/internal/modules/exchange\"\n)\n\nconst (\n\t// default person id (returned on error)\n\tdefaultPersonID = 0\n)\n\nvar (\n\t// validation errors\n\terrNameMissing     = errors.New(\"name is missing\")\n\terrPhoneMissing    = errors.New(\"phone is missing\")\n\terrCurrencyMissing = errors.New(\"currency is missing\")\n\terrInvalidCurrency = errors.New(\"currency is invalid, supported types are AUD, CNY, EUR, GBP, JPY, MYR, SGD, USD\")\n\n\t// a little trick to make checking for supported currencies easier\n\tsupportedCurrencies = map[string]struct{}{\n\t\t\"AUD\": {},\n\t\t\"CNY\": {},\n\t\t\"EUR\": {},\n\t\t\"GBP\": {},\n\t\t\"JPY\": {},\n\t\t\"MYR\": {},\n\t\t\"SGD\": {},\n\t\t\"USD\": {},\n\t}\n)\n\n// Registerer validates the supplied person, calculates the price in the requested currency and saves the result.\n// It will return an error when:\n// -the person object does not include all the fields\n// -the currency is invalid\n// -the exchange rate cannot be loaded\n// -the data layer throws an error.\ntype Registerer struct {\n}\n\n// Do is API for this struct\nfunc (r *Registerer) Do(in *data.Person) (int, error) {\n\t// validate the request\n\terr := r.validateInput(in)\n\tif err != nil {\n\t\tlogging.L.Warn(\"input validation failed with err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\t// get price in the requested currency\n\tprice, err := r.getPrice(in.Currency)\n\tif err != nil {\n\t\treturn defaultPersonID, err\n\t}\n\n\t// save registration\n\tid, err := r.save(in, price)\n\tif err != nil {\n\t\t// no need to log here as we expect the data layer to do so\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn id, nil\n}\n\n// validate input and return error on fail\nfunc (r *Registerer) validateInput(in *data.Person) error {\n\tif in.FullName == \"\" {\n\t\treturn errNameMissing\n\t}\n\tif in.Phone == \"\" {\n\t\treturn errPhoneMissing\n\t}\n\tif in.Currency == \"\" {\n\t\treturn errCurrencyMissing\n\t}\n\n\tif _, found := supportedCurrencies[in.Currency]; !found {\n\t\treturn errInvalidCurrency\n\t}\n\n\t// happy path\n\treturn nil\n}\n\n// get price in the requested currency\nfunc (r *Registerer) getPrice(currency string) (float64, error) {\n\tconverter := &exchange.Converter{}\n\tprice, err := converter.Do(config.App.BasePrice, currency)\n\tif err != nil {\n\t\tlogging.L.Warn(\"failed to convert the price. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn price, nil\n}\n\n// save the registration\nfunc (r *Registerer) save(in *data.Person, price float64) (int, error) {\n\tperson := &data.Person{\n\t\tFullName: in.FullName,\n\t\tPhone:    in.Phone,\n\t\tCurrency: in.Currency,\n\t\tPrice:    price,\n\t}\n\treturn saver(person)\n}\n\n// this function as a variable allows us to Monkey Patch during testing\nvar saver = data.Save\n"
  },
  {
    "path": "ch06/acme/internal/modules/register/register_test.go",
    "content": "package register\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestRegisterer_Do_happyPath(t *testing.T) {\n\t// monkey patch calls to the data package\n\tdefer func(original func(in *data.Person) (int, error)) {\n\t\t// restore original\n\t\tsaver = original\n\t}(saver)\n\n\t// replace method\n\tsaver = func(in *data.Person) (int, error) {\n\t\tresult := 888\n\t\tvar resultErr error\n\n\t\treturn result, resultErr\n\t}\n\t// end of monkey patch\n\n\t// inputs\n\tin := &data.Person{\n\t\tFullName: \"Chang\",\n\t\tPhone:    \"11122233355\",\n\t\tCurrency: \"CNY\",\n\t}\n\n\t// call method\n\tregisterer := &Registerer{}\n\tID, err := registerer.Do(in)\n\n\t// validate expectations\n\trequire.NoError(t, err)\n\tassert.Equal(t, 888, ID)\n}\n\nfunc TestRegisterer_Do_error(t *testing.T) {\n\t// monkey patch calls to the data package\n\tdefer func(original func(in *data.Person) (int, error)) {\n\t\t// restore original\n\t\tsaver = original\n\t}(saver)\n\n\t// replace method\n\tsaver = func(in *data.Person) (int, error) {\n\t\tvar result int\n\t\tresultErr := errors.New(\"failed to save\")\n\n\t\treturn result, resultErr\n\t}\n\t// end of monkey patch\n\n\t// inputs\n\tin := &data.Person{\n\t\tFullName: \"Chang\",\n\t\tPhone:    \"11122233355\",\n\t\tCurrency: \"CNY\",\n\t}\n\n\t// call method\n\tregisterer := &Registerer{}\n\tID, err := registerer.Do(in)\n\n\t// validate expectations\n\trequire.Error(t, err)\n\tassert.Equal(t, 0, ID)\n}\n"
  },
  {
    "path": "ch06/acme/internal/rest/get.go",
    "content": "package rest\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/acme/internal/modules/data\"\n\t\"github.com/gorilla/mux\"\n)\n\nconst (\n\t// default person id (returned on error)\n\tdefaultPersonID = 0\n\n\t// key in the mux where the ID is stored\n\tmuxVarID = \"id\"\n)\n\n// GetModel will load a registration\n//go:generate mockery -name=GetModel -case underscore -testonly -inpkg -note @generated\ntype GetModel interface {\n\tDo(ID int) (*data.Person, error)\n}\n\n// NewGetHandler is the constructor for GetHandler\nfunc NewGetHandler(model GetModel) *GetHandler {\n\treturn &GetHandler{\n\t\tgetter: model,\n\t}\n}\n\n// GetHandler is the HTTP handler for the \"Get Person\" endpoint\n// In this simplified example we are assuming all possible errors are user errors and returning \"bad request\" HTTP 400\n// or \"not found\" HTTP 404\n// There are some programmer errors possible but hopefully these will be caught in testing.\ntype GetHandler struct {\n\tgetter GetModel\n}\n\n// ServeHTTP implements http.Handler\nfunc (h *GetHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\t// extract person id from request\n\tid, err := h.extractID(request)\n\tif err != nil {\n\t\t// output error\n\t\tresponse.WriteHeader(http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// attempt get\n\tperson, err := h.getter.Do(id)\n\tif err != nil {\n\t\t// not need to log here as we can expect other layers to do so\n\t\tresponse.WriteHeader(http.StatusNotFound)\n\t\treturn\n\t}\n\n\t// happy path\n\terr = h.writeJSON(response, person)\n\tif err != nil {\n\t\t// this error should not happen but if it does there is nothing we can do to recover\n\t\tresponse.WriteHeader(http.StatusInternalServerError)\n\t}\n}\n\n// extract the person ID from the request\nfunc (h *GetHandler) extractID(request *http.Request) (int, error) {\n\t// ID is part of the URL, so we extract it from there\n\tvars := mux.Vars(request)\n\tidAsString, exists := vars[muxVarID]\n\tif !exists {\n\t\t// log and return error\n\t\terr := errors.New(\"[get] person id missing from request\")\n\t\tlogging.L.Warn(err.Error())\n\t\treturn defaultPersonID, err\n\t}\n\n\t// convert ID to int\n\tid, err := strconv.Atoi(idAsString)\n\tif err != nil {\n\t\t// log and return error\n\t\terr = fmt.Errorf(\"[get] failed to convert person id into a number. err: %s\", err)\n\t\tlogging.L.Error(err.Error())\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn id, nil\n}\n\n// output the supplied person as JSON\nfunc (h *GetHandler) writeJSON(writer io.Writer, person *data.Person) error {\n\toutput := &getResponseFormat{\n\t\tID:       person.ID,\n\t\tFullName: person.FullName,\n\t\tPhone:    person.Phone,\n\t\tCurrency: person.Currency,\n\t\tPrice:    person.Price,\n\t}\n\n\t// call to http.ResponseWriter.Write() will cause HTTP OK (200) to be output as well\n\treturn json.NewEncoder(writer).Encode(output)\n}\n\n// the JSON response format\ntype getResponseFormat struct {\n\tID       int     `json:\"id\"`\n\tFullName string  `json:\"name\"`\n\tPhone    string  `json:\"phone\"`\n\tCurrency string  `json:\"currency\"`\n\tPrice    float64 `json:\"price\"`\n}\n"
  },
  {
    "path": "ch06/acme/internal/rest/get_test.go",
    "content": "package rest\n\nimport (\n\t\"errors\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/acme/internal/modules/data\"\n\t\"github.com/gorilla/mux\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestGetHandler_ServeHTTP(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc            string\n\t\tinRequest       func() *http.Request\n\t\tinModelMock     func() *MockGetModel\n\t\texpectedStatus  int\n\t\texpectedPayload string\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/1/\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// set values into request (required by the mux)\n\t\t\t\treturn mux.SetURLVars(req, map[string]string{muxVarID: \"1\"})\n\t\t\t},\n\t\t\tinModelMock: func() *MockGetModel {\n\t\t\t\toutput := &data.Person{\n\t\t\t\t\tID:       1,\n\t\t\t\t\tFullName: \"John\",\n\t\t\t\t\tPhone:    \"0123456789\",\n\t\t\t\t\tCurrency: \"USD\",\n\t\t\t\t\tPrice:    100,\n\t\t\t\t}\n\n\t\t\t\tmockGetModel := &MockGetModel{}\n\t\t\t\tmockGetModel.On(\"Do\", mock.Anything).Return(output, nil).Once()\n\n\t\t\t\treturn mockGetModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusOK,\n\t\t\texpectedPayload: `{\"id\":1,\"name\":\"John\",\"phone\":\"0123456789\",\"currency\":\"USD\",\"price\":100}` + \"\\n\",\n\t\t},\n\t\t{\n\t\t\tdesc: \"bad input (ID is invalid)\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/x/\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// set values into request (required by the mux)\n\t\t\t\treturn mux.SetURLVars(req, map[string]string{muxVarID: \"x\"})\n\t\t\t},\n\t\t\tinModelMock: func() *MockGetModel {\n\t\t\t\t// expect the model not to be called\n\t\t\t\tmockRegisterModel := &MockGetModel{}\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusBadRequest,\n\t\t\texpectedPayload: ``,\n\t\t},\n\t\t{\n\t\t\tdesc: \"bad input (ID is missing)\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person//\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// set values into request (required by the mux)\n\t\t\t\treturn mux.SetURLVars(req, map[string]string{})\n\t\t\t},\n\t\t\tinModelMock: func() *MockGetModel {\n\t\t\t\t// expect the model not to be called\n\t\t\t\tmockRegisterModel := &MockGetModel{}\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusBadRequest,\n\t\t\texpectedPayload: ``,\n\t\t},\n\t\t{\n\t\t\tdesc: \"dependency fail\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/1/\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// set values into request (required by the mux)\n\t\t\t\treturn mux.SetURLVars(req, map[string]string{muxVarID: \"1\"})\n\t\t\t},\n\t\t\tinModelMock: func() *MockGetModel {\n\t\t\t\tmockRegisterModel := &MockGetModel{}\n\t\t\t\tmockRegisterModel.On(\"Do\", mock.Anything).Return(nil, errors.New(\"something failed\")).Once()\n\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusNotFound,\n\t\t\texpectedPayload: ``,\n\t\t},\n\t\t{\n\t\t\tdesc: \"requested registration does not exist\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/1/\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// set values into request (required by the mux)\n\t\t\t\treturn mux.SetURLVars(req, map[string]string{muxVarID: \"1\"})\n\t\t\t},\n\t\t\tinModelMock: func() *MockGetModel {\n\t\t\t\tmockRegisterModel := &MockGetModel{}\n\t\t\t\tmockRegisterModel.On(\"Do\", mock.Anything).Return(nil, errors.New(\"person not found\")).Once()\n\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusNotFound,\n\t\t\texpectedPayload: ``,\n\t\t},\n\t}\n\n\tfor _, s := range scenarios {\n\t\tscenario := s\n\t\tt.Run(scenario.desc, func(t *testing.T) {\n\t\t\t// define model layer mock\n\t\t\tmockGetModel := scenario.inModelMock()\n\n\t\t\t// build handler\n\t\t\thandler := NewGetHandler(mockGetModel)\n\n\t\t\t// perform request\n\t\t\tresponse := httptest.NewRecorder()\n\t\t\thandler.ServeHTTP(response, scenario.inRequest())\n\n\t\t\t// validate outputs\n\t\t\trequire.Equal(t, scenario.expectedStatus, response.Code, scenario.desc)\n\n\t\t\tpayload, _ := ioutil.ReadAll(response.Body)\n\t\t\tassert.Equal(t, scenario.expectedPayload, string(payload), scenario.desc)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "ch06/acme/internal/rest/list.go",
    "content": "package rest\n\nimport (\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/acme/internal/modules/data\"\n)\n\n// ListModel will load all registrations\n//go:generate mockery -name=ListModel -case underscore -testonly -inpkg -note @generated\ntype ListModel interface {\n\tDo() ([]*data.Person, error)\n}\n\n// NewLister is the constructor for ListHandler\nfunc NewListHandler(model ListModel) *ListHandler {\n\treturn &ListHandler{\n\t\tlister: model,\n\t}\n}\n\n// ListHandler is the HTTP handler for the \"List Do people\" endpoint\n// In this simplified example we are assuming all possible errors are system errors (HTTP 500)\ntype ListHandler struct {\n\tlister ListModel\n}\n\n// ServeHTTP implements http.Handler\nfunc (h *ListHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\t// attempt loadAll\n\tpeople, err := h.lister.Do()\n\tif err != nil {\n\t\t// not need to log here as we can expect other layers to do so\n\t\tresponse.WriteHeader(http.StatusNotFound)\n\t\treturn\n\t}\n\n\t// happy path\n\terr = h.writeJSON(response, people)\n\tif err != nil {\n\t\t// this error should not happen but if it does there is nothing we can do to recover\n\t\tresponse.WriteHeader(http.StatusInternalServerError)\n\t}\n}\n\n// output the result as JSON\nfunc (h *ListHandler) writeJSON(writer io.Writer, people []*data.Person) error {\n\toutput := &listResponseFormat{\n\t\tPeople: make([]*listResponseItemFormat, len(people)),\n\t}\n\n\tfor index, record := range people {\n\t\toutput.People[index] = &listResponseItemFormat{\n\t\t\tID:       record.ID,\n\t\t\tFullName: record.FullName,\n\t\t\tPhone:    record.Phone,\n\t\t}\n\t}\n\n\t// call to http.ResponseWriter.Write() will cause HTTP OK (200) to be output as well\n\treturn json.NewEncoder(writer).Encode(output)\n}\n\ntype listResponseFormat struct {\n\tPeople []*listResponseItemFormat `json:\"people\"`\n}\n\ntype listResponseItemFormat struct {\n\tID       int    `json:\"id\"`\n\tFullName string `json:\"name\"`\n\tPhone    string `json:\"phone\"`\n}\n"
  },
  {
    "path": "ch06/acme/internal/rest/list_test.go",
    "content": "package rest\n\nimport (\n\t\"errors\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestListHandler_ServeHTTP(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc            string\n\t\tinRequest       func() *http.Request\n\t\tinModelMock     func() *MockListModel\n\t\texpectedStatus  int\n\t\texpectedPayload string\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/list\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn req\n\t\t\t},\n\t\t\tinModelMock: func() *MockListModel {\n\t\t\t\toutput := []*data.Person{\n\t\t\t\t\t{\n\t\t\t\t\t\tID:       1,\n\t\t\t\t\t\tFullName: \"John\",\n\t\t\t\t\t\tPhone:    \"0123456789\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tID:       2,\n\t\t\t\t\t\tFullName: \"Paul\",\n\t\t\t\t\t\tPhone:    \"0123456781\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tID:       3,\n\t\t\t\t\t\tFullName: \"George\",\n\t\t\t\t\t\tPhone:    \"0123456782\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tID:       1,\n\t\t\t\t\t\tFullName: \"Ringo\",\n\t\t\t\t\t\tPhone:    \"0123456783\",\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\tmockListModel := &MockListModel{}\n\t\t\t\tmockListModel.On(\"Do\", mock.Anything).Return(output, nil).Once()\n\n\t\t\t\treturn mockListModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusOK,\n\t\t\texpectedPayload: `{\"people\":[{\"id\":1,\"name\":\"John\",\"phone\":\"0123456789\"},{\"id\":2,\"name\":\"Paul\",\"phone\":\"0123456781\"},{\"id\":3,\"name\":\"George\",\"phone\":\"0123456782\"},{\"id\":1,\"name\":\"Ringo\",\"phone\":\"0123456783\"}]}` + \"\\n\",\n\t\t},\n\t\t{\n\t\t\tdesc: \"dependency failure\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/list\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn req\n\t\t\t},\n\t\t\tinModelMock: func() *MockListModel {\n\t\t\t\tmockListModel := &MockListModel{}\n\t\t\t\tmockListModel.On(\"Do\", mock.Anything).Return(nil, errors.New(\"something failed\")).Once()\n\n\t\t\t\treturn mockListModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusNotFound,\n\t\t\texpectedPayload: ``,\n\t\t},\n\t\t{\n\t\t\tdesc: \"no data\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/list\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn req\n\t\t\t},\n\t\t\tinModelMock: func() *MockListModel {\n\t\t\t\t// no data\n\t\t\t\toutput := []*data.Person{}\n\n\t\t\t\tmockListModel := &MockListModel{}\n\t\t\t\tmockListModel.On(\"Do\", mock.Anything).Return(output, nil).Once()\n\n\t\t\t\treturn mockListModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusOK,\n\t\t\texpectedPayload: `{\"people\":[]}` + \"\\n\",\n\t\t},\n\t}\n\n\tfor _, s := range scenarios {\n\t\tscenario := s\n\t\tt.Run(scenario.desc, func(t *testing.T) {\n\t\t\t// define model layer mock\n\t\t\tmockListModel := scenario.inModelMock()\n\n\t\t\t// build handler\n\t\t\thandler := NewListHandler(mockListModel)\n\n\t\t\t// perform request\n\t\t\tresponse := httptest.NewRecorder()\n\t\t\thandler.ServeHTTP(response, scenario.inRequest())\n\n\t\t\t// validate outputs\n\t\t\trequire.Equal(t, scenario.expectedStatus, response.Code, scenario.desc)\n\n\t\t\tpayload, _ := ioutil.ReadAll(response.Body)\n\t\t\tassert.Equal(t, scenario.expectedPayload, string(payload), scenario.desc)\n\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "ch06/acme/internal/rest/mock_get_model_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage rest\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// MockGetModel is an autogenerated mock type for the GetModel type\ntype MockGetModel struct {\n\tmock.Mock\n}\n\n// Do provides a mock function with given fields: ID\nfunc (_m *MockGetModel) Do(ID int) (*data.Person, error) {\n\tret := _m.Called(ID)\n\n\tvar r0 *data.Person\n\tif rf, ok := ret.Get(0).(func(int) *data.Person); ok {\n\t\tr0 = rf(ID)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*data.Person)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(int) error); ok {\n\t\tr1 = rf(ID)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch06/acme/internal/rest/mock_list_model_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage rest\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// MockListModel is an autogenerated mock type for the ListModel type\ntype MockListModel struct {\n\tmock.Mock\n}\n\n// Do provides a mock function with given fields:\nfunc (_m *MockListModel) Do() ([]*data.Person, error) {\n\tret := _m.Called()\n\n\tvar r0 []*data.Person\n\tif rf, ok := ret.Get(0).(func() []*data.Person); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]*data.Person)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func() error); ok {\n\t\tr1 = rf()\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch06/acme/internal/rest/mock_register_model_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage rest\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// MockRegisterModel is an autogenerated mock type for the RegisterModel type\ntype MockRegisterModel struct {\n\tmock.Mock\n}\n\n// Do provides a mock function with given fields: in\nfunc (_m *MockRegisterModel) Do(in *data.Person) (int, error) {\n\tret := _m.Called(in)\n\n\tvar r0 int\n\tif rf, ok := ret.Get(0).(func(*data.Person) int); ok {\n\t\tr0 = rf(in)\n\t} else {\n\t\tr0 = ret.Get(0).(int)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(*data.Person) error); ok {\n\t\tr1 = rf(in)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch06/acme/internal/rest/not_found.go",
    "content": "package rest\n\nimport (\n\t\"net/http\"\n)\n\nfunc notFoundHandler(response http.ResponseWriter, _ *http.Request) {\n\tresponse.WriteHeader(http.StatusNotFound)\n\t_, _ = response.Write([]byte(`Not found`))\n}\n"
  },
  {
    "path": "ch06/acme/internal/rest/not_found_test.go",
    "content": "package rest\n\nimport (\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestNotFoundHandler_ServeHTTP(t *testing.T) {\n\t// build inputs\n\tresponse := httptest.NewRecorder()\n\trequest := &http.Request{}\n\n\t// call handler\n\tnotFoundHandler(response, request)\n\n\t// validate outputs\n\trequire.Equal(t, http.StatusNotFound, response.Code)\n}\n"
  },
  {
    "path": "ch06/acme/internal/rest/register.go",
    "content": "package rest\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/acme/internal/modules/data\"\n)\n\n// RegisterModel will validate and save a registration\n//go:generate mockery -name=RegisterModel -case underscore -testonly -inpkg -note @generated\ntype RegisterModel interface {\n\tDo(in *data.Person) (int, error)\n}\n\n// NewRegisterHandler is the constructor for RegisterHandler\nfunc NewRegisterHandler(model RegisterModel) *RegisterHandler {\n\treturn &RegisterHandler{\n\t\tregisterer: model,\n\t}\n}\n\n// RegisterHandler is the HTTP handler for the \"Register\" endpoint\n// In this simplified example we are assuming all possible errors are user errors and returning \"bad request\" HTTP 400.\n// There are some programmer errors possible but hopefully these will be caught in testing.\ntype RegisterHandler struct {\n\tregisterer RegisterModel\n}\n\n// ServeHTTP implements http.Handler\nfunc (h *RegisterHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\t// extract payload from request\n\trequestPayload, err := h.extractPayload(request)\n\tif err != nil {\n\t\t// output error\n\t\tresponse.WriteHeader(http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// register person\n\tid, err := h.register(requestPayload)\n\tif err != nil {\n\t\t// not need to log here as we can expect other layers to do so\n\t\tresponse.WriteHeader(http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// happy path\n\tresponse.Header().Add(\"Location\", fmt.Sprintf(\"/person/%d/\", id))\n\tresponse.WriteHeader(http.StatusCreated)\n}\n\n// extract payload from request\nfunc (h *RegisterHandler) extractPayload(request *http.Request) (*registerRequest, error) {\n\trequestPayload := &registerRequest{}\n\n\tdecoder := json.NewDecoder(request.Body)\n\terr := decoder.Decode(requestPayload)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn requestPayload, nil\n}\n\n// call the logic layer\nfunc (h *RegisterHandler) register(requestPayload *registerRequest) (int, error) {\n\tperson := &data.Person{\n\t\tFullName: requestPayload.FullName,\n\t\tPhone:    requestPayload.Phone,\n\t\tCurrency: requestPayload.Currency,\n\t}\n\n\treturn h.registerer.Do(person)\n}\n\n// register endpoint request format\ntype registerRequest struct {\n\t// FullName of the person\n\tFullName string `json:\"fullName\"`\n\t// Phone of the person\n\tPhone string `json:\"phone\"`\n\t// Currency the wish to register in\n\tCurrency string `json:\"currency\"`\n}\n"
  },
  {
    "path": "ch06/acme/internal/rest/register_test.go",
    "content": "package rest\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestRegisterHandler_ServeHTTP(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc           string\n\t\tinRequest      func() *http.Request\n\t\tinModelMock    func() *MockRegisterModel\n\t\texpectedStatus int\n\t\texpectedHeader string\n\t}{\n\t\t{\n\t\t\tdesc: \"Happy Path\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\tvalidRequest := buildValidRegisterRequest()\n\t\t\t\trequest, err := http.NewRequest(\"POST\", \"/person/register\", validRequest)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn request\n\t\t\t},\n\t\t\tinModelMock: func() *MockRegisterModel {\n\t\t\t\t// valid downstream configuration\n\t\t\t\tresultID := 1234\n\t\t\t\tvar resultErr error\n\n\t\t\t\tmockRegisterModel := &MockRegisterModel{}\n\t\t\t\tmockRegisterModel.On(\"Do\", mock.Anything).Return(resultID, resultErr).Once()\n\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus: http.StatusCreated,\n\t\t\texpectedHeader: \"/person/1234/\",\n\t\t},\n\t\t{\n\t\t\tdesc: \"Bad Input / User Error\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\tinvalidRequest := bytes.NewBufferString(`this is not valid JSON`)\n\t\t\t\trequest, err := http.NewRequest(\"POST\", \"/person/register\", invalidRequest)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn request\n\t\t\t},\n\t\t\tinModelMock: func() *MockRegisterModel {\n\t\t\t\t// Dependency should not be called\n\t\t\t\tmockRegisterModel := &MockRegisterModel{}\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus: http.StatusBadRequest,\n\t\t\texpectedHeader: \"\",\n\t\t},\n\t\t{\n\t\t\tdesc: \"Dependency Failure\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\tvalidRequest := buildValidRegisterRequest()\n\t\t\t\trequest, err := http.NewRequest(\"POST\", \"/person/register\", validRequest)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn request\n\t\t\t},\n\t\t\tinModelMock: func() *MockRegisterModel {\n\t\t\t\t// call to the dependency failed\n\t\t\t\tresultErr := errors.New(\"something failed\")\n\n\t\t\t\tmockRegisterModel := &MockRegisterModel{}\n\t\t\t\tmockRegisterModel.On(\"Do\", mock.Anything).Return(0, resultErr).Once()\n\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus: http.StatusBadRequest,\n\t\t\texpectedHeader: \"\",\n\t\t},\n\t}\n\n\tfor _, s := range scenarios {\n\t\tscenario := s\n\t\tt.Run(scenario.desc, func(t *testing.T) {\n\t\t\t// define model layer mock\n\t\t\tmockRegisterModel := scenario.inModelMock()\n\n\t\t\t// build handler\n\t\t\thandler := NewRegisterHandler(mockRegisterModel)\n\n\t\t\t// perform request\n\t\t\tresponse := httptest.NewRecorder()\n\t\t\thandler.ServeHTTP(response, scenario.inRequest())\n\n\t\t\t// validate outputs\n\t\t\trequire.Equal(t, scenario.expectedStatus, response.Code)\n\n\t\t\t// call should output the location to the new person\n\t\t\tresultHeader := response.Header().Get(\"Location\")\n\t\t\tassert.Equal(t, scenario.expectedHeader, resultHeader)\n\n\t\t\t// validate the mock was used as we expected\n\t\t\tassert.True(t, mockRegisterModel.AssertExpectations(t))\n\t\t})\n\t}\n}\n\nfunc buildValidRegisterRequest() io.Reader {\n\trequestData := &registerRequest{\n\t\tFullName: \"Joan Smith\",\n\t\tCurrency: \"AUD\",\n\t\tPhone:    \"01234567890\",\n\t}\n\n\tdata, _ := json.Marshal(requestData)\n\treturn bytes.NewBuffer(data)\n}\n"
  },
  {
    "path": "ch06/acme/internal/rest/server.go",
    "content": "package rest\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/gorilla/mux\"\n)\n\n// New will create and initialize the server\nfunc New(address string,\n\tgetModel GetModel,\n\tlistModel ListModel,\n\tregisterModel RegisterModel) *Server {\n\n\treturn &Server{\n\t\taddress:         address,\n\t\thandlerGet:      NewGetHandler(getModel),\n\t\thandlerList:     NewListHandler(listModel),\n\t\thandlerNotFound: notFoundHandler,\n\t\thandlerRegister: NewRegisterHandler(registerModel),\n\t}\n}\n\n// Server is the HTTP REST server\ntype Server struct {\n\taddress string\n\tserver  *http.Server\n\n\thandlerGet      http.Handler\n\thandlerList     http.Handler\n\thandlerNotFound http.HandlerFunc\n\thandlerRegister http.Handler\n}\n\n// Listen will start a HTTP rest for this service\nfunc (s *Server) Listen(stop <-chan struct{}) {\n\trouter := s.buildRouter()\n\n\t// create the HTTP server\n\ts.server = &http.Server{\n\t\tHandler: router,\n\t\tAddr:    s.address,\n\t}\n\n\t// listen for shutdown\n\tgo func() {\n\t\t// wait for shutdown signal\n\t\t<-stop\n\n\t\t_ = s.server.Close()\n\t}()\n\n\t// start the HTTP server\n\t_ = s.server.ListenAndServe()\n}\n\n// configure the endpoints to handlers\nfunc (s *Server) buildRouter() http.Handler {\n\trouter := mux.NewRouter()\n\n\t// map URL endpoints to HTTP handlers\n\trouter.Handle(\"/person/{id}/\", s.handlerGet).Methods(\"GET\")\n\trouter.Handle(\"/person/list\", s.handlerList).Methods(\"GET\")\n\trouter.Handle(\"/person/register\", s.handlerRegister).Methods(\"POST\")\n\n\t// convert a \"catch all\" not found handler\n\trouter.NotFoundHandler = s.handlerNotFound\n\n\treturn router\n}\n"
  },
  {
    "path": "ch06/acme/main.go",
    "content": "package main\n\nimport (\n\t\"context\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/acme/internal/config\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/acme/internal/modules/get\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/acme/internal/modules/list\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/acme/internal/modules/register\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch06/acme/internal/rest\"\n)\n\nfunc main() {\n\t// bind stop channel to context\n\tctx := context.Background()\n\n\t// build model layer\n\tgetModel := &get.Getter{}\n\tlistModel := &list.Lister{}\n\tregisterModel := &register.Registerer{}\n\n\t// start REST server\n\tserver := rest.New(config.App.Address, getModel, listModel, registerModel)\n\tserver.Listen(ctx.Done())\n}\n"
  },
  {
    "path": "ch06/fake.go",
    "content": "package ch06\n\nfunc init() {\n\t// This file is included so that Go tools (like `go list`) will find Go code in this directory and not error\n}\n"
  },
  {
    "path": "ch06/pcov-html",
    "content": "#!/usr/bin/env bash\n\nif [ \"$1\" == \"\" ]; then\n\techo \"No input file. Usage: pcov-html ./your-package-dir/\"\n\texit 1\nfi\n\n# Inputs\n# Trim any ... from the end of the supplied directory\nDIR=${1%...}\n# Ensure there is a / at the end of the directory\nPKG_DIR=${DIR%/}/\n\n# Generated coverage\ngo test $PKG_DIR -coverprofile=$PKG_DIR/coverage.out ${@:1}\n\n# Convert coverage to HTML\ngo tool cover -html=$PKG_DIR/coverage.out\n\n# Clean up after ourselves\nrm $PKG_DIR/coverage.out\n"
  },
  {
    "path": "ch07/01_method_injection/01_fprint.go",
    "content": "package method_injection\n\nimport (\n\t\"fmt\"\n\t\"os\"\n)\n\nfunc ExampleA() {\n\tfmt.Fprint(os.Stdout, \"Hello World\")\n}\n"
  },
  {
    "path": "ch07/01_method_injection/02_http_request.go",
    "content": "package method_injection\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"net/http\"\n)\n\nfunc ExampleB() {\n\t// added to make the compiler happy\n\tbody := &bytes.Buffer{}\n\n\t// example is here\n\treq, err := http.NewRequest(\"POST\", \"/login\", body)\n\n\t// added to make the compiler happy\n\tfmt.Printf(\"req: %#v / err: %s\", req, err)\n}\n"
  },
  {
    "path": "ch07/01_method_injection/03_fprint.go",
    "content": "package method_injection\n\nimport (\n\t\"io\"\n)\n\n// Fprint formats using the default formats for its operands and writes to w.\n// It returns the number of bytes written and any write error encountered.\nfunc Fprint(w io.Writer, a ...interface{}) (n int, err error) {\n\treturn\n}\n"
  },
  {
    "path": "ch07/01_method_injection/04_http_request.go",
    "content": "package method_injection\n\nimport (\n\t\"io\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"net/url\"\n)\n\nfunc NewRequest(method, url string, body io.Reader) (*http.Request, error) {\n\t// validate method\n\tm, err := validateMethod(method)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// validate URL\n\tu, err := validateURL(url)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// process body (if exists)\n\tvar b io.ReadCloser\n\tif body != nil {\n\t\t// read body\n\t\tb = ioutil.NopCloser(body)\n\t}\n\n\t// build Request and return\n\treq := &http.Request{\n\t\tURL:    u,\n\t\tMethod: m,\n\t\tBody:   b,\n\t}\n\n\treturn req, nil\n}\n\nfunc validateMethod(method string) (string, error) {\n\treturn \"\", nil\n}\n\nfunc validateURL(url string) (*url.URL, error) {\n\treturn nil, nil\n}\n"
  },
  {
    "path": "ch07/01_method_injection/05_timestamp_writer_v1.go",
    "content": "package method_injection\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"time\"\n)\n\n// TimeStampWriterV1 will output the supplied message to writer preceded with a timestamp\nfunc TimeStampWriterV1(writer io.Writer, message string) {\n\ttimestamp := time.Now().Format(time.RFC3339)\n\tfmt.Fprintf(writer, \"%s -> %s\", timestamp, message)\n}\n"
  },
  {
    "path": "ch07/01_method_injection/06_timestamp_writer_v2.go",
    "content": "package method_injection\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"time\"\n)\n\n// TimeStampWriterV2 will output the supplied message to writer preceded with a timestamp\nfunc TimeStampWriterV2(writer io.Writer, message string) error {\n\tif writer == nil {\n\t\treturn errors.New(\"writer cannot be nil\")\n\t}\n\n\ttimestamp := time.Now().Format(time.RFC3339)\n\tfmt.Fprintf(writer, \"%s -> %s\", timestamp, message)\n\n\treturn nil\n}\n"
  },
  {
    "path": "ch07/01_method_injection/07_timestamp_writer_v3.go",
    "content": "package method_injection\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"time\"\n)\n\n// TimeStampWriterV3 will output the supplied message to writer preceded with a timestamp\nfunc TimeStampWriterV3(writer io.Writer, message string) {\n\tif writer == nil {\n\t\t// default to Standard Out\n\t\twriter = os.Stdout\n\t}\n\n\ttimestamp := time.Now().Format(time.RFC3339)\n\tfmt.Fprintf(writer, \"%s -> %s\", timestamp, message)\n}\n"
  },
  {
    "path": "ch07/02_advantages/01_handler_v1.go",
    "content": "package advantages\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n)\n\nfunc HandlerV1(response http.ResponseWriter, request *http.Request) {\n\tgarfield := &Animal{\n\t\tType: \"Cat\",\n\t\tName: \"Garfield\",\n\t}\n\n\t// encode as JSON and output\n\tencoder := json.NewEncoder(response)\n\terr := encoder.Encode(garfield)\n\tif err != nil {\n\t\tresponse.WriteHeader(http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tresponse.WriteHeader(http.StatusOK)\n}\n\ntype Animal struct {\n\tType string\n\tName string\n}\n"
  },
  {
    "path": "ch07/02_advantages/02_handler_v2.go",
    "content": "package advantages\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n)\n\nfunc HandlerV2(response http.ResponseWriter, request *http.Request) {\n\tgarfield := &Animal{\n\t\tType: \"Cat\",\n\t\tName: \"Garfield\",\n\t}\n\n\t// encode as JSON and output\n\toutputAnimal(response, garfield)\n}\n\nfunc outputAnimal(response http.ResponseWriter, animal *Animal) {\n\tencoder := json.NewEncoder(response)\n\terr := encoder.Encode(animal)\n\tif err != nil {\n\t\tresponse.WriteHeader(http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\t// Happy Path\n\tresponse.WriteHeader(http.StatusOK)\n}\n"
  },
  {
    "path": "ch07/02_advantages/03_handler_v3.go",
    "content": "package advantages\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n)\n\nfunc HandlerV3(response http.ResponseWriter, request *http.Request) {\n\tgarfield := &Animal{\n\t\tType: \"Cat\",\n\t\tName: \"Garfield\",\n\t}\n\n\t// encode as JSON and output\n\toutputJSON(response, garfield)\n}\n\nfunc outputJSON(response http.ResponseWriter, data interface{}) {\n\tencoder := json.NewEncoder(response)\n\terr := encoder.Encode(data)\n\tif err != nil {\n\t\tresponse.WriteHeader(http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\t// Happy Path\n\tresponse.WriteHeader(http.StatusOK)\n}\n"
  },
  {
    "path": "ch07/02_advantages/04_context_influence.go",
    "content": "package advantages\n\nimport (\n\t\"io\"\n\t\"net\"\n\t\"os\"\n)\n\nfunc WriteLog(writer io.Writer, message string) error {\n\t_, err := writer.Write([]byte(message))\n\treturn err\n}\n\nfunc Usage() {\n\t// Write to console\n\tWriteLog(os.Stdout, \"Hello World!\")\n\n\t// Write to file\n\tfile, _ := os.Create(\"my-log.log\")\n\tWriteLog(file, \"Hello World!\")\n\n\t// Write to TCP connection\n\ttcpPipe, _ := net.Dial(\"tcp\", \"127.0.0.1:1234\")\n\tWriteLog(tcpPipe, \"Hello World!\")\n}\n"
  },
  {
    "path": "ch07/02_advantages/05_person_loader.go",
    "content": "package advantages\n\nimport (\n\t\"database/sql\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"net/http\"\n)\n\nvar (\n\t// thrown when the supplied order does not exist in the database\n\terrNotFound = errors.New(\"order not found\")\n)\n\n// Loads orders based on supplied owner and order ID\ntype OrderLoader interface {\n\tloadOrder(owner Owner, orderID int) (Order, error)\n}\n\n// NewLoadOrderHandler creates a new instance of LoadOrderHandler\nfunc NewLoadOrderHandler(loader OrderLoader) *LoadOrderHandler {\n\treturn &LoadOrderHandler{\n\t\tloader: loader,\n\t}\n}\n\n// LoadOrderHandler is a HTTP handler that loads orders based on the current user and supplied user ID\ntype LoadOrderHandler struct {\n\tloader OrderLoader\n}\n\n// ServeHTTP implements http.Handler\nfunc (l *LoadOrderHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\t// extract user from supplied authentication credentials\n\tcurrentUser, err := l.authenticateUser(request)\n\tif err != nil {\n\t\tresponse.WriteHeader(http.StatusUnauthorized)\n\t\treturn\n\t}\n\n\t// extract order ID from request\n\torderID, err := l.extractOrderID(request)\n\tif err != nil {\n\t\tresponse.WriteHeader(http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// load order using the current user as a request-scoped dependency\n\t// (with method injection)\n\torder, err := l.loader.loadOrder(currentUser, orderID)\n\tif err != nil {\n\t\tresponse.WriteHeader(http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\t// output order\n\tencoder := json.NewEncoder(response)\n\terr = encoder.Encode(order)\n\tif err != nil {\n\t\tresponse.WriteHeader(http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tresponse.WriteHeader(http.StatusOK)\n}\n\n// AuthenticatedLoader will load orders for based on the supplied owner\ntype AuthenticatedLoader struct {\n\t// This pool is expensive to create.  We will want to create it once and then reuse it.\n\tdb *sql.DB\n}\n\n// load the order from the database based on owner and order ID\nfunc (a *AuthenticatedLoader) loadByOwner(owner Owner, orderID int) (*Order, error) {\n\torder, err := a.load(orderID)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif order.OwnerID != owner.ID() {\n\t\t// Return not found so we do not leak information to hackers\n\t\treturn nil, errNotFound\n\t}\n\n\t// happy path\n\treturn order, nil\n}\n\nfunc (a *AuthenticatedLoader) load(orderID int) (*Order, error) {\n\t// load order from DB\n\treturn &Order{OwnerID: 1}, nil\n}\n\ntype Owner interface {\n\tID() int\n}\n\ntype Order struct {\n\tOwnerID int\n\n\t// other order details\n}\n\ntype User struct {\n\tid int\n\n\t// other attributes\n}\n\nfunc (u *User) ID() int {\n\treturn u.id\n}\n\n// Extract the user from the request (e.g. from a JWT token).\nfunc (l *LoadOrderHandler) authenticateUser(request *http.Request) (*User, error) {\n\treturn &User{id: 1}, nil\n}\n\n// Extract the order ID from the request (e.g. from the URL or HTTP POST body)\nfunc (l *LoadOrderHandler) extractOrderID(request *http.Request) (int, error) {\n\treturn 2, nil\n}\n"
  },
  {
    "path": "ch07/04_disadvantages/01_data_struct.go",
    "content": "package disadvantages\n\nimport (\n\t\"database/sql\"\n\t\"errors\"\n)\n\n// Load people from the database\ntype PersonLoader struct {\n}\n\nfunc (d *PersonLoader) Load(db *sql.DB, ID int) (*Person, error) {\n\treturn nil, errors.New(\"not implemented\")\n}\n\nfunc (d *PersonLoader) LoadAll(db *sql.DB) ([]*Person, error) {\n\treturn nil, errors.New(\"not implemented\")\n}\n\ntype Person struct {\n\tName string\n\tAge  int\n}\n"
  },
  {
    "path": "ch07/04_disadvantages/02_ux_improvement.go",
    "content": "package disadvantages\n\ntype MyPersonLoader interface {\n\tLoad(ID int) (*Person, error)\n}\n"
  },
  {
    "path": "ch07/04_disadvantages/03_many_params.go",
    "content": "package disadvantages\n\nimport (\n\t\"io\"\n)\n\ntype Generator struct{}\n\nfunc (g *Generator) Generate(storage Storage, template io.Reader, destination io.Writer, renderer Renderer, formatter Formatter, params ...interface{}) {\n\n}\n\ntype Storage interface {\n\tLoad() []interface{}\n}\n\ntype Renderer interface {\n\tRender(template io.Reader, params ...interface{}) []byte\n}\n\ntype Formatter interface {\n\tFormat([]byte) []byte\n}\n"
  },
  {
    "path": "ch07/04_disadvantages/04_many_params_v2.go",
    "content": "package disadvantages\n\nimport (\n\t\"io\"\n)\n\nfunc NewGeneratorV2(storage Storage, renderer Renderer, formatter Formatter) *GeneratorV2 {\n\treturn &GeneratorV2{\n\t\tstorage:   storage,\n\t\trenderer:  renderer,\n\t\tformatter: formatter,\n\t}\n}\n\ntype GeneratorV2 struct {\n\tstorage   Storage\n\trenderer  Renderer\n\tformatter Formatter\n}\n\nfunc (g *GeneratorV2) Generate(template io.Reader, destination io.Writer, params ...interface{}) {\n\n}\n"
  },
  {
    "path": "ch07/acme/internal/config/config.go",
    "content": "package config\n\nimport (\n\t\"encoding/json\"\n\t\"io/ioutil\"\n\t\"os\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch07/acme/internal/logging\"\n)\n\n// DefaultEnvVar is the default environment variable the points to the config file\nconst DefaultEnvVar = \"ACME_CONFIG\"\n\n// App is the application config\nvar App *Config\n\n// Config defines the JSON format for the config file\ntype Config struct {\n\t// DSN is the data source name (format: https://github.com/go-sql-driver/mysql/#dsn-data-source-name)\n\tDSN string\n\n\t// Address is the IP address and port to bind this rest to\n\tAddress string\n\n\t// BasePrice is the price of registration\n\tBasePrice float64\n\n\t// ExchangeRateBaseURL is the server and protocol part of the URL from which to load the exchange rate\n\tExchangeRateBaseURL string\n\n\t// ExchangeRateAPIKey is the API for the exchange rate API\n\tExchangeRateAPIKey string\n}\n\n// Load returns the config loaded from environment\nfunc init() {\n\tfilename, found := os.LookupEnv(DefaultEnvVar)\n\tif !found {\n\t\tlogging.L.Error(\"failed to locate file specified by %s\", DefaultEnvVar)\n\t\treturn\n\t}\n\n\t_ = load(filename)\n}\n\nfunc load(filename string) error {\n\tApp = &Config{}\n\tbytes, err := ioutil.ReadFile(filename)\n\tif err != nil {\n\t\tlogging.L.Error(\"failed to read config file. err: %s\", err)\n\t\treturn err\n\t}\n\n\terr = json.Unmarshal(bytes, App)\n\tif err != nil {\n\t\tlogging.L.Error(\"failed to parse config file. err : %s\", err)\n\t\treturn err\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "ch07/acme/internal/config/config_test.go",
    "content": "package config\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestLoad(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc           string\n\t\tin             string\n\t\texpectedConfig *Config\n\t\texpectError    bool\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tin:   \"../../../../default-config.json\",\n\t\t\texpectedConfig: &Config{\n\t\t\t\tDSN:                 \"[insert your db config here]\",\n\t\t\t\tAddress:             \"0.0.0.0:8080\",\n\t\t\t\tBasePrice:           100.00,\n\t\t\t\tExchangeRateBaseURL: \"http://apilayer.net\",\n\t\t\t\tExchangeRateAPIKey:  \"[insert your API key here]\",\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tdesc:           \"invalid path\",\n\t\t\tin:             \"invalid.json\",\n\t\t\texpectedConfig: &Config{},\n\t\t\texpectError:    true,\n\t\t},\n\t}\n\n\tfor _, s := range scenarios {\n\t\tscenario := s\n\t\tt.Run(scenario.desc, func(t *testing.T) {\n\t\t\tresultErr := load(scenario.in)\n\t\t\trequire.Equal(t, scenario.expectError, resultErr != nil, \"err: %s\", resultErr)\n\t\t\tassert.Equal(t, scenario.expectedConfig, App, scenario.desc)\n\t\t})\n\t}\n\n}\n"
  },
  {
    "path": "ch07/acme/internal/logging/logging.go",
    "content": "package logging\n\nimport (\n\t\"fmt\"\n)\n\n// L is the global instance of the logger\nvar L = &LoggerStdOut{}\n\n// LoggerStdOut logs to std out\ntype LoggerStdOut struct{}\n\n// Debug logs messages at DEBUG level\nfunc (l LoggerStdOut) Debug(message string, args ...interface{}) {\n\tfmt.Printf(\"[DEBUG] \"+message, args...)\n}\n\n// Info logs messages at INFO level\nfunc (l LoggerStdOut) Info(message string, args ...interface{}) {\n\tfmt.Printf(\"[INFO] \"+message, args...)\n}\n\n// Warn logs messages at WARN level\nfunc (l LoggerStdOut) Warn(message string, args ...interface{}) {\n\tfmt.Printf(\"[WARN] \"+message, args...)\n}\n\n// Error logs messages at ERROR level\nfunc (l LoggerStdOut) Error(message string, args ...interface{}) {\n\tfmt.Printf(\"[ERROR] \"+message, args...)\n}\n"
  },
  {
    "path": "ch07/acme/internal/modules/data/data.go",
    "content": "package data\n\nimport (\n\t// import the MySQL Driver\n\t\"context\"\n\t\"database/sql\"\n\t\"errors\"\n\t\"time\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch07/acme/internal/config\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch07/acme/internal/logging\"\n\t_ \"github.com/go-sql-driver/mysql\"\n)\n\nconst (\n\t// default person id (returned on error)\n\tdefaultPersonID = 0\n\n\t// SQL statements as constants (to reduce duplication and maintenance in tests)\n\tsqlAllColumns = \"id, fullname, phone, currency, price\"\n\tsqlInsert     = \"INSERT INTO person (fullname, phone, currency, price) VALUES (?, ?, ?, ?)\"\n\tsqlLoadAll    = \"SELECT \" + sqlAllColumns + \" FROM person\"\n\tsqlLoadByID   = \"SELECT \" + sqlAllColumns + \" FROM person WHERE id = ? LIMIT 1\"\n)\n\nvar (\n\tdb *sql.DB\n\n\t// ErrNotFound is returned when the no records where matched by the query\n\tErrNotFound = errors.New(\"not found\")\n)\n\nvar getDB = func() (*sql.DB, error) {\n\tif db == nil {\n\t\tif config.App == nil {\n\t\t\treturn nil, errors.New(\"config is not initialized\")\n\t\t}\n\n\t\tvar err error\n\t\tdb, err = sql.Open(\"mysql\", config.App.DSN)\n\t\tif err != nil {\n\t\t\t// if the DB cannot be accessed we are dead\n\t\t\tpanic(err.Error())\n\t\t}\n\t}\n\n\treturn db, nil\n}\n\n// Person is the data transfer object (DTO) for this package\ntype Person struct {\n\t// ID is the unique ID for this person\n\tID int\n\t// FullName is the name of this person\n\tFullName string\n\t// Phone is the phone for this person\n\tPhone string\n\t// Currency is the currency this person has paid in\n\tCurrency string\n\t// Price is the amount (in the above currency) paid by this person\n\tPrice float64\n}\n\n// Save will save the supplied person and return the ID of the newly created person or an error.\n// Errors returned are caused by the underlying database or our connection to it.\nfunc Save(ctx context.Context, in *Person) (int, error) {\n\tdb, err := getDB()\n\tif err != nil {\n\t\tlogging.L.Error(\"failed to get DB connection. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\t// set latency budget for the database call\n\tsubCtx, cancel := context.WithTimeout(ctx, 1*time.Second)\n\tdefer cancel()\n\n\t// perform DB insert\n\tresult, err := db.ExecContext(subCtx, sqlInsert, in.FullName, in.Phone, in.Currency, in.Price)\n\tif err != nil {\n\t\tlogging.L.Error(\"failed to save person into DB. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\t// retrieve and return the ID of the person created\n\tid, err := result.LastInsertId()\n\tif err != nil {\n\t\tlogging.L.Error(\"failed to retrieve id of last saved person. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn int(id), nil\n}\n\n// LoadAll will attempt to load all people in the database\n// It will return ErrNotFound when there are not people in the database\n// Any other errors returned are caused by the underlying database or our connection to it.\nfunc LoadAll(ctx context.Context) ([]*Person, error) {\n\tdb, err := getDB()\n\tif err != nil {\n\t\tlogging.L.Error(\"failed to get DB connection. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// set latency budget for the database call\n\tsubCtx, cancel := context.WithTimeout(ctx, 1*time.Second)\n\tdefer cancel()\n\n\t// perform DB select\n\trows, err := db.QueryContext(subCtx, sqlLoadAll)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer func() {\n\t\t_ = rows.Close()\n\t}()\n\n\tvar out []*Person\n\n\tfor rows.Next() {\n\t\t// retrieve columns and populate the person object\n\t\trecord, err := populatePerson(rows.Scan)\n\t\tif err != nil {\n\t\t\tlogging.L.Error(\"failed to convert query result. err: %s\", err)\n\t\t\treturn nil, err\n\t\t}\n\n\t\tout = append(out, record)\n\t}\n\n\tif len(out) == 0 {\n\t\tlogging.L.Warn(\"no people found in the database.\")\n\t\treturn nil, ErrNotFound\n\t}\n\n\treturn out, nil\n}\n\n// Load will attempt to load and return a person.\n// It will return ErrNotFound when the requested person does not exist.\n// Any other errors returned are caused by the underlying database or our connection to it.\nfunc Load(ctx context.Context, ID int) (*Person, error) {\n\tdb, err := getDB()\n\tif err != nil {\n\t\tlogging.L.Error(\"failed to get DB connection. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// set latency budget for the database call\n\tsubCtx, cancel := context.WithTimeout(ctx, 1*time.Second)\n\tdefer cancel()\n\n\t// perform DB select\n\trow := db.QueryRowContext(subCtx, sqlLoadByID, ID)\n\n\t// retrieve columns and populate the person object\n\tout, err := populatePerson(row.Scan)\n\tif err != nil {\n\t\tif err == sql.ErrNoRows {\n\t\t\tlogging.L.Warn(\"failed to load requested person '%d'. err: %s\", ID, err)\n\t\t\treturn nil, ErrNotFound\n\t\t}\n\n\t\tlogging.L.Error(\"failed to convert query result. err: %s\", err)\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\n// custom type so we can convert sql results to easily\ntype scanner func(dest ...interface{}) error\n\n// reduce the duplication (and maintenance) between sql.Row and sql.Rows usage\nfunc populatePerson(scanner scanner) (*Person, error) {\n\tout := &Person{}\n\terr := scanner(&out.ID, &out.FullName, &out.Phone, &out.Currency, &out.Price)\n\treturn out, err\n}\n\nfunc init() {\n\t// ensure the config is loaded and the db initialized\n\t_, _ = getDB()\n}\n"
  },
  {
    "path": "ch07/acme/internal/modules/data/data_test.go",
    "content": "package data\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"errors\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/DATA-DOG/go-sqlmock\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestSave_happyPath(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\t// define a mock db\n\ttestDb, dbMock, err := sqlmock.New()\n\tdefer testDb.Close()\n\trequire.NoError(t, err)\n\n\t// configure the mock db\n\tqueryRegex := convertSQLToRegex(sqlInsert)\n\tdbMock.ExpectExec(queryRegex).WillReturnResult(sqlmock.NewResult(2, 1))\n\n\t// monkey patching starts here\n\tdefer func(original sql.DB) {\n\t\t// restore original DB (after test)\n\t\tdb = &original\n\t}(*db)\n\n\t// replace db for this test\n\tdb = testDb\n\t// end of monkey patch\n\n\t// inputs\n\tin := &Person{\n\t\tFullName: \"Jake Blues\",\n\t\tPhone:    \"01234567890\",\n\t\tCurrency: \"AUD\",\n\t\tPrice:    123.45,\n\t}\n\n\t// call function\n\tresultID, err := Save(ctx, in)\n\n\t// validate result\n\trequire.NoError(t, err)\n\tassert.Equal(t, 2, resultID)\n\tassert.NoError(t, dbMock.ExpectationsWereMet())\n}\n\nfunc TestSave_insertError(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\t// define a mock db\n\ttestDb, dbMock, err := sqlmock.New()\n\tdefer testDb.Close()\n\n\trequire.NoError(t, err)\n\n\t// configure the mock db\n\tqueryRegex := convertSQLToRegex(sqlInsert)\n\tdbMock.ExpectExec(queryRegex).WillReturnError(errors.New(\"failed to insert\"))\n\n\t// monkey patching starts here\n\tdefer func(original sql.DB) {\n\t\t// restore original DB (after test)\n\t\tdb = &original\n\t}(*db)\n\n\t// replace db for this test\n\tdb = testDb\n\t// end of monkey patch\n\n\t// inputs\n\tin := &Person{\n\t\tFullName: \"Jake Blues\",\n\t\tPhone:    \"01234567890\",\n\t\tCurrency: \"AUD\",\n\t\tPrice:    123.45,\n\t}\n\n\t// call function\n\tresultID, err := Save(ctx, in)\n\n\t// validate result\n\trequire.Error(t, err)\n\tassert.Equal(t, defaultPersonID, resultID)\n\tassert.NoError(t, dbMock.ExpectationsWereMet())\n}\n\nfunc TestSave_getDBError(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\t// monkey patching starts here\n\tdefer func(original func() (*sql.DB, error)) {\n\t\t// restore original DB (after test)\n\t\tgetDB = original\n\t}(getDB)\n\n\t// replace getDB() function for this test\n\tgetDB = func() (*sql.DB, error) {\n\t\treturn nil, errors.New(\"getDB() failed\")\n\t}\n\t// end of monkey patch\n\n\t// inputs\n\tin := &Person{\n\t\tFullName: \"Jake Blues\",\n\t\tPhone:    \"01234567890\",\n\t\tCurrency: \"AUD\",\n\t\tPrice:    123.45,\n\t}\n\n\t// call function\n\tresultID, err := Save(ctx, in)\n\trequire.Error(t, err)\n\tassert.Equal(t, defaultPersonID, resultID)\n}\n\nfunc TestLoadAll_tableDrivenTest(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\n\tdefer cancel()\n\n\tscenarios := []struct {\n\t\tdesc            string\n\t\tconfigureMockDB func(sqlmock.Sqlmock)\n\t\texpectedResults []*Person\n\t\texpectError     bool\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tconfigureMockDB: func(dbMock sqlmock.Sqlmock) {\n\t\t\t\tqueryRegex := convertSQLToRegex(sqlLoadAll)\n\t\t\t\tdbMock.ExpectQuery(queryRegex).WillReturnRows(\n\t\t\t\t\tsqlmock.NewRows(strings.Split(sqlAllColumns, \", \")).\n\t\t\t\t\t\tAddRow(1, \"John\", \"0123456789\", \"AUD\", 12.34))\n\t\t\t},\n\t\t\texpectedResults: []*Person{\n\t\t\t\t{\n\t\t\t\t\tID:       1,\n\t\t\t\t\tFullName: \"John\",\n\t\t\t\t\tPhone:    \"0123456789\",\n\t\t\t\t\tCurrency: \"AUD\",\n\t\t\t\t\tPrice:    12.34,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tdesc: \"load error\",\n\t\t\tconfigureMockDB: func(dbMock sqlmock.Sqlmock) {\n\t\t\t\tqueryRegex := convertSQLToRegex(sqlLoadAll)\n\t\t\t\tdbMock.ExpectQuery(queryRegex).WillReturnError(errors.New(\"something failed\"))\n\t\t\t},\n\t\t\texpectedResults: nil,\n\t\t\texpectError:     true,\n\t\t},\n\t}\n\n\tfor _, scenario := range scenarios {\n\t\t// define a mock db\n\t\ttestDb, dbMock, err := sqlmock.New()\n\t\trequire.NoError(t, err)\n\n\t\t// configure the mock db\n\t\tscenario.configureMockDB(dbMock)\n\n\t\t// monkey patch the db for this test\n\t\toriginal := *db\n\t\tdb = testDb\n\n\t\t// call function\n\t\tresults, err := LoadAll(ctx)\n\n\t\t// validate results\n\t\tassert.Equal(t, scenario.expectedResults, results, scenario.desc)\n\t\tassert.Equal(t, scenario.expectError, err != nil, scenario.desc)\n\t\tassert.NoError(t, dbMock.ExpectationsWereMet())\n\n\t\t// restore original DB (after test)\n\t\tdb = &original\n\t\ttestDb.Close()\n\t}\n}\n\nfunc TestLoad_tableDrivenTest(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\n\tdefer cancel()\n\n\tscenarios := []struct {\n\t\tdesc            string\n\t\tconfigureMockDB func(sqlmock.Sqlmock)\n\t\texpectedResult  *Person\n\t\texpectError     bool\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tconfigureMockDB: func(dbMock sqlmock.Sqlmock) {\n\t\t\t\tqueryRegex := convertSQLToRegex(sqlLoadAll)\n\t\t\t\tdbMock.ExpectQuery(queryRegex).WillReturnRows(\n\t\t\t\t\tsqlmock.NewRows(strings.Split(sqlAllColumns, \", \")).\n\t\t\t\t\t\tAddRow(2, \"Paul\", \"0123456789\", \"CAD\", 23.45))\n\t\t\t},\n\t\t\texpectedResult: &Person{\n\t\t\t\tID:       2,\n\t\t\t\tFullName: \"Paul\",\n\t\t\t\tPhone:    \"0123456789\",\n\t\t\t\tCurrency: \"CAD\",\n\t\t\t\tPrice:    23.45,\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tdesc: \"load error\",\n\t\t\tconfigureMockDB: func(dbMock sqlmock.Sqlmock) {\n\t\t\t\tqueryRegex := convertSQLToRegex(sqlLoadAll)\n\t\t\t\tdbMock.ExpectQuery(queryRegex).WillReturnError(errors.New(\"something failed\"))\n\t\t\t},\n\t\t\texpectedResult: nil,\n\t\t\texpectError:    true,\n\t\t},\n\t}\n\n\tfor _, scenario := range scenarios {\n\t\t// define a mock db\n\t\ttestDb, dbMock, err := sqlmock.New()\n\t\trequire.NoError(t, err)\n\n\t\t// configure the mock db\n\t\tscenario.configureMockDB(dbMock)\n\n\t\t// monkey db for this test\n\t\toriginal := *db\n\t\tdb = testDb\n\n\t\t// call function\n\t\tresult, err := Load(ctx, 2)\n\n\t\t// validate results\n\t\tassert.Equal(t, scenario.expectedResult, result, scenario.desc)\n\t\tassert.Equal(t, scenario.expectError, err != nil, scenario.desc)\n\t\tassert.NoError(t, dbMock.ExpectationsWereMet())\n\n\t\t// restore original DB (after test)\n\t\tdb = &original\n\t\ttestDb.Close()\n\t}\n}\n\n// convert SQL string to regex by treating the entire query as a literal\nfunc convertSQLToRegex(in string) string {\n\treturn `\\Q` + in + `\\E`\n}\n"
  },
  {
    "path": "ch07/acme/internal/modules/exchange/converter.go",
    "content": "package exchange\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"math\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch07/acme/internal/config\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch07/acme/internal/logging\"\n)\n\nconst (\n\t// request URL for the exchange rate API\n\turlFormat = \"%s/api/historical?access_key=%s&date=2018-06-20&currencies=%s\"\n\n\t// default price that is sent when an error occurs\n\tdefaultPrice = 0.0\n)\n\n// Converter will convert the base price to the currency supplied\n// Note: we are expecting sane inputs and therefore skipping input validation\ntype Converter struct{}\n\n// Do will perform the conversion\nfunc (c *Converter) Do(ctx context.Context, basePrice float64, currency string) (float64, error) {\n\t// load rate from the external API\n\tresponse, err := c.loadRateFromServer(ctx, currency)\n\tif err != nil {\n\t\treturn defaultPrice, err\n\t}\n\n\t// extract rate from response\n\trate, err := c.extractRate(response, currency)\n\tif err != nil {\n\t\treturn defaultPrice, err\n\t}\n\n\t// apply rate and round to 2 decimal places\n\treturn math.Floor((basePrice/rate)*100) / 100, nil\n}\n\n// load rate from the external API\nfunc (c *Converter) loadRateFromServer(ctx context.Context, currency string) (*http.Response, error) {\n\t// build the request\n\turl := fmt.Sprintf(urlFormat,\n\t\tconfig.App.ExchangeRateBaseURL,\n\t\tconfig.App.ExchangeRateAPIKey,\n\t\tcurrency)\n\n\t// perform request\n\treq, err := http.NewRequest(\"GET\", url, nil)\n\tif err != nil {\n\t\tlogging.L.Warn(\"[exchange] failed to create request. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// set latency budget for the upstream call\n\tsubCtx, cancel := context.WithTimeout(ctx, 1*time.Second)\n\tdefer cancel()\n\n\t// replace the default context with our custom one\n\treq = req.WithContext(subCtx)\n\n\t// perform the HTTP request\n\tresponse, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tlogging.L.Warn(\"[exchange] failed to load. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\tif response.StatusCode != http.StatusOK {\n\t\terr = fmt.Errorf(\"request failed with code %d\", response.StatusCode)\n\t\tlogging.L.Warn(\"[exchange] %s\", err)\n\t\treturn nil, err\n\t}\n\n\treturn response, nil\n}\n\nfunc (c *Converter) extractRate(response *http.Response, currency string) (float64, error) {\n\tdefer func() {\n\t\t_ = response.Body.Close()\n\t}()\n\n\t// extract data from response\n\tdata, err := c.extractResponse(response)\n\tif err != nil {\n\t\treturn defaultPrice, err\n\t}\n\n\t// pull rate from response data\n\trate, found := data.Quotes[\"USD\"+currency]\n\tif !found {\n\t\terr = fmt.Errorf(\"response did not include expected currency '%s'\", currency)\n\t\tlogging.L.Error(\"[exchange] %s\", err)\n\t\treturn defaultPrice, err\n\t}\n\n\t// happy path\n\treturn rate, nil\n}\n\nfunc (c *Converter) extractResponse(response *http.Response) (*apiResponseFormat, error) {\n\tpayload, err := ioutil.ReadAll(response.Body)\n\tif err != nil {\n\t\tlogging.L.Error(\"[exchange] failed to ready response body. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\tdata := &apiResponseFormat{}\n\terr = json.Unmarshal(payload, data)\n\tif err != nil {\n\t\tlogging.L.Error(\"[exchange] error converting response. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// happy path\n\treturn data, nil\n}\n\n// the response format from the exchange rate API\ntype apiResponseFormat struct {\n\tQuotes map[string]float64 `json:\"quotes\"`\n}\n"
  },
  {
    "path": "ch07/acme/internal/modules/get/get.go",
    "content": "package get\n\nimport (\n\t\"context\"\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch07/acme/internal/modules/data\"\n)\n\nvar (\n\t// error thrown when the requested person is not in the database\n\terrPersonNotFound = errors.New(\"person not found\")\n)\n\n// Getter will attempt to load a person.\n// It can return an error caused by the data layer or when the requested person is not found\ntype Getter struct {\n}\n\n// Do will perform the get\nfunc (g *Getter) Do(ID int) (*data.Person, error) {\n\t// load person from the data layer\n\tperson, err := loader(context.TODO(), ID)\n\tif err != nil {\n\t\tif err == data.ErrNotFound {\n\t\t\t// By converting the error we are hiding the implementation details from our users.\n\t\t\treturn nil, errPersonNotFound\n\t\t}\n\t\treturn nil, err\n\t}\n\n\treturn person, err\n}\n\n// this function as a variable allows us to Monkey Patch during testing\nvar loader = data.Load\n"
  },
  {
    "path": "ch07/acme/internal/modules/get/go_test.go",
    "content": "package get\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch07/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestGetter_Do_happyPath(t *testing.T) {\n\t// inputs\n\tID := 1234\n\n\t// monkey patch calls to the data package\n\tdefer func(original func(_ context.Context, ID int) (*data.Person, error)) {\n\t\t// restore original\n\t\tloader = original\n\t}(loader)\n\n\t// replace method\n\tloader = func(_ context.Context, ID int) (*data.Person, error) {\n\t\tresult := &data.Person{\n\t\t\tID:       1234,\n\t\t\tFullName: \"Doug\",\n\t\t}\n\t\tvar resultErr error\n\n\t\treturn result, resultErr\n\t}\n\t// end of monkey patch\n\n\t// call method\n\tgetter := &Getter{}\n\tperson, err := getter.Do(ID)\n\n\t// validate expectations\n\trequire.NoError(t, err)\n\tassert.Equal(t, ID, person.ID)\n\tassert.Equal(t, \"Doug\", person.FullName)\n}\n\nfunc TestGetter_Do_noSuchPerson(t *testing.T) {\n\t// inputs\n\tID := 5678\n\n\t// monkey patch calls to the data package\n\tdefer func(original func(_ context.Context, ID int) (*data.Person, error)) {\n\t\t// restore original\n\t\tloader = original\n\t}(loader)\n\n\t// replace method\n\tloader = func(_ context.Context, ID int) (*data.Person, error) {\n\t\tvar result *data.Person\n\t\tresultErr := data.ErrNotFound\n\n\t\treturn result, resultErr\n\t}\n\t// end of monkey patch\n\n\t// call method\n\tgetter := &Getter{}\n\tperson, err := getter.Do(ID)\n\n\t// validate expectations\n\trequire.Equal(t, errPersonNotFound, err)\n\tassert.Nil(t, person)\n}\n\nfunc TestGetter_Do_error(t *testing.T) {\n\t// inputs\n\tID := 1234\n\n\t// monkey patch calls to the data package\n\tdefer func(original func(_ context.Context, ID int) (*data.Person, error)) {\n\t\t// restore original\n\t\tloader = original\n\t}(loader)\n\n\t// replace method\n\tloader = func(_ context.Context, ID int) (*data.Person, error) {\n\t\tvar result *data.Person\n\t\tresultErr := errors.New(\"failed to load person\")\n\n\t\treturn result, resultErr\n\t}\n\t// end of monkey patch\n\n\t// call method\n\tgetter := &Getter{}\n\tperson, err := getter.Do(ID)\n\n\t// validate expectations\n\trequire.Error(t, err)\n\tassert.Nil(t, person)\n}\n"
  },
  {
    "path": "ch07/acme/internal/modules/list/list.go",
    "content": "package list\n\nimport (\n\t\"context\"\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch07/acme/internal/modules/data\"\n)\n\nvar (\n\t// error thrown when there are no people in the database\n\terrPeopleNotFound = errors.New(\"no people found\")\n)\n\n// Lister will attempt to load all people in the database.\n// It can return an error caused by the data layer\ntype Lister struct {\n}\n\n// Do will load the people from the data layer\nfunc (l *Lister) Do() ([]*data.Person, error) {\n\t// load all people\n\tpeople, err := l.load()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(people) == 0 {\n\t\t// special processing for 0 people returned\n\t\treturn nil, errPeopleNotFound\n\t}\n\n\treturn people, nil\n}\n\n// load all people\nfunc (l *Lister) load() ([]*data.Person, error) {\n\tpeople, err := loader(context.TODO())\n\tif err != nil {\n\t\tif err == data.ErrNotFound {\n\t\t\t// By converting the error we are encapsulating the implementation details from our users.\n\t\t\treturn nil, errPeopleNotFound\n\t\t}\n\t\treturn nil, err\n\t}\n\n\treturn people, nil\n}\n\n// this function as a variable allows us to Monkey Patch during testing\nvar loader = data.LoadAll\n"
  },
  {
    "path": "ch07/acme/internal/modules/list/list_test.go",
    "content": "package list\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch07/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestLister_Do_happyPath(t *testing.T) {\n\t// monkey patch calls to the data package\n\tdefer func(original func(_ context.Context) ([]*data.Person, error)) {\n\t\t// restore original\n\t\tloader = original\n\t}(loader)\n\n\t// replace method\n\tloader = func(_ context.Context) ([]*data.Person, error) {\n\t\tresult := []*data.Person{\n\t\t\t{\n\t\t\t\tID:       1234,\n\t\t\t\tFullName: \"Sally\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tID:       5678,\n\t\t\t\tFullName: \"Jane\",\n\t\t\t},\n\t\t}\n\t\tvar resultErr error\n\n\t\treturn result, resultErr\n\t}\n\t// end of monkey patch\n\n\t// call method\n\tlister := &Lister{}\n\tpersons, err := lister.load()\n\n\t// validate expectations\n\trequire.NoError(t, err)\n\tassert.Equal(t, 2, len(persons))\n}\n\nfunc TestLister_Do_noResults(t *testing.T) {\n\t// monkey patch calls to the data package\n\tdefer func(original func(_ context.Context) ([]*data.Person, error)) {\n\t\t// restore original\n\t\tloader = original\n\t}(loader)\n\n\t// replace method\n\tloader = func(_ context.Context) ([]*data.Person, error) {\n\t\tvar result []*data.Person\n\t\tresultErr := data.ErrNotFound\n\n\t\treturn result, resultErr\n\t}\n\t// end of monkey patch\n\n\t// call method\n\tlister := &Lister{}\n\tpersons, err := lister.load()\n\n\t// validate expectations\n\trequire.Equal(t, errPeopleNotFound, err)\n\tassert.Equal(t, 0, len(persons))\n}\n\nfunc TestLister_Do_error(t *testing.T) {\n\t// monkey patch calls to the data package\n\tdefer func(original func(_ context.Context) ([]*data.Person, error)) {\n\t\t// restore original\n\t\tloader = original\n\t}(loader)\n\n\t// replace method\n\tloader = func(_ context.Context) ([]*data.Person, error) {\n\t\tvar result []*data.Person\n\t\tresultErr := errors.New(\"failed to load people\")\n\n\t\treturn result, resultErr\n\t}\n\t// end of monkey patch\n\n\t// call method\n\tlister := &Lister{}\n\tpersons, err := lister.load()\n\n\t// validate expectations\n\trequire.Error(t, err)\n\tassert.Equal(t, 0, len(persons))\n}\n"
  },
  {
    "path": "ch07/acme/internal/modules/register/register.go",
    "content": "package register\n\nimport (\n\t\"context\"\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch07/acme/internal/config\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch07/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch07/acme/internal/modules/data\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch07/acme/internal/modules/exchange\"\n)\n\nconst (\n\t// default person id (returned on error)\n\tdefaultPersonID = 0\n)\n\nvar (\n\t// validation errors\n\terrNameMissing     = errors.New(\"name is missing\")\n\terrPhoneMissing    = errors.New(\"phone is missing\")\n\terrCurrencyMissing = errors.New(\"currency is missing\")\n\terrInvalidCurrency = errors.New(\"currency is invalid, supported types are AUD, CNY, EUR, GBP, JPY, MYR, SGD, USD\")\n\n\t// a little trick to make checking for supported currencies easier\n\tsupportedCurrencies = map[string]struct{}{\n\t\t\"AUD\": {},\n\t\t\"CNY\": {},\n\t\t\"EUR\": {},\n\t\t\"GBP\": {},\n\t\t\"JPY\": {},\n\t\t\"MYR\": {},\n\t\t\"SGD\": {},\n\t\t\"USD\": {},\n\t}\n)\n\n// Registerer validates the supplied person, calculates the price in the requested currency and saves the result.\n// It will return an error when:\n// -the person object does not include all the fields\n// -the currency is invalid\n// -the exchange rate cannot be loaded\n// -the data layer throws an error.\ntype Registerer struct {\n}\n\n// Do is API for this struct\nfunc (r *Registerer) Do(ctx context.Context, in *data.Person) (int, error) {\n\t// validate the request\n\terr := r.validateInput(in)\n\tif err != nil {\n\t\tlogging.L.Warn(\"input validation failed with err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\t// get price in the requested currency\n\tprice, err := r.getPrice(ctx, in.Currency)\n\tif err != nil {\n\t\treturn defaultPersonID, err\n\t}\n\n\t// save registration\n\tid, err := r.save(ctx, in, price)\n\tif err != nil {\n\t\t// no need to log here as we expect the data layer to do so\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn id, nil\n}\n\n// validate input and return error on fail\nfunc (r *Registerer) validateInput(in *data.Person) error {\n\tif in.FullName == \"\" {\n\t\treturn errNameMissing\n\t}\n\tif in.Phone == \"\" {\n\t\treturn errPhoneMissing\n\t}\n\tif in.Currency == \"\" {\n\t\treturn errCurrencyMissing\n\t}\n\n\tif _, found := supportedCurrencies[in.Currency]; !found {\n\t\treturn errInvalidCurrency\n\t}\n\n\t// happy path\n\treturn nil\n}\n\n// get price in the requested currency\nfunc (r *Registerer) getPrice(ctx context.Context, currency string) (float64, error) {\n\tconverter := &exchange.Converter{}\n\tprice, err := converter.Do(ctx, config.App.BasePrice, currency)\n\tif err != nil {\n\t\tlogging.L.Warn(\"failed to convert the price. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn price, nil\n}\n\n// save the registration\nfunc (r *Registerer) save(ctx context.Context, in *data.Person, price float64) (int, error) {\n\tperson := &data.Person{\n\t\tFullName: in.FullName,\n\t\tPhone:    in.Phone,\n\t\tCurrency: in.Currency,\n\t\tPrice:    price,\n\t}\n\treturn saver(ctx, person)\n}\n\n// this function as a variable allows us to Monkey Patch during testing\nvar saver = data.Save\n"
  },
  {
    "path": "ch07/acme/internal/modules/register/register_test.go",
    "content": "package register\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch07/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestRegisterer_Do_happyPath(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\t// monkey patch calls to the data package\n\tdefer func(original func(ctx context.Context, in *data.Person) (int, error)) {\n\t\t// restore original\n\t\tsaver = original\n\t}(saver)\n\n\t// replace method\n\tsaver = func(ctx context.Context, in *data.Person) (int, error) {\n\t\tresult := 888\n\t\tvar resultErr error\n\n\t\treturn result, resultErr\n\t}\n\t// end of monkey patch\n\n\t// inputs\n\tin := &data.Person{\n\t\tFullName: \"Chang\",\n\t\tPhone:    \"11122233355\",\n\t\tCurrency: \"CNY\",\n\t}\n\n\t// call method\n\tregisterer := &Registerer{}\n\tID, err := registerer.Do(ctx, in)\n\n\t// validate expectations\n\trequire.NoError(t, err)\n\tassert.Equal(t, 888, ID)\n}\n\nfunc TestRegisterer_Do_error(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\t// monkey patch calls to the data package\n\tdefer func(original func(ctx context.Context, in *data.Person) (int, error)) {\n\t\t// restore original\n\t\tsaver = original\n\t}(saver)\n\n\t// replace method\n\tsaver = func(ctx context.Context, in *data.Person) (int, error) {\n\t\tvar result int\n\t\tresultErr := errors.New(\"failed to save\")\n\n\t\treturn result, resultErr\n\t}\n\t// end of monkey patch\n\n\t// inputs\n\tin := &data.Person{\n\t\tFullName: \"Chang\",\n\t\tPhone:    \"11122233355\",\n\t\tCurrency: \"CNY\",\n\t}\n\n\t// call method\n\tregisterer := &Registerer{}\n\tID, err := registerer.Do(ctx, in)\n\n\t// validate expectations\n\trequire.Error(t, err)\n\tassert.Equal(t, 0, ID)\n}\n"
  },
  {
    "path": "ch07/acme/internal/rest/get.go",
    "content": "package rest\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch07/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch07/acme/internal/modules/data\"\n\t\"github.com/gorilla/mux\"\n)\n\nconst (\n\t// default person id (returned on error)\n\tdefaultPersonID = 0\n\n\t// key in the mux where the ID is stored\n\tmuxVarID = \"id\"\n)\n\n// GetModel will load a registration\n//go:generate mockery -name=GetModel -case underscore -testonly -inpkg -note @generated\ntype GetModel interface {\n\tDo(ID int) (*data.Person, error)\n}\n\n// NewGetHandler is the constructor for GetHandler\nfunc NewGetHandler(model GetModel) *GetHandler {\n\treturn &GetHandler{\n\t\tgetter: model,\n\t}\n}\n\n// GetHandler is the HTTP handler for the \"Get Person\" endpoint\n// In this simplified example we are assuming all possible errors are user errors and returning \"bad request\" HTTP 400\n// or \"not found\" HTTP 404\n// There are some programmer errors possible but hopefully these will be caught in testing.\ntype GetHandler struct {\n\tgetter GetModel\n}\n\n// ServeHTTP implements http.Handler\nfunc (h *GetHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\t// extract person id from request\n\tid, err := h.extractID(request)\n\tif err != nil {\n\t\t// output error\n\t\tresponse.WriteHeader(http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// attempt get\n\tperson, err := h.getter.Do(id)\n\tif err != nil {\n\t\t// not need to log here as we can expect other layers to do so\n\t\tresponse.WriteHeader(http.StatusNotFound)\n\t\treturn\n\t}\n\n\t// happy path\n\terr = h.writeJSON(response, person)\n\tif err != nil {\n\t\t// this error should not happen but if it does there is nothing we can do to recover\n\t\tresponse.WriteHeader(http.StatusInternalServerError)\n\t}\n}\n\n// extract the person ID from the request\nfunc (h *GetHandler) extractID(request *http.Request) (int, error) {\n\t// ID is part of the URL, so we extract it from there\n\tvars := mux.Vars(request)\n\tidAsString, exists := vars[muxVarID]\n\tif !exists {\n\t\t// log and return error\n\t\terr := errors.New(\"[get] person id missing from request\")\n\t\tlogging.L.Warn(err.Error())\n\t\treturn defaultPersonID, err\n\t}\n\n\t// convert ID to int\n\tid, err := strconv.Atoi(idAsString)\n\tif err != nil {\n\t\t// log and return error\n\t\terr = fmt.Errorf(\"[get] failed to convert person id into a number. err: %s\", err)\n\t\tlogging.L.Error(err.Error())\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn id, nil\n}\n\n// output the supplied person as JSON\nfunc (h *GetHandler) writeJSON(writer io.Writer, person *data.Person) error {\n\toutput := &getResponseFormat{\n\t\tID:       person.ID,\n\t\tFullName: person.FullName,\n\t\tPhone:    person.Phone,\n\t\tCurrency: person.Currency,\n\t\tPrice:    person.Price,\n\t}\n\n\t// call to http.ResponseWriter.Write() will cause HTTP OK (200) to be output as well\n\treturn json.NewEncoder(writer).Encode(output)\n}\n\n// the JSON response format\ntype getResponseFormat struct {\n\tID       int     `json:\"id\"`\n\tFullName string  `json:\"name\"`\n\tPhone    string  `json:\"phone\"`\n\tCurrency string  `json:\"currency\"`\n\tPrice    float64 `json:\"price\"`\n}\n"
  },
  {
    "path": "ch07/acme/internal/rest/get_test.go",
    "content": "package rest\n\nimport (\n\t\"errors\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch07/acme/internal/modules/data\"\n\t\"github.com/gorilla/mux\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestGetHandler_ServeHTTP(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc            string\n\t\tinRequest       func() *http.Request\n\t\tinModelMock     func() *MockGetModel\n\t\texpectedStatus  int\n\t\texpectedPayload string\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/1/\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// set values into request (required by the mux)\n\t\t\t\treturn mux.SetURLVars(req, map[string]string{muxVarID: \"1\"})\n\t\t\t},\n\t\t\tinModelMock: func() *MockGetModel {\n\t\t\t\toutput := &data.Person{\n\t\t\t\t\tID:       1,\n\t\t\t\t\tFullName: \"John\",\n\t\t\t\t\tPhone:    \"0123456789\",\n\t\t\t\t\tCurrency: \"USD\",\n\t\t\t\t\tPrice:    100,\n\t\t\t\t}\n\n\t\t\t\tmockGetModel := &MockGetModel{}\n\t\t\t\tmockGetModel.On(\"Do\", mock.Anything).Return(output, nil).Once()\n\n\t\t\t\treturn mockGetModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusOK,\n\t\t\texpectedPayload: `{\"id\":1,\"name\":\"John\",\"phone\":\"0123456789\",\"currency\":\"USD\",\"price\":100}` + \"\\n\",\n\t\t},\n\t\t{\n\t\t\tdesc: \"bad input (ID is invalid)\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/x/\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// set values into request (required by the mux)\n\t\t\t\treturn mux.SetURLVars(req, map[string]string{muxVarID: \"x\"})\n\t\t\t},\n\t\t\tinModelMock: func() *MockGetModel {\n\t\t\t\t// expect the model not to be called\n\t\t\t\tmockRegisterModel := &MockGetModel{}\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusBadRequest,\n\t\t\texpectedPayload: ``,\n\t\t},\n\t\t{\n\t\t\tdesc: \"bad input (ID is missing)\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person//\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// set values into request (required by the mux)\n\t\t\t\treturn mux.SetURLVars(req, map[string]string{})\n\t\t\t},\n\t\t\tinModelMock: func() *MockGetModel {\n\t\t\t\t// expect the model not to be called\n\t\t\t\tmockRegisterModel := &MockGetModel{}\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusBadRequest,\n\t\t\texpectedPayload: ``,\n\t\t},\n\t\t{\n\t\t\tdesc: \"dependency fail\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/1/\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// set values into request (required by the mux)\n\t\t\t\treturn mux.SetURLVars(req, map[string]string{muxVarID: \"1\"})\n\t\t\t},\n\t\t\tinModelMock: func() *MockGetModel {\n\t\t\t\tmockRegisterModel := &MockGetModel{}\n\t\t\t\tmockRegisterModel.On(\"Do\", mock.Anything).Return(nil, errors.New(\"something failed\")).Once()\n\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusNotFound,\n\t\t\texpectedPayload: ``,\n\t\t},\n\t\t{\n\t\t\tdesc: \"requested registration does not exist\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/1/\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// set values into request (required by the mux)\n\t\t\t\treturn mux.SetURLVars(req, map[string]string{muxVarID: \"1\"})\n\t\t\t},\n\t\t\tinModelMock: func() *MockGetModel {\n\t\t\t\tmockRegisterModel := &MockGetModel{}\n\t\t\t\tmockRegisterModel.On(\"Do\", mock.Anything).Return(nil, errors.New(\"person not found\")).Once()\n\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusNotFound,\n\t\t\texpectedPayload: ``,\n\t\t},\n\t}\n\n\tfor _, s := range scenarios {\n\t\tscenario := s\n\t\tt.Run(scenario.desc, func(t *testing.T) {\n\t\t\t// define model layer mock\n\t\t\tmockGetModel := scenario.inModelMock()\n\n\t\t\t// build handler\n\t\t\thandler := NewGetHandler(mockGetModel)\n\n\t\t\t// perform request\n\t\t\tresponse := httptest.NewRecorder()\n\t\t\thandler.ServeHTTP(response, scenario.inRequest())\n\n\t\t\t// validate outputs\n\t\t\trequire.Equal(t, scenario.expectedStatus, response.Code, scenario.desc)\n\n\t\t\tpayload, _ := ioutil.ReadAll(response.Body)\n\t\t\tassert.Equal(t, scenario.expectedPayload, string(payload), scenario.desc)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "ch07/acme/internal/rest/list.go",
    "content": "package rest\n\nimport (\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch07/acme/internal/modules/data\"\n)\n\n// ListModel will load all registrations\n//go:generate mockery -name=ListModel -case underscore -testonly -inpkg -note @generated\ntype ListModel interface {\n\tDo() ([]*data.Person, error)\n}\n\n// NewLister is the constructor for ListHandler\nfunc NewListHandler(model ListModel) *ListHandler {\n\treturn &ListHandler{\n\t\tlister: model,\n\t}\n}\n\n// ListHandler is the HTTP handler for the \"List Do people\" endpoint\n// In this simplified example we are assuming all possible errors are system errors (HTTP 500)\ntype ListHandler struct {\n\tlister ListModel\n}\n\n// ServeHTTP implements http.Handler\nfunc (h *ListHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\t// attempt loadAll\n\tpeople, err := h.lister.Do()\n\tif err != nil {\n\t\t// not need to log here as we can expect other layers to do so\n\t\tresponse.WriteHeader(http.StatusNotFound)\n\t\treturn\n\t}\n\n\t// happy path\n\terr = h.writeJSON(response, people)\n\tif err != nil {\n\t\t// this error should not happen but if it does there is nothing we can do to recover\n\t\tresponse.WriteHeader(http.StatusInternalServerError)\n\t}\n}\n\n// output the result as JSON\nfunc (h *ListHandler) writeJSON(writer io.Writer, people []*data.Person) error {\n\toutput := &listResponseFormat{\n\t\tPeople: make([]*listResponseItemFormat, len(people)),\n\t}\n\n\tfor index, record := range people {\n\t\toutput.People[index] = &listResponseItemFormat{\n\t\t\tID:       record.ID,\n\t\t\tFullName: record.FullName,\n\t\t\tPhone:    record.Phone,\n\t\t}\n\t}\n\n\t// call to http.ResponseWriter.Write() will cause HTTP OK (200) to be output as well\n\treturn json.NewEncoder(writer).Encode(output)\n}\n\ntype listResponseFormat struct {\n\tPeople []*listResponseItemFormat `json:\"people\"`\n}\n\ntype listResponseItemFormat struct {\n\tID       int    `json:\"id\"`\n\tFullName string `json:\"name\"`\n\tPhone    string `json:\"phone\"`\n}\n"
  },
  {
    "path": "ch07/acme/internal/rest/list_test.go",
    "content": "package rest\n\nimport (\n\t\"errors\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch07/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestListHandler_ServeHTTP(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc            string\n\t\tinRequest       func() *http.Request\n\t\tinModelMock     func() *MockListModel\n\t\texpectedStatus  int\n\t\texpectedPayload string\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/list\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn req\n\t\t\t},\n\t\t\tinModelMock: func() *MockListModel {\n\t\t\t\toutput := []*data.Person{\n\t\t\t\t\t{\n\t\t\t\t\t\tID:       1,\n\t\t\t\t\t\tFullName: \"John\",\n\t\t\t\t\t\tPhone:    \"0123456789\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tID:       2,\n\t\t\t\t\t\tFullName: \"Paul\",\n\t\t\t\t\t\tPhone:    \"0123456781\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tID:       3,\n\t\t\t\t\t\tFullName: \"George\",\n\t\t\t\t\t\tPhone:    \"0123456782\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tID:       1,\n\t\t\t\t\t\tFullName: \"Ringo\",\n\t\t\t\t\t\tPhone:    \"0123456783\",\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\tmockListModel := &MockListModel{}\n\t\t\t\tmockListModel.On(\"Do\", mock.Anything).Return(output, nil).Once()\n\n\t\t\t\treturn mockListModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusOK,\n\t\t\texpectedPayload: `{\"people\":[{\"id\":1,\"name\":\"John\",\"phone\":\"0123456789\"},{\"id\":2,\"name\":\"Paul\",\"phone\":\"0123456781\"},{\"id\":3,\"name\":\"George\",\"phone\":\"0123456782\"},{\"id\":1,\"name\":\"Ringo\",\"phone\":\"0123456783\"}]}` + \"\\n\",\n\t\t},\n\t\t{\n\t\t\tdesc: \"dependency failure\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/list\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn req\n\t\t\t},\n\t\t\tinModelMock: func() *MockListModel {\n\t\t\t\tmockListModel := &MockListModel{}\n\t\t\t\tmockListModel.On(\"Do\", mock.Anything).Return(nil, errors.New(\"something failed\")).Once()\n\n\t\t\t\treturn mockListModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusNotFound,\n\t\t\texpectedPayload: ``,\n\t\t},\n\t\t{\n\t\t\tdesc: \"no data\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/list\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn req\n\t\t\t},\n\t\t\tinModelMock: func() *MockListModel {\n\t\t\t\t// no data\n\t\t\t\toutput := []*data.Person{}\n\n\t\t\t\tmockListModel := &MockListModel{}\n\t\t\t\tmockListModel.On(\"Do\", mock.Anything).Return(output, nil).Once()\n\n\t\t\t\treturn mockListModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusOK,\n\t\t\texpectedPayload: `{\"people\":[]}` + \"\\n\",\n\t\t},\n\t}\n\n\tfor _, s := range scenarios {\n\t\tscenario := s\n\t\tt.Run(scenario.desc, func(t *testing.T) {\n\t\t\t// define model layer mock\n\t\t\tmockListModel := scenario.inModelMock()\n\n\t\t\t// build handler\n\t\t\thandler := NewListHandler(mockListModel)\n\n\t\t\t// perform request\n\t\t\tresponse := httptest.NewRecorder()\n\t\t\thandler.ServeHTTP(response, scenario.inRequest())\n\n\t\t\t// validate outputs\n\t\t\trequire.Equal(t, scenario.expectedStatus, response.Code, scenario.desc)\n\n\t\t\tpayload, _ := ioutil.ReadAll(response.Body)\n\t\t\tassert.Equal(t, scenario.expectedPayload, string(payload), scenario.desc)\n\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "ch07/acme/internal/rest/mock_get_model_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage rest\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch07/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// MockGetModel is an autogenerated mock type for the GetModel type\ntype MockGetModel struct {\n\tmock.Mock\n}\n\n// Do provides a mock function with given fields: ID\nfunc (_m *MockGetModel) Do(ID int) (*data.Person, error) {\n\tret := _m.Called(ID)\n\n\tvar r0 *data.Person\n\tif rf, ok := ret.Get(0).(func(int) *data.Person); ok {\n\t\tr0 = rf(ID)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*data.Person)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(int) error); ok {\n\t\tr1 = rf(ID)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch07/acme/internal/rest/mock_list_model_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage rest\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch07/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// MockListModel is an autogenerated mock type for the ListModel type\ntype MockListModel struct {\n\tmock.Mock\n}\n\n// Do provides a mock function with given fields:\nfunc (_m *MockListModel) Do() ([]*data.Person, error) {\n\tret := _m.Called()\n\n\tvar r0 []*data.Person\n\tif rf, ok := ret.Get(0).(func() []*data.Person); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]*data.Person)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func() error); ok {\n\t\tr1 = rf()\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch07/acme/internal/rest/mock_register_model_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage rest\n\nimport (\n\t\"context\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch07/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// MockRegisterModel is an autogenerated mock type for the RegisterModel type\ntype MockRegisterModel struct {\n\tmock.Mock\n}\n\n// Do provides a mock function with given fields: ctx, in\nfunc (_m *MockRegisterModel) Do(ctx context.Context, in *data.Person) (int, error) {\n\tret := _m.Called(ctx, in)\n\n\tvar r0 int\n\tif rf, ok := ret.Get(0).(func(context.Context, *data.Person) int); ok {\n\t\tr0 = rf(ctx, in)\n\t} else {\n\t\tr0 = ret.Get(0).(int)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, *data.Person) error); ok {\n\t\tr1 = rf(ctx, in)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch07/acme/internal/rest/not_found.go",
    "content": "package rest\n\nimport (\n\t\"net/http\"\n)\n\nfunc notFoundHandler(response http.ResponseWriter, _ *http.Request) {\n\tresponse.WriteHeader(http.StatusNotFound)\n\t_, _ = response.Write([]byte(`Not found`))\n}\n"
  },
  {
    "path": "ch07/acme/internal/rest/not_found_test.go",
    "content": "package rest\n\nimport (\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestNotFoundHandler_ServeHTTP(t *testing.T) {\n\t// build inputs\n\tresponse := httptest.NewRecorder()\n\trequest := &http.Request{}\n\n\t// call handler\n\tnotFoundHandler(response, request)\n\n\t// validate outputs\n\trequire.Equal(t, http.StatusNotFound, response.Code)\n}\n"
  },
  {
    "path": "ch07/acme/internal/rest/register.go",
    "content": "package rest\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch07/acme/internal/modules/data\"\n)\n\n// RegisterModel will validate and save a registration\n//go:generate mockery -name=RegisterModel -case underscore -testonly -inpkg -note @generated\ntype RegisterModel interface {\n\tDo(ctx context.Context, in *data.Person) (int, error)\n}\n\n// NewRegisterHandler is the constructor for RegisterHandler\nfunc NewRegisterHandler(model RegisterModel) *RegisterHandler {\n\treturn &RegisterHandler{\n\t\tregisterer: model,\n\t}\n}\n\n// RegisterHandler is the HTTP handler for the \"Register\" endpoint\n// In this simplified example we are assuming all possible errors are user errors and returning \"bad request\" HTTP 400.\n// There are some programmer errors possible but hopefully these will be caught in testing.\ntype RegisterHandler struct {\n\tregisterer RegisterModel\n}\n\n// ServeHTTP implements http.Handler\nfunc (h *RegisterHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\t// set latency budget for this API\n\tsubCtx, cancel := context.WithTimeout(request.Context(), 1500*time.Millisecond)\n\tdefer cancel()\n\n\t// extract payload from request\n\trequestPayload, err := h.extractPayload(request)\n\tif err != nil {\n\t\t// output error\n\t\tresponse.WriteHeader(http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// call the business logic using the request data and context\n\tid, err := h.register(subCtx, requestPayload)\n\tif err != nil {\n\t\t// not need to log here as we can expect other layers to do so\n\t\tresponse.WriteHeader(http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// happy path\n\tresponse.Header().Add(\"Location\", fmt.Sprintf(\"/person/%d/\", id))\n\tresponse.WriteHeader(http.StatusCreated)\n}\n\n// extract payload from request\nfunc (h *RegisterHandler) extractPayload(request *http.Request) (*registerRequest, error) {\n\trequestPayload := &registerRequest{}\n\n\tdecoder := json.NewDecoder(request.Body)\n\terr := decoder.Decode(requestPayload)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn requestPayload, nil\n}\n\n// call the logic layer\nfunc (h *RegisterHandler) register(ctx context.Context, requestPayload *registerRequest) (int, error) {\n\tperson := &data.Person{\n\t\tFullName: requestPayload.FullName,\n\t\tPhone:    requestPayload.Phone,\n\t\tCurrency: requestPayload.Currency,\n\t}\n\n\treturn h.registerer.Do(ctx, person)\n}\n\n// register endpoint request format\ntype registerRequest struct {\n\t// FullName of the person\n\tFullName string `json:\"fullName\"`\n\t// Phone of the person\n\tPhone string `json:\"phone\"`\n\t// Currency the wish to register in\n\tCurrency string `json:\"currency\"`\n}\n"
  },
  {
    "path": "ch07/acme/internal/rest/register_test.go",
    "content": "package rest\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestRegisterHandler_ServeHTTP(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc           string\n\t\tinRequest      func() *http.Request\n\t\tinModelMock    func() *MockRegisterModel\n\t\texpectedStatus int\n\t\texpectedHeader string\n\t}{\n\t\t{\n\t\t\tdesc: \"Happy Path\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\tvalidRequest := buildValidRegisterRequest()\n\t\t\t\trequest, err := http.NewRequest(\"POST\", \"/person/register\", validRequest)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn request\n\t\t\t},\n\t\t\tinModelMock: func() *MockRegisterModel {\n\t\t\t\t// valid downstream configuration\n\t\t\t\tresultID := 1234\n\t\t\t\tvar resultErr error\n\n\t\t\t\tmockRegisterModel := &MockRegisterModel{}\n\t\t\t\tmockRegisterModel.On(\"Do\", mock.Anything, mock.Anything).Return(resultID, resultErr).Once()\n\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus: http.StatusCreated,\n\t\t\texpectedHeader: \"/person/1234/\",\n\t\t},\n\t\t{\n\t\t\tdesc: \"Bad Input / User Error\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\tinvalidRequest := bytes.NewBufferString(`this is not valid JSON`)\n\t\t\t\trequest, err := http.NewRequest(\"POST\", \"/person/register\", invalidRequest)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn request\n\t\t\t},\n\t\t\tinModelMock: func() *MockRegisterModel {\n\t\t\t\t// Dependency should not be called\n\t\t\t\tmockRegisterModel := &MockRegisterModel{}\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus: http.StatusBadRequest,\n\t\t\texpectedHeader: \"\",\n\t\t},\n\t\t{\n\t\t\tdesc: \"Dependency Failure\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\tvalidRequest := buildValidRegisterRequest()\n\t\t\t\trequest, err := http.NewRequest(\"POST\", \"/person/register\", validRequest)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn request\n\t\t\t},\n\t\t\tinModelMock: func() *MockRegisterModel {\n\t\t\t\t// call to the dependency failed\n\t\t\t\tresultErr := errors.New(\"something failed\")\n\n\t\t\t\tmockRegisterModel := &MockRegisterModel{}\n\t\t\t\tmockRegisterModel.On(\"Do\", mock.Anything, mock.Anything).Return(0, resultErr).Once()\n\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus: http.StatusBadRequest,\n\t\t\texpectedHeader: \"\",\n\t\t},\n\t}\n\n\tfor _, s := range scenarios {\n\t\tscenario := s\n\t\tt.Run(scenario.desc, func(t *testing.T) {\n\t\t\t// define model layer mock\n\t\t\tmockRegisterModel := scenario.inModelMock()\n\n\t\t\t// build handler\n\t\t\thandler := NewRegisterHandler(mockRegisterModel)\n\n\t\t\t// perform request\n\t\t\tresponse := httptest.NewRecorder()\n\t\t\thandler.ServeHTTP(response, scenario.inRequest())\n\n\t\t\t// validate outputs\n\t\t\trequire.Equal(t, scenario.expectedStatus, response.Code)\n\n\t\t\t// call should output the location to the new person\n\t\t\tresultHeader := response.Header().Get(\"Location\")\n\t\t\tassert.Equal(t, scenario.expectedHeader, resultHeader)\n\n\t\t\t// validate the mock was used as we expected\n\t\t\tassert.True(t, mockRegisterModel.AssertExpectations(t))\n\t\t})\n\t}\n}\n\nfunc buildValidRegisterRequest() io.Reader {\n\trequestData := &registerRequest{\n\t\tFullName: \"Joan Smith\",\n\t\tCurrency: \"AUD\",\n\t\tPhone:    \"01234567890\",\n\t}\n\n\tdata, _ := json.Marshal(requestData)\n\treturn bytes.NewBuffer(data)\n}\n"
  },
  {
    "path": "ch07/acme/internal/rest/server.go",
    "content": "package rest\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/gorilla/mux\"\n)\n\n// New will create and initialize the server\nfunc New(address string,\n\tgetModel GetModel,\n\tlistModel ListModel,\n\tregisterModel RegisterModel) *Server {\n\n\treturn &Server{\n\t\taddress:         address,\n\t\thandlerGet:      NewGetHandler(getModel),\n\t\thandlerList:     NewListHandler(listModel),\n\t\thandlerNotFound: notFoundHandler,\n\t\thandlerRegister: NewRegisterHandler(registerModel),\n\t}\n}\n\n// Server is the HTTP REST server\ntype Server struct {\n\taddress string\n\tserver  *http.Server\n\n\thandlerGet      http.Handler\n\thandlerList     http.Handler\n\thandlerNotFound http.HandlerFunc\n\thandlerRegister http.Handler\n}\n\n// Listen will start a HTTP rest for this service\nfunc (s *Server) Listen(stop <-chan struct{}) {\n\trouter := s.buildRouter()\n\n\t// create the HTTP server\n\ts.server = &http.Server{\n\t\tHandler: router,\n\t\tAddr:    s.address,\n\t}\n\n\t// listen for shutdown\n\tgo func() {\n\t\t// wait for shutdown signal\n\t\t<-stop\n\n\t\t_ = s.server.Close()\n\t}()\n\n\t// start the HTTP server\n\t_ = s.server.ListenAndServe()\n}\n\n// configure the endpoints to handlers\nfunc (s *Server) buildRouter() http.Handler {\n\trouter := mux.NewRouter()\n\n\t// map URL endpoints to HTTP handlers\n\trouter.Handle(\"/person/{id}/\", s.handlerGet).Methods(\"GET\")\n\trouter.Handle(\"/person/list\", s.handlerList).Methods(\"GET\")\n\trouter.Handle(\"/person/register\", s.handlerRegister).Methods(\"POST\")\n\n\t// convert a \"catch all\" not found handler\n\trouter.NotFoundHandler = s.handlerNotFound\n\n\treturn router\n}\n"
  },
  {
    "path": "ch07/acme/main.go",
    "content": "package main\n\nimport (\n\t\"context\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch07/acme/internal/config\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch07/acme/internal/modules/get\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch07/acme/internal/modules/list\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch07/acme/internal/modules/register\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch07/acme/internal/rest\"\n)\n\nfunc main() {\n\t// bind stop channel to context\n\tctx := context.Background()\n\n\t// build model layer\n\tgetModel := &get.Getter{}\n\tlistModel := &list.Lister{}\n\tregisterModel := &register.Registerer{}\n\n\t// start REST server\n\tserver := rest.New(config.App.Address, getModel, listModel, registerModel)\n\tserver.Listen(ctx.Done())\n}\n"
  },
  {
    "path": "ch07/fake.go",
    "content": "package ch07\n\nfunc init() {\n\t// This file is included so that Go tools (like `go list`) will find Go code in this directory and not error\n}\n"
  },
  {
    "path": "ch08/01_config_injection/01_long_constructor.go",
    "content": "package config_injection\n\nimport (\n\t\"time\"\n)\n\n// NewLongConstructor is the constructor for MyStruct\nfunc NewLongConstructor(logger Logger, stats Instrumentation, limiter RateLimiter, cache Cache, timeout time.Duration, workers int) *MyStruct {\n\treturn &MyStruct{\n\t\t// code removed\n\t}\n}\n\n// MyStruct does something fantastic\ntype MyStruct struct {\n}\n\n// Logger logs stuff\ntype Logger interface {\n\tError(message string, args ...interface{})\n\tWarn(message string, args ...interface{})\n\tInfo(message string, args ...interface{})\n\tDebug(message string, args ...interface{})\n}\n\n// Instrumentation records the performances and events\ntype Instrumentation interface {\n\tCount(key string, value int)\n\tDuration(key string, start time.Time)\n}\n\n// RateLimiter limits how many concurrent requests we can make or process\ntype RateLimiter interface {\n\tAcquire()\n\tRelease()\n}\n\n// Cache will store/retrieve data in a fast way\ntype Cache interface {\n\tStore(key string, data []byte)\n\tGet(key string) ([]byte, error)\n}\n"
  },
  {
    "path": "ch08/01_config_injection/02_by_config_example.go",
    "content": "package config_injection\n\nimport (\n\t\"time\"\n)\n\n// NewByConfigConstructor is the constructor for MyStruct\nfunc NewByConfigConstructor(cfg MyConfig, limiter RateLimiter, cache Cache) *MyStruct {\n\treturn &MyStruct{\n\t\t// code removed\n\t}\n}\n\n// MyConfig defines the config for MyStruct\ntype MyConfig interface {\n\tLogger() Logger\n\tInstrumentation() Instrumentation\n\tTimeout() time.Duration\n\tWorkers() int\n}\n"
  },
  {
    "path": "ch08/01_config_injection/03_shared_params.go",
    "content": "package config_injection\n\nimport (\n\t\"fmt\"\n\t\"time\"\n)\n\nfunc Usage() {\n\tcfg := &fakeConfig{}\n\n\tmyFetcher := NewFetcher(cfg, cfg.URL(), cfg.Timeout())\n\n\t// do something with the object so the compiler does not complain\n\tfmt.Printf(\"%#v\", myFetcher)\n}\n\ntype FetcherConfig interface {\n\tLogger() Logger\n\tInstrumentation() Instrumentation\n}\n\nfunc NewFetcher(cfg FetcherConfig, url string, timeout time.Duration) *MyObject {\n\treturn nil\n}\n\ntype MyObject struct{}\n\n// fake implementation of the FetcherConfig interface\ntype fakeConfig struct{}\n\n// Logger implements FetcherConfig\nfunc (f *fakeConfig) Logger() Logger {\n\treturn nil\n}\n\n// Instrumentation implements FetcherConfig\nfunc (f *fakeConfig) Instrumentation() Instrumentation {\n\treturn nil\n}\n\nfunc (f *fakeConfig) URL() string {\n\treturn \"\"\n}\n\nfunc (f *fakeConfig) Timeout() time.Duration {\n\treturn time.Duration(0)\n}\n"
  },
  {
    "path": "ch08/02_advantages/01_injected_config/01.go",
    "content": "package injected_config\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/02_advantages/config\"\n)\n\nfunc NewMyObject(cfg *config.Config) *MyObject {\n\treturn &MyObject{\n\t\tcfg: cfg,\n\t}\n}\n\ntype MyObject struct {\n\tcfg *config.Config\n}\n\nfunc (m *MyObject) Do() (interface{}, error) {\n\tm.cfg.Logger().Error(\"not implemented\")\n\treturn struct{}{}, nil\n}\n"
  },
  {
    "path": "ch08/02_advantages/01_injected_config/01_test.go",
    "content": "package injected_config\n\nimport (\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/02_advantages/config\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nconst (\n\ttestConfigLocation = \"\"\n)\n\nfunc TestInjectedConfig(t *testing.T) {\n\t// load test config\n\tcfg, err := config.LoadFromFile(testConfigLocation)\n\trequire.NoError(t, err)\n\n\t// build and use object\n\tobj := NewMyObject(cfg)\n\tresult, resultErr := obj.Do()\n\n\t// validate\n\tassert.NotNil(t, result)\n\tassert.NoError(t, resultErr)\n}\n"
  },
  {
    "path": "ch08/02_advantages/02_config_injection/02.go",
    "content": "package config_injection\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/02_advantages/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/02_advantages/stats\"\n)\n\nfunc NewMyObject(cfg Config) *MyObject {\n\treturn &MyObject{\n\t\tcfg: cfg,\n\t}\n}\n\ntype Config interface {\n\tLogger() *logging.Logger\n\tStats() *stats.Collector\n}\n\ntype MyObject struct {\n\tcfg Config\n}\n\nfunc (m *MyObject) Do() (interface{}, error) {\n\tm.cfg.Logger().Error(\"not implemented\")\n\treturn struct{}{}, nil\n}\n"
  },
  {
    "path": "ch08/02_advantages/02_config_injection/02_test.go",
    "content": "package config_injection\n\nimport (\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/02_advantages/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/02_advantages/stats\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestConfigInjection(t *testing.T) {\n\t// build test config\n\tcfg := &TestConfig{}\n\n\t// build and use object\n\tobj := NewMyObject(cfg)\n\tresult, resultErr := obj.Do()\n\n\t// validate\n\tassert.NotNil(t, result)\n\tassert.NoError(t, resultErr)\n}\n\n// Simple implementation of the Config interface\ntype TestConfig struct {\n\tlogger *logging.Logger\n\tstats  *stats.Collector\n}\n\nfunc (t *TestConfig) Logger() *logging.Logger {\n\treturn t.logger\n}\n\nfunc (t *TestConfig) Stats() *stats.Collector {\n\treturn t.stats\n}\n"
  },
  {
    "path": "ch08/02_advantages/03_long_constructor.go",
    "content": "package config_injection\n\nimport (\n\t\"time\"\n)\n\n// NewLongConstructor is the constructor for MyStruct\nfunc NewLongConstructor(logger Logger, stats Instrumentation, limiter RateLimiter, cache Cache, url string, credentials string) *MyStruct {\n\treturn &MyStruct{\n\t\t// code removed\n\t}\n}\n\n// MyStruct does something fantastic\ntype MyStruct struct {\n}\n\n// Logger logs stuff\ntype Logger interface {\n\tError(message string, args ...interface{})\n\tWarn(message string, args ...interface{})\n\tInfo(message string, args ...interface{})\n\tDebug(message string, args ...interface{})\n}\n\n// Instrumentation records the performances and events\ntype Instrumentation interface {\n\tCount(key string, value int)\n\tDuration(key string, start time.Time)\n}\n\n// RateLimiter limits how many concurrent requests we can make or process\ntype RateLimiter interface {\n\tAcquire()\n\tRelease()\n}\n\n// Cache will store/retrieve data in a fast way\ntype Cache interface {\n\tStore(key string, data []byte)\n\tGet(key string) ([]byte, error)\n}\n"
  },
  {
    "path": "ch08/02_advantages/04_by_config_example.go",
    "content": "package config_injection\n\n// NewByConfigConstructor is the constructor for MyStruct\nfunc NewByConfigConstructor(cfg MyConfig, url string, credentials string) *MyStruct {\n\treturn &MyStruct{\n\t\t// code removed\n\t}\n}\n\n// MyConfig defines the config for MyStruct\ntype MyConfig interface {\n\tLogger() Logger\n\tInstrumentation() Instrumentation\n\tRateLimiter() RateLimiter\n\tCache() Cache\n}\n"
  },
  {
    "path": "ch08/02_advantages/config/config.go",
    "content": "package config\n\nimport (\n\t\"sync\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/02_advantages/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/02_advantages/stats\"\n)\n\n// LoadFromFile loads the config from the supplied path\nfunc LoadFromFile(path string) (*Config, error) {\n\t// TODO: implement\n\treturn &Config{}, nil\n}\n\n// Config is the result of loading config from a file\ntype Config struct {\n\t// Log config\n\tLogLevel       int `json:\"log_level\"`\n\tlogger         *logging.Logger\n\tloggerInitOnce sync.Once\n\n\t// Instrumentation config\n\tStatsDHostAndPort string `json:\"stats_d_host_and_port\"`\n\tstats             *stats.Collector\n\tstatsInitOnce     sync.Once\n\n\t// Rate Limiter config\n\tRateLimiterMaxConcurrent int `json:\"rate_limiter_max_concurrent\"`\n}\n\nfunc (c *Config) Logger() *logging.Logger {\n\tc.loggerInitOnce.Do(func() {\n\t\t// use log level to create new logger\n\t\tc.logger = &logging.Logger{\n\t\t\tLevel: c.LogLevel,\n\t\t}\n\t})\n\n\treturn c.logger\n}\n\nfunc (c *Config) Stats() *stats.Collector {\n\tc.statsInitOnce.Do(func() {\n\t\tc.stats = &stats.Collector{\n\t\t\tHostAndPort: c.StatsDHostAndPort,\n\t\t}\n\t})\n\n\treturn c.stats\n}\n"
  },
  {
    "path": "ch08/02_advantages/logging/logger.go",
    "content": "package logging\n\n// Logger logs stuff\ntype Logger struct {\n\tLevel int\n}\n\n// Error outputs a log at level ERROR\nfunc (l *Logger) Error(message string, args ...interface{}) {\n\t// TODO: implement\n}\n\n// Warn outputs a log at level ERROR\nfunc (l *Logger) Warn(message string, args ...interface{}) {\n\t// TODO: implement\n}\n\n// Info outputs a log at level ERROR\nfunc (l *Logger) Info(message string, args ...interface{}) {\n\t// TODO: implement\n}\n\n// Debug outputs a log at level ERROR\nfunc (l *Logger) Debug(message string, args ...interface{}) {\n\t// TODO: implement\n}\n"
  },
  {
    "path": "ch08/02_advantages/stats/stats.go",
    "content": "package stats\n\nimport (\n\t\"time\"\n)\n\n// Collector collects and forwards stats\ntype Collector struct {\n\tHostAndPort string\n}\n\n// Count will record an event\nfunc (c *Collector) Count(key string, value int) {\n\t// TODO: implement\n}\n\n// Count will record the duration of an event\nfunc (c *Collector) Duration(key string, start time.Time) {\n\t// TODO: implement\n}\n"
  },
  {
    "path": "ch08/03_applying/01_define_register_config.go",
    "content": "// +build do-not-build\n\npackage applying\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/logging\"\n)\n\n// Config is the configuration for the Registerer\ntype Config interface {\n\tLogger() *logging.LoggerStdOut\n\tBasePrice() float64\n}\n"
  },
  {
    "path": "ch08/03_applying/02_register_with_config_injection.go",
    "content": "// +build do-not-build\n\npackage applying\n\nimport (\n\t\"context\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/modules/exchange\"\n)\n\n// NewRegisterer creates and initializes a Registerer\nfunc NewRegisterer(cfg Config) *Registerer {\n\treturn &Registerer{\n\t\tcfg: cfg,\n\t}\n}\n\n// Config is the configuration for the Registerer\ntype Config interface {\n\tLogger() logging.Logger\n\tRegistrationBasePrice() float64\n}\n\n// Registerer validates the supplied person, calculates the price in the requested currency and saves the result.\n// It will return an error when:\n// -the person object does not include all the fields\n// -the currency is invalid\n// -the exchange rate cannot be loaded\n// -the data layer throws an error.\ntype Registerer struct {\n\tcfg Config\n}\n\n// get price in the requested currency\nfunc (r *Registerer) getPrice(ctx context.Context, currency string) (float64, error) {\n\tconverter := &exchange.Converter{}\n\tprice, err := converter.Do(ctx, r.cfg.RegistrationBasePrice(), currency)\n\tif err != nil {\n\t\tr.logger().Warn(\"failed to convert the price. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn price, nil\n}\n\nfunc (r *Registerer) logger() logging.Logger {\n\treturn r.cfg.Logger()\n}\n"
  },
  {
    "path": "ch08/03_applying/03_model_before_data_changes.go",
    "content": "// +build do-not-build\n\npackage applying\n\nimport (\n\t\"context\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/modules/data\"\n)\n\n// GetterConfig is the configuration for Getter\ntype GetterConfig interface {\n\tLogger() logging.Logger\n}\n\n// Getter will attempt to load a person.\n// It can return an error caused by the data layer or when the requested person is not found\ntype Getter struct {\n\tcfg GetterConfig\n}\n\n// Do will perform the get\nfunc (g *Getter) Do(ID int) (*data.Person, error) {\n\t// load person from the data layer\n\tperson, err := loader(context.TODO(), ID)\n\tif err != nil {\n\t\tif err == data.ErrNotFound {\n\t\t\t// By converting the error we are hiding the implementation details from our users.\n\t\t\treturn nil, errPersonNotFound\n\t\t}\n\t\treturn nil, err\n\t}\n\n\treturn person, err\n}\n\n// this function as a variable allows us to Monkey Patch during testing\nvar loader = data.Load\n"
  },
  {
    "path": "ch08/03_applying/04_test_config_link_to_config_package.go",
    "content": "// +build do-not-build\n\npackage applying\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/config\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/logging\"\n)\n\ntype testConfig struct{}\n\n// Logger implement Config\nfunc (t *testConfig) Logger() logging.Logger {\n\treturn &logging.LoggerStdOut{}\n}\n\n// RegistrationBasePrice implement Config\nfunc (t *testConfig) RegistrationBasePrice() float64 {\n\treturn 12.34\n}\n\n// DataDSN implements Config\nfunc (t *testConfig) DataDSN() string {\n\treturn \"\"\n}\n\n// ExchangeBaseURL implements Config\nfunc (t *testConfig) ExchangeBaseURL() string {\n\treturn config.App.ExchangeRateBaseURL\n}\n\n// ExchangeAPIKey implements Config\nfunc (t *testConfig) ExchangeAPIKey() string {\n\treturn config.App.ExchangeRateAPIKey\n}\n"
  },
  {
    "path": "ch08/03_applying/05_result_payload.json",
    "content": "{\n  \"success\":true,\n  \"historical\":true,\n  \"date\":\"2010-11-09\",\n  \"timestamp\":1289347199,\n  \"source\":\"USD\",\n  \"quotes\":{\n    \"USDAUD\":0.989981\n  }\n}"
  },
  {
    "path": "ch08/03_applying/06_simple_test_server.go",
    "content": "// +build do-not-build\n\npackage applying\n\nimport (\n\t\"net/http\"\n)\n\ntype happyExchangeRateService struct{}\n\n// ServeHTTP implements http.Handler\nfunc (*happyExchangeRateService) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\tpayload := []byte(`\n{\n   \"success\":true,\n   \"historical\":true,\n   \"date\":\"2010-11-09\",\n   \"timestamp\":1289347199,\n   \"source\":\"USD\",\n   \"quotes\":{\n      \"USDAUD\":0.989981\n   }\n}`)\n\tresponse.Write(payload)\n}\n"
  },
  {
    "path": "ch08/04_disadvantages/01_leaking_details.go",
    "content": "package disadvantages\n\nimport (\n\t\"errors\"\n\t\"strings\"\n)\n\ntype PeopleFilterConfig interface {\n\tDSN() string\n}\n\nfunc PeopleFilter(cfg PeopleFilterConfig, filter string) ([]Person, error) {\n\t// load people\n\tloader := &PersonLoader{}\n\tpeople, err := loader.LoadAll(cfg)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// filter people\n\tout := []Person{}\n\tfor _, person := range people {\n\t\tif strings.Contains(person.Name, filter) {\n\t\t\tout = append(out, person)\n\t\t}\n\t}\n\n\treturn out, nil\n}\n\ntype PersonLoaderConfig interface {\n\tDSN() string\n}\n\ntype PersonLoader struct{}\n\nfunc (p *PersonLoader) LoadAll(cfg PersonLoaderConfig) ([]Person, error) {\n\treturn nil, errors.New(\"not implemented\")\n}\n\n// Some data\ntype Person struct {\n\tName string\n}\n"
  },
  {
    "path": "ch08/04_disadvantages/02_hiding_details.go",
    "content": "package disadvantages\n\nimport (\n\t\"strings\"\n)\n\ntype Loader interface {\n\tLoadAll() ([]Person, error)\n}\n\nfunc PeopleFilterV2(loader Loader, filter string) ([]Person, error) {\n\t// load people\n\tpeople, err := loader.LoadAll()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// filter people\n\tout := []Person{}\n\tfor _, person := range people {\n\t\tif strings.Contains(person.Name, filter) {\n\t\t\tout = append(out, person)\n\t\t}\n\t}\n\n\treturn out, nil\n}\n"
  },
  {
    "path": "ch08/04_disadvantages/03_unclear_lifecycle.go",
    "content": "package disadvantages\n\nimport (\n\t\"errors\"\n\t\"time\"\n)\n\nfunc DoJob(pool WorkerPool, job Job) error {\n\t// wait for pool\n\tready := pool.IsReady()\n\n\tselect {\n\tcase <-ready:\n\t\t// happy path\n\n\tcase <-time.After(1 * time.Second):\n\t\treturn errors.New(\"timeout waiting for worker pool\")\n\t}\n\n\tworker := pool.GetWorker()\n\treturn worker.Do(job)\n}\n\n// Pool of workers\ntype WorkerPool interface {\n\tGetWorker() Worker\n\tIsReady() chan struct{}\n}\n\n// Executes/processes a unit of work and returns\ntype Worker interface {\n\tDo(job Job) error\n}\n\n// A unit of work to be executed against the pool\ntype Job interface {\n\t// implementation omitted\n}\n"
  },
  {
    "path": "ch08/04_disadvantages/04_clear_lifecycle.go",
    "content": "package disadvantages\n\nfunc DoJobUpdated(pool WorkerPool, job Job) error {\n\tworker := pool.GetWorker()\n\treturn worker.Do(job)\n}\n"
  },
  {
    "path": "ch08/04_disadvantages/05_layers.go",
    "content": "package disadvantages\n\nfunc NewLayer1Object(config Layer1Config) *Layer1Object {\n\treturn &Layer1Object{\n\t\tMyConfig:     config,\n\t\tMyDependency: NewLayer2Object(config),\n\t}\n}\n\n// Configuration for the Layer 1 Object\ntype Layer1Config interface {\n\tLogger() Logger\n}\n\n// Layer 1 Object\ntype Layer1Object struct {\n\tMyConfig     Layer1Config\n\tMyDependency *Layer2Object\n}\n\n// Configuration for the Layer 2 Object\ntype Layer2Config interface {\n\tLogger() Logger\n}\n\n// Layer 2 Object\ntype Layer2Object struct {\n\tMyConfig Layer2Config\n}\n\nfunc NewLayer2Object(config Layer2Config) *Layer2Object {\n\treturn &Layer2Object{\n\t\tMyConfig: config,\n\t}\n}\n\n// Stub implementation to make the compiler happy\ntype Logger interface {\n}\n"
  },
  {
    "path": "ch08/acme/internal/config/config.go",
    "content": "package config\n\nimport (\n\t\"encoding/json\"\n\t\"io/ioutil\"\n\t\"os\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/logging\"\n)\n\n// DefaultEnvVar is the default environment variable the points to the config file\nconst DefaultEnvVar = \"ACME_CONFIG\"\n\n// App is the application config\nvar App *Config\n\n// Config defines the JSON format for the config file\ntype Config struct {\n\t// DSN is the data source name (format: https://github.com/go-sql-driver/mysql/#dsn-data-source-name)\n\tDSN string\n\n\t// Address is the IP address and port to bind this rest to\n\tAddress string\n\n\t// BasePrice is the price of registration\n\tBasePrice float64\n\n\t// ExchangeRateBaseURL is the server and protocol part of the URL from which to load the exchange rate\n\tExchangeRateBaseURL string\n\n\t// ExchangeRateAPIKey is the API for the exchange rate API\n\tExchangeRateAPIKey string\n\n\t// environmental dependencies\n\tlogger logging.Logger\n}\n\n// Logger returns a reference to the singleton logger\nfunc (c *Config) Logger() logging.Logger {\n\tif c.logger == nil {\n\t\tc.logger = &logging.LoggerStdOut{}\n\t}\n\n\treturn c.logger\n}\n\n// RegistrationBasePrice returns the base price for registrations\nfunc (c *Config) RegistrationBasePrice() float64 {\n\treturn c.BasePrice\n}\n\n// DataDSN returns the DSN\nfunc (c *Config) DataDSN() string {\n\treturn c.DSN\n}\n\n// ExchangeBaseURL returns the Base URL from which we can load exchange rates\nfunc (c *Config) ExchangeBaseURL() string {\n\treturn c.ExchangeRateBaseURL\n}\n\n// ExchangeAPIKey returns the DSN\nfunc (c *Config) ExchangeAPIKey() string {\n\treturn c.ExchangeRateAPIKey\n}\n\n// BindAddress returns the host and port this service should bind to\nfunc (c *Config) BindAddress() string {\n\treturn c.Address\n}\n\n// Load returns the config loaded from environment\nfunc init() {\n\tfilename, found := os.LookupEnv(DefaultEnvVar)\n\tif !found {\n\t\tlogging.L.Error(\"failed to locate file specified by %s\", DefaultEnvVar)\n\t\treturn\n\t}\n\n\t_ = load(filename)\n}\n\nfunc load(filename string) error {\n\tApp = &Config{}\n\tbytes, err := ioutil.ReadFile(filename)\n\tif err != nil {\n\t\tlogging.L.Error(\"failed to read config file. err: %s\", err)\n\t\treturn err\n\t}\n\n\terr = json.Unmarshal(bytes, App)\n\tif err != nil {\n\t\tlogging.L.Error(\"failed to parse config file. err : %s\", err)\n\t\treturn err\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "ch08/acme/internal/config/config_test.go",
    "content": "package config\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestLoad(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc           string\n\t\tin             string\n\t\texpectedConfig *Config\n\t\texpectError    bool\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tin:   \"../../../../default-config.json\",\n\t\t\texpectedConfig: &Config{\n\t\t\t\tDSN:                 \"[insert your db config here]\",\n\t\t\t\tAddress:             \"0.0.0.0:8080\",\n\t\t\t\tBasePrice:           100.00,\n\t\t\t\tExchangeRateBaseURL: \"http://apilayer.net\",\n\t\t\t\tExchangeRateAPIKey:  \"[insert your API key here]\",\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tdesc:           \"invalid path\",\n\t\t\tin:             \"invalid.json\",\n\t\t\texpectedConfig: &Config{},\n\t\t\texpectError:    true,\n\t\t},\n\t}\n\n\tfor _, s := range scenarios {\n\t\tscenario := s\n\t\tt.Run(scenario.desc, func(t *testing.T) {\n\t\t\tresultErr := load(scenario.in)\n\t\t\trequire.Equal(t, scenario.expectError, resultErr != nil, \"err: %s\", resultErr)\n\t\t\tassert.Equal(t, scenario.expectedConfig, App, scenario.desc)\n\t\t})\n\t}\n\n}\n"
  },
  {
    "path": "ch08/acme/internal/logging/logging.go",
    "content": "package logging\n\nimport (\n\t\"fmt\"\n)\n\n// Logger is our standard interface\ntype Logger interface {\n\tDebug(message string, args ...interface{})\n\tInfo(message string, args ...interface{})\n\tWarn(message string, args ...interface{})\n\tError(message string, args ...interface{})\n}\n\n// L is the global instance of the logger\nvar L = &LoggerStdOut{}\n\n// LoggerStdOut logs to std out\ntype LoggerStdOut struct{}\n\n// Debug logs messages at DEBUG level\nfunc (l LoggerStdOut) Debug(message string, args ...interface{}) {\n\tfmt.Printf(\"[DEBUG] \"+message, args...)\n}\n\n// Info logs messages at INFO level\nfunc (l LoggerStdOut) Info(message string, args ...interface{}) {\n\tfmt.Printf(\"[INFO] \"+message, args...)\n}\n\n// Warn logs messages at WARN level\nfunc (l LoggerStdOut) Warn(message string, args ...interface{}) {\n\tfmt.Printf(\"[WARN] \"+message, args...)\n}\n\n// Error logs messages at ERROR level\nfunc (l LoggerStdOut) Error(message string, args ...interface{}) {\n\tfmt.Printf(\"[ERROR] \"+message, args...)\n}\n"
  },
  {
    "path": "ch08/acme/internal/modules/data/data.go",
    "content": "package data\n\nimport (\n\t// import the MySQL Driver\n\t\"context\"\n\t\"database/sql\"\n\t\"errors\"\n\t\"time\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/logging\"\n\t_ \"github.com/go-sql-driver/mysql\"\n)\n\nconst (\n\t// default person id (returned on error)\n\tdefaultPersonID = 0\n\n\t// SQL statements as constants (to reduce duplication and maintenance in tests)\n\tsqlAllColumns = \"id, fullname, phone, currency, price\"\n\tsqlInsert     = \"INSERT INTO person (fullname, phone, currency, price) VALUES (?, ?, ?, ?)\"\n\tsqlLoadAll    = \"SELECT \" + sqlAllColumns + \" FROM person\"\n\tsqlLoadByID   = \"SELECT \" + sqlAllColumns + \" FROM person WHERE id = ? LIMIT 1\"\n)\n\nvar (\n\tdb *sql.DB\n\n\t// ErrNotFound is returned when the no records where matched by the query\n\tErrNotFound = errors.New(\"not found\")\n)\n\n// Config is the configuration for the data package\ntype Config interface {\n\t// Logger returns a reference to the logger\n\tLogger() logging.Logger\n\n\t// DataDSN returns the data source name\n\tDataDSN() string\n}\n\nvar getDB = func(cfg Config) (*sql.DB, error) {\n\tif db == nil {\n\t\tvar err error\n\t\tdb, err = sql.Open(\"mysql\", cfg.DataDSN())\n\t\tif err != nil {\n\t\t\t// if the DB cannot be accessed we are dead\n\t\t\tpanic(err.Error())\n\t\t}\n\t}\n\n\treturn db, nil\n}\n\n// Person is the data transfer object (DTO) for this package\ntype Person struct {\n\t// ID is the unique ID for this person\n\tID int\n\t// FullName is the name of this person\n\tFullName string\n\t// Phone is the phone for this person\n\tPhone string\n\t// Currency is the currency this person has paid in\n\tCurrency string\n\t// Price is the amount (in the above currency) paid by this person\n\tPrice float64\n}\n\n// Save will save the supplied person and return the ID of the newly created person or an error.\n// Errors returned are caused by the underlying database or our connection to it.\nfunc Save(ctx context.Context, cfg Config, in *Person) (int, error) {\n\tdb, err := getDB(cfg)\n\tif err != nil {\n\t\tcfg.Logger().Error(\"failed to get DB connection. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\t// set latency budget for the database call\n\tsubCtx, cancel := context.WithTimeout(ctx, 1*time.Second)\n\tdefer cancel()\n\n\t// perform DB insert\n\tresult, err := db.ExecContext(subCtx, sqlInsert, in.FullName, in.Phone, in.Currency, in.Price)\n\tif err != nil {\n\t\tcfg.Logger().Error(\"failed to save person into DB. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\t// retrieve and return the ID of the person created\n\tid, err := result.LastInsertId()\n\tif err != nil {\n\t\tcfg.Logger().Error(\"failed to retrieve id of last saved person. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn int(id), nil\n}\n\n// LoadAll will attempt to load all people in the database\n// It will return ErrNotFound when there are not people in the database\n// Any other errors returned are caused by the underlying database or our connection to it.\nfunc LoadAll(ctx context.Context, cfg Config) ([]*Person, error) {\n\tdb, err := getDB(cfg)\n\tif err != nil {\n\t\tcfg.Logger().Error(\"failed to get DB connection. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// set latency budget for the database call\n\tsubCtx, cancel := context.WithTimeout(ctx, 1*time.Second)\n\tdefer cancel()\n\n\t// perform DB select\n\trows, err := db.QueryContext(subCtx, sqlLoadAll)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer func() {\n\t\t_ = rows.Close()\n\t}()\n\n\tvar out []*Person\n\n\tfor rows.Next() {\n\t\t// retrieve columns and populate the person object\n\t\trecord, err := populatePerson(rows.Scan)\n\t\tif err != nil {\n\t\t\tcfg.Logger().Error(\"failed to convert query result. err: %s\", err)\n\t\t\treturn nil, err\n\t\t}\n\n\t\tout = append(out, record)\n\t}\n\n\tif len(out) == 0 {\n\t\tcfg.Logger().Warn(\"no people found in the database.\")\n\t\treturn nil, ErrNotFound\n\t}\n\n\treturn out, nil\n}\n\n// Load will attempt to load and return a person.\n// It will return ErrNotFound when the requested person does not exist.\n// Any other errors returned are caused by the underlying database or our connection to it.\nfunc Load(ctx context.Context, cfg Config, ID int) (*Person, error) {\n\tdb, err := getDB(cfg)\n\tif err != nil {\n\t\tcfg.Logger().Error(\"failed to get DB connection. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// set latency budget for the database call\n\tsubCtx, cancel := context.WithTimeout(ctx, 1*time.Second)\n\tdefer cancel()\n\n\t// perform DB select\n\trow := db.QueryRowContext(subCtx, sqlLoadByID, ID)\n\n\t// retrieve columns and populate the person object\n\tout, err := populatePerson(row.Scan)\n\tif err != nil {\n\t\tif err == sql.ErrNoRows {\n\t\t\tcfg.Logger().Warn(\"failed to load requested person '%d'. err: %s\", ID, err)\n\t\t\treturn nil, ErrNotFound\n\t\t}\n\n\t\tcfg.Logger().Error(\"failed to convert query result. err: %s\", err)\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\n// custom type so we can convert sql results to easily\ntype scanner func(dest ...interface{}) error\n\n// reduce the duplication (and maintenance) between sql.Row and sql.Rows usage\nfunc populatePerson(scanner scanner) (*Person, error) {\n\tout := &Person{}\n\terr := scanner(&out.ID, &out.FullName, &out.Phone, &out.Currency, &out.Price)\n\treturn out, err\n}\n"
  },
  {
    "path": "ch08/acme/internal/modules/data/data_test.go",
    "content": "package data\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"errors\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/DATA-DOG/go-sqlmock\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/logging\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestSave_happyPath(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\t// define a mock db\n\ttestDb, dbMock, err := sqlmock.New()\n\tdefer testDb.Close()\n\trequire.NoError(t, err)\n\n\t// configure the mock db\n\tqueryRegex := convertSQLToRegex(sqlInsert)\n\tdbMock.ExpectExec(queryRegex).WillReturnResult(sqlmock.NewResult(2, 1))\n\n\t// monkey patching starts here\n\tdb = testDb\n\t// end of monkey patch\n\n\t// inputs\n\tin := &Person{\n\t\tFullName: \"Jake Blues\",\n\t\tPhone:    \"01234567890\",\n\t\tCurrency: \"AUD\",\n\t\tPrice:    123.45,\n\t}\n\n\t// call function\n\tresultID, err := Save(ctx, &testConfig{}, in)\n\n\t// validate result\n\trequire.NoError(t, err)\n\tassert.Equal(t, 2, resultID)\n\tassert.NoError(t, dbMock.ExpectationsWereMet())\n}\n\nfunc TestSave_insertError(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\t// define a mock db\n\ttestDb, dbMock, err := sqlmock.New()\n\tdefer testDb.Close()\n\n\trequire.NoError(t, err)\n\n\t// configure the mock db\n\tqueryRegex := convertSQLToRegex(sqlInsert)\n\tdbMock.ExpectExec(queryRegex).WillReturnError(errors.New(\"failed to insert\"))\n\n\t// monkey patching starts here\n\tdb = testDb\n\t// end of monkey patch\n\n\t// inputs\n\tin := &Person{\n\t\tFullName: \"Jake Blues\",\n\t\tPhone:    \"01234567890\",\n\t\tCurrency: \"AUD\",\n\t\tPrice:    123.45,\n\t}\n\n\t// call function\n\tresultID, err := Save(ctx, &testConfig{}, in)\n\n\t// validate result\n\trequire.Error(t, err)\n\tassert.Equal(t, defaultPersonID, resultID)\n\tassert.NoError(t, dbMock.ExpectationsWereMet())\n}\n\nfunc TestSave_getDBError(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\t// monkey patching starts here\n\tdefer func(original func(_ Config) (*sql.DB, error)) {\n\t\t// restore original DB (after test)\n\t\tgetDB = original\n\t}(getDB)\n\n\t// replace getDB() function for this test\n\tgetDB = func(_ Config) (*sql.DB, error) {\n\t\treturn nil, errors.New(\"getDB() failed\")\n\t}\n\t// end of monkey patch\n\n\t// inputs\n\tin := &Person{\n\t\tFullName: \"Jake Blues\",\n\t\tPhone:    \"01234567890\",\n\t\tCurrency: \"AUD\",\n\t\tPrice:    123.45,\n\t}\n\n\t// call function\n\tresultID, err := Save(ctx, &testConfig{}, in)\n\trequire.Error(t, err)\n\tassert.Equal(t, defaultPersonID, resultID)\n}\n\nfunc TestLoadAll_tableDrivenTest(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\n\tdefer cancel()\n\n\tscenarios := []struct {\n\t\tdesc            string\n\t\tconfigureMockDB func(sqlmock.Sqlmock)\n\t\texpectedResults []*Person\n\t\texpectError     bool\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tconfigureMockDB: func(dbMock sqlmock.Sqlmock) {\n\t\t\t\tqueryRegex := convertSQLToRegex(sqlLoadAll)\n\t\t\t\tdbMock.ExpectQuery(queryRegex).WillReturnRows(\n\t\t\t\t\tsqlmock.NewRows(strings.Split(sqlAllColumns, \", \")).\n\t\t\t\t\t\tAddRow(1, \"John\", \"0123456789\", \"AUD\", 12.34))\n\t\t\t},\n\t\t\texpectedResults: []*Person{\n\t\t\t\t{\n\t\t\t\t\tID:       1,\n\t\t\t\t\tFullName: \"John\",\n\t\t\t\t\tPhone:    \"0123456789\",\n\t\t\t\t\tCurrency: \"AUD\",\n\t\t\t\t\tPrice:    12.34,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tdesc: \"load error\",\n\t\t\tconfigureMockDB: func(dbMock sqlmock.Sqlmock) {\n\t\t\t\tqueryRegex := convertSQLToRegex(sqlLoadAll)\n\t\t\t\tdbMock.ExpectQuery(queryRegex).WillReturnError(errors.New(\"something failed\"))\n\t\t\t},\n\t\t\texpectedResults: nil,\n\t\t\texpectError:     true,\n\t\t},\n\t}\n\n\tfor _, scenario := range scenarios {\n\t\t// define a mock db\n\t\ttestDb, dbMock, err := sqlmock.New()\n\t\trequire.NoError(t, err)\n\n\t\t// configure the mock db\n\t\tscenario.configureMockDB(dbMock)\n\n\t\t// monkey patch the db for this test\n\t\toriginal := *db\n\t\tdb = testDb\n\n\t\t// call function\n\t\tresults, err := LoadAll(ctx, &testConfig{})\n\n\t\t// validate results\n\t\tassert.Equal(t, scenario.expectedResults, results, scenario.desc)\n\t\tassert.Equal(t, scenario.expectError, err != nil, scenario.desc)\n\t\tassert.NoError(t, dbMock.ExpectationsWereMet())\n\n\t\t// restore original DB (after test)\n\t\tdb = &original\n\t\ttestDb.Close()\n\t}\n}\n\nfunc TestLoad_tableDrivenTest(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\n\tdefer cancel()\n\n\tscenarios := []struct {\n\t\tdesc            string\n\t\tconfigureMockDB func(sqlmock.Sqlmock)\n\t\texpectedResult  *Person\n\t\texpectError     bool\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tconfigureMockDB: func(dbMock sqlmock.Sqlmock) {\n\t\t\t\tqueryRegex := convertSQLToRegex(sqlLoadAll)\n\t\t\t\tdbMock.ExpectQuery(queryRegex).WillReturnRows(\n\t\t\t\t\tsqlmock.NewRows(strings.Split(sqlAllColumns, \", \")).\n\t\t\t\t\t\tAddRow(2, \"Paul\", \"0123456789\", \"CAD\", 23.45))\n\t\t\t},\n\t\t\texpectedResult: &Person{\n\t\t\t\tID:       2,\n\t\t\t\tFullName: \"Paul\",\n\t\t\t\tPhone:    \"0123456789\",\n\t\t\t\tCurrency: \"CAD\",\n\t\t\t\tPrice:    23.45,\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tdesc: \"load error\",\n\t\t\tconfigureMockDB: func(dbMock sqlmock.Sqlmock) {\n\t\t\t\tqueryRegex := convertSQLToRegex(sqlLoadAll)\n\t\t\t\tdbMock.ExpectQuery(queryRegex).WillReturnError(errors.New(\"something failed\"))\n\t\t\t},\n\t\t\texpectedResult: nil,\n\t\t\texpectError:    true,\n\t\t},\n\t}\n\n\tfor _, scenario := range scenarios {\n\t\t// define a mock db\n\t\ttestDb, dbMock, err := sqlmock.New()\n\t\trequire.NoError(t, err)\n\n\t\t// configure the mock db\n\t\tscenario.configureMockDB(dbMock)\n\n\t\t// monkey db for this test\n\t\toriginal := *db\n\t\tdb = testDb\n\n\t\t// call function\n\t\tresult, err := Load(ctx, &testConfig{}, 2)\n\n\t\t// validate results\n\t\tassert.Equal(t, scenario.expectedResult, result, scenario.desc)\n\t\tassert.Equal(t, scenario.expectError, err != nil, scenario.desc)\n\t\tassert.NoError(t, dbMock.ExpectationsWereMet())\n\n\t\t// restore original DB (after test)\n\t\tdb = &original\n\t\ttestDb.Close()\n\t}\n}\n\n// convert SQL string to regex by treating the entire query as a literal\nfunc convertSQLToRegex(in string) string {\n\treturn `\\Q` + in + `\\E`\n}\n\ntype testConfig struct{}\n\n// Logger implements Config\nfunc (t *testConfig) Logger() logging.Logger {\n\treturn logging.LoggerStdOut{}\n}\n\n// DataDSN implements Config\nfunc (t *testConfig) DataDSN() string {\n\treturn \"\"\n}\n"
  },
  {
    "path": "ch08/acme/internal/modules/exchange/converter.go",
    "content": "package exchange\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"math\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/logging\"\n)\n\nconst (\n\t// request URL for the exchange rate API\n\turlFormat = \"%s/api/historical?access_key=%s&date=2018-06-20&currencies=%s\"\n\n\t// default price that is sent when an error occurs\n\tdefaultPrice = 0.0\n)\n\n// NewConverter creates and initializes the converter\nfunc NewConverter(cfg Config) *Converter {\n\treturn &Converter{\n\t\tcfg: cfg,\n\t}\n}\n\n// Config is the config for Converter\ntype Config interface {\n\tLogger() logging.Logger\n\tExchangeBaseURL() string\n\tExchangeAPIKey() string\n}\n\n// Converter will convert the base price to the currency supplied\n// Note: we are expecting sane inputs and therefore skipping input validation\ntype Converter struct {\n\tcfg Config\n}\n\n// Exchange will perform the conversion\nfunc (c *Converter) Exchange(ctx context.Context, basePrice float64, currency string) (float64, error) {\n\t// load rate from the external API\n\tresponse, err := c.loadRateFromServer(ctx, currency)\n\tif err != nil {\n\t\treturn defaultPrice, err\n\t}\n\n\t// extract rate from response\n\trate, err := c.extractRate(response, currency)\n\tif err != nil {\n\t\treturn defaultPrice, err\n\t}\n\n\t// apply rate and round to 2 decimal places\n\treturn math.Floor((basePrice/rate)*100) / 100, nil\n}\n\n// load rate from the external API\nfunc (c *Converter) loadRateFromServer(ctx context.Context, currency string) (*http.Response, error) {\n\t// build the request\n\turl := fmt.Sprintf(urlFormat,\n\t\tc.cfg.ExchangeBaseURL(),\n\t\tc.cfg.ExchangeAPIKey(),\n\t\tcurrency)\n\n\t// perform request\n\treq, err := http.NewRequest(\"GET\", url, nil)\n\tif err != nil {\n\t\tc.logger().Warn(\"[exchange] failed to create request. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// set latency budget for the upstream call\n\tsubCtx, cancel := context.WithTimeout(ctx, 1*time.Second)\n\tdefer cancel()\n\n\t// replace the default context with our custom one\n\treq = req.WithContext(subCtx)\n\n\t// perform the HTTP request\n\tresponse, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tc.logger().Warn(\"[exchange] failed to load. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\tif response.StatusCode != http.StatusOK {\n\t\terr = fmt.Errorf(\"request failed with code %d\", response.StatusCode)\n\t\tc.logger().Warn(\"[exchange] %s\", err)\n\t\treturn nil, err\n\t}\n\n\treturn response, nil\n}\n\nfunc (c *Converter) extractRate(response *http.Response, currency string) (float64, error) {\n\tdefer func() {\n\t\t_ = response.Body.Close()\n\t}()\n\n\t// extract data from response\n\tdata, err := c.extractResponse(response)\n\tif err != nil {\n\t\treturn defaultPrice, err\n\t}\n\n\t// pull rate from response data\n\trate, found := data.Quotes[\"USD\"+currency]\n\tif !found {\n\t\terr = fmt.Errorf(\"response did not include expected currency '%s'\", currency)\n\t\tc.logger().Error(\"[exchange] %s\", err)\n\t\treturn defaultPrice, err\n\t}\n\n\t// happy path\n\treturn rate, nil\n}\n\nfunc (c *Converter) extractResponse(response *http.Response) (*apiResponseFormat, error) {\n\tpayload, err := ioutil.ReadAll(response.Body)\n\tif err != nil {\n\t\tc.logger().Error(\"[exchange] failed to ready response body. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\tdata := &apiResponseFormat{}\n\terr = json.Unmarshal(payload, data)\n\tif err != nil {\n\t\tc.logger().Error(\"[exchange] error converting response. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// happy path\n\treturn data, nil\n}\n\nfunc (c *Converter) logger() logging.Logger {\n\treturn c.cfg.Logger()\n}\n\n// the response format from the exchange rate API\ntype apiResponseFormat struct {\n\tQuotes map[string]float64 `json:\"quotes\"`\n}\n"
  },
  {
    "path": "ch08/acme/internal/modules/exchange/converter_ext_bounday_test.go",
    "content": "// +build external\n\npackage exchange\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/config\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestExternalBoundaryTest(t *testing.T) {\n\t// define the config\n\tcfg := &testConfig{\n\t\tbaseURL: config.App.ExchangeRateBaseURL,\n\t\tapiKey:  config.App.ExchangeRateAPIKey,\n\t}\n\n\t// create a converter to test\n\tconverter := NewConverter(cfg)\n\n\t// fetch from the server\n\tresponse, err := converter.loadRateFromServer(context.Background(), \"AUD\")\n\trequire.NotNil(t, response)\n\trequire.NoError(t, err)\n\n\t// parse the response\n\tresultRate, err := converter.extractRate(response, \"AUD\")\n\trequire.NoError(t, err)\n\n\t// validate the result\n\tassert.True(t, resultRate > 0)\n}\n"
  },
  {
    "path": "ch08/acme/internal/modules/exchange/converter_int_bounday_test.go",
    "content": "package exchange\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/logging\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestInternalBoundaryTest(t *testing.T) {\n\t// start our test server\n\tserver := httptest.NewServer(&happyExchangeRateService{})\n\tdefer server.Close()\n\n\t// define the config\n\tcfg := &testConfig{\n\t\tbaseURL: server.URL,\n\t\tapiKey:  \"\",\n\t}\n\n\t// create a converter to test\n\tconverter := NewConverter(cfg)\n\tresultRate, resultErr := converter.Exchange(context.Background(), 100.00, \"AUD\")\n\n\t// validate the result\n\tassert.Equal(t, 101.01, resultRate)\n\tassert.NoError(t, resultErr)\n}\n\ntype happyExchangeRateService struct{}\n\n// ServeHTTP implements http.Handler\nfunc (*happyExchangeRateService) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\tpayload := []byte(`\n{\n   \"success\":true,\n   \"historical\":true,\n   \"date\":\"2010-11-09\",\n   \"timestamp\":1289347199,\n   \"source\":\"USD\",\n   \"quotes\":{\n      \"USDAUD\":0.989981\n   }\n}`)\n\tresponse.Write(payload)\n}\n\n// test implementation of Config\ntype testConfig struct {\n\tbaseURL string\n\tapiKey  string\n}\n\n// Logger implements Config\nfunc (t *testConfig) Logger() logging.Logger {\n\treturn &logging.LoggerStdOut{}\n}\n\n// ExchangeBaseURL implements Config\nfunc (t *testConfig) ExchangeBaseURL() string {\n\treturn t.baseURL\n}\n\n// ExchangeAPIKey implements Config\nfunc (t *testConfig) ExchangeAPIKey() string {\n\treturn t.apiKey\n}\n"
  },
  {
    "path": "ch08/acme/internal/modules/get/get.go",
    "content": "package get\n\nimport (\n\t\"context\"\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/modules/data\"\n)\n\nvar (\n\t// error thrown when the requested person is not in the database\n\terrPersonNotFound = errors.New(\"person not found\")\n)\n\n// NewGetter creates and initializes a Getter\nfunc NewGetter(cfg Config) *Getter {\n\treturn &Getter{\n\t\tcfg: cfg,\n\t}\n}\n\n// Config is the configuration for Getter\ntype Config interface {\n\tLogger() logging.Logger\n\tDataDSN() string\n}\n\n// Getter will attempt to load a person.\n// It can return an error caused by the data layer or when the requested person is not found\ntype Getter struct {\n\tcfg Config\n}\n\n// Do will perform the get\nfunc (g *Getter) Do(ID int) (*data.Person, error) {\n\t// load person from the data layer\n\tperson, err := loader(context.TODO(), g.cfg, ID)\n\tif err != nil {\n\t\tif err == data.ErrNotFound {\n\t\t\t// By converting the error we are hiding the implementation details from our users.\n\t\t\treturn nil, errPersonNotFound\n\t\t}\n\t\treturn nil, err\n\t}\n\n\treturn person, err\n}\n\n// this function as a variable allows us to Monkey Patch during testing\nvar loader = data.Load\n"
  },
  {
    "path": "ch08/acme/internal/modules/get/go_test.go",
    "content": "package get\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestGetter_Do_happyPath(t *testing.T) {\n\t// inputs\n\tID := 1234\n\n\t// monkey patch calls to the data package\n\tdefer func(original func(_ context.Context, _ data.Config, _ int) (*data.Person, error)) {\n\t\t// restore original\n\t\tloader = original\n\t}(loader)\n\n\t// replace method\n\tloader = func(_ context.Context, _ data.Config, _ int) (*data.Person, error) {\n\t\tresult := &data.Person{\n\t\t\tID:       1234,\n\t\t\tFullName: \"Doug\",\n\t\t}\n\t\tvar resultErr error\n\n\t\treturn result, resultErr\n\t}\n\t// end of monkey patch\n\n\t// call method\n\tgetter := &Getter{}\n\tperson, err := getter.Do(ID)\n\n\t// validate expectations\n\trequire.NoError(t, err)\n\tassert.Equal(t, ID, person.ID)\n\tassert.Equal(t, \"Doug\", person.FullName)\n}\n\nfunc TestGetter_Do_noSuchPerson(t *testing.T) {\n\t// inputs\n\tID := 5678\n\n\t// monkey patch calls to the data package\n\tdefer func(original func(_ context.Context, _ data.Config, _ int) (*data.Person, error)) {\n\t\t// restore original\n\t\tloader = original\n\t}(loader)\n\n\t// replace method\n\tloader = func(_ context.Context, _ data.Config, _ int) (*data.Person, error) {\n\t\tvar result *data.Person\n\t\tresultErr := data.ErrNotFound\n\n\t\treturn result, resultErr\n\t}\n\t// end of monkey patch\n\n\t// call method\n\tgetter := &Getter{}\n\tperson, err := getter.Do(ID)\n\n\t// validate expectations\n\trequire.Equal(t, errPersonNotFound, err)\n\tassert.Nil(t, person)\n}\n\nfunc TestGetter_Do_error(t *testing.T) {\n\t// inputs\n\tID := 1234\n\n\t// monkey patch calls to the data package\n\tdefer func(original func(_ context.Context, _ data.Config, _ int) (*data.Person, error)) {\n\t\t// restore original\n\t\tloader = original\n\t}(loader)\n\n\t// replace method\n\tloader = func(_ context.Context, _ data.Config, _ int) (*data.Person, error) {\n\t\tvar result *data.Person\n\t\tresultErr := errors.New(\"failed to load person\")\n\n\t\treturn result, resultErr\n\t}\n\t// end of monkey patch\n\n\t// call method\n\tgetter := &Getter{}\n\tperson, err := getter.Do(ID)\n\n\t// validate expectations\n\trequire.Error(t, err)\n\tassert.Nil(t, person)\n}\n"
  },
  {
    "path": "ch08/acme/internal/modules/list/list.go",
    "content": "package list\n\nimport (\n\t\"context\"\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/modules/data\"\n)\n\nvar (\n\t// error thrown when there are no people in the database\n\terrPeopleNotFound = errors.New(\"no people found\")\n)\n\n// NewLister creates and initializes a Lister\nfunc NewLister(cfg Config) *Lister {\n\treturn &Lister{\n\t\tcfg: cfg,\n\t}\n}\n\n// Config is the config for Lister\ntype Config interface {\n\tLogger() logging.Logger\n\tDataDSN() string\n}\n\n// Lister will attempt to load all people in the database.\n// It can return an error caused by the data layer\ntype Lister struct {\n\tcfg Config\n}\n\n// Exchange will load the people from the data layer\nfunc (l *Lister) Do() ([]*data.Person, error) {\n\t// load all people\n\tpeople, err := l.load()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(people) == 0 {\n\t\t// special processing for 0 people returned\n\t\treturn nil, errPeopleNotFound\n\t}\n\n\treturn people, nil\n}\n\n// load all people\nfunc (l *Lister) load() ([]*data.Person, error) {\n\tpeople, err := loader(context.TODO(), l.cfg)\n\tif err != nil {\n\t\tif err == data.ErrNotFound {\n\t\t\t// By converting the error we are encapsulating the implementation details from our users.\n\t\t\treturn nil, errPeopleNotFound\n\t\t}\n\t\treturn nil, err\n\t}\n\n\treturn people, nil\n}\n\n// this function as a variable allows us to Monkey Patch during testing\nvar loader = data.LoadAll\n"
  },
  {
    "path": "ch08/acme/internal/modules/list/list_test.go",
    "content": "package list\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestLister_Do_happyPath(t *testing.T) {\n\t// monkey patch calls to the data package\n\tdefer func(original func(_ context.Context, _ data.Config) ([]*data.Person, error)) {\n\t\t// restore original\n\t\tloader = original\n\t}(loader)\n\n\t// replace method\n\tloader = func(_ context.Context, _ data.Config) ([]*data.Person, error) {\n\t\tresult := []*data.Person{\n\t\t\t{\n\t\t\t\tID:       1234,\n\t\t\t\tFullName: \"Sally\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tID:       5678,\n\t\t\t\tFullName: \"Jane\",\n\t\t\t},\n\t\t}\n\t\tvar resultErr error\n\n\t\treturn result, resultErr\n\t}\n\t// end of monkey patch\n\n\t// call method\n\tlister := &Lister{}\n\tpersons, err := lister.load()\n\n\t// validate expectations\n\trequire.NoError(t, err)\n\tassert.Equal(t, 2, len(persons))\n}\n\nfunc TestLister_Do_noResults(t *testing.T) {\n\t// monkey patch calls to the data package\n\tdefer func(original func(_ context.Context, _ data.Config) ([]*data.Person, error)) {\n\t\t// restore original\n\t\tloader = original\n\t}(loader)\n\n\t// replace method\n\tloader = func(_ context.Context, _ data.Config) ([]*data.Person, error) {\n\t\tvar result []*data.Person\n\t\tresultErr := data.ErrNotFound\n\n\t\treturn result, resultErr\n\t}\n\t// end of monkey patch\n\n\t// call method\n\tlister := &Lister{}\n\tpersons, err := lister.load()\n\n\t// validate expectations\n\trequire.Equal(t, errPeopleNotFound, err)\n\tassert.Equal(t, 0, len(persons))\n}\n\nfunc TestLister_Do_error(t *testing.T) {\n\t// monkey patch calls to the data package\n\tdefer func(original func(_ context.Context, _ data.Config) ([]*data.Person, error)) {\n\t\t// restore original\n\t\tloader = original\n\t}(loader)\n\n\t// replace method\n\tloader = func(_ context.Context, _ data.Config) ([]*data.Person, error) {\n\t\tvar result []*data.Person\n\t\tresultErr := errors.New(\"failed to load people\")\n\n\t\treturn result, resultErr\n\t}\n\t// end of monkey patch\n\n\t// call method\n\tlister := &Lister{}\n\tpersons, err := lister.load()\n\n\t// validate expectations\n\trequire.Error(t, err)\n\tassert.Equal(t, 0, len(persons))\n}\n"
  },
  {
    "path": "ch08/acme/internal/modules/register/register.go",
    "content": "package register\n\nimport (\n\t\"context\"\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/modules/data\"\n)\n\nconst (\n\t// default person id (returned on error)\n\tdefaultPersonID = 0\n)\n\nvar (\n\t// validation errors\n\terrNameMissing     = errors.New(\"name is missing\")\n\terrPhoneMissing    = errors.New(\"phone is missing\")\n\terrCurrencyMissing = errors.New(\"currency is missing\")\n\terrInvalidCurrency = errors.New(\"currency is invalid, supported types are AUD, CNY, EUR, GBP, JPY, MYR, SGD, USD\")\n\n\t// a little trick to make checking for supported currencies easier\n\tsupportedCurrencies = map[string]struct{}{\n\t\t\"AUD\": {},\n\t\t\"CNY\": {},\n\t\t\"EUR\": {},\n\t\t\"GBP\": {},\n\t\t\"JPY\": {},\n\t\t\"MYR\": {},\n\t\t\"SGD\": {},\n\t\t\"USD\": {},\n\t}\n)\n\n// NewRegisterer creates and initializes a Registerer\nfunc NewRegisterer(cfg Config, exchanger Exchanger) *Registerer {\n\treturn &Registerer{\n\t\tcfg:       cfg,\n\t\texchanger: exchanger,\n\t}\n}\n\n// Exchanger will convert from one currency to another\ntype Exchanger interface {\n\t// Exchange will perform the conversion\n\tExchange(ctx context.Context, basePrice float64, currency string) (float64, error)\n}\n\n// Config is the configuration for the Registerer\ntype Config interface {\n\tLogger() logging.Logger\n\tRegistrationBasePrice() float64\n\tDataDSN() string\n}\n\n// Registerer validates the supplied person, calculates the price in the requested currency and saves the result.\n// It will return an error when:\n// -the person object does not include all the fields\n// -the currency is invalid\n// -the exchange rate cannot be loaded\n// -the data layer throws an error.\ntype Registerer struct {\n\tcfg       Config\n\texchanger Exchanger\n}\n\n// Do is API for this struct\nfunc (r *Registerer) Do(ctx context.Context, in *data.Person) (int, error) {\n\t// validate the request\n\terr := r.validateInput(in)\n\tif err != nil {\n\t\tr.logger().Warn(\"input validation failed with err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\t// get price in the requested currency\n\tprice, err := r.getPrice(ctx, in.Currency)\n\tif err != nil {\n\t\treturn defaultPersonID, err\n\t}\n\n\t// save registration\n\tid, err := r.save(ctx, in, price)\n\tif err != nil {\n\t\t// no need to log here as we expect the data layer to do so\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn id, nil\n}\n\n// validate input and return error on fail\nfunc (r *Registerer) validateInput(in *data.Person) error {\n\tif in.FullName == \"\" {\n\t\treturn errNameMissing\n\t}\n\tif in.Phone == \"\" {\n\t\treturn errPhoneMissing\n\t}\n\tif in.Currency == \"\" {\n\t\treturn errCurrencyMissing\n\t}\n\n\tif _, found := supportedCurrencies[in.Currency]; !found {\n\t\treturn errInvalidCurrency\n\t}\n\n\t// happy path\n\treturn nil\n}\n\n// get price in the requested currency\nfunc (r *Registerer) getPrice(ctx context.Context, currency string) (float64, error) {\n\tprice, err := r.exchanger.Exchange(ctx, r.cfg.RegistrationBasePrice(), currency)\n\tif err != nil {\n\t\tr.logger().Warn(\"failed to convert the price. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn price, nil\n}\n\n// save the registration\nfunc (r *Registerer) save(ctx context.Context, in *data.Person, price float64) (int, error) {\n\tperson := &data.Person{\n\t\tFullName: in.FullName,\n\t\tPhone:    in.Phone,\n\t\tCurrency: in.Currency,\n\t\tPrice:    price,\n\t}\n\treturn saver(ctx, r.cfg, person)\n}\n\nfunc (r *Registerer) logger() logging.Logger {\n\treturn r.cfg.Logger()\n}\n\n// this function as a variable allows us to Monkey Patch during testing\nvar saver = data.Save\n"
  },
  {
    "path": "ch08/acme/internal/modules/register/register_test.go",
    "content": "package register\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestRegisterer_Do_happyPath(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\t// monkey patch calls to the data package\n\tdefer func(original func(_ context.Context, _ data.Config, _ *data.Person) (int, error)) {\n\t\t// restore original\n\t\tsaver = original\n\t}(saver)\n\n\t// replace method\n\tsaver = func(_ context.Context, _ data.Config, _ *data.Person) (int, error) {\n\t\tresult := 888\n\t\tvar resultErr error\n\n\t\treturn result, resultErr\n\t}\n\t// end of monkey patch\n\n\t// inputs\n\tin := &data.Person{\n\t\tFullName: \"Chang\",\n\t\tPhone:    \"11122233355\",\n\t\tCurrency: \"CNY\",\n\t}\n\n\t// call method\n\tregisterer := &Registerer{\n\t\tcfg:       &testConfig{},\n\t\texchanger: &stubExchanger{},\n\t}\n\tID, err := registerer.Do(ctx, in)\n\n\t// validate expectations\n\trequire.NoError(t, err)\n\tassert.Equal(t, 888, ID)\n}\n\nfunc TestRegisterer_Do_error(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\t// monkey patch calls to the data package\n\tdefer func(original func(_ context.Context, _ data.Config, _ *data.Person) (int, error)) {\n\t\t// restore original\n\t\tsaver = original\n\t}(saver)\n\n\t// replace method\n\tsaver = func(_ context.Context, _ data.Config, _ *data.Person) (int, error) {\n\t\tvar result int\n\t\tresultErr := errors.New(\"failed to save\")\n\n\t\treturn result, resultErr\n\t}\n\t// end of monkey patch\n\n\t// inputs\n\tin := &data.Person{\n\t\tFullName: \"Chang\",\n\t\tPhone:    \"11122233355\",\n\t\tCurrency: \"CNY\",\n\t}\n\n\t// call method\n\tregisterer := &Registerer{\n\t\tcfg:       &testConfig{},\n\t\texchanger: &stubExchanger{},\n\t}\n\tID, err := registerer.Do(ctx, in)\n\n\t// validate expectations\n\trequire.Error(t, err)\n\tassert.Equal(t, 0, ID)\n}\n\n// Stub implementation of Config\ntype testConfig struct{}\n\n// Logger implement Config\nfunc (t *testConfig) Logger() logging.Logger {\n\treturn &logging.LoggerStdOut{}\n}\n\n// RegistrationBasePrice implement Config\nfunc (t *testConfig) RegistrationBasePrice() float64 {\n\treturn 12.34\n}\n\n// DataDSN implements Config\nfunc (t *testConfig) DataDSN() string {\n\treturn \"\"\n}\n\ntype stubExchanger struct{}\n\n// Exchange implements Exchanger\nfunc (s stubExchanger) Exchange(ctx context.Context, basePrice float64, currency string) (float64, error) {\n\treturn 12.34, nil\n}\n"
  },
  {
    "path": "ch08/acme/internal/rest/get.go",
    "content": "package rest\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/modules/data\"\n\t\"github.com/gorilla/mux\"\n)\n\nconst (\n\t// default person id (returned on error)\n\tdefaultPersonID = 0\n\n\t// key in the mux where the ID is stored\n\tmuxVarID = \"id\"\n)\n\n// GetModel will load a registration\n//go:generate mockery -name=GetModel -case underscore -testonly -inpkg -note @generated\ntype GetModel interface {\n\tDo(ID int) (*data.Person, error)\n}\n\n// GetConfig is the config for the Get Handler\ntype GetConfig interface {\n\tLogger() logging.Logger\n}\n\n// NewGetHandler is the constructor for GetHandler\nfunc NewGetHandler(cfg GetConfig, model GetModel) *GetHandler {\n\treturn &GetHandler{\n\t\tcfg:    cfg,\n\t\tgetter: model,\n\t}\n}\n\n// GetHandler is the HTTP handler for the \"Get Person\" endpoint\n// In this simplified example we are assuming all possible errors are user errors and returning \"bad request\" HTTP 400\n// or \"not found\" HTTP 404\n// There are some programmer errors possible but hopefully these will be caught in testing.\ntype GetHandler struct {\n\tcfg    GetConfig\n\tgetter GetModel\n}\n\n// ServeHTTP implements http.Handler\nfunc (h *GetHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\t// extract person id from request\n\tid, err := h.extractID(request)\n\tif err != nil {\n\t\t// output error\n\t\tresponse.WriteHeader(http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// attempt get\n\tperson, err := h.getter.Do(id)\n\tif err != nil {\n\t\t// not need to log here as we can expect other layers to do so\n\t\tresponse.WriteHeader(http.StatusNotFound)\n\t\treturn\n\t}\n\n\t// happy path\n\terr = h.writeJSON(response, person)\n\tif err != nil {\n\t\t// this error should not happen but if it does there is nothing we can do to recover\n\t\tresponse.WriteHeader(http.StatusInternalServerError)\n\t}\n}\n\n// extract the person ID from the request\nfunc (h *GetHandler) extractID(request *http.Request) (int, error) {\n\t// ID is part of the URL, so we extract it from there\n\tvars := mux.Vars(request)\n\tidAsString, exists := vars[muxVarID]\n\tif !exists {\n\t\t// log and return error\n\t\terr := errors.New(\"[get] person id missing from request\")\n\t\th.cfg.Logger().Warn(err.Error())\n\t\treturn defaultPersonID, err\n\t}\n\n\t// convert ID to int\n\tid, err := strconv.Atoi(idAsString)\n\tif err != nil {\n\t\t// log and return error\n\t\terr = fmt.Errorf(\"[get] failed to convert person id into a number. err: %s\", err)\n\t\th.cfg.Logger().Error(err.Error())\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn id, nil\n}\n\n// output the supplied person as JSON\nfunc (h *GetHandler) writeJSON(writer io.Writer, person *data.Person) error {\n\toutput := &getResponseFormat{\n\t\tID:       person.ID,\n\t\tFullName: person.FullName,\n\t\tPhone:    person.Phone,\n\t\tCurrency: person.Currency,\n\t\tPrice:    person.Price,\n\t}\n\n\t// call to http.ResponseWriter.Write() will cause HTTP OK (200) to be output as well\n\treturn json.NewEncoder(writer).Encode(output)\n}\n\n// the JSON response format\ntype getResponseFormat struct {\n\tID       int     `json:\"id\"`\n\tFullName string  `json:\"name\"`\n\tPhone    string  `json:\"phone\"`\n\tCurrency string  `json:\"currency\"`\n\tPrice    float64 `json:\"price\"`\n}\n"
  },
  {
    "path": "ch08/acme/internal/rest/get_test.go",
    "content": "package rest\n\nimport (\n\t\"errors\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/modules/data\"\n\t\"github.com/gorilla/mux\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestGetHandler_ServeHTTP(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc            string\n\t\tinRequest       func() *http.Request\n\t\tinModelMock     func() *MockGetModel\n\t\texpectedStatus  int\n\t\texpectedPayload string\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/1/\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// set values into request (required by the mux)\n\t\t\t\treturn mux.SetURLVars(req, map[string]string{muxVarID: \"1\"})\n\t\t\t},\n\t\t\tinModelMock: func() *MockGetModel {\n\t\t\t\toutput := &data.Person{\n\t\t\t\t\tID:       1,\n\t\t\t\t\tFullName: \"John\",\n\t\t\t\t\tPhone:    \"0123456789\",\n\t\t\t\t\tCurrency: \"USD\",\n\t\t\t\t\tPrice:    100,\n\t\t\t\t}\n\n\t\t\t\tmockGetModel := &MockGetModel{}\n\t\t\t\tmockGetModel.On(\"Do\", mock.Anything).Return(output, nil).Once()\n\n\t\t\t\treturn mockGetModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusOK,\n\t\t\texpectedPayload: `{\"id\":1,\"name\":\"John\",\"phone\":\"0123456789\",\"currency\":\"USD\",\"price\":100}` + \"\\n\",\n\t\t},\n\t\t{\n\t\t\tdesc: \"bad input (ID is invalid)\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/x/\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// set values into request (required by the mux)\n\t\t\t\treturn mux.SetURLVars(req, map[string]string{muxVarID: \"x\"})\n\t\t\t},\n\t\t\tinModelMock: func() *MockGetModel {\n\t\t\t\t// expect the model not to be called\n\t\t\t\tmockRegisterModel := &MockGetModel{}\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusBadRequest,\n\t\t\texpectedPayload: ``,\n\t\t},\n\t\t{\n\t\t\tdesc: \"bad input (ID is missing)\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person//\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// set values into request (required by the mux)\n\t\t\t\treturn mux.SetURLVars(req, map[string]string{})\n\t\t\t},\n\t\t\tinModelMock: func() *MockGetModel {\n\t\t\t\t// expect the model not to be called\n\t\t\t\tmockRegisterModel := &MockGetModel{}\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusBadRequest,\n\t\t\texpectedPayload: ``,\n\t\t},\n\t\t{\n\t\t\tdesc: \"dependency fail\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/1/\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// set values into request (required by the mux)\n\t\t\t\treturn mux.SetURLVars(req, map[string]string{muxVarID: \"1\"})\n\t\t\t},\n\t\t\tinModelMock: func() *MockGetModel {\n\t\t\t\tmockRegisterModel := &MockGetModel{}\n\t\t\t\tmockRegisterModel.On(\"Do\", mock.Anything).Return(nil, errors.New(\"something failed\")).Once()\n\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusNotFound,\n\t\t\texpectedPayload: ``,\n\t\t},\n\t\t{\n\t\t\tdesc: \"requested registration does not exist\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/1/\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// set values into request (required by the mux)\n\t\t\t\treturn mux.SetURLVars(req, map[string]string{muxVarID: \"1\"})\n\t\t\t},\n\t\t\tinModelMock: func() *MockGetModel {\n\t\t\t\tmockRegisterModel := &MockGetModel{}\n\t\t\t\tmockRegisterModel.On(\"Do\", mock.Anything).Return(nil, errors.New(\"person not found\")).Once()\n\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusNotFound,\n\t\t\texpectedPayload: ``,\n\t\t},\n\t}\n\n\tfor _, s := range scenarios {\n\t\tscenario := s\n\t\tt.Run(scenario.desc, func(t *testing.T) {\n\t\t\t// define model layer mock\n\t\t\tmockGetModel := scenario.inModelMock()\n\n\t\t\t// build handler\n\t\t\thandler := NewGetHandler(&testConfig{}, mockGetModel)\n\n\t\t\t// perform request\n\t\t\tresponse := httptest.NewRecorder()\n\t\t\thandler.ServeHTTP(response, scenario.inRequest())\n\n\t\t\t// validate outputs\n\t\t\trequire.Equal(t, scenario.expectedStatus, response.Code, scenario.desc)\n\n\t\t\tpayload, _ := ioutil.ReadAll(response.Body)\n\t\t\tassert.Equal(t, scenario.expectedPayload, string(payload), scenario.desc)\n\t\t})\n\t}\n}\n\ntype testConfig struct {\n}\n\nfunc (t *testConfig) Logger() logging.Logger {\n\treturn &logging.LoggerStdOut{}\n}\n\nfunc (*testConfig) BindAddress() string {\n\treturn \"0.0.0.0:0\"\n}\n"
  },
  {
    "path": "ch08/acme/internal/rest/list.go",
    "content": "package rest\n\nimport (\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/modules/data\"\n)\n\n// ListModel will load all registrations\n//go:generate mockery -name=ListModel -case underscore -testonly -inpkg -note @generated\ntype ListModel interface {\n\tDo() ([]*data.Person, error)\n}\n\n// NewLister is the constructor for ListHandler\nfunc NewListHandler(model ListModel) *ListHandler {\n\treturn &ListHandler{\n\t\tlister: model,\n\t}\n}\n\n// ListHandler is the HTTP handler for the \"List Do people\" endpoint\n// In this simplified example we are assuming all possible errors are system errors (HTTP 500)\ntype ListHandler struct {\n\tlister ListModel\n}\n\n// ServeHTTP implements http.Handler\nfunc (h *ListHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\t// attempt loadAll\n\tpeople, err := h.lister.Do()\n\tif err != nil {\n\t\t// not need to log here as we can expect other layers to do so\n\t\tresponse.WriteHeader(http.StatusNotFound)\n\t\treturn\n\t}\n\n\t// happy path\n\terr = h.writeJSON(response, people)\n\tif err != nil {\n\t\t// this error should not happen but if it does there is nothing we can do to recover\n\t\tresponse.WriteHeader(http.StatusInternalServerError)\n\t}\n}\n\n// output the result as JSON\nfunc (h *ListHandler) writeJSON(writer io.Writer, people []*data.Person) error {\n\toutput := &listResponseFormat{\n\t\tPeople: make([]*listResponseItemFormat, len(people)),\n\t}\n\n\tfor index, record := range people {\n\t\toutput.People[index] = &listResponseItemFormat{\n\t\t\tID:       record.ID,\n\t\t\tFullName: record.FullName,\n\t\t\tPhone:    record.Phone,\n\t\t}\n\t}\n\n\t// call to http.ResponseWriter.Write() will cause HTTP OK (200) to be output as well\n\treturn json.NewEncoder(writer).Encode(output)\n}\n\ntype listResponseFormat struct {\n\tPeople []*listResponseItemFormat `json:\"people\"`\n}\n\ntype listResponseItemFormat struct {\n\tID       int    `json:\"id\"`\n\tFullName string `json:\"name\"`\n\tPhone    string `json:\"phone\"`\n}\n"
  },
  {
    "path": "ch08/acme/internal/rest/list_test.go",
    "content": "package rest\n\nimport (\n\t\"errors\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestListHandler_ServeHTTP(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc            string\n\t\tinRequest       func() *http.Request\n\t\tinModelMock     func() *MockListModel\n\t\texpectedStatus  int\n\t\texpectedPayload string\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/list\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn req\n\t\t\t},\n\t\t\tinModelMock: func() *MockListModel {\n\t\t\t\toutput := []*data.Person{\n\t\t\t\t\t{\n\t\t\t\t\t\tID:       1,\n\t\t\t\t\t\tFullName: \"John\",\n\t\t\t\t\t\tPhone:    \"0123456789\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tID:       2,\n\t\t\t\t\t\tFullName: \"Paul\",\n\t\t\t\t\t\tPhone:    \"0123456781\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tID:       3,\n\t\t\t\t\t\tFullName: \"George\",\n\t\t\t\t\t\tPhone:    \"0123456782\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tID:       1,\n\t\t\t\t\t\tFullName: \"Ringo\",\n\t\t\t\t\t\tPhone:    \"0123456783\",\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\tmockListModel := &MockListModel{}\n\t\t\t\tmockListModel.On(\"Do\", mock.Anything).Return(output, nil).Once()\n\n\t\t\t\treturn mockListModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusOK,\n\t\t\texpectedPayload: `{\"people\":[{\"id\":1,\"name\":\"John\",\"phone\":\"0123456789\"},{\"id\":2,\"name\":\"Paul\",\"phone\":\"0123456781\"},{\"id\":3,\"name\":\"George\",\"phone\":\"0123456782\"},{\"id\":1,\"name\":\"Ringo\",\"phone\":\"0123456783\"}]}` + \"\\n\",\n\t\t},\n\t\t{\n\t\t\tdesc: \"dependency failure\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/list\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn req\n\t\t\t},\n\t\t\tinModelMock: func() *MockListModel {\n\t\t\t\tmockListModel := &MockListModel{}\n\t\t\t\tmockListModel.On(\"Do\", mock.Anything).Return(nil, errors.New(\"something failed\")).Once()\n\n\t\t\t\treturn mockListModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusNotFound,\n\t\t\texpectedPayload: ``,\n\t\t},\n\t\t{\n\t\t\tdesc: \"no data\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/list\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn req\n\t\t\t},\n\t\t\tinModelMock: func() *MockListModel {\n\t\t\t\t// no data\n\t\t\t\toutput := []*data.Person{}\n\n\t\t\t\tmockListModel := &MockListModel{}\n\t\t\t\tmockListModel.On(\"Do\", mock.Anything).Return(output, nil).Once()\n\n\t\t\t\treturn mockListModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusOK,\n\t\t\texpectedPayload: `{\"people\":[]}` + \"\\n\",\n\t\t},\n\t}\n\n\tfor _, s := range scenarios {\n\t\tscenario := s\n\t\tt.Run(scenario.desc, func(t *testing.T) {\n\t\t\t// define model layer mock\n\t\t\tmockListModel := scenario.inModelMock()\n\n\t\t\t// build handler\n\t\t\thandler := NewListHandler(mockListModel)\n\n\t\t\t// perform request\n\t\t\tresponse := httptest.NewRecorder()\n\t\t\thandler.ServeHTTP(response, scenario.inRequest())\n\n\t\t\t// validate outputs\n\t\t\trequire.Equal(t, scenario.expectedStatus, response.Code, scenario.desc)\n\n\t\t\tpayload, _ := ioutil.ReadAll(response.Body)\n\t\t\tassert.Equal(t, scenario.expectedPayload, string(payload), scenario.desc)\n\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "ch08/acme/internal/rest/mock_get_model_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage rest\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// MockGetModel is an autogenerated mock type for the GetModel type\ntype MockGetModel struct {\n\tmock.Mock\n}\n\n// Do provides a mock function with given fields: ID\nfunc (_m *MockGetModel) Do(ID int) (*data.Person, error) {\n\tret := _m.Called(ID)\n\n\tvar r0 *data.Person\n\tif rf, ok := ret.Get(0).(func(int) *data.Person); ok {\n\t\tr0 = rf(ID)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*data.Person)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(int) error); ok {\n\t\tr1 = rf(ID)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch08/acme/internal/rest/mock_list_model_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage rest\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// MockListModel is an autogenerated mock type for the ListModel type\ntype MockListModel struct {\n\tmock.Mock\n}\n\n// Do provides a mock function with given fields:\nfunc (_m *MockListModel) Do() ([]*data.Person, error) {\n\tret := _m.Called()\n\n\tvar r0 []*data.Person\n\tif rf, ok := ret.Get(0).(func() []*data.Person); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]*data.Person)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func() error); ok {\n\t\tr1 = rf()\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch08/acme/internal/rest/mock_register_model_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage rest\n\nimport (\n\t\"context\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// MockRegisterModel is an autogenerated mock type for the RegisterModel type\ntype MockRegisterModel struct {\n\tmock.Mock\n}\n\n// Do provides a mock function with given fields: ctx, in\nfunc (_m *MockRegisterModel) Do(ctx context.Context, in *data.Person) (int, error) {\n\tret := _m.Called(ctx, in)\n\n\tvar r0 int\n\tif rf, ok := ret.Get(0).(func(context.Context, *data.Person) int); ok {\n\t\tr0 = rf(ctx, in)\n\t} else {\n\t\tr0 = ret.Get(0).(int)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, *data.Person) error); ok {\n\t\tr1 = rf(ctx, in)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch08/acme/internal/rest/not_found.go",
    "content": "package rest\n\nimport (\n\t\"net/http\"\n)\n\nfunc notFoundHandler(response http.ResponseWriter, _ *http.Request) {\n\tresponse.WriteHeader(http.StatusNotFound)\n\t_, _ = response.Write([]byte(`Not found`))\n}\n"
  },
  {
    "path": "ch08/acme/internal/rest/not_found_test.go",
    "content": "package rest\n\nimport (\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestNotFoundHandler_ServeHTTP(t *testing.T) {\n\t// build inputs\n\tresponse := httptest.NewRecorder()\n\trequest := &http.Request{}\n\n\t// call handler\n\tnotFoundHandler(response, request)\n\n\t// validate outputs\n\trequire.Equal(t, http.StatusNotFound, response.Code)\n}\n"
  },
  {
    "path": "ch08/acme/internal/rest/register.go",
    "content": "package rest\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/modules/data\"\n)\n\n// RegisterModel will validate and save a registration\n//go:generate mockery -name=RegisterModel -case underscore -testonly -inpkg -note @generated\ntype RegisterModel interface {\n\tDo(ctx context.Context, in *data.Person) (int, error)\n}\n\n// NewRegisterHandler is the constructor for RegisterHandler\nfunc NewRegisterHandler(model RegisterModel) *RegisterHandler {\n\treturn &RegisterHandler{\n\t\tregisterer: model,\n\t}\n}\n\n// RegisterHandler is the HTTP handler for the \"Register\" endpoint\n// In this simplified example we are assuming all possible errors are user errors and returning \"bad request\" HTTP 400.\n// There are some programmer errors possible but hopefully these will be caught in testing.\ntype RegisterHandler struct {\n\tregisterer RegisterModel\n}\n\n// ServeHTTP implements http.Handler\nfunc (h *RegisterHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\t// set latency budget for this API\n\tsubCtx, cancel := context.WithTimeout(request.Context(), 1500*time.Millisecond)\n\tdefer cancel()\n\n\t// extract payload from request\n\trequestPayload, err := h.extractPayload(request)\n\tif err != nil {\n\t\t// output error\n\t\tresponse.WriteHeader(http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// call the business logic using the request data and context\n\tid, err := h.register(subCtx, requestPayload)\n\tif err != nil {\n\t\t// not need to log here as we can expect other layers to do so\n\t\tresponse.WriteHeader(http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// happy path\n\tresponse.Header().Add(\"Location\", fmt.Sprintf(\"/person/%d/\", id))\n\tresponse.WriteHeader(http.StatusCreated)\n}\n\n// extract payload from request\nfunc (h *RegisterHandler) extractPayload(request *http.Request) (*registerRequest, error) {\n\trequestPayload := &registerRequest{}\n\n\tdecoder := json.NewDecoder(request.Body)\n\terr := decoder.Decode(requestPayload)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn requestPayload, nil\n}\n\n// call the logic layer\nfunc (h *RegisterHandler) register(ctx context.Context, requestPayload *registerRequest) (int, error) {\n\tperson := &data.Person{\n\t\tFullName: requestPayload.FullName,\n\t\tPhone:    requestPayload.Phone,\n\t\tCurrency: requestPayload.Currency,\n\t}\n\n\treturn h.registerer.Do(ctx, person)\n}\n\n// register endpoint request format\ntype registerRequest struct {\n\t// FullName of the person\n\tFullName string `json:\"fullName\"`\n\t// Phone of the person\n\tPhone string `json:\"phone\"`\n\t// Currency the wish to register in\n\tCurrency string `json:\"currency\"`\n}\n"
  },
  {
    "path": "ch08/acme/internal/rest/register_test.go",
    "content": "package rest\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestRegisterHandler_ServeHTTP(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc           string\n\t\tinRequest      func() *http.Request\n\t\tinModelMock    func() *MockRegisterModel\n\t\texpectedStatus int\n\t\texpectedHeader string\n\t}{\n\t\t{\n\t\t\tdesc: \"Happy Path\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\tvalidRequest := buildValidRegisterRequest()\n\t\t\t\trequest, err := http.NewRequest(\"POST\", \"/person/register\", validRequest)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn request\n\t\t\t},\n\t\t\tinModelMock: func() *MockRegisterModel {\n\t\t\t\t// valid downstream configuration\n\t\t\t\tresultID := 1234\n\t\t\t\tvar resultErr error\n\n\t\t\t\tmockRegisterModel := &MockRegisterModel{}\n\t\t\t\tmockRegisterModel.On(\"Do\", mock.Anything, mock.Anything).Return(resultID, resultErr).Once()\n\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus: http.StatusCreated,\n\t\t\texpectedHeader: \"/person/1234/\",\n\t\t},\n\t\t{\n\t\t\tdesc: \"Bad Input / User Error\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\tinvalidRequest := bytes.NewBufferString(`this is not valid JSON`)\n\t\t\t\trequest, err := http.NewRequest(\"POST\", \"/person/register\", invalidRequest)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn request\n\t\t\t},\n\t\t\tinModelMock: func() *MockRegisterModel {\n\t\t\t\t// Dependency should not be called\n\t\t\t\tmockRegisterModel := &MockRegisterModel{}\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus: http.StatusBadRequest,\n\t\t\texpectedHeader: \"\",\n\t\t},\n\t\t{\n\t\t\tdesc: \"Dependency Failure\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\tvalidRequest := buildValidRegisterRequest()\n\t\t\t\trequest, err := http.NewRequest(\"POST\", \"/person/register\", validRequest)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn request\n\t\t\t},\n\t\t\tinModelMock: func() *MockRegisterModel {\n\t\t\t\t// call to the dependency failed\n\t\t\t\tresultErr := errors.New(\"something failed\")\n\n\t\t\t\tmockRegisterModel := &MockRegisterModel{}\n\t\t\t\tmockRegisterModel.On(\"Do\", mock.Anything, mock.Anything).Return(0, resultErr).Once()\n\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus: http.StatusBadRequest,\n\t\t\texpectedHeader: \"\",\n\t\t},\n\t}\n\n\tfor _, s := range scenarios {\n\t\tscenario := s\n\t\tt.Run(scenario.desc, func(t *testing.T) {\n\t\t\t// define model layer mock\n\t\t\tmockRegisterModel := scenario.inModelMock()\n\n\t\t\t// build handler\n\t\t\thandler := NewRegisterHandler(mockRegisterModel)\n\n\t\t\t// perform request\n\t\t\tresponse := httptest.NewRecorder()\n\t\t\thandler.ServeHTTP(response, scenario.inRequest())\n\n\t\t\t// validate outputs\n\t\t\trequire.Equal(t, scenario.expectedStatus, response.Code)\n\n\t\t\t// call should output the location to the new person\n\t\t\tresultHeader := response.Header().Get(\"Location\")\n\t\t\tassert.Equal(t, scenario.expectedHeader, resultHeader)\n\n\t\t\t// validate the mock was used as we expected\n\t\t\tassert.True(t, mockRegisterModel.AssertExpectations(t))\n\t\t})\n\t}\n}\n\nfunc buildValidRegisterRequest() io.Reader {\n\trequestData := &registerRequest{\n\t\tFullName: \"Joan Smith\",\n\t\tCurrency: \"AUD\",\n\t\tPhone:    \"01234567890\",\n\t}\n\n\tdata, _ := json.Marshal(requestData)\n\treturn bytes.NewBuffer(data)\n}\n"
  },
  {
    "path": "ch08/acme/internal/rest/server.go",
    "content": "package rest\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/logging\"\n\t\"github.com/gorilla/mux\"\n)\n\n// Config is the config for the REST package\ntype Config interface {\n\tLogger() logging.Logger\n\tBindAddress() string\n}\n\n// New will create and initialize the server\nfunc New(cfg Config,\n\tgetModel GetModel,\n\tlistModel ListModel,\n\tregisterModel RegisterModel) *Server {\n\n\treturn &Server{\n\t\taddress:         cfg.BindAddress(),\n\t\thandlerGet:      NewGetHandler(cfg, getModel),\n\t\thandlerList:     NewListHandler(listModel),\n\t\thandlerNotFound: notFoundHandler,\n\t\thandlerRegister: NewRegisterHandler(registerModel),\n\t}\n}\n\n// Server is the HTTP REST server\ntype Server struct {\n\taddress string\n\tserver  *http.Server\n\n\thandlerGet      http.Handler\n\thandlerList     http.Handler\n\thandlerNotFound http.HandlerFunc\n\thandlerRegister http.Handler\n}\n\n// Listen will start a HTTP rest for this service\nfunc (s *Server) Listen(stop <-chan struct{}) {\n\trouter := s.buildRouter()\n\n\t// create the HTTP server\n\ts.server = &http.Server{\n\t\tHandler: router,\n\t\tAddr:    s.address,\n\t}\n\n\t// listen for shutdown\n\tgo func() {\n\t\t// wait for shutdown signal\n\t\t<-stop\n\n\t\t_ = s.server.Close()\n\t}()\n\n\t// start the HTTP server\n\t_ = s.server.ListenAndServe()\n}\n\n// configure the endpoints to handlers\nfunc (s *Server) buildRouter() http.Handler {\n\trouter := mux.NewRouter()\n\n\t// map URL endpoints to HTTP handlers\n\trouter.Handle(\"/person/{id}/\", s.handlerGet).Methods(\"GET\")\n\trouter.Handle(\"/person/list\", s.handlerList).Methods(\"GET\")\n\trouter.Handle(\"/person/register\", s.handlerRegister).Methods(\"POST\")\n\n\t// convert a \"catch all\" not found handler\n\trouter.NotFoundHandler = s.handlerNotFound\n\n\treturn router\n}\n"
  },
  {
    "path": "ch08/acme/main.go",
    "content": "package main\n\nimport (\n\t\"context\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/config\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/modules/exchange\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/modules/get\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/modules/list\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/modules/register\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/acme/internal/rest\"\n)\n\nfunc main() {\n\t// bind stop channel to context\n\tctx := context.Background()\n\n\t// build the exchanger\n\texchanger := exchange.NewConverter(config.App)\n\n\t// build model layer\n\tgetModel := get.NewGetter(config.App)\n\tlistModel := list.NewLister(config.App)\n\tregisterModel := register.NewRegisterer(config.App, exchanger)\n\n\t// start REST server\n\tserver := rest.New(config.App, getModel, listModel, registerModel)\n\tserver.Listen(ctx.Done())\n}\n"
  },
  {
    "path": "ch08/fake.go",
    "content": "package ch08\n\nfunc init() {\n\t// This file is included so that Go tools (like `go list`) will find Go code in this directory and not error\n}\n"
  },
  {
    "path": "ch09/01_jit_injection/01_injecting_db.go",
    "content": "package jit_injection\n\nfunc NewMyLoadPersonLogic(ds DataSource) *MyLoadPersonLogic {\n\treturn &MyLoadPersonLogic{\n\t\tdataSource: ds,\n\t}\n}\n\ntype MyLoadPersonLogic struct {\n\tdataSource DataSource\n}\n\n// Load person by supplied ID\nfunc (m *MyLoadPersonLogic) Load(ID int) (Person, error) {\n\treturn m.dataSource.Load(ID)\n}\n\ntype DataSource interface {\n\t// Load person by ID\n\tLoad(ID int) (Person, error)\n}\n\ntype Person struct {\n\tName string\n}\n"
  },
  {
    "path": "ch09/01_jit_injection/01_injecting_db_test.go",
    "content": "package jit_injection\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestMyLoadPersonLogic(t *testing.T) {\n\t// setup the mock db\n\tmockDB := &mockDB{\n\t\tout: Person{Name: \"Fred\"},\n\t}\n\n\t// call the object we are testing\n\ttestObj := NewMyLoadPersonLogic(mockDB)\n\tresult, resultErr := testObj.Load(123)\n\n\t// validate expectations\n\tassert.Equal(t, Person{Name: \"Fred\"}, result)\n\tassert.Nil(t, resultErr)\n}\n\n// mock implementation of DataSource\ntype mockDB struct {\n\tout    Person\n\toutErr error\n}\n\n// Load implements DataSource\nfunc (m *mockDB) Load(ID int) (Person, error) {\n\treturn m.out, m.outErr\n}\n"
  },
  {
    "path": "ch09/01_jit_injection/02_injecting_business_logic.go",
    "content": "package jit_injection\n\nimport (\n\t\"errors\"\n\t\"net/http\"\n)\n\nfunc NewLoadPersonHandler(logic LoadPersonLogic) *LoadPersonHandler {\n\treturn &LoadPersonHandler{\n\t\tbusinessLogic: logic,\n\t}\n}\n\ntype LoadPersonHandler struct {\n\tbusinessLogic LoadPersonLogic\n}\n\nfunc (h *LoadPersonHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\trequestedID, err := h.extractInputFromRequest(request)\n\n\toutput, err := h.businessLogic.Load(requestedID)\n\tif err != nil {\n\t\tresponse.WriteHeader(http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\th.writeOutput(response, output)\n}\n\n// extract the person ID from the request\nfunc (h *LoadPersonHandler) extractInputFromRequest(request *http.Request) (int, error) {\n\treturn 0, errors.New(\"not implemented yet\")\n}\n\n// convert person to JSON and write to the HTTP response\nfunc (h *LoadPersonHandler) writeOutput(writer http.ResponseWriter, person Person) {\n\t// not implemented yet\n}\n\ntype LoadPersonLogic interface {\n\t// Load person by supplied ID\n\tLoad(ID int) (Person, error)\n}\n"
  },
  {
    "path": "ch09/01_jit_injection/03_injecting_db_jit.go",
    "content": "package jit_injection\n\nimport (\n\t\"errors\"\n)\n\ntype MyLoadPersonLogicJIT struct {\n\tdataSource DataSourceJIT\n}\n\n// Load person by supplied ID\nfunc (m *MyLoadPersonLogicJIT) Load(ID int) (Person, error) {\n\treturn m.getDataSource().Load(ID)\n}\n\nfunc (m *MyLoadPersonLogicJIT) getDataSource() DataSourceJIT {\n\tif m.dataSource == nil {\n\t\tm.dataSource = NewMyDataSourceJIT()\n\t}\n\n\treturn m.dataSource\n}\n\ntype DataSourceJIT interface {\n\t// Load person by ID\n\tLoad(ID int) (Person, error)\n}\n\nfunc NewMyDataSourceJIT() *MyDataSourceJIT {\n\treturn &MyDataSourceJIT{}\n}\n\n// Default implementation of DataSourceJIT\ntype MyDataSourceJIT struct {\n}\n\nfunc (m *MyDataSourceJIT) Load(ID int) (Person, error) {\n\treturn Person{}, errors.New(\"not implemented yet\")\n}\n"
  },
  {
    "path": "ch09/01_jit_injection/03_injecting_db_jit_test.go",
    "content": "package jit_injection\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestMyLoadPersonLogicJIT(t *testing.T) {\n\t// setup the mock db\n\tmockDB := &mockDB{\n\t\tout: Person{Name: \"Fred\"},\n\t}\n\n\t// call the object we are testing\n\ttestObj := MyLoadPersonLogicJIT{\n\t\tdataSource: mockDB,\n\t}\n\tresult, resultErr := testObj.Load(123)\n\n\t// validate expectations\n\tassert.Equal(t, Person{Name: \"Fred\"}, result)\n\tassert.Nil(t, resultErr)\n}\n"
  },
  {
    "path": "ch09/01_jit_injection/04_noop_debugger.go",
    "content": "package jit_injection\n\nimport (\n\t\"errors\"\n)\n\ntype ObjectWithDebugger struct {\n\tDebugger Debugger\n}\n\nfunc (o *ObjectWithDebugger) DoSomethingAmazing(input int) error {\n\to.getDebugger().Log(\"input was: %d\", input)\n\n\terr := o.doSomething()\n\n\to.getDebugger().Log(\"result was: %v\", err)\n\treturn err\n}\n\nfunc (o *ObjectWithDebugger) getDebugger() Debugger {\n\tif o.Debugger == nil {\n\t\to.Debugger = &noopDebugger{}\n\t}\n\n\treturn o.Debugger\n}\n\nfunc (o *ObjectWithDebugger) doSomething() error {\n\treturn errors.New(\"not implemented yet\")\n}\n\ntype Debugger interface {\n\tLog(msg string, args ...interface{})\n}\n\n// NO-OP implementation of the Debugger interface\ntype noopDebugger struct {\n\t// intentionally left blank\n}\n\n// Log implements Debugger\nfunc (n *noopDebugger) Log(_ string, args ...interface{}) {\n\t// intentionally does nothing\n}\n"
  },
  {
    "path": "ch09/02_advantages/01_long_constructor.go",
    "content": "package advantages\n\nimport (\n\t\"io\"\n)\n\nfunc NewGenerator(storage Storage, renderer Renderer, template io.Reader) *Generator {\n\treturn &Generator{\n\t\tstorage:  storage,\n\t\trenderer: renderer,\n\t\ttemplate: template,\n\t}\n}\n\ntype Generator struct {\n\tstorage  Storage\n\trenderer Renderer\n\ttemplate io.Reader\n}\n\nfunc (g *Generator) Generate(destination io.Writer, params ...interface{}) {\n\n}\n\ntype Storage interface {\n\tLoad() []interface{}\n}\n\ntype Renderer interface {\n\tRender(template io.Reader, params ...interface{}) []byte\n}\n"
  },
  {
    "path": "ch09/02_advantages/02_short_constructor.go",
    "content": "package advantages\n\nimport (\n\t\"io\"\n)\n\nfunc NewGeneratorV2(template io.Reader) *Generator {\n\treturn &Generator{\n\t\ttemplate: template,\n\t}\n}\n\nfunc (g *Generator) getStorage() Storage {\n\tif g.storage == nil {\n\t\tg.storage = &DefaultStorage{}\n\t}\n\treturn g.storage\n}\n\nfunc (g *Generator) getRenderer() Renderer {\n\tif g.renderer == nil {\n\t\tg.renderer = &DefaultRenderer{}\n\t}\n\treturn g.renderer\n}\n\n// Default implementation of Storage\ntype DefaultStorage struct{}\n\n// Load implements Storage\nfunc (d *DefaultStorage) Load() []interface{} {\n\treturn nil\n}\n\n// Default implementation of Storage\ntype DefaultRenderer struct{}\n\n// Load implements Renderer\nfunc (d *DefaultRenderer) Render(template io.Reader, params ...interface{}) []byte {\n\treturn nil\n}\n"
  },
  {
    "path": "ch09/02_advantages/03_optional_dep_without_jitdi.go",
    "content": "package advantages\n\nfunc NewLoaderWithoutJIT(ds Datastore) *LoaderWithoutJIT {\n\treturn &LoaderWithoutJIT{\n\t\tdatastore: ds,\n\t}\n}\n\ntype LoaderWithoutJIT struct {\n\t// required private dependency\n\tdatastore Datastore\n\n\t// optional cache\n\tOptionalCache Cache\n}\n\nfunc (l *LoaderWithoutJIT) Load(ID int) (*Animal, error) {\n\tvar output *Animal\n\tvar err error\n\n\t// attempt to load from cache\n\tif l.OptionalCache != nil {\n\t\toutput = l.OptionalCache.Get(ID)\n\t\tif output != nil {\n\t\t\t// return cached value\n\t\t\treturn output, nil\n\t\t}\n\t}\n\n\t// load from data store\n\toutput, err = l.datastore.Load(ID)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// cache the loaded value\n\tif l.OptionalCache != nil {\n\t\tl.OptionalCache.Put(ID, output)\n\t}\n\n\t// output the result\n\treturn output, nil\n}\n\ntype Cache interface {\n\tGet(ID int) *Animal\n\tPut(ID int, value *Animal)\n}\n\ntype Datastore interface {\n\tLoad(ID int) (*Animal, error)\n\tSave(ID int, value *Animal) error\n}\n\ntype Animal struct {\n\t// some data fields go here\n}\n"
  },
  {
    "path": "ch09/02_advantages/04_optional_dep_with_jitdi.go",
    "content": "package advantages\n\nfunc NewLoaderWithJIT(ds Datastore) *LoaderWithJIT {\n\treturn &LoaderWithJIT{\n\t\tdatastore: ds,\n\t}\n}\n\ntype LoaderWithJIT struct {\n\t// required private dependency\n\tdatastore Datastore\n\n\t// optional cache\n\tOptionalCache Cache\n}\n\nfunc (l *LoaderWithJIT) Load(ID int) (*Animal, error) {\n\t// attempt to load from cache\n\toutput := l.cache().Get(ID)\n\tif output != nil {\n\t\t// return cached value\n\t\treturn output, nil\n\t}\n\n\t// load from data store\n\toutput, err := l.datastore.Load(ID)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// cache the loaded value\n\tl.cache().Put(ID, output)\n\n\t// output the result\n\treturn output, nil\n}\n\nfunc (l *LoaderWithJIT) cache() Cache {\n\tif l.OptionalCache == nil {\n\t\tl.OptionalCache = &noopCache{}\n\t}\n\n\treturn l.OptionalCache\n}\n\n// NO-OP implementation of the cache\ntype noopCache struct {\n\t// intentionally blank\n}\n\nfunc (n *noopCache) Get(ID int) *Animal {\n\t// intentionally does nothing\n\treturn nil\n}\n\nfunc (n *noopCache) Put(ID int, value *Animal) {\n\t// intentionally does nothing\n}\n"
  },
  {
    "path": "ch09/02_advantages/05_loader.go",
    "content": "package advantages\n\nimport (\n\t\"errors\"\n)\n\nfunc NewLoader(ds Datastore, cache Cache) *MyLoader {\n\treturn &MyLoader{\n\t\tds:    ds,\n\t\tcache: cache,\n\t}\n}\n\ntype MyLoader struct {\n\tds    Datastore\n\tcache Cache\n}\n\nfunc (l *MyLoader) LoadAll() ([]interface{}, error) {\n\treturn nil, errors.New(\"not implemented\")\n}\n"
  },
  {
    "path": "ch09/02_advantages/06_global_variable/06_global_variable.go",
    "content": "package global_variable\n\n// Global singleton of connections to our data store\nvar storage UserStorage\n\ntype Saver struct {\n}\n\nfunc (s *Saver) Do(in *User) error {\n\terr := s.validate(in)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn storage.Save(in)\n}\n\nfunc (s *Saver) validate(in *User) error {\n\t// validate user and return error when there is a problem\n\treturn nil\n}\n\ntype UserStorage interface {\n\tSave(in *User) error\n}\n\ntype User struct {\n\tName     string\n\tPassword string\n}\n"
  },
  {
    "path": "ch09/02_advantages/07_global_variable_jit/07_global_variable_jit.go",
    "content": "package global_variable_jit\n\n// Global singleton of connections to our data store\nvar storage UserStorage\n\ntype Saver struct {\n\tstorage UserStorage\n}\n\nfunc (s *Saver) Do(in *User) error {\n\terr := s.validate(in)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn s.getStorage().Save(in)\n}\n\n// Just-in-time DI\nfunc (s *Saver) getStorage() UserStorage {\n\tif s.storage == nil {\n\t\ts.storage = storage\n\t}\n\n\treturn s.storage\n}\n\nfunc (s *Saver) validate(in *User) error {\n\t// validate user and return error when there is a problem\n\treturn nil\n}\n\ntype UserStorage interface {\n\tSave(in *User) error\n}\n\ntype User struct {\n\tName     string\n\tPassword string\n}\n"
  },
  {
    "path": "ch09/02_advantages/07_global_variable_jit/07_global_variable_jit_test.go",
    "content": "package global_variable_jit\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestSaver_Do(t *testing.T) {\n\t// input\n\tcarol := &User{\n\t\tName:     \"Carol\",\n\t\tPassword: \"IamKing\",\n\t}\n\n\t// mocks/stubs\n\tstubStorage := &StubUserStorage{}\n\n\t// do call\n\tsaver := &Saver{\n\t\tstorage: stubStorage,\n\t}\n\tresultErr := saver.Do(carol)\n\n\t// validate\n\tassert.NotEqual(t, resultErr, \"unexpected error\")\n}\n\n// Stub implementation of UserStorage\ntype StubUserStorage struct{}\n\nfunc (s *StubUserStorage) Save(_ *User) error {\n\t// return \"happy path\"\n\treturn nil\n}\n"
  },
  {
    "path": "ch09/02_advantages/08_car_v1.go",
    "content": "package advantages\n\ntype CarV1 struct {\n\tengine Engine\n}\n\nfunc (c *CarV1) Drive() {\n\tc.engine.Start()\n\tdefer c.engine.Stop()\n\n\tc.engine.Drive()\n}\n\ntype Engine interface {\n\tStart()\n\tDrive()\n\tStop()\n}\n"
  },
  {
    "path": "ch09/02_advantages/09_car_v2.go",
    "content": "package advantages\n\ntype CarV2 struct {\n\tengine Engine\n}\n\nfunc (c *CarV2) Drive() {\n\tengine := c.getEngine()\n\n\tengine.Start()\n\tdefer engine.Stop()\n\n\tengine.Drive()\n}\n\nfunc (c *CarV2) getEngine() Engine {\n\tif c.engine == nil {\n\t\tc.engine = newEngine()\n\t}\n\n\treturn c.engine\n}\n\nfunc newEngine() Engine {\n\t// not implemented\n\treturn nil\n}\n"
  },
  {
    "path": "ch09/03_applying/01_commands.sh",
    "content": "#!/usr/bin/env bash\n\ncd $GOPATH/src/github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch08/\n\npackage-coverage -a -prefix $(go list)/ ./acme/\n"
  },
  {
    "path": "ch09/03_applying/02_coverage.txt",
    "content": "-------------------------------------------------------------------------\n|      Branch     |       Dir       |                                   |\n|   Cov% |  Stmts |   Cov% |  Stmts | Package                           |\n-------------------------------------------------------------------------\n|  65.66 |    265 |   0.00 |      7 | acme/                             |\n|  47.83 |     23 |  47.83 |     23 | acme/internal/config/             |\n|   0.00 |      4 |   0.00 |      4 | acme/internal/logging/            |\n|  73.77 |     61 |  73.77 |     61 | acme/internal/modules/data/       |\n|  61.70 |     47 |  61.70 |     47 | acme/internal/modules/exchange/   |\n|  85.71 |      7 |  85.71 |      7 | acme/internal/modules/get/        |\n|  46.15 |     13 |  46.15 |     13 | acme/internal/modules/list/       |\n|  62.07 |     29 |  62.07 |     29 | acme/internal/modules/register/   |\n|  79.73 |     74 |  79.73 |     74 | acme/internal/rest/               |\n-------------------------------------------------------------------------\n"
  },
  {
    "path": "ch09/03_applying/03_initial_dao.go",
    "content": "//+build willNotCompile\n\npackage applying\n\nimport (\n\t\"context\"\n)\n\n// NewDAO will initialize the database connection pool (if not already done) and return a data access object which\n// can be used to interact with the database\nfunc NewDAO(cfg Config) *DAO {\n\t// initialize the db connection pool\n\t_, _ = getDB(cfg)\n\n\treturn &DAO{\n\t\tcfg: cfg,\n\t}\n}\n\n// DAO is a data access object that provides an abstraction over our database interactions.\ntype DAO struct {\n\tcfg Config\n}\n\n// Load will attempt to load and return a person.\n// It will return ErrNotFound when the requested person does not exist.\n// Any other errors returned are caused by the underlying database or our connection to it.\nfunc (d *DAO) Load(ctx context.Context, ID int) (*Person, error) {\n\treturn Load(ctx, d.cfg, ID)\n}\n"
  },
  {
    "path": "ch09/04_disadvantages/01_uncertain_init_state.go",
    "content": "package disadvantages\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"net\"\n\t\"sync\"\n)\n\ntype ConnectionPool interface {\n\tIsReady() <-chan struct{}\n\tGet() net.Conn\n\tRelease(conn net.Conn)\n}\n\ntype Sender struct {\n\tconnectionPool ConnectionPool\n\n\tinitPoolOnce sync.Once\n}\n\nfunc (l *Sender) Send(ctx context.Context, payload []byte) error {\n\tpool := l.getConnectionPool()\n\n\t// ensure pool is ready\n\tselect {\n\tcase <-pool.IsReady():\n\t\t// happy path\n\n\tcase <-ctx.Done():\n\t\t// context timed out or was cancelled\n\t\treturn errors.New(\"failed to get connection\")\n\t}\n\n\t// get connection from pool and return afterwards\n\tconn := pool.Get()\n\tdefer l.connectionPool.Release(conn)\n\n\t// send and return\n\t_, err := conn.Write(payload)\n\n\treturn err\n}\n\nfunc (l *Sender) getConnectionPool() ConnectionPool {\n\t// Inject the connection pool with JIT DI\n\tif l.connectionPool == nil {\n\t\tmyPool := &myConnectionPool{}\n\t\tgo myPool.init()\n\n\t\tl.connectionPool = myPool\n\t}\n\n\treturn l.connectionPool\n}\n\n// default implementation of the connection pool\ntype myConnectionPool struct {\n}\n\n// IsReady implements ConnectionPool\nfunc (m *myConnectionPool) IsReady() <-chan struct{} {\n\t// not implemented yet\n\treturn make(chan struct{})\n}\n\n// IsReady implements ConnectionPool\nfunc (m *myConnectionPool) Get() net.Conn {\n\t// not implemented yet\n\treturn nil\n}\n\n// IsReady implements ConnectionPool\nfunc (m *myConnectionPool) Release(_ net.Conn) {\n\t// not implemented yet\n}\n\nfunc (m *myConnectionPool) init() {\n\t// create connection and populate the pool\n}\n"
  },
  {
    "path": "ch09/04_disadvantages/02_certain_init_state.go",
    "content": "package disadvantages\n\nfunc (l *Sender) SendWithoutReadyCheck(payload []byte) error {\n\tpool := l.getConnectionPool()\n\n\t// get connection from pool and return afterwards\n\tconn := pool.Get()\n\tdefer l.connectionPool.Release(conn)\n\n\t// send and return\n\t_, err := conn.Write(payload)\n\n\treturn err\n}\n"
  },
  {
    "path": "ch09/04_disadvantages/03_cpool_slow_constructor.go",
    "content": "package disadvantages\n\nfunc newConnectionPool() ConnectionPool {\n\tpool := &myConnectionPool{}\n\n\t// initialize the pool\n\tpool.init()\n\n\t// return a \"ready to use pool\"\n\treturn pool\n}\n"
  },
  {
    "path": "ch09/04_disadvantages/04_get_pool_with_once.go",
    "content": "package disadvantages\n\nfunc (l *Sender) getConnectionPoolOnce() ConnectionPool {\n\tl.initPoolOnce.Do(func() {\n\t\tl.connectionPool = newConnectionPool()\n\t})\n\n\treturn l.connectionPool\n}\n"
  },
  {
    "path": "ch09/acme/internal/config/config.go",
    "content": "package config\n\nimport (\n\t\"encoding/json\"\n\t\"io/ioutil\"\n\t\"os\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/logging\"\n)\n\n// DefaultEnvVar is the default environment variable the points to the config file\nconst DefaultEnvVar = \"ACME_CONFIG\"\n\n// App is the application config\nvar App *Config\n\n// Config defines the JSON format for the config file\ntype Config struct {\n\t// DSN is the data source name (format: https://github.com/go-sql-driver/mysql/#dsn-data-source-name)\n\tDSN string\n\n\t// Address is the IP address and port to bind this rest to\n\tAddress string\n\n\t// BasePrice is the price of registration\n\tBasePrice float64\n\n\t// ExchangeRateBaseURL is the server and protocol part of the URL from which to load the exchange rate\n\tExchangeRateBaseURL string\n\n\t// ExchangeRateAPIKey is the API for the exchange rate API\n\tExchangeRateAPIKey string\n\n\t// environmental dependencies\n\tlogger logging.Logger\n}\n\n// Logger returns a reference to the singleton logger\nfunc (c *Config) Logger() logging.Logger {\n\tif c.logger == nil {\n\t\tc.logger = &logging.LoggerStdOut{}\n\t}\n\n\treturn c.logger\n}\n\n// RegistrationBasePrice returns the base price for registrations\nfunc (c *Config) RegistrationBasePrice() float64 {\n\treturn c.BasePrice\n}\n\n// DataDSN returns the DSN\nfunc (c *Config) DataDSN() string {\n\treturn c.DSN\n}\n\n// ExchangeBaseURL returns the Base URL from which we can load exchange rates\nfunc (c *Config) ExchangeBaseURL() string {\n\treturn c.ExchangeRateBaseURL\n}\n\n// ExchangeAPIKey returns the DSN\nfunc (c *Config) ExchangeAPIKey() string {\n\treturn c.ExchangeRateAPIKey\n}\n\n// BindAddress returns the host and port this service should bind to\nfunc (c *Config) BindAddress() string {\n\treturn c.Address\n}\n\n// Load returns the config loaded from environment\nfunc init() {\n\tfilename, found := os.LookupEnv(DefaultEnvVar)\n\tif !found {\n\t\tlogging.L.Error(\"failed to locate file specified by %s\", DefaultEnvVar)\n\t\treturn\n\t}\n\n\t_ = load(filename)\n}\n\nfunc load(filename string) error {\n\tApp = &Config{}\n\tbytes, err := ioutil.ReadFile(filename)\n\tif err != nil {\n\t\tlogging.L.Error(\"failed to read config file. err: %s\", err)\n\t\treturn err\n\t}\n\n\terr = json.Unmarshal(bytes, App)\n\tif err != nil {\n\t\tlogging.L.Error(\"failed to parse config file. err : %s\", err)\n\t\treturn err\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "ch09/acme/internal/config/config_test.go",
    "content": "package config\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestLoad(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc           string\n\t\tin             string\n\t\texpectedConfig *Config\n\t\texpectError    bool\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tin:   \"../../../../default-config.json\",\n\t\t\texpectedConfig: &Config{\n\t\t\t\tDSN:                 \"[insert your db config here]\",\n\t\t\t\tAddress:             \"0.0.0.0:8080\",\n\t\t\t\tBasePrice:           100.00,\n\t\t\t\tExchangeRateBaseURL: \"http://apilayer.net\",\n\t\t\t\tExchangeRateAPIKey:  \"[insert your API key here]\",\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tdesc:           \"invalid path\",\n\t\t\tin:             \"invalid.json\",\n\t\t\texpectedConfig: &Config{},\n\t\t\texpectError:    true,\n\t\t},\n\t}\n\n\tfor _, s := range scenarios {\n\t\tscenario := s\n\t\tt.Run(scenario.desc, func(t *testing.T) {\n\t\t\tresultErr := load(scenario.in)\n\t\t\trequire.Equal(t, scenario.expectError, resultErr != nil, \"err: %s\", resultErr)\n\t\t\tassert.Equal(t, scenario.expectedConfig, App, scenario.desc)\n\t\t})\n\t}\n\n}\n"
  },
  {
    "path": "ch09/acme/internal/logging/logging.go",
    "content": "package logging\n\nimport (\n\t\"fmt\"\n)\n\n// Logger is our standard interface\ntype Logger interface {\n\tDebug(message string, args ...interface{})\n\tInfo(message string, args ...interface{})\n\tWarn(message string, args ...interface{})\n\tError(message string, args ...interface{})\n}\n\n// L is the global instance of the logger\nvar L = &LoggerStdOut{}\n\n// LoggerStdOut logs to std out\ntype LoggerStdOut struct{}\n\n// Debug logs messages at DEBUG level\nfunc (l LoggerStdOut) Debug(message string, args ...interface{}) {\n\tfmt.Printf(\"[DEBUG] \"+message, args...)\n}\n\n// Info logs messages at INFO level\nfunc (l LoggerStdOut) Info(message string, args ...interface{}) {\n\tfmt.Printf(\"[INFO] \"+message, args...)\n}\n\n// Warn logs messages at WARN level\nfunc (l LoggerStdOut) Warn(message string, args ...interface{}) {\n\tfmt.Printf(\"[WARN] \"+message, args...)\n}\n\n// Error logs messages at ERROR level\nfunc (l LoggerStdOut) Error(message string, args ...interface{}) {\n\tfmt.Printf(\"[ERROR] \"+message, args...)\n}\n"
  },
  {
    "path": "ch09/acme/internal/modules/data/dao.go",
    "content": "package data\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"time\"\n)\n\n// NewDAO will initialize the database connection pool (if not already done) and return a data access object which\n// can be used to interact with the database\nfunc NewDAO(cfg Config) *DAO {\n\t// initialize the db connection pool\n\t_, _ = getDB(cfg)\n\n\treturn &DAO{\n\t\tcfg: cfg,\n\t}\n}\n\n// DAO is a data access object that provides an abstraction over our database interactions.\ntype DAO struct {\n\tcfg Config\n\n\t// Tracker is an optional query timer\n\tTracker QueryTracker\n}\n\n// Load will attempt to load and return a person.\n// It will return ErrNotFound when the requested person does not exist.\n// Any other errors returned are caused by the underlying database or our connection to it.\nfunc (d *DAO) Load(ctx context.Context, ID int) (*Person, error) {\n\t// track processing time\n\tdefer d.getTracker().Track(\"Load\", time.Now())\n\n\tdb, err := getDB(d.cfg)\n\tif err != nil {\n\t\td.cfg.Logger().Error(\"failed to get DB connection. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// set latency budget for the database call\n\tsubCtx, cancel := context.WithTimeout(ctx, 1*time.Second)\n\tdefer cancel()\n\n\t// perform DB select\n\trow := db.QueryRowContext(subCtx, sqlLoadByID, ID)\n\n\t// retrieve columns and populate the person object\n\tout, err := populatePerson(row.Scan)\n\tif err != nil {\n\t\tif err == sql.ErrNoRows {\n\t\t\td.cfg.Logger().Warn(\"failed to load requested person '%d'. err: %s\", ID, err)\n\t\t\treturn nil, ErrNotFound\n\t\t}\n\n\t\td.cfg.Logger().Error(\"failed to convert query result. err: %s\", err)\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\n// LoadAll will attempt to load all people in the database\n// It will return ErrNotFound when there are not people in the database\n// Any other errors returned are caused by the underlying database or our connection to it.\nfunc (d *DAO) LoadAll(ctx context.Context) ([]*Person, error) {\n\t// track processing time\n\tdefer d.getTracker().Track(\"LoadAll\", time.Now())\n\n\tdb, err := getDB(d.cfg)\n\tif err != nil {\n\t\td.cfg.Logger().Error(\"failed to get DB connection. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// set latency budget for the database call\n\tsubCtx, cancel := context.WithTimeout(ctx, 1*time.Second)\n\tdefer cancel()\n\n\t// perform DB select\n\trows, err := db.QueryContext(subCtx, sqlLoadAll)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer func() {\n\t\t_ = rows.Close()\n\t}()\n\n\tvar out []*Person\n\n\tfor rows.Next() {\n\t\t// retrieve columns and populate the person object\n\t\trecord, err := populatePerson(rows.Scan)\n\t\tif err != nil {\n\t\t\td.cfg.Logger().Error(\"failed to convert query result. err: %s\", err)\n\t\t\treturn nil, err\n\t\t}\n\n\t\tout = append(out, record)\n\t}\n\n\tif len(out) == 0 {\n\t\td.cfg.Logger().Warn(\"no people found in the database.\")\n\t\treturn nil, ErrNotFound\n\t}\n\n\treturn out, nil\n}\n\n// Save will save the supplied person and return the ID of the newly created person or an error.\n// Errors returned are caused by the underlying database or our connection to it.\nfunc (d *DAO) Save(ctx context.Context, in *Person) (int, error) {\n\t// track processing time\n\tdefer d.getTracker().Track(\"Save\", time.Now())\n\n\tdb, err := getDB(d.cfg)\n\tif err != nil {\n\t\td.cfg.Logger().Error(\"failed to get DB connection. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\t// set latency budget for the database call\n\tsubCtx, cancel := context.WithTimeout(ctx, 1*time.Second)\n\tdefer cancel()\n\n\t// perform DB insert\n\tresult, err := db.ExecContext(subCtx, sqlInsert, in.FullName, in.Phone, in.Currency, in.Price)\n\tif err != nil {\n\t\td.cfg.Logger().Error(\"failed to save person into DB. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\t// retrieve and return the ID of the person created\n\tid, err := result.LastInsertId()\n\tif err != nil {\n\t\td.cfg.Logger().Error(\"failed to retrieve id of last saved person. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn int(id), nil\n}\n\nfunc (d *DAO) getTracker() QueryTracker {\n\tif d.Tracker == nil {\n\t\td.Tracker = &noopTracker{}\n\t}\n\n\treturn d.Tracker\n}\n"
  },
  {
    "path": "ch09/acme/internal/modules/data/data.go",
    "content": "package data\n\nimport (\n\t\"database/sql\"\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/logging\"\n\t_ \"github.com/go-sql-driver/mysql\"\n)\n\nconst (\n\t// default person id (returned on error)\n\tdefaultPersonID = 0\n\n\t// SQL statements as constants (to reduce duplication and maintenance in tests)\n\tsqlAllColumns = \"id, fullname, phone, currency, price\"\n\tsqlInsert     = \"INSERT INTO person (fullname, phone, currency, price) VALUES (?, ?, ?, ?)\"\n\tsqlLoadAll    = \"SELECT \" + sqlAllColumns + \" FROM person\"\n\tsqlLoadByID   = \"SELECT \" + sqlAllColumns + \" FROM person WHERE id = ? LIMIT 1\"\n)\n\nvar (\n\tdb *sql.DB\n\n\t// ErrNotFound is returned when the no records where matched by the query\n\tErrNotFound = errors.New(\"not found\")\n)\n\n// Config is the configuration for the data package\ntype Config interface {\n\t// Logger returns a reference to the logger\n\tLogger() logging.Logger\n\n\t// DataDSN returns the data source name\n\tDataDSN() string\n}\n\nvar getDB = func(cfg Config) (*sql.DB, error) {\n\tif db == nil {\n\t\tvar err error\n\t\tdb, err = sql.Open(\"mysql\", cfg.DataDSN())\n\t\tif err != nil {\n\t\t\t// if the DB cannot be accessed we are dead\n\t\t\tpanic(err.Error())\n\t\t}\n\t}\n\n\treturn db, nil\n}\n\n// Person is the data transfer object (DTO) for this package\ntype Person struct {\n\t// ID is the unique ID for this person\n\tID int\n\t// FullName is the name of this person\n\tFullName string\n\t// Phone is the phone for this person\n\tPhone string\n\t// Currency is the currency this person has paid in\n\tCurrency string\n\t// Price is the amount (in the above currency) paid by this person\n\tPrice float64\n}\n\n// custom type so we can convert sql results to easily\ntype scanner func(dest ...interface{}) error\n\n// reduce the duplication (and maintenance) between sql.Row and sql.Rows usage\nfunc populatePerson(scanner scanner) (*Person, error) {\n\tout := &Person{}\n\terr := scanner(&out.ID, &out.FullName, &out.Phone, &out.Currency, &out.Price)\n\treturn out, err\n}\n"
  },
  {
    "path": "ch09/acme/internal/modules/data/data_test.go",
    "content": "package data\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"errors\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/DATA-DOG/go-sqlmock\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/logging\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestSave_happyPath(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\t// define a mock db\n\ttestDb, dbMock, err := sqlmock.New()\n\tdefer testDb.Close()\n\trequire.NoError(t, err)\n\n\t// configure the mock db\n\tqueryRegex := convertSQLToRegex(sqlInsert)\n\tdbMock.ExpectExec(queryRegex).WillReturnResult(sqlmock.NewResult(2, 1))\n\n\t// monkey patching starts here\n\tdb = testDb\n\t// end of monkey patch\n\n\t// inputs\n\tin := &Person{\n\t\tFullName: \"Jake Blues\",\n\t\tPhone:    \"01234567890\",\n\t\tCurrency: \"AUD\",\n\t\tPrice:    123.45,\n\t}\n\n\t// call function\n\tdao := NewDAO(&testConfig{})\n\tresultID, err := dao.Save(ctx, in)\n\n\t// validate result\n\trequire.NoError(t, err)\n\tassert.Equal(t, 2, resultID)\n\tassert.NoError(t, dbMock.ExpectationsWereMet())\n}\n\nfunc TestSave_insertError(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\t// define a mock db\n\ttestDb, dbMock, err := sqlmock.New()\n\tdefer testDb.Close()\n\n\trequire.NoError(t, err)\n\n\t// configure the mock db\n\tqueryRegex := convertSQLToRegex(sqlInsert)\n\tdbMock.ExpectExec(queryRegex).WillReturnError(errors.New(\"failed to insert\"))\n\n\t// monkey patching starts here\n\tdb = testDb\n\t// end of monkey patch\n\n\t// inputs\n\tin := &Person{\n\t\tFullName: \"Jake Blues\",\n\t\tPhone:    \"01234567890\",\n\t\tCurrency: \"AUD\",\n\t\tPrice:    123.45,\n\t}\n\n\t// call function\n\tdao := NewDAO(&testConfig{})\n\tresultID, err := dao.Save(ctx, in)\n\n\t// validate result\n\trequire.Error(t, err)\n\tassert.Equal(t, defaultPersonID, resultID)\n\tassert.NoError(t, dbMock.ExpectationsWereMet())\n}\n\nfunc TestSave_getDBError(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\t// monkey patching starts here\n\tdefer func(original func(_ Config) (*sql.DB, error)) {\n\t\t// restore original DB (after test)\n\t\tgetDB = original\n\t}(getDB)\n\n\t// replace getDB() function for this test\n\tgetDB = func(_ Config) (*sql.DB, error) {\n\t\treturn nil, errors.New(\"getDB() failed\")\n\t}\n\t// end of monkey patch\n\n\t// inputs\n\tin := &Person{\n\t\tFullName: \"Jake Blues\",\n\t\tPhone:    \"01234567890\",\n\t\tCurrency: \"AUD\",\n\t\tPrice:    123.45,\n\t}\n\n\t// call function\n\tdao := NewDAO(&testConfig{})\n\tresultID, err := dao.Save(ctx, in)\n\trequire.Error(t, err)\n\tassert.Equal(t, defaultPersonID, resultID)\n}\n\nfunc TestLoadAll_tableDrivenTest(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\n\tdefer cancel()\n\n\tscenarios := []struct {\n\t\tdesc            string\n\t\tconfigureMockDB func(sqlmock.Sqlmock)\n\t\texpectedResults []*Person\n\t\texpectError     bool\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tconfigureMockDB: func(dbMock sqlmock.Sqlmock) {\n\t\t\t\tqueryRegex := convertSQLToRegex(sqlLoadAll)\n\t\t\t\tdbMock.ExpectQuery(queryRegex).WillReturnRows(\n\t\t\t\t\tsqlmock.NewRows(strings.Split(sqlAllColumns, \", \")).\n\t\t\t\t\t\tAddRow(1, \"John\", \"0123456789\", \"AUD\", 12.34))\n\t\t\t},\n\t\t\texpectedResults: []*Person{\n\t\t\t\t{\n\t\t\t\t\tID:       1,\n\t\t\t\t\tFullName: \"John\",\n\t\t\t\t\tPhone:    \"0123456789\",\n\t\t\t\t\tCurrency: \"AUD\",\n\t\t\t\t\tPrice:    12.34,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tdesc: \"load error\",\n\t\t\tconfigureMockDB: func(dbMock sqlmock.Sqlmock) {\n\t\t\t\tqueryRegex := convertSQLToRegex(sqlLoadAll)\n\t\t\t\tdbMock.ExpectQuery(queryRegex).WillReturnError(errors.New(\"something failed\"))\n\t\t\t},\n\t\t\texpectedResults: nil,\n\t\t\texpectError:     true,\n\t\t},\n\t}\n\n\tfor _, scenario := range scenarios {\n\t\t// define a mock db\n\t\ttestDb, dbMock, err := sqlmock.New()\n\t\trequire.NoError(t, err)\n\n\t\t// configure the mock db\n\t\tscenario.configureMockDB(dbMock)\n\n\t\t// monkey patch the db for this test\n\t\toriginal := *db\n\t\tdb = testDb\n\n\t\t// call function\n\t\tdao := NewDAO(&testConfig{})\n\t\tresults, err := dao.LoadAll(ctx)\n\n\t\t// validate results\n\t\tassert.Equal(t, scenario.expectedResults, results, scenario.desc)\n\t\tassert.Equal(t, scenario.expectError, err != nil, scenario.desc)\n\t\tassert.NoError(t, dbMock.ExpectationsWereMet())\n\n\t\t// restore original DB (after test)\n\t\tdb = &original\n\t\ttestDb.Close()\n\t}\n}\n\nfunc TestLoad_tableDrivenTest(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\n\tdefer cancel()\n\n\tscenarios := []struct {\n\t\tdesc            string\n\t\tconfigureMockDB func(sqlmock.Sqlmock)\n\t\texpectedResult  *Person\n\t\texpectError     bool\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tconfigureMockDB: func(dbMock sqlmock.Sqlmock) {\n\t\t\t\tqueryRegex := convertSQLToRegex(sqlLoadAll)\n\t\t\t\tdbMock.ExpectQuery(queryRegex).WillReturnRows(\n\t\t\t\t\tsqlmock.NewRows(strings.Split(sqlAllColumns, \", \")).\n\t\t\t\t\t\tAddRow(2, \"Paul\", \"0123456789\", \"CAD\", 23.45))\n\t\t\t},\n\t\t\texpectedResult: &Person{\n\t\t\t\tID:       2,\n\t\t\t\tFullName: \"Paul\",\n\t\t\t\tPhone:    \"0123456789\",\n\t\t\t\tCurrency: \"CAD\",\n\t\t\t\tPrice:    23.45,\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tdesc: \"load error\",\n\t\t\tconfigureMockDB: func(dbMock sqlmock.Sqlmock) {\n\t\t\t\tqueryRegex := convertSQLToRegex(sqlLoadAll)\n\t\t\t\tdbMock.ExpectQuery(queryRegex).WillReturnError(errors.New(\"something failed\"))\n\t\t\t},\n\t\t\texpectedResult: nil,\n\t\t\texpectError:    true,\n\t\t},\n\t}\n\n\tfor _, scenario := range scenarios {\n\t\t// define a mock db\n\t\ttestDb, dbMock, err := sqlmock.New()\n\t\trequire.NoError(t, err)\n\n\t\t// configure the mock db\n\t\tscenario.configureMockDB(dbMock)\n\n\t\t// monkey db for this test\n\t\toriginal := *db\n\t\tdb = testDb\n\n\t\t// call function\n\t\tdao := NewDAO(&testConfig{})\n\t\tresult, err := dao.Load(ctx, 2)\n\n\t\t// validate results\n\t\tassert.Equal(t, scenario.expectedResult, result, scenario.desc)\n\t\tassert.Equal(t, scenario.expectError, err != nil, scenario.desc)\n\t\tassert.NoError(t, dbMock.ExpectationsWereMet())\n\n\t\t// restore original DB (after test)\n\t\tdb = &original\n\t\ttestDb.Close()\n\t}\n}\n\n// convert SQL string to regex by treating the entire query as a literal\nfunc convertSQLToRegex(in string) string {\n\treturn `\\Q` + in + `\\E`\n}\n\ntype testConfig struct{}\n\n// Logger implements Config\nfunc (t *testConfig) Logger() logging.Logger {\n\treturn logging.LoggerStdOut{}\n}\n\n// DataDSN implements Config\nfunc (t *testConfig) DataDSN() string {\n\treturn \"\"\n}\n"
  },
  {
    "path": "ch09/acme/internal/modules/data/tracker.go",
    "content": "package data\n\nimport (\n\t\"time\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/logging\"\n)\n\n// QueryTracker is an interface to track query timing\ntype QueryTracker interface {\n\t// Track will record/out the time a query took by calculating time.Now().Sub(start)\n\tTrack(key string, start time.Time)\n}\n\n// NO-OP implementation of QueryTracker\ntype noopTracker struct{}\n\n// Track implements QueryTracker\nfunc (_ *noopTracker) Track(_ string, _ time.Time) {\n\t// intentionally does nothing\n}\n\n// NewLogTracker returns a Tracker that outputs tracking data to log\nfunc NewLogTracker(logger logging.Logger) *LogTracker {\n\treturn &LogTracker{\n\t\tlogger: logger,\n\t}\n}\n\n// LogTracker implements QueryTracker and outputs to the supplied logger\ntype LogTracker struct {\n\tlogger logging.Logger\n}\n\n// Track implements QueryTracker\nfunc (l *LogTracker) Track(key string, start time.Time) {\n\tl.logger.Info(\"[%s] Timing: %s\\n\", key, time.Now().Sub(start).String())\n}\n"
  },
  {
    "path": "ch09/acme/internal/modules/exchange/converter.go",
    "content": "package exchange\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"math\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/logging\"\n)\n\nconst (\n\t// request URL for the exchange rate API\n\turlFormat = \"%s/api/historical?access_key=%s&date=2018-06-20&currencies=%s\"\n\n\t// default price that is sent when an error occurs\n\tdefaultPrice = 0.0\n)\n\n// NewConverter creates and initializes the converter\nfunc NewConverter(cfg Config) *Converter {\n\treturn &Converter{\n\t\tcfg: cfg,\n\t}\n}\n\n// Config is the config for Converter\ntype Config interface {\n\tLogger() logging.Logger\n\tExchangeBaseURL() string\n\tExchangeAPIKey() string\n}\n\n// Converter will convert the base price to the currency supplied\n// Note: we are expecting sane inputs and therefore skipping input validation\ntype Converter struct {\n\tcfg Config\n}\n\n// Exchange will perform the conversion\nfunc (c *Converter) Exchange(ctx context.Context, basePrice float64, currency string) (float64, error) {\n\t// load rate from the external API\n\tresponse, err := c.loadRateFromServer(ctx, currency)\n\tif err != nil {\n\t\treturn defaultPrice, err\n\t}\n\n\t// extract rate from response\n\trate, err := c.extractRate(response, currency)\n\tif err != nil {\n\t\treturn defaultPrice, err\n\t}\n\n\t// apply rate and round to 2 decimal places\n\treturn math.Floor((basePrice/rate)*100) / 100, nil\n}\n\n// load rate from the external API\nfunc (c *Converter) loadRateFromServer(ctx context.Context, currency string) (*http.Response, error) {\n\t// build the request\n\turl := fmt.Sprintf(urlFormat,\n\t\tc.cfg.ExchangeBaseURL(),\n\t\tc.cfg.ExchangeAPIKey(),\n\t\tcurrency)\n\n\t// perform request\n\treq, err := http.NewRequest(\"GET\", url, nil)\n\tif err != nil {\n\t\tc.logger().Warn(\"[exchange] failed to create request. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// set latency budget for the upstream call\n\tsubCtx, cancel := context.WithTimeout(ctx, 1*time.Second)\n\tdefer cancel()\n\n\t// replace the default context with our custom one\n\treq = req.WithContext(subCtx)\n\n\t// perform the HTTP request\n\tresponse, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tc.logger().Warn(\"[exchange] failed to load. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\tif response.StatusCode != http.StatusOK {\n\t\terr = fmt.Errorf(\"request failed with code %d\", response.StatusCode)\n\t\tc.logger().Warn(\"[exchange] %s\", err)\n\t\treturn nil, err\n\t}\n\n\treturn response, nil\n}\n\nfunc (c *Converter) extractRate(response *http.Response, currency string) (float64, error) {\n\tdefer func() {\n\t\t_ = response.Body.Close()\n\t}()\n\n\t// extract data from response\n\tdata, err := c.extractResponse(response)\n\tif err != nil {\n\t\treturn defaultPrice, err\n\t}\n\n\t// pull rate from response data\n\trate, found := data.Quotes[\"USD\"+currency]\n\tif !found {\n\t\terr = fmt.Errorf(\"response did not include expected currency '%s'\", currency)\n\t\tc.logger().Error(\"[exchange] %s\", err)\n\t\treturn defaultPrice, err\n\t}\n\n\t// happy path\n\treturn rate, nil\n}\n\nfunc (c *Converter) extractResponse(response *http.Response) (*apiResponseFormat, error) {\n\tpayload, err := ioutil.ReadAll(response.Body)\n\tif err != nil {\n\t\tc.logger().Error(\"[exchange] failed to ready response body. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\tdata := &apiResponseFormat{}\n\terr = json.Unmarshal(payload, data)\n\tif err != nil {\n\t\tc.logger().Error(\"[exchange] error converting response. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// happy path\n\treturn data, nil\n}\n\nfunc (c *Converter) logger() logging.Logger {\n\treturn c.cfg.Logger()\n}\n\n// the response format from the exchange rate API\ntype apiResponseFormat struct {\n\tQuotes map[string]float64 `json:\"quotes\"`\n}\n"
  },
  {
    "path": "ch09/acme/internal/modules/exchange/converter_ext_bounday_test.go",
    "content": "// +build external\n\npackage exchange\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/config\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestExternalBoundaryTest(t *testing.T) {\n\t// define the config\n\tcfg := &testConfig{\n\t\tbaseURL: config.App.ExchangeRateBaseURL,\n\t\tapiKey:  config.App.ExchangeRateAPIKey,\n\t}\n\n\t// create a converter to test\n\tconverter := NewConverter(cfg)\n\n\t// fetch from the server\n\tresponse, err := converter.loadRateFromServer(context.Background(), \"AUD\")\n\trequire.NotNil(t, response)\n\trequire.NoError(t, err)\n\n\t// parse the response\n\tresultRate, err := converter.extractRate(response, \"AUD\")\n\trequire.NoError(t, err)\n\n\t// validate the result\n\tassert.True(t, resultRate > 0)\n}\n"
  },
  {
    "path": "ch09/acme/internal/modules/exchange/converter_int_bounday_test.go",
    "content": "package exchange\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/logging\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestInternalBoundaryTest(t *testing.T) {\n\t// start our test server\n\tserver := httptest.NewServer(&happyExchangeRateService{})\n\tdefer server.Close()\n\n\t// define the config\n\tcfg := &testConfig{\n\t\tbaseURL: server.URL,\n\t\tapiKey:  \"\",\n\t}\n\n\t// create a converter to test\n\tconverter := NewConverter(cfg)\n\tresultRate, resultErr := converter.Exchange(context.Background(), 100.00, \"AUD\")\n\n\t// validate the result\n\tassert.Equal(t, 101.01, resultRate)\n\tassert.NoError(t, resultErr)\n}\n\ntype happyExchangeRateService struct{}\n\n// ServeHTTP implements http.Handler\nfunc (*happyExchangeRateService) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\tpayload := []byte(`\n{\n   \"success\":true,\n   \"historical\":true,\n   \"date\":\"2010-11-09\",\n   \"timestamp\":1289347199,\n   \"source\":\"USD\",\n   \"quotes\":{\n      \"USDAUD\":0.989981\n   }\n}`)\n\tresponse.Write(payload)\n}\n\n// test implementation of Config\ntype testConfig struct {\n\tbaseURL string\n\tapiKey  string\n}\n\n// Logger implements Config\nfunc (t *testConfig) Logger() logging.Logger {\n\treturn &logging.LoggerStdOut{}\n}\n\n// ExchangeBaseURL implements Config\nfunc (t *testConfig) ExchangeBaseURL() string {\n\treturn t.baseURL\n}\n\n// ExchangeAPIKey implements Config\nfunc (t *testConfig) ExchangeAPIKey() string {\n\treturn t.apiKey\n}\n"
  },
  {
    "path": "ch09/acme/internal/modules/get/get.go",
    "content": "package get\n\nimport (\n\t\"context\"\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/modules/data\"\n)\n\nvar (\n\t// error thrown when the requested person is not in the database\n\terrPersonNotFound = errors.New(\"person not found\")\n)\n\n// NewGetter creates and initializes a Getter\nfunc NewGetter(cfg Config) *Getter {\n\treturn &Getter{\n\t\tcfg: cfg,\n\t}\n}\n\n// Config is the configuration for Getter\ntype Config interface {\n\tLogger() logging.Logger\n\tDataDSN() string\n}\n\n// Getter will attempt to load a person.\n// It can return an error caused by the data layer or when the requested person is not found\ntype Getter struct {\n\tcfg  Config\n\tdata myLoader\n}\n\n// Do will perform the get\nfunc (g *Getter) Do(ID int) (*data.Person, error) {\n\t// load person from the data layer\n\tperson, err := g.getLoader().Load(context.TODO(), ID)\n\tif err != nil {\n\t\tif err == data.ErrNotFound {\n\t\t\t// By converting the error we are hiding the implementation details from our users.\n\t\t\treturn nil, errPersonNotFound\n\t\t}\n\t\treturn nil, err\n\t}\n\n\treturn person, err\n}\n\nfunc (g *Getter) getLoader() myLoader {\n\tif g.data == nil {\n\t\tg.data = data.NewDAO(g.cfg)\n\t}\n\n\treturn g.data\n}\n\n//go:generate mockery -name=myLoader -case underscore -testonly -inpkg -note @generated\ntype myLoader interface {\n\tLoad(ctx context.Context, ID int) (*data.Person, error)\n}\n"
  },
  {
    "path": "ch09/acme/internal/modules/get/go_test.go",
    "content": "package get\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestGetter_Do_happyPath(t *testing.T) {\n\t// inputs\n\tID := 1234\n\n\t// configure the mock loader\n\tmockResult := &data.Person{\n\t\tID:       1234,\n\t\tFullName: \"Doug\",\n\t}\n\tmockLoader := &mockMyLoader{}\n\tmockLoader.On(\"Load\", mock.Anything, ID).Return(mockResult, nil).Once()\n\n\t// call method\n\tgetter := &Getter{\n\t\tdata: mockLoader,\n\t}\n\tperson, err := getter.Do(ID)\n\n\t// validate expectations\n\trequire.NoError(t, err)\n\tassert.Equal(t, ID, person.ID)\n\tassert.Equal(t, \"Doug\", person.FullName)\n\tassert.True(t, mockLoader.AssertExpectations(t))\n}\n\nfunc TestGetter_Do_noSuchPerson(t *testing.T) {\n\t// inputs\n\tID := 5678\n\n\t// configure the mock loader\n\tmockLoader := &mockMyLoader{}\n\tmockLoader.On(\"Load\", mock.Anything, ID).Return(nil, data.ErrNotFound).Once()\n\n\t// call method\n\tgetter := &Getter{\n\t\tdata: mockLoader,\n\t}\n\tperson, err := getter.Do(ID)\n\n\t// validate expectations\n\trequire.Equal(t, errPersonNotFound, err)\n\tassert.Nil(t, person)\n\tassert.True(t, mockLoader.AssertExpectations(t))\n}\n\nfunc TestGetter_Do_error(t *testing.T) {\n\t// inputs\n\tID := 1234\n\n\t// configure the mock loader\n\tmockLoader := &mockMyLoader{}\n\tmockLoader.On(\"Load\", mock.Anything, ID).Return(nil, errors.New(\"something failed\")).Once()\n\n\t// call method\n\tgetter := &Getter{\n\t\tdata: mockLoader,\n\t}\n\tperson, err := getter.Do(ID)\n\n\t// validate expectations\n\trequire.Error(t, err)\n\tassert.Nil(t, person)\n\tassert.True(t, mockLoader.AssertExpectations(t))\n}\n"
  },
  {
    "path": "ch09/acme/internal/modules/get/mock_my_loader_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage get\n\nimport (\n\t\"context\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// mockMyLoader is an autogenerated mock type for the myLoader type\ntype mockMyLoader struct {\n\tmock.Mock\n}\n\n// Load provides a mock function with given fields: ctx, ID\nfunc (_m *mockMyLoader) Load(ctx context.Context, ID int) (*data.Person, error) {\n\tret := _m.Called(ctx, ID)\n\n\tvar r0 *data.Person\n\tif rf, ok := ret.Get(0).(func(context.Context, int) *data.Person); ok {\n\t\tr0 = rf(ctx, ID)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*data.Person)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, int) error); ok {\n\t\tr1 = rf(ctx, ID)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch09/acme/internal/modules/list/list.go",
    "content": "package list\n\nimport (\n\t\"context\"\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/modules/data\"\n)\n\nvar (\n\t// error thrown when there are no people in the database\n\terrPeopleNotFound = errors.New(\"no people found\")\n)\n\n// NewLister creates and initializes a Lister\nfunc NewLister(cfg Config) *Lister {\n\treturn &Lister{\n\t\tcfg: cfg,\n\t}\n}\n\n// Config is the config for Lister\ntype Config interface {\n\tLogger() logging.Logger\n\tDataDSN() string\n}\n\n// Lister will attempt to load all people in the database.\n// It can return an error caused by the data layer\ntype Lister struct {\n\tcfg  Config\n\tdata myLoader\n}\n\n// Exchange will load the people from the data layer\nfunc (l *Lister) Do() ([]*data.Person, error) {\n\t// load all people\n\tpeople, err := l.load()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(people) == 0 {\n\t\t// special processing for 0 people returned\n\t\treturn nil, errPeopleNotFound\n\t}\n\n\treturn people, nil\n}\n\n// load all people\nfunc (l *Lister) load() ([]*data.Person, error) {\n\tpeople, err := l.getLoader().LoadAll(context.TODO())\n\tif err != nil {\n\t\tif err == data.ErrNotFound {\n\t\t\t// By converting the error we are encapsulating the implementation details from our users.\n\t\t\treturn nil, errPeopleNotFound\n\t\t}\n\t\treturn nil, err\n\t}\n\n\treturn people, nil\n}\n\nfunc (l *Lister) getLoader() myLoader {\n\tif l.data == nil {\n\t\tl.data = data.NewDAO(l.cfg)\n\n\t\t// temporarily add a log tracker\n\t\tl.data.(*data.DAO).Tracker = data.NewLogTracker(l.cfg.Logger())\n\t}\n\n\treturn l.data\n}\n\n//go:generate mockery -name=myLoader -case underscore -testonly -inpkg -note @generated\ntype myLoader interface {\n\tLoadAll(ctx context.Context) ([]*data.Person, error)\n}\n"
  },
  {
    "path": "ch09/acme/internal/modules/list/list_test.go",
    "content": "package list\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestLister_Do_happyPath(t *testing.T) {\n\t// configure the mock loader\n\tmockResult := []*data.Person{\n\t\t{\n\t\t\tID:       1234,\n\t\t\tFullName: \"Sally\",\n\t\t},\n\t\t{\n\t\t\tID:       5678,\n\t\t\tFullName: \"Jane\",\n\t\t},\n\t}\n\n\tmockLoader := &mockMyLoader{}\n\tmockLoader.On(\"LoadAll\", mock.Anything).Return(mockResult, nil).Once()\n\n\t// call method\n\tlister := &Lister{\n\t\tdata: mockLoader,\n\t}\n\tpersons, err := lister.load()\n\n\t// validate expectations\n\trequire.NoError(t, err)\n\tassert.Equal(t, 2, len(persons))\n\tassert.True(t, mockLoader.AssertExpectations(t))\n}\n\nfunc TestLister_Do_noResults(t *testing.T) {\n\t// configure the mock loader\n\tmockLoader := &mockMyLoader{}\n\tmockLoader.On(\"LoadAll\", mock.Anything).Return(nil, data.ErrNotFound).Once()\n\n\t// call method\n\tlister := &Lister{\n\t\tdata: mockLoader,\n\t}\n\tpersons, err := lister.load()\n\n\t// validate expectations\n\trequire.Equal(t, errPeopleNotFound, err)\n\tassert.Equal(t, 0, len(persons))\n\tassert.True(t, mockLoader.AssertExpectations(t))\n}\n\nfunc TestLister_Do_error(t *testing.T) {\n\t// configure the mock loader\n\tmockLoader := &mockMyLoader{}\n\tmockLoader.On(\"LoadAll\", mock.Anything).Return(nil, errors.New(\"something failed\")).Once()\n\n\t// call method\n\tlister := &Lister{\n\t\tdata: mockLoader,\n\t}\n\tpersons, err := lister.load()\n\n\t// validate expectations\n\trequire.Error(t, err)\n\tassert.Equal(t, 0, len(persons))\n\tassert.True(t, mockLoader.AssertExpectations(t))\n}\n"
  },
  {
    "path": "ch09/acme/internal/modules/list/mock_my_loader_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage list\n\nimport (\n\t\"context\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// mockMyLoader is an autogenerated mock type for the myLoader type\ntype mockMyLoader struct {\n\tmock.Mock\n}\n\n// LoadAll provides a mock function with given fields: ctx\nfunc (_m *mockMyLoader) LoadAll(ctx context.Context) ([]*data.Person, error) {\n\tret := _m.Called(ctx)\n\n\tvar r0 []*data.Person\n\tif rf, ok := ret.Get(0).(func(context.Context) []*data.Person); ok {\n\t\tr0 = rf(ctx)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]*data.Person)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context) error); ok {\n\t\tr1 = rf(ctx)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch09/acme/internal/modules/register/mock_my_saver_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage register\n\nimport (\n\t\"context\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// mockMySaver is an autogenerated mock type for the mySaver type\ntype mockMySaver struct {\n\tmock.Mock\n}\n\n// Save provides a mock function with given fields: ctx, in\nfunc (_m *mockMySaver) Save(ctx context.Context, in *data.Person) (int, error) {\n\tret := _m.Called(ctx, in)\n\n\tvar r0 int\n\tif rf, ok := ret.Get(0).(func(context.Context, *data.Person) int); ok {\n\t\tr0 = rf(ctx, in)\n\t} else {\n\t\tr0 = ret.Get(0).(int)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, *data.Person) error); ok {\n\t\tr1 = rf(ctx, in)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch09/acme/internal/modules/register/register.go",
    "content": "package register\n\nimport (\n\t\"context\"\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/modules/data\"\n)\n\nconst (\n\t// default person id (returned on error)\n\tdefaultPersonID = 0\n)\n\nvar (\n\t// validation errors\n\terrNameMissing     = errors.New(\"name is missing\")\n\terrPhoneMissing    = errors.New(\"phone is missing\")\n\terrCurrencyMissing = errors.New(\"currency is missing\")\n\terrInvalidCurrency = errors.New(\"currency is invalid, supported types are AUD, CNY, EUR, GBP, JPY, MYR, SGD, USD\")\n\n\t// a little trick to make checking for supported currencies easier\n\tsupportedCurrencies = map[string]struct{}{\n\t\t\"AUD\": {},\n\t\t\"CNY\": {},\n\t\t\"EUR\": {},\n\t\t\"GBP\": {},\n\t\t\"JPY\": {},\n\t\t\"MYR\": {},\n\t\t\"SGD\": {},\n\t\t\"USD\": {},\n\t}\n)\n\n// NewRegisterer creates and initializes a Registerer\nfunc NewRegisterer(cfg Config, exchanger Exchanger) *Registerer {\n\treturn &Registerer{\n\t\tcfg:       cfg,\n\t\texchanger: exchanger,\n\t}\n}\n\n// Exchanger will convert from one currency to another\ntype Exchanger interface {\n\t// Exchange will perform the conversion\n\tExchange(ctx context.Context, basePrice float64, currency string) (float64, error)\n}\n\n// Config is the configuration for the Registerer\ntype Config interface {\n\tLogger() logging.Logger\n\tRegistrationBasePrice() float64\n\tDataDSN() string\n}\n\n// Registerer validates the supplied person, calculates the price in the requested currency and saves the result.\n// It will return an error when:\n// -the person object does not include all the fields\n// -the currency is invalid\n// -the exchange rate cannot be loaded\n// -the data layer throws an error.\ntype Registerer struct {\n\tcfg       Config\n\texchanger Exchanger\n\tdata      mySaver\n}\n\n// Do is API for this struct\nfunc (r *Registerer) Do(ctx context.Context, in *data.Person) (int, error) {\n\t// validate the request\n\terr := r.validateInput(in)\n\tif err != nil {\n\t\tr.logger().Warn(\"input validation failed with err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\t// get price in the requested currency\n\tprice, err := r.getPrice(ctx, in.Currency)\n\tif err != nil {\n\t\treturn defaultPersonID, err\n\t}\n\n\t// save registration\n\tid, err := r.save(ctx, in, price)\n\tif err != nil {\n\t\t// no need to log here as we expect the data layer to do so\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn id, nil\n}\n\n// validate input and return error on fail\nfunc (r *Registerer) validateInput(in *data.Person) error {\n\tif in.FullName == \"\" {\n\t\treturn errNameMissing\n\t}\n\tif in.Phone == \"\" {\n\t\treturn errPhoneMissing\n\t}\n\tif in.Currency == \"\" {\n\t\treturn errCurrencyMissing\n\t}\n\n\tif _, found := supportedCurrencies[in.Currency]; !found {\n\t\treturn errInvalidCurrency\n\t}\n\n\t// happy path\n\treturn nil\n}\n\n// get price in the requested currency\nfunc (r *Registerer) getPrice(ctx context.Context, currency string) (float64, error) {\n\tprice, err := r.exchanger.Exchange(ctx, r.cfg.RegistrationBasePrice(), currency)\n\tif err != nil {\n\t\tr.logger().Warn(\"failed to convert the price. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn price, nil\n}\n\n// save the registration\nfunc (r *Registerer) save(ctx context.Context, in *data.Person, price float64) (int, error) {\n\tperson := &data.Person{\n\t\tFullName: in.FullName,\n\t\tPhone:    in.Phone,\n\t\tCurrency: in.Currency,\n\t\tPrice:    price,\n\t}\n\treturn r.getSaver().Save(ctx, person)\n}\n\nfunc (r *Registerer) getSaver() mySaver {\n\tif r.data == nil {\n\t\tr.data = data.NewDAO(r.cfg)\n\t}\n\n\treturn r.data\n}\n\nfunc (r *Registerer) logger() logging.Logger {\n\treturn r.cfg.Logger()\n}\n\n//go:generate mockery -name=mySaver -case underscore -testonly -inpkg -note @generated\ntype mySaver interface {\n\tSave(ctx context.Context, in *data.Person) (int, error)\n}\n"
  },
  {
    "path": "ch09/acme/internal/modules/register/register_test.go",
    "content": "package register\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestRegisterer_Do_happyPath(t *testing.T) {\n\t// configure the mock saver\n\tmockResult := 888\n\n\tmockSaver := &mockMySaver{}\n\tmockSaver.On(\"Save\", mock.Anything, mock.Anything).Return(mockResult, nil).Once()\n\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\t// inputs\n\tin := &data.Person{\n\t\tFullName: \"Chang\",\n\t\tPhone:    \"11122233355\",\n\t\tCurrency: \"CNY\",\n\t}\n\n\t// call method\n\tregisterer := &Registerer{\n\t\tcfg:       &testConfig{},\n\t\texchanger: &stubExchanger{},\n\t\tdata:      mockSaver,\n\t}\n\tID, err := registerer.Do(ctx, in)\n\n\t// validate expectations\n\trequire.NoError(t, err)\n\tassert.Equal(t, 888, ID)\n\tassert.True(t, mockSaver.AssertExpectations(t))\n}\n\nfunc TestRegisterer_Do_error(t *testing.T) {\n\t// configure the mock saver\n\tmockSaver := &mockMySaver{}\n\tmockSaver.On(\"Save\", mock.Anything, mock.Anything).Return(0, errors.New(\"something failed\")).Once()\n\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\t// inputs\n\tin := &data.Person{\n\t\tFullName: \"Chang\",\n\t\tPhone:    \"11122233355\",\n\t\tCurrency: \"CNY\",\n\t}\n\n\t// call method\n\tregisterer := &Registerer{\n\t\tcfg:       &testConfig{},\n\t\texchanger: &stubExchanger{},\n\t\tdata:      mockSaver,\n\t}\n\tID, err := registerer.Do(ctx, in)\n\n\t// validate expectations\n\trequire.Error(t, err)\n\tassert.Equal(t, 0, ID)\n\tassert.True(t, mockSaver.AssertExpectations(t))\n}\n\n// Stub implementation of Config\ntype testConfig struct{}\n\n// Logger implement Config\nfunc (t *testConfig) Logger() logging.Logger {\n\treturn &logging.LoggerStdOut{}\n}\n\n// RegistrationBasePrice implement Config\nfunc (t *testConfig) RegistrationBasePrice() float64 {\n\treturn 12.34\n}\n\n// DataDSN implements Config\nfunc (t *testConfig) DataDSN() string {\n\treturn \"\"\n}\n\ntype stubExchanger struct{}\n\n// Exchange implements Exchanger\nfunc (s stubExchanger) Exchange(ctx context.Context, basePrice float64, currency string) (float64, error) {\n\treturn 12.34, nil\n}\n"
  },
  {
    "path": "ch09/acme/internal/rest/get.go",
    "content": "package rest\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/modules/data\"\n\t\"github.com/gorilla/mux\"\n)\n\nconst (\n\t// default person id (returned on error)\n\tdefaultPersonID = 0\n\n\t// key in the mux where the ID is stored\n\tmuxVarID = \"id\"\n)\n\n// GetModel will load a registration\n//go:generate mockery -name=GetModel -case underscore -testonly -inpkg -note @generated\ntype GetModel interface {\n\tDo(ID int) (*data.Person, error)\n}\n\n// GetConfig is the config for the Get Handler\ntype GetConfig interface {\n\tLogger() logging.Logger\n}\n\n// NewGetHandler is the constructor for GetHandler\nfunc NewGetHandler(cfg GetConfig, model GetModel) *GetHandler {\n\treturn &GetHandler{\n\t\tcfg:    cfg,\n\t\tgetter: model,\n\t}\n}\n\n// GetHandler is the HTTP handler for the \"Get Person\" endpoint\n// In this simplified example we are assuming all possible errors are user errors and returning \"bad request\" HTTP 400\n// or \"not found\" HTTP 404\n// There are some programmer errors possible but hopefully these will be caught in testing.\ntype GetHandler struct {\n\tcfg    GetConfig\n\tgetter GetModel\n}\n\n// ServeHTTP implements http.Handler\nfunc (h *GetHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\t// extract person id from request\n\tid, err := h.extractID(request)\n\tif err != nil {\n\t\t// output error\n\t\tresponse.WriteHeader(http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// attempt get\n\tperson, err := h.getter.Do(id)\n\tif err != nil {\n\t\t// not need to log here as we can expect other layers to do so\n\t\tresponse.WriteHeader(http.StatusNotFound)\n\t\treturn\n\t}\n\n\t// happy path\n\terr = h.writeJSON(response, person)\n\tif err != nil {\n\t\t// this error should not happen but if it does there is nothing we can do to recover\n\t\tresponse.WriteHeader(http.StatusInternalServerError)\n\t}\n}\n\n// extract the person ID from the request\nfunc (h *GetHandler) extractID(request *http.Request) (int, error) {\n\t// ID is part of the URL, so we extract it from there\n\tvars := mux.Vars(request)\n\tidAsString, exists := vars[muxVarID]\n\tif !exists {\n\t\t// log and return error\n\t\terr := errors.New(\"[get] person id missing from request\")\n\t\th.cfg.Logger().Warn(err.Error())\n\t\treturn defaultPersonID, err\n\t}\n\n\t// convert ID to int\n\tid, err := strconv.Atoi(idAsString)\n\tif err != nil {\n\t\t// log and return error\n\t\terr = fmt.Errorf(\"[get] failed to convert person id into a number. err: %s\", err)\n\t\th.cfg.Logger().Error(err.Error())\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn id, nil\n}\n\n// output the supplied person as JSON\nfunc (h *GetHandler) writeJSON(writer io.Writer, person *data.Person) error {\n\toutput := &getResponseFormat{\n\t\tID:       person.ID,\n\t\tFullName: person.FullName,\n\t\tPhone:    person.Phone,\n\t\tCurrency: person.Currency,\n\t\tPrice:    person.Price,\n\t}\n\n\t// call to http.ResponseWriter.Write() will cause HTTP OK (200) to be output as well\n\treturn json.NewEncoder(writer).Encode(output)\n}\n\n// the JSON response format\ntype getResponseFormat struct {\n\tID       int     `json:\"id\"`\n\tFullName string  `json:\"name\"`\n\tPhone    string  `json:\"phone\"`\n\tCurrency string  `json:\"currency\"`\n\tPrice    float64 `json:\"price\"`\n}\n"
  },
  {
    "path": "ch09/acme/internal/rest/get_test.go",
    "content": "package rest\n\nimport (\n\t\"errors\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/modules/data\"\n\t\"github.com/gorilla/mux\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestGetHandler_ServeHTTP(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc            string\n\t\tinRequest       func() *http.Request\n\t\tinModelMock     func() *MockGetModel\n\t\texpectedStatus  int\n\t\texpectedPayload string\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/1/\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// set values into request (required by the mux)\n\t\t\t\treturn mux.SetURLVars(req, map[string]string{muxVarID: \"1\"})\n\t\t\t},\n\t\t\tinModelMock: func() *MockGetModel {\n\t\t\t\toutput := &data.Person{\n\t\t\t\t\tID:       1,\n\t\t\t\t\tFullName: \"John\",\n\t\t\t\t\tPhone:    \"0123456789\",\n\t\t\t\t\tCurrency: \"USD\",\n\t\t\t\t\tPrice:    100,\n\t\t\t\t}\n\n\t\t\t\tmockGetModel := &MockGetModel{}\n\t\t\t\tmockGetModel.On(\"Do\", mock.Anything).Return(output, nil).Once()\n\n\t\t\t\treturn mockGetModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusOK,\n\t\t\texpectedPayload: `{\"id\":1,\"name\":\"John\",\"phone\":\"0123456789\",\"currency\":\"USD\",\"price\":100}` + \"\\n\",\n\t\t},\n\t\t{\n\t\t\tdesc: \"bad input (ID is invalid)\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/x/\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// set values into request (required by the mux)\n\t\t\t\treturn mux.SetURLVars(req, map[string]string{muxVarID: \"x\"})\n\t\t\t},\n\t\t\tinModelMock: func() *MockGetModel {\n\t\t\t\t// expect the model not to be called\n\t\t\t\tmockRegisterModel := &MockGetModel{}\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusBadRequest,\n\t\t\texpectedPayload: ``,\n\t\t},\n\t\t{\n\t\t\tdesc: \"bad input (ID is missing)\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person//\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// set values into request (required by the mux)\n\t\t\t\treturn mux.SetURLVars(req, map[string]string{})\n\t\t\t},\n\t\t\tinModelMock: func() *MockGetModel {\n\t\t\t\t// expect the model not to be called\n\t\t\t\tmockRegisterModel := &MockGetModel{}\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusBadRequest,\n\t\t\texpectedPayload: ``,\n\t\t},\n\t\t{\n\t\t\tdesc: \"dependency fail\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/1/\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// set values into request (required by the mux)\n\t\t\t\treturn mux.SetURLVars(req, map[string]string{muxVarID: \"1\"})\n\t\t\t},\n\t\t\tinModelMock: func() *MockGetModel {\n\t\t\t\tmockRegisterModel := &MockGetModel{}\n\t\t\t\tmockRegisterModel.On(\"Do\", mock.Anything).Return(nil, errors.New(\"something failed\")).Once()\n\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusNotFound,\n\t\t\texpectedPayload: ``,\n\t\t},\n\t\t{\n\t\t\tdesc: \"requested registration does not exist\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/1/\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// set values into request (required by the mux)\n\t\t\t\treturn mux.SetURLVars(req, map[string]string{muxVarID: \"1\"})\n\t\t\t},\n\t\t\tinModelMock: func() *MockGetModel {\n\t\t\t\tmockRegisterModel := &MockGetModel{}\n\t\t\t\tmockRegisterModel.On(\"Do\", mock.Anything).Return(nil, errors.New(\"person not found\")).Once()\n\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusNotFound,\n\t\t\texpectedPayload: ``,\n\t\t},\n\t}\n\n\tfor _, s := range scenarios {\n\t\tscenario := s\n\t\tt.Run(scenario.desc, func(t *testing.T) {\n\t\t\t// define model layer mock\n\t\t\tmockGetModel := scenario.inModelMock()\n\n\t\t\t// build handler\n\t\t\thandler := NewGetHandler(&testConfig{}, mockGetModel)\n\n\t\t\t// perform request\n\t\t\tresponse := httptest.NewRecorder()\n\t\t\thandler.ServeHTTP(response, scenario.inRequest())\n\n\t\t\t// validate outputs\n\t\t\trequire.Equal(t, scenario.expectedStatus, response.Code, scenario.desc)\n\n\t\t\tpayload, _ := ioutil.ReadAll(response.Body)\n\t\t\tassert.Equal(t, scenario.expectedPayload, string(payload), scenario.desc)\n\t\t})\n\t}\n}\n\ntype testConfig struct {\n}\n\nfunc (t *testConfig) Logger() logging.Logger {\n\treturn &logging.LoggerStdOut{}\n}\n\nfunc (*testConfig) BindAddress() string {\n\treturn \"0.0.0.0:0\"\n}\n"
  },
  {
    "path": "ch09/acme/internal/rest/list.go",
    "content": "package rest\n\nimport (\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/modules/data\"\n)\n\n// ListModel will load all registrations\n//go:generate mockery -name=ListModel -case underscore -testonly -inpkg -note @generated\ntype ListModel interface {\n\tDo() ([]*data.Person, error)\n}\n\n// NewLister is the constructor for ListHandler\nfunc NewListHandler(model ListModel) *ListHandler {\n\treturn &ListHandler{\n\t\tlister: model,\n\t}\n}\n\n// ListHandler is the HTTP handler for the \"List Do people\" endpoint\n// In this simplified example we are assuming all possible errors are system errors (HTTP 500)\ntype ListHandler struct {\n\tlister ListModel\n}\n\n// ServeHTTP implements http.Handler\nfunc (h *ListHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\t// attempt loadAll\n\tpeople, err := h.lister.Do()\n\tif err != nil {\n\t\t// not need to log here as we can expect other layers to do so\n\t\tresponse.WriteHeader(http.StatusNotFound)\n\t\treturn\n\t}\n\n\t// happy path\n\terr = h.writeJSON(response, people)\n\tif err != nil {\n\t\t// this error should not happen but if it does there is nothing we can do to recover\n\t\tresponse.WriteHeader(http.StatusInternalServerError)\n\t}\n}\n\n// output the result as JSON\nfunc (h *ListHandler) writeJSON(writer io.Writer, people []*data.Person) error {\n\toutput := &listResponseFormat{\n\t\tPeople: make([]*listResponseItemFormat, len(people)),\n\t}\n\n\tfor index, record := range people {\n\t\toutput.People[index] = &listResponseItemFormat{\n\t\t\tID:       record.ID,\n\t\t\tFullName: record.FullName,\n\t\t\tPhone:    record.Phone,\n\t\t}\n\t}\n\n\t// call to http.ResponseWriter.Write() will cause HTTP OK (200) to be output as well\n\treturn json.NewEncoder(writer).Encode(output)\n}\n\ntype listResponseFormat struct {\n\tPeople []*listResponseItemFormat `json:\"people\"`\n}\n\ntype listResponseItemFormat struct {\n\tID       int    `json:\"id\"`\n\tFullName string `json:\"name\"`\n\tPhone    string `json:\"phone\"`\n}\n"
  },
  {
    "path": "ch09/acme/internal/rest/list_test.go",
    "content": "package rest\n\nimport (\n\t\"errors\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestListHandler_ServeHTTP(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc            string\n\t\tinRequest       func() *http.Request\n\t\tinModelMock     func() *MockListModel\n\t\texpectedStatus  int\n\t\texpectedPayload string\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/list\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn req\n\t\t\t},\n\t\t\tinModelMock: func() *MockListModel {\n\t\t\t\toutput := []*data.Person{\n\t\t\t\t\t{\n\t\t\t\t\t\tID:       1,\n\t\t\t\t\t\tFullName: \"John\",\n\t\t\t\t\t\tPhone:    \"0123456789\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tID:       2,\n\t\t\t\t\t\tFullName: \"Paul\",\n\t\t\t\t\t\tPhone:    \"0123456781\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tID:       3,\n\t\t\t\t\t\tFullName: \"George\",\n\t\t\t\t\t\tPhone:    \"0123456782\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tID:       1,\n\t\t\t\t\t\tFullName: \"Ringo\",\n\t\t\t\t\t\tPhone:    \"0123456783\",\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\tmockListModel := &MockListModel{}\n\t\t\t\tmockListModel.On(\"Do\", mock.Anything).Return(output, nil).Once()\n\n\t\t\t\treturn mockListModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusOK,\n\t\t\texpectedPayload: `{\"people\":[{\"id\":1,\"name\":\"John\",\"phone\":\"0123456789\"},{\"id\":2,\"name\":\"Paul\",\"phone\":\"0123456781\"},{\"id\":3,\"name\":\"George\",\"phone\":\"0123456782\"},{\"id\":1,\"name\":\"Ringo\",\"phone\":\"0123456783\"}]}` + \"\\n\",\n\t\t},\n\t\t{\n\t\t\tdesc: \"dependency failure\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/list\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn req\n\t\t\t},\n\t\t\tinModelMock: func() *MockListModel {\n\t\t\t\tmockListModel := &MockListModel{}\n\t\t\t\tmockListModel.On(\"Do\", mock.Anything).Return(nil, errors.New(\"something failed\")).Once()\n\n\t\t\t\treturn mockListModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusNotFound,\n\t\t\texpectedPayload: ``,\n\t\t},\n\t\t{\n\t\t\tdesc: \"no data\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/list\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn req\n\t\t\t},\n\t\t\tinModelMock: func() *MockListModel {\n\t\t\t\t// no data\n\t\t\t\toutput := []*data.Person{}\n\n\t\t\t\tmockListModel := &MockListModel{}\n\t\t\t\tmockListModel.On(\"Do\", mock.Anything).Return(output, nil).Once()\n\n\t\t\t\treturn mockListModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusOK,\n\t\t\texpectedPayload: `{\"people\":[]}` + \"\\n\",\n\t\t},\n\t}\n\n\tfor _, s := range scenarios {\n\t\tscenario := s\n\t\tt.Run(scenario.desc, func(t *testing.T) {\n\t\t\t// define model layer mock\n\t\t\tmockListModel := scenario.inModelMock()\n\n\t\t\t// build handler\n\t\t\thandler := NewListHandler(mockListModel)\n\n\t\t\t// perform request\n\t\t\tresponse := httptest.NewRecorder()\n\t\t\thandler.ServeHTTP(response, scenario.inRequest())\n\n\t\t\t// validate outputs\n\t\t\trequire.Equal(t, scenario.expectedStatus, response.Code, scenario.desc)\n\n\t\t\tpayload, _ := ioutil.ReadAll(response.Body)\n\t\t\tassert.Equal(t, scenario.expectedPayload, string(payload), scenario.desc)\n\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "ch09/acme/internal/rest/mock_get_model_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage rest\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// MockGetModel is an autogenerated mock type for the GetModel type\ntype MockGetModel struct {\n\tmock.Mock\n}\n\n// Do provides a mock function with given fields: ID\nfunc (_m *MockGetModel) Do(ID int) (*data.Person, error) {\n\tret := _m.Called(ID)\n\n\tvar r0 *data.Person\n\tif rf, ok := ret.Get(0).(func(int) *data.Person); ok {\n\t\tr0 = rf(ID)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*data.Person)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(int) error); ok {\n\t\tr1 = rf(ID)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch09/acme/internal/rest/mock_list_model_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage rest\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// MockListModel is an autogenerated mock type for the ListModel type\ntype MockListModel struct {\n\tmock.Mock\n}\n\n// Do provides a mock function with given fields:\nfunc (_m *MockListModel) Do() ([]*data.Person, error) {\n\tret := _m.Called()\n\n\tvar r0 []*data.Person\n\tif rf, ok := ret.Get(0).(func() []*data.Person); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]*data.Person)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func() error); ok {\n\t\tr1 = rf()\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch09/acme/internal/rest/mock_register_model_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage rest\n\nimport (\n\t\"context\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// MockRegisterModel is an autogenerated mock type for the RegisterModel type\ntype MockRegisterModel struct {\n\tmock.Mock\n}\n\n// Do provides a mock function with given fields: ctx, in\nfunc (_m *MockRegisterModel) Do(ctx context.Context, in *data.Person) (int, error) {\n\tret := _m.Called(ctx, in)\n\n\tvar r0 int\n\tif rf, ok := ret.Get(0).(func(context.Context, *data.Person) int); ok {\n\t\tr0 = rf(ctx, in)\n\t} else {\n\t\tr0 = ret.Get(0).(int)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, *data.Person) error); ok {\n\t\tr1 = rf(ctx, in)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch09/acme/internal/rest/not_found.go",
    "content": "package rest\n\nimport (\n\t\"net/http\"\n)\n\nfunc notFoundHandler(response http.ResponseWriter, _ *http.Request) {\n\tresponse.WriteHeader(http.StatusNotFound)\n\t_, _ = response.Write([]byte(`Not found`))\n}\n"
  },
  {
    "path": "ch09/acme/internal/rest/not_found_test.go",
    "content": "package rest\n\nimport (\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestNotFoundHandler_ServeHTTP(t *testing.T) {\n\t// build inputs\n\tresponse := httptest.NewRecorder()\n\trequest := &http.Request{}\n\n\t// call handler\n\tnotFoundHandler(response, request)\n\n\t// validate outputs\n\trequire.Equal(t, http.StatusNotFound, response.Code)\n}\n"
  },
  {
    "path": "ch09/acme/internal/rest/register.go",
    "content": "package rest\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/modules/data\"\n)\n\n// RegisterModel will validate and save a registration\n//go:generate mockery -name=RegisterModel -case underscore -testonly -inpkg -note @generated\ntype RegisterModel interface {\n\tDo(ctx context.Context, in *data.Person) (int, error)\n}\n\n// NewRegisterHandler is the constructor for RegisterHandler\nfunc NewRegisterHandler(model RegisterModel) *RegisterHandler {\n\treturn &RegisterHandler{\n\t\tregisterer: model,\n\t}\n}\n\n// RegisterHandler is the HTTP handler for the \"Register\" endpoint\n// In this simplified example we are assuming all possible errors are user errors and returning \"bad request\" HTTP 400.\n// There are some programmer errors possible but hopefully these will be caught in testing.\ntype RegisterHandler struct {\n\tregisterer RegisterModel\n}\n\n// ServeHTTP implements http.Handler\nfunc (h *RegisterHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\t// set latency budget for this API\n\tsubCtx, cancel := context.WithTimeout(request.Context(), 1500*time.Millisecond)\n\tdefer cancel()\n\n\t// extract payload from request\n\trequestPayload, err := h.extractPayload(request)\n\tif err != nil {\n\t\t// output error\n\t\tresponse.WriteHeader(http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// call the business logic using the request data and context\n\tid, err := h.register(subCtx, requestPayload)\n\tif err != nil {\n\t\t// not need to log here as we can expect other layers to do so\n\t\tresponse.WriteHeader(http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// happy path\n\tresponse.Header().Add(\"Location\", fmt.Sprintf(\"/person/%d/\", id))\n\tresponse.WriteHeader(http.StatusCreated)\n}\n\n// extract payload from request\nfunc (h *RegisterHandler) extractPayload(request *http.Request) (*registerRequest, error) {\n\trequestPayload := &registerRequest{}\n\n\tdecoder := json.NewDecoder(request.Body)\n\terr := decoder.Decode(requestPayload)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn requestPayload, nil\n}\n\n// call the logic layer\nfunc (h *RegisterHandler) register(ctx context.Context, requestPayload *registerRequest) (int, error) {\n\tperson := &data.Person{\n\t\tFullName: requestPayload.FullName,\n\t\tPhone:    requestPayload.Phone,\n\t\tCurrency: requestPayload.Currency,\n\t}\n\n\treturn h.registerer.Do(ctx, person)\n}\n\n// register endpoint request format\ntype registerRequest struct {\n\t// FullName of the person\n\tFullName string `json:\"fullName\"`\n\t// Phone of the person\n\tPhone string `json:\"phone\"`\n\t// Currency the wish to register in\n\tCurrency string `json:\"currency\"`\n}\n"
  },
  {
    "path": "ch09/acme/internal/rest/register_test.go",
    "content": "package rest\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestRegisterHandler_ServeHTTP(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc           string\n\t\tinRequest      func() *http.Request\n\t\tinModelMock    func() *MockRegisterModel\n\t\texpectedStatus int\n\t\texpectedHeader string\n\t}{\n\t\t{\n\t\t\tdesc: \"Happy Path\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\tvalidRequest := buildValidRegisterRequest()\n\t\t\t\trequest, err := http.NewRequest(\"POST\", \"/person/register\", validRequest)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn request\n\t\t\t},\n\t\t\tinModelMock: func() *MockRegisterModel {\n\t\t\t\t// valid downstream configuration\n\t\t\t\tresultID := 1234\n\t\t\t\tvar resultErr error\n\n\t\t\t\tmockRegisterModel := &MockRegisterModel{}\n\t\t\t\tmockRegisterModel.On(\"Do\", mock.Anything, mock.Anything).Return(resultID, resultErr).Once()\n\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus: http.StatusCreated,\n\t\t\texpectedHeader: \"/person/1234/\",\n\t\t},\n\t\t{\n\t\t\tdesc: \"Bad Input / User Error\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\tinvalidRequest := bytes.NewBufferString(`this is not valid JSON`)\n\t\t\t\trequest, err := http.NewRequest(\"POST\", \"/person/register\", invalidRequest)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn request\n\t\t\t},\n\t\t\tinModelMock: func() *MockRegisterModel {\n\t\t\t\t// Dependency should not be called\n\t\t\t\tmockRegisterModel := &MockRegisterModel{}\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus: http.StatusBadRequest,\n\t\t\texpectedHeader: \"\",\n\t\t},\n\t\t{\n\t\t\tdesc: \"Dependency Failure\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\tvalidRequest := buildValidRegisterRequest()\n\t\t\t\trequest, err := http.NewRequest(\"POST\", \"/person/register\", validRequest)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn request\n\t\t\t},\n\t\t\tinModelMock: func() *MockRegisterModel {\n\t\t\t\t// call to the dependency failed\n\t\t\t\tresultErr := errors.New(\"something failed\")\n\n\t\t\t\tmockRegisterModel := &MockRegisterModel{}\n\t\t\t\tmockRegisterModel.On(\"Do\", mock.Anything, mock.Anything).Return(0, resultErr).Once()\n\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus: http.StatusBadRequest,\n\t\t\texpectedHeader: \"\",\n\t\t},\n\t}\n\n\tfor _, s := range scenarios {\n\t\tscenario := s\n\t\tt.Run(scenario.desc, func(t *testing.T) {\n\t\t\t// define model layer mock\n\t\t\tmockRegisterModel := scenario.inModelMock()\n\n\t\t\t// build handler\n\t\t\thandler := NewRegisterHandler(mockRegisterModel)\n\n\t\t\t// perform request\n\t\t\tresponse := httptest.NewRecorder()\n\t\t\thandler.ServeHTTP(response, scenario.inRequest())\n\n\t\t\t// validate outputs\n\t\t\trequire.Equal(t, scenario.expectedStatus, response.Code)\n\n\t\t\t// call should output the location to the new person\n\t\t\tresultHeader := response.Header().Get(\"Location\")\n\t\t\tassert.Equal(t, scenario.expectedHeader, resultHeader)\n\n\t\t\t// validate the mock was used as we expected\n\t\t\tassert.True(t, mockRegisterModel.AssertExpectations(t))\n\t\t})\n\t}\n}\n\nfunc buildValidRegisterRequest() io.Reader {\n\trequestData := &registerRequest{\n\t\tFullName: \"Joan Smith\",\n\t\tCurrency: \"AUD\",\n\t\tPhone:    \"01234567890\",\n\t}\n\n\tdata, _ := json.Marshal(requestData)\n\treturn bytes.NewBuffer(data)\n}\n"
  },
  {
    "path": "ch09/acme/internal/rest/server.go",
    "content": "package rest\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/logging\"\n\t\"github.com/gorilla/mux\"\n)\n\n// Config is the config for the REST package\ntype Config interface {\n\tLogger() logging.Logger\n\tBindAddress() string\n}\n\n// New will create and initialize the server\nfunc New(cfg Config,\n\tgetModel GetModel,\n\tlistModel ListModel,\n\tregisterModel RegisterModel) *Server {\n\n\treturn &Server{\n\t\taddress:         cfg.BindAddress(),\n\t\thandlerGet:      NewGetHandler(cfg, getModel),\n\t\thandlerList:     NewListHandler(listModel),\n\t\thandlerNotFound: notFoundHandler,\n\t\thandlerRegister: NewRegisterHandler(registerModel),\n\t}\n}\n\n// Server is the HTTP REST server\ntype Server struct {\n\taddress string\n\tserver  *http.Server\n\n\thandlerGet      http.Handler\n\thandlerList     http.Handler\n\thandlerNotFound http.HandlerFunc\n\thandlerRegister http.Handler\n}\n\n// Listen will start a HTTP rest for this service\nfunc (s *Server) Listen(stop <-chan struct{}) {\n\trouter := s.buildRouter()\n\n\t// create the HTTP server\n\ts.server = &http.Server{\n\t\tHandler: router,\n\t\tAddr:    s.address,\n\t}\n\n\t// listen for shutdown\n\tgo func() {\n\t\t// wait for shutdown signal\n\t\t<-stop\n\n\t\t_ = s.server.Close()\n\t}()\n\n\t// start the HTTP server\n\t_ = s.server.ListenAndServe()\n}\n\n// configure the endpoints to handlers\nfunc (s *Server) buildRouter() http.Handler {\n\trouter := mux.NewRouter()\n\n\t// map URL endpoints to HTTP handlers\n\trouter.Handle(\"/person/{id}/\", s.handlerGet).Methods(\"GET\")\n\trouter.Handle(\"/person/list\", s.handlerList).Methods(\"GET\")\n\trouter.Handle(\"/person/register\", s.handlerRegister).Methods(\"POST\")\n\n\t// convert a \"catch all\" not found handler\n\trouter.NotFoundHandler = s.handlerNotFound\n\n\treturn router\n}\n"
  },
  {
    "path": "ch09/acme/main.go",
    "content": "package main\n\nimport (\n\t\"context\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/config\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/modules/exchange\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/modules/get\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/modules/list\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/modules/register\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch09/acme/internal/rest\"\n)\n\nfunc main() {\n\t// bind stop channel to context\n\tctx := context.Background()\n\n\t// build the exchanger\n\texchanger := exchange.NewConverter(config.App)\n\n\t// build model layer\n\tgetModel := get.NewGetter(config.App)\n\tlistModel := list.NewLister(config.App)\n\tregisterModel := register.NewRegisterer(config.App, exchanger)\n\n\t// start REST server\n\tserver := rest.New(config.App, getModel, listModel, registerModel)\n\tserver.Listen(ctx.Done())\n}\n"
  },
  {
    "path": "ch09/fake.go",
    "content": "package ch09\n\nfunc init() {\n\t// This file is included so that Go tools (like `go list`) will find Go code in this directory and not error\n}\n"
  },
  {
    "path": "ch10/01_intro_to_wire/01_simple/main.go",
    "content": "package main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/google/wire\"\n)\n\nfunc main() {\n\tf := initializeDeps()\n\n\tresult, err := f.GoFetch()\n\tfmt.Printf(\"Result: %s / %s\", result, err)\n}\n\n// list of wire enabled dependencies\nvar wireSet = wire.NewSet(ProvideFetcher)\n\n// Provider\nfunc ProvideFetcher() *Fetcher {\n\treturn &Fetcher{}\n}\n\n// Object being \"provided\"\ntype Fetcher struct {\n}\n\nfunc (f *Fetcher) GoFetch() (string, error) {\n\treturn \"\", errors.New(\"not implemented yet\")\n}\n"
  },
  {
    "path": "ch10/01_intro_to_wire/01_simple/wire.go",
    "content": "//+build wireinject\n\npackage main\n\nimport (\n\t\"github.com/google/wire\"\n)\n\n// The build tag makes sure the stub is not built in the final build.\n\nfunc initializeDeps() *Fetcher {\n\twire.Build(wireSet)\n\treturn nil\n}\n"
  },
  {
    "path": "ch10/01_intro_to_wire/01_simple/wire_gen.go",
    "content": "// Code generated by Wire. DO NOT EDIT.\n\n//go:generate wire\n//+build !wireinject\n\npackage main\n\n// Injectors from wire.go:\n\nfunc initializeDeps() *Fetcher {\n\tfetcher := ProvideFetcher()\n\treturn fetcher\n}\n"
  },
  {
    "path": "ch10/01_intro_to_wire/02_params/main.go",
    "content": "package main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/google/wire\"\n)\n\nfunc main() {\n\tf := initializeDeps()\n\n\tresult, err := f.GoFetch()\n\tfmt.Printf(\"Result: %s / %s\", result, err)\n}\n\n// list of wire enabled dependencies\nvar wireSet = wire.NewSet(ProvideFetcher, ProvideCache)\n\n// Providers\nfunc ProvideFetcher(cache *Cache) *Fetcher {\n\treturn &Fetcher{\n\t\tcache: cache,\n\t}\n}\n\nfunc ProvideCache() *Cache {\n\treturn &Cache{}\n}\n\ntype Cache struct{}\n\nfunc (c *Cache) Get(key string) (string, error) {\n\treturn \"\", errors.New(\"not implemented yet\")\n}\n\nfunc (c *Cache) Set(key string, value string) error {\n\treturn errors.New(\"not implemented\")\n}\n\ntype Fetcher struct {\n\tcache *Cache\n}\n\nfunc (f *Fetcher) GoFetch() (string, error) {\n\treturn \"\", errors.New(\"not implemented yet\")\n}\n"
  },
  {
    "path": "ch10/01_intro_to_wire/02_params/wire.go",
    "content": "//+build wireinject\n\npackage main\n\nimport (\n\t\"github.com/google/wire\"\n)\n\n// The build tag makes sure the stub is not built in the final build.\n\nfunc initializeDeps() *Fetcher {\n\twire.Build(wireSet)\n\treturn nil\n}\n"
  },
  {
    "path": "ch10/01_intro_to_wire/02_params/wire_gen.go",
    "content": "// Code generated by Wire. DO NOT EDIT.\n\n//go:generate wire\n//+build !wireinject\n\npackage main\n\n// Injectors from wire.go:\n\nfunc initializeDeps() *Fetcher {\n\tcache := ProvideCache()\n\tfetcher := ProvideFetcher(cache)\n\treturn fetcher\n}\n"
  },
  {
    "path": "ch10/01_intro_to_wire/03_error/main.go",
    "content": "package main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/google/wire\"\n)\n\nfunc main() {\n\tf, err := initializeDeps()\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\n\tresult, err := f.GoFetch()\n\tfmt.Printf(\"Result: %s / %s\", result, err)\n}\n\n// list of wire enabled dependencies\nvar wireSet = wire.NewSet(ProvideFetcher, ProvideCache)\n\n// Providers\nfunc ProvideFetcher(cache *Cache) *Fetcher {\n\treturn &Fetcher{\n\t\tcache: cache,\n\t}\n}\n\nfunc ProvideCache() (*Cache, error) {\n\tcache := &Cache{}\n\n\terr := cache.Start()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn cache, nil\n}\n\ntype Cache struct{}\n\nfunc (c *Cache) Start() error {\n\treturn errors.New(\"not implemented yet\")\n}\n\nfunc (c *Cache) Get(key string) (string, error) {\n\treturn \"\", errors.New(\"not implemented yet\")\n}\n\nfunc (c *Cache) Set(key string, value string) error {\n\treturn errors.New(\"not implemented\")\n}\n\ntype Fetcher struct {\n\tcache *Cache\n}\n\nfunc (f *Fetcher) GoFetch() (string, error) {\n\treturn \"\", errors.New(\"not implemented yet\")\n}\n"
  },
  {
    "path": "ch10/01_intro_to_wire/03_error/wire.go",
    "content": "//+build wireinject\n\npackage main\n\nimport (\n\t\"github.com/google/wire\"\n)\n\n// The build tag makes sure the stub is not built in the final build.\n\nfunc initializeDeps() (*Fetcher, error) {\n\twire.Build(wireSet)\n\treturn nil, nil\n}\n"
  },
  {
    "path": "ch10/01_intro_to_wire/03_error/wire_gen.go",
    "content": "// Code generated by Wire. DO NOT EDIT.\n\n//go:generate wire\n//+build !wireinject\n\npackage main\n\n// Injectors from wire.go:\n\nfunc initializeDeps() (*Fetcher, error) {\n\tcache, err := ProvideCache()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfetcher := ProvideFetcher(cache)\n\treturn fetcher, nil\n}\n"
  },
  {
    "path": "ch10/01_intro_to_wire/04_without_pset/main.go",
    "content": "//+build ignore\n// Code above this line should be ignored as it's not part of the example\n\npackage main\n\nimport (\n\t\"context\"\n\t\"os\"\n)\n\nfunc main() {\n\t// bind stop channel to context\n\tctx := context.Background()\n\n\t// start REST server\n\tserver, err := initializeServer()\n\tif err != nil {\n\t\tos.Exit(-1)\n\t}\n\n\tserver.Listen(ctx.Done())\n}\n"
  },
  {
    "path": "ch10/01_intro_to_wire/04_without_pset/wire.go",
    "content": "//+build ignore\n// Code above this line should be ignored as it's not part of the example\n\n//+build wireinject\n\npackage main\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/config\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/exchange\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/get\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/list\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/register\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/rest\"\n\t\"github.com/google/wire\"\n)\n\n// The build tag makes sure the stub is not built in the final build.\n\nfunc initializeServer() (*rest.Server, error) {\n\twire.Build(\n\t\t// *config.Config\n\t\tconfig.Load,\n\n\t\t// *exchange.Converter\n\t\twire.Bind(new(exchange.Config), &config.Config{}),\n\t\texchange.NewConverter,\n\n\t\t// *get.Getter\n\t\twire.Bind(new(get.Config), &config.Config{}),\n\t\tget.NewGetter,\n\n\t\t// *list.Lister\n\t\twire.Bind(new(list.Config), &config.Config{}),\n\t\tlist.NewLister,\n\n\t\t// *register.Registerer\n\t\twire.Bind(new(register.Config), &config.Config{}),\n\t\twire.Bind(new(register.Exchanger), &exchange.Converter{}),\n\t\tregister.NewRegisterer,\n\n\t\t// *rest.Server\n\t\twire.Bind(new(rest.Config), &config.Config{}),\n\t\twire.Bind(new(rest.GetModel), &get.Getter{}),\n\t\twire.Bind(new(rest.ListModel), &list.Lister{}),\n\t\twire.Bind(new(rest.RegisterModel), &register.Registerer{}),\n\t\trest.New,\n\t)\n\n\treturn nil, nil\n}\n"
  },
  {
    "path": "ch10/01_intro_to_wire/04_without_pset/wire_gen.go",
    "content": "//+build ignore\n// Code above this line should be ignored as it's not part of the example\n\n// Code generated by Wire. DO NOT EDIT.\n\n//go:generate wire\n//+build !wireinject\n\npackage main\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/config\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/exchange\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/get\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/list\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/register\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/rest\"\n)\n\n// Injectors from wire.go:\n\nfunc initializeServer() (*rest.Server, error) {\n\tconfigConfig, err := config.Load()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tgetter := get.NewGetter(configConfig)\n\tlister := list.NewLister(configConfig)\n\tconverter := exchange.NewConverter(configConfig)\n\tregisterer := register.NewRegisterer(configConfig, converter)\n\tserver := rest.New(configConfig, getter, lister, registerer)\n\treturn server, nil\n}\n"
  },
  {
    "path": "ch10/02_advantages/01_dig/main.go",
    "content": "//+build ignore\n// Code above this line should be ignored as it's not part of the example\n\npackage main\n\nimport (\n\t\"context\"\n\t\"os\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/config\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/exchange\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/get\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/list\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/register\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/rest\"\n\t\"go.uber.org/dig\"\n)\n\nfunc main() {\n\t// bind stop channel to context\n\tctx := context.Background()\n\n\t// build DIG container\n\tcontainer := BuildContainer()\n\n\t// start REST server\n\terr := container.Invoke(func(server *rest.Server) {\n\t\tserver.Listen(ctx.Done())\n\t})\n\n\tif err != nil {\n\t\tos.Exit(-1)\n\t}\n}\n\nfunc BuildContainer() *dig.Container {\n\tcontainer := dig.New()\n\n\tcontainer.Provide(config.Load)\n\tcontainer.Provide(exchange.NewConverter)\n\tcontainer.Provide(get.NewGetter)\n\tcontainer.Provide(list.NewLister)\n\tcontainer.Provide(register.NewRegisterer)\n\tcontainer.Provide(rest.New)\n\n\treturn container\n}\n"
  },
  {
    "path": "ch10/02_advantages/02_instantiation_order/handler.go",
    "content": "package main\n\nimport (\n\t\"net/http\"\n)\n\nfunc NewGetPersonHandler(model *GetPersonModel) *GetPersonHandler {\n\treturn &GetPersonHandler{\n\t\tmodel: model,\n\t}\n}\n\ntype GetPersonHandler struct {\n\tmodel *GetPersonModel\n}\n\nfunc (g *GetPersonHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\tresponse.WriteHeader(http.StatusInternalServerError)\n\tresponse.Write([]byte(`not implemented yet`))\n}\n"
  },
  {
    "path": "ch10/02_advantages/02_instantiation_order/injectors.go",
    "content": "//+build wireinject\n\npackage main\n\nimport (\n\t\"github.com/google/wire\"\n)\n\n// The build tag makes sure the stub is not built in the final build.\n\nfunc initializeDeps() *GetPersonHandler {\n\twire.Build(wireSet)\n\treturn nil\n}\n"
  },
  {
    "path": "ch10/02_advantages/02_instantiation_order/main.go",
    "content": "package main\n\nfunc main() {\n\t// something fantastic goes here!\n}\n"
  },
  {
    "path": "ch10/02_advantages/02_instantiation_order/model.go",
    "content": "package main\n\nimport (\n\t\"database/sql\"\n\t\"errors\"\n)\n\nfunc NewGetPersonModel(db *sql.DB) *GetPersonModel {\n\treturn &GetPersonModel{\n\t\tdb: db,\n\t}\n}\n\ntype GetPersonModel struct {\n\tdb *sql.DB\n}\n\nfunc (g *GetPersonModel) LoadByID(ID int) (*Person, error) {\n\treturn nil, errors.New(\"not implemented yet\")\n}\n\ntype Person struct {\n\tName string\n}\n"
  },
  {
    "path": "ch10/02_advantages/02_instantiation_order/providers.go",
    "content": "package main\n\nimport (\n\t\"database/sql\"\n\n\t\"github.com/google/wire\"\n)\n\nfunc ProvideHandler(model *GetPersonModel) *GetPersonHandler {\n\treturn &GetPersonHandler{\n\t\tmodel: model,\n\t}\n}\n\nfunc ProvideModel(db *sql.DB) *GetPersonModel {\n\treturn &GetPersonModel{\n\t\tdb: db,\n\t}\n}\n\nfunc ProvideDatabase() *sql.DB {\n\treturn &sql.DB{}\n}\n\nvar wireSet = wire.NewSet(\n\tProvideHandler,\n\tProvideModel,\n\tProvideDatabase,\n)\n"
  },
  {
    "path": "ch10/02_advantages/02_instantiation_order/wire_gen.go",
    "content": "// Code generated by Wire. DO NOT EDIT.\n\n//go:generate wire\n//+build !wireinject\n\npackage main\n\n// Injectors from injectors.go:\n\nfunc initializeDeps() *GetPersonHandler {\n\tdb := ProvideDatabase()\n\tgetPersonModel := ProvideModel(db)\n\tgetPersonHandler := ProvideHandler(getPersonModel)\n\treturn getPersonHandler\n}\n"
  },
  {
    "path": "ch10/03_applying/01_before_config/main.go",
    "content": "//+build ignore\n// Code above this line should be ignored as it's not part of the example\n\npackage main\n\nimport (\n\t\"context\"\n\t\"os\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/config\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/exchange\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/get\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/list\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/register\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/rest\"\n)\n\nfunc main() {\n\t// bind stop channel to context\n\tctx := context.Background()\n\n\t// load config\n\tcfg, err := config.Load(config.DefaultEnvVar)\n\tif err != nil {\n\t\tos.Exit(-1)\n\t}\n\n\t// build the exchanger\n\texchanger := exchange.NewConverter(cfg)\n\n\t// build model layer\n\tgetModel := get.NewGetter(cfg)\n\tlistModel := list.NewLister(cfg)\n\tregisterModel := register.NewRegisterer(cfg, exchanger)\n\n\t// start REST server\n\tserver := rest.New(cfg, getModel, listModel, registerModel)\n\tserver.Listen(ctx.Done())\n}\n"
  },
  {
    "path": "ch10/03_applying/02_after_config/main.go",
    "content": "//+build ignore\n// Code above this line should be ignored as it's not part of the example\n\npackage main\n\nimport (\n\t\"context\"\n\t\"os\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/exchange\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/get\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/list\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/register\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/rest\"\n)\n\nfunc main() {\n\t// bind stop channel to context\n\tctx := context.Background()\n\n\t// load config\n\tcfg, err := initializeConfig()\n\tif err != nil {\n\t\tos.Exit(-1)\n\t}\n\n\t// build the exchanger\n\texchanger := exchange.NewConverter(cfg)\n\n\t// build model layer\n\tgetModel := get.NewGetter(cfg)\n\tlistModel := list.NewLister(cfg)\n\tregisterModel := register.NewRegisterer(cfg, exchanger)\n\n\t// start REST server\n\tserver := rest.New(cfg, getModel, listModel, registerModel)\n\tserver.Listen(ctx.Done())\n}\n"
  },
  {
    "path": "ch10/03_applying/02_after_config/wire.go",
    "content": "//+build ignore\n// Code above this line should be ignored as it's not part of the example\n\n//+build wireinject\n\npackage main\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/config\"\n\t\"github.com/google/wire\"\n)\n\n// The build tag makes sure the stub is not built in the final build.\n\nfunc initializeConfig() (*config.Config, error) {\n\twire.Build(config.Load)\n\treturn nil, nil\n}\n"
  },
  {
    "path": "ch10/03_applying/02_after_config/wire_gen.go",
    "content": "//+build ignore\n// Code above this line should be ignored as it's not part of the example\n\n// Code generated by Wire. DO NOT EDIT.\n\n//go:generate wire\n//+build !wireinject\n\npackage main\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/config\"\n)\n\n// Injectors from wire.go:\n\nfunc initializeConfig() (*config.Config, error) {\n\tconfigConfig, err := config.Load()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn configConfig, nil\n}\n"
  },
  {
    "path": "ch10/03_applying/03_after_exchange/main.go",
    "content": "//+build ignore\n// Code above this line should be ignored as it's not part of the example\n\npackage main\n\nimport (\n\t\"context\"\n\t\"os\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/config\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/exchange\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/get\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/list\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/register\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/rest\"\n\t\"github.com/google/wire\"\n)\n\nfunc main() {\n\t// bind stop channel to context\n\tctx := context.Background()\n\n\t// load config\n\tcfg, err := initializeConfig()\n\tif err != nil {\n\t\tos.Exit(-1)\n\t}\n\n\t// build the exchanger\n\texchanger, err := initializeExchanger()\n\tif err != nil {\n\t\tos.Exit(-1)\n\t}\n\n\t// build model layer\n\tgetModel := get.NewGetter(cfg)\n\tlistModel := list.NewLister(cfg)\n\tregisterModel := register.NewRegisterer(cfg, exchanger)\n\n\t// start REST server\n\tserver := rest.New(cfg, getModel, listModel, registerModel)\n\tserver.Listen(ctx.Done())\n}\n\n// List of wire enabled objects\nvar wireSet = wire.NewSet(\n\t// *config.Config\n\tconfig.Load,\n\n\t// *exchange.Converter\n\twire.Bind(new(exchange.Config), &config.Config{}),\n\texchange.NewConverter,\n)\n"
  },
  {
    "path": "ch10/03_applying/03_after_exchange/wire.go",
    "content": "//+build ignore\n// Code above this line should be ignored as it's not part of the example\n\n//+build wireinject\n\npackage main\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/config\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/exchange\"\n\t\"github.com/google/wire\"\n)\n\n// The build tag makes sure the stub is not built in the final build.\n\nfunc initializeConfig() (*config.Config, error) {\n\twire.Build(wireSet)\n\treturn nil, nil\n}\n\nfunc initializeExchanger() (*exchange.Converter, error) {\n\twire.Build(wireSet)\n\treturn nil, nil\n}\n"
  },
  {
    "path": "ch10/03_applying/04_after_model/main.go",
    "content": "//+build ignore\n// Code above this line should be ignored as it's not part of the example\n\npackage main\n\nimport (\n\t\"context\"\n\t\"os\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/config\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/exchange\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/get\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/list\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/register\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/rest\"\n\t\"github.com/google/wire\"\n)\n\nfunc main() {\n\t// bind stop channel to context\n\tctx := context.Background()\n\n\t// load config\n\tcfg, err := initializeConfig()\n\tif err != nil {\n\t\tos.Exit(-1)\n\t}\n\n\t// build model layer\n\tgetModel, _ := initializeGetter()\n\tlistModel, _ := initializeLister()\n\tregisterModel, _ := initializeRegisterer()\n\n\t// start REST server\n\tserver := rest.New(cfg, getModel, listModel, registerModel)\n\tserver.Listen(ctx.Done())\n}\n\n// List of wire enabled objects\nvar wireSet = wire.NewSet(\n\t// *config.Config\n\tconfig.Load,\n\n\t// *exchange.Converter\n\twire.Bind(new(exchange.Config), &config.Config{}),\n\texchange.NewConverter,\n\n\t// *get.Getter\n\twire.Bind(new(get.Config), &config.Config{}),\n\tget.NewGetter,\n\n\t// *list.Lister\n\twire.Bind(new(list.Config), &config.Config{}),\n\tlist.NewLister,\n\n\t// *register.Registerer\n\twire.Bind(new(register.Config), &config.Config{}),\n\twire.Bind(new(register.Exchanger), &exchange.Converter{}),\n\tregister.NewRegisterer,\n)\n"
  },
  {
    "path": "ch10/03_applying/04_after_model/wire.go",
    "content": "//+build ignore\n// Code above this line should be ignored as it's not part of the example\n\n//+build wireinject\n\npackage main\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/config\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/get\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/list\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/register\"\n\t\"github.com/google/wire\"\n)\n\n// The build tag makes sure the stub is not built in the final build.\n\nfunc initializeConfig() (*config.Config, error) {\n\twire.Build(wireSet)\n\treturn nil, nil\n}\n\nfunc initializeGetter() (*get.Getter, error) {\n\twire.Build(wireSet)\n\treturn nil, nil\n}\n\nfunc initializeLister() (*list.Lister, error) {\n\twire.Build(wireSet)\n\treturn nil, nil\n}\n\nfunc initializeRegisterer() (*register.Registerer, error) {\n\twire.Build(wireSet)\n\treturn nil, nil\n}\n"
  },
  {
    "path": "ch10/03_applying/05_after_rest/main.go",
    "content": "//+build ignore\n// Code above this line should be ignored as it's not part of the example\n\npackage main\n\nimport (\n\t\"context\"\n\t\"os\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/config\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/exchange\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/get\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/list\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/register\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/rest\"\n\t\"github.com/google/wire\"\n)\n\nfunc main() {\n\t// bind stop channel to context\n\tctx := context.Background()\n\n\t// start REST server\n\tserver, err := initializeServer()\n\tif err != nil {\n\t\tos.Exit(-1)\n\t}\n\n\tserver.Listen(ctx.Done())\n}\n\n// List of wire enabled objects\nvar wireSet = wire.NewSet(\n\t// *config.Config\n\tconfig.Load,\n\n\t// *exchange.Converter\n\twire.Bind(new(exchange.Config), &config.Config{}),\n\texchange.NewConverter,\n\n\t// *get.Getter\n\twire.Bind(new(get.Config), &config.Config{}),\n\tget.NewGetter,\n\n\t// *list.Lister\n\twire.Bind(new(list.Config), &config.Config{}),\n\tlist.NewLister,\n\n\t// *register.Registerer\n\twire.Bind(new(register.Config), &config.Config{}),\n\twire.Bind(new(register.Exchanger), &exchange.Converter{}),\n\tregister.NewRegisterer,\n\n\t// *rest.Server\n\twire.Bind(new(rest.Config), &config.Config{}),\n\twire.Bind(new(rest.GetModel), &get.Getter{}),\n\twire.Bind(new(rest.ListModel), &list.Lister{}),\n\twire.Bind(new(rest.RegisterModel), &register.Registerer{}),\n\trest.New,\n)\n"
  },
  {
    "path": "ch10/03_applying/05_after_rest/wire.go",
    "content": "//+build ignore\n// Code above this line should be ignored as it's not part of the example\n\n//+build wireinject\n\npackage main\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/rest\"\n\t\"github.com/google/wire\"\n)\n\n// The build tag makes sure the stub is not built in the final build.\n\nfunc initializeServer() (*rest.Server, error) {\n\twire.Build(wireSet)\n\treturn nil, nil\n}\n"
  },
  {
    "path": "ch10/03_applying/05_after_rest/wire_gen.go",
    "content": "//+build ignore\n// Code above this line should be ignored as it's not part of the example\n\n// Code generated by Wire. DO NOT EDIT.\n\n//go:generate wire\n//+build !wireinject\n\npackage main\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/config\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/exchange\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/get\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/list\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/register\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/rest\"\n)\n\n// Injectors from wire.go:\n\nfunc initializeServer() (*rest.Server, error) {\n\tconfigConfig, err := config.Load()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tgetter := get.NewGetter(configConfig)\n\tlister := list.NewLister(configConfig)\n\tconverter := exchange.NewConverter(configConfig)\n\tregisterer := register.NewRegisterer(configConfig, converter)\n\tserver := rest.New(configConfig, getter, lister, registerer)\n\treturn server, nil\n}\n"
  },
  {
    "path": "ch10/03_applying/06_build_tag.go",
    "content": "//+build myTag\n\npackage main\n\nimport (\n\t\"fmt\"\n)\n\nfunc sayHello() {\n\tfmt.Println(\"Hello World!\")\n}\n"
  },
  {
    "path": "ch10/03_applying/06_build_tag_inverse.go",
    "content": "//+build !myTag\n\npackage main\n\nimport (\n\t\"fmt\"\n)\n\nfunc sayHello() {\n\tfmt.Println(\"Hello Universe!\")\n}\n"
  },
  {
    "path": "ch10/03_applying/06_main.go",
    "content": "package main\n\nfunc main() {\n\tsayHello()\n}\n"
  },
  {
    "path": "ch10/04_disadvantages/01_complexity/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"io/ioutil\"\n\n\t\"go.uber.org/dig\"\n)\n\nconst (\n\tconfigFile = \"config.json\"\n)\n\nfunc main() {\n\tc := dig.New()\n\n\terr := c.Provide(func() (*Config, error) {\n\t\tout := &Config{}\n\t\tbytes, err := ioutil.ReadFile(configFile)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\terr = json.Unmarshal(bytes, out)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn out, nil\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\terr = c.Provide(func(cfg *Config) *Logger {\n\t\treturn &Logger{level: cfg.Level}\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\terr = c.Provide(func(logger *Logger) *Server {\n\t\treturn &Server{logger: logger}\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\terr = c.Invoke(func(server *Server) {\n\t\tserver.Listen()\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n\ntype Config struct {\n\tLevel string\n}\n\ntype Logger struct {\n\tlevel string\n}\n\nfunc (l *Logger) Debug(msg string, args ...interface{}) {\n\t// not implemented\n}\n\nfunc (l *Logger) Warn(msg string, args ...interface{}) {\n\t// not implemented\n}\n\nfunc (l *Logger) Error(msg string, args ...interface{}) {\n\t// not implemented\n}\n\ntype Server struct {\n\tlogger *Logger\n}\n\nfunc (s *Server) Listen() {\n\t// not implemented\n}\n"
  },
  {
    "path": "ch10/acme/internal/config/config.go",
    "content": "package config\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"os\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/logging\"\n)\n\n// DefaultEnvVar is the default environment variable the points to the config file\nconst DefaultEnvVar = \"ACME_CONFIG\"\n\n// Config defines the JSON format for the config file\ntype Config struct {\n\t// DSN is the data source name (format: https://github.com/go-sql-driver/mysql/#dsn-data-source-name)\n\tDSN string\n\n\t// Address is the IP address and port to bind this rest to\n\tAddress string\n\n\t// BasePrice is the price of registration\n\tBasePrice float64\n\n\t// ExchangeRateBaseURL is the server and protocol part of the URL from which to load the exchange rate\n\tExchangeRateBaseURL string\n\n\t// ExchangeRateAPIKey is the API for the exchange rate API\n\tExchangeRateAPIKey string\n\n\t// environmental dependencies\n\tlogger logging.Logger\n}\n\n// Logger returns a reference to the singleton logger\nfunc (c *Config) Logger() logging.Logger {\n\tif c.logger == nil {\n\t\tc.logger = &logging.LoggerStdOut{}\n\t}\n\n\treturn c.logger\n}\n\n// RegistrationBasePrice returns the base price for registrations\nfunc (c *Config) RegistrationBasePrice() float64 {\n\treturn c.BasePrice\n}\n\n// DataDSN returns the DSN\nfunc (c *Config) DataDSN() string {\n\treturn c.DSN\n}\n\n// ExchangeBaseURL returns the Base URL from which we can load exchange rates\nfunc (c *Config) ExchangeBaseURL() string {\n\treturn c.ExchangeRateBaseURL\n}\n\n// ExchangeAPIKey returns the DSN\nfunc (c *Config) ExchangeAPIKey() string {\n\treturn c.ExchangeRateAPIKey\n}\n\n// BindAddress returns the host and port this service should bind to\nfunc (c *Config) BindAddress() string {\n\treturn c.Address\n}\n\n// Load returns the config loaded from environment\nfunc Load() (*Config, error) {\n\tfilename, found := os.LookupEnv(DefaultEnvVar)\n\tif !found {\n\t\terr := fmt.Errorf(\"failed to locate file specified by %s\", DefaultEnvVar)\n\t\tlogging.L.Error(err.Error())\n\t\treturn nil, err\n\t}\n\n\tcfg, err := load(filename)\n\tif err != nil {\n\t\tlogging.L.Error(\"failed to load config with err %s\", err)\n\t\treturn nil, err\n\t}\n\n\treturn cfg, nil\n}\n\nfunc load(filename string) (*Config, error) {\n\tout := &Config{}\n\tbytes, err := ioutil.ReadFile(filename)\n\tif err != nil {\n\t\tlogging.L.Error(\"failed to read config file. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\terr = json.Unmarshal(bytes, out)\n\tif err != nil {\n\t\tlogging.L.Error(\"failed to parse config file. err : %s\", err)\n\t\treturn nil, err\n\t}\n\n\treturn out, nil\n}\n"
  },
  {
    "path": "ch10/acme/internal/config/config_test.go",
    "content": "package config\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestLoad(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc           string\n\t\tin             string\n\t\texpectedConfig *Config\n\t\texpectError    bool\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tin:   \"../../../../default-config.json\",\n\t\t\texpectedConfig: &Config{\n\t\t\t\tDSN:                 \"[insert your db config here]\",\n\t\t\t\tAddress:             \"0.0.0.0:8080\",\n\t\t\t\tBasePrice:           100.00,\n\t\t\t\tExchangeRateBaseURL: \"http://apilayer.net\",\n\t\t\t\tExchangeRateAPIKey:  \"[insert your API key here]\",\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tdesc:           \"invalid path\",\n\t\t\tin:             \"invalid.json\",\n\t\t\texpectedConfig: nil,\n\t\t\texpectError:    true,\n\t\t},\n\t}\n\n\tfor _, s := range scenarios {\n\t\tscenario := s\n\t\tt.Run(scenario.desc, func(t *testing.T) {\n\t\t\tresult, resultErr := load(scenario.in)\n\t\t\trequire.Equal(t, scenario.expectError, resultErr != nil, \"err: %s\", resultErr)\n\t\t\tassert.Equal(t, scenario.expectedConfig, result, scenario.desc)\n\t\t})\n\t}\n\n}\n"
  },
  {
    "path": "ch10/acme/internal/logging/logging.go",
    "content": "package logging\n\nimport (\n\t\"fmt\"\n)\n\n// Logger is our standard interface\ntype Logger interface {\n\tDebug(message string, args ...interface{})\n\tInfo(message string, args ...interface{})\n\tWarn(message string, args ...interface{})\n\tError(message string, args ...interface{})\n}\n\n// L is the global instance of the logger\nvar L = &LoggerStdOut{}\n\n// LoggerStdOut logs to std out\ntype LoggerStdOut struct{}\n\n// Debug logs messages at DEBUG level\nfunc (l LoggerStdOut) Debug(message string, args ...interface{}) {\n\tfmt.Printf(\"[DEBUG] \"+message, args...)\n}\n\n// Info logs messages at INFO level\nfunc (l LoggerStdOut) Info(message string, args ...interface{}) {\n\tfmt.Printf(\"[INFO] \"+message, args...)\n}\n\n// Warn logs messages at WARN level\nfunc (l LoggerStdOut) Warn(message string, args ...interface{}) {\n\tfmt.Printf(\"[WARN] \"+message, args...)\n}\n\n// Error logs messages at ERROR level\nfunc (l LoggerStdOut) Error(message string, args ...interface{}) {\n\tfmt.Printf(\"[ERROR] \"+message, args...)\n}\n"
  },
  {
    "path": "ch10/acme/internal/modules/data/dao.go",
    "content": "package data\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"time\"\n)\n\n// NewDAO will initialize the database connection pool (if not already done) and return a data access object which\n// can be used to interact with the database\nfunc NewDAO(cfg Config) *DAO {\n\t// initialize the db connection pool\n\t_, _ = getDB(cfg)\n\n\treturn &DAO{\n\t\tcfg: cfg,\n\t}\n}\n\n// DAO is a data access object that provides an abstraction over our database interactions.\ntype DAO struct {\n\tcfg Config\n\n\t// Tracker is an optional query timer\n\tTracker QueryTracker\n}\n\n// Load will attempt to load and return a person.\n// It will return ErrNotFound when the requested person does not exist.\n// Any other errors returned are caused by the underlying database or our connection to it.\nfunc (d *DAO) Load(ctx context.Context, ID int) (*Person, error) {\n\t// track processing time\n\tdefer d.getTracker().Track(\"Load\", time.Now())\n\n\tdb, err := getDB(d.cfg)\n\tif err != nil {\n\t\td.cfg.Logger().Error(\"failed to get DB connection. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// set latency budget for the database call\n\tsubCtx, cancel := context.WithTimeout(ctx, 1*time.Second)\n\tdefer cancel()\n\n\t// perform DB select\n\trow := db.QueryRowContext(subCtx, sqlLoadByID, ID)\n\n\t// retrieve columns and populate the person object\n\tout, err := populatePerson(row.Scan)\n\tif err != nil {\n\t\tif err == sql.ErrNoRows {\n\t\t\td.cfg.Logger().Warn(\"failed to load requested person '%d'. err: %s\", ID, err)\n\t\t\treturn nil, ErrNotFound\n\t\t}\n\n\t\td.cfg.Logger().Error(\"failed to convert query result. err: %s\", err)\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\n// LoadAll will attempt to load all people in the database\n// It will return ErrNotFound when there are not people in the database\n// Any other errors returned are caused by the underlying database or our connection to it.\nfunc (d *DAO) LoadAll(ctx context.Context) ([]*Person, error) {\n\t// track processing time\n\tdefer d.getTracker().Track(\"LoadAll\", time.Now())\n\n\tdb, err := getDB(d.cfg)\n\tif err != nil {\n\t\td.cfg.Logger().Error(\"failed to get DB connection. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// set latency budget for the database call\n\tsubCtx, cancel := context.WithTimeout(ctx, 1*time.Second)\n\tdefer cancel()\n\n\t// perform DB select\n\trows, err := db.QueryContext(subCtx, sqlLoadAll)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer func() {\n\t\t_ = rows.Close()\n\t}()\n\n\tvar out []*Person\n\n\tfor rows.Next() {\n\t\t// retrieve columns and populate the person object\n\t\trecord, err := populatePerson(rows.Scan)\n\t\tif err != nil {\n\t\t\td.cfg.Logger().Error(\"failed to convert query result. err: %s\", err)\n\t\t\treturn nil, err\n\t\t}\n\n\t\tout = append(out, record)\n\t}\n\n\tif len(out) == 0 {\n\t\td.cfg.Logger().Warn(\"no people found in the database.\")\n\t\treturn nil, ErrNotFound\n\t}\n\n\treturn out, nil\n}\n\n// Save will save the supplied person and return the ID of the newly created person or an error.\n// Errors returned are caused by the underlying database or our connection to it.\nfunc (d *DAO) Save(ctx context.Context, in *Person) (int, error) {\n\t// track processing time\n\tdefer d.getTracker().Track(\"Save\", time.Now())\n\n\tdb, err := getDB(d.cfg)\n\tif err != nil {\n\t\td.cfg.Logger().Error(\"failed to get DB connection. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\t// set latency budget for the database call\n\tsubCtx, cancel := context.WithTimeout(ctx, 1*time.Second)\n\tdefer cancel()\n\n\t// perform DB insert\n\tresult, err := db.ExecContext(subCtx, sqlInsert, in.FullName, in.Phone, in.Currency, in.Price)\n\tif err != nil {\n\t\td.cfg.Logger().Error(\"failed to save person into DB. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\t// retrieve and return the ID of the person created\n\tid, err := result.LastInsertId()\n\tif err != nil {\n\t\td.cfg.Logger().Error(\"failed to retrieve id of last saved person. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn int(id), nil\n}\n\nfunc (d *DAO) getTracker() QueryTracker {\n\tif d.Tracker == nil {\n\t\td.Tracker = &noopTracker{}\n\t}\n\n\treturn d.Tracker\n}\n"
  },
  {
    "path": "ch10/acme/internal/modules/data/data.go",
    "content": "package data\n\nimport (\n\t\"database/sql\"\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/logging\"\n\t_ \"github.com/go-sql-driver/mysql\"\n)\n\nconst (\n\t// default person id (returned on error)\n\tdefaultPersonID = 0\n\n\t// SQL statements as constants (to reduce duplication and maintenance in tests)\n\tsqlAllColumns = \"id, fullname, phone, currency, price\"\n\tsqlInsert     = \"INSERT INTO person (fullname, phone, currency, price) VALUES (?, ?, ?, ?)\"\n\tsqlLoadAll    = \"SELECT \" + sqlAllColumns + \" FROM person\"\n\tsqlLoadByID   = \"SELECT \" + sqlAllColumns + \" FROM person WHERE id = ? LIMIT 1\"\n)\n\nvar (\n\tdb *sql.DB\n\n\t// ErrNotFound is returned when the no records where matched by the query\n\tErrNotFound = errors.New(\"not found\")\n)\n\n// Config is the configuration for the data package\ntype Config interface {\n\t// Logger returns a reference to the logger\n\tLogger() logging.Logger\n\n\t// DataDSN returns the data source name\n\tDataDSN() string\n}\n\nvar getDB = func(cfg Config) (*sql.DB, error) {\n\tif db == nil {\n\t\tvar err error\n\t\tdb, err = sql.Open(\"mysql\", cfg.DataDSN())\n\t\tif err != nil {\n\t\t\t// if the DB cannot be accessed we are dead\n\t\t\tpanic(err.Error())\n\t\t}\n\t}\n\n\treturn db, nil\n}\n\n// Person is the data transfer object (DTO) for this package\ntype Person struct {\n\t// ID is the unique ID for this person\n\tID int\n\t// FullName is the name of this person\n\tFullName string\n\t// Phone is the phone for this person\n\tPhone string\n\t// Currency is the currency this person has paid in\n\tCurrency string\n\t// Price is the amount (in the above currency) paid by this person\n\tPrice float64\n}\n\n// custom type so we can convert sql results to easily\ntype scanner func(dest ...interface{}) error\n\n// reduce the duplication (and maintenance) between sql.Row and sql.Rows usage\nfunc populatePerson(scanner scanner) (*Person, error) {\n\tout := &Person{}\n\terr := scanner(&out.ID, &out.FullName, &out.Phone, &out.Currency, &out.Price)\n\treturn out, err\n}\n"
  },
  {
    "path": "ch10/acme/internal/modules/data/data_test.go",
    "content": "package data\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"errors\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/DATA-DOG/go-sqlmock\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/logging\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestSave_happyPath(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\t// define a mock db\n\ttestDb, dbMock, err := sqlmock.New()\n\tdefer testDb.Close()\n\trequire.NoError(t, err)\n\n\t// configure the mock db\n\tqueryRegex := convertSQLToRegex(sqlInsert)\n\tdbMock.ExpectExec(queryRegex).WillReturnResult(sqlmock.NewResult(2, 1))\n\n\t// monkey patching starts here\n\tdb = testDb\n\t// end of monkey patch\n\n\t// inputs\n\tin := &Person{\n\t\tFullName: \"Jake Blues\",\n\t\tPhone:    \"01234567890\",\n\t\tCurrency: \"AUD\",\n\t\tPrice:    123.45,\n\t}\n\n\t// call function\n\tdao := NewDAO(&testConfig{})\n\tresultID, err := dao.Save(ctx, in)\n\n\t// validate result\n\trequire.NoError(t, err)\n\tassert.Equal(t, 2, resultID)\n\tassert.NoError(t, dbMock.ExpectationsWereMet())\n}\n\nfunc TestSave_insertError(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\t// define a mock db\n\ttestDb, dbMock, err := sqlmock.New()\n\tdefer testDb.Close()\n\n\trequire.NoError(t, err)\n\n\t// configure the mock db\n\tqueryRegex := convertSQLToRegex(sqlInsert)\n\tdbMock.ExpectExec(queryRegex).WillReturnError(errors.New(\"failed to insert\"))\n\n\t// monkey patching starts here\n\tdb = testDb\n\t// end of monkey patch\n\n\t// inputs\n\tin := &Person{\n\t\tFullName: \"Jake Blues\",\n\t\tPhone:    \"01234567890\",\n\t\tCurrency: \"AUD\",\n\t\tPrice:    123.45,\n\t}\n\n\t// call function\n\tdao := NewDAO(&testConfig{})\n\tresultID, err := dao.Save(ctx, in)\n\n\t// validate result\n\trequire.Error(t, err)\n\tassert.Equal(t, defaultPersonID, resultID)\n\tassert.NoError(t, dbMock.ExpectationsWereMet())\n}\n\nfunc TestSave_getDBError(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\t// monkey patching starts here\n\tdefer func(original func(_ Config) (*sql.DB, error)) {\n\t\t// restore original DB (after test)\n\t\tgetDB = original\n\t}(getDB)\n\n\t// replace getDB() function for this test\n\tgetDB = func(_ Config) (*sql.DB, error) {\n\t\treturn nil, errors.New(\"getDB() failed\")\n\t}\n\t// end of monkey patch\n\n\t// inputs\n\tin := &Person{\n\t\tFullName: \"Jake Blues\",\n\t\tPhone:    \"01234567890\",\n\t\tCurrency: \"AUD\",\n\t\tPrice:    123.45,\n\t}\n\n\t// call function\n\tdao := NewDAO(&testConfig{})\n\tresultID, err := dao.Save(ctx, in)\n\trequire.Error(t, err)\n\tassert.Equal(t, defaultPersonID, resultID)\n}\n\nfunc TestLoadAll_tableDrivenTest(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\n\tdefer cancel()\n\n\tscenarios := []struct {\n\t\tdesc            string\n\t\tconfigureMockDB func(sqlmock.Sqlmock)\n\t\texpectedResults []*Person\n\t\texpectError     bool\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tconfigureMockDB: func(dbMock sqlmock.Sqlmock) {\n\t\t\t\tqueryRegex := convertSQLToRegex(sqlLoadAll)\n\t\t\t\tdbMock.ExpectQuery(queryRegex).WillReturnRows(\n\t\t\t\t\tsqlmock.NewRows(strings.Split(sqlAllColumns, \", \")).\n\t\t\t\t\t\tAddRow(1, \"John\", \"0123456789\", \"AUD\", 12.34))\n\t\t\t},\n\t\t\texpectedResults: []*Person{\n\t\t\t\t{\n\t\t\t\t\tID:       1,\n\t\t\t\t\tFullName: \"John\",\n\t\t\t\t\tPhone:    \"0123456789\",\n\t\t\t\t\tCurrency: \"AUD\",\n\t\t\t\t\tPrice:    12.34,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tdesc: \"load error\",\n\t\t\tconfigureMockDB: func(dbMock sqlmock.Sqlmock) {\n\t\t\t\tqueryRegex := convertSQLToRegex(sqlLoadAll)\n\t\t\t\tdbMock.ExpectQuery(queryRegex).WillReturnError(errors.New(\"something failed\"))\n\t\t\t},\n\t\t\texpectedResults: nil,\n\t\t\texpectError:     true,\n\t\t},\n\t}\n\n\tfor _, scenario := range scenarios {\n\t\t// define a mock db\n\t\ttestDb, dbMock, err := sqlmock.New()\n\t\trequire.NoError(t, err)\n\n\t\t// configure the mock db\n\t\tscenario.configureMockDB(dbMock)\n\n\t\t// monkey patch the db for this test\n\t\toriginal := *db\n\t\tdb = testDb\n\n\t\t// call function\n\t\tdao := NewDAO(&testConfig{})\n\t\tresults, err := dao.LoadAll(ctx)\n\n\t\t// validate results\n\t\tassert.Equal(t, scenario.expectedResults, results, scenario.desc)\n\t\tassert.Equal(t, scenario.expectError, err != nil, scenario.desc)\n\t\tassert.NoError(t, dbMock.ExpectationsWereMet())\n\n\t\t// restore original DB (after test)\n\t\tdb = &original\n\t\ttestDb.Close()\n\t}\n}\n\nfunc TestLoad_tableDrivenTest(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\n\tdefer cancel()\n\n\tscenarios := []struct {\n\t\tdesc            string\n\t\tconfigureMockDB func(sqlmock.Sqlmock)\n\t\texpectedResult  *Person\n\t\texpectError     bool\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tconfigureMockDB: func(dbMock sqlmock.Sqlmock) {\n\t\t\t\tqueryRegex := convertSQLToRegex(sqlLoadAll)\n\t\t\t\tdbMock.ExpectQuery(queryRegex).WillReturnRows(\n\t\t\t\t\tsqlmock.NewRows(strings.Split(sqlAllColumns, \", \")).\n\t\t\t\t\t\tAddRow(2, \"Paul\", \"0123456789\", \"CAD\", 23.45))\n\t\t\t},\n\t\t\texpectedResult: &Person{\n\t\t\t\tID:       2,\n\t\t\t\tFullName: \"Paul\",\n\t\t\t\tPhone:    \"0123456789\",\n\t\t\t\tCurrency: \"CAD\",\n\t\t\t\tPrice:    23.45,\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tdesc: \"load error\",\n\t\t\tconfigureMockDB: func(dbMock sqlmock.Sqlmock) {\n\t\t\t\tqueryRegex := convertSQLToRegex(sqlLoadAll)\n\t\t\t\tdbMock.ExpectQuery(queryRegex).WillReturnError(errors.New(\"something failed\"))\n\t\t\t},\n\t\t\texpectedResult: nil,\n\t\t\texpectError:    true,\n\t\t},\n\t}\n\n\tfor _, scenario := range scenarios {\n\t\t// define a mock db\n\t\ttestDb, dbMock, err := sqlmock.New()\n\t\trequire.NoError(t, err)\n\n\t\t// configure the mock db\n\t\tscenario.configureMockDB(dbMock)\n\n\t\t// monkey db for this test\n\t\toriginal := *db\n\t\tdb = testDb\n\n\t\t// call function\n\t\tdao := NewDAO(&testConfig{})\n\t\tresult, err := dao.Load(ctx, 2)\n\n\t\t// validate results\n\t\tassert.Equal(t, scenario.expectedResult, result, scenario.desc)\n\t\tassert.Equal(t, scenario.expectError, err != nil, scenario.desc)\n\t\tassert.NoError(t, dbMock.ExpectationsWereMet())\n\n\t\t// restore original DB (after test)\n\t\tdb = &original\n\t\ttestDb.Close()\n\t}\n}\n\n// convert SQL string to regex by treating the entire query as a literal\nfunc convertSQLToRegex(in string) string {\n\treturn `\\Q` + in + `\\E`\n}\n\ntype testConfig struct{}\n\n// Logger implements Config\nfunc (t *testConfig) Logger() logging.Logger {\n\treturn logging.LoggerStdOut{}\n}\n\n// DataDSN implements Config\nfunc (t *testConfig) DataDSN() string {\n\treturn \"\"\n}\n"
  },
  {
    "path": "ch10/acme/internal/modules/data/tracker.go",
    "content": "package data\n\nimport (\n\t\"time\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/logging\"\n)\n\n// QueryTracker is an interface to track query timing\ntype QueryTracker interface {\n\t// Track will record/out the time a query took by calculating time.Now().Sub(start)\n\tTrack(key string, start time.Time)\n}\n\n// NO-OP implementation of QueryTracker\ntype noopTracker struct{}\n\n// Track implements QueryTracker\nfunc (_ *noopTracker) Track(_ string, _ time.Time) {\n\t// intentionally does nothing\n}\n\n// NewLogTracker returns a Tracker that outputs tracking data to log\nfunc NewLogTracker(logger logging.Logger) *LogTracker {\n\treturn &LogTracker{\n\t\tlogger: logger,\n\t}\n}\n\n// LogTracker implements QueryTracker and outputs to the supplied logger\ntype LogTracker struct {\n\tlogger logging.Logger\n}\n\n// Track implements QueryTracker\nfunc (l *LogTracker) Track(key string, start time.Time) {\n\tl.logger.Info(\"[%s] Timing: %s\\n\", key, time.Now().Sub(start).String())\n}\n"
  },
  {
    "path": "ch10/acme/internal/modules/exchange/converter.go",
    "content": "package exchange\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"math\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/logging\"\n)\n\nconst (\n\t// request URL for the exchange rate API\n\turlFormat = \"%s/api/historical?access_key=%s&date=2018-06-20&currencies=%s\"\n\n\t// default price that is sent when an error occurs\n\tdefaultPrice = 0.0\n)\n\n// NewConverter creates and initializes the converter\nfunc NewConverter(cfg Config) *Converter {\n\treturn &Converter{\n\t\tcfg: cfg,\n\t}\n}\n\n// Config is the config for Converter\ntype Config interface {\n\tLogger() logging.Logger\n\tExchangeBaseURL() string\n\tExchangeAPIKey() string\n}\n\n// Converter will convert the base price to the currency supplied\n// Note: we are expecting sane inputs and therefore skipping input validation\ntype Converter struct {\n\tcfg Config\n}\n\n// Exchange will perform the conversion\nfunc (c *Converter) Exchange(ctx context.Context, basePrice float64, currency string) (float64, error) {\n\t// load rate from the external API\n\tresponse, err := c.loadRateFromServer(ctx, currency)\n\tif err != nil {\n\t\treturn defaultPrice, err\n\t}\n\n\t// extract rate from response\n\trate, err := c.extractRate(response, currency)\n\tif err != nil {\n\t\treturn defaultPrice, err\n\t}\n\n\t// apply rate and round to 2 decimal places\n\treturn math.Floor((basePrice/rate)*100) / 100, nil\n}\n\n// load rate from the external API\nfunc (c *Converter) loadRateFromServer(ctx context.Context, currency string) (*http.Response, error) {\n\t// build the request\n\turl := fmt.Sprintf(urlFormat,\n\t\tc.cfg.ExchangeBaseURL(),\n\t\tc.cfg.ExchangeAPIKey(),\n\t\tcurrency)\n\n\t// perform request\n\treq, err := http.NewRequest(\"GET\", url, nil)\n\tif err != nil {\n\t\tc.logger().Warn(\"[exchange] failed to create request. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// set latency budget for the upstream call\n\tsubCtx, cancel := context.WithTimeout(ctx, 1*time.Second)\n\tdefer cancel()\n\n\t// replace the default context with our custom one\n\treq = req.WithContext(subCtx)\n\n\t// perform the HTTP request\n\tresponse, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tc.logger().Warn(\"[exchange] failed to load. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\tif response.StatusCode != http.StatusOK {\n\t\terr = fmt.Errorf(\"request failed with code %d\", response.StatusCode)\n\t\tc.logger().Warn(\"[exchange] %s\", err)\n\t\treturn nil, err\n\t}\n\n\treturn response, nil\n}\n\nfunc (c *Converter) extractRate(response *http.Response, currency string) (float64, error) {\n\tdefer func() {\n\t\t_ = response.Body.Close()\n\t}()\n\n\t// extract data from response\n\tdata, err := c.extractResponse(response)\n\tif err != nil {\n\t\treturn defaultPrice, err\n\t}\n\n\t// pull rate from response data\n\trate, found := data.Quotes[\"USD\"+currency]\n\tif !found {\n\t\terr = fmt.Errorf(\"response did not include expected currency '%s'\", currency)\n\t\tc.logger().Error(\"[exchange] %s\", err)\n\t\treturn defaultPrice, err\n\t}\n\n\t// happy path\n\treturn rate, nil\n}\n\nfunc (c *Converter) extractResponse(response *http.Response) (*apiResponseFormat, error) {\n\tpayload, err := ioutil.ReadAll(response.Body)\n\tif err != nil {\n\t\tc.logger().Error(\"[exchange] failed to ready response body. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\tdata := &apiResponseFormat{}\n\terr = json.Unmarshal(payload, data)\n\tif err != nil {\n\t\tc.logger().Error(\"[exchange] error converting response. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// happy path\n\treturn data, nil\n}\n\nfunc (c *Converter) logger() logging.Logger {\n\treturn c.cfg.Logger()\n}\n\n// the response format from the exchange rate API\ntype apiResponseFormat struct {\n\tQuotes map[string]float64 `json:\"quotes\"`\n}\n"
  },
  {
    "path": "ch10/acme/internal/modules/exchange/converter_ext_bounday_test.go",
    "content": "// +build external\n\npackage exchange\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/config\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestExternalBoundaryTest(t *testing.T) {\n\t// define the config\n\tcfg, err := config.Load()\n\trequire.NoError(t, err)\n\n\t// create a converter to test\n\tconverter := NewConverter(cfg)\n\n\t// fetch from the server\n\tresponse, err := converter.loadRateFromServer(context.Background(), \"AUD\")\n\trequire.NotNil(t, response)\n\trequire.NoError(t, err)\n\n\t// parse the response\n\tresultRate, err := converter.extractRate(response, \"AUD\")\n\trequire.NoError(t, err)\n\n\t// validate the result\n\tassert.True(t, resultRate > 0)\n}\n"
  },
  {
    "path": "ch10/acme/internal/modules/exchange/converter_int_bounday_test.go",
    "content": "package exchange\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/logging\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestInternalBoundaryTest(t *testing.T) {\n\t// start our test server\n\tserver := httptest.NewServer(&happyExchangeRateService{})\n\tdefer server.Close()\n\n\t// define the config\n\tcfg := &testConfig{\n\t\tbaseURL: server.URL,\n\t\tapiKey:  \"\",\n\t}\n\n\t// create a converter to test\n\tconverter := NewConverter(cfg)\n\tresultRate, resultErr := converter.Exchange(context.Background(), 100.00, \"AUD\")\n\n\t// validate the result\n\tassert.Equal(t, 101.01, resultRate)\n\tassert.NoError(t, resultErr)\n}\n\ntype happyExchangeRateService struct{}\n\n// ServeHTTP implements http.Handler\nfunc (*happyExchangeRateService) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\tpayload := []byte(`\n{\n   \"success\":true,\n   \"historical\":true,\n   \"date\":\"2010-11-09\",\n   \"timestamp\":1289347199,\n   \"source\":\"USD\",\n   \"quotes\":{\n      \"USDAUD\":0.989981\n   }\n}`)\n\tresponse.Write(payload)\n}\n\n// test implementation of Config\ntype testConfig struct {\n\tbaseURL string\n\tapiKey  string\n}\n\n// Logger implements Config\nfunc (t *testConfig) Logger() logging.Logger {\n\treturn &logging.LoggerStdOut{}\n}\n\n// ExchangeBaseURL implements Config\nfunc (t *testConfig) ExchangeBaseURL() string {\n\treturn t.baseURL\n}\n\n// ExchangeAPIKey implements Config\nfunc (t *testConfig) ExchangeAPIKey() string {\n\treturn t.apiKey\n}\n"
  },
  {
    "path": "ch10/acme/internal/modules/get/get.go",
    "content": "package get\n\nimport (\n\t\"context\"\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/data\"\n)\n\nvar (\n\t// error thrown when the requested person is not in the database\n\terrPersonNotFound = errors.New(\"person not found\")\n)\n\n// NewGetter creates and initializes a Getter\nfunc NewGetter(cfg Config) *Getter {\n\treturn &Getter{\n\t\tcfg: cfg,\n\t}\n}\n\n// Config is the configuration for Getter\ntype Config interface {\n\tLogger() logging.Logger\n\tDataDSN() string\n}\n\n// Getter will attempt to load a person.\n// It can return an error caused by the data layer or when the requested person is not found\ntype Getter struct {\n\tcfg  Config\n\tdata myLoader\n}\n\n// Do will perform the get\nfunc (g *Getter) Do(ID int) (*data.Person, error) {\n\t// load person from the data layer\n\tperson, err := g.getLoader().Load(context.TODO(), ID)\n\tif err != nil {\n\t\tif err == data.ErrNotFound {\n\t\t\t// By converting the error we are hiding the implementation details from our users.\n\t\t\treturn nil, errPersonNotFound\n\t\t}\n\t\treturn nil, err\n\t}\n\n\treturn person, err\n}\n\nfunc (g *Getter) getLoader() myLoader {\n\tif g.data == nil {\n\t\tg.data = data.NewDAO(g.cfg)\n\t}\n\n\treturn g.data\n}\n\n//go:generate mockery -name=myLoader -case underscore -testonly -inpkg -note @generated\ntype myLoader interface {\n\tLoad(ctx context.Context, ID int) (*data.Person, error)\n}\n"
  },
  {
    "path": "ch10/acme/internal/modules/get/go_test.go",
    "content": "package get\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestGetter_Do_happyPath(t *testing.T) {\n\t// inputs\n\tID := 1234\n\n\t// configure the mock loader\n\tmockResult := &data.Person{\n\t\tID:       1234,\n\t\tFullName: \"Doug\",\n\t}\n\tmockLoader := &mockMyLoader{}\n\tmockLoader.On(\"Load\", mock.Anything, ID).Return(mockResult, nil).Once()\n\n\t// call method\n\tgetter := &Getter{\n\t\tdata: mockLoader,\n\t}\n\tperson, err := getter.Do(ID)\n\n\t// validate expectations\n\trequire.NoError(t, err)\n\tassert.Equal(t, ID, person.ID)\n\tassert.Equal(t, \"Doug\", person.FullName)\n\tassert.True(t, mockLoader.AssertExpectations(t))\n}\n\nfunc TestGetter_Do_noSuchPerson(t *testing.T) {\n\t// inputs\n\tID := 5678\n\n\t// configure the mock loader\n\tmockLoader := &mockMyLoader{}\n\tmockLoader.On(\"Load\", mock.Anything, ID).Return(nil, data.ErrNotFound).Once()\n\n\t// call method\n\tgetter := &Getter{\n\t\tdata: mockLoader,\n\t}\n\tperson, err := getter.Do(ID)\n\n\t// validate expectations\n\trequire.Equal(t, errPersonNotFound, err)\n\tassert.Nil(t, person)\n\tassert.True(t, mockLoader.AssertExpectations(t))\n}\n\nfunc TestGetter_Do_error(t *testing.T) {\n\t// inputs\n\tID := 1234\n\n\t// configure the mock loader\n\tmockLoader := &mockMyLoader{}\n\tmockLoader.On(\"Load\", mock.Anything, ID).Return(nil, errors.New(\"something failed\")).Once()\n\n\t// call method\n\tgetter := &Getter{\n\t\tdata: mockLoader,\n\t}\n\tperson, err := getter.Do(ID)\n\n\t// validate expectations\n\trequire.Error(t, err)\n\tassert.Nil(t, person)\n\tassert.True(t, mockLoader.AssertExpectations(t))\n}\n"
  },
  {
    "path": "ch10/acme/internal/modules/get/mock_my_loader_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage get\n\nimport (\n\t\"context\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// mockMyLoader is an autogenerated mock type for the myLoader type\ntype mockMyLoader struct {\n\tmock.Mock\n}\n\n// Load provides a mock function with given fields: ctx, ID\nfunc (_m *mockMyLoader) Load(ctx context.Context, ID int) (*data.Person, error) {\n\tret := _m.Called(ctx, ID)\n\n\tvar r0 *data.Person\n\tif rf, ok := ret.Get(0).(func(context.Context, int) *data.Person); ok {\n\t\tr0 = rf(ctx, ID)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*data.Person)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, int) error); ok {\n\t\tr1 = rf(ctx, ID)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch10/acme/internal/modules/list/list.go",
    "content": "package list\n\nimport (\n\t\"context\"\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/data\"\n)\n\nvar (\n\t// error thrown when there are no people in the database\n\terrPeopleNotFound = errors.New(\"no people found\")\n)\n\n// NewLister creates and initializes a Lister\nfunc NewLister(cfg Config) *Lister {\n\treturn &Lister{\n\t\tcfg: cfg,\n\t}\n}\n\n// Config is the config for Lister\ntype Config interface {\n\tLogger() logging.Logger\n\tDataDSN() string\n}\n\n// Lister will attempt to load all people in the database.\n// It can return an error caused by the data layer\ntype Lister struct {\n\tcfg  Config\n\tdata myLoader\n}\n\n// Exchange will load the people from the data layer\nfunc (l *Lister) Do() ([]*data.Person, error) {\n\t// load all people\n\tpeople, err := l.load()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(people) == 0 {\n\t\t// special processing for 0 people returned\n\t\treturn nil, errPeopleNotFound\n\t}\n\n\treturn people, nil\n}\n\n// load all people\nfunc (l *Lister) load() ([]*data.Person, error) {\n\tpeople, err := l.getLoader().LoadAll(context.TODO())\n\tif err != nil {\n\t\tif err == data.ErrNotFound {\n\t\t\t// By converting the error we are encapsulating the implementation details from our users.\n\t\t\treturn nil, errPeopleNotFound\n\t\t}\n\t\treturn nil, err\n\t}\n\n\treturn people, nil\n}\n\nfunc (l *Lister) getLoader() myLoader {\n\tif l.data == nil {\n\t\tl.data = data.NewDAO(l.cfg)\n\n\t\t// temporarily add a log tracker\n\t\tl.data.(*data.DAO).Tracker = data.NewLogTracker(l.cfg.Logger())\n\t}\n\n\treturn l.data\n}\n\n//go:generate mockery -name=myLoader -case underscore -testonly -inpkg -note @generated\ntype myLoader interface {\n\tLoadAll(ctx context.Context) ([]*data.Person, error)\n}\n"
  },
  {
    "path": "ch10/acme/internal/modules/list/list_test.go",
    "content": "package list\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestLister_Do_happyPath(t *testing.T) {\n\t// configure the mock loader\n\tmockResult := []*data.Person{\n\t\t{\n\t\t\tID:       1234,\n\t\t\tFullName: \"Sally\",\n\t\t},\n\t\t{\n\t\t\tID:       5678,\n\t\t\tFullName: \"Jane\",\n\t\t},\n\t}\n\n\tmockLoader := &mockMyLoader{}\n\tmockLoader.On(\"LoadAll\", mock.Anything).Return(mockResult, nil).Once()\n\n\t// call method\n\tlister := &Lister{\n\t\tdata: mockLoader,\n\t}\n\tpersons, err := lister.load()\n\n\t// validate expectations\n\trequire.NoError(t, err)\n\tassert.Equal(t, 2, len(persons))\n\tassert.True(t, mockLoader.AssertExpectations(t))\n}\n\nfunc TestLister_Do_noResults(t *testing.T) {\n\t// configure the mock loader\n\tmockLoader := &mockMyLoader{}\n\tmockLoader.On(\"LoadAll\", mock.Anything).Return(nil, data.ErrNotFound).Once()\n\n\t// call method\n\tlister := &Lister{\n\t\tdata: mockLoader,\n\t}\n\tpersons, err := lister.load()\n\n\t// validate expectations\n\trequire.Equal(t, errPeopleNotFound, err)\n\tassert.Equal(t, 0, len(persons))\n\tassert.True(t, mockLoader.AssertExpectations(t))\n}\n\nfunc TestLister_Do_error(t *testing.T) {\n\t// configure the mock loader\n\tmockLoader := &mockMyLoader{}\n\tmockLoader.On(\"LoadAll\", mock.Anything).Return(nil, errors.New(\"something failed\")).Once()\n\n\t// call method\n\tlister := &Lister{\n\t\tdata: mockLoader,\n\t}\n\tpersons, err := lister.load()\n\n\t// validate expectations\n\trequire.Error(t, err)\n\tassert.Equal(t, 0, len(persons))\n\tassert.True(t, mockLoader.AssertExpectations(t))\n}\n"
  },
  {
    "path": "ch10/acme/internal/modules/list/mock_my_loader_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage list\n\nimport (\n\t\"context\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// mockMyLoader is an autogenerated mock type for the myLoader type\ntype mockMyLoader struct {\n\tmock.Mock\n}\n\n// LoadAll provides a mock function with given fields: ctx\nfunc (_m *mockMyLoader) LoadAll(ctx context.Context) ([]*data.Person, error) {\n\tret := _m.Called(ctx)\n\n\tvar r0 []*data.Person\n\tif rf, ok := ret.Get(0).(func(context.Context) []*data.Person); ok {\n\t\tr0 = rf(ctx)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]*data.Person)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context) error); ok {\n\t\tr1 = rf(ctx)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch10/acme/internal/modules/register/mock_my_saver_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage register\n\nimport (\n\t\"context\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// mockMySaver is an autogenerated mock type for the mySaver type\ntype mockMySaver struct {\n\tmock.Mock\n}\n\n// Save provides a mock function with given fields: ctx, in\nfunc (_m *mockMySaver) Save(ctx context.Context, in *data.Person) (int, error) {\n\tret := _m.Called(ctx, in)\n\n\tvar r0 int\n\tif rf, ok := ret.Get(0).(func(context.Context, *data.Person) int); ok {\n\t\tr0 = rf(ctx, in)\n\t} else {\n\t\tr0 = ret.Get(0).(int)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, *data.Person) error); ok {\n\t\tr1 = rf(ctx, in)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch10/acme/internal/modules/register/register.go",
    "content": "package register\n\nimport (\n\t\"context\"\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/data\"\n)\n\nconst (\n\t// default person id (returned on error)\n\tdefaultPersonID = 0\n)\n\nvar (\n\t// validation errors\n\terrNameMissing     = errors.New(\"name is missing\")\n\terrPhoneMissing    = errors.New(\"phone is missing\")\n\terrCurrencyMissing = errors.New(\"currency is missing\")\n\terrInvalidCurrency = errors.New(\"currency is invalid, supported types are AUD, CNY, EUR, GBP, JPY, MYR, SGD, USD\")\n\n\t// a little trick to make checking for supported currencies easier\n\tsupportedCurrencies = map[string]struct{}{\n\t\t\"AUD\": {},\n\t\t\"CNY\": {},\n\t\t\"EUR\": {},\n\t\t\"GBP\": {},\n\t\t\"JPY\": {},\n\t\t\"MYR\": {},\n\t\t\"SGD\": {},\n\t\t\"USD\": {},\n\t}\n)\n\n// NewRegisterer creates and initializes a Registerer\nfunc NewRegisterer(cfg Config, exchanger Exchanger) *Registerer {\n\treturn &Registerer{\n\t\tcfg:       cfg,\n\t\texchanger: exchanger,\n\t}\n}\n\n// Exchanger will convert from one currency to another\ntype Exchanger interface {\n\t// Exchange will perform the conversion\n\tExchange(ctx context.Context, basePrice float64, currency string) (float64, error)\n}\n\n// Config is the configuration for the Registerer\ntype Config interface {\n\tLogger() logging.Logger\n\tRegistrationBasePrice() float64\n\tDataDSN() string\n}\n\n// Registerer validates the supplied person, calculates the price in the requested currency and saves the result.\n// It will return an error when:\n// -the person object does not include all the fields\n// -the currency is invalid\n// -the exchange rate cannot be loaded\n// -the data layer throws an error.\ntype Registerer struct {\n\tcfg       Config\n\texchanger Exchanger\n\tdata      mySaver\n}\n\n// Do is API for this struct\nfunc (r *Registerer) Do(ctx context.Context, in *data.Person) (int, error) {\n\t// validate the request\n\terr := r.validateInput(in)\n\tif err != nil {\n\t\tr.logger().Warn(\"input validation failed with err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\t// get price in the requested currency\n\tprice, err := r.getPrice(ctx, in.Currency)\n\tif err != nil {\n\t\treturn defaultPersonID, err\n\t}\n\n\t// save registration\n\tid, err := r.save(ctx, in, price)\n\tif err != nil {\n\t\t// no need to log here as we expect the data layer to do so\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn id, nil\n}\n\n// validate input and return error on fail\nfunc (r *Registerer) validateInput(in *data.Person) error {\n\tif in.FullName == \"\" {\n\t\treturn errNameMissing\n\t}\n\tif in.Phone == \"\" {\n\t\treturn errPhoneMissing\n\t}\n\tif in.Currency == \"\" {\n\t\treturn errCurrencyMissing\n\t}\n\n\tif _, found := supportedCurrencies[in.Currency]; !found {\n\t\treturn errInvalidCurrency\n\t}\n\n\t// happy path\n\treturn nil\n}\n\n// get price in the requested currency\nfunc (r *Registerer) getPrice(ctx context.Context, currency string) (float64, error) {\n\tprice, err := r.exchanger.Exchange(ctx, r.cfg.RegistrationBasePrice(), currency)\n\tif err != nil {\n\t\tr.logger().Warn(\"failed to convert the price. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn price, nil\n}\n\n// save the registration\nfunc (r *Registerer) save(ctx context.Context, in *data.Person, price float64) (int, error) {\n\tperson := &data.Person{\n\t\tFullName: in.FullName,\n\t\tPhone:    in.Phone,\n\t\tCurrency: in.Currency,\n\t\tPrice:    price,\n\t}\n\treturn r.getSaver().Save(ctx, person)\n}\n\nfunc (r *Registerer) getSaver() mySaver {\n\tif r.data == nil {\n\t\tr.data = data.NewDAO(r.cfg)\n\t}\n\n\treturn r.data\n}\n\nfunc (r *Registerer) logger() logging.Logger {\n\treturn r.cfg.Logger()\n}\n\n//go:generate mockery -name=mySaver -case underscore -testonly -inpkg -note @generated\ntype mySaver interface {\n\tSave(ctx context.Context, in *data.Person) (int, error)\n}\n"
  },
  {
    "path": "ch10/acme/internal/modules/register/register_test.go",
    "content": "package register\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestRegisterer_Do_happyPath(t *testing.T) {\n\t// configure the mock saver\n\tmockResult := 888\n\n\tmockSaver := &mockMySaver{}\n\tmockSaver.On(\"Save\", mock.Anything, mock.Anything).Return(mockResult, nil).Once()\n\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\t// inputs\n\tin := &data.Person{\n\t\tFullName: \"Chang\",\n\t\tPhone:    \"11122233355\",\n\t\tCurrency: \"CNY\",\n\t}\n\n\t// call method\n\tregisterer := &Registerer{\n\t\tcfg:       &testConfig{},\n\t\texchanger: &stubExchanger{},\n\t\tdata:      mockSaver,\n\t}\n\tID, err := registerer.Do(ctx, in)\n\n\t// validate expectations\n\trequire.NoError(t, err)\n\tassert.Equal(t, 888, ID)\n\tassert.True(t, mockSaver.AssertExpectations(t))\n}\n\nfunc TestRegisterer_Do_error(t *testing.T) {\n\t// configure the mock saver\n\tmockSaver := &mockMySaver{}\n\tmockSaver.On(\"Save\", mock.Anything, mock.Anything).Return(0, errors.New(\"something failed\")).Once()\n\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\t// inputs\n\tin := &data.Person{\n\t\tFullName: \"Chang\",\n\t\tPhone:    \"11122233355\",\n\t\tCurrency: \"CNY\",\n\t}\n\n\t// call method\n\tregisterer := &Registerer{\n\t\tcfg:       &testConfig{},\n\t\texchanger: &stubExchanger{},\n\t\tdata:      mockSaver,\n\t}\n\tID, err := registerer.Do(ctx, in)\n\n\t// validate expectations\n\trequire.Error(t, err)\n\tassert.Equal(t, 0, ID)\n\tassert.True(t, mockSaver.AssertExpectations(t))\n}\n\n// Stub implementation of Config\ntype testConfig struct{}\n\n// Logger implement Config\nfunc (t *testConfig) Logger() logging.Logger {\n\treturn &logging.LoggerStdOut{}\n}\n\n// RegistrationBasePrice implement Config\nfunc (t *testConfig) RegistrationBasePrice() float64 {\n\treturn 12.34\n}\n\n// DataDSN implements Config\nfunc (t *testConfig) DataDSN() string {\n\treturn \"\"\n}\n\ntype stubExchanger struct{}\n\n// Exchange implements Exchanger\nfunc (s stubExchanger) Exchange(ctx context.Context, basePrice float64, currency string) (float64, error) {\n\treturn 12.34, nil\n}\n"
  },
  {
    "path": "ch10/acme/internal/rest/get.go",
    "content": "package rest\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/data\"\n\t\"github.com/gorilla/mux\"\n)\n\nconst (\n\t// default person id (returned on error)\n\tdefaultPersonID = 0\n\n\t// key in the mux where the ID is stored\n\tmuxVarID = \"id\"\n)\n\n// GetModel will load a registration\n//go:generate mockery -name=GetModel -case underscore -testonly -inpkg -note @generated\ntype GetModel interface {\n\tDo(ID int) (*data.Person, error)\n}\n\n// GetConfig is the config for the Get Handler\ntype GetConfig interface {\n\tLogger() logging.Logger\n}\n\n// NewGetHandler is the constructor for GetHandler\nfunc NewGetHandler(cfg GetConfig, model GetModel) *GetHandler {\n\treturn &GetHandler{\n\t\tcfg:    cfg,\n\t\tgetter: model,\n\t}\n}\n\n// GetHandler is the HTTP handler for the \"Get Person\" endpoint\n// In this simplified example we are assuming all possible errors are user errors and returning \"bad request\" HTTP 400\n// or \"not found\" HTTP 404\n// There are some programmer errors possible but hopefully these will be caught in testing.\ntype GetHandler struct {\n\tcfg    GetConfig\n\tgetter GetModel\n}\n\n// ServeHTTP implements http.Handler\nfunc (h *GetHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\t// extract person id from request\n\tid, err := h.extractID(request)\n\tif err != nil {\n\t\t// output error\n\t\tresponse.WriteHeader(http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// attempt get\n\tperson, err := h.getter.Do(id)\n\tif err != nil {\n\t\t// not need to log here as we can expect other layers to do so\n\t\tresponse.WriteHeader(http.StatusNotFound)\n\t\treturn\n\t}\n\n\t// happy path\n\terr = h.writeJSON(response, person)\n\tif err != nil {\n\t\t// this error should not happen but if it does there is nothing we can do to recover\n\t\tresponse.WriteHeader(http.StatusInternalServerError)\n\t}\n}\n\n// extract the person ID from the request\nfunc (h *GetHandler) extractID(request *http.Request) (int, error) {\n\t// ID is part of the URL, so we extract it from there\n\tvars := mux.Vars(request)\n\tidAsString, exists := vars[muxVarID]\n\tif !exists {\n\t\t// log and return error\n\t\terr := errors.New(\"[get] person id missing from request\")\n\t\th.cfg.Logger().Warn(err.Error())\n\t\treturn defaultPersonID, err\n\t}\n\n\t// convert ID to int\n\tid, err := strconv.Atoi(idAsString)\n\tif err != nil {\n\t\t// log and return error\n\t\terr = fmt.Errorf(\"[get] failed to convert person id into a number. err: %s\", err)\n\t\th.cfg.Logger().Error(err.Error())\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn id, nil\n}\n\n// output the supplied person as JSON\nfunc (h *GetHandler) writeJSON(writer io.Writer, person *data.Person) error {\n\toutput := &getResponseFormat{\n\t\tID:       person.ID,\n\t\tFullName: person.FullName,\n\t\tPhone:    person.Phone,\n\t\tCurrency: person.Currency,\n\t\tPrice:    person.Price,\n\t}\n\n\t// call to http.ResponseWriter.Write() will cause HTTP OK (200) to be output as well\n\treturn json.NewEncoder(writer).Encode(output)\n}\n\n// the JSON response format\ntype getResponseFormat struct {\n\tID       int     `json:\"id\"`\n\tFullName string  `json:\"name\"`\n\tPhone    string  `json:\"phone\"`\n\tCurrency string  `json:\"currency\"`\n\tPrice    float64 `json:\"price\"`\n}\n"
  },
  {
    "path": "ch10/acme/internal/rest/get_test.go",
    "content": "package rest\n\nimport (\n\t\"errors\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/data\"\n\t\"github.com/gorilla/mux\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestGetHandler_ServeHTTP(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc            string\n\t\tinRequest       func() *http.Request\n\t\tinModelMock     func() *MockGetModel\n\t\texpectedStatus  int\n\t\texpectedPayload string\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/1/\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// set values into request (required by the mux)\n\t\t\t\treturn mux.SetURLVars(req, map[string]string{muxVarID: \"1\"})\n\t\t\t},\n\t\t\tinModelMock: func() *MockGetModel {\n\t\t\t\toutput := &data.Person{\n\t\t\t\t\tID:       1,\n\t\t\t\t\tFullName: \"John\",\n\t\t\t\t\tPhone:    \"0123456789\",\n\t\t\t\t\tCurrency: \"USD\",\n\t\t\t\t\tPrice:    100,\n\t\t\t\t}\n\n\t\t\t\tmockGetModel := &MockGetModel{}\n\t\t\t\tmockGetModel.On(\"Do\", mock.Anything).Return(output, nil).Once()\n\n\t\t\t\treturn mockGetModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusOK,\n\t\t\texpectedPayload: `{\"id\":1,\"name\":\"John\",\"phone\":\"0123456789\",\"currency\":\"USD\",\"price\":100}` + \"\\n\",\n\t\t},\n\t\t{\n\t\t\tdesc: \"bad input (ID is invalid)\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/x/\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// set values into request (required by the mux)\n\t\t\t\treturn mux.SetURLVars(req, map[string]string{muxVarID: \"x\"})\n\t\t\t},\n\t\t\tinModelMock: func() *MockGetModel {\n\t\t\t\t// expect the model not to be called\n\t\t\t\tmockRegisterModel := &MockGetModel{}\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusBadRequest,\n\t\t\texpectedPayload: ``,\n\t\t},\n\t\t{\n\t\t\tdesc: \"bad input (ID is missing)\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person//\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// set values into request (required by the mux)\n\t\t\t\treturn mux.SetURLVars(req, map[string]string{})\n\t\t\t},\n\t\t\tinModelMock: func() *MockGetModel {\n\t\t\t\t// expect the model not to be called\n\t\t\t\tmockRegisterModel := &MockGetModel{}\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusBadRequest,\n\t\t\texpectedPayload: ``,\n\t\t},\n\t\t{\n\t\t\tdesc: \"dependency fail\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/1/\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// set values into request (required by the mux)\n\t\t\t\treturn mux.SetURLVars(req, map[string]string{muxVarID: \"1\"})\n\t\t\t},\n\t\t\tinModelMock: func() *MockGetModel {\n\t\t\t\tmockRegisterModel := &MockGetModel{}\n\t\t\t\tmockRegisterModel.On(\"Do\", mock.Anything).Return(nil, errors.New(\"something failed\")).Once()\n\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusNotFound,\n\t\t\texpectedPayload: ``,\n\t\t},\n\t\t{\n\t\t\tdesc: \"requested registration does not exist\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/1/\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// set values into request (required by the mux)\n\t\t\t\treturn mux.SetURLVars(req, map[string]string{muxVarID: \"1\"})\n\t\t\t},\n\t\t\tinModelMock: func() *MockGetModel {\n\t\t\t\tmockRegisterModel := &MockGetModel{}\n\t\t\t\tmockRegisterModel.On(\"Do\", mock.Anything).Return(nil, errors.New(\"person not found\")).Once()\n\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusNotFound,\n\t\t\texpectedPayload: ``,\n\t\t},\n\t}\n\n\tfor _, s := range scenarios {\n\t\tscenario := s\n\t\tt.Run(scenario.desc, func(t *testing.T) {\n\t\t\t// define model layer mock\n\t\t\tmockGetModel := scenario.inModelMock()\n\n\t\t\t// build handler\n\t\t\thandler := NewGetHandler(&testConfig{}, mockGetModel)\n\n\t\t\t// perform request\n\t\t\tresponse := httptest.NewRecorder()\n\t\t\thandler.ServeHTTP(response, scenario.inRequest())\n\n\t\t\t// validate outputs\n\t\t\trequire.Equal(t, scenario.expectedStatus, response.Code, scenario.desc)\n\n\t\t\tpayload, _ := ioutil.ReadAll(response.Body)\n\t\t\tassert.Equal(t, scenario.expectedPayload, string(payload), scenario.desc)\n\t\t})\n\t}\n}\n\ntype testConfig struct {\n}\n\nfunc (t *testConfig) Logger() logging.Logger {\n\treturn &logging.LoggerStdOut{}\n}\n\nfunc (*testConfig) BindAddress() string {\n\treturn \"0.0.0.0:0\"\n}\n"
  },
  {
    "path": "ch10/acme/internal/rest/list.go",
    "content": "package rest\n\nimport (\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/data\"\n)\n\n// ListModel will load all registrations\n//go:generate mockery -name=ListModel -case underscore -testonly -inpkg -note @generated\ntype ListModel interface {\n\tDo() ([]*data.Person, error)\n}\n\n// NewLister is the constructor for ListHandler\nfunc NewListHandler(model ListModel) *ListHandler {\n\treturn &ListHandler{\n\t\tlister: model,\n\t}\n}\n\n// ListHandler is the HTTP handler for the \"List Do people\" endpoint\n// In this simplified example we are assuming all possible errors are system errors (HTTP 500)\ntype ListHandler struct {\n\tlister ListModel\n}\n\n// ServeHTTP implements http.Handler\nfunc (h *ListHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\t// attempt loadAll\n\tpeople, err := h.lister.Do()\n\tif err != nil {\n\t\t// not need to log here as we can expect other layers to do so\n\t\tresponse.WriteHeader(http.StatusNotFound)\n\t\treturn\n\t}\n\n\t// happy path\n\terr = h.writeJSON(response, people)\n\tif err != nil {\n\t\t// this error should not happen but if it does there is nothing we can do to recover\n\t\tresponse.WriteHeader(http.StatusInternalServerError)\n\t}\n}\n\n// output the result as JSON\nfunc (h *ListHandler) writeJSON(writer io.Writer, people []*data.Person) error {\n\toutput := &listResponseFormat{\n\t\tPeople: make([]*listResponseItemFormat, len(people)),\n\t}\n\n\tfor index, record := range people {\n\t\toutput.People[index] = &listResponseItemFormat{\n\t\t\tID:       record.ID,\n\t\t\tFullName: record.FullName,\n\t\t\tPhone:    record.Phone,\n\t\t}\n\t}\n\n\t// call to http.ResponseWriter.Write() will cause HTTP OK (200) to be output as well\n\treturn json.NewEncoder(writer).Encode(output)\n}\n\ntype listResponseFormat struct {\n\tPeople []*listResponseItemFormat `json:\"people\"`\n}\n\ntype listResponseItemFormat struct {\n\tID       int    `json:\"id\"`\n\tFullName string `json:\"name\"`\n\tPhone    string `json:\"phone\"`\n}\n"
  },
  {
    "path": "ch10/acme/internal/rest/list_test.go",
    "content": "package rest\n\nimport (\n\t\"errors\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestListHandler_ServeHTTP(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc            string\n\t\tinRequest       func() *http.Request\n\t\tinModelMock     func() *MockListModel\n\t\texpectedStatus  int\n\t\texpectedPayload string\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/list\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn req\n\t\t\t},\n\t\t\tinModelMock: func() *MockListModel {\n\t\t\t\toutput := []*data.Person{\n\t\t\t\t\t{\n\t\t\t\t\t\tID:       1,\n\t\t\t\t\t\tFullName: \"John\",\n\t\t\t\t\t\tPhone:    \"0123456789\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tID:       2,\n\t\t\t\t\t\tFullName: \"Paul\",\n\t\t\t\t\t\tPhone:    \"0123456781\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tID:       3,\n\t\t\t\t\t\tFullName: \"George\",\n\t\t\t\t\t\tPhone:    \"0123456782\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tID:       1,\n\t\t\t\t\t\tFullName: \"Ringo\",\n\t\t\t\t\t\tPhone:    \"0123456783\",\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\tmockListModel := &MockListModel{}\n\t\t\t\tmockListModel.On(\"Do\", mock.Anything).Return(output, nil).Once()\n\n\t\t\t\treturn mockListModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusOK,\n\t\t\texpectedPayload: `{\"people\":[{\"id\":1,\"name\":\"John\",\"phone\":\"0123456789\"},{\"id\":2,\"name\":\"Paul\",\"phone\":\"0123456781\"},{\"id\":3,\"name\":\"George\",\"phone\":\"0123456782\"},{\"id\":1,\"name\":\"Ringo\",\"phone\":\"0123456783\"}]}` + \"\\n\",\n\t\t},\n\t\t{\n\t\t\tdesc: \"dependency failure\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/list\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn req\n\t\t\t},\n\t\t\tinModelMock: func() *MockListModel {\n\t\t\t\tmockListModel := &MockListModel{}\n\t\t\t\tmockListModel.On(\"Do\", mock.Anything).Return(nil, errors.New(\"something failed\")).Once()\n\n\t\t\t\treturn mockListModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusNotFound,\n\t\t\texpectedPayload: ``,\n\t\t},\n\t\t{\n\t\t\tdesc: \"no data\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/list\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn req\n\t\t\t},\n\t\t\tinModelMock: func() *MockListModel {\n\t\t\t\t// no data\n\t\t\t\toutput := []*data.Person{}\n\n\t\t\t\tmockListModel := &MockListModel{}\n\t\t\t\tmockListModel.On(\"Do\", mock.Anything).Return(output, nil).Once()\n\n\t\t\t\treturn mockListModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusOK,\n\t\t\texpectedPayload: `{\"people\":[]}` + \"\\n\",\n\t\t},\n\t}\n\n\tfor _, s := range scenarios {\n\t\tscenario := s\n\t\tt.Run(scenario.desc, func(t *testing.T) {\n\t\t\t// define model layer mock\n\t\t\tmockListModel := scenario.inModelMock()\n\n\t\t\t// build handler\n\t\t\thandler := NewListHandler(mockListModel)\n\n\t\t\t// perform request\n\t\t\tresponse := httptest.NewRecorder()\n\t\t\thandler.ServeHTTP(response, scenario.inRequest())\n\n\t\t\t// validate outputs\n\t\t\trequire.Equal(t, scenario.expectedStatus, response.Code, scenario.desc)\n\n\t\t\tpayload, _ := ioutil.ReadAll(response.Body)\n\t\t\tassert.Equal(t, scenario.expectedPayload, string(payload), scenario.desc)\n\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "ch10/acme/internal/rest/mock_get_model_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage rest\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// MockGetModel is an autogenerated mock type for the GetModel type\ntype MockGetModel struct {\n\tmock.Mock\n}\n\n// Do provides a mock function with given fields: ID\nfunc (_m *MockGetModel) Do(ID int) (*data.Person, error) {\n\tret := _m.Called(ID)\n\n\tvar r0 *data.Person\n\tif rf, ok := ret.Get(0).(func(int) *data.Person); ok {\n\t\tr0 = rf(ID)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*data.Person)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(int) error); ok {\n\t\tr1 = rf(ID)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch10/acme/internal/rest/mock_list_model_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage rest\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// MockListModel is an autogenerated mock type for the ListModel type\ntype MockListModel struct {\n\tmock.Mock\n}\n\n// Do provides a mock function with given fields:\nfunc (_m *MockListModel) Do() ([]*data.Person, error) {\n\tret := _m.Called()\n\n\tvar r0 []*data.Person\n\tif rf, ok := ret.Get(0).(func() []*data.Person); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]*data.Person)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func() error); ok {\n\t\tr1 = rf()\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch10/acme/internal/rest/mock_register_model_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage rest\n\nimport (\n\t\"context\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// MockRegisterModel is an autogenerated mock type for the RegisterModel type\ntype MockRegisterModel struct {\n\tmock.Mock\n}\n\n// Do provides a mock function with given fields: ctx, in\nfunc (_m *MockRegisterModel) Do(ctx context.Context, in *data.Person) (int, error) {\n\tret := _m.Called(ctx, in)\n\n\tvar r0 int\n\tif rf, ok := ret.Get(0).(func(context.Context, *data.Person) int); ok {\n\t\tr0 = rf(ctx, in)\n\t} else {\n\t\tr0 = ret.Get(0).(int)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, *data.Person) error); ok {\n\t\tr1 = rf(ctx, in)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch10/acme/internal/rest/not_found.go",
    "content": "package rest\n\nimport (\n\t\"net/http\"\n)\n\nfunc notFoundHandler(response http.ResponseWriter, _ *http.Request) {\n\tresponse.WriteHeader(http.StatusNotFound)\n\t_, _ = response.Write([]byte(`Not found`))\n}\n"
  },
  {
    "path": "ch10/acme/internal/rest/not_found_test.go",
    "content": "package rest\n\nimport (\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestNotFoundHandler_ServeHTTP(t *testing.T) {\n\t// build inputs\n\tresponse := httptest.NewRecorder()\n\trequest := &http.Request{}\n\n\t// call handler\n\tnotFoundHandler(response, request)\n\n\t// validate outputs\n\trequire.Equal(t, http.StatusNotFound, response.Code)\n}\n"
  },
  {
    "path": "ch10/acme/internal/rest/register.go",
    "content": "package rest\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/data\"\n)\n\n// RegisterModel will validate and save a registration\n//go:generate mockery -name=RegisterModel -case underscore -testonly -inpkg -note @generated\ntype RegisterModel interface {\n\tDo(ctx context.Context, in *data.Person) (int, error)\n}\n\n// NewRegisterHandler is the constructor for RegisterHandler\nfunc NewRegisterHandler(model RegisterModel) *RegisterHandler {\n\treturn &RegisterHandler{\n\t\tregisterer: model,\n\t}\n}\n\n// RegisterHandler is the HTTP handler for the \"Register\" endpoint\n// In this simplified example we are assuming all possible errors are user errors and returning \"bad request\" HTTP 400.\n// There are some programmer errors possible but hopefully these will be caught in testing.\ntype RegisterHandler struct {\n\tregisterer RegisterModel\n}\n\n// ServeHTTP implements http.Handler\nfunc (h *RegisterHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\t// set latency budget for this API\n\tsubCtx, cancel := context.WithTimeout(request.Context(), 1500*time.Millisecond)\n\tdefer cancel()\n\n\t// extract payload from request\n\trequestPayload, err := h.extractPayload(request)\n\tif err != nil {\n\t\t// output error\n\t\tresponse.WriteHeader(http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// call the business logic using the request data and context\n\tid, err := h.register(subCtx, requestPayload)\n\tif err != nil {\n\t\t// not need to log here as we can expect other layers to do so\n\t\tresponse.WriteHeader(http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// happy path\n\tresponse.Header().Add(\"Location\", fmt.Sprintf(\"/person/%d/\", id))\n\tresponse.WriteHeader(http.StatusCreated)\n}\n\n// extract payload from request\nfunc (h *RegisterHandler) extractPayload(request *http.Request) (*registerRequest, error) {\n\trequestPayload := &registerRequest{}\n\n\tdecoder := json.NewDecoder(request.Body)\n\terr := decoder.Decode(requestPayload)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn requestPayload, nil\n}\n\n// call the logic layer\nfunc (h *RegisterHandler) register(ctx context.Context, requestPayload *registerRequest) (int, error) {\n\tperson := &data.Person{\n\t\tFullName: requestPayload.FullName,\n\t\tPhone:    requestPayload.Phone,\n\t\tCurrency: requestPayload.Currency,\n\t}\n\n\treturn h.registerer.Do(ctx, person)\n}\n\n// register endpoint request format\ntype registerRequest struct {\n\t// FullName of the person\n\tFullName string `json:\"fullName\"`\n\t// Phone of the person\n\tPhone string `json:\"phone\"`\n\t// Currency the wish to register in\n\tCurrency string `json:\"currency\"`\n}\n"
  },
  {
    "path": "ch10/acme/internal/rest/register_test.go",
    "content": "package rest\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestRegisterHandler_ServeHTTP(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc           string\n\t\tinRequest      func() *http.Request\n\t\tinModelMock    func() *MockRegisterModel\n\t\texpectedStatus int\n\t\texpectedHeader string\n\t}{\n\t\t{\n\t\t\tdesc: \"Happy Path\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\tvalidRequest := buildValidRegisterRequest()\n\t\t\t\trequest, err := http.NewRequest(\"POST\", \"/person/register\", validRequest)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn request\n\t\t\t},\n\t\t\tinModelMock: func() *MockRegisterModel {\n\t\t\t\t// valid downstream configuration\n\t\t\t\tresultID := 1234\n\t\t\t\tvar resultErr error\n\n\t\t\t\tmockRegisterModel := &MockRegisterModel{}\n\t\t\t\tmockRegisterModel.On(\"Do\", mock.Anything, mock.Anything).Return(resultID, resultErr).Once()\n\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus: http.StatusCreated,\n\t\t\texpectedHeader: \"/person/1234/\",\n\t\t},\n\t\t{\n\t\t\tdesc: \"Bad Input / User Error\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\tinvalidRequest := bytes.NewBufferString(`this is not valid JSON`)\n\t\t\t\trequest, err := http.NewRequest(\"POST\", \"/person/register\", invalidRequest)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn request\n\t\t\t},\n\t\t\tinModelMock: func() *MockRegisterModel {\n\t\t\t\t// Dependency should not be called\n\t\t\t\tmockRegisterModel := &MockRegisterModel{}\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus: http.StatusBadRequest,\n\t\t\texpectedHeader: \"\",\n\t\t},\n\t\t{\n\t\t\tdesc: \"Dependency Failure\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\tvalidRequest := buildValidRegisterRequest()\n\t\t\t\trequest, err := http.NewRequest(\"POST\", \"/person/register\", validRequest)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn request\n\t\t\t},\n\t\t\tinModelMock: func() *MockRegisterModel {\n\t\t\t\t// call to the dependency failed\n\t\t\t\tresultErr := errors.New(\"something failed\")\n\n\t\t\t\tmockRegisterModel := &MockRegisterModel{}\n\t\t\t\tmockRegisterModel.On(\"Do\", mock.Anything, mock.Anything).Return(0, resultErr).Once()\n\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus: http.StatusBadRequest,\n\t\t\texpectedHeader: \"\",\n\t\t},\n\t}\n\n\tfor _, s := range scenarios {\n\t\tscenario := s\n\t\tt.Run(scenario.desc, func(t *testing.T) {\n\t\t\t// define model layer mock\n\t\t\tmockRegisterModel := scenario.inModelMock()\n\n\t\t\t// build handler\n\t\t\thandler := NewRegisterHandler(mockRegisterModel)\n\n\t\t\t// perform request\n\t\t\tresponse := httptest.NewRecorder()\n\t\t\thandler.ServeHTTP(response, scenario.inRequest())\n\n\t\t\t// validate outputs\n\t\t\trequire.Equal(t, scenario.expectedStatus, response.Code)\n\n\t\t\t// call should output the location to the new person\n\t\t\tresultHeader := response.Header().Get(\"Location\")\n\t\t\tassert.Equal(t, scenario.expectedHeader, resultHeader)\n\n\t\t\t// validate the mock was used as we expected\n\t\t\tassert.True(t, mockRegisterModel.AssertExpectations(t))\n\t\t})\n\t}\n}\n\nfunc buildValidRegisterRequest() io.Reader {\n\trequestData := &registerRequest{\n\t\tFullName: \"Joan Smith\",\n\t\tCurrency: \"AUD\",\n\t\tPhone:    \"01234567890\",\n\t}\n\n\tdata, _ := json.Marshal(requestData)\n\treturn bytes.NewBuffer(data)\n}\n"
  },
  {
    "path": "ch10/acme/internal/rest/server.go",
    "content": "package rest\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/logging\"\n\t\"github.com/gorilla/mux\"\n)\n\n// Config is the config for the REST package\ntype Config interface {\n\tLogger() logging.Logger\n\tBindAddress() string\n}\n\n// New will create and initialize the server\nfunc New(cfg Config,\n\tgetModel GetModel,\n\tlistModel ListModel,\n\tregisterModel RegisterModel) *Server {\n\n\treturn &Server{\n\t\taddress:         cfg.BindAddress(),\n\t\thandlerGet:      NewGetHandler(cfg, getModel),\n\t\thandlerList:     NewListHandler(listModel),\n\t\thandlerNotFound: notFoundHandler,\n\t\thandlerRegister: NewRegisterHandler(registerModel),\n\t}\n}\n\n// Server is the HTTP REST server\ntype Server struct {\n\taddress string\n\tserver  *http.Server\n\n\thandlerGet      http.Handler\n\thandlerList     http.Handler\n\thandlerNotFound http.HandlerFunc\n\thandlerRegister http.Handler\n}\n\n// Listen will start a HTTP rest for this service\nfunc (s *Server) Listen(stop <-chan struct{}) {\n\trouter := s.buildRouter()\n\n\t// create the HTTP server\n\ts.server = &http.Server{\n\t\tHandler: router,\n\t\tAddr:    s.address,\n\t}\n\n\t// listen for shutdown\n\tgo func() {\n\t\t// wait for shutdown signal\n\t\t<-stop\n\n\t\t_ = s.server.Close()\n\t}()\n\n\t// start the HTTP server\n\t_ = s.server.ListenAndServe()\n}\n\n// configure the endpoints to handlers\nfunc (s *Server) buildRouter() http.Handler {\n\trouter := mux.NewRouter()\n\n\t// map URL endpoints to HTTP handlers\n\trouter.Handle(\"/person/{id}/\", s.handlerGet).Methods(\"GET\")\n\trouter.Handle(\"/person/list\", s.handlerList).Methods(\"GET\")\n\trouter.Handle(\"/person/register\", s.handlerRegister).Methods(\"POST\")\n\n\t// convert a \"catch all\" not found handler\n\trouter.NotFoundHandler = s.handlerNotFound\n\n\treturn router\n}\n"
  },
  {
    "path": "ch10/acme/main.go",
    "content": "package main\n\nimport (\n\t\"context\"\n\t\"os\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/config\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/exchange\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/get\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/list\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/register\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/rest\"\n\t\"github.com/google/wire\"\n)\n\nfunc main() {\n\t// bind stop channel to context\n\tctx := context.Background()\n\n\t// start REST server\n\tserver, err := initializeServer()\n\tif err != nil {\n\t\tos.Exit(-1)\n\t}\n\n\tserver.Listen(ctx.Done())\n}\n\n// List of wire enabled objects\nvar wireSetWithoutConfig = wire.NewSet(\n\t// *exchange.Converter\n\texchange.NewConverter,\n\n\t// *get.Getter\n\tget.NewGetter,\n\n\t// *list.Lister\n\tlist.NewLister,\n\n\t// *register.Registerer\n\twire.Bind(new(register.Exchanger), &exchange.Converter{}),\n\tregister.NewRegisterer,\n\n\t// *rest.Server\n\twire.Bind(new(rest.GetModel), &get.Getter{}),\n\twire.Bind(new(rest.ListModel), &list.Lister{}),\n\twire.Bind(new(rest.RegisterModel), &register.Registerer{}),\n\trest.New,\n)\n\nvar wireSet = wire.NewSet(\n\twireSetWithoutConfig,\n\n\t// *config.Config\n\tconfig.Load,\n\n\t// *exchange.Converter\n\twire.Bind(new(exchange.Config), &config.Config{}),\n\n\t// *get.Getter\n\twire.Bind(new(get.Config), &config.Config{}),\n\n\t// *list.Lister\n\twire.Bind(new(list.Config), &config.Config{}),\n\n\t// *register.Registerer\n\twire.Bind(new(register.Config), &config.Config{}),\n\n\t// *rest.Server\n\twire.Bind(new(rest.Config), &config.Config{}),\n)\n"
  },
  {
    "path": "ch10/acme/main_test.go",
    "content": "package main\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/config\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestRegister(t *testing.T) {\n\t// start a context with a max execution time\n\tctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n\tdefer cancel()\n\n\t// start test server\n\tserverAddress := startTestServer(t, ctx)\n\n\t// build and send request\n\tpayload := bytes.NewBufferString(`\n{\n\t\"fullName\": \"Bob\",\n\t\"phone\": \"0123456789\",\n\t\"currency\": \"AUD\"\n}\n`)\n\n\treq, err := http.NewRequest(\"POST\", serverAddress+\"/person/register\", payload)\n\trequire.NoError(t, err)\n\n\tresp, err := http.DefaultClient.Do(req)\n\trequire.NoError(t, err)\n\n\t// validate expectations\n\tassert.Equal(t, http.StatusCreated, resp.StatusCode)\n\tassert.NotEmpty(t, resp.Header.Get(\"Location\"))\n}\n\nfunc TestGet(t *testing.T) {\n\t// start a context with a max execution time\n\tctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n\tdefer cancel()\n\n\t// start test server\n\tserverAddress := startTestServer(t, ctx)\n\n\t// build and send request\n\treq, err := http.NewRequest(\"GET\", serverAddress+\"/person/1/\", nil)\n\trequire.NoError(t, err)\n\n\tresp, err := http.DefaultClient.Do(req)\n\trequire.NoError(t, err)\n\n\t// validate expectations\n\tassert.Equal(t, http.StatusOK, resp.StatusCode)\n}\n\nfunc TestList(t *testing.T) {\n\t// start a context with a max execution time\n\tctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n\tdefer cancel()\n\n\t// start test server\n\tserverAddress := startTestServer(t, ctx)\n\n\t// build and send request\n\treq, err := http.NewRequest(\"GET\", serverAddress+\"/person/list\", nil)\n\trequire.NoError(t, err)\n\n\tresp, err := http.DefaultClient.Do(req)\n\trequire.NoError(t, err)\n\n\t// validate expectations\n\tassert.Equal(t, http.StatusOK, resp.StatusCode)\n}\n\nfunc startTestServer(t *testing.T, ctx context.Context) string {\n\t// load the standard config (from the ENV)\n\tcfg, err := config.Load()\n\trequire.NoError(t, err)\n\n\t// get a free port (so tests can run concurrently)\n\tport, err := getFreePort()\n\trequire.NoError(t, err)\n\n\t// override config port with free one\n\tcfg.Address = net.JoinHostPort(\"0.0.0.0\", port)\n\n\t// start the test server on a random port\n\tgo func() {\n\t\t// start REST server\n\t\tserver := initializeServerCustomConfig(cfg, cfg, cfg, cfg, cfg)\n\t\tserver.Listen(ctx.Done())\n\t}()\n\n\t// give the server a chance to start\n\t<-time.After(100 * time.Millisecond)\n\n\t// return the address of the test server\n\treturn \"http://\" + cfg.Address\n}\n\nfunc getFreePort() (string, error) {\n\tfor attempt := 0; attempt <= 10; attempt++ {\n\t\taddr := net.JoinHostPort(\"\", \"0\")\n\t\tlistener, err := net.Listen(\"tcp\", addr)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tport, err := getPort(listener.Addr())\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\t// close/free the port\n\t\ttcpListener := listener.(*net.TCPListener)\n\t\tcErr := tcpListener.Close()\n\t\tif cErr == nil {\n\t\t\tfile, fErr := tcpListener.File()\n\t\t\tif fErr == nil {\n\t\t\t\t// ignore any errors cleaning up the file\n\t\t\t\t_ = file.Close()\n\t\t\t}\n\t\t\treturn port, nil\n\t\t}\n\t}\n\n\treturn \"\", errors.New(\"no free ports\")\n}\n\nfunc getPort(addr fmt.Stringer) (string, error) {\n\tactualAddress := addr.String()\n\t_, port, err := net.SplitHostPort(actualAddress)\n\treturn port, err\n}\n"
  },
  {
    "path": "ch10/acme/wire.go",
    "content": "//+build wireinject\n\npackage main\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/exchange\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/get\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/list\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/register\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/rest\"\n\t\"github.com/google/wire\"\n)\n\n// The build tag makes sure the stub is not built in the final build.\n\nfunc initializeServer() (*rest.Server, error) {\n\twire.Build(wireSet)\n\treturn nil, nil\n}\n\nfunc initializeServerCustomConfig(_ exchange.Config, _ get.Config, _ list.Config, _ register.Config, _ rest.Config) *rest.Server {\n\twire.Build(wireSetWithoutConfig)\n\treturn nil\n}\n"
  },
  {
    "path": "ch10/acme/wire_gen.go",
    "content": "// Code generated by Wire. DO NOT EDIT.\n\n//go:generate wire\n//+build !wireinject\n\npackage main\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/config\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/exchange\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/get\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/list\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/modules/register\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch10/acme/internal/rest\"\n)\n\n// Injectors from wire.go:\n\nfunc initializeServer() (*rest.Server, error) {\n\tconfigConfig, err := config.Load()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tgetter := get.NewGetter(configConfig)\n\tlister := list.NewLister(configConfig)\n\tconverter := exchange.NewConverter(configConfig)\n\tregisterer := register.NewRegisterer(configConfig, converter)\n\tserver := rest.New(configConfig, getter, lister, registerer)\n\treturn server, nil\n}\n\nfunc initializeServerCustomConfig(exchangeConfig exchange.Config, getConfig get.Config, listConfig list.Config, registerConfig register.Config, restConfig rest.Config) *rest.Server {\n\tgetter := get.NewGetter(getConfig)\n\tlister := list.NewLister(listConfig)\n\tconverter := exchange.NewConverter(exchangeConfig)\n\tregisterer := register.NewRegisterer(registerConfig, converter)\n\tserver := rest.New(restConfig, getter, lister, registerer)\n\treturn server\n}\n"
  },
  {
    "path": "ch10/fake.go",
    "content": "package ch10\n\nfunc init() {\n\t// This file is included so that Go tools (like `go list`) will find Go code in this directory and not error\n}\n"
  },
  {
    "path": "ch11/01_di_induced_damage/01_long_param/01_long_param.go",
    "content": "package long_param\n\nimport (\n\t\"net/http\"\n\t\"time\"\n)\n\nfunc NewMyHandler(logger Logger, stats Instrumentation,\n\tparser Parser, formatter Formatter,\n\tlimiter RateLimiter,\n\tcache Cache, db Datastore) *MyHandler {\n\n\treturn &MyHandler{\n\t\t// code removed\n\t}\n}\n\n// MyHandler does something fantastic\ntype MyHandler struct {\n\t// code removed\n}\n\nfunc (m *MyHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\t// code removed\n}\n\n// Logger logs stuff\ntype Logger interface {\n\tError(message string, args ...interface{})\n\tWarn(message string, args ...interface{})\n\tInfo(message string, args ...interface{})\n\tDebug(message string, args ...interface{})\n}\n\n// Instrumentation records the performances and events\ntype Instrumentation interface {\n\tCount(key string, value int)\n\tDuration(key string, start time.Time)\n}\n\n// Parse will extract details from the request\ntype Parser interface {\n\tExtract(req *http.Request) (int, error)\n}\n\n// Formatter will build the output\ntype Formatter interface {\n\tFormat(resp http.ResponseWriter, data []byte) error\n}\n\n// RateLimiter limits how many concurrent requests we can make or process\ntype RateLimiter interface {\n\tAcquire()\n\tRelease()\n}\n\n// Datastore will store/retrieve data in a permanent\ntype Datastore interface {\n\tLoad(ID int) ([]byte, error)\n}\n\n// Cache will store/retrieve data in a fast way\ntype Cache interface {\n\tStore(key string, data []byte)\n\tGet(key string) ([]byte, error)\n}\n"
  },
  {
    "path": "ch11/01_di_induced_damage/02_long_param/01_long_param.go",
    "content": "package long_param\n\nimport (\n\t\"net/http\"\n\t\"time\"\n)\n\nfunc NewMyHandler(logger Logger, stats Instrumentation,\n\tparser Parser, formatter Formatter,\n\tlimiter RateLimiter,\n\tloader Loader) *MyHandler {\n\n\treturn &MyHandler{\n\t\t// code removed\n\t}\n}\n\n// MyHandler does something fantastic\ntype MyHandler struct {\n\t// code removed\n}\n\nfunc (m *MyHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\t// code removed\n}\n\n// Logger logs stuff\ntype Logger interface {\n\tError(message string, args ...interface{})\n\tWarn(message string, args ...interface{})\n\tInfo(message string, args ...interface{})\n\tDebug(message string, args ...interface{})\n}\n\n// Instrumentation records the performances and events\ntype Instrumentation interface {\n\tCount(key string, value int)\n\tDuration(key string, start time.Time)\n}\n\n// Parse will extract details from the request\ntype Parser interface {\n\tExtract(req *http.Request) (int, error)\n}\n\n// Formatter will build the output\ntype Formatter interface {\n\tFormat(resp http.ResponseWriter, data []byte) error\n}\n\n// RateLimiter limits how many concurrent requests we can make or process\ntype RateLimiter interface {\n\tAcquire()\n\tRelease()\n}\n\n// Loader is responsible for loading the data\ntype Loader interface {\n\tLoad(ID int) ([]byte, error)\n}\n"
  },
  {
    "path": "ch11/01_di_induced_damage/03_long_param/01_long_param.go",
    "content": "package long_param\n\nimport (\n\t\"net/http\"\n\t\"time\"\n)\n\nfunc NewMyHandler(config Config,\n\tparser Parser, formatter Formatter,\n\tlimiter RateLimiter,\n\tloader Loader) *MyHandler {\n\n\treturn &MyHandler{\n\t\tconfig:    config,\n\t\tparser:    parser,\n\t\tformatter: formatter,\n\t\tlimiter:   limiter,\n\t\tloader:    loader,\n\t}\n}\n\n// MyHandler does something fantastic\ntype MyHandler struct {\n\tconfig    Config\n\tparser    Parser\n\tformatter Formatter\n\tlimiter   RateLimiter\n\tloader    Loader\n}\n\nfunc (m *MyHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\tID, err := m.parser.Extract(request)\n\tif err != nil {\n\t\tresponse.WriteHeader(http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tdata, err := m.loader.Load(ID)\n\tif err != nil {\n\t\tresponse.WriteHeader(http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\terr = m.formatter.Format(response, data)\n\tif err != nil {\n\t\tresponse.WriteHeader(http.StatusInternalServerError)\n\t\treturn\n\t}\n}\n\n// Config combines environmental concerns like logging and instrumentation with any other config\ntype Config interface {\n\tLogger() Logger\n\tInstrumentation() Instrumentation\n}\n\n// Logger logs stuff\ntype Logger interface {\n\tError(message string, args ...interface{})\n\tWarn(message string, args ...interface{})\n\tInfo(message string, args ...interface{})\n\tDebug(message string, args ...interface{})\n}\n\n// Instrumentation records the performances and events\ntype Instrumentation interface {\n\tCount(key string, value int)\n\tDuration(key string, start time.Time)\n}\n\n// Parse will extract details from the request\ntype Parser interface {\n\tExtract(req *http.Request) (int, error)\n}\n\n// Formatter will build the output\ntype Formatter interface {\n\tFormat(resp http.ResponseWriter, data []byte) error\n}\n\n// RateLimiter limits how many concurrent requests we can make or process\ntype RateLimiter interface {\n\tAcquire()\n\tRelease()\n}\n\n// Loader is responsible for loading the data\ntype Loader interface {\n\tLoad(ID int) ([]byte, error)\n}\n"
  },
  {
    "path": "ch11/01_di_induced_damage/04_long_param/01_long_param.go",
    "content": "package long_param\n\nimport (\n\t\"net/http\"\n\t\"time\"\n)\n\nfunc NewFancyFormatHandler(config Config,\n\tparser Parser,\n\tlimiter RateLimiter,\n\tloader Loader) *FancyFormatHandler {\n\n\treturn &FancyFormatHandler{\n\t\t&MyHandler{\n\t\t\tconfig:    config,\n\t\t\tformatter: &FancyFormatter{},\n\t\t\tparser:    parser,\n\t\t\tlimiter:   limiter,\n\t\t\tloader:    loader,\n\t\t},\n\t}\n}\n\n// FancyFormatHandler does something fancy\ntype FancyFormatHandler struct {\n\t*MyHandler\n}\n\n// MyHandler does something fantastic\ntype MyHandler struct {\n\tconfig    Config\n\tparser    Parser\n\tformatter Formatter\n\tlimiter   RateLimiter\n\tloader    Loader\n}\n\nfunc (m *MyHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\tID, err := m.parser.Extract(request)\n\tif err != nil {\n\t\tresponse.WriteHeader(http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tdata, err := m.loader.Load(ID)\n\tif err != nil {\n\t\tresponse.WriteHeader(http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\terr = m.formatter.Format(response, data)\n\tif err != nil {\n\t\tresponse.WriteHeader(http.StatusInternalServerError)\n\t\treturn\n\t}\n}\n\n// Config combines environmental concerns like logging and instrumentation with any other config\ntype Config interface {\n\tLogger() Logger\n\tInstrumentation() Instrumentation\n}\n\n// Logger logs stuff\ntype Logger interface {\n\tError(message string, args ...interface{})\n\tWarn(message string, args ...interface{})\n\tInfo(message string, args ...interface{})\n\tDebug(message string, args ...interface{})\n}\n\n// Instrumentation records the performances and events\ntype Instrumentation interface {\n\tCount(key string, value int)\n\tDuration(key string, start time.Time)\n}\n\n// Parse will extract details from the request\ntype Parser interface {\n\tExtract(req *http.Request) (int, error)\n}\n\n// Formatter will build the output\ntype Formatter interface {\n\tFormat(resp http.ResponseWriter, data []byte) error\n}\n\n// FancyFormatter Implements Formatter\ntype FancyFormatter struct{}\n\nfunc (f *FancyFormatter) Format(response http.ResponseWriter, data []byte) error {\n\t// does something fancy with the data\n\t_, err := response.Write([]byte(`something fancy!`))\n\treturn err\n}\n\n// RateLimiter limits how many concurrent requests we can make or process\ntype RateLimiter interface {\n\tAcquire()\n\tRelease()\n}\n\n// Loader is responsible for loading the data\ntype Loader interface {\n\tLoad(ID int) ([]byte, error)\n}\n"
  },
  {
    "path": "ch11/01_di_induced_damage/04_long_param/01_long_param_test.go",
    "content": "package long_param\n\nimport (\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestNewFancyFormatHandler(t *testing.T) {\n\t// inputs\n\tconfig := &stubConfig{}\n\tparser := &stubParser{}\n\tlimiter := &stubRateLimiter{}\n\tloader := &stubLoader{}\n\n\t// create the handler\n\tfancyHandler := NewFancyFormatHandler(config, parser, limiter, loader)\n\n\t// call with fake HTTP request\n\tresponse := httptest.NewRecorder()\n\trequest := &http.Request{}\n\tfancyHandler.ServeHTTP(response, request)\n\n\t// validate result\n\tassert.Equal(t, http.StatusOK, response.Code)\n\tassert.Equal(t, \"something fancy!\", response.Body.String())\n}\n\n// define some mock implementations so that our test can run\ntype stubConfig struct{}\n\nfunc (s *stubConfig) Logger() Logger {\n\treturn &stubLogger{}\n}\n\nfunc (s *stubConfig) Instrumentation() Instrumentation {\n\treturn &stubInstrumentation{}\n}\n\ntype stubLogger struct{}\n\nfunc (s *stubLogger) Error(message string, args ...interface{}) {\n\t// do nothing\n}\n\nfunc (s *stubLogger) Warn(message string, args ...interface{}) {\n\t// do nothing\n}\n\nfunc (s *stubLogger) Info(message string, args ...interface{}) {\n\t// do nothing\n}\n\nfunc (s *stubLogger) Debug(message string, args ...interface{}) {\n\t// do nothing\n}\n\ntype stubInstrumentation struct{}\n\nfunc (s *stubInstrumentation) Count(key string, value int) {\n\t// do nothing\n}\n\nfunc (s *stubInstrumentation) Duration(key string, start time.Time) {\n\t// do nothing\n}\n\ntype stubParser struct{}\n\nfunc (s *stubParser) Extract(req *http.Request) (int, error) {\n\treturn 1, nil\n}\n\ntype stubRateLimiter struct{}\n\nfunc (s *stubRateLimiter) Acquire() {\n\t// do nothing\n}\n\nfunc (s *stubRateLimiter) Release() {\n\t// do nothing\n}\n\ntype stubLoader struct{}\n\nfunc (s *stubLoader) Load(ID int) ([]byte, error) {\n\treturn []byte(`some data`), nil\n}\n"
  },
  {
    "path": "ch11/01_di_induced_damage/05_inject_sql/01_interface.go",
    "content": "package inject_vs_config\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n)\n\ntype Connection interface {\n\tQueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row\n\tQueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)\n\tExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)\n}\n"
  },
  {
    "path": "ch11/01_di_induced_damage/06_inject_sql/01_interface.go",
    "content": "package data\n\nimport (\n\t\"context\"\n)\n\ntype Database interface {\n\tQueryRowContext(ctx context.Context, query string, args ...interface{}) Row\n\tQueryContext(ctx context.Context, query string, args ...interface{}) (Rows, error)\n\tExecContext(ctx context.Context, query string, args ...interface{}) (Result, error)\n}\n\ntype Row interface {\n\tScan(dest ...interface{}) error\n}\n\ntype Rows interface {\n\tScan(dest ...interface{}) error\n\tClose() error\n\tNext() bool\n}\n\ntype Result interface {\n\tLastInsertId() (int64, error)\n\tRowsAffected() (int64, error)\n}\n"
  },
  {
    "path": "ch11/01_di_induced_damage/06_inject_sql/02_implementation.go",
    "content": "package data\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n)\n\ntype DatabaseImpl struct {\n\tdb *sql.DB\n}\n\nfunc (c *DatabaseImpl) QueryRowContext(ctx context.Context, query string, args ...interface{}) Row {\n\treturn c.db.QueryRowContext(ctx, query, args...)\n}\n\nfunc (c *DatabaseImpl) QueryContext(ctx context.Context, query string, args ...interface{}) (Rows, error) {\n\treturn c.db.QueryContext(ctx, query, args...)\n}\n\nfunc (c *DatabaseImpl) ExecContext(ctx context.Context, query string, args ...interface{}) (Result, error) {\n\treturn c.db.ExecContext(ctx, query, args...)\n}\n\ntype RowImpl struct {\n\trow *sql.Row\n}\n\nfunc (r *RowImpl) Scan(dest ...interface{}) error {\n\treturn r.row.Scan(dest...)\n}\n\ntype RowsImpl struct {\n\trows *sql.Rows\n}\n\nfunc (r RowsImpl) Scan(dest ...interface{}) error {\n\treturn r.rows.Scan(dest...)\n}\n\nfunc (r RowsImpl) Close() error {\n\treturn r.rows.Close()\n}\n\nfunc (r RowsImpl) Next() bool {\n\treturn r.rows.Next()\n}\n\ntype ResultImpl struct {\n\tresult sql.Result\n}\n\nfunc (r *ResultImpl) LastInsertId() (int64, error) {\n\treturn r.result.LastInsertId()\n}\n\nfunc (r *ResultImpl) RowsAffected() (int64, error) {\n\treturn r.result.RowsAffected()\n}\n"
  },
  {
    "path": "ch11/01_di_induced_damage/06_inject_sql/02_implementation_test.go",
    "content": "package data\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestImplements(t *testing.T) {\n\tassert.Implements(t, (*Database)(nil), &DatabaseImpl{})\n\tassert.Implements(t, (*Row)(nil), &RowImpl{})\n\tassert.Implements(t, (*Rows)(nil), &RowsImpl{})\n\tassert.Implements(t, (*Result)(nil), &ResultImpl{})\n}\n"
  },
  {
    "path": "ch11/01_di_induced_damage/06_inject_sql/dao.go",
    "content": "package data\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"os\"\n\t\"time\"\n)\n\n// NewDAO will initialize the database connection pool (if not already done) and return a data access object which\n// can be used to interact with the database\nfunc NewDAO(cfg Config) *DAO {\n\t// initialize the db connection pool\n\t_, _ = getDB(cfg)\n\n\treturn &DAO{\n\t\tcfg: cfg,\n\t}\n}\n\n// DAO is a data access object that provides an abstraction over our database interactions.\ntype DAO struct {\n\tcfg Config\n}\n\n// Load will attempt to load and return a person.\n// It will return ErrNotFound when the requested person does not exist.\n// Any other errors returned are caused by the underlying database or our connection to it.\nfunc (d *DAO) Load(ctx context.Context, ID int) (*Person, error) {\n\tdb, err := getDB(d.cfg)\n\tif err != nil {\n\t\tfmt.Fprintf(os.Stderr, \"failed to get DB connection. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// set latency budget for the database call\n\tsubCtx, cancel := context.WithTimeout(ctx, 1*time.Second)\n\tdefer cancel()\n\n\t// perform DB select\n\trow := db.QueryRowContext(subCtx, sqlLoadByID, ID)\n\n\t// retrieve columns and populate the person object\n\tout, err := populatePerson(row.Scan)\n\tif err != nil {\n\t\tif err == sql.ErrNoRows {\n\t\t\tfmt.Fprintf(os.Stderr, \"failed to load requested person '%d'. err: %s\", ID, err)\n\t\t\treturn nil, ErrNotFound\n\t\t}\n\n\t\tfmt.Fprintf(os.Stderr, \"failed to convert query result. err: %s\", err)\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\n// LoadAll will attempt to load all people in the database\n// It will return ErrNotFound when there are not people in the database\n// Any other errors returned are caused by the underlying database or our connection to it.\nfunc (d *DAO) LoadAll(ctx context.Context) ([]*Person, error) {\n\tdb, err := getDB(d.cfg)\n\tif err != nil {\n\t\tfmt.Fprintf(os.Stderr, \"failed to get DB connection. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// set latency budget for the database call\n\tsubCtx, cancel := context.WithTimeout(ctx, 1*time.Second)\n\tdefer cancel()\n\n\t// perform DB select\n\trows, err := db.QueryContext(subCtx, sqlLoadAll)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer func() {\n\t\t_ = rows.Close()\n\t}()\n\n\tvar out []*Person\n\n\tfor rows.Next() {\n\t\t// retrieve columns and populate the person object\n\t\trecord, err := populatePerson(rows.Scan)\n\t\tif err != nil {\n\t\t\tfmt.Fprintf(os.Stderr, \"failed to convert query result. err: %s\", err)\n\t\t\treturn nil, err\n\t\t}\n\n\t\tout = append(out, record)\n\t}\n\n\tif len(out) == 0 {\n\t\tfmt.Fprintf(os.Stderr, \"no people found in the database.\")\n\t\treturn nil, ErrNotFound\n\t}\n\n\treturn out, nil\n}\n\n// Save will save the supplied person and return the ID of the newly created person or an error.\n// Errors returned are caused by the underlying database or our connection to it.\nfunc (d *DAO) Save(ctx context.Context, in *Person) (int, error) {\n\tdb, err := getDB(d.cfg)\n\tif err != nil {\n\t\tfmt.Fprintf(os.Stderr, \"failed to get DB connection. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\t// set latency budget for the database call\n\tsubCtx, cancel := context.WithTimeout(ctx, 1*time.Second)\n\tdefer cancel()\n\n\t// perform DB insert\n\tresult, err := db.ExecContext(subCtx, sqlInsert, in.FullName, in.Phone, in.Currency, in.Price)\n\tif err != nil {\n\t\tfmt.Fprintf(os.Stderr, \"failed to save person into DB. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\t// retrieve and return the ID of the person created\n\tid, err := result.LastInsertId()\n\tif err != nil {\n\t\tfmt.Fprintf(os.Stderr, \"failed to retrieve id of last saved person. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn int(id), nil\n}\n"
  },
  {
    "path": "ch11/01_di_induced_damage/06_inject_sql/data.go",
    "content": "package data\n\nimport (\n\t\"database/sql\"\n\t\"errors\"\n\n\t_ \"github.com/go-sql-driver/mysql\"\n)\n\nconst (\n\t// default person id (returned on error)\n\tdefaultPersonID = 0\n\n\t// SQL statements as constants (to reduce duplication and maintenance in tests)\n\tsqlAllColumns = \"id, fullname, phone, currency, price\"\n\tsqlInsert     = \"INSERT INTO person (fullname, phone, currency, price) VALUES (?, ?, ?, ?)\"\n\tsqlLoadAll    = \"SELECT \" + sqlAllColumns + \" FROM person\"\n\tsqlLoadByID   = \"SELECT \" + sqlAllColumns + \" FROM person WHERE id = ? LIMIT 1\"\n)\n\nvar (\n\tdb *sql.DB\n\n\t// ErrNotFound is returned when the no records where matched by the query\n\tErrNotFound = errors.New(\"not found\")\n)\n\n// Config is the configuration for the data package\ntype Config interface {\n\t// DataDSN returns the data source name\n\tDataDSN() string\n}\n\nvar getDB = func(cfg Config) (Database, error) {\n\tif db == nil {\n\t\tvar err error\n\t\tdb, err = sql.Open(\"mysql\", cfg.DataDSN())\n\t\tif err != nil {\n\t\t\t// if the DB cannot be accessed we are dead\n\t\t\tpanic(err.Error())\n\t\t}\n\t}\n\n\treturn &DatabaseImpl{db: db}, nil\n}\n\n// Person is the data transfer object (DTO) for this package\ntype Person struct {\n\t// ID is the unique ID for this person\n\tID int\n\t// FullName is the name of this person\n\tFullName string\n\t// Phone is the phone for this person\n\tPhone string\n\t// Currency is the currency this person has paid in\n\tCurrency string\n\t// Price is the amount (in the above currency) paid by this person\n\tPrice float64\n}\n\n// custom type so we can convert sql results to easily\ntype scanner func(dest ...interface{}) error\n\n// reduce the duplication (and maintenance) between sql.Row and sql.Rows usage\nfunc populatePerson(scanner scanner) (*Person, error) {\n\tout := &Person{}\n\terr := scanner(&out.ID, &out.FullName, &out.Phone, &out.Currency, &out.Price)\n\treturn out, err\n}\n"
  },
  {
    "path": "ch11/01_di_induced_damage/06_inject_sql/data_test.go",
    "content": "package data\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/DATA-DOG/go-sqlmock\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestSave_happyPath(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\t// define a mock db\n\ttestDb, dbMock, err := sqlmock.New()\n\tdefer testDb.Close()\n\trequire.NoError(t, err)\n\n\t// configure the mock db\n\tqueryRegex := convertSQLToRegex(sqlInsert)\n\tdbMock.ExpectExec(queryRegex).WillReturnResult(sqlmock.NewResult(2, 1))\n\n\t// monkey patching starts here\n\tdb = testDb\n\t// end of monkey patch\n\n\t// inputs\n\tin := &Person{\n\t\tFullName: \"Jake Blues\",\n\t\tPhone:    \"01234567890\",\n\t\tCurrency: \"AUD\",\n\t\tPrice:    123.45,\n\t}\n\n\t// call function\n\tdao := NewDAO(&testConfig{})\n\tresultID, err := dao.Save(ctx, in)\n\n\t// validate result\n\trequire.NoError(t, err)\n\tassert.Equal(t, 2, resultID)\n\tassert.NoError(t, dbMock.ExpectationsWereMet())\n}\n\nfunc TestSave_insertError(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\t// define a mock db\n\ttestDb, dbMock, err := sqlmock.New()\n\tdefer testDb.Close()\n\n\trequire.NoError(t, err)\n\n\t// configure the mock db\n\tqueryRegex := convertSQLToRegex(sqlInsert)\n\tdbMock.ExpectExec(queryRegex).WillReturnError(errors.New(\"failed to insert\"))\n\n\t// monkey patching starts here\n\tdb = testDb\n\t// end of monkey patch\n\n\t// inputs\n\tin := &Person{\n\t\tFullName: \"Jake Blues\",\n\t\tPhone:    \"01234567890\",\n\t\tCurrency: \"AUD\",\n\t\tPrice:    123.45,\n\t}\n\n\t// call function\n\tdao := NewDAO(&testConfig{})\n\tresultID, err := dao.Save(ctx, in)\n\n\t// validate result\n\trequire.Error(t, err)\n\tassert.Equal(t, defaultPersonID, resultID)\n\tassert.NoError(t, dbMock.ExpectationsWereMet())\n}\n\nfunc TestSave_getDBError(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\t// monkey patching starts here\n\tdefer func(original func(_ Config) (Database, error)) {\n\t\t// restore original DB (after test)\n\t\tgetDB = original\n\t}(getDB)\n\n\t// replace getDB() function for this test\n\tgetDB = func(_ Config) (Database, error) {\n\t\treturn nil, errors.New(\"getDB() failed\")\n\t}\n\t// end of monkey patch\n\n\t// inputs\n\tin := &Person{\n\t\tFullName: \"Jake Blues\",\n\t\tPhone:    \"01234567890\",\n\t\tCurrency: \"AUD\",\n\t\tPrice:    123.45,\n\t}\n\n\t// call function\n\tdao := NewDAO(&testConfig{})\n\tresultID, err := dao.Save(ctx, in)\n\trequire.Error(t, err)\n\tassert.Equal(t, defaultPersonID, resultID)\n}\n\nfunc TestLoadAll_tableDrivenTest(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\n\tdefer cancel()\n\n\tscenarios := []struct {\n\t\tdesc            string\n\t\tconfigureMockDB func(sqlmock.Sqlmock)\n\t\texpectedResults []*Person\n\t\texpectError     bool\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tconfigureMockDB: func(dbMock sqlmock.Sqlmock) {\n\t\t\t\tqueryRegex := convertSQLToRegex(sqlLoadAll)\n\t\t\t\tdbMock.ExpectQuery(queryRegex).WillReturnRows(\n\t\t\t\t\tsqlmock.NewRows(strings.Split(sqlAllColumns, \", \")).\n\t\t\t\t\t\tAddRow(1, \"John\", \"0123456789\", \"AUD\", 12.34))\n\t\t\t},\n\t\t\texpectedResults: []*Person{\n\t\t\t\t{\n\t\t\t\t\tID:       1,\n\t\t\t\t\tFullName: \"John\",\n\t\t\t\t\tPhone:    \"0123456789\",\n\t\t\t\t\tCurrency: \"AUD\",\n\t\t\t\t\tPrice:    12.34,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tdesc: \"load error\",\n\t\t\tconfigureMockDB: func(dbMock sqlmock.Sqlmock) {\n\t\t\t\tqueryRegex := convertSQLToRegex(sqlLoadAll)\n\t\t\t\tdbMock.ExpectQuery(queryRegex).WillReturnError(errors.New(\"something failed\"))\n\t\t\t},\n\t\t\texpectedResults: nil,\n\t\t\texpectError:     true,\n\t\t},\n\t}\n\n\tfor _, scenario := range scenarios {\n\t\t// define a mock db\n\t\ttestDb, dbMock, err := sqlmock.New()\n\t\trequire.NoError(t, err)\n\n\t\t// configure the mock db\n\t\tscenario.configureMockDB(dbMock)\n\n\t\t// monkey patch the db for this test\n\t\toriginal := *db\n\t\tdb = testDb\n\n\t\t// call function\n\t\tdao := NewDAO(&testConfig{})\n\t\tresults, err := dao.LoadAll(ctx)\n\n\t\t// validate results\n\t\tassert.Equal(t, scenario.expectedResults, results, scenario.desc)\n\t\tassert.Equal(t, scenario.expectError, err != nil, scenario.desc)\n\t\tassert.NoError(t, dbMock.ExpectationsWereMet())\n\n\t\t// restore original DB (after test)\n\t\tdb = &original\n\t\ttestDb.Close()\n\t}\n}\n\nfunc TestLoad_tableDrivenTest(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\n\tdefer cancel()\n\n\tscenarios := []struct {\n\t\tdesc            string\n\t\tconfigureMockDB func(sqlmock.Sqlmock)\n\t\texpectedResult  *Person\n\t\texpectError     bool\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tconfigureMockDB: func(dbMock sqlmock.Sqlmock) {\n\t\t\t\tqueryRegex := convertSQLToRegex(sqlLoadAll)\n\t\t\t\tdbMock.ExpectQuery(queryRegex).WillReturnRows(\n\t\t\t\t\tsqlmock.NewRows(strings.Split(sqlAllColumns, \", \")).\n\t\t\t\t\t\tAddRow(2, \"Paul\", \"0123456789\", \"CAD\", 23.45))\n\t\t\t},\n\t\t\texpectedResult: &Person{\n\t\t\t\tID:       2,\n\t\t\t\tFullName: \"Paul\",\n\t\t\t\tPhone:    \"0123456789\",\n\t\t\t\tCurrency: \"CAD\",\n\t\t\t\tPrice:    23.45,\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tdesc: \"load error\",\n\t\t\tconfigureMockDB: func(dbMock sqlmock.Sqlmock) {\n\t\t\t\tqueryRegex := convertSQLToRegex(sqlLoadAll)\n\t\t\t\tdbMock.ExpectQuery(queryRegex).WillReturnError(errors.New(\"something failed\"))\n\t\t\t},\n\t\t\texpectedResult: nil,\n\t\t\texpectError:    true,\n\t\t},\n\t}\n\n\tfor _, scenario := range scenarios {\n\t\t// define a mock db\n\t\ttestDb, dbMock, err := sqlmock.New()\n\t\trequire.NoError(t, err)\n\n\t\t// configure the mock db\n\t\tscenario.configureMockDB(dbMock)\n\n\t\t// monkey db for this test\n\t\toriginal := *db\n\t\tdb = testDb\n\n\t\t// call function\n\t\tdao := NewDAO(&testConfig{})\n\t\tresult, err := dao.Load(ctx, 2)\n\n\t\t// validate results\n\t\tassert.Equal(t, scenario.expectedResult, result, scenario.desc)\n\t\tassert.Equal(t, scenario.expectError, err != nil, scenario.desc)\n\t\tassert.NoError(t, dbMock.ExpectationsWereMet())\n\n\t\t// restore original DB (after test)\n\t\tdb = &original\n\t\ttestDb.Close()\n\t}\n}\n\n// convert SQL string to regex by treating the entire query as a literal\nfunc convertSQLToRegex(in string) string {\n\treturn `\\Q` + in + `\\E`\n}\n\ntype testConfig struct{}\n\n// DataDSN implements Config\nfunc (t *testConfig) DataDSN() string {\n\treturn \"\"\n}\n"
  },
  {
    "path": "ch11/01_di_induced_damage/07_needless_indirection/example_test.go",
    "content": "package needless_indirection\n\nimport (\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestExample(t *testing.T) {\n\trouter := http.NewServeMux()\n\trouter.HandleFunc(\"/health\", func(resp http.ResponseWriter, req *http.Request) {\n\t\t_, _ = resp.Write([]byte(`OK`))\n\t})\n\n\t// start a server\n\taddress := \":8080\"\n\tgo func() {\n\t\t_ = http.ListenAndServe(address, router)\n\t}()\n\n\t// call the server\n\tresp, err := http.Get(\"http://:8080/health\")\n\trequire.NoError(t, err)\n\n\t// validate the response\n\tresponseBody, err := ioutil.ReadAll(resp.Body)\n\tassert.Equal(t, []byte(`OK`), responseBody)\n}\n"
  },
  {
    "path": "ch11/01_di_induced_damage/08_needless_indirection/01_mux.go",
    "content": "package needless_indirection\n\nimport (\n\t\"net/http\"\n)\n\n//go:generate mockery -name=MyMux -case underscore -testonly -inpkg -note @generated\ntype MyMux interface {\n\tHandle(pattern string, handler http.Handler)\n\tHandler(req *http.Request) (handler http.Handler, pattern string)\n\tServeHTTP(resp http.ResponseWriter, req *http.Request)\n}\n\n// build HTTP handler routing\nfunc buildRouter(mux MyMux) {\n\tmux.Handle(\"/get\", &getEndpoint{})\n\tmux.Handle(\"/list\", &listEndpoint{})\n\tmux.Handle(\"/save\", &saveEndpoint{})\n}\n\ntype getEndpoint struct{}\n\nfunc (*getEndpoint) ServeHTTP(_ http.ResponseWriter, _ *http.Request) {\n\t// not implemented\n}\n\ntype listEndpoint struct{}\n\nfunc (*listEndpoint) ServeHTTP(_ http.ResponseWriter, _ *http.Request) {\n\t// not implemented\n}\n\ntype saveEndpoint struct{}\n\nfunc (*saveEndpoint) ServeHTTP(_ http.ResponseWriter, _ *http.Request) {\n\t// not implemented\n}\n"
  },
  {
    "path": "ch11/01_di_induced_damage/08_needless_indirection/01_mux_test.go",
    "content": "package needless_indirection\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestBuildRouter(t *testing.T) {\n\t// build mock\n\tmockRouter := &MockMyMux{}\n\tmockRouter.On(\"Handle\", \"/get\", &getEndpoint{}).Once()\n\tmockRouter.On(\"Handle\", \"/list\", &listEndpoint{}).Once()\n\tmockRouter.On(\"Handle\", \"/save\", &saveEndpoint{}).Once()\n\n\t// call function\n\tbuildRouter(mockRouter)\n\n\t// assert expectations\n\tassert.True(t, mockRouter.AssertExpectations(t))\n}\n"
  },
  {
    "path": "ch11/01_di_induced_damage/08_needless_indirection/mock_my_mux_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage needless_indirection\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// MockMyMux is an autogenerated mock type for the MyMux type\ntype MockMyMux struct {\n\tmock.Mock\n}\n\n// Handle provides a mock function with given fields: pattern, handler\nfunc (_m *MockMyMux) Handle(pattern string, handler http.Handler) {\n\t_m.Called(pattern, handler)\n}\n\n// Handler provides a mock function with given fields: req\nfunc (_m *MockMyMux) Handler(req *http.Request) (http.Handler, string) {\n\tret := _m.Called(req)\n\n\tvar r0 http.Handler\n\tif rf, ok := ret.Get(0).(func(*http.Request) http.Handler); ok {\n\t\tr0 = rf(req)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(http.Handler)\n\t\t}\n\t}\n\n\tvar r1 string\n\tif rf, ok := ret.Get(1).(func(*http.Request) string); ok {\n\t\tr1 = rf(req)\n\t} else {\n\t\tr1 = ret.Get(1).(string)\n\t}\n\n\treturn r0, r1\n}\n\n// ServeHTTP provides a mock function with given fields: resp, req\nfunc (_m *MockMyMux) ServeHTTP(resp http.ResponseWriter, req *http.Request) {\n\t_m.Called(resp, req)\n}\n"
  },
  {
    "path": "ch11/01_di_induced_damage/09_needless_indirection/01_mux.go",
    "content": "package needless_indirection\n\nimport (\n\t\"net/http\"\n)\n\n// build HTTP handler routing\nfunc buildRouter(mux *http.ServeMux) {\n\tmux.Handle(\"/get\", &getEndpoint{})\n\tmux.Handle(\"/list\", &listEndpoint{})\n\tmux.Handle(\"/save\", &saveEndpoint{})\n}\n\ntype getEndpoint struct{}\n\nfunc (*getEndpoint) ServeHTTP(_ http.ResponseWriter, _ *http.Request) {\n\t// not implemented\n}\n\ntype listEndpoint struct{}\n\nfunc (*listEndpoint) ServeHTTP(_ http.ResponseWriter, _ *http.Request) {\n\t// not implemented\n}\n\ntype saveEndpoint struct{}\n\nfunc (*saveEndpoint) ServeHTTP(_ http.ResponseWriter, _ *http.Request) {\n\t// not implemented\n}\n"
  },
  {
    "path": "ch11/01_di_induced_damage/09_needless_indirection/01_mux_test.go",
    "content": "package needless_indirection\n\nimport (\n\t\"net/http\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestBuildRouter(t *testing.T) {\n\trouter := http.NewServeMux()\n\n\t// call function\n\tbuildRouter(router)\n\n\t// assertions\n\tassert.IsType(t, &getEndpoint{}, extractHandler(router, \"/get\"))\n\tassert.IsType(t, &listEndpoint{}, extractHandler(router, \"/list\"))\n\tassert.IsType(t, &saveEndpoint{}, extractHandler(router, \"/save\"))\n}\n\nfunc extractHandler(router *http.ServeMux, path string) http.Handler {\n\treq, _ := http.NewRequest(\"GET\", path, nil)\n\thandler, _ := router.Handler(req)\n\treturn handler\n}\n"
  },
  {
    "path": "ch11/01_di_induced_damage/10_needless_indirection/01_mux_e2e.go",
    "content": "package needless_indirection\n\nimport (\n\t\"net/http\"\n)\n\n// build HTTP handler routing\nfunc buildRouter(mux *http.ServeMux) {\n\tmux.Handle(\"/get\", &getEndpoint{})\n\tmux.Handle(\"/list\", &listEndpoint{})\n\tmux.Handle(\"/save\", &saveEndpoint{})\n}\n\ntype getEndpoint struct{}\n\nfunc (*getEndpoint) ServeHTTP(resp http.ResponseWriter, _ *http.Request) {\n\t_, _ = resp.Write([]byte(`Hi from Get!`))\n}\n\ntype listEndpoint struct{}\n\nfunc (*listEndpoint) ServeHTTP(resp http.ResponseWriter, _ *http.Request) {\n\t_, _ = resp.Write([]byte(`Hi from List!`))\n}\n\ntype saveEndpoint struct{}\n\nfunc (*saveEndpoint) ServeHTTP(resp http.ResponseWriter, _ *http.Request) {\n\t_, _ = resp.Write([]byte(`Hi from Save!`))\n}\n"
  },
  {
    "path": "ch11/01_di_induced_damage/10_needless_indirection/01_mux_e2e_test.go",
    "content": "package needless_indirection\n\nimport (\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestBuildRouter(t *testing.T) {\n\trouter := http.NewServeMux()\n\n\t// call function\n\tbuildRouter(router)\n\n\t// start a server\n\taddress := \":8080\"\n\tgo func() {\n\t\t_ = http.ListenAndServe(address, router)\n\t}()\n\n\t// call endpoints\n\tresponseBody := doGet(t, address+\"/get\")\n\tassert.Equal(t, `Hi from Get!`, responseBody)\n\n\tresponseBody = doGet(t, address+\"/list\")\n\tassert.Equal(t, `Hi from List!`, responseBody)\n\n\tresponseBody = doGet(t, address+\"/save\")\n\tassert.Equal(t, `Hi from Save!`, responseBody)\n\n}\n\nfunc doGet(t *testing.T, address string) string {\n\tresp, err := http.Get(\"http://\" + address)\n\trequire.NoError(t, err)\n\n\tbody, err := ioutil.ReadAll(resp.Body)\n\trequire.NoError(t, err)\n\n\tdefer resp.Body.Close()\n\treturn string(body)\n}\n"
  },
  {
    "path": "ch11/01_di_induced_damage/11_service_locator/01_service_locator.go",
    "content": "package service_locator\n\nfunc NewServiceLocator() *ServiceLocator {\n\treturn &ServiceLocator{\n\t\tdeps: map[string]interface{}{},\n\t}\n}\n\ntype ServiceLocator struct {\n\tdeps map[string]interface{}\n}\n\n// Store or map a dependency to a key\nfunc (s *ServiceLocator) Store(key string, dep interface{}) {\n\ts.deps[key] = dep\n}\n\n// Retrieve a dependency by key\nfunc (s *ServiceLocator) Get(key string) interface{} {\n\treturn s.deps[key]\n}\n"
  },
  {
    "path": "ch11/01_di_induced_damage/11_service_locator/02_usage.go",
    "content": "package service_locator\n\nfunc Example() {\n\tlocator := buildServiceLocator()\n\tuseServiceLocator(locator)\n}\n\nfunc buildServiceLocator() *ServiceLocator {\n\t// build a service locator\n\tlocator := NewServiceLocator()\n\n\t// load the dependency mappings\n\tlocator.Store(\"logger\", &myLogger{})\n\tlocator.Store(\"converter\", &myConverter{})\n\n\treturn locator\n}\n\nfunc useServiceLocator(locator *ServiceLocator) {\n\t// use the locators to get the logger\n\tlogger := locator.Get(\"logger\").(Logger)\n\n\t// use the logger\n\tlogger.Info(\"Hello World!\")\n}\n\nfunc useServiceLocatorExtended(locator *ServiceLocator) {\n\t// use the locators to get the logger\n\tloggerRetrieved := locator.Get(\"logger\")\n\tif loggerRetrieved == nil {\n\t\treturn\n\t}\n\tlogger, ok := loggerRetrieved.(Logger)\n\tif !ok {\n\t\treturn\n\t}\n\n\t// use the logger\n\tlogger.Info(\"Hello World!\")\n}\n\ntype Logger interface {\n\tInfo(message string, args ...interface{})\n}\n\ntype myLogger struct{}\n\nfunc (m *myLogger) Info(message string, args ...interface{}) {\n\t// not implemented\n}\n\ntype Converter interface {\n\tConvert(int float64) (float64, error)\n}\n\ntype myConverter struct{}\n\nfunc (m *myConverter) Convert(in float64) (float64, error) {\n\t// not implemented\n\treturn 0, nil\n}\n"
  },
  {
    "path": "ch11/02_premature_future/get.go",
    "content": "package rest\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/gorilla/mux\"\n)\n\nconst (\n\t// default person id (returned on error)\n\tdefaultPersonID = 0\n\n\t// key in the mux where the ID is stored\n\tmuxVarID = \"id\"\n)\n\n// GetModel will load a registration\ntype GetModel interface {\n\tDo(ID int) (*Person, error)\n}\n\n// GetConfig is the config for the Get Handler\ntype GetConfig interface {\n\tLogger() Logger\n}\n\n// Formatter will convert the supplied object to bytes\ntype Formatter interface {\n\tMarshal(interface{}) ([]byte, error)\n}\n\n// NewGetHandler is the constructor for GetHandler\nfunc NewGetHandler(cfg GetConfig, model GetModel, formatter Formatter) *GetHandler {\n\treturn &GetHandler{\n\t\tcfg:       cfg,\n\t\tgetter:    model,\n\t\tformatter: formatter,\n\t}\n}\n\n// GetHandler is the HTTP handler for the \"Get Person\" endpoint\ntype GetHandler struct {\n\tcfg       GetConfig\n\tgetter    GetModel\n\tformatter Formatter\n}\n\n// ServeHTTP implements http.Handler\nfunc (h *GetHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\t// extract person id from request\n\tid, err := h.extractID(request)\n\tif err != nil {\n\t\t// output error\n\t\tresponse.WriteHeader(http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// attempt get\n\tperson, err := h.getter.Do(id)\n\tif err != nil {\n\t\t// not need to log here as we can expect other layers to do so\n\t\tresponse.WriteHeader(http.StatusNotFound)\n\t\treturn\n\t}\n\n\t// happy path\n\terr = h.buildOutput(response, person)\n\tif err != nil {\n\t\t// this error should not happen but if it does there is nothing we can do to recover\n\t\tresponse.WriteHeader(http.StatusInternalServerError)\n\t}\n}\n\n// extract the person ID from the request\nfunc (h *GetHandler) extractID(request *http.Request) (int, error) {\n\t// ID is part of the URL, so we extract it from there\n\tvars := mux.Vars(request)\n\tidAsString, exists := vars[muxVarID]\n\tif !exists {\n\t\t// log and return error\n\t\terr := errors.New(\"[get] person id missing from request\")\n\t\th.cfg.Logger().Warn(err.Error())\n\t\treturn defaultPersonID, err\n\t}\n\n\t// convert ID to int\n\tid, err := strconv.Atoi(idAsString)\n\tif err != nil {\n\t\t// log and return error\n\t\terr = fmt.Errorf(\"[get] failed to convert person id into a number. err: %s\", err)\n\t\th.cfg.Logger().Error(err.Error())\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn id, nil\n}\n\n// output the supplied person\nfunc (h *GetHandler) buildOutput(writer io.Writer, person *Person) error {\n\toutput := &getResponseFormat{\n\t\tID:       person.ID,\n\t\tFullName: person.FullName,\n\t\tPhone:    person.Phone,\n\t\tCurrency: person.Currency,\n\t\tPrice:    person.Price,\n\t}\n\n\t// build output payload\n\tpayload, err := h.formatter.Marshal(output)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// write payload to response and return\n\t_, err = writer.Write(payload)\n\treturn err\n}\n\n// the JSON response format\ntype getResponseFormat struct {\n\tID       int     `json:\"id\"`\n\tFullName string  `json:\"name\"`\n\tPhone    string  `json:\"phone\"`\n\tCurrency string  `json:\"currency\"`\n\tPrice    float64 `json:\"price\"`\n}\n\ntype Person struct {\n\tID       int\n\tFullName string\n\tPhone    string\n\tCurrency string\n\tPrice    float64\n}\n\ntype Logger interface {\n\tDebug(message string, args ...interface{})\n\tInfo(message string, args ...interface{})\n\tWarn(message string, args ...interface{})\n\tError(message string, args ...interface{})\n}\n"
  },
  {
    "path": "ch11/03_mocking_http_requests/converter.go",
    "content": "package mocking_http_reques\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"math\"\n\t\"net/http\"\n\t\"time\"\n)\n\nconst (\n\t// request URL for the exchange rate API\n\turlFormat = \"%s/api/historical?access_key=%s&date=2018-06-20&currencies=%s\"\n\n\t// default price that is sent when an error occurs\n\tdefaultPrice = 0.0\n)\n\n// Config is the config for Converter\ntype Config interface {\n\tLogger() Logger\n\tExchangeBaseURL() string\n\tExchangeAPIKey() string\n}\n\n// NewConverter creates and initializes the converter\nfunc NewConverter(cfg Config, requester Requester) *Converter {\n\treturn &Converter{\n\t\tcfg:       cfg,\n\t\trequester: requester,\n\t}\n}\n\n// Converter will convert the base price to the currency supplied\ntype Converter struct {\n\tcfg       Config\n\trequester Requester\n}\n\n// Exchange will perform the conversion\nfunc (c *Converter) Exchange(ctx context.Context, basePrice float64, currency string) (float64, error) {\n\t// load rate from the external API\n\tresponse, err := c.loadRateFromServer(ctx, currency)\n\tif err != nil {\n\t\treturn defaultPrice, err\n\t}\n\n\t// extract rate from response\n\trate, err := c.extractRate(response, currency)\n\tif err != nil {\n\t\treturn defaultPrice, err\n\t}\n\n\t// apply rate and round to 2 decimal places\n\treturn math.Floor((basePrice/rate)*100) / 100, nil\n}\n\n// load rate from the external API\nfunc (c *Converter) loadRateFromServer(ctx context.Context, currency string) (*http.Response, error) {\n\t// build the request\n\turl := fmt.Sprintf(urlFormat,\n\t\tc.cfg.ExchangeBaseURL(),\n\t\tc.cfg.ExchangeAPIKey(),\n\t\tcurrency)\n\n\t// perform request\n\tresponse, err := c.requester.doRequest(ctx, url)\n\tif err != nil {\n\t\tc.logger().Warn(\"[exchange] failed to load. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\tif response.StatusCode != http.StatusOK {\n\t\terr = fmt.Errorf(\"request failed with code %d\", response.StatusCode)\n\t\tc.logger().Warn(\"[exchange] %s\", err)\n\t\treturn nil, err\n\t}\n\n\treturn response, nil\n}\n\nfunc (c *Converter) extractRate(response *http.Response, currency string) (float64, error) {\n\tdefer func() {\n\t\t_ = response.Body.Close()\n\t}()\n\n\t// extract data from response\n\tdata, err := c.extractResponse(response)\n\tif err != nil {\n\t\treturn defaultPrice, err\n\t}\n\n\t// pull rate from response data\n\trate, found := data.Quotes[\"USD\"+currency]\n\tif !found {\n\t\terr = fmt.Errorf(\"response did not include expected currency '%s'\", currency)\n\t\tc.logger().Error(\"[exchange] %s\", err)\n\t\treturn defaultPrice, err\n\t}\n\n\t// happy path\n\treturn rate, nil\n}\n\nfunc (c *Converter) extractResponse(response *http.Response) (*apiResponseFormat, error) {\n\tpayload, err := ioutil.ReadAll(response.Body)\n\tif err != nil {\n\t\tc.logger().Error(\"[exchange] failed to ready response body. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\tdata := &apiResponseFormat{}\n\terr = json.Unmarshal(payload, data)\n\tif err != nil {\n\t\tc.logger().Error(\"[exchange] error converting response. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// happy path\n\treturn data, nil\n}\n\nfunc (c *Converter) logger() Logger {\n\treturn c.cfg.Logger()\n}\n\n// the response format from the exchange rate API\ntype apiResponseFormat struct {\n\tQuotes map[string]float64 `json:\"quotes\"`\n}\n\n// Requester builds and sending HTTP requests\n//go:generate mockery -name=Requester -case underscore -testonly -inpkg -note @generated\ntype Requester interface {\n\tdoRequest(ctx context.Context, url string) (*http.Response, error)\n}\n\n// Requesterer is the default implementation of Requester\ntype Requesterer struct {\n}\n\nfunc (r *Requesterer) doRequest(ctx context.Context, url string) (*http.Response, error) {\n\treq, err := http.NewRequest(\"GET\", url, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// set latency budget for the upstream call\n\tsubCtx, cancel := context.WithTimeout(ctx, 1*time.Second)\n\tdefer cancel()\n\n\t// replace the default context with our custom one\n\treq = req.WithContext(subCtx)\n\n\t// perform the HTTP request\n\treturn http.DefaultClient.Do(req)\n}\n\ntype Logger interface {\n\tWarn(message string, args ...interface{})\n\tError(message string, args ...interface{})\n}\n\ntype stubLogger struct{}\n\nfunc (l *stubLogger) Warn(message string, args ...interface{}) {\n\t// do nothing\n}\n\nfunc (l *stubLogger) Error(message string, args ...interface{}) {\n\t// do nothing\n}\n"
  },
  {
    "path": "ch11/03_mocking_http_requests/converter_test.go",
    "content": "package mocking_http_reques\n\nimport (\n\t\"context\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestExchange_invalidResponse(t *testing.T) {\n\t// build response\n\tresponse := httptest.NewRecorder()\n\t_, err := response.WriteString(`invalid payload`)\n\trequire.NoError(t, err)\n\n\t// configure mock\n\tmockRequester := &mockRequester{}\n\tmockRequester.On(\"doRequest\", mock.Anything, mock.Anything).Return(response.Result(), nil).Once()\n\n\t// inputs\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\tbasePrice := 12.34\n\tcurrency := \"AUD\"\n\n\t// perform call\n\tconverter := &Converter{\n\t\trequester: mockRequester,\n\t\tcfg:       &testConfig{},\n\t}\n\tresult, resultErr := converter.Exchange(ctx, basePrice, currency)\n\n\t// validate response\n\tassert.Equal(t, float64(0), result)\n\tassert.Error(t, resultErr)\n\tassert.True(t, mockRequester.AssertExpectations(t))\n}\n\n// stub config that returns known values\ntype testConfig struct {\n}\n\nfunc (t *testConfig) Logger() Logger {\n\treturn &stubLogger{}\n}\n\nfunc (t *testConfig) ExchangeBaseURL() string {\n\treturn \"http://www.example.com\"\n}\n\nfunc (t *testConfig) ExchangeAPIKey() string {\n\treturn \"foo\"\n}\n"
  },
  {
    "path": "ch11/03_mocking_http_requests/mock_requester_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage mocking_http_reques\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// mockRequester is an autogenerated mock type for the requester type\ntype mockRequester struct {\n\tmock.Mock\n}\n\n// doRequest provides a mock function with given fields: ctx, url\nfunc (_m *mockRequester) doRequest(ctx context.Context, url string) (*http.Response, error) {\n\tret := _m.Called(ctx, url)\n\n\tvar r0 *http.Response\n\tif rf, ok := ret.Get(0).(func(context.Context, string) *http.Response); ok {\n\t\tr0 = rf(ctx, url)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*http.Response)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, string) error); ok {\n\t\tr1 = rf(ctx, url)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch11/acme/internal/config/config.go",
    "content": "package config\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"os\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/logging\"\n)\n\n// DefaultEnvVar is the default environment variable the points to the config file\nconst DefaultEnvVar = \"ACME_CONFIG\"\n\n// Config defines the JSON format for the config file\ntype Config struct {\n\t// DSN is the data source name (format: https://github.com/go-sql-driver/mysql/#dsn-data-source-name)\n\tDSN string\n\n\t// Address is the IP address and port to bind this rest to\n\tAddress string\n\n\t// BasePrice is the price of registration\n\tBasePrice float64\n\n\t// ExchangeRateBaseURL is the server and protocol part of the URL from which to load the exchange rate\n\tExchangeRateBaseURL string\n\n\t// ExchangeRateAPIKey is the API for the exchange rate API\n\tExchangeRateAPIKey string\n\n\t// environmental dependencies\n\tlogger logging.Logger\n}\n\n// Logger returns a reference to the singleton logger\nfunc (c *Config) Logger() logging.Logger {\n\tif c.logger == nil {\n\t\tc.logger = &logging.LoggerStdOut{}\n\t}\n\n\treturn c.logger\n}\n\n// RegistrationBasePrice returns the base price for registrations\nfunc (c *Config) RegistrationBasePrice() float64 {\n\treturn c.BasePrice\n}\n\n// DataDSN returns the DSN\nfunc (c *Config) DataDSN() string {\n\treturn c.DSN\n}\n\n// ExchangeBaseURL returns the Base URL from which we can load exchange rates\nfunc (c *Config) ExchangeBaseURL() string {\n\treturn c.ExchangeRateBaseURL\n}\n\n// ExchangeAPIKey returns the DSN\nfunc (c *Config) ExchangeAPIKey() string {\n\treturn c.ExchangeRateAPIKey\n}\n\n// BindAddress returns the host and port this service should bind to\nfunc (c *Config) BindAddress() string {\n\treturn c.Address\n}\n\n// Load returns the config loaded from environment\nfunc Load() (*Config, error) {\n\tfilename, found := os.LookupEnv(DefaultEnvVar)\n\tif !found {\n\t\terr := fmt.Errorf(\"failed to locate file specified by %s\", DefaultEnvVar)\n\t\tfmt.Fprintf(os.Stderr, err.Error())\n\t\treturn nil, err\n\t}\n\n\tcfg, err := load(filename)\n\tif err != nil {\n\t\tfmt.Fprintf(os.Stderr, \"failed to load config with err %s\", err)\n\t\treturn nil, err\n\t}\n\n\treturn cfg, nil\n}\n\nfunc load(filename string) (*Config, error) {\n\tout := &Config{}\n\tbytes, err := ioutil.ReadFile(filename)\n\tif err != nil {\n\t\tfmt.Fprintf(os.Stderr, \"failed to read config file. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\terr = json.Unmarshal(bytes, out)\n\tif err != nil {\n\t\tfmt.Fprintf(os.Stderr, \"failed to parse config file. err : %s\", err)\n\t\treturn nil, err\n\t}\n\n\treturn out, nil\n}\n"
  },
  {
    "path": "ch11/acme/internal/config/config_test.go",
    "content": "package config\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestLoad(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc           string\n\t\tin             string\n\t\texpectedConfig *Config\n\t\texpectError    bool\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tin:   \"../../../../default-config.json\",\n\t\t\texpectedConfig: &Config{\n\t\t\t\tDSN:                 \"[insert your db config here]\",\n\t\t\t\tAddress:             \"0.0.0.0:8080\",\n\t\t\t\tBasePrice:           100.00,\n\t\t\t\tExchangeRateBaseURL: \"http://apilayer.net\",\n\t\t\t\tExchangeRateAPIKey:  \"[insert your API key here]\",\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tdesc:           \"invalid path\",\n\t\t\tin:             \"invalid.json\",\n\t\t\texpectedConfig: nil,\n\t\t\texpectError:    true,\n\t\t},\n\t}\n\n\tfor _, s := range scenarios {\n\t\tscenario := s\n\t\tt.Run(scenario.desc, func(t *testing.T) {\n\t\t\tresult, resultErr := load(scenario.in)\n\t\t\trequire.Equal(t, scenario.expectError, resultErr != nil, \"err: %s\", resultErr)\n\t\t\tassert.Equal(t, scenario.expectedConfig, result, scenario.desc)\n\t\t})\n\t}\n\n}\n"
  },
  {
    "path": "ch11/acme/internal/logging/logging.go",
    "content": "package logging\n\nimport (\n\t\"fmt\"\n)\n\n// Logger is our standard interface\ntype Logger interface {\n\tDebug(message string, args ...interface{})\n\tInfo(message string, args ...interface{})\n\tWarn(message string, args ...interface{})\n\tError(message string, args ...interface{})\n}\n\n// LoggerStdOut logs to std out\ntype LoggerStdOut struct{}\n\n// Debug logs messages at DEBUG level\nfunc (l LoggerStdOut) Debug(message string, args ...interface{}) {\n\tfmt.Printf(\"[DEBUG] \"+message, args...)\n}\n\n// Info logs messages at INFO level\nfunc (l LoggerStdOut) Info(message string, args ...interface{}) {\n\tfmt.Printf(\"[INFO] \"+message, args...)\n}\n\n// Warn logs messages at WARN level\nfunc (l LoggerStdOut) Warn(message string, args ...interface{}) {\n\tfmt.Printf(\"[WARN] \"+message, args...)\n}\n\n// Error logs messages at ERROR level\nfunc (l LoggerStdOut) Error(message string, args ...interface{}) {\n\tfmt.Printf(\"[ERROR] \"+message, args...)\n}\n"
  },
  {
    "path": "ch11/acme/internal/modules/data/dao.go",
    "content": "package data\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"time\"\n)\n\n// NewDAO will initialize the database connection pool (if not already done) and return a data access object which\n// can be used to interact with the database\nfunc NewDAO(cfg Config) *DAO {\n\t// initialize the db connection pool\n\t_, _ = getDB(cfg)\n\n\treturn &DAO{\n\t\tcfg: cfg,\n\t}\n}\n\n// DAO is a data access object that provides an abstraction over our database interactions.\ntype DAO struct {\n\tcfg Config\n\n\t// Tracker is an optional query timer\n\tTracker QueryTracker\n}\n\n// Load will attempt to load and return a person.\n// It will return ErrNotFound when the requested person does not exist.\n// Any other errors returned are caused by the underlying database or our connection to it.\nfunc (d *DAO) Load(ctx context.Context, ID int) (*Person, error) {\n\t// track processing time\n\tdefer d.getTracker().Track(\"Load\", time.Now())\n\n\tdb, err := getDB(d.cfg)\n\tif err != nil {\n\t\td.cfg.Logger().Error(\"failed to get DB connection. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// set latency budget for the database call\n\tsubCtx, cancel := context.WithTimeout(ctx, 1*time.Second)\n\tdefer cancel()\n\n\t// perform DB select\n\trow := db.QueryRowContext(subCtx, sqlLoadByID, ID)\n\n\t// retrieve columns and populate the person object\n\tout, err := populatePerson(row.Scan)\n\tif err != nil {\n\t\tif err == sql.ErrNoRows {\n\t\t\td.cfg.Logger().Warn(\"failed to load requested person '%d'. err: %s\", ID, err)\n\t\t\treturn nil, ErrNotFound\n\t\t}\n\n\t\td.cfg.Logger().Error(\"failed to convert query result. err: %s\", err)\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\n// LoadAll will attempt to load all people in the database\n// It will return ErrNotFound when there are not people in the database\n// Any other errors returned are caused by the underlying database or our connection to it.\nfunc (d *DAO) LoadAll(ctx context.Context) ([]*Person, error) {\n\t// track processing time\n\tdefer d.getTracker().Track(\"LoadAll\", time.Now())\n\n\tdb, err := getDB(d.cfg)\n\tif err != nil {\n\t\td.cfg.Logger().Error(\"failed to get DB connection. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// set latency budget for the database call\n\tsubCtx, cancel := context.WithTimeout(ctx, 1*time.Second)\n\tdefer cancel()\n\n\t// perform DB select\n\trows, err := db.QueryContext(subCtx, sqlLoadAll)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer func() {\n\t\t_ = rows.Close()\n\t}()\n\n\tvar out []*Person\n\n\tfor rows.Next() {\n\t\t// retrieve columns and populate the person object\n\t\trecord, err := populatePerson(rows.Scan)\n\t\tif err != nil {\n\t\t\td.cfg.Logger().Error(\"failed to convert query result. err: %s\", err)\n\t\t\treturn nil, err\n\t\t}\n\n\t\tout = append(out, record)\n\t}\n\n\tif len(out) == 0 {\n\t\td.cfg.Logger().Warn(\"no people found in the database.\")\n\t\treturn nil, ErrNotFound\n\t}\n\n\treturn out, nil\n}\n\n// Save will save the supplied person and return the ID of the newly created person or an error.\n// Errors returned are caused by the underlying database or our connection to it.\nfunc (d *DAO) Save(ctx context.Context, in *Person) (int, error) {\n\t// track processing time\n\tdefer d.getTracker().Track(\"Save\", time.Now())\n\n\tdb, err := getDB(d.cfg)\n\tif err != nil {\n\t\td.cfg.Logger().Error(\"failed to get DB connection. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\t// set latency budget for the database call\n\tsubCtx, cancel := context.WithTimeout(ctx, 1*time.Second)\n\tdefer cancel()\n\n\t// perform DB insert\n\tresult, err := db.ExecContext(subCtx, sqlInsert, in.FullName, in.Phone, in.Currency, in.Price)\n\tif err != nil {\n\t\td.cfg.Logger().Error(\"failed to save person into DB. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\t// retrieve and return the ID of the person created\n\tid, err := result.LastInsertId()\n\tif err != nil {\n\t\td.cfg.Logger().Error(\"failed to retrieve id of last saved person. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn int(id), nil\n}\n\nfunc (d *DAO) getTracker() QueryTracker {\n\tif d.Tracker == nil {\n\t\td.Tracker = &noopTracker{}\n\t}\n\n\treturn d.Tracker\n}\n"
  },
  {
    "path": "ch11/acme/internal/modules/data/data.go",
    "content": "package data\n\nimport (\n\t\"database/sql\"\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/logging\"\n\t_ \"github.com/go-sql-driver/mysql\"\n)\n\nconst (\n\t// default person id (returned on error)\n\tdefaultPersonID = 0\n\n\t// SQL statements as constants (to reduce duplication and maintenance in tests)\n\tsqlAllColumns = \"id, fullname, phone, currency, price\"\n\tsqlInsert     = \"INSERT INTO person (fullname, phone, currency, price) VALUES (?, ?, ?, ?)\"\n\tsqlLoadAll    = \"SELECT \" + sqlAllColumns + \" FROM person\"\n\tsqlLoadByID   = \"SELECT \" + sqlAllColumns + \" FROM person WHERE id = ? LIMIT 1\"\n)\n\nvar (\n\tdb *sql.DB\n\n\t// ErrNotFound is returned when the no records where matched by the query\n\tErrNotFound = errors.New(\"not found\")\n)\n\n// Config is the configuration for the data package\ntype Config interface {\n\t// Logger returns a reference to the logger\n\tLogger() logging.Logger\n\n\t// DataDSN returns the data source name\n\tDataDSN() string\n}\n\nvar getDB = func(cfg Config) (*sql.DB, error) {\n\tif db == nil {\n\t\tvar err error\n\t\tdb, err = sql.Open(\"mysql\", cfg.DataDSN())\n\t\tif err != nil {\n\t\t\t// if the DB cannot be accessed we are dead\n\t\t\tpanic(err.Error())\n\t\t}\n\t}\n\n\treturn db, nil\n}\n\n// Person is the data transfer object (DTO) for this package\ntype Person struct {\n\t// ID is the unique ID for this person\n\tID int\n\t// FullName is the name of this person\n\tFullName string\n\t// Phone is the phone for this person\n\tPhone string\n\t// Currency is the currency this person has paid in\n\tCurrency string\n\t// Price is the amount (in the above currency) paid by this person\n\tPrice float64\n}\n\n// custom type so we can convert sql results to easily\ntype scanner func(dest ...interface{}) error\n\n// reduce the duplication (and maintenance) between sql.Row and sql.Rows usage\nfunc populatePerson(scanner scanner) (*Person, error) {\n\tout := &Person{}\n\terr := scanner(&out.ID, &out.FullName, &out.Phone, &out.Currency, &out.Price)\n\treturn out, err\n}\n"
  },
  {
    "path": "ch11/acme/internal/modules/data/data_test.go",
    "content": "package data\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"errors\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/DATA-DOG/go-sqlmock\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/logging\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestSave_happyPath(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\t// define a mock db\n\ttestDb, dbMock, err := sqlmock.New()\n\tdefer testDb.Close()\n\trequire.NoError(t, err)\n\n\t// configure the mock db\n\tqueryRegex := convertSQLToRegex(sqlInsert)\n\tdbMock.ExpectExec(queryRegex).WillReturnResult(sqlmock.NewResult(2, 1))\n\n\t// monkey patching starts here\n\tdb = testDb\n\t// end of monkey patch\n\n\t// inputs\n\tin := &Person{\n\t\tFullName: \"Jake Blues\",\n\t\tPhone:    \"01234567890\",\n\t\tCurrency: \"AUD\",\n\t\tPrice:    123.45,\n\t}\n\n\t// call function\n\tdao := NewDAO(&testConfig{})\n\tresultID, err := dao.Save(ctx, in)\n\n\t// validate result\n\trequire.NoError(t, err)\n\tassert.Equal(t, 2, resultID)\n\tassert.NoError(t, dbMock.ExpectationsWereMet())\n}\n\nfunc TestSave_insertError(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\t// define a mock db\n\ttestDb, dbMock, err := sqlmock.New()\n\tdefer testDb.Close()\n\n\trequire.NoError(t, err)\n\n\t// configure the mock db\n\tqueryRegex := convertSQLToRegex(sqlInsert)\n\tdbMock.ExpectExec(queryRegex).WillReturnError(errors.New(\"failed to insert\"))\n\n\t// monkey patching starts here\n\tdb = testDb\n\t// end of monkey patch\n\n\t// inputs\n\tin := &Person{\n\t\tFullName: \"Jake Blues\",\n\t\tPhone:    \"01234567890\",\n\t\tCurrency: \"AUD\",\n\t\tPrice:    123.45,\n\t}\n\n\t// call function\n\tdao := NewDAO(&testConfig{})\n\tresultID, err := dao.Save(ctx, in)\n\n\t// validate result\n\trequire.Error(t, err)\n\tassert.Equal(t, defaultPersonID, resultID)\n\tassert.NoError(t, dbMock.ExpectationsWereMet())\n}\n\nfunc TestSave_getDBError(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\t// monkey patching starts here\n\tdefer func(original func(_ Config) (*sql.DB, error)) {\n\t\t// restore original DB (after test)\n\t\tgetDB = original\n\t}(getDB)\n\n\t// replace getDB() function for this test\n\tgetDB = func(_ Config) (*sql.DB, error) {\n\t\treturn nil, errors.New(\"getDB() failed\")\n\t}\n\t// end of monkey patch\n\n\t// inputs\n\tin := &Person{\n\t\tFullName: \"Jake Blues\",\n\t\tPhone:    \"01234567890\",\n\t\tCurrency: \"AUD\",\n\t\tPrice:    123.45,\n\t}\n\n\t// call function\n\tdao := NewDAO(&testConfig{})\n\tresultID, err := dao.Save(ctx, in)\n\trequire.Error(t, err)\n\tassert.Equal(t, defaultPersonID, resultID)\n}\n\nfunc TestLoadAll_tableDrivenTest(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\n\tdefer cancel()\n\n\tscenarios := []struct {\n\t\tdesc            string\n\t\tconfigureMockDB func(sqlmock.Sqlmock)\n\t\texpectedResults []*Person\n\t\texpectError     bool\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tconfigureMockDB: func(dbMock sqlmock.Sqlmock) {\n\t\t\t\tqueryRegex := convertSQLToRegex(sqlLoadAll)\n\t\t\t\tdbMock.ExpectQuery(queryRegex).WillReturnRows(\n\t\t\t\t\tsqlmock.NewRows(strings.Split(sqlAllColumns, \", \")).\n\t\t\t\t\t\tAddRow(1, \"John\", \"0123456789\", \"AUD\", 12.34))\n\t\t\t},\n\t\t\texpectedResults: []*Person{\n\t\t\t\t{\n\t\t\t\t\tID:       1,\n\t\t\t\t\tFullName: \"John\",\n\t\t\t\t\tPhone:    \"0123456789\",\n\t\t\t\t\tCurrency: \"AUD\",\n\t\t\t\t\tPrice:    12.34,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tdesc: \"load error\",\n\t\t\tconfigureMockDB: func(dbMock sqlmock.Sqlmock) {\n\t\t\t\tqueryRegex := convertSQLToRegex(sqlLoadAll)\n\t\t\t\tdbMock.ExpectQuery(queryRegex).WillReturnError(errors.New(\"something failed\"))\n\t\t\t},\n\t\t\texpectedResults: nil,\n\t\t\texpectError:     true,\n\t\t},\n\t}\n\n\tfor _, scenario := range scenarios {\n\t\t// define a mock db\n\t\ttestDb, dbMock, err := sqlmock.New()\n\t\trequire.NoError(t, err)\n\n\t\t// configure the mock db\n\t\tscenario.configureMockDB(dbMock)\n\n\t\t// monkey patch the db for this test\n\t\toriginal := *db\n\t\tdb = testDb\n\n\t\t// call function\n\t\tdao := NewDAO(&testConfig{})\n\t\tresults, err := dao.LoadAll(ctx)\n\n\t\t// validate results\n\t\tassert.Equal(t, scenario.expectedResults, results, scenario.desc)\n\t\tassert.Equal(t, scenario.expectError, err != nil, scenario.desc)\n\t\tassert.NoError(t, dbMock.ExpectationsWereMet())\n\n\t\t// restore original DB (after test)\n\t\tdb = &original\n\t\ttestDb.Close()\n\t}\n}\n\nfunc TestLoad_tableDrivenTest(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\n\tdefer cancel()\n\n\tscenarios := []struct {\n\t\tdesc            string\n\t\tconfigureMockDB func(sqlmock.Sqlmock)\n\t\texpectedResult  *Person\n\t\texpectError     bool\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tconfigureMockDB: func(dbMock sqlmock.Sqlmock) {\n\t\t\t\tqueryRegex := convertSQLToRegex(sqlLoadAll)\n\t\t\t\tdbMock.ExpectQuery(queryRegex).WillReturnRows(\n\t\t\t\t\tsqlmock.NewRows(strings.Split(sqlAllColumns, \", \")).\n\t\t\t\t\t\tAddRow(2, \"Paul\", \"0123456789\", \"CAD\", 23.45))\n\t\t\t},\n\t\t\texpectedResult: &Person{\n\t\t\t\tID:       2,\n\t\t\t\tFullName: \"Paul\",\n\t\t\t\tPhone:    \"0123456789\",\n\t\t\t\tCurrency: \"CAD\",\n\t\t\t\tPrice:    23.45,\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tdesc: \"load error\",\n\t\t\tconfigureMockDB: func(dbMock sqlmock.Sqlmock) {\n\t\t\t\tqueryRegex := convertSQLToRegex(sqlLoadAll)\n\t\t\t\tdbMock.ExpectQuery(queryRegex).WillReturnError(errors.New(\"something failed\"))\n\t\t\t},\n\t\t\texpectedResult: nil,\n\t\t\texpectError:    true,\n\t\t},\n\t}\n\n\tfor _, scenario := range scenarios {\n\t\t// define a mock db\n\t\ttestDb, dbMock, err := sqlmock.New()\n\t\trequire.NoError(t, err)\n\n\t\t// configure the mock db\n\t\tscenario.configureMockDB(dbMock)\n\n\t\t// monkey db for this test\n\t\toriginal := *db\n\t\tdb = testDb\n\n\t\t// call function\n\t\tdao := NewDAO(&testConfig{})\n\t\tresult, err := dao.Load(ctx, 2)\n\n\t\t// validate results\n\t\tassert.Equal(t, scenario.expectedResult, result, scenario.desc)\n\t\tassert.Equal(t, scenario.expectError, err != nil, scenario.desc)\n\t\tassert.NoError(t, dbMock.ExpectationsWereMet())\n\n\t\t// restore original DB (after test)\n\t\tdb = &original\n\t\ttestDb.Close()\n\t}\n}\n\n// convert SQL string to regex by treating the entire query as a literal\nfunc convertSQLToRegex(in string) string {\n\treturn `\\Q` + in + `\\E`\n}\n\ntype testConfig struct{}\n\n// Logger implements Config\nfunc (t *testConfig) Logger() logging.Logger {\n\treturn logging.LoggerStdOut{}\n}\n\n// DataDSN implements Config\nfunc (t *testConfig) DataDSN() string {\n\treturn \"\"\n}\n"
  },
  {
    "path": "ch11/acme/internal/modules/data/tracker.go",
    "content": "package data\n\nimport (\n\t\"time\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/logging\"\n)\n\n// QueryTracker is an interface to track query timing\ntype QueryTracker interface {\n\t// Track will record/out the time a query took by calculating time.Now().Sub(start)\n\tTrack(key string, start time.Time)\n}\n\n// NO-OP implementation of QueryTracker\ntype noopTracker struct{}\n\n// Track implements QueryTracker\nfunc (_ *noopTracker) Track(_ string, _ time.Time) {\n\t// intentionally does nothing\n}\n\n// NewLogTracker returns a Tracker that outputs tracking data to log\nfunc NewLogTracker(logger logging.Logger) *LogTracker {\n\treturn &LogTracker{\n\t\tlogger: logger,\n\t}\n}\n\n// LogTracker implements QueryTracker and outputs to the supplied logger\ntype LogTracker struct {\n\tlogger logging.Logger\n}\n\n// Track implements QueryTracker\nfunc (l *LogTracker) Track(key string, start time.Time) {\n\tl.logger.Info(\"[%s] Timing: %s\\n\", key, time.Now().Sub(start).String())\n}\n"
  },
  {
    "path": "ch11/acme/internal/modules/exchange/converter.go",
    "content": "package exchange\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"math\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/logging\"\n)\n\nconst (\n\t// request URL for the exchange rate API\n\turlFormat = \"%s/api/historical?access_key=%s&date=2018-06-20&currencies=%s\"\n\n\t// default price that is sent when an error occurs\n\tdefaultPrice = 0.0\n)\n\n// NewConverter creates and initializes the converter\nfunc NewConverter(cfg Config) *Converter {\n\treturn &Converter{\n\t\tcfg: cfg,\n\t}\n}\n\n// Config is the config for Converter\ntype Config interface {\n\tLogger() logging.Logger\n\tExchangeBaseURL() string\n\tExchangeAPIKey() string\n}\n\n// Converter will convert the base price to the currency supplied\n// Note: we are expecting sane inputs and therefore skipping input validation\ntype Converter struct {\n\tcfg Config\n}\n\n// Exchange will perform the conversion\nfunc (c *Converter) Exchange(ctx context.Context, basePrice float64, currency string) (float64, error) {\n\t// load rate from the external API\n\tresponse, err := c.loadRateFromServer(ctx, currency)\n\tif err != nil {\n\t\treturn defaultPrice, err\n\t}\n\n\t// extract rate from response\n\trate, err := c.extractRate(response, currency)\n\tif err != nil {\n\t\treturn defaultPrice, err\n\t}\n\n\t// apply rate and round to 2 decimal places\n\treturn math.Floor((basePrice/rate)*100) / 100, nil\n}\n\n// load rate from the external API\nfunc (c *Converter) loadRateFromServer(ctx context.Context, currency string) (*http.Response, error) {\n\t// build the request\n\turl := fmt.Sprintf(urlFormat,\n\t\tc.cfg.ExchangeBaseURL(),\n\t\tc.cfg.ExchangeAPIKey(),\n\t\tcurrency)\n\n\t// perform request\n\treq, err := http.NewRequest(\"GET\", url, nil)\n\tif err != nil {\n\t\tc.logger().Warn(\"[exchange] failed to create request. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// set latency budget for the upstream call\n\tsubCtx, cancel := context.WithTimeout(ctx, 1*time.Second)\n\tdefer cancel()\n\n\t// replace the default context with our custom one\n\treq = req.WithContext(subCtx)\n\n\t// perform the HTTP request\n\tresponse, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tc.logger().Warn(\"[exchange] failed to load. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\tif response.StatusCode != http.StatusOK {\n\t\terr = fmt.Errorf(\"request failed with code %d\", response.StatusCode)\n\t\tc.logger().Warn(\"[exchange] %s\", err)\n\t\treturn nil, err\n\t}\n\n\treturn response, nil\n}\n\nfunc (c *Converter) extractRate(response *http.Response, currency string) (float64, error) {\n\tdefer func() {\n\t\t_ = response.Body.Close()\n\t}()\n\n\t// extract data from response\n\tdata, err := c.extractResponse(response)\n\tif err != nil {\n\t\treturn defaultPrice, err\n\t}\n\n\t// pull rate from response data\n\trate, found := data.Quotes[\"USD\"+currency]\n\tif !found {\n\t\terr = fmt.Errorf(\"response did not include expected currency '%s'\", currency)\n\t\tc.logger().Error(\"[exchange] %s\", err)\n\t\treturn defaultPrice, err\n\t}\n\n\t// happy path\n\treturn rate, nil\n}\n\nfunc (c *Converter) extractResponse(response *http.Response) (*apiResponseFormat, error) {\n\tpayload, err := ioutil.ReadAll(response.Body)\n\tif err != nil {\n\t\tc.logger().Error(\"[exchange] failed to ready response body. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\tdata := &apiResponseFormat{}\n\terr = json.Unmarshal(payload, data)\n\tif err != nil {\n\t\tc.logger().Error(\"[exchange] error converting response. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// happy path\n\treturn data, nil\n}\n\nfunc (c *Converter) logger() logging.Logger {\n\treturn c.cfg.Logger()\n}\n\n// the response format from the exchange rate API\ntype apiResponseFormat struct {\n\tQuotes map[string]float64 `json:\"quotes\"`\n}\n"
  },
  {
    "path": "ch11/acme/internal/modules/exchange/converter_ext_bounday_test.go",
    "content": "// +build external\n\npackage exchange\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/config\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestExternalBoundaryTest(t *testing.T) {\n\t// define the config\n\tcfg, err := config.Load()\n\trequire.NoError(t, err)\n\n\t// create a converter to test\n\tconverter := NewConverter(cfg)\n\n\t// fetch from the server\n\tresponse, err := converter.loadRateFromServer(context.Background(), \"AUD\")\n\trequire.NotNil(t, response)\n\trequire.NoError(t, err)\n\n\t// parse the response\n\tresultRate, err := converter.extractRate(response, \"AUD\")\n\trequire.NoError(t, err)\n\n\t// validate the result\n\tassert.True(t, resultRate > 0)\n}\n"
  },
  {
    "path": "ch11/acme/internal/modules/exchange/converter_int_bounday_test.go",
    "content": "package exchange\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/logging\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestInternalBoundaryTest(t *testing.T) {\n\t// start our test server\n\tserver := httptest.NewServer(&happyExchangeRateService{})\n\tdefer server.Close()\n\n\t// define the config\n\tcfg := &testConfig{\n\t\tbaseURL: server.URL,\n\t\tapiKey:  \"\",\n\t}\n\n\t// create a converter to test\n\tconverter := NewConverter(cfg)\n\tresultRate, resultErr := converter.Exchange(context.Background(), 100.00, \"AUD\")\n\n\t// validate the result\n\tassert.Equal(t, 101.01, resultRate)\n\tassert.NoError(t, resultErr)\n}\n\ntype happyExchangeRateService struct{}\n\n// ServeHTTP implements http.Handler\nfunc (*happyExchangeRateService) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\tpayload := []byte(`\n{\n   \"success\":true,\n   \"historical\":true,\n   \"date\":\"2010-11-09\",\n   \"timestamp\":1289347199,\n   \"source\":\"USD\",\n   \"quotes\":{\n      \"USDAUD\":0.989981\n   }\n}`)\n\tresponse.Write(payload)\n}\n\nfunc TestExchange_invalidResponseFromServer(t *testing.T) {\n\t// start our test server\n\tserver := httptest.NewServer(http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) {\n\t\tpayload := []byte(`invalid payload`)\n\t\tresponse.Write(payload)\n\t}))\n\tdefer server.Close()\n\n\t// inputs\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\tbasePrice := 12.34\n\tcurrency := \"AUD\"\n\n\tcfg := &testConfig{\n\t\tbaseURL: server.URL,\n\t\tapiKey:  \"\",\n\t}\n\n\tconverter := NewConverter(cfg)\n\tresult, resultErr := converter.Exchange(ctx, basePrice, currency)\n\n\t// validate response\n\tassert.Equal(t, float64(0), result)\n\tassert.Error(t, resultErr)\n}\n\n// test implementation of Config\ntype testConfig struct {\n\tbaseURL string\n\tapiKey  string\n}\n\n// Logger implements Config\nfunc (t *testConfig) Logger() logging.Logger {\n\treturn &logging.LoggerStdOut{}\n}\n\n// ExchangeBaseURL implements Config\nfunc (t *testConfig) ExchangeBaseURL() string {\n\treturn t.baseURL\n}\n\n// ExchangeAPIKey implements Config\nfunc (t *testConfig) ExchangeAPIKey() string {\n\treturn t.apiKey\n}\n"
  },
  {
    "path": "ch11/acme/internal/modules/get/get.go",
    "content": "package get\n\nimport (\n\t\"context\"\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/modules/data\"\n)\n\nvar (\n\t// error thrown when the requested person is not in the database\n\terrPersonNotFound = errors.New(\"person not found\")\n)\n\n// NewGetter creates and initializes a Getter\nfunc NewGetter(cfg Config) *Getter {\n\treturn &Getter{\n\t\tcfg: cfg,\n\t}\n}\n\n// Config is the configuration for Getter\ntype Config interface {\n\tLogger() logging.Logger\n\tDataDSN() string\n}\n\n// Getter will attempt to load a person.\n// It can return an error caused by the data layer or when the requested person is not found\ntype Getter struct {\n\tcfg  Config\n\tdata myLoader\n}\n\n// Do will perform the get\nfunc (g *Getter) Do(ID int) (*Person, error) {\n\t// load person from the data layer\n\tperson, err := g.getLoader().Load(context.TODO(), ID)\n\tif err != nil {\n\t\tif err == data.ErrNotFound {\n\t\t\t// By converting the error we are hiding the implementation details from our users.\n\t\t\treturn nil, errPersonNotFound\n\t\t}\n\t\treturn nil, err\n\t}\n\n\treturn g.convert(person), err\n}\n\nfunc (g *Getter) getLoader() myLoader {\n\tif g.data == nil {\n\t\tg.data = data.NewDAO(g.cfg)\n\t}\n\n\treturn g.data\n}\n\nfunc (g *Getter) convert(in *data.Person) *Person {\n\treturn &Person{\n\t\tID:       in.ID,\n\t\tCurrency: in.Currency,\n\t\tFullName: in.FullName,\n\t\tPhone:    in.Phone,\n\t\tPrice:    in.Price,\n\t}\n}\n\n//go:generate mockery -name=myLoader -case underscore -testonly -inpkg -note @generated\ntype myLoader interface {\n\tLoad(ctx context.Context, ID int) (*data.Person, error)\n}\n\n// Person is a copy/sub-set of data.Person so that the relationship does not leak.\n// It also allows us to remove/hide and internal fields\ntype Person struct {\n\tID       int\n\tFullName string\n\tPhone    string\n\tCurrency string\n\tPrice    float64\n}\n"
  },
  {
    "path": "ch11/acme/internal/modules/get/go_test.go",
    "content": "package get\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestGetter_Do_happyPath(t *testing.T) {\n\t// inputs\n\tID := 1234\n\n\t// configure the mock loader\n\tmockResult := &data.Person{\n\t\tID:       1234,\n\t\tFullName: \"Doug\",\n\t}\n\tmockLoader := &mockMyLoader{}\n\tmockLoader.On(\"Load\", mock.Anything, ID).Return(mockResult, nil).Once()\n\n\t// call method\n\tgetter := &Getter{\n\t\tdata: mockLoader,\n\t}\n\tperson, err := getter.Do(ID)\n\n\t// validate expectations\n\trequire.NoError(t, err)\n\tassert.Equal(t, ID, person.ID)\n\tassert.Equal(t, \"Doug\", person.FullName)\n\tassert.True(t, mockLoader.AssertExpectations(t))\n}\n\nfunc TestGetter_Do_noSuchPerson(t *testing.T) {\n\t// inputs\n\tID := 5678\n\n\t// configure the mock loader\n\tmockLoader := &mockMyLoader{}\n\tmockLoader.On(\"Load\", mock.Anything, ID).Return(nil, data.ErrNotFound).Once()\n\n\t// call method\n\tgetter := &Getter{\n\t\tdata: mockLoader,\n\t}\n\tperson, err := getter.Do(ID)\n\n\t// validate expectations\n\trequire.Equal(t, errPersonNotFound, err)\n\tassert.Nil(t, person)\n\tassert.True(t, mockLoader.AssertExpectations(t))\n}\n\nfunc TestGetter_Do_error(t *testing.T) {\n\t// inputs\n\tID := 1234\n\n\t// configure the mock loader\n\tmockLoader := &mockMyLoader{}\n\tmockLoader.On(\"Load\", mock.Anything, ID).Return(nil, errors.New(\"something failed\")).Once()\n\n\t// call method\n\tgetter := &Getter{\n\t\tdata: mockLoader,\n\t}\n\tperson, err := getter.Do(ID)\n\n\t// validate expectations\n\trequire.Error(t, err)\n\tassert.Nil(t, person)\n\tassert.True(t, mockLoader.AssertExpectations(t))\n}\n"
  },
  {
    "path": "ch11/acme/internal/modules/get/mock_my_loader_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage get\n\nimport (\n\t\"context\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// mockMyLoader is an autogenerated mock type for the myLoader type\ntype mockMyLoader struct {\n\tmock.Mock\n}\n\n// Load provides a mock function with given fields: ctx, ID\nfunc (_m *mockMyLoader) Load(ctx context.Context, ID int) (*data.Person, error) {\n\tret := _m.Called(ctx, ID)\n\n\tvar r0 *data.Person\n\tif rf, ok := ret.Get(0).(func(context.Context, int) *data.Person); ok {\n\t\tr0 = rf(ctx, ID)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*data.Person)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, int) error); ok {\n\t\tr1 = rf(ctx, ID)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch11/acme/internal/modules/list/list.go",
    "content": "package list\n\nimport (\n\t\"context\"\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/modules/data\"\n)\n\nvar (\n\t// error thrown when there are no people in the database\n\terrPeopleNotFound = errors.New(\"no people found\")\n)\n\n// NewLister creates and initializes a Lister\nfunc NewLister(cfg Config) *Lister {\n\treturn &Lister{\n\t\tcfg: cfg,\n\t}\n}\n\n// Config is the config for Lister\ntype Config interface {\n\tLogger() logging.Logger\n\tDataDSN() string\n}\n\n// Lister will attempt to load all people in the database.\n// It can return an error caused by the data layer\ntype Lister struct {\n\tcfg  Config\n\tdata myLoader\n}\n\n// Exchange will load the people from the data layer\nfunc (l *Lister) Do() ([]*Person, error) {\n\t// load all people\n\tpeople, err := l.load()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(people) == 0 {\n\t\t// special processing for 0 people returned\n\t\treturn nil, errPeopleNotFound\n\t}\n\n\treturn l.convert(people), nil\n}\n\n// load all people\nfunc (l *Lister) load() ([]*data.Person, error) {\n\tpeople, err := l.getLoader().LoadAll(context.TODO())\n\tif err != nil {\n\t\tif err == data.ErrNotFound {\n\t\t\t// By converting the error we are encapsulating the implementation details from our users.\n\t\t\treturn nil, errPeopleNotFound\n\t\t}\n\t\treturn nil, err\n\t}\n\n\treturn people, nil\n}\n\nfunc (l *Lister) getLoader() myLoader {\n\tif l.data == nil {\n\t\tl.data = data.NewDAO(l.cfg)\n\n\t\t// temporarily add a log tracker\n\t\tl.data.(*data.DAO).Tracker = data.NewLogTracker(l.cfg.Logger())\n\t}\n\n\treturn l.data\n}\n\nfunc (l *Lister) convert(in []*data.Person) []*Person {\n\tout := make([]*Person, len(in))\n\n\tfor index, thisRecord := range in {\n\t\tout[index] = &Person{\n\t\t\tID:       thisRecord.ID,\n\t\t\tFullName: thisRecord.FullName,\n\t\t\tPhone:    thisRecord.Phone,\n\t\t}\n\t}\n\n\treturn out\n}\n\n//go:generate mockery -name=myLoader -case underscore -testonly -inpkg -note @generated\ntype myLoader interface {\n\tLoadAll(ctx context.Context) ([]*data.Person, error)\n}\n\n// Person is a copy/sub-set of data.Person so that the relationship does not leak.\n// It also allows us to remove/hide and internal fields\ntype Person struct {\n\tID       int\n\tFullName string\n\tPhone    string\n}\n"
  },
  {
    "path": "ch11/acme/internal/modules/list/list_test.go",
    "content": "package list\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestLister_Do_happyPath(t *testing.T) {\n\t// configure the mock loader\n\tmockResult := []*data.Person{\n\t\t{\n\t\t\tID:       1234,\n\t\t\tFullName: \"Sally\",\n\t\t},\n\t\t{\n\t\t\tID:       5678,\n\t\t\tFullName: \"Jane\",\n\t\t},\n\t}\n\n\tmockLoader := &mockMyLoader{}\n\tmockLoader.On(\"LoadAll\", mock.Anything).Return(mockResult, nil).Once()\n\n\t// call method\n\tlister := &Lister{\n\t\tdata: mockLoader,\n\t}\n\tpersons, err := lister.load()\n\n\t// validate expectations\n\trequire.NoError(t, err)\n\tassert.Equal(t, 2, len(persons))\n\tassert.True(t, mockLoader.AssertExpectations(t))\n}\n\nfunc TestLister_Do_noResults(t *testing.T) {\n\t// configure the mock loader\n\tmockLoader := &mockMyLoader{}\n\tmockLoader.On(\"LoadAll\", mock.Anything).Return(nil, data.ErrNotFound).Once()\n\n\t// call method\n\tlister := &Lister{\n\t\tdata: mockLoader,\n\t}\n\tpersons, err := lister.load()\n\n\t// validate expectations\n\trequire.Equal(t, errPeopleNotFound, err)\n\tassert.Equal(t, 0, len(persons))\n\tassert.True(t, mockLoader.AssertExpectations(t))\n}\n\nfunc TestLister_Do_error(t *testing.T) {\n\t// configure the mock loader\n\tmockLoader := &mockMyLoader{}\n\tmockLoader.On(\"LoadAll\", mock.Anything).Return(nil, errors.New(\"something failed\")).Once()\n\n\t// call method\n\tlister := &Lister{\n\t\tdata: mockLoader,\n\t}\n\tpersons, err := lister.load()\n\n\t// validate expectations\n\trequire.Error(t, err)\n\tassert.Equal(t, 0, len(persons))\n\tassert.True(t, mockLoader.AssertExpectations(t))\n}\n"
  },
  {
    "path": "ch11/acme/internal/modules/list/mock_my_loader_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage list\n\nimport (\n\t\"context\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// mockMyLoader is an autogenerated mock type for the myLoader type\ntype mockMyLoader struct {\n\tmock.Mock\n}\n\n// LoadAll provides a mock function with given fields: ctx\nfunc (_m *mockMyLoader) LoadAll(ctx context.Context) ([]*data.Person, error) {\n\tret := _m.Called(ctx)\n\n\tvar r0 []*data.Person\n\tif rf, ok := ret.Get(0).(func(context.Context) []*data.Person); ok {\n\t\tr0 = rf(ctx)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]*data.Person)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context) error); ok {\n\t\tr1 = rf(ctx)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch11/acme/internal/modules/register/mock_exchanger_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage register\n\nimport (\n\t\"context\"\n\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// MockExchanger is an autogenerated mock type for the Exchanger type\ntype MockExchanger struct {\n\tmock.Mock\n}\n\n// Exchange provides a mock function with given fields: ctx, basePrice, currency\nfunc (_m *MockExchanger) Exchange(ctx context.Context, basePrice float64, currency string) (float64, error) {\n\tret := _m.Called(ctx, basePrice, currency)\n\n\tvar r0 float64\n\tif rf, ok := ret.Get(0).(func(context.Context, float64, string) float64); ok {\n\t\tr0 = rf(ctx, basePrice, currency)\n\t} else {\n\t\tr0 = ret.Get(0).(float64)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, float64, string) error); ok {\n\t\tr1 = rf(ctx, basePrice, currency)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch11/acme/internal/modules/register/mock_my_saver_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage register\n\nimport (\n\t\"context\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// mockMySaver is an autogenerated mock type for the mySaver type\ntype mockMySaver struct {\n\tmock.Mock\n}\n\n// Save provides a mock function with given fields: ctx, in\nfunc (_m *mockMySaver) Save(ctx context.Context, in *data.Person) (int, error) {\n\tret := _m.Called(ctx, in)\n\n\tvar r0 int\n\tif rf, ok := ret.Get(0).(func(context.Context, *data.Person) int); ok {\n\t\tr0 = rf(ctx, in)\n\t} else {\n\t\tr0 = ret.Get(0).(int)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, *data.Person) error); ok {\n\t\tr1 = rf(ctx, in)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch11/acme/internal/modules/register/register.go",
    "content": "package register\n\nimport (\n\t\"context\"\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/modules/data\"\n)\n\nconst (\n\t// default person id (returned on error)\n\tdefaultPersonID = 0\n)\n\nvar (\n\t// validation errors\n\terrNameMissing     = errors.New(\"name is missing\")\n\terrPhoneMissing    = errors.New(\"phone is missing\")\n\terrCurrencyMissing = errors.New(\"currency is missing\")\n\terrInvalidCurrency = errors.New(\"currency is invalid, supported types are AUD, CNY, EUR, GBP, JPY, MYR, SGD, USD\")\n\n\t// a little trick to make checking for supported currencies easier\n\tsupportedCurrencies = map[string]struct{}{\n\t\t\"AUD\": {},\n\t\t\"CNY\": {},\n\t\t\"EUR\": {},\n\t\t\"GBP\": {},\n\t\t\"JPY\": {},\n\t\t\"MYR\": {},\n\t\t\"SGD\": {},\n\t\t\"USD\": {},\n\t}\n)\n\n// NewRegisterer creates and initializes a Registerer\nfunc NewRegisterer(cfg Config, exchanger Exchanger) *Registerer {\n\treturn &Registerer{\n\t\tcfg:       cfg,\n\t\texchanger: exchanger,\n\t}\n}\n\n// Exchanger will convert from one currency to another\n//go:generate mockery -name=Exchanger -case underscore -testonly -inpkg -note @generated\ntype Exchanger interface {\n\t// Exchange will perform the conversion\n\tExchange(ctx context.Context, basePrice float64, currency string) (float64, error)\n}\n\n// Config is the configuration for the Registerer\ntype Config interface {\n\tLogger() logging.Logger\n\tRegistrationBasePrice() float64\n\tDataDSN() string\n}\n\n// Registerer validates the supplied person, calculates the price in the requested currency and saves the result.\n// It will return an error when:\n// -the person object does not include all the fields\n// -the currency is invalid\n// -the exchange rate cannot be loaded\n// -the data layer throws an error.\ntype Registerer struct {\n\tcfg       Config\n\texchanger Exchanger\n\tdata      mySaver\n}\n\n// Do is API for this struct\nfunc (r *Registerer) Do(ctx context.Context, in *Person) (int, error) {\n\t// validate the request\n\terr := r.validateInput(in)\n\tif err != nil {\n\t\tr.logger().Warn(\"input validation failed with err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\t// get price in the requested currency\n\tprice, err := r.getPrice(ctx, in.Currency)\n\tif err != nil {\n\t\treturn defaultPersonID, err\n\t}\n\n\t// save registration\n\tid, err := r.save(ctx, r.convert(in), price)\n\tif err != nil {\n\t\t// no need to log here as we expect the data layer to do so\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn id, nil\n}\n\n// validate input and return error on fail\nfunc (r *Registerer) validateInput(in *Person) error {\n\tif in.FullName == \"\" {\n\t\treturn errNameMissing\n\t}\n\tif in.Phone == \"\" {\n\t\treturn errPhoneMissing\n\t}\n\tif in.Currency == \"\" {\n\t\treturn errCurrencyMissing\n\t}\n\n\tif _, found := supportedCurrencies[in.Currency]; !found {\n\t\treturn errInvalidCurrency\n\t}\n\n\t// happy path\n\treturn nil\n}\n\n// get price in the requested currency\nfunc (r *Registerer) getPrice(ctx context.Context, currency string) (float64, error) {\n\tprice, err := r.exchanger.Exchange(ctx, r.cfg.RegistrationBasePrice(), currency)\n\tif err != nil {\n\t\tr.logger().Warn(\"failed to convert the price. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn price, nil\n}\n\n// save the registration\nfunc (r *Registerer) save(ctx context.Context, in *data.Person, price float64) (int, error) {\n\tperson := &data.Person{\n\t\tFullName: in.FullName,\n\t\tPhone:    in.Phone,\n\t\tCurrency: in.Currency,\n\t\tPrice:    price,\n\t}\n\treturn r.getSaver().Save(ctx, person)\n}\n\nfunc (r *Registerer) getSaver() mySaver {\n\tif r.data == nil {\n\t\tr.data = data.NewDAO(r.cfg)\n\t}\n\n\treturn r.data\n}\n\nfunc (r *Registerer) logger() logging.Logger {\n\treturn r.cfg.Logger()\n}\n\nfunc (r *Registerer) convert(in *Person) *data.Person {\n\treturn &data.Person{\n\t\tID:       in.ID,\n\t\tCurrency: in.Currency,\n\t\tFullName: in.FullName,\n\t\tPhone:    in.Phone,\n\t\tPrice:    in.Price,\n\t}\n}\n\n//go:generate mockery -name=mySaver -case underscore -testonly -inpkg -note @generated\ntype mySaver interface {\n\tSave(ctx context.Context, in *data.Person) (int, error)\n}\n\n// Person is a copy/sub-set of data.Person so that the relationship does not leak.\n// It also allows us to remove/hide and internal fields\ntype Person struct {\n\tID       int\n\tFullName string\n\tPhone    string\n\tCurrency string\n\tPrice    float64\n}\n"
  },
  {
    "path": "ch11/acme/internal/modules/register/register_test.go",
    "content": "package register\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/logging\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestRegisterer_Do_happyPath(t *testing.T) {\n\t// configure the mock saver\n\tmockResult := 888\n\n\tmockSaver := &mockMySaver{}\n\tmockSaver.On(\"Save\", mock.Anything, mock.Anything).Return(mockResult, nil).Once()\n\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\t// inputs\n\tin := &Person{\n\t\tFullName: \"Chang\",\n\t\tPhone:    \"11122233355\",\n\t\tCurrency: \"CNY\",\n\t}\n\n\t// call method\n\tregisterer := &Registerer{\n\t\tcfg:       &testConfig{},\n\t\texchanger: &stubExchanger{},\n\t\tdata:      mockSaver,\n\t}\n\tID, err := registerer.Do(ctx, in)\n\n\t// validate expectations\n\trequire.NoError(t, err)\n\tassert.Equal(t, 888, ID)\n\tassert.True(t, mockSaver.AssertExpectations(t))\n}\n\nfunc TestRegisterer_Do_error(t *testing.T) {\n\t// configure the mock saver\n\tmockSaver := &mockMySaver{}\n\tmockSaver.On(\"Save\", mock.Anything, mock.Anything).Return(0, errors.New(\"something failed\")).Once()\n\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\t// inputs\n\tin := &Person{\n\t\tFullName: \"Chang\",\n\t\tPhone:    \"11122233355\",\n\t\tCurrency: \"CNY\",\n\t}\n\n\t// call method\n\tregisterer := &Registerer{\n\t\tcfg:       &testConfig{},\n\t\texchanger: &stubExchanger{},\n\t\tdata:      mockSaver,\n\t}\n\tID, err := registerer.Do(ctx, in)\n\n\t// validate expectations\n\trequire.Error(t, err)\n\tassert.Equal(t, 0, ID)\n\tassert.True(t, mockSaver.AssertExpectations(t))\n}\n\nfunc TestRegisterer_Do_exchangeError(t *testing.T) {\n\t// configure the mocks\n\tmockSaver := &mockMySaver{}\n\tmockExchanger := &MockExchanger{}\n\tmockExchanger.\n\t\tOn(\"Exchange\", mock.Anything, mock.Anything, mock.Anything).\n\t\tReturn(0.0, errors.New(\"failed to load conversion\")).\n\t\tOnce()\n\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\t// inputs\n\tin := &Person{\n\t\tFullName: \"Chang\",\n\t\tPhone:    \"11122233355\",\n\t\tCurrency: \"CNY\",\n\t}\n\n\t// call method\n\tregisterer := &Registerer{\n\t\tcfg:       &testConfig{},\n\t\texchanger: mockExchanger,\n\t\tdata:      mockSaver,\n\t}\n\tID, err := registerer.Do(ctx, in)\n\n\t// validate expectations\n\trequire.Error(t, err)\n\tassert.Equal(t, 0, ID)\n\tassert.True(t, mockSaver.AssertExpectations(t))\n\tassert.True(t, mockExchanger.AssertExpectations(t))\n}\n\n// Stub implementation of Config\ntype testConfig struct{}\n\n// Logger implement Config\nfunc (t *testConfig) Logger() logging.Logger {\n\treturn &logging.LoggerStdOut{}\n}\n\n// RegistrationBasePrice implement Config\nfunc (t *testConfig) RegistrationBasePrice() float64 {\n\treturn 12.34\n}\n\n// DataDSN implements Config\nfunc (t *testConfig) DataDSN() string {\n\treturn \"\"\n}\n\ntype stubExchanger struct{}\n\n// Exchange implements Exchanger\nfunc (s stubExchanger) Exchange(ctx context.Context, basePrice float64, currency string) (float64, error) {\n\treturn 12.34, nil\n}\n"
  },
  {
    "path": "ch11/acme/internal/rest/get.go",
    "content": "package rest\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/modules/get\"\n\t\"github.com/gorilla/mux\"\n)\n\nconst (\n\t// default person id (returned on error)\n\tdefaultPersonID = 0\n\n\t// key in the mux where the ID is stored\n\tmuxVarID = \"id\"\n)\n\n// GetModel will load a registration\n//go:generate mockery -name=GetModel -case underscore -testonly -inpkg -note @generated\ntype GetModel interface {\n\tDo(ID int) (*get.Person, error)\n}\n\n// GetConfig is the config for the Get Handler\ntype GetConfig interface {\n\tLogger() logging.Logger\n}\n\n// NewGetHandler is the constructor for GetHandler\nfunc NewGetHandler(cfg GetConfig, model GetModel) *GetHandler {\n\treturn &GetHandler{\n\t\tcfg:    cfg,\n\t\tgetter: model,\n\t}\n}\n\n// GetHandler is the HTTP handler for the \"Get Person\" endpoint\n// In this simplified example we are assuming all possible errors are user errors and returning \"bad request\" HTTP 400\n// or \"not found\" HTTP 404\n// There are some programmer errors possible but hopefully these will be caught in testing.\ntype GetHandler struct {\n\tcfg    GetConfig\n\tgetter GetModel\n}\n\n// ServeHTTP implements http.Handler\nfunc (h *GetHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\t// extract person id from request\n\tid, err := h.extractID(request)\n\tif err != nil {\n\t\t// output error\n\t\tresponse.WriteHeader(http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// attempt get\n\tperson, err := h.getter.Do(id)\n\tif err != nil {\n\t\t// not need to log here as we can expect other layers to do so\n\t\tresponse.WriteHeader(http.StatusNotFound)\n\t\treturn\n\t}\n\n\t// happy path\n\terr = h.writeJSON(response, person)\n\tif err != nil {\n\t\t// this error should not happen but if it does there is nothing we can do to recover\n\t\tresponse.WriteHeader(http.StatusInternalServerError)\n\t}\n}\n\n// extract the person ID from the request\nfunc (h *GetHandler) extractID(request *http.Request) (int, error) {\n\t// ID is part of the URL, so we extract it from there\n\tvars := mux.Vars(request)\n\tidAsString, exists := vars[muxVarID]\n\tif !exists {\n\t\t// log and return error\n\t\terr := errors.New(\"[get] person id missing from request\")\n\t\th.cfg.Logger().Warn(err.Error())\n\t\treturn defaultPersonID, err\n\t}\n\n\t// convert ID to int\n\tid, err := strconv.Atoi(idAsString)\n\tif err != nil {\n\t\t// log and return error\n\t\terr = fmt.Errorf(\"[get] failed to convert person id into a number. err: %s\", err)\n\t\th.cfg.Logger().Error(err.Error())\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn id, nil\n}\n\n// output the supplied person as JSON\nfunc (h *GetHandler) writeJSON(writer io.Writer, person *get.Person) error {\n\toutput := &getResponseFormat{\n\t\tID:       person.ID,\n\t\tFullName: person.FullName,\n\t\tPhone:    person.Phone,\n\t\tCurrency: person.Currency,\n\t\tPrice:    person.Price,\n\t}\n\n\t// call to http.ResponseWriter.Write() will cause HTTP OK (200) to be output as well\n\treturn json.NewEncoder(writer).Encode(output)\n}\n\n// the JSON response format\ntype getResponseFormat struct {\n\tID       int     `json:\"id\"`\n\tFullName string  `json:\"name\"`\n\tPhone    string  `json:\"phone\"`\n\tCurrency string  `json:\"currency\"`\n\tPrice    float64 `json:\"price\"`\n}\n"
  },
  {
    "path": "ch11/acme/internal/rest/get_test.go",
    "content": "package rest\n\nimport (\n\t\"errors\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/modules/get\"\n\t\"github.com/gorilla/mux\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestGetHandler_ServeHTTP(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc            string\n\t\tinRequest       func() *http.Request\n\t\tinModelMock     func() *MockGetModel\n\t\texpectedStatus  int\n\t\texpectedPayload string\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/1/\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// set values into request (required by the mux)\n\t\t\t\treturn mux.SetURLVars(req, map[string]string{muxVarID: \"1\"})\n\t\t\t},\n\t\t\tinModelMock: func() *MockGetModel {\n\t\t\t\toutput := &get.Person{\n\t\t\t\t\tID:       1,\n\t\t\t\t\tFullName: \"John\",\n\t\t\t\t\tPhone:    \"0123456789\",\n\t\t\t\t\tCurrency: \"USD\",\n\t\t\t\t\tPrice:    100,\n\t\t\t\t}\n\n\t\t\t\tmockGetModel := &MockGetModel{}\n\t\t\t\tmockGetModel.On(\"Do\", mock.Anything).Return(output, nil).Once()\n\n\t\t\t\treturn mockGetModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusOK,\n\t\t\texpectedPayload: `{\"id\":1,\"name\":\"John\",\"phone\":\"0123456789\",\"currency\":\"USD\",\"price\":100}` + \"\\n\",\n\t\t},\n\t\t{\n\t\t\tdesc: \"bad input (ID is invalid)\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/x/\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// set values into request (required by the mux)\n\t\t\t\treturn mux.SetURLVars(req, map[string]string{muxVarID: \"x\"})\n\t\t\t},\n\t\t\tinModelMock: func() *MockGetModel {\n\t\t\t\t// expect the model not to be called\n\t\t\t\tmockRegisterModel := &MockGetModel{}\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusBadRequest,\n\t\t\texpectedPayload: ``,\n\t\t},\n\t\t{\n\t\t\tdesc: \"bad input (ID is missing)\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person//\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// set values into request (required by the mux)\n\t\t\t\treturn mux.SetURLVars(req, map[string]string{})\n\t\t\t},\n\t\t\tinModelMock: func() *MockGetModel {\n\t\t\t\t// expect the model not to be called\n\t\t\t\tmockRegisterModel := &MockGetModel{}\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusBadRequest,\n\t\t\texpectedPayload: ``,\n\t\t},\n\t\t{\n\t\t\tdesc: \"dependency fail\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/1/\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// set values into request (required by the mux)\n\t\t\t\treturn mux.SetURLVars(req, map[string]string{muxVarID: \"1\"})\n\t\t\t},\n\t\t\tinModelMock: func() *MockGetModel {\n\t\t\t\tmockRegisterModel := &MockGetModel{}\n\t\t\t\tmockRegisterModel.On(\"Do\", mock.Anything).Return(nil, errors.New(\"something failed\")).Once()\n\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusNotFound,\n\t\t\texpectedPayload: ``,\n\t\t},\n\t\t{\n\t\t\tdesc: \"requested registration does not exist\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/1/\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// set values into request (required by the mux)\n\t\t\t\treturn mux.SetURLVars(req, map[string]string{muxVarID: \"1\"})\n\t\t\t},\n\t\t\tinModelMock: func() *MockGetModel {\n\t\t\t\tmockRegisterModel := &MockGetModel{}\n\t\t\t\tmockRegisterModel.On(\"Do\", mock.Anything).Return(nil, errors.New(\"person not found\")).Once()\n\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusNotFound,\n\t\t\texpectedPayload: ``,\n\t\t},\n\t}\n\n\tfor _, s := range scenarios {\n\t\tscenario := s\n\t\tt.Run(scenario.desc, func(t *testing.T) {\n\t\t\t// define model layer mock\n\t\t\tmockGetModel := scenario.inModelMock()\n\n\t\t\t// build handler\n\t\t\thandler := NewGetHandler(&testConfig{}, mockGetModel)\n\n\t\t\t// perform request\n\t\t\tresponse := httptest.NewRecorder()\n\t\t\thandler.ServeHTTP(response, scenario.inRequest())\n\n\t\t\t// validate outputs\n\t\t\trequire.Equal(t, scenario.expectedStatus, response.Code, scenario.desc)\n\n\t\t\tpayload, _ := ioutil.ReadAll(response.Body)\n\t\t\tassert.Equal(t, scenario.expectedPayload, string(payload), scenario.desc)\n\t\t})\n\t}\n}\n\ntype testConfig struct {\n}\n\nfunc (t *testConfig) Logger() logging.Logger {\n\treturn &logging.LoggerStdOut{}\n}\n\nfunc (*testConfig) BindAddress() string {\n\treturn \"0.0.0.0:0\"\n}\n"
  },
  {
    "path": "ch11/acme/internal/rest/list.go",
    "content": "package rest\n\nimport (\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/modules/list\"\n)\n\n// ListModel will load all registrations\n//go:generate mockery -name=ListModel -case underscore -testonly -inpkg -note @generated\ntype ListModel interface {\n\tDo() ([]*list.Person, error)\n}\n\n// NewLister is the constructor for ListHandler\nfunc NewListHandler(model ListModel) *ListHandler {\n\treturn &ListHandler{\n\t\tlister: model,\n\t}\n}\n\n// ListHandler is the HTTP handler for the \"List Do people\" endpoint\n// In this simplified example we are assuming all possible errors are system errors (HTTP 500)\ntype ListHandler struct {\n\tlister ListModel\n}\n\n// ServeHTTP implements http.Handler\nfunc (h *ListHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\t// attempt loadAll\n\tpeople, err := h.lister.Do()\n\tif err != nil {\n\t\t// not need to log here as we can expect other layers to do so\n\t\tresponse.WriteHeader(http.StatusNotFound)\n\t\treturn\n\t}\n\n\t// happy path\n\terr = h.writeJSON(response, people)\n\tif err != nil {\n\t\t// this error should not happen but if it does there is nothing we can do to recover\n\t\tresponse.WriteHeader(http.StatusInternalServerError)\n\t}\n}\n\n// output the result as JSON\nfunc (h *ListHandler) writeJSON(writer io.Writer, people []*list.Person) error {\n\toutput := &listResponseFormat{\n\t\tPeople: make([]*listResponseItemFormat, len(people)),\n\t}\n\n\tfor index, record := range people {\n\t\toutput.People[index] = &listResponseItemFormat{\n\t\t\tID:       record.ID,\n\t\t\tFullName: record.FullName,\n\t\t\tPhone:    record.Phone,\n\t\t}\n\t}\n\n\t// call to http.ResponseWriter.Write() will cause HTTP OK (200) to be output as well\n\treturn json.NewEncoder(writer).Encode(output)\n}\n\ntype listResponseFormat struct {\n\tPeople []*listResponseItemFormat `json:\"people\"`\n}\n\ntype listResponseItemFormat struct {\n\tID       int    `json:\"id\"`\n\tFullName string `json:\"name\"`\n\tPhone    string `json:\"phone\"`\n}\n"
  },
  {
    "path": "ch11/acme/internal/rest/list_test.go",
    "content": "package rest\n\nimport (\n\t\"errors\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/modules/list\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestListHandler_ServeHTTP(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc            string\n\t\tinRequest       func() *http.Request\n\t\tinModelMock     func() *MockListModel\n\t\texpectedStatus  int\n\t\texpectedPayload string\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/list\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn req\n\t\t\t},\n\t\t\tinModelMock: func() *MockListModel {\n\t\t\t\toutput := []*list.Person{\n\t\t\t\t\t{\n\t\t\t\t\t\tID:       1,\n\t\t\t\t\t\tFullName: \"John\",\n\t\t\t\t\t\tPhone:    \"0123456789\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tID:       2,\n\t\t\t\t\t\tFullName: \"Paul\",\n\t\t\t\t\t\tPhone:    \"0123456781\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tID:       3,\n\t\t\t\t\t\tFullName: \"George\",\n\t\t\t\t\t\tPhone:    \"0123456782\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tID:       1,\n\t\t\t\t\t\tFullName: \"Ringo\",\n\t\t\t\t\t\tPhone:    \"0123456783\",\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\tmockListModel := &MockListModel{}\n\t\t\t\tmockListModel.On(\"Do\", mock.Anything).Return(output, nil).Once()\n\n\t\t\t\treturn mockListModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusOK,\n\t\t\texpectedPayload: `{\"people\":[{\"id\":1,\"name\":\"John\",\"phone\":\"0123456789\"},{\"id\":2,\"name\":\"Paul\",\"phone\":\"0123456781\"},{\"id\":3,\"name\":\"George\",\"phone\":\"0123456782\"},{\"id\":1,\"name\":\"Ringo\",\"phone\":\"0123456783\"}]}` + \"\\n\",\n\t\t},\n\t\t{\n\t\t\tdesc: \"dependency failure\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/list\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn req\n\t\t\t},\n\t\t\tinModelMock: func() *MockListModel {\n\t\t\t\tmockListModel := &MockListModel{}\n\t\t\t\tmockListModel.On(\"Do\", mock.Anything).Return(nil, errors.New(\"something failed\")).Once()\n\n\t\t\t\treturn mockListModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusNotFound,\n\t\t\texpectedPayload: ``,\n\t\t},\n\t\t{\n\t\t\tdesc: \"no data\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/list\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn req\n\t\t\t},\n\t\t\tinModelMock: func() *MockListModel {\n\t\t\t\t// no data\n\t\t\t\tvar output []*list.Person\n\n\t\t\t\tmockListModel := &MockListModel{}\n\t\t\t\tmockListModel.On(\"Do\", mock.Anything).Return(output, nil).Once()\n\n\t\t\t\treturn mockListModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusOK,\n\t\t\texpectedPayload: `{\"people\":[]}` + \"\\n\",\n\t\t},\n\t}\n\n\tfor _, s := range scenarios {\n\t\tscenario := s\n\t\tt.Run(scenario.desc, func(t *testing.T) {\n\t\t\t// define model layer mock\n\t\t\tmockListModel := scenario.inModelMock()\n\n\t\t\t// build handler\n\t\t\thandler := NewListHandler(mockListModel)\n\n\t\t\t// perform request\n\t\t\tresponse := httptest.NewRecorder()\n\t\t\thandler.ServeHTTP(response, scenario.inRequest())\n\n\t\t\t// validate outputs\n\t\t\trequire.Equal(t, scenario.expectedStatus, response.Code, scenario.desc)\n\n\t\t\tpayload, _ := ioutil.ReadAll(response.Body)\n\t\t\tassert.Equal(t, scenario.expectedPayload, string(payload), scenario.desc)\n\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "ch11/acme/internal/rest/mock_get_model_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage rest\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/modules/get\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// MockGetModel is an autogenerated mock type for the GetModel type\ntype MockGetModel struct {\n\tmock.Mock\n}\n\n// Do provides a mock function with given fields: ID\nfunc (_m *MockGetModel) Do(ID int) (*get.Person, error) {\n\tret := _m.Called(ID)\n\n\tvar r0 *get.Person\n\tif rf, ok := ret.Get(0).(func(int) *get.Person); ok {\n\t\tr0 = rf(ID)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*get.Person)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(int) error); ok {\n\t\tr1 = rf(ID)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch11/acme/internal/rest/mock_list_model_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage rest\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/modules/list\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// MockListModel is an autogenerated mock type for the ListModel type\ntype MockListModel struct {\n\tmock.Mock\n}\n\n// Do provides a mock function with given fields:\nfunc (_m *MockListModel) Do() ([]*list.Person, error) {\n\tret := _m.Called()\n\n\tvar r0 []*list.Person\n\tif rf, ok := ret.Get(0).(func() []*list.Person); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]*list.Person)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func() error); ok {\n\t\tr1 = rf()\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch11/acme/internal/rest/mock_register_model_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage rest\n\nimport (\n\t\"context\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/modules/register\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// MockRegisterModel is an autogenerated mock type for the RegisterModel type\ntype MockRegisterModel struct {\n\tmock.Mock\n}\n\n// Do provides a mock function with given fields: ctx, in\nfunc (_m *MockRegisterModel) Do(ctx context.Context, in *register.Person) (int, error) {\n\tret := _m.Called(ctx, in)\n\n\tvar r0 int\n\tif rf, ok := ret.Get(0).(func(context.Context, *register.Person) int); ok {\n\t\tr0 = rf(ctx, in)\n\t} else {\n\t\tr0 = ret.Get(0).(int)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, *register.Person) error); ok {\n\t\tr1 = rf(ctx, in)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch11/acme/internal/rest/not_found.go",
    "content": "package rest\n\nimport (\n\t\"net/http\"\n)\n\nfunc notFoundHandler(response http.ResponseWriter, _ *http.Request) {\n\tresponse.WriteHeader(http.StatusNotFound)\n\t_, _ = response.Write([]byte(`Not found`))\n}\n"
  },
  {
    "path": "ch11/acme/internal/rest/not_found_test.go",
    "content": "package rest\n\nimport (\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestNotFoundHandler_ServeHTTP(t *testing.T) {\n\t// build inputs\n\tresponse := httptest.NewRecorder()\n\trequest := &http.Request{}\n\n\t// call handler\n\tnotFoundHandler(response, request)\n\n\t// validate outputs\n\trequire.Equal(t, http.StatusNotFound, response.Code)\n}\n"
  },
  {
    "path": "ch11/acme/internal/rest/register.go",
    "content": "package rest\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/modules/register\"\n)\n\n// RegisterModel will validate and save a registration\n//go:generate mockery -name=RegisterModel -case underscore -testonly -inpkg -note @generated\ntype RegisterModel interface {\n\tDo(ctx context.Context, in *register.Person) (int, error)\n}\n\n// NewRegisterHandler is the constructor for RegisterHandler\nfunc NewRegisterHandler(model RegisterModel) *RegisterHandler {\n\treturn &RegisterHandler{\n\t\tregisterer: model,\n\t}\n}\n\n// RegisterHandler is the HTTP handler for the \"Register\" endpoint\n// In this simplified example we are assuming all possible errors are user errors and returning \"bad request\" HTTP 400.\n// There are some programmer errors possible but hopefully these will be caught in testing.\ntype RegisterHandler struct {\n\tregisterer RegisterModel\n}\n\n// ServeHTTP implements http.Handler\nfunc (h *RegisterHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\t// set latency budget for this API\n\tsubCtx, cancel := context.WithTimeout(request.Context(), 1500*time.Millisecond)\n\tdefer cancel()\n\n\t// extract payload from request\n\trequestPayload, err := h.extractPayload(request)\n\tif err != nil {\n\t\t// output error\n\t\tresponse.WriteHeader(http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// call the business logic using the request data and context\n\tid, err := h.register(subCtx, requestPayload)\n\tif err != nil {\n\t\t// not need to log here as we can expect other layers to do so\n\t\tresponse.WriteHeader(http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// happy path\n\tresponse.Header().Add(\"Location\", fmt.Sprintf(\"/person/%d/\", id))\n\tresponse.WriteHeader(http.StatusCreated)\n}\n\n// extract payload from request\nfunc (h *RegisterHandler) extractPayload(request *http.Request) (*registerRequest, error) {\n\trequestPayload := &registerRequest{}\n\n\tdecoder := json.NewDecoder(request.Body)\n\terr := decoder.Decode(requestPayload)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn requestPayload, nil\n}\n\n// call the logic layer\nfunc (h *RegisterHandler) register(ctx context.Context, requestPayload *registerRequest) (int, error) {\n\tperson := &register.Person{\n\t\tFullName: requestPayload.FullName,\n\t\tPhone:    requestPayload.Phone,\n\t\tCurrency: requestPayload.Currency,\n\t}\n\n\treturn h.registerer.Do(ctx, person)\n}\n\n// register endpoint request format\ntype registerRequest struct {\n\t// FullName of the person\n\tFullName string `json:\"fullName\"`\n\t// Phone of the person\n\tPhone string `json:\"phone\"`\n\t// Currency the wish to register in\n\tCurrency string `json:\"currency\"`\n}\n"
  },
  {
    "path": "ch11/acme/internal/rest/register_test.go",
    "content": "package rest\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestRegisterHandler_ServeHTTP(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc           string\n\t\tinRequest      func() *http.Request\n\t\tinModelMock    func() *MockRegisterModel\n\t\texpectedStatus int\n\t\texpectedHeader string\n\t}{\n\t\t{\n\t\t\tdesc: \"Happy Path\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\tvalidRequest := buildValidRegisterRequest()\n\t\t\t\trequest, err := http.NewRequest(\"POST\", \"/person/register\", validRequest)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn request\n\t\t\t},\n\t\t\tinModelMock: func() *MockRegisterModel {\n\t\t\t\t// valid downstream configuration\n\t\t\t\tresultID := 1234\n\t\t\t\tvar resultErr error\n\n\t\t\t\tmockRegisterModel := &MockRegisterModel{}\n\t\t\t\tmockRegisterModel.On(\"Do\", mock.Anything, mock.Anything).Return(resultID, resultErr).Once()\n\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus: http.StatusCreated,\n\t\t\texpectedHeader: \"/person/1234/\",\n\t\t},\n\t\t{\n\t\t\tdesc: \"Bad Input / User Error\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\tinvalidRequest := bytes.NewBufferString(`this is not valid JSON`)\n\t\t\t\trequest, err := http.NewRequest(\"POST\", \"/person/register\", invalidRequest)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn request\n\t\t\t},\n\t\t\tinModelMock: func() *MockRegisterModel {\n\t\t\t\t// Dependency should not be called\n\t\t\t\tmockRegisterModel := &MockRegisterModel{}\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus: http.StatusBadRequest,\n\t\t\texpectedHeader: \"\",\n\t\t},\n\t\t{\n\t\t\tdesc: \"Dependency Failure\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\tvalidRequest := buildValidRegisterRequest()\n\t\t\t\trequest, err := http.NewRequest(\"POST\", \"/person/register\", validRequest)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn request\n\t\t\t},\n\t\t\tinModelMock: func() *MockRegisterModel {\n\t\t\t\t// call to the dependency failed\n\t\t\t\tresultErr := errors.New(\"something failed\")\n\n\t\t\t\tmockRegisterModel := &MockRegisterModel{}\n\t\t\t\tmockRegisterModel.On(\"Do\", mock.Anything, mock.Anything).Return(0, resultErr).Once()\n\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus: http.StatusBadRequest,\n\t\t\texpectedHeader: \"\",\n\t\t},\n\t}\n\n\tfor _, s := range scenarios {\n\t\tscenario := s\n\t\tt.Run(scenario.desc, func(t *testing.T) {\n\t\t\t// define model layer mock\n\t\t\tmockRegisterModel := scenario.inModelMock()\n\n\t\t\t// build handler\n\t\t\thandler := NewRegisterHandler(mockRegisterModel)\n\n\t\t\t// perform request\n\t\t\tresponse := httptest.NewRecorder()\n\t\t\thandler.ServeHTTP(response, scenario.inRequest())\n\n\t\t\t// validate outputs\n\t\t\trequire.Equal(t, scenario.expectedStatus, response.Code)\n\n\t\t\t// call should output the location to the new person\n\t\t\tresultHeader := response.Header().Get(\"Location\")\n\t\t\tassert.Equal(t, scenario.expectedHeader, resultHeader)\n\n\t\t\t// validate the mock was used as we expected\n\t\t\tassert.True(t, mockRegisterModel.AssertExpectations(t))\n\t\t})\n\t}\n}\n\nfunc buildValidRegisterRequest() io.Reader {\n\trequestData := &registerRequest{\n\t\tFullName: \"Joan Smith\",\n\t\tCurrency: \"AUD\",\n\t\tPhone:    \"01234567890\",\n\t}\n\n\tdata, _ := json.Marshal(requestData)\n\treturn bytes.NewBuffer(data)\n}\n"
  },
  {
    "path": "ch11/acme/internal/rest/server.go",
    "content": "package rest\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/logging\"\n\t\"github.com/gorilla/mux\"\n)\n\n// Config is the config for the REST package\ntype Config interface {\n\tLogger() logging.Logger\n\tBindAddress() string\n}\n\n// New will create and initialize the server\nfunc New(cfg Config,\n\tgetModel GetModel,\n\tlistModel ListModel,\n\tregisterModel RegisterModel) *Server {\n\n\treturn &Server{\n\t\taddress:         cfg.BindAddress(),\n\t\thandlerGet:      NewGetHandler(cfg, getModel),\n\t\thandlerList:     NewListHandler(listModel),\n\t\thandlerNotFound: notFoundHandler,\n\t\thandlerRegister: NewRegisterHandler(registerModel),\n\t}\n}\n\n// Server is the HTTP REST server\ntype Server struct {\n\taddress string\n\tserver  *http.Server\n\n\thandlerGet      http.Handler\n\thandlerList     http.Handler\n\thandlerNotFound http.HandlerFunc\n\thandlerRegister http.Handler\n}\n\n// Listen will start a HTTP rest for this service\nfunc (s *Server) Listen(stop <-chan struct{}) {\n\trouter := s.buildRouter()\n\n\t// create the HTTP server\n\ts.server = &http.Server{\n\t\tHandler: router,\n\t\tAddr:    s.address,\n\t}\n\n\t// listen for shutdown\n\tgo func() {\n\t\t// wait for shutdown signal\n\t\t<-stop\n\n\t\t_ = s.server.Close()\n\t}()\n\n\t// start the HTTP server\n\t_ = s.server.ListenAndServe()\n}\n\n// configure the endpoints to handlers\nfunc (s *Server) buildRouter() http.Handler {\n\trouter := mux.NewRouter()\n\n\t// map URL endpoints to HTTP handlers\n\trouter.Handle(\"/person/{id}/\", s.handlerGet).Methods(\"GET\")\n\trouter.Handle(\"/person/list\", s.handlerList).Methods(\"GET\")\n\trouter.Handle(\"/person/register\", s.handlerRegister).Methods(\"POST\")\n\n\t// convert a \"catch all\" not found handler\n\trouter.NotFoundHandler = s.handlerNotFound\n\n\treturn router\n}\n"
  },
  {
    "path": "ch11/acme/main.go",
    "content": "package main\n\nimport (\n\t\"context\"\n\t\"os\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/config\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/modules/exchange\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/modules/get\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/modules/list\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/modules/register\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/rest\"\n\t\"github.com/google/wire\"\n)\n\nfunc main() {\n\t// bind stop channel to context\n\tctx := context.Background()\n\n\t// start REST server\n\tserver, err := initializeServer()\n\tif err != nil {\n\t\tos.Exit(-1)\n\t}\n\n\tserver.Listen(ctx.Done())\n}\n\n// List of wire enabled objects\nvar wireSetWithoutConfig = wire.NewSet(\n\t// *exchange.Converter\n\texchange.NewConverter,\n\n\t// *get.Getter\n\tget.NewGetter,\n\n\t// *list.Lister\n\tlist.NewLister,\n\n\t// *register.Registerer\n\twire.Bind(new(register.Exchanger), &exchange.Converter{}),\n\tregister.NewRegisterer,\n\n\t// *rest.Server\n\twire.Bind(new(rest.GetModel), &get.Getter{}),\n\twire.Bind(new(rest.ListModel), &list.Lister{}),\n\twire.Bind(new(rest.RegisterModel), &register.Registerer{}),\n\trest.New,\n)\n\nvar wireSet = wire.NewSet(\n\twireSetWithoutConfig,\n\n\t// *config.Config\n\tconfig.Load,\n\n\t// *exchange.Converter\n\twire.Bind(new(exchange.Config), &config.Config{}),\n\n\t// *get.Getter\n\twire.Bind(new(get.Config), &config.Config{}),\n\n\t// *list.Lister\n\twire.Bind(new(list.Config), &config.Config{}),\n\n\t// *register.Registerer\n\twire.Bind(new(register.Config), &config.Config{}),\n\n\t// *rest.Server\n\twire.Bind(new(rest.Config), &config.Config{}),\n)\n"
  },
  {
    "path": "ch11/acme/main_test.go",
    "content": "package main\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/config\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestRegister(t *testing.T) {\n\t// start a context with a max execution time\n\tctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n\tdefer cancel()\n\n\t// start test server\n\tserverAddress := startTestServer(t, ctx)\n\n\t// build and send request\n\tpayload := bytes.NewBufferString(`\n{\n\t\"fullName\": \"Bob\",\n\t\"phone\": \"0123456789\",\n\t\"currency\": \"AUD\"\n}\n`)\n\n\treq, err := http.NewRequest(\"POST\", serverAddress+\"/person/register\", payload)\n\trequire.NoError(t, err)\n\n\tresp, err := http.DefaultClient.Do(req)\n\trequire.NoError(t, err)\n\n\t// validate expectations\n\tassert.Equal(t, http.StatusCreated, resp.StatusCode)\n\tassert.NotEmpty(t, resp.Header.Get(\"Location\"))\n}\n\nfunc TestGet(t *testing.T) {\n\t// start a context with a max execution time\n\tctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n\tdefer cancel()\n\n\t// start test server\n\tserverAddress := startTestServer(t, ctx)\n\n\t// build and send request\n\treq, err := http.NewRequest(\"GET\", serverAddress+\"/person/1/\", nil)\n\trequire.NoError(t, err)\n\n\tresp, err := http.DefaultClient.Do(req)\n\trequire.NoError(t, err)\n\n\t// validate expectations\n\tassert.Equal(t, http.StatusOK, resp.StatusCode)\n}\n\nfunc TestList(t *testing.T) {\n\t// start a context with a max execution time\n\tctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n\tdefer cancel()\n\n\t// start test server\n\tserverAddress := startTestServer(t, ctx)\n\n\t// build and send request\n\treq, err := http.NewRequest(\"GET\", serverAddress+\"/person/list\", nil)\n\trequire.NoError(t, err)\n\n\tresp, err := http.DefaultClient.Do(req)\n\trequire.NoError(t, err)\n\n\t// validate expectations\n\tassert.Equal(t, http.StatusOK, resp.StatusCode)\n}\n\nfunc startTestServer(t *testing.T, ctx context.Context) string {\n\t// load the standard config (from the ENV)\n\tcfg, err := config.Load()\n\trequire.NoError(t, err)\n\n\t// get a free port (so tests can run concurrently)\n\tport, err := getFreePort()\n\trequire.NoError(t, err)\n\n\t// override config port with free one\n\tcfg.Address = net.JoinHostPort(\"0.0.0.0\", port)\n\n\t// start the test server on a random port\n\tgo func() {\n\t\t// start REST server\n\t\tserver := initializeServerCustomConfig(cfg, cfg, cfg, cfg, cfg)\n\t\tserver.Listen(ctx.Done())\n\t}()\n\n\t// give the server a chance to start\n\t<-time.After(100 * time.Millisecond)\n\n\t// return the address of the test server\n\treturn \"http://\" + cfg.Address\n}\n\nfunc getFreePort() (string, error) {\n\tfor attempt := 0; attempt <= 10; attempt++ {\n\t\taddr := net.JoinHostPort(\"\", \"0\")\n\t\tlistener, err := net.Listen(\"tcp\", addr)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tport, err := getPort(listener.Addr())\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\t// close/free the port\n\t\ttcpListener := listener.(*net.TCPListener)\n\t\tcErr := tcpListener.Close()\n\t\tif cErr == nil {\n\t\t\tfile, fErr := tcpListener.File()\n\t\t\tif fErr == nil {\n\t\t\t\t// ignore any errors cleaning up the file\n\t\t\t\t_ = file.Close()\n\t\t\t}\n\t\t\treturn port, nil\n\t\t}\n\t}\n\n\treturn \"\", errors.New(\"no free ports\")\n}\n\nfunc getPort(addr fmt.Stringer) (string, error) {\n\tactualAddress := addr.String()\n\t_, port, err := net.SplitHostPort(actualAddress)\n\treturn port, err\n}\n"
  },
  {
    "path": "ch11/acme/wire.go",
    "content": "//+build wireinject\n\npackage main\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/modules/exchange\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/modules/get\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/modules/list\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/modules/register\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/rest\"\n\t\"github.com/google/wire\"\n)\n\n// The build tag makes sure the stub is not built in the final build.\n\nfunc initializeServer() (*rest.Server, error) {\n\twire.Build(wireSet)\n\treturn nil, nil\n}\n\nfunc initializeServerCustomConfig(_ exchange.Config, _ get.Config, _ list.Config, _ register.Config, _ rest.Config) *rest.Server {\n\twire.Build(wireSetWithoutConfig)\n\treturn nil\n}\n"
  },
  {
    "path": "ch11/acme/wire_gen.go",
    "content": "// Code generated by Wire. DO NOT EDIT.\n\n//go:generate wire\n//+build !wireinject\n\npackage main\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/config\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/modules/exchange\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/modules/get\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/modules/list\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/modules/register\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch11/acme/internal/rest\"\n)\n\n// Injectors from wire.go:\n\nfunc initializeServer() (*rest.Server, error) {\n\tconfigConfig, err := config.Load()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tgetter := get.NewGetter(configConfig)\n\tlister := list.NewLister(configConfig)\n\tconverter := exchange.NewConverter(configConfig)\n\tregisterer := register.NewRegisterer(configConfig, converter)\n\tserver := rest.New(configConfig, getter, lister, registerer)\n\treturn server, nil\n}\n\nfunc initializeServerCustomConfig(exchangeConfig exchange.Config, getConfig get.Config, listConfig list.Config, registerConfig register.Config, restConfig rest.Config) *rest.Server {\n\tgetter := get.NewGetter(getConfig)\n\tlister := list.NewLister(listConfig)\n\tconverter := exchange.NewConverter(exchangeConfig)\n\tregisterer := register.NewRegisterer(registerConfig, converter)\n\tserver := rest.New(restConfig, getter, lister, registerer)\n\treturn server\n}\n"
  },
  {
    "path": "ch12/01_improvements/01_test_logging_test.go",
    "content": "package improvements\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestLogging(t *testing.T) {\n\t// build log recorder\n\trecorder := &LogRecorder{}\n\n\t// Call struct that uses a logger\n\tcalculator := &Calculator{\n\t\tlogger: recorder,\n\t}\n\tresult := calculator.divide(10, 0)\n\n\t// validate expectations, including that the logger was called\n\tassert.Equal(t, 0, result)\n\trequire.Equal(t, 1, len(recorder.Logs))\n\tassert.Equal(t, \"cannot divide by 0\", recorder.Logs[0])\n}\n\ntype Calculator struct {\n\tlogger Logger\n}\n\nfunc (c *Calculator) divide(dividend int, divisor int) int {\n\tif divisor == 0 {\n\t\tc.logger.Error(\"cannot divide by 0\")\n\t\treturn 0\n\t}\n\n\treturn dividend / divisor\n}\n\n// Logger is our standard interface\ntype Logger interface {\n\tError(message string, args ...interface{})\n}\n\n// LogRecorder implements Logger interface\ntype LogRecorder struct {\n\tLogs []string\n}\n\nfunc (l *LogRecorder) Error(message string, args ...interface{}) {\n\t// build log message\n\tlogMessage := fmt.Sprintf(message, args...)\n\n\t// record log message\n\tl.Logs = append(l.Logs, logMessage)\n}\n"
  },
  {
    "path": "ch12/03_testing/01_mock_get_model.go",
    "content": "package testing\n\nimport (\n\t\"github.com/stretchr/testify/mock\"\n)\n\ntype MockGetModel struct {\n\tmock.Mock\n}\n\nfunc (_m *MockGetModel) Do(ID int) (*Person, error) {\n\toutputs := _m.Called(ID)\n\n\tif outputs.Get(0) != nil {\n\t\treturn outputs.Get(0).(*Person), outputs.Error(1)\n\t}\n\n\treturn nil, outputs.Error(1)\n}\n\ntype Person struct {\n\tID       int\n\tFullName string\n\tPhone    string\n\tCurrency string\n\tPrice    float64\n}\n"
  },
  {
    "path": "ch12/03_testing/02_coverage_ch04.txt",
    "content": "----------------------------------------------------------------------------\n|      Branch     |       Dir       |                                      |\n|   Cov% |  Stmts |   Cov% |  Stmts | Package                              |\n----------------------------------------------------------------------------\n|  52.94 |    238 |   0.00 |      3 | acme/                                |\n|  73.33 |     15 |  73.33 |     15 | acme/internal/config/                |\n|   0.00 |      4 |   0.00 |      4 | acme/internal/logging/               |\n|  63.33 |     60 |  63.33 |     60 | acme/internal/modules/data/          |\n|   0.00 |     38 |   0.00 |     38 | acme/internal/modules/exchange/      |\n|  50.00 |      6 |  50.00 |      6 | acme/internal/modules/get/           |\n|  25.00 |     12 |  25.00 |     12 | acme/internal/modules/list/          |\n|  64.29 |     28 |  64.29 |     28 | acme/internal/modules/register/      |\n|  73.61 |     72 |  73.61 |     72 | acme/internal/rest/                  |\n----------------------------------------------------------------------------"
  },
  {
    "path": "ch12/03_testing/03_coverage_ch11.txt",
    "content": "----------------------------------------------------------------------------\n|      Branch     |       Dir       |                                      |\n|   Cov% |  Stmts |   Cov% |  Stmts | Package                              |\n----------------------------------------------------------------------------\n|  63.11 |    309 |  30.00 |     20 | acme/                                |\n|  28.57 |     28 |  28.57 |     28 | acme/internal/config/                |\n|   0.00 |      4 |   0.00 |      4 | acme/internal/logging/               |\n|  74.65 |     71 |  74.65 |     71 | acme/internal/modules/data/          |\n|  61.70 |     47 |  61.70 |     47 | acme/internal/modules/exchange/      |\n|  81.82 |     11 |  81.82 |     11 | acme/internal/modules/get/           |\n|  38.10 |     21 |  38.10 |     21 | acme/internal/modules/list/          |\n|  75.76 |     33 |  75.76 |     33 | acme/internal/modules/register/      |\n|  77.03 |     74 |  77.03 |     74 | acme/internal/rest/                  |\n----------------------------------------------------------------------------\n"
  },
  {
    "path": "ch12/03_testing/04_coverage_config.htm",
    "content": "<!DOCTYPE html>\n<!-- saved from url=(0098)file:///private/var/folders/j1/jctgvxk55ngftwfqp1wzrt440000gs/T/cover172097763/coverage.html#file0 -->\n<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n\t\t\n\t\t<style>\n\t\t\tbody {\n\t\t\t\tbackground: black;\n\t\t\t\tcolor: rgb(80, 80, 80);\n\t\t\t}\n\t\t\tbody, pre, #legend span {\n\t\t\t\tfont-family: Menlo, monospace;\n\t\t\t\tfont-weight: bold;\n\t\t\t}\n\t\t\t#topbar {\n\t\t\t\tbackground: black;\n\t\t\t\tposition: fixed;\n\t\t\t\ttop: 0; left: 0; right: 0;\n\t\t\t\theight: 42px;\n\t\t\t\tborder-bottom: 1px solid rgb(80, 80, 80);\n\t\t\t}\n\t\t\t#content {\n\t\t\t\tmargin-top: 50px;\n\t\t\t}\n\t\t\t#nav, #legend {\n\t\t\t\tfloat: left;\n\t\t\t\tmargin-left: 10px;\n\t\t\t}\n\t\t\t#legend {\n\t\t\t\tmargin-top: 12px;\n\t\t\t}\n\t\t\t#nav {\n\t\t\t\tmargin-top: 10px;\n\t\t\t}\n\t\t\t#legend span {\n\t\t\t\tmargin: 0 5px;\n\t\t\t}\n\t\t\t.cov0 { color: rgb(192, 0, 0) }\n.cov1 { color: rgb(128, 128, 128) }\n.cov2 { color: rgb(116, 140, 131) }\n.cov3 { color: rgb(104, 152, 134) }\n.cov4 { color: rgb(92, 164, 137) }\n.cov5 { color: rgb(80, 176, 140) }\n.cov6 { color: rgb(68, 188, 143) }\n.cov7 { color: rgb(56, 200, 146) }\n.cov8 { color: rgb(44, 212, 149) }\n.cov9 { color: rgb(32, 224, 152) }\n.cov10 { color: rgb(20, 236, 155) }\n\n\t\t</style>\n\t</head>\n\t<body>\n\t\t<div id=\"topbar\">\n\t\t\t<div id=\"nav\">\n\t\t\t\t<select id=\"files\">\n\t\t\t\t\n\t\t\t\t<option value=\"file0\">github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/config/config.go (28.6%)</option>\n\t\t\t\t\n\t\t\t\t</select>\n\t\t\t</div>\n\t\t\t<div id=\"legend\">\n\t\t\t\t<span>not tracked</span>\n\t\t\t\n\t\t\t\t<span class=\"cov0\">not covered</span>\n\t\t\t\t<span class=\"cov8\">covered</span>\n\t\t\t\n\t\t\t</div>\n\t\t</div>\n\t\t<div id=\"content\">\n\t\t\n\t\t<pre class=\"file\" id=\"file0\" style=\"display: block;\">package config\n\nimport (\n        \"encoding/json\"\n        \"fmt\"\n        \"io/ioutil\"\n        \"os\"\n\n        \"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/logging\"\n)\n\n// DefaultEnvVar is the default environment variable the points to the config file\nconst DefaultEnvVar = \"ACME_CONFIG\"\n\n// Config defines the JSON format for the config file\ntype Config struct {\n        // DSN is the data source name (format: https://github.com/go-sql-driver/mysql/#dsn-data-source-name)\n        DSN string\n\n        // Address is the IP address and port to bind this rest to\n        Address string\n\n        // BasePrice is the price of registration\n        BasePrice float64\n\n        // ExchangeRateBaseURL is the server and protocol part of the URL from which to load the exchange rate\n        ExchangeRateBaseURL string\n\n        // ExchangeRateAPIKey is the API for the exchange rate API\n        ExchangeRateAPIKey string\n\n        // environmental dependencies\n        logger logging.Logger\n}\n\n// Logger returns a reference to the singleton logger\nfunc (c *Config) Logger() logging.Logger <span class=\"cov0\" title=\"0\">{\n        if c.logger == nil </span><span class=\"cov0\" title=\"0\">{\n                c.logger = &amp;logging.LoggerStdOut{}\n        }</span>\n\n        <span class=\"cov0\" title=\"0\">return c.logger</span>\n}\n\n// RegistrationBasePrice returns the base price for registrations\nfunc (c *Config) RegistrationBasePrice() float64 <span class=\"cov0\" title=\"0\">{\n        return c.BasePrice\n}</span>\n\n// DataDSN returns the DSN\nfunc (c *Config) DataDSN() string <span class=\"cov0\" title=\"0\">{\n        return c.DSN\n}</span>\n\n// ExchangeBaseURL returns the Base URL from which we can load exchange rates\nfunc (c *Config) ExchangeBaseURL() string <span class=\"cov0\" title=\"0\">{\n        return c.ExchangeRateBaseURL\n}</span>\n\n// ExchangeAPIKey returns the DSN\nfunc (c *Config) ExchangeAPIKey() string <span class=\"cov0\" title=\"0\">{\n        return c.ExchangeRateAPIKey\n}</span>\n\n// BindAddress returns the host and port this service should bind to\nfunc (c *Config) BindAddress() string <span class=\"cov0\" title=\"0\">{\n        return c.Address\n}</span>\n\n// Load returns the config loaded from environment\nfunc Load() (*Config, error) <span class=\"cov0\" title=\"0\">{\n        filename, found := os.LookupEnv(DefaultEnvVar)\n        if !found </span><span class=\"cov0\" title=\"0\">{\n                err := fmt.Errorf(\"failed to locate file specified by %s\", DefaultEnvVar)\n                fmt.Fprintf(os.Stderr, err.Error())\n                return nil, err\n        }</span>\n\n        <span class=\"cov0\" title=\"0\">cfg, err := load(filename)\n        if err != nil </span><span class=\"cov0\" title=\"0\">{\n                fmt.Fprintf(os.Stderr, \"failed to load config with err %s\", err)\n                return nil, err\n        }</span>\n\n        <span class=\"cov0\" title=\"0\">return cfg, nil</span>\n}\n\nfunc load(filename string) (*Config, error) <span class=\"cov8\" title=\"1\">{\n        out := &amp;Config{}\n        bytes, err := ioutil.ReadFile(filename)\n        if err != nil </span><span class=\"cov8\" title=\"1\">{\n                fmt.Fprintf(os.Stderr, \"failed to read config file. err: %s\", err)\n                return nil, err\n        }</span>\n\n        <span class=\"cov8\" title=\"1\">err = json.Unmarshal(bytes, out)\n        if err != nil </span><span class=\"cov0\" title=\"0\">{\n                fmt.Fprintf(os.Stderr, \"failed to parse config file. err : %s\", err)\n                return nil, err\n        }</span>\n\n        <span class=\"cov8\" title=\"1\">return out, nil</span>\n}\n</pre>\n\t\t\n\t\t</div>\n\t\n\t<script>\n\t(function() {\n\t\tvar files = document.getElementById('files');\n\t\tvar visible;\n\t\tfiles.addEventListener('change', onChange, false);\n\t\tfunction select(part) {\n\t\t\tif (visible)\n\t\t\t\tvisible.style.display = 'none';\n\t\t\tvisible = document.getElementById(part);\n\t\t\tif (!visible)\n\t\t\t\treturn;\n\t\t\tfiles.value = part;\n\t\t\tvisible.style.display = 'block';\n\t\t\tlocation.hash = part;\n\t\t}\n\t\tfunction onChange() {\n\t\t\tselect(files.value);\n\t\t\twindow.scrollTo(0, 0);\n\t\t}\n\t\tif (location.hash != \"\") {\n\t\t\tselect(location.hash.substr(1));\n\t\t}\n\t\tif (!visible) {\n\t\t\tselect(\"file0\");\n\t\t}\n\t})();\n\t</script>\n\n</body></html>"
  },
  {
    "path": "ch12/03_testing/04_coverage_data.htm",
    "content": "<!DOCTYPE html>\n<!-- saved from url=(0098)file:///private/var/folders/j1/jctgvxk55ngftwfqp1wzrt440000gs/T/cover386841411/coverage.html#file0 -->\n<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n\t\t\n\t\t<style>\n\t\t\tbody {\n\t\t\t\tbackground: black;\n\t\t\t\tcolor: rgb(80, 80, 80);\n\t\t\t}\n\t\t\tbody, pre, #legend span {\n\t\t\t\tfont-family: Menlo, monospace;\n\t\t\t\tfont-weight: bold;\n\t\t\t}\n\t\t\t#topbar {\n\t\t\t\tbackground: black;\n\t\t\t\tposition: fixed;\n\t\t\t\ttop: 0; left: 0; right: 0;\n\t\t\t\theight: 42px;\n\t\t\t\tborder-bottom: 1px solid rgb(80, 80, 80);\n\t\t\t}\n\t\t\t#content {\n\t\t\t\tmargin-top: 50px;\n\t\t\t}\n\t\t\t#nav, #legend {\n\t\t\t\tfloat: left;\n\t\t\t\tmargin-left: 10px;\n\t\t\t}\n\t\t\t#legend {\n\t\t\t\tmargin-top: 12px;\n\t\t\t}\n\t\t\t#nav {\n\t\t\t\tmargin-top: 10px;\n\t\t\t}\n\t\t\t#legend span {\n\t\t\t\tmargin: 0 5px;\n\t\t\t}\n\t\t\t.cov0 { color: rgb(192, 0, 0) }\n.cov1 { color: rgb(128, 128, 128) }\n.cov2 { color: rgb(116, 140, 131) }\n.cov3 { color: rgb(104, 152, 134) }\n.cov4 { color: rgb(92, 164, 137) }\n.cov5 { color: rgb(80, 176, 140) }\n.cov6 { color: rgb(68, 188, 143) }\n.cov7 { color: rgb(56, 200, 146) }\n.cov8 { color: rgb(44, 212, 149) }\n.cov9 { color: rgb(32, 224, 152) }\n.cov10 { color: rgb(20, 236, 155) }\n\n\t\t</style>\n\t</head>\n\t<body>\n\t\t<div id=\"topbar\">\n\t\t\t<div id=\"nav\">\n\t\t\t\t<select id=\"files\">\n\t\t\t\t\n\t\t\t\t<option value=\"file0\">github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/data/dao.go (80.0%)</option>\n\t\t\t\t\n\t\t\t\t<option value=\"file1\">github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/data/data.go (55.6%)</option>\n\t\t\t\t\n\t\t\t\t<option value=\"file2\">github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/data/tracker.go (0.0%)</option>\n\t\t\t\t\n\t\t\t\t</select>\n\t\t\t</div>\n\t\t\t<div id=\"legend\">\n\t\t\t\t<span>not tracked</span>\n\t\t\t\n\t\t\t\t<span class=\"cov0\">not covered</span>\n\t\t\t\t<span class=\"cov8\">covered</span>\n\t\t\t\n\t\t\t</div>\n\t\t</div>\n\t\t<div id=\"content\">\n\t\t\n\t\t<pre class=\"file\" id=\"file0\" style=\"display: block;\">package data\n\nimport (\n        \"context\"\n        \"database/sql\"\n        \"time\"\n)\n\n// NewDAO will initialize the database connection pool (if not already done) and return a data access object which\n// can be used to interact with the database\nfunc NewDAO(cfg Config) *DAO <span class=\"cov8\" title=\"1\">{\n        // initialize the db connection pool\n        _, _ = getDB(cfg)\n\n        return &amp;DAO{\n                cfg: cfg,\n        }\n}</span>\n\n// DAO is a data access object that provides an abstraction over our database interactions.\ntype DAO struct {\n        cfg Config\n\n        // Tracker is an optional query timer\n        Tracker QueryTracker\n}\n\n// Load will attempt to load and return a person.\n// It will return ErrNotFound when the requested person does not exist.\n// Any other errors returned are caused by the underlying database or our connection to it.\nfunc (d *DAO) Load(ctx context.Context, ID int) (*Person, error) <span class=\"cov8\" title=\"1\">{\n        // track processing time\n        defer d.getTracker().Track(\"Load\", time.Now())\n\n        db, err := getDB(d.cfg)\n        if err != nil </span><span class=\"cov0\" title=\"0\">{\n                d.cfg.Logger().Error(\"failed to get DB connection. err: %s\", err)\n                return nil, err\n        }</span>\n\n        // set latency budget for the database call\n        <span class=\"cov8\" title=\"1\">subCtx, cancel := context.WithTimeout(ctx, 1*time.Second)\n        defer cancel()\n\n        // perform DB select\n        row := db.QueryRowContext(subCtx, sqlLoadByID, ID)\n\n        // retrieve columns and populate the person object\n        out, err := populatePerson(row.Scan)\n        if err != nil </span><span class=\"cov8\" title=\"1\">{\n                if err == sql.ErrNoRows </span><span class=\"cov0\" title=\"0\">{\n                        d.cfg.Logger().Warn(\"failed to load requested person '%d'. err: %s\", ID, err)\n                        return nil, ErrNotFound\n                }</span>\n\n                <span class=\"cov8\" title=\"1\">d.cfg.Logger().Error(\"failed to convert query result. err: %s\", err)\n                return nil, err</span>\n        }\n        <span class=\"cov8\" title=\"1\">return out, nil</span>\n}\n\n// LoadAll will attempt to load all people in the database\n// It will return ErrNotFound when there are not people in the database\n// Any other errors returned are caused by the underlying database or our connection to it.\nfunc (d *DAO) LoadAll(ctx context.Context) ([]*Person, error) <span class=\"cov8\" title=\"1\">{\n        // track processing time\n        defer d.getTracker().Track(\"LoadAll\", time.Now())\n\n        db, err := getDB(d.cfg)\n        if err != nil </span><span class=\"cov0\" title=\"0\">{\n                d.cfg.Logger().Error(\"failed to get DB connection. err: %s\", err)\n                return nil, err\n        }</span>\n\n        // set latency budget for the database call\n        <span class=\"cov8\" title=\"1\">subCtx, cancel := context.WithTimeout(ctx, 1*time.Second)\n        defer cancel()\n\n        // perform DB select\n        rows, err := db.QueryContext(subCtx, sqlLoadAll)\n        if err != nil </span><span class=\"cov8\" title=\"1\">{\n                return nil, err\n        }</span>\n        <span class=\"cov8\" title=\"1\">defer func() </span><span class=\"cov8\" title=\"1\">{\n                _ = rows.Close()\n        }</span>()\n\n        <span class=\"cov8\" title=\"1\">var out []*Person\n\n        for rows.Next() </span><span class=\"cov8\" title=\"1\">{\n                // retrieve columns and populate the person object\n                record, err := populatePerson(rows.Scan)\n                if err != nil </span><span class=\"cov0\" title=\"0\">{\n                        d.cfg.Logger().Error(\"failed to convert query result. err: %s\", err)\n                        return nil, err\n                }</span>\n\n                <span class=\"cov8\" title=\"1\">out = append(out, record)</span>\n        }\n\n        <span class=\"cov8\" title=\"1\">if len(out) == 0 </span><span class=\"cov0\" title=\"0\">{\n                d.cfg.Logger().Warn(\"no people found in the database.\")\n                return nil, ErrNotFound\n        }</span>\n\n        <span class=\"cov8\" title=\"1\">return out, nil</span>\n}\n\n// Save will save the supplied person and return the ID of the newly created person or an error.\n// Errors returned are caused by the underlying database or our connection to it.\nfunc (d *DAO) Save(ctx context.Context, in *Person) (int, error) <span class=\"cov8\" title=\"1\">{\n        // track processing time\n        defer d.getTracker().Track(\"Save\", time.Now())\n\n        db, err := getDB(d.cfg)\n        if err != nil </span><span class=\"cov8\" title=\"1\">{\n                d.cfg.Logger().Error(\"failed to get DB connection. err: %s\", err)\n                return defaultPersonID, err\n        }</span>\n\n        // set latency budget for the database call\n        <span class=\"cov8\" title=\"1\">subCtx, cancel := context.WithTimeout(ctx, 1*time.Second)\n        defer cancel()\n\n        // perform DB insert\n        result, err := db.ExecContext(subCtx, sqlInsert, in.FullName, in.Phone, in.Currency, in.Price)\n        if err != nil </span><span class=\"cov8\" title=\"1\">{\n                d.cfg.Logger().Error(\"failed to save person into DB. err: %s\", err)\n                return defaultPersonID, err\n        }</span>\n\n        // retrieve and return the ID of the person created\n        <span class=\"cov8\" title=\"1\">id, err := result.LastInsertId()\n        if err != nil </span><span class=\"cov0\" title=\"0\">{\n                d.cfg.Logger().Error(\"failed to retrieve id of last saved person. err: %s\", err)\n                return defaultPersonID, err\n        }</span>\n\n        <span class=\"cov8\" title=\"1\">return int(id), nil</span>\n}\n\nfunc (d *DAO) getTracker() QueryTracker <span class=\"cov8\" title=\"1\">{\n        if d.Tracker == nil </span><span class=\"cov8\" title=\"1\">{\n                d.Tracker = &amp;noopTracker{}\n        }</span>\n\n        <span class=\"cov8\" title=\"1\">return d.Tracker</span>\n}\n</pre>\n\t\t\n\t\t<pre class=\"file\" id=\"file1\" style=\"display: none\">package data\n\nimport (\n        \"database/sql\"\n        \"errors\"\n\n        \"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/logging\"\n        _ \"github.com/go-sql-driver/mysql\"\n)\n\nconst (\n        // default person id (returned on error)\n        defaultPersonID = 0\n\n        // SQL statements as constants (to reduce duplication and maintenance in tests)\n        sqlAllColumns = \"id, fullname, phone, currency, price\"\n        sqlInsert     = \"INSERT INTO person (fullname, phone, currency, price) VALUES (?, ?, ?, ?)\"\n        sqlLoadAll    = \"SELECT \" + sqlAllColumns + \" FROM person\"\n        sqlLoadByID   = \"SELECT \" + sqlAllColumns + \" FROM person WHERE id = ? LIMIT 1\"\n)\n\nvar (\n        db *sql.DB\n\n        // ErrNotFound is returned when the no records where matched by the query\n        ErrNotFound = errors.New(\"not found\")\n)\n\n// Config is the configuration for the data package\ntype Config interface {\n        // Logger returns a reference to the logger\n        Logger() logging.Logger\n\n        // DataDSN returns the data source name\n        DataDSN() string\n}\n\nvar getDB = func(cfg Config) (*sql.DB, error) <span class=\"cov8\" title=\"1\">{\n        if db == nil </span><span class=\"cov0\" title=\"0\">{\n                var err error\n                db, err = sql.Open(\"mysql\", cfg.DataDSN())\n                if err != nil </span><span class=\"cov0\" title=\"0\">{\n                        // if the DB cannot be accessed we are dead\n                        panic(err.Error())</span>\n                }\n        }\n\n        <span class=\"cov8\" title=\"1\">return db, nil</span>\n}\n\n// Person is the data transfer object (DTO) for this package\ntype Person struct {\n        // ID is the unique ID for this person\n        ID int\n        // FullName is the name of this person\n        FullName string\n        // Phone is the phone for this person\n        Phone string\n        // Currency is the currency this person has paid in\n        Currency string\n        // Price is the amount (in the above currency) paid by this person\n        Price float64\n}\n\n// custom type so we can convert sql results to easily\ntype scanner func(dest ...interface{}) error\n\n// reduce the duplication (and maintenance) between sql.Row and sql.Rows usage\nfunc populatePerson(scanner scanner) (*Person, error) <span class=\"cov8\" title=\"1\">{\n        out := &amp;Person{}\n        err := scanner(&amp;out.ID, &amp;out.FullName, &amp;out.Phone, &amp;out.Currency, &amp;out.Price)\n        return out, err\n}</span>\n</pre>\n\t\t\n\t\t<pre class=\"file\" id=\"file2\" style=\"display: none\">package data\n\nimport (\n        \"time\"\n\n        \"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/logging\"\n)\n\n// QueryTracker is an interface to track query timing\ntype QueryTracker interface {\n        // Track will record/out the time a query took by calculating time.Now().Sub(start)\n        Track(key string, start time.Time)\n}\n\n// NO-OP implementation of QueryTracker\ntype noopTracker struct{}\n\n// Track implements QueryTracker\nfunc (_ *noopTracker) Track(_ string, _ time.Time) {<span class=\"cov8\" title=\"1\">\n        // intentionally does nothing\n}</span>\n\n// NewLogTracker returns a Tracker that outputs tracking data to log\nfunc NewLogTracker(logger logging.Logger) *LogTracker <span class=\"cov0\" title=\"0\">{\n        return &amp;LogTracker{\n                logger: logger,\n        }\n}</span>\n\n// LogTracker implements QueryTracker and outputs to the supplied logger\ntype LogTracker struct {\n        logger logging.Logger\n}\n\n// Track implements QueryTracker\nfunc (l *LogTracker) Track(key string, start time.Time) <span class=\"cov0\" title=\"0\">{\n        l.logger.Info(\"[%s] Timing: %s\\n\", key, time.Now().Sub(start).String())\n}</span>\n</pre>\n\t\t\n\t\t</div>\n\t\n\t<script>\n\t(function() {\n\t\tvar files = document.getElementById('files');\n\t\tvar visible;\n\t\tfiles.addEventListener('change', onChange, false);\n\t\tfunction select(part) {\n\t\t\tif (visible)\n\t\t\t\tvisible.style.display = 'none';\n\t\t\tvisible = document.getElementById(part);\n\t\t\tif (!visible)\n\t\t\t\treturn;\n\t\t\tfiles.value = part;\n\t\t\tvisible.style.display = 'block';\n\t\t\tlocation.hash = part;\n\t\t}\n\t\tfunction onChange() {\n\t\t\tselect(files.value);\n\t\t\twindow.scrollTo(0, 0);\n\t\t}\n\t\tif (location.hash != \"\") {\n\t\t\tselect(location.hash.substr(1));\n\t\t}\n\t\tif (!visible) {\n\t\t\tselect(\"file0\");\n\t\t}\n\t})();\n\t</script>\n\n</body></html>"
  },
  {
    "path": "ch12/03_testing/04_coverage_exchange.htm",
    "content": "<!DOCTYPE html>\n<!-- saved from url=(0098)file:///private/var/folders/j1/jctgvxk55ngftwfqp1wzrt440000gs/T/cover261749083/coverage.html#file0 -->\n<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n\t\t\n\t\t<style>\n\t\t\tbody {\n\t\t\t\tbackground: black;\n\t\t\t\tcolor: rgb(80, 80, 80);\n\t\t\t}\n\t\t\tbody, pre, #legend span {\n\t\t\t\tfont-family: Menlo, monospace;\n\t\t\t\tfont-weight: bold;\n\t\t\t}\n\t\t\t#topbar {\n\t\t\t\tbackground: black;\n\t\t\t\tposition: fixed;\n\t\t\t\ttop: 0; left: 0; right: 0;\n\t\t\t\theight: 42px;\n\t\t\t\tborder-bottom: 1px solid rgb(80, 80, 80);\n\t\t\t}\n\t\t\t#content {\n\t\t\t\tmargin-top: 50px;\n\t\t\t}\n\t\t\t#nav, #legend {\n\t\t\t\tfloat: left;\n\t\t\t\tmargin-left: 10px;\n\t\t\t}\n\t\t\t#legend {\n\t\t\t\tmargin-top: 12px;\n\t\t\t}\n\t\t\t#nav {\n\t\t\t\tmargin-top: 10px;\n\t\t\t}\n\t\t\t#legend span {\n\t\t\t\tmargin: 0 5px;\n\t\t\t}\n\t\t\t.cov0 { color: rgb(192, 0, 0) }\n.cov1 { color: rgb(128, 128, 128) }\n.cov2 { color: rgb(116, 140, 131) }\n.cov3 { color: rgb(104, 152, 134) }\n.cov4 { color: rgb(92, 164, 137) }\n.cov5 { color: rgb(80, 176, 140) }\n.cov6 { color: rgb(68, 188, 143) }\n.cov7 { color: rgb(56, 200, 146) }\n.cov8 { color: rgb(44, 212, 149) }\n.cov9 { color: rgb(32, 224, 152) }\n.cov10 { color: rgb(20, 236, 155) }\n\n\t\t</style>\n\t</head>\n\t<body>\n\t\t<div id=\"topbar\">\n\t\t\t<div id=\"nav\">\n\t\t\t\t<select id=\"files\">\n\t\t\t\t\n\t\t\t\t<option value=\"file0\">github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/exchange/converter.go (61.7%)</option>\n\t\t\t\t\n\t\t\t\t</select>\n\t\t\t</div>\n\t\t\t<div id=\"legend\">\n\t\t\t\t<span>not tracked</span>\n\t\t\t\n\t\t\t\t<span class=\"cov0\">not covered</span>\n\t\t\t\t<span class=\"cov8\">covered</span>\n\t\t\t\n\t\t\t</div>\n\t\t</div>\n\t\t<div id=\"content\">\n\t\t\n\t\t<pre class=\"file\" id=\"file0\" style=\"display: block;\">package exchange\n\nimport (\n        \"context\"\n        \"encoding/json\"\n        \"fmt\"\n        \"io/ioutil\"\n        \"math\"\n        \"net/http\"\n        \"time\"\n\n        \"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/logging\"\n)\n\nconst (\n        // request URL for the exchange rate API\n\t\turlFormat = \"%s/api/historical?access_key=%s&date=2018-06-20&currencies=%s\"\n\n        // default price that is sent when an error occurs\n        defaultPrice = 0.0\n)\n\n// NewConverter creates and initializes the converter\nfunc NewConverter(cfg Config) *Converter <span class=\"cov8\" title=\"1\">{\n        return &amp;Converter{\n                cfg: cfg,\n        }\n}</span>\n\n// Config is the config for Converter\ntype Config interface {\n        Logger() logging.Logger\n        ExchangeBaseURL() string\n        ExchangeAPIKey() string\n}\n\n// Converter will convert the base price to the currency supplied\n// Note: we are expecting sane inputs and therefore skipping input validation\ntype Converter struct {\n        cfg Config\n}\n\n// Exchange will perform the conversion\nfunc (c *Converter) Exchange(ctx context.Context, basePrice float64, currency string) (float64, error) <span class=\"cov8\" title=\"1\">{\n        // load rate from the external API\n        response, err := c.loadRateFromServer(ctx, currency)\n        if err != nil </span><span class=\"cov0\" title=\"0\">{\n                return defaultPrice, err\n        }</span>\n\n        // extract rate from response\n        <span class=\"cov8\" title=\"1\">rate, err := c.extractRate(response, currency)\n        if err != nil </span><span class=\"cov0\" title=\"0\">{\n                return defaultPrice, err\n        }</span>\n\n        // apply rate and round to 2 decimal places\n        <span class=\"cov8\" title=\"1\">return math.Floor((basePrice/rate)*100) / 100, nil</span>\n}\n\n// load rate from the external API\nfunc (c *Converter) loadRateFromServer(ctx context.Context, currency string) (*http.Response, error) <span class=\"cov8\" title=\"1\">{\n        // build the request\n        url := fmt.Sprintf(urlFormat,\n                c.cfg.ExchangeBaseURL(),\n                c.cfg.ExchangeAPIKey(),\n                currency)\n\n        // perform request\n        req, err := http.NewRequest(\"GET\", url, nil)\n        if err != nil </span><span class=\"cov0\" title=\"0\">{\n                c.logger().Warn(\"[exchange] failed to create request. err: %s\", err)\n                return nil, err\n        }</span>\n\n        // set latency budget for the upstream call\n        <span class=\"cov8\" title=\"1\">subCtx, cancel := context.WithTimeout(ctx, 1*time.Second)\n        defer cancel()\n\n        // replace the default context with our custom one\n        req = req.WithContext(subCtx)\n\n        // perform the HTTP request\n        response, err := http.DefaultClient.Do(req)\n        if err != nil </span><span class=\"cov0\" title=\"0\">{\n                c.logger().Warn(\"[exchange] failed to load. err: %s\", err)\n                return nil, err\n        }</span>\n\n        <span class=\"cov8\" title=\"1\">if response.StatusCode != http.StatusOK </span><span class=\"cov0\" title=\"0\">{\n                err = fmt.Errorf(\"request failed with code %d\", response.StatusCode)\n                c.logger().Warn(\"[exchange] %s\", err)\n                return nil, err\n        }</span>\n\n        <span class=\"cov8\" title=\"1\">return response, nil</span>\n}\n\nfunc (c *Converter) extractRate(response *http.Response, currency string) (float64, error) <span class=\"cov8\" title=\"1\">{\n        defer func() </span><span class=\"cov8\" title=\"1\">{\n                _ = response.Body.Close()\n        }</span>()\n\n        // extract data from response\n        <span class=\"cov8\" title=\"1\">data, err := c.extractResponse(response)\n        if err != nil </span><span class=\"cov0\" title=\"0\">{\n                return defaultPrice, err\n        }</span>\n\n        // pull rate from response data\n        <span class=\"cov8\" title=\"1\">rate, found := data.Quotes[\"USD\" + currency]\n        if !found </span><span class=\"cov0\" title=\"0\">{\n                err = fmt.Errorf(\"response did not include expected currency '%s'\", currency)\n                c.logger().Error(\"[exchange] %s\", err)\n                return defaultPrice, err\n        }</span>\n\n        // happy path\n        <span class=\"cov8\" title=\"1\">return rate, nil</span>\n}\n\nfunc (c *Converter) extractResponse(response *http.Response) (*apiResponseFormat, error) <span class=\"cov8\" title=\"1\">{\n        payload, err := ioutil.ReadAll(response.Body)\n        if err != nil </span><span class=\"cov0\" title=\"0\">{\n                c.logger().Error(\"[exchange] failed to ready response body. err: %s\", err)\n                return nil, err\n        }</span>\n\n        <span class=\"cov8\" title=\"1\">data := &amp;apiResponseFormat{}\n        err = json.Unmarshal(payload, data)\n        if err != nil </span><span class=\"cov0\" title=\"0\">{\n                c.logger().Error(\"[exchange] error converting response. err: %s\", err)\n                return nil, err\n        }</span>\n\n        // happy path\n        <span class=\"cov8\" title=\"1\">return data, nil</span>\n}\n\nfunc (c *Converter) logger() logging.Logger <span class=\"cov0\" title=\"0\">{\n        return c.cfg.Logger()\n}</span>\n\n// the response format from the exchange rate API\ntype apiResponseFormat struct {\n        Quotes map[string]float64 `json:\"quotes\"`\n}\n</pre>\n\t\t\n\t\t</div>\n\t\n\t<script>\n\t(function() {\n\t\tvar files = document.getElementById('files');\n\t\tvar visible;\n\t\tfiles.addEventListener('change', onChange, false);\n\t\tfunction select(part) {\n\t\t\tif (visible)\n\t\t\t\tvisible.style.display = 'none';\n\t\t\tvisible = document.getElementById(part);\n\t\t\tif (!visible)\n\t\t\t\treturn;\n\t\t\tfiles.value = part;\n\t\t\tvisible.style.display = 'block';\n\t\t\tlocation.hash = part;\n\t\t}\n\t\tfunction onChange() {\n\t\t\tselect(files.value);\n\t\t\twindow.scrollTo(0, 0);\n\t\t}\n\t\tif (location.hash != \"\") {\n\t\t\tselect(location.hash.substr(1));\n\t\t}\n\t\tif (!visible) {\n\t\t\tselect(\"file0\");\n\t\t}\n\t})();\n\t</script>\n\n</body></html>"
  },
  {
    "path": "ch12/03_testing/04_coverage_get.htm",
    "content": "<!DOCTYPE html>\n<!-- saved from url=(0098)file:///private/var/folders/j1/jctgvxk55ngftwfqp1wzrt440000gs/T/cover426703470/coverage.html#file0 -->\n<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n\t\t\n\t\t<style>\n\t\t\tbody {\n\t\t\t\tbackground: black;\n\t\t\t\tcolor: rgb(80, 80, 80);\n\t\t\t}\n\t\t\tbody, pre, #legend span {\n\t\t\t\tfont-family: Menlo, monospace;\n\t\t\t\tfont-weight: bold;\n\t\t\t}\n\t\t\t#topbar {\n\t\t\t\tbackground: black;\n\t\t\t\tposition: fixed;\n\t\t\t\ttop: 0; left: 0; right: 0;\n\t\t\t\theight: 42px;\n\t\t\t\tborder-bottom: 1px solid rgb(80, 80, 80);\n\t\t\t}\n\t\t\t#content {\n\t\t\t\tmargin-top: 50px;\n\t\t\t}\n\t\t\t#nav, #legend {\n\t\t\t\tfloat: left;\n\t\t\t\tmargin-left: 10px;\n\t\t\t}\n\t\t\t#legend {\n\t\t\t\tmargin-top: 12px;\n\t\t\t}\n\t\t\t#nav {\n\t\t\t\tmargin-top: 10px;\n\t\t\t}\n\t\t\t#legend span {\n\t\t\t\tmargin: 0 5px;\n\t\t\t}\n\t\t\t.cov0 { color: rgb(192, 0, 0) }\n.cov1 { color: rgb(128, 128, 128) }\n.cov2 { color: rgb(116, 140, 131) }\n.cov3 { color: rgb(104, 152, 134) }\n.cov4 { color: rgb(92, 164, 137) }\n.cov5 { color: rgb(80, 176, 140) }\n.cov6 { color: rgb(68, 188, 143) }\n.cov7 { color: rgb(56, 200, 146) }\n.cov8 { color: rgb(44, 212, 149) }\n.cov9 { color: rgb(32, 224, 152) }\n.cov10 { color: rgb(20, 236, 155) }\n\n\t\t</style>\n\t</head>\n\t<body>\n\t\t<div id=\"topbar\">\n\t\t\t<div id=\"nav\">\n\t\t\t\t<select id=\"files\">\n\t\t\t\t\n\t\t\t\t<option value=\"file0\">github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/get/get.go (81.8%)</option>\n\t\t\t\t\n\t\t\t\t</select>\n\t\t\t</div>\n\t\t\t<div id=\"legend\">\n\t\t\t\t<span>not tracked</span>\n\t\t\t\n\t\t\t\t<span class=\"cov0\">not covered</span>\n\t\t\t\t<span class=\"cov8\">covered</span>\n\t\t\t\n\t\t\t</div>\n\t\t</div>\n\t\t<div id=\"content\">\n\t\t\n\t\t<pre class=\"file\" id=\"file0\" style=\"display: block;\">package get\n\nimport (\n        \"context\"\n        \"errors\"\n\n        \"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/logging\"\n        \"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/data\"\n)\n\nvar (\n        // error thrown when the requested person is not in the database\n        errPersonNotFound = errors.New(\"person not found\")\n)\n\n// NewGetter creates and initializes a Getter\nfunc NewGetter(cfg Config) *Getter <span class=\"cov0\" title=\"0\">{\n        return &amp;Getter{\n                cfg: cfg,\n        }\n}</span>\n\n// Config is the configuration for Getter\ntype Config interface {\n        Logger() logging.Logger\n        DataDSN() string\n}\n\n// Getter will attempt to load a person.\n// It can return an error caused by the data layer or when the requested person is not found\ntype Getter struct {\n        cfg  Config\n        data myLoader\n}\n\n// Do will perform the get\nfunc (g *Getter) Do(ID int) (*Person, error) <span class=\"cov8\" title=\"1\">{\n        // load person from the data layer\n        person, err := g.getLoader().Load(context.TODO(), ID)\n        if err != nil </span><span class=\"cov8\" title=\"1\">{\n                if err == data.ErrNotFound </span><span class=\"cov8\" title=\"1\">{\n                        // By converting the error we are hiding the implementation details from our users.\n                        return nil, errPersonNotFound\n                }</span>\n                <span class=\"cov8\" title=\"1\">return nil, err</span>\n        }\n\n        <span class=\"cov8\" title=\"1\">return g.convert(person), err</span>\n}\n\nfunc (g *Getter) getLoader() myLoader <span class=\"cov8\" title=\"1\">{\n        if g.data == nil </span><span class=\"cov0\" title=\"0\">{\n                g.data = data.NewDAO(g.cfg)\n        }</span>\n\n        <span class=\"cov8\" title=\"1\">return g.data</span>\n}\n\nfunc (g *Getter) convert(in *data.Person) *Person <span class=\"cov8\" title=\"1\">{\n        return &amp;Person{\n                ID:       in.ID,\n                Currency: in.Currency,\n                FullName: in.FullName,\n                Phone:    in.Phone,\n                Price:    in.Price,\n        }\n}</span>\n\n//go:generate mockery -name=myLoader -case underscore -testonly -inpkg -note @generated\ntype myLoader interface {\n        Load(ctx context.Context, ID int) (*data.Person, error)\n}\n\n// Person is a copy/sub-set of data.Person so that the relationship does not leak.\n// It also allows us to remove/hide and internal fields\ntype Person struct {\n        ID       int\n        FullName string\n        Phone    string\n        Currency string\n        Price    float64\n}\n</pre>\n\t\t\n\t\t</div>\n\t\n\t<script>\n\t(function() {\n\t\tvar files = document.getElementById('files');\n\t\tvar visible;\n\t\tfiles.addEventListener('change', onChange, false);\n\t\tfunction select(part) {\n\t\t\tif (visible)\n\t\t\t\tvisible.style.display = 'none';\n\t\t\tvisible = document.getElementById(part);\n\t\t\tif (!visible)\n\t\t\t\treturn;\n\t\t\tfiles.value = part;\n\t\t\tvisible.style.display = 'block';\n\t\t\tlocation.hash = part;\n\t\t}\n\t\tfunction onChange() {\n\t\t\tselect(files.value);\n\t\t\twindow.scrollTo(0, 0);\n\t\t}\n\t\tif (location.hash != \"\") {\n\t\t\tselect(location.hash.substr(1));\n\t\t}\n\t\tif (!visible) {\n\t\t\tselect(\"file0\");\n\t\t}\n\t})();\n\t</script>\n\n</body></html>"
  },
  {
    "path": "ch12/03_testing/04_coverage_list.htm",
    "content": "<!DOCTYPE html>\n<!-- saved from url=(0098)file:///private/var/folders/j1/jctgvxk55ngftwfqp1wzrt440000gs/T/cover379897937/coverage.html#file0 -->\n<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n\t\t\n\t\t<style>\n\t\t\tbody {\n\t\t\t\tbackground: black;\n\t\t\t\tcolor: rgb(80, 80, 80);\n\t\t\t}\n\t\t\tbody, pre, #legend span {\n\t\t\t\tfont-family: Menlo, monospace;\n\t\t\t\tfont-weight: bold;\n\t\t\t}\n\t\t\t#topbar {\n\t\t\t\tbackground: black;\n\t\t\t\tposition: fixed;\n\t\t\t\ttop: 0; left: 0; right: 0;\n\t\t\t\theight: 42px;\n\t\t\t\tborder-bottom: 1px solid rgb(80, 80, 80);\n\t\t\t}\n\t\t\t#content {\n\t\t\t\tmargin-top: 50px;\n\t\t\t}\n\t\t\t#nav, #legend {\n\t\t\t\tfloat: left;\n\t\t\t\tmargin-left: 10px;\n\t\t\t}\n\t\t\t#legend {\n\t\t\t\tmargin-top: 12px;\n\t\t\t}\n\t\t\t#nav {\n\t\t\t\tmargin-top: 10px;\n\t\t\t}\n\t\t\t#legend span {\n\t\t\t\tmargin: 0 5px;\n\t\t\t}\n\t\t\t.cov0 { color: rgb(192, 0, 0) }\n.cov1 { color: rgb(128, 128, 128) }\n.cov2 { color: rgb(116, 140, 131) }\n.cov3 { color: rgb(104, 152, 134) }\n.cov4 { color: rgb(92, 164, 137) }\n.cov5 { color: rgb(80, 176, 140) }\n.cov6 { color: rgb(68, 188, 143) }\n.cov7 { color: rgb(56, 200, 146) }\n.cov8 { color: rgb(44, 212, 149) }\n.cov9 { color: rgb(32, 224, 152) }\n.cov10 { color: rgb(20, 236, 155) }\n\n\t\t</style>\n\t</head>\n\t<body>\n\t\t<div id=\"topbar\">\n\t\t\t<div id=\"nav\">\n\t\t\t\t<select id=\"files\">\n\t\t\t\t\n\t\t\t\t<option value=\"file0\">github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/list/list.go (38.1%)</option>\n\t\t\t\t\n\t\t\t\t</select>\n\t\t\t</div>\n\t\t\t<div id=\"legend\">\n\t\t\t\t<span>not tracked</span>\n\t\t\t\n\t\t\t\t<span class=\"cov0\">not covered</span>\n\t\t\t\t<span class=\"cov8\">covered</span>\n\t\t\t\n\t\t\t</div>\n\t\t</div>\n\t\t<div id=\"content\">\n\t\t\n\t\t<pre class=\"file\" id=\"file0\" style=\"display: block;\">package list\n\nimport (\n        \"context\"\n        \"errors\"\n\n        \"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/logging\"\n        \"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/data\"\n)\n\nvar (\n        // error thrown when there are no people in the database\n        errPeopleNotFound = errors.New(\"no people found\")\n)\n\n// NewLister creates and initializes a Lister\nfunc NewLister(cfg Config) *Lister <span class=\"cov0\" title=\"0\">{\n        return &amp;Lister{\n                cfg: cfg,\n        }\n}</span>\n\n// Config is the config for Lister\ntype Config interface {\n        Logger() logging.Logger\n        DataDSN() string\n}\n\n// Lister will attempt to load all people in the database.\n// It can return an error caused by the data layer\ntype Lister struct {\n        cfg  Config\n        data myLoader\n}\n\n// Exchange will load the people from the data layer\nfunc (l *Lister) Do() ([]*Person, error) <span class=\"cov0\" title=\"0\">{\n        // load all people\n        people, err := l.load()\n        if err != nil </span><span class=\"cov0\" title=\"0\">{\n                return nil, err\n        }</span>\n\n        <span class=\"cov0\" title=\"0\">if len(people) == 0 </span><span class=\"cov0\" title=\"0\">{\n                // special processing for 0 people returned\n                return nil, errPeopleNotFound\n        }</span>\n\n        <span class=\"cov0\" title=\"0\">return l.convert(people), nil</span>\n}\n\n// load all people\nfunc (l *Lister) load() ([]*data.Person, error) <span class=\"cov8\" title=\"1\">{\n        people, err := l.getLoader().LoadAll(context.TODO())\n        if err != nil </span><span class=\"cov8\" title=\"1\">{\n                if err == data.ErrNotFound </span><span class=\"cov8\" title=\"1\">{\n                        // By converting the error we are encapsulating the implementation details from our users.\n                        return nil, errPeopleNotFound\n                }</span>\n                <span class=\"cov8\" title=\"1\">return nil, err</span>\n        }\n\n        <span class=\"cov8\" title=\"1\">return people, nil</span>\n}\n\nfunc (l *Lister) getLoader() myLoader <span class=\"cov8\" title=\"1\">{\n        if l.data == nil </span><span class=\"cov0\" title=\"0\">{\n                l.data = data.NewDAO(l.cfg)\n\n                // temporarily add a log tracker\n                l.data.(*data.DAO).Tracker = data.NewLogTracker(l.cfg.Logger())\n        }</span>\n\n        <span class=\"cov8\" title=\"1\">return l.data</span>\n}\n\nfunc (l *Lister) convert(in []*data.Person) []*Person <span class=\"cov0\" title=\"0\">{\n        out := make([]*Person, len(in))\n\n        for index, thisRecord := range in </span><span class=\"cov0\" title=\"0\">{\n                out[index] = &amp;Person{\n                        ID:       thisRecord.ID,\n                        FullName: thisRecord.FullName,\n                        Phone:    thisRecord.Phone,\n                }\n        }</span>\n\n        <span class=\"cov0\" title=\"0\">return out</span>\n}\n\n//go:generate mockery -name=myLoader -case underscore -testonly -inpkg -note @generated\ntype myLoader interface {\n        LoadAll(ctx context.Context) ([]*data.Person, error)\n}\n\n// Person is a copy/sub-set of data.Person so that the relationship does not leak.\n// It also allows us to remove/hide and internal fields\ntype Person struct {\n        ID       int\n        FullName string\n        Phone    string\n}\n</pre>\n\t\t\n\t\t</div>\n\t\n\t<script>\n\t(function() {\n\t\tvar files = document.getElementById('files');\n\t\tvar visible;\n\t\tfiles.addEventListener('change', onChange, false);\n\t\tfunction select(part) {\n\t\t\tif (visible)\n\t\t\t\tvisible.style.display = 'none';\n\t\t\tvisible = document.getElementById(part);\n\t\t\tif (!visible)\n\t\t\t\treturn;\n\t\t\tfiles.value = part;\n\t\t\tvisible.style.display = 'block';\n\t\t\tlocation.hash = part;\n\t\t}\n\t\tfunction onChange() {\n\t\t\tselect(files.value);\n\t\t\twindow.scrollTo(0, 0);\n\t\t}\n\t\tif (location.hash != \"\") {\n\t\t\tselect(location.hash.substr(1));\n\t\t}\n\t\tif (!visible) {\n\t\t\tselect(\"file0\");\n\t\t}\n\t})();\n\t</script>\n\n</body></html>"
  },
  {
    "path": "ch12/03_testing/04_coverage_main.htm",
    "content": "<!DOCTYPE html>\n<!-- saved from url=(0098)file:///private/var/folders/j1/jctgvxk55ngftwfqp1wzrt440000gs/T/cover635887609/coverage.html#file0 -->\n<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n\t\t\n\t\t<style>\n\t\t\tbody {\n\t\t\t\tbackground: black;\n\t\t\t\tcolor: rgb(80, 80, 80);\n\t\t\t}\n\t\t\tbody, pre, #legend span {\n\t\t\t\tfont-family: Menlo, monospace;\n\t\t\t\tfont-weight: bold;\n\t\t\t}\n\t\t\t#topbar {\n\t\t\t\tbackground: black;\n\t\t\t\tposition: fixed;\n\t\t\t\ttop: 0; left: 0; right: 0;\n\t\t\t\theight: 42px;\n\t\t\t\tborder-bottom: 1px solid rgb(80, 80, 80);\n\t\t\t}\n\t\t\t#content {\n\t\t\t\tmargin-top: 50px;\n\t\t\t}\n\t\t\t#nav, #legend {\n\t\t\t\tfloat: left;\n\t\t\t\tmargin-left: 10px;\n\t\t\t}\n\t\t\t#legend {\n\t\t\t\tmargin-top: 12px;\n\t\t\t}\n\t\t\t#nav {\n\t\t\t\tmargin-top: 10px;\n\t\t\t}\n\t\t\t#legend span {\n\t\t\t\tmargin: 0 5px;\n\t\t\t}\n\t\t\t.cov0 { color: rgb(192, 0, 0) }\n.cov1 { color: rgb(128, 128, 128) }\n.cov2 { color: rgb(116, 140, 131) }\n.cov3 { color: rgb(104, 152, 134) }\n.cov4 { color: rgb(92, 164, 137) }\n.cov5 { color: rgb(80, 176, 140) }\n.cov6 { color: rgb(68, 188, 143) }\n.cov7 { color: rgb(56, 200, 146) }\n.cov8 { color: rgb(44, 212, 149) }\n.cov9 { color: rgb(32, 224, 152) }\n.cov10 { color: rgb(20, 236, 155) }\n\n\t\t</style>\n\t</head>\n\t<body>\n\t\t<div id=\"topbar\">\n\t\t\t<div id=\"nav\">\n\t\t\t\t<select id=\"files\">\n\t\t\t\t\n\t\t\t\t<option value=\"file0\">github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/main.go (0.0%)</option>\n\t\t\t\t\n\t\t\t\t<option value=\"file1\">github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/wire_gen.go (40.0%)</option>\n\t\t\t\t\n\t\t\t\t</select>\n\t\t\t</div>\n\t\t\t<div id=\"legend\">\n\t\t\t\t<span>not tracked</span>\n\t\t\t\n\t\t\t\t<span class=\"cov0\">not covered</span>\n\t\t\t\t<span class=\"cov8\">covered</span>\n\t\t\t\n\t\t\t</div>\n\t\t</div>\n\t\t<div id=\"content\">\n\t\t\n\t\t<pre class=\"file\" id=\"file0\" style=\"display: block;\">package main\n\nimport (\n        \"context\"\n        \"os\"\n\n        \"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/config\"\n        \"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/exchange\"\n        \"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/get\"\n        \"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/list\"\n        \"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/register\"\n        \"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/rest\"\n        \"github.com/google/wire\"\n)\n\nfunc main() <span class=\"cov0\" title=\"0\">{\n        // bind stop channel to context\n        ctx := context.Background()\n\n        // start REST server\n        server, err := initializeServer()\n        if err != nil </span><span class=\"cov0\" title=\"0\">{\n                os.Exit(-1)\n        }</span>\n\n        <span class=\"cov0\" title=\"0\">server.Listen(ctx.Done())</span>\n}\n\n// List of wire enabled objects\nvar wireSetWithoutConfig = wire.NewSet(\n        // *exchange.Converter\n        exchange.NewConverter,\n\n        // *get.Getter\n        get.NewGetter,\n\n        // *list.Lister\n        list.NewLister,\n\n        // *register.Registerer\n        wire.Bind(new(register.Exchanger), &amp;exchange.Converter{}),\n        register.NewRegisterer,\n\n        // *rest.Server\n        wire.Bind(new(rest.GetModel), &amp;get.Getter{}),\n        wire.Bind(new(rest.ListModel), &amp;list.Lister{}),\n        wire.Bind(new(rest.RegisterModel), &amp;register.Registerer{}),\n        rest.New,\n)\n\nvar wireSet = wire.NewSet(\n        wireSetWithoutConfig,\n\n        // *config.Config\n        config.Load,\n\n        // *exchange.Converter\n        wire.Bind(new(exchange.Config), &amp;config.Config{}),\n\n        // *get.Getter\n        wire.Bind(new(get.Config), &amp;config.Config{}),\n\n        // *list.Lister\n        wire.Bind(new(list.Config), &amp;config.Config{}),\n\n        // *register.Registerer\n        wire.Bind(new(register.Config), &amp;config.Config{}),\n\n        // *rest.Server\n        wire.Bind(new(rest.Config), &amp;config.Config{}),\n)\n</pre>\n\t\t\n\t\t<pre class=\"file\" id=\"file1\" style=\"display: none\">// Code generated by Wire. DO NOT EDIT.\n\n//go:generate wire\n//+build !wireinject\n\npackage main\n\nimport (\n        \"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/config\"\n        \"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/exchange\"\n        \"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/get\"\n        \"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/list\"\n        \"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/register\"\n        \"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/rest\"\n)\n\n// Injectors from wire.go:\n\nfunc initializeServer() (*rest.Server, error) <span class=\"cov0\" title=\"0\">{\n        configConfig, err := config.Load()\n        if err != nil </span><span class=\"cov0\" title=\"0\">{\n                return nil, err\n        }</span>\n        <span class=\"cov0\" title=\"0\">getter := get.NewGetter(configConfig)\n        lister := list.NewLister(configConfig)\n        converter := exchange.NewConverter(configConfig)\n        registerer := register.NewRegisterer(configConfig, converter)\n        server := rest.New(configConfig, getter, lister, registerer)\n        return server, nil</span>\n}\n\nfunc initializeServerCustomConfig(exchangeConfig exchange.Config, getConfig get.Config, listConfig list.Config, registerConfig register.Config, restConfig rest.Config) *rest.Server <span class=\"cov8\" title=\"1\">{\n        getter := get.NewGetter(getConfig)\n        lister := list.NewLister(listConfig)\n        converter := exchange.NewConverter(exchangeConfig)\n        registerer := register.NewRegisterer(registerConfig, converter)\n        server := rest.New(restConfig, getter, lister, registerer)\n        return server\n}</span>\n</pre>\n\t\t\n\t\t</div>\n\t\n\t<script>\n\t(function() {\n\t\tvar files = document.getElementById('files');\n\t\tvar visible;\n\t\tfiles.addEventListener('change', onChange, false);\n\t\tfunction select(part) {\n\t\t\tif (visible)\n\t\t\t\tvisible.style.display = 'none';\n\t\t\tvisible = document.getElementById(part);\n\t\t\tif (!visible)\n\t\t\t\treturn;\n\t\t\tfiles.value = part;\n\t\t\tvisible.style.display = 'block';\n\t\t\tlocation.hash = part;\n\t\t}\n\t\tfunction onChange() {\n\t\t\tselect(files.value);\n\t\t\twindow.scrollTo(0, 0);\n\t\t}\n\t\tif (location.hash != \"\") {\n\t\t\tselect(location.hash.substr(1));\n\t\t}\n\t\tif (!visible) {\n\t\t\tselect(\"file0\");\n\t\t}\n\t})();\n\t</script>\n\n</body></html>"
  },
  {
    "path": "ch12/03_testing/04_coverage_register.htm",
    "content": "<!DOCTYPE html>\n<!-- saved from url=(0098)file:///private/var/folders/j1/jctgvxk55ngftwfqp1wzrt440000gs/T/cover088022372/coverage.html#file0 -->\n<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n\t\t\n\t\t<style>\n\t\t\tbody {\n\t\t\t\tbackground: black;\n\t\t\t\tcolor: rgb(80, 80, 80);\n\t\t\t}\n\t\t\tbody, pre, #legend span {\n\t\t\t\tfont-family: Menlo, monospace;\n\t\t\t\tfont-weight: bold;\n\t\t\t}\n\t\t\t#topbar {\n\t\t\t\tbackground: black;\n\t\t\t\tposition: fixed;\n\t\t\t\ttop: 0; left: 0; right: 0;\n\t\t\t\theight: 42px;\n\t\t\t\tborder-bottom: 1px solid rgb(80, 80, 80);\n\t\t\t}\n\t\t\t#content {\n\t\t\t\tmargin-top: 50px;\n\t\t\t}\n\t\t\t#nav, #legend {\n\t\t\t\tfloat: left;\n\t\t\t\tmargin-left: 10px;\n\t\t\t}\n\t\t\t#legend {\n\t\t\t\tmargin-top: 12px;\n\t\t\t}\n\t\t\t#nav {\n\t\t\t\tmargin-top: 10px;\n\t\t\t}\n\t\t\t#legend span {\n\t\t\t\tmargin: 0 5px;\n\t\t\t}\n\t\t\t.cov0 { color: rgb(192, 0, 0) }\n.cov1 { color: rgb(128, 128, 128) }\n.cov2 { color: rgb(116, 140, 131) }\n.cov3 { color: rgb(104, 152, 134) }\n.cov4 { color: rgb(92, 164, 137) }\n.cov5 { color: rgb(80, 176, 140) }\n.cov6 { color: rgb(68, 188, 143) }\n.cov7 { color: rgb(56, 200, 146) }\n.cov8 { color: rgb(44, 212, 149) }\n.cov9 { color: rgb(32, 224, 152) }\n.cov10 { color: rgb(20, 236, 155) }\n\n\t\t</style>\n\t</head>\n\t<body>\n\t\t<div id=\"topbar\">\n\t\t\t<div id=\"nav\">\n\t\t\t\t<select id=\"files\">\n\t\t\t\t\n\t\t\t\t<option value=\"file0\">github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/register/register.go (75.8%)</option>\n\t\t\t\t\n\t\t\t\t</select>\n\t\t\t</div>\n\t\t\t<div id=\"legend\">\n\t\t\t\t<span>not tracked</span>\n\t\t\t\n\t\t\t\t<span class=\"cov0\">not covered</span>\n\t\t\t\t<span class=\"cov8\">covered</span>\n\t\t\t\n\t\t\t</div>\n\t\t</div>\n\t\t<div id=\"content\">\n\t\t\n\t\t<pre class=\"file\" id=\"file0\" style=\"display: block;\">package register\n\nimport (\n        \"context\"\n        \"errors\"\n\n        \"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/logging\"\n        \"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/data\"\n)\n\nconst (\n        // default person id (returned on error)\n        defaultPersonID = 0\n)\n\nvar (\n        // validation errors\n        errNameMissing     = errors.New(\"name is missing\")\n        errPhoneMissing    = errors.New(\"phone is missing\")\n        errCurrencyMissing = errors.New(\"currency is missing\")\n        errInvalidCurrency = errors.New(\"currency is invalid, supported types are AUD, CNY, EUR, GBP, JPY, MYR, SGD, USD\")\n\n        // a little trick to make checking for supported currencies easier\n        supportedCurrencies = map[string]struct{}{\n                \"AUD\": {},\n                \"CNY\": {},\n                \"EUR\": {},\n                \"GBP\": {},\n                \"JPY\": {},\n                \"MYR\": {},\n                \"SGD\": {},\n                \"USD\": {},\n        }\n)\n\n// NewRegisterer creates and initializes a Registerer\nfunc NewRegisterer(cfg Config, exchanger Exchanger) *Registerer <span class=\"cov0\" title=\"0\">{\n        return &amp;Registerer{\n                cfg:       cfg,\n                exchanger: exchanger,\n        }\n}</span>\n\n// Exchanger will convert from one currency to another\n//go:generate mockery -name=Exchanger -case underscore -testonly -inpkg -note @generated\ntype Exchanger interface {\n        // Exchange will perform the conversion\n        Exchange(ctx context.Context, basePrice float64, currency string) (float64, error)\n}\n\n// Config is the configuration for the Registerer\ntype Config interface {\n        Logger() logging.Logger\n        RegistrationBasePrice() float64\n        DataDSN() string\n}\n\n// Registerer validates the supplied person, calculates the price in the requested currency and saves the result.\n// It will return an error when:\n// -the person object does not include all the fields\n// -the currency is invalid\n// -the exchange rate cannot be loaded\n// -the data layer throws an error.\ntype Registerer struct {\n        cfg       Config\n        exchanger Exchanger\n        data      mySaver\n}\n\n// Do is API for this struct\nfunc (r *Registerer) Do(ctx context.Context, in *Person) (int, error) <span class=\"cov8\" title=\"1\">{\n        // validate the request\n        err := r.validateInput(in)\n        if err != nil </span><span class=\"cov0\" title=\"0\">{\n                r.logger().Warn(\"input validation failed with err: %s\", err)\n                return defaultPersonID, err\n        }</span>\n\n        // get price in the requested currency\n        <span class=\"cov8\" title=\"1\">price, err := r.getPrice(ctx, in.Currency)\n        if err != nil </span><span class=\"cov8\" title=\"1\">{\n                return defaultPersonID, err\n        }</span>\n\n        // save registration\n        <span class=\"cov8\" title=\"1\">id, err := r.save(ctx, r.convert(in), price)\n        if err != nil </span><span class=\"cov8\" title=\"1\">{\n                // no need to log here as we expect the data layer to do so\n                return defaultPersonID, err\n        }</span>\n\n        <span class=\"cov8\" title=\"1\">return id, nil</span>\n}\n\n// validate input and return error on fail\nfunc (r *Registerer) validateInput(in *Person) error <span class=\"cov8\" title=\"1\">{\n        if in.FullName == \"\" </span><span class=\"cov0\" title=\"0\">{\n                return errNameMissing\n        }</span>\n        <span class=\"cov8\" title=\"1\">if in.Phone == \"\" </span><span class=\"cov0\" title=\"0\">{\n                return errPhoneMissing\n        }</span>\n        <span class=\"cov8\" title=\"1\">if in.Currency == \"\" </span><span class=\"cov0\" title=\"0\">{\n                return errCurrencyMissing\n        }</span>\n\n        <span class=\"cov8\" title=\"1\">if _, found := supportedCurrencies[in.Currency]; !found </span><span class=\"cov0\" title=\"0\">{\n                return errInvalidCurrency\n        }</span>\n\n        // happy path\n        <span class=\"cov8\" title=\"1\">return nil</span>\n}\n\n// get price in the requested currency\nfunc (r *Registerer) getPrice(ctx context.Context, currency string) (float64, error) <span class=\"cov8\" title=\"1\">{\n        price, err := r.exchanger.Exchange(ctx, r.cfg.RegistrationBasePrice(), currency)\n        if err != nil </span><span class=\"cov8\" title=\"1\">{\n                r.logger().Warn(\"failed to convert the price. err: %s\", err)\n                return defaultPersonID, err\n        }</span>\n\n        <span class=\"cov8\" title=\"1\">return price, nil</span>\n}\n\n// save the registration\nfunc (r *Registerer) save(ctx context.Context, in *data.Person, price float64) (int, error) <span class=\"cov8\" title=\"1\">{\n        person := &amp;data.Person{\n                FullName: in.FullName,\n                Phone:    in.Phone,\n                Currency: in.Currency,\n                Price:    price,\n        }\n        return r.getSaver().Save(ctx, person)\n}</span>\n\nfunc (r *Registerer) getSaver() mySaver <span class=\"cov8\" title=\"1\">{\n        if r.data == nil </span><span class=\"cov0\" title=\"0\">{\n                r.data = data.NewDAO(r.cfg)\n        }</span>\n\n        <span class=\"cov8\" title=\"1\">return r.data</span>\n}\n\nfunc (r *Registerer) logger() logging.Logger <span class=\"cov8\" title=\"1\">{\n        return r.cfg.Logger()\n}</span>\n\nfunc (r *Registerer) convert(in *Person) *data.Person <span class=\"cov8\" title=\"1\">{\n        return &amp;data.Person{\n                ID:       in.ID,\n                Currency: in.Currency,\n                FullName: in.FullName,\n                Phone:    in.Phone,\n                Price:    in.Price,\n        }\n}</span>\n\n//go:generate mockery -name=mySaver -case underscore -testonly -inpkg -note @generated\ntype mySaver interface {\n        Save(ctx context.Context, in *data.Person) (int, error)\n}\n\n// Person is a copy/sub-set of data.Person so that the relationship does not leak.\n// It also allows us to remove/hide and internal fields\ntype Person struct {\n        ID       int\n        FullName string\n        Phone    string\n        Currency string\n        Price    float64\n}\n</pre>\n\t\t\n\t\t</div>\n\t\n\t<script>\n\t(function() {\n\t\tvar files = document.getElementById('files');\n\t\tvar visible;\n\t\tfiles.addEventListener('change', onChange, false);\n\t\tfunction select(part) {\n\t\t\tif (visible)\n\t\t\t\tvisible.style.display = 'none';\n\t\t\tvisible = document.getElementById(part);\n\t\t\tif (!visible)\n\t\t\t\treturn;\n\t\t\tfiles.value = part;\n\t\t\tvisible.style.display = 'block';\n\t\t\tlocation.hash = part;\n\t\t}\n\t\tfunction onChange() {\n\t\t\tselect(files.value);\n\t\t\twindow.scrollTo(0, 0);\n\t\t}\n\t\tif (location.hash != \"\") {\n\t\t\tselect(location.hash.substr(1));\n\t\t}\n\t\tif (!visible) {\n\t\t\tselect(\"file0\");\n\t\t}\n\t})();\n\t</script>\n\n</body></html>"
  },
  {
    "path": "ch12/03_testing/04_coverage_rest.htm",
    "content": "<!DOCTYPE html>\n<!-- saved from url=(0098)file:///private/var/folders/j1/jctgvxk55ngftwfqp1wzrt440000gs/T/cover676848292/coverage.html#file0 -->\n<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n\t\t\n\t\t<style>\n\t\t\tbody {\n\t\t\t\tbackground: black;\n\t\t\t\tcolor: rgb(80, 80, 80);\n\t\t\t}\n\t\t\tbody, pre, #legend span {\n\t\t\t\tfont-family: Menlo, monospace;\n\t\t\t\tfont-weight: bold;\n\t\t\t}\n\t\t\t#topbar {\n\t\t\t\tbackground: black;\n\t\t\t\tposition: fixed;\n\t\t\t\ttop: 0; left: 0; right: 0;\n\t\t\t\theight: 42px;\n\t\t\t\tborder-bottom: 1px solid rgb(80, 80, 80);\n\t\t\t}\n\t\t\t#content {\n\t\t\t\tmargin-top: 50px;\n\t\t\t}\n\t\t\t#nav, #legend {\n\t\t\t\tfloat: left;\n\t\t\t\tmargin-left: 10px;\n\t\t\t}\n\t\t\t#legend {\n\t\t\t\tmargin-top: 12px;\n\t\t\t}\n\t\t\t#nav {\n\t\t\t\tmargin-top: 10px;\n\t\t\t}\n\t\t\t#legend span {\n\t\t\t\tmargin: 0 5px;\n\t\t\t}\n\t\t\t.cov0 { color: rgb(192, 0, 0) }\n.cov1 { color: rgb(128, 128, 128) }\n.cov2 { color: rgb(116, 140, 131) }\n.cov3 { color: rgb(104, 152, 134) }\n.cov4 { color: rgb(92, 164, 137) }\n.cov5 { color: rgb(80, 176, 140) }\n.cov6 { color: rgb(68, 188, 143) }\n.cov7 { color: rgb(56, 200, 146) }\n.cov8 { color: rgb(44, 212, 149) }\n.cov9 { color: rgb(32, 224, 152) }\n.cov10 { color: rgb(20, 236, 155) }\n\n\t\t</style>\n\t</head>\n\t<body>\n\t\t<div id=\"topbar\">\n\t\t\t<div id=\"nav\">\n\t\t\t\t<select id=\"files\">\n\t\t\t\t\n\t\t\t\t<option value=\"file0\">github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/rest/get.go (96.2%)</option>\n\t\t\t\t\n\t\t\t\t<option value=\"file1\">github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/rest/list.go (91.7%)</option>\n\t\t\t\t\n\t\t\t\t<option value=\"file2\">github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/rest/not_found.go (100.0%)</option>\n\t\t\t\t\n\t\t\t\t<option value=\"file3\">github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/rest/register.go (90.5%)</option>\n\t\t\t\t\n\t\t\t\t<option value=\"file4\">github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/rest/server.go (0.0%)</option>\n\t\t\t\t\n\t\t\t\t</select>\n\t\t\t</div>\n\t\t\t<div id=\"legend\">\n\t\t\t\t<span>not tracked</span>\n\t\t\t\n\t\t\t\t<span class=\"cov0\">not covered</span>\n\t\t\t\t<span class=\"cov8\">covered</span>\n\t\t\t\n\t\t\t</div>\n\t\t</div>\n\t\t<div id=\"content\">\n\t\t\n\t\t<pre class=\"file\" id=\"file0\" style=\"display: block;\">package rest\n\nimport (\n        \"encoding/json\"\n        \"errors\"\n        \"fmt\"\n        \"io\"\n        \"net/http\"\n        \"strconv\"\n\n        \"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/logging\"\n        \"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/get\"\n        \"github.com/gorilla/mux\"\n)\n\nconst (\n        // default person id (returned on error)\n        defaultPersonID = 0\n\n        // key in the mux where the ID is stored\n        muxVarID = \"id\"\n)\n\n// GetModel will load a registration\n//go:generate mockery -name=GetModel -case underscore -testonly -inpkg -note @generated\ntype GetModel interface {\n        Do(ID int) (*get.Person, error)\n}\n\n// GetConfig is the config for the Get Handler\ntype GetConfig interface {\n        Logger() logging.Logger\n}\n\n// NewGetHandler is the constructor for GetHandler\nfunc NewGetHandler(cfg GetConfig, model GetModel) *GetHandler <span class=\"cov8\" title=\"1\">{\n        return &amp;GetHandler{\n                cfg:    cfg,\n                getter: model,\n        }\n}</span>\n\n// GetHandler is the HTTP handler for the \"Get Person\" endpoint\n// In this simplified example we are assuming all possible errors are user errors and returning \"bad request\" HTTP 400\n// or \"not found\" HTTP 404\n// There are some programmer errors possible but hopefully these will be caught in testing.\ntype GetHandler struct {\n        cfg    GetConfig\n        getter GetModel\n}\n\n// ServeHTTP implements http.Handler\nfunc (h *GetHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) <span class=\"cov8\" title=\"1\">{\n        // extract person id from request\n        id, err := h.extractID(request)\n        if err != nil </span><span class=\"cov8\" title=\"1\">{\n                // output error\n                response.WriteHeader(http.StatusBadRequest)\n                return\n        }</span>\n\n        // attempt get\n        <span class=\"cov8\" title=\"1\">person, err := h.getter.Do(id)\n        if err != nil </span><span class=\"cov8\" title=\"1\">{\n                // not need to log here as we can expect other layers to do so\n                response.WriteHeader(http.StatusNotFound)\n                return\n        }</span>\n\n        // happy path\n        <span class=\"cov8\" title=\"1\">err = h.writeJSON(response, person)\n        if err != nil </span><span class=\"cov0\" title=\"0\">{\n                // this error should not happen but if it does there is nothing we can do to recover\n                response.WriteHeader(http.StatusInternalServerError)\n        }</span>\n}\n\n// extract the person ID from the request\nfunc (h *GetHandler) extractID(request *http.Request) (int, error) <span class=\"cov8\" title=\"1\">{\n        // ID is part of the URL, so we extract it from there\n        vars := mux.Vars(request)\n        idAsString, exists := vars[muxVarID]\n        if !exists </span><span class=\"cov8\" title=\"1\">{\n                // log and return error\n                err := errors.New(\"[get] person id missing from request\")\n                h.cfg.Logger().Warn(err.Error())\n                return defaultPersonID, err\n        }</span>\n\n        // convert ID to int\n        <span class=\"cov8\" title=\"1\">id, err := strconv.Atoi(idAsString)\n        if err != nil </span><span class=\"cov8\" title=\"1\">{\n                // log and return error\n                err = fmt.Errorf(\"[get] failed to convert person id into a number. err: %s\", err)\n                h.cfg.Logger().Error(err.Error())\n                return defaultPersonID, err\n        }</span>\n\n        <span class=\"cov8\" title=\"1\">return id, nil</span>\n}\n\n// output the supplied person as JSON\nfunc (h *GetHandler) writeJSON(writer io.Writer, person *get.Person) error <span class=\"cov8\" title=\"1\">{\n        output := &amp;getResponseFormat{\n                ID:       person.ID,\n                FullName: person.FullName,\n                Phone:    person.Phone,\n                Currency: person.Currency,\n                Price:    person.Price,\n        }\n\n        // call to http.ResponseWriter.Write() will cause HTTP OK (200) to be output as well\n        return json.NewEncoder(writer).Encode(output)\n}</span>\n\n// the JSON response format\ntype getResponseFormat struct {\n        ID       int     `json:\"id\"`\n        FullName string  `json:\"name\"`\n        Phone    string  `json:\"phone\"`\n        Currency string  `json:\"currency\"`\n        Price    float64 `json:\"price\"`\n}\n</pre>\n\t\t\n\t\t<pre class=\"file\" id=\"file1\" style=\"display: none\">package rest\n\nimport (\n        \"encoding/json\"\n        \"io\"\n        \"net/http\"\n\n        \"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/list\"\n)\n\n// ListModel will load all registrations\n//go:generate mockery -name=ListModel -case underscore -testonly -inpkg -note @generated\ntype ListModel interface {\n        Do() ([]*list.Person, error)\n}\n\n// NewLister is the constructor for ListHandler\nfunc NewListHandler(model ListModel) *ListHandler <span class=\"cov8\" title=\"1\">{\n        return &amp;ListHandler{\n                lister: model,\n        }\n}</span>\n\n// ListHandler is the HTTP handler for the \"List Do people\" endpoint\n// In this simplified example we are assuming all possible errors are system errors (HTTP 500)\ntype ListHandler struct {\n        lister ListModel\n}\n\n// ServeHTTP implements http.Handler\nfunc (h *ListHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) <span class=\"cov8\" title=\"1\">{\n        // attempt loadAll\n        people, err := h.lister.Do()\n        if err != nil </span><span class=\"cov8\" title=\"1\">{\n                // not need to log here as we can expect other layers to do so\n                response.WriteHeader(http.StatusNotFound)\n                return\n        }</span>\n\n        // happy path\n        <span class=\"cov8\" title=\"1\">err = h.writeJSON(response, people)\n        if err != nil </span><span class=\"cov0\" title=\"0\">{\n                // this error should not happen but if it does there is nothing we can do to recover\n                response.WriteHeader(http.StatusInternalServerError)\n        }</span>\n}\n\n// output the result as JSON\nfunc (h *ListHandler) writeJSON(writer io.Writer, people []*list.Person) error <span class=\"cov8\" title=\"1\">{\n        output := &amp;listResponseFormat{\n                People: make([]*listResponseItemFormat, len(people)),\n        }\n\n        for index, record := range people </span><span class=\"cov8\" title=\"1\">{\n                output.People[index] = &amp;listResponseItemFormat{\n                        ID:       record.ID,\n                        FullName: record.FullName,\n                        Phone:    record.Phone,\n                }\n        }</span>\n\n        // call to http.ResponseWriter.Write() will cause HTTP OK (200) to be output as well\n        <span class=\"cov8\" title=\"1\">return json.NewEncoder(writer).Encode(output)</span>\n}\n\ntype listResponseFormat struct {\n        People []*listResponseItemFormat `json:\"people\"`\n}\n\ntype listResponseItemFormat struct {\n        ID       int    `json:\"id\"`\n        FullName string `json:\"name\"`\n        Phone    string `json:\"phone\"`\n}\n</pre>\n\t\t\n\t\t<pre class=\"file\" id=\"file2\" style=\"display: none\">package rest\n\nimport (\n        \"net/http\"\n)\n\nfunc notFoundHandler(response http.ResponseWriter, _ *http.Request) <span class=\"cov8\" title=\"1\">{\n        response.WriteHeader(http.StatusNotFound)\n        _, _ = response.Write([]byte(`Not found`))\n}</span>\n</pre>\n\t\t\n\t\t<pre class=\"file\" id=\"file3\" style=\"display: none\">package rest\n\nimport (\n        \"context\"\n        \"encoding/json\"\n        \"fmt\"\n        \"net/http\"\n        \"time\"\n\n        \"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/register\"\n)\n\n// RegisterModel will validate and save a registration\n//go:generate mockery -name=RegisterModel -case underscore -testonly -inpkg -note @generated\ntype RegisterModel interface {\n        Do(ctx context.Context, in *register.Person) (int, error)\n}\n\n// NewRegisterHandler is the constructor for RegisterHandler\nfunc NewRegisterHandler(model RegisterModel) *RegisterHandler <span class=\"cov8\" title=\"1\">{\n        return &amp;RegisterHandler{\n                registerer: model,\n        }\n}</span>\n\n// RegisterHandler is the HTTP handler for the \"Register\" endpoint\n// In this simplified example we are assuming all possible errors are user errors and returning \"bad request\" HTTP 400.\n// There are some programmer errors possible but hopefully these will be caught in testing.\ntype RegisterHandler struct {\n        registerer RegisterModel\n}\n\n// ServeHTTP implements http.Handler\nfunc (h *RegisterHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) <span class=\"cov8\" title=\"1\">{\n        // set latency budget for this API\n        subCtx, cancel := context.WithTimeout(request.Context(), 1500*time.Millisecond)\n        defer cancel()\n\n        // extract payload from request\n        requestPayload, err := h.extractPayload(request)\n        if err != nil </span><span class=\"cov8\" title=\"1\">{\n                // output error\n                response.WriteHeader(http.StatusBadRequest)\n                return\n        }</span>\n\n        // call the business logic using the request data and context\n        <span class=\"cov8\" title=\"1\">id, err := h.register(subCtx, requestPayload)\n        if err != nil </span><span class=\"cov0\" title=\"0\">{\n                // not need to log here as we can expect other layers to do so\n                response.WriteHeader(http.StatusBadRequest)\n                return\n        }</span>\n\n        // happy path\n        <span class=\"cov8\" title=\"1\">response.Header().Add(\"Location\", fmt.Sprintf(\"/person/%d/\", id))\n        response.WriteHeader(http.StatusCreated)</span>\n}\n\n// extract payload from request\nfunc (h *RegisterHandler) extractPayload(request *http.Request) (*registerRequest, error) <span class=\"cov8\" title=\"1\">{\n        requestPayload := &amp;registerRequest{}\n\n        decoder := json.NewDecoder(request.Body)\n        err := decoder.Decode(requestPayload)\n        if err != nil </span><span class=\"cov8\" title=\"1\">{\n                return nil, err\n        }</span>\n\n        <span class=\"cov8\" title=\"1\">return requestPayload, nil</span>\n}\n\n// call the logic layer\nfunc (h *RegisterHandler) register(ctx context.Context, requestPayload *registerRequest) (int, error) <span class=\"cov8\" title=\"1\">{\n        person := &amp;register.Person{\n                FullName: requestPayload.FullName,\n                Phone:    requestPayload.Phone,\n                Currency: requestPayload.Currency,\n        }\n\n        return h.registerer.Do(ctx, person)\n}</span>\n\n// register endpoint request format\ntype registerRequest struct {\n        // FullName of the person\n        FullName string `json:\"fullName\"`\n        // Phone of the person\n        Phone string `json:\"phone\"`\n        // Currency the wish to register in\n        Currency string `json:\"currency\"`\n}\n</pre>\n\t\t\n\t\t<pre class=\"file\" id=\"file4\" style=\"display: none\">package rest\n\nimport (\n        \"net/http\"\n\n        \"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/logging\"\n        \"github.com/gorilla/mux\"\n)\n\n// Config is the config for the REST package\ntype Config interface {\n        Logger() logging.Logger\n        BindAddress() string\n}\n\n// New will create and initialize the server\nfunc New(cfg Config,\n        getModel GetModel,\n        listModel ListModel,\n        registerModel RegisterModel) *Server <span class=\"cov0\" title=\"0\">{\n\n        return &amp;Server{\n                address:         cfg.BindAddress(),\n                handlerGet:      NewGetHandler(cfg, getModel),\n                handlerList:     NewListHandler(listModel),\n                handlerNotFound: notFoundHandler,\n                handlerRegister: NewRegisterHandler(registerModel),\n        }\n}</span>\n\n// Server is the HTTP REST server\ntype Server struct {\n        address string\n        server  *http.Server\n\n        handlerGet      http.Handler\n        handlerList     http.Handler\n        handlerNotFound http.HandlerFunc\n        handlerRegister http.Handler\n}\n\n// Listen will start a HTTP rest for this service\nfunc (s *Server) Listen(stop &lt;-chan struct{}) <span class=\"cov0\" title=\"0\">{\n        router := s.buildRouter()\n\n        // create the HTTP server\n        s.server = &amp;http.Server{\n                Handler: router,\n                Addr:    s.address,\n        }\n\n        // listen for shutdown\n        go func() </span><span class=\"cov0\" title=\"0\">{\n                // wait for shutdown signal\n                &lt;-stop\n\n                _ = s.server.Close()\n        }</span>()\n\n        // start the HTTP server\n        <span class=\"cov0\" title=\"0\">_ = s.server.ListenAndServe()</span>\n}\n\n// configure the endpoints to handlers\nfunc (s *Server) buildRouter() http.Handler <span class=\"cov0\" title=\"0\">{\n        router := mux.NewRouter()\n\n        // map URL endpoints to HTTP handlers\n        router.Handle(\"/person/{id}/\", s.handlerGet).Methods(\"GET\")\n        router.Handle(\"/person/list\", s.handlerList).Methods(\"GET\")\n        router.Handle(\"/person/register\", s.handlerRegister).Methods(\"POST\")\n\n        // convert a \"catch all\" not found handler\n        router.NotFoundHandler = s.handlerNotFound\n\n        return router\n}</span>\n</pre>\n\t\t\n\t\t</div>\n\t\n\t<script>\n\t(function() {\n\t\tvar files = document.getElementById('files');\n\t\tvar visible;\n\t\tfiles.addEventListener('change', onChange, false);\n\t\tfunction select(part) {\n\t\t\tif (visible)\n\t\t\t\tvisible.style.display = 'none';\n\t\t\tvisible = document.getElementById(part);\n\t\t\tif (!visible)\n\t\t\t\treturn;\n\t\t\tfiles.value = part;\n\t\t\tvisible.style.display = 'block';\n\t\t\tlocation.hash = part;\n\t\t}\n\t\tfunction onChange() {\n\t\t\tselect(files.value);\n\t\t\twindow.scrollTo(0, 0);\n\t\t}\n\t\tif (location.hash != \"\") {\n\t\t\tselect(location.hash.substr(1));\n\t\t}\n\t\tif (!visible) {\n\t\t\tselect(\"file0\");\n\t\t}\n\t})();\n\t</script>\n\n</body></html>"
  },
  {
    "path": "ch12/04_new_service/01_data_with_cache/dao.go",
    "content": "package data\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"encoding/json\"\n\t\"fmt\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/04_new_service/01_data_with_cache/internal/cache\"\n)\n\n// DAO is a data access object that provides an abstraction over our database interactions.\ntype DAO struct {\n\tcfg Config\n\n\tdb    *sql.DB\n\tcache *cache.Cache\n}\n\n// Load will attempt to load and return a person.\n// It will return ErrNotFound when the requested person does not exist.\n// Any other errors returned are caused by the underlying database or our connection to it.\nfunc (d *DAO) Load(ctx context.Context, ID int) (*Person, error) {\n\t// load from cache\n\tout := d.loadFromCache(ID)\n\tif out != nil {\n\t\treturn out, nil\n\t}\n\n\t// load from database\n\trow := d.db.QueryRowContext(ctx, sqlLoadByID, ID)\n\n\t// retrieve columns and populate the person object\n\tout, err := populatePerson(row.Scan)\n\tif err != nil {\n\t\tif err == sql.ErrNoRows {\n\t\t\td.cfg.Logger().Warn(\"failed to load requested person '%d'. err: %s\", ID, err)\n\t\t\treturn nil, ErrNotFound\n\t\t}\n\n\t\td.cfg.Logger().Error(\"failed to convert query result. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// save person into the cache\n\td.saveToCache(ID, out)\n\n\treturn out, nil\n}\n\nfunc (d *DAO) loadFromCache(ID int) *Person {\n\tpayload, err := d.cache.Get(d.buildCacheKey(ID))\n\tif err != nil {\n\t\td.cfg.Logger().Error(\"failed to load requested person from cache with error: %s\", err)\n\t\treturn nil\n\t}\n\n\tif payload == nil {\n\t\treturn nil\n\t}\n\n\tout := &Person{}\n\terr = json.Unmarshal(payload, out)\n\tif err != nil {\n\t\td.cfg.Logger().Error(\"failed to decode cache response with error: %s\", err)\n\t}\n\n\treturn out\n}\n\nfunc (d *DAO) saveToCache(ID int, person *Person) {\n\tpayload, err := json.Marshal(person)\n\tif err != nil {\n\t\td.cfg.Logger().Error(\"failed to encode person to JSON with error: %s\", err)\n\t\treturn\n\t}\n\n\terr = d.cache.Set(d.buildCacheKey(ID), payload)\n\tif err != nil {\n\t\td.cfg.Logger().Error(\"failed to save person into cache with error: %s\", err)\n\t}\n}\n\nfunc (d *DAO) buildCacheKey(ID int) string {\n\treturn fmt.Sprintf(\"person-%d\", ID)\n}\n"
  },
  {
    "path": "ch12/04_new_service/01_data_with_cache/data.go",
    "content": "package data\n\nimport (\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/04_new_service/01_data_with_cache/internal/logging\"\n\t_ \"github.com/go-sql-driver/mysql\"\n)\n\nconst (\n\t// SQL statements as constants (to reduce duplication and maintenance in tests)\n\tsqlAllColumns = \"id, fullname, phone, currency, price\"\n\tsqlLoadByID   = \"SELECT \" + sqlAllColumns + \" FROM person WHERE id = ? LIMIT 1\"\n)\n\nvar (\n\t// ErrNotFound is returned when the no records where matched by the query\n\tErrNotFound = errors.New(\"not found\")\n)\n\n// Config is the configuration for the data package\ntype Config interface {\n\t// Logger returns a reference to the logger\n\tLogger() logging.Logger\n\n\t// DataDSN returns the data source name\n\tDataDSN() string\n}\n\n// Person is the data transfer object (DTO) for this package\ntype Person struct {\n\t// ID is the unique ID for this person\n\tID int\n\t// FullName is the name of this person\n\tFullName string\n\t// Phone is the phone for this person\n\tPhone string\n\t// Currency is the currency this person has paid in\n\tCurrency string\n\t// Price is the amount (in the above currency) paid by this person\n\tPrice float64\n}\n\n// custom type so we can convert sql results to easily\ntype scanner func(dest ...interface{}) error\n\n// reduce the duplication (and maintenance) between sql.Row and sql.Rows usage\nfunc populatePerson(scanner scanner) (*Person, error) {\n\tout := &Person{}\n\terr := scanner(&out.ID, &out.FullName, &out.Phone, &out.Currency, &out.Price)\n\treturn out, err\n}\n"
  },
  {
    "path": "ch12/04_new_service/01_data_with_cache/internal/cache/cache.go",
    "content": "package cache\n\nimport (\n\t\"errors\"\n)\n\ntype Cache struct{}\n\nfunc (c *Cache) Get(key string) ([]byte, error) {\n\treturn nil, errors.New(\"not implemented\")\n}\n\nfunc (c *Cache) Set(key string, data []byte) error {\n\treturn errors.New(\"not implemented\")\n}\n"
  },
  {
    "path": "ch12/04_new_service/01_data_with_cache/internal/logging/logging.go",
    "content": "package logging\n\nimport (\n\t\"fmt\"\n)\n\n// Logger is our standard interface\ntype Logger interface {\n\tDebug(message string, args ...interface{})\n\tInfo(message string, args ...interface{})\n\tWarn(message string, args ...interface{})\n\tError(message string, args ...interface{})\n}\n\n// LoggerStdOut logs to std out\ntype LoggerStdOut struct{}\n\n// Debug logs messages at DEBUG level\nfunc (l LoggerStdOut) Debug(message string, args ...interface{}) {\n\tfmt.Printf(\"[DEBUG] \"+message, args...)\n}\n\n// Info logs messages at INFO level\nfunc (l LoggerStdOut) Info(message string, args ...interface{}) {\n\tfmt.Printf(\"[INFO] \"+message, args...)\n}\n\n// Warn logs messages at WARN level\nfunc (l LoggerStdOut) Warn(message string, args ...interface{}) {\n\tfmt.Printf(\"[WARN] \"+message, args...)\n}\n\n// Error logs messages at ERROR level\nfunc (l LoggerStdOut) Error(message string, args ...interface{}) {\n\tfmt.Printf(\"[ERROR] \"+message, args...)\n}\n"
  },
  {
    "path": "ch12/acme/internal/config/config.go",
    "content": "package config\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"os\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/logging\"\n)\n\n// DefaultEnvVar is the default environment variable the points to the config file\nconst DefaultEnvVar = \"ACME_CONFIG\"\n\n// Config defines the JSON format for the config file\ntype Config struct {\n\t// DSN is the data source name (format: https://github.com/go-sql-driver/mysql/#dsn-data-source-name)\n\tDSN string\n\n\t// Address is the IP address and port to bind this rest to\n\tAddress string\n\n\t// BasePrice is the price of registration\n\tBasePrice float64\n\n\t// ExchangeRateBaseURL is the server and protocol part of the URL from which to load the exchange rate\n\tExchangeRateBaseURL string\n\n\t// ExchangeRateAPIKey is the API for the exchange rate API\n\tExchangeRateAPIKey string\n\n\t// environmental dependencies\n\tlogger logging.Logger\n}\n\n// Logger returns a reference to the singleton logger\nfunc (c *Config) Logger() logging.Logger {\n\tif c.logger == nil {\n\t\tc.logger = &logging.LoggerStdOut{}\n\t}\n\n\treturn c.logger\n}\n\n// RegistrationBasePrice returns the base price for registrations\nfunc (c *Config) RegistrationBasePrice() float64 {\n\treturn c.BasePrice\n}\n\n// DataDSN returns the DSN\nfunc (c *Config) DataDSN() string {\n\treturn c.DSN\n}\n\n// ExchangeBaseURL returns the Base URL from which we can load exchange rates\nfunc (c *Config) ExchangeBaseURL() string {\n\treturn c.ExchangeRateBaseURL\n}\n\n// ExchangeAPIKey returns the DSN\nfunc (c *Config) ExchangeAPIKey() string {\n\treturn c.ExchangeRateAPIKey\n}\n\n// BindAddress returns the host and port this service should bind to\nfunc (c *Config) BindAddress() string {\n\treturn c.Address\n}\n\n// Load returns the config loaded from environment\nfunc Load() (*Config, error) {\n\tfilename, found := os.LookupEnv(DefaultEnvVar)\n\tif !found {\n\t\terr := fmt.Errorf(\"failed to locate file specified by %s\", DefaultEnvVar)\n\t\tfmt.Fprintf(os.Stderr, err.Error())\n\t\treturn nil, err\n\t}\n\n\tcfg, err := load(filename)\n\tif err != nil {\n\t\tfmt.Fprintf(os.Stderr, \"failed to load config with err %s\", err)\n\t\treturn nil, err\n\t}\n\n\treturn cfg, nil\n}\n\nfunc load(filename string) (*Config, error) {\n\tout := &Config{}\n\tbytes, err := ioutil.ReadFile(filename)\n\tif err != nil {\n\t\tfmt.Fprintf(os.Stderr, \"failed to read config file. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\terr = json.Unmarshal(bytes, out)\n\tif err != nil {\n\t\tfmt.Fprintf(os.Stderr, \"failed to parse config file. err : %s\", err)\n\t\treturn nil, err\n\t}\n\n\treturn out, nil\n}\n"
  },
  {
    "path": "ch12/acme/internal/config/config_test.go",
    "content": "package config\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestLoad(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc           string\n\t\tin             string\n\t\texpectedConfig *Config\n\t\texpectError    bool\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tin:   \"../../../../default-config.json\",\n\t\t\texpectedConfig: &Config{\n\t\t\t\tDSN:                 \"[insert your db config here]\",\n\t\t\t\tAddress:             \"0.0.0.0:8080\",\n\t\t\t\tBasePrice:           100.00,\n\t\t\t\tExchangeRateBaseURL: \"http://apilayer.net\",\n\t\t\t\tExchangeRateAPIKey:  \"[insert your API key here]\",\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tdesc:           \"invalid path\",\n\t\t\tin:             \"invalid.json\",\n\t\t\texpectedConfig: nil,\n\t\t\texpectError:    true,\n\t\t},\n\t}\n\n\tfor _, s := range scenarios {\n\t\tscenario := s\n\t\tt.Run(scenario.desc, func(t *testing.T) {\n\t\t\tresult, resultErr := load(scenario.in)\n\t\t\trequire.Equal(t, scenario.expectError, resultErr != nil, \"err: %s\", resultErr)\n\t\t\tassert.Equal(t, scenario.expectedConfig, result, scenario.desc)\n\t\t})\n\t}\n\n}\n"
  },
  {
    "path": "ch12/acme/internal/logging/logging.go",
    "content": "package logging\n\nimport (\n\t\"fmt\"\n)\n\n// Logger is our standard interface\ntype Logger interface {\n\tDebug(message string, args ...interface{})\n\tInfo(message string, args ...interface{})\n\tWarn(message string, args ...interface{})\n\tError(message string, args ...interface{})\n}\n\n// LoggerStdOut logs to std out\ntype LoggerStdOut struct{}\n\n// Debug logs messages at DEBUG level\nfunc (l LoggerStdOut) Debug(message string, args ...interface{}) {\n\tfmt.Printf(\"[DEBUG] \"+message, args...)\n}\n\n// Info logs messages at INFO level\nfunc (l LoggerStdOut) Info(message string, args ...interface{}) {\n\tfmt.Printf(\"[INFO] \"+message, args...)\n}\n\n// Warn logs messages at WARN level\nfunc (l LoggerStdOut) Warn(message string, args ...interface{}) {\n\tfmt.Printf(\"[WARN] \"+message, args...)\n}\n\n// Error logs messages at ERROR level\nfunc (l LoggerStdOut) Error(message string, args ...interface{}) {\n\tfmt.Printf(\"[ERROR] \"+message, args...)\n}\n"
  },
  {
    "path": "ch12/acme/internal/modules/data/dao.go",
    "content": "package data\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"time\"\n)\n\n// NewDAO will initialize the database connection pool (if not already done) and return a data access object which\n// can be used to interact with the database\nfunc NewDAO(cfg Config) *DAO {\n\t// initialize the db connection pool\n\t_, _ = getDB(cfg)\n\n\treturn &DAO{\n\t\tcfg: cfg,\n\t}\n}\n\n// DAO is a data access object that provides an abstraction over our database interactions.\ntype DAO struct {\n\tcfg Config\n\n\t// Tracker is an optional query timer\n\tTracker QueryTracker\n}\n\n// Load will attempt to load and return a person.\n// It will return ErrNotFound when the requested person does not exist.\n// Any other errors returned are caused by the underlying database or our connection to it.\nfunc (d *DAO) Load(ctx context.Context, ID int) (*Person, error) {\n\t// track processing time\n\tdefer d.getTracker().Track(\"Load\", time.Now())\n\n\tdb, err := getDB(d.cfg)\n\tif err != nil {\n\t\td.cfg.Logger().Error(\"failed to get DB connection. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// set latency budget for the database call\n\tsubCtx, cancel := context.WithTimeout(ctx, 1*time.Second)\n\tdefer cancel()\n\n\t// perform DB select\n\trow := db.QueryRowContext(subCtx, sqlLoadByID, ID)\n\n\t// retrieve columns and populate the person object\n\tout, err := populatePerson(row.Scan)\n\tif err != nil {\n\t\tif err == sql.ErrNoRows {\n\t\t\td.cfg.Logger().Warn(\"failed to load requested person '%d'. err: %s\", ID, err)\n\t\t\treturn nil, ErrNotFound\n\t\t}\n\n\t\td.cfg.Logger().Error(\"failed to convert query result. err: %s\", err)\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\n// LoadAll will attempt to load all people in the database\n// It will return ErrNotFound when there are not people in the database\n// Any other errors returned are caused by the underlying database or our connection to it.\nfunc (d *DAO) LoadAll(ctx context.Context) ([]*Person, error) {\n\t// track processing time\n\tdefer d.getTracker().Track(\"LoadAll\", time.Now())\n\n\tdb, err := getDB(d.cfg)\n\tif err != nil {\n\t\td.cfg.Logger().Error(\"failed to get DB connection. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// set latency budget for the database call\n\tsubCtx, cancel := context.WithTimeout(ctx, 1*time.Second)\n\tdefer cancel()\n\n\t// perform DB select\n\trows, err := db.QueryContext(subCtx, sqlLoadAll)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer func() {\n\t\t_ = rows.Close()\n\t}()\n\n\tvar out []*Person\n\n\tfor rows.Next() {\n\t\t// retrieve columns and populate the person object\n\t\trecord, err := populatePerson(rows.Scan)\n\t\tif err != nil {\n\t\t\td.cfg.Logger().Error(\"failed to convert query result. err: %s\", err)\n\t\t\treturn nil, err\n\t\t}\n\n\t\tout = append(out, record)\n\t}\n\n\tif len(out) == 0 {\n\t\td.cfg.Logger().Warn(\"no people found in the database.\")\n\t\treturn nil, ErrNotFound\n\t}\n\n\treturn out, nil\n}\n\n// Save will save the supplied person and return the ID of the newly created person or an error.\n// Errors returned are caused by the underlying database or our connection to it.\nfunc (d *DAO) Save(ctx context.Context, in *Person) (int, error) {\n\t// track processing time\n\tdefer d.getTracker().Track(\"Save\", time.Now())\n\n\tdb, err := getDB(d.cfg)\n\tif err != nil {\n\t\td.cfg.Logger().Error(\"failed to get DB connection. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\t// set latency budget for the database call\n\tsubCtx, cancel := context.WithTimeout(ctx, 1*time.Second)\n\tdefer cancel()\n\n\t// perform DB insert\n\tresult, err := db.ExecContext(subCtx, sqlInsert, in.FullName, in.Phone, in.Currency, in.Price)\n\tif err != nil {\n\t\td.cfg.Logger().Error(\"failed to save person into DB. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\t// retrieve and return the ID of the person created\n\tid, err := result.LastInsertId()\n\tif err != nil {\n\t\td.cfg.Logger().Error(\"failed to retrieve id of last saved person. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn int(id), nil\n}\n\nfunc (d *DAO) getTracker() QueryTracker {\n\tif d.Tracker == nil {\n\t\td.Tracker = &noopTracker{}\n\t}\n\n\treturn d.Tracker\n}\n"
  },
  {
    "path": "ch12/acme/internal/modules/data/data.go",
    "content": "package data\n\nimport (\n\t\"database/sql\"\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/logging\"\n\t_ \"github.com/go-sql-driver/mysql\"\n)\n\nconst (\n\t// default person id (returned on error)\n\tdefaultPersonID = 0\n\n\t// SQL statements as constants (to reduce duplication and maintenance in tests)\n\tsqlAllColumns = \"id, fullname, phone, currency, price\"\n\tsqlInsert     = \"INSERT INTO person (fullname, phone, currency, price) VALUES (?, ?, ?, ?)\"\n\tsqlLoadAll    = \"SELECT \" + sqlAllColumns + \" FROM person\"\n\tsqlLoadByID   = \"SELECT \" + sqlAllColumns + \" FROM person WHERE id = ? LIMIT 1\"\n)\n\nvar (\n\tdb *sql.DB\n\n\t// ErrNotFound is returned when the no records where matched by the query\n\tErrNotFound = errors.New(\"not found\")\n)\n\n// Config is the configuration for the data package\ntype Config interface {\n\t// Logger returns a reference to the logger\n\tLogger() logging.Logger\n\n\t// DataDSN returns the data source name\n\tDataDSN() string\n}\n\nvar getDB = func(cfg Config) (*sql.DB, error) {\n\tif db == nil {\n\t\tvar err error\n\t\tdb, err = sql.Open(\"mysql\", cfg.DataDSN())\n\t\tif err != nil {\n\t\t\t// if the DB cannot be accessed we are dead\n\t\t\tpanic(err.Error())\n\t\t}\n\t}\n\n\treturn db, nil\n}\n\n// Person is the data transfer object (DTO) for this package\ntype Person struct {\n\t// ID is the unique ID for this person\n\tID int\n\t// FullName is the name of this person\n\tFullName string\n\t// Phone is the phone for this person\n\tPhone string\n\t// Currency is the currency this person has paid in\n\tCurrency string\n\t// Price is the amount (in the above currency) paid by this person\n\tPrice float64\n}\n\n// custom type so we can convert sql results to easily\ntype scanner func(dest ...interface{}) error\n\n// reduce the duplication (and maintenance) between sql.Row and sql.Rows usage\nfunc populatePerson(scanner scanner) (*Person, error) {\n\tout := &Person{}\n\terr := scanner(&out.ID, &out.FullName, &out.Phone, &out.Currency, &out.Price)\n\treturn out, err\n}\n"
  },
  {
    "path": "ch12/acme/internal/modules/data/data_test.go",
    "content": "package data\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"errors\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/DATA-DOG/go-sqlmock\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/logging\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestSave_happyPath(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\t// define a mock db\n\ttestDb, dbMock, err := sqlmock.New()\n\tdefer testDb.Close()\n\trequire.NoError(t, err)\n\n\t// configure the mock db\n\tqueryRegex := convertSQLToRegex(sqlInsert)\n\tdbMock.ExpectExec(queryRegex).WillReturnResult(sqlmock.NewResult(2, 1))\n\n\t// monkey patching starts here\n\tdb = testDb\n\t// end of monkey patch\n\n\t// inputs\n\tin := &Person{\n\t\tFullName: \"Jake Blues\",\n\t\tPhone:    \"01234567890\",\n\t\tCurrency: \"AUD\",\n\t\tPrice:    123.45,\n\t}\n\n\t// call function\n\tdao := NewDAO(&testConfig{})\n\tresultID, err := dao.Save(ctx, in)\n\n\t// validate result\n\trequire.NoError(t, err)\n\tassert.Equal(t, 2, resultID)\n\tassert.NoError(t, dbMock.ExpectationsWereMet())\n}\n\nfunc TestSave_insertError(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\t// define a mock db\n\ttestDb, dbMock, err := sqlmock.New()\n\tdefer testDb.Close()\n\n\trequire.NoError(t, err)\n\n\t// configure the mock db\n\tqueryRegex := convertSQLToRegex(sqlInsert)\n\tdbMock.ExpectExec(queryRegex).WillReturnError(errors.New(\"failed to insert\"))\n\n\t// monkey patching starts here\n\tdb = testDb\n\t// end of monkey patch\n\n\t// inputs\n\tin := &Person{\n\t\tFullName: \"Jake Blues\",\n\t\tPhone:    \"01234567890\",\n\t\tCurrency: \"AUD\",\n\t\tPrice:    123.45,\n\t}\n\n\t// call function\n\tdao := NewDAO(&testConfig{})\n\tresultID, err := dao.Save(ctx, in)\n\n\t// validate result\n\trequire.Error(t, err)\n\tassert.Equal(t, defaultPersonID, resultID)\n\tassert.NoError(t, dbMock.ExpectationsWereMet())\n}\n\nfunc TestSave_getDBError(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\t// monkey patching starts here\n\tdefer func(original func(_ Config) (*sql.DB, error)) {\n\t\t// restore original DB (after test)\n\t\tgetDB = original\n\t}(getDB)\n\n\t// replace getDB() function for this test\n\tgetDB = func(_ Config) (*sql.DB, error) {\n\t\treturn nil, errors.New(\"getDB() failed\")\n\t}\n\t// end of monkey patch\n\n\t// inputs\n\tin := &Person{\n\t\tFullName: \"Jake Blues\",\n\t\tPhone:    \"01234567890\",\n\t\tCurrency: \"AUD\",\n\t\tPrice:    123.45,\n\t}\n\n\t// call function\n\tdao := NewDAO(&testConfig{})\n\tresultID, err := dao.Save(ctx, in)\n\trequire.Error(t, err)\n\tassert.Equal(t, defaultPersonID, resultID)\n}\n\nfunc TestLoadAll_tableDrivenTest(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\n\tdefer cancel()\n\n\tscenarios := []struct {\n\t\tdesc            string\n\t\tconfigureMockDB func(sqlmock.Sqlmock)\n\t\texpectedResults []*Person\n\t\texpectError     bool\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tconfigureMockDB: func(dbMock sqlmock.Sqlmock) {\n\t\t\t\tqueryRegex := convertSQLToRegex(sqlLoadAll)\n\t\t\t\tdbMock.ExpectQuery(queryRegex).WillReturnRows(\n\t\t\t\t\tsqlmock.NewRows(strings.Split(sqlAllColumns, \", \")).\n\t\t\t\t\t\tAddRow(1, \"John\", \"0123456789\", \"AUD\", 12.34))\n\t\t\t},\n\t\t\texpectedResults: []*Person{\n\t\t\t\t{\n\t\t\t\t\tID:       1,\n\t\t\t\t\tFullName: \"John\",\n\t\t\t\t\tPhone:    \"0123456789\",\n\t\t\t\t\tCurrency: \"AUD\",\n\t\t\t\t\tPrice:    12.34,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tdesc: \"load error\",\n\t\t\tconfigureMockDB: func(dbMock sqlmock.Sqlmock) {\n\t\t\t\tqueryRegex := convertSQLToRegex(sqlLoadAll)\n\t\t\t\tdbMock.ExpectQuery(queryRegex).WillReturnError(errors.New(\"something failed\"))\n\t\t\t},\n\t\t\texpectedResults: nil,\n\t\t\texpectError:     true,\n\t\t},\n\t}\n\n\tfor _, scenario := range scenarios {\n\t\t// define a mock db\n\t\ttestDb, dbMock, err := sqlmock.New()\n\t\trequire.NoError(t, err)\n\n\t\t// configure the mock db\n\t\tscenario.configureMockDB(dbMock)\n\n\t\t// monkey patch the db for this test\n\t\toriginal := *db\n\t\tdb = testDb\n\n\t\t// call function\n\t\tdao := NewDAO(&testConfig{})\n\t\tresults, err := dao.LoadAll(ctx)\n\n\t\t// validate results\n\t\tassert.Equal(t, scenario.expectedResults, results, scenario.desc)\n\t\tassert.Equal(t, scenario.expectError, err != nil, scenario.desc)\n\t\tassert.NoError(t, dbMock.ExpectationsWereMet())\n\n\t\t// restore original DB (after test)\n\t\tdb = &original\n\t\ttestDb.Close()\n\t}\n}\n\nfunc TestLoad_tableDrivenTest(t *testing.T) {\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\n\tdefer cancel()\n\n\tscenarios := []struct {\n\t\tdesc            string\n\t\tconfigureMockDB func(sqlmock.Sqlmock)\n\t\texpectedResult  *Person\n\t\texpectError     bool\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tconfigureMockDB: func(dbMock sqlmock.Sqlmock) {\n\t\t\t\tqueryRegex := convertSQLToRegex(sqlLoadAll)\n\t\t\t\tdbMock.ExpectQuery(queryRegex).WillReturnRows(\n\t\t\t\t\tsqlmock.NewRows(strings.Split(sqlAllColumns, \", \")).\n\t\t\t\t\t\tAddRow(2, \"Paul\", \"0123456789\", \"CAD\", 23.45))\n\t\t\t},\n\t\t\texpectedResult: &Person{\n\t\t\t\tID:       2,\n\t\t\t\tFullName: \"Paul\",\n\t\t\t\tPhone:    \"0123456789\",\n\t\t\t\tCurrency: \"CAD\",\n\t\t\t\tPrice:    23.45,\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tdesc: \"load error\",\n\t\t\tconfigureMockDB: func(dbMock sqlmock.Sqlmock) {\n\t\t\t\tqueryRegex := convertSQLToRegex(sqlLoadAll)\n\t\t\t\tdbMock.ExpectQuery(queryRegex).WillReturnError(errors.New(\"something failed\"))\n\t\t\t},\n\t\t\texpectedResult: nil,\n\t\t\texpectError:    true,\n\t\t},\n\t}\n\n\tfor _, scenario := range scenarios {\n\t\t// define a mock db\n\t\ttestDb, dbMock, err := sqlmock.New()\n\t\trequire.NoError(t, err)\n\n\t\t// configure the mock db\n\t\tscenario.configureMockDB(dbMock)\n\n\t\t// monkey db for this test\n\t\toriginal := *db\n\t\tdb = testDb\n\n\t\t// call function\n\t\tdao := NewDAO(&testConfig{})\n\t\tresult, err := dao.Load(ctx, 2)\n\n\t\t// validate results\n\t\tassert.Equal(t, scenario.expectedResult, result, scenario.desc)\n\t\tassert.Equal(t, scenario.expectError, err != nil, scenario.desc)\n\t\tassert.NoError(t, dbMock.ExpectationsWereMet())\n\n\t\t// restore original DB (after test)\n\t\tdb = &original\n\t\ttestDb.Close()\n\t}\n}\n\n// convert SQL string to regex by treating the entire query as a literal\nfunc convertSQLToRegex(in string) string {\n\treturn `\\Q` + in + `\\E`\n}\n\ntype testConfig struct{}\n\n// Logger implements Config\nfunc (t *testConfig) Logger() logging.Logger {\n\treturn logging.LoggerStdOut{}\n}\n\n// DataDSN implements Config\nfunc (t *testConfig) DataDSN() string {\n\treturn \"\"\n}\n"
  },
  {
    "path": "ch12/acme/internal/modules/data/tracker.go",
    "content": "package data\n\nimport (\n\t\"time\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/logging\"\n)\n\n// QueryTracker is an interface to track query timing\ntype QueryTracker interface {\n\t// Track will record/out the time a query took by calculating time.Now().Sub(start)\n\tTrack(key string, start time.Time)\n}\n\n// NO-OP implementation of QueryTracker\ntype noopTracker struct{}\n\n// Track implements QueryTracker\nfunc (_ *noopTracker) Track(_ string, _ time.Time) {\n\t// intentionally does nothing\n}\n\n// NewLogTracker returns a Tracker that outputs tracking data to log\nfunc NewLogTracker(logger logging.Logger) *LogTracker {\n\treturn &LogTracker{\n\t\tlogger: logger,\n\t}\n}\n\n// LogTracker implements QueryTracker and outputs to the supplied logger\ntype LogTracker struct {\n\tlogger logging.Logger\n}\n\n// Track implements QueryTracker\nfunc (l *LogTracker) Track(key string, start time.Time) {\n\tl.logger.Info(\"[%s] Timing: %s\\n\", key, time.Now().Sub(start).String())\n}\n"
  },
  {
    "path": "ch12/acme/internal/modules/exchange/converter.go",
    "content": "package exchange\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"math\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/logging\"\n)\n\nconst (\n\t// request URL for the exchange rate API\n\turlFormat = \"%s/api/historical?access_key=%s&date=2018-06-20&currencies=%s\"\n\n\t// default price that is sent when an error occurs\n\tdefaultPrice = 0.0\n)\n\n// NewConverter creates and initializes the converter\nfunc NewConverter(cfg Config) *Converter {\n\treturn &Converter{\n\t\tcfg: cfg,\n\t}\n}\n\n// Config is the config for Converter\ntype Config interface {\n\tLogger() logging.Logger\n\tExchangeBaseURL() string\n\tExchangeAPIKey() string\n}\n\n// Converter will convert the base price to the currency supplied\n// Note: we are expecting sane inputs and therefore skipping input validation\ntype Converter struct {\n\tcfg Config\n}\n\n// Exchange will perform the conversion\nfunc (c *Converter) Exchange(ctx context.Context, basePrice float64, currency string) (float64, error) {\n\t// load rate from the external API\n\tresponse, err := c.loadRateFromServer(ctx, currency)\n\tif err != nil {\n\t\treturn defaultPrice, err\n\t}\n\n\t// extract rate from response\n\trate, err := c.extractRate(response, currency)\n\tif err != nil {\n\t\treturn defaultPrice, err\n\t}\n\n\t// apply rate and round to 2 decimal places\n\treturn math.Floor((basePrice/rate)*100) / 100, nil\n}\n\n// load rate from the external API\nfunc (c *Converter) loadRateFromServer(ctx context.Context, currency string) (*http.Response, error) {\n\t// build the request\n\turl := fmt.Sprintf(urlFormat,\n\t\tc.cfg.ExchangeBaseURL(),\n\t\tc.cfg.ExchangeAPIKey(),\n\t\tcurrency)\n\n\t// perform request\n\treq, err := http.NewRequest(\"GET\", url, nil)\n\tif err != nil {\n\t\tc.logger().Warn(\"[exchange] failed to create request. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// set latency budget for the upstream call\n\tsubCtx, cancel := context.WithTimeout(ctx, 1*time.Second)\n\tdefer cancel()\n\n\t// replace the default context with our custom one\n\treq = req.WithContext(subCtx)\n\n\t// perform the HTTP request\n\tresponse, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tc.logger().Warn(\"[exchange] failed to load. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\tif response.StatusCode != http.StatusOK {\n\t\terr = fmt.Errorf(\"request failed with code %d\", response.StatusCode)\n\t\tc.logger().Warn(\"[exchange] %s\", err)\n\t\treturn nil, err\n\t}\n\n\treturn response, nil\n}\n\nfunc (c *Converter) extractRate(response *http.Response, currency string) (float64, error) {\n\tdefer func() {\n\t\t_ = response.Body.Close()\n\t}()\n\n\t// extract data from response\n\tdata, err := c.extractResponse(response)\n\tif err != nil {\n\t\treturn defaultPrice, err\n\t}\n\n\t// pull rate from response data\n\trate, found := data.Quotes[\"USD\"+currency]\n\tif !found {\n\t\terr = fmt.Errorf(\"response did not include expected currency '%s'\", currency)\n\t\tc.logger().Error(\"[exchange] %s\", err)\n\t\treturn defaultPrice, err\n\t}\n\n\t// happy path\n\treturn rate, nil\n}\n\nfunc (c *Converter) extractResponse(response *http.Response) (*apiResponseFormat, error) {\n\tpayload, err := ioutil.ReadAll(response.Body)\n\tif err != nil {\n\t\tc.logger().Error(\"[exchange] failed to ready response body. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\tdata := &apiResponseFormat{}\n\terr = json.Unmarshal(payload, data)\n\tif err != nil {\n\t\tc.logger().Error(\"[exchange] error converting response. err: %s\", err)\n\t\treturn nil, err\n\t}\n\n\t// happy path\n\treturn data, nil\n}\n\nfunc (c *Converter) logger() logging.Logger {\n\treturn c.cfg.Logger()\n}\n\n// the response format from the exchange rate API\ntype apiResponseFormat struct {\n\tQuotes map[string]float64 `json:\"quotes\"`\n}\n"
  },
  {
    "path": "ch12/acme/internal/modules/exchange/converter_ext_bounday_test.go",
    "content": "// +build external\n\npackage exchange\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/config\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestExternalBoundaryTest(t *testing.T) {\n\t// define the config\n\tcfg, err := config.Load()\n\trequire.NoError(t, err)\n\n\t// create a converter to test\n\tconverter := NewConverter(cfg)\n\n\t// fetch from the server\n\tresponse, err := converter.loadRateFromServer(context.Background(), \"AUD\")\n\trequire.NotNil(t, response)\n\trequire.NoError(t, err)\n\n\t// parse the response\n\tresultRate, err := converter.extractRate(response, \"AUD\")\n\trequire.NoError(t, err)\n\n\t// validate the result\n\tassert.True(t, resultRate > 0)\n}\n"
  },
  {
    "path": "ch12/acme/internal/modules/exchange/converter_int_bounday_test.go",
    "content": "package exchange\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/logging\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestInternalBoundaryTest(t *testing.T) {\n\t// start our test server\n\tserver := httptest.NewServer(&happyExchangeRateService{})\n\tdefer server.Close()\n\n\t// define the config\n\tcfg := &testConfig{\n\t\tbaseURL: server.URL,\n\t\tapiKey:  \"\",\n\t}\n\n\t// create a converter to test\n\tconverter := NewConverter(cfg)\n\tresultRate, resultErr := converter.Exchange(context.Background(), 100.00, \"AUD\")\n\n\t// validate the result\n\tassert.Equal(t, 101.01, resultRate)\n\tassert.NoError(t, resultErr)\n}\n\ntype happyExchangeRateService struct{}\n\n// ServeHTTP implements http.Handler\nfunc (*happyExchangeRateService) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\tpayload := []byte(`\n{\n   \"success\":true,\n   \"historical\":true,\n   \"date\":\"2010-11-09\",\n   \"timestamp\":1289347199,\n   \"source\":\"USD\",\n   \"quotes\":{\n      \"USDAUD\":0.989981\n   }\n}`)\n\tresponse.Write(payload)\n}\n\nfunc TestExchange_invalidResponseFromServer(t *testing.T) {\n\t// start our test server\n\tserver := httptest.NewServer(http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) {\n\t\tpayload := []byte(`invalid payload`)\n\t\tresponse.Write(payload)\n\t}))\n\tdefer server.Close()\n\n\t// inputs\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\tbasePrice := 12.34\n\tcurrency := \"AUD\"\n\n\tcfg := &testConfig{\n\t\tbaseURL: server.URL,\n\t\tapiKey:  \"\",\n\t}\n\n\t// create a converter to test\n\tconverter := NewConverter(cfg)\n\tresult, resultErr := converter.Exchange(ctx, basePrice, currency)\n\n\t// validate response\n\tassert.Equal(t, float64(0), result)\n\tassert.Error(t, resultErr)\n}\n\n// test implementation of Config\ntype testConfig struct {\n\tbaseURL string\n\tapiKey  string\n}\n\n// Logger implements Config\nfunc (t *testConfig) Logger() logging.Logger {\n\treturn &logging.LoggerStdOut{}\n}\n\n// ExchangeBaseURL implements Config\nfunc (t *testConfig) ExchangeBaseURL() string {\n\treturn t.baseURL\n}\n\n// ExchangeAPIKey implements Config\nfunc (t *testConfig) ExchangeAPIKey() string {\n\treturn t.apiKey\n}\n"
  },
  {
    "path": "ch12/acme/internal/modules/get/get.go",
    "content": "package get\n\nimport (\n\t\"context\"\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/data\"\n)\n\nvar (\n\t// error thrown when the requested person is not in the database\n\terrPersonNotFound = errors.New(\"person not found\")\n)\n\n// NewGetter creates and initializes a Getter\nfunc NewGetter(cfg Config) *Getter {\n\treturn &Getter{\n\t\tcfg: cfg,\n\t}\n}\n\n// Config is the configuration for Getter\ntype Config interface {\n\tLogger() logging.Logger\n\tDataDSN() string\n}\n\n// Getter will attempt to load a person.\n// It can return an error caused by the data layer or when the requested person is not found\ntype Getter struct {\n\tcfg  Config\n\tdata myLoader\n}\n\n// Do will perform the get\nfunc (g *Getter) Do(ID int) (*Person, error) {\n\t// load person from the data layer\n\tperson, err := g.getLoader().Load(context.TODO(), ID)\n\tif err != nil {\n\t\tif err == data.ErrNotFound {\n\t\t\t// By converting the error we are hiding the implementation details from our users.\n\t\t\treturn nil, errPersonNotFound\n\t\t}\n\t\treturn nil, err\n\t}\n\n\treturn g.convert(person), err\n}\n\nfunc (g *Getter) getLoader() myLoader {\n\tif g.data == nil {\n\t\tg.data = data.NewDAO(g.cfg)\n\t}\n\n\treturn g.data\n}\n\nfunc (g *Getter) convert(in *data.Person) *Person {\n\treturn &Person{\n\t\tID:       in.ID,\n\t\tCurrency: in.Currency,\n\t\tFullName: in.FullName,\n\t\tPhone:    in.Phone,\n\t\tPrice:    in.Price,\n\t}\n}\n\n//go:generate mockery -name=myLoader -case underscore -testonly -inpkg -note @generated\ntype myLoader interface {\n\tLoad(ctx context.Context, ID int) (*data.Person, error)\n}\n\n// Person is a copy/sub-set of data.Person so that the relationship does not leak.\n// It also allows us to remove/hide and internal fields\ntype Person struct {\n\tID       int\n\tFullName string\n\tPhone    string\n\tCurrency string\n\tPrice    float64\n}\n"
  },
  {
    "path": "ch12/acme/internal/modules/get/go_test.go",
    "content": "package get\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestGetter_Do_happyPath(t *testing.T) {\n\t// inputs\n\tID := 1234\n\n\t// configure the mock loader\n\tmockResult := &data.Person{\n\t\tID:       1234,\n\t\tFullName: \"Doug\",\n\t}\n\tmockLoader := &mockMyLoader{}\n\tmockLoader.On(\"Load\", mock.Anything, ID).Return(mockResult, nil).Once()\n\n\t// call method\n\tgetter := &Getter{\n\t\tdata: mockLoader,\n\t}\n\tperson, err := getter.Do(ID)\n\n\t// validate expectations\n\trequire.NoError(t, err)\n\tassert.Equal(t, ID, person.ID)\n\tassert.Equal(t, \"Doug\", person.FullName)\n\tassert.True(t, mockLoader.AssertExpectations(t))\n}\n\nfunc TestGetter_Do_noSuchPerson(t *testing.T) {\n\t// inputs\n\tID := 5678\n\n\t// configure the mock loader\n\tmockLoader := &mockMyLoader{}\n\tmockLoader.On(\"Load\", mock.Anything, ID).Return(nil, data.ErrNotFound).Once()\n\n\t// call method\n\tgetter := &Getter{\n\t\tdata: mockLoader,\n\t}\n\tperson, err := getter.Do(ID)\n\n\t// validate expectations\n\trequire.Equal(t, errPersonNotFound, err)\n\tassert.Nil(t, person)\n\tassert.True(t, mockLoader.AssertExpectations(t))\n}\n\nfunc TestGetter_Do_error(t *testing.T) {\n\t// inputs\n\tID := 1234\n\n\t// configure the mock loader\n\tmockLoader := &mockMyLoader{}\n\tmockLoader.On(\"Load\", mock.Anything, ID).Return(nil, errors.New(\"something failed\")).Once()\n\n\t// call method\n\tgetter := &Getter{\n\t\tdata: mockLoader,\n\t}\n\tperson, err := getter.Do(ID)\n\n\t// validate expectations\n\trequire.Error(t, err)\n\tassert.Nil(t, person)\n\tassert.True(t, mockLoader.AssertExpectations(t))\n}\n"
  },
  {
    "path": "ch12/acme/internal/modules/get/mock_my_loader_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage get\n\nimport (\n\t\"context\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// mockMyLoader is an autogenerated mock type for the myLoader type\ntype mockMyLoader struct {\n\tmock.Mock\n}\n\n// Load provides a mock function with given fields: ctx, ID\nfunc (_m *mockMyLoader) Load(ctx context.Context, ID int) (*data.Person, error) {\n\tret := _m.Called(ctx, ID)\n\n\tvar r0 *data.Person\n\tif rf, ok := ret.Get(0).(func(context.Context, int) *data.Person); ok {\n\t\tr0 = rf(ctx, ID)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*data.Person)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, int) error); ok {\n\t\tr1 = rf(ctx, ID)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch12/acme/internal/modules/list/list.go",
    "content": "package list\n\nimport (\n\t\"context\"\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/data\"\n)\n\nvar (\n\t// error thrown when there are no people in the database\n\terrPeopleNotFound = errors.New(\"no people found\")\n)\n\n// NewLister creates and initializes a Lister\nfunc NewLister(cfg Config) *Lister {\n\treturn &Lister{\n\t\tcfg: cfg,\n\t}\n}\n\n// Config is the config for Lister\ntype Config interface {\n\tLogger() logging.Logger\n\tDataDSN() string\n}\n\n// Lister will attempt to load all people in the database.\n// It can return an error caused by the data layer\ntype Lister struct {\n\tcfg  Config\n\tdata myLoader\n}\n\n// Exchange will load the people from the data layer\nfunc (l *Lister) Do() ([]*Person, error) {\n\t// load all people\n\tpeople, err := l.load()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(people) == 0 {\n\t\t// special processing for 0 people returned\n\t\treturn nil, errPeopleNotFound\n\t}\n\n\treturn l.convert(people), nil\n}\n\n// load all people\nfunc (l *Lister) load() ([]*data.Person, error) {\n\tpeople, err := l.getLoader().LoadAll(context.TODO())\n\tif err != nil {\n\t\tif err == data.ErrNotFound {\n\t\t\t// By converting the error we are encapsulating the implementation details from our users.\n\t\t\treturn nil, errPeopleNotFound\n\t\t}\n\t\treturn nil, err\n\t}\n\n\treturn people, nil\n}\n\nfunc (l *Lister) getLoader() myLoader {\n\tif l.data == nil {\n\t\tl.data = data.NewDAO(l.cfg)\n\n\t\t// temporarily add a log tracker\n\t\tl.data.(*data.DAO).Tracker = data.NewLogTracker(l.cfg.Logger())\n\t}\n\n\treturn l.data\n}\n\nfunc (l *Lister) convert(in []*data.Person) []*Person {\n\tout := make([]*Person, len(in))\n\n\tfor index, thisRecord := range in {\n\t\tout[index] = &Person{\n\t\t\tID:       thisRecord.ID,\n\t\t\tFullName: thisRecord.FullName,\n\t\t\tPhone:    thisRecord.Phone,\n\t\t}\n\t}\n\n\treturn out\n}\n\n//go:generate mockery -name=myLoader -case underscore -testonly -inpkg -note @generated\ntype myLoader interface {\n\tLoadAll(ctx context.Context) ([]*data.Person, error)\n}\n\n// Person is a copy/sub-set of data.Person so that the relationship does not leak.\n// It also allows us to remove/hide and internal fields\ntype Person struct {\n\tID       int\n\tFullName string\n\tPhone    string\n}\n"
  },
  {
    "path": "ch12/acme/internal/modules/list/list_test.go",
    "content": "package list\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestLister_Do_happyPath(t *testing.T) {\n\t// configure the mock loader\n\tmockResult := []*data.Person{\n\t\t{\n\t\t\tID:       1234,\n\t\t\tFullName: \"Sally\",\n\t\t},\n\t\t{\n\t\t\tID:       5678,\n\t\t\tFullName: \"Jane\",\n\t\t},\n\t}\n\n\tmockLoader := &mockMyLoader{}\n\tmockLoader.On(\"LoadAll\", mock.Anything).Return(mockResult, nil).Once()\n\n\t// call method\n\tlister := &Lister{\n\t\tdata: mockLoader,\n\t}\n\tpersons, err := lister.load()\n\n\t// validate expectations\n\trequire.NoError(t, err)\n\tassert.Equal(t, 2, len(persons))\n\tassert.True(t, mockLoader.AssertExpectations(t))\n}\n\nfunc TestLister_Do_noResults(t *testing.T) {\n\t// configure the mock loader\n\tmockLoader := &mockMyLoader{}\n\tmockLoader.On(\"LoadAll\", mock.Anything).Return(nil, data.ErrNotFound).Once()\n\n\t// call method\n\tlister := &Lister{\n\t\tdata: mockLoader,\n\t}\n\tpersons, err := lister.load()\n\n\t// validate expectations\n\trequire.Equal(t, errPeopleNotFound, err)\n\tassert.Equal(t, 0, len(persons))\n\tassert.True(t, mockLoader.AssertExpectations(t))\n}\n\nfunc TestLister_Do_error(t *testing.T) {\n\t// configure the mock loader\n\tmockLoader := &mockMyLoader{}\n\tmockLoader.On(\"LoadAll\", mock.Anything).Return(nil, errors.New(\"something failed\")).Once()\n\n\t// call method\n\tlister := &Lister{\n\t\tdata: mockLoader,\n\t}\n\tpersons, err := lister.load()\n\n\t// validate expectations\n\trequire.Error(t, err)\n\tassert.Equal(t, 0, len(persons))\n\tassert.True(t, mockLoader.AssertExpectations(t))\n}\n"
  },
  {
    "path": "ch12/acme/internal/modules/list/mock_my_loader_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage list\n\nimport (\n\t\"context\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// mockMyLoader is an autogenerated mock type for the myLoader type\ntype mockMyLoader struct {\n\tmock.Mock\n}\n\n// LoadAll provides a mock function with given fields: ctx\nfunc (_m *mockMyLoader) LoadAll(ctx context.Context) ([]*data.Person, error) {\n\tret := _m.Called(ctx)\n\n\tvar r0 []*data.Person\n\tif rf, ok := ret.Get(0).(func(context.Context) []*data.Person); ok {\n\t\tr0 = rf(ctx)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]*data.Person)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context) error); ok {\n\t\tr1 = rf(ctx)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch12/acme/internal/modules/register/mock_exchanger_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage register\n\nimport (\n\t\"context\"\n\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// MockExchanger is an autogenerated mock type for the Exchanger type\ntype MockExchanger struct {\n\tmock.Mock\n}\n\n// Exchange provides a mock function with given fields: ctx, basePrice, currency\nfunc (_m *MockExchanger) Exchange(ctx context.Context, basePrice float64, currency string) (float64, error) {\n\tret := _m.Called(ctx, basePrice, currency)\n\n\tvar r0 float64\n\tif rf, ok := ret.Get(0).(func(context.Context, float64, string) float64); ok {\n\t\tr0 = rf(ctx, basePrice, currency)\n\t} else {\n\t\tr0 = ret.Get(0).(float64)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, float64, string) error); ok {\n\t\tr1 = rf(ctx, basePrice, currency)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch12/acme/internal/modules/register/mock_my_saver_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage register\n\nimport (\n\t\"context\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/data\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// mockMySaver is an autogenerated mock type for the mySaver type\ntype mockMySaver struct {\n\tmock.Mock\n}\n\n// Save provides a mock function with given fields: ctx, in\nfunc (_m *mockMySaver) Save(ctx context.Context, in *data.Person) (int, error) {\n\tret := _m.Called(ctx, in)\n\n\tvar r0 int\n\tif rf, ok := ret.Get(0).(func(context.Context, *data.Person) int); ok {\n\t\tr0 = rf(ctx, in)\n\t} else {\n\t\tr0 = ret.Get(0).(int)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, *data.Person) error); ok {\n\t\tr1 = rf(ctx, in)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch12/acme/internal/modules/register/register.go",
    "content": "package register\n\nimport (\n\t\"context\"\n\t\"errors\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/data\"\n)\n\nconst (\n\t// default person id (returned on error)\n\tdefaultPersonID = 0\n)\n\nvar (\n\t// validation errors\n\terrNameMissing     = errors.New(\"name is missing\")\n\terrPhoneMissing    = errors.New(\"phone is missing\")\n\terrCurrencyMissing = errors.New(\"currency is missing\")\n\terrInvalidCurrency = errors.New(\"currency is invalid, supported types are AUD, CNY, EUR, GBP, JPY, MYR, SGD, USD\")\n\n\t// a little trick to make checking for supported currencies easier\n\tsupportedCurrencies = map[string]struct{}{\n\t\t\"AUD\": {},\n\t\t\"CNY\": {},\n\t\t\"EUR\": {},\n\t\t\"GBP\": {},\n\t\t\"JPY\": {},\n\t\t\"MYR\": {},\n\t\t\"SGD\": {},\n\t\t\"USD\": {},\n\t}\n)\n\n// NewRegisterer creates and initializes a Registerer\nfunc NewRegisterer(cfg Config, exchanger Exchanger) *Registerer {\n\treturn &Registerer{\n\t\tcfg:       cfg,\n\t\texchanger: exchanger,\n\t}\n}\n\n// Exchanger will convert from one currency to another\n//go:generate mockery -name=Exchanger -case underscore -testonly -inpkg -note @generated\ntype Exchanger interface {\n\t// Exchange will perform the conversion\n\tExchange(ctx context.Context, basePrice float64, currency string) (float64, error)\n}\n\n// Config is the configuration for the Registerer\ntype Config interface {\n\tLogger() logging.Logger\n\tRegistrationBasePrice() float64\n\tDataDSN() string\n}\n\n// Registerer validates the supplied person, calculates the price in the requested currency and saves the result.\n// It will return an error when:\n// -the person object does not include all the fields\n// -the currency is invalid\n// -the exchange rate cannot be loaded\n// -the data layer throws an error.\ntype Registerer struct {\n\tcfg       Config\n\texchanger Exchanger\n\tdata      mySaver\n}\n\n// Do is API for this struct\nfunc (r *Registerer) Do(ctx context.Context, in *Person) (int, error) {\n\t// validate the request\n\terr := r.validateInput(in)\n\tif err != nil {\n\t\tr.logger().Warn(\"input validation failed with err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\t// get price in the requested currency\n\tprice, err := r.getPrice(ctx, in.Currency)\n\tif err != nil {\n\t\treturn defaultPersonID, err\n\t}\n\n\t// save registration\n\tid, err := r.save(ctx, r.convert(in), price)\n\tif err != nil {\n\t\t// no need to log here as we expect the data layer to do so\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn id, nil\n}\n\n// validate input and return error on fail\nfunc (r *Registerer) validateInput(in *Person) error {\n\tif in.FullName == \"\" {\n\t\treturn errNameMissing\n\t}\n\tif in.Phone == \"\" {\n\t\treturn errPhoneMissing\n\t}\n\tif in.Currency == \"\" {\n\t\treturn errCurrencyMissing\n\t}\n\n\tif _, found := supportedCurrencies[in.Currency]; !found {\n\t\treturn errInvalidCurrency\n\t}\n\n\t// happy path\n\treturn nil\n}\n\n// get price in the requested currency\nfunc (r *Registerer) getPrice(ctx context.Context, currency string) (float64, error) {\n\tprice, err := r.exchanger.Exchange(ctx, r.cfg.RegistrationBasePrice(), currency)\n\tif err != nil {\n\t\tr.logger().Warn(\"failed to convert the price. err: %s\", err)\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn price, nil\n}\n\n// save the registration\nfunc (r *Registerer) save(ctx context.Context, in *data.Person, price float64) (int, error) {\n\tperson := &data.Person{\n\t\tFullName: in.FullName,\n\t\tPhone:    in.Phone,\n\t\tCurrency: in.Currency,\n\t\tPrice:    price,\n\t}\n\treturn r.getSaver().Save(ctx, person)\n}\n\nfunc (r *Registerer) getSaver() mySaver {\n\tif r.data == nil {\n\t\tr.data = data.NewDAO(r.cfg)\n\t}\n\n\treturn r.data\n}\n\nfunc (r *Registerer) logger() logging.Logger {\n\treturn r.cfg.Logger()\n}\n\nfunc (r *Registerer) convert(in *Person) *data.Person {\n\treturn &data.Person{\n\t\tID:       in.ID,\n\t\tCurrency: in.Currency,\n\t\tFullName: in.FullName,\n\t\tPhone:    in.Phone,\n\t\tPrice:    in.Price,\n\t}\n}\n\n//go:generate mockery -name=mySaver -case underscore -testonly -inpkg -note @generated\ntype mySaver interface {\n\tSave(ctx context.Context, in *data.Person) (int, error)\n}\n\n// Person is a copy/sub-set of data.Person so that the relationship does not leak.\n// It also allows us to remove/hide and internal fields\ntype Person struct {\n\tID       int\n\tFullName string\n\tPhone    string\n\tCurrency string\n\tPrice    float64\n}\n"
  },
  {
    "path": "ch12/acme/internal/modules/register/register_test.go",
    "content": "package register\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/logging\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestRegisterer_Do_happyPath(t *testing.T) {\n\t// configure the mock saver\n\tmockResult := 888\n\n\tmockSaver := &mockMySaver{}\n\tmockSaver.On(\"Save\", mock.Anything, mock.Anything).Return(mockResult, nil).Once()\n\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\t// inputs\n\tin := &Person{\n\t\tFullName: \"Chang\",\n\t\tPhone:    \"11122233355\",\n\t\tCurrency: \"CNY\",\n\t}\n\n\t// call method\n\tregisterer := &Registerer{\n\t\tcfg:       &testConfig{},\n\t\texchanger: &stubExchanger{},\n\t\tdata:      mockSaver,\n\t}\n\tID, err := registerer.Do(ctx, in)\n\n\t// validate expectations\n\trequire.NoError(t, err)\n\tassert.Equal(t, 888, ID)\n\tassert.True(t, mockSaver.AssertExpectations(t))\n}\n\nfunc TestRegisterer_Do_error(t *testing.T) {\n\t// configure the mock saver\n\tmockSaver := &mockMySaver{}\n\tmockSaver.On(\"Save\", mock.Anything, mock.Anything).Return(0, errors.New(\"something failed\")).Once()\n\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\t// inputs\n\tin := &Person{\n\t\tFullName: \"Chang\",\n\t\tPhone:    \"11122233355\",\n\t\tCurrency: \"CNY\",\n\t}\n\n\t// call method\n\tregisterer := &Registerer{\n\t\tcfg:       &testConfig{},\n\t\texchanger: &stubExchanger{},\n\t\tdata:      mockSaver,\n\t}\n\tID, err := registerer.Do(ctx, in)\n\n\t// validate expectations\n\trequire.Error(t, err)\n\tassert.Equal(t, 0, ID)\n\tassert.True(t, mockSaver.AssertExpectations(t))\n}\n\nfunc TestRegisterer_Do_exchangeError(t *testing.T) {\n\t// configure the mocks\n\tmockSaver := &mockMySaver{}\n\tmockExchanger := &MockExchanger{}\n\tmockExchanger.\n\t\tOn(\"Exchange\", mock.Anything, mock.Anything, mock.Anything).\n\t\tReturn(0.0, errors.New(\"failed to load conversion\")).\n\t\tOnce()\n\n\t// define context and therefore test timeout\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)\n\tdefer cancel()\n\n\t// inputs\n\tin := &Person{\n\t\tFullName: \"Chang\",\n\t\tPhone:    \"11122233355\",\n\t\tCurrency: \"CNY\",\n\t}\n\n\t// call method\n\tregisterer := &Registerer{\n\t\tcfg:       &testConfig{},\n\t\texchanger: mockExchanger,\n\t\tdata:      mockSaver,\n\t}\n\tID, err := registerer.Do(ctx, in)\n\n\t// validate expectations\n\trequire.Error(t, err)\n\tassert.Equal(t, 0, ID)\n\tassert.True(t, mockSaver.AssertExpectations(t))\n\tassert.True(t, mockExchanger.AssertExpectations(t))\n}\n\n// Stub implementation of Config\ntype testConfig struct{}\n\n// Logger implement Config\nfunc (t *testConfig) Logger() logging.Logger {\n\treturn &logging.LoggerStdOut{}\n}\n\n// RegistrationBasePrice implement Config\nfunc (t *testConfig) RegistrationBasePrice() float64 {\n\treturn 12.34\n}\n\n// DataDSN implements Config\nfunc (t *testConfig) DataDSN() string {\n\treturn \"\"\n}\n\ntype stubExchanger struct{}\n\n// Exchange implements Exchanger\nfunc (s stubExchanger) Exchange(ctx context.Context, basePrice float64, currency string) (float64, error) {\n\treturn 12.34, nil\n}\n"
  },
  {
    "path": "ch12/acme/internal/rest/get.go",
    "content": "package rest\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/get\"\n\t\"github.com/gorilla/mux\"\n)\n\nconst (\n\t// default person id (returned on error)\n\tdefaultPersonID = 0\n\n\t// key in the mux where the ID is stored\n\tmuxVarID = \"id\"\n)\n\n// GetModel will load a registration\n//go:generate mockery -name=GetModel -case underscore -testonly -inpkg -note @generated\ntype GetModel interface {\n\tDo(ID int) (*get.Person, error)\n}\n\n// GetConfig is the config for the Get Handler\ntype GetConfig interface {\n\tLogger() logging.Logger\n}\n\n// NewGetHandler is the constructor for GetHandler\nfunc NewGetHandler(cfg GetConfig, model GetModel) *GetHandler {\n\treturn &GetHandler{\n\t\tcfg:    cfg,\n\t\tgetter: model,\n\t}\n}\n\n// GetHandler is the HTTP handler for the \"Get Person\" endpoint\n// In this simplified example we are assuming all possible errors are user errors and returning \"bad request\" HTTP 400\n// or \"not found\" HTTP 404\n// There are some programmer errors possible but hopefully these will be caught in testing.\ntype GetHandler struct {\n\tcfg    GetConfig\n\tgetter GetModel\n}\n\n// ServeHTTP implements http.Handler\nfunc (h *GetHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\t// extract person id from request\n\tid, err := h.extractID(request)\n\tif err != nil {\n\t\t// output error\n\t\tresponse.WriteHeader(http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// attempt get\n\tperson, err := h.getter.Do(id)\n\tif err != nil {\n\t\t// not need to log here as we can expect other layers to do so\n\t\tresponse.WriteHeader(http.StatusNotFound)\n\t\treturn\n\t}\n\n\t// happy path\n\terr = h.writeJSON(response, person)\n\tif err != nil {\n\t\t// this error should not happen but if it does there is nothing we can do to recover\n\t\tresponse.WriteHeader(http.StatusInternalServerError)\n\t}\n}\n\n// extract the person ID from the request\nfunc (h *GetHandler) extractID(request *http.Request) (int, error) {\n\t// ID is part of the URL, so we extract it from there\n\tvars := mux.Vars(request)\n\tidAsString, exists := vars[muxVarID]\n\tif !exists {\n\t\t// log and return error\n\t\terr := errors.New(\"[get] person id missing from request\")\n\t\th.cfg.Logger().Warn(err.Error())\n\t\treturn defaultPersonID, err\n\t}\n\n\t// convert ID to int\n\tid, err := strconv.Atoi(idAsString)\n\tif err != nil {\n\t\t// log and return error\n\t\terr = fmt.Errorf(\"[get] failed to convert person id into a number. err: %s\", err)\n\t\th.cfg.Logger().Error(err.Error())\n\t\treturn defaultPersonID, err\n\t}\n\n\treturn id, nil\n}\n\n// output the supplied person as JSON\nfunc (h *GetHandler) writeJSON(writer io.Writer, person *get.Person) error {\n\toutput := &getResponseFormat{\n\t\tID:       person.ID,\n\t\tFullName: person.FullName,\n\t\tPhone:    person.Phone,\n\t\tCurrency: person.Currency,\n\t\tPrice:    person.Price,\n\t}\n\n\t// call to http.ResponseWriter.Write() will cause HTTP OK (200) to be output as well\n\treturn json.NewEncoder(writer).Encode(output)\n}\n\n// the JSON response format\ntype getResponseFormat struct {\n\tID       int     `json:\"id\"`\n\tFullName string  `json:\"name\"`\n\tPhone    string  `json:\"phone\"`\n\tCurrency string  `json:\"currency\"`\n\tPrice    float64 `json:\"price\"`\n}\n"
  },
  {
    "path": "ch12/acme/internal/rest/get_test.go",
    "content": "package rest\n\nimport (\n\t\"errors\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/logging\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/get\"\n\t\"github.com/gorilla/mux\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestGetHandler_ServeHTTP(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc            string\n\t\tinRequest       func() *http.Request\n\t\tinModelMock     func() *MockGetModel\n\t\texpectedStatus  int\n\t\texpectedPayload string\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/1/\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// set values into request (required by the mux)\n\t\t\t\treturn mux.SetURLVars(req, map[string]string{muxVarID: \"1\"})\n\t\t\t},\n\t\t\tinModelMock: func() *MockGetModel {\n\t\t\t\toutput := &get.Person{\n\t\t\t\t\tID:       1,\n\t\t\t\t\tFullName: \"John\",\n\t\t\t\t\tPhone:    \"0123456789\",\n\t\t\t\t\tCurrency: \"USD\",\n\t\t\t\t\tPrice:    100,\n\t\t\t\t}\n\n\t\t\t\tmockGetModel := &MockGetModel{}\n\t\t\t\tmockGetModel.On(\"Do\", mock.Anything).Return(output, nil).Once()\n\n\t\t\t\treturn mockGetModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusOK,\n\t\t\texpectedPayload: `{\"id\":1,\"name\":\"John\",\"phone\":\"0123456789\",\"currency\":\"USD\",\"price\":100}` + \"\\n\",\n\t\t},\n\t\t{\n\t\t\tdesc: \"bad input (ID is invalid)\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/x/\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// set values into request (required by the mux)\n\t\t\t\treturn mux.SetURLVars(req, map[string]string{muxVarID: \"x\"})\n\t\t\t},\n\t\t\tinModelMock: func() *MockGetModel {\n\t\t\t\t// expect the model not to be called\n\t\t\t\tmockRegisterModel := &MockGetModel{}\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusBadRequest,\n\t\t\texpectedPayload: ``,\n\t\t},\n\t\t{\n\t\t\tdesc: \"bad input (ID is missing)\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person//\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// set values into request (required by the mux)\n\t\t\t\treturn mux.SetURLVars(req, map[string]string{})\n\t\t\t},\n\t\t\tinModelMock: func() *MockGetModel {\n\t\t\t\t// expect the model not to be called\n\t\t\t\tmockRegisterModel := &MockGetModel{}\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusBadRequest,\n\t\t\texpectedPayload: ``,\n\t\t},\n\t\t{\n\t\t\tdesc: \"dependency fail\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/1/\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// set values into request (required by the mux)\n\t\t\t\treturn mux.SetURLVars(req, map[string]string{muxVarID: \"1\"})\n\t\t\t},\n\t\t\tinModelMock: func() *MockGetModel {\n\t\t\t\tmockRegisterModel := &MockGetModel{}\n\t\t\t\tmockRegisterModel.On(\"Do\", mock.Anything).Return(nil, errors.New(\"something failed\")).Once()\n\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusNotFound,\n\t\t\texpectedPayload: ``,\n\t\t},\n\t\t{\n\t\t\tdesc: \"requested registration does not exist\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/1/\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// set values into request (required by the mux)\n\t\t\t\treturn mux.SetURLVars(req, map[string]string{muxVarID: \"1\"})\n\t\t\t},\n\t\t\tinModelMock: func() *MockGetModel {\n\t\t\t\tmockRegisterModel := &MockGetModel{}\n\t\t\t\tmockRegisterModel.On(\"Do\", mock.Anything).Return(nil, errors.New(\"person not found\")).Once()\n\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusNotFound,\n\t\t\texpectedPayload: ``,\n\t\t},\n\t}\n\n\tfor _, s := range scenarios {\n\t\tscenario := s\n\t\tt.Run(scenario.desc, func(t *testing.T) {\n\t\t\t// define model layer mock\n\t\t\tmockGetModel := scenario.inModelMock()\n\n\t\t\t// build handler\n\t\t\thandler := NewGetHandler(&testConfig{}, mockGetModel)\n\n\t\t\t// perform request\n\t\t\tresponse := httptest.NewRecorder()\n\t\t\thandler.ServeHTTP(response, scenario.inRequest())\n\n\t\t\t// validate outputs\n\t\t\trequire.Equal(t, scenario.expectedStatus, response.Code, scenario.desc)\n\n\t\t\tpayload, _ := ioutil.ReadAll(response.Body)\n\t\t\tassert.Equal(t, scenario.expectedPayload, string(payload), scenario.desc)\n\t\t})\n\t}\n}\n\ntype testConfig struct {\n}\n\nfunc (t *testConfig) Logger() logging.Logger {\n\treturn &logging.LoggerStdOut{}\n}\n\nfunc (*testConfig) BindAddress() string {\n\treturn \"0.0.0.0:0\"\n}\n"
  },
  {
    "path": "ch12/acme/internal/rest/list.go",
    "content": "package rest\n\nimport (\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/list\"\n)\n\n// ListModel will load all registrations\n//go:generate mockery -name=ListModel -case underscore -testonly -inpkg -note @generated\ntype ListModel interface {\n\tDo() ([]*list.Person, error)\n}\n\n// NewLister is the constructor for ListHandler\nfunc NewListHandler(model ListModel) *ListHandler {\n\treturn &ListHandler{\n\t\tlister: model,\n\t}\n}\n\n// ListHandler is the HTTP handler for the \"List Do people\" endpoint\n// In this simplified example we are assuming all possible errors are system errors (HTTP 500)\ntype ListHandler struct {\n\tlister ListModel\n}\n\n// ServeHTTP implements http.Handler\nfunc (h *ListHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\t// attempt loadAll\n\tpeople, err := h.lister.Do()\n\tif err != nil {\n\t\t// not need to log here as we can expect other layers to do so\n\t\tresponse.WriteHeader(http.StatusNotFound)\n\t\treturn\n\t}\n\n\t// happy path\n\terr = h.writeJSON(response, people)\n\tif err != nil {\n\t\t// this error should not happen but if it does there is nothing we can do to recover\n\t\tresponse.WriteHeader(http.StatusInternalServerError)\n\t}\n}\n\n// output the result as JSON\nfunc (h *ListHandler) writeJSON(writer io.Writer, people []*list.Person) error {\n\toutput := &listResponseFormat{\n\t\tPeople: make([]*listResponseItemFormat, len(people)),\n\t}\n\n\tfor index, record := range people {\n\t\toutput.People[index] = &listResponseItemFormat{\n\t\t\tID:       record.ID,\n\t\t\tFullName: record.FullName,\n\t\t\tPhone:    record.Phone,\n\t\t}\n\t}\n\n\t// call to http.ResponseWriter.Write() will cause HTTP OK (200) to be output as well\n\treturn json.NewEncoder(writer).Encode(output)\n}\n\ntype listResponseFormat struct {\n\tPeople []*listResponseItemFormat `json:\"people\"`\n}\n\ntype listResponseItemFormat struct {\n\tID       int    `json:\"id\"`\n\tFullName string `json:\"name\"`\n\tPhone    string `json:\"phone\"`\n}\n"
  },
  {
    "path": "ch12/acme/internal/rest/list_test.go",
    "content": "package rest\n\nimport (\n\t\"errors\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/list\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestListHandler_ServeHTTP(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc            string\n\t\tinRequest       func() *http.Request\n\t\tinModelMock     func() *MockListModel\n\t\texpectedStatus  int\n\t\texpectedPayload string\n\t}{\n\t\t{\n\t\t\tdesc: \"happy path\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/list\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn req\n\t\t\t},\n\t\t\tinModelMock: func() *MockListModel {\n\t\t\t\toutput := []*list.Person{\n\t\t\t\t\t{\n\t\t\t\t\t\tID:       1,\n\t\t\t\t\t\tFullName: \"John\",\n\t\t\t\t\t\tPhone:    \"0123456789\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tID:       2,\n\t\t\t\t\t\tFullName: \"Paul\",\n\t\t\t\t\t\tPhone:    \"0123456781\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tID:       3,\n\t\t\t\t\t\tFullName: \"George\",\n\t\t\t\t\t\tPhone:    \"0123456782\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tID:       1,\n\t\t\t\t\t\tFullName: \"Ringo\",\n\t\t\t\t\t\tPhone:    \"0123456783\",\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\tmockListModel := &MockListModel{}\n\t\t\t\tmockListModel.On(\"Do\", mock.Anything).Return(output, nil).Once()\n\n\t\t\t\treturn mockListModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusOK,\n\t\t\texpectedPayload: `{\"people\":[{\"id\":1,\"name\":\"John\",\"phone\":\"0123456789\"},{\"id\":2,\"name\":\"Paul\",\"phone\":\"0123456781\"},{\"id\":3,\"name\":\"George\",\"phone\":\"0123456782\"},{\"id\":1,\"name\":\"Ringo\",\"phone\":\"0123456783\"}]}` + \"\\n\",\n\t\t},\n\t\t{\n\t\t\tdesc: \"dependency failure\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/list\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn req\n\t\t\t},\n\t\t\tinModelMock: func() *MockListModel {\n\t\t\t\tmockListModel := &MockListModel{}\n\t\t\t\tmockListModel.On(\"Do\", mock.Anything).Return(nil, errors.New(\"something failed\")).Once()\n\n\t\t\t\treturn mockListModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusNotFound,\n\t\t\texpectedPayload: ``,\n\t\t},\n\t\t{\n\t\t\tdesc: \"no data\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\treq, err := http.NewRequest(\"GET\", \"/person/list\", nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn req\n\t\t\t},\n\t\t\tinModelMock: func() *MockListModel {\n\t\t\t\t// no data\n\t\t\t\tvar output []*list.Person\n\n\t\t\t\tmockListModel := &MockListModel{}\n\t\t\t\tmockListModel.On(\"Do\", mock.Anything).Return(output, nil).Once()\n\n\t\t\t\treturn mockListModel\n\t\t\t},\n\t\t\texpectedStatus:  http.StatusOK,\n\t\t\texpectedPayload: `{\"people\":[]}` + \"\\n\",\n\t\t},\n\t}\n\n\tfor _, s := range scenarios {\n\t\tscenario := s\n\t\tt.Run(scenario.desc, func(t *testing.T) {\n\t\t\t// define model layer mock\n\t\t\tmockListModel := scenario.inModelMock()\n\n\t\t\t// build handler\n\t\t\thandler := NewListHandler(mockListModel)\n\n\t\t\t// perform request\n\t\t\tresponse := httptest.NewRecorder()\n\t\t\thandler.ServeHTTP(response, scenario.inRequest())\n\n\t\t\t// validate outputs\n\t\t\trequire.Equal(t, scenario.expectedStatus, response.Code, scenario.desc)\n\n\t\t\tpayload, _ := ioutil.ReadAll(response.Body)\n\t\t\tassert.Equal(t, scenario.expectedPayload, string(payload), scenario.desc)\n\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "ch12/acme/internal/rest/mock_get_model_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage rest\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/get\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// MockGetModel is an autogenerated mock type for the GetModel type\ntype MockGetModel struct {\n\tmock.Mock\n}\n\n// Do provides a mock function with given fields: ID\nfunc (_m *MockGetModel) Do(ID int) (*get.Person, error) {\n\tret := _m.Called(ID)\n\n\tvar r0 *get.Person\n\tif rf, ok := ret.Get(0).(func(int) *get.Person); ok {\n\t\tr0 = rf(ID)\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).(*get.Person)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(int) error); ok {\n\t\tr1 = rf(ID)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch12/acme/internal/rest/mock_list_model_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage rest\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/list\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// MockListModel is an autogenerated mock type for the ListModel type\ntype MockListModel struct {\n\tmock.Mock\n}\n\n// Do provides a mock function with given fields:\nfunc (_m *MockListModel) Do() ([]*list.Person, error) {\n\tret := _m.Called()\n\n\tvar r0 []*list.Person\n\tif rf, ok := ret.Get(0).(func() []*list.Person); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tif ret.Get(0) != nil {\n\t\t\tr0 = ret.Get(0).([]*list.Person)\n\t\t}\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func() error); ok {\n\t\tr1 = rf()\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch12/acme/internal/rest/mock_register_model_test.go",
    "content": "// Code generated by mockery v1.0.0\n\n// @generated\n\npackage rest\n\nimport (\n\t\"context\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/register\"\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// MockRegisterModel is an autogenerated mock type for the RegisterModel type\ntype MockRegisterModel struct {\n\tmock.Mock\n}\n\n// Do provides a mock function with given fields: ctx, in\nfunc (_m *MockRegisterModel) Do(ctx context.Context, in *register.Person) (int, error) {\n\tret := _m.Called(ctx, in)\n\n\tvar r0 int\n\tif rf, ok := ret.Get(0).(func(context.Context, *register.Person) int); ok {\n\t\tr0 = rf(ctx, in)\n\t} else {\n\t\tr0 = ret.Get(0).(int)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(context.Context, *register.Person) error); ok {\n\t\tr1 = rf(ctx, in)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "ch12/acme/internal/rest/not_found.go",
    "content": "package rest\n\nimport (\n\t\"net/http\"\n)\n\nfunc notFoundHandler(response http.ResponseWriter, _ *http.Request) {\n\tresponse.WriteHeader(http.StatusNotFound)\n\t_, _ = response.Write([]byte(`Not found`))\n}\n"
  },
  {
    "path": "ch12/acme/internal/rest/not_found_test.go",
    "content": "package rest\n\nimport (\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestNotFoundHandler_ServeHTTP(t *testing.T) {\n\t// build inputs\n\tresponse := httptest.NewRecorder()\n\trequest := &http.Request{}\n\n\t// call handler\n\tnotFoundHandler(response, request)\n\n\t// validate outputs\n\trequire.Equal(t, http.StatusNotFound, response.Code)\n}\n"
  },
  {
    "path": "ch12/acme/internal/rest/register.go",
    "content": "package rest\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/register\"\n)\n\n// RegisterModel will validate and save a registration\n//go:generate mockery -name=RegisterModel -case underscore -testonly -inpkg -note @generated\ntype RegisterModel interface {\n\tDo(ctx context.Context, in *register.Person) (int, error)\n}\n\n// NewRegisterHandler is the constructor for RegisterHandler\nfunc NewRegisterHandler(model RegisterModel) *RegisterHandler {\n\treturn &RegisterHandler{\n\t\tregisterer: model,\n\t}\n}\n\n// RegisterHandler is the HTTP handler for the \"Register\" endpoint\n// In this simplified example we are assuming all possible errors are user errors and returning \"bad request\" HTTP 400.\n// There are some programmer errors possible but hopefully these will be caught in testing.\ntype RegisterHandler struct {\n\tregisterer RegisterModel\n}\n\n// ServeHTTP implements http.Handler\nfunc (h *RegisterHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {\n\t// set latency budget for this API\n\tsubCtx, cancel := context.WithTimeout(request.Context(), 1500*time.Millisecond)\n\tdefer cancel()\n\n\t// extract payload from request\n\trequestPayload, err := h.extractPayload(request)\n\tif err != nil {\n\t\t// output error\n\t\tresponse.WriteHeader(http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// call the business logic using the request data and context\n\tid, err := h.register(subCtx, requestPayload)\n\tif err != nil {\n\t\t// not need to log here as we can expect other layers to do so\n\t\tresponse.WriteHeader(http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// happy path\n\tresponse.Header().Add(\"Location\", fmt.Sprintf(\"/person/%d/\", id))\n\tresponse.WriteHeader(http.StatusCreated)\n}\n\n// extract payload from request\nfunc (h *RegisterHandler) extractPayload(request *http.Request) (*registerRequest, error) {\n\trequestPayload := &registerRequest{}\n\n\tdecoder := json.NewDecoder(request.Body)\n\terr := decoder.Decode(requestPayload)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn requestPayload, nil\n}\n\n// call the logic layer\nfunc (h *RegisterHandler) register(ctx context.Context, requestPayload *registerRequest) (int, error) {\n\tperson := &register.Person{\n\t\tFullName: requestPayload.FullName,\n\t\tPhone:    requestPayload.Phone,\n\t\tCurrency: requestPayload.Currency,\n\t}\n\n\treturn h.registerer.Do(ctx, person)\n}\n\n// register endpoint request format\ntype registerRequest struct {\n\t// FullName of the person\n\tFullName string `json:\"fullName\"`\n\t// Phone of the person\n\tPhone string `json:\"phone\"`\n\t// Currency the wish to register in\n\tCurrency string `json:\"currency\"`\n}\n"
  },
  {
    "path": "ch12/acme/internal/rest/register_test.go",
    "content": "package rest\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestRegisterHandler_ServeHTTP(t *testing.T) {\n\tscenarios := []struct {\n\t\tdesc           string\n\t\tinRequest      func() *http.Request\n\t\tinModelMock    func() *MockRegisterModel\n\t\texpectedStatus int\n\t\texpectedHeader string\n\t}{\n\t\t{\n\t\t\tdesc: \"Happy Path\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\tvalidRequest := buildValidRegisterRequest()\n\t\t\t\trequest, err := http.NewRequest(\"POST\", \"/person/register\", validRequest)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn request\n\t\t\t},\n\t\t\tinModelMock: func() *MockRegisterModel {\n\t\t\t\t// valid downstream configuration\n\t\t\t\tresultID := 1234\n\t\t\t\tvar resultErr error\n\n\t\t\t\tmockRegisterModel := &MockRegisterModel{}\n\t\t\t\tmockRegisterModel.On(\"Do\", mock.Anything, mock.Anything).Return(resultID, resultErr).Once()\n\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus: http.StatusCreated,\n\t\t\texpectedHeader: \"/person/1234/\",\n\t\t},\n\t\t{\n\t\t\tdesc: \"Bad Input / User Error\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\tinvalidRequest := bytes.NewBufferString(`this is not valid JSON`)\n\t\t\t\trequest, err := http.NewRequest(\"POST\", \"/person/register\", invalidRequest)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn request\n\t\t\t},\n\t\t\tinModelMock: func() *MockRegisterModel {\n\t\t\t\t// Dependency should not be called\n\t\t\t\tmockRegisterModel := &MockRegisterModel{}\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus: http.StatusBadRequest,\n\t\t\texpectedHeader: \"\",\n\t\t},\n\t\t{\n\t\t\tdesc: \"Dependency Failure\",\n\t\t\tinRequest: func() *http.Request {\n\t\t\t\tvalidRequest := buildValidRegisterRequest()\n\t\t\t\trequest, err := http.NewRequest(\"POST\", \"/person/register\", validRequest)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn request\n\t\t\t},\n\t\t\tinModelMock: func() *MockRegisterModel {\n\t\t\t\t// call to the dependency failed\n\t\t\t\tresultErr := errors.New(\"something failed\")\n\n\t\t\t\tmockRegisterModel := &MockRegisterModel{}\n\t\t\t\tmockRegisterModel.On(\"Do\", mock.Anything, mock.Anything).Return(0, resultErr).Once()\n\n\t\t\t\treturn mockRegisterModel\n\t\t\t},\n\t\t\texpectedStatus: http.StatusBadRequest,\n\t\t\texpectedHeader: \"\",\n\t\t},\n\t}\n\n\tfor _, s := range scenarios {\n\t\tscenario := s\n\t\tt.Run(scenario.desc, func(t *testing.T) {\n\t\t\t// define model layer mock\n\t\t\tmockRegisterModel := scenario.inModelMock()\n\n\t\t\t// build handler\n\t\t\thandler := NewRegisterHandler(mockRegisterModel)\n\n\t\t\t// perform request\n\t\t\tresponse := httptest.NewRecorder()\n\t\t\thandler.ServeHTTP(response, scenario.inRequest())\n\n\t\t\t// validate outputs\n\t\t\trequire.Equal(t, scenario.expectedStatus, response.Code)\n\n\t\t\t// call should output the location to the new person\n\t\t\tresultHeader := response.Header().Get(\"Location\")\n\t\t\tassert.Equal(t, scenario.expectedHeader, resultHeader)\n\n\t\t\t// validate the mock was used as we expected\n\t\t\tassert.True(t, mockRegisterModel.AssertExpectations(t))\n\t\t})\n\t}\n}\n\nfunc buildValidRegisterRequest() io.Reader {\n\trequestData := &registerRequest{\n\t\tFullName: \"Joan Smith\",\n\t\tCurrency: \"AUD\",\n\t\tPhone:    \"01234567890\",\n\t}\n\n\tdata, _ := json.Marshal(requestData)\n\treturn bytes.NewBuffer(data)\n}\n"
  },
  {
    "path": "ch12/acme/internal/rest/server.go",
    "content": "package rest\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/logging\"\n\t\"github.com/gorilla/mux\"\n)\n\n// Config is the config for the REST package\ntype Config interface {\n\tLogger() logging.Logger\n\tBindAddress() string\n}\n\n// New will create and initialize the server\nfunc New(cfg Config,\n\tgetModel GetModel,\n\tlistModel ListModel,\n\tregisterModel RegisterModel) *Server {\n\n\treturn &Server{\n\t\taddress:         cfg.BindAddress(),\n\t\thandlerGet:      NewGetHandler(cfg, getModel),\n\t\thandlerList:     NewListHandler(listModel),\n\t\thandlerNotFound: notFoundHandler,\n\t\thandlerRegister: NewRegisterHandler(registerModel),\n\t}\n}\n\n// Server is the HTTP REST server\ntype Server struct {\n\taddress string\n\tserver  *http.Server\n\n\thandlerGet      http.Handler\n\thandlerList     http.Handler\n\thandlerNotFound http.HandlerFunc\n\thandlerRegister http.Handler\n}\n\n// Listen will start a HTTP rest for this service\nfunc (s *Server) Listen(stop <-chan struct{}) {\n\trouter := s.buildRouter()\n\n\t// create the HTTP server\n\ts.server = &http.Server{\n\t\tHandler: router,\n\t\tAddr:    s.address,\n\t}\n\n\t// listen for shutdown\n\tgo func() {\n\t\t// wait for shutdown signal\n\t\t<-stop\n\n\t\t_ = s.server.Close()\n\t}()\n\n\t// start the HTTP server\n\t_ = s.server.ListenAndServe()\n}\n\n// configure the endpoints to handlers\nfunc (s *Server) buildRouter() http.Handler {\n\trouter := mux.NewRouter()\n\n\t// map URL endpoints to HTTP handlers\n\trouter.Handle(\"/person/{id}/\", s.handlerGet).Methods(\"GET\")\n\trouter.Handle(\"/person/list\", s.handlerList).Methods(\"GET\")\n\trouter.Handle(\"/person/register\", s.handlerRegister).Methods(\"POST\")\n\n\t// convert a \"catch all\" not found handler\n\trouter.NotFoundHandler = s.handlerNotFound\n\n\treturn router\n}\n"
  },
  {
    "path": "ch12/acme/main.go",
    "content": "package main\n\nimport (\n\t\"context\"\n\t\"os\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/config\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/exchange\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/get\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/list\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/register\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/rest\"\n\t\"github.com/google/wire\"\n)\n\nfunc main() {\n\t// bind stop channel to context\n\tctx := context.Background()\n\n\t// start REST server\n\tserver, err := initializeServer()\n\tif err != nil {\n\t\tos.Exit(-1)\n\t}\n\n\tserver.Listen(ctx.Done())\n}\n\n// List of wire enabled objects\nvar wireSetWithoutConfig = wire.NewSet(\n\t// *exchange.Converter\n\texchange.NewConverter,\n\n\t// *get.Getter\n\tget.NewGetter,\n\n\t// *list.Lister\n\tlist.NewLister,\n\n\t// *register.Registerer\n\twire.Bind(new(register.Exchanger), &exchange.Converter{}),\n\tregister.NewRegisterer,\n\n\t// *rest.Server\n\twire.Bind(new(rest.GetModel), &get.Getter{}),\n\twire.Bind(new(rest.ListModel), &list.Lister{}),\n\twire.Bind(new(rest.RegisterModel), &register.Registerer{}),\n\trest.New,\n)\n\nvar wireSet = wire.NewSet(\n\twireSetWithoutConfig,\n\n\t// *config.Config\n\tconfig.Load,\n\n\t// *exchange.Converter\n\twire.Bind(new(exchange.Config), &config.Config{}),\n\n\t// *get.Getter\n\twire.Bind(new(get.Config), &config.Config{}),\n\n\t// *list.Lister\n\twire.Bind(new(list.Config), &config.Config{}),\n\n\t// *register.Registerer\n\twire.Bind(new(register.Config), &config.Config{}),\n\n\t// *rest.Server\n\twire.Bind(new(rest.Config), &config.Config{}),\n)\n"
  },
  {
    "path": "ch12/acme/main_test.go",
    "content": "package main\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/config\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestRegister(t *testing.T) {\n\t// start a context with a max execution time\n\tctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n\tdefer cancel()\n\n\t// start test server\n\tserverAddress := startTestServer(t, ctx)\n\n\t// build and send request\n\tpayload := bytes.NewBufferString(`\n{\n\t\"fullName\": \"Bob\",\n\t\"phone\": \"0123456789\",\n\t\"currency\": \"AUD\"\n}\n`)\n\n\treq, err := http.NewRequest(\"POST\", serverAddress+\"/person/register\", payload)\n\trequire.NoError(t, err)\n\n\tresp, err := http.DefaultClient.Do(req)\n\trequire.NoError(t, err)\n\n\t// validate expectations\n\tassert.Equal(t, http.StatusCreated, resp.StatusCode)\n\tassert.NotEmpty(t, resp.Header.Get(\"Location\"))\n}\n\nfunc TestGet(t *testing.T) {\n\t// start a context with a max execution time\n\tctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n\tdefer cancel()\n\n\t// start test server\n\tserverAddress := startTestServer(t, ctx)\n\n\t// build and send request\n\treq, err := http.NewRequest(\"GET\", serverAddress+\"/person/1/\", nil)\n\trequire.NoError(t, err)\n\n\tresp, err := http.DefaultClient.Do(req)\n\trequire.NoError(t, err)\n\n\t// validate expectations\n\tassert.Equal(t, http.StatusOK, resp.StatusCode)\n}\n\nfunc TestList(t *testing.T) {\n\t// start a context with a max execution time\n\tctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n\tdefer cancel()\n\n\t// start test server\n\tserverAddress := startTestServer(t, ctx)\n\n\t// build and send request\n\treq, err := http.NewRequest(\"GET\", serverAddress+\"/person/list\", nil)\n\trequire.NoError(t, err)\n\n\tresp, err := http.DefaultClient.Do(req)\n\trequire.NoError(t, err)\n\n\t// validate expectations\n\tassert.Equal(t, http.StatusOK, resp.StatusCode)\n}\n\nfunc startTestServer(t *testing.T, ctx context.Context) string {\n\t// load the standard config (from the ENV)\n\tcfg, err := config.Load()\n\trequire.NoError(t, err)\n\n\t// get a free port (so tests can run concurrently)\n\tport, err := getFreePort()\n\trequire.NoError(t, err)\n\n\t// override config port with free one\n\tcfg.Address = net.JoinHostPort(\"0.0.0.0\", port)\n\n\t// start the test server on a random port\n\tgo func() {\n\t\t// start REST server\n\t\tserver := initializeServerCustomConfig(cfg, cfg, cfg, cfg, cfg)\n\t\tserver.Listen(ctx.Done())\n\t}()\n\n\t// give the server a chance to start\n\t<-time.After(100 * time.Millisecond)\n\n\t// return the address of the test server\n\treturn \"http://\" + cfg.Address\n}\n\nfunc getFreePort() (string, error) {\n\tfor attempt := 0; attempt <= 10; attempt++ {\n\t\taddr := net.JoinHostPort(\"\", \"0\")\n\t\tlistener, err := net.Listen(\"tcp\", addr)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tport, err := getPort(listener.Addr())\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\t// close/free the port\n\t\ttcpListener := listener.(*net.TCPListener)\n\t\tcErr := tcpListener.Close()\n\t\tif cErr == nil {\n\t\t\tfile, fErr := tcpListener.File()\n\t\t\tif fErr == nil {\n\t\t\t\t// ignore any errors cleaning up the file\n\t\t\t\t_ = file.Close()\n\t\t\t}\n\t\t\treturn port, nil\n\t\t}\n\t}\n\n\treturn \"\", errors.New(\"no free ports\")\n}\n\nfunc getPort(addr fmt.Stringer) (string, error) {\n\tactualAddress := addr.String()\n\t_, port, err := net.SplitHostPort(actualAddress)\n\treturn port, err\n}\n"
  },
  {
    "path": "ch12/acme/wire.go",
    "content": "//+build wireinject\n\npackage main\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/exchange\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/get\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/list\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/register\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/rest\"\n\t\"github.com/google/wire\"\n)\n\n// The build tag makes sure the stub is not built in the final build.\n\nfunc initializeServer() (*rest.Server, error) {\n\twire.Build(wireSet)\n\treturn nil, nil\n}\n\nfunc initializeServerCustomConfig(_ exchange.Config, _ get.Config, _ list.Config, _ register.Config, _ rest.Config) *rest.Server {\n\twire.Build(wireSetWithoutConfig)\n\treturn nil\n}\n"
  },
  {
    "path": "ch12/acme/wire_gen.go",
    "content": "// Code generated by Wire. DO NOT EDIT.\n\n//go:generate wire\n//+build !wireinject\n\npackage main\n\nimport (\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/config\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/exchange\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/get\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/list\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/modules/register\"\n\t\"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go/ch12/acme/internal/rest\"\n)\n\n// Injectors from wire.go:\n\nfunc initializeServer() (*rest.Server, error) {\n\tconfigConfig, err := config.Load()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tgetter := get.NewGetter(configConfig)\n\tlister := list.NewLister(configConfig)\n\tconverter := exchange.NewConverter(configConfig)\n\tregisterer := register.NewRegisterer(configConfig, converter)\n\tserver := rest.New(configConfig, getter, lister, registerer)\n\treturn server, nil\n}\n\nfunc initializeServerCustomConfig(exchangeConfig exchange.Config, getConfig get.Config, listConfig list.Config, registerConfig register.Config, restConfig rest.Config) *rest.Server {\n\tgetter := get.NewGetter(getConfig)\n\tlister := list.NewLister(listConfig)\n\tconverter := exchange.NewConverter(exchangeConfig)\n\tregisterer := register.NewRegisterer(registerConfig, converter)\n\tserver := rest.New(restConfig, getter, lister, registerer)\n\treturn server\n}\n"
  },
  {
    "path": "ch12/fake.go",
    "content": "package ch12\n\nfunc init() {\n\t// This file is included so that Go tools (like `go list`) will find Go code in this directory and not error\n}\n"
  },
  {
    "path": "default-config.json",
    "content": "{\n  \"dsn\": \"[insert your db config here]\",\n  \"address\": \"0.0.0.0:8080\",\n  \"basePrice\":  100.00,\n  \"exchangeRateBaseURL\": \"http://apilayer.net\",\n  \"exchangeRateAPIKey\": \"[insert your API key here]\"\n}"
  },
  {
    "path": "fake.go",
    "content": "package Hands_On_Dependency_Injection_in_Go\n\nfunc init() {\n\t// This file is included so that Go tools (like `go list`) will find Go code in this directory and not error\n}\n"
  },
  {
    "path": "resources/create.sql",
    "content": "CREATE DATABASE IF NOT EXISTS acme;\n\nCREATE TABLE IF NOT EXISTS `acme`.`person` (\n  `id` BIGINT(20) NOT NULL AUTO_INCREMENT,\n  `fullName` VARCHAR(100) NOT NULL,\n  `phone` CHAR(15) NOT NULL,\n  `currency` CHAR(3) NOT NULL,\n  `price` DECIMAL(6,2) NOT NULL,\n  PRIMARY KEY (`id`));\n\nINSERT INTO `acme`.`person` (`id`, `fullName`, `phone`, `currency`, `price`)\n  VALUES (\"1\", \"John\", \"0123456780\", \"USD\", 100);\nINSERT INTO `acme`.`person` (`id`, `fullName`, `phone`, `currency`, `price`)\n  VALUES (\"2\", \"Paul\", \"0123456781\", \"AUD\", 120);\nINSERT INTO `acme`.`person` (`id`, `fullName`, `phone`, `currency`, `price`)\n  VALUES (\"3\", \"George\", \"0123456782\", \"GBP\", 150);\nINSERT INTO `acme`.`person` (`id`, `fullName`, `phone`, `currency`, `price`)\n  VALUES (\"4\", \"Ringo\", \"0123456783\", \"EUR\", 110);\n\n"
  },
  {
    "path": "vendor/github.com/DATA-DOG/go-sqlmock/LICENSE",
    "content": "The three clause BSD license (http://en.wikipedia.org/wiki/BSD_licenses)\n\nCopyright (c) 2013-2018, DATA-DOG team\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* The name DataDog.lt may not be used to endorse or promote products\n  derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT,\nINDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\nBUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\nOF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\nNEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\nEVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "vendor/github.com/DATA-DOG/go-sqlmock/README.md",
    "content": "[![Build Status](https://travis-ci.org/DATA-DOG/go-sqlmock.svg)](https://travis-ci.org/DATA-DOG/go-sqlmock)\n[![GoDoc](https://godoc.org/github.com/DATA-DOG/go-sqlmock?status.svg)](https://godoc.org/github.com/DATA-DOG/go-sqlmock)\n[![Go Report Card](https://goreportcard.com/badge/github.com/DATA-DOG/go-sqlmock)](https://goreportcard.com/report/github.com/DATA-DOG/go-sqlmock)\n[![codecov.io](https://codecov.io/github/DATA-DOG/go-sqlmock/branch/master/graph/badge.svg)](https://codecov.io/github/DATA-DOG/go-sqlmock)\n\n# Sql driver mock for Golang\n\n**sqlmock** is a mock library implementing [sql/driver](https://godoc.org/database/sql/driver). Which has one and only\npurpose - to simulate any **sql** driver behavior in tests, without needing a real database connection. It helps to\nmaintain correct **TDD** workflow.\n\n- this library is now complete and stable. (you may not find new changes for this reason)\n- supports concurrency and multiple connections.\n- supports **go1.8** Context related feature mocking and Named sql parameters.\n- does not require any modifications to your source code.\n- the driver allows to mock any sql driver method behavior.\n- has strict by default expectation order matching.\n- has no third party dependencies.\n\n**NOTE:** in **v1.2.0** **sqlmock.Rows** has changed to struct from interface, if you were using any type references to that\ninterface, you will need to switch it to a pointer struct type. Also, **sqlmock.Rows** were used to implement **driver.Rows**\ninterface, which was not required or useful for mocking and was removed. Hope it will not cause issues.\n\n## Install\n\n    go get gopkg.in/DATA-DOG/go-sqlmock.v1\n\n## Documentation and Examples\n\nVisit [godoc](http://godoc.org/github.com/DATA-DOG/go-sqlmock) for general examples and public api reference.\nSee **.travis.yml** for supported **go** versions.\nDifferent use case, is to functionally test with a real database - [go-txdb](https://github.com/DATA-DOG/go-txdb)\nall database related actions are isolated within a single transaction so the database can remain in the same state.\n\nSee implementation examples:\n\n- [blog API server](https://github.com/DATA-DOG/go-sqlmock/tree/master/examples/blog)\n- [the same orders example](https://github.com/DATA-DOG/go-sqlmock/tree/master/examples/orders)\n\n### Something you may want to test\n\n``` go\npackage main\n\nimport \"database/sql\"\n\nfunc recordStats(db *sql.DB, userID, productID int64) (err error) {\n\ttx, err := db.Begin()\n\tif err != nil {\n\t\treturn\n\t}\n\n\tdefer func() {\n\t\tswitch err {\n\t\tcase nil:\n\t\t\terr = tx.Commit()\n\t\tdefault:\n\t\t\ttx.Rollback()\n\t\t}\n\t}()\n\n\tif _, err = tx.Exec(\"UPDATE products SET views = views + 1\"); err != nil {\n\t\treturn\n\t}\n\tif _, err = tx.Exec(\"INSERT INTO product_viewers (user_id, product_id) VALUES (?, ?)\", userID, productID); err != nil {\n\t\treturn\n\t}\n\treturn\n}\n\nfunc main() {\n\t// @NOTE: the real connection is not required for tests\n\tdb, err := sql.Open(\"mysql\", \"root@/blog\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer db.Close()\n\n\tif err = recordStats(db, 1 /*some user id*/, 5 /*some product id*/); err != nil {\n\t\tpanic(err)\n\t}\n}\n```\n\n### Tests with sqlmock\n\n``` go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"gopkg.in/DATA-DOG/go-sqlmock.v1\"\n)\n\n// a successful case\nfunc TestShouldUpdateStats(t *testing.T) {\n\tdb, mock, err := sqlmock.New()\n\tif err != nil {\n\t\tt.Fatalf(\"an error '%s' was not expected when opening a stub database connection\", err)\n\t}\n\tdefer db.Close()\n\n\tmock.ExpectBegin()\n\tmock.ExpectExec(\"UPDATE products\").WillReturnResult(sqlmock.NewResult(1, 1))\n\tmock.ExpectExec(\"INSERT INTO product_viewers\").WithArgs(2, 3).WillReturnResult(sqlmock.NewResult(1, 1))\n\tmock.ExpectCommit()\n\n\t// now we execute our method\n\tif err = recordStats(db, 2, 3); err != nil {\n\t\tt.Errorf(\"error was not expected while updating stats: %s\", err)\n\t}\n\n\t// we make sure that all expectations were met\n\tif err := mock.ExpectationsWereMet(); err != nil {\n\t\tt.Errorf(\"there were unfulfilled expectations: %s\", err)\n\t}\n}\n\n// a failing test case\nfunc TestShouldRollbackStatUpdatesOnFailure(t *testing.T) {\n\tdb, mock, err := sqlmock.New()\n\tif err != nil {\n\t\tt.Fatalf(\"an error '%s' was not expected when opening a stub database connection\", err)\n\t}\n\tdefer db.Close()\n\n\tmock.ExpectBegin()\n\tmock.ExpectExec(\"UPDATE products\").WillReturnResult(sqlmock.NewResult(1, 1))\n\tmock.ExpectExec(\"INSERT INTO product_viewers\").\n\t\tWithArgs(2, 3).\n\t\tWillReturnError(fmt.Errorf(\"some error\"))\n\tmock.ExpectRollback()\n\n\t// now we execute our method\n\tif err = recordStats(db, 2, 3); err == nil {\n\t\tt.Errorf(\"was expecting an error, but there was none\")\n\t}\n\n\t// we make sure that all expectations were met\n\tif err := mock.ExpectationsWereMet(); err != nil {\n\t\tt.Errorf(\"there were unfulfilled expectations: %s\", err)\n\t}\n}\n```\n\n## Matching arguments like time.Time\n\nThere may be arguments which are of `struct` type and cannot be compared easily by value like `time.Time`. In this case\n**sqlmock** provides an [Argument](https://godoc.org/github.com/DATA-DOG/go-sqlmock#Argument) interface which\ncan be used in more sophisticated matching. Here is a simple example of time argument matching:\n\n``` go\ntype AnyTime struct{}\n\n// Match satisfies sqlmock.Argument interface\nfunc (a AnyTime) Match(v driver.Value) bool {\n\t_, ok := v.(time.Time)\n\treturn ok\n}\n\nfunc TestAnyTimeArgument(t *testing.T) {\n\tt.Parallel()\n\tdb, mock, err := New()\n\tif err != nil {\n\t\tt.Errorf(\"an error '%s' was not expected when opening a stub database connection\", err)\n\t}\n\tdefer db.Close()\n\n\tmock.ExpectExec(\"INSERT INTO users\").\n\t\tWithArgs(\"john\", AnyTime{}).\n\t\tWillReturnResult(NewResult(1, 1))\n\n\t_, err = db.Exec(\"INSERT INTO users(name, created_at) VALUES (?, ?)\", \"john\", time.Now())\n\tif err != nil {\n\t\tt.Errorf(\"error '%s' was not expected, while inserting a row\", err)\n\t}\n\n\tif err := mock.ExpectationsWereMet(); err != nil {\n\t\tt.Errorf(\"there were unfulfilled expectations: %s\", err)\n\t}\n}\n```\n\nIt only asserts that argument is of `time.Time` type.\n\n## Run tests\n\n    go test -race\n\n## Change Log\n\n- **2017-09-01** - it is now possible to expect that prepared statement will be closed,\n  using **ExpectedPrepare.WillBeClosed**.\n- **2017-02-09** - implemented support for **go1.8** features. **Rows** interface was changed to struct\n  but contains all methods as before and should maintain backwards compatibility. **ExpectedQuery.WillReturnRows** may now\n  accept multiple row sets.\n- **2016-11-02** - `db.Prepare()` was not validating expected prepare SQL\n  query. It should still be validated even if Exec or Query is not\n  executed on that prepared statement.\n- **2016-02-23** - added **sqlmock.AnyArg()** function to provide any kind\n  of argument matcher.\n- **2016-02-23** - convert expected arguments to driver.Value as natural\n  driver does, the change may affect time.Time comparison and will be\n  stricter. See [issue](https://github.com/DATA-DOG/go-sqlmock/issues/31).\n- **2015-08-27** - **v1** api change, concurrency support, all known issues fixed.\n- **2014-08-16** instead of **panic** during reflect type mismatch when comparing query arguments - now return error\n- **2014-08-14** added **sqlmock.NewErrorResult** which gives an option to return driver.Result with errors for\ninterface methods, see [issue](https://github.com/DATA-DOG/go-sqlmock/issues/5)\n- **2014-05-29** allow to match arguments in more sophisticated ways, by providing an **sqlmock.Argument** interface\n- **2014-04-21** introduce **sqlmock.New()** to open a mock database connection for tests. This method\ncalls sql.DB.Ping to ensure that connection is open, see [issue](https://github.com/DATA-DOG/go-sqlmock/issues/4).\nThis way on Close it will surely assert if all expectations are met, even if database was not triggered at all.\nThe old way is still available, but it is advisable to call db.Ping manually before asserting with db.Close.\n- **2014-02-14** RowsFromCSVString is now a part of Rows interface named as FromCSVString.\nIt has changed to allow more ways to construct rows and to easily extend this API in future.\nSee [issue 1](https://github.com/DATA-DOG/go-sqlmock/issues/1)\n**RowsFromCSVString** is deprecated and will be removed in future\n\n## Contributions\n\nFeel free to open a pull request. Note, if you wish to contribute an extension to public (exported methods or types) -\nplease open an issue before, to discuss whether these changes can be accepted. All backward incompatible changes are\nand will be treated cautiously\n\n## License\n\nThe [three clause BSD license](http://en.wikipedia.org/wiki/BSD_licenses)\n\n"
  },
  {
    "path": "vendor/github.com/DATA-DOG/go-sqlmock/argument.go",
    "content": "package sqlmock\n\nimport \"database/sql/driver\"\n\n// Argument interface allows to match\n// any argument in specific way when used with\n// ExpectedQuery and ExpectedExec expectations.\ntype Argument interface {\n\tMatch(driver.Value) bool\n}\n\n// AnyArg will return an Argument which can\n// match any kind of arguments.\n//\n// Useful for time.Time or similar kinds of arguments.\nfunc AnyArg() Argument {\n\treturn anyArgument{}\n}\n\ntype anyArgument struct{}\n\nfunc (a anyArgument) Match(_ driver.Value) bool {\n\treturn true\n}\n"
  },
  {
    "path": "vendor/github.com/DATA-DOG/go-sqlmock/driver.go",
    "content": "package sqlmock\n\nimport (\n\t\"database/sql\"\n\t\"database/sql/driver\"\n\t\"fmt\"\n\t\"sync\"\n)\n\nvar pool *mockDriver\n\nfunc init() {\n\tpool = &mockDriver{\n\t\tconns: make(map[string]*sqlmock),\n\t}\n\tsql.Register(\"sqlmock\", pool)\n}\n\ntype mockDriver struct {\n\tsync.Mutex\n\tcounter int\n\tconns   map[string]*sqlmock\n}\n\nfunc (d *mockDriver) Open(dsn string) (driver.Conn, error) {\n\td.Lock()\n\tdefer d.Unlock()\n\n\tc, ok := d.conns[dsn]\n\tif !ok {\n\t\treturn c, fmt.Errorf(\"expected a connection to be available, but it is not\")\n\t}\n\n\tc.opened++\n\treturn c, nil\n}\n\n// New creates sqlmock database connection\n// and a mock to manage expectations.\n// Pings db so that all expectations could be\n// asserted.\nfunc New() (*sql.DB, Sqlmock, error) {\n\tpool.Lock()\n\tdsn := fmt.Sprintf(\"sqlmock_db_%d\", pool.counter)\n\tpool.counter++\n\n\tsmock := &sqlmock{dsn: dsn, drv: pool, ordered: true}\n\tpool.conns[dsn] = smock\n\tpool.Unlock()\n\n\treturn smock.open()\n}\n\n// NewWithDSN creates sqlmock database connection\n// with a specific DSN and a mock to manage expectations.\n// Pings db so that all expectations could be asserted.\n//\n// This method is introduced because of sql abstraction\n// libraries, which do not provide a way to initialize\n// with sql.DB instance. For example GORM library.\n//\n// Note, it will error if attempted to create with an\n// already used dsn\n//\n// It is not recommended to use this method, unless you\n// really need it and there is no other way around.\nfunc NewWithDSN(dsn string) (*sql.DB, Sqlmock, error) {\n\tpool.Lock()\n\tif _, ok := pool.conns[dsn]; ok {\n\t\tpool.Unlock()\n\t\treturn nil, nil, fmt.Errorf(\"cannot create a new mock database with the same dsn: %s\", dsn)\n\t}\n\tsmock := &sqlmock{dsn: dsn, drv: pool, ordered: true}\n\tpool.conns[dsn] = smock\n\tpool.Unlock()\n\n\treturn smock.open()\n}\n"
  },
  {
    "path": "vendor/github.com/DATA-DOG/go-sqlmock/expectations.go",
    "content": "package sqlmock\n\nimport (\n\t\"database/sql/driver\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n)\n\n// an expectation interface\ntype expectation interface {\n\tfulfilled() bool\n\tLock()\n\tUnlock()\n\tString() string\n}\n\n// common expectation struct\n// satisfies the expectation interface\ntype commonExpectation struct {\n\tsync.Mutex\n\ttriggered bool\n\terr       error\n}\n\nfunc (e *commonExpectation) fulfilled() bool {\n\treturn e.triggered\n}\n\n// ExpectedClose is used to manage *sql.DB.Close expectation\n// returned by *Sqlmock.ExpectClose.\ntype ExpectedClose struct {\n\tcommonExpectation\n}\n\n// WillReturnError allows to set an error for *sql.DB.Close action\nfunc (e *ExpectedClose) WillReturnError(err error) *ExpectedClose {\n\te.err = err\n\treturn e\n}\n\n// String returns string representation\nfunc (e *ExpectedClose) String() string {\n\tmsg := \"ExpectedClose => expecting database Close\"\n\tif e.err != nil {\n\t\tmsg += fmt.Sprintf(\", which should return error: %s\", e.err)\n\t}\n\treturn msg\n}\n\n// ExpectedBegin is used to manage *sql.DB.Begin expectation\n// returned by *Sqlmock.ExpectBegin.\ntype ExpectedBegin struct {\n\tcommonExpectation\n\tdelay time.Duration\n}\n\n// WillReturnError allows to set an error for *sql.DB.Begin action\nfunc (e *ExpectedBegin) WillReturnError(err error) *ExpectedBegin {\n\te.err = err\n\treturn e\n}\n\n// String returns string representation\nfunc (e *ExpectedBegin) String() string {\n\tmsg := \"ExpectedBegin => expecting database transaction Begin\"\n\tif e.err != nil {\n\t\tmsg += fmt.Sprintf(\", which should return error: %s\", e.err)\n\t}\n\treturn msg\n}\n\n// WillDelayFor allows to specify duration for which it will delay\n// result. May be used together with Context\nfunc (e *ExpectedBegin) WillDelayFor(duration time.Duration) *ExpectedBegin {\n\te.delay = duration\n\treturn e\n}\n\n// ExpectedCommit is used to manage *sql.Tx.Commit expectation\n// returned by *Sqlmock.ExpectCommit.\ntype ExpectedCommit struct {\n\tcommonExpectation\n}\n\n// WillReturnError allows to set an error for *sql.Tx.Close action\nfunc (e *ExpectedCommit) WillReturnError(err error) *ExpectedCommit {\n\te.err = err\n\treturn e\n}\n\n// String returns string representation\nfunc (e *ExpectedCommit) String() string {\n\tmsg := \"ExpectedCommit => expecting transaction Commit\"\n\tif e.err != nil {\n\t\tmsg += fmt.Sprintf(\", which should return error: %s\", e.err)\n\t}\n\treturn msg\n}\n\n// ExpectedRollback is used to manage *sql.Tx.Rollback expectation\n// returned by *Sqlmock.ExpectRollback.\ntype ExpectedRollback struct {\n\tcommonExpectation\n}\n\n// WillReturnError allows to set an error for *sql.Tx.Rollback action\nfunc (e *ExpectedRollback) WillReturnError(err error) *ExpectedRollback {\n\te.err = err\n\treturn e\n}\n\n// String returns string representation\nfunc (e *ExpectedRollback) String() string {\n\tmsg := \"ExpectedRollback => expecting transaction Rollback\"\n\tif e.err != nil {\n\t\tmsg += fmt.Sprintf(\", which should return error: %s\", e.err)\n\t}\n\treturn msg\n}\n\n// ExpectedQuery is used to manage *sql.DB.Query, *dql.DB.QueryRow, *sql.Tx.Query,\n// *sql.Tx.QueryRow, *sql.Stmt.Query or *sql.Stmt.QueryRow expectations.\n// Returned by *Sqlmock.ExpectQuery.\ntype ExpectedQuery struct {\n\tqueryBasedExpectation\n\trows  driver.Rows\n\tdelay time.Duration\n}\n\n// WithArgs will match given expected args to actual database query arguments.\n// if at least one argument does not match, it will return an error. For specific\n// arguments an sqlmock.Argument interface can be used to match an argument.\nfunc (e *ExpectedQuery) WithArgs(args ...driver.Value) *ExpectedQuery {\n\te.args = args\n\treturn e\n}\n\n// WillReturnError allows to set an error for expected database query\nfunc (e *ExpectedQuery) WillReturnError(err error) *ExpectedQuery {\n\te.err = err\n\treturn e\n}\n\n// WillDelayFor allows to specify duration for which it will delay\n// result. May be used together with Context\nfunc (e *ExpectedQuery) WillDelayFor(duration time.Duration) *ExpectedQuery {\n\te.delay = duration\n\treturn e\n}\n\n// String returns string representation\nfunc (e *ExpectedQuery) String() string {\n\tmsg := \"ExpectedQuery => expecting Query, QueryContext or QueryRow which:\"\n\tmsg += \"\\n  - matches sql: '\" + e.sqlRegex.String() + \"'\"\n\n\tif len(e.args) == 0 {\n\t\tmsg += \"\\n  - is without arguments\"\n\t} else {\n\t\tmsg += \"\\n  - is with arguments:\\n\"\n\t\tfor i, arg := range e.args {\n\t\t\tmsg += fmt.Sprintf(\"    %d - %+v\\n\", i, arg)\n\t\t}\n\t\tmsg = strings.TrimSpace(msg)\n\t}\n\n\tif e.rows != nil {\n\t\tmsg += fmt.Sprintf(\"\\n  - %s\", e.rows)\n\t}\n\n\tif e.err != nil {\n\t\tmsg += fmt.Sprintf(\"\\n  - should return error: %s\", e.err)\n\t}\n\n\treturn msg\n}\n\n// ExpectedExec is used to manage *sql.DB.Exec, *sql.Tx.Exec or *sql.Stmt.Exec expectations.\n// Returned by *Sqlmock.ExpectExec.\ntype ExpectedExec struct {\n\tqueryBasedExpectation\n\tresult driver.Result\n\tdelay  time.Duration\n}\n\n// WithArgs will match given expected args to actual database exec operation arguments.\n// if at least one argument does not match, it will return an error. For specific\n// arguments an sqlmock.Argument interface can be used to match an argument.\nfunc (e *ExpectedExec) WithArgs(args ...driver.Value) *ExpectedExec {\n\te.args = args\n\treturn e\n}\n\n// WillReturnError allows to set an error for expected database exec action\nfunc (e *ExpectedExec) WillReturnError(err error) *ExpectedExec {\n\te.err = err\n\treturn e\n}\n\n// WillDelayFor allows to specify duration for which it will delay\n// result. May be used together with Context\nfunc (e *ExpectedExec) WillDelayFor(duration time.Duration) *ExpectedExec {\n\te.delay = duration\n\treturn e\n}\n\n// String returns string representation\nfunc (e *ExpectedExec) String() string {\n\tmsg := \"ExpectedExec => expecting Exec or ExecContext which:\"\n\tmsg += \"\\n  - matches sql: '\" + e.sqlRegex.String() + \"'\"\n\n\tif len(e.args) == 0 {\n\t\tmsg += \"\\n  - is without arguments\"\n\t} else {\n\t\tmsg += \"\\n  - is with arguments:\\n\"\n\t\tvar margs []string\n\t\tfor i, arg := range e.args {\n\t\t\tmargs = append(margs, fmt.Sprintf(\"    %d - %+v\", i, arg))\n\t\t}\n\t\tmsg += strings.Join(margs, \"\\n\")\n\t}\n\n\tif e.result != nil {\n\t\tres, _ := e.result.(*result)\n\t\tmsg += \"\\n  - should return Result having:\"\n\t\tmsg += fmt.Sprintf(\"\\n      LastInsertId: %d\", res.insertID)\n\t\tmsg += fmt.Sprintf(\"\\n      RowsAffected: %d\", res.rowsAffected)\n\t\tif res.err != nil {\n\t\t\tmsg += fmt.Sprintf(\"\\n      Error: %s\", res.err)\n\t\t}\n\t}\n\n\tif e.err != nil {\n\t\tmsg += fmt.Sprintf(\"\\n  - should return error: %s\", e.err)\n\t}\n\n\treturn msg\n}\n\n// WillReturnResult arranges for an expected Exec() to return a particular\n// result, there is sqlmock.NewResult(lastInsertID int64, affectedRows int64) method\n// to build a corresponding result. Or if actions needs to be tested against errors\n// sqlmock.NewErrorResult(err error) to return a given error.\nfunc (e *ExpectedExec) WillReturnResult(result driver.Result) *ExpectedExec {\n\te.result = result\n\treturn e\n}\n\n// ExpectedPrepare is used to manage *sql.DB.Prepare or *sql.Tx.Prepare expectations.\n// Returned by *Sqlmock.ExpectPrepare.\ntype ExpectedPrepare struct {\n\tcommonExpectation\n\tmock         *sqlmock\n\tsqlRegex     *regexp.Regexp\n\tstatement    driver.Stmt\n\tcloseErr     error\n\tmustBeClosed bool\n\twasClosed    bool\n\tdelay        time.Duration\n}\n\n// WillReturnError allows to set an error for the expected *sql.DB.Prepare or *sql.Tx.Prepare action.\nfunc (e *ExpectedPrepare) WillReturnError(err error) *ExpectedPrepare {\n\te.err = err\n\treturn e\n}\n\n// WillReturnCloseError allows to set an error for this prepared statement Close action\nfunc (e *ExpectedPrepare) WillReturnCloseError(err error) *ExpectedPrepare {\n\te.closeErr = err\n\treturn e\n}\n\n// WillDelayFor allows to specify duration for which it will delay\n// result. May be used together with Context\nfunc (e *ExpectedPrepare) WillDelayFor(duration time.Duration) *ExpectedPrepare {\n\te.delay = duration\n\treturn e\n}\n\n// WillBeClosed expects this prepared statement to\n// be closed.\nfunc (e *ExpectedPrepare) WillBeClosed() *ExpectedPrepare {\n\te.mustBeClosed = true\n\treturn e\n}\n\n// ExpectQuery allows to expect Query() or QueryRow() on this prepared statement.\n// this method is convenient in order to prevent duplicating sql query string matching.\nfunc (e *ExpectedPrepare) ExpectQuery() *ExpectedQuery {\n\teq := &ExpectedQuery{}\n\teq.sqlRegex = e.sqlRegex\n\te.mock.expected = append(e.mock.expected, eq)\n\treturn eq\n}\n\n// ExpectExec allows to expect Exec() on this prepared statement.\n// this method is convenient in order to prevent duplicating sql query string matching.\nfunc (e *ExpectedPrepare) ExpectExec() *ExpectedExec {\n\teq := &ExpectedExec{}\n\teq.sqlRegex = e.sqlRegex\n\te.mock.expected = append(e.mock.expected, eq)\n\treturn eq\n}\n\n// String returns string representation\nfunc (e *ExpectedPrepare) String() string {\n\tmsg := \"ExpectedPrepare => expecting Prepare statement which:\"\n\tmsg += \"\\n  - matches sql: '\" + e.sqlRegex.String() + \"'\"\n\n\tif e.err != nil {\n\t\tmsg += fmt.Sprintf(\"\\n  - should return error: %s\", e.err)\n\t}\n\n\tif e.closeErr != nil {\n\t\tmsg += fmt.Sprintf(\"\\n  - should return error on Close: %s\", e.closeErr)\n\t}\n\n\treturn msg\n}\n\n// query based expectation\n// adds a query matching logic\ntype queryBasedExpectation struct {\n\tcommonExpectation\n\tsqlRegex *regexp.Regexp\n\targs     []driver.Value\n}\n\nfunc (e *queryBasedExpectation) attemptMatch(sql string, args []namedValue) (err error) {\n\tif !e.queryMatches(sql) {\n\t\treturn fmt.Errorf(`could not match sql: \"%s\" with expected regexp \"%s\"`, sql, e.sqlRegex.String())\n\t}\n\n\t// catch panic\n\tdefer func() {\n\t\tif e := recover(); e != nil {\n\t\t\t_, ok := e.(error)\n\t\t\tif !ok {\n\t\t\t\terr = fmt.Errorf(e.(string))\n\t\t\t}\n\t\t}\n\t}()\n\n\terr = e.argsMatches(args)\n\treturn\n}\n\nfunc (e *queryBasedExpectation) queryMatches(sql string) bool {\n\treturn e.sqlRegex.MatchString(sql)\n}\n"
  },
  {
    "path": "vendor/github.com/DATA-DOG/go-sqlmock/expectations_before_go18.go",
    "content": "// +build !go1.8\n\npackage sqlmock\n\nimport (\n\t\"database/sql/driver\"\n\t\"fmt\"\n\t\"reflect\"\n)\n\n// WillReturnRows specifies the set of resulting rows that will be returned\n// by the triggered query\nfunc (e *ExpectedQuery) WillReturnRows(rows *Rows) *ExpectedQuery {\n\te.rows = &rowSets{sets: []*Rows{rows}}\n\treturn e\n}\n\nfunc (e *queryBasedExpectation) argsMatches(args []namedValue) error {\n\tif nil == e.args {\n\t\treturn nil\n\t}\n\tif len(args) != len(e.args) {\n\t\treturn fmt.Errorf(\"expected %d, but got %d arguments\", len(e.args), len(args))\n\t}\n\tfor k, v := range args {\n\t\t// custom argument matcher\n\t\tmatcher, ok := e.args[k].(Argument)\n\t\tif ok {\n\t\t\t// @TODO: does it make sense to pass value instead of named value?\n\t\t\tif !matcher.Match(v.Value) {\n\t\t\t\treturn fmt.Errorf(\"matcher %T could not match %d argument %T - %+v\", matcher, k, args[k], args[k])\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tdval := e.args[k]\n\t\t// convert to driver converter\n\t\tdarg, err := driver.DefaultParameterConverter.ConvertValue(dval)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"could not convert %d argument %T - %+v to driver value: %s\", k, e.args[k], e.args[k], err)\n\t\t}\n\n\t\tif !driver.IsValue(darg) {\n\t\t\treturn fmt.Errorf(\"argument %d: non-subset type %T returned from Value\", k, darg)\n\t\t}\n\n\t\tif !reflect.DeepEqual(darg, v.Value) {\n\t\t\treturn fmt.Errorf(\"argument %d expected [%T - %+v] does not match actual [%T - %+v]\", k, darg, darg, v.Value, v.Value)\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/DATA-DOG/go-sqlmock/expectations_go18.go",
    "content": "// +build go1.8\n\npackage sqlmock\n\nimport (\n\t\"database/sql\"\n\t\"database/sql/driver\"\n\t\"fmt\"\n\t\"reflect\"\n)\n\n// WillReturnRows specifies the set of resulting rows that will be returned\n// by the triggered query\nfunc (e *ExpectedQuery) WillReturnRows(rows ...*Rows) *ExpectedQuery {\n\tsets := make([]*Rows, len(rows))\n\tfor i, r := range rows {\n\t\tsets[i] = r\n\t}\n\te.rows = &rowSets{sets: sets}\n\treturn e\n}\n\nfunc (e *queryBasedExpectation) argsMatches(args []namedValue) error {\n\tif nil == e.args {\n\t\treturn nil\n\t}\n\tif len(args) != len(e.args) {\n\t\treturn fmt.Errorf(\"expected %d, but got %d arguments\", len(e.args), len(args))\n\t}\n\t// @TODO should we assert either all args are named or ordinal?\n\tfor k, v := range args {\n\t\t// custom argument matcher\n\t\tmatcher, ok := e.args[k].(Argument)\n\t\tif ok {\n\t\t\tif !matcher.Match(v.Value) {\n\t\t\t\treturn fmt.Errorf(\"matcher %T could not match %d argument %T - %+v\", matcher, k, args[k], args[k])\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tdval := e.args[k]\n\t\tif named, isNamed := dval.(sql.NamedArg); isNamed {\n\t\t\tdval = named.Value\n\t\t\tif v.Name != named.Name {\n\t\t\t\treturn fmt.Errorf(\"named argument %d: name: \\\"%s\\\" does not match expected: \\\"%s\\\"\", k, v.Name, named.Name)\n\t\t\t}\n\t\t} else if k+1 != v.Ordinal {\n\t\t\treturn fmt.Errorf(\"argument %d: ordinal position: %d does not match expected: %d\", k, k+1, v.Ordinal)\n\t\t}\n\n\t\t// convert to driver converter\n\t\tdarg, err := driver.DefaultParameterConverter.ConvertValue(dval)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"could not convert %d argument %T - %+v to driver value: %s\", k, e.args[k], e.args[k], err)\n\t\t}\n\n\t\tif !driver.IsValue(darg) {\n\t\t\treturn fmt.Errorf(\"argument %d: non-subset type %T returned from Value\", k, darg)\n\t\t}\n\n\t\tif !reflect.DeepEqual(darg, v.Value) {\n\t\t\treturn fmt.Errorf(\"argument %d expected [%T - %+v] does not match actual [%T - %+v]\", k, darg, darg, v.Value, v.Value)\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/DATA-DOG/go-sqlmock/result.go",
    "content": "package sqlmock\n\nimport (\n\t\"database/sql/driver\"\n)\n\n// Result satisfies sql driver Result, which\n// holds last insert id and rows affected\n// by Exec queries\ntype result struct {\n\tinsertID     int64\n\trowsAffected int64\n\terr          error\n}\n\n// NewResult creates a new sql driver Result\n// for Exec based query mocks.\nfunc NewResult(lastInsertID int64, rowsAffected int64) driver.Result {\n\treturn &result{\n\t\tinsertID:     lastInsertID,\n\t\trowsAffected: rowsAffected,\n\t}\n}\n\n// NewErrorResult creates a new sql driver Result\n// which returns an error given for both interface methods\nfunc NewErrorResult(err error) driver.Result {\n\treturn &result{\n\t\terr: err,\n\t}\n}\n\nfunc (r *result) LastInsertId() (int64, error) {\n\treturn r.insertID, r.err\n}\n\nfunc (r *result) RowsAffected() (int64, error) {\n\treturn r.rowsAffected, r.err\n}\n"
  },
  {
    "path": "vendor/github.com/DATA-DOG/go-sqlmock/rows.go",
    "content": "package sqlmock\n\nimport (\n\t\"database/sql/driver\"\n\t\"encoding/csv\"\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n)\n\n// CSVColumnParser is a function which converts trimmed csv\n// column string to a []byte representation. currently\n// transforms NULL to nil\nvar CSVColumnParser = func(s string) []byte {\n\tswitch {\n\tcase strings.ToLower(s) == \"null\":\n\t\treturn nil\n\t}\n\treturn []byte(s)\n}\n\ntype rowSets struct {\n\tsets []*Rows\n\tpos  int\n}\n\nfunc (rs *rowSets) Columns() []string {\n\treturn rs.sets[rs.pos].cols\n}\n\nfunc (rs *rowSets) Close() error {\n\treturn rs.sets[rs.pos].closeErr\n}\n\n// advances to next row\nfunc (rs *rowSets) Next(dest []driver.Value) error {\n\tr := rs.sets[rs.pos]\n\tr.pos++\n\tif r.pos > len(r.rows) {\n\t\treturn io.EOF // per interface spec\n\t}\n\n\tfor i, col := range r.rows[r.pos-1] {\n\t\tdest[i] = col\n\t}\n\n\treturn r.nextErr[r.pos-1]\n}\n\n// transforms to debuggable printable string\nfunc (rs *rowSets) String() string {\n\tif rs.empty() {\n\t\treturn \"with empty rows\"\n\t}\n\n\tmsg := \"should return rows:\\n\"\n\tif len(rs.sets) == 1 {\n\t\tfor n, row := range rs.sets[0].rows {\n\t\t\tmsg += fmt.Sprintf(\"    row %d - %+v\\n\", n, row)\n\t\t}\n\t\treturn strings.TrimSpace(msg)\n\t}\n\tfor i, set := range rs.sets {\n\t\tmsg += fmt.Sprintf(\"    result set: %d\\n\", i)\n\t\tfor n, row := range set.rows {\n\t\t\tmsg += fmt.Sprintf(\"      row %d - %+v\\n\", n, row)\n\t\t}\n\t}\n\treturn strings.TrimSpace(msg)\n}\n\nfunc (rs *rowSets) empty() bool {\n\tfor _, set := range rs.sets {\n\t\tif len(set.rows) > 0 {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// Rows is a mocked collection of rows to\n// return for Query result\ntype Rows struct {\n\tcols     []string\n\trows     [][]driver.Value\n\tpos      int\n\tnextErr  map[int]error\n\tcloseErr error\n}\n\n// NewRows allows Rows to be created from a\n// sql driver.Value slice or from the CSV string and\n// to be used as sql driver.Rows\nfunc NewRows(columns []string) *Rows {\n\treturn &Rows{cols: columns, nextErr: make(map[int]error)}\n}\n\n// CloseError allows to set an error\n// which will be returned by rows.Close\n// function.\n//\n// The close error will be triggered only in cases\n// when rows.Next() EOF was not yet reached, that is\n// a default sql library behavior\nfunc (r *Rows) CloseError(err error) *Rows {\n\tr.closeErr = err\n\treturn r\n}\n\n// RowError allows to set an error\n// which will be returned when a given\n// row number is read\nfunc (r *Rows) RowError(row int, err error) *Rows {\n\tr.nextErr[row] = err\n\treturn r\n}\n\n// AddRow composed from database driver.Value slice\n// return the same instance to perform subsequent actions.\n// Note that the number of values must match the number\n// of columns\nfunc (r *Rows) AddRow(values ...driver.Value) *Rows {\n\tif len(values) != len(r.cols) {\n\t\tpanic(\"Expected number of values to match number of columns\")\n\t}\n\n\trow := make([]driver.Value, len(r.cols))\n\tfor i, v := range values {\n\t\trow[i] = v\n\t}\n\n\tr.rows = append(r.rows, row)\n\treturn r\n}\n\n// FromCSVString build rows from csv string.\n// return the same instance to perform subsequent actions.\n// Note that the number of values must match the number\n// of columns\nfunc (r *Rows) FromCSVString(s string) *Rows {\n\tres := strings.NewReader(strings.TrimSpace(s))\n\tcsvReader := csv.NewReader(res)\n\n\tfor {\n\t\tres, err := csvReader.Read()\n\t\tif err != nil || res == nil {\n\t\t\tbreak\n\t\t}\n\n\t\trow := make([]driver.Value, len(r.cols))\n\t\tfor i, v := range res {\n\t\t\trow[i] = CSVColumnParser(strings.TrimSpace(v))\n\t\t}\n\t\tr.rows = append(r.rows, row)\n\t}\n\treturn r\n}\n"
  },
  {
    "path": "vendor/github.com/DATA-DOG/go-sqlmock/rows_go18.go",
    "content": "// +build go1.8\n\npackage sqlmock\n\nimport \"io\"\n\n// Implement the \"RowsNextResultSet\" interface\nfunc (rs *rowSets) HasNextResultSet() bool {\n\treturn rs.pos+1 < len(rs.sets)\n}\n\n// Implement the \"RowsNextResultSet\" interface\nfunc (rs *rowSets) NextResultSet() error {\n\tif !rs.HasNextResultSet() {\n\t\treturn io.EOF\n\t}\n\n\trs.pos++\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/DATA-DOG/go-sqlmock/sqlmock.go",
    "content": "/*\nPackage sqlmock is a mock library implementing sql driver. Which has one and only\npurpose - to simulate any sql driver behavior in tests, without needing a real\ndatabase connection. It helps to maintain correct **TDD** workflow.\n\nIt does not require any modifications to your source code in order to test\nand mock database operations. Supports concurrency and multiple database mocking.\n\nThe driver allows to mock any sql driver method behavior.\n*/\npackage sqlmock\n\nimport (\n\t\"database/sql\"\n\t\"database/sql/driver\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"time\"\n)\n\n// Sqlmock interface serves to create expectations\n// for any kind of database action in order to mock\n// and test real database behavior.\ntype Sqlmock interface {\n\n\t// ExpectClose queues an expectation for this database\n\t// action to be triggered. the *ExpectedClose allows\n\t// to mock database response\n\tExpectClose() *ExpectedClose\n\n\t// ExpectationsWereMet checks whether all queued expectations\n\t// were met in order. If any of them was not met - an error is returned.\n\tExpectationsWereMet() error\n\n\t// ExpectPrepare expects Prepare() to be called with sql query\n\t// which match sqlRegexStr given regexp.\n\t// the *ExpectedPrepare allows to mock database response.\n\t// Note that you may expect Query() or Exec() on the *ExpectedPrepare\n\t// statement to prevent repeating sqlRegexStr\n\tExpectPrepare(sqlRegexStr string) *ExpectedPrepare\n\n\t// ExpectQuery expects Query() or QueryRow() to be called with sql query\n\t// which match sqlRegexStr given regexp.\n\t// the *ExpectedQuery allows to mock database response.\n\tExpectQuery(sqlRegexStr string) *ExpectedQuery\n\n\t// ExpectExec expects Exec() to be called with sql query\n\t// which match sqlRegexStr given regexp.\n\t// the *ExpectedExec allows to mock database response\n\tExpectExec(sqlRegexStr string) *ExpectedExec\n\n\t// ExpectBegin expects *sql.DB.Begin to be called.\n\t// the *ExpectedBegin allows to mock database response\n\tExpectBegin() *ExpectedBegin\n\n\t// ExpectCommit expects *sql.Tx.Commit to be called.\n\t// the *ExpectedCommit allows to mock database response\n\tExpectCommit() *ExpectedCommit\n\n\t// ExpectRollback expects *sql.Tx.Rollback to be called.\n\t// the *ExpectedRollback allows to mock database response\n\tExpectRollback() *ExpectedRollback\n\n\t// MatchExpectationsInOrder gives an option whether to match all\n\t// expectations in the order they were set or not.\n\t//\n\t// By default it is set to - true. But if you use goroutines\n\t// to parallelize your query executation, that option may\n\t// be handy.\n\t//\n\t// This option may be turned on anytime during tests. As soon\n\t// as it is switched to false, expectations will be matched\n\t// in any order. Or otherwise if switched to true, any unmatched\n\t// expectations will be expected in order\n\tMatchExpectationsInOrder(bool)\n}\n\ntype sqlmock struct {\n\tordered bool\n\tdsn     string\n\topened  int\n\tdrv     *mockDriver\n\n\texpected []expectation\n}\n\nfunc (c *sqlmock) open() (*sql.DB, Sqlmock, error) {\n\tdb, err := sql.Open(\"sqlmock\", c.dsn)\n\tif err != nil {\n\t\treturn db, c, err\n\t}\n\treturn db, c, db.Ping()\n}\n\nfunc (c *sqlmock) ExpectClose() *ExpectedClose {\n\te := &ExpectedClose{}\n\tc.expected = append(c.expected, e)\n\treturn e\n}\n\nfunc (c *sqlmock) MatchExpectationsInOrder(b bool) {\n\tc.ordered = b\n}\n\n// Close a mock database driver connection. It may or may not\n// be called depending on the sircumstances, but if it is called\n// there must be an *ExpectedClose expectation satisfied.\n// meets http://golang.org/pkg/database/sql/driver/#Conn interface\nfunc (c *sqlmock) Close() error {\n\tc.drv.Lock()\n\tdefer c.drv.Unlock()\n\n\tc.opened--\n\tif c.opened == 0 {\n\t\tdelete(c.drv.conns, c.dsn)\n\t}\n\n\tvar expected *ExpectedClose\n\tvar fulfilled int\n\tvar ok bool\n\tfor _, next := range c.expected {\n\t\tnext.Lock()\n\t\tif next.fulfilled() {\n\t\t\tnext.Unlock()\n\t\t\tfulfilled++\n\t\t\tcontinue\n\t\t}\n\n\t\tif expected, ok = next.(*ExpectedClose); ok {\n\t\t\tbreak\n\t\t}\n\n\t\tnext.Unlock()\n\t\tif c.ordered {\n\t\t\treturn fmt.Errorf(\"call to database Close, was not expected, next expectation is: %s\", next)\n\t\t}\n\t}\n\n\tif expected == nil {\n\t\tmsg := \"call to database Close was not expected\"\n\t\tif fulfilled == len(c.expected) {\n\t\t\tmsg = \"all expectations were already fulfilled, \" + msg\n\t\t}\n\t\treturn fmt.Errorf(msg)\n\t}\n\n\texpected.triggered = true\n\texpected.Unlock()\n\treturn expected.err\n}\n\nfunc (c *sqlmock) ExpectationsWereMet() error {\n\tfor _, e := range c.expected {\n\t\tif !e.fulfilled() {\n\t\t\treturn fmt.Errorf(\"there is a remaining expectation which was not matched: %s\", e)\n\t\t}\n\n\t\t// for expected prepared statement check whether it was closed if expected\n\t\tif prep, ok := e.(*ExpectedPrepare); ok {\n\t\t\tif prep.mustBeClosed && !prep.wasClosed {\n\t\t\t\treturn fmt.Errorf(\"expected prepared statement to be closed, but it was not: %s\", prep)\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// Begin meets http://golang.org/pkg/database/sql/driver/#Conn interface\nfunc (c *sqlmock) Begin() (driver.Tx, error) {\n\tex, err := c.begin()\n\tif ex != nil {\n\t\ttime.Sleep(ex.delay)\n\t}\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn c, nil\n}\n\nfunc (c *sqlmock) begin() (*ExpectedBegin, error) {\n\tvar expected *ExpectedBegin\n\tvar ok bool\n\tvar fulfilled int\n\tfor _, next := range c.expected {\n\t\tnext.Lock()\n\t\tif next.fulfilled() {\n\t\t\tnext.Unlock()\n\t\t\tfulfilled++\n\t\t\tcontinue\n\t\t}\n\n\t\tif expected, ok = next.(*ExpectedBegin); ok {\n\t\t\tbreak\n\t\t}\n\n\t\tnext.Unlock()\n\t\tif c.ordered {\n\t\t\treturn nil, fmt.Errorf(\"call to database transaction Begin, was not expected, next expectation is: %s\", next)\n\t\t}\n\t}\n\tif expected == nil {\n\t\tmsg := \"call to database transaction Begin was not expected\"\n\t\tif fulfilled == len(c.expected) {\n\t\t\tmsg = \"all expectations were already fulfilled, \" + msg\n\t\t}\n\t\treturn nil, fmt.Errorf(msg)\n\t}\n\n\texpected.triggered = true\n\texpected.Unlock()\n\n\treturn expected, expected.err\n}\n\nfunc (c *sqlmock) ExpectBegin() *ExpectedBegin {\n\te := &ExpectedBegin{}\n\tc.expected = append(c.expected, e)\n\treturn e\n}\n\n// Exec meets http://golang.org/pkg/database/sql/driver/#Execer\nfunc (c *sqlmock) Exec(query string, args []driver.Value) (driver.Result, error) {\n\tnamedArgs := make([]namedValue, len(args))\n\tfor i, v := range args {\n\t\tnamedArgs[i] = namedValue{\n\t\t\tOrdinal: i + 1,\n\t\t\tValue:   v,\n\t\t}\n\t}\n\n\tex, err := c.exec(query, namedArgs)\n\tif ex != nil {\n\t\ttime.Sleep(ex.delay)\n\t}\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn ex.result, nil\n}\n\nfunc (c *sqlmock) exec(query string, args []namedValue) (*ExpectedExec, error) {\n\tquery = stripQuery(query)\n\tvar expected *ExpectedExec\n\tvar fulfilled int\n\tvar ok bool\n\tfor _, next := range c.expected {\n\t\tnext.Lock()\n\t\tif next.fulfilled() {\n\t\t\tnext.Unlock()\n\t\t\tfulfilled++\n\t\t\tcontinue\n\t\t}\n\n\t\tif c.ordered {\n\t\t\tif expected, ok = next.(*ExpectedExec); ok {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tnext.Unlock()\n\t\t\treturn nil, fmt.Errorf(\"call to ExecQuery '%s' with args %+v, was not expected, next expectation is: %s\", query, args, next)\n\t\t}\n\t\tif exec, ok := next.(*ExpectedExec); ok {\n\t\t\tif err := exec.attemptMatch(query, args); err == nil {\n\t\t\t\texpected = exec\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tnext.Unlock()\n\t}\n\tif expected == nil {\n\t\tmsg := \"call to ExecQuery '%s' with args %+v was not expected\"\n\t\tif fulfilled == len(c.expected) {\n\t\t\tmsg = \"all expectations were already fulfilled, \" + msg\n\t\t}\n\t\treturn nil, fmt.Errorf(msg, query, args)\n\t}\n\tdefer expected.Unlock()\n\n\tif !expected.queryMatches(query) {\n\t\treturn nil, fmt.Errorf(\"ExecQuery '%s', does not match regex '%s'\", query, expected.sqlRegex.String())\n\t}\n\n\tif err := expected.argsMatches(args); err != nil {\n\t\treturn nil, fmt.Errorf(\"ExecQuery '%s', arguments do not match: %s\", query, err)\n\t}\n\n\texpected.triggered = true\n\tif expected.err != nil {\n\t\treturn expected, expected.err // mocked to return error\n\t}\n\n\tif expected.result == nil {\n\t\treturn nil, fmt.Errorf(\"ExecQuery '%s' with args %+v, must return a database/sql/driver.Result, but it was not set for expectation %T as %+v\", query, args, expected, expected)\n\t}\n\n\treturn expected, nil\n}\n\nfunc (c *sqlmock) ExpectExec(sqlRegexStr string) *ExpectedExec {\n\te := &ExpectedExec{}\n\tsqlRegexStr = stripQuery(sqlRegexStr)\n\te.sqlRegex = regexp.MustCompile(sqlRegexStr)\n\tc.expected = append(c.expected, e)\n\treturn e\n}\n\n// Prepare meets http://golang.org/pkg/database/sql/driver/#Conn interface\nfunc (c *sqlmock) Prepare(query string) (driver.Stmt, error) {\n\tex, err := c.prepare(query)\n\tif ex != nil {\n\t\ttime.Sleep(ex.delay)\n\t}\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &statement{c, ex, query}, nil\n}\n\nfunc (c *sqlmock) prepare(query string) (*ExpectedPrepare, error) {\n\tvar expected *ExpectedPrepare\n\tvar fulfilled int\n\tvar ok bool\n\n\tquery = stripQuery(query)\n\n\tfor _, next := range c.expected {\n\t\tnext.Lock()\n\t\tif next.fulfilled() {\n\t\t\tnext.Unlock()\n\t\t\tfulfilled++\n\t\t\tcontinue\n\t\t}\n\n\t\tif c.ordered {\n\t\t\tif expected, ok = next.(*ExpectedPrepare); ok {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tnext.Unlock()\n\t\t\treturn nil, fmt.Errorf(\"call to Prepare statement with query '%s', was not expected, next expectation is: %s\", query, next)\n\t\t}\n\n\t\tif pr, ok := next.(*ExpectedPrepare); ok {\n\t\t\tif pr.sqlRegex.MatchString(query) {\n\t\t\t\texpected = pr\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tnext.Unlock()\n\t}\n\n\tif expected == nil {\n\t\tmsg := \"call to Prepare '%s' query was not expected\"\n\t\tif fulfilled == len(c.expected) {\n\t\t\tmsg = \"all expectations were already fulfilled, \" + msg\n\t\t}\n\t\treturn nil, fmt.Errorf(msg, query)\n\t}\n\tdefer expected.Unlock()\n\tif !expected.sqlRegex.MatchString(query) {\n\t\treturn nil, fmt.Errorf(\"Prepare query string '%s', does not match regex [%s]\", query, expected.sqlRegex.String())\n\t}\n\n\texpected.triggered = true\n\treturn expected, expected.err\n}\n\nfunc (c *sqlmock) ExpectPrepare(sqlRegexStr string) *ExpectedPrepare {\n\tsqlRegexStr = stripQuery(sqlRegexStr)\n\te := &ExpectedPrepare{sqlRegex: regexp.MustCompile(sqlRegexStr), mock: c}\n\tc.expected = append(c.expected, e)\n\treturn e\n}\n\ntype namedValue struct {\n\tName    string\n\tOrdinal int\n\tValue   driver.Value\n}\n\n// Query meets http://golang.org/pkg/database/sql/driver/#Queryer\nfunc (c *sqlmock) Query(query string, args []driver.Value) (driver.Rows, error) {\n\tnamedArgs := make([]namedValue, len(args))\n\tfor i, v := range args {\n\t\tnamedArgs[i] = namedValue{\n\t\t\tOrdinal: i + 1,\n\t\t\tValue:   v,\n\t\t}\n\t}\n\n\tex, err := c.query(query, namedArgs)\n\tif ex != nil {\n\t\ttime.Sleep(ex.delay)\n\t}\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn ex.rows, nil\n}\n\nfunc (c *sqlmock) query(query string, args []namedValue) (*ExpectedQuery, error) {\n\tquery = stripQuery(query)\n\tvar expected *ExpectedQuery\n\tvar fulfilled int\n\tvar ok bool\n\tfor _, next := range c.expected {\n\t\tnext.Lock()\n\t\tif next.fulfilled() {\n\t\t\tnext.Unlock()\n\t\t\tfulfilled++\n\t\t\tcontinue\n\t\t}\n\n\t\tif c.ordered {\n\t\t\tif expected, ok = next.(*ExpectedQuery); ok {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tnext.Unlock()\n\t\t\treturn nil, fmt.Errorf(\"call to Query '%s' with args %+v, was not expected, next expectation is: %s\", query, args, next)\n\t\t}\n\t\tif qr, ok := next.(*ExpectedQuery); ok {\n\t\t\tif err := qr.attemptMatch(query, args); err == nil {\n\t\t\t\texpected = qr\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tnext.Unlock()\n\t}\n\n\tif expected == nil {\n\t\tmsg := \"call to Query '%s' with args %+v was not expected\"\n\t\tif fulfilled == len(c.expected) {\n\t\t\tmsg = \"all expectations were already fulfilled, \" + msg\n\t\t}\n\t\treturn nil, fmt.Errorf(msg, query, args)\n\t}\n\n\tdefer expected.Unlock()\n\n\tif !expected.queryMatches(query) {\n\t\treturn nil, fmt.Errorf(\"Query '%s', does not match regex [%s]\", query, expected.sqlRegex.String())\n\t}\n\n\tif err := expected.argsMatches(args); err != nil {\n\t\treturn nil, fmt.Errorf(\"Query '%s', arguments do not match: %s\", query, err)\n\t}\n\n\texpected.triggered = true\n\tif expected.err != nil {\n\t\treturn expected, expected.err // mocked to return error\n\t}\n\n\tif expected.rows == nil {\n\t\treturn nil, fmt.Errorf(\"Query '%s' with args %+v, must return a database/sql/driver.Rows, but it was not set for expectation %T as %+v\", query, args, expected, expected)\n\t}\n\treturn expected, nil\n}\n\nfunc (c *sqlmock) ExpectQuery(sqlRegexStr string) *ExpectedQuery {\n\te := &ExpectedQuery{}\n\tsqlRegexStr = stripQuery(sqlRegexStr)\n\te.sqlRegex = regexp.MustCompile(sqlRegexStr)\n\tc.expected = append(c.expected, e)\n\treturn e\n}\n\nfunc (c *sqlmock) ExpectCommit() *ExpectedCommit {\n\te := &ExpectedCommit{}\n\tc.expected = append(c.expected, e)\n\treturn e\n}\n\nfunc (c *sqlmock) ExpectRollback() *ExpectedRollback {\n\te := &ExpectedRollback{}\n\tc.expected = append(c.expected, e)\n\treturn e\n}\n\n// Commit meets http://golang.org/pkg/database/sql/driver/#Tx\nfunc (c *sqlmock) Commit() error {\n\tvar expected *ExpectedCommit\n\tvar fulfilled int\n\tvar ok bool\n\tfor _, next := range c.expected {\n\t\tnext.Lock()\n\t\tif next.fulfilled() {\n\t\t\tnext.Unlock()\n\t\t\tfulfilled++\n\t\t\tcontinue\n\t\t}\n\n\t\tif expected, ok = next.(*ExpectedCommit); ok {\n\t\t\tbreak\n\t\t}\n\n\t\tnext.Unlock()\n\t\tif c.ordered {\n\t\t\treturn fmt.Errorf(\"call to Commit transaction, was not expected, next expectation is: %s\", next)\n\t\t}\n\t}\n\tif expected == nil {\n\t\tmsg := \"call to Commit transaction was not expected\"\n\t\tif fulfilled == len(c.expected) {\n\t\t\tmsg = \"all expectations were already fulfilled, \" + msg\n\t\t}\n\t\treturn fmt.Errorf(msg)\n\t}\n\n\texpected.triggered = true\n\texpected.Unlock()\n\treturn expected.err\n}\n\n// Rollback meets http://golang.org/pkg/database/sql/driver/#Tx\nfunc (c *sqlmock) Rollback() error {\n\tvar expected *ExpectedRollback\n\tvar fulfilled int\n\tvar ok bool\n\tfor _, next := range c.expected {\n\t\tnext.Lock()\n\t\tif next.fulfilled() {\n\t\t\tnext.Unlock()\n\t\t\tfulfilled++\n\t\t\tcontinue\n\t\t}\n\n\t\tif expected, ok = next.(*ExpectedRollback); ok {\n\t\t\tbreak\n\t\t}\n\n\t\tnext.Unlock()\n\t\tif c.ordered {\n\t\t\treturn fmt.Errorf(\"call to Rollback transaction, was not expected, next expectation is: %s\", next)\n\t\t}\n\t}\n\tif expected == nil {\n\t\tmsg := \"call to Rollback transaction was not expected\"\n\t\tif fulfilled == len(c.expected) {\n\t\t\tmsg = \"all expectations were already fulfilled, \" + msg\n\t\t}\n\t\treturn fmt.Errorf(msg)\n\t}\n\n\texpected.triggered = true\n\texpected.Unlock()\n\treturn expected.err\n}\n"
  },
  {
    "path": "vendor/github.com/DATA-DOG/go-sqlmock/sqlmock_go18.go",
    "content": "// +build go1.8\n\npackage sqlmock\n\nimport (\n\t\"context\"\n\t\"database/sql/driver\"\n\t\"errors\"\n\t\"time\"\n)\n\nvar ErrCancelled = errors.New(\"canceling query due to user request\")\n\n// Implement the \"QueryerContext\" interface\nfunc (c *sqlmock) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {\n\tnamedArgs := make([]namedValue, len(args))\n\tfor i, nv := range args {\n\t\tnamedArgs[i] = namedValue(nv)\n\t}\n\n\tex, err := c.query(query, namedArgs)\n\tif ex != nil {\n\t\tselect {\n\t\tcase <-time.After(ex.delay):\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn ex.rows, nil\n\t\tcase <-ctx.Done():\n\t\t\treturn nil, ErrCancelled\n\t\t}\n\t}\n\n\treturn nil, err\n}\n\n// Implement the \"ExecerContext\" interface\nfunc (c *sqlmock) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {\n\tnamedArgs := make([]namedValue, len(args))\n\tfor i, nv := range args {\n\t\tnamedArgs[i] = namedValue(nv)\n\t}\n\n\tex, err := c.exec(query, namedArgs)\n\tif ex != nil {\n\t\tselect {\n\t\tcase <-time.After(ex.delay):\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn ex.result, nil\n\t\tcase <-ctx.Done():\n\t\t\treturn nil, ErrCancelled\n\t\t}\n\t}\n\n\treturn nil, err\n}\n\n// Implement the \"ConnBeginTx\" interface\nfunc (c *sqlmock) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {\n\tex, err := c.begin()\n\tif ex != nil {\n\t\tselect {\n\t\tcase <-time.After(ex.delay):\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn c, nil\n\t\tcase <-ctx.Done():\n\t\t\treturn nil, ErrCancelled\n\t\t}\n\t}\n\n\treturn nil, err\n}\n\n// Implement the \"ConnPrepareContext\" interface\nfunc (c *sqlmock) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) {\n\tex, err := c.prepare(query)\n\tif ex != nil {\n\t\tselect {\n\t\tcase <-time.After(ex.delay):\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn &statement{c, ex, query}, nil\n\t\tcase <-ctx.Done():\n\t\t\treturn nil, ErrCancelled\n\t\t}\n\t}\n\n\treturn nil, err\n}\n\n// Implement the \"Pinger\" interface\n// for now we do not have a Ping expectation\n// may be something for the future\nfunc (c *sqlmock) Ping(ctx context.Context) error {\n\treturn nil\n}\n\n// Implement the \"StmtExecContext\" interface\nfunc (stmt *statement) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {\n\treturn stmt.conn.ExecContext(ctx, stmt.query, args)\n}\n\n// Implement the \"StmtQueryContext\" interface\nfunc (stmt *statement) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {\n\treturn stmt.conn.QueryContext(ctx, stmt.query, args)\n}\n\n// @TODO maybe add ExpectedBegin.WithOptions(driver.TxOptions)\n"
  },
  {
    "path": "vendor/github.com/DATA-DOG/go-sqlmock/statement.go",
    "content": "package sqlmock\n\nimport (\n\t\"database/sql/driver\"\n)\n\ntype statement struct {\n\tconn  *sqlmock\n\tex    *ExpectedPrepare\n\tquery string\n}\n\nfunc (stmt *statement) Close() error {\n\tstmt.ex.wasClosed = true\n\treturn stmt.ex.closeErr\n}\n\nfunc (stmt *statement) NumInput() int {\n\treturn -1\n}\n\nfunc (stmt *statement) Exec(args []driver.Value) (driver.Result, error) {\n\treturn stmt.conn.Exec(stmt.query, args)\n}\n\nfunc (stmt *statement) Query(args []driver.Value) (driver.Rows, error) {\n\treturn stmt.conn.Query(stmt.query, args)\n}\n"
  },
  {
    "path": "vendor/github.com/DATA-DOG/go-sqlmock/util.go",
    "content": "package sqlmock\n\nimport (\n\t\"regexp\"\n\t\"strings\"\n)\n\nvar re = regexp.MustCompile(\"\\\\s+\")\n\n// strip out new lines and trim spaces\nfunc stripQuery(q string) (s string) {\n\treturn strings.TrimSpace(re.ReplaceAllString(q, \" \"))\n}\n"
  },
  {
    "path": "vendor/github.com/davecgh/go-spew/LICENSE",
    "content": "ISC License\n\nCopyright (c) 2012-2013 Dave Collins <dave@davec.name>\n\nPermission to use, copy, modify, and distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\nANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\nOR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n"
  },
  {
    "path": "vendor/github.com/davecgh/go-spew/spew/bypass.go",
    "content": "// Copyright (c) 2015 Dave Collins <dave@davec.name>\n//\n// Permission to use, copy, modify, and distribute this software for any\n// purpose with or without fee is hereby granted, provided that the above\n// copyright notice and this permission notice appear in all copies.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n\n// NOTE: Due to the following build constraints, this file will only be compiled\n// when the code is not running on Google App Engine, compiled by GopherJS, and\n// \"-tags safe\" is not added to the go build command line.  The \"disableunsafe\"\n// tag is deprecated and thus should not be used.\n// +build !js,!appengine,!safe,!disableunsafe\n\npackage spew\n\nimport (\n\t\"reflect\"\n\t\"unsafe\"\n)\n\nconst (\n\t// UnsafeDisabled is a build-time constant which specifies whether or\n\t// not access to the unsafe package is available.\n\tUnsafeDisabled = false\n\n\t// ptrSize is the size of a pointer on the current arch.\n\tptrSize = unsafe.Sizeof((*byte)(nil))\n)\n\nvar (\n\t// offsetPtr, offsetScalar, and offsetFlag are the offsets for the\n\t// internal reflect.Value fields.  These values are valid before golang\n\t// commit ecccf07e7f9d which changed the format.  The are also valid\n\t// after commit 82f48826c6c7 which changed the format again to mirror\n\t// the original format.  Code in the init function updates these offsets\n\t// as necessary.\n\toffsetPtr    = uintptr(ptrSize)\n\toffsetScalar = uintptr(0)\n\toffsetFlag   = uintptr(ptrSize * 2)\n\n\t// flagKindWidth and flagKindShift indicate various bits that the\n\t// reflect package uses internally to track kind information.\n\t//\n\t// flagRO indicates whether or not the value field of a reflect.Value is\n\t// read-only.\n\t//\n\t// flagIndir indicates whether the value field of a reflect.Value is\n\t// the actual data or a pointer to the data.\n\t//\n\t// These values are valid before golang commit 90a7c3c86944 which\n\t// changed their positions.  Code in the init function updates these\n\t// flags as necessary.\n\tflagKindWidth = uintptr(5)\n\tflagKindShift = uintptr(flagKindWidth - 1)\n\tflagRO        = uintptr(1 << 0)\n\tflagIndir     = uintptr(1 << 1)\n)\n\nfunc init() {\n\t// Older versions of reflect.Value stored small integers directly in the\n\t// ptr field (which is named val in the older versions).  Versions\n\t// between commits ecccf07e7f9d and 82f48826c6c7 added a new field named\n\t// scalar for this purpose which unfortunately came before the flag\n\t// field, so the offset of the flag field is different for those\n\t// versions.\n\t//\n\t// This code constructs a new reflect.Value from a known small integer\n\t// and checks if the size of the reflect.Value struct indicates it has\n\t// the scalar field. When it does, the offsets are updated accordingly.\n\tvv := reflect.ValueOf(0xf00)\n\tif unsafe.Sizeof(vv) == (ptrSize * 4) {\n\t\toffsetScalar = ptrSize * 2\n\t\toffsetFlag = ptrSize * 3\n\t}\n\n\t// Commit 90a7c3c86944 changed the flag positions such that the low\n\t// order bits are the kind.  This code extracts the kind from the flags\n\t// field and ensures it's the correct type.  When it's not, the flag\n\t// order has been changed to the newer format, so the flags are updated\n\t// accordingly.\n\tupf := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) + offsetFlag)\n\tupfv := *(*uintptr)(upf)\n\tflagKindMask := uintptr((1<<flagKindWidth - 1) << flagKindShift)\n\tif (upfv&flagKindMask)>>flagKindShift != uintptr(reflect.Int) {\n\t\tflagKindShift = 0\n\t\tflagRO = 1 << 5\n\t\tflagIndir = 1 << 6\n\n\t\t// Commit adf9b30e5594 modified the flags to separate the\n\t\t// flagRO flag into two bits which specifies whether or not the\n\t\t// field is embedded.  This causes flagIndir to move over a bit\n\t\t// and means that flagRO is the combination of either of the\n\t\t// original flagRO bit and the new bit.\n\t\t//\n\t\t// This code detects the change by extracting what used to be\n\t\t// the indirect bit to ensure it's set.  When it's not, the flag\n\t\t// order has been changed to the newer format, so the flags are\n\t\t// updated accordingly.\n\t\tif upfv&flagIndir == 0 {\n\t\t\tflagRO = 3 << 5\n\t\t\tflagIndir = 1 << 7\n\t\t}\n\t}\n}\n\n// unsafeReflectValue converts the passed reflect.Value into a one that bypasses\n// the typical safety restrictions preventing access to unaddressable and\n// unexported data.  It works by digging the raw pointer to the underlying\n// value out of the protected value and generating a new unprotected (unsafe)\n// reflect.Value to it.\n//\n// This allows us to check for implementations of the Stringer and error\n// interfaces to be used for pretty printing ordinarily unaddressable and\n// inaccessible values such as unexported struct fields.\nfunc unsafeReflectValue(v reflect.Value) (rv reflect.Value) {\n\tindirects := 1\n\tvt := v.Type()\n\tupv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr)\n\trvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag))\n\tif rvf&flagIndir != 0 {\n\t\tvt = reflect.PtrTo(v.Type())\n\t\tindirects++\n\t} else if offsetScalar != 0 {\n\t\t// The value is in the scalar field when it's not one of the\n\t\t// reference types.\n\t\tswitch vt.Kind() {\n\t\tcase reflect.Uintptr:\n\t\tcase reflect.Chan:\n\t\tcase reflect.Func:\n\t\tcase reflect.Map:\n\t\tcase reflect.Ptr:\n\t\tcase reflect.UnsafePointer:\n\t\tdefault:\n\t\t\tupv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) +\n\t\t\t\toffsetScalar)\n\t\t}\n\t}\n\n\tpv := reflect.NewAt(vt, upv)\n\trv = pv\n\tfor i := 0; i < indirects; i++ {\n\t\trv = rv.Elem()\n\t}\n\treturn rv\n}\n"
  },
  {
    "path": "vendor/github.com/davecgh/go-spew/spew/bypasssafe.go",
    "content": "// Copyright (c) 2015 Dave Collins <dave@davec.name>\n//\n// Permission to use, copy, modify, and distribute this software for any\n// purpose with or without fee is hereby granted, provided that the above\n// copyright notice and this permission notice appear in all copies.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n\n// NOTE: Due to the following build constraints, this file will only be compiled\n// when the code is running on Google App Engine, compiled by GopherJS, or\n// \"-tags safe\" is added to the go build command line.  The \"disableunsafe\"\n// tag is deprecated and thus should not be used.\n// +build js appengine safe disableunsafe\n\npackage spew\n\nimport \"reflect\"\n\nconst (\n\t// UnsafeDisabled is a build-time constant which specifies whether or\n\t// not access to the unsafe package is available.\n\tUnsafeDisabled = true\n)\n\n// unsafeReflectValue typically converts the passed reflect.Value into a one\n// that bypasses the typical safety restrictions preventing access to\n// unaddressable and unexported data.  However, doing this relies on access to\n// the unsafe package.  This is a stub version which simply returns the passed\n// reflect.Value when the unsafe package is not available.\nfunc unsafeReflectValue(v reflect.Value) reflect.Value {\n\treturn v\n}\n"
  },
  {
    "path": "vendor/github.com/davecgh/go-spew/spew/common.go",
    "content": "/*\n * Copyright (c) 2013 Dave Collins <dave@davec.name>\n *\n * Permission to use, copy, modify, and distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\npackage spew\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"reflect\"\n\t\"sort\"\n\t\"strconv\"\n)\n\n// Some constants in the form of bytes to avoid string overhead.  This mirrors\n// the technique used in the fmt package.\nvar (\n\tpanicBytes            = []byte(\"(PANIC=\")\n\tplusBytes             = []byte(\"+\")\n\tiBytes                = []byte(\"i\")\n\ttrueBytes             = []byte(\"true\")\n\tfalseBytes            = []byte(\"false\")\n\tinterfaceBytes        = []byte(\"(interface {})\")\n\tcommaNewlineBytes     = []byte(\",\\n\")\n\tnewlineBytes          = []byte(\"\\n\")\n\topenBraceBytes        = []byte(\"{\")\n\topenBraceNewlineBytes = []byte(\"{\\n\")\n\tcloseBraceBytes       = []byte(\"}\")\n\tasteriskBytes         = []byte(\"*\")\n\tcolonBytes            = []byte(\":\")\n\tcolonSpaceBytes       = []byte(\": \")\n\topenParenBytes        = []byte(\"(\")\n\tcloseParenBytes       = []byte(\")\")\n\tspaceBytes            = []byte(\" \")\n\tpointerChainBytes     = []byte(\"->\")\n\tnilAngleBytes         = []byte(\"<nil>\")\n\tmaxNewlineBytes       = []byte(\"<max depth reached>\\n\")\n\tmaxShortBytes         = []byte(\"<max>\")\n\tcircularBytes         = []byte(\"<already shown>\")\n\tcircularShortBytes    = []byte(\"<shown>\")\n\tinvalidAngleBytes     = []byte(\"<invalid>\")\n\topenBracketBytes      = []byte(\"[\")\n\tcloseBracketBytes     = []byte(\"]\")\n\tpercentBytes          = []byte(\"%\")\n\tprecisionBytes        = []byte(\".\")\n\topenAngleBytes        = []byte(\"<\")\n\tcloseAngleBytes       = []byte(\">\")\n\topenMapBytes          = []byte(\"map[\")\n\tcloseMapBytes         = []byte(\"]\")\n\tlenEqualsBytes        = []byte(\"len=\")\n\tcapEqualsBytes        = []byte(\"cap=\")\n)\n\n// hexDigits is used to map a decimal value to a hex digit.\nvar hexDigits = \"0123456789abcdef\"\n\n// catchPanic handles any panics that might occur during the handleMethods\n// calls.\nfunc catchPanic(w io.Writer, v reflect.Value) {\n\tif err := recover(); err != nil {\n\t\tw.Write(panicBytes)\n\t\tfmt.Fprintf(w, \"%v\", err)\n\t\tw.Write(closeParenBytes)\n\t}\n}\n\n// handleMethods attempts to call the Error and String methods on the underlying\n// type the passed reflect.Value represents and outputes the result to Writer w.\n//\n// It handles panics in any called methods by catching and displaying the error\n// as the formatted value.\nfunc handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool) {\n\t// We need an interface to check if the type implements the error or\n\t// Stringer interface.  However, the reflect package won't give us an\n\t// interface on certain things like unexported struct fields in order\n\t// to enforce visibility rules.  We use unsafe, when it's available,\n\t// to bypass these restrictions since this package does not mutate the\n\t// values.\n\tif !v.CanInterface() {\n\t\tif UnsafeDisabled {\n\t\t\treturn false\n\t\t}\n\n\t\tv = unsafeReflectValue(v)\n\t}\n\n\t// Choose whether or not to do error and Stringer interface lookups against\n\t// the base type or a pointer to the base type depending on settings.\n\t// Technically calling one of these methods with a pointer receiver can\n\t// mutate the value, however, types which choose to satisify an error or\n\t// Stringer interface with a pointer receiver should not be mutating their\n\t// state inside these interface methods.\n\tif !cs.DisablePointerMethods && !UnsafeDisabled && !v.CanAddr() {\n\t\tv = unsafeReflectValue(v)\n\t}\n\tif v.CanAddr() {\n\t\tv = v.Addr()\n\t}\n\n\t// Is it an error or Stringer?\n\tswitch iface := v.Interface().(type) {\n\tcase error:\n\t\tdefer catchPanic(w, v)\n\t\tif cs.ContinueOnMethod {\n\t\t\tw.Write(openParenBytes)\n\t\t\tw.Write([]byte(iface.Error()))\n\t\t\tw.Write(closeParenBytes)\n\t\t\tw.Write(spaceBytes)\n\t\t\treturn false\n\t\t}\n\n\t\tw.Write([]byte(iface.Error()))\n\t\treturn true\n\n\tcase fmt.Stringer:\n\t\tdefer catchPanic(w, v)\n\t\tif cs.ContinueOnMethod {\n\t\t\tw.Write(openParenBytes)\n\t\t\tw.Write([]byte(iface.String()))\n\t\t\tw.Write(closeParenBytes)\n\t\t\tw.Write(spaceBytes)\n\t\t\treturn false\n\t\t}\n\t\tw.Write([]byte(iface.String()))\n\t\treturn true\n\t}\n\treturn false\n}\n\n// printBool outputs a boolean value as true or false to Writer w.\nfunc printBool(w io.Writer, val bool) {\n\tif val {\n\t\tw.Write(trueBytes)\n\t} else {\n\t\tw.Write(falseBytes)\n\t}\n}\n\n// printInt outputs a signed integer value to Writer w.\nfunc printInt(w io.Writer, val int64, base int) {\n\tw.Write([]byte(strconv.FormatInt(val, base)))\n}\n\n// printUint outputs an unsigned integer value to Writer w.\nfunc printUint(w io.Writer, val uint64, base int) {\n\tw.Write([]byte(strconv.FormatUint(val, base)))\n}\n\n// printFloat outputs a floating point value using the specified precision,\n// which is expected to be 32 or 64bit, to Writer w.\nfunc printFloat(w io.Writer, val float64, precision int) {\n\tw.Write([]byte(strconv.FormatFloat(val, 'g', -1, precision)))\n}\n\n// printComplex outputs a complex value using the specified float precision\n// for the real and imaginary parts to Writer w.\nfunc printComplex(w io.Writer, c complex128, floatPrecision int) {\n\tr := real(c)\n\tw.Write(openParenBytes)\n\tw.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision)))\n\ti := imag(c)\n\tif i >= 0 {\n\t\tw.Write(plusBytes)\n\t}\n\tw.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision)))\n\tw.Write(iBytes)\n\tw.Write(closeParenBytes)\n}\n\n// printHexPtr outputs a uintptr formatted as hexidecimal with a leading '0x'\n// prefix to Writer w.\nfunc printHexPtr(w io.Writer, p uintptr) {\n\t// Null pointer.\n\tnum := uint64(p)\n\tif num == 0 {\n\t\tw.Write(nilAngleBytes)\n\t\treturn\n\t}\n\n\t// Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix\n\tbuf := make([]byte, 18)\n\n\t// It's simpler to construct the hex string right to left.\n\tbase := uint64(16)\n\ti := len(buf) - 1\n\tfor num >= base {\n\t\tbuf[i] = hexDigits[num%base]\n\t\tnum /= base\n\t\ti--\n\t}\n\tbuf[i] = hexDigits[num]\n\n\t// Add '0x' prefix.\n\ti--\n\tbuf[i] = 'x'\n\ti--\n\tbuf[i] = '0'\n\n\t// Strip unused leading bytes.\n\tbuf = buf[i:]\n\tw.Write(buf)\n}\n\n// valuesSorter implements sort.Interface to allow a slice of reflect.Value\n// elements to be sorted.\ntype valuesSorter struct {\n\tvalues  []reflect.Value\n\tstrings []string // either nil or same len and values\n\tcs      *ConfigState\n}\n\n// newValuesSorter initializes a valuesSorter instance, which holds a set of\n// surrogate keys on which the data should be sorted.  It uses flags in\n// ConfigState to decide if and how to populate those surrogate keys.\nfunc newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Interface {\n\tvs := &valuesSorter{values: values, cs: cs}\n\tif canSortSimply(vs.values[0].Kind()) {\n\t\treturn vs\n\t}\n\tif !cs.DisableMethods {\n\t\tvs.strings = make([]string, len(values))\n\t\tfor i := range vs.values {\n\t\t\tb := bytes.Buffer{}\n\t\t\tif !handleMethods(cs, &b, vs.values[i]) {\n\t\t\t\tvs.strings = nil\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tvs.strings[i] = b.String()\n\t\t}\n\t}\n\tif vs.strings == nil && cs.SpewKeys {\n\t\tvs.strings = make([]string, len(values))\n\t\tfor i := range vs.values {\n\t\t\tvs.strings[i] = Sprintf(\"%#v\", vs.values[i].Interface())\n\t\t}\n\t}\n\treturn vs\n}\n\n// canSortSimply tests whether a reflect.Kind is a primitive that can be sorted\n// directly, or whether it should be considered for sorting by surrogate keys\n// (if the ConfigState allows it).\nfunc canSortSimply(kind reflect.Kind) bool {\n\t// This switch parallels valueSortLess, except for the default case.\n\tswitch kind {\n\tcase reflect.Bool:\n\t\treturn true\n\tcase reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:\n\t\treturn true\n\tcase reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:\n\t\treturn true\n\tcase reflect.Float32, reflect.Float64:\n\t\treturn true\n\tcase reflect.String:\n\t\treturn true\n\tcase reflect.Uintptr:\n\t\treturn true\n\tcase reflect.Array:\n\t\treturn true\n\t}\n\treturn false\n}\n\n// Len returns the number of values in the slice.  It is part of the\n// sort.Interface implementation.\nfunc (s *valuesSorter) Len() int {\n\treturn len(s.values)\n}\n\n// Swap swaps the values at the passed indices.  It is part of the\n// sort.Interface implementation.\nfunc (s *valuesSorter) Swap(i, j int) {\n\ts.values[i], s.values[j] = s.values[j], s.values[i]\n\tif s.strings != nil {\n\t\ts.strings[i], s.strings[j] = s.strings[j], s.strings[i]\n\t}\n}\n\n// valueSortLess returns whether the first value should sort before the second\n// value.  It is used by valueSorter.Less as part of the sort.Interface\n// implementation.\nfunc valueSortLess(a, b reflect.Value) bool {\n\tswitch a.Kind() {\n\tcase reflect.Bool:\n\t\treturn !a.Bool() && b.Bool()\n\tcase reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:\n\t\treturn a.Int() < b.Int()\n\tcase reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:\n\t\treturn a.Uint() < b.Uint()\n\tcase reflect.Float32, reflect.Float64:\n\t\treturn a.Float() < b.Float()\n\tcase reflect.String:\n\t\treturn a.String() < b.String()\n\tcase reflect.Uintptr:\n\t\treturn a.Uint() < b.Uint()\n\tcase reflect.Array:\n\t\t// Compare the contents of both arrays.\n\t\tl := a.Len()\n\t\tfor i := 0; i < l; i++ {\n\t\t\tav := a.Index(i)\n\t\t\tbv := b.Index(i)\n\t\t\tif av.Interface() == bv.Interface() {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\treturn valueSortLess(av, bv)\n\t\t}\n\t}\n\treturn a.String() < b.String()\n}\n\n// Less returns whether the value at index i should sort before the\n// value at index j.  It is part of the sort.Interface implementation.\nfunc (s *valuesSorter) Less(i, j int) bool {\n\tif s.strings == nil {\n\t\treturn valueSortLess(s.values[i], s.values[j])\n\t}\n\treturn s.strings[i] < s.strings[j]\n}\n\n// sortValues is a sort function that handles both native types and any type that\n// can be converted to error or Stringer.  Other inputs are sorted according to\n// their Value.String() value to ensure display stability.\nfunc sortValues(values []reflect.Value, cs *ConfigState) {\n\tif len(values) == 0 {\n\t\treturn\n\t}\n\tsort.Sort(newValuesSorter(values, cs))\n}\n"
  },
  {
    "path": "vendor/github.com/davecgh/go-spew/spew/config.go",
    "content": "/*\n * Copyright (c) 2013 Dave Collins <dave@davec.name>\n *\n * Permission to use, copy, modify, and distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\npackage spew\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n)\n\n// ConfigState houses the configuration options used by spew to format and\n// display values.  There is a global instance, Config, that is used to control\n// all top-level Formatter and Dump functionality.  Each ConfigState instance\n// provides methods equivalent to the top-level functions.\n//\n// The zero value for ConfigState provides no indentation.  You would typically\n// want to set it to a space or a tab.\n//\n// Alternatively, you can use NewDefaultConfig to get a ConfigState instance\n// with default settings.  See the documentation of NewDefaultConfig for default\n// values.\ntype ConfigState struct {\n\t// Indent specifies the string to use for each indentation level.  The\n\t// global config instance that all top-level functions use set this to a\n\t// single space by default.  If you would like more indentation, you might\n\t// set this to a tab with \"\\t\" or perhaps two spaces with \"  \".\n\tIndent string\n\n\t// MaxDepth controls the maximum number of levels to descend into nested\n\t// data structures.  The default, 0, means there is no limit.\n\t//\n\t// NOTE: Circular data structures are properly detected, so it is not\n\t// necessary to set this value unless you specifically want to limit deeply\n\t// nested data structures.\n\tMaxDepth int\n\n\t// DisableMethods specifies whether or not error and Stringer interfaces are\n\t// invoked for types that implement them.\n\tDisableMethods bool\n\n\t// DisablePointerMethods specifies whether or not to check for and invoke\n\t// error and Stringer interfaces on types which only accept a pointer\n\t// receiver when the current type is not a pointer.\n\t//\n\t// NOTE: This might be an unsafe action since calling one of these methods\n\t// with a pointer receiver could technically mutate the value, however,\n\t// in practice, types which choose to satisify an error or Stringer\n\t// interface with a pointer receiver should not be mutating their state\n\t// inside these interface methods.  As a result, this option relies on\n\t// access to the unsafe package, so it will not have any effect when\n\t// running in environments without access to the unsafe package such as\n\t// Google App Engine or with the \"safe\" build tag specified.\n\tDisablePointerMethods bool\n\n\t// DisablePointerAddresses specifies whether to disable the printing of\n\t// pointer addresses. This is useful when diffing data structures in tests.\n\tDisablePointerAddresses bool\n\n\t// DisableCapacities specifies whether to disable the printing of capacities\n\t// for arrays, slices, maps and channels. This is useful when diffing\n\t// data structures in tests.\n\tDisableCapacities bool\n\n\t// ContinueOnMethod specifies whether or not recursion should continue once\n\t// a custom error or Stringer interface is invoked.  The default, false,\n\t// means it will print the results of invoking the custom error or Stringer\n\t// interface and return immediately instead of continuing to recurse into\n\t// the internals of the data type.\n\t//\n\t// NOTE: This flag does not have any effect if method invocation is disabled\n\t// via the DisableMethods or DisablePointerMethods options.\n\tContinueOnMethod bool\n\n\t// SortKeys specifies map keys should be sorted before being printed. Use\n\t// this to have a more deterministic, diffable output.  Note that only\n\t// native types (bool, int, uint, floats, uintptr and string) and types\n\t// that support the error or Stringer interfaces (if methods are\n\t// enabled) are supported, with other types sorted according to the\n\t// reflect.Value.String() output which guarantees display stability.\n\tSortKeys bool\n\n\t// SpewKeys specifies that, as a last resort attempt, map keys should\n\t// be spewed to strings and sorted by those strings.  This is only\n\t// considered if SortKeys is true.\n\tSpewKeys bool\n}\n\n// Config is the active configuration of the top-level functions.\n// The configuration can be changed by modifying the contents of spew.Config.\nvar Config = ConfigState{Indent: \" \"}\n\n// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were\n// passed with a Formatter interface returned by c.NewFormatter.  It returns\n// the formatted string as a value that satisfies error.  See NewFormatter\n// for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Errorf(format, c.NewFormatter(a), c.NewFormatter(b))\nfunc (c *ConfigState) Errorf(format string, a ...interface{}) (err error) {\n\treturn fmt.Errorf(format, c.convertArgs(a)...)\n}\n\n// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were\n// passed with a Formatter interface returned by c.NewFormatter.  It returns\n// the number of bytes written and any write error encountered.  See\n// NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Fprint(w, c.NewFormatter(a), c.NewFormatter(b))\nfunc (c *ConfigState) Fprint(w io.Writer, a ...interface{}) (n int, err error) {\n\treturn fmt.Fprint(w, c.convertArgs(a)...)\n}\n\n// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were\n// passed with a Formatter interface returned by c.NewFormatter.  It returns\n// the number of bytes written and any write error encountered.  See\n// NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Fprintf(w, format, c.NewFormatter(a), c.NewFormatter(b))\nfunc (c *ConfigState) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {\n\treturn fmt.Fprintf(w, format, c.convertArgs(a)...)\n}\n\n// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it\n// passed with a Formatter interface returned by c.NewFormatter.  See\n// NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Fprintln(w, c.NewFormatter(a), c.NewFormatter(b))\nfunc (c *ConfigState) Fprintln(w io.Writer, a ...interface{}) (n int, err error) {\n\treturn fmt.Fprintln(w, c.convertArgs(a)...)\n}\n\n// Print is a wrapper for fmt.Print that treats each argument as if it were\n// passed with a Formatter interface returned by c.NewFormatter.  It returns\n// the number of bytes written and any write error encountered.  See\n// NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Print(c.NewFormatter(a), c.NewFormatter(b))\nfunc (c *ConfigState) Print(a ...interface{}) (n int, err error) {\n\treturn fmt.Print(c.convertArgs(a)...)\n}\n\n// Printf is a wrapper for fmt.Printf that treats each argument as if it were\n// passed with a Formatter interface returned by c.NewFormatter.  It returns\n// the number of bytes written and any write error encountered.  See\n// NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Printf(format, c.NewFormatter(a), c.NewFormatter(b))\nfunc (c *ConfigState) Printf(format string, a ...interface{}) (n int, err error) {\n\treturn fmt.Printf(format, c.convertArgs(a)...)\n}\n\n// Println is a wrapper for fmt.Println that treats each argument as if it were\n// passed with a Formatter interface returned by c.NewFormatter.  It returns\n// the number of bytes written and any write error encountered.  See\n// NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Println(c.NewFormatter(a), c.NewFormatter(b))\nfunc (c *ConfigState) Println(a ...interface{}) (n int, err error) {\n\treturn fmt.Println(c.convertArgs(a)...)\n}\n\n// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were\n// passed with a Formatter interface returned by c.NewFormatter.  It returns\n// the resulting string.  See NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Sprint(c.NewFormatter(a), c.NewFormatter(b))\nfunc (c *ConfigState) Sprint(a ...interface{}) string {\n\treturn fmt.Sprint(c.convertArgs(a)...)\n}\n\n// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were\n// passed with a Formatter interface returned by c.NewFormatter.  It returns\n// the resulting string.  See NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Sprintf(format, c.NewFormatter(a), c.NewFormatter(b))\nfunc (c *ConfigState) Sprintf(format string, a ...interface{}) string {\n\treturn fmt.Sprintf(format, c.convertArgs(a)...)\n}\n\n// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it\n// were passed with a Formatter interface returned by c.NewFormatter.  It\n// returns the resulting string.  See NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Sprintln(c.NewFormatter(a), c.NewFormatter(b))\nfunc (c *ConfigState) Sprintln(a ...interface{}) string {\n\treturn fmt.Sprintln(c.convertArgs(a)...)\n}\n\n/*\nNewFormatter returns a custom formatter that satisfies the fmt.Formatter\ninterface.  As a result, it integrates cleanly with standard fmt package\nprinting functions.  The formatter is useful for inline printing of smaller data\ntypes similar to the standard %v format specifier.\n\nThe custom formatter only responds to the %v (most compact), %+v (adds pointer\naddresses), %#v (adds types), and %#+v (adds types and pointer addresses) verb\ncombinations.  Any other verbs such as %x and %q will be sent to the the\nstandard fmt package for formatting.  In addition, the custom formatter ignores\nthe width and precision arguments (however they will still work on the format\nspecifiers not handled by the custom formatter).\n\nTypically this function shouldn't be called directly.  It is much easier to make\nuse of the custom formatter by calling one of the convenience functions such as\nc.Printf, c.Println, or c.Printf.\n*/\nfunc (c *ConfigState) NewFormatter(v interface{}) fmt.Formatter {\n\treturn newFormatter(c, v)\n}\n\n// Fdump formats and displays the passed arguments to io.Writer w.  It formats\n// exactly the same as Dump.\nfunc (c *ConfigState) Fdump(w io.Writer, a ...interface{}) {\n\tfdump(c, w, a...)\n}\n\n/*\nDump displays the passed parameters to standard out with newlines, customizable\nindentation, and additional debug information such as complete types and all\npointer addresses used to indirect to the final value.  It provides the\nfollowing features over the built-in printing facilities provided by the fmt\npackage:\n\n\t* Pointers are dereferenced and followed\n\t* Circular data structures are detected and handled properly\n\t* Custom Stringer/error interfaces are optionally invoked, including\n\t  on unexported types\n\t* Custom types which only implement the Stringer/error interfaces via\n\t  a pointer receiver are optionally invoked when passing non-pointer\n\t  variables\n\t* Byte arrays and slices are dumped like the hexdump -C command which\n\t  includes offsets, byte values in hex, and ASCII output\n\nThe configuration options are controlled by modifying the public members\nof c.  See ConfigState for options documentation.\n\nSee Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to\nget the formatted result as a string.\n*/\nfunc (c *ConfigState) Dump(a ...interface{}) {\n\tfdump(c, os.Stdout, a...)\n}\n\n// Sdump returns a string with the passed arguments formatted exactly the same\n// as Dump.\nfunc (c *ConfigState) Sdump(a ...interface{}) string {\n\tvar buf bytes.Buffer\n\tfdump(c, &buf, a...)\n\treturn buf.String()\n}\n\n// convertArgs accepts a slice of arguments and returns a slice of the same\n// length with each argument converted to a spew Formatter interface using\n// the ConfigState associated with s.\nfunc (c *ConfigState) convertArgs(args []interface{}) (formatters []interface{}) {\n\tformatters = make([]interface{}, len(args))\n\tfor index, arg := range args {\n\t\tformatters[index] = newFormatter(c, arg)\n\t}\n\treturn formatters\n}\n\n// NewDefaultConfig returns a ConfigState with the following default settings.\n//\n// \tIndent: \" \"\n// \tMaxDepth: 0\n// \tDisableMethods: false\n// \tDisablePointerMethods: false\n// \tContinueOnMethod: false\n// \tSortKeys: false\nfunc NewDefaultConfig() *ConfigState {\n\treturn &ConfigState{Indent: \" \"}\n}\n"
  },
  {
    "path": "vendor/github.com/davecgh/go-spew/spew/doc.go",
    "content": "/*\n * Copyright (c) 2013 Dave Collins <dave@davec.name>\n *\n * Permission to use, copy, modify, and distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n/*\nPackage spew implements a deep pretty printer for Go data structures to aid in\ndebugging.\n\nA quick overview of the additional features spew provides over the built-in\nprinting facilities for Go data types are as follows:\n\n\t* Pointers are dereferenced and followed\n\t* Circular data structures are detected and handled properly\n\t* Custom Stringer/error interfaces are optionally invoked, including\n\t  on unexported types\n\t* Custom types which only implement the Stringer/error interfaces via\n\t  a pointer receiver are optionally invoked when passing non-pointer\n\t  variables\n\t* Byte arrays and slices are dumped like the hexdump -C command which\n\t  includes offsets, byte values in hex, and ASCII output (only when using\n\t  Dump style)\n\nThere are two different approaches spew allows for dumping Go data structures:\n\n\t* Dump style which prints with newlines, customizable indentation,\n\t  and additional debug information such as types and all pointer addresses\n\t  used to indirect to the final value\n\t* A custom Formatter interface that integrates cleanly with the standard fmt\n\t  package and replaces %v, %+v, %#v, and %#+v to provide inline printing\n\t  similar to the default %v while providing the additional functionality\n\t  outlined above and passing unsupported format verbs such as %x and %q\n\t  along to fmt\n\nQuick Start\n\nThis section demonstrates how to quickly get started with spew.  See the\nsections below for further details on formatting and configuration options.\n\nTo dump a variable with full newlines, indentation, type, and pointer\ninformation use Dump, Fdump, or Sdump:\n\tspew.Dump(myVar1, myVar2, ...)\n\tspew.Fdump(someWriter, myVar1, myVar2, ...)\n\tstr := spew.Sdump(myVar1, myVar2, ...)\n\nAlternatively, if you would prefer to use format strings with a compacted inline\nprinting style, use the convenience wrappers Printf, Fprintf, etc with\n%v (most compact), %+v (adds pointer addresses), %#v (adds types), or\n%#+v (adds types and pointer addresses):\n\tspew.Printf(\"myVar1: %v -- myVar2: %+v\", myVar1, myVar2)\n\tspew.Printf(\"myVar3: %#v -- myVar4: %#+v\", myVar3, myVar4)\n\tspew.Fprintf(someWriter, \"myVar1: %v -- myVar2: %+v\", myVar1, myVar2)\n\tspew.Fprintf(someWriter, \"myVar3: %#v -- myVar4: %#+v\", myVar3, myVar4)\n\nConfiguration Options\n\nConfiguration of spew is handled by fields in the ConfigState type.  For\nconvenience, all of the top-level functions use a global state available\nvia the spew.Config global.\n\nIt is also possible to create a ConfigState instance that provides methods\nequivalent to the top-level functions.  This allows concurrent configuration\noptions.  See the ConfigState documentation for more details.\n\nThe following configuration options are available:\n\t* Indent\n\t\tString to use for each indentation level for Dump functions.\n\t\tIt is a single space by default.  A popular alternative is \"\\t\".\n\n\t* MaxDepth\n\t\tMaximum number of levels to descend into nested data structures.\n\t\tThere is no limit by default.\n\n\t* DisableMethods\n\t\tDisables invocation of error and Stringer interface methods.\n\t\tMethod invocation is enabled by default.\n\n\t* DisablePointerMethods\n\t\tDisables invocation of error and Stringer interface methods on types\n\t\twhich only accept pointer receivers from non-pointer variables.\n\t\tPointer method invocation is enabled by default.\n\n\t* ContinueOnMethod\n\t\tEnables recursion into types after invoking error and Stringer interface\n\t\tmethods. Recursion after method invocation is disabled by default.\n\n\t* SortKeys\n\t\tSpecifies map keys should be sorted before being printed. Use\n\t\tthis to have a more deterministic, diffable output.  Note that\n\t\tonly native types (bool, int, uint, floats, uintptr and string)\n\t\tand types which implement error or Stringer interfaces are\n\t\tsupported with other types sorted according to the\n\t\treflect.Value.String() output which guarantees display\n\t\tstability.  Natural map order is used by default.\n\n\t* SpewKeys\n\t\tSpecifies that, as a last resort attempt, map keys should be\n\t\tspewed to strings and sorted by those strings.  This is only\n\t\tconsidered if SortKeys is true.\n\nDump Usage\n\nSimply call spew.Dump with a list of variables you want to dump:\n\n\tspew.Dump(myVar1, myVar2, ...)\n\nYou may also call spew.Fdump if you would prefer to output to an arbitrary\nio.Writer.  For example, to dump to standard error:\n\n\tspew.Fdump(os.Stderr, myVar1, myVar2, ...)\n\nA third option is to call spew.Sdump to get the formatted output as a string:\n\n\tstr := spew.Sdump(myVar1, myVar2, ...)\n\nSample Dump Output\n\nSee the Dump example for details on the setup of the types and variables being\nshown here.\n\n\t(main.Foo) {\n\t unexportedField: (*main.Bar)(0xf84002e210)({\n\t  flag: (main.Flag) flagTwo,\n\t  data: (uintptr) <nil>\n\t }),\n\t ExportedField: (map[interface {}]interface {}) (len=1) {\n\t  (string) (len=3) \"one\": (bool) true\n\t }\n\t}\n\nByte (and uint8) arrays and slices are displayed uniquely like the hexdump -C\ncommand as shown.\n\t([]uint8) (len=32 cap=32) {\n\t 00000000  11 12 13 14 15 16 17 18  19 1a 1b 1c 1d 1e 1f 20  |............... |\n\t 00000010  21 22 23 24 25 26 27 28  29 2a 2b 2c 2d 2e 2f 30  |!\"#$%&'()*+,-./0|\n\t 00000020  31 32                                             |12|\n\t}\n\nCustom Formatter\n\nSpew provides a custom formatter that implements the fmt.Formatter interface\nso that it integrates cleanly with standard fmt package printing functions. The\nformatter is useful for inline printing of smaller data types similar to the\nstandard %v format specifier.\n\nThe custom formatter only responds to the %v (most compact), %+v (adds pointer\naddresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb\ncombinations.  Any other verbs such as %x and %q will be sent to the the\nstandard fmt package for formatting.  In addition, the custom formatter ignores\nthe width and precision arguments (however they will still work on the format\nspecifiers not handled by the custom formatter).\n\nCustom Formatter Usage\n\nThe simplest way to make use of the spew custom formatter is to call one of the\nconvenience functions such as spew.Printf, spew.Println, or spew.Printf.  The\nfunctions have syntax you are most likely already familiar with:\n\n\tspew.Printf(\"myVar1: %v -- myVar2: %+v\", myVar1, myVar2)\n\tspew.Printf(\"myVar3: %#v -- myVar4: %#+v\", myVar3, myVar4)\n\tspew.Println(myVar, myVar2)\n\tspew.Fprintf(os.Stderr, \"myVar1: %v -- myVar2: %+v\", myVar1, myVar2)\n\tspew.Fprintf(os.Stderr, \"myVar3: %#v -- myVar4: %#+v\", myVar3, myVar4)\n\nSee the Index for the full list convenience functions.\n\nSample Formatter Output\n\nDouble pointer to a uint8:\n\t  %v: <**>5\n\t %+v: <**>(0xf8400420d0->0xf8400420c8)5\n\t %#v: (**uint8)5\n\t%#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5\n\nPointer to circular struct with a uint8 field and a pointer to itself:\n\t  %v: <*>{1 <*><shown>}\n\t %+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)<shown>}\n\t %#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)<shown>}\n\t%#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)<shown>}\n\nSee the Printf example for details on the setup of variables being shown\nhere.\n\nErrors\n\nSince it is possible for custom Stringer/error interfaces to panic, spew\ndetects them and handles them internally by printing the panic information\ninline with the output.  Since spew is intended to provide deep pretty printing\ncapabilities on structures, it intentionally does not return any errors.\n*/\npackage spew\n"
  },
  {
    "path": "vendor/github.com/davecgh/go-spew/spew/dump.go",
    "content": "/*\n * Copyright (c) 2013 Dave Collins <dave@davec.name>\n *\n * Permission to use, copy, modify, and distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\npackage spew\n\nimport (\n\t\"bytes\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"reflect\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n)\n\nvar (\n\t// uint8Type is a reflect.Type representing a uint8.  It is used to\n\t// convert cgo types to uint8 slices for hexdumping.\n\tuint8Type = reflect.TypeOf(uint8(0))\n\n\t// cCharRE is a regular expression that matches a cgo char.\n\t// It is used to detect character arrays to hexdump them.\n\tcCharRE = regexp.MustCompile(\"^.*\\\\._Ctype_char$\")\n\n\t// cUnsignedCharRE is a regular expression that matches a cgo unsigned\n\t// char.  It is used to detect unsigned character arrays to hexdump\n\t// them.\n\tcUnsignedCharRE = regexp.MustCompile(\"^.*\\\\._Ctype_unsignedchar$\")\n\n\t// cUint8tCharRE is a regular expression that matches a cgo uint8_t.\n\t// It is used to detect uint8_t arrays to hexdump them.\n\tcUint8tCharRE = regexp.MustCompile(\"^.*\\\\._Ctype_uint8_t$\")\n)\n\n// dumpState contains information about the state of a dump operation.\ntype dumpState struct {\n\tw                io.Writer\n\tdepth            int\n\tpointers         map[uintptr]int\n\tignoreNextType   bool\n\tignoreNextIndent bool\n\tcs               *ConfigState\n}\n\n// indent performs indentation according to the depth level and cs.Indent\n// option.\nfunc (d *dumpState) indent() {\n\tif d.ignoreNextIndent {\n\t\td.ignoreNextIndent = false\n\t\treturn\n\t}\n\td.w.Write(bytes.Repeat([]byte(d.cs.Indent), d.depth))\n}\n\n// unpackValue returns values inside of non-nil interfaces when possible.\n// This is useful for data types like structs, arrays, slices, and maps which\n// can contain varying types packed inside an interface.\nfunc (d *dumpState) unpackValue(v reflect.Value) reflect.Value {\n\tif v.Kind() == reflect.Interface && !v.IsNil() {\n\t\tv = v.Elem()\n\t}\n\treturn v\n}\n\n// dumpPtr handles formatting of pointers by indirecting them as necessary.\nfunc (d *dumpState) dumpPtr(v reflect.Value) {\n\t// Remove pointers at or below the current depth from map used to detect\n\t// circular refs.\n\tfor k, depth := range d.pointers {\n\t\tif depth >= d.depth {\n\t\t\tdelete(d.pointers, k)\n\t\t}\n\t}\n\n\t// Keep list of all dereferenced pointers to show later.\n\tpointerChain := make([]uintptr, 0)\n\n\t// Figure out how many levels of indirection there are by dereferencing\n\t// pointers and unpacking interfaces down the chain while detecting circular\n\t// references.\n\tnilFound := false\n\tcycleFound := false\n\tindirects := 0\n\tve := v\n\tfor ve.Kind() == reflect.Ptr {\n\t\tif ve.IsNil() {\n\t\t\tnilFound = true\n\t\t\tbreak\n\t\t}\n\t\tindirects++\n\t\taddr := ve.Pointer()\n\t\tpointerChain = append(pointerChain, addr)\n\t\tif pd, ok := d.pointers[addr]; ok && pd < d.depth {\n\t\t\tcycleFound = true\n\t\t\tindirects--\n\t\t\tbreak\n\t\t}\n\t\td.pointers[addr] = d.depth\n\n\t\tve = ve.Elem()\n\t\tif ve.Kind() == reflect.Interface {\n\t\t\tif ve.IsNil() {\n\t\t\t\tnilFound = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tve = ve.Elem()\n\t\t}\n\t}\n\n\t// Display type information.\n\td.w.Write(openParenBytes)\n\td.w.Write(bytes.Repeat(asteriskBytes, indirects))\n\td.w.Write([]byte(ve.Type().String()))\n\td.w.Write(closeParenBytes)\n\n\t// Display pointer information.\n\tif !d.cs.DisablePointerAddresses && len(pointerChain) > 0 {\n\t\td.w.Write(openParenBytes)\n\t\tfor i, addr := range pointerChain {\n\t\t\tif i > 0 {\n\t\t\t\td.w.Write(pointerChainBytes)\n\t\t\t}\n\t\t\tprintHexPtr(d.w, addr)\n\t\t}\n\t\td.w.Write(closeParenBytes)\n\t}\n\n\t// Display dereferenced value.\n\td.w.Write(openParenBytes)\n\tswitch {\n\tcase nilFound == true:\n\t\td.w.Write(nilAngleBytes)\n\n\tcase cycleFound == true:\n\t\td.w.Write(circularBytes)\n\n\tdefault:\n\t\td.ignoreNextType = true\n\t\td.dump(ve)\n\t}\n\td.w.Write(closeParenBytes)\n}\n\n// dumpSlice handles formatting of arrays and slices.  Byte (uint8 under\n// reflection) arrays and slices are dumped in hexdump -C fashion.\nfunc (d *dumpState) dumpSlice(v reflect.Value) {\n\t// Determine whether this type should be hex dumped or not.  Also,\n\t// for types which should be hexdumped, try to use the underlying data\n\t// first, then fall back to trying to convert them to a uint8 slice.\n\tvar buf []uint8\n\tdoConvert := false\n\tdoHexDump := false\n\tnumEntries := v.Len()\n\tif numEntries > 0 {\n\t\tvt := v.Index(0).Type()\n\t\tvts := vt.String()\n\t\tswitch {\n\t\t// C types that need to be converted.\n\t\tcase cCharRE.MatchString(vts):\n\t\t\tfallthrough\n\t\tcase cUnsignedCharRE.MatchString(vts):\n\t\t\tfallthrough\n\t\tcase cUint8tCharRE.MatchString(vts):\n\t\t\tdoConvert = true\n\n\t\t// Try to use existing uint8 slices and fall back to converting\n\t\t// and copying if that fails.\n\t\tcase vt.Kind() == reflect.Uint8:\n\t\t\t// We need an addressable interface to convert the type\n\t\t\t// to a byte slice.  However, the reflect package won't\n\t\t\t// give us an interface on certain things like\n\t\t\t// unexported struct fields in order to enforce\n\t\t\t// visibility rules.  We use unsafe, when available, to\n\t\t\t// bypass these restrictions since this package does not\n\t\t\t// mutate the values.\n\t\t\tvs := v\n\t\t\tif !vs.CanInterface() || !vs.CanAddr() {\n\t\t\t\tvs = unsafeReflectValue(vs)\n\t\t\t}\n\t\t\tif !UnsafeDisabled {\n\t\t\t\tvs = vs.Slice(0, numEntries)\n\n\t\t\t\t// Use the existing uint8 slice if it can be\n\t\t\t\t// type asserted.\n\t\t\t\tiface := vs.Interface()\n\t\t\t\tif slice, ok := iface.([]uint8); ok {\n\t\t\t\t\tbuf = slice\n\t\t\t\t\tdoHexDump = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// The underlying data needs to be converted if it can't\n\t\t\t// be type asserted to a uint8 slice.\n\t\t\tdoConvert = true\n\t\t}\n\n\t\t// Copy and convert the underlying type if needed.\n\t\tif doConvert && vt.ConvertibleTo(uint8Type) {\n\t\t\t// Convert and copy each element into a uint8 byte\n\t\t\t// slice.\n\t\t\tbuf = make([]uint8, numEntries)\n\t\t\tfor i := 0; i < numEntries; i++ {\n\t\t\t\tvv := v.Index(i)\n\t\t\t\tbuf[i] = uint8(vv.Convert(uint8Type).Uint())\n\t\t\t}\n\t\t\tdoHexDump = true\n\t\t}\n\t}\n\n\t// Hexdump the entire slice as needed.\n\tif doHexDump {\n\t\tindent := strings.Repeat(d.cs.Indent, d.depth)\n\t\tstr := indent + hex.Dump(buf)\n\t\tstr = strings.Replace(str, \"\\n\", \"\\n\"+indent, -1)\n\t\tstr = strings.TrimRight(str, d.cs.Indent)\n\t\td.w.Write([]byte(str))\n\t\treturn\n\t}\n\n\t// Recursively call dump for each item.\n\tfor i := 0; i < numEntries; i++ {\n\t\td.dump(d.unpackValue(v.Index(i)))\n\t\tif i < (numEntries - 1) {\n\t\t\td.w.Write(commaNewlineBytes)\n\t\t} else {\n\t\t\td.w.Write(newlineBytes)\n\t\t}\n\t}\n}\n\n// dump is the main workhorse for dumping a value.  It uses the passed reflect\n// value to figure out what kind of object we are dealing with and formats it\n// appropriately.  It is a recursive function, however circular data structures\n// are detected and handled properly.\nfunc (d *dumpState) dump(v reflect.Value) {\n\t// Handle invalid reflect values immediately.\n\tkind := v.Kind()\n\tif kind == reflect.Invalid {\n\t\td.w.Write(invalidAngleBytes)\n\t\treturn\n\t}\n\n\t// Handle pointers specially.\n\tif kind == reflect.Ptr {\n\t\td.indent()\n\t\td.dumpPtr(v)\n\t\treturn\n\t}\n\n\t// Print type information unless already handled elsewhere.\n\tif !d.ignoreNextType {\n\t\td.indent()\n\t\td.w.Write(openParenBytes)\n\t\td.w.Write([]byte(v.Type().String()))\n\t\td.w.Write(closeParenBytes)\n\t\td.w.Write(spaceBytes)\n\t}\n\td.ignoreNextType = false\n\n\t// Display length and capacity if the built-in len and cap functions\n\t// work with the value's kind and the len/cap itself is non-zero.\n\tvalueLen, valueCap := 0, 0\n\tswitch v.Kind() {\n\tcase reflect.Array, reflect.Slice, reflect.Chan:\n\t\tvalueLen, valueCap = v.Len(), v.Cap()\n\tcase reflect.Map, reflect.String:\n\t\tvalueLen = v.Len()\n\t}\n\tif valueLen != 0 || !d.cs.DisableCapacities && valueCap != 0 {\n\t\td.w.Write(openParenBytes)\n\t\tif valueLen != 0 {\n\t\t\td.w.Write(lenEqualsBytes)\n\t\t\tprintInt(d.w, int64(valueLen), 10)\n\t\t}\n\t\tif !d.cs.DisableCapacities && valueCap != 0 {\n\t\t\tif valueLen != 0 {\n\t\t\t\td.w.Write(spaceBytes)\n\t\t\t}\n\t\t\td.w.Write(capEqualsBytes)\n\t\t\tprintInt(d.w, int64(valueCap), 10)\n\t\t}\n\t\td.w.Write(closeParenBytes)\n\t\td.w.Write(spaceBytes)\n\t}\n\n\t// Call Stringer/error interfaces if they exist and the handle methods flag\n\t// is enabled\n\tif !d.cs.DisableMethods {\n\t\tif (kind != reflect.Invalid) && (kind != reflect.Interface) {\n\t\t\tif handled := handleMethods(d.cs, d.w, v); handled {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\tswitch kind {\n\tcase reflect.Invalid:\n\t\t// Do nothing.  We should never get here since invalid has already\n\t\t// been handled above.\n\n\tcase reflect.Bool:\n\t\tprintBool(d.w, v.Bool())\n\n\tcase reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:\n\t\tprintInt(d.w, v.Int(), 10)\n\n\tcase reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:\n\t\tprintUint(d.w, v.Uint(), 10)\n\n\tcase reflect.Float32:\n\t\tprintFloat(d.w, v.Float(), 32)\n\n\tcase reflect.Float64:\n\t\tprintFloat(d.w, v.Float(), 64)\n\n\tcase reflect.Complex64:\n\t\tprintComplex(d.w, v.Complex(), 32)\n\n\tcase reflect.Complex128:\n\t\tprintComplex(d.w, v.Complex(), 64)\n\n\tcase reflect.Slice:\n\t\tif v.IsNil() {\n\t\t\td.w.Write(nilAngleBytes)\n\t\t\tbreak\n\t\t}\n\t\tfallthrough\n\n\tcase reflect.Array:\n\t\td.w.Write(openBraceNewlineBytes)\n\t\td.depth++\n\t\tif (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {\n\t\t\td.indent()\n\t\t\td.w.Write(maxNewlineBytes)\n\t\t} else {\n\t\t\td.dumpSlice(v)\n\t\t}\n\t\td.depth--\n\t\td.indent()\n\t\td.w.Write(closeBraceBytes)\n\n\tcase reflect.String:\n\t\td.w.Write([]byte(strconv.Quote(v.String())))\n\n\tcase reflect.Interface:\n\t\t// The only time we should get here is for nil interfaces due to\n\t\t// unpackValue calls.\n\t\tif v.IsNil() {\n\t\t\td.w.Write(nilAngleBytes)\n\t\t}\n\n\tcase reflect.Ptr:\n\t\t// Do nothing.  We should never get here since pointers have already\n\t\t// been handled above.\n\n\tcase reflect.Map:\n\t\t// nil maps should be indicated as different than empty maps\n\t\tif v.IsNil() {\n\t\t\td.w.Write(nilAngleBytes)\n\t\t\tbreak\n\t\t}\n\n\t\td.w.Write(openBraceNewlineBytes)\n\t\td.depth++\n\t\tif (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {\n\t\t\td.indent()\n\t\t\td.w.Write(maxNewlineBytes)\n\t\t} else {\n\t\t\tnumEntries := v.Len()\n\t\t\tkeys := v.MapKeys()\n\t\t\tif d.cs.SortKeys {\n\t\t\t\tsortValues(keys, d.cs)\n\t\t\t}\n\t\t\tfor i, key := range keys {\n\t\t\t\td.dump(d.unpackValue(key))\n\t\t\t\td.w.Write(colonSpaceBytes)\n\t\t\t\td.ignoreNextIndent = true\n\t\t\t\td.dump(d.unpackValue(v.MapIndex(key)))\n\t\t\t\tif i < (numEntries - 1) {\n\t\t\t\t\td.w.Write(commaNewlineBytes)\n\t\t\t\t} else {\n\t\t\t\t\td.w.Write(newlineBytes)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\td.depth--\n\t\td.indent()\n\t\td.w.Write(closeBraceBytes)\n\n\tcase reflect.Struct:\n\t\td.w.Write(openBraceNewlineBytes)\n\t\td.depth++\n\t\tif (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {\n\t\t\td.indent()\n\t\t\td.w.Write(maxNewlineBytes)\n\t\t} else {\n\t\t\tvt := v.Type()\n\t\t\tnumFields := v.NumField()\n\t\t\tfor i := 0; i < numFields; i++ {\n\t\t\t\td.indent()\n\t\t\t\tvtf := vt.Field(i)\n\t\t\t\td.w.Write([]byte(vtf.Name))\n\t\t\t\td.w.Write(colonSpaceBytes)\n\t\t\t\td.ignoreNextIndent = true\n\t\t\t\td.dump(d.unpackValue(v.Field(i)))\n\t\t\t\tif i < (numFields - 1) {\n\t\t\t\t\td.w.Write(commaNewlineBytes)\n\t\t\t\t} else {\n\t\t\t\t\td.w.Write(newlineBytes)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\td.depth--\n\t\td.indent()\n\t\td.w.Write(closeBraceBytes)\n\n\tcase reflect.Uintptr:\n\t\tprintHexPtr(d.w, uintptr(v.Uint()))\n\n\tcase reflect.UnsafePointer, reflect.Chan, reflect.Func:\n\t\tprintHexPtr(d.w, v.Pointer())\n\n\t// There were not any other types at the time this code was written, but\n\t// fall back to letting the default fmt package handle it in case any new\n\t// types are added.\n\tdefault:\n\t\tif v.CanInterface() {\n\t\t\tfmt.Fprintf(d.w, \"%v\", v.Interface())\n\t\t} else {\n\t\t\tfmt.Fprintf(d.w, \"%v\", v.String())\n\t\t}\n\t}\n}\n\n// fdump is a helper function to consolidate the logic from the various public\n// methods which take varying writers and config states.\nfunc fdump(cs *ConfigState, w io.Writer, a ...interface{}) {\n\tfor _, arg := range a {\n\t\tif arg == nil {\n\t\t\tw.Write(interfaceBytes)\n\t\t\tw.Write(spaceBytes)\n\t\t\tw.Write(nilAngleBytes)\n\t\t\tw.Write(newlineBytes)\n\t\t\tcontinue\n\t\t}\n\n\t\td := dumpState{w: w, cs: cs}\n\t\td.pointers = make(map[uintptr]int)\n\t\td.dump(reflect.ValueOf(arg))\n\t\td.w.Write(newlineBytes)\n\t}\n}\n\n// Fdump formats and displays the passed arguments to io.Writer w.  It formats\n// exactly the same as Dump.\nfunc Fdump(w io.Writer, a ...interface{}) {\n\tfdump(&Config, w, a...)\n}\n\n// Sdump returns a string with the passed arguments formatted exactly the same\n// as Dump.\nfunc Sdump(a ...interface{}) string {\n\tvar buf bytes.Buffer\n\tfdump(&Config, &buf, a...)\n\treturn buf.String()\n}\n\n/*\nDump displays the passed parameters to standard out with newlines, customizable\nindentation, and additional debug information such as complete types and all\npointer addresses used to indirect to the final value.  It provides the\nfollowing features over the built-in printing facilities provided by the fmt\npackage:\n\n\t* Pointers are dereferenced and followed\n\t* Circular data structures are detected and handled properly\n\t* Custom Stringer/error interfaces are optionally invoked, including\n\t  on unexported types\n\t* Custom types which only implement the Stringer/error interfaces via\n\t  a pointer receiver are optionally invoked when passing non-pointer\n\t  variables\n\t* Byte arrays and slices are dumped like the hexdump -C command which\n\t  includes offsets, byte values in hex, and ASCII output\n\nThe configuration options are controlled by an exported package global,\nspew.Config.  See ConfigState for options documentation.\n\nSee Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to\nget the formatted result as a string.\n*/\nfunc Dump(a ...interface{}) {\n\tfdump(&Config, os.Stdout, a...)\n}\n"
  },
  {
    "path": "vendor/github.com/davecgh/go-spew/spew/format.go",
    "content": "/*\n * Copyright (c) 2013 Dave Collins <dave@davec.name>\n *\n * Permission to use, copy, modify, and distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\npackage spew\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n)\n\n// supportedFlags is a list of all the character flags supported by fmt package.\nconst supportedFlags = \"0-+# \"\n\n// formatState implements the fmt.Formatter interface and contains information\n// about the state of a formatting operation.  The NewFormatter function can\n// be used to get a new Formatter which can be used directly as arguments\n// in standard fmt package printing calls.\ntype formatState struct {\n\tvalue          interface{}\n\tfs             fmt.State\n\tdepth          int\n\tpointers       map[uintptr]int\n\tignoreNextType bool\n\tcs             *ConfigState\n}\n\n// buildDefaultFormat recreates the original format string without precision\n// and width information to pass in to fmt.Sprintf in the case of an\n// unrecognized type.  Unless new types are added to the language, this\n// function won't ever be called.\nfunc (f *formatState) buildDefaultFormat() (format string) {\n\tbuf := bytes.NewBuffer(percentBytes)\n\n\tfor _, flag := range supportedFlags {\n\t\tif f.fs.Flag(int(flag)) {\n\t\t\tbuf.WriteRune(flag)\n\t\t}\n\t}\n\n\tbuf.WriteRune('v')\n\n\tformat = buf.String()\n\treturn format\n}\n\n// constructOrigFormat recreates the original format string including precision\n// and width information to pass along to the standard fmt package.  This allows\n// automatic deferral of all format strings this package doesn't support.\nfunc (f *formatState) constructOrigFormat(verb rune) (format string) {\n\tbuf := bytes.NewBuffer(percentBytes)\n\n\tfor _, flag := range supportedFlags {\n\t\tif f.fs.Flag(int(flag)) {\n\t\t\tbuf.WriteRune(flag)\n\t\t}\n\t}\n\n\tif width, ok := f.fs.Width(); ok {\n\t\tbuf.WriteString(strconv.Itoa(width))\n\t}\n\n\tif precision, ok := f.fs.Precision(); ok {\n\t\tbuf.Write(precisionBytes)\n\t\tbuf.WriteString(strconv.Itoa(precision))\n\t}\n\n\tbuf.WriteRune(verb)\n\n\tformat = buf.String()\n\treturn format\n}\n\n// unpackValue returns values inside of non-nil interfaces when possible and\n// ensures that types for values which have been unpacked from an interface\n// are displayed when the show types flag is also set.\n// This is useful for data types like structs, arrays, slices, and maps which\n// can contain varying types packed inside an interface.\nfunc (f *formatState) unpackValue(v reflect.Value) reflect.Value {\n\tif v.Kind() == reflect.Interface {\n\t\tf.ignoreNextType = false\n\t\tif !v.IsNil() {\n\t\t\tv = v.Elem()\n\t\t}\n\t}\n\treturn v\n}\n\n// formatPtr handles formatting of pointers by indirecting them as necessary.\nfunc (f *formatState) formatPtr(v reflect.Value) {\n\t// Display nil if top level pointer is nil.\n\tshowTypes := f.fs.Flag('#')\n\tif v.IsNil() && (!showTypes || f.ignoreNextType) {\n\t\tf.fs.Write(nilAngleBytes)\n\t\treturn\n\t}\n\n\t// Remove pointers at or below the current depth from map used to detect\n\t// circular refs.\n\tfor k, depth := range f.pointers {\n\t\tif depth >= f.depth {\n\t\t\tdelete(f.pointers, k)\n\t\t}\n\t}\n\n\t// Keep list of all dereferenced pointers to possibly show later.\n\tpointerChain := make([]uintptr, 0)\n\n\t// Figure out how many levels of indirection there are by derferencing\n\t// pointers and unpacking interfaces down the chain while detecting circular\n\t// references.\n\tnilFound := false\n\tcycleFound := false\n\tindirects := 0\n\tve := v\n\tfor ve.Kind() == reflect.Ptr {\n\t\tif ve.IsNil() {\n\t\t\tnilFound = true\n\t\t\tbreak\n\t\t}\n\t\tindirects++\n\t\taddr := ve.Pointer()\n\t\tpointerChain = append(pointerChain, addr)\n\t\tif pd, ok := f.pointers[addr]; ok && pd < f.depth {\n\t\t\tcycleFound = true\n\t\t\tindirects--\n\t\t\tbreak\n\t\t}\n\t\tf.pointers[addr] = f.depth\n\n\t\tve = ve.Elem()\n\t\tif ve.Kind() == reflect.Interface {\n\t\t\tif ve.IsNil() {\n\t\t\t\tnilFound = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tve = ve.Elem()\n\t\t}\n\t}\n\n\t// Display type or indirection level depending on flags.\n\tif showTypes && !f.ignoreNextType {\n\t\tf.fs.Write(openParenBytes)\n\t\tf.fs.Write(bytes.Repeat(asteriskBytes, indirects))\n\t\tf.fs.Write([]byte(ve.Type().String()))\n\t\tf.fs.Write(closeParenBytes)\n\t} else {\n\t\tif nilFound || cycleFound {\n\t\t\tindirects += strings.Count(ve.Type().String(), \"*\")\n\t\t}\n\t\tf.fs.Write(openAngleBytes)\n\t\tf.fs.Write([]byte(strings.Repeat(\"*\", indirects)))\n\t\tf.fs.Write(closeAngleBytes)\n\t}\n\n\t// Display pointer information depending on flags.\n\tif f.fs.Flag('+') && (len(pointerChain) > 0) {\n\t\tf.fs.Write(openParenBytes)\n\t\tfor i, addr := range pointerChain {\n\t\t\tif i > 0 {\n\t\t\t\tf.fs.Write(pointerChainBytes)\n\t\t\t}\n\t\t\tprintHexPtr(f.fs, addr)\n\t\t}\n\t\tf.fs.Write(closeParenBytes)\n\t}\n\n\t// Display dereferenced value.\n\tswitch {\n\tcase nilFound == true:\n\t\tf.fs.Write(nilAngleBytes)\n\n\tcase cycleFound == true:\n\t\tf.fs.Write(circularShortBytes)\n\n\tdefault:\n\t\tf.ignoreNextType = true\n\t\tf.format(ve)\n\t}\n}\n\n// format is the main workhorse for providing the Formatter interface.  It\n// uses the passed reflect value to figure out what kind of object we are\n// dealing with and formats it appropriately.  It is a recursive function,\n// however circular data structures are detected and handled properly.\nfunc (f *formatState) format(v reflect.Value) {\n\t// Handle invalid reflect values immediately.\n\tkind := v.Kind()\n\tif kind == reflect.Invalid {\n\t\tf.fs.Write(invalidAngleBytes)\n\t\treturn\n\t}\n\n\t// Handle pointers specially.\n\tif kind == reflect.Ptr {\n\t\tf.formatPtr(v)\n\t\treturn\n\t}\n\n\t// Print type information unless already handled elsewhere.\n\tif !f.ignoreNextType && f.fs.Flag('#') {\n\t\tf.fs.Write(openParenBytes)\n\t\tf.fs.Write([]byte(v.Type().String()))\n\t\tf.fs.Write(closeParenBytes)\n\t}\n\tf.ignoreNextType = false\n\n\t// Call Stringer/error interfaces if they exist and the handle methods\n\t// flag is enabled.\n\tif !f.cs.DisableMethods {\n\t\tif (kind != reflect.Invalid) && (kind != reflect.Interface) {\n\t\t\tif handled := handleMethods(f.cs, f.fs, v); handled {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\tswitch kind {\n\tcase reflect.Invalid:\n\t\t// Do nothing.  We should never get here since invalid has already\n\t\t// been handled above.\n\n\tcase reflect.Bool:\n\t\tprintBool(f.fs, v.Bool())\n\n\tcase reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:\n\t\tprintInt(f.fs, v.Int(), 10)\n\n\tcase reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:\n\t\tprintUint(f.fs, v.Uint(), 10)\n\n\tcase reflect.Float32:\n\t\tprintFloat(f.fs, v.Float(), 32)\n\n\tcase reflect.Float64:\n\t\tprintFloat(f.fs, v.Float(), 64)\n\n\tcase reflect.Complex64:\n\t\tprintComplex(f.fs, v.Complex(), 32)\n\n\tcase reflect.Complex128:\n\t\tprintComplex(f.fs, v.Complex(), 64)\n\n\tcase reflect.Slice:\n\t\tif v.IsNil() {\n\t\t\tf.fs.Write(nilAngleBytes)\n\t\t\tbreak\n\t\t}\n\t\tfallthrough\n\n\tcase reflect.Array:\n\t\tf.fs.Write(openBracketBytes)\n\t\tf.depth++\n\t\tif (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {\n\t\t\tf.fs.Write(maxShortBytes)\n\t\t} else {\n\t\t\tnumEntries := v.Len()\n\t\t\tfor i := 0; i < numEntries; i++ {\n\t\t\t\tif i > 0 {\n\t\t\t\t\tf.fs.Write(spaceBytes)\n\t\t\t\t}\n\t\t\t\tf.ignoreNextType = true\n\t\t\t\tf.format(f.unpackValue(v.Index(i)))\n\t\t\t}\n\t\t}\n\t\tf.depth--\n\t\tf.fs.Write(closeBracketBytes)\n\n\tcase reflect.String:\n\t\tf.fs.Write([]byte(v.String()))\n\n\tcase reflect.Interface:\n\t\t// The only time we should get here is for nil interfaces due to\n\t\t// unpackValue calls.\n\t\tif v.IsNil() {\n\t\t\tf.fs.Write(nilAngleBytes)\n\t\t}\n\n\tcase reflect.Ptr:\n\t\t// Do nothing.  We should never get here since pointers have already\n\t\t// been handled above.\n\n\tcase reflect.Map:\n\t\t// nil maps should be indicated as different than empty maps\n\t\tif v.IsNil() {\n\t\t\tf.fs.Write(nilAngleBytes)\n\t\t\tbreak\n\t\t}\n\n\t\tf.fs.Write(openMapBytes)\n\t\tf.depth++\n\t\tif (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {\n\t\t\tf.fs.Write(maxShortBytes)\n\t\t} else {\n\t\t\tkeys := v.MapKeys()\n\t\t\tif f.cs.SortKeys {\n\t\t\t\tsortValues(keys, f.cs)\n\t\t\t}\n\t\t\tfor i, key := range keys {\n\t\t\t\tif i > 0 {\n\t\t\t\t\tf.fs.Write(spaceBytes)\n\t\t\t\t}\n\t\t\t\tf.ignoreNextType = true\n\t\t\t\tf.format(f.unpackValue(key))\n\t\t\t\tf.fs.Write(colonBytes)\n\t\t\t\tf.ignoreNextType = true\n\t\t\t\tf.format(f.unpackValue(v.MapIndex(key)))\n\t\t\t}\n\t\t}\n\t\tf.depth--\n\t\tf.fs.Write(closeMapBytes)\n\n\tcase reflect.Struct:\n\t\tnumFields := v.NumField()\n\t\tf.fs.Write(openBraceBytes)\n\t\tf.depth++\n\t\tif (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {\n\t\t\tf.fs.Write(maxShortBytes)\n\t\t} else {\n\t\t\tvt := v.Type()\n\t\t\tfor i := 0; i < numFields; i++ {\n\t\t\t\tif i > 0 {\n\t\t\t\t\tf.fs.Write(spaceBytes)\n\t\t\t\t}\n\t\t\t\tvtf := vt.Field(i)\n\t\t\t\tif f.fs.Flag('+') || f.fs.Flag('#') {\n\t\t\t\t\tf.fs.Write([]byte(vtf.Name))\n\t\t\t\t\tf.fs.Write(colonBytes)\n\t\t\t\t}\n\t\t\t\tf.format(f.unpackValue(v.Field(i)))\n\t\t\t}\n\t\t}\n\t\tf.depth--\n\t\tf.fs.Write(closeBraceBytes)\n\n\tcase reflect.Uintptr:\n\t\tprintHexPtr(f.fs, uintptr(v.Uint()))\n\n\tcase reflect.UnsafePointer, reflect.Chan, reflect.Func:\n\t\tprintHexPtr(f.fs, v.Pointer())\n\n\t// There were not any other types at the time this code was written, but\n\t// fall back to letting the default fmt package handle it if any get added.\n\tdefault:\n\t\tformat := f.buildDefaultFormat()\n\t\tif v.CanInterface() {\n\t\t\tfmt.Fprintf(f.fs, format, v.Interface())\n\t\t} else {\n\t\t\tfmt.Fprintf(f.fs, format, v.String())\n\t\t}\n\t}\n}\n\n// Format satisfies the fmt.Formatter interface. See NewFormatter for usage\n// details.\nfunc (f *formatState) Format(fs fmt.State, verb rune) {\n\tf.fs = fs\n\n\t// Use standard formatting for verbs that are not v.\n\tif verb != 'v' {\n\t\tformat := f.constructOrigFormat(verb)\n\t\tfmt.Fprintf(fs, format, f.value)\n\t\treturn\n\t}\n\n\tif f.value == nil {\n\t\tif fs.Flag('#') {\n\t\t\tfs.Write(interfaceBytes)\n\t\t}\n\t\tfs.Write(nilAngleBytes)\n\t\treturn\n\t}\n\n\tf.format(reflect.ValueOf(f.value))\n}\n\n// newFormatter is a helper function to consolidate the logic from the various\n// public methods which take varying config states.\nfunc newFormatter(cs *ConfigState, v interface{}) fmt.Formatter {\n\tfs := &formatState{value: v, cs: cs}\n\tfs.pointers = make(map[uintptr]int)\n\treturn fs\n}\n\n/*\nNewFormatter returns a custom formatter that satisfies the fmt.Formatter\ninterface.  As a result, it integrates cleanly with standard fmt package\nprinting functions.  The formatter is useful for inline printing of smaller data\ntypes similar to the standard %v format specifier.\n\nThe custom formatter only responds to the %v (most compact), %+v (adds pointer\naddresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb\ncombinations.  Any other verbs such as %x and %q will be sent to the the\nstandard fmt package for formatting.  In addition, the custom formatter ignores\nthe width and precision arguments (however they will still work on the format\nspecifiers not handled by the custom formatter).\n\nTypically this function shouldn't be called directly.  It is much easier to make\nuse of the custom formatter by calling one of the convenience functions such as\nPrintf, Println, or Fprintf.\n*/\nfunc NewFormatter(v interface{}) fmt.Formatter {\n\treturn newFormatter(&Config, v)\n}\n"
  },
  {
    "path": "vendor/github.com/davecgh/go-spew/spew/spew.go",
    "content": "/*\n * Copyright (c) 2013 Dave Collins <dave@davec.name>\n *\n * Permission to use, copy, modify, and distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\npackage spew\n\nimport (\n\t\"fmt\"\n\t\"io\"\n)\n\n// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were\n// passed with a default Formatter interface returned by NewFormatter.  It\n// returns the formatted string as a value that satisfies error.  See\n// NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Errorf(format, spew.NewFormatter(a), spew.NewFormatter(b))\nfunc Errorf(format string, a ...interface{}) (err error) {\n\treturn fmt.Errorf(format, convertArgs(a)...)\n}\n\n// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were\n// passed with a default Formatter interface returned by NewFormatter.  It\n// returns the number of bytes written and any write error encountered.  See\n// NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Fprint(w, spew.NewFormatter(a), spew.NewFormatter(b))\nfunc Fprint(w io.Writer, a ...interface{}) (n int, err error) {\n\treturn fmt.Fprint(w, convertArgs(a)...)\n}\n\n// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were\n// passed with a default Formatter interface returned by NewFormatter.  It\n// returns the number of bytes written and any write error encountered.  See\n// NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Fprintf(w, format, spew.NewFormatter(a), spew.NewFormatter(b))\nfunc Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {\n\treturn fmt.Fprintf(w, format, convertArgs(a)...)\n}\n\n// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it\n// passed with a default Formatter interface returned by NewFormatter.  See\n// NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Fprintln(w, spew.NewFormatter(a), spew.NewFormatter(b))\nfunc Fprintln(w io.Writer, a ...interface{}) (n int, err error) {\n\treturn fmt.Fprintln(w, convertArgs(a)...)\n}\n\n// Print is a wrapper for fmt.Print that treats each argument as if it were\n// passed with a default Formatter interface returned by NewFormatter.  It\n// returns the number of bytes written and any write error encountered.  See\n// NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Print(spew.NewFormatter(a), spew.NewFormatter(b))\nfunc Print(a ...interface{}) (n int, err error) {\n\treturn fmt.Print(convertArgs(a)...)\n}\n\n// Printf is a wrapper for fmt.Printf that treats each argument as if it were\n// passed with a default Formatter interface returned by NewFormatter.  It\n// returns the number of bytes written and any write error encountered.  See\n// NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Printf(format, spew.NewFormatter(a), spew.NewFormatter(b))\nfunc Printf(format string, a ...interface{}) (n int, err error) {\n\treturn fmt.Printf(format, convertArgs(a)...)\n}\n\n// Println is a wrapper for fmt.Println that treats each argument as if it were\n// passed with a default Formatter interface returned by NewFormatter.  It\n// returns the number of bytes written and any write error encountered.  See\n// NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Println(spew.NewFormatter(a), spew.NewFormatter(b))\nfunc Println(a ...interface{}) (n int, err error) {\n\treturn fmt.Println(convertArgs(a)...)\n}\n\n// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were\n// passed with a default Formatter interface returned by NewFormatter.  It\n// returns the resulting string.  See NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Sprint(spew.NewFormatter(a), spew.NewFormatter(b))\nfunc Sprint(a ...interface{}) string {\n\treturn fmt.Sprint(convertArgs(a)...)\n}\n\n// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were\n// passed with a default Formatter interface returned by NewFormatter.  It\n// returns the resulting string.  See NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Sprintf(format, spew.NewFormatter(a), spew.NewFormatter(b))\nfunc Sprintf(format string, a ...interface{}) string {\n\treturn fmt.Sprintf(format, convertArgs(a)...)\n}\n\n// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it\n// were passed with a default Formatter interface returned by NewFormatter.  It\n// returns the resulting string.  See NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Sprintln(spew.NewFormatter(a), spew.NewFormatter(b))\nfunc Sprintln(a ...interface{}) string {\n\treturn fmt.Sprintln(convertArgs(a)...)\n}\n\n// convertArgs accepts a slice of arguments and returns a slice of the same\n// length with each argument converted to a default spew Formatter interface.\nfunc convertArgs(args []interface{}) (formatters []interface{}) {\n\tformatters = make([]interface{}, len(args))\n\tfor index, arg := range args {\n\t\tformatters[index] = NewFormatter(arg)\n\t}\n\treturn formatters\n}\n"
  },
  {
    "path": "vendor/github.com/go-sql-driver/mysql/AUTHORS",
    "content": "# This is the official list of Go-MySQL-Driver authors for copyright purposes.\n\n# If you are submitting a patch, please add your name or the name of the\n# organization which holds the copyright to this list in alphabetical order.\n\n# Names should be added to this file as\n#\tName <email address>\n# The email address is not required for organizations.\n# Please keep the list sorted.\n\n\n# Individual Persons\n\nAaron Hopkins <go-sql-driver at die.net>\nAchille Roussel <achille.roussel at gmail.com>\nAlexey Palazhchenko <alexey.palazhchenko at gmail.com>\nAndrew Reid <andrew.reid at tixtrack.com>\nArne Hormann <arnehormann at gmail.com>\nAsta Xie <xiemengjun at gmail.com>\nBulat Gaifullin <gaifullinbf at gmail.com>\nCarlos Nieto <jose.carlos at menteslibres.net>\nChris Moos <chris at tech9computers.com>\nDaniel Montoya <dsmontoyam at gmail.com>\nDaniel Nichter <nil at codenode.com>\nDaniël van Eeden <git at myname.nl>\nDave Protasowski <dprotaso at gmail.com>\nDisposaBoy <disposaboy at dby.me>\nEgor Smolyakov <egorsmkv at gmail.com>\nEvan Shaw <evan at vendhq.com>\nFrederick Mayle <frederickmayle at gmail.com>\nGustavo Kristic <gkristic at gmail.com>\nHanno Braun <mail at hannobraun.com>\nHenri Yandell <flamefew at gmail.com>\nHirotaka Yamamoto <ymmt2005 at gmail.com>\nICHINOSE Shogo <shogo82148 at gmail.com>\nINADA Naoki <songofacandy at gmail.com>\nJacek Szwec <szwec.jacek at gmail.com>\nJames Harr <james.harr at gmail.com>\nJeff Hodges <jeff at somethingsimilar.com>\nJeffrey Charles <jeffreycharles at gmail.com>\nJian Zhen <zhenjl at gmail.com>\nJoshua Prunier <joshua.prunier at gmail.com>\nJulien Lefevre <julien.lefevr at gmail.com>\nJulien Schmidt <go-sql-driver at julienschmidt.com>\nJustin Li <jli at j-li.net>\nJustin Nuß <nuss.justin at gmail.com>\nKamil Dziedzic <kamil at klecza.pl>\nKevin Malachowski <kevin at chowski.com>\nKieron Woodhouse <kieron.woodhouse at infosum.com>\nLennart Rudolph <lrudolph at hmc.edu>\nLeonardo YongUk Kim <dalinaum at gmail.com>\nLinh Tran Tuan <linhduonggnu at gmail.com>\nLion Yang <lion at aosc.xyz>\nLuca Looz <luca.looz92 at gmail.com>\nLucas Liu <extrafliu at gmail.com>\nLuke Scott <luke at webconnex.com>\nMaciej Zimnoch <maciej.zimnoch@codilime.com>\nMichael Woolnough <michael.woolnough at gmail.com>\nNicola Peduzzi <thenikso at gmail.com>\nOlivier Mengué <dolmen at cpan.org>\noscarzhao <oscarzhaosl at gmail.com>\nPaul Bonser <misterpib at gmail.com>\nPeter Schultz <peter.schultz at classmarkets.com>\nRebecca Chin <rchin at pivotal.io>\nReed Allman <rdallman10 at gmail.com>\nRobert Russell <robert at rrbrussell.com>\nRunrioter Wung <runrioter at gmail.com>\nShuode Li <elemount at qq.com>\nSoroush Pour <me at soroushjp.com>\nStan Putrya <root.vagner at gmail.com>\nStanley Gunawan <gunawan.stanley at gmail.com>\nXiangyu Hu <xiangyu.hu at outlook.com>\nXiaobing Jiang <s7v7nislands at gmail.com>\nXiuming Chen <cc at cxm.cc>\nZhenye Xie <xiezhenye at gmail.com>\n\n# Organizations\n\nBarracuda Networks, Inc.\nCounting Ltd.\nGoogle Inc.\nInfoSum Ltd.\nKeybase Inc.\nPercona LLC\nPivotal Inc.\nStripe Inc.\n"
  },
  {
    "path": "vendor/github.com/go-sql-driver/mysql/CHANGELOG.md",
    "content": "## Version 1.3 (2016-12-01)\n\nChanges:\n\n - Go 1.1 is no longer supported\n - Use decimals fields in MySQL to format time types (#249)\n - Buffer optimizations (#269)\n - TLS ServerName defaults to the host (#283)\n - Refactoring (#400, #410, #437)\n - Adjusted documentation for second generation CloudSQL (#485)\n - Documented DSN system var quoting rules (#502)\n - Made statement.Close() calls idempotent to avoid errors in Go 1.6+ (#512)\n\nNew Features:\n\n - Enable microsecond resolution on TIME, DATETIME and TIMESTAMP (#249)\n - Support for returning table alias on Columns() (#289, #359, #382)\n - Placeholder interpolation, can be actived with the DSN parameter `interpolateParams=true` (#309, #318, #490)\n - Support for uint64 parameters with high bit set (#332, #345)\n - Cleartext authentication plugin support (#327)\n - Exported ParseDSN function and the Config struct (#403, #419, #429)\n - Read / Write timeouts (#401)\n - Support for JSON field type (#414)\n - Support for multi-statements and multi-results (#411, #431)\n - DSN parameter to set the driver-side max_allowed_packet value manually (#489)\n - Native password authentication plugin support (#494, #524)\n\nBugfixes:\n\n - Fixed handling of queries without columns and rows (#255)\n - Fixed a panic when SetKeepAlive() failed (#298)\n - Handle ERR packets while reading rows (#321)\n - Fixed reading NULL length-encoded integers in MySQL 5.6+ (#349)\n - Fixed absolute paths support in LOAD LOCAL DATA INFILE (#356)\n - Actually zero out bytes in handshake response (#378)\n - Fixed race condition in registering LOAD DATA INFILE handler (#383)\n - Fixed tests with MySQL 5.7.9+ (#380)\n - QueryUnescape TLS config names (#397)\n - Fixed \"broken pipe\" error by writing to closed socket (#390)\n - Fixed LOAD LOCAL DATA INFILE buffering (#424)\n - Fixed parsing of floats into float64 when placeholders are used (#434)\n - Fixed DSN tests with Go 1.7+ (#459)\n - Handle ERR packets while waiting for EOF (#473)\n - Invalidate connection on error while discarding additional results (#513)\n - Allow terminating packets of length 0 (#516)\n\n\n## Version 1.2 (2014-06-03)\n\nChanges:\n\n - We switched back to a \"rolling release\". `go get` installs the current master branch again\n - Version v1 of the driver will not be maintained anymore. Go 1.0 is no longer supported by this driver\n - Exported errors to allow easy checking from application code\n - Enabled TCP Keepalives on TCP connections\n - Optimized INFILE handling (better buffer size calculation, lazy init, ...)\n - The DSN parser also checks for a missing separating slash\n - Faster binary date / datetime to string formatting\n - Also exported the MySQLWarning type\n - mysqlConn.Close returns the first error encountered instead of ignoring all errors\n - writePacket() automatically writes the packet size to the header\n - readPacket() uses an iterative approach instead of the recursive approach to merge splitted packets\n\nNew Features:\n\n - `RegisterDial` allows the usage of a custom dial function to establish the network connection\n - Setting the connection collation is possible with the `collation` DSN parameter. This parameter should be preferred over the `charset` parameter\n - Logging of critical errors is configurable with `SetLogger`\n - Google CloudSQL support\n\nBugfixes:\n\n - Allow more than 32 parameters in prepared statements\n - Various old_password fixes\n - Fixed TestConcurrent test to pass Go's race detection\n - Fixed appendLengthEncodedInteger for large numbers\n - Renamed readLengthEnodedString to readLengthEncodedString and skipLengthEnodedString to skipLengthEncodedString (fixed typo)\n\n\n## Version 1.1 (2013-11-02)\n\nChanges:\n\n  - Go-MySQL-Driver now requires Go 1.1\n  - Connections now use the collation `utf8_general_ci` by default. Adding `&charset=UTF8` to the DSN should not be necessary anymore\n  - Made closing rows and connections error tolerant. This allows for example deferring rows.Close() without checking for errors\n  - `[]byte(nil)` is now treated as a NULL value. Before, it was treated like an empty string / `[]byte(\"\")`\n  - DSN parameter values must now be url.QueryEscape'ed. This allows text values to contain special characters, such as '&'.\n  - Use the IO buffer also for writing. This results in zero allocations (by the driver) for most queries\n  - Optimized the buffer for reading\n  - stmt.Query now caches column metadata\n  - New Logo\n  - Changed the copyright header to include all contributors\n  - Improved the LOAD INFILE documentation\n  - The driver struct is now exported to make the driver directly accessible\n  - Refactored the driver tests\n  - Added more benchmarks and moved all to a separate file\n  - Other small refactoring\n\nNew Features:\n\n  - Added *old_passwords* support: Required in some cases, but must be enabled by adding `allowOldPasswords=true` to the DSN since it is insecure\n  - Added a `clientFoundRows` parameter: Return the number of matching rows instead of the number of rows changed on UPDATEs\n  - Added TLS/SSL support: Use a TLS/SSL encrypted connection to the server. Custom TLS configs can be registered and used\n\nBugfixes:\n\n  - Fixed MySQL 4.1 support: MySQL 4.1 sends packets with lengths which differ from the specification\n  - Convert to DB timezone when inserting `time.Time`\n  - Splitted packets (more than 16MB) are now merged correctly\n  - Fixed false positive `io.EOF` errors when the data was fully read\n  - Avoid panics on reuse of closed connections\n  - Fixed empty string producing false nil values\n  - Fixed sign byte for positive TIME fields\n\n\n## Version 1.0 (2013-05-14)\n\nInitial Release\n"
  },
  {
    "path": "vendor/github.com/go-sql-driver/mysql/CONTRIBUTING.md",
    "content": "# Contributing Guidelines\n\n## Reporting Issues\n\nBefore creating a new Issue, please check first if a similar Issue [already exists](https://github.com/go-sql-driver/mysql/issues?state=open) or was [recently closed](https://github.com/go-sql-driver/mysql/issues?direction=desc&page=1&sort=updated&state=closed).\n\n## Contributing Code\n\nBy contributing to this project, you share your code under the Mozilla Public License 2, as specified in the LICENSE file.\nDon't forget to add yourself to the AUTHORS file.\n\n### Code Review\n\nEveryone is invited to review and comment on pull requests.\nIf it looks fine to you, comment with \"LGTM\" (Looks good to me).\n\nIf changes are required, notice the reviewers with \"PTAL\" (Please take another look) after committing the fixes.\n\nBefore merging the Pull Request, at least one [team member](https://github.com/go-sql-driver?tab=members) must have commented with \"LGTM\".\n\n## Development Ideas\n\nIf you are looking for ideas for code contributions, please check our [Development Ideas](https://github.com/go-sql-driver/mysql/wiki/Development-Ideas) Wiki page.\n"
  },
  {
    "path": "vendor/github.com/go-sql-driver/mysql/LICENSE",
    "content": "Mozilla Public License Version 2.0\n==================================\n\n1. Definitions\n--------------\n\n1.1. \"Contributor\"\n    means each individual or legal entity that creates, contributes to\n    the creation of, or owns Covered Software.\n\n1.2. \"Contributor Version\"\n    means the combination of the Contributions of others (if any) used\n    by a Contributor and that particular Contributor's Contribution.\n\n1.3. \"Contribution\"\n    means Covered Software of a particular Contributor.\n\n1.4. \"Covered Software\"\n    means Source Code Form to which the initial Contributor has attached\n    the notice in Exhibit A, the Executable Form of such Source Code\n    Form, and Modifications of such Source Code Form, in each case\n    including portions thereof.\n\n1.5. \"Incompatible With Secondary Licenses\"\n    means\n\n    (a) that the initial Contributor has attached the notice described\n        in Exhibit B to the Covered Software; or\n\n    (b) that the Covered Software was made available under the terms of\n        version 1.1 or earlier of the License, but not also under the\n        terms of a Secondary License.\n\n1.6. \"Executable Form\"\n    means any form of the work other than Source Code Form.\n\n1.7. \"Larger Work\"\n    means a work that combines Covered Software with other material, in \n    a separate file or files, that is not Covered Software.\n\n1.8. \"License\"\n    means this document.\n\n1.9. \"Licensable\"\n    means having the right to grant, to the maximum extent possible,\n    whether at the time of the initial grant or subsequently, any and\n    all of the rights conveyed by this License.\n\n1.10. \"Modifications\"\n    means any of the following:\n\n    (a) any file in Source Code Form that results from an addition to,\n        deletion from, or modification of the contents of Covered\n        Software; or\n\n    (b) any new file in Source Code Form that contains any Covered\n        Software.\n\n1.11. \"Patent Claims\" of a Contributor\n    means any patent claim(s), including without limitation, method,\n    process, and apparatus claims, in any patent Licensable by such\n    Contributor that would be infringed, but for the grant of the\n    License, by the making, using, selling, offering for sale, having\n    made, import, or transfer of either its Contributions or its\n    Contributor Version.\n\n1.12. \"Secondary License\"\n    means either the GNU General Public License, Version 2.0, the GNU\n    Lesser General Public License, Version 2.1, the GNU Affero General\n    Public License, Version 3.0, or any later versions of those\n    licenses.\n\n1.13. \"Source Code Form\"\n    means the form of the work preferred for making modifications.\n\n1.14. \"You\" (or \"Your\")\n    means an individual or a legal entity exercising rights under this\n    License. For legal entities, \"You\" includes any entity that\n    controls, is controlled by, or is under common control with You. For\n    purposes of this definition, \"control\" means (a) the power, direct\n    or indirect, to cause the direction or management of such entity,\n    whether by contract or otherwise, or (b) ownership of more than\n    fifty percent (50%) of the outstanding shares or beneficial\n    ownership of such entity.\n\n2. License Grants and Conditions\n--------------------------------\n\n2.1. Grants\n\nEach Contributor hereby grants You a world-wide, royalty-free,\nnon-exclusive license:\n\n(a) under intellectual property rights (other than patent or trademark)\n    Licensable by such Contributor to use, reproduce, make available,\n    modify, display, perform, distribute, and otherwise exploit its\n    Contributions, either on an unmodified basis, with Modifications, or\n    as part of a Larger Work; and\n\n(b) under Patent Claims of such Contributor to make, use, sell, offer\n    for sale, have made, import, and otherwise transfer either its\n    Contributions or its Contributor Version.\n\n2.2. Effective Date\n\nThe licenses granted in Section 2.1 with respect to any Contribution\nbecome effective for each Contribution on the date the Contributor first\ndistributes such Contribution.\n\n2.3. Limitations on Grant Scope\n\nThe licenses granted in this Section 2 are the only rights granted under\nthis License. No additional rights or licenses will be implied from the\ndistribution or licensing of Covered Software under this License.\nNotwithstanding Section 2.1(b) above, no patent license is granted by a\nContributor:\n\n(a) for any code that a Contributor has removed from Covered Software;\n    or\n\n(b) for infringements caused by: (i) Your and any other third party's\n    modifications of Covered Software, or (ii) the combination of its\n    Contributions with other software (except as part of its Contributor\n    Version); or\n\n(c) under Patent Claims infringed by Covered Software in the absence of\n    its Contributions.\n\nThis License does not grant any rights in the trademarks, service marks,\nor logos of any Contributor (except as may be necessary to comply with\nthe notice requirements in Section 3.4).\n\n2.4. Subsequent Licenses\n\nNo Contributor makes additional grants as a result of Your choice to\ndistribute the Covered Software under a subsequent version of this\nLicense (see Section 10.2) or under the terms of a Secondary License (if\npermitted under the terms of Section 3.3).\n\n2.5. Representation\n\nEach Contributor represents that the Contributor believes its\nContributions are its original creation(s) or it has sufficient rights\nto grant the rights to its Contributions conveyed by this License.\n\n2.6. Fair Use\n\nThis License is not intended to limit any rights You have under\napplicable copyright doctrines of fair use, fair dealing, or other\nequivalents.\n\n2.7. Conditions\n\nSections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted\nin Section 2.1.\n\n3. Responsibilities\n-------------------\n\n3.1. Distribution of Source Form\n\nAll distribution of Covered Software in Source Code Form, including any\nModifications that You create or to which You contribute, must be under\nthe terms of this License. You must inform recipients that the Source\nCode Form of the Covered Software is governed by the terms of this\nLicense, and how they can obtain a copy of this License. You may not\nattempt to alter or restrict the recipients' rights in the Source Code\nForm.\n\n3.2. Distribution of Executable Form\n\nIf You distribute Covered Software in Executable Form then:\n\n(a) such Covered Software must also be made available in Source Code\n    Form, as described in Section 3.1, and You must inform recipients of\n    the Executable Form how they can obtain a copy of such Source Code\n    Form by reasonable means in a timely manner, at a charge no more\n    than the cost of distribution to the recipient; and\n\n(b) You may distribute such Executable Form under the terms of this\n    License, or sublicense it under different terms, provided that the\n    license for the Executable Form does not attempt to limit or alter\n    the recipients' rights in the Source Code Form under this License.\n\n3.3. Distribution of a Larger Work\n\nYou may create and distribute a Larger Work under terms of Your choice,\nprovided that You also comply with the requirements of this License for\nthe Covered Software. If the Larger Work is a combination of Covered\nSoftware with a work governed by one or more Secondary Licenses, and the\nCovered Software is not Incompatible With Secondary Licenses, this\nLicense permits You to additionally distribute such Covered Software\nunder the terms of such Secondary License(s), so that the recipient of\nthe Larger Work may, at their option, further distribute the Covered\nSoftware under the terms of either this License or such Secondary\nLicense(s).\n\n3.4. Notices\n\nYou may not remove or alter the substance of any license notices\n(including copyright notices, patent notices, disclaimers of warranty,\nor limitations of liability) contained within the Source Code Form of\nthe Covered Software, except that You may alter any license notices to\nthe extent required to remedy known factual inaccuracies.\n\n3.5. Application of Additional Terms\n\nYou may choose to offer, and to charge a fee for, warranty, support,\nindemnity or liability obligations to one or more recipients of Covered\nSoftware. However, You may do so only on Your own behalf, and not on\nbehalf of any Contributor. You must make it absolutely clear that any\nsuch warranty, support, indemnity, or liability obligation is offered by\nYou alone, and You hereby agree to indemnify every Contributor for any\nliability incurred by such Contributor as a result of warranty, support,\nindemnity or liability terms You offer. You may include additional\ndisclaimers of warranty and limitations of liability specific to any\njurisdiction.\n\n4. Inability to Comply Due to Statute or Regulation\n---------------------------------------------------\n\nIf it is impossible for You to comply with any of the terms of this\nLicense with respect to some or all of the Covered Software due to\nstatute, judicial order, or regulation then You must: (a) comply with\nthe terms of this License to the maximum extent possible; and (b)\ndescribe the limitations and the code they affect. Such description must\nbe placed in a text file included with all distributions of the Covered\nSoftware under this License. Except to the extent prohibited by statute\nor regulation, such description must be sufficiently detailed for a\nrecipient of ordinary skill to be able to understand it.\n\n5. Termination\n--------------\n\n5.1. The rights granted under this License will terminate automatically\nif You fail to comply with any of its terms. However, if You become\ncompliant, then the rights granted under this License from a particular\nContributor are reinstated (a) provisionally, unless and until such\nContributor explicitly and finally terminates Your grants, and (b) on an\nongoing basis, if such Contributor fails to notify You of the\nnon-compliance by some reasonable means prior to 60 days after You have\ncome back into compliance. Moreover, Your grants from a particular\nContributor are reinstated on an ongoing basis if such Contributor\nnotifies You of the non-compliance by some reasonable means, this is the\nfirst time You have received notice of non-compliance with this License\nfrom such Contributor, and You become compliant prior to 30 days after\nYour receipt of the notice.\n\n5.2. If You initiate litigation against any entity by asserting a patent\ninfringement claim (excluding declaratory judgment actions,\ncounter-claims, and cross-claims) alleging that a Contributor Version\ndirectly or indirectly infringes any patent, then the rights granted to\nYou by any and all Contributors for the Covered Software under Section\n2.1 of this License shall terminate.\n\n5.3. In the event of termination under Sections 5.1 or 5.2 above, all\nend user license agreements (excluding distributors and resellers) which\nhave been validly granted by You or Your distributors under this License\nprior to termination shall survive termination.\n\n************************************************************************\n*                                                                      *\n*  6. Disclaimer of Warranty                                           *\n*  -------------------------                                           *\n*                                                                      *\n*  Covered Software is provided under this License on an \"as is\"       *\n*  basis, without warranty of any kind, either expressed, implied, or  *\n*  statutory, including, without limitation, warranties that the       *\n*  Covered Software is free of defects, merchantable, fit for a        *\n*  particular purpose or non-infringing. The entire risk as to the     *\n*  quality and performance of the Covered Software is with You.        *\n*  Should any Covered Software prove defective in any respect, You     *\n*  (not any Contributor) assume the cost of any necessary servicing,   *\n*  repair, or correction. This disclaimer of warranty constitutes an   *\n*  essential part of this License. No use of any Covered Software is   *\n*  authorized under this License except under this disclaimer.         *\n*                                                                      *\n************************************************************************\n\n************************************************************************\n*                                                                      *\n*  7. Limitation of Liability                                          *\n*  --------------------------                                          *\n*                                                                      *\n*  Under no circumstances and under no legal theory, whether tort      *\n*  (including negligence), contract, or otherwise, shall any           *\n*  Contributor, or anyone who distributes Covered Software as          *\n*  permitted above, be liable to You for any direct, indirect,         *\n*  special, incidental, or consequential damages of any character      *\n*  including, without limitation, damages for lost profits, loss of    *\n*  goodwill, work stoppage, computer failure or malfunction, or any    *\n*  and all other commercial damages or losses, even if such party      *\n*  shall have been informed of the possibility of such damages. This   *\n*  limitation of liability shall not apply to liability for death or   *\n*  personal injury resulting from such party's negligence to the       *\n*  extent applicable law prohibits such limitation. Some               *\n*  jurisdictions do not allow the exclusion or limitation of           *\n*  incidental or consequential damages, so this exclusion and          *\n*  limitation may not apply to You.                                    *\n*                                                                      *\n************************************************************************\n\n8. Litigation\n-------------\n\nAny litigation relating to this License may be brought only in the\ncourts of a jurisdiction where the defendant maintains its principal\nplace of business and such litigation shall be governed by laws of that\njurisdiction, without reference to its conflict-of-law provisions.\nNothing in this Section shall prevent a party's ability to bring\ncross-claims or counter-claims.\n\n9. Miscellaneous\n----------------\n\nThis License represents the complete agreement concerning the subject\nmatter hereof. If any provision of this License is held to be\nunenforceable, such provision shall be reformed only to the extent\nnecessary to make it enforceable. Any law or regulation which provides\nthat the language of a contract shall be construed against the drafter\nshall not be used to construe this License against a Contributor.\n\n10. Versions of the License\n---------------------------\n\n10.1. New Versions\n\nMozilla Foundation is the license steward. Except as provided in Section\n10.3, no one other than the license steward has the right to modify or\npublish new versions of this License. Each version will be given a\ndistinguishing version number.\n\n10.2. Effect of New Versions\n\nYou may distribute the Covered Software under the terms of the version\nof the License under which You originally received the Covered Software,\nor under the terms of any subsequent version published by the license\nsteward.\n\n10.3. Modified Versions\n\nIf you create software not governed by this License, and you want to\ncreate a new license for such software, you may create and use a\nmodified version of this License if you rename the license and remove\nany references to the name of the license steward (except to note that\nsuch modified license differs from this License).\n\n10.4. Distributing Source Code Form that is Incompatible With Secondary\nLicenses\n\nIf You choose to distribute Source Code Form that is Incompatible With\nSecondary Licenses under the terms of this version of the License, the\nnotice described in Exhibit B of this License must be attached.\n\nExhibit A - Source Code Form License Notice\n-------------------------------------------\n\n  This Source Code Form is subject to the terms of the Mozilla Public\n  License, v. 2.0. If a copy of the MPL was not distributed with this\n  file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\nIf it is not possible or desirable to put the notice in a particular\nfile, then You may include the notice in a location (such as a LICENSE\nfile in a relevant directory) where a recipient would be likely to look\nfor such a notice.\n\nYou may add additional accurate notices of copyright ownership.\n\nExhibit B - \"Incompatible With Secondary Licenses\" Notice\n---------------------------------------------------------\n\n  This Source Code Form is \"Incompatible With Secondary Licenses\", as\n  defined by the Mozilla Public License, v. 2.0.\n"
  },
  {
    "path": "vendor/github.com/go-sql-driver/mysql/README.md",
    "content": "# Go-MySQL-Driver\n\nA MySQL-Driver for Go's [database/sql](https://golang.org/pkg/database/sql/) package\n\n![Go-MySQL-Driver logo](https://raw.github.com/wiki/go-sql-driver/mysql/gomysql_m.png \"Golang Gopher holding the MySQL Dolphin\")\n\n---------------------------------------\n  * [Features](#features)\n  * [Requirements](#requirements)\n  * [Installation](#installation)\n  * [Usage](#usage)\n    * [DSN (Data Source Name)](#dsn-data-source-name)\n      * [Password](#password)\n      * [Protocol](#protocol)\n      * [Address](#address)\n      * [Parameters](#parameters)\n      * [Examples](#examples)\n    * [Connection pool and timeouts](#connection-pool-and-timeouts)\n    * [context.Context Support](#contextcontext-support)\n    * [ColumnType Support](#columntype-support)\n    * [LOAD DATA LOCAL INFILE support](#load-data-local-infile-support)\n    * [time.Time support](#timetime-support)\n    * [Unicode support](#unicode-support)\n  * [Testing / Development](#testing--development)\n  * [License](#license)\n\n---------------------------------------\n\n## Features\n  * Lightweight and [fast](https://github.com/go-sql-driver/sql-benchmark \"golang MySQL-Driver performance\")\n  * Native Go implementation. No C-bindings, just pure Go\n  * Connections over TCP/IPv4, TCP/IPv6, Unix domain sockets or [custom protocols](https://godoc.org/github.com/go-sql-driver/mysql#DialFunc)\n  * Automatic handling of broken connections\n  * Automatic Connection Pooling *(by database/sql package)*\n  * Supports queries larger than 16MB\n  * Full [`sql.RawBytes`](https://golang.org/pkg/database/sql/#RawBytes) support.\n  * Intelligent `LONG DATA` handling in prepared statements\n  * Secure `LOAD DATA LOCAL INFILE` support with file Whitelisting and `io.Reader` support\n  * Optional `time.Time` parsing\n  * Optional placeholder interpolation\n\n## Requirements\n  * Go 1.7 or higher. We aim to support the 3 latest versions of Go.\n  * MySQL (4.1+), MariaDB, Percona Server, Google CloudSQL or Sphinx (2.2.3+)\n\n---------------------------------------\n\n## Installation\nSimple install the package to your [$GOPATH](https://github.com/golang/go/wiki/GOPATH \"GOPATH\") with the [go tool](https://golang.org/cmd/go/ \"go command\") from shell:\n```bash\n$ go get -u github.com/go-sql-driver/mysql\n```\nMake sure [Git is installed](https://git-scm.com/downloads) on your machine and in your system's `PATH`.\n\n## Usage\n_Go MySQL Driver_ is an implementation of Go's `database/sql/driver` interface. You only need to import the driver and can use the full [`database/sql`](https://golang.org/pkg/database/sql/) API then.\n\nUse `mysql` as `driverName` and a valid [DSN](#dsn-data-source-name)  as `dataSourceName`:\n```go\nimport \"database/sql\"\nimport _ \"github.com/go-sql-driver/mysql\"\n\ndb, err := sql.Open(\"mysql\", \"user:password@/dbname\")\n```\n\n[Examples are available in our Wiki](https://github.com/go-sql-driver/mysql/wiki/Examples \"Go-MySQL-Driver Examples\").\n\n\n### DSN (Data Source Name)\n\nThe Data Source Name has a common format, like e.g. [PEAR DB](http://pear.php.net/manual/en/package.database.db.intro-dsn.php) uses it, but without type-prefix (optional parts marked by squared brackets):\n```\n[username[:password]@][protocol[(address)]]/dbname[?param1=value1&...&paramN=valueN]\n```\n\nA DSN in its fullest form:\n```\nusername:password@protocol(address)/dbname?param=value\n```\n\nExcept for the databasename, all values are optional. So the minimal DSN is:\n```\n/dbname\n```\n\nIf you do not want to preselect a database, leave `dbname` empty:\n```\n/\n```\nThis has the same effect as an empty DSN string:\n```\n\n```\n\nAlternatively, [Config.FormatDSN](https://godoc.org/github.com/go-sql-driver/mysql#Config.FormatDSN) can be used to create a DSN string by filling a struct.\n\n#### Password\nPasswords can consist of any character. Escaping is **not** necessary.\n\n#### Protocol\nSee [net.Dial](https://golang.org/pkg/net/#Dial) for more information which networks are available.\nIn general you should use an Unix domain socket if available and TCP otherwise for best performance.\n\n#### Address\nFor TCP and UDP networks, addresses have the form `host[:port]`.\nIf `port` is omitted, the default port will be used.\nIf `host` is a literal IPv6 address, it must be enclosed in square brackets.\nThe functions [net.JoinHostPort](https://golang.org/pkg/net/#JoinHostPort) and [net.SplitHostPort](https://golang.org/pkg/net/#SplitHostPort) manipulate addresses in this form.\n\nFor Unix domain sockets the address is the absolute path to the MySQL-Server-socket, e.g. `/var/run/mysqld/mysqld.sock` or `/tmp/mysql.sock`.\n\n#### Parameters\n*Parameters are case-sensitive!*\n\nNotice that any of `true`, `TRUE`, `True` or `1` is accepted to stand for a true boolean value. Not surprisingly, false can be specified as any of: `false`, `FALSE`, `False` or `0`.\n\n##### `allowAllFiles`\n\n```\nType:           bool\nValid Values:   true, false\nDefault:        false\n```\n\n`allowAllFiles=true` disables the file Whitelist for `LOAD DATA LOCAL INFILE` and allows *all* files.\n[*Might be insecure!*](http://dev.mysql.com/doc/refman/5.7/en/load-data-local.html)\n\n##### `allowCleartextPasswords`\n\n```\nType:           bool\nValid Values:   true, false\nDefault:        false\n```\n\n`allowCleartextPasswords=true` allows using the [cleartext client side plugin](http://dev.mysql.com/doc/en/cleartext-authentication-plugin.html) if required by an account, such as one defined with the [PAM authentication plugin](http://dev.mysql.com/doc/en/pam-authentication-plugin.html). Sending passwords in clear text may be a security problem in some configurations. To avoid problems if there is any possibility that the password would be intercepted, clients should connect to MySQL Server using a method that protects the password. Possibilities include [TLS / SSL](#tls), IPsec, or a private network.\n\n##### `allowNativePasswords`\n\n```\nType:           bool\nValid Values:   true, false\nDefault:        true\n```\n`allowNativePasswords=false` disallows the usage of MySQL native password method.\n\n##### `allowOldPasswords`\n\n```\nType:           bool\nValid Values:   true, false\nDefault:        false\n```\n`allowOldPasswords=true` allows the usage of the insecure old password method. This should be avoided, but is necessary in some cases. See also [the old_passwords wiki page](https://github.com/go-sql-driver/mysql/wiki/old_passwords).\n\n##### `charset`\n\n```\nType:           string\nValid Values:   <name>\nDefault:        none\n```\n\nSets the charset used for client-server interaction (`\"SET NAMES <value>\"`). If multiple charsets are set (separated by a comma), the following charset is used if setting the charset failes. This enables for example support for `utf8mb4` ([introduced in MySQL 5.5.3](http://dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8mb4.html)) with fallback to `utf8` for older servers (`charset=utf8mb4,utf8`).\n\nUsage of the `charset` parameter is discouraged because it issues additional queries to the server.\nUnless you need the fallback behavior, please use `collation` instead.\n\n##### `collation`\n\n```\nType:           string\nValid Values:   <name>\nDefault:        utf8_general_ci\n```\n\nSets the collation used for client-server interaction on connection. In contrast to `charset`, `collation` does not issue additional queries. If the specified collation is unavailable on the target server, the connection will fail.\n\nA list of valid charsets for a server is retrievable with `SHOW COLLATION`.\n\n##### `clientFoundRows`\n\n```\nType:           bool\nValid Values:   true, false\nDefault:        false\n```\n\n`clientFoundRows=true` causes an UPDATE to return the number of matching rows instead of the number of rows changed.\n\n##### `columnsWithAlias`\n\n```\nType:           bool\nValid Values:   true, false\nDefault:        false\n```\n\nWhen `columnsWithAlias` is true, calls to `sql.Rows.Columns()` will return the table alias and the column name separated by a dot. For example:\n\n```\nSELECT u.id FROM users as u\n```\n\nwill return `u.id` instead of just `id` if `columnsWithAlias=true`.\n\n##### `interpolateParams`\n\n```\nType:           bool\nValid Values:   true, false\nDefault:        false\n```\n\nIf `interpolateParams` is true, placeholders (`?`) in calls to `db.Query()` and `db.Exec()` are interpolated into a single query string with given parameters. This reduces the number of roundtrips, since the driver has to prepare a statement, execute it with given parameters and close the statement again with `interpolateParams=false`.\n\n*This can not be used together with the multibyte encodings BIG5, CP932, GB2312, GBK or SJIS. These are blacklisted as they may [introduce a SQL injection vulnerability](http://stackoverflow.com/a/12118602/3430118)!*\n\n##### `loc`\n\n```\nType:           string\nValid Values:   <escaped name>\nDefault:        UTC\n```\n\nSets the location for time.Time values (when using `parseTime=true`). *\"Local\"* sets the system's location. See [time.LoadLocation](https://golang.org/pkg/time/#LoadLocation) for details.\n\nNote that this sets the location for time.Time values but does not change MySQL's [time_zone setting](https://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html). For that see the [time_zone system variable](#system-variables), which can also be set as a DSN parameter.\n\nPlease keep in mind, that param values must be [url.QueryEscape](https://golang.org/pkg/net/url/#QueryEscape)'ed. Alternatively you can manually replace the `/` with `%2F`. For example `US/Pacific` would be `loc=US%2FPacific`.\n\n##### `maxAllowedPacket`\n```\nType:          decimal number\nDefault:       4194304\n```\n\nMax packet size allowed in bytes. The default value is 4 MiB and should be adjusted to match the server settings. `maxAllowedPacket=0` can be used to automatically fetch the `max_allowed_packet` variable from server *on every connection*.\n\n##### `multiStatements`\n\n```\nType:           bool\nValid Values:   true, false\nDefault:        false\n```\n\nAllow multiple statements in one query. While this allows batch queries, it also greatly increases the risk of SQL injections. Only the result of the first query is returned, all other results are silently discarded.\n\nWhen `multiStatements` is used, `?` parameters must only be used in the first statement.\n\n##### `parseTime`\n\n```\nType:           bool\nValid Values:   true, false\nDefault:        false\n```\n\n`parseTime=true` changes the output type of `DATE` and `DATETIME` values to `time.Time` instead of `[]byte` / `string`\n\n\n##### `readTimeout`\n\n```\nType:           duration\nDefault:        0\n```\n\nI/O read timeout. The value must be a decimal number with a unit suffix (*\"ms\"*, *\"s\"*, *\"m\"*, *\"h\"*), such as *\"30s\"*, *\"0.5m\"* or *\"1m30s\"*.\n\n##### `rejectReadOnly`\n\n```\nType:           bool\nValid Values:   true, false\nDefault:        false\n```\n\n\n`rejectReadOnly=true` causes the driver to reject read-only connections. This\nis for a possible race condition during an automatic failover, where the mysql\nclient gets connected to a read-only replica after the failover.\n\nNote that this should be a fairly rare case, as an automatic failover normally\nhappens when the primary is down, and the race condition shouldn't happen\nunless it comes back up online as soon as the failover is kicked off. On the\nother hand, when this happens, a MySQL application can get stuck on a\nread-only connection until restarted. It is however fairly easy to reproduce,\nfor example, using a manual failover on AWS Aurora's MySQL-compatible cluster.\n\nIf you are not relying on read-only transactions to reject writes that aren't\nsupposed to happen, setting this on some MySQL providers (such as AWS Aurora)\nis safer for failovers.\n\nNote that ERROR 1290 can be returned for a `read-only` server and this option will\ncause a retry for that error. However the same error number is used for some\nother cases. You should ensure your application will never cause an ERROR 1290\nexcept for `read-only` mode when enabling this option.\n\n\n##### `timeout`\n\n```\nType:           duration\nDefault:        OS default\n```\n\nTimeout for establishing connections, aka dial timeout. The value must be a decimal number with a unit suffix (*\"ms\"*, *\"s\"*, *\"m\"*, *\"h\"*), such as *\"30s\"*, *\"0.5m\"* or *\"1m30s\"*.\n\n\n##### `tls`\n\n```\nType:           bool / string\nValid Values:   true, false, skip-verify, <name>\nDefault:        false\n```\n\n`tls=true` enables TLS / SSL encrypted connection to the server. Use `skip-verify` if you want to use a self-signed or invalid certificate (server side). Use a custom value registered with [`mysql.RegisterTLSConfig`](https://godoc.org/github.com/go-sql-driver/mysql#RegisterTLSConfig).\n\n\n##### `writeTimeout`\n\n```\nType:           duration\nDefault:        0\n```\n\nI/O write timeout. The value must be a decimal number with a unit suffix (*\"ms\"*, *\"s\"*, *\"m\"*, *\"h\"*), such as *\"30s\"*, *\"0.5m\"* or *\"1m30s\"*.\n\n\n##### System Variables\n\nAny other parameters are interpreted as system variables:\n  * `<boolean_var>=<value>`: `SET <boolean_var>=<value>`\n  * `<enum_var>=<value>`: `SET <enum_var>=<value>`\n  * `<string_var>=%27<value>%27`: `SET <string_var>='<value>'`\n\nRules:\n* The values for string variables must be quoted with `'`.\n* The values must also be [url.QueryEscape](http://golang.org/pkg/net/url/#QueryEscape)'ed!\n (which implies values of string variables must be wrapped with `%27`).\n\nExamples:\n  * `autocommit=1`: `SET autocommit=1`\n  * [`time_zone=%27Europe%2FParis%27`](https://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html): `SET time_zone='Europe/Paris'`\n  * [`tx_isolation=%27REPEATABLE-READ%27`](https://dev.mysql.com/doc/refman/5.5/en/server-system-variables.html#sysvar_tx_isolation): `SET tx_isolation='REPEATABLE-READ'`\n\n\n#### Examples\n```\nuser@unix(/path/to/socket)/dbname\n```\n\n```\nroot:pw@unix(/tmp/mysql.sock)/myDatabase?loc=Local\n```\n\n```\nuser:password@tcp(localhost:5555)/dbname?tls=skip-verify&autocommit=true\n```\n\nTreat warnings as errors by setting the system variable [`sql_mode`](https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html):\n```\nuser:password@/dbname?sql_mode=TRADITIONAL\n```\n\nTCP via IPv6:\n```\nuser:password@tcp([de:ad:be:ef::ca:fe]:80)/dbname?timeout=90s&collation=utf8mb4_unicode_ci\n```\n\nTCP on a remote host, e.g. Amazon RDS:\n```\nid:password@tcp(your-amazonaws-uri.com:3306)/dbname\n```\n\nGoogle Cloud SQL on App Engine (First Generation MySQL Server):\n```\nuser@cloudsql(project-id:instance-name)/dbname\n```\n\nGoogle Cloud SQL on App Engine (Second Generation MySQL Server):\n```\nuser@cloudsql(project-id:regionname:instance-name)/dbname\n```\n\nTCP using default port (3306) on localhost:\n```\nuser:password@tcp/dbname?charset=utf8mb4,utf8&sys_var=esc%40ped\n```\n\nUse the default protocol (tcp) and host (localhost:3306):\n```\nuser:password@/dbname\n```\n\nNo Database preselected:\n```\nuser:password@/\n```\n\n\n### Connection pool and timeouts\nThe connection pool is managed by Go's database/sql package. For details on how to configure the size of the pool and how long connections stay in the pool see `*DB.SetMaxOpenConns`, `*DB.SetMaxIdleConns`, and `*DB.SetConnMaxLifetime` in the [database/sql documentation](https://golang.org/pkg/database/sql/). The read, write, and dial timeouts for each individual connection are configured with the DSN parameters [`readTimeout`](#readtimeout), [`writeTimeout`](#writetimeout), and [`timeout`](#timeout), respectively.\n\n## `ColumnType` Support\nThis driver supports the [`ColumnType` interface](https://golang.org/pkg/database/sql/#ColumnType) introduced in Go 1.8, with the exception of [`ColumnType.Length()`](https://golang.org/pkg/database/sql/#ColumnType.Length), which is currently not supported.\n\n## `context.Context` Support\nGo 1.8 added `database/sql` support for `context.Context`. This driver supports query timeouts and cancellation via contexts.\nSee [context support in the database/sql package](https://golang.org/doc/go1.8#database_sql) for more details.\n\n\n### `LOAD DATA LOCAL INFILE` support\nFor this feature you need direct access to the package. Therefore you must change the import path (no `_`):\n```go\nimport \"github.com/go-sql-driver/mysql\"\n```\n\nFiles must be whitelisted by registering them with `mysql.RegisterLocalFile(filepath)` (recommended) or the Whitelist check must be deactivated by using the DSN parameter `allowAllFiles=true` ([*Might be insecure!*](http://dev.mysql.com/doc/refman/5.7/en/load-data-local.html)).\n\nTo use a `io.Reader` a handler function must be registered with `mysql.RegisterReaderHandler(name, handler)` which returns a `io.Reader` or `io.ReadCloser`. The Reader is available with the filepath `Reader::<name>` then. Choose different names for different handlers and `DeregisterReaderHandler` when you don't need it anymore.\n\nSee the [godoc of Go-MySQL-Driver](https://godoc.org/github.com/go-sql-driver/mysql \"golang mysql driver documentation\") for details.\n\n\n### `time.Time` support\nThe default internal output type of MySQL `DATE` and `DATETIME` values is `[]byte` which allows you to scan the value into a `[]byte`, `string` or `sql.RawBytes` variable in your program.\n\nHowever, many want to scan MySQL `DATE` and `DATETIME` values into `time.Time` variables, which is the logical opposite in Go to `DATE` and `DATETIME` in MySQL. You can do that by changing the internal output type from `[]byte` to `time.Time` with the DSN parameter `parseTime=true`. You can set the default [`time.Time` location](https://golang.org/pkg/time/#Location) with the `loc` DSN parameter.\n\n**Caution:** As of Go 1.1, this makes `time.Time` the only variable type you can scan `DATE` and `DATETIME` values into. This breaks for example [`sql.RawBytes` support](https://github.com/go-sql-driver/mysql/wiki/Examples#rawbytes).\n\nAlternatively you can use the [`NullTime`](https://godoc.org/github.com/go-sql-driver/mysql#NullTime) type as the scan destination, which works with both `time.Time` and `string` / `[]byte`.\n\n\n### Unicode support\nSince version 1.1 Go-MySQL-Driver automatically uses the collation `utf8_general_ci` by default.\n\nOther collations / charsets can be set using the [`collation`](#collation) DSN parameter.\n\nVersion 1.0 of the driver recommended adding `&charset=utf8` (alias for `SET NAMES utf8`) to the DSN to enable proper UTF-8 support. This is not necessary anymore. The [`collation`](#collation) parameter should be preferred to set another collation / charset than the default.\n\nSee http://dev.mysql.com/doc/refman/5.7/en/charset-unicode.html for more details on MySQL's Unicode support.\n\n## Testing / Development\nTo run the driver tests you may need to adjust the configuration. See the [Testing Wiki-Page](https://github.com/go-sql-driver/mysql/wiki/Testing \"Testing\") for details.\n\nGo-MySQL-Driver is not feature-complete yet. Your help is very appreciated.\nIf you want to contribute, you can work on an [open issue](https://github.com/go-sql-driver/mysql/issues?state=open) or review a [pull request](https://github.com/go-sql-driver/mysql/pulls).\n\nSee the [Contribution Guidelines](https://github.com/go-sql-driver/mysql/blob/master/CONTRIBUTING.md) for details.\n\n---------------------------------------\n\n## License\nGo-MySQL-Driver is licensed under the [Mozilla Public License Version 2.0](https://raw.github.com/go-sql-driver/mysql/master/LICENSE)\n\nMozilla summarizes the license scope as follows:\n> MPL: The copyleft applies to any files containing MPLed code.\n\n\nThat means:\n  * You can **use** the **unchanged** source code both in private and commercially.\n  * When distributing, you **must publish** the source code of any **changed files** licensed under the MPL 2.0 under a) the MPL 2.0 itself or b) a compatible license (e.g. GPL 3.0 or Apache License 2.0).\n  * You **needn't publish** the source code of your library as long as the files licensed under the MPL 2.0 are **unchanged**.\n\nPlease read the [MPL 2.0 FAQ](https://www.mozilla.org/en-US/MPL/2.0/FAQ/) if you have further questions regarding the license.\n\nYou can read the full terms here: [LICENSE](https://raw.github.com/go-sql-driver/mysql/master/LICENSE).\n\n![Go Gopher and MySQL Dolphin](https://raw.github.com/wiki/go-sql-driver/mysql/go-mysql-driver_m.jpg \"Golang Gopher transporting the MySQL Dolphin in a wheelbarrow\")\n\n"
  },
  {
    "path": "vendor/github.com/go-sql-driver/mysql/appengine.go",
    "content": "// Go MySQL Driver - A MySQL-Driver for Go's database/sql package\n//\n// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.\n//\n// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this file,\n// You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// +build appengine\n\npackage mysql\n\nimport (\n\t\"google.golang.org/appengine/cloudsql\"\n)\n\nfunc init() {\n\tRegisterDial(\"cloudsql\", cloudsql.Dial)\n}\n"
  },
  {
    "path": "vendor/github.com/go-sql-driver/mysql/buffer.go",
    "content": "// Go MySQL Driver - A MySQL-Driver for Go's database/sql package\n//\n// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.\n//\n// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this file,\n// You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage mysql\n\nimport (\n\t\"io\"\n\t\"net\"\n\t\"time\"\n)\n\nconst defaultBufSize = 4096\n\n// A buffer which is used for both reading and writing.\n// This is possible since communication on each connection is synchronous.\n// In other words, we can't write and read simultaneously on the same connection.\n// The buffer is similar to bufio.Reader / Writer but zero-copy-ish\n// Also highly optimized for this particular use case.\ntype buffer struct {\n\tbuf     []byte\n\tnc      net.Conn\n\tidx     int\n\tlength  int\n\ttimeout time.Duration\n}\n\nfunc newBuffer(nc net.Conn) buffer {\n\tvar b [defaultBufSize]byte\n\treturn buffer{\n\t\tbuf: b[:],\n\t\tnc:  nc,\n\t}\n}\n\n// fill reads into the buffer until at least _need_ bytes are in it\nfunc (b *buffer) fill(need int) error {\n\tn := b.length\n\n\t// move existing data to the beginning\n\tif n > 0 && b.idx > 0 {\n\t\tcopy(b.buf[0:n], b.buf[b.idx:])\n\t}\n\n\t// grow buffer if necessary\n\t// TODO: let the buffer shrink again at some point\n\t//       Maybe keep the org buf slice and swap back?\n\tif need > len(b.buf) {\n\t\t// Round up to the next multiple of the default size\n\t\tnewBuf := make([]byte, ((need/defaultBufSize)+1)*defaultBufSize)\n\t\tcopy(newBuf, b.buf)\n\t\tb.buf = newBuf\n\t}\n\n\tb.idx = 0\n\n\tfor {\n\t\tif b.timeout > 0 {\n\t\t\tif err := b.nc.SetReadDeadline(time.Now().Add(b.timeout)); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tnn, err := b.nc.Read(b.buf[n:])\n\t\tn += nn\n\n\t\tswitch err {\n\t\tcase nil:\n\t\t\tif n < need {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tb.length = n\n\t\t\treturn nil\n\n\t\tcase io.EOF:\n\t\t\tif n >= need {\n\t\t\t\tb.length = n\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\treturn io.ErrUnexpectedEOF\n\n\t\tdefault:\n\t\t\treturn err\n\t\t}\n\t}\n}\n\n// returns next N bytes from buffer.\n// The returned slice is only guaranteed to be valid until the next read\nfunc (b *buffer) readNext(need int) ([]byte, error) {\n\tif b.length < need {\n\t\t// refill\n\t\tif err := b.fill(need); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\toffset := b.idx\n\tb.idx += need\n\tb.length -= need\n\treturn b.buf[offset:b.idx], nil\n}\n\n// returns a buffer with the requested size.\n// If possible, a slice from the existing buffer is returned.\n// Otherwise a bigger buffer is made.\n// Only one buffer (total) can be used at a time.\nfunc (b *buffer) takeBuffer(length int) []byte {\n\tif b.length > 0 {\n\t\treturn nil\n\t}\n\n\t// test (cheap) general case first\n\tif length <= defaultBufSize || length <= cap(b.buf) {\n\t\treturn b.buf[:length]\n\t}\n\n\tif length < maxPacketSize {\n\t\tb.buf = make([]byte, length)\n\t\treturn b.buf\n\t}\n\treturn make([]byte, length)\n}\n\n// shortcut which can be used if the requested buffer is guaranteed to be\n// smaller than defaultBufSize\n// Only one buffer (total) can be used at a time.\nfunc (b *buffer) takeSmallBuffer(length int) []byte {\n\tif b.length == 0 {\n\t\treturn b.buf[:length]\n\t}\n\treturn nil\n}\n\n// takeCompleteBuffer returns the complete existing buffer.\n// This can be used if the necessary buffer size is unknown.\n// Only one buffer (total) can be used at a time.\nfunc (b *buffer) takeCompleteBuffer() []byte {\n\tif b.length == 0 {\n\t\treturn b.buf\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/go-sql-driver/mysql/collations.go",
    "content": "// Go MySQL Driver - A MySQL-Driver for Go's database/sql package\n//\n// Copyright 2014 The Go-MySQL-Driver Authors. All rights reserved.\n//\n// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this file,\n// You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage mysql\n\nconst defaultCollation = \"utf8_general_ci\"\nconst binaryCollation = \"binary\"\n\n// A list of available collations mapped to the internal ID.\n// To update this map use the following MySQL query:\n//     SELECT COLLATION_NAME, ID FROM information_schema.COLLATIONS\nvar collations = map[string]byte{\n\t\"big5_chinese_ci\":          1,\n\t\"latin2_czech_cs\":          2,\n\t\"dec8_swedish_ci\":          3,\n\t\"cp850_general_ci\":         4,\n\t\"latin1_german1_ci\":        5,\n\t\"hp8_english_ci\":           6,\n\t\"koi8r_general_ci\":         7,\n\t\"latin1_swedish_ci\":        8,\n\t\"latin2_general_ci\":        9,\n\t\"swe7_swedish_ci\":          10,\n\t\"ascii_general_ci\":         11,\n\t\"ujis_japanese_ci\":         12,\n\t\"sjis_japanese_ci\":         13,\n\t\"cp1251_bulgarian_ci\":      14,\n\t\"latin1_danish_ci\":         15,\n\t\"hebrew_general_ci\":        16,\n\t\"tis620_thai_ci\":           18,\n\t\"euckr_korean_ci\":          19,\n\t\"latin7_estonian_cs\":       20,\n\t\"latin2_hungarian_ci\":      21,\n\t\"koi8u_general_ci\":         22,\n\t\"cp1251_ukrainian_ci\":      23,\n\t\"gb2312_chinese_ci\":        24,\n\t\"greek_general_ci\":         25,\n\t\"cp1250_general_ci\":        26,\n\t\"latin2_croatian_ci\":       27,\n\t\"gbk_chinese_ci\":           28,\n\t\"cp1257_lithuanian_ci\":     29,\n\t\"latin5_turkish_ci\":        30,\n\t\"latin1_german2_ci\":        31,\n\t\"armscii8_general_ci\":      32,\n\t\"utf8_general_ci\":          33,\n\t\"cp1250_czech_cs\":          34,\n\t\"ucs2_general_ci\":          35,\n\t\"cp866_general_ci\":         36,\n\t\"keybcs2_general_ci\":       37,\n\t\"macce_general_ci\":         38,\n\t\"macroman_general_ci\":      39,\n\t\"cp852_general_ci\":         40,\n\t\"latin7_general_ci\":        41,\n\t\"latin7_general_cs\":        42,\n\t\"macce_bin\":                43,\n\t\"cp1250_croatian_ci\":       44,\n\t\"utf8mb4_general_ci\":       45,\n\t\"utf8mb4_bin\":              46,\n\t\"latin1_bin\":               47,\n\t\"latin1_general_ci\":        48,\n\t\"latin1_general_cs\":        49,\n\t\"cp1251_bin\":               50,\n\t\"cp1251_general_ci\":        51,\n\t\"cp1251_general_cs\":        52,\n\t\"macroman_bin\":             53,\n\t\"utf16_general_ci\":         54,\n\t\"utf16_bin\":                55,\n\t\"utf16le_general_ci\":       56,\n\t\"cp1256_general_ci\":        57,\n\t\"cp1257_bin\":               58,\n\t\"cp1257_general_ci\":        59,\n\t\"utf32_general_ci\":         60,\n\t\"utf32_bin\":                61,\n\t\"utf16le_bin\":              62,\n\t\"binary\":                   63,\n\t\"armscii8_bin\":             64,\n\t\"ascii_bin\":                65,\n\t\"cp1250_bin\":               66,\n\t\"cp1256_bin\":               67,\n\t\"cp866_bin\":                68,\n\t\"dec8_bin\":                 69,\n\t\"greek_bin\":                70,\n\t\"hebrew_bin\":               71,\n\t\"hp8_bin\":                  72,\n\t\"keybcs2_bin\":              73,\n\t\"koi8r_bin\":                74,\n\t\"koi8u_bin\":                75,\n\t\"latin2_bin\":               77,\n\t\"latin5_bin\":               78,\n\t\"latin7_bin\":               79,\n\t\"cp850_bin\":                80,\n\t\"cp852_bin\":                81,\n\t\"swe7_bin\":                 82,\n\t\"utf8_bin\":                 83,\n\t\"big5_bin\":                 84,\n\t\"euckr_bin\":                85,\n\t\"gb2312_bin\":               86,\n\t\"gbk_bin\":                  87,\n\t\"sjis_bin\":                 88,\n\t\"tis620_bin\":               89,\n\t\"ucs2_bin\":                 90,\n\t\"ujis_bin\":                 91,\n\t\"geostd8_general_ci\":       92,\n\t\"geostd8_bin\":              93,\n\t\"latin1_spanish_ci\":        94,\n\t\"cp932_japanese_ci\":        95,\n\t\"cp932_bin\":                96,\n\t\"eucjpms_japanese_ci\":      97,\n\t\"eucjpms_bin\":              98,\n\t\"cp1250_polish_ci\":         99,\n\t\"utf16_unicode_ci\":         101,\n\t\"utf16_icelandic_ci\":       102,\n\t\"utf16_latvian_ci\":         103,\n\t\"utf16_romanian_ci\":        104,\n\t\"utf16_slovenian_ci\":       105,\n\t\"utf16_polish_ci\":          106,\n\t\"utf16_estonian_ci\":        107,\n\t\"utf16_spanish_ci\":         108,\n\t\"utf16_swedish_ci\":         109,\n\t\"utf16_turkish_ci\":         110,\n\t\"utf16_czech_ci\":           111,\n\t\"utf16_danish_ci\":          112,\n\t\"utf16_lithuanian_ci\":      113,\n\t\"utf16_slovak_ci\":          114,\n\t\"utf16_spanish2_ci\":        115,\n\t\"utf16_roman_ci\":           116,\n\t\"utf16_persian_ci\":         117,\n\t\"utf16_esperanto_ci\":       118,\n\t\"utf16_hungarian_ci\":       119,\n\t\"utf16_sinhala_ci\":         120,\n\t\"utf16_german2_ci\":         121,\n\t\"utf16_croatian_ci\":        122,\n\t\"utf16_unicode_520_ci\":     123,\n\t\"utf16_vietnamese_ci\":      124,\n\t\"ucs2_unicode_ci\":          128,\n\t\"ucs2_icelandic_ci\":        129,\n\t\"ucs2_latvian_ci\":          130,\n\t\"ucs2_romanian_ci\":         131,\n\t\"ucs2_slovenian_ci\":        132,\n\t\"ucs2_polish_ci\":           133,\n\t\"ucs2_estonian_ci\":         134,\n\t\"ucs2_spanish_ci\":          135,\n\t\"ucs2_swedish_ci\":          136,\n\t\"ucs2_turkish_ci\":          137,\n\t\"ucs2_czech_ci\":            138,\n\t\"ucs2_danish_ci\":           139,\n\t\"ucs2_lithuanian_ci\":       140,\n\t\"ucs2_slovak_ci\":           141,\n\t\"ucs2_spanish2_ci\":         142,\n\t\"ucs2_roman_ci\":            143,\n\t\"ucs2_persian_ci\":          144,\n\t\"ucs2_esperanto_ci\":        145,\n\t\"ucs2_hungarian_ci\":        146,\n\t\"ucs2_sinhala_ci\":          147,\n\t\"ucs2_german2_ci\":          148,\n\t\"ucs2_croatian_ci\":         149,\n\t\"ucs2_unicode_520_ci\":      150,\n\t\"ucs2_vietnamese_ci\":       151,\n\t\"ucs2_general_mysql500_ci\": 159,\n\t\"utf32_unicode_ci\":         160,\n\t\"utf32_icelandic_ci\":       161,\n\t\"utf32_latvian_ci\":         162,\n\t\"utf32_romanian_ci\":        163,\n\t\"utf32_slovenian_ci\":       164,\n\t\"utf32_polish_ci\":          165,\n\t\"utf32_estonian_ci\":        166,\n\t\"utf32_spanish_ci\":         167,\n\t\"utf32_swedish_ci\":         168,\n\t\"utf32_turkish_ci\":         169,\n\t\"utf32_czech_ci\":           170,\n\t\"utf32_danish_ci\":          171,\n\t\"utf32_lithuanian_ci\":      172,\n\t\"utf32_slovak_ci\":          173,\n\t\"utf32_spanish2_ci\":        174,\n\t\"utf32_roman_ci\":           175,\n\t\"utf32_persian_ci\":         176,\n\t\"utf32_esperanto_ci\":       177,\n\t\"utf32_hungarian_ci\":       178,\n\t\"utf32_sinhala_ci\":         179,\n\t\"utf32_german2_ci\":         180,\n\t\"utf32_croatian_ci\":        181,\n\t\"utf32_unicode_520_ci\":     182,\n\t\"utf32_vietnamese_ci\":      183,\n\t\"utf8_unicode_ci\":          192,\n\t\"utf8_icelandic_ci\":        193,\n\t\"utf8_latvian_ci\":          194,\n\t\"utf8_romanian_ci\":         195,\n\t\"utf8_slovenian_ci\":        196,\n\t\"utf8_polish_ci\":           197,\n\t\"utf8_estonian_ci\":         198,\n\t\"utf8_spanish_ci\":          199,\n\t\"utf8_swedish_ci\":          200,\n\t\"utf8_turkish_ci\":          201,\n\t\"utf8_czech_ci\":            202,\n\t\"utf8_danish_ci\":           203,\n\t\"utf8_lithuanian_ci\":       204,\n\t\"utf8_slovak_ci\":           205,\n\t\"utf8_spanish2_ci\":         206,\n\t\"utf8_roman_ci\":            207,\n\t\"utf8_persian_ci\":          208,\n\t\"utf8_esperanto_ci\":        209,\n\t\"utf8_hungarian_ci\":        210,\n\t\"utf8_sinhala_ci\":          211,\n\t\"utf8_german2_ci\":          212,\n\t\"utf8_croatian_ci\":         213,\n\t\"utf8_unicode_520_ci\":      214,\n\t\"utf8_vietnamese_ci\":       215,\n\t\"utf8_general_mysql500_ci\": 223,\n\t\"utf8mb4_unicode_ci\":       224,\n\t\"utf8mb4_icelandic_ci\":     225,\n\t\"utf8mb4_latvian_ci\":       226,\n\t\"utf8mb4_romanian_ci\":      227,\n\t\"utf8mb4_slovenian_ci\":     228,\n\t\"utf8mb4_polish_ci\":        229,\n\t\"utf8mb4_estonian_ci\":      230,\n\t\"utf8mb4_spanish_ci\":       231,\n\t\"utf8mb4_swedish_ci\":       232,\n\t\"utf8mb4_turkish_ci\":       233,\n\t\"utf8mb4_czech_ci\":         234,\n\t\"utf8mb4_danish_ci\":        235,\n\t\"utf8mb4_lithuanian_ci\":    236,\n\t\"utf8mb4_slovak_ci\":        237,\n\t\"utf8mb4_spanish2_ci\":      238,\n\t\"utf8mb4_roman_ci\":         239,\n\t\"utf8mb4_persian_ci\":       240,\n\t\"utf8mb4_esperanto_ci\":     241,\n\t\"utf8mb4_hungarian_ci\":     242,\n\t\"utf8mb4_sinhala_ci\":       243,\n\t\"utf8mb4_german2_ci\":       244,\n\t\"utf8mb4_croatian_ci\":      245,\n\t\"utf8mb4_unicode_520_ci\":   246,\n\t\"utf8mb4_vietnamese_ci\":    247,\n}\n\n// A blacklist of collations which is unsafe to interpolate parameters.\n// These multibyte encodings may contains 0x5c (`\\`) in their trailing bytes.\nvar unsafeCollations = map[string]bool{\n\t\"big5_chinese_ci\":   true,\n\t\"sjis_japanese_ci\":  true,\n\t\"gbk_chinese_ci\":    true,\n\t\"big5_bin\":          true,\n\t\"gb2312_bin\":        true,\n\t\"gbk_bin\":           true,\n\t\"sjis_bin\":          true,\n\t\"cp932_japanese_ci\": true,\n\t\"cp932_bin\":         true,\n}\n"
  },
  {
    "path": "vendor/github.com/go-sql-driver/mysql/connection.go",
    "content": "// Go MySQL Driver - A MySQL-Driver for Go's database/sql package\n//\n// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.\n//\n// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this file,\n// You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage mysql\n\nimport (\n\t\"database/sql/driver\"\n\t\"io\"\n\t\"net\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n)\n\n// a copy of context.Context for Go 1.7 and earlier\ntype mysqlContext interface {\n\tDone() <-chan struct{}\n\tErr() error\n\n\t// defined in context.Context, but not used in this driver:\n\t// Deadline() (deadline time.Time, ok bool)\n\t// Value(key interface{}) interface{}\n}\n\ntype mysqlConn struct {\n\tbuf              buffer\n\tnetConn          net.Conn\n\taffectedRows     uint64\n\tinsertId         uint64\n\tcfg              *Config\n\tmaxAllowedPacket int\n\tmaxWriteSize     int\n\twriteTimeout     time.Duration\n\tflags            clientFlag\n\tstatus           statusFlag\n\tsequence         uint8\n\tparseTime        bool\n\n\t// for context support (Go 1.8+)\n\twatching bool\n\twatcher  chan<- mysqlContext\n\tclosech  chan struct{}\n\tfinished chan<- struct{}\n\tcanceled atomicError // set non-nil if conn is canceled\n\tclosed   atomicBool  // set when conn is closed, before closech is closed\n}\n\n// Handles parameters set in DSN after the connection is established\nfunc (mc *mysqlConn) handleParams() (err error) {\n\tfor param, val := range mc.cfg.Params {\n\t\tswitch param {\n\t\t// Charset\n\t\tcase \"charset\":\n\t\t\tcharsets := strings.Split(val, \",\")\n\t\t\tfor i := range charsets {\n\t\t\t\t// ignore errors here - a charset may not exist\n\t\t\t\terr = mc.exec(\"SET NAMES \" + charsets[i])\n\t\t\t\tif err == nil {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t// System Vars\n\t\tdefault:\n\t\t\terr = mc.exec(\"SET \" + param + \"=\" + val + \"\")\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\treturn\n}\n\nfunc (mc *mysqlConn) markBadConn(err error) error {\n\tif mc == nil {\n\t\treturn err\n\t}\n\tif err != errBadConnNoWrite {\n\t\treturn err\n\t}\n\treturn driver.ErrBadConn\n}\n\nfunc (mc *mysqlConn) Begin() (driver.Tx, error) {\n\treturn mc.begin(false)\n}\n\nfunc (mc *mysqlConn) begin(readOnly bool) (driver.Tx, error) {\n\tif mc.closed.IsSet() {\n\t\terrLog.Print(ErrInvalidConn)\n\t\treturn nil, driver.ErrBadConn\n\t}\n\tvar q string\n\tif readOnly {\n\t\tq = \"START TRANSACTION READ ONLY\"\n\t} else {\n\t\tq = \"START TRANSACTION\"\n\t}\n\terr := mc.exec(q)\n\tif err == nil {\n\t\treturn &mysqlTx{mc}, err\n\t}\n\treturn nil, mc.markBadConn(err)\n}\n\nfunc (mc *mysqlConn) Close() (err error) {\n\t// Makes Close idempotent\n\tif !mc.closed.IsSet() {\n\t\terr = mc.writeCommandPacket(comQuit)\n\t}\n\n\tmc.cleanup()\n\n\treturn\n}\n\n// Closes the network connection and unsets internal variables. Do not call this\n// function after successfully authentication, call Close instead. This function\n// is called before auth or on auth failure because MySQL will have already\n// closed the network connection.\nfunc (mc *mysqlConn) cleanup() {\n\tif !mc.closed.TrySet(true) {\n\t\treturn\n\t}\n\n\t// Makes cleanup idempotent\n\tclose(mc.closech)\n\tif mc.netConn == nil {\n\t\treturn\n\t}\n\tif err := mc.netConn.Close(); err != nil {\n\t\terrLog.Print(err)\n\t}\n}\n\nfunc (mc *mysqlConn) error() error {\n\tif mc.closed.IsSet() {\n\t\tif err := mc.canceled.Value(); err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn ErrInvalidConn\n\t}\n\treturn nil\n}\n\nfunc (mc *mysqlConn) Prepare(query string) (driver.Stmt, error) {\n\tif mc.closed.IsSet() {\n\t\terrLog.Print(ErrInvalidConn)\n\t\treturn nil, driver.ErrBadConn\n\t}\n\t// Send command\n\terr := mc.writeCommandPacketStr(comStmtPrepare, query)\n\tif err != nil {\n\t\treturn nil, mc.markBadConn(err)\n\t}\n\n\tstmt := &mysqlStmt{\n\t\tmc: mc,\n\t}\n\n\t// Read Result\n\tcolumnCount, err := stmt.readPrepareResultPacket()\n\tif err == nil {\n\t\tif stmt.paramCount > 0 {\n\t\t\tif err = mc.readUntilEOF(); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\n\t\tif columnCount > 0 {\n\t\t\terr = mc.readUntilEOF()\n\t\t}\n\t}\n\n\treturn stmt, err\n}\n\nfunc (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (string, error) {\n\t// Number of ? should be same to len(args)\n\tif strings.Count(query, \"?\") != len(args) {\n\t\treturn \"\", driver.ErrSkip\n\t}\n\n\tbuf := mc.buf.takeCompleteBuffer()\n\tif buf == nil {\n\t\t// can not take the buffer. Something must be wrong with the connection\n\t\terrLog.Print(ErrBusyBuffer)\n\t\treturn \"\", ErrInvalidConn\n\t}\n\tbuf = buf[:0]\n\targPos := 0\n\n\tfor i := 0; i < len(query); i++ {\n\t\tq := strings.IndexByte(query[i:], '?')\n\t\tif q == -1 {\n\t\t\tbuf = append(buf, query[i:]...)\n\t\t\tbreak\n\t\t}\n\t\tbuf = append(buf, query[i:i+q]...)\n\t\ti += q\n\n\t\targ := args[argPos]\n\t\targPos++\n\n\t\tif arg == nil {\n\t\t\tbuf = append(buf, \"NULL\"...)\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch v := arg.(type) {\n\t\tcase int64:\n\t\t\tbuf = strconv.AppendInt(buf, v, 10)\n\t\tcase float64:\n\t\t\tbuf = strconv.AppendFloat(buf, v, 'g', -1, 64)\n\t\tcase bool:\n\t\t\tif v {\n\t\t\t\tbuf = append(buf, '1')\n\t\t\t} else {\n\t\t\t\tbuf = append(buf, '0')\n\t\t\t}\n\t\tcase time.Time:\n\t\t\tif v.IsZero() {\n\t\t\t\tbuf = append(buf, \"'0000-00-00'\"...)\n\t\t\t} else {\n\t\t\t\tv := v.In(mc.cfg.Loc)\n\t\t\t\tv = v.Add(time.Nanosecond * 500) // To round under microsecond\n\t\t\t\tyear := v.Year()\n\t\t\t\tyear100 := year / 100\n\t\t\t\tyear1 := year % 100\n\t\t\t\tmonth := v.Month()\n\t\t\t\tday := v.Day()\n\t\t\t\thour := v.Hour()\n\t\t\t\tminute := v.Minute()\n\t\t\t\tsecond := v.Second()\n\t\t\t\tmicro := v.Nanosecond() / 1000\n\n\t\t\t\tbuf = append(buf, []byte{\n\t\t\t\t\t'\\'',\n\t\t\t\t\tdigits10[year100], digits01[year100],\n\t\t\t\t\tdigits10[year1], digits01[year1],\n\t\t\t\t\t'-',\n\t\t\t\t\tdigits10[month], digits01[month],\n\t\t\t\t\t'-',\n\t\t\t\t\tdigits10[day], digits01[day],\n\t\t\t\t\t' ',\n\t\t\t\t\tdigits10[hour], digits01[hour],\n\t\t\t\t\t':',\n\t\t\t\t\tdigits10[minute], digits01[minute],\n\t\t\t\t\t':',\n\t\t\t\t\tdigits10[second], digits01[second],\n\t\t\t\t}...)\n\n\t\t\t\tif micro != 0 {\n\t\t\t\t\tmicro10000 := micro / 10000\n\t\t\t\t\tmicro100 := micro / 100 % 100\n\t\t\t\t\tmicro1 := micro % 100\n\t\t\t\t\tbuf = append(buf, []byte{\n\t\t\t\t\t\t'.',\n\t\t\t\t\t\tdigits10[micro10000], digits01[micro10000],\n\t\t\t\t\t\tdigits10[micro100], digits01[micro100],\n\t\t\t\t\t\tdigits10[micro1], digits01[micro1],\n\t\t\t\t\t}...)\n\t\t\t\t}\n\t\t\t\tbuf = append(buf, '\\'')\n\t\t\t}\n\t\tcase []byte:\n\t\t\tif v == nil {\n\t\t\t\tbuf = append(buf, \"NULL\"...)\n\t\t\t} else {\n\t\t\t\tbuf = append(buf, \"_binary'\"...)\n\t\t\t\tif mc.status&statusNoBackslashEscapes == 0 {\n\t\t\t\t\tbuf = escapeBytesBackslash(buf, v)\n\t\t\t\t} else {\n\t\t\t\t\tbuf = escapeBytesQuotes(buf, v)\n\t\t\t\t}\n\t\t\t\tbuf = append(buf, '\\'')\n\t\t\t}\n\t\tcase string:\n\t\t\tbuf = append(buf, '\\'')\n\t\t\tif mc.status&statusNoBackslashEscapes == 0 {\n\t\t\t\tbuf = escapeStringBackslash(buf, v)\n\t\t\t} else {\n\t\t\t\tbuf = escapeStringQuotes(buf, v)\n\t\t\t}\n\t\t\tbuf = append(buf, '\\'')\n\t\tdefault:\n\t\t\treturn \"\", driver.ErrSkip\n\t\t}\n\n\t\tif len(buf)+4 > mc.maxAllowedPacket {\n\t\t\treturn \"\", driver.ErrSkip\n\t\t}\n\t}\n\tif argPos != len(args) {\n\t\treturn \"\", driver.ErrSkip\n\t}\n\treturn string(buf), nil\n}\n\nfunc (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, error) {\n\tif mc.closed.IsSet() {\n\t\terrLog.Print(ErrInvalidConn)\n\t\treturn nil, driver.ErrBadConn\n\t}\n\tif len(args) != 0 {\n\t\tif !mc.cfg.InterpolateParams {\n\t\t\treturn nil, driver.ErrSkip\n\t\t}\n\t\t// try to interpolate the parameters to save extra roundtrips for preparing and closing a statement\n\t\tprepared, err := mc.interpolateParams(query, args)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tquery = prepared\n\t}\n\tmc.affectedRows = 0\n\tmc.insertId = 0\n\n\terr := mc.exec(query)\n\tif err == nil {\n\t\treturn &mysqlResult{\n\t\t\taffectedRows: int64(mc.affectedRows),\n\t\t\tinsertId:     int64(mc.insertId),\n\t\t}, err\n\t}\n\treturn nil, mc.markBadConn(err)\n}\n\n// Internal function to execute commands\nfunc (mc *mysqlConn) exec(query string) error {\n\t// Send command\n\tif err := mc.writeCommandPacketStr(comQuery, query); err != nil {\n\t\treturn mc.markBadConn(err)\n\t}\n\n\t// Read Result\n\tresLen, err := mc.readResultSetHeaderPacket()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif resLen > 0 {\n\t\t// columns\n\t\tif err := mc.readUntilEOF(); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// rows\n\t\tif err := mc.readUntilEOF(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn mc.discardResults()\n}\n\nfunc (mc *mysqlConn) Query(query string, args []driver.Value) (driver.Rows, error) {\n\treturn mc.query(query, args)\n}\n\nfunc (mc *mysqlConn) query(query string, args []driver.Value) (*textRows, error) {\n\tif mc.closed.IsSet() {\n\t\terrLog.Print(ErrInvalidConn)\n\t\treturn nil, driver.ErrBadConn\n\t}\n\tif len(args) != 0 {\n\t\tif !mc.cfg.InterpolateParams {\n\t\t\treturn nil, driver.ErrSkip\n\t\t}\n\t\t// try client-side prepare to reduce roundtrip\n\t\tprepared, err := mc.interpolateParams(query, args)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tquery = prepared\n\t}\n\t// Send command\n\terr := mc.writeCommandPacketStr(comQuery, query)\n\tif err == nil {\n\t\t// Read Result\n\t\tvar resLen int\n\t\tresLen, err = mc.readResultSetHeaderPacket()\n\t\tif err == nil {\n\t\t\trows := new(textRows)\n\t\t\trows.mc = mc\n\n\t\t\tif resLen == 0 {\n\t\t\t\trows.rs.done = true\n\n\t\t\t\tswitch err := rows.NextResultSet(); err {\n\t\t\t\tcase nil, io.EOF:\n\t\t\t\t\treturn rows, nil\n\t\t\t\tdefault:\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Columns\n\t\t\trows.rs.columns, err = mc.readColumns(resLen)\n\t\t\treturn rows, err\n\t\t}\n\t}\n\treturn nil, mc.markBadConn(err)\n}\n\n// Gets the value of the given MySQL System Variable\n// The returned byte slice is only valid until the next read\nfunc (mc *mysqlConn) getSystemVar(name string) ([]byte, error) {\n\t// Send command\n\tif err := mc.writeCommandPacketStr(comQuery, \"SELECT @@\"+name); err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Read Result\n\tresLen, err := mc.readResultSetHeaderPacket()\n\tif err == nil {\n\t\trows := new(textRows)\n\t\trows.mc = mc\n\t\trows.rs.columns = []mysqlField{{fieldType: fieldTypeVarChar}}\n\n\t\tif resLen > 0 {\n\t\t\t// Columns\n\t\t\tif err := mc.readUntilEOF(); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\n\t\tdest := make([]driver.Value, resLen)\n\t\tif err = rows.readRow(dest); err == nil {\n\t\t\treturn dest[0].([]byte), mc.readUntilEOF()\n\t\t}\n\t}\n\treturn nil, err\n}\n\n// finish is called when the query has canceled.\nfunc (mc *mysqlConn) cancel(err error) {\n\tmc.canceled.Set(err)\n\tmc.cleanup()\n}\n\n// finish is called when the query has succeeded.\nfunc (mc *mysqlConn) finish() {\n\tif !mc.watching || mc.finished == nil {\n\t\treturn\n\t}\n\tselect {\n\tcase mc.finished <- struct{}{}:\n\t\tmc.watching = false\n\tcase <-mc.closech:\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/go-sql-driver/mysql/connection_go18.go",
    "content": "// Go MySQL Driver - A MySQL-Driver for Go's database/sql package\n//\n// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.\n//\n// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this file,\n// You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// +build go1.8\n\npackage mysql\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"database/sql/driver\"\n)\n\n// Ping implements driver.Pinger interface\nfunc (mc *mysqlConn) Ping(ctx context.Context) error {\n\tif mc.closed.IsSet() {\n\t\terrLog.Print(ErrInvalidConn)\n\t\treturn driver.ErrBadConn\n\t}\n\n\tif err := mc.watchCancel(ctx); err != nil {\n\t\treturn err\n\t}\n\tdefer mc.finish()\n\n\tif err := mc.writeCommandPacket(comPing); err != nil {\n\t\treturn err\n\t}\n\tif _, err := mc.readResultOK(); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// BeginTx implements driver.ConnBeginTx interface\nfunc (mc *mysqlConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {\n\tif err := mc.watchCancel(ctx); err != nil {\n\t\treturn nil, err\n\t}\n\tdefer mc.finish()\n\n\tif sql.IsolationLevel(opts.Isolation) != sql.LevelDefault {\n\t\tlevel, err := mapIsolationLevel(opts.Isolation)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\terr = mc.exec(\"SET TRANSACTION ISOLATION LEVEL \" + level)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn mc.begin(opts.ReadOnly)\n}\n\nfunc (mc *mysqlConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {\n\tdargs, err := namedValueToValue(args)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := mc.watchCancel(ctx); err != nil {\n\t\treturn nil, err\n\t}\n\n\trows, err := mc.query(query, dargs)\n\tif err != nil {\n\t\tmc.finish()\n\t\treturn nil, err\n\t}\n\trows.finish = mc.finish\n\treturn rows, err\n}\n\nfunc (mc *mysqlConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {\n\tdargs, err := namedValueToValue(args)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := mc.watchCancel(ctx); err != nil {\n\t\treturn nil, err\n\t}\n\tdefer mc.finish()\n\n\treturn mc.Exec(query, dargs)\n}\n\nfunc (mc *mysqlConn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) {\n\tif err := mc.watchCancel(ctx); err != nil {\n\t\treturn nil, err\n\t}\n\n\tstmt, err := mc.Prepare(query)\n\tmc.finish()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tselect {\n\tdefault:\n\tcase <-ctx.Done():\n\t\tstmt.Close()\n\t\treturn nil, ctx.Err()\n\t}\n\treturn stmt, nil\n}\n\nfunc (stmt *mysqlStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {\n\tdargs, err := namedValueToValue(args)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := stmt.mc.watchCancel(ctx); err != nil {\n\t\treturn nil, err\n\t}\n\n\trows, err := stmt.query(dargs)\n\tif err != nil {\n\t\tstmt.mc.finish()\n\t\treturn nil, err\n\t}\n\trows.finish = stmt.mc.finish\n\treturn rows, err\n}\n\nfunc (stmt *mysqlStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {\n\tdargs, err := namedValueToValue(args)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := stmt.mc.watchCancel(ctx); err != nil {\n\t\treturn nil, err\n\t}\n\tdefer stmt.mc.finish()\n\n\treturn stmt.Exec(dargs)\n}\n\nfunc (mc *mysqlConn) watchCancel(ctx context.Context) error {\n\tif mc.watching {\n\t\t// Reach here if canceled,\n\t\t// so the connection is already invalid\n\t\tmc.cleanup()\n\t\treturn nil\n\t}\n\tif ctx.Done() == nil {\n\t\treturn nil\n\t}\n\n\tmc.watching = true\n\tselect {\n\tdefault:\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\t}\n\tif mc.watcher == nil {\n\t\treturn nil\n\t}\n\n\tmc.watcher <- ctx\n\n\treturn nil\n}\n\nfunc (mc *mysqlConn) startWatcher() {\n\twatcher := make(chan mysqlContext, 1)\n\tmc.watcher = watcher\n\tfinished := make(chan struct{})\n\tmc.finished = finished\n\tgo func() {\n\t\tfor {\n\t\t\tvar ctx mysqlContext\n\t\t\tselect {\n\t\t\tcase ctx = <-watcher:\n\t\t\tcase <-mc.closech:\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\tmc.cancel(ctx.Err())\n\t\t\tcase <-finished:\n\t\t\tcase <-mc.closech:\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}()\n}\n\nfunc (mc *mysqlConn) CheckNamedValue(nv *driver.NamedValue) (err error) {\n\tnv.Value, err = converter{}.ConvertValue(nv.Value)\n\treturn\n}\n"
  },
  {
    "path": "vendor/github.com/go-sql-driver/mysql/const.go",
    "content": "// Go MySQL Driver - A MySQL-Driver for Go's database/sql package\n//\n// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.\n//\n// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this file,\n// You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage mysql\n\nconst (\n\tdefaultMaxAllowedPacket = 4 << 20 // 4 MiB\n\tminProtocolVersion      = 10\n\tmaxPacketSize           = 1<<24 - 1\n\ttimeFormat              = \"2006-01-02 15:04:05.999999\"\n)\n\n// MySQL constants documentation:\n// http://dev.mysql.com/doc/internals/en/client-server-protocol.html\n\nconst (\n\tiOK          byte = 0x00\n\tiLocalInFile byte = 0xfb\n\tiEOF         byte = 0xfe\n\tiERR         byte = 0xff\n)\n\n// https://dev.mysql.com/doc/internals/en/capability-flags.html#packet-Protocol::CapabilityFlags\ntype clientFlag uint32\n\nconst (\n\tclientLongPassword clientFlag = 1 << iota\n\tclientFoundRows\n\tclientLongFlag\n\tclientConnectWithDB\n\tclientNoSchema\n\tclientCompress\n\tclientODBC\n\tclientLocalFiles\n\tclientIgnoreSpace\n\tclientProtocol41\n\tclientInteractive\n\tclientSSL\n\tclientIgnoreSIGPIPE\n\tclientTransactions\n\tclientReserved\n\tclientSecureConn\n\tclientMultiStatements\n\tclientMultiResults\n\tclientPSMultiResults\n\tclientPluginAuth\n\tclientConnectAttrs\n\tclientPluginAuthLenEncClientData\n\tclientCanHandleExpiredPasswords\n\tclientSessionTrack\n\tclientDeprecateEOF\n)\n\nconst (\n\tcomQuit byte = iota + 1\n\tcomInitDB\n\tcomQuery\n\tcomFieldList\n\tcomCreateDB\n\tcomDropDB\n\tcomRefresh\n\tcomShutdown\n\tcomStatistics\n\tcomProcessInfo\n\tcomConnect\n\tcomProcessKill\n\tcomDebug\n\tcomPing\n\tcomTime\n\tcomDelayedInsert\n\tcomChangeUser\n\tcomBinlogDump\n\tcomTableDump\n\tcomConnectOut\n\tcomRegisterSlave\n\tcomStmtPrepare\n\tcomStmtExecute\n\tcomStmtSendLongData\n\tcomStmtClose\n\tcomStmtReset\n\tcomSetOption\n\tcomStmtFetch\n)\n\n// https://dev.mysql.com/doc/internals/en/com-query-response.html#packet-Protocol::ColumnType\ntype fieldType byte\n\nconst (\n\tfieldTypeDecimal fieldType = iota\n\tfieldTypeTiny\n\tfieldTypeShort\n\tfieldTypeLong\n\tfieldTypeFloat\n\tfieldTypeDouble\n\tfieldTypeNULL\n\tfieldTypeTimestamp\n\tfieldTypeLongLong\n\tfieldTypeInt24\n\tfieldTypeDate\n\tfieldTypeTime\n\tfieldTypeDateTime\n\tfieldTypeYear\n\tfieldTypeNewDate\n\tfieldTypeVarChar\n\tfieldTypeBit\n)\nconst (\n\tfieldTypeJSON fieldType = iota + 0xf5\n\tfieldTypeNewDecimal\n\tfieldTypeEnum\n\tfieldTypeSet\n\tfieldTypeTinyBLOB\n\tfieldTypeMediumBLOB\n\tfieldTypeLongBLOB\n\tfieldTypeBLOB\n\tfieldTypeVarString\n\tfieldTypeString\n\tfieldTypeGeometry\n)\n\ntype fieldFlag uint16\n\nconst (\n\tflagNotNULL fieldFlag = 1 << iota\n\tflagPriKey\n\tflagUniqueKey\n\tflagMultipleKey\n\tflagBLOB\n\tflagUnsigned\n\tflagZeroFill\n\tflagBinary\n\tflagEnum\n\tflagAutoIncrement\n\tflagTimestamp\n\tflagSet\n\tflagUnknown1\n\tflagUnknown2\n\tflagUnknown3\n\tflagUnknown4\n)\n\n// http://dev.mysql.com/doc/internals/en/status-flags.html\ntype statusFlag uint16\n\nconst (\n\tstatusInTrans statusFlag = 1 << iota\n\tstatusInAutocommit\n\tstatusReserved // Not in documentation\n\tstatusMoreResultsExists\n\tstatusNoGoodIndexUsed\n\tstatusNoIndexUsed\n\tstatusCursorExists\n\tstatusLastRowSent\n\tstatusDbDropped\n\tstatusNoBackslashEscapes\n\tstatusMetadataChanged\n\tstatusQueryWasSlow\n\tstatusPsOutParams\n\tstatusInTransReadonly\n\tstatusSessionStateChanged\n)\n"
  },
  {
    "path": "vendor/github.com/go-sql-driver/mysql/driver.go",
    "content": "// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.\n//\n// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this file,\n// You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package mysql provides a MySQL driver for Go's database/sql package.\n//\n// The driver should be used via the database/sql package:\n//\n//  import \"database/sql\"\n//  import _ \"github.com/go-sql-driver/mysql\"\n//\n//  db, err := sql.Open(\"mysql\", \"user:password@/dbname\")\n//\n// See https://github.com/go-sql-driver/mysql#usage for details\npackage mysql\n\nimport (\n\t\"database/sql\"\n\t\"database/sql/driver\"\n\t\"net\"\n\t\"sync\"\n)\n\n// watcher interface is used for context support (From Go 1.8)\ntype watcher interface {\n\tstartWatcher()\n}\n\n// MySQLDriver is exported to make the driver directly accessible.\n// In general the driver is used via the database/sql package.\ntype MySQLDriver struct{}\n\n// DialFunc is a function which can be used to establish the network connection.\n// Custom dial functions must be registered with RegisterDial\ntype DialFunc func(addr string) (net.Conn, error)\n\nvar (\n\tdialsLock sync.RWMutex\n\tdials     map[string]DialFunc\n)\n\n// RegisterDial registers a custom dial function. It can then be used by the\n// network address mynet(addr), where mynet is the registered new network.\n// addr is passed as a parameter to the dial function.\nfunc RegisterDial(net string, dial DialFunc) {\n\tdialsLock.Lock()\n\tdefer dialsLock.Unlock()\n\tif dials == nil {\n\t\tdials = make(map[string]DialFunc)\n\t}\n\tdials[net] = dial\n}\n\n// Open new Connection.\n// See https://github.com/go-sql-driver/mysql#dsn-data-source-name for how\n// the DSN string is formated\nfunc (d MySQLDriver) Open(dsn string) (driver.Conn, error) {\n\tvar err error\n\n\t// New mysqlConn\n\tmc := &mysqlConn{\n\t\tmaxAllowedPacket: maxPacketSize,\n\t\tmaxWriteSize:     maxPacketSize - 1,\n\t\tclosech:          make(chan struct{}),\n\t}\n\tmc.cfg, err = ParseDSN(dsn)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tmc.parseTime = mc.cfg.ParseTime\n\n\t// Connect to Server\n\tdialsLock.RLock()\n\tdial, ok := dials[mc.cfg.Net]\n\tdialsLock.RUnlock()\n\tif ok {\n\t\tmc.netConn, err = dial(mc.cfg.Addr)\n\t} else {\n\t\tnd := net.Dialer{Timeout: mc.cfg.Timeout}\n\t\tmc.netConn, err = nd.Dial(mc.cfg.Net, mc.cfg.Addr)\n\t}\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Enable TCP Keepalives on TCP connections\n\tif tc, ok := mc.netConn.(*net.TCPConn); ok {\n\t\tif err := tc.SetKeepAlive(true); err != nil {\n\t\t\t// Don't send COM_QUIT before handshake.\n\t\t\tmc.netConn.Close()\n\t\t\tmc.netConn = nil\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\t// Call startWatcher for context support (From Go 1.8)\n\tif s, ok := interface{}(mc).(watcher); ok {\n\t\ts.startWatcher()\n\t}\n\n\tmc.buf = newBuffer(mc.netConn)\n\n\t// Set I/O timeouts\n\tmc.buf.timeout = mc.cfg.ReadTimeout\n\tmc.writeTimeout = mc.cfg.WriteTimeout\n\n\t// Reading Handshake Initialization Packet\n\tcipher, err := mc.readInitPacket()\n\tif err != nil {\n\t\tmc.cleanup()\n\t\treturn nil, err\n\t}\n\n\t// Send Client Authentication Packet\n\tif err = mc.writeAuthPacket(cipher); err != nil {\n\t\tmc.cleanup()\n\t\treturn nil, err\n\t}\n\n\t// Handle response to auth packet, switch methods if possible\n\tif err = handleAuthResult(mc, cipher); err != nil {\n\t\t// Authentication failed and MySQL has already closed the connection\n\t\t// (https://dev.mysql.com/doc/internals/en/authentication-fails.html).\n\t\t// Do not send COM_QUIT, just cleanup and return the error.\n\t\tmc.cleanup()\n\t\treturn nil, err\n\t}\n\n\tif mc.cfg.MaxAllowedPacket > 0 {\n\t\tmc.maxAllowedPacket = mc.cfg.MaxAllowedPacket\n\t} else {\n\t\t// Get max allowed packet size\n\t\tmaxap, err := mc.getSystemVar(\"max_allowed_packet\")\n\t\tif err != nil {\n\t\t\tmc.Close()\n\t\t\treturn nil, err\n\t\t}\n\t\tmc.maxAllowedPacket = stringToInt(maxap) - 1\n\t}\n\tif mc.maxAllowedPacket < maxPacketSize {\n\t\tmc.maxWriteSize = mc.maxAllowedPacket\n\t}\n\n\t// Handle DSN Params\n\terr = mc.handleParams()\n\tif err != nil {\n\t\tmc.Close()\n\t\treturn nil, err\n\t}\n\n\treturn mc, nil\n}\n\nfunc handleAuthResult(mc *mysqlConn, oldCipher []byte) error {\n\t// Read Result Packet\n\tcipher, err := mc.readResultOK()\n\tif err == nil {\n\t\treturn nil // auth successful\n\t}\n\n\tif mc.cfg == nil {\n\t\treturn err // auth failed and retry not possible\n\t}\n\n\t// Retry auth if configured to do so.\n\tif mc.cfg.AllowOldPasswords && err == ErrOldPassword {\n\t\t// Retry with old authentication method. Note: there are edge cases\n\t\t// where this should work but doesn't; this is currently \"wontfix\":\n\t\t// https://github.com/go-sql-driver/mysql/issues/184\n\n\t\t// If CLIENT_PLUGIN_AUTH capability is not supported, no new cipher is\n\t\t// sent and we have to keep using the cipher sent in the init packet.\n\t\tif cipher == nil {\n\t\t\tcipher = oldCipher\n\t\t}\n\n\t\tif err = mc.writeOldAuthPacket(cipher); err != nil {\n\t\t\treturn err\n\t\t}\n\t\t_, err = mc.readResultOK()\n\t} else if mc.cfg.AllowCleartextPasswords && err == ErrCleartextPassword {\n\t\t// Retry with clear text password for\n\t\t// http://dev.mysql.com/doc/refman/5.7/en/cleartext-authentication-plugin.html\n\t\t// http://dev.mysql.com/doc/refman/5.7/en/pam-authentication-plugin.html\n\t\tif err = mc.writeClearAuthPacket(); err != nil {\n\t\t\treturn err\n\t\t}\n\t\t_, err = mc.readResultOK()\n\t} else if mc.cfg.AllowNativePasswords && err == ErrNativePassword {\n\t\tif err = mc.writeNativeAuthPacket(cipher); err != nil {\n\t\t\treturn err\n\t\t}\n\t\t_, err = mc.readResultOK()\n\t}\n\treturn err\n}\n\nfunc init() {\n\tsql.Register(\"mysql\", &MySQLDriver{})\n}\n"
  },
  {
    "path": "vendor/github.com/go-sql-driver/mysql/dsn.go",
    "content": "// Go MySQL Driver - A MySQL-Driver for Go's database/sql package\n//\n// Copyright 2016 The Go-MySQL-Driver Authors. All rights reserved.\n//\n// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this file,\n// You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage mysql\n\nimport (\n\t\"bytes\"\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/url\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n)\n\nvar (\n\terrInvalidDSNUnescaped       = errors.New(\"invalid DSN: did you forget to escape a param value?\")\n\terrInvalidDSNAddr            = errors.New(\"invalid DSN: network address not terminated (missing closing brace)\")\n\terrInvalidDSNNoSlash         = errors.New(\"invalid DSN: missing the slash separating the database name\")\n\terrInvalidDSNUnsafeCollation = errors.New(\"invalid DSN: interpolateParams can not be used with unsafe collations\")\n)\n\n// Config is a configuration parsed from a DSN string.\n// If a new Config is created instead of being parsed from a DSN string,\n// the NewConfig function should be used, which sets default values.\ntype Config struct {\n\tUser             string            // Username\n\tPasswd           string            // Password (requires User)\n\tNet              string            // Network type\n\tAddr             string            // Network address (requires Net)\n\tDBName           string            // Database name\n\tParams           map[string]string // Connection parameters\n\tCollation        string            // Connection collation\n\tLoc              *time.Location    // Location for time.Time values\n\tMaxAllowedPacket int               // Max packet size allowed\n\tTLSConfig        string            // TLS configuration name\n\ttls              *tls.Config       // TLS configuration\n\tTimeout          time.Duration     // Dial timeout\n\tReadTimeout      time.Duration     // I/O read timeout\n\tWriteTimeout     time.Duration     // I/O write timeout\n\n\tAllowAllFiles           bool // Allow all files to be used with LOAD DATA LOCAL INFILE\n\tAllowCleartextPasswords bool // Allows the cleartext client side plugin\n\tAllowNativePasswords    bool // Allows the native password authentication method\n\tAllowOldPasswords       bool // Allows the old insecure password method\n\tClientFoundRows         bool // Return number of matching rows instead of rows changed\n\tColumnsWithAlias        bool // Prepend table alias to column names\n\tInterpolateParams       bool // Interpolate placeholders into query string\n\tMultiStatements         bool // Allow multiple statements in one query\n\tParseTime               bool // Parse time values to time.Time\n\tRejectReadOnly          bool // Reject read-only connections\n}\n\n// NewConfig creates a new Config and sets default values.\nfunc NewConfig() *Config {\n\treturn &Config{\n\t\tCollation:            defaultCollation,\n\t\tLoc:                  time.UTC,\n\t\tMaxAllowedPacket:     defaultMaxAllowedPacket,\n\t\tAllowNativePasswords: true,\n\t}\n}\n\nfunc (cfg *Config) normalize() error {\n\tif cfg.InterpolateParams && unsafeCollations[cfg.Collation] {\n\t\treturn errInvalidDSNUnsafeCollation\n\t}\n\n\t// Set default network if empty\n\tif cfg.Net == \"\" {\n\t\tcfg.Net = \"tcp\"\n\t}\n\n\t// Set default address if empty\n\tif cfg.Addr == \"\" {\n\t\tswitch cfg.Net {\n\t\tcase \"tcp\":\n\t\t\tcfg.Addr = \"127.0.0.1:3306\"\n\t\tcase \"unix\":\n\t\t\tcfg.Addr = \"/tmp/mysql.sock\"\n\t\tdefault:\n\t\t\treturn errors.New(\"default addr for network '\" + cfg.Net + \"' unknown\")\n\t\t}\n\n\t} else if cfg.Net == \"tcp\" {\n\t\tcfg.Addr = ensureHavePort(cfg.Addr)\n\t}\n\n\tif cfg.tls != nil {\n\t\tif cfg.tls.ServerName == \"\" && !cfg.tls.InsecureSkipVerify {\n\t\t\thost, _, err := net.SplitHostPort(cfg.Addr)\n\t\t\tif err == nil {\n\t\t\t\tcfg.tls.ServerName = host\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// FormatDSN formats the given Config into a DSN string which can be passed to\n// the driver.\nfunc (cfg *Config) FormatDSN() string {\n\tvar buf bytes.Buffer\n\n\t// [username[:password]@]\n\tif len(cfg.User) > 0 {\n\t\tbuf.WriteString(cfg.User)\n\t\tif len(cfg.Passwd) > 0 {\n\t\t\tbuf.WriteByte(':')\n\t\t\tbuf.WriteString(cfg.Passwd)\n\t\t}\n\t\tbuf.WriteByte('@')\n\t}\n\n\t// [protocol[(address)]]\n\tif len(cfg.Net) > 0 {\n\t\tbuf.WriteString(cfg.Net)\n\t\tif len(cfg.Addr) > 0 {\n\t\t\tbuf.WriteByte('(')\n\t\t\tbuf.WriteString(cfg.Addr)\n\t\t\tbuf.WriteByte(')')\n\t\t}\n\t}\n\n\t// /dbname\n\tbuf.WriteByte('/')\n\tbuf.WriteString(cfg.DBName)\n\n\t// [?param1=value1&...&paramN=valueN]\n\thasParam := false\n\n\tif cfg.AllowAllFiles {\n\t\thasParam = true\n\t\tbuf.WriteString(\"?allowAllFiles=true\")\n\t}\n\n\tif cfg.AllowCleartextPasswords {\n\t\tif hasParam {\n\t\t\tbuf.WriteString(\"&allowCleartextPasswords=true\")\n\t\t} else {\n\t\t\thasParam = true\n\t\t\tbuf.WriteString(\"?allowCleartextPasswords=true\")\n\t\t}\n\t}\n\n\tif !cfg.AllowNativePasswords {\n\t\tif hasParam {\n\t\t\tbuf.WriteString(\"&allowNativePasswords=false\")\n\t\t} else {\n\t\t\thasParam = true\n\t\t\tbuf.WriteString(\"?allowNativePasswords=false\")\n\t\t}\n\t}\n\n\tif cfg.AllowOldPasswords {\n\t\tif hasParam {\n\t\t\tbuf.WriteString(\"&allowOldPasswords=true\")\n\t\t} else {\n\t\t\thasParam = true\n\t\t\tbuf.WriteString(\"?allowOldPasswords=true\")\n\t\t}\n\t}\n\n\tif cfg.ClientFoundRows {\n\t\tif hasParam {\n\t\t\tbuf.WriteString(\"&clientFoundRows=true\")\n\t\t} else {\n\t\t\thasParam = true\n\t\t\tbuf.WriteString(\"?clientFoundRows=true\")\n\t\t}\n\t}\n\n\tif col := cfg.Collation; col != defaultCollation && len(col) > 0 {\n\t\tif hasParam {\n\t\t\tbuf.WriteString(\"&collation=\")\n\t\t} else {\n\t\t\thasParam = true\n\t\t\tbuf.WriteString(\"?collation=\")\n\t\t}\n\t\tbuf.WriteString(col)\n\t}\n\n\tif cfg.ColumnsWithAlias {\n\t\tif hasParam {\n\t\t\tbuf.WriteString(\"&columnsWithAlias=true\")\n\t\t} else {\n\t\t\thasParam = true\n\t\t\tbuf.WriteString(\"?columnsWithAlias=true\")\n\t\t}\n\t}\n\n\tif cfg.InterpolateParams {\n\t\tif hasParam {\n\t\t\tbuf.WriteString(\"&interpolateParams=true\")\n\t\t} else {\n\t\t\thasParam = true\n\t\t\tbuf.WriteString(\"?interpolateParams=true\")\n\t\t}\n\t}\n\n\tif cfg.Loc != time.UTC && cfg.Loc != nil {\n\t\tif hasParam {\n\t\t\tbuf.WriteString(\"&loc=\")\n\t\t} else {\n\t\t\thasParam = true\n\t\t\tbuf.WriteString(\"?loc=\")\n\t\t}\n\t\tbuf.WriteString(url.QueryEscape(cfg.Loc.String()))\n\t}\n\n\tif cfg.MultiStatements {\n\t\tif hasParam {\n\t\t\tbuf.WriteString(\"&multiStatements=true\")\n\t\t} else {\n\t\t\thasParam = true\n\t\t\tbuf.WriteString(\"?multiStatements=true\")\n\t\t}\n\t}\n\n\tif cfg.ParseTime {\n\t\tif hasParam {\n\t\t\tbuf.WriteString(\"&parseTime=true\")\n\t\t} else {\n\t\t\thasParam = true\n\t\t\tbuf.WriteString(\"?parseTime=true\")\n\t\t}\n\t}\n\n\tif cfg.ReadTimeout > 0 {\n\t\tif hasParam {\n\t\t\tbuf.WriteString(\"&readTimeout=\")\n\t\t} else {\n\t\t\thasParam = true\n\t\t\tbuf.WriteString(\"?readTimeout=\")\n\t\t}\n\t\tbuf.WriteString(cfg.ReadTimeout.String())\n\t}\n\n\tif cfg.RejectReadOnly {\n\t\tif hasParam {\n\t\t\tbuf.WriteString(\"&rejectReadOnly=true\")\n\t\t} else {\n\t\t\thasParam = true\n\t\t\tbuf.WriteString(\"?rejectReadOnly=true\")\n\t\t}\n\t}\n\n\tif cfg.Timeout > 0 {\n\t\tif hasParam {\n\t\t\tbuf.WriteString(\"&timeout=\")\n\t\t} else {\n\t\t\thasParam = true\n\t\t\tbuf.WriteString(\"?timeout=\")\n\t\t}\n\t\tbuf.WriteString(cfg.Timeout.String())\n\t}\n\n\tif len(cfg.TLSConfig) > 0 {\n\t\tif hasParam {\n\t\t\tbuf.WriteString(\"&tls=\")\n\t\t} else {\n\t\t\thasParam = true\n\t\t\tbuf.WriteString(\"?tls=\")\n\t\t}\n\t\tbuf.WriteString(url.QueryEscape(cfg.TLSConfig))\n\t}\n\n\tif cfg.WriteTimeout > 0 {\n\t\tif hasParam {\n\t\t\tbuf.WriteString(\"&writeTimeout=\")\n\t\t} else {\n\t\t\thasParam = true\n\t\t\tbuf.WriteString(\"?writeTimeout=\")\n\t\t}\n\t\tbuf.WriteString(cfg.WriteTimeout.String())\n\t}\n\n\tif cfg.MaxAllowedPacket != defaultMaxAllowedPacket {\n\t\tif hasParam {\n\t\t\tbuf.WriteString(\"&maxAllowedPacket=\")\n\t\t} else {\n\t\t\thasParam = true\n\t\t\tbuf.WriteString(\"?maxAllowedPacket=\")\n\t\t}\n\t\tbuf.WriteString(strconv.Itoa(cfg.MaxAllowedPacket))\n\n\t}\n\n\t// other params\n\tif cfg.Params != nil {\n\t\tvar params []string\n\t\tfor param := range cfg.Params {\n\t\t\tparams = append(params, param)\n\t\t}\n\t\tsort.Strings(params)\n\t\tfor _, param := range params {\n\t\t\tif hasParam {\n\t\t\t\tbuf.WriteByte('&')\n\t\t\t} else {\n\t\t\t\thasParam = true\n\t\t\t\tbuf.WriteByte('?')\n\t\t\t}\n\n\t\t\tbuf.WriteString(param)\n\t\t\tbuf.WriteByte('=')\n\t\t\tbuf.WriteString(url.QueryEscape(cfg.Params[param]))\n\t\t}\n\t}\n\n\treturn buf.String()\n}\n\n// ParseDSN parses the DSN string to a Config\nfunc ParseDSN(dsn string) (cfg *Config, err error) {\n\t// New config with some default values\n\tcfg = NewConfig()\n\n\t// [user[:password]@][net[(addr)]]/dbname[?param1=value1&paramN=valueN]\n\t// Find the last '/' (since the password or the net addr might contain a '/')\n\tfoundSlash := false\n\tfor i := len(dsn) - 1; i >= 0; i-- {\n\t\tif dsn[i] == '/' {\n\t\t\tfoundSlash = true\n\t\t\tvar j, k int\n\n\t\t\t// left part is empty if i <= 0\n\t\t\tif i > 0 {\n\t\t\t\t// [username[:password]@][protocol[(address)]]\n\t\t\t\t// Find the last '@' in dsn[:i]\n\t\t\t\tfor j = i; j >= 0; j-- {\n\t\t\t\t\tif dsn[j] == '@' {\n\t\t\t\t\t\t// username[:password]\n\t\t\t\t\t\t// Find the first ':' in dsn[:j]\n\t\t\t\t\t\tfor k = 0; k < j; k++ {\n\t\t\t\t\t\t\tif dsn[k] == ':' {\n\t\t\t\t\t\t\t\tcfg.Passwd = dsn[k+1 : j]\n\t\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcfg.User = dsn[:k]\n\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// [protocol[(address)]]\n\t\t\t\t// Find the first '(' in dsn[j+1:i]\n\t\t\t\tfor k = j + 1; k < i; k++ {\n\t\t\t\t\tif dsn[k] == '(' {\n\t\t\t\t\t\t// dsn[i-1] must be == ')' if an address is specified\n\t\t\t\t\t\tif dsn[i-1] != ')' {\n\t\t\t\t\t\t\tif strings.ContainsRune(dsn[k+1:i], ')') {\n\t\t\t\t\t\t\t\treturn nil, errInvalidDSNUnescaped\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn nil, errInvalidDSNAddr\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcfg.Addr = dsn[k+1 : i-1]\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcfg.Net = dsn[j+1 : k]\n\t\t\t}\n\n\t\t\t// dbname[?param1=value1&...&paramN=valueN]\n\t\t\t// Find the first '?' in dsn[i+1:]\n\t\t\tfor j = i + 1; j < len(dsn); j++ {\n\t\t\t\tif dsn[j] == '?' {\n\t\t\t\t\tif err = parseDSNParams(cfg, dsn[j+1:]); err != nil {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tcfg.DBName = dsn[i+1 : j]\n\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif !foundSlash && len(dsn) > 0 {\n\t\treturn nil, errInvalidDSNNoSlash\n\t}\n\n\tif err = cfg.normalize(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn\n}\n\n// parseDSNParams parses the DSN \"query string\"\n// Values must be url.QueryEscape'ed\nfunc parseDSNParams(cfg *Config, params string) (err error) {\n\tfor _, v := range strings.Split(params, \"&\") {\n\t\tparam := strings.SplitN(v, \"=\", 2)\n\t\tif len(param) != 2 {\n\t\t\tcontinue\n\t\t}\n\n\t\t// cfg params\n\t\tswitch value := param[1]; param[0] {\n\t\t// Disable INFILE whitelist / enable all files\n\t\tcase \"allowAllFiles\":\n\t\t\tvar isBool bool\n\t\t\tcfg.AllowAllFiles, isBool = readBool(value)\n\t\t\tif !isBool {\n\t\t\t\treturn errors.New(\"invalid bool value: \" + value)\n\t\t\t}\n\n\t\t// Use cleartext authentication mode (MySQL 5.5.10+)\n\t\tcase \"allowCleartextPasswords\":\n\t\t\tvar isBool bool\n\t\t\tcfg.AllowCleartextPasswords, isBool = readBool(value)\n\t\t\tif !isBool {\n\t\t\t\treturn errors.New(\"invalid bool value: \" + value)\n\t\t\t}\n\n\t\t// Use native password authentication\n\t\tcase \"allowNativePasswords\":\n\t\t\tvar isBool bool\n\t\t\tcfg.AllowNativePasswords, isBool = readBool(value)\n\t\t\tif !isBool {\n\t\t\t\treturn errors.New(\"invalid bool value: \" + value)\n\t\t\t}\n\n\t\t// Use old authentication mode (pre MySQL 4.1)\n\t\tcase \"allowOldPasswords\":\n\t\t\tvar isBool bool\n\t\t\tcfg.AllowOldPasswords, isBool = readBool(value)\n\t\t\tif !isBool {\n\t\t\t\treturn errors.New(\"invalid bool value: \" + value)\n\t\t\t}\n\n\t\t// Switch \"rowsAffected\" mode\n\t\tcase \"clientFoundRows\":\n\t\t\tvar isBool bool\n\t\t\tcfg.ClientFoundRows, isBool = readBool(value)\n\t\t\tif !isBool {\n\t\t\t\treturn errors.New(\"invalid bool value: \" + value)\n\t\t\t}\n\n\t\t// Collation\n\t\tcase \"collation\":\n\t\t\tcfg.Collation = value\n\t\t\tbreak\n\n\t\tcase \"columnsWithAlias\":\n\t\t\tvar isBool bool\n\t\t\tcfg.ColumnsWithAlias, isBool = readBool(value)\n\t\t\tif !isBool {\n\t\t\t\treturn errors.New(\"invalid bool value: \" + value)\n\t\t\t}\n\n\t\t// Compression\n\t\tcase \"compress\":\n\t\t\treturn errors.New(\"compression not implemented yet\")\n\n\t\t// Enable client side placeholder substitution\n\t\tcase \"interpolateParams\":\n\t\t\tvar isBool bool\n\t\t\tcfg.InterpolateParams, isBool = readBool(value)\n\t\t\tif !isBool {\n\t\t\t\treturn errors.New(\"invalid bool value: \" + value)\n\t\t\t}\n\n\t\t// Time Location\n\t\tcase \"loc\":\n\t\t\tif value, err = url.QueryUnescape(value); err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tcfg.Loc, err = time.LoadLocation(value)\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t// multiple statements in one query\n\t\tcase \"multiStatements\":\n\t\t\tvar isBool bool\n\t\t\tcfg.MultiStatements, isBool = readBool(value)\n\t\t\tif !isBool {\n\t\t\t\treturn errors.New(\"invalid bool value: \" + value)\n\t\t\t}\n\n\t\t// time.Time parsing\n\t\tcase \"parseTime\":\n\t\t\tvar isBool bool\n\t\t\tcfg.ParseTime, isBool = readBool(value)\n\t\t\tif !isBool {\n\t\t\t\treturn errors.New(\"invalid bool value: \" + value)\n\t\t\t}\n\n\t\t// I/O read Timeout\n\t\tcase \"readTimeout\":\n\t\t\tcfg.ReadTimeout, err = time.ParseDuration(value)\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t// Reject read-only connections\n\t\tcase \"rejectReadOnly\":\n\t\t\tvar isBool bool\n\t\t\tcfg.RejectReadOnly, isBool = readBool(value)\n\t\t\tif !isBool {\n\t\t\t\treturn errors.New(\"invalid bool value: \" + value)\n\t\t\t}\n\n\t\t// Strict mode\n\t\tcase \"strict\":\n\t\t\tpanic(\"strict mode has been removed. See https://github.com/go-sql-driver/mysql/wiki/strict-mode\")\n\n\t\t// Dial Timeout\n\t\tcase \"timeout\":\n\t\t\tcfg.Timeout, err = time.ParseDuration(value)\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t// TLS-Encryption\n\t\tcase \"tls\":\n\t\t\tboolValue, isBool := readBool(value)\n\t\t\tif isBool {\n\t\t\t\tif boolValue {\n\t\t\t\t\tcfg.TLSConfig = \"true\"\n\t\t\t\t\tcfg.tls = &tls.Config{}\n\t\t\t\t} else {\n\t\t\t\t\tcfg.TLSConfig = \"false\"\n\t\t\t\t}\n\t\t\t} else if vl := strings.ToLower(value); vl == \"skip-verify\" {\n\t\t\t\tcfg.TLSConfig = vl\n\t\t\t\tcfg.tls = &tls.Config{InsecureSkipVerify: true}\n\t\t\t} else {\n\t\t\t\tname, err := url.QueryUnescape(value)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"invalid value for TLS config name: %v\", err)\n\t\t\t\t}\n\n\t\t\t\tif tlsConfig := getTLSConfigClone(name); tlsConfig != nil {\n\t\t\t\t\tcfg.TLSConfig = name\n\t\t\t\t\tcfg.tls = tlsConfig\n\t\t\t\t} else {\n\t\t\t\t\treturn errors.New(\"invalid value / unknown config name: \" + name)\n\t\t\t\t}\n\t\t\t}\n\n\t\t// I/O write Timeout\n\t\tcase \"writeTimeout\":\n\t\t\tcfg.WriteTimeout, err = time.ParseDuration(value)\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\tcase \"maxAllowedPacket\":\n\t\t\tcfg.MaxAllowedPacket, err = strconv.Atoi(value)\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\tdefault:\n\t\t\t// lazy init\n\t\t\tif cfg.Params == nil {\n\t\t\t\tcfg.Params = make(map[string]string)\n\t\t\t}\n\n\t\t\tif cfg.Params[param[0]], err = url.QueryUnescape(value); err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\treturn\n}\n\nfunc ensureHavePort(addr string) string {\n\tif _, _, err := net.SplitHostPort(addr); err != nil {\n\t\treturn net.JoinHostPort(addr, \"3306\")\n\t}\n\treturn addr\n}\n"
  },
  {
    "path": "vendor/github.com/go-sql-driver/mysql/errors.go",
    "content": "// Go MySQL Driver - A MySQL-Driver for Go's database/sql package\n//\n// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.\n//\n// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this file,\n// You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage mysql\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n)\n\n// Various errors the driver might return. Can change between driver versions.\nvar (\n\tErrInvalidConn       = errors.New(\"invalid connection\")\n\tErrMalformPkt        = errors.New(\"malformed packet\")\n\tErrNoTLS             = errors.New(\"TLS requested but server does not support TLS\")\n\tErrCleartextPassword = errors.New(\"this user requires clear text authentication. If you still want to use it, please add 'allowCleartextPasswords=1' to your DSN\")\n\tErrNativePassword    = errors.New(\"this user requires mysql native password authentication.\")\n\tErrOldPassword       = errors.New(\"this user requires old password authentication. If you still want to use it, please add 'allowOldPasswords=1' to your DSN. See also https://github.com/go-sql-driver/mysql/wiki/old_passwords\")\n\tErrUnknownPlugin     = errors.New(\"this authentication plugin is not supported\")\n\tErrOldProtocol       = errors.New(\"MySQL server does not support required protocol 41+\")\n\tErrPktSync           = errors.New(\"commands out of sync. You can't run this command now\")\n\tErrPktSyncMul        = errors.New(\"commands out of sync. Did you run multiple statements at once?\")\n\tErrPktTooLarge       = errors.New(\"packet for query is too large. Try adjusting the 'max_allowed_packet' variable on the server\")\n\tErrBusyBuffer        = errors.New(\"busy buffer\")\n\n\t// errBadConnNoWrite is used for connection errors where nothing was sent to the database yet.\n\t// If this happens first in a function starting a database interaction, it should be replaced by driver.ErrBadConn\n\t// to trigger a resend.\n\t// See https://github.com/go-sql-driver/mysql/pull/302\n\terrBadConnNoWrite = errors.New(\"bad connection\")\n)\n\nvar errLog = Logger(log.New(os.Stderr, \"[mysql] \", log.Ldate|log.Ltime|log.Lshortfile))\n\n// Logger is used to log critical error messages.\ntype Logger interface {\n\tPrint(v ...interface{})\n}\n\n// SetLogger is used to set the logger for critical errors.\n// The initial logger is os.Stderr.\nfunc SetLogger(logger Logger) error {\n\tif logger == nil {\n\t\treturn errors.New(\"logger is nil\")\n\t}\n\terrLog = logger\n\treturn nil\n}\n\n// MySQLError is an error type which represents a single MySQL error\ntype MySQLError struct {\n\tNumber  uint16\n\tMessage string\n}\n\nfunc (me *MySQLError) Error() string {\n\treturn fmt.Sprintf(\"Error %d: %s\", me.Number, me.Message)\n}\n"
  },
  {
    "path": "vendor/github.com/go-sql-driver/mysql/fields.go",
    "content": "// Go MySQL Driver - A MySQL-Driver for Go's database/sql package\n//\n// Copyright 2017 The Go-MySQL-Driver Authors. All rights reserved.\n//\n// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this file,\n// You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage mysql\n\nimport (\n\t\"database/sql\"\n\t\"reflect\"\n)\n\nfunc (mf *mysqlField) typeDatabaseName() string {\n\tswitch mf.fieldType {\n\tcase fieldTypeBit:\n\t\treturn \"BIT\"\n\tcase fieldTypeBLOB:\n\t\tif mf.charSet != collations[binaryCollation] {\n\t\t\treturn \"TEXT\"\n\t\t}\n\t\treturn \"BLOB\"\n\tcase fieldTypeDate:\n\t\treturn \"DATE\"\n\tcase fieldTypeDateTime:\n\t\treturn \"DATETIME\"\n\tcase fieldTypeDecimal:\n\t\treturn \"DECIMAL\"\n\tcase fieldTypeDouble:\n\t\treturn \"DOUBLE\"\n\tcase fieldTypeEnum:\n\t\treturn \"ENUM\"\n\tcase fieldTypeFloat:\n\t\treturn \"FLOAT\"\n\tcase fieldTypeGeometry:\n\t\treturn \"GEOMETRY\"\n\tcase fieldTypeInt24:\n\t\treturn \"MEDIUMINT\"\n\tcase fieldTypeJSON:\n\t\treturn \"JSON\"\n\tcase fieldTypeLong:\n\t\treturn \"INT\"\n\tcase fieldTypeLongBLOB:\n\t\tif mf.charSet != collations[binaryCollation] {\n\t\t\treturn \"LONGTEXT\"\n\t\t}\n\t\treturn \"LONGBLOB\"\n\tcase fieldTypeLongLong:\n\t\treturn \"BIGINT\"\n\tcase fieldTypeMediumBLOB:\n\t\tif mf.charSet != collations[binaryCollation] {\n\t\t\treturn \"MEDIUMTEXT\"\n\t\t}\n\t\treturn \"MEDIUMBLOB\"\n\tcase fieldTypeNewDate:\n\t\treturn \"DATE\"\n\tcase fieldTypeNewDecimal:\n\t\treturn \"DECIMAL\"\n\tcase fieldTypeNULL:\n\t\treturn \"NULL\"\n\tcase fieldTypeSet:\n\t\treturn \"SET\"\n\tcase fieldTypeShort:\n\t\treturn \"SMALLINT\"\n\tcase fieldTypeString:\n\t\tif mf.charSet == collations[binaryCollation] {\n\t\t\treturn \"BINARY\"\n\t\t}\n\t\treturn \"CHAR\"\n\tcase fieldTypeTime:\n\t\treturn \"TIME\"\n\tcase fieldTypeTimestamp:\n\t\treturn \"TIMESTAMP\"\n\tcase fieldTypeTiny:\n\t\treturn \"TINYINT\"\n\tcase fieldTypeTinyBLOB:\n\t\tif mf.charSet != collations[binaryCollation] {\n\t\t\treturn \"TINYTEXT\"\n\t\t}\n\t\treturn \"TINYBLOB\"\n\tcase fieldTypeVarChar:\n\t\tif mf.charSet == collations[binaryCollation] {\n\t\t\treturn \"VARBINARY\"\n\t\t}\n\t\treturn \"VARCHAR\"\n\tcase fieldTypeVarString:\n\t\tif mf.charSet == collations[binaryCollation] {\n\t\t\treturn \"VARBINARY\"\n\t\t}\n\t\treturn \"VARCHAR\"\n\tcase fieldTypeYear:\n\t\treturn \"YEAR\"\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\nvar (\n\tscanTypeFloat32   = reflect.TypeOf(float32(0))\n\tscanTypeFloat64   = reflect.TypeOf(float64(0))\n\tscanTypeInt8      = reflect.TypeOf(int8(0))\n\tscanTypeInt16     = reflect.TypeOf(int16(0))\n\tscanTypeInt32     = reflect.TypeOf(int32(0))\n\tscanTypeInt64     = reflect.TypeOf(int64(0))\n\tscanTypeNullFloat = reflect.TypeOf(sql.NullFloat64{})\n\tscanTypeNullInt   = reflect.TypeOf(sql.NullInt64{})\n\tscanTypeNullTime  = reflect.TypeOf(NullTime{})\n\tscanTypeUint8     = reflect.TypeOf(uint8(0))\n\tscanTypeUint16    = reflect.TypeOf(uint16(0))\n\tscanTypeUint32    = reflect.TypeOf(uint32(0))\n\tscanTypeUint64    = reflect.TypeOf(uint64(0))\n\tscanTypeRawBytes  = reflect.TypeOf(sql.RawBytes{})\n\tscanTypeUnknown   = reflect.TypeOf(new(interface{}))\n)\n\ntype mysqlField struct {\n\ttableName string\n\tname      string\n\tlength    uint32\n\tflags     fieldFlag\n\tfieldType fieldType\n\tdecimals  byte\n\tcharSet   uint8\n}\n\nfunc (mf *mysqlField) scanType() reflect.Type {\n\tswitch mf.fieldType {\n\tcase fieldTypeTiny:\n\t\tif mf.flags&flagNotNULL != 0 {\n\t\t\tif mf.flags&flagUnsigned != 0 {\n\t\t\t\treturn scanTypeUint8\n\t\t\t}\n\t\t\treturn scanTypeInt8\n\t\t}\n\t\treturn scanTypeNullInt\n\n\tcase fieldTypeShort, fieldTypeYear:\n\t\tif mf.flags&flagNotNULL != 0 {\n\t\t\tif mf.flags&flagUnsigned != 0 {\n\t\t\t\treturn scanTypeUint16\n\t\t\t}\n\t\t\treturn scanTypeInt16\n\t\t}\n\t\treturn scanTypeNullInt\n\n\tcase fieldTypeInt24, fieldTypeLong:\n\t\tif mf.flags&flagNotNULL != 0 {\n\t\t\tif mf.flags&flagUnsigned != 0 {\n\t\t\t\treturn scanTypeUint32\n\t\t\t}\n\t\t\treturn scanTypeInt32\n\t\t}\n\t\treturn scanTypeNullInt\n\n\tcase fieldTypeLongLong:\n\t\tif mf.flags&flagNotNULL != 0 {\n\t\t\tif mf.flags&flagUnsigned != 0 {\n\t\t\t\treturn scanTypeUint64\n\t\t\t}\n\t\t\treturn scanTypeInt64\n\t\t}\n\t\treturn scanTypeNullInt\n\n\tcase fieldTypeFloat:\n\t\tif mf.flags&flagNotNULL != 0 {\n\t\t\treturn scanTypeFloat32\n\t\t}\n\t\treturn scanTypeNullFloat\n\n\tcase fieldTypeDouble:\n\t\tif mf.flags&flagNotNULL != 0 {\n\t\t\treturn scanTypeFloat64\n\t\t}\n\t\treturn scanTypeNullFloat\n\n\tcase fieldTypeDecimal, fieldTypeNewDecimal, fieldTypeVarChar,\n\t\tfieldTypeBit, fieldTypeEnum, fieldTypeSet, fieldTypeTinyBLOB,\n\t\tfieldTypeMediumBLOB, fieldTypeLongBLOB, fieldTypeBLOB,\n\t\tfieldTypeVarString, fieldTypeString, fieldTypeGeometry, fieldTypeJSON,\n\t\tfieldTypeTime:\n\t\treturn scanTypeRawBytes\n\n\tcase fieldTypeDate, fieldTypeNewDate,\n\t\tfieldTypeTimestamp, fieldTypeDateTime:\n\t\t// NullTime is always returned for more consistent behavior as it can\n\t\t// handle both cases of parseTime regardless if the field is nullable.\n\t\treturn scanTypeNullTime\n\n\tdefault:\n\t\treturn scanTypeUnknown\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/go-sql-driver/mysql/infile.go",
    "content": "// Go MySQL Driver - A MySQL-Driver for Go's database/sql package\n//\n// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.\n//\n// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this file,\n// You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage mysql\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"strings\"\n\t\"sync\"\n)\n\nvar (\n\tfileRegister       map[string]bool\n\tfileRegisterLock   sync.RWMutex\n\treaderRegister     map[string]func() io.Reader\n\treaderRegisterLock sync.RWMutex\n)\n\n// RegisterLocalFile adds the given file to the file whitelist,\n// so that it can be used by \"LOAD DATA LOCAL INFILE <filepath>\".\n// Alternatively you can allow the use of all local files with\n// the DSN parameter 'allowAllFiles=true'\n//\n//  filePath := \"/home/gopher/data.csv\"\n//  mysql.RegisterLocalFile(filePath)\n//  err := db.Exec(\"LOAD DATA LOCAL INFILE '\" + filePath + \"' INTO TABLE foo\")\n//  if err != nil {\n//  ...\n//\nfunc RegisterLocalFile(filePath string) {\n\tfileRegisterLock.Lock()\n\t// lazy map init\n\tif fileRegister == nil {\n\t\tfileRegister = make(map[string]bool)\n\t}\n\n\tfileRegister[strings.Trim(filePath, `\"`)] = true\n\tfileRegisterLock.Unlock()\n}\n\n// DeregisterLocalFile removes the given filepath from the whitelist.\nfunc DeregisterLocalFile(filePath string) {\n\tfileRegisterLock.Lock()\n\tdelete(fileRegister, strings.Trim(filePath, `\"`))\n\tfileRegisterLock.Unlock()\n}\n\n// RegisterReaderHandler registers a handler function which is used\n// to receive a io.Reader.\n// The Reader can be used by \"LOAD DATA LOCAL INFILE Reader::<name>\".\n// If the handler returns a io.ReadCloser Close() is called when the\n// request is finished.\n//\n//  mysql.RegisterReaderHandler(\"data\", func() io.Reader {\n//  \tvar csvReader io.Reader // Some Reader that returns CSV data\n//  \t... // Open Reader here\n//  \treturn csvReader\n//  })\n//  err := db.Exec(\"LOAD DATA LOCAL INFILE 'Reader::data' INTO TABLE foo\")\n//  if err != nil {\n//  ...\n//\nfunc RegisterReaderHandler(name string, handler func() io.Reader) {\n\treaderRegisterLock.Lock()\n\t// lazy map init\n\tif readerRegister == nil {\n\t\treaderRegister = make(map[string]func() io.Reader)\n\t}\n\n\treaderRegister[name] = handler\n\treaderRegisterLock.Unlock()\n}\n\n// DeregisterReaderHandler removes the ReaderHandler function with\n// the given name from the registry.\nfunc DeregisterReaderHandler(name string) {\n\treaderRegisterLock.Lock()\n\tdelete(readerRegister, name)\n\treaderRegisterLock.Unlock()\n}\n\nfunc deferredClose(err *error, closer io.Closer) {\n\tcloseErr := closer.Close()\n\tif *err == nil {\n\t\t*err = closeErr\n\t}\n}\n\nfunc (mc *mysqlConn) handleInFileRequest(name string) (err error) {\n\tvar rdr io.Reader\n\tvar data []byte\n\tpacketSize := 16 * 1024 // 16KB is small enough for disk readahead and large enough for TCP\n\tif mc.maxWriteSize < packetSize {\n\t\tpacketSize = mc.maxWriteSize\n\t}\n\n\tif idx := strings.Index(name, \"Reader::\"); idx == 0 || (idx > 0 && name[idx-1] == '/') { // io.Reader\n\t\t// The server might return an an absolute path. See issue #355.\n\t\tname = name[idx+8:]\n\n\t\treaderRegisterLock.RLock()\n\t\thandler, inMap := readerRegister[name]\n\t\treaderRegisterLock.RUnlock()\n\n\t\tif inMap {\n\t\t\trdr = handler()\n\t\t\tif rdr != nil {\n\t\t\t\tif cl, ok := rdr.(io.Closer); ok {\n\t\t\t\t\tdefer deferredClose(&err, cl)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\terr = fmt.Errorf(\"Reader '%s' is <nil>\", name)\n\t\t\t}\n\t\t} else {\n\t\t\terr = fmt.Errorf(\"Reader '%s' is not registered\", name)\n\t\t}\n\t} else { // File\n\t\tname = strings.Trim(name, `\"`)\n\t\tfileRegisterLock.RLock()\n\t\tfr := fileRegister[name]\n\t\tfileRegisterLock.RUnlock()\n\t\tif mc.cfg.AllowAllFiles || fr {\n\t\t\tvar file *os.File\n\t\t\tvar fi os.FileInfo\n\n\t\t\tif file, err = os.Open(name); err == nil {\n\t\t\t\tdefer deferredClose(&err, file)\n\n\t\t\t\t// get file size\n\t\t\t\tif fi, err = file.Stat(); err == nil {\n\t\t\t\t\trdr = file\n\t\t\t\t\tif fileSize := int(fi.Size()); fileSize < packetSize {\n\t\t\t\t\t\tpacketSize = fileSize\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\terr = fmt.Errorf(\"local file '%s' is not registered\", name)\n\t\t}\n\t}\n\n\t// send content packets\n\t// if packetSize == 0, the Reader contains no data\n\tif err == nil && packetSize > 0 {\n\t\tdata := make([]byte, 4+packetSize)\n\t\tvar n int\n\t\tfor err == nil {\n\t\t\tn, err = rdr.Read(data[4:])\n\t\t\tif n > 0 {\n\t\t\t\tif ioErr := mc.writePacket(data[:4+n]); ioErr != nil {\n\t\t\t\t\treturn ioErr\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif err == io.EOF {\n\t\t\terr = nil\n\t\t}\n\t}\n\n\t// send empty packet (termination)\n\tif data == nil {\n\t\tdata = make([]byte, 4)\n\t}\n\tif ioErr := mc.writePacket(data[:4]); ioErr != nil {\n\t\treturn ioErr\n\t}\n\n\t// read OK packet\n\tif err == nil {\n\t\t_, err = mc.readResultOK()\n\t\treturn err\n\t}\n\n\tmc.readPacket()\n\treturn err\n}\n"
  },
  {
    "path": "vendor/github.com/go-sql-driver/mysql/packets.go",
    "content": "// Go MySQL Driver - A MySQL-Driver for Go's database/sql package\n//\n// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.\n//\n// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this file,\n// You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage mysql\n\nimport (\n\t\"bytes\"\n\t\"crypto/tls\"\n\t\"database/sql/driver\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"math\"\n\t\"time\"\n)\n\n// Packets documentation:\n// http://dev.mysql.com/doc/internals/en/client-server-protocol.html\n\n// Read packet to buffer 'data'\nfunc (mc *mysqlConn) readPacket() ([]byte, error) {\n\tvar prevData []byte\n\tfor {\n\t\t// read packet header\n\t\tdata, err := mc.buf.readNext(4)\n\t\tif err != nil {\n\t\t\tif cerr := mc.canceled.Value(); cerr != nil {\n\t\t\t\treturn nil, cerr\n\t\t\t}\n\t\t\terrLog.Print(err)\n\t\t\tmc.Close()\n\t\t\treturn nil, ErrInvalidConn\n\t\t}\n\n\t\t// packet length [24 bit]\n\t\tpktLen := int(uint32(data[0]) | uint32(data[1])<<8 | uint32(data[2])<<16)\n\n\t\t// check packet sync [8 bit]\n\t\tif data[3] != mc.sequence {\n\t\t\tif data[3] > mc.sequence {\n\t\t\t\treturn nil, ErrPktSyncMul\n\t\t\t}\n\t\t\treturn nil, ErrPktSync\n\t\t}\n\t\tmc.sequence++\n\n\t\t// packets with length 0 terminate a previous packet which is a\n\t\t// multiple of (2^24)−1 bytes long\n\t\tif pktLen == 0 {\n\t\t\t// there was no previous packet\n\t\t\tif prevData == nil {\n\t\t\t\terrLog.Print(ErrMalformPkt)\n\t\t\t\tmc.Close()\n\t\t\t\treturn nil, ErrInvalidConn\n\t\t\t}\n\n\t\t\treturn prevData, nil\n\t\t}\n\n\t\t// read packet body [pktLen bytes]\n\t\tdata, err = mc.buf.readNext(pktLen)\n\t\tif err != nil {\n\t\t\tif cerr := mc.canceled.Value(); cerr != nil {\n\t\t\t\treturn nil, cerr\n\t\t\t}\n\t\t\terrLog.Print(err)\n\t\t\tmc.Close()\n\t\t\treturn nil, ErrInvalidConn\n\t\t}\n\n\t\t// return data if this was the last packet\n\t\tif pktLen < maxPacketSize {\n\t\t\t// zero allocations for non-split packets\n\t\t\tif prevData == nil {\n\t\t\t\treturn data, nil\n\t\t\t}\n\n\t\t\treturn append(prevData, data...), nil\n\t\t}\n\n\t\tprevData = append(prevData, data...)\n\t}\n}\n\n// Write packet buffer 'data'\nfunc (mc *mysqlConn) writePacket(data []byte) error {\n\tpktLen := len(data) - 4\n\n\tif pktLen > mc.maxAllowedPacket {\n\t\treturn ErrPktTooLarge\n\t}\n\n\tfor {\n\t\tvar size int\n\t\tif pktLen >= maxPacketSize {\n\t\t\tdata[0] = 0xff\n\t\t\tdata[1] = 0xff\n\t\t\tdata[2] = 0xff\n\t\t\tsize = maxPacketSize\n\t\t} else {\n\t\t\tdata[0] = byte(pktLen)\n\t\t\tdata[1] = byte(pktLen >> 8)\n\t\t\tdata[2] = byte(pktLen >> 16)\n\t\t\tsize = pktLen\n\t\t}\n\t\tdata[3] = mc.sequence\n\n\t\t// Write packet\n\t\tif mc.writeTimeout > 0 {\n\t\t\tif err := mc.netConn.SetWriteDeadline(time.Now().Add(mc.writeTimeout)); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tn, err := mc.netConn.Write(data[:4+size])\n\t\tif err == nil && n == 4+size {\n\t\t\tmc.sequence++\n\t\t\tif size != maxPacketSize {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tpktLen -= size\n\t\t\tdata = data[size:]\n\t\t\tcontinue\n\t\t}\n\n\t\t// Handle error\n\t\tif err == nil { // n != len(data)\n\t\t\tmc.cleanup()\n\t\t\terrLog.Print(ErrMalformPkt)\n\t\t} else {\n\t\t\tif cerr := mc.canceled.Value(); cerr != nil {\n\t\t\t\treturn cerr\n\t\t\t}\n\t\t\tif n == 0 && pktLen == len(data)-4 {\n\t\t\t\t// only for the first loop iteration when nothing was written yet\n\t\t\t\treturn errBadConnNoWrite\n\t\t\t}\n\t\t\tmc.cleanup()\n\t\t\terrLog.Print(err)\n\t\t}\n\t\treturn ErrInvalidConn\n\t}\n}\n\n/******************************************************************************\n*                           Initialisation Process                            *\n******************************************************************************/\n\n// Handshake Initialization Packet\n// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::Handshake\nfunc (mc *mysqlConn) readInitPacket() ([]byte, error) {\n\tdata, err := mc.readPacket()\n\tif err != nil {\n\t\t// for init we can rewrite this to ErrBadConn for sql.Driver to retry, since\n\t\t// in connection initialization we don't risk retrying non-idempotent actions.\n\t\tif err == ErrInvalidConn {\n\t\t\treturn nil, driver.ErrBadConn\n\t\t}\n\t\treturn nil, err\n\t}\n\n\tif data[0] == iERR {\n\t\treturn nil, mc.handleErrorPacket(data)\n\t}\n\n\t// protocol version [1 byte]\n\tif data[0] < minProtocolVersion {\n\t\treturn nil, fmt.Errorf(\n\t\t\t\"unsupported protocol version %d. Version %d or higher is required\",\n\t\t\tdata[0],\n\t\t\tminProtocolVersion,\n\t\t)\n\t}\n\n\t// server version [null terminated string]\n\t// connection id [4 bytes]\n\tpos := 1 + bytes.IndexByte(data[1:], 0x00) + 1 + 4\n\n\t// first part of the password cipher [8 bytes]\n\tcipher := data[pos : pos+8]\n\n\t// (filler) always 0x00 [1 byte]\n\tpos += 8 + 1\n\n\t// capability flags (lower 2 bytes) [2 bytes]\n\tmc.flags = clientFlag(binary.LittleEndian.Uint16(data[pos : pos+2]))\n\tif mc.flags&clientProtocol41 == 0 {\n\t\treturn nil, ErrOldProtocol\n\t}\n\tif mc.flags&clientSSL == 0 && mc.cfg.tls != nil {\n\t\treturn nil, ErrNoTLS\n\t}\n\tpos += 2\n\n\tif len(data) > pos {\n\t\t// character set [1 byte]\n\t\t// status flags [2 bytes]\n\t\t// capability flags (upper 2 bytes) [2 bytes]\n\t\t// length of auth-plugin-data [1 byte]\n\t\t// reserved (all [00]) [10 bytes]\n\t\tpos += 1 + 2 + 2 + 1 + 10\n\n\t\t// second part of the password cipher [mininum 13 bytes],\n\t\t// where len=MAX(13, length of auth-plugin-data - 8)\n\t\t//\n\t\t// The web documentation is ambiguous about the length. However,\n\t\t// according to mysql-5.7/sql/auth/sql_authentication.cc line 538,\n\t\t// the 13th byte is \"\\0 byte, terminating the second part of\n\t\t// a scramble\". So the second part of the password cipher is\n\t\t// a NULL terminated string that's at least 13 bytes with the\n\t\t// last byte being NULL.\n\t\t//\n\t\t// The official Python library uses the fixed length 12\n\t\t// which seems to work but technically could have a hidden bug.\n\t\tcipher = append(cipher, data[pos:pos+12]...)\n\n\t\t// TODO: Verify string termination\n\t\t// EOF if version (>= 5.5.7 and < 5.5.10) or (>= 5.6.0 and < 5.6.2)\n\t\t// \\NUL otherwise\n\t\t//\n\t\t//if data[len(data)-1] == 0 {\n\t\t//\treturn\n\t\t//}\n\t\t//return ErrMalformPkt\n\n\t\t// make a memory safe copy of the cipher slice\n\t\tvar b [20]byte\n\t\tcopy(b[:], cipher)\n\t\treturn b[:], nil\n\t}\n\n\t// make a memory safe copy of the cipher slice\n\tvar b [8]byte\n\tcopy(b[:], cipher)\n\treturn b[:], nil\n}\n\n// Client Authentication Packet\n// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::HandshakeResponse\nfunc (mc *mysqlConn) writeAuthPacket(cipher []byte) error {\n\t// Adjust client flags based on server support\n\tclientFlags := clientProtocol41 |\n\t\tclientSecureConn |\n\t\tclientLongPassword |\n\t\tclientTransactions |\n\t\tclientLocalFiles |\n\t\tclientPluginAuth |\n\t\tclientMultiResults |\n\t\tmc.flags&clientLongFlag\n\n\tif mc.cfg.ClientFoundRows {\n\t\tclientFlags |= clientFoundRows\n\t}\n\n\t// To enable TLS / SSL\n\tif mc.cfg.tls != nil {\n\t\tclientFlags |= clientSSL\n\t}\n\n\tif mc.cfg.MultiStatements {\n\t\tclientFlags |= clientMultiStatements\n\t}\n\n\t// User Password\n\tscrambleBuff := scramblePassword(cipher, []byte(mc.cfg.Passwd))\n\n\tpktLen := 4 + 4 + 1 + 23 + len(mc.cfg.User) + 1 + 1 + len(scrambleBuff) + 21 + 1\n\n\t// To specify a db name\n\tif n := len(mc.cfg.DBName); n > 0 {\n\t\tclientFlags |= clientConnectWithDB\n\t\tpktLen += n + 1\n\t}\n\n\t// Calculate packet length and get buffer with that size\n\tdata := mc.buf.takeSmallBuffer(pktLen + 4)\n\tif data == nil {\n\t\t// can not take the buffer. Something must be wrong with the connection\n\t\terrLog.Print(ErrBusyBuffer)\n\t\treturn errBadConnNoWrite\n\t}\n\n\t// ClientFlags [32 bit]\n\tdata[4] = byte(clientFlags)\n\tdata[5] = byte(clientFlags >> 8)\n\tdata[6] = byte(clientFlags >> 16)\n\tdata[7] = byte(clientFlags >> 24)\n\n\t// MaxPacketSize [32 bit] (none)\n\tdata[8] = 0x00\n\tdata[9] = 0x00\n\tdata[10] = 0x00\n\tdata[11] = 0x00\n\n\t// Charset [1 byte]\n\tvar found bool\n\tdata[12], found = collations[mc.cfg.Collation]\n\tif !found {\n\t\t// Note possibility for false negatives:\n\t\t// could be triggered  although the collation is valid if the\n\t\t// collations map does not contain entries the server supports.\n\t\treturn errors.New(\"unknown collation\")\n\t}\n\n\t// SSL Connection Request Packet\n\t// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::SSLRequest\n\tif mc.cfg.tls != nil {\n\t\t// Send TLS / SSL request packet\n\t\tif err := mc.writePacket(data[:(4+4+1+23)+4]); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// Switch to TLS\n\t\ttlsConn := tls.Client(mc.netConn, mc.cfg.tls)\n\t\tif err := tlsConn.Handshake(); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tmc.netConn = tlsConn\n\t\tmc.buf.nc = tlsConn\n\t}\n\n\t// Filler [23 bytes] (all 0x00)\n\tpos := 13\n\tfor ; pos < 13+23; pos++ {\n\t\tdata[pos] = 0\n\t}\n\n\t// User [null terminated string]\n\tif len(mc.cfg.User) > 0 {\n\t\tpos += copy(data[pos:], mc.cfg.User)\n\t}\n\tdata[pos] = 0x00\n\tpos++\n\n\t// ScrambleBuffer [length encoded integer]\n\tdata[pos] = byte(len(scrambleBuff))\n\tpos += 1 + copy(data[pos+1:], scrambleBuff)\n\n\t// Databasename [null terminated string]\n\tif len(mc.cfg.DBName) > 0 {\n\t\tpos += copy(data[pos:], mc.cfg.DBName)\n\t\tdata[pos] = 0x00\n\t\tpos++\n\t}\n\n\t// Assume native client during response\n\tpos += copy(data[pos:], \"mysql_native_password\")\n\tdata[pos] = 0x00\n\n\t// Send Auth packet\n\treturn mc.writePacket(data)\n}\n\n//  Client old authentication packet\n// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchResponse\nfunc (mc *mysqlConn) writeOldAuthPacket(cipher []byte) error {\n\t// User password\n\t// https://dev.mysql.com/doc/internals/en/old-password-authentication.html\n\t// Old password authentication only need and will need 8-byte challenge.\n\tscrambleBuff := scrambleOldPassword(cipher[:8], []byte(mc.cfg.Passwd))\n\n\t// Calculate the packet length and add a tailing 0\n\tpktLen := len(scrambleBuff) + 1\n\tdata := mc.buf.takeSmallBuffer(4 + pktLen)\n\tif data == nil {\n\t\t// can not take the buffer. Something must be wrong with the connection\n\t\terrLog.Print(ErrBusyBuffer)\n\t\treturn errBadConnNoWrite\n\t}\n\n\t// Add the scrambled password [null terminated string]\n\tcopy(data[4:], scrambleBuff)\n\tdata[4+pktLen-1] = 0x00\n\n\treturn mc.writePacket(data)\n}\n\n//  Client clear text authentication packet\n// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchResponse\nfunc (mc *mysqlConn) writeClearAuthPacket() error {\n\t// Calculate the packet length and add a tailing 0\n\tpktLen := len(mc.cfg.Passwd) + 1\n\tdata := mc.buf.takeSmallBuffer(4 + pktLen)\n\tif data == nil {\n\t\t// can not take the buffer. Something must be wrong with the connection\n\t\terrLog.Print(ErrBusyBuffer)\n\t\treturn errBadConnNoWrite\n\t}\n\n\t// Add the clear password [null terminated string]\n\tcopy(data[4:], mc.cfg.Passwd)\n\tdata[4+pktLen-1] = 0x00\n\n\treturn mc.writePacket(data)\n}\n\n//  Native password authentication method\n// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchResponse\nfunc (mc *mysqlConn) writeNativeAuthPacket(cipher []byte) error {\n\t// https://dev.mysql.com/doc/internals/en/secure-password-authentication.html\n\t// Native password authentication only need and will need 20-byte challenge.\n\tscrambleBuff := scramblePassword(cipher[0:20], []byte(mc.cfg.Passwd))\n\n\t// Calculate the packet length and add a tailing 0\n\tpktLen := len(scrambleBuff)\n\tdata := mc.buf.takeSmallBuffer(4 + pktLen)\n\tif data == nil {\n\t\t// can not take the buffer. Something must be wrong with the connection\n\t\terrLog.Print(ErrBusyBuffer)\n\t\treturn errBadConnNoWrite\n\t}\n\n\t// Add the scramble\n\tcopy(data[4:], scrambleBuff)\n\n\treturn mc.writePacket(data)\n}\n\n/******************************************************************************\n*                             Command Packets                                 *\n******************************************************************************/\n\nfunc (mc *mysqlConn) writeCommandPacket(command byte) error {\n\t// Reset Packet Sequence\n\tmc.sequence = 0\n\n\tdata := mc.buf.takeSmallBuffer(4 + 1)\n\tif data == nil {\n\t\t// can not take the buffer. Something must be wrong with the connection\n\t\terrLog.Print(ErrBusyBuffer)\n\t\treturn errBadConnNoWrite\n\t}\n\n\t// Add command byte\n\tdata[4] = command\n\n\t// Send CMD packet\n\treturn mc.writePacket(data)\n}\n\nfunc (mc *mysqlConn) writeCommandPacketStr(command byte, arg string) error {\n\t// Reset Packet Sequence\n\tmc.sequence = 0\n\n\tpktLen := 1 + len(arg)\n\tdata := mc.buf.takeBuffer(pktLen + 4)\n\tif data == nil {\n\t\t// can not take the buffer. Something must be wrong with the connection\n\t\terrLog.Print(ErrBusyBuffer)\n\t\treturn errBadConnNoWrite\n\t}\n\n\t// Add command byte\n\tdata[4] = command\n\n\t// Add arg\n\tcopy(data[5:], arg)\n\n\t// Send CMD packet\n\treturn mc.writePacket(data)\n}\n\nfunc (mc *mysqlConn) writeCommandPacketUint32(command byte, arg uint32) error {\n\t// Reset Packet Sequence\n\tmc.sequence = 0\n\n\tdata := mc.buf.takeSmallBuffer(4 + 1 + 4)\n\tif data == nil {\n\t\t// can not take the buffer. Something must be wrong with the connection\n\t\terrLog.Print(ErrBusyBuffer)\n\t\treturn errBadConnNoWrite\n\t}\n\n\t// Add command byte\n\tdata[4] = command\n\n\t// Add arg [32 bit]\n\tdata[5] = byte(arg)\n\tdata[6] = byte(arg >> 8)\n\tdata[7] = byte(arg >> 16)\n\tdata[8] = byte(arg >> 24)\n\n\t// Send CMD packet\n\treturn mc.writePacket(data)\n}\n\n/******************************************************************************\n*                              Result Packets                                 *\n******************************************************************************/\n\n// Returns error if Packet is not an 'Result OK'-Packet\nfunc (mc *mysqlConn) readResultOK() ([]byte, error) {\n\tdata, err := mc.readPacket()\n\tif err == nil {\n\t\t// packet indicator\n\t\tswitch data[0] {\n\n\t\tcase iOK:\n\t\t\treturn nil, mc.handleOkPacket(data)\n\n\t\tcase iEOF:\n\t\t\tif len(data) > 1 {\n\t\t\t\tpluginEndIndex := bytes.IndexByte(data, 0x00)\n\t\t\t\tplugin := string(data[1:pluginEndIndex])\n\t\t\t\tcipher := data[pluginEndIndex+1:]\n\n\t\t\t\tswitch plugin {\n\t\t\t\tcase \"mysql_old_password\":\n\t\t\t\t\t// using old_passwords\n\t\t\t\t\treturn cipher, ErrOldPassword\n\t\t\t\tcase \"mysql_clear_password\":\n\t\t\t\t\t// using clear text password\n\t\t\t\t\treturn cipher, ErrCleartextPassword\n\t\t\t\tcase \"mysql_native_password\":\n\t\t\t\t\t// using mysql default authentication method\n\t\t\t\t\treturn cipher, ErrNativePassword\n\t\t\t\tdefault:\n\t\t\t\t\treturn cipher, ErrUnknownPlugin\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::OldAuthSwitchRequest\n\t\t\treturn nil, ErrOldPassword\n\n\t\tdefault: // Error otherwise\n\t\t\treturn nil, mc.handleErrorPacket(data)\n\t\t}\n\t}\n\treturn nil, err\n}\n\n// Result Set Header Packet\n// http://dev.mysql.com/doc/internals/en/com-query-response.html#packet-ProtocolText::Resultset\nfunc (mc *mysqlConn) readResultSetHeaderPacket() (int, error) {\n\tdata, err := mc.readPacket()\n\tif err == nil {\n\t\tswitch data[0] {\n\n\t\tcase iOK:\n\t\t\treturn 0, mc.handleOkPacket(data)\n\n\t\tcase iERR:\n\t\t\treturn 0, mc.handleErrorPacket(data)\n\n\t\tcase iLocalInFile:\n\t\t\treturn 0, mc.handleInFileRequest(string(data[1:]))\n\t\t}\n\n\t\t// column count\n\t\tnum, _, n := readLengthEncodedInteger(data)\n\t\tif n-len(data) == 0 {\n\t\t\treturn int(num), nil\n\t\t}\n\n\t\treturn 0, ErrMalformPkt\n\t}\n\treturn 0, err\n}\n\n// Error Packet\n// http://dev.mysql.com/doc/internals/en/generic-response-packets.html#packet-ERR_Packet\nfunc (mc *mysqlConn) handleErrorPacket(data []byte) error {\n\tif data[0] != iERR {\n\t\treturn ErrMalformPkt\n\t}\n\n\t// 0xff [1 byte]\n\n\t// Error Number [16 bit uint]\n\terrno := binary.LittleEndian.Uint16(data[1:3])\n\n\t// 1792: ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION\n\t// 1290: ER_OPTION_PREVENTS_STATEMENT (returned by Aurora during failover)\n\tif (errno == 1792 || errno == 1290) && mc.cfg.RejectReadOnly {\n\t\t// Oops; we are connected to a read-only connection, and won't be able\n\t\t// to issue any write statements. Since RejectReadOnly is configured,\n\t\t// we throw away this connection hoping this one would have write\n\t\t// permission. This is specifically for a possible race condition\n\t\t// during failover (e.g. on AWS Aurora). See README.md for more.\n\t\t//\n\t\t// We explicitly close the connection before returning\n\t\t// driver.ErrBadConn to ensure that `database/sql` purges this\n\t\t// connection and initiates a new one for next statement next time.\n\t\tmc.Close()\n\t\treturn driver.ErrBadConn\n\t}\n\n\tpos := 3\n\n\t// SQL State [optional: # + 5bytes string]\n\tif data[3] == 0x23 {\n\t\t//sqlstate := string(data[4 : 4+5])\n\t\tpos = 9\n\t}\n\n\t// Error Message [string]\n\treturn &MySQLError{\n\t\tNumber:  errno,\n\t\tMessage: string(data[pos:]),\n\t}\n}\n\nfunc readStatus(b []byte) statusFlag {\n\treturn statusFlag(b[0]) | statusFlag(b[1])<<8\n}\n\n// Ok Packet\n// http://dev.mysql.com/doc/internals/en/generic-response-packets.html#packet-OK_Packet\nfunc (mc *mysqlConn) handleOkPacket(data []byte) error {\n\tvar n, m int\n\n\t// 0x00 [1 byte]\n\n\t// Affected rows [Length Coded Binary]\n\tmc.affectedRows, _, n = readLengthEncodedInteger(data[1:])\n\n\t// Insert id [Length Coded Binary]\n\tmc.insertId, _, m = readLengthEncodedInteger(data[1+n:])\n\n\t// server_status [2 bytes]\n\tmc.status = readStatus(data[1+n+m : 1+n+m+2])\n\tif mc.status&statusMoreResultsExists != 0 {\n\t\treturn nil\n\t}\n\n\t// warning count [2 bytes]\n\n\treturn nil\n}\n\n// Read Packets as Field Packets until EOF-Packet or an Error appears\n// http://dev.mysql.com/doc/internals/en/com-query-response.html#packet-Protocol::ColumnDefinition41\nfunc (mc *mysqlConn) readColumns(count int) ([]mysqlField, error) {\n\tcolumns := make([]mysqlField, count)\n\n\tfor i := 0; ; i++ {\n\t\tdata, err := mc.readPacket()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\t// EOF Packet\n\t\tif data[0] == iEOF && (len(data) == 5 || len(data) == 1) {\n\t\t\tif i == count {\n\t\t\t\treturn columns, nil\n\t\t\t}\n\t\t\treturn nil, fmt.Errorf(\"column count mismatch n:%d len:%d\", count, len(columns))\n\t\t}\n\n\t\t// Catalog\n\t\tpos, err := skipLengthEncodedString(data)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\t// Database [len coded string]\n\t\tn, err := skipLengthEncodedString(data[pos:])\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tpos += n\n\n\t\t// Table [len coded string]\n\t\tif mc.cfg.ColumnsWithAlias {\n\t\t\ttableName, _, n, err := readLengthEncodedString(data[pos:])\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tpos += n\n\t\t\tcolumns[i].tableName = string(tableName)\n\t\t} else {\n\t\t\tn, err = skipLengthEncodedString(data[pos:])\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tpos += n\n\t\t}\n\n\t\t// Original table [len coded string]\n\t\tn, err = skipLengthEncodedString(data[pos:])\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tpos += n\n\n\t\t// Name [len coded string]\n\t\tname, _, n, err := readLengthEncodedString(data[pos:])\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tcolumns[i].name = string(name)\n\t\tpos += n\n\n\t\t// Original name [len coded string]\n\t\tn, err = skipLengthEncodedString(data[pos:])\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tpos += n\n\n\t\t// Filler [uint8]\n\t\tpos++\n\n\t\t// Charset [charset, collation uint8]\n\t\tcolumns[i].charSet = data[pos]\n\t\tpos += 2\n\n\t\t// Length [uint32]\n\t\tcolumns[i].length = binary.LittleEndian.Uint32(data[pos : pos+4])\n\t\tpos += 4\n\n\t\t// Field type [uint8]\n\t\tcolumns[i].fieldType = fieldType(data[pos])\n\t\tpos++\n\n\t\t// Flags [uint16]\n\t\tcolumns[i].flags = fieldFlag(binary.LittleEndian.Uint16(data[pos : pos+2]))\n\t\tpos += 2\n\n\t\t// Decimals [uint8]\n\t\tcolumns[i].decimals = data[pos]\n\t\t//pos++\n\n\t\t// Default value [len coded binary]\n\t\t//if pos < len(data) {\n\t\t//\tdefaultVal, _, err = bytesToLengthCodedBinary(data[pos:])\n\t\t//}\n\t}\n}\n\n// Read Packets as Field Packets until EOF-Packet or an Error appears\n// http://dev.mysql.com/doc/internals/en/com-query-response.html#packet-ProtocolText::ResultsetRow\nfunc (rows *textRows) readRow(dest []driver.Value) error {\n\tmc := rows.mc\n\n\tif rows.rs.done {\n\t\treturn io.EOF\n\t}\n\n\tdata, err := mc.readPacket()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// EOF Packet\n\tif data[0] == iEOF && len(data) == 5 {\n\t\t// server_status [2 bytes]\n\t\trows.mc.status = readStatus(data[3:])\n\t\trows.rs.done = true\n\t\tif !rows.HasNextResultSet() {\n\t\t\trows.mc = nil\n\t\t}\n\t\treturn io.EOF\n\t}\n\tif data[0] == iERR {\n\t\trows.mc = nil\n\t\treturn mc.handleErrorPacket(data)\n\t}\n\n\t// RowSet Packet\n\tvar n int\n\tvar isNull bool\n\tpos := 0\n\n\tfor i := range dest {\n\t\t// Read bytes and convert to string\n\t\tdest[i], isNull, n, err = readLengthEncodedString(data[pos:])\n\t\tpos += n\n\t\tif err == nil {\n\t\t\tif !isNull {\n\t\t\t\tif !mc.parseTime {\n\t\t\t\t\tcontinue\n\t\t\t\t} else {\n\t\t\t\t\tswitch rows.rs.columns[i].fieldType {\n\t\t\t\t\tcase fieldTypeTimestamp, fieldTypeDateTime,\n\t\t\t\t\t\tfieldTypeDate, fieldTypeNewDate:\n\t\t\t\t\t\tdest[i], err = parseDateTime(\n\t\t\t\t\t\t\tstring(dest[i].([]byte)),\n\t\t\t\t\t\t\tmc.cfg.Loc,\n\t\t\t\t\t\t)\n\t\t\t\t\t\tif err == nil {\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t} else {\n\t\t\t\tdest[i] = nil\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\treturn err // err != nil\n\t}\n\n\treturn nil\n}\n\n// Reads Packets until EOF-Packet or an Error appears. Returns count of Packets read\nfunc (mc *mysqlConn) readUntilEOF() error {\n\tfor {\n\t\tdata, err := mc.readPacket()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tswitch data[0] {\n\t\tcase iERR:\n\t\t\treturn mc.handleErrorPacket(data)\n\t\tcase iEOF:\n\t\t\tif len(data) == 5 {\n\t\t\t\tmc.status = readStatus(data[3:])\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\t}\n}\n\n/******************************************************************************\n*                           Prepared Statements                               *\n******************************************************************************/\n\n// Prepare Result Packets\n// http://dev.mysql.com/doc/internals/en/com-stmt-prepare-response.html\nfunc (stmt *mysqlStmt) readPrepareResultPacket() (uint16, error) {\n\tdata, err := stmt.mc.readPacket()\n\tif err == nil {\n\t\t// packet indicator [1 byte]\n\t\tif data[0] != iOK {\n\t\t\treturn 0, stmt.mc.handleErrorPacket(data)\n\t\t}\n\n\t\t// statement id [4 bytes]\n\t\tstmt.id = binary.LittleEndian.Uint32(data[1:5])\n\n\t\t// Column count [16 bit uint]\n\t\tcolumnCount := binary.LittleEndian.Uint16(data[5:7])\n\n\t\t// Param count [16 bit uint]\n\t\tstmt.paramCount = int(binary.LittleEndian.Uint16(data[7:9]))\n\n\t\t// Reserved [8 bit]\n\n\t\t// Warning count [16 bit uint]\n\n\t\treturn columnCount, nil\n\t}\n\treturn 0, err\n}\n\n// http://dev.mysql.com/doc/internals/en/com-stmt-send-long-data.html\nfunc (stmt *mysqlStmt) writeCommandLongData(paramID int, arg []byte) error {\n\tmaxLen := stmt.mc.maxAllowedPacket - 1\n\tpktLen := maxLen\n\n\t// After the header (bytes 0-3) follows before the data:\n\t// 1 byte command\n\t// 4 bytes stmtID\n\t// 2 bytes paramID\n\tconst dataOffset = 1 + 4 + 2\n\n\t// Can not use the write buffer since\n\t// a) the buffer is too small\n\t// b) it is in use\n\tdata := make([]byte, 4+1+4+2+len(arg))\n\n\tcopy(data[4+dataOffset:], arg)\n\n\tfor argLen := len(arg); argLen > 0; argLen -= pktLen - dataOffset {\n\t\tif dataOffset+argLen < maxLen {\n\t\t\tpktLen = dataOffset + argLen\n\t\t}\n\n\t\tstmt.mc.sequence = 0\n\t\t// Add command byte [1 byte]\n\t\tdata[4] = comStmtSendLongData\n\n\t\t// Add stmtID [32 bit]\n\t\tdata[5] = byte(stmt.id)\n\t\tdata[6] = byte(stmt.id >> 8)\n\t\tdata[7] = byte(stmt.id >> 16)\n\t\tdata[8] = byte(stmt.id >> 24)\n\n\t\t// Add paramID [16 bit]\n\t\tdata[9] = byte(paramID)\n\t\tdata[10] = byte(paramID >> 8)\n\n\t\t// Send CMD packet\n\t\terr := stmt.mc.writePacket(data[:4+pktLen])\n\t\tif err == nil {\n\t\t\tdata = data[pktLen-dataOffset:]\n\t\t\tcontinue\n\t\t}\n\t\treturn err\n\n\t}\n\n\t// Reset Packet Sequence\n\tstmt.mc.sequence = 0\n\treturn nil\n}\n\n// Execute Prepared Statement\n// http://dev.mysql.com/doc/internals/en/com-stmt-execute.html\nfunc (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {\n\tif len(args) != stmt.paramCount {\n\t\treturn fmt.Errorf(\n\t\t\t\"argument count mismatch (got: %d; has: %d)\",\n\t\t\tlen(args),\n\t\t\tstmt.paramCount,\n\t\t)\n\t}\n\n\tconst minPktLen = 4 + 1 + 4 + 1 + 4\n\tmc := stmt.mc\n\n\t// Determine threshould dynamically to avoid packet size shortage.\n\tlongDataSize := mc.maxAllowedPacket / (stmt.paramCount + 1)\n\tif longDataSize < 64 {\n\t\tlongDataSize = 64\n\t}\n\n\t// Reset packet-sequence\n\tmc.sequence = 0\n\n\tvar data []byte\n\n\tif len(args) == 0 {\n\t\tdata = mc.buf.takeBuffer(minPktLen)\n\t} else {\n\t\tdata = mc.buf.takeCompleteBuffer()\n\t}\n\tif data == nil {\n\t\t// can not take the buffer. Something must be wrong with the connection\n\t\terrLog.Print(ErrBusyBuffer)\n\t\treturn errBadConnNoWrite\n\t}\n\n\t// command [1 byte]\n\tdata[4] = comStmtExecute\n\n\t// statement_id [4 bytes]\n\tdata[5] = byte(stmt.id)\n\tdata[6] = byte(stmt.id >> 8)\n\tdata[7] = byte(stmt.id >> 16)\n\tdata[8] = byte(stmt.id >> 24)\n\n\t// flags (0: CURSOR_TYPE_NO_CURSOR) [1 byte]\n\tdata[9] = 0x00\n\n\t// iteration_count (uint32(1)) [4 bytes]\n\tdata[10] = 0x01\n\tdata[11] = 0x00\n\tdata[12] = 0x00\n\tdata[13] = 0x00\n\n\tif len(args) > 0 {\n\t\tpos := minPktLen\n\n\t\tvar nullMask []byte\n\t\tif maskLen, typesLen := (len(args)+7)/8, 1+2*len(args); pos+maskLen+typesLen >= len(data) {\n\t\t\t// buffer has to be extended but we don't know by how much so\n\t\t\t// we depend on append after all data with known sizes fit.\n\t\t\t// We stop at that because we deal with a lot of columns here\n\t\t\t// which makes the required allocation size hard to guess.\n\t\t\ttmp := make([]byte, pos+maskLen+typesLen)\n\t\t\tcopy(tmp[:pos], data[:pos])\n\t\t\tdata = tmp\n\t\t\tnullMask = data[pos : pos+maskLen]\n\t\t\tpos += maskLen\n\t\t} else {\n\t\t\tnullMask = data[pos : pos+maskLen]\n\t\t\tfor i := 0; i < maskLen; i++ {\n\t\t\t\tnullMask[i] = 0\n\t\t\t}\n\t\t\tpos += maskLen\n\t\t}\n\n\t\t// newParameterBoundFlag 1 [1 byte]\n\t\tdata[pos] = 0x01\n\t\tpos++\n\n\t\t// type of each parameter [len(args)*2 bytes]\n\t\tparamTypes := data[pos:]\n\t\tpos += len(args) * 2\n\n\t\t// value of each parameter [n bytes]\n\t\tparamValues := data[pos:pos]\n\t\tvaluesCap := cap(paramValues)\n\n\t\tfor i, arg := range args {\n\t\t\t// build NULL-bitmap\n\t\t\tif arg == nil {\n\t\t\t\tnullMask[i/8] |= 1 << (uint(i) & 7)\n\t\t\t\tparamTypes[i+i] = byte(fieldTypeNULL)\n\t\t\t\tparamTypes[i+i+1] = 0x00\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// cache types and values\n\t\t\tswitch v := arg.(type) {\n\t\t\tcase int64:\n\t\t\t\tparamTypes[i+i] = byte(fieldTypeLongLong)\n\t\t\t\tparamTypes[i+i+1] = 0x00\n\n\t\t\t\tif cap(paramValues)-len(paramValues)-8 >= 0 {\n\t\t\t\t\tparamValues = paramValues[:len(paramValues)+8]\n\t\t\t\t\tbinary.LittleEndian.PutUint64(\n\t\t\t\t\t\tparamValues[len(paramValues)-8:],\n\t\t\t\t\t\tuint64(v),\n\t\t\t\t\t)\n\t\t\t\t} else {\n\t\t\t\t\tparamValues = append(paramValues,\n\t\t\t\t\t\tuint64ToBytes(uint64(v))...,\n\t\t\t\t\t)\n\t\t\t\t}\n\n\t\t\tcase float64:\n\t\t\t\tparamTypes[i+i] = byte(fieldTypeDouble)\n\t\t\t\tparamTypes[i+i+1] = 0x00\n\n\t\t\t\tif cap(paramValues)-len(paramValues)-8 >= 0 {\n\t\t\t\t\tparamValues = paramValues[:len(paramValues)+8]\n\t\t\t\t\tbinary.LittleEndian.PutUint64(\n\t\t\t\t\t\tparamValues[len(paramValues)-8:],\n\t\t\t\t\t\tmath.Float64bits(v),\n\t\t\t\t\t)\n\t\t\t\t} else {\n\t\t\t\t\tparamValues = append(paramValues,\n\t\t\t\t\t\tuint64ToBytes(math.Float64bits(v))...,\n\t\t\t\t\t)\n\t\t\t\t}\n\n\t\t\tcase bool:\n\t\t\t\tparamTypes[i+i] = byte(fieldTypeTiny)\n\t\t\t\tparamTypes[i+i+1] = 0x00\n\n\t\t\t\tif v {\n\t\t\t\t\tparamValues = append(paramValues, 0x01)\n\t\t\t\t} else {\n\t\t\t\t\tparamValues = append(paramValues, 0x00)\n\t\t\t\t}\n\n\t\t\tcase []byte:\n\t\t\t\t// Common case (non-nil value) first\n\t\t\t\tif v != nil {\n\t\t\t\t\tparamTypes[i+i] = byte(fieldTypeString)\n\t\t\t\t\tparamTypes[i+i+1] = 0x00\n\n\t\t\t\t\tif len(v) < longDataSize {\n\t\t\t\t\t\tparamValues = appendLengthEncodedInteger(paramValues,\n\t\t\t\t\t\t\tuint64(len(v)),\n\t\t\t\t\t\t)\n\t\t\t\t\t\tparamValues = append(paramValues, v...)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif err := stmt.writeCommandLongData(i, v); err != nil {\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\t// Handle []byte(nil) as a NULL value\n\t\t\t\tnullMask[i/8] |= 1 << (uint(i) & 7)\n\t\t\t\tparamTypes[i+i] = byte(fieldTypeNULL)\n\t\t\t\tparamTypes[i+i+1] = 0x00\n\n\t\t\tcase string:\n\t\t\t\tparamTypes[i+i] = byte(fieldTypeString)\n\t\t\t\tparamTypes[i+i+1] = 0x00\n\n\t\t\t\tif len(v) < longDataSize {\n\t\t\t\t\tparamValues = appendLengthEncodedInteger(paramValues,\n\t\t\t\t\t\tuint64(len(v)),\n\t\t\t\t\t)\n\t\t\t\t\tparamValues = append(paramValues, v...)\n\t\t\t\t} else {\n\t\t\t\t\tif err := stmt.writeCommandLongData(i, []byte(v)); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\tcase time.Time:\n\t\t\t\tparamTypes[i+i] = byte(fieldTypeString)\n\t\t\t\tparamTypes[i+i+1] = 0x00\n\n\t\t\t\tvar a [64]byte\n\t\t\t\tvar b = a[:0]\n\n\t\t\t\tif v.IsZero() {\n\t\t\t\t\tb = append(b, \"0000-00-00\"...)\n\t\t\t\t} else {\n\t\t\t\t\tb = v.In(mc.cfg.Loc).AppendFormat(b, timeFormat)\n\t\t\t\t}\n\n\t\t\t\tparamValues = appendLengthEncodedInteger(paramValues,\n\t\t\t\t\tuint64(len(b)),\n\t\t\t\t)\n\t\t\t\tparamValues = append(paramValues, b...)\n\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"can not convert type: %T\", arg)\n\t\t\t}\n\t\t}\n\n\t\t// Check if param values exceeded the available buffer\n\t\t// In that case we must build the data packet with the new values buffer\n\t\tif valuesCap != cap(paramValues) {\n\t\t\tdata = append(data[:pos], paramValues...)\n\t\t\tmc.buf.buf = data\n\t\t}\n\n\t\tpos += len(paramValues)\n\t\tdata = data[:pos]\n\t}\n\n\treturn mc.writePacket(data)\n}\n\nfunc (mc *mysqlConn) discardResults() error {\n\tfor mc.status&statusMoreResultsExists != 0 {\n\t\tresLen, err := mc.readResultSetHeaderPacket()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif resLen > 0 {\n\t\t\t// columns\n\t\t\tif err := mc.readUntilEOF(); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\t// rows\n\t\t\tif err := mc.readUntilEOF(); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// http://dev.mysql.com/doc/internals/en/binary-protocol-resultset-row.html\nfunc (rows *binaryRows) readRow(dest []driver.Value) error {\n\tdata, err := rows.mc.readPacket()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// packet indicator [1 byte]\n\tif data[0] != iOK {\n\t\t// EOF Packet\n\t\tif data[0] == iEOF && len(data) == 5 {\n\t\t\trows.mc.status = readStatus(data[3:])\n\t\t\trows.rs.done = true\n\t\t\tif !rows.HasNextResultSet() {\n\t\t\t\trows.mc = nil\n\t\t\t}\n\t\t\treturn io.EOF\n\t\t}\n\t\tmc := rows.mc\n\t\trows.mc = nil\n\n\t\t// Error otherwise\n\t\treturn mc.handleErrorPacket(data)\n\t}\n\n\t// NULL-bitmap,  [(column-count + 7 + 2) / 8 bytes]\n\tpos := 1 + (len(dest)+7+2)>>3\n\tnullMask := data[1:pos]\n\n\tfor i := range dest {\n\t\t// Field is NULL\n\t\t// (byte >> bit-pos) % 2 == 1\n\t\tif ((nullMask[(i+2)>>3] >> uint((i+2)&7)) & 1) == 1 {\n\t\t\tdest[i] = nil\n\t\t\tcontinue\n\t\t}\n\n\t\t// Convert to byte-coded string\n\t\tswitch rows.rs.columns[i].fieldType {\n\t\tcase fieldTypeNULL:\n\t\t\tdest[i] = nil\n\t\t\tcontinue\n\n\t\t// Numeric Types\n\t\tcase fieldTypeTiny:\n\t\t\tif rows.rs.columns[i].flags&flagUnsigned != 0 {\n\t\t\t\tdest[i] = int64(data[pos])\n\t\t\t} else {\n\t\t\t\tdest[i] = int64(int8(data[pos]))\n\t\t\t}\n\t\t\tpos++\n\t\t\tcontinue\n\n\t\tcase fieldTypeShort, fieldTypeYear:\n\t\t\tif rows.rs.columns[i].flags&flagUnsigned != 0 {\n\t\t\t\tdest[i] = int64(binary.LittleEndian.Uint16(data[pos : pos+2]))\n\t\t\t} else {\n\t\t\t\tdest[i] = int64(int16(binary.LittleEndian.Uint16(data[pos : pos+2])))\n\t\t\t}\n\t\t\tpos += 2\n\t\t\tcontinue\n\n\t\tcase fieldTypeInt24, fieldTypeLong:\n\t\t\tif rows.rs.columns[i].flags&flagUnsigned != 0 {\n\t\t\t\tdest[i] = int64(binary.LittleEndian.Uint32(data[pos : pos+4]))\n\t\t\t} else {\n\t\t\t\tdest[i] = int64(int32(binary.LittleEndian.Uint32(data[pos : pos+4])))\n\t\t\t}\n\t\t\tpos += 4\n\t\t\tcontinue\n\n\t\tcase fieldTypeLongLong:\n\t\t\tif rows.rs.columns[i].flags&flagUnsigned != 0 {\n\t\t\t\tval := binary.LittleEndian.Uint64(data[pos : pos+8])\n\t\t\t\tif val > math.MaxInt64 {\n\t\t\t\t\tdest[i] = uint64ToString(val)\n\t\t\t\t} else {\n\t\t\t\t\tdest[i] = int64(val)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tdest[i] = int64(binary.LittleEndian.Uint64(data[pos : pos+8]))\n\t\t\t}\n\t\t\tpos += 8\n\t\t\tcontinue\n\n\t\tcase fieldTypeFloat:\n\t\t\tdest[i] = math.Float32frombits(binary.LittleEndian.Uint32(data[pos : pos+4]))\n\t\t\tpos += 4\n\t\t\tcontinue\n\n\t\tcase fieldTypeDouble:\n\t\t\tdest[i] = math.Float64frombits(binary.LittleEndian.Uint64(data[pos : pos+8]))\n\t\t\tpos += 8\n\t\t\tcontinue\n\n\t\t// Length coded Binary Strings\n\t\tcase fieldTypeDecimal, fieldTypeNewDecimal, fieldTypeVarChar,\n\t\t\tfieldTypeBit, fieldTypeEnum, fieldTypeSet, fieldTypeTinyBLOB,\n\t\t\tfieldTypeMediumBLOB, fieldTypeLongBLOB, fieldTypeBLOB,\n\t\t\tfieldTypeVarString, fieldTypeString, fieldTypeGeometry, fieldTypeJSON:\n\t\t\tvar isNull bool\n\t\t\tvar n int\n\t\t\tdest[i], isNull, n, err = readLengthEncodedString(data[pos:])\n\t\t\tpos += n\n\t\t\tif err == nil {\n\t\t\t\tif !isNull {\n\t\t\t\t\tcontinue\n\t\t\t\t} else {\n\t\t\t\t\tdest[i] = nil\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn err\n\n\t\tcase\n\t\t\tfieldTypeDate, fieldTypeNewDate, // Date YYYY-MM-DD\n\t\t\tfieldTypeTime,                         // Time [-][H]HH:MM:SS[.fractal]\n\t\t\tfieldTypeTimestamp, fieldTypeDateTime: // Timestamp YYYY-MM-DD HH:MM:SS[.fractal]\n\n\t\t\tnum, isNull, n := readLengthEncodedInteger(data[pos:])\n\t\t\tpos += n\n\n\t\t\tswitch {\n\t\t\tcase isNull:\n\t\t\t\tdest[i] = nil\n\t\t\t\tcontinue\n\t\t\tcase rows.rs.columns[i].fieldType == fieldTypeTime:\n\t\t\t\t// database/sql does not support an equivalent to TIME, return a string\n\t\t\t\tvar dstlen uint8\n\t\t\t\tswitch decimals := rows.rs.columns[i].decimals; decimals {\n\t\t\t\tcase 0x00, 0x1f:\n\t\t\t\t\tdstlen = 8\n\t\t\t\tcase 1, 2, 3, 4, 5, 6:\n\t\t\t\t\tdstlen = 8 + 1 + decimals\n\t\t\t\tdefault:\n\t\t\t\t\treturn fmt.Errorf(\n\t\t\t\t\t\t\"protocol error, illegal decimals value %d\",\n\t\t\t\t\t\trows.rs.columns[i].decimals,\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tdest[i], err = formatBinaryDateTime(data[pos:pos+int(num)], dstlen, true)\n\t\t\tcase rows.mc.parseTime:\n\t\t\t\tdest[i], err = parseBinaryDateTime(num, data[pos:], rows.mc.cfg.Loc)\n\t\t\tdefault:\n\t\t\t\tvar dstlen uint8\n\t\t\t\tif rows.rs.columns[i].fieldType == fieldTypeDate {\n\t\t\t\t\tdstlen = 10\n\t\t\t\t} else {\n\t\t\t\t\tswitch decimals := rows.rs.columns[i].decimals; decimals {\n\t\t\t\t\tcase 0x00, 0x1f:\n\t\t\t\t\t\tdstlen = 19\n\t\t\t\t\tcase 1, 2, 3, 4, 5, 6:\n\t\t\t\t\t\tdstlen = 19 + 1 + decimals\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn fmt.Errorf(\n\t\t\t\t\t\t\t\"protocol error, illegal decimals value %d\",\n\t\t\t\t\t\t\trows.rs.columns[i].decimals,\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tdest[i], err = formatBinaryDateTime(data[pos:pos+int(num)], dstlen, false)\n\t\t\t}\n\n\t\t\tif err == nil {\n\t\t\t\tpos += int(num)\n\t\t\t\tcontinue\n\t\t\t} else {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t// Please report if this happens!\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unknown field type %d\", rows.rs.columns[i].fieldType)\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/go-sql-driver/mysql/result.go",
    "content": "// Go MySQL Driver - A MySQL-Driver for Go's database/sql package\n//\n// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.\n//\n// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this file,\n// You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage mysql\n\ntype mysqlResult struct {\n\taffectedRows int64\n\tinsertId     int64\n}\n\nfunc (res *mysqlResult) LastInsertId() (int64, error) {\n\treturn res.insertId, nil\n}\n\nfunc (res *mysqlResult) RowsAffected() (int64, error) {\n\treturn res.affectedRows, nil\n}\n"
  },
  {
    "path": "vendor/github.com/go-sql-driver/mysql/rows.go",
    "content": "// Go MySQL Driver - A MySQL-Driver for Go's database/sql package\n//\n// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.\n//\n// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this file,\n// You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage mysql\n\nimport (\n\t\"database/sql/driver\"\n\t\"io\"\n\t\"math\"\n\t\"reflect\"\n)\n\ntype resultSet struct {\n\tcolumns     []mysqlField\n\tcolumnNames []string\n\tdone        bool\n}\n\ntype mysqlRows struct {\n\tmc     *mysqlConn\n\trs     resultSet\n\tfinish func()\n}\n\ntype binaryRows struct {\n\tmysqlRows\n}\n\ntype textRows struct {\n\tmysqlRows\n}\n\nfunc (rows *mysqlRows) Columns() []string {\n\tif rows.rs.columnNames != nil {\n\t\treturn rows.rs.columnNames\n\t}\n\n\tcolumns := make([]string, len(rows.rs.columns))\n\tif rows.mc != nil && rows.mc.cfg.ColumnsWithAlias {\n\t\tfor i := range columns {\n\t\t\tif tableName := rows.rs.columns[i].tableName; len(tableName) > 0 {\n\t\t\t\tcolumns[i] = tableName + \".\" + rows.rs.columns[i].name\n\t\t\t} else {\n\t\t\t\tcolumns[i] = rows.rs.columns[i].name\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfor i := range columns {\n\t\t\tcolumns[i] = rows.rs.columns[i].name\n\t\t}\n\t}\n\n\trows.rs.columnNames = columns\n\treturn columns\n}\n\nfunc (rows *mysqlRows) ColumnTypeDatabaseTypeName(i int) string {\n\treturn rows.rs.columns[i].typeDatabaseName()\n}\n\n// func (rows *mysqlRows) ColumnTypeLength(i int) (length int64, ok bool) {\n// \treturn int64(rows.rs.columns[i].length), true\n// }\n\nfunc (rows *mysqlRows) ColumnTypeNullable(i int) (nullable, ok bool) {\n\treturn rows.rs.columns[i].flags&flagNotNULL == 0, true\n}\n\nfunc (rows *mysqlRows) ColumnTypePrecisionScale(i int) (int64, int64, bool) {\n\tcolumn := rows.rs.columns[i]\n\tdecimals := int64(column.decimals)\n\n\tswitch column.fieldType {\n\tcase fieldTypeDecimal, fieldTypeNewDecimal:\n\t\tif decimals > 0 {\n\t\t\treturn int64(column.length) - 2, decimals, true\n\t\t}\n\t\treturn int64(column.length) - 1, decimals, true\n\tcase fieldTypeTimestamp, fieldTypeDateTime, fieldTypeTime:\n\t\treturn decimals, decimals, true\n\tcase fieldTypeFloat, fieldTypeDouble:\n\t\tif decimals == 0x1f {\n\t\t\treturn math.MaxInt64, math.MaxInt64, true\n\t\t}\n\t\treturn math.MaxInt64, decimals, true\n\t}\n\n\treturn 0, 0, false\n}\n\nfunc (rows *mysqlRows) ColumnTypeScanType(i int) reflect.Type {\n\treturn rows.rs.columns[i].scanType()\n}\n\nfunc (rows *mysqlRows) Close() (err error) {\n\tif f := rows.finish; f != nil {\n\t\tf()\n\t\trows.finish = nil\n\t}\n\n\tmc := rows.mc\n\tif mc == nil {\n\t\treturn nil\n\t}\n\tif err := mc.error(); err != nil {\n\t\treturn err\n\t}\n\n\t// Remove unread packets from stream\n\tif !rows.rs.done {\n\t\terr = mc.readUntilEOF()\n\t}\n\tif err == nil {\n\t\tif err = mc.discardResults(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\trows.mc = nil\n\treturn err\n}\n\nfunc (rows *mysqlRows) HasNextResultSet() (b bool) {\n\tif rows.mc == nil {\n\t\treturn false\n\t}\n\treturn rows.mc.status&statusMoreResultsExists != 0\n}\n\nfunc (rows *mysqlRows) nextResultSet() (int, error) {\n\tif rows.mc == nil {\n\t\treturn 0, io.EOF\n\t}\n\tif err := rows.mc.error(); err != nil {\n\t\treturn 0, err\n\t}\n\n\t// Remove unread packets from stream\n\tif !rows.rs.done {\n\t\tif err := rows.mc.readUntilEOF(); err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\trows.rs.done = true\n\t}\n\n\tif !rows.HasNextResultSet() {\n\t\trows.mc = nil\n\t\treturn 0, io.EOF\n\t}\n\trows.rs = resultSet{}\n\treturn rows.mc.readResultSetHeaderPacket()\n}\n\nfunc (rows *mysqlRows) nextNotEmptyResultSet() (int, error) {\n\tfor {\n\t\tresLen, err := rows.nextResultSet()\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\n\t\tif resLen > 0 {\n\t\t\treturn resLen, nil\n\t\t}\n\n\t\trows.rs.done = true\n\t}\n}\n\nfunc (rows *binaryRows) NextResultSet() error {\n\tresLen, err := rows.nextNotEmptyResultSet()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\trows.rs.columns, err = rows.mc.readColumns(resLen)\n\treturn err\n}\n\nfunc (rows *binaryRows) Next(dest []driver.Value) error {\n\tif mc := rows.mc; mc != nil {\n\t\tif err := mc.error(); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// Fetch next row from stream\n\t\treturn rows.readRow(dest)\n\t}\n\treturn io.EOF\n}\n\nfunc (rows *textRows) NextResultSet() (err error) {\n\tresLen, err := rows.nextNotEmptyResultSet()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\trows.rs.columns, err = rows.mc.readColumns(resLen)\n\treturn err\n}\n\nfunc (rows *textRows) Next(dest []driver.Value) error {\n\tif mc := rows.mc; mc != nil {\n\t\tif err := mc.error(); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// Fetch next row from stream\n\t\treturn rows.readRow(dest)\n\t}\n\treturn io.EOF\n}\n"
  },
  {
    "path": "vendor/github.com/go-sql-driver/mysql/statement.go",
    "content": "// Go MySQL Driver - A MySQL-Driver for Go's database/sql package\n//\n// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.\n//\n// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this file,\n// You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage mysql\n\nimport (\n\t\"database/sql/driver\"\n\t\"fmt\"\n\t\"io\"\n\t\"reflect\"\n\t\"strconv\"\n)\n\ntype mysqlStmt struct {\n\tmc         *mysqlConn\n\tid         uint32\n\tparamCount int\n}\n\nfunc (stmt *mysqlStmt) Close() error {\n\tif stmt.mc == nil || stmt.mc.closed.IsSet() {\n\t\t// driver.Stmt.Close can be called more than once, thus this function\n\t\t// has to be idempotent.\n\t\t// See also Issue #450 and golang/go#16019.\n\t\t//errLog.Print(ErrInvalidConn)\n\t\treturn driver.ErrBadConn\n\t}\n\n\terr := stmt.mc.writeCommandPacketUint32(comStmtClose, stmt.id)\n\tstmt.mc = nil\n\treturn err\n}\n\nfunc (stmt *mysqlStmt) NumInput() int {\n\treturn stmt.paramCount\n}\n\nfunc (stmt *mysqlStmt) ColumnConverter(idx int) driver.ValueConverter {\n\treturn converter{}\n}\n\nfunc (stmt *mysqlStmt) Exec(args []driver.Value) (driver.Result, error) {\n\tif stmt.mc.closed.IsSet() {\n\t\terrLog.Print(ErrInvalidConn)\n\t\treturn nil, driver.ErrBadConn\n\t}\n\t// Send command\n\terr := stmt.writeExecutePacket(args)\n\tif err != nil {\n\t\treturn nil, stmt.mc.markBadConn(err)\n\t}\n\n\tmc := stmt.mc\n\n\tmc.affectedRows = 0\n\tmc.insertId = 0\n\n\t// Read Result\n\tresLen, err := mc.readResultSetHeaderPacket()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif resLen > 0 {\n\t\t// Columns\n\t\tif err = mc.readUntilEOF(); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\t// Rows\n\t\tif err := mc.readUntilEOF(); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tif err := mc.discardResults(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &mysqlResult{\n\t\taffectedRows: int64(mc.affectedRows),\n\t\tinsertId:     int64(mc.insertId),\n\t}, nil\n}\n\nfunc (stmt *mysqlStmt) Query(args []driver.Value) (driver.Rows, error) {\n\treturn stmt.query(args)\n}\n\nfunc (stmt *mysqlStmt) query(args []driver.Value) (*binaryRows, error) {\n\tif stmt.mc.closed.IsSet() {\n\t\terrLog.Print(ErrInvalidConn)\n\t\treturn nil, driver.ErrBadConn\n\t}\n\t// Send command\n\terr := stmt.writeExecutePacket(args)\n\tif err != nil {\n\t\treturn nil, stmt.mc.markBadConn(err)\n\t}\n\n\tmc := stmt.mc\n\n\t// Read Result\n\tresLen, err := mc.readResultSetHeaderPacket()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\trows := new(binaryRows)\n\n\tif resLen > 0 {\n\t\trows.mc = mc\n\t\trows.rs.columns, err = mc.readColumns(resLen)\n\t} else {\n\t\trows.rs.done = true\n\n\t\tswitch err := rows.NextResultSet(); err {\n\t\tcase nil, io.EOF:\n\t\t\treturn rows, nil\n\t\tdefault:\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn rows, err\n}\n\ntype converter struct{}\n\n// ConvertValue mirrors the reference/default converter in database/sql/driver\n// with _one_ exception.  We support uint64 with their high bit and the default\n// implementation does not.  This function should be kept in sync with\n// database/sql/driver defaultConverter.ConvertValue() except for that\n// deliberate difference.\nfunc (c converter) ConvertValue(v interface{}) (driver.Value, error) {\n\tif driver.IsValue(v) {\n\t\treturn v, nil\n\t}\n\n\tif vr, ok := v.(driver.Valuer); ok {\n\t\tsv, err := callValuerValue(vr)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif !driver.IsValue(sv) {\n\t\t\treturn nil, fmt.Errorf(\"non-Value type %T returned from Value\", sv)\n\t\t}\n\t\treturn sv, nil\n\t}\n\n\trv := reflect.ValueOf(v)\n\tswitch rv.Kind() {\n\tcase reflect.Ptr:\n\t\t// indirect pointers\n\t\tif rv.IsNil() {\n\t\t\treturn nil, nil\n\t\t} else {\n\t\t\treturn c.ConvertValue(rv.Elem().Interface())\n\t\t}\n\tcase reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:\n\t\treturn rv.Int(), nil\n\tcase reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:\n\t\treturn int64(rv.Uint()), nil\n\tcase reflect.Uint64:\n\t\tu64 := rv.Uint()\n\t\tif u64 >= 1<<63 {\n\t\t\treturn strconv.FormatUint(u64, 10), nil\n\t\t}\n\t\treturn int64(u64), nil\n\tcase reflect.Float32, reflect.Float64:\n\t\treturn rv.Float(), nil\n\tcase reflect.Bool:\n\t\treturn rv.Bool(), nil\n\tcase reflect.Slice:\n\t\tek := rv.Type().Elem().Kind()\n\t\tif ek == reflect.Uint8 {\n\t\t\treturn rv.Bytes(), nil\n\t\t}\n\t\treturn nil, fmt.Errorf(\"unsupported type %T, a slice of %s\", v, ek)\n\tcase reflect.String:\n\t\treturn rv.String(), nil\n\t}\n\treturn nil, fmt.Errorf(\"unsupported type %T, a %s\", v, rv.Kind())\n}\n\nvar valuerReflectType = reflect.TypeOf((*driver.Valuer)(nil)).Elem()\n\n// callValuerValue returns vr.Value(), with one exception:\n// If vr.Value is an auto-generated method on a pointer type and the\n// pointer is nil, it would panic at runtime in the panicwrap\n// method. Treat it like nil instead.\n//\n// This is so people can implement driver.Value on value types and\n// still use nil pointers to those types to mean nil/NULL, just like\n// string/*string.\n//\n// This is an exact copy of the same-named unexported function from the\n// database/sql package.\nfunc callValuerValue(vr driver.Valuer) (v driver.Value, err error) {\n\tif rv := reflect.ValueOf(vr); rv.Kind() == reflect.Ptr &&\n\t\trv.IsNil() &&\n\t\trv.Type().Elem().Implements(valuerReflectType) {\n\t\treturn nil, nil\n\t}\n\treturn vr.Value()\n}\n"
  },
  {
    "path": "vendor/github.com/go-sql-driver/mysql/transaction.go",
    "content": "// Go MySQL Driver - A MySQL-Driver for Go's database/sql package\n//\n// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.\n//\n// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this file,\n// You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage mysql\n\ntype mysqlTx struct {\n\tmc *mysqlConn\n}\n\nfunc (tx *mysqlTx) Commit() (err error) {\n\tif tx.mc == nil || tx.mc.closed.IsSet() {\n\t\treturn ErrInvalidConn\n\t}\n\terr = tx.mc.exec(\"COMMIT\")\n\ttx.mc = nil\n\treturn\n}\n\nfunc (tx *mysqlTx) Rollback() (err error) {\n\tif tx.mc == nil || tx.mc.closed.IsSet() {\n\t\treturn ErrInvalidConn\n\t}\n\terr = tx.mc.exec(\"ROLLBACK\")\n\ttx.mc = nil\n\treturn\n}\n"
  },
  {
    "path": "vendor/github.com/go-sql-driver/mysql/utils.go",
    "content": "// Go MySQL Driver - A MySQL-Driver for Go's database/sql package\n//\n// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.\n//\n// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this file,\n// You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage mysql\n\nimport (\n\t\"crypto/sha1\"\n\t\"crypto/tls\"\n\t\"database/sql/driver\"\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n)\n\nvar (\n\ttlsConfigLock     sync.RWMutex\n\ttlsConfigRegister map[string]*tls.Config // Register for custom tls.Configs\n)\n\n// RegisterTLSConfig registers a custom tls.Config to be used with sql.Open.\n// Use the key as a value in the DSN where tls=value.\n//\n// Note: The tls.Config provided to needs to be exclusively owned by the driver after registering.\n//\n//  rootCertPool := x509.NewCertPool()\n//  pem, err := ioutil.ReadFile(\"/path/ca-cert.pem\")\n//  if err != nil {\n//      log.Fatal(err)\n//  }\n//  if ok := rootCertPool.AppendCertsFromPEM(pem); !ok {\n//      log.Fatal(\"Failed to append PEM.\")\n//  }\n//  clientCert := make([]tls.Certificate, 0, 1)\n//  certs, err := tls.LoadX509KeyPair(\"/path/client-cert.pem\", \"/path/client-key.pem\")\n//  if err != nil {\n//      log.Fatal(err)\n//  }\n//  clientCert = append(clientCert, certs)\n//  mysql.RegisterTLSConfig(\"custom\", &tls.Config{\n//      RootCAs: rootCertPool,\n//      Certificates: clientCert,\n//  })\n//  db, err := sql.Open(\"mysql\", \"user@tcp(localhost:3306)/test?tls=custom\")\n//\nfunc RegisterTLSConfig(key string, config *tls.Config) error {\n\tif _, isBool := readBool(key); isBool || strings.ToLower(key) == \"skip-verify\" {\n\t\treturn fmt.Errorf(\"key '%s' is reserved\", key)\n\t}\n\n\ttlsConfigLock.Lock()\n\tif tlsConfigRegister == nil {\n\t\ttlsConfigRegister = make(map[string]*tls.Config)\n\t}\n\n\ttlsConfigRegister[key] = config\n\ttlsConfigLock.Unlock()\n\treturn nil\n}\n\n// DeregisterTLSConfig removes the tls.Config associated with key.\nfunc DeregisterTLSConfig(key string) {\n\ttlsConfigLock.Lock()\n\tif tlsConfigRegister != nil {\n\t\tdelete(tlsConfigRegister, key)\n\t}\n\ttlsConfigLock.Unlock()\n}\n\nfunc getTLSConfigClone(key string) (config *tls.Config) {\n\ttlsConfigLock.RLock()\n\tif v, ok := tlsConfigRegister[key]; ok {\n\t\tconfig = cloneTLSConfig(v)\n\t}\n\ttlsConfigLock.RUnlock()\n\treturn\n}\n\n// Returns the bool value of the input.\n// The 2nd return value indicates if the input was a valid bool value\nfunc readBool(input string) (value bool, valid bool) {\n\tswitch input {\n\tcase \"1\", \"true\", \"TRUE\", \"True\":\n\t\treturn true, true\n\tcase \"0\", \"false\", \"FALSE\", \"False\":\n\t\treturn false, true\n\t}\n\n\t// Not a valid bool value\n\treturn\n}\n\n/******************************************************************************\n*                             Authentication                                  *\n******************************************************************************/\n\n// Encrypt password using 4.1+ method\nfunc scramblePassword(scramble, password []byte) []byte {\n\tif len(password) == 0 {\n\t\treturn nil\n\t}\n\n\t// stage1Hash = SHA1(password)\n\tcrypt := sha1.New()\n\tcrypt.Write(password)\n\tstage1 := crypt.Sum(nil)\n\n\t// scrambleHash = SHA1(scramble + SHA1(stage1Hash))\n\t// inner Hash\n\tcrypt.Reset()\n\tcrypt.Write(stage1)\n\thash := crypt.Sum(nil)\n\n\t// outer Hash\n\tcrypt.Reset()\n\tcrypt.Write(scramble)\n\tcrypt.Write(hash)\n\tscramble = crypt.Sum(nil)\n\n\t// token = scrambleHash XOR stage1Hash\n\tfor i := range scramble {\n\t\tscramble[i] ^= stage1[i]\n\t}\n\treturn scramble\n}\n\n// Encrypt password using pre 4.1 (old password) method\n// https://github.com/atcurtis/mariadb/blob/master/mysys/my_rnd.c\ntype myRnd struct {\n\tseed1, seed2 uint32\n}\n\nconst myRndMaxVal = 0x3FFFFFFF\n\n// Pseudo random number generator\nfunc newMyRnd(seed1, seed2 uint32) *myRnd {\n\treturn &myRnd{\n\t\tseed1: seed1 % myRndMaxVal,\n\t\tseed2: seed2 % myRndMaxVal,\n\t}\n}\n\n// Tested to be equivalent to MariaDB's floating point variant\n// http://play.golang.org/p/QHvhd4qved\n// http://play.golang.org/p/RG0q4ElWDx\nfunc (r *myRnd) NextByte() byte {\n\tr.seed1 = (r.seed1*3 + r.seed2) % myRndMaxVal\n\tr.seed2 = (r.seed1 + r.seed2 + 33) % myRndMaxVal\n\n\treturn byte(uint64(r.seed1) * 31 / myRndMaxVal)\n}\n\n// Generate binary hash from byte string using insecure pre 4.1 method\nfunc pwHash(password []byte) (result [2]uint32) {\n\tvar add uint32 = 7\n\tvar tmp uint32\n\n\tresult[0] = 1345345333\n\tresult[1] = 0x12345671\n\n\tfor _, c := range password {\n\t\t// skip spaces and tabs in password\n\t\tif c == ' ' || c == '\\t' {\n\t\t\tcontinue\n\t\t}\n\n\t\ttmp = uint32(c)\n\t\tresult[0] ^= (((result[0] & 63) + add) * tmp) + (result[0] << 8)\n\t\tresult[1] += (result[1] << 8) ^ result[0]\n\t\tadd += tmp\n\t}\n\n\t// Remove sign bit (1<<31)-1)\n\tresult[0] &= 0x7FFFFFFF\n\tresult[1] &= 0x7FFFFFFF\n\n\treturn\n}\n\n// Encrypt password using insecure pre 4.1 method\nfunc scrambleOldPassword(scramble, password []byte) []byte {\n\tif len(password) == 0 {\n\t\treturn nil\n\t}\n\n\tscramble = scramble[:8]\n\n\thashPw := pwHash(password)\n\thashSc := pwHash(scramble)\n\n\tr := newMyRnd(hashPw[0]^hashSc[0], hashPw[1]^hashSc[1])\n\n\tvar out [8]byte\n\tfor i := range out {\n\t\tout[i] = r.NextByte() + 64\n\t}\n\n\tmask := r.NextByte()\n\tfor i := range out {\n\t\tout[i] ^= mask\n\t}\n\n\treturn out[:]\n}\n\n/******************************************************************************\n*                           Time related utils                                *\n******************************************************************************/\n\n// NullTime represents a time.Time that may be NULL.\n// NullTime implements the Scanner interface so\n// it can be used as a scan destination:\n//\n//  var nt NullTime\n//  err := db.QueryRow(\"SELECT time FROM foo WHERE id=?\", id).Scan(&nt)\n//  ...\n//  if nt.Valid {\n//     // use nt.Time\n//  } else {\n//     // NULL value\n//  }\n//\n// This NullTime implementation is not driver-specific\ntype NullTime struct {\n\tTime  time.Time\n\tValid bool // Valid is true if Time is not NULL\n}\n\n// Scan implements the Scanner interface.\n// The value type must be time.Time or string / []byte (formatted time-string),\n// otherwise Scan fails.\nfunc (nt *NullTime) Scan(value interface{}) (err error) {\n\tif value == nil {\n\t\tnt.Time, nt.Valid = time.Time{}, false\n\t\treturn\n\t}\n\n\tswitch v := value.(type) {\n\tcase time.Time:\n\t\tnt.Time, nt.Valid = v, true\n\t\treturn\n\tcase []byte:\n\t\tnt.Time, err = parseDateTime(string(v), time.UTC)\n\t\tnt.Valid = (err == nil)\n\t\treturn\n\tcase string:\n\t\tnt.Time, err = parseDateTime(v, time.UTC)\n\t\tnt.Valid = (err == nil)\n\t\treturn\n\t}\n\n\tnt.Valid = false\n\treturn fmt.Errorf(\"Can't convert %T to time.Time\", value)\n}\n\n// Value implements the driver Valuer interface.\nfunc (nt NullTime) Value() (driver.Value, error) {\n\tif !nt.Valid {\n\t\treturn nil, nil\n\t}\n\treturn nt.Time, nil\n}\n\nfunc parseDateTime(str string, loc *time.Location) (t time.Time, err error) {\n\tbase := \"0000-00-00 00:00:00.0000000\"\n\tswitch len(str) {\n\tcase 10, 19, 21, 22, 23, 24, 25, 26: // up to \"YYYY-MM-DD HH:MM:SS.MMMMMM\"\n\t\tif str == base[:len(str)] {\n\t\t\treturn\n\t\t}\n\t\tt, err = time.Parse(timeFormat[:len(str)], str)\n\tdefault:\n\t\terr = fmt.Errorf(\"invalid time string: %s\", str)\n\t\treturn\n\t}\n\n\t// Adjust location\n\tif err == nil && loc != time.UTC {\n\t\ty, mo, d := t.Date()\n\t\th, mi, s := t.Clock()\n\t\tt, err = time.Date(y, mo, d, h, mi, s, t.Nanosecond(), loc), nil\n\t}\n\n\treturn\n}\n\nfunc parseBinaryDateTime(num uint64, data []byte, loc *time.Location) (driver.Value, error) {\n\tswitch num {\n\tcase 0:\n\t\treturn time.Time{}, nil\n\tcase 4:\n\t\treturn time.Date(\n\t\t\tint(binary.LittleEndian.Uint16(data[:2])), // year\n\t\t\ttime.Month(data[2]),                       // month\n\t\t\tint(data[3]),                              // day\n\t\t\t0, 0, 0, 0,\n\t\t\tloc,\n\t\t), nil\n\tcase 7:\n\t\treturn time.Date(\n\t\t\tint(binary.LittleEndian.Uint16(data[:2])), // year\n\t\t\ttime.Month(data[2]),                       // month\n\t\t\tint(data[3]),                              // day\n\t\t\tint(data[4]),                              // hour\n\t\t\tint(data[5]),                              // minutes\n\t\t\tint(data[6]),                              // seconds\n\t\t\t0,\n\t\t\tloc,\n\t\t), nil\n\tcase 11:\n\t\treturn time.Date(\n\t\t\tint(binary.LittleEndian.Uint16(data[:2])), // year\n\t\t\ttime.Month(data[2]),                       // month\n\t\t\tint(data[3]),                              // day\n\t\t\tint(data[4]),                              // hour\n\t\t\tint(data[5]),                              // minutes\n\t\t\tint(data[6]),                              // seconds\n\t\t\tint(binary.LittleEndian.Uint32(data[7:11]))*1000, // nanoseconds\n\t\t\tloc,\n\t\t), nil\n\t}\n\treturn nil, fmt.Errorf(\"invalid DATETIME packet length %d\", num)\n}\n\n// zeroDateTime is used in formatBinaryDateTime to avoid an allocation\n// if the DATE or DATETIME has the zero value.\n// It must never be changed.\n// The current behavior depends on database/sql copying the result.\nvar zeroDateTime = []byte(\"0000-00-00 00:00:00.000000\")\n\nconst digits01 = \"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\"\nconst digits10 = \"0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999\"\n\nfunc formatBinaryDateTime(src []byte, length uint8, justTime bool) (driver.Value, error) {\n\t// length expects the deterministic length of the zero value,\n\t// negative time and 100+ hours are automatically added if needed\n\tif len(src) == 0 {\n\t\tif justTime {\n\t\t\treturn zeroDateTime[11 : 11+length], nil\n\t\t}\n\t\treturn zeroDateTime[:length], nil\n\t}\n\tvar dst []byte          // return value\n\tvar pt, p1, p2, p3 byte // current digit pair\n\tvar zOffs byte          // offset of value in zeroDateTime\n\tif justTime {\n\t\tswitch length {\n\t\tcase\n\t\t\t8,                      // time (can be up to 10 when negative and 100+ hours)\n\t\t\t10, 11, 12, 13, 14, 15: // time with fractional seconds\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"illegal TIME length %d\", length)\n\t\t}\n\t\tswitch len(src) {\n\t\tcase 8, 12:\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"invalid TIME packet length %d\", len(src))\n\t\t}\n\t\t// +2 to enable negative time and 100+ hours\n\t\tdst = make([]byte, 0, length+2)\n\t\tif src[0] == 1 {\n\t\t\tdst = append(dst, '-')\n\t\t}\n\t\tif src[1] != 0 {\n\t\t\thour := uint16(src[1])*24 + uint16(src[5])\n\t\t\tpt = byte(hour / 100)\n\t\t\tp1 = byte(hour - 100*uint16(pt))\n\t\t\tdst = append(dst, digits01[pt])\n\t\t} else {\n\t\t\tp1 = src[5]\n\t\t}\n\t\tzOffs = 11\n\t\tsrc = src[6:]\n\t} else {\n\t\tswitch length {\n\t\tcase 10, 19, 21, 22, 23, 24, 25, 26:\n\t\tdefault:\n\t\t\tt := \"DATE\"\n\t\t\tif length > 10 {\n\t\t\t\tt += \"TIME\"\n\t\t\t}\n\t\t\treturn nil, fmt.Errorf(\"illegal %s length %d\", t, length)\n\t\t}\n\t\tswitch len(src) {\n\t\tcase 4, 7, 11:\n\t\tdefault:\n\t\t\tt := \"DATE\"\n\t\t\tif length > 10 {\n\t\t\t\tt += \"TIME\"\n\t\t\t}\n\t\t\treturn nil, fmt.Errorf(\"illegal %s packet length %d\", t, len(src))\n\t\t}\n\t\tdst = make([]byte, 0, length)\n\t\t// start with the date\n\t\tyear := binary.LittleEndian.Uint16(src[:2])\n\t\tpt = byte(year / 100)\n\t\tp1 = byte(year - 100*uint16(pt))\n\t\tp2, p3 = src[2], src[3]\n\t\tdst = append(dst,\n\t\t\tdigits10[pt], digits01[pt],\n\t\t\tdigits10[p1], digits01[p1], '-',\n\t\t\tdigits10[p2], digits01[p2], '-',\n\t\t\tdigits10[p3], digits01[p3],\n\t\t)\n\t\tif length == 10 {\n\t\t\treturn dst, nil\n\t\t}\n\t\tif len(src) == 4 {\n\t\t\treturn append(dst, zeroDateTime[10:length]...), nil\n\t\t}\n\t\tdst = append(dst, ' ')\n\t\tp1 = src[4] // hour\n\t\tsrc = src[5:]\n\t}\n\t// p1 is 2-digit hour, src is after hour\n\tp2, p3 = src[0], src[1]\n\tdst = append(dst,\n\t\tdigits10[p1], digits01[p1], ':',\n\t\tdigits10[p2], digits01[p2], ':',\n\t\tdigits10[p3], digits01[p3],\n\t)\n\tif length <= byte(len(dst)) {\n\t\treturn dst, nil\n\t}\n\tsrc = src[2:]\n\tif len(src) == 0 {\n\t\treturn append(dst, zeroDateTime[19:zOffs+length]...), nil\n\t}\n\tmicrosecs := binary.LittleEndian.Uint32(src[:4])\n\tp1 = byte(microsecs / 10000)\n\tmicrosecs -= 10000 * uint32(p1)\n\tp2 = byte(microsecs / 100)\n\tmicrosecs -= 100 * uint32(p2)\n\tp3 = byte(microsecs)\n\tswitch decimals := zOffs + length - 20; decimals {\n\tdefault:\n\t\treturn append(dst, '.',\n\t\t\tdigits10[p1], digits01[p1],\n\t\t\tdigits10[p2], digits01[p2],\n\t\t\tdigits10[p3], digits01[p3],\n\t\t), nil\n\tcase 1:\n\t\treturn append(dst, '.',\n\t\t\tdigits10[p1],\n\t\t), nil\n\tcase 2:\n\t\treturn append(dst, '.',\n\t\t\tdigits10[p1], digits01[p1],\n\t\t), nil\n\tcase 3:\n\t\treturn append(dst, '.',\n\t\t\tdigits10[p1], digits01[p1],\n\t\t\tdigits10[p2],\n\t\t), nil\n\tcase 4:\n\t\treturn append(dst, '.',\n\t\t\tdigits10[p1], digits01[p1],\n\t\t\tdigits10[p2], digits01[p2],\n\t\t), nil\n\tcase 5:\n\t\treturn append(dst, '.',\n\t\t\tdigits10[p1], digits01[p1],\n\t\t\tdigits10[p2], digits01[p2],\n\t\t\tdigits10[p3],\n\t\t), nil\n\t}\n}\n\n/******************************************************************************\n*                       Convert from and to bytes                             *\n******************************************************************************/\n\nfunc uint64ToBytes(n uint64) []byte {\n\treturn []byte{\n\t\tbyte(n),\n\t\tbyte(n >> 8),\n\t\tbyte(n >> 16),\n\t\tbyte(n >> 24),\n\t\tbyte(n >> 32),\n\t\tbyte(n >> 40),\n\t\tbyte(n >> 48),\n\t\tbyte(n >> 56),\n\t}\n}\n\nfunc uint64ToString(n uint64) []byte {\n\tvar a [20]byte\n\ti := 20\n\n\t// U+0030 = 0\n\t// ...\n\t// U+0039 = 9\n\n\tvar q uint64\n\tfor n >= 10 {\n\t\ti--\n\t\tq = n / 10\n\t\ta[i] = uint8(n-q*10) + 0x30\n\t\tn = q\n\t}\n\n\ti--\n\ta[i] = uint8(n) + 0x30\n\n\treturn a[i:]\n}\n\n// treats string value as unsigned integer representation\nfunc stringToInt(b []byte) int {\n\tval := 0\n\tfor i := range b {\n\t\tval *= 10\n\t\tval += int(b[i] - 0x30)\n\t}\n\treturn val\n}\n\n// returns the string read as a bytes slice, wheter the value is NULL,\n// the number of bytes read and an error, in case the string is longer than\n// the input slice\nfunc readLengthEncodedString(b []byte) ([]byte, bool, int, error) {\n\t// Get length\n\tnum, isNull, n := readLengthEncodedInteger(b)\n\tif num < 1 {\n\t\treturn b[n:n], isNull, n, nil\n\t}\n\n\tn += int(num)\n\n\t// Check data length\n\tif len(b) >= n {\n\t\treturn b[n-int(num) : n : n], false, n, nil\n\t}\n\treturn nil, false, n, io.EOF\n}\n\n// returns the number of bytes skipped and an error, in case the string is\n// longer than the input slice\nfunc skipLengthEncodedString(b []byte) (int, error) {\n\t// Get length\n\tnum, _, n := readLengthEncodedInteger(b)\n\tif num < 1 {\n\t\treturn n, nil\n\t}\n\n\tn += int(num)\n\n\t// Check data length\n\tif len(b) >= n {\n\t\treturn n, nil\n\t}\n\treturn n, io.EOF\n}\n\n// returns the number read, whether the value is NULL and the number of bytes read\nfunc readLengthEncodedInteger(b []byte) (uint64, bool, int) {\n\t// See issue #349\n\tif len(b) == 0 {\n\t\treturn 0, true, 1\n\t}\n\n\tswitch b[0] {\n\t// 251: NULL\n\tcase 0xfb:\n\t\treturn 0, true, 1\n\n\t// 252: value of following 2\n\tcase 0xfc:\n\t\treturn uint64(b[1]) | uint64(b[2])<<8, false, 3\n\n\t// 253: value of following 3\n\tcase 0xfd:\n\t\treturn uint64(b[1]) | uint64(b[2])<<8 | uint64(b[3])<<16, false, 4\n\n\t// 254: value of following 8\n\tcase 0xfe:\n\t\treturn uint64(b[1]) | uint64(b[2])<<8 | uint64(b[3])<<16 |\n\t\t\t\tuint64(b[4])<<24 | uint64(b[5])<<32 | uint64(b[6])<<40 |\n\t\t\t\tuint64(b[7])<<48 | uint64(b[8])<<56,\n\t\t\tfalse, 9\n\t}\n\n\t// 0-250: value of first byte\n\treturn uint64(b[0]), false, 1\n}\n\n// encodes a uint64 value and appends it to the given bytes slice\nfunc appendLengthEncodedInteger(b []byte, n uint64) []byte {\n\tswitch {\n\tcase n <= 250:\n\t\treturn append(b, byte(n))\n\n\tcase n <= 0xffff:\n\t\treturn append(b, 0xfc, byte(n), byte(n>>8))\n\n\tcase n <= 0xffffff:\n\t\treturn append(b, 0xfd, byte(n), byte(n>>8), byte(n>>16))\n\t}\n\treturn append(b, 0xfe, byte(n), byte(n>>8), byte(n>>16), byte(n>>24),\n\t\tbyte(n>>32), byte(n>>40), byte(n>>48), byte(n>>56))\n}\n\n// reserveBuffer checks cap(buf) and expand buffer to len(buf) + appendSize.\n// If cap(buf) is not enough, reallocate new buffer.\nfunc reserveBuffer(buf []byte, appendSize int) []byte {\n\tnewSize := len(buf) + appendSize\n\tif cap(buf) < newSize {\n\t\t// Grow buffer exponentially\n\t\tnewBuf := make([]byte, len(buf)*2+appendSize)\n\t\tcopy(newBuf, buf)\n\t\tbuf = newBuf\n\t}\n\treturn buf[:newSize]\n}\n\n// escapeBytesBackslash escapes []byte with backslashes (\\)\n// This escapes the contents of a string (provided as []byte) by adding backslashes before special\n// characters, and turning others into specific escape sequences, such as\n// turning newlines into \\n and null bytes into \\0.\n// https://github.com/mysql/mysql-server/blob/mysql-5.7.5/mysys/charset.c#L823-L932\nfunc escapeBytesBackslash(buf, v []byte) []byte {\n\tpos := len(buf)\n\tbuf = reserveBuffer(buf, len(v)*2)\n\n\tfor _, c := range v {\n\t\tswitch c {\n\t\tcase '\\x00':\n\t\t\tbuf[pos] = '\\\\'\n\t\t\tbuf[pos+1] = '0'\n\t\t\tpos += 2\n\t\tcase '\\n':\n\t\t\tbuf[pos] = '\\\\'\n\t\t\tbuf[pos+1] = 'n'\n\t\t\tpos += 2\n\t\tcase '\\r':\n\t\t\tbuf[pos] = '\\\\'\n\t\t\tbuf[pos+1] = 'r'\n\t\t\tpos += 2\n\t\tcase '\\x1a':\n\t\t\tbuf[pos] = '\\\\'\n\t\t\tbuf[pos+1] = 'Z'\n\t\t\tpos += 2\n\t\tcase '\\'':\n\t\t\tbuf[pos] = '\\\\'\n\t\t\tbuf[pos+1] = '\\''\n\t\t\tpos += 2\n\t\tcase '\"':\n\t\t\tbuf[pos] = '\\\\'\n\t\t\tbuf[pos+1] = '\"'\n\t\t\tpos += 2\n\t\tcase '\\\\':\n\t\t\tbuf[pos] = '\\\\'\n\t\t\tbuf[pos+1] = '\\\\'\n\t\t\tpos += 2\n\t\tdefault:\n\t\t\tbuf[pos] = c\n\t\t\tpos++\n\t\t}\n\t}\n\n\treturn buf[:pos]\n}\n\n// escapeStringBackslash is similar to escapeBytesBackslash but for string.\nfunc escapeStringBackslash(buf []byte, v string) []byte {\n\tpos := len(buf)\n\tbuf = reserveBuffer(buf, len(v)*2)\n\n\tfor i := 0; i < len(v); i++ {\n\t\tc := v[i]\n\t\tswitch c {\n\t\tcase '\\x00':\n\t\t\tbuf[pos] = '\\\\'\n\t\t\tbuf[pos+1] = '0'\n\t\t\tpos += 2\n\t\tcase '\\n':\n\t\t\tbuf[pos] = '\\\\'\n\t\t\tbuf[pos+1] = 'n'\n\t\t\tpos += 2\n\t\tcase '\\r':\n\t\t\tbuf[pos] = '\\\\'\n\t\t\tbuf[pos+1] = 'r'\n\t\t\tpos += 2\n\t\tcase '\\x1a':\n\t\t\tbuf[pos] = '\\\\'\n\t\t\tbuf[pos+1] = 'Z'\n\t\t\tpos += 2\n\t\tcase '\\'':\n\t\t\tbuf[pos] = '\\\\'\n\t\t\tbuf[pos+1] = '\\''\n\t\t\tpos += 2\n\t\tcase '\"':\n\t\t\tbuf[pos] = '\\\\'\n\t\t\tbuf[pos+1] = '\"'\n\t\t\tpos += 2\n\t\tcase '\\\\':\n\t\t\tbuf[pos] = '\\\\'\n\t\t\tbuf[pos+1] = '\\\\'\n\t\t\tpos += 2\n\t\tdefault:\n\t\t\tbuf[pos] = c\n\t\t\tpos++\n\t\t}\n\t}\n\n\treturn buf[:pos]\n}\n\n// escapeBytesQuotes escapes apostrophes in []byte by doubling them up.\n// This escapes the contents of a string by doubling up any apostrophes that\n// it contains. This is used when the NO_BACKSLASH_ESCAPES SQL_MODE is in\n// effect on the server.\n// https://github.com/mysql/mysql-server/blob/mysql-5.7.5/mysys/charset.c#L963-L1038\nfunc escapeBytesQuotes(buf, v []byte) []byte {\n\tpos := len(buf)\n\tbuf = reserveBuffer(buf, len(v)*2)\n\n\tfor _, c := range v {\n\t\tif c == '\\'' {\n\t\t\tbuf[pos] = '\\''\n\t\t\tbuf[pos+1] = '\\''\n\t\t\tpos += 2\n\t\t} else {\n\t\t\tbuf[pos] = c\n\t\t\tpos++\n\t\t}\n\t}\n\n\treturn buf[:pos]\n}\n\n// escapeStringQuotes is similar to escapeBytesQuotes but for string.\nfunc escapeStringQuotes(buf []byte, v string) []byte {\n\tpos := len(buf)\n\tbuf = reserveBuffer(buf, len(v)*2)\n\n\tfor i := 0; i < len(v); i++ {\n\t\tc := v[i]\n\t\tif c == '\\'' {\n\t\t\tbuf[pos] = '\\''\n\t\t\tbuf[pos+1] = '\\''\n\t\t\tpos += 2\n\t\t} else {\n\t\t\tbuf[pos] = c\n\t\t\tpos++\n\t\t}\n\t}\n\n\treturn buf[:pos]\n}\n\n/******************************************************************************\n*                               Sync utils                                    *\n******************************************************************************/\n\n// noCopy may be embedded into structs which must not be copied\n// after the first use.\n//\n// See https://github.com/golang/go/issues/8005#issuecomment-190753527\n// for details.\ntype noCopy struct{}\n\n// Lock is a no-op used by -copylocks checker from `go vet`.\nfunc (*noCopy) Lock() {}\n\n// atomicBool is a wrapper around uint32 for usage as a boolean value with\n// atomic access.\ntype atomicBool struct {\n\t_noCopy noCopy\n\tvalue   uint32\n}\n\n// IsSet returns wether the current boolean value is true\nfunc (ab *atomicBool) IsSet() bool {\n\treturn atomic.LoadUint32(&ab.value) > 0\n}\n\n// Set sets the value of the bool regardless of the previous value\nfunc (ab *atomicBool) Set(value bool) {\n\tif value {\n\t\tatomic.StoreUint32(&ab.value, 1)\n\t} else {\n\t\tatomic.StoreUint32(&ab.value, 0)\n\t}\n}\n\n// TrySet sets the value of the bool and returns wether the value changed\nfunc (ab *atomicBool) TrySet(value bool) bool {\n\tif value {\n\t\treturn atomic.SwapUint32(&ab.value, 1) == 0\n\t}\n\treturn atomic.SwapUint32(&ab.value, 0) > 0\n}\n\n// atomicError is a wrapper for atomically accessed error values\ntype atomicError struct {\n\t_noCopy noCopy\n\tvalue   atomic.Value\n}\n\n// Set sets the error value regardless of the previous value.\n// The value must not be nil\nfunc (ae *atomicError) Set(value error) {\n\tae.value.Store(value)\n}\n\n// Value returns the current error value\nfunc (ae *atomicError) Value() error {\n\tif v := ae.value.Load(); v != nil {\n\t\t// this will panic if the value doesn't implement the error interface\n\t\treturn v.(error)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/go-sql-driver/mysql/utils_go17.go",
    "content": "// Go MySQL Driver - A MySQL-Driver for Go's database/sql package\n//\n// Copyright 2017 The Go-MySQL-Driver Authors. All rights reserved.\n//\n// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this file,\n// You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// +build go1.7\n// +build !go1.8\n\npackage mysql\n\nimport \"crypto/tls\"\n\nfunc cloneTLSConfig(c *tls.Config) *tls.Config {\n\treturn &tls.Config{\n\t\tRand:                        c.Rand,\n\t\tTime:                        c.Time,\n\t\tCertificates:                c.Certificates,\n\t\tNameToCertificate:           c.NameToCertificate,\n\t\tGetCertificate:              c.GetCertificate,\n\t\tRootCAs:                     c.RootCAs,\n\t\tNextProtos:                  c.NextProtos,\n\t\tServerName:                  c.ServerName,\n\t\tClientAuth:                  c.ClientAuth,\n\t\tClientCAs:                   c.ClientCAs,\n\t\tInsecureSkipVerify:          c.InsecureSkipVerify,\n\t\tCipherSuites:                c.CipherSuites,\n\t\tPreferServerCipherSuites:    c.PreferServerCipherSuites,\n\t\tSessionTicketsDisabled:      c.SessionTicketsDisabled,\n\t\tSessionTicketKey:            c.SessionTicketKey,\n\t\tClientSessionCache:          c.ClientSessionCache,\n\t\tMinVersion:                  c.MinVersion,\n\t\tMaxVersion:                  c.MaxVersion,\n\t\tCurvePreferences:            c.CurvePreferences,\n\t\tDynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled,\n\t\tRenegotiation:               c.Renegotiation,\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/go-sql-driver/mysql/utils_go18.go",
    "content": "// Go MySQL Driver - A MySQL-Driver for Go's database/sql package\n//\n// Copyright 2017 The Go-MySQL-Driver Authors. All rights reserved.\n//\n// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this file,\n// You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// +build go1.8\n\npackage mysql\n\nimport (\n\t\"crypto/tls\"\n\t\"database/sql\"\n\t\"database/sql/driver\"\n\t\"errors\"\n\t\"fmt\"\n)\n\nfunc cloneTLSConfig(c *tls.Config) *tls.Config {\n\treturn c.Clone()\n}\n\nfunc namedValueToValue(named []driver.NamedValue) ([]driver.Value, error) {\n\tdargs := make([]driver.Value, len(named))\n\tfor n, param := range named {\n\t\tif len(param.Name) > 0 {\n\t\t\t// TODO: support the use of Named Parameters #561\n\t\t\treturn nil, errors.New(\"mysql: driver does not support the use of Named Parameters\")\n\t\t}\n\t\tdargs[n] = param.Value\n\t}\n\treturn dargs, nil\n}\n\nfunc mapIsolationLevel(level driver.IsolationLevel) (string, error) {\n\tswitch sql.IsolationLevel(level) {\n\tcase sql.LevelRepeatableRead:\n\t\treturn \"REPEATABLE READ\", nil\n\tcase sql.LevelReadCommitted:\n\t\treturn \"READ COMMITTED\", nil\n\tcase sql.LevelReadUncommitted:\n\t\treturn \"READ UNCOMMITTED\", nil\n\tcase sql.LevelSerializable:\n\t\treturn \"SERIALIZABLE\", nil\n\tdefault:\n\t\treturn \"\", fmt.Errorf(\"mysql: unsupported isolation level: %v\", level)\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/google/wire/AUTHORS",
    "content": "# This is the official list of Wire authors for copyright purposes.\n# This file is distinct from the CONTRIBUTORS files.\n# See the latter for an explanation.\n\n# Names should be added to this file as one of\n#     Organization's name\n#     Individual's name <submission email address>\n#     Individual's name <submission email address> <email2> <emailN>\n# See CONTRIBUTORS for the meaning of multiple email addresses.\n\n# Please keep the list sorted.\n\nGoogle LLC\nktr <ktr@syfm.me>\nOleg Kovalov <iamolegkovalov@gmail.com>\nYoichiro Shimizu <budougumi0617@gmail.com>\nZachary Romero <zacromero3@gmail.com>\n"
  },
  {
    "path": "vendor/github.com/google/wire/CODE_OF_CONDUCT.md",
    "content": "# Code of Conduct\n\nThis project is covered under the [Go Code of Conduct][]. In summary:\n\n-   Treat everyone with respect and kindness.\n-   Be thoughtful in how you communicate.\n-   Don’t be destructive or inflammatory.\n-   If you encounter an issue, please mail conduct@golang.org.\n\n[Go Code of Conduct]: https://golang.org/conduct\n"
  },
  {
    "path": "vendor/github.com/google/wire/CONTRIBUTING.md",
    "content": "# How to Contribute\n\nWe would love to accept your patches and contributions to this project. Here is\nhow you can help.\n\n## Filing issues\n\nFiling issues is an important way you can contribute to the Wire Project. We\nwant your feedback on things like bugs, desired API changes, or just anything\nthat isn't working for you.\n\n### Bugs\n\nIf your issue is a bug, open one\n[here](https://github.com/google/wire/issues/new). The easiest way to file an\nissue with all the right information is to run `go bug`. `go bug` will print out\na handy template of questions and system information that will help us get to\nthe root of the issue quicker.\n\n### Changes\n\nUnlike the core Go project, we do not have a formal proposal process for\nchanges. If you have a change you would like to see in Wire, please file an\nissue with the necessary details.\n\n### Triaging\n\nThe Go Cloud team triages issues at least every two weeks, but usually within\ntwo business days. Bugs or feature requests are either placed into a **Sprint**\nmilestone which means the issue is intended to be worked on. Issues that we\nwould like to address but do not have time for are placed into the [Unplanned][]\nmilestone.\n\n[Unplanned]: https://github.com/google/wire/milestone/1\n\n## Contributing Code\n\nWe love accepting contributions! If your change is minor, please feel free\nsubmit a [pull request](https://help.github.com/articles/about-pull-requests/).\nIf your change is larger, or adds a feature, please file an issue beforehand so\nthat we can discuss the change. You're welcome to file an implementation pull\nrequest immediately as well, although we generally lean towards discussing the\nchange and then reviewing the implementation separately.\n\n### Finding something to work on\n\nIf you want to write some code, but don't know where to start or what you might\nwant to do, take a look at our [Unplanned][] milestone. This is where you can\nfind issues we would like to address but can't currently find time for. See if\nany of the latest ones look interesting! If you need help before you can start\nwork, you can comment on the issue and we will try to help as best we can.\n\n### Contributor License Agreement\n\nContributions to this project can only be made by those who have signed Google's\nContributor License Agreement. You (or your employer) retain the copyright to\nyour contribution, this simply gives us permission to use and redistribute your\ncontributions as part of the project. Head over to\n<https://cla.developers.google.com/> to see your current agreements on file or\nto sign a new one.\n\nAs a personal contributor, you only need to sign the Google CLA once across all\nGoogle projects. If you've already signed the CLA, there is no need to do it\nagain. If you are submitting code on behalf of your employer, there's\n[a separate corporate CLA that your employer manages for you](https://opensource.google.com/docs/cla/#external-contributors).\n\n## Making a pull request\n\n*   Follow the normal\n    [pull request flow](https://help.github.com/articles/creating-a-pull-request/)\n*   Build your changes using Go 1.11 with Go modules enabled. Wire's continuous\n    integration uses Go modules in order to ensure\n    [reproducible builds](https://research.swtch.com/vgo-repro).\n*   Test your changes using `go test ./...`. Please add tests that show the\n    change does what it says it does, even if there wasn't a test in the first\n    place.\n*   Feel free to make as many commits as you want; we will squash them all into\n    a single commit before merging your change.\n*   Check the diffs, write a useful description (including something like\n    `Fixes #123` if it's fixing a bug) and send the PR out.\n*   [Travis CI](http://travis-ci.com) will run tests against the PR. This should\n    happen within 10 minutes or so. If a test fails, go back to the coding stage\n    and try to fix the test and push the same branch again. You won't need to\n    make a new pull request, the changes will be rolled directly into the PR you\n    already opened. Wait for Travis again. There is no need to assign a reviewer\n    to the PR, the project team will assign someone for review during the\n    standard [triage](#triaging) process.\n\n## Code review\n\nAll submissions, including submissions by project members, require review. It is\nalmost never the case that a pull request is accepted without some changes\nrequested, so please do not be offended!\n\nWhen you have finished making requested changes to your pull request, please\nmake a comment containing \"PTAL\" (Please Take Another Look) on your pull\nrequest. GitHub notifications can be noisy, and it is unfortunately easy for\nthings to be lost in the shuffle.\n\nOnce your PR is approved (hooray!) the reviewer will squash your commits into a\nsingle commit, and then merge the commit onto the Wire master branch. Thank you!\n\n## Github code review workflow conventions\n\n(For project members and frequent contributors.)\n\nAs a contributor:\n\n-   Try hard to make each Pull Request as small and focused as possible. In\n    particular, this means that if a reviewer asks you to do something that is\n    beyond the scope of the Pull Request, the best practice is to file another\n    issue and reference it from the Pull Request rather than just adding more\n    commits to the existing PR.\n-   Adding someone as a Reviewer means \"please feel free to look and comment\";\n    the review is optional. Choose as many Reviewers as you'd like.\n-   Adding someone as an Assignee means that the Pull Request should not be\n    submitted until they approve. If you choose multiple Assignees, wait until\n    all of them approve. It is fine to ask someone if they are OK with being\n    removed as an Assignee.\n    -   Note that if you don't select any assignees, ContributeBot will turn all\n        of your Reviewers into Assignees.\n-   Make as many commits as you want locally, but try not to push them to Github\n    until you've addressed comments; this allows the email notification about\n    the push to be a signal to reviewers that the PR is ready to be looked at\n    again.\n-   When there may be confusion about what should happen next for a PR, be\n    explicit; add a \"PTAL\" comment if it is ready for review again, or a \"Please\n    hold off on reviewing for now\" if you are still working on addressing\n    comments.\n-   \"Resolve\" comments that you are sure you've addressed; let your reviewers\n    resolve ones that you're not sure about.\n-   Do not use `git push --force`; this can cause comments from your reviewers\n    that are associated with a specific commit to be lost. This implies that\n    once you've sent a Pull Request, you should use `git merge` instead of `git\n    rebase` to incorporate commits from the master branch.\n\nAs a reviewer:\n\n-   Be timely in your review process, especially if you are an Assignee.\n-   Try to use `Start a Review` instead of single comments, to reduce email\n    spam.\n-   \"Resolve\" your own comments if they have been addressed.\n-   If you want your review to be blocking, and are not currently an Assignee,\n    add yourself as an Assignee.\n\nWhen squashing-and-merging:\n\n-   Ensure that **all** of the Assignees have approved.\n-   Do a final review of the one-line PR summary, ensuring that it accurately\n    describes the change.\n-   Delete the automatically added commit lines; these are generally not\n    interesting and make commit history harder to read.\n"
  },
  {
    "path": "vendor/github.com/google/wire/CONTRIBUTORS",
    "content": "# This is the official list of people who can contribute\n# (and typically have contributed) code to the Wire repository.\n# The AUTHORS file lists the copyright holders; this file\n# lists people.  For example, Google employees are listed here\n# but not in AUTHORS, because Google holds the copyright.\n#\n# Names should be added to this file only after verifying that\n# the individual or the individual's organization has agreed to\n# the appropriate Contributor License Agreement, found here:\n#\n#     http://code.google.com/legal/individual-cla-v1.0.html\n#     http://code.google.com/legal/corporate-cla-v1.0.html\n#\n# The agreement for individuals can be filled out on the web.\n#\n# When adding J Random Contributor's name to this file,\n# either J's name or J's organization's name should be\n# added to the AUTHORS file, depending on whether the\n# individual or corporate CLA was used.\n\n# Names should be added to this file like so:\n#     Individual's name <submission email address>\n#     Individual's name <submission email address> <email2> <emailN>\n#\n# An entry with multiple email addresses specifies that the\n# first address should be used in the submit logs and\n# that the other addresses should be recognized as the\n# same person when interacting with Git.\n\n# Please keep the list sorted.\n\nChris Lewis <cflewis@google.com> <cflewis@golang.org> <c@chris.to>\nChristina Austin <4240737+clausti@users.noreply.github.com>\nEno Compton <enocom@google.com>\nIssac Trotts <issactrotts@google.com> <issac.trotts@gmail.com>\nktr <ktr@syfm.me>\nOleg Kovalov <iamolegkovalov@gmail.com>\nRobert van Gent <rvangent@google.com> <vangent@gmail.com>\nRoss Light <light@google.com> <ross@zombiezen.com>\nTuo Shan <shantuo@google.com> <sturbo89@gmail.com>\nYoichiro Shimizu <budougumi0617@gmail.com>\nZachary Romero <zacromero3@gmail.com>\n"
  },
  {
    "path": "vendor/github.com/google/wire/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "vendor/github.com/google/wire/README.md",
    "content": "# Wire: Automated Initialization in Go\n\n[![Build Status](https://travis-ci.com/google/wire.svg?branch=master)][travis]\n[![godoc](https://godoc.org/github.com/google/wire?status.svg)][godoc]\n[![Coverage Status](https://coveralls.io/repos/github/google/wire/badge.svg?branch=master)](https://coveralls.io/github/google/wire?branch=master)\n\nWire is a code generation tool that automates connecting components using\n[dependency injection][]. Dependencies between components are represented in\nWire as function parameters, encouraging explicit initialization instead of\nglobal variables. Because Wire operates without runtime state or reflection,\ncode written to be used with Wire is useful even for hand-written\ninitialization.\n\nFor an overview, see the [introductory blog post][].\n\n[dependency injection]: https://en.wikipedia.org/wiki/Dependency_injection\n[introductory blog post]: https://blog.golang.org/wire\n[godoc]: https://godoc.org/github.com/google/wire\n[travis]: https://travis-ci.com/google/wire\n\n## Installing\n\nInstall Wire by running:\n\n```shell\ngo get github.com/google/wire/cmd/wire\n```\n\nand ensuring that `$GOPATH/bin` is added to your `$PATH`.\n\n## Documentation\n\n- [Tutorial][]\n- [User Guide][]\n- [Best Practices][]\n- [FAQ][]\n\n[Tutorial]: ./_tutorial/README.md\n[Best Practices]: ./docs/best-practices.md\n[FAQ]: ./docs/faq.md\n[User Guide]: ./docs/guide.md\n\n## Project status\n\n**This project is in alpha and is not yet suitable for production.**\n\nWhile in alpha, the API is subject to breaking changes.\n\n## Community\n\nYou can contact us on the [go-cloud mailing list][].\n\nThis project is covered by the Go [Code of Conduct][].\n\n[Code of Conduct]: ./CODE_OF_CONDUCT.md\n[go-cloud mailing list]: https://groups.google.com/forum/#!forum/go-cloud\n"
  },
  {
    "path": "vendor/github.com/google/wire/go.mod",
    "content": "module github.com/google/wire\n\nrequire (\n\tgithub.com/google/go-cmp v0.2.0\n\tgithub.com/pmezard/go-difflib v1.0.0\n\tgolang.org/x/tools v0.0.0-20181017214349-06f26fdaaa28\n)\n"
  },
  {
    "path": "vendor/github.com/google/wire/go.sum",
    "content": "github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=\ngithub.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngolang.org/x/tools v0.0.0-20181017214349-06f26fdaaa28 h1:vnbqcYKfOxPnXXUlBo7t+R4pVIh0wInyOSNxih1S9Dc=\ngolang.org/x/tools v0.0.0-20181017214349-06f26fdaaa28/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\n"
  },
  {
    "path": "vendor/github.com/google/wire/wire.go",
    "content": "// Copyright 2018 The Wire Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     https://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Package wire contains directives for Wire code generation.\n// For an overview of working with Wire, see the user guide at\n// https://github.com/google/wire/blob/master/docs/guide.md\n//\n// The directives in this package are used as input to the Wire code generation\n// tool. The entry point of Wire's analysis are injector functions: function\n// templates denoted by only containing a call to Build. The arguments to Build\n// describes a set of providers and the Wire code generation tool builds a\n// directed acylic graph of the providers' output types. The generated code will\n// fill in the function template by using the providers from the provider set to\n// instantiate any needed types.\npackage wire\n\n// ProviderSet is a marker type that collects a group of providers.\ntype ProviderSet struct{}\n\n// NewSet creates a new provider set that includes the providers in its\n// arguments. Each argument is a function value, a struct (zero) value, a\n// provider set, a call to Bind, a call to Value, or a call to InterfaceValue.\n//\n// Passing a function value to NewSet declares that the function's first\n// return value type will be provided by calling the function. The arguments\n// to the function will come from the providers for their types. As such, all\n// the parameters must be of non-identical types. The function may optionally\n// return an error as its last return value and a cleanup function as the\n// second return value. A cleanup function must be of type func() and is\n// guaranteed to be called before the cleanup function of any of the\n// provider's inputs. If any provider returns an error, the injector function\n// will call all the appropriate cleanup functions and return the error from\n// the injector function.\n//\n// Passing a struct value of type S to NewSet declares that both S and *S will\n// be provided by creating a new value of the appropriate type by filling in\n// each field of S using the provider of the field's type.\n//\n// Passing a ProviderSet to NewSet is the same as if the set's contents\n// were passed as arguments to NewSet directly.\n//\n// The behavior of passing the result of a call to other functions in this\n// package are described in their respective doc comments.\nfunc NewSet(...interface{}) ProviderSet {\n\treturn ProviderSet{}\n}\n\n// Build is placed in the body of an injector function template to declare the\n// providers to use. The Wire code generation tool will fill in an\n// implementation of the function. The arguments to Build are interpreted the\n// same as NewSet: they determine the provider set presented to Wire's\n// dependency graph. Build returns an error message that can be sent to a call\n// to panic().\n//\n// The parameters of the injector function are used as inputs in the dependency\n// graph.\n//\n// Similar to provider functions passed into NewSet, the first return value is\n// the output of the injector function, the optional second return value is a\n// cleanup function, and the optional last return value is an error. If any of\n// the provider functions in the injector function's provider set return errors\n// or cleanup functions, the corresponding return value must be present in the\n// injector function template.\n//\n// Examples:\n//\n//\tfunc injector(ctx context.Context) (*sql.DB, error) {\n//\t\twire.Build(otherpkg.FooSet, myProviderFunc)\n//\t\treturn nil, nil\n//\t}\n//\n//\tfunc injector(ctx context.Context) (*sql.DB, error) {\n//\t\tpanic(wire.Build(otherpkg.FooSet, myProviderFunc))\n//\t}\nfunc Build(...interface{}) string {\n\treturn \"implementation not generated, run wire\"\n}\n\n// A Binding maps an interface to a concrete type.\ntype Binding struct{}\n\n// Bind declares that a concrete type should be used to satisfy a\n// dependency on the type of iface, which must be a pointer to an\n// interface type.\n//\n// Example:\n//\n//\ttype Fooer interface {\n//\t\tFoo()\n//\t}\n//\n//\ttype MyFoo struct{}\n//\n//\tfunc (MyFoo) Foo() {}\n//\n//\tvar MySet = wire.NewSet(\n//\t\tMyFoo{},\n//\t\twire.Bind(new(Fooer), new(MyFoo)))\nfunc Bind(iface, to interface{}) Binding {\n\treturn Binding{}\n}\n\n// A ProvidedValue is an expression that is copied to the generated injector.\ntype ProvidedValue struct{}\n\n// Value binds an expression to provide the type of the expression.\n// The expression may not be an interface value; use InterfaceValue for that.\n//\n// Example:\n//\n//\tvar MySet = wire.NewSet(wire.Value([]string(nil)))\nfunc Value(interface{}) ProvidedValue {\n\treturn ProvidedValue{}\n}\n\n// InterfaceValue binds an expression to provide a specific interface type.\n//\n// Example:\n//\n//\tvar MySet = wire.NewSet(wire.InterfaceValue(new(io.Reader), os.Stdin))\nfunc InterfaceValue(typ interface{}, x interface{}) ProvidedValue {\n\treturn ProvidedValue{}\n}\n"
  },
  {
    "path": "vendor/github.com/gorilla/context/LICENSE",
    "content": "Copyright (c) 2012 Rodrigo Moraes. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n\t * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n\t * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n\t * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "vendor/github.com/gorilla/context/README.md",
    "content": "context\n=======\n[![Build Status](https://travis-ci.org/gorilla/context.png?branch=master)](https://travis-ci.org/gorilla/context)\n\ngorilla/context is a general purpose registry for global request variables.\n\n> Note: gorilla/context, having been born well before `context.Context` existed, does not play well\n> with the shallow copying of the request that [`http.Request.WithContext`](https://golang.org/pkg/net/http/#Request.WithContext) (added to net/http Go 1.7 onwards) performs. You should either use *just* gorilla/context, or moving forward, the new `http.Request.Context()`.\n\nRead the full documentation here: http://www.gorillatoolkit.org/pkg/context\n"
  },
  {
    "path": "vendor/github.com/gorilla/context/context.go",
    "content": "// Copyright 2012 The Gorilla Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage context\n\nimport (\n\t\"net/http\"\n\t\"sync\"\n\t\"time\"\n)\n\nvar (\n\tmutex sync.RWMutex\n\tdata  = make(map[*http.Request]map[interface{}]interface{})\n\tdatat = make(map[*http.Request]int64)\n)\n\n// Set stores a value for a given key in a given request.\nfunc Set(r *http.Request, key, val interface{}) {\n\tmutex.Lock()\n\tif data[r] == nil {\n\t\tdata[r] = make(map[interface{}]interface{})\n\t\tdatat[r] = time.Now().Unix()\n\t}\n\tdata[r][key] = val\n\tmutex.Unlock()\n}\n\n// Get returns a value stored for a given key in a given request.\nfunc Get(r *http.Request, key interface{}) interface{} {\n\tmutex.RLock()\n\tif ctx := data[r]; ctx != nil {\n\t\tvalue := ctx[key]\n\t\tmutex.RUnlock()\n\t\treturn value\n\t}\n\tmutex.RUnlock()\n\treturn nil\n}\n\n// GetOk returns stored value and presence state like multi-value return of map access.\nfunc GetOk(r *http.Request, key interface{}) (interface{}, bool) {\n\tmutex.RLock()\n\tif _, ok := data[r]; ok {\n\t\tvalue, ok := data[r][key]\n\t\tmutex.RUnlock()\n\t\treturn value, ok\n\t}\n\tmutex.RUnlock()\n\treturn nil, false\n}\n\n// GetAll returns all stored values for the request as a map. Nil is returned for invalid requests.\nfunc GetAll(r *http.Request) map[interface{}]interface{} {\n\tmutex.RLock()\n\tif context, ok := data[r]; ok {\n\t\tresult := make(map[interface{}]interface{}, len(context))\n\t\tfor k, v := range context {\n\t\t\tresult[k] = v\n\t\t}\n\t\tmutex.RUnlock()\n\t\treturn result\n\t}\n\tmutex.RUnlock()\n\treturn nil\n}\n\n// GetAllOk returns all stored values for the request as a map and a boolean value that indicates if\n// the request was registered.\nfunc GetAllOk(r *http.Request) (map[interface{}]interface{}, bool) {\n\tmutex.RLock()\n\tcontext, ok := data[r]\n\tresult := make(map[interface{}]interface{}, len(context))\n\tfor k, v := range context {\n\t\tresult[k] = v\n\t}\n\tmutex.RUnlock()\n\treturn result, ok\n}\n\n// Delete removes a value stored for a given key in a given request.\nfunc Delete(r *http.Request, key interface{}) {\n\tmutex.Lock()\n\tif data[r] != nil {\n\t\tdelete(data[r], key)\n\t}\n\tmutex.Unlock()\n}\n\n// Clear removes all values stored for a given request.\n//\n// This is usually called by a handler wrapper to clean up request\n// variables at the end of a request lifetime. See ClearHandler().\nfunc Clear(r *http.Request) {\n\tmutex.Lock()\n\tclear(r)\n\tmutex.Unlock()\n}\n\n// clear is Clear without the lock.\nfunc clear(r *http.Request) {\n\tdelete(data, r)\n\tdelete(datat, r)\n}\n\n// Purge removes request data stored for longer than maxAge, in seconds.\n// It returns the amount of requests removed.\n//\n// If maxAge <= 0, all request data is removed.\n//\n// This is only used for sanity check: in case context cleaning was not\n// properly set some request data can be kept forever, consuming an increasing\n// amount of memory. In case this is detected, Purge() must be called\n// periodically until the problem is fixed.\nfunc Purge(maxAge int) int {\n\tmutex.Lock()\n\tcount := 0\n\tif maxAge <= 0 {\n\t\tcount = len(data)\n\t\tdata = make(map[*http.Request]map[interface{}]interface{})\n\t\tdatat = make(map[*http.Request]int64)\n\t} else {\n\t\tmin := time.Now().Unix() - int64(maxAge)\n\t\tfor r := range data {\n\t\t\tif datat[r] < min {\n\t\t\t\tclear(r)\n\t\t\t\tcount++\n\t\t\t}\n\t\t}\n\t}\n\tmutex.Unlock()\n\treturn count\n}\n\n// ClearHandler wraps an http.Handler and clears request values at the end\n// of a request lifetime.\nfunc ClearHandler(h http.Handler) http.Handler {\n\treturn http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tdefer Clear(r)\n\t\th.ServeHTTP(w, r)\n\t})\n}\n"
  },
  {
    "path": "vendor/github.com/gorilla/context/doc.go",
    "content": "// Copyright 2012 The Gorilla Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n/*\nPackage context stores values shared during a request lifetime.\n\nNote: gorilla/context, having been born well before `context.Context` existed,\ndoes not play well > with the shallow copying of the request that\n[`http.Request.WithContext`](https://golang.org/pkg/net/http/#Request.WithContext)\n(added to net/http Go 1.7 onwards) performs. You should either use *just*\ngorilla/context, or moving forward, the new `http.Request.Context()`.\n\nFor example, a router can set variables extracted from the URL and later\napplication handlers can access those values, or it can be used to store\nsessions values to be saved at the end of a request. There are several\nothers common uses.\n\nThe idea was posted by Brad Fitzpatrick to the go-nuts mailing list:\n\n\thttp://groups.google.com/group/golang-nuts/msg/e2d679d303aa5d53\n\nHere's the basic usage: first define the keys that you will need. The key\ntype is interface{} so a key can be of any type that supports equality.\nHere we define a key using a custom int type to avoid name collisions:\n\n\tpackage foo\n\n\timport (\n\t\t\"github.com/gorilla/context\"\n\t)\n\n\ttype key int\n\n\tconst MyKey key = 0\n\nThen set a variable. Variables are bound to an http.Request object, so you\nneed a request instance to set a value:\n\n\tcontext.Set(r, MyKey, \"bar\")\n\nThe application can later access the variable using the same key you provided:\n\n\tfunc MyHandler(w http.ResponseWriter, r *http.Request) {\n\t\t// val is \"bar\".\n\t\tval := context.Get(r, foo.MyKey)\n\n\t\t// returns (\"bar\", true)\n\t\tval, ok := context.GetOk(r, foo.MyKey)\n\t\t// ...\n\t}\n\nAnd that's all about the basic usage. We discuss some other ideas below.\n\nAny type can be stored in the context. To enforce a given type, make the key\nprivate and wrap Get() and Set() to accept and return values of a specific\ntype:\n\n\ttype key int\n\n\tconst mykey key = 0\n\n\t// GetMyKey returns a value for this package from the request values.\n\tfunc GetMyKey(r *http.Request) SomeType {\n\t\tif rv := context.Get(r, mykey); rv != nil {\n\t\t\treturn rv.(SomeType)\n\t\t}\n\t\treturn nil\n\t}\n\n\t// SetMyKey sets a value for this package in the request values.\n\tfunc SetMyKey(r *http.Request, val SomeType) {\n\t\tcontext.Set(r, mykey, val)\n\t}\n\nVariables must be cleared at the end of a request, to remove all values\nthat were stored. This can be done in an http.Handler, after a request was\nserved. Just call Clear() passing the request:\n\n\tcontext.Clear(r)\n\n...or use ClearHandler(), which conveniently wraps an http.Handler to clear\nvariables at the end of a request lifetime.\n\nThe Routers from the packages gorilla/mux and gorilla/pat call Clear()\nso if you are using either of them you don't need to clear the context manually.\n*/\npackage context\n"
  },
  {
    "path": "vendor/github.com/gorilla/mux/ISSUE_TEMPLATE.md",
    "content": "**What version of Go are you running?** (Paste the output of `go version`)\n\n\n**What version of gorilla/mux are you at?** (Paste the output of `git rev-parse HEAD` inside `$GOPATH/src/github.com/gorilla/mux`)\n\n\n**Describe your problem** (and what you have tried so far)\n\n\n**Paste a minimal, runnable, reproduction of your issue below** (use backticks to format it)\n\n"
  },
  {
    "path": "vendor/github.com/gorilla/mux/LICENSE",
    "content": "Copyright (c) 2012 Rodrigo Moraes. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n\t * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n\t * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n\t * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "vendor/github.com/gorilla/mux/README.md",
    "content": "# gorilla/mux\n\n[![GoDoc](https://godoc.org/github.com/gorilla/mux?status.svg)](https://godoc.org/github.com/gorilla/mux)\n[![Build Status](https://travis-ci.org/gorilla/mux.svg?branch=master)](https://travis-ci.org/gorilla/mux)\n[![Sourcegraph](https://sourcegraph.com/github.com/gorilla/mux/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/mux?badge)\n\n![Gorilla Logo](http://www.gorillatoolkit.org/static/images/gorilla-icon-64.png)\n\nhttp://www.gorillatoolkit.org/pkg/mux\n\nPackage `gorilla/mux` implements a request router and dispatcher for matching incoming requests to\ntheir respective handler.\n\nThe name mux stands for \"HTTP request multiplexer\". Like the standard `http.ServeMux`, `mux.Router` matches incoming requests against a list of registered routes and calls a handler for the route that matches the URL or other conditions. The main features are:\n\n* It implements the `http.Handler` interface so it is compatible with the standard `http.ServeMux`.\n* Requests can be matched based on URL host, path, path prefix, schemes, header and query values, HTTP methods or using custom matchers.\n* URL hosts, paths and query values can have variables with an optional regular expression.\n* Registered URLs can be built, or \"reversed\", which helps maintaining references to resources.\n* Routes can be used as subrouters: nested routes are only tested if the parent route matches. This is useful to define groups of routes that share common conditions like a host, a path prefix or other repeated attributes. As a bonus, this optimizes request matching.\n\n---\n\n* [Install](#install)\n* [Examples](#examples)\n* [Matching Routes](#matching-routes)\n* [Static Files](#static-files)\n* [Registered URLs](#registered-urls)\n* [Walking Routes](#walking-routes)\n* [Graceful Shutdown](#graceful-shutdown)\n* [Middleware](#middleware)\n* [Testing Handlers](#testing-handlers)\n* [Full Example](#full-example)\n\n---\n\n## Install\n\nWith a [correctly configured](https://golang.org/doc/install#testing) Go toolchain:\n\n```sh\ngo get -u github.com/gorilla/mux\n```\n\n## Examples\n\nLet's start registering a couple of URL paths and handlers:\n\n```go\nfunc main() {\n    r := mux.NewRouter()\n    r.HandleFunc(\"/\", HomeHandler)\n    r.HandleFunc(\"/products\", ProductsHandler)\n    r.HandleFunc(\"/articles\", ArticlesHandler)\n    http.Handle(\"/\", r)\n}\n```\n\nHere we register three routes mapping URL paths to handlers. This is equivalent to how `http.HandleFunc()` works: if an incoming request URL matches one of the paths, the corresponding handler is called passing (`http.ResponseWriter`, `*http.Request`) as parameters.\n\nPaths can have variables. They are defined using the format `{name}` or `{name:pattern}`. If a regular expression pattern is not defined, the matched variable will be anything until the next slash. For example:\n\n```go\nr := mux.NewRouter()\nr.HandleFunc(\"/products/{key}\", ProductHandler)\nr.HandleFunc(\"/articles/{category}/\", ArticlesCategoryHandler)\nr.HandleFunc(\"/articles/{category}/{id:[0-9]+}\", ArticleHandler)\n```\n\nThe names are used to create a map of route variables which can be retrieved calling `mux.Vars()`:\n\n```go\nfunc ArticlesCategoryHandler(w http.ResponseWriter, r *http.Request) {\n    vars := mux.Vars(r)\n    w.WriteHeader(http.StatusOK)\n    fmt.Fprintf(w, \"Category: %v\\n\", vars[\"category\"])\n}\n```\n\nAnd this is all you need to know about the basic usage. More advanced options are explained below.\n\n### Matching Routes\n\nRoutes can also be restricted to a domain or subdomain. Just define a host pattern to be matched. They can also have variables:\n\n```go\nr := mux.NewRouter()\n// Only matches if domain is \"www.example.com\".\nr.Host(\"www.example.com\")\n// Matches a dynamic subdomain.\nr.Host(\"{subdomain:[a-z]+}.domain.com\")\n```\n\nThere are several other matchers that can be added. To match path prefixes:\n\n```go\nr.PathPrefix(\"/products/\")\n```\n\n...or HTTP methods:\n\n```go\nr.Methods(\"GET\", \"POST\")\n```\n\n...or URL schemes:\n\n```go\nr.Schemes(\"https\")\n```\n\n...or header values:\n\n```go\nr.Headers(\"X-Requested-With\", \"XMLHttpRequest\")\n```\n\n...or query values:\n\n```go\nr.Queries(\"key\", \"value\")\n```\n\n...or to use a custom matcher function:\n\n```go\nr.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool {\n    return r.ProtoMajor == 0\n})\n```\n\n...and finally, it is possible to combine several matchers in a single route:\n\n```go\nr.HandleFunc(\"/products\", ProductsHandler).\n  Host(\"www.example.com\").\n  Methods(\"GET\").\n  Schemes(\"http\")\n```\n\nRoutes are tested in the order they were added to the router. If two routes match, the first one wins:\n\n```go\nr := mux.NewRouter()\nr.HandleFunc(\"/specific\", specificHandler)\nr.PathPrefix(\"/\").Handler(catchAllHandler)\n```\n\nSetting the same matching conditions again and again can be boring, so we have a way to group several routes that share the same requirements. We call it \"subrouting\".\n\nFor example, let's say we have several URLs that should only match when the host is `www.example.com`. Create a route for that host and get a \"subrouter\" from it:\n\n```go\nr := mux.NewRouter()\ns := r.Host(\"www.example.com\").Subrouter()\n```\n\nThen register routes in the subrouter:\n\n```go\ns.HandleFunc(\"/products/\", ProductsHandler)\ns.HandleFunc(\"/products/{key}\", ProductHandler)\ns.HandleFunc(\"/articles/{category}/{id:[0-9]+}\", ArticleHandler)\n```\n\nThe three URL paths we registered above will only be tested if the domain is `www.example.com`, because the subrouter is tested first. This is not only convenient, but also optimizes request matching. You can create subrouters combining any attribute matchers accepted by a route.\n\nSubrouters can be used to create domain or path \"namespaces\": you define subrouters in a central place and then parts of the app can register its paths relatively to a given subrouter.\n\nThere's one more thing about subroutes. When a subrouter has a path prefix, the inner routes use it as base for their paths:\n\n```go\nr := mux.NewRouter()\ns := r.PathPrefix(\"/products\").Subrouter()\n// \"/products/\"\ns.HandleFunc(\"/\", ProductsHandler)\n// \"/products/{key}/\"\ns.HandleFunc(\"/{key}/\", ProductHandler)\n// \"/products/{key}/details\"\ns.HandleFunc(\"/{key}/details\", ProductDetailsHandler)\n```\n\n\n### Static Files\n\nNote that the path provided to `PathPrefix()` represents a \"wildcard\": calling\n`PathPrefix(\"/static/\").Handler(...)` means that the handler will be passed any\nrequest that matches \"/static/\\*\". This makes it easy to serve static files with mux:\n\n```go\nfunc main() {\n    var dir string\n\n    flag.StringVar(&dir, \"dir\", \".\", \"the directory to serve files from. Defaults to the current dir\")\n    flag.Parse()\n    r := mux.NewRouter()\n\n    // This will serve files under http://localhost:8000/static/<filename>\n    r.PathPrefix(\"/static/\").Handler(http.StripPrefix(\"/static/\", http.FileServer(http.Dir(dir))))\n\n    srv := &http.Server{\n        Handler:      r,\n        Addr:         \"127.0.0.1:8000\",\n        // Good practice: enforce timeouts for servers you create!\n        WriteTimeout: 15 * time.Second,\n        ReadTimeout:  15 * time.Second,\n    }\n\n    log.Fatal(srv.ListenAndServe())\n}\n```\n\n### Registered URLs\n\nNow let's see how to build registered URLs.\n\nRoutes can be named. All routes that define a name can have their URLs built, or \"reversed\". We define a name calling `Name()` on a route. For example:\n\n```go\nr := mux.NewRouter()\nr.HandleFunc(\"/articles/{category}/{id:[0-9]+}\", ArticleHandler).\n  Name(\"article\")\n```\n\nTo build a URL, get the route and call the `URL()` method, passing a sequence of key/value pairs for the route variables. For the previous route, we would do:\n\n```go\nurl, err := r.Get(\"article\").URL(\"category\", \"technology\", \"id\", \"42\")\n```\n\n...and the result will be a `url.URL` with the following path:\n\n```\n\"/articles/technology/42\"\n```\n\nThis also works for host and query value variables:\n\n```go\nr := mux.NewRouter()\nr.Host(\"{subdomain}.domain.com\").\n  Path(\"/articles/{category}/{id:[0-9]+}\").\n  Queries(\"filter\", \"{filter}\").\n  HandlerFunc(ArticleHandler).\n  Name(\"article\")\n\n// url.String() will be \"http://news.domain.com/articles/technology/42?filter=gorilla\"\nurl, err := r.Get(\"article\").URL(\"subdomain\", \"news\",\n                                 \"category\", \"technology\",\n                                 \"id\", \"42\",\n                                 \"filter\", \"gorilla\")\n```\n\nAll variables defined in the route are required, and their values must conform to the corresponding patterns. These requirements guarantee that a generated URL will always match a registered route -- the only exception is for explicitly defined \"build-only\" routes which never match.\n\nRegex support also exists for matching Headers within a route. For example, we could do:\n\n```go\nr.HeadersRegexp(\"Content-Type\", \"application/(text|json)\")\n```\n\n...and the route will match both requests with a Content-Type of `application/json` as well as `application/text`\n\nThere's also a way to build only the URL host or path for a route: use the methods `URLHost()` or `URLPath()` instead. For the previous route, we would do:\n\n```go\n// \"http://news.domain.com/\"\nhost, err := r.Get(\"article\").URLHost(\"subdomain\", \"news\")\n\n// \"/articles/technology/42\"\npath, err := r.Get(\"article\").URLPath(\"category\", \"technology\", \"id\", \"42\")\n```\n\nAnd if you use subrouters, host and path defined separately can be built as well:\n\n```go\nr := mux.NewRouter()\ns := r.Host(\"{subdomain}.domain.com\").Subrouter()\ns.Path(\"/articles/{category}/{id:[0-9]+}\").\n  HandlerFunc(ArticleHandler).\n  Name(\"article\")\n\n// \"http://news.domain.com/articles/technology/42\"\nurl, err := r.Get(\"article\").URL(\"subdomain\", \"news\",\n                                 \"category\", \"technology\",\n                                 \"id\", \"42\")\n```\n\n### Walking Routes\n\nThe `Walk` function on `mux.Router` can be used to visit all of the routes that are registered on a router. For example,\nthe following prints all of the registered routes:\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/gorilla/mux\"\n)\n\nfunc handler(w http.ResponseWriter, r *http.Request) {\n\treturn\n}\n\nfunc main() {\n\tr := mux.NewRouter()\n\tr.HandleFunc(\"/\", handler)\n\tr.HandleFunc(\"/products\", handler).Methods(\"POST\")\n\tr.HandleFunc(\"/articles\", handler).Methods(\"GET\")\n\tr.HandleFunc(\"/articles/{id}\", handler).Methods(\"GET\", \"PUT\")\n\tr.HandleFunc(\"/authors\", handler).Queries(\"surname\", \"{surname}\")\n\terr := r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {\n\t\tpathTemplate, err := route.GetPathTemplate()\n\t\tif err == nil {\n\t\t\tfmt.Println(\"ROUTE:\", pathTemplate)\n\t\t}\n\t\tpathRegexp, err := route.GetPathRegexp()\n\t\tif err == nil {\n\t\t\tfmt.Println(\"Path regexp:\", pathRegexp)\n\t\t}\n\t\tqueriesTemplates, err := route.GetQueriesTemplates()\n\t\tif err == nil {\n\t\t\tfmt.Println(\"Queries templates:\", strings.Join(queriesTemplates, \",\"))\n\t\t}\n\t\tqueriesRegexps, err := route.GetQueriesRegexp()\n\t\tif err == nil {\n\t\t\tfmt.Println(\"Queries regexps:\", strings.Join(queriesRegexps, \",\"))\n\t\t}\n\t\tmethods, err := route.GetMethods()\n\t\tif err == nil {\n\t\t\tfmt.Println(\"Methods:\", strings.Join(methods, \",\"))\n\t\t}\n\t\tfmt.Println()\n\t\treturn nil\n\t})\n\n\tif err != nil {\n\t\tfmt.Println(err)\n\t}\n\n\thttp.Handle(\"/\", r)\n}\n```\n\n### Graceful Shutdown\n\nGo 1.8 introduced the ability to [gracefully shutdown](https://golang.org/doc/go1.8#http_shutdown) a `*http.Server`. Here's how to do that alongside `mux`:\n\n```go\npackage main\n\nimport (\n    \"context\"\n    \"flag\"\n    \"log\"\n    \"net/http\"\n    \"os\"\n    \"os/signal\"\n    \"time\"\n\n    \"github.com/gorilla/mux\"\n)\n\nfunc main() {\n    var wait time.Duration\n    flag.DurationVar(&wait, \"graceful-timeout\", time.Second * 15, \"the duration for which the server gracefully wait for existing connections to finish - e.g. 15s or 1m\")\n    flag.Parse()\n\n    r := mux.NewRouter()\n    // Add your routes as needed\n\n    srv := &http.Server{\n        Addr:         \"0.0.0.0:8080\",\n        // Good practice to set timeouts to avoid Slowloris attacks.\n        WriteTimeout: time.Second * 15,\n        ReadTimeout:  time.Second * 15,\n        IdleTimeout:  time.Second * 60,\n        Handler: r, // Pass our instance of gorilla/mux in.\n    }\n\n    // Run our server in a goroutine so that it doesn't block.\n    go func() {\n        if err := srv.ListenAndServe(); err != nil {\n            log.Println(err)\n        }\n    }()\n\n    c := make(chan os.Signal, 1)\n    // We'll accept graceful shutdowns when quit via SIGINT (Ctrl+C)\n    // SIGKILL, SIGQUIT or SIGTERM (Ctrl+/) will not be caught.\n    signal.Notify(c, os.Interrupt)\n\n    // Block until we receive our signal.\n    <-c\n\n    // Create a deadline to wait for.\n    ctx, cancel := context.WithTimeout(context.Background(), wait)\n    defer cancel()\n    // Doesn't block if no connections, but will otherwise wait\n    // until the timeout deadline.\n    srv.Shutdown(ctx)\n    // Optionally, you could run srv.Shutdown in a goroutine and block on\n    // <-ctx.Done() if your application should wait for other services\n    // to finalize based on context cancellation.\n    log.Println(\"shutting down\")\n    os.Exit(0)\n}\n```\n\n### Middleware\n\nMux supports the addition of middlewares to a [Router](https://godoc.org/github.com/gorilla/mux#Router), which are executed in the order they are added if a match is found, including its subrouters.\nMiddlewares are (typically) small pieces of code which take one request, do something with it, and pass it down to another middleware or the final handler. Some common use cases for middleware are request logging, header manipulation, or `ResponseWriter` hijacking.\n\nMux middlewares are defined using the de facto standard type:\n\n```go\ntype MiddlewareFunc func(http.Handler) http.Handler\n```\n\nTypically, the returned handler is a closure which does something with the http.ResponseWriter and http.Request passed to it, and then calls the handler passed as parameter to the MiddlewareFunc. This takes advantage of closures being able access variables from the context where they are created, while retaining the signature enforced by the receivers.\n\nA very basic middleware which logs the URI of the request being handled could be written as:\n\n```go\nfunc loggingMiddleware(next http.Handler) http.Handler {\n    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n        // Do stuff here\n        log.Println(r.RequestURI)\n        // Call the next handler, which can be another middleware in the chain, or the final handler.\n        next.ServeHTTP(w, r)\n    })\n}\n```\n\nMiddlewares can be added to a router using `Router.Use()`:\n\n```go\nr := mux.NewRouter()\nr.HandleFunc(\"/\", handler)\nr.Use(loggingMiddleware)\n```\n\nA more complex authentication middleware, which maps session token to users, could be written as:\n\n```go\n// Define our struct\ntype authenticationMiddleware struct {\n\ttokenUsers map[string]string\n}\n\n// Initialize it somewhere\nfunc (amw *authenticationMiddleware) Populate() {\n\tamw.tokenUsers[\"00000000\"] = \"user0\"\n\tamw.tokenUsers[\"aaaaaaaa\"] = \"userA\"\n\tamw.tokenUsers[\"05f717e5\"] = \"randomUser\"\n\tamw.tokenUsers[\"deadbeef\"] = \"user0\"\n}\n\n// Middleware function, which will be called for each request\nfunc (amw *authenticationMiddleware) Middleware(next http.Handler) http.Handler {\n    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n        token := r.Header.Get(\"X-Session-Token\")\n\n        if user, found := amw.tokenUsers[token]; found {\n        \t// We found the token in our map\n        \tlog.Printf(\"Authenticated user %s\\n\", user)\n        \t// Pass down the request to the next middleware (or final handler)\n        \tnext.ServeHTTP(w, r)\n        } else {\n        \t// Write an error and stop the handler chain\n        \thttp.Error(w, \"Forbidden\", http.StatusForbidden)\n        }\n    })\n}\n```\n\n```go\nr := mux.NewRouter()\nr.HandleFunc(\"/\", handler)\n\namw := authenticationMiddleware{}\namw.Populate()\n\nr.Use(amw.Middleware)\n```\n\nNote: The handler chain will be stopped if your middleware doesn't call `next.ServeHTTP()` with the corresponding parameters. This can be used to abort a request if the middleware writer wants to. Middlewares _should_ write to `ResponseWriter` if they _are_ going to terminate the request, and they _should not_ write to `ResponseWriter` if they _are not_ going to terminate it.\n\n### Testing Handlers\n\nTesting handlers in a Go web application is straightforward, and _mux_ doesn't complicate this any further. Given two files: `endpoints.go` and `endpoints_test.go`, here's how we'd test an application using _mux_.\n\nFirst, our simple HTTP handler:\n\n```go\n// endpoints.go\npackage main\n\nfunc HealthCheckHandler(w http.ResponseWriter, r *http.Request) {\n    // A very simple health check.\n    w.WriteHeader(http.StatusOK)\n    w.Header().Set(\"Content-Type\", \"application/json\")\n\n    // In the future we could report back on the status of our DB, or our cache\n    // (e.g. Redis) by performing a simple PING, and include them in the response.\n    io.WriteString(w, `{\"alive\": true}`)\n}\n\nfunc main() {\n    r := mux.NewRouter()\n    r.HandleFunc(\"/health\", HealthCheckHandler)\n\n    log.Fatal(http.ListenAndServe(\"localhost:8080\", r))\n}\n```\n\nOur test code:\n\n```go\n// endpoints_test.go\npackage main\n\nimport (\n    \"net/http\"\n    \"net/http/httptest\"\n    \"testing\"\n)\n\nfunc TestHealthCheckHandler(t *testing.T) {\n    // Create a request to pass to our handler. We don't have any query parameters for now, so we'll\n    // pass 'nil' as the third parameter.\n    req, err := http.NewRequest(\"GET\", \"/health\", nil)\n    if err != nil {\n        t.Fatal(err)\n    }\n\n    // We create a ResponseRecorder (which satisfies http.ResponseWriter) to record the response.\n    rr := httptest.NewRecorder()\n    handler := http.HandlerFunc(HealthCheckHandler)\n\n    // Our handlers satisfy http.Handler, so we can call their ServeHTTP method\n    // directly and pass in our Request and ResponseRecorder.\n    handler.ServeHTTP(rr, req)\n\n    // Check the status code is what we expect.\n    if status := rr.Code; status != http.StatusOK {\n        t.Errorf(\"handler returned wrong status code: got %v want %v\",\n            status, http.StatusOK)\n    }\n\n    // Check the response body is what we expect.\n    expected := `{\"alive\": true}`\n    if rr.Body.String() != expected {\n        t.Errorf(\"handler returned unexpected body: got %v want %v\",\n            rr.Body.String(), expected)\n    }\n}\n```\n\nIn the case that our routes have [variables](#examples), we can pass those in the request. We could write\n[table-driven tests](https://dave.cheney.net/2013/06/09/writing-table-driven-tests-in-go) to test multiple\npossible route variables as needed.\n\n```go\n// endpoints.go\nfunc main() {\n    r := mux.NewRouter()\n    // A route with a route variable:\n    r.HandleFunc(\"/metrics/{type}\", MetricsHandler)\n\n    log.Fatal(http.ListenAndServe(\"localhost:8080\", r))\n}\n```\n\nOur test file, with a table-driven test of `routeVariables`:\n\n```go\n// endpoints_test.go\nfunc TestMetricsHandler(t *testing.T) {\n    tt := []struct{\n        routeVariable string\n        shouldPass bool\n    }{\n        {\"goroutines\", true},\n        {\"heap\", true},\n        {\"counters\", true},\n        {\"queries\", true},\n        {\"adhadaeqm3k\", false},\n    }\n\n    for _, tc := range tt {\n        path := fmt.Sprintf(\"/metrics/%s\", tc.routeVariable)\n        req, err := http.NewRequest(\"GET\", path, nil)\n        if err != nil {\n            t.Fatal(err)\n        }\n\n        rr := httptest.NewRecorder()\n        handler := http.HandlerFunc(MetricsHandler)\n        handler.ServeHTTP(rr, req)\n\n        // In this case, our MetricsHandler returns a non-200 response\n        // for a route variable it doesn't know about.\n        if rr.Code == http.StatusOK && !tc.shouldPass {\n            t.Errorf(\"handler should have failed on routeVariable %s: got %v want %v\",\n                tc.routeVariable, rr.Code, http.StatusOK)\n        }\n    }\n}\n```\n\n## Full Example\n\nHere's a complete, runnable example of a small `mux` based server:\n\n```go\npackage main\n\nimport (\n    \"net/http\"\n    \"log\"\n    \"github.com/gorilla/mux\"\n)\n\nfunc YourHandler(w http.ResponseWriter, r *http.Request) {\n    w.Write([]byte(\"Gorilla!\\n\"))\n}\n\nfunc main() {\n    r := mux.NewRouter()\n    // Routes consist of a path and a handler function.\n    r.HandleFunc(\"/\", YourHandler)\n\n    // Bind to a port and pass our router in\n    log.Fatal(http.ListenAndServe(\":8000\", r))\n}\n```\n\n## License\n\nBSD licensed. See the LICENSE file for details.\n"
  },
  {
    "path": "vendor/github.com/gorilla/mux/context_gorilla.go",
    "content": "// +build !go1.7\n\npackage mux\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/gorilla/context\"\n)\n\nfunc contextGet(r *http.Request, key interface{}) interface{} {\n\treturn context.Get(r, key)\n}\n\nfunc contextSet(r *http.Request, key, val interface{}) *http.Request {\n\tif val == nil {\n\t\treturn r\n\t}\n\n\tcontext.Set(r, key, val)\n\treturn r\n}\n\nfunc contextClear(r *http.Request) {\n\tcontext.Clear(r)\n}\n"
  },
  {
    "path": "vendor/github.com/gorilla/mux/context_native.go",
    "content": "// +build go1.7\n\npackage mux\n\nimport (\n\t\"context\"\n\t\"net/http\"\n)\n\nfunc contextGet(r *http.Request, key interface{}) interface{} {\n\treturn r.Context().Value(key)\n}\n\nfunc contextSet(r *http.Request, key, val interface{}) *http.Request {\n\tif val == nil {\n\t\treturn r\n\t}\n\n\treturn r.WithContext(context.WithValue(r.Context(), key, val))\n}\n\nfunc contextClear(r *http.Request) {\n\treturn\n}\n"
  },
  {
    "path": "vendor/github.com/gorilla/mux/doc.go",
    "content": "// Copyright 2012 The Gorilla Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n/*\nPackage mux implements a request router and dispatcher.\n\nThe name mux stands for \"HTTP request multiplexer\". Like the standard\nhttp.ServeMux, mux.Router matches incoming requests against a list of\nregistered routes and calls a handler for the route that matches the URL\nor other conditions. The main features are:\n\n\t* Requests can be matched based on URL host, path, path prefix, schemes,\n\t  header and query values, HTTP methods or using custom matchers.\n\t* URL hosts, paths and query values can have variables with an optional\n\t  regular expression.\n\t* Registered URLs can be built, or \"reversed\", which helps maintaining\n\t  references to resources.\n\t* Routes can be used as subrouters: nested routes are only tested if the\n\t  parent route matches. This is useful to define groups of routes that\n\t  share common conditions like a host, a path prefix or other repeated\n\t  attributes. As a bonus, this optimizes request matching.\n\t* It implements the http.Handler interface so it is compatible with the\n\t  standard http.ServeMux.\n\nLet's start registering a couple of URL paths and handlers:\n\n\tfunc main() {\n\t\tr := mux.NewRouter()\n\t\tr.HandleFunc(\"/\", HomeHandler)\n\t\tr.HandleFunc(\"/products\", ProductsHandler)\n\t\tr.HandleFunc(\"/articles\", ArticlesHandler)\n\t\thttp.Handle(\"/\", r)\n\t}\n\nHere we register three routes mapping URL paths to handlers. This is\nequivalent to how http.HandleFunc() works: if an incoming request URL matches\none of the paths, the corresponding handler is called passing\n(http.ResponseWriter, *http.Request) as parameters.\n\nPaths can have variables. They are defined using the format {name} or\n{name:pattern}. If a regular expression pattern is not defined, the matched\nvariable will be anything until the next slash. For example:\n\n\tr := mux.NewRouter()\n\tr.HandleFunc(\"/products/{key}\", ProductHandler)\n\tr.HandleFunc(\"/articles/{category}/\", ArticlesCategoryHandler)\n\tr.HandleFunc(\"/articles/{category}/{id:[0-9]+}\", ArticleHandler)\n\nGroups can be used inside patterns, as long as they are non-capturing (?:re). For example:\n\n\tr.HandleFunc(\"/articles/{category}/{sort:(?:asc|desc|new)}\", ArticlesCategoryHandler)\n\nThe names are used to create a map of route variables which can be retrieved\ncalling mux.Vars():\n\n\tvars := mux.Vars(request)\n\tcategory := vars[\"category\"]\n\nNote that if any capturing groups are present, mux will panic() during parsing. To prevent\nthis, convert any capturing groups to non-capturing, e.g. change \"/{sort:(asc|desc)}\" to\n\"/{sort:(?:asc|desc)}\". This is a change from prior versions which behaved unpredictably\nwhen capturing groups were present.\n\nAnd this is all you need to know about the basic usage. More advanced options\nare explained below.\n\nRoutes can also be restricted to a domain or subdomain. Just define a host\npattern to be matched. They can also have variables:\n\n\tr := mux.NewRouter()\n\t// Only matches if domain is \"www.example.com\".\n\tr.Host(\"www.example.com\")\n\t// Matches a dynamic subdomain.\n\tr.Host(\"{subdomain:[a-z]+}.domain.com\")\n\nThere are several other matchers that can be added. To match path prefixes:\n\n\tr.PathPrefix(\"/products/\")\n\n...or HTTP methods:\n\n\tr.Methods(\"GET\", \"POST\")\n\n...or URL schemes:\n\n\tr.Schemes(\"https\")\n\n...or header values:\n\n\tr.Headers(\"X-Requested-With\", \"XMLHttpRequest\")\n\n...or query values:\n\n\tr.Queries(\"key\", \"value\")\n\n...or to use a custom matcher function:\n\n\tr.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool {\n\t\treturn r.ProtoMajor == 0\n\t})\n\n...and finally, it is possible to combine several matchers in a single route:\n\n\tr.HandleFunc(\"/products\", ProductsHandler).\n\t  Host(\"www.example.com\").\n\t  Methods(\"GET\").\n\t  Schemes(\"http\")\n\nSetting the same matching conditions again and again can be boring, so we have\na way to group several routes that share the same requirements.\nWe call it \"subrouting\".\n\nFor example, let's say we have several URLs that should only match when the\nhost is \"www.example.com\". Create a route for that host and get a \"subrouter\"\nfrom it:\n\n\tr := mux.NewRouter()\n\ts := r.Host(\"www.example.com\").Subrouter()\n\nThen register routes in the subrouter:\n\n\ts.HandleFunc(\"/products/\", ProductsHandler)\n\ts.HandleFunc(\"/products/{key}\", ProductHandler)\n\ts.HandleFunc(\"/articles/{category}/{id:[0-9]+}\"), ArticleHandler)\n\nThe three URL paths we registered above will only be tested if the domain is\n\"www.example.com\", because the subrouter is tested first. This is not\nonly convenient, but also optimizes request matching. You can create\nsubrouters combining any attribute matchers accepted by a route.\n\nSubrouters can be used to create domain or path \"namespaces\": you define\nsubrouters in a central place and then parts of the app can register its\npaths relatively to a given subrouter.\n\nThere's one more thing about subroutes. When a subrouter has a path prefix,\nthe inner routes use it as base for their paths:\n\n\tr := mux.NewRouter()\n\ts := r.PathPrefix(\"/products\").Subrouter()\n\t// \"/products/\"\n\ts.HandleFunc(\"/\", ProductsHandler)\n\t// \"/products/{key}/\"\n\ts.HandleFunc(\"/{key}/\", ProductHandler)\n\t// \"/products/{key}/details\"\n\ts.HandleFunc(\"/{key}/details\", ProductDetailsHandler)\n\nNote that the path provided to PathPrefix() represents a \"wildcard\": calling\nPathPrefix(\"/static/\").Handler(...) means that the handler will be passed any\nrequest that matches \"/static/*\". This makes it easy to serve static files with mux:\n\n\tfunc main() {\n\t\tvar dir string\n\n\t\tflag.StringVar(&dir, \"dir\", \".\", \"the directory to serve files from. Defaults to the current dir\")\n\t\tflag.Parse()\n\t\tr := mux.NewRouter()\n\n\t\t// This will serve files under http://localhost:8000/static/<filename>\n\t\tr.PathPrefix(\"/static/\").Handler(http.StripPrefix(\"/static/\", http.FileServer(http.Dir(dir))))\n\n\t\tsrv := &http.Server{\n\t\t\tHandler:      r,\n\t\t\tAddr:         \"127.0.0.1:8000\",\n\t\t\t// Good practice: enforce timeouts for servers you create!\n\t\t\tWriteTimeout: 15 * time.Second,\n\t\t\tReadTimeout:  15 * time.Second,\n\t\t}\n\n\t\tlog.Fatal(srv.ListenAndServe())\n\t}\n\nNow let's see how to build registered URLs.\n\nRoutes can be named. All routes that define a name can have their URLs built,\nor \"reversed\". We define a name calling Name() on a route. For example:\n\n\tr := mux.NewRouter()\n\tr.HandleFunc(\"/articles/{category}/{id:[0-9]+}\", ArticleHandler).\n\t  Name(\"article\")\n\nTo build a URL, get the route and call the URL() method, passing a sequence of\nkey/value pairs for the route variables. For the previous route, we would do:\n\n\turl, err := r.Get(\"article\").URL(\"category\", \"technology\", \"id\", \"42\")\n\n...and the result will be a url.URL with the following path:\n\n\t\"/articles/technology/42\"\n\nThis also works for host and query value variables:\n\n\tr := mux.NewRouter()\n\tr.Host(\"{subdomain}.domain.com\").\n\t  Path(\"/articles/{category}/{id:[0-9]+}\").\n\t  Queries(\"filter\", \"{filter}\").\n\t  HandlerFunc(ArticleHandler).\n\t  Name(\"article\")\n\n\t// url.String() will be \"http://news.domain.com/articles/technology/42?filter=gorilla\"\n\turl, err := r.Get(\"article\").URL(\"subdomain\", \"news\",\n\t                                 \"category\", \"technology\",\n\t                                 \"id\", \"42\",\n\t                                 \"filter\", \"gorilla\")\n\nAll variables defined in the route are required, and their values must\nconform to the corresponding patterns. These requirements guarantee that a\ngenerated URL will always match a registered route -- the only exception is\nfor explicitly defined \"build-only\" routes which never match.\n\nRegex support also exists for matching Headers within a route. For example, we could do:\n\n\tr.HeadersRegexp(\"Content-Type\", \"application/(text|json)\")\n\n...and the route will match both requests with a Content-Type of `application/json` as well as\n`application/text`\n\nThere's also a way to build only the URL host or path for a route:\nuse the methods URLHost() or URLPath() instead. For the previous route,\nwe would do:\n\n\t// \"http://news.domain.com/\"\n\thost, err := r.Get(\"article\").URLHost(\"subdomain\", \"news\")\n\n\t// \"/articles/technology/42\"\n\tpath, err := r.Get(\"article\").URLPath(\"category\", \"technology\", \"id\", \"42\")\n\nAnd if you use subrouters, host and path defined separately can be built\nas well:\n\n\tr := mux.NewRouter()\n\ts := r.Host(\"{subdomain}.domain.com\").Subrouter()\n\ts.Path(\"/articles/{category}/{id:[0-9]+}\").\n\t  HandlerFunc(ArticleHandler).\n\t  Name(\"article\")\n\n\t// \"http://news.domain.com/articles/technology/42\"\n\turl, err := r.Get(\"article\").URL(\"subdomain\", \"news\",\n\t                                 \"category\", \"technology\",\n\t                                 \"id\", \"42\")\n\nMux supports the addition of middlewares to a Router, which are executed in the order they are added if a match is found, including its subrouters. Middlewares are (typically) small pieces of code which take one request, do something with it, and pass it down to another middleware or the final handler. Some common use cases for middleware are request logging, header manipulation, or ResponseWriter hijacking.\n\n\ttype MiddlewareFunc func(http.Handler) http.Handler\n\nTypically, the returned handler is a closure which does something with the http.ResponseWriter and http.Request passed to it, and then calls the handler passed as parameter to the MiddlewareFunc (closures can access variables from the context where they are created).\n\nA very basic middleware which logs the URI of the request being handled could be written as:\n\n\tfunc simpleMw(next http.Handler) http.Handler {\n\t\treturn http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\t// Do stuff here\n\t\t\tlog.Println(r.RequestURI)\n\t\t\t// Call the next handler, which can be another middleware in the chain, or the final handler.\n\t\t\tnext.ServeHTTP(w, r)\n\t\t})\n\t}\n\nMiddlewares can be added to a router using `Router.Use()`:\n\n\tr := mux.NewRouter()\n\tr.HandleFunc(\"/\", handler)\n\tr.Use(simpleMw)\n\nA more complex authentication middleware, which maps session token to users, could be written as:\n\n\t// Define our struct\n\ttype authenticationMiddleware struct {\n\t\ttokenUsers map[string]string\n\t}\n\n\t// Initialize it somewhere\n\tfunc (amw *authenticationMiddleware) Populate() {\n\t\tamw.tokenUsers[\"00000000\"] = \"user0\"\n\t\tamw.tokenUsers[\"aaaaaaaa\"] = \"userA\"\n\t\tamw.tokenUsers[\"05f717e5\"] = \"randomUser\"\n\t\tamw.tokenUsers[\"deadbeef\"] = \"user0\"\n\t}\n\n\t// Middleware function, which will be called for each request\n\tfunc (amw *authenticationMiddleware) Middleware(next http.Handler) http.Handler {\n\t\treturn http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\ttoken := r.Header.Get(\"X-Session-Token\")\n\n\t\t\tif user, found := amw.tokenUsers[token]; found {\n\t\t\t\t// We found the token in our map\n\t\t\t\tlog.Printf(\"Authenticated user %s\\n\", user)\n\t\t\t\tnext.ServeHTTP(w, r)\n\t\t\t} else {\n\t\t\t\thttp.Error(w, \"Forbidden\", http.StatusForbidden)\n\t\t\t}\n\t\t})\n\t}\n\n\tr := mux.NewRouter()\n\tr.HandleFunc(\"/\", handler)\n\n\tamw := authenticationMiddleware{}\n\tamw.Populate()\n\n\tr.Use(amw.Middleware)\n\nNote: The handler chain will be stopped if your middleware doesn't call `next.ServeHTTP()` with the corresponding parameters. This can be used to abort a request if the middleware writer wants to.\n\n*/\npackage mux\n"
  },
  {
    "path": "vendor/github.com/gorilla/mux/middleware.go",
    "content": "package mux\n\nimport \"net/http\"\n\n// MiddlewareFunc is a function which receives an http.Handler and returns another http.Handler.\n// Typically, the returned handler is a closure which does something with the http.ResponseWriter and http.Request passed\n// to it, and then calls the handler passed as parameter to the MiddlewareFunc.\ntype MiddlewareFunc func(http.Handler) http.Handler\n\n// middleware interface is anything which implements a MiddlewareFunc named Middleware.\ntype middleware interface {\n\tMiddleware(handler http.Handler) http.Handler\n}\n\n// MiddlewareFunc also implements the middleware interface.\nfunc (mw MiddlewareFunc) Middleware(handler http.Handler) http.Handler {\n\treturn mw(handler)\n}\n\n// Use appends a MiddlewareFunc to the chain. Middleware can be used to intercept or otherwise modify requests and/or responses, and are executed in the order that they are applied to the Router.\nfunc (r *Router) Use(mwf ...MiddlewareFunc) {\n\tfor _, fn := range mwf {\n\t\tr.middlewares = append(r.middlewares, fn)\n\t}\n}\n\n// useInterface appends a middleware to the chain. Middleware can be used to intercept or otherwise modify requests and/or responses, and are executed in the order that they are applied to the Router.\nfunc (r *Router) useInterface(mw middleware) {\n\tr.middlewares = append(r.middlewares, mw)\n}\n"
  },
  {
    "path": "vendor/github.com/gorilla/mux/mux.go",
    "content": "// Copyright 2012 The Gorilla Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage mux\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"path\"\n\t\"regexp\"\n)\n\nvar (\n\tErrMethodMismatch = errors.New(\"method is not allowed\")\n\tErrNotFound       = errors.New(\"no matching route was found\")\n)\n\n// NewRouter returns a new router instance.\nfunc NewRouter() *Router {\n\treturn &Router{namedRoutes: make(map[string]*Route), KeepContext: false}\n}\n\n// Router registers routes to be matched and dispatches a handler.\n//\n// It implements the http.Handler interface, so it can be registered to serve\n// requests:\n//\n//     var router = mux.NewRouter()\n//\n//     func main() {\n//         http.Handle(\"/\", router)\n//     }\n//\n// Or, for Google App Engine, register it in a init() function:\n//\n//     func init() {\n//         http.Handle(\"/\", router)\n//     }\n//\n// This will send all incoming requests to the router.\ntype Router struct {\n\t// Configurable Handler to be used when no route matches.\n\tNotFoundHandler http.Handler\n\n\t// Configurable Handler to be used when the request method does not match the route.\n\tMethodNotAllowedHandler http.Handler\n\n\t// Parent route, if this is a subrouter.\n\tparent parentRoute\n\t// Routes to be matched, in order.\n\troutes []*Route\n\t// Routes by name for URL building.\n\tnamedRoutes map[string]*Route\n\t// See Router.StrictSlash(). This defines the flag for new routes.\n\tstrictSlash bool\n\t// See Router.SkipClean(). This defines the flag for new routes.\n\tskipClean bool\n\t// If true, do not clear the request context after handling the request.\n\t// This has no effect when go1.7+ is used, since the context is stored\n\t// on the request itself.\n\tKeepContext bool\n\t// see Router.UseEncodedPath(). This defines a flag for all routes.\n\tuseEncodedPath bool\n\t// Slice of middlewares to be called after a match is found\n\tmiddlewares []middleware\n}\n\n// Match attempts to match the given request against the router's registered routes.\n//\n// If the request matches a route of this router or one of its subrouters the Route,\n// Handler, and Vars fields of the the match argument are filled and this function\n// returns true.\n//\n// If the request does not match any of this router's or its subrouters' routes\n// then this function returns false. If available, a reason for the match failure\n// will be filled in the match argument's MatchErr field. If the match failure type\n// (eg: not found) has a registered handler, the handler is assigned to the Handler\n// field of the match argument.\nfunc (r *Router) Match(req *http.Request, match *RouteMatch) bool {\n\tfor _, route := range r.routes {\n\t\tif route.Match(req, match) {\n\t\t\t// Build middleware chain if no error was found\n\t\t\tif match.MatchErr == nil {\n\t\t\t\tfor i := len(r.middlewares) - 1; i >= 0; i-- {\n\t\t\t\t\tmatch.Handler = r.middlewares[i].Middleware(match.Handler)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true\n\t\t}\n\t}\n\n\tif match.MatchErr == ErrMethodMismatch {\n\t\tif r.MethodNotAllowedHandler != nil {\n\t\t\tmatch.Handler = r.MethodNotAllowedHandler\n\t\t\treturn true\n\t\t} else {\n\t\t\treturn false\n\t\t}\n\t}\n\n\t// Closest match for a router (includes sub-routers)\n\tif r.NotFoundHandler != nil {\n\t\tmatch.Handler = r.NotFoundHandler\n\t\tmatch.MatchErr = ErrNotFound\n\t\treturn true\n\t}\n\n\tmatch.MatchErr = ErrNotFound\n\treturn false\n}\n\n// ServeHTTP dispatches the handler registered in the matched route.\n//\n// When there is a match, the route variables can be retrieved calling\n// mux.Vars(request).\nfunc (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {\n\tif !r.skipClean {\n\t\tpath := req.URL.Path\n\t\tif r.useEncodedPath {\n\t\t\tpath = req.URL.EscapedPath()\n\t\t}\n\t\t// Clean path to canonical form and redirect.\n\t\tif p := cleanPath(path); p != path {\n\n\t\t\t// Added 3 lines (Philip Schlump) - It was dropping the query string and #whatever from query.\n\t\t\t// This matches with fix in go 1.2 r.c. 4 for same problem.  Go Issue:\n\t\t\t// http://code.google.com/p/go/issues/detail?id=5252\n\t\t\turl := *req.URL\n\t\t\turl.Path = p\n\t\t\tp = url.String()\n\n\t\t\tw.Header().Set(\"Location\", p)\n\t\t\tw.WriteHeader(http.StatusMovedPermanently)\n\t\t\treturn\n\t\t}\n\t}\n\tvar match RouteMatch\n\tvar handler http.Handler\n\tif r.Match(req, &match) {\n\t\thandler = match.Handler\n\t\treq = setVars(req, match.Vars)\n\t\treq = setCurrentRoute(req, match.Route)\n\t}\n\n\tif handler == nil && match.MatchErr == ErrMethodMismatch {\n\t\thandler = methodNotAllowedHandler()\n\t}\n\n\tif handler == nil {\n\t\thandler = http.NotFoundHandler()\n\t}\n\n\tif !r.KeepContext {\n\t\tdefer contextClear(req)\n\t}\n\n\thandler.ServeHTTP(w, req)\n}\n\n// Get returns a route registered with the given name.\nfunc (r *Router) Get(name string) *Route {\n\treturn r.getNamedRoutes()[name]\n}\n\n// GetRoute returns a route registered with the given name. This method\n// was renamed to Get() and remains here for backwards compatibility.\nfunc (r *Router) GetRoute(name string) *Route {\n\treturn r.getNamedRoutes()[name]\n}\n\n// StrictSlash defines the trailing slash behavior for new routes. The initial\n// value is false.\n//\n// When true, if the route path is \"/path/\", accessing \"/path\" will perform a redirect\n// to the former and vice versa. In other words, your application will always\n// see the path as specified in the route.\n//\n// When false, if the route path is \"/path\", accessing \"/path/\" will not match\n// this route and vice versa.\n//\n// The re-direct is a HTTP 301 (Moved Permanently). Note that when this is set for\n// routes with a non-idempotent method (e.g. POST, PUT), the subsequent re-directed\n// request will be made as a GET by most clients. Use middleware or client settings\n// to modify this behaviour as needed.\n//\n// Special case: when a route sets a path prefix using the PathPrefix() method,\n// strict slash is ignored for that route because the redirect behavior can't\n// be determined from a prefix alone. However, any subrouters created from that\n// route inherit the original StrictSlash setting.\nfunc (r *Router) StrictSlash(value bool) *Router {\n\tr.strictSlash = value\n\treturn r\n}\n\n// SkipClean defines the path cleaning behaviour for new routes. The initial\n// value is false. Users should be careful about which routes are not cleaned\n//\n// When true, if the route path is \"/path//to\", it will remain with the double\n// slash. This is helpful if you have a route like: /fetch/http://xkcd.com/534/\n//\n// When false, the path will be cleaned, so /fetch/http://xkcd.com/534/ will\n// become /fetch/http/xkcd.com/534\nfunc (r *Router) SkipClean(value bool) *Router {\n\tr.skipClean = value\n\treturn r\n}\n\n// UseEncodedPath tells the router to match the encoded original path\n// to the routes.\n// For eg. \"/path/foo%2Fbar/to\" will match the path \"/path/{var}/to\".\n//\n// If not called, the router will match the unencoded path to the routes.\n// For eg. \"/path/foo%2Fbar/to\" will match the path \"/path/foo/bar/to\"\nfunc (r *Router) UseEncodedPath() *Router {\n\tr.useEncodedPath = true\n\treturn r\n}\n\n// ----------------------------------------------------------------------------\n// parentRoute\n// ----------------------------------------------------------------------------\n\nfunc (r *Router) getBuildScheme() string {\n\tif r.parent != nil {\n\t\treturn r.parent.getBuildScheme()\n\t}\n\treturn \"\"\n}\n\n// getNamedRoutes returns the map where named routes are registered.\nfunc (r *Router) getNamedRoutes() map[string]*Route {\n\tif r.namedRoutes == nil {\n\t\tif r.parent != nil {\n\t\t\tr.namedRoutes = r.parent.getNamedRoutes()\n\t\t} else {\n\t\t\tr.namedRoutes = make(map[string]*Route)\n\t\t}\n\t}\n\treturn r.namedRoutes\n}\n\n// getRegexpGroup returns regexp definitions from the parent route, if any.\nfunc (r *Router) getRegexpGroup() *routeRegexpGroup {\n\tif r.parent != nil {\n\t\treturn r.parent.getRegexpGroup()\n\t}\n\treturn nil\n}\n\nfunc (r *Router) buildVars(m map[string]string) map[string]string {\n\tif r.parent != nil {\n\t\tm = r.parent.buildVars(m)\n\t}\n\treturn m\n}\n\n// ----------------------------------------------------------------------------\n// Route factories\n// ----------------------------------------------------------------------------\n\n// NewRoute registers an empty route.\nfunc (r *Router) NewRoute() *Route {\n\troute := &Route{parent: r, strictSlash: r.strictSlash, skipClean: r.skipClean, useEncodedPath: r.useEncodedPath}\n\tr.routes = append(r.routes, route)\n\treturn route\n}\n\n// Handle registers a new route with a matcher for the URL path.\n// See Route.Path() and Route.Handler().\nfunc (r *Router) Handle(path string, handler http.Handler) *Route {\n\treturn r.NewRoute().Path(path).Handler(handler)\n}\n\n// HandleFunc registers a new route with a matcher for the URL path.\n// See Route.Path() and Route.HandlerFunc().\nfunc (r *Router) HandleFunc(path string, f func(http.ResponseWriter,\n\t*http.Request)) *Route {\n\treturn r.NewRoute().Path(path).HandlerFunc(f)\n}\n\n// Headers registers a new route with a matcher for request header values.\n// See Route.Headers().\nfunc (r *Router) Headers(pairs ...string) *Route {\n\treturn r.NewRoute().Headers(pairs...)\n}\n\n// Host registers a new route with a matcher for the URL host.\n// See Route.Host().\nfunc (r *Router) Host(tpl string) *Route {\n\treturn r.NewRoute().Host(tpl)\n}\n\n// MatcherFunc registers a new route with a custom matcher function.\n// See Route.MatcherFunc().\nfunc (r *Router) MatcherFunc(f MatcherFunc) *Route {\n\treturn r.NewRoute().MatcherFunc(f)\n}\n\n// Methods registers a new route with a matcher for HTTP methods.\n// See Route.Methods().\nfunc (r *Router) Methods(methods ...string) *Route {\n\treturn r.NewRoute().Methods(methods...)\n}\n\n// Path registers a new route with a matcher for the URL path.\n// See Route.Path().\nfunc (r *Router) Path(tpl string) *Route {\n\treturn r.NewRoute().Path(tpl)\n}\n\n// PathPrefix registers a new route with a matcher for the URL path prefix.\n// See Route.PathPrefix().\nfunc (r *Router) PathPrefix(tpl string) *Route {\n\treturn r.NewRoute().PathPrefix(tpl)\n}\n\n// Queries registers a new route with a matcher for URL query values.\n// See Route.Queries().\nfunc (r *Router) Queries(pairs ...string) *Route {\n\treturn r.NewRoute().Queries(pairs...)\n}\n\n// Schemes registers a new route with a matcher for URL schemes.\n// See Route.Schemes().\nfunc (r *Router) Schemes(schemes ...string) *Route {\n\treturn r.NewRoute().Schemes(schemes...)\n}\n\n// BuildVarsFunc registers a new route with a custom function for modifying\n// route variables before building a URL.\nfunc (r *Router) BuildVarsFunc(f BuildVarsFunc) *Route {\n\treturn r.NewRoute().BuildVarsFunc(f)\n}\n\n// Walk walks the router and all its sub-routers, calling walkFn for each route\n// in the tree. The routes are walked in the order they were added. Sub-routers\n// are explored depth-first.\nfunc (r *Router) Walk(walkFn WalkFunc) error {\n\treturn r.walk(walkFn, []*Route{})\n}\n\n// SkipRouter is used as a return value from WalkFuncs to indicate that the\n// router that walk is about to descend down to should be skipped.\nvar SkipRouter = errors.New(\"skip this router\")\n\n// WalkFunc is the type of the function called for each route visited by Walk.\n// At every invocation, it is given the current route, and the current router,\n// and a list of ancestor routes that lead to the current route.\ntype WalkFunc func(route *Route, router *Router, ancestors []*Route) error\n\nfunc (r *Router) walk(walkFn WalkFunc, ancestors []*Route) error {\n\tfor _, t := range r.routes {\n\t\terr := walkFn(t, r, ancestors)\n\t\tif err == SkipRouter {\n\t\t\tcontinue\n\t\t}\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfor _, sr := range t.matchers {\n\t\t\tif h, ok := sr.(*Router); ok {\n\t\t\t\tancestors = append(ancestors, t)\n\t\t\t\terr := h.walk(walkFn, ancestors)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tancestors = ancestors[:len(ancestors)-1]\n\t\t\t}\n\t\t}\n\t\tif h, ok := t.handler.(*Router); ok {\n\t\t\tancestors = append(ancestors, t)\n\t\t\terr := h.walk(walkFn, ancestors)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tancestors = ancestors[:len(ancestors)-1]\n\t\t}\n\t}\n\treturn nil\n}\n\n// ----------------------------------------------------------------------------\n// Context\n// ----------------------------------------------------------------------------\n\n// RouteMatch stores information about a matched route.\ntype RouteMatch struct {\n\tRoute   *Route\n\tHandler http.Handler\n\tVars    map[string]string\n\n\t// MatchErr is set to appropriate matching error\n\t// It is set to ErrMethodMismatch if there is a mismatch in\n\t// the request method and route method\n\tMatchErr error\n}\n\ntype contextKey int\n\nconst (\n\tvarsKey contextKey = iota\n\trouteKey\n)\n\n// Vars returns the route variables for the current request, if any.\nfunc Vars(r *http.Request) map[string]string {\n\tif rv := contextGet(r, varsKey); rv != nil {\n\t\treturn rv.(map[string]string)\n\t}\n\treturn nil\n}\n\n// CurrentRoute returns the matched route for the current request, if any.\n// This only works when called inside the handler of the matched route\n// because the matched route is stored in the request context which is cleared\n// after the handler returns, unless the KeepContext option is set on the\n// Router.\nfunc CurrentRoute(r *http.Request) *Route {\n\tif rv := contextGet(r, routeKey); rv != nil {\n\t\treturn rv.(*Route)\n\t}\n\treturn nil\n}\n\nfunc setVars(r *http.Request, val interface{}) *http.Request {\n\treturn contextSet(r, varsKey, val)\n}\n\nfunc setCurrentRoute(r *http.Request, val interface{}) *http.Request {\n\treturn contextSet(r, routeKey, val)\n}\n\n// ----------------------------------------------------------------------------\n// Helpers\n// ----------------------------------------------------------------------------\n\n// cleanPath returns the canonical path for p, eliminating . and .. elements.\n// Borrowed from the net/http package.\nfunc cleanPath(p string) string {\n\tif p == \"\" {\n\t\treturn \"/\"\n\t}\n\tif p[0] != '/' {\n\t\tp = \"/\" + p\n\t}\n\tnp := path.Clean(p)\n\t// path.Clean removes trailing slash except for root;\n\t// put the trailing slash back if necessary.\n\tif p[len(p)-1] == '/' && np != \"/\" {\n\t\tnp += \"/\"\n\t}\n\n\treturn np\n}\n\n// uniqueVars returns an error if two slices contain duplicated strings.\nfunc uniqueVars(s1, s2 []string) error {\n\tfor _, v1 := range s1 {\n\t\tfor _, v2 := range s2 {\n\t\t\tif v1 == v2 {\n\t\t\t\treturn fmt.Errorf(\"mux: duplicated route variable %q\", v2)\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// checkPairs returns the count of strings passed in, and an error if\n// the count is not an even number.\nfunc checkPairs(pairs ...string) (int, error) {\n\tlength := len(pairs)\n\tif length%2 != 0 {\n\t\treturn length, fmt.Errorf(\n\t\t\t\"mux: number of parameters must be multiple of 2, got %v\", pairs)\n\t}\n\treturn length, nil\n}\n\n// mapFromPairsToString converts variadic string parameters to a\n// string to string map.\nfunc mapFromPairsToString(pairs ...string) (map[string]string, error) {\n\tlength, err := checkPairs(pairs...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tm := make(map[string]string, length/2)\n\tfor i := 0; i < length; i += 2 {\n\t\tm[pairs[i]] = pairs[i+1]\n\t}\n\treturn m, nil\n}\n\n// mapFromPairsToRegex converts variadic string parameters to a\n// string to regex map.\nfunc mapFromPairsToRegex(pairs ...string) (map[string]*regexp.Regexp, error) {\n\tlength, err := checkPairs(pairs...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tm := make(map[string]*regexp.Regexp, length/2)\n\tfor i := 0; i < length; i += 2 {\n\t\tregex, err := regexp.Compile(pairs[i+1])\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tm[pairs[i]] = regex\n\t}\n\treturn m, nil\n}\n\n// matchInArray returns true if the given string value is in the array.\nfunc matchInArray(arr []string, value string) bool {\n\tfor _, v := range arr {\n\t\tif v == value {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// matchMapWithString returns true if the given key/value pairs exist in a given map.\nfunc matchMapWithString(toCheck map[string]string, toMatch map[string][]string, canonicalKey bool) bool {\n\tfor k, v := range toCheck {\n\t\t// Check if key exists.\n\t\tif canonicalKey {\n\t\t\tk = http.CanonicalHeaderKey(k)\n\t\t}\n\t\tif values := toMatch[k]; values == nil {\n\t\t\treturn false\n\t\t} else if v != \"\" {\n\t\t\t// If value was defined as an empty string we only check that the\n\t\t\t// key exists. Otherwise we also check for equality.\n\t\t\tvalueExists := false\n\t\t\tfor _, value := range values {\n\t\t\t\tif v == value {\n\t\t\t\t\tvalueExists = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif !valueExists {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\treturn true\n}\n\n// matchMapWithRegex returns true if the given key/value pairs exist in a given map compiled against\n// the given regex\nfunc matchMapWithRegex(toCheck map[string]*regexp.Regexp, toMatch map[string][]string, canonicalKey bool) bool {\n\tfor k, v := range toCheck {\n\t\t// Check if key exists.\n\t\tif canonicalKey {\n\t\t\tk = http.CanonicalHeaderKey(k)\n\t\t}\n\t\tif values := toMatch[k]; values == nil {\n\t\t\treturn false\n\t\t} else if v != nil {\n\t\t\t// If value was defined as an empty string we only check that the\n\t\t\t// key exists. Otherwise we also check for equality.\n\t\t\tvalueExists := false\n\t\t\tfor _, value := range values {\n\t\t\t\tif v.MatchString(value) {\n\t\t\t\t\tvalueExists = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif !valueExists {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\treturn true\n}\n\n// methodNotAllowed replies to the request with an HTTP status code 405.\nfunc methodNotAllowed(w http.ResponseWriter, r *http.Request) {\n\tw.WriteHeader(http.StatusMethodNotAllowed)\n}\n\n// methodNotAllowedHandler returns a simple request handler\n// that replies to each request with a status code 405.\nfunc methodNotAllowedHandler() http.Handler { return http.HandlerFunc(methodNotAllowed) }\n"
  },
  {
    "path": "vendor/github.com/gorilla/mux/regexp.go",
    "content": "// Copyright 2012 The Gorilla Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage mux\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n)\n\ntype routeRegexpOptions struct {\n\tstrictSlash    bool\n\tuseEncodedPath bool\n}\n\ntype regexpType int\n\nconst (\n\tregexpTypePath   regexpType = 0\n\tregexpTypeHost   regexpType = 1\n\tregexpTypePrefix regexpType = 2\n\tregexpTypeQuery  regexpType = 3\n)\n\n// newRouteRegexp parses a route template and returns a routeRegexp,\n// used to match a host, a path or a query string.\n//\n// It will extract named variables, assemble a regexp to be matched, create\n// a \"reverse\" template to build URLs and compile regexps to validate variable\n// values used in URL building.\n//\n// Previously we accepted only Python-like identifiers for variable\n// names ([a-zA-Z_][a-zA-Z0-9_]*), but currently the only restriction is that\n// name and pattern can't be empty, and names can't contain a colon.\nfunc newRouteRegexp(tpl string, typ regexpType, options routeRegexpOptions) (*routeRegexp, error) {\n\t// Check if it is well-formed.\n\tidxs, errBraces := braceIndices(tpl)\n\tif errBraces != nil {\n\t\treturn nil, errBraces\n\t}\n\t// Backup the original.\n\ttemplate := tpl\n\t// Now let's parse it.\n\tdefaultPattern := \"[^/]+\"\n\tif typ == regexpTypeQuery {\n\t\tdefaultPattern = \".*\"\n\t} else if typ == regexpTypeHost {\n\t\tdefaultPattern = \"[^.]+\"\n\t}\n\t// Only match strict slash if not matching\n\tif typ != regexpTypePath {\n\t\toptions.strictSlash = false\n\t}\n\t// Set a flag for strictSlash.\n\tendSlash := false\n\tif options.strictSlash && strings.HasSuffix(tpl, \"/\") {\n\t\ttpl = tpl[:len(tpl)-1]\n\t\tendSlash = true\n\t}\n\tvarsN := make([]string, len(idxs)/2)\n\tvarsR := make([]*regexp.Regexp, len(idxs)/2)\n\tpattern := bytes.NewBufferString(\"\")\n\tpattern.WriteByte('^')\n\treverse := bytes.NewBufferString(\"\")\n\tvar end int\n\tvar err error\n\tfor i := 0; i < len(idxs); i += 2 {\n\t\t// Set all values we are interested in.\n\t\traw := tpl[end:idxs[i]]\n\t\tend = idxs[i+1]\n\t\tparts := strings.SplitN(tpl[idxs[i]+1:end-1], \":\", 2)\n\t\tname := parts[0]\n\t\tpatt := defaultPattern\n\t\tif len(parts) == 2 {\n\t\t\tpatt = parts[1]\n\t\t}\n\t\t// Name or pattern can't be empty.\n\t\tif name == \"\" || patt == \"\" {\n\t\t\treturn nil, fmt.Errorf(\"mux: missing name or pattern in %q\",\n\t\t\t\ttpl[idxs[i]:end])\n\t\t}\n\t\t// Build the regexp pattern.\n\t\tfmt.Fprintf(pattern, \"%s(?P<%s>%s)\", regexp.QuoteMeta(raw), varGroupName(i/2), patt)\n\n\t\t// Build the reverse template.\n\t\tfmt.Fprintf(reverse, \"%s%%s\", raw)\n\n\t\t// Append variable name and compiled pattern.\n\t\tvarsN[i/2] = name\n\t\tvarsR[i/2], err = regexp.Compile(fmt.Sprintf(\"^%s$\", patt))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\t// Add the remaining.\n\traw := tpl[end:]\n\tpattern.WriteString(regexp.QuoteMeta(raw))\n\tif options.strictSlash {\n\t\tpattern.WriteString(\"[/]?\")\n\t}\n\tif typ == regexpTypeQuery {\n\t\t// Add the default pattern if the query value is empty\n\t\tif queryVal := strings.SplitN(template, \"=\", 2)[1]; queryVal == \"\" {\n\t\t\tpattern.WriteString(defaultPattern)\n\t\t}\n\t}\n\tif typ != regexpTypePrefix {\n\t\tpattern.WriteByte('$')\n\t}\n\treverse.WriteString(raw)\n\tif endSlash {\n\t\treverse.WriteByte('/')\n\t}\n\t// Compile full regexp.\n\treg, errCompile := regexp.Compile(pattern.String())\n\tif errCompile != nil {\n\t\treturn nil, errCompile\n\t}\n\n\t// Check for capturing groups which used to work in older versions\n\tif reg.NumSubexp() != len(idxs)/2 {\n\t\tpanic(fmt.Sprintf(\"route %s contains capture groups in its regexp. \", template) +\n\t\t\t\"Only non-capturing groups are accepted: e.g. (?:pattern) instead of (pattern)\")\n\t}\n\n\t// Done!\n\treturn &routeRegexp{\n\t\ttemplate:   template,\n\t\tregexpType: typ,\n\t\toptions:    options,\n\t\tregexp:     reg,\n\t\treverse:    reverse.String(),\n\t\tvarsN:      varsN,\n\t\tvarsR:      varsR,\n\t}, nil\n}\n\n// routeRegexp stores a regexp to match a host or path and information to\n// collect and validate route variables.\ntype routeRegexp struct {\n\t// The unmodified template.\n\ttemplate string\n\t// The type of match\n\tregexpType regexpType\n\t// Options for matching\n\toptions routeRegexpOptions\n\t// Expanded regexp.\n\tregexp *regexp.Regexp\n\t// Reverse template.\n\treverse string\n\t// Variable names.\n\tvarsN []string\n\t// Variable regexps (validators).\n\tvarsR []*regexp.Regexp\n}\n\n// Match matches the regexp against the URL host or path.\nfunc (r *routeRegexp) Match(req *http.Request, match *RouteMatch) bool {\n\tif r.regexpType != regexpTypeHost {\n\t\tif r.regexpType == regexpTypeQuery {\n\t\t\treturn r.matchQueryString(req)\n\t\t}\n\t\tpath := req.URL.Path\n\t\tif r.options.useEncodedPath {\n\t\t\tpath = req.URL.EscapedPath()\n\t\t}\n\t\treturn r.regexp.MatchString(path)\n\t}\n\n\treturn r.regexp.MatchString(getHost(req))\n}\n\n// url builds a URL part using the given values.\nfunc (r *routeRegexp) url(values map[string]string) (string, error) {\n\turlValues := make([]interface{}, len(r.varsN))\n\tfor k, v := range r.varsN {\n\t\tvalue, ok := values[v]\n\t\tif !ok {\n\t\t\treturn \"\", fmt.Errorf(\"mux: missing route variable %q\", v)\n\t\t}\n\t\tif r.regexpType == regexpTypeQuery {\n\t\t\tvalue = url.QueryEscape(value)\n\t\t}\n\t\turlValues[k] = value\n\t}\n\trv := fmt.Sprintf(r.reverse, urlValues...)\n\tif !r.regexp.MatchString(rv) {\n\t\t// The URL is checked against the full regexp, instead of checking\n\t\t// individual variables. This is faster but to provide a good error\n\t\t// message, we check individual regexps if the URL doesn't match.\n\t\tfor k, v := range r.varsN {\n\t\t\tif !r.varsR[k].MatchString(values[v]) {\n\t\t\t\treturn \"\", fmt.Errorf(\n\t\t\t\t\t\"mux: variable %q doesn't match, expected %q\", values[v],\n\t\t\t\t\tr.varsR[k].String())\n\t\t\t}\n\t\t}\n\t}\n\treturn rv, nil\n}\n\n// getURLQuery returns a single query parameter from a request URL.\n// For a URL with foo=bar&baz=ding, we return only the relevant key\n// value pair for the routeRegexp.\nfunc (r *routeRegexp) getURLQuery(req *http.Request) string {\n\tif r.regexpType != regexpTypeQuery {\n\t\treturn \"\"\n\t}\n\ttemplateKey := strings.SplitN(r.template, \"=\", 2)[0]\n\tfor key, vals := range req.URL.Query() {\n\t\tif key == templateKey && len(vals) > 0 {\n\t\t\treturn key + \"=\" + vals[0]\n\t\t}\n\t}\n\treturn \"\"\n}\n\nfunc (r *routeRegexp) matchQueryString(req *http.Request) bool {\n\treturn r.regexp.MatchString(r.getURLQuery(req))\n}\n\n// braceIndices returns the first level curly brace indices from a string.\n// It returns an error in case of unbalanced braces.\nfunc braceIndices(s string) ([]int, error) {\n\tvar level, idx int\n\tvar idxs []int\n\tfor i := 0; i < len(s); i++ {\n\t\tswitch s[i] {\n\t\tcase '{':\n\t\t\tif level++; level == 1 {\n\t\t\t\tidx = i\n\t\t\t}\n\t\tcase '}':\n\t\t\tif level--; level == 0 {\n\t\t\t\tidxs = append(idxs, idx, i+1)\n\t\t\t} else if level < 0 {\n\t\t\t\treturn nil, fmt.Errorf(\"mux: unbalanced braces in %q\", s)\n\t\t\t}\n\t\t}\n\t}\n\tif level != 0 {\n\t\treturn nil, fmt.Errorf(\"mux: unbalanced braces in %q\", s)\n\t}\n\treturn idxs, nil\n}\n\n// varGroupName builds a capturing group name for the indexed variable.\nfunc varGroupName(idx int) string {\n\treturn \"v\" + strconv.Itoa(idx)\n}\n\n// ----------------------------------------------------------------------------\n// routeRegexpGroup\n// ----------------------------------------------------------------------------\n\n// routeRegexpGroup groups the route matchers that carry variables.\ntype routeRegexpGroup struct {\n\thost    *routeRegexp\n\tpath    *routeRegexp\n\tqueries []*routeRegexp\n}\n\n// setMatch extracts the variables from the URL once a route matches.\nfunc (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route) {\n\t// Store host variables.\n\tif v.host != nil {\n\t\thost := getHost(req)\n\t\tmatches := v.host.regexp.FindStringSubmatchIndex(host)\n\t\tif len(matches) > 0 {\n\t\t\textractVars(host, matches, v.host.varsN, m.Vars)\n\t\t}\n\t}\n\tpath := req.URL.Path\n\tif r.useEncodedPath {\n\t\tpath = req.URL.EscapedPath()\n\t}\n\t// Store path variables.\n\tif v.path != nil {\n\t\tmatches := v.path.regexp.FindStringSubmatchIndex(path)\n\t\tif len(matches) > 0 {\n\t\t\textractVars(path, matches, v.path.varsN, m.Vars)\n\t\t\t// Check if we should redirect.\n\t\t\tif v.path.options.strictSlash {\n\t\t\t\tp1 := strings.HasSuffix(path, \"/\")\n\t\t\t\tp2 := strings.HasSuffix(v.path.template, \"/\")\n\t\t\t\tif p1 != p2 {\n\t\t\t\t\tu, _ := url.Parse(req.URL.String())\n\t\t\t\t\tif p1 {\n\t\t\t\t\t\tu.Path = u.Path[:len(u.Path)-1]\n\t\t\t\t\t} else {\n\t\t\t\t\t\tu.Path += \"/\"\n\t\t\t\t\t}\n\t\t\t\t\tm.Handler = http.RedirectHandler(u.String(), 301)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t// Store query string variables.\n\tfor _, q := range v.queries {\n\t\tqueryURL := q.getURLQuery(req)\n\t\tmatches := q.regexp.FindStringSubmatchIndex(queryURL)\n\t\tif len(matches) > 0 {\n\t\t\textractVars(queryURL, matches, q.varsN, m.Vars)\n\t\t}\n\t}\n}\n\n// getHost tries its best to return the request host.\nfunc getHost(r *http.Request) string {\n\tif r.URL.IsAbs() {\n\t\treturn r.URL.Host\n\t}\n\thost := r.Host\n\t// Slice off any port information.\n\tif i := strings.Index(host, \":\"); i != -1 {\n\t\thost = host[:i]\n\t}\n\treturn host\n\n}\n\nfunc extractVars(input string, matches []int, names []string, output map[string]string) {\n\tfor i, name := range names {\n\t\toutput[name] = input[matches[2*i+2]:matches[2*i+3]]\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/gorilla/mux/route.go",
    "content": "// Copyright 2012 The Gorilla Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage mux\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"regexp\"\n\t\"strings\"\n)\n\n// Route stores information to match a request and build URLs.\ntype Route struct {\n\t// Parent where the route was registered (a Router).\n\tparent parentRoute\n\t// Request handler for the route.\n\thandler http.Handler\n\t// List of matchers.\n\tmatchers []matcher\n\t// Manager for the variables from host and path.\n\tregexp *routeRegexpGroup\n\t// If true, when the path pattern is \"/path/\", accessing \"/path\" will\n\t// redirect to the former and vice versa.\n\tstrictSlash bool\n\t// If true, when the path pattern is \"/path//to\", accessing \"/path//to\"\n\t// will not redirect\n\tskipClean bool\n\t// If true, \"/path/foo%2Fbar/to\" will match the path \"/path/{var}/to\"\n\tuseEncodedPath bool\n\t// The scheme used when building URLs.\n\tbuildScheme string\n\t// If true, this route never matches: it is only used to build URLs.\n\tbuildOnly bool\n\t// The name used to build URLs.\n\tname string\n\t// Error resulted from building a route.\n\terr error\n\n\tbuildVarsFunc BuildVarsFunc\n}\n\nfunc (r *Route) SkipClean() bool {\n\treturn r.skipClean\n}\n\n// Match matches the route against the request.\nfunc (r *Route) Match(req *http.Request, match *RouteMatch) bool {\n\tif r.buildOnly || r.err != nil {\n\t\treturn false\n\t}\n\n\tvar matchErr error\n\n\t// Match everything.\n\tfor _, m := range r.matchers {\n\t\tif matched := m.Match(req, match); !matched {\n\t\t\tif _, ok := m.(methodMatcher); ok {\n\t\t\t\tmatchErr = ErrMethodMismatch\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tmatchErr = nil\n\t\t\treturn false\n\t\t}\n\t}\n\n\tif matchErr != nil {\n\t\tmatch.MatchErr = matchErr\n\t\treturn false\n\t}\n\n\tif match.MatchErr == ErrMethodMismatch {\n\t\t// We found a route which matches request method, clear MatchErr\n\t\tmatch.MatchErr = nil\n\t\t// Then override the mis-matched handler\n\t\tmatch.Handler = r.handler\n\t}\n\n\t// Yay, we have a match. Let's collect some info about it.\n\tif match.Route == nil {\n\t\tmatch.Route = r\n\t}\n\tif match.Handler == nil {\n\t\tmatch.Handler = r.handler\n\t}\n\tif match.Vars == nil {\n\t\tmatch.Vars = make(map[string]string)\n\t}\n\n\t// Set variables.\n\tif r.regexp != nil {\n\t\tr.regexp.setMatch(req, match, r)\n\t}\n\treturn true\n}\n\n// ----------------------------------------------------------------------------\n// Route attributes\n// ----------------------------------------------------------------------------\n\n// GetError returns an error resulted from building the route, if any.\nfunc (r *Route) GetError() error {\n\treturn r.err\n}\n\n// BuildOnly sets the route to never match: it is only used to build URLs.\nfunc (r *Route) BuildOnly() *Route {\n\tr.buildOnly = true\n\treturn r\n}\n\n// Handler --------------------------------------------------------------------\n\n// Handler sets a handler for the route.\nfunc (r *Route) Handler(handler http.Handler) *Route {\n\tif r.err == nil {\n\t\tr.handler = handler\n\t}\n\treturn r\n}\n\n// HandlerFunc sets a handler function for the route.\nfunc (r *Route) HandlerFunc(f func(http.ResponseWriter, *http.Request)) *Route {\n\treturn r.Handler(http.HandlerFunc(f))\n}\n\n// GetHandler returns the handler for the route, if any.\nfunc (r *Route) GetHandler() http.Handler {\n\treturn r.handler\n}\n\n// Name -----------------------------------------------------------------------\n\n// Name sets the name for the route, used to build URLs.\n// If the name was registered already it will be overwritten.\nfunc (r *Route) Name(name string) *Route {\n\tif r.name != \"\" {\n\t\tr.err = fmt.Errorf(\"mux: route already has name %q, can't set %q\",\n\t\t\tr.name, name)\n\t}\n\tif r.err == nil {\n\t\tr.name = name\n\t\tr.getNamedRoutes()[name] = r\n\t}\n\treturn r\n}\n\n// GetName returns the name for the route, if any.\nfunc (r *Route) GetName() string {\n\treturn r.name\n}\n\n// ----------------------------------------------------------------------------\n// Matchers\n// ----------------------------------------------------------------------------\n\n// matcher types try to match a request.\ntype matcher interface {\n\tMatch(*http.Request, *RouteMatch) bool\n}\n\n// addMatcher adds a matcher to the route.\nfunc (r *Route) addMatcher(m matcher) *Route {\n\tif r.err == nil {\n\t\tr.matchers = append(r.matchers, m)\n\t}\n\treturn r\n}\n\n// addRegexpMatcher adds a host or path matcher and builder to a route.\nfunc (r *Route) addRegexpMatcher(tpl string, typ regexpType) error {\n\tif r.err != nil {\n\t\treturn r.err\n\t}\n\tr.regexp = r.getRegexpGroup()\n\tif typ == regexpTypePath || typ == regexpTypePrefix {\n\t\tif len(tpl) > 0 && tpl[0] != '/' {\n\t\t\treturn fmt.Errorf(\"mux: path must start with a slash, got %q\", tpl)\n\t\t}\n\t\tif r.regexp.path != nil {\n\t\t\ttpl = strings.TrimRight(r.regexp.path.template, \"/\") + tpl\n\t\t}\n\t}\n\trr, err := newRouteRegexp(tpl, typ, routeRegexpOptions{\n\t\tstrictSlash:    r.strictSlash,\n\t\tuseEncodedPath: r.useEncodedPath,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor _, q := range r.regexp.queries {\n\t\tif err = uniqueVars(rr.varsN, q.varsN); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif typ == regexpTypeHost {\n\t\tif r.regexp.path != nil {\n\t\t\tif err = uniqueVars(rr.varsN, r.regexp.path.varsN); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tr.regexp.host = rr\n\t} else {\n\t\tif r.regexp.host != nil {\n\t\t\tif err = uniqueVars(rr.varsN, r.regexp.host.varsN); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tif typ == regexpTypeQuery {\n\t\t\tr.regexp.queries = append(r.regexp.queries, rr)\n\t\t} else {\n\t\t\tr.regexp.path = rr\n\t\t}\n\t}\n\tr.addMatcher(rr)\n\treturn nil\n}\n\n// Headers --------------------------------------------------------------------\n\n// headerMatcher matches the request against header values.\ntype headerMatcher map[string]string\n\nfunc (m headerMatcher) Match(r *http.Request, match *RouteMatch) bool {\n\treturn matchMapWithString(m, r.Header, true)\n}\n\n// Headers adds a matcher for request header values.\n// It accepts a sequence of key/value pairs to be matched. For example:\n//\n//     r := mux.NewRouter()\n//     r.Headers(\"Content-Type\", \"application/json\",\n//               \"X-Requested-With\", \"XMLHttpRequest\")\n//\n// The above route will only match if both request header values match.\n// If the value is an empty string, it will match any value if the key is set.\nfunc (r *Route) Headers(pairs ...string) *Route {\n\tif r.err == nil {\n\t\tvar headers map[string]string\n\t\theaders, r.err = mapFromPairsToString(pairs...)\n\t\treturn r.addMatcher(headerMatcher(headers))\n\t}\n\treturn r\n}\n\n// headerRegexMatcher matches the request against the route given a regex for the header\ntype headerRegexMatcher map[string]*regexp.Regexp\n\nfunc (m headerRegexMatcher) Match(r *http.Request, match *RouteMatch) bool {\n\treturn matchMapWithRegex(m, r.Header, true)\n}\n\n// HeadersRegexp accepts a sequence of key/value pairs, where the value has regex\n// support. For example:\n//\n//     r := mux.NewRouter()\n//     r.HeadersRegexp(\"Content-Type\", \"application/(text|json)\",\n//               \"X-Requested-With\", \"XMLHttpRequest\")\n//\n// The above route will only match if both the request header matches both regular expressions.\n// If the value is an empty string, it will match any value if the key is set.\n// Use the start and end of string anchors (^ and $) to match an exact value.\nfunc (r *Route) HeadersRegexp(pairs ...string) *Route {\n\tif r.err == nil {\n\t\tvar headers map[string]*regexp.Regexp\n\t\theaders, r.err = mapFromPairsToRegex(pairs...)\n\t\treturn r.addMatcher(headerRegexMatcher(headers))\n\t}\n\treturn r\n}\n\n// Host -----------------------------------------------------------------------\n\n// Host adds a matcher for the URL host.\n// It accepts a template with zero or more URL variables enclosed by {}.\n// Variables can define an optional regexp pattern to be matched:\n//\n// - {name} matches anything until the next dot.\n//\n// - {name:pattern} matches the given regexp pattern.\n//\n// For example:\n//\n//     r := mux.NewRouter()\n//     r.Host(\"www.example.com\")\n//     r.Host(\"{subdomain}.domain.com\")\n//     r.Host(\"{subdomain:[a-z]+}.domain.com\")\n//\n// Variable names must be unique in a given route. They can be retrieved\n// calling mux.Vars(request).\nfunc (r *Route) Host(tpl string) *Route {\n\tr.err = r.addRegexpMatcher(tpl, regexpTypeHost)\n\treturn r\n}\n\n// MatcherFunc ----------------------------------------------------------------\n\n// MatcherFunc is the function signature used by custom matchers.\ntype MatcherFunc func(*http.Request, *RouteMatch) bool\n\n// Match returns the match for a given request.\nfunc (m MatcherFunc) Match(r *http.Request, match *RouteMatch) bool {\n\treturn m(r, match)\n}\n\n// MatcherFunc adds a custom function to be used as request matcher.\nfunc (r *Route) MatcherFunc(f MatcherFunc) *Route {\n\treturn r.addMatcher(f)\n}\n\n// Methods --------------------------------------------------------------------\n\n// methodMatcher matches the request against HTTP methods.\ntype methodMatcher []string\n\nfunc (m methodMatcher) Match(r *http.Request, match *RouteMatch) bool {\n\treturn matchInArray(m, r.Method)\n}\n\n// Methods adds a matcher for HTTP methods.\n// It accepts a sequence of one or more methods to be matched, e.g.:\n// \"GET\", \"POST\", \"PUT\".\nfunc (r *Route) Methods(methods ...string) *Route {\n\tfor k, v := range methods {\n\t\tmethods[k] = strings.ToUpper(v)\n\t}\n\treturn r.addMatcher(methodMatcher(methods))\n}\n\n// Path -----------------------------------------------------------------------\n\n// Path adds a matcher for the URL path.\n// It accepts a template with zero or more URL variables enclosed by {}. The\n// template must start with a \"/\".\n// Variables can define an optional regexp pattern to be matched:\n//\n// - {name} matches anything until the next slash.\n//\n// - {name:pattern} matches the given regexp pattern.\n//\n// For example:\n//\n//     r := mux.NewRouter()\n//     r.Path(\"/products/\").Handler(ProductsHandler)\n//     r.Path(\"/products/{key}\").Handler(ProductsHandler)\n//     r.Path(\"/articles/{category}/{id:[0-9]+}\").\n//       Handler(ArticleHandler)\n//\n// Variable names must be unique in a given route. They can be retrieved\n// calling mux.Vars(request).\nfunc (r *Route) Path(tpl string) *Route {\n\tr.err = r.addRegexpMatcher(tpl, regexpTypePath)\n\treturn r\n}\n\n// PathPrefix -----------------------------------------------------------------\n\n// PathPrefix adds a matcher for the URL path prefix. This matches if the given\n// template is a prefix of the full URL path. See Route.Path() for details on\n// the tpl argument.\n//\n// Note that it does not treat slashes specially (\"/foobar/\" will be matched by\n// the prefix \"/foo\") so you may want to use a trailing slash here.\n//\n// Also note that the setting of Router.StrictSlash() has no effect on routes\n// with a PathPrefix matcher.\nfunc (r *Route) PathPrefix(tpl string) *Route {\n\tr.err = r.addRegexpMatcher(tpl, regexpTypePrefix)\n\treturn r\n}\n\n// Query ----------------------------------------------------------------------\n\n// Queries adds a matcher for URL query values.\n// It accepts a sequence of key/value pairs. Values may define variables.\n// For example:\n//\n//     r := mux.NewRouter()\n//     r.Queries(\"foo\", \"bar\", \"id\", \"{id:[0-9]+}\")\n//\n// The above route will only match if the URL contains the defined queries\n// values, e.g.: ?foo=bar&id=42.\n//\n// It the value is an empty string, it will match any value if the key is set.\n//\n// Variables can define an optional regexp pattern to be matched:\n//\n// - {name} matches anything until the next slash.\n//\n// - {name:pattern} matches the given regexp pattern.\nfunc (r *Route) Queries(pairs ...string) *Route {\n\tlength := len(pairs)\n\tif length%2 != 0 {\n\t\tr.err = fmt.Errorf(\n\t\t\t\"mux: number of parameters must be multiple of 2, got %v\", pairs)\n\t\treturn nil\n\t}\n\tfor i := 0; i < length; i += 2 {\n\t\tif r.err = r.addRegexpMatcher(pairs[i]+\"=\"+pairs[i+1], regexpTypeQuery); r.err != nil {\n\t\t\treturn r\n\t\t}\n\t}\n\n\treturn r\n}\n\n// Schemes --------------------------------------------------------------------\n\n// schemeMatcher matches the request against URL schemes.\ntype schemeMatcher []string\n\nfunc (m schemeMatcher) Match(r *http.Request, match *RouteMatch) bool {\n\treturn matchInArray(m, r.URL.Scheme)\n}\n\n// Schemes adds a matcher for URL schemes.\n// It accepts a sequence of schemes to be matched, e.g.: \"http\", \"https\".\nfunc (r *Route) Schemes(schemes ...string) *Route {\n\tfor k, v := range schemes {\n\t\tschemes[k] = strings.ToLower(v)\n\t}\n\tif r.buildScheme == \"\" && len(schemes) > 0 {\n\t\tr.buildScheme = schemes[0]\n\t}\n\treturn r.addMatcher(schemeMatcher(schemes))\n}\n\n// BuildVarsFunc --------------------------------------------------------------\n\n// BuildVarsFunc is the function signature used by custom build variable\n// functions (which can modify route variables before a route's URL is built).\ntype BuildVarsFunc func(map[string]string) map[string]string\n\n// BuildVarsFunc adds a custom function to be used to modify build variables\n// before a route's URL is built.\nfunc (r *Route) BuildVarsFunc(f BuildVarsFunc) *Route {\n\tr.buildVarsFunc = f\n\treturn r\n}\n\n// Subrouter ------------------------------------------------------------------\n\n// Subrouter creates a subrouter for the route.\n//\n// It will test the inner routes only if the parent route matched. For example:\n//\n//     r := mux.NewRouter()\n//     s := r.Host(\"www.example.com\").Subrouter()\n//     s.HandleFunc(\"/products/\", ProductsHandler)\n//     s.HandleFunc(\"/products/{key}\", ProductHandler)\n//     s.HandleFunc(\"/articles/{category}/{id:[0-9]+}\"), ArticleHandler)\n//\n// Here, the routes registered in the subrouter won't be tested if the host\n// doesn't match.\nfunc (r *Route) Subrouter() *Router {\n\trouter := &Router{parent: r, strictSlash: r.strictSlash}\n\tr.addMatcher(router)\n\treturn router\n}\n\n// ----------------------------------------------------------------------------\n// URL building\n// ----------------------------------------------------------------------------\n\n// URL builds a URL for the route.\n//\n// It accepts a sequence of key/value pairs for the route variables. For\n// example, given this route:\n//\n//     r := mux.NewRouter()\n//     r.HandleFunc(\"/articles/{category}/{id:[0-9]+}\", ArticleHandler).\n//       Name(\"article\")\n//\n// ...a URL for it can be built using:\n//\n//     url, err := r.Get(\"article\").URL(\"category\", \"technology\", \"id\", \"42\")\n//\n// ...which will return an url.URL with the following path:\n//\n//     \"/articles/technology/42\"\n//\n// This also works for host variables:\n//\n//     r := mux.NewRouter()\n//     r.Host(\"{subdomain}.domain.com\").\n//       HandleFunc(\"/articles/{category}/{id:[0-9]+}\", ArticleHandler).\n//       Name(\"article\")\n//\n//     // url.String() will be \"http://news.domain.com/articles/technology/42\"\n//     url, err := r.Get(\"article\").URL(\"subdomain\", \"news\",\n//                                      \"category\", \"technology\",\n//                                      \"id\", \"42\")\n//\n// All variables defined in the route are required, and their values must\n// conform to the corresponding patterns.\nfunc (r *Route) URL(pairs ...string) (*url.URL, error) {\n\tif r.err != nil {\n\t\treturn nil, r.err\n\t}\n\tif r.regexp == nil {\n\t\treturn nil, errors.New(\"mux: route doesn't have a host or path\")\n\t}\n\tvalues, err := r.prepareVars(pairs...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar scheme, host, path string\n\tqueries := make([]string, 0, len(r.regexp.queries))\n\tif r.regexp.host != nil {\n\t\tif host, err = r.regexp.host.url(values); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tscheme = \"http\"\n\t\tif s := r.getBuildScheme(); s != \"\" {\n\t\t\tscheme = s\n\t\t}\n\t}\n\tif r.regexp.path != nil {\n\t\tif path, err = r.regexp.path.url(values); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tfor _, q := range r.regexp.queries {\n\t\tvar query string\n\t\tif query, err = q.url(values); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tqueries = append(queries, query)\n\t}\n\treturn &url.URL{\n\t\tScheme:   scheme,\n\t\tHost:     host,\n\t\tPath:     path,\n\t\tRawQuery: strings.Join(queries, \"&\"),\n\t}, nil\n}\n\n// URLHost builds the host part of the URL for a route. See Route.URL().\n//\n// The route must have a host defined.\nfunc (r *Route) URLHost(pairs ...string) (*url.URL, error) {\n\tif r.err != nil {\n\t\treturn nil, r.err\n\t}\n\tif r.regexp == nil || r.regexp.host == nil {\n\t\treturn nil, errors.New(\"mux: route doesn't have a host\")\n\t}\n\tvalues, err := r.prepareVars(pairs...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\thost, err := r.regexp.host.url(values)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tu := &url.URL{\n\t\tScheme: \"http\",\n\t\tHost:   host,\n\t}\n\tif s := r.getBuildScheme(); s != \"\" {\n\t\tu.Scheme = s\n\t}\n\treturn u, nil\n}\n\n// URLPath builds the path part of the URL for a route. See Route.URL().\n//\n// The route must have a path defined.\nfunc (r *Route) URLPath(pairs ...string) (*url.URL, error) {\n\tif r.err != nil {\n\t\treturn nil, r.err\n\t}\n\tif r.regexp == nil || r.regexp.path == nil {\n\t\treturn nil, errors.New(\"mux: route doesn't have a path\")\n\t}\n\tvalues, err := r.prepareVars(pairs...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tpath, err := r.regexp.path.url(values)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &url.URL{\n\t\tPath: path,\n\t}, nil\n}\n\n// GetPathTemplate returns the template used to build the\n// route match.\n// This is useful for building simple REST API documentation and for instrumentation\n// against third-party services.\n// An error will be returned if the route does not define a path.\nfunc (r *Route) GetPathTemplate() (string, error) {\n\tif r.err != nil {\n\t\treturn \"\", r.err\n\t}\n\tif r.regexp == nil || r.regexp.path == nil {\n\t\treturn \"\", errors.New(\"mux: route doesn't have a path\")\n\t}\n\treturn r.regexp.path.template, nil\n}\n\n// GetPathRegexp returns the expanded regular expression used to match route path.\n// This is useful for building simple REST API documentation and for instrumentation\n// against third-party services.\n// An error will be returned if the route does not define a path.\nfunc (r *Route) GetPathRegexp() (string, error) {\n\tif r.err != nil {\n\t\treturn \"\", r.err\n\t}\n\tif r.regexp == nil || r.regexp.path == nil {\n\t\treturn \"\", errors.New(\"mux: route does not have a path\")\n\t}\n\treturn r.regexp.path.regexp.String(), nil\n}\n\n// GetQueriesRegexp returns the expanded regular expressions used to match the\n// route queries.\n// This is useful for building simple REST API documentation and for instrumentation\n// against third-party services.\n// An error will be returned if the route does not have queries.\nfunc (r *Route) GetQueriesRegexp() ([]string, error) {\n\tif r.err != nil {\n\t\treturn nil, r.err\n\t}\n\tif r.regexp == nil || r.regexp.queries == nil {\n\t\treturn nil, errors.New(\"mux: route doesn't have queries\")\n\t}\n\tvar queries []string\n\tfor _, query := range r.regexp.queries {\n\t\tqueries = append(queries, query.regexp.String())\n\t}\n\treturn queries, nil\n}\n\n// GetQueriesTemplates returns the templates used to build the\n// query matching.\n// This is useful for building simple REST API documentation and for instrumentation\n// against third-party services.\n// An error will be returned if the route does not define queries.\nfunc (r *Route) GetQueriesTemplates() ([]string, error) {\n\tif r.err != nil {\n\t\treturn nil, r.err\n\t}\n\tif r.regexp == nil || r.regexp.queries == nil {\n\t\treturn nil, errors.New(\"mux: route doesn't have queries\")\n\t}\n\tvar queries []string\n\tfor _, query := range r.regexp.queries {\n\t\tqueries = append(queries, query.template)\n\t}\n\treturn queries, nil\n}\n\n// GetMethods returns the methods the route matches against\n// This is useful for building simple REST API documentation and for instrumentation\n// against third-party services.\n// An error will be returned if route does not have methods.\nfunc (r *Route) GetMethods() ([]string, error) {\n\tif r.err != nil {\n\t\treturn nil, r.err\n\t}\n\tfor _, m := range r.matchers {\n\t\tif methods, ok := m.(methodMatcher); ok {\n\t\t\treturn []string(methods), nil\n\t\t}\n\t}\n\treturn nil, errors.New(\"mux: route doesn't have methods\")\n}\n\n// GetHostTemplate returns the template used to build the\n// route match.\n// This is useful for building simple REST API documentation and for instrumentation\n// against third-party services.\n// An error will be returned if the route does not define a host.\nfunc (r *Route) GetHostTemplate() (string, error) {\n\tif r.err != nil {\n\t\treturn \"\", r.err\n\t}\n\tif r.regexp == nil || r.regexp.host == nil {\n\t\treturn \"\", errors.New(\"mux: route doesn't have a host\")\n\t}\n\treturn r.regexp.host.template, nil\n}\n\n// prepareVars converts the route variable pairs into a map. If the route has a\n// BuildVarsFunc, it is invoked.\nfunc (r *Route) prepareVars(pairs ...string) (map[string]string, error) {\n\tm, err := mapFromPairsToString(pairs...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn r.buildVars(m), nil\n}\n\nfunc (r *Route) buildVars(m map[string]string) map[string]string {\n\tif r.parent != nil {\n\t\tm = r.parent.buildVars(m)\n\t}\n\tif r.buildVarsFunc != nil {\n\t\tm = r.buildVarsFunc(m)\n\t}\n\treturn m\n}\n\n// ----------------------------------------------------------------------------\n// parentRoute\n// ----------------------------------------------------------------------------\n\n// parentRoute allows routes to know about parent host and path definitions.\ntype parentRoute interface {\n\tgetBuildScheme() string\n\tgetNamedRoutes() map[string]*Route\n\tgetRegexpGroup() *routeRegexpGroup\n\tbuildVars(map[string]string) map[string]string\n}\n\nfunc (r *Route) getBuildScheme() string {\n\tif r.buildScheme != \"\" {\n\t\treturn r.buildScheme\n\t}\n\tif r.parent != nil {\n\t\treturn r.parent.getBuildScheme()\n\t}\n\treturn \"\"\n}\n\n// getNamedRoutes returns the map where named routes are registered.\nfunc (r *Route) getNamedRoutes() map[string]*Route {\n\tif r.parent == nil {\n\t\t// During tests router is not always set.\n\t\tr.parent = NewRouter()\n\t}\n\treturn r.parent.getNamedRoutes()\n}\n\n// getRegexpGroup returns regexp definitions from this route.\nfunc (r *Route) getRegexpGroup() *routeRegexpGroup {\n\tif r.regexp == nil {\n\t\tif r.parent == nil {\n\t\t\t// During tests router is not always set.\n\t\t\tr.parent = NewRouter()\n\t\t}\n\t\tregexp := r.parent.getRegexpGroup()\n\t\tif regexp == nil {\n\t\t\tr.regexp = new(routeRegexpGroup)\n\t\t} else {\n\t\t\t// Copy.\n\t\t\tr.regexp = &routeRegexpGroup{\n\t\t\t\thost:    regexp.host,\n\t\t\t\tpath:    regexp.path,\n\t\t\t\tqueries: regexp.queries,\n\t\t\t}\n\t\t}\n\t}\n\treturn r.regexp\n}\n"
  },
  {
    "path": "vendor/github.com/gorilla/mux/test_helpers.go",
    "content": "// Copyright 2012 The Gorilla Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage mux\n\nimport \"net/http\"\n\n// SetURLVars sets the URL variables for the given request, to be accessed via\n// mux.Vars for testing route behaviour. Arguments are not modified, a shallow\n// copy is returned.\n//\n// This API should only be used for testing purposes; it provides a way to\n// inject variables into the request context. Alternatively, URL variables\n// can be set by making a route that captures the required variables,\n// starting a server and sending the request to that server.\nfunc SetURLVars(r *http.Request, val map[string]string) *http.Request {\n\treturn setVars(r, val)\n}\n"
  },
  {
    "path": "vendor/github.com/pmezard/go-difflib/LICENSE",
    "content": "Copyright (c) 2013, Patrick Mezard\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n    Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n    Redistributions in binary form must reproduce the above copyright\nnotice, this list of conditions and the following disclaimer in the\ndocumentation and/or other materials provided with the distribution.\n    The names of its contributors may not be used to endorse or promote\nproducts derived from this software without specific prior written\npermission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\nIS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\nTO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A\nPARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nHOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\nTO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\nPROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\nLIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\nNEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "vendor/github.com/pmezard/go-difflib/difflib/difflib.go",
    "content": "// Package difflib is a partial port of Python difflib module.\n//\n// It provides tools to compare sequences of strings and generate textual diffs.\n//\n// The following class and functions have been ported:\n//\n// - SequenceMatcher\n//\n// - unified_diff\n//\n// - context_diff\n//\n// Getting unified diffs was the main goal of the port. Keep in mind this code\n// is mostly suitable to output text differences in a human friendly way, there\n// are no guarantees generated diffs are consumable by patch(1).\npackage difflib\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n)\n\nfunc min(a, b int) int {\n\tif a < b {\n\t\treturn a\n\t}\n\treturn b\n}\n\nfunc max(a, b int) int {\n\tif a > b {\n\t\treturn a\n\t}\n\treturn b\n}\n\nfunc calculateRatio(matches, length int) float64 {\n\tif length > 0 {\n\t\treturn 2.0 * float64(matches) / float64(length)\n\t}\n\treturn 1.0\n}\n\ntype Match struct {\n\tA    int\n\tB    int\n\tSize int\n}\n\ntype OpCode struct {\n\tTag byte\n\tI1  int\n\tI2  int\n\tJ1  int\n\tJ2  int\n}\n\n// SequenceMatcher compares sequence of strings. The basic\n// algorithm predates, and is a little fancier than, an algorithm\n// published in the late 1980's by Ratcliff and Obershelp under the\n// hyperbolic name \"gestalt pattern matching\".  The basic idea is to find\n// the longest contiguous matching subsequence that contains no \"junk\"\n// elements (R-O doesn't address junk).  The same idea is then applied\n// recursively to the pieces of the sequences to the left and to the right\n// of the matching subsequence.  This does not yield minimal edit\n// sequences, but does tend to yield matches that \"look right\" to people.\n//\n// SequenceMatcher tries to compute a \"human-friendly diff\" between two\n// sequences.  Unlike e.g. UNIX(tm) diff, the fundamental notion is the\n// longest *contiguous* & junk-free matching subsequence.  That's what\n// catches peoples' eyes.  The Windows(tm) windiff has another interesting\n// notion, pairing up elements that appear uniquely in each sequence.\n// That, and the method here, appear to yield more intuitive difference\n// reports than does diff.  This method appears to be the least vulnerable\n// to synching up on blocks of \"junk lines\", though (like blank lines in\n// ordinary text files, or maybe \"<P>\" lines in HTML files).  That may be\n// because this is the only method of the 3 that has a *concept* of\n// \"junk\" <wink>.\n//\n// Timing:  Basic R-O is cubic time worst case and quadratic time expected\n// case.  SequenceMatcher is quadratic time for the worst case and has\n// expected-case behavior dependent in a complicated way on how many\n// elements the sequences have in common; best case time is linear.\ntype SequenceMatcher struct {\n\ta              []string\n\tb              []string\n\tb2j            map[string][]int\n\tIsJunk         func(string) bool\n\tautoJunk       bool\n\tbJunk          map[string]struct{}\n\tmatchingBlocks []Match\n\tfullBCount     map[string]int\n\tbPopular       map[string]struct{}\n\topCodes        []OpCode\n}\n\nfunc NewMatcher(a, b []string) *SequenceMatcher {\n\tm := SequenceMatcher{autoJunk: true}\n\tm.SetSeqs(a, b)\n\treturn &m\n}\n\nfunc NewMatcherWithJunk(a, b []string, autoJunk bool,\n\tisJunk func(string) bool) *SequenceMatcher {\n\n\tm := SequenceMatcher{IsJunk: isJunk, autoJunk: autoJunk}\n\tm.SetSeqs(a, b)\n\treturn &m\n}\n\n// Set two sequences to be compared.\nfunc (m *SequenceMatcher) SetSeqs(a, b []string) {\n\tm.SetSeq1(a)\n\tm.SetSeq2(b)\n}\n\n// Set the first sequence to be compared. The second sequence to be compared is\n// not changed.\n//\n// SequenceMatcher computes and caches detailed information about the second\n// sequence, so if you want to compare one sequence S against many sequences,\n// use .SetSeq2(s) once and call .SetSeq1(x) repeatedly for each of the other\n// sequences.\n//\n// See also SetSeqs() and SetSeq2().\nfunc (m *SequenceMatcher) SetSeq1(a []string) {\n\tif &a == &m.a {\n\t\treturn\n\t}\n\tm.a = a\n\tm.matchingBlocks = nil\n\tm.opCodes = nil\n}\n\n// Set the second sequence to be compared. The first sequence to be compared is\n// not changed.\nfunc (m *SequenceMatcher) SetSeq2(b []string) {\n\tif &b == &m.b {\n\t\treturn\n\t}\n\tm.b = b\n\tm.matchingBlocks = nil\n\tm.opCodes = nil\n\tm.fullBCount = nil\n\tm.chainB()\n}\n\nfunc (m *SequenceMatcher) chainB() {\n\t// Populate line -> index mapping\n\tb2j := map[string][]int{}\n\tfor i, s := range m.b {\n\t\tindices := b2j[s]\n\t\tindices = append(indices, i)\n\t\tb2j[s] = indices\n\t}\n\n\t// Purge junk elements\n\tm.bJunk = map[string]struct{}{}\n\tif m.IsJunk != nil {\n\t\tjunk := m.bJunk\n\t\tfor s, _ := range b2j {\n\t\t\tif m.IsJunk(s) {\n\t\t\t\tjunk[s] = struct{}{}\n\t\t\t}\n\t\t}\n\t\tfor s, _ := range junk {\n\t\t\tdelete(b2j, s)\n\t\t}\n\t}\n\n\t// Purge remaining popular elements\n\tpopular := map[string]struct{}{}\n\tn := len(m.b)\n\tif m.autoJunk && n >= 200 {\n\t\tntest := n/100 + 1\n\t\tfor s, indices := range b2j {\n\t\t\tif len(indices) > ntest {\n\t\t\t\tpopular[s] = struct{}{}\n\t\t\t}\n\t\t}\n\t\tfor s, _ := range popular {\n\t\t\tdelete(b2j, s)\n\t\t}\n\t}\n\tm.bPopular = popular\n\tm.b2j = b2j\n}\n\nfunc (m *SequenceMatcher) isBJunk(s string) bool {\n\t_, ok := m.bJunk[s]\n\treturn ok\n}\n\n// Find longest matching block in a[alo:ahi] and b[blo:bhi].\n//\n// If IsJunk is not defined:\n//\n// Return (i,j,k) such that a[i:i+k] is equal to b[j:j+k], where\n//     alo <= i <= i+k <= ahi\n//     blo <= j <= j+k <= bhi\n// and for all (i',j',k') meeting those conditions,\n//     k >= k'\n//     i <= i'\n//     and if i == i', j <= j'\n//\n// In other words, of all maximal matching blocks, return one that\n// starts earliest in a, and of all those maximal matching blocks that\n// start earliest in a, return the one that starts earliest in b.\n//\n// If IsJunk is defined, first the longest matching block is\n// determined as above, but with the additional restriction that no\n// junk element appears in the block.  Then that block is extended as\n// far as possible by matching (only) junk elements on both sides.  So\n// the resulting block never matches on junk except as identical junk\n// happens to be adjacent to an \"interesting\" match.\n//\n// If no blocks match, return (alo, blo, 0).\nfunc (m *SequenceMatcher) findLongestMatch(alo, ahi, blo, bhi int) Match {\n\t// CAUTION:  stripping common prefix or suffix would be incorrect.\n\t// E.g.,\n\t//    ab\n\t//    acab\n\t// Longest matching block is \"ab\", but if common prefix is\n\t// stripped, it's \"a\" (tied with \"b\").  UNIX(tm) diff does so\n\t// strip, so ends up claiming that ab is changed to acab by\n\t// inserting \"ca\" in the middle.  That's minimal but unintuitive:\n\t// \"it's obvious\" that someone inserted \"ac\" at the front.\n\t// Windiff ends up at the same place as diff, but by pairing up\n\t// the unique 'b's and then matching the first two 'a's.\n\tbesti, bestj, bestsize := alo, blo, 0\n\n\t// find longest junk-free match\n\t// during an iteration of the loop, j2len[j] = length of longest\n\t// junk-free match ending with a[i-1] and b[j]\n\tj2len := map[int]int{}\n\tfor i := alo; i != ahi; i++ {\n\t\t// look at all instances of a[i] in b; note that because\n\t\t// b2j has no junk keys, the loop is skipped if a[i] is junk\n\t\tnewj2len := map[int]int{}\n\t\tfor _, j := range m.b2j[m.a[i]] {\n\t\t\t// a[i] matches b[j]\n\t\t\tif j < blo {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif j >= bhi {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tk := j2len[j-1] + 1\n\t\t\tnewj2len[j] = k\n\t\t\tif k > bestsize {\n\t\t\t\tbesti, bestj, bestsize = i-k+1, j-k+1, k\n\t\t\t}\n\t\t}\n\t\tj2len = newj2len\n\t}\n\n\t// Extend the best by non-junk elements on each end.  In particular,\n\t// \"popular\" non-junk elements aren't in b2j, which greatly speeds\n\t// the inner loop above, but also means \"the best\" match so far\n\t// doesn't contain any junk *or* popular non-junk elements.\n\tfor besti > alo && bestj > blo && !m.isBJunk(m.b[bestj-1]) &&\n\t\tm.a[besti-1] == m.b[bestj-1] {\n\t\tbesti, bestj, bestsize = besti-1, bestj-1, bestsize+1\n\t}\n\tfor besti+bestsize < ahi && bestj+bestsize < bhi &&\n\t\t!m.isBJunk(m.b[bestj+bestsize]) &&\n\t\tm.a[besti+bestsize] == m.b[bestj+bestsize] {\n\t\tbestsize += 1\n\t}\n\n\t// Now that we have a wholly interesting match (albeit possibly\n\t// empty!), we may as well suck up the matching junk on each\n\t// side of it too.  Can't think of a good reason not to, and it\n\t// saves post-processing the (possibly considerable) expense of\n\t// figuring out what to do with it.  In the case of an empty\n\t// interesting match, this is clearly the right thing to do,\n\t// because no other kind of match is possible in the regions.\n\tfor besti > alo && bestj > blo && m.isBJunk(m.b[bestj-1]) &&\n\t\tm.a[besti-1] == m.b[bestj-1] {\n\t\tbesti, bestj, bestsize = besti-1, bestj-1, bestsize+1\n\t}\n\tfor besti+bestsize < ahi && bestj+bestsize < bhi &&\n\t\tm.isBJunk(m.b[bestj+bestsize]) &&\n\t\tm.a[besti+bestsize] == m.b[bestj+bestsize] {\n\t\tbestsize += 1\n\t}\n\n\treturn Match{A: besti, B: bestj, Size: bestsize}\n}\n\n// Return list of triples describing matching subsequences.\n//\n// Each triple is of the form (i, j, n), and means that\n// a[i:i+n] == b[j:j+n].  The triples are monotonically increasing in\n// i and in j. It's also guaranteed that if (i, j, n) and (i', j', n') are\n// adjacent triples in the list, and the second is not the last triple in the\n// list, then i+n != i' or j+n != j'. IOW, adjacent triples never describe\n// adjacent equal blocks.\n//\n// The last triple is a dummy, (len(a), len(b), 0), and is the only\n// triple with n==0.\nfunc (m *SequenceMatcher) GetMatchingBlocks() []Match {\n\tif m.matchingBlocks != nil {\n\t\treturn m.matchingBlocks\n\t}\n\n\tvar matchBlocks func(alo, ahi, blo, bhi int, matched []Match) []Match\n\tmatchBlocks = func(alo, ahi, blo, bhi int, matched []Match) []Match {\n\t\tmatch := m.findLongestMatch(alo, ahi, blo, bhi)\n\t\ti, j, k := match.A, match.B, match.Size\n\t\tif match.Size > 0 {\n\t\t\tif alo < i && blo < j {\n\t\t\t\tmatched = matchBlocks(alo, i, blo, j, matched)\n\t\t\t}\n\t\t\tmatched = append(matched, match)\n\t\t\tif i+k < ahi && j+k < bhi {\n\t\t\t\tmatched = matchBlocks(i+k, ahi, j+k, bhi, matched)\n\t\t\t}\n\t\t}\n\t\treturn matched\n\t}\n\tmatched := matchBlocks(0, len(m.a), 0, len(m.b), nil)\n\n\t// It's possible that we have adjacent equal blocks in the\n\t// matching_blocks list now.\n\tnonAdjacent := []Match{}\n\ti1, j1, k1 := 0, 0, 0\n\tfor _, b := range matched {\n\t\t// Is this block adjacent to i1, j1, k1?\n\t\ti2, j2, k2 := b.A, b.B, b.Size\n\t\tif i1+k1 == i2 && j1+k1 == j2 {\n\t\t\t// Yes, so collapse them -- this just increases the length of\n\t\t\t// the first block by the length of the second, and the first\n\t\t\t// block so lengthened remains the block to compare against.\n\t\t\tk1 += k2\n\t\t} else {\n\t\t\t// Not adjacent.  Remember the first block (k1==0 means it's\n\t\t\t// the dummy we started with), and make the second block the\n\t\t\t// new block to compare against.\n\t\t\tif k1 > 0 {\n\t\t\t\tnonAdjacent = append(nonAdjacent, Match{i1, j1, k1})\n\t\t\t}\n\t\t\ti1, j1, k1 = i2, j2, k2\n\t\t}\n\t}\n\tif k1 > 0 {\n\t\tnonAdjacent = append(nonAdjacent, Match{i1, j1, k1})\n\t}\n\n\tnonAdjacent = append(nonAdjacent, Match{len(m.a), len(m.b), 0})\n\tm.matchingBlocks = nonAdjacent\n\treturn m.matchingBlocks\n}\n\n// Return list of 5-tuples describing how to turn a into b.\n//\n// Each tuple is of the form (tag, i1, i2, j1, j2).  The first tuple\n// has i1 == j1 == 0, and remaining tuples have i1 == the i2 from the\n// tuple preceding it, and likewise for j1 == the previous j2.\n//\n// The tags are characters, with these meanings:\n//\n// 'r' (replace):  a[i1:i2] should be replaced by b[j1:j2]\n//\n// 'd' (delete):   a[i1:i2] should be deleted, j1==j2 in this case.\n//\n// 'i' (insert):   b[j1:j2] should be inserted at a[i1:i1], i1==i2 in this case.\n//\n// 'e' (equal):    a[i1:i2] == b[j1:j2]\nfunc (m *SequenceMatcher) GetOpCodes() []OpCode {\n\tif m.opCodes != nil {\n\t\treturn m.opCodes\n\t}\n\ti, j := 0, 0\n\tmatching := m.GetMatchingBlocks()\n\topCodes := make([]OpCode, 0, len(matching))\n\tfor _, m := range matching {\n\t\t//  invariant:  we've pumped out correct diffs to change\n\t\t//  a[:i] into b[:j], and the next matching block is\n\t\t//  a[ai:ai+size] == b[bj:bj+size]. So we need to pump\n\t\t//  out a diff to change a[i:ai] into b[j:bj], pump out\n\t\t//  the matching block, and move (i,j) beyond the match\n\t\tai, bj, size := m.A, m.B, m.Size\n\t\ttag := byte(0)\n\t\tif i < ai && j < bj {\n\t\t\ttag = 'r'\n\t\t} else if i < ai {\n\t\t\ttag = 'd'\n\t\t} else if j < bj {\n\t\t\ttag = 'i'\n\t\t}\n\t\tif tag > 0 {\n\t\t\topCodes = append(opCodes, OpCode{tag, i, ai, j, bj})\n\t\t}\n\t\ti, j = ai+size, bj+size\n\t\t// the list of matching blocks is terminated by a\n\t\t// sentinel with size 0\n\t\tif size > 0 {\n\t\t\topCodes = append(opCodes, OpCode{'e', ai, i, bj, j})\n\t\t}\n\t}\n\tm.opCodes = opCodes\n\treturn m.opCodes\n}\n\n// Isolate change clusters by eliminating ranges with no changes.\n//\n// Return a generator of groups with up to n lines of context.\n// Each group is in the same format as returned by GetOpCodes().\nfunc (m *SequenceMatcher) GetGroupedOpCodes(n int) [][]OpCode {\n\tif n < 0 {\n\t\tn = 3\n\t}\n\tcodes := m.GetOpCodes()\n\tif len(codes) == 0 {\n\t\tcodes = []OpCode{OpCode{'e', 0, 1, 0, 1}}\n\t}\n\t// Fixup leading and trailing groups if they show no changes.\n\tif codes[0].Tag == 'e' {\n\t\tc := codes[0]\n\t\ti1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2\n\t\tcodes[0] = OpCode{c.Tag, max(i1, i2-n), i2, max(j1, j2-n), j2}\n\t}\n\tif codes[len(codes)-1].Tag == 'e' {\n\t\tc := codes[len(codes)-1]\n\t\ti1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2\n\t\tcodes[len(codes)-1] = OpCode{c.Tag, i1, min(i2, i1+n), j1, min(j2, j1+n)}\n\t}\n\tnn := n + n\n\tgroups := [][]OpCode{}\n\tgroup := []OpCode{}\n\tfor _, c := range codes {\n\t\ti1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2\n\t\t// End the current group and start a new one whenever\n\t\t// there is a large range with no changes.\n\t\tif c.Tag == 'e' && i2-i1 > nn {\n\t\t\tgroup = append(group, OpCode{c.Tag, i1, min(i2, i1+n),\n\t\t\t\tj1, min(j2, j1+n)})\n\t\t\tgroups = append(groups, group)\n\t\t\tgroup = []OpCode{}\n\t\t\ti1, j1 = max(i1, i2-n), max(j1, j2-n)\n\t\t}\n\t\tgroup = append(group, OpCode{c.Tag, i1, i2, j1, j2})\n\t}\n\tif len(group) > 0 && !(len(group) == 1 && group[0].Tag == 'e') {\n\t\tgroups = append(groups, group)\n\t}\n\treturn groups\n}\n\n// Return a measure of the sequences' similarity (float in [0,1]).\n//\n// Where T is the total number of elements in both sequences, and\n// M is the number of matches, this is 2.0*M / T.\n// Note that this is 1 if the sequences are identical, and 0 if\n// they have nothing in common.\n//\n// .Ratio() is expensive to compute if you haven't already computed\n// .GetMatchingBlocks() or .GetOpCodes(), in which case you may\n// want to try .QuickRatio() or .RealQuickRation() first to get an\n// upper bound.\nfunc (m *SequenceMatcher) Ratio() float64 {\n\tmatches := 0\n\tfor _, m := range m.GetMatchingBlocks() {\n\t\tmatches += m.Size\n\t}\n\treturn calculateRatio(matches, len(m.a)+len(m.b))\n}\n\n// Return an upper bound on ratio() relatively quickly.\n//\n// This isn't defined beyond that it is an upper bound on .Ratio(), and\n// is faster to compute.\nfunc (m *SequenceMatcher) QuickRatio() float64 {\n\t// viewing a and b as multisets, set matches to the cardinality\n\t// of their intersection; this counts the number of matches\n\t// without regard to order, so is clearly an upper bound\n\tif m.fullBCount == nil {\n\t\tm.fullBCount = map[string]int{}\n\t\tfor _, s := range m.b {\n\t\t\tm.fullBCount[s] = m.fullBCount[s] + 1\n\t\t}\n\t}\n\n\t// avail[x] is the number of times x appears in 'b' less the\n\t// number of times we've seen it in 'a' so far ... kinda\n\tavail := map[string]int{}\n\tmatches := 0\n\tfor _, s := range m.a {\n\t\tn, ok := avail[s]\n\t\tif !ok {\n\t\t\tn = m.fullBCount[s]\n\t\t}\n\t\tavail[s] = n - 1\n\t\tif n > 0 {\n\t\t\tmatches += 1\n\t\t}\n\t}\n\treturn calculateRatio(matches, len(m.a)+len(m.b))\n}\n\n// Return an upper bound on ratio() very quickly.\n//\n// This isn't defined beyond that it is an upper bound on .Ratio(), and\n// is faster to compute than either .Ratio() or .QuickRatio().\nfunc (m *SequenceMatcher) RealQuickRatio() float64 {\n\tla, lb := len(m.a), len(m.b)\n\treturn calculateRatio(min(la, lb), la+lb)\n}\n\n// Convert range to the \"ed\" format\nfunc formatRangeUnified(start, stop int) string {\n\t// Per the diff spec at http://www.unix.org/single_unix_specification/\n\tbeginning := start + 1 // lines start numbering with one\n\tlength := stop - start\n\tif length == 1 {\n\t\treturn fmt.Sprintf(\"%d\", beginning)\n\t}\n\tif length == 0 {\n\t\tbeginning -= 1 // empty ranges begin at line just before the range\n\t}\n\treturn fmt.Sprintf(\"%d,%d\", beginning, length)\n}\n\n// Unified diff parameters\ntype UnifiedDiff struct {\n\tA        []string // First sequence lines\n\tFromFile string   // First file name\n\tFromDate string   // First file time\n\tB        []string // Second sequence lines\n\tToFile   string   // Second file name\n\tToDate   string   // Second file time\n\tEol      string   // Headers end of line, defaults to LF\n\tContext  int      // Number of context lines\n}\n\n// Compare two sequences of lines; generate the delta as a unified diff.\n//\n// Unified diffs are a compact way of showing line changes and a few\n// lines of context.  The number of context lines is set by 'n' which\n// defaults to three.\n//\n// By default, the diff control lines (those with ---, +++, or @@) are\n// created with a trailing newline.  This is helpful so that inputs\n// created from file.readlines() result in diffs that are suitable for\n// file.writelines() since both the inputs and outputs have trailing\n// newlines.\n//\n// For inputs that do not have trailing newlines, set the lineterm\n// argument to \"\" so that the output will be uniformly newline free.\n//\n// The unidiff format normally has a header for filenames and modification\n// times.  Any or all of these may be specified using strings for\n// 'fromfile', 'tofile', 'fromfiledate', and 'tofiledate'.\n// The modification times are normally expressed in the ISO 8601 format.\nfunc WriteUnifiedDiff(writer io.Writer, diff UnifiedDiff) error {\n\tbuf := bufio.NewWriter(writer)\n\tdefer buf.Flush()\n\tw := func(format string, args ...interface{}) error {\n\t\t_, err := buf.WriteString(fmt.Sprintf(format, args...))\n\t\treturn err\n\t}\n\n\tif len(diff.Eol) == 0 {\n\t\tdiff.Eol = \"\\n\"\n\t}\n\n\tstarted := false\n\tm := NewMatcher(diff.A, diff.B)\n\tfor _, g := range m.GetGroupedOpCodes(diff.Context) {\n\t\tif !started {\n\t\t\tstarted = true\n\t\t\tfromDate := \"\"\n\t\t\tif len(diff.FromDate) > 0 {\n\t\t\t\tfromDate = \"\\t\" + diff.FromDate\n\t\t\t}\n\t\t\ttoDate := \"\"\n\t\t\tif len(diff.ToDate) > 0 {\n\t\t\t\ttoDate = \"\\t\" + diff.ToDate\n\t\t\t}\n\t\t\terr := w(\"--- %s%s%s\", diff.FromFile, fromDate, diff.Eol)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\terr = w(\"+++ %s%s%s\", diff.ToFile, toDate, diff.Eol)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tfirst, last := g[0], g[len(g)-1]\n\t\trange1 := formatRangeUnified(first.I1, last.I2)\n\t\trange2 := formatRangeUnified(first.J1, last.J2)\n\t\tif err := w(\"@@ -%s +%s @@%s\", range1, range2, diff.Eol); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfor _, c := range g {\n\t\t\ti1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2\n\t\t\tif c.Tag == 'e' {\n\t\t\t\tfor _, line := range diff.A[i1:i2] {\n\t\t\t\t\tif err := w(\" \" + line); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif c.Tag == 'r' || c.Tag == 'd' {\n\t\t\t\tfor _, line := range diff.A[i1:i2] {\n\t\t\t\t\tif err := w(\"-\" + line); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif c.Tag == 'r' || c.Tag == 'i' {\n\t\t\t\tfor _, line := range diff.B[j1:j2] {\n\t\t\t\t\tif err := w(\"+\" + line); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// Like WriteUnifiedDiff but returns the diff a string.\nfunc GetUnifiedDiffString(diff UnifiedDiff) (string, error) {\n\tw := &bytes.Buffer{}\n\terr := WriteUnifiedDiff(w, diff)\n\treturn string(w.Bytes()), err\n}\n\n// Convert range to the \"ed\" format.\nfunc formatRangeContext(start, stop int) string {\n\t// Per the diff spec at http://www.unix.org/single_unix_specification/\n\tbeginning := start + 1 // lines start numbering with one\n\tlength := stop - start\n\tif length == 0 {\n\t\tbeginning -= 1 // empty ranges begin at line just before the range\n\t}\n\tif length <= 1 {\n\t\treturn fmt.Sprintf(\"%d\", beginning)\n\t}\n\treturn fmt.Sprintf(\"%d,%d\", beginning, beginning+length-1)\n}\n\ntype ContextDiff UnifiedDiff\n\n// Compare two sequences of lines; generate the delta as a context diff.\n//\n// Context diffs are a compact way of showing line changes and a few\n// lines of context. The number of context lines is set by diff.Context\n// which defaults to three.\n//\n// By default, the diff control lines (those with *** or ---) are\n// created with a trailing newline.\n//\n// For inputs that do not have trailing newlines, set the diff.Eol\n// argument to \"\" so that the output will be uniformly newline free.\n//\n// The context diff format normally has a header for filenames and\n// modification times.  Any or all of these may be specified using\n// strings for diff.FromFile, diff.ToFile, diff.FromDate, diff.ToDate.\n// The modification times are normally expressed in the ISO 8601 format.\n// If not specified, the strings default to blanks.\nfunc WriteContextDiff(writer io.Writer, diff ContextDiff) error {\n\tbuf := bufio.NewWriter(writer)\n\tdefer buf.Flush()\n\tvar diffErr error\n\tw := func(format string, args ...interface{}) {\n\t\t_, err := buf.WriteString(fmt.Sprintf(format, args...))\n\t\tif diffErr == nil && err != nil {\n\t\t\tdiffErr = err\n\t\t}\n\t}\n\n\tif len(diff.Eol) == 0 {\n\t\tdiff.Eol = \"\\n\"\n\t}\n\n\tprefix := map[byte]string{\n\t\t'i': \"+ \",\n\t\t'd': \"- \",\n\t\t'r': \"! \",\n\t\t'e': \"  \",\n\t}\n\n\tstarted := false\n\tm := NewMatcher(diff.A, diff.B)\n\tfor _, g := range m.GetGroupedOpCodes(diff.Context) {\n\t\tif !started {\n\t\t\tstarted = true\n\t\t\tfromDate := \"\"\n\t\t\tif len(diff.FromDate) > 0 {\n\t\t\t\tfromDate = \"\\t\" + diff.FromDate\n\t\t\t}\n\t\t\ttoDate := \"\"\n\t\t\tif len(diff.ToDate) > 0 {\n\t\t\t\ttoDate = \"\\t\" + diff.ToDate\n\t\t\t}\n\t\t\tw(\"*** %s%s%s\", diff.FromFile, fromDate, diff.Eol)\n\t\t\tw(\"--- %s%s%s\", diff.ToFile, toDate, diff.Eol)\n\t\t}\n\n\t\tfirst, last := g[0], g[len(g)-1]\n\t\tw(\"***************\" + diff.Eol)\n\n\t\trange1 := formatRangeContext(first.I1, last.I2)\n\t\tw(\"*** %s ****%s\", range1, diff.Eol)\n\t\tfor _, c := range g {\n\t\t\tif c.Tag == 'r' || c.Tag == 'd' {\n\t\t\t\tfor _, cc := range g {\n\t\t\t\t\tif cc.Tag == 'i' {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tfor _, line := range diff.A[cc.I1:cc.I2] {\n\t\t\t\t\t\tw(prefix[cc.Tag] + line)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\trange2 := formatRangeContext(first.J1, last.J2)\n\t\tw(\"--- %s ----%s\", range2, diff.Eol)\n\t\tfor _, c := range g {\n\t\t\tif c.Tag == 'r' || c.Tag == 'i' {\n\t\t\t\tfor _, cc := range g {\n\t\t\t\t\tif cc.Tag == 'd' {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tfor _, line := range diff.B[cc.J1:cc.J2] {\n\t\t\t\t\t\tw(prefix[cc.Tag] + line)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\treturn diffErr\n}\n\n// Like WriteContextDiff but returns the diff a string.\nfunc GetContextDiffString(diff ContextDiff) (string, error) {\n\tw := &bytes.Buffer{}\n\terr := WriteContextDiff(w, diff)\n\treturn string(w.Bytes()), err\n}\n\n// Split a string on \"\\n\" while preserving them. The output can be used\n// as input for UnifiedDiff and ContextDiff structures.\nfunc SplitLines(s string) []string {\n\tlines := strings.SplitAfter(s, \"\\n\")\n\tlines[len(lines)-1] += \"\\n\"\n\treturn lines\n}\n"
  },
  {
    "path": "vendor/github.com/stretchr/objx/LICENSE.md",
    "content": "objx - by Mat Ryer and Tyler Bunnell\n\nThe MIT License (MIT)\n\nCopyright (c) 2014 Stretchr, Inc.\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": "vendor/github.com/stretchr/objx/README.md",
    "content": "# objx\n\n  * Jump into the [API Documentation](http://godoc.org/github.com/stretchr/objx)\n"
  },
  {
    "path": "vendor/github.com/stretchr/objx/accessors.go",
    "content": "package objx\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n)\n\n// arrayAccesRegexString is the regex used to extract the array number\n// from the access path\nconst arrayAccesRegexString = `^(.+)\\[([0-9]+)\\]$`\n\n// arrayAccesRegex is the compiled arrayAccesRegexString\nvar arrayAccesRegex = regexp.MustCompile(arrayAccesRegexString)\n\n// Get gets the value using the specified selector and\n// returns it inside a new Obj object.\n//\n// If it cannot find the value, Get will return a nil\n// value inside an instance of Obj.\n//\n// Get can only operate directly on map[string]interface{} and []interface.\n//\n// Example\n//\n// To access the title of the third chapter of the second book, do:\n//\n//    o.Get(\"books[1].chapters[2].title\")\nfunc (m Map) Get(selector string) *Value {\n\trawObj := access(m, selector, nil, false, false)\n\treturn &Value{data: rawObj}\n}\n\n// Set sets the value using the specified selector and\n// returns the object on which Set was called.\n//\n// Set can only operate directly on map[string]interface{} and []interface\n//\n// Example\n//\n// To set the title of the third chapter of the second book, do:\n//\n//    o.Set(\"books[1].chapters[2].title\",\"Time to Go\")\nfunc (m Map) Set(selector string, value interface{}) Map {\n\taccess(m, selector, value, true, false)\n\treturn m\n}\n\n// access accesses the object using the selector and performs the\n// appropriate action.\nfunc access(current, selector, value interface{}, isSet, panics bool) interface{} {\n\n\tswitch selector.(type) {\n\tcase int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:\n\n\t\tif array, ok := current.([]interface{}); ok {\n\t\t\tindex := intFromInterface(selector)\n\n\t\t\tif index >= len(array) {\n\t\t\t\tif panics {\n\t\t\t\t\tpanic(fmt.Sprintf(\"objx: Index %d is out of range. Slice only contains %d items.\", index, len(array)))\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\treturn array[index]\n\t\t}\n\n\t\treturn nil\n\n\tcase string:\n\n\t\tselStr := selector.(string)\n\t\tselSegs := strings.SplitN(selStr, PathSeparator, 2)\n\t\tthisSel := selSegs[0]\n\t\tindex := -1\n\t\tvar err error\n\n\t\t// https://github.com/stretchr/objx/issues/12\n\t\tif strings.Contains(thisSel, \"[\") {\n\n\t\t\tarrayMatches := arrayAccesRegex.FindStringSubmatch(thisSel)\n\n\t\t\tif len(arrayMatches) > 0 {\n\n\t\t\t\t// Get the key into the map\n\t\t\t\tthisSel = arrayMatches[1]\n\n\t\t\t\t// Get the index into the array at the key\n\t\t\t\tindex, err = strconv.Atoi(arrayMatches[2])\n\n\t\t\t\tif err != nil {\n\t\t\t\t\t// This should never happen. If it does, something has gone\n\t\t\t\t\t// seriously wrong. Panic.\n\t\t\t\t\tpanic(\"objx: Array index is not an integer.  Must use array[int].\")\n\t\t\t\t}\n\n\t\t\t}\n\t\t}\n\n\t\tif curMap, ok := current.(Map); ok {\n\t\t\tcurrent = map[string]interface{}(curMap)\n\t\t}\n\n\t\t// get the object in question\n\t\tswitch current.(type) {\n\t\tcase map[string]interface{}:\n\t\t\tcurMSI := current.(map[string]interface{})\n\t\t\tif len(selSegs) <= 1 && isSet {\n\t\t\t\tcurMSI[thisSel] = value\n\t\t\t\treturn nil\n\t\t\t} else {\n\t\t\t\tcurrent = curMSI[thisSel]\n\t\t\t}\n\t\tdefault:\n\t\t\tcurrent = nil\n\t\t}\n\n\t\tif current == nil && panics {\n\t\t\tpanic(fmt.Sprintf(\"objx: '%v' invalid on object.\", selector))\n\t\t}\n\n\t\t// do we need to access the item of an array?\n\t\tif index > -1 {\n\t\t\tif array, ok := current.([]interface{}); ok {\n\t\t\t\tif index < len(array) {\n\t\t\t\t\tcurrent = array[index]\n\t\t\t\t} else {\n\t\t\t\t\tif panics {\n\t\t\t\t\t\tpanic(fmt.Sprintf(\"objx: Index %d is out of range. Slice only contains %d items.\", index, len(array)))\n\t\t\t\t\t}\n\t\t\t\t\tcurrent = nil\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif len(selSegs) > 1 {\n\t\t\tcurrent = access(current, selSegs[1], value, isSet, panics)\n\t\t}\n\n\t}\n\n\treturn current\n\n}\n\n// intFromInterface converts an interface object to the largest\n// representation of an unsigned integer using a type switch and\n// assertions\nfunc intFromInterface(selector interface{}) int {\n\tvar value int\n\tswitch selector.(type) {\n\tcase int:\n\t\tvalue = selector.(int)\n\tcase int8:\n\t\tvalue = int(selector.(int8))\n\tcase int16:\n\t\tvalue = int(selector.(int16))\n\tcase int32:\n\t\tvalue = int(selector.(int32))\n\tcase int64:\n\t\tvalue = int(selector.(int64))\n\tcase uint:\n\t\tvalue = int(selector.(uint))\n\tcase uint8:\n\t\tvalue = int(selector.(uint8))\n\tcase uint16:\n\t\tvalue = int(selector.(uint16))\n\tcase uint32:\n\t\tvalue = int(selector.(uint32))\n\tcase uint64:\n\t\tvalue = int(selector.(uint64))\n\tdefault:\n\t\tpanic(\"objx: array access argument is not an integer type (this should never happen)\")\n\t}\n\n\treturn value\n}\n"
  },
  {
    "path": "vendor/github.com/stretchr/objx/constants.go",
    "content": "package objx\n\nconst (\n\t// PathSeparator is the character used to separate the elements\n\t// of the keypath.\n\t//\n\t// For example, `location.address.city`\n\tPathSeparator string = \".\"\n\n\t// SignatureSeparator is the character that is used to\n\t// separate the Base64 string from the security signature.\n\tSignatureSeparator = \"_\"\n)\n"
  },
  {
    "path": "vendor/github.com/stretchr/objx/conversions.go",
    "content": "package objx\n\nimport (\n\t\"bytes\"\n\t\"encoding/base64\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/url\"\n)\n\n// JSON converts the contained object to a JSON string\n// representation\nfunc (m Map) JSON() (string, error) {\n\n\tresult, err := json.Marshal(m)\n\n\tif err != nil {\n\t\terr = errors.New(\"objx: JSON encode failed with: \" + err.Error())\n\t}\n\n\treturn string(result), err\n\n}\n\n// MustJSON converts the contained object to a JSON string\n// representation and panics if there is an error\nfunc (m Map) MustJSON() string {\n\tresult, err := m.JSON()\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\treturn result\n}\n\n// Base64 converts the contained object to a Base64 string\n// representation of the JSON string representation\nfunc (m Map) Base64() (string, error) {\n\n\tvar buf bytes.Buffer\n\n\tjsonData, err := m.JSON()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tencoder := base64.NewEncoder(base64.StdEncoding, &buf)\n\tencoder.Write([]byte(jsonData))\n\tencoder.Close()\n\n\treturn buf.String(), nil\n\n}\n\n// MustBase64 converts the contained object to a Base64 string\n// representation of the JSON string representation and panics\n// if there is an error\nfunc (m Map) MustBase64() string {\n\tresult, err := m.Base64()\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\treturn result\n}\n\n// SignedBase64 converts the contained object to a Base64 string\n// representation of the JSON string representation and signs it\n// using the provided key.\nfunc (m Map) SignedBase64(key string) (string, error) {\n\n\tbase64, err := m.Base64()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tsig := HashWithKey(base64, key)\n\n\treturn base64 + SignatureSeparator + sig, nil\n\n}\n\n// MustSignedBase64 converts the contained object to a Base64 string\n// representation of the JSON string representation and signs it\n// using the provided key and panics if there is an error\nfunc (m Map) MustSignedBase64(key string) string {\n\tresult, err := m.SignedBase64(key)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\treturn result\n}\n\n/*\n\tURL Query\n\t------------------------------------------------\n*/\n\n// URLValues creates a url.Values object from an Obj. This\n// function requires that the wrapped object be a map[string]interface{}\nfunc (m Map) URLValues() url.Values {\n\n\tvals := make(url.Values)\n\n\tfor k, v := range m {\n\t\t//TODO: can this be done without sprintf?\n\t\tvals.Set(k, fmt.Sprintf(\"%v\", v))\n\t}\n\n\treturn vals\n}\n\n// URLQuery gets an encoded URL query representing the given\n// Obj. This function requires that the wrapped object be a\n// map[string]interface{}\nfunc (m Map) URLQuery() (string, error) {\n\treturn m.URLValues().Encode(), nil\n}\n"
  },
  {
    "path": "vendor/github.com/stretchr/objx/doc.go",
    "content": "// objx - Go package for dealing with maps, slices, JSON and other data.\n//\n// Overview\n//\n// Objx provides the `objx.Map` type, which is a `map[string]interface{}` that exposes\n// a powerful `Get` method (among others) that allows you to easily and quickly get\n// access to data within the map, without having to worry too much about type assertions,\n// missing data, default values etc.\n//\n// Pattern\n//\n// Objx uses a preditable pattern to make access data from within `map[string]interface{}'s\n// easy.\n//\n// Call one of the `objx.` functions to create your `objx.Map` to get going:\n//\n//     m, err := objx.FromJSON(json)\n//\n// NOTE: Any methods or functions with the `Must` prefix will panic if something goes wrong,\n// the rest will be optimistic and try to figure things out without panicking.\n//\n// Use `Get` to access the value you're interested in.  You can use dot and array\n// notation too:\n//\n//     m.Get(\"places[0].latlng\")\n//\n// Once you have saught the `Value` you're interested in, you can use the `Is*` methods\n// to determine its type.\n//\n//     if m.Get(\"code\").IsStr() { /* ... */ }\n//\n// Or you can just assume the type, and use one of the strong type methods to\n// extract the real value:\n//\n//     m.Get(\"code\").Int()\n//\n// If there's no value there (or if it's the wrong type) then a default value\n// will be returned, or you can be explicit about the default value.\n//\n//     Get(\"code\").Int(-1)\n//\n// If you're dealing with a slice of data as a value, Objx provides many useful\n// methods for iterating, manipulating and selecting that data.  You can find out more\n// by exploring the index below.\n//\n// Reading data\n//\n// A simple example of how to use Objx:\n//\n//     // use MustFromJSON to make an objx.Map from some JSON\n//     m := objx.MustFromJSON(`{\"name\": \"Mat\", \"age\": 30}`)\n//\n//     // get the details\n//     name := m.Get(\"name\").Str()\n//     age := m.Get(\"age\").Int()\n//\n//     // get their nickname (or use their name if they\n//     // don't have one)\n//     nickname := m.Get(\"nickname\").Str(name)\n//\n// Ranging\n//\n// Since `objx.Map` is a `map[string]interface{}` you can treat it as such.  For\n// example, to `range` the data, do what you would expect:\n//\n//     m := objx.MustFromJSON(json)\n//     for key, value := range m {\n//\n//       /* ... do your magic ... */\n//\n//     }\npackage objx\n"
  },
  {
    "path": "vendor/github.com/stretchr/objx/map.go",
    "content": "package objx\n\nimport (\n\t\"encoding/base64\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"io/ioutil\"\n\t\"net/url\"\n\t\"strings\"\n)\n\n// MSIConvertable is an interface that defines methods for converting your\n// custom types to a map[string]interface{} representation.\ntype MSIConvertable interface {\n\t// MSI gets a map[string]interface{} (msi) representing the\n\t// object.\n\tMSI() map[string]interface{}\n}\n\n// Map provides extended functionality for working with\n// untyped data, in particular map[string]interface (msi).\ntype Map map[string]interface{}\n\n// Value returns the internal value instance\nfunc (m Map) Value() *Value {\n\treturn &Value{data: m}\n}\n\n// Nil represents a nil Map.\nvar Nil Map = New(nil)\n\n// New creates a new Map containing the map[string]interface{} in the data argument.\n// If the data argument is not a map[string]interface, New attempts to call the\n// MSI() method on the MSIConvertable interface to create one.\nfunc New(data interface{}) Map {\n\tif _, ok := data.(map[string]interface{}); !ok {\n\t\tif converter, ok := data.(MSIConvertable); ok {\n\t\t\tdata = converter.MSI()\n\t\t} else {\n\t\t\treturn nil\n\t\t}\n\t}\n\treturn Map(data.(map[string]interface{}))\n}\n\n// MSI creates a map[string]interface{} and puts it inside a new Map.\n//\n// The arguments follow a key, value pattern.\n//\n// Panics\n//\n// Panics if any key arugment is non-string or if there are an odd number of arguments.\n//\n// Example\n//\n// To easily create Maps:\n//\n//     m := objx.MSI(\"name\", \"Mat\", \"age\", 29, \"subobj\", objx.MSI(\"active\", true))\n//\n//     // creates an Map equivalent to\n//     m := objx.New(map[string]interface{}{\"name\": \"Mat\", \"age\": 29, \"subobj\": map[string]interface{}{\"active\": true}})\nfunc MSI(keyAndValuePairs ...interface{}) Map {\n\n\tnewMap := make(map[string]interface{})\n\tkeyAndValuePairsLen := len(keyAndValuePairs)\n\n\tif keyAndValuePairsLen%2 != 0 {\n\t\tpanic(\"objx: MSI must have an even number of arguments following the 'key, value' pattern.\")\n\t}\n\n\tfor i := 0; i < keyAndValuePairsLen; i = i + 2 {\n\n\t\tkey := keyAndValuePairs[i]\n\t\tvalue := keyAndValuePairs[i+1]\n\n\t\t// make sure the key is a string\n\t\tkeyString, keyStringOK := key.(string)\n\t\tif !keyStringOK {\n\t\t\tpanic(\"objx: MSI must follow 'string, interface{}' pattern.  \" + keyString + \" is not a valid key.\")\n\t\t}\n\n\t\tnewMap[keyString] = value\n\n\t}\n\n\treturn New(newMap)\n}\n\n// ****** Conversion Constructors\n\n// MustFromJSON creates a new Map containing the data specified in the\n// jsonString.\n//\n// Panics if the JSON is invalid.\nfunc MustFromJSON(jsonString string) Map {\n\to, err := FromJSON(jsonString)\n\n\tif err != nil {\n\t\tpanic(\"objx: MustFromJSON failed with error: \" + err.Error())\n\t}\n\n\treturn o\n}\n\n// FromJSON creates a new Map containing the data specified in the\n// jsonString.\n//\n// Returns an error if the JSON is invalid.\nfunc FromJSON(jsonString string) (Map, error) {\n\n\tvar data interface{}\n\terr := json.Unmarshal([]byte(jsonString), &data)\n\n\tif err != nil {\n\t\treturn Nil, err\n\t}\n\n\treturn New(data), nil\n\n}\n\n// FromBase64 creates a new Obj containing the data specified\n// in the Base64 string.\n//\n// The string is an encoded JSON string returned by Base64\nfunc FromBase64(base64String string) (Map, error) {\n\n\tdecoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(base64String))\n\n\tdecoded, err := ioutil.ReadAll(decoder)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn FromJSON(string(decoded))\n}\n\n// MustFromBase64 creates a new Obj containing the data specified\n// in the Base64 string and panics if there is an error.\n//\n// The string is an encoded JSON string returned by Base64\nfunc MustFromBase64(base64String string) Map {\n\n\tresult, err := FromBase64(base64String)\n\n\tif err != nil {\n\t\tpanic(\"objx: MustFromBase64 failed with error: \" + err.Error())\n\t}\n\n\treturn result\n}\n\n// FromSignedBase64 creates a new Obj containing the data specified\n// in the Base64 string.\n//\n// The string is an encoded JSON string returned by SignedBase64\nfunc FromSignedBase64(base64String, key string) (Map, error) {\n\tparts := strings.Split(base64String, SignatureSeparator)\n\tif len(parts) != 2 {\n\t\treturn nil, errors.New(\"objx: Signed base64 string is malformed.\")\n\t}\n\n\tsig := HashWithKey(parts[0], key)\n\tif parts[1] != sig {\n\t\treturn nil, errors.New(\"objx: Signature for base64 data does not match.\")\n\t}\n\n\treturn FromBase64(parts[0])\n}\n\n// MustFromSignedBase64 creates a new Obj containing the data specified\n// in the Base64 string and panics if there is an error.\n//\n// The string is an encoded JSON string returned by Base64\nfunc MustFromSignedBase64(base64String, key string) Map {\n\n\tresult, err := FromSignedBase64(base64String, key)\n\n\tif err != nil {\n\t\tpanic(\"objx: MustFromSignedBase64 failed with error: \" + err.Error())\n\t}\n\n\treturn result\n}\n\n// FromURLQuery generates a new Obj by parsing the specified\n// query.\n//\n// For queries with multiple values, the first value is selected.\nfunc FromURLQuery(query string) (Map, error) {\n\n\tvals, err := url.ParseQuery(query)\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tm := make(map[string]interface{})\n\tfor k, vals := range vals {\n\t\tm[k] = vals[0]\n\t}\n\n\treturn New(m), nil\n}\n\n// MustFromURLQuery generates a new Obj by parsing the specified\n// query.\n//\n// For queries with multiple values, the first value is selected.\n//\n// Panics if it encounters an error\nfunc MustFromURLQuery(query string) Map {\n\n\to, err := FromURLQuery(query)\n\n\tif err != nil {\n\t\tpanic(\"objx: MustFromURLQuery failed with error: \" + err.Error())\n\t}\n\n\treturn o\n\n}\n"
  },
  {
    "path": "vendor/github.com/stretchr/objx/mutations.go",
    "content": "package objx\n\n// Exclude returns a new Map with the keys in the specified []string\n// excluded.\nfunc (d Map) Exclude(exclude []string) Map {\n\n\texcluded := make(Map)\n\tfor k, v := range d {\n\t\tvar shouldInclude bool = true\n\t\tfor _, toExclude := range exclude {\n\t\t\tif k == toExclude {\n\t\t\t\tshouldInclude = false\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif shouldInclude {\n\t\t\texcluded[k] = v\n\t\t}\n\t}\n\n\treturn excluded\n}\n\n// Copy creates a shallow copy of the Obj.\nfunc (m Map) Copy() Map {\n\tcopied := make(map[string]interface{})\n\tfor k, v := range m {\n\t\tcopied[k] = v\n\t}\n\treturn New(copied)\n}\n\n// Merge blends the specified map with a copy of this map and returns the result.\n//\n// Keys that appear in both will be selected from the specified map.\n// This method requires that the wrapped object be a map[string]interface{}\nfunc (m Map) Merge(merge Map) Map {\n\treturn m.Copy().MergeHere(merge)\n}\n\n// Merge blends the specified map with this map and returns the current map.\n//\n// Keys that appear in both will be selected from the specified map.  The original map\n// will be modified. This method requires that\n// the wrapped object be a map[string]interface{}\nfunc (m Map) MergeHere(merge Map) Map {\n\n\tfor k, v := range merge {\n\t\tm[k] = v\n\t}\n\n\treturn m\n\n}\n\n// Transform builds a new Obj giving the transformer a chance\n// to change the keys and values as it goes. This method requires that\n// the wrapped object be a map[string]interface{}\nfunc (m Map) Transform(transformer func(key string, value interface{}) (string, interface{})) Map {\n\tnewMap := make(map[string]interface{})\n\tfor k, v := range m {\n\t\tmodifiedKey, modifiedVal := transformer(k, v)\n\t\tnewMap[modifiedKey] = modifiedVal\n\t}\n\treturn New(newMap)\n}\n\n// TransformKeys builds a new map using the specified key mapping.\n//\n// Unspecified keys will be unaltered.\n// This method requires that the wrapped object be a map[string]interface{}\nfunc (m Map) TransformKeys(mapping map[string]string) Map {\n\treturn m.Transform(func(key string, value interface{}) (string, interface{}) {\n\n\t\tif newKey, ok := mapping[key]; ok {\n\t\t\treturn newKey, value\n\t\t}\n\n\t\treturn key, value\n\t})\n}\n"
  },
  {
    "path": "vendor/github.com/stretchr/objx/security.go",
    "content": "package objx\n\nimport (\n\t\"crypto/sha1\"\n\t\"encoding/hex\"\n)\n\n// HashWithKey hashes the specified string using the security\n// key.\nfunc HashWithKey(data, key string) string {\n\thash := sha1.New()\n\thash.Write([]byte(data + \":\" + key))\n\treturn hex.EncodeToString(hash.Sum(nil))\n}\n"
  },
  {
    "path": "vendor/github.com/stretchr/objx/tests.go",
    "content": "package objx\n\n// Has gets whether there is something at the specified selector\n// or not.\n//\n// If m is nil, Has will always return false.\nfunc (m Map) Has(selector string) bool {\n\tif m == nil {\n\t\treturn false\n\t}\n\treturn !m.Get(selector).IsNil()\n}\n\n// IsNil gets whether the data is nil or not.\nfunc (v *Value) IsNil() bool {\n\treturn v == nil || v.data == nil\n}\n"
  },
  {
    "path": "vendor/github.com/stretchr/objx/type_specific_codegen.go",
    "content": "package objx\n\n/*\n\tInter (interface{} and []interface{})\n\t--------------------------------------------------\n*/\n\n// Inter gets the value as a interface{}, returns the optionalDefault\n// value or a system default object if the value is the wrong type.\nfunc (v *Value) Inter(optionalDefault ...interface{}) interface{} {\n\tif s, ok := v.data.(interface{}); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn nil\n}\n\n// MustInter gets the value as a interface{}.\n//\n// Panics if the object is not a interface{}.\nfunc (v *Value) MustInter() interface{} {\n\treturn v.data.(interface{})\n}\n\n// InterSlice gets the value as a []interface{}, returns the optionalDefault\n// value or nil if the value is not a []interface{}.\nfunc (v *Value) InterSlice(optionalDefault ...[]interface{}) []interface{} {\n\tif s, ok := v.data.([]interface{}); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn nil\n}\n\n// MustInterSlice gets the value as a []interface{}.\n//\n// Panics if the object is not a []interface{}.\nfunc (v *Value) MustInterSlice() []interface{} {\n\treturn v.data.([]interface{})\n}\n\n// IsInter gets whether the object contained is a interface{} or not.\nfunc (v *Value) IsInter() bool {\n\t_, ok := v.data.(interface{})\n\treturn ok\n}\n\n// IsInterSlice gets whether the object contained is a []interface{} or not.\nfunc (v *Value) IsInterSlice() bool {\n\t_, ok := v.data.([]interface{})\n\treturn ok\n}\n\n// EachInter calls the specified callback for each object\n// in the []interface{}.\n//\n// Panics if the object is the wrong type.\nfunc (v *Value) EachInter(callback func(int, interface{}) bool) *Value {\n\n\tfor index, val := range v.MustInterSlice() {\n\t\tcarryon := callback(index, val)\n\t\tif carryon == false {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn v\n\n}\n\n// WhereInter uses the specified decider function to select items\n// from the []interface{}.  The object contained in the result will contain\n// only the selected items.\nfunc (v *Value) WhereInter(decider func(int, interface{}) bool) *Value {\n\n\tvar selected []interface{}\n\n\tv.EachInter(func(index int, val interface{}) bool {\n\t\tshouldSelect := decider(index, val)\n\t\tif shouldSelect == false {\n\t\t\tselected = append(selected, val)\n\t\t}\n\t\treturn true\n\t})\n\n\treturn &Value{data: selected}\n\n}\n\n// GroupInter uses the specified grouper function to group the items\n// keyed by the return of the grouper.  The object contained in the\n// result will contain a map[string][]interface{}.\nfunc (v *Value) GroupInter(grouper func(int, interface{}) string) *Value {\n\n\tgroups := make(map[string][]interface{})\n\n\tv.EachInter(func(index int, val interface{}) bool {\n\t\tgroup := grouper(index, val)\n\t\tif _, ok := groups[group]; !ok {\n\t\t\tgroups[group] = make([]interface{}, 0)\n\t\t}\n\t\tgroups[group] = append(groups[group], val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: groups}\n\n}\n\n// ReplaceInter uses the specified function to replace each interface{}s\n// by iterating each item.  The data in the returned result will be a\n// []interface{} containing the replaced items.\nfunc (v *Value) ReplaceInter(replacer func(int, interface{}) interface{}) *Value {\n\n\tarr := v.MustInterSlice()\n\treplaced := make([]interface{}, len(arr))\n\n\tv.EachInter(func(index int, val interface{}) bool {\n\t\treplaced[index] = replacer(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: replaced}\n\n}\n\n// CollectInter uses the specified collector function to collect a value\n// for each of the interface{}s in the slice.  The data returned will be a\n// []interface{}.\nfunc (v *Value) CollectInter(collector func(int, interface{}) interface{}) *Value {\n\n\tarr := v.MustInterSlice()\n\tcollected := make([]interface{}, len(arr))\n\n\tv.EachInter(func(index int, val interface{}) bool {\n\t\tcollected[index] = collector(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: collected}\n}\n\n/*\n\tMSI (map[string]interface{} and []map[string]interface{})\n\t--------------------------------------------------\n*/\n\n// MSI gets the value as a map[string]interface{}, returns the optionalDefault\n// value or a system default object if the value is the wrong type.\nfunc (v *Value) MSI(optionalDefault ...map[string]interface{}) map[string]interface{} {\n\tif s, ok := v.data.(map[string]interface{}); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn nil\n}\n\n// MustMSI gets the value as a map[string]interface{}.\n//\n// Panics if the object is not a map[string]interface{}.\nfunc (v *Value) MustMSI() map[string]interface{} {\n\treturn v.data.(map[string]interface{})\n}\n\n// MSISlice gets the value as a []map[string]interface{}, returns the optionalDefault\n// value or nil if the value is not a []map[string]interface{}.\nfunc (v *Value) MSISlice(optionalDefault ...[]map[string]interface{}) []map[string]interface{} {\n\tif s, ok := v.data.([]map[string]interface{}); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn nil\n}\n\n// MustMSISlice gets the value as a []map[string]interface{}.\n//\n// Panics if the object is not a []map[string]interface{}.\nfunc (v *Value) MustMSISlice() []map[string]interface{} {\n\treturn v.data.([]map[string]interface{})\n}\n\n// IsMSI gets whether the object contained is a map[string]interface{} or not.\nfunc (v *Value) IsMSI() bool {\n\t_, ok := v.data.(map[string]interface{})\n\treturn ok\n}\n\n// IsMSISlice gets whether the object contained is a []map[string]interface{} or not.\nfunc (v *Value) IsMSISlice() bool {\n\t_, ok := v.data.([]map[string]interface{})\n\treturn ok\n}\n\n// EachMSI calls the specified callback for each object\n// in the []map[string]interface{}.\n//\n// Panics if the object is the wrong type.\nfunc (v *Value) EachMSI(callback func(int, map[string]interface{}) bool) *Value {\n\n\tfor index, val := range v.MustMSISlice() {\n\t\tcarryon := callback(index, val)\n\t\tif carryon == false {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn v\n\n}\n\n// WhereMSI uses the specified decider function to select items\n// from the []map[string]interface{}.  The object contained in the result will contain\n// only the selected items.\nfunc (v *Value) WhereMSI(decider func(int, map[string]interface{}) bool) *Value {\n\n\tvar selected []map[string]interface{}\n\n\tv.EachMSI(func(index int, val map[string]interface{}) bool {\n\t\tshouldSelect := decider(index, val)\n\t\tif shouldSelect == false {\n\t\t\tselected = append(selected, val)\n\t\t}\n\t\treturn true\n\t})\n\n\treturn &Value{data: selected}\n\n}\n\n// GroupMSI uses the specified grouper function to group the items\n// keyed by the return of the grouper.  The object contained in the\n// result will contain a map[string][]map[string]interface{}.\nfunc (v *Value) GroupMSI(grouper func(int, map[string]interface{}) string) *Value {\n\n\tgroups := make(map[string][]map[string]interface{})\n\n\tv.EachMSI(func(index int, val map[string]interface{}) bool {\n\t\tgroup := grouper(index, val)\n\t\tif _, ok := groups[group]; !ok {\n\t\t\tgroups[group] = make([]map[string]interface{}, 0)\n\t\t}\n\t\tgroups[group] = append(groups[group], val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: groups}\n\n}\n\n// ReplaceMSI uses the specified function to replace each map[string]interface{}s\n// by iterating each item.  The data in the returned result will be a\n// []map[string]interface{} containing the replaced items.\nfunc (v *Value) ReplaceMSI(replacer func(int, map[string]interface{}) map[string]interface{}) *Value {\n\n\tarr := v.MustMSISlice()\n\treplaced := make([]map[string]interface{}, len(arr))\n\n\tv.EachMSI(func(index int, val map[string]interface{}) bool {\n\t\treplaced[index] = replacer(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: replaced}\n\n}\n\n// CollectMSI uses the specified collector function to collect a value\n// for each of the map[string]interface{}s in the slice.  The data returned will be a\n// []interface{}.\nfunc (v *Value) CollectMSI(collector func(int, map[string]interface{}) interface{}) *Value {\n\n\tarr := v.MustMSISlice()\n\tcollected := make([]interface{}, len(arr))\n\n\tv.EachMSI(func(index int, val map[string]interface{}) bool {\n\t\tcollected[index] = collector(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: collected}\n}\n\n/*\n\tObjxMap ((Map) and [](Map))\n\t--------------------------------------------------\n*/\n\n// ObjxMap gets the value as a (Map), returns the optionalDefault\n// value or a system default object if the value is the wrong type.\nfunc (v *Value) ObjxMap(optionalDefault ...(Map)) Map {\n\tif s, ok := v.data.((Map)); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn New(nil)\n}\n\n// MustObjxMap gets the value as a (Map).\n//\n// Panics if the object is not a (Map).\nfunc (v *Value) MustObjxMap() Map {\n\treturn v.data.((Map))\n}\n\n// ObjxMapSlice gets the value as a [](Map), returns the optionalDefault\n// value or nil if the value is not a [](Map).\nfunc (v *Value) ObjxMapSlice(optionalDefault ...[](Map)) [](Map) {\n\tif s, ok := v.data.([](Map)); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn nil\n}\n\n// MustObjxMapSlice gets the value as a [](Map).\n//\n// Panics if the object is not a [](Map).\nfunc (v *Value) MustObjxMapSlice() [](Map) {\n\treturn v.data.([](Map))\n}\n\n// IsObjxMap gets whether the object contained is a (Map) or not.\nfunc (v *Value) IsObjxMap() bool {\n\t_, ok := v.data.((Map))\n\treturn ok\n}\n\n// IsObjxMapSlice gets whether the object contained is a [](Map) or not.\nfunc (v *Value) IsObjxMapSlice() bool {\n\t_, ok := v.data.([](Map))\n\treturn ok\n}\n\n// EachObjxMap calls the specified callback for each object\n// in the [](Map).\n//\n// Panics if the object is the wrong type.\nfunc (v *Value) EachObjxMap(callback func(int, Map) bool) *Value {\n\n\tfor index, val := range v.MustObjxMapSlice() {\n\t\tcarryon := callback(index, val)\n\t\tif carryon == false {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn v\n\n}\n\n// WhereObjxMap uses the specified decider function to select items\n// from the [](Map).  The object contained in the result will contain\n// only the selected items.\nfunc (v *Value) WhereObjxMap(decider func(int, Map) bool) *Value {\n\n\tvar selected [](Map)\n\n\tv.EachObjxMap(func(index int, val Map) bool {\n\t\tshouldSelect := decider(index, val)\n\t\tif shouldSelect == false {\n\t\t\tselected = append(selected, val)\n\t\t}\n\t\treturn true\n\t})\n\n\treturn &Value{data: selected}\n\n}\n\n// GroupObjxMap uses the specified grouper function to group the items\n// keyed by the return of the grouper.  The object contained in the\n// result will contain a map[string][](Map).\nfunc (v *Value) GroupObjxMap(grouper func(int, Map) string) *Value {\n\n\tgroups := make(map[string][](Map))\n\n\tv.EachObjxMap(func(index int, val Map) bool {\n\t\tgroup := grouper(index, val)\n\t\tif _, ok := groups[group]; !ok {\n\t\t\tgroups[group] = make([](Map), 0)\n\t\t}\n\t\tgroups[group] = append(groups[group], val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: groups}\n\n}\n\n// ReplaceObjxMap uses the specified function to replace each (Map)s\n// by iterating each item.  The data in the returned result will be a\n// [](Map) containing the replaced items.\nfunc (v *Value) ReplaceObjxMap(replacer func(int, Map) Map) *Value {\n\n\tarr := v.MustObjxMapSlice()\n\treplaced := make([](Map), len(arr))\n\n\tv.EachObjxMap(func(index int, val Map) bool {\n\t\treplaced[index] = replacer(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: replaced}\n\n}\n\n// CollectObjxMap uses the specified collector function to collect a value\n// for each of the (Map)s in the slice.  The data returned will be a\n// []interface{}.\nfunc (v *Value) CollectObjxMap(collector func(int, Map) interface{}) *Value {\n\n\tarr := v.MustObjxMapSlice()\n\tcollected := make([]interface{}, len(arr))\n\n\tv.EachObjxMap(func(index int, val Map) bool {\n\t\tcollected[index] = collector(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: collected}\n}\n\n/*\n\tBool (bool and []bool)\n\t--------------------------------------------------\n*/\n\n// Bool gets the value as a bool, returns the optionalDefault\n// value or a system default object if the value is the wrong type.\nfunc (v *Value) Bool(optionalDefault ...bool) bool {\n\tif s, ok := v.data.(bool); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn false\n}\n\n// MustBool gets the value as a bool.\n//\n// Panics if the object is not a bool.\nfunc (v *Value) MustBool() bool {\n\treturn v.data.(bool)\n}\n\n// BoolSlice gets the value as a []bool, returns the optionalDefault\n// value or nil if the value is not a []bool.\nfunc (v *Value) BoolSlice(optionalDefault ...[]bool) []bool {\n\tif s, ok := v.data.([]bool); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn nil\n}\n\n// MustBoolSlice gets the value as a []bool.\n//\n// Panics if the object is not a []bool.\nfunc (v *Value) MustBoolSlice() []bool {\n\treturn v.data.([]bool)\n}\n\n// IsBool gets whether the object contained is a bool or not.\nfunc (v *Value) IsBool() bool {\n\t_, ok := v.data.(bool)\n\treturn ok\n}\n\n// IsBoolSlice gets whether the object contained is a []bool or not.\nfunc (v *Value) IsBoolSlice() bool {\n\t_, ok := v.data.([]bool)\n\treturn ok\n}\n\n// EachBool calls the specified callback for each object\n// in the []bool.\n//\n// Panics if the object is the wrong type.\nfunc (v *Value) EachBool(callback func(int, bool) bool) *Value {\n\n\tfor index, val := range v.MustBoolSlice() {\n\t\tcarryon := callback(index, val)\n\t\tif carryon == false {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn v\n\n}\n\n// WhereBool uses the specified decider function to select items\n// from the []bool.  The object contained in the result will contain\n// only the selected items.\nfunc (v *Value) WhereBool(decider func(int, bool) bool) *Value {\n\n\tvar selected []bool\n\n\tv.EachBool(func(index int, val bool) bool {\n\t\tshouldSelect := decider(index, val)\n\t\tif shouldSelect == false {\n\t\t\tselected = append(selected, val)\n\t\t}\n\t\treturn true\n\t})\n\n\treturn &Value{data: selected}\n\n}\n\n// GroupBool uses the specified grouper function to group the items\n// keyed by the return of the grouper.  The object contained in the\n// result will contain a map[string][]bool.\nfunc (v *Value) GroupBool(grouper func(int, bool) string) *Value {\n\n\tgroups := make(map[string][]bool)\n\n\tv.EachBool(func(index int, val bool) bool {\n\t\tgroup := grouper(index, val)\n\t\tif _, ok := groups[group]; !ok {\n\t\t\tgroups[group] = make([]bool, 0)\n\t\t}\n\t\tgroups[group] = append(groups[group], val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: groups}\n\n}\n\n// ReplaceBool uses the specified function to replace each bools\n// by iterating each item.  The data in the returned result will be a\n// []bool containing the replaced items.\nfunc (v *Value) ReplaceBool(replacer func(int, bool) bool) *Value {\n\n\tarr := v.MustBoolSlice()\n\treplaced := make([]bool, len(arr))\n\n\tv.EachBool(func(index int, val bool) bool {\n\t\treplaced[index] = replacer(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: replaced}\n\n}\n\n// CollectBool uses the specified collector function to collect a value\n// for each of the bools in the slice.  The data returned will be a\n// []interface{}.\nfunc (v *Value) CollectBool(collector func(int, bool) interface{}) *Value {\n\n\tarr := v.MustBoolSlice()\n\tcollected := make([]interface{}, len(arr))\n\n\tv.EachBool(func(index int, val bool) bool {\n\t\tcollected[index] = collector(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: collected}\n}\n\n/*\n\tStr (string and []string)\n\t--------------------------------------------------\n*/\n\n// Str gets the value as a string, returns the optionalDefault\n// value or a system default object if the value is the wrong type.\nfunc (v *Value) Str(optionalDefault ...string) string {\n\tif s, ok := v.data.(string); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn \"\"\n}\n\n// MustStr gets the value as a string.\n//\n// Panics if the object is not a string.\nfunc (v *Value) MustStr() string {\n\treturn v.data.(string)\n}\n\n// StrSlice gets the value as a []string, returns the optionalDefault\n// value or nil if the value is not a []string.\nfunc (v *Value) StrSlice(optionalDefault ...[]string) []string {\n\tif s, ok := v.data.([]string); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn nil\n}\n\n// MustStrSlice gets the value as a []string.\n//\n// Panics if the object is not a []string.\nfunc (v *Value) MustStrSlice() []string {\n\treturn v.data.([]string)\n}\n\n// IsStr gets whether the object contained is a string or not.\nfunc (v *Value) IsStr() bool {\n\t_, ok := v.data.(string)\n\treturn ok\n}\n\n// IsStrSlice gets whether the object contained is a []string or not.\nfunc (v *Value) IsStrSlice() bool {\n\t_, ok := v.data.([]string)\n\treturn ok\n}\n\n// EachStr calls the specified callback for each object\n// in the []string.\n//\n// Panics if the object is the wrong type.\nfunc (v *Value) EachStr(callback func(int, string) bool) *Value {\n\n\tfor index, val := range v.MustStrSlice() {\n\t\tcarryon := callback(index, val)\n\t\tif carryon == false {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn v\n\n}\n\n// WhereStr uses the specified decider function to select items\n// from the []string.  The object contained in the result will contain\n// only the selected items.\nfunc (v *Value) WhereStr(decider func(int, string) bool) *Value {\n\n\tvar selected []string\n\n\tv.EachStr(func(index int, val string) bool {\n\t\tshouldSelect := decider(index, val)\n\t\tif shouldSelect == false {\n\t\t\tselected = append(selected, val)\n\t\t}\n\t\treturn true\n\t})\n\n\treturn &Value{data: selected}\n\n}\n\n// GroupStr uses the specified grouper function to group the items\n// keyed by the return of the grouper.  The object contained in the\n// result will contain a map[string][]string.\nfunc (v *Value) GroupStr(grouper func(int, string) string) *Value {\n\n\tgroups := make(map[string][]string)\n\n\tv.EachStr(func(index int, val string) bool {\n\t\tgroup := grouper(index, val)\n\t\tif _, ok := groups[group]; !ok {\n\t\t\tgroups[group] = make([]string, 0)\n\t\t}\n\t\tgroups[group] = append(groups[group], val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: groups}\n\n}\n\n// ReplaceStr uses the specified function to replace each strings\n// by iterating each item.  The data in the returned result will be a\n// []string containing the replaced items.\nfunc (v *Value) ReplaceStr(replacer func(int, string) string) *Value {\n\n\tarr := v.MustStrSlice()\n\treplaced := make([]string, len(arr))\n\n\tv.EachStr(func(index int, val string) bool {\n\t\treplaced[index] = replacer(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: replaced}\n\n}\n\n// CollectStr uses the specified collector function to collect a value\n// for each of the strings in the slice.  The data returned will be a\n// []interface{}.\nfunc (v *Value) CollectStr(collector func(int, string) interface{}) *Value {\n\n\tarr := v.MustStrSlice()\n\tcollected := make([]interface{}, len(arr))\n\n\tv.EachStr(func(index int, val string) bool {\n\t\tcollected[index] = collector(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: collected}\n}\n\n/*\n\tInt (int and []int)\n\t--------------------------------------------------\n*/\n\n// Int gets the value as a int, returns the optionalDefault\n// value or a system default object if the value is the wrong type.\nfunc (v *Value) Int(optionalDefault ...int) int {\n\tif s, ok := v.data.(int); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn 0\n}\n\n// MustInt gets the value as a int.\n//\n// Panics if the object is not a int.\nfunc (v *Value) MustInt() int {\n\treturn v.data.(int)\n}\n\n// IntSlice gets the value as a []int, returns the optionalDefault\n// value or nil if the value is not a []int.\nfunc (v *Value) IntSlice(optionalDefault ...[]int) []int {\n\tif s, ok := v.data.([]int); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn nil\n}\n\n// MustIntSlice gets the value as a []int.\n//\n// Panics if the object is not a []int.\nfunc (v *Value) MustIntSlice() []int {\n\treturn v.data.([]int)\n}\n\n// IsInt gets whether the object contained is a int or not.\nfunc (v *Value) IsInt() bool {\n\t_, ok := v.data.(int)\n\treturn ok\n}\n\n// IsIntSlice gets whether the object contained is a []int or not.\nfunc (v *Value) IsIntSlice() bool {\n\t_, ok := v.data.([]int)\n\treturn ok\n}\n\n// EachInt calls the specified callback for each object\n// in the []int.\n//\n// Panics if the object is the wrong type.\nfunc (v *Value) EachInt(callback func(int, int) bool) *Value {\n\n\tfor index, val := range v.MustIntSlice() {\n\t\tcarryon := callback(index, val)\n\t\tif carryon == false {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn v\n\n}\n\n// WhereInt uses the specified decider function to select items\n// from the []int.  The object contained in the result will contain\n// only the selected items.\nfunc (v *Value) WhereInt(decider func(int, int) bool) *Value {\n\n\tvar selected []int\n\n\tv.EachInt(func(index int, val int) bool {\n\t\tshouldSelect := decider(index, val)\n\t\tif shouldSelect == false {\n\t\t\tselected = append(selected, val)\n\t\t}\n\t\treturn true\n\t})\n\n\treturn &Value{data: selected}\n\n}\n\n// GroupInt uses the specified grouper function to group the items\n// keyed by the return of the grouper.  The object contained in the\n// result will contain a map[string][]int.\nfunc (v *Value) GroupInt(grouper func(int, int) string) *Value {\n\n\tgroups := make(map[string][]int)\n\n\tv.EachInt(func(index int, val int) bool {\n\t\tgroup := grouper(index, val)\n\t\tif _, ok := groups[group]; !ok {\n\t\t\tgroups[group] = make([]int, 0)\n\t\t}\n\t\tgroups[group] = append(groups[group], val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: groups}\n\n}\n\n// ReplaceInt uses the specified function to replace each ints\n// by iterating each item.  The data in the returned result will be a\n// []int containing the replaced items.\nfunc (v *Value) ReplaceInt(replacer func(int, int) int) *Value {\n\n\tarr := v.MustIntSlice()\n\treplaced := make([]int, len(arr))\n\n\tv.EachInt(func(index int, val int) bool {\n\t\treplaced[index] = replacer(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: replaced}\n\n}\n\n// CollectInt uses the specified collector function to collect a value\n// for each of the ints in the slice.  The data returned will be a\n// []interface{}.\nfunc (v *Value) CollectInt(collector func(int, int) interface{}) *Value {\n\n\tarr := v.MustIntSlice()\n\tcollected := make([]interface{}, len(arr))\n\n\tv.EachInt(func(index int, val int) bool {\n\t\tcollected[index] = collector(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: collected}\n}\n\n/*\n\tInt8 (int8 and []int8)\n\t--------------------------------------------------\n*/\n\n// Int8 gets the value as a int8, returns the optionalDefault\n// value or a system default object if the value is the wrong type.\nfunc (v *Value) Int8(optionalDefault ...int8) int8 {\n\tif s, ok := v.data.(int8); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn 0\n}\n\n// MustInt8 gets the value as a int8.\n//\n// Panics if the object is not a int8.\nfunc (v *Value) MustInt8() int8 {\n\treturn v.data.(int8)\n}\n\n// Int8Slice gets the value as a []int8, returns the optionalDefault\n// value or nil if the value is not a []int8.\nfunc (v *Value) Int8Slice(optionalDefault ...[]int8) []int8 {\n\tif s, ok := v.data.([]int8); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn nil\n}\n\n// MustInt8Slice gets the value as a []int8.\n//\n// Panics if the object is not a []int8.\nfunc (v *Value) MustInt8Slice() []int8 {\n\treturn v.data.([]int8)\n}\n\n// IsInt8 gets whether the object contained is a int8 or not.\nfunc (v *Value) IsInt8() bool {\n\t_, ok := v.data.(int8)\n\treturn ok\n}\n\n// IsInt8Slice gets whether the object contained is a []int8 or not.\nfunc (v *Value) IsInt8Slice() bool {\n\t_, ok := v.data.([]int8)\n\treturn ok\n}\n\n// EachInt8 calls the specified callback for each object\n// in the []int8.\n//\n// Panics if the object is the wrong type.\nfunc (v *Value) EachInt8(callback func(int, int8) bool) *Value {\n\n\tfor index, val := range v.MustInt8Slice() {\n\t\tcarryon := callback(index, val)\n\t\tif carryon == false {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn v\n\n}\n\n// WhereInt8 uses the specified decider function to select items\n// from the []int8.  The object contained in the result will contain\n// only the selected items.\nfunc (v *Value) WhereInt8(decider func(int, int8) bool) *Value {\n\n\tvar selected []int8\n\n\tv.EachInt8(func(index int, val int8) bool {\n\t\tshouldSelect := decider(index, val)\n\t\tif shouldSelect == false {\n\t\t\tselected = append(selected, val)\n\t\t}\n\t\treturn true\n\t})\n\n\treturn &Value{data: selected}\n\n}\n\n// GroupInt8 uses the specified grouper function to group the items\n// keyed by the return of the grouper.  The object contained in the\n// result will contain a map[string][]int8.\nfunc (v *Value) GroupInt8(grouper func(int, int8) string) *Value {\n\n\tgroups := make(map[string][]int8)\n\n\tv.EachInt8(func(index int, val int8) bool {\n\t\tgroup := grouper(index, val)\n\t\tif _, ok := groups[group]; !ok {\n\t\t\tgroups[group] = make([]int8, 0)\n\t\t}\n\t\tgroups[group] = append(groups[group], val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: groups}\n\n}\n\n// ReplaceInt8 uses the specified function to replace each int8s\n// by iterating each item.  The data in the returned result will be a\n// []int8 containing the replaced items.\nfunc (v *Value) ReplaceInt8(replacer func(int, int8) int8) *Value {\n\n\tarr := v.MustInt8Slice()\n\treplaced := make([]int8, len(arr))\n\n\tv.EachInt8(func(index int, val int8) bool {\n\t\treplaced[index] = replacer(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: replaced}\n\n}\n\n// CollectInt8 uses the specified collector function to collect a value\n// for each of the int8s in the slice.  The data returned will be a\n// []interface{}.\nfunc (v *Value) CollectInt8(collector func(int, int8) interface{}) *Value {\n\n\tarr := v.MustInt8Slice()\n\tcollected := make([]interface{}, len(arr))\n\n\tv.EachInt8(func(index int, val int8) bool {\n\t\tcollected[index] = collector(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: collected}\n}\n\n/*\n\tInt16 (int16 and []int16)\n\t--------------------------------------------------\n*/\n\n// Int16 gets the value as a int16, returns the optionalDefault\n// value or a system default object if the value is the wrong type.\nfunc (v *Value) Int16(optionalDefault ...int16) int16 {\n\tif s, ok := v.data.(int16); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn 0\n}\n\n// MustInt16 gets the value as a int16.\n//\n// Panics if the object is not a int16.\nfunc (v *Value) MustInt16() int16 {\n\treturn v.data.(int16)\n}\n\n// Int16Slice gets the value as a []int16, returns the optionalDefault\n// value or nil if the value is not a []int16.\nfunc (v *Value) Int16Slice(optionalDefault ...[]int16) []int16 {\n\tif s, ok := v.data.([]int16); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn nil\n}\n\n// MustInt16Slice gets the value as a []int16.\n//\n// Panics if the object is not a []int16.\nfunc (v *Value) MustInt16Slice() []int16 {\n\treturn v.data.([]int16)\n}\n\n// IsInt16 gets whether the object contained is a int16 or not.\nfunc (v *Value) IsInt16() bool {\n\t_, ok := v.data.(int16)\n\treturn ok\n}\n\n// IsInt16Slice gets whether the object contained is a []int16 or not.\nfunc (v *Value) IsInt16Slice() bool {\n\t_, ok := v.data.([]int16)\n\treturn ok\n}\n\n// EachInt16 calls the specified callback for each object\n// in the []int16.\n//\n// Panics if the object is the wrong type.\nfunc (v *Value) EachInt16(callback func(int, int16) bool) *Value {\n\n\tfor index, val := range v.MustInt16Slice() {\n\t\tcarryon := callback(index, val)\n\t\tif carryon == false {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn v\n\n}\n\n// WhereInt16 uses the specified decider function to select items\n// from the []int16.  The object contained in the result will contain\n// only the selected items.\nfunc (v *Value) WhereInt16(decider func(int, int16) bool) *Value {\n\n\tvar selected []int16\n\n\tv.EachInt16(func(index int, val int16) bool {\n\t\tshouldSelect := decider(index, val)\n\t\tif shouldSelect == false {\n\t\t\tselected = append(selected, val)\n\t\t}\n\t\treturn true\n\t})\n\n\treturn &Value{data: selected}\n\n}\n\n// GroupInt16 uses the specified grouper function to group the items\n// keyed by the return of the grouper.  The object contained in the\n// result will contain a map[string][]int16.\nfunc (v *Value) GroupInt16(grouper func(int, int16) string) *Value {\n\n\tgroups := make(map[string][]int16)\n\n\tv.EachInt16(func(index int, val int16) bool {\n\t\tgroup := grouper(index, val)\n\t\tif _, ok := groups[group]; !ok {\n\t\t\tgroups[group] = make([]int16, 0)\n\t\t}\n\t\tgroups[group] = append(groups[group], val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: groups}\n\n}\n\n// ReplaceInt16 uses the specified function to replace each int16s\n// by iterating each item.  The data in the returned result will be a\n// []int16 containing the replaced items.\nfunc (v *Value) ReplaceInt16(replacer func(int, int16) int16) *Value {\n\n\tarr := v.MustInt16Slice()\n\treplaced := make([]int16, len(arr))\n\n\tv.EachInt16(func(index int, val int16) bool {\n\t\treplaced[index] = replacer(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: replaced}\n\n}\n\n// CollectInt16 uses the specified collector function to collect a value\n// for each of the int16s in the slice.  The data returned will be a\n// []interface{}.\nfunc (v *Value) CollectInt16(collector func(int, int16) interface{}) *Value {\n\n\tarr := v.MustInt16Slice()\n\tcollected := make([]interface{}, len(arr))\n\n\tv.EachInt16(func(index int, val int16) bool {\n\t\tcollected[index] = collector(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: collected}\n}\n\n/*\n\tInt32 (int32 and []int32)\n\t--------------------------------------------------\n*/\n\n// Int32 gets the value as a int32, returns the optionalDefault\n// value or a system default object if the value is the wrong type.\nfunc (v *Value) Int32(optionalDefault ...int32) int32 {\n\tif s, ok := v.data.(int32); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn 0\n}\n\n// MustInt32 gets the value as a int32.\n//\n// Panics if the object is not a int32.\nfunc (v *Value) MustInt32() int32 {\n\treturn v.data.(int32)\n}\n\n// Int32Slice gets the value as a []int32, returns the optionalDefault\n// value or nil if the value is not a []int32.\nfunc (v *Value) Int32Slice(optionalDefault ...[]int32) []int32 {\n\tif s, ok := v.data.([]int32); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn nil\n}\n\n// MustInt32Slice gets the value as a []int32.\n//\n// Panics if the object is not a []int32.\nfunc (v *Value) MustInt32Slice() []int32 {\n\treturn v.data.([]int32)\n}\n\n// IsInt32 gets whether the object contained is a int32 or not.\nfunc (v *Value) IsInt32() bool {\n\t_, ok := v.data.(int32)\n\treturn ok\n}\n\n// IsInt32Slice gets whether the object contained is a []int32 or not.\nfunc (v *Value) IsInt32Slice() bool {\n\t_, ok := v.data.([]int32)\n\treturn ok\n}\n\n// EachInt32 calls the specified callback for each object\n// in the []int32.\n//\n// Panics if the object is the wrong type.\nfunc (v *Value) EachInt32(callback func(int, int32) bool) *Value {\n\n\tfor index, val := range v.MustInt32Slice() {\n\t\tcarryon := callback(index, val)\n\t\tif carryon == false {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn v\n\n}\n\n// WhereInt32 uses the specified decider function to select items\n// from the []int32.  The object contained in the result will contain\n// only the selected items.\nfunc (v *Value) WhereInt32(decider func(int, int32) bool) *Value {\n\n\tvar selected []int32\n\n\tv.EachInt32(func(index int, val int32) bool {\n\t\tshouldSelect := decider(index, val)\n\t\tif shouldSelect == false {\n\t\t\tselected = append(selected, val)\n\t\t}\n\t\treturn true\n\t})\n\n\treturn &Value{data: selected}\n\n}\n\n// GroupInt32 uses the specified grouper function to group the items\n// keyed by the return of the grouper.  The object contained in the\n// result will contain a map[string][]int32.\nfunc (v *Value) GroupInt32(grouper func(int, int32) string) *Value {\n\n\tgroups := make(map[string][]int32)\n\n\tv.EachInt32(func(index int, val int32) bool {\n\t\tgroup := grouper(index, val)\n\t\tif _, ok := groups[group]; !ok {\n\t\t\tgroups[group] = make([]int32, 0)\n\t\t}\n\t\tgroups[group] = append(groups[group], val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: groups}\n\n}\n\n// ReplaceInt32 uses the specified function to replace each int32s\n// by iterating each item.  The data in the returned result will be a\n// []int32 containing the replaced items.\nfunc (v *Value) ReplaceInt32(replacer func(int, int32) int32) *Value {\n\n\tarr := v.MustInt32Slice()\n\treplaced := make([]int32, len(arr))\n\n\tv.EachInt32(func(index int, val int32) bool {\n\t\treplaced[index] = replacer(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: replaced}\n\n}\n\n// CollectInt32 uses the specified collector function to collect a value\n// for each of the int32s in the slice.  The data returned will be a\n// []interface{}.\nfunc (v *Value) CollectInt32(collector func(int, int32) interface{}) *Value {\n\n\tarr := v.MustInt32Slice()\n\tcollected := make([]interface{}, len(arr))\n\n\tv.EachInt32(func(index int, val int32) bool {\n\t\tcollected[index] = collector(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: collected}\n}\n\n/*\n\tInt64 (int64 and []int64)\n\t--------------------------------------------------\n*/\n\n// Int64 gets the value as a int64, returns the optionalDefault\n// value or a system default object if the value is the wrong type.\nfunc (v *Value) Int64(optionalDefault ...int64) int64 {\n\tif s, ok := v.data.(int64); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn 0\n}\n\n// MustInt64 gets the value as a int64.\n//\n// Panics if the object is not a int64.\nfunc (v *Value) MustInt64() int64 {\n\treturn v.data.(int64)\n}\n\n// Int64Slice gets the value as a []int64, returns the optionalDefault\n// value or nil if the value is not a []int64.\nfunc (v *Value) Int64Slice(optionalDefault ...[]int64) []int64 {\n\tif s, ok := v.data.([]int64); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn nil\n}\n\n// MustInt64Slice gets the value as a []int64.\n//\n// Panics if the object is not a []int64.\nfunc (v *Value) MustInt64Slice() []int64 {\n\treturn v.data.([]int64)\n}\n\n// IsInt64 gets whether the object contained is a int64 or not.\nfunc (v *Value) IsInt64() bool {\n\t_, ok := v.data.(int64)\n\treturn ok\n}\n\n// IsInt64Slice gets whether the object contained is a []int64 or not.\nfunc (v *Value) IsInt64Slice() bool {\n\t_, ok := v.data.([]int64)\n\treturn ok\n}\n\n// EachInt64 calls the specified callback for each object\n// in the []int64.\n//\n// Panics if the object is the wrong type.\nfunc (v *Value) EachInt64(callback func(int, int64) bool) *Value {\n\n\tfor index, val := range v.MustInt64Slice() {\n\t\tcarryon := callback(index, val)\n\t\tif carryon == false {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn v\n\n}\n\n// WhereInt64 uses the specified decider function to select items\n// from the []int64.  The object contained in the result will contain\n// only the selected items.\nfunc (v *Value) WhereInt64(decider func(int, int64) bool) *Value {\n\n\tvar selected []int64\n\n\tv.EachInt64(func(index int, val int64) bool {\n\t\tshouldSelect := decider(index, val)\n\t\tif shouldSelect == false {\n\t\t\tselected = append(selected, val)\n\t\t}\n\t\treturn true\n\t})\n\n\treturn &Value{data: selected}\n\n}\n\n// GroupInt64 uses the specified grouper function to group the items\n// keyed by the return of the grouper.  The object contained in the\n// result will contain a map[string][]int64.\nfunc (v *Value) GroupInt64(grouper func(int, int64) string) *Value {\n\n\tgroups := make(map[string][]int64)\n\n\tv.EachInt64(func(index int, val int64) bool {\n\t\tgroup := grouper(index, val)\n\t\tif _, ok := groups[group]; !ok {\n\t\t\tgroups[group] = make([]int64, 0)\n\t\t}\n\t\tgroups[group] = append(groups[group], val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: groups}\n\n}\n\n// ReplaceInt64 uses the specified function to replace each int64s\n// by iterating each item.  The data in the returned result will be a\n// []int64 containing the replaced items.\nfunc (v *Value) ReplaceInt64(replacer func(int, int64) int64) *Value {\n\n\tarr := v.MustInt64Slice()\n\treplaced := make([]int64, len(arr))\n\n\tv.EachInt64(func(index int, val int64) bool {\n\t\treplaced[index] = replacer(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: replaced}\n\n}\n\n// CollectInt64 uses the specified collector function to collect a value\n// for each of the int64s in the slice.  The data returned will be a\n// []interface{}.\nfunc (v *Value) CollectInt64(collector func(int, int64) interface{}) *Value {\n\n\tarr := v.MustInt64Slice()\n\tcollected := make([]interface{}, len(arr))\n\n\tv.EachInt64(func(index int, val int64) bool {\n\t\tcollected[index] = collector(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: collected}\n}\n\n/*\n\tUint (uint and []uint)\n\t--------------------------------------------------\n*/\n\n// Uint gets the value as a uint, returns the optionalDefault\n// value or a system default object if the value is the wrong type.\nfunc (v *Value) Uint(optionalDefault ...uint) uint {\n\tif s, ok := v.data.(uint); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn 0\n}\n\n// MustUint gets the value as a uint.\n//\n// Panics if the object is not a uint.\nfunc (v *Value) MustUint() uint {\n\treturn v.data.(uint)\n}\n\n// UintSlice gets the value as a []uint, returns the optionalDefault\n// value or nil if the value is not a []uint.\nfunc (v *Value) UintSlice(optionalDefault ...[]uint) []uint {\n\tif s, ok := v.data.([]uint); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn nil\n}\n\n// MustUintSlice gets the value as a []uint.\n//\n// Panics if the object is not a []uint.\nfunc (v *Value) MustUintSlice() []uint {\n\treturn v.data.([]uint)\n}\n\n// IsUint gets whether the object contained is a uint or not.\nfunc (v *Value) IsUint() bool {\n\t_, ok := v.data.(uint)\n\treturn ok\n}\n\n// IsUintSlice gets whether the object contained is a []uint or not.\nfunc (v *Value) IsUintSlice() bool {\n\t_, ok := v.data.([]uint)\n\treturn ok\n}\n\n// EachUint calls the specified callback for each object\n// in the []uint.\n//\n// Panics if the object is the wrong type.\nfunc (v *Value) EachUint(callback func(int, uint) bool) *Value {\n\n\tfor index, val := range v.MustUintSlice() {\n\t\tcarryon := callback(index, val)\n\t\tif carryon == false {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn v\n\n}\n\n// WhereUint uses the specified decider function to select items\n// from the []uint.  The object contained in the result will contain\n// only the selected items.\nfunc (v *Value) WhereUint(decider func(int, uint) bool) *Value {\n\n\tvar selected []uint\n\n\tv.EachUint(func(index int, val uint) bool {\n\t\tshouldSelect := decider(index, val)\n\t\tif shouldSelect == false {\n\t\t\tselected = append(selected, val)\n\t\t}\n\t\treturn true\n\t})\n\n\treturn &Value{data: selected}\n\n}\n\n// GroupUint uses the specified grouper function to group the items\n// keyed by the return of the grouper.  The object contained in the\n// result will contain a map[string][]uint.\nfunc (v *Value) GroupUint(grouper func(int, uint) string) *Value {\n\n\tgroups := make(map[string][]uint)\n\n\tv.EachUint(func(index int, val uint) bool {\n\t\tgroup := grouper(index, val)\n\t\tif _, ok := groups[group]; !ok {\n\t\t\tgroups[group] = make([]uint, 0)\n\t\t}\n\t\tgroups[group] = append(groups[group], val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: groups}\n\n}\n\n// ReplaceUint uses the specified function to replace each uints\n// by iterating each item.  The data in the returned result will be a\n// []uint containing the replaced items.\nfunc (v *Value) ReplaceUint(replacer func(int, uint) uint) *Value {\n\n\tarr := v.MustUintSlice()\n\treplaced := make([]uint, len(arr))\n\n\tv.EachUint(func(index int, val uint) bool {\n\t\treplaced[index] = replacer(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: replaced}\n\n}\n\n// CollectUint uses the specified collector function to collect a value\n// for each of the uints in the slice.  The data returned will be a\n// []interface{}.\nfunc (v *Value) CollectUint(collector func(int, uint) interface{}) *Value {\n\n\tarr := v.MustUintSlice()\n\tcollected := make([]interface{}, len(arr))\n\n\tv.EachUint(func(index int, val uint) bool {\n\t\tcollected[index] = collector(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: collected}\n}\n\n/*\n\tUint8 (uint8 and []uint8)\n\t--------------------------------------------------\n*/\n\n// Uint8 gets the value as a uint8, returns the optionalDefault\n// value or a system default object if the value is the wrong type.\nfunc (v *Value) Uint8(optionalDefault ...uint8) uint8 {\n\tif s, ok := v.data.(uint8); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn 0\n}\n\n// MustUint8 gets the value as a uint8.\n//\n// Panics if the object is not a uint8.\nfunc (v *Value) MustUint8() uint8 {\n\treturn v.data.(uint8)\n}\n\n// Uint8Slice gets the value as a []uint8, returns the optionalDefault\n// value or nil if the value is not a []uint8.\nfunc (v *Value) Uint8Slice(optionalDefault ...[]uint8) []uint8 {\n\tif s, ok := v.data.([]uint8); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn nil\n}\n\n// MustUint8Slice gets the value as a []uint8.\n//\n// Panics if the object is not a []uint8.\nfunc (v *Value) MustUint8Slice() []uint8 {\n\treturn v.data.([]uint8)\n}\n\n// IsUint8 gets whether the object contained is a uint8 or not.\nfunc (v *Value) IsUint8() bool {\n\t_, ok := v.data.(uint8)\n\treturn ok\n}\n\n// IsUint8Slice gets whether the object contained is a []uint8 or not.\nfunc (v *Value) IsUint8Slice() bool {\n\t_, ok := v.data.([]uint8)\n\treturn ok\n}\n\n// EachUint8 calls the specified callback for each object\n// in the []uint8.\n//\n// Panics if the object is the wrong type.\nfunc (v *Value) EachUint8(callback func(int, uint8) bool) *Value {\n\n\tfor index, val := range v.MustUint8Slice() {\n\t\tcarryon := callback(index, val)\n\t\tif carryon == false {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn v\n\n}\n\n// WhereUint8 uses the specified decider function to select items\n// from the []uint8.  The object contained in the result will contain\n// only the selected items.\nfunc (v *Value) WhereUint8(decider func(int, uint8) bool) *Value {\n\n\tvar selected []uint8\n\n\tv.EachUint8(func(index int, val uint8) bool {\n\t\tshouldSelect := decider(index, val)\n\t\tif shouldSelect == false {\n\t\t\tselected = append(selected, val)\n\t\t}\n\t\treturn true\n\t})\n\n\treturn &Value{data: selected}\n\n}\n\n// GroupUint8 uses the specified grouper function to group the items\n// keyed by the return of the grouper.  The object contained in the\n// result will contain a map[string][]uint8.\nfunc (v *Value) GroupUint8(grouper func(int, uint8) string) *Value {\n\n\tgroups := make(map[string][]uint8)\n\n\tv.EachUint8(func(index int, val uint8) bool {\n\t\tgroup := grouper(index, val)\n\t\tif _, ok := groups[group]; !ok {\n\t\t\tgroups[group] = make([]uint8, 0)\n\t\t}\n\t\tgroups[group] = append(groups[group], val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: groups}\n\n}\n\n// ReplaceUint8 uses the specified function to replace each uint8s\n// by iterating each item.  The data in the returned result will be a\n// []uint8 containing the replaced items.\nfunc (v *Value) ReplaceUint8(replacer func(int, uint8) uint8) *Value {\n\n\tarr := v.MustUint8Slice()\n\treplaced := make([]uint8, len(arr))\n\n\tv.EachUint8(func(index int, val uint8) bool {\n\t\treplaced[index] = replacer(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: replaced}\n\n}\n\n// CollectUint8 uses the specified collector function to collect a value\n// for each of the uint8s in the slice.  The data returned will be a\n// []interface{}.\nfunc (v *Value) CollectUint8(collector func(int, uint8) interface{}) *Value {\n\n\tarr := v.MustUint8Slice()\n\tcollected := make([]interface{}, len(arr))\n\n\tv.EachUint8(func(index int, val uint8) bool {\n\t\tcollected[index] = collector(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: collected}\n}\n\n/*\n\tUint16 (uint16 and []uint16)\n\t--------------------------------------------------\n*/\n\n// Uint16 gets the value as a uint16, returns the optionalDefault\n// value or a system default object if the value is the wrong type.\nfunc (v *Value) Uint16(optionalDefault ...uint16) uint16 {\n\tif s, ok := v.data.(uint16); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn 0\n}\n\n// MustUint16 gets the value as a uint16.\n//\n// Panics if the object is not a uint16.\nfunc (v *Value) MustUint16() uint16 {\n\treturn v.data.(uint16)\n}\n\n// Uint16Slice gets the value as a []uint16, returns the optionalDefault\n// value or nil if the value is not a []uint16.\nfunc (v *Value) Uint16Slice(optionalDefault ...[]uint16) []uint16 {\n\tif s, ok := v.data.([]uint16); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn nil\n}\n\n// MustUint16Slice gets the value as a []uint16.\n//\n// Panics if the object is not a []uint16.\nfunc (v *Value) MustUint16Slice() []uint16 {\n\treturn v.data.([]uint16)\n}\n\n// IsUint16 gets whether the object contained is a uint16 or not.\nfunc (v *Value) IsUint16() bool {\n\t_, ok := v.data.(uint16)\n\treturn ok\n}\n\n// IsUint16Slice gets whether the object contained is a []uint16 or not.\nfunc (v *Value) IsUint16Slice() bool {\n\t_, ok := v.data.([]uint16)\n\treturn ok\n}\n\n// EachUint16 calls the specified callback for each object\n// in the []uint16.\n//\n// Panics if the object is the wrong type.\nfunc (v *Value) EachUint16(callback func(int, uint16) bool) *Value {\n\n\tfor index, val := range v.MustUint16Slice() {\n\t\tcarryon := callback(index, val)\n\t\tif carryon == false {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn v\n\n}\n\n// WhereUint16 uses the specified decider function to select items\n// from the []uint16.  The object contained in the result will contain\n// only the selected items.\nfunc (v *Value) WhereUint16(decider func(int, uint16) bool) *Value {\n\n\tvar selected []uint16\n\n\tv.EachUint16(func(index int, val uint16) bool {\n\t\tshouldSelect := decider(index, val)\n\t\tif shouldSelect == false {\n\t\t\tselected = append(selected, val)\n\t\t}\n\t\treturn true\n\t})\n\n\treturn &Value{data: selected}\n\n}\n\n// GroupUint16 uses the specified grouper function to group the items\n// keyed by the return of the grouper.  The object contained in the\n// result will contain a map[string][]uint16.\nfunc (v *Value) GroupUint16(grouper func(int, uint16) string) *Value {\n\n\tgroups := make(map[string][]uint16)\n\n\tv.EachUint16(func(index int, val uint16) bool {\n\t\tgroup := grouper(index, val)\n\t\tif _, ok := groups[group]; !ok {\n\t\t\tgroups[group] = make([]uint16, 0)\n\t\t}\n\t\tgroups[group] = append(groups[group], val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: groups}\n\n}\n\n// ReplaceUint16 uses the specified function to replace each uint16s\n// by iterating each item.  The data in the returned result will be a\n// []uint16 containing the replaced items.\nfunc (v *Value) ReplaceUint16(replacer func(int, uint16) uint16) *Value {\n\n\tarr := v.MustUint16Slice()\n\treplaced := make([]uint16, len(arr))\n\n\tv.EachUint16(func(index int, val uint16) bool {\n\t\treplaced[index] = replacer(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: replaced}\n\n}\n\n// CollectUint16 uses the specified collector function to collect a value\n// for each of the uint16s in the slice.  The data returned will be a\n// []interface{}.\nfunc (v *Value) CollectUint16(collector func(int, uint16) interface{}) *Value {\n\n\tarr := v.MustUint16Slice()\n\tcollected := make([]interface{}, len(arr))\n\n\tv.EachUint16(func(index int, val uint16) bool {\n\t\tcollected[index] = collector(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: collected}\n}\n\n/*\n\tUint32 (uint32 and []uint32)\n\t--------------------------------------------------\n*/\n\n// Uint32 gets the value as a uint32, returns the optionalDefault\n// value or a system default object if the value is the wrong type.\nfunc (v *Value) Uint32(optionalDefault ...uint32) uint32 {\n\tif s, ok := v.data.(uint32); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn 0\n}\n\n// MustUint32 gets the value as a uint32.\n//\n// Panics if the object is not a uint32.\nfunc (v *Value) MustUint32() uint32 {\n\treturn v.data.(uint32)\n}\n\n// Uint32Slice gets the value as a []uint32, returns the optionalDefault\n// value or nil if the value is not a []uint32.\nfunc (v *Value) Uint32Slice(optionalDefault ...[]uint32) []uint32 {\n\tif s, ok := v.data.([]uint32); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn nil\n}\n\n// MustUint32Slice gets the value as a []uint32.\n//\n// Panics if the object is not a []uint32.\nfunc (v *Value) MustUint32Slice() []uint32 {\n\treturn v.data.([]uint32)\n}\n\n// IsUint32 gets whether the object contained is a uint32 or not.\nfunc (v *Value) IsUint32() bool {\n\t_, ok := v.data.(uint32)\n\treturn ok\n}\n\n// IsUint32Slice gets whether the object contained is a []uint32 or not.\nfunc (v *Value) IsUint32Slice() bool {\n\t_, ok := v.data.([]uint32)\n\treturn ok\n}\n\n// EachUint32 calls the specified callback for each object\n// in the []uint32.\n//\n// Panics if the object is the wrong type.\nfunc (v *Value) EachUint32(callback func(int, uint32) bool) *Value {\n\n\tfor index, val := range v.MustUint32Slice() {\n\t\tcarryon := callback(index, val)\n\t\tif carryon == false {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn v\n\n}\n\n// WhereUint32 uses the specified decider function to select items\n// from the []uint32.  The object contained in the result will contain\n// only the selected items.\nfunc (v *Value) WhereUint32(decider func(int, uint32) bool) *Value {\n\n\tvar selected []uint32\n\n\tv.EachUint32(func(index int, val uint32) bool {\n\t\tshouldSelect := decider(index, val)\n\t\tif shouldSelect == false {\n\t\t\tselected = append(selected, val)\n\t\t}\n\t\treturn true\n\t})\n\n\treturn &Value{data: selected}\n\n}\n\n// GroupUint32 uses the specified grouper function to group the items\n// keyed by the return of the grouper.  The object contained in the\n// result will contain a map[string][]uint32.\nfunc (v *Value) GroupUint32(grouper func(int, uint32) string) *Value {\n\n\tgroups := make(map[string][]uint32)\n\n\tv.EachUint32(func(index int, val uint32) bool {\n\t\tgroup := grouper(index, val)\n\t\tif _, ok := groups[group]; !ok {\n\t\t\tgroups[group] = make([]uint32, 0)\n\t\t}\n\t\tgroups[group] = append(groups[group], val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: groups}\n\n}\n\n// ReplaceUint32 uses the specified function to replace each uint32s\n// by iterating each item.  The data in the returned result will be a\n// []uint32 containing the replaced items.\nfunc (v *Value) ReplaceUint32(replacer func(int, uint32) uint32) *Value {\n\n\tarr := v.MustUint32Slice()\n\treplaced := make([]uint32, len(arr))\n\n\tv.EachUint32(func(index int, val uint32) bool {\n\t\treplaced[index] = replacer(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: replaced}\n\n}\n\n// CollectUint32 uses the specified collector function to collect a value\n// for each of the uint32s in the slice.  The data returned will be a\n// []interface{}.\nfunc (v *Value) CollectUint32(collector func(int, uint32) interface{}) *Value {\n\n\tarr := v.MustUint32Slice()\n\tcollected := make([]interface{}, len(arr))\n\n\tv.EachUint32(func(index int, val uint32) bool {\n\t\tcollected[index] = collector(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: collected}\n}\n\n/*\n\tUint64 (uint64 and []uint64)\n\t--------------------------------------------------\n*/\n\n// Uint64 gets the value as a uint64, returns the optionalDefault\n// value or a system default object if the value is the wrong type.\nfunc (v *Value) Uint64(optionalDefault ...uint64) uint64 {\n\tif s, ok := v.data.(uint64); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn 0\n}\n\n// MustUint64 gets the value as a uint64.\n//\n// Panics if the object is not a uint64.\nfunc (v *Value) MustUint64() uint64 {\n\treturn v.data.(uint64)\n}\n\n// Uint64Slice gets the value as a []uint64, returns the optionalDefault\n// value or nil if the value is not a []uint64.\nfunc (v *Value) Uint64Slice(optionalDefault ...[]uint64) []uint64 {\n\tif s, ok := v.data.([]uint64); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn nil\n}\n\n// MustUint64Slice gets the value as a []uint64.\n//\n// Panics if the object is not a []uint64.\nfunc (v *Value) MustUint64Slice() []uint64 {\n\treturn v.data.([]uint64)\n}\n\n// IsUint64 gets whether the object contained is a uint64 or not.\nfunc (v *Value) IsUint64() bool {\n\t_, ok := v.data.(uint64)\n\treturn ok\n}\n\n// IsUint64Slice gets whether the object contained is a []uint64 or not.\nfunc (v *Value) IsUint64Slice() bool {\n\t_, ok := v.data.([]uint64)\n\treturn ok\n}\n\n// EachUint64 calls the specified callback for each object\n// in the []uint64.\n//\n// Panics if the object is the wrong type.\nfunc (v *Value) EachUint64(callback func(int, uint64) bool) *Value {\n\n\tfor index, val := range v.MustUint64Slice() {\n\t\tcarryon := callback(index, val)\n\t\tif carryon == false {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn v\n\n}\n\n// WhereUint64 uses the specified decider function to select items\n// from the []uint64.  The object contained in the result will contain\n// only the selected items.\nfunc (v *Value) WhereUint64(decider func(int, uint64) bool) *Value {\n\n\tvar selected []uint64\n\n\tv.EachUint64(func(index int, val uint64) bool {\n\t\tshouldSelect := decider(index, val)\n\t\tif shouldSelect == false {\n\t\t\tselected = append(selected, val)\n\t\t}\n\t\treturn true\n\t})\n\n\treturn &Value{data: selected}\n\n}\n\n// GroupUint64 uses the specified grouper function to group the items\n// keyed by the return of the grouper.  The object contained in the\n// result will contain a map[string][]uint64.\nfunc (v *Value) GroupUint64(grouper func(int, uint64) string) *Value {\n\n\tgroups := make(map[string][]uint64)\n\n\tv.EachUint64(func(index int, val uint64) bool {\n\t\tgroup := grouper(index, val)\n\t\tif _, ok := groups[group]; !ok {\n\t\t\tgroups[group] = make([]uint64, 0)\n\t\t}\n\t\tgroups[group] = append(groups[group], val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: groups}\n\n}\n\n// ReplaceUint64 uses the specified function to replace each uint64s\n// by iterating each item.  The data in the returned result will be a\n// []uint64 containing the replaced items.\nfunc (v *Value) ReplaceUint64(replacer func(int, uint64) uint64) *Value {\n\n\tarr := v.MustUint64Slice()\n\treplaced := make([]uint64, len(arr))\n\n\tv.EachUint64(func(index int, val uint64) bool {\n\t\treplaced[index] = replacer(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: replaced}\n\n}\n\n// CollectUint64 uses the specified collector function to collect a value\n// for each of the uint64s in the slice.  The data returned will be a\n// []interface{}.\nfunc (v *Value) CollectUint64(collector func(int, uint64) interface{}) *Value {\n\n\tarr := v.MustUint64Slice()\n\tcollected := make([]interface{}, len(arr))\n\n\tv.EachUint64(func(index int, val uint64) bool {\n\t\tcollected[index] = collector(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: collected}\n}\n\n/*\n\tUintptr (uintptr and []uintptr)\n\t--------------------------------------------------\n*/\n\n// Uintptr gets the value as a uintptr, returns the optionalDefault\n// value or a system default object if the value is the wrong type.\nfunc (v *Value) Uintptr(optionalDefault ...uintptr) uintptr {\n\tif s, ok := v.data.(uintptr); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn 0\n}\n\n// MustUintptr gets the value as a uintptr.\n//\n// Panics if the object is not a uintptr.\nfunc (v *Value) MustUintptr() uintptr {\n\treturn v.data.(uintptr)\n}\n\n// UintptrSlice gets the value as a []uintptr, returns the optionalDefault\n// value or nil if the value is not a []uintptr.\nfunc (v *Value) UintptrSlice(optionalDefault ...[]uintptr) []uintptr {\n\tif s, ok := v.data.([]uintptr); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn nil\n}\n\n// MustUintptrSlice gets the value as a []uintptr.\n//\n// Panics if the object is not a []uintptr.\nfunc (v *Value) MustUintptrSlice() []uintptr {\n\treturn v.data.([]uintptr)\n}\n\n// IsUintptr gets whether the object contained is a uintptr or not.\nfunc (v *Value) IsUintptr() bool {\n\t_, ok := v.data.(uintptr)\n\treturn ok\n}\n\n// IsUintptrSlice gets whether the object contained is a []uintptr or not.\nfunc (v *Value) IsUintptrSlice() bool {\n\t_, ok := v.data.([]uintptr)\n\treturn ok\n}\n\n// EachUintptr calls the specified callback for each object\n// in the []uintptr.\n//\n// Panics if the object is the wrong type.\nfunc (v *Value) EachUintptr(callback func(int, uintptr) bool) *Value {\n\n\tfor index, val := range v.MustUintptrSlice() {\n\t\tcarryon := callback(index, val)\n\t\tif carryon == false {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn v\n\n}\n\n// WhereUintptr uses the specified decider function to select items\n// from the []uintptr.  The object contained in the result will contain\n// only the selected items.\nfunc (v *Value) WhereUintptr(decider func(int, uintptr) bool) *Value {\n\n\tvar selected []uintptr\n\n\tv.EachUintptr(func(index int, val uintptr) bool {\n\t\tshouldSelect := decider(index, val)\n\t\tif shouldSelect == false {\n\t\t\tselected = append(selected, val)\n\t\t}\n\t\treturn true\n\t})\n\n\treturn &Value{data: selected}\n\n}\n\n// GroupUintptr uses the specified grouper function to group the items\n// keyed by the return of the grouper.  The object contained in the\n// result will contain a map[string][]uintptr.\nfunc (v *Value) GroupUintptr(grouper func(int, uintptr) string) *Value {\n\n\tgroups := make(map[string][]uintptr)\n\n\tv.EachUintptr(func(index int, val uintptr) bool {\n\t\tgroup := grouper(index, val)\n\t\tif _, ok := groups[group]; !ok {\n\t\t\tgroups[group] = make([]uintptr, 0)\n\t\t}\n\t\tgroups[group] = append(groups[group], val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: groups}\n\n}\n\n// ReplaceUintptr uses the specified function to replace each uintptrs\n// by iterating each item.  The data in the returned result will be a\n// []uintptr containing the replaced items.\nfunc (v *Value) ReplaceUintptr(replacer func(int, uintptr) uintptr) *Value {\n\n\tarr := v.MustUintptrSlice()\n\treplaced := make([]uintptr, len(arr))\n\n\tv.EachUintptr(func(index int, val uintptr) bool {\n\t\treplaced[index] = replacer(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: replaced}\n\n}\n\n// CollectUintptr uses the specified collector function to collect a value\n// for each of the uintptrs in the slice.  The data returned will be a\n// []interface{}.\nfunc (v *Value) CollectUintptr(collector func(int, uintptr) interface{}) *Value {\n\n\tarr := v.MustUintptrSlice()\n\tcollected := make([]interface{}, len(arr))\n\n\tv.EachUintptr(func(index int, val uintptr) bool {\n\t\tcollected[index] = collector(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: collected}\n}\n\n/*\n\tFloat32 (float32 and []float32)\n\t--------------------------------------------------\n*/\n\n// Float32 gets the value as a float32, returns the optionalDefault\n// value or a system default object if the value is the wrong type.\nfunc (v *Value) Float32(optionalDefault ...float32) float32 {\n\tif s, ok := v.data.(float32); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn 0\n}\n\n// MustFloat32 gets the value as a float32.\n//\n// Panics if the object is not a float32.\nfunc (v *Value) MustFloat32() float32 {\n\treturn v.data.(float32)\n}\n\n// Float32Slice gets the value as a []float32, returns the optionalDefault\n// value or nil if the value is not a []float32.\nfunc (v *Value) Float32Slice(optionalDefault ...[]float32) []float32 {\n\tif s, ok := v.data.([]float32); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn nil\n}\n\n// MustFloat32Slice gets the value as a []float32.\n//\n// Panics if the object is not a []float32.\nfunc (v *Value) MustFloat32Slice() []float32 {\n\treturn v.data.([]float32)\n}\n\n// IsFloat32 gets whether the object contained is a float32 or not.\nfunc (v *Value) IsFloat32() bool {\n\t_, ok := v.data.(float32)\n\treturn ok\n}\n\n// IsFloat32Slice gets whether the object contained is a []float32 or not.\nfunc (v *Value) IsFloat32Slice() bool {\n\t_, ok := v.data.([]float32)\n\treturn ok\n}\n\n// EachFloat32 calls the specified callback for each object\n// in the []float32.\n//\n// Panics if the object is the wrong type.\nfunc (v *Value) EachFloat32(callback func(int, float32) bool) *Value {\n\n\tfor index, val := range v.MustFloat32Slice() {\n\t\tcarryon := callback(index, val)\n\t\tif carryon == false {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn v\n\n}\n\n// WhereFloat32 uses the specified decider function to select items\n// from the []float32.  The object contained in the result will contain\n// only the selected items.\nfunc (v *Value) WhereFloat32(decider func(int, float32) bool) *Value {\n\n\tvar selected []float32\n\n\tv.EachFloat32(func(index int, val float32) bool {\n\t\tshouldSelect := decider(index, val)\n\t\tif shouldSelect == false {\n\t\t\tselected = append(selected, val)\n\t\t}\n\t\treturn true\n\t})\n\n\treturn &Value{data: selected}\n\n}\n\n// GroupFloat32 uses the specified grouper function to group the items\n// keyed by the return of the grouper.  The object contained in the\n// result will contain a map[string][]float32.\nfunc (v *Value) GroupFloat32(grouper func(int, float32) string) *Value {\n\n\tgroups := make(map[string][]float32)\n\n\tv.EachFloat32(func(index int, val float32) bool {\n\t\tgroup := grouper(index, val)\n\t\tif _, ok := groups[group]; !ok {\n\t\t\tgroups[group] = make([]float32, 0)\n\t\t}\n\t\tgroups[group] = append(groups[group], val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: groups}\n\n}\n\n// ReplaceFloat32 uses the specified function to replace each float32s\n// by iterating each item.  The data in the returned result will be a\n// []float32 containing the replaced items.\nfunc (v *Value) ReplaceFloat32(replacer func(int, float32) float32) *Value {\n\n\tarr := v.MustFloat32Slice()\n\treplaced := make([]float32, len(arr))\n\n\tv.EachFloat32(func(index int, val float32) bool {\n\t\treplaced[index] = replacer(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: replaced}\n\n}\n\n// CollectFloat32 uses the specified collector function to collect a value\n// for each of the float32s in the slice.  The data returned will be a\n// []interface{}.\nfunc (v *Value) CollectFloat32(collector func(int, float32) interface{}) *Value {\n\n\tarr := v.MustFloat32Slice()\n\tcollected := make([]interface{}, len(arr))\n\n\tv.EachFloat32(func(index int, val float32) bool {\n\t\tcollected[index] = collector(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: collected}\n}\n\n/*\n\tFloat64 (float64 and []float64)\n\t--------------------------------------------------\n*/\n\n// Float64 gets the value as a float64, returns the optionalDefault\n// value or a system default object if the value is the wrong type.\nfunc (v *Value) Float64(optionalDefault ...float64) float64 {\n\tif s, ok := v.data.(float64); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn 0\n}\n\n// MustFloat64 gets the value as a float64.\n//\n// Panics if the object is not a float64.\nfunc (v *Value) MustFloat64() float64 {\n\treturn v.data.(float64)\n}\n\n// Float64Slice gets the value as a []float64, returns the optionalDefault\n// value or nil if the value is not a []float64.\nfunc (v *Value) Float64Slice(optionalDefault ...[]float64) []float64 {\n\tif s, ok := v.data.([]float64); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn nil\n}\n\n// MustFloat64Slice gets the value as a []float64.\n//\n// Panics if the object is not a []float64.\nfunc (v *Value) MustFloat64Slice() []float64 {\n\treturn v.data.([]float64)\n}\n\n// IsFloat64 gets whether the object contained is a float64 or not.\nfunc (v *Value) IsFloat64() bool {\n\t_, ok := v.data.(float64)\n\treturn ok\n}\n\n// IsFloat64Slice gets whether the object contained is a []float64 or not.\nfunc (v *Value) IsFloat64Slice() bool {\n\t_, ok := v.data.([]float64)\n\treturn ok\n}\n\n// EachFloat64 calls the specified callback for each object\n// in the []float64.\n//\n// Panics if the object is the wrong type.\nfunc (v *Value) EachFloat64(callback func(int, float64) bool) *Value {\n\n\tfor index, val := range v.MustFloat64Slice() {\n\t\tcarryon := callback(index, val)\n\t\tif carryon == false {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn v\n\n}\n\n// WhereFloat64 uses the specified decider function to select items\n// from the []float64.  The object contained in the result will contain\n// only the selected items.\nfunc (v *Value) WhereFloat64(decider func(int, float64) bool) *Value {\n\n\tvar selected []float64\n\n\tv.EachFloat64(func(index int, val float64) bool {\n\t\tshouldSelect := decider(index, val)\n\t\tif shouldSelect == false {\n\t\t\tselected = append(selected, val)\n\t\t}\n\t\treturn true\n\t})\n\n\treturn &Value{data: selected}\n\n}\n\n// GroupFloat64 uses the specified grouper function to group the items\n// keyed by the return of the grouper.  The object contained in the\n// result will contain a map[string][]float64.\nfunc (v *Value) GroupFloat64(grouper func(int, float64) string) *Value {\n\n\tgroups := make(map[string][]float64)\n\n\tv.EachFloat64(func(index int, val float64) bool {\n\t\tgroup := grouper(index, val)\n\t\tif _, ok := groups[group]; !ok {\n\t\t\tgroups[group] = make([]float64, 0)\n\t\t}\n\t\tgroups[group] = append(groups[group], val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: groups}\n\n}\n\n// ReplaceFloat64 uses the specified function to replace each float64s\n// by iterating each item.  The data in the returned result will be a\n// []float64 containing the replaced items.\nfunc (v *Value) ReplaceFloat64(replacer func(int, float64) float64) *Value {\n\n\tarr := v.MustFloat64Slice()\n\treplaced := make([]float64, len(arr))\n\n\tv.EachFloat64(func(index int, val float64) bool {\n\t\treplaced[index] = replacer(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: replaced}\n\n}\n\n// CollectFloat64 uses the specified collector function to collect a value\n// for each of the float64s in the slice.  The data returned will be a\n// []interface{}.\nfunc (v *Value) CollectFloat64(collector func(int, float64) interface{}) *Value {\n\n\tarr := v.MustFloat64Slice()\n\tcollected := make([]interface{}, len(arr))\n\n\tv.EachFloat64(func(index int, val float64) bool {\n\t\tcollected[index] = collector(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: collected}\n}\n\n/*\n\tComplex64 (complex64 and []complex64)\n\t--------------------------------------------------\n*/\n\n// Complex64 gets the value as a complex64, returns the optionalDefault\n// value or a system default object if the value is the wrong type.\nfunc (v *Value) Complex64(optionalDefault ...complex64) complex64 {\n\tif s, ok := v.data.(complex64); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn 0\n}\n\n// MustComplex64 gets the value as a complex64.\n//\n// Panics if the object is not a complex64.\nfunc (v *Value) MustComplex64() complex64 {\n\treturn v.data.(complex64)\n}\n\n// Complex64Slice gets the value as a []complex64, returns the optionalDefault\n// value or nil if the value is not a []complex64.\nfunc (v *Value) Complex64Slice(optionalDefault ...[]complex64) []complex64 {\n\tif s, ok := v.data.([]complex64); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn nil\n}\n\n// MustComplex64Slice gets the value as a []complex64.\n//\n// Panics if the object is not a []complex64.\nfunc (v *Value) MustComplex64Slice() []complex64 {\n\treturn v.data.([]complex64)\n}\n\n// IsComplex64 gets whether the object contained is a complex64 or not.\nfunc (v *Value) IsComplex64() bool {\n\t_, ok := v.data.(complex64)\n\treturn ok\n}\n\n// IsComplex64Slice gets whether the object contained is a []complex64 or not.\nfunc (v *Value) IsComplex64Slice() bool {\n\t_, ok := v.data.([]complex64)\n\treturn ok\n}\n\n// EachComplex64 calls the specified callback for each object\n// in the []complex64.\n//\n// Panics if the object is the wrong type.\nfunc (v *Value) EachComplex64(callback func(int, complex64) bool) *Value {\n\n\tfor index, val := range v.MustComplex64Slice() {\n\t\tcarryon := callback(index, val)\n\t\tif carryon == false {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn v\n\n}\n\n// WhereComplex64 uses the specified decider function to select items\n// from the []complex64.  The object contained in the result will contain\n// only the selected items.\nfunc (v *Value) WhereComplex64(decider func(int, complex64) bool) *Value {\n\n\tvar selected []complex64\n\n\tv.EachComplex64(func(index int, val complex64) bool {\n\t\tshouldSelect := decider(index, val)\n\t\tif shouldSelect == false {\n\t\t\tselected = append(selected, val)\n\t\t}\n\t\treturn true\n\t})\n\n\treturn &Value{data: selected}\n\n}\n\n// GroupComplex64 uses the specified grouper function to group the items\n// keyed by the return of the grouper.  The object contained in the\n// result will contain a map[string][]complex64.\nfunc (v *Value) GroupComplex64(grouper func(int, complex64) string) *Value {\n\n\tgroups := make(map[string][]complex64)\n\n\tv.EachComplex64(func(index int, val complex64) bool {\n\t\tgroup := grouper(index, val)\n\t\tif _, ok := groups[group]; !ok {\n\t\t\tgroups[group] = make([]complex64, 0)\n\t\t}\n\t\tgroups[group] = append(groups[group], val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: groups}\n\n}\n\n// ReplaceComplex64 uses the specified function to replace each complex64s\n// by iterating each item.  The data in the returned result will be a\n// []complex64 containing the replaced items.\nfunc (v *Value) ReplaceComplex64(replacer func(int, complex64) complex64) *Value {\n\n\tarr := v.MustComplex64Slice()\n\treplaced := make([]complex64, len(arr))\n\n\tv.EachComplex64(func(index int, val complex64) bool {\n\t\treplaced[index] = replacer(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: replaced}\n\n}\n\n// CollectComplex64 uses the specified collector function to collect a value\n// for each of the complex64s in the slice.  The data returned will be a\n// []interface{}.\nfunc (v *Value) CollectComplex64(collector func(int, complex64) interface{}) *Value {\n\n\tarr := v.MustComplex64Slice()\n\tcollected := make([]interface{}, len(arr))\n\n\tv.EachComplex64(func(index int, val complex64) bool {\n\t\tcollected[index] = collector(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: collected}\n}\n\n/*\n\tComplex128 (complex128 and []complex128)\n\t--------------------------------------------------\n*/\n\n// Complex128 gets the value as a complex128, returns the optionalDefault\n// value or a system default object if the value is the wrong type.\nfunc (v *Value) Complex128(optionalDefault ...complex128) complex128 {\n\tif s, ok := v.data.(complex128); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn 0\n}\n\n// MustComplex128 gets the value as a complex128.\n//\n// Panics if the object is not a complex128.\nfunc (v *Value) MustComplex128() complex128 {\n\treturn v.data.(complex128)\n}\n\n// Complex128Slice gets the value as a []complex128, returns the optionalDefault\n// value or nil if the value is not a []complex128.\nfunc (v *Value) Complex128Slice(optionalDefault ...[]complex128) []complex128 {\n\tif s, ok := v.data.([]complex128); ok {\n\t\treturn s\n\t}\n\tif len(optionalDefault) == 1 {\n\t\treturn optionalDefault[0]\n\t}\n\treturn nil\n}\n\n// MustComplex128Slice gets the value as a []complex128.\n//\n// Panics if the object is not a []complex128.\nfunc (v *Value) MustComplex128Slice() []complex128 {\n\treturn v.data.([]complex128)\n}\n\n// IsComplex128 gets whether the object contained is a complex128 or not.\nfunc (v *Value) IsComplex128() bool {\n\t_, ok := v.data.(complex128)\n\treturn ok\n}\n\n// IsComplex128Slice gets whether the object contained is a []complex128 or not.\nfunc (v *Value) IsComplex128Slice() bool {\n\t_, ok := v.data.([]complex128)\n\treturn ok\n}\n\n// EachComplex128 calls the specified callback for each object\n// in the []complex128.\n//\n// Panics if the object is the wrong type.\nfunc (v *Value) EachComplex128(callback func(int, complex128) bool) *Value {\n\n\tfor index, val := range v.MustComplex128Slice() {\n\t\tcarryon := callback(index, val)\n\t\tif carryon == false {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn v\n\n}\n\n// WhereComplex128 uses the specified decider function to select items\n// from the []complex128.  The object contained in the result will contain\n// only the selected items.\nfunc (v *Value) WhereComplex128(decider func(int, complex128) bool) *Value {\n\n\tvar selected []complex128\n\n\tv.EachComplex128(func(index int, val complex128) bool {\n\t\tshouldSelect := decider(index, val)\n\t\tif shouldSelect == false {\n\t\t\tselected = append(selected, val)\n\t\t}\n\t\treturn true\n\t})\n\n\treturn &Value{data: selected}\n\n}\n\n// GroupComplex128 uses the specified grouper function to group the items\n// keyed by the return of the grouper.  The object contained in the\n// result will contain a map[string][]complex128.\nfunc (v *Value) GroupComplex128(grouper func(int, complex128) string) *Value {\n\n\tgroups := make(map[string][]complex128)\n\n\tv.EachComplex128(func(index int, val complex128) bool {\n\t\tgroup := grouper(index, val)\n\t\tif _, ok := groups[group]; !ok {\n\t\t\tgroups[group] = make([]complex128, 0)\n\t\t}\n\t\tgroups[group] = append(groups[group], val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: groups}\n\n}\n\n// ReplaceComplex128 uses the specified function to replace each complex128s\n// by iterating each item.  The data in the returned result will be a\n// []complex128 containing the replaced items.\nfunc (v *Value) ReplaceComplex128(replacer func(int, complex128) complex128) *Value {\n\n\tarr := v.MustComplex128Slice()\n\treplaced := make([]complex128, len(arr))\n\n\tv.EachComplex128(func(index int, val complex128) bool {\n\t\treplaced[index] = replacer(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: replaced}\n\n}\n\n// CollectComplex128 uses the specified collector function to collect a value\n// for each of the complex128s in the slice.  The data returned will be a\n// []interface{}.\nfunc (v *Value) CollectComplex128(collector func(int, complex128) interface{}) *Value {\n\n\tarr := v.MustComplex128Slice()\n\tcollected := make([]interface{}, len(arr))\n\n\tv.EachComplex128(func(index int, val complex128) bool {\n\t\tcollected[index] = collector(index, val)\n\t\treturn true\n\t})\n\n\treturn &Value{data: collected}\n}\n"
  },
  {
    "path": "vendor/github.com/stretchr/objx/value.go",
    "content": "package objx\n\n// Value provides methods for extracting interface{} data in various\n// types.\ntype Value struct {\n\t// data contains the raw data being managed by this Value\n\tdata interface{}\n}\n\n// Data returns the raw data contained by this Value\nfunc (v *Value) Data() interface{} {\n\treturn v.data\n}\n"
  },
  {
    "path": "vendor/github.com/stretchr/testify/LICENSE",
    "content": "Copyright (c) 2012 - 2013 Mat Ryer and Tyler Bunnell\n\nPlease consider promoting this project if you find it useful.\n\nPermission is hereby granted, free of charge, to any person \nobtaining a copy of this software and associated documentation \nfiles (the \"Software\"), to deal in the Software without restriction, \nincluding without limitation the rights to use, copy, modify, merge, \npublish, distribute, sublicense, and/or sell copies of the Software, \nand to permit persons to whom the Software is furnished to do so, \nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included\nin all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, \nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES \nOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. \nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, \nDAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT \nOR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE \nOR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "vendor/github.com/stretchr/testify/assert/assertion_format.go",
    "content": "/*\n* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen\n* THIS FILE MUST NOT BE EDITED BY HAND\n */\n\npackage assert\n\nimport (\n\thttp \"net/http\"\n\turl \"net/url\"\n\ttime \"time\"\n)\n\n// Conditionf uses a Comparison to assert a complex condition.\nfunc Conditionf(t TestingT, comp Comparison, msg string, args ...interface{}) bool {\n\treturn Condition(t, comp, append([]interface{}{msg}, args...)...)\n}\n\n// Containsf asserts that the specified string, list(array, slice...) or map contains the\n// specified substring or element.\n//\n//    assert.Containsf(t, \"Hello World\", \"World\", \"error message %s\", \"formatted\")\n//    assert.Containsf(t, [\"Hello\", \"World\"], \"World\", \"error message %s\", \"formatted\")\n//    assert.Containsf(t, {\"Hello\": \"World\"}, \"Hello\", \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Containsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool {\n\treturn Contains(t, s, contains, append([]interface{}{msg}, args...)...)\n}\n\n// Emptyf asserts that the specified object is empty.  I.e. nil, \"\", false, 0 or either\n// a slice or a channel with len == 0.\n//\n//  assert.Emptyf(t, obj, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool {\n\treturn Empty(t, object, append([]interface{}{msg}, args...)...)\n}\n\n// Equalf asserts that two objects are equal.\n//\n//    assert.Equalf(t, 123, 123, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\n//\n// Pointer variable equality is determined based on the equality of the\n// referenced values (as opposed to the memory addresses). Function equality\n// cannot be determined and will always fail.\nfunc Equalf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {\n\treturn Equal(t, expected, actual, append([]interface{}{msg}, args...)...)\n}\n\n// EqualErrorf asserts that a function returned an error (i.e. not `nil`)\n// and that it is equal to the provided error.\n//\n//   actualObj, err := SomeFunction()\n//   assert.EqualErrorf(t, err,  expectedErrorString, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc EqualErrorf(t TestingT, theError error, errString string, msg string, args ...interface{}) bool {\n\treturn EqualError(t, theError, errString, append([]interface{}{msg}, args...)...)\n}\n\n// EqualValuesf asserts that two objects are equal or convertable to the same types\n// and equal.\n//\n//    assert.EqualValuesf(t, uint32(123, \"error message %s\", \"formatted\"), int32(123))\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {\n\treturn EqualValues(t, expected, actual, append([]interface{}{msg}, args...)...)\n}\n\n// Errorf asserts that a function returned an error (i.e. not `nil`).\n//\n//   actualObj, err := SomeFunction()\n//   if assert.Errorf(t, err, \"error message %s\", \"formatted\") {\n// \t   assert.Equal(t, expectedErrorf, err)\n//   }\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Errorf(t TestingT, err error, msg string, args ...interface{}) bool {\n\treturn Error(t, err, append([]interface{}{msg}, args...)...)\n}\n\n// Exactlyf asserts that two objects are equal is value and type.\n//\n//    assert.Exactlyf(t, int32(123, \"error message %s\", \"formatted\"), int64(123))\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {\n\treturn Exactly(t, expected, actual, append([]interface{}{msg}, args...)...)\n}\n\n// Failf reports a failure through\nfunc Failf(t TestingT, failureMessage string, msg string, args ...interface{}) bool {\n\treturn Fail(t, failureMessage, append([]interface{}{msg}, args...)...)\n}\n\n// FailNowf fails test\nfunc FailNowf(t TestingT, failureMessage string, msg string, args ...interface{}) bool {\n\treturn FailNow(t, failureMessage, append([]interface{}{msg}, args...)...)\n}\n\n// Falsef asserts that the specified value is false.\n//\n//    assert.Falsef(t, myBool, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Falsef(t TestingT, value bool, msg string, args ...interface{}) bool {\n\treturn False(t, value, append([]interface{}{msg}, args...)...)\n}\n\n// HTTPBodyContainsf asserts that a specified handler returns a\n// body that contains a string.\n//\n//  assert.HTTPBodyContainsf(t, myHandler, \"www.google.com\", nil, \"I'm Feeling Lucky\", \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) bool {\n\treturn HTTPBodyContains(t, handler, method, url, values, str)\n}\n\n// HTTPBodyNotContainsf asserts that a specified handler returns a\n// body that does not contain a string.\n//\n//  assert.HTTPBodyNotContainsf(t, myHandler, \"www.google.com\", nil, \"I'm Feeling Lucky\", \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) bool {\n\treturn HTTPBodyNotContains(t, handler, method, url, values, str)\n}\n\n// HTTPErrorf asserts that a specified handler returns an error status code.\n//\n//  assert.HTTPErrorf(t, myHandler, \"POST\", \"/a/b/c\", url.Values{\"a\": []string{\"b\", \"c\"}}\n//\n// Returns whether the assertion was successful (true, \"error message %s\", \"formatted\") or not (false).\nfunc HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values) bool {\n\treturn HTTPError(t, handler, method, url, values)\n}\n\n// HTTPRedirectf asserts that a specified handler returns a redirect status code.\n//\n//  assert.HTTPRedirectf(t, myHandler, \"GET\", \"/a/b/c\", url.Values{\"a\": []string{\"b\", \"c\"}}\n//\n// Returns whether the assertion was successful (true, \"error message %s\", \"formatted\") or not (false).\nfunc HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values) bool {\n\treturn HTTPRedirect(t, handler, method, url, values)\n}\n\n// HTTPSuccessf asserts that a specified handler returns a success status code.\n//\n//  assert.HTTPSuccessf(t, myHandler, \"POST\", \"http://www.google.com\", nil, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values) bool {\n\treturn HTTPSuccess(t, handler, method, url, values)\n}\n\n// Implementsf asserts that an object is implemented by the specified interface.\n//\n//    assert.Implementsf(t, (*MyInterface, \"error message %s\", \"formatted\")(nil), new(MyObject))\nfunc Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool {\n\treturn Implements(t, interfaceObject, object, append([]interface{}{msg}, args...)...)\n}\n\n// InDeltaf asserts that the two numerals are within delta of each other.\n//\n// \t assert.InDeltaf(t, math.Pi, (22 / 7.0, \"error message %s\", \"formatted\"), 0.01)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {\n\treturn InDelta(t, expected, actual, delta, append([]interface{}{msg}, args...)...)\n}\n\n// InDeltaSlicef is the same as InDelta, except it compares two slices.\nfunc InDeltaSlicef(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {\n\treturn InDeltaSlice(t, expected, actual, delta, append([]interface{}{msg}, args...)...)\n}\n\n// InEpsilonf asserts that expected and actual have a relative error less than epsilon\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc InEpsilonf(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {\n\treturn InEpsilon(t, expected, actual, epsilon, append([]interface{}{msg}, args...)...)\n}\n\n// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices.\nfunc InEpsilonSlicef(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {\n\treturn InEpsilonSlice(t, expected, actual, epsilon, append([]interface{}{msg}, args...)...)\n}\n\n// IsTypef asserts that the specified objects are of the same type.\nfunc IsTypef(t TestingT, expectedType interface{}, object interface{}, msg string, args ...interface{}) bool {\n\treturn IsType(t, expectedType, object, append([]interface{}{msg}, args...)...)\n}\n\n// JSONEqf asserts that two JSON strings are equivalent.\n//\n//  assert.JSONEqf(t, `{\"hello\": \"world\", \"foo\": \"bar\"}`, `{\"foo\": \"bar\", \"hello\": \"world\"}`, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc JSONEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool {\n\treturn JSONEq(t, expected, actual, append([]interface{}{msg}, args...)...)\n}\n\n// Lenf asserts that the specified object has specific length.\n// Lenf also fails if the object has a type that len() not accept.\n//\n//    assert.Lenf(t, mySlice, 3, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Lenf(t TestingT, object interface{}, length int, msg string, args ...interface{}) bool {\n\treturn Len(t, object, length, append([]interface{}{msg}, args...)...)\n}\n\n// Nilf asserts that the specified object is nil.\n//\n//    assert.Nilf(t, err, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Nilf(t TestingT, object interface{}, msg string, args ...interface{}) bool {\n\treturn Nil(t, object, append([]interface{}{msg}, args...)...)\n}\n\n// NoErrorf asserts that a function returned no error (i.e. `nil`).\n//\n//   actualObj, err := SomeFunction()\n//   if assert.NoErrorf(t, err, \"error message %s\", \"formatted\") {\n// \t   assert.Equal(t, expectedObj, actualObj)\n//   }\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NoErrorf(t TestingT, err error, msg string, args ...interface{}) bool {\n\treturn NoError(t, err, append([]interface{}{msg}, args...)...)\n}\n\n// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the\n// specified substring or element.\n//\n//    assert.NotContainsf(t, \"Hello World\", \"Earth\", \"error message %s\", \"formatted\")\n//    assert.NotContainsf(t, [\"Hello\", \"World\"], \"Earth\", \"error message %s\", \"formatted\")\n//    assert.NotContainsf(t, {\"Hello\": \"World\"}, \"Earth\", \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool {\n\treturn NotContains(t, s, contains, append([]interface{}{msg}, args...)...)\n}\n\n// NotEmptyf asserts that the specified object is NOT empty.  I.e. not nil, \"\", false, 0 or either\n// a slice or a channel with len == 0.\n//\n//  if assert.NotEmptyf(t, obj, \"error message %s\", \"formatted\") {\n//    assert.Equal(t, \"two\", obj[1])\n//  }\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool {\n\treturn NotEmpty(t, object, append([]interface{}{msg}, args...)...)\n}\n\n// NotEqualf asserts that the specified values are NOT equal.\n//\n//    assert.NotEqualf(t, obj1, obj2, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\n//\n// Pointer variable equality is determined based on the equality of the\n// referenced values (as opposed to the memory addresses).\nfunc NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {\n\treturn NotEqual(t, expected, actual, append([]interface{}{msg}, args...)...)\n}\n\n// NotNilf asserts that the specified object is not nil.\n//\n//    assert.NotNilf(t, err, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) bool {\n\treturn NotNil(t, object, append([]interface{}{msg}, args...)...)\n}\n\n// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic.\n//\n//   assert.NotPanicsf(t, func(){ RemainCalm() }, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NotPanicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool {\n\treturn NotPanics(t, f, append([]interface{}{msg}, args...)...)\n}\n\n// NotRegexpf asserts that a specified regexp does not match a string.\n//\n//  assert.NotRegexpf(t, regexp.MustCompile(\"starts\", \"error message %s\", \"formatted\"), \"it's starting\")\n//  assert.NotRegexpf(t, \"^start\", \"it's not starting\", \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool {\n\treturn NotRegexp(t, rx, str, append([]interface{}{msg}, args...)...)\n}\n\n// NotSubsetf asserts that the specified list(array, slice...) contains not all\n// elements given in the specified subset(array, slice...).\n//\n//    assert.NotSubsetf(t, [1, 3, 4], [1, 2], \"But [1, 3, 4] does not contain [1, 2]\", \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NotSubsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool {\n\treturn NotSubset(t, list, subset, append([]interface{}{msg}, args...)...)\n}\n\n// NotZerof asserts that i is not the zero value for its type and returns the truth.\nfunc NotZerof(t TestingT, i interface{}, msg string, args ...interface{}) bool {\n\treturn NotZero(t, i, append([]interface{}{msg}, args...)...)\n}\n\n// Panicsf asserts that the code inside the specified PanicTestFunc panics.\n//\n//   assert.Panicsf(t, func(){ GoCrazy() }, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Panicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool {\n\treturn Panics(t, f, append([]interface{}{msg}, args...)...)\n}\n\n// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that\n// the recovered panic value equals the expected panic value.\n//\n//   assert.PanicsWithValuef(t, \"crazy error\", func(){ GoCrazy() }, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc PanicsWithValuef(t TestingT, expected interface{}, f PanicTestFunc, msg string, args ...interface{}) bool {\n\treturn PanicsWithValue(t, expected, f, append([]interface{}{msg}, args...)...)\n}\n\n// Regexpf asserts that a specified regexp matches a string.\n//\n//  assert.Regexpf(t, regexp.MustCompile(\"start\", \"error message %s\", \"formatted\"), \"it's starting\")\n//  assert.Regexpf(t, \"start...$\", \"it's not starting\", \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool {\n\treturn Regexp(t, rx, str, append([]interface{}{msg}, args...)...)\n}\n\n// Subsetf asserts that the specified list(array, slice...) contains all\n// elements given in the specified subset(array, slice...).\n//\n//    assert.Subsetf(t, [1, 2, 3], [1, 2], \"But [1, 2, 3] does contain [1, 2]\", \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool {\n\treturn Subset(t, list, subset, append([]interface{}{msg}, args...)...)\n}\n\n// Truef asserts that the specified value is true.\n//\n//    assert.Truef(t, myBool, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Truef(t TestingT, value bool, msg string, args ...interface{}) bool {\n\treturn True(t, value, append([]interface{}{msg}, args...)...)\n}\n\n// WithinDurationf asserts that the two times are within duration delta of each other.\n//\n//   assert.WithinDurationf(t, time.Now(), time.Now(), 10*time.Second, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) bool {\n\treturn WithinDuration(t, expected, actual, delta, append([]interface{}{msg}, args...)...)\n}\n\n// Zerof asserts that i is the zero value for its type and returns the truth.\nfunc Zerof(t TestingT, i interface{}, msg string, args ...interface{}) bool {\n\treturn Zero(t, i, append([]interface{}{msg}, args...)...)\n}\n"
  },
  {
    "path": "vendor/github.com/stretchr/testify/assert/assertion_format.go.tmpl",
    "content": "{{.CommentFormat}}\nfunc {{.DocInfo.Name}}f(t TestingT, {{.ParamsFormat}}) bool {\n\treturn {{.DocInfo.Name}}(t, {{.ForwardedParamsFormat}})\n}\n"
  },
  {
    "path": "vendor/github.com/stretchr/testify/assert/assertion_forward.go",
    "content": "/*\n* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen\n* THIS FILE MUST NOT BE EDITED BY HAND\n */\n\npackage assert\n\nimport (\n\thttp \"net/http\"\n\turl \"net/url\"\n\ttime \"time\"\n)\n\n// Condition uses a Comparison to assert a complex condition.\nfunc (a *Assertions) Condition(comp Comparison, msgAndArgs ...interface{}) bool {\n\treturn Condition(a.t, comp, msgAndArgs...)\n}\n\n// Conditionf uses a Comparison to assert a complex condition.\nfunc (a *Assertions) Conditionf(comp Comparison, msg string, args ...interface{}) bool {\n\treturn Conditionf(a.t, comp, msg, args...)\n}\n\n// Contains asserts that the specified string, list(array, slice...) or map contains the\n// specified substring or element.\n//\n//    a.Contains(\"Hello World\", \"World\")\n//    a.Contains([\"Hello\", \"World\"], \"World\")\n//    a.Contains({\"Hello\": \"World\"}, \"Hello\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool {\n\treturn Contains(a.t, s, contains, msgAndArgs...)\n}\n\n// Containsf asserts that the specified string, list(array, slice...) or map contains the\n// specified substring or element.\n//\n//    a.Containsf(\"Hello World\", \"World\", \"error message %s\", \"formatted\")\n//    a.Containsf([\"Hello\", \"World\"], \"World\", \"error message %s\", \"formatted\")\n//    a.Containsf({\"Hello\": \"World\"}, \"Hello\", \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Containsf(s interface{}, contains interface{}, msg string, args ...interface{}) bool {\n\treturn Containsf(a.t, s, contains, msg, args...)\n}\n\n// Empty asserts that the specified object is empty.  I.e. nil, \"\", false, 0 or either\n// a slice or a channel with len == 0.\n//\n//  a.Empty(obj)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) bool {\n\treturn Empty(a.t, object, msgAndArgs...)\n}\n\n// Emptyf asserts that the specified object is empty.  I.e. nil, \"\", false, 0 or either\n// a slice or a channel with len == 0.\n//\n//  a.Emptyf(obj, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{}) bool {\n\treturn Emptyf(a.t, object, msg, args...)\n}\n\n// Equal asserts that two objects are equal.\n//\n//    a.Equal(123, 123)\n//\n// Returns whether the assertion was successful (true) or not (false).\n//\n// Pointer variable equality is determined based on the equality of the\n// referenced values (as opposed to the memory addresses). Function equality\n// cannot be determined and will always fail.\nfunc (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {\n\treturn Equal(a.t, expected, actual, msgAndArgs...)\n}\n\n// EqualError asserts that a function returned an error (i.e. not `nil`)\n// and that it is equal to the provided error.\n//\n//   actualObj, err := SomeFunction()\n//   a.EqualError(err,  expectedErrorString)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) bool {\n\treturn EqualError(a.t, theError, errString, msgAndArgs...)\n}\n\n// EqualErrorf asserts that a function returned an error (i.e. not `nil`)\n// and that it is equal to the provided error.\n//\n//   actualObj, err := SomeFunction()\n//   a.EqualErrorf(err,  expectedErrorString, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) EqualErrorf(theError error, errString string, msg string, args ...interface{}) bool {\n\treturn EqualErrorf(a.t, theError, errString, msg, args...)\n}\n\n// EqualValues asserts that two objects are equal or convertable to the same types\n// and equal.\n//\n//    a.EqualValues(uint32(123), int32(123))\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {\n\treturn EqualValues(a.t, expected, actual, msgAndArgs...)\n}\n\n// EqualValuesf asserts that two objects are equal or convertable to the same types\n// and equal.\n//\n//    a.EqualValuesf(uint32(123, \"error message %s\", \"formatted\"), int32(123))\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {\n\treturn EqualValuesf(a.t, expected, actual, msg, args...)\n}\n\n// Equalf asserts that two objects are equal.\n//\n//    a.Equalf(123, 123, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\n//\n// Pointer variable equality is determined based on the equality of the\n// referenced values (as opposed to the memory addresses). Function equality\n// cannot be determined and will always fail.\nfunc (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {\n\treturn Equalf(a.t, expected, actual, msg, args...)\n}\n\n// Error asserts that a function returned an error (i.e. not `nil`).\n//\n//   actualObj, err := SomeFunction()\n//   if a.Error(err) {\n// \t   assert.Equal(t, expectedError, err)\n//   }\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Error(err error, msgAndArgs ...interface{}) bool {\n\treturn Error(a.t, err, msgAndArgs...)\n}\n\n// Errorf asserts that a function returned an error (i.e. not `nil`).\n//\n//   actualObj, err := SomeFunction()\n//   if a.Errorf(err, \"error message %s\", \"formatted\") {\n// \t   assert.Equal(t, expectedErrorf, err)\n//   }\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Errorf(err error, msg string, args ...interface{}) bool {\n\treturn Errorf(a.t, err, msg, args...)\n}\n\n// Exactly asserts that two objects are equal is value and type.\n//\n//    a.Exactly(int32(123), int64(123))\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {\n\treturn Exactly(a.t, expected, actual, msgAndArgs...)\n}\n\n// Exactlyf asserts that two objects are equal is value and type.\n//\n//    a.Exactlyf(int32(123, \"error message %s\", \"formatted\"), int64(123))\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {\n\treturn Exactlyf(a.t, expected, actual, msg, args...)\n}\n\n// Fail reports a failure through\nfunc (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) bool {\n\treturn Fail(a.t, failureMessage, msgAndArgs...)\n}\n\n// FailNow fails test\nfunc (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) bool {\n\treturn FailNow(a.t, failureMessage, msgAndArgs...)\n}\n\n// FailNowf fails test\nfunc (a *Assertions) FailNowf(failureMessage string, msg string, args ...interface{}) bool {\n\treturn FailNowf(a.t, failureMessage, msg, args...)\n}\n\n// Failf reports a failure through\nfunc (a *Assertions) Failf(failureMessage string, msg string, args ...interface{}) bool {\n\treturn Failf(a.t, failureMessage, msg, args...)\n}\n\n// False asserts that the specified value is false.\n//\n//    a.False(myBool)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) False(value bool, msgAndArgs ...interface{}) bool {\n\treturn False(a.t, value, msgAndArgs...)\n}\n\n// Falsef asserts that the specified value is false.\n//\n//    a.Falsef(myBool, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Falsef(value bool, msg string, args ...interface{}) bool {\n\treturn Falsef(a.t, value, msg, args...)\n}\n\n// HTTPBodyContains asserts that a specified handler returns a\n// body that contains a string.\n//\n//  a.HTTPBodyContains(myHandler, \"www.google.com\", nil, \"I'm Feeling Lucky\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) bool {\n\treturn HTTPBodyContains(a.t, handler, method, url, values, str)\n}\n\n// HTTPBodyContainsf asserts that a specified handler returns a\n// body that contains a string.\n//\n//  a.HTTPBodyContainsf(myHandler, \"www.google.com\", nil, \"I'm Feeling Lucky\", \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) bool {\n\treturn HTTPBodyContainsf(a.t, handler, method, url, values, str)\n}\n\n// HTTPBodyNotContains asserts that a specified handler returns a\n// body that does not contain a string.\n//\n//  a.HTTPBodyNotContains(myHandler, \"www.google.com\", nil, \"I'm Feeling Lucky\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) bool {\n\treturn HTTPBodyNotContains(a.t, handler, method, url, values, str)\n}\n\n// HTTPBodyNotContainsf asserts that a specified handler returns a\n// body that does not contain a string.\n//\n//  a.HTTPBodyNotContainsf(myHandler, \"www.google.com\", nil, \"I'm Feeling Lucky\", \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) bool {\n\treturn HTTPBodyNotContainsf(a.t, handler, method, url, values, str)\n}\n\n// HTTPError asserts that a specified handler returns an error status code.\n//\n//  a.HTTPError(myHandler, \"POST\", \"/a/b/c\", url.Values{\"a\": []string{\"b\", \"c\"}}\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values) bool {\n\treturn HTTPError(a.t, handler, method, url, values)\n}\n\n// HTTPErrorf asserts that a specified handler returns an error status code.\n//\n//  a.HTTPErrorf(myHandler, \"POST\", \"/a/b/c\", url.Values{\"a\": []string{\"b\", \"c\"}}\n//\n// Returns whether the assertion was successful (true, \"error message %s\", \"formatted\") or not (false).\nfunc (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values) bool {\n\treturn HTTPErrorf(a.t, handler, method, url, values)\n}\n\n// HTTPRedirect asserts that a specified handler returns a redirect status code.\n//\n//  a.HTTPRedirect(myHandler, \"GET\", \"/a/b/c\", url.Values{\"a\": []string{\"b\", \"c\"}}\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values) bool {\n\treturn HTTPRedirect(a.t, handler, method, url, values)\n}\n\n// HTTPRedirectf asserts that a specified handler returns a redirect status code.\n//\n//  a.HTTPRedirectf(myHandler, \"GET\", \"/a/b/c\", url.Values{\"a\": []string{\"b\", \"c\"}}\n//\n// Returns whether the assertion was successful (true, \"error message %s\", \"formatted\") or not (false).\nfunc (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values) bool {\n\treturn HTTPRedirectf(a.t, handler, method, url, values)\n}\n\n// HTTPSuccess asserts that a specified handler returns a success status code.\n//\n//  a.HTTPSuccess(myHandler, \"POST\", \"http://www.google.com\", nil)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values) bool {\n\treturn HTTPSuccess(a.t, handler, method, url, values)\n}\n\n// HTTPSuccessf asserts that a specified handler returns a success status code.\n//\n//  a.HTTPSuccessf(myHandler, \"POST\", \"http://www.google.com\", nil, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values) bool {\n\treturn HTTPSuccessf(a.t, handler, method, url, values)\n}\n\n// Implements asserts that an object is implemented by the specified interface.\n//\n//    a.Implements((*MyInterface)(nil), new(MyObject))\nfunc (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {\n\treturn Implements(a.t, interfaceObject, object, msgAndArgs...)\n}\n\n// Implementsf asserts that an object is implemented by the specified interface.\n//\n//    a.Implementsf((*MyInterface, \"error message %s\", \"formatted\")(nil), new(MyObject))\nfunc (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool {\n\treturn Implementsf(a.t, interfaceObject, object, msg, args...)\n}\n\n// InDelta asserts that the two numerals are within delta of each other.\n//\n// \t a.InDelta(math.Pi, (22 / 7.0), 0.01)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {\n\treturn InDelta(a.t, expected, actual, delta, msgAndArgs...)\n}\n\n// InDeltaSlice is the same as InDelta, except it compares two slices.\nfunc (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {\n\treturn InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...)\n}\n\n// InDeltaSlicef is the same as InDelta, except it compares two slices.\nfunc (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {\n\treturn InDeltaSlicef(a.t, expected, actual, delta, msg, args...)\n}\n\n// InDeltaf asserts that the two numerals are within delta of each other.\n//\n// \t a.InDeltaf(math.Pi, (22 / 7.0, \"error message %s\", \"formatted\"), 0.01)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {\n\treturn InDeltaf(a.t, expected, actual, delta, msg, args...)\n}\n\n// InEpsilon asserts that expected and actual have a relative error less than epsilon\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) InEpsilon(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {\n\treturn InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...)\n}\n\n// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.\nfunc (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {\n\treturn InEpsilonSlice(a.t, expected, actual, epsilon, msgAndArgs...)\n}\n\n// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices.\nfunc (a *Assertions) InEpsilonSlicef(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {\n\treturn InEpsilonSlicef(a.t, expected, actual, epsilon, msg, args...)\n}\n\n// InEpsilonf asserts that expected and actual have a relative error less than epsilon\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) InEpsilonf(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {\n\treturn InEpsilonf(a.t, expected, actual, epsilon, msg, args...)\n}\n\n// IsType asserts that the specified objects are of the same type.\nfunc (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool {\n\treturn IsType(a.t, expectedType, object, msgAndArgs...)\n}\n\n// IsTypef asserts that the specified objects are of the same type.\nfunc (a *Assertions) IsTypef(expectedType interface{}, object interface{}, msg string, args ...interface{}) bool {\n\treturn IsTypef(a.t, expectedType, object, msg, args...)\n}\n\n// JSONEq asserts that two JSON strings are equivalent.\n//\n//  a.JSONEq(`{\"hello\": \"world\", \"foo\": \"bar\"}`, `{\"foo\": \"bar\", \"hello\": \"world\"}`)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) bool {\n\treturn JSONEq(a.t, expected, actual, msgAndArgs...)\n}\n\n// JSONEqf asserts that two JSON strings are equivalent.\n//\n//  a.JSONEqf(`{\"hello\": \"world\", \"foo\": \"bar\"}`, `{\"foo\": \"bar\", \"hello\": \"world\"}`, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) JSONEqf(expected string, actual string, msg string, args ...interface{}) bool {\n\treturn JSONEqf(a.t, expected, actual, msg, args...)\n}\n\n// Len asserts that the specified object has specific length.\n// Len also fails if the object has a type that len() not accept.\n//\n//    a.Len(mySlice, 3)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) bool {\n\treturn Len(a.t, object, length, msgAndArgs...)\n}\n\n// Lenf asserts that the specified object has specific length.\n// Lenf also fails if the object has a type that len() not accept.\n//\n//    a.Lenf(mySlice, 3, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Lenf(object interface{}, length int, msg string, args ...interface{}) bool {\n\treturn Lenf(a.t, object, length, msg, args...)\n}\n\n// Nil asserts that the specified object is nil.\n//\n//    a.Nil(err)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) bool {\n\treturn Nil(a.t, object, msgAndArgs...)\n}\n\n// Nilf asserts that the specified object is nil.\n//\n//    a.Nilf(err, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) bool {\n\treturn Nilf(a.t, object, msg, args...)\n}\n\n// NoError asserts that a function returned no error (i.e. `nil`).\n//\n//   actualObj, err := SomeFunction()\n//   if a.NoError(err) {\n// \t   assert.Equal(t, expectedObj, actualObj)\n//   }\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) NoError(err error, msgAndArgs ...interface{}) bool {\n\treturn NoError(a.t, err, msgAndArgs...)\n}\n\n// NoErrorf asserts that a function returned no error (i.e. `nil`).\n//\n//   actualObj, err := SomeFunction()\n//   if a.NoErrorf(err, \"error message %s\", \"formatted\") {\n// \t   assert.Equal(t, expectedObj, actualObj)\n//   }\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) bool {\n\treturn NoErrorf(a.t, err, msg, args...)\n}\n\n// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the\n// specified substring or element.\n//\n//    a.NotContains(\"Hello World\", \"Earth\")\n//    a.NotContains([\"Hello\", \"World\"], \"Earth\")\n//    a.NotContains({\"Hello\": \"World\"}, \"Earth\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool {\n\treturn NotContains(a.t, s, contains, msgAndArgs...)\n}\n\n// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the\n// specified substring or element.\n//\n//    a.NotContainsf(\"Hello World\", \"Earth\", \"error message %s\", \"formatted\")\n//    a.NotContainsf([\"Hello\", \"World\"], \"Earth\", \"error message %s\", \"formatted\")\n//    a.NotContainsf({\"Hello\": \"World\"}, \"Earth\", \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg string, args ...interface{}) bool {\n\treturn NotContainsf(a.t, s, contains, msg, args...)\n}\n\n// NotEmpty asserts that the specified object is NOT empty.  I.e. not nil, \"\", false, 0 or either\n// a slice or a channel with len == 0.\n//\n//  if a.NotEmpty(obj) {\n//    assert.Equal(t, \"two\", obj[1])\n//  }\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) bool {\n\treturn NotEmpty(a.t, object, msgAndArgs...)\n}\n\n// NotEmptyf asserts that the specified object is NOT empty.  I.e. not nil, \"\", false, 0 or either\n// a slice or a channel with len == 0.\n//\n//  if a.NotEmptyf(obj, \"error message %s\", \"formatted\") {\n//    assert.Equal(t, \"two\", obj[1])\n//  }\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface{}) bool {\n\treturn NotEmptyf(a.t, object, msg, args...)\n}\n\n// NotEqual asserts that the specified values are NOT equal.\n//\n//    a.NotEqual(obj1, obj2)\n//\n// Returns whether the assertion was successful (true) or not (false).\n//\n// Pointer variable equality is determined based on the equality of the\n// referenced values (as opposed to the memory addresses).\nfunc (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {\n\treturn NotEqual(a.t, expected, actual, msgAndArgs...)\n}\n\n// NotEqualf asserts that the specified values are NOT equal.\n//\n//    a.NotEqualf(obj1, obj2, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\n//\n// Pointer variable equality is determined based on the equality of the\n// referenced values (as opposed to the memory addresses).\nfunc (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {\n\treturn NotEqualf(a.t, expected, actual, msg, args...)\n}\n\n// NotNil asserts that the specified object is not nil.\n//\n//    a.NotNil(err)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) bool {\n\treturn NotNil(a.t, object, msgAndArgs...)\n}\n\n// NotNilf asserts that the specified object is not nil.\n//\n//    a.NotNilf(err, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{}) bool {\n\treturn NotNilf(a.t, object, msg, args...)\n}\n\n// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.\n//\n//   a.NotPanics(func(){ RemainCalm() })\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) NotPanics(f PanicTestFunc, msgAndArgs ...interface{}) bool {\n\treturn NotPanics(a.t, f, msgAndArgs...)\n}\n\n// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic.\n//\n//   a.NotPanicsf(func(){ RemainCalm() }, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) NotPanicsf(f PanicTestFunc, msg string, args ...interface{}) bool {\n\treturn NotPanicsf(a.t, f, msg, args...)\n}\n\n// NotRegexp asserts that a specified regexp does not match a string.\n//\n//  a.NotRegexp(regexp.MustCompile(\"starts\"), \"it's starting\")\n//  a.NotRegexp(\"^start\", \"it's not starting\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {\n\treturn NotRegexp(a.t, rx, str, msgAndArgs...)\n}\n\n// NotRegexpf asserts that a specified regexp does not match a string.\n//\n//  a.NotRegexpf(regexp.MustCompile(\"starts\", \"error message %s\", \"formatted\"), \"it's starting\")\n//  a.NotRegexpf(\"^start\", \"it's not starting\", \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) bool {\n\treturn NotRegexpf(a.t, rx, str, msg, args...)\n}\n\n// NotSubset asserts that the specified list(array, slice...) contains not all\n// elements given in the specified subset(array, slice...).\n//\n//    a.NotSubset([1, 3, 4], [1, 2], \"But [1, 3, 4] does not contain [1, 2]\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs ...interface{}) bool {\n\treturn NotSubset(a.t, list, subset, msgAndArgs...)\n}\n\n// NotSubsetf asserts that the specified list(array, slice...) contains not all\n// elements given in the specified subset(array, slice...).\n//\n//    a.NotSubsetf([1, 3, 4], [1, 2], \"But [1, 3, 4] does not contain [1, 2]\", \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) bool {\n\treturn NotSubsetf(a.t, list, subset, msg, args...)\n}\n\n// NotZero asserts that i is not the zero value for its type and returns the truth.\nfunc (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) bool {\n\treturn NotZero(a.t, i, msgAndArgs...)\n}\n\n// NotZerof asserts that i is not the zero value for its type and returns the truth.\nfunc (a *Assertions) NotZerof(i interface{}, msg string, args ...interface{}) bool {\n\treturn NotZerof(a.t, i, msg, args...)\n}\n\n// Panics asserts that the code inside the specified PanicTestFunc panics.\n//\n//   a.Panics(func(){ GoCrazy() })\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Panics(f PanicTestFunc, msgAndArgs ...interface{}) bool {\n\treturn Panics(a.t, f, msgAndArgs...)\n}\n\n// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that\n// the recovered panic value equals the expected panic value.\n//\n//   a.PanicsWithValue(\"crazy error\", func(){ GoCrazy() })\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) PanicsWithValue(expected interface{}, f PanicTestFunc, msgAndArgs ...interface{}) bool {\n\treturn PanicsWithValue(a.t, expected, f, msgAndArgs...)\n}\n\n// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that\n// the recovered panic value equals the expected panic value.\n//\n//   a.PanicsWithValuef(\"crazy error\", func(){ GoCrazy() }, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) PanicsWithValuef(expected interface{}, f PanicTestFunc, msg string, args ...interface{}) bool {\n\treturn PanicsWithValuef(a.t, expected, f, msg, args...)\n}\n\n// Panicsf asserts that the code inside the specified PanicTestFunc panics.\n//\n//   a.Panicsf(func(){ GoCrazy() }, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Panicsf(f PanicTestFunc, msg string, args ...interface{}) bool {\n\treturn Panicsf(a.t, f, msg, args...)\n}\n\n// Regexp asserts that a specified regexp matches a string.\n//\n//  a.Regexp(regexp.MustCompile(\"start\"), \"it's starting\")\n//  a.Regexp(\"start...$\", \"it's not starting\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {\n\treturn Regexp(a.t, rx, str, msgAndArgs...)\n}\n\n// Regexpf asserts that a specified regexp matches a string.\n//\n//  a.Regexpf(regexp.MustCompile(\"start\", \"error message %s\", \"formatted\"), \"it's starting\")\n//  a.Regexpf(\"start...$\", \"it's not starting\", \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) bool {\n\treturn Regexpf(a.t, rx, str, msg, args...)\n}\n\n// Subset asserts that the specified list(array, slice...) contains all\n// elements given in the specified subset(array, slice...).\n//\n//    a.Subset([1, 2, 3], [1, 2], \"But [1, 2, 3] does contain [1, 2]\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...interface{}) bool {\n\treturn Subset(a.t, list, subset, msgAndArgs...)\n}\n\n// Subsetf asserts that the specified list(array, slice...) contains all\n// elements given in the specified subset(array, slice...).\n//\n//    a.Subsetf([1, 2, 3], [1, 2], \"But [1, 2, 3] does contain [1, 2]\", \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) bool {\n\treturn Subsetf(a.t, list, subset, msg, args...)\n}\n\n// True asserts that the specified value is true.\n//\n//    a.True(myBool)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) True(value bool, msgAndArgs ...interface{}) bool {\n\treturn True(a.t, value, msgAndArgs...)\n}\n\n// Truef asserts that the specified value is true.\n//\n//    a.Truef(myBool, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Truef(value bool, msg string, args ...interface{}) bool {\n\treturn Truef(a.t, value, msg, args...)\n}\n\n// WithinDuration asserts that the two times are within duration delta of each other.\n//\n//   a.WithinDuration(time.Now(), time.Now(), 10*time.Second)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool {\n\treturn WithinDuration(a.t, expected, actual, delta, msgAndArgs...)\n}\n\n// WithinDurationf asserts that the two times are within duration delta of each other.\n//\n//   a.WithinDurationf(time.Now(), time.Now(), 10*time.Second, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) bool {\n\treturn WithinDurationf(a.t, expected, actual, delta, msg, args...)\n}\n\n// Zero asserts that i is the zero value for its type and returns the truth.\nfunc (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) bool {\n\treturn Zero(a.t, i, msgAndArgs...)\n}\n\n// Zerof asserts that i is the zero value for its type and returns the truth.\nfunc (a *Assertions) Zerof(i interface{}, msg string, args ...interface{}) bool {\n\treturn Zerof(a.t, i, msg, args...)\n}\n"
  },
  {
    "path": "vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl",
    "content": "{{.CommentWithoutT \"a\"}}\nfunc (a *Assertions) {{.DocInfo.Name}}({{.Params}}) bool {\n\treturn {{.DocInfo.Name}}(a.t, {{.ForwardedParams}})\n}\n"
  },
  {
    "path": "vendor/github.com/stretchr/testify/assert/assertions.go",
    "content": "package assert\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"reflect\"\n\t\"regexp\"\n\t\"runtime\"\n\t\"strings\"\n\t\"time\"\n\t\"unicode\"\n\t\"unicode/utf8\"\n\n\t\"github.com/davecgh/go-spew/spew\"\n\t\"github.com/pmezard/go-difflib/difflib\"\n)\n\n//go:generate go run ../_codegen/main.go -output-package=assert -template=assertion_format.go.tmpl\n\n// TestingT is an interface wrapper around *testing.T\ntype TestingT interface {\n\tErrorf(format string, args ...interface{})\n}\n\n// Comparison a custom function that returns true on success and false on failure\ntype Comparison func() (success bool)\n\n/*\n\tHelper functions\n*/\n\n// ObjectsAreEqual determines if two objects are considered equal.\n//\n// This function does no assertion of any kind.\nfunc ObjectsAreEqual(expected, actual interface{}) bool {\n\n\tif expected == nil || actual == nil {\n\t\treturn expected == actual\n\t}\n\tif exp, ok := expected.([]byte); ok {\n\t\tact, ok := actual.([]byte)\n\t\tif !ok {\n\t\t\treturn false\n\t\t} else if exp == nil || act == nil {\n\t\t\treturn exp == nil && act == nil\n\t\t}\n\t\treturn bytes.Equal(exp, act)\n\t}\n\treturn reflect.DeepEqual(expected, actual)\n\n}\n\n// ObjectsAreEqualValues gets whether two objects are equal, or if their\n// values are equal.\nfunc ObjectsAreEqualValues(expected, actual interface{}) bool {\n\tif ObjectsAreEqual(expected, actual) {\n\t\treturn true\n\t}\n\n\tactualType := reflect.TypeOf(actual)\n\tif actualType == nil {\n\t\treturn false\n\t}\n\texpectedValue := reflect.ValueOf(expected)\n\tif expectedValue.IsValid() && expectedValue.Type().ConvertibleTo(actualType) {\n\t\t// Attempt comparison after type conversion\n\t\treturn reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), actual)\n\t}\n\n\treturn false\n}\n\n/* CallerInfo is necessary because the assert functions use the testing object\ninternally, causing it to print the file:line of the assert method, rather than where\nthe problem actually occurred in calling code.*/\n\n// CallerInfo returns an array of strings containing the file and line number\n// of each stack frame leading from the current test to the assert call that\n// failed.\nfunc CallerInfo() []string {\n\n\tpc := uintptr(0)\n\tfile := \"\"\n\tline := 0\n\tok := false\n\tname := \"\"\n\n\tcallers := []string{}\n\tfor i := 0; ; i++ {\n\t\tpc, file, line, ok = runtime.Caller(i)\n\t\tif !ok {\n\t\t\t// The breaks below failed to terminate the loop, and we ran off the\n\t\t\t// end of the call stack.\n\t\t\tbreak\n\t\t}\n\n\t\t// This is a huge edge case, but it will panic if this is the case, see #180\n\t\tif file == \"<autogenerated>\" {\n\t\t\tbreak\n\t\t}\n\n\t\tf := runtime.FuncForPC(pc)\n\t\tif f == nil {\n\t\t\tbreak\n\t\t}\n\t\tname = f.Name()\n\n\t\t// testing.tRunner is the standard library function that calls\n\t\t// tests. Subtests are called directly by tRunner, without going through\n\t\t// the Test/Benchmark/Example function that contains the t.Run calls, so\n\t\t// with subtests we should break when we hit tRunner, without adding it\n\t\t// to the list of callers.\n\t\tif name == \"testing.tRunner\" {\n\t\t\tbreak\n\t\t}\n\n\t\tparts := strings.Split(file, \"/\")\n\t\tfile = parts[len(parts)-1]\n\t\tif len(parts) > 1 {\n\t\t\tdir := parts[len(parts)-2]\n\t\t\tif (dir != \"assert\" && dir != \"mock\" && dir != \"require\") || file == \"mock_test.go\" {\n\t\t\t\tcallers = append(callers, fmt.Sprintf(\"%s:%d\", file, line))\n\t\t\t}\n\t\t}\n\n\t\t// Drop the package\n\t\tsegments := strings.Split(name, \".\")\n\t\tname = segments[len(segments)-1]\n\t\tif isTest(name, \"Test\") ||\n\t\t\tisTest(name, \"Benchmark\") ||\n\t\t\tisTest(name, \"Example\") {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn callers\n}\n\n// Stolen from the `go test` tool.\n// isTest tells whether name looks like a test (or benchmark, according to prefix).\n// It is a Test (say) if there is a character after Test that is not a lower-case letter.\n// We don't want TesticularCancer.\nfunc isTest(name, prefix string) bool {\n\tif !strings.HasPrefix(name, prefix) {\n\t\treturn false\n\t}\n\tif len(name) == len(prefix) { // \"Test\" is ok\n\t\treturn true\n\t}\n\trune, _ := utf8.DecodeRuneInString(name[len(prefix):])\n\treturn !unicode.IsLower(rune)\n}\n\n// getWhitespaceString returns a string that is long enough to overwrite the default\n// output from the go testing framework.\nfunc getWhitespaceString() string {\n\n\t_, file, line, ok := runtime.Caller(1)\n\tif !ok {\n\t\treturn \"\"\n\t}\n\tparts := strings.Split(file, \"/\")\n\tfile = parts[len(parts)-1]\n\n\treturn strings.Repeat(\" \", len(fmt.Sprintf(\"%s:%d:        \", file, line)))\n\n}\n\nfunc messageFromMsgAndArgs(msgAndArgs ...interface{}) string {\n\tif len(msgAndArgs) == 0 || msgAndArgs == nil {\n\t\treturn \"\"\n\t}\n\tif len(msgAndArgs) == 1 {\n\t\treturn msgAndArgs[0].(string)\n\t}\n\tif len(msgAndArgs) > 1 {\n\t\treturn fmt.Sprintf(msgAndArgs[0].(string), msgAndArgs[1:]...)\n\t}\n\treturn \"\"\n}\n\n// Aligns the provided message so that all lines after the first line start at the same location as the first line.\n// Assumes that the first line starts at the correct location (after carriage return, tab, label, spacer and tab).\n// The longestLabelLen parameter specifies the length of the longest label in the output (required becaues this is the\n// basis on which the alignment occurs).\nfunc indentMessageLines(message string, longestLabelLen int) string {\n\toutBuf := new(bytes.Buffer)\n\n\tfor i, scanner := 0, bufio.NewScanner(strings.NewReader(message)); scanner.Scan(); i++ {\n\t\t// no need to align first line because it starts at the correct location (after the label)\n\t\tif i != 0 {\n\t\t\t// append alignLen+1 spaces to align with \"{{longestLabel}}:\" before adding tab\n\t\t\toutBuf.WriteString(\"\\n\\r\\t\" + strings.Repeat(\" \", longestLabelLen+1) + \"\\t\")\n\t\t}\n\t\toutBuf.WriteString(scanner.Text())\n\t}\n\n\treturn outBuf.String()\n}\n\ntype failNower interface {\n\tFailNow()\n}\n\n// FailNow fails test\nfunc FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool {\n\tFail(t, failureMessage, msgAndArgs...)\n\n\t// We cannot extend TestingT with FailNow() and\n\t// maintain backwards compatibility, so we fallback\n\t// to panicking when FailNow is not available in\n\t// TestingT.\n\t// See issue #263\n\n\tif t, ok := t.(failNower); ok {\n\t\tt.FailNow()\n\t} else {\n\t\tpanic(\"test failed and t is missing `FailNow()`\")\n\t}\n\treturn false\n}\n\n// Fail reports a failure through\nfunc Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool {\n\tcontent := []labeledContent{\n\t\t{\"Error Trace\", strings.Join(CallerInfo(), \"\\n\\r\\t\\t\\t\")},\n\t\t{\"Error\", failureMessage},\n\t}\n\n\tmessage := messageFromMsgAndArgs(msgAndArgs...)\n\tif len(message) > 0 {\n\t\tcontent = append(content, labeledContent{\"Messages\", message})\n\t}\n\n\tt.Errorf(\"%s\", \"\\r\"+getWhitespaceString()+labeledOutput(content...))\n\n\treturn false\n}\n\ntype labeledContent struct {\n\tlabel   string\n\tcontent string\n}\n\n// labeledOutput returns a string consisting of the provided labeledContent. Each labeled output is appended in the following manner:\n//\n//   \\r\\t{{label}}:{{align_spaces}}\\t{{content}}\\n\n//\n// The initial carriage return is required to undo/erase any padding added by testing.T.Errorf. The \"\\t{{label}}:\" is for the label.\n// If a label is shorter than the longest label provided, padding spaces are added to make all the labels match in length. Once this\n// alignment is achieved, \"\\t{{content}}\\n\" is added for the output.\n//\n// If the content of the labeledOutput contains line breaks, the subsequent lines are aligned so that they start at the same location as the first line.\nfunc labeledOutput(content ...labeledContent) string {\n\tlongestLabel := 0\n\tfor _, v := range content {\n\t\tif len(v.label) > longestLabel {\n\t\t\tlongestLabel = len(v.label)\n\t\t}\n\t}\n\tvar output string\n\tfor _, v := range content {\n\t\toutput += \"\\r\\t\" + v.label + \":\" + strings.Repeat(\" \", longestLabel-len(v.label)) + \"\\t\" + indentMessageLines(v.content, longestLabel) + \"\\n\"\n\t}\n\treturn output\n}\n\n// Implements asserts that an object is implemented by the specified interface.\n//\n//    assert.Implements(t, (*MyInterface)(nil), new(MyObject))\nfunc Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {\n\n\tinterfaceType := reflect.TypeOf(interfaceObject).Elem()\n\n\tif !reflect.TypeOf(object).Implements(interfaceType) {\n\t\treturn Fail(t, fmt.Sprintf(\"%T must implement %v\", object, interfaceType), msgAndArgs...)\n\t}\n\n\treturn true\n\n}\n\n// IsType asserts that the specified objects are of the same type.\nfunc IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool {\n\n\tif !ObjectsAreEqual(reflect.TypeOf(object), reflect.TypeOf(expectedType)) {\n\t\treturn Fail(t, fmt.Sprintf(\"Object expected to be of type %v, but was %v\", reflect.TypeOf(expectedType), reflect.TypeOf(object)), msgAndArgs...)\n\t}\n\n\treturn true\n}\n\n// Equal asserts that two objects are equal.\n//\n//    assert.Equal(t, 123, 123)\n//\n// Returns whether the assertion was successful (true) or not (false).\n//\n// Pointer variable equality is determined based on the equality of the\n// referenced values (as opposed to the memory addresses). Function equality\n// cannot be determined and will always fail.\nfunc Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {\n\tif err := validateEqualArgs(expected, actual); err != nil {\n\t\treturn Fail(t, fmt.Sprintf(\"Invalid operation: %#v == %#v (%s)\",\n\t\t\texpected, actual, err), msgAndArgs...)\n\t}\n\n\tif !ObjectsAreEqual(expected, actual) {\n\t\tdiff := diff(expected, actual)\n\t\texpected, actual = formatUnequalValues(expected, actual)\n\t\treturn Fail(t, fmt.Sprintf(\"Not equal: \\n\"+\n\t\t\t\"expected: %s\\n\"+\n\t\t\t\"actual: %s%s\", expected, actual, diff), msgAndArgs...)\n\t}\n\n\treturn true\n\n}\n\n// formatUnequalValues takes two values of arbitrary types and returns string\n// representations appropriate to be presented to the user.\n//\n// If the values are not of like type, the returned strings will be prefixed\n// with the type name, and the value will be enclosed in parenthesis similar\n// to a type conversion in the Go grammar.\nfunc formatUnequalValues(expected, actual interface{}) (e string, a string) {\n\tif reflect.TypeOf(expected) != reflect.TypeOf(actual) {\n\t\treturn fmt.Sprintf(\"%T(%#v)\", expected, expected),\n\t\t\tfmt.Sprintf(\"%T(%#v)\", actual, actual)\n\t}\n\n\treturn fmt.Sprintf(\"%#v\", expected),\n\t\tfmt.Sprintf(\"%#v\", actual)\n}\n\n// EqualValues asserts that two objects are equal or convertable to the same types\n// and equal.\n//\n//    assert.EqualValues(t, uint32(123), int32(123))\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {\n\n\tif !ObjectsAreEqualValues(expected, actual) {\n\t\tdiff := diff(expected, actual)\n\t\texpected, actual = formatUnequalValues(expected, actual)\n\t\treturn Fail(t, fmt.Sprintf(\"Not equal: \\n\"+\n\t\t\t\"expected: %s\\n\"+\n\t\t\t\"actual: %s%s\", expected, actual, diff), msgAndArgs...)\n\t}\n\n\treturn true\n\n}\n\n// Exactly asserts that two objects are equal is value and type.\n//\n//    assert.Exactly(t, int32(123), int64(123))\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {\n\n\taType := reflect.TypeOf(expected)\n\tbType := reflect.TypeOf(actual)\n\n\tif aType != bType {\n\t\treturn Fail(t, fmt.Sprintf(\"Types expected to match exactly\\n\\r\\t%v != %v\", aType, bType), msgAndArgs...)\n\t}\n\n\treturn Equal(t, expected, actual, msgAndArgs...)\n\n}\n\n// NotNil asserts that the specified object is not nil.\n//\n//    assert.NotNil(t, err)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {\n\tif !isNil(object) {\n\t\treturn true\n\t}\n\treturn Fail(t, \"Expected value not to be nil.\", msgAndArgs...)\n}\n\n// isNil checks if a specified object is nil or not, without Failing.\nfunc isNil(object interface{}) bool {\n\tif object == nil {\n\t\treturn true\n\t}\n\n\tvalue := reflect.ValueOf(object)\n\tkind := value.Kind()\n\tif kind >= reflect.Chan && kind <= reflect.Slice && value.IsNil() {\n\t\treturn true\n\t}\n\n\treturn false\n}\n\n// Nil asserts that the specified object is nil.\n//\n//    assert.Nil(t, err)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {\n\tif isNil(object) {\n\t\treturn true\n\t}\n\treturn Fail(t, fmt.Sprintf(\"Expected nil, but got: %#v\", object), msgAndArgs...)\n}\n\nvar numericZeros = []interface{}{\n\tint(0),\n\tint8(0),\n\tint16(0),\n\tint32(0),\n\tint64(0),\n\tuint(0),\n\tuint8(0),\n\tuint16(0),\n\tuint32(0),\n\tuint64(0),\n\tfloat32(0),\n\tfloat64(0),\n}\n\n// isEmpty gets whether the specified object is considered empty or not.\nfunc isEmpty(object interface{}) bool {\n\n\tif object == nil {\n\t\treturn true\n\t} else if object == \"\" {\n\t\treturn true\n\t} else if object == false {\n\t\treturn true\n\t}\n\n\tfor _, v := range numericZeros {\n\t\tif object == v {\n\t\t\treturn true\n\t\t}\n\t}\n\n\tobjValue := reflect.ValueOf(object)\n\n\tswitch objValue.Kind() {\n\tcase reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String:\n\t\t{\n\t\t\treturn (objValue.Len() == 0)\n\t\t}\n\tcase reflect.Struct:\n\t\tswitch object.(type) {\n\t\tcase time.Time:\n\t\t\treturn object.(time.Time).IsZero()\n\t\t}\n\tcase reflect.Ptr:\n\t\t{\n\t\t\tif objValue.IsNil() {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tswitch object.(type) {\n\t\t\tcase *time.Time:\n\t\t\t\treturn object.(*time.Time).IsZero()\n\t\t\tdefault:\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\treturn false\n}\n\n// Empty asserts that the specified object is empty.  I.e. nil, \"\", false, 0 or either\n// a slice or a channel with len == 0.\n//\n//  assert.Empty(t, obj)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {\n\n\tpass := isEmpty(object)\n\tif !pass {\n\t\tFail(t, fmt.Sprintf(\"Should be empty, but was %v\", object), msgAndArgs...)\n\t}\n\n\treturn pass\n\n}\n\n// NotEmpty asserts that the specified object is NOT empty.  I.e. not nil, \"\", false, 0 or either\n// a slice or a channel with len == 0.\n//\n//  if assert.NotEmpty(t, obj) {\n//    assert.Equal(t, \"two\", obj[1])\n//  }\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {\n\n\tpass := !isEmpty(object)\n\tif !pass {\n\t\tFail(t, fmt.Sprintf(\"Should NOT be empty, but was %v\", object), msgAndArgs...)\n\t}\n\n\treturn pass\n\n}\n\n// getLen try to get length of object.\n// return (false, 0) if impossible.\nfunc getLen(x interface{}) (ok bool, length int) {\n\tv := reflect.ValueOf(x)\n\tdefer func() {\n\t\tif e := recover(); e != nil {\n\t\t\tok = false\n\t\t}\n\t}()\n\treturn true, v.Len()\n}\n\n// Len asserts that the specified object has specific length.\n// Len also fails if the object has a type that len() not accept.\n//\n//    assert.Len(t, mySlice, 3)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) bool {\n\tok, l := getLen(object)\n\tif !ok {\n\t\treturn Fail(t, fmt.Sprintf(\"\\\"%s\\\" could not be applied builtin len()\", object), msgAndArgs...)\n\t}\n\n\tif l != length {\n\t\treturn Fail(t, fmt.Sprintf(\"\\\"%s\\\" should have %d item(s), but has %d\", object, length, l), msgAndArgs...)\n\t}\n\treturn true\n}\n\n// True asserts that the specified value is true.\n//\n//    assert.True(t, myBool)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc True(t TestingT, value bool, msgAndArgs ...interface{}) bool {\n\n\tif value != true {\n\t\treturn Fail(t, \"Should be true\", msgAndArgs...)\n\t}\n\n\treturn true\n\n}\n\n// False asserts that the specified value is false.\n//\n//    assert.False(t, myBool)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc False(t TestingT, value bool, msgAndArgs ...interface{}) bool {\n\n\tif value != false {\n\t\treturn Fail(t, \"Should be false\", msgAndArgs...)\n\t}\n\n\treturn true\n\n}\n\n// NotEqual asserts that the specified values are NOT equal.\n//\n//    assert.NotEqual(t, obj1, obj2)\n//\n// Returns whether the assertion was successful (true) or not (false).\n//\n// Pointer variable equality is determined based on the equality of the\n// referenced values (as opposed to the memory addresses).\nfunc NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {\n\tif err := validateEqualArgs(expected, actual); err != nil {\n\t\treturn Fail(t, fmt.Sprintf(\"Invalid operation: %#v != %#v (%s)\",\n\t\t\texpected, actual, err), msgAndArgs...)\n\t}\n\n\tif ObjectsAreEqual(expected, actual) {\n\t\treturn Fail(t, fmt.Sprintf(\"Should not be: %#v\\n\", actual), msgAndArgs...)\n\t}\n\n\treturn true\n\n}\n\n// containsElement try loop over the list check if the list includes the element.\n// return (false, false) if impossible.\n// return (true, false) if element was not found.\n// return (true, true) if element was found.\nfunc includeElement(list interface{}, element interface{}) (ok, found bool) {\n\n\tlistValue := reflect.ValueOf(list)\n\telementValue := reflect.ValueOf(element)\n\tdefer func() {\n\t\tif e := recover(); e != nil {\n\t\t\tok = false\n\t\t\tfound = false\n\t\t}\n\t}()\n\n\tif reflect.TypeOf(list).Kind() == reflect.String {\n\t\treturn true, strings.Contains(listValue.String(), elementValue.String())\n\t}\n\n\tif reflect.TypeOf(list).Kind() == reflect.Map {\n\t\tmapKeys := listValue.MapKeys()\n\t\tfor i := 0; i < len(mapKeys); i++ {\n\t\t\tif ObjectsAreEqual(mapKeys[i].Interface(), element) {\n\t\t\t\treturn true, true\n\t\t\t}\n\t\t}\n\t\treturn true, false\n\t}\n\n\tfor i := 0; i < listValue.Len(); i++ {\n\t\tif ObjectsAreEqual(listValue.Index(i).Interface(), element) {\n\t\t\treturn true, true\n\t\t}\n\t}\n\treturn true, false\n\n}\n\n// Contains asserts that the specified string, list(array, slice...) or map contains the\n// specified substring or element.\n//\n//    assert.Contains(t, \"Hello World\", \"World\")\n//    assert.Contains(t, [\"Hello\", \"World\"], \"World\")\n//    assert.Contains(t, {\"Hello\": \"World\"}, \"Hello\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool {\n\n\tok, found := includeElement(s, contains)\n\tif !ok {\n\t\treturn Fail(t, fmt.Sprintf(\"\\\"%s\\\" could not be applied builtin len()\", s), msgAndArgs...)\n\t}\n\tif !found {\n\t\treturn Fail(t, fmt.Sprintf(\"\\\"%s\\\" does not contain \\\"%s\\\"\", s, contains), msgAndArgs...)\n\t}\n\n\treturn true\n\n}\n\n// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the\n// specified substring or element.\n//\n//    assert.NotContains(t, \"Hello World\", \"Earth\")\n//    assert.NotContains(t, [\"Hello\", \"World\"], \"Earth\")\n//    assert.NotContains(t, {\"Hello\": \"World\"}, \"Earth\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool {\n\n\tok, found := includeElement(s, contains)\n\tif !ok {\n\t\treturn Fail(t, fmt.Sprintf(\"\\\"%s\\\" could not be applied builtin len()\", s), msgAndArgs...)\n\t}\n\tif found {\n\t\treturn Fail(t, fmt.Sprintf(\"\\\"%s\\\" should not contain \\\"%s\\\"\", s, contains), msgAndArgs...)\n\t}\n\n\treturn true\n\n}\n\n// Subset asserts that the specified list(array, slice...) contains all\n// elements given in the specified subset(array, slice...).\n//\n//    assert.Subset(t, [1, 2, 3], [1, 2], \"But [1, 2, 3] does contain [1, 2]\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) {\n\tif subset == nil {\n\t\treturn true // we consider nil to be equal to the nil set\n\t}\n\n\tsubsetValue := reflect.ValueOf(subset)\n\tdefer func() {\n\t\tif e := recover(); e != nil {\n\t\t\tok = false\n\t\t}\n\t}()\n\n\tlistKind := reflect.TypeOf(list).Kind()\n\tsubsetKind := reflect.TypeOf(subset).Kind()\n\n\tif listKind != reflect.Array && listKind != reflect.Slice {\n\t\treturn Fail(t, fmt.Sprintf(\"%q has an unsupported type %s\", list, listKind), msgAndArgs...)\n\t}\n\n\tif subsetKind != reflect.Array && subsetKind != reflect.Slice {\n\t\treturn Fail(t, fmt.Sprintf(\"%q has an unsupported type %s\", subset, subsetKind), msgAndArgs...)\n\t}\n\n\tfor i := 0; i < subsetValue.Len(); i++ {\n\t\telement := subsetValue.Index(i).Interface()\n\t\tok, found := includeElement(list, element)\n\t\tif !ok {\n\t\t\treturn Fail(t, fmt.Sprintf(\"\\\"%s\\\" could not be applied builtin len()\", list), msgAndArgs...)\n\t\t}\n\t\tif !found {\n\t\t\treturn Fail(t, fmt.Sprintf(\"\\\"%s\\\" does not contain \\\"%s\\\"\", list, element), msgAndArgs...)\n\t\t}\n\t}\n\n\treturn true\n}\n\n// NotSubset asserts that the specified list(array, slice...) contains not all\n// elements given in the specified subset(array, slice...).\n//\n//    assert.NotSubset(t, [1, 3, 4], [1, 2], \"But [1, 3, 4] does not contain [1, 2]\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) {\n\tif subset == nil {\n\t\treturn false // we consider nil to be equal to the nil set\n\t}\n\n\tsubsetValue := reflect.ValueOf(subset)\n\tdefer func() {\n\t\tif e := recover(); e != nil {\n\t\t\tok = false\n\t\t}\n\t}()\n\n\tlistKind := reflect.TypeOf(list).Kind()\n\tsubsetKind := reflect.TypeOf(subset).Kind()\n\n\tif listKind != reflect.Array && listKind != reflect.Slice {\n\t\treturn Fail(t, fmt.Sprintf(\"%q has an unsupported type %s\", list, listKind), msgAndArgs...)\n\t}\n\n\tif subsetKind != reflect.Array && subsetKind != reflect.Slice {\n\t\treturn Fail(t, fmt.Sprintf(\"%q has an unsupported type %s\", subset, subsetKind), msgAndArgs...)\n\t}\n\n\tfor i := 0; i < subsetValue.Len(); i++ {\n\t\telement := subsetValue.Index(i).Interface()\n\t\tok, found := includeElement(list, element)\n\t\tif !ok {\n\t\t\treturn Fail(t, fmt.Sprintf(\"\\\"%s\\\" could not be applied builtin len()\", list), msgAndArgs...)\n\t\t}\n\t\tif !found {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn Fail(t, fmt.Sprintf(\"%q is a subset of %q\", subset, list), msgAndArgs...)\n}\n\n// Condition uses a Comparison to assert a complex condition.\nfunc Condition(t TestingT, comp Comparison, msgAndArgs ...interface{}) bool {\n\tresult := comp()\n\tif !result {\n\t\tFail(t, \"Condition failed!\", msgAndArgs...)\n\t}\n\treturn result\n}\n\n// PanicTestFunc defines a func that should be passed to the assert.Panics and assert.NotPanics\n// methods, and represents a simple func that takes no arguments, and returns nothing.\ntype PanicTestFunc func()\n\n// didPanic returns true if the function passed to it panics. Otherwise, it returns false.\nfunc didPanic(f PanicTestFunc) (bool, interface{}) {\n\n\tdidPanic := false\n\tvar message interface{}\n\tfunc() {\n\n\t\tdefer func() {\n\t\t\tif message = recover(); message != nil {\n\t\t\t\tdidPanic = true\n\t\t\t}\n\t\t}()\n\n\t\t// call the target function\n\t\tf()\n\n\t}()\n\n\treturn didPanic, message\n\n}\n\n// Panics asserts that the code inside the specified PanicTestFunc panics.\n//\n//   assert.Panics(t, func(){ GoCrazy() })\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Panics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {\n\n\tif funcDidPanic, panicValue := didPanic(f); !funcDidPanic {\n\t\treturn Fail(t, fmt.Sprintf(\"func %#v should panic\\n\\r\\tPanic value:\\t%v\", f, panicValue), msgAndArgs...)\n\t}\n\n\treturn true\n}\n\n// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that\n// the recovered panic value equals the expected panic value.\n//\n//   assert.PanicsWithValue(t, \"crazy error\", func(){ GoCrazy() })\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc PanicsWithValue(t TestingT, expected interface{}, f PanicTestFunc, msgAndArgs ...interface{}) bool {\n\n\tfuncDidPanic, panicValue := didPanic(f)\n\tif !funcDidPanic {\n\t\treturn Fail(t, fmt.Sprintf(\"func %#v should panic\\n\\r\\tPanic value:\\t%v\", f, panicValue), msgAndArgs...)\n\t}\n\tif panicValue != expected {\n\t\treturn Fail(t, fmt.Sprintf(\"func %#v should panic with value:\\t%v\\n\\r\\tPanic value:\\t%v\", f, expected, panicValue), msgAndArgs...)\n\t}\n\n\treturn true\n}\n\n// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.\n//\n//   assert.NotPanics(t, func(){ RemainCalm() })\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NotPanics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {\n\n\tif funcDidPanic, panicValue := didPanic(f); funcDidPanic {\n\t\treturn Fail(t, fmt.Sprintf(\"func %#v should not panic\\n\\r\\tPanic value:\\t%v\", f, panicValue), msgAndArgs...)\n\t}\n\n\treturn true\n}\n\n// WithinDuration asserts that the two times are within duration delta of each other.\n//\n//   assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc WithinDuration(t TestingT, expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool {\n\n\tdt := expected.Sub(actual)\n\tif dt < -delta || dt > delta {\n\t\treturn Fail(t, fmt.Sprintf(\"Max difference between %v and %v allowed is %v, but difference was %v\", expected, actual, delta, dt), msgAndArgs...)\n\t}\n\n\treturn true\n}\n\nfunc toFloat(x interface{}) (float64, bool) {\n\tvar xf float64\n\txok := true\n\n\tswitch xn := x.(type) {\n\tcase uint8:\n\t\txf = float64(xn)\n\tcase uint16:\n\t\txf = float64(xn)\n\tcase uint32:\n\t\txf = float64(xn)\n\tcase uint64:\n\t\txf = float64(xn)\n\tcase int:\n\t\txf = float64(xn)\n\tcase int8:\n\t\txf = float64(xn)\n\tcase int16:\n\t\txf = float64(xn)\n\tcase int32:\n\t\txf = float64(xn)\n\tcase int64:\n\t\txf = float64(xn)\n\tcase float32:\n\t\txf = float64(xn)\n\tcase float64:\n\t\txf = float64(xn)\n\tcase time.Duration:\n\t\txf = float64(xn)\n\tdefault:\n\t\txok = false\n\t}\n\n\treturn xf, xok\n}\n\n// InDelta asserts that the two numerals are within delta of each other.\n//\n// \t assert.InDelta(t, math.Pi, (22 / 7.0), 0.01)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {\n\n\taf, aok := toFloat(expected)\n\tbf, bok := toFloat(actual)\n\n\tif !aok || !bok {\n\t\treturn Fail(t, fmt.Sprintf(\"Parameters must be numerical\"), msgAndArgs...)\n\t}\n\n\tif math.IsNaN(af) {\n\t\treturn Fail(t, fmt.Sprintf(\"Expected must not be NaN\"), msgAndArgs...)\n\t}\n\n\tif math.IsNaN(bf) {\n\t\treturn Fail(t, fmt.Sprintf(\"Expected %v with delta %v, but was NaN\", expected, delta), msgAndArgs...)\n\t}\n\n\tdt := af - bf\n\tif dt < -delta || dt > delta {\n\t\treturn Fail(t, fmt.Sprintf(\"Max difference between %v and %v allowed is %v, but difference was %v\", expected, actual, delta, dt), msgAndArgs...)\n\t}\n\n\treturn true\n}\n\n// InDeltaSlice is the same as InDelta, except it compares two slices.\nfunc InDeltaSlice(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {\n\tif expected == nil || actual == nil ||\n\t\treflect.TypeOf(actual).Kind() != reflect.Slice ||\n\t\treflect.TypeOf(expected).Kind() != reflect.Slice {\n\t\treturn Fail(t, fmt.Sprintf(\"Parameters must be slice\"), msgAndArgs...)\n\t}\n\n\tactualSlice := reflect.ValueOf(actual)\n\texpectedSlice := reflect.ValueOf(expected)\n\n\tfor i := 0; i < actualSlice.Len(); i++ {\n\t\tresult := InDelta(t, actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface(), delta, msgAndArgs...)\n\t\tif !result {\n\t\t\treturn result\n\t\t}\n\t}\n\n\treturn true\n}\n\nfunc calcRelativeError(expected, actual interface{}) (float64, error) {\n\taf, aok := toFloat(expected)\n\tif !aok {\n\t\treturn 0, fmt.Errorf(\"expected value %q cannot be converted to float\", expected)\n\t}\n\tif af == 0 {\n\t\treturn 0, fmt.Errorf(\"expected value must have a value other than zero to calculate the relative error\")\n\t}\n\tbf, bok := toFloat(actual)\n\tif !bok {\n\t\treturn 0, fmt.Errorf(\"actual value %q cannot be converted to float\", actual)\n\t}\n\n\treturn math.Abs(af-bf) / math.Abs(af), nil\n}\n\n// InEpsilon asserts that expected and actual have a relative error less than epsilon\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {\n\tactualEpsilon, err := calcRelativeError(expected, actual)\n\tif err != nil {\n\t\treturn Fail(t, err.Error(), msgAndArgs...)\n\t}\n\tif actualEpsilon > epsilon {\n\t\treturn Fail(t, fmt.Sprintf(\"Relative error is too high: %#v (expected)\\n\"+\n\t\t\t\"        < %#v (actual)\", epsilon, actualEpsilon), msgAndArgs...)\n\t}\n\n\treturn true\n}\n\n// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.\nfunc InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {\n\tif expected == nil || actual == nil ||\n\t\treflect.TypeOf(actual).Kind() != reflect.Slice ||\n\t\treflect.TypeOf(expected).Kind() != reflect.Slice {\n\t\treturn Fail(t, fmt.Sprintf(\"Parameters must be slice\"), msgAndArgs...)\n\t}\n\n\tactualSlice := reflect.ValueOf(actual)\n\texpectedSlice := reflect.ValueOf(expected)\n\n\tfor i := 0; i < actualSlice.Len(); i++ {\n\t\tresult := InEpsilon(t, actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface(), epsilon)\n\t\tif !result {\n\t\t\treturn result\n\t\t}\n\t}\n\n\treturn true\n}\n\n/*\n\tErrors\n*/\n\n// NoError asserts that a function returned no error (i.e. `nil`).\n//\n//   actualObj, err := SomeFunction()\n//   if assert.NoError(t, err) {\n//\t   assert.Equal(t, expectedObj, actualObj)\n//   }\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NoError(t TestingT, err error, msgAndArgs ...interface{}) bool {\n\tif err != nil {\n\t\treturn Fail(t, fmt.Sprintf(\"Received unexpected error:\\n%+v\", err), msgAndArgs...)\n\t}\n\n\treturn true\n}\n\n// Error asserts that a function returned an error (i.e. not `nil`).\n//\n//   actualObj, err := SomeFunction()\n//   if assert.Error(t, err) {\n//\t   assert.Equal(t, expectedError, err)\n//   }\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Error(t TestingT, err error, msgAndArgs ...interface{}) bool {\n\n\tif err == nil {\n\t\treturn Fail(t, \"An error is expected but got nil.\", msgAndArgs...)\n\t}\n\n\treturn true\n}\n\n// EqualError asserts that a function returned an error (i.e. not `nil`)\n// and that it is equal to the provided error.\n//\n//   actualObj, err := SomeFunction()\n//   assert.EqualError(t, err,  expectedErrorString)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) bool {\n\tif !Error(t, theError, msgAndArgs...) {\n\t\treturn false\n\t}\n\texpected := errString\n\tactual := theError.Error()\n\t// don't need to use deep equals here, we know they are both strings\n\tif expected != actual {\n\t\treturn Fail(t, fmt.Sprintf(\"Error message not equal:\\n\"+\n\t\t\t\"expected: %q\\n\"+\n\t\t\t\"actual: %q\", expected, actual), msgAndArgs...)\n\t}\n\treturn true\n}\n\n// matchRegexp return true if a specified regexp matches a string.\nfunc matchRegexp(rx interface{}, str interface{}) bool {\n\n\tvar r *regexp.Regexp\n\tif rr, ok := rx.(*regexp.Regexp); ok {\n\t\tr = rr\n\t} else {\n\t\tr = regexp.MustCompile(fmt.Sprint(rx))\n\t}\n\n\treturn (r.FindStringIndex(fmt.Sprint(str)) != nil)\n\n}\n\n// Regexp asserts that a specified regexp matches a string.\n//\n//  assert.Regexp(t, regexp.MustCompile(\"start\"), \"it's starting\")\n//  assert.Regexp(t, \"start...$\", \"it's not starting\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {\n\n\tmatch := matchRegexp(rx, str)\n\n\tif !match {\n\t\tFail(t, fmt.Sprintf(\"Expect \\\"%v\\\" to match \\\"%v\\\"\", str, rx), msgAndArgs...)\n\t}\n\n\treturn match\n}\n\n// NotRegexp asserts that a specified regexp does not match a string.\n//\n//  assert.NotRegexp(t, regexp.MustCompile(\"starts\"), \"it's starting\")\n//  assert.NotRegexp(t, \"^start\", \"it's not starting\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {\n\tmatch := matchRegexp(rx, str)\n\n\tif match {\n\t\tFail(t, fmt.Sprintf(\"Expect \\\"%v\\\" to NOT match \\\"%v\\\"\", str, rx), msgAndArgs...)\n\t}\n\n\treturn !match\n\n}\n\n// Zero asserts that i is the zero value for its type and returns the truth.\nfunc Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool {\n\tif i != nil && !reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) {\n\t\treturn Fail(t, fmt.Sprintf(\"Should be zero, but was %v\", i), msgAndArgs...)\n\t}\n\treturn true\n}\n\n// NotZero asserts that i is not the zero value for its type and returns the truth.\nfunc NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool {\n\tif i == nil || reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) {\n\t\treturn Fail(t, fmt.Sprintf(\"Should not be zero, but was %v\", i), msgAndArgs...)\n\t}\n\treturn true\n}\n\n// JSONEq asserts that two JSON strings are equivalent.\n//\n//  assert.JSONEq(t, `{\"hello\": \"world\", \"foo\": \"bar\"}`, `{\"foo\": \"bar\", \"hello\": \"world\"}`)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool {\n\tvar expectedJSONAsInterface, actualJSONAsInterface interface{}\n\n\tif err := json.Unmarshal([]byte(expected), &expectedJSONAsInterface); err != nil {\n\t\treturn Fail(t, fmt.Sprintf(\"Expected value ('%s') is not valid json.\\nJSON parsing error: '%s'\", expected, err.Error()), msgAndArgs...)\n\t}\n\n\tif err := json.Unmarshal([]byte(actual), &actualJSONAsInterface); err != nil {\n\t\treturn Fail(t, fmt.Sprintf(\"Input ('%s') needs to be valid json.\\nJSON parsing error: '%s'\", actual, err.Error()), msgAndArgs...)\n\t}\n\n\treturn Equal(t, expectedJSONAsInterface, actualJSONAsInterface, msgAndArgs...)\n}\n\nfunc typeAndKind(v interface{}) (reflect.Type, reflect.Kind) {\n\tt := reflect.TypeOf(v)\n\tk := t.Kind()\n\n\tif k == reflect.Ptr {\n\t\tt = t.Elem()\n\t\tk = t.Kind()\n\t}\n\treturn t, k\n}\n\n// diff returns a diff of both values as long as both are of the same type and\n// are a struct, map, slice or array. Otherwise it returns an empty string.\nfunc diff(expected interface{}, actual interface{}) string {\n\tif expected == nil || actual == nil {\n\t\treturn \"\"\n\t}\n\n\tet, ek := typeAndKind(expected)\n\tat, _ := typeAndKind(actual)\n\n\tif et != at {\n\t\treturn \"\"\n\t}\n\n\tif ek != reflect.Struct && ek != reflect.Map && ek != reflect.Slice && ek != reflect.Array {\n\t\treturn \"\"\n\t}\n\n\te := spewConfig.Sdump(expected)\n\ta := spewConfig.Sdump(actual)\n\n\tdiff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{\n\t\tA:        difflib.SplitLines(e),\n\t\tB:        difflib.SplitLines(a),\n\t\tFromFile: \"Expected\",\n\t\tFromDate: \"\",\n\t\tToFile:   \"Actual\",\n\t\tToDate:   \"\",\n\t\tContext:  1,\n\t})\n\n\treturn \"\\n\\nDiff:\\n\" + diff\n}\n\n// validateEqualArgs checks whether provided arguments can be safely used in the\n// Equal/NotEqual functions.\nfunc validateEqualArgs(expected, actual interface{}) error {\n\tif isFunction(expected) || isFunction(actual) {\n\t\treturn errors.New(\"cannot take func type as argument\")\n\t}\n\treturn nil\n}\n\nfunc isFunction(arg interface{}) bool {\n\tif arg == nil {\n\t\treturn false\n\t}\n\treturn reflect.TypeOf(arg).Kind() == reflect.Func\n}\n\nvar spewConfig = spew.ConfigState{\n\tIndent:                  \" \",\n\tDisablePointerAddresses: true,\n\tDisableCapacities:       true,\n\tSortKeys:                true,\n}\n"
  },
  {
    "path": "vendor/github.com/stretchr/testify/assert/doc.go",
    "content": "// Package assert provides a set of comprehensive testing tools for use with the normal Go testing system.\n//\n// Example Usage\n//\n// The following is a complete example using assert in a standard test function:\n//    import (\n//      \"testing\"\n//      \"github.com/stretchr/testify/assert\"\n//    )\n//\n//    func TestSomething(t *testing.T) {\n//\n//      var a string = \"Hello\"\n//      var b string = \"Hello\"\n//\n//      assert.Equal(t, a, b, \"The two words should be the same.\")\n//\n//    }\n//\n// if you assert many times, use the format below:\n//\n//    import (\n//      \"testing\"\n//      \"github.com/stretchr/testify/assert\"\n//    )\n//\n//    func TestSomething(t *testing.T) {\n//      assert := assert.New(t)\n//\n//      var a string = \"Hello\"\n//      var b string = \"Hello\"\n//\n//      assert.Equal(a, b, \"The two words should be the same.\")\n//    }\n//\n// Assertions\n//\n// Assertions allow you to easily write test code, and are global funcs in the `assert` package.\n// All assertion functions take, as the first argument, the `*testing.T` object provided by the\n// testing framework. This allows the assertion funcs to write the failings and other details to\n// the correct place.\n//\n// Every assertion function also takes an optional string message as the final argument,\n// allowing custom error messages to be appended to the message the assertion method outputs.\npackage assert\n"
  },
  {
    "path": "vendor/github.com/stretchr/testify/assert/errors.go",
    "content": "package assert\n\nimport (\n\t\"errors\"\n)\n\n// AnError is an error instance useful for testing.  If the code does not care\n// about error specifics, and only needs to return the error for example, this\n// error should be used to make the test code more readable.\nvar AnError = errors.New(\"assert.AnError general error for testing\")\n"
  },
  {
    "path": "vendor/github.com/stretchr/testify/assert/forward_assertions.go",
    "content": "package assert\n\n// Assertions provides assertion methods around the\n// TestingT interface.\ntype Assertions struct {\n\tt TestingT\n}\n\n// New makes a new Assertions object for the specified TestingT.\nfunc New(t TestingT) *Assertions {\n\treturn &Assertions{\n\t\tt: t,\n\t}\n}\n\n//go:generate go run ../_codegen/main.go -output-package=assert -template=assertion_forward.go.tmpl -include-format-funcs\n"
  },
  {
    "path": "vendor/github.com/stretchr/testify/assert/http_assertions.go",
    "content": "package assert\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"strings\"\n)\n\n// httpCode is a helper that returns HTTP code of the response. It returns -1 and\n// an error if building a new request fails.\nfunc httpCode(handler http.HandlerFunc, method, url string, values url.Values) (int, error) {\n\tw := httptest.NewRecorder()\n\treq, err := http.NewRequest(method, url+\"?\"+values.Encode(), nil)\n\tif err != nil {\n\t\treturn -1, err\n\t}\n\thandler(w, req)\n\treturn w.Code, nil\n}\n\n// HTTPSuccess asserts that a specified handler returns a success status code.\n//\n//  assert.HTTPSuccess(t, myHandler, \"POST\", \"http://www.google.com\", nil)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, values url.Values) bool {\n\tcode, err := httpCode(handler, method, url, values)\n\tif err != nil {\n\t\tFail(t, fmt.Sprintf(\"Failed to build test request, got error: %s\", err))\n\t\treturn false\n\t}\n\n\tisSuccessCode := code >= http.StatusOK && code <= http.StatusPartialContent\n\tif !isSuccessCode {\n\t\tFail(t, fmt.Sprintf(\"Expected HTTP success status code for %q but received %d\", url+\"?\"+values.Encode(), code))\n\t}\n\n\treturn isSuccessCode\n}\n\n// HTTPRedirect asserts that a specified handler returns a redirect status code.\n//\n//  assert.HTTPRedirect(t, myHandler, \"GET\", \"/a/b/c\", url.Values{\"a\": []string{\"b\", \"c\"}}\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, values url.Values) bool {\n\tcode, err := httpCode(handler, method, url, values)\n\tif err != nil {\n\t\tFail(t, fmt.Sprintf(\"Failed to build test request, got error: %s\", err))\n\t\treturn false\n\t}\n\n\tisRedirectCode := code >= http.StatusMultipleChoices && code <= http.StatusTemporaryRedirect\n\tif !isRedirectCode {\n\t\tFail(t, fmt.Sprintf(\"Expected HTTP redirect status code for %q but received %d\", url+\"?\"+values.Encode(), code))\n\t}\n\n\treturn isRedirectCode\n}\n\n// HTTPError asserts that a specified handler returns an error status code.\n//\n//  assert.HTTPError(t, myHandler, \"POST\", \"/a/b/c\", url.Values{\"a\": []string{\"b\", \"c\"}}\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values url.Values) bool {\n\tcode, err := httpCode(handler, method, url, values)\n\tif err != nil {\n\t\tFail(t, fmt.Sprintf(\"Failed to build test request, got error: %s\", err))\n\t\treturn false\n\t}\n\n\tisErrorCode := code >= http.StatusBadRequest\n\tif !isErrorCode {\n\t\tFail(t, fmt.Sprintf(\"Expected HTTP error status code for %q but received %d\", url+\"?\"+values.Encode(), code))\n\t}\n\n\treturn isErrorCode\n}\n\n// HTTPBody is a helper that returns HTTP body of the response. It returns\n// empty string if building a new request fails.\nfunc HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) string {\n\tw := httptest.NewRecorder()\n\treq, err := http.NewRequest(method, url+\"?\"+values.Encode(), nil)\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\thandler(w, req)\n\treturn w.Body.String()\n}\n\n// HTTPBodyContains asserts that a specified handler returns a\n// body that contains a string.\n//\n//  assert.HTTPBodyContains(t, myHandler, \"www.google.com\", nil, \"I'm Feeling Lucky\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}) bool {\n\tbody := HTTPBody(handler, method, url, values)\n\n\tcontains := strings.Contains(body, fmt.Sprint(str))\n\tif !contains {\n\t\tFail(t, fmt.Sprintf(\"Expected response body for \\\"%s\\\" to contain \\\"%s\\\" but found \\\"%s\\\"\", url+\"?\"+values.Encode(), str, body))\n\t}\n\n\treturn contains\n}\n\n// HTTPBodyNotContains asserts that a specified handler returns a\n// body that does not contain a string.\n//\n//  assert.HTTPBodyNotContains(t, myHandler, \"www.google.com\", nil, \"I'm Feeling Lucky\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}) bool {\n\tbody := HTTPBody(handler, method, url, values)\n\n\tcontains := strings.Contains(body, fmt.Sprint(str))\n\tif contains {\n\t\tFail(t, fmt.Sprintf(\"Expected response body for \\\"%s\\\" to NOT contain \\\"%s\\\" but found \\\"%s\\\"\", url+\"?\"+values.Encode(), str, body))\n\t}\n\n\treturn !contains\n}\n"
  },
  {
    "path": "vendor/github.com/stretchr/testify/mock/doc.go",
    "content": "// Package mock provides a system by which it is possible to mock your objects\n// and verify calls are happening as expected.\n//\n// Example Usage\n//\n// The mock package provides an object, Mock, that tracks activity on another object.  It is usually\n// embedded into a test object as shown below:\n//\n//   type MyTestObject struct {\n//     // add a Mock object instance\n//     mock.Mock\n//\n//     // other fields go here as normal\n//   }\n//\n// When implementing the methods of an interface, you wire your functions up\n// to call the Mock.Called(args...) method, and return the appropriate values.\n//\n// For example, to mock a method that saves the name and age of a person and returns\n// the year of their birth or an error, you might write this:\n//\n//     func (o *MyTestObject) SavePersonDetails(firstname, lastname string, age int) (int, error) {\n//       args := o.Called(firstname, lastname, age)\n//       return args.Int(0), args.Error(1)\n//     }\n//\n// The Int, Error and Bool methods are examples of strongly typed getters that take the argument\n// index position. Given this argument list:\n//\n//     (12, true, \"Something\")\n//\n// You could read them out strongly typed like this:\n//\n//     args.Int(0)\n//     args.Bool(1)\n//     args.String(2)\n//\n// For objects of your own type, use the generic Arguments.Get(index) method and make a type assertion:\n//\n//     return args.Get(0).(*MyObject), args.Get(1).(*AnotherObjectOfMine)\n//\n// This may cause a panic if the object you are getting is nil (the type assertion will fail), in those\n// cases you should check for nil first.\npackage mock\n"
  },
  {
    "path": "vendor/github.com/stretchr/testify/mock/mock.go",
    "content": "package mock\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"regexp\"\n\t\"runtime\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/davecgh/go-spew/spew\"\n\t\"github.com/pmezard/go-difflib/difflib\"\n\t\"github.com/stretchr/objx\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\n// TestingT is an interface wrapper around *testing.T\ntype TestingT interface {\n\tLogf(format string, args ...interface{})\n\tErrorf(format string, args ...interface{})\n\tFailNow()\n}\n\n/*\n\tCall\n*/\n\n// Call represents a method call and is used for setting expectations,\n// as well as recording activity.\ntype Call struct {\n\tParent *Mock\n\n\t// The name of the method that was or will be called.\n\tMethod string\n\n\t// Holds the arguments of the method.\n\tArguments Arguments\n\n\t// Holds the arguments that should be returned when\n\t// this method is called.\n\tReturnArguments Arguments\n\n\t// The number of times to return the return arguments when setting\n\t// expectations. 0 means to always return the value.\n\tRepeatability int\n\n\t// Amount of times this call has been called\n\ttotalCalls int\n\n\t// Holds a channel that will be used to block the Return until it either\n\t// receives a message or is closed. nil means it returns immediately.\n\tWaitFor <-chan time.Time\n\n\t// Holds a handler used to manipulate arguments content that are passed by\n\t// reference. It's useful when mocking methods such as unmarshalers or\n\t// decoders.\n\tRunFn func(Arguments)\n}\n\nfunc newCall(parent *Mock, methodName string, methodArguments ...interface{}) *Call {\n\treturn &Call{\n\t\tParent:          parent,\n\t\tMethod:          methodName,\n\t\tArguments:       methodArguments,\n\t\tReturnArguments: make([]interface{}, 0),\n\t\tRepeatability:   0,\n\t\tWaitFor:         nil,\n\t\tRunFn:           nil,\n\t}\n}\n\nfunc (c *Call) lock() {\n\tc.Parent.mutex.Lock()\n}\n\nfunc (c *Call) unlock() {\n\tc.Parent.mutex.Unlock()\n}\n\n// Return specifies the return arguments for the expectation.\n//\n//    Mock.On(\"DoSomething\").Return(errors.New(\"failed\"))\nfunc (c *Call) Return(returnArguments ...interface{}) *Call {\n\tc.lock()\n\tdefer c.unlock()\n\n\tc.ReturnArguments = returnArguments\n\n\treturn c\n}\n\n// Once indicates that that the mock should only return the value once.\n//\n//    Mock.On(\"MyMethod\", arg1, arg2).Return(returnArg1, returnArg2).Once()\nfunc (c *Call) Once() *Call {\n\treturn c.Times(1)\n}\n\n// Twice indicates that that the mock should only return the value twice.\n//\n//    Mock.On(\"MyMethod\", arg1, arg2).Return(returnArg1, returnArg2).Twice()\nfunc (c *Call) Twice() *Call {\n\treturn c.Times(2)\n}\n\n// Times indicates that that the mock should only return the indicated number\n// of times.\n//\n//    Mock.On(\"MyMethod\", arg1, arg2).Return(returnArg1, returnArg2).Times(5)\nfunc (c *Call) Times(i int) *Call {\n\tc.lock()\n\tdefer c.unlock()\n\tc.Repeatability = i\n\treturn c\n}\n\n// WaitUntil sets the channel that will block the mock's return until its closed\n// or a message is received.\n//\n//    Mock.On(\"MyMethod\", arg1, arg2).WaitUntil(time.After(time.Second))\nfunc (c *Call) WaitUntil(w <-chan time.Time) *Call {\n\tc.lock()\n\tdefer c.unlock()\n\tc.WaitFor = w\n\treturn c\n}\n\n// After sets how long to block until the call returns\n//\n//    Mock.On(\"MyMethod\", arg1, arg2).After(time.Second)\nfunc (c *Call) After(d time.Duration) *Call {\n\treturn c.WaitUntil(time.After(d))\n}\n\n// Run sets a handler to be called before returning. It can be used when\n// mocking a method such as unmarshalers that takes a pointer to a struct and\n// sets properties in such struct\n//\n//    Mock.On(\"Unmarshal\", AnythingOfType(\"*map[string]interface{}\").Return().Run(func(args Arguments) {\n//    \targ := args.Get(0).(*map[string]interface{})\n//    \targ[\"foo\"] = \"bar\"\n//    })\nfunc (c *Call) Run(fn func(args Arguments)) *Call {\n\tc.lock()\n\tdefer c.unlock()\n\tc.RunFn = fn\n\treturn c\n}\n\n// On chains a new expectation description onto the mocked interface. This\n// allows syntax like.\n//\n//    Mock.\n//       On(\"MyMethod\", 1).Return(nil).\n//       On(\"MyOtherMethod\", 'a', 'b', 'c').Return(errors.New(\"Some Error\"))\nfunc (c *Call) On(methodName string, arguments ...interface{}) *Call {\n\treturn c.Parent.On(methodName, arguments...)\n}\n\n// Mock is the workhorse used to track activity on another object.\n// For an example of its usage, refer to the \"Example Usage\" section at the top\n// of this document.\ntype Mock struct {\n\t// Represents the calls that are expected of\n\t// an object.\n\tExpectedCalls []*Call\n\n\t// Holds the calls that were made to this mocked object.\n\tCalls []Call\n\n\t// TestData holds any data that might be useful for testing.  Testify ignores\n\t// this data completely allowing you to do whatever you like with it.\n\ttestData objx.Map\n\n\tmutex sync.Mutex\n}\n\n// TestData holds any data that might be useful for testing.  Testify ignores\n// this data completely allowing you to do whatever you like with it.\nfunc (m *Mock) TestData() objx.Map {\n\n\tif m.testData == nil {\n\t\tm.testData = make(objx.Map)\n\t}\n\n\treturn m.testData\n}\n\n/*\n\tSetting expectations\n*/\n\n// On starts a description of an expectation of the specified method\n// being called.\n//\n//     Mock.On(\"MyMethod\", arg1, arg2)\nfunc (m *Mock) On(methodName string, arguments ...interface{}) *Call {\n\tfor _, arg := range arguments {\n\t\tif v := reflect.ValueOf(arg); v.Kind() == reflect.Func {\n\t\t\tpanic(fmt.Sprintf(\"cannot use Func in expectations. Use mock.AnythingOfType(\\\"%T\\\")\", arg))\n\t\t}\n\t}\n\n\tm.mutex.Lock()\n\tdefer m.mutex.Unlock()\n\tc := newCall(m, methodName, arguments...)\n\tm.ExpectedCalls = append(m.ExpectedCalls, c)\n\treturn c\n}\n\n// /*\n// \tRecording and responding to activity\n// */\n\nfunc (m *Mock) findExpectedCall(method string, arguments ...interface{}) (int, *Call) {\n\tfor i, call := range m.ExpectedCalls {\n\t\tif call.Method == method && call.Repeatability > -1 {\n\n\t\t\t_, diffCount := call.Arguments.Diff(arguments)\n\t\t\tif diffCount == 0 {\n\t\t\t\treturn i, call\n\t\t\t}\n\n\t\t}\n\t}\n\treturn -1, nil\n}\n\nfunc (m *Mock) findClosestCall(method string, arguments ...interface{}) (bool, *Call) {\n\tdiffCount := 0\n\tvar closestCall *Call\n\n\tfor _, call := range m.expectedCalls() {\n\t\tif call.Method == method {\n\n\t\t\t_, tempDiffCount := call.Arguments.Diff(arguments)\n\t\t\tif tempDiffCount < diffCount || diffCount == 0 {\n\t\t\t\tdiffCount = tempDiffCount\n\t\t\t\tclosestCall = call\n\t\t\t}\n\n\t\t}\n\t}\n\n\tif closestCall == nil {\n\t\treturn false, nil\n\t}\n\n\treturn true, closestCall\n}\n\nfunc callString(method string, arguments Arguments, includeArgumentValues bool) string {\n\n\tvar argValsString string\n\tif includeArgumentValues {\n\t\tvar argVals []string\n\t\tfor argIndex, arg := range arguments {\n\t\t\targVals = append(argVals, fmt.Sprintf(\"%d: %#v\", argIndex, arg))\n\t\t}\n\t\targValsString = fmt.Sprintf(\"\\n\\t\\t%s\", strings.Join(argVals, \"\\n\\t\\t\"))\n\t}\n\n\treturn fmt.Sprintf(\"%s(%s)%s\", method, arguments.String(), argValsString)\n}\n\n// Called tells the mock object that a method has been called, and gets an array\n// of arguments to return.  Panics if the call is unexpected (i.e. not preceded by\n// appropriate .On .Return() calls)\n// If Call.WaitFor is set, blocks until the channel is closed or receives a message.\nfunc (m *Mock) Called(arguments ...interface{}) Arguments {\n\t// get the calling function's name\n\tpc, _, _, ok := runtime.Caller(1)\n\tif !ok {\n\t\tpanic(\"Couldn't get the caller information\")\n\t}\n\tfunctionPath := runtime.FuncForPC(pc).Name()\n\t//Next four lines are required to use GCCGO function naming conventions.\n\t//For Ex:  github_com_docker_libkv_store_mock.WatchTree.pN39_github_com_docker_libkv_store_mock.Mock\n\t//uses interface information unlike golang github.com/docker/libkv/store/mock.(*Mock).WatchTree\n\t//With GCCGO we need to remove interface information starting from pN<dd>.\n\tre := regexp.MustCompile(\"\\\\.pN\\\\d+_\")\n\tif re.MatchString(functionPath) {\n\t\tfunctionPath = re.Split(functionPath, -1)[0]\n\t}\n\tparts := strings.Split(functionPath, \".\")\n\tfunctionName := parts[len(parts)-1]\n\treturn m.MethodCalled(functionName, arguments...)\n}\n\n// MethodCalled tells the mock object that the given method has been called, and gets\n// an array of arguments to return. Panics if the call is unexpected (i.e. not preceded\n// by appropriate .On .Return() calls)\n// If Call.WaitFor is set, blocks until the channel is closed or receives a message.\nfunc (m *Mock) MethodCalled(methodName string, arguments ...interface{}) Arguments {\n\tm.mutex.Lock()\n\tfound, call := m.findExpectedCall(methodName, arguments...)\n\n\tif found < 0 {\n\t\t// we have to fail here - because we don't know what to do\n\t\t// as the return arguments.  This is because:\n\t\t//\n\t\t//   a) this is a totally unexpected call to this method,\n\t\t//   b) the arguments are not what was expected, or\n\t\t//   c) the developer has forgotten to add an accompanying On...Return pair.\n\n\t\tclosestFound, closestCall := m.findClosestCall(methodName, arguments...)\n\t\tm.mutex.Unlock()\n\n\t\tif closestFound {\n\t\t\tpanic(fmt.Sprintf(\"\\n\\nmock: Unexpected Method Call\\n-----------------------------\\n\\n%s\\n\\nThe closest call I have is: \\n\\n%s\\n\\n%s\\n\", callString(methodName, arguments, true), callString(methodName, closestCall.Arguments, true), diffArguments(arguments, closestCall.Arguments)))\n\t\t} else {\n\t\t\tpanic(fmt.Sprintf(\"\\nassert: mock: I don't know what to return because the method call was unexpected.\\n\\tEither do Mock.On(\\\"%s\\\").Return(...) first, or remove the %s() call.\\n\\tThis method was unexpected:\\n\\t\\t%s\\n\\tat: %s\", methodName, methodName, callString(methodName, arguments, true), assert.CallerInfo()))\n\t\t}\n\t}\n\n\tswitch {\n\tcase call.Repeatability == 1:\n\t\tcall.Repeatability = -1\n\t\tcall.totalCalls++\n\n\tcase call.Repeatability > 1:\n\t\tcall.Repeatability--\n\t\tcall.totalCalls++\n\n\tcase call.Repeatability == 0:\n\t\tcall.totalCalls++\n\t}\n\n\t// add the call\n\tm.Calls = append(m.Calls, *newCall(m, methodName, arguments...))\n\tm.mutex.Unlock()\n\n\t// block if specified\n\tif call.WaitFor != nil {\n\t\t<-call.WaitFor\n\t}\n\n\tm.mutex.Lock()\n\trunFn := call.RunFn\n\tm.mutex.Unlock()\n\n\tif runFn != nil {\n\t\trunFn(arguments)\n\t}\n\n\tm.mutex.Lock()\n\treturnArgs := call.ReturnArguments\n\tm.mutex.Unlock()\n\n\treturn returnArgs\n}\n\n/*\n\tAssertions\n*/\n\ntype assertExpectationser interface {\n\tAssertExpectations(TestingT) bool\n}\n\n// AssertExpectationsForObjects asserts that everything specified with On and Return\n// of the specified objects was in fact called as expected.\n//\n// Calls may have occurred in any order.\nfunc AssertExpectationsForObjects(t TestingT, testObjects ...interface{}) bool {\n\tfor _, obj := range testObjects {\n\t\tif m, ok := obj.(Mock); ok {\n\t\t\tt.Logf(\"Deprecated mock.AssertExpectationsForObjects(myMock.Mock) use mock.AssertExpectationsForObjects(myMock)\")\n\t\t\tobj = &m\n\t\t}\n\t\tm := obj.(assertExpectationser)\n\t\tif !m.AssertExpectations(t) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// AssertExpectations asserts that everything specified with On and Return was\n// in fact called as expected.  Calls may have occurred in any order.\nfunc (m *Mock) AssertExpectations(t TestingT) bool {\n\tm.mutex.Lock()\n\tdefer m.mutex.Unlock()\n\tvar somethingMissing bool\n\tvar failedExpectations int\n\n\t// iterate through each expectation\n\texpectedCalls := m.expectedCalls()\n\tfor _, expectedCall := range expectedCalls {\n\t\tif !m.methodWasCalled(expectedCall.Method, expectedCall.Arguments) && expectedCall.totalCalls == 0 {\n\t\t\tsomethingMissing = true\n\t\t\tfailedExpectations++\n\t\t\tt.Logf(\"\\u274C\\t%s(%s)\", expectedCall.Method, expectedCall.Arguments.String())\n\t\t} else {\n\t\t\tif expectedCall.Repeatability > 0 {\n\t\t\t\tsomethingMissing = true\n\t\t\t\tfailedExpectations++\n\t\t\t} else {\n\t\t\t\tt.Logf(\"\\u2705\\t%s(%s)\", expectedCall.Method, expectedCall.Arguments.String())\n\t\t\t}\n\t\t}\n\t}\n\n\tif somethingMissing {\n\t\tt.Errorf(\"FAIL: %d out of %d expectation(s) were met.\\n\\tThe code you are testing needs to make %d more call(s).\\n\\tat: %s\", len(expectedCalls)-failedExpectations, len(expectedCalls), failedExpectations, assert.CallerInfo())\n\t}\n\n\treturn !somethingMissing\n}\n\n// AssertNumberOfCalls asserts that the method was called expectedCalls times.\nfunc (m *Mock) AssertNumberOfCalls(t TestingT, methodName string, expectedCalls int) bool {\n\tm.mutex.Lock()\n\tdefer m.mutex.Unlock()\n\tvar actualCalls int\n\tfor _, call := range m.calls() {\n\t\tif call.Method == methodName {\n\t\t\tactualCalls++\n\t\t}\n\t}\n\treturn assert.Equal(t, expectedCalls, actualCalls, fmt.Sprintf(\"Expected number of calls (%d) does not match the actual number of calls (%d).\", expectedCalls, actualCalls))\n}\n\n// AssertCalled asserts that the method was called.\n// It can produce a false result when an argument is a pointer type and the underlying value changed after calling the mocked method.\nfunc (m *Mock) AssertCalled(t TestingT, methodName string, arguments ...interface{}) bool {\n\tm.mutex.Lock()\n\tdefer m.mutex.Unlock()\n\tif !assert.True(t, m.methodWasCalled(methodName, arguments), fmt.Sprintf(\"The \\\"%s\\\" method should have been called with %d argument(s), but was not.\", methodName, len(arguments))) {\n\t\tt.Logf(\"%v\", m.expectedCalls())\n\t\treturn false\n\t}\n\treturn true\n}\n\n// AssertNotCalled asserts that the method was not called.\n// It can produce a false result when an argument is a pointer type and the underlying value changed after calling the mocked method.\nfunc (m *Mock) AssertNotCalled(t TestingT, methodName string, arguments ...interface{}) bool {\n\tm.mutex.Lock()\n\tdefer m.mutex.Unlock()\n\tif !assert.False(t, m.methodWasCalled(methodName, arguments), fmt.Sprintf(\"The \\\"%s\\\" method was called with %d argument(s), but should NOT have been.\", methodName, len(arguments))) {\n\t\tt.Logf(\"%v\", m.expectedCalls())\n\t\treturn false\n\t}\n\treturn true\n}\n\nfunc (m *Mock) methodWasCalled(methodName string, expected []interface{}) bool {\n\tfor _, call := range m.calls() {\n\t\tif call.Method == methodName {\n\n\t\t\t_, differences := Arguments(expected).Diff(call.Arguments)\n\n\t\t\tif differences == 0 {\n\t\t\t\t// found the expected call\n\t\t\t\treturn true\n\t\t\t}\n\n\t\t}\n\t}\n\t// we didn't find the expected call\n\treturn false\n}\n\nfunc (m *Mock) expectedCalls() []*Call {\n\treturn append([]*Call{}, m.ExpectedCalls...)\n}\n\nfunc (m *Mock) calls() []Call {\n\treturn append([]Call{}, m.Calls...)\n}\n\n/*\n\tArguments\n*/\n\n// Arguments holds an array of method arguments or return values.\ntype Arguments []interface{}\n\nconst (\n\t// Anything is used in Diff and Assert when the argument being tested\n\t// shouldn't be taken into consideration.\n\tAnything string = \"mock.Anything\"\n)\n\n// AnythingOfTypeArgument is a string that contains the type of an argument\n// for use when type checking.  Used in Diff and Assert.\ntype AnythingOfTypeArgument string\n\n// AnythingOfType returns an AnythingOfTypeArgument object containing the\n// name of the type to check for.  Used in Diff and Assert.\n//\n// For example:\n//\tAssert(t, AnythingOfType(\"string\"), AnythingOfType(\"int\"))\nfunc AnythingOfType(t string) AnythingOfTypeArgument {\n\treturn AnythingOfTypeArgument(t)\n}\n\n// argumentMatcher performs custom argument matching, returning whether or\n// not the argument is matched by the expectation fixture function.\ntype argumentMatcher struct {\n\t// fn is a function which accepts one argument, and returns a bool.\n\tfn reflect.Value\n}\n\nfunc (f argumentMatcher) Matches(argument interface{}) bool {\n\texpectType := f.fn.Type().In(0)\n\n\tif reflect.TypeOf(argument).AssignableTo(expectType) {\n\t\tresult := f.fn.Call([]reflect.Value{reflect.ValueOf(argument)})\n\t\treturn result[0].Bool()\n\t}\n\treturn false\n}\n\nfunc (f argumentMatcher) String() string {\n\treturn fmt.Sprintf(\"func(%s) bool\", f.fn.Type().In(0).Name())\n}\n\n// MatchedBy can be used to match a mock call based on only certain properties\n// from a complex struct or some calculation. It takes a function that will be\n// evaluated with the called argument and will return true when there's a match\n// and false otherwise.\n//\n// Example:\n// m.On(\"Do\", MatchedBy(func(req *http.Request) bool { return req.Host == \"example.com\" }))\n//\n// |fn|, must be a function accepting a single argument (of the expected type)\n// which returns a bool. If |fn| doesn't match the required signature,\n// MatchedBy() panics.\nfunc MatchedBy(fn interface{}) argumentMatcher {\n\tfnType := reflect.TypeOf(fn)\n\n\tif fnType.Kind() != reflect.Func {\n\t\tpanic(fmt.Sprintf(\"assert: arguments: %s is not a func\", fn))\n\t}\n\tif fnType.NumIn() != 1 {\n\t\tpanic(fmt.Sprintf(\"assert: arguments: %s does not take exactly one argument\", fn))\n\t}\n\tif fnType.NumOut() != 1 || fnType.Out(0).Kind() != reflect.Bool {\n\t\tpanic(fmt.Sprintf(\"assert: arguments: %s does not return a bool\", fn))\n\t}\n\n\treturn argumentMatcher{fn: reflect.ValueOf(fn)}\n}\n\n// Get Returns the argument at the specified index.\nfunc (args Arguments) Get(index int) interface{} {\n\tif index+1 > len(args) {\n\t\tpanic(fmt.Sprintf(\"assert: arguments: Cannot call Get(%d) because there are %d argument(s).\", index, len(args)))\n\t}\n\treturn args[index]\n}\n\n// Is gets whether the objects match the arguments specified.\nfunc (args Arguments) Is(objects ...interface{}) bool {\n\tfor i, obj := range args {\n\t\tif obj != objects[i] {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// Diff gets a string describing the differences between the arguments\n// and the specified objects.\n//\n// Returns the diff string and number of differences found.\nfunc (args Arguments) Diff(objects []interface{}) (string, int) {\n\n\tvar output = \"\\n\"\n\tvar differences int\n\n\tvar maxArgCount = len(args)\n\tif len(objects) > maxArgCount {\n\t\tmaxArgCount = len(objects)\n\t}\n\n\tfor i := 0; i < maxArgCount; i++ {\n\t\tvar actual, expected interface{}\n\n\t\tif len(objects) <= i {\n\t\t\tactual = \"(Missing)\"\n\t\t} else {\n\t\t\tactual = objects[i]\n\t\t}\n\n\t\tif len(args) <= i {\n\t\t\texpected = \"(Missing)\"\n\t\t} else {\n\t\t\texpected = args[i]\n\t\t}\n\n\t\tif matcher, ok := expected.(argumentMatcher); ok {\n\t\t\tif matcher.Matches(actual) {\n\t\t\t\toutput = fmt.Sprintf(\"%s\\t%d: \\u2705  %s matched by %s\\n\", output, i, actual, matcher)\n\t\t\t} else {\n\t\t\t\tdifferences++\n\t\t\t\toutput = fmt.Sprintf(\"%s\\t%d: \\u2705  %s not matched by %s\\n\", output, i, actual, matcher)\n\t\t\t}\n\t\t} else if reflect.TypeOf(expected) == reflect.TypeOf((*AnythingOfTypeArgument)(nil)).Elem() {\n\n\t\t\t// type checking\n\t\t\tif reflect.TypeOf(actual).Name() != string(expected.(AnythingOfTypeArgument)) && reflect.TypeOf(actual).String() != string(expected.(AnythingOfTypeArgument)) {\n\t\t\t\t// not match\n\t\t\t\tdifferences++\n\t\t\t\toutput = fmt.Sprintf(\"%s\\t%d: \\u274C  type %s != type %s - %s\\n\", output, i, expected, reflect.TypeOf(actual).Name(), actual)\n\t\t\t}\n\n\t\t} else {\n\n\t\t\t// normal checking\n\n\t\t\tif assert.ObjectsAreEqual(expected, Anything) || assert.ObjectsAreEqual(actual, Anything) || assert.ObjectsAreEqual(actual, expected) {\n\t\t\t\t// match\n\t\t\t\toutput = fmt.Sprintf(\"%s\\t%d: \\u2705  %s == %s\\n\", output, i, actual, expected)\n\t\t\t} else {\n\t\t\t\t// not match\n\t\t\t\tdifferences++\n\t\t\t\toutput = fmt.Sprintf(\"%s\\t%d: \\u274C  %s != %s\\n\", output, i, actual, expected)\n\t\t\t}\n\t\t}\n\n\t}\n\n\tif differences == 0 {\n\t\treturn \"No differences.\", differences\n\t}\n\n\treturn output, differences\n\n}\n\n// Assert compares the arguments with the specified objects and fails if\n// they do not exactly match.\nfunc (args Arguments) Assert(t TestingT, objects ...interface{}) bool {\n\n\t// get the differences\n\tdiff, diffCount := args.Diff(objects)\n\n\tif diffCount == 0 {\n\t\treturn true\n\t}\n\n\t// there are differences... report them...\n\tt.Logf(diff)\n\tt.Errorf(\"%sArguments do not match.\", assert.CallerInfo())\n\n\treturn false\n\n}\n\n// String gets the argument at the specified index. Panics if there is no argument, or\n// if the argument is of the wrong type.\n//\n// If no index is provided, String() returns a complete string representation\n// of the arguments.\nfunc (args Arguments) String(indexOrNil ...int) string {\n\n\tif len(indexOrNil) == 0 {\n\t\t// normal String() method - return a string representation of the args\n\t\tvar argsStr []string\n\t\tfor _, arg := range args {\n\t\t\targsStr = append(argsStr, fmt.Sprintf(\"%s\", reflect.TypeOf(arg)))\n\t\t}\n\t\treturn strings.Join(argsStr, \",\")\n\t} else if len(indexOrNil) == 1 {\n\t\t// Index has been specified - get the argument at that index\n\t\tvar index = indexOrNil[0]\n\t\tvar s string\n\t\tvar ok bool\n\t\tif s, ok = args.Get(index).(string); !ok {\n\t\t\tpanic(fmt.Sprintf(\"assert: arguments: String(%d) failed because object wasn't correct type: %s\", index, args.Get(index)))\n\t\t}\n\t\treturn s\n\t}\n\n\tpanic(fmt.Sprintf(\"assert: arguments: Wrong number of arguments passed to String.  Must be 0 or 1, not %d\", len(indexOrNil)))\n\n}\n\n// Int gets the argument at the specified index. Panics if there is no argument, or\n// if the argument is of the wrong type.\nfunc (args Arguments) Int(index int) int {\n\tvar s int\n\tvar ok bool\n\tif s, ok = args.Get(index).(int); !ok {\n\t\tpanic(fmt.Sprintf(\"assert: arguments: Int(%d) failed because object wasn't correct type: %v\", index, args.Get(index)))\n\t}\n\treturn s\n}\n\n// Error gets the argument at the specified index. Panics if there is no argument, or\n// if the argument is of the wrong type.\nfunc (args Arguments) Error(index int) error {\n\tobj := args.Get(index)\n\tvar s error\n\tvar ok bool\n\tif obj == nil {\n\t\treturn nil\n\t}\n\tif s, ok = obj.(error); !ok {\n\t\tpanic(fmt.Sprintf(\"assert: arguments: Error(%d) failed because object wasn't correct type: %v\", index, args.Get(index)))\n\t}\n\treturn s\n}\n\n// Bool gets the argument at the specified index. Panics if there is no argument, or\n// if the argument is of the wrong type.\nfunc (args Arguments) Bool(index int) bool {\n\tvar s bool\n\tvar ok bool\n\tif s, ok = args.Get(index).(bool); !ok {\n\t\tpanic(fmt.Sprintf(\"assert: arguments: Bool(%d) failed because object wasn't correct type: %v\", index, args.Get(index)))\n\t}\n\treturn s\n}\n\nfunc typeAndKind(v interface{}) (reflect.Type, reflect.Kind) {\n\tt := reflect.TypeOf(v)\n\tk := t.Kind()\n\n\tif k == reflect.Ptr {\n\t\tt = t.Elem()\n\t\tk = t.Kind()\n\t}\n\treturn t, k\n}\n\nfunc diffArguments(expected Arguments, actual Arguments) string {\n\tif len(expected) != len(actual) {\n\t\treturn fmt.Sprintf(\"Provided %v arguments, mocked for %v arguments\", len(expected), len(actual))\n\t}\n\n\tfor x := range expected {\n\t\tif diffString := diff(expected[x], actual[x]); diffString != \"\" {\n\t\t\treturn fmt.Sprintf(\"Difference found in argument %v:\\n\\n%s\", x, diffString)\n\t\t}\n\t}\n\n\treturn \"\"\n}\n\n// diff returns a diff of both values as long as both are of the same type and\n// are a struct, map, slice or array. Otherwise it returns an empty string.\nfunc diff(expected interface{}, actual interface{}) string {\n\tif expected == nil || actual == nil {\n\t\treturn \"\"\n\t}\n\n\tet, ek := typeAndKind(expected)\n\tat, _ := typeAndKind(actual)\n\n\tif et != at {\n\t\treturn \"\"\n\t}\n\n\tif ek != reflect.Struct && ek != reflect.Map && ek != reflect.Slice && ek != reflect.Array {\n\t\treturn \"\"\n\t}\n\n\te := spewConfig.Sdump(expected)\n\ta := spewConfig.Sdump(actual)\n\n\tdiff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{\n\t\tA:        difflib.SplitLines(e),\n\t\tB:        difflib.SplitLines(a),\n\t\tFromFile: \"Expected\",\n\t\tFromDate: \"\",\n\t\tToFile:   \"Actual\",\n\t\tToDate:   \"\",\n\t\tContext:  1,\n\t})\n\n\treturn diff\n}\n\nvar spewConfig = spew.ConfigState{\n\tIndent:                  \" \",\n\tDisablePointerAddresses: true,\n\tDisableCapacities:       true,\n\tSortKeys:                true,\n}\n"
  },
  {
    "path": "vendor/github.com/stretchr/testify/require/doc.go",
    "content": "// Package require implements the same assertions as the `assert` package but\n// stops test execution when a test fails.\n//\n// Example Usage\n//\n// The following is a complete example using require in a standard test function:\n//    import (\n//      \"testing\"\n//      \"github.com/stretchr/testify/require\"\n//    )\n//\n//    func TestSomething(t *testing.T) {\n//\n//      var a string = \"Hello\"\n//      var b string = \"Hello\"\n//\n//      require.Equal(t, a, b, \"The two words should be the same.\")\n//\n//    }\n//\n// Assertions\n//\n// The `require` package have same global functions as in the `assert` package,\n// but instead of returning a boolean result they call `t.FailNow()`.\n//\n// Every assertion function also takes an optional string message as the final argument,\n// allowing custom error messages to be appended to the message the assertion method outputs.\npackage require\n"
  },
  {
    "path": "vendor/github.com/stretchr/testify/require/forward_requirements.go",
    "content": "package require\n\n// Assertions provides assertion methods around the\n// TestingT interface.\ntype Assertions struct {\n\tt TestingT\n}\n\n// New makes a new Assertions object for the specified TestingT.\nfunc New(t TestingT) *Assertions {\n\treturn &Assertions{\n\t\tt: t,\n\t}\n}\n\n//go:generate go run ../_codegen/main.go -output-package=require -template=require_forward.go.tmpl -include-format-funcs\n"
  },
  {
    "path": "vendor/github.com/stretchr/testify/require/require.go",
    "content": "/*\n* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen\n* THIS FILE MUST NOT BE EDITED BY HAND\n */\n\npackage require\n\nimport (\n\tassert \"github.com/stretchr/testify/assert\"\n\thttp \"net/http\"\n\turl \"net/url\"\n\ttime \"time\"\n)\n\n// Condition uses a Comparison to assert a complex condition.\nfunc Condition(t TestingT, comp assert.Comparison, msgAndArgs ...interface{}) {\n\tif !assert.Condition(t, comp, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// Conditionf uses a Comparison to assert a complex condition.\nfunc Conditionf(t TestingT, comp assert.Comparison, msg string, args ...interface{}) {\n\tif !assert.Conditionf(t, comp, msg, args...) {\n\t\tt.FailNow()\n\t}\n}\n\n// Contains asserts that the specified string, list(array, slice...) or map contains the\n// specified substring or element.\n//\n//    assert.Contains(t, \"Hello World\", \"World\")\n//    assert.Contains(t, [\"Hello\", \"World\"], \"World\")\n//    assert.Contains(t, {\"Hello\": \"World\"}, \"Hello\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Contains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...interface{}) {\n\tif !assert.Contains(t, s, contains, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// Containsf asserts that the specified string, list(array, slice...) or map contains the\n// specified substring or element.\n//\n//    assert.Containsf(t, \"Hello World\", \"World\", \"error message %s\", \"formatted\")\n//    assert.Containsf(t, [\"Hello\", \"World\"], \"World\", \"error message %s\", \"formatted\")\n//    assert.Containsf(t, {\"Hello\": \"World\"}, \"Hello\", \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Containsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) {\n\tif !assert.Containsf(t, s, contains, msg, args...) {\n\t\tt.FailNow()\n\t}\n}\n\n// Empty asserts that the specified object is empty.  I.e. nil, \"\", false, 0 or either\n// a slice or a channel with len == 0.\n//\n//  assert.Empty(t, obj)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) {\n\tif !assert.Empty(t, object, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// Emptyf asserts that the specified object is empty.  I.e. nil, \"\", false, 0 or either\n// a slice or a channel with len == 0.\n//\n//  assert.Emptyf(t, obj, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) {\n\tif !assert.Emptyf(t, object, msg, args...) {\n\t\tt.FailNow()\n\t}\n}\n\n// Equal asserts that two objects are equal.\n//\n//    assert.Equal(t, 123, 123)\n//\n// Returns whether the assertion was successful (true) or not (false).\n//\n// Pointer variable equality is determined based on the equality of the\n// referenced values (as opposed to the memory addresses). Function equality\n// cannot be determined and will always fail.\nfunc Equal(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {\n\tif !assert.Equal(t, expected, actual, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// EqualError asserts that a function returned an error (i.e. not `nil`)\n// and that it is equal to the provided error.\n//\n//   actualObj, err := SomeFunction()\n//   assert.EqualError(t, err,  expectedErrorString)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) {\n\tif !assert.EqualError(t, theError, errString, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// EqualErrorf asserts that a function returned an error (i.e. not `nil`)\n// and that it is equal to the provided error.\n//\n//   actualObj, err := SomeFunction()\n//   assert.EqualErrorf(t, err,  expectedErrorString, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc EqualErrorf(t TestingT, theError error, errString string, msg string, args ...interface{}) {\n\tif !assert.EqualErrorf(t, theError, errString, msg, args...) {\n\t\tt.FailNow()\n\t}\n}\n\n// EqualValues asserts that two objects are equal or convertable to the same types\n// and equal.\n//\n//    assert.EqualValues(t, uint32(123), int32(123))\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc EqualValues(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {\n\tif !assert.EqualValues(t, expected, actual, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// EqualValuesf asserts that two objects are equal or convertable to the same types\n// and equal.\n//\n//    assert.EqualValuesf(t, uint32(123, \"error message %s\", \"formatted\"), int32(123))\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {\n\tif !assert.EqualValuesf(t, expected, actual, msg, args...) {\n\t\tt.FailNow()\n\t}\n}\n\n// Equalf asserts that two objects are equal.\n//\n//    assert.Equalf(t, 123, 123, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\n//\n// Pointer variable equality is determined based on the equality of the\n// referenced values (as opposed to the memory addresses). Function equality\n// cannot be determined and will always fail.\nfunc Equalf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {\n\tif !assert.Equalf(t, expected, actual, msg, args...) {\n\t\tt.FailNow()\n\t}\n}\n\n// Error asserts that a function returned an error (i.e. not `nil`).\n//\n//   actualObj, err := SomeFunction()\n//   if assert.Error(t, err) {\n// \t   assert.Equal(t, expectedError, err)\n//   }\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Error(t TestingT, err error, msgAndArgs ...interface{}) {\n\tif !assert.Error(t, err, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// Errorf asserts that a function returned an error (i.e. not `nil`).\n//\n//   actualObj, err := SomeFunction()\n//   if assert.Errorf(t, err, \"error message %s\", \"formatted\") {\n// \t   assert.Equal(t, expectedErrorf, err)\n//   }\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Errorf(t TestingT, err error, msg string, args ...interface{}) {\n\tif !assert.Errorf(t, err, msg, args...) {\n\t\tt.FailNow()\n\t}\n}\n\n// Exactly asserts that two objects are equal is value and type.\n//\n//    assert.Exactly(t, int32(123), int64(123))\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Exactly(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {\n\tif !assert.Exactly(t, expected, actual, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// Exactlyf asserts that two objects are equal is value and type.\n//\n//    assert.Exactlyf(t, int32(123, \"error message %s\", \"formatted\"), int64(123))\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {\n\tif !assert.Exactlyf(t, expected, actual, msg, args...) {\n\t\tt.FailNow()\n\t}\n}\n\n// Fail reports a failure through\nfunc Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) {\n\tif !assert.Fail(t, failureMessage, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// FailNow fails test\nfunc FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) {\n\tif !assert.FailNow(t, failureMessage, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// FailNowf fails test\nfunc FailNowf(t TestingT, failureMessage string, msg string, args ...interface{}) {\n\tif !assert.FailNowf(t, failureMessage, msg, args...) {\n\t\tt.FailNow()\n\t}\n}\n\n// Failf reports a failure through\nfunc Failf(t TestingT, failureMessage string, msg string, args ...interface{}) {\n\tif !assert.Failf(t, failureMessage, msg, args...) {\n\t\tt.FailNow()\n\t}\n}\n\n// False asserts that the specified value is false.\n//\n//    assert.False(t, myBool)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc False(t TestingT, value bool, msgAndArgs ...interface{}) {\n\tif !assert.False(t, value, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// Falsef asserts that the specified value is false.\n//\n//    assert.Falsef(t, myBool, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Falsef(t TestingT, value bool, msg string, args ...interface{}) {\n\tif !assert.Falsef(t, value, msg, args...) {\n\t\tt.FailNow()\n\t}\n}\n\n// HTTPBodyContains asserts that a specified handler returns a\n// body that contains a string.\n//\n//  assert.HTTPBodyContains(t, myHandler, \"www.google.com\", nil, \"I'm Feeling Lucky\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc HTTPBodyContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) {\n\tif !assert.HTTPBodyContains(t, handler, method, url, values, str) {\n\t\tt.FailNow()\n\t}\n}\n\n// HTTPBodyContainsf asserts that a specified handler returns a\n// body that contains a string.\n//\n//  assert.HTTPBodyContainsf(t, myHandler, \"www.google.com\", nil, \"I'm Feeling Lucky\", \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) {\n\tif !assert.HTTPBodyContainsf(t, handler, method, url, values, str) {\n\t\tt.FailNow()\n\t}\n}\n\n// HTTPBodyNotContains asserts that a specified handler returns a\n// body that does not contain a string.\n//\n//  assert.HTTPBodyNotContains(t, myHandler, \"www.google.com\", nil, \"I'm Feeling Lucky\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) {\n\tif !assert.HTTPBodyNotContains(t, handler, method, url, values, str) {\n\t\tt.FailNow()\n\t}\n}\n\n// HTTPBodyNotContainsf asserts that a specified handler returns a\n// body that does not contain a string.\n//\n//  assert.HTTPBodyNotContainsf(t, myHandler, \"www.google.com\", nil, \"I'm Feeling Lucky\", \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) {\n\tif !assert.HTTPBodyNotContainsf(t, handler, method, url, values, str) {\n\t\tt.FailNow()\n\t}\n}\n\n// HTTPError asserts that a specified handler returns an error status code.\n//\n//  assert.HTTPError(t, myHandler, \"POST\", \"/a/b/c\", url.Values{\"a\": []string{\"b\", \"c\"}}\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc HTTPError(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values) {\n\tif !assert.HTTPError(t, handler, method, url, values) {\n\t\tt.FailNow()\n\t}\n}\n\n// HTTPErrorf asserts that a specified handler returns an error status code.\n//\n//  assert.HTTPErrorf(t, myHandler, \"POST\", \"/a/b/c\", url.Values{\"a\": []string{\"b\", \"c\"}}\n//\n// Returns whether the assertion was successful (true, \"error message %s\", \"formatted\") or not (false).\nfunc HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values) {\n\tif !assert.HTTPErrorf(t, handler, method, url, values) {\n\t\tt.FailNow()\n\t}\n}\n\n// HTTPRedirect asserts that a specified handler returns a redirect status code.\n//\n//  assert.HTTPRedirect(t, myHandler, \"GET\", \"/a/b/c\", url.Values{\"a\": []string{\"b\", \"c\"}}\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc HTTPRedirect(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values) {\n\tif !assert.HTTPRedirect(t, handler, method, url, values) {\n\t\tt.FailNow()\n\t}\n}\n\n// HTTPRedirectf asserts that a specified handler returns a redirect status code.\n//\n//  assert.HTTPRedirectf(t, myHandler, \"GET\", \"/a/b/c\", url.Values{\"a\": []string{\"b\", \"c\"}}\n//\n// Returns whether the assertion was successful (true, \"error message %s\", \"formatted\") or not (false).\nfunc HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values) {\n\tif !assert.HTTPRedirectf(t, handler, method, url, values) {\n\t\tt.FailNow()\n\t}\n}\n\n// HTTPSuccess asserts that a specified handler returns a success status code.\n//\n//  assert.HTTPSuccess(t, myHandler, \"POST\", \"http://www.google.com\", nil)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc HTTPSuccess(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values) {\n\tif !assert.HTTPSuccess(t, handler, method, url, values) {\n\t\tt.FailNow()\n\t}\n}\n\n// HTTPSuccessf asserts that a specified handler returns a success status code.\n//\n//  assert.HTTPSuccessf(t, myHandler, \"POST\", \"http://www.google.com\", nil, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values) {\n\tif !assert.HTTPSuccessf(t, handler, method, url, values) {\n\t\tt.FailNow()\n\t}\n}\n\n// Implements asserts that an object is implemented by the specified interface.\n//\n//    assert.Implements(t, (*MyInterface)(nil), new(MyObject))\nfunc Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) {\n\tif !assert.Implements(t, interfaceObject, object, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// Implementsf asserts that an object is implemented by the specified interface.\n//\n//    assert.Implementsf(t, (*MyInterface, \"error message %s\", \"formatted\")(nil), new(MyObject))\nfunc Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) {\n\tif !assert.Implementsf(t, interfaceObject, object, msg, args...) {\n\t\tt.FailNow()\n\t}\n}\n\n// InDelta asserts that the two numerals are within delta of each other.\n//\n// \t assert.InDelta(t, math.Pi, (22 / 7.0), 0.01)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc InDelta(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {\n\tif !assert.InDelta(t, expected, actual, delta, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// InDeltaSlice is the same as InDelta, except it compares two slices.\nfunc InDeltaSlice(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {\n\tif !assert.InDeltaSlice(t, expected, actual, delta, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// InDeltaSlicef is the same as InDelta, except it compares two slices.\nfunc InDeltaSlicef(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {\n\tif !assert.InDeltaSlicef(t, expected, actual, delta, msg, args...) {\n\t\tt.FailNow()\n\t}\n}\n\n// InDeltaf asserts that the two numerals are within delta of each other.\n//\n// \t assert.InDeltaf(t, math.Pi, (22 / 7.0, \"error message %s\", \"formatted\"), 0.01)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {\n\tif !assert.InDeltaf(t, expected, actual, delta, msg, args...) {\n\t\tt.FailNow()\n\t}\n}\n\n// InEpsilon asserts that expected and actual have a relative error less than epsilon\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc InEpsilon(t TestingT, expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {\n\tif !assert.InEpsilon(t, expected, actual, epsilon, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.\nfunc InEpsilonSlice(t TestingT, expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {\n\tif !assert.InEpsilonSlice(t, expected, actual, epsilon, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices.\nfunc InEpsilonSlicef(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) {\n\tif !assert.InEpsilonSlicef(t, expected, actual, epsilon, msg, args...) {\n\t\tt.FailNow()\n\t}\n}\n\n// InEpsilonf asserts that expected and actual have a relative error less than epsilon\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc InEpsilonf(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) {\n\tif !assert.InEpsilonf(t, expected, actual, epsilon, msg, args...) {\n\t\tt.FailNow()\n\t}\n}\n\n// IsType asserts that the specified objects are of the same type.\nfunc IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) {\n\tif !assert.IsType(t, expectedType, object, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// IsTypef asserts that the specified objects are of the same type.\nfunc IsTypef(t TestingT, expectedType interface{}, object interface{}, msg string, args ...interface{}) {\n\tif !assert.IsTypef(t, expectedType, object, msg, args...) {\n\t\tt.FailNow()\n\t}\n}\n\n// JSONEq asserts that two JSON strings are equivalent.\n//\n//  assert.JSONEq(t, `{\"hello\": \"world\", \"foo\": \"bar\"}`, `{\"foo\": \"bar\", \"hello\": \"world\"}`)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) {\n\tif !assert.JSONEq(t, expected, actual, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// JSONEqf asserts that two JSON strings are equivalent.\n//\n//  assert.JSONEqf(t, `{\"hello\": \"world\", \"foo\": \"bar\"}`, `{\"foo\": \"bar\", \"hello\": \"world\"}`, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc JSONEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) {\n\tif !assert.JSONEqf(t, expected, actual, msg, args...) {\n\t\tt.FailNow()\n\t}\n}\n\n// Len asserts that the specified object has specific length.\n// Len also fails if the object has a type that len() not accept.\n//\n//    assert.Len(t, mySlice, 3)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) {\n\tif !assert.Len(t, object, length, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// Lenf asserts that the specified object has specific length.\n// Lenf also fails if the object has a type that len() not accept.\n//\n//    assert.Lenf(t, mySlice, 3, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Lenf(t TestingT, object interface{}, length int, msg string, args ...interface{}) {\n\tif !assert.Lenf(t, object, length, msg, args...) {\n\t\tt.FailNow()\n\t}\n}\n\n// Nil asserts that the specified object is nil.\n//\n//    assert.Nil(t, err)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) {\n\tif !assert.Nil(t, object, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// Nilf asserts that the specified object is nil.\n//\n//    assert.Nilf(t, err, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Nilf(t TestingT, object interface{}, msg string, args ...interface{}) {\n\tif !assert.Nilf(t, object, msg, args...) {\n\t\tt.FailNow()\n\t}\n}\n\n// NoError asserts that a function returned no error (i.e. `nil`).\n//\n//   actualObj, err := SomeFunction()\n//   if assert.NoError(t, err) {\n// \t   assert.Equal(t, expectedObj, actualObj)\n//   }\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NoError(t TestingT, err error, msgAndArgs ...interface{}) {\n\tif !assert.NoError(t, err, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// NoErrorf asserts that a function returned no error (i.e. `nil`).\n//\n//   actualObj, err := SomeFunction()\n//   if assert.NoErrorf(t, err, \"error message %s\", \"formatted\") {\n// \t   assert.Equal(t, expectedObj, actualObj)\n//   }\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NoErrorf(t TestingT, err error, msg string, args ...interface{}) {\n\tif !assert.NoErrorf(t, err, msg, args...) {\n\t\tt.FailNow()\n\t}\n}\n\n// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the\n// specified substring or element.\n//\n//    assert.NotContains(t, \"Hello World\", \"Earth\")\n//    assert.NotContains(t, [\"Hello\", \"World\"], \"Earth\")\n//    assert.NotContains(t, {\"Hello\": \"World\"}, \"Earth\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NotContains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...interface{}) {\n\tif !assert.NotContains(t, s, contains, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the\n// specified substring or element.\n//\n//    assert.NotContainsf(t, \"Hello World\", \"Earth\", \"error message %s\", \"formatted\")\n//    assert.NotContainsf(t, [\"Hello\", \"World\"], \"Earth\", \"error message %s\", \"formatted\")\n//    assert.NotContainsf(t, {\"Hello\": \"World\"}, \"Earth\", \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) {\n\tif !assert.NotContainsf(t, s, contains, msg, args...) {\n\t\tt.FailNow()\n\t}\n}\n\n// NotEmpty asserts that the specified object is NOT empty.  I.e. not nil, \"\", false, 0 or either\n// a slice or a channel with len == 0.\n//\n//  if assert.NotEmpty(t, obj) {\n//    assert.Equal(t, \"two\", obj[1])\n//  }\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) {\n\tif !assert.NotEmpty(t, object, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// NotEmptyf asserts that the specified object is NOT empty.  I.e. not nil, \"\", false, 0 or either\n// a slice or a channel with len == 0.\n//\n//  if assert.NotEmptyf(t, obj, \"error message %s\", \"formatted\") {\n//    assert.Equal(t, \"two\", obj[1])\n//  }\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) {\n\tif !assert.NotEmptyf(t, object, msg, args...) {\n\t\tt.FailNow()\n\t}\n}\n\n// NotEqual asserts that the specified values are NOT equal.\n//\n//    assert.NotEqual(t, obj1, obj2)\n//\n// Returns whether the assertion was successful (true) or not (false).\n//\n// Pointer variable equality is determined based on the equality of the\n// referenced values (as opposed to the memory addresses).\nfunc NotEqual(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {\n\tif !assert.NotEqual(t, expected, actual, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// NotEqualf asserts that the specified values are NOT equal.\n//\n//    assert.NotEqualf(t, obj1, obj2, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\n//\n// Pointer variable equality is determined based on the equality of the\n// referenced values (as opposed to the memory addresses).\nfunc NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {\n\tif !assert.NotEqualf(t, expected, actual, msg, args...) {\n\t\tt.FailNow()\n\t}\n}\n\n// NotNil asserts that the specified object is not nil.\n//\n//    assert.NotNil(t, err)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) {\n\tif !assert.NotNil(t, object, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// NotNilf asserts that the specified object is not nil.\n//\n//    assert.NotNilf(t, err, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) {\n\tif !assert.NotNilf(t, object, msg, args...) {\n\t\tt.FailNow()\n\t}\n}\n\n// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.\n//\n//   assert.NotPanics(t, func(){ RemainCalm() })\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NotPanics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) {\n\tif !assert.NotPanics(t, f, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic.\n//\n//   assert.NotPanicsf(t, func(){ RemainCalm() }, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NotPanicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...interface{}) {\n\tif !assert.NotPanicsf(t, f, msg, args...) {\n\t\tt.FailNow()\n\t}\n}\n\n// NotRegexp asserts that a specified regexp does not match a string.\n//\n//  assert.NotRegexp(t, regexp.MustCompile(\"starts\"), \"it's starting\")\n//  assert.NotRegexp(t, \"^start\", \"it's not starting\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) {\n\tif !assert.NotRegexp(t, rx, str, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// NotRegexpf asserts that a specified regexp does not match a string.\n//\n//  assert.NotRegexpf(t, regexp.MustCompile(\"starts\", \"error message %s\", \"formatted\"), \"it's starting\")\n//  assert.NotRegexpf(t, \"^start\", \"it's not starting\", \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) {\n\tif !assert.NotRegexpf(t, rx, str, msg, args...) {\n\t\tt.FailNow()\n\t}\n}\n\n// NotSubset asserts that the specified list(array, slice...) contains not all\n// elements given in the specified subset(array, slice...).\n//\n//    assert.NotSubset(t, [1, 3, 4], [1, 2], \"But [1, 3, 4] does not contain [1, 2]\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NotSubset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...interface{}) {\n\tif !assert.NotSubset(t, list, subset, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// NotSubsetf asserts that the specified list(array, slice...) contains not all\n// elements given in the specified subset(array, slice...).\n//\n//    assert.NotSubsetf(t, [1, 3, 4], [1, 2], \"But [1, 3, 4] does not contain [1, 2]\", \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc NotSubsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) {\n\tif !assert.NotSubsetf(t, list, subset, msg, args...) {\n\t\tt.FailNow()\n\t}\n}\n\n// NotZero asserts that i is not the zero value for its type and returns the truth.\nfunc NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) {\n\tif !assert.NotZero(t, i, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// NotZerof asserts that i is not the zero value for its type and returns the truth.\nfunc NotZerof(t TestingT, i interface{}, msg string, args ...interface{}) {\n\tif !assert.NotZerof(t, i, msg, args...) {\n\t\tt.FailNow()\n\t}\n}\n\n// Panics asserts that the code inside the specified PanicTestFunc panics.\n//\n//   assert.Panics(t, func(){ GoCrazy() })\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Panics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) {\n\tif !assert.Panics(t, f, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that\n// the recovered panic value equals the expected panic value.\n//\n//   assert.PanicsWithValue(t, \"crazy error\", func(){ GoCrazy() })\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc PanicsWithValue(t TestingT, expected interface{}, f assert.PanicTestFunc, msgAndArgs ...interface{}) {\n\tif !assert.PanicsWithValue(t, expected, f, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that\n// the recovered panic value equals the expected panic value.\n//\n//   assert.PanicsWithValuef(t, \"crazy error\", func(){ GoCrazy() }, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc PanicsWithValuef(t TestingT, expected interface{}, f assert.PanicTestFunc, msg string, args ...interface{}) {\n\tif !assert.PanicsWithValuef(t, expected, f, msg, args...) {\n\t\tt.FailNow()\n\t}\n}\n\n// Panicsf asserts that the code inside the specified PanicTestFunc panics.\n//\n//   assert.Panicsf(t, func(){ GoCrazy() }, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Panicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...interface{}) {\n\tif !assert.Panicsf(t, f, msg, args...) {\n\t\tt.FailNow()\n\t}\n}\n\n// Regexp asserts that a specified regexp matches a string.\n//\n//  assert.Regexp(t, regexp.MustCompile(\"start\"), \"it's starting\")\n//  assert.Regexp(t, \"start...$\", \"it's not starting\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) {\n\tif !assert.Regexp(t, rx, str, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// Regexpf asserts that a specified regexp matches a string.\n//\n//  assert.Regexpf(t, regexp.MustCompile(\"start\", \"error message %s\", \"formatted\"), \"it's starting\")\n//  assert.Regexpf(t, \"start...$\", \"it's not starting\", \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) {\n\tif !assert.Regexpf(t, rx, str, msg, args...) {\n\t\tt.FailNow()\n\t}\n}\n\n// Subset asserts that the specified list(array, slice...) contains all\n// elements given in the specified subset(array, slice...).\n//\n//    assert.Subset(t, [1, 2, 3], [1, 2], \"But [1, 2, 3] does contain [1, 2]\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Subset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...interface{}) {\n\tif !assert.Subset(t, list, subset, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// Subsetf asserts that the specified list(array, slice...) contains all\n// elements given in the specified subset(array, slice...).\n//\n//    assert.Subsetf(t, [1, 2, 3], [1, 2], \"But [1, 2, 3] does contain [1, 2]\", \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) {\n\tif !assert.Subsetf(t, list, subset, msg, args...) {\n\t\tt.FailNow()\n\t}\n}\n\n// True asserts that the specified value is true.\n//\n//    assert.True(t, myBool)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc True(t TestingT, value bool, msgAndArgs ...interface{}) {\n\tif !assert.True(t, value, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// Truef asserts that the specified value is true.\n//\n//    assert.Truef(t, myBool, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc Truef(t TestingT, value bool, msg string, args ...interface{}) {\n\tif !assert.Truef(t, value, msg, args...) {\n\t\tt.FailNow()\n\t}\n}\n\n// WithinDuration asserts that the two times are within duration delta of each other.\n//\n//   assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc WithinDuration(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) {\n\tif !assert.WithinDuration(t, expected, actual, delta, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// WithinDurationf asserts that the two times are within duration delta of each other.\n//\n//   assert.WithinDurationf(t, time.Now(), time.Now(), 10*time.Second, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) {\n\tif !assert.WithinDurationf(t, expected, actual, delta, msg, args...) {\n\t\tt.FailNow()\n\t}\n}\n\n// Zero asserts that i is the zero value for its type and returns the truth.\nfunc Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) {\n\tif !assert.Zero(t, i, msgAndArgs...) {\n\t\tt.FailNow()\n\t}\n}\n\n// Zerof asserts that i is the zero value for its type and returns the truth.\nfunc Zerof(t TestingT, i interface{}, msg string, args ...interface{}) {\n\tif !assert.Zerof(t, i, msg, args...) {\n\t\tt.FailNow()\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/stretchr/testify/require/require.go.tmpl",
    "content": "{{.Comment}}\nfunc {{.DocInfo.Name}}(t TestingT, {{.Params}}) {\n\tif !assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) {\n\t\tt.FailNow()\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/stretchr/testify/require/require_forward.go",
    "content": "/*\n* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen\n* THIS FILE MUST NOT BE EDITED BY HAND\n */\n\npackage require\n\nimport (\n\tassert \"github.com/stretchr/testify/assert\"\n\thttp \"net/http\"\n\turl \"net/url\"\n\ttime \"time\"\n)\n\n// Condition uses a Comparison to assert a complex condition.\nfunc (a *Assertions) Condition(comp assert.Comparison, msgAndArgs ...interface{}) {\n\tCondition(a.t, comp, msgAndArgs...)\n}\n\n// Conditionf uses a Comparison to assert a complex condition.\nfunc (a *Assertions) Conditionf(comp assert.Comparison, msg string, args ...interface{}) {\n\tConditionf(a.t, comp, msg, args...)\n}\n\n// Contains asserts that the specified string, list(array, slice...) or map contains the\n// specified substring or element.\n//\n//    a.Contains(\"Hello World\", \"World\")\n//    a.Contains([\"Hello\", \"World\"], \"World\")\n//    a.Contains({\"Hello\": \"World\"}, \"Hello\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) {\n\tContains(a.t, s, contains, msgAndArgs...)\n}\n\n// Containsf asserts that the specified string, list(array, slice...) or map contains the\n// specified substring or element.\n//\n//    a.Containsf(\"Hello World\", \"World\", \"error message %s\", \"formatted\")\n//    a.Containsf([\"Hello\", \"World\"], \"World\", \"error message %s\", \"formatted\")\n//    a.Containsf({\"Hello\": \"World\"}, \"Hello\", \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Containsf(s interface{}, contains interface{}, msg string, args ...interface{}) {\n\tContainsf(a.t, s, contains, msg, args...)\n}\n\n// Empty asserts that the specified object is empty.  I.e. nil, \"\", false, 0 or either\n// a slice or a channel with len == 0.\n//\n//  a.Empty(obj)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) {\n\tEmpty(a.t, object, msgAndArgs...)\n}\n\n// Emptyf asserts that the specified object is empty.  I.e. nil, \"\", false, 0 or either\n// a slice or a channel with len == 0.\n//\n//  a.Emptyf(obj, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{}) {\n\tEmptyf(a.t, object, msg, args...)\n}\n\n// Equal asserts that two objects are equal.\n//\n//    a.Equal(123, 123)\n//\n// Returns whether the assertion was successful (true) or not (false).\n//\n// Pointer variable equality is determined based on the equality of the\n// referenced values (as opposed to the memory addresses). Function equality\n// cannot be determined and will always fail.\nfunc (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {\n\tEqual(a.t, expected, actual, msgAndArgs...)\n}\n\n// EqualError asserts that a function returned an error (i.e. not `nil`)\n// and that it is equal to the provided error.\n//\n//   actualObj, err := SomeFunction()\n//   a.EqualError(err,  expectedErrorString)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) {\n\tEqualError(a.t, theError, errString, msgAndArgs...)\n}\n\n// EqualErrorf asserts that a function returned an error (i.e. not `nil`)\n// and that it is equal to the provided error.\n//\n//   actualObj, err := SomeFunction()\n//   a.EqualErrorf(err,  expectedErrorString, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) EqualErrorf(theError error, errString string, msg string, args ...interface{}) {\n\tEqualErrorf(a.t, theError, errString, msg, args...)\n}\n\n// EqualValues asserts that two objects are equal or convertable to the same types\n// and equal.\n//\n//    a.EqualValues(uint32(123), int32(123))\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {\n\tEqualValues(a.t, expected, actual, msgAndArgs...)\n}\n\n// EqualValuesf asserts that two objects are equal or convertable to the same types\n// and equal.\n//\n//    a.EqualValuesf(uint32(123, \"error message %s\", \"formatted\"), int32(123))\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) {\n\tEqualValuesf(a.t, expected, actual, msg, args...)\n}\n\n// Equalf asserts that two objects are equal.\n//\n//    a.Equalf(123, 123, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\n//\n// Pointer variable equality is determined based on the equality of the\n// referenced values (as opposed to the memory addresses). Function equality\n// cannot be determined and will always fail.\nfunc (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string, args ...interface{}) {\n\tEqualf(a.t, expected, actual, msg, args...)\n}\n\n// Error asserts that a function returned an error (i.e. not `nil`).\n//\n//   actualObj, err := SomeFunction()\n//   if a.Error(err) {\n// \t   assert.Equal(t, expectedError, err)\n//   }\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Error(err error, msgAndArgs ...interface{}) {\n\tError(a.t, err, msgAndArgs...)\n}\n\n// Errorf asserts that a function returned an error (i.e. not `nil`).\n//\n//   actualObj, err := SomeFunction()\n//   if a.Errorf(err, \"error message %s\", \"formatted\") {\n// \t   assert.Equal(t, expectedErrorf, err)\n//   }\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Errorf(err error, msg string, args ...interface{}) {\n\tErrorf(a.t, err, msg, args...)\n}\n\n// Exactly asserts that two objects are equal is value and type.\n//\n//    a.Exactly(int32(123), int64(123))\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {\n\tExactly(a.t, expected, actual, msgAndArgs...)\n}\n\n// Exactlyf asserts that two objects are equal is value and type.\n//\n//    a.Exactlyf(int32(123, \"error message %s\", \"formatted\"), int64(123))\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) {\n\tExactlyf(a.t, expected, actual, msg, args...)\n}\n\n// Fail reports a failure through\nfunc (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) {\n\tFail(a.t, failureMessage, msgAndArgs...)\n}\n\n// FailNow fails test\nfunc (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) {\n\tFailNow(a.t, failureMessage, msgAndArgs...)\n}\n\n// FailNowf fails test\nfunc (a *Assertions) FailNowf(failureMessage string, msg string, args ...interface{}) {\n\tFailNowf(a.t, failureMessage, msg, args...)\n}\n\n// Failf reports a failure through\nfunc (a *Assertions) Failf(failureMessage string, msg string, args ...interface{}) {\n\tFailf(a.t, failureMessage, msg, args...)\n}\n\n// False asserts that the specified value is false.\n//\n//    a.False(myBool)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) False(value bool, msgAndArgs ...interface{}) {\n\tFalse(a.t, value, msgAndArgs...)\n}\n\n// Falsef asserts that the specified value is false.\n//\n//    a.Falsef(myBool, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Falsef(value bool, msg string, args ...interface{}) {\n\tFalsef(a.t, value, msg, args...)\n}\n\n// HTTPBodyContains asserts that a specified handler returns a\n// body that contains a string.\n//\n//  a.HTTPBodyContains(myHandler, \"www.google.com\", nil, \"I'm Feeling Lucky\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) {\n\tHTTPBodyContains(a.t, handler, method, url, values, str)\n}\n\n// HTTPBodyContainsf asserts that a specified handler returns a\n// body that contains a string.\n//\n//  a.HTTPBodyContainsf(myHandler, \"www.google.com\", nil, \"I'm Feeling Lucky\", \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) {\n\tHTTPBodyContainsf(a.t, handler, method, url, values, str)\n}\n\n// HTTPBodyNotContains asserts that a specified handler returns a\n// body that does not contain a string.\n//\n//  a.HTTPBodyNotContains(myHandler, \"www.google.com\", nil, \"I'm Feeling Lucky\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) {\n\tHTTPBodyNotContains(a.t, handler, method, url, values, str)\n}\n\n// HTTPBodyNotContainsf asserts that a specified handler returns a\n// body that does not contain a string.\n//\n//  a.HTTPBodyNotContainsf(myHandler, \"www.google.com\", nil, \"I'm Feeling Lucky\", \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) {\n\tHTTPBodyNotContainsf(a.t, handler, method, url, values, str)\n}\n\n// HTTPError asserts that a specified handler returns an error status code.\n//\n//  a.HTTPError(myHandler, \"POST\", \"/a/b/c\", url.Values{\"a\": []string{\"b\", \"c\"}}\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values) {\n\tHTTPError(a.t, handler, method, url, values)\n}\n\n// HTTPErrorf asserts that a specified handler returns an error status code.\n//\n//  a.HTTPErrorf(myHandler, \"POST\", \"/a/b/c\", url.Values{\"a\": []string{\"b\", \"c\"}}\n//\n// Returns whether the assertion was successful (true, \"error message %s\", \"formatted\") or not (false).\nfunc (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values) {\n\tHTTPErrorf(a.t, handler, method, url, values)\n}\n\n// HTTPRedirect asserts that a specified handler returns a redirect status code.\n//\n//  a.HTTPRedirect(myHandler, \"GET\", \"/a/b/c\", url.Values{\"a\": []string{\"b\", \"c\"}}\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values) {\n\tHTTPRedirect(a.t, handler, method, url, values)\n}\n\n// HTTPRedirectf asserts that a specified handler returns a redirect status code.\n//\n//  a.HTTPRedirectf(myHandler, \"GET\", \"/a/b/c\", url.Values{\"a\": []string{\"b\", \"c\"}}\n//\n// Returns whether the assertion was successful (true, \"error message %s\", \"formatted\") or not (false).\nfunc (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values) {\n\tHTTPRedirectf(a.t, handler, method, url, values)\n}\n\n// HTTPSuccess asserts that a specified handler returns a success status code.\n//\n//  a.HTTPSuccess(myHandler, \"POST\", \"http://www.google.com\", nil)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values) {\n\tHTTPSuccess(a.t, handler, method, url, values)\n}\n\n// HTTPSuccessf asserts that a specified handler returns a success status code.\n//\n//  a.HTTPSuccessf(myHandler, \"POST\", \"http://www.google.com\", nil, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values) {\n\tHTTPSuccessf(a.t, handler, method, url, values)\n}\n\n// Implements asserts that an object is implemented by the specified interface.\n//\n//    a.Implements((*MyInterface)(nil), new(MyObject))\nfunc (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) {\n\tImplements(a.t, interfaceObject, object, msgAndArgs...)\n}\n\n// Implementsf asserts that an object is implemented by the specified interface.\n//\n//    a.Implementsf((*MyInterface, \"error message %s\", \"formatted\")(nil), new(MyObject))\nfunc (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) {\n\tImplementsf(a.t, interfaceObject, object, msg, args...)\n}\n\n// InDelta asserts that the two numerals are within delta of each other.\n//\n// \t a.InDelta(math.Pi, (22 / 7.0), 0.01)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {\n\tInDelta(a.t, expected, actual, delta, msgAndArgs...)\n}\n\n// InDeltaSlice is the same as InDelta, except it compares two slices.\nfunc (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {\n\tInDeltaSlice(a.t, expected, actual, delta, msgAndArgs...)\n}\n\n// InDeltaSlicef is the same as InDelta, except it compares two slices.\nfunc (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {\n\tInDeltaSlicef(a.t, expected, actual, delta, msg, args...)\n}\n\n// InDeltaf asserts that the two numerals are within delta of each other.\n//\n// \t a.InDeltaf(math.Pi, (22 / 7.0, \"error message %s\", \"formatted\"), 0.01)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {\n\tInDeltaf(a.t, expected, actual, delta, msg, args...)\n}\n\n// InEpsilon asserts that expected and actual have a relative error less than epsilon\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) InEpsilon(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {\n\tInEpsilon(a.t, expected, actual, epsilon, msgAndArgs...)\n}\n\n// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.\nfunc (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {\n\tInEpsilonSlice(a.t, expected, actual, epsilon, msgAndArgs...)\n}\n\n// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices.\nfunc (a *Assertions) InEpsilonSlicef(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) {\n\tInEpsilonSlicef(a.t, expected, actual, epsilon, msg, args...)\n}\n\n// InEpsilonf asserts that expected and actual have a relative error less than epsilon\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) InEpsilonf(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) {\n\tInEpsilonf(a.t, expected, actual, epsilon, msg, args...)\n}\n\n// IsType asserts that the specified objects are of the same type.\nfunc (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) {\n\tIsType(a.t, expectedType, object, msgAndArgs...)\n}\n\n// IsTypef asserts that the specified objects are of the same type.\nfunc (a *Assertions) IsTypef(expectedType interface{}, object interface{}, msg string, args ...interface{}) {\n\tIsTypef(a.t, expectedType, object, msg, args...)\n}\n\n// JSONEq asserts that two JSON strings are equivalent.\n//\n//  a.JSONEq(`{\"hello\": \"world\", \"foo\": \"bar\"}`, `{\"foo\": \"bar\", \"hello\": \"world\"}`)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) {\n\tJSONEq(a.t, expected, actual, msgAndArgs...)\n}\n\n// JSONEqf asserts that two JSON strings are equivalent.\n//\n//  a.JSONEqf(`{\"hello\": \"world\", \"foo\": \"bar\"}`, `{\"foo\": \"bar\", \"hello\": \"world\"}`, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) JSONEqf(expected string, actual string, msg string, args ...interface{}) {\n\tJSONEqf(a.t, expected, actual, msg, args...)\n}\n\n// Len asserts that the specified object has specific length.\n// Len also fails if the object has a type that len() not accept.\n//\n//    a.Len(mySlice, 3)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) {\n\tLen(a.t, object, length, msgAndArgs...)\n}\n\n// Lenf asserts that the specified object has specific length.\n// Lenf also fails if the object has a type that len() not accept.\n//\n//    a.Lenf(mySlice, 3, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Lenf(object interface{}, length int, msg string, args ...interface{}) {\n\tLenf(a.t, object, length, msg, args...)\n}\n\n// Nil asserts that the specified object is nil.\n//\n//    a.Nil(err)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) {\n\tNil(a.t, object, msgAndArgs...)\n}\n\n// Nilf asserts that the specified object is nil.\n//\n//    a.Nilf(err, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) {\n\tNilf(a.t, object, msg, args...)\n}\n\n// NoError asserts that a function returned no error (i.e. `nil`).\n//\n//   actualObj, err := SomeFunction()\n//   if a.NoError(err) {\n// \t   assert.Equal(t, expectedObj, actualObj)\n//   }\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) NoError(err error, msgAndArgs ...interface{}) {\n\tNoError(a.t, err, msgAndArgs...)\n}\n\n// NoErrorf asserts that a function returned no error (i.e. `nil`).\n//\n//   actualObj, err := SomeFunction()\n//   if a.NoErrorf(err, \"error message %s\", \"formatted\") {\n// \t   assert.Equal(t, expectedObj, actualObj)\n//   }\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) {\n\tNoErrorf(a.t, err, msg, args...)\n}\n\n// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the\n// specified substring or element.\n//\n//    a.NotContains(\"Hello World\", \"Earth\")\n//    a.NotContains([\"Hello\", \"World\"], \"Earth\")\n//    a.NotContains({\"Hello\": \"World\"}, \"Earth\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) {\n\tNotContains(a.t, s, contains, msgAndArgs...)\n}\n\n// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the\n// specified substring or element.\n//\n//    a.NotContainsf(\"Hello World\", \"Earth\", \"error message %s\", \"formatted\")\n//    a.NotContainsf([\"Hello\", \"World\"], \"Earth\", \"error message %s\", \"formatted\")\n//    a.NotContainsf({\"Hello\": \"World\"}, \"Earth\", \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg string, args ...interface{}) {\n\tNotContainsf(a.t, s, contains, msg, args...)\n}\n\n// NotEmpty asserts that the specified object is NOT empty.  I.e. not nil, \"\", false, 0 or either\n// a slice or a channel with len == 0.\n//\n//  if a.NotEmpty(obj) {\n//    assert.Equal(t, \"two\", obj[1])\n//  }\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) {\n\tNotEmpty(a.t, object, msgAndArgs...)\n}\n\n// NotEmptyf asserts that the specified object is NOT empty.  I.e. not nil, \"\", false, 0 or either\n// a slice or a channel with len == 0.\n//\n//  if a.NotEmptyf(obj, \"error message %s\", \"formatted\") {\n//    assert.Equal(t, \"two\", obj[1])\n//  }\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface{}) {\n\tNotEmptyf(a.t, object, msg, args...)\n}\n\n// NotEqual asserts that the specified values are NOT equal.\n//\n//    a.NotEqual(obj1, obj2)\n//\n// Returns whether the assertion was successful (true) or not (false).\n//\n// Pointer variable equality is determined based on the equality of the\n// referenced values (as opposed to the memory addresses).\nfunc (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {\n\tNotEqual(a.t, expected, actual, msgAndArgs...)\n}\n\n// NotEqualf asserts that the specified values are NOT equal.\n//\n//    a.NotEqualf(obj1, obj2, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\n//\n// Pointer variable equality is determined based on the equality of the\n// referenced values (as opposed to the memory addresses).\nfunc (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg string, args ...interface{}) {\n\tNotEqualf(a.t, expected, actual, msg, args...)\n}\n\n// NotNil asserts that the specified object is not nil.\n//\n//    a.NotNil(err)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) {\n\tNotNil(a.t, object, msgAndArgs...)\n}\n\n// NotNilf asserts that the specified object is not nil.\n//\n//    a.NotNilf(err, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{}) {\n\tNotNilf(a.t, object, msg, args...)\n}\n\n// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.\n//\n//   a.NotPanics(func(){ RemainCalm() })\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) NotPanics(f assert.PanicTestFunc, msgAndArgs ...interface{}) {\n\tNotPanics(a.t, f, msgAndArgs...)\n}\n\n// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic.\n//\n//   a.NotPanicsf(func(){ RemainCalm() }, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) NotPanicsf(f assert.PanicTestFunc, msg string, args ...interface{}) {\n\tNotPanicsf(a.t, f, msg, args...)\n}\n\n// NotRegexp asserts that a specified regexp does not match a string.\n//\n//  a.NotRegexp(regexp.MustCompile(\"starts\"), \"it's starting\")\n//  a.NotRegexp(\"^start\", \"it's not starting\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) {\n\tNotRegexp(a.t, rx, str, msgAndArgs...)\n}\n\n// NotRegexpf asserts that a specified regexp does not match a string.\n//\n//  a.NotRegexpf(regexp.MustCompile(\"starts\", \"error message %s\", \"formatted\"), \"it's starting\")\n//  a.NotRegexpf(\"^start\", \"it's not starting\", \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) {\n\tNotRegexpf(a.t, rx, str, msg, args...)\n}\n\n// NotSubset asserts that the specified list(array, slice...) contains not all\n// elements given in the specified subset(array, slice...).\n//\n//    a.NotSubset([1, 3, 4], [1, 2], \"But [1, 3, 4] does not contain [1, 2]\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs ...interface{}) {\n\tNotSubset(a.t, list, subset, msgAndArgs...)\n}\n\n// NotSubsetf asserts that the specified list(array, slice...) contains not all\n// elements given in the specified subset(array, slice...).\n//\n//    a.NotSubsetf([1, 3, 4], [1, 2], \"But [1, 3, 4] does not contain [1, 2]\", \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) {\n\tNotSubsetf(a.t, list, subset, msg, args...)\n}\n\n// NotZero asserts that i is not the zero value for its type and returns the truth.\nfunc (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) {\n\tNotZero(a.t, i, msgAndArgs...)\n}\n\n// NotZerof asserts that i is not the zero value for its type and returns the truth.\nfunc (a *Assertions) NotZerof(i interface{}, msg string, args ...interface{}) {\n\tNotZerof(a.t, i, msg, args...)\n}\n\n// Panics asserts that the code inside the specified PanicTestFunc panics.\n//\n//   a.Panics(func(){ GoCrazy() })\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Panics(f assert.PanicTestFunc, msgAndArgs ...interface{}) {\n\tPanics(a.t, f, msgAndArgs...)\n}\n\n// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that\n// the recovered panic value equals the expected panic value.\n//\n//   a.PanicsWithValue(\"crazy error\", func(){ GoCrazy() })\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) PanicsWithValue(expected interface{}, f assert.PanicTestFunc, msgAndArgs ...interface{}) {\n\tPanicsWithValue(a.t, expected, f, msgAndArgs...)\n}\n\n// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that\n// the recovered panic value equals the expected panic value.\n//\n//   a.PanicsWithValuef(\"crazy error\", func(){ GoCrazy() }, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) PanicsWithValuef(expected interface{}, f assert.PanicTestFunc, msg string, args ...interface{}) {\n\tPanicsWithValuef(a.t, expected, f, msg, args...)\n}\n\n// Panicsf asserts that the code inside the specified PanicTestFunc panics.\n//\n//   a.Panicsf(func(){ GoCrazy() }, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Panicsf(f assert.PanicTestFunc, msg string, args ...interface{}) {\n\tPanicsf(a.t, f, msg, args...)\n}\n\n// Regexp asserts that a specified regexp matches a string.\n//\n//  a.Regexp(regexp.MustCompile(\"start\"), \"it's starting\")\n//  a.Regexp(\"start...$\", \"it's not starting\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) {\n\tRegexp(a.t, rx, str, msgAndArgs...)\n}\n\n// Regexpf asserts that a specified regexp matches a string.\n//\n//  a.Regexpf(regexp.MustCompile(\"start\", \"error message %s\", \"formatted\"), \"it's starting\")\n//  a.Regexpf(\"start...$\", \"it's not starting\", \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) {\n\tRegexpf(a.t, rx, str, msg, args...)\n}\n\n// Subset asserts that the specified list(array, slice...) contains all\n// elements given in the specified subset(array, slice...).\n//\n//    a.Subset([1, 2, 3], [1, 2], \"But [1, 2, 3] does contain [1, 2]\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...interface{}) {\n\tSubset(a.t, list, subset, msgAndArgs...)\n}\n\n// Subsetf asserts that the specified list(array, slice...) contains all\n// elements given in the specified subset(array, slice...).\n//\n//    a.Subsetf([1, 2, 3], [1, 2], \"But [1, 2, 3] does contain [1, 2]\", \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) {\n\tSubsetf(a.t, list, subset, msg, args...)\n}\n\n// True asserts that the specified value is true.\n//\n//    a.True(myBool)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) True(value bool, msgAndArgs ...interface{}) {\n\tTrue(a.t, value, msgAndArgs...)\n}\n\n// Truef asserts that the specified value is true.\n//\n//    a.Truef(myBool, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) Truef(value bool, msg string, args ...interface{}) {\n\tTruef(a.t, value, msg, args...)\n}\n\n// WithinDuration asserts that the two times are within duration delta of each other.\n//\n//   a.WithinDuration(time.Now(), time.Now(), 10*time.Second)\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) {\n\tWithinDuration(a.t, expected, actual, delta, msgAndArgs...)\n}\n\n// WithinDurationf asserts that the two times are within duration delta of each other.\n//\n//   a.WithinDurationf(time.Now(), time.Now(), 10*time.Second, \"error message %s\", \"formatted\")\n//\n// Returns whether the assertion was successful (true) or not (false).\nfunc (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) {\n\tWithinDurationf(a.t, expected, actual, delta, msg, args...)\n}\n\n// Zero asserts that i is the zero value for its type and returns the truth.\nfunc (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) {\n\tZero(a.t, i, msgAndArgs...)\n}\n\n// Zerof asserts that i is the zero value for its type and returns the truth.\nfunc (a *Assertions) Zerof(i interface{}, msg string, args ...interface{}) {\n\tZerof(a.t, i, msg, args...)\n}\n"
  },
  {
    "path": "vendor/github.com/stretchr/testify/require/require_forward.go.tmpl",
    "content": "{{.CommentWithoutT \"a\"}}\nfunc (a *Assertions) {{.DocInfo.Name}}({{.Params}}) {\n\t{{.DocInfo.Name}}(a.t, {{.ForwardedParams}})\n}\n"
  },
  {
    "path": "vendor/github.com/stretchr/testify/require/requirements.go",
    "content": "package require\n\n// TestingT is an interface wrapper around *testing.T\ntype TestingT interface {\n\tErrorf(format string, args ...interface{})\n\tFailNow()\n}\n\n//go:generate go run ../_codegen/main.go -output-package=require -template=require.go.tmpl -include-format-funcs\n"
  },
  {
    "path": "vendor/go.uber.org/dig/CHANGELOG.md",
    "content": "# Changelog\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)\nand this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).\n\n## [Unreleased]\n\n- No changes yet.\n\n## [1.5.0] - 2018-09-19\n### Added\n- Added a `DeferAcyclicVerification` container option that defers graph cycle\n  detection until the next Invoke.\n\n### Changed\n- Improved cycle-detection performance by 50x in certain degenerative cases.\n\n## [1.4.0] - 2018-08-16\n### Added\n- Added `Visualize` function to visualize the state of the container in the\n  GraphViz DOT format. This allows visualization of error types and the\n  dependency relationships of types in the container.\n- Added `CanVisualizeError` function to determine if an error can be visualized\n  in the graph.\n- Added `Name` option for `Provide` to add named values to the container\n  without rewriting constructors. See package documentation for more\n  information.\n\n### Changed\n- `name:\"...\"` tags on nested Result Objects will now cause errors instead of\n  being ignored.\n\n## [1.3.0] - 2017-12-04\n### Changed\n- Improved messages for errors thrown by Dig under a many scenarios to be more\n  informative.\n\n## [1.2.0] - 2017-11-07\n### Added\n- `dig.In` and `dig.Out` now support value groups, making it possible to\n  produce many values of the same type from different constructors. See package\n  documentation for more information.\n\n## [1.1.0] - 2017-09-15\n### Added\n- Added the `dig.RootCause` function which allows retrieving the original\n  constructor error that caused an `Invoke` failure.\n\n### Changed\n- Errors from `Invoke` now attempt to hint to the user a presence of a similar\n  type, for example a pointer to the requested type and vice versa.\n\n## [1.0.0] - 2017-07-31\n\nFirst stable release: no breaking changes will be made in the 1.x series.\n\n### Changed\n- `Provide` and `Invoke` will now fail if `dig.In` or `dig.Out` structs\n  contain unexported fields. Previously these fields were ignored which often\n  led to confusion.\n\n## [1.0.0-rc2] - 2017-07-21\n### Added\n- Exported `dig.IsIn` and `dig.IsOut` so that consuming libraries can check if\n  a params or return struct embeds the `dig.In` and `dig.Out` types, respectively.\n\n### Changed\n- Added variadic options to all public APIS so that new functionality can be\n  introduced post v1.0.0 without introducing breaking changes.\n- Functions with variadic arguments can now be passed to `dig.Provide` and\n  `dig.Invoke`. Previously this caused an error, whereas now the args will be ignored.\n\n## [1.0.0-rc1] - 2017-06-21\n\nFirst release candidate.\n\n## [0.5.0] - 2017-06-19\n### Added\n- `dig.In` and `dig.Out` now support named instances, i.e.:\n\n    ```go\n    type param struct {\n      dig.In\n\n      DB1 DB.Connection `name:\"primary\"`\n      DB2 DB.Connection `name:\"secondary\"`\n    }\n    ```\n\n### Fixed\n- Structs compatible with `dig.In` and `dig.Out` may now be generated using\n  `reflect.StructOf`.\n\n## [0.4.0] - 2017-06-12\n### Added\n- Add `dig.In` embeddable type for advanced use-cases of specifying dependencies.\n- Add `dig.Out` embeddable type for advanced use-cases of constructors\n  inserting types in the container.\n- Add support for optional parameters through `optional:\"true\"` tag on `dig.In` objects.\n- Add support for value types and many built-ins (maps, slices, channels).\n\n### Changed\n- **[Breaking]** Restrict the API surface to only `Provide` and `Invoke`.\n- **[Breaking]** Update `Provide` method to accept variadic arguments.\n\n### Removed\n- **[Breaking]** Remove `Must*` funcs to greatly reduce API surface area.\n- Providing constructors with common returned types results in an error.\n\n## [0.3] - 2017-05-02\n### Added\n- Add functionality to `Provide` to support constructor with `n` return\n  objects to be resolved into the `dig.Graph`\n- Add `Invoke` function to invoke provided function and insert return\n  objects into the `dig.Graph`\n\n### Changed\n- Rename `RegisterAll` and `MustRegisterAll` to `ProvideAll` and\n  `MustProvideAll`.\n\n## [0.2] - 2017-03-27\n### Changed\n- Rename `Register` to `Provide` for clarity and to recude clash with other\n  Register functions.\n- Rename `dig.Graph` to `dig.Container`.\n\n### Removed\n- Remove the package-level functions and the `DefaultGraph`.\n\n## 0.1 - 2017-03-23\n\nInitial release.\n\n[Unreleased]: https://github.com/uber-go/dig/compare/v1.5.0...HEAD\n[1.5.0]: https://github.com/uber-go/dig/compare/v1.4.0...v1.5.0\n[1.4.0]: https://github.com/uber-go/dig/compare/v1.3.0...v1.4.0\n[1.3.0]: https://github.com/uber-go/dig/compare/v1.2.0...v1.3.0\n[1.2.0]: https://github.com/uber-go/dig/compare/v1.1.0...v1.2.0\n[1.1.0]: https://github.com/uber-go/dig/compare/v1.0.0...v1.1.0\n[1.0.0]: https://github.com/uber-go/dig/compare/v1.0.0-rc2...v1.0.0\n[1.0.0-rc2]: https://github.com/uber-go/dig/compare/v1.0.0-rc1...v1.0.0-rc2\n[1.0.0-rc1]: https://github.com/uber-go/dig/compare/v0.5.0...v1.0.0-rc1\n[0.5.0]: https://github.com/uber-go/dig/compare/v0.4.0...v0.5.0\n[0.4.0]: https://github.com/uber-go/dig/compare/v0.3...v0.4.0\n[0.3]: https://github.com/uber-go/dig/compare/v0.2...v0.3\n[0.2]: https://github.com/uber-go/dig/compare/v0.1...v0.2\n"
  },
  {
    "path": "vendor/go.uber.org/dig/LICENSE",
    "content": "Copyright (c) 2017-2018 Uber Technologies, Inc.\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\nall copies 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\nTHE SOFTWARE.\n"
  },
  {
    "path": "vendor/go.uber.org/dig/Makefile",
    "content": "BENCH_FLAGS ?= -cpuprofile=cpu.pprof -memprofile=mem.pprof -benchmem\nPKGS ?= $(shell glide novendor | grep -v examples)\nPKG_FILES ?= *.go\nGO_VERSION := $(shell go version | cut -d \" \" -f 3)\n\n.PHONY: all\nall: lint test\n\n.PHONY: dependencies\ndependencies:\n\t@echo \"Installing Glide and locked dependencies...\"\n\tglide --version || go get -u -f github.com/Masterminds/glide\n\tglide install\n\t@echo \"Installing uber-license tool...\"\n\tcommand -v update-license >/dev/null || go get -u -f go.uber.org/tools/update-license\n\t@echo \"Installing golint...\"\n\tcommand -v golint >/dev/null || go get -u -f github.com/golang/lint/golint\n\n.PHONY: license\nlicense: dependencies\n\t./check_license.sh | tee -a lint.log\n\n.PHONY: lint\nlint:\n\t@rm -rf lint.log\n\t@echo \"Checking formatting...\"\n\t@gofmt -d -s $(PKG_FILES) 2>&1 | tee lint.log\n\t@echo \"Installing test dependencies for vet...\"\n\t@go test -i $(PKGS)\n\t@echo \"Checking vet...\"\n\t@$(foreach dir,$(PKG_FILES),go tool vet $(VET_RULES) $(dir) 2>&1 | tee -a lint.log;)\n\t@echo \"Checking lint...\"\n\t@$(foreach dir,$(PKGS),golint $(dir) 2>&1 | tee -a lint.log;)\n\t@echo \"Checking for unresolved FIXMEs...\"\n\t@git grep -i fixme | grep -v -e vendor -e Makefile | tee -a lint.log\n\t@echo \"Checking for license headers...\"\n\t@DRY_RUN=1 ./check_license.sh | tee -a lint.log\n\t@[ ! -s lint.log ]\n\n.PHONY: test\ntest:\n\t@.build/test.sh\n\n.PHONY: ci\nci: SHELL := /bin/bash\nci: test\n\tbash <(curl -s https://codecov.io/bash)\n\n.PHONY: bench\nBENCH ?= .\nbench:\n\t@$(foreach pkg,$(PKGS),go test -bench=$(BENCH) -run=\"^$$\" $(BENCH_FLAGS) $(pkg);)\n"
  },
  {
    "path": "vendor/go.uber.org/dig/README.md",
    "content": "# :hammer: dig [![GoDoc][doc-img]][doc] [![GitHub release][release-img]][release] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov] [![Go Report Card][report-card-img]][report-card]\n\nA reflection based dependency injection toolkit for Go.\n\n### Good for:\n\n* Powering an application framework, e.g. [Fx](https://github.com/uber-go/fx).\n* Resolving the object graph during process startup.\n\n### Bad for:\n\n* Using in place of an application framework, e.g. [Fx](https://github.com/uber-go/fx).\n* Resolving dependencies after the process has already started.\n* Exposing to user-land code as a [Service Locator](https://martinfowler.com/articles/injection.html#UsingAServiceLocator).\n\n## Installation\n\nWe recommend locking to [SemVer](http://semver.org/) range `^1` using [Glide](https://github.com/Masterminds/glide):\n\n```\nglide get 'go.uber.org/dig#^1'\n```\n\n## Stability\n\nThis library is `v1` and follows [SemVer](http://semver.org/) strictly.\n\nNo breaking changes will be made to exported APIs before `v2.0.0`.\n\n[doc-img]: http://img.shields.io/badge/GoDoc-Reference-blue.svg\n[doc]: https://godoc.org/go.uber.org/dig\n\n[release-img]: https://img.shields.io/github/release/uber-go/dig.svg\n[release]: https://github.com/uber-go/dig/releases\n\n[ci-img]: https://img.shields.io/travis/uber-go/dig/master.svg\n[ci]: https://travis-ci.org/uber-go/dig/branches\n\n[cov-img]: https://codecov.io/gh/uber-go/dig/branch/master/graph/badge.svg\n[cov]: https://codecov.io/gh/uber-go/dig/branch/master\n\n[report-card-img]: https://goreportcard.com/badge/github.com/uber-go/dig\n[report-card]: https://goreportcard.com/report/github.com/uber-go/dig\n"
  },
  {
    "path": "vendor/go.uber.org/dig/check_license.sh",
    "content": "#!/bin/bash\n\nset -eo pipefail\n\nrun_update_license() {\n  # doing this because of SC2046 warning\n  for file in $(git ls-files | grep '\\.go$'); do\n    update-license $@ \"${file}\"\n  done\n}\n\nif [ -z \"${DRY_RUN}\" ]; then\n  run_update_license\nelse\n  DRY_OUTPUT=\"$(run_update_license --dry)\"\n  if [ -n \"${DRY_OUTPUT}\" ]; then\n    echo \"The following files do not have correct license headers.\"\n    echo \"Please run make license and amend your commit.\"\n    echo\n    echo \"${DRY_OUTPUT}\"\n    exit 1\n  fi\nfi\n"
  },
  {
    "path": "vendor/go.uber.org/dig/cycle.go",
    "content": "// Copyright (c) 2018 Uber Technologies, Inc.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\npackage dig\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\n\t\"go.uber.org/dig/internal/digreflect\"\n)\n\ntype cycleEntry struct {\n\tKey  key\n\tFunc *digreflect.Func\n}\n\ntype errCycleDetected struct {\n\tPath []cycleEntry\n}\n\nfunc (e errCycleDetected) Error() string {\n\t// We get something like,\n\t//\n\t//   foo provided by \"path/to/package\".NewFoo (path/to/file.go:42)\n\t//   \tdepends on bar provided by \"another/package\".NewBar (somefile.go:1)\n\t//   \tdepends on baz provided by \"somepackage\".NewBar (anotherfile.go:2)\n\t//   \tdepends on foo provided by \"path/to/package\".NewFoo (path/to/file.go:42)\n\t//\n\tb := new(bytes.Buffer)\n\n\tfor i, entry := range e.Path {\n\t\tif i > 0 {\n\t\t\tb.WriteString(\"\\n\\tdepends on \")\n\t\t}\n\t\tfmt.Fprintf(b, \"%v provided by %v\", entry.Key, entry.Func)\n\t}\n\treturn b.String()\n}\n\n// IsCycleDetected returns a boolean as to whether the provided error indicates\n// a cycle was detected in the container graph.\nfunc IsCycleDetected(err error) bool {\n\t_, ok := RootCause(err).(errCycleDetected)\n\treturn ok\n}\n\nfunc verifyAcyclic(c containerStore, n provider, k key) error {\n\tvisited := make(map[key]struct{})\n\terr := detectCycles(n, c, []cycleEntry{\n\t\t{Key: k, Func: n.Location()},\n\t}, visited)\n\tif err != nil {\n\t\terr = errWrapf(err, \"this function introduces a cycle\")\n\t}\n\treturn err\n}\n\nfunc detectCycles(n provider, c containerStore, path []cycleEntry, visited map[key]struct{}) error {\n\tvar err error\n\twalkParam(n.ParamList(), paramVisitorFunc(func(param param) bool {\n\t\tif err != nil {\n\t\t\treturn false\n\t\t}\n\n\t\tvar (\n\t\t\tk         key\n\t\t\tproviders []provider\n\t\t)\n\t\tswitch p := param.(type) {\n\t\tcase paramSingle:\n\t\t\tk = key{name: p.Name, t: p.Type}\n\t\t\tif _, ok := visited[k]; ok {\n\t\t\t\t// We've already checked the dependencies for this type.\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tproviders = c.getValueProviders(p.Name, p.Type)\n\t\tcase paramGroupedSlice:\n\t\t\t// NOTE: The key uses the element type, not the slice type.\n\t\t\tk = key{group: p.Group, t: p.Type.Elem()}\n\t\t\tif _, ok := visited[k]; ok {\n\t\t\t\t// We've already checked the dependencies for this type.\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tproviders = c.getGroupProviders(p.Group, p.Type.Elem())\n\t\tdefault:\n\t\t\t// Recurse for non-edge params.\n\t\t\treturn true\n\t\t}\n\n\t\tentry := cycleEntry{Func: n.Location(), Key: k}\n\n\t\tif len(path) > 0 {\n\t\t\t// Only mark a key as visited if path exists, i.e. this is not the\n\t\t\t// first iteration through the c.verifyAcyclic() check. Otherwise the\n\t\t\t// early exit from checking visited above will short circuit the\n\t\t\t// cycle check below.\n\t\t\tvisited[k] = struct{}{}\n\n\t\t\t// If it exists, the first element of path is the new addition to the\n\t\t\t// graph, therefore it must be in any cycle that exists, assuming\n\t\t\t// verifyAcyclic has been run for every previous Provide.\n\t\t\t//\n\t\t\t// Alternatively, if deferAcyclicVerification was set and detectCycles\n\t\t\t// is only being called before the first Invoke, each node in the\n\t\t\t// graph will be tested as the first element of the path, so any\n\t\t\t// cycle that exists is guaranteed to trip the following condition.\n\t\t\tif path[0].Key == k {\n\t\t\t\terr = errCycleDetected{Path: append(path, entry)}\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\n\t\tfor _, n := range providers {\n\t\t\tif e := detectCycles(n, c, append(path, entry), visited); e != nil {\n\t\t\t\terr = e\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\n\t\treturn true\n\t}))\n\n\treturn err\n}\n"
  },
  {
    "path": "vendor/go.uber.org/dig/dig.go",
    "content": "// Copyright (c) 2018 Uber Technologies, Inc.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\npackage dig\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"math/rand\"\n\t\"reflect\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\t\"text/template\"\n\t\"time\"\n\n\t\"go.uber.org/dig/internal/digreflect\"\n\t\"go.uber.org/dig/internal/dot\"\n)\n\nconst (\n\t_optionalTag = \"optional\"\n\t_nameTag     = \"name\"\n\t_groupTag    = \"group\"\n)\n\n// Unique identification of an object in the graph.\ntype key struct {\n\tt reflect.Type\n\n\t// Only one of name or group will be set.\n\tname  string\n\tgroup string\n}\n\n// Option configures a Container. It's included for future functionality;\n// currently, there are no concrete implementations.\ntype Option interface {\n\tapplyOption(*Container)\n}\n\ntype optionFunc func(*Container)\n\nfunc (f optionFunc) applyOption(c *Container) { f(c) }\n\ntype provideOptions struct {\n\tName string\n}\n\nfunc (o *provideOptions) Validate() error {\n\t// Names must be representable inside a backquoted string. The only\n\t// limitation for raw string literals as per\n\t// https://golang.org/ref/spec#raw_string_lit is that they cannot contain\n\t// backquotes.\n\tif strings.ContainsRune(o.Name, '`') {\n\t\treturn fmt.Errorf(\"invalid dig.Name(%q): names cannot contain backquotes\", o.Name)\n\t}\n\treturn nil\n}\n\n// A ProvideOption modifies the default behavior of Provide.\ntype ProvideOption interface {\n\tapplyProvideOption(*provideOptions)\n}\n\ntype provideOptionFunc func(*provideOptions)\n\nfunc (f provideOptionFunc) applyProvideOption(opts *provideOptions) { f(opts) }\n\n// Name is a ProvideOption that specifies that all values produced by a\n// constructor should have the given name. See also the package documentation\n// about Named Values.\n//\n// Given,\n//\n//   func NewReadOnlyConnection(...) (*Connection, error)\n//   func NewReadWriteConnection(...) (*Connection, error)\n//\n// The following will provide two connections to the container: one under the\n// name \"ro\" and the other under the name \"rw\".\n//\n//   c.Provide(NewReadOnlyConnection, dig.Name(\"ro\"))\n//   c.Provide(NewReadWriteConnection, dig.Name(\"rw\"))\n//\n// This option cannot be provided for constructors which produce result\n// objects.\nfunc Name(name string) ProvideOption {\n\treturn provideOptionFunc(func(opts *provideOptions) {\n\t\topts.Name = name\n\t})\n}\n\n// An InvokeOption modifies the default behavior of Invoke. It's included for\n// future functionality; currently, there are no concrete implementations.\ntype InvokeOption interface {\n\tunimplemented()\n}\n\n// Container is a directed acyclic graph of types and their dependencies.\ntype Container struct {\n\t// Mapping from key to all the nodes that can provide a value for that\n\t// key.\n\tproviders map[key][]*node\n\n\t// All nodes in the container.\n\tnodes []*node\n\n\t// Values that have already been generated in the container.\n\tvalues map[key]reflect.Value\n\n\t// Values groups that have already been generated in the container.\n\tgroups map[key][]reflect.Value\n\n\t// Source of randomness.\n\trand *rand.Rand\n\n\t// Flag indicating whether the graph has been checked for cycles.\n\tisVerifiedAcyclic bool\n\n\t// Defer acyclic check on provide until Invoke.\n\tdeferAcyclicVerification bool\n}\n\n// containerWriter provides write access to the Container's underlying data\n// store.\ntype containerWriter interface {\n\t// setValue sets the value with the given name and type in the container.\n\t// If a value with the same name and type already exists, it will be\n\t// overwritten.\n\tsetValue(name string, t reflect.Type, v reflect.Value)\n\n\t// submitGroupedValue submits a value to the value group with the provided\n\t// name.\n\tsubmitGroupedValue(name string, t reflect.Type, v reflect.Value)\n}\n\n// containerStore provides access to the Container's underlying data store.\ntype containerStore interface {\n\tcontainerWriter\n\n\t// Returns a slice containing all known types.\n\tknownTypes() []reflect.Type\n\n\t// Retrieves the value with the provided name and type, if any.\n\tgetValue(name string, t reflect.Type) (v reflect.Value, ok bool)\n\n\t// Retrieves all values for the provided group and type.\n\t//\n\t// The order in which the values are returned is undefined.\n\tgetValueGroup(name string, t reflect.Type) []reflect.Value\n\n\t// Returns the providers that can produce a value with the given name and\n\t// type.\n\tgetValueProviders(name string, t reflect.Type) []provider\n\n\t// Returns the providers that can produce values for the given group and\n\t// type.\n\tgetGroupProviders(name string, t reflect.Type) []provider\n\n\tcreateGraph() *dot.Graph\n}\n\n// provider encapsulates a user-provided constructor.\ntype provider interface {\n\t// ID is a unique numerical identifier for this provider.\n\tID() dot.CtorID\n\n\t// Location returns where this constructor was defined.\n\tLocation() *digreflect.Func\n\n\t// ParamList returns information about the direct dependencies of this\n\t// constructor.\n\tParamList() paramList\n\n\t// ResultList returns information about the values produced by this\n\t// constructor.\n\tResultList() resultList\n\n\t// Calls the underlying constructor, reading values from the\n\t// containerStore as needed.\n\t//\n\t// The values produced by this provider should be submitted into the\n\t// containerStore.\n\tCall(containerStore) error\n}\n\n// New constructs a Container.\nfunc New(opts ...Option) *Container {\n\tc := &Container{\n\t\tproviders: make(map[key][]*node),\n\t\tvalues:    make(map[key]reflect.Value),\n\t\tgroups:    make(map[key][]reflect.Value),\n\t\trand:      rand.New(rand.NewSource(time.Now().UnixNano())),\n\t}\n\n\tfor _, opt := range opts {\n\t\topt.applyOption(c)\n\t}\n\treturn c\n}\n\n// DeferAcyclicVerification is an Option to override the default behavior\n// of container.Provide, deferring the dependency graph validation to no longer\n// run after each call to container.Provide. The container will instead verify\n// the graph on first `Invoke`.\n//\n// Applications adding providers to a container in a tight loop may experience\n// performance improvements by initializing the container with this option.\nfunc DeferAcyclicVerification() Option {\n\treturn optionFunc(func(c *Container) {\n\t\tc.deferAcyclicVerification = true\n\t})\n}\n\n// A VisualizeOption modifies the default behavior of Visualize.\ntype VisualizeOption interface {\n\tapplyVisualizeOption(*visualizeOptions)\n}\n\ntype visualizeOptions struct {\n\tVisualizeError error\n}\n\ntype visualizeOptionFunc func(*visualizeOptions)\n\nfunc (f visualizeOptionFunc) applyVisualizeOption(opts *visualizeOptions) { f(opts) }\n\n// VisualizeError includes a visualization of the given error in the output of\n// Visualize if an error was returned by Invoke or Provide.\n//\n//   if err := c.Provide(...); err != nil {\n//     dig.Visualize(c, w, dig.VisualizeError(err))\n//   }\n//\n// This option has no effect if the error was nil or if it didn't contain any\n// information to visualize.\nfunc VisualizeError(err error) VisualizeOption {\n\treturn visualizeOptionFunc(func(opts *visualizeOptions) {\n\t\topts.VisualizeError = err\n\t})\n}\n\nfunc updateGraph(dg *dot.Graph, err error) error {\n\tvar errors []errVisualizer\n\t// Unwrap error to find the root cause.\n\tfor {\n\t\tif ev, ok := err.(errVisualizer); ok {\n\t\t\terrors = append(errors, ev)\n\t\t}\n\t\te, ok := err.(causer)\n\t\tif !ok {\n\t\t\tbreak\n\t\t}\n\t\terr = e.cause()\n\t}\n\n\t// If there are no errVisualizers included, we do not modify the graph.\n\tif len(errors) == 0 {\n\t\treturn nil\n\t}\n\n\t// We iterate in reverse because the last element is the root cause.\n\tfor i := len(errors) - 1; i >= 0; i-- {\n\t\terrors[i].updateGraph(dg)\n\t}\n\n\treturn nil\n}\n\nvar _graphTmpl = template.Must(\n\ttemplate.New(\"DotGraph\").\n\t\tFuncs(template.FuncMap{\n\t\t\t\"quote\": strconv.Quote,\n\t\t}).\n\t\tParse(`digraph {\n\tgraph [compound=true];\n\t{{range $g := .Groups}}\n\t\t{{- quote .String}} [{{.Attributes}}];\n\t\t{{range .Results}}\n\t\t\t{{- quote $g.String}} -> {{quote .String}};\n\t\t{{end}}\n\t{{end -}}\n\t{{range $index, $ctor := .Ctors}}\n\t\tsubgraph cluster_{{$index}} {\n\t\t\tconstructor_{{$index}} [shape=plaintext label={{quote .Name}}];\n\t\t\t{{with .ErrorType}}color={{.Color}};{{end}}\n\t\t\t{{range .Results}}\n\t\t\t\t{{- quote .String}} [{{.Attributes}}];\n\t\t\t{{end}}\n\t\t}\n\t\t{{range .Params}}\n\t\t\tconstructor_{{$index}} -> {{quote .String}} [ltail=cluster_{{$index}}{{if .Optional}} style=dashed{{end}}];\n\t\t{{end}}\n\t\t{{range .GroupParams}}\n\t\t\tconstructor_{{$index}} -> {{quote .String}} [ltail=cluster_{{$index}}];\n\t\t{{end -}}\n\t{{end}}\n\t{{range .Failed.TransitiveFailures}}\n\t\t{{- quote .String}} [color=orange];\n\t{{end -}}\n\t{{range .Failed.RootCauses}}\n\t\t{{- quote .String}} [color=red];\n\t{{end}}\n}`))\n\n// Visualize parses the graph in Container c into DOT format and writes it to\n// io.Writer w.\nfunc Visualize(c *Container, w io.Writer, opts ...VisualizeOption) error {\n\tdg := c.createGraph()\n\n\tvar options visualizeOptions\n\tfor _, o := range opts {\n\t\to.applyVisualizeOption(&options)\n\t}\n\n\tif options.VisualizeError != nil {\n\t\tif err := updateGraph(dg, options.VisualizeError); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn _graphTmpl.Execute(w, dg)\n}\n\n// CanVisualizeError returns true if the error is an errVisualizer.\nfunc CanVisualizeError(err error) bool {\n\tfor {\n\t\tif _, ok := err.(errVisualizer); ok {\n\t\t\treturn true\n\t\t}\n\t\te, ok := err.(causer)\n\t\tif !ok {\n\t\t\tbreak\n\t\t}\n\t\terr = e.cause()\n\t}\n\n\treturn false\n}\n\nfunc (c *Container) createGraph() *dot.Graph {\n\tdg := dot.NewGraph()\n\n\tfor _, n := range c.nodes {\n\t\tdg.AddCtor(newDotCtor(n), n.paramList.DotParam(), n.resultList.DotResult())\n\t}\n\n\treturn dg\n}\n\n// Changes the source of randomness for the container.\n//\n// This will help provide determinism during tests.\nfunc setRand(r *rand.Rand) Option {\n\treturn optionFunc(func(c *Container) {\n\t\tc.rand = r\n\t})\n}\n\nfunc (c *Container) knownTypes() []reflect.Type {\n\ttypeSet := make(map[reflect.Type]struct{}, len(c.providers))\n\tfor k := range c.providers {\n\t\ttypeSet[k.t] = struct{}{}\n\t}\n\n\ttypes := make([]reflect.Type, 0, len(typeSet))\n\tfor t := range typeSet {\n\t\ttypes = append(types, t)\n\t}\n\tsort.Sort(byTypeName(types))\n\treturn types\n}\n\nfunc (c *Container) getValue(name string, t reflect.Type) (v reflect.Value, ok bool) {\n\tv, ok = c.values[key{name: name, t: t}]\n\treturn\n}\n\nfunc (c *Container) setValue(name string, t reflect.Type, v reflect.Value) {\n\tc.values[key{name: name, t: t}] = v\n}\n\nfunc (c *Container) getValueGroup(name string, t reflect.Type) []reflect.Value {\n\titems := c.groups[key{group: name, t: t}]\n\t// shuffle the list so users don't rely on the ordering of grouped values\n\treturn shuffledCopy(c.rand, items)\n}\n\nfunc (c *Container) submitGroupedValue(name string, t reflect.Type, v reflect.Value) {\n\tk := key{group: name, t: t}\n\tc.groups[k] = append(c.groups[k], v)\n}\n\nfunc (c *Container) getValueProviders(name string, t reflect.Type) []provider {\n\treturn c.getProviders(key{name: name, t: t})\n}\n\nfunc (c *Container) getGroupProviders(name string, t reflect.Type) []provider {\n\treturn c.getProviders(key{group: name, t: t})\n}\n\nfunc (c *Container) getProviders(k key) []provider {\n\tnodes := c.providers[k]\n\tproviders := make([]provider, len(nodes))\n\tfor i, n := range nodes {\n\t\tproviders[i] = n\n\t}\n\treturn providers\n}\n\n// Provide teaches the container how to build values of one or more types and\n// expresses their dependencies.\n//\n// The first argument of Provide is a function that accepts zero or more\n// parameters and returns one or more results. The function may optionally\n// return an error to indicate that it failed to build the value. This\n// function will be treated as the constructor for all the types it returns.\n// This function will be called AT MOST ONCE when a type produced by it, or a\n// type that consumes this function's output, is requested via Invoke. If the\n// same types are requested multiple times, the previously produced value will\n// be reused.\n//\n// In addition to accepting constructors that accept dependencies as separate\n// arguments and produce results as separate return values, Provide also\n// accepts constructors that specify dependencies as dig.In structs and/or\n// specify results as dig.Out structs.\nfunc (c *Container) Provide(constructor interface{}, opts ...ProvideOption) error {\n\tctype := reflect.TypeOf(constructor)\n\tif ctype == nil {\n\t\treturn errors.New(\"can't provide an untyped nil\")\n\t}\n\tif ctype.Kind() != reflect.Func {\n\t\treturn fmt.Errorf(\"must provide constructor function, got %v (type %v)\", constructor, ctype)\n\t}\n\n\tvar options provideOptions\n\tfor _, o := range opts {\n\t\to.applyProvideOption(&options)\n\t}\n\tif err := options.Validate(); err != nil {\n\t\treturn err\n\t}\n\n\tif err := c.provide(constructor, options); err != nil {\n\t\treturn errProvide{\n\t\t\tFunc:   digreflect.InspectFunc(constructor),\n\t\t\tReason: err,\n\t\t}\n\t}\n\treturn nil\n}\n\n// Invoke runs the given function after instantiating its dependencies.\n//\n// Any arguments that the function has are treated as its dependencies. The\n// dependencies are instantiated in an unspecified order along with any\n// dependencies that they might have.\n//\n// The function may return an error to indicate failure. The error will be\n// returned to the caller as-is.\nfunc (c *Container) Invoke(function interface{}, opts ...InvokeOption) error {\n\tftype := reflect.TypeOf(function)\n\tif ftype == nil {\n\t\treturn errors.New(\"can't invoke an untyped nil\")\n\t}\n\tif ftype.Kind() != reflect.Func {\n\t\treturn fmt.Errorf(\"can't invoke non-function %v (type %v)\", function, ftype)\n\t}\n\n\tpl, err := newParamList(ftype)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err := shallowCheckDependencies(c, pl); err != nil {\n\t\treturn errMissingDependencies{\n\t\t\tFunc:   digreflect.InspectFunc(function),\n\t\t\tReason: err,\n\t\t}\n\t}\n\n\tif !c.isVerifiedAcyclic {\n\t\tif err := c.verifyAcyclic(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\targs, err := pl.BuildList(c)\n\tif err != nil {\n\t\treturn errArgumentsFailed{\n\t\t\tFunc:   digreflect.InspectFunc(function),\n\t\t\tReason: err,\n\t\t}\n\t}\n\n\treturned := reflect.ValueOf(function).Call(args)\n\tif len(returned) == 0 {\n\t\treturn nil\n\t}\n\tif last := returned[len(returned)-1]; isError(last.Type()) {\n\t\tif err, _ := last.Interface().(error); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (c *Container) verifyAcyclic() error {\n\tvisited := make(map[key]struct{})\n\tfor _, n := range c.nodes {\n\t\tif err := detectCycles(n, c, nil /* path */, visited); err != nil {\n\t\t\treturn errWrapf(err, \"cycle detected in dependency graph\")\n\t\t}\n\t}\n\n\tc.isVerifiedAcyclic = true\n\treturn nil\n}\n\nfunc (c *Container) provide(ctor interface{}, opts provideOptions) error {\n\tn, err := newNode(ctor, nodeOptions{ResultName: opts.Name})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tkeys, err := c.findAndValidateResults(n)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tctype := reflect.TypeOf(ctor)\n\tif len(keys) == 0 {\n\t\treturn fmt.Errorf(\"%v must provide at least one non-error type\", ctype)\n\t}\n\n\tfor k := range keys {\n\t\tc.isVerifiedAcyclic = false\n\t\toldProviders := c.providers[k]\n\t\tc.providers[k] = append(c.providers[k], n)\n\n\t\tif c.deferAcyclicVerification {\n\t\t\tcontinue\n\t\t}\n\t\tif err := verifyAcyclic(c, n, k); err != nil {\n\t\t\tc.providers[k] = oldProviders\n\t\t\treturn err\n\t\t}\n\t\tc.isVerifiedAcyclic = true\n\t}\n\n\tc.nodes = append(c.nodes, n)\n\n\treturn nil\n}\n\n// Builds a collection of all result types produced by this node.\nfunc (c *Container) findAndValidateResults(n *node) (map[key]struct{}, error) {\n\tvar err error\n\tkeyPaths := make(map[key]string)\n\twalkResult(n.ResultList(), connectionVisitor{\n\t\tc:        c,\n\t\tn:        n,\n\t\terr:      &err,\n\t\tkeyPaths: keyPaths,\n\t})\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tkeys := make(map[key]struct{}, len(keyPaths))\n\tfor k := range keyPaths {\n\t\tkeys[k] = struct{}{}\n\t}\n\treturn keys, nil\n}\n\n// Visits the results of a node and compiles a collection of all the keys\n// produced by that node.\ntype connectionVisitor struct {\n\tc *Container\n\tn *node\n\n\t// If this points to a non-nil value, we've already encountered an error\n\t// and should stop traversing.\n\terr *error\n\n\t// Map of keys provided to path that provided this. The path is a string\n\t// documenting which positional return value or dig.Out attribute is\n\t// providing this particular key.\n\t//\n\t// For example, \"[0].Foo\" indicates that the value was provided by the Foo\n\t// attribute of the dig.Out returned as the first result of the\n\t// constructor.\n\tkeyPaths map[key]string\n\n\t// We track the path to the current result here. For example, this will\n\t// be, [\"[1]\", \"Foo\", \"Bar\"] when we're visiting Bar in,\n\t//\n\t//   func() (io.Writer, struct {\n\t//     dig.Out\n\t//\n\t//     Foo struct {\n\t//       dig.Out\n\t//\n\t//       Bar io.Reader\n\t//     }\n\t//   })\n\tcurrentResultPath []string\n}\n\nfunc (cv connectionVisitor) AnnotateWithField(f resultObjectField) resultVisitor {\n\tcv.currentResultPath = append(cv.currentResultPath, f.FieldName)\n\treturn cv\n}\n\nfunc (cv connectionVisitor) AnnotateWithPosition(i int) resultVisitor {\n\tcv.currentResultPath = append(cv.currentResultPath, fmt.Sprintf(\"[%d]\", i))\n\treturn cv\n}\n\nfunc (cv connectionVisitor) Visit(res result) resultVisitor {\n\t// Already failed. Stop looking.\n\tif *cv.err != nil {\n\t\treturn nil\n\t}\n\n\tpath := strings.Join(cv.currentResultPath, \".\")\n\n\tswitch r := res.(type) {\n\tcase resultSingle:\n\t\tk := key{name: r.Name, t: r.Type}\n\n\t\tif conflict, ok := cv.keyPaths[k]; ok {\n\t\t\t*cv.err = fmt.Errorf(\n\t\t\t\t\"cannot provide %v from %v: already provided by %v\",\n\t\t\t\tk, path, conflict)\n\t\t\treturn nil\n\t\t}\n\n\t\tif ps := cv.c.providers[k]; len(ps) > 0 {\n\t\t\tcons := make([]string, len(ps))\n\t\t\tfor i, p := range ps {\n\t\t\t\tcons[i] = fmt.Sprint(p.Location())\n\t\t\t}\n\n\t\t\t*cv.err = fmt.Errorf(\n\t\t\t\t\"cannot provide %v from %v: already provided by %v\",\n\t\t\t\tk, path, strings.Join(cons, \"; \"))\n\t\t\treturn nil\n\t\t}\n\n\t\tcv.keyPaths[k] = path\n\n\tcase resultGrouped:\n\t\t// we don't really care about the path for this since conflicts are\n\t\t// okay for group results. We'll track it for the sake of having a\n\t\t// value there.\n\t\tk := key{group: r.Group, t: r.Type}\n\t\tcv.keyPaths[k] = path\n\t}\n\n\treturn cv\n}\n\n// node is a node in the dependency graph. Each node maps to a single\n// constructor provided by the user.\n//\n// Nodes can produce zero or more values that they store into the container.\n// For the Provide path, we verify that nodes produce at least one value,\n// otherwise the function will never be called.\ntype node struct {\n\tctor  interface{}\n\tctype reflect.Type\n\n\t// Location where this function was defined.\n\tlocation *digreflect.Func\n\n\t// id uniquely identifies the constructor that produces a node.\n\tid dot.CtorID\n\n\t// Whether the constructor owned by this node was already called.\n\tcalled bool\n\n\t// Type information about constructor parameters.\n\tparamList paramList\n\n\t// Type information about constructor results.\n\tresultList resultList\n}\n\ntype nodeOptions struct {\n\t// If specified, all values produced by this node have the provided name.\n\tResultName string\n}\n\nfunc newNode(ctor interface{}, opts nodeOptions) (*node, error) {\n\tcval := reflect.ValueOf(ctor)\n\tctype := cval.Type()\n\tcptr := cval.Pointer()\n\n\tparams, err := newParamList(ctype)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tresults, err := newResultList(ctype, resultOptions{Name: opts.ResultName})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &node{\n\t\tctor:       ctor,\n\t\tctype:      ctype,\n\t\tlocation:   digreflect.InspectFunc(ctor),\n\t\tid:         dot.CtorID(cptr),\n\t\tparamList:  params,\n\t\tresultList: results,\n\t}, err\n}\n\nfunc (n *node) Location() *digreflect.Func { return n.location }\nfunc (n *node) ParamList() paramList       { return n.paramList }\nfunc (n *node) ResultList() resultList     { return n.resultList }\nfunc (n *node) ID() dot.CtorID             { return n.id }\n\n// Call calls this node's constructor if it hasn't already been called and\n// injects any values produced by it into the provided container.\nfunc (n *node) Call(c containerStore) error {\n\tif n.called {\n\t\treturn nil\n\t}\n\n\tif err := shallowCheckDependencies(c, n.paramList); err != nil {\n\t\treturn errMissingDependencies{\n\t\t\tFunc:   n.location,\n\t\t\tReason: err,\n\t\t}\n\t}\n\n\targs, err := n.paramList.BuildList(c)\n\tif err != nil {\n\t\treturn errArgumentsFailed{\n\t\t\tFunc:   n.location,\n\t\t\tReason: err,\n\t\t}\n\t}\n\n\treceiver := newStagingContainerWriter()\n\tresults := reflect.ValueOf(n.ctor).Call(args)\n\tif err := n.resultList.ExtractList(receiver, results); err != nil {\n\t\treturn errConstructorFailed{Func: n.location, Reason: err}\n\t}\n\treceiver.Commit(c)\n\tn.called = true\n\treturn nil\n}\n\n// Checks if a field of an In struct is optional.\nfunc isFieldOptional(f reflect.StructField) (bool, error) {\n\ttag := f.Tag.Get(_optionalTag)\n\tif tag == \"\" {\n\t\treturn false, nil\n\t}\n\n\toptional, err := strconv.ParseBool(tag)\n\tif err != nil {\n\t\terr = errWrapf(err,\n\t\t\t\"invalid value %q for %q tag on field %v\",\n\t\t\ttag, _optionalTag, f.Name)\n\t}\n\n\treturn optional, err\n}\n\n// Checks that all direct dependencies of the provided param are present in\n// the container. Returns an error if not.\nfunc shallowCheckDependencies(c containerStore, p param) error {\n\tvar missing errMissingManyTypes\n\tvar addMissingNodes []*dot.Param\n\twalkParam(p, paramVisitorFunc(func(p param) bool {\n\t\tps, ok := p.(paramSingle)\n\t\tif !ok {\n\t\t\treturn true\n\t\t}\n\n\t\tif ns := c.getValueProviders(ps.Name, ps.Type); len(ns) == 0 && !ps.Optional {\n\t\t\tmissing = append(missing, newErrMissingType(c, key{name: ps.Name, t: ps.Type}))\n\t\t\taddMissingNodes = append(addMissingNodes, ps.DotParam()...)\n\t\t}\n\n\t\treturn true\n\t}))\n\n\tif len(missing) > 0 {\n\t\treturn missing\n\t}\n\treturn nil\n}\n\n// stagingContainerWriter is a containerWriter that records the changes that\n// would be made to a containerWriter and defers them until Commit is called.\ntype stagingContainerWriter struct {\n\tvalues map[key]reflect.Value\n\tgroups map[key][]reflect.Value\n}\n\nvar _ containerWriter = (*stagingContainerWriter)(nil)\n\nfunc newStagingContainerWriter() *stagingContainerWriter {\n\treturn &stagingContainerWriter{\n\t\tvalues: make(map[key]reflect.Value),\n\t\tgroups: make(map[key][]reflect.Value),\n\t}\n}\n\nfunc (sr *stagingContainerWriter) setValue(name string, t reflect.Type, v reflect.Value) {\n\tsr.values[key{t: t, name: name}] = v\n}\n\nfunc (sr *stagingContainerWriter) submitGroupedValue(group string, t reflect.Type, v reflect.Value) {\n\tk := key{t: t, group: group}\n\tsr.groups[k] = append(sr.groups[k], v)\n}\n\n// Commit commits the received results to the provided containerWriter.\nfunc (sr *stagingContainerWriter) Commit(cw containerWriter) {\n\tfor k, v := range sr.values {\n\t\tcw.setValue(k.name, k.t, v)\n\t}\n\n\tfor k, vs := range sr.groups {\n\t\tfor _, v := range vs {\n\t\t\tcw.submitGroupedValue(k.group, k.t, v)\n\t\t}\n\t}\n}\n\ntype byTypeName []reflect.Type\n\nfunc (bs byTypeName) Len() int {\n\treturn len(bs)\n}\n\nfunc (bs byTypeName) Less(i int, j int) bool {\n\treturn fmt.Sprint(bs[i]) < fmt.Sprint(bs[j])\n}\n\nfunc (bs byTypeName) Swap(i int, j int) {\n\tbs[i], bs[j] = bs[j], bs[i]\n}\n\nfunc shuffledCopy(rand *rand.Rand, items []reflect.Value) []reflect.Value {\n\tnewItems := make([]reflect.Value, len(items))\n\tfor i, j := range rand.Perm(len(items)) {\n\t\tnewItems[i] = items[j]\n\t}\n\treturn newItems\n}\n\nfunc newDotCtor(n *node) *dot.Ctor {\n\treturn &dot.Ctor{\n\t\tID:      n.id,\n\t\tName:    n.location.Name,\n\t\tPackage: n.location.Package,\n\t\tFile:    n.location.File,\n\t\tLine:    n.location.Line,\n\t}\n}\n"
  },
  {
    "path": "vendor/go.uber.org/dig/doc.go",
    "content": "// Copyright (c) 2018 Uber Technologies, Inc.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\n// Package dig provides an opinionated way of resolving object dependencies.\n//\n// Status\n//\n// STABLE. No breaking changes will be made in this major version.\n//\n// Container\n//\n// Dig exposes type Container as an object capable of resolving a directed\n// acyclic dependency graph. Use the New function to create one.\n//\n//   c := dig.New()\n//\n// Provide\n//\n// Constructors for different types are added to the container by using the\n// Provide method. A constructor can declare a dependency on another type by\n// simply adding it as a function parameter. Dependencies for a type can be\n// added to the graph both, before and after the type was added.\n//\n//   err := c.Provide(func(conn *sql.DB) (*UserGateway, error) {\n//     // ...\n//   })\n//   if err != nil {\n//     // ...\n//   }\n//\n//   if err := c.Provide(newDBConnection); err != nil {\n//     // ...\n//   }\n//\n// Multiple constructors can rely on the same type. The container creates a\n// singleton for each retained type, instantiating it at most once when\n// requested directly or as a dependency of another type.\n//\n//   err := c.Provide(func(conn *sql.DB) *CommentGateway {\n//     // ...\n//   })\n//   if err != nil {\n//     // ...\n//   }\n//\n// Constructors can declare any number of dependencies as parameters and\n// optionally, return errors.\n//\n//   err := c.Provide(func(u *UserGateway, c *CommentGateway) (*RequestHandler, error) {\n//     // ...\n//   })\n//   if err != nil {\n//     // ...\n//   }\n//\n//   if err := c.Provide(newHTTPServer); err != nil {\n//     // ...\n//   }\n//\n// Constructors can also return multiple results to add multiple types to the\n// container.\n//\n//   err := c.Provide(func(conn *sql.DB) (*UserGateway, *CommentGateway, error) {\n//     // ...\n//   })\n//   if err != nil {\n//     // ...\n//   }\n//\n// Constructors that accept a variadic number of arguments are treated as if\n// they don't have those arguments. That is,\n//\n//   func NewVoteGateway(db *sql.DB, options ...Option) *VoteGateway\n//\n// Is treated the same as,\n//\n//   func NewVoteGateway(db *sql.DB) *VoteGateway\n//\n// The constructor will be called with all other dependencies and no variadic\n// arguments.\n//\n// Invoke\n//\n// Types added to to the container may be consumed by using the Invoke method.\n// Invoke accepts any function that accepts one or more parameters and\n// optionally, returns an error. Dig calls the function with the requested\n// type, instantiating only those types that were requested by the function.\n// The call fails if any type or its dependencies (both direct and transitive)\n// were not available in the container.\n//\n//   err := c.Invoke(func(l *log.Logger) {\n//     // ...\n//   })\n//   if err != nil {\n//     // ...\n//   }\n//\n//   err := c.Invoke(func(server *http.Server) error {\n//     // ...\n//   })\n//   if err != nil {\n//     // ...\n//   }\n//\n// Any error returned by the invoked function is propagated back to the\n// caller.\n//\n// Parameter Objects\n//\n// Constructors declare their dependencies as function parameters. This can\n// very quickly become unreadable if the constructor has a lot of\n// dependencies.\n//\n//   func NewHandler(users *UserGateway, comments *CommentGateway, posts *PostGateway, votes *VoteGateway, authz *AuthZGateway) *Handler {\n//     // ...\n//   }\n//\n// A pattern employed to improve readability in a situation like this is to\n// create a struct that lists all the parameters of the function as fields and\n// changing the function to accept that struct instead. This is referred to as\n// a parameter object.\n//\n// Dig has first class support for parameter objects: any struct embedding\n// dig.In gets treated as a parameter object. The following is equivalent to\n// the constructor above.\n//\n//   type HandlerParams struct {\n//     dig.In\n//\n//     Users    *UserGateway\n//     Comments *CommentGateway\n//     Posts    *PostGateway\n//     Votes    *VoteGateway\n//     AuthZ    *AuthZGateway\n//   }\n//\n//   func NewHandler(p HandlerParams) *Handler {\n//     // ...\n//   }\n//\n// Handlers can receive any combination of parameter objects and parameters.\n//\n//   func NewHandler(p HandlerParams, l *log.Logger) *Handler {\n//     // ...\n//   }\n//\n// Result Objects\n//\n// Result objects are the flip side of parameter objects. These are structs\n// that represent multiple outputs from a single function as fields in the\n// struct. Structs embedding dig.Out get treated as result objects.\n//\n//   func SetupGateways(conn *sql.DB) (*UserGateway, *CommentGateway, *PostGateway, error) {\n//     // ...\n//   }\n//\n// The above is equivalent to,\n//\n//  type Gateways struct {\n//    dig.Out\n//\n//    Users    *UserGateway\n//    Comments *CommentGateway\n//    Posts    *PostGateway\n//  }\n//\n//  func SetupGateways(conn *sql.DB) (Gateways, error) {\n//    // ...\n//  }\n//\n// Optional Dependencies\n//\n// Constructors often don't have a hard dependency on some types and\n// are able to operate in a degraded state when that dependency is missing.\n// Dig supports declaring dependencies as optional by adding an\n// `optional:\"true\"` tag to fields of a dig.In struct.\n//\n// Fields in a dig.In structs that have the `optional:\"true\"` tag are treated\n// as optional by Dig.\n//\n//   type UserGatewayParams struct {\n//     dig.In\n//\n//     Conn  *sql.DB\n//     Cache *redis.Client `optional:\"true\"`\n//   }\n//\n// If an optional field is not available in the container, the constructor\n// will receive a zero value for the field.\n//\n//   func NewUserGateway(p UserGatewayParams, log *log.Logger) (*UserGateway, error) {\n//     if p.Cache != nil {\n//       log.Print(\"Logging disabled\")\n//     }\n//     // ...\n//   }\n//\n// Constructors that declare dependencies as optional MUST handle the case of\n// those dependencies being absent.\n//\n// The optional tag also allows adding new dependencies without breaking\n// existing consumers of the constructor.\n//\n// Named Values\n//\n// Some use cases call for multiple values of the same type. Dig allows adding\n// multiple values of the same type to the container with the use of Named\n// Values.\n//\n// Named Values can be produced by passing the dig.Name option when a\n// constructor is provided. All values produced by that constructor will have\n// the given name.\n//\n// Given the following constructors,\n//\n//   func NewReadOnlyConnection(...) (*sql.DB, error)\n//   func NewReadWriteConnection(...) (*sql.DB, error)\n//\n// You can provide *sql.DB into a Container under different names by passing\n// the dig.Name option.\n//\n//   c.Provide(NewReadOnlyConnection, dig.Name(\"ro\"))\n//   c.Provide(NewReadWriteConnection, dig.Name(\"rw\"))\n//\n// Alternatively, you can produce a dig.Out struct and tag its fields with\n// `name:\"..\"` to have the corresponding value added to the graph under the\n// specified name.\n//\n//   type ConnectionResult struct {\n//     dig.Out\n//\n//     ReadWrite *sql.DB `name:\"rw\"`\n//     ReadOnly  *sql.DB `name:\"ro\"`\n//   }\n//\n//   func ConnectToDatabase(...) (ConnectionResult, error) {\n//     // ...\n//     return ConnectionResult{ReadWrite: rw, ReadOnly:  ro}, nil\n//   }\n//\n// Regardless of how a Named Value was produced, it can be consumed by another\n// constructor by accepting a dig.In struct which has exported fields with the\n// same name AND type that you provided.\n//\n//   type GatewayParams struct {\n//     dig.In\n//\n//     WriteToConn  *sql.DB `name:\"rw\"`\n//     ReadFromConn *sql.DB `name:\"ro\"`\n//   }\n//\n// The name tag may be combined with the optional tag to declare the\n// dependency optional.\n//\n//   type GatewayParams struct {\n//     dig.In\n//\n//     WriteToConn  *sql.DB `name:\"rw\"`\n//     ReadFromConn *sql.DB `name:\"ro\" optional:\"true\"`\n//   }\n//\n//   func NewCommentGateway(p GatewayParams, log *log.Logger) (*CommentGateway, error) {\n//     if p.ReadFromConn == nil {\n//       log.Print(\"Warning: Using RW connection for reads\")\n//       p.ReadFromConn = p.WriteToConn\n//     }\n//     // ...\n//   }\n//\n// Value Groups\n//\n// Added in Dig 1.2.\n//\n// Dig provides value groups to allow producing and consuming many values of\n// the same type. Value groups allow constructors to send values to a named,\n// unordered collection in the container. Other constructors can request all\n// values in this collection as a slice.\n//\n// Constructors can send values into value groups by returning a dig.Out\n// struct tagged with `group:\"..\"`.\n//\n//   type HandlerResult struct {\n//     dig.Out\n//\n//     Handler Handler `group:\"server\"`\n//   }\n//\n//   func NewHelloHandler() HandlerResult {\n//     ..\n//   }\n//\n//   func NewEchoHandler() HandlerResult {\n//     ..\n//   }\n//\n// Any number of constructors may provide values to this named collection.\n// Other constructors can request all values for this collection by requesting\n// a slice tagged with `group:\"..\"`. This will execute all constructors that\n// provide a value to that group in an unspecified order.\n//\n//   type ServerParams struct {\n//     dig.In\n//\n//     Handlers []Handler `group:\"server\"`\n//   }\n//\n//   func NewServer(p ServerParams) *Server {\n//     server := newServer()\n//     for _, h := range p.Handlers {\n//       server.Register(h)\n//     }\n//     return server\n//   }\n//\n// Note that values in a value group are unordered. Dig makes no guarantees\n// about the order in which these values will be produced.\npackage dig // import \"go.uber.org/dig\"\n"
  },
  {
    "path": "vendor/go.uber.org/dig/error.go",
    "content": "// Copyright (c) 2018 Uber Technologies, Inc.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\npackage dig\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"sort\"\n\n\t\"go.uber.org/dig/internal/digreflect\"\n\t\"go.uber.org/dig/internal/dot\"\n)\n\n// Errors which know their underlying cause should implement this interface to\n// be compatible with RootCause.\n//\n// We use an unexported \"cause\" method instead of \"Cause\" because we don't\n// want dig-internal causes to be confused with the cause of the user-provided\n// errors. (For example, if the users are using github.com/pkg/errors.)\ntype causer interface {\n\tcause() error\n}\n\n// RootCause returns the original error that caused the provided dig failure.\n//\n// RootCause may be used on errors returned by Invoke to get the original\n// error returned by a constructor or invoked function.\nfunc RootCause(err error) error {\n\tfor {\n\t\tif e, ok := err.(causer); ok {\n\t\t\terr = e.cause()\n\t\t} else {\n\t\t\treturn err\n\t\t}\n\t}\n}\n\n// errWrapf wraps an existing error with more contextual information.\n//\n// The given error is treated as the cause of the returned error (see causer).\n//\n//   RootCause(errWrapf(errWrapf(err, ...), ...)) == err\n//\n// Use errWrapf instead of fmt.Errorf if the message ends with \": <original error>\".\nfunc errWrapf(err error, msg string, args ...interface{}) error {\n\tif err == nil {\n\t\treturn nil\n\t}\n\n\tif len(args) > 0 {\n\t\tmsg = fmt.Sprintf(msg, args...)\n\t}\n\n\treturn wrappedError{err: err, msg: msg}\n}\n\ntype wrappedError struct {\n\terr error\n\tmsg string\n}\n\nfunc (e wrappedError) cause() error { return e.err }\n\nfunc (e wrappedError) Error() string {\n\treturn fmt.Sprintf(\"%v: %v\", e.msg, e.err)\n}\n\n// errProvide is returned when a constructor could not be Provided into the\n// container.\ntype errProvide struct {\n\tFunc   *digreflect.Func\n\tReason error\n}\n\nfunc (e errProvide) cause() error { return e.Reason }\n\nfunc (e errProvide) Error() string {\n\treturn fmt.Sprintf(\"function %v cannot be provided: %v\", e.Func, e.Reason)\n}\n\n// errConstructorFailed is returned when a user-provided constructor failed\n// with a non-nil error.\ntype errConstructorFailed struct {\n\tFunc   *digreflect.Func\n\tReason error\n}\n\nfunc (e errConstructorFailed) cause() error { return e.Reason }\n\nfunc (e errConstructorFailed) Error() string {\n\treturn fmt.Sprintf(\"function %v returned a non-nil error: %v\", e.Func, e.Reason)\n}\n\n// errArgumentsFailed is returned when a function could not be run because one\n// of its dependencies failed to build for any reason.\ntype errArgumentsFailed struct {\n\tFunc   *digreflect.Func\n\tReason error\n}\n\nfunc (e errArgumentsFailed) cause() error { return e.Reason }\n\nfunc (e errArgumentsFailed) Error() string {\n\treturn fmt.Sprintf(\"could not build arguments for function %v: %v\", e.Func, e.Reason)\n}\n\n// errMissingDependencies is returned when the dependencies of a function are\n// not available in the container.\ntype errMissingDependencies struct {\n\tFunc   *digreflect.Func\n\tReason error\n}\n\nfunc (e errMissingDependencies) cause() error { return e.Reason }\n\nfunc (e errMissingDependencies) Error() string {\n\treturn fmt.Sprintf(\"missing dependencies for function %v: %v\", e.Func, e.Reason)\n}\n\n// errParamSingleFailed is returned when a paramSingle could not be built.\ntype errParamSingleFailed struct {\n\tKey    key\n\tReason error\n\tCtorID dot.CtorID\n}\n\nfunc (e errParamSingleFailed) cause() error { return e.Reason }\n\nfunc (e errParamSingleFailed) Error() string {\n\treturn fmt.Sprintf(\"failed to build %v: %v\", e.Key, e.Reason)\n}\n\nfunc (e errParamSingleFailed) updateGraph(g *dot.Graph) {\n\tfailed := &dot.Result{\n\t\tNode: &dot.Node{\n\t\t\tName:  e.Key.name,\n\t\t\tGroup: e.Key.group,\n\t\t\tType:  e.Key.t,\n\t\t},\n\t}\n\tg.FailNodes([]*dot.Result{failed}, e.CtorID)\n}\n\n// errParamGroupFailed is returned when a value group cannot be built because\n// any of the values in the group failed to build.\ntype errParamGroupFailed struct {\n\tKey    key\n\tReason error\n\tCtorID dot.CtorID\n}\n\nfunc (e errParamGroupFailed) cause() error { return e.Reason }\n\nfunc (e errParamGroupFailed) Error() string {\n\treturn fmt.Sprintf(\"could not build value group %v: %v\", e.Key, e.Reason)\n}\n\nfunc (e errParamGroupFailed) updateGraph(g *dot.Graph) {\n\tg.FailGroupNodes(e.Key.group, e.Key.t, e.CtorID)\n}\n\n// errMissingType is returned when a single value that was expected in the\n// container was not available.\ntype errMissingType struct {\n\tKey key\n\n\t// If non-empty, we will include suggestions for what the user may have\n\t// meant.\n\tsuggestions []key\n}\n\nfunc newErrMissingType(c containerStore, k key) errMissingType {\n\t// Possible types we will look for in the container. We will always look\n\t// for pointers to the requested type and some extras on a per-Kind basis.\n\n\tsuggestions := []reflect.Type{reflect.PtrTo(k.t)}\n\tif k.t.Kind() == reflect.Ptr {\n\t\t// The user requested a pointer but maybe we have a value.\n\t\tsuggestions = append(suggestions, k.t.Elem())\n\t}\n\n\tknownTypes := c.knownTypes()\n\tif k.t.Kind() == reflect.Interface {\n\t\t// Maybe we have an implementation of the interface.\n\t\tfor _, t := range knownTypes {\n\t\t\tif t.Implements(k.t) {\n\t\t\t\tsuggestions = append(suggestions, t)\n\t\t\t}\n\t\t}\n\t} else {\n\t\t// Maybe we have an interface that this type implements.\n\t\tfor _, t := range knownTypes {\n\t\t\tif t.Kind() == reflect.Interface {\n\t\t\t\tif k.t.Implements(t) {\n\t\t\t\t\tsuggestions = append(suggestions, t)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// range through c.providers is non-deterministic. Let's sort the list of\n\t// suggestions.\n\tsort.Sort(byTypeName(suggestions))\n\n\terr := errMissingType{Key: k}\n\tfor _, t := range suggestions {\n\t\tif len(c.getValueProviders(k.name, t)) > 0 {\n\t\t\tk.t = t\n\t\t\terr.suggestions = append(err.suggestions, k)\n\t\t}\n\t}\n\n\treturn err\n}\n\nfunc (e errMissingType) Error() string {\n\t// Sample messages:\n\t//\n\t//   type io.Reader is not in the container, did you mean to Provide it?\n\t//   type io.Reader is not in the container, did you mean to use one of *bytes.Buffer, *MyBuffer\n\t//   type bytes.Buffer is not in the container, did you mean to use *bytes.Buffer?\n\t//   type *foo[name=\"bar\"] is not in the container, did you mean to use foo[name=\"bar\"]?\n\n\tb := new(bytes.Buffer)\n\n\tfmt.Fprintf(b, \"type %v is not in the container\", e.Key)\n\tswitch len(e.suggestions) {\n\tcase 0:\n\t\tb.WriteString(\", did you mean to Provide it?\")\n\tcase 1:\n\t\tfmt.Fprintf(b, \", did you mean to use %v?\", e.suggestions[0])\n\tdefault:\n\t\tb.WriteString(\", did you mean to use one of \")\n\t\tfor i, k := range e.suggestions {\n\t\t\tif i > 0 {\n\t\t\t\tb.WriteString(\", \")\n\t\t\t\tif i == len(e.suggestions)-1 {\n\t\t\t\t\tb.WriteString(\"or \")\n\t\t\t\t}\n\t\t\t}\n\t\t\tfmt.Fprint(b, k)\n\t\t}\n\t\tb.WriteString(\"?\")\n\t}\n\n\treturn b.String()\n}\n\n// errMissingManyTypes combines multiple errMissingType errors.\ntype errMissingManyTypes []errMissingType // length must be non-zero\n\nfunc (e errMissingManyTypes) Error() string {\n\tif len(e) == 1 {\n\t\treturn e[0].Error()\n\t}\n\n\tb := new(bytes.Buffer)\n\n\tb.WriteString(\"the following types are not in the container: \")\n\tfor i, err := range e {\n\t\tif i > 0 {\n\t\t\tb.WriteString(\"; \")\n\t\t}\n\t\tfmt.Fprintf(b, \"%v\", err.Key)\n\t\tswitch len(err.suggestions) {\n\t\tcase 0:\n\t\t\t// do nothing\n\t\tcase 1:\n\t\t\tfmt.Fprintf(b, \" (did you mean %v?)\", err.suggestions[0])\n\t\tdefault:\n\t\t\tb.WriteString(\" (did you mean \")\n\t\t\tfor i, k := range err.suggestions {\n\t\t\t\tif i > 0 {\n\t\t\t\t\tb.WriteString(\", \")\n\t\t\t\t\tif i == len(err.suggestions)-1 {\n\t\t\t\t\t\tb.WriteString(\"or \")\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfmt.Fprint(b, k)\n\t\t\t}\n\t\t\tb.WriteString(\"?)\")\n\t\t}\n\t}\n\n\treturn b.String()\n}\n\nfunc (e errMissingManyTypes) updateGraph(g *dot.Graph) {\n\tmissing := make([]*dot.Result, len(e))\n\n\tfor i, err := range e {\n\t\tmissing[i] = &dot.Result{\n\t\t\tNode: &dot.Node{\n\t\t\t\tName:  err.Key.name,\n\t\t\t\tGroup: err.Key.group,\n\t\t\t\tType:  err.Key.t,\n\t\t\t},\n\t\t}\n\t}\n\tg.AddMissingNodes(missing)\n}\n\ntype errVisualizer interface {\n\tupdateGraph(*dot.Graph)\n}\n"
  },
  {
    "path": "vendor/go.uber.org/dig/glide.yaml",
    "content": "package: go.uber.org/dig\nlicense: MIT\ntestImport:\n- package: github.com/stretchr/testify\n  subpackages:\n  - assert\n  - require\n"
  },
  {
    "path": "vendor/go.uber.org/dig/internal/digreflect/func.go",
    "content": "// Copyright (c) 2018 Uber Technologies, Inc.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\npackage digreflect\n\nimport (\n\t\"fmt\"\n\t\"net/url\"\n\t\"reflect\"\n\t\"runtime\"\n\t\"strings\"\n)\n\n// Func contains runtime information about a function.\ntype Func struct {\n\t// Name of the function.\n\tName string\n\n\t// Name of the package in which this function is defined.\n\tPackage string\n\n\t// Path to the file in which this function is defined.\n\tFile string\n\n\t// Line number in the file at which this function is defined.\n\tLine int\n}\n\n// String returns a string representation of the function.\nfunc (f *Func) String() string {\n\t// \"path/to/package\".MyFunction (path/to/file.go:42)\n\treturn fmt.Sprintf(\"%q.%v (%v:%v)\", f.Package, f.Name, f.File, f.Line)\n}\n\n// InspectFunc inspects and returns runtime information about the given\n// function.\nfunc InspectFunc(function interface{}) *Func {\n\tfptr := reflect.ValueOf(function).Pointer()\n\tf := runtime.FuncForPC(fptr)\n\tpkgName, funcName := splitFuncName(f.Name())\n\tfileName, lineNum := f.FileLine(fptr)\n\treturn &Func{\n\t\tName:    funcName,\n\t\tPackage: pkgName,\n\t\tFile:    fileName,\n\t\tLine:    lineNum,\n\t}\n}\n\nconst _vendor = \"/vendor/\"\n\nfunc splitFuncName(function string) (pname string, fname string) {\n\tif len(function) == 0 {\n\t\treturn\n\t}\n\n\t// We have something like \"path.to/my/pkg.MyFunction\". If the function is\n\t// a closure, it is something like, \"path.to/my/pkg.MyFunction.func1\".\n\n\tidx := 0\n\n\t// Everything up to the first \".\" after the last \"/\" is the package name.\n\t// Everything after the \".\" is the full function name.\n\tif i := strings.LastIndex(function, \"/\"); i >= 0 {\n\t\tidx = i\n\t}\n\tif i := strings.Index(function[idx:], \".\"); i >= 0 {\n\t\tidx += i\n\t}\n\tpname, fname = function[:idx], function[idx+1:]\n\n\t// The package may be vendored.\n\tif i := strings.Index(pname, _vendor); i > 0 {\n\t\tpname = pname[i+len(_vendor):]\n\t}\n\n\t// Package names are URL-encoded to avoid ambiguity in the case where the\n\t// package name contains \".git\". Otherwise, \"foo/bar.git.MyFunction\" would\n\t// mean that \"git\" is the top-level function and \"MyFunction\" is embedded\n\t// inside it.\n\tif unescaped, err := url.QueryUnescape(pname); err == nil {\n\t\tpname = unescaped\n\t}\n\n\treturn\n}\n"
  },
  {
    "path": "vendor/go.uber.org/dig/internal/dot/graph.go",
    "content": "// Copyright (c) 2018 Uber Technologies, Inc.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\npackage dot\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n)\n\n// ErrorType of a constructor or group is updated when they fail to build.\ntype ErrorType int\n\nconst (\n\tnoError ErrorType = iota\n\trootCause\n\ttransitiveFailure\n)\n\n// CtorID is a unique numeric identifier for constructors.\ntype CtorID uintptr\n\n// Ctor encodes a constructor provided to the container for the DOT graph.\ntype Ctor struct {\n\tName        string\n\tPackage     string\n\tFile        string\n\tLine        int\n\tID          CtorID\n\tParams      []*Param\n\tGroupParams []*Group\n\tResults     []*Result\n\tErrorType   ErrorType\n}\n\n// Node is a single node in a graph and is embedded into Params and Results.\ntype Node struct {\n\tType  reflect.Type\n\tName  string\n\tGroup string\n}\n\n// Param is a parameter node in the graph.\ntype Param struct {\n\t*Node\n\n\tOptional bool\n}\n\n// Result is a result node in the graph.\ntype Result struct {\n\t*Node\n\n\t// GroupIndex is added to differentiate grouped values from one another.\n\t// Since grouped values have the same type and group, their Node / string\n\t// representations are the same so we need indices to uniquely identify\n\t// the values.\n\tGroupIndex int\n}\n\n// Group is a group node in the graph.\ntype Group struct {\n\t// Type is the type of values in the group.\n\tType      reflect.Type\n\tName      string\n\tResults   []*Result\n\tErrorType ErrorType\n}\n\n// Graph is the DOT-format graph in a Container.\ntype Graph struct {\n\tCtors   []*Ctor\n\tctorMap map[CtorID]*Ctor\n\n\tGroups   []*Group\n\tgroupMap map[groupKey]*Group\n\n\tFailed *FailedNodes\n}\n\n// FailedNodes is the nodes that failed in the graph.\ntype FailedNodes struct {\n\t// RootCauses is a list of the point of failures. They are the root causes\n\t// of failed invokes and can be either missing types (not provided) or\n\t// error types (error providing).\n\tRootCauses []*Result\n\n\t// TransitiveFailures is the list of nodes that failed to build due to\n\t// missing/failed dependencies.\n\tTransitiveFailures []*Result\n}\n\ntype groupKey struct {\n\tt     reflect.Type\n\tgroup string\n}\n\n// NewGraph creates an empty graph.\nfunc NewGraph() *Graph {\n\treturn &Graph{\n\t\tctorMap:  make(map[CtorID]*Ctor),\n\t\tgroupMap: make(map[groupKey]*Group),\n\t\tFailed:   &FailedNodes{},\n\t}\n}\n\n// NewGroup creates a new group with information in the groupKey.\nfunc NewGroup(k groupKey) *Group {\n\treturn &Group{\n\t\tType: k.t,\n\t\tName: k.group,\n\t}\n}\n\n// AddCtor adds the constructor with paramList and resultList into the graph.\nfunc (dg *Graph) AddCtor(c *Ctor, paramList []*Param, resultList []*Result) {\n\tvar (\n\t\tparams      []*Param\n\t\tgroupParams []*Group\n\t)\n\n\t// Loop through the paramList to separate them into regular params and\n\t// grouped params. For grouped params, we use getGroup to find the actual\n\t// group.\n\tfor _, param := range paramList {\n\t\tif param.Group == \"\" {\n\t\t\t// Not a value group.\n\t\t\tparams = append(params, param)\n\t\t\tcontinue\n\t\t}\n\n\t\tk := groupKey{t: param.Type.Elem(), group: param.Group}\n\t\tgroup := dg.getGroup(k)\n\t\tgroupParams = append(groupParams, group)\n\t}\n\n\tfor _, result := range resultList {\n\t\t// If the result is a grouped value, we want to update its GroupIndex\n\t\t// and add it to the Group.\n\t\tif result.Group != \"\" {\n\t\t\tdg.addToGroup(result, c.ID)\n\t\t}\n\t}\n\n\tc.Params = params\n\tc.GroupParams = groupParams\n\tc.Results = resultList\n\n\tdg.Ctors = append(dg.Ctors, c)\n\tdg.ctorMap[c.ID] = c\n}\n\nfunc (dg *Graph) failNode(r *Result, isRootCause bool) {\n\tif isRootCause {\n\t\tdg.addRootCause(r)\n\t} else {\n\t\tdg.addTransitiveFailure(r)\n\t}\n}\n\n// AddMissingNodes adds missing nodes to the list of failed Results in the graph.\nfunc (dg *Graph) AddMissingNodes(results []*Result) {\n\t// The failure(s) are root causes if there are no other failures.\n\tisRootCause := len(dg.Failed.RootCauses) == 0\n\n\tfor _, r := range results {\n\t\tdg.failNode(r, isRootCause)\n\t}\n}\n\n// FailNodes adds results to the list of failed Results in the graph, and\n// updates the state of the constructor with the given id accordingly.\nfunc (dg *Graph) FailNodes(results []*Result, id CtorID) {\n\t// This failure is the root cause if there are no other failures.\n\tisRootCause := len(dg.Failed.RootCauses) == 0\n\n\tfor _, r := range results {\n\t\tdg.failNode(r, isRootCause)\n\t}\n\n\tif c, ok := dg.ctorMap[id]; ok {\n\t\tif isRootCause {\n\t\t\tc.ErrorType = rootCause\n\t\t} else {\n\t\t\tc.ErrorType = transitiveFailure\n\t\t}\n\t}\n}\n\n// FailGroupNodes finds and adds the failed grouped nodes to the list of failed\n// Results in the graph, and updates the state of the group and constructor\n// with the given id accordingly.\nfunc (dg *Graph) FailGroupNodes(name string, t reflect.Type, id CtorID) {\n\t// This failure is the root cause if there are no other failures.\n\tisRootCause := len(dg.Failed.RootCauses) == 0\n\n\tk := groupKey{t: t, group: name}\n\tgroup := dg.getGroup(k)\n\n\tfor _, r := range dg.ctorMap[id].Results {\n\t\tif r.Type == t && r.Group == name {\n\t\t\tdg.failNode(r, isRootCause)\n\t\t}\n\t}\n\n\tif c, ok := dg.ctorMap[id]; ok {\n\t\tif isRootCause {\n\t\t\tgroup.ErrorType = rootCause\n\t\t\tc.ErrorType = rootCause\n\t\t} else {\n\t\t\tgroup.ErrorType = transitiveFailure\n\t\t\tc.ErrorType = transitiveFailure\n\t\t}\n\t}\n}\n\n// getGroup finds the group by groupKey from the graph. If it is not available,\n// a new group is created and returned.\nfunc (dg *Graph) getGroup(k groupKey) *Group {\n\tg, ok := dg.groupMap[k]\n\tif !ok {\n\t\tg = NewGroup(k)\n\t\tdg.groupMap[k] = g\n\t\tdg.Groups = append(dg.Groups, g)\n\t}\n\treturn g\n}\n\n// addToGroup adds a newly provided grouped result to the appropriate group.\nfunc (dg *Graph) addToGroup(r *Result, id CtorID) {\n\tk := groupKey{t: r.Type, group: r.Group}\n\tgroup := dg.getGroup(k)\n\n\tr.GroupIndex = len(group.Results)\n\tgroup.Results = append(group.Results, r)\n}\n\n// String implements fmt.Stringer for Param.\nfunc (p *Param) String() string {\n\tif p.Name != \"\" {\n\t\treturn fmt.Sprintf(\"%v[name=%v]\", p.Type.String(), p.Name)\n\t}\n\treturn p.Type.String()\n}\n\n// String implements fmt.Stringer for Result.\nfunc (r *Result) String() string {\n\tswitch {\n\tcase r.Name != \"\":\n\t\treturn fmt.Sprintf(\"%v[name=%v]\", r.Type.String(), r.Name)\n\tcase r.Group != \"\":\n\t\treturn fmt.Sprintf(\"%v[group=%v]%v\", r.Type.String(), r.Group, r.GroupIndex)\n\tdefault:\n\t\treturn r.Type.String()\n\t}\n}\n\n// String implements fmt.Stringer for Group.\nfunc (g *Group) String() string {\n\treturn fmt.Sprintf(\"[type=%v group=%v]\", g.Type.String(), g.Name)\n}\n\n// Attributes composes and returns a string of the Result node's attributes.\nfunc (r *Result) Attributes() string {\n\tswitch {\n\tcase r.Name != \"\":\n\t\treturn fmt.Sprintf(`label=<%v<BR /><FONT POINT-SIZE=\"10\">Name: %v</FONT>>`, r.Type, r.Name)\n\tcase r.Group != \"\":\n\t\treturn fmt.Sprintf(`label=<%v<BR /><FONT POINT-SIZE=\"10\">Group: %v</FONT>>`, r.Type, r.Group)\n\tdefault:\n\t\treturn fmt.Sprintf(`label=<%v>`, r.Type)\n\t}\n}\n\n// Attributes composes and returns a string of the Group node's attributes.\nfunc (g *Group) Attributes() string {\n\tattr := fmt.Sprintf(`shape=diamond label=<%v<BR /><FONT POINT-SIZE=\"10\">Group: %v</FONT>>`, g.Type, g.Name)\n\tif g.ErrorType != noError {\n\t\tattr += \" color=\" + g.ErrorType.Color()\n\t}\n\treturn attr\n}\n\n// Color returns the color representation of each ErrorType.\nfunc (s ErrorType) Color() string {\n\tswitch s {\n\tcase rootCause:\n\t\treturn \"red\"\n\tcase transitiveFailure:\n\t\treturn \"orange\"\n\tdefault:\n\t\treturn \"black\"\n\t}\n}\n\nfunc (dg *Graph) addRootCause(r *Result) {\n\tdg.Failed.RootCauses = append(dg.Failed.RootCauses, r)\n}\n\nfunc (dg *Graph) addTransitiveFailure(r *Result) {\n\tdg.Failed.TransitiveFailures = append(dg.Failed.TransitiveFailures, r)\n}\n"
  },
  {
    "path": "vendor/go.uber.org/dig/param.go",
    "content": "// Copyright (c) 2018 Uber Technologies, Inc.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\npackage dig\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"reflect\"\n\n\t\"go.uber.org/dig/internal/dot\"\n)\n\n// The param interface represents a dependency for a constructor.\n//\n// The following implementations exist:\n//  paramList     All arguments of the constructor.\n//  paramSingle   An explicitly requested type.\n//  paramObject   dig.In struct where each field in the struct can be another\n//                param.\n//  paramGroupedSlice\n//                A slice consuming a value group. This will receive all\n//                values produced with a `group:\"..\"` tag with the same name\n//                as a slice.\ntype param interface {\n\tfmt.Stringer\n\n\t// Builds this dependency and any of its dependencies from the provided\n\t// Container.\n\t//\n\t// This MAY panic if the param does not produce a single value.\n\tBuild(containerStore) (reflect.Value, error)\n\n\t// DotParam returns a slice of dot.Param(s).\n\tDotParam() []*dot.Param\n}\n\nvar (\n\t_ param = paramSingle{}\n\t_ param = paramObject{}\n\t_ param = paramList{}\n\t_ param = paramGroupedSlice{}\n)\n\n// newParam builds a param from the given type. If the provided type is a\n// dig.In struct, an paramObject will be returned.\nfunc newParam(t reflect.Type) (param, error) {\n\tswitch {\n\tcase IsOut(t) || (t.Kind() == reflect.Ptr && IsOut(t.Elem())) || embedsType(t, _outPtrType):\n\t\treturn nil, fmt.Errorf(\"cannot depend on result objects: %v embeds a dig.Out\", t)\n\tcase IsIn(t):\n\t\treturn newParamObject(t)\n\tcase embedsType(t, _inPtrType):\n\t\treturn nil, fmt.Errorf(\n\t\t\t\"cannot build a parameter object by embedding *dig.In, embed dig.In instead: \"+\n\t\t\t\t\"%v embeds *dig.In\", t)\n\tcase t.Kind() == reflect.Ptr && IsIn(t.Elem()):\n\t\treturn nil, fmt.Errorf(\n\t\t\t\"cannot depend on a pointer to a parameter object, use a value instead: \"+\n\t\t\t\t\"%v is a pointer to a struct that embeds dig.In\", t)\n\tdefault:\n\t\treturn paramSingle{Type: t}, nil\n\t}\n}\n\n// paramVisitor visits every param in a param tree, allowing tracking state at\n// each level.\ntype paramVisitor interface {\n\t// Visit is called on the param being visited.\n\t//\n\t// If Visit returns a non-nil paramVisitor, that paramVisitor visits all\n\t// the child params of this param.\n\tVisit(param) paramVisitor\n\n\t// We can implement AnnotateWithField and AnnotateWithPosition like\n\t// resultVisitor if we need to track that information in the future.\n}\n\n// paramVisitorFunc is a paramVisitor that visits param in a tree with the\n// return value deciding whether the descendants of this param should be\n// recursed into.\ntype paramVisitorFunc func(param) (recurse bool)\n\nfunc (f paramVisitorFunc) Visit(p param) paramVisitor {\n\tif f(p) {\n\t\treturn f\n\t}\n\treturn nil\n}\n\n// walkParam walks the param tree for the given param with the provided\n// visitor.\n//\n// paramVisitor.Visit will be called on the provided param and if a non-nil\n// paramVisitor is received, this param's descendants will be walked with that\n// visitor.\n//\n// This is very similar to how go/ast.Walk works.\nfunc walkParam(p param, v paramVisitor) {\n\tv = v.Visit(p)\n\tif v == nil {\n\t\treturn\n\t}\n\n\tswitch par := p.(type) {\n\tcase paramSingle, paramGroupedSlice:\n\t\t// No sub-results\n\tcase paramObject:\n\t\tfor _, f := range par.Fields {\n\t\t\twalkParam(f.Param, v)\n\t\t}\n\tcase paramList:\n\t\tfor _, p := range par.Params {\n\t\t\twalkParam(p, v)\n\t\t}\n\tdefault:\n\t\tpanic(fmt.Sprintf(\n\t\t\t\"It looks like you have found a bug in dig. \"+\n\t\t\t\t\"Please file an issue at https://github.com/uber-go/dig/issues/ \"+\n\t\t\t\t\"and provide the following message: \"+\n\t\t\t\t\"received unknown param type %T\", p))\n\t}\n}\n\n// paramList holds all arguments of the constructor as params.\n//\n// NOTE: Build() MUST NOT be called on paramList. Instead, BuildList\n// must be called.\ntype paramList struct {\n\tctype reflect.Type // type of the constructor\n\n\tParams []param\n}\n\nfunc (pl paramList) DotParam() []*dot.Param {\n\tvar types []*dot.Param\n\tfor _, param := range pl.Params {\n\t\ttypes = append(types, param.DotParam()...)\n\t}\n\treturn types\n}\n\n// newParamList builds a paramList from the provided constructor type.\n//\n// Variadic arguments of a constructor are ignored and not included as\n// dependencies.\nfunc newParamList(ctype reflect.Type) (paramList, error) {\n\tnumArgs := ctype.NumIn()\n\tif ctype.IsVariadic() {\n\t\t// NOTE: If the function is variadic, we skip the last argument\n\t\t// because we're not filling variadic arguments yet. See #120.\n\t\tnumArgs--\n\t}\n\n\tpl := paramList{\n\t\tctype:  ctype,\n\t\tParams: make([]param, 0, numArgs),\n\t}\n\n\tfor i := 0; i < numArgs; i++ {\n\t\tp, err := newParam(ctype.In(i))\n\t\tif err != nil {\n\t\t\treturn pl, errWrapf(err, \"bad argument %d\", i+1)\n\t\t}\n\t\tpl.Params = append(pl.Params, p)\n\t}\n\n\treturn pl, nil\n}\n\nfunc (pl paramList) Build(containerStore) (reflect.Value, error) {\n\tpanic(\"It looks like you have found a bug in dig. \" +\n\t\t\"Please file an issue at https://github.com/uber-go/dig/issues/ \" +\n\t\t\"and provide the following message: \" +\n\t\t\"paramList.Build() must never be called\")\n}\n\n// BuildList returns an ordered list of values which may be passed directly\n// to the underlying constructor.\nfunc (pl paramList) BuildList(c containerStore) ([]reflect.Value, error) {\n\targs := make([]reflect.Value, len(pl.Params))\n\tfor i, p := range pl.Params {\n\t\tvar err error\n\t\targs[i], err = p.Build(c)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn args, nil\n}\n\n// paramSingle is an explicitly requested type, optionally with a name.\n//\n// This object must be present in the graph as-is unless it's specified as\n// optional.\ntype paramSingle struct {\n\tName     string\n\tOptional bool\n\tType     reflect.Type\n}\n\nfunc (ps paramSingle) DotParam() []*dot.Param {\n\treturn []*dot.Param{\n\t\t{\n\t\t\tNode: &dot.Node{\n\t\t\t\tType: ps.Type,\n\t\t\t\tName: ps.Name,\n\t\t\t},\n\t\t\tOptional: ps.Optional,\n\t\t},\n\t}\n}\n\nfunc (ps paramSingle) Build(c containerStore) (reflect.Value, error) {\n\tif v, ok := c.getValue(ps.Name, ps.Type); ok {\n\t\treturn v, nil\n\t}\n\n\tproviders := c.getValueProviders(ps.Name, ps.Type)\n\tif len(providers) == 0 {\n\t\tif ps.Optional {\n\t\t\treturn reflect.Zero(ps.Type), nil\n\t\t}\n\t\treturn _noValue, newErrMissingType(c, key{name: ps.Name, t: ps.Type})\n\t}\n\n\tfor _, n := range providers {\n\t\terr := n.Call(c)\n\t\tif err == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\t// If we're missing dependencies but the parameter itself is optional,\n\t\t// we can just move on.\n\t\tif _, ok := err.(errMissingDependencies); ok && ps.Optional {\n\t\t\treturn reflect.Zero(ps.Type), nil\n\t\t}\n\n\t\treturn _noValue, errParamSingleFailed{\n\t\t\tCtorID: n.ID(),\n\t\t\tKey:    key{t: ps.Type, name: ps.Name},\n\t\t\tReason: err,\n\t\t}\n\t}\n\n\t// If we get here, it's impossible for the value to be absent from the\n\t// container.\n\tv, _ := c.getValue(ps.Name, ps.Type)\n\treturn v, nil\n}\n\n// paramObject is a dig.In struct where each field is another param.\n//\n// This object is not expected in the graph as-is.\ntype paramObject struct {\n\tType   reflect.Type\n\tFields []paramObjectField\n}\n\nfunc (po paramObject) DotParam() []*dot.Param {\n\tvar types []*dot.Param\n\tfor _, field := range po.Fields {\n\t\ttypes = append(types, field.DotParam()...)\n\t}\n\treturn types\n}\n\n// newParamObject builds an paramObject from the provided type. The type MUST\n// be a dig.In struct.\nfunc newParamObject(t reflect.Type) (paramObject, error) {\n\tpo := paramObject{Type: t}\n\n\tfor i := 0; i < t.NumField(); i++ {\n\t\tf := t.Field(i)\n\t\tif f.Type == _inType {\n\t\t\t// Skip over the dig.In embed.\n\t\t\tcontinue\n\t\t}\n\n\t\tpof, err := newParamObjectField(i, f)\n\t\tif err != nil {\n\t\t\treturn po, errWrapf(err, \"bad field %q of %v\", f.Name, t)\n\t\t}\n\n\t\tpo.Fields = append(po.Fields, pof)\n\t}\n\n\treturn po, nil\n}\n\nfunc (po paramObject) Build(c containerStore) (reflect.Value, error) {\n\tdest := reflect.New(po.Type).Elem()\n\tfor _, f := range po.Fields {\n\t\tv, err := f.Build(c)\n\t\tif err != nil {\n\t\t\treturn dest, err\n\t\t}\n\t\tdest.Field(f.FieldIndex).Set(v)\n\t}\n\treturn dest, nil\n}\n\n// paramObjectField is a single field of a dig.In struct.\ntype paramObjectField struct {\n\t// Name of the field in the struct.\n\tFieldName string\n\n\t// Index of this field in the target struct.\n\t//\n\t// We need to track this separately because not all fields of the\n\t// struct map to params.\n\tFieldIndex int\n\n\t// The dependency requested by this field.\n\tParam param\n}\n\nfunc (pof paramObjectField) DotParam() []*dot.Param {\n\treturn pof.Param.DotParam()\n}\n\nfunc newParamObjectField(idx int, f reflect.StructField) (paramObjectField, error) {\n\tpof := paramObjectField{\n\t\tFieldName:  f.Name,\n\t\tFieldIndex: idx,\n\t}\n\n\tvar p param\n\tswitch {\n\tcase f.PkgPath != \"\":\n\t\treturn pof, fmt.Errorf(\n\t\t\t\"unexported fields not allowed in dig.In, did you mean to export %q (%v)?\",\n\t\t\tf.Name, f.Type)\n\n\tcase f.Tag.Get(_groupTag) != \"\":\n\t\tvar err error\n\t\tp, err = newParamGroupedSlice(f)\n\t\tif err != nil {\n\t\t\treturn pof, err\n\t\t}\n\n\tdefault:\n\t\tvar err error\n\t\tp, err = newParam(f.Type)\n\t\tif err != nil {\n\t\t\treturn pof, err\n\t\t}\n\t}\n\n\tif ps, ok := p.(paramSingle); ok {\n\t\tps.Name = f.Tag.Get(_nameTag)\n\n\t\tvar err error\n\t\tps.Optional, err = isFieldOptional(f)\n\t\tif err != nil {\n\t\t\treturn pof, err\n\t\t}\n\n\t\tp = ps\n\t}\n\n\tpof.Param = p\n\treturn pof, nil\n}\n\nfunc (pof paramObjectField) Build(c containerStore) (reflect.Value, error) {\n\tv, err := pof.Param.Build(c)\n\tif err != nil {\n\t\treturn v, err\n\t}\n\treturn v, nil\n}\n\n// paramGroupedSlice is a param which produces a slice of values with the same\n// group name.\ntype paramGroupedSlice struct {\n\t// Name of the group as specified in the `group:\"..\"` tag.\n\tGroup string\n\n\t// Type of the slice.\n\tType reflect.Type\n}\n\nfunc (pt paramGroupedSlice) DotParam() []*dot.Param {\n\treturn []*dot.Param{\n\t\t{\n\t\t\tNode: &dot.Node{\n\t\t\t\tType:  pt.Type,\n\t\t\t\tGroup: pt.Group,\n\t\t\t},\n\t\t},\n\t}\n}\n\n// newParamGroupedSlice builds a paramGroupedSlice from the provided type with\n// the given name.\n//\n// The type MUST be a slice type.\nfunc newParamGroupedSlice(f reflect.StructField) (paramGroupedSlice, error) {\n\tpg := paramGroupedSlice{Group: f.Tag.Get(_groupTag), Type: f.Type}\n\n\tname := f.Tag.Get(_nameTag)\n\toptional, _ := isFieldOptional(f)\n\tswitch {\n\tcase f.Type.Kind() != reflect.Slice:\n\t\treturn pg, fmt.Errorf(\"value groups may be consumed as slices only: \"+\n\t\t\t\"field %q (%v) is not a slice\", f.Name, f.Type)\n\tcase name != \"\":\n\t\treturn pg, fmt.Errorf(\n\t\t\t\"cannot use named values with value groups: name:%q requested with group:%q\", name, pg.Group)\n\n\tcase optional:\n\t\treturn pg, errors.New(\"value groups cannot be optional\")\n\t}\n\n\treturn pg, nil\n}\n\nfunc (pt paramGroupedSlice) Build(c containerStore) (reflect.Value, error) {\n\tfor _, n := range c.getGroupProviders(pt.Group, pt.Type.Elem()) {\n\t\tif err := n.Call(c); err != nil {\n\t\t\treturn _noValue, errParamGroupFailed{\n\t\t\t\tCtorID: n.ID(),\n\t\t\t\tKey:    key{group: pt.Group, t: pt.Type.Elem()},\n\t\t\t\tReason: err,\n\t\t\t}\n\t\t}\n\t}\n\n\titems := c.getValueGroup(pt.Group, pt.Type.Elem())\n\n\tresult := reflect.MakeSlice(pt.Type, len(items), len(items))\n\tfor i, v := range items {\n\t\tresult.Index(i).Set(v)\n\t}\n\treturn result, nil\n}\n"
  },
  {
    "path": "vendor/go.uber.org/dig/result.go",
    "content": "// Copyright (c) 2018 Uber Technologies, Inc.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\npackage dig\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"reflect\"\n\n\t\"go.uber.org/dig/internal/dot\"\n)\n\n// The result interface represents a result produced by a constructor.\n//\n// The following implementations exist:\n//   resultList    All values returned by the constructor.\n//   resultSingle  A single value produced by a constructor.\n//   resultObject  dig.Out struct where each field in the struct can be\n//                 another result.\n//   resultGrouped A value produced by a constructor that is part of a value\n//                 group.\ntype result interface {\n\t// Extracts the values for this result from the provided value and\n\t// stores them into the provided containerWriter.\n\t//\n\t// This MAY panic if the result does not consume a single value.\n\tExtract(containerWriter, reflect.Value)\n\n\t// DotResult returns a slice of dot.Result(s).\n\tDotResult() []*dot.Result\n}\n\nvar (\n\t_ result = resultSingle{}\n\t_ result = resultObject{}\n\t_ result = resultList{}\n\t_ result = resultGrouped{}\n)\n\ntype resultOptions struct {\n\t// If set, this is the name of the associated result value.\n\t//\n\t// For Result Objects, name:\"..\" tags on fields override this.\n\tName string\n}\n\n// newResult builds a result from the given type.\nfunc newResult(t reflect.Type, opts resultOptions) (result, error) {\n\tswitch {\n\tcase IsIn(t) || (t.Kind() == reflect.Ptr && IsIn(t.Elem())) || embedsType(t, _inPtrType):\n\t\treturn nil, fmt.Errorf(\"cannot provide parameter objects: %v embeds a dig.In\", t)\n\tcase isError(t):\n\t\treturn nil, fmt.Errorf(\"cannot return an error here, return it from the constructor instead\")\n\tcase IsOut(t):\n\t\treturn newResultObject(t, opts)\n\tcase embedsType(t, _outPtrType):\n\t\treturn nil, fmt.Errorf(\n\t\t\t\"cannot build a result object by embedding *dig.Out, embed dig.Out instead: \"+\n\t\t\t\t\"%v embeds *dig.Out\", t)\n\tcase t.Kind() == reflect.Ptr && IsOut(t.Elem()):\n\t\treturn nil, fmt.Errorf(\n\t\t\t\"cannot return a pointer to a result object, use a value instead: \"+\n\t\t\t\t\"%v is a pointer to a struct that embeds dig.Out\", t)\n\tdefault:\n\t\treturn resultSingle{Type: t, Name: opts.Name}, nil\n\t}\n}\n\n// resultVisitor visits every result in a result tree, allowing tracking state\n// at each level.\ntype resultVisitor interface {\n\t// Visit is called on the result being visited.\n\t//\n\t// If Visit returns a non-nil resultVisitor, that resultVisitor visits all\n\t// the child results of this result.\n\tVisit(result) resultVisitor\n\n\t// AnnotateWithField is called on each field of a resultObject after\n\t// visiting it but before walking its descendants.\n\t//\n\t// The same resultVisitor is used for all fields: the one returned upon\n\t// visiting the resultObject.\n\t//\n\t// For each visited field, if AnnotateWithField returns a non-nil\n\t// resultVisitor, it will be used to walk the result of that field.\n\tAnnotateWithField(resultObjectField) resultVisitor\n\n\t// AnnotateWithPosition is called with the index of each result of a\n\t// resultList after vising it but before walking its descendants.\n\t//\n\t// The same resultVisitor is used for all results: the one returned upon\n\t// visiting the resultList.\n\t//\n\t// For each position, if AnnotateWithPosition returns a non-nil\n\t// resultVisitor, it will be used to walk the result at that index.\n\tAnnotateWithPosition(idx int) resultVisitor\n}\n\n// walkResult walks the result tree for the given result with the provided\n// visitor.\n//\n// resultVisitor.Visit will be called on the provided result and if a non-nil\n// resultVisitor is received, it will be used to walk its descendants. If a\n// resultObject or resultList was visited, AnnotateWithField and\n// AnnotateWithPosition respectively will be called before visiting the\n// descendants of that resultObject/resultList.\n//\n// This is very similar to how go/ast.Walk works.\nfunc walkResult(r result, v resultVisitor) {\n\tv = v.Visit(r)\n\tif v == nil {\n\t\treturn\n\t}\n\n\tswitch res := r.(type) {\n\tcase resultSingle, resultGrouped:\n\t\t// No sub-results\n\tcase resultObject:\n\t\tw := v\n\t\tfor _, f := range res.Fields {\n\t\t\tif v := w.AnnotateWithField(f); v != nil {\n\t\t\t\twalkResult(f.Result, v)\n\t\t\t}\n\t\t}\n\tcase resultList:\n\t\tw := v\n\t\tfor i, r := range res.Results {\n\t\t\tif v := w.AnnotateWithPosition(i); v != nil {\n\t\t\t\twalkResult(r, v)\n\t\t\t}\n\t\t}\n\tdefault:\n\t\tpanic(fmt.Sprintf(\n\t\t\t\"It looks like you have found a bug in dig. \"+\n\t\t\t\t\"Please file an issue at https://github.com/uber-go/dig/issues/ \"+\n\t\t\t\t\"and provide the following message: \"+\n\t\t\t\t\"received unknown result type %T\", res))\n\t}\n}\n\n// resultList holds all values returned by the constructor as results.\ntype resultList struct {\n\tctype reflect.Type\n\n\tResults []result\n\n\t// For each item at index i returned by the constructor, resultIndexes[i]\n\t// is the index in .Results for the corresponding result object.\n\t// resultIndexes[i] is -1 for errors returned by constructors.\n\tresultIndexes []int\n}\n\nfunc (rl resultList) DotResult() []*dot.Result {\n\tvar types []*dot.Result\n\tfor _, result := range rl.Results {\n\t\ttypes = append(types, result.DotResult()...)\n\t}\n\treturn types\n}\n\nfunc newResultList(ctype reflect.Type, opts resultOptions) (resultList, error) {\n\trl := resultList{\n\t\tctype:         ctype,\n\t\tResults:       make([]result, 0, ctype.NumOut()),\n\t\tresultIndexes: make([]int, ctype.NumOut()),\n\t}\n\n\tresultIdx := 0\n\tfor i := 0; i < ctype.NumOut(); i++ {\n\t\tt := ctype.Out(i)\n\t\tif isError(t) {\n\t\t\trl.resultIndexes[i] = -1\n\t\t\tcontinue\n\t\t}\n\n\t\tr, err := newResult(t, opts)\n\t\tif err != nil {\n\t\t\treturn rl, errWrapf(err, \"bad result %d\", i+1)\n\t\t}\n\n\t\trl.Results = append(rl.Results, r)\n\t\trl.resultIndexes[i] = resultIdx\n\t\tresultIdx++\n\t}\n\n\treturn rl, nil\n}\n\nfunc (resultList) Extract(containerWriter, reflect.Value) {\n\tpanic(\"It looks like you have found a bug in dig. \" +\n\t\t\"Please file an issue at https://github.com/uber-go/dig/issues/ \" +\n\t\t\"and provide the following message: \" +\n\t\t\"resultList.Extract() must never be called\")\n}\n\nfunc (rl resultList) ExtractList(cw containerWriter, values []reflect.Value) error {\n\tfor i, v := range values {\n\t\tif resultIdx := rl.resultIndexes[i]; resultIdx >= 0 {\n\t\t\trl.Results[resultIdx].Extract(cw, v)\n\t\t\tcontinue\n\t\t}\n\n\t\tif err, _ := v.Interface().(error); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// resultSingle is an explicit value produced by a constructor, optionally\n// with a name.\n//\n// This object will be added to the graph as-is.\ntype resultSingle struct {\n\tName string\n\tType reflect.Type\n}\n\nfunc (rs resultSingle) DotResult() []*dot.Result {\n\treturn []*dot.Result{\n\t\t{\n\t\t\tNode: &dot.Node{\n\t\t\t\tType: rs.Type,\n\t\t\t\tName: rs.Name,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc (rs resultSingle) Extract(cw containerWriter, v reflect.Value) {\n\tcw.setValue(rs.Name, rs.Type, v)\n}\n\n// resultObject is a dig.Out struct where each field is another result.\n//\n// This object is not added to the graph. Its fields are interpreted as\n// results and added to the graph if needed.\ntype resultObject struct {\n\tType   reflect.Type\n\tFields []resultObjectField\n}\n\nfunc (ro resultObject) DotResult() []*dot.Result {\n\tvar types []*dot.Result\n\tfor _, field := range ro.Fields {\n\t\ttypes = append(types, field.DotResult()...)\n\t}\n\treturn types\n}\n\nfunc newResultObject(t reflect.Type, opts resultOptions) (resultObject, error) {\n\tro := resultObject{Type: t}\n\tif len(opts.Name) > 0 {\n\t\treturn ro, fmt.Errorf(\n\t\t\t\"cannot specify a name for result objects: %v embeds dig.Out\", t)\n\t}\n\n\tfor i := 0; i < t.NumField(); i++ {\n\t\tf := t.Field(i)\n\t\tif f.Type == _outType {\n\t\t\t// Skip over the dig.Out embed.\n\t\t\tcontinue\n\t\t}\n\n\t\trof, err := newResultObjectField(i, f, opts)\n\t\tif err != nil {\n\t\t\treturn ro, errWrapf(err, \"bad field %q of %v\", f.Name, t)\n\t\t}\n\n\t\tro.Fields = append(ro.Fields, rof)\n\t}\n\treturn ro, nil\n}\n\nfunc (ro resultObject) Extract(cw containerWriter, v reflect.Value) {\n\tfor _, f := range ro.Fields {\n\t\tf.Result.Extract(cw, v.Field(f.FieldIndex))\n\t}\n}\n\n// resultObjectField is a single field inside a dig.Out struct.\ntype resultObjectField struct {\n\t// Name of the field in the struct.\n\tFieldName string\n\n\t// Index of the field in the struct.\n\t//\n\t// We need to track this separately because not all fields of the struct\n\t// map to results.\n\tFieldIndex int\n\n\t// Result produced by this field.\n\tResult result\n}\n\nfunc (rof resultObjectField) DotResult() []*dot.Result {\n\treturn rof.Result.DotResult()\n}\n\n// newResultObjectField(i, f, opts) builds a resultObjectField from the field\n// f at index i.\nfunc newResultObjectField(idx int, f reflect.StructField, opts resultOptions) (resultObjectField, error) {\n\trof := resultObjectField{\n\t\tFieldName:  f.Name,\n\t\tFieldIndex: idx,\n\t}\n\n\tvar r result\n\tswitch {\n\tcase f.PkgPath != \"\":\n\t\treturn rof, fmt.Errorf(\n\t\t\t\"unexported fields not allowed in dig.Out, did you mean to export %q (%v)?\", f.Name, f.Type)\n\n\tcase f.Tag.Get(_groupTag) != \"\":\n\t\tvar err error\n\t\tr, err = newResultGrouped(f)\n\t\tif err != nil {\n\t\t\treturn rof, err\n\t\t}\n\n\tdefault:\n\t\tvar err error\n\t\tif name := f.Tag.Get(_nameTag); len(name) > 0 {\n\t\t\t// can modify in-place because options are passed-by-value.\n\t\t\topts.Name = name\n\t\t}\n\t\tr, err = newResult(f.Type, opts)\n\t\tif err != nil {\n\t\t\treturn rof, err\n\t\t}\n\t}\n\n\trof.Result = r\n\treturn rof, nil\n}\n\n// resultGrouped is a value produced by a constructor that is part of a result\n// group.\n//\n// These will be produced as fields of a dig.Out struct.\ntype resultGrouped struct {\n\t// Name of the group as specified in the `group:\"..\"` tag.\n\tGroup string\n\n\t// Type of value produced.\n\tType reflect.Type\n}\n\nfunc (rt resultGrouped) DotResult() []*dot.Result {\n\treturn []*dot.Result{\n\t\t{\n\t\t\tNode: &dot.Node{\n\t\t\t\tType:  rt.Type,\n\t\t\t\tGroup: rt.Group,\n\t\t\t},\n\t\t},\n\t}\n}\n\n// newResultGrouped(f) builds a new resultGrouped from the provided field.\nfunc newResultGrouped(f reflect.StructField) (resultGrouped, error) {\n\trg := resultGrouped{Group: f.Tag.Get(_groupTag), Type: f.Type}\n\n\tname := f.Tag.Get(_nameTag)\n\toptional, _ := isFieldOptional(f)\n\tswitch {\n\tcase name != \"\":\n\t\treturn rg, fmt.Errorf(\n\t\t\t\"cannot use named values with value groups: name:%q provided with group:%q\", name, rg.Group)\n\tcase optional:\n\t\treturn rg, errors.New(\"value groups cannot be optional\")\n\t}\n\n\treturn rg, nil\n}\n\nfunc (rt resultGrouped) Extract(cw containerWriter, v reflect.Value) {\n\tcw.submitGroupedValue(rt.Group, rt.Type, v)\n}\n"
  },
  {
    "path": "vendor/go.uber.org/dig/stringer.go",
    "content": "// Copyright (c) 2018 Uber Technologies, Inc.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\npackage dig\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"strings\"\n)\n\n// String representation of the entire Container\nfunc (c *Container) String() string {\n\tb := &bytes.Buffer{}\n\tfmt.Fprintln(b, \"nodes: {\")\n\tfor k, vs := range c.providers {\n\t\tfor _, v := range vs {\n\t\t\tfmt.Fprintln(b, \"\\t\", k, \"->\", v)\n\t\t}\n\t}\n\tfmt.Fprintln(b, \"}\")\n\n\tfmt.Fprintln(b, \"values: {\")\n\tfor k, v := range c.values {\n\t\tfmt.Fprintln(b, \"\\t\", k, \"=>\", v)\n\t}\n\tfor k, vs := range c.groups {\n\t\tfor _, v := range vs {\n\t\t\tfmt.Fprintln(b, \"\\t\", k, \"=>\", v)\n\t\t}\n\t}\n\tfmt.Fprintln(b, \"}\")\n\n\treturn b.String()\n}\n\nfunc (n *node) String() string {\n\treturn fmt.Sprintf(\"deps: %v, ctor: %v\", n.paramList, n.ctype)\n}\n\nfunc (k key) String() string {\n\tif k.name != \"\" {\n\t\treturn fmt.Sprintf(\"%v[name=%q]\", k.t, k.name)\n\t}\n\tif k.group != \"\" {\n\t\treturn fmt.Sprintf(\"%v[group=%q]\", k.t, k.group)\n\t}\n\treturn k.t.String()\n}\n\nfunc (pl paramList) String() string {\n\targs := make([]string, len(pl.Params))\n\tfor i, p := range pl.Params {\n\t\targs[i] = p.String()\n\t}\n\treturn fmt.Sprint(args)\n}\n\nfunc (sp paramSingle) String() string {\n\t// tally.Scope[optional] means optional\n\t// tally.Scope[optional, name=\"foo\"] means named optional\n\n\tvar opts []string\n\tif sp.Optional {\n\t\topts = append(opts, \"optional\")\n\t}\n\tif sp.Name != \"\" {\n\t\topts = append(opts, fmt.Sprintf(\"name=%q\", sp.Name))\n\t}\n\n\tif len(opts) == 0 {\n\t\treturn fmt.Sprint(sp.Type)\n\t}\n\n\treturn fmt.Sprintf(\"%v[%v]\", sp.Type, strings.Join(opts, \", \"))\n}\n\nfunc (op paramObject) String() string {\n\tfields := make([]string, len(op.Fields))\n\tfor i, f := range op.Fields {\n\t\tfields[i] = f.Param.String()\n\t}\n\treturn strings.Join(fields, \" \")\n}\n\nfunc (pt paramGroupedSlice) String() string {\n\t// io.Reader[group=\"foo\"] refers to a group of io.Readers called 'foo'\n\treturn fmt.Sprintf(\"%v[group=%q]\", pt.Type.Elem(), pt.Group)\n}\n"
  },
  {
    "path": "vendor/go.uber.org/dig/types.go",
    "content": "// Copyright (c) 2018 Uber Technologies, Inc.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\npackage dig\n\nimport (\n\t\"container/list\"\n\t\"reflect\"\n)\n\nvar (\n\t_noValue    reflect.Value\n\t_errType    = reflect.TypeOf((*error)(nil)).Elem()\n\t_inPtrType  = reflect.TypeOf((*In)(nil))\n\t_inType     = reflect.TypeOf(In{})\n\t_outPtrType = reflect.TypeOf((*Out)(nil))\n\t_outType    = reflect.TypeOf(Out{})\n)\n\n// Special interface embedded inside dig sentinel values (dig.In, dig.Out) to\n// make their special nature obvious in the godocs. Otherwise they will appear\n// as plain empty structs.\ntype digSentinel interface {\n\tdigSentinel()\n}\n\n// In may be embedded into structs to request dig to treat them as special\n// parameter structs. When a constructor accepts such a struct, instead of the\n// struct becoming a dependency for that constructor, all its fields become\n// dependencies instead. See the section on Parameter Objects in the\n// package-level documentation for more information.\n//\n// Fields of the struct may optionally be tagged to customize the behavior of\n// dig. The following tags are supported,\n//\n//   name        Requests a value with the same name and type from the\n//               container. See Named Values for more information.\n//   optional    If set to true, indicates that the dependency is optional and\n//               the constructor gracefully handles its absence.\n//   group       Name of the Value Group from which this field will be filled.\n//               The field must be a slice type. See Value Groups in the\n//               package documentation for more information.\ntype In struct{ digSentinel }\n\n// Out is an embeddable type that signals to dig that the returned\n// struct should be treated differently. Instead of the struct itself\n// becoming part of the container, all members of the struct will.\n\n// Out may be embedded into structs to request dig to treat them as special\n// result structs. When a constructor returns such a struct, instead of the\n// struct becoming a result of the constructor, all its fields become results\n// of the constructor. See the section on Result Objects in the package-level\n// documentation for more information.\n//\n// Fields of the struct may optionally be tagged to customize the behavior of\n// dig. The following tags are supported,\n//\n//   name        Specifies the name of the value. Only a field on a dig.In\n//               struct with the same 'name' annotation can receive this\n//               value. See Named Values for more information.\n//   group       Name of the Value Group to which this field's value is being\n//               sent. See Value Groups in the package documentation for more\n//               information.\ntype Out struct{ digSentinel }\n\nfunc isError(t reflect.Type) bool {\n\treturn t.Implements(_errType)\n}\n\n// IsIn checks whether the given struct is a dig.In struct. A struct qualifies\n// as a dig.In struct if it embeds the dig.In type or if any struct that it\n// embeds is a dig.In struct. The parameter may be the reflect.Type of the\n// struct rather than the struct itself.\n//\n// A struct MUST qualify as a dig.In struct for its fields to be treated\n// specially by dig.\n//\n// See the documentation for dig.In for a comprehensive list of supported\n// tags.\nfunc IsIn(o interface{}) bool {\n\treturn embedsType(o, _inType)\n}\n\n// IsOut checks whether the given struct is a dig.Out struct. A struct\n// qualifies as a dig.Out struct if it embeds the dig.Out type or if any\n// struct that it embeds is a dig.Out struct. The parameter may be the\n// reflect.Type of the struct rather than the struct itself.\n//\n// A struct MUST qualify as a dig.Out struct for its fields to be treated\n// specially by dig.\n//\n// See the documentation for dig.Out for a comprehensive list of supported\n// tags.\nfunc IsOut(o interface{}) bool {\n\treturn embedsType(o, _outType)\n}\n\n// Returns true if t embeds e or if any of the types embedded by t embed e.\nfunc embedsType(i interface{}, e reflect.Type) bool {\n\t// TODO: this function doesn't consider e being a pointer.\n\t// given `type A foo { *In }`, this function would return false for\n\t// embedding dig.In, which makes for some extra error checking in places\n\t// that call this funciton. Might be worthwhile to consider reflect.Indirect\n\t// usage to clean up the callers.\n\n\tif i == nil {\n\t\treturn false\n\t}\n\n\t// maybe it's already a reflect.Type\n\tt, ok := i.(reflect.Type)\n\tif !ok {\n\t\t// take the type if it's not\n\t\tt = reflect.TypeOf(i)\n\t}\n\n\t// We are going to do a breadth-first search of all embedded fields.\n\ttypes := list.New()\n\ttypes.PushBack(t)\n\tfor types.Len() > 0 {\n\t\tt := types.Remove(types.Front()).(reflect.Type)\n\n\t\tif t == e {\n\t\t\treturn true\n\t\t}\n\n\t\tif t.Kind() != reflect.Struct {\n\t\t\tcontinue\n\t\t}\n\n\t\tfor i := 0; i < t.NumField(); i++ {\n\t\t\tf := t.Field(i)\n\t\t\tif f.Anonymous {\n\t\t\t\ttypes.PushBack(f.Type)\n\t\t\t}\n\t\t}\n\t}\n\n\t// If perf is an issue, we can cache known In objects and Out objects in a\n\t// map[reflect.Type]struct{}.\n\treturn false\n}\n"
  },
  {
    "path": "vendor/go.uber.org/dig/version.go",
    "content": "// Copyright (c) 2018 Uber Technologies, Inc.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\npackage dig\n\n// Version of the library\nconst Version = \"1.6.0\"\n"
  },
  {
    "path": "vendor/google.golang.org/appengine/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "vendor/google.golang.org/appengine/cloudsql/cloudsql.go",
    "content": "// Copyright 2013 Google Inc. All rights reserved.\n// Use of this source code is governed by the Apache 2.0\n// license that can be found in the LICENSE file.\n\n/*\nPackage cloudsql exposes access to Google Cloud SQL databases.\n\nThis package does not work in App Engine \"flexible environment\".\n\nThis package is intended for MySQL drivers to make App Engine-specific\nconnections. Applications should use this package through database/sql:\nSelect a pure Go MySQL driver that supports this package, and use sql.Open\nwith protocol \"cloudsql\" and an address of the Cloud SQL instance.\n\nA Go MySQL driver that has been tested to work well with Cloud SQL\nis the go-sql-driver:\n\timport \"database/sql\"\n\timport _ \"github.com/go-sql-driver/mysql\"\n\n\tdb, err := sql.Open(\"mysql\", \"user@cloudsql(project-id:instance-name)/dbname\")\n\n\nAnother driver that works well with Cloud SQL is the mymysql driver:\n\timport \"database/sql\"\n\timport _ \"github.com/ziutek/mymysql/godrv\"\n\n\tdb, err := sql.Open(\"mymysql\", \"cloudsql:instance-name*dbname/user/password\")\n\n\nUsing either of these drivers, you can perform a standard SQL query.\nThis example assumes there is a table named 'users' with\ncolumns 'first_name' and 'last_name':\n\n\trows, err := db.Query(\"SELECT first_name, last_name FROM users\")\n\tif err != nil {\n\t\tlog.Errorf(ctx, \"db.Query: %v\", err)\n\t}\n\tdefer rows.Close()\n\n\tfor rows.Next() {\n\t\tvar firstName string\n\t\tvar lastName string\n\t\tif err := rows.Scan(&firstName, &lastName); err != nil {\n\t\t\tlog.Errorf(ctx, \"rows.Scan: %v\", err)\n\t\t\tcontinue\n\t\t}\n\t\tlog.Infof(ctx, \"First: %v - Last: %v\", firstName, lastName)\n\t}\n\tif err := rows.Err(); err != nil {\n\t\tlog.Errorf(ctx, \"Row error: %v\", err)\n\t}\n*/\npackage cloudsql\n\nimport (\n\t\"net\"\n)\n\n// Dial connects to the named Cloud SQL instance.\nfunc Dial(instance string) (net.Conn, error) {\n\treturn connect(instance)\n}\n"
  },
  {
    "path": "vendor/google.golang.org/appengine/cloudsql/cloudsql_classic.go",
    "content": "// Copyright 2013 Google Inc. All rights reserved.\n// Use of this source code is governed by the Apache 2.0\n// license that can be found in the LICENSE file.\n\n// +build appengine\n\npackage cloudsql\n\nimport (\n\t\"net\"\n\n\t\"appengine/cloudsql\"\n)\n\nfunc connect(instance string) (net.Conn, error) {\n\treturn cloudsql.Dial(instance)\n}\n"
  },
  {
    "path": "vendor/google.golang.org/appengine/cloudsql/cloudsql_vm.go",
    "content": "// Copyright 2013 Google Inc. All rights reserved.\n// Use of this source code is governed by the Apache 2.0\n// license that can be found in the LICENSE file.\n\n// +build !appengine\n\npackage cloudsql\n\nimport (\n\t\"errors\"\n\t\"net\"\n)\n\nfunc connect(instance string) (net.Conn, error) {\n\treturn nil, errors.New(`cloudsql: not supported in App Engine \"flexible environment\"`)\n}\n"
  },
  {
    "path": "vendor/vendor.json",
    "content": "{\n\t\"comment\": \"\",\n\t\"ignore\": \"test\",\n\t\"package\": [\n\t\t{\n\t\t\t\"path\": \"appengine/cloudsql\",\n\t\t\t\"revision\": \"\"\n\t\t},\n\t\t{\n\t\t\t\"checksumSHA1\": \"AIF4lP/6rhhHA4zsdvzfM1uFXi4=\",\n\t\t\t\"path\": \"github.com/DATA-DOG/go-sqlmock\",\n\t\t\t\"revision\": \"b9ca56ce96879f5362120ae10866bbf66f2c5db6\",\n\t\t\t\"revisionTime\": \"2018-03-04T15:30:57Z\"\n\t\t},\n\t\t{\n\t\t\t\"checksumSHA1\": \"OFu4xJEIjiI8Suu+j/gabfp+y6Q=\",\n\t\t\t\"origin\": \"github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew\",\n\t\t\t\"path\": \"github.com/davecgh/go-spew/spew\",\n\t\t\t\"revision\": \"2aa2c176b9dab406a6970f6a55f513e8a8c8b18f\",\n\t\t\t\"revisionTime\": \"2017-08-14T20:04:35Z\"\n\t\t},\n\t\t{\n\t\t\t\"checksumSHA1\": \"JXVlDIoOSmyi1QAgDI455Wsr/gY=\",\n\t\t\t\"path\": \"github.com/go-sql-driver/mysql\",\n\t\t\t\"revision\": \"3287d94d4c6a48a63e16fffaabf27ab20203af2a\",\n\t\t\t\"revisionTime\": \"2018-04-13T18:15:57Z\"\n\t\t},\n\t\t{\n\t\t\t\"checksumSHA1\": \"g/V4qrXjUGG9B+e3hB+4NAYJ5Gs=\",\n\t\t\t\"path\": \"github.com/gorilla/context\",\n\t\t\t\"revision\": \"08b5f424b9271eedf6f9f0ce86cb9396ed337a42\",\n\t\t\t\"revisionTime\": \"2016-08-17T18:46:32Z\"\n\t\t},\n\t\t{\n\t\t\t\"checksumSHA1\": \"YuYKzn2jczaM6DQcFDmukvAHUX4=\",\n\t\t\t\"path\": \"github.com/gorilla/mux\",\n\t\t\t\"revision\": \"94231ffd98496cbcb1c15b7bf2a9edfd5f852cd4\",\n\t\t\t\"revisionTime\": \"2018-04-03T18:23:30Z\"\n\t\t},\n\t\t{\n\t\t\t\"checksumSHA1\": \"zKKp5SZ3d3ycKe4EKMNT0BqAWBw=\",\n\t\t\t\"origin\": \"github.com/stretchr/testify/vendor/github.com/pmezard/go-difflib/difflib\",\n\t\t\t\"path\": \"github.com/pmezard/go-difflib/difflib\",\n\t\t\t\"revision\": \"2aa2c176b9dab406a6970f6a55f513e8a8c8b18f\",\n\t\t\t\"revisionTime\": \"2017-08-14T20:04:35Z\"\n\t\t},\n\t\t{\n\t\t\t\"checksumSHA1\": \"EO+jcRet/AJ6IY3lBO8l8BLsZWg=\",\n\t\t\t\"origin\": \"github.com/stretchr/testify/vendor/github.com/stretchr/objx\",\n\t\t\t\"path\": \"github.com/stretchr/objx\",\n\t\t\t\"revision\": \"2aa2c176b9dab406a6970f6a55f513e8a8c8b18f\",\n\t\t\t\"revisionTime\": \"2017-08-14T20:04:35Z\"\n\t\t},\n\t\t{\n\t\t\t\"checksumSHA1\": \"mGbTYZ8dHVTiPTTJu3ktp+84pPI=\",\n\t\t\t\"path\": \"github.com/stretchr/testify/assert\",\n\t\t\t\"revision\": \"2aa2c176b9dab406a6970f6a55f513e8a8c8b18f\",\n\t\t\t\"revisionTime\": \"2017-08-14T20:04:35Z\"\n\t\t},\n\t\t{\n\t\t\t\"checksumSHA1\": \"hs0IfAV4wNExbAXc0aUU9V2SuFc=\",\n\t\t\t\"path\": \"github.com/stretchr/testify/mock\",\n\t\t\t\"revision\": \"2aa2c176b9dab406a6970f6a55f513e8a8c8b18f\",\n\t\t\t\"revisionTime\": \"2017-08-14T20:04:35Z\"\n\t\t},\n\t\t{\n\t\t\t\"checksumSHA1\": \"7vs6dSc1PPGBKyzb/SCIyeMJPLQ=\",\n\t\t\t\"path\": \"github.com/stretchr/testify/require\",\n\t\t\t\"revision\": \"2aa2c176b9dab406a6970f6a55f513e8a8c8b18f\",\n\t\t\t\"revisionTime\": \"2017-08-14T20:04:35Z\"\n\t\t},\n\t\t{\n\t\t\t\"checksumSHA1\": \"4nm6kgOL/4Xj3j+CwKcggRg8Wno=\",\n\t\t\t\"path\": \"go.uber.org/dig\",\n\t\t\t\"revision\": \"007ab720a796b1027b6c289fb4e836c8fc077357\",\n\t\t\t\"revisionTime\": \"2018-09-19T20:28:59Z\"\n\t\t},\n\t\t{\n\t\t\t\"checksumSHA1\": \"ukkiijCfrA/L+yTvOhmUH+5sWyI=\",\n\t\t\t\"path\": \"go.uber.org/dig/internal/digreflect\",\n\t\t\t\"revision\": \"007ab720a796b1027b6c289fb4e836c8fc077357\",\n\t\t\t\"revisionTime\": \"2018-09-19T20:28:59Z\"\n\t\t},\n\t\t{\n\t\t\t\"checksumSHA1\": \"WURKr1FAB8025bzGumOQ/4U0rxI=\",\n\t\t\t\"path\": \"go.uber.org/dig/internal/dot\",\n\t\t\t\"revision\": \"007ab720a796b1027b6c289fb4e836c8fc077357\",\n\t\t\t\"revisionTime\": \"2018-09-19T20:28:59Z\"\n\t\t},\n\t\t{\n\t\t\t\"checksumSHA1\": \"LiyXfqOzaeQ8vgYZH3t2hUEdVTw=\",\n\t\t\t\"path\": \"google.golang.org/appengine/cloudsql\",\n\t\t\t\"revision\": \"0a24098c0ec68416ec050f567f75df563d6b231e\",\n\t\t\t\"revisionTime\": \"2018-04-05T22:03:34Z\"\n\t\t}\n\t],\n\t\"rootPath\": \"github.com/PacktPublishing/Hands-On-Dependency-Injection-in-Go\"\n}\n"
  }
]