<commit_before>package websocket

import (
	"bytes"
	"io"
	"net/url"
	"time"

	"github.com/gopherjs/gopherjs/js"
	"honnef.co/go/js/dom"
)

func beginHandlerOpen(ch chan error) func(ev js.Object) {
	return func(ev js.Object) {
		close(ch)
	}
}

func beginHandlerClose(ch chan error) func(ev js.Object) {
	return func(ev js.Object) {
		ch <- &js.Error{Object: ev}
		close(ch)
	}
}

// Dial opens a new WebSocket connection. It will block until the connection is
// established or fails to connect.
func Dial(url string) (*Conn, error) {
	ws, err := New(url)
	if err != nil {
		return nil, err
	}

	openCh := make(chan error, 1)

	// We have to use variables for the functions so that we can remove the
	// event handlers afterwards.
	openHandler := beginHandlerOpen(openCh)
	closeHandler := beginHandlerClose(openCh)

	ws.AddEventListener("open", false, openHandler)
	ws.AddEventListener("close", false, closeHandler)

	err, ok := <-openCh

	ws.RemoveEventListener("open", false, openHandler)
	ws.RemoveEventListener("close", false, closeHandler)

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

	conn := &Conn{
		WebSocket: ws,
		ch:        make(chan *dom.MessageEvent, 1),
	}
	conn.Initialize()

	return conn, nil
}

// Conn is a high-level wrapper around WebSocket. It is intended to
// provide a net.TCPConn-like interface.
type Conn struct {
	*WebSocket

	ch      chan *dom.MessageEvent
	readBuf *bytes.Reader
}

func (c *Conn) onMessage(event js.Object) {
	go func() {
		c.ch <- dom.WrapEvent(event).(*dom.MessageEvent)
	}()
}

func (c *Conn) onClose(event js.Object) {
	go func() {
		// We queue nil to the end so that any messages received prior to
		// closing get handled first.
		c.ch <- nil
	}()
}

// Initialize adds all of the event handlers necessary for a Conn to function.
// It should never be called more than once and is already called if you used
// Dial to create the Conn.
func (c *Conn) Initialize() {
	// We need this so that received binary data is in ArrayBufferView format so
	// that it can easily be read.
	c.BinaryType = "arraybuffer"

	c.AddEventListener("message", false, c.onMessage)
	c.AddEventListener("close", false, c.onClose)
}

// receiveFrame receives one full frame from the WebSocket. It blocks until the
// frame is received.
func (c *Conn) receiveFrame() (*dom.MessageEvent, error) {
	item, ok := <-c.ch
	if !ok { // The channel has been closed
		return nil, io.EOF
	} else if item == nil {
		// See onClose for the explanation about sending a nil item.
		close(c.ch)
		return nil, io.EOF
	}
	return item, nil
}

func getFrameData(obj js.Object) []byte {
	// TODO(nightexcessive): Is there a better way to do this?

	frameStr := obj.Str()
	if frameStr == "[object ArrayBuffer]" {
		int8Array := js.Global.Get("Uint8Array").New(obj)
		return int8Array.Interface().([]byte)
	}

	return []byte(frameStr)
}

func (c *Conn) Read(b []byte) (n int, err error) {
	// TODO(nightexcessive): Implement the deadline functions.

	if c.readBuf != nil {
		n, err = c.readBuf.Read(b)
		if err == io.EOF {
			c.readBuf = nil
			err = nil
		}
		// If we read nothing from the buffer, continue to trying to receive.
		// This saves us when the last Read call emptied the buffer and this
		// call triggers the EOF. There's probably a better way of doing this,
		// but I'm really tired.
		if n > 0 {
			return
		}
	}

	frame, err := c.receiveFrame()
	if err != nil {
		return 0, err
	}

	receivedBytes := getFrameData(frame.Data)

	n = copy(b, receivedBytes)
	// Fast path: The entire frame's contents have been copied into b.
	if n >= len(receivedBytes) {
		return
	}

	c.readBuf = bytes.NewReader(receivedBytes[n:])
	return
}

// Write writes the contents of b to the WebSocket using a binary opcode.
func (c *Conn) Write(b []byte) (n int, err error) {
	// []byte is converted to an (U)Int8Array by GopherJS, which fullfils the
	// ArrayBufferView definition.
	err = c.Send(b)
	if err != nil {
		return
	}
	n = len(b)
	return
}

// WriteString writes the contents of s to the WebSocket using a text frame
// opcode.
func (c *Conn) WriteString(s string) (n int, err error) {
	err = c.Send(s)
	if err != nil {
		return
	}
	n = len(s)
	return
}

// BUG(nightexcessive): We can't return net.Addr from Conn.LocalAddr and
// Conn.RemoteAddr because net.init() causes a panic due to attempts to make
// syscalls. See: https://github.com/gopherjs/gopherjs/issues/123

// LocalAddr would typically return the local network address, but due to
// limitations in the JavaScript API, it is unable to. Calling this method will
// cause a panic.
func (c *Conn) LocalAddr() *Addr {
	// BUG(nightexcessive): Conn.LocalAddr() panics because the underlying
	// JavaScript API has no way of figuring out the local address.

	// TODO(nightexcessive): Find a more graceful way to handle this
	panic("we are unable to implement websocket.Conn.LocalAddr() due to limitations in the underlying JavaScript API")
}

// RemoteAddr returns the remote network address, based on
// websocket.WebSocket.URL.
func (c *Conn) RemoteAddr() *Addr {
	wsURL, err := url.Parse(c.URL)
	if err != nil {
		// TODO(nightexcessive): Should we be panicking for this?
		panic(err)
	}
	return &Addr{wsURL}
}

// SetDeadline implements the net.Conn.SetDeadline method.
func (c *Conn) SetDeadline(t time.Time) error {
	// TODO(nightexcessive): Implement
	panic("not yet implemeneted")
}

// SetReadDeadline implements the net.Conn.SetReadDeadline method.
func (c *Conn) SetReadDeadline(t time.Time) error {
	// TODO(nightexcessive): Implement
	panic("not yet implemeneted")
}

// SetWriteDeadline implements the net.Conn.SetWriteDeadline method.
func (c *Conn) SetWriteDeadline(t time.Time) error {
	// TODO(nightexcessive): Implement
	panic("not yet implemeneted")
}
<commit_msg>Improve getFrameData so that it doesn't rely on hacky string detection<commit_after>package websocket

import (
	"bytes"
	"io"
	"net/url"
	"time"

	"github.com/gopherjs/gopherjs/js"
	"honnef.co/go/js/dom"
)

func beginHandlerOpen(ch chan error) func(ev js.Object) {
	return func(ev js.Object) {
		close(ch)
	}
}

func beginHandlerClose(ch chan error) func(ev js.Object) {
	return func(ev js.Object) {
		ch <- &js.Error{Object: ev}
		close(ch)
	}
}

// Dial opens a new WebSocket connection. It will block until the connection is
// established or fails to connect.
func Dial(url string) (*Conn, error) {
	ws, err := New(url)
	if err != nil {
		return nil, err
	}

	openCh := make(chan error, 1)

	// We have to use variables for the functions so that we can remove the
	// event handlers afterwards.
	openHandler := beginHandlerOpen(openCh)
	closeHandler := beginHandlerClose(openCh)

	ws.AddEventListener("open", false, openHandler)
	ws.AddEventListener("close", false, closeHandler)

	err, ok := <-openCh

	ws.RemoveEventListener("open", false, openHandler)
	ws.RemoveEventListener("close", false, closeHandler)

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

	conn := &Conn{
		WebSocket: ws,
		ch:        make(chan *dom.MessageEvent, 1),
	}
	conn.Initialize()

	return conn, nil
}

// Conn is a high-level wrapper around WebSocket. It is intended to
// provide a net.TCPConn-like interface.
type Conn struct {
	*WebSocket

	ch      chan *dom.MessageEvent
	readBuf *bytes.Reader
}

func (c *Conn) onMessage(event js.Object) {
	go func() {
		c.ch <- dom.WrapEvent(event).(*dom.MessageEvent)
	}()
}

func (c *Conn) onClose(event js.Object) {
	go func() {
		// We queue nil to the end so that any messages received prior to
		// closing get handled first.
		c.ch <- nil
	}()
}

// Initialize adds all of the event handlers necessary for a Conn to function.
// It should never be called more than once and is already called if you used
// Dial to create the Conn.
func (c *Conn) Initialize() {
	// We need this so that received binary data is in ArrayBufferView format so
	// that it can easily be read.
	c.BinaryType = "arraybuffer"

	c.AddEventListener("message", false, c.onMessage)
	c.AddEventListener("close", false, c.onClose)
}

// receiveFrame receives one full frame from the WebSocket. It blocks until the
// frame is received.
func (c *Conn) receiveFrame() (*dom.MessageEvent, error) {
	item, ok := <-c.ch
	if !ok { // The channel has been closed
		return nil, io.EOF
	} else if item == nil {
		// See onClose for the explanation about sending a nil item.
		close(c.ch)
		return nil, io.EOF
	}
	return item, nil
}

func getFrameData(obj js.Object) []byte {
	// Check if it's an array buffer. If so, convert it to a Go byte slice.
	if constructor := obj.Get("constructor"); constructor == js.Global.Get("ArrayBuffer") {
		int8Array := js.Global.Get("Uint8Array").New(obj)
		return int8Array.Interface().([]byte)
	}

	return []byte(obj.Str())
}

func (c *Conn) Read(b []byte) (n int, err error) {
	// TODO(nightexcessive): Implement the deadline functions.

	if c.readBuf != nil {
		n, err = c.readBuf.Read(b)
		if err == io.EOF {
			c.readBuf = nil
			err = nil
		}
		// If we read nothing from the buffer, continue to trying to receive.
		// This saves us when the last Read call emptied the buffer and this
		// call triggers the EOF. There's probably a better way of doing this,
		// but I'm really tired.
		if n > 0 {
			return
		}
	}

	frame, err := c.receiveFrame()
	if err != nil {
		return 0, err
	}

	receivedBytes := getFrameData(frame.Data)

	n = copy(b, receivedBytes)
	// Fast path: The entire frame's contents have been copied into b.
	if n >= len(receivedBytes) {
		return
	}

	c.readBuf = bytes.NewReader(receivedBytes[n:])
	return
}

// Write writes the contents of b to the WebSocket using a binary opcode.
func (c *Conn) Write(b []byte) (n int, err error) {
	// []byte is converted to an (U)Int8Array by GopherJS, which fullfils the
	// ArrayBufferView definition.
	err = c.Send(b)
	if err != nil {
		return
	}
	n = len(b)
	return
}

// WriteString writes the contents of s to the WebSocket using a text frame
// opcode.
func (c *Conn) WriteString(s string) (n int, err error) {
	err = c.Send(s)
	if err != nil {
		return
	}
	n = len(s)
	return
}

// BUG(nightexcessive): We can't return net.Addr from Conn.LocalAddr and
// Conn.RemoteAddr because net.init() causes a panic due to attempts to make
// syscalls. See: https://github.com/gopherjs/gopherjs/issues/123

// LocalAddr would typically return the local network address, but due to
// limitations in the JavaScript API, it is unable to. Calling this method will
// cause a panic.
func (c *Conn) LocalAddr() *Addr {
	// BUG(nightexcessive): Conn.LocalAddr() panics because the underlying
	// JavaScript API has no way of figuring out the local address.

	// TODO(nightexcessive): Find a more graceful way to handle this
	panic("we are unable to implement websocket.Conn.LocalAddr() due to limitations in the underlying JavaScript API")
}

// RemoteAddr returns the remote network address, based on
// websocket.WebSocket.URL.
func (c *Conn) RemoteAddr() *Addr {
	wsURL, err := url.Parse(c.URL)
	if err != nil {
		// TODO(nightexcessive): Should we be panicking for this?
		panic(err)
	}
	return &Addr{wsURL}
}

// SetDeadline implements the net.Conn.SetDeadline method.
func (c *Conn) SetDeadline(t time.Time) error {
	// TODO(nightexcessive): Implement
	panic("not yet implemeneted")
}

// SetReadDeadline implements the net.Conn.SetReadDeadline method.
func (c *Conn) SetReadDeadline(t time.Time) error {
	// TODO(nightexcessive): Implement
	panic("not yet implemeneted")
}

// SetWriteDeadline implements the net.Conn.SetWriteDeadline method.
func (c *Conn) SetWriteDeadline(t time.Time) error {
	// TODO(nightexcessive): Implement
	panic("not yet implemeneted")
}
<|endoftext|>


<commit_before>package nntp

import (
    "crypto/tls"
    "fmt"
    "net/textproto"
)

// Interface implementation check
var _ Conn = (*conn)(nil)

// Conn represent(s) a single connection to a NNTP Server
type Conn interface {
    Connect() bool
    Close() error

    SwitchGroup(group string) error
    ArticleExists(id string) (bool, error)
    FetchArticle(id string) ([]byte, error)
}

// Conn represents a NNTP Connection
type conn struct {
    Info        *ServerInfo

    id          int
    conn        *textproto.Conn
    group       string
}

// NewConn create a new NNTP connection based on provided ServerInfo
func NewConn(id int, i *ServerInfo) Conn {
    return &conn {
        id: id,
        Info: i,
    }
}

func (c *conn) String() string {
    return fmt.Sprintf("%s:%d", c.Info.Host, c.id)
}

// Connect to NNTP server
func (c *conn) Connect() bool {
    // (Re)connect
    // Try to connect to newsgroup server
    // if unable to connect start auto-reconnect timer
    if c.Info.TLS {
        // Secured connection is requested
        err := c.dialTLS()
        if err != nil {
            return false
        }

        return true
    }

    err := c.dial()
    if err != nil {
        return false
    }

    return true
}

func (c *conn) dial() error {

	var err error
    c.conn, err = textproto.Dial("tcp", fmt.Sprintf("%s:%d", c.Info.Host, c.Info.Port))
	if err != nil {
		return err
	}

    _, _, err = c.conn.ReadCodeLine(20)
	if err != nil {
		c.conn.Close()
		return err
	}

    if c.Info.Auth != nil {
        err = c.authenticate()
    	if err != nil {
    		return err
    	}
    }

	return nil
}

func (c *conn) dialTLS() error {

    tlsConn, err := tls.Dial("tcp", fmt.Sprintf("%s:%d", c.Info.Host, c.Info.Port), nil)
	if err != nil {
		return err
	}

    c.conn = textproto.NewConn(tlsConn)
    _, _, err = c.conn.ReadCodeLine(20)
	if err != nil {
		c.conn.Close()
		return err
	}

    if c.Info.Auth != nil {
        err = c.authenticate()
    	if err != nil {
    		return err
    	}
    }

	return nil
}

//Authenticate will authenticate with the NNTP server, using the supplied
//username and password. It returns an error, if any
func (c *conn) authenticate() error {

    u, err := c.conn.Cmd("AUTHINFO USER %s", c.Info.Auth.Username)
	if err != nil {
		return err
	}

    c.conn.StartResponse(u)
	code, _, err := c.conn.ReadCodeLine(381)
    c.conn.EndResponse(u)

    switch code {
	case 481, 482, 502:
		//failed, out of sequence or command not available
		return err
	case 281:
		//accepted without password
		return nil
	case 381:
		//need password
		break
	default:
		return err
	}

    p, err := c.conn.Cmd("AUTHINFO PASS %s", c.Info.Auth.Password)
	if err != nil {
		return err
	}

	c.conn.StartResponse(p)
	code, _, err = c.conn.ReadCodeLine(281)
    c.conn.EndResponse(p)

	return err
}

// EOF
<commit_msg>fix Connect() include connection error in return<commit_after>package nntp

import (
    "crypto/tls"
    "fmt"
    "net/textproto"
)

// Interface implementation check
var _ Conn = (*conn)(nil)

// Conn represent(s) a single connection to a NNTP Server
type Conn interface {
    Connect() (bool, error)
    Close() error

    SwitchGroup(group string) error
    ArticleExists(id string) (bool, error)
    FetchArticle(id string) ([]byte, error)
}

// Conn represents a NNTP Connection
type conn struct {
    Info        *ServerInfo

    id          int
    conn        *textproto.Conn
    group       string
}

// NewConn create a new NNTP connection based on provided ServerInfo
func NewConn(id int, i *ServerInfo) Conn {
    return &conn {
        id: id,
        Info: i,
    }
}

func (c *conn) String() string {
    return fmt.Sprintf("%s:%d", c.Info.Host, c.id)
}

// Connect to NNTP server
func (c *conn) Connect() (bool, error) {
    // (Re)connect
    // Try to connect to newsgroup server
    // if unable to connect start auto-reconnect timer
    if c.Info.TLS {
        // Secured connection is requested
        err := c.dialTLS()
        if err != nil {
            return false, err
        }

        return true, nil
    }

    err := c.dial()
    if err != nil {
        return false, err
    }

    return true, nil
}

func (c *conn) dial() error {

	var err error
    c.conn, err = textproto.Dial("tcp", fmt.Sprintf("%s:%d", c.Info.Host, c.Info.Port))
	if err != nil {
		return err
	}

    _, _, err = c.conn.ReadCodeLine(20)
	if err != nil {
		c.conn.Close()
		return err
	}

    if c.Info.Auth != nil {
        err = c.authenticate()
    	if err != nil {
    		return err
    	}
    }

	return nil
}

func (c *conn) dialTLS() error {

    tlsConn, err := tls.Dial("tcp", fmt.Sprintf("%s:%d", c.Info.Host, c.Info.Port), nil)
	if err != nil {
		return err
	}

    c.conn = textproto.NewConn(tlsConn)
    _, _, err = c.conn.ReadCodeLine(20)
	if err != nil {
		c.conn.Close()
		return err
	}

    if c.Info.Auth != nil {
        err = c.authenticate()
    	if err != nil {
    		return err
    	}
    }

	return nil
}

//Authenticate will authenticate with the NNTP server, using the supplied
//username and password. It returns an error, if any
func (c *conn) authenticate() error {

    u, err := c.conn.Cmd("AUTHINFO USER %s", c.Info.Auth.Username)
	if err != nil {
		return err
	}

    c.conn.StartResponse(u)
	code, _, err := c.conn.ReadCodeLine(381)
    c.conn.EndResponse(u)

    switch code {
	case 481, 482, 502:
		//failed, out of sequence or command not available
		return err
	case 281:
		//accepted without password
		return nil
	case 381:
		//need password
		break
	default:
		return err
	}

    p, err := c.conn.Cmd("AUTHINFO PASS %s", c.Info.Auth.Password)
	if err != nil {
		return err
	}

	c.conn.StartResponse(p)
	code, _, err = c.conn.ReadCodeLine(281)
    c.conn.EndResponse(p)

	return err
}

// EOF
<|endoftext|>


<commit_before>/*
Package cors is net/http handler to handle CORS related requests
as defined by http://www.w3.org/TR/cors/

You can configure it by passing an option struct to cors.New:

    c := cors.New(cors.Options{
        AllowedOrigins: []string{"foo.com"},
        AllowedMethods: []string{"GET", "POST", "DELETE"},
        AllowCredentials: true,
    })

See Options documentation for more options.

The resulting handler is a standard net/http handler.
*/
package cors

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

// Options is a struct for specifying configuration options for the Cors middleware.
type Options struct {
	// AllowedOrigins is a list of origins a cross-domain request can be executed from.
	// If the special "*" value is present in the list, all origins will be allowed.
	// Default value is ["*"]
	AllowedOrigins []string
	// AllowedMethods is a list of methods the client is allowed to use with
	// cross-domain requests.
	AllowedMethods []string
	// AllowedHeaders is list of non simple headers the client is allowed to use with
	// cross-domain requests. Default value is simple methods (GET and POST)
	AllowedHeaders []string
	// ExposedHeaders indicates which headers are safe to expose to the API of a CORS
	// API specification
	ExposedHeaders []string
	// AllowCredentials indicates whether the request can include user credentials like
	// cookies, HTTP authentication or client side SSL certificates.
	AllowCredentials bool
	// MaxAge indicates how long (in seconds) the results of a preflight request
	// can be cached
	MaxAge int
}

type Cors struct {
	options Options
}

// New creates a new Cors handler with the provided options. Options are normalized.
func New(options Options) *Cors {
	// Normalize options
	// Note: for origins and methods matching, the spec requires a case-sensitive matching.
	// As it may error prone, we chose to ignore the spec here.
	normOptions := Options{
		AllowedOrigins: convert(options.AllowedOrigins, strings.ToLower),
		AllowedMethods: convert(options.AllowedMethods, strings.ToUpper),
		// Origin is always appended as some browsers will always request
		// for this header at preflight
		AllowedHeaders:   convert(append(options.AllowedHeaders, "Origin"), toHeader),
		ExposedHeaders:   convert(options.ExposedHeaders, toHeader),
		AllowCredentials: options.AllowCredentials,
		MaxAge:           options.MaxAge,
	}
	if len(normOptions.AllowedOrigins) == 0 {
		// Default is all origins
		normOptions.AllowedOrigins = []string{"*"}
	}
	if len(normOptions.AllowedMethods) == 0 {
		// Default is simple methods
		normOptions.AllowedMethods = []string{"GET", "POST"}
	}
	return &Cors{
		options: normOptions,
	}
}

// Default creates a new Cors handler with all default options
func Default() *Cors {
	return New(Options{})
}

// Handler apply the CORS specification on the request, and add relevant CORS headers
// as necessary.
func (cors *Cors) Handler(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "OPTIONS" {
			cors.handlePreflight(w, r)
		} else {
			cors.handleActualRequest(w, r)
		}
		h.ServeHTTP(w, r)
	})
}

// Martini compatible handler
func (cors *Cors) HandlerFunc(w http.ResponseWriter, r *http.Request) {
	if r.Method == "OPTIONS" {
		cors.handlePreflight(w, r)
	} else {
		cors.handleActualRequest(w, r)
	}
}

// Negroni compatible interface
func (cors *Cors) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	if r.Method == "OPTIONS" {
		cors.handlePreflight(w, r)
	} else {
		cors.handleActualRequest(w, r)
	}
	next(w, r)
}

// handlePreflight handles pre-flight CORS requests
func (cors *Cors) handlePreflight(w http.ResponseWriter, r *http.Request) {
	options := cors.options
	headers := w.Header()
	origin := r.Header.Get("Origin")
	if r.Method != "OPTIONS" || origin == "" || !cors.isOriginAllowed(origin) {
		return
	}
	reqMethod := r.Header.Get("Access-Control-Request-Method")
	if !cors.isMethodAllowed(reqMethod) {
		return
	}
	reqHeaders := parseHeaderList(r.Header.Get("Access-Control-Request-Headers"))
	if !cors.areHeadersAllowed(reqHeaders) {
		return
	}
	headers.Set("Access-Control-Allow-Origin", origin)
	// Spec says: Since the list of methods can be unbounded, simply returning the method indicated
	// by Access-Control-Request-Method (if supported) can be enough
	headers.Set("Access-Control-Allow-Methods", strings.ToUpper(reqMethod))
	if len(reqHeaders) > 0 {

		// Spec says: Since the list of headers can be unbounded, simply returning supported headers
		// from Access-Control-Request-Headers can be enough
		headers.Set("Access-Control-Allow-Headers", strings.Join(reqHeaders, ", "))
	}
	if options.AllowCredentials {
		headers.Set("Access-Control-Allow-Credentials", "true")
	}
	if options.MaxAge > 0 {
		headers.Set("Access-Control-Max-Age", strconv.Itoa(options.MaxAge))
	}
}

// handleActualRequest handles simple cross-origin requests, actual request or redirects
func (cors *Cors) handleActualRequest(w http.ResponseWriter, r *http.Request) {
	options := cors.options
	headers := w.Header()
	origin := r.Header.Get("Origin")
	if r.Method == "OPTIONS" || origin == "" || !cors.isOriginAllowed(origin) {
		return
	}
	// Note that spec does define a way to specifically disallow a simple method like GET or
	// POST. Access-Control-Allow-Methods is only used for pre-flight requests and the
	// spec doesn't instruct to check the allowed methods for simple cross-origin requests.
	// We think it's a nice feature to be able to have control on those methods though.
	if !cors.isMethodAllowed(r.Method) {
		return
	}
	headers.Set("Access-Control-Allow-Origin", origin)
	if len(options.ExposedHeaders) > 0 {
		headers.Set("Access-Control-Expose-Headers", strings.Join(options.ExposedHeaders, ", "))
	}
	if options.AllowCredentials {
		headers.Set("Access-Control-Allow-Credentials", "true")
	}
}

// isOriginAllowed checks if a given origin is allowed to perform cross-domain requests
// on the endpoint
func (cors *Cors) isOriginAllowed(origin string) bool {
	allowedOrigins := cors.options.AllowedOrigins
	origin = strings.ToLower(origin)
	for _, allowedOrigin := range allowedOrigins {
		switch allowedOrigin {
		case "*":
			return true
		case origin:
			return true
		}
	}
	return false
}

// isMethodAllowed checks if a given method can be used as part of a cross-domain request
// on the endpoing
func (cors *Cors) isMethodAllowed(method string) bool {
	allowedMethods := cors.options.AllowedMethods
	if len(allowedMethods) == 0 {
		// If no method allowed, always return false, even for preflight request
		return false
	}
	method = strings.ToUpper(method)
	if method == "OPTIONS" {
		// Always allow preflight requests
		return true
	}
	for _, allowedMethod := range allowedMethods {
		if allowedMethod == method {
			return true
		}
	}
	return false
}

// areHeadersAllowed checks if a given list of headers are allowed to used within
// a cross-domain request.
func (cors *Cors) areHeadersAllowed(requestedHeaders []string) bool {
	if len(requestedHeaders) == 0 {
		return true
	}
	for _, header := range requestedHeaders {
		found := false
		for _, allowedHeader := range cors.options.AllowedHeaders {
			if header == allowedHeader {
				found = true
				break
			}
		}
		if !found {
			return false
		}
	}
	return true
}
<commit_msg>Fix some doc<commit_after>/*
Package cors is net/http handler to handle CORS related requests
as defined by http://www.w3.org/TR/cors/

You can configure it by passing an option struct to cors.New:

    c := cors.New(cors.Options{
        AllowedOrigins: []string{"foo.com"},
        AllowedMethods: []string{"GET", "POST", "DELETE"},
        AllowCredentials: true,
    })

Then insert the handler in the chain:

    handler = c.Handler(handler)

See Options documentation for more options.

The resulting handler is a standard net/http handler.
*/
package cors

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

// Options is a configuration container to setup the CORS middleware.
type Options struct {
	// AllowedOrigins is a list of origins a cross-domain request can be executed from.
	// If the special "*" value is present in the list, all origins will be allowed.
	// Default value is ["*"]
	AllowedOrigins []string
	// AllowedMethods is a list of methods the client is allowed to use with
	// cross-domain requests.
	AllowedMethods []string
	// AllowedHeaders is list of non simple headers the client is allowed to use with
	// cross-domain requests. Default value is simple methods (GET and POST)
	AllowedHeaders []string
	// ExposedHeaders indicates which headers are safe to expose to the API of a CORS
	// API specification
	ExposedHeaders []string
	// AllowCredentials indicates whether the request can include user credentials like
	// cookies, HTTP authentication or client side SSL certificates.
	AllowCredentials bool
	// MaxAge indicates how long (in seconds) the results of a preflight request
	// can be cached
	MaxAge int
}

type Cors struct {
	// The CORS Options
	options Options
}

// New creates a new Cors handler with the provided options.
func New(options Options) *Cors {
	// Normalize options
	// Note: for origins and methods matching, the spec requires a case-sensitive matching.
	// As it may error prone, we chose to ignore the spec here.
	normOptions := Options{
		AllowedOrigins: convert(options.AllowedOrigins, strings.ToLower),
		AllowedMethods: convert(options.AllowedMethods, strings.ToUpper),
		// Origin is always appended as some browsers will always request
		// for this header at preflight
		AllowedHeaders:   convert(append(options.AllowedHeaders, "Origin"), toHeader),
		ExposedHeaders:   convert(options.ExposedHeaders, toHeader),
		AllowCredentials: options.AllowCredentials,
		MaxAge:           options.MaxAge,
	}
	if len(normOptions.AllowedOrigins) == 0 {
		// Default is all origins
		normOptions.AllowedOrigins = []string{"*"}
	}
	if len(normOptions.AllowedMethods) == 0 {
		// Default is simple methods
		normOptions.AllowedMethods = []string{"GET", "POST"}
	}
	return &Cors{
		options: normOptions,
	}
}

// Default creates a new Cors handler with default options
func Default() *Cors {
	return New(Options{})
}

// Handler apply the CORS specification on the request, and add relevant CORS headers
// as necessary.
func (cors *Cors) Handler(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "OPTIONS" {
			cors.handlePreflight(w, r)
		} else {
			cors.handleActualRequest(w, r)
		}
		h.ServeHTTP(w, r)
	})
}

// Martini compatible handler
func (cors *Cors) HandlerFunc(w http.ResponseWriter, r *http.Request) {
	if r.Method == "OPTIONS" {
		cors.handlePreflight(w, r)
	} else {
		cors.handleActualRequest(w, r)
	}
}

// Negroni compatible interface
func (cors *Cors) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	if r.Method == "OPTIONS" {
		cors.handlePreflight(w, r)
	} else {
		cors.handleActualRequest(w, r)
	}
	next(w, r)
}

// handlePreflight handles pre-flight CORS requests
func (cors *Cors) handlePreflight(w http.ResponseWriter, r *http.Request) {
	options := cors.options
	headers := w.Header()
	origin := r.Header.Get("Origin")
	if r.Method != "OPTIONS" || origin == "" || !cors.isOriginAllowed(origin) {
		return
	}
	reqMethod := r.Header.Get("Access-Control-Request-Method")
	if !cors.isMethodAllowed(reqMethod) {
		return
	}
	reqHeaders := parseHeaderList(r.Header.Get("Access-Control-Request-Headers"))
	if !cors.areHeadersAllowed(reqHeaders) {
		return
	}
	headers.Set("Access-Control-Allow-Origin", origin)
	// Spec says: Since the list of methods can be unbounded, simply returning the method indicated
	// by Access-Control-Request-Method (if supported) can be enough
	headers.Set("Access-Control-Allow-Methods", strings.ToUpper(reqMethod))
	if len(reqHeaders) > 0 {

		// Spec says: Since the list of headers can be unbounded, simply returning supported headers
		// from Access-Control-Request-Headers can be enough
		headers.Set("Access-Control-Allow-Headers", strings.Join(reqHeaders, ", "))
	}
	if options.AllowCredentials {
		headers.Set("Access-Control-Allow-Credentials", "true")
	}
	if options.MaxAge > 0 {
		headers.Set("Access-Control-Max-Age", strconv.Itoa(options.MaxAge))
	}
}

// handleActualRequest handles simple cross-origin requests, actual request or redirects
func (cors *Cors) handleActualRequest(w http.ResponseWriter, r *http.Request) {
	options := cors.options
	headers := w.Header()
	origin := r.Header.Get("Origin")
	if r.Method == "OPTIONS" || origin == "" || !cors.isOriginAllowed(origin) {
		return
	}
	// Note that spec does define a way to specifically disallow a simple method like GET or
	// POST. Access-Control-Allow-Methods is only used for pre-flight requests and the
	// spec doesn't instruct to check the allowed methods for simple cross-origin requests.
	// We think it's a nice feature to be able to have control on those methods though.
	if !cors.isMethodAllowed(r.Method) {
		return
	}
	headers.Set("Access-Control-Allow-Origin", origin)
	if len(options.ExposedHeaders) > 0 {
		headers.Set("Access-Control-Expose-Headers", strings.Join(options.ExposedHeaders, ", "))
	}
	if options.AllowCredentials {
		headers.Set("Access-Control-Allow-Credentials", "true")
	}
}

// isOriginAllowed checks if a given origin is allowed to perform cross-domain requests
// on the endpoint
func (cors *Cors) isOriginAllowed(origin string) bool {
	allowedOrigins := cors.options.AllowedOrigins
	origin = strings.ToLower(origin)
	for _, allowedOrigin := range allowedOrigins {
		switch allowedOrigin {
		case "*":
			return true
		case origin:
			return true
		}
	}
	return false
}

// isMethodAllowed checks if a given method can be used as part of a cross-domain request
// on the endpoing
func (cors *Cors) isMethodAllowed(method string) bool {
	allowedMethods := cors.options.AllowedMethods
	if len(allowedMethods) == 0 {
		// If no method allowed, always return false, even for preflight request
		return false
	}
	method = strings.ToUpper(method)
	if method == "OPTIONS" {
		// Always allow preflight requests
		return true
	}
	for _, allowedMethod := range allowedMethods {
		if allowedMethod == method {
			return true
		}
	}
	return false
}

// areHeadersAllowed checks if a given list of headers are allowed to used within
// a cross-domain request.
func (cors *Cors) areHeadersAllowed(requestedHeaders []string) bool {
	if len(requestedHeaders) == 0 {
		return true
	}
	for _, header := range requestedHeaders {
		found := false
		for _, allowedHeader := range cors.options.AllowedHeaders {
			if header == allowedHeader {
				found = true
				break
			}
		}
		if !found {
			return false
		}
	}
	return true
}
<|endoftext|>


<commit_before>/*

   Copyright 2016 Wenhui Shen <www.webx.top>

   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 echo

import (
	"encoding/gob"
	"fmt"
	"net/http"
)

func init() {
	gob.Register(&RawData{})
	gob.Register(H{})
}

//Status 状态值
type Status struct {
	Text string
	Code int
}

var (
	//States 状态码对应的文本
	States = map[State]*Status{
		-2: {`Non-Privileged`, http.StatusOK},  //无权限
		-1: {`Unauthenticated`, http.StatusOK}, //未登录
		0:  {`Failure`, http.StatusOK},         //操作失败
		1:  {`Success`, http.StatusOK},         //操作成功
	}
	//GetStatus 获取状态值
	GetStatus = func(key State) (*Status, bool) {
		v, y := States[key]
		return v, y
	}
)

//State 状态码类型
type State int

func (s State) String() string {
	if v, y := GetStatus(s); y {
		return v.Text
	}
	return `Undefined`
}

//Int 返回int类型的自定义状态码
func (s State) Int() int {
	return int(s)
}

//HTTPCode 返回HTTP状态码
func (s State) HTTPCode() int {
	if v, y := GetStatus(s); y {
		return v.Code
	}
	return http.StatusOK
}

//Data 响应数据
type Data interface {
	Assign(key string, val interface{})
	Assignx(values *map[string]interface{})
	SetTmplFuncs()
	Render(tmpl string, code ...int) error
	SetContext(ctx Context) Data
	String() string
	Set(code int, args ...interface{}) Data
	Reset() Data
	SetError(err error, args ...int) Data
	SetCode(code int) Data
	SetInfo(info interface{}, args ...int) Data
	SetZone(zone interface{}) Data
	SetData(data interface{}, args ...int) Data
	Gets() (code State, info interface{}, zone interface{}, data interface{})
	GetCode() State
	GetInfo() interface{}
	GetZone() interface{}
	GetData() interface{}
}

type RawData struct {
	context Context
	Code    State
	State   string `json:",omitempty" xml:",omitempty"`
	Info    interface{}
	Zone    interface{} `json:",omitempty" xml:",omitempty"`
	Data    interface{} `json:",omitempty" xml:",omitempty"`
}

func (d *RawData) Error() string {
	return fmt.Sprintf(`%v`, d.Info)
}

func (d *RawData) Reset() Data {
	d.Code = State(0)
	d.State = ``
	d.Info = nil
	d.Zone = nil
	d.Data = nil
	return d
}

func (d *RawData) String() string {
	return fmt.Sprintf(`%v`, d.Info)
}

//Render 通过模板渲染结果
func (d *RawData) Render(tmpl string, code ...int) error {
	return d.context.Render(tmpl, d.Data, code...)
}

//Gets 获取全部数据
func (d *RawData) Gets() (State, interface{}, interface{}, interface{}) {
	return d.Code, d.Info, d.Zone, d.Data
}

func (d *RawData) GetCode() State {
	return d.Code
}

func (d *RawData) GetInfo() interface{} {
	return d.Info
}

func (d *RawData) GetZone() interface{} {
	return d.Zone
}

//GetData 获取数据
func (d *RawData) GetData() interface{} {
	return d.Data
}

//SetError 设置错误
func (d *RawData) SetError(err error, args ...int) Data {
	if err != nil {
		if len(args) > 0 {
			d.SetCode(args[0])
		} else {
			d.SetCode(0)
		}
		d.Info = err.Error()
	} else {
		d.SetCode(1)
	}
	return d
}

//SetCode 设置状态码
func (d *RawData) SetCode(code int) Data {
	d.Code = State(code)
	d.State = d.Code.String()
	return d
}

//SetInfo 设置提示信息
func (d *RawData) SetInfo(info interface{}, args ...int) Data {
	d.Info = info
	if len(args) > 0 {
		d.SetCode(args[0])
	}
	return d
}

//SetZone 设置提示区域
func (d *RawData) SetZone(zone interface{}) Data {
	d.Zone = zone
	return d
}

//SetData 设置正常数据
func (d *RawData) SetData(data interface{}, args ...int) Data {
	d.Data = data
	if len(args) > 0 {
		d.SetCode(args[0])
	} else {
		d.SetCode(1)
	}
	return d
}

//SetContext 设置Context
func (d *RawData) SetContext(ctx Context) Data {
	d.context = ctx
	return d
}

//Assign 赋值
func (d *RawData) Assign(key string, val interface{}) {
	RawData, _ := d.Data.(H)
	if RawData == nil {
		RawData = H{}
	}
	RawData[key] = val
	d.Data = RawData
}

//Assignx 批量赋值
func (d *RawData) Assignx(values *map[string]interface{}) {
	if values == nil {
		return
	}
	RawData, _ := d.Data.(H)
	if RawData == nil {
		RawData = H{}
	}
	for key, val := range *values {
		RawData[key] = val
	}
	d.Data = RawData
}

//SetTmplFuncs 设置模板函数
func (d *RawData) SetTmplFuncs() {
	flash, ok := d.context.Session().Get(`webx:flash`).(*RawData)
	if ok {
		d.context.Session().Delete(`webx:flash`).Save()
		d.context.SetFunc(`Code`, func() State {
			return flash.Code
		})
		d.context.SetFunc(`Info`, func() interface{} {
			return flash.Info
		})
		d.context.SetFunc(`Zone`, func() interface{} {
			return flash.Zone
		})
	} else {
		d.context.SetFunc(`Code`, func() State {
			return d.Code
		})
		d.context.SetFunc(`Info`, func() interface{} {
			return d.Info
		})
		d.context.SetFunc(`Zone`, func() interface{} {
			return d.Zone
		})
	}
}

// Set 设置输出(code,info,zone,RawData)
func (d *RawData) Set(code int, args ...interface{}) Data {
	d.SetCode(code)
	var hasData bool
	switch len(args) {
	case 3:
		d.Data = args[2]
		hasData = true
		fallthrough
	case 2:
		d.Zone = args[1]
		fallthrough
	case 1:
		d.Info = args[0]
		if !hasData {
			flash := &RawData{
				context: d.context,
				Code:    d.Code,
				State:   d.State,
				Info:    d.Info,
				Zone:    d.Zone,
				Data:    nil,
			}
			d.context.Session().Set(`webx:flash`, flash).Save()
		}
	}
	return d
}

func NewData(ctx Context) *RawData {
	c := State(1)
	return &RawData{
		context: ctx,
		Code:    c,
		State:   c.String(),
	}
}

//KV 键值对
type KV struct {
	K string
	V string
}

//NewKVData 键值对数据
func NewKVData() *KVData {
	return &KVData{
		slice: []*KV{},
		index: map[string][]int{},
	}
}

//KVData 键值对数据（保持顺序）
type KVData struct {
	slice []*KV
	index map[string][]int
}

//Slice 返回切片
func (a *KVData) Slice() []*KV {
	return a.slice
}

//Index 返回某个key的所有索引值
func (a *KVData) Index(k string) []int {
	v, _ := a.index[k]
	return v
}

//Indexes 返回所有索引值
func (a *KVData) Indexes() map[string][]int {
	return a.index
}

//Reset 重置
func (a *KVData) Reset() *KVData {
	a.index = map[string][]int{}
	a.slice = []*KV{}
	return a
}

//Add 添加键值
func (a *KVData) Add(k, v string) *KVData {
	if _, y := a.index[k]; !y {
		a.index[k] = []int{}
	}
	a.index[k] = append(a.index[k], len(a.slice))
	a.slice = append(a.slice, &KV{K: k, V: v})
	return a
}

//Set 设置首个键值
func (a *KVData) Set(k, v string) *KVData {
	a.index[k] = []int{0}
	a.slice = []*KV{&KV{K: k, V: v}}
	return a
}

func (a *KVData) Get(k string) string {
	if indexes, ok := a.index[k]; ok {
		if len(indexes) > 0 {
			return a.slice[indexes[0]].V
		}
	}
	return ``
}

func (a *KVData) Has(k string) bool {
	if _, ok := a.index[k]; ok {
		return true
	}
	return false
}

//Delete 设置某个键的所有值
func (a *KVData) Delete(ks ...string) *KVData {
	indexes := []int{}
	for _, k := range ks {
		v, y := a.index[k]
		if !y {
			continue
		}
		for _, key := range v {
			indexes = append(indexes, key)
		}
	}
	newSlice := []*KV{}
	a.index = map[string][]int{}
	for i, v := range a.slice {
		var exists bool
		for _, idx := range indexes {
			if i != idx {
				continue
			}
			exists = true
			break
		}
		if exists {
			continue
		}
		if _, y := a.index[v.K]; !y {
			a.index[v.K] = []int{}
		}
		a.index[v.K] = append(a.index[v.K], len(newSlice))
		newSlice = append(newSlice, v)
	}
	a.slice = newSlice
	return a
}
<commit_msg>update<commit_after>/*

   Copyright 2016 Wenhui Shen <www.webx.top>

   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 echo

import (
	"encoding/gob"
	"fmt"
	"net/http"
)

func init() {
	gob.Register(&RawData{})
	gob.Register(H{})
}

//Status 状态值
type Status struct {
	Text string
	Code int
}

var (
	//States 状态码对应的文本
	States = map[State]*Status{
		-2: {`Non-Privileged`, http.StatusOK},  //无权限
		-1: {`Unauthenticated`, http.StatusOK}, //未登录
		0:  {`Failure`, http.StatusOK},         //操作失败
		1:  {`Success`, http.StatusOK},         //操作成功
	}
	//GetStatus 获取状态值
	GetStatus = func(key State) (*Status, bool) {
		v, y := States[key]
		return v, y
	}
)

//State 状态码类型
type State int

func (s State) String() string {
	if v, y := GetStatus(s); y {
		return v.Text
	}
	return `Undefined`
}

//Int 返回int类型的自定义状态码
func (s State) Int() int {
	return int(s)
}

//HTTPCode 返回HTTP状态码
func (s State) HTTPCode() int {
	if v, y := GetStatus(s); y {
		return v.Code
	}
	return http.StatusOK
}

//Data 响应数据
type Data interface {
	Assign(key string, val interface{})
	Assignx(values *map[string]interface{})
	SetTmplFuncs()
	Render(tmpl string, code ...int) error
	SetContext(ctx Context) Data
	String() string
	Set(code int, args ...interface{}) Data
	Reset() Data
	SetError(err error, args ...int) Data
	SetCode(code int) Data
	SetInfo(info interface{}, args ...int) Data
	SetZone(zone interface{}) Data
	SetData(data interface{}, args ...int) Data
	Gets() (code State, info interface{}, zone interface{}, data interface{})
	GetCode() State
	GetInfo() interface{}
	GetZone() interface{}
	GetData() interface{}
}

type RawData struct {
	context Context
	Code    State
	State   string `json:",omitempty" xml:",omitempty"`
	Info    interface{}
	Zone    interface{} `json:",omitempty" xml:",omitempty"`
	Data    interface{} `json:",omitempty" xml:",omitempty"`
}

func (d *RawData) Error() string {
	return fmt.Sprintf(`%v`, d.Info)
}

func (d *RawData) Reset() Data {
	d.Code = State(0)
	d.State = ``
	d.Info = nil
	d.Zone = nil
	d.Data = nil
	return d
}

func (d *RawData) String() string {
	return fmt.Sprintf(`%v`, d.Info)
}

//Render 通过模板渲染结果
func (d *RawData) Render(tmpl string, code ...int) error {
	return d.context.Render(tmpl, d.Data, code...)
}

//Gets 获取全部数据
func (d *RawData) Gets() (State, interface{}, interface{}, interface{}) {
	return d.Code, d.Info, d.Zone, d.Data
}

func (d *RawData) GetCode() State {
	return d.Code
}

func (d *RawData) GetInfo() interface{} {
	return d.Info
}

func (d *RawData) GetZone() interface{} {
	return d.Zone
}

//GetData 获取数据
func (d *RawData) GetData() interface{} {
	return d.Data
}

//SetError 设置错误
func (d *RawData) SetError(err error, args ...int) Data {
	if err != nil {
		if len(args) > 0 {
			d.SetCode(args[0])
		} else {
			d.SetCode(0)
		}
		d.Info = err.Error()
	} else {
		d.SetCode(1)
	}
	return d
}

//SetCode 设置状态码
func (d *RawData) SetCode(code int) Data {
	d.Code = State(code)
	d.State = d.Code.String()
	return d
}

//SetInfo 设置提示信息
func (d *RawData) SetInfo(info interface{}, args ...int) Data {
	d.Info = info
	if len(args) > 0 {
		d.SetCode(args[0])
	}
	return d
}

//SetZone 设置提示区域
func (d *RawData) SetZone(zone interface{}) Data {
	d.Zone = zone
	return d
}

//SetData 设置正常数据
func (d *RawData) SetData(data interface{}, args ...int) Data {
	d.Data = data
	if len(args) > 0 {
		d.SetCode(args[0])
	} else {
		d.SetCode(1)
	}
	return d
}

//SetContext 设置Context
func (d *RawData) SetContext(ctx Context) Data {
	d.context = ctx
	return d
}

//Assign 赋值
func (d *RawData) Assign(key string, val interface{}) {
	RawData, _ := d.Data.(H)
	if RawData == nil {
		RawData = H{}
	}
	RawData[key] = val
	d.Data = RawData
}

//Assignx 批量赋值
func (d *RawData) Assignx(values *map[string]interface{}) {
	if values == nil {
		return
	}
	RawData, _ := d.Data.(H)
	if RawData == nil {
		RawData = H{}
	}
	for key, val := range *values {
		RawData[key] = val
	}
	d.Data = RawData
}

//SetTmplFuncs 设置模板函数
func (d *RawData) SetTmplFuncs() {
	flash, ok := d.context.Session().Get(`webx:flash`).(*RawData)
	if ok {
		d.context.Session().Delete(`webx:flash`).Save()
		d.context.SetFunc(`Code`, func() State {
			return flash.Code
		})
		d.context.SetFunc(`Info`, func() interface{} {
			return flash.Info
		})
		d.context.SetFunc(`Zone`, func() interface{} {
			return flash.Zone
		})
	} else {
		d.context.SetFunc(`Code`, func() State {
			return d.Code
		})
		d.context.SetFunc(`Info`, func() interface{} {
			return d.Info
		})
		d.context.SetFunc(`Zone`, func() interface{} {
			return d.Zone
		})
	}
}

// Set 设置输出(code,info,zone,RawData)
func (d *RawData) Set(code int, args ...interface{}) Data {
	d.SetCode(code)
	var hasData bool
	switch len(args) {
	case 3:
		d.Data = args[2]
		hasData = true
		fallthrough
	case 2:
		d.Zone = args[1]
		fallthrough
	case 1:
		d.Info = args[0]
		if !hasData {
			flash := &RawData{
				context: d.context,
				Code:    d.Code,
				State:   d.State,
				Info:    d.Info,
				Zone:    d.Zone,
				Data:    nil,
			}
			d.context.Session().Set(`webx:flash`, flash).Save()
		}
	}
	return d
}

func NewData(ctx Context) *RawData {
	c := State(1)
	return &RawData{
		context: ctx,
		Code:    c,
		State:   c.String(),
	}
}

//KV 键值对
type KV struct {
	K string
	V string
}

type KVList []*KV

func (list KVList) Add(k, v string) {
	list = append(list, &KV{K: k, V: v})
}

func (list KVList) Del(i int) {
	if i+1 < len(list) {
		list = append(list[0:i], list[i+1:]...)
	} else if i < len(list) {
		list = list[0:i]
	}
}

func (list KVList) Reset() {
	list = list[0:0]
}

//NewKVData 键值对数据
func NewKVData() *KVData {
	return &KVData{
		slice: []*KV{},
		index: map[string][]int{},
	}
}

//KVData 键值对数据（保持顺序）
type KVData struct {
	slice []*KV
	index map[string][]int
}

//Slice 返回切片
func (a *KVData) Slice() []*KV {
	return a.slice
}

//Index 返回某个key的所有索引值
func (a *KVData) Index(k string) []int {
	v, _ := a.index[k]
	return v
}

//Indexes 返回所有索引值
func (a *KVData) Indexes() map[string][]int {
	return a.index
}

//Reset 重置
func (a *KVData) Reset() *KVData {
	a.index = map[string][]int{}
	a.slice = []*KV{}
	return a
}

//Add 添加键值
func (a *KVData) Add(k, v string) *KVData {
	if _, y := a.index[k]; !y {
		a.index[k] = []int{}
	}
	a.index[k] = append(a.index[k], len(a.slice))
	a.slice = append(a.slice, &KV{K: k, V: v})
	return a
}

//Set 设置首个键值
func (a *KVData) Set(k, v string) *KVData {
	a.index[k] = []int{0}
	a.slice = []*KV{&KV{K: k, V: v}}
	return a
}

func (a *KVData) Get(k string) string {
	if indexes, ok := a.index[k]; ok {
		if len(indexes) > 0 {
			return a.slice[indexes[0]].V
		}
	}
	return ``
}

func (a *KVData) Has(k string) bool {
	if _, ok := a.index[k]; ok {
		return true
	}
	return false
}

//Delete 设置某个键的所有值
func (a *KVData) Delete(ks ...string) *KVData {
	indexes := []int{}
	for _, k := range ks {
		v, y := a.index[k]
		if !y {
			continue
		}
		for _, key := range v {
			indexes = append(indexes, key)
		}
	}
	newSlice := []*KV{}
	a.index = map[string][]int{}
	for i, v := range a.slice {
		var exists bool
		for _, idx := range indexes {
			if i != idx {
				continue
			}
			exists = true
			break
		}
		if exists {
			continue
		}
		if _, y := a.index[v.K]; !y {
			a.index[v.K] = []int{}
		}
		a.index[v.K] = append(a.index[v.K], len(newSlice))
		newSlice = append(newSlice, v)
	}
	a.slice = newSlice
	return a
}
<|endoftext|>


<commit_before>/*
   Copyright 2015 Tom Cameron

   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 main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

type Present struct {
	Length, Width, Height int
}

func (p *Present) surfaceArea() int {
	// Surface area of a rectangular cuboid is the sum of the area of its sides.
	// 2*l*w + 2*w*h + 2*h*l
	return (2 * p.Length * p.Width) + (2 * p.Width * p.Height) + (2 * p.Height * p.Length)
}

func (p *Present) slackPaper() int {
	// Slack paper is the area of the smallest side of the present
	top := p.Length * p.Width
	side := p.Length * p.Height
	front := p.Width * p.Height

	switch {
	case top <= front && top <= side:
		// Top is smallest area
		return top
	case front <= top && front <= side:
		return front
	default:
		return side
	}
}

func (p *Present) totalPaper() int {
	return p.surfaceArea() + p.slackPaper()
}

func parsePresents(path string) (*[]Present, error) {
	var presents []Present
	var present Present // Move this up here to prevent extra garbage collection

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

	scanner := bufio.NewScanner(f)
	for scanner.Scan() {
		present.Length, present.Width, present.Height = 0, 0, 0
		line := strings.Split(scanner.Text(), "x")

		// Parse each size from the split text line, convert to an int
		if i, err := strconv.Atoi(line[0]); err != nil {
			return nil, err
		} else {
			present.Length = i
		}
		if i, err := strconv.Atoi(line[1]); err != nil {
			return nil, err
		} else {
			present.Width = i
		}
		if i, err := strconv.Atoi(line[2]); err != nil {
			return nil, err
		} else {
			present.Height = i
		}
		presents = append(presents, present)
	}
	if err := scanner.Err(); err != nil {
		return nil, err
	}

	return &presents, nil
}

func main() {
	var totalArea int

	presents, err := parsePresents("day2.data")
	if err != nil {
		fmt.Printf("Error reading present sizes.\n%s", err)
	}

	for _, p := range *presents {
		totalArea += p.totalPaper()
	}
	fmt.Printf("Total Area: %d sq. ft.\n", totalArea)
}
<commit_msg>Extend to include ribbon, simplify lots of code<commit_after>/*
   Copyright 2015 Tom Cameron

   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 main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
	"strconv"
	"strings"
)

type Present struct {
	Length, Width, Height int
}

func (p *Present) minSide() []int {
	sides := []int{p.Length, p.Width, p.Height}
	sort.Ints(sides)
	return sides[0:2]
}

func (p *Present) surfaceArea() int {
	// Surface area of a rectangular cuboid is the sum of the area of its sides.
	// 2*l*w + 2*w*h + 2*h*l
	return (2 * p.Length * p.Width) +
		(2 * p.Width * p.Height) +
		(2 * p.Height * p.Length)
}

func (p *Present) slackPaper() int {
	// Slack paper is the area of the smallest side of the present
	return product(p.minSide())
}

func (p *Present) ribbonLength() int {
	// Ribbon required is the sum of the sides of the smallest face plus
	// the volume of the present.
	return (2 * sum(p.minSide())) + (p.Length * p.Width * p.Height)
}

func (p *Present) paperArea() int {
	return p.surfaceArea() + p.slackPaper()
}

func sum(i []int) int {
	var total int

	for _, v := range i {
		total += v
	}
	return total
}

func product(i []int) int {
	var total int

	for _, v := range i {
		if total == 0 {
			total = v
		} else {
			total *= v
		}
	}
	return total
}

func parsePresents(path string) (*[]Present, error) {
	var presents []Present
	var present Present // Prevent unnecessary garbage collection

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

	scanner := bufio.NewScanner(f)
	for scanner.Scan() {
		present.Length, present.Width, present.Height = 0, 0, 0
		line := strings.Split(scanner.Text(), "x")

		// Parse each size from the split text line, convert to an int
		if i, err := strconv.Atoi(line[0]); err != nil {
			return nil, err
		} else {
			present.Length = i
		}
		if i, err := strconv.Atoi(line[1]); err != nil {
			return nil, err
		} else {
			present.Width = i
		}
		if i, err := strconv.Atoi(line[2]); err != nil {
			return nil, err
		} else {
			present.Height = i
		}
		presents = append(presents, present)
	}
	if err := scanner.Err(); err != nil {
		return nil, err
	}

	return &presents, nil
}

func main() {
	var totalArea int
	var ribbonLength int

	presents, err := parsePresents("day2.data")
	if err != nil {
		fmt.Printf("Error reading present sizes.\n%s", err)
	}

	for _, p := range *presents {
		totalArea += p.paperArea()
		ribbonLength += p.ribbonLength()
	}
	fmt.Printf("Total Area: %d sq. ft.\nRibbon Length: %d\n", totalArea, ribbonLength)
}
<|endoftext|>


<commit_before>package parser

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"strings"
	"sync"
	"testing"
)

// Simple test of lexical coherence.
// `TestListen` produces set of updates from the file and for each such
// update tests lexical equality with corresponding line of the source.
// By nature `TestListen` cannot be used as exhaustive parser test, but it's an
// important part of global testing.

func TestListen(t *testing.T) {
	r, err := os.Open("monitor")
	if err != nil {
		t.Fatal("os.Open:\n", err)
	}
	s := NewScanner(r)
	bd := NewBabelDesc()
	updChan := make(chan BabelUpdate)
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		err = bd.Listen(s, updChan)
		wg.Done()
		close(updChan)
	}()
	r2, err := os.Open("monitor")
	if err != nil {
		t.Fatal("os.Open:\n", err)
	}
	reader := bufio.NewReader(r2)
	fieldStringHook := make(map[string](func(interface{}) string))
	fieldStringHook["neighbour_reach"] = func(v interface{}) string {
		return fmt.Sprintf("%04x", v)
	}
	fieldStringHook["route_installed"] = func(v interface{}) string {
		if b := v.(bool); b {
			return "yes"
		}
		return "no"
	}
	for upd := range updChan {
		upd.lequal(reader, t, fieldStringHook)
		if testing.Verbose() {
			fmt.Print(upd)
		}
	}
	wg.Wait()
	if err != nil {
		t.Fatal("parser.Listen:\n", err)
	}
}

// Lexical comparison of the given update with next valid line from `reader`.
// `fieldStringHook` associates entry field with 'toString-like' function.
// `lequal` uses `nextWord`, which must be tested separately.
// `lequal` is ugly and slow, but really simple
// (otherwise we need to test our test)

func (upd BabelUpdate) lequal(reader *bufio.Reader, t *testing.T,
	fieldStringHook map[string](func(interface{}) string)) {
	for {
		nextLine, err := reader.ReadString('\n')
		if err != nil {
			t.Fatal(err)
		}
		r := strings.NewReader(nextLine)
		s := NewScanner(r)
		w, err := nextWord(s)
		if err != nil && err != io.EOF && err != errEOL {
			t.Fatal("parser.nextWord:\n", err)
		}
		if err == io.EOF || err == errEOL {
			return
		}
		line := w

		// In general, it's not an error,
		// but if it is, we need to be sure to track it.
		if w != string(upd.action) {
			fmt.Println("Warning: unknown action '" + w +
				"' (skip rest of the line)")
			for {
				w, err = nextWord(s)
				if err != nil && err != io.EOF &&
					err != errEOL {
					t.Fatal("parser.nextWord:\n", err)
				}
				if err == io.EOF || err == errEOL {
					if testing.Verbose() {
						fmt.Println(line)
					}
					break
				}
				line += (" " + w)
			}
			continue
		}
		checkNextWord := func(given string) {
			w, err = nextWord(s)
			if err != nil && err != io.EOF && err != errEOL {
				t.Fatal("parser.nextWord:\n", err)
			}
			if err == io.EOF || err == errEOL {
				if testing.Verbose() {
					fmt.Println(line)
				}
				return
			}
			line += (" " + w)
			if w != given {
				t.Fatal("In the line: ", line,
					"...\n\texpected: ", w,
					"\n\tgiven: ", given)
			}
		}
		checkNextWord(string(upd.tableId))
		checkNextWord(string(upd.entryId))
		for {
			w, err = nextWord(s)
			if err != nil && err != io.EOF && err != errEOL {
				t.Fatal("parser.nextWord:\n", err)
			}
			if err == io.EOF || err == errEOL {
				if testing.Verbose() {
					fmt.Println(line)
				}
				return
			}
			value, exists := upd.entry[Id(w)]
			if !exists {
				t.Fatal("No such field: " + w +
					"\n" + upd.entry.String())
			}
			line += (" " + w)
			w2, err := nextWord(s)
			if err != nil && err != io.EOF && err != errEOL {
				t.Fatal("parser.nextWord:\n", err)
			}
			if err == io.EOF || err == errEOL {
				if testing.Verbose() {
					fmt.Println(line)
				}
				return
			}
			line += (" " + w2)
			hook, exists := fieldStringHook[string(upd.tableId)+
				"_"+w]
			var given string
			if exists {
				given = hook(value.data)
			} else {
				given = fmt.Sprint(value.data)
			}
			if given != w2 {
				t.Fatal("In the line: ", line,
					"...\nexpected: ", w2,
					"\ngiven: ", given)
			}
		}
	}
}

func TestNextWord(t *testing.T) {
	input := "  Lorem ipsum dolor sit amet. Neighbour   55c47b990d90 " +
		"172.28.175.26/32-::/0\n" +
		"\"Now I have a machine gun. Ho-ho-ho.\"" + " \"\" " +
		"\"Who You Gonna Call?\nGhostbusters!\"" +
		" \"I have a bad feeling about t\"h\"is\" " +
		"\"Well, I called me wife and I said to her:\"" +
		"\"\\\"Will you kindly tell to me\n" +
		"Who owns that head upon the bed " +
		"where my old head should be?\\\"\"" +
		"\n\\\"A\" Spoonful of \"\"Sugar\"\\\""
	expect := []struct {
		word string
		err  error
	}{
		{"Lorem", nil},
		{"ipsum", nil},
		{"dolor", nil},
		{"sit", nil},
		{"amet.", nil},
		{"Neighbour", nil},
		{"55c47b990d90", nil},
		{"172.28.175.26/32-::/0", nil},
		{"", errEOL},
		{"Now I have a machine gun. Ho-ho-ho.", nil},
		{"", nil},
		{"Who You Gonna Call?\nGhostbusters!", nil},
		{"I have a bad feeling about this", nil},
		{"Well, I called me wife and I said to her:" +
			"\"Will you kindly tell to me\n" +
			"Who owns that head upon the bed " +
			"where my old head should be?\"", nil},
		{"", errEOL},
		{"\"A Spoonful of Sugar\"", nil},
		{"", io.EOF},
		{"", io.EOF},
	}
	r := strings.NewReader(input)
	s := NewScanner(r)
	for _, e := range expect {
		word, err := nextWord(s)
		if word != e.word || err != e.err {
			t.Errorf("nextWord:\nexpected: (%v, %v)\ngot: "+
				"(%v, %v)", e.word, e.err, word, err)
		}
	}
}
<commit_msg>Fix parser test (in a terrifically silly way).<commit_after>package parser

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"strings"
	"sync"
	"testing"
)

// Simple test of lexical coherence.
// `TestListen` produces set of updates from the file and for each such
// update tests lexical equality with corresponding line of the source.
// By nature `TestListen` cannot be used as exhaustive parser test, but it's an
// important part of global testing.

func TestListen(t *testing.T) {
	r, err := os.Open("monitor")
	if err != nil {
		t.Fatal("os.Open:\n", err)
	}
	s := NewScanner(r)
	bd := NewBabelDesc()
	updChan := make(chan BabelUpdate)
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		err = Listen(bd, s, updChan)
		wg.Done()
		close(updChan)
	}()
	r2, err := os.Open("monitor")
	if err != nil {
		t.Fatal("os.Open:\n", err)
	}
	reader := bufio.NewReader(r2)
	fieldStringHook := make(map[string](func(interface{}) string))
	fieldStringHook["neighbour_reach"] = func(v interface{}) string {
		return fmt.Sprintf("%04x", v)
	}
	fieldStringHook["route_installed"] = func(v interface{}) string {
		if b := v.(bool); b {
			return "yes"
		}
		return "no"
	}
	for upd := range updChan {
		upd.lequal(reader, t, fieldStringHook)
		if testing.Verbose() {
			fmt.Print(upd)
		}
	}
	wg.Wait()
	if err != nil {
		t.Fatal("parser.Listen:\n", err)
	}
}

// Lexical comparison of the given update with next valid line from `reader`.
// `fieldStringHook` associates entry field with 'toString-like' function.
// `lequal` uses `nextWord`, which must be tested separately.
// `lequal` is ugly and slow, but really simple
// (otherwise we need to test our test)

func (upd BabelUpdate) lequal(reader *bufio.Reader, t *testing.T,
	fieldStringHook map[string](func(interface{}) string)) {
	for {
		nextLine, err := reader.ReadString('\n')
		if err != nil {
			t.Fatal(err)
		}
		r := strings.NewReader(nextLine)
		s := NewScanner(r)
		w, err := nextWord(s)
		if err != nil && err != io.EOF && err != errEOL {
			t.Fatal("parser.nextWord:\n", err)
		}
		if err == io.EOF || err == errEOL {
			return
		}
		line := w

		// In general, it's not an error,
		// but if it is, we need to be sure to track it.
		if w != string(upd.action) {
			fmt.Println("Warning: unknown action '" + w +
				"' (skip rest of the line)")
			for {
				w, err = nextWord(s)
				if err != nil && err != io.EOF &&
					err != errEOL {
					t.Fatal("parser.nextWord:\n", err)
				}
				if err == io.EOF || err == errEOL {
					if testing.Verbose() {
						fmt.Println(line)
					}
					break
				}
				line += (" " + w)
			}
			continue
		}
		checkNextWord := func(given string) {
			w, err = nextWord(s)
			if err != nil && err != io.EOF && err != errEOL {
				t.Fatal("parser.nextWord:\n", err)
			}
			if err == io.EOF || err == errEOL {
				if testing.Verbose() {
					fmt.Println(line)
				}
				return
			}
			line += (" " + w)
			if w != given {
				t.Fatal("In the line: ", line,
					"...\n\texpected: ", w,
					"\n\tgiven: ", given)
			}
		}
		checkNextWord(string(upd.tableId))
		checkNextWord(string(upd.entryId))
		for {
			w, err = nextWord(s)
			if err != nil && err != io.EOF && err != errEOL {
				t.Fatal("parser.nextWord:\n", err)
			}
			if err == io.EOF || err == errEOL {
				if testing.Verbose() {
					fmt.Println(line)
				}
				return
			}
			value, exists := upd.entry[Id(w)]
			if !exists {
				t.Fatal("No such field: " + w +
					"\n" + upd.entry.String())
			}
			line += (" " + w)
			w2, err := nextWord(s)
			if err != nil && err != io.EOF && err != errEOL {
				t.Fatal("parser.nextWord:\n", err)
			}
			if err == io.EOF || err == errEOL {
				if testing.Verbose() {
					fmt.Println(line)
				}
				return
			}
			line += (" " + w2)
			hook, exists := fieldStringHook[string(upd.tableId)+
				"_"+w]
			var given string
			if exists {
				given = hook(value.data)
			} else {
				given = fmt.Sprint(value.data)
			}
			if given != w2 {
				t.Fatal("In the line: ", line,
					"...\nexpected: ", w2,
					"\ngiven: ", given)
			}
		}
	}
}

func TestNextWord(t *testing.T) {
	input := "  Lorem ipsum dolor sit amet. Neighbour   55c47b990d90 " +
		"172.28.175.26/32-::/0\n" +
		"\"Now I have a machine gun. Ho-ho-ho.\"" + " \"\" " +
		"\"Who You Gonna Call?\nGhostbusters!\"" +
		" \"I have a bad feeling about t\"h\"is\" " +
		"\"Well, I called me wife and I said to her:\"" +
		"\"\\\"Will you kindly tell to me\n" +
		"Who owns that head upon the bed " +
		"where my old head should be?\\\"\"" +
		"\n\\\"A\" Spoonful of \"\"Sugar\"\\\""
	expect := []struct {
		word string
		err  error
	}{
		{"Lorem", nil},
		{"ipsum", nil},
		{"dolor", nil},
		{"sit", nil},
		{"amet.", nil},
		{"Neighbour", nil},
		{"55c47b990d90", nil},
		{"172.28.175.26/32-::/0", nil},
		{"", errEOL},
		{"Now I have a machine gun. Ho-ho-ho.", nil},
		{"", nil},
		{"Who You Gonna Call?\nGhostbusters!", nil},
		{"I have a bad feeling about this", nil},
		{"Well, I called me wife and I said to her:" +
			"\"Will you kindly tell to me\n" +
			"Who owns that head upon the bed " +
			"where my old head should be?\"", nil},
		{"", errEOL},
		{"\"A Spoonful of Sugar\"", nil},
		{"", io.EOF},
		{"", io.EOF},
	}
	r := strings.NewReader(input)
	s := NewScanner(r)
	for _, e := range expect {
		word, err := nextWord(s)
		if word != e.word || err != e.err {
			t.Errorf("nextWord:\nexpected: (%v, %v)\ngot: "+
				"(%v, %v)", e.word, e.err, word, err)
		}
	}
}

func Listen(bd *BabelDesc, s *Scanner, updChan chan BabelUpdate) error {
	for {
		upd, err := bd.ParseAction(s)
		if err != nil && err != io.EOF && err != errEOL {
			return err
		}
		if err == io.EOF {
			break
		}
		if upd.action != emptyUpdate.action {
			updChan <- upd
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package resources

import (
	"fmt"

	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/sns"
)

func init() {
	register("SNSTopic", ListSNSTopics)
}

func ListSNSTopics(sess *session.Session) ([]Resource, error) {
	svc := sns.New(sess)

	resp, err := svc.ListTopics(nil)
	if err != nil {
		return nil, err
	}
	resources := make([]Resource, 0)
	for _, topic := range resp.Topics {
		resources = append(resources, &SNSTopic{
			svc: svc,
			id:  topic.TopicArn,
		})
	}
	return resources, nil
}

type SNSTopic struct {
	svc *sns.SNS
	id  *string
}

func (topic *SNSTopic) Remove() error {
	_, err := topic.svc.DeleteTopic(&sns.DeleteTopicInput{
		TopicArn: topic.id,
	})
	return err
}

func (topic *SNSTopic) String() string {
	return fmt.Sprintf("TopicARN: %s", *topic.id)
}
<commit_msg>updte SNS with properties and pages (#592)<commit_after>package resources

import (
	"fmt"

	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/sns"
	"github.com/rebuy-de/aws-nuke/pkg/types"
)

type SNSTopic struct {
	svc  *sns.SNS
	id   *string
	tags []*sns.Tag
}

func init() {
	register("SNSTopic", ListSNSTopics)
}

func ListSNSTopics(sess *session.Session) ([]Resource, error) {
	svc := sns.New(sess)

	topics := make([]*sns.Topic, 0)

	params := &sns.ListTopicsInput{}

	err := svc.ListTopicsPages(params, func(page *sns.ListTopicsOutput, lastPage bool) bool {
		for _, out := range page.Topics {
			topics = append(topics, out)
		}
		return true
	})
	if err != nil {
		return nil, err
	}
	resources := make([]Resource, 0)
	for _, topic := range topics {
		tags, err := svc.ListTagsForResource(&sns.ListTagsForResourceInput{
			ResourceArn: topic.TopicArn,
		})

		if err != nil {
			continue
		}

		resources = append(resources, &SNSTopic{
			svc:  svc,
			id:   topic.TopicArn,
			tags: tags.Tags,
		})
	}
	return resources, nil
}

func (topic *SNSTopic) Remove() error {
	_, err := topic.svc.DeleteTopic(&sns.DeleteTopicInput{
		TopicArn: topic.id,
	})
	return err
}

func (topic *SNSTopic) Properties() types.Properties {
	properties := types.NewProperties()

	for _, tag := range topic.tags {
		properties.SetTag(tag.Key, tag.Value)
	}
	properties.Set("TopicARN", topic.id)

	return properties
}

func (topic *SNSTopic) String() string {
	return fmt.Sprintf("TopicARN: %s", *topic.id)
}
<|endoftext|>


<commit_before>package admin

import (
	"fmt"
	"time"

	"github.com/qor/worker"
)

func getWorker() *worker.Worker {
	Worker := worker.New()

	type sendNewsletterArgument struct {
		Subject      string
		Content      string `sql:"size:65532"`
		SendPassword string
	}

	Worker.RegisterJob(worker.Job{
		Name: "send_newsletter",
		Handler: func(argument interface{}, qorJob worker.QorJobInterface) error {
			qorJob.AddLog("Started sending newsletters...")
			qorJob.AddLog(fmt.Sprintf("Argument: %+v", argument.(*sendNewsletterArgument)))
			for i := 1; i <= 100; i++ {
				time.Sleep(100 * time.Millisecond)
				qorJob.AddLog(fmt.Sprintf("Sending newsletter %v...", i))
				qorJob.SetProgress(uint(i))
			}
			qorJob.AddLog("Finished send newsletters")
			return nil
		},
		Resource: Admin.NewResource(&sendNewsletterArgument{}),
	})

	Worker.RegisterJob(worker.Job{
		Name: "export_products",
		Handler: func(argument interface{}, qorJob worker.QorJobInterface) error {
			fmt.Println("exporting products...")
			time.Sleep(5 * time.Second)
			return nil
		},
	})
	return Worker
}
<commit_msg>Add upload file for import products<commit_after>package admin

import (
	"fmt"
	"time"

	"github.com/qor/qor/media_library"
	"github.com/qor/worker"
)

func getWorker() *worker.Worker {
	Worker := worker.New()

	type sendNewsletterArgument struct {
		Subject      string
		Content      string `sql:"size:65532"`
		SendPassword string
	}

	Worker.RegisterJob(worker.Job{
		Name: "send_newsletter",
		Handler: func(argument interface{}, qorJob worker.QorJobInterface) error {
			qorJob.AddLog("Started sending newsletters...")
			qorJob.AddLog(fmt.Sprintf("Argument: %+v", argument.(*sendNewsletterArgument)))
			for i := 1; i <= 100; i++ {
				time.Sleep(100 * time.Millisecond)
				qorJob.AddLog(fmt.Sprintf("Sending newsletter %v...", i))
				qorJob.SetProgress(uint(i))
			}
			qorJob.AddLog("Finished send newsletters")
			return nil
		},
		Resource: Admin.NewResource(&sendNewsletterArgument{}),
	})

	Worker.RegisterJob(worker.Job{
		Name: "export_products",
		Handler: func(argument interface{}, qorJob worker.QorJobInterface) error {
			fmt.Println("exporting products...")
			time.Sleep(5 * time.Second)
			return nil
		},
	})

	type importProductArgument struct {
		File media_library.FileSystem
	}

	Worker.RegisterJob(worker.Job{
		Name: "import_products",
		Handler: func(argument interface{}, qorJob worker.QorJobInterface) error {
			fmt.Println("importing products...")
			return nil
		},
		Resource: Admin.NewResource(&importProductArgument{}),
	})
	return Worker
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"testing"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
	"github.com/mitchellh/goamz/rds"
)

func TestAccAWSDBSecurityGroup(t *testing.T) {
	var v rds.DBSecurityGroup

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAWSDBSecurityGroupDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccAWSDBSecurityGroupConfig,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSDBSecurityGroupExists("aws_db_security_group.bar", &v),
					testAccCheckAWSDBSecurityGroupAttributes(&v),
					resource.TestCheckResourceAttr(
						"aws_db_security_group.bar", "name", "secgroup-terraform"),
					resource.TestCheckResourceAttr(
						"aws_db_security_group.bar", "description", "just cuz"),
					resource.TestCheckResourceAttr(
						"aws_db_security_group.bar", "ingress.0.cidr", "10.0.0.1/24"),
					resource.TestCheckResourceAttr(
						"aws_db_security_group.bar", "ingress.#", "1"),
				),
			},
		},
	})
}

func testAccCheckAWSDBSecurityGroupDestroy(s *terraform.State) error {
	conn := testAccProvider.Meta().(*AWSClient).rdsconn

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "aws_db_security_group" {
			continue
		}

		// Try to find the Group
		resp, err := conn.DescribeDBSecurityGroups(
			&rds.DescribeDBSecurityGroups{
				DBSecurityGroupName: rs.Primary.ID,
			})

		if err == nil {
			if len(resp.DBSecurityGroups) != 0 &&
				resp.DBSecurityGroups[0].Name == rs.Primary.ID {
				return fmt.Errorf("DB Security Group still exists")
			}
		}

		// Verify the error
		newerr, ok := err.(*rds.Error)
		if !ok {
			return err
		}
		if newerr.Code != "InvalidDBSecurityGroup.NotFound" {
			return err
		}
	}

	return nil
}

func testAccCheckAWSDBSecurityGroupAttributes(group *rds.DBSecurityGroup) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		if len(group.CidrIps) == 0 {
			return fmt.Errorf("no cidr: %#v", group.CidrIps)
		}

		if group.CidrIps[0] != "10.0.0.1/24" {
			return fmt.Errorf("bad cidr: %#v", group.CidrIps)
		}

		if group.CidrStatuses[0] != "authorized" {
			return fmt.Errorf("bad status: %#v", group.CidrStatuses)
		}

		if group.Name != "secgroup-terraform" {
			return fmt.Errorf("bad name: %#v", group.Name)
		}

		if group.Description != "just cuz" {
			return fmt.Errorf("bad description: %#v", group.Description)
		}

		return nil
	}
}

func testAccCheckAWSDBSecurityGroupExists(n string, v *rds.DBSecurityGroup) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[n]
		if !ok {
			return fmt.Errorf("Not found: %s", n)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No DB Security Group ID is set")
		}

		conn := testAccProvider.Meta().(*AWSClient).rdsconn

		opts := rds.DescribeDBSecurityGroups{
			DBSecurityGroupName: rs.Primary.ID,
		}

		resp, err := conn.DescribeDBSecurityGroups(&opts)

		if err != nil {
			return err
		}

		if len(resp.DBSecurityGroups) != 1 ||
			resp.DBSecurityGroups[0].Name != rs.Primary.ID {
			return fmt.Errorf("DB Security Group not found")
		}

		*v = resp.DBSecurityGroups[0]

		return nil
	}
}

const testAccAWSDBSecurityGroupConfig = `
resource "aws_db_security_group" "bar" {
    name = "secgroup-terraform"
    description = "just cuz"

    ingress {
        cidr = "10.0.0.1/24"
    }
}
`
<commit_msg>Update ingress signature<commit_after>package aws

import (
	"fmt"
	"testing"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
	"github.com/mitchellh/goamz/rds"
)

func TestAccAWSDBSecurityGroup(t *testing.T) {
	var v rds.DBSecurityGroup

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAWSDBSecurityGroupDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccAWSDBSecurityGroupConfig,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSDBSecurityGroupExists("aws_db_security_group.bar", &v),
					testAccCheckAWSDBSecurityGroupAttributes(&v),
					resource.TestCheckResourceAttr(
						"aws_db_security_group.bar", "name", "secgroup-terraform"),
					resource.TestCheckResourceAttr(
						"aws_db_security_group.bar", "description", "just cuz"),
					resource.TestCheckResourceAttr(
                                                "aws_db_security_group.bar", "ingress.3363517775.cidr", "10.0.0.1/24"),
					resource.TestCheckResourceAttr(
						"aws_db_security_group.bar", "ingress.#", "1"),
				),
			},
		},
	})
}

func testAccCheckAWSDBSecurityGroupDestroy(s *terraform.State) error {
	conn := testAccProvider.Meta().(*AWSClient).rdsconn

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "aws_db_security_group" {
			continue
		}

		// Try to find the Group
		resp, err := conn.DescribeDBSecurityGroups(
			&rds.DescribeDBSecurityGroups{
				DBSecurityGroupName: rs.Primary.ID,
			})

		if err == nil {
			if len(resp.DBSecurityGroups) != 0 &&
				resp.DBSecurityGroups[0].Name == rs.Primary.ID {
				return fmt.Errorf("DB Security Group still exists")
			}
		}

		// Verify the error
		newerr, ok := err.(*rds.Error)
		if !ok {
			return err
		}
		if newerr.Code != "InvalidDBSecurityGroup.NotFound" {
			return err
		}
	}

	return nil
}

func testAccCheckAWSDBSecurityGroupAttributes(group *rds.DBSecurityGroup) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		if len(group.CidrIps) == 0 {
			return fmt.Errorf("no cidr: %#v", group.CidrIps)
		}

		if group.CidrIps[0] != "10.0.0.1/24" {
			return fmt.Errorf("bad cidr: %#v", group.CidrIps)
		}

		if group.CidrStatuses[0] != "authorized" {
			return fmt.Errorf("bad status: %#v", group.CidrStatuses)
		}

		if group.Name != "secgroup-terraform" {
			return fmt.Errorf("bad name: %#v", group.Name)
		}

		if group.Description != "just cuz" {
			return fmt.Errorf("bad description: %#v", group.Description)
		}

		return nil
	}
}

func testAccCheckAWSDBSecurityGroupExists(n string, v *rds.DBSecurityGroup) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[n]
		if !ok {
			return fmt.Errorf("Not found: %s", n)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No DB Security Group ID is set")
		}

		conn := testAccProvider.Meta().(*AWSClient).rdsconn

		opts := rds.DescribeDBSecurityGroups{
			DBSecurityGroupName: rs.Primary.ID,
		}

		resp, err := conn.DescribeDBSecurityGroups(&opts)

		if err != nil {
			return err
		}

		if len(resp.DBSecurityGroups) != 1 ||
			resp.DBSecurityGroups[0].Name != rs.Primary.ID {
			return fmt.Errorf("DB Security Group not found")
		}

		*v = resp.DBSecurityGroups[0]

		return nil
	}
}

const testAccAWSDBSecurityGroupConfig = `
resource "aws_db_security_group" "bar" {
    name = "secgroup-terraform"
    description = "just cuz"

    ingress {
        cidr = "10.0.0.1/24"
    }
}
`
<|endoftext|>


<commit_before>package agent

import "runtime"

// You can overridden buildVersion at compile time by using:
//
//  go run -ldflags "-X github.com/buildkite/agent/agent.buildVersion abc" *.go --version
//
// On CI, the binaries are always build with the buildVersion variable set.

var baseVersion string = "3.13.0"
var buildVersion string = ""

func Version() string {
	return baseVersion
}

func BuildVersion() string {
	if buildVersion != "" {
		return buildVersion
	} else {
		return "x"
	}
}

func UserAgent() string {
	return "buildkite-agent/" + Version() + "." + BuildVersion() + " (" + runtime.GOOS + "; " + runtime.GOARCH + ")"
}
<commit_msg>Bump version and CHANGELOG for v3.13.1<commit_after>package agent

import "runtime"

// You can overridden buildVersion at compile time by using:
//
//  go run -ldflags "-X github.com/buildkite/agent/agent.buildVersion abc" *.go --version
//
// On CI, the binaries are always build with the buildVersion variable set.

var baseVersion string = "3.13.1"
var buildVersion string = ""

func Version() string {
	return baseVersion
}

func BuildVersion() string {
	if buildVersion != "" {
		return buildVersion
	} else {
		return "x"
	}
}

func UserAgent() string {
	return "buildkite-agent/" + Version() + "." + BuildVersion() + " (" + runtime.GOOS + "; " + runtime.GOARCH + ")"
}
<|endoftext|>


<commit_before>package scanner

import (
	"reflect"
	"strings"
	"testing"

	"github.com/aybabtme/streamql/lang/token"
)

func TestParseInlineString(t *testing.T) {
	tests := []struct {
		name    string
		input   string
		want    string
		wantErr bool
	}{
		{
			name:  "inline string",
			input: `hello`,
			want:  "hello",
		},
		{
			name:  "inline string that contains escaped whitespace",
			input: `hello\ \ \ \ `,
			want:  "hello    ",
		},
		{
			name: "inline string of escaped characters",
			input: `\\\.\ \|\:\,\[\]\	\` + "\n",
			want: `\. |:,[]` + "\t\n",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {

			sc := NewScanner(strings.NewReader(tt.input))
			tok, lit, err := sc.Scan()
			if err != nil != tt.wantErr {
				t.Fatalf("scanning: %v", err)
			}
			if tok != token.InlineString {
				t.Fatalf("got a %v", tok)
			}
			if lit != tt.input {
				t.Errorf("want literal=%q", tt.input)
				t.Errorf(" got literal=%q", lit)
			}

			got, err := ParseInlineString(lit)
			if err != nil != tt.wantErr {
				t.Fatalf("ParseInlineString: %v", err)
			}

			if !reflect.DeepEqual(tt.want, got) {
				t.Errorf("want=%q", tt.want)
				t.Errorf(" got=%q", got)
			}
		})
	}
}

func TestParseString(t *testing.T) {
	tests := []struct {
		name    string
		input   string
		want    string
		wantErr bool
	}{
		{
			name:  "string",
			input: `"hello"`,
			want:  "hello",
		},
		{
			name:  "string that contains whitespace",
			input: `"hello    "`,
			want:  "hello    ",
		},
		{
			name:  "string of escaped characters",
			input: `"\\\"\n\t\r"`,
			want:  `\"` + "\n\t\r",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {

			sc := NewScanner(strings.NewReader(tt.input))
			tok, lit, err := sc.Scan()
			if err != nil != tt.wantErr {
				t.Fatalf("scanning: %v", err)
			}
			if tok != token.String {
				t.Fatalf("got a %v (lit=%q)", tok, lit)
			}
			if lit != tt.input {
				t.Errorf("want literal=%q", tt.input)
				t.Errorf(" got literal=%q", lit)
			}

			got, err := ParseString(lit)
			if err != nil != tt.wantErr {
				t.Fatalf("ParseString: %v", err)
			}

			if !reflect.DeepEqual(tt.want, got) {
				t.Errorf("want=%q", tt.want)
				t.Errorf(" got=%q", got)
			}
		})
	}
}

func TestParseNumber(t *testing.T) {

	tests := []struct {
		name    string
		input   string
		want    float64
		wantErr bool
	}{
		// regular integers
		{"", `0`, 0, false},
		{"", `-0`, -0, false},
		{"", `1`, 1, false},
		{"", `-1`, -1, false},
		{"", `12`, 12, false},
		{"", `-12`, -12, false},
		{"", `1234567890`, 1234567890, false},
		{"", `-1234567890`, -1234567890, false},

		// decimal values
		{"", `0.0`, 0.0, false},
		{"", `-0.0`, -0.0, false},
		{"", `0.1`, 0.1, false},
		{"", `-0.1`, -0.1, false},
		{"", `0.12`, 0.12, false},
		{"", `-0.12`, -0.12, false},
		{"", `0.1234567890`, 0.1234567890, false},
		{"", `-0.1234567890`, -0.1234567890, false},
		{"", `0.0001`, 0.0001, false},
		{"", `1.2`, 1.2, false},
		{"", `-1.2`, -1.2, false},
		{"", `12.34`, 12.34, false},
		{"", `-12.34`, -12.34, false},

		// exponential values
		{"", `0e0`, 0e0, false},
		{"", `-0e0`, -0, false},
		{"", `0e1`, 0, false},
		{"", `-0e1`, -0, false},
		{"", `0e3`, 0, false},
		{"", `-0e3`, -0e3, false},

		{"", `1e2`, 1e2, false},
		{"", `-1e2`, -1e2, false},
		{"", `1e-2`, 1e-2, false},
		{"", `-1e-2`, -1e-2, false},
		{"", `12e34`, 12e34, false},
		{"", `-12e34`, -12e34, false},

		{"", `0.1e0`, 0.1e0, false},
		{"", `-0.1e0`, -0.1e0, false},
		{"", `0.1e1`, 0.1e1, false},
		{"", `-0.1e1`, -0.1e1, false},
		{"", `0.1e3`, 0.1e3, false},
		{"", `-0.1e3`, -0.1e3, false},

		{"", `1.1e2`, 1.1e2, false},
		{"", `-1.1e2`, -1.1e2, false},
		{"", `1.1e-2`, 1.1e-2, false},
		{"", `-1.1e-2`, -1.1e-2, false},
		{"", `12.1e34`, 12.1e34, false},
		{"", `-12.1e34`, -12.1e34, false},

		{"", `0.0e0`, 0.0e0, false},
		{"", `-0.0e0`, -0.0e0, false},
		{"", `0.0e1`, 0.0e1, false},
		{"", `-0.0e1`, -0.0e1, false},
		{"", `0.0e3`, 0.0e3, false},
		{"", `-0.0e3`, -0.0e3, false},

		{"", `1.0e2`, 1.0e2, false},
		{"", `-1.0e2`, -1.0e2, false},
		{"", `1.0e-2`, 1.0e-2, false},
		{"", `-1.0e-2`, -1.0e-2, false},
		{"", `12.0e34`, 12.0e34, false},
		{"", `-12.0e34`, -12.0e34, false},

		{"", `0.1234e0`, 0.1234e0, false},
		{"", `-0.1234e0`, -0.1234e0, false},
		{"", `0.1234e1`, 0.1234e1, false},
		{"", `-0.1234e1`, -0.1234e1, false},
		{"", `0.1234e3`, 0.1234e3, false},
		{"", `-0.1234e3`, -0.1234e3, false},

		{"", `1.1234e2`, 1.1234e2, false},
		{"", `-1.1234e2`, -1.1234e2, false},
		{"", `1.1234e-2`, 1.1234e-2, false},
		{"", `-1.1234e-2`, -1.1234e-2, false},
		{"", `12.1234e34`, 12.1234e34, false},
		{"", `-12.1234e34`, -12.1234e34, false},

		{"", `0.01234e0`, 0.01234e0, false},
		{"", `-0.01234e0`, -0.01234e0, false},
		{"", `0.01234e1`, 0.01234e1, false},
		{"", `-0.01234e1`, -0.01234e1, false},
		{"", `0.01234e3`, 0.01234e3, false},
		{"", `-0.01234e3`, -0.01234e3, false},

		{"", `1.01234e2`, 1.01234e2, false},
		{"", `-1.01234e2`, -1.01234e2, false},
		{"", `1.01234e-2`, 1.01234e-2, false},
		{"", `-1.01234e-2`, -1.01234e-2, false},
		{"", `12.01234e34`, 12.01234e34, false},
		{"", `-12.01234e34`, -12.01234e34, false},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {

			t.Logf("input=%q", tt.input)
			sc := NewScanner(strings.NewReader(tt.input))
			tok, lit, err := sc.Scan()
			if err != nil != tt.wantErr {
				t.Fatalf("scanning: %v", err)
			}
			if tok != token.Float && tok != token.Integer {
				t.Fatalf("got a %v", tok)
			}
			if lit != tt.input {
				t.Errorf("want literal=%q", tt.input)
				t.Errorf(" got literal=%q", lit)
			}

			got, err := ParseNumber(lit)
			if err != nil != tt.wantErr {
				t.Fatalf("ParseNumber: %v", err)
			}

			acceptRoundError := 0.000000000000001
			if (tt.want > got && acceptRoundError < (tt.want-got)/tt.want) ||
				(tt.want < got && acceptRoundError < (got-tt.want)/got) {
				t.Errorf("want=%#v", tt.want)
				t.Errorf(" got=%#v", got)
			}
		})
	}
}

func TestParseInteger(t *testing.T) {
	tests := []struct {
		name    string
		input   string
		want    int
		wantErr bool
	}{
		{"zero", `0`, 0, false},
		{"negative zero", `-0`, -0, false},
		{"single digit", `1`, 1, false},
		{"negative single digit", `-1`, -1, false},
		{"multiple digit", `12`, 12, false},
		{"negative multiple digit", `-12`, -12, false},
		{"all digits", `1234567890`, 1234567890, false},
		{"negative all digits", `-1234567890`, -1234567890, false},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {

			sc := NewScanner(strings.NewReader(tt.input))
			tok, lit, err := sc.Scan()
			if err != nil != tt.wantErr {
				t.Fatalf("scanning: %v", err)
			}
			if tok != token.Integer {
				t.Fatalf("got a %v", tok)
			}
			if lit != tt.input {
				t.Errorf("want literal=%q", tt.input)
				t.Errorf(" got literal=%q", lit)
			}

			got, err := ParseInteger(lit)
			if err != nil != tt.wantErr {
				t.Fatalf("ParseInteger: %v", err)
			}

			if !reflect.DeepEqual(tt.want, got) {
				t.Errorf("want=%#v", tt.want)
				t.Errorf(" got=%#v", got)
			}
		})
	}
}

func TestParseBoolean(t *testing.T) {
	tests := []struct {
		name    string
		input   string
		want    bool
		wantTok token.Token
		wantErr bool
	}{
		{"true", "true", true, token.InlineString, false},
		{"false", "false", false, token.InlineString, false},
		{"other things", "1", false, token.Integer, true},
		{"other things", "0", false, token.Integer, true},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {

			sc := NewScanner(strings.NewReader(tt.input))
			tok, lit, err := sc.Scan()
			if tok != tt.wantTok {
				t.Fatalf("want a %v", tt.wantTok)
				t.Fatalf(" got a %v", tok)
			}
			if lit != tt.input {
				t.Errorf("want literal=%q", tt.input)
				t.Errorf(" got literal=%q", lit)
			}

			got, err := ParseBoolean(lit)
			if err != nil != tt.wantErr {
				t.Fatalf("ParseBoolean: %v", err)
			} else if !reflect.DeepEqual(tt.want, got) {
				t.Errorf("want=%#v", tt.want)
				t.Errorf(" got=%#v", got)
			}
		})
	}
}
<commit_msg>fix scanner int64 vs int<commit_after>package scanner

import (
	"reflect"
	"strings"
	"testing"

	"github.com/aybabtme/streamql/lang/token"
)

func TestParseInlineString(t *testing.T) {
	tests := []struct {
		name    string
		input   string
		want    string
		wantErr bool
	}{
		{
			name:  "inline string",
			input: `hello`,
			want:  "hello",
		},
		{
			name:  "inline string that contains escaped whitespace",
			input: `hello\ \ \ \ `,
			want:  "hello    ",
		},
		{
			name: "inline string of escaped characters",
			input: `\\\.\ \|\:\,\[\]\	\` + "\n",
			want: `\. |:,[]` + "\t\n",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {

			sc := NewScanner(strings.NewReader(tt.input))
			tok, lit, err := sc.Scan()
			if err != nil != tt.wantErr {
				t.Fatalf("scanning: %v", err)
			}
			if tok != token.InlineString {
				t.Fatalf("got a %v", tok)
			}
			if lit != tt.input {
				t.Errorf("want literal=%q", tt.input)
				t.Errorf(" got literal=%q", lit)
			}

			got, err := ParseInlineString(lit)
			if err != nil != tt.wantErr {
				t.Fatalf("ParseInlineString: %v", err)
			}

			if !reflect.DeepEqual(tt.want, got) {
				t.Errorf("want=%q", tt.want)
				t.Errorf(" got=%q", got)
			}
		})
	}
}

func TestParseString(t *testing.T) {
	tests := []struct {
		name    string
		input   string
		want    string
		wantErr bool
	}{
		{
			name:  "string",
			input: `"hello"`,
			want:  "hello",
		},
		{
			name:  "string that contains whitespace",
			input: `"hello    "`,
			want:  "hello    ",
		},
		{
			name:  "string of escaped characters",
			input: `"\\\"\n\t\r"`,
			want:  `\"` + "\n\t\r",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {

			sc := NewScanner(strings.NewReader(tt.input))
			tok, lit, err := sc.Scan()
			if err != nil != tt.wantErr {
				t.Fatalf("scanning: %v", err)
			}
			if tok != token.String {
				t.Fatalf("got a %v (lit=%q)", tok, lit)
			}
			if lit != tt.input {
				t.Errorf("want literal=%q", tt.input)
				t.Errorf(" got literal=%q", lit)
			}

			got, err := ParseString(lit)
			if err != nil != tt.wantErr {
				t.Fatalf("ParseString: %v", err)
			}

			if !reflect.DeepEqual(tt.want, got) {
				t.Errorf("want=%q", tt.want)
				t.Errorf(" got=%q", got)
			}
		})
	}
}

func TestParseNumber(t *testing.T) {

	tests := []struct {
		name    string
		input   string
		want    float64
		wantErr bool
	}{
		// regular integers
		{"", `0`, 0, false},
		{"", `-0`, -0, false},
		{"", `1`, 1, false},
		{"", `-1`, -1, false},
		{"", `12`, 12, false},
		{"", `-12`, -12, false},
		{"", `1234567890`, 1234567890, false},
		{"", `-1234567890`, -1234567890, false},

		// decimal values
		{"", `0.0`, 0.0, false},
		{"", `-0.0`, -0.0, false},
		{"", `0.1`, 0.1, false},
		{"", `-0.1`, -0.1, false},
		{"", `0.12`, 0.12, false},
		{"", `-0.12`, -0.12, false},
		{"", `0.1234567890`, 0.1234567890, false},
		{"", `-0.1234567890`, -0.1234567890, false},
		{"", `0.0001`, 0.0001, false},
		{"", `1.2`, 1.2, false},
		{"", `-1.2`, -1.2, false},
		{"", `12.34`, 12.34, false},
		{"", `-12.34`, -12.34, false},

		// exponential values
		{"", `0e0`, 0e0, false},
		{"", `-0e0`, -0, false},
		{"", `0e1`, 0, false},
		{"", `-0e1`, -0, false},
		{"", `0e3`, 0, false},
		{"", `-0e3`, -0e3, false},

		{"", `1e2`, 1e2, false},
		{"", `-1e2`, -1e2, false},
		{"", `1e-2`, 1e-2, false},
		{"", `-1e-2`, -1e-2, false},
		{"", `12e34`, 12e34, false},
		{"", `-12e34`, -12e34, false},

		{"", `0.1e0`, 0.1e0, false},
		{"", `-0.1e0`, -0.1e0, false},
		{"", `0.1e1`, 0.1e1, false},
		{"", `-0.1e1`, -0.1e1, false},
		{"", `0.1e3`, 0.1e3, false},
		{"", `-0.1e3`, -0.1e3, false},

		{"", `1.1e2`, 1.1e2, false},
		{"", `-1.1e2`, -1.1e2, false},
		{"", `1.1e-2`, 1.1e-2, false},
		{"", `-1.1e-2`, -1.1e-2, false},
		{"", `12.1e34`, 12.1e34, false},
		{"", `-12.1e34`, -12.1e34, false},

		{"", `0.0e0`, 0.0e0, false},
		{"", `-0.0e0`, -0.0e0, false},
		{"", `0.0e1`, 0.0e1, false},
		{"", `-0.0e1`, -0.0e1, false},
		{"", `0.0e3`, 0.0e3, false},
		{"", `-0.0e3`, -0.0e3, false},

		{"", `1.0e2`, 1.0e2, false},
		{"", `-1.0e2`, -1.0e2, false},
		{"", `1.0e-2`, 1.0e-2, false},
		{"", `-1.0e-2`, -1.0e-2, false},
		{"", `12.0e34`, 12.0e34, false},
		{"", `-12.0e34`, -12.0e34, false},

		{"", `0.1234e0`, 0.1234e0, false},
		{"", `-0.1234e0`, -0.1234e0, false},
		{"", `0.1234e1`, 0.1234e1, false},
		{"", `-0.1234e1`, -0.1234e1, false},
		{"", `0.1234e3`, 0.1234e3, false},
		{"", `-0.1234e3`, -0.1234e3, false},

		{"", `1.1234e2`, 1.1234e2, false},
		{"", `-1.1234e2`, -1.1234e2, false},
		{"", `1.1234e-2`, 1.1234e-2, false},
		{"", `-1.1234e-2`, -1.1234e-2, false},
		{"", `12.1234e34`, 12.1234e34, false},
		{"", `-12.1234e34`, -12.1234e34, false},

		{"", `0.01234e0`, 0.01234e0, false},
		{"", `-0.01234e0`, -0.01234e0, false},
		{"", `0.01234e1`, 0.01234e1, false},
		{"", `-0.01234e1`, -0.01234e1, false},
		{"", `0.01234e3`, 0.01234e3, false},
		{"", `-0.01234e3`, -0.01234e3, false},

		{"", `1.01234e2`, 1.01234e2, false},
		{"", `-1.01234e2`, -1.01234e2, false},
		{"", `1.01234e-2`, 1.01234e-2, false},
		{"", `-1.01234e-2`, -1.01234e-2, false},
		{"", `12.01234e34`, 12.01234e34, false},
		{"", `-12.01234e34`, -12.01234e34, false},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {

			t.Logf("input=%q", tt.input)
			sc := NewScanner(strings.NewReader(tt.input))
			tok, lit, err := sc.Scan()
			if err != nil != tt.wantErr {
				t.Fatalf("scanning: %v", err)
			}
			if tok != token.Float && tok != token.Integer {
				t.Fatalf("got a %v", tok)
			}
			if lit != tt.input {
				t.Errorf("want literal=%q", tt.input)
				t.Errorf(" got literal=%q", lit)
			}

			got, err := ParseNumber(lit)
			if err != nil != tt.wantErr {
				t.Fatalf("ParseNumber: %v", err)
			}

			acceptRoundError := 0.000000000000001
			if (tt.want > got && acceptRoundError < (tt.want-got)/tt.want) ||
				(tt.want < got && acceptRoundError < (got-tt.want)/got) {
				t.Errorf("want=%#v", tt.want)
				t.Errorf(" got=%#v", got)
			}
		})
	}
}

func TestParseInteger(t *testing.T) {
	tests := []struct {
		name    string
		input   string
		want    int64
		wantErr bool
	}{
		{"zero", `0`, 0, false},
		{"negative zero", `-0`, -0, false},
		{"single digit", `1`, 1, false},
		{"negative single digit", `-1`, -1, false},
		{"multiple digit", `12`, 12, false},
		{"negative multiple digit", `-12`, -12, false},
		{"all digits", `1234567890`, 1234567890, false},
		{"negative all digits", `-1234567890`, -1234567890, false},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {

			sc := NewScanner(strings.NewReader(tt.input))
			tok, lit, err := sc.Scan()
			if err != nil != tt.wantErr {
				t.Fatalf("scanning: %v", err)
			}
			if tok != token.Integer {
				t.Fatalf("got a %v", tok)
			}
			if lit != tt.input {
				t.Errorf("want literal=%q", tt.input)
				t.Errorf(" got literal=%q", lit)
			}

			got, err := ParseInteger(lit)
			if err != nil != tt.wantErr {
				t.Fatalf("ParseInteger: %v", err)
			}

			if !reflect.DeepEqual(tt.want, got) {
				t.Errorf("want=%#v", tt.want)
				t.Errorf(" got=%#v", got)
			}
		})
	}
}

func TestParseBoolean(t *testing.T) {
	tests := []struct {
		name    string
		input   string
		want    bool
		wantTok token.Token
		wantErr bool
	}{
		{"true", "true", true, token.InlineString, false},
		{"false", "false", false, token.InlineString, false},
		{"other things", "1", false, token.Integer, true},
		{"other things", "0", false, token.Integer, true},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {

			sc := NewScanner(strings.NewReader(tt.input))
			tok, lit, err := sc.Scan()
			if tok != tt.wantTok {
				t.Fatalf("want a %v", tt.wantTok)
				t.Fatalf(" got a %v", tok)
			}
			if lit != tt.input {
				t.Errorf("want literal=%q", tt.input)
				t.Errorf(" got literal=%q", lit)
			}

			got, err := ParseBoolean(lit)
			if err != nil != tt.wantErr {
				t.Fatalf("ParseBoolean: %v", err)
			} else if !reflect.DeepEqual(tt.want, got) {
				t.Errorf("want=%#v", tt.want)
				t.Errorf(" got=%#v", got)
			}
		})
	}
}
<|endoftext|>


<commit_before>package auth

import "github.com/micro/go-micro/v2/auth"

// SystemRules are the default rules which are applied to the runtime services
var SystemRules = map[string][]*auth.Resource{
	"service": {
		&auth.Resource{Namespace: auth.DefaultNamespace, Type: "*", Name: "*", Endpoint: "*"},
	},
	"admin": {
		&auth.Resource{Namespace: auth.DefaultNamespace, Type: "*", Name: "*", Endpoint: "*"},
	},
	"developer": {
		&auth.Resource{Namespace: auth.DefaultNamespace, Type: "*", Name: "*", Endpoint: "*"},
	},
	"*": {
		&auth.Resource{Namespace: auth.DefaultNamespace, Type: "service", Name: "go.micro.auth", Endpoint: "Auth.Generate"},
		&auth.Resource{Namespace: auth.DefaultNamespace, Type: "service", Name: "go.micro.auth", Endpoint: "Auth.Token"},
		&auth.Resource{Namespace: auth.DefaultNamespace, Type: "service", Name: "go.micro.auth", Endpoint: "Auth.Inspect"},
		&auth.Resource{Namespace: auth.DefaultNamespace, Type: "service", Name: "go.micro.registry", Endpoint: "Registry.GetService"},
	},
}
<commit_msg>Unauthenticate all go.micro.registry endpoints<commit_after>package auth

import "github.com/micro/go-micro/v2/auth"

// SystemRules are the default rules which are applied to the runtime services
var SystemRules = map[string][]*auth.Resource{
	"service": {
		&auth.Resource{Namespace: auth.DefaultNamespace, Type: "*", Name: "*", Endpoint: "*"},
	},
	"admin": {
		&auth.Resource{Namespace: auth.DefaultNamespace, Type: "*", Name: "*", Endpoint: "*"},
	},
	"developer": {
		&auth.Resource{Namespace: auth.DefaultNamespace, Type: "*", Name: "*", Endpoint: "*"},
	},
	"*": {
		&auth.Resource{Namespace: auth.DefaultNamespace, Type: "service", Name: "go.micro.auth", Endpoint: "Auth.Generate"},
		&auth.Resource{Namespace: auth.DefaultNamespace, Type: "service", Name: "go.micro.auth", Endpoint: "Auth.Token"},
		&auth.Resource{Namespace: auth.DefaultNamespace, Type: "service", Name: "go.micro.auth", Endpoint: "Auth.Inspect"},
		&auth.Resource{Namespace: auth.DefaultNamespace, Type: "service", Name: "go.micro.registry", Endpoint: "Registry.GetService"},
		&auth.Resource{Namespace: auth.DefaultNamespace, Type: "service", Name: "go.micro.registry", Endpoint: "*"},
	},
}
<|endoftext|>