<commit_before>package id3v2

import (
	"errors"
	"io"
	"os"

	"github.com/bogem/id3v2/util"
)

const frameHeaderSize = 10

type frameHeader struct {
	ID        string
	FrameSize uint32
}

func parseTag(file *os.File) (*Tag, error) {
	if file == nil {
		err := errors.New("Invalid file: file is nil")
		return nil, err
	}
	header, err := parseHeader(file)
	if err != nil {
		err = errors.New("Trying to parse tag header: " + err.Error())
		return nil, err
	}
	if header == nil {
		return newTag(file, 0), nil
	}
	if header.Version < 3 {
		err = errors.New("Unsupported version of ID3 tag")
		return nil, err
	}

	t := newTag(file, tagHeaderSize+header.FramesSize)
	err = t.findAllFrames()

	return t, nil
}

func newTag(file *os.File, originalSize uint32) *Tag {
	return &Tag{
		ids: V24IDs,

		file:         file,
		originalSize: originalSize,
	}
}

func (t *Tag) findAllFrames() error {
	if t.framesCoords == nil {
		t.framesCoords = make(map[string][]frameCoordinates)
	}

	pos := uint32(tagHeaderSize) // initial position of read - end of tag header (beginning of first frame)
	tagSize := t.originalSize
	f := t.file

	for pos < tagSize {
		if _, err := f.Seek(int64(pos), os.SEEK_SET); err != nil {
			return err
		}

		header, err := parseFrameHeader(f)
		if err != nil {
			return err
		}
		pos += frameHeaderSize

		fc := frameCoordinates{
			Len: int64(header.FrameSize),
			Pos: int64(pos),
		}
		fcs := t.framesCoords[header.ID]
		fcs = append(fcs, fc)
		t.framesCoords[header.ID] = fcs

		pos += header.FrameSize
	}

	return nil
}

func parseFrameHeader(rd io.Reader) (*frameHeader, error) {
	byteHeader := make([]byte, frameHeaderSize)
	n, err := rd.Read(byteHeader)
	if err != nil {
		return nil, err
	}
	if n < frameHeaderSize {
		err = errors.New("Size of frame header is less than expected")
	}

	header := &frameHeader{
		ID:        string(byteHeader[:4]),
		FrameSize: util.ParseSize(byteHeader[4:8]),
	}

	return header, nil

}

func (t Tag) findParseFunc(id string) func(io.Reader) (Framer, error) {
	if id[0] == 'T' {
		return ParseTextFrame
	}
	switch id {
	case t.ids["Attached picture"]:
		return ParsePictureFrame
	case t.ids["Comments"]:
		return ParseCommentFrame
	case t.ids["Unsynchronised lyrics/text transcription"]:
		return ParseUnsynchronisedLyricsFrame
	}
	return nil
}

func readFrame(parseFunc func(io.Reader) (Framer, error), file *os.File, fc frameCoordinates) Framer {
	file.Seek(fc.Pos, os.SEEK_SET)
	rd := &io.LimitedReader{R: file, N: fc.Len}
	fr, err := parseFunc(rd)
	if err != nil {
		panic(err)
	}
	return fr
}

func (t *Tag) parseAllFramesCoords() {
	for id := range t.framesCoords {
		t.parseFramesCoordsWithID(id)
	}
}

func (t *Tag) parseFramesCoordsWithID(id string) {
	fcs, exists := t.framesCoords[id]
	if !exists {
		return
	}

	parseFunc := t.findParseFunc(id)
	if parseFunc != nil {
		for _, fc := range fcs {
			fr := readFrame(parseFunc, t.file, fc)
			t.AddFrame(id, fr)
		}
	}
	// Delete frames with id from t.framesCoords,
	// because they are just being parsed
	delete(t.framesCoords, id)
}
<commit_msg>Return err in parseTag<commit_after>package id3v2

import (
	"errors"
	"io"
	"os"

	"github.com/bogem/id3v2/util"
)

const frameHeaderSize = 10

type frameHeader struct {
	ID        string
	FrameSize uint32
}

func parseTag(file *os.File) (*Tag, error) {
	if file == nil {
		err := errors.New("Invalid file: file is nil")
		return nil, err
	}
	header, err := parseHeader(file)
	if err != nil {
		err = errors.New("Trying to parse tag header: " + err.Error())
		return nil, err
	}
	if header == nil {
		return newTag(file, 0), nil
	}
	if header.Version < 3 {
		err = errors.New("Unsupported version of ID3 tag")
		return nil, err
	}

	t := newTag(file, tagHeaderSize+header.FramesSize)
	err = t.findAllFrames()

	return t, err
}

func newTag(file *os.File, originalSize uint32) *Tag {
	return &Tag{
		ids: V24IDs,

		file:         file,
		originalSize: originalSize,
	}
}

func (t *Tag) findAllFrames() error {
	if t.framesCoords == nil {
		t.framesCoords = make(map[string][]frameCoordinates)
	}

	pos := uint32(tagHeaderSize) // initial position of read - end of tag header (beginning of first frame)
	tagSize := t.originalSize
	f := t.file

	for pos < tagSize {
		if _, err := f.Seek(int64(pos), os.SEEK_SET); err != nil {
			return err
		}

		header, err := parseFrameHeader(f)
		if err != nil {
			return err
		}
		pos += frameHeaderSize

		fc := frameCoordinates{
			Len: int64(header.FrameSize),
			Pos: int64(pos),
		}
		fcs := t.framesCoords[header.ID]
		fcs = append(fcs, fc)
		t.framesCoords[header.ID] = fcs

		pos += header.FrameSize
	}

	return nil
}

func parseFrameHeader(rd io.Reader) (*frameHeader, error) {
	byteHeader := make([]byte, frameHeaderSize)
	n, err := rd.Read(byteHeader)
	if err != nil {
		return nil, err
	}
	if n < frameHeaderSize {
		err = errors.New("Size of frame header is less than expected")
	}

	header := &frameHeader{
		ID:        string(byteHeader[:4]),
		FrameSize: util.ParseSize(byteHeader[4:8]),
	}

	return header, nil

}

func (t Tag) findParseFunc(id string) func(io.Reader) (Framer, error) {
	if id[0] == 'T' {
		return ParseTextFrame
	}
	switch id {
	case t.ids["Attached picture"]:
		return ParsePictureFrame
	case t.ids["Comments"]:
		return ParseCommentFrame
	case t.ids["Unsynchronised lyrics/text transcription"]:
		return ParseUnsynchronisedLyricsFrame
	}
	return nil
}

func readFrame(parseFunc func(io.Reader) (Framer, error), file *os.File, fc frameCoordinates) Framer {
	file.Seek(fc.Pos, os.SEEK_SET)
	rd := &io.LimitedReader{R: file, N: fc.Len}
	fr, err := parseFunc(rd)
	if err != nil {
		panic(err)
	}
	return fr
}

func (t *Tag) parseAllFramesCoords() {
	for id := range t.framesCoords {
		t.parseFramesCoordsWithID(id)
	}
}

func (t *Tag) parseFramesCoordsWithID(id string) {
	fcs, exists := t.framesCoords[id]
	if !exists {
		return
	}

	parseFunc := t.findParseFunc(id)
	if parseFunc != nil {
		for _, fc := range fcs {
			fr := readFrame(parseFunc, t.file, fc)
			t.AddFrame(id, fr)
		}
	}
	// Delete frames with id from t.framesCoords,
	// because they are just being parsed
	delete(t.framesCoords, id)
}
<|endoftext|>


<commit_before>package shp

import (
	"archive/zip"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
)

func compressFileToZIP(zw *zip.Writer, src, tgt string, t *testing.T) {
	r, err := os.Open(src)
	if err != nil {
		t.Fatalf("Could not open for compression %s: %v", src, err)
	}
	w, err := zw.Create(tgt)
	if err != nil {
		t.Fatalf("Could not start to compress %s: %v", tgt, err)
	}
	_, err = io.Copy(w, r)
	if err != nil {
		t.Fatalf("Could not compress contents for %s: %v", tgt, err)
	}
}

// createTempZIP packs the SHP, SHX, and DBF into a ZIP in a temporary
// directory
func createTempZIP(prefix string, t *testing.T) (dir, filename string) {
	dir, err := ioutil.TempDir("", "go-shp-test")
	if err != nil {
		t.Fatalf("Could not create temporary directory: %v", err)
	}
	base := filepath.Base(prefix)
	zipName := base + ".zip"
	w, err := os.Create(filepath.Join(dir, zipName))
	if err != nil {
		t.Fatalf("Could not create temporary zip file: %v", err)
	}
	zw := zip.NewWriter(w)
	for _, suffix := range []string{".shp", ".shx", ".dbf"} {
		compressFileToZIP(zw, prefix+suffix, base+suffix, t)
	}
	if err := zw.Close(); err != nil {
		t.Fatalf("Could not close the written zip: %v", err)
	}
	return dir, zipName
}

func getShapesZipped(prefix string, t *testing.T) (shapes []Shape) {
	dir, filename := createTempZIP(prefix, t)
	defer os.RemoveAll(dir)
	zr, err := OpenZip(filepath.Join(dir, filename))
	if err != nil {
		t.Errorf("Error when opening zip file: %v", err)
	}
	for zr.Next() {
		_, shape := zr.Shape()
		shapes = append(shapes, shape)
	}
	if err := zr.Err(); err != nil {
		t.Errorf("Error when iterating over the shapes: %v", err)
	}

	if err := zr.Close(); err != nil {
		t.Errorf("Could not close zipreader: %v", err)
	}
	return shapes
}

func TestZipReader(t *testing.T) {
	for prefix, _ := range dataForReadTests {
		t.Logf("Testing zipped reading for %s", prefix)
		test_shapeIdentity(t, prefix, getShapesZipped)
	}
}

// TestZipReaderAttributes reads the same shapesfile twice, first directly from
// the Shp with a Reader, and, second, from a zip. It compares the fields as
// well as the shapes and the attributes. For this test, the Shapes are
// considered to be equal if their bounding boxes are equal.
func TestZipReaderAttribute(t *testing.T) {
	lr, err := Open("ne_110m_admin_0_countries.shp")
	if err != nil {
		t.Fatal(err)
	}
	defer lr.Close()
	zr, err := OpenZip("ne_110m_admin_0_countries.zip")
	if err != nil {
		t.Fatal(err)
	}
	defer zr.Close()
	fsl := lr.Fields()
	fsz := zr.Fields()
	if len(fsl) != len(fsz) {
		t.Fatalf("Number of attributes do not match: Wanted %d, got %d", len(fsl), len(fsz))
	}
	for i := range fsl {
		if fsl[i] != fsz[i] {
			t.Fatalf("Attribute %d (%s) does not match (%s)", i, fsl[i], fsz[i])
		}
	}
	for zr.Next() && lr.Next() {
		ln, ls := lr.Shape()
		zn, zs := zr.Shape()
		if ln != zn {
			t.Fatalf("Sequence number wrong: Wanted %d, got %d", ln, zn)
		}
		if ls.BBox() != zs.BBox() {
			t.Fatalf("Bounding boxes for shape #%d do not match", ln)
		}
		for i := range fsl {
			la := lr.Attribute(i)
			za := zr.Attribute(i)
			if la != za {
				t.Fatalf("Shape %d: Attribute %d (%s) are unequal: '%s' vs '%s'",
					ln, i, fsl[i].FooString(), la, za)
			}
		}
	}
	if lr.Err() != nil {
		t.Logf("Reader error: %v / ZipReader error: %v", lr.Err(), zr.Err())
		t.FailNow()
	}
}

func TestNaturalEarthZip(t *testing.T) {
	zr, err := OpenZip("ne_110m_admin_0_countries.zip")
	if err != nil {
		t.Fatal(err)
	}
	defer zr.Close()
	t.Log(len(zr.Fields()))
	for zr.Next() {
	}
	if zr.Err() != nil {
		t.Fatal(zr.Err())
	}
}
<commit_msg>Tests can download natural earth data set<commit_after>package shp

import (
	"archive/zip"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path"
	"path/filepath"
	"testing"
)

func compressFileToZIP(zw *zip.Writer, src, tgt string, t *testing.T) {
	r, err := os.Open(src)
	if err != nil {
		t.Fatalf("Could not open for compression %s: %v", src, err)
	}
	w, err := zw.Create(tgt)
	if err != nil {
		t.Fatalf("Could not start to compress %s: %v", tgt, err)
	}
	_, err = io.Copy(w, r)
	if err != nil {
		t.Fatalf("Could not compress contents for %s: %v", tgt, err)
	}
}

// createTempZIP packs the SHP, SHX, and DBF into a ZIP in a temporary
// directory
func createTempZIP(prefix string, t *testing.T) (dir, filename string) {
	dir, err := ioutil.TempDir("", "go-shp-test")
	if err != nil {
		t.Fatalf("Could not create temporary directory: %v", err)
	}
	base := filepath.Base(prefix)
	zipName := base + ".zip"
	w, err := os.Create(filepath.Join(dir, zipName))
	if err != nil {
		t.Fatalf("Could not create temporary zip file: %v", err)
	}
	zw := zip.NewWriter(w)
	for _, suffix := range []string{".shp", ".shx", ".dbf"} {
		compressFileToZIP(zw, prefix+suffix, base+suffix, t)
	}
	if err := zw.Close(); err != nil {
		t.Fatalf("Could not close the written zip: %v", err)
	}
	return dir, zipName
}

func getShapesZipped(prefix string, t *testing.T) (shapes []Shape) {
	dir, filename := createTempZIP(prefix, t)
	defer os.RemoveAll(dir)
	zr, err := OpenZip(filepath.Join(dir, filename))
	if err != nil {
		t.Errorf("Error when opening zip file: %v", err)
	}
	for zr.Next() {
		_, shape := zr.Shape()
		shapes = append(shapes, shape)
	}
	if err := zr.Err(); err != nil {
		t.Errorf("Error when iterating over the shapes: %v", err)
	}

	if err := zr.Close(); err != nil {
		t.Errorf("Could not close zipreader: %v", err)
	}
	return shapes
}

func TestZipReader(t *testing.T) {
	for prefix, _ := range dataForReadTests {
		t.Logf("Testing zipped reading for %s", prefix)
		test_shapeIdentity(t, prefix, getShapesZipped)
	}
}

func unzipToTempDir(t *testing.T, p string) string {
	td, err := ioutil.TempDir("", "")
	if err != nil {
		t.Fatalf("%v", err)
	}
	zip, err := zip.OpenReader(p)
	if err != nil {
		t.Fatalf("%v", err)
	}
	defer zip.Close()
	for _, f := range zip.File {
		_, fn := path.Split(f.Name)
		pn := filepath.Join(td, fn)
		t.Logf("Uncompress: %s -> %s", f.Name, pn)
		w, err := os.Create(pn)
		if err != nil {
			t.Fatalf("Cannot unzip %s: %v", p, err)
		}
		defer w.Close()
		r, err := f.Open()
		if err != nil {
			t.Fatalf("Cannot unzip %s: %v", p, err)
		}
		defer r.Close()
		_, err = io.Copy(w, r)
		if err != nil {
			t.Fatalf("Cannot unzip %s: %v", p, err)
		}
	}
	return td
}

// TestZipReaderAttributes reads the same shapesfile twice, first directly from
// the Shp with a Reader, and, second, from a zip. It compares the fields as
// well as the shapes and the attributes. For this test, the Shapes are
// considered to be equal if their bounding boxes are equal.
func TestZipReaderAttribute(t *testing.T) {
	b := "ne_110m_admin_0_countries"
	skipOrDownloadNaturalEarth(t, b+".zip")
	d := unzipToTempDir(t, b+".zip")
	defer os.RemoveAll(d)
	lr, err := Open(filepath.Join(d, b+".shp"))
	if err != nil {
		t.Fatal(err)
	}
	defer lr.Close()
	zr, err := OpenZip(b + ".zip")
	if os.IsNotExist(err) {
		t.Skipf("Skipping test, as Natural Earth dataset wasn't found")
	}
	if err != nil {
		t.Fatal(err)
	}
	defer zr.Close()
	fsl := lr.Fields()
	fsz := zr.Fields()
	if len(fsl) != len(fsz) {
		t.Fatalf("Number of attributes do not match: Wanted %d, got %d", len(fsl), len(fsz))
	}
	sum := 0
	for i := range fsl {
		sum += int(fsz[i].Size)
		if fsl[i] != fsz[i] {
			t.Fatalf("Attribute %d (%s) does not match (%s)", i, fsl[i], fsz[i])
		}
	}
	for zr.Next() && lr.Next() {
		ln, ls := lr.Shape()
		zn, zs := zr.Shape()
		if ln != zn {
			t.Fatalf("Sequence number wrong: Wanted %d, got %d", ln, zn)
		}
		if ls.BBox() != zs.BBox() {
			t.Fatalf("Bounding boxes for shape #%d do not match", ln+1)
		}
		for i := range fsl {
			la := lr.Attribute(i)
			za := zr.Attribute(i)
			if la != za {
				t.Fatalf("Shape %d: Attribute %d (%s) are unequal: '%s' vs '%s'",
					ln+1, i, fsl[i].String(), la, za)
			}
		}
	}
	if lr.Err() != nil {
		t.Logf("Reader error: %v / ZipReader error: %v", lr.Err(), zr.Err())
		t.FailNow()
	}
}

func skipOrDownloadNaturalEarth(t *testing.T, p string) {
	if _, err := os.Stat(p); os.IsNotExist(err) {
		dl := false
		for _, a := range os.Args {
			if a == "download" {
				dl = true
				break
			}
		}
		u := "http://www.naturalearthdata.com/http//www.naturalearthdata.com/download/110m/cultural/ne_110m_admin_0_countries.zip"
		if !dl {
			t.Skipf("Skipped, as %s does not exist. Consider calling tests with '-args download` "+
				"or download manually from '%s'", p, u)
		} else {
			t.Logf("Downloading %s", u)
			w, err := os.Create(p)
			if err != nil {
				t.Fatalf("Could not download: %p: %v", p, err)
			}
			defer w.Close()
			resp, err := http.Get(u)
			if err != nil {
				t.Fatalf("Could not download: %p: %v", p, err)
			}
			defer resp.Body.Close()
			_, err = io.Copy(w, resp.Body)
			if err != nil {
				t.Fatalf("Could not download: %p: %v", p, err)
			}
			t.Logf("Download complete")
		}
	}
}

func TestNaturalEarthZip(t *testing.T) {
	type metaShape struct {
		Attributes map[string]string
		Shape
	}
	p := "ne_110m_admin_0_countries.zip"
	skipOrDownloadNaturalEarth(t, p)
	zr, err := OpenZip(p)
	if err != nil {
		t.Fatal(err)
	}
	defer zr.Close()

	fs := zr.Fields()
	if len(fs) != 63 {
		t.Fatalf("Expected 63 columns in Natural Earth dataset, got %d", len(fs))
	}
	var metas []metaShape
	for zr.Next() {
		m := metaShape{
			Attributes: make(map[string]string),
		}
		_, m.Shape = zr.Shape()
		for n := range fs {
			m.Attributes[fs[n].String()] = zr.Attribute(n)
		}
		metas = append(metas, m)
	}
	if zr.Err() != nil {
		t.Fatal(zr.Err())
	}
	for _, m := range metas {
		t.Log(m.Attributes["name"])
	}
}
<|endoftext|>


<commit_before>// Package millipede provides a framework for creating millipedes.
// millipede is designed to be easy to understand and write, the most simple
// application can be written as follow:
//   func main() {
//     fmt.Println(millipede.New(20))
//   }
package millipede

import (
	"bytes"
	"fmt"
	"strings"
	"unicode/utf8"

	"github.com/getmillipede/millipede-go/vendor/github.com/Sirupsen/logrus"
	"github.com/getmillipede/millipede-go/vendor/github.com/mgutz/ansi"
	"github.com/kortschak/zalgo"
)

type Millipede struct {
	// Size is the amount of feet pairs
	Size uint64

	// Reverse is the flag that indicates the direction (up/down)
	Reverse bool

	// Skin is the current millipede skin (template)
	Skin string

	// Opposite is the flag that indicates the direction (left/right)
	Opposite bool

	// Width is the width of the millipede (depending on its age and the food it consumes)
	Width uint64

	// Curve is the size of the curve
	Curve uint64

	// Chameleon is the flag that indicates the millipede share its environment color
	Chameleon bool

	// Rainbow is the flag that indicates the millipede live with care bears
	Rainbow bool

	// Zalgo is the flag that invoke the hive-mind representing chaos
	Zalgo bool
}

type Skin struct {
	// Head is used by the millipede to think about its life
	Head string
	// Pede are what make this arthropod so special
	Pede string

	// Reverse is the reverse skin of the millipede
	Reverse *Skin
}

// String returns a string representing a millipede
func (m *Millipede) String() string {
	// --curve support
	paddingOffsets := []string{""}
	if m.Curve > 0 {
		for n := uint64(1); n < m.Curve+1; n++ {
			paddingOffsets = append(paddingOffsets, strings.Repeat(" ", int(n)))
		}
		for n := m.Curve - 1; n > 0; n-- {
			paddingOffsets = append(paddingOffsets, strings.Repeat(" ", int(n)))
		}
	}

	// --opposite support
	if m.Opposite {
		paddingOffsets = append(paddingOffsets[m.Curve:], paddingOffsets[:m.Curve]...)
	}

	skins := map[string]Skin{
		"default": {
			Head: "  ╚⊙ ⊙╝  ",
			Pede: "╚═(███)═╝",
			Reverse: &Skin{
				Head: "  ╔⊙ ⊙╗  ",
				Pede: "╔═(███)═╗",
			},
		},
		"frozen": {
			Head: "  ╚⊙ ⊙╝  ",
			Pede: "╚═(❄❄❄)═╝",
			Reverse: &Skin{
				Head: "  ╔⊙ ⊙╗  ",
				Pede: "╔═(❄❄❄)═╗",
			},
		},
		"corporate": {
			Head: "  ╚⊙ ⊙╝  ",
			Pede: "╚═(©©©)═╝",
			Reverse: &Skin{
				Head: "  ╔⊙ ⊙╗  ",
				Pede: "╔═(©©©)═╗",
			},
		},
		"love": {
			Head: "  ╚⊙ ⊙╝  ",
			Pede: "╚═(♥♥♥)═╝",
			Reverse: &Skin{
				Head: "  ╔⊙ ⊙╗  ",
				Pede: "╔═(♥♥♥)═╗",
			},
		},
		"musician": {
			Head: "  ╚⊙ ⊙╝  ",
			Pede: "╚═(♫♩♬)═╝",
			Reverse: &Skin{
				Head: "  ╔⊙ ⊙╗  ",
				Pede: "╔═(♫♩♬)═╗",
			},
		},
		"bocal": {
			Head: "  ╚⊙ ⊙╝  ",
			Pede: "╚═(🐟🐟🐟)═╝",
			Reverse: &Skin{
				Head: "  ╔⊙ ⊙╗  ",
				Pede: "╔═(🐟🐟🐟)═╗",
			},
		},
		"ascii": {
			Head: "  \\o o/  ",
			Pede: "|=(###)=|",
			Reverse: &Skin{
				Head: "  /o o\\  ",
				Pede: "|=(###)=|",
			},
		},
		"inception": {
			Head: "    👀    ",
			Pede: "╚═(🐛🐛🐛)═╝",
			Reverse: &Skin{
				Head: "    👀    ",
				Pede: "╔═(🐛🐛🐛)═╗",
			},
		},
		"humancentipede": {
			Head: "    👀    ",
			Pede: "╚═(😷😷😷)═╝",
			Reverse: &Skin{
				Head: "    👀    ",
				Pede: "╔═(😷😷😷)═╗",
			},
		},
		"finger": {
			Head: "    👀    ",
			Pede: "👈~~~  ~~~👉",
			Reverse: &Skin{
				Head: "    👀    ",
				Pede: "👈~~~~~~~~👉",
			},
		},
	}

	// --skin support
	skin := skins[m.Skin]
	if skin.Head == "" {
		logrus.Fatalf("no such skin: '%s'", m.Skin)
	}

	// --reverse support
	if m.Reverse && skin.Reverse != nil && skin.Reverse.Head != "" {
		skin = *skin.Reverse
	}

	// --width support
	if m.Width < 3 {
		logrus.Fatalf("millipede cannot have a witch < 3")
	}
	if m.Width > 3 {
		w := utf8.RuneCountInString(skin.Head)
		head := StringToRuneSlice(skin.Head)
		skin.Head = string(head[:w/2]) + strings.Repeat(string(head[w/2:w/2+1]), int(m.Width-2)) + string(head[w/2+1:])
		pede := StringToRuneSlice(skin.Pede)
		skin.Pede = string(pede[:w/2]) + strings.Repeat(string(pede[w/2:w/2+1]), int(m.Width-2)) + string(pede[w/2+1:])
	}

	// build the millipede body
	body := []string{paddingOffsets[0] + strings.TrimRight(skin.Head, " ")}
	var x uint64
	for x = 0; x < m.Size; x++ {
		var line string
		if m.Curve > 0 {
			line = paddingOffsets[x%(m.Curve*2)] + skin.Pede
		} else {
			line = "" + skin.Pede
		}
		body = append(body, line)
	}

	// --reverse support
	if m.Reverse {
		for i, j := 0, len(body)-1; i < j; i, j = i+1, j-1 {
			body[i], body[j] = body[j], body[i]
		}
	}

	// --chameleon and --rainbow support
	for idx, line := range body {
		colors := []string{"red", "green", "yellow", "blue", "magenta", "cyan", "white"}

		fgColor := ""
		bgColor := ""

		// --chameleon support
		if m.Chameleon {
			fgColor = "black"
		}

		// --rainbow
		if m.Rainbow {
			bgColor = colors[idx%len(colors)]
			if m.Chameleon {
				fgColor = bgColor
				fgColor = "black"
			}
		}

		if fgColor != "" || bgColor != "" {
			paddingSize := len(line) - len(strings.TrimSpace(line))
			line = strings.Repeat(" ", paddingSize) + ansi.Color(line[paddingSize:], fgColor+":"+bgColor)
		}

		body[idx] = line
	}

	output := strings.Join(body, "\n")

	// --zalgo support
	if m.Zalgo {
		buf := new(bytes.Buffer)

		z := zalgo.NewCorrupter(buf)
		z.Zalgo = func(n int, r rune, z *zalgo.Corrupter) bool {
			if string(r) == " " || r == 10 {
				z.Up = 0
				z.Middle = 0
				z.Down = 0
			} else {
				if z.Up == 0 {
					z.Up = complex(0, 0.2)
					z.Middle = complex(0, 0.2)
					z.Down = complex(0.001, 0.3)
				}
				z.Up += 0.1
				z.Middle += complex(0.1, 0.2)
				z.Down += 0.1
			}
			return false
		}
		fmt.Fprintln(z, output)
		output = buf.String()
	}

	return output
}

// New returns a millipede
func New(size uint64) *Millipede {
	return &Millipede{
		Size:      size,
		Reverse:   false,
		Skin:      "default",
		Opposite:  false,
		Width:     3,
		Curve:     4,
		Chameleon: false,
		Rainbow:   false,
		Zalgo:     false,
	}
}

// StringToRuneSlice converts a string to a slice of runes
func StringToRuneSlice(input string) []rune {
	output := make([]rune, utf8.RuneCountInString(input))
	n := 0
	for _, r := range input {
		output[n] = r
		n++
	}
	return output
}
<commit_msg>party -c<commit_after>// Package millipede provides a framework for creating millipedes.
// millipede is designed to be easy to understand and write, the most simple
// application can be written as follow:
//   func main() {
//     fmt.Println(millipede.New(20))
//   }
package millipede

import (
	"bytes"
	"fmt"
	"strings"
	"unicode/utf8"

	"github.com/getmillipede/millipede-go/vendor/github.com/Sirupsen/logrus"
	"github.com/getmillipede/millipede-go/vendor/github.com/kortschak/zalgo"
	"github.com/getmillipede/millipede-go/vendor/github.com/mgutz/ansi"
)

type Millipede struct {
	// Size is the amount of feet pairs
	Size uint64

	// Reverse is the flag that indicates the direction (up/down)
	Reverse bool

	// Skin is the current millipede skin (template)
	Skin string

	// Opposite is the flag that indicates the direction (left/right)
	Opposite bool

	// Width is the width of the millipede (depending on its age and the food it consumes)
	Width uint64

	// Curve is the size of the curve
	Curve uint64

	// Chameleon is the flag that indicates the millipede share its environment color
	Chameleon bool

	// Rainbow is the flag that indicates the millipede live with care bears
	Rainbow bool

	// Zalgo is the flag that invoke the hive-mind representing chaos
	Zalgo bool
}

type Skin struct {
	// Head is used by the millipede to think about its life
	Head string
	// Pede are what make this arthropod so special
	Pede string

	// Reverse is the reverse skin of the millipede
	Reverse *Skin
}

// String returns a string representing a millipede
func (m *Millipede) String() string {
	// --curve support
	paddingOffsets := []string{""}
	if m.Curve > 0 {
		for n := uint64(1); n < m.Curve+1; n++ {
			paddingOffsets = append(paddingOffsets, strings.Repeat(" ", int(n)))
		}
		for n := m.Curve - 1; n > 0; n-- {
			paddingOffsets = append(paddingOffsets, strings.Repeat(" ", int(n)))
		}
	}

	// --opposite support
	if m.Opposite {
		paddingOffsets = append(paddingOffsets[m.Curve:], paddingOffsets[:m.Curve]...)
	}

	skins := map[string]Skin{
		"default": {
			Head: "  ╚⊙ ⊙╝  ",
			Pede: "╚═(███)═╝",
			Reverse: &Skin{
				Head: "  ╔⊙ ⊙╗  ",
				Pede: "╔═(███)═╗",
			},
		},
		"frozen": {
			Head: "  ╚⊙ ⊙╝  ",
			Pede: "╚═(❄❄❄)═╝",
			Reverse: &Skin{
				Head: "  ╔⊙ ⊙╗  ",
				Pede: "╔═(❄❄❄)═╗",
			},
		},
		"corporate": {
			Head: "  ╚⊙ ⊙╝  ",
			Pede: "╚═(©©©)═╝",
			Reverse: &Skin{
				Head: "  ╔⊙ ⊙╗  ",
				Pede: "╔═(©©©)═╗",
			},
		},
		"love": {
			Head: "  ╚⊙ ⊙╝  ",
			Pede: "╚═(♥♥♥)═╝",
			Reverse: &Skin{
				Head: "  ╔⊙ ⊙╗  ",
				Pede: "╔═(♥♥♥)═╗",
			},
		},
		"musician": {
			Head: "  ╚⊙ ⊙╝  ",
			Pede: "╚═(♫♩♬)═╝",
			Reverse: &Skin{
				Head: "  ╔⊙ ⊙╗  ",
				Pede: "╔═(♫♩♬)═╗",
			},
		},
		"bocal": {
			Head: "  ╚⊙ ⊙╝  ",
			Pede: "╚═(🐟🐟🐟)═╝",
			Reverse: &Skin{
				Head: "  ╔⊙ ⊙╗  ",
				Pede: "╔═(🐟🐟🐟)═╗",
			},
		},
		"ascii": {
			Head: "  \\o o/  ",
			Pede: "|=(###)=|",
			Reverse: &Skin{
				Head: "  /o o\\  ",
				Pede: "|=(###)=|",
			},
		},
		"inception": {
			Head: "    👀    ",
			Pede: "╚═(🐛🐛🐛)═╝",
			Reverse: &Skin{
				Head: "    👀    ",
				Pede: "╔═(🐛🐛🐛)═╗",
			},
		},
		"humancentipede": {
			Head: "    👀    ",
			Pede: "╚═(😷😷😷)═╝",
			Reverse: &Skin{
				Head: "    👀    ",
				Pede: "╔═(😷😷😷)═╗",
			},
		},
		"finger": {
			Head: "    👀    ",
			Pede: "👈~~~  ~~~👉",
			Reverse: &Skin{
				Head: "    👀    ",
				Pede: "👈~~~~~~~~👉",
			},
		},
	}

	// --skin support
	skin := skins[m.Skin]
	if skin.Head == "" {
		logrus.Fatalf("no such skin: '%s'", m.Skin)
	}

	// --reverse support
	if m.Reverse && skin.Reverse != nil && skin.Reverse.Head != "" {
		skin = *skin.Reverse
	}

	// --width support
	if m.Width < 3 {
		logrus.Fatalf("millipede cannot have a witch < 3")
	}
	if m.Width > 3 {
		w := utf8.RuneCountInString(skin.Head)
		head := StringToRuneSlice(skin.Head)
		skin.Head = string(head[:w/2]) + strings.Repeat(string(head[w/2:w/2+1]), int(m.Width-2)) + string(head[w/2+1:])
		pede := StringToRuneSlice(skin.Pede)
		skin.Pede = string(pede[:w/2]) + strings.Repeat(string(pede[w/2:w/2+1]), int(m.Width-2)) + string(pede[w/2+1:])
	}

	// build the millipede body
	body := []string{paddingOffsets[0] + strings.TrimRight(skin.Head, " ")}
	var x uint64
	for x = 0; x < m.Size; x++ {
		var line string
		if m.Curve > 0 {
			line = paddingOffsets[x%(m.Curve*2)] + skin.Pede
		} else {
			line = "" + skin.Pede
		}
		body = append(body, line)
	}

	// --reverse support
	if m.Reverse {
		for i, j := 0, len(body)-1; i < j; i, j = i+1, j-1 {
			body[i], body[j] = body[j], body[i]
		}
	}

	// --chameleon and --rainbow support
	for idx, line := range body {
		colors := []string{"red", "green", "yellow", "blue", "magenta", "cyan", "white"}

		fgColor := ""
		bgColor := ""

		// --chameleon support
		if m.Chameleon {
			fgColor = "black"
		}

		// --rainbow
		if m.Rainbow {
			bgColor = colors[idx%len(colors)]
			if m.Chameleon {
				fgColor = bgColor
				fgColor = "black"
			}
		}

		if fgColor != "" || bgColor != "" {
			paddingSize := len(line) - len(strings.TrimSpace(line))
			line = strings.Repeat(" ", paddingSize) + ansi.Color(line[paddingSize:], fgColor+":"+bgColor)
		}

		body[idx] = line
	}

	output := strings.Join(body, "\n")

	// --zalgo support
	if m.Zalgo {
		buf := new(bytes.Buffer)

		z := zalgo.NewCorrupter(buf)
		z.Zalgo = func(n int, r rune, z *zalgo.Corrupter) bool {
			if string(r) == " " || r == 10 {
				z.Up = 0
				z.Middle = 0
				z.Down = 0
			} else {
				if z.Up == 0 {
					z.Up = complex(0, 0.2)
					z.Middle = complex(0, 0.2)
					z.Down = complex(0.001, 0.3)
				}
				z.Up += 0.1
				z.Middle += complex(0.1, 0.2)
				z.Down += 0.1
			}
			return false
		}
		fmt.Fprintln(z, output)
		output = buf.String()
	}

	return output
}

// New returns a millipede
func New(size uint64) *Millipede {
	return &Millipede{
		Size:      size,
		Reverse:   false,
		Skin:      "default",
		Opposite:  false,
		Width:     3,
		Curve:     4,
		Chameleon: false,
		Rainbow:   false,
		Zalgo:     false,
	}
}

// StringToRuneSlice converts a string to a slice of runes
func StringToRuneSlice(input string) []rune {
	output := make([]rune, utf8.RuneCountInString(input))
	n := 0
	for _, r := range input {
		output[n] = r
		n++
	}
	return output
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package apiclient

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"os"

	"github.com/srinandan/apigeecli/clilog"
)

//PostHttpOctet method is used to send resources, proxy bundles, shared flows etc.
func PostHttpOctet(print bool, url string, proxyName string) (respBody []byte, err error) {
	file, _ := os.Open(proxyName)
	defer file.Close()

	body := &bytes.Buffer{}
	writer := multipart.NewWriter(body)
	part, err := writer.CreateFormFile("proxy", proxyName)
	if err != nil {
		clilog.Error.Println("Error writing multi-part: ", err)
		return nil, err
	}
	_, err = io.Copy(part, file)
	if err != nil {
		clilog.Error.Println("error copying multi-part: ", err)
		return nil, err
	}

	err = writer.Close()
	if err != nil {
		clilog.Error.Println("error closing multi-part: ", err)
		return nil, err
	}
	client := &http.Client{}

	clilog.Info.Println("Connecting to : ", url)
	req, err := http.NewRequest("POST", url, body)
	if err != nil {
		clilog.Error.Println("error in client: ", err)
		return nil, err
	}

	clilog.Info.Println("Setting token : ", GetApigeeToken())
	req.Header.Add("Authorization", "Bearer "+GetApigeeToken())
	req.Header.Set("Content-Type", writer.FormDataContentType())
	resp, err := client.Do(req)

	if err != nil {
		clilog.Error.Println("error connecting: ", err)
		return nil, err
	}

	defer resp.Body.Close()
	respBody, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		clilog.Error.Println("error in response: ", err)
		return nil, err
	} else if resp.StatusCode != 200 {
		clilog.Error.Println("error in response: ", string(respBody))
		return nil, errors.New("error in response")
	}
	if print {
		return respBody, PrettyPrint(respBody)
	}

	return respBody, nil
}

//DownloadResource method is used to download resources, proxy bundles, sharedflows
func DownloadResource(url string, name string, resType string) error {
	var filename string

	if resType == ".zip" {
		filename = name + ".zip"
	} else {
		filename = name
	}

	out, err := os.Create(filename)
	if err != nil {
		clilog.Error.Println("error creating file: ", err)
		return err
	}
	defer out.Close()

	client := &http.Client{}

	clilog.Info.Println("Connecting to : ", url)
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		clilog.Error.Println("error in client: ", err)
		return err
	}

	clilog.Info.Println("Setting token : ", GetApigeeToken())
	req.Header.Add("Authorization", "Bearer "+GetApigeeToken())

	resp, err := client.Do(req)

	if err != nil {
		clilog.Error.Println("error connecting: ", err)
		return err
	} else if resp.StatusCode > 299 {
		clilog.Error.Println("error in response: ", resp.Body)
		return errors.New("error in response")
	}
	defer resp.Body.Close()
	_, err = io.Copy(out, resp.Body)
	if err != nil {
		clilog.Error.Println("error writing response to file: ", err)
		return err
	}

	fmt.Println("Resource " + filename + " completed")
	return nil
}

//HttpClient method is used to GET,POST,PUT or DELETE JSON data
func HttpClient(print bool, params ...string) (respBody []byte, err error) {
	// The first parameter instructs whether the output should be printed
	// The second parameter is url. If only one parameter is sent, assume GET
	// The third parameter is the payload. The two parameters are sent, assume POST
	// THe fourth parameter is the method. If three parameters are sent, assume method in param
	//The fifth parameter is content type
	var req *http.Request
	contentType := "application/json"

	client := &http.Client{}
	clilog.Info.Println("Connecting to: ", params[0])

	switch paramLen := len(params); paramLen {
	case 1:
		req, err = http.NewRequest("GET", params[0], nil)
	case 2:
		clilog.Info.Println("Payload: ", params[1])
		req, err = http.NewRequest("POST", params[0], bytes.NewBuffer([]byte(params[1])))
	case 3:
		if req, err = getRequest(params); err != nil {
			return nil, err
		}
	case 4:
		if req, err = getRequest(params); err != nil {
			return nil, err
		}
		contentType = params[2]
	default:
		return nil, errors.New("unsupported method")
	}

	if err != nil {
		clilog.Error.Println("error in client: ", err)
		return nil, err
	}

	if GetApigeeToken() == "" {
		if err = SetAccessToken(); err != nil {
			return nil, err
		}
	}

	clilog.Info.Println("Setting token : ", GetApigeeToken())
	req.Header.Add("Authorization", "Bearer "+GetApigeeToken())
	req.Header.Set("Content-Type", contentType)

	resp, err := client.Do(req)

	if err != nil {
		clilog.Error.Println("error connecting: ", err)
		return nil, err
	}

	if resp != nil {
		defer resp.Body.Close()
	}

	respBody, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		clilog.Error.Println("error in response: ", err)
		return nil, err
	} else if resp.StatusCode > 299 {
		clilog.Error.Println("error in response: ", string(respBody))
		return nil, errors.New("error in response")
	}
	if print {
		return respBody, PrettyPrint(respBody)
	}
	return respBody, nil
}

//PrettyPrint method prints formatted json
func PrettyPrint(body []byte) error {
	var prettyJSON bytes.Buffer
	err := json.Indent(&prettyJSON, body, "", "\t")
	if err != nil {
		clilog.Error.Println("error parsing response: ", err)
		return err
	}
	fmt.Println(prettyJSON.String())
	return nil
}

func getRequest(params []string) (req *http.Request, err error) {
	if params[2] == "DELETE" {
		req, err = http.NewRequest("DELETE", params[0], nil)
	} else if params[2] == "PUT" {
		clilog.Info.Println("Payload: ", params[1])
		req, err = http.NewRequest("PUT", params[0], bytes.NewBuffer([]byte(params[1])))
	} else if params[2] == "PATCH" {
		clilog.Info.Println("Payload: ", params[1])
		req, err = http.NewRequest("PATCH", params[0], bytes.NewBuffer([]byte(params[1])))
	} else {
		return nil, errors.New("unsupported method")
	}
	return req, err
}
<commit_msg>support put<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package apiclient

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"os"

	"github.com/srinandan/apigeecli/clilog"
)

//PostHttpOctet method is used to send resources, proxy bundles, shared flows etc.
func PostHttpOctet(print bool, update bool, url string, proxyName string) (respBody []byte, err error) {
	file, _ := os.Open(proxyName)
	defer file.Close()

	var req *http.Request

	body := &bytes.Buffer{}
	writer := multipart.NewWriter(body)
	part, err := writer.CreateFormFile("proxy", proxyName)
	if err != nil {
		clilog.Error.Println("Error writing multi-part: ", err)
		return nil, err
	}
	_, err = io.Copy(part, file)
	if err != nil {
		clilog.Error.Println("error copying multi-part: ", err)
		return nil, err
	}

	err = writer.Close()
	if err != nil {
		clilog.Error.Println("error closing multi-part: ", err)
		return nil, err
	}
	client := &http.Client{}

	clilog.Info.Println("Connecting to : ", url)
	if !update {
		req, err = http.NewRequest("POST", url, body)
	} else {
		req, err = http.NewRequest("PUT", url, body)
	}

	if err != nil {
		clilog.Error.Println("error in client: ", err)
		return nil, err
	}

	clilog.Info.Println("Setting token : ", GetApigeeToken())
	req.Header.Add("Authorization", "Bearer "+GetApigeeToken())
	req.Header.Set("Content-Type", writer.FormDataContentType())
	resp, err := client.Do(req)

	if err != nil {
		clilog.Error.Println("error connecting: ", err)
		return nil, err
	}

	defer resp.Body.Close()
	respBody, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		clilog.Error.Println("error in response: ", err)
		return nil, err
	} else if resp.StatusCode != 200 {
		clilog.Error.Println("error in response: ", string(respBody))
		return nil, errors.New("error in response")
	}
	if print {
		return respBody, PrettyPrint(respBody)
	}

	return respBody, nil
}

//DownloadResource method is used to download resources, proxy bundles, sharedflows
func DownloadResource(url string, name string, resType string) error {
	var filename string

	if resType == ".zip" {
		filename = name + ".zip"
	} else {
		filename = name
	}

	out, err := os.Create(filename)
	if err != nil {
		clilog.Error.Println("error creating file: ", err)
		return err
	}
	defer out.Close()

	client := &http.Client{}

	clilog.Info.Println("Connecting to : ", url)
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		clilog.Error.Println("error in client: ", err)
		return err
	}

	clilog.Info.Println("Setting token : ", GetApigeeToken())
	req.Header.Add("Authorization", "Bearer "+GetApigeeToken())

	resp, err := client.Do(req)

	if err != nil {
		clilog.Error.Println("error connecting: ", err)
		return err
	} else if resp.StatusCode > 299 {
		clilog.Error.Println("error in response: ", resp.Body)
		return errors.New("error in response")
	}
	defer resp.Body.Close()
	_, err = io.Copy(out, resp.Body)
	if err != nil {
		clilog.Error.Println("error writing response to file: ", err)
		return err
	}

	fmt.Println("Resource " + filename + " completed")
	return nil
}

//HttpClient method is used to GET,POST,PUT or DELETE JSON data
func HttpClient(print bool, params ...string) (respBody []byte, err error) {
	// The first parameter instructs whether the output should be printed
	// The second parameter is url. If only one parameter is sent, assume GET
	// The third parameter is the payload. The two parameters are sent, assume POST
	// THe fourth parameter is the method. If three parameters are sent, assume method in param
	//The fifth parameter is content type
	var req *http.Request
	contentType := "application/json"

	client := &http.Client{}
	clilog.Info.Println("Connecting to: ", params[0])

	switch paramLen := len(params); paramLen {
	case 1:
		req, err = http.NewRequest("GET", params[0], nil)
	case 2:
		clilog.Info.Println("Payload: ", params[1])
		req, err = http.NewRequest("POST", params[0], bytes.NewBuffer([]byte(params[1])))
	case 3:
		if req, err = getRequest(params); err != nil {
			return nil, err
		}
	case 4:
		if req, err = getRequest(params); err != nil {
			return nil, err
		}
		contentType = params[2]
	default:
		return nil, errors.New("unsupported method")
	}

	if err != nil {
		clilog.Error.Println("error in client: ", err)
		return nil, err
	}

	if GetApigeeToken() == "" {
		if err = SetAccessToken(); err != nil {
			return nil, err
		}
	}

	clilog.Info.Println("Setting token : ", GetApigeeToken())
	req.Header.Add("Authorization", "Bearer "+GetApigeeToken())
	req.Header.Set("Content-Type", contentType)

	resp, err := client.Do(req)

	if err != nil {
		clilog.Error.Println("error connecting: ", err)
		return nil, err
	}

	if resp != nil {
		defer resp.Body.Close()
	}

	respBody, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		clilog.Error.Println("error in response: ", err)
		return nil, err
	} else if resp.StatusCode > 299 {
		clilog.Error.Println("error in response: ", string(respBody))
		return nil, errors.New("error in response")
	}
	if print {
		return respBody, PrettyPrint(respBody)
	}
	return respBody, nil
}

//PrettyPrint method prints formatted json
func PrettyPrint(body []byte) error {
	var prettyJSON bytes.Buffer
	err := json.Indent(&prettyJSON, body, "", "\t")
	if err != nil {
		clilog.Error.Println("error parsing response: ", err)
		return err
	}
	fmt.Println(prettyJSON.String())
	return nil
}

func getRequest(params []string) (req *http.Request, err error) {
	if params[2] == "DELETE" {
		req, err = http.NewRequest("DELETE", params[0], nil)
	} else if params[2] == "PUT" {
		clilog.Info.Println("Payload: ", params[1])
		req, err = http.NewRequest("PUT", params[0], bytes.NewBuffer([]byte(params[1])))
	} else if params[2] == "PATCH" {
		clilog.Info.Println("Payload: ", params[1])
		req, err = http.NewRequest("PATCH", params[0], bytes.NewBuffer([]byte(params[1])))
	} else {
		return nil, errors.New("unsupported method")
	}
	return req, err
}
<|endoftext|>


<commit_before>package nisql

import (
	"bytes"
	"database/sql"
	"encoding/json"
	"time"

	"github.com/lib/pq"
)

var nullString = []byte("null")

// NullString is a type that can be null or a string
type NullString struct {
	sql.NullString
}

// NullFloat64 is a type that can be null or a float64
type NullFloat64 struct {
	sql.NullFloat64
}

// NullInt64 is a type that can be null or an int
type NullInt64 struct {
	sql.NullInt64
}

// NullBool is a type that can be null or a bool
type NullBool struct {
	sql.NullBool
}

// MarshalJSON correctly serializes a NullString to JSON
func (n *NullString) MarshalJSON() ([]byte, error) {
	if !n.Valid {
		return nullString, nil
	}

	return json.Marshal(n.String)
}

// MarshalJSON correctly serializes a NullInt64 to JSON
func (n *NullInt64) MarshalJSON() ([]byte, error) {
	if !n.Valid {
		return nullString, nil
	}

	return json.Marshal(n.Int64)
}

// MarshalJSON correctly serializes a NullFloat64 to JSON
func (n *NullFloat64) MarshalJSON() ([]byte, error) {
	if !n.Valid {
		return nullString, nil
	}

	return json.Marshal(n.Float64)
}

// MarshalJSON correctly serializes a NullBool to JSON
func (n *NullBool) MarshalJSON() ([]byte, error) {
	if !n.Valid {
		return nullString, nil
	}

	return json.Marshal(n.Bool)
}

// UnmarshalJSON turns *NullString into a json.Unmarshaller.
func (n *NullString) UnmarshalJSON(b []byte) error {
	return unmarshal(n, b)
}

// UnmarshalJSON turns *NullInt64 into a json.Unmarshaller.
func (n *NullInt64) UnmarshalJSON(b []byte) error {
	return unmarshal(n, b)
}

// UnmarshalJSON turns *NullFloat64 into a json.Unmarshaller.
func (n *NullFloat64) UnmarshalJSON(b []byte) error {
	return unmarshal(n, b)
}

// UnmarshalJSON turns *NullBool into a json.Unmarshaller.
func (n *NullBool) UnmarshalJSON(b []byte) error {
	return unmarshal(n, b)
}

func unmarshal(s sql.Scanner, b []byte) error {
	var d interface{}
	if err := json.Unmarshal(b, &d); err != nil {
		return err
	}

	return s.Scan(d)
}

type NullTime struct {
	pq.NullTime
}

// MarshalJSON correctly serializes a NullTime to JSON
func (n *NullTime) MarshalJSON() ([]byte, error) {
	if !n.Valid {
		return nullString, nil
	}

	return json.Marshal(n.Time)
}

// UnmarshalJSON turns *NullTime into a json.Unmarshaller.
func (n *NullTime) UnmarshalJSON(b []byte) error {
	if bytes.Equal(b, nullString) {
		return n.Scan(nil)
	}

	var t time.Time
	if err := json.Unmarshal(b, &t); err != nil {
		return err
	}
	return n.Scan(t)
}
<commit_msg>Nisql: created constructor functions<commit_after>package nisql

import (
	"bytes"
	"database/sql"
	"encoding/json"
	"time"

	"github.com/lib/pq"
)

var nullString = []byte("null")

// String creates a new valid NullString
func String(s string) NullString {
	return NullString{
		sql.NullString{
			String: s,
			Valid:  true,
		},
	}
}

// NullString is a type that can be null or a string
type NullString struct {
	sql.NullString
}

// MarshalJSON correctly serializes a NullString to JSON
func (n *NullString) MarshalJSON() ([]byte, error) {
	if !n.Valid {
		return nullString, nil
	}

	return json.Marshal(n.String)
}

// UnmarshalJSON turns *NullString into a json.Unmarshaller.
func (n *NullString) UnmarshalJSON(b []byte) error {
	return unmarshal(n, b)
}

// Float64 creates a new valid NullFloat64
func Float64(f float64) NullFloat64 {
	return NullFloat64{
		sql.NullFloat64{
			Float64: f,
			Valid:   true,
		},
	}
}

// NullFloat64 is a type that can be null or a float64
type NullFloat64 struct {
	sql.NullFloat64
}

// MarshalJSON correctly serializes a NullFloat64 to JSON
func (n *NullFloat64) MarshalJSON() ([]byte, error) {
	if !n.Valid {
		return nullString, nil
	}

	return json.Marshal(n.Float64)
}

// UnmarshalJSON turns *NullFloat64 into a json.Unmarshaller.
func (n *NullFloat64) UnmarshalJSON(b []byte) error {
	return unmarshal(n, b)
}

// Int64 creates a new valid NullInt64
func Int64(i int64) NullInt64 {
	return NullInt64{
		sql.NullInt64{
			Int64: i,
			Valid: true,
		},
	}
}

// NullInt64 is a type that can be null or an int
type NullInt64 struct {
	sql.NullInt64
}

// MarshalJSON correctly serializes a NullInt64 to JSON
func (n *NullInt64) MarshalJSON() ([]byte, error) {
	if !n.Valid {
		return nullString, nil
	}

	return json.Marshal(n.Int64)
}

// UnmarshalJSON turns *NullInt64 into a json.Unmarshaller.
func (n *NullInt64) UnmarshalJSON(b []byte) error {
	return unmarshal(n, b)
}

// Bool creates a new valid NullBool
func Bool(b bool) NullBool {
	return NullBool{
		sql.NullBool{
			Bool:  b,
			Valid: true,
		},
	}
}

// NullBool is a type that can be null or a bool
type NullBool struct {
	sql.NullBool
}

// MarshalJSON correctly serializes a NullBool to JSON
func (n *NullBool) MarshalJSON() ([]byte, error) {
	if !n.Valid {
		return nullString, nil
	}

	return json.Marshal(n.Bool)
}

// UnmarshalJSON turns *NullBool into a json.Unmarshaller.
func (n *NullBool) UnmarshalJSON(b []byte) error {
	return unmarshal(n, b)
}

// Time creates a new valid NullTime
func Time(t time.Time) NullTime {
	return NullTime{
		pq.NullTime{
			Time:  t,
			Valid: true,
		},
	}
}

// NullTime is a type that can be null or a time.Time
type NullTime struct {
	pq.NullTime
}

// MarshalJSON correctly serializes a NullTime to JSON
func (n *NullTime) MarshalJSON() ([]byte, error) {
	if !n.Valid {
		return nullString, nil
	}

	return json.Marshal(n.Time)
}

// UnmarshalJSON turns *NullTime into a json.Unmarshaller.
func (n *NullTime) UnmarshalJSON(b []byte) error {
	if bytes.Equal(b, nullString) {
		return n.Scan(nil)
	}

	var t time.Time
	if err := json.Unmarshal(b, &t); err != nil {
		return err
	}

	return n.Scan(t)
}

func unmarshal(s sql.Scanner, b []byte) error {
	var d interface{}
	if err := json.Unmarshal(b, &d); err != nil {
		return err
	}

	return s.Scan(d)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net"

	"github.com/davecgh/go-spew/spew"
	"github.com/lightningnetwork/lnd/autopilot"
	"github.com/lightningnetwork/lnd/lnwire"
	"github.com/roasbeef/btcd/btcec"
	"github.com/roasbeef/btcd/wire"
	"github.com/roasbeef/btcutil"
)

// chanController is an implementation of the autopilot.ChannelController
// interface that's backed by a running lnd instance.
type chanController struct {
	server *server
}

// OpenChannel opens a channel to a target peer, with a capacity of the
// specified amount. This function should un-block immediately after the
// funding transaction that marks the channel open has been broadcast.
func (c *chanController) OpenChannel(target *btcec.PublicKey,
	amt btcutil.Amount, addrs []net.Addr) error {

	// We can't establish a channel if no addresses were provided for the
	// peer.
	if len(addrs) == 0 {
		return fmt.Errorf("Unable to create channel w/o an active " +
			"address")
	}

	// First, we'll check if we're already connected to the target peer. If
	// not, then we'll need to establish a connection.
	if _, err := c.server.FindPeer(target); err != nil {
		// TODO(roasbeef): try teach addr

		atplLog.Tracef("Connecting to %x to auto-create channel: ",
			target.SerializeCompressed())

		lnAddr := &lnwire.NetAddress{
			IdentityKey: target,
			ChainNet:    activeNetParams.Net,
		}

		// We'll attempt to successively connect to each of the
		// advertised IP addresses until we've either exhausted the
		// advertised IP addresses, or have made a connection.
		var connected bool
		for _, addr := range addrs {
			// If the address doesn't already have a port, then
			// we'll assume the current default port.
			tcpAddr, ok := addr.(*net.TCPAddr)
			if !ok {
				return fmt.Errorf("TCP address required instead "+
					"have %T", addr)
			}
			if tcpAddr.Port == 0 {
				tcpAddr.Port = defaultPeerPort
			}

			lnAddr.Address = tcpAddr

			// TODO(roasbeef): make perm connection in server after
			// chan open?
			err := c.server.ConnectToPeer(lnAddr, false)
			if err != nil {
				// If we weren't able to connect to the peer,
				// then we'll move onto the next.
				continue
			}

			connected = true
			break
		}

		// If we weren't able to establish a connection at all, then
		// we'll error out.
		if !connected {
			return fmt.Errorf("Unable to connect to %x",
				target.SerializeCompressed())
		}
	}

	// With the connection established, we'll now establish our connection
	// to the target peer, waiting for the first update before we exit.
	feePerWeight, err := c.server.cc.feeEstimator.EstimateFeePerWeight(3)
	if err != nil {
		return err
	}
	updateStream, errChan := c.server.OpenChannel(-1, target, amt, 0,
		feePerWeight, false)

	select {
	case err := <-errChan:
		return err
	case <-updateStream:
		return nil
	case <-c.server.quit:
		return nil
	}
}

func (c *chanController) CloseChannel(chanPoint *wire.OutPoint) error {
	return nil
}
func (c *chanController) SpliceIn(chanPoint *wire.OutPoint,
	amt btcutil.Amount) (*autopilot.Channel, error) {
	return nil, nil
}
func (c *chanController) SpliceOut(chanPoint *wire.OutPoint,
	amt btcutil.Amount) (*autopilot.Channel, error) {
	return nil, nil
}

// A compile time assertion to ensure chanController meets the
// autopilot.ChannelController interface.
var _ autopilot.ChannelController = (*chanController)(nil)

// initAutoPilot initializes a new autopilot.Agent instance based on the passed
// configuration struct. All interfaces needed to drive the pilot will be
// registered and launched.
func initAutoPilot(svr *server, cfg *autoPilotConfig) (*autopilot.Agent, error) {
	atplLog.Infof("Instantiating autopilot with cfg: %v", spew.Sdump(cfg))

	// First, we'll create the preferential attachment heuristic,
	// initialized with the passed auto pilot configuration parameters.
	//
	// TODO(roasbeef): switch here to dispatch specified heuristic
	minChanSize := svr.cc.wallet.Cfg.DefaultConstraints.DustLimit * 5
	prefAttachment := autopilot.NewConstrainedPrefAttachment(
		minChanSize, maxFundingAmount,
		uint16(cfg.MaxChannels), cfg.Allocation,
	)

	// With the heuristic itself created, we can now populate the remainder
	// of the items that the autopilot agent needs to perform its duties.
	self := svr.identityPriv.PubKey()
	pilotCfg := autopilot.Config{
		Self:           self,
		Heuristic:      prefAttachment,
		ChanController: &chanController{svr},
		WalletBalance: func() (btcutil.Amount, error) {
			return svr.cc.wallet.ConfirmedBalance(1, true)
		},
		Graph: autopilot.ChannelGraphFromDatabase(svr.chanDB.ChannelGraph()),
	}

	// Next, we'll fetch the current state of open channels from the
	// database to use as initial state for the auto-pilot agent.
	activeChannels, err := svr.chanDB.FetchAllChannels()
	if err != nil {
		return nil, err
	}
	initialChanState := make([]autopilot.Channel, len(activeChannels))
	for i, channel := range activeChannels {
		initialChanState[i] = autopilot.Channel{
			ChanID:   channel.ShortChanID,
			Capacity: channel.Capacity,
			Node:     autopilot.NewNodeID(channel.IdentityPub),
		}
	}

	// Now that we have all the initial dependencies, we can create the
	// auto-pilot instance itself.
	pilot, err := autopilot.New(pilotCfg, initialChanState)
	if err != nil {
		return nil, err
	}

	// Finally, we'll need to subscribe to two things: incoming
	// transactions that modify the wallet's balance, and also any graph
	// topology updates.
	txnSubscription, err := svr.cc.wallet.SubscribeTransactions()
	if err != nil {
		return nil, err
	}
	graphSubscription, err := svr.chanRouter.SubscribeTopology()
	if err != nil {
		return nil, err
	}

	// We'll launch a goroutine to provide the agent with notifications
	// whenever the balance of the wallet changes.
	svr.wg.Add(2)
	go func() {
		defer txnSubscription.Cancel()
		defer svr.wg.Done()

		for {
			select {
			case txnUpdate := <-txnSubscription.ConfirmedTransactions():
				pilot.OnBalanceChange(txnUpdate.Value)
			case <-svr.quit:
				return
			}
		}

	}()
	go func() {
		defer svr.wg.Done()

		for {
			select {
			// We won't act upon new unconfirmed transaction, as
			// we'll only use confirmed outputs when funding.
			// However, we will still drain this request in order
			// to avoid goroutine leaks, and ensure we promptly
			// read from the channel if available.
			case <-txnSubscription.UnconfirmedTransactions():
			case <-svr.quit:
				return
			}
		}

	}()

	// We'll also launch a goroutine to provide the agent with
	// notifications for when the graph topology controlled by the node
	// changes.
	svr.wg.Add(1)
	go func() {
		defer graphSubscription.Cancel()
		defer svr.wg.Done()

		for {
			select {
			case topChange, ok := <-graphSubscription.TopologyChanges:
				// If the router is shutting down, then we will
				// as well.
				if !ok {
					return
				}

				for _, edgeUpdate := range topChange.ChannelEdgeUpdates {
					// If this isn't an advertisement by
					// the backing lnd node, then we'll
					// continue as we only want to add
					// channels that we've created
					// ourselves.
					if !edgeUpdate.AdvertisingNode.IsEqual(self) {
						continue
					}

					// If this is indeed a channel we
					// opened, then we'll convert it to the
					// autopilot.Channel format, and notify
					// the pilot of the new channel.
					chanNode := autopilot.NewNodeID(
						edgeUpdate.ConnectingNode,
					)
					chanID := lnwire.NewShortChanIDFromInt(
						edgeUpdate.ChanID,
					)
					edge := autopilot.Channel{
						ChanID:   chanID,
						Capacity: edgeUpdate.Capacity,
						Node:     chanNode,
					}
					pilot.OnChannelOpen(edge)
				}

				// For each closed closed channel, we'll obtain
				// the chanID of the closed channel and send it
				// to the pilot.
				for _, chanClose := range topChange.ClosedChannels {
					chanID := lnwire.NewShortChanIDFromInt(
						chanClose.ChanID,
					)

					pilot.OnChannelClose(chanID)
				}

			case <-svr.quit:
				return
			}
		}
	}()

	return pilot, nil
}
<commit_msg>pilot: pass minHtlc = 1 satoshi to OpenChannel<commit_after>package main

import (
	"fmt"
	"net"

	"github.com/davecgh/go-spew/spew"
	"github.com/lightningnetwork/lnd/autopilot"
	"github.com/lightningnetwork/lnd/lnwire"
	"github.com/roasbeef/btcd/btcec"
	"github.com/roasbeef/btcd/wire"
	"github.com/roasbeef/btcutil"
)

// chanController is an implementation of the autopilot.ChannelController
// interface that's backed by a running lnd instance.
type chanController struct {
	server *server
}

// OpenChannel opens a channel to a target peer, with a capacity of the
// specified amount. This function should un-block immediately after the
// funding transaction that marks the channel open has been broadcast.
func (c *chanController) OpenChannel(target *btcec.PublicKey,
	amt btcutil.Amount, addrs []net.Addr) error {

	// We can't establish a channel if no addresses were provided for the
	// peer.
	if len(addrs) == 0 {
		return fmt.Errorf("Unable to create channel w/o an active " +
			"address")
	}

	// First, we'll check if we're already connected to the target peer. If
	// not, then we'll need to establish a connection.
	if _, err := c.server.FindPeer(target); err != nil {
		// TODO(roasbeef): try teach addr

		atplLog.Tracef("Connecting to %x to auto-create channel: ",
			target.SerializeCompressed())

		lnAddr := &lnwire.NetAddress{
			IdentityKey: target,
			ChainNet:    activeNetParams.Net,
		}

		// We'll attempt to successively connect to each of the
		// advertised IP addresses until we've either exhausted the
		// advertised IP addresses, or have made a connection.
		var connected bool
		for _, addr := range addrs {
			// If the address doesn't already have a port, then
			// we'll assume the current default port.
			tcpAddr, ok := addr.(*net.TCPAddr)
			if !ok {
				return fmt.Errorf("TCP address required instead "+
					"have %T", addr)
			}
			if tcpAddr.Port == 0 {
				tcpAddr.Port = defaultPeerPort
			}

			lnAddr.Address = tcpAddr

			// TODO(roasbeef): make perm connection in server after
			// chan open?
			err := c.server.ConnectToPeer(lnAddr, false)
			if err != nil {
				// If we weren't able to connect to the peer,
				// then we'll move onto the next.
				continue
			}

			connected = true
			break
		}

		// If we weren't able to establish a connection at all, then
		// we'll error out.
		if !connected {
			return fmt.Errorf("Unable to connect to %x",
				target.SerializeCompressed())
		}
	}

	// With the connection established, we'll now establish our connection
	// to the target peer, waiting for the first update before we exit.
	feePerWeight, err := c.server.cc.feeEstimator.EstimateFeePerWeight(3)
	if err != nil {
		return err
	}

	// TODO(halseth): make configurable?
	minHtlc := lnwire.NewMSatFromSatoshis(1)

	updateStream, errChan := c.server.OpenChannel(-1, target, amt, 0,
		minHtlc, feePerWeight, false)

	select {
	case err := <-errChan:
		return err
	case <-updateStream:
		return nil
	case <-c.server.quit:
		return nil
	}
}

func (c *chanController) CloseChannel(chanPoint *wire.OutPoint) error {
	return nil
}
func (c *chanController) SpliceIn(chanPoint *wire.OutPoint,
	amt btcutil.Amount) (*autopilot.Channel, error) {
	return nil, nil
}
func (c *chanController) SpliceOut(chanPoint *wire.OutPoint,
	amt btcutil.Amount) (*autopilot.Channel, error) {
	return nil, nil
}

// A compile time assertion to ensure chanController meets the
// autopilot.ChannelController interface.
var _ autopilot.ChannelController = (*chanController)(nil)

// initAutoPilot initializes a new autopilot.Agent instance based on the passed
// configuration struct. All interfaces needed to drive the pilot will be
// registered and launched.
func initAutoPilot(svr *server, cfg *autoPilotConfig) (*autopilot.Agent, error) {
	atplLog.Infof("Instantiating autopilot with cfg: %v", spew.Sdump(cfg))

	// First, we'll create the preferential attachment heuristic,
	// initialized with the passed auto pilot configuration parameters.
	//
	// TODO(roasbeef): switch here to dispatch specified heuristic
	minChanSize := svr.cc.wallet.Cfg.DefaultConstraints.DustLimit * 5
	prefAttachment := autopilot.NewConstrainedPrefAttachment(
		minChanSize, maxFundingAmount,
		uint16(cfg.MaxChannels), cfg.Allocation,
	)

	// With the heuristic itself created, we can now populate the remainder
	// of the items that the autopilot agent needs to perform its duties.
	self := svr.identityPriv.PubKey()
	pilotCfg := autopilot.Config{
		Self:           self,
		Heuristic:      prefAttachment,
		ChanController: &chanController{svr},
		WalletBalance: func() (btcutil.Amount, error) {
			return svr.cc.wallet.ConfirmedBalance(1, true)
		},
		Graph: autopilot.ChannelGraphFromDatabase(svr.chanDB.ChannelGraph()),
	}

	// Next, we'll fetch the current state of open channels from the
	// database to use as initial state for the auto-pilot agent.
	activeChannels, err := svr.chanDB.FetchAllChannels()
	if err != nil {
		return nil, err
	}
	initialChanState := make([]autopilot.Channel, len(activeChannels))
	for i, channel := range activeChannels {
		initialChanState[i] = autopilot.Channel{
			ChanID:   channel.ShortChanID,
			Capacity: channel.Capacity,
			Node:     autopilot.NewNodeID(channel.IdentityPub),
		}
	}

	// Now that we have all the initial dependencies, we can create the
	// auto-pilot instance itself.
	pilot, err := autopilot.New(pilotCfg, initialChanState)
	if err != nil {
		return nil, err
	}

	// Finally, we'll need to subscribe to two things: incoming
	// transactions that modify the wallet's balance, and also any graph
	// topology updates.
	txnSubscription, err := svr.cc.wallet.SubscribeTransactions()
	if err != nil {
		return nil, err
	}
	graphSubscription, err := svr.chanRouter.SubscribeTopology()
	if err != nil {
		return nil, err
	}

	// We'll launch a goroutine to provide the agent with notifications
	// whenever the balance of the wallet changes.
	svr.wg.Add(2)
	go func() {
		defer txnSubscription.Cancel()
		defer svr.wg.Done()

		for {
			select {
			case txnUpdate := <-txnSubscription.ConfirmedTransactions():
				pilot.OnBalanceChange(txnUpdate.Value)
			case <-svr.quit:
				return
			}
		}

	}()
	go func() {
		defer svr.wg.Done()

		for {
			select {
			// We won't act upon new unconfirmed transaction, as
			// we'll only use confirmed outputs when funding.
			// However, we will still drain this request in order
			// to avoid goroutine leaks, and ensure we promptly
			// read from the channel if available.
			case <-txnSubscription.UnconfirmedTransactions():
			case <-svr.quit:
				return
			}
		}

	}()

	// We'll also launch a goroutine to provide the agent with
	// notifications for when the graph topology controlled by the node
	// changes.
	svr.wg.Add(1)
	go func() {
		defer graphSubscription.Cancel()
		defer svr.wg.Done()

		for {
			select {
			case topChange, ok := <-graphSubscription.TopologyChanges:
				// If the router is shutting down, then we will
				// as well.
				if !ok {
					return
				}

				for _, edgeUpdate := range topChange.ChannelEdgeUpdates {
					// If this isn't an advertisement by
					// the backing lnd node, then we'll
					// continue as we only want to add
					// channels that we've created
					// ourselves.
					if !edgeUpdate.AdvertisingNode.IsEqual(self) {
						continue
					}

					// If this is indeed a channel we
					// opened, then we'll convert it to the
					// autopilot.Channel format, and notify
					// the pilot of the new channel.
					chanNode := autopilot.NewNodeID(
						edgeUpdate.ConnectingNode,
					)
					chanID := lnwire.NewShortChanIDFromInt(
						edgeUpdate.ChanID,
					)
					edge := autopilot.Channel{
						ChanID:   chanID,
						Capacity: edgeUpdate.Capacity,
						Node:     chanNode,
					}
					pilot.OnChannelOpen(edge)
				}

				// For each closed closed channel, we'll obtain
				// the chanID of the closed channel and send it
				// to the pilot.
				for _, chanClose := range topChange.ClosedChannels {
					chanID := lnwire.NewShortChanIDFromInt(
						chanClose.ChanID,
					)

					pilot.OnChannelClose(chanID)
				}

			case <-svr.quit:
				return
			}
		}
	}()

	return pilot, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"path"
	"path/filepath"
	"strings"

	"github.com/ryanuber/go-license"
)

const root = "vendor/"

var files []string
var rootPath string
var noLicense = map[string]bool{}

// Response contains license and file info
type Response struct {
	License string
	File    string
}

func getLicense(input chan string, output chan Response) {
	for file := range input {
		l, err := license.NewFromFile(file)
		splitFile := strings.Split(file, "/")
		splitFile = splitFile[1 : len(splitFile)-1]
		file := path.Join(splitFile...)
		if err != nil {
			output <- Response{File: file, License: err.Error()}
		} else {
			output <- Response{File: file, License: l.Type}
		}
	}
}
func checkLicense(path string) bool {
	path = strings.ToUpper(path)
	return strings.Contains(path, "LICENSE") || strings.Contains(path, "COPYING")
}

func walker(filePath string, f os.FileInfo, err error) error {
	if err != nil {
		fmt.Println("No vendor folder found. Aborting..")
		return err
	}

	if !f.IsDir() {
		// checks that a path is the root path and assigns it to rootpath.
		// Determines root path by checking the directory of the first file seen after a change in the previous root path
		if currentDir := path.Dir(filePath); !strings.Contains(currentDir, ".git") && (!strings.HasPrefix(currentDir, rootPath) || rootPath == "") {
			rootPath = currentDir
			noLicense[rootPath] = true
		}
		rawPath := path.Base(filePath)
		if checkLicense(rawPath) {
			//removes current rootpath from no license list once a license is seen in one of the rootpaths subdirectories
			delete(noLicense, rootPath)
			files = append(files, filePath)
		}
	}
	return nil
}

func main() {
	input := make(chan string)
	output := make(chan Response)

	filepath.Walk(root, walker)

	for a := 0; a < 5; a++ {
		go getLicense(input, output)
	}

	if len(files) == 0 { // checks that a license file was gotten
		return
	}

	go func() {
		for _, v := range files {
			input <- v
		}
	}()

	for i := 0; i < len(files); i++ {
		out := <-output
		fmt.Printf("%v =======> %v\n", out.File, out.License)
	}

	for key := range noLicense {
		key = strings.Replace(key, root, "", 1)
		fmt.Printf("Packages without a License file: %v\n", key)
	}
}
<commit_msg>Refactor how package list is generated<commit_after>package main

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"strconv"
	"strings"
	"text/tabwriter"

	"github.com/ryanuber/go-license"
)

const root = "vendor/"

// Response contains license and file info
type response struct {
	License string
	File    string
}

type request struct {
	path        string
	licenseFile string
}

func catch(err error) {
	if err != nil {
		panic(err)
	}
}
func getLicense(input chan request, output chan response, size int) {
	for i := range input {
		file := strings.TrimPrefix(i.path, root)
		if i.licenseFile == "" {
			output <- response{File: file, License: "FILE HAS NO LICENSE"}
		} else {
			l, err := license.NewFromFile(i.licenseFile)
			if err != nil {
				f, err := os.Open(i.licenseFile)
				catch(err)
				dat, err := bufio.NewReader(f).Peek(size)
				catch(err)
				output <- response{File: file, License: "#" + string(dat)}
			} else {
				output <- response{File: file, License: l.Type}
			}
		}
	}
}

func isLicense(fileName string) bool {
	fileName = strings.ToUpper(fileName)
	return strings.Contains(fileName, "LICENSE") || strings.Contains(fileName, "COPYING")
}

func isPackage(filePath string) bool {
	files, err := ioutil.ReadDir(filePath)
	if err != nil {
		return false
	}
	for _, file := range files {
		if file.Name() == ".git" {
			return true
		}
	}
	return false
}

func getLicenseFile(filePath string) string {
	files, err := ioutil.ReadDir(filePath)
	if err != nil {
		return ""
	}
	for _, file := range files {
		if isLicense(file.Name()) {
			return path.Join(filePath, file.Name())
		}
	}
	return ""
}

func getPackageLicenses() map[string]string {
	var licenseInfo = map[string]string{}

	filepath.Walk(root, func(filePath string, f os.FileInfo, err error) error {
		if err != nil {
			fmt.Println("No vendor folder found. Aborting..")
			return err
		}

		if isPackage(filePath) {
			licenseInfo[filePath] = getLicenseFile(filePath)
		} else if isLicense(filePath) && f.Mode().IsRegular() {
			licenseInfo[path.Dir(filePath)] = filePath
		}

		return nil
	})
	return licenseInfo
}

func main() {
	input := make(chan request)
	output := make(chan response)

	packageFiles := getPackageLicenses()

	size := 100
	if len(os.Args) > 1 {
		size, _ = strconv.Atoi(os.Args[1])
	}
	for a := 0; a < 5; a++ {
		go getLicense(input, output, size)
	}

	if len(packageFiles) == 0 { // checks that a license file was gotten
		return
	}

	go func() {
		for k, v := range packageFiles {
			input <- request{
				path:        k,
				licenseFile: v,
			}
		}
	}()
	w := tabwriter.NewWriter(os.Stdout, 1, 4, 2, ' ', 0)
	for i := 0; i < len(packageFiles); i++ {
		out := <-output
		_, err := w.Write([]byte(out.File + "\t" + out.License + "\n"))
		if err != nil {
			panic(err)
		}
	}
	w.Flush()

}
<|endoftext|>


<commit_before>package rabbithole

import (
	"net/url"
)

// TODO: this probably should be fixed in RabbitMQ management plugin
type OsPid string

type NameDescriptionEnabled struct {
	Name        string `json:"name"`
	Description string `json:"description"`
	Enabled     bool   `json:"enabled"`
}

type AuthMechanism NameDescriptionEnabled

type ExchangeType NameDescriptionEnabled

type NameDescriptionVersion struct {
	Name        string `json:"name"`
	Description string `json:"description"`
	Version     string `json:"version"`
}

type ErlangApp NameDescriptionVersion

type NodeInfo struct {
	Name      string `json:"name"`
	NodeType  string `json:"type"`
	IsRunning bool   `json:"running"`
	OsPid     OsPid  `json:"os_pid"`

	FdUsed        int  `json:"fd_used"`
	FdTotal       int  `json:"fd_total"`
	SocketsUsed   int  `json:"sockets_used"`
	SocketsTotal  int  `json:"sockets_total"`
	MemUsed       int  `json:"mem_used"`
	MemLimit      int  `json:"mem_limit"`
	MemAlarm      bool `json:"mem_alarm"`
	DiskFree      int  `json:"disk_free"`
	DiskFreeLimit int  `json:"disk_free_limit"`
	DiskFreeAlarm bool `json:"disk_free_alarm"`

	// Erlang scheduler run queue length
	RunQueueLength  uint32  `json:"run_queue"`
	Processors      uint32  `json:"processors"`
	Uptime          uint32  `json:"uptime"`

	ExchangeTypes  []ExchangeType  `json:"exchange_types"`
	AuthMechanisms []AuthMechanism `json:"auth_mechanisms"`
	ErlangApps     []ErlangApp     `json:"applications"`
	Contexts       []BrokerContext `json:"contexts"`
}

//
// GET /api/nodes
//

func (c *Client) ListNodes() (rec []NodeInfo, err error) {
	req, err := newGETRequest(c, "nodes")
	if err != nil {
		return []NodeInfo{}, err
	}

	if err = executeAndParseRequest(req, &rec); err != nil {
		return nil, err
	}

	return rec, nil
}

//
// GET /api/nodes/{name}
//

// {
//   "partitions": [],
//   "os_pid": "39292",
//   "fd_used": 35,
//   "fd_total": 256,
//   "sockets_used": 4,
//   "sockets_total": 138,
//   "mem_used": 69964432,
//   "mem_limit": 2960660889,
//   "mem_alarm": false,
//   "disk_free_limit": 50000000,
//   "disk_free": 188362731520,
//   "disk_free_alarm": false,
//   "proc_used": 370,
//   "proc_total": 1048576,
//   "statistics_level": "fine",
//   "uptime": 98355255,
//   "run_queue": 0,
//   "processors": 8,
//   "exchange_types": [
//     {
//       "name": "topic",
//       "description": "AMQP topic exchange, as per the AMQP specification",
//       "enabled": true
//     },
//     {
//       "name": "x-consistent-hash",
//       "description": "Consistent Hashing Exchange",
//       "enabled": true
//     },
//     {
//       "name": "fanout",
//       "description": "AMQP fanout exchange, as per the AMQP specification",
//       "enabled": true
//     },
//     {
//       "name": "direct",
//       "description": "AMQP direct exchange, as per the AMQP specification",
//       "enabled": true
//     },
//     {
//       "name": "headers",
//       "description": "AMQP headers exchange, as per the AMQP specification",
//       "enabled": true
//     }
//   ],
//   "auth_mechanisms": [
//     {
//       "name": "AMQPLAIN",
//       "description": "QPid AMQPLAIN mechanism",
//       "enabled": true
//     },
//     {
//       "name": "PLAIN",
//       "description": "SASL PLAIN authentication mechanism",
//       "enabled": true
//     },
//     {
//       "name": "RABBIT-CR-DEMO",
//       "description": "RabbitMQ Demo challenge-response authentication mechanism",
//       "enabled": false
//     }
//   ],
//   "applications": [
//     {
//       "name": "amqp_client",
//       "description": "RabbitMQ AMQP Client",
//       "version": "3.2.0"
//     },
//     {
//       "name": "asn1",
//       "description": "The Erlang ASN1 compiler version 2.0.3",
//       "version": "2.0.3"
//     },
//     {
//       "name": "cowboy",
//       "description": "Small, fast, modular HTTP server.",
//       "version": "0.5.0-rmq3.2.0-git4b93c2d"
//     },
//     {
//       "name": "crypto",
//       "description": "CRYPTO version 2",
//       "version": "3.1"
//     },
//     {
//       "name": "inets",
//       "description": "INETS  CXC 138 49",
//       "version": "5.9.6"
//     },
//     {
//       "name": "kernel",
//       "description": "ERTS  CXC 138 10",
//       "version": "2.16.3"
//     },
//     {
//       "name": "mnesia",
//       "description": "MNESIA  CXC 138 12",
//       "version": "4.10"
//     },
//     {
//       "name": "mochiweb",
//       "description": "MochiMedia Web Server",
//       "version": "2.7.0-rmq3.2.0-git680dba8"
//     },
//     {
//       "name": "os_mon",
//       "description": "CPO  CXC 138 46",
//       "version": "2.2.13"
//     },
//     {
//       "name": "public_key",
//       "description": "Public key infrastructure",
//       "version": "0.20"
//     },
//     {
//       "name": "rabbit",
//       "description": "RabbitMQ",
//       "version": "3.2.0"
//     },
//     {
//       "name": "rabbitmq_consistent_hash_exchange",
//       "description": "Consistent Hash Exchange Type",
//       "version": "3.2.0"
//     },
//     {
//       "name": "rabbitmq_management",
//       "description": "RabbitMQ Management Console",
//       "version": "3.2.0"
//     },
//     {
//       "name": "rabbitmq_management_agent",
//       "description": "RabbitMQ Management Agent",
//       "version": "3.2.0"
//     },
//     {
//       "name": "rabbitmq_mqtt",
//       "description": "RabbitMQ MQTT Adapter",
//       "version": "3.2.0"
//     },
//     {
//       "name": "rabbitmq_shovel",
//       "description": "Data Shovel for RabbitMQ",
//       "version": "3.2.0"
//     },
//     {
//       "name": "rabbitmq_shovel_management",
//       "description": "Shovel Status",
//       "version": "3.2.0"
//     },
//     {
//       "name": "rabbitmq_stomp",
//       "description": "Embedded Rabbit Stomp Adapter",
//       "version": "3.2.0"
//     },
//     {
//       "name": "rabbitmq_web_dispatch",
//       "description": "RabbitMQ Web Dispatcher",
//       "version": "3.2.0"
//     },
//     {
//       "name": "rabbitmq_web_stomp",
//       "description": "Rabbit WEB-STOMP - WebSockets to Stomp adapter",
//       "version": "3.2.0"
//     },
//     {
//       "name": "sasl",
//       "description": "SASL  CXC 138 11",
//       "version": "2.3.3"
//     },
//     {
//       "name": "sockjs",
//       "description": "SockJS",
//       "version": "0.3.4-rmq3.2.0-git3132eb9"
//     },
//     {
//       "name": "ssl",
//       "description": "Erlang\/OTP SSL application",
//       "version": "5.3.1"
//     },
//     {
//       "name": "stdlib",
//       "description": "ERTS  CXC 138 10",
//       "version": "1.19.3"
//     },
//     {
//       "name": "webmachine",
//       "description": "webmachine",
//       "version": "1.10.3-rmq3.2.0-gite9359c7"
//     },
//     {
//       "name": "xmerl",
//       "description": "XML parser",
//       "version": "1.3.4"
//     }
//   ],
//   "contexts": [
//     {
//       "description": "Redirect to port 15672",
//       "path": "\/",
//       "port": 55672,
//       "ignore_in_use": true
//     },
//     {
//       "description": "RabbitMQ Management",
//       "path": "\/",
//       "port": 15672
//     }
//   ],
//   "name": "rabbit@mercurio",
//   "type": "disc",
//   "running": true
// }

func (c *Client) GetNode(name string) (rec *NodeInfo, err error) {
	req, err := newGETRequest(c, "nodes/"+url.QueryEscape(name))
	if err != nil {
		return nil, err
	}

	if err = executeAndParseRequest(req, &rec); err != nil {
		return nil, err
	}

	return rec, nil
}
<commit_msg>Changed node uptime in nodeinfo struct to uint64<commit_after>package rabbithole

import (
	"net/url"
)

// TODO: this probably should be fixed in RabbitMQ management plugin
type OsPid string

type NameDescriptionEnabled struct {
	Name        string `json:"name"`
	Description string `json:"description"`
	Enabled     bool   `json:"enabled"`
}

type AuthMechanism NameDescriptionEnabled

type ExchangeType NameDescriptionEnabled

type NameDescriptionVersion struct {
	Name        string `json:"name"`
	Description string `json:"description"`
	Version     string `json:"version"`
}

type ErlangApp NameDescriptionVersion

type NodeInfo struct {
	Name      string `json:"name"`
	NodeType  string `json:"type"`
	IsRunning bool   `json:"running"`
	OsPid     OsPid  `json:"os_pid"`

	FdUsed        int  `json:"fd_used"`
	FdTotal       int  `json:"fd_total"`
	SocketsUsed   int  `json:"sockets_used"`
	SocketsTotal  int  `json:"sockets_total"`
	MemUsed       int  `json:"mem_used"`
	MemLimit      int  `json:"mem_limit"`
	MemAlarm      bool `json:"mem_alarm"`
	DiskFree      int  `json:"disk_free"`
	DiskFreeLimit int  `json:"disk_free_limit"`
	DiskFreeAlarm bool `json:"disk_free_alarm"`

	// Erlang scheduler run queue length
	RunQueueLength uint32 `json:"run_queue"`
	Processors     uint32 `json:"processors"`
	Uptime         uint64 `json:"uptime"`

	ExchangeTypes  []ExchangeType  `json:"exchange_types"`
	AuthMechanisms []AuthMechanism `json:"auth_mechanisms"`
	ErlangApps     []ErlangApp     `json:"applications"`
	Contexts       []BrokerContext `json:"contexts"`
}

//
// GET /api/nodes
//

func (c *Client) ListNodes() (rec []NodeInfo, err error) {
	req, err := newGETRequest(c, "nodes")
	if err != nil {
		return []NodeInfo{}, err
	}

	if err = executeAndParseRequest(req, &rec); err != nil {
		return nil, err
	}

	return rec, nil
}

//
// GET /api/nodes/{name}
//

// {
//   "partitions": [],
//   "os_pid": "39292",
//   "fd_used": 35,
//   "fd_total": 256,
//   "sockets_used": 4,
//   "sockets_total": 138,
//   "mem_used": 69964432,
//   "mem_limit": 2960660889,
//   "mem_alarm": false,
//   "disk_free_limit": 50000000,
//   "disk_free": 188362731520,
//   "disk_free_alarm": false,
//   "proc_used": 370,
//   "proc_total": 1048576,
//   "statistics_level": "fine",
//   "uptime": 98355255,
//   "run_queue": 0,
//   "processors": 8,
//   "exchange_types": [
//     {
//       "name": "topic",
//       "description": "AMQP topic exchange, as per the AMQP specification",
//       "enabled": true
//     },
//     {
//       "name": "x-consistent-hash",
//       "description": "Consistent Hashing Exchange",
//       "enabled": true
//     },
//     {
//       "name": "fanout",
//       "description": "AMQP fanout exchange, as per the AMQP specification",
//       "enabled": true
//     },
//     {
//       "name": "direct",
//       "description": "AMQP direct exchange, as per the AMQP specification",
//       "enabled": true
//     },
//     {
//       "name": "headers",
//       "description": "AMQP headers exchange, as per the AMQP specification",
//       "enabled": true
//     }
//   ],
//   "auth_mechanisms": [
//     {
//       "name": "AMQPLAIN",
//       "description": "QPid AMQPLAIN mechanism",
//       "enabled": true
//     },
//     {
//       "name": "PLAIN",
//       "description": "SASL PLAIN authentication mechanism",
//       "enabled": true
//     },
//     {
//       "name": "RABBIT-CR-DEMO",
//       "description": "RabbitMQ Demo challenge-response authentication mechanism",
//       "enabled": false
//     }
//   ],
//   "applications": [
//     {
//       "name": "amqp_client",
//       "description": "RabbitMQ AMQP Client",
//       "version": "3.2.0"
//     },
//     {
//       "name": "asn1",
//       "description": "The Erlang ASN1 compiler version 2.0.3",
//       "version": "2.0.3"
//     },
//     {
//       "name": "cowboy",
//       "description": "Small, fast, modular HTTP server.",
//       "version": "0.5.0-rmq3.2.0-git4b93c2d"
//     },
//     {
//       "name": "crypto",
//       "description": "CRYPTO version 2",
//       "version": "3.1"
//     },
//     {
//       "name": "inets",
//       "description": "INETS  CXC 138 49",
//       "version": "5.9.6"
//     },
//     {
//       "name": "kernel",
//       "description": "ERTS  CXC 138 10",
//       "version": "2.16.3"
//     },
//     {
//       "name": "mnesia",
//       "description": "MNESIA  CXC 138 12",
//       "version": "4.10"
//     },
//     {
//       "name": "mochiweb",
//       "description": "MochiMedia Web Server",
//       "version": "2.7.0-rmq3.2.0-git680dba8"
//     },
//     {
//       "name": "os_mon",
//       "description": "CPO  CXC 138 46",
//       "version": "2.2.13"
//     },
//     {
//       "name": "public_key",
//       "description": "Public key infrastructure",
//       "version": "0.20"
//     },
//     {
//       "name": "rabbit",
//       "description": "RabbitMQ",
//       "version": "3.2.0"
//     },
//     {
//       "name": "rabbitmq_consistent_hash_exchange",
//       "description": "Consistent Hash Exchange Type",
//       "version": "3.2.0"
//     },
//     {
//       "name": "rabbitmq_management",
//       "description": "RabbitMQ Management Console",
//       "version": "3.2.0"
//     },
//     {
//       "name": "rabbitmq_management_agent",
//       "description": "RabbitMQ Management Agent",
//       "version": "3.2.0"
//     },
//     {
//       "name": "rabbitmq_mqtt",
//       "description": "RabbitMQ MQTT Adapter",
//       "version": "3.2.0"
//     },
//     {
//       "name": "rabbitmq_shovel",
//       "description": "Data Shovel for RabbitMQ",
//       "version": "3.2.0"
//     },
//     {
//       "name": "rabbitmq_shovel_management",
//       "description": "Shovel Status",
//       "version": "3.2.0"
//     },
//     {
//       "name": "rabbitmq_stomp",
//       "description": "Embedded Rabbit Stomp Adapter",
//       "version": "3.2.0"
//     },
//     {
//       "name": "rabbitmq_web_dispatch",
//       "description": "RabbitMQ Web Dispatcher",
//       "version": "3.2.0"
//     },
//     {
//       "name": "rabbitmq_web_stomp",
//       "description": "Rabbit WEB-STOMP - WebSockets to Stomp adapter",
//       "version": "3.2.0"
//     },
//     {
//       "name": "sasl",
//       "description": "SASL  CXC 138 11",
//       "version": "2.3.3"
//     },
//     {
//       "name": "sockjs",
//       "description": "SockJS",
//       "version": "0.3.4-rmq3.2.0-git3132eb9"
//     },
//     {
//       "name": "ssl",
//       "description": "Erlang\/OTP SSL application",
//       "version": "5.3.1"
//     },
//     {
//       "name": "stdlib",
//       "description": "ERTS  CXC 138 10",
//       "version": "1.19.3"
//     },
//     {
//       "name": "webmachine",
//       "description": "webmachine",
//       "version": "1.10.3-rmq3.2.0-gite9359c7"
//     },
//     {
//       "name": "xmerl",
//       "description": "XML parser",
//       "version": "1.3.4"
//     }
//   ],
//   "contexts": [
//     {
//       "description": "Redirect to port 15672",
//       "path": "\/",
//       "port": 55672,
//       "ignore_in_use": true
//     },
//     {
//       "description": "RabbitMQ Management",
//       "path": "\/",
//       "port": 15672
//     }
//   ],
//   "name": "rabbit@mercurio",
//   "type": "disc",
//   "running": true
// }

func (c *Client) GetNode(name string) (rec *NodeInfo, err error) {
	req, err := newGETRequest(c, "nodes/"+url.QueryEscape(name))
	if err != nil {
		return nil, err
	}

	if err = executeAndParseRequest(req, &rec); err != nil {
		return nil, err
	}

	return rec, nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Serge Gebhardt. All rights reserved.
//
// Use of this source code is governed by the ISC
// license that can be found in the LICENSE file.

package acd

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"net/url"
	"reflect"

	"github.com/google/go-querystring/query"
)

// NodesService provides access to the nodes in the Amazon Cloud Drive API.
//
// See: https://developer.amazon.com/public/apis/experience/cloud-drive/content/nodes
type NodesService struct {
	client *Client
}

// Gets the root folder of the Amazon Cloud Drive.
func (s *NodesService) GetRoot() (*Folder, *http.Response, error) {
	opts := &NodeListOptions{Filters: "kind:FOLDER AND isRoot:true"}

	roots, resp, err := s.GetNodes(opts)
	if err != nil {
		return nil, resp, err
	}

	if len(roots) < 1 {
		return nil, resp, errors.New("No root found")
	}

	return &Folder{roots[0]}, resp, nil
}

// Gets the list of all nodes.
func (s *NodesService) GetAllNodes(opts *NodeListOptions) ([]*Node, *http.Response, error) {
	return s.listAllNodes("nodes", opts)
}

// Gets a list of nodes, up until the limit (either default or the one set in opts).
func (s *NodesService) GetNodes(opts *NodeListOptions) ([]*Node, *http.Response, error) {
	return s.listNodes("nodes", opts)
}

func (s *NodesService) listAllNodes(url string, opts *NodeListOptions) ([]*Node, *http.Response, error) {
	// Need opts to maintain state (NodeListOptions.reachedEnd)
	if opts == nil {
		opts = &NodeListOptions{}
	}

	result := make([]*Node, 0, 200)

	for {
		nodes, resp, err := s.listNodes(url, opts)
		if err != nil {
			return result, resp, err
		}
		if nodes == nil {
			break
		}

		result = append(result, nodes...)
	}

	return result, nil, nil
}

func (s *NodesService) listNodes(url string, opts *NodeListOptions) ([]*Node, *http.Response, error) {
	if opts != nil && opts.reachedEnd {
		return nil, nil, nil
	}

	url, err := addOptions(url, opts)
	if err != nil {
		return nil, nil, err
	}

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

	nodeList := &nodeListInternal{}
	resp, err := s.client.Do(req, nodeList)
	if err != nil {
		return nil, resp, err
	}

	if opts != nil {
		if nodeList.NextToken != nil {
			opts.StartToken = *nodeList.NextToken
		} else {
			opts.reachedEnd = true
		}
	}

	nodes := nodeList.Data
	for _, node := range nodes {
		node.service = s
	}

	return nodes, resp, nil
}

type nodeListInternal struct {
	Count     *uint64 `json:"count"`
	NextToken *string `json:"nextToken"`
	Data      []*Node `json:"data"`
}

// Node represents a digital asset on the Amazon Cloud Drive, including files
// and folders, in a parent-child relationship. A node contains only metadata
// (e.g. folder) or it contains metadata and content (e.g. file).
type Node struct {
	Id                *string `json:"id"`
	Name              *string `json:"name"`
	Kind              *string `json:"kind"`
	ContentProperties *struct {
		Size *uint64 `json:"size"`
	} `json:"contentProperties"`

	service *NodesService
}

// IsFile returns whether the node represents a file.
func (n *Node) IsFile() bool {
	return n.Kind != nil && *n.Kind == "FILE"
}

// IsFolder returns whether the node represents a folder.
func (n *Node) IsFolder() bool {
	return n.Kind != nil && *n.Kind == "FOLDER"
}

// Typed returns the Node typed as either File or Folder.
func (n *Node) Typed() interface{} {
	if n.IsFile() {
		return &File{n}
	}

	if n.IsFolder() {
		return &Folder{n}
	}

	return n
}

// GetMetadata return a pretty-printed JSON string of the node's metadata
func (n *Node) GetMetadata() (string, error) {
	url := fmt.Sprintf("nodes/%s?tempLink=true", *n.Id)
	req, err := n.service.client.NewMetadataRequest("GET", url, nil)
	if err != nil {
		return "", err
	}

	buf := &bytes.Buffer{}
	_, err = n.service.client.Do(req, buf)
	if err != nil {
		return "", err
	}

	md := &bytes.Buffer{}
	err = json.Indent(md, buf.Bytes(), "", "    ")
	if err != nil {
		return "", err
	}

	return md.String(), nil
}

// File represents a file on the Amazon Cloud Drive.
type File struct {
	*Node
}

// Folder represents a folder on the Amazon Cloud Drive.
type Folder struct {
	*Node
}

// Gets the list of all children.
func (f *Folder) GetAllChildren(opts *NodeListOptions) ([]*Node, *http.Response, error) {
	url := fmt.Sprintf("nodes/%s/children", *f.Id)
	return f.service.listAllNodes(url, opts)
}

// Gets a list of children, up until the limit (either default or the one set in opts).
func (f *Folder) GetChildren(opts *NodeListOptions) ([]*Node, *http.Response, error) {
	url := fmt.Sprintf("nodes/%s/children", *f.Id)
	return f.service.listNodes(url, opts)
}

// Gets the subfolder by name. It is an error if not exactly one subfolder is found.
func (f *Folder) GetFolder(name string) (*Folder, *http.Response, error) {
	n, resp, err := f.GetNode(name)
	if err != nil {
		return nil, resp, err
	}

	res, ok := n.Typed().(*Folder)
	if !ok {
		err := errors.New(fmt.Sprintf("Node '%s' is not a folder", name))
		return nil, resp, err
	}

	return res, resp, nil
}

// Gets the file by name. It is an error if not exactly one file is found.
func (f *Folder) GetFile(name string) (*File, *http.Response, error) {
	n, resp, err := f.GetNode(name)
	if err != nil {
		return nil, resp, err
	}

	res, ok := n.Typed().(*File)
	if !ok {
		err := errors.New(fmt.Sprintf("Node '%s' is not a file", name))
		return nil, resp, err
	}

	return res, resp, nil
}

// Gets the node by name. It is an error if not exactly one node is found.
func (f *Folder) GetNode(name string) (*Node, *http.Response, error) {
	filter := fmt.Sprintf("parents:\"%v\" AND name:\"%s\"", *f.Id, name)
	opts := &NodeListOptions{Filters: filter}

	nodes, resp, err := f.service.GetNodes(opts)
	if err != nil {
		return nil, resp, err
	}

	if len(nodes) < 1 {
		err := errors.New(fmt.Sprintf("No node '%s' found", name))
		return nil, resp, err
	}
	if len(nodes) > 1 {
		err := errors.New(fmt.Sprintf("Too many nodes '%s' found (%v)", name, len(nodes)))
		return nil, resp, err
	}

	return nodes[0], resp, nil
}

// WalkNodes walks the given node hierarchy, getting each node along the way, and returns
// the deepest node. If an error occurs, returns the furthest successful node and the list
// of HTTP responses.
func (f *Folder) WalkNodes(names ...string) (*Node, []*http.Response, error) {
	resps := make([]*http.Response, 0, len(names))

	if len(names) == 0 {
		return f.Node, resps, nil
	}

	// process each node except the last one
	fp := f
	for _, name := range names[:len(names)-1] {
		fn, resp, err := fp.GetFolder(name)
		resps = append(resps, resp)
		if err != nil {
			return fp.Node, resps, err
		}

		fp = fn
	}

	// process the last node
	nl, resp, err := fp.GetNode(names[len(names)-1])
	resps = append(resps, resp)
	if err != nil {
		return fp.Node, resps, err
	}

	return nl, resps, nil
}

// NodeListOptions holds the options when getting a list of nodes, such as the filter,
// sorting and pagination.
type NodeListOptions struct {
	Limit   uint   `url:"limit,omitempty"`
	Filters string `url:"filters,omitempty"`
	Sort    string `url:"sort,omitempty"`

	// Token where to start for next page (internal)
	StartToken string `url:"startToken,omitempty"`
	reachedEnd bool
}

// addOptions adds the parameters in opts as URL query parameters to s.  opts
// must be a struct whose fields may contain "url" tags.
func addOptions(s string, opts interface{}) (string, error) {
	v := reflect.ValueOf(opts)
	if v.Kind() == reflect.Ptr && v.IsNil() {
		return s, nil
	}

	u, err := url.Parse(s)
	if err != nil {
		return s, err
	}

	qs, err := query.Values(opts)
	if err != nil {
		return s, err
	}

	u.RawQuery = qs.Encode()
	return u.String(), nil
}
<commit_msg>Add support to download files<commit_after>// Copyright (c) 2015 Serge Gebhardt. All rights reserved.
//
// Use of this source code is governed by the ISC
// license that can be found in the LICENSE file.

package acd

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"net/url"
	"os"
	"reflect"

	"github.com/google/go-querystring/query"
)

// NodesService provides access to the nodes in the Amazon Cloud Drive API.
//
// See: https://developer.amazon.com/public/apis/experience/cloud-drive/content/nodes
type NodesService struct {
	client *Client
}

// Gets the root folder of the Amazon Cloud Drive.
func (s *NodesService) GetRoot() (*Folder, *http.Response, error) {
	opts := &NodeListOptions{Filters: "kind:FOLDER AND isRoot:true"}

	roots, resp, err := s.GetNodes(opts)
	if err != nil {
		return nil, resp, err
	}

	if len(roots) < 1 {
		return nil, resp, errors.New("No root found")
	}

	return &Folder{roots[0]}, resp, nil
}

// Gets the list of all nodes.
func (s *NodesService) GetAllNodes(opts *NodeListOptions) ([]*Node, *http.Response, error) {
	return s.listAllNodes("nodes", opts)
}

// Gets a list of nodes, up until the limit (either default or the one set in opts).
func (s *NodesService) GetNodes(opts *NodeListOptions) ([]*Node, *http.Response, error) {
	return s.listNodes("nodes", opts)
}

func (s *NodesService) listAllNodes(url string, opts *NodeListOptions) ([]*Node, *http.Response, error) {
	// Need opts to maintain state (NodeListOptions.reachedEnd)
	if opts == nil {
		opts = &NodeListOptions{}
	}

	result := make([]*Node, 0, 200)

	for {
		nodes, resp, err := s.listNodes(url, opts)
		if err != nil {
			return result, resp, err
		}
		if nodes == nil {
			break
		}

		result = append(result, nodes...)
	}

	return result, nil, nil
}

func (s *NodesService) listNodes(url string, opts *NodeListOptions) ([]*Node, *http.Response, error) {
	if opts != nil && opts.reachedEnd {
		return nil, nil, nil
	}

	url, err := addOptions(url, opts)
	if err != nil {
		return nil, nil, err
	}

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

	nodeList := &nodeListInternal{}
	resp, err := s.client.Do(req, nodeList)
	if err != nil {
		return nil, resp, err
	}

	if opts != nil {
		if nodeList.NextToken != nil {
			opts.StartToken = *nodeList.NextToken
		} else {
			opts.reachedEnd = true
		}
	}

	nodes := nodeList.Data
	for _, node := range nodes {
		node.service = s
	}

	return nodes, resp, nil
}

type nodeListInternal struct {
	Count     *uint64 `json:"count"`
	NextToken *string `json:"nextToken"`
	Data      []*Node `json:"data"`
}

// Node represents a digital asset on the Amazon Cloud Drive, including files
// and folders, in a parent-child relationship. A node contains only metadata
// (e.g. folder) or it contains metadata and content (e.g. file).
type Node struct {
	Id                *string `json:"id"`
	Name              *string `json:"name"`
	Kind              *string `json:"kind"`
	ContentProperties *struct {
		Size *uint64 `json:"size"`
	} `json:"contentProperties"`

	service *NodesService
}

// IsFile returns whether the node represents a file.
func (n *Node) IsFile() bool {
	return n.Kind != nil && *n.Kind == "FILE"
}

// IsFolder returns whether the node represents a folder.
func (n *Node) IsFolder() bool {
	return n.Kind != nil && *n.Kind == "FOLDER"
}

// Typed returns the Node typed as either File or Folder.
func (n *Node) Typed() interface{} {
	if n.IsFile() {
		return &File{n}
	}

	if n.IsFolder() {
		return &Folder{n}
	}

	return n
}

// GetMetadata return a pretty-printed JSON string of the node's metadata
func (n *Node) GetMetadata() (string, error) {
	url := fmt.Sprintf("nodes/%s?tempLink=true", *n.Id)
	req, err := n.service.client.NewMetadataRequest("GET", url, nil)
	if err != nil {
		return "", err
	}

	buf := &bytes.Buffer{}
	_, err = n.service.client.Do(req, buf)
	if err != nil {
		return "", err
	}

	md := &bytes.Buffer{}
	err = json.Indent(md, buf.Bytes(), "", "    ")
	if err != nil {
		return "", err
	}

	return md.String(), nil
}

// File represents a file on the Amazon Cloud Drive.
type File struct {
	*Node
}

// Download fetches the content of file f and stores it into the file pointed
// to by path. Errors if the file at path already exists. Does not create the
// intermediate directories in path.
func (f *File) Download(path string) (*http.Response, error) {
	url := fmt.Sprintf("nodes/%s/content", *f.Id)
	req, err := f.service.client.NewContentRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}

	out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666)
	if err != nil {
		return nil, err
	}
	defer out.Close()

	resp, err := f.service.client.Do(req, out)
	return resp, err
}

// Folder represents a folder on the Amazon Cloud Drive.
type Folder struct {
	*Node
}

// Gets the list of all children.
func (f *Folder) GetAllChildren(opts *NodeListOptions) ([]*Node, *http.Response, error) {
	url := fmt.Sprintf("nodes/%s/children", *f.Id)
	return f.service.listAllNodes(url, opts)
}

// Gets a list of children, up until the limit (either default or the one set in opts).
func (f *Folder) GetChildren(opts *NodeListOptions) ([]*Node, *http.Response, error) {
	url := fmt.Sprintf("nodes/%s/children", *f.Id)
	return f.service.listNodes(url, opts)
}

// Gets the subfolder by name. It is an error if not exactly one subfolder is found.
func (f *Folder) GetFolder(name string) (*Folder, *http.Response, error) {
	n, resp, err := f.GetNode(name)
	if err != nil {
		return nil, resp, err
	}

	res, ok := n.Typed().(*Folder)
	if !ok {
		err := errors.New(fmt.Sprintf("Node '%s' is not a folder", name))
		return nil, resp, err
	}

	return res, resp, nil
}

// Gets the file by name. It is an error if not exactly one file is found.
func (f *Folder) GetFile(name string) (*File, *http.Response, error) {
	n, resp, err := f.GetNode(name)
	if err != nil {
		return nil, resp, err
	}

	res, ok := n.Typed().(*File)
	if !ok {
		err := errors.New(fmt.Sprintf("Node '%s' is not a file", name))
		return nil, resp, err
	}

	return res, resp, nil
}

// Gets the node by name. It is an error if not exactly one node is found.
func (f *Folder) GetNode(name string) (*Node, *http.Response, error) {
	filter := fmt.Sprintf("parents:\"%v\" AND name:\"%s\"", *f.Id, name)
	opts := &NodeListOptions{Filters: filter}

	nodes, resp, err := f.service.GetNodes(opts)
	if err != nil {
		return nil, resp, err
	}

	if len(nodes) < 1 {
		err := errors.New(fmt.Sprintf("No node '%s' found", name))
		return nil, resp, err
	}
	if len(nodes) > 1 {
		err := errors.New(fmt.Sprintf("Too many nodes '%s' found (%v)", name, len(nodes)))
		return nil, resp, err
	}

	return nodes[0], resp, nil
}

// WalkNodes walks the given node hierarchy, getting each node along the way, and returns
// the deepest node. If an error occurs, returns the furthest successful node and the list
// of HTTP responses.
func (f *Folder) WalkNodes(names ...string) (*Node, []*http.Response, error) {
	resps := make([]*http.Response, 0, len(names))

	if len(names) == 0 {
		return f.Node, resps, nil
	}

	// process each node except the last one
	fp := f
	for _, name := range names[:len(names)-1] {
		fn, resp, err := fp.GetFolder(name)
		resps = append(resps, resp)
		if err != nil {
			return fp.Node, resps, err
		}

		fp = fn
	}

	// process the last node
	nl, resp, err := fp.GetNode(names[len(names)-1])
	resps = append(resps, resp)
	if err != nil {
		return fp.Node, resps, err
	}

	return nl, resps, nil
}

// NodeListOptions holds the options when getting a list of nodes, such as the filter,
// sorting and pagination.
type NodeListOptions struct {
	Limit   uint   `url:"limit,omitempty"`
	Filters string `url:"filters,omitempty"`
	Sort    string `url:"sort,omitempty"`

	// Token where to start for next page (internal)
	StartToken string `url:"startToken,omitempty"`
	reachedEnd bool
}

// addOptions adds the parameters in opts as URL query parameters to s.  opts
// must be a struct whose fields may contain "url" tags.
func addOptions(s string, opts interface{}) (string, error) {
	v := reflect.ValueOf(opts)
	if v.Kind() == reflect.Ptr && v.IsNil() {
		return s, nil
	}

	u, err := url.Parse(s)
	if err != nil {
		return s, err
	}

	qs, err := query.Values(opts)
	if err != nil {
		return s, err
	}

	u.RawQuery = qs.Encode()
	return u.String(), nil
}
<|endoftext|>