<commit_before>// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
// this source code is governed by a BSD-style license that can be found in
// the LICENSE file.
//
// Package excelize providing a set of functions that allow you to write to
// and read from XLSX files. Support reads and writes XLSX file generated by
// Microsoft Excel™ 2007 and later. Support save file without losing original
// charts of XLSX. This library needs Go version 1.8 or later.

package excelize

import (
	"encoding/json"
	"encoding/xml"
	"fmt"
	"strconv"
	"strings"
)

// parseFormatCommentsSet provides a function to parse the format settings of
// the comment with default value.
func parseFormatCommentsSet(formatSet string) (*formatComment, error) {
	format := formatComment{
		Author: "Author:",
		Text:   " ",
	}
	err := json.Unmarshal([]byte(formatSet), &format)
	return &format, err
}

// GetComments retrieves all comments and returns a map of worksheet name to
// the worksheet comments.
func (f *File) GetComments() (comments map[string][]Comment) {
	comments = map[string][]Comment{}
	for n := range f.sheetMap {
		commentID := f.GetSheetIndex(n)
		commentsXML := "xl/comments" + strconv.Itoa(commentID) + ".xml"
		c, ok := f.XLSX[commentsXML]
		if ok {
			d := xlsxComments{}
			xml.Unmarshal([]byte(c), &d)
			sheetComments := []Comment{}
			for _, comment := range d.CommentList.Comment {
				sheetComment := Comment{}
				if comment.AuthorID < len(d.Authors) {
					sheetComment.Author = d.Authors[comment.AuthorID].Author
				}
				sheetComment.Ref = comment.Ref
				sheetComment.AuthorID = comment.AuthorID
				for _, text := range comment.Text.R {
					sheetComment.Text += text.T
				}
				sheetComments = append(sheetComments, sheetComment)
			}
			comments[n] = sheetComments
		}
	}
	return
}

// AddComment provides the method to add comment in a sheet by given worksheet
// index, cell and format set (such as author and text). Note that the max
// author length is 255 and the max text length is 32512. For example, add a
// comment in Sheet1!$A$30:
//
//    xlsx.AddComment("Sheet1", "A30", `{"author":"Excelize: ","text":"This is a comment."}`)
//
func (f *File) AddComment(sheet, cell, format string) error {
	formatSet, err := parseFormatCommentsSet(format)
	if err != nil {
		return err
	}
	// Read sheet data.
	xlsx := f.workSheetReader(sheet)
	commentID := f.countComments() + 1
	drawingVML := "xl/drawings/vmlDrawing" + strconv.Itoa(commentID) + ".vml"
	sheetRelationshipsComments := "../comments" + strconv.Itoa(commentID) + ".xml"
	sheetRelationshipsDrawingVML := "../drawings/vmlDrawing" + strconv.Itoa(commentID) + ".vml"
	if xlsx.LegacyDrawing != nil {
		// The worksheet already has a comments relationships, use the relationships drawing ../drawings/vmlDrawing%d.vml.
		sheetRelationshipsDrawingVML = f.getSheetRelationshipsTargetByID(sheet, xlsx.LegacyDrawing.RID)
		commentID, _ = strconv.Atoi(strings.TrimSuffix(strings.TrimPrefix(sheetRelationshipsDrawingVML, "../drawings/vmlDrawing"), ".vml"))
		drawingVML = strings.Replace(sheetRelationshipsDrawingVML, "..", "xl", -1)
	} else {
		// Add first comment for given sheet.
		rID := f.addSheetRelationships(sheet, SourceRelationshipDrawingVML, sheetRelationshipsDrawingVML, "")
		f.addSheetRelationships(sheet, SourceRelationshipComments, sheetRelationshipsComments, "")
		f.addSheetLegacyDrawing(sheet, rID)
	}
	commentsXML := "xl/comments" + strconv.Itoa(commentID) + ".xml"
	f.addComment(commentsXML, cell, formatSet)
	var colCount int
	for i, l := range strings.Split(formatSet.Text, "\n") {
		if ll := len(l); ll > colCount {
			if i == 0 {
				ll += len(formatSet.Author)
			}
			colCount = ll
		}
	}
	f.addDrawingVML(commentID, drawingVML, cell, strings.Count(formatSet.Text, "\n")+1, colCount)
	f.addContentTypePart(commentID, "comments")
	return err
}

// addDrawingVML provides a function to create comment as
// xl/drawings/vmlDrawing%d.vml by given commit ID and cell.
func (f *File) addDrawingVML(commentID int, drawingVML, cell string, lineCount, colCount int) {
	col := string(strings.Map(letterOnlyMapF, cell))
	row, _ := strconv.Atoi(strings.Map(intOnlyMapF, cell))
	xAxis := row - 1
	yAxis := TitleToNumber(col)
	vml := vmlDrawing{
		XMLNSv:  "urn:schemas-microsoft-com:vml",
		XMLNSo:  "urn:schemas-microsoft-com:office:office",
		XMLNSx:  "urn:schemas-microsoft-com:office:excel",
		XMLNSmv: "http://macVmlSchemaUri",
		Shapelayout: &xlsxShapelayout{
			Ext: "edit",
			IDmap: &xlsxIDmap{
				Ext:  "edit",
				Data: commentID,
			},
		},
		Shapetype: &xlsxShapetype{
			ID:        "_x0000_t202",
			Coordsize: "21600,21600",
			Spt:       202,
			Path:      "m0,0l0,21600,21600,21600,21600,0xe",
			Stroke: &xlsxStroke{
				Joinstyle: "miter",
			},
			VPath: &vPath{
				Gradientshapeok: "t",
				Connecttype:     "miter",
			},
		},
	}
	sp := encodeShape{
		Fill: &vFill{
			Color2: "#fbfe82",
			Angle:  -180,
			Type:   "gradient",
			Fill: &oFill{
				Ext:  "view",
				Type: "gradientUnscaled",
			},
		},
		Shadow: &vShadow{
			On:       "t",
			Color:    "black",
			Obscured: "t",
		},
		Path: &vPath{
			Connecttype: "none",
		},
		Textbox: &vTextbox{
			Style: "mso-direction-alt:auto",
			Div: &xlsxDiv{
				Style: "text-align:left",
			},
		},
		ClientData: &xClientData{
			ObjectType: "Note",
			Anchor: fmt.Sprintf(
				"%d, 23, %d, 0, %d, %d, %d, 5",
				1+yAxis, 1+xAxis, 2+yAxis+lineCount, colCount+yAxis, 2+xAxis+lineCount),
			AutoFill: "True",
			Row:      xAxis,
			Column:   yAxis,
		},
	}
	s, _ := xml.Marshal(sp)
	shape := xlsxShape{
		ID:          "_x0000_s1025",
		Type:        "#_x0000_t202",
		Style:       "position:absolute;73.5pt;width:108pt;height:59.25pt;z-index:1;visibility:hidden",
		Fillcolor:   "#fbf6d6",
		Strokecolor: "#edeaa1",
		Val:         string(s[13 : len(s)-14]),
	}
	c, ok := f.XLSX[drawingVML]
	if ok {
		d := decodeVmlDrawing{}
		_ = xml.Unmarshal(namespaceStrictToTransitional(c), &d)
		for _, v := range d.Shape {
			s := xlsxShape{
				ID:          "_x0000_s1025",
				Type:        "#_x0000_t202",
				Style:       "position:absolute;73.5pt;width:108pt;height:59.25pt;z-index:1;visibility:hidden",
				Fillcolor:   "#fbf6d6",
				Strokecolor: "#edeaa1",
				Val:         v.Val,
			}
			vml.Shape = append(vml.Shape, s)
		}
	}
	vml.Shape = append(vml.Shape, shape)
	v, _ := xml.Marshal(vml)
	f.XLSX[drawingVML] = v
}

// addComment provides a function to create chart as xl/comments%d.xml by
// given cell and format sets.
func (f *File) addComment(commentsXML, cell string, formatSet *formatComment) {
	a := formatSet.Author
	t := formatSet.Text
	if len(a) > 255 {
		a = a[0:255]
	}
	if len(t) > 32512 {
		t = t[0:32512]
	}
	comments := xlsxComments{
		Authors: []xlsxAuthor{
			{
				Author: formatSet.Author,
			},
		},
	}
	cmt := xlsxComment{
		Ref:      cell,
		AuthorID: 0,
		Text: xlsxText{
			R: []xlsxR{
				{
					RPr: &xlsxRPr{
						B:  " ",
						Sz: &attrValFloat{Val: 9},
						Color: &xlsxColor{
							Indexed: 81,
						},
						RFont:  &attrValString{Val: "Calibri"},
						Family: &attrValInt{Val: 2},
					},
					T: a,
				},
				{
					RPr: &xlsxRPr{
						Sz: &attrValFloat{Val: 9},
						Color: &xlsxColor{
							Indexed: 81,
						},
						RFont:  &attrValString{Val: "Calibri"},
						Family: &attrValInt{Val: 2},
					},
					T: t,
				},
			},
		},
	}
	c, ok := f.XLSX[commentsXML]
	if ok {
		d := xlsxComments{}
		_ = xml.Unmarshal(namespaceStrictToTransitional(c), &d)
		comments.CommentList.Comment = append(comments.CommentList.Comment, d.CommentList.Comment...)
	}
	comments.CommentList.Comment = append(comments.CommentList.Comment, cmt)
	v, _ := xml.Marshal(comments)
	f.saveFileList(commentsXML, v)
}

// countComments provides a function to get comments files count storage in
// the folder xl.
func (f *File) countComments() int {
	count := 0
	for k := range f.XLSX {
		if strings.Contains(k, "xl/comments") {
			count++
		}
	}
	return count
}
<commit_msg>Resolve #345, get comments by target reference<commit_after>// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
// this source code is governed by a BSD-style license that can be found in
// the LICENSE file.
//
// Package excelize providing a set of functions that allow you to write to
// and read from XLSX files. Support reads and writes XLSX file generated by
// Microsoft Excel™ 2007 and later. Support save file without losing original
// charts of XLSX. This library needs Go version 1.8 or later.

package excelize

import (
	"encoding/json"
	"encoding/xml"
	"fmt"
	"strconv"
	"strings"
)

// parseFormatCommentsSet provides a function to parse the format settings of
// the comment with default value.
func parseFormatCommentsSet(formatSet string) (*formatComment, error) {
	format := formatComment{
		Author: "Author:",
		Text:   " ",
	}
	err := json.Unmarshal([]byte(formatSet), &format)
	return &format, err
}

// GetComments retrieves all comments and returns a map of worksheet name to
// the worksheet comments.
func (f *File) GetComments() (comments map[string][]Comment) {
	comments = map[string][]Comment{}
	for n := range f.sheetMap {
		c, ok := f.XLSX["xl"+strings.TrimPrefix(f.getSheetComments(f.GetSheetIndex(n)), "..")]
		if ok {
			d := xlsxComments{}
			xml.Unmarshal([]byte(c), &d)
			sheetComments := []Comment{}
			for _, comment := range d.CommentList.Comment {
				sheetComment := Comment{}
				if comment.AuthorID < len(d.Authors) {
					sheetComment.Author = d.Authors[comment.AuthorID].Author
				}
				sheetComment.Ref = comment.Ref
				sheetComment.AuthorID = comment.AuthorID
				for _, text := range comment.Text.R {
					sheetComment.Text += text.T
				}
				sheetComments = append(sheetComments, sheetComment)
			}
			comments[n] = sheetComments
		}
	}
	return
}

// getSheetComments provides the method to get the target comment reference by
// given worksheet index.
func (f *File) getSheetComments(sheetID int) string {
	var rels = "xl/worksheets/_rels/sheet" + strconv.Itoa(sheetID) + ".xml.rels"
	var sheetRels xlsxWorkbookRels
	_ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML(rels)), &sheetRels)
	for _, v := range sheetRels.Relationships {
		if v.Type == SourceRelationshipComments {
			return v.Target
		}
	}
	return ""
}

// AddComment provides the method to add comment in a sheet by given worksheet
// index, cell and format set (such as author and text). Note that the max
// author length is 255 and the max text length is 32512. For example, add a
// comment in Sheet1!$A$30:
//
//    xlsx.AddComment("Sheet1", "A30", `{"author":"Excelize: ","text":"This is a comment."}`)
//
func (f *File) AddComment(sheet, cell, format string) error {
	formatSet, err := parseFormatCommentsSet(format)
	if err != nil {
		return err
	}
	// Read sheet data.
	xlsx := f.workSheetReader(sheet)
	commentID := f.countComments() + 1
	drawingVML := "xl/drawings/vmlDrawing" + strconv.Itoa(commentID) + ".vml"
	sheetRelationshipsComments := "../comments" + strconv.Itoa(commentID) + ".xml"
	sheetRelationshipsDrawingVML := "../drawings/vmlDrawing" + strconv.Itoa(commentID) + ".vml"
	if xlsx.LegacyDrawing != nil {
		// The worksheet already has a comments relationships, use the relationships drawing ../drawings/vmlDrawing%d.vml.
		sheetRelationshipsDrawingVML = f.getSheetRelationshipsTargetByID(sheet, xlsx.LegacyDrawing.RID)
		commentID, _ = strconv.Atoi(strings.TrimSuffix(strings.TrimPrefix(sheetRelationshipsDrawingVML, "../drawings/vmlDrawing"), ".vml"))
		drawingVML = strings.Replace(sheetRelationshipsDrawingVML, "..", "xl", -1)
	} else {
		// Add first comment for given sheet.
		rID := f.addSheetRelationships(sheet, SourceRelationshipDrawingVML, sheetRelationshipsDrawingVML, "")
		f.addSheetRelationships(sheet, SourceRelationshipComments, sheetRelationshipsComments, "")
		f.addSheetLegacyDrawing(sheet, rID)
	}
	commentsXML := "xl/comments" + strconv.Itoa(commentID) + ".xml"
	f.addComment(commentsXML, cell, formatSet)
	var colCount int
	for i, l := range strings.Split(formatSet.Text, "\n") {
		if ll := len(l); ll > colCount {
			if i == 0 {
				ll += len(formatSet.Author)
			}
			colCount = ll
		}
	}
	f.addDrawingVML(commentID, drawingVML, cell, strings.Count(formatSet.Text, "\n")+1, colCount)
	f.addContentTypePart(commentID, "comments")
	return err
}

// addDrawingVML provides a function to create comment as
// xl/drawings/vmlDrawing%d.vml by given commit ID and cell.
func (f *File) addDrawingVML(commentID int, drawingVML, cell string, lineCount, colCount int) {
	col := string(strings.Map(letterOnlyMapF, cell))
	row, _ := strconv.Atoi(strings.Map(intOnlyMapF, cell))
	xAxis := row - 1
	yAxis := TitleToNumber(col)
	vml := vmlDrawing{
		XMLNSv:  "urn:schemas-microsoft-com:vml",
		XMLNSo:  "urn:schemas-microsoft-com:office:office",
		XMLNSx:  "urn:schemas-microsoft-com:office:excel",
		XMLNSmv: "http://macVmlSchemaUri",
		Shapelayout: &xlsxShapelayout{
			Ext: "edit",
			IDmap: &xlsxIDmap{
				Ext:  "edit",
				Data: commentID,
			},
		},
		Shapetype: &xlsxShapetype{
			ID:        "_x0000_t202",
			Coordsize: "21600,21600",
			Spt:       202,
			Path:      "m0,0l0,21600,21600,21600,21600,0xe",
			Stroke: &xlsxStroke{
				Joinstyle: "miter",
			},
			VPath: &vPath{
				Gradientshapeok: "t",
				Connecttype:     "miter",
			},
		},
	}
	sp := encodeShape{
		Fill: &vFill{
			Color2: "#fbfe82",
			Angle:  -180,
			Type:   "gradient",
			Fill: &oFill{
				Ext:  "view",
				Type: "gradientUnscaled",
			},
		},
		Shadow: &vShadow{
			On:       "t",
			Color:    "black",
			Obscured: "t",
		},
		Path: &vPath{
			Connecttype: "none",
		},
		Textbox: &vTextbox{
			Style: "mso-direction-alt:auto",
			Div: &xlsxDiv{
				Style: "text-align:left",
			},
		},
		ClientData: &xClientData{
			ObjectType: "Note",
			Anchor: fmt.Sprintf(
				"%d, 23, %d, 0, %d, %d, %d, 5",
				1+yAxis, 1+xAxis, 2+yAxis+lineCount, colCount+yAxis, 2+xAxis+lineCount),
			AutoFill: "True",
			Row:      xAxis,
			Column:   yAxis,
		},
	}
	s, _ := xml.Marshal(sp)
	shape := xlsxShape{
		ID:          "_x0000_s1025",
		Type:        "#_x0000_t202",
		Style:       "position:absolute;73.5pt;width:108pt;height:59.25pt;z-index:1;visibility:hidden",
		Fillcolor:   "#fbf6d6",
		Strokecolor: "#edeaa1",
		Val:         string(s[13 : len(s)-14]),
	}
	c, ok := f.XLSX[drawingVML]
	if ok {
		d := decodeVmlDrawing{}
		_ = xml.Unmarshal(namespaceStrictToTransitional(c), &d)
		for _, v := range d.Shape {
			s := xlsxShape{
				ID:          "_x0000_s1025",
				Type:        "#_x0000_t202",
				Style:       "position:absolute;73.5pt;width:108pt;height:59.25pt;z-index:1;visibility:hidden",
				Fillcolor:   "#fbf6d6",
				Strokecolor: "#edeaa1",
				Val:         v.Val,
			}
			vml.Shape = append(vml.Shape, s)
		}
	}
	vml.Shape = append(vml.Shape, shape)
	v, _ := xml.Marshal(vml)
	f.XLSX[drawingVML] = v
}

// addComment provides a function to create chart as xl/comments%d.xml by
// given cell and format sets.
func (f *File) addComment(commentsXML, cell string, formatSet *formatComment) {
	a := formatSet.Author
	t := formatSet.Text
	if len(a) > 255 {
		a = a[0:255]
	}
	if len(t) > 32512 {
		t = t[0:32512]
	}
	comments := xlsxComments{
		Authors: []xlsxAuthor{
			{
				Author: formatSet.Author,
			},
		},
	}
	cmt := xlsxComment{
		Ref:      cell,
		AuthorID: 0,
		Text: xlsxText{
			R: []xlsxR{
				{
					RPr: &xlsxRPr{
						B:  " ",
						Sz: &attrValFloat{Val: 9},
						Color: &xlsxColor{
							Indexed: 81,
						},
						RFont:  &attrValString{Val: "Calibri"},
						Family: &attrValInt{Val: 2},
					},
					T: a,
				},
				{
					RPr: &xlsxRPr{
						Sz: &attrValFloat{Val: 9},
						Color: &xlsxColor{
							Indexed: 81,
						},
						RFont:  &attrValString{Val: "Calibri"},
						Family: &attrValInt{Val: 2},
					},
					T: t,
				},
			},
		},
	}
	c, ok := f.XLSX[commentsXML]
	if ok {
		d := xlsxComments{}
		_ = xml.Unmarshal(namespaceStrictToTransitional(c), &d)
		comments.CommentList.Comment = append(comments.CommentList.Comment, d.CommentList.Comment...)
	}
	comments.CommentList.Comment = append(comments.CommentList.Comment, cmt)
	v, _ := xml.Marshal(comments)
	f.saveFileList(commentsXML, v)
}

// countComments provides a function to get comments files count storage in
// the folder xl.
func (f *File) countComments() int {
	count := 0
	for k := range f.XLSX {
		if strings.Contains(k, "xl/comments") {
			count++
		}
	}
	return count
}
<|endoftext|>


<commit_before>// Command Gondl provides command line access to Quandl API
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/DannyBen/filecache"
	"github.com/DannyBen/quandl"
	"io/ioutil"
	"log"
	"os"
	"sort"
	"strconv"
)

const version = "0.2.0"

func main() {
	run(nil)
}

// run is injectable main
func run(args []string) {
	config := NewConfig(usage, args, version)
	arguments := config.Values

	switch {
	case arguments["--make-config"] != false:
		makeConfig()
	case arguments["--config"] != false:
		showConfig()
	case arguments["get"] != false:
		getSymbol(arguments)
	case arguments["list"] != false:
		getList(arguments)
	case arguments["search"] != false:
		getSearch(arguments)
	}

	if arguments["--debug"].(bool) {
		showArgs(arguments)
	}
}

// getSymbol downloads symbol data from Quandl and
// outputs it to stdout or file
func getSymbol(a map[string]interface{}) {
	quandlSetup(a)

	format := a["--format"].(string)
	showUrl := a["--url"].(bool)
	symbol := a["<symbol>"].(string)

	opts := getOptions(a, "column", "rows", "trim_start",
		"trim_end", "sort_order", "collapse", "transformation",
		"exclude_headers", "exclude_data")

	var result []byte
	var err error
	result, err = quandl.GetSymbolRaw(symbol, format, opts)
	panicon(err)

	output(a, result, format)
	showQuandlUrl(showUrl, quandl.LastUrl)
}

// getList downloads list of symbols for a given source
// and outputs it to stdout or file
func getList(a map[string]interface{}) {
	quandlSetup(a)
	source := a["<source>"].(string)
	format := a["--format"].(string)
	showUrl := a["--url"].(bool)
	page, _ := strconv.Atoi(a["--page"].(string))
	perPage, _ := strconv.Atoi(a["--per_page"].(string))

	result, err := quandl.GetListRaw(source, format, page, perPage)
	panicon(err)

	output(a, result, format)
	showQuandlUrl(showUrl, quandl.LastUrl)
}

// getSearch downloads search results given query and
// outputs it to stdout or file
func getSearch(a map[string]interface{}) {
	quandlSetup(a)
	query := a["<query>"].(string)
	format := a["--format"].(string)
	showUrl := a["--url"].(bool)
	page, _ := strconv.Atoi(a["--page"].(string))
	perPage, _ := strconv.Atoi(a["--per_page"].(string))

	// TODO: Remove this patch when Quandl guys fix the bug
	//       Also remove from quandl library
	if format == "csv" {
		format = "json"
	}

	result, err := quandl.GetSearchRaw(query, format, page, perPage)
	panicon(err)

	output(a, result, format)
	showQuandlUrl(showUrl, quandl.LastUrl)
}

// getOptions converts command line flags to quandl query string options
func getOptions(a map[string]interface{}, names ...string) quandl.Options {
	opts := quandl.Options{}
	for _, n := range names {
		key := string("--" + n)
		if a[key] != nil {
			if v, ok := a[key].(string); ok {
				opts.Set(n, v)
			} else if v, ok := a[key].(bool); ok {
				if v {
					opts.Set(n, "true")
				}
			}
		}
	}

	return opts
}

// output sends formatted output to stdout or file
func output(a map[string]interface{}, result []byte, format string) {
	outfile := a["--out"]

	var out bytes.Buffer

	if format == "json" {
		json.Indent(&out, result, "", "\t")
	} else {
		out.Write(result)
	}

	if outfile == nil {
		out.WriteTo(os.Stdout)
	} else {
		err := ioutil.WriteFile(outfile.(string), out.Bytes(), 0644)
		panicon(err)
	}
}

// quandlSetup configures the quandl object before each call
func quandlSetup(a map[string]interface{}) {
	if a["--apikey"] != nil {
		quandl.ApiKey = a["--apikey"].(string)
	}

	cacheDir := a["--cachedir"].(string)
	cacheLife, _ := strconv.ParseFloat(a["--cache"].(string), 32)
	if cacheLife > 0 {
		quandl.CacheHandler = filecache.Handler{cacheDir, cacheLife}
	}
}

// showArgs shows the command line args (--debug)
func showArgs(a map[string]interface{}) {
	fmt.Println("\nRegistered Arguments:")
	var keys []string
	for k := range a {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	for _, k := range keys {
		fmt.Printf("  %-18s %v\n", k, a[k])
	}
}

// showQuandlUrl shows the url used in the request (--url)
func showQuandlUrl(show bool, url string) {
	if show {
		fmt.Printf("\nQuandl URL:\n%s\n\n", url)
	}
}

func panicon(err error) {
	if err != nil {
		log.Fatal(err.Error())
	}
}

const usage = `Gondl - Command line console for Quandl

Usage:
  gondl --help | -h
  gondl --version | -v
  gondl --config [options]
  gondl --make-config
  gondl get <symbol> [options]
  gondl list <source> [options]
  gondl search <query> [options]

Standalone Options:
  -h, --help                Show this help.
  -v, --version             Show version details.
      --config              Show config files location and info.
      --make-config         Create a default gondl.json file.

Global Options:
  -k, --apikey <key>        Send this api key with the request
  -f, --format <format>     Output as csv, json or xml (default: csv)
  -o, --out <file>          Save to file
  -u, --url                 Show the request URL
  -d, --debug               Show all registered arguments
  -D, --cachedir <dir>      Set cache directory (default: ./cache)
  -C, --cache <mins>        Set cache life to <mins> minutes
                            0 to disable (default: 240)

Get Options:
  -c, --column <n>          Request data column <n> only
  -r, --rows <n>            Request <n> rows
  -t, --trim_start <date>   Start data at <date>, format yyyy-mm-dd
  -T, --trim_end <date>     End data at <date>, format yyyy-mm-dd
  -s, --sort_order <order>  Set sort order to asc or desc
  -x, --exclude_headers     Exclude CSV headers
      --exclude_data        Get meta data only (JSON/XML format)
      --collapse <f>        Set frequency to one of: none | daily |
                            weekly | monthly | quarterly | annual
      --transformation <t>  Enable data calculation. Set to one of:
                            diff | rdiff | cumul | normalize

Search/List Options:
  -p, --page <n>            Start at page <n> (default: 1)
  -P, --per_page <n>        Show <n> results per page (default: 300)

`

//;D
<commit_msg>Remove minor leftover code<commit_after>// Command Gondl provides command line access to Quandl API
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/DannyBen/filecache"
	"github.com/DannyBen/quandl"
	"io/ioutil"
	"log"
	"os"
	"sort"
	"strconv"
)

const version = "0.2.0"

func main() {
	run(nil)
}

// run is injectable main
func run(args []string) {
	config := NewConfig(usage, args, version)
	arguments := config.Values

	switch {
	case arguments["--make-config"] != false:
		makeConfig()
	case arguments["--config"] != false:
		showConfig()
	case arguments["get"] != false:
		getSymbol(arguments)
	case arguments["list"] != false:
		getList(arguments)
	case arguments["search"] != false:
		getSearch(arguments)
	}

	if arguments["--debug"].(bool) {
		showArgs(arguments)
	}
}

// getSymbol downloads symbol data from Quandl and
// outputs it to stdout or file
func getSymbol(a map[string]interface{}) {
	quandlSetup(a)

	format := a["--format"].(string)
	showUrl := a["--url"].(bool)
	symbol := a["<symbol>"].(string)

	opts := getOptions(a, "column", "rows", "trim_start",
		"trim_end", "sort_order", "collapse", "transformation",
		"exclude_headers", "exclude_data")

	result, err := quandl.GetSymbolRaw(symbol, format, opts)
	panicon(err)

	output(a, result, format)
	showQuandlUrl(showUrl, quandl.LastUrl)
}

// getList downloads list of symbols for a given source
// and outputs it to stdout or file
func getList(a map[string]interface{}) {
	quandlSetup(a)
	source := a["<source>"].(string)
	format := a["--format"].(string)
	showUrl := a["--url"].(bool)
	page, _ := strconv.Atoi(a["--page"].(string))
	perPage, _ := strconv.Atoi(a["--per_page"].(string))

	result, err := quandl.GetListRaw(source, format, page, perPage)
	panicon(err)

	output(a, result, format)
	showQuandlUrl(showUrl, quandl.LastUrl)
}

// getSearch downloads search results given query and
// outputs it to stdout or file
func getSearch(a map[string]interface{}) {
	quandlSetup(a)
	query := a["<query>"].(string)
	format := a["--format"].(string)
	showUrl := a["--url"].(bool)
	page, _ := strconv.Atoi(a["--page"].(string))
	perPage, _ := strconv.Atoi(a["--per_page"].(string))

	// TODO: Remove this patch when Quandl guys fix the bug
	//       Also remove from quandl library
	if format == "csv" {
		format = "json"
	}

	result, err := quandl.GetSearchRaw(query, format, page, perPage)
	panicon(err)

	output(a, result, format)
	showQuandlUrl(showUrl, quandl.LastUrl)
}

// getOptions converts command line flags to quandl query string options
func getOptions(a map[string]interface{}, names ...string) quandl.Options {
	opts := quandl.Options{}
	for _, n := range names {
		key := string("--" + n)
		if a[key] != nil {
			if v, ok := a[key].(string); ok {
				opts.Set(n, v)
			} else if v, ok := a[key].(bool); ok {
				if v {
					opts.Set(n, "true")
				}
			}
		}
	}

	return opts
}

// output sends formatted output to stdout or file
func output(a map[string]interface{}, result []byte, format string) {
	outfile := a["--out"]

	var out bytes.Buffer

	if format == "json" {
		json.Indent(&out, result, "", "\t")
	} else {
		out.Write(result)
	}

	if outfile == nil {
		out.WriteTo(os.Stdout)
	} else {
		err := ioutil.WriteFile(outfile.(string), out.Bytes(), 0644)
		panicon(err)
	}
}

// quandlSetup configures the quandl object before each call
func quandlSetup(a map[string]interface{}) {
	if a["--apikey"] != nil {
		quandl.ApiKey = a["--apikey"].(string)
	}

	cacheDir := a["--cachedir"].(string)
	cacheLife, _ := strconv.ParseFloat(a["--cache"].(string), 32)
	if cacheLife > 0 {
		quandl.CacheHandler = filecache.Handler{cacheDir, cacheLife}
	}
}

// showArgs shows the command line args (--debug)
func showArgs(a map[string]interface{}) {
	fmt.Println("\nRegistered Arguments:")
	var keys []string
	for k := range a {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	for _, k := range keys {
		fmt.Printf("  %-18s %v\n", k, a[k])
	}
}

// showQuandlUrl shows the url used in the request (--url)
func showQuandlUrl(show bool, url string) {
	if show {
		fmt.Printf("\nQuandl URL:\n%s\n\n", url)
	}
}

func panicon(err error) {
	if err != nil {
		log.Fatal(err.Error())
	}
}

const usage = `Gondl - Command line console for Quandl

Usage:
  gondl --help | -h
  gondl --version | -v
  gondl --config [options]
  gondl --make-config
  gondl get <symbol> [options]
  gondl list <source> [options]
  gondl search <query> [options]

Standalone Options:
  -h, --help                Show this help.
  -v, --version             Show version details.
      --config              Show config files location and info.
      --make-config         Create a default gondl.json file.

Global Options:
  -k, --apikey <key>        Send this api key with the request
  -f, --format <format>     Output as csv, json or xml (default: csv)
  -o, --out <file>          Save to file
  -u, --url                 Show the request URL
  -d, --debug               Show all registered arguments
  -D, --cachedir <dir>      Set cache directory (default: ./cache)
  -C, --cache <mins>        Set cache life to <mins> minutes
                            0 to disable (default: 240)

Get Options:
  -c, --column <n>          Request data column <n> only
  -r, --rows <n>            Request <n> rows
  -t, --trim_start <date>   Start data at <date>, format yyyy-mm-dd
  -T, --trim_end <date>     End data at <date>, format yyyy-mm-dd
  -s, --sort_order <order>  Set sort order to asc or desc
  -x, --exclude_headers     Exclude CSV headers
      --exclude_data        Get meta data only (JSON/XML format)
      --collapse <f>        Set frequency to one of: none | daily |
                            weekly | monthly | quarterly | annual
      --transformation <t>  Enable data calculation. Set to one of:
                            diff | rdiff | cumul | normalize

Search/List Options:
  -p, --page <n>            Start at page <n> (default: 1)
  -P, --per_page <n>        Show <n> results per page (default: 300)

`

//;D
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"os"
	"runtime"

	"github.com/pachyderm/pachyderm/src/common"
	"github.com/pachyderm/pachyderm/src/pfs"
	"github.com/pachyderm/pachyderm/src/pfs/fuse"
	"github.com/pachyderm/pachyderm/src/pfs/pfsutil"
	"github.com/peter-edge/go-env"
	"github.com/spf13/cobra"
	"google.golang.org/grpc"
)

const (
	defaultAddress = "0.0.0.0:650"
)

type appEnv struct {
	Address string `env:"PFS_ADDRESS"`
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	appEnv := &appEnv{}
	check(env.Populate(appEnv, env.PopulateOptions{}))
	if appEnv.Address == "" {
		appEnv.Address = defaultAddress
	}

	clientConn, err := grpc.Dial(appEnv.Address)
	check(err)
	apiClient := pfs.NewApiClient(clientConn)

	versionCmd := &cobra.Command{
		Use:  "version",
		Long: "Print the version.",
		Run: func(cmd *cobra.Command, args []string) {
			getVersionResponse, err := pfsutil.GetVersion(apiClient)
			check(err)
			fmt.Printf("Client: %s\nServer: %s\n", common.VersionString(), pfs.VersionString(getVersionResponse.Version))
		},
	}

	initCmd := &cobra.Command{
		Use:  "init repository-name",
		Long: "Initalize a repository.",
		Run: func(cmd *cobra.Command, args []string) {
			check(pfsutil.InitRepository(apiClient, args[0]))
		},
	}

	mkdirCmd := &cobra.Command{
		Use:  "mkdir repository-name commit-id path/to/dir",
		Long: "Make a directory. Sub directories must already exist.",
		Run: func(cmd *cobra.Command, args []string) {
			check(pfsutil.MakeDirectory(apiClient, args[0], args[1], args[2]))
		},
	}

	putCmd := &cobra.Command{
		Use:  "put repository-name branch-id path/to/file",
		Long: "Put a file from stdin. Directories must exist. branch-id must be a writeable commit.",
		Run: func(cmd *cobra.Command, args []string) {
			_, err := pfsutil.PutFile(apiClient, args[0], args[1], args[2], os.Stdin)
			check(err)
		},
	}

	getCmd := &cobra.Command{
		Use:  "get repository-name commit-id path/to/file",
		Long: "Get a file from stdout. commit-id must be a readable commit.",
		Run: func(cmd *cobra.Command, args []string) {
			reader, err := pfsutil.GetFile(apiClient, args[0], args[1], args[2])
			check(err)
			_, err = bufio.NewReader(reader).WriteTo(os.Stdout)
			check(err)
		},
	}

	lsCmd := &cobra.Command{
		Use:  "ls repository-name branch-id path/to/dir",
		Long: "List a directory. Directory must exist.",
		Run: func(cmd *cobra.Command, args []string) {
			listFilesResponse, err := pfsutil.ListFiles(apiClient, args[0], args[1], args[2], 0, 1)
			check(err)
			for _, fileInfo := range listFilesResponse.FileInfo {
				fmt.Printf("%+v\n", fileInfo)
			}
		},
	}

	branchCmd := &cobra.Command{
		Use:  "branch repository-name commit-id",
		Long: "Branch a commit. commit-id must be a readable commit.",
		Run: func(cmd *cobra.Command, args []string) {
			branchResponse, err := pfsutil.Branch(apiClient, args[0], args[1])
			check(err)
			fmt.Println(branchResponse.Commit.Id)
		},
	}

	commitCmd := &cobra.Command{
		Use:  "commit repository-name branch-id",
		Long: "Commit a branch. branch-id must be a writeable commit.",
		Run: func(cmd *cobra.Command, args []string) {
			check(pfsutil.Commit(apiClient, args[0], args[1]))
		},
	}

	commitInfoCmd := &cobra.Command{
		Use:  "commit-info repository-name commit-id",
		Long: "Get info for a commit.",
		Run: func(cmd *cobra.Command, args []string) {
			commitInfoResponse, err := pfsutil.GetCommitInfo(apiClient, args[0], args[1])
			check(err)
			fmt.Printf("%+v\n", commitInfoResponse.CommitInfo)
		},
	}

	mountCmd := &cobra.Command{
		Use:  "mount repository-name commit-id mount-point",
		Long: "Mount a repository as a local file system.",
		Run: func(cmd *cobra.Command, args []string) {
			check(fuse.Mount(apiClient, args[0], args[1], args[2]))
		},
	}

	rootCmd := &cobra.Command{
		Use: "pfs",
		Long: `Access the PFS API.

Note that this CLI is experimental and does not even check for common errors.
The environment variable PFS_ADDRESS controls what server the CLI connects to, the default is 0.0.0.0:650.`,
	}

	rootCmd.AddCommand(versionCmd)
	rootCmd.AddCommand(initCmd)
	rootCmd.AddCommand(mkdirCmd)
	rootCmd.AddCommand(putCmd)
	rootCmd.AddCommand(getCmd)
	rootCmd.AddCommand(lsCmd)
	rootCmd.AddCommand(branchCmd)
	rootCmd.AddCommand(commitCmd)
	rootCmd.AddCommand(commitInfoCmd)
	rootCmd.AddCommand(mountCmd)
	check(rootCmd.Execute())

	os.Exit(0)
}

func check(err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err.Error())
		os.Exit(1)
	}
}
<commit_msg>Adds checks for argument counts.<commit_after>package main

import (
	"bufio"
	"fmt"
	"os"
	"runtime"

	"github.com/pachyderm/pachyderm/src/common"
	"github.com/pachyderm/pachyderm/src/pfs"
	"github.com/pachyderm/pachyderm/src/pfs/fuse"
	"github.com/pachyderm/pachyderm/src/pfs/pfsutil"
	"github.com/peter-edge/go-env"
	"github.com/spf13/cobra"
	"google.golang.org/grpc"
)

const (
	defaultAddress = "0.0.0.0:650"
)

type appEnv struct {
	Address string `env:"PFS_ADDRESS"`
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	appEnv := &appEnv{}
	check(env.Populate(appEnv, env.PopulateOptions{}))
	if appEnv.Address == "" {
		appEnv.Address = defaultAddress
	}

	clientConn, err := grpc.Dial(appEnv.Address)
	check(err)
	apiClient := pfs.NewApiClient(clientConn)

	versionCmd := &cobra.Command{
		Use:  "version",
		Long: "Print the version.",
		Run: func(cmd *cobra.Command, args []string) {
			getVersionResponse, err := pfsutil.GetVersion(apiClient)
			check(err)
			fmt.Printf("Client: %s\nServer: %s\n", common.VersionString(), pfs.VersionString(getVersionResponse.Version))
		},
	}

	initUsage := "init repository-name"
	initCmd := &cobra.Command{
		Use:  initUsage,
		Long: "Initalize a repository.",
		Run: func(cmd *cobra.Command, args []string) {
			checkArgs(args, 1, initUsage)
			check(pfsutil.InitRepository(apiClient, args[0]))
		},
	}
	mkdirUsage := "mkdir repository-name commit-id path/to/dir"
	mkdirCmd := &cobra.Command{
		Use:  mkdirUsage,
		Long: "Make a directory. Sub directories must already exist.",
		Run: func(cmd *cobra.Command, args []string) {
			checkArgs(args, 3, mkdirUsage)
			check(pfsutil.MakeDirectory(apiClient, args[0], args[1], args[2]))
		},
	}

	putUsage := "put repository-name branch-id path/to/file"
	putCmd := &cobra.Command{
		Use:  putUsage,
		Long: "Put a file from stdin. Directories must exist. branch-id must be a writeable commit.",
		Run: func(cmd *cobra.Command, args []string) {
			checkArgs(args, 3, putUsage)
			_, err := pfsutil.PutFile(apiClient, args[0], args[1], args[2], os.Stdin)
			check(err)
		},
	}

	getUsage := "get repository-name commit-id path/to/file"
	getCmd := &cobra.Command{
		Use:  getUsage,
		Long: "Get a file from stdout. commit-id must be a readable commit.",
		Run: func(cmd *cobra.Command, args []string) {
			checkArgs(args, 3, getUsage)
			reader, err := pfsutil.GetFile(apiClient, args[0], args[1], args[2])
			check(err)
			_, err = bufio.NewReader(reader).WriteTo(os.Stdout)
			check(err)
		},
	}

	lsUsage := "ls repository-name branch-id path/to/dir"
	lsCmd := &cobra.Command{
		Use:  lsUsage,
		Long: "List a directory. Directory must exist.",
		Run: func(cmd *cobra.Command, args []string) {
			checkArgs(args, 3, lsUsage)
			listFilesResponse, err := pfsutil.ListFiles(apiClient, args[0], args[1], args[2], 0, 1)
			check(err)
			for _, fileInfo := range listFilesResponse.FileInfo {
				fmt.Printf("%+v\n", fileInfo)
			}
		},
	}

	branchUsage := "branch repository-name commit-id"
	branchCmd := &cobra.Command{
		Use:  branchUsage,
		Long: "Branch a commit. commit-id must be a readable commit.",
		Run: func(cmd *cobra.Command, args []string) {
			checkArgs(args, 2, branchUsage)
			branchResponse, err := pfsutil.Branch(apiClient, args[0], args[1])
			check(err)
			fmt.Println(branchResponse.Commit.Id)
		},
	}

	commitUsage := "commit repository-name branch-id"
	commitCmd := &cobra.Command{
		Use:  commitUsage,
		Long: "Commit a branch. branch-id must be a writeable commit.",
		Run: func(cmd *cobra.Command, args []string) {
			checkArgs(args, 2, commitUsage)
			check(pfsutil.Commit(apiClient, args[0], args[1]))
		},
	}

	commitInfoUsage := "commit-info repository-name commit-id"
	commitInfoCmd := &cobra.Command{
		Use:  commitInfoUsage,
		Long: "Get info for a commit.",
		Run: func(cmd *cobra.Command, args []string) {
			checkArgs(args, 2, commitInfoUsage)
			commitInfoResponse, err := pfsutil.GetCommitInfo(apiClient, args[0], args[1])
			check(err)
			fmt.Printf("%+v\n", commitInfoResponse.CommitInfo)
		},
	}

	mountUsage := "mount repository-name commit-id mount-point"
	mountCmd := &cobra.Command{
		Use:  mountUsage,
		Long: "Mount a repository as a local file system.",
		Run: func(cmd *cobra.Command, args []string) {
			checkArgs(args, 3, mountUsage)
			check(fuse.Mount(apiClient, args[0], args[1], args[2]))
		},
	}

	rootCmd := &cobra.Command{
		Use: "pfs",
		Long: `Access the PFS API.

Note that this CLI is experimental and does not even check for common errors.
The environment variable PFS_ADDRESS controls what server the CLI connects to, the default is 0.0.0.0:650.`,
	}

	rootCmd.AddCommand(versionCmd)
	rootCmd.AddCommand(initCmd)
	rootCmd.AddCommand(mkdirCmd)
	rootCmd.AddCommand(putCmd)
	rootCmd.AddCommand(getCmd)
	rootCmd.AddCommand(lsCmd)
	rootCmd.AddCommand(branchCmd)
	rootCmd.AddCommand(commitCmd)
	rootCmd.AddCommand(commitInfoCmd)
	rootCmd.AddCommand(mountCmd)
	check(rootCmd.Execute())

	os.Exit(0)
}

func check(err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err.Error())
		os.Exit(1)
	}
}

func checkArgs(args []string, expected int, usage string) {
	if len(args) != expected {
		fmt.Fprintf(os.Stderr,
			`Error, wrong number of arguments. Got %d, need %d.
%s
`,
			len(args), expected, usage)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package httpclient

import (
	"bytes"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
	"strings"
	"time"
)

var XmlHeaderBytes []byte = []byte(xml.Header)

type HTTPClient struct {
	BaseURL          *url.URL
	Headers          http.Header
	Client           *http.Client
	PostHooks        map[int]func(*http.Request, *http.Response) error
	rateLimited      bool
	rateLimitChan    chan struct{}
	rateLimitTimeout time.Duration
}

func New() (httpClient *HTTPClient) {
	return &HTTPClient{
		Client:    HttpClient,
		Headers:   make(http.Header),
		PostHooks: make(map[int]func(*http.Request, *http.Response) error),
	}
}

func Insecure() (httpClient *HTTPClient) {
	httpClient = New()
	httpClient.Client = InsecureHttpClient
	return httpClient
}

var DefaultClient = New()

func (c *HTTPClient) SetPostHook(onStatus int, hook func(*http.Request, *http.Response) error) {
	c.PostHooks[onStatus] = hook
}

func (c *HTTPClient) SetRateLimit(limit int, timeout time.Duration) {
	c.rateLimited = true
	c.rateLimitChan = make(chan struct{}, limit)

	for i := 0; i < limit; i++ {
		c.rateLimitChan <- struct{}{}
	}

	c.rateLimitTimeout = timeout
}

func (c *HTTPClient) buildURL(req *RequestData) *url.URL {
	bu := c.BaseURL

	opaque := EscapePath(bu.Path + req.Path)

	u := &url.URL{
		Scheme: bu.Scheme,
		Host:   bu.Host,
		Opaque: opaque,
	}

	if req.Params != nil {
		u.RawQuery = req.Params.Encode()
	}

	return u
}

func (c *HTTPClient) setHeaders(req *RequestData, httpReq *http.Request) {
	switch req.RespEncoding {
	case EncodingJSON:
		httpReq.Header.Set("Accept", "application/json")
	case EncodingXML:
		httpReq.Header.Set("Accept", "application/xml")
	}

	if c.Headers != nil {
		for key, values := range c.Headers {
			for _, value := range values {
				httpReq.Header.Set(key, value)
			}
		}
	}

	if req.Headers != nil {
		for key, values := range req.Headers {
			for _, value := range values {
				httpReq.Header.Set(key, value)
			}
		}
	}
}

func (c *HTTPClient) checkStatus(req *RequestData, response *http.Response) (err error) {
	if req.ExpectedStatus != nil {
		statusOk := false

		for _, status := range req.ExpectedStatus {
			if response.StatusCode == status {
				statusOk = true
			}
		}

		if !statusOk {
			lr := io.LimitReader(response.Body, 10*1024)
			contentBytes, _ := ioutil.ReadAll(lr)
			content := string(contentBytes)

			err = InvalidStatusError{
				Expected: req.ExpectedStatus,
				Got:      response.StatusCode,
				Headers:  response.Header,
				Content:  content,
			}

			return err
		}
	}

	return nil
}

func (c *HTTPClient) unmarshalResponse(req *RequestData, response *http.Response) (err error) {
	var buf []byte

	switch req.RespEncoding {
	case EncodingJSON:
		defer response.Body.Close()

		if buf, err = ioutil.ReadAll(response.Body); err != nil {
			return err
		}

		err = json.Unmarshal(buf, req.RespValue)

		if err != nil {
			return err
		}

		return nil

	case EncodingXML:
		defer response.Body.Close()

		if buf, err = ioutil.ReadAll(response.Body); err != nil {
			return err
		}

		err = xml.Unmarshal(buf, req.RespValue)

		if err != nil {
			return err
		}

		return nil
	}

	switch req.RespValue.(type) {
	case *[]byte:
		defer response.Body.Close()

		if buf, err = ioutil.ReadAll(response.Body); err != nil {
			return err
		}

		respVal := req.RespValue.(*[]byte)
		*respVal = buf

		return nil
	}

	if req.RespConsume {
		defer response.Body.Close()
		ioutil.ReadAll(response.Body)
	}

	return nil
}

func (c *HTTPClient) marshalRequest(req *RequestData) (err error) {
	if req.ReqReader != nil || req.ReqValue == nil {
		return nil
	}

	if req.Headers == nil {
		req.Headers = make(http.Header)
	}

	var buf []byte

	switch req.ReqEncoding {
	case EncodingJSON:
		buf, err = json.Marshal(req.ReqValue)

		if err != nil {
			return err
		}

		req.ReqReader = bytes.NewReader(buf)
		req.Headers.Set("Content-Type", "application/json")
		req.Headers.Set("Content-Length", fmt.Sprintf("%d", len(buf)))

		req.ReqContentLength = int64(len(buf))

		return nil

	case EncodingXML:
		buf, err = xml.Marshal(req.ReqValue)

		if err != nil {
			return err
		}

		buf = append(XmlHeaderBytes, buf...)

		req.ReqReader = bytes.NewReader(buf)
		req.Headers.Set("Content-Type", "application/xml")
		req.Headers.Set("Content-Length", fmt.Sprintf("%d", len(buf)))

		req.ReqContentLength = int64(len(buf))

		return nil

	case EncodingForm:
		if data, ok := req.ReqValue.(url.Values); ok {
			formStr := data.Encode()
			req.ReqReader = strings.NewReader(formStr)
			req.Headers.Set("Content-Type", "application/x-www-form-urlencoded")

			req.Headers.Set("Content-Length", fmt.Sprintf("%d", len(formStr)))

			req.ReqContentLength = int64(len(formStr))

			return nil
		} else {
			return fmt.Errorf("HTTPClient: invalid ReqValue type %T", req.ReqValue)
		}
	}

	return fmt.Errorf("HTTPClient: invalid ReqEncoding: %s", req.ReqEncoding)
}

func (c *HTTPClient) runPostHook(req *http.Request, response *http.Response) (err error) {
	hook, ok := c.PostHooks[response.StatusCode]

	if ok {
		err = hook(req, response)
	}

	return err
}

func (c *HTTPClient) Request(req *RequestData) (response *http.Response, err error) {
	err = c.marshalRequest(req)

	if err != nil {
		return nil, err
	}

	r, err := http.NewRequest(req.Method, req.FullURL, req.ReqReader)

	if err != nil {
		return nil, err
	}

	r.ContentLength = req.ReqContentLength

	if req.FullURL == "" {
		r.URL = c.buildURL(req)
		r.Host = r.URL.Host
	}

	c.setHeaders(req, r)

	if c.rateLimited {
		if c.rateLimitTimeout > 0 {
			select {
			case t := <-c.rateLimitChan:
				defer func() {
					c.rateLimitChan <- t
				}()
			case <-time.After(c.rateLimitTimeout):
				return nil, RateLimitTimeoutError
			}
		} else {
			t := <-c.rateLimitChan
			defer func() {
				c.rateLimitChan <- t
			}()
		}
	}

	isTraceEnabled := os.Getenv("HTTPCLIENT_TRACE") != ""

	if isTraceEnabled {
		requestBytes, _ := httputil.DumpRequestOut(r, true)
		fmt.Println(string(requestBytes))
	}

	if req.IgnoreRedirects {
		transport := c.Client.Transport

		if transport == nil {
			transport = http.DefaultTransport
		}

		response, err = transport.RoundTrip(r)
	} else {
		response, err = c.Client.Do(r)
	}

	if isTraceEnabled {
		responseBytes, _ := httputil.DumpResponse(response, true)
		fmt.Println(string(responseBytes))
	}

	if err != nil {
		return response, err
	}

	if err = c.runPostHook(r, response); err != nil {
		return response, err
	}

	if err = c.checkStatus(req, response); err != nil {
		defer response.Body.Close()
		return response, err
	}

	if err = c.unmarshalResponse(req, response); err != nil {
		return response, err
	}

	return response, nil
}
<commit_msg>Fix URL path concatenation<commit_after>package httpclient

import (
	"bytes"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
	"strings"
	"time"
)

var XmlHeaderBytes []byte = []byte(xml.Header)

type HTTPClient struct {
	BaseURL          *url.URL
	Headers          http.Header
	Client           *http.Client
	PostHooks        map[int]func(*http.Request, *http.Response) error
	rateLimited      bool
	rateLimitChan    chan struct{}
	rateLimitTimeout time.Duration
}

func New() (httpClient *HTTPClient) {
	return &HTTPClient{
		Client:    HttpClient,
		Headers:   make(http.Header),
		PostHooks: make(map[int]func(*http.Request, *http.Response) error),
	}
}

func Insecure() (httpClient *HTTPClient) {
	httpClient = New()
	httpClient.Client = InsecureHttpClient
	return httpClient
}

var DefaultClient = New()

func (c *HTTPClient) SetPostHook(onStatus int, hook func(*http.Request, *http.Response) error) {
	c.PostHooks[onStatus] = hook
}

func (c *HTTPClient) SetRateLimit(limit int, timeout time.Duration) {
	c.rateLimited = true
	c.rateLimitChan = make(chan struct{}, limit)

	for i := 0; i < limit; i++ {
		c.rateLimitChan <- struct{}{}
	}

	c.rateLimitTimeout = timeout
}

func (c *HTTPClient) buildURL(req *RequestData) *url.URL {
	bu := c.BaseURL

	rpath := req.Path

	if strings.HasSuffix(bu.Path, "/") && strings.HasPrefix(rpath, "/") {
		rpath = rpath[1:]
	}

	opaque := EscapePath(bu.Path + rpath)

	u := &url.URL{
		Scheme: bu.Scheme,
		Host:   bu.Host,
		Opaque: opaque,
	}

	if req.Params != nil {
		u.RawQuery = req.Params.Encode()
	}

	return u
}

func (c *HTTPClient) setHeaders(req *RequestData, httpReq *http.Request) {
	switch req.RespEncoding {
	case EncodingJSON:
		httpReq.Header.Set("Accept", "application/json")
	case EncodingXML:
		httpReq.Header.Set("Accept", "application/xml")
	}

	if c.Headers != nil {
		for key, values := range c.Headers {
			for _, value := range values {
				httpReq.Header.Set(key, value)
			}
		}
	}

	if req.Headers != nil {
		for key, values := range req.Headers {
			for _, value := range values {
				httpReq.Header.Set(key, value)
			}
		}
	}
}

func (c *HTTPClient) checkStatus(req *RequestData, response *http.Response) (err error) {
	if req.ExpectedStatus != nil {
		statusOk := false

		for _, status := range req.ExpectedStatus {
			if response.StatusCode == status {
				statusOk = true
			}
		}

		if !statusOk {
			lr := io.LimitReader(response.Body, 10*1024)
			contentBytes, _ := ioutil.ReadAll(lr)
			content := string(contentBytes)

			err = InvalidStatusError{
				Expected: req.ExpectedStatus,
				Got:      response.StatusCode,
				Headers:  response.Header,
				Content:  content,
			}

			return err
		}
	}

	return nil
}

func (c *HTTPClient) unmarshalResponse(req *RequestData, response *http.Response) (err error) {
	var buf []byte

	switch req.RespEncoding {
	case EncodingJSON:
		defer response.Body.Close()

		if buf, err = ioutil.ReadAll(response.Body); err != nil {
			return err
		}

		err = json.Unmarshal(buf, req.RespValue)

		if err != nil {
			return err
		}

		return nil

	case EncodingXML:
		defer response.Body.Close()

		if buf, err = ioutil.ReadAll(response.Body); err != nil {
			return err
		}

		err = xml.Unmarshal(buf, req.RespValue)

		if err != nil {
			return err
		}

		return nil
	}

	switch req.RespValue.(type) {
	case *[]byte:
		defer response.Body.Close()

		if buf, err = ioutil.ReadAll(response.Body); err != nil {
			return err
		}

		respVal := req.RespValue.(*[]byte)
		*respVal = buf

		return nil
	}

	if req.RespConsume {
		defer response.Body.Close()
		ioutil.ReadAll(response.Body)
	}

	return nil
}

func (c *HTTPClient) marshalRequest(req *RequestData) (err error) {
	if req.ReqReader != nil || req.ReqValue == nil {
		return nil
	}

	if req.Headers == nil {
		req.Headers = make(http.Header)
	}

	var buf []byte

	switch req.ReqEncoding {
	case EncodingJSON:
		buf, err = json.Marshal(req.ReqValue)

		if err != nil {
			return err
		}

		req.ReqReader = bytes.NewReader(buf)
		req.Headers.Set("Content-Type", "application/json")
		req.Headers.Set("Content-Length", fmt.Sprintf("%d", len(buf)))

		req.ReqContentLength = int64(len(buf))

		return nil

	case EncodingXML:
		buf, err = xml.Marshal(req.ReqValue)

		if err != nil {
			return err
		}

		buf = append(XmlHeaderBytes, buf...)

		req.ReqReader = bytes.NewReader(buf)
		req.Headers.Set("Content-Type", "application/xml")
		req.Headers.Set("Content-Length", fmt.Sprintf("%d", len(buf)))

		req.ReqContentLength = int64(len(buf))

		return nil

	case EncodingForm:
		if data, ok := req.ReqValue.(url.Values); ok {
			formStr := data.Encode()
			req.ReqReader = strings.NewReader(formStr)
			req.Headers.Set("Content-Type", "application/x-www-form-urlencoded")

			req.Headers.Set("Content-Length", fmt.Sprintf("%d", len(formStr)))

			req.ReqContentLength = int64(len(formStr))

			return nil
		} else {
			return fmt.Errorf("HTTPClient: invalid ReqValue type %T", req.ReqValue)
		}
	}

	return fmt.Errorf("HTTPClient: invalid ReqEncoding: %s", req.ReqEncoding)
}

func (c *HTTPClient) runPostHook(req *http.Request, response *http.Response) (err error) {
	hook, ok := c.PostHooks[response.StatusCode]

	if ok {
		err = hook(req, response)
	}

	return err
}

func (c *HTTPClient) Request(req *RequestData) (response *http.Response, err error) {
	err = c.marshalRequest(req)

	if err != nil {
		return nil, err
	}

	r, err := http.NewRequest(req.Method, req.FullURL, req.ReqReader)

	if err != nil {
		return nil, err
	}

	r.ContentLength = req.ReqContentLength

	if req.FullURL == "" {
		r.URL = c.buildURL(req)
		r.Host = r.URL.Host
	}

	c.setHeaders(req, r)

	if c.rateLimited {
		if c.rateLimitTimeout > 0 {
			select {
			case t := <-c.rateLimitChan:
				defer func() {
					c.rateLimitChan <- t
				}()
			case <-time.After(c.rateLimitTimeout):
				return nil, RateLimitTimeoutError
			}
		} else {
			t := <-c.rateLimitChan
			defer func() {
				c.rateLimitChan <- t
			}()
		}
	}

	isTraceEnabled := os.Getenv("HTTPCLIENT_TRACE") != ""

	if isTraceEnabled {
		requestBytes, _ := httputil.DumpRequestOut(r, true)
		fmt.Println(string(requestBytes))
	}

	if req.IgnoreRedirects {
		transport := c.Client.Transport

		if transport == nil {
			transport = http.DefaultTransport
		}

		response, err = transport.RoundTrip(r)
	} else {
		response, err = c.Client.Do(r)
	}

	if isTraceEnabled {
		responseBytes, _ := httputil.DumpResponse(response, true)
		fmt.Println(string(responseBytes))
	}

	if err != nil {
		return response, err
	}

	if err = c.runPostHook(r, response); err != nil {
		return response, err
	}

	if err = c.checkStatus(req, response); err != nil {
		defer response.Body.Close()
		return response, err
	}

	if err = c.unmarshalResponse(req, response); err != nil {
		return response, err
	}

	return response, nil
}
<|endoftext|>


<commit_before>package hub

import (
	"os"

	"github.com/streadway/amqp"
)

type Stream struct {
	AmqpUri   string `json:"amqp_uri"`
	QueueName string `json:"queue_name"`
}

func (s *Stream) Consume() error {
	conn, err := amqp.Dial(s.AmqpUri)
	defer conn.Close()

	if err != nil {
		return err
	}

	channel, err := conn.Channel()
	defer channel.Close()

	if err != nil {
		return err
	}

	q, err := channel.QueueDeclare(
		s.QueueName, // name
		false,       // durable
		true,        // delete when unused
		false,       // exclusive
		false,       // no-wait
		nil,         // arguments
	)

	if err != nil {
		return err
	}

	msgs, err := channel.Consume(
		q.Name, // queue
		"",     // consumer
		true,   // auto-ack
		false,  // exclusive
		false,  // no-local
		false,  // no-wait
		nil,    // args
	)

	if err != nil {
		return err
	}

	forever := make(chan bool)

	go func() {
		for d := range msgs {
			if string(d.Body) == "kthxbai" {
				forever <- true
				return
			}
			os.Stdout.Write(d.Body)
		}
	}()

	<-forever
	conn.Close()

	return nil
}
<commit_msg>bugfix(stream): Add new line at the end of stream<commit_after>package hub

import (
	"os"

	"github.com/streadway/amqp"
)

type Stream struct {
	AmqpUri   string `json:"amqp_uri"`
	QueueName string `json:"queue_name"`
}

func (s *Stream) Consume() error {
	conn, err := amqp.Dial(s.AmqpUri)
	defer conn.Close()

	if err != nil {
		return err
	}

	channel, err := conn.Channel()
	defer channel.Close()

	if err != nil {
		return err
	}

	q, err := channel.QueueDeclare(
		s.QueueName, // name
		false,       // durable
		true,        // delete when unused
		false,       // exclusive
		false,       // no-wait
		nil,         // arguments
	)

	if err != nil {
		return err
	}

	msgs, err := channel.Consume(
		q.Name, // queue
		"",     // consumer
		true,   // auto-ack
		false,  // exclusive
		false,  // no-local
		false,  // no-wait
		nil,    // args
	)

	if err != nil {
		return err
	}

	forever := make(chan bool)

	go func() {
		for d := range msgs {
			if string(d.Body) == "kthxbai" {
				os.Stdout.Write([]byte("\n"))
				forever <- true
				return
			}
			os.Stdout.Write(d.Body)
		}
	}()

	<-forever
	conn.Close()

	return nil
}
<|endoftext|>


<commit_before>package goose

import (
   "os"
   "fmt"
   "log"
   "strings"
   "runtime"
   "log/syslog"
)

// Alert is the basic type that implements the goose log object
type Alert uint8

// SyslogGoose is a wrapper type around *syslog.Writer to ensure a syslogger that satisfies the io.Writer inrterface
type SyslogGoose struct {
   W *syslog.Writer
}

var notrace bool = true

// Write is the method that satisfies the io.Writer inrterface
func (ng SyslogGoose) Write(b []byte) (int, error) {
   return ng.W.Write(b)
}

func trace() string {
   var pc      []uintptr
   var f        *runtime.Func
   var path    []string
   var file      string
   var line      int
   var pkgfunc []string
   var pkg     []string

   if notrace {
      return ""
   }
   pc = make([]uintptr, 10)  // at least 1 entry needed
   runtime.Callers(2, pc)
   f = runtime.FuncForPC(pc[1])
   file, line = f.FileLine(pc[1])
   path = strings.Split(file,string([]byte{os.PathSeparator}))
   file = path[len(path)-1]
   pkgfunc = strings.Split(f.Name(),string([]byte{os.PathSeparator}))
   pkgfunc = strings.Split(pkgfunc[len(pkgfunc)-1],".")
   pkg     = strings.Split(pkgfunc[0],"/")
   return fmt.Sprintf("{%s}[%s]<%s>(%d): ", pkg[len(pkg)-1], file, strings.Join(pkgfunc[1:],"."), line)
}

// UseSyslogNet redirects the log output from os.Stderr to the system logger
// connecting to it via network.
func UseSyslogNet(proto string, srv string, priority syslog.Priority) error {
   var logOutput     SyslogGoose
   var binParts    []string
   var binName       string
   var err           error

   binParts = strings.Split(os.Args[0],string([]byte{os.PathSeparator}))
   binName  = binParts[len(binParts)-1]

   logOutput.W, err = syslog.Dial(proto, srv, priority, binName)
   if err != nil {
      return err
   }
   log.SetOutput(logOutput)
   log.SetFlags(0)
   return nil
}

// TraceOn enables the inclusion of the package name, source file name, method/function caller and source line number in the log messages.
// As stated in https://golang.org/pkg/runtime/#Func.FileLine about the line numbering, "The result will not be accurate if pc is not a program
// counter within f".
func TraceOn() {
   notrace = false
}

// TraceOff disables the inclusion of the package name, source file name, method/function caller and source line number in the log messages.
// This is the default state of logging.
func TraceOff() {
   notrace = true
}

// Logf emits the messages based on the log.Printf
func (d Alert) Logf(level int, format string, parms ...interface{}) {
   if uint8(d) >= uint8(level) {
      log.Printf(trace() + format , parms...)
   }
}

// Fatalf behaves as Logf but stops program execution. The execution ends EVEN WHEN the log level of the message is higher the the current log level.
func (d Alert) Fatalf(level int, format string, parms ...interface{}) {
   if uint8(d) >= uint8(level) {
      log.Fatalf(trace() + format, parms...)
   }
   os.Exit(-1)
}

// Logf emits the messages based on fmt.Printf
func (d Alert) Printf(level int, format string, parms ...interface{}) {
   if uint8(d) >= uint8(level) {
      fmt.Printf(trace() + format, parms...)
   }
}

// Sprintf returns the messages as a string value
func (d Alert) Sprintf(level int, format string, parms ...interface{}) string {
   if uint8(d) >= uint8(level) {
      return fmt.Sprintf(trace() + format, parms...)
   }
   return ""
}

// Set accepts either integer or string values to initialize the goose Alert level
func (d *Alert) Set(level interface{}) {
   var n uint8

   switch level.(type) {
      case int8:
         (*d) = Alert(level.(int8))
      case int:
         (*d) = Alert(level.(int))
      case int16:
         (*d) = Alert(level.(int16))
      case int32:
         (*d) = Alert(level.(int32))
      case int64:
         (*d) = Alert(level.(int64))
      case uint8:
         (*d) = Alert(level.(uint8))
      case uint:
         (*d) = Alert(level.(uint))
      case uint16:
         (*d) = Alert(level.(uint16))
      case uint32:
         (*d) = Alert(level.(uint32))
      case uint64:
         (*d) = Alert(level.(uint64))
      case string:
         fmt.Sscanf(level.(string),"%d",&n)
         (*d) = Alert(n)
      case []byte:
         fmt.Sscanf(string(level.([]byte)),"%d",&n)
         (*d) = Alert(n)
   }
}
<commit_msg>{newfeature}Dropped usage of FuncForPC in favor of CallersFrames, giving a precise information<commit_after>package goose

import (
   "os"
   "fmt"
   "log"
   "strings"
   "runtime"
   "log/syslog"
)

// Alert is the basic type that implements the goose log object
type Alert uint8

// SyslogGoose is a wrapper type around *syslog.Writer to ensure a syslogger that satisfies the io.Writer inrterface
type SyslogGoose struct {
   W *syslog.Writer
}

var notrace bool = true

// Write is the method that satisfies the io.Writer inrterface
func (ng SyslogGoose) Write(b []byte) (int, error) {
   return ng.W.Write(b)
}

func trace() string {
   var pc      []uintptr
   var path    []string
   var file      string
   var pkgfunc []string
   var pkg     []string
   var n         int
   var frames   *runtime.Frames
   var frame     runtime.Frame

   if notrace {
      return ""
   }
   pc = make([]uintptr, 10)  // at least 1 entry needed
   n = runtime.Callers(2, pc)
   if n == 0 {
      return ""
   }

   pc = pc[:n]
   frames = runtime.CallersFrames(pc)
   frame, _ = frames.Next()
   frame, _ = frames.Next()

   path = strings.Split(frame.File,string([]byte{os.PathSeparator}))
   file = path[len(path)-1]

   pkgfunc = strings.Split(frame.Function,string([]byte{os.PathSeparator}))
   pkgfunc = strings.Split(pkgfunc[len(pkgfunc)-1],".")
   pkg     = strings.Split(pkgfunc[0],"/")
   return fmt.Sprintf("{%s}[%s]<%s>(%d): ", pkg[len(pkg)-1], file, strings.Join(pkgfunc[1:],"."), frame.Line)
}

// UseSyslogNet redirects the log output from os.Stderr to the system logger
// connecting to it via network.
func UseSyslogNet(proto string, srv string, priority syslog.Priority) error {
   var logOutput     SyslogGoose
   var binParts    []string
   var binName       string
   var err           error

   binParts = strings.Split(os.Args[0],string([]byte{os.PathSeparator}))
   binName  = binParts[len(binParts)-1]

   logOutput.W, err = syslog.Dial(proto, srv, priority, binName)
   if err != nil {
      return err
   }
   log.SetOutput(logOutput)
   log.SetFlags(0)
   return nil
}

// TraceOn enables the inclusion of the package name, source file name, method/function caller and source line number in the log messages.
// As stated in https://golang.org/pkg/runtime/#Func.FileLine about the line numbering, "The result will not be accurate if pc is not a program
// counter within f".
func TraceOn() {
   notrace = false
}

// TraceOff disables the inclusion of the package name, source file name, method/function caller and source line number in the log messages.
// This is the default state of logging.
func TraceOff() {
   notrace = true
}

// Logf emits the messages based on the log.Printf
func (d Alert) Logf(level int, format string, parms ...interface{}) {
   if uint8(d) >= uint8(level) {
      log.Printf(trace() + format , parms...)
   }
}

// Fatalf behaves as Logf but stops program execution. The execution ends EVEN WHEN the log level of the message is higher the the current log level.
func (d Alert) Fatalf(level int, format string, parms ...interface{}) {
   if uint8(d) >= uint8(level) {
      log.Fatalf(trace() + format, parms...)
   }
   os.Exit(-1)
}

// Logf emits the messages based on fmt.Printf
func (d Alert) Printf(level int, format string, parms ...interface{}) {
   if uint8(d) >= uint8(level) {
      fmt.Printf(trace() + format, parms...)
   }
}

// Sprintf returns the messages as a string value
func (d Alert) Sprintf(level int, format string, parms ...interface{}) string {
   if uint8(d) >= uint8(level) {
      return fmt.Sprintf(trace() + format, parms...)
   }
   return ""
}

// Set accepts either integer or string values to initialize the goose Alert level
func (d *Alert) Set(level interface{}) {
   var n uint8

   switch level.(type) {
      case int8:
         (*d) = Alert(level.(int8))
      case int:
         (*d) = Alert(level.(int))
      case int16:
         (*d) = Alert(level.(int16))
      case int32:
         (*d) = Alert(level.(int32))
      case int64:
         (*d) = Alert(level.(int64))
      case uint8:
         (*d) = Alert(level.(uint8))
      case uint:
         (*d) = Alert(level.(uint))
      case uint16:
         (*d) = Alert(level.(uint16))
      case uint32:
         (*d) = Alert(level.(uint32))
      case uint64:
         (*d) = Alert(level.(uint64))
      case string:
         fmt.Sscanf(level.(string),"%d",&n)
         (*d) = Alert(n)
      case []byte:
         fmt.Sscanf(string(level.([]byte)),"%d",&n)
         (*d) = Alert(n)
   }
}
<|endoftext|>


<commit_before>package goson

import (
    "encoding/json"
    "strings"
    "errors"
    "strconv"
)

/**
 * Created by tuxer on 9/6/17.
 */

type JsonObject struct {
    dataMap map[string]interface{}
}

func (j *JsonObject) ToString() *string {
    data, e := json.Marshal(j.dataMap)
    if e != nil {
        return nil
    }
    str := string(data)
    return &str
}

func (j *JsonObject) GetJsonArray(path string) []JsonObject    {
    obj := j.get(path)

    values, ok := obj.([]interface{})

    if !ok  {
        return nil
    }
    var arrJson []JsonObject
    for _, value := range values   {
        mapValue, ok := value.(map[string]interface{})
        if ok   {
            jo := JsonObject{dataMap: mapValue}
            arrJson = append(arrJson, jo)
        }
    }
    return arrJson
}
func (j *JsonObject) GetJsonObject(path string) *JsonObject    {
    obj := j.get(path)

    v, ok := obj.(map[string]interface{})
    if ok   {
        jo := JsonObject{ dataMap: v }
        return &jo
    }
    return nil
}

func (j *JsonObject) GetInt(path string) (int, error) {
    obj := j.get(path)

    switch obj.(type) {
    case float64:
        float, _ := obj.(float64)
        return int(float), nil
    case string:
        str, _ := obj.(string)
        i, e := strconv.Atoi(str)
        if e != nil {
            return 0, e
        }
        return i, nil
    default:
        return 0, errors.New(`unable to get ` + path + `, is not int`)
    }
}
func (j *JsonObject) GetString(path string) *string {
    obj := j.get(path)

    switch obj.(type) {
    case string:
        str, _ := obj.(string)
        return &str
    case float64:
        float, _ := obj.(float64)
        str := strconv.FormatFloat(float, 'f', -1, 64)
        return &str
    default:
        return nil
    }
}

func (j *JsonObject) Put(path string, value interface{}) error   {
    splittedPath := strings.Split(path, `.`)

    if j.dataMap == nil  {
        j.dataMap = make(map[string]interface{})
    }

    rootMap := j.dataMap
    currentMap := rootMap

    for index, pathItem := range splittedPath   {
        if index < len(splittedPath) - 1    {
            _, ok := currentMap[pathItem]
            if !ok   {
                currentMap[pathItem] = make(map[string]interface{})
            }
            currentMap, ok = currentMap[pathItem].(map[string]interface{})
            if !ok  {
                return errors.New(pathItem + `is not a json object`)
            }
        } else {
            currentMap[pathItem] = value
        }
    }
    j.dataMap = rootMap
    return nil
}

func (j *JsonObject) get(path string) interface{} {
    splittedPath := strings.Split(path, `.`)

    var jsonMap interface{}
    jsonMap = j.dataMap
    var val interface{}
    for _, pathItem := range splittedPath   {
        if jsonMap == nil   {
            return nil
        }
        val = jsonMap.(map[string]interface{})[pathItem]

        switch val.(type) {
        case map[string]interface{}:
            jsonMap = val
        default:
            jsonMap = nil
        }
    }
    return val
}

func Parse(data []byte) *JsonObject    {
    jo := JsonObject{}
    json.Unmarshal(data, &jo.dataMap)
    return &jo
}<commit_msg>improve put method, supporting array<commit_after>package goson

import (
    "encoding/json"
    "strings"
    "errors"
    "strconv"
)

/**
 * Created by tuxer on 9/6/17.
 */

type JsonObject struct {
    dataMap map[string]interface{}
}

func (j *JsonObject) ToString() *string {
    data, e := json.Marshal(j.dataMap)
    if e != nil {
        return nil
    }
    str := string(data)
    return &str
}

func (j *JsonObject) GetJsonArray(path string) []JsonObject    {
    obj := j.get(path)

    values, ok := obj.([]interface{})

    if !ok  {
        return nil
    }
    var arrJson []JsonObject
    for _, value := range values   {
        mapValue, ok := value.(map[string]interface{})
        if ok   {
            jo := JsonObject{dataMap: mapValue}
            arrJson = append(arrJson, jo)
        }
    }
    return arrJson
}
func (j *JsonObject) GetJsonObject(path string) *JsonObject    {
    obj := j.get(path)

    v, ok := obj.(map[string]interface{})
    if ok   {
        jo := JsonObject{ dataMap: v }
        return &jo
    }
    return nil
}

func (j *JsonObject) GetInt(path string) (int, error) {
    obj := j.get(path)

    switch obj.(type) {
    case float64:
        float, _ := obj.(float64)
        return int(float), nil
    case string:
        str, _ := obj.(string)
        i, e := strconv.Atoi(str)
        if e != nil {
            return 0, e
        }
        return i, nil
    default:
        return 0, errors.New(`unable to get ` + path + `, is not int`)
    }
}
func (j *JsonObject) GetString(path string) *string {
    obj := j.get(path)

    switch obj.(type) {
    case string:
        str, _ := obj.(string)
        return &str
    case float64:
        float, _ := obj.(float64)
        str := strconv.FormatFloat(float, 'f', -1, 64)
        return &str
    default:
        return nil
    }
}

func (j *JsonObject) Put(path string, value interface{}) error   {
    splittedPath := strings.Split(path, `.`)

    _, ok := value.(JsonObject)
    if ok   {
        value = value.(JsonObject).dataMap
    }

    if j.dataMap == nil  {
        j.dataMap = make(map[string]interface{})
    }

    rootMap := j.dataMap
    currentMap := rootMap

    for index, pathItem := range splittedPath   {
        if index < len(splittedPath) - 1    {
            _, ok := currentMap[pathItem]
            if !ok   {
                currentMap[pathItem] = make(map[string]interface{})
            }
            currentMap, ok = currentMap[pathItem].(map[string]interface{})
            if !ok  {
                return errors.New(pathItem + `is not a json object`)
            }
        } else {
            curr, ok := currentMap[pathItem]
            if ok  {
                value = []interface{}{curr, value}
            }
            currentMap[pathItem] = value
        }
    }
    j.dataMap = rootMap
    return nil
}

func (j *JsonObject) get(path string) interface{} {
    splittedPath := strings.Split(path, `.`)

    var jsonMap interface{}
    jsonMap = j.dataMap
    var val interface{}
    for _, pathItem := range splittedPath   {
        if jsonMap == nil   {
            return nil
        }
        val = jsonMap.(map[string]interface{})[pathItem]

        switch val.(type) {
        case map[string]interface{}:
            jsonMap = val
        default:
            jsonMap = nil
        }
    }
    return val
}

func Parse(data []byte) *JsonObject    {
    jo := JsonObject{}
    json.Unmarshal(data, &jo.dataMap)
    return &jo
}<|endoftext|>


<commit_before>package presenter

import (
	"io"

	"github.com/anchore/imgbom/imgbom/pkg"
	"github.com/anchore/imgbom/imgbom/presenter/json"
	"github.com/anchore/stereoscope/pkg/image"
)

type Presenter interface {
	Present(io.Writer, *image.Image, *pkg.Catalog) error
}

func GetPresenter(option Option) Presenter {
	switch option {
	case JSONPresenter:
		return json.NewPresenter()
	default:
		return nil
	}
}
<commit_msg>presenter: allow a text presenter option<commit_after>package presenter

import (
	"io"

	"github.com/anchore/imgbom/imgbom/pkg"
	"github.com/anchore/imgbom/imgbom/presenter/json"
	"github.com/anchore/imgbom/imgbom/presenter/text"
	"github.com/anchore/stereoscope/pkg/image"
)

type Presenter interface {
	Present(io.Writer, *image.Image, *pkg.Catalog) error
}

func GetPresenter(option Option) Presenter {
	switch option {
	case JSONPresenter:
		return json.NewPresenter()
	case TextPresenter:
		return text.NewPresenter()
	default:
		return nil
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build java android

package discovery

import (
	jutil "v.io/x/jni/util"

	"v.io/v23/discovery"
	idiscovery "v.io/x/ref/lib/discovery"
)
// #include "jni.h"
import "C"

// JavaDiscovery converts a Go discovery instance into a Java discovery instance.
func JavaDiscovery(env jutil.Env, d discovery.T) (jutil.Object, error) {
	trigger := idiscovery.NewTrigger()
	// This reference will get unrefed when the jDiscovery object below is finalized.
	jutil.GoRef(trigger)

	jDiscovery, err := jutil.NewObject(env, jVDiscoveryImplClass, []jutil.Sign{jutil.LongSign, jutil.LongSign}, int64(jutil.PtrValue(&d)), int64(jutil.PtrValue(trigger)))
	if err != nil {
		return jutil.NullObject, err
	}
	return jDiscovery, nil
}
<commit_msg>TBR: java: Capture a reference to the go discovery instance in JavaDiscovery<commit_after>// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build java android

package discovery

import (
	jutil "v.io/x/jni/util"

	"v.io/v23/discovery"
	idiscovery "v.io/x/ref/lib/discovery"
)
// #include "jni.h"
import "C"

// JavaDiscovery converts a Go discovery instance into a Java discovery instance.
func JavaDiscovery(env jutil.Env, d discovery.T) (jutil.Object, error) {
	trigger := idiscovery.NewTrigger()
	// These reference will get unrefed when the jDiscovery object below is finalized.
	jutil.GoRef(trigger)
	jutil.GoRef(&d)

	jDiscovery, err := jutil.NewObject(env, jVDiscoveryImplClass, []jutil.Sign{jutil.LongSign, jutil.LongSign}, int64(jutil.PtrValue(&d)), int64(jutil.PtrValue(trigger)))
	if err != nil {
		return jutil.NullObject, err
	}
	return jDiscovery, nil
}
<|endoftext|>


<commit_before>// Copyright 2016 The go-github AUTHORS. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package github

import (
	"context"
	"fmt"
)

// ReactionsService provides access to the reactions-related functions in the
// GitHub API.
//
// GitHub API docs: https://developer.github.com/v3/reactions/
type ReactionsService service

// Reaction represents a GitHub reaction.
type Reaction struct {
	// ID is the Reaction ID.
	ID     *int64  `json:"id,omitempty"`
	User   *User   `json:"user,omitempty"`
	NodeID *string `json:"node_id,omitempty"`
	// Content is the type of reaction.
	// Possible values are:
	//     "+1", "-1", "laugh", "confused", "heart", "hooray".
	Content *string `json:"content,omitempty"`
}

// Reactions represents a summary of GitHub reactions.
type Reactions struct {
	TotalCount *int    `json:"total_count,omitempty"`
	PlusOne    *int    `json:"+1,omitempty"`
	MinusOne   *int    `json:"-1,omitempty"`
	Laugh      *int    `json:"laugh,omitempty"`
	Confused   *int    `json:"confused,omitempty"`
	Heart      *int    `json:"heart,omitempty"`
	Hooray     *int    `json:"hooray,omitempty"`
	URL        *string `json:"url,omitempty"`
}

func (r Reaction) String() string {
	return Stringify(r)
}

// ListCommentReactions lists the reactions for a commit comment.
//
// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-a-commit-comment
func (s *ReactionsService) ListCommentReactions(ctx context.Context, owner, repo string, id int64, opt *ListOptions) ([]*Reaction, *Response, error) {
	u := fmt.Sprintf("repos/%v/%v/comments/%v/reactions", owner, repo, id)
	u, err := addOptions(u, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept headers when APIs fully launch.
	req.Header.Set("Accept", mediaTypeReactionsPreview)

	var m []*Reaction
	resp, err := s.client.Do(ctx, req, &m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// CreateCommentReaction creates a reaction for a commit comment.
// Note that if you have already created a reaction of type content, the
// previously created reaction will be returned with Status: 200 OK.
// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray".
//
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-a-commit-comment
func (s ReactionsService) CreateCommentReaction(ctx context.Context, owner, repo string, id int64, content string) (*Reaction, *Response, error) {
	u := fmt.Sprintf("repos/%v/%v/comments/%v/reactions", owner, repo, id)

	body := &Reaction{Content: String(content)}
	req, err := s.client.NewRequest("POST", u, body)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept headers when APIs fully launch.
	req.Header.Set("Accept", mediaTypeReactionsPreview)

	m := &Reaction{}
	resp, err := s.client.Do(ctx, req, m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// ListIssueReactions lists the reactions for an issue.
//
// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-an-issue
func (s *ReactionsService) ListIssueReactions(ctx context.Context, owner, repo string, number int, opt *ListOptions) ([]*Reaction, *Response, error) {
	u := fmt.Sprintf("repos/%v/%v/issues/%v/reactions", owner, repo, number)
	u, err := addOptions(u, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept headers when APIs fully launch.
	req.Header.Set("Accept", mediaTypeReactionsPreview)

	var m []*Reaction
	resp, err := s.client.Do(ctx, req, &m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// CreateIssueReaction creates a reaction for an issue.
// Note that if you have already created a reaction of type content, the
// previously created reaction will be returned with Status: 200 OK.
// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray".
//
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue
func (s ReactionsService) CreateIssueReaction(ctx context.Context, owner, repo string, number int, content string) (*Reaction, *Response, error) {
	u := fmt.Sprintf("repos/%v/%v/issues/%v/reactions", owner, repo, number)

	body := &Reaction{Content: String(content)}
	req, err := s.client.NewRequest("POST", u, body)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept headers when APIs fully launch.
	req.Header.Set("Accept", mediaTypeReactionsPreview)

	m := &Reaction{}
	resp, err := s.client.Do(ctx, req, m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// ListIssueCommentReactions lists the reactions for an issue comment.
//
// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-an-issue-comment
func (s *ReactionsService) ListIssueCommentReactions(ctx context.Context, owner, repo string, id int64, opt *ListOptions) ([]*Reaction, *Response, error) {
	u := fmt.Sprintf("repos/%v/%v/issues/comments/%v/reactions", owner, repo, id)
	u, err := addOptions(u, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept headers when APIs fully launch.
	req.Header.Set("Accept", mediaTypeReactionsPreview)

	var m []*Reaction
	resp, err := s.client.Do(ctx, req, &m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// CreateIssueCommentReaction creates a reaction for an issue comment.
// Note that if you have already created a reaction of type content, the
// previously created reaction will be returned with Status: 200 OK.
// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray".
//
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue-comment
func (s ReactionsService) CreateIssueCommentReaction(ctx context.Context, owner, repo string, id int64, content string) (*Reaction, *Response, error) {
	u := fmt.Sprintf("repos/%v/%v/issues/comments/%v/reactions", owner, repo, id)

	body := &Reaction{Content: String(content)}
	req, err := s.client.NewRequest("POST", u, body)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept headers when APIs fully launch.
	req.Header.Set("Accept", mediaTypeReactionsPreview)

	m := &Reaction{}
	resp, err := s.client.Do(ctx, req, m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// ListPullRequestCommentReactions lists the reactions for a pull request review comment.
//
// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-an-issue-comment
func (s *ReactionsService) ListPullRequestCommentReactions(ctx context.Context, owner, repo string, id int64, opt *ListOptions) ([]*Reaction, *Response, error) {
	u := fmt.Sprintf("repos/%v/%v/pulls/comments/%v/reactions", owner, repo, id)
	u, err := addOptions(u, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept headers when APIs fully launch.
	req.Header.Set("Accept", mediaTypeReactionsPreview)

	var m []*Reaction
	resp, err := s.client.Do(ctx, req, &m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// CreatePullRequestCommentReaction creates a reaction for a pull request review comment.
// Note that if you have already created a reaction of type content, the
// previously created reaction will be returned with Status: 200 OK.
// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray".
//
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue-comment
func (s ReactionsService) CreatePullRequestCommentReaction(ctx context.Context, owner, repo string, id int64, content string) (*Reaction, *Response, error) {
	u := fmt.Sprintf("repos/%v/%v/pulls/comments/%v/reactions", owner, repo, id)

	body := &Reaction{Content: String(content)}
	req, err := s.client.NewRequest("POST", u, body)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept headers when APIs fully launch.
	req.Header.Set("Accept", mediaTypeReactionsPreview)

	m := &Reaction{}
	resp, err := s.client.Do(ctx, req, m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// ListTeamDiscussionReactions lists the reactions for a team discussion.
//
// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-a-team-discussion
func (s *ReactionsService) ListTeamDiscussionReactions(ctx context.Context, teamID int64, discussionNumber int, opt *ListOptions) ([]*Reaction, *Response, error) {
	u := fmt.Sprintf("teams/%v/discussions/%v/reactions", teamID, discussionNumber)
	u, err := addOptions(u, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	req.Header.Set("Accept", mediaTypeReactionsPreview)

	var m []*Reaction
	resp, err := s.client.Do(ctx, req, &m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// CreateTeamDiscussionReaction creates a reaction for a team discussion.
// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray".
//
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-a-team-discussion
func (s *ReactionsService) CreateTeamDiscussionReaction(ctx context.Context, teamID int64, discussionNumber int, content string) (*Reaction, *Response, error) {
	u := fmt.Sprintf("teams/%v/discussions/%v/reactions", teamID, discussionNumber)

	body := &Reaction{Content: String(content)}
	req, err := s.client.NewRequest("POST", u, body)
	if err != nil {
		return nil, nil, err
	}

	req.Header.Set("Accept", mediaTypeReactionsPreview)

	m := &Reaction{}
	resp, err := s.client.Do(ctx, req, m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// ListTeamDiscussionCommentReactions lists the reactions for a team discussion comment.
//
// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-a-team-discussion-comment
func (s *ReactionsService) ListTeamDiscussionCommentReactions(ctx context.Context, teamID int64, discussionNumber, commentNumber int, opt *ListOptions) ([]*Reaction, *Response, error) {
	u := fmt.Sprintf("teams/%v/discussions/%v/comments/%v/reactions", teamID, discussionNumber, commentNumber)
	u, err := addOptions(u, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	req.Header.Set("Accept", mediaTypeReactionsPreview)

	var m []*Reaction
	resp, err := s.client.Do(ctx, req, &m)

	return m, resp, nil
}

// CreateTeamDiscussionCommentReaction creates a reaction for a team discussion comment.
// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray".
//
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-a-team-discussion-comment
func (s *ReactionsService) CreateTeamDiscussionCommentReaction(ctx context.Context, teamID int64, discussionNumber, commentNumber int, content string) (*Reaction, *Response, error) {
	u := fmt.Sprintf("teams/%v/discussions/%v/comments/%v/reactions", teamID, discussionNumber, commentNumber)

	body := &Reaction{Content: String(content)}
	req, err := s.client.NewRequest("POST", u, body)
	if err != nil {
		return nil, nil, err
	}

	req.Header.Set("Accept", mediaTypeReactionsPreview)

	m := &Reaction{}
	resp, err := s.client.Do(ctx, req, m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// DeleteReaction deletes a reaction.
//
// GitHub API docs: https://developer.github.com/v3/reaction/reactions/#delete-a-reaction-archive
func (s *ReactionsService) DeleteReaction(ctx context.Context, id int64) (*Response, error) {
	u := fmt.Sprintf("reactions/%v", id)

	req, err := s.client.NewRequest("DELETE", u, nil)
	if err != nil {
		return nil, err
	}

	// TODO: remove custom Accept header when this API fully launches.
	req.Header.Set("Accept", mediaTypeReactionsPreview)

	return s.client.Do(ctx, req, nil)
}
<commit_msg>Fix ineffassign issues (#1094)<commit_after>// Copyright 2016 The go-github AUTHORS. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package github

import (
	"context"
	"fmt"
)

// ReactionsService provides access to the reactions-related functions in the
// GitHub API.
//
// GitHub API docs: https://developer.github.com/v3/reactions/
type ReactionsService service

// Reaction represents a GitHub reaction.
type Reaction struct {
	// ID is the Reaction ID.
	ID     *int64  `json:"id,omitempty"`
	User   *User   `json:"user,omitempty"`
	NodeID *string `json:"node_id,omitempty"`
	// Content is the type of reaction.
	// Possible values are:
	//     "+1", "-1", "laugh", "confused", "heart", "hooray".
	Content *string `json:"content,omitempty"`
}

// Reactions represents a summary of GitHub reactions.
type Reactions struct {
	TotalCount *int    `json:"total_count,omitempty"`
	PlusOne    *int    `json:"+1,omitempty"`
	MinusOne   *int    `json:"-1,omitempty"`
	Laugh      *int    `json:"laugh,omitempty"`
	Confused   *int    `json:"confused,omitempty"`
	Heart      *int    `json:"heart,omitempty"`
	Hooray     *int    `json:"hooray,omitempty"`
	URL        *string `json:"url,omitempty"`
}

func (r Reaction) String() string {
	return Stringify(r)
}

// ListCommentReactions lists the reactions for a commit comment.
//
// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-a-commit-comment
func (s *ReactionsService) ListCommentReactions(ctx context.Context, owner, repo string, id int64, opt *ListOptions) ([]*Reaction, *Response, error) {
	u := fmt.Sprintf("repos/%v/%v/comments/%v/reactions", owner, repo, id)
	u, err := addOptions(u, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept headers when APIs fully launch.
	req.Header.Set("Accept", mediaTypeReactionsPreview)

	var m []*Reaction
	resp, err := s.client.Do(ctx, req, &m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// CreateCommentReaction creates a reaction for a commit comment.
// Note that if you have already created a reaction of type content, the
// previously created reaction will be returned with Status: 200 OK.
// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray".
//
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-a-commit-comment
func (s ReactionsService) CreateCommentReaction(ctx context.Context, owner, repo string, id int64, content string) (*Reaction, *Response, error) {
	u := fmt.Sprintf("repos/%v/%v/comments/%v/reactions", owner, repo, id)

	body := &Reaction{Content: String(content)}
	req, err := s.client.NewRequest("POST", u, body)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept headers when APIs fully launch.
	req.Header.Set("Accept", mediaTypeReactionsPreview)

	m := &Reaction{}
	resp, err := s.client.Do(ctx, req, m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// ListIssueReactions lists the reactions for an issue.
//
// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-an-issue
func (s *ReactionsService) ListIssueReactions(ctx context.Context, owner, repo string, number int, opt *ListOptions) ([]*Reaction, *Response, error) {
	u := fmt.Sprintf("repos/%v/%v/issues/%v/reactions", owner, repo, number)
	u, err := addOptions(u, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept headers when APIs fully launch.
	req.Header.Set("Accept", mediaTypeReactionsPreview)

	var m []*Reaction
	resp, err := s.client.Do(ctx, req, &m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// CreateIssueReaction creates a reaction for an issue.
// Note that if you have already created a reaction of type content, the
// previously created reaction will be returned with Status: 200 OK.
// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray".
//
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue
func (s ReactionsService) CreateIssueReaction(ctx context.Context, owner, repo string, number int, content string) (*Reaction, *Response, error) {
	u := fmt.Sprintf("repos/%v/%v/issues/%v/reactions", owner, repo, number)

	body := &Reaction{Content: String(content)}
	req, err := s.client.NewRequest("POST", u, body)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept headers when APIs fully launch.
	req.Header.Set("Accept", mediaTypeReactionsPreview)

	m := &Reaction{}
	resp, err := s.client.Do(ctx, req, m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// ListIssueCommentReactions lists the reactions for an issue comment.
//
// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-an-issue-comment
func (s *ReactionsService) ListIssueCommentReactions(ctx context.Context, owner, repo string, id int64, opt *ListOptions) ([]*Reaction, *Response, error) {
	u := fmt.Sprintf("repos/%v/%v/issues/comments/%v/reactions", owner, repo, id)
	u, err := addOptions(u, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept headers when APIs fully launch.
	req.Header.Set("Accept", mediaTypeReactionsPreview)

	var m []*Reaction
	resp, err := s.client.Do(ctx, req, &m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// CreateIssueCommentReaction creates a reaction for an issue comment.
// Note that if you have already created a reaction of type content, the
// previously created reaction will be returned with Status: 200 OK.
// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray".
//
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue-comment
func (s ReactionsService) CreateIssueCommentReaction(ctx context.Context, owner, repo string, id int64, content string) (*Reaction, *Response, error) {
	u := fmt.Sprintf("repos/%v/%v/issues/comments/%v/reactions", owner, repo, id)

	body := &Reaction{Content: String(content)}
	req, err := s.client.NewRequest("POST", u, body)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept headers when APIs fully launch.
	req.Header.Set("Accept", mediaTypeReactionsPreview)

	m := &Reaction{}
	resp, err := s.client.Do(ctx, req, m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// ListPullRequestCommentReactions lists the reactions for a pull request review comment.
//
// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-an-issue-comment
func (s *ReactionsService) ListPullRequestCommentReactions(ctx context.Context, owner, repo string, id int64, opt *ListOptions) ([]*Reaction, *Response, error) {
	u := fmt.Sprintf("repos/%v/%v/pulls/comments/%v/reactions", owner, repo, id)
	u, err := addOptions(u, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept headers when APIs fully launch.
	req.Header.Set("Accept", mediaTypeReactionsPreview)

	var m []*Reaction
	resp, err := s.client.Do(ctx, req, &m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// CreatePullRequestCommentReaction creates a reaction for a pull request review comment.
// Note that if you have already created a reaction of type content, the
// previously created reaction will be returned with Status: 200 OK.
// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray".
//
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue-comment
func (s ReactionsService) CreatePullRequestCommentReaction(ctx context.Context, owner, repo string, id int64, content string) (*Reaction, *Response, error) {
	u := fmt.Sprintf("repos/%v/%v/pulls/comments/%v/reactions", owner, repo, id)

	body := &Reaction{Content: String(content)}
	req, err := s.client.NewRequest("POST", u, body)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept headers when APIs fully launch.
	req.Header.Set("Accept", mediaTypeReactionsPreview)

	m := &Reaction{}
	resp, err := s.client.Do(ctx, req, m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// ListTeamDiscussionReactions lists the reactions for a team discussion.
//
// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-a-team-discussion
func (s *ReactionsService) ListTeamDiscussionReactions(ctx context.Context, teamID int64, discussionNumber int, opt *ListOptions) ([]*Reaction, *Response, error) {
	u := fmt.Sprintf("teams/%v/discussions/%v/reactions", teamID, discussionNumber)
	u, err := addOptions(u, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	req.Header.Set("Accept", mediaTypeReactionsPreview)

	var m []*Reaction
	resp, err := s.client.Do(ctx, req, &m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// CreateTeamDiscussionReaction creates a reaction for a team discussion.
// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray".
//
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-a-team-discussion
func (s *ReactionsService) CreateTeamDiscussionReaction(ctx context.Context, teamID int64, discussionNumber int, content string) (*Reaction, *Response, error) {
	u := fmt.Sprintf("teams/%v/discussions/%v/reactions", teamID, discussionNumber)

	body := &Reaction{Content: String(content)}
	req, err := s.client.NewRequest("POST", u, body)
	if err != nil {
		return nil, nil, err
	}

	req.Header.Set("Accept", mediaTypeReactionsPreview)

	m := &Reaction{}
	resp, err := s.client.Do(ctx, req, m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// ListTeamDiscussionCommentReactions lists the reactions for a team discussion comment.
//
// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-a-team-discussion-comment
func (s *ReactionsService) ListTeamDiscussionCommentReactions(ctx context.Context, teamID int64, discussionNumber, commentNumber int, opt *ListOptions) ([]*Reaction, *Response, error) {
	u := fmt.Sprintf("teams/%v/discussions/%v/comments/%v/reactions", teamID, discussionNumber, commentNumber)
	u, err := addOptions(u, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	req.Header.Set("Accept", mediaTypeReactionsPreview)

	var m []*Reaction
	resp, err := s.client.Do(ctx, req, &m)
	if err != nil {
		return nil, nil, err
	}
	return m, resp, nil
}

// CreateTeamDiscussionCommentReaction creates a reaction for a team discussion comment.
// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray".
//
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-a-team-discussion-comment
func (s *ReactionsService) CreateTeamDiscussionCommentReaction(ctx context.Context, teamID int64, discussionNumber, commentNumber int, content string) (*Reaction, *Response, error) {
	u := fmt.Sprintf("teams/%v/discussions/%v/comments/%v/reactions", teamID, discussionNumber, commentNumber)

	body := &Reaction{Content: String(content)}
	req, err := s.client.NewRequest("POST", u, body)
	if err != nil {
		return nil, nil, err
	}

	req.Header.Set("Accept", mediaTypeReactionsPreview)

	m := &Reaction{}
	resp, err := s.client.Do(ctx, req, m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// DeleteReaction deletes a reaction.
//
// GitHub API docs: https://developer.github.com/v3/reaction/reactions/#delete-a-reaction-archive
func (s *ReactionsService) DeleteReaction(ctx context.Context, id int64) (*Response, error) {
	u := fmt.Sprintf("reactions/%v", id)

	req, err := s.client.NewRequest("DELETE", u, nil)
	if err != nil {
		return nil, err
	}

	// TODO: remove custom Accept header when this API fully launches.
	req.Header.Set("Accept", mediaTypeReactionsPreview)

	return s.client.Do(ctx, req, nil)
}
<|endoftext|>