<commit_before>package lorawan

import (
	"encoding/binary"
	"encoding/hex"
	"errors"
	"fmt"
)

// DevAddr represents the device address.
type DevAddr [4]byte

// NetIDType returns the NetID type of the DevAddr.
func (a DevAddr) NetIDType() int {
	for i := 0; i < 8; i++ {
		if a[0]&(0xff<<(byte(7-i))) == 0xff&(0xff<<(byte(8-i))) {
			return i
		}
	}
	panic("NetIDType bug!")
}

// NwkID returns the NwkID bits of the DevAddr.
func (a DevAddr) NwkID() []byte {
	switch a.NetIDType() {
	case 0:
		return a.getNwkID(1, 6)
	case 1:
		return a.getNwkID(2, 6)
	case 2:
		return a.getNwkID(3, 9)
	case 3:
		return a.getNwkID(4, 11)
	case 4:
		return a.getNwkID(5, 12)
	case 5:
		return a.getNwkID(6, 13)
	case 6:
		return a.getNwkID(7, 15)
	case 7:
		return a.getNwkID(8, 17)
	default:
		return nil
	}
}

// SetAddrPrefix sets the NetID based AddrPrefix.
func (a *DevAddr) SetAddrPrefix(netID NetID) {
	switch netID.Type() {
	case 0:
		a.setAddrPrefix(1, 6, netID)
	case 1:
		a.setAddrPrefix(2, 6, netID)
	case 2:
		a.setAddrPrefix(3, 9, netID)
	case 3:
		a.setAddrPrefix(4, 11, netID)
	case 4:
		a.setAddrPrefix(5, 12, netID)
	case 5:
		a.setAddrPrefix(6, 13, netID)
	case 6:
		a.setAddrPrefix(7, 15, netID)
	case 7:
		a.setAddrPrefix(8, 17, netID)
	}
}

// IsNetID returns a bool indicating if the NwkID matches the given NetID.
func (a DevAddr) IsNetID(netID NetID) bool {
	tempDevAddr := a
	tempDevAddr.SetAddrPrefix(netID)

	if a == tempDevAddr {
		return true
	}

	return false
}

func (a *DevAddr) setAddrPrefix(prefixLength, nwkIDBits int, netID NetID) {
	// convert DevAddr to uint32
	devAddr := binary.BigEndian.Uint32(a[:])

	// clear the bits for the prefix and NwkID
	var mask uint32
	mask-- // sets all uint32 bits to 1
	devAddr &^= mask << uint32(32-prefixLength-nwkIDBits)

	// set the type prefix
	prefix := uint32(254) << uint32(32-prefixLength)
	devAddr |= prefix

	// set the nwkID
	nwkIDBytes := make([]byte, 4)
	id := netID.ID()
	copy(nwkIDBytes[len(nwkIDBytes)-len(id):], id)

	nwkID := binary.BigEndian.Uint32(nwkIDBytes)
	nwkID = nwkID << uint32(32-nwkIDBits) // truncate the MSB of the NetID ID field
	nwkID = nwkID >> uint32(prefixLength) // shift back for the prefix MSB
	devAddr |= nwkID

	binary.BigEndian.PutUint32(a[:], devAddr)
}

func (a DevAddr) getNwkID(prefixLength, nwkIDBits int) []byte {
	// convert DevAddr to uint32
	temp := binary.BigEndian.Uint32(a[:])

	// clear prefix
	temp = temp << uint32(prefixLength)

	// shift to starting of NwkID
	temp = temp >> (32 - uint32(nwkIDBits))

	// back to bytes
	out := make([]byte, 4)
	binary.BigEndian.PutUint32(out, temp)

	bLen := nwkIDBits / 8
	if nwkIDBits%8 != 0 {
		bLen++
	}

	return out[len(out)-bLen:]
}

// MarshalBinary marshals the object in binary form.
func (a DevAddr) MarshalBinary() ([]byte, error) {
	out := make([]byte, len(a))
	for i, v := range a {
		// little endian
		out[len(a)-i-1] = v
	}
	return out, nil
}

// UnmarshalBinary decodes the object from binary form.
func (a *DevAddr) UnmarshalBinary(data []byte) error {
	if len(data) != len(a) {
		return fmt.Errorf("lorawan: %d bytes of data are expected", len(a))
	}
	for i, v := range data {
		// little endian
		a[len(a)-i-1] = v
	}
	return nil
}

// MarshalText implements encoding.TextMarshaler.
func (a DevAddr) MarshalText() ([]byte, error) {
	return []byte(a.String()), nil
}

// UnmarshalText implements encoding.TextUnmarshaler.
func (a *DevAddr) UnmarshalText(text []byte) error {
	b, err := hex.DecodeString(string(text))
	if err != nil {
		return err
	}

	if len(b) != len(a) {
		return fmt.Errorf("lorawan: exactly %d bytes are expected", len(a))
	}
	copy(a[:], b)
	return nil
}

// String implements fmt.Stringer.
func (a DevAddr) String() string {
	return hex.EncodeToString(a[:])
}

// Scan implements sql.Scanner.
func (a *DevAddr) Scan(src interface{}) error {
	b, ok := src.([]byte)
	if !ok {
		return errors.New("lorawan: []byte type expected")
	}
	if len(b) != len(a) {
		return fmt.Errorf("lorawan []byte must have length %d", len(a))
	}
	copy(a[:], b)
	return nil
}

// FCtrl represents the FCtrl (frame control) field.
// Please note that the FPending and ClassB are mapped to the same bit. This
// means that when unmarshaling from a byte-slice, both fields will contain
// the same value (either true or false).
type FCtrl struct {
	ADR       bool  `json:"adr"`
	ADRACKReq bool  `json:"adrAckReq"`
	ACK       bool  `json:"ack"`
	FPending  bool  `json:"fPending"` // only used for downlink messages
	ClassB    bool  `json:"classB"`   // only used for uplink messages
	fOptsLen  uint8 // will be set automatically by the FHDR when serialized to []byte
}

// MarshalBinary marshals the object in binary form.
func (c FCtrl) MarshalBinary() ([]byte, error) {
	if c.fOptsLen > 15 {
		return []byte{}, errors.New("lorawan: max value of FOptsLen is 15")
	}
	b := byte(c.fOptsLen)
	if c.FPending || c.ClassB {
		b = b ^ (1 << 4)
	}
	if c.ACK {
		b = b ^ (1 << 5)
	}
	if c.ADRACKReq {
		b = b ^ (1 << 6)
	}
	if c.ADR {
		b = b ^ (1 << 7)
	}
	return []byte{b}, nil
}

// UnmarshalBinary decodes the object from binary form.
func (c *FCtrl) UnmarshalBinary(data []byte) error {
	if len(data) != 1 {
		return errors.New("lorawan: 1 byte of data is expected")
	}
	c.fOptsLen = data[0] & ((1 << 3) ^ (1 << 2) ^ (1 << 1) ^ (1 << 0))
	c.FPending = data[0]&(1<<4) != 0
	c.ClassB = data[0]&(1<<4) != 0
	c.ACK = data[0]&(1<<5) != 0
	c.ADRACKReq = data[0]&(1<<6) != 0
	c.ADR = data[0]&(1<<7) != 0
	return nil
}

// FHDR represents the frame header.
type FHDR struct {
	DevAddr DevAddr   `json:"devAddr"`
	FCtrl   FCtrl     `json:"fCtrl"`
	FCnt    uint32    `json:"fCnt"`  // only the least-significant 16 bits will be marshalled
	FOpts   []Payload `json:"fOpts"` // max. number of allowed bytes is 15
}

// MarshalBinary marshals the object in binary form.
func (h FHDR) MarshalBinary() ([]byte, error) {
	var b []byte
	var err error
	var opts []byte

	for _, mac := range h.FOpts {
		b, err = mac.MarshalBinary()
		if err != nil {
			return []byte{}, err
		}
		opts = append(opts, b...)
	}
	h.FCtrl.fOptsLen = uint8(len(opts))
	if h.FCtrl.fOptsLen > 15 {
		return []byte{}, errors.New("lorawan: max number of FOpts bytes is 15")
	}

	out := make([]byte, 0, 7+h.FCtrl.fOptsLen)
	b, err = h.DevAddr.MarshalBinary()
	if err != nil {
		return []byte{}, err
	}
	out = append(out, b...)

	b, err = h.FCtrl.MarshalBinary()
	if err != nil {
		return []byte{}, err
	}
	out = append(out, b...)
	fCntBytes := make([]byte, 4)
	binary.LittleEndian.PutUint32(fCntBytes, h.FCnt)
	out = append(out, fCntBytes[0:2]...)
	out = append(out, opts...)

	return out, nil
}

// UnmarshalBinary decodes the object from binary form.
func (h *FHDR) UnmarshalBinary(uplink bool, data []byte) error {
	if len(data) < 7 {
		return errors.New("lorawan: at least 7 bytes are expected")
	}

	if err := h.DevAddr.UnmarshalBinary(data[0:4]); err != nil {
		return err
	}
	if err := h.FCtrl.UnmarshalBinary(data[4:5]); err != nil {
		return err
	}
	fCntBytes := make([]byte, 4)
	copy(fCntBytes, data[5:7])
	h.FCnt = binary.LittleEndian.Uint32(fCntBytes)

	if len(data) > 7 {
		h.FOpts = []Payload{
			&DataPayload{Bytes: data[7:]},
		}
	}

	return nil
}
<commit_msg>Simplify DevAddr.NetIDType. (#43)<commit_after>package lorawan

import (
	"encoding/binary"
	"encoding/hex"
	"errors"
	"fmt"
)

// DevAddr represents the device address.
type DevAddr [4]byte

// NetIDType returns the NetID type of the DevAddr.
func (a DevAddr) NetIDType() int {
	for i := 7; i >= 0; i-- {
		if a[0]&(1<<byte(i)) == 0 {
			return 7 - i
		}
	}
	panic("NetIDType bug!")
}

// NwkID returns the NwkID bits of the DevAddr.
func (a DevAddr) NwkID() []byte {
	switch a.NetIDType() {
	case 0:
		return a.getNwkID(1, 6)
	case 1:
		return a.getNwkID(2, 6)
	case 2:
		return a.getNwkID(3, 9)
	case 3:
		return a.getNwkID(4, 11)
	case 4:
		return a.getNwkID(5, 12)
	case 5:
		return a.getNwkID(6, 13)
	case 6:
		return a.getNwkID(7, 15)
	case 7:
		return a.getNwkID(8, 17)
	default:
		return nil
	}
}

// SetAddrPrefix sets the NetID based AddrPrefix.
func (a *DevAddr) SetAddrPrefix(netID NetID) {
	switch netID.Type() {
	case 0:
		a.setAddrPrefix(1, 6, netID)
	case 1:
		a.setAddrPrefix(2, 6, netID)
	case 2:
		a.setAddrPrefix(3, 9, netID)
	case 3:
		a.setAddrPrefix(4, 11, netID)
	case 4:
		a.setAddrPrefix(5, 12, netID)
	case 5:
		a.setAddrPrefix(6, 13, netID)
	case 6:
		a.setAddrPrefix(7, 15, netID)
	case 7:
		a.setAddrPrefix(8, 17, netID)
	}
}

// IsNetID returns a bool indicating if the NwkID matches the given NetID.
func (a DevAddr) IsNetID(netID NetID) bool {
	tempDevAddr := a
	tempDevAddr.SetAddrPrefix(netID)

	if a == tempDevAddr {
		return true
	}

	return false
}

func (a *DevAddr) setAddrPrefix(prefixLength, nwkIDBits int, netID NetID) {
	// convert DevAddr to uint32
	devAddr := binary.BigEndian.Uint32(a[:])

	// clear the bits for the prefix and NwkID
	var mask uint32
	mask-- // sets all uint32 bits to 1
	devAddr &^= mask << uint32(32-prefixLength-nwkIDBits)

	// set the type prefix
	prefix := uint32(254) << uint32(32-prefixLength)
	devAddr |= prefix

	// set the nwkID
	nwkIDBytes := make([]byte, 4)
	id := netID.ID()
	copy(nwkIDBytes[len(nwkIDBytes)-len(id):], id)

	nwkID := binary.BigEndian.Uint32(nwkIDBytes)
	nwkID = nwkID << uint32(32-nwkIDBits) // truncate the MSB of the NetID ID field
	nwkID = nwkID >> uint32(prefixLength) // shift back for the prefix MSB
	devAddr |= nwkID

	binary.BigEndian.PutUint32(a[:], devAddr)
}

func (a DevAddr) getNwkID(prefixLength, nwkIDBits int) []byte {
	// convert DevAddr to uint32
	temp := binary.BigEndian.Uint32(a[:])

	// clear prefix
	temp = temp << uint32(prefixLength)

	// shift to starting of NwkID
	temp = temp >> (32 - uint32(nwkIDBits))

	// back to bytes
	out := make([]byte, 4)
	binary.BigEndian.PutUint32(out, temp)

	bLen := nwkIDBits / 8
	if nwkIDBits%8 != 0 {
		bLen++
	}

	return out[len(out)-bLen:]
}

// MarshalBinary marshals the object in binary form.
func (a DevAddr) MarshalBinary() ([]byte, error) {
	out := make([]byte, len(a))
	for i, v := range a {
		// little endian
		out[len(a)-i-1] = v
	}
	return out, nil
}

// UnmarshalBinary decodes the object from binary form.
func (a *DevAddr) UnmarshalBinary(data []byte) error {
	if len(data) != len(a) {
		return fmt.Errorf("lorawan: %d bytes of data are expected", len(a))
	}
	for i, v := range data {
		// little endian
		a[len(a)-i-1] = v
	}
	return nil
}

// MarshalText implements encoding.TextMarshaler.
func (a DevAddr) MarshalText() ([]byte, error) {
	return []byte(a.String()), nil
}

// UnmarshalText implements encoding.TextUnmarshaler.
func (a *DevAddr) UnmarshalText(text []byte) error {
	b, err := hex.DecodeString(string(text))
	if err != nil {
		return err
	}

	if len(b) != len(a) {
		return fmt.Errorf("lorawan: exactly %d bytes are expected", len(a))
	}
	copy(a[:], b)
	return nil
}

// String implements fmt.Stringer.
func (a DevAddr) String() string {
	return hex.EncodeToString(a[:])
}

// Scan implements sql.Scanner.
func (a *DevAddr) Scan(src interface{}) error {
	b, ok := src.([]byte)
	if !ok {
		return errors.New("lorawan: []byte type expected")
	}
	if len(b) != len(a) {
		return fmt.Errorf("lorawan []byte must have length %d", len(a))
	}
	copy(a[:], b)
	return nil
}

// FCtrl represents the FCtrl (frame control) field.
// Please note that the FPending and ClassB are mapped to the same bit. This
// means that when unmarshaling from a byte-slice, both fields will contain
// the same value (either true or false).
type FCtrl struct {
	ADR       bool  `json:"adr"`
	ADRACKReq bool  `json:"adrAckReq"`
	ACK       bool  `json:"ack"`
	FPending  bool  `json:"fPending"` // only used for downlink messages
	ClassB    bool  `json:"classB"`   // only used for uplink messages
	fOptsLen  uint8 // will be set automatically by the FHDR when serialized to []byte
}

// MarshalBinary marshals the object in binary form.
func (c FCtrl) MarshalBinary() ([]byte, error) {
	if c.fOptsLen > 15 {
		return []byte{}, errors.New("lorawan: max value of FOptsLen is 15")
	}
	b := byte(c.fOptsLen)
	if c.FPending || c.ClassB {
		b = b ^ (1 << 4)
	}
	if c.ACK {
		b = b ^ (1 << 5)
	}
	if c.ADRACKReq {
		b = b ^ (1 << 6)
	}
	if c.ADR {
		b = b ^ (1 << 7)
	}
	return []byte{b}, nil
}

// UnmarshalBinary decodes the object from binary form.
func (c *FCtrl) UnmarshalBinary(data []byte) error {
	if len(data) != 1 {
		return errors.New("lorawan: 1 byte of data is expected")
	}
	c.fOptsLen = data[0] & ((1 << 3) ^ (1 << 2) ^ (1 << 1) ^ (1 << 0))
	c.FPending = data[0]&(1<<4) != 0
	c.ClassB = data[0]&(1<<4) != 0
	c.ACK = data[0]&(1<<5) != 0
	c.ADRACKReq = data[0]&(1<<6) != 0
	c.ADR = data[0]&(1<<7) != 0
	return nil
}

// FHDR represents the frame header.
type FHDR struct {
	DevAddr DevAddr   `json:"devAddr"`
	FCtrl   FCtrl     `json:"fCtrl"`
	FCnt    uint32    `json:"fCnt"`  // only the least-significant 16 bits will be marshalled
	FOpts   []Payload `json:"fOpts"` // max. number of allowed bytes is 15
}

// MarshalBinary marshals the object in binary form.
func (h FHDR) MarshalBinary() ([]byte, error) {
	var b []byte
	var err error
	var opts []byte

	for _, mac := range h.FOpts {
		b, err = mac.MarshalBinary()
		if err != nil {
			return []byte{}, err
		}
		opts = append(opts, b...)
	}
	h.FCtrl.fOptsLen = uint8(len(opts))
	if h.FCtrl.fOptsLen > 15 {
		return []byte{}, errors.New("lorawan: max number of FOpts bytes is 15")
	}

	out := make([]byte, 0, 7+h.FCtrl.fOptsLen)
	b, err = h.DevAddr.MarshalBinary()
	if err != nil {
		return []byte{}, err
	}
	out = append(out, b...)

	b, err = h.FCtrl.MarshalBinary()
	if err != nil {
		return []byte{}, err
	}
	out = append(out, b...)
	fCntBytes := make([]byte, 4)
	binary.LittleEndian.PutUint32(fCntBytes, h.FCnt)
	out = append(out, fCntBytes[0:2]...)
	out = append(out, opts...)

	return out, nil
}

// UnmarshalBinary decodes the object from binary form.
func (h *FHDR) UnmarshalBinary(uplink bool, data []byte) error {
	if len(data) < 7 {
		return errors.New("lorawan: at least 7 bytes are expected")
	}

	if err := h.DevAddr.UnmarshalBinary(data[0:4]); err != nil {
		return err
	}
	if err := h.FCtrl.UnmarshalBinary(data[4:5]); err != nil {
		return err
	}
	fCntBytes := make([]byte, 4)
	copy(fCntBytes, data[5:7])
	h.FCnt = binary.LittleEndian.Uint32(fCntBytes)

	if len(data) > 7 {
		h.FOpts = []Payload{
			&DataPayload{Bytes: data[7:]},
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package instructions

import "jvmgo/rtda"

//type Ref *rtda.Obj

// Load reference from array
type aaload struct {NoOperandsInstruction}
func (self *aaload) execute(thread *rtda.Thread) {
    stack, arrRef, index := popArrAndIndex(thread)
    refArr := arrRef.Fields().([]*rtda.Obj)
    ref := refArr[checkIndex(index, len(refArr))]
    stack.PushRef(ref)
}

// Load byte or boolean from array
type baload struct {NoOperandsInstruction}
func (self *baload) execute(thread *rtda.Thread) {
    stack, arrRef, index := popArrAndIndex(thread)
    byteArr := arrRef.Fields().([]int8)
    val := byteArr[checkIndex(index, len(byteArr))]
    stack.PushInt(int32(val))
}

// Load char from array
type caload struct {NoOperandsInstruction}
func (self *caload) execute(thread *rtda.Thread) {
    stack, arrRef, index := popArrAndIndex(thread)
    charArr := arrRef.Fields().([]uint16)
    val := charArr[checkIndex(index, len(charArr))]
    stack.PushInt(int32(val))
}

// Load double from array
type daload struct {NoOperandsInstruction}
func (self *daload) execute(thread *rtda.Thread) {
    stack, arrRef, index := popArrAndIndex(thread)
    doubleArr := arrRef.Fields().([]float64)
    val := doubleArr[checkIndex(index, len(doubleArr))]
    stack.PushDouble(val)
}

// Load float from array
type faload struct {NoOperandsInstruction}
func (self *faload) execute(thread *rtda.Thread) {
    stack, arrRef, index := popArrAndIndex(thread)
    floatArr := arrRef.Fields().([]float32)
    val := floatArr[checkIndex(index, len(floatArr))]
    stack.PushFloat(val)
}

// Load int from array
type iaload struct {NoOperandsInstruction}
func (self *iaload) execute(thread *rtda.Thread) {
    // todo
}

// Load long from array
type laload struct {NoOperandsInstruction}
func (self *laload) execute(thread *rtda.Thread) {
    // todo
}

// Load short from array
type saload struct {NoOperandsInstruction}
func (self *saload) execute(thread *rtda.Thread) {
    // todo
}

func popArrAndIndex(thread *rtda.Thread) (*rtda.OperandStack, *rtda.Obj, int) {
    stack := thread.CurrentFrame().OperandStack()
    arrRef := stack.PopRef()
    index := int(stack.PopInt())
    if arrRef == nil {
        // todo
        panic("NullPointerException")
    }
    return stack, arrRef, index
}

func checkIndex(index, len int) (int) {
    if index < 0 || index >= len {
        panic("ArrayIndexOutOfBoundsException")
    }
    return index
}
<commit_msg>iaload<commit_after>package instructions

import "jvmgo/rtda"

//type Ref *rtda.Obj

// Load reference from array
type aaload struct {NoOperandsInstruction}
func (self *aaload) execute(thread *rtda.Thread) {
    stack, arrRef, index := popArrAndIndex(thread)
    refArr := arrRef.Fields().([]*rtda.Obj)
    ref := refArr[checkIndex(index, len(refArr))]
    stack.PushRef(ref)
}

// Load byte or boolean from array
type baload struct {NoOperandsInstruction}
func (self *baload) execute(thread *rtda.Thread) {
    stack, arrRef, index := popArrAndIndex(thread)
    byteArr := arrRef.Fields().([]int8)
    val := byteArr[checkIndex(index, len(byteArr))]
    stack.PushInt(int32(val))
}

// Load char from array
type caload struct {NoOperandsInstruction}
func (self *caload) execute(thread *rtda.Thread) {
    stack, arrRef, index := popArrAndIndex(thread)
    charArr := arrRef.Fields().([]uint16)
    val := charArr[checkIndex(index, len(charArr))]
    stack.PushInt(int32(val))
}

// Load double from array
type daload struct {NoOperandsInstruction}
func (self *daload) execute(thread *rtda.Thread) {
    stack, arrRef, index := popArrAndIndex(thread)
    doubleArr := arrRef.Fields().([]float64)
    val := doubleArr[checkIndex(index, len(doubleArr))]
    stack.PushDouble(val)
}

// Load float from array
type faload struct {NoOperandsInstruction}
func (self *faload) execute(thread *rtda.Thread) {
    stack, arrRef, index := popArrAndIndex(thread)
    floatArr := arrRef.Fields().([]float32)
    val := floatArr[checkIndex(index, len(floatArr))]
    stack.PushFloat(val)
}

// Load int from array
type iaload struct {NoOperandsInstruction}
func (self *iaload) execute(thread *rtda.Thread) {
    stack, arrRef, index := popArrAndIndex(thread)
    intArr := arrRef.Fields().([]int32)
    val := intArr[checkIndex(index, len(intArr))]
    stack.PushInt(val)
}

// Load long from array
type laload struct {NoOperandsInstruction}
func (self *laload) execute(thread *rtda.Thread) {
    // todo
}

// Load short from array
type saload struct {NoOperandsInstruction}
func (self *saload) execute(thread *rtda.Thread) {
    // todo
}

func popArrAndIndex(thread *rtda.Thread) (*rtda.OperandStack, *rtda.Obj, int) {
    stack := thread.CurrentFrame().OperandStack()
    arrRef := stack.PopRef()
    index := int(stack.PopInt())
    if arrRef == nil {
        // todo
        panic("NullPointerException")
    }
    return stack, arrRef, index
}

func checkIndex(index, len int) (int) {
    if index < 0 || index >= len {
        panic("ArrayIndexOutOfBoundsException")
    }
    return index
}
<|endoftext|>


<commit_before>package tlcore

import (
	"encoding/binary"
	"os"
	"testing"
)
import "bytes"

/*
This file contains all core testing functions.

*/

const numChunks = 8

//Test a simple put & get
func TestSimple(t *testing.T) {
	m := NewMap("testdb/", numChunks)
	defer os.RemoveAll("testdb/")
	defer m.Close()

	m.Set([]byte("k1"), []byte("v1"))
	rval, _ := m.Get([]byte("k1"))
	if !bytes.Equal([]byte("v1"), rval) {
		t.Fatal("Error: value mismatch")
	}
}

//Test a simple put & get (after a map close())
func TestSimpleRestore(t *testing.T) {
	defer os.RemoveAll("testdb/")
	{
		m := NewMap("testdb/", numChunks)
		m.Set([]byte("k1"), []byte("v1"))
		m.Close()
	}
	{
		m := OpenMap("testdb/")
		rval, _ := m.Get([]byte("k1"))
		if !bytes.Equal([]byte("v1"), rval) {
			t.Fatal("Error: value mismatch")
		}
		m.Close()
	}
}

//Test lots of simple put & get before and after closing the map
func TestSimpleLots(t *testing.T) {
	defer os.RemoveAll("testdb/")
	k := make([]byte, 4)
	v := make([]byte, 4)
	{
		m1 := NewMap("testdb/", numChunks)
		for i := 0; i < 128*1024; i++ {
			binary.LittleEndian.PutUint32(k, uint32(i))
			binary.LittleEndian.PutUint32(v, uint32(i))
			m1.Set(k, v)
		}
		for i := 0; i < 128*1024; i++ {
			binary.LittleEndian.PutUint32(k, uint32(i))
			binary.LittleEndian.PutUint32(v, uint32(i))
			rval, _ := m1.Get(k)
			if !bytes.Equal(v, rval) {
				t.Fatal("Error 1: value mismatch")
			}
		}
		m1.Close()
	}
	{
		m2 := OpenMap("testdb/")
		for i := 0; i < 128*1024; i++ {
			binary.LittleEndian.PutUint32(k, uint32(i))
			binary.LittleEndian.PutUint32(v, uint32(i))
			rval, _ := m2.Get(k)
			if !bytes.Equal(v, rval) {
				t.Fatal("Error 2: value mismatch")
			}
		}
		m2.Close()
	}
}

/*
//Test lots of simple put & get, in a parallel way, test multi thread safety
func TestParSimpleLots(t *testing.T) {
	defer os.RemoveAll("testdb/")
	defer os.Chdir("../")
	k := make([]byte, 4)
	v := make([]byte, 4)
	{
		db := Create("testdb")
		m1, _ := db.AllocMap("mapa1")

		for tid := 0; tid < 27; tid++ {
			for i := 0; i < 1024; i++ {
				binary.LittleEndian.PutUint32(k, uint32(i*27+tid))
				binary.LittleEndian.PutUint32(v, uint32(i*27+tid))
				m1.Put(k, v)
			}
		}

		for i := 0; i < 27*1024; i++ {
			binary.LittleEndian.PutUint32(k, uint32(i))
			binary.LittleEndian.PutUint32(v, uint32(i))
			rval, _ := m1.Get(k)
			if !bytes.Equal(v, rval) {
				t.Fatal("Err 1: mismatch")
			}
		}

		db.Close()
	}
	{
		db := Open("testdb")
		m1 := db.mapsByName["mapa1"]
		for i := 0; i < 27*1024; i++ {
			binary.LittleEndian.PutUint32(k, uint32(i))
			binary.LittleEndian.PutUint32(v, uint32(i))
			rval, _ := m1.Get(k)
			if !bytes.Equal(v, rval) {
				t.Fatal("Err 2: mismatch")
			}
		}
		db.Close()
	}
}

//Test simple set
//Test simple del

//Test complex get, put, set, del mix

//Common functions test
func TestCmplx1(t *testing.T) {
	coreTest(100000, 11, 129, 64)
}

//Low key size: test delete operation
func TestCmplx2(t *testing.T) {
	coreTest(100000, 2, 129, 64)
}

//Large key size
func TestCmplx3(t *testing.T) {
	coreTest(10000, 130, 129, 64)
}

//Large value size
func TestCmplx4(t *testing.T) {
	coreTest(10000, 11, 555, 64)
}

//Test low value size
func TestCmplx5(t *testing.T) {
	coreTest(10000, 11, 2, 64)
}

func operate() {

}
func goOperate() {

}
func dbOperate() {

}
func checkDB() {

}

func coreTest(numOperations, maxKeySize, maxValueSize, threads int) {
	//Operate on built-in map

	goMap := make(map[string][]byte)
	var goDeletes []([]byte)
	for core := 0; core < threads; core++ {
		r := rand.New(rand.NewSource(int64(core)))
		base := make([]byte, 4)
		base2 := make([]byte, 4)
		for i := 0; i < numOperations; i++ {
			opType := 1 + r.Intn(3)
			opKeySize := r.Intn(maxKeySize-1) + 1
			opValueSize := r.Intn(maxValueSize-1) + 1
			binary.LittleEndian.PutUint32(base, uint32(r.Int31()*64)+uint32(core))
			binary.LittleEndian.PutUint32(base2, uint32(i*64+core))
			key := bytes.Repeat([]byte(base), opKeySize)
			value := bytes.Repeat([]byte(base), opValueSize)
			//fmt.Println("gomap", opType, key, value)
			switch opType {
			case OpPut:
				if _, ok := goMap[string(key)]; !ok {
					goMap[string(key)] = value
				}
			case OpDel:
				if _, ok := goMap[string(key)]; ok {
					delete(goMap, string(key))
					goDeletes = append(goDeletes, key)
				}
			case OpSet:
				if _, ok := goMap[string(key)]; ok {
					goMap[string(key)] = value
				}
			}
		}
	}
	//Operate on DB
	db := Create("testdb2")
	defer os.RemoveAll("testdb2/")
	defer os.Chdir("../")

	m1, _ := db.AllocMap("mapa1")

	var w sync.WaitGroup
	w.Add(threads)
	for core := 0; core < threads; core++ {
		go func(core int) {
			r := rand.New(rand.NewSource(int64(core)))
			base := make([]byte, 4)
			base2 := make([]byte, 4)
			for i := 0; i < numOperations; i++ {
				opType := 1 + r.Intn(3)
				opKeySize := r.Intn(maxKeySize-1) + 1
				opValueSize := r.Intn(maxValueSize-1) + 1
				binary.LittleEndian.PutUint32(base, uint32(r.Int31()*64)+uint32(core))
				binary.LittleEndian.PutUint32(base2, uint32(i*64+core))
				key := bytes.Repeat([]byte(base), opKeySize)[0:opKeySize]
				value := bytes.Repeat([]byte(base2), opValueSize)[0:opValueSize]
				//fmt.Println("db   ", opType, key, value)
				switch opType {
				case OpPut:
					m1.Put(key, value)
				case OpDel:
					m1.Delete(key)
				case OpSet:
					m1.Set(key, value)
				}
			}
			w.Done()
		}(core)
	}
	w.Wait()
	//Check map is in DB
	for key, value := range goMap {
		rval, err := m1.Get([]byte(key))
		//fmt.Println([]byte(key), value)
		if err != nil {
			panic(err)
		}
		if !bytes.Equal(rval, value) {
			panic(1)
		}
	}

	//Check deleteds aren't in DB
	fmt.Println("Tested deletes:", len(goDeletes))
	for i := 0; i < len(goDeletes); i++ {
		key := goDeletes[i]
		_, err := m1.Get([]byte(key))
		if err == nil {
			panic(2)
		}
	}
	//Close DB
	db.Close()

	{
		//Restore DB
		db := Open("testdb2")
		m1 := db.mapsByName["mapa1"]
		//Check again
		//Check map is in DB
		for key, value := range goMap {
			rval, err := m1.Get([]byte(key))
			//fmt.Println([]byte(key), value)
			if err != nil {
				panic(err)
			}
			if !bytes.Equal(rval, value) {
				panic(1)
			}
		}

		//Check deleteds aren't in DB
		fmt.Println("Tested deletes:", len(goDeletes))
		for i := 0; i < len(goDeletes); i++ {
			key := goDeletes[i]
			_, err := m1.Get([]byte(key))
			if err == nil {
				panic(2)
			}
		}
	}
}

//Test parallel complex get, put, set, del mix

//Tests operational limits: size

//Test sync/nosync file

//Bench with diferents sizes

//Bench lots of gets
func BenchmarkGet(b *testing.B) {
	defer os.RemoveAll("benchdb/")
	defer os.Chdir("../")
	if testing.Verbose() {
		fmt.Println("\tInserting", b.N, "keys...")
	}
	db := Create("benchdb/")
	m, _ := db.AllocMap("mapA")
	key := make([]byte, 4)
	lenValue := 100
	value := bytes.Repeat([]byte("X"), lenValue)
	for i := 0; i < b.N/32+1; i++ {
		binary.LittleEndian.PutUint32(key, uint32(3*i))
		binary.LittleEndian.PutUint32(value, uint32(3*i))
		err := m.Put(key, value)
		if err != nil {
			panic(err)
		}
	}
	gid := uint64(0)
	fmt.Println("get...")
	b.ResetTimer()
	b.RunParallel(func(pb *testing.PB) {
		sum := 0
		key := make([]byte, 4)
		id := uint32(atomic.AddUint64(&gid, 1))
		fmt.Println(id)
		r := rand.New(rand.NewSource(int64(id)))
		for i := 0; pb.Next(); i++ {
			binary.LittleEndian.PutUint32(key, uint32(3*r.Intn(b.N/32+1)))
			v, err := m.Get(key)
			sum += int(v[len(v)-1])
			if err != nil || !bytes.Equal(v, v) {
				b.Fatal("Key not present", key, id, i, v, sum)
			}
		}
	})
	b.StopTimer()
	db.Close()
}

//Bench lots of gets, in a parallel way

//Bench lots of puts

//Bench lots of puts, in a parallel way
*/
<commit_msg>core - TestParSimpleLots recuperado<commit_after>package tlcore

import (
	"encoding/binary"
	"os"
	"sync"
	"testing"
)
import "bytes"

/*
This file contains all core testing functions.

*/

const numChunks = 8

//Test a simple put & get
func TestSimple(t *testing.T) {
	m := NewMap("testdb/", numChunks)
	defer os.RemoveAll("testdb/")
	defer m.Close()

	m.Set([]byte("k1"), []byte("v1"))
	rval, _ := m.Get([]byte("k1"))
	if !bytes.Equal([]byte("v1"), rval) {
		t.Fatal("Error: value mismatch")
	}
}

//Test a simple put & get (after a map close())
func TestSimpleRestore(t *testing.T) {
	defer os.RemoveAll("testdb/")
	{
		m := NewMap("testdb/", numChunks)
		m.Set([]byte("k1"), []byte("v1"))
		m.Close()
	}
	{
		m := OpenMap("testdb/")
		rval, _ := m.Get([]byte("k1"))
		if !bytes.Equal([]byte("v1"), rval) {
			t.Fatal("Error: value mismatch")
		}
		m.Close()
	}
}

//Test lots of simple put & get before and after closing the map
func TestSimpleLots(t *testing.T) {
	defer os.RemoveAll("testdb/")
	k := make([]byte, 4)
	v := make([]byte, 4)
	{
		m1 := NewMap("testdb/", numChunks)
		for i := 0; i < 128*1024; i++ {
			binary.LittleEndian.PutUint32(k, uint32(i))
			binary.LittleEndian.PutUint32(v, uint32(i))
			m1.Set(k, v)
		}
		for i := 0; i < 128*1024; i++ {
			binary.LittleEndian.PutUint32(k, uint32(i))
			binary.LittleEndian.PutUint32(v, uint32(i))
			rval, _ := m1.Get(k)
			if !bytes.Equal(v, rval) {
				t.Fatal("Error 1: value mismatch")
			}
		}
		m1.Close()
	}
	{
		m2 := OpenMap("testdb/")
		for i := 0; i < 128*1024; i++ {
			binary.LittleEndian.PutUint32(k, uint32(i))
			binary.LittleEndian.PutUint32(v, uint32(i))
			rval, _ := m2.Get(k)
			if !bytes.Equal(v, rval) {
				t.Fatal("Error 2: value mismatch")
			}
		}
		m2.Close()
	}
}

//Test lots of simple put & get, in a parallel way, test multi thread safety
func TestParSimpleLots(t *testing.T) {
	defer os.RemoveAll("testdb/")
	m1 := NewMap("testdb/", numChunks)
	var w sync.WaitGroup
	w.Add(27)
	for tid := 0; tid < 27; tid++ {
		go func(tid int) {
			k := make([]byte, 4)
			v := make([]byte, 4)
			for i := 0; i < 1024; i++ {
				binary.LittleEndian.PutUint32(k, uint32(i*27+tid))
				binary.LittleEndian.PutUint32(v, uint32(i*27+tid))
				m1.Set(k, v)
			}
			w.Done()
		}(tid)
	}
	w.Wait()

	k := make([]byte, 4)
	v := make([]byte, 4)
	for i := 0; i < 27*1024; i++ {
		binary.LittleEndian.PutUint32(k, uint32(i))
		binary.LittleEndian.PutUint32(v, uint32(i))
		rval, _ := m1.Get(k)
		if !bytes.Equal(v, rval) {
			t.Fatal("Error 1: value mismatch")
		}
	}

	m1.Close()
}

//Test lots of simple put & get, in a parallel way, test multi thread safety, after a map close
func TestParSimpleLotsRestore(t *testing.T) {
	defer os.RemoveAll("testdb/")
	{
		m1 := NewMap("testdb/", numChunks)
		var w sync.WaitGroup
		w.Add(27)
		for tid := 0; tid < 27; tid++ {
			go func(tid int) {
				k := make([]byte, 4)
				v := make([]byte, 4)
				for i := 0; i < 1024; i++ {
					binary.LittleEndian.PutUint32(k, uint32(i*27+tid))
					binary.LittleEndian.PutUint32(v, uint32(i*27+tid))
					m1.Set(k, v)
				}
				w.Done()
			}(tid)
		}
		w.Wait()
		m1.Close()
	}
	{
		m2 := OpenMap("testdb/")
		k := make([]byte, 4)
		v := make([]byte, 4)
		for i := 0; i < 27*1024; i++ {
			binary.LittleEndian.PutUint32(k, uint32(i))
			binary.LittleEndian.PutUint32(v, uint32(i))
			rval, _ := m2.Get(k)
			if !bytes.Equal(v, rval) {
				t.Fatal("Error 2: value mismatch")
			}
		}
		m2.Close()
	}
}

/*
//Test simple set
//Test simple del

//Test complex get, put, set, del mix

//Common functions test
func TestCmplx1(t *testing.T) {
	coreTest(100000, 11, 129, 64)
}

//Low key size: test delete operation
func TestCmplx2(t *testing.T) {
	coreTest(100000, 2, 129, 64)
}

//Large key size
func TestCmplx3(t *testing.T) {
	coreTest(10000, 130, 129, 64)
}

//Large value size
func TestCmplx4(t *testing.T) {
	coreTest(10000, 11, 555, 64)
}

//Test low value size
func TestCmplx5(t *testing.T) {
	coreTest(10000, 11, 2, 64)
}

func operate() {

}
func goOperate() {

}
func dbOperate() {

}
func checkDB() {

}

func coreTest(numOperations, maxKeySize, maxValueSize, threads int) {
	//Operate on built-in map

	goMap := make(map[string][]byte)
	var goDeletes []([]byte)
	for core := 0; core < threads; core++ {
		r := rand.New(rand.NewSource(int64(core)))
		base := make([]byte, 4)
		base2 := make([]byte, 4)
		for i := 0; i < numOperations; i++ {
			opType := 1 + r.Intn(3)
			opKeySize := r.Intn(maxKeySize-1) + 1
			opValueSize := r.Intn(maxValueSize-1) + 1
			binary.LittleEndian.PutUint32(base, uint32(r.Int31()*64)+uint32(core))
			binary.LittleEndian.PutUint32(base2, uint32(i*64+core))
			key := bytes.Repeat([]byte(base), opKeySize)
			value := bytes.Repeat([]byte(base), opValueSize)
			//fmt.Println("gomap", opType, key, value)
			switch opType {
			case OpPut:
				if _, ok := goMap[string(key)]; !ok {
					goMap[string(key)] = value
				}
			case OpDel:
				if _, ok := goMap[string(key)]; ok {
					delete(goMap, string(key))
					goDeletes = append(goDeletes, key)
				}
			case OpSet:
				if _, ok := goMap[string(key)]; ok {
					goMap[string(key)] = value
				}
			}
		}
	}
	//Operate on DB
	db := Create("testdb2")
	defer os.RemoveAll("testdb2/")
	defer os.Chdir("../")

	m1, _ := db.AllocMap("mapa1")

	var w sync.WaitGroup
	w.Add(threads)
	for core := 0; core < threads; core++ {
		go func(core int) {
			r := rand.New(rand.NewSource(int64(core)))
			base := make([]byte, 4)
			base2 := make([]byte, 4)
			for i := 0; i < numOperations; i++ {
				opType := 1 + r.Intn(3)
				opKeySize := r.Intn(maxKeySize-1) + 1
				opValueSize := r.Intn(maxValueSize-1) + 1
				binary.LittleEndian.PutUint32(base, uint32(r.Int31()*64)+uint32(core))
				binary.LittleEndian.PutUint32(base2, uint32(i*64+core))
				key := bytes.Repeat([]byte(base), opKeySize)[0:opKeySize]
				value := bytes.Repeat([]byte(base2), opValueSize)[0:opValueSize]
				//fmt.Println("db   ", opType, key, value)
				switch opType {
				case OpPut:
					m1.Put(key, value)
				case OpDel:
					m1.Delete(key)
				case OpSet:
					m1.Set(key, value)
				}
			}
			w.Done()
		}(core)
	}
	w.Wait()
	//Check map is in DB
	for key, value := range goMap {
		rval, err := m1.Get([]byte(key))
		//fmt.Println([]byte(key), value)
		if err != nil {
			panic(err)
		}
		if !bytes.Equal(rval, value) {
			panic(1)
		}
	}

	//Check deleteds aren't in DB
	fmt.Println("Tested deletes:", len(goDeletes))
	for i := 0; i < len(goDeletes); i++ {
		key := goDeletes[i]
		_, err := m1.Get([]byte(key))
		if err == nil {
			panic(2)
		}
	}
	//Close DB
	db.Close()

	{
		//Restore DB
		db := Open("testdb2")
		m1 := db.mapsByName["mapa1"]
		//Check again
		//Check map is in DB
		for key, value := range goMap {
			rval, err := m1.Get([]byte(key))
			//fmt.Println([]byte(key), value)
			if err != nil {
				panic(err)
			}
			if !bytes.Equal(rval, value) {
				panic(1)
			}
		}

		//Check deleteds aren't in DB
		fmt.Println("Tested deletes:", len(goDeletes))
		for i := 0; i < len(goDeletes); i++ {
			key := goDeletes[i]
			_, err := m1.Get([]byte(key))
			if err == nil {
				panic(2)
			}
		}
	}
}

//Test parallel complex get, put, set, del mix

//Tests operational limits: size

//Test sync/nosync file

//Bench with diferents sizes

//Bench lots of gets
func BenchmarkGet(b *testing.B) {
	defer os.RemoveAll("benchdb/")
	defer os.Chdir("../")
	if testing.Verbose() {
		fmt.Println("\tInserting", b.N, "keys...")
	}
	db := Create("benchdb/")
	m, _ := db.AllocMap("mapA")
	key := make([]byte, 4)
	lenValue := 100
	value := bytes.Repeat([]byte("X"), lenValue)
	for i := 0; i < b.N/32+1; i++ {
		binary.LittleEndian.PutUint32(key, uint32(3*i))
		binary.LittleEndian.PutUint32(value, uint32(3*i))
		err := m.Put(key, value)
		if err != nil {
			panic(err)
		}
	}
	gid := uint64(0)
	fmt.Println("get...")
	b.ResetTimer()
	b.RunParallel(func(pb *testing.PB) {
		sum := 0
		key := make([]byte, 4)
		id := uint32(atomic.AddUint64(&gid, 1))
		fmt.Println(id)
		r := rand.New(rand.NewSource(int64(id)))
		for i := 0; pb.Next(); i++ {
			binary.LittleEndian.PutUint32(key, uint32(3*r.Intn(b.N/32+1)))
			v, err := m.Get(key)
			sum += int(v[len(v)-1])
			if err != nil || !bytes.Equal(v, v) {
				b.Fatal("Key not present", key, id, i, v, sum)
			}
		}
	})
	b.StopTimer()
	db.Close()
}

//Bench lots of gets, in a parallel way

//Bench lots of puts

//Bench lots of puts, in a parallel way
*/
<|endoftext|>


<commit_before>// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see <http://www.gnu.org/licenses/>.

package url

import (
	"errors"
	"github.com/nmeum/marvin/irc"
	"github.com/nmeum/marvin/modules"
	"html"
	"io/ioutil"
	"net/http"
	"net/url"
	"regexp"
)

const (
	urlRegex = `(http|https)\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(:[a-zA-Z0-9]*)?/?([a-zA-Z0-9\-\._\?\,\'/\\\+&%\$#\=~])*`
)

type Module struct {
	Exclude []string `json:"exclude"`
}

func Init(moduleSet *modules.ModuleSet) {
	moduleSet.Register(new(Module))
}

func (m *Module) Name() string {
	return "url"
}

func (m *Module) Help() string {
	return "Displays HTML titles for HTTP links."
}

func (m *Module) Defaults() {
	return
}

func (m *Module) Load(client *irc.Client) error {
	regex := regexp.MustCompile(urlRegex)
	client.CmdHook("privmsg", func(c *irc.Client, msg irc.Message) error {
		link := regex.FindString(msg.Data)
		if len(link) <= 0 {
			return nil
		}

		uri, err := url.Parse(link)
		if err != nil {
			return err
		}

		if err == nil && !m.isExcluded(uri.Host) {
			title, err := m.extractTitle(link)
			if err == nil {
				c.Write("NOTICE %s :Page title: %q", msg.Receiver, title)
			}
		}

		return nil
	})

	return nil
}

func (m *Module) isExcluded(host string) bool {
	for _, h := range m.Exclude {
		if host == h {
			return true
		}
	}

	return false
}

func (m *Module) extractTitle(uri string) (title string, err error) {
	resp, err := http.Get(uri)
	if err != nil {
		return
	}

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

	regex := regexp.MustCompile("<title>(.*)</title>")
	match := regex.FindStringSubmatch(string(body))

	if len(match) < 2 {
		err = errors.New("Couldn't extract title")
		return
	}

	title = html.UnescapeString(match[1])
	return
}
<commit_msg>url: Don't qoute page title<commit_after>// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see <http://www.gnu.org/licenses/>.

package url

import (
	"errors"
	"github.com/nmeum/marvin/irc"
	"github.com/nmeum/marvin/modules"
	"html"
	"io/ioutil"
	"net/http"
	"net/url"
	"regexp"
)

const (
	urlRegex = `(http|https)\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(:[a-zA-Z0-9]*)?/?([a-zA-Z0-9\-\._\?\,\'/\\\+&%\$#\=~])*`
)

type Module struct {
	Exclude []string `json:"exclude"`
}

func Init(moduleSet *modules.ModuleSet) {
	moduleSet.Register(new(Module))
}

func (m *Module) Name() string {
	return "url"
}

func (m *Module) Help() string {
	return "Displays HTML titles for HTTP links."
}

func (m *Module) Defaults() {
	return
}

func (m *Module) Load(client *irc.Client) error {
	regex := regexp.MustCompile(urlRegex)
	client.CmdHook("privmsg", func(c *irc.Client, msg irc.Message) error {
		link := regex.FindString(msg.Data)
		if len(link) <= 0 {
			return nil
		}

		uri, err := url.Parse(link)
		if err != nil {
			return err
		}

		if err == nil && !m.isExcluded(uri.Host) {
			title, err := m.extractTitle(link)
			if err == nil {
				c.Write("NOTICE %s :Page title: %s", msg.Receiver, title)
			}
		}

		return nil
	})

	return nil
}

func (m *Module) isExcluded(host string) bool {
	for _, h := range m.Exclude {
		if host == h {
			return true
		}
	}

	return false
}

func (m *Module) extractTitle(uri string) (title string, err error) {
	resp, err := http.Get(uri)
	if err != nil {
		return
	}

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

	regex := regexp.MustCompile("<title>(.*)</title>")
	match := regex.FindStringSubmatch(string(body))

	if len(match) < 2 {
		err = errors.New("Couldn't extract title")
		return
	}

	title = html.UnescapeString(match[1])
	return
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"errors"
	"fmt"
	"os"
	"unicode/utf8"
)

// isCreatable check if users has permission to create.
// If the file already exists, it will return error.
//
// NOTE: It actually creates the file then delete.
func isCreatable(f string) (bool, error) {
	// ensure the file does not exist.
	_, err := os.Stat(f)
	if err == nil {
		return false, fmt.Errorf("file should not exists: %v", f)
	}
	if !os.IsNotExist(err) {
		return false, err
	}
	// file creation checking.
	file, err := os.Create(f)
	if err != nil {
		if !os.IsPermission(err) {
			return false, err
		}
		return false, nil
	}
	if err := file.Close(); err != nil {
		return false, err
	}
	if err := os.Remove(f); err != nil {
		// TODO: better finalization for remove failure?
		return false, err
	}
	return true, nil
}

// isWritable checks whether f is writable file or not.
// If it couldn't open the file for check, it will return error.
func isWritable(f string) (bool, error) {
	file, err := os.OpenFile(f, os.O_WRONLY, 0666)
	if err != nil {
		if os.IsPermission(err) {
			return false, nil
		}
		return false, err
	}
	file.Close()
	return true, nil
}

// openOrCreate open f and return it's Text.
// When f doesn't exist and allow to create, it will create a new Text.
func openOrCreate(f string, allowCreate bool) (*Text, error) {
	if _, err := os.Stat(f); err != nil {
		if os.IsNotExist(err) {
			if allowCreate {
				return create(f)
			}
			return nil, errors.New("file not exist. please retry with -new flag.")
		}
		return nil, err
	}
	return open(f)
}

// create creates a new Text for f.
// When f is not creatable, it will return error.
func create(f string) (*Text, error) {
	writable, err := isCreatable(f)
	if err != nil {
		return nil, err
	}
	return &Text{lines: []Line{{""}}, tabToSpace: false, tabWidth: 4, writable: writable}, nil
}

// open reads a file and returns it as *Text.
// When the file is not exists, it will return error with nil *Text.
func open(f string) (*Text, error) {
	file, err := os.Open(f)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	writable, err := isWritable(f)
	if err != nil {
		return nil, err
	}

	// aggregate the text info.
	// tor uses tab (4 space) for indentation.
	// but when parse an exist file, follow the file's rule.
	lines := make([]Line, 0)
	tabToSpace := false
	tabWidth := 4

	findIndentLine := false
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		t := scanner.Text()
		if !findIndentLine {
			r, _ := utf8.DecodeRuneInString(t)
			if r == ' ' || r == '\t' {
				findIndentLine = true
				if r == ' ' {
					tabToSpace = true
					// calculate tab width
					tabWidth = 0
					remain := t
					for len(remain) != 0 {
						r, rlen := utf8.DecodeRuneInString(remain)
						remain = remain[rlen:]
						if r != ' ' {
							break
						}
						tabWidth++
					}
				}
			}
		}
		lines = append(lines, Line{t})
	}
	if err := scanner.Err(); err != nil {
		return nil, err
	}

	// `touch` cmd creates a file with no content.
	// avoid program panic from empty text.
	if len(lines) == 0 {
		lines = []Line{{""}}
	}

	return &Text{lines: lines, tabToSpace: tabToSpace, tabWidth: tabWidth, writable: writable}, nil
}

// save saves Text to a file.
func save(f string, t *Text) error {
	file, err := os.Create(f)
	if err != nil {
		return err
	}
	defer file.Close()
	for _, line := range t.lines {
		file.WriteString(line.data + "\n")
	}
	return nil
}
<commit_msg>don't start tor if the file is not creatable<commit_after>package main

import (
	"bufio"
	"errors"
	"fmt"
	"os"
	"unicode/utf8"
)

// isCreatable check if users has permission to create.
// If the file already exists, it will return error.
//
// NOTE: It actually creates the file then delete.
func isCreatable(f string) (bool, error) {
	// ensure the file does not exist.
	_, err := os.Stat(f)
	if err == nil {
		return false, fmt.Errorf("file should not exists: %v", f)
	}
	if !os.IsNotExist(err) {
		return false, err
	}
	// file creation checking.
	file, err := os.Create(f)
	if err != nil {
		if !os.IsPermission(err) {
			return false, err
		}
		return false, nil
	}
	if err := file.Close(); err != nil {
		return false, err
	}
	if err := os.Remove(f); err != nil {
		// TODO: better finalization for remove failure?
		return false, err
	}
	return true, nil
}

// isWritable checks whether f is writable file or not.
// If it couldn't open the file for check, it will return error.
func isWritable(f string) (bool, error) {
	file, err := os.OpenFile(f, os.O_WRONLY, 0666)
	if err != nil {
		if os.IsPermission(err) {
			return false, nil
		}
		return false, err
	}
	file.Close()
	return true, nil
}

// openOrCreate open f and return it's Text.
// When f doesn't exist and allow to create, it will create a new Text.
func openOrCreate(f string, allowCreate bool) (*Text, error) {
	if _, err := os.Stat(f); err != nil {
		if os.IsNotExist(err) {
			if allowCreate {
				return create(f)
			}
			return nil, errors.New("file not exist. please retry with -new flag.")
		}
		return nil, err
	}
	return open(f)
}

// create creates a new Text for f.
// When f is not creatable, it will return error.
func create(f string) (*Text, error) {
	writable, err := isCreatable(f)
	if err != nil {
		return nil, err
	}
	if !writable {
		return nil, errors.New("could not create the file. please check the directory permission.")
	}
	return &Text{lines: []Line{{""}}, tabToSpace: false, tabWidth: 4, writable: writable}, nil
}

// open reads a file and returns it as *Text.
// When the file is not exists, it will return error with nil *Text.
func open(f string) (*Text, error) {
	file, err := os.Open(f)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	writable, err := isWritable(f)
	if err != nil {
		return nil, err
	}

	// aggregate the text info.
	// tor uses tab (4 space) for indentation.
	// but when parse an exist file, follow the file's rule.
	lines := make([]Line, 0)
	tabToSpace := false
	tabWidth := 4

	findIndentLine := false
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		t := scanner.Text()
		if !findIndentLine {
			r, _ := utf8.DecodeRuneInString(t)
			if r == ' ' || r == '\t' {
				findIndentLine = true
				if r == ' ' {
					tabToSpace = true
					// calculate tab width
					tabWidth = 0
					remain := t
					for len(remain) != 0 {
						r, rlen := utf8.DecodeRuneInString(remain)
						remain = remain[rlen:]
						if r != ' ' {
							break
						}
						tabWidth++
					}
				}
			}
		}
		lines = append(lines, Line{t})
	}
	if err := scanner.Err(); err != nil {
		return nil, err
	}

	// `touch` cmd creates a file with no content.
	// avoid program panic from empty text.
	if len(lines) == 0 {
		lines = []Line{{""}}
	}

	return &Text{lines: lines, tabToSpace: tabToSpace, tabWidth: tabWidth, writable: writable}, nil
}

// save saves Text to a file.
func save(f string, t *Text) error {
	file, err := os.Create(f)
	if err != nil {
		return err
	}
	defer file.Close()
	for _, line := range t.lines {
		file.WriteString(line.data + "\n")
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2016 The go-vgo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// https://github.com/go-ego/ego/blob/master/LICENSE
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

package gt

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"strings"
)

func FileExist(filename string) bool {
	_, err := os.Stat(filename)
	return err == nil || os.IsExist(err)
}

func PathExists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return false, err
}

func CopyFile(src, dst string) (w int64, err error) {
	srcFile, err := os.Open(src)
	if err != nil {
		return
	}
	defer srcFile.Close()
	// if FileExist(dst) != true {
	if !FileExist(dst) {
		Wirtefile("", dst)
	}
	dstFile, err := os.Create(dst)
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	defer dstFile.Close()
	return io.Copy(dstFile, srcFile)
}

func CopyOFile(srcName, dstName string) (written int64, err error) {
	src, err := os.Open(srcName)
	if err != nil {
		return
	}
	defer src.Close()
	dst, err := os.OpenFile(dstName, os.O_WRONLY|os.O_CREATE, 0644)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer dst.Close()
	return io.Copy(dst, src)
}

func Readfile(fname string) (string, error) {
	userFile := fname
	fin, err := os.Open(userFile)
	defer fin.Close()
	if err != nil {
		fmt.Println(userFile, err)
		return "", err
	}
	var restr string = ""

	buf := make([]byte, 1024)
	for {
		n, _ := fin.Read(buf)
		if 0 == n {
			break
		}
		// os.Stdout.Write(buf[:n])

		strbuf := string(buf[:n])

		restr += strbuf
	}

	return restr, nil
}

func Wirtefile(wirtestr string, userFile string) {
	os.MkdirAll(path.Dir(userFile), os.ModePerm)

	fout, err := os.Create(userFile)
	defer fout.Close()
	if err != nil {
		fmt.Println(userFile, err)
		return
	}

	fout.WriteString(wirtestr)
}

func ListFile(dirPth string, suffix string) (files []string, err error) {
	files = make([]string, 0, 10)
	dir, err := ioutil.ReadDir(dirPth)
	if err != nil {
		return nil, err
	}
	PthSep := string(os.PathSeparator)
	suffix = strings.ToUpper(suffix)
	for _, fi := range dir {
		if fi.IsDir() {
			continue
		}
		if strings.HasSuffix(strings.ToUpper(fi.Name()), suffix) {
			files = append(files, dirPth+PthSep+fi.Name())
		}
	}
	return files, nil
}

func ListDir(dirPth string, suffix string) (files []string, err error) {
	files = make([]string, 0, 10)
	dir, err := ioutil.ReadDir(dirPth)
	if err != nil {
		return nil, err
	}
	PthSep := string(os.PathSeparator)
	suffix = strings.ToUpper(suffix)
	for _, fi := range dir {
		if !fi.IsDir() {
			continue
		}
		if strings.HasSuffix(strings.ToUpper(fi.Name()), suffix) {
			files = append(files, dirPth+PthSep+fi.Name())
		}
	}
	return files, nil
}

func WalkFile(dirPth, suffix string) (files []string, err error) {
	files = make([]string, 0, 30)
	suffix = strings.ToUpper(suffix)
	err = filepath.Walk(dirPth, func(filename string, fi os.FileInfo, err error) error {
		if fi.IsDir() {
			return nil
		}

		if strings.HasSuffix(strings.ToUpper(fi.Name()), suffix) {
			files = append(files, filename)
		}
		return nil
	})
	return files, err
}

func WalkDir(dirPth, suffix string) (files []string, err error) {
	files = make([]string, 0, 30)
	suffix = strings.ToUpper(suffix)
	err = filepath.Walk(dirPth, func(filename string, fi os.FileInfo, err error) error {

		if !fi.IsDir() {
			return nil
		}

		if strings.HasSuffix(strings.ToUpper(fi.Name()), suffix) {
			files = append(files, filename)
		}
		return nil
	})
	return files, err
}
<commit_msg>Add more func<commit_after>// Copyright 2016 The go-vgo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// https://github.com/go-ego/ego/blob/master/LICENSE
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

package gt

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"strings"
)

func FileExist(filename string) bool {
	_, err := os.Stat(filename)
	return err == nil || os.IsExist(err)
}

func PathExists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return false, err
}

// FileSize returns file size in bytes and possible error.
func FileSize(file string) (int64, error) {
	f, err := os.Stat(file)
	if err != nil {
		return 0, err
	}
	return f.Size(), nil
}

func Copy(src, dest string) error {
	// Gather file information to set back later.
	si, err := os.Lstat(src)
	if err != nil {
		return err
	}

	// Handle symbolic link.
	if si.Mode()&os.ModeSymlink != 0 {
		target, err := os.Readlink(src)
		if err != nil {
			return err
		}
		// NOTE: os.Chmod and os.Chtimes don't recoganize symbolic link,
		// which will lead "no such file or directory" error.
		return os.Symlink(target, dest)
	}

	sr, err := os.Open(src)
	if err != nil {
		return err
	}
	defer sr.Close()

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

	if _, err = io.Copy(dw, sr); err != nil {
		return err
	}

	// Set back file information.
	if err = os.Chtimes(dest, si.ModTime(), si.ModTime()); err != nil {
		return err
	}
	return os.Chmod(dest, si.Mode())
}

func CopyFile(src, dst string) (w int64, err error) {
	srcFile, err := os.Open(src)
	if err != nil {
		return
	}
	defer srcFile.Close()
	// if FileExist(dst) != true {
	if !FileExist(dst) {
		Wirtefile("", dst)
	}
	dstFile, err := os.Create(dst)
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	defer dstFile.Close()
	return io.Copy(dstFile, srcFile)
}

func CopyOFile(srcName, dstName string) (written int64, err error) {
	src, err := os.Open(srcName)
	if err != nil {
		return
	}
	defer src.Close()
	dst, err := os.OpenFile(dstName, os.O_WRONLY|os.O_CREATE, 0644)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer dst.Close()
	return io.Copy(dst, src)
}

func Readfile(fname string) (string, error) {
	userFile := fname
	fin, err := os.Open(userFile)
	defer fin.Close()
	if err != nil {
		fmt.Println(userFile, err)
		return "", err
	}
	var restr string = ""

	buf := make([]byte, 1024)
	for {
		n, _ := fin.Read(buf)
		if 0 == n {
			break
		}
		// os.Stdout.Write(buf[:n])

		strbuf := string(buf[:n])

		restr += strbuf
	}

	return restr, nil
}

func Wirtefile(wirtestr string, userFile string) {
	os.MkdirAll(path.Dir(userFile), os.ModePerm)

	fout, err := os.Create(userFile)
	defer fout.Close()
	if err != nil {
		fmt.Println(userFile, err)
		return
	}

	fout.WriteString(wirtestr)
}

func ListFile(dirPth string, suffix string) (files []string, err error) {
	files = make([]string, 0, 10)
	dir, err := ioutil.ReadDir(dirPth)
	if err != nil {
		return nil, err
	}
	PthSep := string(os.PathSeparator)
	suffix = strings.ToUpper(suffix)
	for _, fi := range dir {
		if fi.IsDir() {
			continue
		}
		if strings.HasSuffix(strings.ToUpper(fi.Name()), suffix) {
			files = append(files, dirPth+PthSep+fi.Name())
		}
	}
	return files, nil
}

func ListDir(dirPth string, suffix string) (files []string, err error) {
	files = make([]string, 0, 10)
	dir, err := ioutil.ReadDir(dirPth)
	if err != nil {
		return nil, err
	}
	PthSep := string(os.PathSeparator)
	suffix = strings.ToUpper(suffix)
	for _, fi := range dir {
		if !fi.IsDir() {
			continue
		}
		if strings.HasSuffix(strings.ToUpper(fi.Name()), suffix) {
			files = append(files, dirPth+PthSep+fi.Name())
		}
	}
	return files, nil
}

func WalkFile(dirPth, suffix string) (files []string, err error) {
	files = make([]string, 0, 30)
	suffix = strings.ToUpper(suffix)
	err = filepath.Walk(dirPth, func(filename string, fi os.FileInfo, err error) error {
		if fi.IsDir() {
			return nil
		}

		if strings.HasSuffix(strings.ToUpper(fi.Name()), suffix) {
			files = append(files, filename)
		}
		return nil
	})
	return files, err
}

func WalkDir(dirPth, suffix string) (files []string, err error) {
	files = make([]string, 0, 30)
	suffix = strings.ToUpper(suffix)
	err = filepath.Walk(dirPth, func(filename string, fi os.FileInfo, err error) error {

		if !fi.IsDir() {
			return nil
		}

		if strings.HasSuffix(strings.ToUpper(fi.Name()), suffix) {
			files = append(files, filename)
		}
		return nil
	})
	return files, err
}
<|endoftext|>


<commit_before>package sse

import (
	"net/http"
	"time"
	"strconv"
	"bufio"
	"strings"
)

type Listener func(data string) error

type Stream struct {
	Client *http.Client
	Request *http.Request
	Listeners map[string]Listener
	RetryTime time.Duration
	WillRetry bool
	LastEventID string
	URL string
}

func NewStream(c *http.Client, urlStr string) (*Stream) {
	return &Stream{
		Client: c,
		Listeners: map[string]Listener{},
		RetryTime: 1 * time.Second,
		WillRetry: true,
		URL: urlStr,
	}
}

func (s *Stream) On(event string, listener Listener) {
	s.Listeners[event] = listener
}

func (s *Stream) emit(event string, data string) {
	if listener, ok := s.Listeners[event]; ok {
		listener(data)
	}
}

func (s *Stream) Close() {
	if s.Request != nil {
		s.WillRetry = false
		//close(s.Request.Cancel) // TODO: use context.Context for cancel
	}
}

func (s *Stream) retry() {
	if s.WillRetry {
		time.Sleep(s.RetryTime)
		s.Start()
	}
}

var defaultEvent = "message"

func (s *Stream) Start() {
	s.Request = nil // TODO: mutex
	req, err := http.NewRequest("GET", s.URL, nil)
	if err != nil {
		return // TODO: errならabortでいいか
	}
	s.Request = req

	// TODO: should support means to set other headers?
	req.Header.Set("Accept", "text/event-stream")

	// TODO: User-Agent

	if s.LastEventID != "" {
		req.Header.Set("Last-Event-ID", s.LastEventID)
	}

	// TODO: mutex?
	t := s.Client.Timeout
	s.Client.Timeout = 0
	resp, err := s.Client.Do(req)
	s.Client.Timeout = t
	if err != nil {
		s.emit("error", "connection error: " + err.Error())
	}
	defer resp.Body.Close()

	if 500 <= resp.StatusCode {
		s.emit("error", "bad response status: " + strconv.Itoa(resp.StatusCode))
		s.retry()
		return
	} else if 400 <= resp.StatusCode && resp.StatusCode < 500 {
		// 4XX系ならretryしない
		s.emit("error", "bad response status: " + strconv.Itoa(resp.StatusCode))
		return
	}
	// TODO: 3XXのときはどうするか

	contentType := resp.Header.Get("Content-Type")
	if !strings.HasPrefix(contentType, "text/event-stream") {
		s.emit("error", "bad content type")
		s.retry()
		return
	}

	data := ""
	event := defaultEvent

	r := bufio.NewReader(resp.Body) // TODO: もしBOMがあったら無視する仕様

	for {
		line, err := r.ReadString('\n') // TODO: 仕様上は\rによって行末とすることも許されている
		if err != nil {
			s.emit("error", err.Error()) // TODO: 正常なケースもありそう
			s.retry()
			return
		}

		line = strings.TrimSuffix(strings.TrimSuffix(line, "\n"), "\r")

		// https://www.w3.org/TR/eventsource/#event-stream-interpretation
		if line == "" {
			if data != "" {
				s.emit(event, data)
				event = defaultEvent
				data = ""
			}
			continue
		}
		split := strings.SplitN(line, ":", 2)
		field := split[0]
		value := ""
		if len(split) == 2 {
			value = strings.TrimPrefix(split[1], " ")
		}
		switch field {
		case "event":
			event = value
		case "retry":
			if n, err := strconv.Atoi(value); err != nil {
				s.RetryTime = time.Duration(n) * time.Millisecond
			}
		case "id":
			s.LastEventID = value
		case "data":
			if data != "" {
				data += "\n"
			}
			data += value
		default:
			// ignore
		}
	}
}

<commit_msg>Use bufio.Scanner<commit_after>package sse

import (
	"net/http"
	"time"
	"strconv"
	"bufio"
	"strings"
)

type Listener func(data string) error

type Stream struct {
	Client *http.Client
	Request *http.Request
	Listeners map[string]Listener
	RetryTime time.Duration
	WillRetry bool
	LastEventID string
	URL string
}

func NewStream(c *http.Client, urlStr string) (*Stream) {
	return &Stream{
		Client: c,
		Listeners: map[string]Listener{},
		RetryTime: 1 * time.Second,
		WillRetry: true,
		URL: urlStr,
	}
}

func (s *Stream) On(event string, listener Listener) {
	s.Listeners[event] = listener
}

func (s *Stream) emit(event string, data string) {
	if listener, ok := s.Listeners[event]; ok {
		listener(data)
	}
}

func (s *Stream) Close() {
	if s.Request != nil {
		s.WillRetry = false
		//close(s.Request.Cancel) // TODO: use context.Context for cancel
	}
}

func (s *Stream) retry() {
	if s.WillRetry {
		time.Sleep(s.RetryTime)
		s.Start()
	}
}

var defaultEvent = "message"

func (s *Stream) Start() {
	s.Request = nil // TODO: mutex
	req, err := http.NewRequest("GET", s.URL, nil)
	if err != nil {
		return // TODO: errならabortでいいか
	}
	s.Request = req

	// TODO: should support means to set other headers?
	req.Header.Set("Accept", "text/event-stream")

	// TODO: User-Agent

	if s.LastEventID != "" {
		req.Header.Set("Last-Event-ID", s.LastEventID)
	}

	// TODO: mutex?
	t := s.Client.Timeout
	s.Client.Timeout = 0
	resp, err := s.Client.Do(req)
	s.Client.Timeout = t
	if err != nil {
		s.emit("error", "connection error: " + err.Error())
	}
	defer resp.Body.Close()

	if 500 <= resp.StatusCode {
		s.emit("error", "bad response status: " + strconv.Itoa(resp.StatusCode))
		s.retry()
		return
	} else if 400 <= resp.StatusCode && resp.StatusCode < 500 {
		// 4XX系ならretryしない
		s.emit("error", "bad response status: " + strconv.Itoa(resp.StatusCode))
		return
	}
	// TODO: 3XXのときはどうするか

	contentType := resp.Header.Get("Content-Type")
	if !strings.HasPrefix(contentType, "text/event-stream") {
		s.emit("error", "bad content type")
		s.retry()
		return
	}

	data := ""
	event := defaultEvent

	scanner := bufio.NewScanner(resp.Body) // TODO: もしBOMがあったら無視する仕様

	for scanner.Scan() { // TODO: scanner.Scanは\r?\nをdelimiterとするが、SSEの仕様上は\r単独もあり得る

		line := scanner.Text()

		// https://www.w3.org/TR/eventsource/#event-stream-interpretation
		if line == "" {
			if data != "" {
				s.emit(event, data)
				event = defaultEvent
				data = ""
			}
			continue
		}
		split := strings.SplitN(line, ":", 2)
		field := split[0]
		value := ""
		if len(split) == 2 {
			value = strings.TrimPrefix(split[1], " ")
		}
		switch field {
		case "event":
			event = value
		case "retry":
			if n, err := strconv.Atoi(value); err != nil {
				s.RetryTime = time.Duration(n) * time.Millisecond
			}
		case "id":
			s.LastEventID = value
		case "data":
			if data != "" {
				data += "\n"
			}
			data += value
		default:
			// ignore
		}
	}

	if err := scanner.Err(); err != nil {
		s.emit("error", err)
	}
	s.retry()
}

<|endoftext|>


<commit_before>package goquery

import (
	"testing"
)

func BenchmarkFirst(b *testing.B) {
	b.StopTimer()
	sel := DocB().Root.Find("dd")
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		sel.First()
	}
}

func BenchmarkLast(b *testing.B) {
	b.StopTimer()
	sel := DocB().Root.Find("dd")
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		sel.Last()
	}
}

func BenchmarkEq(b *testing.B) {
	b.StopTimer()
	sel := DocB().Root.Find("dd")
	j := 0
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		sel.Eq(j)
		if j++; j >= sel.Length() {
			j = 0
		}
	}
}

func BenchmarkSlice(b *testing.B) {
	b.StopTimer()
	sel := DocB().Root.Find("dd")
	j := 0
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		sel.Slice(j, j+4)
		if j++; j >= (sel.Length() - 4) {
			j = 0
		}
	}
}

func BenchmarkGet(b *testing.B) {
	b.StopTimer()
	sel := DocB().Root.Find("dd")
	j := 0
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		sel.Get(j)
		if j++; j >= sel.Length() {
			j = 0
		}
	}
}

func BenchmarkIndex(b *testing.B) {
	b.StopTimer()
	sel := DocB().Root.Find("#main")
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		sel.Index()
	}
}
<commit_msg>finalize benchmarks for array.go methods<commit_after>package goquery

import (
	"testing"
)

func BenchmarkFirst(b *testing.B) {
	b.StopTimer()
	sel := DocB().Root.Find("dd")
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		sel.First()
	}
}

func BenchmarkLast(b *testing.B) {
	b.StopTimer()
	sel := DocB().Root.Find("dd")
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		sel.Last()
	}
}

func BenchmarkEq(b *testing.B) {
	b.StopTimer()
	sel := DocB().Root.Find("dd")
	j := 0
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		sel.Eq(j)
		if j++; j >= sel.Length() {
			j = 0
		}
	}
}

func BenchmarkSlice(b *testing.B) {
	b.StopTimer()
	sel := DocB().Root.Find("dd")
	j := 0
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		sel.Slice(j, j+4)
		if j++; j >= (sel.Length() - 4) {
			j = 0
		}
	}
}

func BenchmarkGet(b *testing.B) {
	b.StopTimer()
	sel := DocB().Root.Find("dd")
	j := 0
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		sel.Get(j)
		if j++; j >= sel.Length() {
			j = 0
		}
	}
}

func BenchmarkIndex(b *testing.B) {
	var j int

	b.StopTimer()
	sel := DocB().Root.Find("#main")
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		j = sel.Index()
	}
	b.Logf("Index=%d\n", j)
}

func BenchmarkIndexSelector(b *testing.B) {
	var j int

	b.StopTimer()
	sel := DocB().Root.Find("#manual-nav dl dd:nth-child(1)")
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		j = sel.IndexSelector("dd")
	}
	b.Logf("IndexSelector=%d\n", j)
}

func BenchmarkIndexOfNode(b *testing.B) {
	var j int

	b.StopTimer()
	sel := DocB().Root.Find("span a")
	sel2 := DocB().Root.Find("span a:nth-child(3)")
	n := sel2.Get(0)
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		j = sel.IndexOfNode(n)
	}
	b.Logf("IndexOfNode=%d\n", j)
}

func BenchmarkIndexOfSelection(b *testing.B) {
	var j int
	b.StopTimer()
	sel := DocB().Root.Find("span a")
	sel2 := DocB().Root.Find("span a:nth-child(3)")
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		j = sel.IndexOfSelection(sel2)
	}
	b.Logf("IndexOfSelection=%d\n", j)
}
<|endoftext|>


<commit_before><commit_msg>Fix ping error on dynamodb-local because of NoCredentialProviders<commit_after><|endoftext|>


<commit_before>package redis

import (
	"errors"
	"fmt"
	"strconv"
	"time"

	"github.com/garyburd/redigo/redis"
)

type RedisSession struct {
	pool   *redis.Pool
	prefix string
}

func NewRedisSession(server string) (*RedisSession, error) {
	s := &RedisSession{}

	pool := &redis.Pool{
		MaxIdle:     3,
		MaxActive:   1000,
		IdleTimeout: 240 * time.Second,
		Dial: func() (redis.Conn, error) {
			c, err := redis.Dial("tcp", server)
			if err != nil {
				return nil, err
			}
			return c, err
		},
	}
	s.pool = pool
	// when we use connection pooling
	// dialing and returning an error will be
	// with the request
	return s, nil
}

// Close closes the connection pool for redis
func (r *RedisSession) Close() error {
	return r.pool.Close()
}

// SetPrefix is used to add a prefix to all keys to be used. It is useful for
// creating namespaces for each different application
func (r *RedisSession) SetPrefix(name string) {
	r.prefix = name + ":"
}

func (r *RedisSession) addPrefix(name string) string {
	return r.prefix + name
}

// Do is a wrapper around redigo's redis.Do method that executes any redis
// command. Do does not support prefix support. Example usage: redis.Do("INCR",
// "counter").
func (r *RedisSession) Do(cmd string, args ...interface{}) (interface{}, error) {
	conn := r.pool.Get()
	// conn.Close() returns an error but we are allready returning regarding error
	// while returning the Do(..) response
	defer conn.Close()
	return conn.Do(cmd, args...)
}

// Send is a wrapper around redigo's redis.Send method that writes the
// command to the client's output buffer.
func (r *RedisSession) Send(cmd string, args ...interface{}) error {
	conn := r.pool.Get()
	// conn.Close() returns an error but we are allready returning regarding error
	// while returning the Do(..) response
	defer conn.Close()
	return conn.Send(cmd, args...)
}

// Set is used to hold the string value. If key already holds a value, it is
// overwritten, regardless of its type. A return of nil means successfull.
// Example usage: redis.Set("arslan:name", "fatih")
func (r *RedisSession) Set(key, value string) error {
	reply, err := r.Do("SET", r.addPrefix(key), value)
	if err != nil {
		return err
	}

	if reply != "OK" {
		return fmt.Errorf("reply string is wrong!: %s", reply)

	}
	return nil
}

// Get is used to get the value of key. If the key does not exist an empty
// string is returned. Usage: redis.Get("arslan")
func (r *RedisSession) Get(key string) (string, error) {
	reply, err := redis.String(r.Do("GET", r.addPrefix(key)))
	if err != nil {
		return "", err
	}
	return reply, nil
}

// GetInt is used the value of key as an integer. If the key does not exist or
// the stored value is a non-integer, zero is returned. Example usage:
// redis.GetInt("counter")
func (r *RedisSession) GetInt(key string) (int, error) {
	reply, err := redis.Int(r.Do("GET", r.addPrefix(key)))
	if err != nil {
		return 0, err
	}

	return reply, nil
}

// Del is used to remove the specified keys. Key is ignored if it does not
// exist. It returns the number of keys that were removed. Example usage:
// redis.Del("counter", "arslan:name")
func (r *RedisSession) Del(args ...interface{}) (int, error) {
	prefixed := make([]interface{}, 0)
	for _, arg := range args {
		prefixed = append(prefixed, r.addPrefix(arg.(string)))
	}

	reply, err := redis.Int(r.Do("DEL", prefixed...))
	if err != nil {
		return 0, err
	}
	return reply, nil
}

// Incr increments the number stored at key by one. If the key does not exist,
// it is set to 0 before performing the operation. An error is returned if the
// key contains a value of the wrong type or contains a string that can not be
// represented as integer
func (r *RedisSession) Incr(key string) (int, error) {
	reply, err := redis.Int(r.Do("INCR", r.addPrefix(key)))
	if err != nil {
		return 0, err
	}

	return reply, nil
}

// Expire sets a timeout on a key. After the timeout has expired, the key will
// automatically be deleted. Calling Expire on a key that has already expire
// set will update the expire value.
func (r *RedisSession) Expire(key string, timeout time.Duration) error {
	seconds := strconv.Itoa(int(timeout.Seconds()))
	reply, err := redis.Int(r.Do("EXPIRE", r.addPrefix(key), seconds))
	if err != nil {
		return err
	}

	if reply != 1 {
		return errors.New("key does not exist or the timeout could not be set")
	}

	return nil
}

// Exists returns true if key exists or false if not.
func (r *RedisSession) Exists(key string) bool {
	// does not have any err message to be checked, it return either 1 or 0
	reply, _ := redis.Int(r.Do("EXISTS", r.addPrefix(key)))

	if reply == 1 {
		return true
	}

	return false // means reply is 0, key does not exist
}

// Ping pings the redis server to check if it is alive or not
// If the server is not alive will return a proper error
func (r *RedisSession) Ping() error {
	reply, err := redis.String(r.Do("PING"))
	if err != nil {
		return err
	}

	if reply != "PONG" {
		return fmt.Errorf("reply string is wrong!: %s", reply)
	}

	return nil
}

// Scard gets the member count of a Set with given key
func (r *RedisSession) Scard(key string) (int, error) {
	reply, err := redis.Int(r.Do("SCARD", key))
	if err != nil {
		return 0, err
	}

	return reply, nil
}

// SortedSetIncrBy increments the value of a member
// in a sorted set
//
// This function tries to return last floating value of the item,
// if it fails to parse reply to float64, returns parsing error along with
// Reply it self
func (r *RedisSession) SortedSetIncrBy(key string, incrBy, item interface{}) (float64, error) {
	prefixed := make([]interface{}, 0)
	// add key
	prefixed = append(prefixed, r.addPrefix(key))

	// add incrBy
	prefixed = append(prefixed, incrBy)

	// add item
	prefixed = append(prefixed, item)

	return redis.Float64(r.Do("ZINCRBY", prefixed...))
}

// ZREVRANGE key start stop [WITHSCORES]
// Returns the specified range of elements in the sorted set stored at key.
// The elements are considered to be ordered from the highest
// to the lowest score. Descending lexicographical order is used
// for elements with equal score.
//
// Apart from the reversed ordering, ZREVRANGE is similar to ZRANGE.
func (r *RedisSession) SortedSetReverseRange(key string, rest ...interface{}) ([]interface{}, error) {
	// create a slice with rest length +1
	// because we are gonna prepend key to it
	prefixedReq := make([]interface{}, len(rest)+1)

	// prepend prefixed key
	prefixedReq[0] = r.addPrefix(key)

	for key, el := range rest {
		prefixedReq[key+1] = el
	}

	return redis.Values(r.Do("ZREVRANGE", prefixedReq...))
}

// HashMultipleSet sets multiple hashset elements stored at key with given field values.
// Returns error state of this operation
func (r *RedisSession) HashMultipleSet(key string, item map[string]interface{}) error {

	// not an optimal solution
	fieldValuePairs := make([]interface{}, 0)
	fieldValuePairs = append(fieldValuePairs, r.addPrefix(key))
	for field, value := range item {
		fieldValuePairs = append(fieldValuePairs, field, value)
	}

	reply, err := r.Do("HMSET", fieldValuePairs...)
	if err != nil {
		return err
	}

	if reply != "OK" {
		return fmt.Errorf("reply string is wrong!: %s", reply)

	}

	return nil
}

// GetHashMultipleSet returns values of the hashset at stored key with
// requested field order
// Usage: GetHashMultipleSet("canthefason", "name", "age", "birthDate")
func (r *RedisSession) GetHashMultipleSet(key string, rest ...interface{}) ([]interface{}, error) {
	prefixedReq := r.prepareArgsWithKey(key, rest...)
	return redis.Values(r.Do("HMGET", prefixedReq.s..))
}

// AddSetMembers adds given elements to the set stored at key. Given elements
// that are already included in set are ignored.
// Returns successfully added key count and error state
func (r *RedisSession) AddSetMembers(key string, rest ...interface{}) (int, error) {
	prefixedReq := r.prepareArgsWithKey(key, rest...)

	reply, err := redis.Int(r.Do("SADD", prefixedReq...))
	if err != nil {
		return 0, err
	}

	return reply, nil
}

// GetSetMembers returns all members included in the set at key
// Returns members array and error state
func (r *RedisSession) GetSetMembers(key string) ([]interface{}, error) {
	return redis.Values(r.Do("SMEMBERS", r.addPrefix(key)))
}

// SortBy sorts elements stored at key with given weight and order(ASC|DESC)
//
// i.e. Suppose we have elements stored at key as object_1, object_2 and object_3
// and their weight is relatively stored at object_1:weight, object_2:weight, object_3:weight
// When we give sortBy parameter as *:weight, it gets all weight values and sorts the objects
// at given key with specified order.
func (r *RedisSession) SortBy(key, sortBy, order string) ([]interface{}, error) {
	return redis.Values(r.Do("SORT", r.addPrefix(key), "by", r.addPrefix(sortBy), order))
}

// Keys returns all keys with given pattern
// WARNING: Redis Doc says: "Don't use KEYS in your regular application code."
func (r *RedisSession) Keys(key string) ([]interface{}, error) {
	return redis.Values(r.Do("KEYS", r.addPrefix(key)))
}

// Bool converts the given value to boolean
func (r *RedisSession) Bool(reply interface{}) (bool, error) {
	return redis.Bool(reply, nil)
}

// Int converts the given value to integer
func (r *RedisSession) Int(reply interface{}) (int, error) {
	return redis.Int(reply, nil)
}

// String converts the given value to string
func (r *RedisSession) String(reply interface{}) (string, error) {
	return redis.String(reply, nil)
}

// Int64 converts the given value to 64 bit integer
func (r *RedisSession) Int64(reply interface{}) (int64, error) {
	return redis.Int64(reply, nil)
}

// prepareArgsWithKey helper method prepends key to given variadic parameter
func (r *RedisSession) prepareArgsWithKey(key string, rest ...interface{}) []interface{} {
	prefixedReq := make([]interface{}, len(rest)+1)

	// prepend prefixed key
	prefixedReq[0] = r.addPrefix(key)

	for key, el := range rest {
		prefixedReq[key+1] = el
	}

	return prefixedReq
}<commit_msg>Redis: fixed typo in GetHashMultipleSet<commit_after>package redis

import (
	"errors"
	"fmt"
	"strconv"
	"time"

	"github.com/garyburd/redigo/redis"
)

type RedisSession struct {
	pool   *redis.Pool
	prefix string
}

func NewRedisSession(server string) (*RedisSession, error) {
	s := &RedisSession{}

	pool := &redis.Pool{
		MaxIdle:     3,
		MaxActive:   1000,
		IdleTimeout: 240 * time.Second,
		Dial: func() (redis.Conn, error) {
			c, err := redis.Dial("tcp", server)
			if err != nil {
				return nil, err
			}
			return c, err
		},
	}
	s.pool = pool
	// when we use connection pooling
	// dialing and returning an error will be
	// with the request
	return s, nil
}

// Close closes the connection pool for redis
func (r *RedisSession) Close() error {
	return r.pool.Close()
}

// SetPrefix is used to add a prefix to all keys to be used. It is useful for
// creating namespaces for each different application
func (r *RedisSession) SetPrefix(name string) {
	r.prefix = name + ":"
}

func (r *RedisSession) addPrefix(name string) string {
	return r.prefix + name
}

// Do is a wrapper around redigo's redis.Do method that executes any redis
// command. Do does not support prefix support. Example usage: redis.Do("INCR",
// "counter").
func (r *RedisSession) Do(cmd string, args ...interface{}) (interface{}, error) {
	conn := r.pool.Get()
	// conn.Close() returns an error but we are allready returning regarding error
	// while returning the Do(..) response
	defer conn.Close()
	return conn.Do(cmd, args...)
}

// Send is a wrapper around redigo's redis.Send method that writes the
// command to the client's output buffer.
func (r *RedisSession) Send(cmd string, args ...interface{}) error {
	conn := r.pool.Get()
	// conn.Close() returns an error but we are allready returning regarding error
	// while returning the Do(..) response
	defer conn.Close()
	return conn.Send(cmd, args...)
}

// Set is used to hold the string value. If key already holds a value, it is
// overwritten, regardless of its type. A return of nil means successfull.
// Example usage: redis.Set("arslan:name", "fatih")
func (r *RedisSession) Set(key, value string) error {
	reply, err := r.Do("SET", r.addPrefix(key), value)
	if err != nil {
		return err
	}

	if reply != "OK" {
		return fmt.Errorf("reply string is wrong!: %s", reply)

	}
	return nil
}

// Get is used to get the value of key. If the key does not exist an empty
// string is returned. Usage: redis.Get("arslan")
func (r *RedisSession) Get(key string) (string, error) {
	reply, err := redis.String(r.Do("GET", r.addPrefix(key)))
	if err != nil {
		return "", err
	}
	return reply, nil
}

// GetInt is used the value of key as an integer. If the key does not exist or
// the stored value is a non-integer, zero is returned. Example usage:
// redis.GetInt("counter")
func (r *RedisSession) GetInt(key string) (int, error) {
	reply, err := redis.Int(r.Do("GET", r.addPrefix(key)))
	if err != nil {
		return 0, err
	}

	return reply, nil
}

// Del is used to remove the specified keys. Key is ignored if it does not
// exist. It returns the number of keys that were removed. Example usage:
// redis.Del("counter", "arslan:name")
func (r *RedisSession) Del(args ...interface{}) (int, error) {
	prefixed := make([]interface{}, 0)
	for _, arg := range args {
		prefixed = append(prefixed, r.addPrefix(arg.(string)))
	}

	reply, err := redis.Int(r.Do("DEL", prefixed...))
	if err != nil {
		return 0, err
	}
	return reply, nil
}

// Incr increments the number stored at key by one. If the key does not exist,
// it is set to 0 before performing the operation. An error is returned if the
// key contains a value of the wrong type or contains a string that can not be
// represented as integer
func (r *RedisSession) Incr(key string) (int, error) {
	reply, err := redis.Int(r.Do("INCR", r.addPrefix(key)))
	if err != nil {
		return 0, err
	}

	return reply, nil
}

// Expire sets a timeout on a key. After the timeout has expired, the key will
// automatically be deleted. Calling Expire on a key that has already expire
// set will update the expire value.
func (r *RedisSession) Expire(key string, timeout time.Duration) error {
	seconds := strconv.Itoa(int(timeout.Seconds()))
	reply, err := redis.Int(r.Do("EXPIRE", r.addPrefix(key), seconds))
	if err != nil {
		return err
	}

	if reply != 1 {
		return errors.New("key does not exist or the timeout could not be set")
	}

	return nil
}

// Exists returns true if key exists or false if not.
func (r *RedisSession) Exists(key string) bool {
	// does not have any err message to be checked, it return either 1 or 0
	reply, _ := redis.Int(r.Do("EXISTS", r.addPrefix(key)))

	if reply == 1 {
		return true
	}

	return false // means reply is 0, key does not exist
}

// Ping pings the redis server to check if it is alive or not
// If the server is not alive will return a proper error
func (r *RedisSession) Ping() error {
	reply, err := redis.String(r.Do("PING"))
	if err != nil {
		return err
	}

	if reply != "PONG" {
		return fmt.Errorf("reply string is wrong!: %s", reply)
	}

	return nil
}

// Scard gets the member count of a Set with given key
func (r *RedisSession) Scard(key string) (int, error) {
	reply, err := redis.Int(r.Do("SCARD", key))
	if err != nil {
		return 0, err
	}

	return reply, nil
}

// SortedSetIncrBy increments the value of a member
// in a sorted set
//
// This function tries to return last floating value of the item,
// if it fails to parse reply to float64, returns parsing error along with
// Reply it self
func (r *RedisSession) SortedSetIncrBy(key string, incrBy, item interface{}) (float64, error) {
	prefixed := make([]interface{}, 0)
	// add key
	prefixed = append(prefixed, r.addPrefix(key))

	// add incrBy
	prefixed = append(prefixed, incrBy)

	// add item
	prefixed = append(prefixed, item)

	return redis.Float64(r.Do("ZINCRBY", prefixed...))
}

// ZREVRANGE key start stop [WITHSCORES]
// Returns the specified range of elements in the sorted set stored at key.
// The elements are considered to be ordered from the highest
// to the lowest score. Descending lexicographical order is used
// for elements with equal score.
//
// Apart from the reversed ordering, ZREVRANGE is similar to ZRANGE.
func (r *RedisSession) SortedSetReverseRange(key string, rest ...interface{}) ([]interface{}, error) {
	// create a slice with rest length +1
	// because we are gonna prepend key to it
	prefixedReq := make([]interface{}, len(rest)+1)

	// prepend prefixed key
	prefixedReq[0] = r.addPrefix(key)

	for key, el := range rest {
		prefixedReq[key+1] = el
	}

	return redis.Values(r.Do("ZREVRANGE", prefixedReq...))
}

// HashMultipleSet sets multiple hashset elements stored at key with given field values.
// Returns error state of this operation
func (r *RedisSession) HashMultipleSet(key string, item map[string]interface{}) error {

	// not an optimal solution
	fieldValuePairs := make([]interface{}, 0)
	fieldValuePairs = append(fieldValuePairs, r.addPrefix(key))
	for field, value := range item {
		fieldValuePairs = append(fieldValuePairs, field, value)
	}

	reply, err := r.Do("HMSET", fieldValuePairs...)
	if err != nil {
		return err
	}

	if reply != "OK" {
		return fmt.Errorf("reply string is wrong!: %s", reply)

	}

	return nil
}

// GetHashMultipleSet returns values of the hashset at stored key with
// requested field order
// Usage: GetHashMultipleSet("canthefason", "name", "age", "birthDate")
func (r *RedisSession) GetHashMultipleSet(key string, rest ...interface{}) ([]interface{}, error) {
	prefixedReq := r.prepareArgsWithKey(key, rest...)
	return redis.Values(r.Do("HMGET", prefixedReq...))
}

// AddSetMembers adds given elements to the set stored at key. Given elements
// that are already included in set are ignored.
// Returns successfully added key count and error state
func (r *RedisSession) AddSetMembers(key string, rest ...interface{}) (int, error) {
	prefixedReq := r.prepareArgsWithKey(key, rest...)

	reply, err := redis.Int(r.Do("SADD", prefixedReq...))
	if err != nil {
		return 0, err
	}

	return reply, nil
}

// GetSetMembers returns all members included in the set at key
// Returns members array and error state
func (r *RedisSession) GetSetMembers(key string) ([]interface{}, error) {
	return redis.Values(r.Do("SMEMBERS", r.addPrefix(key)))
}

// SortBy sorts elements stored at key with given weight and order(ASC|DESC)
//
// i.e. Suppose we have elements stored at key as object_1, object_2 and object_3
// and their weight is relatively stored at object_1:weight, object_2:weight, object_3:weight
// When we give sortBy parameter as *:weight, it gets all weight values and sorts the objects
// at given key with specified order.
func (r *RedisSession) SortBy(key, sortBy, order string) ([]interface{}, error) {
	return redis.Values(r.Do("SORT", r.addPrefix(key), "by", r.addPrefix(sortBy), order))
}

// Keys returns all keys with given pattern
// WARNING: Redis Doc says: "Don't use KEYS in your regular application code."
func (r *RedisSession) Keys(key string) ([]interface{}, error) {
	return redis.Values(r.Do("KEYS", r.addPrefix(key)))
}

// Bool converts the given value to boolean
func (r *RedisSession) Bool(reply interface{}) (bool, error) {
	return redis.Bool(reply, nil)
}

// Int converts the given value to integer
func (r *RedisSession) Int(reply interface{}) (int, error) {
	return redis.Int(reply, nil)
}

// String converts the given value to string
func (r *RedisSession) String(reply interface{}) (string, error) {
	return redis.String(reply, nil)
}

// Int64 converts the given value to 64 bit integer
func (r *RedisSession) Int64(reply interface{}) (int64, error) {
	return redis.Int64(reply, nil)
}

// prepareArgsWithKey helper method prepends key to given variadic parameter
func (r *RedisSession) prepareArgsWithKey(key string, rest ...interface{}) []interface{} {
	prefixedReq := make([]interface{}, len(rest)+1)

	// prepend prefixed key
	prefixedReq[0] = r.addPrefix(key)

	for key, el := range rest {
		prefixedReq[key+1] = el
	}

	return prefixedReq
}
<|endoftext|>


<commit_before>package turn

import (
	"io"
	"net"
	"testing"
	"time"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"go.uber.org/zap/zaptest/observer"
)

type closeFunc func() error

func (f closeFunc) Close() error {
	return f()
}

type readFunc func(buf []byte) (int, error)

func (f readFunc) Read(buf []byte) (int, error) {
	return f(buf)
}

func TestMultiplexer(t *testing.T) {
	t.Run("closeLogged", func(t *testing.T) {
		core, logs := observer.New(zapcore.ErrorLevel)
		logger := zap.New(core)
		closeLogged(logger, "message", closeFunc(func() error {
			return io.ErrUnexpectedEOF
		}))
		if logs.Len() < 1 {
			t.Error("no errors logged")
		}
	})
	t.Run("discardLogged", func(t *testing.T) {
		core, logs := observer.New(zapcore.ErrorLevel)
		logger := zap.New(core)
		discardLogged(logger, "message", readFunc(func(buf []byte) (int, error) {
			return 0, io.ErrUnexpectedEOF
		}))
		if logs.Len() < 1 {
			t.Error("no errors logged")
		}
	})
	t.Run("AppData", func(t *testing.T) {
		core, logs := observer.New(zapcore.ErrorLevel)
		logger := zap.New(core)
		connL, connR := net.Pipe()
		m := newMultiplexer(connR, logger)
		go func() {
			if err := connL.SetWriteDeadline(time.Now().Add(time.Second)); err != nil {
				t.Error(err)
			}
			if _, err := connL.Write([]byte{1, 2, 3, 4}); err != nil {
				t.Error(err)
			}
		}()
		buf := make([]byte, 1024)
		if _, err := m.dataL.Read(buf); err != nil {
			t.Error(err)
		}
		if logs.Len() > 0 {
			t.Error("no logs expected")
		}
	})
	t.Run("Write error", func(t *testing.T) {
		core, logs := observer.New(zapcore.WarnLevel)
		logger := zap.New(core)
		connL, connR := net.Pipe()
		m := newMultiplexer(connR, logger)
		if err := m.dataR.Close(); err != nil {
			t.Error(err)
		}
		if err := m.dataL.Close(); err != nil {
			t.Error(err)
		}
		if err := connL.SetWriteDeadline(time.Now().Add(time.Second)); err != nil {
			t.Error(err)
		}
		if _, err := connL.Write([]byte{1, 2, 3, 4}); err != nil {
			t.Error(err)
		}
		timeout := time.Tick(time.Second)
		for logs.Len() < 1 {
			select {
			case <-timeout:
				t.Error("timed out waiting for logs")
			default:
				continue
			}
		}
	})
}
<commit_msg>multiplexer: increase wait timeout in tests<commit_after>package turn

import (
	"io"
	"net"
	"testing"
	"time"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"go.uber.org/zap/zaptest/observer"
)

type closeFunc func() error

func (f closeFunc) Close() error {
	return f()
}

type readFunc func(buf []byte) (int, error)

func (f readFunc) Read(buf []byte) (int, error) {
	return f(buf)
}

func TestMultiplexer(t *testing.T) {
	t.Run("closeLogged", func(t *testing.T) {
		core, logs := observer.New(zapcore.ErrorLevel)
		logger := zap.New(core)
		closeLogged(logger, "message", closeFunc(func() error {
			return io.ErrUnexpectedEOF
		}))
		if logs.Len() < 1 {
			t.Error("no errors logged")
		}
	})
	t.Run("discardLogged", func(t *testing.T) {
		core, logs := observer.New(zapcore.ErrorLevel)
		logger := zap.New(core)
		discardLogged(logger, "message", readFunc(func(buf []byte) (int, error) {
			return 0, io.ErrUnexpectedEOF
		}))
		if logs.Len() < 1 {
			t.Error("no errors logged")
		}
	})
	t.Run("AppData", func(t *testing.T) {
		core, logs := observer.New(zapcore.ErrorLevel)
		logger := zap.New(core)
		connL, connR := net.Pipe()
		m := newMultiplexer(connR, logger)
		go func() {
			if err := connL.SetWriteDeadline(time.Now().Add(time.Second)); err != nil {
				t.Error(err)
			}
			if _, err := connL.Write([]byte{1, 2, 3, 4}); err != nil {
				t.Error(err)
			}
		}()
		buf := make([]byte, 1024)
		if _, err := m.dataL.Read(buf); err != nil {
			t.Error(err)
		}
		if logs.Len() > 0 {
			t.Error("no logs expected")
		}
	})
	t.Run("Write error", func(t *testing.T) {
		core, logs := observer.New(zapcore.WarnLevel)
		logger := zap.New(core)
		connL, connR := net.Pipe()
		m := newMultiplexer(connR, logger)
		if err := m.dataR.Close(); err != nil {
			t.Error(err)
		}
		if err := m.dataL.Close(); err != nil {
			t.Error(err)
		}
		if err := connL.SetWriteDeadline(time.Now().Add(time.Second)); err != nil {
			t.Error(err)
		}
		if _, err := connL.Write([]byte{1, 2, 3, 4}); err != nil {
			t.Error(err)
		}
		timeout := time.Tick(time.Second * 5)
		for logs.Len() < 1 {
			select {
			case <-timeout:
				t.Error("timed out waiting for logs")
			default:
				continue
			}
		}
	})
}
<|endoftext|>