<commit_before>package nicolive

import (
	"bufio"
	"fmt"
	"html"
	"io/ioutil"
	"net"
	"strconv"
	"strings"
	"sync"
	"time"

	"gopkg.in/xmlpath.v2"
)

const (
	numCommentConnectionRoutines = 2
	keepAliveDuration            = time.Minute
	postKeyDuration              = 10 * time.Second
	heartbeatDuration            = 90 * time.Second
)

// Comment is struct to hold a comment
type Comment struct {
	No          int
	Date        time.Time
	UserID      string
	IsPremium   bool
	IsCommand   bool
	IsStaff     bool
	IsAnonymity bool
	Comment     string
	Mail        string
	Locale      string
	Score       int
}

// CommentConnection is a struct to manage sending/receiving comments.
// This struct automatically submits NULL character to reserve connection and
// get the PostKey, which is necessary for sending comments.
// liveWaku should have connection information which is able to get by fetchInformation()
type CommentConnection struct {
	IsConnected bool

	lv     *LiveWaku
	sock   net.Conn
	ticket string
	svrDu  time.Duration
	block  int

	rw           bufio.ReadWriter
	keepAliveTmr *time.Timer
	postKeyTmr   *time.Timer
	heartbeatTmr *time.Timer
	wmu          sync.Mutex
	termc        chan bool
	ev           EventReceiver
}

// NewCommentConnection returns a pointer to new CommentConnection
func NewCommentConnection(ev EventReceiver) *CommentConnection {
	kat := time.NewTimer(keepAliveDuration)
	kat.Stop()
	pkt := time.NewTimer(postKeyDuration)
	pkt.Stop()
	hbt := time.NewTimer(heartbeatDuration)
	hbt.Stop()

	if ev == nil {
		ev = &defaultEventReceiver{}
	}

	return &CommentConnection{
		termc:        make(chan bool),
		keepAliveTmr: kat,
		postKeyTmr:   pkt,
		heartbeatTmr: hbt,
		ev:           ev,
	}
}

// SetLv sets lv with given pointer to LiveWaku
func (cc *CommentConnection) SetLv(l *LiveWaku) Error {
	if cc.IsConnected {
		return MakeError(ErrOther,
			"already connected.\nlv can not be changed while it's connected")
	}

	cc.lv = l
	return nil
}

func (cc *CommentConnection) open() Error {
	if cc.lv.Account == nil {
		return MakeError(ErrOther, "nil account in LiveWaku")
	}
	if cc.lv.BroadID == "" {
		return MakeError(ErrOther, "BroadID is not set")
	}

	var err error

	addrport := fmt.Sprintf("%s:%s",
		cc.lv.CommentServer.Addr,
		cc.lv.CommentServer.Port)

	cc.wmu.Lock()

	cc.sock, err = net.Dial("tcp", addrport)
	if err != nil {
		return ErrFromStdErr(err)
	}

	cc.rw = bufio.ReadWriter{
		Reader: bufio.NewReader(cc.sock),
		Writer: bufio.NewWriter(cc.sock),
	}

	_, err = fmt.Fprintf(cc.rw,
		"<thread thread=\"%s\" res_from=\"-1000\" version=\"20061206\" />\x00",
		cc.lv.CommentServer.Thread)
	if err != nil {
		return ErrFromStdErr(err)
	}
	err = cc.rw.Flush()
	if err != nil {
		return ErrFromStdErr(err)
	}

	cc.wmu.Unlock()

	return nil
}

// Connect Connect to nicolive and start receiving comment
func (cc *CommentConnection) Connect() Error {
	if cc.IsConnected {
		return MakeError(ErrOther, "already connected")
	}
	cc.IsConnected = true

	nerr := cc.open()
	if nerr != nil {
		return nerr
	}
	cc.keepAliveTmr.Reset(keepAliveDuration)

	go cc.receiveStream()
	go cc.timer()

	return nil
}

func (cc *CommentConnection) receiveStream() {
	for {
		select {
		case <-cc.termc:
			return
		default:
			cc.sock.SetReadDeadline(time.Now().Add(time.Second))
			commxml, err := cc.rw.ReadString('\x00')
			if err != nil {
				nerr, ok := err.(net.Error)
				if ok && nerr.Timeout() && nerr.Temporary() {
					continue
				}

				if cc.IsConnected {
					go cc.Disconnect()
				}
				cc.ev.ProceedNicoEvent(&Event{
					Type:    EventTypeErr,
					Content: ErrFromStdErr(err),
				})
				<-cc.termc
				return
			}

			// strip null char
			commxml = commxml[:len(commxml)-1]

			commxmlr := strings.NewReader(commxml)
			rt, err := xmlpath.Parse(commxmlr)
			if err != nil {
				cc.ev.ProceedNicoEvent(&Event{
					Type:    EventTypeErr,
					Content: ErrFromStdErr(err),
				})
				continue
			}

			if strings.HasPrefix(commxml, "<thread ") {
				if v, ok := xmlpath.MustCompile("/thread/@last_res").String(rt); ok {
					lbl, _ := strconv.Atoi(v)
					cc.block = lbl / 10
				}
				if v, ok := xmlpath.MustCompile("/thread/@ticket").String(rt); ok {
					cc.ticket = v
				}
				if v, ok := xmlpath.MustCompile("/thread/@server_time").String(rt); ok {
					i, _ := strconv.ParseInt(v, 10, 64)
					cc.svrDu = time.Unix(i, 0).Sub(time.Now())
				}

				// immediately update postkey and start the timer
				cc.postKeyTmr.Reset(0)
				cc.heartbeatTmr.Reset(0)

				cc.ev.ProceedNicoEvent(&Event{
					Type:    EventTypeOpen,
					Content: nil,
				})

				continue
			}
			if strings.HasPrefix(commxml, "<chat_result ") {
				if v, ok := xmlpath.MustCompile("/chat_result/@status").String(rt); ok {
					if v != "0" {
						cc.ev.ProceedNicoEvent(&Event{
							Type:    EventTypeErr,
							Content: MakeError(ErrSendComment, "comment send error. chat_result status : "+v),
						})
						continue
					}
					cc.ev.ProceedNicoEvent(&Event{
						Type:    EventTypeSend,
						Content: nil,
					})
				}
				continue
			}
			if strings.HasPrefix(commxml, "<chat ") {
				var comment Comment

				if v, ok := xmlpath.MustCompile("/chat").String(rt); ok {
					comment.Comment = html.UnescapeString(v)
				}
				if v, ok := xmlpath.MustCompile("/chat/@no").String(rt); ok {
					comment.No, _ = strconv.Atoi(v)
				}
				if d, ok := xmlpath.MustCompile("/chat/@date").String(rt); ok {
					di, _ := strconv.ParseInt(d, 10, 64)
					var udi int64
					if ud, ok := xmlpath.MustCompile("/chat/@date_usec").String(rt); ok {
						udi, _ = strconv.ParseInt(ud, 10, 64)
					}
					comment.Date = time.Unix(di, udi*1000)
				}
				if v, ok := xmlpath.MustCompile("/chat/@mail").String(rt); ok {
					comment.Mail = v
				}
				if v, ok := xmlpath.MustCompile("/chat/@user_id").String(rt); ok {
					comment.UserID = v
				}
				if v, ok := xmlpath.MustCompile("/chat/@premium").String(rt); ok {
					i, _ := strconv.Atoi(v)
					comment.IsPremium = i%2 == 1
					i >>= 1
					comment.IsCommand = i%2 == 1
					i >>= 1
					comment.IsStaff = i%2 == 1
				}
				if v, ok := xmlpath.MustCompile("/chat/@anonymity").String(rt); ok {
					comment.IsAnonymity, _ = strconv.ParseBool(v)
				}
				if v, ok := xmlpath.MustCompile("/chat/@locale").String(rt); ok {
					comment.Locale = v
				}
				if v, ok := xmlpath.MustCompile("/chat/@score").String(rt); ok {
					comment.Score, _ = strconv.Atoi(v)
				}

				blk := comment.No / 10
				if blk > cc.block {
					cc.block = blk
					cc.postKeyTmr.Reset(0)
				}

				cc.ev.ProceedNicoEvent(&Event{
					Type:    EventTypeGot,
					Content: comment,
				})

				if comment.IsCommand && comment.Comment == "/disconnect" {
					go cc.Disconnect()

					cc.ev.ProceedNicoEvent(&Event{
						Type:    EventTypeWakuEnd,
						Content: *cc.lv,
					})

					<-cc.termc
					return
				}
				continue
			}

			cc.ev.ProceedNicoEvent(&Event{
				Type:    EventTypeErr,
				Content: MakeError(ErrSendComment, "unknown stream : "+commxml),
			})

		}
	}
}

func (cc *CommentConnection) timer() {
	for {
		select {
		case <-cc.termc:
			return
		case <-cc.keepAliveTmr.C:
			cc.keepAliveTmr.Reset(keepAliveDuration)
			cc.wmu.Lock()
			err := cc.rw.WriteByte(0)
			if err == nil {
				err = cc.rw.Flush()
			}
			cc.wmu.Unlock()
			if err != nil {
				cc.ev.ProceedNicoEvent(&Event{
					Type:    EventTypeErr,
					Content: MakeError(ErrConnection, "keep alive : "+err.Error()),
				})
				continue
			}
		case <-cc.postKeyTmr.C:
			cc.postKeyTmr.Reset(postKeyDuration)
			nerr := cc.FetchPostKey()
			if nerr != nil {
				cc.ev.ProceedNicoEvent(&Event{
					Type:    EventTypeErr,
					Content: nerr,
				})
				continue
			}
		case <-cc.heartbeatTmr.C:
			cc.heartbeatTmr.Reset(heartbeatDuration)
			hbv, nerr := cc.lv.FetchHeartBeat()
			if nerr != nil {
				cc.ev.ProceedNicoEvent(&Event{
					Type:    EventTypeErr,
					Content: nerr,
				})
				continue
			}
			cc.ev.ProceedNicoEvent(&Event{
				Type:    EventTypeHeartBeatGot,
				Content: hbv,
			})
		}
	}
}

// FetchPostKey gets postkey using getpostkey API
func (cc *CommentConnection) FetchPostKey() Error {
	if cc.lv.Account == nil {
		return MakeError(ErrOther, "nil account in LiveWaku")
	}
	if cc.lv.BroadID == "" {
		return MakeError(ErrOther, "BroadID is not set")
	}

	c, nicoerr := NewNicoClient(cc.lv.Account)
	if nicoerr != nil {
		return nicoerr
	}

	url := fmt.Sprintf(
		"http://live.nicovideo.jp/api/getpostkey?thread=%s&block_no=%d",
		cc.lv.CommentServer.Thread, cc.block)
	res, err := c.Get(url)
	if err != nil {
		return ErrFromStdErr(err)
	}
	defer res.Body.Close()

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

	pk := string(allb[8:])
	if pk == "" {
		return MakeError(ErrOther, "failed to get postkey")
	}

	cc.lv.PostKey = pk

	return nil
}

// SendComment sends comment to current comment connection
func (cc *CommentConnection) SendComment(text string, iyayo bool) Error {
	if !cc.IsConnected {
		return MakeError(ErrOther, "not connected")
	}
	if cc.lv.PostKey == "" {
		return MakeError(ErrOther, "no postkey in livewaku")
	}
	if text == "" {
		return MakeError(ErrOther, "empty text")
	}

	vpos := 100 *
		(time.Now().Add(cc.svrDu).Unix() - cc.lv.Stream.OpenTime.Unix())

	var iyayos string
	if iyayo {
		iyayos = " mail=\"184\""
	}
	var prems string
	if cc.lv.User.IsPremium {
		prems = " premium=\"1\""
	}

	sdcomm := fmt.Sprintf("<chat thread=\"%s\" ticket=\"%s\" "+
		"vpos=\"%d\" postkey=\"%s\"%s user_id=\"%s\"%s>%s</chat>\x00",
		cc.lv.CommentServer.Thread,
		cc.ticket,
		vpos,
		cc.lv.PostKey,
		iyayos,
		cc.lv.User.UserID,
		prems,
		html.EscapeString(text))

	fmt.Println(sdcomm)

	cc.wmu.Lock()
	fmt.Fprint(cc.rw, sdcomm)
	err := cc.rw.Flush()
	cc.wmu.Unlock()
	if err != nil {
		return ErrFromStdErr(err)
	}
	cc.keepAliveTmr.Reset(keepAliveDuration)

	return nil
}

// Disconnect close and disconnect
// terminate all goroutines and wait to exit
func (cc *CommentConnection) Disconnect() Error {
	if !cc.IsConnected {
		return MakeError(ErrOther, "not connected yet")
	}
	cc.IsConnected = false

	cc.keepAliveTmr.Stop()
	cc.postKeyTmr.Stop()
	cc.heartbeatTmr.Stop()

	for i := 0; i < numCommentConnectionRoutines; i++ {
		cc.termc <- true
	}

	cc.sock.Close()

	cc.ev.ProceedNicoEvent(&Event{
		Type:    EventTypeClose,
		Content: nil,
	})

	return nil
}
<commit_msg>add connectedTime to CommentConnection<commit_after>package nicolive

import (
	"bufio"
	"fmt"
	"html"
	"io/ioutil"
	"net"
	"strconv"
	"strings"
	"sync"
	"time"

	"gopkg.in/xmlpath.v2"
)

const (
	numCommentConnectionRoutines = 2
	keepAliveDuration            = time.Minute
	postKeyDuration              = 10 * time.Second
	heartbeatDuration            = 90 * time.Second
)

// Comment is struct to hold a comment
type Comment struct {
	No          int
	Date        time.Time
	UserID      string
	IsPremium   bool
	IsCommand   bool
	IsStaff     bool
	IsAnonymity bool
	Comment     string
	Mail        string
	Locale      string
	Score       int
}

// CommentConnection is a struct to manage sending/receiving comments.
// This struct automatically submits NULL character to reserve connection and
// get the PostKey, which is necessary for sending comments.
// liveWaku should have connection information which is able to get by fetchInformation()
type CommentConnection struct {
	IsConnected bool
	ConnectedTm time.Time // The time when this connection started

	lv     *LiveWaku
	sock   net.Conn
	ticket string
	svrDu  time.Duration
	block  int

	rw           bufio.ReadWriter
	keepAliveTmr *time.Timer
	postKeyTmr   *time.Timer
	heartbeatTmr *time.Timer
	wmu          sync.Mutex
	termc        chan bool
	ev           EventReceiver
}

// NewCommentConnection returns a pointer to new CommentConnection
func NewCommentConnection(ev EventReceiver) *CommentConnection {
	kat := time.NewTimer(keepAliveDuration)
	kat.Stop()
	pkt := time.NewTimer(postKeyDuration)
	pkt.Stop()
	hbt := time.NewTimer(heartbeatDuration)
	hbt.Stop()

	if ev == nil {
		ev = &defaultEventReceiver{}
	}

	return &CommentConnection{
		termc:        make(chan bool),
		keepAliveTmr: kat,
		postKeyTmr:   pkt,
		heartbeatTmr: hbt,
		ev:           ev,
	}
}

// SetLv sets lv with given pointer to LiveWaku
func (cc *CommentConnection) SetLv(l *LiveWaku) Error {
	if cc.IsConnected {
		return MakeError(ErrOther,
			"already connected.\nlv can not be changed while it's connected")
	}

	cc.lv = l
	return nil
}

func (cc *CommentConnection) open() Error {
	if cc.lv.Account == nil {
		return MakeError(ErrOther, "nil account in LiveWaku")
	}
	if cc.lv.BroadID == "" {
		return MakeError(ErrOther, "BroadID is not set")
	}

	var err error

	addrport := fmt.Sprintf("%s:%s",
		cc.lv.CommentServer.Addr,
		cc.lv.CommentServer.Port)

	cc.wmu.Lock()

	cc.sock, err = net.Dial("tcp", addrport)
	if err != nil {
		return ErrFromStdErr(err)
	}

	cc.rw = bufio.ReadWriter{
		Reader: bufio.NewReader(cc.sock),
		Writer: bufio.NewWriter(cc.sock),
	}

	_, err = fmt.Fprintf(cc.rw,
		"<thread thread=\"%s\" res_from=\"-1000\" version=\"20061206\" />\x00",
		cc.lv.CommentServer.Thread)
	if err != nil {
		return ErrFromStdErr(err)
	}
	err = cc.rw.Flush()
	if err != nil {
		return ErrFromStdErr(err)
	}

	cc.wmu.Unlock()

	return nil
}

// Connect Connect to nicolive and start receiving comment
func (cc *CommentConnection) Connect() Error {
	if cc.IsConnected {
		return MakeError(ErrOther, "already connected")
	}
	cc.IsConnected = true

	nerr := cc.open()
	if nerr != nil {
		return nerr
	}
	cc.keepAliveTmr.Reset(keepAliveDuration)

	go cc.receiveStream()
	go cc.timer()

	return nil
}

func (cc *CommentConnection) receiveStream() {
	for {
		select {
		case <-cc.termc:
			return
		default:
			cc.sock.SetReadDeadline(time.Now().Add(time.Second))
			commxml, err := cc.rw.ReadString('\x00')
			if err != nil {
				nerr, ok := err.(net.Error)
				if ok && nerr.Timeout() && nerr.Temporary() {
					continue
				}

				if cc.IsConnected {
					go cc.Disconnect()
				}
				cc.ev.ProceedNicoEvent(&Event{
					Type:    EventTypeErr,
					Content: ErrFromStdErr(err),
				})
				<-cc.termc
				return
			}

			// strip null char
			commxml = commxml[:len(commxml)-1]

			commxmlr := strings.NewReader(commxml)
			rt, err := xmlpath.Parse(commxmlr)
			if err != nil {
				cc.ev.ProceedNicoEvent(&Event{
					Type:    EventTypeErr,
					Content: ErrFromStdErr(err),
				})
				continue
			}

			if strings.HasPrefix(commxml, "<thread ") {
				if v, ok := xmlpath.MustCompile("/thread/@last_res").String(rt); ok {
					lbl, _ := strconv.Atoi(v)
					cc.block = lbl / 10
				}
				if v, ok := xmlpath.MustCompile("/thread/@ticket").String(rt); ok {
					cc.ticket = v
				}
				if v, ok := xmlpath.MustCompile("/thread/@server_time").String(rt); ok {
					i, _ := strconv.ParseInt(v, 10, 64)
					cc.ConnectedTm = time.Unix(i, 0)
					cc.svrDu = cc.ConnectedTm.Sub(time.Now())
				}

				// immediately update postkey and start the timer
				cc.postKeyTmr.Reset(0)
				cc.heartbeatTmr.Reset(0)

				cc.ev.ProceedNicoEvent(&Event{
					Type:    EventTypeOpen,
					Content: nil,
				})

				continue
			}
			if strings.HasPrefix(commxml, "<chat_result ") {
				if v, ok := xmlpath.MustCompile("/chat_result/@status").String(rt); ok {
					if v != "0" {
						cc.ev.ProceedNicoEvent(&Event{
							Type:    EventTypeErr,
							Content: MakeError(ErrSendComment, "comment send error. chat_result status : "+v),
						})
						continue
					}
					cc.ev.ProceedNicoEvent(&Event{
						Type:    EventTypeSend,
						Content: nil,
					})
				}
				continue
			}
			if strings.HasPrefix(commxml, "<chat ") {
				var comment Comment

				if v, ok := xmlpath.MustCompile("/chat").String(rt); ok {
					comment.Comment = html.UnescapeString(v)
				}
				if v, ok := xmlpath.MustCompile("/chat/@no").String(rt); ok {
					comment.No, _ = strconv.Atoi(v)
				}
				if d, ok := xmlpath.MustCompile("/chat/@date").String(rt); ok {
					di, _ := strconv.ParseInt(d, 10, 64)
					var udi int64
					if ud, ok := xmlpath.MustCompile("/chat/@date_usec").String(rt); ok {
						udi, _ = strconv.ParseInt(ud, 10, 64)
					}
					comment.Date = time.Unix(di, udi*1000)
				}
				if v, ok := xmlpath.MustCompile("/chat/@mail").String(rt); ok {
					comment.Mail = v
				}
				if v, ok := xmlpath.MustCompile("/chat/@user_id").String(rt); ok {
					comment.UserID = v
				}
				if v, ok := xmlpath.MustCompile("/chat/@premium").String(rt); ok {
					i, _ := strconv.Atoi(v)
					comment.IsPremium = i%2 == 1
					i >>= 1
					comment.IsCommand = i%2 == 1
					i >>= 1
					comment.IsStaff = i%2 == 1
				}
				if v, ok := xmlpath.MustCompile("/chat/@anonymity").String(rt); ok {
					comment.IsAnonymity, _ = strconv.ParseBool(v)
				}
				if v, ok := xmlpath.MustCompile("/chat/@locale").String(rt); ok {
					comment.Locale = v
				}
				if v, ok := xmlpath.MustCompile("/chat/@score").String(rt); ok {
					comment.Score, _ = strconv.Atoi(v)
				}

				blk := comment.No / 10
				if blk > cc.block {
					cc.block = blk
					cc.postKeyTmr.Reset(0)
				}

				cc.ev.ProceedNicoEvent(&Event{
					Type:    EventTypeGot,
					Content: comment,
				})

				if comment.IsCommand && comment.Comment == "/disconnect" {
					go cc.Disconnect()

					cc.ev.ProceedNicoEvent(&Event{
						Type:    EventTypeWakuEnd,
						Content: *cc.lv,
					})

					<-cc.termc
					return
				}
				continue
			}

			cc.ev.ProceedNicoEvent(&Event{
				Type:    EventTypeErr,
				Content: MakeError(ErrSendComment, "unknown stream : "+commxml),
			})

		}
	}
}

func (cc *CommentConnection) timer() {
	for {
		select {
		case <-cc.termc:
			return
		case <-cc.keepAliveTmr.C:
			cc.keepAliveTmr.Reset(keepAliveDuration)
			cc.wmu.Lock()
			err := cc.rw.WriteByte(0)
			if err == nil {
				err = cc.rw.Flush()
			}
			cc.wmu.Unlock()
			if err != nil {
				cc.ev.ProceedNicoEvent(&Event{
					Type:    EventTypeErr,
					Content: MakeError(ErrConnection, "keep alive : "+err.Error()),
				})
				continue
			}
		case <-cc.postKeyTmr.C:
			cc.postKeyTmr.Reset(postKeyDuration)
			nerr := cc.FetchPostKey()
			if nerr != nil {
				cc.ev.ProceedNicoEvent(&Event{
					Type:    EventTypeErr,
					Content: nerr,
				})
				continue
			}
		case <-cc.heartbeatTmr.C:
			cc.heartbeatTmr.Reset(heartbeatDuration)
			hbv, nerr := cc.lv.FetchHeartBeat()
			if nerr != nil {
				cc.ev.ProceedNicoEvent(&Event{
					Type:    EventTypeErr,
					Content: nerr,
				})
				continue
			}
			cc.ev.ProceedNicoEvent(&Event{
				Type:    EventTypeHeartBeatGot,
				Content: hbv,
			})
		}
	}
}

// FetchPostKey gets postkey using getpostkey API
func (cc *CommentConnection) FetchPostKey() Error {
	if cc.lv.Account == nil {
		return MakeError(ErrOther, "nil account in LiveWaku")
	}
	if cc.lv.BroadID == "" {
		return MakeError(ErrOther, "BroadID is not set")
	}

	c, nicoerr := NewNicoClient(cc.lv.Account)
	if nicoerr != nil {
		return nicoerr
	}

	url := fmt.Sprintf(
		"http://live.nicovideo.jp/api/getpostkey?thread=%s&block_no=%d",
		cc.lv.CommentServer.Thread, cc.block)
	res, err := c.Get(url)
	if err != nil {
		return ErrFromStdErr(err)
	}
	defer res.Body.Close()

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

	pk := string(allb[8:])
	if pk == "" {
		return MakeError(ErrOther, "failed to get postkey")
	}

	cc.lv.PostKey = pk

	return nil
}

// SendComment sends comment to current comment connection
func (cc *CommentConnection) SendComment(text string, iyayo bool) Error {
	if !cc.IsConnected {
		return MakeError(ErrOther, "not connected")
	}
	if cc.lv.PostKey == "" {
		return MakeError(ErrOther, "no postkey in livewaku")
	}
	if text == "" {
		return MakeError(ErrOther, "empty text")
	}

	vpos := 100 *
		(time.Now().Add(cc.svrDu).Unix() - cc.lv.Stream.OpenTime.Unix())

	var iyayos string
	if iyayo {
		iyayos = " mail=\"184\""
	}
	var prems string
	if cc.lv.User.IsPremium {
		prems = " premium=\"1\""
	}

	sdcomm := fmt.Sprintf("<chat thread=\"%s\" ticket=\"%s\" "+
		"vpos=\"%d\" postkey=\"%s\"%s user_id=\"%s\"%s>%s</chat>\x00",
		cc.lv.CommentServer.Thread,
		cc.ticket,
		vpos,
		cc.lv.PostKey,
		iyayos,
		cc.lv.User.UserID,
		prems,
		html.EscapeString(text))

	fmt.Println(sdcomm)

	cc.wmu.Lock()
	fmt.Fprint(cc.rw, sdcomm)
	err := cc.rw.Flush()
	cc.wmu.Unlock()
	if err != nil {
		return ErrFromStdErr(err)
	}
	cc.keepAliveTmr.Reset(keepAliveDuration)

	return nil
}

// Disconnect close and disconnect
// terminate all goroutines and wait to exit
func (cc *CommentConnection) Disconnect() Error {
	if !cc.IsConnected {
		return MakeError(ErrOther, "not connected yet")
	}
	cc.IsConnected = false

	cc.keepAliveTmr.Stop()
	cc.postKeyTmr.Stop()
	cc.heartbeatTmr.Stop()

	for i := 0; i < numCommentConnectionRoutines; i++ {
		cc.termc <- true
	}

	cc.sock.Close()

	cc.ev.ProceedNicoEvent(&Event{
		Type:    EventTypeClose,
		Content: nil,
	})

	return nil
}
<|endoftext|>


<commit_before>// +build !linux

/*
Copyright 2017 The Kubernetes Authors.

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.
*/

// Dummy implementation. Real one should be built on linux.

package kubemark

import (
	apiv1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/resource"
	"k8s.io/autoscaler/cluster-autoscaler/cloudprovider"
	"k8s.io/autoscaler/cluster-autoscaler/utils/errors"
)

const (
	// ProviderName is the cloud provider name for kubemark
	ProviderName = "kubemark"
)

type KubemarkCloudProvider struct{}

func BuildKubemarkCloudProvider(kubemarkController interface{}, specs []string, resourceLimiter *cloudprovider.ResourceLimiter) (*KubemarkCloudProvider, error) {
	return nil, cloudprovider.ErrNotImplemented
}

func (kubemark *KubemarkCloudProvider) Name() string { return "" }

func (kubemark *KubemarkCloudProvider) NodeGroups() []cloudprovider.NodeGroup {
	return []cloudprovider.NodeGroup{}
}

func (kubemark *KubemarkCloudProvider) Pricing() (cloudprovider.PricingModel, errors.AutoscalerError) {
	return nil, cloudprovider.ErrNotImplemented
}

func (kubemark *KubemarkCloudProvider) NodeGroupForNode(node *apiv1.Node) (cloudprovider.NodeGroup, error) {
	return nil, cloudprovider.ErrNotImplemented
}

func (kubemark *KubemarkCloudProvider) GetAvailableMachineTypes() ([]string, error) {
	return []string{}, cloudprovider.ErrNotImplemented
}

func (kubemark *KubemarkCloudProvider) NewNodeGroup(machineType string, labels map[string]string, systemLabels map[string]string,
	extraResources map[string]resource.Quantity) (cloudprovider.NodeGroup, error) {
	return nil, cloudprovider.ErrNotImplemented
}

// GetResourceLimiter returns struct containing limits (max, min) for resources (cores, memory etc.).
func (kubemark *KubemarkCloudProvider) GetResourceLimiter() (*cloudprovider.ResourceLimiter, error) {
	return nil, cloudprovider.ErrNotImplemented
}

// Refresh is called before every main loop and can be used to dynamically update cloud provider state.
// In particular the list of node groups returned by NodeGroups can change as a result of CloudProvider.Refresh().
func (kubemark *KubemarkCloudProvider) Refresh() error {
	return cloudprovider.ErrNotImplemented
}

// Cleanup cleans up all resources before the cloud provider is removed
func (kubemark *KubemarkCloudProvider) Cleanup() error {
	return cloudprovider.ErrNotImplemented
}
<commit_msg>Kubemark cloud provider doesn't compile on Mac<commit_after>// +build !linux

/*
Copyright 2017 The Kubernetes Authors.

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.
*/

// Dummy implementation. Real one should be built on linux.

package kubemark

import (
	apiv1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/resource"
	"k8s.io/autoscaler/cluster-autoscaler/cloudprovider"
	"k8s.io/autoscaler/cluster-autoscaler/utils/errors"
)

const (
	// ProviderName is the cloud provider name for kubemark
	ProviderName = "kubemark"
)

type KubemarkCloudProvider struct{}

func BuildKubemarkCloudProvider(kubemarkController interface{}, specs []string, resourceLimiter *cloudprovider.ResourceLimiter) (*KubemarkCloudProvider, error) {
	return nil, cloudprovider.ErrNotImplemented
}

func (kubemark *KubemarkCloudProvider) Name() string { return "" }

func (kubemark *KubemarkCloudProvider) NodeGroups() []cloudprovider.NodeGroup {
	return []cloudprovider.NodeGroup{}
}

func (kubemark *KubemarkCloudProvider) Pricing() (cloudprovider.PricingModel, errors.AutoscalerError) {
	return nil, cloudprovider.ErrNotImplemented
}

func (kubemark *KubemarkCloudProvider) NodeGroupForNode(node *apiv1.Node) (cloudprovider.NodeGroup, error) {
	return nil, cloudprovider.ErrNotImplemented
}

func (kubemark *KubemarkCloudProvider) GetAvailableMachineTypes() ([]string, error) {
	return []string{}, cloudprovider.ErrNotImplemented
}

func (kubemark *KubemarkCloudProvider) NewNodeGroup(machineType string, labels map[string]string, systemLabels map[string]string,
	taints []apiv1.Taint,
	extraResources map[string]resource.Quantity) (cloudprovider.NodeGroup, error) {
	return nil, cloudprovider.ErrNotImplemented
}

// GetResourceLimiter returns struct containing limits (max, min) for resources (cores, memory etc.).
func (kubemark *KubemarkCloudProvider) GetResourceLimiter() (*cloudprovider.ResourceLimiter, error) {
	return nil, cloudprovider.ErrNotImplemented
}

// Refresh is called before every main loop and can be used to dynamically update cloud provider state.
// In particular the list of node groups returned by NodeGroups can change as a result of CloudProvider.Refresh().
func (kubemark *KubemarkCloudProvider) Refresh() error {
	return cloudprovider.ErrNotImplemented
}

// Cleanup cleans up all resources before the cloud provider is removed
func (kubemark *KubemarkCloudProvider) Cleanup() error {
	return cloudprovider.ErrNotImplemented
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Knative Authors

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 tracker

import (
	"regexp"
	"testing"
	"time"

	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/tools/cache"

	. "github.com/knative/pkg/testing"
)

func TestHappyPaths(t *testing.T) {
	calls := 0
	f := func(key string) {
		calls = calls + 1
	}

	trk := New(f, 10*time.Millisecond)

	thing1 := &Resource{
		TypeMeta: metav1.TypeMeta{
			APIVersion: "ref.knative.dev/v1alpha1",
			Kind:       "Thing1",
		},
		ObjectMeta: metav1.ObjectMeta{
			Namespace: "ns",
			Name:      "foo",
		},
	}
	objRef := objectReference(thing1)

	thing2 := &Resource{
		TypeMeta: metav1.TypeMeta{
			APIVersion: "reffer.knative.dev/v1alpha1",
			Kind:       "Thing2",
		},
		ObjectMeta: metav1.ObjectMeta{
			Namespace: "default",
			Name:      "bar.baz.this-is-fine",
		},
	}

	t.Run("Not tracked yet", func(t *testing.T) {
		trk.OnChanged(thing1)
		if got, want := calls, 0; got != want {
			t.Errorf("OnChanged() = %v, wanted %v", got, want)
		}
	})

	t.Run("Tracked gets called", func(t *testing.T) {
		if err := trk.Track(objRef, thing2); err != nil {
			t.Errorf("Track() = %v", err)
		}
		// New registrations should result in an immediate callback.
		if got, want := calls, 1; got != want {
			t.Errorf("Track() = %v, wanted %v", got, want)
		}

		trk.OnChanged(thing1)
		if got, want := calls, 2; got != want {
			t.Errorf("OnChanged() = %v, wanted %v", got, want)
		}
	})

	t.Run("Still gets called", func(t *testing.T) {
		trk.OnChanged(thing1)
		if got, want := calls, 3; got != want {
			t.Errorf("OnChanged() = %v, wanted %v", got, want)
		}
	})

	// Check that after the sleep duration, we stop getting called.
	time.Sleep(20 * time.Millisecond)
	t.Run("Stops getting called", func(t *testing.T) {
		trk.OnChanged(thing1)
		if got, want := calls, 3; got != want {
			t.Errorf("OnChanged() = %v, wanted %v", got, want)
		}
		if _, stillThere := trk.(*impl).mapping[objRef]; stillThere {
			t.Error("Timeout passed, but mapping for objectReference is still there")
		}
	})

	t.Run("Starts getting called again", func(t *testing.T) {
		if err := trk.Track(objRef, thing2); err != nil {
			t.Errorf("Track() = %v", err)
		}
		// New registrations should result in an immediate callback.
		if got, want := calls, 4; got != want {
			t.Errorf("Track() = %v, wanted %v", got, want)
		}

		trk.OnChanged(thing1)
		if got, want := calls, 5; got != want {
			t.Errorf("OnChanged() = %v, wanted %v", got, want)
		}
	})

	t.Run("OnChanged non-accessor", func(t *testing.T) {
		// Check that passing in a resource that doesn't implement
		// accessor won't panic.
		trk.OnChanged("not an accessor")

		if got, want := calls, 5; got != want {
			t.Errorf("OnChanged() = %v, wanted %v", got, want)
		}
	})

	t.Run("OnChanged non-accessor in DeletedFinalStateUnknown", func(t *testing.T) {
		// Check that passing in a DeletedFinalStateUnknown instance
		// with a resource that doesn't implement accessor won't get
		// Tracked called, and won't panic.
		trk.OnChanged(cache.DeletedFinalStateUnknown{
			Key: "ns/foo",
			Obj: "not an accessor",
		})

		if got, want := calls, 5; got != want {
			t.Errorf("OnChanged() = %v, wanted %v", got, want)
		}
	})

	t.Run("Tracked gets called by DeletedFinalStateUnknown", func(t *testing.T) {
		trk.OnChanged(cache.DeletedFinalStateUnknown{
			Key: "ns/foo",
			Obj: thing1,
		})
		if got, want := calls, 6; got != want {
			t.Errorf("OnChanged() = %v, wanted %v", got, want)
		}
	})

	t.Run("Track bad object", func(t *testing.T) {
		if err := trk.Track(objRef, struct{}{}); err == nil {
			t.Error("Track() = nil, wanted error")
		}
	})
}

func TestAllowedObjectReferences(t *testing.T) {
	trk := New(func(key string) {}, 10*time.Millisecond)
	thing1 := &Resource{
		TypeMeta: metav1.TypeMeta{
			APIVersion: "ref.knative.dev/v1alpha1",
			Kind:       "Thing1",
		},
		ObjectMeta: metav1.ObjectMeta{
			Namespace: "ns",
			Name:      "foo",
		},
	}
	tests := []struct {
		name   string
		objRef corev1.ObjectReference
	}{{
		name: "Pod",
		objRef: corev1.ObjectReference{
			APIVersion: "v1",
			Kind:       "Pod",
			Namespace:  "default",
			Name:       "test",
		},
	}, {
		name: "Non-core resource",
		objRef: corev1.ObjectReference{
			APIVersion: "custom.example.com/v1alpha17",
			Kind:       "Widget",
			Namespace:  "default",
			Name:       "test",
		},
	}, {
		name: "Complex Kind",
		objRef: corev1.ObjectReference{
			APIVersion: "custom.example.com/v1alpha17",
			Kind:       "Widget_v3",
			Namespace:  "default",
			Name:       "test",
		},
	}, {
		name: "Dashed Namespace",
		objRef: corev1.ObjectReference{
			APIVersion: "v1",
			Kind:       "ConfigMap",
			Namespace:  "not-default",
			Name:       "test",
		},
	}, {
		name: "Complex Name",
		objRef: corev1.ObjectReference{
			APIVersion: "v1",
			Kind:       "ConfigMap",
			Namespace:  "default",
			Name:       "test.example.cluster.local",
		},
	}}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			if err := trk.Track(test.objRef, thing1); err != nil {
				t.Errorf("Track() on %v returned error: %v", test.objRef, err)
			}
		})
	}
}

func TestBadObjectReferences(t *testing.T) {
	trk := New(func(key string) {}, 10*time.Millisecond)
	thing1 := &Resource{
		TypeMeta: metav1.TypeMeta{
			APIVersion: "ref.knative.dev/v1alpha1",
			Kind:       "Thing1",
		},
		ObjectMeta: metav1.ObjectMeta{
			Namespace: "ns",
			Name:      "foo",
		},
	}

	tests := []struct {
		name   string
		objRef corev1.ObjectReference
		match  string
	}{{
		name: "Missing APIVersion",
		objRef: corev1.ObjectReference{
			// APIVersion: "build.knative.dev/v1alpha1",
			Kind:      "Build",
			Namespace: "default",
			Name:      "kaniko",
		},
		match: "APIVersion",
	}, {
		name: "Bad char in APIVersion",
		objRef: corev1.ObjectReference{
			APIVersion: "build.knative.dev%v1alpha1",
			Kind:       "Build",
			Namespace:  "default",
			Name:       "kaniko",
		},
		match: "APIVersion",
	}, {
		name: "Extra slashes in APIVersion",
		objRef: corev1.ObjectReference{
			APIVersion: "build.knative.dev/v1/alpha1",
			Kind:       "Build",
			Namespace:  "default",
			Name:       "kaniko",
		},
		match: "APIVersion",
	}, {
		name: "Missing Kind",
		objRef: corev1.ObjectReference{
			APIVersion: "build.knative.dev/v1alpha1",
			// Kind:      "Build",
			Namespace: "default",
			Name:      "kaniko",
		},
		match: "Kind",
	}, {
		name: "Invalid Kind",
		objRef: corev1.ObjectReference{
			APIVersion: "build.knative.dev/v1alpha1",
			Kind:       "Build.1",
			Namespace:  "default",
			Name:       "kaniko",
		},
		match: "Kind",
	}, {
		name: "Missing Namespace",
		objRef: corev1.ObjectReference{
			APIVersion: "build.knative.dev/v1alpha1",
			Kind:       "Build",
			// Namespace: "default",
			Name: "kaniko",
		},
		match: "Namespace",
	}, {
		name: "Capital in Namespace",
		objRef: corev1.ObjectReference{
			APIVersion: "build.knative.dev/v1alpha1",
			Kind:       "Build",
			Namespace:  "Default",
			Name:       "kaniko",
		},
		match: "Namespace",
	}, {
		name: "Domain-separated Namespace",
		objRef: corev1.ObjectReference{
			APIVersion: "build.knative.dev/v1alpha1",
			Kind:       "Build",
			Namespace:  "not.default",
			Name:       "kaniko",
		},
		match: "Namespace",
	}, {
		name: "Missing Name",
		objRef: corev1.ObjectReference{
			APIVersion: "build.knative.dev/v1alpha1",
			Kind:       "Build",
			Namespace:  "default",
			// Name:      "kaniko",
		},
		match: "Name",
	}, {
		name: "Capital in Name",
		objRef: corev1.ObjectReference{
			APIVersion: "build.knative.dev/v1alpha1",
			Kind:       "Build",
			Namespace:  "default",
			Name:       "Kaniko",
		},
		match: "Name",
	}, {
		name: "Bad char in Name",
		objRef: corev1.ObjectReference{
			APIVersion: "build.knative.dev/v1alpha1",
			Kind:       "Build",
			Namespace:  "default",
			Name:       "kaniko_small",
		},
		match: "Name",
	}, {
		name:   "Missing All",
		objRef: corev1.ObjectReference{
			// APIVersion: "build.knative.dev/v1alpha1",
			// Kind:       "Build",
			// Namespace:  "default",
			// Name:      "kaniko",
		},
		match: "\nAPIVersion:.*\nKind:.*\nName:.*\nNamespace:",
	}}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			if err := trk.Track(test.objRef, thing1); err == nil {
				t.Error("Track() = nil, wanted error")
			} else {
				match, e2 := regexp.Match(test.match, []byte(err.Error()))
				if e2 != nil {
					t.Errorf("Failed to compile %q: %v", e2, test.match)
				} else if !match {
					t.Errorf("Track() = %v, wanted match: %s", err, test.match)
				}
			}
		})
	}
}
<commit_msg>Refactor the tracker testing. (#483)<commit_after>/*
Copyright 2018 The Knative Authors

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 tracker

import (
	"regexp"
	"testing"
	"time"

	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/tools/cache"

	. "github.com/knative/pkg/testing"
)

func TestHappyPaths(t *testing.T) {
	calls := 0
	f := func(key string) {
		calls = calls + 1
	}

	trk := New(f, 100*time.Millisecond)

	thing1 := &Resource{
		TypeMeta: metav1.TypeMeta{
			APIVersion: "ref.knative.dev/v1alpha1",
			Kind:       "Thing1",
		},
		ObjectMeta: metav1.ObjectMeta{
			Namespace: "ns",
			Name:      "foo",
		},
	}
	objRef := objectReference(thing1)

	thing2 := &Resource{
		TypeMeta: metav1.TypeMeta{
			APIVersion: "reffer.knative.dev/v1alpha1",
			Kind:       "Thing2",
		},
		ObjectMeta: metav1.ObjectMeta{
			Namespace: "default",
			Name:      "bar.baz.this-is-fine",
		},
	}

	// Not tracked yet
	{
		trk.OnChanged(thing1)
		if got, want := calls, 0; got != want {
			t.Errorf("OnChanged() = %v, wanted %v", got, want)
		}
	}

	// Tracked gets called
	{
		if err := trk.Track(objRef, thing2); err != nil {
			t.Errorf("Track() = %v", err)
		}
		// New registrations should result in an immediate callback.
		if got, want := calls, 1; got != want {
			t.Errorf("Track() = %v, wanted %v", got, want)
		}

		trk.OnChanged(thing1)
		if got, want := calls, 2; got != want {
			t.Errorf("OnChanged() = %v, wanted %v", got, want)
		}
	}

	// Still gets called
	{
		trk.OnChanged(thing1)
		if got, want := calls, 3; got != want {
			t.Errorf("OnChanged() = %v, wanted %v", got, want)
		}
	}

	// Check that after the sleep duration, we stop getting called.
	time.Sleep(200 * time.Millisecond)
	{
		trk.OnChanged(thing1)
		if got, want := calls, 3; got != want {
			t.Errorf("OnChanged() = %v, wanted %v", got, want)
		}
		if _, stillThere := trk.(*impl).mapping[objRef]; stillThere {
			t.Error("Timeout passed, but mapping for objectReference is still there")
		}
	}

	// Starts getting called again
	{
		if err := trk.Track(objRef, thing2); err != nil {
			t.Errorf("Track() = %v", err)
		}
		// New registrations should result in an immediate callback.
		if got, want := calls, 4; got != want {
			t.Errorf("Track() = %v, wanted %v", got, want)
		}

		trk.OnChanged(thing1)
		if got, want := calls, 5; got != want {
			t.Errorf("OnChanged() = %v, wanted %v", got, want)
		}
	}

	// OnChanged non-accessor
	{
		// Check that passing in a resource that doesn't implement
		// accessor won't panic.
		trk.OnChanged("not an accessor")

		if got, want := calls, 5; got != want {
			t.Errorf("OnChanged() = %v, wanted %v", got, want)
		}
	}

	// OnChanged non-accessor in DeletedFinalStateUnknown
	{
		// Check that passing in a DeletedFinalStateUnknown instance
		// with a resource that doesn't implement accessor won't get
		// Tracked called, and won't panic.
		trk.OnChanged(cache.DeletedFinalStateUnknown{
			Key: "ns/foo",
			Obj: "not an accessor",
		})

		if got, want := calls, 5; got != want {
			t.Errorf("OnChanged() = %v, wanted %v", got, want)
		}
	}

	// Tracked gets called by DeletedFinalStateUnknown
	{
		trk.OnChanged(cache.DeletedFinalStateUnknown{
			Key: "ns/foo",
			Obj: thing1,
		})
		if got, want := calls, 6; got != want {
			t.Errorf("OnChanged() = %v, wanted %v", got, want)
		}
	}

	// Track bad object
	{
		if err := trk.Track(objRef, struct{}{}); err == nil {
			t.Error("Track() = nil, wanted error")
		}
	}
}

func TestAllowedObjectReferences(t *testing.T) {
	trk := New(func(key string) {}, 10*time.Millisecond)
	thing1 := &Resource{
		TypeMeta: metav1.TypeMeta{
			APIVersion: "ref.knative.dev/v1alpha1",
			Kind:       "Thing1",
		},
		ObjectMeta: metav1.ObjectMeta{
			Namespace: "ns",
			Name:      "foo",
		},
	}
	tests := []struct {
		name   string
		objRef corev1.ObjectReference
	}{{
		name: "Pod",
		objRef: corev1.ObjectReference{
			APIVersion: "v1",
			Kind:       "Pod",
			Namespace:  "default",
			Name:       "test",
		},
	}, {
		name: "Non-core resource",
		objRef: corev1.ObjectReference{
			APIVersion: "custom.example.com/v1alpha17",
			Kind:       "Widget",
			Namespace:  "default",
			Name:       "test",
		},
	}, {
		name: "Complex Kind",
		objRef: corev1.ObjectReference{
			APIVersion: "custom.example.com/v1alpha17",
			Kind:       "Widget_v3",
			Namespace:  "default",
			Name:       "test",
		},
	}, {
		name: "Dashed Namespace",
		objRef: corev1.ObjectReference{
			APIVersion: "v1",
			Kind:       "ConfigMap",
			Namespace:  "not-default",
			Name:       "test",
		},
	}, {
		name: "Complex Name",
		objRef: corev1.ObjectReference{
			APIVersion: "v1",
			Kind:       "ConfigMap",
			Namespace:  "default",
			Name:       "test.example.cluster.local",
		},
	}}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			if err := trk.Track(test.objRef, thing1); err != nil {
				t.Errorf("Track() on %v returned error: %v", test.objRef, err)
			}
		})
	}
}

func TestBadObjectReferences(t *testing.T) {
	trk := New(func(key string) {}, 10*time.Millisecond)
	thing1 := &Resource{
		TypeMeta: metav1.TypeMeta{
			APIVersion: "ref.knative.dev/v1alpha1",
			Kind:       "Thing1",
		},
		ObjectMeta: metav1.ObjectMeta{
			Namespace: "ns",
			Name:      "foo",
		},
	}

	tests := []struct {
		name   string
		objRef corev1.ObjectReference
		match  string
	}{{
		name: "Missing APIVersion",
		objRef: corev1.ObjectReference{
			// APIVersion: "build.knative.dev/v1alpha1",
			Kind:      "Build",
			Namespace: "default",
			Name:      "kaniko",
		},
		match: "APIVersion",
	}, {
		name: "Bad char in APIVersion",
		objRef: corev1.ObjectReference{
			APIVersion: "build.knative.dev%v1alpha1",
			Kind:       "Build",
			Namespace:  "default",
			Name:       "kaniko",
		},
		match: "APIVersion",
	}, {
		name: "Extra slashes in APIVersion",
		objRef: corev1.ObjectReference{
			APIVersion: "build.knative.dev/v1/alpha1",
			Kind:       "Build",
			Namespace:  "default",
			Name:       "kaniko",
		},
		match: "APIVersion",
	}, {
		name: "Missing Kind",
		objRef: corev1.ObjectReference{
			APIVersion: "build.knative.dev/v1alpha1",
			// Kind:      "Build",
			Namespace: "default",
			Name:      "kaniko",
		},
		match: "Kind",
	}, {
		name: "Invalid Kind",
		objRef: corev1.ObjectReference{
			APIVersion: "build.knative.dev/v1alpha1",
			Kind:       "Build.1",
			Namespace:  "default",
			Name:       "kaniko",
		},
		match: "Kind",
	}, {
		name: "Missing Namespace",
		objRef: corev1.ObjectReference{
			APIVersion: "build.knative.dev/v1alpha1",
			Kind:       "Build",
			// Namespace: "default",
			Name: "kaniko",
		},
		match: "Namespace",
	}, {
		name: "Capital in Namespace",
		objRef: corev1.ObjectReference{
			APIVersion: "build.knative.dev/v1alpha1",
			Kind:       "Build",
			Namespace:  "Default",
			Name:       "kaniko",
		},
		match: "Namespace",
	}, {
		name: "Domain-separated Namespace",
		objRef: corev1.ObjectReference{
			APIVersion: "build.knative.dev/v1alpha1",
			Kind:       "Build",
			Namespace:  "not.default",
			Name:       "kaniko",
		},
		match: "Namespace",
	}, {
		name: "Missing Name",
		objRef: corev1.ObjectReference{
			APIVersion: "build.knative.dev/v1alpha1",
			Kind:       "Build",
			Namespace:  "default",
			// Name:      "kaniko",
		},
		match: "Name",
	}, {
		name: "Capital in Name",
		objRef: corev1.ObjectReference{
			APIVersion: "build.knative.dev/v1alpha1",
			Kind:       "Build",
			Namespace:  "default",
			Name:       "Kaniko",
		},
		match: "Name",
	}, {
		name: "Bad char in Name",
		objRef: corev1.ObjectReference{
			APIVersion: "build.knative.dev/v1alpha1",
			Kind:       "Build",
			Namespace:  "default",
			Name:       "kaniko_small",
		},
		match: "Name",
	}, {
		name:   "Missing All",
		objRef: corev1.ObjectReference{
			// APIVersion: "build.knative.dev/v1alpha1",
			// Kind:       "Build",
			// Namespace:  "default",
			// Name:      "kaniko",
		},
		match: "\nAPIVersion:.*\nKind:.*\nName:.*\nNamespace:",
	}}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			if err := trk.Track(test.objRef, thing1); err == nil {
				t.Error("Track() = nil, wanted error")
			} else {
				match, e2 := regexp.Match(test.match, []byte(err.Error()))
				if e2 != nil {
					t.Errorf("Failed to compile %q: %v", e2, test.match)
				} else if !match {
					t.Errorf("Track() = %v, wanted match: %s", err, test.match)
				}
			}
		})
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"math/rand"
	"sync"
	"time"

	"github.com/vbauerster/mpb/v4"
	"github.com/vbauerster/mpb/v4/decor"
)

const (
	totalBars = 32
)

func init() {
	rand.Seed(time.Now().UnixNano())
}

func main() {
	var wg sync.WaitGroup
	p := mpb.New(
		mpb.WithWaitGroup(&wg),
		mpb.WithRefreshRate(50*time.Millisecond),
	)
	wg.Add(totalBars)

	for i := 0; i < totalBars; i++ {
		name := fmt.Sprintf("Bar#%02d: ", i)
		total := rand.Intn(320) + 10
		bar := p.AddBar(int64(total),
			mpb.PrependDecorators(
				decor.Name(name),
				decor.EwmaETA(decor.ET_STYLE_GO, 60, decor.WCSyncSpace),
			),
			mpb.AppendDecorators(
				decor.OnComplete(
					decor.Percentage(decor.WC{W: 5}), "done",
				),
			),
		)

		go func() {
			defer wg.Done()
			max := 100 * time.Millisecond
			for !bar.Completed() {
				start := time.Now()
				time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10)
				// ewma based decorators require work duration measurement
				bar.IncrBy(1, time.Since(start))
			}
		}()
	}

	p.Wait()
}
<commit_msg>use Elapsed decorator<commit_after>package main

import (
	"fmt"
	"math/rand"
	"sync"
	"time"

	"github.com/vbauerster/mpb/v4"
	"github.com/vbauerster/mpb/v4/decor"
)

const (
	totalBars = 32
)

func init() {
	rand.Seed(time.Now().UnixNano())
}

func main() {
	var wg sync.WaitGroup
	p := mpb.New(
		mpb.WithWaitGroup(&wg),
		mpb.WithRefreshRate(50*time.Millisecond),
	)
	wg.Add(totalBars)

	for i := 0; i < totalBars; i++ {
		name := fmt.Sprintf("Bar#%02d: ", i)
		total := rand.Intn(320) + 10
		bar := p.AddBar(int64(total),
			mpb.PrependDecorators(
				decor.Name(name),
				decor.Elapsed(decor.ET_STYLE_GO, decor.WCSyncSpace),
			),
			mpb.AppendDecorators(
				decor.OnComplete(
					decor.Percentage(decor.WC{W: 5}), "done",
				),
			),
		)

		go func() {
			defer wg.Done()
			max := 100 * time.Millisecond
			for !bar.Completed() {
				start := time.Now()
				time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10)
				// ewma based decorators require work duration measurement
				bar.IncrBy(1, time.Since(start))
			}
		}()
	}

	p.Wait()
}
<|endoftext|>


<commit_before>package psi

import (
	"github.com/ziutek/dvb"
	"github.com/ziutek/dvb/ts"
)

var (
	ErrSectionLength   = dvb.TemporaryError("incorrect value of section_length field")
	ErrSectionPointer  = dvb.TemporaryError("incorrect pointer_field")
	ErrSectionSpace    = dvb.TemporaryError("no free space for section decoding")
	ErrSectionCRC      = dvb.TemporaryError("section has incorrect CRC")
	ErrSectionReserved = dvb.TemporaryError("section has wrong value of header reserved bits")
	ErrSectionData     = dvb.TemporaryError("too few data to decode section")
)

// SectionDecoder can decode section from stream of packets
type SectionDecoder struct {
	r        ts.PktReplacer
	pkt      *ts.ArrayPkt
	buffered bool // Not processed data in pkt
	check    bool
}

// NewSectionDecoder creates section decoder. You can use r == nil and
// set source of packets lather using SetPktReplacer or SetPktReader method.
// If check is true decoder checks value of reserved header bits and CRC.
func NewSectionDecoder(r ts.PktReplacer, check bool) *SectionDecoder {
	return &SectionDecoder{r: r, pkt: new(ts.ArrayPkt), check: check}
}

// SetPktReplacer sets ts.PktReplacer that will be used as data source
func (d *SectionDecoder) SetPktReplacer(r ts.PktReplacer) {
	d.r = r
}

// SetPktReader sets ts.PktReader that will be usea as data source
func (d *SectionDecoder) SetPktReader(r ts.PktReader) {
	d.r = ts.PktReaderAsReplacer{r}
}

// Reset resets internal state of decoder (discards possible buffered data for
// next section decoding)
func (d *SectionDecoder) Reset() {
	d.buffered = false
}

// ReadSection decodes one section.
func (d *SectionDecoder) ReadSection(s Section) error {
	if len(s) < 8 {
		panic("section length should be >= 8")
	}
	var (
		p   []byte
		err error
	)

	// Waiting for packet where a payload starts
	for {
		if d.buffered {
			d.buffered = false
		} else {
			if d.pkt, err = d.r.ReplacePkt(d.pkt); err != nil {
				return err
			}
		}
		p = d.pkt.Payload()
		if len(p) == 0 {
			continue
		}
		if d.pkt.Flags().PayloadStart() {
			offset := int(p[0]) + 1
			if offset >= len(p) {
				return ErrSectionPointer
			}
			p = p[offset:]
			break
		}
	}
	// p contains begining of section, n number of bytes copied to s
	n := copy(s[:3], p)
	p = p[n:]
	for n < 3 {
		// p doesn't contain enough data
		if d.pkt, err = d.r.ReplacePkt(d.pkt); err != nil {
			return err
		}
		d.buffered = true // d.pkt contains next packet
		p = d.pkt.Payload()
		k := copy(s[n:3], p)
		p = p[k:]
		n += k
	}
	l := s.Len()
	if l == -1 {
		return ErrSectionLength
	}
	if l > len(s) {
		return ErrSectionSpace
	}
	// Now we know section length, so we can copy data and read next packets
	for {
		k := copy(s[n:l], p)
		n += k
		if n == l {
			break
		}
		if d.pkt, err = d.r.ReplacePkt(d.pkt); err != nil {
			return err
		}
		d.buffered = true // d.pkt contains next packet
		p = d.pkt.Payload()
		if d.pkt.PayloadStart() {
			if len(p) > 0 {
				p = p[1:] // skip pointer_field
			}
		}
	}
	// We read all needed data.
	if d.buffered && !d.pkt.Flags().PayloadStart() {
		d.buffered = false // d.pkt doesn't contain begining of next section.
	}
	if d.check {
		if s.Reserved() != 3 {
			return ErrSectionReserved
		}
		if !s.CheckCRC() {
			return ErrSectionCRC
		}
	}
	return nil
}

/*func (d *SectionDecoder) ReadSection(s Section) error {
	if len(s) < 8 {
		panic("section length should be >= 8")
	}
	n, limit := 0, -1
	for {
		if d.buffered {
			d.buffered = false
		} else {
			var err error
			if d.pkt, err = d.r.ReplacePkt(d.pkt); err != nil {
				return err
			}
		}

		p := d.pkt.Payload()
		if len(p) == 0 {
			continue
		}

		offset := 0
		if d.pkt.Flags().PayloadStart() {
			offset = int(p[0]) + 1
			if offset >= len(p) {
				return ErrSectionPointer
			}
		}

		if n == 0 {
			// Decoding isn't started yet
			if offset == 0 {
				// Section doesn't start in this packet
				continue
			}
			p = p[offset:]
		} else {
			if offset != 0 {
				p = p[1:offset]
				d.buffered = true
			}
		}

		if limit == -1 {
			// Copy only up to the section_length byte
			k := copy(s[n:3], p)
			n += k
			if n < 3 {
				// Can't decode section_length - need more bytes
				continue
			}
			limit = s.Len()
			if limit == -1 {
				return ErrSectionLength
			}
			if limit > len(s) {
				return ErrSectionSpace
			}
			p = p[k:]
		}

		n += copy(s[n:limit], p)

		if n < limit {
			if d.buffered {
				// New section begins in this packet
				return ErrSectionData
			}
			continue
		}

		// Whole section was read
		if s.CheckCRC() {
			break
		}
		return ErrSectionCRC
	}
	return nil
}*/
<commit_msg>psi: Check section syntax indicator before CRC checking<commit_after>package psi

import (
	"github.com/ziutek/dvb"
	"github.com/ziutek/dvb/ts"
)

var (
	ErrSectionLength   = dvb.TemporaryError("incorrect value of section_length field")
	ErrSectionPointer  = dvb.TemporaryError("incorrect pointer_field")
	ErrSectionSpace    = dvb.TemporaryError("no free space for section decoding")
	ErrSectionSyntax   = dvb.TemporaryError("section syntax indicator not set")
	ErrSectionCRC      = dvb.TemporaryError("section has incorrect CRC")
	ErrSectionReserved = dvb.TemporaryError("section has wrong value of header reserved bits")
	ErrSectionData     = dvb.TemporaryError("too few data to decode section")
)

// SectionDecoder can decode section from stream of packets
type SectionDecoder struct {
	r        ts.PktReplacer
	pkt      *ts.ArrayPkt
	buffered bool // Not processed data in pkt
	check    bool
}

// NewSectionDecoder creates section decoder. You can use r == nil and
// set source of packets lather using SetPktReplacer or SetPktReader method.
// If check is true decoder checks value of reserved header bits and CRC.
func NewSectionDecoder(r ts.PktReplacer, check bool) *SectionDecoder {
	return &SectionDecoder{r: r, pkt: new(ts.ArrayPkt), check: check}
}

// SetPktReplacer sets ts.PktReplacer that will be used as data source
func (d *SectionDecoder) SetPktReplacer(r ts.PktReplacer) {
	d.r = r
}

// SetPktReader sets ts.PktReader that will be usea as data source
func (d *SectionDecoder) SetPktReader(r ts.PktReader) {
	d.r = ts.PktReaderAsReplacer{r}
}

// Reset resets internal state of decoder (discards possible buffered data for
// next section decoding)
func (d *SectionDecoder) Reset() {
	d.buffered = false
}

// ReadSection decodes one section.
func (d *SectionDecoder) ReadSection(s Section) error {
	if len(s) < 8 {
		panic("section length should be >= 8")
	}
	var (
		p   []byte
		err error
	)

	// Waiting for packet where a payload starts
	for {
		if d.buffered {
			d.buffered = false
		} else {
			if d.pkt, err = d.r.ReplacePkt(d.pkt); err != nil {
				return err
			}
		}
		p = d.pkt.Payload()
		if len(p) == 0 {
			continue
		}
		if d.pkt.Flags().PayloadStart() {
			offset := int(p[0]) + 1
			if offset >= len(p) {
				return ErrSectionPointer
			}
			p = p[offset:]
			break
		}
	}
	// p contains begining of section, n number of bytes copied to s
	n := copy(s[:3], p)
	p = p[n:]
	for n < 3 {
		// p doesn't contain enough data
		if d.pkt, err = d.r.ReplacePkt(d.pkt); err != nil {
			return err
		}
		d.buffered = true // d.pkt contains next packet
		p = d.pkt.Payload()
		k := copy(s[n:3], p)
		p = p[k:]
		n += k
	}
	l := s.Len()
	if l == -1 {
		return ErrSectionLength
	}
	if l > len(s) {
		return ErrSectionSpace
	}
	// Now we know section length, so we can copy data and read next packets
	for {
		k := copy(s[n:l], p)
		n += k
		if n == l {
			break
		}
		if d.pkt, err = d.r.ReplacePkt(d.pkt); err != nil {
			return err
		}
		d.buffered = true // d.pkt contains next packet
		p = d.pkt.Payload()
		if d.pkt.PayloadStart() {
			if len(p) > 0 {
				p = p[1:] // skip pointer_field
			}
		}
	}
	// We read all needed data.
	if d.buffered && !d.pkt.Flags().PayloadStart() {
		d.buffered = false // d.pkt doesn't contain begining of next section.
	}
	if d.check {
		if s.Reserved() != 3 {
			return ErrSectionReserved
		}
		if !s.GenericSyntax() {
			return ErrSectionSyntax
		}
		if !s.CheckCRC() {
			return ErrSectionCRC
		}
	}
	return nil
}

/*func (d *SectionDecoder) ReadSection(s Section) error {
	if len(s) < 8 {
		panic("section length should be >= 8")
	}
	n, limit := 0, -1
	for {
		if d.buffered {
			d.buffered = false
		} else {
			var err error
			if d.pkt, err = d.r.ReplacePkt(d.pkt); err != nil {
				return err
			}
		}

		p := d.pkt.Payload()
		if len(p) == 0 {
			continue
		}

		offset := 0
		if d.pkt.Flags().PayloadStart() {
			offset = int(p[0]) + 1
			if offset >= len(p) {
				return ErrSectionPointer
			}
		}

		if n == 0 {
			// Decoding isn't started yet
			if offset == 0 {
				// Section doesn't start in this packet
				continue
			}
			p = p[offset:]
		} else {
			if offset != 0 {
				p = p[1:offset]
				d.buffered = true
			}
		}

		if limit == -1 {
			// Copy only up to the section_length byte
			k := copy(s[n:3], p)
			n += k
			if n < 3 {
				// Can't decode section_length - need more bytes
				continue
			}
			limit = s.Len()
			if limit == -1 {
				return ErrSectionLength
			}
			if limit > len(s) {
				return ErrSectionSpace
			}
			p = p[k:]
		}

		n += copy(s[n:limit], p)

		if n < limit {
			if d.buffered {
				// New section begins in this packet
				return ErrSectionData
			}
			continue
		}

		// Whole section was read
		if s.CheckCRC() {
			break
		}
		return ErrSectionCRC
	}
	return nil
}*/
<|endoftext|>


<commit_before>package tuikit

import (
	"fmt"

	"github.com/nsf/tulib"
)

type AnchorEdge uint

const (
	AnchorEdgeTop AnchorEdge = iota
	AnchorEdgeBottom
	AnchorEdgeLeft
	AnchorEdgeRight
)

type AnchoringView struct {
	*BaseView

	anchorEdge  AnchorEdge
	anchorWidth int

	anchor, main Painter
}

func NewAnchoringView(
	anchorEdge AnchorEdge,
	anchorWidth int,
	anchor, main Painter,
) *AnchoringView {
	return &AnchoringView{
		BaseView:    NewBaseView(),
		anchorEdge:  anchorEdge,
		anchorWidth: anchorWidth,
		anchor:      anchor,
		main:        main,
	}
}

func (v *AnchoringView) PaintTo(buffer *tulib.Buffer, rect Rect) error {
	if err := v.calcSizes(rect); err != nil {
		return err
	}

	return v.BaseView.PaintTo(buffer, rect)
}

func (v *AnchoringView) calcSizes(rect Rect) error {
	var (
		x, y, w, h     int = rect.X, rect.Y, rect.Width, rect.Height
		ax, ay, aw, ah int
		mx, my, mw, mh int
	)

	// Set width and height
	switch v.anchorEdge {
	case AnchorEdgeTop, AnchorEdgeBottom:
		aw = w
		ah = v.anchorWidth
		mw = w
		mh = h - v.anchorWidth
	case AnchorEdgeLeft, AnchorEdgeRight:
		aw = v.anchorWidth
		ah = h
		mw = w - v.anchorWidth
		mh = h
	}

	// Set x, y
	switch v.anchorEdge {
	case AnchorEdgeBottom, AnchorEdgeRight:
		ax = x + w - aw
		ay = y + h - ah
		mx = x
		my = y
	case AnchorEdgeTop, AnchorEdgeLeft:
		ax = x
		ay = y
		mx = x + w - mw
		my = y + h - mh
	}

	aRect := NewRect(ax, ay, aw, ah)
	mRect := NewRect(mx, my, mw, mh)

	if !aRect.In(rect) {
		return fmt.Errorf("Anchor too big, anchor: %v, container: %v", aRect, rect)
	}
	if !mRect.In(rect) {
		return fmt.Errorf("Main too big, main: %v, container: %v", mRect, rect)
	}

	v.AttachChild(v.anchor, aRect)
	v.AttachChild(v.main, mRect)
	return nil
}
<commit_msg>AnchoringView.calcSizes only when rect changed<commit_after>package tuikit

import (
	"fmt"

	"github.com/nsf/tulib"
)

type AnchorEdge uint

const (
	AnchorEdgeTop AnchorEdge = iota
	AnchorEdgeBottom
	AnchorEdgeLeft
	AnchorEdgeRight
)

type AnchoringView struct {
	*BaseView

	anchorEdge  AnchorEdge
	anchorWidth int

	anchor, main Painter
}

func NewAnchoringView(
	anchorEdge AnchorEdge,
	anchorWidth int,
	anchor, main Painter,
) *AnchoringView {
	return &AnchoringView{
		BaseView:    NewBaseView(),
		anchorEdge:  anchorEdge,
		anchorWidth: anchorWidth,
		anchor:      anchor,
		main:        main,
	}
}

func (v *AnchoringView) PaintTo(buffer *tulib.Buffer, rect Rect) error {
	if !v.LastPaintedRect.Eq(rect) {
		if err := v.calcSizes(rect); err != nil {
			return err
		}
	}

	return v.BaseView.PaintTo(buffer, rect)
}

func (v *AnchoringView) calcSizes(rect Rect) error {
	var (
		x, y, w, h     int = rect.X, rect.Y, rect.Width, rect.Height
		ax, ay, aw, ah int
		mx, my, mw, mh int
	)

	// Set width and height
	switch v.anchorEdge {
	case AnchorEdgeTop, AnchorEdgeBottom:
		aw = w
		ah = v.anchorWidth
		mw = w
		mh = h - v.anchorWidth
	case AnchorEdgeLeft, AnchorEdgeRight:
		aw = v.anchorWidth
		ah = h
		mw = w - v.anchorWidth
		mh = h
	}

	// Set x, y
	switch v.anchorEdge {
	case AnchorEdgeBottom, AnchorEdgeRight:
		ax = x + w - aw
		ay = y + h - ah
		mx = x
		my = y
	case AnchorEdgeTop, AnchorEdgeLeft:
		ax = x
		ay = y
		mx = x + w - mw
		my = y + h - mh
	}

	aRect := NewRect(ax, ay, aw, ah)
	mRect := NewRect(mx, my, mw, mh)

	if !aRect.In(rect) {
		return fmt.Errorf("Anchor too big, anchor: %v, container: %v", aRect, rect)
	}
	if !mRect.In(rect) {
		return fmt.Errorf("Main too big, main: %v, container: %v", mRect, rect)
	}

	v.AttachChild(v.anchor, aRect)
	v.AttachChild(v.main, mRect)
	return nil
}
<|endoftext|>


<commit_before>package capn

import (
	"bytes"
	"errors"
	"io"
	"math"
)

var (
	errBufferCall     = errors.New("capn: can't call on a memory buffer")
	ErrInvalidSegment = errors.New("capn: invalid segment id")
	ErrTooMuchData    = errors.New("capn: too much data in stream")
)

type buffer Segment

// NewBuffer creates an expanding single segment buffer. Creating new objects
// will expand the buffer. Data can be nil (or length 0 with some capacity) if
// creating a new session. If parsing an existing segment than data should be
// the segment contents and will not be copied.
func NewBuffer(data []byte) *Segment {
	if uint64(len(data)) > uint64(math.MaxUint32) {
		return nil
	}

	b := &buffer{}
	b.Message = b
	b.Data = data
	return (*Segment)(b)
}

func (b *buffer) NewSegment(minsz int) (*Segment, error) {
	if uint64(len(b.Data)) > uint64(math.MaxUint32)-uint64(minsz) {
		return nil, ErrOverlarge
	}
	b.Data = append(b.Data, make([]byte, minsz)...)
	b.Data = b.Data[:len(b.Data)-minsz]
	return (*Segment)(b), nil
}

func (b *buffer) Lookup(segid uint32) (*Segment, error) {
	if segid == 0 {
		return (*Segment)(b), nil
	} else {
		return nil, ErrInvalidSegment
	}
}

type MultiBuffer struct {
	segments []*Segment
}

// NewmultiBuffer creates a new multi segment message. Creating new objects
// will try and reuse the buffers available, but will create new ones if there
// is insufficient capacity. When parsing an existing message data should be
// the list of segments. The data buffers will not be copied.
func NewmultiBuffer(data [][]byte) *Segment {
	m := &MultiBuffer{make([]*Segment, len(data))}
	for i, d := range data {
		m.segments[i] = &Segment{m, d, uint32(i)}
	}
	if len(data) > 0 {
		return m.segments[0]
	}
	return &Segment{m, nil, 0xFFFFFFFF}
}

var (
	MaxSegmentNumber = 1024
	MaxTotalSize     = 1024 * 1024 * 1024
)

func (m *MultiBuffer) NewSegment(minsz int) (*Segment, error) {
	for _, s := range m.segments {
		if len(s.Data)+minsz <= cap(s.Data) {
			return s, nil
		}
	}

	if minsz < 4096 {
		minsz = 4096
	}
	s := &Segment{m, make([]byte, 0, minsz), uint32(len(m.segments))}
	m.segments = append(m.segments, s)
	return s, nil
}

func (m *MultiBuffer) Lookup(segid uint32) (*Segment, error) {
	if uint(segid) < uint(len(m.segments)) {
		return m.segments[segid], nil
	} else {
		return nil, ErrInvalidSegment
	}
}

// ReadFromStream reads a non-packed serialized stream from r. buf is used to
// buffer the read contents, can be nil, and is provided so that the buffer
// can be reused between messages. The returned segment is the first segment
// read, which contains the root pointer.
func ReadFromStream(r io.Reader, buf *bytes.Buffer) (*Segment, error) {
	if buf == nil {
		buf = new(bytes.Buffer)
	} else {
		buf.Reset()
	}

	if _, err := io.CopyN(buf, r, 4); err != nil {
		return nil, err
	}

	if little32(buf.Bytes()[:]) >= uint32(MaxSegmentNumber) {
		return nil, ErrTooMuchData
	}

	segnum := int(little32(buf.Bytes()[:]) + 1)
	hdrsz := 8*(segnum/2) + 4

	if _, err := io.CopyN(buf, r, int64(hdrsz)); err != nil {
		return nil, err
	}

	total := 0
	for i := 0; i < segnum; i++ {
		sz := little32(buf.Bytes()[4*i+4:])
		if uint64(total)+uint64(sz)*8 > uint64(MaxTotalSize) {
			return nil, ErrTooMuchData
		}
		total += int(sz) * 8
	}

	if _, err := io.CopyN(buf, r, int64(total)); err != nil {
		return nil, err
	}

	hdrv := buf.Bytes()[4 : hdrsz+4]
	datav := buf.Bytes()[hdrsz+4:]

	if segnum == 1 {
		sz := int(little32(hdrv)) * 8
		return NewBuffer(datav[:sz]), nil
	}

	m := &MultiBuffer{make([]*Segment, segnum)}
	for i := 0; i < segnum; i++ {
		sz := int(little32(hdrv[4*i:])) * 8
		m.segments[i] = &Segment{m, datav[:sz], uint32(i)}
		datav = datav[sz:]
	}

	return m.segments[0], nil
}

// ReadFromMemoryZeroCopy: like ReadFromStream, but reads a non-packed
// serialized stream that already resides in memory in the argument data.
// The returned segment is the first segment read, which contains
// the root pointer. The returned bytesRead says how many bytes were
// consumed from data in making seg. The caller should advance the
// data slice by doing data = data[bytesRead:] between successive calls
// to ReadFromMemoryZeroCopy().
func ReadFromMemoryZeroCopy(data []byte) (seg *Segment, bytesRead int64, err error) {

	if len(data) < 4 {
		return nil, 0, io.EOF
	}

	if little32(data[0:4]) >= uint32(MaxSegmentNumber) {
		return nil, 0, ErrTooMuchData
	}

	segnum := int(little32(data[0:4]) + 1)
	hdrsz := 8*(segnum/2) + 4

	b := data[0:(hdrsz + 4)]

	total := 0
	for i := 0; i < segnum; i++ {
		sz := little32(b[4*i+4:])
		if uint64(total)+uint64(sz)*8 > uint64(MaxTotalSize) {
			return nil, 0, ErrTooMuchData
		}
		total += int(sz) * 8
	}
	if total == 0 {
		return nil, 0, io.EOF
	}

	hdrv := data[4:(hdrsz + 4)]
	datav := data[hdrsz+4:]
	m := &MultiBuffer{make([]*Segment, segnum)}
	for i := 0; i < segnum; i++ {
		sz := int(little32(hdrv[4*i:])) * 8
		m.segments[i] = &Segment{m, datav[:sz], uint32(i)}
		datav = datav[sz:]
	}

	return m.segments[0], int64(4 + hdrsz + total), nil
}

// WriteTo writes the message that the segment is part of to the
// provided stream in serialized form.
func (s *Segment) WriteTo(w io.Writer) (int64, error) {
	segnum := uint32(1)
	for {
		if seg, _ := s.Message.Lookup(segnum); seg == nil {
			break
		}
		segnum++
	}

	hdrv := make([]uint8, 8*(segnum/2)+8)
	putLittle32(hdrv, segnum-1)
	for i := uint32(0); i < segnum; i++ {
		seg, _ := s.Message.Lookup(i)
		putLittle32(hdrv[4*i+4:], uint32(len(seg.Data)/8))
	}

	if n, err := w.Write(hdrv); err != nil {
		return int64(n), err
	}
	written := int64(len(hdrv))

	for i := uint32(0); i < segnum; i++ {
		seg, _ := s.Message.Lookup(i)
		if n, err := w.Write(seg.Data); err != nil {
			return written + int64(n), err
		} else {
			written += int64(n)
		}
	}

	return written, nil
}
<commit_msg>MultiBuffer -> multiBuffer ce6950c69aa8f94eb0c1f3698e796653c47df498 1 parent a727307 .<commit_after>package capn

import (
	"bytes"
	"errors"
	"io"
	"math"
)

var (
	errBufferCall     = errors.New("capn: can't call on a memory buffer")
	ErrInvalidSegment = errors.New("capn: invalid segment id")
	ErrTooMuchData    = errors.New("capn: too much data in stream")
)

type buffer Segment

// NewBuffer creates an expanding single segment buffer. Creating new objects
// will expand the buffer. Data can be nil (or length 0 with some capacity) if
// creating a new session. If parsing an existing segment than data should be
// the segment contents and will not be copied.
func NewBuffer(data []byte) *Segment {
	if uint64(len(data)) > uint64(math.MaxUint32) {
		return nil
	}

	b := &buffer{}
	b.Message = b
	b.Data = data
	return (*Segment)(b)
}

func (b *buffer) NewSegment(minsz int) (*Segment, error) {
	if uint64(len(b.Data)) > uint64(math.MaxUint32)-uint64(minsz) {
		return nil, ErrOverlarge
	}
	b.Data = append(b.Data, make([]byte, minsz)...)
	b.Data = b.Data[:len(b.Data)-minsz]
	return (*Segment)(b), nil
}

func (b *buffer) Lookup(segid uint32) (*Segment, error) {
	if segid == 0 {
		return (*Segment)(b), nil
	} else {
		return nil, ErrInvalidSegment
	}
}

type multiBuffer struct {
	segments []*Segment
}

// NewmultiBuffer creates a new multi segment message. Creating new objects
// will try and reuse the buffers available, but will create new ones if there
// is insufficient capacity. When parsing an existing message data should be
// the list of segments. The data buffers will not be copied.
func NewmultiBuffer(data [][]byte) *Segment {
	m := &multiBuffer{make([]*Segment, len(data))}
	for i, d := range data {
		m.segments[i] = &Segment{m, d, uint32(i)}
	}
	if len(data) > 0 {
		return m.segments[0]
	}
	return &Segment{m, nil, 0xFFFFFFFF}
}

var (
	MaxSegmentNumber = 1024
	MaxTotalSize     = 1024 * 1024 * 1024
)

func (m *multiBuffer) NewSegment(minsz int) (*Segment, error) {
	for _, s := range m.segments {
		if len(s.Data)+minsz <= cap(s.Data) {
			return s, nil
		}
	}

	if minsz < 4096 {
		minsz = 4096
	}
	s := &Segment{m, make([]byte, 0, minsz), uint32(len(m.segments))}
	m.segments = append(m.segments, s)
	return s, nil
}

func (m *multiBuffer) Lookup(segid uint32) (*Segment, error) {
	if uint(segid) < uint(len(m.segments)) {
		return m.segments[segid], nil
	} else {
		return nil, ErrInvalidSegment
	}
}

// ReadFromStream reads a non-packed serialized stream from r. buf is used to
// buffer the read contents, can be nil, and is provided so that the buffer
// can be reused between messages. The returned segment is the first segment
// read, which contains the root pointer.
func ReadFromStream(r io.Reader, buf *bytes.Buffer) (*Segment, error) {
	if buf == nil {
		buf = new(bytes.Buffer)
	} else {
		buf.Reset()
	}

	if _, err := io.CopyN(buf, r, 4); err != nil {
		return nil, err
	}

	if little32(buf.Bytes()[:]) >= uint32(MaxSegmentNumber) {
		return nil, ErrTooMuchData
	}

	segnum := int(little32(buf.Bytes()[:]) + 1)
	hdrsz := 8*(segnum/2) + 4

	if _, err := io.CopyN(buf, r, int64(hdrsz)); err != nil {
		return nil, err
	}

	total := 0
	for i := 0; i < segnum; i++ {
		sz := little32(buf.Bytes()[4*i+4:])
		if uint64(total)+uint64(sz)*8 > uint64(MaxTotalSize) {
			return nil, ErrTooMuchData
		}
		total += int(sz) * 8
	}

	if _, err := io.CopyN(buf, r, int64(total)); err != nil {
		return nil, err
	}

	hdrv := buf.Bytes()[4 : hdrsz+4]
	datav := buf.Bytes()[hdrsz+4:]

	if segnum == 1 {
		sz := int(little32(hdrv)) * 8
		return NewBuffer(datav[:sz]), nil
	}

	m := &multiBuffer{make([]*Segment, segnum)}
	for i := 0; i < segnum; i++ {
		sz := int(little32(hdrv[4*i:])) * 8
		m.segments[i] = &Segment{m, datav[:sz], uint32(i)}
		datav = datav[sz:]
	}

	return m.segments[0], nil
}

// ReadFromMemoryZeroCopy: like ReadFromStream, but reads a non-packed
// serialized stream that already resides in memory in the argument data.
// The returned segment is the first segment read, which contains
// the root pointer. The returned bytesRead says how many bytes were
// consumed from data in making seg. The caller should advance the
// data slice by doing data = data[bytesRead:] between successive calls
// to ReadFromMemoryZeroCopy().
func ReadFromMemoryZeroCopy(data []byte) (seg *Segment, bytesRead int64, err error) {

	if len(data) < 4 {
		return nil, 0, io.EOF
	}

	if little32(data[0:4]) >= uint32(MaxSegmentNumber) {
		return nil, 0, ErrTooMuchData
	}

	segnum := int(little32(data[0:4]) + 1)
	hdrsz := 8*(segnum/2) + 4

	b := data[0:(hdrsz + 4)]

	total := 0
	for i := 0; i < segnum; i++ {
		sz := little32(b[4*i+4:])
		if uint64(total)+uint64(sz)*8 > uint64(MaxTotalSize) {
			return nil, 0, ErrTooMuchData
		}
		total += int(sz) * 8
	}
	if total == 0 {
		return nil, 0, io.EOF
	}

	hdrv := data[4:(hdrsz + 4)]
	datav := data[hdrsz+4:]
	m := &multiBuffer{make([]*Segment, segnum)}
	for i := 0; i < segnum; i++ {
		sz := int(little32(hdrv[4*i:])) * 8
		m.segments[i] = &Segment{m, datav[:sz], uint32(i)}
		datav = datav[sz:]
	}

	return m.segments[0], int64(4 + hdrsz + total), nil
}

// WriteTo writes the message that the segment is part of to the
// provided stream in serialized form.
func (s *Segment) WriteTo(w io.Writer) (int64, error) {
	segnum := uint32(1)
	for {
		if seg, _ := s.Message.Lookup(segnum); seg == nil {
			break
		}
		segnum++
	}

	hdrv := make([]uint8, 8*(segnum/2)+8)
	putLittle32(hdrv, segnum-1)
	for i := uint32(0); i < segnum; i++ {
		seg, _ := s.Message.Lookup(i)
		putLittle32(hdrv[4*i+4:], uint32(len(seg.Data)/8))
	}

	if n, err := w.Write(hdrv); err != nil {
		return int64(n), err
	}
	written := int64(len(hdrv))

	for i := uint32(0); i < segnum; i++ {
		seg, _ := s.Message.Lookup(i)
		if n, err := w.Write(seg.Data); err != nil {
			return written + int64(n), err
		} else {
			written += int64(n)
		}
	}

	return written, nil
}
<|endoftext|>


<commit_before>package logger

/**
 * Barista Paxos Logger
 *
 * @author: Manasi Vartak
 * @date: 04/25/2014
 */

import "io/ioutil"
 import "os"
//import "json"

type Logger struct {
  filename string
}

func Make(filename string) *Logger {
  logger := &Logger{}
  logger.filename = filename
  return logger
}

func (lg *Logger) WriteToLog(text string) error {
  //return ioutil.WriteFile(lg.filename, b, 0644)
  f, err := os.OpenFile(lg.filename, os.O_APPEND, 0644)
  n, err := f.WriteString(text)
  f.Close()
  return err
}

func (lg *Logger) ReadFromLog() ([]byte, error) {
  return ioutil.ReadFile(lg.filename)
}

<commit_msg>fixes<commit_after>package logger

/**
 * Barista Paxos Logger
 *
 * @author: Manasi Vartak
 * @date: 04/25/2014
 */

import "io/ioutil"
 import "os"
//import "json"

type Logger struct {
  filename string
}

func Make(filename string) *Logger {
  logger := &Logger{}
  logger.filename = filename
  return logger
}

func (lg *Logger) WriteToLog(text string) error {
  //return ioutil.WriteFile(lg.filename, b, 0644)
  f, err := os.OpenFile(lg.filename, os.O_APPEND, 0644)
  _, err = f.WriteString(text)
  f.Close()
  return err
}

func (lg *Logger) ReadFromLog() ([]byte, error) {
  return ioutil.ReadFile(lg.filename)
}

<|endoftext|>


<commit_before>package devicetype

// DeviceType is a const for each device.
type DeviceType int

// Device type constants
const (
	IPHONE DeviceType = iota
	ANDROID
	OTHER
)

// DeviceDetector is a user agent parser.
type DeviceDetector struct {
	UserAgent string
}

// DeviceType represents this ua’s DeviceType code.
func (d *DeviceDetector) DeviceType() DeviceType {
	return OTHER
}

// IsIPhone returns true if this ua represents iPhone.
func (d *DeviceDetector) IsIPhone() bool {
	return true
}

// IsAndroid returns true if this ua represents Android
func (d *DeviceDetector) IsAndroid() bool {
	return true
}
<commit_msg>Add Usage to devicetype.go<commit_after>/*
devicetype detects device type like iPhone, Android, etc... from UserAgent.

Usage:
	package main
	import (
		"fmt"

		"github.com/y-matsuwitter/devicetype"
	)

	func main() {
		ua := "Mozilla/5.0 (Linux; Android 4.2.2; HogePhone)"
		dd := devicetype.DeviceType{ua}
		fmt.Println(dd.IsAndroid()) // true
	}
*/

package devicetype

// DeviceType is a const for each device.
type DeviceType int

// Device type constants
const (
	IPHONE DeviceType = iota
	ANDROID
	OTHER
)

// DeviceDetector is a user agent parser.
type DeviceDetector struct {
	UserAgent string
}

// DeviceType represents this ua’s DeviceType code.
func (d *DeviceDetector) DeviceType() DeviceType {
	return OTHER
}

// IsIPhone returns true if this ua represents iPhone.
func (d *DeviceDetector) IsIPhone() bool {
	return true
}

// IsAndroid returns true if this ua represents Android
func (d *DeviceDetector) IsAndroid() bool {
	return true
}
<|endoftext|>


<commit_before>/*
 * ZAnnotate Copyright 2017 Regents of the University of Michigan
 *
 * 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 zannotate

import (
	"encoding/json"
	"io"
	"log"
	"net"
	"os"

	"github.com/osrg/gobgp/packet/bgp"
	"github.com/zmap/go-iptree/iptree"
	"github.com/zmap/zannotate/zmrt"
)

type ASNameNode struct {
	ASN          uint32 `json:"asn"`
	Description  string `json:"description"`
	Name         string `json:"name"`
	Organization string `json:"organization"`
	CountryCode  string `json:"country_code"`
}

type ASTreeNode struct {
	Prefix string   `json:"prefix"`
	ASN    uint32   `json:"asn,omitempty"`
	Path   []uint32 `json:"path,omitempty"`
}

type RoutingConf struct {
	RoutingTablePath string
	ASNamesPath      string
	ASNames          map[uint32]ASNameNode
	IPTree           *iptree.IPTree
}

type RoutingOutput struct {
	Description  string `json:"description,omitempty"`
	Name         string `json:"name,omitempty"`
	Organization string `json:"organization"`
	CountryCode  string `json:"country_code"`
	ASTreeNode
}

func BuildTree(conf *RoutingConf) {
	if conf.ASNamesPath != "" {
		conf.ASNames = make(map[uint32]ASNameNode)
		f, err := os.Open(conf.ASNamesPath)
		if err != nil {
			log.Fatalf("Unable to open as name file (%s): %s", conf.ASNamesPath, err.Error())
		}
		d := json.NewDecoder(f)
		for {
			var m ASNameNode
			if err := d.Decode(&m); err == io.EOF {
				break
			} else if err != nil {
				log.Fatalf("%s", err)
			}
			conf.ASNames[m.ASN] = m
		}
	}
	// build radix tree and populate with
	conf.IPTree = iptree.New()
	zmrt.MrtPathIterate(conf.RoutingTablePath, func(e *zmrt.RIBEntry) {
		if e.AFI == bgp.AFI_IP {
			var n ASTreeNode
			n.Prefix = e.Prefix
			n.Path = e.Attributes.ASPath
			if len(n.Path) > 0 {
				n.ASN = n.Path[len(n.Path)-1]
			}
			if err := conf.IPTree.AddByString(e.Prefix, n); err != nil {
				//log.Fatal("unable to add to tree ", err)
			}
		}
	})
}

func RoutingFillStruct(ip net.IP, conf *RoutingConf) *RoutingOutput {
	var out RoutingOutput
	if n, ok, err := conf.IPTree.Get(ip); ok && err == nil {
		node := n.(ASTreeNode)
		out.Prefix = node.Prefix
		out.Path = node.Path
		out.ASN = node.ASN
		if conf.ASNamesPath != "" {
			if name, ok := conf.ASNames[out.ASN]; ok {
				out.Description = name.Description
				out.Organization = name.Organization
				out.Name = name.Name
				out.CountryCode = name.CountryCode
			}
		}
		return &out
	} else {
		log.Fatal("not ok", n, err)
	}
	return nil
}
<commit_msg>putting name in the right place<commit_after>/*
 * ZAnnotate Copyright 2017 Regents of the University of Michigan
 *
 * 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 zannotate

import (
	"encoding/json"
	"io"
	"log"
	"net"
	"os"

	"github.com/osrg/gobgp/packet/bgp"
	"github.com/zmap/go-iptree/iptree"
	"github.com/zmap/zannotate/zmrt"
)

type ASNameNode struct {
	ASN          uint32 `json:"asn,omitempty"`
	Description  string `json:"description"`
	Name         string `json:"name"`
	Organization string `json:"organization"`
	CountryCode  string `json:"country_code"`
}

type ASTreeNode struct {
	Prefix string
	ASN    uint32
	Path   []uint32
}

type RoutingConf struct {
	RoutingTablePath string
	ASNamesPath      string
	ASNames          map[uint32]ASNameNode
	IPTree           *iptree.IPTree
}

type RoutingOutput struct {
	Prefix string      `json:"prefix"`
	ASN    uint32      `json:"asn,omitempty"`
	Path   []uint32    `json:"path,omitempty"`
	AS     *ASNameNode `json:"as"`
}

func BuildTree(conf *RoutingConf) {
	if conf.ASNamesPath != "" {
		conf.ASNames = make(map[uint32]ASNameNode)
		f, err := os.Open(conf.ASNamesPath)
		if err != nil {
			log.Fatalf("Unable to open as name file (%s): %s", conf.ASNamesPath, err.Error())
		}
		d := json.NewDecoder(f)
		for {
			var m ASNameNode
			if err := d.Decode(&m); err == io.EOF {
				break
			} else if err != nil {
				log.Fatalf("%s", err)
			}
			conf.ASNames[m.ASN] = m
		}
	}
	// build radix tree and populate with
	conf.IPTree = iptree.New()
	zmrt.MrtPathIterate(conf.RoutingTablePath, func(e *zmrt.RIBEntry) {
		if e.AFI == bgp.AFI_IP {
			var n ASTreeNode
			n.Prefix = e.Prefix
			n.Path = e.Attributes.ASPath
			if len(n.Path) > 0 {
				n.ASN = n.Path[len(n.Path)-1]
			}
			conf.IPTree.AddByString(e.Prefix, n)
		}
	})
}

func RoutingFillStruct(ip net.IP, conf *RoutingConf) *RoutingOutput {
	var out RoutingOutput
	if n, ok, err := conf.IPTree.Get(ip); ok && err == nil {
		node := n.(ASTreeNode)
		out.Prefix = node.Prefix
		out.Path = node.Path
		out.ASN = node.ASN
		if conf.ASNamesPath != "" {
			var n ASNameNode
			if name, ok := conf.ASNames[out.ASN]; ok {
				n.Description = name.Description
				n.Organization = name.Organization
				n.Name = name.Name
				n.CountryCode = name.CountryCode
				out.AS = &n
			}
		}
		return &out
	} else {
		log.Fatal("not ok", n, err)
	}
	return nil
}
<|endoftext|>


<commit_before><commit_msg>eval: expose the two Scope members via accessor methods<commit_after><|endoftext|>


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

// +build darwin dragonfly freebsd linux netbsd openbsd solaris

// Socket control messages

package syscall

import "unsafe"

// Round the length of a raw sockaddr up to align it properly.
func cmsgAlignOf(salen int) int {
	salign := sizeofPtr
	// NOTE: It seems like 64-bit Darwin and DragonFly BSD kernels
	// still require 32-bit aligned access to network subsystem.
	if darwin64Bit || dragonfly64Bit {
		salign = 4
	}
	return (salen + salign - 1) & ^(salign - 1)
}

// CmsgLen returns the value to store in the Len field of the Cmsghdr
// structure, taking into account any necessary alignment.
func CmsgLen(datalen int) int {
	return cmsgAlignOf(SizeofCmsghdr) + datalen
}

// CmsgSpace returns the number of bytes an ancillary element with
// payload of the passed data length occupies.
func CmsgSpace(datalen int) int {
	return cmsgAlignOf(SizeofCmsghdr) + cmsgAlignOf(datalen)
}

func cmsgData(h *Cmsghdr) unsafe.Pointer {
	return unsafe.Pointer(uintptr(unsafe.Pointer(h)) + uintptr(cmsgAlignOf(SizeofCmsghdr)))
}

// SocketControlMessage represents a socket control message.
type SocketControlMessage struct {
	Header Cmsghdr
	Data   []byte
}

// ParseSocketControlMessage parses b as an array of socket control
// messages.
func ParseSocketControlMessage(b []byte) ([]SocketControlMessage, error) {
	var msgs []SocketControlMessage
	i := 0
	for i+CmsgLen(0) <= len(b) {
		h, dbuf, err := socketControlMessageHeaderAndData(b[i:])
		if err != nil {
			return nil, err
		}
		m := SocketControlMessage{Header: *h, Data: dbuf}
		msgs = append(msgs, m)
		i += cmsgAlignOf(int(h.Len))
	}
	return msgs, nil
}

func socketControlMessageHeaderAndData(b []byte) (*Cmsghdr, []byte, error) {
	h := (*Cmsghdr)(unsafe.Pointer(&b[0]))
	if h.Len < SizeofCmsghdr || int(h.Len) > len(b) {
		return nil, nil, EINVAL
	}
	return h, b[cmsgAlignOf(SizeofCmsghdr):h.Len], nil
}

// UnixRights encodes a set of open file descriptors into a socket
// control message for sending to another process.
func UnixRights(fds ...int) []byte {
	datalen := len(fds) * 4
	b := make([]byte, CmsgSpace(datalen))
	h := (*Cmsghdr)(unsafe.Pointer(&b[0]))
	h.Level = SOL_SOCKET
	h.Type = SCM_RIGHTS
	h.SetLen(CmsgLen(datalen))
	data := cmsgData(h)
	for _, fd := range fds {
		*(*int32)(data) = int32(fd)
		data = unsafe.Pointer(uintptr(data) + 4)
	}
	return b
}

// ParseUnixRights decodes a socket control message that contains an
// integer array of open file descriptors from another process.
func ParseUnixRights(m *SocketControlMessage) ([]int, error) {
	if m.Header.Level != SOL_SOCKET {
		return nil, EINVAL
	}
	if m.Header.Type != SCM_RIGHTS {
		return nil, EINVAL
	}
	fds := make([]int, len(m.Data)>>2)
	for i, j := 0, 0; i < len(m.Data); i += 4 {
		fds[j] = int(*(*int32)(unsafe.Pointer(&m.Data[i])))
		j++
	}
	return fds, nil
}
<commit_msg>syscall: fix uint64->int cast of control message header<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build darwin dragonfly freebsd linux netbsd openbsd solaris

// Socket control messages

package syscall

import "unsafe"

// Round the length of a raw sockaddr up to align it properly.
func cmsgAlignOf(salen int) int {
	salign := sizeofPtr
	// NOTE: It seems like 64-bit Darwin and DragonFly BSD kernels
	// still require 32-bit aligned access to network subsystem.
	if darwin64Bit || dragonfly64Bit {
		salign = 4
	}
	return (salen + salign - 1) & ^(salign - 1)
}

// CmsgLen returns the value to store in the Len field of the Cmsghdr
// structure, taking into account any necessary alignment.
func CmsgLen(datalen int) int {
	return cmsgAlignOf(SizeofCmsghdr) + datalen
}

// CmsgSpace returns the number of bytes an ancillary element with
// payload of the passed data length occupies.
func CmsgSpace(datalen int) int {
	return cmsgAlignOf(SizeofCmsghdr) + cmsgAlignOf(datalen)
}

func cmsgData(h *Cmsghdr) unsafe.Pointer {
	return unsafe.Pointer(uintptr(unsafe.Pointer(h)) + uintptr(cmsgAlignOf(SizeofCmsghdr)))
}

// SocketControlMessage represents a socket control message.
type SocketControlMessage struct {
	Header Cmsghdr
	Data   []byte
}

// ParseSocketControlMessage parses b as an array of socket control
// messages.
func ParseSocketControlMessage(b []byte) ([]SocketControlMessage, error) {
	var msgs []SocketControlMessage
	i := 0
	for i+CmsgLen(0) <= len(b) {
		h, dbuf, err := socketControlMessageHeaderAndData(b[i:])
		if err != nil {
			return nil, err
		}
		m := SocketControlMessage{Header: *h, Data: dbuf}
		msgs = append(msgs, m)
		i += cmsgAlignOf(int(h.Len))
	}
	return msgs, nil
}

func socketControlMessageHeaderAndData(b []byte) (*Cmsghdr, []byte, error) {
	h := (*Cmsghdr)(unsafe.Pointer(&b[0]))
	if h.Len < SizeofCmsghdr || uint64(h.Len) > uint64(len(b)) {
		return nil, nil, EINVAL
	}
	return h, b[cmsgAlignOf(SizeofCmsghdr):h.Len], nil
}

// UnixRights encodes a set of open file descriptors into a socket
// control message for sending to another process.
func UnixRights(fds ...int) []byte {
	datalen := len(fds) * 4
	b := make([]byte, CmsgSpace(datalen))
	h := (*Cmsghdr)(unsafe.Pointer(&b[0]))
	h.Level = SOL_SOCKET
	h.Type = SCM_RIGHTS
	h.SetLen(CmsgLen(datalen))
	data := cmsgData(h)
	for _, fd := range fds {
		*(*int32)(data) = int32(fd)
		data = unsafe.Pointer(uintptr(data) + 4)
	}
	return b
}

// ParseUnixRights decodes a socket control message that contains an
// integer array of open file descriptors from another process.
func ParseUnixRights(m *SocketControlMessage) ([]int, error) {
	if m.Header.Level != SOL_SOCKET {
		return nil, EINVAL
	}
	if m.Header.Type != SCM_RIGHTS {
		return nil, EINVAL
	}
	fds := make([]int, len(m.Data)>>2)
	for i, j := 0, 0; i < len(m.Data); i += 4 {
		fds[j] = int(*(*int32)(unsafe.Pointer(&m.Data[i])))
		j++
	}
	return fds, nil
}
<|endoftext|>


<commit_before>package otp

import (
	"fmt"
)

type Pad struct {
	pages       [][]byte
	currentPage int
}

func NewPad(material []byte, pageSize int, startPage int) (*Pad, error) {
	if len(material)%pageSize != 0 {
		return nil, fmt.Errorf("pad size must be divisible by page size")
	}

	var pages [][]byte
	for i := 0; i < len(material); i += pageSize {
		pages = append(pages, material[i:i+pageSize])
	}

	if startPage < 1 || startPage > len(pages) {
		return nil, fmt.Errorf("start page (%d) out of bounds", startPage)
	}

	p := Pad{
		pages:       pages,
		currentPage: startPage - 1,
	}

	return &p, nil
}

func (p *Pad) TotalPages() int {
	return len(p.pages)
}

func (p *Pad) RemainingPages() int {
	return len(p.pages) - p.currentPage
}

func (p *Pad) UsedPages() int {
	return p.currentPage + 1
}

func (p *Pad) PreviousPage() ([]byte, error) {
	if p.currentPage == 0 {
		return nil, fmt.Errorf("no previous pages")
	}
	return p.pages[p.currentPage-1], nil
}

func (p *Pad) CurrentPage() []byte {
	return p.pages[p.currentPage]
}

func (p *Pad) NextPage() ([]byte, error) {
	if p.RemainingPages() == 0 {
		return nil, fmt.Errorf("pad depleted")
	}
	p.currentPage++
	return p.CurrentPage(), nil
}

func (p *Pad) PeekNextPage() ([]byte, error) {
	if p.RemainingPages() == 0 {
		return nil, fmt.Errorf("no pages left")
	}
	return p.pages[p.currentPage+1], nil
}
<commit_msg>Fixed bug in RemainingPages(), where you could still request the next page at the end of the pad.<commit_after>package otp

import (
	"fmt"
)

type Pad struct {
	pages       [][]byte
	currentPage int
}

func NewPad(material []byte, pageSize int, startPage int) (*Pad, error) {
	if len(material)%pageSize != 0 {
		return nil, fmt.Errorf("pad size must be divisible by page size")
	}

	var pages [][]byte
	for i := 0; i < len(material); i += pageSize {
		pages = append(pages, material[i:i+pageSize])
	}

	if startPage < 1 || startPage > len(pages) {
		return nil, fmt.Errorf("start page (%d) out of bounds", startPage)
	}

	p := Pad{
		pages:       pages,
		currentPage: startPage - 1,
	}

	return &p, nil
}

func (p *Pad) TotalPages() int {
	return len(p.pages)
}

func (p *Pad) RemainingPages() int {
	return len(p.pages) - (p.currentPage + 1)
}

func (p *Pad) UsedPages() int {
	return p.currentPage + 1
}

func (p *Pad) PreviousPage() ([]byte, error) {
	if p.currentPage == 0 {
		return nil, fmt.Errorf("no previous pages")
	}
	return p.pages[p.currentPage-1], nil
}

func (p *Pad) CurrentPage() []byte {
	return p.pages[p.currentPage]
}

func (p *Pad) NextPage() ([]byte, error) {
	if p.RemainingPages() == 0 {
		return nil, fmt.Errorf("pad depleted")
	}
	p.currentPage++
	return p.CurrentPage(), nil
}

func (p *Pad) PeekNextPage() ([]byte, error) {
	if p.RemainingPages() == 0 {
		return nil, fmt.Errorf("no pages left")
	}
	return p.pages[p.currentPage+1], nil
}
<|endoftext|>


<commit_before>//Stupidly simple package for parsing XML RSS from a byte slice.
package easyrss

import (
	"bytes"
	"encoding/xml"
)

type RSS struct {
	XMLname  xml.Name   `xml:"rss"`
	Channels []*Channel `xml:"channel"` //Slice of the channels
}

type Channel struct {
	XMLname         xml.Name    `xml:"channel"`
	Title           string      `xml:"title"`           //Channel title
	Link            string      `xml:"link"`            //Channel link
	Generator       string      `xmlL"generator"`       //Channel Generator
	Description     string      `xml:"description"`     //Channel description
	Language        string      `xml:"language"`        //Channel language
	Copyright       string      `xml:"copyright"`       //Channel Copyright
	Categories      []string    `xml:"category"`        //Channel Categories
	Items           []*Item     `xml:"item"`            //Slice of the items in the channel
	MediaCategories []string    `xml:"media:category"`  //Slice of media tag categories
	MediaCopyright  string      `xml:"media:copyright"` //Media Copyright
	MediaRating     string      `xml:"media:rating"`    //Media Rating
	MediaThumbnail  Image       `xml:"media:thumbnail"` //Media Thumbnail
	ItunesCategory  string      `xml:"itunes:category"` //Itunes Podcast Category
	ItunesOwner     ItunesOwner `xml:"itunes:owner"`    //Itunes Podcast Owner Contact Info
	ItunesKeywords  string      `xml:"itunes:keywords"` //Itunes Podcast Keywords

}

type ItunesOwner struct {
	Name  string `xml:"itunes:name"`
	Email string `xml:"itunes:email"`
}
type RSSEnclosure struct {
	URL       string `xml:"url,attr"`
	MediaType string `xml:"type,attr"`
	Size      string `xml:"fileSize,attr"`
}
type Image struct {
	URL    string `xml:"url,attr"`
	Width  string `xml:"width,attr"`
	Height string `xml:"height,attr"`
}
type Item struct {
	XMLname        xml.Name     `xml:"item"`
	Title          string       `xml:"title"`       //Item title
	Link           string       `xml:"link"`        //Item link
	Content        string       `xml:"encoded"`     //Item content
	Description    string       `xml:"description"` //Item description
	Category       []string     `xml:"category"`    //Item categories
	Enclosure      RSSEnclosure `xml"enclosure"`    //Optional RSS Media Enclosure
	Date           string       `xml:"pubDate"`     //Last date of item publication
	GUID           string       `xml:"guid"`
	ItunesAuthor   string       `xml:"itunes:author"`   //Itunes Episode Author
	ItunesDuration string       `xml:"itunes:duration"` //Itunes Episode Duration
	ItunesImage    Image        `xml:"itunes:image"`    //Itunes Episode Th
	ItunesSubtitle string       `xml:"itunes:subtitle"` //Itunes Episode Subtitle
	ItunesSummary  string       `xml"itunes:summary"`   //Itunes Episode Summary
	MediaContent   RSSEnclosure `xml:"media:content"`   //Media Payload
	MediaThumbnail Image        `xml:"media:thumbnail"` //Media Thumbnail
}

//Pass in a byte slice containing the feed, get an RSS struct back, with stuff populated.
func Decode(data []byte) (*RSS, error) {
	r := bytes.NewReader(data)
	decoder := xml.NewDecoder(r)
	rss := &RSS{}
	return rss, decoder.Decode(rss)
}
<commit_msg>Namespace fix I think<commit_after>//Stupidly simple package for parsing XML RSS from a byte slice.
package easyrss

import (
	"bytes"
	"encoding/xml"
)

type RSS struct {
	XMLname  xml.Name   `xml:"rss"`
	Channels []*Channel `xml:"channel"` //Slice of the channels
}

type Channel struct {
	XMLname         xml.Name    `xml:"channel"`
	Title           string      `xml:"title"`           //Channel title
	Link            string      `xml:"link"`            //Channel link
	Generator       string      `xmlL"generator"`       //Channel Generator
	Description     string      `xml:"description"`     //Channel description
	Language        string      `xml:"language"`        //Channel language
	Copyright       string      `xml:"copyright"`       //Channel Copyright
	Categories      []string    `xml:"category"`        //Channel Categories
	Items           []*Item     `xml:"item"`            //Slice of the items in the channel
	MediaCategories []string    `xml:"media:category"`  //Slice of media tag categories
	MediaCopyright  string      `xml:"media:copyright"` //Media Copyright
	MediaRating     string      `xml:"media:rating"`    //Media Rating
	MediaThumbnail  Image       `xml:"media:thumbnail"` //Media Thumbnail
	ItunesCategory  string      `xml:"itunes:category"` //Itunes Podcast Category
	ItunesOwner     ItunesOwner `xml:"itunes:owner"`    //Itunes Podcast Owner Contact Info
	ItunesKeywords  string      `xml:"itunes:keywords"` //Itunes Podcast Keywords

}

type ItunesOwner struct {
	Name  string `xml:"itunes:name"`
	Email string `xml:"itunes:email"`
}
type RSSEnclosure struct {
	URL       string `xml:"url,attr"`
	MediaType string `xml:"type,attr"`
	Size      string `xml:"fileSize,attr"`
}
type Image struct {
	URL    string `xml:"url,attr"`
	Width  string `xml:"width,attr"`
	Height string `xml:"height,attr"`
}

type Itunes struct {
	Author   string `xml:"author"`
	Duration string `xml:"duration"`
	Image    Image  `xml:"image"`
	Subtitle string `xml:"subtitle"`
	Summary  string `xml:"summary"`
}

type Media struct {
	Content   RSSEnclosure `xml:"content"`
	Thumbnail Image        `xml:"thumbnail"`
}

type Item struct {
	XMLname     xml.Name     `xml:"item"`
	Title       string       `xml:"title"`       //Item title
	Link        string       `xml:"link"`        //Item link
	Content     string       `xml:"encoded"`     //Item content
	Description string       `xml:"description"` //Item description
	Category    []string     `xml:"category"`    //Item categories
	Enclosure   RSSEnclosure `xml"enclosure"`    //Optional RSS Media Enclosure
	Date        string       `xml:"pubDate"`     //Last date of item publication
	GUID        string       `xml:"guid"`        //ID
	Itunes      Itunes       //Itunes Data
	Media       Media        //Media Payload
}

//Pass in a byte slice containing the feed, get an RSS struct back, with stuff populated.
func Decode(data []byte) (*RSS, error) {
	r := bytes.NewReader(data)
	decoder := xml.NewDecoder(r)
	rss := &RSS{}
	return rss, decoder.Decode(rss)
}
<|endoftext|>