<commit_before>package peerstream

import (
	"errors"
	"fmt"
	"net"
	"sync"

	smux "github.com/jbenet/go-peerstream/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer"
)

// ConnHandler is a function which receives a Conn. It allows
// clients to set a function to receive newly accepted
// connections. It works like StreamHandler, but is usually
// less useful than usual as most services will only use
// Streams. It is safe to pass or store the *Conn elsewhere.
// Note: the ConnHandler is called sequentially, so spawn
// goroutines or pass the Conn. See EchoHandler.
type ConnHandler func(s *Conn)

// SelectConn selects a connection out of list. It allows
// delegation of decision making to clients. Clients can
// make SelectConn functons that check things connection
// qualities -- like latency andbandwidth -- or pick from
// a logical set of connections.
type SelectConn func([]*Conn) *Conn

// ErrInvalidConnSelected signals that a connection selected
// with a SelectConn function is invalid. This may be due to
// the Conn not being part of the original set given to the
// function, or the value being nil.
var ErrInvalidConnSelected = errors.New("invalid selected connection")

// ErrNoConnections signals that no connections are available
var ErrNoConnections = errors.New("no connections")

// Conn is a Swarm-associated connection.
type Conn struct {
	smuxConn smux.Conn
	netConn  net.Conn // underlying connection

	swarm  *Swarm
	groups groupSet

	streams    map[*Stream]struct{}
	streamLock sync.RWMutex
}

func newConn(nconn net.Conn, tconn smux.Conn, s *Swarm) *Conn {
	return &Conn{
		netConn:  nconn,
		smuxConn: tconn,
		swarm:    s,
		groups:   groupSet{m: make(map[Group]struct{})},
		streams:  make(map[*Stream]struct{}),
	}
}

// String returns a string representation of the Conn
func (c *Conn) String() string {
	c.streamLock.RLock()
	ls := len(c.streams)
	c.streamLock.RUnlock()
	f := "<peerstream.Conn %d streams %s <--> %s>"
	return fmt.Sprintf(f, ls, c.netConn.LocalAddr(), c.netConn.RemoteAddr())
}

// Swarm returns the Swarm associated with this Conn
func (c *Conn) Swarm() *Swarm {
	return c.swarm
}

// NetConn returns the underlying net.Conn
func (c *Conn) NetConn() net.Conn {
	return c.netConn
}

// Conn returns the underlying transport Connection we use
// Warning: modifying this object is undefined.
func (c *Conn) Conn() smux.Conn {
	return c.smuxConn
}

// Groups returns the Groups this Conn belongs to
func (c *Conn) Groups() []Group {
	return c.groups.Groups()
}

// InGroup returns whether this Conn belongs to a Group
func (c *Conn) InGroup(g Group) bool {
	return c.groups.Has(g)
}

// AddGroup assigns given Group to Conn
func (c *Conn) AddGroup(g Group) {
	c.groups.Add(g)
}

// Stream returns a stream associated with this Conn
func (c *Conn) NewStream() (*Stream, error) {
	return c.swarm.NewStreamWithConn(c)
}

func (c *Conn) Streams() []*Stream {
	c.streamLock.RLock()
	defer c.streamLock.RUnlock()

	streams := make([]*Stream, 0, len(c.streams))
	for s := range c.streams {
		streams = append(streams, s)
	}
	return streams
}

// Close closes this connection
func (c *Conn) Close() error {
	// close streams
	streams := c.Streams()
	for _, s := range streams {
		s.Close()
	}

	// close underlying connection
	c.swarm.removeConn(c)
	err := c.smuxConn.Close()
	c.swarm.notifyAll(func(n Notifiee) {
		n.Disconnected(c)
	})
	return err
}

// ConnsWithGroup narrows down a set of connections to those in a given group.
func ConnsWithGroup(g Group, conns []*Conn) []*Conn {
	var out []*Conn
	for _, c := range conns {
		if c.InGroup(g) {
			out = append(out, c)
		}
	}
	return out
}

func ConnInConns(c1 *Conn, conns []*Conn) bool {
	for _, c2 := range conns {
		if c2 == c1 {
			return true
		}
	}
	return false
}

// ------------------------------------------------------------------
// All the connection setup logic here, in one place.
// these are mostly *Swarm methods, but i wanted a less-crowded place
// for them.
// ------------------------------------------------------------------

// addConn is the internal version of AddConn. we need the server bool
// as spdystream requires it.
func (s *Swarm) addConn(netConn net.Conn, isServer bool) (*Conn, error) {
	c, err := s.setupConn(netConn, isServer)
	if err != nil {
		return nil, err
	}

	s.ConnHandler()(c)

	// go listen for incoming streams on this connection
	go c.smuxConn.Serve(func(ss smux.Stream) {
		// log.Printf("accepted stream %d from %s\n", ssS.Identifier(), netConn.RemoteAddr())
		stream := s.setupStream(ss, c)
		s.StreamHandler()(stream) // call our handler
	})

	s.notifyAll(func(n Notifiee) {
		n.Connected(c)
	})
	return c, nil
}

// setupConn adds the relevant connection to the map, first checking if it
// was already there.
func (s *Swarm) setupConn(netConn net.Conn, isServer bool) (*Conn, error) {
	if netConn == nil {
		return nil, errors.New("nil conn")
	}

	// first, check if we already have it, to avoid constructing it
	// if it is already there
	s.connLock.Lock()
	for c := range s.conns {
		if c.netConn == netConn {
			s.connLock.Unlock()
			return c, nil
		}
	}
	s.connLock.Unlock()
	// construct the connection without hanging onto the lock
	// (as there could be deadlock if so.)

	// create a new spdystream connection
	ssConn, err := s.transport.NewConn(netConn, isServer)
	if err != nil {
		return nil, err
	}

	// take the lock to add it to the map.
	s.connLock.Lock()
	defer s.connLock.Unlock()

	// check for it again as it may have been added already. (TOCTTOU)
	for c := range s.conns {
		if c.netConn == netConn {
			return c, nil
		}
	}

	// add the connection
	c := newConn(netConn, ssConn, s)
	s.conns[c] = struct{}{}
	return c, nil
}

// createStream is the internal function that creates a new stream. assumes
// all validation has happened.
func (s *Swarm) createStream(c *Conn) (*Stream, error) {

	// Create a new smux.Stream
	smuxStream, err := c.smuxConn.OpenStream()
	if err != nil {
		return nil, err
	}

	return s.setupStream(smuxStream, c), nil
}

// newStream is the internal function that creates a new stream. assumes
// all validation has happened.
func (s *Swarm) setupStream(smuxStream smux.Stream, c *Conn) *Stream {

	// create a new stream
	stream := newStream(smuxStream, c)

	// add it to our streams maps
	s.streamLock.Lock()
	c.streamLock.Lock()
	s.streams[stream] = struct{}{}
	c.streams[stream] = struct{}{}
	s.streamLock.Unlock()
	c.streamLock.Unlock()

	s.notifyAll(func(n Notifiee) {
		n.OpenedStream(stream)
	})
	return stream
}

func (s *Swarm) removeStream(stream *Stream) error {

	// remove from our maps
	s.streamLock.Lock()
	stream.conn.streamLock.Lock()
	delete(s.streams, stream)
	delete(stream.conn.streams, stream)
	s.streamLock.Unlock()
	stream.conn.streamLock.Unlock()

	err := stream.smuxStream.Close()
	s.notifyAll(func(n Notifiee) {
		n.ClosedStream(stream)
	})
	return err
}

func (s *Swarm) removeConn(conn *Conn) {
	// remove from our maps
	s.connLock.Lock()
	delete(s.conns, conn)
	s.connLock.Unlock()
}
<commit_msg>make close call idempotent<commit_after>package peerstream

import (
	"errors"
	"fmt"
	"net"
	"sync"

	smux "github.com/jbenet/go-peerstream/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer"
)

// ConnHandler is a function which receives a Conn. It allows
// clients to set a function to receive newly accepted
// connections. It works like StreamHandler, but is usually
// less useful than usual as most services will only use
// Streams. It is safe to pass or store the *Conn elsewhere.
// Note: the ConnHandler is called sequentially, so spawn
// goroutines or pass the Conn. See EchoHandler.
type ConnHandler func(s *Conn)

// SelectConn selects a connection out of list. It allows
// delegation of decision making to clients. Clients can
// make SelectConn functons that check things connection
// qualities -- like latency andbandwidth -- or pick from
// a logical set of connections.
type SelectConn func([]*Conn) *Conn

// ErrInvalidConnSelected signals that a connection selected
// with a SelectConn function is invalid. This may be due to
// the Conn not being part of the original set given to the
// function, or the value being nil.
var ErrInvalidConnSelected = errors.New("invalid selected connection")

// ErrNoConnections signals that no connections are available
var ErrNoConnections = errors.New("no connections")

// Conn is a Swarm-associated connection.
type Conn struct {
	smuxConn smux.Conn
	netConn  net.Conn // underlying connection

	swarm  *Swarm
	groups groupSet

	streams    map[*Stream]struct{}
	streamLock sync.RWMutex

	closed    bool
	closeLock sync.Mutex
}

func newConn(nconn net.Conn, tconn smux.Conn, s *Swarm) *Conn {
	return &Conn{
		netConn:  nconn,
		smuxConn: tconn,
		swarm:    s,
		groups:   groupSet{m: make(map[Group]struct{})},
		streams:  make(map[*Stream]struct{}),
	}
}

// String returns a string representation of the Conn
func (c *Conn) String() string {
	c.streamLock.RLock()
	ls := len(c.streams)
	c.streamLock.RUnlock()
	f := "<peerstream.Conn %d streams %s <--> %s>"
	return fmt.Sprintf(f, ls, c.netConn.LocalAddr(), c.netConn.RemoteAddr())
}

// Swarm returns the Swarm associated with this Conn
func (c *Conn) Swarm() *Swarm {
	return c.swarm
}

// NetConn returns the underlying net.Conn
func (c *Conn) NetConn() net.Conn {
	return c.netConn
}

// Conn returns the underlying transport Connection we use
// Warning: modifying this object is undefined.
func (c *Conn) Conn() smux.Conn {
	return c.smuxConn
}

// Groups returns the Groups this Conn belongs to
func (c *Conn) Groups() []Group {
	return c.groups.Groups()
}

// InGroup returns whether this Conn belongs to a Group
func (c *Conn) InGroup(g Group) bool {
	return c.groups.Has(g)
}

// AddGroup assigns given Group to Conn
func (c *Conn) AddGroup(g Group) {
	c.groups.Add(g)
}

// Stream returns a stream associated with this Conn
func (c *Conn) NewStream() (*Stream, error) {
	return c.swarm.NewStreamWithConn(c)
}

func (c *Conn) Streams() []*Stream {
	c.streamLock.RLock()
	defer c.streamLock.RUnlock()

	streams := make([]*Stream, 0, len(c.streams))
	for s := range c.streams {
		streams = append(streams, s)
	}
	return streams
}

// Close closes this connection
func (c *Conn) Close() error {
	c.closeLock.Lock()
	defer c.closeLock.Unlock()

	if c.closed {
		return nil
	}
	c.closed = true

	// close streams
	streams := c.Streams()
	for _, s := range streams {
		s.Close()
	}

	// close underlying connection
	c.swarm.removeConn(c)
	err := c.smuxConn.Close()
	c.swarm.notifyAll(func(n Notifiee) {
		n.Disconnected(c)
	})
	return err
}

// ConnsWithGroup narrows down a set of connections to those in a given group.
func ConnsWithGroup(g Group, conns []*Conn) []*Conn {
	var out []*Conn
	for _, c := range conns {
		if c.InGroup(g) {
			out = append(out, c)
		}
	}
	return out
}

func ConnInConns(c1 *Conn, conns []*Conn) bool {
	for _, c2 := range conns {
		if c2 == c1 {
			return true
		}
	}
	return false
}

// ------------------------------------------------------------------
// All the connection setup logic here, in one place.
// these are mostly *Swarm methods, but i wanted a less-crowded place
// for them.
// ------------------------------------------------------------------

// addConn is the internal version of AddConn. we need the server bool
// as spdystream requires it.
func (s *Swarm) addConn(netConn net.Conn, isServer bool) (*Conn, error) {
	c, err := s.setupConn(netConn, isServer)
	if err != nil {
		return nil, err
	}

	s.ConnHandler()(c)

	// go listen for incoming streams on this connection
	go c.smuxConn.Serve(func(ss smux.Stream) {
		// log.Printf("accepted stream %d from %s\n", ssS.Identifier(), netConn.RemoteAddr())
		stream := s.setupStream(ss, c)
		s.StreamHandler()(stream) // call our handler
	})

	s.notifyAll(func(n Notifiee) {
		n.Connected(c)
	})
	return c, nil
}

// setupConn adds the relevant connection to the map, first checking if it
// was already there.
func (s *Swarm) setupConn(netConn net.Conn, isServer bool) (*Conn, error) {
	if netConn == nil {
		return nil, errors.New("nil conn")
	}

	// first, check if we already have it, to avoid constructing it
	// if it is already there
	s.connLock.Lock()
	for c := range s.conns {
		if c.netConn == netConn {
			s.connLock.Unlock()
			return c, nil
		}
	}
	s.connLock.Unlock()
	// construct the connection without hanging onto the lock
	// (as there could be deadlock if so.)

	// create a new spdystream connection
	ssConn, err := s.transport.NewConn(netConn, isServer)
	if err != nil {
		return nil, err
	}

	// take the lock to add it to the map.
	s.connLock.Lock()
	defer s.connLock.Unlock()

	// check for it again as it may have been added already. (TOCTTOU)
	for c := range s.conns {
		if c.netConn == netConn {
			return c, nil
		}
	}

	// add the connection
	c := newConn(netConn, ssConn, s)
	s.conns[c] = struct{}{}
	return c, nil
}

// createStream is the internal function that creates a new stream. assumes
// all validation has happened.
func (s *Swarm) createStream(c *Conn) (*Stream, error) {

	// Create a new smux.Stream
	smuxStream, err := c.smuxConn.OpenStream()
	if err != nil {
		return nil, err
	}

	return s.setupStream(smuxStream, c), nil
}

// newStream is the internal function that creates a new stream. assumes
// all validation has happened.
func (s *Swarm) setupStream(smuxStream smux.Stream, c *Conn) *Stream {

	// create a new stream
	stream := newStream(smuxStream, c)

	// add it to our streams maps
	s.streamLock.Lock()
	c.streamLock.Lock()
	s.streams[stream] = struct{}{}
	c.streams[stream] = struct{}{}
	s.streamLock.Unlock()
	c.streamLock.Unlock()

	s.notifyAll(func(n Notifiee) {
		n.OpenedStream(stream)
	})
	return stream
}

func (s *Swarm) removeStream(stream *Stream) error {

	// remove from our maps
	s.streamLock.Lock()
	stream.conn.streamLock.Lock()
	delete(s.streams, stream)
	delete(stream.conn.streams, stream)
	s.streamLock.Unlock()
	stream.conn.streamLock.Unlock()

	err := stream.smuxStream.Close()
	s.notifyAll(func(n Notifiee) {
		n.ClosedStream(stream)
	})
	return err
}

func (s *Swarm) removeConn(conn *Conn) {
	// remove from our maps
	s.connLock.Lock()
	delete(s.conns, conn)
	s.connLock.Unlock()
}
<|endoftext|>


<commit_before>package script

import "testing"

func TestGetMethod(t *testing.T) {
	methodName := "abcdeg"
	op := Operation{
		opType:     OpCall,
		callMethod: methodName,
	}

	if op.GetMethod() != methodName {
		t.Errorf("GetMethod() should not be %v, but "+methodName, op.GetMethod())
	}

	op = Operation{
		opType:     OpAssignment,
		callMethod: "abcdefg",
	}

	if op.GetMethod() != "" {
		t.Errorf("GetMethod() should not be %v but an empty string", op.GetMethod())
	}
}

func TestPrintingConditionalOperations(t *testing.T) {
	a := Operation{
		opType:  OpConditional,
		condOp1: "Var[1]",
		condOp2: "Var[2]",
		condOp:  "==",
		condDst: 0x2345,
	}
	if a.String() != "unless (Var[1] == Var[2]) goto 2345" {
		t.Errorf("conditional operation `%v` is not properly formatted", a.String())
	}
}

func TestPrintingAssignmentOperations(t *testing.T) {
	a := Operation{
		opType:    OpAssignment,
		assignDst: "Var[123]",
		assignVal: "999",
	}
	if a.String() != "Var[123] = 999" {
		t.Errorf("operation `%v` is not properly formatted", a.String())
	}
}

func TestPrintingCallOperations(t *testing.T) {
	a := Operation{
		opType:     OpCall,
		callMethod: "myMethod",
		callParams: []string{
			"123", "456",
		},
	}

	if a.String() != "myMethod(123, 456)" {
		t.Errorf("conditional operation `%v` is not properly formatted", a.String())
	}

	b := Operation{
		opType:     OpCall,
		callMethod: "myMethod",
		callMap: map[string]string{
			"x": "1234",
			"y": "6789",
		},
	}

	opPrint := b.String()
	if opPrint != "myMethod(x=1234, y=6789)" &&
		opPrint != "myMethod(y=6789, x=1234)" {
		t.Errorf("conditional operation `%v` is not properly formatted", opPrint)
	}
}
<commit_msg>Add tests for operation<commit_after>package script

import "testing"

func TestPrint(t *testing.T) {
	methodName := "abcdef"
	op := Operation{
		opCode:     0x22,
		opType:     OpCall,
		callMethod: methodName,
		callParams: []string{"one", "two"},
		offset:     0x234,
	}

	script := Script{}
	script = append(script, op)
	script = append(script, op)
	result := script.Print()
	expected := "abcdef(one, two)\n"

	if result != expected+expected {
		t.Errorf("Was expecting %v, but got %v", expected+expected, result)
	}
}

func TestDebug(t *testing.T) {
	methodName := "abcdef"
	op := Operation{
		opCode:     0x22,
		opType:     OpCall,
		callMethod: methodName,
		offset:     0x234,
	}

	script := Script{}
	script = append(script, op)
	script = append(script, op)
	result := script.Debug()
	expected := "[0234] (22) abcdef()\n"

	if result != expected+expected {
		t.Errorf("Was expecting %v, but got %v", expected+expected, result)
	}
}

func TestGetMethod(t *testing.T) {
	methodName := "abcdeg"
	op := Operation{
		opType:     OpCall,
		callMethod: methodName,
	}

	if op.GetMethod() != methodName {
		t.Errorf("GetMethod() should not be %v, but "+methodName, op.GetMethod())
	}

	op = Operation{
		opType:     OpAssignment,
		callMethod: "abcdefg",
	}

	if op.GetMethod() != "" {
		t.Errorf("GetMethod() should not be %v but an empty string", op.GetMethod())
	}
}

func TestPrintingConditionalOperations(t *testing.T) {
	a := Operation{
		opType:  OpConditional,
		condOp1: "Var[1]",
		condOp2: "Var[2]",
		condOp:  "==",
		condDst: 0x2345,
	}
	if a.String() != "unless (Var[1] == Var[2]) goto 2345" {
		t.Errorf("conditional operation `%v` is not properly formatted", a.String())
	}
}

func TestPrintingAssignmentOperations(t *testing.T) {
	a := Operation{
		opType:    OpAssignment,
		assignDst: "Var[123]",
		assignVal: "999",
	}
	if a.String() != "Var[123] = 999" {
		t.Errorf("operation `%v` is not properly formatted", a.String())
	}
}

func TestPrintingCallOperations(t *testing.T) {
	a := Operation{
		opType:     OpCall,
		callMethod: "myMethod",
		callResult: "result",
		callParams: []string{
			"123", "456",
		},
	}

	if a.String() != "result = myMethod(123, 456)" {
		t.Errorf("call operation `%v` is not properly formatted", a.String())
	}

	b := Operation{
		opType:     OpCall,
		callMethod: "myMethod",
		callMap: map[string]string{
			"x": "1234",
			"y": "6789",
		},
	}

	opPrint := b.String()
	if opPrint != "myMethod(x=1234, y=6789)" &&
		opPrint != "myMethod(y=6789, x=1234)" {
		t.Errorf("conditional operation `%v` is not properly formatted", opPrint)
	}
}
<|endoftext|>


<commit_before>package protos

import "golang.org/x/crypto/nacl/secretbox"

// TransportSize is the number of bytes that all payloads are padded to before
// sending on the network.
const TransportSize = 5000000 - 2 - secretbox.Overhead

// MessageOverhead is the number of bytes reserved for wrapping a Message up in
// protobufs. That includes the overhead of the protobufs themselves, as well
// as the metadata in the protobuf and the group signature.
const MessageOverhead = 512

// MaxSerializedMessage is the maximum size of the serialized Message protobuf.
// The message will end up looking like this:
//    [length - 4 bytes       ]  | NaCl box  | Message that server sees.
//    [nonce - 24 bytes               ]
//
//      [secretbox.Overhead - 16 bytes]
//      [message count - 4 bytes      ]
//      [prev message count - 4 bytes ]
//      [ratchet public - 32 bytes    ]
//      [inner nonce - 32 bytes       ]
//
//      [secretbox.Overhead - 16 bytes]
//      [serialized message           ]
const MaxSerializedMessage = TransportSize - (secretbox.Overhead + 4 + 4 + 32 + 24) - secretbox.Overhead - MessageOverhead
<commit_msg>Lowwered transport size<commit_after>package protos

import "golang.org/x/crypto/nacl/secretbox"

// TransportSize is the number of bytes that all payloads are padded to before
// sending on the network.
const TransportSize = 4250000 - 2 - secretbox.Overhead

// MessageOverhead is the number of bytes reserved for wrapping a Message up in
// protobufs. That includes the overhead of the protobufs themselves, as well
// as the metadata in the protobuf and the group signature.
const MessageOverhead = 512

// MaxSerializedMessage is the maximum size of the serialized Message protobuf.
// The message will end up looking like this:
//    [length - 4 bytes       ]  | NaCl box  | Message that server sees.
//    [nonce - 24 bytes               ]
//
//      [secretbox.Overhead - 16 bytes]
//      [message count - 4 bytes      ]
//      [prev message count - 4 bytes ]
//      [ratchet public - 32 bytes    ]
//      [inner nonce - 32 bytes       ]
//
//      [secretbox.Overhead - 16 bytes]
//      [serialized message           ]
const MaxSerializedMessage = TransportSize - (secretbox.Overhead + 4 + 4 + 32 + 24) - secretbox.Overhead - MessageOverhead
<|endoftext|>


<commit_before>// prscrape is a framework for scraping press releases.
//
// It's designed to be run as a server, and will:
// 1) periodically scrape a bunch of press release sources
// 2) hold an archive of press releases sufficient to cover a few days
// 3) serves up the scraped press releases via HTTP, as server side event
//    endpoints
//
// The scraped press releases are persistent, in a sqlite db. The idea is
// that eventually it'll be set up to keep just a week or so archive, to let
// consumers of the stream have a chance to catch up if they go down for a
// day or two.
// (but for now, it just keeps adding to the db)
//
// Clients connect to:
//
//   http://<host>:<port>/<source>/
//
// where source is the name of one of the installed scrapers.
//
// Clients can send a last-event-id header to access archived press releases.
// eg:
//  $ curl http://localhost:9998/72point/ -H "Last-Event-ID: 0"
// Will serve up _all_ the stored 72point press releases.
//
// Without last-event-id, the client will be served only new press
// releases as they come in.
//
//
// TODOs
// - proper logging and better error handling (kill all the panics!)
// - we've already got a http server running, so should implement a simple
//   browsing interface for visual sanity-checking of press releases.
// - add a html-scrubbing func to clean up extracted content (remove style
//   attrs, ids, dodgy elements etc)
// - better interval timing
// - expire old data from the store
// - split prscrape out from ukpr

package prscrape
<commit_msg>tidy up scraper framework docs slightly<commit_after>// prscrape is a framework for scraping press releases.
//
// It's designed to be run as a server, and will:
// 1) periodically scrape a bunch of press release sources
// 2) hold an archive of press releases sufficient to cover a few days
// 3) serves up the scraped press releases via HTTP, as server side event
//    endpoints
//
// The scraped press releases are persistent, in a sqlite db. The idea is
// that eventually it'll be set up to keep just a week or so archive, to let
// consumers of the stream have a chance to catch up if they go down for a
// day or two.
// (but for now, it just keeps adding to the db)
//
// Clients connect to:
//
//   http://<host>:<port>/<source>/
//
// where source is the name of one of the installed scrapers.
//
// Clients can send a last-event-id header to access archived press releases.
// eg:
//  $ curl http://localhost:9998/72point/ -H "Last-Event-ID: 0"
// Will serve up _all_ the stored 72point press releases.
//
// Without last-event-id, the client will be served only new press
// releases as they come in.
//

package prscrape
<|endoftext|>


<commit_before>package parser

import (
	"errors"
	"fmt"
	"github.com/araddon/dateparse"
	"github.com/telemetryapp/gotelemetry_agent/agent/aggregations"
	"io"
	"time"
)

// Number

type seriesExpression struct {
	name   string
	series *aggregations.Series
	l      int
	p      int
}

func newSeriesExpression(name string, series *aggregations.Series, line, position int) expression {
	result := &seriesExpression{
		name:   name,
		series: series,
		l:      line,
		p:      position,
	}

	return result
}

type seriesProperty func(g *seriesExpression) expression

var seriesProperties = map[string]seriesProperty{
	"avg": func(s *seriesExpression) expression {
		return s.compute("avg", aggregations.Avg)
	},
	"min": func(s *seriesExpression) expression {
		return s.compute("min", aggregations.Min)
	},
	"max": func(s *seriesExpression) expression {
		return s.compute("max", aggregations.Max)
	},
	"sum": func(s *seriesExpression) expression {
		return s.compute("sum", aggregations.Sum)
	},
	"count": func(s *seriesExpression) expression {
		return s.compute("count", aggregations.Count)
	},
	"stddev": func(s *seriesExpression) expression {
		return s.compute("stddev", aggregations.StdDev)
	},
	"last": func(s *seriesExpression) expression {
		return s.last()
	},
	"aggregate": func(s *seriesExpression) expression {
		return s.aggregate()
	},
	"trim": func(s *seriesExpression) expression {
		return s.trim()
	},
	"push": func(s *seriesExpression) expression {
		return s.push()
	},
	"pop": func(s *seriesExpression) expression {
		return s.pop()
	},
	"items": func(s *seriesExpression) expression {
		return s.items()
	},
}

func (s *seriesExpression) compute(name string, functionType aggregations.FunctionType) expression {
	return newCallableExpression(
		"name",
		func(c *executionContext, args map[string]interface{}) (expression, error) {
			intervalDuration, err := time.ParseDuration(args["interval"].(string))

			if err != nil {
				return nil, err
			}

			end := time.Now()
			start := end.Add(-intervalDuration)

			l, err := s.series.Compute(functionType, &start, &end)

			if err != nil {
				return nil, err
			}

			return newNumericExpression(l, s.l, s.p), nil
		},
		map[string]callableArgument{
			"interval": callableArgumentString,
		},
		s.l,
		s.p,
	)
}

func (s *seriesExpression) last() expression {
	return newCallableExpression(
		"last",
		func(c *executionContext, args map[string]interface{}) (expression, error) {
			l, err := s.series.Last()

			if err != nil && err != io.EOF {
				return nil, err
			}

			v, _ := l["value"].(float64)
			ts, _ := l["ts"].(int64)

			return newSeriesResultExpression(v, ts, s.l, s.p), nil
		},
		map[string]callableArgument{},
		s.l,
		s.p,
	)
}

func (s *seriesExpression) items() expression {
	return newCallableExpression(
		"items",
		func(c *executionContext, args map[string]interface{}) (expression, error) {
			count := int(args["max"].(float64))

			l, err := s.series.Items(count)

			if err != nil && err != io.EOF {
				return nil, err
			}

			return newSeriesResultAggregateExpression(l.([]interface{}), s.l, s.p), nil
		},
		map[string]callableArgument{
			"max": callableArgumentNumeric,
		},
		s.l,
		s.p,
	)
}

func (s *seriesExpression) push() expression {
	return newCallableExpression(
		"push",
		func(c *executionContext, args map[string]interface{}) (expression, error) {
			var timestamp time.Time

			if ts, ok := args["timestamp"].(float64); ok {
				timestamp = time.Unix(int64(ts), 0)
			} else {
				timestamp = time.Now()
			}

			value := args["value"].(float64)

			return nil, s.series.Push(&timestamp, value)
		},
		map[string]callableArgument{
			"timestamp": callableArgumentOptionalNumeric,
			"value":     callableArgumentNumeric,
		},
		s.l,
		s.p,
	)
}

func (s *seriesExpression) pop() expression {
	return newCallableExpression(
		"pop",
		func(c *executionContext, args map[string]interface{}) (expression, error) {
			l, err := s.series.Pop(false)

			if err != nil && err != io.EOF {
				return nil, err
			}

			v, _ := l["value"].(float64)
			ts, _ := l["ts"].(int64)

			return newSeriesResultExpression(v, ts, s.l, s.p), nil
		},
		map[string]callableArgument{},
		s.l,
		s.p,
	)
}

func (s *seriesExpression) trim() expression {
	return newCallableExpression(
		"trim",
		func(c *executionContext, args map[string]interface{}) (expression, error) {
			since, ok1 := args["since"].(string)
			count, ok2 := args["count"].(float64)

			if ok1 && ok2 {
				return nil, errors.New("A call to trim() cannot contain both `since` and `count` arguments")
			}

			if ok1 {
				d, err := time.ParseDuration(since)

				if err != nil {
					return nil, err
				}

				return nil, s.series.TrimSince(time.Now().Add(d))
			}

			if ok2 {
				return nil, s.series.TrimCount(int(count))
			}

			return nil, errors.New("Either a `since` or `count` argument is required when calling trim()")
		},
		map[string]callableArgument{
			"since": callableArgumentOptionalString,
			"count": callableArgumentOptionalNumeric,
		},
		s.l,
		s.p,
	)
}

func (s *seriesExpression) aggregate() expression {
	return newCallableExpression(
		"",
		func(c *executionContext, args map[string]interface{}) (expression, error) {
			function, err := aggregations.AggregationFunctionTypeFromName(args["func"].(string))

			if err != nil {
				return nil, err
			}

			intervalDuration, err := time.ParseDuration(args["interval"].(string))

			if err != nil {
				return nil, err
			}

			interval := int(intervalDuration.Seconds())

			if interval < 1 {
				interval = 1
			}

			count := int(args["count"].(float64))

			var endTimePtr *time.Time = nil
			if endTimeStr, ok := args["end_time"].(string); ok && len(endTimeStr) > 0 {
				endTime, err := dateparse.ParseAny(endTimeStr)
				if err != nil {
					return nil, err
				}
				endTimePtr = &endTime
			}

			l, err := s.series.Aggregate(function, interval, count, endTimePtr)

			if err != nil {
				return nil, err
			}

			return newSeriesResultAggregateExpression(l.([]interface{}), s.l, s.p), nil
		},
		map[string]callableArgument{
			"func":     callableArgumentString,
			"interval": callableArgumentString,
			"count":    callableArgumentNumeric,
			"end_time": callableArgumentOptionalString,
		},
		s.l,
		s.p,
	)
}

func (s *seriesExpression) extract(c *executionContext, property string) (expression, error) {
	if f, ok := seriesProperties[property]; ok {
		return f(s), nil
	}

	return nil, errors.New(fmt.Sprintf("%s does not contain a property with the key `%s`", s, property))
}

func (s *seriesExpression) evaluate(c *executionContext) (interface{}, error) {
	return nil, errors.New(fmt.Sprintf("%s cannot be evaluated", s))
}

func (s *seriesExpression) line() int {
	return s.l
}

func (s *seriesExpression) position() int {
	return s.p
}

func (s *seriesExpression) String() string {
	return fmt.Sprintf("Series(%s)", s.name)
}
<commit_msg>- Fix trim function<commit_after>package parser

import (
	"errors"
	"fmt"
	"github.com/araddon/dateparse"
	"github.com/telemetryapp/gotelemetry_agent/agent/aggregations"
	"github.com/telemetryapp/gotelemetry_agent/agent/config"
	"io"
	"time"
)

// Number

type seriesExpression struct {
	name   string
	series *aggregations.Series
	l      int
	p      int
}

func newSeriesExpression(name string, series *aggregations.Series, line, position int) expression {
	result := &seriesExpression{
		name:   name,
		series: series,
		l:      line,
		p:      position,
	}

	return result
}

type seriesProperty func(g *seriesExpression) expression

var seriesProperties = map[string]seriesProperty{
	"avg": func(s *seriesExpression) expression {
		return s.compute("avg", aggregations.Avg)
	},
	"min": func(s *seriesExpression) expression {
		return s.compute("min", aggregations.Min)
	},
	"max": func(s *seriesExpression) expression {
		return s.compute("max", aggregations.Max)
	},
	"sum": func(s *seriesExpression) expression {
		return s.compute("sum", aggregations.Sum)
	},
	"count": func(s *seriesExpression) expression {
		return s.compute("count", aggregations.Count)
	},
	"stddev": func(s *seriesExpression) expression {
		return s.compute("stddev", aggregations.StdDev)
	},
	"last": func(s *seriesExpression) expression {
		return s.last()
	},
	"aggregate": func(s *seriesExpression) expression {
		return s.aggregate()
	},
	"trim": func(s *seriesExpression) expression {
		return s.trim()
	},
	"push": func(s *seriesExpression) expression {
		return s.push()
	},
	"pop": func(s *seriesExpression) expression {
		return s.pop()
	},
	"items": func(s *seriesExpression) expression {
		return s.items()
	},
}

func (s *seriesExpression) compute(name string, functionType aggregations.FunctionType) expression {
	return newCallableExpression(
		"name",
		func(c *executionContext, args map[string]interface{}) (expression, error) {
			intervalDuration, err := time.ParseDuration(args["interval"].(string))

			if err != nil {
				return nil, err
			}

			end := time.Now()
			start := end.Add(-intervalDuration)

			l, err := s.series.Compute(functionType, &start, &end)

			if err != nil {
				return nil, err
			}

			return newNumericExpression(l, s.l, s.p), nil
		},
		map[string]callableArgument{
			"interval": callableArgumentString,
		},
		s.l,
		s.p,
	)
}

func (s *seriesExpression) last() expression {
	return newCallableExpression(
		"last",
		func(c *executionContext, args map[string]interface{}) (expression, error) {
			l, err := s.series.Last()

			if err != nil && err != io.EOF {
				return nil, err
			}

			v, _ := l["value"].(float64)
			ts, _ := l["ts"].(int64)

			return newSeriesResultExpression(v, ts, s.l, s.p), nil
		},
		map[string]callableArgument{},
		s.l,
		s.p,
	)
}

func (s *seriesExpression) items() expression {
	return newCallableExpression(
		"items",
		func(c *executionContext, args map[string]interface{}) (expression, error) {
			count := int(args["max"].(float64))

			l, err := s.series.Items(count)

			if err != nil && err != io.EOF {
				return nil, err
			}

			return newSeriesResultAggregateExpression(l.([]interface{}), s.l, s.p), nil
		},
		map[string]callableArgument{
			"max": callableArgumentNumeric,
		},
		s.l,
		s.p,
	)
}

func (s *seriesExpression) push() expression {
	return newCallableExpression(
		"push",
		func(c *executionContext, args map[string]interface{}) (expression, error) {
			var timestamp time.Time

			if ts, ok := args["timestamp"].(float64); ok {
				timestamp = time.Unix(int64(ts), 0)
			} else {
				timestamp = time.Now()
			}

			value := args["value"].(float64)

			return nil, s.series.Push(&timestamp, value)
		},
		map[string]callableArgument{
			"timestamp": callableArgumentOptionalNumeric,
			"value":     callableArgumentNumeric,
		},
		s.l,
		s.p,
	)
}

func (s *seriesExpression) pop() expression {
	return newCallableExpression(
		"pop",
		func(c *executionContext, args map[string]interface{}) (expression, error) {
			l, err := s.series.Pop(false)

			if err != nil && err != io.EOF {
				return nil, err
			}

			v, _ := l["value"].(float64)
			ts, _ := l["ts"].(int64)

			return newSeriesResultExpression(v, ts, s.l, s.p), nil
		},
		map[string]callableArgument{},
		s.l,
		s.p,
	)
}

func (s *seriesExpression) trim() expression {
	return newCallableExpression(
		"trim",
		func(c *executionContext, args map[string]interface{}) (expression, error) {
			since, ok1 := args["since"].(string)
			count, ok2 := args["count"].(float64)

			if ok1 && ok2 {
				return nil, errors.New("A call to trim() cannot contain both `since` and `count` arguments")
			}

			if ok1 {
				d, err := config.ParseTimeInterval(since)

				if err != nil {
					return nil, err
				}

				return nil, s.series.TrimSince(time.Now().Sub(d))
			}

			if ok2 {
				return nil, s.series.TrimCount(int(count))
			}

			return nil, errors.New("Either a `since` or `count` argument is required when calling trim()")
		},
		map[string]callableArgument{
			"since": callableArgumentOptionalString,
			"count": callableArgumentOptionalNumeric,
		},
		s.l,
		s.p,
	)
}

func (s *seriesExpression) aggregate() expression {
	return newCallableExpression(
		"",
		func(c *executionContext, args map[string]interface{}) (expression, error) {
			function, err := aggregations.AggregationFunctionTypeFromName(args["func"].(string))

			if err != nil {
				return nil, err
			}

			intervalDuration, err := time.ParseDuration(args["interval"].(string))

			if err != nil {
				return nil, err
			}

			interval := int(intervalDuration.Seconds())

			if interval < 1 {
				interval = 1
			}

			count := int(args["count"].(float64))

			var endTimePtr *time.Time = nil
			if endTimeStr, ok := args["end_time"].(string); ok && len(endTimeStr) > 0 {
				endTime, err := dateparse.ParseAny(endTimeStr)
				if err != nil {
					return nil, err
				}
				endTimePtr = &endTime
			}

			l, err := s.series.Aggregate(function, interval, count, endTimePtr)

			if err != nil {
				return nil, err
			}

			return newSeriesResultAggregateExpression(l.([]interface{}), s.l, s.p), nil
		},
		map[string]callableArgument{
			"func":     callableArgumentString,
			"interval": callableArgumentString,
			"count":    callableArgumentNumeric,
			"end_time": callableArgumentOptionalString,
		},
		s.l,
		s.p,
	)
}

func (s *seriesExpression) extract(c *executionContext, property string) (expression, error) {
	if f, ok := seriesProperties[property]; ok {
		return f(s), nil
	}

	return nil, errors.New(fmt.Sprintf("%s does not contain a property with the key `%s`", s, property))
}

func (s *seriesExpression) evaluate(c *executionContext) (interface{}, error) {
	return nil, errors.New(fmt.Sprintf("%s cannot be evaluated", s))
}

func (s *seriesExpression) line() int {
	return s.l
}

func (s *seriesExpression) position() int {
	return s.p
}

func (s *seriesExpression) String() string {
	return fmt.Sprintf("Series(%s)", s.name)
}
<|endoftext|>


<commit_before>// Copyright 2021 The etcd 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 schema

import (
	"fmt"

	"github.com/coreos/go-semver/semver"
	"go.etcd.io/etcd/server/v3/storage/backend"
	"go.uber.org/zap"
)

type migrationPlan []migrationStep

func newPlan(lg *zap.Logger, current semver.Version, target semver.Version) (plan migrationPlan, err error) {
	current = trimToMinor(current)
	target = trimToMinor(target)
	if current.Major != target.Major {
		lg.Error("Changing major storage version is not supported",
			zap.String("storage-version", current.String()),
			zap.String("target-storage-version", target.String()),
		)
		return plan, fmt.Errorf("changing major storage version is not supported")
	}
	for !current.Equal(target) {
		isUpgrade := current.Minor < target.Minor

		changes, err := schemaChangesForVersion(current, isUpgrade)
		if err != nil {
			return plan, err
		}
		step := newMigrationStep(current, isUpgrade, changes)
		plan = append(plan, step)
		current = step.target
	}
	return plan, nil
}

func (p migrationPlan) Execute(lg *zap.Logger, tx backend.BatchTx) error {
	tx.Lock()
	defer tx.Unlock()
	return p.unsafeExecute(lg, tx)
}

func (p migrationPlan) unsafeExecute(lg *zap.Logger, tx backend.BatchTx) (err error) {
	for _, s := range p {
		err = s.unsafeExecute(lg, tx)
		if err != nil {
			return err
		}
		lg.Info("upgraded storage version", zap.String("new-storage-version", s.target.String()))
	}
	return nil
}

// migrationStep represents a single migrationStep of migrating etcd storage between two minor versions.
type migrationStep struct {
	target  semver.Version
	actions ActionList
}

func newMigrationStep(v semver.Version, isUpgrade bool, changes []schemaChange) (step migrationStep) {
	step.actions = make(ActionList, len(changes))
	for i, change := range changes {
		if isUpgrade {
			step.actions[i] = change.upgradeAction()
		} else {
			step.actions[len(changes)-1-i] = change.downgradeAction()
		}
	}
	if isUpgrade {
		step.target = semver.Version{Major: v.Major, Minor: v.Minor + 1}
	} else {
		step.target = semver.Version{Major: v.Major, Minor: v.Minor - 1}
	}
	return step
}

// execute runs actions required to migrate etcd storage between two minor versions.
func (s migrationStep) execute(lg *zap.Logger, tx backend.BatchTx) error {
	tx.Lock()
	defer tx.Unlock()
	return s.unsafeExecute(lg, tx)
}

// unsafeExecute is non thread-safe version of execute.
func (s migrationStep) unsafeExecute(lg *zap.Logger, tx backend.BatchTx) error {
	err := s.actions.unsafeExecute(lg, tx)
	if err != nil {
		return err
	}
	// Storage version is available since v3.6, downgrading target v3.5 should clean this field.
	if !s.target.LessThan(V3_6) {
		UnsafeSetStorageVersion(tx, &s.target)
	}
	return nil
}

func trimToMinor(ver semver.Version) semver.Version {
	return semver.Version{Major: ver.Major, Minor: ver.Minor}
}
<commit_msg>update incorrect migration log message<commit_after>// Copyright 2021 The etcd 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 schema

import (
	"fmt"

	"github.com/coreos/go-semver/semver"
	"go.etcd.io/etcd/server/v3/storage/backend"
	"go.uber.org/zap"
)

type migrationPlan []migrationStep

func newPlan(lg *zap.Logger, current semver.Version, target semver.Version) (plan migrationPlan, err error) {
	current = trimToMinor(current)
	target = trimToMinor(target)
	if current.Major != target.Major {
		lg.Error("Changing major storage version is not supported",
			zap.String("storage-version", current.String()),
			zap.String("target-storage-version", target.String()),
		)
		return plan, fmt.Errorf("changing major storage version is not supported")
	}
	for !current.Equal(target) {
		isUpgrade := current.Minor < target.Minor

		changes, err := schemaChangesForVersion(current, isUpgrade)
		if err != nil {
			return plan, err
		}
		step := newMigrationStep(current, isUpgrade, changes)
		plan = append(plan, step)
		current = step.target
	}
	return plan, nil
}

func (p migrationPlan) Execute(lg *zap.Logger, tx backend.BatchTx) error {
	tx.Lock()
	defer tx.Unlock()
	return p.unsafeExecute(lg, tx)
}

func (p migrationPlan) unsafeExecute(lg *zap.Logger, tx backend.BatchTx) (err error) {
	for _, s := range p {
		err = s.unsafeExecute(lg, tx)
		if err != nil {
			return err
		}
		lg.Info("updated storage version", zap.String("new-storage-version", s.target.String()))
	}
	return nil
}

// migrationStep represents a single migrationStep of migrating etcd storage between two minor versions.
type migrationStep struct {
	target  semver.Version
	actions ActionList
}

func newMigrationStep(v semver.Version, isUpgrade bool, changes []schemaChange) (step migrationStep) {
	step.actions = make(ActionList, len(changes))
	for i, change := range changes {
		if isUpgrade {
			step.actions[i] = change.upgradeAction()
		} else {
			step.actions[len(changes)-1-i] = change.downgradeAction()
		}
	}
	if isUpgrade {
		step.target = semver.Version{Major: v.Major, Minor: v.Minor + 1}
	} else {
		step.target = semver.Version{Major: v.Major, Minor: v.Minor - 1}
	}
	return step
}

// execute runs actions required to migrate etcd storage between two minor versions.
func (s migrationStep) execute(lg *zap.Logger, tx backend.BatchTx) error {
	tx.Lock()
	defer tx.Unlock()
	return s.unsafeExecute(lg, tx)
}

// unsafeExecute is non thread-safe version of execute.
func (s migrationStep) unsafeExecute(lg *zap.Logger, tx backend.BatchTx) error {
	err := s.actions.unsafeExecute(lg, tx)
	if err != nil {
		return err
	}
	// Storage version is available since v3.6, downgrading target v3.5 should clean this field.
	if !s.target.LessThan(V3_6) {
		UnsafeSetStorageVersion(tx, &s.target)
	}
	return nil
}

func trimToMinor(ver semver.Version) semver.Version {
	return semver.Version{Major: ver.Major, Minor: ver.Minor}
}
<|endoftext|>


<commit_before>// run

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

// Test the behavior of closures.

package main

import "runtime"

var c = make(chan int)

func check(a []int) {
	for i := 0; i < len(a); i++ {
		n := <-c
		if n != a[i] {
			println("want", a[i], "got", n, "at", i)
			panic("fail")
		}
	}
}

func f() {
	var i, j int

	i = 1
	j = 2
	f := func() {
		c <- i
		i = 4
		g := func() {
			c <- i
			c <- j
		}
		g()
		c <- i
	}
	j = 5
	f()
}

// Accumulator generator
func accum(n int) func(int) int {
	return func(i int) int {
		n += i
		return n
	}
}

func g(a, b func(int) int) {
	c <- a(2)
	c <- b(3)
	c <- a(4)
	c <- b(5)
}

func h() {
	var x8 byte = 100
	var x64 int64 = 200

	c <- int(x8)
	c <- int(x64)
	f := func(z int) {
		g := func() {
			c <- int(x8)
			c <- int(x64)
			c <- z
		}
		g()
		c <- int(x8)
		c <- int(x64)
		c <- int(z)
	}
	x8 = 101
	x64 = 201
	f(500)
}

func newfunc() func(int) int { return func(x int) int { return x } }

func main() {
	var fail bool

	go f()
	check([]int{1, 4, 5, 4})

	a := accum(0)
	b := accum(1)
	go g(a, b)
	check([]int{2, 4, 6, 9})

	go h()
	check([]int{100, 200, 101, 201, 500, 101, 201, 500})

	memstats := new(runtime.MemStats)
	runtime.ReadMemStats(memstats)
	n0 := memstats.Mallocs

	x, y := newfunc(), newfunc()
	if x(1) != 1 || y(2) != 2 {
		println("newfunc returned broken funcs")
		fail = true
	}

	runtime.ReadMemStats(memstats)
	if n0 != memstats.Mallocs {
		println("newfunc allocated unexpectedly")
		fail = true
	}

	ff(1)

	if fail {
		panic("fail")
	}
}

func ff(x int) {
	call(func() {
		_ = x
	})
}

func call(func()) {
}
<commit_msg>test: enforce 1 proc in the test otherwise it fails spuriously with "newfunc allocated unexpectedly" message when run with GOMAXPROCS>1 (other goroutine allocates).<commit_after>// run

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

// Test the behavior of closures.

package main

import "runtime"

var c = make(chan int)

func check(a []int) {
	for i := 0; i < len(a); i++ {
		n := <-c
		if n != a[i] {
			println("want", a[i], "got", n, "at", i)
			panic("fail")
		}
	}
}

func f() {
	var i, j int

	i = 1
	j = 2
	f := func() {
		c <- i
		i = 4
		g := func() {
			c <- i
			c <- j
		}
		g()
		c <- i
	}
	j = 5
	f()
}

// Accumulator generator
func accum(n int) func(int) int {
	return func(i int) int {
		n += i
		return n
	}
}

func g(a, b func(int) int) {
	c <- a(2)
	c <- b(3)
	c <- a(4)
	c <- b(5)
}

func h() {
	var x8 byte = 100
	var x64 int64 = 200

	c <- int(x8)
	c <- int(x64)
	f := func(z int) {
		g := func() {
			c <- int(x8)
			c <- int(x64)
			c <- z
		}
		g()
		c <- int(x8)
		c <- int(x64)
		c <- int(z)
	}
	x8 = 101
	x64 = 201
	f(500)
}

func newfunc() func(int) int { return func(x int) int { return x } }

func main() {
	runtime.GOMAXPROCS(1)
	var fail bool

	go f()
	check([]int{1, 4, 5, 4})

	a := accum(0)
	b := accum(1)
	go g(a, b)
	check([]int{2, 4, 6, 9})

	go h()
	check([]int{100, 200, 101, 201, 500, 101, 201, 500})

	memstats := new(runtime.MemStats)
	runtime.ReadMemStats(memstats)
	n0 := memstats.Mallocs

	x, y := newfunc(), newfunc()
	if x(1) != 1 || y(2) != 2 {
		println("newfunc returned broken funcs")
		fail = true
	}

	runtime.ReadMemStats(memstats)
	if n0 != memstats.Mallocs {
		println("newfunc allocated unexpectedly")
		fail = true
	}

	ff(1)

	if fail {
		panic("fail")
	}
}

func ff(x int) {
	call(func() {
		_ = x
	})
}

func call(func()) {
}
<|endoftext|>


<commit_before>package polecalc

import "math"

func ZeroTempDelta(env Environment, k []float64) float64 {
	sx := math.Sin(k[0])
	sy := math.Sin(k[1])
	return 4 * env.F0 * (env.T0 + env.Tz) * (sx + float64(env.Alpha) * sy)
}

func ZeroTempPairEnergy(env Environment, k []float64) float64 {
	xi := Xi(env, k)
	delta := ZeroTempDelta(env, k)
	return math.Sqrt(xi * xi + delta * delta)
}

func ZeroTempFermi(energy float64) float64 {
	if (energy <= 0.0) {
		return 1.0
	}
	return 0.0
}
<commit_msg>code for zero-temperature specific functions and self-consistent equations<commit_after>package polecalc

import (
	"math"
	"os"
)

func ZeroTempDelta(env Environment, k []float64) float64 {
	sx := math.Sin(k[0])
	sy := math.Sin(k[1])
	return 4 * env.F0 * (env.T0 + env.Tz) * (sx + float64(env.Alpha) * sy)
}

func ZeroTempPairEnergy(env Environment, k []float64) float64 {
	xi := Xi(env, k)
	delta := ZeroTempDelta(env, k)
	return math.Sqrt(xi * xi + delta * delta)
}

func ZeroTempFermi(energy float64) float64 {
	if (energy <= 0.0) {
		return 1.0
	}
	return 0.0
}

type ZeroTempD1Equation struct{}

func (eq ZeroTempD1Equation) AbsError(args interface{}) float64 {
	env := args.(Environment)
	worker := func(k []float64) float64 {
		sx := math.Sin(k[0])
		sy := math.Sin(k[1])
		return -0.5 * (1 - Xi(env, k)) / ZeroTempPairEnergy(env, k) * sx * sy
	}
	return env.D1 - Average(env.GridLength, worker, env.NumProcs)
}

func (eq ZeroTempD1Equation) SetArguments(D1 float64, args *interface{}) {
	env := (*args).(Environment)
	env.D1 = D1
}

func (eq ZeroTempD1Equation) Range(args interface{}) (float64, float64, os.Error) {
	return 0.0, 1.0, nil
}

type ZeroTempMuEquation struct{}

func (eq ZeroTempMuEquation) AbsError(args interface{}) float64 {
	env := args.(Environment)
	worker := func(k []float64) float64 {
		return 0.5 * (1 - Xi(env, k)) / ZeroTempPairEnergy(env, k)
	}
	return env.X - Average(env.GridLength, worker, env.NumProcs)
}

func (eq ZeroTempMuEquation) SetArguments(Mu float64, args *interface{}) {
	env := (*args).(Environment)
	env.Mu = Mu
}

func (eq ZeroTempMuEquation) Range(args interface{}) (float64, float64, os.Error) {
	env := args.(Environment)
	return -2 * env.T0, 2 * env.T0, nil
}

type ZeroTempF0Equation struct{}

func (eq ZeroTempF0Equation) AbsError(args interface{}) float64 {
	env := args.(Environment)
	worker := func(k []float64) float64 {
		sinPart := math.Sin(k[0]) + float64(env.Alpha) * math.Sin(k[1])
		return sinPart * sinPart / ZeroTempPairEnergy(env, k)
	}
	return env.D1 - Average(env.GridLength, worker, env.NumProcs)
}

func (eq ZeroTempF0Equation) SetArguments(F0 float64, args *interface{}) {
	env := (*args).(Environment)
	env.F0 = F0
}

func (eq ZeroTempF0Equation) Range(args interface{}) (float64, float64, os.Error) {
	return 0.0, 1.0, nil
}
<|endoftext|>


<commit_before>package handlers

import "net/http"

// CORSOption represents a functional option for configuring the CORS middleware.
type CORSOption func(*cors) error

type cors struct {
	h              http.Handler
	allowedHeaders []string
	allowedMethods []string
	allowedOrigins []string
	maxAge         int
	ignoreOptions  bool
}

func (ch *cors) ServeHTTP(w http.ResponseWriter, r *http.Request) {

	ch.h.ServeHTTP(w, r)
}

// CORS provides Cross-Origin Resource Sharing middleware.
// Example:
//
//  import (
//      "net/http"
//
//      "github.com/gorilla/handlers"
//      "github.com/gorilla/mux"
//  )
//
//  func main() {
//      r := mux.NewRouter()
//      r.HandleFunc("/users", UserEndpoint)
//      r.HandleFunc("/projects", ProjectEndpoint)
//
//      // Apply the CORS middleware to our top-level router, with the defaults.
//      http.ListenAndServe(":8000", handlers.CORS()(r))
//  }
//
func CORS(opts ...CORSOption) func(http.Handler) http.Handler {
	ch := parseCORSOptions(opts...)

	// TODO(all): Set defaults
	// Note: append(allowedHeaders, defaultHeaders...) - the default headers here
	// should always be allowed:
	// https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Simple_requests

	return func(h http.Handler) http.Handler {
		ch.h = h
		return ch
	}
}

func parseCORSOptions(opts ...CORSOption) *cors {
	ch := &cors{}

	for _, option := range opts {
		option(ch)
	}

	return ch
}

//
// Functional options for configuring CORS.
//

// AllowedHeaders adds the provided headers to the list of allowed headers in a
// CORS request.
// The headers Content-Type, Expires, Cache-Control, ... are always allowed.
func AllowedHeaders(headers []string) CORSOption {
	return func(ch *cors) error {
		ch.allowedHeaders = headers
		return nil
	}
}

// AllowedMethods ...
func AllowedMethods(methods []string) CORSOption {
	return func(ch *cors) error {
		ch.allowedMethods = methods
		return nil
	}
}

// AllowedOrigins sets the allowed origins for CORS requests, as used in the
// 'Allow-Access-Control-Origin' HTTP header.
// Note: Passing in a []string{"*"} will allow any domain.
func AllowedOrigins(origins []string) CORSOption {
	return func(ch *cors) error {
		ch.allowedOrigins = origins
		return nil
	}
}

// MaxAge determines the maximum age (in seconds) between preflight requests. A
// maximum of 10 minutes is allowed. An age above this value will default to 10
// minutes.
func MaxAge(age int) CORSOption {
	return func(ch *cors) error {
		// Maximum of 10 minutes.
		if age > 600 {
			age = 600
		}

		ch.maxAge = age
		return nil
	}
}

// IgnoreOptions causes the CORS middleware to ignore OPTIONS requests, instead
// passing them through to the next handler. This is useful when your application
// or framework has a pre-existing mechanism for responding to OPTIONS requests.
func IgnoreOptions() CORSOption {
	return func(ch *cors) error {
		ch.ignoreOptions = true
		return nil
	}
}
<commit_msg>Initial implementation<commit_after>package handlers

import (
	// "log"
	"net/http"
	"strconv"
	"strings"
)

// CORSOption represents a functional option for configuring the CORS middleware.
type CORSOption func(*cors) error

type cors struct {
	h                http.Handler
	allowedHeaders   []string
	allowedMethods   []string
	allowedOrigins   []string
	exposedHeaders   []string
	maxAge           int
	ignoreOptions    bool
	allowCredentials bool
}

var (
	defaultCorsMethods = []string{"GET", "HEAD", "POST"}
	defaultCorsHeaders = []string{"Accept", "Accept-Language", "Content-Language"}
)

const (
	corsOptionMethod           string = "OPTIONS"
	corsAllowOriginHeader      string = "Access-Control-Allow-Origin"
	corsExposeHeadersHeader    string = "Access-Control-Expose-Headers"
	corsMaxAgeHeader           string = "Access-Control-Max-Age"
	corsAllowMethodsHeader     string = "Access-Control-Allow-Methods"
	corsAllowHeadersHeader     string = "Access-Control-Allow-Headers"
	corsAllowCredentialsHeader string = "Access-Control-Allow-Credentials"
	corsRequestMethodHeader    string = "Access-Control-Request-Method"
	corsRequestHeadersHeader   string = "Access-Control-Request-Headers"
	corsOriginHeader           string = "Origin"
	corsVaryHeader             string = "Vary"
	corsGlobMatch              string = "*"
)

func (ch *cors) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	origin := r.Header.Get(corsOriginHeader)

	if !ch.isOriginAllowed(origin) {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	handler := ch.h
	defer func() {
		handler.ServeHTTP(w, r)
	}()

	if r.Method == corsOptionMethod && !ch.ignoreOptions {
		handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return })
		if _, ok := r.Header[corsRequestMethodHeader]; !ok {
			w.WriteHeader(http.StatusBadRequest)
			return
		}

		method := r.Header.Get(corsRequestMethodHeader)
		if !ch.isMatch(method, ch.allowedMethods) {
			w.WriteHeader(http.StatusMethodNotAllowed)
			return
		}

		requestHeaders := strings.Split(r.Header.Get(corsRequestHeadersHeader), ",")
		allowedHeaders := []string{}
		for _, v := range requestHeaders {
			canonicalHeader := http.CanonicalHeaderKey(strings.TrimSpace(v))
			if canonicalHeader == "" || ch.isMatch(canonicalHeader, defaultCorsHeaders) {
				continue
			}

			if !ch.isMatch(canonicalHeader, ch.allowedHeaders) {
				w.WriteHeader(http.StatusForbidden)
				return
			}

			allowedHeaders = append(allowedHeaders, canonicalHeader)
		}

		if len(allowedHeaders) > 0 {
			w.Header().Set(corsAllowHeadersHeader, strings.Join(allowedHeaders, ","))
		}

		if ch.maxAge > 0 {
			w.Header().Set(corsMaxAgeHeader, strconv.Itoa(ch.maxAge))
		}

		if !ch.isMatch(method, defaultCorsMethods) {
			w.Header().Set(corsAllowMethodsHeader, method)
		}
	} else {
		if len(ch.exposedHeaders) > 0 {
			w.Header().Set(corsExposeHeadersHeader, strings.Join(ch.exposedHeaders, ","))
		}
	}

	if ch.allowCredentials {
		w.Header().Set(corsAllowCredentialsHeader, "true")
	}

	if len(ch.allowedOrigins) > 1 {
		w.Header().Set(corsVaryHeader, corsOriginHeader)
	}

	w.Header().Set(corsAllowOriginHeader, origin)
}

// CORS provides Cross-Origin Resource Sharing middleware.
// Example:
//
//  import (
//      "net/http"
//
//      "github.com/gorilla/handlers"
//      "github.com/gorilla/mux"
//  )
//
//  func main() {
//      r := mux.NewRouter()
//      r.HandleFunc("/users", UserEndpoint)
//      r.HandleFunc("/projects", ProjectEndpoint)
//
//      // Apply the CORS middleware to our top-level router, with the defaults.
//      http.ListenAndServe(":8000", handlers.CORS()(r))
//  }
//
func CORS(opts ...CORSOption) func(http.Handler) http.Handler {
	ch := parseCORSOptions(opts...)

	// TODO(all): Set defaults
	// Note: append(allowedHeaders, defaultHeaders...) - the default headers here
	// should always be allowed:
	// https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Simple_requests

	return func(h http.Handler) http.Handler {
		ch.h = h
		return ch
	}
}

func parseCORSOptions(opts ...CORSOption) *cors {
	ch := &cors{
		allowedMethods: defaultCorsMethods,
		allowedHeaders: defaultCorsHeaders,
	}

	for _, option := range opts {
		option(ch)
	}

	return ch
}

//
// Functional options for configuring CORS.
//

// AllowedHeaders adds the provided headers to the list of allowed headers in a
// CORS request.
// The headers Content-Type, Expires, Cache-Control, ... are always allowed.
func AllowedHeaders(headers []string) CORSOption {
	return func(ch *cors) error {
		for _, v := range headers {
			normalizedHeader := http.CanonicalHeaderKey(strings.TrimSpace(v))
			if normalizedHeader == "" {
				continue
			}

			if !ch.isMatch(normalizedHeader, ch.allowedHeaders) {
				ch.allowedHeaders = append(ch.allowedHeaders, normalizedHeader)
			}
		}

		return nil
	}
}

// AllowedMethods ...
func AllowedMethods(methods []string) CORSOption {
	return func(ch *cors) error {
		for _, v := range methods {
			normalizedMethod := strings.ToUpper(strings.TrimSpace(v))
			if normalizedMethod == "" {
				continue
			}

			if !ch.isMatch(normalizedMethod, ch.allowedMethods) {
				ch.allowedHeaders = append(ch.allowedHeaders, normalizedMethod)
			}
		}

		return nil
	}
}

// AllowedOrigins sets the allowed origins for CORS requests, as used in the
// 'Allow-Access-Control-Origin' HTTP header.
// Note: Passing in a []string{"*"} will allow any domain.
func AllowedOrigins(origins []string) CORSOption {
	return func(ch *cors) error {
		for _, v := range origins {
			if v == corsGlobMatch {
				ch.allowedOrigins = []string{corsGlobMatch}
				return nil
			}
		}

		ch.allowedOrigins = origins
		return nil
	}
}

// ExposeHeaders are additional headers outside of those which are apart
// of the simple response headers (http://www.w3.org/TR/cors/#simple-response-header)
func ExposedHeaders(headers []string) CORSOption {
	return func(ch *cors) error {
		ch.exposedHeaders = headers
		return nil
	}
}

// MaxAge determines the maximum age (in seconds) between preflight requests. A
// maximum of 10 minutes is allowed. An age above this value will default to 10
// minutes.
func MaxAge(age int) CORSOption {
	return func(ch *cors) error {
		// Maximum of 10 minutes.
		if age > 600 {
			age = 600
		}

		ch.maxAge = age
		return nil
	}
}

// IgnoreOptions causes the CORS middleware to ignore OPTIONS requests, instead
// passing them through to the next handler. This is useful when your application
// or framework has a pre-existing mechanism for responding to OPTIONS requests.
func IgnoreOptions() CORSOption {
	return func(ch *cors) error {
		ch.ignoreOptions = true
		return nil
	}
}

// AllowCredentials ...
func AllowCredentials() CORSOption {
	return func(ch *cors) error {
		ch.allowCredentials = true
		return nil
	}
}

func (ch *cors) isOriginAllowed(origin string) bool {
	if origin == "" {
		return false
	}

	for _, allowedOrigin := range ch.allowedOrigins {
		if allowedOrigin == origin || allowedOrigin == corsGlobMatch {
			return true
		}
	}

	return false
}

func (ch *cors) isMatch(needle string, haystack []string) bool {
	for _, v := range haystack {
		if v == needle {
			return true
		}
	}

	return false
}
<|endoftext|>


<commit_before>package main

import (
	"math"
	"time"

	twodee "../libs/twodee"
)

type PlanetaryState int32

const (
	_                  = iota
	Sun PlanetaryState = 1 << iota
	Fertile
	TooClose
	TooFar
)

var PlanetaryAnimations = map[PlanetaryState][]int{
	Sun:      []int{0},
	Fertile:  []int{4},
	TooClose: []int{8},
	TooFar:   []int{12},
}

type PlanetaryBody struct {
	*twodee.AnimatingEntity
	// Velocity is in units/ms.
	Velocity             twodee.Point
	Mass                 float32
	Population           float32
	MaxPopulation        float32
	PopulationGrowthRate float32
	Temperature          int32
	State                PlanetaryState
}

func NewSun() *PlanetaryBody {
	body := &PlanetaryBody{
		AnimatingEntity: twodee.NewAnimatingEntity(
			0, 0,
			32.0/PxPerUnit, 32.0/PxPerUnit,
			0,
			twodee.Step10Hz,
			[]int{0},
		),
		Mass:                 1000.0,
		Population:           0.0,
		MaxPopulation:        0.0,
		PopulationGrowthRate: 0.0,
		Temperature:          27000000,
	}
	body.SetState(Sun)
	return body
}

func NewPlanet(x, y float32) *PlanetaryBody {
	body := &PlanetaryBody{
		AnimatingEntity: twodee.NewAnimatingEntity(
			x, y,
			32.0/PxPerUnit, 32.0/PxPerUnit,
			0,
			twodee.Step10Hz,
			[]int{0},
		),
		Velocity: twodee.Pt(0, 0),
		//		Velocity:             twodee.Pt(rand.Float32(), rand.Float32()),
		Mass:                 2000.0,
		Population:           100.0,
		MaxPopulation:        0.0,
		PopulationGrowthRate: 0.0001,
		Temperature:          72,
	}
	body.SetState(Fertile)
	body.MaxPopulation = body.Mass * 1000
	return body
}

func (p *PlanetaryBody) MoveToward(sc twodee.Point) {
	var (
		pc = p.Pos()
		dx = float64(sc.X - pc.X)
		dy = float64(sc.Y - pc.Y)
		h  = math.Hypot(dx, dy)
		vx = float32(math.Max(1, 5-h) * 0.3 * dx / h)
		vy = float32(math.Max(1, 5-h) * 0.3 * dy / h)
	)
	p.Velocity.X += (vx - p.Velocity.X)
	p.Velocity.Y += (vy - p.Velocity.Y)
}

// Calculates the PlanetaryBody's new velocity vector given an acceleration vector and time.
func (p *PlanetaryBody) CalcNewVelocity(av twodee.Point, elapsed time.Duration) {
	// Essentially, v = v0 + at
	av = av.Scale(float32(elapsed.Seconds() * 1e3))
	p.Velocity = p.Velocity.Add(av)
}

func (p *PlanetaryBody) GravitateToward(sc twodee.Point) {
	var (
		pc  = p.Pos()
		avx = float64(sc.X - pc.X)
		avy = float64(sc.Y - pc.Y)
		d   = math.Hypot(avx, avy)
	)
	// Normalize vector and include sensible constraints.
	avx = avx / d
	avy = avy / d
	av := twodee.Pt(float32(math.Max(1, 5-d)*0.3*avx), float32(math.Max(1, 5-d)*0.3*avy))

	// There are two possible orthogonal 'circulation' vectors.
	cv1 := twodee.Pt(-av.Y, av.X)
	cv2 := twodee.Pt(av.Y, -av.X)
	cv := cv1

	// Compute whichever circulation vector is closer to our present vector.
	// cos(theta) = A -dot- B / ||A||*||B||
	dp1 := p.Velocity.X*cv1.X + p.Velocity.Y*cv1.Y
	denom := math.Sqrt(float64(p.Velocity.X*p.Velocity.X + p.Velocity.Y*p.Velocity.Y))
	theta1 := dp1 / float32(denom)
	dp2 := p.Velocity.X*cv2.X + p.Velocity.Y*cv2.Y
	theta2 := dp2 / float32(denom)
	if theta1 >= theta2 {
		cv = cv1
	} else {
		cv = cv2
	}

	// Now do some vector addition.
	fv := twodee.Pt(av.X+cv.X, av.Y+cv.Y)
	p.Velocity.X += (fv.X - p.Velocity.X) / 30
	p.Velocity.Y += (fv.Y - p.Velocity.Y) / 30
}

func (p *PlanetaryBody) UpdatePopulation(elapsed time.Duration) {
	if p.State == Fertile {
		p.Population = p.MaxPopulation / (1 + ((p.MaxPopulation/p.Population)-1)*float32(math.Exp(-1*float64(p.PopulationGrowthRate)*float64(elapsed/time.Millisecond))))
	} else {
		p.Population = p.MaxPopulation / (1 + ((p.MaxPopulation/p.Population)-1)*float32(math.Exp(float64(p.PopulationGrowthRate)*float64(elapsed/time.Millisecond))))
	}
}

func (p *PlanetaryBody) UpdateTemperature(elapsed time.Duration) {
	if p.State == TooFar {
		p.Temperature += (-400 - p.Temperature) / int32(elapsed/time.Millisecond)
	} else if p.State == TooClose {
		p.Temperature += (5000 - p.Temperature) / int32(elapsed/time.Millisecond)
	} else if p.State == Fertile {
		p.Temperature += (72 - p.Temperature) / int32(elapsed/time.Millisecond)
	}
}

func (p *PlanetaryBody) Update(elapsed time.Duration) {
	p.AnimatingEntity.Update(elapsed)
	p.UpdatePopulation(elapsed)
	p.UpdateTemperature(elapsed)
	pos := p.Pos()
	ms := float32(elapsed.Seconds() * 1e3)
	dist := p.Velocity.Scale(ms)
	p.MoveTo(twodee.Pt(pos.X+dist.X, pos.Y+dist.Y))
}

func (p *PlanetaryBody) RemState(state PlanetaryState) {
	p.SetState(p.State & ^state)
}

func (p *PlanetaryBody) AddState(state PlanetaryState) {
	p.SetState(p.State | state)
}

func (p *PlanetaryBody) SwapState(rem, add PlanetaryState) {
	p.SetState(p.State & ^rem | add)
}

func (p *PlanetaryBody) SetState(state PlanetaryState) {
	if state != p.State {
		p.State = state
		if frames, ok := PlanetaryAnimations[p.State]; ok {
			p.SetFrames(frames)
		}
	}
}

func (p *PlanetaryBody) GetPopulation() int {
	return int(p.Population)
}

func (p *PlanetaryBody) GetTemperature() int32 {
	return int32(p.Temperature)
}
<commit_msg>Added constant to temperature formula<commit_after>package main

import (
	"math"
	"time"

	twodee "../libs/twodee"
)

type PlanetaryState int32

const (
	_                  = iota
	Sun PlanetaryState = 1 << iota
	Fertile
	TooClose
	TooFar
)

var PlanetaryAnimations = map[PlanetaryState][]int{
	Sun:      []int{0},
	Fertile:  []int{4},
	TooClose: []int{8},
	TooFar:   []int{12},
}

type PlanetaryBody struct {
	*twodee.AnimatingEntity
	// Velocity is in units/ms.
	Velocity             twodee.Point
	Mass                 float32
	Population           float32
	MaxPopulation        float32
	PopulationGrowthRate float32
	Temperature          int32
	State                PlanetaryState
}

func NewSun() *PlanetaryBody {
	body := &PlanetaryBody{
		AnimatingEntity: twodee.NewAnimatingEntity(
			0, 0,
			32.0/PxPerUnit, 32.0/PxPerUnit,
			0,
			twodee.Step10Hz,
			[]int{0},
		),
		Mass:                 1000.0,
		Population:           0.0,
		MaxPopulation:        0.0,
		PopulationGrowthRate: 0.0,
		Temperature:          27000000,
	}
	body.SetState(Sun)
	return body
}

func NewPlanet(x, y float32) *PlanetaryBody {
	body := &PlanetaryBody{
		AnimatingEntity: twodee.NewAnimatingEntity(
			x, y,
			32.0/PxPerUnit, 32.0/PxPerUnit,
			0,
			twodee.Step10Hz,
			[]int{0},
		),
		Velocity: twodee.Pt(0, 0),
		//		Velocity:             twodee.Pt(rand.Float32(), rand.Float32()),
		Mass:                 2000.0,
		Population:           100.0,
		MaxPopulation:        0.0,
		PopulationGrowthRate: 0.0001,
		Temperature:          72,
	}
	body.SetState(Fertile)
	body.MaxPopulation = body.Mass * 1000
	return body
}

func (p *PlanetaryBody) MoveToward(sc twodee.Point) {
	var (
		pc = p.Pos()
		dx = float64(sc.X - pc.X)
		dy = float64(sc.Y - pc.Y)
		h  = math.Hypot(dx, dy)
		vx = float32(math.Max(1, 5-h) * 0.3 * dx / h)
		vy = float32(math.Max(1, 5-h) * 0.3 * dy / h)
	)
	p.Velocity.X += (vx - p.Velocity.X)
	p.Velocity.Y += (vy - p.Velocity.Y)
}

// Calculates the PlanetaryBody's new velocity vector given an acceleration vector and time.
func (p *PlanetaryBody) CalcNewVelocity(av twodee.Point, elapsed time.Duration) {
	// Essentially, v = v0 + at
	av = av.Scale(float32(elapsed.Seconds() * 1e3))
	p.Velocity = p.Velocity.Add(av)
}

func (p *PlanetaryBody) GravitateToward(sc twodee.Point) {
	var (
		pc  = p.Pos()
		avx = float64(sc.X - pc.X)
		avy = float64(sc.Y - pc.Y)
		d   = math.Hypot(avx, avy)
	)
	// Normalize vector and include sensible constraints.
	avx = avx / d
	avy = avy / d
	av := twodee.Pt(float32(math.Max(1, 5-d)*0.3*avx), float32(math.Max(1, 5-d)*0.3*avy))

	// There are two possible orthogonal 'circulation' vectors.
	cv1 := twodee.Pt(-av.Y, av.X)
	cv2 := twodee.Pt(av.Y, -av.X)
	cv := cv1

	// Compute whichever circulation vector is closer to our present vector.
	// cos(theta) = A -dot- B / ||A||*||B||
	dp1 := p.Velocity.X*cv1.X + p.Velocity.Y*cv1.Y
	denom := math.Sqrt(float64(p.Velocity.X*p.Velocity.X + p.Velocity.Y*p.Velocity.Y))
	theta1 := dp1 / float32(denom)
	dp2 := p.Velocity.X*cv2.X + p.Velocity.Y*cv2.Y
	theta2 := dp2 / float32(denom)
	if theta1 >= theta2 {
		cv = cv1
	} else {
		cv = cv2
	}

	// Now do some vector addition.
	fv := twodee.Pt(av.X+cv.X, av.Y+cv.Y)
	p.Velocity.X += (fv.X - p.Velocity.X) / 30
	p.Velocity.Y += (fv.Y - p.Velocity.Y) / 30
}

func (p *PlanetaryBody) UpdatePopulation(elapsed time.Duration) {
	if p.State == Fertile {
		p.Population = p.MaxPopulation / (1 + ((p.MaxPopulation/p.Population)-1)*float32(math.Exp(-1*float64(p.PopulationGrowthRate)*float64(elapsed/time.Millisecond))))
	} else {
		p.Population = p.MaxPopulation / (1 + ((p.MaxPopulation/p.Population)-1)*float32(math.Exp(float64(p.PopulationGrowthRate)*float64(elapsed/time.Millisecond))))
	}
}

func (p *PlanetaryBody) UpdateTemperature(elapsed time.Duration) {
	if p.State == TooFar {
		p.Temperature += (-400 - p.Temperature) / int32(elapsed/time.Millisecond)
	} else if p.State == TooClose {
		p.Temperature += ((5000 - p.Temperature) / int32(elapsed/time.Millisecond)) / 10
	} else if p.State == Fertile {
		p.Temperature += (72 - p.Temperature) / int32(elapsed/time.Millisecond)
	}
}

func (p *PlanetaryBody) Update(elapsed time.Duration) {
	p.AnimatingEntity.Update(elapsed)
	p.UpdatePopulation(elapsed)
	p.UpdateTemperature(elapsed)
	pos := p.Pos()
	ms := float32(elapsed.Seconds() * 1e3)
	dist := p.Velocity.Scale(ms)
	p.MoveTo(twodee.Pt(pos.X+dist.X, pos.Y+dist.Y))
}

func (p *PlanetaryBody) RemState(state PlanetaryState) {
	p.SetState(p.State & ^state)
}

func (p *PlanetaryBody) AddState(state PlanetaryState) {
	p.SetState(p.State | state)
}

func (p *PlanetaryBody) SwapState(rem, add PlanetaryState) {
	p.SetState(p.State & ^rem | add)
}

func (p *PlanetaryBody) SetState(state PlanetaryState) {
	if state != p.State {
		p.State = state
		if frames, ok := PlanetaryAnimations[p.State]; ok {
			p.SetFrames(frames)
		}
	}
}

func (p *PlanetaryBody) GetPopulation() int {
	return int(p.Population)
}

func (p *PlanetaryBody) GetTemperature() int32 {
	return int32(p.Temperature)
}
<|endoftext|>


<commit_before>package goproxy

import (
	"bytes"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha1"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"math/big"
	"net"
	"strings"
	"sync"
	"time"

	"github.com/google/martian/log"
)

// MaxSerialNumber is the upper boundary that is used to create unique serial
// numbers for the certificate. This can be any unsigned integer up to 20
// bytes (2^(8*20)-1).
var MaxSerialNumber = big.NewInt(0).SetBytes(bytes.Repeat([]byte{255}, 20))

func getWildcardHost(host string) string {
	first := strings.Index(host, ".")
	if first <= 0 {
		return host
	}
	last := strings.LastIndex(host, ".")
	if last == first {
		// root domain, no wildcard
		return host
	}
	return "*" + host[first:]
}

// Config is a set of configuration values that are used to build TLS configs
// capable of MITM.
type GoproxyConfig struct {
	Root   *x509.Certificate
	capriv interface{}

	priv  *rsa.PrivateKey
	keyID []byte

	validity time.Duration

	certmu sync.RWMutex

	*tls.Config
}

// NewConfig creates a MITM config using the CA certificate and
// private key to generate on-the-fly certificates.
func NewConfig(ca *x509.Certificate, privateKey interface{}) (*GoproxyConfig, error) {
	roots := x509.NewCertPool()
	roots.AddCert(ca)

	priv, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		return nil, err
	}
	pub := priv.Public()

	// Subject Key Identifier support for end entity certificate.
	// https://www.ietf.org/rfc/rfc3280.txt (section 4.2.1.2)
	pkixpub, err := x509.MarshalPKIXPublicKey(pub)
	if err != nil {
		return nil, err
	}
	h := sha1.New()
	h.Write(pkixpub)
	keyID := h.Sum(nil)

	tlsConfig := &GoproxyConfig{
		Root:     ca,
		capriv:   privateKey,
		priv:     priv,
		keyID:    keyID,
		validity: time.Hour * 24 * 3650,

		Config: &tls.Config{
			InsecureSkipVerify: true,
			Certificates:       make([]tls.Certificate, 0),
			MinVersion:         tls.VersionTLS12,
			RootCAs:            roots,
			NameToCertificate:  make(map[string]*tls.Certificate),
		},
	}

	return tlsConfig, nil
}

func (c *GoproxyConfig) cert(hostname string) error {
	// Remove the port if it exists.
	host, _, err := net.SplitHostPort(getWildcardHost(hostname))
	if err == nil {
		hostname = host
	}

	// Remove the port if it exists.
	c.certmu.RLock()
	tlsc, ok := c.NameToCertificate[hostname]
	c.certmu.RUnlock()

	if ok {
		log.Debugf("mitm: cache hit for %s", hostname)

		// Check validity of the certificate for hostname match, expiry, etc. In
		// particular, if the cached certificate has expired, create a new one.
		if _, err := tlsc.Leaf.Verify(x509.VerifyOptions{
			DNSName: hostname,
			Roots:   c.RootCAs,
		}); err == nil {
			return nil
		}

		log.Debugf("mitm: invalid certificate in cache for %s", hostname)
	}

	log.Debugf("mitm: cache miss for %s", hostname)

	serial, err := rand.Int(rand.Reader, MaxSerialNumber)
	if err != nil {
		return err
	}

	tmpl := &x509.Certificate{
		SerialNumber: serial,
		Subject: pkix.Name{
			CommonName:   hostname,
			Organization: []string{"StopLight"},
		},
		SubjectKeyId:          c.keyID,
		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
		BasicConstraintsValid: true,
		NotBefore:             time.Now().Add(-c.validity),
		NotAfter:              time.Now().Add(c.validity),
	}

	if ip := net.ParseIP(hostname); ip != nil {
		tmpl.IPAddresses = []net.IP{ip}
	} else {
		tmpl.DNSNames = []string{hostname}
	}

	raw, err := x509.CreateCertificate(rand.Reader, tmpl, c.Root, c.priv.Public(), c.capriv)
	if err != nil {
		return err
	}

	// Parse certificate bytes so that we have a leaf certificate.
	x509c, err := x509.ParseCertificate(raw)
	if err != nil {
		return err
	}

	tlsc = &tls.Certificate{
		Certificate: [][]byte{raw, c.Root.Raw},
		PrivateKey:  c.priv,
		Leaf:        x509c,
	}

	c.certmu.Lock()
	c.NameToCertificate[hostname] = tlsc
	c.Certificates = append(c.Certificates, *tlsc)
	c.certmu.Unlock()

	return nil
}
<commit_msg>Remove debug logs.<commit_after>package goproxy

import (
	"bytes"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha1"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"math/big"
	"net"
	"strings"
	"sync"
	"time"
)

// MaxSerialNumber is the upper boundary that is used to create unique serial
// numbers for the certificate. This can be any unsigned integer up to 20
// bytes (2^(8*20)-1).
var MaxSerialNumber = big.NewInt(0).SetBytes(bytes.Repeat([]byte{255}, 20))

func getWildcardHost(host string) string {
	first := strings.Index(host, ".")
	if first <= 0 {
		return host
	}
	last := strings.LastIndex(host, ".")
	if last == first {
		// root domain, no wildcard
		return host
	}
	return "*" + host[first:]
}

// Config is a set of configuration values that are used to build TLS configs
// capable of MITM.
type GoproxyConfig struct {
	Root   *x509.Certificate
	capriv interface{}

	priv  *rsa.PrivateKey
	keyID []byte

	validity time.Duration

	certmu sync.RWMutex

	*tls.Config
}

// NewConfig creates a MITM config using the CA certificate and
// private key to generate on-the-fly certificates.
func NewConfig(ca *x509.Certificate, privateKey interface{}) (*GoproxyConfig, error) {
	roots := x509.NewCertPool()
	roots.AddCert(ca)

	priv, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		return nil, err
	}
	pub := priv.Public()

	// Subject Key Identifier support for end entity certificate.
	// https://www.ietf.org/rfc/rfc3280.txt (section 4.2.1.2)
	pkixpub, err := x509.MarshalPKIXPublicKey(pub)
	if err != nil {
		return nil, err
	}
	h := sha1.New()
	h.Write(pkixpub)
	keyID := h.Sum(nil)

	tlsConfig := &GoproxyConfig{
		Root:     ca,
		capriv:   privateKey,
		priv:     priv,
		keyID:    keyID,
		validity: time.Hour * 24 * 3650,

		Config: &tls.Config{
			InsecureSkipVerify: true,
			Certificates:       make([]tls.Certificate, 0),
			MinVersion:         tls.VersionTLS12,
			RootCAs:            roots,
			NameToCertificate:  make(map[string]*tls.Certificate),
		},
	}

	return tlsConfig, nil
}

func (c *GoproxyConfig) cert(hostname string) error {
	// Remove the port if it exists.
	host, _, err := net.SplitHostPort(getWildcardHost(hostname))
	if err == nil {
		hostname = host
	}

	// Remove the port if it exists.
	c.certmu.RLock()
	tlsc, ok := c.NameToCertificate[hostname]
	c.certmu.RUnlock()

	if ok {
		// Check validity of the certificate for hostname match, expiry, etc. In
		// particular, if the cached certificate has expired, create a new one.
		if _, err := tlsc.Leaf.Verify(x509.VerifyOptions{
			DNSName: hostname,
			Roots:   c.RootCAs,
		}); err == nil {
			return nil
		}
	}

	serial, err := rand.Int(rand.Reader, MaxSerialNumber)
	if err != nil {
		return err
	}

	tmpl := &x509.Certificate{
		SerialNumber: serial,
		Subject: pkix.Name{
			CommonName:   hostname,
			Organization: []string{"StopLight"},
		},
		SubjectKeyId:          c.keyID,
		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
		BasicConstraintsValid: true,
		NotBefore:             time.Now().Add(-c.validity),
		NotAfter:              time.Now().Add(c.validity),
	}

	if ip := net.ParseIP(hostname); ip != nil {
		tmpl.IPAddresses = []net.IP{ip}
	} else {
		tmpl.DNSNames = []string{hostname}
	}

	raw, err := x509.CreateCertificate(rand.Reader, tmpl, c.Root, c.priv.Public(), c.capriv)
	if err != nil {
		return err
	}

	// Parse certificate bytes so that we have a leaf certificate.
	x509c, err := x509.ParseCertificate(raw)
	if err != nil {
		return err
	}

	tlsc = &tls.Certificate{
		Certificate: [][]byte{raw, c.Root.Raw},
		PrivateKey:  c.priv,
		Leaf:        x509c,
	}

	c.certmu.Lock()
	c.NameToCertificate[hostname] = tlsc
	c.Certificates = append(c.Certificates, *tlsc)
	c.certmu.Unlock()

	return nil
}
<|endoftext|>


<commit_before>package jwthelper

import (
	"fmt"

	"github.com/dgrijalva/jwt-go"
)

// Signer is used to sign JWT tokens.
// It stores signing method and key internally.
type Signer struct {
	method jwt.SigningMethod
	key    interface{}
}

// SignerOption represents the option for JWT token signing.
type SignerOption struct {
	f func(s *Signer)
}

var (
	// ErrInvalidSigner is the error of invalid signer.
	ErrInvalidSigner = fmt.Errorf("invalid signer")
)

func SignerMethod(m jwt.SigningMethod) SignerOption {
	return SignerOption{func(s *Signer) {
		s.method = m
	}}
}

func NewRSASHASigner(key []byte, options ...SignerOption) *Signer {
	s := &Signer{
		// Default signing method: RSASHA-256.
		method: jwt.SigningMethodRS256,
	}

	// Override customized options.
	for _, op := range options {
		op.f(s)
	}

	privateKey, err := jwt.ParseRSAPrivateKeyFromPEM(key)
	if err != nil {
		return &Signer{}
	}

	s.key = privateKey
	return s
}

func NewRSASHASignerFromPEMFile(privatePEM string, options ...SignerOption) *Signer {
	key, err := ReadKey(privatePEM)
	if err != nil {
		return &Signer{}
	}

	return NewRSASHASigner(key, options...)
}

func (s *Signer) Valid() bool {
	if s.method == nil || s.key == nil {
		return false
	}
	return true
}

func (s *Signer) SignedString(claims ...Claim) (string, error) {
	if !s.Valid() {
		return "", ErrInvalidSigner
	}

	myClaims := newClaims()

	for _, claim := range claims {
		claim.f(&myClaims)
	}

	token := jwt.NewWithClaims(s.method, myClaims.claims)
	return token.SignedString(s.key)
}
<commit_msg>Add comment of SignerMethod<commit_after>package jwthelper

import (
	"fmt"

	"github.com/dgrijalva/jwt-go"
)

// Signer is used to sign JWT tokens.
// It stores signing method and key internally.
type Signer struct {
	method jwt.SigningMethod
	key    interface{}
}

// SignerOption represents the option for JWT token signing.
type SignerOption struct {
	f func(s *Signer)
}

var (
	// ErrInvalidSigner is the error of invalid signer.
	ErrInvalidSigner = fmt.Errorf("invalid signer")
)

// SignerMethod returns the option for signing method.
func SignerMethod(m jwt.SigningMethod) SignerOption {
	return SignerOption{func(s *Signer) {
		s.method = m
	}}
}

func NewRSASHASigner(key []byte, options ...SignerOption) *Signer {
	s := &Signer{
		// Default signing method: RSASHA-256.
		method: jwt.SigningMethodRS256,
	}

	// Override customized options.
	for _, op := range options {
		op.f(s)
	}

	privateKey, err := jwt.ParseRSAPrivateKeyFromPEM(key)
	if err != nil {
		return &Signer{}
	}

	s.key = privateKey
	return s
}

func NewRSASHASignerFromPEMFile(privatePEM string, options ...SignerOption) *Signer {
	key, err := ReadKey(privatePEM)
	if err != nil {
		return &Signer{}
	}

	return NewRSASHASigner(key, options...)
}

func (s *Signer) Valid() bool {
	if s.method == nil || s.key == nil {
		return false
	}
	return true
}

func (s *Signer) SignedString(claims ...Claim) (string, error) {
	if !s.Valid() {
		return "", ErrInvalidSigner
	}

	myClaims := newClaims()

	for _, claim := range claims {
		claim.f(&myClaims)
	}

	token := jwt.NewWithClaims(s.method, myClaims.claims)
	return token.SignedString(s.key)
}
<|endoftext|>


<commit_before>// Package cron parses cron time schedules and computes scheduling.
package cron

import (
	"bytes"
	"fmt"
	"strconv"
	"strings"
	"time"
)

// Parse parses a cron expression string. Five fields (minute, hour, day of
// month, month, day of week) are expected. Valid symbols are
//
//   * , - /
//
// Month and weekday names (or any unique prefix thereof) may be used in those
// respective fields (case sensitivity is ignored).
//
// Read http://en.wikipedia.org/wiki/Cron for more information about the format.
func Parse(expr string) (*Schedule, error) {
	if fieldExpr, ok := namedSchedules[expr]; ok {
		return parseFields(fieldExpr)
	}
	schedule, err := parseFields(expr)
	if err != nil {
		// Just for a friendlier error message
		if strings.HasPrefix(expr, "@") {
			return nil, fmt.Errorf("unrecognized cron schedule name: %q\n", expr)
		}
		return nil, fmt.Errorf("invalid cron schedule: %s", err)
	}
	return schedule, nil
}

// Valid reports whether s is a valid schedule (that is, whether it could
// correspond to some well-formed cron expression).
func (s *Schedule) Valid() bool {
outer:
	for i, size := range fieldSizes {
		for j := 0; j < size; j++ {
			if s.isSet(fieldOffsets[i] + j) {
				continue outer
			}
		}
		return false
	}
	return true
}

// Next gives the smallest time greater than t when the Schedule is satisfied.
// Next panics if s is not valid.
func (s *Schedule) Next(t time.Time) time.Time {
	if !s.Valid() {
		panic("Next() called on invalid schedule")
	}
	// Start t off at the earliest possible subsequent minute.
	t = t.Truncate(time.Minute).Add(time.Minute)

	for {
		if !s.matchesMonth(t) {
			t = advanceMonth(t)
			continue
		}
		if !s.matchesDay(t) {
			t = advanceDay(t)
			continue
		}
		if !s.matchesHour(t) {
			t = advanceHour(t)
			continue
		}
		if !s.matchesMinute(t) {
			t = advanceMinute(t)
			continue
		}
		return t
	}
}

func advanceMonth(t time.Time) time.Time {
	year, month, _ := t.Date()
	return time.Date(year, month+1, 1, 0, 0, 0, 0, t.Location())
}

func advanceDay(t time.Time) time.Time {
	year, month, day := t.Date()
	return time.Date(year, month, day+1, 0, 0, 0, 0, t.Location())
}

func advanceHour(t time.Time) time.Time {
	return t.Truncate(time.Hour).Add(time.Hour)
}

func advanceMinute(t time.Time) time.Time {
	return t.Truncate(time.Minute).Add(time.Minute)
}

func (s *Schedule) matchesMonth(t time.Time) bool {
	return s.isSet(monthOffset + int(t.Month()) - 1)
}

func (s *Schedule) matchesDay(t time.Time) bool {
	return s.isSet(domOffset+t.Day()-1) && s.isSet(dowOffset+int(t.Weekday()))
}

func (s *Schedule) matchesHour(t time.Time) bool {
	return s.isSet(hourOffset + t.Hour())
}

func (s *Schedule) matchesMinute(t time.Time) bool {
	return s.isSet(minuteOffset + t.Minute())
}

const (
	// These are in order, LSB first.
	minutes = 60
	hours   = 24
	doms    = 31
	months  = 12
	dows    = 7

	minuteOffset  = 0
	hourOffset    = minuteOffset + minutes
	domOffset     = hourOffset + hours
	monthOffset   = domOffset + doms
	dowOffset     = monthOffset + months
	end           = dowOffset + dows
	scheduleBytes = (end-1)/8 + 1
)

var fieldSizes = [...]int{
	0: minutes,
	1: hours,
	2: doms,
	3: months,
	4: dows,
}

var fieldOffsets = [...]int{
	0: minuteOffset,
	1: hourOffset,
	2: domOffset,
	3: monthOffset,
	4: dowOffset,
}

var fieldNames = [...]string{
	0: "minute",
	1: "hour",
	2: "day of month",
	3: "month",
	4: "day of week",
}

// A Schedule is a parsed cron schedule.
type Schedule struct {
	b [scheduleBytes]byte
}

var namedSchedules = map[string]string{
	"@monthly": "0 0 1 * *",
	"@weekly":  "0 0 * * 0",
	"@daily":   "0 0 * * *",
	"@hourly":  "0 * * * *",
}

var monthNames = []string{
	"january",
	"february",
	"march",
	"april",
	"may",
	"june",
	"july",
	"august",
	"september",
	"october",
	"november",
	"december",
}

var dowNames = []string{
	"sunday",
	"monday",
	"tuesday",
	"wednesday",
	"thursday",
	"friday",
	"saturday",
}

func parseFields(expr string) (*Schedule, error) {
	var schedule Schedule
	fields := strings.Fields(expr)
	if len(fields) != 5 {
		return nil, fmt.Errorf("wrong number of fields in schedule %q (expected 5)", expr)
	}
	for i, field := range fields {
		for _, part := range strings.Split(field, ",") {
			partial, err := parseSinglePart(part, i)
			if err != nil {
				return nil, err
			}
			schedule.union(partial)
		}
	}
	return &schedule, nil
}

func parseSinglePart(part string, fieldIndex int) (*Schedule, error) {
	inc := 1
	incParts := strings.SplitN(part, "/", 2)
	if len(incParts) == 2 {
		var err error
		inc, err = strconv.Atoi(incParts[1])
		if err != nil {
			return nil, fmt.Errorf("invalid increment: %q", incParts[1])
		}
		if inc < 1 {
			return nil, fmt.Errorf("invalid increment %d (must be at least 1)", inc)
		}
	}
	var rangeStart, rangeEnd int // inclusive
	var err error
	if incParts[0] == "*" {
		rangeStart = 0
		rangeEnd = fieldSizes[fieldIndex] - 1
	} else {
		if rangeParts := strings.SplitN(incParts[0], "-", 2); len(rangeParts) == 2 {
			rangeStart, err = parseSingleValue(rangeParts[0], fieldIndex)
			if err != nil {
				return nil, err
			}
			rangeEnd, err = parseSingleValue(rangeParts[1], fieldIndex)
			if err != nil {
				return nil, err
			}
			if rangeStart == rangeEnd {
				return nil, fmt.Errorf("bad range %q -- start and end must be different", incParts[0])
			}
		} else {
			rangeStart, err = parseSingleValue(incParts[0], fieldIndex)
			if err != nil {
				return nil, err
			}
			rangeEnd = rangeStart
		}
		// Compensate for the 1-indexed fields.
		switch fieldIndex {
		case 2, 3:
			rangeStart--
			rangeEnd--
		}
	}

	var i int
	j := rangeStart
	first := false
	var s Schedule
	for {
		if i%inc == 0 {
			s.set(fieldOffsets[fieldIndex] + j)
		}
		if first {
			first = false
		} else if j == rangeEnd {
			break
		}
		i++
		j++
		if j == fieldSizes[fieldIndex] {
			j = 0
		}
	}
	return &s, nil
}

func parseSingleValue(val string, fieldIndex int) (int, error) {
	if n, err := strconv.Atoi(val); err == nil {
		switch fieldIndex {
		case 0, 1, 4:
			if n < 0 || n >= fieldSizes[fieldIndex] {
				goto badRange
			}
		case 2, 3:
			if n < 1 || n > fieldSizes[fieldIndex] {
				goto badRange
			}
		default:
			panic("unreachable")
		}
		return n, nil
	badRange:
		return 0, fmt.Errorf("invalid value %d for the %s field", n, fieldNames[fieldIndex])
	}
	switch fieldIndex {
	case 3:
		n := matchUniquePrefix(val, monthNames)
		if n >= 0 {
			return n + 1, nil
		}
	case 4:
		n := matchUniquePrefix(val, dowNames)
		if n >= 0 {
			return n, nil
		}
	}
	return 0, fmt.Errorf("invalid value %q for the %s field", val, fieldNames[fieldIndex])
}

func matchUniquePrefix(prefix string, dict []string) int {
	s := strings.ToLower(prefix)
	result := -1
	for i, s2 := range dict {
		if strings.HasPrefix(s2, s) {
			if result >= 0 {
				return -1
			}
			result = i
		}
	}
	return result
}

func (s *Schedule) set(off int) {
	s.b[off/8] |= (1 << uint(off%8))
}

func (s *Schedule) isSet(off int) bool {
	return s.b[off/8]&(1<<uint(off%8)) > 0
}

func (s *Schedule) union(s1 *Schedule) {
	for i := range s.b {
		s.b[i] |= s1.b[i]
	}
}

func (s *Schedule) debugString() string {
	var buf bytes.Buffer
	for i, b := range s.b {
		fmt.Fprintf(&buf, "%08b", b)
		if i < len(s.b) {
			fmt.Fprint(&buf, " ")
		}
	}
	fmt.Fprintln(&buf)
	for i := 0; i < 5; i++ {
		anyUnset := false
		var indices []int
		for j := 0; j < fieldSizes[i]; j++ {
			if s.isSet(fieldOffsets[i] + j) {
				indices = append(indices, j)
			} else {
				anyUnset = true
			}
		}
		setList := fmt.Sprintf("%v", indices)
		if !anyUnset {
			setList = "*"
		}
		fmt.Fprintf(&buf, "%-15s %s\n", fieldNames[i], setList)
	}
	return buf.String()
}
<commit_msg>Apply staticcheck cleanups<commit_after>// Package cron parses cron time schedules and computes scheduling.
package cron

import (
	"fmt"
	"strconv"
	"strings"
	"time"
)

// Parse parses a cron expression string. Five fields (minute, hour, day of
// month, month, day of week) are expected. Valid symbols are
//
//   * , - /
//
// Month and weekday names (or any unique prefix thereof) may be used in those
// respective fields (case sensitivity is ignored).
//
// Read http://en.wikipedia.org/wiki/Cron for more information about the format.
func Parse(expr string) (*Schedule, error) {
	if fieldExpr, ok := namedSchedules[expr]; ok {
		return parseFields(fieldExpr)
	}
	schedule, err := parseFields(expr)
	if err != nil {
		// Just for a friendlier error message
		if strings.HasPrefix(expr, "@") {
			return nil, fmt.Errorf("unrecognized cron schedule name: %q", expr)
		}
		return nil, fmt.Errorf("invalid cron schedule: %s", err)
	}
	return schedule, nil
}

// Valid reports whether s is a valid schedule (that is, whether it could
// correspond to some well-formed cron expression).
func (s *Schedule) Valid() bool {
outer:
	for i, size := range fieldSizes {
		for j := 0; j < size; j++ {
			if s.isSet(fieldOffsets[i] + j) {
				continue outer
			}
		}
		return false
	}
	return true
}

// Next gives the smallest time greater than t when the Schedule is satisfied.
// Next panics if s is not valid.
func (s *Schedule) Next(t time.Time) time.Time {
	if !s.Valid() {
		panic("Next() called on invalid schedule")
	}
	// Start t off at the earliest possible subsequent minute.
	t = t.Truncate(time.Minute).Add(time.Minute)

	for {
		if !s.matchesMonth(t) {
			t = advanceMonth(t)
			continue
		}
		if !s.matchesDay(t) {
			t = advanceDay(t)
			continue
		}
		if !s.matchesHour(t) {
			t = advanceHour(t)
			continue
		}
		if !s.matchesMinute(t) {
			t = advanceMinute(t)
			continue
		}
		return t
	}
}

func advanceMonth(t time.Time) time.Time {
	year, month, _ := t.Date()
	return time.Date(year, month+1, 1, 0, 0, 0, 0, t.Location())
}

func advanceDay(t time.Time) time.Time {
	year, month, day := t.Date()
	return time.Date(year, month, day+1, 0, 0, 0, 0, t.Location())
}

func advanceHour(t time.Time) time.Time {
	return t.Truncate(time.Hour).Add(time.Hour)
}

func advanceMinute(t time.Time) time.Time {
	return t.Truncate(time.Minute).Add(time.Minute)
}

func (s *Schedule) matchesMonth(t time.Time) bool {
	return s.isSet(monthOffset + int(t.Month()) - 1)
}

func (s *Schedule) matchesDay(t time.Time) bool {
	return s.isSet(domOffset+t.Day()-1) && s.isSet(dowOffset+int(t.Weekday()))
}

func (s *Schedule) matchesHour(t time.Time) bool {
	return s.isSet(hourOffset + t.Hour())
}

func (s *Schedule) matchesMinute(t time.Time) bool {
	return s.isSet(minuteOffset + t.Minute())
}

const (
	// These are in order, LSB first.
	minutes = 60
	hours   = 24
	doms    = 31
	months  = 12
	dows    = 7

	minuteOffset  = 0
	hourOffset    = minuteOffset + minutes
	domOffset     = hourOffset + hours
	monthOffset   = domOffset + doms
	dowOffset     = monthOffset + months
	end           = dowOffset + dows
	scheduleBytes = (end-1)/8 + 1
)

var fieldSizes = [...]int{
	0: minutes,
	1: hours,
	2: doms,
	3: months,
	4: dows,
}

var fieldOffsets = [...]int{
	0: minuteOffset,
	1: hourOffset,
	2: domOffset,
	3: monthOffset,
	4: dowOffset,
}

var fieldNames = [...]string{
	0: "minute",
	1: "hour",
	2: "day of month",
	3: "month",
	4: "day of week",
}

// A Schedule is a parsed cron schedule.
type Schedule struct {
	b [scheduleBytes]byte
}

var namedSchedules = map[string]string{
	"@monthly": "0 0 1 * *",
	"@weekly":  "0 0 * * 0",
	"@daily":   "0 0 * * *",
	"@hourly":  "0 * * * *",
}

var monthNames = []string{
	"january",
	"february",
	"march",
	"april",
	"may",
	"june",
	"july",
	"august",
	"september",
	"october",
	"november",
	"december",
}

var dowNames = []string{
	"sunday",
	"monday",
	"tuesday",
	"wednesday",
	"thursday",
	"friday",
	"saturday",
}

func parseFields(expr string) (*Schedule, error) {
	var schedule Schedule
	fields := strings.Fields(expr)
	if len(fields) != 5 {
		return nil, fmt.Errorf("wrong number of fields in schedule %q (expected 5)", expr)
	}
	for i, field := range fields {
		for _, part := range strings.Split(field, ",") {
			partial, err := parseSinglePart(part, i)
			if err != nil {
				return nil, err
			}
			schedule.union(partial)
		}
	}
	return &schedule, nil
}

func parseSinglePart(part string, fieldIndex int) (*Schedule, error) {
	inc := 1
	incParts := strings.SplitN(part, "/", 2)
	if len(incParts) == 2 {
		var err error
		inc, err = strconv.Atoi(incParts[1])
		if err != nil {
			return nil, fmt.Errorf("invalid increment: %q", incParts[1])
		}
		if inc < 1 {
			return nil, fmt.Errorf("invalid increment %d (must be at least 1)", inc)
		}
	}
	var rangeStart, rangeEnd int // inclusive
	var err error
	if incParts[0] == "*" {
		rangeStart = 0
		rangeEnd = fieldSizes[fieldIndex] - 1
	} else {
		if rangeParts := strings.SplitN(incParts[0], "-", 2); len(rangeParts) == 2 {
			rangeStart, err = parseSingleValue(rangeParts[0], fieldIndex)
			if err != nil {
				return nil, err
			}
			rangeEnd, err = parseSingleValue(rangeParts[1], fieldIndex)
			if err != nil {
				return nil, err
			}
			if rangeStart == rangeEnd {
				return nil, fmt.Errorf("bad range %q -- start and end must be different", incParts[0])
			}
		} else {
			rangeStart, err = parseSingleValue(incParts[0], fieldIndex)
			if err != nil {
				return nil, err
			}
			rangeEnd = rangeStart
		}
		// Compensate for the 1-indexed fields.
		switch fieldIndex {
		case 2, 3:
			rangeStart--
			rangeEnd--
		}
	}

	var i int
	j := rangeStart
	first := false
	var s Schedule
	for {
		if i%inc == 0 {
			s.set(fieldOffsets[fieldIndex] + j)
		}
		if first {
			first = false
		} else if j == rangeEnd {
			break
		}
		i++
		j++
		if j == fieldSizes[fieldIndex] {
			j = 0
		}
	}
	return &s, nil
}

func parseSingleValue(val string, fieldIndex int) (int, error) {
	if n, err := strconv.Atoi(val); err == nil {
		switch fieldIndex {
		case 0, 1, 4:
			if n < 0 || n >= fieldSizes[fieldIndex] {
				goto badRange
			}
		case 2, 3:
			if n < 1 || n > fieldSizes[fieldIndex] {
				goto badRange
			}
		default:
			panic("unreachable")
		}
		return n, nil
	badRange:
		return 0, fmt.Errorf("invalid value %d for the %s field", n, fieldNames[fieldIndex])
	}
	switch fieldIndex {
	case 3:
		n := matchUniquePrefix(val, monthNames)
		if n >= 0 {
			return n + 1, nil
		}
	case 4:
		n := matchUniquePrefix(val, dowNames)
		if n >= 0 {
			return n, nil
		}
	}
	return 0, fmt.Errorf("invalid value %q for the %s field", val, fieldNames[fieldIndex])
}

func matchUniquePrefix(prefix string, dict []string) int {
	s := strings.ToLower(prefix)
	result := -1
	for i, s2 := range dict {
		if strings.HasPrefix(s2, s) {
			if result >= 0 {
				return -1
			}
			result = i
		}
	}
	return result
}

func (s *Schedule) set(off int) {
	s.b[off/8] |= (1 << uint(off%8))
}

func (s *Schedule) isSet(off int) bool {
	return s.b[off/8]&(1<<uint(off%8)) > 0
}

func (s *Schedule) union(s1 *Schedule) {
	for i := range s.b {
		s.b[i] |= s1.b[i]
	}
}
<|endoftext|>