<commit_before>/*-
 * Copyright 2015 Square Inc.
 *
 * 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 main

import (
	"crypto/tls"
	"crypto/x509"
	"io"
	"net"
	"strings"
	"sync"

	"github.com/rcrowley/go-metrics"
)

// Accept incoming connections in server mode and spawn Go routines to handle them.
// The signal handler (serverSignalHandle) can close the listener socket and
// send true to the stopper channel. When that happens, we stop accepting new
// connections and wait for outstanding connections to end.
func serverAccept(listener net.Listener, wg *sync.WaitGroup, stopper chan bool, leaf *x509.Certificate, dial func() (net.Conn, error)) {
	defer wg.Done()
	// TODO: defer listener.Close() is redundant because serverSignalHandler closes
	// the socket.
	defer listener.Close()

	openCounter := metrics.GetOrRegisterCounter("conn.open", metrics.DefaultRegistry)
	totalCounter := metrics.GetOrRegisterCounter("accept.total", metrics.DefaultRegistry)
	successCounter := metrics.GetOrRegisterCounter("accept.success", metrics.DefaultRegistry)
	errorCounter := metrics.GetOrRegisterCounter("accept.error", metrics.DefaultRegistry)
	timer := metrics.GetOrRegisterTimer("conn.lifetime", metrics.DefaultRegistry)

	for {
		// Wait for new connection
		conn, err := listener.Accept()
		openCounter.Inc(1)
		totalCounter.Inc(1)

		if err != nil {
			openCounter.Dec(1)
			errorCounter.Inc(1)

			// Check if we're supposed to stop
			select {
			case _ = <-stopper:
				logger.Printf("closing socket with cert serial no. %d (expiring %s)", leaf.SerialNumber, leaf.NotAfter.String())
				return
			default:
			}

			logger.Printf("error accepting connection: %s", err)
			continue
		}

		logger.Printf("incoming connection: %s", conn.RemoteAddr())

		tlsConn, ok := conn.(*tls.Conn)
		if !ok {
			openCounter.Dec(1)
			errorCounter.Inc(1)
			logger.Printf("received non-TLS connection from %s? ignoring", conn.RemoteAddr())
			conn.Close()
			continue
		}

		// Force handshake. Handshake usually happens on first read/write, but
		// we want to authenticate before reading/writing so we need to force
		// the handshake to get the client cert.
		err = tlsConn.Handshake()
		if err != nil {
			openCounter.Dec(1)
			errorCounter.Inc(1)
			logger.Printf("failed TLS handshake on %s: %s", conn.RemoteAddr(), err)
			conn.Close()
			continue
		}

		if !authorized(tlsConn.ConnectionState()) {
			openCounter.Dec(1)
			errorCounter.Inc(1)
			logger.Printf("rejecting connection from %s: bad client certificate", conn.RemoteAddr())
			conn.Close()
			continue
		}

		logger.Printf("successful handshake with %s", conn.RemoteAddr())

		wg.Add(1)
		go timer.Time(func() {
			defer wg.Done()
			defer conn.Close()
			defer openCounter.Dec(1)
			handle(conn, successCounter, errorCounter, dial)
		})
	}
}

// Accept incoming connections in client mode and spawn Go routines to handle them.
func clientAccept(listener net.Listener, stopper chan bool, dial func() (net.Conn, error)) {
	// TODO: defer listener.Close() is redundant because serverSignalHandler closes
	// the socket.
	defer listener.Close()

	openCounter := metrics.GetOrRegisterCounter("conn.open", metrics.DefaultRegistry)
	totalCounter := metrics.GetOrRegisterCounter("accept.total", metrics.DefaultRegistry)
	successCounter := metrics.GetOrRegisterCounter("accept.success", metrics.DefaultRegistry)
	errorCounter := metrics.GetOrRegisterCounter("accept.error", metrics.DefaultRegistry)
	timer := metrics.GetOrRegisterTimer("conn.lifetime", metrics.DefaultRegistry)

	handlers := &sync.WaitGroup{}

	for {
		// Wait for new conenction
		conn, err := listener.Accept()
		openCounter.Inc(1)
		totalCounter.Inc(1)

		if err != nil {
			openCounter.Dec(1)
			errorCounter.Inc(1)

			// Check if we're supposed to stop
			select {
			case _ = <-stopper:
				logger.Printf("closing listening socket")
				// wait for all the connects to end
				handlers.Wait()
				return
			default:
			}

			logger.Printf("error accepting connection: %s", err)
			continue
		}

		logger.Printf("incoming connection: %s", conn.RemoteAddr())

		handlers.Add(1)
		go timer.Time(func() {
			defer handlers.Done()
			defer conn.Close()
			defer openCounter.Dec(1)
			handle(conn, successCounter, errorCounter, dial)
		})
	}
}

// Handle incoming connection by opening new connection to our backend service
// and fusing them together.
func handle(conn net.Conn, successCounter metrics.Counter, errorCounter metrics.Counter, dial func() (net.Conn, error)) {
	backend, err := dial()

	if err != nil {
		errorCounter.Inc(1)
		logger.Printf("failed to dial backend: %s", err)
		return
	}

	successCounter.Inc(1)
	fuse(conn, backend)
}

// Fuse connections together
func fuse(client, backend net.Conn) {
	// Copy from client -> backend, and from backend -> client
	go func() { copyData(client, backend) }()
	copyData(backend, client)
}

// Copy data between two connections
func copyData(dst net.Conn, src net.Conn) {
	defer dst.Close()
	defer src.Close()
	defer logger.Printf("closed pipe: %s:%s <- %s:%s", dst.RemoteAddr().Network(), dst.RemoteAddr().String(), src.RemoteAddr().Network(), src.RemoteAddr().String())
	logger.Printf("opening pipe: %s:%s <- %s:%s", dst.RemoteAddr().Network(), dst.RemoteAddr().String(), src.RemoteAddr().Network(), src.RemoteAddr().String())

	_, err := io.Copy(dst, src)

	if err != nil {
		logger.Printf("%s", err)
	}
}

// Helper function to decode a *net.TCPAddr into a tuple of network and
// address. Must use this since kavu/so_reuseport does not currently
// support passing "tcp" to support for IPv4 and IPv6. We must pass "tcp4"
// or "tcp6" explicitly.
func decodeAddress(tuple *net.TCPAddr) (network, address string) {
	if tuple.IP.To4() != nil {
		network = "tcp4"
	} else {
		network = "tcp6"
	}

	address = tuple.String()
	return
}

// Parse a string representing a TCP address or UNIX socket for our backend
// target. The input can be or the form "HOST:PORT" for TCP or "unix:PATH"
// for a UNIX socket.
func parseUnixOrTCPAddress(input string) (network, address, host string, err error) {
	if strings.HasPrefix(input, "unix:") {
		network = "unix"
		address = input[5:]
		return
	}

	host, _, err = net.SplitHostPort(input)
	if err != nil {
		return
	}

	var tcp *net.TCPAddr
	tcp, err = net.ResolveTCPAddr("tcp", input)
	if err != nil {
		return
	}

	network, address = decodeAddress(tcp)
	return
}
<commit_msg>spelling: connection<commit_after>/*-
 * Copyright 2015 Square Inc.
 *
 * 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 main

import (
	"crypto/tls"
	"crypto/x509"
	"io"
	"net"
	"strings"
	"sync"

	"github.com/rcrowley/go-metrics"
)

// Accept incoming connections in server mode and spawn Go routines to handle them.
// The signal handler (serverSignalHandle) can close the listener socket and
// send true to the stopper channel. When that happens, we stop accepting new
// connections and wait for outstanding connections to end.
func serverAccept(listener net.Listener, wg *sync.WaitGroup, stopper chan bool, leaf *x509.Certificate, dial func() (net.Conn, error)) {
	defer wg.Done()
	// TODO: defer listener.Close() is redundant because serverSignalHandler closes
	// the socket.
	defer listener.Close()

	openCounter := metrics.GetOrRegisterCounter("conn.open", metrics.DefaultRegistry)
	totalCounter := metrics.GetOrRegisterCounter("accept.total", metrics.DefaultRegistry)
	successCounter := metrics.GetOrRegisterCounter("accept.success", metrics.DefaultRegistry)
	errorCounter := metrics.GetOrRegisterCounter("accept.error", metrics.DefaultRegistry)
	timer := metrics.GetOrRegisterTimer("conn.lifetime", metrics.DefaultRegistry)

	for {
		// Wait for new connection
		conn, err := listener.Accept()
		openCounter.Inc(1)
		totalCounter.Inc(1)

		if err != nil {
			openCounter.Dec(1)
			errorCounter.Inc(1)

			// Check if we're supposed to stop
			select {
			case _ = <-stopper:
				logger.Printf("closing socket with cert serial no. %d (expiring %s)", leaf.SerialNumber, leaf.NotAfter.String())
				return
			default:
			}

			logger.Printf("error accepting connection: %s", err)
			continue
		}

		logger.Printf("incoming connection: %s", conn.RemoteAddr())

		tlsConn, ok := conn.(*tls.Conn)
		if !ok {
			openCounter.Dec(1)
			errorCounter.Inc(1)
			logger.Printf("received non-TLS connection from %s? ignoring", conn.RemoteAddr())
			conn.Close()
			continue
		}

		// Force handshake. Handshake usually happens on first read/write, but
		// we want to authenticate before reading/writing so we need to force
		// the handshake to get the client cert.
		err = tlsConn.Handshake()
		if err != nil {
			openCounter.Dec(1)
			errorCounter.Inc(1)
			logger.Printf("failed TLS handshake on %s: %s", conn.RemoteAddr(), err)
			conn.Close()
			continue
		}

		if !authorized(tlsConn.ConnectionState()) {
			openCounter.Dec(1)
			errorCounter.Inc(1)
			logger.Printf("rejecting connection from %s: bad client certificate", conn.RemoteAddr())
			conn.Close()
			continue
		}

		logger.Printf("successful handshake with %s", conn.RemoteAddr())

		wg.Add(1)
		go timer.Time(func() {
			defer wg.Done()
			defer conn.Close()
			defer openCounter.Dec(1)
			handle(conn, successCounter, errorCounter, dial)
		})
	}
}

// Accept incoming connections in client mode and spawn Go routines to handle them.
func clientAccept(listener net.Listener, stopper chan bool, dial func() (net.Conn, error)) {
	// TODO: defer listener.Close() is redundant because serverSignalHandler closes
	// the socket.
	defer listener.Close()

	openCounter := metrics.GetOrRegisterCounter("conn.open", metrics.DefaultRegistry)
	totalCounter := metrics.GetOrRegisterCounter("accept.total", metrics.DefaultRegistry)
	successCounter := metrics.GetOrRegisterCounter("accept.success", metrics.DefaultRegistry)
	errorCounter := metrics.GetOrRegisterCounter("accept.error", metrics.DefaultRegistry)
	timer := metrics.GetOrRegisterTimer("conn.lifetime", metrics.DefaultRegistry)

	handlers := &sync.WaitGroup{}

	for {
		// Wait for new connection
		conn, err := listener.Accept()
		openCounter.Inc(1)
		totalCounter.Inc(1)

		if err != nil {
			openCounter.Dec(1)
			errorCounter.Inc(1)

			// Check if we're supposed to stop
			select {
			case _ = <-stopper:
				logger.Printf("closing listening socket")
				// wait for all the connects to end
				handlers.Wait()
				return
			default:
			}

			logger.Printf("error accepting connection: %s", err)
			continue
		}

		logger.Printf("incoming connection: %s", conn.RemoteAddr())

		handlers.Add(1)
		go timer.Time(func() {
			defer handlers.Done()
			defer conn.Close()
			defer openCounter.Dec(1)
			handle(conn, successCounter, errorCounter, dial)
		})
	}
}

// Handle incoming connection by opening new connection to our backend service
// and fusing them together.
func handle(conn net.Conn, successCounter metrics.Counter, errorCounter metrics.Counter, dial func() (net.Conn, error)) {
	backend, err := dial()

	if err != nil {
		errorCounter.Inc(1)
		logger.Printf("failed to dial backend: %s", err)
		return
	}

	successCounter.Inc(1)
	fuse(conn, backend)
}

// Fuse connections together
func fuse(client, backend net.Conn) {
	// Copy from client -> backend, and from backend -> client
	go func() { copyData(client, backend) }()
	copyData(backend, client)
}

// Copy data between two connections
func copyData(dst net.Conn, src net.Conn) {
	defer dst.Close()
	defer src.Close()
	defer logger.Printf("closed pipe: %s:%s <- %s:%s", dst.RemoteAddr().Network(), dst.RemoteAddr().String(), src.RemoteAddr().Network(), src.RemoteAddr().String())
	logger.Printf("opening pipe: %s:%s <- %s:%s", dst.RemoteAddr().Network(), dst.RemoteAddr().String(), src.RemoteAddr().Network(), src.RemoteAddr().String())

	_, err := io.Copy(dst, src)

	if err != nil {
		logger.Printf("%s", err)
	}
}

// Helper function to decode a *net.TCPAddr into a tuple of network and
// address. Must use this since kavu/so_reuseport does not currently
// support passing "tcp" to support for IPv4 and IPv6. We must pass "tcp4"
// or "tcp6" explicitly.
func decodeAddress(tuple *net.TCPAddr) (network, address string) {
	if tuple.IP.To4() != nil {
		network = "tcp4"
	} else {
		network = "tcp6"
	}

	address = tuple.String()
	return
}

// Parse a string representing a TCP address or UNIX socket for our backend
// target. The input can be or the form "HOST:PORT" for TCP or "unix:PATH"
// for a UNIX socket.
func parseUnixOrTCPAddress(input string) (network, address, host string, err error) {
	if strings.HasPrefix(input, "unix:") {
		network = "unix"
		address = input[5:]
		return
	}

	host, _, err = net.SplitHostPort(input)
	if err != nil {
		return
	}

	var tcp *net.TCPAddr
	tcp, err = net.ResolveTCPAddr("tcp", input)
	if err != nil {
		return
	}

	network, address = decodeAddress(tcp)
	return
}
<|endoftext|>


<commit_before>package ssh

import (
	"bytes"
	"crypto/dsa"
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"strings"

	"golang.org/x/crypto/ed25519"
	gossh "golang.org/x/crypto/ssh"
)

const (
	// That's a lot of bits.
	defaultRsaBits = 4096

	// Markers for various SSH key pair types.
	Default KeyPairType = ""
	Rsa     KeyPairType = "RSA"
	Ecdsa   KeyPairType = "ECDSA"
	Dsa     KeyPairType = "DSA"
	Ed25519 KeyPairType = "ED25519"
)

// KeyPairType represents different types of SSH key pairs.
// See the 'const' block for details.
type KeyPairType string

func (o KeyPairType) String() string {
	return string(o)
}

// CreateKeyPairConfig describes how an SSH key pair should be created.
type CreateKeyPairConfig struct {
	// Type describes the key pair's type.
	Type KeyPairType

	// Bits represents the key pair's bits of entropy. E.g., 4096 for
	// a 4096 bit RSA key pair, or 521 for a ECDSA key pair with a
	// 521-bit curve.
	Bits int

	// Name is the resulting key pair's name. This is used to identify
	// the key pair in the SSH server's 'authorized_keys'.
	Name string
}

// FromPrivateKeyConfig describes how an SSH key pair should be loaded from an
// existing private key.
type FromPrivateKeyConfig struct {
	// RawPrivateKeyPemBlock is the raw private key that the key pair
	// should be loaded from.
	RawPrivateKeyPemBlock []byte

	// Name is the resulting key pair's name. This is used to identify
	// the key pair in the SSH server's 'authorized_keys'.
	Name string
}

// KeyPair represents an SSH key pair.
type KeyPair struct {
	// PrivateKeyPemBlock represents the key pair's private key in
	// ASN.1 Distinguished Encoding Rules (DER) format in a
	// Privacy-Enhanced Mail (PEM) block.
	PrivateKeyPemBlock []byte

	// PublicKeyAuthorizedKeysLine represents the key pair's public key
	// as a line in OpenSSH authorized_keys.
	PublicKeyAuthorizedKeysLine []byte

	// Name is the key pair's name. This is used to identify
	// the key pair in the SSH server's 'authorized_keys'.
	Name string
}

// KeyPairFromPrivateKey returns a KeyPair loaded from an existing private key.
//
// Supported key pair types include:
// 	- DSA
// 	- ECDSA
// 	- ED25519
// 	- RSA
func KeyPairFromPrivateKey(config FromPrivateKeyConfig) (KeyPair, error) {
	privateKey, err := gossh.ParseRawPrivateKey(config.RawPrivateKeyPemBlock)
	if err != nil {
		return KeyPair{}, err
	}

	switch pk := privateKey.(type) {
	case *rsa.PrivateKey:
		publicKey, err := gossh.NewPublicKey(&pk.PublicKey)
		if err != nil {
			return KeyPair{}, err
		}
		return KeyPair{
			PrivateKeyPemBlock:          config.RawPrivateKeyPemBlock,
			PublicKeyAuthorizedKeysLine: authorizedKeysLine(publicKey, config.Name),
		}, nil
	case *ecdsa.PrivateKey:
		publicKey, err := gossh.NewPublicKey(&pk.PublicKey)
		if err != nil {
			return KeyPair{}, err
		}
		return KeyPair{
			PrivateKeyPemBlock:          config.RawPrivateKeyPemBlock,
			PublicKeyAuthorizedKeysLine: authorizedKeysLine(publicKey, config.Name),
		}, nil
	case *dsa.PrivateKey:
		publicKey, err := gossh.NewPublicKey(&pk.PublicKey)
		if err != nil {
			return KeyPair{}, err
		}
		return KeyPair{
			PrivateKeyPemBlock:          config.RawPrivateKeyPemBlock,
			PublicKeyAuthorizedKeysLine: authorizedKeysLine(publicKey, config.Name),
		}, nil
	case *ed25519.PrivateKey:
		publicKey, err := gossh.NewPublicKey(pk.Public())
		if err != nil {
			return KeyPair{}, err
		}
		return KeyPair{
			PrivateKeyPemBlock:          config.RawPrivateKeyPemBlock,
			PublicKeyAuthorizedKeysLine: authorizedKeysLine(publicKey, config.Name),
		}, nil
	}

	return KeyPair{}, fmt.Errorf("Cannot parse existing SSH key pair - unknown key pair type")
}

// NewKeyPair generates a new SSH key pair using the specified
// CreateKeyPairConfig.
func NewKeyPair(config CreateKeyPairConfig) (KeyPair, error) {
	if config.Type == Default {
		config.Type = Ecdsa
	}

	switch config.Type {
	case Ecdsa:
		return newEcdsaKeyPair(config)
	case Rsa:
		return newRsaKeyPair(config)
	}

	return KeyPair{}, fmt.Errorf("Unable to generate new key pair, type %s is not supported",
		config.Type.String())
}

// newEcdsaKeyPair returns a new ECDSA SSH key pair.
func newEcdsaKeyPair(config CreateKeyPairConfig) (KeyPair, error) {
	var curve elliptic.Curve

	switch config.Bits {
	case 0:
		config.Bits = 521
		fallthrough
	case 521:
		curve = elliptic.P521()
	case 384:
		curve = elliptic.P384()
	case 256:
		curve = elliptic.P256()
	case 224:
		// Not supported by "golang.org/x/crypto/ssh".
		return KeyPair{}, fmt.Errorf("golang.org/x/crypto/ssh does not support %d bits", config.Bits)
	default:
		return KeyPair{}, fmt.Errorf("crypto/elliptic does not support %d bits", config.Bits)
	}

	privateKey, err := ecdsa.GenerateKey(curve, rand.Reader)
	if err != nil {
		return KeyPair{}, err
	}

	sshPublicKey, err := gossh.NewPublicKey(&privateKey.PublicKey)
	if err != nil {
		return KeyPair{}, err
	}

	privateRaw, err := x509.MarshalECPrivateKey(privateKey)
	if err != nil {
		return KeyPair{}, err
	}

	privatePem, err := rawPemBlock(&pem.Block{
		Type:    "EC PRIVATE KEY",
		Headers: nil,
		Bytes:   privateRaw,
	})
	if err != nil {
		return KeyPair{}, err
	}

	return KeyPair{
		PrivateKeyPemBlock:          privatePem,
		PublicKeyAuthorizedKeysLine: authorizedKeysLine(sshPublicKey, config.Name),
		Name:                        config.Name,
	}, nil
}

// newRsaKeyPair returns a new RSA SSH key pair.
func newRsaKeyPair(config CreateKeyPairConfig) (KeyPair, error) {
	if config.Bits == 0 {
		config.Bits = defaultRsaBits
	}

	privateKey, err := rsa.GenerateKey(rand.Reader, config.Bits)
	if err != nil {
		return KeyPair{}, err
	}

	sshPublicKey, err := gossh.NewPublicKey(&privateKey.PublicKey)
	if err != nil {
		return KeyPair{}, err
	}

	privatePemBlock, err := rawPemBlock(&pem.Block{
		Type:    "RSA PRIVATE KEY",
		Headers: nil,
		Bytes:   x509.MarshalPKCS1PrivateKey(privateKey),
	})
	if err != nil {
		return KeyPair{}, err
	}

	return KeyPair{
		PrivateKeyPemBlock:          privatePemBlock,
		PublicKeyAuthorizedKeysLine: authorizedKeysLine(sshPublicKey, config.Name),
		Name:                        config.Name,
	}, nil
}

// rawPemBlock encodes a pem.Block to a slice of bytes.
func rawPemBlock(block *pem.Block) ([]byte, error) {
	buffer := bytes.NewBuffer(nil)

	err := pem.Encode(buffer, block)
	if err != nil {
		return []byte{}, err
	}

	return buffer.Bytes(), nil
}

// authorizedKeysLine returns a slice of bytes representing an SSH public key
// as a line in OpenSSH authorized_keys format. No line break is appended.
func authorizedKeysLine(sshPublicKey gossh.PublicKey, name string) []byte {
	result := gossh.MarshalAuthorizedKey(sshPublicKey)

	// Remove the mandatory unix new line.
	// Awful, but the go ssh library automatically appends
	// a unix new line.
	result = bytes.TrimSpace(result)

	if len(strings.TrimSpace(name)) > 0 {
		result = append(result, ' ')
		result = append(result, name...)
	}

	return result
}
<commit_msg>Update 'authorizedKeysLine' doc per review feedback.<commit_after>package ssh

import (
	"bytes"
	"crypto/dsa"
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"strings"

	"golang.org/x/crypto/ed25519"
	gossh "golang.org/x/crypto/ssh"
)

const (
	// That's a lot of bits.
	defaultRsaBits = 4096

	// Markers for various SSH key pair types.
	Default KeyPairType = ""
	Rsa     KeyPairType = "RSA"
	Ecdsa   KeyPairType = "ECDSA"
	Dsa     KeyPairType = "DSA"
	Ed25519 KeyPairType = "ED25519"
)

// KeyPairType represents different types of SSH key pairs.
// See the 'const' block for details.
type KeyPairType string

func (o KeyPairType) String() string {
	return string(o)
}

// CreateKeyPairConfig describes how an SSH key pair should be created.
type CreateKeyPairConfig struct {
	// Type describes the key pair's type.
	Type KeyPairType

	// Bits represents the key pair's bits of entropy. E.g., 4096 for
	// a 4096 bit RSA key pair, or 521 for a ECDSA key pair with a
	// 521-bit curve.
	Bits int

	// Name is the resulting key pair's name. This is used to identify
	// the key pair in the SSH server's 'authorized_keys'.
	Name string
}

// FromPrivateKeyConfig describes how an SSH key pair should be loaded from an
// existing private key.
type FromPrivateKeyConfig struct {
	// RawPrivateKeyPemBlock is the raw private key that the key pair
	// should be loaded from.
	RawPrivateKeyPemBlock []byte

	// Name is the resulting key pair's name. This is used to identify
	// the key pair in the SSH server's 'authorized_keys'.
	Name string
}

// KeyPair represents an SSH key pair.
type KeyPair struct {
	// PrivateKeyPemBlock represents the key pair's private key in
	// ASN.1 Distinguished Encoding Rules (DER) format in a
	// Privacy-Enhanced Mail (PEM) block.
	PrivateKeyPemBlock []byte

	// PublicKeyAuthorizedKeysLine represents the key pair's public key
	// as a line in OpenSSH authorized_keys.
	PublicKeyAuthorizedKeysLine []byte

	// Name is the key pair's name. This is used to identify
	// the key pair in the SSH server's 'authorized_keys'.
	Name string
}

// KeyPairFromPrivateKey returns a KeyPair loaded from an existing private key.
//
// Supported key pair types include:
// 	- DSA
// 	- ECDSA
// 	- ED25519
// 	- RSA
func KeyPairFromPrivateKey(config FromPrivateKeyConfig) (KeyPair, error) {
	privateKey, err := gossh.ParseRawPrivateKey(config.RawPrivateKeyPemBlock)
	if err != nil {
		return KeyPair{}, err
	}

	switch pk := privateKey.(type) {
	case *rsa.PrivateKey:
		publicKey, err := gossh.NewPublicKey(&pk.PublicKey)
		if err != nil {
			return KeyPair{}, err
		}
		return KeyPair{
			PrivateKeyPemBlock:          config.RawPrivateKeyPemBlock,
			PublicKeyAuthorizedKeysLine: authorizedKeysLine(publicKey, config.Name),
		}, nil
	case *ecdsa.PrivateKey:
		publicKey, err := gossh.NewPublicKey(&pk.PublicKey)
		if err != nil {
			return KeyPair{}, err
		}
		return KeyPair{
			PrivateKeyPemBlock:          config.RawPrivateKeyPemBlock,
			PublicKeyAuthorizedKeysLine: authorizedKeysLine(publicKey, config.Name),
		}, nil
	case *dsa.PrivateKey:
		publicKey, err := gossh.NewPublicKey(&pk.PublicKey)
		if err != nil {
			return KeyPair{}, err
		}
		return KeyPair{
			PrivateKeyPemBlock:          config.RawPrivateKeyPemBlock,
			PublicKeyAuthorizedKeysLine: authorizedKeysLine(publicKey, config.Name),
		}, nil
	case *ed25519.PrivateKey:
		publicKey, err := gossh.NewPublicKey(pk.Public())
		if err != nil {
			return KeyPair{}, err
		}
		return KeyPair{
			PrivateKeyPemBlock:          config.RawPrivateKeyPemBlock,
			PublicKeyAuthorizedKeysLine: authorizedKeysLine(publicKey, config.Name),
		}, nil
	}

	return KeyPair{}, fmt.Errorf("Cannot parse existing SSH key pair - unknown key pair type")
}

// NewKeyPair generates a new SSH key pair using the specified
// CreateKeyPairConfig.
func NewKeyPair(config CreateKeyPairConfig) (KeyPair, error) {
	if config.Type == Default {
		config.Type = Ecdsa
	}

	switch config.Type {
	case Ecdsa:
		return newEcdsaKeyPair(config)
	case Rsa:
		return newRsaKeyPair(config)
	}

	return KeyPair{}, fmt.Errorf("Unable to generate new key pair, type %s is not supported",
		config.Type.String())
}

// newEcdsaKeyPair returns a new ECDSA SSH key pair.
func newEcdsaKeyPair(config CreateKeyPairConfig) (KeyPair, error) {
	var curve elliptic.Curve

	switch config.Bits {
	case 0:
		config.Bits = 521
		fallthrough
	case 521:
		curve = elliptic.P521()
	case 384:
		curve = elliptic.P384()
	case 256:
		curve = elliptic.P256()
	case 224:
		// Not supported by "golang.org/x/crypto/ssh".
		return KeyPair{}, fmt.Errorf("golang.org/x/crypto/ssh does not support %d bits", config.Bits)
	default:
		return KeyPair{}, fmt.Errorf("crypto/elliptic does not support %d bits", config.Bits)
	}

	privateKey, err := ecdsa.GenerateKey(curve, rand.Reader)
	if err != nil {
		return KeyPair{}, err
	}

	sshPublicKey, err := gossh.NewPublicKey(&privateKey.PublicKey)
	if err != nil {
		return KeyPair{}, err
	}

	privateRaw, err := x509.MarshalECPrivateKey(privateKey)
	if err != nil {
		return KeyPair{}, err
	}

	privatePem, err := rawPemBlock(&pem.Block{
		Type:    "EC PRIVATE KEY",
		Headers: nil,
		Bytes:   privateRaw,
	})
	if err != nil {
		return KeyPair{}, err
	}

	return KeyPair{
		PrivateKeyPemBlock:          privatePem,
		PublicKeyAuthorizedKeysLine: authorizedKeysLine(sshPublicKey, config.Name),
		Name:                        config.Name,
	}, nil
}

// newRsaKeyPair returns a new RSA SSH key pair.
func newRsaKeyPair(config CreateKeyPairConfig) (KeyPair, error) {
	if config.Bits == 0 {
		config.Bits = defaultRsaBits
	}

	privateKey, err := rsa.GenerateKey(rand.Reader, config.Bits)
	if err != nil {
		return KeyPair{}, err
	}

	sshPublicKey, err := gossh.NewPublicKey(&privateKey.PublicKey)
	if err != nil {
		return KeyPair{}, err
	}

	privatePemBlock, err := rawPemBlock(&pem.Block{
		Type:    "RSA PRIVATE KEY",
		Headers: nil,
		Bytes:   x509.MarshalPKCS1PrivateKey(privateKey),
	})
	if err != nil {
		return KeyPair{}, err
	}

	return KeyPair{
		PrivateKeyPemBlock:          privatePemBlock,
		PublicKeyAuthorizedKeysLine: authorizedKeysLine(sshPublicKey, config.Name),
		Name:                        config.Name,
	}, nil
}

// rawPemBlock encodes a pem.Block to a slice of bytes.
func rawPemBlock(block *pem.Block) ([]byte, error) {
	buffer := bytes.NewBuffer(nil)

	err := pem.Encode(buffer, block)
	if err != nil {
		return []byte{}, err
	}

	return buffer.Bytes(), nil
}

// authorizedKeysLine serializes key for inclusion in an OpenSSH
// authorized_keys file. The return value ends without newline so
// a key name can be appended to the end.
func authorizedKeysLine(key gossh.PublicKey, name string) []byte {
	marshaledPublicKey := gossh.MarshalAuthorizedKey(key)

	// Remove the mandatory unix new line. Awful, but the go
	// ssh library automatically appends a unix new line.
	// We remove it so a key name can be safely appended to the
	// end of the string.
	marshaledPublicKey = bytes.TrimSpace(marshaledPublicKey)

	if len(strings.TrimSpace(name)) > 0 {
		marshaledPublicKey = append(marshaledPublicKey, ' ')
		marshaledPublicKey = append(marshaledPublicKey, name...)
	}

	return marshaledPublicKey
}
<|endoftext|>


<commit_before>package helpers

import (
	"fmt"
	"sort"
	"strings"

	"github.com/jessemillar/stalks/accessors"
	"github.com/jessemillar/stalks/models"
)

// ReportLeaders returns a string of the leaderboard
func ReportLeaders(ag *accessors.AccessorGroup) string {
	users := ag.GetAllUsers()
	pValues := make([]models.PortfolioValue, len(users))

	// Compile portfolio data
	for _, user := range users {
		portfolio := ag.GetPortfolio(user.UserID)
		worth := portfolio.Turnips

		for _, value := range portfolio.Investments {
			if value.Quantity > 0 {
				price := models.CheckStock(value.Ticker).Price
				worth = worth + price*value.Quantity
			}
		}

		pValues = append(pValues, models.PortfolioValue{UserID: user.UserID, Username: user.Username, Value: worth})

	}

	// Sort the portfolios by value
	sort.Sort(models.SortedPortfolioValue(pValues))

	message := []string{}
	message = append(message, fmt.Sprintf("*End of the Day Leaderboard*"))
	// Run through the sorted values and compile the message
	for _, pValue := range pValues {
		message = append(message, fmt.Sprintf("<@%s|%s> has a net worth of %s turnips.", pValue.UserID, pValue.Username, Comma(pValue.Value)))
	}

	response := strings.Join(message, "\\n") // Double escape the newline because Slack incoming webhooks are obsessive with JSON formatting while the /slash-command "endpoints" are now

	return response
}
<commit_msg>Removed preallocation of the array<commit_after>package helpers

import (
	"fmt"
	"sort"
	"strings"

	"github.com/jessemillar/stalks/accessors"
	"github.com/jessemillar/stalks/models"
)

// ReportLeaders returns a string of the leaderboard
func ReportLeaders(ag *accessors.AccessorGroup) string {
	users := ag.GetAllUsers()
	pValues := []models.PortfolioValue{}

	// Compile portfolio data
	for _, user := range users {
		portfolio := ag.GetPortfolio(user.UserID)
		worth := portfolio.Turnips

		for _, value := range portfolio.Investments {
			if value.Quantity > 0 {
				price := models.CheckStock(value.Ticker).Price
				worth = worth + price*value.Quantity
			}
		}

		pValues = append(pValues, models.PortfolioValue{UserID: user.UserID, Username: user.Username, Value: worth})

	}

	// Sort the portfolios by value
	sort.Sort(models.SortedPortfolioValue(pValues))

	message := []string{}
	message = append(message, fmt.Sprintf("*End of the Day Leaderboard*"))
	// Run through the sorted values and compile the message
	for _, pValue := range pValues {
		message = append(message, fmt.Sprintf("<@%s|%s> has a net worth of %s turnips.", pValue.UserID, pValue.Username, Comma(pValue.Value)))
	}

	response := strings.Join(message, "\\n") // Double escape the newline because Slack incoming webhooks are obsessive with JSON formatting while the /slash-command "endpoints" are now

	return response
}
<|endoftext|>


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

package main

import (
	"bufio";
	"flag";
	"fmt";
	"http";
	"io";
	"net";
	"os";
)

// hello world, the web server
func HelloServer(c *http.Conn, req *http.Request) {
	io.WriteString(c, "hello, world!\n");
}

// simple counter server
type Counter struct {
	n int;
}

func (ctr *Counter) ServeHTTP(c *http.Conn, req *http.Request) {
	fmt.Fprintf(c, "counter = %d\n", ctr.n);
	ctr.n++;
}

// simple file server
var webroot = flag.String("root", "/home/rsc", "web root directory")
func FileServer(c *http.Conn, req *http.Request) {
	c.SetHeader("content-type", "text/plain; charset=utf-8");
	path := *webroot + req.Url.Path;	// TODO: insecure: use os.CleanName
	fd, err := os.Open(path, os.O_RDONLY, 0);
	if err != nil {
		c.WriteHeader(http.StatusNotFound);
		fmt.Fprintf(c, "open %s: %v\n", path, err);
		return;
	}
	n, err1 := io.Copy(fd, c);
	fmt.Fprintf(c, "[%d bytes]\n", n);
}

// a channel (just for the fun of it)
type Chan chan int

func ChanCreate() Chan {
	c := make(Chan);
	go func(c Chan) {
		for x := 0;; x++ {
			c <- x
		}
	}(c);
	return c;
}

func (ch Chan) ServeHTTP(c *http.Conn, req *http.Request) {
	io.WriteString(c, fmt.Sprintf("channel send #%d\n", <-ch));
}

func main() {
	flag.Parse();
	http.Handle("/counter", new(Counter));
	http.Handle("/go/", http.HandlerFunc(FileServer));
	http.Handle("/go/hello", http.HandlerFunc(HelloServer));
	http.Handle("/chan", ChanCreate());
	err := http.ListenAndServe(":12345", nil);
	if err != nil {
		panic("ListenAndServe: ", err.String())
	}
}

<commit_msg>more fun with triv.go: flags and arguments<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bufio";
	"flag";
	"fmt";
	"http";
	"io";
	"net";
	"os";
)

// hello world, the web server
func HelloServer(c *http.Conn, req *http.Request) {
	io.WriteString(c, "hello, world!\n");
}

// simple counter server
type Counter struct {
	n int;
}

func (ctr *Counter) ServeHTTP(c *http.Conn, req *http.Request) {
	fmt.Fprintf(c, "counter = %d\n", ctr.n);
	ctr.n++;
}

// simple file server
var webroot = flag.String("root", "/home/rsc", "web root directory")
func FileServer(c *http.Conn, req *http.Request) {
	c.SetHeader("content-type", "text/plain; charset=utf-8");
	path := *webroot + req.Url.Path;	// TODO: insecure: use os.CleanName
	fd, err := os.Open(path, os.O_RDONLY, 0);
	if err != nil {
		c.WriteHeader(http.StatusNotFound);
		fmt.Fprintf(c, "open %s: %v\n", path, err);
		return;
	}
	n, err1 := io.Copy(fd, c);
	fmt.Fprintf(c, "[%d bytes]\n", n);
}

// simple flag server
var booleanflag = flag.Bool("boolean", true, "another flag for testing")
func FlagServer(c *http.Conn, req *http.Request) {
	c.SetHeader("content-type", "text/plain; charset=utf-8");
	fmt.Fprint(c, "Flags:\n");
	flag.VisitAll(func (f *flag.Flag) {
		if f.Value.String() != f.DefValue {
			fmt.Fprintf(c, "%s = %s [default = %s]\n", f.Name, f.Value.String(), f.DefValue);
		} else {
			fmt.Fprintf(c, "%s = %s\n", f.Name, f.Value.String());
		}
	});
}

// simple argument server
func ArgServer(c *http.Conn, req *http.Request) {
	for i, s := range sys.Args {
		fmt.Fprint(c, s, " ");
	}
}

// a channel (just for the fun of it)
type Chan chan int

func ChanCreate() Chan {
	c := make(Chan);
	go func(c Chan) {
		for x := 0;; x++ {
			c <- x
		}
	}(c);
	return c;
}

func (ch Chan) ServeHTTP(c *http.Conn, req *http.Request) {
	io.WriteString(c, fmt.Sprintf("channel send #%d\n", <-ch));
}

func main() {
	flag.Parse();
	http.Handle("/counter", new(Counter));
	http.Handle("/go/", http.HandlerFunc(FileServer));
	http.Handle("/flags/", http.HandlerFunc(FlagServer));
	http.Handle("/args/", http.HandlerFunc(ArgServer));
	http.Handle("/go/hello", http.HandlerFunc(HelloServer));
	http.Handle("/chan", ChanCreate());
	err := http.ListenAndServe(":12345", nil);
	if err != nil {
		panic("ListenAndServe: ", err.String())
	}
}

<|endoftext|>


<commit_before>package nsf

import (
	"errors"
	"io"
	"io/ioutil"
	"time"

	"github.com/mjibson/mog/codec/nsf/cpu6502"
)

const (
	// 1.79 MHz
	cpuClock = 236250000 / 11 / 12
)

var (
	// DefaultSampleRate is the default sample rate of a track after calling
	// Init().
	DefaultSampleRate = 44100
	ErrUnrecognized   = errors.New("nsf: unrecognized format")
)

const (
	NSF_HEADER_LEN = 0x80
	NSF_VERSION    = 0x5
	NSF_SONGS      = 0x6
	NSF_START      = 0x7
	NSF_LOAD       = 0x8
	NSF_INIT       = 0xa
	NSF_PLAY       = 0xc
	NSF_SONG       = 0xe
	NSF_ARTIST     = 0x2e
	NSF_COPYRIGHT  = 0x4e
	NSF_SPEED_NTSC = 0x6e
	NSF_BANKSWITCH = 0x70
	NSF_SPEED_PAL  = 0x78
	NSF_PAL_NTSC   = 0x7a
	NSF_EXTRA      = 0x7b
	NSF_ZERO       = 0x7c
)

func ReadNSF(r io.Reader) (n *NSF, err error) {
	n = New()
	n.b, err = ioutil.ReadAll(r)
	if err != nil {
		return
	}
	if len(n.b) < NSF_HEADER_LEN ||
		string(n.b[0:NSF_VERSION]) != "NESM\u001a" {
		return nil, ErrUnrecognized
	}
	n.Version = n.b[NSF_VERSION]
	n.Songs = n.b[NSF_SONGS]
	n.Start = n.b[NSF_START]
	n.LoadAddr = bLEtoUint16(n.b[NSF_LOAD:])
	n.InitAddr = bLEtoUint16(n.b[NSF_INIT:])
	n.PlayAddr = bLEtoUint16(n.b[NSF_PLAY:])
	n.Song = bToString(n.b[NSF_SONG:])
	n.Artist = bToString(n.b[NSF_ARTIST:])
	n.Copyright = bToString(n.b[NSF_COPYRIGHT:])
	n.SpeedNTSC = bLEtoUint16(n.b[NSF_SPEED_NTSC:])
	copy(n.Bankswitch[:], n.b[NSF_BANKSWITCH:NSF_SPEED_PAL])
	n.SpeedPAL = bLEtoUint16(n.b[NSF_SPEED_PAL:])
	n.PALNTSC = n.b[NSF_PAL_NTSC]
	n.Extra = n.b[NSF_EXTRA]
	n.Data = n.b[NSF_HEADER_LEN:]
	return
}

type NSF struct {
	*Ram
	*cpu6502.Cpu

	b []byte // raw NSF data

	Version byte
	Songs   byte
	Start   byte

	LoadAddr uint16
	InitAddr uint16
	PlayAddr uint16

	Song      string
	Artist    string
	Copyright string

	SpeedNTSC  uint16
	Bankswitch [8]byte
	SpeedPAL   uint16
	PALNTSC    byte
	Extra      byte
	Data       []byte

	// SampleRate is the sample rate at which samples will be generated. If not
	// set before Init(), it is set to DefaultSampleRate.
	SampleRate  int64
	totalTicks  int64
	frameTicks  int64
	sampleTicks int64
	playTicks   int64
	samples     []float32
	prevs       [4]float32
	pi          int // prevs index
}

func New() *NSF {
	n := NSF{
		Ram: new(Ram),
	}
	n.Cpu = cpu6502.New(n.Ram)
	n.Cpu.T = &n
	n.Cpu.DisableDecimal = true
	n.Cpu.P = 0x24
	n.Cpu.S = 0xfd
	return &n
}

func (n *NSF) Tick() {
	n.Ram.A.Step()
	n.totalTicks++
	n.frameTicks++
	if n.frameTicks == cpuClock/240 {
		n.frameTicks = 0
		n.Ram.A.FrameStep()
	}
	n.sampleTicks++
	if n.SampleRate > 0 && n.sampleTicks >= cpuClock/n.SampleRate {
		n.sampleTicks = 0
		n.append(n.Ram.A.Volume())
	}
	n.playTicks++
}

func (n *NSF) append(v float32) {
	n.prevs[n.pi] = v
	n.pi++
	if n.pi >= len(n.prevs) {
		n.pi = 0
	}
	var sum float32
	for _, s := range n.prevs {
		sum += s
	}
	sum /= float32(len(n.prevs))
	n.samples = append(n.samples, sum)
}

func (n *NSF) Init(song byte) {
	if n.SampleRate == 0 {
		n.SampleRate = int64(DefaultSampleRate)
	}
	copy(n.Ram.M[n.LoadAddr:], n.Data)
	n.Ram.A.Init()
	n.Cpu.A = song - 1
	n.Cpu.PC = n.InitAddr
	n.Cpu.T = nil
	n.Cpu.Run()
	n.Cpu.T = n
}

func (n *NSF) Step() {
	n.Cpu.Step()
	if !n.Cpu.I() && n.Ram.A.Interrupt {
		println("INTERRUPT")
		n.Cpu.Interrupt()
	}
}

func (n *NSF) Play(samples int) []float32 {
	playDur := time.Duration(n.SpeedNTSC) * time.Nanosecond * 1000
	ticksPerPlay := int64(playDur / (time.Second / cpuClock))
	n.samples = make([]float32, 0, samples)
	for len(n.samples) < samples {
		n.playTicks = 0
		n.Cpu.PC = n.PlayAddr
		for n.Cpu.PC != 0 && len(n.samples) < samples {
			n.Step()
		}
		for i := ticksPerPlay - n.playTicks; i > 0 && len(n.samples) < samples; i-- {
			n.Tick()
		}
	}
	return n.samples
}

// little-endian [2]byte to uint16 conversion
func bLEtoUint16(b []byte) uint16 {
	return uint16(b[1])<<8 + uint16(b[0])
}

// null-terminated bytes to string
func bToString(b []byte) string {
	i := 0
	for i = range b {
		if b[i] == 0 {
			break
		}
	}
	return string(b[:i])
}

type Ram struct {
	M [0xffff + 1]byte
	A Apu
}

func (r *Ram) Read(v uint16) byte {
	switch v {
	case 0x4015:
		return r.A.Read(v)
	default:
		return r.M[v]
	}
}

func (r *Ram) Write(v uint16, b byte) {
	r.M[v] = b
	if v&0xf000 == 0x4000 {
		r.A.Write(v, b)
	}
}
<commit_msg>Remove debug<commit_after>package nsf

import (
	"errors"
	"io"
	"io/ioutil"
	"time"

	"github.com/mjibson/mog/codec/nsf/cpu6502"
)

const (
	// 1.79 MHz
	cpuClock = 236250000 / 11 / 12
)

var (
	// DefaultSampleRate is the default sample rate of a track after calling
	// Init().
	DefaultSampleRate = 44100
	ErrUnrecognized   = errors.New("nsf: unrecognized format")
)

const (
	NSF_HEADER_LEN = 0x80
	NSF_VERSION    = 0x5
	NSF_SONGS      = 0x6
	NSF_START      = 0x7
	NSF_LOAD       = 0x8
	NSF_INIT       = 0xa
	NSF_PLAY       = 0xc
	NSF_SONG       = 0xe
	NSF_ARTIST     = 0x2e
	NSF_COPYRIGHT  = 0x4e
	NSF_SPEED_NTSC = 0x6e
	NSF_BANKSWITCH = 0x70
	NSF_SPEED_PAL  = 0x78
	NSF_PAL_NTSC   = 0x7a
	NSF_EXTRA      = 0x7b
	NSF_ZERO       = 0x7c
)

func ReadNSF(r io.Reader) (n *NSF, err error) {
	n = New()
	n.b, err = ioutil.ReadAll(r)
	if err != nil {
		return
	}
	if len(n.b) < NSF_HEADER_LEN ||
		string(n.b[0:NSF_VERSION]) != "NESM\u001a" {
		return nil, ErrUnrecognized
	}
	n.Version = n.b[NSF_VERSION]
	n.Songs = n.b[NSF_SONGS]
	n.Start = n.b[NSF_START]
	n.LoadAddr = bLEtoUint16(n.b[NSF_LOAD:])
	n.InitAddr = bLEtoUint16(n.b[NSF_INIT:])
	n.PlayAddr = bLEtoUint16(n.b[NSF_PLAY:])
	n.Song = bToString(n.b[NSF_SONG:])
	n.Artist = bToString(n.b[NSF_ARTIST:])
	n.Copyright = bToString(n.b[NSF_COPYRIGHT:])
	n.SpeedNTSC = bLEtoUint16(n.b[NSF_SPEED_NTSC:])
	copy(n.Bankswitch[:], n.b[NSF_BANKSWITCH:NSF_SPEED_PAL])
	n.SpeedPAL = bLEtoUint16(n.b[NSF_SPEED_PAL:])
	n.PALNTSC = n.b[NSF_PAL_NTSC]
	n.Extra = n.b[NSF_EXTRA]
	n.Data = n.b[NSF_HEADER_LEN:]
	return
}

type NSF struct {
	*Ram
	*cpu6502.Cpu

	b []byte // raw NSF data

	Version byte
	Songs   byte
	Start   byte

	LoadAddr uint16
	InitAddr uint16
	PlayAddr uint16

	Song      string
	Artist    string
	Copyright string

	SpeedNTSC  uint16
	Bankswitch [8]byte
	SpeedPAL   uint16
	PALNTSC    byte
	Extra      byte
	Data       []byte

	// SampleRate is the sample rate at which samples will be generated. If not
	// set before Init(), it is set to DefaultSampleRate.
	SampleRate  int64
	totalTicks  int64
	frameTicks  int64
	sampleTicks int64
	playTicks   int64
	samples     []float32
	prevs       [4]float32
	pi          int // prevs index
}

func New() *NSF {
	n := NSF{
		Ram: new(Ram),
	}
	n.Cpu = cpu6502.New(n.Ram)
	n.Cpu.T = &n
	n.Cpu.DisableDecimal = true
	n.Cpu.P = 0x24
	n.Cpu.S = 0xfd
	return &n
}

func (n *NSF) Tick() {
	n.Ram.A.Step()
	n.totalTicks++
	n.frameTicks++
	if n.frameTicks == cpuClock/240 {
		n.frameTicks = 0
		n.Ram.A.FrameStep()
	}
	n.sampleTicks++
	if n.SampleRate > 0 && n.sampleTicks >= cpuClock/n.SampleRate {
		n.sampleTicks = 0
		n.append(n.Ram.A.Volume())
	}
	n.playTicks++
}

func (n *NSF) append(v float32) {
	n.prevs[n.pi] = v
	n.pi++
	if n.pi >= len(n.prevs) {
		n.pi = 0
	}
	var sum float32
	for _, s := range n.prevs {
		sum += s
	}
	sum /= float32(len(n.prevs))
	n.samples = append(n.samples, sum)
}

func (n *NSF) Init(song byte) {
	if n.SampleRate == 0 {
		n.SampleRate = int64(DefaultSampleRate)
	}
	copy(n.Ram.M[n.LoadAddr:], n.Data)
	n.Ram.A.Init()
	n.Cpu.A = song - 1
	n.Cpu.PC = n.InitAddr
	n.Cpu.T = nil
	n.Cpu.Run()
	n.Cpu.T = n
}

func (n *NSF) Step() {
	n.Cpu.Step()
	if !n.Cpu.I() && n.Ram.A.Interrupt {
		n.Cpu.Interrupt()
	}
}

func (n *NSF) Play(samples int) []float32 {
	playDur := time.Duration(n.SpeedNTSC) * time.Nanosecond * 1000
	ticksPerPlay := int64(playDur / (time.Second / cpuClock))
	n.samples = make([]float32, 0, samples)
	for len(n.samples) < samples {
		n.playTicks = 0
		n.Cpu.PC = n.PlayAddr
		for n.Cpu.PC != 0 && len(n.samples) < samples {
			n.Step()
		}
		for i := ticksPerPlay - n.playTicks; i > 0 && len(n.samples) < samples; i-- {
			n.Tick()
		}
	}
	return n.samples
}

// little-endian [2]byte to uint16 conversion
func bLEtoUint16(b []byte) uint16 {
	return uint16(b[1])<<8 + uint16(b[0])
}

// null-terminated bytes to string
func bToString(b []byte) string {
	i := 0
	for i = range b {
		if b[i] == 0 {
			break
		}
	}
	return string(b[:i])
}

type Ram struct {
	M [0xffff + 1]byte
	A Apu
}

func (r *Ram) Read(v uint16) byte {
	switch v {
	case 0x4015:
		return r.A.Read(v)
	default:
		return r.M[v]
	}
}

func (r *Ram) Write(v uint16, b byte) {
	r.M[v] = b
	if v&0xf000 == 0x4000 {
		r.A.Write(v, b)
	}
}
<|endoftext|>


<commit_before>package nsf

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"time"

	"github.com/mjibson/mog/codec"
	"github.com/mjibson/mog/codec/nsf/cpu6502"
)

const (
	// 1.79 MHz
	cpuClock = 236250000 / 11 / 12
)

var (
	// DefaultSampleRate is the default sample rate of a track after calling
	// Init().
	DefaultSampleRate int64 = 44100
	ErrUnrecognized         = errors.New("nsf: unrecognized format")
)

func init() {
	codec.RegisterCodec("NSF", "NESM\u001a", ReadNSFSongs)
}

const (
	NSF_HEADER_LEN = 0x80
	NSF_VERSION    = 0x5
	NSF_SONGS      = 0x6
	NSF_START      = 0x7
	NSF_LOAD       = 0x8
	NSF_INIT       = 0xa
	NSF_PLAY       = 0xc
	NSF_SONG       = 0xe
	NSF_ARTIST     = 0x2e
	NSF_COPYRIGHT  = 0x4e
	NSF_SPEED_NTSC = 0x6e
	NSF_BANKSWITCH = 0x70
	NSF_SPEED_PAL  = 0x78
	NSF_PAL_NTSC   = 0x7a
	NSF_EXTRA      = 0x7b
	NSF_ZERO       = 0x7c
)

func ReadNSFSongs(r io.Reader) ([]codec.Song, error) {
	n, err := ReadNSF(r)
	if err != nil {
		return nil, err
	}
	songs := make([]codec.Song, n.Songs)
	for i := range songs {
		songs[i] = &NSFSong{n, i + 1}
	}
	return songs, nil
}

type NSFSong struct {
	*NSF
	Index int
}

func (n *NSFSong) Play(samples int) []float32 {
	if n.playing == 0 {
		n.Init(n.Index)
	}
	return n.NSF.Play(samples)
}

func (n *NSFSong) Close() {
	// todo: implement
}

func (n *NSFSong) Info() codec.SongInfo {
	return codec.SongInfo{
		Time:       time.Minute * 2,
		Artist:     n.Artist,
		Album:      n.Song,
		Track:      n.Index,
		Title:      fmt.Sprintf("%s:%d", n.Song, n.Index),
		SampleRate: int(n.SampleRate),
		Channels:   1,
	}
}

func ReadNSF(r io.Reader) (n *NSF, err error) {
	n = New()
	n.b, err = ioutil.ReadAll(r)
	if err != nil {
		return
	}
	if len(n.b) < NSF_HEADER_LEN ||
		string(n.b[0:NSF_VERSION]) != "NESM\u001a" {
		return nil, ErrUnrecognized
	}
	n.Version = n.b[NSF_VERSION]
	n.Songs = n.b[NSF_SONGS]
	n.Start = n.b[NSF_START]
	n.LoadAddr = bLEtoUint16(n.b[NSF_LOAD:])
	n.InitAddr = bLEtoUint16(n.b[NSF_INIT:])
	n.PlayAddr = bLEtoUint16(n.b[NSF_PLAY:])
	n.Song = bToString(n.b[NSF_SONG:])
	n.Artist = bToString(n.b[NSF_ARTIST:])
	n.Copyright = bToString(n.b[NSF_COPYRIGHT:])
	n.SpeedNTSC = bLEtoUint16(n.b[NSF_SPEED_NTSC:])
	copy(n.Bankswitch[:], n.b[NSF_BANKSWITCH:NSF_SPEED_PAL])
	n.SpeedPAL = bLEtoUint16(n.b[NSF_SPEED_PAL:])
	n.PALNTSC = n.b[NSF_PAL_NTSC]
	n.Extra = n.b[NSF_EXTRA]
	n.Data = n.b[NSF_HEADER_LEN:]
	if n.SampleRate == 0 {
		n.SampleRate = DefaultSampleRate
	}
	copy(n.Ram.M[n.LoadAddr:], n.Data)
	return
}

type NSF struct {
	*Ram
	*cpu6502.Cpu

	b []byte // raw NSF data

	Version byte
	Songs   byte
	Start   byte

	LoadAddr uint16
	InitAddr uint16
	PlayAddr uint16

	Song      string
	Artist    string
	Copyright string

	SpeedNTSC  uint16
	Bankswitch [8]byte
	SpeedPAL   uint16
	PALNTSC    byte
	Extra      byte
	Data       []byte

	// SampleRate is the sample rate at which samples will be generated. If not
	// set before Init(), it is set to DefaultSampleRate.
	SampleRate  int64
	totalTicks  int64
	frameTicks  int64
	sampleTicks int64
	playTicks   int64
	samples     []float32
	prevs       [4]float32
	pi          int // prevs index
	playing     int // 1-based index of currently-playing song
}

func New() *NSF {
	n := NSF{
		Ram: new(Ram),
	}
	n.Cpu = cpu6502.New(n.Ram)
	n.Cpu.T = &n
	n.Cpu.DisableDecimal = true
	n.Cpu.P = 0x24
	n.Cpu.S = 0xfd
	return &n
}

func (n *NSF) Tick() {
	n.Ram.A.Step()
	n.totalTicks++
	n.frameTicks++
	if n.frameTicks == cpuClock/240 {
		n.frameTicks = 0
		n.Ram.A.FrameStep()
	}
	n.sampleTicks++
	if n.SampleRate > 0 && n.sampleTicks >= cpuClock/n.SampleRate {
		n.sampleTicks = 0
		n.append(n.Ram.A.Volume())
	}
	n.playTicks++
}

func (n *NSF) append(v float32) {
	n.prevs[n.pi] = v
	n.pi++
	if n.pi >= len(n.prevs) {
		n.pi = 0
	}
	var sum float32
	for _, s := range n.prevs {
		sum += s
	}
	sum /= float32(len(n.prevs))
	n.samples = append(n.samples, sum)
}

func (n *NSF) Init(song int) {
	n.Ram.A.Init()
	n.Cpu.A = byte(song - 1)
	n.Cpu.PC = n.InitAddr
	n.Cpu.T = nil
	n.Cpu.Run()
	n.Cpu.T = n
}

func (n *NSF) Step() {
	n.Cpu.Step()
	if !n.Cpu.I() && n.Ram.A.Interrupt {
		n.Cpu.Interrupt()
	}
}

func (n *NSF) Play(samples int) []float32 {
	playDur := time.Duration(n.SpeedNTSC) * time.Nanosecond * 1000
	ticksPerPlay := int64(playDur / (time.Second / cpuClock))
	n.samples = make([]float32, 0, samples)
	for len(n.samples) < samples {
		n.playTicks = 0
		n.Cpu.PC = n.PlayAddr
		for n.Cpu.PC != 0 && len(n.samples) < samples {
			n.Step()
		}
		for i := ticksPerPlay - n.playTicks; i > 0 && len(n.samples) < samples; i-- {
			n.Tick()
		}
	}
	return n.samples
}

// little-endian [2]byte to uint16 conversion
func bLEtoUint16(b []byte) uint16 {
	return uint16(b[1])<<8 + uint16(b[0])
}

// null-terminated bytes to string
func bToString(b []byte) string {
	i := 0
	for i = range b {
		if b[i] == 0 {
			break
		}
	}
	return string(b[:i])
}

type Ram struct {
	M [0xffff + 1]byte
	A Apu
}

func (r *Ram) Read(v uint16) byte {
	switch v {
	case 0x4015:
		return r.A.Read(v)
	default:
		return r.M[v]
	}
}

func (r *Ram) Write(v uint16, b byte) {
	r.M[v] = b
	if v&0xf000 == 0x4000 {
		r.A.Write(v, b)
	}
}

func (n *NSF) Seek(t time.Time) {
	// todo: implement
}
<commit_msg>Record playing song correctly<commit_after>package nsf

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"time"

	"github.com/mjibson/mog/codec"
	"github.com/mjibson/mog/codec/nsf/cpu6502"
)

const (
	// 1.79 MHz
	cpuClock = 236250000 / 11 / 12
)

var (
	// DefaultSampleRate is the default sample rate of a track after calling
	// Init().
	DefaultSampleRate int64 = 44100
	ErrUnrecognized         = errors.New("nsf: unrecognized format")
)

func init() {
	codec.RegisterCodec("NSF", "NESM\u001a", ReadNSFSongs)
}

const (
	NSF_HEADER_LEN = 0x80
	NSF_VERSION    = 0x5
	NSF_SONGS      = 0x6
	NSF_START      = 0x7
	NSF_LOAD       = 0x8
	NSF_INIT       = 0xa
	NSF_PLAY       = 0xc
	NSF_SONG       = 0xe
	NSF_ARTIST     = 0x2e
	NSF_COPYRIGHT  = 0x4e
	NSF_SPEED_NTSC = 0x6e
	NSF_BANKSWITCH = 0x70
	NSF_SPEED_PAL  = 0x78
	NSF_PAL_NTSC   = 0x7a
	NSF_EXTRA      = 0x7b
	NSF_ZERO       = 0x7c
)

func ReadNSFSongs(r io.Reader) ([]codec.Song, error) {
	n, err := ReadNSF(r)
	if err != nil {
		return nil, err
	}
	songs := make([]codec.Song, n.Songs)
	for i := range songs {
		songs[i] = &NSFSong{n, i + 1}
	}
	return songs, nil
}

type NSFSong struct {
	*NSF
	Index int
}

func (n *NSFSong) Play(samples int) []float32 {
	if n.playing != n.Index {
		n.Init(n.Index)
		n.playing = n.Index
	}
	return n.NSF.Play(samples)
}

func (n *NSFSong) Close() {
	// todo: implement
}

func (n *NSFSong) Info() codec.SongInfo {
	return codec.SongInfo{
		Time:       time.Minute * 2,
		Artist:     n.Artist,
		Album:      n.Song,
		Track:      n.Index,
		Title:      fmt.Sprintf("%s:%d", n.Song, n.Index),
		SampleRate: int(n.SampleRate),
		Channels:   1,
	}
}

func ReadNSF(r io.Reader) (n *NSF, err error) {
	n = New()
	n.b, err = ioutil.ReadAll(r)
	if err != nil {
		return
	}
	if len(n.b) < NSF_HEADER_LEN ||
		string(n.b[0:NSF_VERSION]) != "NESM\u001a" {
		return nil, ErrUnrecognized
	}
	n.Version = n.b[NSF_VERSION]
	n.Songs = n.b[NSF_SONGS]
	n.Start = n.b[NSF_START]
	n.LoadAddr = bLEtoUint16(n.b[NSF_LOAD:])
	n.InitAddr = bLEtoUint16(n.b[NSF_INIT:])
	n.PlayAddr = bLEtoUint16(n.b[NSF_PLAY:])
	n.Song = bToString(n.b[NSF_SONG:])
	n.Artist = bToString(n.b[NSF_ARTIST:])
	n.Copyright = bToString(n.b[NSF_COPYRIGHT:])
	n.SpeedNTSC = bLEtoUint16(n.b[NSF_SPEED_NTSC:])
	copy(n.Bankswitch[:], n.b[NSF_BANKSWITCH:NSF_SPEED_PAL])
	n.SpeedPAL = bLEtoUint16(n.b[NSF_SPEED_PAL:])
	n.PALNTSC = n.b[NSF_PAL_NTSC]
	n.Extra = n.b[NSF_EXTRA]
	n.Data = n.b[NSF_HEADER_LEN:]
	if n.SampleRate == 0 {
		n.SampleRate = DefaultSampleRate
	}
	copy(n.Ram.M[n.LoadAddr:], n.Data)
	return
}

type NSF struct {
	*Ram
	*cpu6502.Cpu

	b []byte // raw NSF data

	Version byte
	Songs   byte
	Start   byte

	LoadAddr uint16
	InitAddr uint16
	PlayAddr uint16

	Song      string
	Artist    string
	Copyright string

	SpeedNTSC  uint16
	Bankswitch [8]byte
	SpeedPAL   uint16
	PALNTSC    byte
	Extra      byte
	Data       []byte

	// SampleRate is the sample rate at which samples will be generated. If not
	// set before Init(), it is set to DefaultSampleRate.
	SampleRate  int64
	totalTicks  int64
	frameTicks  int64
	sampleTicks int64
	playTicks   int64
	samples     []float32
	prevs       [4]float32
	pi          int // prevs index
	playing     int // 1-based index of currently-playing song
}

func New() *NSF {
	n := NSF{
		Ram: new(Ram),
	}
	n.Cpu = cpu6502.New(n.Ram)
	n.Cpu.T = &n
	n.Cpu.DisableDecimal = true
	n.Cpu.P = 0x24
	n.Cpu.S = 0xfd
	return &n
}

func (n *NSF) Tick() {
	n.Ram.A.Step()
	n.totalTicks++
	n.frameTicks++
	if n.frameTicks == cpuClock/240 {
		n.frameTicks = 0
		n.Ram.A.FrameStep()
	}
	n.sampleTicks++
	if n.SampleRate > 0 && n.sampleTicks >= cpuClock/n.SampleRate {
		n.sampleTicks = 0
		n.append(n.Ram.A.Volume())
	}
	n.playTicks++
}

func (n *NSF) append(v float32) {
	n.prevs[n.pi] = v
	n.pi++
	if n.pi >= len(n.prevs) {
		n.pi = 0
	}
	var sum float32
	for _, s := range n.prevs {
		sum += s
	}
	sum /= float32(len(n.prevs))
	n.samples = append(n.samples, sum)
}

func (n *NSF) Init(song int) {
	n.Ram.A.Init()
	n.Cpu.A = byte(song - 1)
	n.Cpu.PC = n.InitAddr
	n.Cpu.T = nil
	n.Cpu.Run()
	n.Cpu.T = n
}

func (n *NSF) Step() {
	n.Cpu.Step()
	if !n.Cpu.I() && n.Ram.A.Interrupt {
		n.Cpu.Interrupt()
	}
}

func (n *NSF) Play(samples int) []float32 {
	playDur := time.Duration(n.SpeedNTSC) * time.Nanosecond * 1000
	ticksPerPlay := int64(playDur / (time.Second / cpuClock))
	n.samples = make([]float32, 0, samples)
	for len(n.samples) < samples {
		n.playTicks = 0
		n.Cpu.PC = n.PlayAddr
		for n.Cpu.PC != 0 && len(n.samples) < samples {
			n.Step()
		}
		for i := ticksPerPlay - n.playTicks; i > 0 && len(n.samples) < samples; i-- {
			n.Tick()
		}
	}
	return n.samples
}

// little-endian [2]byte to uint16 conversion
func bLEtoUint16(b []byte) uint16 {
	return uint16(b[1])<<8 + uint16(b[0])
}

// null-terminated bytes to string
func bToString(b []byte) string {
	i := 0
	for i = range b {
		if b[i] == 0 {
			break
		}
	}
	return string(b[:i])
}

type Ram struct {
	M [0xffff + 1]byte
	A Apu
}

func (r *Ram) Read(v uint16) byte {
	switch v {
	case 0x4015:
		return r.A.Read(v)
	default:
		return r.M[v]
	}
}

func (r *Ram) Write(v uint16, b byte) {
	r.M[v] = b
	if v&0xf000 == 0x4000 {
		r.A.Write(v, b)
	}
}

func (n *NSF) Seek(t time.Time) {
	// todo: implement
}
<|endoftext|>


<commit_before>// Bitfinex exchange API

package bitfinex

import (
	"bitfx2/exchange"
	"crypto/hmac"
	"crypto/sha512"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"math"
	"net/http"
	"sort"
	"strconv"
	"time"
)

// Client contains all exchange information
type Client struct {
	key, secret, symbol, currency, name           string
	priority                                      int
	position, fee, maxPos, availShort, availFunds float64
	currencyCode                                  byte
	baseURL                                       string
}

// New returns a pointer to a new Bitfinex instance
func New(key, secret, symbol, currency string, priority int, fee, availShort, availFunds float64) *Client {
	return &Client{
		key:          key,
		secret:       secret,
		symbol:       symbol,
		currency:     currency,
		priority:     priority,
		fee:          fee,
		availShort:   availShort,
		availFunds:   availFunds,
		currencyCode: 0,
		name:         fmt.Sprintf("Bitfinex(%s)", currency),
		baseURL:      "https://api.bitfinex.com",
	}
}

// String implements the Stringer interface
func (client *Client) String() string {
	return client.name
}

// Priority returns the exchange priority for order execution
func (client *Client) Priority() int {
	return client.priority
}

// Fee returns the exchange order fee
func (client *Client) Fee() float64 {
	return client.fee
}

// SetPosition sets the exchange position
func (client *Client) SetPosition(pos float64) {
	client.position = pos
}

// Position returns the exchange position
func (client *Client) Position() float64 {
	return client.position
}

// Currency returns the exchange currency
func (client *Client) Currency() string {
	return client.currency
}

// CurrencyCode returns the exchange currency code
func (client *Client) CurrencyCode() byte {
	return client.currencyCode
}

// SetMaxPos sets the exchange max position
func (client *Client) SetMaxPos(maxPos float64) {
	client.maxPos = maxPos
}

// MaxPos returns the exchange max position
func (client *Client) MaxPos() float64 {
	return client.maxPos
}

// AvailFunds returns the exchange available funds
func (client *Client) AvailFunds() float64 {
	return client.availFunds
}

// AvailShort returns the exchange quantity available for short selling
func (client *Client) AvailShort() float64 {
	return client.availShort
}

// HasCrytpoFee returns true if fee is taken in cryptocurrency on buys
func (client *Client) HasCryptoFee() bool {
	return false
}

// CommunicateBook sends the latest available book data on the supplied channel
func (client *Client) CommunicateBook(bookChan chan<- exchange.Book, doneChan <-chan bool) exchange.Book {
	// Initial book to return
	book, _ := client.getBook()

	// Run read loop in new goroutine
	go client.runLoop(bookChan, doneChan)

	return book
}

// HTTP read loop
func (client *Client) runLoop(bookChan chan<- exchange.Book, doneChan <-chan bool) {
	// Used to compare timestamps
	oldTimestamps := make([]float64, 40)

	for {
		select {
		case <-doneChan:
			return
		default:
			book, newTimestamps := client.getBook()
			// Send out only if changed
			if bookChanged(oldTimestamps, newTimestamps) {
				bookChan <- book
			}
			oldTimestamps = newTimestamps
		}
	}
}

// Get book data with an HTTP request
func (client *Client) getBook() (exchange.Book, []float64) {
	// Used to compare timestamps
	timestamps := make([]float64, 40)

	// Send GET request
	url := fmt.Sprintf("%s/v1/book/%s%s?limit_bids=%d&limit_asks=%d", client.baseURL, client.symbol, client.currency, 20, 20)
	data, err := client.get(url)
	if err != nil {
		return exchange.Book{Error: fmt.Errorf("%s UpdateBook error: %s", client, err.Error())}, timestamps
	}

	// Format returned from the exchange
	var tmp struct {
		Bids []struct {
			Price     float64 `json:"price,string"`
			Amount    float64 `json:"amount,string"`
			Timestamp float64 `json:"timestamp,string"`
		} `json:"bids"`
		Asks []struct {
			Price     float64 `json:"price,string"`
			Amount    float64 `json:"amount,string"`
			Timestamp float64 `json:"timestamp,string"`
		} `json:"asks"`
	}
	if err := json.Unmarshal(data, &tmp); err != nil {
		return exchange.Book{Error: fmt.Errorf("%s UpdateBook error: %s", client, err.Error())}, timestamps
	}

	// Translate into an exchange.Book
	bids := make(exchange.BidItems, 20)
	asks := make(exchange.AskItems, 20)
	for i := 0; i < 20; i++ {
		bids[i].Price = tmp.Bids[i].Price
		bids[i].Amount = tmp.Bids[i].Amount
		asks[i].Price = tmp.Asks[i].Price
		asks[i].Amount = tmp.Asks[i].Amount
		timestamps[i] = tmp.Bids[i].Timestamp
		timestamps[i+20] = tmp.Asks[i].Timestamp
	}
	sort.Sort(bids)
	sort.Sort(asks)

	// Return book and timestamps
	return exchange.Book{
		Exg:   client,
		Time:  time.Now(),
		Bids:  bids,
		Asks:  asks,
		Error: nil,
	}, timestamps
}

// Returns true if the book has changed
func bookChanged(timestamps1, timestamps2 []float64) bool {
	for i := 0; i < 40; i++ {
		if math.Abs(timestamps1[i]-timestamps2[i]) > .5 {
			return true
		}
	}
	return false
}

// SendOrder sends an order to the exchange
func (client *Client) SendOrder(action, otype string, amount, price float64) (int64, error) {
	// Create request struct
	request := struct {
		URL      string  `json:"request"`
		Nonce    string  `json:"nonce"`
		Symbol   string  `json:"symbol"`
		Amount   float64 `json:"amount,string"`
		Price    float64 `json:"price,string"`
		Exchange string  `json:"exchange"`
		Side     string  `json:"side"`
		Type     string  `json:"type"`
	}{
		"/v1/order/new",
		strconv.FormatInt(time.Now().UnixNano(), 10),
		client.symbol + client.currency,
		amount,
		price,
		"bitfinex",
		action,
		otype,
	}

	// Send POST request
	data, err := client.post(client.baseURL+request.URL, request)
	if err != nil {
		return 0, fmt.Errorf("%s SendOrder error: %s", client, err.Error())
	}

	// Unmarshal response
	var response struct {
		ID      int64  `json:"order_id"`
		Message string `json:"message"`
	}
	err = json.Unmarshal(data, &response)
	if err != nil {
		return 0, fmt.Errorf("%s SendOrder error: %s", client, err.Error())
	}
	if response.Message != "" {
		return 0, fmt.Errorf("%s SendOrder error: %s", client, response.Message)
	}

	return response.ID, nil
}

// CancelOrder cancels an order on the exchange
func (client *Client) CancelOrder(id int64) (bool, error) {
	// Create request struct
	request := struct {
		URL     string `json:"request"`
		Nonce   string `json:"nonce"`
		OrderID int64  `json:"order_id"`
	}{
		"/v1/order/cancel",
		strconv.FormatInt(time.Now().UnixNano(), 10),
		id,
	}

	// Send POST request
	data, err := client.post(client.baseURL+request.URL, request)
	if err != nil {
		return false, fmt.Errorf("%s CancelOrder error: %s", client, err.Error())
	}

	// Unmarshal response
	var response struct {
		Message string `json:"message"`
	}
	err = json.Unmarshal(data, &response)
	if err != nil {
		return false, fmt.Errorf("%s CancelOrder error: %s", client, err.Error())
	}
	if response.Message != "" {
		return false, fmt.Errorf("%s CancelOrder error: %s", client, response.Message)
	}

	return true, nil
}

// GetOrderStatus gets the status of an order on the exchange
func (client *Client) GetOrderStatus(id int64) (exchange.Order, error) {
	// Create request struct
	request := struct {
		URL     string `json:"request"`
		Nonce   string `json:"nonce"`
		OrderID int64  `json:"order_id"`
	}{
		"/v1/order/status",
		strconv.FormatInt(time.Now().UnixNano(), 10),
		id,
	}

	// Create order to be returned
	var order exchange.Order

	// Send POST request
	data, err := client.post(client.baseURL+request.URL, request)
	if err != nil {
		return order, fmt.Errorf("%s GetOrderStatus error: %s", client, err.Error())
	}

	// Unmarshal response
	var response struct {
		Message        string  `json:"message"`
		IsLive         bool    `json:"is_live,bool"`
		ExecutedAmount float64 `json:"executed_amount,string"`
	}
	err = json.Unmarshal(data, &response)
	if err != nil {
		return order, fmt.Errorf("%s GetOrderStatus error: %s", client, err.Error())
	}
	if response.Message != "" {
		return order, fmt.Errorf("%s GetOrderStatus error: %s", client, response.Message)
	}

	if response.IsLive {
		order.Status = "live"
	} else {
		order.Status = "dead"
	}
	order.FilledAmount = math.Abs(response.ExecutedAmount)
	return order, nil
}

// Authenticated POST
func (client *Client) post(url string, payload interface{}) ([]byte, error) {
	// Payload = parameters-dictionary -> JSON encode -> base64
	payloadJSON, err := json.Marshal(payload)
	if err != nil {
		return []byte{}, err
	}
	payloadBase64 := base64.StdEncoding.EncodeToString(payloadJSON)

	// Signature = HMAC-SHA384(payload, api-secret) as hexadecimal
	h := hmac.New(sha512.New384, []byte(client.secret))
	h.Write([]byte(payloadBase64))
	signature := hex.EncodeToString(h.Sum(nil))

	req, err := http.NewRequest("POST", url, nil)
	if err != nil {
		return []byte{}, err
	}

	// HTTP headers:
	// X-BFX-APIKEY
	// X-BFX-PAYLOAD
	// X-BFX-SIGNATURE
	req.Header.Add("X-BFX-APIKEY", client.key)
	req.Header.Add("X-BFX-PAYLOAD", payloadBase64)
	req.Header.Add("X-BFX-SIGNATURE", signature)

	httpClient := http.Client{}
	resp, err := httpClient.Do(req)
	if err != nil {
		return []byte{}, err
	}
	defer resp.Body.Close()

	return ioutil.ReadAll(resp.Body)
}

// Unauthenticated GET
func (client *Client) get(url string) ([]byte, error) {
	resp, err := http.Get(url)
	if err != nil {
		return []byte{}, err
	}
	if resp.StatusCode != 200 {
		return []byte{}, fmt.Errorf(resp.Status)
	}
	defer resp.Body.Close()

	return ioutil.ReadAll(resp.Body)
}
<commit_msg>clean up Client struct format<commit_after>// Bitfinex exchange API

package bitfinex

import (
	"bitfx2/exchange"
	"crypto/hmac"
	"crypto/sha512"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"math"
	"net/http"
	"sort"
	"strconv"
	"time"
)

// Client contains all exchange information
type Client struct {
	key, secret, symbol, currency, name, baseURL  string
	priority                                      int
	position, fee, maxPos, availShort, availFunds float64
	currencyCode                                  byte
}

// New returns a pointer to a new Bitfinex instance
func New(key, secret, symbol, currency string, priority int, fee, availShort, availFunds float64) *Client {
	return &Client{
		key:          key,
		secret:       secret,
		symbol:       symbol,
		currency:     currency,
		priority:     priority,
		fee:          fee,
		availShort:   availShort,
		availFunds:   availFunds,
		currencyCode: 0,
		name:         fmt.Sprintf("Bitfinex(%s)", currency),
		baseURL:      "https://api.bitfinex.com",
	}
}

// String implements the Stringer interface
func (client *Client) String() string {
	return client.name
}

// Priority returns the exchange priority for order execution
func (client *Client) Priority() int {
	return client.priority
}

// Fee returns the exchange order fee
func (client *Client) Fee() float64 {
	return client.fee
}

// SetPosition sets the exchange position
func (client *Client) SetPosition(pos float64) {
	client.position = pos
}

// Position returns the exchange position
func (client *Client) Position() float64 {
	return client.position
}

// Currency returns the exchange currency
func (client *Client) Currency() string {
	return client.currency
}

// CurrencyCode returns the exchange currency code
func (client *Client) CurrencyCode() byte {
	return client.currencyCode
}

// SetMaxPos sets the exchange max position
func (client *Client) SetMaxPos(maxPos float64) {
	client.maxPos = maxPos
}

// MaxPos returns the exchange max position
func (client *Client) MaxPos() float64 {
	return client.maxPos
}

// AvailFunds returns the exchange available funds
func (client *Client) AvailFunds() float64 {
	return client.availFunds
}

// AvailShort returns the exchange quantity available for short selling
func (client *Client) AvailShort() float64 {
	return client.availShort
}

// HasCrytpoFee returns true if fee is taken in cryptocurrency on buys
func (client *Client) HasCryptoFee() bool {
	return false
}

// CommunicateBook sends the latest available book data on the supplied channel
func (client *Client) CommunicateBook(bookChan chan<- exchange.Book, doneChan <-chan bool) exchange.Book {
	// Initial book to return
	book, _ := client.getBook()

	// Run read loop in new goroutine
	go client.runLoop(bookChan, doneChan)

	return book
}

// HTTP read loop
func (client *Client) runLoop(bookChan chan<- exchange.Book, doneChan <-chan bool) {
	// Used to compare timestamps
	oldTimestamps := make([]float64, 40)

	for {
		select {
		case <-doneChan:
			return
		default:
			book, newTimestamps := client.getBook()
			// Send out only if changed
			if bookChanged(oldTimestamps, newTimestamps) {
				bookChan <- book
			}
			oldTimestamps = newTimestamps
		}
	}
}

// Get book data with an HTTP request
func (client *Client) getBook() (exchange.Book, []float64) {
	// Used to compare timestamps
	timestamps := make([]float64, 40)

	// Send GET request
	url := fmt.Sprintf("%s/v1/book/%s%s?limit_bids=%d&limit_asks=%d", client.baseURL, client.symbol, client.currency, 20, 20)
	data, err := client.get(url)
	if err != nil {
		return exchange.Book{Error: fmt.Errorf("%s UpdateBook error: %s", client, err.Error())}, timestamps
	}

	// Format returned from the exchange
	var tmp struct {
		Bids []struct {
			Price     float64 `json:"price,string"`
			Amount    float64 `json:"amount,string"`
			Timestamp float64 `json:"timestamp,string"`
		} `json:"bids"`
		Asks []struct {
			Price     float64 `json:"price,string"`
			Amount    float64 `json:"amount,string"`
			Timestamp float64 `json:"timestamp,string"`
		} `json:"asks"`
	}
	if err := json.Unmarshal(data, &tmp); err != nil {
		return exchange.Book{Error: fmt.Errorf("%s UpdateBook error: %s", client, err.Error())}, timestamps
	}

	// Translate into an exchange.Book
	bids := make(exchange.BidItems, 20)
	asks := make(exchange.AskItems, 20)
	for i := 0; i < 20; i++ {
		bids[i].Price = tmp.Bids[i].Price
		bids[i].Amount = tmp.Bids[i].Amount
		asks[i].Price = tmp.Asks[i].Price
		asks[i].Amount = tmp.Asks[i].Amount
		timestamps[i] = tmp.Bids[i].Timestamp
		timestamps[i+20] = tmp.Asks[i].Timestamp
	}
	sort.Sort(bids)
	sort.Sort(asks)

	// Return book and timestamps
	return exchange.Book{
		Exg:   client,
		Time:  time.Now(),
		Bids:  bids,
		Asks:  asks,
		Error: nil,
	}, timestamps
}

// Returns true if the book has changed
func bookChanged(timestamps1, timestamps2 []float64) bool {
	for i := 0; i < 40; i++ {
		if math.Abs(timestamps1[i]-timestamps2[i]) > .5 {
			return true
		}
	}
	return false
}

// SendOrder sends an order to the exchange
func (client *Client) SendOrder(action, otype string, amount, price float64) (int64, error) {
	// Create request struct
	request := struct {
		URL      string  `json:"request"`
		Nonce    string  `json:"nonce"`
		Symbol   string  `json:"symbol"`
		Amount   float64 `json:"amount,string"`
		Price    float64 `json:"price,string"`
		Exchange string  `json:"exchange"`
		Side     string  `json:"side"`
		Type     string  `json:"type"`
	}{
		"/v1/order/new",
		strconv.FormatInt(time.Now().UnixNano(), 10),
		client.symbol + client.currency,
		amount,
		price,
		"bitfinex",
		action,
		otype,
	}

	// Send POST request
	data, err := client.post(client.baseURL+request.URL, request)
	if err != nil {
		return 0, fmt.Errorf("%s SendOrder error: %s", client, err.Error())
	}

	// Unmarshal response
	var response struct {
		ID      int64  `json:"order_id"`
		Message string `json:"message"`
	}
	err = json.Unmarshal(data, &response)
	if err != nil {
		return 0, fmt.Errorf("%s SendOrder error: %s", client, err.Error())
	}
	if response.Message != "" {
		return 0, fmt.Errorf("%s SendOrder error: %s", client, response.Message)
	}

	return response.ID, nil
}

// CancelOrder cancels an order on the exchange
func (client *Client) CancelOrder(id int64) (bool, error) {
	// Create request struct
	request := struct {
		URL     string `json:"request"`
		Nonce   string `json:"nonce"`
		OrderID int64  `json:"order_id"`
	}{
		"/v1/order/cancel",
		strconv.FormatInt(time.Now().UnixNano(), 10),
		id,
	}

	// Send POST request
	data, err := client.post(client.baseURL+request.URL, request)
	if err != nil {
		return false, fmt.Errorf("%s CancelOrder error: %s", client, err.Error())
	}

	// Unmarshal response
	var response struct {
		Message string `json:"message"`
	}
	err = json.Unmarshal(data, &response)
	if err != nil {
		return false, fmt.Errorf("%s CancelOrder error: %s", client, err.Error())
	}
	if response.Message != "" {
		return false, fmt.Errorf("%s CancelOrder error: %s", client, response.Message)
	}

	return true, nil
}

// GetOrderStatus gets the status of an order on the exchange
func (client *Client) GetOrderStatus(id int64) (exchange.Order, error) {
	// Create request struct
	request := struct {
		URL     string `json:"request"`
		Nonce   string `json:"nonce"`
		OrderID int64  `json:"order_id"`
	}{
		"/v1/order/status",
		strconv.FormatInt(time.Now().UnixNano(), 10),
		id,
	}

	// Create order to be returned
	var order exchange.Order

	// Send POST request
	data, err := client.post(client.baseURL+request.URL, request)
	if err != nil {
		return order, fmt.Errorf("%s GetOrderStatus error: %s", client, err.Error())
	}

	// Unmarshal response
	var response struct {
		Message        string  `json:"message"`
		IsLive         bool    `json:"is_live,bool"`
		ExecutedAmount float64 `json:"executed_amount,string"`
	}
	err = json.Unmarshal(data, &response)
	if err != nil {
		return order, fmt.Errorf("%s GetOrderStatus error: %s", client, err.Error())
	}
	if response.Message != "" {
		return order, fmt.Errorf("%s GetOrderStatus error: %s", client, response.Message)
	}

	if response.IsLive {
		order.Status = "live"
	} else {
		order.Status = "dead"
	}
	order.FilledAmount = math.Abs(response.ExecutedAmount)
	return order, nil
}

// Authenticated POST
func (client *Client) post(url string, payload interface{}) ([]byte, error) {
	// Payload = parameters-dictionary -> JSON encode -> base64
	payloadJSON, err := json.Marshal(payload)
	if err != nil {
		return []byte{}, err
	}
	payloadBase64 := base64.StdEncoding.EncodeToString(payloadJSON)

	// Signature = HMAC-SHA384(payload, api-secret) as hexadecimal
	h := hmac.New(sha512.New384, []byte(client.secret))
	h.Write([]byte(payloadBase64))
	signature := hex.EncodeToString(h.Sum(nil))

	req, err := http.NewRequest("POST", url, nil)
	if err != nil {
		return []byte{}, err
	}

	// HTTP headers:
	// X-BFX-APIKEY
	// X-BFX-PAYLOAD
	// X-BFX-SIGNATURE
	req.Header.Add("X-BFX-APIKEY", client.key)
	req.Header.Add("X-BFX-PAYLOAD", payloadBase64)
	req.Header.Add("X-BFX-SIGNATURE", signature)

	httpClient := http.Client{}
	resp, err := httpClient.Do(req)
	if err != nil {
		return []byte{}, err
	}
	defer resp.Body.Close()

	return ioutil.ReadAll(resp.Body)
}

// Unauthenticated GET
func (client *Client) get(url string) ([]byte, error) {
	resp, err := http.Get(url)
	if err != nil {
		return []byte{}, err
	}
	if resp.StatusCode != 200 {
		return []byte{}, fmt.Errorf(resp.Status)
	}
	defer resp.Body.Close()

	return ioutil.ReadAll(resp.Body)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/deferpanic/dpcli/api"
	"os"
	"strings"
)

// supportedDarwin contains the list of known osx versions that work
var supportedDarwin = []string{"10.11.4", "10.11.5", "10.11.6", "10.12", "10.12.2", "10.12.3", "10.12.6", "10.13.1"}

// darwinFW contains the known list of osx versions that need the
// fw.enable sysctl setting
var darwinFW = []string{"10.11.4", "10.11.5", "10.11.6"}

// checkHAX returns true if HAX support is enabled
func checkHAX() bool {
	out := strings.TrimSpace(runCmd("kextstat | grep -c hax"))
	if out == "1" {
		return true
	} else {
		return false
	}
}

// needsFW returns true if we need the fw.enable sysctl setting
func needsFW(vers string) bool {
	for i := 0; i < len(darwinFW); i++ {
		if darwinFW[i] == vers {
			return true
		}
	}

	return false
}

// osCheck ensures we are dealing with el capitan or above
func osCheck() string {
	out := strings.TrimSpace(runCmd("sw_vers -productVersion"))
	for i := 0; i < len(supportedDarwin); i++ {
		if supportedDarwin[i] == out {
			fmt.Println(api.GreenBold("found supported osx version"))
			return out
		}
	}

	fmt.Printf(api.RedBold(fmt.Sprintf("You are running osX version %s\n", out)))
	fmt.Printf(api.RedBold(fmt.Sprintf("This is only tested on osX %v.\n"+
		"pf_ctl is used. If using an earlier osx you might need to use natd "+
		"or contribute a patch :)\n", supportedDarwin)))
	os.Exit(1)
	return ""
}

// cpulimitCheck looks for cpulimit which helps languages that use a lot
// of cpu
func cpulimitCheck() {
	out := strings.TrimSpace(runCmd("/usr/bin/which cpulimit"))
	if out == "" {
		fmt.Println(api.RedBold("cpulimit not found - installing..."))
		runCmd("brew install cpulimit")
	} else {
		fmt.Println(api.GreenBold("found cpulimit"))
	}
}

func qemuCheck() {
	out := strings.TrimSpace(runCmd("which qemu-system-x86_64"))
	if out == "qemu-system-x86_64 not found" {
		fmt.Println(api.RedBold("qemu not found - installing..."))
		runCmd("brew install qemu")
	} else {
		fmt.Println(api.GreenBold("found qemu"))
	}
}

func tuntapCheck() {
	out := strings.TrimSpace(runCmd("sudo kextstat | grep tap"))
	if out != "" {
		fmt.Println(api.GreenBold("found tuntap support"))
	} else {
		fmt.Println(api.RedBold("Please download and install tuntaposx"))
		fmt.Println(api.RedBold("wget http://downloads.sourceforge.net/tuntaposx/tuntap_20150118.tar.gz"))
		os.Exit(1)
	}
}
<commit_msg>bumping osx version<commit_after>package main

import (
	"fmt"
	"github.com/deferpanic/dpcli/api"
	"os"
	"strings"
)

// supportedDarwin contains the list of known osx versions that work
var supportedDarwin = []string{"10.11.4", "10.11.5", "10.11.6", "10.12", "10.12.2", "10.12.3", "10.12.6", "10.13.1", "10.13.3"}

// darwinFW contains the known list of osx versions that need the
// fw.enable sysctl setting
var darwinFW = []string{"10.11.4", "10.11.5", "10.11.6"}

// checkHAX returns true if HAX support is enabled
func checkHAX() bool {
	out := strings.TrimSpace(runCmd("kextstat | grep -c hax"))
	if out == "1" {
		return true
	} else {
		return false
	}
}

// needsFW returns true if we need the fw.enable sysctl setting
func needsFW(vers string) bool {
	for i := 0; i < len(darwinFW); i++ {
		if darwinFW[i] == vers {
			return true
		}
	}

	return false
}

// osCheck ensures we are dealing with el capitan or above
func osCheck() string {
	out := strings.TrimSpace(runCmd("sw_vers -productVersion"))
	for i := 0; i < len(supportedDarwin); i++ {
		if supportedDarwin[i] == out {
			fmt.Println(api.GreenBold("found supported osx version"))
			return out
		}
	}

	fmt.Printf(api.RedBold(fmt.Sprintf("You are running osX version %s\n", out)))
	fmt.Printf(api.RedBold(fmt.Sprintf("This is only tested on osX %v.\n"+
		"pf_ctl is used. If using an earlier osx you might need to use natd "+
		"or contribute a patch :)\n", supportedDarwin)))
	os.Exit(1)
	return ""
}

// cpulimitCheck looks for cpulimit which helps languages that use a lot
// of cpu
func cpulimitCheck() {
	out := strings.TrimSpace(runCmd("/usr/bin/which cpulimit"))
	if out == "" {
		fmt.Println(api.RedBold("cpulimit not found - installing..."))
		runCmd("brew install cpulimit")
	} else {
		fmt.Println(api.GreenBold("found cpulimit"))
	}
}

func qemuCheck() {
	out := strings.TrimSpace(runCmd("which qemu-system-x86_64"))
	if out == "qemu-system-x86_64 not found" {
		fmt.Println(api.RedBold("qemu not found - installing..."))
		runCmd("brew install qemu")
	} else {
		fmt.Println(api.GreenBold("found qemu"))
	}
}

func tuntapCheck() {
	out := strings.TrimSpace(runCmd("sudo kextstat | grep tap"))
	if out != "" {
		fmt.Println(api.GreenBold("found tuntap support"))
	} else {
		fmt.Println(api.RedBold("Please download and install tuntaposx"))
		fmt.Println(api.RedBold("wget http://downloads.sourceforge.net/tuntaposx/tuntap_20150118.tar.gz"))
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"errors"
	"flag"
	"fmt"
	"html"
	"io/ioutil"
	"net/http"
	"os"
	"os/user"
	"regexp"
	"strings"

	"github.com/imwally/pinboard"
)

var (
	options   = flag.NewFlagSet("", flag.ExitOnError)
	privFlag  = options.Bool("private", false, "private bookmark")
	readFlag  = options.Bool("readlater", false, "read later bookmark")
	longFlag  = options.Bool("l", false, "display long format")
	extFlag   = options.String("text", "", "longer description of bookmark")
	tagFlag   = options.String("tag", "", "space delimited tags for bookmark")
	titleFlag = options.String("title", "", "title of the bookmark")

	token string
)

var usage = `Usage: pin
  pin rm  URL
  pin add URL [OPTION]
  pin ls [OPTION]

Options:
  -title      title of bookmark being added
  -tag        space delimited tags
  -private    mark bookmark as private
  -readlater  mark bookmark as read later
  -text       longer description of bookmark
  -l          long format for ls
`

// COUNT is the number of bookmarks to display.
const COUNT int = 50

// Piped is a helper function to check for piped input. It will return
// input, true if data was piped.
func Piped() (string, bool) {
	fi, err := os.Stdin.Stat()
	if err != nil {
		fmt.Fprintf(os.Stderr, "pin: %s", err)
		return "", false
	}

	isPipe := (fi.Mode() & os.ModeNamedPipe) == os.ModeNamedPipe
	if isPipe {
		read := bufio.NewReader(os.Stdin)
		line, _, err := read.ReadLine()
		if err != nil {
			fmt.Fprintf(os.Stderr, "pin: %s", err)
			return "", false
		}
		return string(line), true
	}

	return "", false
}

// PageTitle attempts to parse an HTML document for the <title> tag
// using the regexp package.
func PageTitle(url string) (title string, err error) {
	resp, err := http.Get(url)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	// A regular expression that searches for any characters or
	// new lines within the bounds of <title> and </title>.
	re := regexp.MustCompile("<title>(?s)(.*?)(?s)</title>")
	t := string(re.FindSubmatch(body)[1])

	// If no title is found, return an error.
	if len(t) < 1 {
		return "", errors.New("pin: couldn't get page title")
	}

	// Trim new lines and white spaces from title.
	t = strings.TrimSpace(t)

	return html.UnescapeString(t), nil
}

// Add checks flag values and encodes the GET URL for adding a bookmark.
func Add(p *pinboard.Post) {
	var args []string

	// Check if URL is piped in or first argument. Optional tags
	// should follow the URL.
	if url, ok := Piped(); ok {
		p.URL = url
		args = flag.Args()[1:]
	} else {
		p.URL = flag.Args()[1]
		args = flag.Args()[2:]
	}

	// Parse flags after the URL.
	options.Parse(args)

	if *titleFlag != "" {
		p.Description = *titleFlag
	} else {
		// Use page title if title flag is not supplied.
		title, err := PageTitle(p.URL)
		if err != nil {
			fmt.Fprintf(os.Stderr, "pin: %s: %s\n", err, p.URL)
			return
		}

		p.Description = title
	}

	if *privFlag {
		p.Shared = "no"
	}

	if *readFlag {
		p.Toread = "yes"
	}

	p.Extended = *extFlag
	p.Tags = *tagFlag

	err := p.Add()
	if err != nil {
		fmt.Fprintf(os.Stderr, "pin: %s\n", err)
	}
}

// Delete will delete the URL specified.
func Delete(p *pinboard.Post) {
	// Check if URL is piped in or first argument.
	if url, ok := Piped(); ok {
		p.URL = url
	} else {
		p.URL = flag.Args()[1]
	}

	err := p.Delete()
	if err != nil {
		fmt.Fprintf(os.Stderr, "pin: %s\n", err)
	}
}

// Show will list the most recent bookmarks. The -tag and -readlater
// flags can be used to filter results.
func Show(p *pinboard.Post) {
	args := flag.Args()[1:]
	options.Parse(args)

	if *tagFlag != "" {
		p.Tag = *tagFlag
	}
	if *readFlag {
		p.Toread = "yes"
	}

	p.Count = COUNT

	recent := p.ShowRecent()
	for _, v := range recent.Posts {
		if *longFlag {
			var shared, unread string
			if v.Shared == "no" {
				shared = "[*]"
			}
			if v.Toread == "yes" {
				unread = "[#]"
			}
			fmt.Println(unread + shared + v.Description)
			fmt.Println(v.Href)
			if v.Extended != "" {
				fmt.Println(v.Extended)
			}
			fmt.Println(v.Tags, "\n")
		} else {
			fmt.Println(v.Href)
		}
	}
}

// Help prints pin's usage text.
func Help(p *pinboard.Post) {
	fmt.Printf("%s", usage)
}

// Start takes a map of command names to functions, parses flag
// arguments, initialises a new pinboard.Post and runs the command if
// found.
func Start(cmds map[string]func(p *pinboard.Post)) {
	flag.Parse()
	if flag.NArg() < 1 {
		fmt.Fprintf(os.Stderr, "pin: no command is given.\n")
		return
	}

	cmdName := flag.Arg(0)

	cmd, ok := cmds[cmdName]
	if !ok {
		fmt.Fprintf(os.Stderr, "pin: command %s not found.\n", cmdName)
		return
	}

	// Initialise a new Pinboard post and token.
	p := new(pinboard.Post)
	p.Token = token

	cmd(p)
}

// TokenIsSet will check to make sure an authentication token is set before
// making any API calls.
func TokenIsSet() bool {
	return token != ""
}

func init() {
	u, err := user.Current()
	if err != nil {
		fmt.Fprintf(os.Stderr, "pin: %s", err)
	}

	content, err := ioutil.ReadFile(u.HomeDir + "/.pinboard")
	if err != nil {
		fmt.Fprintf(os.Stderr, "pin: No authorization token found. Please add your authorization token to ~/.pinboard\n")
	}

	token = string(content)
}

func main() {
	if !TokenIsSet() {
		return
	}

	cmds := map[string]func(*pinboard.Post){
		"help": Help,
		"add":  Add,
		"rm":   Delete,
		"ls":   Show,
	}

	Start(cmds)
}
<commit_msg>Better title checking in PageTitle.<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"html"
	"io/ioutil"
	"net/http"
	"os"
	"os/user"
	"regexp"
	"strings"

	"github.com/imwally/pinboard"
)

var (
	options   = flag.NewFlagSet("", flag.ExitOnError)
	privFlag  = options.Bool("private", false, "private bookmark")
	readFlag  = options.Bool("readlater", false, "read later bookmark")
	longFlag  = options.Bool("l", false, "display long format")
	extFlag   = options.String("text", "", "longer description of bookmark")
	tagFlag   = options.String("tag", "", "space delimited tags for bookmark")
	titleFlag = options.String("title", "", "title of the bookmark")

	token string
)

var usage = `Usage: pin
  pin rm  URL
  pin add URL [OPTION]
  pin ls [OPTION]

Options:
  -title      title of bookmark being added
  -tag        space delimited tags
  -private    mark bookmark as private
  -readlater  mark bookmark as read later
  -text       longer description of bookmark
  -l          long format for ls
`

// COUNT is the number of bookmarks to display.
const COUNT int = 50

// Piped is a helper function to check for piped input. It will return
// input, true if data was piped.
func Piped() (string, bool) {
	fi, err := os.Stdin.Stat()
	if err != nil {
		fmt.Fprintf(os.Stderr, "pin: %s", err)
		return "", false
	}

	isPipe := (fi.Mode() & os.ModeNamedPipe) == os.ModeNamedPipe
	if isPipe {
		read := bufio.NewReader(os.Stdin)
		line, _, err := read.ReadLine()
		if err != nil {
			fmt.Fprintf(os.Stderr, "pin: %s", err)
			return "", false
		}
		return string(line), true
	}

	return "", false
}

// PageTitle attempts to parse an HTML document for the <title> tag
// using the regexp package. If no title is found then the url itself
// is returned as the title.
func PageTitle(url string) (title string, err error) {
	// Check first to see if this is an HTML document.
	head, err := http.Head(url)
	if err != nil {
		return "", err
	}

	// This is not an HTML document, using URL as title.
	if !strings.Contains(head.Header["Content-Type"][0], "text/html") {
		return url, nil
	}

	// Carry on getting the HTML document.
	resp, err := http.Get(url)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	// A regular expression that searches for any characters or
	// new lines within the bounds of <title> and </title>.
	re := regexp.MustCompile("<title>(?s)(.*?)(?s)</title>")
	t := string(re.FindSubmatch(body)[1])

	// No title found, using URL as title.
	if len(t) < 1 {
		return url, nil
	}

	// Trim new lines and white spaces from title.
	t = strings.TrimSpace(t)

	return html.UnescapeString(t), nil
}

// Add checks flag values and encodes the GET URL for adding a bookmark.
func Add(p *pinboard.Post) {
	var args []string

	// Check if URL is piped in or first argument. Optional tags
	// should follow the URL.
	if url, ok := Piped(); ok {
		p.URL = url
		args = flag.Args()[1:]
	} else {
		p.URL = flag.Args()[1]
		args = flag.Args()[2:]
	}

	// Parse flags after the URL.
	options.Parse(args)

	if *titleFlag != "" {
		p.Description = *titleFlag
	} else {
		// Use page title if title flag is not supplied.
		title, err := PageTitle(p.URL)
		if err != nil {
			fmt.Fprintf(os.Stderr, "pin: %s: %s\n", err, p.URL)
			return
		}

		p.Description = title
	}

	if *privFlag {
		p.Shared = "no"
	}

	if *readFlag {
		p.Toread = "yes"
	}

	p.Extended = *extFlag
	p.Tags = *tagFlag

	err := p.Add()
	if err != nil {
		fmt.Fprintf(os.Stderr, "pin: %s\n", err)
	}
}

// Delete will delete the URL specified.
func Delete(p *pinboard.Post) {
	// Check if URL is piped in or first argument.
	if url, ok := Piped(); ok {
		p.URL = url
	} else {
		p.URL = flag.Args()[1]
	}

	err := p.Delete()
	if err != nil {
		fmt.Fprintf(os.Stderr, "pin: %s\n", err)
	}
}

// Show will list the most recent bookmarks. The -tag and -readlater
// flags can be used to filter results.
func Show(p *pinboard.Post) {
	args := flag.Args()[1:]
	options.Parse(args)

	if *tagFlag != "" {
		p.Tag = *tagFlag
	}
	if *readFlag {
		p.Toread = "yes"
	}

	p.Count = COUNT

	recent := p.ShowRecent()
	for _, v := range recent.Posts {
		if *longFlag {
			var shared, unread string
			if v.Shared == "no" {
				shared = "[*]"
			}
			if v.Toread == "yes" {
				unread = "[#]"
			}
			fmt.Println(unread + shared + v.Description)
			fmt.Println(v.Href)
			if v.Extended != "" {
				fmt.Println(v.Extended)
			}
			fmt.Println(v.Tags, "\n")
		} else {
			fmt.Println(v.Href)
		}
	}
}

// Help prints pin's usage text.
func Help(p *pinboard.Post) {
	fmt.Printf("%s", usage)
}

// Start takes a map of command names to functions, parses flag
// arguments, initialises a new pinboard.Post and runs the command if
// found.
func Start(cmds map[string]func(p *pinboard.Post)) {
	flag.Parse()
	if flag.NArg() < 1 {
		fmt.Fprintf(os.Stderr, "pin: no command is given.\n")
		return
	}

	cmdName := flag.Arg(0)

	cmd, ok := cmds[cmdName]
	if !ok {
		fmt.Fprintf(os.Stderr, "pin: command %s not found.\n", cmdName)
		return
	}

	// Initialise a new Pinboard post and token.
	p := new(pinboard.Post)
	p.Token = token

	cmd(p)
}

// TokenIsSet will check to make sure an authentication token is set before
// making any API calls.
func TokenIsSet() bool {
	return token != ""
}

func init() {
	u, err := user.Current()
	if err != nil {
		fmt.Fprintf(os.Stderr, "pin: %s", err)
	}

	content, err := ioutil.ReadFile(u.HomeDir + "/.pinboard")
	if err != nil {
		fmt.Fprintf(os.Stderr, "pin: No authorization token found. Please add your authorization token to ~/.pinboard\n")
	}

	token = string(content)
}

func main() {
	if !TokenIsSet() {
		return
	}

	cmds := map[string]func(*pinboard.Post){
		"help": Help,
		"add":  Add,
		"rm":   Delete,
		"ls":   Show,
	}

	Start(cmds)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	"golang.org/x/net/html"
	"golang.org/x/net/html/charset"
)

//      _=,_
//   o_/6 /#\
//   \__ |##/
//    ='|--\
//      /   #'-.
//      \#|_   _'-. /
//       |/ \_( # |"
//      C/ ,--___/

var VERSION string = "0.3.4"

func main() {
	// process flags and arguments
	cmds, err := ParseArgs()
	if err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err.Error())
		os.Exit(2)
	}

	// Determine the charset of the input
	cr, err := charset.NewReader(pupIn, "")
	if err != nil {
		fmt.Fprintf(os.Stderr, err.Error())
		os.Exit(2)
	}

	// Parse the input and get the root node
	root, err := html.Parse(cr)
	if err != nil {
		fmt.Fprintf(os.Stderr, err.Error())
		os.Exit(2)
	}

	// Parse the selectors
	selectorFuncs := []SelectorFunc{}
	funcGenerator := Select
	var cmd string
	for len(cmds) > 0 {
		cmd, cmds = cmds[0], cmds[1:]
		if len(cmds) == 0 {
			if err := ParseDisplayer(cmd); err == nil {
				continue
			}
		}
		switch cmd {
		case "*":
			continue
		case "+":
			funcGenerator = SelectFromChildren
		case ">":
			funcGenerator = SelectNextSibling
		default:
			selector, err := ParseSelector(cmd)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Selector parsing error: %s\n", err.Error())
				os.Exit(2)
			}
			selectorFuncs = append(selectorFuncs, funcGenerator(selector))
			funcGenerator = Select
		}
	}

	currNodes := []*html.Node{root}
	for _, selectorFunc := range selectorFuncs {
		currNodes = selectorFunc(currNodes)
	}
	pupDisplayer.Display(currNodes)
}
<commit_msg>comma separated selectors added<commit_after>package main

import (
	"fmt"
	"os"

	"golang.org/x/net/html"
	"golang.org/x/net/html/charset"
)

//      _=,_
//   o_/6 /#\
//   \__ |##/
//    ='|--\
//      /   #'-.
//      \#|_   _'-. /
//       |/ \_( # |"
//      C/ ,--___/

var VERSION string = "0.3.4"

func main() {
	// process flags and arguments
	cmds, err := ParseArgs()
	if err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err.Error())
		os.Exit(2)
	}

	// Determine the charset of the input
	cr, err := charset.NewReader(pupIn, "")
	if err != nil {
		fmt.Fprintf(os.Stderr, err.Error())
		os.Exit(2)
	}

	// Parse the input and get the root node
	root, err := html.Parse(cr)
	if err != nil {
		fmt.Fprintf(os.Stderr, err.Error())
		os.Exit(2)
	}

	// Parse the selectors
	selectorFuncs := []SelectorFunc{}
	funcGenerator := Select
	var cmd string
	for len(cmds) > 0 {
		cmd, cmds = cmds[0], cmds[1:]
		if len(cmds) == 0 {
			if err := ParseDisplayer(cmd); err == nil {
				continue
			}
		}
		switch cmd {
		case "*": // select all
			continue
		case "+":
			funcGenerator = SelectFromChildren
		case ">":
			funcGenerator = SelectNextSibling
		case ",": // nil will signify a comma
			selectorFuncs = append(selectorFuncs, nil)
		default:
			selector, err := ParseSelector(cmd)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Selector parsing error: %s\n", err.Error())
				os.Exit(2)
			}
			selectorFuncs = append(selectorFuncs, funcGenerator(selector))
			funcGenerator = Select
		}
	}

	selectedNodes := []*html.Node{}
	currNodes := []*html.Node{root}
	for _, selectorFunc := range selectorFuncs {
		if selectorFunc == nil { // hit a comma
			selectedNodes = append(selectedNodes, currNodes...)
			currNodes = []*html.Node{root}
		} else {
			currNodes = selectorFunc(currNodes)
		}
	}
	selectedNodes = append(selectedNodes, currNodes...)
	pupDisplayer.Display(selectedNodes)
}
<|endoftext|>


<commit_before>package hpcloud

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	//"strings"
)

/*
 ListDBInstances will list all the available database instances
*/
func (a Access) ListDBInstances() (*DBInstances, error) {
	url := fmt.Sprintf("%s%s/instances", RDB_URL, a.TenantID)
	body, err := a.baseRequest(url, "GET", nil)
	if err != nil {
		return nil, err
	}
	dbs := &DBInstances{}
	err = json.Unmarshal(body, dbs)
	if err != nil {
		return nil, err
	}
	return dbs, nil
}

/*
 CreateDBInstance creates new database instance in the HPCloud using
settings found in the DatabaseReq instance passed to this function

 This function implements the interface as described in:
 http://api-docs.hpcloud.com/hpcloud-rdb-mysql/1.0/content/create-instance.html
*/
/*func (a Access) CreateDBInstance(db DatabaseReq) (*NewDBInstance, error) {
	b, err := db.MarshalJSON()
	if err != nil {
		return nil, err
	}

	body, err := a.baseRDBRequest("instances", "POST",
		strings.NewReader(string(b)))
	if err != nil {
		return nil, err
	}

	sr := &NewDBInstance{}
	err = json.Unmarshal(body, sr)
	if err != nil {
		return nil, err
	}
	return sr, nil
} */

type DBInstance struct {
	Created string  `json:"created"`
	Flavor  Flavor_ `json:"flavor"`
	Id      string  `json:"id"`
	Links   []Link  `json:"links"`
	Name    string  `json:"name"`
	Status  string  `json:"name"`
}

type DBInstances struct {
	Instances []DBInstance `json:"instances"`
}

/*
 This type describes the JSON data which should be sent to the
create database instance resource.
*/
type DatabaseReq struct {
	Instance Database `json:"instance"`
}

type Database struct {
	Name      string       `json:"name"`
	FlavorRef string       `json:"flavorRef"`
	Port      int          `json:"port"`
	Dbtype    DatabaseType `json:"port"`
}

type DatabaseType struct {
	Name    string `json:"name"`
	Version string `json:"version"`
}

/*
 This type describes JSON response from a successful CreateDBInstance
 call.
*/
type NewDBInstance struct {
	Created        string        `json:"created"`
	Credential     DBCredentials `json:"credential"`
	Flavor         Flavor_       `json:"flavor"`
	Hostname       string        `json:"hostname"`
	Id             string        `json:"id"`
	Links          []Link        `json:"links"`
	Name           string        `json:"name"`
	SecurityGroups []DBSecGroups `json:"security_groups"`
	Status         string        `json:"status"`
}

/*
 This type describes Database Security groups
*/
type DBSecGroups struct {
	Id    string `json:"id"`
	Links []Link `json:"links"`
}

/*
 This type describes Database Credentials
*/
type DBCredentials struct {
	Password string `json:"password"`
	Username string `json:"username"`
}
<commit_msg>added list flavors method<commit_after>package hpcloud

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	//"strings"
)

/*
 ListDBInstances will list all the available database instances
*/
func (a Access) ListDBInstances() (*DBInstances, error) {
	url := fmt.Sprintf("%s%s/instances", RDB_URL, a.TenantID)
	body, err := a.baseRequest(url, "GET", nil)
	if err != nil {
		return nil, err
	}
	dbs := &DBInstances{}
	err = json.Unmarshal(body, dbs)
	if err != nil {
		return nil, err
	}
	return dbs, nil
}

func (a Access) ListAllFlavors() (*DBFlavors, error) {
	url := fmt.Sprintf("%s%s/flavors", RDB_URL, a.TenantID)
	body, err := a.baseRequest(url, "GET", nil)
	if err != nil {
		return nil, err
	}

	flv := &DBFlavors{}
	err = json.Unmarshal(body, flv)
	if err != nil {
		return nil, err
	}
	return flv, nil
}

/*
 CreateDBInstance creates new database instance in the HPCloud using
settings found in the DatabaseReq instance passed to this function

 This function implements the interface as described in:
 http://api-docs.hpcloud.com/hpcloud-rdb-mysql/1.0/content/create-instance.html
*/ /*
func (a Access) CreateDBInstance(db DatabaseReq) (*NewDBInstance, error) {
	b, err := json.M
	if err != nil {
		return nil, err
	}

	url := fmt.Sprintf("%s%s/instances", RDB_URL, a.TenantID)

	body, err := a.baseRequest(url, "POST",
		strings.NewReader(string(b)))
	if err != nil {
		return nil, err
	}

	sr := &NewDBInstance{}
	err = json.Unmarshal(body, sr)
	if err != nil {
		return nil, err
	}
	return sr, nil
}*/

type DBInstance struct {
	Created string  `json:"created"`
	Flavor  Flavor_ `json:"flavor"`
	Id      string  `json:"id"`
	Links   []Link  `json:"links"`
	Name    string  `json:"name"`
	Status  string  `json:"name"`
}

type DBInstances struct {
	Instances []DBInstance `json:"instances"`
}

type Database struct {
	Name      string `json:"name"`
	FlavorRef string `json:"flavorRef"`
	Port      int    `json:"port"`
	DBType    struct {
		Name    string `json:"name"`
		Version string `json:"version"`
	} `json:"dbtype"`
}

type DBFlavors struct {
	Flavors []DBFlavor `json:"flavors"`
}

/*
 Type describing database flavor
*/
type DBFlavor struct {
	Id    int    `json:"id"`
	Links []Link `json:"links"`
	Name  string `json:"name"`
	Ram   int    `json:"ram"`
	Vcpu  int    `json:"vcpu"`
}

/*
 This type describes the JSON data which should be sent to the
create database instance resource.
*/
type DatabaseReq struct {
	Instance Database `json:"instance"`
}

/*
 This type describes JSON response from a successful CreateDBInstance
 call.
*/
type NewDBInstance struct {
	Created        string        `json:"created"`
	Credential     DBCredentials `json:"credential"`
	Flavor         Flavor_       `json:"flavor"`
	Hostname       string        `json:"hostname"`
	Id             string        `json:"id"`
	Links          []Link        `json:"links"`
	Name           string        `json:"name"`
	SecurityGroups []DBSecGroups `json:"security_groups"`
	Status         string        `json:"status"`
}

/*
 This type describes Database Security groups
*/
type DBSecGroups struct {
	Id    string `json:"id"`
	Links []Link `json:"links"`
}

/*
 This type describes Database Credentials
*/
type DBCredentials struct {
	Password string `json:"password"`
	Username string `json:"username"`
}
<|endoftext|>