<commit_before>package rtnetlink

import (
	"errors"
	"fmt"
	"net"

	"github.com/mdlayher/netlink"
	"github.com/mdlayher/netlink/nlenc"
)

var (
	// errInvalidLinkMessage is returned when a LinkMessage is malformed.
	errInvalidLinkMessage = errors.New("rtnetlink LinkMessage is invalid or too short")

	// errInvalidLinkMessageAttr is returned when link attributes are malformed.
	errInvalidLinkMessageAttr = errors.New("rtnetlink LinkMessage has a wrong attribute data length")
)

var _ Message = &LinkMessage{}

// A LinkMessage is a route netlink link message.
type LinkMessage struct {
	// Always set to AF_UNSPEC (0)
	Family uint16

	// Device Type
	Type uint16

	// Unique interface index, using a nonzero value with
	// NewLink will instruct the kernel to create a
	// device with the given index (kernel 3.7+ required)
	Index uint32

	// Contains device flags, see netdevice(7)
	Flags uint32

	// Change Flags, reserved for future use and should
	// always be 0xffffffff
	Change uint32

	// Attributes List
	Attributes LinkAttributes
}

const linkMessageLength = 16

// MarshalBinary marshals a LinkMessage into a byte slice.
func (m *LinkMessage) MarshalBinary() ([]byte, error) {
	b := make([]byte, linkMessageLength)

	b[0] = 0 //Family
	b[1] = 0 //reserved
	nlenc.PutUint16(b[2:4], m.Type)
	nlenc.PutUint32(b[4:8], m.Index)
	nlenc.PutUint32(b[8:12], m.Flags)
	nlenc.PutUint32(b[12:16], 0) //Change, reserved

	a, err := m.Attributes.MarshalBinary()
	if err != nil {
		return nil, err
	}

	return append(b, a...), nil
}

// UnmarshalBinary unmarshals the contents of a byte slice into a LinkMessage.
func (m *LinkMessage) UnmarshalBinary(b []byte) error {
	l := len(b)
	if l < 16 {
		return errInvalidLinkMessage
	}

	m.Family = nlenc.Uint16(b[0:2])
	m.Type = nlenc.Uint16(b[2:4])
	m.Index = nlenc.Uint32(b[4:8])
	m.Flags = nlenc.Uint32(b[8:12])
	m.Change = nlenc.Uint32(b[12:16])

	if l > 16 {
		m.Attributes = LinkAttributes{}
		err := m.Attributes.UnmarshalBinary(b[16:])
		if err != nil {
			return err
		}
	}

	return nil
}

// rtMessage is an empty method to sattisfy the Message interface.
func (*LinkMessage) rtMessage() {}

// LinkService is used to retrieve rtnetlink family information.
type LinkService struct {
	c *Conn
}

// Constants used to request information from rtnetlink links.
const (
	rtmNewLink = 16
	rtmDelLink = 17
	rtmGetLink = 18
	rtmSetLink = 19
)

// New creates a new interface using the LinkMessage information.
func (l *LinkService) New(req *LinkMessage) error {
	flags := netlink.HeaderFlagsRequest
	_, err := l.c.Send(req, rtmSetLink, flags)
	if err != nil {
		return err
	}

	return nil
}

// Delete removes an interface by index.
func (l *LinkService) Delete(index uint32) error {
	req := &LinkMessage{
		Index: index,
	}

	flags := netlink.HeaderFlagsRequest
	_, err := l.c.Send(req, rtmDelLink, flags)
	if err != nil {
		return err
	}

	return nil
}

// Get retrieves interface information by index.
func (l *LinkService) Get(index uint32) (LinkMessage, error) {
	req := &LinkMessage{
		Index: index,
	}

	flags := netlink.HeaderFlagsRequest | netlink.HeaderFlagsDumpFiltered
	msg, err := l.c.Execute(req, rtmGetLink, flags)
	if err != nil {
		return LinkMessage{}, err
	}

	if len(msg) != 1 {
		return LinkMessage{}, fmt.Errorf("too many/little matches, expected 1")
	}

	link := (msg[0]).(*LinkMessage)
	return *link, nil
}

// Set sets interface attributes according to the LinkMessage information.
func (l *LinkService) Set(req *LinkMessage) error {
	flags := netlink.HeaderFlagsRequest
	_, err := l.c.Send(req, rtmSetLink, flags)
	if err != nil {
		return err
	}

	return nil
}

// List retrieves all interfaces.
func (l *LinkService) List() ([]LinkMessage, error) {
	req := &LinkMessage{}

	flags := netlink.HeaderFlagsRequest | netlink.HeaderFlagsDump
	msgs, err := l.c.Execute(req, rtmGetLink, flags)
	if err != nil {
		return nil, err
	}

	links := make([]LinkMessage, 0, len(msgs))
	for _, m := range msgs {
		link := (m).(*LinkMessage)
		links = append(links, *link)
	}

	return links, nil
}

// LinkAttributes contains all attributes for an interface.
type LinkAttributes struct {
	Address   net.HardwareAddr // Interface L2 address
	Broadcast net.HardwareAddr // L2 broadcast address
	Name      string           // Device name
	MTU       uint32           // MTU of the device
	Type      uint32           // Link type
	QueueDisc string           // Queueing discipline
	Stats     *LinkStats       // Interface Statistics
}

// Attribute IDs mapped to specific LinkAttribute fields.
const (
	iflaUnspec uint16 = iota
	iflaAddress
	iflaBroadcast
	iflaIfname
	iflaMTU
	iflaLink
	iflaQdisc
	iflaStats
)

// UnmarshalBinary unmarshals the contents of a byte slice into a LinkMessage.
func (a *LinkAttributes) UnmarshalBinary(b []byte) error {
	attrs, err := netlink.UnmarshalAttributes(b)
	if err != nil {
		return err
	}

	for _, attr := range attrs {
		switch attr.Type {
		case iflaUnspec:
			//unused attribute
		case iflaAddress:
			if len(attr.Data) != 6 {
				return errInvalidLinkMessageAttr
			}
			a.Address = attr.Data
		case iflaBroadcast:
			if len(attr.Data) != 6 {
				return errInvalidLinkMessageAttr
			}
			a.Broadcast = attr.Data
		case iflaIfname:
			a.Name = nlenc.String(attr.Data)
		case iflaMTU:
			if len(attr.Data) != 4 {
				return errInvalidLinkMessageAttr
			}
			a.MTU = nlenc.Uint32(attr.Data)
		case iflaLink:
			if len(attr.Data) != 4 {
				return errInvalidLinkMessageAttr
			}
			a.Type = nlenc.Uint32(attr.Data)
		case iflaQdisc:
			a.QueueDisc = nlenc.String(attr.Data)
		case iflaStats:
			a.Stats = &LinkStats{}
			err := a.Stats.UnmarshalBinary(attr.Data)
			if err != nil {
				return err
			}
		}
	}

	return nil
}

func uint16tobyte(v uint16) []byte {
	b := make([]byte, 2)
	nlenc.PutUint16(b, v)
	return b
}

func uint32tobyte(v uint32) []byte {
	b := make([]byte, 4)
	nlenc.PutUint32(b, v)
	return b
}

// MarshalBinary marshals a LinkAttributes into a byte slice.
func (a *LinkAttributes) MarshalBinary() ([]byte, error) {
	return netlink.MarshalAttributes([]netlink.Attribute{
		{
			Type: iflaUnspec,
			Data: uint16tobyte(0),
		},
		{
			Type: iflaAddress,
			Data: a.Address,
		},
		{
			Type: iflaBroadcast,
			Data: a.Broadcast,
		},
		{
			Type: iflaIfname,
			Data: nlenc.Bytes(a.Name),
		},
		{
			Type: iflaMTU,
			Data: uint32tobyte(a.MTU),
		},
		{
			Type: iflaLink,
			Data: uint32tobyte(a.Type),
		},
		{
			Type: iflaQdisc,
			Data: nlenc.Bytes(a.QueueDisc),
		},
		/*
			{
				Type: iflaStats,
				Data: nlenc.Bytes(name),
			},
		*/
	})
}

//LinkStats contains packet statistics
type LinkStats struct {
	RXPackets  uint32 // total packets received
	TXPackets  uint32 // total packets transmitted
	RXBytes    uint32 // total bytes received
	TXBytes    uint32 // total bytes transmitted
	RXErrors   uint32 // bad packets received
	TXErrors   uint32 // packet transmit problems
	RXDropped  uint32 // no space in linux buffers
	TXDropped  uint32 // no space available in linux
	Multicast  uint32 // multicast packets received
	Collisions uint32

	// detailed rx_errors:
	RXLengthErrors uint32
	RXOverErrors   uint32 // receiver ring buff overflow
	RXCRCErrors    uint32 // recved pkt with crc error
	RXFrameErrors  uint32 // recv'd frame alignment error
	RXFIFOErrors   uint32 // recv'r fifo overrun
	RXMissedErrors uint32 // receiver missed packet

	// detailed tx_errors
	TXAbortedErrors   uint32
	TXCarrierErrors   uint32
	TXFIFOErrors      uint32
	TXHeartbeatErrors uint32
	TXWindowErrors    uint32

	// for cslip etc
	RXCompressed uint32
	TXCompressed uint32

	RXNoHandler uint32 // dropped, no handler found
}

// UnmarshalBinary unmarshals the contents of a byte slice into a LinkMessage.
func (a *LinkStats) UnmarshalBinary(b []byte) error {
	if len(b) != 96 && len(b) != 104 {
		return fmt.Errorf("incorrect size, want: 96 or 104, got: %d", len(b))
	}

	a.RXPackets = nlenc.Uint32(b[0:4])
	a.TXPackets = nlenc.Uint32(b[4:8])
	a.RXBytes = nlenc.Uint32(b[8:12])
	a.TXBytes = nlenc.Uint32(b[12:16])
	a.RXErrors = nlenc.Uint32(b[16:20])
	a.TXErrors = nlenc.Uint32(b[20:24])
	a.RXDropped = nlenc.Uint32(b[24:28])
	a.TXDropped = nlenc.Uint32(b[28:32])
	a.Multicast = nlenc.Uint32(b[32:36])
	a.Collisions = nlenc.Uint32(b[36:40])

	a.RXLengthErrors = nlenc.Uint32(b[40:44])
	a.RXOverErrors = nlenc.Uint32(b[44:48])
	a.RXCRCErrors = nlenc.Uint32(b[48:52])
	a.RXFrameErrors = nlenc.Uint32(b[52:56])
	a.RXFIFOErrors = nlenc.Uint32(b[56:60])
	a.RXMissedErrors = nlenc.Uint32(b[60:64])

	a.TXAbortedErrors = nlenc.Uint32(b[68:72])
	a.TXCarrierErrors = nlenc.Uint32(b[76:80])
	a.TXFIFOErrors = nlenc.Uint32(b[80:84])
	a.TXHeartbeatErrors = nlenc.Uint32(b[84:88])
	a.TXWindowErrors = nlenc.Uint32(b[88:92])

	if len(b) == 96 {
		a.RXNoHandler = nlenc.Uint32(b[92:96])
	}

	if len(b) == 104 {
		a.RXCompressed = nlenc.Uint32(b[92:96])
		a.TXCompressed = nlenc.Uint32(b[96:100])
		a.RXNoHandler = nlenc.Uint32(b[100:104])
	}

	return nil
}
<commit_msg>rtnetlink: use new nlenc.Uint{16,32}Bytes<commit_after>package rtnetlink

import (
	"errors"
	"fmt"
	"net"

	"github.com/mdlayher/netlink"
	"github.com/mdlayher/netlink/nlenc"
)

var (
	// errInvalidLinkMessage is returned when a LinkMessage is malformed.
	errInvalidLinkMessage = errors.New("rtnetlink LinkMessage is invalid or too short")

	// errInvalidLinkMessageAttr is returned when link attributes are malformed.
	errInvalidLinkMessageAttr = errors.New("rtnetlink LinkMessage has a wrong attribute data length")
)

var _ Message = &LinkMessage{}

// A LinkMessage is a route netlink link message.
type LinkMessage struct {
	// Always set to AF_UNSPEC (0)
	Family uint16

	// Device Type
	Type uint16

	// Unique interface index, using a nonzero value with
	// NewLink will instruct the kernel to create a
	// device with the given index (kernel 3.7+ required)
	Index uint32

	// Contains device flags, see netdevice(7)
	Flags uint32

	// Change Flags, reserved for future use and should
	// always be 0xffffffff
	Change uint32

	// Attributes List
	Attributes LinkAttributes
}

const linkMessageLength = 16

// MarshalBinary marshals a LinkMessage into a byte slice.
func (m *LinkMessage) MarshalBinary() ([]byte, error) {
	b := make([]byte, linkMessageLength)

	b[0] = 0 //Family
	b[1] = 0 //reserved
	nlenc.PutUint16(b[2:4], m.Type)
	nlenc.PutUint32(b[4:8], m.Index)
	nlenc.PutUint32(b[8:12], m.Flags)
	nlenc.PutUint32(b[12:16], 0) //Change, reserved

	a, err := m.Attributes.MarshalBinary()
	if err != nil {
		return nil, err
	}

	return append(b, a...), nil
}

// UnmarshalBinary unmarshals the contents of a byte slice into a LinkMessage.
func (m *LinkMessage) UnmarshalBinary(b []byte) error {
	l := len(b)
	if l < 16 {
		return errInvalidLinkMessage
	}

	m.Family = nlenc.Uint16(b[0:2])
	m.Type = nlenc.Uint16(b[2:4])
	m.Index = nlenc.Uint32(b[4:8])
	m.Flags = nlenc.Uint32(b[8:12])
	m.Change = nlenc.Uint32(b[12:16])

	if l > 16 {
		m.Attributes = LinkAttributes{}
		err := m.Attributes.UnmarshalBinary(b[16:])
		if err != nil {
			return err
		}
	}

	return nil
}

// rtMessage is an empty method to sattisfy the Message interface.
func (*LinkMessage) rtMessage() {}

// LinkService is used to retrieve rtnetlink family information.
type LinkService struct {
	c *Conn
}

// Constants used to request information from rtnetlink links.
const (
	rtmNewLink = 16
	rtmDelLink = 17
	rtmGetLink = 18
	rtmSetLink = 19
)

// New creates a new interface using the LinkMessage information.
func (l *LinkService) New(req *LinkMessage) error {
	flags := netlink.HeaderFlagsRequest
	_, err := l.c.Send(req, rtmSetLink, flags)
	if err != nil {
		return err
	}

	return nil
}

// Delete removes an interface by index.
func (l *LinkService) Delete(index uint32) error {
	req := &LinkMessage{
		Index: index,
	}

	flags := netlink.HeaderFlagsRequest
	_, err := l.c.Send(req, rtmDelLink, flags)
	if err != nil {
		return err
	}

	return nil
}

// Get retrieves interface information by index.
func (l *LinkService) Get(index uint32) (LinkMessage, error) {
	req := &LinkMessage{
		Index: index,
	}

	flags := netlink.HeaderFlagsRequest | netlink.HeaderFlagsDumpFiltered
	msg, err := l.c.Execute(req, rtmGetLink, flags)
	if err != nil {
		return LinkMessage{}, err
	}

	if len(msg) != 1 {
		return LinkMessage{}, fmt.Errorf("too many/little matches, expected 1")
	}

	link := (msg[0]).(*LinkMessage)
	return *link, nil
}

// Set sets interface attributes according to the LinkMessage information.
func (l *LinkService) Set(req *LinkMessage) error {
	flags := netlink.HeaderFlagsRequest
	_, err := l.c.Send(req, rtmSetLink, flags)
	if err != nil {
		return err
	}

	return nil
}

// List retrieves all interfaces.
func (l *LinkService) List() ([]LinkMessage, error) {
	req := &LinkMessage{}

	flags := netlink.HeaderFlagsRequest | netlink.HeaderFlagsDump
	msgs, err := l.c.Execute(req, rtmGetLink, flags)
	if err != nil {
		return nil, err
	}

	links := make([]LinkMessage, 0, len(msgs))
	for _, m := range msgs {
		link := (m).(*LinkMessage)
		links = append(links, *link)
	}

	return links, nil
}

// LinkAttributes contains all attributes for an interface.
type LinkAttributes struct {
	Address   net.HardwareAddr // Interface L2 address
	Broadcast net.HardwareAddr // L2 broadcast address
	Name      string           // Device name
	MTU       uint32           // MTU of the device
	Type      uint32           // Link type
	QueueDisc string           // Queueing discipline
	Stats     *LinkStats       // Interface Statistics
}

// Attribute IDs mapped to specific LinkAttribute fields.
const (
	iflaUnspec uint16 = iota
	iflaAddress
	iflaBroadcast
	iflaIfname
	iflaMTU
	iflaLink
	iflaQdisc
	iflaStats
)

// UnmarshalBinary unmarshals the contents of a byte slice into a LinkMessage.
func (a *LinkAttributes) UnmarshalBinary(b []byte) error {
	attrs, err := netlink.UnmarshalAttributes(b)
	if err != nil {
		return err
	}

	for _, attr := range attrs {
		switch attr.Type {
		case iflaUnspec:
			//unused attribute
		case iflaAddress:
			if len(attr.Data) != 6 {
				return errInvalidLinkMessageAttr
			}
			a.Address = attr.Data
		case iflaBroadcast:
			if len(attr.Data) != 6 {
				return errInvalidLinkMessageAttr
			}
			a.Broadcast = attr.Data
		case iflaIfname:
			a.Name = nlenc.String(attr.Data)
		case iflaMTU:
			if len(attr.Data) != 4 {
				return errInvalidLinkMessageAttr
			}
			a.MTU = nlenc.Uint32(attr.Data)
		case iflaLink:
			if len(attr.Data) != 4 {
				return errInvalidLinkMessageAttr
			}
			a.Type = nlenc.Uint32(attr.Data)
		case iflaQdisc:
			a.QueueDisc = nlenc.String(attr.Data)
		case iflaStats:
			a.Stats = &LinkStats{}
			err := a.Stats.UnmarshalBinary(attr.Data)
			if err != nil {
				return err
			}
		}
	}

	return nil
}

// MarshalBinary marshals a LinkAttributes into a byte slice.
func (a *LinkAttributes) MarshalBinary() ([]byte, error) {
	return netlink.MarshalAttributes([]netlink.Attribute{
		{
			Type: iflaUnspec,
			Data: nlenc.Uint16Bytes(0),
		},
		{
			Type: iflaAddress,
			Data: a.Address,
		},
		{
			Type: iflaBroadcast,
			Data: a.Broadcast,
		},
		{
			Type: iflaIfname,
			Data: nlenc.Bytes(a.Name),
		},
		{
			Type: iflaMTU,
			Data: nlenc.Uint32Bytes(a.MTU),
		},
		{
			Type: iflaLink,
			Data: nlenc.Uint32Bytes(a.Type),
		},
		{
			Type: iflaQdisc,
			Data: nlenc.Bytes(a.QueueDisc),
		},
		/*
			{
				Type: iflaStats,
				Data: nlenc.Bytes(name),
			},
		*/
	})
}

//LinkStats contains packet statistics
type LinkStats struct {
	RXPackets  uint32 // total packets received
	TXPackets  uint32 // total packets transmitted
	RXBytes    uint32 // total bytes received
	TXBytes    uint32 // total bytes transmitted
	RXErrors   uint32 // bad packets received
	TXErrors   uint32 // packet transmit problems
	RXDropped  uint32 // no space in linux buffers
	TXDropped  uint32 // no space available in linux
	Multicast  uint32 // multicast packets received
	Collisions uint32

	// detailed rx_errors:
	RXLengthErrors uint32
	RXOverErrors   uint32 // receiver ring buff overflow
	RXCRCErrors    uint32 // recved pkt with crc error
	RXFrameErrors  uint32 // recv'd frame alignment error
	RXFIFOErrors   uint32 // recv'r fifo overrun
	RXMissedErrors uint32 // receiver missed packet

	// detailed tx_errors
	TXAbortedErrors   uint32
	TXCarrierErrors   uint32
	TXFIFOErrors      uint32
	TXHeartbeatErrors uint32
	TXWindowErrors    uint32

	// for cslip etc
	RXCompressed uint32
	TXCompressed uint32

	RXNoHandler uint32 // dropped, no handler found
}

// UnmarshalBinary unmarshals the contents of a byte slice into a LinkMessage.
func (a *LinkStats) UnmarshalBinary(b []byte) error {
	if len(b) != 96 && len(b) != 104 {
		return fmt.Errorf("incorrect size, want: 96 or 104, got: %d", len(b))
	}

	a.RXPackets = nlenc.Uint32(b[0:4])
	a.TXPackets = nlenc.Uint32(b[4:8])
	a.RXBytes = nlenc.Uint32(b[8:12])
	a.TXBytes = nlenc.Uint32(b[12:16])
	a.RXErrors = nlenc.Uint32(b[16:20])
	a.TXErrors = nlenc.Uint32(b[20:24])
	a.RXDropped = nlenc.Uint32(b[24:28])
	a.TXDropped = nlenc.Uint32(b[28:32])
	a.Multicast = nlenc.Uint32(b[32:36])
	a.Collisions = nlenc.Uint32(b[36:40])

	a.RXLengthErrors = nlenc.Uint32(b[40:44])
	a.RXOverErrors = nlenc.Uint32(b[44:48])
	a.RXCRCErrors = nlenc.Uint32(b[48:52])
	a.RXFrameErrors = nlenc.Uint32(b[52:56])
	a.RXFIFOErrors = nlenc.Uint32(b[56:60])
	a.RXMissedErrors = nlenc.Uint32(b[60:64])

	a.TXAbortedErrors = nlenc.Uint32(b[68:72])
	a.TXCarrierErrors = nlenc.Uint32(b[76:80])
	a.TXFIFOErrors = nlenc.Uint32(b[80:84])
	a.TXHeartbeatErrors = nlenc.Uint32(b[84:88])
	a.TXWindowErrors = nlenc.Uint32(b[88:92])

	if len(b) == 96 {
		a.RXNoHandler = nlenc.Uint32(b[92:96])
	}

	if len(b) == 104 {
		a.RXCompressed = nlenc.Uint32(b[92:96])
		a.TXCompressed = nlenc.Uint32(b[96:100])
		a.RXNoHandler = nlenc.Uint32(b[100:104])
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright © 2016 Nick Klauer <klauer@gmail.com>
//
// 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 trackello

import (
	"fmt"
	"sort"

	"github.com/VojtechVitek/go-trello"
	"github.com/klauern/trackello/rest"
	"github.com/pkg/errors"
)

// List is both the Trello List + other stats on the actions in it.
type List struct {
	name  string
	cards map[cardID]Card
	stats *statistics
	list  *trello.List
}

// Print will print out a list and all of the cards to the command-line.
func (l *List) Print() {
	if len(l.name) > 0 {
		fmt.Printf("%s\n", l.name)
		cardSlice := make([]Card, 0, len(l.cards))
		for _, card := range l.cards {
			cardSlice = append(cardSlice, card)
		}
		sort.Sort(ByStatisticsCountRev(cardSlice))
		for _, card := range cardSlice {
			fmt.Printf("  * %s\n", card.String())
		}
	}
}

// NewList constructs a new *List based off of a go-trello *List.
func NewList(l *trello.List) *List {
	return &List{
		name:  l.Name,
		cards: make(map[cardID]Card),
		stats: &statistics{},
		list:  l,
	}
}

// MapActions will map all of the Actions that occurred on a List.
func (l *List) MapActions() (bool, error) {
	args := rest.CreateArgsForBoardActions()
	actions, err := l.list.Actions(args...)
	if err != nil {
		fmt.Println("error in MapActions")
		return false, errors.Wrapf(err, "Error getting List \"%s\" Actions: ", l.name)
	}
	for _, action := range actions {
		card, ok := l.cards[cardID(action.Data.Card.Id)]
		if !ok {
			fmt.Printf("Card info is %+v\n", card)
			switch action.Type {
			case "updateList", "createList":
				continue
			}

			fmt.Printf("Not Ok for id %s, action information is %+v\n", action.Data.Card.Id, action)
			if len(action.Data.Card.Id) == 0 {
				continue
			}
		}
		card, ok = l.cards[cardID(action.Data.Card.Id)]
		// maybe an action doesn't exist on this card anymore, but it did at some time?  Need to RE-investigate what
		// card this action belongs to in order to determine whether we're dealing with missing cards in the map
		if !ok {
			panic("Still not ok")
		}
		card.AddCalculation(action)
		l.cards[cardID(action.Data.Card.Id)] = card
	}
	return true, nil
}

// MapCards maps all of the cards for a list into the List.cards map[string]Card based on the cardID.
func (l *List) MapCards() error {
	cards, err := l.list.Cards()
	if err != nil {
		fmt.Printf("Error MapCards %s\n", err)
		return err
	}
	for _, card := range cards {
		l.cards[cardID(card.Id)] = NewCard(&card)
	}
	return nil
}

func makeList(listMap map[string]List) []List {
	list := make([]List, len(listMap))
	for _, v := range listMap {
		list = append(list, v)
	}
	return list
}

// ByListName is a super type of a List[], with functions that implement the sort interface.
type ByListName []List

// Len returns the length of the ByListName slice.
func (l ByListName) Len() int {
	return len(l)
}

// Swap will swap the positions of two trackello.List items in the ByListName slice.
func (l ByListName) Swap(i, j int) {
	l[i], l[j] = l[j], l[i]
}

// Less determines which of the two trackello.List items is before other based on the List Name.
func (l ByListName) Less(i, j int) bool {
	return l[i].name < l[j].name
}
<commit_msg>fix sorting to be case-insensitive on list name<commit_after>// Copyright © 2016 Nick Klauer <klauer@gmail.com>
//
// 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 trackello

import (
	"fmt"
	"sort"

	"github.com/VojtechVitek/go-trello"
	"github.com/klauern/trackello/rest"
	"github.com/pkg/errors"
	"strings"
)

// List is both the Trello List + other stats on the actions in it.
type List struct {
	name  string
	cards map[cardID]Card
	stats *statistics
	list  *trello.List
}

// Print will print out a list and all of the cards to the command-line.
func (l *List) Print() {
	if len(l.name) > 0 {
		fmt.Printf("%s\n", l.name)
		cardSlice := make([]Card, 0, len(l.cards))
		for _, card := range l.cards {
			cardSlice = append(cardSlice, card)
		}
		sort.Sort(ByStatisticsCountRev(cardSlice))
		for _, card := range cardSlice {
			fmt.Printf("  * %s\n", card.String())
		}
	}
}

// NewList constructs a new *List based off of a go-trello *List.
func NewList(l *trello.List) *List {
	return &List{
		name:  l.Name,
		cards: make(map[cardID]Card),
		stats: &statistics{},
		list:  l,
	}
}

// MapActions will map all of the Actions that occurred on a List.
func (l *List) MapActions() (bool, error) {
	args := rest.CreateArgsForBoardActions()
	actions, err := l.list.Actions(args...)
	if err != nil {
		fmt.Println("error in MapActions")
		return false, errors.Wrapf(err, "Error getting List \"%s\" Actions: ", l.name)
	}
	for _, action := range actions {
		card, ok := l.cards[cardID(action.Data.Card.Id)]
		if !ok {
			fmt.Printf("Card info is %+v\n", card)
			switch action.Type {
			case "updateList", "createList":
				continue
			}

			fmt.Printf("Not Ok for id %s, action information is %+v\n", action.Data.Card.Id, action)
			if len(action.Data.Card.Id) == 0 {
				continue
			}
		}
		card, ok = l.cards[cardID(action.Data.Card.Id)]
		// maybe an action doesn't exist on this card anymore, but it did at some time?  Need to RE-investigate what
		// card this action belongs to in order to determine whether we're dealing with missing cards in the map
		if !ok {
			panic("Still not ok")
		}
		card.AddCalculation(action)
		l.cards[cardID(action.Data.Card.Id)] = card
	}
	return true, nil
}

// MapCards maps all of the cards for a list into the List.cards map[string]Card based on the cardID.
func (l *List) MapCards() error {
	cards, err := l.list.Cards()
	if err != nil {
		fmt.Printf("Error MapCards %s\n", err)
		return err
	}
	for _, card := range cards {
		l.cards[cardID(card.Id)] = NewCard(&card)
	}
	return nil
}

func makeList(listMap map[string]List) []List {
	list := make([]List, len(listMap))
	for _, v := range listMap {
		list = append(list, v)
	}
	return list
}

// ByListName is a super type of a List[], with functions that implement the sort interface.
type ByListName []List

// Len returns the length of the ByListName slice.
func (l ByListName) Len() int {
	return len(l)
}

// Swap will swap the positions of two trackello.List items in the ByListName slice.
func (l ByListName) Swap(i, j int) {
	l[i], l[j] = l[j], l[i]
}

// Less determines which of the two trackello.List items is before other based on the List Name.
func (l ByListName) Less(i, j int) bool {
	return strings.Compare(strings.ToLower(l[i].name), strings.ToLower(l[j].name)) == -1
}
<|endoftext|>


<commit_before>package tview

import (
	"fmt"

	"github.com/gdamore/tcell"
)

// listItem represents one item in a List.
type listItem struct {
	MainText      string // The main text of the list item.
	SecondaryText string // A secondary text to be shown underneath the main text.
	Shortcut      rune   // The key to select the list item directly, 0 if there is no shortcut.
	Selected      func() // The optional function which is called when the item is selected.
}

// List displays rows of items, each of which can be selected.
//
// See https://github.com/rivo/tview/wiki/List for an example.
type List struct {
	*Box

	// The items of the list.
	items []*listItem

	// The index of the currently selected item.
	currentItem int

	// Whether or not to show the secondary item texts.
	showSecondaryText bool

	// The item main text color.
	mainTextColor tcell.Color

	// The item secondary text color.
	secondaryTextColor tcell.Color

	// The item shortcut text color.
	shortcutColor tcell.Color

	// The text color for selected items.
	selectedTextColor tcell.Color

	// The background color for selected items.
	selectedBackgroundColor tcell.Color

	// An optional function which is called when the user has navigated to a list
	// item.
	changed func(index int, mainText, secondaryText string, shortcut rune)

	// An optional function which is called when a list item was selected. This
	// function will be called even if the list item defines its own callback.
	selected func(index int, mainText, secondaryText string, shortcut rune)

	// An optional function which is called when the user presses the Escape key.
	done func()
}

// NewList returns a new form.
func NewList() *List {
	return &List{
		Box:                     NewBox(),
		showSecondaryText:       true,
		mainTextColor:           Styles.PrimaryTextColor,
		secondaryTextColor:      Styles.TertiaryTextColor,
		shortcutColor:           Styles.SecondaryTextColor,
		selectedTextColor:       Styles.PrimitiveBackgroundColor,
		selectedBackgroundColor: Styles.PrimaryTextColor,
	}
}

// SetCurrentItem sets the currently selected item by its index. This triggers
// a "changed" event.
func (l *List) SetCurrentItem(index int) *List {
	l.currentItem = index
	if l.currentItem < len(l.items) && l.changed != nil {
		item := l.items[l.currentItem]
		l.changed(l.currentItem, item.MainText, item.SecondaryText, item.Shortcut)
	}
	return l
}

// GetCurrentItem returns the index of the currently selected list item.
func (l *List) GetCurrentItem() int {
	return l.currentItem
}

// SetMainTextColor sets the color of the items' main text.
func (l *List) SetMainTextColor(color tcell.Color) *List {
	l.mainTextColor = color
	return l
}

// SetSecondaryTextColor sets the color of the items' secondary text.
func (l *List) SetSecondaryTextColor(color tcell.Color) *List {
	l.secondaryTextColor = color
	return l
}

// SetShortcutColor sets the color of the items' shortcut.
func (l *List) SetShortcutColor(color tcell.Color) *List {
	l.shortcutColor = color
	return l
}

// SetSelectedTextColor sets the text color of selected items.
func (l *List) SetSelectedTextColor(color tcell.Color) *List {
	l.selectedTextColor = color
	return l
}

// SetSelectedBackgroundColor sets the background color of selected items.
func (l *List) SetSelectedBackgroundColor(color tcell.Color) *List {
	l.selectedBackgroundColor = color
	return l
}

// ShowSecondaryText determines whether or not to show secondary item texts.
func (l *List) ShowSecondaryText(show bool) *List {
	l.showSecondaryText = show
	return l
}

// SetChangedFunc sets the function which is called when the user navigates to
// a list item. The function receives the item's index in the list of items
// (starting with 0), its main text, secondary text, and its shortcut rune.
//
// This function is also called when the first item is added or when
// SetCurrentItem() is called.
func (l *List) SetChangedFunc(handler func(int, string, string, rune)) *List {
	l.changed = handler
	return l
}

// SetSelectedFunc sets the function which is called when the user selects a
// list item by pressing Enter on the current selection. The function receives
// the item's index in the list of items (starting with 0), its main text,
// secondary text, and its shortcut rune.
func (l *List) SetSelectedFunc(handler func(int, string, string, rune)) *List {
	l.selected = handler
	return l
}

// SetDoneFunc sets a function which is called when the user presses the Escape
// key.
func (l *List) SetDoneFunc(handler func()) *List {
	l.done = handler
	return l
}

// AddItem adds a new item to the list. An item has a main text which will be
// highlighted when selected. It also has a secondary text which is shown
// underneath the main text (if it is set to visible) but which may remain
// empty.
//
// The shortcut is a key binding. If the specified rune is entered, the item
// is selected immediately. Set to 0 for no binding.
//
// The "selected" callback will be invoked when the user selects the item. You
// may provide nil if no such item is needed or if all events are handled
// through the selected callback set with SetSelectedFunc().
func (l *List) AddItem(mainText, secondaryText string, shortcut rune, selected func()) *List {
	l.items = append(l.items, &listItem{
		MainText:      mainText,
		SecondaryText: secondaryText,
		Shortcut:      shortcut,
		Selected:      selected,
	})
	if len(l.items) == 1 && l.changed != nil {
		item := l.items[0]
		l.changed(0, item.MainText, item.SecondaryText, item.Shortcut)
	}
	return l
}

// GetItemCount returns the number of items in the list.
func (l *List) GetItemCount() int {
	return len(l.items)
}

// GetItemText returns an item's texts (main and secondary). Panics if the index
// is out of range.
func (l *List) GetItemText(index int) (main, secondary string) {
	return l.items[index].MainText, l.items[index].SecondaryText
}

// SetItemText sets an item's main and secondary text. Panics if the index is
// out of range.
func (l *List) SetItemText(index int, main, secondary string) *List {
	item := l.items[index]
	item.MainText = main
	item.SecondaryText = secondary
	return l
}

// Clear removes all items from the list.
func (l *List) Clear() *List {
	l.items = nil
	l.currentItem = 0
	return l
}

// Draw draws this primitive onto the screen.
func (l *List) Draw(screen tcell.Screen) {
	l.Box.Draw(screen)

	// Determine the dimensions.
	x, y, width, height := l.GetInnerRect()
	bottomLimit := y + height

	// Do we show any shortcuts?
	var showShortcuts bool
	for _, item := range l.items {
		if item.Shortcut != 0 {
			showShortcuts = true
			x += 4
			width -= 4
			break
		}
	}

	// We want to keep the current selection in view. What is our offset?
	var offset int
	if l.showSecondaryText {
		if l.currentItem >= height/2 {
			offset = l.currentItem + 1 - (height / 2)
		}
	} else {
		if l.currentItem >= height {
			offset = l.currentItem + 1 - height
		}
	}

	// Draw the list items.
	for index, item := range l.items {
		if index < offset {
			continue
		}

		if y >= bottomLimit {
			break
		}

		// Shortcuts.
		if showShortcuts && item.Shortcut != 0 {
			Print(screen, fmt.Sprintf("(%s)", string(item.Shortcut)), x-5, y, 4, AlignRight, l.shortcutColor)
		}

		// Main text.
		Print(screen, item.MainText, x, y, width, AlignLeft, l.mainTextColor)

		// Background color of selected text.
		if index == l.currentItem {
			textWidth := StringWidth(item.MainText)
			for bx := 0; bx < textWidth && bx < width; bx++ {
				m, c, style, _ := screen.GetContent(x+bx, y)
				fg, _, _ := style.Decompose()
				if fg == l.mainTextColor {
					fg = l.selectedTextColor
				}
				style = style.Background(l.selectedBackgroundColor).Foreground(fg)
				screen.SetContent(x+bx, y, m, c, style)
			}
		}

		y++

		if y >= bottomLimit {
			break
		}

		// Secondary text.
		if l.showSecondaryText {
			Print(screen, item.SecondaryText, x, y, width, AlignLeft, l.secondaryTextColor)
			y++
		}
	}
}

// InputHandler returns the handler for this primitive.
func (l *List) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) {
	return l.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) {
		previousItem := l.currentItem

		switch key := event.Key(); key {
		case tcell.KeyTab, tcell.KeyDown, tcell.KeyRight:
			l.currentItem++
		case tcell.KeyBacktab, tcell.KeyUp, tcell.KeyLeft:
			l.currentItem--
		case tcell.KeyHome:
			l.currentItem = 0
		case tcell.KeyEnd:
			l.currentItem = len(l.items) - 1
		case tcell.KeyPgDn:
			l.currentItem += 5
		case tcell.KeyPgUp:
			l.currentItem -= 5
		case tcell.KeyEnter:
			item := l.items[l.currentItem]
			if item.Selected != nil {
				item.Selected()
			}
			if l.selected != nil {
				l.selected(l.currentItem, item.MainText, item.SecondaryText, item.Shortcut)
			}
		case tcell.KeyEscape:
			if l.done != nil {
				l.done()
			}
		case tcell.KeyRune:
			ch := event.Rune()
			if ch != ' ' {
				// It's not a space bar. Is it a shortcut?
				var found bool
				for index, item := range l.items {
					if item.Shortcut == ch {
						// We have a shortcut.
						found = true
						l.currentItem = index
						break
					}
				}
				if !found {
					break
				}
			}
			item := l.items[l.currentItem]
			if item.Selected != nil {
				item.Selected()
			}
			if l.selected != nil {
				l.selected(l.currentItem, item.MainText, item.SecondaryText, item.Shortcut)
			}
		}

		if l.currentItem < 0 {
			l.currentItem = len(l.items) - 1
		} else if l.currentItem >= len(l.items) {
			l.currentItem = 0
		}

		if l.currentItem != previousItem && l.currentItem < len(l.items) && l.changed != nil {
			item := l.items[l.currentItem]
			l.changed(l.currentItem, item.MainText, item.SecondaryText, item.Shortcut)
		}
	})
}
<commit_msg>Fix panic with empty list<commit_after>package tview

import (
	"fmt"

	"github.com/gdamore/tcell"
)

// listItem represents one item in a List.
type listItem struct {
	MainText      string // The main text of the list item.
	SecondaryText string // A secondary text to be shown underneath the main text.
	Shortcut      rune   // The key to select the list item directly, 0 if there is no shortcut.
	Selected      func() // The optional function which is called when the item is selected.
}

// List displays rows of items, each of which can be selected.
//
// See https://github.com/rivo/tview/wiki/List for an example.
type List struct {
	*Box

	// The items of the list.
	items []*listItem

	// The index of the currently selected item.
	currentItem int

	// Whether or not to show the secondary item texts.
	showSecondaryText bool

	// The item main text color.
	mainTextColor tcell.Color

	// The item secondary text color.
	secondaryTextColor tcell.Color

	// The item shortcut text color.
	shortcutColor tcell.Color

	// The text color for selected items.
	selectedTextColor tcell.Color

	// The background color for selected items.
	selectedBackgroundColor tcell.Color

	// An optional function which is called when the user has navigated to a list
	// item.
	changed func(index int, mainText, secondaryText string, shortcut rune)

	// An optional function which is called when a list item was selected. This
	// function will be called even if the list item defines its own callback.
	selected func(index int, mainText, secondaryText string, shortcut rune)

	// An optional function which is called when the user presses the Escape key.
	done func()
}

// NewList returns a new form.
func NewList() *List {
	return &List{
		Box:                     NewBox(),
		showSecondaryText:       true,
		mainTextColor:           Styles.PrimaryTextColor,
		secondaryTextColor:      Styles.TertiaryTextColor,
		shortcutColor:           Styles.SecondaryTextColor,
		selectedTextColor:       Styles.PrimitiveBackgroundColor,
		selectedBackgroundColor: Styles.PrimaryTextColor,
	}
}

// SetCurrentItem sets the currently selected item by its index. This triggers
// a "changed" event.
func (l *List) SetCurrentItem(index int) *List {
	l.currentItem = index
	if l.currentItem < len(l.items) && l.changed != nil {
		item := l.items[l.currentItem]
		l.changed(l.currentItem, item.MainText, item.SecondaryText, item.Shortcut)
	}
	return l
}

// GetCurrentItem returns the index of the currently selected list item.
func (l *List) GetCurrentItem() int {
	return l.currentItem
}

// SetMainTextColor sets the color of the items' main text.
func (l *List) SetMainTextColor(color tcell.Color) *List {
	l.mainTextColor = color
	return l
}

// SetSecondaryTextColor sets the color of the items' secondary text.
func (l *List) SetSecondaryTextColor(color tcell.Color) *List {
	l.secondaryTextColor = color
	return l
}

// SetShortcutColor sets the color of the items' shortcut.
func (l *List) SetShortcutColor(color tcell.Color) *List {
	l.shortcutColor = color
	return l
}

// SetSelectedTextColor sets the text color of selected items.
func (l *List) SetSelectedTextColor(color tcell.Color) *List {
	l.selectedTextColor = color
	return l
}

// SetSelectedBackgroundColor sets the background color of selected items.
func (l *List) SetSelectedBackgroundColor(color tcell.Color) *List {
	l.selectedBackgroundColor = color
	return l
}

// ShowSecondaryText determines whether or not to show secondary item texts.
func (l *List) ShowSecondaryText(show bool) *List {
	l.showSecondaryText = show
	return l
}

// SetChangedFunc sets the function which is called when the user navigates to
// a list item. The function receives the item's index in the list of items
// (starting with 0), its main text, secondary text, and its shortcut rune.
//
// This function is also called when the first item is added or when
// SetCurrentItem() is called.
func (l *List) SetChangedFunc(handler func(int, string, string, rune)) *List {
	l.changed = handler
	return l
}

// SetSelectedFunc sets the function which is called when the user selects a
// list item by pressing Enter on the current selection. The function receives
// the item's index in the list of items (starting with 0), its main text,
// secondary text, and its shortcut rune.
func (l *List) SetSelectedFunc(handler func(int, string, string, rune)) *List {
	l.selected = handler
	return l
}

// SetDoneFunc sets a function which is called when the user presses the Escape
// key.
func (l *List) SetDoneFunc(handler func()) *List {
	l.done = handler
	return l
}

// AddItem adds a new item to the list. An item has a main text which will be
// highlighted when selected. It also has a secondary text which is shown
// underneath the main text (if it is set to visible) but which may remain
// empty.
//
// The shortcut is a key binding. If the specified rune is entered, the item
// is selected immediately. Set to 0 for no binding.
//
// The "selected" callback will be invoked when the user selects the item. You
// may provide nil if no such item is needed or if all events are handled
// through the selected callback set with SetSelectedFunc().
func (l *List) AddItem(mainText, secondaryText string, shortcut rune, selected func()) *List {
	l.items = append(l.items, &listItem{
		MainText:      mainText,
		SecondaryText: secondaryText,
		Shortcut:      shortcut,
		Selected:      selected,
	})
	if len(l.items) == 1 && l.changed != nil {
		item := l.items[0]
		l.changed(0, item.MainText, item.SecondaryText, item.Shortcut)
	}
	return l
}

// GetItemCount returns the number of items in the list.
func (l *List) GetItemCount() int {
	return len(l.items)
}

// GetItemText returns an item's texts (main and secondary). Panics if the index
// is out of range.
func (l *List) GetItemText(index int) (main, secondary string) {
	return l.items[index].MainText, l.items[index].SecondaryText
}

// SetItemText sets an item's main and secondary text. Panics if the index is
// out of range.
func (l *List) SetItemText(index int, main, secondary string) *List {
	item := l.items[index]
	item.MainText = main
	item.SecondaryText = secondary
	return l
}

// Clear removes all items from the list.
func (l *List) Clear() *List {
	l.items = nil
	l.currentItem = 0
	return l
}

// Draw draws this primitive onto the screen.
func (l *List) Draw(screen tcell.Screen) {
	l.Box.Draw(screen)

	// Determine the dimensions.
	x, y, width, height := l.GetInnerRect()
	bottomLimit := y + height

	// Do we show any shortcuts?
	var showShortcuts bool
	for _, item := range l.items {
		if item.Shortcut != 0 {
			showShortcuts = true
			x += 4
			width -= 4
			break
		}
	}

	// We want to keep the current selection in view. What is our offset?
	var offset int
	if l.showSecondaryText {
		if l.currentItem >= height/2 {
			offset = l.currentItem + 1 - (height / 2)
		}
	} else {
		if l.currentItem >= height {
			offset = l.currentItem + 1 - height
		}
	}

	// Draw the list items.
	for index, item := range l.items {
		if index < offset {
			continue
		}

		if y >= bottomLimit {
			break
		}

		// Shortcuts.
		if showShortcuts && item.Shortcut != 0 {
			Print(screen, fmt.Sprintf("(%s)", string(item.Shortcut)), x-5, y, 4, AlignRight, l.shortcutColor)
		}

		// Main text.
		Print(screen, item.MainText, x, y, width, AlignLeft, l.mainTextColor)

		// Background color of selected text.
		if index == l.currentItem {
			textWidth := StringWidth(item.MainText)
			for bx := 0; bx < textWidth && bx < width; bx++ {
				m, c, style, _ := screen.GetContent(x+bx, y)
				fg, _, _ := style.Decompose()
				if fg == l.mainTextColor {
					fg = l.selectedTextColor
				}
				style = style.Background(l.selectedBackgroundColor).Foreground(fg)
				screen.SetContent(x+bx, y, m, c, style)
			}
		}

		y++

		if y >= bottomLimit {
			break
		}

		// Secondary text.
		if l.showSecondaryText {
			Print(screen, item.SecondaryText, x, y, width, AlignLeft, l.secondaryTextColor)
			y++
		}
	}
}

// InputHandler returns the handler for this primitive.
func (l *List) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) {
	return l.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) {
		previousItem := l.currentItem

		switch key := event.Key(); key {
		case tcell.KeyTab, tcell.KeyDown, tcell.KeyRight:
			l.currentItem++
		case tcell.KeyBacktab, tcell.KeyUp, tcell.KeyLeft:
			l.currentItem--
		case tcell.KeyHome:
			l.currentItem = 0
		case tcell.KeyEnd:
			l.currentItem = len(l.items) - 1
		case tcell.KeyPgDn:
			l.currentItem += 5
		case tcell.KeyPgUp:
			l.currentItem -= 5
		case tcell.KeyEnter:
			if l.currentItem >= 0 && l.currentItem < len(l.items) {
				item := l.items[l.currentItem]
				if item.Selected != nil {
					item.Selected()
				}
				if l.selected != nil {
					l.selected(l.currentItem, item.MainText, item.SecondaryText, item.Shortcut)
				}
			}
		case tcell.KeyEscape:
			if l.done != nil {
				l.done()
			}
		case tcell.KeyRune:
			ch := event.Rune()
			if ch != ' ' {
				// It's not a space bar. Is it a shortcut?
				var found bool
				for index, item := range l.items {
					if item.Shortcut == ch {
						// We have a shortcut.
						found = true
						l.currentItem = index
						break
					}
				}
				if !found {
					break
				}
			}
			item := l.items[l.currentItem]
			if item.Selected != nil {
				item.Selected()
			}
			if l.selected != nil {
				l.selected(l.currentItem, item.MainText, item.SecondaryText, item.Shortcut)
			}
		}

		if l.currentItem < 0 {
			l.currentItem = len(l.items) - 1
		} else if l.currentItem >= len(l.items) {
			l.currentItem = 0
		}

		if l.currentItem != previousItem && l.currentItem < len(l.items) && l.changed != nil {
			item := l.items[l.currentItem]
			l.changed(l.currentItem, item.MainText, item.SecondaryText, item.Shortcut)
		}
	})
}
<|endoftext|>


<commit_before>package ws

import (
	"encoding/binary"
)

// Cipher applies XOR cipher to the payload using mask.
// Offset is used to cipher chunked data (e.g. in io.Reader implementations).
//
// To convert masked data into unmasked data, or vice versa, the following
// algorithm is applied.  The same algorithm applies regardless of the
// direction of the translation, e.g., the same steps are applied to
// mask the data as to unmask the data.
func Cipher(payload []byte, mask [4]byte, offset int) {
	n := len(payload)
	if n < 8 {
		for i := 0; i < n; i++ {
			payload[i] ^= mask[(offset+i)%4]
		}
		return
	}

	// Calculate position in mask due to previously processed bytes number.
	mpos := offset % 4
	// Count number of bytes will processed one by one from the beginning of payload.
	ln := remain[mpos]
	// Count number of bytes will processed one by one from the end of payload.
	// This is done to process payload by 8 bytes in each iteration of main loop.
	rn := (n - ln) % 8

	for i := 0; i < ln; i++ {
		payload[i] ^= mask[(mpos+i)%4]
	}
	for i := n - rn; i < n; i++ {
		payload[i] ^= mask[(mpos+i)%4]
	}

	// NOTE: we use here binary.LittleEndian regardless of what is real
	// endianess on machine is. To do so, we have to use binary.LittleEndian in
	// the masking loop below as well.
	var (
		m  = binary.LittleEndian.Uint32(mask[:])
		m2 = uint64(m)<<32 | uint64(m)
	)
	// Skip already processed right part.
	// Get number of uint64 parts remaining to process.
	n = (n - ln - rn) >> 3
	for i := 0; i < n; i++ {
		var (
			j     = ln + (i << 3)
			chunk = payload[j : j+8]
		)
		p := binary.LittleEndian.Uint64(chunk)
		p = p ^ m2
		binary.LittleEndian.PutUint64(chunk, p)
	}
}

// remain maps position in masking key [0,4) to number
// of bytes that need to be processed manually inside Cipher().
var remain = [4]int{0, 3, 2, 1}
<commit_msg>spell fix<commit_after>package ws

import (
	"encoding/binary"
)

// Cipher applies XOR cipher to the payload using mask.
// Offset is used to cipher chunked data (e.g. in io.Reader implementations).
//
// To convert masked data into unmasked data, or vice versa, the following
// algorithm is applied.  The same algorithm applies regardless of the
// direction of the translation, e.g., the same steps are applied to
// mask the data as to unmask the data.
func Cipher(payload []byte, mask [4]byte, offset int) {
	n := len(payload)
	if n < 8 {
		for i := 0; i < n; i++ {
			payload[i] ^= mask[(offset+i)%4]
		}
		return
	}

	// Calculate position in mask due to previously processed bytes number.
	mpos := offset % 4
	// Count number of bytes will processed one by one from the beginning of payload.
	ln := remain[mpos]
	// Count number of bytes will processed one by one from the end of payload.
	// This is done to process payload by 8 bytes in each iteration of main loop.
	rn := (n - ln) % 8

	for i := 0; i < ln; i++ {
		payload[i] ^= mask[(mpos+i)%4]
	}
	for i := n - rn; i < n; i++ {
		payload[i] ^= mask[(mpos+i)%4]
	}

	// NOTE: we use here binary.LittleEndian regardless of what is real
	// endianness on machine is. To do so, we have to use binary.LittleEndian in
	// the masking loop below as well.
	var (
		m  = binary.LittleEndian.Uint32(mask[:])
		m2 = uint64(m)<<32 | uint64(m)
	)
	// Skip already processed right part.
	// Get number of uint64 parts remaining to process.
	n = (n - ln - rn) >> 3
	for i := 0; i < n; i++ {
		var (
			j     = ln + (i << 3)
			chunk = payload[j : j+8]
		)
		p := binary.LittleEndian.Uint64(chunk)
		p = p ^ m2
		binary.LittleEndian.PutUint64(chunk, p)
	}
}

// remain maps position in masking key [0,4) to number
// of bytes that need to be processed manually inside Cipher().
var remain = [4]int{0, 3, 2, 1}
<|endoftext|>


<commit_before>package hdfs

import (
	"io"
	"io/ioutil"
	"os"
	"os/user"

	hdfs "github.com/colinmarc/hdfs/protocol/hadoop_hdfs"
	"github.com/colinmarc/hdfs/rpc"
)

// A Client represents a connection to an HDFS cluster
type Client struct {
	namenode *rpc.NamenodeConnection
	defaults *hdfs.FsServerDefaultsProto
}

// ClientOptions represents the configurable options for a client.
type ClientOptions struct {
	Addresses []string
	Namenode  *rpc.NamenodeConnection
	User      string
}

// Username returns the value of HADOOP_USER_NAME in the environment, or
// the current system user if it is not set.
func Username() (string, error) {
	username := os.Getenv("HADOOP_USER_NAME")
	if username != "" {
		return username, nil
	}
	currentUser, err := user.Current()
	if err != nil {
		return "", err
	}
	return currentUser.Username, nil
}

// NewClient returns a connected Client for the given options, or an error if
// the client could not be created.
func NewClient(options ClientOptions) (*Client, error) {
	var err error

	if options.User == "" {
		options.User, err = Username()
		if err != nil {
			return nil, err
		}
	}

	if options.Addresses == nil || len(options.Addresses) == 0 {
		options.Addresses, err = getNameNodeFromConf()
		if err != nil {
			return nil, err
		}
	}

	if options.Namenode == nil {
		options.Namenode, err = rpc.NewNamenodeConnectionWithOptions(
			rpc.NamenodeConnectionOptions{
				Addresses: options.Addresses,
				User:      options.User,
			},
		)
		if err != nil {
			return nil, err
		}
	}

	return &Client{namenode: options.Namenode}, nil
}

// New returns a connected Client, or an error if it can't connect. The user
// will be the user the code is running under. If address is an empty string
// it will try and get the namenode address from the hadoop configuration
// files.
func New(address string) (*Client, error) {
	options := ClientOptions{}

	if address != "" {
		options.Addresses = []string{address}
	}

	return NewClient(options)
}

// getNameNodeFromConf returns namenodes from the system Hadoop configuration.
func getNameNodeFromConf() ([]string, error) {
	hadoopConf := LoadHadoopConf("")

	namenodes, nnErr := hadoopConf.Namenodes()
	if nnErr != nil {
		return nil, nnErr
	}
	return namenodes, nil
}

// NewForUser returns a connected Client with the user specified, or an error if
// it can't connect.
func NewForUser(address string, user string) (*Client, error) {
	return NewClient(ClientOptions{
		Addresses: []string{address},
		User:      user,
	})
}

// NewForConnection returns Client with the specified, underlying rpc.NamenodeConnection.
// You can use rpc.WrapNamenodeConnection to wrap your own net.Conn.
func NewForConnection(namenode *rpc.NamenodeConnection) *Client {
	client, _ := NewClient(ClientOptions{Namenode: namenode})
	return client
}

// ReadFile reads the file named by filename and returns the contents.
func (c *Client) ReadFile(filename string) ([]byte, error) {
	f, err := c.Open(filename)
	if err != nil {
		return nil, err
	}

	defer f.Close()
	return ioutil.ReadAll(f)
}

// CopyToLocal copies the HDFS file specified by src to the local file at dst.
// If dst already exists, it will be overwritten.
func (c *Client) CopyToLocal(src string, dst string) error {
	remote, err := c.Open(src)
	if err != nil {
		return err
	}
	defer remote.Close()

	local, err := os.Create(dst)
	if err != nil {
		return err
	}
	defer local.Close()

	_, err = io.Copy(local, remote)
	return err
}

// CopyToRemote copies the local file specified by src to the HDFS file at dst.
func (c *Client) CopyToRemote(src string, dst string) error {
	local, err := os.Open(src)
	if err != nil {
		return err
	}
	defer local.Close()

	remote, err := c.Create(dst)
	if err != nil {
		return err
	}
	defer remote.Close()

	_, err = io.Copy(remote, local)
	return err
}

func (c *Client) fetchDefaults() (*hdfs.FsServerDefaultsProto, error) {
	if c.defaults != nil {
		return c.defaults, nil
	}

	req := &hdfs.GetServerDefaultsRequestProto{}
	resp := &hdfs.GetServerDefaultsResponseProto{}

	err := c.namenode.Execute("getServerDefaults", req, resp)
	if err != nil {
		return nil, err
	}

	c.defaults = resp.GetServerDefaults()
	return c.defaults, nil
}

// Close terminates all underlying socket connections to remote server.
func (c *Client) Close() error {
	return c.namenode.Close()
}
<commit_msg>Deprecate NewForUser and NewForConnection<commit_after>package hdfs

import (
	"io"
	"io/ioutil"
	"os"
	"os/user"

	hdfs "github.com/colinmarc/hdfs/protocol/hadoop_hdfs"
	"github.com/colinmarc/hdfs/rpc"
)

// A Client represents a connection to an HDFS cluster
type Client struct {
	namenode *rpc.NamenodeConnection
	defaults *hdfs.FsServerDefaultsProto
}

// ClientOptions represents the configurable options for a client.
type ClientOptions struct {
	Addresses []string
	Namenode  *rpc.NamenodeConnection
	User      string
}

// Username returns the value of HADOOP_USER_NAME in the environment, or
// the current system user if it is not set.
func Username() (string, error) {
	username := os.Getenv("HADOOP_USER_NAME")
	if username != "" {
		return username, nil
	}
	currentUser, err := user.Current()
	if err != nil {
		return "", err
	}
	return currentUser.Username, nil
}

// NewClient returns a connected Client for the given options, or an error if
// the client could not be created.
func NewClient(options ClientOptions) (*Client, error) {
	var err error

	if options.User == "" {
		options.User, err = Username()
		if err != nil {
			return nil, err
		}
	}

	if options.Addresses == nil || len(options.Addresses) == 0 {
		options.Addresses, err = getNameNodeFromConf()
		if err != nil {
			return nil, err
		}
	}

	if options.Namenode == nil {
		options.Namenode, err = rpc.NewNamenodeConnectionWithOptions(
			rpc.NamenodeConnectionOptions{
				Addresses: options.Addresses,
				User:      options.User,
			},
		)
		if err != nil {
			return nil, err
		}
	}

	return &Client{namenode: options.Namenode}, nil
}

// New returns a connected Client, or an error if it can't connect. The user
// will be the user the code is running under. If address is an empty string
// it will try and get the namenode address from the hadoop configuration
// files.
func New(address string) (*Client, error) {
	options := ClientOptions{}

	if address != "" {
		options.Addresses = []string{address}
	}

	return NewClient(options)
}

// getNameNodeFromConf returns namenodes from the system Hadoop configuration.
func getNameNodeFromConf() ([]string, error) {
	hadoopConf := LoadHadoopConf("")

	namenodes, nnErr := hadoopConf.Namenodes()
	if nnErr != nil {
		return nil, nnErr
	}
	return namenodes, nil
}

// NewForUser returns a connected Client with the user specified, or an error if
// it can't connect.
//
// Deprecated: Use NewClient with ClientOptions instead.
func NewForUser(address string, user string) (*Client, error) {
	return NewClient(ClientOptions{
		Addresses: []string{address},
		User:      user,
	})
}

// NewForConnection returns Client with the specified, underlying rpc.NamenodeConnection.
// You can use rpc.WrapNamenodeConnection to wrap your own net.Conn.
//
// Deprecated: Use NewClient with ClientOptions instead.
func NewForConnection(namenode *rpc.NamenodeConnection) *Client {
	client, _ := NewClient(ClientOptions{Namenode: namenode})
	return client
}

// ReadFile reads the file named by filename and returns the contents.
func (c *Client) ReadFile(filename string) ([]byte, error) {
	f, err := c.Open(filename)
	if err != nil {
		return nil, err
	}

	defer f.Close()
	return ioutil.ReadAll(f)
}

// CopyToLocal copies the HDFS file specified by src to the local file at dst.
// If dst already exists, it will be overwritten.
func (c *Client) CopyToLocal(src string, dst string) error {
	remote, err := c.Open(src)
	if err != nil {
		return err
	}
	defer remote.Close()

	local, err := os.Create(dst)
	if err != nil {
		return err
	}
	defer local.Close()

	_, err = io.Copy(local, remote)
	return err
}

// CopyToRemote copies the local file specified by src to the HDFS file at dst.
func (c *Client) CopyToRemote(src string, dst string) error {
	local, err := os.Open(src)
	if err != nil {
		return err
	}
	defer local.Close()

	remote, err := c.Create(dst)
	if err != nil {
		return err
	}
	defer remote.Close()

	_, err = io.Copy(remote, local)
	return err
}

func (c *Client) fetchDefaults() (*hdfs.FsServerDefaultsProto, error) {
	if c.defaults != nil {
		return c.defaults, nil
	}

	req := &hdfs.GetServerDefaultsRequestProto{}
	resp := &hdfs.GetServerDefaultsResponseProto{}

	err := c.namenode.Execute("getServerDefaults", req, resp)
	if err != nil {
		return nil, err
	}

	c.defaults = resp.GetServerDefaults()
	return c.defaults, nil
}

// Close terminates all underlying socket connections to remote server.
func (c *Client) Close() error {
	return c.namenode.Close()
}
<|endoftext|>


<commit_before>package sirius

import (
	"errors"
	"strings"
	"time"
)

type Client struct {
	Ready   chan bool
	user    *User
	conn    Connection
	loader  ExtensionLoader
	runner  ExtensionRunner
	timeout time.Duration
	done    chan bool
}

type ClientConfig struct {
	user    *User
	loader  ExtensionLoader
	runner  ExtensionRunner
	timeout time.Duration
}

func NewClient(cfg ClientConfig) *Client {
	cl := &Client{
		conn:    NewRTMConnection(cfg.user.Token),
		user:    cfg.user,
		loader:  cfg.loader,
		runner:  cfg.runner,
		timeout: cfg.timeout,
		Ready:   make(chan bool, 1),
		done:    make(chan bool),
	}
	if cl.runner == nil {
		cl.runner = NewAsyncRunner()
	}
	if cl.timeout == 0 {
		cl.timeout = time.Second * 2
	}
	return cl
}

func (c *Client) Start() {
	go c.conn.Listen()

	err := c.authenticate()
	if err != nil {
		panic(err)
	}

	c.Ready <- true

	for {
		select {
		// Make sure we always check for termination signal first
		case <-c.done:
			c.conn.Close()
			return
		case <-c.conn.Dead():
			c.done <- true
			return
		}

		select {
		case msg := <-c.conn.Messages():
			c.handle(&msg)
		}
	}
}

func (c *Client) Stop() {
	c.done <- true
}

func (c *Client) authenticate() error {
	auth := c.conn.Auth()

	for {
		select {
		case id := <-auth:
			c.user.ID = id
			return nil
		case <-time.After(time.Second * 3):
			return errors.New("Client authentication timed out (<-c.conn.Auth())")
		}
	}
}

func (c *Client) handle(msg *Message) {
	if !msg.sentBy(c.user) {
		return
	}

	if msg.escaped() {
		edit := msg.EditText().Set(trimEscape(msg.Text))
		msg.perform(edit)

		c.conn.Update(msg)
		return
	}

	c.run(msg)
}

func (c *Client) run(m *Message) {
	exe := c.loadExecutions(m)
	act := c.runExecutions(exe)

	if performActions(act, m) {
		c.conn.Update(m)
	}
}

func (c *Client) runExecutions(exe []Execution) []MessageAction {
	var act []MessageAction
	res := make(chan ExecutionResult, len(c.user.Configurations))

	c.runner.Run(exe, res, c.timeout)

	for r := range res {
		if r.Err != nil {
			panic(r.Err)
		}

		if _, ok := r.Action.(*EmptyAction); ok {
			continue
		}

		act = append(act, r.Action)
	}

	return act
}

func (c *Client) loadExecutions(m *Message) []Execution {
	var exe []Execution
	for _, cfg := range c.user.Configurations {
		var x Extension

		// Check for HTTP extensions
		if cfg.URL != "" {
			x = NewHttpExtension(cfg.URL, nil)
		} else {
			var err error
			x, err = c.loader.Load(cfg.EID)

			if err != nil {
				panic(err)
			}
		}

		exe = append(exe, *NewExecution(x, *m, cfg.Cfg))
	}

	return exe
}

func (m *Message) sentBy(u *User) bool {
	return u.ID.Equals(m.UserID)
}

func (m *Message) escaped() bool {
	return strings.HasPrefix(m.Text, `\`)
}

func trimEscape(text string) string {
	return strings.TrimPrefix(text, `\`)
}

func performActions(act []MessageAction, msg *Message) (modified bool) {
	for _, a := range act {
		err, mod := msg.perform(a)

		if err != nil {
			panic(err)
		}

		modified = modified || mod
	}

	return
}
<commit_msg>Remove block on killchannels<commit_after>package sirius

import (
	"errors"
	"strings"
	"time"
)

type Client struct {
	Ready   chan bool
	user    *User
	conn    Connection
	loader  ExtensionLoader
	runner  ExtensionRunner
	timeout time.Duration
	done    chan bool
}

type ClientConfig struct {
	user    *User
	loader  ExtensionLoader
	runner  ExtensionRunner
	timeout time.Duration
}

func NewClient(cfg ClientConfig) *Client {
	cl := &Client{
		conn:    NewRTMConnection(cfg.user.Token),
		user:    cfg.user,
		loader:  cfg.loader,
		runner:  cfg.runner,
		timeout: cfg.timeout,
		Ready:   make(chan bool, 1),
		done:    make(chan bool),
	}
	if cl.runner == nil {
		cl.runner = NewAsyncRunner()
	}
	if cl.timeout == 0 {
		cl.timeout = time.Second * 2
	}
	return cl
}

func (c *Client) Start() {
	go c.conn.Listen()

	err := c.authenticate()
	if err != nil {
		panic(err)
	}

	c.Ready <- true

	for {
		select {
		// Make sure we always check for termination signal first
		case <-c.done:
			c.conn.Close()
			return
		case <-c.conn.Dead():
			c.done <- true
			return
		default:
		}

		select {
		case msg := <-c.conn.Messages():
			c.handle(&msg)
		}
	}
}

func (c *Client) Stop() {
	c.done <- true
}

func (c *Client) authenticate() error {
	auth := c.conn.Auth()

	for {
		select {
		case id := <-auth:
			c.user.ID = id
			return nil
		case <-time.After(time.Second * 3):
			return errors.New("Client authentication timed out (<-c.conn.Auth())")
		}
	}
}

func (c *Client) handle(msg *Message) {
	if !msg.sentBy(c.user) {
		return
	}

	if msg.escaped() {
		edit := msg.EditText().Set(trimEscape(msg.Text))
		msg.perform(edit)

		c.conn.Update(msg)
		return
	}

	c.run(msg)
}

func (c *Client) run(m *Message) {
	exe := c.loadExecutions(m)
	act := c.runExecutions(exe)

	if performActions(act, m) {
		c.conn.Update(m)
	}
}

func (c *Client) runExecutions(exe []Execution) []MessageAction {
	var act []MessageAction
	res := make(chan ExecutionResult, len(c.user.Configurations))

	c.runner.Run(exe, res, c.timeout)

	for r := range res {
		if r.Err != nil {
			panic(r.Err)
		}

		if _, ok := r.Action.(*EmptyAction); ok {
			continue
		}

		act = append(act, r.Action)
	}

	return act
}

func (c *Client) loadExecutions(m *Message) []Execution {
	var exe []Execution
	for _, cfg := range c.user.Configurations {
		var x Extension

		// Check for HTTP extensions
		if cfg.URL != "" {
			x = NewHttpExtension(cfg.URL, nil)
		} else {
			var err error
			x, err = c.loader.Load(cfg.EID)

			if err != nil {
				panic(err)
			}
		}

		exe = append(exe, *NewExecution(x, *m, cfg.Cfg))
	}

	return exe
}

func (m *Message) sentBy(u *User) bool {
	return u.ID.Equals(m.UserID)
}

func (m *Message) escaped() bool {
	return strings.HasPrefix(m.Text, `\`)
}

func trimEscape(text string) string {
	return strings.TrimPrefix(text, `\`)
}

func performActions(act []MessageAction, msg *Message) (modified bool) {
	for _, a := range act {
		err, mod := msg.perform(a)

		if err != nil {
			panic(err)
		}

		modified = modified || mod
	}

	return
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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.

// More information about Google Directions API is available on
// https://developers.google.com/maps/documentation/directions/

package maps // import "google.golang.org/maps"

import (
	"encoding/base64"
	"fmt"
	"net/http"
	"net/url"
	"time"

	"google.golang.org/maps/internal"
)

type requestQuota struct{}

// Client may be used to make requests to the Google Maps WebService APIs
type Client struct {
<<<<<<< HEAD
	httpClient        *http.Client
	apiKey            string
	baseURL           string
	clientID          string
	signature         string
	requestsPerSecond int
	rateLimiter       chan requestQuota
=======
	httpClient *http.Client
	apiKey     string
	baseURL    string
	clientID   string
	signature  []byte
>>>>>>> upstream/master
}

//
type clientOption func(*Client) error

// NewClient constructs a new Client which can make requests to the Google Maps WebService APIs.
// The supplied http.Client is used for making requests to the Maps WebService APIs
func NewClient(options ...clientOption) (*Client, error) {
	c := &Client{requestsPerSecond: 10}
	WithHTTPClient(&http.Client{})(c)
	for _, option := range options {
		err := option(c)
		if err != nil {
			return nil, err
		}
	}
	if c.apiKey == "" && (c.clientID == "" || len(c.signature) == 0) {
		return nil, fmt.Errorf("maps.Client with no API Key or Maps for Work credentials")
	}

	// Implement a bursty rate limiter.
	// Allow up to 1 second worth of requests to be made at once.
	c.rateLimiter = make(chan requestQuota, c.requestsPerSecond)
	// Prefill rateLimiter with 1 seconds worth of requests.
	for i := 0; i < c.requestsPerSecond; i++ {
		c.rateLimiter <- requestQuota{}
	}
	go func() {
		// Refill rateLimiter continuously
		for range time.Tick(time.Second / time.Duration(c.requestsPerSecond)) {
			c.rateLimiter <- requestQuota{}
		}
	}()

	return c, nil
}

// WithHTTPClient configures a Maps API client with a http.Client to make requests over.
func WithHTTPClient(c *http.Client) clientOption {
	return func(client *Client) error {
		if _, ok := c.Transport.(*transport); !ok {
			t := c.Transport
			if t != nil {
				c.Transport = &transport{Base: t}
			} else {
				c.Transport = &transport{Base: http.DefaultTransport}
			}
		}
		client.httpClient = c
		return nil
	}
}

// withBaseURL is for testing only.
func withBaseURL(url string) clientOption {
	return func(client *Client) error {
		client.baseURL = url
		return nil
	}
}

// WithAPIKey configures a Maps API client with an API Key
func WithAPIKey(apiKey string) clientOption {
	return func(client *Client) error {
		client.apiKey = apiKey
		return nil
	}
}

// WithClientIDAndSignature configures a Maps API client for a Maps for Work application
// The signature is assumed to be URL modified Base64 encoded
func WithClientIDAndSignature(clientID, signature string) clientOption {
	return func(client *Client) error {
		client.clientID = clientID
		decoded, err := base64.URLEncoding.DecodeString(signature)
		if err != nil {
			return err
		}
		client.signature = decoded
		return nil
	}
}

// WithRateLimit configures the rate limit for back end requests.
// Default is to limit to 10 requests per second.
func WithRateLimit(requestsPerSecond int) func(*Client) error {
	return func(client *Client) error {
		client.requestsPerSecond = requestsPerSecond
		return nil
	}
}

func (client *Client) httpDo(req *http.Request) (*http.Response, error) {
	<-client.rateLimiter
	return client.httpClient.Do(req)
}

const userAgent = "GoogleGeoApiClientGo/0.1"

// Transport is an http.RoundTripper that appends
// Google Cloud client's user-agent to the original
// request's user-agent header.
type transport struct {
	// Base represents the actual http.RoundTripper
	// the requests will be delegated to.
	Base http.RoundTripper
}

// RoundTrip appends a user-agent to the existing user-agent
// header and delegates the request to the base http.RoundTripper.
func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) {
	req = cloneRequest(req)
	ua := req.Header.Get("User-Agent")
	if ua == "" {
		ua = userAgent
	} else {
		ua = fmt.Sprintf("%s;%s", ua, userAgent)
	}
	req.Header.Set("User-Agent", ua)
	return t.Base.RoundTrip(req)
}

// cloneRequest returns a clone of the provided *http.Request.
// The clone is a shallow copy of the struct and its Header map.
func cloneRequest(r *http.Request) *http.Request {
	// shallow copy of the struct
	r2 := new(http.Request)
	*r2 = *r
	// deep copy of the Header
	r2.Header = make(http.Header)
	for k, s := range r.Header {
		r2.Header[k] = s
	}
	return r2
}

func (client *Client) generateAuthQuery(path string, q url.Values, acceptClientID bool) (string, error) {
	if client.apiKey != "" {
		q.Set("key", client.apiKey)
		return q.Encode(), nil
	}
	if acceptClientID {
		query, err := internal.SignURL(path, client.clientID, client.signature, q)
		if err != nil {
			return "", err
		}
		return query, nil
	}
	return "", fmt.Errorf("Must provide API key for this API. It does not accept enterprise credentials.")
}
<commit_msg>Fixing merge<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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.

// More information about Google Directions API is available on
// https://developers.google.com/maps/documentation/directions/

package maps // import "google.golang.org/maps"

import (
	"encoding/base64"
	"fmt"
	"net/http"
	"net/url"
	"time"

	"google.golang.org/maps/internal"
)

type requestQuota struct{}

// Client may be used to make requests to the Google Maps WebService APIs
type Client struct {
	httpClient        *http.Client
	apiKey            string
	baseURL           string
	clientID          string
	signature         []byte
	requestsPerSecond int
	rateLimiter       chan requestQuota
}

//
type clientOption func(*Client) error

// NewClient constructs a new Client which can make requests to the Google Maps WebService APIs.
// The supplied http.Client is used for making requests to the Maps WebService APIs
func NewClient(options ...clientOption) (*Client, error) {
	c := &Client{requestsPerSecond: 10}
	WithHTTPClient(&http.Client{})(c)
	for _, option := range options {
		err := option(c)
		if err != nil {
			return nil, err
		}
	}
	if c.apiKey == "" && (c.clientID == "" || len(c.signature) == 0) {
		return nil, fmt.Errorf("maps.Client with no API Key or Maps for Work credentials")
	}

	// Implement a bursty rate limiter.
	// Allow up to 1 second worth of requests to be made at once.
	c.rateLimiter = make(chan requestQuota, c.requestsPerSecond)
	// Prefill rateLimiter with 1 seconds worth of requests.
	for i := 0; i < c.requestsPerSecond; i++ {
		c.rateLimiter <- requestQuota{}
	}
	go func() {
		// Refill rateLimiter continuously
		for range time.Tick(time.Second / time.Duration(c.requestsPerSecond)) {
			c.rateLimiter <- requestQuota{}
		}
	}()

	return c, nil
}

// WithHTTPClient configures a Maps API client with a http.Client to make requests over.
func WithHTTPClient(c *http.Client) clientOption {
	return func(client *Client) error {
		if _, ok := c.Transport.(*transport); !ok {
			t := c.Transport
			if t != nil {
				c.Transport = &transport{Base: t}
			} else {
				c.Transport = &transport{Base: http.DefaultTransport}
			}
		}
		client.httpClient = c
		return nil
	}
}

// withBaseURL is for testing only.
func withBaseURL(url string) clientOption {
	return func(client *Client) error {
		client.baseURL = url
		return nil
	}
}

// WithAPIKey configures a Maps API client with an API Key
func WithAPIKey(apiKey string) clientOption {
	return func(client *Client) error {
		client.apiKey = apiKey
		return nil
	}
}

// WithClientIDAndSignature configures a Maps API client for a Maps for Work application
// The signature is assumed to be URL modified Base64 encoded
func WithClientIDAndSignature(clientID, signature string) clientOption {
	return func(client *Client) error {
		client.clientID = clientID
		decoded, err := base64.URLEncoding.DecodeString(signature)
		if err != nil {
			return err
		}
		client.signature = decoded
		return nil
	}
}

// WithRateLimit configures the rate limit for back end requests.
// Default is to limit to 10 requests per second.
func WithRateLimit(requestsPerSecond int) func(*Client) error {
	return func(client *Client) error {
		client.requestsPerSecond = requestsPerSecond
		return nil
	}
}

func (client *Client) httpDo(req *http.Request) (*http.Response, error) {
	<-client.rateLimiter
	return client.httpClient.Do(req)
}

const userAgent = "GoogleGeoApiClientGo/0.1"

// Transport is an http.RoundTripper that appends
// Google Cloud client's user-agent to the original
// request's user-agent header.
type transport struct {
	// Base represents the actual http.RoundTripper
	// the requests will be delegated to.
	Base http.RoundTripper
}

// RoundTrip appends a user-agent to the existing user-agent
// header and delegates the request to the base http.RoundTripper.
func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) {
	req = cloneRequest(req)
	ua := req.Header.Get("User-Agent")
	if ua == "" {
		ua = userAgent
	} else {
		ua = fmt.Sprintf("%s;%s", ua, userAgent)
	}
	req.Header.Set("User-Agent", ua)
	return t.Base.RoundTrip(req)
}

// cloneRequest returns a clone of the provided *http.Request.
// The clone is a shallow copy of the struct and its Header map.
func cloneRequest(r *http.Request) *http.Request {
	// shallow copy of the struct
	r2 := new(http.Request)
	*r2 = *r
	// deep copy of the Header
	r2.Header = make(http.Header)
	for k, s := range r.Header {
		r2.Header[k] = s
	}
	return r2
}

func (client *Client) generateAuthQuery(path string, q url.Values, acceptClientID bool) (string, error) {
	if client.apiKey != "" {
		q.Set("key", client.apiKey)
		return q.Encode(), nil
	}
	if acceptClientID {
		query, err := internal.SignURL(path, client.clientID, client.signature, q)
		if err != nil {
			return "", err
		}
		return query, nil
	}
	return "", fmt.Errorf("Must provide API key for this API. It does not accept enterprise credentials.")
}
<|endoftext|>


<commit_before>package resty

import (
	"bytes"
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"regexp"
	"strings"
)

type Reply struct {
	Err    error
	Status int
	Header http.Header
	Value  []byte
	URL    string
}

func (r *Reply) Unmarshal(v interface{}) error {
	return json.Unmarshal(r.Value, v)
}

type Client struct {
	HTTPClient  http.Client
	BaseURL     string
	ContentType string
}

func NewClient(baseURL string) *Client {
	c := &Client{
		BaseURL:     baseURL,
		ContentType: "application/json",
	}
	c.Reset()
	return c
}

var re = regexp.MustCompile(`/+`)

func (c *Client) GetFullURL(subPath string) (*url.URL, error) {
	if strings.HasPrefix(subPath, "http:") || strings.HasPrefix(subPath, "https:") {
		return url.Parse(subPath)
	}

	u, err := url.Parse(c.BaseURL + "/" + subPath)
	if u != nil {
		u.Path = re.ReplaceAllString(u.Path, "/")
	}
	return u, err

}
func (c *Client) Do(method, path string, data interface{}, out interface{}) (r Reply) {
	var u *url.URL
	if u, r.Err = c.GetFullURL(path); r.Err != nil {
		return
	}
	var (
		body io.Reader
		req  *http.Request
	)
	switch data := data.(type) {
	case io.Reader:
		body = data
	case string:
		body = strings.NewReader(data)
	case []byte:
		body = bytes.NewReader(data)
	case nil:
	// nothing
	default:
		if c.ContentType != "application/json" {
			panic("not supported")
		}
		var j []byte
		if j, r.Err = json.MarshalIndent(data, "", "\t"); r.Err != nil {
			return
		}
		body = bytes.NewReader(j)
	}

	if req, r.Err = http.NewRequest(method, u.String(), body); r.Err != nil {
		return
	}
	if body != nil {
		req.Header.Set("Content-Type", c.ContentType)
	}
	var resp *http.Response
	if resp, r.Err = c.HTTPClient.Do(req); r.Err != nil {
		return
	}

	defer resp.Body.Close()
	r.Status, r.Header = resp.StatusCode, resp.Header
	if r.Value, r.Err = ioutil.ReadAll(resp.Body); r.Err != nil {
		return
	}
	if out != nil {
		r.Err = r.Unmarshal(out)
	}

	r.URL = resp.Request.URL.String()
	return
}

func (c *Client) Reset() {
	c.HTTPClient.Jar, _ = cookiejar.New(nil)
}
<commit_msg>Extra method for resty<commit_after>package resty

import (
	"bytes"
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"regexp"
	"strings"
)

type Reply struct {
	Err    error
	Status int
	Header http.Header
	Value  []byte
	URL    string
}

func (r *Reply) Unmarshal(v interface{}) error {
	return json.Unmarshal(r.Value, v)
}

type Client struct {
	HTTPClient  http.Client
	BaseURL     string
	ContentType string
}

func NewClient(baseURL string) *Client {
	c := &Client{
		BaseURL:     baseURL,
		ContentType: "application/json",
	}
	c.Reset()
	return c
}

var re = regexp.MustCompile(`/+`)

func (c *Client) GetFullURL(subPath string) (*url.URL, error) {
	if strings.HasPrefix(subPath, "http:") || strings.HasPrefix(subPath, "https:") {
		return url.Parse(subPath)
	}

	u, err := url.Parse(c.BaseURL + "/" + subPath)
	if u != nil {
		u.Path = re.ReplaceAllString(u.Path, "/")
	}
	return u, err

}
func (c *Client) Do(method, path string, data interface{}, out interface{}) (r Reply) {
	var u *url.URL
	if u, r.Err = c.GetFullURL(path); r.Err != nil {
		return
	}
	var (
		body io.Reader
		req  *http.Request
	)
	switch data := data.(type) {
	case io.Reader:
		body = data
	case string:
		body = strings.NewReader(data)
	case []byte:
		body = bytes.NewReader(data)
	case nil:
	// nothing
	default:
		if c.ContentType != "application/json" {
			panic("not supported")
		}
		var j []byte
		if j, r.Err = json.MarshalIndent(data, "", "\t"); r.Err != nil {
			return
		}
		body = bytes.NewReader(j)
	}

	if req, r.Err = http.NewRequest(method, u.String(), body); r.Err != nil {
		return
	}
	if body != nil {
		req.Header.Set("Content-Type", c.ContentType)
	}
	var resp *http.Response
	if resp, r.Err = c.HTTPClient.Do(req); r.Err != nil {
		return
	}

	defer resp.Body.Close()
	r.Status, r.Header = resp.StatusCode, resp.Header
	if r.Value, r.Err = ioutil.ReadAll(resp.Body); r.Err != nil {
		return
	}
	if out != nil {
		r.Err = r.Unmarshal(out)
	}

	r.URL = resp.Request.URL.String()
	return
}

func (c *Client) RawDo(method, path string) (*http.Response, error) {
	var (
		u   *url.URL
		err error
	)
	if u, err = c.GetFullURL(path); err != nil {
		return nil, err
	}

	var (
		req *http.Request
	)

	if req, err = http.NewRequest(method, u.String(), nil); err != nil {
		return nil, err
	}

	var resp *http.Response
	if resp, err = c.HTTPClient.Do(req); err != nil {
		return nil, err
	}

	return resp, nil
}

func (c *Client) Reset() {
	c.HTTPClient.Jar, _ = cookiejar.New(nil)
}
<|endoftext|>


<commit_before>// Package webfinger provides a simple client implementation of the WebFinger
// protocol.
//
// It is a work in progress, the API is not frozen.
// We're trying to catchup with the last draft of the protocol:
// http://tools.ietf.org/html/draft-ietf-appsawg-webfinger-14
// and to support the http://webfist.org
//
// Example:
//
//  package main
//
//  import (
//          "fmt"
//          "github.com/ant0ine/go-webfinger"
//          "os"
//  )
//
//  func main() {
//          email := os.Args[1]
//
//          client := webfinger.NewClient(nil)
//
//          resource, err := webfinger.MakeResource(email)
//          if err != nil {
//                  panic(err)
//          }
//
//          jrd, err := client.GetJRD(resource)
//          if err != nil {
//                  fmt.Println(err)
//                  return
//          }
//
//          fmt.Printf("JRD: %+v", jrd)
//  }
package webfinger

import (
	"errors"
	"fmt"
	"github.com/ant0ine/go-webfinger/jrd"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"strings"
)

// Resource is a resource for which a WebFinger query can be issued.
type Resource url.URL

// Parse parses rawurl into a WebFinger Resource.  The rawurl should be an
// absolute URL, or an email-like identifier (e.g. "bob@example.com").
func Parse(rawurl string) (*Resource, error) {
	u, err := url.Parse(rawurl)
	if err != nil {
		return nil, err
	}

	// if parsed URL has no scheme but is email-like, treat it as an acct: URL.
	if u.Scheme == "" {
		parts := strings.SplitN(rawurl, "@", 2)
		if len(parts) != 2 {
			return nil, fmt.Errorf("URL must be absolute, or an email address: %v", rawurl)
		}
		return Parse("acct:" + rawurl)
	}

	r := Resource(*u)
	return &r, nil
}

// WebFingerHost returns the default host for issuing WebFinger queries for
// this resource.  For Resource URLs with a host component, that value is used.
// For URLs that do not have a host component, the host is determined by other
// mains if possible (for example, the domain in the addr-spec of a mailto
// URL).  If the host cannot be determined from the URL, this value will be an
// empty string.
func (r *Resource) WebFingerHost() string {
	if r.Host != "" {
		return r.Host
	} else if r.Scheme == "acct" || r.Scheme == "mailto" {
		parts := strings.SplitN(r.Opaque, "@", 2)
		if len(parts) == 2 {
			return parts[1]
		}
	}
	return ""
}

// String reassembles the Resource into a valid URL string.
func (r *Resource) String() string {
	u := url.URL(*r)
	return u.String()
}

// JRDURL returns the WebFinger query URL at the specified host for this
// resource.  If host is an empty string, the default host for the resource
// will be used, as returned from WebFingerHost().
func (r *Resource) JRDURL(host string, rels []string) *url.URL {
	if host == "" {
		host = r.WebFingerHost()
	}

	return &url.URL{
		Scheme: "https",
		Host:   host,
		Path:   "/.well-known/webfinger",
		RawQuery: url.Values{
			"resource": []string{r.String()},
			"rel":      rels,
		}.Encode(),
	}
}

// A Client is a WebFinger client.
type Client struct {
	// HTTP client used to perform WebFinger lookups.
	client *http.Client

	// WebFistServer is the host used for issuing WebFist queries when standard
	// WebFinger lookup fails.  If set to the empty string, queries will not fall
	// back to the WebFist protocol.
	WebFistServer string

	// Allow the use of HTTP endoints for lookups.  The WebFinger spec requires
	// all lookups be performed over HTTPS, so this should only ever be enabled
	// for development.
	AllowHTTP bool
}

// DefaultClient is the default Client and is used by Lookup.
var DefaultClient = &Client{
	client:        http.DefaultClient,
}

// Lookup returns the JRD for the specified identifier.
//
// Lookup is a wrapper around DefaultClient.Lookup.
func Lookup(identifier string, rels []string) (*jrd.JRD, error) {
	return DefaultClient.Lookup(identifier, rels)
}

// NewClient returns a new WebFinger Client.  If a nil http.Client is provied,
// http.DefaultClient will be used.  New Clients will use the default WebFist
// host if WebFinger lookup fails.
func NewClient(httpClient *http.Client) *Client {
	if httpClient == nil {
		httpClient = http.DefaultClient
	}
	return &Client{
		client: httpClient,
		WebFistServer: webFistDefaultServer,
	}
}

// Lookup returns the JRD for the specified identifier.  If provided, only the
// specified rel values will be requested, though WebFinger servers are not
// obligated to respect that request.
func (c *Client) Lookup(identifier string, rels []string) (*jrd.JRD, error) {
	resource, err := Parse(identifier)
	if err != nil {
		return nil, err
	}

	return c.LookupResource(resource, rels)
}

// LookupResource returns the JRD for the specified Resource.  If provided,
// only the specified rel values will be requested, though WebFinger servers
// are not obligated to respect that request.
func (c *Client) LookupResource(resource *Resource, rels []string) (*jrd.JRD, error) {
	log.Printf("Looking up WebFinger data for %s", resource)

	resourceJRD, err := c.fetchJRD(resource.JRDURL("", rels))
	if err != nil {
		log.Print(err)

		// Fallback to WebFist protocol
		if c.WebFistServer != "" {
			log.Print("Falling back to WebFist protocol")
			resourceJRD, err = c.webfistLookup(resource)
		}

		if err != nil {
			return nil, err
		}
	}

	return resourceJRD, nil
}

func (self *Client) fetchJRD(jrdURL *url.URL) (*jrd.JRD, error) {
	// TODO verify signature if not https
	// TODO extract http cache info

	// Get follows up to 10 redirects
	log.Printf("GET %s", jrdURL.String())
	res, err := self.client.Get(jrdURL.String())
	if err != nil {
		log.Printf("%s", err)
		errString := strings.ToLower(err.Error())
		// For some crazy reason, App Engine returns a "ssl_certificate_error" when
		// unable to connect to an HTTPS URL, so we check for that as well here.
		if (strings.Contains(errString, "connection refused") ||
			strings.Contains(errString, "ssl_certificate_error")) && self.AllowHTTP {
			jrdURL.Scheme = "http"
			log.Printf("GET %s", jrdURL.String())
			res, err = self.client.Get(jrdURL.String())
			if err != nil {
				return nil, err
			}
		} else {
			return nil, err
		}
	}

	if !(200 <= res.StatusCode && res.StatusCode < 300) {
		return nil, errors.New(res.Status)
	}

	content, err := ioutil.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
		return nil, err
	}

	ct := strings.ToLower(res.Header.Get("content-type"))
	if strings.Contains(ct, "application/jrd+json") ||
		strings.Contains(ct, "application/json") {
		parsed, err := jrd.ParseJRD(content)
		if err != nil {
			return nil, err
		}
		return parsed, nil
	}

	return nil, errors.New(fmt.Sprintf("invalid content-type: %s", ct))
}
<commit_msg>Enable Webfist for the DefaultClient<commit_after>// Package webfinger provides a simple client implementation of the WebFinger
// protocol.
//
// It is a work in progress, the API is not frozen.
// We're trying to catchup with the last draft of the protocol:
// http://tools.ietf.org/html/draft-ietf-appsawg-webfinger-14
// and to support the http://webfist.org
//
// Example:
//
//  package main
//
//  import (
//          "fmt"
//          "github.com/ant0ine/go-webfinger"
//          "os"
//  )
//
//  func main() {
//          email := os.Args[1]
//
//          client := webfinger.NewClient(nil)
//
//          resource, err := webfinger.MakeResource(email)
//          if err != nil {
//                  panic(err)
//          }
//
//          jrd, err := client.GetJRD(resource)
//          if err != nil {
//                  fmt.Println(err)
//                  return
//          }
//
//          fmt.Printf("JRD: %+v", jrd)
//  }
package webfinger

import (
	"errors"
	"fmt"
	"github.com/ant0ine/go-webfinger/jrd"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"strings"
)

// Resource is a resource for which a WebFinger query can be issued.
type Resource url.URL

// Parse parses rawurl into a WebFinger Resource.  The rawurl should be an
// absolute URL, or an email-like identifier (e.g. "bob@example.com").
func Parse(rawurl string) (*Resource, error) {
	u, err := url.Parse(rawurl)
	if err != nil {
		return nil, err
	}

	// if parsed URL has no scheme but is email-like, treat it as an acct: URL.
	if u.Scheme == "" {
		parts := strings.SplitN(rawurl, "@", 2)
		if len(parts) != 2 {
			return nil, fmt.Errorf("URL must be absolute, or an email address: %v", rawurl)
		}
		return Parse("acct:" + rawurl)
	}

	r := Resource(*u)
	return &r, nil
}

// WebFingerHost returns the default host for issuing WebFinger queries for
// this resource.  For Resource URLs with a host component, that value is used.
// For URLs that do not have a host component, the host is determined by other
// mains if possible (for example, the domain in the addr-spec of a mailto
// URL).  If the host cannot be determined from the URL, this value will be an
// empty string.
func (r *Resource) WebFingerHost() string {
	if r.Host != "" {
		return r.Host
	} else if r.Scheme == "acct" || r.Scheme == "mailto" {
		parts := strings.SplitN(r.Opaque, "@", 2)
		if len(parts) == 2 {
			return parts[1]
		}
	}
	return ""
}

// String reassembles the Resource into a valid URL string.
func (r *Resource) String() string {
	u := url.URL(*r)
	return u.String()
}

// JRDURL returns the WebFinger query URL at the specified host for this
// resource.  If host is an empty string, the default host for the resource
// will be used, as returned from WebFingerHost().
func (r *Resource) JRDURL(host string, rels []string) *url.URL {
	if host == "" {
		host = r.WebFingerHost()
	}

	return &url.URL{
		Scheme: "https",
		Host:   host,
		Path:   "/.well-known/webfinger",
		RawQuery: url.Values{
			"resource": []string{r.String()},
			"rel":      rels,
		}.Encode(),
	}
}

// A Client is a WebFinger client.
type Client struct {
	// HTTP client used to perform WebFinger lookups.
	client *http.Client

	// WebFistServer is the host used for issuing WebFist queries when standard
	// WebFinger lookup fails.  If set to the empty string, queries will not fall
	// back to the WebFist protocol.
	WebFistServer string

	// Allow the use of HTTP endoints for lookups.  The WebFinger spec requires
	// all lookups be performed over HTTPS, so this should only ever be enabled
	// for development.
	AllowHTTP bool
}

// DefaultClient is the default Client and is used by Lookup.
var DefaultClient = &Client{
	client:        http.DefaultClient,
	WebFistServer: webFistDefaultServer,
}

// Lookup returns the JRD for the specified identifier.
//
// Lookup is a wrapper around DefaultClient.Lookup.
func Lookup(identifier string, rels []string) (*jrd.JRD, error) {
	return DefaultClient.Lookup(identifier, rels)
}

// NewClient returns a new WebFinger Client.  If a nil http.Client is provied,
// http.DefaultClient will be used.  New Clients will use the default WebFist
// host if WebFinger lookup fails.
func NewClient(httpClient *http.Client) *Client {
	if httpClient == nil {
		httpClient = http.DefaultClient
	}
	return &Client{
		client:        httpClient,
		WebFistServer: webFistDefaultServer,
	}
}

// Lookup returns the JRD for the specified identifier.  If provided, only the
// specified rel values will be requested, though WebFinger servers are not
// obligated to respect that request.
func (c *Client) Lookup(identifier string, rels []string) (*jrd.JRD, error) {
	resource, err := Parse(identifier)
	if err != nil {
		return nil, err
	}

	return c.LookupResource(resource, rels)
}

// LookupResource returns the JRD for the specified Resource.  If provided,
// only the specified rel values will be requested, though WebFinger servers
// are not obligated to respect that request.
func (c *Client) LookupResource(resource *Resource, rels []string) (*jrd.JRD, error) {
	log.Printf("Looking up WebFinger data for %s", resource)

	resourceJRD, err := c.fetchJRD(resource.JRDURL("", rels))
	if err != nil {
		log.Print(err)

		// Fallback to WebFist protocol
		if c.WebFistServer != "" {
			log.Print("Falling back to WebFist protocol")
			resourceJRD, err = c.webfistLookup(resource)
		}

		if err != nil {
			return nil, err
		}
	}

	return resourceJRD, nil
}

func (self *Client) fetchJRD(jrdURL *url.URL) (*jrd.JRD, error) {
	// TODO verify signature if not https
	// TODO extract http cache info

	// Get follows up to 10 redirects
	log.Printf("GET %s", jrdURL.String())
	res, err := self.client.Get(jrdURL.String())
	if err != nil {
		log.Printf("%s", err)
		errString := strings.ToLower(err.Error())
		// For some crazy reason, App Engine returns a "ssl_certificate_error" when
		// unable to connect to an HTTPS URL, so we check for that as well here.
		if (strings.Contains(errString, "connection refused") ||
			strings.Contains(errString, "ssl_certificate_error")) && self.AllowHTTP {
			jrdURL.Scheme = "http"
			log.Printf("GET %s", jrdURL.String())
			res, err = self.client.Get(jrdURL.String())
			if err != nil {
				return nil, err
			}
		} else {
			return nil, err
		}
	}

	if !(200 <= res.StatusCode && res.StatusCode < 300) {
		return nil, errors.New(res.Status)
	}

	content, err := ioutil.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
		return nil, err
	}

	ct := strings.ToLower(res.Header.Get("content-type"))
	if strings.Contains(ct, "application/jrd+json") ||
		strings.Contains(ct, "application/json") {
		parsed, err := jrd.ParseJRD(content)
		if err != nil {
			return nil, err
		}
		return parsed, nil
	}

	return nil, errors.New(fmt.Sprintf("invalid content-type: %s", ct))
}
<|endoftext|>


<commit_before>/*
 * Datadog API for Go
 *
 * Please see the included LICENSE file for licensing information.
 *
 * Copyright 2013 by authors and contributors.
 */

package datadog

import (
	"encoding/json"
	"io/ioutil"
	"net/http"
	"os"
	"time"
)

// Client is the object that handles talking to the Datadog API. This maintains
// state information for a particular application connection.
type Client struct {
	apiKey, appKey, baseUrl string

	//The Http Client that is used to make requests
	HttpClient   *http.Client
	RetryTimeout time.Duration
}

// valid is the struct to unmarshal validation endpoint responses into.
type valid struct {
	Errors  []string `json:"errors"`
	IsValid bool     `json:"valid"`
}

// NewClient returns a new datadog.Client which can be used to access the API
// methods. The expected argument is the API key.
func NewClient(apiKey, appKey string) *Client {
	baseUrl := os.Getenv("DATADOG_HOST")
	if baseUrl == "" {
		baseUrl = "https://app.datadoghq.com"
	}

	return &Client{
		apiKey:       apiKey,
		appKey:       appKey,
		baseUrl:      baseUrl,
		HttpClient:   http.DefaultClient,
		RetryTimeout: time.Duration(60 * time.Second),
	}
}

// SetKeys changes the value of apiKey and appKey.
func (c *Client) SetKeys(apiKey, appKey string) {
	c.apiKey = apiKey
	c.appKey = appKey
}

// SetBaseUrl changes the value of baseUrl.
func (c *Client) SetBaseUrl(baseUrl string) {
	c.baseUrl = baseUrl
}

// GetBaseUrl returns the baseUrl.
func (c *Client) GetBaseUrl() string {
	return c.baseUrl
}

// Validate checks if the API and application keys are valid.
func (client *Client) Validate() (bool, error) {
	var out valid
	var resp *http.Response

	uri, err := client.uriForAPI("/v1/validate")
	if err != nil {
		return false, err
	}

	req, err := http.NewRequest("GET", uri, nil)
	if err != nil {
		return false, err
	}

	resp, err = client.doRequestWithRetries(req, client.RetryTimeout)
	if err != nil {
		return false, err
	}

	defer resp.Body.Close()

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

	if err = json.Unmarshal(body, &out); err != nil {
		return false, err
	}

	return out.IsValid, nil
}
<commit_msg>api instead of app<commit_after>/*
 * Datadog API for Go
 *
 * Please see the included LICENSE file for licensing information.
 *
 * Copyright 2013 by authors and contributors.
 */

package datadog

import (
	"encoding/json"
	"io/ioutil"
	"net/http"
	"os"
	"time"
)

// Client is the object that handles talking to the Datadog API. This maintains
// state information for a particular application connection.
type Client struct {
	apiKey, appKey, baseUrl string

	//The Http Client that is used to make requests
	HttpClient   *http.Client
	RetryTimeout time.Duration
}

// valid is the struct to unmarshal validation endpoint responses into.
type valid struct {
	Errors  []string `json:"errors"`
	IsValid bool     `json:"valid"`
}

// NewClient returns a new datadog.Client which can be used to access the API
// methods. The expected argument is the API key.
func NewClient(apiKey, appKey string) *Client {
	baseUrl := os.Getenv("DATADOG_HOST")
	if baseUrl == "" {
		baseUrl = "https://api.datadoghq.com"
	}

	return &Client{
		apiKey:       apiKey,
		appKey:       appKey,
		baseUrl:      baseUrl,
		HttpClient:   http.DefaultClient,
		RetryTimeout: time.Duration(60 * time.Second),
	}
}

// SetKeys changes the value of apiKey and appKey.
func (c *Client) SetKeys(apiKey, appKey string) {
	c.apiKey = apiKey
	c.appKey = appKey
}

// SetBaseUrl changes the value of baseUrl.
func (c *Client) SetBaseUrl(baseUrl string) {
	c.baseUrl = baseUrl
}

// GetBaseUrl returns the baseUrl.
func (c *Client) GetBaseUrl() string {
	return c.baseUrl
}

// Validate checks if the API and application keys are valid.
func (client *Client) Validate() (bool, error) {
	var out valid
	var resp *http.Response

	uri, err := client.uriForAPI("/v1/validate")
	if err != nil {
		return false, err
	}

	req, err := http.NewRequest("GET", uri, nil)
	if err != nil {
		return false, err
	}

	resp, err = client.doRequestWithRetries(req, client.RetryTimeout)
	if err != nil {
		return false, err
	}

	defer resp.Body.Close()

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

	if err = json.Unmarshal(body, &out); err != nil {
		return false, err
	}

	return out.IsValid, nil
}
<|endoftext|>