<commit_before>package main

import (
	"encoding/xml"
	"golang.org/x/text/encoding/charmap"
	"io"
	"os"
	"path/filepath"
	"strings"
)

var (
	parsedFiles map[string]struct{}
)

func parseXSDFile(fname string) ([]xsdSchema, error) {
	schemas := []xsdSchema{}
	parsedFiles = make(map[string]struct{})
	schemas, err := parse(fname)
	if err != nil {
		return nil, err
	}
	return schemas, nil
}

// makeCharsetReader returns special readers as needed for xml encodings, or
// nil.
func makeCharsetReader(charset string, input io.Reader) (io.Reader, error) {
	if charset == "Windows-1252" {
		return charmap.Windows1252.NewDecoder().Reader(input), nil
	}
	return nil, nil
}

func parse(fname string) ([]xsdSchema, error) {
	f, err := os.Open(fname)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	var schema xsdSchema

	d := xml.NewDecoder(f)

	// handle special character sets
	d.CharsetReader = makeCharsetReader

	if err := d.Decode(&schema); err != nil {
		return nil, err
	}

	schemas := []xsdSchema{schema}
	dir, file := filepath.Split(fname)
	parsedFiles[file] = struct{}{}
	for _, imp := range schema.Imports {
		if _, ok := parsedFiles[imp.Location]; ok {
			continue
		}
		s, err := parse(filepath.Join(dir, imp.Location))
		if err != nil {
			return nil, err
		}
		schemas = append(schemas, s...)
	}
	return schemas, nil
}

// xsdSchema is the Go representation of an XSD schema.
type xsdSchema struct {
	XMLName      xml.Name
	Ns           string           `xml:"xmlns,attr"`
	Imports      []xsdImport      `xml:"import"`
	Elements     []xsdElement     `xml:"element"`
	ComplexTypes []xsdComplexType `xml:"complexType"`
	SimpleTypes  []xsdSimpleType  `xml:"simpleType"`
}

// ns parses the namespace from a value in the expected format
// http://host/namespace/v1
func (s xsdSchema) ns() string {
	split := strings.Split(s.Ns, "/")
	if len(split) > 2 {
		return split[len(split)-2]
	}
	return ""
}

type xsdImport struct {
	Location string `xml:"schemaLocation,attr"`
}

type xsdElement struct {
	Name        string          `xml:"name,attr"`
	Type        string          `xml:"type,attr"`
	Default     string          `xml:"default,attr"`
	Min         string          `xml:"minOccurs,attr"`
	Max         string          `xml:"maxOccurs,attr"`
	Annotation  string          `xml:"annotation>documentation"`
	ComplexType *xsdComplexType `xml:"complexType"` // inline complex type
	SimpleType  *xsdSimpleType  `xml:"simpleType"`  // inline simple type
}

func (e xsdElement) isList() bool {
	return e.Max == "unbounded"
}

func (e xsdElement) inlineType() bool {
	return e.Type == ""
}

type xsdComplexType struct {
	Name           string             `xml:"name,attr"`
	Abstract       string             `xml:"abstract,attr"`
	Annotation     string             `xml:"annotation>documentation"`
	Sequence       []xsdElement       `xml:"sequence>element"`
	Attributes     []xsdAttribute     `xml:"attribute"`
	ComplexContent *xsdComplexContent `xml:"complexContent"`
	SimpleContent  *xsdSimpleContent  `xml:"simpleContent"`
}

type xsdComplexContent struct {
	Extension   *xsdExtension   `xml:"extension"`
	Restriction *xsdRestriction `xml:"restriction"`
}

type xsdSimpleContent struct {
	Extension   *xsdExtension   `xml:"extension"`
	Restriction *xsdRestriction `xml:"restriction"`
}

type xsdExtension struct {
	Base       string         `xml:"base,attr"`
	Attributes []xsdAttribute `xml:"attribute"`
	Sequence   []xsdElement   `xml:"sequence>element"`
}

type xsdAttribute struct {
	Name       string `xml:"name,attr"`
	Type       string `xml:"type,attr"`
	Use        string `xml:"use,attr"`
	Annotation string `xml:"annotation>documentation"`
}

type xsdSimpleType struct {
	Name        string         `xml:"name,attr"`
	Annotation  string         `xml:"annotation>documentation"`
	Restriction xsdRestriction `xml:"restriction"`
}

type xsdRestriction struct {
	Base        string           `xml:"base,attr"`
	Pattern     xsdPattern       `xml:"pattern"`
	Enumeration []xsdEnumeration `xml:"enumeration"`
}

type xsdPattern struct {
	Value string `xml:"value,attr"`
}

type xsdEnumeration struct {
	Value string `xml:"value,attr"`
}
<commit_msg>#3 return error from makeCharsetReader when no matching character set.<commit_after>package main

import (
	"encoding/xml"
	"fmt"
	"golang.org/x/text/encoding/charmap"
	"io"
	"os"
	"path/filepath"
	"strings"
)

var (
	parsedFiles map[string]struct{}
)

func parseXSDFile(fname string) ([]xsdSchema, error) {
	schemas := []xsdSchema{}
	parsedFiles = make(map[string]struct{})
	schemas, err := parse(fname)
	if err != nil {
		return nil, err
	}
	return schemas, nil
}

// makeCharsetReader returns special readers as needed for xml encodings, or
// nil.
func makeCharsetReader(charset string, input io.Reader) (io.Reader, error) {
	if charset == "Windows-1252" {
		return charmap.Windows1252.NewDecoder().Reader(input), nil
	}
	return nil, fmt.Errorf("Unknown charset: %s", charset)
}

func parse(fname string) ([]xsdSchema, error) {
	f, err := os.Open(fname)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	var schema xsdSchema

	d := xml.NewDecoder(f)

	// handle special character sets
	d.CharsetReader = makeCharsetReader

	if err := d.Decode(&schema); err != nil {
		return nil, err
	}

	schemas := []xsdSchema{schema}
	dir, file := filepath.Split(fname)
	parsedFiles[file] = struct{}{}
	for _, imp := range schema.Imports {
		if _, ok := parsedFiles[imp.Location]; ok {
			continue
		}
		s, err := parse(filepath.Join(dir, imp.Location))
		if err != nil {
			return nil, err
		}
		schemas = append(schemas, s...)
	}
	return schemas, nil
}

// xsdSchema is the Go representation of an XSD schema.
type xsdSchema struct {
	XMLName      xml.Name
	Ns           string           `xml:"xmlns,attr"`
	Imports      []xsdImport      `xml:"import"`
	Elements     []xsdElement     `xml:"element"`
	ComplexTypes []xsdComplexType `xml:"complexType"`
	SimpleTypes  []xsdSimpleType  `xml:"simpleType"`
}

// ns parses the namespace from a value in the expected format
// http://host/namespace/v1
func (s xsdSchema) ns() string {
	split := strings.Split(s.Ns, "/")
	if len(split) > 2 {
		return split[len(split)-2]
	}
	return ""
}

type xsdImport struct {
	Location string `xml:"schemaLocation,attr"`
}

type xsdElement struct {
	Name        string          `xml:"name,attr"`
	Type        string          `xml:"type,attr"`
	Default     string          `xml:"default,attr"`
	Min         string          `xml:"minOccurs,attr"`
	Max         string          `xml:"maxOccurs,attr"`
	Annotation  string          `xml:"annotation>documentation"`
	ComplexType *xsdComplexType `xml:"complexType"` // inline complex type
	SimpleType  *xsdSimpleType  `xml:"simpleType"`  // inline simple type
}

func (e xsdElement) isList() bool {
	return e.Max == "unbounded"
}

func (e xsdElement) inlineType() bool {
	return e.Type == ""
}

type xsdComplexType struct {
	Name           string             `xml:"name,attr"`
	Abstract       string             `xml:"abstract,attr"`
	Annotation     string             `xml:"annotation>documentation"`
	Sequence       []xsdElement       `xml:"sequence>element"`
	Attributes     []xsdAttribute     `xml:"attribute"`
	ComplexContent *xsdComplexContent `xml:"complexContent"`
	SimpleContent  *xsdSimpleContent  `xml:"simpleContent"`
}

type xsdComplexContent struct {
	Extension   *xsdExtension   `xml:"extension"`
	Restriction *xsdRestriction `xml:"restriction"`
}

type xsdSimpleContent struct {
	Extension   *xsdExtension   `xml:"extension"`
	Restriction *xsdRestriction `xml:"restriction"`
}

type xsdExtension struct {
	Base       string         `xml:"base,attr"`
	Attributes []xsdAttribute `xml:"attribute"`
	Sequence   []xsdElement   `xml:"sequence>element"`
}

type xsdAttribute struct {
	Name       string `xml:"name,attr"`
	Type       string `xml:"type,attr"`
	Use        string `xml:"use,attr"`
	Annotation string `xml:"annotation>documentation"`
}

type xsdSimpleType struct {
	Name        string         `xml:"name,attr"`
	Annotation  string         `xml:"annotation>documentation"`
	Restriction xsdRestriction `xml:"restriction"`
}

type xsdRestriction struct {
	Base        string           `xml:"base,attr"`
	Pattern     xsdPattern       `xml:"pattern"`
	Enumeration []xsdEnumeration `xml:"enumeration"`
}

type xsdPattern struct {
	Value string `xml:"value,attr"`
}

type xsdEnumeration struct {
	Value string `xml:"value,attr"`
}
<|endoftext|>


<commit_before>package zmq

// import "fmt"
import . "bytes"
import "io"
import "os"
import "unsafe"
import "strconv"
import . "unsafe/coffer"
import . "gonewrong"

// #include <zmq.h>
// #include <stdlib.h>
import "C"

// ******** Global ZMQ Constants ********

const (
  ZmqPoll        = C.ZMQ_POLL
  ZmqP2P         = C.ZMQ_P2P // About to be renamed as ZMQ_PAIR
  ZmqPair        = C.ZMQ_P2P
  ZmqPub         = C.ZMQ_PUB
  ZmqSub         = C.ZMQ_SUB
  ZmqReq         = C.ZMQ_REQ
  ZmqRep         = C.ZMQ_REP
  ZmqXReq        = C.ZMQ_XREQ
  ZmqXRep        = C.ZMQ_XREP
  ZmqUpstream    = C.ZMQ_UPSTREAM
  ZmqDownstream  = C.ZMQ_DOWNSTREAM
  ZmqNoBlock     = C.ZMQ_NOBLOCK
  ZmqNoFlush     = C.ZMQ_NOFLUSH
  ZmqPollIn      = C.ZMQ_POLLIN
  ZmqPollOut     = C.ZMQ_POLLOUT
  ZmqPollErr     = C.ZMQ_POLLERR
  ZmqHWM         = C.ZMQ_HWM
  ZmqLWM         = C.ZMQ_LWM
  ZmqSwap        = C.ZMQ_SWAP
  ZmqAffinity    = C.ZMQ_AFFINITY
  ZmqIdentitiy   = C.ZMQ_IDENTITY
  ZmqRate        = C.ZMQ_RATE
  ZmqSubscribe   = C.ZMQ_SUBSCRIBE
  ZmqUnsubscribe = C.ZMQ_UNSUBSCRIBE
  ZmqRecoveryIVL = C.ZMQ_RECOVERY_IVL
  ZmqMCastLoop   = C.ZMQ_MCAST_LOOP
  ZmqSendBuf     = C.ZMQ_SNDBUF
  ZmqSndBuf      = C.ZMQ_SNDBUF
  ZmqRecvBuf     = C.ZMQ_RCVBUF
  ZmqRcvBuf      = C.ZMQ_RCVBUF
)

// ******** ZMQ Interfaces ********

type Provider interface {
  ErrKnow // implemented in utils.go

  NewContext(initArgs InitArgs) (Context, os.Error)
  NewMessage() Message

  StartWatch() Watch

  Version() (major int, minor int, pl int)

  Sleep(secs int)
}

type Provided interface {
  Provider() Provider
}

// Arguments to New Context
type InitArgs struct {
  AppThreads int
  IoThreads  int
  Flags      int
}

// Sensible default init args
// AppThreads = EnvGOMAXPROCS(), IoThreads = 2, Flags = 0 /*no polling! */
func DefaultInitArgs() InitArgs {
  return InitArgs{AppThreads: EnvGOMAXPROCS(), IoThreads: 2, Flags: 0}
}

// Integer value of environment variable GOMAXPROCS if > 1, 1 otherwise
func EnvGOMAXPROCS() int {
  var maxProcs, error = strconv.Atoi(os.Getenv("GOMAXPROCS"))
  if error == nil && maxProcs > 1 {
    return maxProcs
  }
  return 1
}

// Context interface
//
// Contexts are always global thread-safe objects
type Context interface {
  io.Closer
  Provided

  NewSocket(socketType int) (Socket, os.Error)
  Terminate() os.Error
}

// Message interface
//
// Messages may only be used reliably with sockets from the same provider
type Message interface {
  io.Closer
  Provided

  WriteTo(buf *Buffer) (n int, err os.Error)
  ReadFrom(buf *Buffer) (n int, err os.Error)

	// GetData(coffer Coffer) os.Error
	// SetData(coffer Coffer) os.Error

  MoveTo(msg Message) os.Error
  CopyTo(msg Message) os.Error

  Size() int
}

// Socket interface
//
// Sockets are typically thread-bound
type Socket interface {
  io.Closer
  Provided

  Bind(address string) os.Error
  Connect(address string) os.Error

  Receive(msg Message, flags int) os.Error
  Send(msg Message, flags int) os.Error

  // TODO: Poll

  Flush() os.Error
}

// Watch interface
type Watch interface {
	Stop() uint64
}

// ******** lzmq: Provider ********

// libzmq provider impl
func LibZmqProvider() Provider { return _libZmqProvider }

type libZmqProvider struct{}

var _libZmqProvider = new(libZmqProvider)

// ******** lzmq: Context ********

// libzmq context wrapper
type lzmqContext uintptr

// Creates a zmq context and returns it.
//
// Don't forget to set EnvGOMAXPROCS appropriately when working with libzmq
//
// Contexts are finalized by the GC unless they are manually destructed
// by calling Terminate() beforehand.  Applications need to arrange
// that no socket is used or even closed after the owning context has
// been destructed.  This requires to have at least one running go routine
// with a live referene to the context.
func (p libZmqProvider) NewContext(args InitArgs) (Context, os.Error) {
  contextPtr := C.zmq_init(
    C.int(args.AppThreads),
    C.int(args.IoThreads),
    C.int(args.Flags))

  if IsCNullPtr(uintptr(contextPtr)) {
    return nil, p.GetError()
  }

  lzmqContext := lzmqContext(contextPtr)
  return lzmqContext, nil
}

func (p *libZmqProvider) NewMessage() Message {
  msg := new(lzmqMessage)
  return msg
}

func (p *libZmqProvider) StartWatch() Watch {
	watch := uintptr(C.zmq_stopwatch_start())
	return lzmqWatch(watch)
}

// Type of error codes used by LibZmq
//
// Necessary since lzmq provides its own zmq_errno, zmq_strerror functions
type LibZmqErrno int

func (p LibZmqErrno) String() string { return C.GoString(C.zmq_strerror(C.int(p))) }

func (p *libZmqProvider) GetError() os.Error {
  return LibZmqErrno(C.zmq_errno())
}

func (p *libZmqProvider) OkIf(cond bool) os.Error { return p.ErrorIf(!cond) }

func (p *libZmqProvider) ErrorIf(cond bool) os.Error {
  if cond {
    err := p.GetError()
    if err != nil {
      return err
    }
  }
  return nil
}
func (p *libZmqProvider) Sleep(secs int) {
  if secs < 0 {
    return
  }
  C.zmq_sleep(C.int(secs))
}

func (p *libZmqProvider) Version() (major int, minor int, pl int) {
  C.zmq_version((*C.int)(unsafe.Pointer(&major)), (*C.int)(unsafe.Pointer(&minor)), (*C.int)(unsafe.Pointer(&pl)))
  return
}

func (p lzmqContext) Provider() Provider { return LibZmqProvider() }

// Calls Terminate()
func (p lzmqContext) Close() os.Error {
  return p.Terminate()
}

// Calls zmq_term on underlying context pointer
//
// Only call once
func (p lzmqContext) Terminate() os.Error {
  ch := make(chan os.Error)
  ptr := unsafe.Pointer(p)
  if ptr != nil {
    // Needs to run in separate go routine to safely lock the OS Thread
    // and synchronize via channel to know when we're done
    Thunk(func() {
      ch <- p.Provider().OkIf(C.zmq_term(ptr) == 0)
    }).RunInOSThread()
    // Wait for completion
    return <-ch
  }
  return nil
}

// ******** lzmq: Messages ********

type lzmqMessageHolder interface {
  Message

  getLzmqMessage() *lzmqMessage
}

type lzmqMessage C.zmq_msg_t

func (p *lzmqMessage) empty() os.Error {
  return p.Provider().OkIf(C.zmq_msg_init(p.ptr()) == 0)
}

func (p *lzmqMessage) allocate(length int) os.Error {
  return p.Provider().OkIf(C.zmq_msg_init_size(p.ptr(), C.size_t(length)) == 0)
}

func (p *lzmqMessage) Provider() Provider { return LibZmqProvider() }

func (p *lzmqMessage) Size() int {
  // size_t always fits int, we do not allocate larger messages
  return int(C.zmq_msg_size(p.ptr()))
}

func (p *lzmqMessage) MoveTo(msg Message) os.Error {
  if msg == nil {
    return os.EINVAL
  }
  lzmqMsgHolder, err := msg.(lzmqMessageHolder)
  if err == false {
    return os.EINVAL
  }
  lzmqMsg := lzmqMsgHolder.getLzmqMessage()

	return p.Provider().OkIf(C.zmq_msg_move(lzmqMsg.ptr(), p.ptr()) == 0)
}

func (p *lzmqMessage) CopyTo(msg Message) os.Error {
  if msg == nil {
    return os.EINVAL
  }
  lzmqMsgHolder, err := msg.(lzmqMessageHolder)
  if err == false {
    return os.EINVAL
  }
  lzmqMsg := lzmqMsgHolder.getLzmqMessage()

	return p.Provider().OkIf(C.zmq_msg_copy(lzmqMsg.ptr(), p.ptr()) == 0)
}

func (p *lzmqMessage) WriteTo(buf *Buffer) (n int, err os.Error) {
  n = p.Size()
  if n <= 0 {
    return 0, nil
  }
  start := p.data()
  var coffr Coffer
  coffr, err = NewPtrCoffer(start, n)
  if err != nil {
    return 0, err
  }

  var n64 int64
  n64, err = buf.ReadFrom(coffr)
  if n64 == int64(n) && err == os.EOF {
    err = nil
  }
  return int(n64), err
}

func (p *lzmqMessage) ReadFrom(buf *Buffer) (n int, err os.Error) {
  n = buf.Len()
  if n <= 0 {
    return 0, nil
  }
  err = p.allocate(n)
  if err != nil {
    return 0, err
  }

  start := p.data()
  var coffr Coffer
  coffr, err = NewPtrCoffer(start, n)
  if err != nil {
    return 0, err
  }

  var n64 int64
  n64, err = buf.WriteTo(coffr)
  if n64 == int64(n) && err == os.EOF {
    err = nil
  }
  return int(n64), err
}

func (p *lzmqMessage) ptr() *C.zmq_msg_t {
  return (*C.zmq_msg_t)(unsafe.Pointer(p))
}

func (p *lzmqMessage) data() uintptr {
  return uintptr(C.zmq_msg_data(p.ptr()))
}

func (p *lzmqMessage) getLzmqMessage() *lzmqMessage {
  return p
}

func (p *lzmqMessage) Close() os.Error {
  return p.Provider().OkIf(C.zmq_msg_close(p.ptr()) == 0)
}

// ******** lzmq: Sockets ********

// libzmq socket wrapper
type lzmqSocket uintptr

// Creates a new Socket with the given socketType
//
// Sockets only must be used from a fixed OSThread. This may be achieved
// by conveniently using Thunk.NewOSThread() or by calling runtime.LockOSThread()
func (p lzmqContext) NewSocket(socketType int) (Socket, os.Error) {
  ptr := unsafe.Pointer(C.zmq_socket(unsafe.Pointer(p), C.int(socketType)))
  if IsCNullPtr(uintptr(ptr)) {
    return nil, p.Provider().GetError()
  }
  return lzmqSocket(ptr), nil
}

func (p lzmqSocket) Provider() Provider { return LibZmqProvider() }

// Bind server socket
func (p lzmqSocket) Bind(address string) os.Error {
  ptr := unsafe.Pointer(p)
  // apparantly freed by zmq
  c_addr := C.CString(address)
  return p.Provider().OkIf(C.zmq_bind(ptr, c_addr) == 0)
}

// Connect client socket
func (p lzmqSocket) Connect(address string) os.Error {
  ptr := unsafe.Pointer(p)
  // apparantly freed by zmq
  c_addr := C.CString(address)
  return p.Provider().OkIf(C.zmq_connect(ptr, c_addr) == 0)
}

func (p lzmqSocket) Receive(msg Message, flags int) os.Error {
  if msg == nil {
    return os.EINVAL
  }
  lzmqMsgHolder, castable := msg.(lzmqMessageHolder)
  if !castable {
    return os.EINVAL
  }
  lzmqMsg := lzmqMsgHolder.getLzmqMessage()
  err := lzmqMsg.empty()
  if err != nil {
    return err
  }
  ret := p.Provider().OkIf(C.zmq_recv(unsafe.Pointer(p), lzmqMsg.ptr(), C.int(flags)) == 0)
  // fmt.Println("recv", msg)
  return ret
}

func (p lzmqSocket) Send(msg Message, flags int) os.Error {
  if msg == nil {
    return os.EINVAL
  }
  lzmqMsgHolder, err := msg.(lzmqMessageHolder)
  if err == false {
    return os.EINVAL
  }
  lzmqMsg := lzmqMsgHolder.getLzmqMessage()
  ret := p.Provider().OkIf(C.zmq_send(unsafe.Pointer(p), lzmqMsg.ptr(), C.int(flags)) == 0)
  // fmt.Println("sent", msg)
  return ret
}

func (p lzmqSocket) Flush() os.Error {
  return p.Provider().OkIf(C.zmq_flush(unsafe.Pointer(p)) == 0)
}

// Closes this socket
//
// Expects the executing go routine to still be locked onto an OSThread.
// May be called only once
func (p lzmqSocket) Close() os.Error {
  return p.Provider().OkIf(C.zmq_close(unsafe.Pointer(p)) == 0)
}

// ******** Watches ********

type lzmqWatch uintptr

func (p lzmqWatch) Stop() uint64 {
	return uint64(C.zmq_stopwatch_stop(unsafe.Pointer(p)))
}

// {}
<commit_msg>Added untested poll() API<commit_after>package zmq

// import "fmt"
import . "bytes"
import "io"
import "os"
import "unsafe"
import "strconv"
import . "unsafe/coffer"
import . "gonewrong"

// #include <zmq.h>
// #include <stdlib.h>
import "C"

// ******** Global ZMQ Constants ********

const (
  ZmqPoll        = C.ZMQ_POLL
  ZmqP2P         = C.ZMQ_P2P // About to be renamed as ZMQ_PAIR
  ZmqPair        = C.ZMQ_P2P
  ZmqPub         = C.ZMQ_PUB
  ZmqSub         = C.ZMQ_SUB
  ZmqReq         = C.ZMQ_REQ
  ZmqRep         = C.ZMQ_REP
  ZmqXReq        = C.ZMQ_XREQ
  ZmqXRep        = C.ZMQ_XREP
  ZmqUpstream    = C.ZMQ_UPSTREAM
  ZmqDownstream  = C.ZMQ_DOWNSTREAM
  ZmqNoBlock     = C.ZMQ_NOBLOCK
  ZmqNoFlush     = C.ZMQ_NOFLUSH
  ZmqPollIn      = C.ZMQ_POLLIN
  ZmqPollOut     = C.ZMQ_POLLOUT
  ZmqPollErr     = C.ZMQ_POLLERR
  ZmqHWM         = C.ZMQ_HWM
  ZmqLWM         = C.ZMQ_LWM
  ZmqSwap        = C.ZMQ_SWAP
  ZmqAffinity    = C.ZMQ_AFFINITY
  ZmqIdentitiy   = C.ZMQ_IDENTITY
  ZmqRate        = C.ZMQ_RATE
  ZmqSubscribe   = C.ZMQ_SUBSCRIBE
  ZmqUnsubscribe = C.ZMQ_UNSUBSCRIBE
  ZmqRecoveryIVL = C.ZMQ_RECOVERY_IVL
  ZmqMCastLoop   = C.ZMQ_MCAST_LOOP
  ZmqSendBuf     = C.ZMQ_SNDBUF
  ZmqSndBuf      = C.ZMQ_SNDBUF
  ZmqRecvBuf     = C.ZMQ_RCVBUF
  ZmqRcvBuf      = C.ZMQ_RCVBUF
)

// ******** ZMQ Interfaces ********

type Provider interface {
  ErrKnow // implemented in utils.go

  NewContext(initArgs InitArgs) (Context, os.Error)
  NewMessage() Message

  StartWatch() Watch

  Version() (major int, minor int, pl int)

  Sleep(secs int)
}

type Provided interface {
  Provider() Provider
}

// Arguments to New Context
type InitArgs struct {
  AppThreads int
  IoThreads  int
  Flags      int
}

// Sensible default init args
// AppThreads = EnvGOMAXPROCS(), IoThreads = 2, Flags = 0 /*no polling! */
func DefaultInitArgs() InitArgs {
  return InitArgs{AppThreads: EnvGOMAXPROCS(), IoThreads: 2, Flags: 0}
}

// Integer value of environment variable GOMAXPROCS if > 1, 1 otherwise
func EnvGOMAXPROCS() int {
  var maxProcs, error = strconv.Atoi(os.Getenv("GOMAXPROCS"))
  if error == nil && maxProcs > 1 {
    return maxProcs
  }
  return 1
}

// Context interface
//
// Contexts are always global thread-safe objects
type Context interface {
  io.Closer
  Provided

  NewSocket(socketType int) (Socket, os.Error)

	ProcPollItem(pi *PollItem, fdFun ProcFdFun, socketFun ProcSocketFun) os.Error
	Poll(items []PollItem, timeout int) (int, os.Error)

  Terminate() os.Error
}

type PollItem C.zmq_pollitem_t

type ProcFdFun func(fd int, events int8, revents int8)
type ProcSocketFun func(socket Socket, events int8, revents int8)

func SetFdPollItem(pi *PollItem, fd int, events int8) {
	pi.fd     = C.int(fd)
	pi.socket = unsafe.Pointer(uintptr(0))
	pi.events = C.short(events)
}

func (p lzmqSocket) SetPollItem(pi *PollItem, revents int8) os.Error {
	if pi == nil { return os.EINVAL }
	pi.socket  = unsafe.Pointer(uintptr(p))
	pi.revents = C.short(revents)
	pi.fd      = 0
	return nil
}

func (p lzmqContext) Poll(items []PollItem, timeout int) (int, os.Error) {
	ret := int(C.zmq_poll((*C.zmq_pollitem_t)(unsafe.Pointer(&items[0])), C.int(len(items)), C.long(timeout)))
	if (ret >= 0) { return ret, nil }
	return 0, p.Provider().GetError()
}

func (p lzmqContext) ProcPollItem(pi *PollItem, fdFun ProcFdFun, socketFun ProcSocketFun) os.Error {
	if pi == nil { return os.EINVAL }
	var ptr uintptr = uintptr(pi.socket)
	if IsCNullPtr(ptr) {
	  if fdFun != nil {
  		fdFun(int(pi.fd), int8(pi.events), int8(pi.revents))
		} else { return os.EINVAL }
  } else {
		if socketFun != nil {
			socketFun(lzmqSocket(ptr), int8(pi.events), int8(pi.revents))
		} else { return os.EINVAL }
	}
	return nil
}

// Message interface
//
// Messages may only be used reliably with sockets from the same provider
type Message interface {
  io.Closer
  Provided

  WriteTo(buf *Buffer) (n int, err os.Error)
  ReadFrom(buf *Buffer) (n int, err os.Error)

	// GetData(coffer Coffer) os.Error
	// SetData(coffer Coffer) os.Error

  MoveTo(msg Message) os.Error
  CopyTo(msg Message) os.Error

  Size() int
}

// Socket interface
//
// Sockets are typically thread-bound
type Socket interface {
  io.Closer
  Provided

  Bind(address string) os.Error
  Connect(address string) os.Error

  Receive(msg Message, flags int) os.Error
  Send(msg Message, flags int) os.Error

	SetPollItem(pi *PollItem, revents int8) os.Error

  Flush() os.Error
}

// Watch interface
type Watch interface {
	Stop() uint64
}

// ******** lzmq: Provider ********

// libzmq provider impl
func LibZmqProvider() Provider { return _libZmqProvider }

type libZmqProvider struct{}

var _libZmqProvider = new(libZmqProvider)

// ******** lzmq: Context ********

// libzmq context wrapper
type lzmqContext uintptr

// Creates a zmq context and returns it.
//
// Don't forget to set EnvGOMAXPROCS appropriately when working with libzmq
//
// Contexts are finalized by the GC unless they are manually destructed
// by calling Terminate() beforehand.  Applications need to arrange
// that no socket is used or even closed after the owning context has
// been destructed.  This requires to have at least one running go routine
// with a live referene to the context.
func (p libZmqProvider) NewContext(args InitArgs) (Context, os.Error) {
  contextPtr := C.zmq_init(
    C.int(args.AppThreads),
    C.int(args.IoThreads),
    C.int(args.Flags))

  if IsCNullPtr(uintptr(contextPtr)) {
    return nil, p.GetError()
  }

  lzmqContext := lzmqContext(contextPtr)
  return lzmqContext, nil
}

func (p *libZmqProvider) NewMessage() Message {
  msg := new(lzmqMessage)
  return msg
}

func (p *libZmqProvider) StartWatch() Watch {
	watch := uintptr(C.zmq_stopwatch_start())
	return lzmqWatch(watch)
}

// Type of error codes used by LibZmq
//
// Necessary since lzmq provides its own zmq_errno, zmq_strerror functions
type LibZmqErrno int

func (p LibZmqErrno) String() string { return C.GoString(C.zmq_strerror(C.int(p))) }

func (p *libZmqProvider) GetError() os.Error {
  return LibZmqErrno(C.zmq_errno())
}

func (p *libZmqProvider) OkIf(cond bool) os.Error { return p.ErrorIf(!cond) }

func (p *libZmqProvider) ErrorIf(cond bool) os.Error {
  if cond {
    err := p.GetError()
    if err != nil {
      return err
    }
  }
  return nil
}
func (p *libZmqProvider) Sleep(secs int) {
  if secs < 0 {
    return
  }
  C.zmq_sleep(C.int(secs))
}

func (p *libZmqProvider) Version() (major int, minor int, pl int) {
  C.zmq_version((*C.int)(unsafe.Pointer(&major)), (*C.int)(unsafe.Pointer(&minor)), (*C.int)(unsafe.Pointer(&pl)))
  return
}

func (p lzmqContext) Provider() Provider { return LibZmqProvider() }

// Calls Terminate()
func (p lzmqContext) Close() os.Error {
  return p.Terminate()
}

// Calls zmq_term on underlying context pointer
//
// Only call once
func (p lzmqContext) Terminate() os.Error {
  ch := make(chan os.Error)
  ptr := unsafe.Pointer(p)
  if ptr != nil {
    // Needs to run in separate go routine to safely lock the OS Thread
    // and synchronize via channel to know when we're done
    Thunk(func() {
      ch <- p.Provider().OkIf(C.zmq_term(ptr) == 0)
    }).RunInOSThread()
    // Wait for completion
    return <-ch
  }
  return nil
}

// ******** lzmq: Messages ********

type lzmqMessageHolder interface {
  Message

  getLzmqMessage() *lzmqMessage
}

type lzmqMessage C.zmq_msg_t

func (p *lzmqMessage) empty() os.Error {
  return p.Provider().OkIf(C.zmq_msg_init(p.ptr()) == 0)
}

func (p *lzmqMessage) allocate(length int) os.Error {
  return p.Provider().OkIf(C.zmq_msg_init_size(p.ptr(), C.size_t(length)) == 0)
}

func (p *lzmqMessage) Provider() Provider { return LibZmqProvider() }

func (p *lzmqMessage) Size() int {
  // size_t always fits int, we do not allocate larger messages
  return int(C.zmq_msg_size(p.ptr()))
}

func (p *lzmqMessage) MoveTo(msg Message) os.Error {
  if msg == nil {
    return os.EINVAL
  }
  lzmqMsgHolder, err := msg.(lzmqMessageHolder)
  if err == false {
    return os.EINVAL
  }
  lzmqMsg := lzmqMsgHolder.getLzmqMessage()

	return p.Provider().OkIf(C.zmq_msg_move(lzmqMsg.ptr(), p.ptr()) == 0)
}

func (p *lzmqMessage) CopyTo(msg Message) os.Error {
  if msg == nil {
    return os.EINVAL
  }
  lzmqMsgHolder, err := msg.(lzmqMessageHolder)
  if err == false {
    return os.EINVAL
  }
  lzmqMsg := lzmqMsgHolder.getLzmqMessage()

	return p.Provider().OkIf(C.zmq_msg_copy(lzmqMsg.ptr(), p.ptr()) == 0)
}

func (p *lzmqMessage) WriteTo(buf *Buffer) (n int, err os.Error) {
  n = p.Size()
  if n <= 0 {
    return 0, nil
  }
  start := p.data()
  var coffr Coffer
  coffr, err = NewPtrCoffer(start, n)
  if err != nil {
    return 0, err
  }

  var n64 int64
  n64, err = buf.ReadFrom(coffr)
  if n64 == int64(n) && err == os.EOF {
    err = nil
  }
  return int(n64), err
}

func (p *lzmqMessage) ReadFrom(buf *Buffer) (n int, err os.Error) {
  n = buf.Len()
  if n <= 0 {
    return 0, nil
  }
  err = p.allocate(n)
  if err != nil {
    return 0, err
  }

  start := p.data()
  var coffr Coffer
  coffr, err = NewPtrCoffer(start, n)
  if err != nil {
    return 0, err
  }

  var n64 int64
  n64, err = buf.WriteTo(coffr)
  if n64 == int64(n) && err == os.EOF {
    err = nil
  }
  return int(n64), err
}

func (p *lzmqMessage) ptr() *C.zmq_msg_t {
  return (*C.zmq_msg_t)(unsafe.Pointer(p))
}

func (p *lzmqMessage) data() uintptr {
  return uintptr(C.zmq_msg_data(p.ptr()))
}

func (p *lzmqMessage) getLzmqMessage() *lzmqMessage {
  return p
}

func (p *lzmqMessage) Close() os.Error {
  return p.Provider().OkIf(C.zmq_msg_close(p.ptr()) == 0)
}

// ******** lzmq: Sockets ********

// For casting
type lzmqSocketHolder interface {
	Socket

	getLzmqSocket() lzmqSocket
}

// libzmq socket wrapper
type lzmqSocket uintptr

// Creates a new Socket with the given socketType
//
// Sockets only must be used from a fixed OSThread. This may be achieved
// by conveniently using Thunk.NewOSThread() or by calling runtime.LockOSThread()
func (p lzmqContext) NewSocket(socketType int) (Socket, os.Error) {
  ptr := unsafe.Pointer(C.zmq_socket(unsafe.Pointer(p), C.int(socketType)))
  if IsCNullPtr(uintptr(ptr)) {
    return nil, p.Provider().GetError()
  }
  return lzmqSocket(ptr), nil
}

func (p lzmqSocket) getLzmqSocket() lzmqSocket {
	return p
}

func (p lzmqSocket) Provider() Provider { return LibZmqProvider() }

// Bind server socket
func (p lzmqSocket) Bind(address string) os.Error {
  ptr := unsafe.Pointer(p)
  // apparantly freed by zmq
  c_addr := C.CString(address)
  return p.Provider().OkIf(C.zmq_bind(ptr, c_addr) == 0)
}

// Connect client socket
func (p lzmqSocket) Connect(address string) os.Error {
  ptr := unsafe.Pointer(p)
  // apparantly freed by zmq
  c_addr := C.CString(address)
  return p.Provider().OkIf(C.zmq_connect(ptr, c_addr) == 0)
}

func (p lzmqSocket) Receive(msg Message, flags int) os.Error {
  if msg == nil {
    return os.EINVAL
  }
  lzmqMsgHolder, castable := msg.(lzmqMessageHolder)
  if !castable {
    return os.EINVAL
  }
  lzmqMsg := lzmqMsgHolder.getLzmqMessage()
  err := lzmqMsg.empty()
  if err != nil {
    return err
  }
  ret := p.Provider().OkIf(C.zmq_recv(unsafe.Pointer(p), lzmqMsg.ptr(), C.int(flags)) == 0)
  // fmt.Println("recv", msg)
  return ret
}

func (p lzmqSocket) Send(msg Message, flags int) os.Error {
  if msg == nil {
    return os.EINVAL
  }
  lzmqMsgHolder, err := msg.(lzmqMessageHolder)
  if err == false {
    return os.EINVAL
  }
  lzmqMsg := lzmqMsgHolder.getLzmqMessage()
  ret := p.Provider().OkIf(C.zmq_send(unsafe.Pointer(p), lzmqMsg.ptr(), C.int(flags)) == 0)
  // fmt.Println("sent", msg)
  return ret
}

func (p lzmqSocket) Flush() os.Error {
  return p.Provider().OkIf(C.zmq_flush(unsafe.Pointer(p)) == 0)
}

// Closes this socket
//
// Expects the executing go routine to still be locked onto an OSThread.
// May be called only once
func (p lzmqSocket) Close() os.Error {
  return p.Provider().OkIf(C.zmq_close(unsafe.Pointer(p)) == 0)
}

// ******** Watches ********

type lzmqWatch uintptr

func (p lzmqWatch) Stop() uint64 {
	return uint64(C.zmq_stopwatch_stop(unsafe.Pointer(p)))
}

// {}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"sort"
)

// Hand is the array of cards a player is holding. Max hand size will be ten card.
type Hand []Card

// ByValue container for cards sorted by value.
type ByValue Hand

// BySuit container for cards sorted by suit.
type BySuit Hand

// PickUpAble describes a type that can add a card to player's hand. These
// types are Deck and Stack.
type PickUpAble interface {
	Len() int
	Pop() Card
	DrawCard() Card
}

// ByValue implemented by Sort
func (hand ByValue) Len() int {
	return len(hand)
}
func (hand ByValue) Less(i, j int) bool {
	return hand[i].value < hand[j].value
}
func (hand ByValue) Swap(i, j int) {
	hand[i], hand[j] = hand[j], hand[i]
}

// BySuit implemented by Sort
func (hand BySuit) Len() int {
	return len(hand)
}
func (hand BySuit) Less(i, j int) bool {
	return hand[i].suit < hand[j].suit
}
func (hand BySuit) Swap(i, j int) {
	hand[i], hand[j] = hand[j], hand[i]
}

func (s *Stack) Len() int {
	return len(*s)
}

func (d *Deck) Len() int {
	return len(*d)
}

func (s *Stack) Pop() Card {
	return (*s)[:len(*s)-1], (*s)[len(*s)]
}

// PrettyPrint a player's hand. This is for the view.
func (hand Hand) PrettyPrint() (result string) {
	// First sort Cards then pretty print
	sort.Sort(ByValue(hand))
	for i, card := range hand {
		result += card.symbol + card.suit[:1]
		if i != len(hand)-1 {
			result += " "
		}
	}
	return
}

// String() allows us to pretty print everytime we pass it to fmt.Print.
func (hand *Hand) String() string {
	return hand.PrettyPrint()
}

// CheckTotal checks the total number of points in a player's hand. It must be // less than 10 to knock.
func (hand *Hand) CheckTotal() (total int) {
	hand.CheckMeld()
	// for i, card := range *hand {

	// }
	return
}

// CheckMeld checks the melds that can be made in the player's hand. There may // be more than one meld configuration for various hands.
func (hand *Hand) CheckMeld() Hand {
	sort.Sort(ByValue(*hand))
	sort.Sort(BySuit(*hand))
	return *hand
}

// DrawCard by popping a card from a pickupable and appending it to a player's hand.
func (hand *Hand) DrawCard(pickupable PickUpAble) (d *PickUpAble, err error) {
	p := pickupable
	if len(*hand) >= 11 {
		err = fmt.Errorf("cannot have a hand size more than 11")
		return
	}
	card := p.Len()
	p = p[:len(p)-1]
	*hand = append(*hand, card)
	return
}

// DiscardCard places a card on top of the stack.
func (hand *Hand) DiscardCard(stack *Stack) (err error) {
	return
}
<commit_msg>FIxed draw and discard from hand.<commit_after>package main

import (
	"fmt"
	"sort"
)

// Hand is the array of cards a player is holding. Max hand size will be ten card.
type Hand []Card

// ByValue container for cards sorted by value.
type ByValue Hand

// BySuit container for cards sorted by suit.
type BySuit Hand

// PickUpAble describes a type that can add a card to player's hand. These
// types are Deck and Stack.
type PickUpAble interface {
	DrawCard() Card
}

// ByValue implemented by Sort
func (hand ByValue) Len() int {
	return len(hand)
}
func (hand ByValue) Less(i, j int) bool {
	return hand[i].value < hand[j].value
}
func (hand ByValue) Swap(i, j int) {
	hand[i], hand[j] = hand[j], hand[i]
}

// BySuit implemented by Sort
func (hand BySuit) Len() int {
	return len(hand)
}
func (hand BySuit) Less(i, j int) bool {
	return hand[i].suit < hand[j].suit
}
func (hand BySuit) Swap(i, j int) {
	hand[i], hand[j] = hand[j], hand[i]
}

func (s *Stack) Len() int {
	return len(*s)
}

func (d *Deck) Len() int {
	return len(*d)
}

func (s *Stack) Pop() Card {
	return (*s)[:len(*s)-1], (*s)[len(*s)]
}

// PrettyPrint a player's hand. This is for the view.
func (h Hand) PrettyPrint() (result string) {
	// First sort Cards then pretty print
	sort.Sort(ByValue(h))
	for i, card := range h {
		result += card.symbol + card.suit[:1]
		if i != len(h)-1 {
			result += " "
		}
	}
	return
}

// String() allows us to pretty print everytime we pass it to fmt.Print.
func (h *Hand) String() string {
	return h.PrettyPrint()
}

// CheckTotal checks the total number of points in a player's hand. It must be // less than 10 to knock.
func (h *Hand) CheckTotal() (total int) {
	h.CheckMeld()
	// for i, card := range *hand {

	// }
	return
}

// CheckMeld checks the melds that can be made in the player's hand. There may // be more than one meld configuration for various hands.
func (h *Hand) CheckMeld() Hand {
	sort.Sort(ByValue(*h))
	sort.Sort(BySuit(*h))
	return *h
}

// DrawCard by popping a card from a pickupable and appending it to a player's hand.
func (h *Hand) DrawCard(p *PickUpAble) (err error) {
	if len(*h) >= 11 {
		err = fmt.Errorf("cannot have a hand size more than 11")
		return
	}
	*h = append(*h, (*p).DrawCard())
	return
}

// DiscardCard places a card on top of the stack.
func (h *Hand) DiscardCard(card Card, stack *Stack) (err error) {
	for i, v := range *h {
		if card == v {
			*h = append((*h)[:i], (*h)[i+1:]...)
			*stack = append((*stack), card)
		}
	}
	return
}
<|endoftext|>


<commit_before>package main

import "fmt"

type Pool []*Worker

func (p Pool) Len() int {
	return len(p)
}

func (p Pool) Less(i, j int) bool {
	return p[i].pending < p[j].pending
}

func (p Pool) Swap(i, j int) {
	p[i], p[j] = p[j], p[i]
}

func (p *Pool) Push(x interface{}) {
	*p = append(*p, x.(*Worker))
}

func (p *Pool) Pop() interface{} {
	prev := *p
	last := len(prev) - 1
	elem := prev[last]
	*p = prev[:last]
	return elem
}

func (p Pool) String() string {
	// TODO: Add str devation
	var workers string
	sum := 0
	for _, worker := range p {
		sum += worker.pending
		workers += string(worker.pending) + " "
	}
	avg := sum / len(p)
	return fmt.Sprintf("Workers: %v, Avg Load: %v", workers, avg)
}
<commit_msg>Fixed string method to have proper int to string conversion;<commit_after>package main

import (
	"fmt"
	"strconv"
)

type Pool []*Worker

func (p Pool) Len() int {
	return len(p)
}

func (p Pool) Less(i, j int) bool {
	return p[i].pending < p[j].pending
}

func (p Pool) Swap(i, j int) {
	p[i], p[j] = p[j], p[i]
}

func (p *Pool) Push(x interface{}) {
	*p = append(*p, x.(*Worker))
}

func (p *Pool) Pop() interface{} {
	prev := *p
	last := len(prev) - 1
	elem := prev[last]
	*p = prev[:last]
	return elem
}

func (p Pool) String() string {
	// TODO: Add str devation
	var (
		workers string
		sum     int
		avg     float32
	)
	for _, worker := range p {
		sum += worker.pending
		workers += strconv.Itoa(worker.pending) + " "
	}
	avg = float32(sum / len(p))
	return fmt.Sprintf("Workers: %v, Avg Load: %v", workers, avg)
}
<|endoftext|>


<commit_before>package delayd

import (
	"errors"
	"sync"
	"time"

	"github.com/streadway/amqp"
)

const consumerTag = "delayd-"

// AMQP manages amqp a connection and channel.
type AMQP struct {
	Channel    *amqp.Channel
	Connection *amqp.Connection
}

// NewAMQP connects to url and opens a communication channel and  it returns
// initialized AMQP instance.
func NewAMQP(url string) (*AMQP, error) {
	conn, err := amqp.Dial(url)
	if err != nil {
		return nil, err
	}

	ch, err := conn.Channel()
	if err != nil {
		return nil, err
	}

	return &AMQP{
		Connection: conn,
		Channel:    ch,
	}, nil
}

// Close the connection to amqp gracefully. A caller should ensure they finish
// all in-flight processing.
func (a *AMQP) Close() {
	a.Channel.Close()
	a.Connection.Close()
}

// AMQPConsumer represents general AMQP consumer.
type AMQPConsumer struct {
	*AMQP

	Config AMQPConfig
	Queue  amqp.Queue
}

// NewAMQPConsumer creates a consumer for AMQP and returns a AMQPConsumer instance.
func NewAMQPConsumer(config AMQPConfig, rk string) (*AMQPConsumer, error) {
	a, err := NewAMQP(config.URL)
	if err != nil {
		return nil, err
	}

	Debug("amqp: setting channel QoS to", config.Qos)
	if err := a.Channel.Qos(config.Qos, 0, false); err != nil {
		return nil, err
	}

	e := config.Exchange
	if err := a.Channel.ExchangeDeclare(
		e.Name,
		e.Kind,
		e.Durable,
		e.AutoDelete,
		e.Internal,
		e.NoWait,
		nil,
	); err != nil {
		return nil, err
	}

	q := config.Queue
	queue, err := a.Channel.QueueDeclare(
		q.Name,
		q.Durable,
		q.AutoDelete,
		q.Exclusive,
		q.NoWait,
		nil,
	)
	if err != nil {
		return nil, err
	}

	for _, exch := range config.Queue.Bind {
		if err := a.Channel.QueueBind(queue.Name, rk, exch, q.NoWait, nil); err != nil {
			return nil, err
		}
		Debugf("amqp: binded queue %s to exchange %s with routing key %s", queue.Name, exch, rk)
	}

	return &AMQPConsumer{
		AMQP:   a,
		Config: config,
		Queue:  queue,
	}, nil
}

// AMQPReceiver receives delayd commands over amqp
type AMQPReceiver struct {
	*AMQPConsumer

	c            chan Message
	shutdown     chan bool
	metaMessages chan (<-chan amqp.Delivery)
	messages     chan amqp.Delivery
	paused       bool
	tagCount     uint
	ac           AMQPConfig
	mu           sync.Mutex
}

// NewAMQPReceiver creates a new Receiver based on the provided Config,
// and starts it listening for commands.
func NewAMQPReceiver(ac AMQPConfig, routingKey string) (*AMQPReceiver, error) {
	a, err := NewAMQPConsumer(ac, routingKey)
	if err != nil {
		return nil, err
	}

	receiver := &AMQPReceiver{
		AMQPConsumer: a,

		c:            make(chan Message),
		messages:     make(chan amqp.Delivery, ac.Qos),
		metaMessages: make(chan (<-chan amqp.Delivery)),
		ac:           ac,
		paused:       true,
		shutdown:     make(chan bool),
	}

	go receiver.monitorChannel()
	go receiver.messageLoop()

	return receiver, nil
}

// monitorChannel monitors metaMessages channel.
// It installs new channel when metaMessages channel returns a channel
func (a *AMQPReceiver) monitorChannel() {
	var realMessages <-chan amqp.Delivery
	for {
		select {
		case <-a.shutdown:
			Debug("amqp: received signal to quit reading amqp, exiting goroutine")
			return
		case m := <-a.metaMessages:
			// we have a new source of 'real' messages. swap it in.
			realMessages = m
			Debug("amqp: new amqp channel is installed")
		case msg, ok := <-realMessages:
			// Don't propagate any channel close messages
			if ok {
				a.messages <- msg
			}
		}
	}
}

func (a *AMQPReceiver) messageLoop() {
	for {
		select {
		case <-a.shutdown:
			Debug("amqp: received signal to quit reading amqp, exiting goroutine")
			return
		case delivery := <-a.messages:
			deliverer := &AMQPDeliverer{Delivery: delivery}

			var delay int64
			switch val := delivery.Headers["delayd-delay"].(type) {
			case int32:
				delay = int64(val)
			case int64:
				delay = val
			default:
				Warn(delivery)
				Warn("amqp: bad/missing delay. discarding message")
				deliverer.Ack()
				continue
			}

			entry := &Entry{
				SendAt: time.Now().Add(time.Duration(delay) * time.Millisecond),
			}

			target, found := delivery.Headers["delayd-target"].(string)
			if !found {
				Warn("amqp: bad/missing target. discarding message")
				deliverer.Ack()
				continue
			}
			entry.Target = target

			// optional key value for overwrite
			if k, ok := delivery.Headers["delayd-key"].(string); ok {
				entry.Key = k
			}

			// optional headers that will be relayed
			entry.AMQP = &AMQPMessage{
				ContentType:     delivery.ContentType,
				ContentEncoding: delivery.ContentEncoding,
				CorrelationID:   delivery.CorrelationId,
			}

			entry.Body = delivery.Body
			msg := Message{
				Entry: entry,
				MessageDeliverer: &AMQPDeliverer{
					Delivery: delivery,
				},
			}
			a.c <- msg
		}
	}
}

// MessageCh returns a receiving-only channel returns Message
func (a *AMQPReceiver) MessageCh() <-chan Message {
	return a.c
}

// Close pauses the receiver and signals the shutdown channel.
// Finally, it closes AMQP the channel and connection.
// FIXME: Is this still restartable?
func (a *AMQPReceiver) Close() {
	a.Pause()
	close(a.shutdown)
	close(a.c)
	a.AMQP.Close()
}

// Start or restart listening for messages on the queue
func (a *AMQPReceiver) Start() error {
	a.mu.Lock()
	defer a.mu.Unlock()
	if !a.paused {
		// FIXME: already started?
		return nil
	}

	m, err := a.Channel.Consume(
		a.ac.Queue.Name,
		consumerTag+string(a.tagCount),
		a.ac.Queue.AutoAck,
		a.ac.Queue.Exclusive,
		a.ac.Queue.NoLocal,
		a.ac.Queue.NoWait,
		nil,
	)
	if err != nil {
		return err
	}

	a.paused = false
	a.tagCount++

	// Install new channel
	a.metaMessages <- m
	return err
}

// Pause listening for messages on the queue
func (a *AMQPReceiver) Pause() error {
	a.mu.Lock()
	defer a.mu.Unlock()
	if a.paused {
		return nil
	}
	a.paused = true
	return a.Channel.Cancel(consumerTag+string(a.tagCount), false)
}

// AMQPSender sends delayd entries over amqp after their timeout
type AMQPSender struct {
	*AMQP
}

// NewAMQPSender creates a new Sender connected to the given  URL.
func NewAMQPSender(amqpURL string) (*AMQPSender, error) {
	a, err := NewAMQP(amqpURL)
	if err != nil {
		return nil, err
	}

	return &AMQPSender{AMQP: a}, nil
}

// Send sends a delayd entry over , using the entry's Target as the publish
// exchange.
func (s *AMQPSender) Send(e *Entry) error {
	if e.AMQP == nil {
		return errors.New("amqp: invalid entry")
	}

	msg := amqp.Publishing{
		DeliveryMode:    amqp.Persistent,
		Timestamp:       time.Now(),
		ContentType:     e.AMQP.ContentType,
		ContentEncoding: e.AMQP.ContentEncoding,
		CorrelationId:   e.AMQP.CorrelationID,
		Body:            e.Body,
	}
	return s.Channel.Publish(e.Target, "", true, false, msg)
}
<commit_msg>amqp: cleanup<commit_after>package delayd

import (
	"errors"
	"sync"
	"time"

	"github.com/streadway/amqp"
)

const consumerTag = "delayd-"

// AMQP manages amqp a connection and channel.
type AMQP struct {
	Channel    *amqp.Channel
	Connection *amqp.Connection
}

// NewAMQP connects to url and opens a communication channel and  it returns
// initialized AMQP instance.
func NewAMQP(url string) (*AMQP, error) {
	conn, err := amqp.Dial(url)
	if err != nil {
		return nil, err
	}

	ch, err := conn.Channel()
	if err != nil {
		return nil, err
	}

	return &AMQP{
		Connection: conn,
		Channel:    ch,
	}, nil
}

// Close the connection to amqp gracefully. A caller should ensure they finish
// all in-flight processing.
func (a *AMQP) Close() {
	a.Channel.Close()
	a.Connection.Close()
}

// AMQPConsumer represents general AMQP consumer.
type AMQPConsumer struct {
	*AMQP

	Config AMQPConfig
	Queue  amqp.Queue
}

// NewAMQPConsumer creates a consumer for AMQP and returns a AMQPConsumer instance.
func NewAMQPConsumer(config AMQPConfig, rk string) (*AMQPConsumer, error) {
	a, err := NewAMQP(config.URL)
	if err != nil {
		return nil, err
	}

	Debug("amqp: setting channel QoS to", config.Qos)
	if err := a.Channel.Qos(config.Qos, 0, false); err != nil {
		return nil, err
	}

	e := config.Exchange
	if err := a.Channel.ExchangeDeclare(
		e.Name,
		e.Kind,
		e.Durable,
		e.AutoDelete,
		e.Internal,
		e.NoWait,
		nil,
	); err != nil {
		return nil, err
	}

	q := config.Queue
	queue, err := a.Channel.QueueDeclare(
		q.Name,
		q.Durable,
		q.AutoDelete,
		q.Exclusive,
		q.NoWait,
		nil,
	)
	if err != nil {
		return nil, err
	}

	for _, exch := range config.Queue.Bind {
		if err := a.Channel.QueueBind(queue.Name, rk, exch, q.NoWait, nil); err != nil {
			return nil, err
		}
		Debugf("amqp: binded queue %s to exchange %s with routing key %s", queue.Name, exch, rk)
	}

	return &AMQPConsumer{
		AMQP:   a,
		Config: config,
		Queue:  queue,
	}, nil
}

// AMQPReceiver receives delayd commands over amqp
type AMQPReceiver struct {
	*AMQPConsumer

	c            chan Message
	shutdown     chan struct{}
	metaMessages chan (<-chan amqp.Delivery)
	messages     chan amqp.Delivery
	paused       bool
	tagCount     uint
	ac           AMQPConfig
	mu           sync.Mutex
}

// NewAMQPReceiver creates a new Receiver based on the provided Config,
// and starts it listening for commands.
func NewAMQPReceiver(ac AMQPConfig, routingKey string) (*AMQPReceiver, error) {
	a, err := NewAMQPConsumer(ac, routingKey)
	if err != nil {
		return nil, err
	}

	receiver := &AMQPReceiver{
		AMQPConsumer: a,

		c:            make(chan Message),
		messages:     make(chan amqp.Delivery, ac.Qos),
		metaMessages: make(chan (<-chan amqp.Delivery)),
		ac:           ac,
		paused:       true,
		shutdown:     make(chan struct{}),
	}

	go receiver.monitorChannel()
	go receiver.messageLoop()

	return receiver, nil
}

// monitorChannel monitors metaMessages channel.
// It installs new channel when metaMessages channel returns a channel
func (a *AMQPReceiver) monitorChannel() {
	var realMessages <-chan amqp.Delivery
	for {
		select {
		case <-a.shutdown:
			Debug("amqp: received signal to quit reading amqp, exiting goroutine")
			return
		case m := <-a.metaMessages:
			// we have a new source of 'real' messages. swap it in.
			realMessages = m
			Debug("amqp: new amqp channel is installed")
		case msg, ok := <-realMessages:
			// Don't propagate any channel close messages
			if ok {
				a.messages <- msg
			}
		}
	}
}

func (a *AMQPReceiver) messageLoop() {
	for {
		select {
		case <-a.shutdown:
			Debug("amqp: received signal to quit reading amqp, exiting goroutine")
			return
		case delivery := <-a.messages:
			deliverer := &AMQPDeliverer{Delivery: delivery}

			var delay int64
			switch val := delivery.Headers["delayd-delay"].(type) {
			case int32:
				delay = int64(val)
			case int64:
				delay = val
			default:
				Warn(delivery)
				Warn("amqp: bad/missing delay. discarding message")
				deliverer.Ack()
				continue
			}

			entry := &Entry{
				SendAt: time.Now().Add(time.Duration(delay) * time.Millisecond),
			}

			target, found := delivery.Headers["delayd-target"].(string)
			if !found {
				Warn("amqp: bad/missing target. discarding message")
				deliverer.Ack()
				continue
			}
			entry.Target = target

			// optional key value for overwrite
			if k, ok := delivery.Headers["delayd-key"].(string); ok {
				entry.Key = k
			}

			// optional headers that will be relayed
			entry.AMQP = &AMQPMessage{
				ContentType:     delivery.ContentType,
				ContentEncoding: delivery.ContentEncoding,
				CorrelationID:   delivery.CorrelationId,
			}

			entry.Body = delivery.Body
			msg := Message{
				Entry:            entry,
				MessageDeliverer: deliverer,
			}
			a.c <- msg
		}
	}
}

// MessageCh returns a receiving-only channel returns Message
func (a *AMQPReceiver) MessageCh() <-chan Message {
	return a.c
}

// Close pauses the receiver and signals the shutdown channel.
// Finally, it closes AMQP the channel and connection.
func (a *AMQPReceiver) Close() {
	a.Pause()
	close(a.shutdown)
	close(a.c)
	a.AMQP.Close()
}

// Start or restart listening for messages on the queue
func (a *AMQPReceiver) Start() error {
	a.mu.Lock()
	defer a.mu.Unlock()
	if !a.paused {
		// FIXME: already started?
		return nil
	}

	m, err := a.Channel.Consume(
		a.ac.Queue.Name,
		consumerTag+string(a.tagCount),
		a.ac.Queue.AutoAck,
		a.ac.Queue.Exclusive,
		a.ac.Queue.NoLocal,
		a.ac.Queue.NoWait,
		nil,
	)
	if err != nil {
		return err
	}

	a.paused = false
	a.tagCount++

	// Install new channel
	a.metaMessages <- m
	return err
}

// Pause pauses listening for messages on the queue
func (a *AMQPReceiver) Pause() error {
	a.mu.Lock()
	defer a.mu.Unlock()
	if a.paused {
		return nil
	}
	a.paused = true
	return a.Channel.Cancel(consumerTag+string(a.tagCount), false)
}

// AMQPSender sends delayd entries over amqp after their timeout
type AMQPSender struct {
	*AMQP
}

// NewAMQPSender creates a new Sender connected to the given  URL.
func NewAMQPSender(amqpURL string) (*AMQPSender, error) {
	a, err := NewAMQP(amqpURL)
	if err != nil {
		return nil, err
	}

	return &AMQPSender{AMQP: a}, nil
}

// Send sends a delayd entry over AMQP, using the entry's Target as the publish
// exchange.
func (s *AMQPSender) Send(e *Entry) error {
	if e.AMQP == nil {
		return errors.New("amqp: invalid entry")
	}

	msg := amqp.Publishing{
		DeliveryMode:    amqp.Persistent,
		Timestamp:       time.Now(),
		ContentType:     e.AMQP.ContentType,
		ContentEncoding: e.AMQP.ContentEncoding,
		CorrelationId:   e.AMQP.CorrelationID,
		Body:            e.Body,
	}
	return s.Channel.Publish(e.Target, "", true, false, msg)
}
<|endoftext|>


<commit_before>// +build ansi

package main

import (
	"bufio"
	"errors"
	"fmt"
	"os"
	"os/exec"
	"time"

	termbox "github.com/nsf/termbox-go"
)

type AnsiCell struct {
	fg uicolor
	bg uicolor
	r  rune
}

type termui struct {
	bStdin     *bufio.Reader
	bStdout    *bufio.Writer
	cells      []AnsiCell
	backBuffer []AnsiCell
	cursor     position
}

func WindowsPalette() {
	ColorBgLOS = uicolor(termbox.ColorWhite)
	ColorBgDark = uicolor(termbox.ColorBlack)
	ColorBg = uicolor(termbox.ColorBlack)
	ColorBgCloud = uicolor(termbox.ColorWhite)
	ColorFgLOS = uicolor(termbox.ColorBlack)
	ColorFgDark = uicolor(termbox.ColorWhite)
	ColorFg = uicolor(termbox.ColorWhite)
	ColorFgPlayer = uicolor(termbox.ColorBlue)
	ColorFgMonster = uicolor(termbox.ColorRed)
	ColorFgSleepingMonster = uicolor(termbox.ColorCyan)
	ColorFgWanderingMonster = uicolor(termbox.ColorMagenta)
	ColorFgConfusedMonster = uicolor(termbox.ColorGreen)
	ColorFgCollectable = uicolor(termbox.ColorYellow)
	ColorFgStairs = uicolor(termbox.ColorMagenta)
	ColorFgGold = uicolor(termbox.ColorYellow)
	ColorFgHPok = uicolor(termbox.ColorGreen)
	ColorFgHPwounded = uicolor(termbox.ColorYellow)
	ColorFgHPcritical = uicolor(termbox.ColorRed)
	ColorFgMPok = uicolor(termbox.ColorBlue)
	ColorFgMPpartial = uicolor(termbox.ColorMagenta)
	ColorFgMPcritical = uicolor(termbox.ColorRed)
	ColorFgStatusGood = uicolor(termbox.ColorBlue)
	ColorFgStatusBad = uicolor(termbox.ColorRed)
	ColorFgStatusOther = uicolor(termbox.ColorYellow)
	ColorFgTargetMode = uicolor(termbox.ColorCyan)
	ColorFgTemporalWall = uicolor(termbox.ColorCyan)
}

const (
	UIWidth  = 103
	UIHeigth = 27
)

func (ui *termui) GetIndex(x, y int) int {
	return y*UIWidth + x
}

func (ui *termui) GetPos(i int) (int, int) {
	return i - (i/UIWidth)*UIWidth, i / UIWidth
}

func (ui *termui) ResetCells() {
	for i := 0; i < len(ui.cells); i++ {
		ui.cells[i].r = ' '
		ui.cells[i].bg = ColorBg
	}
}

func (ui *termui) Init() error {
	ui.bStdin = bufio.NewReader(os.Stdin)
	ui.bStdout = bufio.NewWriter(os.Stdout)
	ui.cells = make([]AnsiCell, UIWidth*UIHeigth)
	ui.ResetCells()
	ui.backBuffer = make([]AnsiCell, UIWidth*UIHeigth)
	fmt.Fprint(ui.bStdout, "\x1b[2J")
	// TODO: stty
	return nil
}

func (ui *termui) Close() {
	fmt.Fprint(ui.bStdout, "\x1b[2J")
	fmt.Fprintf(ui.bStdout, "\x1b[?25h")
	ui.bStdout.Flush()
}

func (ui *termui) PostInit() {
	//SolarizedPalette()
	FixColor()
	ui.HideCursor()
}

func (ui *termui) MoveTo(x, y int) {
	fmt.Fprintf(ui.bStdout, "\x1b[%d;%dH", y+1, x+1)
}

func (ui *termui) Clear() {
}

func (ui *termui) Flush() {
	for i := 0; i < len(ui.cells); i++ {
		if ui.cells[i] == ui.backBuffer[i] {
			continue
		}
		cell := ui.cells[i]
		x, y := ui.GetPos(i)
		ui.MoveTo(x, y)
		//fmt.Fprintf(ui.bStdout, "\x1b[%s;%sm", fgAttr, bgAttr)
		fmt.Fprintf(ui.bStdout, "\x1b[38;5;%dm", cell.fg)
		fmt.Fprintf(ui.bStdout, "\x1b[48;5;%dm", cell.bg)
		ui.bStdout.WriteRune(cell.r)
		fmt.Fprintf(ui.bStdout, "\x1b[0m")
		ui.backBuffer[i] = cell
	}
	ui.ResetCells()
	ui.MoveTo(ui.cursor.X, ui.cursor.Y)
	if ui.cursor.X >= 0 && ui.cursor.Y >= 0 {
		fmt.Fprintf(ui.bStdout, "\x1b[?25h")
	} else {
		fmt.Fprintf(ui.bStdout, "\x1b[?25l")
	}
	ui.bStdout.Flush()
}

func (ui *termui) HideCursor() {
	ui.cursor = position{-1, -1}
}

func (ui *termui) SetCursor(pos position) {
	//fmt.Fprintf(ui.bStdout, "\x1b[?25h")
	ui.cursor = pos
}

func (ui *termui) SetCell(x, y int, r rune, fg, bg uicolor) {
	//var fgAttr string
	//if fg <= 7 {
	//fgAttr = fmt.Sprintf("%d", fg)
	//} else {
	//fgAttr = fmt.Sprintf("1;%d", fg)
	//}
	//var bgAttr string
	//if bg <= 7 {
	//bgAttr = fmt.Sprintf("%d", 40+bg)
	//} else {
	//bgAttr = fmt.Sprintf("%d", 100+bg)
	//}
	i := ui.GetIndex(x, y)
	if i >= len(ui.cells) {
		return
	}
	ui.cells[ui.GetIndex(x, y)] = AnsiCell{fg: fg, bg: bg, r: r}

}

func (ui *termui) ReadChar() rune {
	cmd := exec.Command("stty", "-g")
	cmd.Stdin = os.Stdin
	save, err := cmd.Output()
	if err != nil {
		save = []byte("sane")
	}
	cmd = exec.Command("stty", "raw", "-echo")
	cmd.Stdin = os.Stdin
	cmd.Run()
	r, _, _ := ui.bStdin.ReadRune()
	cmd = exec.Command("stty", string(save))
	cmd.Stdin = os.Stdin
	cmd.Run()
	return r
}

func (ui *termui) ExploreStep(g *game) bool {
	time.Sleep(10 * time.Millisecond)
	ui.DrawDungeonView(g, false)
	return false
}

func (ui *termui) WaitForContinue(g *game) {
loop:
	for {
		r := ui.ReadChar()
		switch r {
		case '\x1b', ' ':
			break loop
		}
	}
}

func (ui *termui) PromptConfirmation(g *game) bool {
	for {
		r := ui.ReadChar()
		switch r {
		case 'Y', 'y':
			return true
		default:
			return false
		}
	}
}

func (ui *termui) PressAnyKey() error {
	for {
		ui.ReadChar()
		return nil
	}
}

func (ui *termui) PlayerTurnEvent(g *game, ev event) (err error, again, quit bool) {
	again = true
	r := ui.ReadChar()
	err, again, quit = ui.HandleCharacter(g, ev, r)
	if err != nil {
		again = true
	}
	return err, again, quit
}

func (ui *termui) Scroll(n int) (m int, quit bool) {
	r := ui.ReadChar()
	switch r {
	case '\x1b', ' ':
		quit = true
	case 'u':
		n -= 12
	case 'd':
		n += 12
	case 'j':
		n++
	case 'k':
		n--
	}
	return n, quit
}

func (ui *termui) TargetModeEvent(g *game, targ Targetter, pos position, data *examineData) bool {
	r := ui.ReadChar()
	if r == '\x1b' || r == ' ' {
		return true
	}
	return ui.CursorCharAction(g, targ, r, pos, data)
}

func (ui *termui) Select(g *game, ev event, l int) (index int, alternate bool, err error) {
	for {
		r := ui.ReadChar()
		switch {
		case r == '\x1b' || r == ' ':
			return -1, false, errors.New("Ok, then.")
		case 97 <= r && int(r) < 97+l:
			return int(r - 97), false, nil
		case r == '?':
			return -1, true, nil
		case r == ' ':
			return -1, false, errors.New("Ok, then.")
		}
	}
}
<commit_msg>remove outdated comments<commit_after>// +build ansi

package main

import (
	"bufio"
	"errors"
	"fmt"
	"os"
	"os/exec"
	"time"

	termbox "github.com/nsf/termbox-go"
)

type AnsiCell struct {
	fg uicolor
	bg uicolor
	r  rune
}

type termui struct {
	bStdin     *bufio.Reader
	bStdout    *bufio.Writer
	cells      []AnsiCell
	backBuffer []AnsiCell
	cursor     position
}

func WindowsPalette() {
	ColorBgLOS = uicolor(termbox.ColorWhite)
	ColorBgDark = uicolor(termbox.ColorBlack)
	ColorBg = uicolor(termbox.ColorBlack)
	ColorBgCloud = uicolor(termbox.ColorWhite)
	ColorFgLOS = uicolor(termbox.ColorBlack)
	ColorFgDark = uicolor(termbox.ColorWhite)
	ColorFg = uicolor(termbox.ColorWhite)
	ColorFgPlayer = uicolor(termbox.ColorBlue)
	ColorFgMonster = uicolor(termbox.ColorRed)
	ColorFgSleepingMonster = uicolor(termbox.ColorCyan)
	ColorFgWanderingMonster = uicolor(termbox.ColorMagenta)
	ColorFgConfusedMonster = uicolor(termbox.ColorGreen)
	ColorFgCollectable = uicolor(termbox.ColorYellow)
	ColorFgStairs = uicolor(termbox.ColorMagenta)
	ColorFgGold = uicolor(termbox.ColorYellow)
	ColorFgHPok = uicolor(termbox.ColorGreen)
	ColorFgHPwounded = uicolor(termbox.ColorYellow)
	ColorFgHPcritical = uicolor(termbox.ColorRed)
	ColorFgMPok = uicolor(termbox.ColorBlue)
	ColorFgMPpartial = uicolor(termbox.ColorMagenta)
	ColorFgMPcritical = uicolor(termbox.ColorRed)
	ColorFgStatusGood = uicolor(termbox.ColorBlue)
	ColorFgStatusBad = uicolor(termbox.ColorRed)
	ColorFgStatusOther = uicolor(termbox.ColorYellow)
	ColorFgTargetMode = uicolor(termbox.ColorCyan)
	ColorFgTemporalWall = uicolor(termbox.ColorCyan)
}

const (
	UIWidth  = 103
	UIHeigth = 27
)

func (ui *termui) GetIndex(x, y int) int {
	return y*UIWidth + x
}

func (ui *termui) GetPos(i int) (int, int) {
	return i - (i/UIWidth)*UIWidth, i / UIWidth
}

func (ui *termui) ResetCells() {
	for i := 0; i < len(ui.cells); i++ {
		ui.cells[i].r = ' '
		ui.cells[i].bg = ColorBg
	}
}

func (ui *termui) Init() error {
	ui.bStdin = bufio.NewReader(os.Stdin)
	ui.bStdout = bufio.NewWriter(os.Stdout)
	ui.cells = make([]AnsiCell, UIWidth*UIHeigth)
	ui.ResetCells()
	ui.backBuffer = make([]AnsiCell, UIWidth*UIHeigth)
	fmt.Fprint(ui.bStdout, "\x1b[2J")
	return nil
}

func (ui *termui) Close() {
	fmt.Fprint(ui.bStdout, "\x1b[2J")
	fmt.Fprintf(ui.bStdout, "\x1b[?25h")
	ui.bStdout.Flush()
}

func (ui *termui) PostInit() {
	FixColor()
	ui.HideCursor()
}

func (ui *termui) MoveTo(x, y int) {
	fmt.Fprintf(ui.bStdout, "\x1b[%d;%dH", y+1, x+1)
}

func (ui *termui) Clear() {
}

func (ui *termui) Flush() {
	for i := 0; i < len(ui.cells); i++ {
		if ui.cells[i] == ui.backBuffer[i] {
			continue
		}
		cell := ui.cells[i]
		x, y := ui.GetPos(i)
		ui.MoveTo(x, y)
		fmt.Fprintf(ui.bStdout, "\x1b[38;5;%dm", cell.fg)
		fmt.Fprintf(ui.bStdout, "\x1b[48;5;%dm", cell.bg)
		ui.bStdout.WriteRune(cell.r)
		fmt.Fprintf(ui.bStdout, "\x1b[0m")
		ui.backBuffer[i] = cell
	}
	ui.ResetCells()
	ui.MoveTo(ui.cursor.X, ui.cursor.Y)
	if ui.cursor.X >= 0 && ui.cursor.Y >= 0 {
		fmt.Fprintf(ui.bStdout, "\x1b[?25h")
	} else {
		fmt.Fprintf(ui.bStdout, "\x1b[?25l")
	}
	ui.bStdout.Flush()
}

func (ui *termui) HideCursor() {
	ui.cursor = position{-1, -1}
}

func (ui *termui) SetCursor(pos position) {
	ui.cursor = pos
}

func (ui *termui) SetCell(x, y int, r rune, fg, bg uicolor) {
	i := ui.GetIndex(x, y)
	if i >= len(ui.cells) {
		return
	}
	ui.cells[ui.GetIndex(x, y)] = AnsiCell{fg: fg, bg: bg, r: r}

}

func (ui *termui) ReadChar() rune {
	cmd := exec.Command("stty", "-g")
	cmd.Stdin = os.Stdin
	save, err := cmd.Output()
	if err != nil {
		save = []byte("sane")
	}
	cmd = exec.Command("stty", "raw", "-echo")
	cmd.Stdin = os.Stdin
	cmd.Run()
	r, _, _ := ui.bStdin.ReadRune()
	cmd = exec.Command("stty", string(save))
	cmd.Stdin = os.Stdin
	cmd.Run()
	return r
}

func (ui *termui) ExploreStep(g *game) bool {
	time.Sleep(10 * time.Millisecond)
	ui.DrawDungeonView(g, false)
	return false
}

func (ui *termui) WaitForContinue(g *game) {
loop:
	for {
		r := ui.ReadChar()
		switch r {
		case '\x1b', ' ':
			break loop
		}
	}
}

func (ui *termui) PromptConfirmation(g *game) bool {
	for {
		r := ui.ReadChar()
		switch r {
		case 'Y', 'y':
			return true
		default:
			return false
		}
	}
}

func (ui *termui) PressAnyKey() error {
	for {
		ui.ReadChar()
		return nil
	}
}

func (ui *termui) PlayerTurnEvent(g *game, ev event) (err error, again, quit bool) {
	again = true
	r := ui.ReadChar()
	err, again, quit = ui.HandleCharacter(g, ev, r)
	if err != nil {
		again = true
	}
	return err, again, quit
}

func (ui *termui) Scroll(n int) (m int, quit bool) {
	r := ui.ReadChar()
	switch r {
	case '\x1b', ' ':
		quit = true
	case 'u':
		n -= 12
	case 'd':
		n += 12
	case 'j':
		n++
	case 'k':
		n--
	}
	return n, quit
}

func (ui *termui) TargetModeEvent(g *game, targ Targetter, pos position, data *examineData) bool {
	r := ui.ReadChar()
	if r == '\x1b' || r == ' ' {
		return true
	}
	return ui.CursorCharAction(g, targ, r, pos, data)
}

func (ui *termui) Select(g *game, ev event, l int) (index int, alternate bool, err error) {
	for {
		r := ui.ReadChar()
		switch {
		case r == '\x1b' || r == ' ':
			return -1, false, errors.New("Ok, then.")
		case 97 <= r && int(r) < 97+l:
			return int(r - 97), false, nil
		case r == '?':
			return -1, true, nil
		case r == ' ':
			return -1, false, errors.New("Ok, then.")
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
    "os"
    "fmt"
    "bufio"
    "regexp"
    "strings"
    "time"
    "net/url"
    "flag"
    "errors"
)

type singleUrlsList []Url;
var tempUrls singleUrlsList;

var Usage = func() {
    fmt.Println("Yata");
}

func (u *singleUrlsList) String() string {
    return fmt.Sprint(*u);
}

func (u *singleUrlsList) Set(singleUrl string) error {
    if (!urlExists(singleUrl)) {
        parsedUrl, err := parseUrl(singleUrl);

        if (err != nil) {
            return err;
        } else {
            *u = append(*u, parsedUrl);
        }
    } else {
        return errors.New("Duplicated Url: "+singleUrl);
    }

    return nil;
}

func (u *urlsList) String() string {
    return fmt.Sprint(*u);
}

func (u *urlsList) Set(file string) error {
    urlFile, err = os.Open(file);

    if (err != nil) {
        return errors.New("Error opening file: " + err.Error());
    }

    defer urlFile.Close();

    scanner := bufio.NewScanner(urlFile)

    for scanner.Scan() {
        url := scanner.Text();
        if (!urlExists(url)) {
            parsedUrl, err := parseUrl(url);

            if (err != nil) {
                return err;
            } else {
                *u = append(*u, parsedUrl);
            }
        }
    }

    return nil;
}

func (c *cookiesList) String() string {
    return fmt.Sprint(*c);
}

func (c *cookiesList) Set(cookie string) error {
    cookie = strings.Trim(cookie, "\"' ");

    *c = append(*c, cookie);

    return nil;
}

func (h *headersList) String() string {
    return fmt.Sprint(*h);
}

func (h *headersList) Set(header string) error {
    parts := strings.Split(header, ":");

    if (len(parts) != 2) {
        return errors.New("Wrong header format. Example: 'accept-encoding: gzip, deflate'");
    }

    key := strings.Trim(parts[0], "\"' ");
    value := strings.Trim(parts[1], "\"' ");

    (*h)[key] = value;

    return nil;
}

func (p *proxyURL) String() string {
    return fmt.Sprint(*p);
}

func (p *proxyURL) Set(enteredUrl string) error {
    enteredUrl = strings.Trim(enteredUrl, "\" ");

    var validArg = regexp.MustCompile("^localhost");

    if (enteredUrl == "localhost" || validArg.MatchString(enteredUrl)) {
        enteredUrl = "http://" + enteredUrl;
    }

    tempProxy, err := url.Parse(enteredUrl);

    if (err != nil) {
        return errors.New("Wrong proxy format. Example: http://localhost:8441");
    }

    if (tempProxy.Scheme == "") {
        tempProxy.Scheme = "http";
    }

    *p = proxyURL(tempProxy.String());

    return nil;
}

func init() {
    // Make HTTP Custom headers map
    headers = make(headersList);

    // Number of concurrent requests
    defaultUsage := "The number of concurrent requests (Default is 1)";
    flag.IntVar(&concurrent, "concurrent", 1, defaultUsage);
    flag.IntVar(&concurrent, "c", 1, defaultUsage + " - Shorthand");

    // Number of total requests to be sent
    defaultUsage = "The number of total requests to send (Default is 1)";
    flag.IntVar(&requests, "requests", 1, defaultUsage);
    flag.IntVar(&requests, "r", 1, defaultUsage + " - Shorthand");

    // To be verbose or not to be
    defaultUsage = "Verbosity (Default is False)";
    flag.BoolVar(&verbose, "verbose", false, defaultUsage);
    flag.BoolVar(&verbose, "v", false, defaultUsage + " - Shorthand");

    // To be verbose or not to be
    defaultUsage = "Prevents re-use of TCP connections (Default is False)";
    flag.BoolVar(&disableKeepAlive, "disable-keep-alive", false, defaultUsage);
    flag.BoolVar(&disableKeepAlive, "d", false, defaultUsage + " - Shorthand");

    // Random interval
    defaultUsage = "A random interval in seconds between 0 and the defined number (Default is 0)";
    flag.IntVar(&delay, "delay", 0, defaultUsage);
    flag.IntVar(&delay, "de", 0, defaultUsage + " - Shorthand");

    // Username for basic HTTP Authentication
    defaultUsage = "Username for basic HTTP Authentication";
    flag.StringVar(&basicAuthUsername, "username", "", defaultUsage);
    flag.StringVar(&basicAuthUsername, "user", "", defaultUsage + " - Shorthand");

    // Password for basic HTTP Authentication
    defaultUsage = "Password for basic HTTP Authentication";
    flag.StringVar(&basicAuthPassword, "password", "", defaultUsage);
    flag.StringVar(&basicAuthPassword, "pass", "", defaultUsage + " - Shorthand");

    // Response header timeout
    var tempResponseTimeout int;
    defaultUsage = "Specifies the amount of time to wait for a server's response headers (Default is 0 which means no timeout)";
    flag.IntVar(&tempResponseTimeout, "response-timeout", 0, defaultUsage);
    flag.IntVar(&tempResponseTimeout, "t", 0, defaultUsage + " - Shorthand");
    responseTimeout = time.Duration(tempResponseTimeout) * time.Second;

    // Connection timeout
    var tempConnectionTimeout int;
    defaultUsage = "Specifies the amount of time to wait for establishment of connection (Default is 0 which means no timeout)";
    flag.IntVar(&tempConnectionTimeout, "connection-timeout", 0, defaultUsage);
    flag.IntVar(&tempConnectionTimeout, "ct", 0, defaultUsage + " - Shorthand");
    connectionTimeout = time.Duration(tempConnectionTimeout) * time.Second;

    // Benchmarking url file
    defaultUsage = "Address of file containing urls to benchmark. This field is repeatable.";
    flag.Var(&urls, "file", defaultUsage);
    flag.Var(&urls, "f", defaultUsage + " - Shorthand");

    // Single URL to benchmark
    defaultUsage = "Single URL to benchmark. This field is repeatable.";
    flag.Var(&tempUrls, "url", defaultUsage);
    flag.Var(&tempUrls, "u", defaultUsage + " - Shorthand");

    // Custome cookies
    defaultUsage = "Custom cookies. This field is repeatable.";
    flag.Var(&cookies, "cookie", defaultUsage);
    flag.Var(&cookies, "co", defaultUsage + " - Shorthand");

    // Custom Headers
    defaultUsage = "Additional header information to send. This field is repeatable.";
    flag.Var(&headers, "header", defaultUsage);
    flag.Var(&headers, "he", defaultUsage + " - Shorthand");

    // HTTP proxy
    defaultUsage = "Proxy server to use.";
    flag.Var(&proxyUrl, "proxy", defaultUsage);
    flag.Var(&proxyUrl, "p", defaultUsage + " - Shorthand");

    flag.Usage = func() {
        flagDefaults();
    }

    flag.Parse();

    for _, singleUrl := range urls {
        urls = append(urls, singleUrl);
    }

    if (requests == 0 || concurrent == 0 || requests < concurrent || len(urls) == 0) {
        flagDefaults();
        os.Exit(1);
    }
}

func flagDefaults () {
    fmt.Fprintf(os.Stderr, "\nUsage of gbnech:\n");
    flag.VisitAll(func(f *flag.Flag) {
        fmt.Printf("-%v: %v\n", f.Name, f.Usage);
    });

    fmt.Println("\nURL format should be as follow:");
    fmt.Println("METHOD|URL|POSTDATA or METHOD|URL");
    fmt.Println("Sample URLs: GET|www.google.com?search=test or POST|www.google.com|search=test or HEAD|www.google.com");
    fmt.Println("\nExamples:");
    fmt.Println("gbench -file ~/benchmarkurl.txt -r 100 -c 10 -v");
    fmt.Println("gbench -url www.google.com -url www.yahoo.com -r 100 -c 10 -v");
}

func parseUrl(enteredUrl string) (details Url, parseErr error) {

    enteredUrl = strings.Trim(enteredUrl, "\" ");
    parts := strings.Split(enteredUrl, "|");

    if ((len(parts) != 2 && len(parts) != 3) || (strings.ToUpper(parts[0]) != "GET" && strings.ToUpper(parts[0]) != "POST" && strings.ToUpper(parts[0]) != "HEAD")) {
        parseErr = errors.New("Wrong URL format. Example: GET|www.google.com?search=test or POST|www.google.com|search=test or HEAD|www.google.com");
    } else {

        details.method = strings.ToUpper(parts[0]);

        urlStruct, err := url.Parse(parts[1]);

        if (err != nil) {
            parseErr = errors.New("Wrong URL format: " + err.Error());
        } else {
            if (urlStruct.Scheme == "") {
                urlStruct.Scheme = "http";
            }

            details.url = urlStruct.String();

            if (details.method == "POST") {
                if (len(parts) == 3) {
                    details.data = make(map[string]string);
                    dataParts := strings.Split(parts[2], "&");

                    for i := 0; i < len(dataParts); i++ {
                        keyValue := strings.Split(dataParts[i], "=");
                        details.data[keyValue[0]] = keyValue[1];
                    }
                } else {
                    parseErr = errors.New("Wrong URL format. You need to provide post data. Example: POST|www.google.com|name=sasan&lastname=rose");
                }
            }
        }
    }

    return details, err;
}

func urlExists(url string) bool {
    for _, u := range urls {
        if (url == u.url) {
            return true;
        }
    }

    return false;
}
<commit_msg>tempUrls should be used + return parseErr<commit_after>package main

import (
    "os"
    "fmt"
    "bufio"
    "regexp"
    "strings"
    "time"
    "net/url"
    "flag"
    "errors"
)

type singleUrlsList []Url;
var tempUrls singleUrlsList;

var Usage = func() {
    fmt.Println("Yata");
}

func (u *singleUrlsList) String() string {
    return fmt.Sprint(*u);
}

func (u *singleUrlsList) Set(singleUrl string) error {
    if (!urlExists(singleUrl)) {
        parsedUrl, err := parseUrl(singleUrl);

        if (err != nil) {
            return err;
        } else {
            *u = append(*u, parsedUrl);
        }
    } else {
        return errors.New("Duplicated Url: "+singleUrl);
    }

    return nil;
}

func (u *urlsList) String() string {
    return fmt.Sprint(*u);
}

func (u *urlsList) Set(file string) error {
    urlFile, err = os.Open(file);

    if (err != nil) {
        return errors.New("Error opening file: " + err.Error());
    }

    defer urlFile.Close();

    scanner := bufio.NewScanner(urlFile)

    for scanner.Scan() {
        url := scanner.Text();
        if (!urlExists(url)) {
            parsedUrl, err := parseUrl(url);

            if (err != nil) {
                return err;
            } else {
                *u = append(*u, parsedUrl);
            }
        }
    }

    return nil;
}

func (c *cookiesList) String() string {
    return fmt.Sprint(*c);
}

func (c *cookiesList) Set(cookie string) error {
    cookie = strings.Trim(cookie, "\"' ");

    *c = append(*c, cookie);

    return nil;
}

func (h *headersList) String() string {
    return fmt.Sprint(*h);
}

func (h *headersList) Set(header string) error {
    parts := strings.Split(header, ":");

    if (len(parts) != 2) {
        return errors.New("Wrong header format. Example: 'accept-encoding: gzip, deflate'");
    }

    key := strings.Trim(parts[0], "\"' ");
    value := strings.Trim(parts[1], "\"' ");

    (*h)[key] = value;

    return nil;
}

func (p *proxyURL) String() string {
    return fmt.Sprint(*p);
}

func (p *proxyURL) Set(enteredUrl string) error {
    enteredUrl = strings.Trim(enteredUrl, "\" ");

    var validArg = regexp.MustCompile("^localhost");

    if (enteredUrl == "localhost" || validArg.MatchString(enteredUrl)) {
        enteredUrl = "http://" + enteredUrl;
    }

    tempProxy, err := url.Parse(enteredUrl);

    if (err != nil) {
        return errors.New("Wrong proxy format. Example: http://localhost:8441");
    }

    if (tempProxy.Scheme == "") {
        tempProxy.Scheme = "http";
    }

    *p = proxyURL(tempProxy.String());

    return nil;
}

func init() {
    // Make HTTP Custom headers map
    headers = make(headersList);

    // Number of concurrent requests
    defaultUsage := "The number of concurrent requests (Default is 1)";
    flag.IntVar(&concurrent, "concurrent", 1, defaultUsage);
    flag.IntVar(&concurrent, "c", 1, defaultUsage + " - Shorthand");

    // Number of total requests to be sent
    defaultUsage = "The number of total requests to send (Default is 1)";
    flag.IntVar(&requests, "requests", 1, defaultUsage);
    flag.IntVar(&requests, "r", 1, defaultUsage + " - Shorthand");

    // To be verbose or not to be
    defaultUsage = "Verbosity (Default is False)";
    flag.BoolVar(&verbose, "verbose", false, defaultUsage);
    flag.BoolVar(&verbose, "v", false, defaultUsage + " - Shorthand");

    // To be verbose or not to be
    defaultUsage = "Prevents re-use of TCP connections (Default is False)";
    flag.BoolVar(&disableKeepAlive, "disable-keep-alive", false, defaultUsage);
    flag.BoolVar(&disableKeepAlive, "d", false, defaultUsage + " - Shorthand");

    // Random interval
    defaultUsage = "A random interval in seconds between 0 and the defined number (Default is 0)";
    flag.IntVar(&delay, "delay", 0, defaultUsage);
    flag.IntVar(&delay, "de", 0, defaultUsage + " - Shorthand");

    // Username for basic HTTP Authentication
    defaultUsage = "Username for basic HTTP Authentication";
    flag.StringVar(&basicAuthUsername, "username", "", defaultUsage);
    flag.StringVar(&basicAuthUsername, "user", "", defaultUsage + " - Shorthand");

    // Password for basic HTTP Authentication
    defaultUsage = "Password for basic HTTP Authentication";
    flag.StringVar(&basicAuthPassword, "password", "", defaultUsage);
    flag.StringVar(&basicAuthPassword, "pass", "", defaultUsage + " - Shorthand");

    // Response header timeout
    var tempResponseTimeout int;
    defaultUsage = "Specifies the amount of time to wait for a server's response headers (Default is 0 which means no timeout)";
    flag.IntVar(&tempResponseTimeout, "response-timeout", 0, defaultUsage);
    flag.IntVar(&tempResponseTimeout, "t", 0, defaultUsage + " - Shorthand");
    responseTimeout = time.Duration(tempResponseTimeout) * time.Second;

    // Connection timeout
    var tempConnectionTimeout int;
    defaultUsage = "Specifies the amount of time to wait for establishment of connection (Default is 0 which means no timeout)";
    flag.IntVar(&tempConnectionTimeout, "connection-timeout", 0, defaultUsage);
    flag.IntVar(&tempConnectionTimeout, "ct", 0, defaultUsage + " - Shorthand");
    connectionTimeout = time.Duration(tempConnectionTimeout) * time.Second;

    // Benchmarking url file
    defaultUsage = "Address of file containing urls to benchmark. This field is repeatable.";
    flag.Var(&urls, "file", defaultUsage);
    flag.Var(&urls, "f", defaultUsage + " - Shorthand");

    // Single URL to benchmark
    defaultUsage = "Single URL to benchmark. This field is repeatable.";
    flag.Var(&tempUrls, "url", defaultUsage);
    flag.Var(&tempUrls, "u", defaultUsage + " - Shorthand");

    // Custome cookies
    defaultUsage = "Custom cookies. This field is repeatable.";
    flag.Var(&cookies, "cookie", defaultUsage);
    flag.Var(&cookies, "co", defaultUsage + " - Shorthand");

    // Custom Headers
    defaultUsage = "Additional header information to send. This field is repeatable.";
    flag.Var(&headers, "header", defaultUsage);
    flag.Var(&headers, "he", defaultUsage + " - Shorthand");

    // HTTP proxy
    defaultUsage = "Proxy server to use.";
    flag.Var(&proxyUrl, "proxy", defaultUsage);
    flag.Var(&proxyUrl, "p", defaultUsage + " - Shorthand");

    flag.Usage = func() {
        flagDefaults();
    }

    flag.Parse();

    for _, singleUrl := range tempUrls {
        urls = append(urls, singleUrl);
    }

    if (requests == 0 || concurrent == 0 || requests < concurrent || len(urls) == 0) {
        flagDefaults();
        os.Exit(1);
    }
}

func flagDefaults () {
    fmt.Fprintf(os.Stderr, "\nUsage of gbnech:\n");
    flag.VisitAll(func(f *flag.Flag) {
        fmt.Printf("-%v: %v\n", f.Name, f.Usage);
    });

    fmt.Println("\nURL format should be as follow:");
    fmt.Println("METHOD|URL|POSTDATA or METHOD|URL");
    fmt.Println("Sample URLs: GET|www.google.com?search=test or POST|www.google.com|search=test or HEAD|www.google.com");
    fmt.Println("\nExamples:");
    fmt.Println("gbench -file ~/benchmarkurl.txt -r 100 -c 10 -v");
    fmt.Println("gbench -url www.google.com -url www.yahoo.com -r 100 -c 10 -v");
}

func parseUrl(enteredUrl string) (details Url, parseErr error) {

    enteredUrl = strings.Trim(enteredUrl, "\" ");
    parts := strings.Split(enteredUrl, "|");

    if ((len(parts) != 2 && len(parts) != 3) || (strings.ToUpper(parts[0]) != "GET" && strings.ToUpper(parts[0]) != "POST" && strings.ToUpper(parts[0]) != "HEAD")) {
        parseErr = errors.New("Wrong URL format. Example: GET|www.google.com?search=test or POST|www.google.com|search=test or HEAD|www.google.com");
    } else {

        details.method = strings.ToUpper(parts[0]);

        urlStruct, err := url.Parse(parts[1]);

        if (err != nil) {
            parseErr = errors.New("Wrong URL format: " + err.Error());
        } else {
            if (urlStruct.Scheme == "") {
                urlStruct.Scheme = "http";
            }

            details.url = urlStruct.String();

            if (details.method == "POST") {
                if (len(parts) == 3) {
                    details.data = make(map[string]string);
                    dataParts := strings.Split(parts[2], "&");

                    for i := 0; i < len(dataParts); i++ {
                        keyValue := strings.Split(dataParts[i], "=");
                        details.data[keyValue[0]] = keyValue[1];
                    }
                } else {
                    parseErr = errors.New("Wrong URL format. You need to provide post data. Example: POST|www.google.com|name=sasan&lastname=rose");
                }
            }
        }
    }

    return details, parseErr;
}

func urlExists(url string) bool {
    for _, u := range urls {
        if (url == u.url) {
            return true;
        }
    }

    return false;
}
<|endoftext|>


<commit_before>package gocli

import (
	"strconv"
	"regexp"
	"strings"
	"fmt"
)

const (
	STRING = "string"
	BOOL = "bool"
)

var (
	re = regexp.MustCompile("^([\\-]+.*)")
)

type Args struct {
	Args []string
	Attributes map[string][]string
	currentKey string
	FlagMap map[string]*Flag
	Flags []*Flag
}

type Flag struct {
	Type string
	Keys []string
	Required bool
	DefaultValue string
	Description string
}

func (f *Flag) Matches(key string) bool {
	for _, k := range f.Keys {
		if strings.HasPrefix(k, key) {
			return true
		}
	}
	return false
}

func (a *Args) RegisterFlag(flag *Flag) {
	if a.FlagMap == nil {
		a.FlagMap = make(map[string]*Flag)
	}
	for _, key := range flag.Keys {
		a.FlagMap[key] = flag
	}
	a.Flags = append(a.Flags, flag)
}

func (a *Args) RegisterString(key string, required bool, defaultValue, description string) {
	a.RegisterFlag(
		&Flag{
			Type: STRING,
			Keys: []string { key },
			Required: required,
			DefaultValue: defaultValue,
			Description: description,
		},
	)
}

func (a *Args) RegisterBool(key string, required bool, defaultValue bool, description string) {
	a.RegisterFlag(
		&Flag{
			Type: STRING,
			Keys: []string { key },
			Required: required,
			DefaultValue: strconv.FormatBool(required),
			Description: description,
		},
	)
}

func (f *Flag) Usage() []string {
	parts := make([]string, 3)
	parts[0] = strings.Join(f.Keys, ", ")
	if f.Required {
		parts[1] = "REQUIRED"
	} else {
		parts[1] = fmt.Sprintf("DEFAULT: %q", f.DefaultValue)
	}
	parts[2] = f.Description

	return parts
}

func (a *Args) Usage() string {
	table := NewTable()
	table.Separator = " "
	for _, flag := range a.Flags {
		table.Add(flag.Usage()...)
	}
	return table.String()
}

func (a *Args) lookup(key string) (flags []*Flag) {
	for i := range a.Flags {
		arg := a.Flags[i]
		if arg.Matches(key) {
			flags = append(flags, arg)
		}
	}
	return flags
}

func (a *Args) Length() int {
	return len(a.Args)
}

func (a *Args) String(key string) {
	a.AddFlag(key, STRING)
}

func (a *Args) Bool(key string) {
	a.AddFlag(key, BOOL)
}

func (a *Args) AddFlag(key, value string) {
	a.RegisterFlag(&Flag{Type: value, Keys: []string { key }})
}

func (a *Args) AddAttribute(k, v string) {
	if a.Attributes == nil {
		a.Attributes = map[string][]string{}
	}
	a.Attributes[k] = append(a.Attributes[k], v)
}

func (a *Args) Parse(args []string) error {
	a.Args = make([]string, 0, 10)
	a.Attributes = make(map[string][]string)
	for _, arg := range args {
		if e := a.handleArg(arg); e != nil {
			return e
		}
	}
	return nil
}

func (a *Args) TypeOf(key string) (string, error) {
	flags := a.lookup(key)
	switch len(flags) {
		case 0:
			return "", fmt.Errorf("no mapping defined for %s", key)
		case 1:
			return flags[0].Type, nil
		default:
			return "", fmt.Errorf("mapping for %s not uniq", key)
	}
}

func (a *Args) handleArgFlag(flag string) error {
	if t, e := a.TypeOf(flag); e != nil {
		return e
	} else {
		switch t {
			case STRING:
				a.currentKey = flag
			case BOOL:
				a.AddAttribute(flag, "true")
			default:
				return fmt.Errorf("no mapping defined for %s", flag)
		}
	}
	return nil
}

func (a *Args) handleArg(arg string ) error {
	if parts := re.FindStringSubmatch(arg); len(parts) == 2 {
		chunks := strings.Split(parts[1], "=")
		if len(chunks) == 2 {
			key, value := chunks[0], chunks[1]
			a.AddAttribute(key, value)
			return nil
		} else {
			if e := a.handleArgFlag(chunks[0]); e != nil {
				return e
			}
			return nil
		}
	} else if a.currentKey != "" {
		a.AddAttribute(a.currentKey, arg)
		a.currentKey = ""
		return nil
	}
	a.Args = append(a.Args, arg)
	return nil
}

func (a *Args) Get(key string) ([]string) {
	return a.Attributes[key]
}

func (a *Args) GetString(key string) (string, error) {
	flag, ok := a.FlagMap[key]
	if !ok {
		return "", fmt.Errorf("no mapping defined for %s", key)
	}
	values := a.Get(key)
	if len(values) > 0 {
		return values[len(values)-1], nil
	}
	if flag.Required {
		return "", fmt.Errorf("flag %s is required", key)
	}
	return flag.DefaultValue, nil
}

func (a *Args) GetBool(key string) bool {
	args := a.Attributes[key]
	return (len(args) == 1 && args[0] == "true")
}
<commit_msg>try to add go 1.0 compatibility<commit_after>package gocli

import (
	"strconv"
	"regexp"
	"strings"
	"fmt"
)

const (
	STRING = "string"
	BOOL = "bool"
)

var (
	re = regexp.MustCompile("^([\\-]+.*)")
)

type Args struct {
	Args []string
	Attributes map[string][]string
	currentKey string
	FlagMap map[string]*Flag
	Flags []*Flag
}

type Flag struct {
	Type string
	Keys []string
	Required bool
	DefaultValue string
	Description string
}

func (f *Flag) Matches(key string) bool {
	for _, k := range f.Keys {
		if strings.HasPrefix(k, key) {
			return true
		}
	}
	return false
}

func (a *Args) RegisterFlag(flag *Flag) {
	if a.FlagMap == nil {
		a.FlagMap = make(map[string]*Flag)
	}
	for _, key := range flag.Keys {
		a.FlagMap[key] = flag
	}
	a.Flags = append(a.Flags, flag)
}

func (a *Args) RegisterString(key string, required bool, defaultValue, description string) {
	a.RegisterFlag(
		&Flag{
			Type: STRING,
			Keys: []string { key },
			Required: required,
			DefaultValue: defaultValue,
			Description: description,
		},
	)
}

func (a *Args) RegisterBool(key string, required bool, defaultValue bool, description string) {
	a.RegisterFlag(
		&Flag{
			Type: STRING,
			Keys: []string { key },
			Required: required,
			DefaultValue: strconv.FormatBool(required),
			Description: description,
		},
	)
}

func (f *Flag) Usage() []string {
	parts := make([]string, 3)
	parts[0] = strings.Join(f.Keys, ", ")
	if f.Required {
		parts[1] = "REQUIRED"
	} else {
		parts[1] = fmt.Sprintf("DEFAULT: %q", f.DefaultValue)
	}
	parts[2] = f.Description

	return parts
}

func (a *Args) Usage() string {
	table := NewTable()
	table.Separator = " "
	for _, flag := range a.Flags {
		table.Add(flag.Usage()...)
	}
	return table.String()
}

func (a *Args) lookup(key string) (flags []*Flag) {
	for i := range a.Flags {
		arg := a.Flags[i]
		if arg.Matches(key) {
			flags = append(flags, arg)
		}
	}
	return flags
}

func (a *Args) Length() int {
	return len(a.Args)
}

func (a *Args) String(key string) {
	a.AddFlag(key, STRING)
}

func (a *Args) Bool(key string) {
	a.AddFlag(key, BOOL)
}

func (a *Args) AddFlag(key, value string) {
	a.RegisterFlag(&Flag{Type: value, Keys: []string { key }})
}

func (a *Args) AddAttribute(k, v string) {
	if a.Attributes == nil {
		a.Attributes = map[string][]string{}
	}
	a.Attributes[k] = append(a.Attributes[k], v)
}

func (a *Args) Parse(args []string) error {
	a.Args = make([]string, 0, 10)
	a.Attributes = make(map[string][]string)
	for _, arg := range args {
		if e := a.handleArg(arg); e != nil {
			return e
		}
	}
	return nil
}

func (a *Args) TypeOf(key string) (out string, e error) {
	flags := a.lookup(key)
	switch len(flags) {
		case 0:
			e = fmt.Errorf("no mapping defined for %s", key)
		case 1:
			out = flags[0].Type
		default:
			e = fmt.Errorf("mapping for %s not uniq", key)
	}
	return out, e
}

func (a *Args) handleArgFlag(flag string) error {
	if t, e := a.TypeOf(flag); e != nil {
		return e
	} else {
		switch t {
			case STRING:
				a.currentKey = flag
			case BOOL:
				a.AddAttribute(flag, "true")
			default:
				return fmt.Errorf("no mapping defined for %s", flag)
		}
	}
	return nil
}

func (a *Args) handleArg(arg string ) error {
	if parts := re.FindStringSubmatch(arg); len(parts) == 2 {
		chunks := strings.Split(parts[1], "=")
		if len(chunks) == 2 {
			key, value := chunks[0], chunks[1]
			a.AddAttribute(key, value)
			return nil
		} else {
			if e := a.handleArgFlag(chunks[0]); e != nil {
				return e
			}
			return nil
		}
	} else if a.currentKey != "" {
		a.AddAttribute(a.currentKey, arg)
		a.currentKey = ""
		return nil
	}
	a.Args = append(a.Args, arg)
	return nil
}

func (a *Args) Get(key string) ([]string) {
	return a.Attributes[key]
}

func (a *Args) GetString(key string) (string, error) {
	flag, ok := a.FlagMap[key]
	if !ok {
		return "", fmt.Errorf("no mapping defined for %s", key)
	}
	values := a.Get(key)
	if len(values) > 0 {
		return values[len(values)-1], nil
	}
	if flag.Required {
		return "", fmt.Errorf("flag %s is required", key)
	}
	return flag.DefaultValue, nil
}

func (a *Args) GetBool(key string) bool {
	args := a.Attributes[key]
	return (len(args) == 1 && args[0] == "true")
}
<|endoftext|>


<commit_before>package bgp

// Path Attributes
type PathAttr interface {
	Len() int
	Flags() uint8
	Code() uint8
}

// Path attribute flags.
const (
	FlagOptional   = 1 << 8
	FlagTransitive = 1 << 7
	FlagPartial    = 1 << 6
	FlagLength     = 1 << 5
)

// PathHeader is the header each of the path attributes have
// in common.
type PathHeader struct {
	Flags uint8
	Code uint8
}

// Communites implements RFC 1997 COMMUNITIES path attribute.
type Community struct {
	Flags uint8
	Code uint8
	Value []uint32
}

// Origin implements the ORIGIN path attribute.
type Origin struct {
	Flags uint8
	Code uint8
	Value uint8
}

// AsPath implements the AS_PATH path attribute.
type AsPath struct {
	Flags uint8
	Code uint8
	Value []Path
}

// Path is used to encode the AS paths in the AsPath attribute
type Path struct {
	Type uint8 // Either AS_SET of AS_SEQUENCE
	Length uint8 // Number of AS numbers to follow
	AS []uint16
}

// Define the constants used for well-known path attributes in BGP.
const (
	_ = iota
	ORIGIN
	AS_PATH
	NEXT_HOP
	MULTI_EXIT_DISC
	LOCAL_PREF
	ATOMIC_AGGREGATE
	AGGREGATOR
	COMMUNITIES
)

// Values used int the different path attributes.
const (
	// ORIGIN
	IGP        = 0
	EGP        = 1
	INCOMPLETE = 2

	// AS_PATH
	AS_SET      = 1
	AS_SEQUENCE = 2

	// COMMUNITIES Values
	NO_EXPORT           = uint32(0xFFFFFF01)
	NO_ADVERTISE        = uint32(0xFFFFFF02)
	NO_EXPORT_SUBCONFED = uint32(0xFFFFFF03)
)

// Attr is used in the UPDATE message to set the path attribute(s).
type Attr struct {
	Flags uint8
	Code  uint8
	Value []byte
}

func (p *Attr) len() int {
	if p.Flags&FlagLength == FlagLength {
		return 2 + 2 + len(p.Value)
	}
	return 2 + 1 + len(p.Value)
}
<commit_msg>Prework to make working with path attributes sane<commit_after>package bgp

// Path Attributes
type PathAttr interface {
	Len() int
	Header() *PathHeader
}

// Path attribute flags.
const (
	FlagOptional   = 1 << 8
	FlagTransitive = 1 << 7
	FlagPartial    = 1 << 6
	FlagLength     = 1 << 5
)

// PathHeader is the header each of the path attributes have
// in common.
type PathHeader struct {
	Flags uint8
	Code  uint8
}

func (*p PathHeader) Flags() uint8 {
	return p.Flags
}

func (*p PathHeader) Code() uint8 {
	return p.Code
}

// Communites implements RFC 1997 COMMUNITIES path attribute.
type Community struct {
	*PathHeader
	Value []uint32
}

// Origin implements the ORIGIN path attribute.
type Origin struct {
	*PathHeader
	Value uint8
}

// AsPath implements the AS_PATH path attribute.
type AsPath struct {
	*PathHeader
	Value []Path
}

// Path is used to encode the AS paths in the AsPath attribute
type Path struct {
	Type   uint8 // Either AS_SET of AS_SEQUENCE
	Length uint8 // Number of AS numbers to follow
	AS     []uint16
}

// Define the constants used for well-known path attributes in BGP.
const (
	_ = iota
	ORIGIN
	AS_PATH
	NEXT_HOP
	MULTI_EXIT_DISC
	LOCAL_PREF
	ATOMIC_AGGREGATE
	AGGREGATOR
	COMMUNITIES
)

// Values used int the different path attributes.
const (
	// ORIGIN
	IGP        = 0
	EGP        = 1
	INCOMPLETE = 2

	// AS_PATH
	AS_SET      = 1
	AS_SEQUENCE = 2

	// COMMUNITIES Values
	NO_EXPORT           = uint32(0xFFFFFF01)
	NO_ADVERTISE        = uint32(0xFFFFFF02)
	NO_EXPORT_SUBCONFED = uint32(0xFFFFFF03)
)

// Attr is used in the UPDATE message to set the path attribute(s).
type Attr struct {
	Flags uint8
	Code  uint8
	Value []byte
}

func (p *Attr) len() int {
	if p.Flags&FlagLength == FlagLength {
		return 2 + 2 + len(p.Value)
	}
	return 2 + 1 + len(p.Value)
}
<|endoftext|>