<commit_before>// Copyright 2015 Marc-Antoine Ruel. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

package checks

import (
	"io/ioutil"
	"os"
	"testing"

	"github.com/maruel/pre-commit-go/checks/definitions"
	"github.com/maruel/pre-commit-go/internal"
	"github.com/maruel/ut"
)

func TestCoverageGlobal(t *testing.T) {
	t.Parallel()
	if testing.Short() {
		t.SkipNow()
	}
	td, err := ioutil.TempDir("", "pre-commit-go")
	ut.AssertEqual(t, nil, err)
	defer func() {
		if err := internal.RemoveAll(td); err != nil {
			t.Fail()
		}
	}()
	change := setup(t, td, coverageFiles)

	c := &Coverage{
		UseGlobalInference: true,
		UseCoveralls:       false,
		Global: definitions.CoverageSettings{
			MinCoverage: 50,
			MaxCoverage: 100,
		},
		PerDirDefault: definitions.CoverageSettings{
			MinCoverage: 50,
			MaxCoverage: 100,
		},
		PerDir: map[string]*definitions.CoverageSettings{},
	}
	profile, err := c.RunProfile(change)
	ut.AssertEqual(t, nil, err)
	ut.AssertEqual(t, 55.555555555555555, profile.CoveragePercent())
	ut.AssertEqual(t, 2, profile.PartiallyCoveredFuncs())
	expected := CoverageProfile{
		{
			Source:    "foo.go",
			Line:      2,
			SourceRef: "foo.go:2",
			Name:      "Foo",
			Count:     1,
			Total:     1,
			Percent:   100,
		},
		{
			Source:    "bar/bar.go",
			Line:      2,
			SourceRef: "bar/bar.go:2",
			Name:      "Bar",
			Count:     2,
			Total:     4,
			Percent:   50,
		},
		{
			Source:    "bar/bar.go",
			Line:      10,
			SourceRef: "bar/bar.go:10",
			Name:      "Baz",
			Count:     2,
			Total:     4,
			Percent:   50,
		},
	}
	ut.AssertEqual(t, expected, profile)

	expected = CoverageProfile{
		{
			Source:    "bar.go",
			Line:      2,
			SourceRef: "bar/bar.go:2",
			Name:      "Bar",
			Count:     2,
			Total:     4,
			Percent:   50,
		},
		{
			Source:    "bar.go",
			Line:      10,
			SourceRef: "bar/bar.go:10",
			Name:      "Baz",
			Count:     2,
			Total:     4,
			Percent:   50,
		},
	}
	ut.AssertEqual(t, expected, profile.Subset("bar"))

	expected = CoverageProfile{
		{
			Source:    "foo.go",
			Line:      2,
			SourceRef: "foo.go:2",
			Name:      "Foo",
			Count:     1,
			Total:     1,
			Percent:   100,
		},
	}
	ut.AssertEqual(t, expected, profile.Subset("."))
}

func TestCoverageLocal(t *testing.T) {
	t.Parallel()
	if testing.Short() {
		t.SkipNow()
	}
	td, err := ioutil.TempDir("", "pre-commit-go")
	ut.AssertEqual(t, nil, err)
	defer func() {
		if err := internal.RemoveAll(td); err != nil {
			t.Fail()
		}
	}()
	change := setup(t, td, coverageFiles)

	c := &Coverage{
		UseGlobalInference: false,
		UseCoveralls:       false,
		Global: definitions.CoverageSettings{
			MinCoverage: 50,
			MaxCoverage: 100,
		},
		PerDirDefault: definitions.CoverageSettings{
			MinCoverage: 50,
			MaxCoverage: 100,
		},
		PerDir: map[string]*definitions.CoverageSettings{},
	}
	profile, err := c.RunProfile(change)
	ut.AssertEqual(t, nil, err)
	ut.AssertEqual(t, 55.555555555555555, profile.CoveragePercent())
	ut.AssertEqual(t, 2, profile.PartiallyCoveredFuncs())
	expected := CoverageProfile{
		{
			Source:    "foo.go",
			Line:      2,
			SourceRef: "foo.go:2",
			Name:      "Foo",
			Count:     1,
			Total:     1,
			Percent:   100,
		},
		{
			Source:    "bar/bar.go",
			Line:      2,
			SourceRef: "bar/bar.go:2",
			Name:      "Bar",
			Count:     2,
			Total:     4,
			Percent:   50,
		},
		{
			Source:    "bar/bar.go",
			Line:      10,
			SourceRef: "bar/bar.go:10",
			Name:      "Baz",
			Count:     2,
			Total:     4,
			Percent:   50,
		},
	}
	ut.AssertEqual(t, expected, profile)

	expected = CoverageProfile{
		{
			Source:    "bar.go",
			Line:      2,
			SourceRef: "bar/bar.go:2",
			Name:      "Bar",
			Count:     2,
			Total:     4,
			Percent:   50,
		},
		{
			Source:    "bar.go",
			Line:      10,
			SourceRef: "bar/bar.go:10",
			Name:      "Baz",
			Count:     2,
			Total:     4,
			Percent:   50,
		},
	}
	ut.AssertEqual(t, expected, profile.Subset("bar"))

	ut.AssertEqual(t, nil, c.Run(change))
}

func TestCoveragePrerequisites(t *testing.T) {
	// This test can't be parallel.
	if !IsContinuousIntegration() {
		old := os.Getenv("CI")
		defer os.Setenv("CI", old)
		os.Setenv("CI", "true")
		ut.AssertEqual(t, true, IsContinuousIntegration())
	}
	c := Coverage{UseCoveralls: true}
	ut.AssertEqual(t, 1, len(c.GetPrerequisites()))
}

func TestCoverageEmpty(t *testing.T) {
	t.Parallel()
	ut.AssertEqual(t, 0., CoverageProfile{}.CoveragePercent())
	c := Coverage{PerDir: map[string]*definitions.CoverageSettings{"foo": nil}}
	ut.AssertEqual(t, &definitions.CoverageSettings{}, c.SettingsForPkg("foo"))
}

var coverageFiles = map[string]string{
	"foo.go": `package foo
func Foo() int {
  return 1
}
`,
	"foo_test.go": `package foo
import "testing"
func TestSuccess(t *testing.T) {
  if Foo() != 1 {
    t.Fail()
  }
}
`,
	"bar/bar.go": `package bar
func Bar(i int) int {
	if i == 2 {
		return 2
	}
	i++
	return i
}

func Baz(i int) int {
	if i == 2 {
		return 2
	}
	i++
	return i
}
`,
	"bar/bar_test.go": `package bar
import "testing"
func TestSuccess(t *testing.T) {
  if Bar(2) != 2 {
    t.Fail()
  }
  if Baz(2) != 2 {
    t.Fail()
  }
}
`,
}
<commit_msg>Fix errcheck regression from last commit.<commit_after>// Copyright 2015 Marc-Antoine Ruel. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

package checks

import (
	"io/ioutil"
	"os"
	"testing"

	"github.com/maruel/pre-commit-go/checks/definitions"
	"github.com/maruel/pre-commit-go/internal"
	"github.com/maruel/ut"
)

func TestCoverageGlobal(t *testing.T) {
	t.Parallel()
	if testing.Short() {
		t.SkipNow()
	}
	td, err := ioutil.TempDir("", "pre-commit-go")
	ut.AssertEqual(t, nil, err)
	defer func() {
		if err := internal.RemoveAll(td); err != nil {
			t.Fail()
		}
	}()
	change := setup(t, td, coverageFiles)

	c := &Coverage{
		UseGlobalInference: true,
		UseCoveralls:       false,
		Global: definitions.CoverageSettings{
			MinCoverage: 50,
			MaxCoverage: 100,
		},
		PerDirDefault: definitions.CoverageSettings{
			MinCoverage: 50,
			MaxCoverage: 100,
		},
		PerDir: map[string]*definitions.CoverageSettings{},
	}
	profile, err := c.RunProfile(change)
	ut.AssertEqual(t, nil, err)
	ut.AssertEqual(t, 55.555555555555555, profile.CoveragePercent())
	ut.AssertEqual(t, 2, profile.PartiallyCoveredFuncs())
	expected := CoverageProfile{
		{
			Source:    "foo.go",
			Line:      2,
			SourceRef: "foo.go:2",
			Name:      "Foo",
			Count:     1,
			Total:     1,
			Percent:   100,
		},
		{
			Source:    "bar/bar.go",
			Line:      2,
			SourceRef: "bar/bar.go:2",
			Name:      "Bar",
			Count:     2,
			Total:     4,
			Percent:   50,
		},
		{
			Source:    "bar/bar.go",
			Line:      10,
			SourceRef: "bar/bar.go:10",
			Name:      "Baz",
			Count:     2,
			Total:     4,
			Percent:   50,
		},
	}
	ut.AssertEqual(t, expected, profile)

	expected = CoverageProfile{
		{
			Source:    "bar.go",
			Line:      2,
			SourceRef: "bar/bar.go:2",
			Name:      "Bar",
			Count:     2,
			Total:     4,
			Percent:   50,
		},
		{
			Source:    "bar.go",
			Line:      10,
			SourceRef: "bar/bar.go:10",
			Name:      "Baz",
			Count:     2,
			Total:     4,
			Percent:   50,
		},
	}
	ut.AssertEqual(t, expected, profile.Subset("bar"))

	expected = CoverageProfile{
		{
			Source:    "foo.go",
			Line:      2,
			SourceRef: "foo.go:2",
			Name:      "Foo",
			Count:     1,
			Total:     1,
			Percent:   100,
		},
	}
	ut.AssertEqual(t, expected, profile.Subset("."))
}

func TestCoverageLocal(t *testing.T) {
	t.Parallel()
	if testing.Short() {
		t.SkipNow()
	}
	td, err := ioutil.TempDir("", "pre-commit-go")
	ut.AssertEqual(t, nil, err)
	defer func() {
		if err := internal.RemoveAll(td); err != nil {
			t.Fail()
		}
	}()
	change := setup(t, td, coverageFiles)

	c := &Coverage{
		UseGlobalInference: false,
		UseCoveralls:       false,
		Global: definitions.CoverageSettings{
			MinCoverage: 50,
			MaxCoverage: 100,
		},
		PerDirDefault: definitions.CoverageSettings{
			MinCoverage: 50,
			MaxCoverage: 100,
		},
		PerDir: map[string]*definitions.CoverageSettings{},
	}
	profile, err := c.RunProfile(change)
	ut.AssertEqual(t, nil, err)
	ut.AssertEqual(t, 55.555555555555555, profile.CoveragePercent())
	ut.AssertEqual(t, 2, profile.PartiallyCoveredFuncs())
	expected := CoverageProfile{
		{
			Source:    "foo.go",
			Line:      2,
			SourceRef: "foo.go:2",
			Name:      "Foo",
			Count:     1,
			Total:     1,
			Percent:   100,
		},
		{
			Source:    "bar/bar.go",
			Line:      2,
			SourceRef: "bar/bar.go:2",
			Name:      "Bar",
			Count:     2,
			Total:     4,
			Percent:   50,
		},
		{
			Source:    "bar/bar.go",
			Line:      10,
			SourceRef: "bar/bar.go:10",
			Name:      "Baz",
			Count:     2,
			Total:     4,
			Percent:   50,
		},
	}
	ut.AssertEqual(t, expected, profile)

	expected = CoverageProfile{
		{
			Source:    "bar.go",
			Line:      2,
			SourceRef: "bar/bar.go:2",
			Name:      "Bar",
			Count:     2,
			Total:     4,
			Percent:   50,
		},
		{
			Source:    "bar.go",
			Line:      10,
			SourceRef: "bar/bar.go:10",
			Name:      "Baz",
			Count:     2,
			Total:     4,
			Percent:   50,
		},
	}
	ut.AssertEqual(t, expected, profile.Subset("bar"))

	ut.AssertEqual(t, nil, c.Run(change))
}

func TestCoveragePrerequisites(t *testing.T) {
	// This test can't be parallel.
	if !IsContinuousIntegration() {
		old := os.Getenv("CI")
		defer func() {
			ut.ExpectEqual(t, nil, os.Setenv("CI", old))
		}()
		ut.AssertEqual(t, nil, os.Setenv("CI", "true"))
		ut.AssertEqual(t, true, IsContinuousIntegration())
	}
	c := Coverage{UseCoveralls: true}
	ut.AssertEqual(t, 1, len(c.GetPrerequisites()))
}

func TestCoverageEmpty(t *testing.T) {
	t.Parallel()
	ut.AssertEqual(t, 0., CoverageProfile{}.CoveragePercent())
	c := Coverage{PerDir: map[string]*definitions.CoverageSettings{"foo": nil}}
	ut.AssertEqual(t, &definitions.CoverageSettings{}, c.SettingsForPkg("foo"))
}

var coverageFiles = map[string]string{
	"foo.go": `package foo
func Foo() int {
  return 1
}
`,
	"foo_test.go": `package foo
import "testing"
func TestSuccess(t *testing.T) {
  if Foo() != 1 {
    t.Fail()
  }
}
`,
	"bar/bar.go": `package bar
func Bar(i int) int {
	if i == 2 {
		return 2
	}
	i++
	return i
}

func Baz(i int) int {
	if i == 2 {
		return 2
	}
	i++
	return i
}
`,
	"bar/bar_test.go": `package bar
import "testing"
func TestSuccess(t *testing.T) {
  if Bar(2) != 2 {
    t.Fail()
  }
  if Baz(2) != 2 {
    t.Fail()
  }
}
`,
}
<|endoftext|>


<commit_before>package dtls

import (
	"errors"
	"sync"
	"time"
)

type Listener struct {
	transport          Transport
	peers              map[string]*Peer
	readQueue          chan *msg
	mux                sync.Mutex
	wg                 sync.WaitGroup
	isShutdown         bool
	cipherSuites       []CipherSuite
	compressionMethods []CompressionMethod
}

type msg struct {
	data []byte
	peer *Peer
}

func NewUdpListener(listener string, readTimeout time.Duration) (*Listener, error) {
	utrans, err := newUdpTransport(listener, readTimeout)
	if err != nil {
		return nil, err
	}

	l := &Listener{transport: utrans, peers: make(map[string]*Peer), readQueue: make(chan *msg, 128)}
	l.wg.Add(1)
	go receiver(l)
	return l, nil
}

func receiver(l *Listener) {
	if l.isShutdown {
		logDebug("", "dtls: [%s][%s] receiver shutting down", l.transport.Type(), l.transport.Local())
		l.wg.Done()
		return
	}
	logDebug("", "dtls: [%s][%s] waiting for packet", l.transport.Type(), l.transport.Local())
	data, peer, err := l.transport.ReadPacket()
	if err != nil {
		logError("", "[%s][%s] failed to read packet: %s", l.transport.Type(), l.transport.Local(), err.Error())
		l.wg.Done()
		return
	}

	l.mux.Lock()
	p, found := l.peers[peer.String()]
	l.mux.Unlock()
	if !found {
		//this is where server code will go
		logDebug(peer.String(), "dtls: [%s][%s] received from unknown peer", l.transport.Type(), l.transport.Local())
		p, _ = l.addServerPeer(peer)
	} else {
		logDebug(peer.String(), "dtls: [%s][%s] received from peer", l.transport.Type(), l.transport.Local())
	}

	for {
		rec, rem, err := p.session.parseRecord(data)
		if err != nil {
			logWarn(peer.String(), "dtls: [%s][%s] error parsing record: %s", l.transport.Type(), l.transport.Local(), err.Error())
			l.RemovePeer(p, AlertDesc_DecodeError)
			break
		}

		if rec.IsHandshake() {
			if !p.session.isHandshakeDone() {
				logDebug(peer.String(), "dtls: [%s][%s] handshake in progress", l.transport.Type(), l.transport.Local())
				if err := p.session.processHandshakePacket(rec); err != nil {
					l.RemovePeer(p, AlertDesc_HandshakeFailure)
					logWarn(peer.String(), "dtls: [%s][%s] failed to complete handshake: %s", l.transport.Type(), l.transport.Local(), err.Error())
				}
			} else {
				l.RemovePeer(p, AlertDesc_HandshakeFailure)
				logWarn(peer.String(), "dtls: [%s][%s] received handshake message after handshake is complete", l.transport.Type(), l.transport.Local())
			}
		} else if rec.IsAlert() {
			//handle alert
			alert, err := parseAlert(rec.Data)
			if err != nil {
				l.RemovePeer(p, AlertDesc_DecodeError)
				logWarn(peer.String(), "dtls: [%s][%s] failed to parse alert: %s", l.transport.Type(), l.transport.Local(), err.Error())
			}
			if alert.Type == AlertType_Warning {
				logWarn(peer.String(), "dtls: [%s][%s] received warning alert: %s", l.transport.Type(), l.transport.Local(), alertDescToString(alert.Desc))
			} else {
				l.RemovePeer(p, AlertDesc_Noop)
				logWarn(peer.String(), "dtls: [%s][%s] received fatal alert: %s", l.transport.Type(), l.transport.Local(), alertDescToString(alert.Desc))
			}
		} else if rec.IsAppData() && !p.session.isHandshakeDone() {
			l.RemovePeer(p, AlertDesc_DecryptError)
			logWarn(peer.String(), "dtls: [%s][%s] received app data message without completing handshake", l.transport.Type(), l.transport.Local())
		} else {
			if p.queue != nil {
				p.queue <- rec.Data
			} else {
				l.readQueue <- &msg{rec.Data, p}
			}
			//TODO handle case where queue is full and not being read
		}
		if rem == nil || len(rem) == 0 {
			break
		} else {
			data = rem
		}
	}

	l.wg.Add(1)
	go receiver(l)
	l.wg.Done()
	//TODO need to queue records for each session so that we can process multiple in parallel
}

func (l *Listener) RemovePeer(peer *Peer, alertDesc uint8) error {
	l.mux.Lock()
	if alertDesc != AlertDesc_Noop {
		peer.Close(alertDesc)
	}
	delete(l.peers, peer.RemoteAddr())
	l.mux.Unlock()
	return nil
}

func (l *Listener) addServerPeer(tpeer TransportPeer) (*Peer, error) {
	peer := &Peer{peer: tpeer}
	peer.session = newServerSession(peer.peer)
	if l.cipherSuites != nil {
		peer.session.cipherSuites = l.cipherSuites
	}
	if l.compressionMethods != nil {
		peer.session.compressionMethods = l.compressionMethods
	}
	l.mux.Lock()
	l.peers[peer.peer.String()] = peer
	l.mux.Unlock()
	return peer, nil
}

type PeerParams struct {
	Addr             string
	Identity         string
	HandshakeTimeout time.Duration
}

func (l *Listener) AddPeer(addr string, identity string) (*Peer, error) {
	return l.AddPeerWithParams(&PeerParams{Addr: addr, Identity: identity, HandshakeTimeout: time.Second * 20})
}

func (l *Listener) AddPeerWithParams(params *PeerParams) (*Peer, error) {
	peer := &Peer{peer: l.transport.NewPeer(params.Addr)}
	peer.UseQueue(true)
	peer.session = newClientSession(peer.peer)
	if l.cipherSuites != nil {
		peer.session.cipherSuites = l.cipherSuites
	}
	if l.compressionMethods != nil {
		peer.session.compressionMethods = l.compressionMethods
	}
	peer.session.Client.Identity = params.Identity
	l.mux.Lock()
	l.peers[peer.peer.String()] = peer
	l.mux.Unlock()
	peer.session.startHandshake()
	if err := peer.session.waitForHandshake(params.HandshakeTimeout); err != nil {
		l.mux.Lock()
		delete(l.peers, peer.peer.String())
		l.mux.Unlock()
		return nil, err
	}
	return peer, nil
}

func (l *Listener) Read() ([]byte, *Peer) {
	msg := <-l.readQueue

	return msg.data, msg.peer
}

func (l *Listener) Shutdown() error {
	l.isShutdown = true
	//gracefully send alerts to each connected peer
	err := l.transport.Shutdown()
	l.wg.Wait()
	return err
}

func (l *Listener) AddCipherSuite(cipherSuite CipherSuite) {
	if l.cipherSuites == nil {
		l.cipherSuites = make([]CipherSuite, 0, 4)
	}
	l.cipherSuites = append(l.cipherSuites, cipherSuite)
	return
}

func (l *Listener) AddCompressionMethod(compressionMethod CompressionMethod) {
	if l.compressionMethods == nil {
		l.compressionMethods = make([]CompressionMethod, 0, 4)
	}
	l.compressionMethods = append(l.compressionMethods, compressionMethod)
	return
}

func (l *Listener) FindPeer(addr string) (*Peer, error) {
	l.mux.Lock()
	p, found := l.peers[addr]
	l.mux.Unlock()
	if found {
		return p, nil
	} else {
		return nil, errors.New("dtls: Peer [" + addr + "] not found.")
	}
}

func (l *Listener) CountPeers() int {
	var count int
	l.mux.Lock()
	count = len(l.peers)
	l.mux.Unlock()
	return count
}
<commit_msg>Added RemovePeerByAddr() method for removing peers from the DTLS cache.<commit_after>package dtls

import (
	"errors"
	"sync"
	"time"
)

type Listener struct {
	transport          Transport
	peers              map[string]*Peer
	readQueue          chan *msg
	mux                sync.Mutex
	wg                 sync.WaitGroup
	isShutdown         bool
	cipherSuites       []CipherSuite
	compressionMethods []CompressionMethod
}

type msg struct {
	data []byte
	peer *Peer
}

func NewUdpListener(listener string, readTimeout time.Duration) (*Listener, error) {
	utrans, err := newUdpTransport(listener, readTimeout)
	if err != nil {
		return nil, err
	}

	l := &Listener{transport: utrans, peers: make(map[string]*Peer), readQueue: make(chan *msg, 128)}
	l.wg.Add(1)
	go receiver(l)
	return l, nil
}

func receiver(l *Listener) {
	if l.isShutdown {
		logDebug("", "dtls: [%s][%s] receiver shutting down", l.transport.Type(), l.transport.Local())
		l.wg.Done()
		return
	}
	logDebug("", "dtls: [%s][%s] waiting for packet", l.transport.Type(), l.transport.Local())
	data, peer, err := l.transport.ReadPacket()
	if err != nil {
		logError("", "[%s][%s] failed to read packet: %s", l.transport.Type(), l.transport.Local(), err.Error())
		l.wg.Done()
		return
	}

	l.mux.Lock()
	p, found := l.peers[peer.String()]
	l.mux.Unlock()
	if !found {
		//this is where server code will go
		logDebug(peer.String(), "dtls: [%s][%s] received from unknown peer", l.transport.Type(), l.transport.Local())
		p, _ = l.addServerPeer(peer)
	} else {
		logDebug(peer.String(), "dtls: [%s][%s] received from peer", l.transport.Type(), l.transport.Local())
	}

	for {
		rec, rem, err := p.session.parseRecord(data)
		if err != nil {
			logWarn(peer.String(), "dtls: [%s][%s] error parsing record: %s", l.transport.Type(), l.transport.Local(), err.Error())
			l.RemovePeer(p, AlertDesc_DecodeError)
			break
		}

		if rec.IsHandshake() {
			if !p.session.isHandshakeDone() {
				logDebug(peer.String(), "dtls: [%s][%s] handshake in progress", l.transport.Type(), l.transport.Local())
				if err := p.session.processHandshakePacket(rec); err != nil {
					l.RemovePeer(p, AlertDesc_HandshakeFailure)
					logWarn(peer.String(), "dtls: [%s][%s] failed to complete handshake: %s", l.transport.Type(), l.transport.Local(), err.Error())
				}
			} else {
				l.RemovePeer(p, AlertDesc_HandshakeFailure)
				logWarn(peer.String(), "dtls: [%s][%s] received handshake message after handshake is complete", l.transport.Type(), l.transport.Local())
			}
		} else if rec.IsAlert() {
			//handle alert
			alert, err := parseAlert(rec.Data)
			if err != nil {
				l.RemovePeer(p, AlertDesc_DecodeError)
				logWarn(peer.String(), "dtls: [%s][%s] failed to parse alert: %s", l.transport.Type(), l.transport.Local(), err.Error())
			}
			if alert.Type == AlertType_Warning {
				logWarn(peer.String(), "dtls: [%s][%s] received warning alert: %s", l.transport.Type(), l.transport.Local(), alertDescToString(alert.Desc))
			} else {
				l.RemovePeer(p, AlertDesc_Noop)
				logWarn(peer.String(), "dtls: [%s][%s] received fatal alert: %s", l.transport.Type(), l.transport.Local(), alertDescToString(alert.Desc))
			}
		} else if rec.IsAppData() && !p.session.isHandshakeDone() {
			l.RemovePeer(p, AlertDesc_DecryptError)
			logWarn(peer.String(), "dtls: [%s][%s] received app data message without completing handshake", l.transport.Type(), l.transport.Local())
		} else {
			if p.queue != nil {
				p.queue <- rec.Data
			} else {
				l.readQueue <- &msg{rec.Data, p}
			}
			//TODO handle case where queue is full and not being read
		}
		if rem == nil || len(rem) == 0 {
			break
		} else {
			data = rem
		}
	}

	l.wg.Add(1)
	go receiver(l)
	l.wg.Done()
	//TODO need to queue records for each session so that we can process multiple in parallel
}

func (l *Listener) RemovePeer(peer *Peer, alertDesc uint8) error {
	l.mux.Lock()
	if alertDesc != AlertDesc_Noop {
		peer.Close(alertDesc)
	}
	delete(l.peers, peer.RemoteAddr())
	l.mux.Unlock()
	return nil
}

func (l *Listener) RemovePeerByAddr(addr string, alertDesc uint8) error {
	l.mux.Lock()
	p, found := l.peers[addr]
	if found {
		if alertDesc != AlertDesc_Noop {
			p.Close(alertDesc)
		}
		delete(l.peers, p.RemoteAddr())
	}
	l.mux.Unlock()
	return nil
}

func (l *Listener) addServerPeer(tpeer TransportPeer) (*Peer, error) {
	peer := &Peer{peer: tpeer}
	peer.session = newServerSession(peer.peer)
	if l.cipherSuites != nil {
		peer.session.cipherSuites = l.cipherSuites
	}
	if l.compressionMethods != nil {
		peer.session.compressionMethods = l.compressionMethods
	}
	l.mux.Lock()
	l.peers[peer.peer.String()] = peer
	l.mux.Unlock()
	return peer, nil
}

type PeerParams struct {
	Addr             string
	Identity         string
	HandshakeTimeout time.Duration
}

func (l *Listener) AddPeer(addr string, identity string) (*Peer, error) {
	return l.AddPeerWithParams(&PeerParams{Addr: addr, Identity: identity, HandshakeTimeout: time.Second * 20})
}

func (l *Listener) AddPeerWithParams(params *PeerParams) (*Peer, error) {
	peer := &Peer{peer: l.transport.NewPeer(params.Addr)}
	peer.UseQueue(true)
	peer.session = newClientSession(peer.peer)
	if l.cipherSuites != nil {
		peer.session.cipherSuites = l.cipherSuites
	}
	if l.compressionMethods != nil {
		peer.session.compressionMethods = l.compressionMethods
	}
	peer.session.Client.Identity = params.Identity
	l.mux.Lock()
	l.peers[peer.peer.String()] = peer
	l.mux.Unlock()
	peer.session.startHandshake()
	if err := peer.session.waitForHandshake(params.HandshakeTimeout); err != nil {
		l.mux.Lock()
		delete(l.peers, peer.peer.String())
		l.mux.Unlock()
		return nil, err
	}
	return peer, nil
}

func (l *Listener) Read() ([]byte, *Peer) {
	msg := <-l.readQueue

	return msg.data, msg.peer
}

func (l *Listener) Shutdown() error {
	l.isShutdown = true
	//gracefully send alerts to each connected peer
	err := l.transport.Shutdown()
	l.wg.Wait()
	return err
}

func (l *Listener) AddCipherSuite(cipherSuite CipherSuite) {
	if l.cipherSuites == nil {
		l.cipherSuites = make([]CipherSuite, 0, 4)
	}
	l.cipherSuites = append(l.cipherSuites, cipherSuite)
	return
}

func (l *Listener) AddCompressionMethod(compressionMethod CompressionMethod) {
	if l.compressionMethods == nil {
		l.compressionMethods = make([]CompressionMethod, 0, 4)
	}
	l.compressionMethods = append(l.compressionMethods, compressionMethod)
	return
}

func (l *Listener) FindPeer(addr string) (*Peer, error) {
	l.mux.Lock()
	p, found := l.peers[addr]
	l.mux.Unlock()
	if found {
		return p, nil
	} else {
		return nil, errors.New("dtls: Peer [" + addr + "] not found.")
	}
}

func (l *Listener) CountPeers() int {
	var count int
	l.mux.Lock()
	count = len(l.peers)
	l.mux.Unlock()
	return count
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"github.com/BurntSushi/xgb"
	"github.com/BurntSushi/xgb/xproto"
)

type itemID int

const (
	batteryItem itemID = iota
	timeItem
	audioItem
	netItem
)

const (
	batSysPath = "/sys/class/power_supply"
	netSysPath = "/sys/class/net"
)

type iconID int

const (
	noIcon iconID = iota
	volumeIcon
	muteIcon
	timeIcon
	wifiIcon
	wiredIcon
	batteryIcon
	chargeIcon
	dischargeIcon
	fullIcon
	unknownIcon
)

var icons = map[iconID]string{
	noIcon:        "",
	volumeIcon:    "v:",
	muteIcon:      "m:",
	timeIcon:      "",
	wiredIcon:     "e:",
	wifiIcon:      "w:",
	batteryIcon:   "b:",
	chargeIcon:    "+",
	dischargeIcon: "-",
	fullIcon:      "=",
	unknownIcon:   "?",
}

var (
	updatePeriod = 5 * time.Second
	items        = []itemID{netItem, batteryItem, audioItem, timeItem}
	statusFormat = statusFmt

	netInterfaces = []string{"wlan0", "eth0"}
	wifiFormat    = wifiFmt
	wiredFormat   = wiredFmt
	netFormat     = netFmt

	batteries    = []string{"BAT0"}
	batteryIcons = map[string]iconID{
		"Charging": chargeIcon, "Discharging": dischargeIcon, "Full": fullIcon,
	}
	batteryDevFormat = batteryDevFmt
	batteryFormat    = batteryFmt

	audioFormat = audioFmt

	timeFormat = timeFmt
)

func wifiStatus(dev string, isUp bool) (string, bool) {
	ssid, bitrate, signal := "", 0, 0

	cmd := exec.Command("iw", "dev", dev, "link")
	out, err := cmd.StdoutPipe()
	if err != nil {
		return "", false
	}
	scan := bufio.NewScanner(out)
	if cmd.Start() != nil {
		return "", false
	}
	for scan.Scan() {
		key, value := "", ""
		kv := strings.SplitN(scan.Text(), ": ", 2)
		if len(kv) == 2 {
			key, value = strings.TrimSpace(kv[0]), kv[1]
		}
		switch key {
		case "SSID":
			ssid = value
		case "tx bitrate":
			value = strings.SplitN(value+" ", " ", 2)[0]
			if br, err := strconv.ParseFloat(value, 64); err == nil {
				bitrate = int(br)
			}
		case "signal":
			value = strings.SplitN(value+" ", " ", 2)[0]
			if sig, err := strconv.Atoi(value); err == nil {
				signal = sig
			}
		}
	}
	cmd.Wait()

	return wifiFormat(dev, ssid, bitrate, signal, isUp)
}

func wiredStatus(dev string, isUp bool) (string, bool) {
	speed := 0
	if spd, err := sysfsIntVal(filepath.Join(netSysPath, dev, "speed")); err == nil {
		speed = spd
	}
	return wiredFormat(dev, speed, isUp)
}

func netDevStatus(dev string) (string, bool) {
	status, err := sysfsStringVal(filepath.Join(netSysPath, dev, "operstate"))
	isUp := true
	if err != nil || status != "up" {
		isUp = false
	}

	_, err = os.Stat(filepath.Join(netSysPath, dev, "wireless"))
	isWifi := !os.IsNotExist(err)

	if isWifi {
		return wifiStatus(dev, isUp)
	}
	return wiredStatus(dev, isUp)
}

func netStatus() string {
	var netStats []string
	for _, dev := range netInterfaces {
		devStat, ok := netDevStatus(dev)
		if ok {
			netStats = append(netStats, devStat)
		}
	}
	return netFormat(netStats)
}

func wifiFmt(dev, ssid string, bitrate, signal int, isUp bool) (string, bool) {
	return fmt.Sprintf("%s%s/%d/%d", icons[wifiIcon], ssid, bitrate, signal), isUp
}
func wiredFmt(dev string, speed int, isUp bool) (string, bool) {
	return fmt.Sprintf("%s%d", icons[wiredIcon], speed), isUp
}

func netFmt(devs []string) string {
	return strings.Join(devs, " ")
}

func batteryDevStatus(bat string) string {
	pct, err := sysfsIntVal(filepath.Join(batSysPath, bat, "capacity"))
	if err != nil {
		return icons[unknownIcon]
	}
	status, err := sysfsStringVal(filepath.Join(batSysPath, bat, "status"))
	if err != nil {
		return icons[unknownIcon]
	}
	return batteryDevFormat(pct, status)
}

func batteryStatus() string {
	var batStats []string
	for _, bat := range batteries {
		batStats = append(batStats, batteryDevStatus(bat))
	}
	return batteryFormat(batStats)
}

func batteryDevFmt(pct int, status string) string {
	return fmt.Sprintf("%d%s", pct, icons[batteryIcons[status]])
}

func batteryFmt(bats []string) string {
	return icons[batteryIcon] + strings.Join(bats, "/")
}

func audioStatus() string {
	volStr, err := exec.Command("ponymix", "get-volume").Output()
	if err != nil {
		return icons[unknownIcon]
	}
	vol, err := strconv.Atoi(string(bytes.TrimSpace(volStr)))
	if err != nil {
		return icons[unknownIcon]
	}
	isMuted := (exec.Command("ponymix", "is-muted").Run() == nil)
	return audioFormat(vol, isMuted)
}

func audioFmt(vol int, isMuted bool) string {
	icon := volumeIcon
	if isMuted {
		icon = muteIcon
	}
	return fmt.Sprintf("%s%d", icons[icon], vol)
}

func timeStatus() string {
	return timeFormat(time.Now())
}

func timeFmt(t time.Time) string {
	return t.Format("2006-01-02 15:04")
}

func statusFmt(s []string) string {
	return " " + strings.Join(s, " | ") + " "
}

func updateStatus(x *xgb.Conn, root xproto.Window) {
	var stats []string
	for _, item := range items {
		switch item {
		case batteryItem:
			stats = append(stats, batteryStatus())
		case audioItem:
			stats = append(stats, audioStatus())
		case netItem:
			stats = append(stats, netStatus())
		case timeItem:
			stats = append(stats, timeStatus())
		}
	}
	status := statusFormat(stats)

	xproto.ChangeProperty(x, xproto.PropModeReplace, root, xproto.AtomWmName,
		xproto.AtomString, 8, uint32(len(status)), []byte(status))
}

func sysfsIntVal(path string) (int, error) {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return 0, err
	}
	val, err := strconv.Atoi(string(bytes.TrimSpace(data)))
	if err != nil {
		return 0, err
	}
	return val, nil
}

func sysfsStringVal(path string) (string, error) {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return "", err
	}
	return string(bytes.TrimSpace(data)), nil
}

func main() {
	x, err := xgb.NewConn()
	if err != nil {
		log.Fatal(err)
	}

	root := xproto.Setup(x).DefaultScreen(x).Root
	for t := time.Tick(updatePeriod); ; <-t {
		updateStatus(x, root)
	}
}
<commit_msg>Used amixer to get audio state.<commit_after>package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/BurntSushi/xgb"
	"github.com/BurntSushi/xgb/xproto"
)

type itemID int

const (
	batteryItem itemID = iota
	timeItem
	audioItem
	netItem
)

const (
	batSysPath = "/sys/class/power_supply"
	netSysPath = "/sys/class/net"
)

type iconID int

const (
	noIcon iconID = iota
	volumeIcon
	muteIcon
	timeIcon
	wifiIcon
	wiredIcon
	batteryIcon
	chargeIcon
	dischargeIcon
	fullIcon
	unknownIcon
)

var icons = map[iconID]string{
	noIcon:        "",
	volumeIcon:    "v:",
	muteIcon:      "m:",
	timeIcon:      "",
	wiredIcon:     "e:",
	wifiIcon:      "w:",
	batteryIcon:   "b:",
	chargeIcon:    "+",
	dischargeIcon: "-",
	fullIcon:      "=",
	unknownIcon:   "?",
}

var (
	updatePeriod = 5 * time.Second
	items        = []itemID{netItem, batteryItem, audioItem, timeItem}
	statusFormat = statusFmt

	netInterfaces = []string{"wlan0", "eth0"}
	wifiFormat    = wifiFmt
	wiredFormat   = wiredFmt
	netFormat     = netFmt

	batteries    = []string{"BAT0"}
	batteryIcons = map[string]iconID{
		"Charging": chargeIcon, "Discharging": dischargeIcon, "Full": fullIcon,
	}
	batteryDevFormat = batteryDevFmt
	batteryFormat    = batteryFmt

	audioFormat = audioFmt
	amixerRE    = regexp.MustCompile(`(?m)\[(\d+)%] \[(\w+)]`)

	timeFormat = timeFmt
)

func wifiStatus(dev string, isUp bool) (string, bool) {
	ssid, bitrate, signal := "", 0, 0

	cmd := exec.Command("iw", "dev", dev, "link")
	out, err := cmd.StdoutPipe()
	if err != nil {
		return "", false
	}
	scan := bufio.NewScanner(out)
	if cmd.Start() != nil {
		return "", false
	}
	for scan.Scan() {
		key, value := "", ""
		kv := strings.SplitN(scan.Text(), ": ", 2)
		if len(kv) == 2 {
			key, value = strings.TrimSpace(kv[0]), kv[1]
		}
		switch key {
		case "SSID":
			ssid = value
		case "tx bitrate":
			value = strings.SplitN(value+" ", " ", 2)[0]
			if br, err := strconv.ParseFloat(value, 64); err == nil {
				bitrate = int(br)
			}
		case "signal":
			value = strings.SplitN(value+" ", " ", 2)[0]
			if sig, err := strconv.Atoi(value); err == nil {
				signal = sig
			}
		}
	}
	cmd.Wait()

	return wifiFormat(dev, ssid, bitrate, signal, isUp)
}

func wiredStatus(dev string, isUp bool) (string, bool) {
	speed := 0
	if spd, err := sysfsIntVal(filepath.Join(netSysPath, dev, "speed")); err == nil {
		speed = spd
	}
	return wiredFormat(dev, speed, isUp)
}

func netDevStatus(dev string) (string, bool) {
	status, err := sysfsStringVal(filepath.Join(netSysPath, dev, "operstate"))
	isUp := true
	if err != nil || status != "up" {
		isUp = false
	}

	_, err = os.Stat(filepath.Join(netSysPath, dev, "wireless"))
	isWifi := !os.IsNotExist(err)

	if isWifi {
		return wifiStatus(dev, isUp)
	}
	return wiredStatus(dev, isUp)
}

func netStatus() string {
	var netStats []string
	for _, dev := range netInterfaces {
		devStat, ok := netDevStatus(dev)
		if ok {
			netStats = append(netStats, devStat)
		}
	}
	return netFormat(netStats)
}

func wifiFmt(dev, ssid string, bitrate, signal int, isUp bool) (string, bool) {
	return fmt.Sprintf("%s%s/%d/%d", icons[wifiIcon], ssid, bitrate, signal), isUp
}
func wiredFmt(dev string, speed int, isUp bool) (string, bool) {
	return fmt.Sprintf("%s%d", icons[wiredIcon], speed), isUp
}

func netFmt(devs []string) string {
	return strings.Join(devs, " ")
}

func batteryDevStatus(bat string) string {
	pct, err := sysfsIntVal(filepath.Join(batSysPath, bat, "capacity"))
	if err != nil {
		return icons[unknownIcon]
	}
	status, err := sysfsStringVal(filepath.Join(batSysPath, bat, "status"))
	if err != nil {
		return icons[unknownIcon]
	}
	return batteryDevFormat(pct, status)
}

func batteryStatus() string {
	var batStats []string
	for _, bat := range batteries {
		batStats = append(batStats, batteryDevStatus(bat))
	}
	return batteryFormat(batStats)
}

func batteryDevFmt(pct int, status string) string {
	return fmt.Sprintf("%d%s", pct, icons[batteryIcons[status]])
}

func batteryFmt(bats []string) string {
	return icons[batteryIcon] + strings.Join(bats, "/")
}

func audioStatus() string {
	out, err := exec.Command("amixer", "get", "Master").Output()
	if err != nil {
		return icons[unknownIcon]
	}
	match := amixerRE.FindSubmatch(out)
	if len(match) < 3 {
		return icons[unknownIcon]
	}
	vol, err := strconv.Atoi(string(match[1]))
	if err != nil {
		return icons[unknownIcon]
	}
	isMuted := (string(match[2]) == "off")
	return audioFormat(vol, isMuted)
}

func audioFmt(vol int, isMuted bool) string {
	icon := volumeIcon
	if isMuted {
		icon = muteIcon
	}
	return fmt.Sprintf("%s%d", icons[icon], vol)
}

func timeStatus() string {
	return timeFormat(time.Now())
}

func timeFmt(t time.Time) string {
	return t.Format("2006-01-02 15:04")
}

func statusFmt(s []string) string {
	return " " + strings.Join(s, " | ") + " "
}

func updateStatus(x *xgb.Conn, root xproto.Window) {
	var stats []string
	for _, item := range items {
		switch item {
		case batteryItem:
			stats = append(stats, batteryStatus())
		case audioItem:
			stats = append(stats, audioStatus())
		case netItem:
			stats = append(stats, netStatus())
		case timeItem:
			stats = append(stats, timeStatus())
		}
	}
	status := statusFormat(stats)

	xproto.ChangeProperty(x, xproto.PropModeReplace, root, xproto.AtomWmName,
		xproto.AtomString, 8, uint32(len(status)), []byte(status))
}

func sysfsIntVal(path string) (int, error) {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return 0, err
	}
	val, err := strconv.Atoi(string(bytes.TrimSpace(data)))
	if err != nil {
		return 0, err
	}
	return val, nil
}

func sysfsStringVal(path string) (string, error) {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return "", err
	}
	return string(bytes.TrimSpace(data)), nil
}

func main() {
	x, err := xgb.NewConn()
	if err != nil {
		log.Fatal(err)
	}

	root := xproto.Setup(x).DefaultScreen(x).Root
	for t := time.Tick(updatePeriod); ; <-t {
		updateStatus(x, root)
	}
}
<|endoftext|>


<commit_before>package gopiano

import (
	"bytes"
	"encoding/json"

	"github.com/cellofellow/gopiano/requests"
	"github.com/cellofellow/gopiano/responses"
)

// Client.StationAddFeedback adds feedback (thumbs up or down, or star or ban if you prefer) to a song.
// Argument trackToken is the token identifying a track. Obtained from Client.StationGetPlaylist
// Argument isPositive is a bool which if true is a "star" and if false is a "ban".
// Calls API method "station.addFeedback"
func (c *Client) StationAddFeedback(trackToken string, isPositive bool) (*responses.StationAddFeedback, error) {
	requestData := requests.StationAddFeedback{
		TrackToken:    trackToken,
		IsPositive:    isPositive,
		UserAuthToken: c.userAuthToken,
		SyncTime:      c.GetSyncTime(),
	}
	requestDataEncoded, err := json.Marshal(requestData)
	if err != nil {
		return nil, err
	}
	requestDataReader := bytes.NewReader(requestDataEncoded)

	var resp responses.StationAddFeedback
	err = c.BlowfishCall("http://", "station.addFeedback", requestDataReader, &resp)
	if err != nil {
		return nil, err
	}
	return &resp, nil
}

// Client.StationAddMusic adds an additional music seed to an existing station.
// Argument musicToken is obtained from Client.MusicSearch
// Argument stationToken is obtained from Client.UserGetStationList
// Calls API method "station.addMusic"
func (c *Client) StationAddMusic(musicToken, stationToken string) (*responses.StationAddMusic, error) {
	requestData := requests.StationAddMusic{
		MusicToken:    musicToken,
		StationToken:  stationToken,
		UserAuthToken: c.userAuthToken,
		SyncTime:      c.GetSyncTime(),
	}
	requestDataEncoded, err := json.Marshal(requestData)
	if err != nil {
		return nil, err
	}
	requestDataReader := bytes.NewReader(requestDataEncoded)

	var resp responses.StationAddMusic
	err = c.BlowfishCall("http://", "station.addMusic", requestDataReader, &resp)
	if err != nil {
		return nil, err
	}
	return &resp, nil
}

// Client.StationCreateStationTrack creates a new station from a specified track.
// Argument trackToken is a token of a song or artist obtained from Client.StationGetPlaylist.
// Argument musicType is either "song" or "artist" specifying the type of track being used.
// Calls API method "station.createStation"
func (c *Client) StationCreateStationTrack(trackToken, musicType string) (*responses.StationCreateStation, error) {
	requestData := requests.StationCreateStation{
		TrackToken:    trackToken,
		MusicType:     musicType,
		UserAuthToken: c.userAuthToken,
		SyncTime:      c.GetSyncTime(),
	}
	requestDataEncoded, err := json.Marshal(requestData)
	if err != nil {
		return nil, err
	}
	requestDataReader := bytes.NewReader(requestDataEncoded)

	var resp responses.StationCreateStation
	err = c.BlowfishCall("http://", "station.createStation", requestDataReader, &resp)
	if err != nil {
		return nil, err
	}
	return &resp, nil
}

// Client.StationCreateStationMusic creates a new station from a music search result.
// Argument musicToken is obtained from Client.MusicSearch.
// Calls API method "station.createStation"
func (c *Client) StationCreateStationMusic(musicToken string) (*responses.StationCreateStation, error) {
	requestData := requests.StationCreateStation{
		MusicToken:    musicToken,
		UserAuthToken: c.userAuthToken,
		SyncTime:      c.GetSyncTime(),
	}
	requestDataEncoded, err := json.Marshal(requestData)
	if err != nil {
		return nil, err
	}
	requestDataReader := bytes.NewReader(requestDataEncoded)

	var resp responses.StationCreateStation
	err = c.BlowfishCall("http://", "station.createStation", requestDataReader, &resp)
	if err != nil {
		return nil, err
	}
	return &resp, nil
}

// Client.StationDeleteFeedback deletes feedback (thumbs up/down) on a particular tracks feedback ID.
// Calls API method "station.deleteFeedback"
func (c *Client) StationDeleteFeedback(feedbackID string) error {
	requestData := requests.StationDeleteFeedback{
		FeedbackID:    feedbackID,
		UserAuthToken: c.userAuthToken,
		SyncTime:      c.GetSyncTime(),
	}
	requestDataEncoded, err := json.Marshal(requestData)
	if err != nil {
		return err
	}
	requestDataReader := bytes.NewReader(requestDataEncoded)
	var resp interface{}
	return c.BlowfishCall("http://", "station.deleteFeedback", requestDataReader, &resp)
}

// Client.StationDeleteMusic removes seed music identified by a seedID from a station.
// Calls API method "station.deleteMusic"
func (c *Client) StationDeleteMusic(seedID string) error {
	requestData := requests.StationDeleteMusic{
		SeedID:        seedID,
		UserAuthToken: c.userAuthToken,
		SyncTime:      c.GetSyncTime(),
	}
	requestDataEncoded, err := json.Marshal(requestData)
	if err != nil {
		return err
	}
	requestDataReader := bytes.NewReader(requestDataEncoded)
	var resp interface{}
	return c.BlowfishCall("http://", "station.deleteMusic", requestDataReader, &resp)
}

// Client.StationDeleteStation removes a station identified by a stationToken.
// Calls API method "station.deleteStation"
func (c *Client) StationDeleteStation(stationToken string) error {
	requestData := requests.StationDeleteStation{
		StationToken:  stationToken,
		UserAuthToken: c.userAuthToken,
		SyncTime:      c.GetSyncTime(),
	}
	requestDataEncoded, err := json.Marshal(requestData)
	if err != nil {
		return err
	}
	requestDataReader := bytes.NewReader(requestDataEncoded)
	var resp interface{}
	return c.BlowfishCall("http://", "station.deleteStation", requestDataReader, &resp)
}

// Client.StationGetGenreStations retrieves a list of predefined "genre stations".
// Calls API method "station.getGenreStations"
func (c *Client) StationGetGenreStations() (*responses.StationGetGenreStations, error) {
	requestData := requests.StationGetGenreStations{
		UserAuthToken: c.userAuthToken,
		SyncTime:      c.GetSyncTime(),
	}
	requestDataEncoded, err := json.Marshal(requestData)
	if err != nil {
		return nil, err
	}
	requestDataReader := bytes.NewReader(requestDataEncoded)

	var resp responses.StationGetGenreStations
	err = c.BlowfishCall("http://", "station.addGetGenreStations", requestDataReader, &resp)
	if err != nil {
		return nil, err
	}
	return &resp, nil
}

// Client.StationGetPlaylist retrieves a playlist for a specified token.
// Argument stationToken is a obtained from User.GetStationList.
// Note: an error response with code 0 may mean you've called getPlaylist too much.
// Calls API method "station.getPlaylist"
func (c *Client) StationGetPlaylist(stationToken string) (*responses.StationGetPlaylist, error) {
	requestData := requests.StationGetPlaylist{
		StationToken:  stationToken,
		UserAuthToken: c.userAuthToken,
		SyncTime:      c.GetSyncTime(),
	}
	requestDataEncoded, err := json.Marshal(requestData)
	if err != nil {
		return nil, err
	}
	requestDataReader := bytes.NewReader(requestDataEncoded)

	var resp responses.StationGetPlaylist
	err = c.BlowfishCall("https://", "station.getPlaylist", requestDataReader, &resp)
	if err != nil {
		return nil, err
	}
	return &resp, nil
}

// Client.StationGetStation retrieves station details.
// Argument stationToken is obtained from Client.UserGetStationList
// Argument includeExtendedAttributes will include music seed and feedback IDs in response.
// Calls API method "station.getStation"
func (c *Client) StationGetStation(stationToken string, includeExtendedAttributes bool) (*responses.StationGetStation, error) {
	requestData := requests.StationGetStation{
		StationToken:              stationToken,
		IncludeExtendedAttributes: includeExtendedAttributes,
		UserAuthToken:             c.userAuthToken,
		SyncTime:                  c.GetSyncTime(),
	}
	requestDataEncoded, err := json.Marshal(requestData)
	if err != nil {
		return nil, err
	}
	requestDataReader := bytes.NewReader(requestDataEncoded)

	var resp responses.StationGetStation
	err = c.BlowfishCall("http://", "station.getStation", requestDataReader, &resp)
	if err != nil {
		return nil, err
	}
	return &resp, nil
}

// Client.StationShareStation shares a station with provided email addresses.
// Arguments stationID and stationToken obtained from Client.UserGetStationList
// Argument emails is a list of email addresses.
// Calls API method "station.shareStation"
func (c *Client) StationShareStation(stationID, stationToken string, emails []string) error {
	requestData := requests.StationShareStation{
		StationToken:  stationToken,
		StationID:     stationID,
		Emails:        emails,
		UserAuthToken: c.userAuthToken,
		SyncTime:      c.GetSyncTime(),
	}
	requestDataEncoded, err := json.Marshal(requestData)
	if err != nil {
		return err
	}
	requestDataReader := bytes.NewReader(requestDataEncoded)

	var resp interface{}
	return c.BlowfishCall("http://", "station.shareStation", requestDataReader, &resp)
}

// Client.StationRenameStation sets a new name for a station.
// Calls API method "station.renameStation"
func (c *Client) StationRenameStation(stationToken, stationName string) (*responses.StationRenameStation, error) {
	requestData := requests.StationRenameStation{
		StationToken:  stationToken,
		StationName:   stationName,
		UserAuthToken: c.userAuthToken,
		SyncTime:      c.GetSyncTime(),
	}
	requestDataEncoded, err := json.Marshal(requestData)
	if err != nil {
		return nil, err
	}
	requestDataReader := bytes.NewReader(requestDataEncoded)

	var resp responses.StationRenameStation
	err = c.BlowfishCall("http://", "station.renameStation", requestDataReader, &resp)
	if err != nil {
		return nil, err
	}
	return &resp, nil
}

// Client.StationTransformSharedStation copies a shared station and creates a user-editable station.
// Calls API method "station.transformSharedStation"
func (c *Client) StationTransformSharedStation(stationToken string) (*responses.StationTransformSharedStation, error) {
	requestData := requests.StationTransformSharedStation{
		StationToken:   stationToken,
		UserAuthToken:  c.userAuthToken,
		SyncTime:       c.GetSyncTime(),
	}
	requestDataEncoded, err := json.Marshal(requestData)
	if err != nil {
		return nil, err
	}
	requestDataReader := bytes.NewReader(requestDataEncoded)

	var resp responses.StationTransformSharedStation
	err = c.BlowfishCall("http://", "station.transformSharedStation", requestDataReader, &resp)
	if err != nil {
		return nil, err
	}
	return &resp, nil
}
<commit_msg>Fix getGenreStations method (wrong method name)<commit_after>package gopiano

import (
	"bytes"
	"encoding/json"

	"github.com/cellofellow/gopiano/requests"
	"github.com/cellofellow/gopiano/responses"
)

// Client.StationAddFeedback adds feedback (thumbs up or down, or star or ban if you prefer) to a song.
// Argument trackToken is the token identifying a track. Obtained from Client.StationGetPlaylist
// Argument isPositive is a bool which if true is a "star" and if false is a "ban".
// Calls API method "station.addFeedback"
func (c *Client) StationAddFeedback(trackToken string, isPositive bool) (*responses.StationAddFeedback, error) {
	requestData := requests.StationAddFeedback{
		TrackToken:    trackToken,
		IsPositive:    isPositive,
		UserAuthToken: c.userAuthToken,
		SyncTime:      c.GetSyncTime(),
	}
	requestDataEncoded, err := json.Marshal(requestData)
	if err != nil {
		return nil, err
	}
	requestDataReader := bytes.NewReader(requestDataEncoded)

	var resp responses.StationAddFeedback
	err = c.BlowfishCall("http://", "station.addFeedback", requestDataReader, &resp)
	if err != nil {
		return nil, err
	}
	return &resp, nil
}

// Client.StationAddMusic adds an additional music seed to an existing station.
// Argument musicToken is obtained from Client.MusicSearch
// Argument stationToken is obtained from Client.UserGetStationList
// Calls API method "station.addMusic"
func (c *Client) StationAddMusic(musicToken, stationToken string) (*responses.StationAddMusic, error) {
	requestData := requests.StationAddMusic{
		MusicToken:    musicToken,
		StationToken:  stationToken,
		UserAuthToken: c.userAuthToken,
		SyncTime:      c.GetSyncTime(),
	}
	requestDataEncoded, err := json.Marshal(requestData)
	if err != nil {
		return nil, err
	}
	requestDataReader := bytes.NewReader(requestDataEncoded)

	var resp responses.StationAddMusic
	err = c.BlowfishCall("http://", "station.addMusic", requestDataReader, &resp)
	if err != nil {
		return nil, err
	}
	return &resp, nil
}

// Client.StationCreateStationTrack creates a new station from a specified track.
// Argument trackToken is a token of a song or artist obtained from Client.StationGetPlaylist.
// Argument musicType is either "song" or "artist" specifying the type of track being used.
// Calls API method "station.createStation"
func (c *Client) StationCreateStationTrack(trackToken, musicType string) (*responses.StationCreateStation, error) {
	requestData := requests.StationCreateStation{
		TrackToken:    trackToken,
		MusicType:     musicType,
		UserAuthToken: c.userAuthToken,
		SyncTime:      c.GetSyncTime(),
	}
	requestDataEncoded, err := json.Marshal(requestData)
	if err != nil {
		return nil, err
	}
	requestDataReader := bytes.NewReader(requestDataEncoded)

	var resp responses.StationCreateStation
	err = c.BlowfishCall("http://", "station.createStation", requestDataReader, &resp)
	if err != nil {
		return nil, err
	}
	return &resp, nil
}

// Client.StationCreateStationMusic creates a new station from a music search result.
// Argument musicToken is obtained from Client.MusicSearch.
// Calls API method "station.createStation"
func (c *Client) StationCreateStationMusic(musicToken string) (*responses.StationCreateStation, error) {
	requestData := requests.StationCreateStation{
		MusicToken:    musicToken,
		UserAuthToken: c.userAuthToken,
		SyncTime:      c.GetSyncTime(),
	}
	requestDataEncoded, err := json.Marshal(requestData)
	if err != nil {
		return nil, err
	}
	requestDataReader := bytes.NewReader(requestDataEncoded)

	var resp responses.StationCreateStation
	err = c.BlowfishCall("http://", "station.createStation", requestDataReader, &resp)
	if err != nil {
		return nil, err
	}
	return &resp, nil
}

// Client.StationDeleteFeedback deletes feedback (thumbs up/down) on a particular tracks feedback ID.
// Calls API method "station.deleteFeedback"
func (c *Client) StationDeleteFeedback(feedbackID string) error {
	requestData := requests.StationDeleteFeedback{
		FeedbackID:    feedbackID,
		UserAuthToken: c.userAuthToken,
		SyncTime:      c.GetSyncTime(),
	}
	requestDataEncoded, err := json.Marshal(requestData)
	if err != nil {
		return err
	}
	requestDataReader := bytes.NewReader(requestDataEncoded)
	var resp interface{}
	return c.BlowfishCall("http://", "station.deleteFeedback", requestDataReader, &resp)
}

// Client.StationDeleteMusic removes seed music identified by a seedID from a station.
// Calls API method "station.deleteMusic"
func (c *Client) StationDeleteMusic(seedID string) error {
	requestData := requests.StationDeleteMusic{
		SeedID:        seedID,
		UserAuthToken: c.userAuthToken,
		SyncTime:      c.GetSyncTime(),
	}
	requestDataEncoded, err := json.Marshal(requestData)
	if err != nil {
		return err
	}
	requestDataReader := bytes.NewReader(requestDataEncoded)
	var resp interface{}
	return c.BlowfishCall("http://", "station.deleteMusic", requestDataReader, &resp)
}

// Client.StationDeleteStation removes a station identified by a stationToken.
// Calls API method "station.deleteStation"
func (c *Client) StationDeleteStation(stationToken string) error {
	requestData := requests.StationDeleteStation{
		StationToken:  stationToken,
		UserAuthToken: c.userAuthToken,
		SyncTime:      c.GetSyncTime(),
	}
	requestDataEncoded, err := json.Marshal(requestData)
	if err != nil {
		return err
	}
	requestDataReader := bytes.NewReader(requestDataEncoded)
	var resp interface{}
	return c.BlowfishCall("http://", "station.deleteStation", requestDataReader, &resp)
}

// Client.StationGetGenreStations retrieves a list of predefined "genre stations".
// Calls API method "station.getGenreStations"
func (c *Client) StationGetGenreStations() (*responses.StationGetGenreStations, error) {
	requestData := requests.StationGetGenreStations{
		UserAuthToken: c.userAuthToken,
		SyncTime:      c.GetSyncTime(),
	}
	requestDataEncoded, err := json.Marshal(requestData)
	if err != nil {
		return nil, err
	}
	requestDataReader := bytes.NewReader(requestDataEncoded)

	var resp responses.StationGetGenreStations
	err = c.BlowfishCall("http://", "station.getGenreStations", requestDataReader, &resp)
	if err != nil {
		return nil, err
	}
	return &resp, nil
}

// Client.StationGetPlaylist retrieves a playlist for a specified token.
// Argument stationToken is a obtained from User.GetStationList.
// Note: an error response with code 0 may mean you've called getPlaylist too much.
// Calls API method "station.getPlaylist"
func (c *Client) StationGetPlaylist(stationToken string) (*responses.StationGetPlaylist, error) {
	requestData := requests.StationGetPlaylist{
		StationToken:  stationToken,
		UserAuthToken: c.userAuthToken,
		SyncTime:      c.GetSyncTime(),
	}
	requestDataEncoded, err := json.Marshal(requestData)
	if err != nil {
		return nil, err
	}
	requestDataReader := bytes.NewReader(requestDataEncoded)

	var resp responses.StationGetPlaylist
	err = c.BlowfishCall("https://", "station.getPlaylist", requestDataReader, &resp)
	if err != nil {
		return nil, err
	}
	return &resp, nil
}

// Client.StationGetStation retrieves station details.
// Argument stationToken is obtained from Client.UserGetStationList
// Argument includeExtendedAttributes will include music seed and feedback IDs in response.
// Calls API method "station.getStation"
func (c *Client) StationGetStation(stationToken string, includeExtendedAttributes bool) (*responses.StationGetStation, error) {
	requestData := requests.StationGetStation{
		StationToken:              stationToken,
		IncludeExtendedAttributes: includeExtendedAttributes,
		UserAuthToken:             c.userAuthToken,
		SyncTime:                  c.GetSyncTime(),
	}
	requestDataEncoded, err := json.Marshal(requestData)
	if err != nil {
		return nil, err
	}
	requestDataReader := bytes.NewReader(requestDataEncoded)

	var resp responses.StationGetStation
	err = c.BlowfishCall("http://", "station.getStation", requestDataReader, &resp)
	if err != nil {
		return nil, err
	}
	return &resp, nil
}

// Client.StationShareStation shares a station with provided email addresses.
// Arguments stationID and stationToken obtained from Client.UserGetStationList
// Argument emails is a list of email addresses.
// Calls API method "station.shareStation"
func (c *Client) StationShareStation(stationID, stationToken string, emails []string) error {
	requestData := requests.StationShareStation{
		StationToken:  stationToken,
		StationID:     stationID,
		Emails:        emails,
		UserAuthToken: c.userAuthToken,
		SyncTime:      c.GetSyncTime(),
	}
	requestDataEncoded, err := json.Marshal(requestData)
	if err != nil {
		return err
	}
	requestDataReader := bytes.NewReader(requestDataEncoded)

	var resp interface{}
	return c.BlowfishCall("http://", "station.shareStation", requestDataReader, &resp)
}

// Client.StationRenameStation sets a new name for a station.
// Calls API method "station.renameStation"
func (c *Client) StationRenameStation(stationToken, stationName string) (*responses.StationRenameStation, error) {
	requestData := requests.StationRenameStation{
		StationToken:  stationToken,
		StationName:   stationName,
		UserAuthToken: c.userAuthToken,
		SyncTime:      c.GetSyncTime(),
	}
	requestDataEncoded, err := json.Marshal(requestData)
	if err != nil {
		return nil, err
	}
	requestDataReader := bytes.NewReader(requestDataEncoded)

	var resp responses.StationRenameStation
	err = c.BlowfishCall("http://", "station.renameStation", requestDataReader, &resp)
	if err != nil {
		return nil, err
	}
	return &resp, nil
}

// Client.StationTransformSharedStation copies a shared station and creates a user-editable station.
// Calls API method "station.transformSharedStation"
func (c *Client) StationTransformSharedStation(stationToken string) (*responses.StationTransformSharedStation, error) {
	requestData := requests.StationTransformSharedStation{
		StationToken:  stationToken,
		UserAuthToken: c.userAuthToken,
		SyncTime:      c.GetSyncTime(),
	}
	requestDataEncoded, err := json.Marshal(requestData)
	if err != nil {
		return nil, err
	}
	requestDataReader := bytes.NewReader(requestDataEncoded)

	var resp responses.StationTransformSharedStation
	err = c.BlowfishCall("http://", "station.transformSharedStation", requestDataReader, &resp)
	if err != nil {
		return nil, err
	}
	return &resp, nil
}
<|endoftext|>


<commit_before>package bosh

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"

	"github.com/EngineerBetter/concourse-up/db"
)

const concourseManifestFilename = "concourse.yml"
const credsFilename = "concourse-creds.yml"
const concourseDeploymentName = "concourse"
const concourseVersionsFilename = "versions.json"
const concourseGrafanaFilename = "grafana_dashboard.yml"
const concourseCompatibilityFilename = "cup_compatibility.yml"

func (client *Client) uploadConcourseStemcell() error {
	var ops []struct {
		Path  string
		Value json.RawMessage
	}
	err := json.Unmarshal(awsConcourseVersions, &ops)
	if err != nil {
		return err
	}
	var version string
	for _, op := range ops {
		if op.Path != "/stemcells/alias=xenial/version" {
			continue
		}
		err := json.Unmarshal(op.Value, &version)
		if err != nil {
			return err
		}
	}
	if version == "" {
		return errors.New("did not find stemcell version in versions.json")
	}
	return client.director.RunAuthenticatedCommand(
		client.stdout,
		client.stderr,
		false,
		"upload-stemcell",
		fmt.Sprintf("https://s3.amazonaws.com/bosh-aws-light-stemcells/light-bosh-stemcell-%s-aws-xen-hvm-ubuntu-xenial-go_agent.tgz", version),
	)
}

func (client *Client) deployConcourse(creds []byte, detach bool) (newCreds []byte, err error) {

	concourseManifestPath, err := client.director.SaveFileToWorkingDir(concourseManifestFilename, awsConcourseManifest)
	if err != nil {
		return
	}

	concourseVersionsPath, err := client.director.SaveFileToWorkingDir(concourseVersionsFilename, awsConcourseVersions)
	if err != nil {
		return
	}

	concourseCompatibilityPath, err := client.director.SaveFileToWorkingDir(concourseCompatibilityFilename, awsConcourseCompatibility)
	if err != nil {
		return
	}

	concourseGrafanaPath, err := client.director.SaveFileToWorkingDir(concourseGrafanaFilename, awsConcourseGrafana)
	if err != nil {
		return
	}

	credsPath, err := client.director.SaveFileToWorkingDir(credsFilename, creds)
	if err != nil {
		return
	}

	vmap := map[string]interface{}{
		"deployment_name":          concourseDeploymentName,
		"domain":                   client.config.Domain,
		"project":                  client.config.Project,
		"web_network_name":         "public",
		"worker_network_name":      "private",
		"postgres_host":            client.metadata.BoshDBAddress.Value,
		"postgres_port":            client.metadata.BoshDBPort.Value,
		"postgres_role":            client.config.RDSUsername,
		"postgres_password":        client.config.RDSPassword,
		"postgres_ca_cert":         db.RDSRootCert,
		"web_vm_type":              "concourse-web-" + client.config.ConcourseWebSize,
		"worker_vm_type":           "concourse-" + client.config.ConcourseWorkerSize,
		"worker_count":             client.config.ConcourseWorkerCount,
		"atc_eip":                  client.metadata.ATCPublicIP.Value,
		"external_tls.certificate": client.config.ConcourseCert,
		"external_tls.private_key": client.config.ConcourseKey,
	}

	if client.config.ConcoursePassword != "" {
		vmap["atc_password"] = client.config.ConcoursePassword
	}

	vs := vars(vmap)

	err = client.director.RunAuthenticatedCommand(
		client.stdout,
		client.stderr,
		detach,
		append([]string{
			"--deployment",
			concourseDeploymentName,
			"deploy",
			concourseManifestPath,
			"--vars-store",
			credsPath,
			"--ops-file",
			concourseVersionsPath,
			"--ops-file",
			concourseCompatibilityPath,
			"--vars-file",
			concourseGrafanaPath,
		},
			vs...)...,
	)
	newCreds, err1 := ioutil.ReadFile(credsPath)
	if err == nil {
		err = err1
	}
	return
}

func vars(vars map[string]interface{}) []string {
	var x []string
	for k, v := range vars {
		switch v_ := v.(type) {
		case string:
			x = append(x, "--var", fmt.Sprintf("%s=%q", k, v_))
		case int:
			x = append(x, "--var", fmt.Sprintf("%s=%d", k, v_))
		default:
			panic("unsupported type")
		}
	}
	return x
}

//go:generate go-bindata -pkg $GOPACKAGE  assets/... ../resources/...
var awsConcourseGrafana = MustAsset("assets/grafana_dashboard.yml")
var awsConcourseCompatibility = MustAsset("assets/ops/cup_compatibility.yml")
var awsConcourseManifest = MustAsset("../resources/manifest.yml")
var awsConcourseVersions = MustAsset("../resources/versions.json")
<commit_msg>make golint happy<commit_after>package bosh

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"

	"github.com/EngineerBetter/concourse-up/db"
)

const concourseManifestFilename = "concourse.yml"
const credsFilename = "concourse-creds.yml"
const concourseDeploymentName = "concourse"
const concourseVersionsFilename = "versions.json"
const concourseGrafanaFilename = "grafana_dashboard.yml"
const concourseCompatibilityFilename = "cup_compatibility.yml"

func (client *Client) uploadConcourseStemcell() error {
	var ops []struct {
		Path  string
		Value json.RawMessage
	}
	err := json.Unmarshal(awsConcourseVersions, &ops)
	if err != nil {
		return err
	}
	var version string
	for _, op := range ops {
		if op.Path != "/stemcells/alias=xenial/version" {
			continue
		}
		err := json.Unmarshal(op.Value, &version)
		if err != nil {
			return err
		}
	}
	if version == "" {
		return errors.New("did not find stemcell version in versions.json")
	}
	return client.director.RunAuthenticatedCommand(
		client.stdout,
		client.stderr,
		false,
		"upload-stemcell",
		fmt.Sprintf("https://s3.amazonaws.com/bosh-aws-light-stemcells/light-bosh-stemcell-%s-aws-xen-hvm-ubuntu-xenial-go_agent.tgz", version),
	)
}

func (client *Client) deployConcourse(creds []byte, detach bool) (newCreds []byte, err error) {

	concourseManifestPath, err := client.director.SaveFileToWorkingDir(concourseManifestFilename, awsConcourseManifest)
	if err != nil {
		return
	}

	concourseVersionsPath, err := client.director.SaveFileToWorkingDir(concourseVersionsFilename, awsConcourseVersions)
	if err != nil {
		return
	}

	concourseCompatibilityPath, err := client.director.SaveFileToWorkingDir(concourseCompatibilityFilename, awsConcourseCompatibility)
	if err != nil {
		return
	}

	concourseGrafanaPath, err := client.director.SaveFileToWorkingDir(concourseGrafanaFilename, awsConcourseGrafana)
	if err != nil {
		return
	}

	credsPath, err := client.director.SaveFileToWorkingDir(credsFilename, creds)
	if err != nil {
		return
	}

	vmap := map[string]interface{}{
		"deployment_name":          concourseDeploymentName,
		"domain":                   client.config.Domain,
		"project":                  client.config.Project,
		"web_network_name":         "public",
		"worker_network_name":      "private",
		"postgres_host":            client.metadata.BoshDBAddress.Value,
		"postgres_port":            client.metadata.BoshDBPort.Value,
		"postgres_role":            client.config.RDSUsername,
		"postgres_password":        client.config.RDSPassword,
		"postgres_ca_cert":         db.RDSRootCert,
		"web_vm_type":              "concourse-web-" + client.config.ConcourseWebSize,
		"worker_vm_type":           "concourse-" + client.config.ConcourseWorkerSize,
		"worker_count":             client.config.ConcourseWorkerCount,
		"atc_eip":                  client.metadata.ATCPublicIP.Value,
		"external_tls.certificate": client.config.ConcourseCert,
		"external_tls.private_key": client.config.ConcourseKey,
	}

	if client.config.ConcoursePassword != "" {
		vmap["atc_password"] = client.config.ConcoursePassword
	}

	vs := vars(vmap)

	err = client.director.RunAuthenticatedCommand(
		client.stdout,
		client.stderr,
		detach,
		append([]string{
			"--deployment",
			concourseDeploymentName,
			"deploy",
			concourseManifestPath,
			"--vars-store",
			credsPath,
			"--ops-file",
			concourseVersionsPath,
			"--ops-file",
			concourseCompatibilityPath,
			"--vars-file",
			concourseGrafanaPath,
		},
			vs...)...,
	)
	newCreds, err1 := ioutil.ReadFile(credsPath)
	if err == nil {
		err = err1
	}
	return
}

func vars(vars map[string]interface{}) []string {
	var x []string
	for k, v := range vars {
		switch v.(type) {
		case string:
			x = append(x, "--var", fmt.Sprintf("%s=%q", k, v))
		case int:
			x = append(x, "--var", fmt.Sprintf("%s=%d", k, v))
		default:
			panic("unsupported type")
		}
	}
	return x
}

//go:generate go-bindata -pkg $GOPACKAGE  assets/... ../resources/...
var awsConcourseGrafana = MustAsset("assets/grafana_dashboard.yml")
var awsConcourseCompatibility = MustAsset("assets/ops/cup_compatibility.yml")
var awsConcourseManifest = MustAsset("../resources/manifest.yml")
var awsConcourseVersions = MustAsset("../resources/versions.json")
<|endoftext|>


<commit_before>//
// Copyright 2018, Patrick Webster
//
// 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 gitlab

import "time"

// LicenseService handles communication with the license
// related methods of the GitLab API.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/license.html
type LicenseService struct {
	client *Client
}

// License represents a GitLab license.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/license.html
type License struct {
	ID               int        `json:"id"`
	Plan             string     `json:"plan"`
	CreatedAt        *time.Time `json:"created_at"`
	StartsAt         *ISOTime   `json:"starts_at"`
	ExpiresAt        *ISOTime   `json:"expires_at"`
	HistoricalMax    int        `json:"historical_max"`
	MaximumUserCount int        `json:"maximum_user_count"`
	Expired          bool       `json:"expired"`
	Overage          int        `json:"overage"`
	UserLimit        int        `json:"user_limit"`
	ActiveUsers      int        `json:"active_users"`
	Licensee         struct {
		Name    string `json:"Name"`
		Company string `json:"Company"`
		Email   string `json:"Email"`
	} `json:"licensee"`
	AddOns struct {
		GitLabFileLocks int `json:"GitLabFileLocks"`
	} `json:"add_ons"`
}

func (l License) String() string {
	return Stringify(l)
}

// GetLicense retrieves information about the current license.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/license.html#retrieve-information-about-the-current-license
func (s *LicenseService) GetLicense() (*License, *Response, error) {
	req, err := s.client.NewRequest("GET", "license", nil, nil)
	if err != nil {
		return nil, nil, err
	}

	l := new(License)
	resp, err := s.client.Do(req, l)
	if err != nil {
		return nil, resp, err
	}

	return l, resp, err
}

// AddLicenseOptions represents the available AddLicense() options.
//
// https://docs.gitlab.com/ee/api/license.html#add-a-new-license
type AddLicenseOptions struct {
	License *string `url:"license" json:"license"`
}

// AddLicense adds a new license.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/license.html#add-a-new-license
func (s *LicenseService) AddLicense(opt *AddLicenseOptions, options ...RequestOptionFunc) (*License, *Response, error) {
	req, err := s.client.NewRequest("POST", "license", opt, options)
	if err != nil {
		return nil, nil, err
	}

	l := new(License)
	resp, err := s.client.Do(req, l)
	if err != nil {
		return nil, resp, err
	}

	return l, resp, err
}
<commit_msg>Update license addons<commit_after>//
// Copyright 2018, Patrick Webster
//
// 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 gitlab

import "time"

// LicenseService handles communication with the license
// related methods of the GitLab API.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/license.html
type LicenseService struct {
	client *Client
}

// License represents a GitLab license.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/license.html
type License struct {
	ID               int        `json:"id"`
	Plan             string     `json:"plan"`
	CreatedAt        *time.Time `json:"created_at"`
	StartsAt         *ISOTime   `json:"starts_at"`
	ExpiresAt        *ISOTime   `json:"expires_at"`
	HistoricalMax    int        `json:"historical_max"`
	MaximumUserCount int        `json:"maximum_user_count"`
	Expired          bool       `json:"expired"`
	Overage          int        `json:"overage"`
	UserLimit        int        `json:"user_limit"`
	ActiveUsers      int        `json:"active_users"`
	Licensee         struct {
		Name    string `json:"Name"`
		Company string `json:"Company"`
		Email   string `json:"Email"`
	} `json:"licensee"`
	AddOns struct {
		GitLabFileLocks   int `json:"GitLab_FileLocks"`
		GitLabAuditorUser int `json:"GitLab_Auditor_User"`
	} `json:"add_ons"`
}

func (l License) String() string {
	return Stringify(l)
}

// GetLicense retrieves information about the current license.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/license.html#retrieve-information-about-the-current-license
func (s *LicenseService) GetLicense() (*License, *Response, error) {
	req, err := s.client.NewRequest("GET", "license", nil, nil)
	if err != nil {
		return nil, nil, err
	}

	l := new(License)
	resp, err := s.client.Do(req, l)
	if err != nil {
		return nil, resp, err
	}

	return l, resp, err
}

// AddLicenseOptions represents the available AddLicense() options.
//
// https://docs.gitlab.com/ee/api/license.html#add-a-new-license
type AddLicenseOptions struct {
	License *string `url:"license" json:"license"`
}

// AddLicense adds a new license.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/license.html#add-a-new-license
func (s *LicenseService) AddLicense(opt *AddLicenseOptions, options ...RequestOptionFunc) (*License, *Response, error) {
	req, err := s.client.NewRequest("POST", "license", opt, options)
	if err != nil {
		return nil, nil, err
	}

	l := new(License)
	resp, err := s.client.Do(req, l)
	if err != nil {
		return nil, resp, err
	}

	return l, resp, err
}
<|endoftext|>


<commit_before>// golist is a Go utility for producing readable Go source listings
// using markdown. There are two rules it uses in producing these
// markdown listings:
//
// 1. lines beginning with a double slash are treated as markdown text.
// 2. all other lines are indented with a tab; according to markdown's
// syntax, this should produce a code listing.
//
// Currently, the only output formats supported are writing to standard out
// or a markdown file.
package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
        "io/ioutil"
	"os"
	"regexp"
	"time"
)

const DefaultDateFormat = "2006-01-02 15:04:05 MST"

var (
	CommentLine = regexp.MustCompile("^\\s*//\\s*")
	DateFormat  = DefaultDateFormat
        OutputFormats map[string]OutputWriter
)

// An output writer takes markdown source and an output file name, and
// handles its output, whether writing to a file or displaying to screen.
type OutputWriter func(string, string) error

func init() {
        OutputFormats = make(map[string]OutputWriter, 0)
        OutputFormats["-"] = ScreenWriter
        OutputFormats["html"] = HtmlWriter
        OutputFormats["md"] = MarkdownWriter
}

// SourceToMarkdown takes a file and returns a string containing the
// source converted to markdown.
func SourceToMarkdown(filename string) (markdown string, err error) {
	file, err := os.Open(filename)
	if err != nil {
		return
	}
	defer file.Close()
	buf := bufio.NewReader(file)

	var (
		line      string
		longLine  bool
		lineBytes []byte
		isPrefix  bool
		comment   bool
	)

	markdown += "## " + filename + "\n"
	printDate := time.Now().Format(DateFormat)
	markdown += "### " + printDate + "\n\n"

	for {
		err = nil
		lineBytes, isPrefix, err = buf.ReadLine()
		if io.EOF == err {
			err = nil
			break
		} else if err != nil {
			break
		} else if isPrefix {
			line += string(lineBytes)

			longLine = true
			continue
		} else if longLine {
			line += string(lineBytes)
			longLine = false
		} else {
			line = string(lineBytes)
		}

		if CommentLine.MatchString(line) {
			if !comment {
				markdown += "\n"
			}
			markdown += CommentLine.ReplaceAllString(line, "")
			comment = true
		} else {
			// The comment flag is used to trigger a newline
			// before a codeblock; in some markdown
			// implementations, not doing this will cause the code
                        // block to not be displayed properly.
			if comment {
				markdown += "  \n"
				comment = false
			}
			markdown += "\t"
			markdown += line
		}
		markdown += "\n"
	}
	return
}

func main() {
	fDateFormat := flag.String("t", DefaultDateFormat,
		"specify a format for the listing date")
        fOutputFormat := flag.String("o", "-", "output format")
	flag.Parse()

	DateFormat = *fDateFormat
        outHandler, ok := OutputFormats[*fOutputFormat]
        if !ok {
                fmt.Printf("[!] %s is not a supported output format.\n",
                        *fOutputFormat)
                fmt.Println("Supported formats:")
                fmt.Println("\t-        write markdown to standard output")
                fmt.Println("\tmd       write markdown to file")
                os.Exit(1)
        }

        for _, sourceFile := range flag.Args() {
                md, err := SourceToMarkdown(sourceFile)
                if err != nil {
                        fmt.Fprintf(os.Stderr,
                                "[!] couldn't convert %s to markdown: %s\n",
                                sourceFile, err.Error())
                        continue
                }
                if err := outHandler(md, sourceFile); err != nil {
                        fmt.Fprintf(os.Stderr,
                                "[!] couldn't convert %s to markdown: %s\n",
                                sourceFile, err.Error())
                }
        }

}

// ScreenWriter prints the markdown to standard output.
func ScreenWriter(markdown string, filename string) (err error) {
        _, err = fmt.Println(markdown)
        return
}

// MarkdownWriter writes the markdown listing to a file.
func MarkdownWriter(markdown string, filename string) (err error) {
        err = ioutil.WriteFile(filename + ".md", []byte(markdown), 0644)
        return
}
<commit_msg>add html to output format list<commit_after>// golist is a Go utility for producing readable Go source listings
// using markdown. There are two rules it uses in producing these
// markdown listings:
//
// 1. lines beginning with a double slash are treated as markdown text.
// 2. all other lines are indented with a tab; according to markdown's
// syntax, this should produce a code listing.
//
// Currently, the only output formats supported are writing to standard out
// or a markdown file.
package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
        "io/ioutil"
	"os"
	"regexp"
	"time"
)

const DefaultDateFormat = "2006-01-02 15:04:05 MST"

var (
	CommentLine = regexp.MustCompile("^\\s*//\\s*")
	DateFormat  = DefaultDateFormat
        OutputFormats map[string]OutputWriter
)

// An output writer takes markdown source and an output file name, and
// handles its output, whether writing to a file or displaying to screen.
type OutputWriter func(string, string) error

func init() {
        OutputFormats = make(map[string]OutputWriter, 0)
        OutputFormats["-"] = ScreenWriter
        OutputFormats["html"] = HtmlWriter
        OutputFormats["md"] = MarkdownWriter
}

// SourceToMarkdown takes a file and returns a string containing the
// source converted to markdown.
func SourceToMarkdown(filename string) (markdown string, err error) {
	file, err := os.Open(filename)
	if err != nil {
		return
	}
	defer file.Close()
	buf := bufio.NewReader(file)

	var (
		line      string
		longLine  bool
		lineBytes []byte
		isPrefix  bool
		comment   bool
	)

	markdown += "## " + filename + "\n"
	printDate := time.Now().Format(DateFormat)
	markdown += "### " + printDate + "\n\n"

	for {
		err = nil
		lineBytes, isPrefix, err = buf.ReadLine()
		if io.EOF == err {
			err = nil
			break
		} else if err != nil {
			break
		} else if isPrefix {
			line += string(lineBytes)

			longLine = true
			continue
		} else if longLine {
			line += string(lineBytes)
			longLine = false
		} else {
			line = string(lineBytes)
		}

		if CommentLine.MatchString(line) {
			if !comment {
				markdown += "\n"
			}
			markdown += CommentLine.ReplaceAllString(line, "")
			comment = true
		} else {
			// The comment flag is used to trigger a newline
			// before a codeblock; in some markdown
			// implementations, not doing this will cause the code
                        // block to not be displayed properly.
			if comment {
				markdown += "  \n"
				comment = false
			}
			markdown += "\t"
			markdown += line
		}
		markdown += "\n"
	}
	return
}

func main() {
	fDateFormat := flag.String("t", DefaultDateFormat,
		"specify a format for the listing date")
        fOutputFormat := flag.String("o", "-", "output format")
	flag.Parse()

	DateFormat = *fDateFormat
        outHandler, ok := OutputFormats[*fOutputFormat]
        if !ok {
                fmt.Printf("[!] %s is not a supported output format.\n",
                        *fOutputFormat)
                fmt.Println("Supported formats:")
                fmt.Println("\t-        write markdown to standard output")
                fmt.Println("\thtml     produce an HTML listing")
                fmt.Println("\tmd       write markdown to file")
                os.Exit(1)
        }

        for _, sourceFile := range flag.Args() {
                md, err := SourceToMarkdown(sourceFile)
                if err != nil {
                        fmt.Fprintf(os.Stderr,
                                "[!] couldn't convert %s to markdown: %s\n",
                                sourceFile, err.Error())
                        continue
                }
                if err := outHandler(md, sourceFile); err != nil {
                        fmt.Fprintf(os.Stderr,
                                "[!] couldn't convert %s to markdown: %s\n",
                                sourceFile, err.Error())
                }
        }

}

// ScreenWriter prints the markdown to standard output.
func ScreenWriter(markdown string, filename string) (err error) {
        _, err = fmt.Println(markdown)
        return
}

// MarkdownWriter writes the markdown listing to a file.
func MarkdownWriter(markdown string, filename string) (err error) {
        err = ioutil.WriteFile(filename + ".md", []byte(markdown), 0644)
        return
}
<|endoftext|>


<commit_before>package ln

type Mesh struct {
	Box       Box
	Triangles []*Triangle
	Tree      *Tree
}

func NewMesh(triangles []*Triangle) *Mesh {
	box := BoxForTriangles(triangles)
	return &Mesh{box, triangles, nil}
}

func (m *Mesh) Compile() {
	if m.Tree == nil {
		shapes := make([]Shape, len(m.Triangles))
		for i, triangle := range m.Triangles {
			shapes[i] = triangle
		}
		m.Tree = NewTree(shapes)
	}
}

func (m *Mesh) BoundingBox() Box {
	return m.Box
}

func (m *Mesh) Intersect(r Ray) Hit {
	return m.Tree.Intersect(r)
}

func (m *Mesh) Paths() Paths {
	var result Paths
	for _, t := range m.Triangles {
		result = append(result, t.Paths()...)
	}
	return result
}

func (m *Mesh) UpdateBoundingBox() {
	m.Box = BoxForTriangles(m.Triangles)
}

func (m *Mesh) UnitCube() {
	m.FitInside(Box{Vector{}, Vector{1, 1, 1}}, Vector{})
	m.MoveTo(Vector{}, Vector{0.5, 0.5, 0.5})
}

func (m *Mesh) MoveTo(position, anchor Vector) {
	matrix := Translate(position.Sub(m.Box.Anchor(anchor)))
	m.Transform(matrix)
}

func (m *Mesh) FitInside(box Box, anchor Vector) {
	scale := box.Size().Div(m.BoundingBox().Size()).MinComponent()
	extra := box.Size().Sub(m.BoundingBox().Size().MulScalar(scale))
	matrix := Identity()
	matrix = matrix.Translate(m.BoundingBox().Min.MulScalar(-1))
	matrix = matrix.Scale(Vector{scale, scale, scale})
	matrix = matrix.Translate(box.Min.Add(extra.Mul(anchor)))
	m.Transform(matrix)
}

func (m *Mesh) Transform(matrix Matrix) {
	for _, t := range m.Triangles {
		t.V1 = matrix.MulPosition(t.V1)
		t.V2 = matrix.MulPosition(t.V2)
		t.V3 = matrix.MulPosition(t.V3)
		t.UpdateBoundingBox()
	}
	m.UpdateBoundingBox()
	m.Tree = nil // dirty
}

func (m *Mesh) SaveBinarySTL(path string) error {
	return SaveBinarySTL(path, m)
}
<commit_msg>Mesh.Contains<commit_after>package ln

type Mesh struct {
	Box       Box
	Triangles []*Triangle
	Tree      *Tree
}

func NewMesh(triangles []*Triangle) *Mesh {
	box := BoxForTriangles(triangles)
	return &Mesh{box, triangles, nil}
}

func (m *Mesh) Compile() {
	if m.Tree == nil {
		shapes := make([]Shape, len(m.Triangles))
		for i, triangle := range m.Triangles {
			shapes[i] = triangle
		}
		m.Tree = NewTree(shapes)
	}
}

func (m *Mesh) BoundingBox() Box {
	return m.Box
}

func (m *Mesh) Contains(v Vector, f float64) bool {
	return false
}

func (m *Mesh) Intersect(r Ray) Hit {
	return m.Tree.Intersect(r)
}

func (m *Mesh) Paths() Paths {
	var result Paths
	for _, t := range m.Triangles {
		result = append(result, t.Paths()...)
	}
	return result
}

func (m *Mesh) UpdateBoundingBox() {
	m.Box = BoxForTriangles(m.Triangles)
}

func (m *Mesh) UnitCube() {
	m.FitInside(Box{Vector{}, Vector{1, 1, 1}}, Vector{})
	m.MoveTo(Vector{}, Vector{0.5, 0.5, 0.5})
}

func (m *Mesh) MoveTo(position, anchor Vector) {
	matrix := Translate(position.Sub(m.Box.Anchor(anchor)))
	m.Transform(matrix)
}

func (m *Mesh) FitInside(box Box, anchor Vector) {
	scale := box.Size().Div(m.BoundingBox().Size()).MinComponent()
	extra := box.Size().Sub(m.BoundingBox().Size().MulScalar(scale))
	matrix := Identity()
	matrix = matrix.Translate(m.BoundingBox().Min.MulScalar(-1))
	matrix = matrix.Scale(Vector{scale, scale, scale})
	matrix = matrix.Translate(box.Min.Add(extra.Mul(anchor)))
	m.Transform(matrix)
}

func (m *Mesh) Transform(matrix Matrix) {
	for _, t := range m.Triangles {
		t.V1 = matrix.MulPosition(t.V1)
		t.V2 = matrix.MulPosition(t.V2)
		t.V3 = matrix.MulPosition(t.V3)
		t.UpdateBoundingBox()
	}
	m.UpdateBoundingBox()
	m.Tree = nil // dirty
}

func (m *Mesh) SaveBinarySTL(path string) error {
	return SaveBinarySTL(path, m)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"github.com/gokyle/sshkey"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

func ReadPrompt(prompt string) (in string, err error) {
	fmt.Printf("%s", prompt)
	rd := bufio.NewReader(os.Stdin)
	line, err := rd.ReadString('\n')
	if err != nil {
		return
	}
	in = strings.TrimSpace(line)
	return
}

func checkKeyType(keytype string) {
	switch keytype {
	case "rsa":
		return
	case "ecdsa":
		return
	default:
		fmt.Println("bad key type")
		os.Exit(1)
	}
}

func checkErr(err error) {
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	}
}

func main() {
	flComment := flag.String("c", "", "key comment")
	flFile := flag.String("f", "", "input keyfile")
	flFpr := flag.Bool("l", false, "show fingerprint of keyfile")
	flType := flag.String("t", "ecdsa", "type of key to create")
	flSize := flag.Int("b", 256, "bitsize of key to create")
	flag.Parse()

	checkKeyType(*flType)
	if *flComment == "" {
		*flComment = getDefaultComment()
	}

	if *flType == "rsa" && *flSize == 256 {
		*flSize = 2048
	}

	if *flFpr {
		fingerprint(*flFile, *flType)
	} else {
		keygen(*flFile, *flType, *flComment, *flSize)
	}
}

func defaultKey(keytype string) string {
	home := os.Getenv("HOME")
	defkey := filepath.Join(home, ".ssh", "id_"+keytype)
	return defkey
}

func fingerprint(keyfile string, keytype string) {
	var err error

	if keyfile == "" {
		defkey := defaultKey(keytype)
		defkey += ".pub"
		prompt := fmt.Sprintf("Enter file in which the key is (%s): ", defkey)
		keyfile, err = ReadPrompt(prompt)
		checkErr(err)
		if keyfile == "" {
			keyfile = defkey
		}
	}
	pub, err := sshkey.LoadPublicKeyFile(keyfile, true)
	checkErr(err)

	fpr, err := sshkey.FingerprintPretty(pub, 0)
	checkErr(err)

	comment := pub.Comment
	if comment == "" {
		comment = keyfile
	}

	fmt.Printf("%d %s %s (%s)\n", pub.Size(), fpr, comment, strings.ToUpper(keytype))
	os.Exit(0)
}

func keygen(keyfile, keytype, comment string, size int) {
	var (
		err error
		key interface{}
	)

	switch keytype {
	case "rsa":
		fmt.Println("Generating public/private rsa key pair.")
		key, err = sshkey.GenerateKey(sshkey.KEY_RSA, size)
		checkErr(err)
	case "ecdsa":
		fmt.Println("Generating public/private ecdsa key pair.")
		key, err = sshkey.GenerateKey(sshkey.KEY_ECDSA, size)
		checkErr(err)
	}

	if keyfile == "" {
		defkey := defaultKey(keytype)
		prompt := fmt.Sprintf("Enter file in which to save the key (%s): ", defkey)
		keyfile, err = ReadPrompt(prompt)
		checkErr(err)
		if keyfile == "" {
			keyfile = defkey
		}
	}

	if _, err = os.Stat(keyfile); !os.IsNotExist(err) {
		fmt.Printf("%s already exists.\n", keyfile)
                yn, err := ReadPrompt("Overwrite (y/n)? ")
                checkErr(err)
                if strings.ToUpper(string(yn[0])) != "Y" {
		        os.Exit(1)
                }
	}

	var password string
	for {
		password, err = sshkey.PasswordPrompt("Enter password (empty for no passphrase): ")
		checkErr(err)
		if password != "" {
			var password2 string
			password2, err = sshkey.PasswordPrompt("Enter password again: ")
			checkErr(err)
			if password != password2 {
				fmt.Println("Passphrases do not match. Try again.")
				continue
			}
			break
		} else {
			break
		}
	}

        if password != "" && len(password) < 5 {
                fmt.Printf("passphrase too short: have %d bytes, need > 4\n",
                        len(password))
                fmt.Println("Saving the key failed:", keyfile)
        }

	privout, err := sshkey.MarshalPrivate(key, password)
	checkErr(err)

	pub := sshkey.NewPublic(key, comment)
	if key == nil {
		fmt.Println("Failed to create a public key.")
		os.Exit(1)
	}

	pubout := sshkey.MarshalPublic(pub)
	if pubout == nil {
		fmt.Println("Failed to create a public key.")
		os.Exit(1)
	}

	err = ioutil.WriteFile(keyfile, privout, 0600)
	checkErr(err)
	err = ioutil.WriteFile(keyfile+".pub", pubout, 0644)
	checkErr(err)
}

func getDefaultComment() string {
	cmd := exec.Command("whoami")
	out, err := cmd.Output()
	if err != nil {
		return ""
	}
	whoami := strings.TrimSpace(string(out))

	cmd = exec.Command("hostname")
	out, err = cmd.Output()
	if err != nil {
		return ""
	}
	hostname := strings.TrimSpace(string(out))

	return fmt.Sprintf("%s@%s", whoami, hostname)
}
<commit_msg>Exit when given a short pass.<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"github.com/gokyle/sshkey"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

func ReadPrompt(prompt string) (in string, err error) {
	fmt.Printf("%s", prompt)
	rd := bufio.NewReader(os.Stdin)
	line, err := rd.ReadString('\n')
	if err != nil {
		return
	}
	in = strings.TrimSpace(line)
	return
}

func checkKeyType(keytype string) {
	switch keytype {
	case "rsa":
		return
	case "ecdsa":
		return
	default:
		fmt.Println("bad key type")
		os.Exit(1)
	}
}

func checkErr(err error) {
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	}
}

func main() {
	flComment := flag.String("c", "", "key comment")
	flFile := flag.String("f", "", "input keyfile")
	flFpr := flag.Bool("l", false, "show fingerprint of keyfile")
	flType := flag.String("t", "ecdsa", "type of key to create")
	flSize := flag.Int("b", 256, "bitsize of key to create")
	flag.Parse()

	checkKeyType(*flType)
	if *flComment == "" {
		*flComment = getDefaultComment()
	}

	if *flType == "rsa" && *flSize == 256 {
		*flSize = 2048
	}

	if *flFpr {
		fingerprint(*flFile, *flType)
	} else {
		keygen(*flFile, *flType, *flComment, *flSize)
	}
}

func defaultKey(keytype string) string {
	home := os.Getenv("HOME")
	defkey := filepath.Join(home, ".ssh", "id_"+keytype)
	return defkey
}

func fingerprint(keyfile string, keytype string) {
	var err error

	if keyfile == "" {
		defkey := defaultKey(keytype)
		defkey += ".pub"
		prompt := fmt.Sprintf("Enter file in which the key is (%s): ", defkey)
		keyfile, err = ReadPrompt(prompt)
		checkErr(err)
		if keyfile == "" {
			keyfile = defkey
		}
	}
	pub, err := sshkey.LoadPublicKeyFile(keyfile, true)
	checkErr(err)

	fpr, err := sshkey.FingerprintPretty(pub, 0)
	checkErr(err)

	comment := pub.Comment
	if comment == "" {
		comment = keyfile
	}

	fmt.Printf("%d %s %s (%s)\n", pub.Size(), fpr, comment, strings.ToUpper(keytype))
	os.Exit(0)
}

func keygen(keyfile, keytype, comment string, size int) {
	var (
		err error
		key interface{}
	)

	switch keytype {
	case "rsa":
		fmt.Println("Generating public/private rsa key pair.")
		key, err = sshkey.GenerateKey(sshkey.KEY_RSA, size)
		checkErr(err)
	case "ecdsa":
		fmt.Println("Generating public/private ecdsa key pair.")
		key, err = sshkey.GenerateKey(sshkey.KEY_ECDSA, size)
		checkErr(err)
	}

	if keyfile == "" {
		defkey := defaultKey(keytype)
		prompt := fmt.Sprintf("Enter file in which to save the key (%s): ", defkey)
		keyfile, err = ReadPrompt(prompt)
		checkErr(err)
		if keyfile == "" {
			keyfile = defkey
		}
	}

	if _, err = os.Stat(keyfile); !os.IsNotExist(err) {
		fmt.Printf("%s already exists.\n", keyfile)
                yn, err := ReadPrompt("Overwrite (y/n)? ")
                checkErr(err)
                if strings.ToUpper(string(yn[0])) != "Y" {
		        os.Exit(1)
                }
	}

	var password string
	for {
		password, err = sshkey.PasswordPrompt("Enter password (empty for no passphrase): ")
		checkErr(err)
		if password != "" {
			var password2 string
			password2, err = sshkey.PasswordPrompt("Enter password again: ")
			checkErr(err)
			if password != password2 {
				fmt.Println("Passphrases do not match. Try again.")
				continue
			}
			break
		} else {
			break
		}
	}

        if password != "" && len(password) < 5 {
                fmt.Printf("passphrase too short: have %d bytes, need > 4\n",
                        len(password))
                fmt.Println("Saving the key failed:", keyfile)
		os.Exit(1)
        }

	privout, err := sshkey.MarshalPrivate(key, password)
	checkErr(err)

	pub := sshkey.NewPublic(key, comment)
	if key == nil {
		fmt.Println("Failed to create a public key.")
		os.Exit(1)
	}

	pubout := sshkey.MarshalPublic(pub)
	if pubout == nil {
		fmt.Println("Failed to create a public key.")
		os.Exit(1)
	}

	err = ioutil.WriteFile(keyfile, privout, 0600)
	checkErr(err)
	err = ioutil.WriteFile(keyfile+".pub", pubout, 0644)
	checkErr(err)
}

func getDefaultComment() string {
	cmd := exec.Command("whoami")
	out, err := cmd.Output()
	if err != nil {
		return ""
	}
	whoami := strings.TrimSpace(string(out))

	cmd = exec.Command("hostname")
	out, err = cmd.Output()
	if err != nil {
		return ""
	}
	hostname := strings.TrimSpace(string(out))

	return fmt.Sprintf("%s@%s", whoami, hostname)
}
<|endoftext|>


<commit_before>///bin/true; exec /usr/bin/env go run "$0" "$@"

package main

import (
	_ "bufio"
	"flag"
	"fmt"
	"github.com/omakoto/mlib"
	_ "io"
	"io/ioutil"
	"os/exec"
	"regexp"
	"strconv"
	"strings"
	"time"
)

var (
	pidPatterns = []*regexp.Regexp{
		// brief
		regexp.MustCompile(`^[A-Z]/.+?\(\s*(\d+)`),
		// process or thread
		regexp.MustCompile(`^[A-Z]\(\s*(\d+)`),
		// threadtime
		regexp.MustCompile(`^\d{2}-\d{2}\s+[\d\:\.]+\s+(\d+)`),
		// time
		regexp.MustCompile(`^\d{2}-\d{2} [\d\:\.]+ [A-Z]\/.*?\(\s*(\d+)`),
		// regexp.MustCompile(`^.*?\(\s*(\d+)`),
		// long
		regexp.MustCompile(`^\[\s*\d{2}-\d{2}\s+[\d\:\.]+\s+(\d+)`),
	}

	diePatterns = []*regexp.Regexp{
		regexp.MustCompile(`ActivityManager.*?Process .*?\(pid (\d+)\) has died`),
		regexp.MustCompile(`ActivityManager.*?Killing (\d+)`),
		// Any more?
	}

	whiteSpaces = regexp.MustCompile(`\s+`)

	// Flags
	// autoflush = flag.Bool("f", false, "autoflush") // ?? Not needed?
	width = flag.Int("w", 40, "formatting width")

	// PID -> process name
	procecces = make(map[int]string)

	// Output line format
	outFormat string
)

const (
	PRE_INITIALIZED                       = "<pre-initialized>"
	MAX_PRE_INITIALIZED_RETRY             = 5
	MAX_PRE_INITIALIZED_RETRY_INTERVAL_MS = 200
)

func getProcessNameFromAdbRaw(pid int) string {
	cmd := exec.Command("adb", "shell", fmt.Sprintf("cat /proc/%d/cmdline 2>/dev/null", pid))
	stdout, err := cmd.StdoutPipe()
	mlib.Check(err)

	err = cmd.Start()
	mlib.Check(err)
	defer cmd.Wait()

	cmdline, err := ioutil.ReadAll(stdout)
	mlib.Check(err)

	procname := string(cmdline)
	procname = strings.TrimRight(procname, "\000")
	return procname
}

// Same as getProcessNameFromAdbRaw, but retries when getting PRE_INITIALIZED
func getProcessNameFromAdb(pid int) string {
	var pname string = "(unknown)"

	for i := 0; i <= MAX_PRE_INITIALIZED_RETRY; i++ {
		rawName := getProcessNameFromAdbRaw(pid)
		if rawName == PRE_INITIALIZED {
			mlib.Debug("%s detected\n", PRE_INITIALIZED)
			time.Sleep(MAX_PRE_INITIALIZED_RETRY_INTERVAL_MS * time.Millisecond)
			continue
		}
		if rawName != "" {
			pname = rawName
		}
		break
	}
	return fmt.Sprintf("%s %d", pname, pid)
}

func getProcessNameWithCache(pid int) string {
	name := procecces[pid]
	if name == "" {
		name = getProcessNameFromAdb(pid)
		procecces[pid] = name
	}
	return name
}

// Run for each line
func processLine(line string) {
	var pid = 0
	var processName = ""

	// Find the pid from the line and get the process name
	for _, re := range pidPatterns {
		s := re.FindStringSubmatch(line)
		if s != nil {
			pid, _ = strconv.Atoi(s[1])
			// mlib.Debug("pid=%d\n", pid)
			processName = getProcessNameWithCache(pid)
			break
		}
	}

	// Any process died?
	for _, re := range diePatterns {
		s := re.FindStringSubmatch(line)
		if s != nil {
			diedPid, _ := strconv.Atoi(s[1])
			mlib.Debug("Process %d died\n", diedPid)
			delete(procecces, diedPid)
			break
		}
	}

	fmt.Printf(outFormat, processName, line)
}

func main() {
	flag.Parse()

	outFormat = fmt.Sprintf("[%%-%ds] %%s", *width)

	for line := range mlib.ReadFilesFromArgs() {
		processLine(line)
	}
}
<commit_msg>Replace \0's in process names to " "s<commit_after>///bin/true; exec /usr/bin/env go run "$0" "$@"

package main

import (
	_ "bufio"
	"flag"
	"fmt"
	"github.com/omakoto/mlib"
	_ "io"
	"io/ioutil"
	"os/exec"
	"regexp"
	"strconv"
	"strings"
	"time"
)

var (
	pidPatterns = []*regexp.Regexp{
		// brief
		regexp.MustCompile(`^[A-Z]/.+?\(\s*(\d+)`),
		// process or thread
		regexp.MustCompile(`^[A-Z]\(\s*(\d+)`),
		// threadtime
		regexp.MustCompile(`^\d{2}-\d{2}\s+[\d\:\.]+\s+(\d+)`),
		// time
		regexp.MustCompile(`^\d{2}-\d{2} [\d\:\.]+ [A-Z]\/.*?\(\s*(\d+)`),
		// regexp.MustCompile(`^.*?\(\s*(\d+)`),
		// long
		regexp.MustCompile(`^\[\s*\d{2}-\d{2}\s+[\d\:\.]+\s+(\d+)`),
	}

	diePatterns = []*regexp.Regexp{
		regexp.MustCompile(`ActivityManager.*?Process .*?\(pid (\d+)\) has died`),
		regexp.MustCompile(`ActivityManager.*?Killing (\d+)`),
		// Any more?
	}

	whiteSpaces = regexp.MustCompile(`\s+`)

	// Flags
	// autoflush = flag.Bool("f", false, "autoflush") // ?? Not needed?
	width = flag.Int("w", 40, "formatting width")

	// PID -> process name
	procecces = make(map[int]string)

	// Output line format
	outFormat string
)

const (
	PRE_INITIALIZED                       = "<pre-initialized>"
	MAX_PRE_INITIALIZED_RETRY             = 5
	MAX_PRE_INITIALIZED_RETRY_INTERVAL_MS = 200
)

func getProcessNameFromAdbRaw(pid int) string {
	cmd := exec.Command("adb", "shell", fmt.Sprintf("cat /proc/%d/cmdline 2>/dev/null", pid))
	stdout, err := cmd.StdoutPipe()
	mlib.Check(err)

	err = cmd.Start()
	mlib.Check(err)
	defer cmd.Wait()

	cmdline, err := ioutil.ReadAll(stdout)
	mlib.Check(err)

	procname := string(cmdline)
	procname = strings.TrimRight(procname, "\000")
	procname = strings.Replace(procname, "\000", " ", -1)
	return procname
}

// Same as getProcessNameFromAdbRaw, but retries when getting PRE_INITIALIZED
func getProcessNameFromAdb(pid int) string {
	var pname string = "(unknown)"

	for i := 0; i <= MAX_PRE_INITIALIZED_RETRY; i++ {
		rawName := getProcessNameFromAdbRaw(pid)
		if rawName == PRE_INITIALIZED {
			mlib.Debug("%s detected\n", PRE_INITIALIZED)
			time.Sleep(MAX_PRE_INITIALIZED_RETRY_INTERVAL_MS * time.Millisecond)
			continue
		}
		if rawName != "" {
			pname = rawName
		}
		break
	}
	return fmt.Sprintf("%s %d", pname, pid)
}

func getProcessNameWithCache(pid int) string {
	name := procecces[pid]
	if name == "" {
		name = getProcessNameFromAdb(pid)
		procecces[pid] = name
	}
	return name
}

// Run for each line
func processLine(line string) {
	var pid = 0
	var processName = ""

	// Find the pid from the line and get the process name
	for _, re := range pidPatterns {
		s := re.FindStringSubmatch(line)
		if s != nil {
			pid, _ = strconv.Atoi(s[1])
			// mlib.Debug("pid=%d\n", pid)
			processName = getProcessNameWithCache(pid)
			break
		}
	}

	// Any process died?
	for _, re := range diePatterns {
		s := re.FindStringSubmatch(line)
		if s != nil {
			diedPid, _ := strconv.Atoi(s[1])
			mlib.Debug("Process %d died\n", diedPid)
			delete(procecces, diedPid)
			break
		}
	}

	fmt.Printf(outFormat, processName, line)
}

func main() {
	flag.Parse()

	outFormat = fmt.Sprintf("[%%-%ds] %%s", *width)

	for line := range mlib.ReadFilesFromArgs() {
		processLine(line)
	}
}
<|endoftext|>