<commit_before>// Package guid provides a GUID type. The backing structure for a GUID is
// identical to that used by the golang.org/x/sys/windows GUID type.
// There are two main binary encodings used for a GUID, the big-endian encoding,
// and the Windows (mixed-endian) encoding. See here for details:
// https://en.wikipedia.org/wiki/Universally_unique_identifier#Encoding
package guid

import (
	"crypto/rand"
	"encoding/binary"
	"encoding/json"
	"fmt"
	"strconv"
	"strings"

	"golang.org/x/sys/windows"
)

// Variant specifies which GUID variant (or "type") of the GUID. It determines
// how the entirety of the rest of the GUID is interpreted.
type Variant uint8

// The variants specified by RFC 4122.
const (
	// VariantUnknown specifies a GUID variant which does not conform to one of
	// the variant encodings specified in RFC 4122.
	VariantUnknown Variant = iota
	VariantNCS
	VariantRFC4122
	VariantMicrosoft
	VariantFuture
)

// Version specifies how the bits in the GUID were generated. For instance, a
// version 4 GUID is randomly generated, and a version 5 is generated from the
// hash of an input string.
type Version uint8

var _ = (json.Marshaler)(GUID{})
var _ = (json.Unmarshaler)(&GUID{})

// GUID represents a GUID/UUID. It has the same structure as
// golang.org/x/sys/windows.GUID so that it can be used with functions expecting
// that type. It is defined as its own type so that stringification and
// marshaling can be supported. The representation matches that used by native
// Windows code.
type GUID windows.GUID

// NewV4 returns a new version 4 (pseudorandom) GUID, as defined by RFC 4122.
func NewV4() (GUID, error) {
	var b [16]byte
	if _, err := rand.Read(b[:]); err != nil {
		return GUID{}, err
	}

	b[6] = (b[6] & 0x0f) | 0x40 // Version 4 (randomly generated)
	b[8] = (b[8] & 0x3f) | 0x80 // RFC4122 variant

	return FromArray(b), nil
}

func fromArray(b [16]byte, order binary.ByteOrder) GUID {
	var g GUID
	g.Data1 = order.Uint32(b[0:4])
	g.Data2 = order.Uint16(b[4:6])
	g.Data3 = order.Uint16(b[6:8])
	copy(g.Data4[:], b[8:16])
	return g
}

func (g GUID) toArray(order binary.ByteOrder) [16]byte {
	b := [16]byte{}
	order.PutUint32(b[0:4], g.Data1)
	order.PutUint16(b[4:6], g.Data2)
	order.PutUint16(b[6:8], g.Data3)
	copy(b[8:16], g.Data4[:])
	return b
}

// FromArray constructs a GUID from a big-endian encoding array of 16 bytes.
func FromArray(b [16]byte) GUID {
	return fromArray(b, binary.BigEndian)
}

// ToArray returns an array of 16 bytes representing the GUID in big-endian
// encoding.
func (g GUID) ToArray() [16]byte {
	return g.toArray(binary.BigEndian)
}

// FromWindowsArray constructs a GUID from a Windows encoding array of bytes.
func FromWindowsArray(b [16]byte) GUID {
	return fromArray(b, binary.LittleEndian)
}

// ToWindowsArray returns an array of 16 bytes representing the GUID in Windows
// encoding.
func (g GUID) ToWindowsArray() [16]byte {
	return g.toArray(binary.LittleEndian)
}

func (g GUID) String() string {
	return fmt.Sprintf(
		"%08x-%04x-%04x-%04x-%012x",
		g.Data1,
		g.Data2,
		g.Data3,
		g.Data4[:2],
		g.Data4[2:])
}

// FromString parses a string containing a GUID and returns the GUID. The only
// format currently supported is the `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
// format.
func FromString(s string) (GUID, error) {
	if len(s) != 36 {
		return GUID{}, fmt.Errorf("invalid GUID %q", s)
	}
	if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
		return GUID{}, fmt.Errorf("invalid GUID %q", s)
	}

	var g GUID

	data1, err := strconv.ParseUint(s[0:8], 16, 32)
	if err != nil {
		return GUID{}, fmt.Errorf("invalid GUID %q", s)
	}
	g.Data1 = uint32(data1)

	data2, err := strconv.ParseUint(s[9:13], 16, 16)
	if err != nil {
		return GUID{}, fmt.Errorf("invalid GUID %q", s)
	}
	g.Data2 = uint16(data2)

	data3, err := strconv.ParseUint(s[14:18], 16, 16)
	if err != nil {
		return GUID{}, fmt.Errorf("invalid GUID %q", s)
	}
	g.Data3 = uint16(data3)

	for i, x := range []int{19, 21, 24, 26, 28, 30, 32, 34} {
		v, err := strconv.ParseUint(s[x:x+2], 16, 8)
		if err != nil {
			return GUID{}, fmt.Errorf("invalid GUID %q", s)
		}
		g.Data4[i] = uint8(v)
	}

	return g, nil
}

// Variant returns the GUID variant, as defined in RFC 4122.
func (g GUID) Variant() Variant {
	b := g.Data4[0]
	if b&0x80 == 0 {
		return VariantNCS
	} else if b&0xc0 == 0x80 {
		return VariantRFC4122
	} else if b&0xe0 == 0xc0 {
		return VariantMicrosoft
	} else if b&0xe0 == 0xe0 {
		return VariantFuture
	}
	return VariantUnknown
}

// Version returns the GUID version, as defined in RFC 4122.
func (g GUID) Version() Version {
	return Version((g.Data3 & 0xF000) >> 12)
}

// MarshalJSON marshals the GUID to JSON representation and returns it as a
// slice of bytes.
func (g GUID) MarshalJSON() ([]byte, error) {
	return json.Marshal(g.String())
}

// UnmarshalJSON unmarshals a GUID from JSON representation and sets itself to
// the unmarshaled GUID.
func (g *GUID) UnmarshalJSON(data []byte) error {
	g2, err := FromString(strings.Trim(string(data), "\""))
	if err != nil {
		return err
	}
	*g = g2
	return nil
}
<commit_msg>pkg/guid: Switch from json.Marshaler to encoding.TextMarshaler<commit_after>// Package guid provides a GUID type. The backing structure for a GUID is
// identical to that used by the golang.org/x/sys/windows GUID type.
// There are two main binary encodings used for a GUID, the big-endian encoding,
// and the Windows (mixed-endian) encoding. See here for details:
// https://en.wikipedia.org/wiki/Universally_unique_identifier#Encoding
package guid

import (
	"crypto/rand"
	"encoding"
	"encoding/binary"
	"fmt"
	"strconv"

	"golang.org/x/sys/windows"
)

// Variant specifies which GUID variant (or "type") of the GUID. It determines
// how the entirety of the rest of the GUID is interpreted.
type Variant uint8

// The variants specified by RFC 4122.
const (
	// VariantUnknown specifies a GUID variant which does not conform to one of
	// the variant encodings specified in RFC 4122.
	VariantUnknown Variant = iota
	VariantNCS
	VariantRFC4122
	VariantMicrosoft
	VariantFuture
)

// Version specifies how the bits in the GUID were generated. For instance, a
// version 4 GUID is randomly generated, and a version 5 is generated from the
// hash of an input string.
type Version uint8

var _ = (encoding.TextMarshaler)(GUID{})
var _ = (encoding.TextUnmarshaler)(&GUID{})

// GUID represents a GUID/UUID. It has the same structure as
// golang.org/x/sys/windows.GUID so that it can be used with functions expecting
// that type. It is defined as its own type so that stringification and
// marshaling can be supported. The representation matches that used by native
// Windows code.
type GUID windows.GUID

// NewV4 returns a new version 4 (pseudorandom) GUID, as defined by RFC 4122.
func NewV4() (GUID, error) {
	var b [16]byte
	if _, err := rand.Read(b[:]); err != nil {
		return GUID{}, err
	}

	b[6] = (b[6] & 0x0f) | 0x40 // Version 4 (randomly generated)
	b[8] = (b[8] & 0x3f) | 0x80 // RFC4122 variant

	return FromArray(b), nil
}

func fromArray(b [16]byte, order binary.ByteOrder) GUID {
	var g GUID
	g.Data1 = order.Uint32(b[0:4])
	g.Data2 = order.Uint16(b[4:6])
	g.Data3 = order.Uint16(b[6:8])
	copy(g.Data4[:], b[8:16])
	return g
}

func (g GUID) toArray(order binary.ByteOrder) [16]byte {
	b := [16]byte{}
	order.PutUint32(b[0:4], g.Data1)
	order.PutUint16(b[4:6], g.Data2)
	order.PutUint16(b[6:8], g.Data3)
	copy(b[8:16], g.Data4[:])
	return b
}

// FromArray constructs a GUID from a big-endian encoding array of 16 bytes.
func FromArray(b [16]byte) GUID {
	return fromArray(b, binary.BigEndian)
}

// ToArray returns an array of 16 bytes representing the GUID in big-endian
// encoding.
func (g GUID) ToArray() [16]byte {
	return g.toArray(binary.BigEndian)
}

// FromWindowsArray constructs a GUID from a Windows encoding array of bytes.
func FromWindowsArray(b [16]byte) GUID {
	return fromArray(b, binary.LittleEndian)
}

// ToWindowsArray returns an array of 16 bytes representing the GUID in Windows
// encoding.
func (g GUID) ToWindowsArray() [16]byte {
	return g.toArray(binary.LittleEndian)
}

func (g GUID) String() string {
	return fmt.Sprintf(
		"%08x-%04x-%04x-%04x-%012x",
		g.Data1,
		g.Data2,
		g.Data3,
		g.Data4[:2],
		g.Data4[2:])
}

// FromString parses a string containing a GUID and returns the GUID. The only
// format currently supported is the `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
// format.
func FromString(s string) (GUID, error) {
	if len(s) != 36 {
		return GUID{}, fmt.Errorf("invalid GUID %q", s)
	}
	if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
		return GUID{}, fmt.Errorf("invalid GUID %q", s)
	}

	var g GUID

	data1, err := strconv.ParseUint(s[0:8], 16, 32)
	if err != nil {
		return GUID{}, fmt.Errorf("invalid GUID %q", s)
	}
	g.Data1 = uint32(data1)

	data2, err := strconv.ParseUint(s[9:13], 16, 16)
	if err != nil {
		return GUID{}, fmt.Errorf("invalid GUID %q", s)
	}
	g.Data2 = uint16(data2)

	data3, err := strconv.ParseUint(s[14:18], 16, 16)
	if err != nil {
		return GUID{}, fmt.Errorf("invalid GUID %q", s)
	}
	g.Data3 = uint16(data3)

	for i, x := range []int{19, 21, 24, 26, 28, 30, 32, 34} {
		v, err := strconv.ParseUint(s[x:x+2], 16, 8)
		if err != nil {
			return GUID{}, fmt.Errorf("invalid GUID %q", s)
		}
		g.Data4[i] = uint8(v)
	}

	return g, nil
}

// Variant returns the GUID variant, as defined in RFC 4122.
func (g GUID) Variant() Variant {
	b := g.Data4[0]
	if b&0x80 == 0 {
		return VariantNCS
	} else if b&0xc0 == 0x80 {
		return VariantRFC4122
	} else if b&0xe0 == 0xc0 {
		return VariantMicrosoft
	} else if b&0xe0 == 0xe0 {
		return VariantFuture
	}
	return VariantUnknown
}

// Version returns the GUID version, as defined in RFC 4122.
func (g GUID) Version() Version {
	return Version((g.Data3 & 0xF000) >> 12)
}

// MarshalText returns the textual representation of the GUID.
func (g GUID) MarshalText() ([]byte, error) {
	return []byte(g.String()), nil
}

// UnmarshalText takes the textual representation of a GUID, and unmarhals it
// into this GUID.
func (g *GUID) UnmarshalText(text []byte) error {
	g2, err := FromString(string(text))
	if err != nil {
		return err
	}
	*g = g2
	return nil
}
<|endoftext|>


<commit_before>package http

import (
	"context"
	"encoding/json"
	"fmt"
	"io"

	"net/http"
	"os"
	"strings"
	"time"

	"github.com/gorilla/mux"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/urfave/negroni"

	"github.com/keel-hq/keel/approvals"
	"github.com/keel-hq/keel/provider"
	"github.com/keel-hq/keel/types"
	"github.com/keel-hq/keel/version"

	log "github.com/sirupsen/logrus"
)

// Opts - http server options
type Opts struct {
	Port int

	// available providers
	Providers provider.Providers

	ApprovalManager approvals.Manager

	// Username and password are used for basic auth
	Username string
	Password string
}

// TriggerServer - webhook trigger & healthcheck server
type TriggerServer struct {
	providers        provider.Providers
	approvalsManager approvals.Manager
	port             int
	server           *http.Server
	router           *mux.Router

	// basic auth
	username string
	password string
}

// NewTriggerServer - create new HTTP trigger based server
func NewTriggerServer(opts *Opts) *TriggerServer {
	return &TriggerServer{
		port:             opts.Port,
		providers:        opts.Providers,
		approvalsManager: opts.ApprovalManager,
		router:           mux.NewRouter(),
		username:         opts.Username,
		password:         opts.Password,
	}
}

// Start - start server
func (s *TriggerServer) Start() error {

	s.registerRoutes(s.router)

	n := negroni.New(negroni.NewRecovery())
	// n.UseHandler(negroni.HandlerFunc(corsHeadersMiddleware))
	n.Use(negroni.HandlerFunc(corsHeadersMiddleware))
	n.UseHandler(s.router)

	s.server = &http.Server{
		Addr:    fmt.Sprintf(":%d", s.port),
		Handler: n,
	}

	log.WithFields(log.Fields{
		"port": s.port,
	}).Info("webhook trigger server starting...")
	return s.server.ListenAndServe()
}

// Stop - stop webhook server
func (s *TriggerServer) Stop() {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	s.server.Shutdown(ctx)
}

func getID(req *http.Request) string {
	return mux.Vars(req)["id"]
}

func (s *TriggerServer) registerRoutes(mux *mux.Router) {

	if os.Getenv("DEBUG") == "true" {
		DebugHandler{}.AddRoutes(mux)
	}

	// health endpoint for k8s to be happy
	mux.HandleFunc("/healthz", s.healthHandler).Methods("GET", "OPTIONS")
	// version handler
	mux.HandleFunc("/version", s.versionHandler).Methods("GET", "OPTIONS")

	// auth
	mux.HandleFunc("/v1/user/info", s.requireAdminAuthorization(s.userInfoHandler)).Methods("GET", "OPTIONS")
	mux.HandleFunc("/v1/user/logout", s.requireAdminAuthorization(s.logoutHandler)).Methods("GET", "OPTIONS")

	// approvals
	mux.HandleFunc("/v1/approvals", s.requireAdminAuthorization(s.approvalsHandler)).Methods("GET", "OPTIONS")
	// approving/rejecting
	mux.HandleFunc("/v1/approvals", s.requireAdminAuthorization(s.approvalApproveHandler)).Methods("POST", "OPTIONS")

	mux.HandleFunc("/v1/tracked", s.requireAdminAuthorization(s.trackedHandler)).Methods("GET", "OPTIONS")

	mux.Handle("/metrics", promhttp.Handler())

	s.registerWebhookRoutes(mux)
}

func (s *TriggerServer) registerWebhookRoutes(mux *mux.Router) {
	mux.HandleFunc("/v1/webhooks/native", s.nativeHandler).Methods("POST", "OPTIONS")
	mux.HandleFunc("/v1/webhooks/dockerhub", s.dockerHubHandler).Methods("POST", "OPTIONS")
	mux.HandleFunc("/v1/webhooks/quay", s.quayHandler).Methods("POST", "OPTIONS")
	mux.HandleFunc("/v1/webhooks/azure", s.azureHandler).Methods("POST", "OPTIONS")

	// Docker registry notifications, used by Docker, Gitlab, Harbor
	// https://docs.docker.com/registry/notifications/
	//https://docs.gitlab.com/ee/administration/container_registry.html#configure-container-registry-notifications
	mux.HandleFunc("/v1/webhooks/registry", s.registryNotificationHandler).Methods("POST", "OPTIONS")
}

func (s *TriggerServer) healthHandler(resp http.ResponseWriter, req *http.Request) {
	resp.WriteHeader(http.StatusOK)
}

func (s *TriggerServer) versionHandler(resp http.ResponseWriter, req *http.Request) {
	v := version.GetKeelVersion()

	encoded, err := json.Marshal(v)
	if err != nil {
		log.WithError(err).Error("trigger.http: failed to marshal version")
		resp.WriteHeader(http.StatusInternalServerError)
		return
	}

	resp.WriteHeader(http.StatusOK)
	resp.Write(encoded)
}

func (s *TriggerServer) trigger(event types.Event) error {
	return s.providers.Submit(event)
}

func (s *TriggerServer) requireAdminAuthorization(next http.HandlerFunc) http.HandlerFunc {
	return func(rw http.ResponseWriter, r *http.Request) {

		if s.username == "" && s.password == "" {
			next(rw, r)
			return
		}

		rw.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)

		username, password, ok := r.BasicAuth()
		if ok && username == s.username && password == s.password {
			next(rw, r)
			return
		}

		http.Error(rw, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
	}
}

func response(obj interface{}, statusCode int, err error, resp http.ResponseWriter, req *http.Request) {
	// Check for an error

	if err != nil {

		code := 500
		errMsg := err.Error()
		if strings.Contains(errMsg, "Permission denied") {
			code = 403
		}
		resp.WriteHeader(code)
		resp.Write([]byte(err.Error()))
		return
	}

	// Write out the JSON object
	if obj != nil {

		resp.Header().Set("Content-Type", "application/json")
		resp.WriteHeader(statusCode)

		// Set up the pipe to write data directly into the Reader.
		pr, pw := io.Pipe()

		// Write JSON-encoded data to the Writer end of the pipe.
		// Write in a separate concurrent goroutine, and remember
		// to Close the PipeWriter, to signal to the paired PipeReader
		// that we’re done writing.
		go func() {
			pw.CloseWithError(json.NewEncoder(pw).Encode(obj))
		}()

		io.Copy(resp, pr)

		// encoding/json library has a specific bug(feature) to turn empty slices into json null object,
		// let's make an empty array instead
		// resp.Write(buf)
	}
}

// corsHeadersMiddleware - cors middleware
func corsHeadersMiddleware(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	rw.Header().Set("Access-Control-Allow-Origin", "*")
	rw.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
	rw.Header().Set("Access-Control-Allow-Headers",
		"Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")

	rw.Header().Set("Access-Control-Expose-Headers", "Authorization")
	rw.Header().Set("Access-Control-Request-Headers", "Authorization")

	if r.Method == "OPTIONS" {
		rw.WriteHeader(200)
		return
	}

	next(rw, r)
}

type UserInfo struct {
	ID            string `json:"id"`
	Name          string `json:"name"`
	Username      string `json:"username"`
	Avatar        string `json:"avatar"`
	Status        int    `json:"status"`
	LastLoginIP   string `json:"last_login_ip"`
	LastLoginTime int64  `json:"last_login_time"`
	RoleID        string `json:"role_id"`
}

func (s *TriggerServer) userInfoHandler(resp http.ResponseWriter, req *http.Request) {
	ui := UserInfo{
		ID:            "1",
		Name:          s.username,
		Avatar:        "",
		Status:        1,
		LastLoginIP:   "",
		LastLoginTime: time.Now().Unix(),
		RoleID:        "admin",
	}

	response(&ui, 200, nil, resp, req)
}

func (s *TriggerServer) logoutHandler(resp http.ResponseWriter, req *http.Request) {

	resp.WriteHeader(200)
	resp.Write([]byte(`{}`))
}
<commit_msg>resources, policies handlers<commit_after>package http

import (
	"context"
	"encoding/json"
	"fmt"
	"io"

	"net/http"
	"os"
	"strings"
	"time"

	"github.com/gorilla/mux"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/urfave/negroni"

	"github.com/keel-hq/keel/approvals"
	"github.com/keel-hq/keel/internal/k8s"
	"github.com/keel-hq/keel/provider"
	"github.com/keel-hq/keel/provider/kubernetes"
	"github.com/keel-hq/keel/types"
	"github.com/keel-hq/keel/version"

	log "github.com/sirupsen/logrus"
)

// Opts - http server options
type Opts struct {
	Port int

	// available providers
	Providers provider.Providers

	ApprovalManager approvals.Manager

	// Username and password are used for basic auth
	Username string
	Password string

	GRC *k8s.GenericResourceCache

	KubernetesClient kubernetes.Implementer
}

// TriggerServer - webhook trigger & healthcheck server
type TriggerServer struct {
	grc              *k8s.GenericResourceCache
	kubernetesClient kubernetes.Implementer

	providers        provider.Providers
	approvalsManager approvals.Manager
	port             int
	server           *http.Server
	router           *mux.Router

	// basic auth
	username string
	password string
}

// NewTriggerServer - create new HTTP trigger based server
func NewTriggerServer(opts *Opts) *TriggerServer {
	return &TriggerServer{
		port:             opts.Port,
		grc:              opts.GRC,
		kubernetesClient: opts.KubernetesClient,
		providers:        opts.Providers,
		approvalsManager: opts.ApprovalManager,
		router:           mux.NewRouter(),
		username:         opts.Username,
		password:         opts.Password,
	}
}

// Start - start server
func (s *TriggerServer) Start() error {

	s.registerRoutes(s.router)

	n := negroni.New(negroni.NewRecovery())
	// n.UseHandler(negroni.HandlerFunc(corsHeadersMiddleware))
	n.Use(negroni.HandlerFunc(corsHeadersMiddleware))
	n.UseHandler(s.router)

	s.server = &http.Server{
		Addr:    fmt.Sprintf(":%d", s.port),
		Handler: n,
	}

	log.WithFields(log.Fields{
		"port": s.port,
	}).Info("webhook trigger server starting...")
	return s.server.ListenAndServe()
}

// Stop - stop webhook server
func (s *TriggerServer) Stop() {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	s.server.Shutdown(ctx)
}

func getID(req *http.Request) string {
	return mux.Vars(req)["id"]
}

func (s *TriggerServer) registerRoutes(mux *mux.Router) {

	if os.Getenv("DEBUG") == "true" {
		DebugHandler{}.AddRoutes(mux)
	}

	// health endpoint for k8s to be happy
	mux.HandleFunc("/healthz", s.healthHandler).Methods("GET", "OPTIONS")
	// version handler
	mux.HandleFunc("/version", s.versionHandler).Methods("GET", "OPTIONS")

	// auth
	mux.HandleFunc("/v1/user/info", s.requireAdminAuthorization(s.userInfoHandler)).Methods("GET", "OPTIONS")
	mux.HandleFunc("/v1/user/logout", s.requireAdminAuthorization(s.logoutHandler)).Methods("GET", "OPTIONS")

	// approvals
	mux.HandleFunc("/v1/approvals", s.requireAdminAuthorization(s.approvalsHandler)).Methods("GET", "OPTIONS")
	// approving/rejecting
	mux.HandleFunc("/v1/approvals", s.requireAdminAuthorization(s.approvalApproveHandler)).Methods("POST", "OPTIONS")

	// available resources
	mux.HandleFunc("/v1/resources", s.requireAdminAuthorization(s.resourcesHandler)).Methods("GET", "OPTIONS")

	mux.HandleFunc("/v1/policies", s.requireAdminAuthorization(s.policyUpdateHandler)).Methods("PUT", "OPTIONS")

	// tracked images
	mux.HandleFunc("/v1/tracked", s.requireAdminAuthorization(s.trackedHandler)).Methods("GET", "OPTIONS")

	mux.Handle("/metrics", promhttp.Handler())

	s.registerWebhookRoutes(mux)
}

func (s *TriggerServer) registerWebhookRoutes(mux *mux.Router) {
	mux.HandleFunc("/v1/webhooks/native", s.nativeHandler).Methods("POST", "OPTIONS")
	mux.HandleFunc("/v1/webhooks/dockerhub", s.dockerHubHandler).Methods("POST", "OPTIONS")
	mux.HandleFunc("/v1/webhooks/quay", s.quayHandler).Methods("POST", "OPTIONS")
	mux.HandleFunc("/v1/webhooks/azure", s.azureHandler).Methods("POST", "OPTIONS")

	// Docker registry notifications, used by Docker, Gitlab, Harbor
	// https://docs.docker.com/registry/notifications/
	//https://docs.gitlab.com/ee/administration/container_registry.html#configure-container-registry-notifications
	mux.HandleFunc("/v1/webhooks/registry", s.registryNotificationHandler).Methods("POST", "OPTIONS")
}

func (s *TriggerServer) healthHandler(resp http.ResponseWriter, req *http.Request) {
	resp.WriteHeader(http.StatusOK)
}

func (s *TriggerServer) versionHandler(resp http.ResponseWriter, req *http.Request) {
	v := version.GetKeelVersion()

	encoded, err := json.Marshal(v)
	if err != nil {
		log.WithError(err).Error("trigger.http: failed to marshal version")
		resp.WriteHeader(http.StatusInternalServerError)
		return
	}

	resp.WriteHeader(http.StatusOK)
	resp.Write(encoded)
}

func (s *TriggerServer) trigger(event types.Event) error {
	return s.providers.Submit(event)
}

func (s *TriggerServer) requireAdminAuthorization(next http.HandlerFunc) http.HandlerFunc {
	return func(rw http.ResponseWriter, r *http.Request) {

		if s.username == "" && s.password == "" {
			next(rw, r)
			return
		}

		rw.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)

		username, password, ok := r.BasicAuth()
		if ok && username == s.username && password == s.password {
			next(rw, r)
			return
		}

		http.Error(rw, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
	}
}

func response(obj interface{}, statusCode int, err error, resp http.ResponseWriter, req *http.Request) {
	// Check for an error

	if err != nil {

		code := 500
		errMsg := err.Error()
		if strings.Contains(errMsg, "Permission denied") {
			code = 403
		}
		resp.WriteHeader(code)
		resp.Write([]byte(err.Error()))
		return
	}

	// Write out the JSON object
	if obj != nil {

		resp.Header().Set("Content-Type", "application/json")
		resp.WriteHeader(statusCode)

		// Set up the pipe to write data directly into the Reader.
		pr, pw := io.Pipe()

		// Write JSON-encoded data to the Writer end of the pipe.
		// Write in a separate concurrent goroutine, and remember
		// to Close the PipeWriter, to signal to the paired PipeReader
		// that we’re done writing.
		go func() {
			pw.CloseWithError(json.NewEncoder(pw).Encode(obj))
		}()

		io.Copy(resp, pr)

		// encoding/json library has a specific bug(feature) to turn empty slices into json null object,
		// let's make an empty array instead
		// resp.Write(buf)
	}
}

// corsHeadersMiddleware - cors middleware
func corsHeadersMiddleware(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	rw.Header().Set("Access-Control-Allow-Origin", "*")
	rw.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
	rw.Header().Set("Access-Control-Allow-Headers",
		"Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")

	rw.Header().Set("Access-Control-Expose-Headers", "Authorization")
	rw.Header().Set("Access-Control-Request-Headers", "Authorization")

	if r.Method == "OPTIONS" {
		rw.WriteHeader(200)
		return
	}

	next(rw, r)
}

type UserInfo struct {
	ID            string `json:"id"`
	Name          string `json:"name"`
	Username      string `json:"username"`
	Avatar        string `json:"avatar"`
	Status        int    `json:"status"`
	LastLoginIP   string `json:"last_login_ip"`
	LastLoginTime int64  `json:"last_login_time"`
	RoleID        string `json:"role_id"`
}

func (s *TriggerServer) userInfoHandler(resp http.ResponseWriter, req *http.Request) {
	ui := UserInfo{
		ID:            "1",
		Name:          s.username,
		Avatar:        "",
		Status:        1,
		LastLoginIP:   "",
		LastLoginTime: time.Now().Unix(),
		RoleID:        "admin",
	}

	response(&ui, 200, nil, resp, req)
}

func (s *TriggerServer) logoutHandler(resp http.ResponseWriter, req *http.Request) {

	resp.WriteHeader(200)
	resp.Write([]byte(`{}`))
}

type APIResponse struct {
	Status string `json:"status"`
}
<|endoftext|>


<commit_before>package teem

import (
	"fmt"
	"os"
	"sync"

	log "github.com/F5Networks/k8s-bigip-ctlr/pkg/vlogger"
	"github.com/f5devcentral/go-bigip/f5teem"
	"github.com/google/uuid"
)

// ResourceTypes structure maintains a map of namespaces to resource count
type ResourceTypes struct {
	Ingresses       map[string]int
	Routes          map[string]int
	Configmaps      map[string]int
	VirtualServer   map[string]int
	TransportServer map[string]int
	ExternalDNS     map[string]int
	IngressLink     map[string]int
	IPAMVS          map[string]int
	IPAMTS          map[string]int
	IPAMSvcLB       map[string]int
}

// TeemsData structure contains supporting data to be posted to TEEM's server
type TeemsData struct {
	sync.Mutex
	CisVersion      string
	SDNType         string
	Agent           string
	PoolMemberType  string
	DateOfCISDeploy string
	PlatformInfo    string
	ResourceType    ResourceTypes
	AccessEnabled   bool // Will be set to false if network rules don't permit
	RegistrationKey string
}

const (
	TOTAL      = "total"
	staging    = "staging"
	production = "production"
)

// PostTeemsData posts data to TEEM server and returns a boolean response useful to decide if network rules permit to access server
func (td *TeemsData) PostTeemsData() bool {
	if !td.AccessEnabled {
		return false
	}
	apiEnv := os.Getenv("TEEM_API_ENVIRONMENT")
	var apiKey string
	if apiEnv != "" {
		if apiEnv == staging {
			apiKey = os.Getenv("TEEM_API_KEY")
			if len(apiKey) == 0 {
				log.Error("API key missing to post to staging teem server")
				return false
			}
		} else if apiEnv != production {
			log.Error("Invalid TEEM_API_ENVIRONMENT. Unset to use production server")
			return false
		}
	}
	// Retry only once upon failure
	var retryCount = 1
	var accessEnabled = true

	assetInfo := f5teem.AssetInfo{
		Name:    "CIS-Ecosystem",
		Version: fmt.Sprintf("CIS/v%v", td.CisVersion),
		Id:      uuid.New().String(),
	}
	teemDevice := f5teem.AnonymousClient(assetInfo, apiKey)
	types := []map[string]int{td.ResourceType.IngressLink, td.ResourceType.Ingresses, td.ResourceType.Routes,
		td.ResourceType.Configmaps, td.ResourceType.VirtualServer, td.ResourceType.TransportServer,
		td.ResourceType.ExternalDNS, td.ResourceType.IPAMVS, td.ResourceType.IPAMTS, td.ResourceType.IPAMSvcLB}
	var sum int
	for _, rscType := range types {
		sum = 0
		rscType[TOTAL] = 0 // Reset previous iteration sum
		for _, count := range rscType {
			sum += count
		}
		rscType[TOTAL] = sum
	}
	data := map[string]interface{}{
		"platformInfo":             td.PlatformInfo,
		"agent":                    td.Agent,
		"dateOfCISDeploy":          td.DateOfCISDeploy,
		"mode":                     td.PoolMemberType,
		"sdnType":                  td.SDNType,
		"registrationKey":          td.RegistrationKey,
		"ingressCount":             td.ResourceType.Ingresses[TOTAL],
		"routesCount":              td.ResourceType.Routes[TOTAL],
		"configmapsCount":          td.ResourceType.Configmaps[TOTAL],
		"virtualServerCount":       td.ResourceType.VirtualServer[TOTAL],
		"transportServerCount":     td.ResourceType.TransportServer[TOTAL],
		"externalDNSCount":         td.ResourceType.ExternalDNS[TOTAL],
		"ingressLinkCount":         td.ResourceType.IngressLink[TOTAL],
		"ipamVirtualServerCount":   td.ResourceType.IPAMVS[TOTAL],
		"ipamTransportServerCount": td.ResourceType.IPAMTS[TOTAL],
		"ipamSvcLBCount":           td.ResourceType.IPAMSvcLB[TOTAL],
	}
	for retryCount >= 0 {
		err := teemDevice.Report(data, "CIS Telemetry Data", "1")
		if err != nil {
			log.Errorf("Error reporting telemetry data :%v", err)
			retryCount--
			if retryCount < 0 {
				accessEnabled = false
			}
		} else {
			retryCount = -1
		}
	}

	return accessEnabled
}
<commit_msg>Move teem logs to debug (#2227)<commit_after>package teem

import (
	"fmt"
	"os"
	"strings"
	"sync"

	log "github.com/F5Networks/k8s-bigip-ctlr/pkg/vlogger"
	"github.com/f5devcentral/go-bigip/f5teem"
	"github.com/google/uuid"
)

// ResourceTypes structure maintains a map of namespaces to resource count
type ResourceTypes struct {
	Ingresses       map[string]int
	Routes          map[string]int
	Configmaps      map[string]int
	VirtualServer   map[string]int
	TransportServer map[string]int
	ExternalDNS     map[string]int
	IngressLink     map[string]int
	IPAMVS          map[string]int
	IPAMTS          map[string]int
	IPAMSvcLB       map[string]int
}

// TeemsData structure contains supporting data to be posted to TEEM's server
type TeemsData struct {
	sync.Mutex
	CisVersion      string
	SDNType         string
	Agent           string
	PoolMemberType  string
	DateOfCISDeploy string
	PlatformInfo    string
	ResourceType    ResourceTypes
	AccessEnabled   bool // Will be set to false if network rules don't permit
	RegistrationKey string
}

const (
	TOTAL      = "total"
	staging    = "staging"
	production = "production"
)

// PostTeemsData posts data to TEEM server and returns a boolean response useful to decide if network rules permit to access server
func (td *TeemsData) PostTeemsData() bool {
	if !td.AccessEnabled {
		return false
	}
	apiEnv := os.Getenv("TEEM_API_ENVIRONMENT")
	var apiKey string
	if apiEnv != "" {
		if apiEnv == staging {
			apiKey = os.Getenv("TEEM_API_KEY")
			if len(apiKey) == 0 {
				log.Error("API key missing to post to staging teem server")
				return false
			}
		} else if apiEnv != production {
			log.Error("Invalid TEEM_API_ENVIRONMENT. Unset to use production server")
			return false
		}
	}
	// Retry only once upon failure
	var retryCount = 1
	var accessEnabled = true

	assetInfo := f5teem.AssetInfo{
		Name:    "CIS-Ecosystem",
		Version: fmt.Sprintf("CIS/v%v", td.CisVersion),
		Id:      uuid.New().String(),
	}
	teemDevice := f5teem.AnonymousClient(assetInfo, apiKey)
	types := []map[string]int{td.ResourceType.IngressLink, td.ResourceType.Ingresses, td.ResourceType.Routes,
		td.ResourceType.Configmaps, td.ResourceType.VirtualServer, td.ResourceType.TransportServer,
		td.ResourceType.ExternalDNS, td.ResourceType.IPAMVS, td.ResourceType.IPAMTS, td.ResourceType.IPAMSvcLB}
	var sum int
	for _, rscType := range types {
		sum = 0
		rscType[TOTAL] = 0 // Reset previous iteration sum
		for _, count := range rscType {
			sum += count
		}
		rscType[TOTAL] = sum
	}
	data := map[string]interface{}{
		"platformInfo":             td.PlatformInfo,
		"agent":                    td.Agent,
		"dateOfCISDeploy":          td.DateOfCISDeploy,
		"mode":                     td.PoolMemberType,
		"sdnType":                  td.SDNType,
		"registrationKey":          td.RegistrationKey,
		"ingressCount":             td.ResourceType.Ingresses[TOTAL],
		"routesCount":              td.ResourceType.Routes[TOTAL],
		"configmapsCount":          td.ResourceType.Configmaps[TOTAL],
		"virtualServerCount":       td.ResourceType.VirtualServer[TOTAL],
		"transportServerCount":     td.ResourceType.TransportServer[TOTAL],
		"externalDNSCount":         td.ResourceType.ExternalDNS[TOTAL],
		"ingressLinkCount":         td.ResourceType.IngressLink[TOTAL],
		"ipamVirtualServerCount":   td.ResourceType.IPAMVS[TOTAL],
		"ipamTransportServerCount": td.ResourceType.IPAMTS[TOTAL],
		"ipamSvcLBCount":           td.ResourceType.IPAMSvcLB[TOTAL],
	}
	for retryCount >= 0 {
		err := teemDevice.Report(data, "CIS Telemetry Data", "1")
		if err != nil && !strings.Contains(err.Error(), "request-limit") {
			//log teem error for debugging
			//teems send error code 429 with request-limit, if the limit 30 requests per hour is hit
			//TEEM will start accepting them again automatically after the waiting period.
			log.Debugf("Error reporting telemetry data :%v", err)
			retryCount--
			if retryCount < 0 {
				accessEnabled = false
			}
		} else {
			retryCount = -1
		}
	}

	return accessEnabled
}
<|endoftext|>


<commit_before>package day8

import (
	"fmt"

	"github.com/domdavis/adventofcode/2016/day8/display"
)

func Solution() string {
	return fmt.Sprintf("Part 1: %d, Part 2: %s",
		part1(data), "Not yet done")
}

func part1(input string) int {
	s := display.New(50, 6)
	s.BulkTransform(input)
	return s.Count()
}
<commit_msg>Add day 8 part 2 solution<commit_after>package day8

import (
	"fmt"

	"github.com/domdavis/adventofcode/2016/day8/display"
)

func Solution() string {
	s := display.New(50, 6)
	s.BulkTransform(data)
	return fmt.Sprintf("Part 1: %d, Part 2:\n%s",
		s.Count(), s)
}
<|endoftext|>


<commit_before>package plugin

import (
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"os"
	"os/signal"
	"runtime"
	"strconv"
	"sync/atomic"

	pluginrpc "github.com/hashicorp/otto/rpc"
)

// The APIVersion is outputted along with the RPC address. The plugin
// client validates this API version and will show an error if it doesn't
// know how to speak it.
const APIVersion = "1"

// The "magic cookie" is used to verify that the user intended to
// actually run this binary. If this cookie isn't present as an
// environmental variable, then we bail out early with an error.
const MagicCookieKey = "OTTO_PLUGIN_MAGIC_COOKIE"
const MagicCookieValue = "11aab7ff21cb9ff7b0e9975d53f17a8dab571eac9b5ff0191730046698f07b7f"

// ServeOpts configures what sorts of plugins are served.
type ServeOpts struct {
	AppFunc pluginrpc.AppFunc
}

// Serve serves the plugins given by ServeOpts.
//
// Serve doesn't return until the plugin is done being executed. Any
// errors will be outputted to the log.
func Serve(opts *ServeOpts) {
	// First check the cookie
	if os.Getenv(MagicCookieKey) != MagicCookieValue {
		fmt.Fprintf(os.Stderr,
			"This binary is an Otto plugin. These are not meant to be\n"+
				"executed directly. Please execute `otto`, which will load\n"+
				"any plugins automatically.\n")
		os.Exit(1)
	}

	// Logging goes to the original stderr
	log.SetOutput(os.Stderr)

	// Create our new stdout, stderr files. These will override our built-in
	// stdout/stderr so that it works across the stream boundary.
	stdin_r, stdin_w, err := os.Pipe()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error preparing Otto plugin: %s\n", err)
		os.Exit(1)
	}
	stdout_r, stdout_w, err := os.Pipe()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error preparing Otto plugin: %s\n", err)
		os.Exit(1)
	}
	stderr_r, stderr_w, err := os.Pipe()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error preparing Otto plugin: %s\n", err)
		os.Exit(1)
	}

	// Register a listener so we can accept a connection
	listener, err := serverListener()
	if err != nil {
		log.Printf("[ERR] plugin init: %s", err)
		return
	}
	defer listener.Close()

	// Create the RPC server to dispense
	server := &pluginrpc.Server{
		AppFunc: opts.AppFunc,
		Stdin:   stdin_w,
		Stdout:  stdout_r,
		Stderr:  stderr_r,
	}

	// Output the address and service name to stdout so that core can bring it up.
	log.Printf("Plugin address: %s %s\n",
		listener.Addr().Network(), listener.Addr().String())
	fmt.Printf("%s|%s|%s\n",
		APIVersion,
		listener.Addr().Network(),
		listener.Addr().String())
	os.Stdout.Sync()

	// Eat the interrupts
	ch := make(chan os.Signal, 1)
	signal.Notify(ch, os.Interrupt)
	go func() {
		var count int32 = 0
		for {
			<-ch
			newCount := atomic.AddInt32(&count, 1)
			log.Printf(
				"Received interrupt signal (count: %d). Ignoring.",
				newCount)
		}
	}()

	// Serve
	server.Accept(listener)
}

func serverListener() (net.Listener, error) {
	if runtime.GOOS == "windows" {
		return serverListener_tcp()
	}

	return serverListener_unix()
}

func serverListener_tcp() (net.Listener, error) {
	minPort, err := strconv.ParseInt(os.Getenv("OTTO_PLUGIN_MIN_PORT"), 10, 32)
	if err != nil {
		return nil, err
	}

	maxPort, err := strconv.ParseInt(os.Getenv("OTTO_PLUGIN_MAX_PORT"), 10, 32)
	if err != nil {
		return nil, err
	}

	for port := minPort; port <= maxPort; port++ {
		address := fmt.Sprintf("127.0.0.1:%d", port)
		listener, err := net.Listen("tcp", address)
		if err == nil {
			return listener, nil
		}
	}

	return nil, errors.New("Couldn't bind plugin TCP listener")
}

func serverListener_unix() (net.Listener, error) {
	tf, err := ioutil.TempFile("", "otto-plugin")
	if err != nil {
		return nil, err
	}
	path := tf.Name()

	// Close the file and remove it because it has to not exist for
	// the domain socket.
	if err := tf.Close(); err != nil {
		return nil, err
	}
	if err := os.Remove(path); err != nil {
		return nil, err
	}

	return net.Listen("unix", path)
}
<commit_msg>plugin: hook up the magic os stdout, stderr, stdin<commit_after>package plugin

import (
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"os"
	"os/signal"
	"runtime"
	"strconv"
	"sync/atomic"

	pluginrpc "github.com/hashicorp/otto/rpc"
)

// The APIVersion is outputted along with the RPC address. The plugin
// client validates this API version and will show an error if it doesn't
// know how to speak it.
const APIVersion = "1"

// The "magic cookie" is used to verify that the user intended to
// actually run this binary. If this cookie isn't present as an
// environmental variable, then we bail out early with an error.
const MagicCookieKey = "OTTO_PLUGIN_MAGIC_COOKIE"
const MagicCookieValue = "11aab7ff21cb9ff7b0e9975d53f17a8dab571eac9b5ff0191730046698f07b7f"

// ServeOpts configures what sorts of plugins are served.
type ServeOpts struct {
	AppFunc pluginrpc.AppFunc
}

// Serve serves the plugins given by ServeOpts.
//
// Serve doesn't return until the plugin is done being executed. Any
// errors will be outputted to the log.
func Serve(opts *ServeOpts) {
	// First check the cookie
	if os.Getenv(MagicCookieKey) != MagicCookieValue {
		fmt.Fprintf(os.Stderr,
			"This binary is an Otto plugin. These are not meant to be\n"+
				"executed directly. Please execute `otto`, which will load\n"+
				"any plugins automatically.\n")
		os.Exit(1)
	}

	// Logging goes to the original stderr
	log.SetOutput(os.Stderr)

	// Create our new stdout, stderr files. These will override our built-in
	// stdout/stderr so that it works across the stream boundary.
	stdin_r, stdin_w, err := os.Pipe()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error preparing Otto plugin: %s\n", err)
		os.Exit(1)
	}
	stdout_r, stdout_w, err := os.Pipe()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error preparing Otto plugin: %s\n", err)
		os.Exit(1)
	}
	stderr_r, stderr_w, err := os.Pipe()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error preparing Otto plugin: %s\n", err)
		os.Exit(1)
	}

	// Register a listener so we can accept a connection
	listener, err := serverListener()
	if err != nil {
		log.Printf("[ERR] plugin init: %s", err)
		return
	}
	defer listener.Close()

	// Create the RPC server to dispense
	server := &pluginrpc.Server{
		AppFunc: opts.AppFunc,
		Stdin:   stdin_w,
		Stdout:  stdout_r,
		Stderr:  stderr_r,
	}

	// Output the address and service name to stdout so that core can bring it up.
	log.Printf("Plugin address: %s %s\n",
		listener.Addr().Network(), listener.Addr().String())
	fmt.Printf("%s|%s|%s\n",
		APIVersion,
		listener.Addr().Network(),
		listener.Addr().String())
	os.Stdout.Sync()

	// Eat the interrupts
	ch := make(chan os.Signal, 1)
	signal.Notify(ch, os.Interrupt)
	go func() {
		var count int32 = 0
		for {
			<-ch
			newCount := atomic.AddInt32(&count, 1)
			log.Printf(
				"Received interrupt signal (count: %d). Ignoring.",
				newCount)
		}
	}()

	// Set our new stdin, out, err
	os.Stdin = stdin_r
	os.Stdout = stdout_w
	os.Stderr = stderr_w

	// Serve
	server.Accept(listener)
}

func serverListener() (net.Listener, error) {
	if runtime.GOOS == "windows" {
		return serverListener_tcp()
	}

	return serverListener_unix()
}

func serverListener_tcp() (net.Listener, error) {
	minPort, err := strconv.ParseInt(os.Getenv("OTTO_PLUGIN_MIN_PORT"), 10, 32)
	if err != nil {
		return nil, err
	}

	maxPort, err := strconv.ParseInt(os.Getenv("OTTO_PLUGIN_MAX_PORT"), 10, 32)
	if err != nil {
		return nil, err
	}

	for port := minPort; port <= maxPort; port++ {
		address := fmt.Sprintf("127.0.0.1:%d", port)
		listener, err := net.Listen("tcp", address)
		if err == nil {
			return listener, nil
		}
	}

	return nil, errors.New("Couldn't bind plugin TCP listener")
}

func serverListener_unix() (net.Listener, error) {
	tf, err := ioutil.TempFile("", "otto-plugin")
	if err != nil {
		return nil, err
	}
	path := tf.Name()

	// Close the file and remove it because it has to not exist for
	// the domain socket.
	if err := tf.Close(); err != nil {
		return nil, err
	}
	if err := os.Remove(path); err != nil {
		return nil, err
	}

	return net.Listen("unix", path)
}
<|endoftext|>


<commit_before>package felica

import (
	"errors"
	"fmt"
	"io/ioutil"
	"launchpad.net/goyaml"
	"os"
	"path/filepath"
	"reflect"
	"strings"
	"unsafe"
)

// C言語で使うためにデータにアクセスするポインタを取得する
func DataPtr(data *[]byte) unsafe.Pointer {
	raw := (*reflect.SliceHeader)(unsafe.Pointer(data)).Data

	return unsafe.Pointer(raw)
}

// ファイルを検索ディレクトリから探す
func search_file(fname string, dirs []string) (string, error) {
	for _, dir := range dirs {
		path := filepath.Join(dir, fname)

		if _, err := os.Stat(path); err == nil {
			return path, nil
		}
	}

	return "", errors.New("file not found")
}

// YAML を読込む
func LoadYAML(fname string) (map[interface{}]interface{}, error) {
	cmd, _ := filepath.EvalSymlinks(os.Args[0])
	bindir := filepath.Dir(cmd)
	moddir := filepath.Join(bindir, strings.TrimSuffix(fname, ".yml"))

	dirs := []string{".", bindir, moddir}
	path, err := search_file(fname, dirs)

	if err != nil {
		// ファイルが見つからなかった
		return nil, err
	}

	contents, err := ioutil.ReadFile(path)
	if err != nil {
		// 読込みに失敗
		return nil, err
	}

	m := make(map[interface{}]interface{})
	err = goyaml.Unmarshal(contents, &m)

	return m, err
}

// テーブルを検索して表示用の文字列を返す
func DispName(tables map[interface{}]interface{}, name string, value int, base int, opt_values ...int) interface{} {
	var v interface{}

	t := tables[name]

	if t != nil {
		v = t.(map[interface{}]interface{})[value]
	}

	if v == nil {
		if 0 < len(opt_values) {
			value = opt_values[0]
		}

		if base != 0 {
			f := fmt.Sprintf("%s%dX", "0x%0", base)
			v = fmt.Sprintf(f, value)
		} else {
			v = value
		}
	}

	return v
}
<commit_msg>半角全角混じりの文字を揃える関数<commit_after>package felica

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"reflect"
	"strings"
	"unsafe"

	"github.com/gfx/go-visual_width"
	"launchpad.net/goyaml"
)

// C言語で使うためにデータにアクセスするポインタを取得する
func DataPtr(data *[]byte) unsafe.Pointer {
	raw := (*reflect.SliceHeader)(unsafe.Pointer(data)).Data

	return unsafe.Pointer(raw)
}

// ファイルを検索ディレクトリから探す
func search_file(fname string, dirs []string) (string, error) {
	for _, dir := range dirs {
		path := filepath.Join(dir, fname)

		if _, err := os.Stat(path); err == nil {
			return path, nil
		}
	}

	return "", errors.New("file not found")
}

// YAML を読込む
func LoadYAML(fname string) (map[interface{}]interface{}, error) {
	cmd, _ := filepath.EvalSymlinks(os.Args[0])
	bindir := filepath.Dir(cmd)
	moddir := filepath.Join(bindir, strings.TrimSuffix(fname, ".yml"))

	dirs := []string{".", bindir, moddir}
	path, err := search_file(fname, dirs)

	if err != nil {
		// ファイルが見つからなかった
		return nil, err
	}

	contents, err := ioutil.ReadFile(path)
	if err != nil {
		// 読込みに失敗
		return nil, err
	}

	m := make(map[interface{}]interface{})
	err = goyaml.Unmarshal(contents, &m)

	return m, err
}

// テーブルを検索して表示用の文字列を返す
func DispName(tables map[interface{}]interface{}, name string, value int, base int, opt_values ...int) interface{} {
	var v interface{}

	t := tables[name]

	if t != nil {
		v = t.(map[interface{}]interface{})[value]
	}

	if v == nil {
		if 0 < len(opt_values) {
			value = opt_values[0]
		}

		if base != 0 {
			f := fmt.Sprintf("%s%dX", "0x%0", base)
			v = fmt.Sprintf(f, value)
		} else {
			v = value
		}
	}

	return v
}

// 指定された表示文字になるように調整する
func DispString(str string, width int) string {
	s := visual_width.Truncate(str, true, width, "")
	n := width - visual_width.Measure(s, true)

	if 0 < n {
		s = s + strings.Repeat(" ", n)
	}

	return s
}
<|endoftext|>


<commit_before>package rcmgr

import (
	"fmt"
	"sync"

	"github.com/libp2p/go-buffer-pool"
	"github.com/libp2p/go-libp2p-core/network"
)

// Basic resource mamagement.
type Resources struct {
	limit    Limit
	nconns   int
	nstreams int
	memory   int64
	buffers  map[interface{}][]byte
}

// DAG ResourceScopes.
// Resources accounts for the node usage, constraints signify
// the dependencies that constrain resource usage.
type ResourceScope struct {
	mx   sync.Mutex
	rc   *Resources
	done bool

	constraints []*ResourceScope
}

var _ network.ResourceScope = (*ResourceScope)(nil)
var _ network.TransactionalScope = (*ResourceScope)(nil)

// Resources implementation
func (rc *Resources) checkMemory(rsvp int) error {
	// overflow check; this also has the side-effect that we cannot reserve negative memory.
	newmem := rc.memory + int64(rsvp)
	if newmem < rc.memory {
		return fmt.Errorf("memory reservation overflow: %w", ErrResourceLimitExceeded)
	}

	// limit check
	if newmem > rc.limit.GetMemoryLimit() {
		return fmt.Errorf("cannot reserve memory: %w", ErrResourceLimitExceeded)
	}

	return nil
}

func (rc *Resources) releaseBuffers() {
	for key, buf := range rc.buffers {
		pool.Put(buf)
		delete(rc.buffers, key)
	}
}

func (rc *Resources) reserveMemory(size int) error {
	if err := rc.checkMemory(size); err != nil {
		return err
	}

	rc.memory += int64(size)
	return nil
}

func (rc *Resources) releaseMemory(size int64) {
	rc.memory -= size

	// sanity check for bugs upstream
	if rc.memory < 0 {
		panic("BUG: too much memory released")
	}
}

func (rc *Resources) getBuffer(size int) ([]byte, error) {
	if err := rc.checkMemory(size); err != nil {
		return nil, err
	}

	buf := pool.Get(size)

	rc.memory += int64(size)
	rc.buffers[buf] = buf

	return buf, nil
}

func (rc *Resources) growBuffer(oldbuf []byte, newsize int) ([]byte, error) {
	grow := newsize - len(oldbuf)
	if err := rc.checkMemory(grow); err != nil {
		return nil, err
	}

	newbuf := pool.Get(newsize)
	copy(newbuf, oldbuf)

	rc.memory += int64(grow)
	rc.buffers[newbuf] = newbuf
	delete(rc.buffers, oldbuf)

	return newbuf, nil
}

func (rc *Resources) releaseBuffer(buf []byte) {
	rc.memory -= int64(len(buf))

	// sanity check for bugs upstream
	if rc.memory < 0 {
		panic("BUG: too much memory released")
	}

	delete(rc.buffers, buf)
	pool.Put(buf)
}

func (rc *Resources) addStream(count int) error {
	if rc.nstreams+count > rc.limit.GetStreamLimit() {
		return fmt.Errorf("cannot reserve stream: %w", ErrResourceLimitExceeded)
	}

	rc.nstreams += count
	return nil
}

func (rc *Resources) removeStream(count int) {
	rc.nstreams -= count

	if rc.nstreams < 0 {
		panic("BUG: too many streams released")
	}
}

func (rc *Resources) addConn(count int) error {
	if rc.nconns+count > rc.limit.GetConnLimit() {
		return fmt.Errorf("cannot reserve connection: %w", ErrResourceLimitExceeded)
	}

	rc.nconns += count
	return nil
}

func (rc *Resources) removeConn(count int) {
	rc.nconns -= count

	if rc.nconns < 0 {
		panic("BUG: too many connections released")
	}
}

func (rc *Resources) stat() network.ScopeStat {
	return network.ScopeStat{
		Memory:     rc.memory,
		NumConns:   rc.nconns,
		NumStreams: rc.nstreams,
	}
}

// ResourceScope implementation
func (s *ResourceScope) ReserveMemory(size int) error {
	s.mx.Lock()
	defer s.mx.Unlock()

	if s.done {
		return ErrResourceScopeClosed
	}

	if err := s.rc.reserveMemory(size); err != nil {
		return err
	}

	if err := s.reserveMemoryForConstraints(size); err != nil {
		s.rc.releaseMemory(int64(size))
		return err
	}

	return nil
}

func (s *ResourceScope) reserveMemoryForConstraints(size int) error {
	var reserved int
	var err error
	for _, cst := range s.constraints {
		if err = cst.ReserveMemoryForChild(size); err != nil {
			break
		}
		reserved++
	}

	if err != nil {
		// we failed because of a constraint; undo memory reservations
		for _, cst := range s.constraints[:reserved] {
			cst.ReleaseMemoryForChild(int64(size))
		}
	}

	return err
}

func (s *ResourceScope) ReserveMemoryForChild(size int) error {
	s.mx.Lock()
	defer s.mx.Unlock()

	if s.done {
		return ErrResourceScopeClosed
	}

	return s.rc.reserveMemory(size)
}

func (s *ResourceScope) ReleaseMemory(size int) {
	s.mx.Lock()
	defer s.mx.Unlock()

	if s.done {
		return
	}

	s.rc.releaseMemory(int64(size))
	for _, cst := range s.constraints {
		cst.ReleaseMemoryForChild(int64(size))
	}
}

func (s *ResourceScope) ReleaseMemoryForChild(size int64) {
	s.mx.Lock()
	defer s.mx.Unlock()

	if s.done {
		return
	}

	s.rc.releaseMemory(size)
}

func (s *ResourceScope) GetBuffer(size int) ([]byte, error) {
	s.mx.Lock()
	defer s.mx.Unlock()

	if s.done {
		return nil, ErrResourceScopeClosed
	}

	buf, err := s.rc.getBuffer(size)
	if err != nil {
		return nil, err
	}

	if err := s.reserveMemoryForConstraints(size); err != nil {
		s.rc.releaseBuffer(buf)
		return nil, err
	}

	return buf, err
}

func (s *ResourceScope) GrowBuffer(oldbuf []byte, newsize int) ([]byte, error) {
	s.mx.Lock()
	defer s.mx.Unlock()

	if s.done {
		return nil, ErrResourceScopeClosed
	}

	buf, err := s.rc.growBuffer(oldbuf, newsize)
	if err != nil {
		return nil, err
	}

	if err := s.reserveMemoryForConstraints(newsize - len(oldbuf)); err != nil {
		s.rc.releaseBuffer(buf)
		return nil, err
	}

	return buf, err
}

func (s *ResourceScope) ReleaseBuffer(buf []byte) {
	s.mx.Lock()
	defer s.mx.Unlock()

	if s.done {
		return
	}

	s.rc.releaseBuffer(buf)
	for _, cst := range s.constraints {
		cst.ReleaseMemoryForChild(int64(len(buf)))
	}
}

func (s *ResourceScope) AddStream(count int) error {
	s.mx.Lock()
	defer s.mx.Unlock()

	if s.done {
		return ErrResourceScopeClosed
	}

	if err := s.rc.addStream(count); err != nil {
		return err
	}

	var err error
	var reserved int
	for _, cst := range s.constraints {
		if err = cst.AddStreamForChild(count); err != nil {
			break
		}
		reserved++
	}

	if err != nil {
		for _, cst := range s.constraints[:reserved] {
			cst.RemoveStreamForChild(count)
		}
	}

	return err
}

func (s *ResourceScope) AddStreamForChild(count int) error {
	s.mx.Lock()
	defer s.mx.Unlock()

	return s.rc.addStream(count)
}

func (s *ResourceScope) RemoveStream(count int) {
	s.mx.Lock()
	defer s.mx.Unlock()

	s.rc.removeStream(count)
	for _, cst := range s.constraints {
		cst.RemoveStreamForChild(count)
	}
}

func (s *ResourceScope) RemoveStreamForChild(count int) {
	s.mx.Lock()
	defer s.mx.Unlock()
	s.rc.removeStream(count)
}

func (s *ResourceScope) AddConn(count int) error {
	s.mx.Lock()
	defer s.mx.Unlock()

	if s.done {
		return ErrResourceScopeClosed
	}

	if err := s.rc.addConn(count); err != nil {
		return err
	}

	var err error
	var reserved int
	for _, cst := range s.constraints {
		if err = cst.AddConnForChild(count); err != nil {
			break
		}
		reserved++
	}

	if err != nil {
		for _, cst := range s.constraints[:reserved] {
			cst.RemoveConnForChild(count)
		}
	}

	return err
}

func (s *ResourceScope) AddConnForChild(count int) error {
	s.mx.Lock()
	defer s.mx.Unlock()

	return s.rc.addConn(count)
}

func (s *ResourceScope) RemoveConn(count int) {
	s.mx.Lock()
	defer s.mx.Unlock()

	s.rc.removeConn(count)
	for _, cst := range s.constraints {
		cst.RemoveConnForChild(count)
	}
}

func (s *ResourceScope) RemoveConnForChild(count int) {
	s.mx.Lock()
	defer s.mx.Unlock()
	s.rc.removeConn(count)
}

func (s *ResourceScope) Done() {
	s.mx.Lock()
	defer s.mx.Unlock()

	if s.done {
		return
	}

	for _, cst := range s.constraints {
		cst.ReleaseMemoryForChild(s.rc.memory)
		cst.RemoveStreamForChild(s.rc.nstreams)
		cst.RemoveConnForChild(s.rc.nconns)
	}

	s.rc.releaseBuffers()

	s.rc.nstreams = 0
	s.rc.nconns = 0
	s.rc.memory = 0
	s.rc.buffers = nil

	s.done = true
}

func (s *ResourceScope) Stat() network.ScopeStat {
	s.mx.Lock()
	defer s.mx.Unlock()

	return s.rc.stat()
}
<commit_msg>embed mutex in scope impl, add constructors<commit_after>package rcmgr

import (
	"fmt"
	"sync"

	"github.com/libp2p/go-buffer-pool"
	"github.com/libp2p/go-libp2p-core/network"
)

// Basic resource mamagement.
type Resources struct {
	limit    Limit
	nconns   int
	nstreams int
	memory   int64
	buffers  map[interface{}][]byte
}

// DAG ResourceScopes.
// Resources accounts for the node usage, constraints signify
// the dependencies that constrain resource usage.
type ResourceScope struct {
	sync.Mutex
	done bool

	rc          *Resources
	constraints []*ResourceScope
}

var _ network.ResourceScope = (*ResourceScope)(nil)
var _ network.TransactionalScope = (*ResourceScope)(nil)

func NewResources(limit Limit) *Resources {
	return &Resources{
		limit:   limit,
		buffers: make(map[interface{}][]byte),
	}
}

func NewResourceScope(limit Limit, constraints []*ResourceScope) *ResourceScope {
	return &ResourceScope{
		rc:          NewResources(limit),
		constraints: constraints,
	}
}

// Resources implementation
func (rc *Resources) checkMemory(rsvp int) error {
	// overflow check; this also has the side-effect that we cannot reserve negative memory.
	newmem := rc.memory + int64(rsvp)
	if newmem < rc.memory {
		return fmt.Errorf("memory reservation overflow: %w", ErrResourceLimitExceeded)
	}

	// limit check
	if newmem > rc.limit.GetMemoryLimit() {
		return fmt.Errorf("cannot reserve memory: %w", ErrResourceLimitExceeded)
	}

	return nil
}

func (rc *Resources) releaseBuffers() {
	for key, buf := range rc.buffers {
		pool.Put(buf)
		delete(rc.buffers, key)
	}
}

func (rc *Resources) reserveMemory(size int) error {
	if err := rc.checkMemory(size); err != nil {
		return err
	}

	rc.memory += int64(size)
	return nil
}

func (rc *Resources) releaseMemory(size int64) {
	rc.memory -= size

	// sanity check for bugs upstream
	if rc.memory < 0 {
		panic("BUG: too much memory released")
	}
}

func (rc *Resources) getBuffer(size int) ([]byte, error) {
	if err := rc.checkMemory(size); err != nil {
		return nil, err
	}

	buf := pool.Get(size)

	rc.memory += int64(size)
	rc.buffers[buf] = buf

	return buf, nil
}

func (rc *Resources) growBuffer(oldbuf []byte, newsize int) ([]byte, error) {
	grow := newsize - len(oldbuf)
	if err := rc.checkMemory(grow); err != nil {
		return nil, err
	}

	newbuf := pool.Get(newsize)
	copy(newbuf, oldbuf)

	rc.memory += int64(grow)
	rc.buffers[newbuf] = newbuf
	delete(rc.buffers, oldbuf)

	return newbuf, nil
}

func (rc *Resources) releaseBuffer(buf []byte) {
	rc.memory -= int64(len(buf))

	// sanity check for bugs upstream
	if rc.memory < 0 {
		panic("BUG: too much memory released")
	}

	delete(rc.buffers, buf)
	pool.Put(buf)
}

func (rc *Resources) addStream(count int) error {
	if rc.nstreams+count > rc.limit.GetStreamLimit() {
		return fmt.Errorf("cannot reserve stream: %w", ErrResourceLimitExceeded)
	}

	rc.nstreams += count
	return nil
}

func (rc *Resources) removeStream(count int) {
	rc.nstreams -= count

	if rc.nstreams < 0 {
		panic("BUG: too many streams released")
	}
}

func (rc *Resources) addConn(count int) error {
	if rc.nconns+count > rc.limit.GetConnLimit() {
		return fmt.Errorf("cannot reserve connection: %w", ErrResourceLimitExceeded)
	}

	rc.nconns += count
	return nil
}

func (rc *Resources) removeConn(count int) {
	rc.nconns -= count

	if rc.nconns < 0 {
		panic("BUG: too many connections released")
	}
}

func (rc *Resources) stat() network.ScopeStat {
	return network.ScopeStat{
		Memory:     rc.memory,
		NumConns:   rc.nconns,
		NumStreams: rc.nstreams,
	}
}

// ResourceScope implementation
func (s *ResourceScope) ReserveMemory(size int) error {
	s.Lock()
	defer s.Unlock()

	if s.done {
		return ErrResourceScopeClosed
	}

	if err := s.rc.reserveMemory(size); err != nil {
		return err
	}

	if err := s.reserveMemoryForConstraints(size); err != nil {
		s.rc.releaseMemory(int64(size))
		return err
	}

	return nil
}

func (s *ResourceScope) reserveMemoryForConstraints(size int) error {
	var reserved int
	var err error
	for _, cst := range s.constraints {
		if err = cst.ReserveMemoryForChild(size); err != nil {
			break
		}
		reserved++
	}

	if err != nil {
		// we failed because of a constraint; undo memory reservations
		for _, cst := range s.constraints[:reserved] {
			cst.ReleaseMemoryForChild(int64(size))
		}
	}

	return err
}

func (s *ResourceScope) ReserveMemoryForChild(size int) error {
	s.Lock()
	defer s.Unlock()

	if s.done {
		return ErrResourceScopeClosed
	}

	return s.rc.reserveMemory(size)
}

func (s *ResourceScope) ReleaseMemory(size int) {
	s.Lock()
	defer s.Unlock()

	if s.done {
		return
	}

	s.rc.releaseMemory(int64(size))
	for _, cst := range s.constraints {
		cst.ReleaseMemoryForChild(int64(size))
	}
}

func (s *ResourceScope) ReleaseMemoryForChild(size int64) {
	s.Lock()
	defer s.Unlock()

	if s.done {
		return
	}

	s.rc.releaseMemory(size)
}

func (s *ResourceScope) GetBuffer(size int) ([]byte, error) {
	s.Lock()
	defer s.Unlock()

	if s.done {
		return nil, ErrResourceScopeClosed
	}

	buf, err := s.rc.getBuffer(size)
	if err != nil {
		return nil, err
	}

	if err := s.reserveMemoryForConstraints(size); err != nil {
		s.rc.releaseBuffer(buf)
		return nil, err
	}

	return buf, err
}

func (s *ResourceScope) GrowBuffer(oldbuf []byte, newsize int) ([]byte, error) {
	s.Lock()
	defer s.Unlock()

	if s.done {
		return nil, ErrResourceScopeClosed
	}

	buf, err := s.rc.growBuffer(oldbuf, newsize)
	if err != nil {
		return nil, err
	}

	if err := s.reserveMemoryForConstraints(newsize - len(oldbuf)); err != nil {
		s.rc.releaseBuffer(buf)
		return nil, err
	}

	return buf, err
}

func (s *ResourceScope) ReleaseBuffer(buf []byte) {
	s.Lock()
	defer s.Unlock()

	if s.done {
		return
	}

	s.rc.releaseBuffer(buf)
	for _, cst := range s.constraints {
		cst.ReleaseMemoryForChild(int64(len(buf)))
	}
}

func (s *ResourceScope) AddStream(count int) error {
	s.Lock()
	defer s.Unlock()

	if s.done {
		return ErrResourceScopeClosed
	}

	if err := s.rc.addStream(count); err != nil {
		return err
	}

	var err error
	var reserved int
	for _, cst := range s.constraints {
		if err = cst.AddStreamForChild(count); err != nil {
			break
		}
		reserved++
	}

	if err != nil {
		for _, cst := range s.constraints[:reserved] {
			cst.RemoveStreamForChild(count)
		}
	}

	return err
}

func (s *ResourceScope) AddStreamForChild(count int) error {
	s.Lock()
	defer s.Unlock()

	return s.rc.addStream(count)
}

func (s *ResourceScope) RemoveStream(count int) {
	s.Lock()
	defer s.Unlock()

	s.rc.removeStream(count)
	for _, cst := range s.constraints {
		cst.RemoveStreamForChild(count)
	}
}

func (s *ResourceScope) RemoveStreamForChild(count int) {
	s.Lock()
	defer s.Unlock()
	s.rc.removeStream(count)
}

func (s *ResourceScope) AddConn(count int) error {
	s.Lock()
	defer s.Unlock()

	if s.done {
		return ErrResourceScopeClosed
	}

	if err := s.rc.addConn(count); err != nil {
		return err
	}

	var err error
	var reserved int
	for _, cst := range s.constraints {
		if err = cst.AddConnForChild(count); err != nil {
			break
		}
		reserved++
	}

	if err != nil {
		for _, cst := range s.constraints[:reserved] {
			cst.RemoveConnForChild(count)
		}
	}

	return err
}

func (s *ResourceScope) AddConnForChild(count int) error {
	s.Lock()
	defer s.Unlock()

	return s.rc.addConn(count)
}

func (s *ResourceScope) RemoveConn(count int) {
	s.Lock()
	defer s.Unlock()

	s.rc.removeConn(count)
	for _, cst := range s.constraints {
		cst.RemoveConnForChild(count)
	}
}

func (s *ResourceScope) RemoveConnForChild(count int) {
	s.Lock()
	defer s.Unlock()
	s.rc.removeConn(count)
}

func (s *ResourceScope) Done() {
	s.Lock()
	defer s.Unlock()

	if s.done {
		return
	}

	for _, cst := range s.constraints {
		cst.ReleaseMemoryForChild(s.rc.memory)
		cst.RemoveStreamForChild(s.rc.nstreams)
		cst.RemoveConnForChild(s.rc.nconns)
	}

	s.rc.releaseBuffers()

	s.rc.nstreams = 0
	s.rc.nconns = 0
	s.rc.memory = 0
	s.rc.buffers = nil

	s.done = true
}

func (s *ResourceScope) Stat() network.ScopeStat {
	s.Lock()
	defer s.Unlock()

	return s.rc.stat()
}
<|endoftext|>


<commit_before>package adler32_test

import (
	rollsum "github.com/chmduquesne/rollinghash/adler32"
	"hash/adler32"
	"strings"
	"testing"
)

var data = "The quick brown fox jumps over the lazy dog"

// Stolen from hash/adler32
var golden = []struct {
	out uint32
	in  string
}{
	{0x00000001, ""},
	{0x00620062, "a"},
	{0x012600c4, "ab"},
	{0x024d0127, "abc"},
	{0x03d8018b, "abcd"},
	{0x05c801f0, "abcde"},
	{0x081e0256, "abcdef"},
	{0x0adb02bd, "abcdefg"},
	{0x0e000325, "abcdefgh"},
	{0x118e038e, "abcdefghi"},
	{0x158603f8, "abcdefghij"},
	{0x3f090f02, "Discard medicine more than two years old."},
	{0x46d81477, "He who has a shady past knows that nice guys finish last."},
	{0x40ee0ee1, "I wouldn't marry him with a ten foot pole."},
	{0x16661315, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
	{0x5b2e1480, "The days of the digital watch are numbered.  -Tom Stoppard"},
	{0x8c3c09ea, "Nepal premier won't resign."},
	{0x45ac18fd, "For every action there is an equal and opposite government program."},
	{0x53c61462, "His money is twice tainted: 'taint yours and 'taint mine."},
	{0x7e511e63, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
	{0xe4801a6a, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
	{0x61b507df, "size:  a.out:  bad magic"},
	{0xb8631171, "The major problem is with sendmail.  -Mark Horton"},
	{0x8b5e1904, "Give me a rock, paper and scissors and I will move the world.  CCFestoon"},
	{0x7cc6102b, "If the enemy is within range, then so are you."},
	{0x700318e7, "It's well we cannot hear the screams/That we create in others' dreams."},
	{0x1e601747, "You remind me of a TV show, but that's all right: I watch it anyway."},
	{0xb55b0b09, "C is as portable as Stonehedge!!"},
	{0x39111dd0, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
	{0x91dd304f, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction.  Lewis-Randall Rule"},
	{0x2e5d1316, "How can you write a big system without C++?  -Paul Glick"},
	{0xd0201df6, "'Invariant assertions' is the most elegant programming technique!  -Tom Szymanski"},
	{0x211297c8, strings.Repeat("\xff", 5548) + "8"},
	{0xbaa198c8, strings.Repeat("\xff", 5549) + "9"},
	{0x553499be, strings.Repeat("\xff", 5550) + "0"},
	{0xf0c19abe, strings.Repeat("\xff", 5551) + "1"},
	{0x8d5c9bbe, strings.Repeat("\xff", 5552) + "2"},
	{0x2af69cbe, strings.Repeat("\xff", 5553) + "3"},
	{0xc9809dbe, strings.Repeat("\xff", 5554) + "4"},
	{0x69189ebe, strings.Repeat("\xff", 5555) + "5"},
	{0x86af0001, strings.Repeat("\x00", 1e5)},
	{0x79660b4d, strings.Repeat("a", 1e5)},
	{0x110588ee, strings.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 1e4)},
}

func TestGolden(t *testing.T) {
	for _, g := range golden {
		in := g.in

		// We test the vanilla implementation
		p := []byte(g.in)
		vanilla := adler32.New()
		vanilla.Write(p)
		if got := vanilla.Sum32(); got != g.out {
			t.Errorf("vanilla implentation: for %q, expected 0x%x, got 0x%x", in, g.out, got)
			continue
		}

		// We test the rolling implementation by prefixing the slice by a
		// space, writing it to our rolling hash, and then rolling once
		q := []byte(" ")
		q = append(q, p...)
		rolling := rollsum.New()
		rolling.Write(q[:len(q)-1])
		rolling.Roll(q[len(q)-1])
		if got := rolling.Sum32(); got != g.out {
			t.Errorf("rolling implentation: for %q, expected 0x%x, got 0x%x", in, g.out, got)
			continue
		}
	}
}

func TestSimple(t *testing.T) {
	s := []byte(data)

	vanilla := adler32.New()
	rolling := rollsum.New()

	// arbitrary window len
	n := 16

	// Load the window into the rolling hash
	rolling.Write(s[:n])

	// Roll it and compare the result with full re-calculus every time
	for i := n; i < len(s); i++ {

		vanilla.Reset()
		vanilla.Write(s[i-n+1 : i+1])

		err := rolling.Roll(s[i])
		if err != nil {
			t.Fatal(err)
		}

		if vanilla.Sum32() != rolling.Sum32() {
			t.Fatalf("%v: expected %x, got %x",
				s[i-n+1:i+1], vanilla.Sum32(), rolling.Sum32())
		}

	}
}

func TestUninitialized(t *testing.T) {
	s := []byte(data)
	hash := rollsum.New()
	err := hash.Roll(s[0])

	if err == nil {
		t.Fatal("Rolling with an uninitialized window should trigger an error")
	}
}

// Modified from hash/adler32
func BenchmarkVanillaKB(b *testing.B) {
	b.SetBytes(1024)
	window := make([]byte, 1024)
	for i := range window {
		window[i] = byte(i)
	}
	h := adler32.New()
	in := make([]byte, 0, h.Size())

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		h.Reset()
		h.Write(window)
		h.Sum(in)
	}
}

func BenchmarkRollingKB(b *testing.B) {
	b.SetBytes(1024)
	window := make([]byte, 1024)
	for i := range window {
		window[i] = byte(i)
	}

	h := rollsum.New()
	in := make([]byte, 0, h.Size())

	b.ResetTimer()
	h.Write(window)
	for i := 0; i < b.N; i++ {
		h.Roll(byte(1024 + i))
		h.Sum(in)
	}
}

// A common use is to roll over a 128 bytes window
func BenchmarkVanilla128B(b *testing.B) {
	b.SetBytes(1024)
	window := make([]byte, 128)
	for i := range window {
		window[i] = byte(i)
	}
	h := adler32.New()
	in := make([]byte, 0, h.Size())

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		h.Reset()
		h.Write(window)
		h.Sum(in)
	}
}

func BenchmarkRolling128B(b *testing.B) {
	b.SetBytes(1024)
	window := make([]byte, 128)
	for i := range window {
		window[i] = byte(i)
	}

	h := rollsum.New()
	in := make([]byte, 0, h.Size())

	b.ResetTimer()
	h.Write(window)
	for i := 0; i < b.N; i++ {
		h.Roll(byte(128 + i))
		h.Sum(in)
	}
}
<commit_msg>Adding a test proving that our implementation of adler32 also implements hash.Hash32<commit_after>package adler32_test

import (
	rollsum "github.com/chmduquesne/rollinghash/adler32"
	"hash"
	"hash/adler32"
	"strings"
	"testing"
)

var data = "The quick brown fox jumps over the lazy dog"

// Stolen from hash/adler32
var golden = []struct {
	out uint32
	in  string
}{
	{0x00000001, ""},
	{0x00620062, "a"},
	{0x012600c4, "ab"},
	{0x024d0127, "abc"},
	{0x03d8018b, "abcd"},
	{0x05c801f0, "abcde"},
	{0x081e0256, "abcdef"},
	{0x0adb02bd, "abcdefg"},
	{0x0e000325, "abcdefgh"},
	{0x118e038e, "abcdefghi"},
	{0x158603f8, "abcdefghij"},
	{0x3f090f02, "Discard medicine more than two years old."},
	{0x46d81477, "He who has a shady past knows that nice guys finish last."},
	{0x40ee0ee1, "I wouldn't marry him with a ten foot pole."},
	{0x16661315, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
	{0x5b2e1480, "The days of the digital watch are numbered.  -Tom Stoppard"},
	{0x8c3c09ea, "Nepal premier won't resign."},
	{0x45ac18fd, "For every action there is an equal and opposite government program."},
	{0x53c61462, "His money is twice tainted: 'taint yours and 'taint mine."},
	{0x7e511e63, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
	{0xe4801a6a, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
	{0x61b507df, "size:  a.out:  bad magic"},
	{0xb8631171, "The major problem is with sendmail.  -Mark Horton"},
	{0x8b5e1904, "Give me a rock, paper and scissors and I will move the world.  CCFestoon"},
	{0x7cc6102b, "If the enemy is within range, then so are you."},
	{0x700318e7, "It's well we cannot hear the screams/That we create in others' dreams."},
	{0x1e601747, "You remind me of a TV show, but that's all right: I watch it anyway."},
	{0xb55b0b09, "C is as portable as Stonehedge!!"},
	{0x39111dd0, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
	{0x91dd304f, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction.  Lewis-Randall Rule"},
	{0x2e5d1316, "How can you write a big system without C++?  -Paul Glick"},
	{0xd0201df6, "'Invariant assertions' is the most elegant programming technique!  -Tom Szymanski"},
	{0x211297c8, strings.Repeat("\xff", 5548) + "8"},
	{0xbaa198c8, strings.Repeat("\xff", 5549) + "9"},
	{0x553499be, strings.Repeat("\xff", 5550) + "0"},
	{0xf0c19abe, strings.Repeat("\xff", 5551) + "1"},
	{0x8d5c9bbe, strings.Repeat("\xff", 5552) + "2"},
	{0x2af69cbe, strings.Repeat("\xff", 5553) + "3"},
	{0xc9809dbe, strings.Repeat("\xff", 5554) + "4"},
	{0x69189ebe, strings.Repeat("\xff", 5555) + "5"},
	{0x86af0001, strings.Repeat("\x00", 1e5)},
	{0x79660b4d, strings.Repeat("a", 1e5)},
	{0x110588ee, strings.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 1e4)},
}

// This is a no-op to prove that rollsum.Hash32 implements hash.Hash
var _ = hash.Hash32(rollsum.New())

func TestGolden(t *testing.T) {
	for _, g := range golden {
		in := g.in

		// We test the vanilla implementation
		p := []byte(g.in)
		vanilla := adler32.New()
		vanilla.Write(p)
		if got := vanilla.Sum32(); got != g.out {
			t.Errorf("vanilla implentation: for %q, expected 0x%x, got 0x%x", in, g.out, got)
			continue
		}

		// We test the rolling implementation by prefixing the slice by a
		// space, writing it to our rolling hash, and then rolling once
		q := []byte(" ")
		q = append(q, p...)
		rolling := rollsum.New()
		rolling.Write(q[:len(q)-1])
		rolling.Roll(q[len(q)-1])
		if got := rolling.Sum32(); got != g.out {
			t.Errorf("rolling implentation: for %q, expected 0x%x, got 0x%x", in, g.out, got)
			continue
		}
	}
}

func TestSimple(t *testing.T) {
	s := []byte(data)

	vanilla := adler32.New()
	rolling := rollsum.New()

	// arbitrary window len
	n := 16

	// Load the window into the rolling hash
	rolling.Write(s[:n])

	// Roll it and compare the result with full re-calculus every time
	for i := n; i < len(s); i++ {

		vanilla.Reset()
		vanilla.Write(s[i-n+1 : i+1])

		err := rolling.Roll(s[i])
		if err != nil {
			t.Fatal(err)
		}

		if vanilla.Sum32() != rolling.Sum32() {
			t.Fatalf("%v: expected %x, got %x",
				s[i-n+1:i+1], vanilla.Sum32(), rolling.Sum32())
		}

	}
}

func TestUninitialized(t *testing.T) {
	s := []byte(data)
	hash := rollsum.New()
	err := hash.Roll(s[0])

	if err == nil {
		t.Fatal("Rolling with an uninitialized window should trigger an error")
	}
}

// Modified from hash/adler32
func BenchmarkVanillaKB(b *testing.B) {
	b.SetBytes(1024)
	window := make([]byte, 1024)
	for i := range window {
		window[i] = byte(i)
	}
	h := adler32.New()
	in := make([]byte, 0, h.Size())

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		h.Reset()
		h.Write(window)
		h.Sum(in)
	}
}

func BenchmarkRollingKB(b *testing.B) {
	b.SetBytes(1024)
	window := make([]byte, 1024)
	for i := range window {
		window[i] = byte(i)
	}

	h := rollsum.New()
	in := make([]byte, 0, h.Size())

	b.ResetTimer()
	h.Write(window)
	for i := 0; i < b.N; i++ {
		h.Roll(byte(1024 + i))
		h.Sum(in)
	}
}

// A common use is to roll over a 128 bytes window
func BenchmarkVanilla128B(b *testing.B) {
	b.SetBytes(1024)
	window := make([]byte, 128)
	for i := range window {
		window[i] = byte(i)
	}
	h := adler32.New()
	in := make([]byte, 0, h.Size())

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		h.Reset()
		h.Write(window)
		h.Sum(in)
	}
}

func BenchmarkRolling128B(b *testing.B) {
	b.SetBytes(1024)
	window := make([]byte, 128)
	for i := range window {
		window[i] = byte(i)
	}

	h := rollsum.New()
	in := make([]byte, 0, h.Size())

	b.ResetTimer()
	h.Write(window)
	for i := 0; i < b.N; i++ {
		h.Roll(byte(128 + i))
		h.Sum(in)
	}
}
<|endoftext|>


<commit_before>package adler32_test

import (
	rollsum "github.com/chmduquesne/rollinghash/adler32"
	"hash/adler32"
	"testing"
)

func TestRolling(t *testing.T) {
	s := []byte("The quick brown fox jumps over the lazy dog")

	// window len
	n := 16

	vanilla := adler32.New()
	rolling := rollsum.New()

	// Load the window
	rolling.Write(s[0:n])

	// Roll it and compare the result with full re-calculus every time
	for i := n; i < len(s); i++ {

		vanilla.Reset()
		vanilla.Write(s[i-n+1 : i+1])

		err := rolling.Roll(s[i])
		if err != nil {
			t.Fatal(err)
		}

		if vanilla.Sum32() != rolling.Sum32() {
			t.Fatal("%v: expected %x, got %x",
				s[i:i+n], vanilla.Sum32(), rolling.Sum32())
		}

	}
}

func TestUninitialized(t *testing.T) {
	s := []byte("The brown fox jumps over the lazy dog")
	hash := rollsum.New()
	err := hash.Roll(s[0])

	if err == nil {
		t.Fatal("Rolling with an uninitialized window should trigger an error")
	}
}
<commit_msg>Fatal -> Fatalf<commit_after>package adler32_test

import (
	rollsum "github.com/chmduquesne/rollinghash/adler32"
	"hash/adler32"
	"testing"
)

func TestRolling(t *testing.T) {
	s := []byte("The quick brown fox jumps over the lazy dog")

	// window len
	n := 16

	vanilla := adler32.New()
	rolling := rollsum.New()

	// Load the window
	rolling.Write(s[0:n])

	// Roll it and compare the result with full re-calculus every time
	for i := n; i < len(s); i++ {

		vanilla.Reset()
		vanilla.Write(s[i-n+1 : i+1])

		err := rolling.Roll(s[i])
		if err != nil {
			t.Fatal(err)
		}

		if vanilla.Sum32() != rolling.Sum32() {
			t.Fatalf("%v: expected %x, got %x",
				s[i:i+n], vanilla.Sum32(), rolling.Sum32())
		}

	}
}

func TestUninitialized(t *testing.T) {
	s := []byte("The brown fox jumps over the lazy dog")
	hash := rollsum.New()
	err := hash.Roll(s[0])

	if err == nil {
		t.Fatal("Rolling with an uninitialized window should trigger an error")
	}
}
<|endoftext|>


<commit_before>package checkstyle

import (
	"bytes"
	"encoding/json"
	"go/ast"
	"go/format"
	"go/parser"
	"go/token"
	"strconv"
	"strings"
)

type ProblemType string

const (
	FileLine     ProblemType = "file_line"
	FunctionLine ProblemType = "func_line"
	ParamsNum    ProblemType = "params_num"
	ResultsNum   ProblemType = "results_num"
	Formated     ProblemType = "formated"
	PackageName  ProblemType = "pkg_name"
)

type Problem struct {
	Position    *token.Position
	Description string
	SourceLine  string
	Type        ProblemType
}

type Checker interface {
	Check(fileName string, src []byte) ([]Problem, error)
	IsFatal(p *Problem) bool
}

type checker struct {
	FunctionComment bool     `json:"func_comment"`
	FileLine        int      `json:"file_line"`
	FunctionLine    int      `json:"func_line"`
	MaxIndent       int      `json:"max_indent"`
	Formated        bool     `json:"formated"`
	Fatal           []string `json:"fatal"`
	ParamsNum       int      `json:"params_num"`
	ResultsNum      int      `json:"results_num"`
	PackageName     bool     `json:"pkg_name"`
}

func New(config []byte) (Checker, error) {
	var _checker checker
	err := json.Unmarshal(config, &_checker)
	if err != nil {
		return nil, err
	}
	return &_checker, nil
}

func (c *checker) Check(fileName string, src []byte) (ps []Problem, err error) {
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, fileName, src, parser.ParseComments)
	if err != nil {
		return nil, err
	}
	return (&file{fileName, src, c, f, fset, []Problem{}}).check(), nil
}

func (c *checker) IsFatal(p *Problem) bool {
	for _, v := range c.Fatal {
		if v == string(p.Type) {
			return true
		}
	}
	return false
}

type file struct {
	fileName string
	src      []byte

	config *checker

	ast  *ast.File
	fset *token.FileSet

	problems []Problem
}

func (f *file) isTest() bool {
	return strings.HasSuffix(f.fileName, "_test.go")
}

func (f *file) check() (ps []Problem) {
	f.checkFormat()
	f.checkFileLine()
	f.checkFileContent()
	return f.problems
}

func (f *file) checkFormat() {
	if !f.config.Formated {
		return
	}
	src, err := format.Source(f.src)
	if err != nil {
		panic(f.fileName + err.Error())
	}
	if bytes.Compare(src, f.src) != 0 {
		desc := "source is not formated"
		pos := f.fset.Position(f.ast.Pos())
		problem := Problem{Description: desc, Position: &pos, Type: Formated}
		f.problems = append(f.problems, problem)
	}
}

func (f *file) checkFileLine() {
	if f.isTest() {
		return
	}

	lineLimit := f.config.FileLine
	if lineLimit == 0 {
		return
	}

	f.fset.Iterate(func(_file *token.File) bool {
		lineCount := _file.LineCount()
		if lineCount > lineLimit {
			desc := strconv.Itoa(lineCount) + " lines more than " + strconv.Itoa(lineLimit)
			pos := f.fset.Position(f.ast.End())
			problem := Problem{Description: desc, Position: &pos, Type: FileLine}
			f.problems = append(f.problems, problem)
		}
		return true
	})
}

func genFuncLineProblem(name string, lineCount, lineLimit int, start token.Position) Problem {
	desc := "func " + name + "() body lines num " + strconv.Itoa(lineCount) +
		" more than " + strconv.Itoa(lineLimit)
	return Problem{Description: desc, Position: &start, Type: FunctionLine}
}

func genParamsNumProblem(name string, paramsNum, limit int, start token.Position) Problem {
	desc := "func " + name + "() params num " + strconv.Itoa(paramsNum) +
		"  more than " + strconv.Itoa(limit)
	return Problem{Description: desc, Position: &start, Type: ParamsNum}
}

func genResultsNumProblem(name string, resultsNum, limit int, start token.Position) Problem {
	desc := "func " + name + "() results num " + strconv.Itoa(resultsNum) +
		"  more than " + strconv.Itoa(limit)
	return Problem{Description: desc, Position: &start, Type: ResultsNum}
}

func (f *file) checkFileContent() {
	if f.isTest() {
		return
	}

	if f.config.PackageName {
		//ref "http://golang.org/doc/effective_go.html#package-names"
		pkgName := f.ast.Name.Name
		var desc string
		if strings.Contains(pkgName, "_") {
			suggestName := strings.Replace(pkgName, "_", "/", -1)
			desc = "don't use an underscore in package name, " + pkgName + " should be " + suggestName
		} else if strings.ToLower(pkgName) != pkgName {
			desc = "don't use capital letters in package name: " + pkgName
		}
		if desc != "" {
			start := f.fset.Position(f.ast.Name.Pos())
			problem := Problem{Description: desc, Position: &start, Type: PackageName}
			f.problems = append(f.problems, problem)
		}
	}

	lineLimit := f.config.FunctionLine
	paramsNumLimit := f.config.ParamsNum
	resultsNumLimit := f.config.ResultsNum
	for _, v := range f.ast.Decls {
		switch v2 := v.(type) {
		case *ast.FuncDecl:
			start := f.fset.Position(v2.Pos())
			if lineLimit > 0 {
				startLine := start.Line
				endLine := f.fset.Position(v2.End()).Line
				lineCount := endLine - startLine
				if lineCount > lineLimit {
					problem := genFuncLineProblem(v2.Name.Name, lineCount, lineLimit, start)
					f.problems = append(f.problems, problem)
				}
			}

			_type := v2.Type
			params := _type.Params
			if paramsNumLimit != 0 && params.NumFields() > paramsNumLimit {
				problem := genParamsNumProblem(v2.Name.Name, params.NumFields(), paramsNumLimit, start)
				f.problems = append(f.problems, problem)
			}

			results := _type.Results
			if resultsNumLimit != 0 && results.NumFields() > resultsNumLimit {
				problem := genResultsNumProblem(v2.Name.Name, results.NumFields(), resultsNumLimit, start)
				f.problems = append(f.problems, problem)
			}
		}
	}
}
<commit_msg>optimize compare<commit_after>package checkstyle

import (
	"bytes"
	"encoding/json"
	"go/ast"
	"go/format"
	"go/parser"
	"go/token"
	"strconv"
	"strings"
)

type ProblemType string

const (
	FileLine     ProblemType = "file_line"
	FunctionLine ProblemType = "func_line"
	ParamsNum    ProblemType = "params_num"
	ResultsNum   ProblemType = "results_num"
	Formated     ProblemType = "formated"
	PackageName  ProblemType = "pkg_name"
)

type Problem struct {
	Position    *token.Position
	Description string
	SourceLine  string
	Type        ProblemType
}

type Checker interface {
	Check(fileName string, src []byte) ([]Problem, error)
	IsFatal(p *Problem) bool
}

type checker struct {
	FunctionComment bool     `json:"func_comment"`
	FileLine        int      `json:"file_line"`
	FunctionLine    int      `json:"func_line"`
	MaxIndent       int      `json:"max_indent"`
	Formated        bool     `json:"formated"`
	Fatal           []string `json:"fatal"`
	ParamsNum       int      `json:"params_num"`
	ResultsNum      int      `json:"results_num"`
	PackageName     bool     `json:"pkg_name"`
}

func New(config []byte) (Checker, error) {
	var _checker checker
	err := json.Unmarshal(config, &_checker)
	if err != nil {
		return nil, err
	}
	return &_checker, nil
}

func (c *checker) Check(fileName string, src []byte) (ps []Problem, err error) {
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, fileName, src, parser.ParseComments)
	if err != nil {
		return nil, err
	}
	return (&file{fileName, src, c, f, fset, []Problem{}}).check(), nil
}

func (c *checker) IsFatal(p *Problem) bool {
	for _, v := range c.Fatal {
		if v == string(p.Type) {
			return true
		}
	}
	return false
}

type file struct {
	fileName string
	src      []byte

	config *checker

	ast  *ast.File
	fset *token.FileSet

	problems []Problem
}

func (f *file) isTest() bool {
	return strings.HasSuffix(f.fileName, "_test.go")
}

func (f *file) check() (ps []Problem) {
	f.checkFormat()
	f.checkFileLine()
	f.checkFileContent()
	return f.problems
}

func (f *file) checkFormat() {
	if !f.config.Formated {
		return
	}
	src, err := format.Source(f.src)
	if err != nil {
		panic(f.fileName + err.Error())
	}
	if len(src) != len(f.src) || bytes.Compare(src, f.src) != 0 {
		desc := "source is not formated"
		pos := f.fset.Position(f.ast.Pos())
		problem := Problem{Description: desc, Position: &pos, Type: Formated}
		f.problems = append(f.problems, problem)
	}
}

func (f *file) checkFileLine() {
	if f.isTest() {
		return
	}

	lineLimit := f.config.FileLine
	if lineLimit == 0 {
		return
	}

	f.fset.Iterate(func(_file *token.File) bool {
		lineCount := _file.LineCount()
		if lineCount > lineLimit {
			desc := strconv.Itoa(lineCount) + " lines more than " + strconv.Itoa(lineLimit)
			pos := f.fset.Position(f.ast.End())
			problem := Problem{Description: desc, Position: &pos, Type: FileLine}
			f.problems = append(f.problems, problem)
		}
		return true
	})
}

func genFuncLineProblem(name string, lineCount, lineLimit int, start token.Position) Problem {
	desc := "func " + name + "() body lines num " + strconv.Itoa(lineCount) +
		" more than " + strconv.Itoa(lineLimit)
	return Problem{Description: desc, Position: &start, Type: FunctionLine}
}

func genParamsNumProblem(name string, paramsNum, limit int, start token.Position) Problem {
	desc := "func " + name + "() params num " + strconv.Itoa(paramsNum) +
		"  more than " + strconv.Itoa(limit)
	return Problem{Description: desc, Position: &start, Type: ParamsNum}
}

func genResultsNumProblem(name string, resultsNum, limit int, start token.Position) Problem {
	desc := "func " + name + "() results num " + strconv.Itoa(resultsNum) +
		"  more than " + strconv.Itoa(limit)
	return Problem{Description: desc, Position: &start, Type: ResultsNum}
}

func (f *file) checkFileContent() {
	if f.isTest() {
		return
	}

	if f.config.PackageName {
		//ref "http://golang.org/doc/effective_go.html#package-names"
		pkgName := f.ast.Name.Name
		var desc string
		if strings.Contains(pkgName, "_") {
			suggestName := strings.Replace(pkgName, "_", "/", -1)
			desc = "don't use an underscore in package name, " + pkgName + " should be " + suggestName
		} else if strings.ToLower(pkgName) != pkgName {
			desc = "don't use capital letters in package name: " + pkgName
		}
		if desc != "" {
			start := f.fset.Position(f.ast.Name.Pos())
			problem := Problem{Description: desc, Position: &start, Type: PackageName}
			f.problems = append(f.problems, problem)
		}
	}

	lineLimit := f.config.FunctionLine
	paramsNumLimit := f.config.ParamsNum
	resultsNumLimit := f.config.ResultsNum
	for _, v := range f.ast.Decls {
		switch v2 := v.(type) {
		case *ast.FuncDecl:
			start := f.fset.Position(v2.Pos())
			if lineLimit > 0 {
				startLine := start.Line
				endLine := f.fset.Position(v2.End()).Line
				lineCount := endLine - startLine
				if lineCount > lineLimit {
					problem := genFuncLineProblem(v2.Name.Name, lineCount, lineLimit, start)
					f.problems = append(f.problems, problem)
				}
			}

			_type := v2.Type
			params := _type.Params
			if paramsNumLimit != 0 && params.NumFields() > paramsNumLimit {
				problem := genParamsNumProblem(v2.Name.Name, params.NumFields(), paramsNumLimit, start)
				f.problems = append(f.problems, problem)
			}

			results := _type.Results
			if resultsNumLimit != 0 && results.NumFields() > resultsNumLimit {
				problem := genResultsNumProblem(v2.Name.Name, results.NumFields(), resultsNumLimit, start)
				f.problems = append(f.problems, problem)
			}
		}
	}
}
<|endoftext|>


<commit_before>package clc

import (
	"errors"
	"fmt"
	"regexp"
)

type ServerService struct {
	*Client
}

func (s *ServerService) Get(name string) (*ServerResponse, error) {
	var query string
	var uuidRegex = regexp.MustCompile("[0-9a-f]{8}[0-9a-f]{4}[0-9a-f]{4}[0-9a-f]{4}[0-9a-f]{12}")

	if uuidRegex.MatchString(name) {
		query = "?uuid=true"
	}
	url := fmt.Sprintf("%s/servers/%s/%s%s", s.baseURL, s.config.Alias, name, query)
	server := &ServerResponse{}
	err := s.get(url, server)
	return server, err
}

func (s *ServerService) Create(server Server, poll chan *StatusResponse) (*ServerQueuedResponse, error) {
	if !server.Valid() {
		return nil, errors.New("server: server missing required field(s). (Name, CPU, MemoryGB, GroupID, SourceServerID, Type)")
	}

	if server.Type == "hyperscale" {
		server.Storagetype = "hyperscale"
	}

	resp := &ServerQueuedResponse{}
	err := s.post(fmt.Sprintf("%s/servers/%s", s.baseURL, s.config.Alias), server, resp)
	if err == nil && poll != nil {
		ok, id := resp.Links.GetID("status")
		if !ok {
			return resp, fmt.Errorf("No status ID avaiable to poll for server: %s", resp.Server)
		}
		go s.Status.Poll(id, poll)
	}

	return resp, err
}

func (s *ServerService) Delete(name string) (*ServerQueuedResponse, error) {
	url := fmt.Sprintf("%s/servers/%s/%s", s.baseURL, s.config.Alias, name)
	server := &ServerQueuedResponse{}
	err := s.delete(url, server)
	return server, err
}

type Server struct {
	Name           string `json:"name"`
	Description    string `json:"description,omitempty"`
	GroupID        string `json:"groupId"`
	SourceServerID string `json:"sourceServerId"`
	IsManagedOS    bool   `json:"isManagedOS,omitempty"`
	PrimaryDNS     string `json:"primaryDns,omitempty"`
	SecondaryDNS   string `json:"secondaryDns,omitempty"`
	NetworkID      string `json:"networkId,omitempty"`
	IPaddress      string `json:"ipAddress,omitempty"`
	Password       string `json:"password,omitempty"`
	CPU            int    `json:"cpu"`
	MemoryGB       int    `json:"memoryGB"`
	Type           string `json:"type"`
	Storagetype    string `json:"storageType,omitempty"`
	Customfields   []struct {
		ID    string `json:"id"`
		Value string `json:"value"`
	} `json:"customFields,omitempty"`
	Additionaldisks []struct {
		Path   string `json:"path"`
		SizeGB int    `json:"sizeGB"`
		Type   string `json:"type"`
	} `json:"additionalDisks,omitempty"`
}

func (s *Server) Valid() bool {
	return s.Name != "" && s.CPU != 0 && s.MemoryGB != 0 && s.GroupID != "" && s.SourceServerID != ""
}

type ServerResponse struct {
	ID          string `json:"id"`
	Name        string `json:"name"`
	Description string `json:"description"`
	GroupID     string `json:"groupId"`
	IsTemplate  bool   `json:"isTemplate"`
	LocationID  string `json:"locationId"`
	OStype      string `json:"osType"`
	Status      string `json:"status"`
	Details     struct {
		IPaddresses []struct {
			Internal string `json:"internal"`
		} `json:"ipAddresses"`
		AlertPolicies []struct {
			ID    string `json:"id"`
			Name  string `json:"name"`
			Links []Link `json:"links"`
		} `json:"alertPolicies"`
		CPU               int    `json:"cpu"`
		Diskcount         int    `json:"diskCount"`
		Hostname          string `json:"hostName"`
		InMaintenanceMode bool   `json:"inMaintenanceMode"`
		MemoryMB          int    `json:"memoryMB"`
		Powerstate        string `json:"powerState"`
		Storagegb         int    `json:"storageGB"`
		Disks             []struct {
			ID             string        `json:"id"`
			SizeGB         int           `json:"sizeGB"`
			PartitionPaths []interface{} `json:"partitionPaths"`
		} `json:"disks"`
		Partitions []struct {
			SizeGB float64 `json:"sizeGB"`
			Path   string  `json:"path"`
		} `json:"partitions"`
		Snapshots []struct {
			Name  string `json:"name"`
			Links []Link `json:"links"`
		} `json:"snapshots"`
		Customfields []struct {
			ID           string `json:"id"`
			Name         string `json:"name"`
			Value        string `json:"value"`
			Displayvalue string `json:"displayValue"`
		} `json:"customFields"`
	} `json:"details"`
	Type        string `json:"type"`
	Storagetype string `json:"storageType"`
	ChangeInfo  struct {
		CreatedDate  string `json:"createdDate"`
		CreatedBy    string `json:"createdBy"`
		ModifiedDate string `json:"modifiedDate"`
		ModifiedBy   string `json:"modifiedBy"`
	} `json:"changeInfo"`
	Links Links `json:"links"`
}

type ServerQueuedResponse struct {
	Server   string `json:"server"`
	IsQueued bool   `json:"isQueued"`
	Links    Links  `json:"links"`
}
<commit_msg>breaking out common struct in server<commit_after>package clc

import (
	"errors"
	"fmt"
	"regexp"
)

type ServerService struct {
	*Client
}

func (s *ServerService) Get(name string) (*ServerResponse, error) {
	var query string
	var uuidRegex = regexp.MustCompile("[0-9a-f]{8}[0-9a-f]{4}[0-9a-f]{4}[0-9a-f]{4}[0-9a-f]{12}")

	if uuidRegex.MatchString(name) {
		query = "?uuid=true"
	}
	url := fmt.Sprintf("%s/servers/%s/%s%s", s.baseURL, s.config.Alias, name, query)
	server := &ServerResponse{}
	err := s.get(url, server)
	return server, err
}

func (s *ServerService) Create(server Server, poll chan *StatusResponse) (*ServerQueuedResponse, error) {
	if !server.Valid() {
		return nil, errors.New("server: server missing required field(s). (Name, CPU, MemoryGB, GroupID, SourceServerID, Type)")
	}

	if server.Type == "hyperscale" {
		server.Storagetype = "hyperscale"
	}

	resp := &ServerQueuedResponse{}
	err := s.post(fmt.Sprintf("%s/servers/%s", s.baseURL, s.config.Alias), server, resp)
	if err == nil && poll != nil {
		ok, id := resp.Links.GetID("status")
		if !ok {
			return resp, fmt.Errorf("No status ID avaiable to poll for server: %s", resp.Server)
		}
		go s.Status.Poll(id, poll)
	}

	return resp, err
}

func (s *ServerService) Delete(name string) (*ServerQueuedResponse, error) {
	url := fmt.Sprintf("%s/servers/%s/%s", s.baseURL, s.config.Alias, name)
	server := &ServerQueuedResponse{}
	err := s.delete(url, server)
	return server, err
}

type Server struct {
	Name            string         `json:"name"`
	Description     string         `json:"description,omitempty"`
	GroupID         string         `json:"groupId"`
	SourceServerID  string         `json:"sourceServerId"`
	IsManagedOS     bool           `json:"isManagedOS,omitempty"`
	PrimaryDNS      string         `json:"primaryDns,omitempty"`
	SecondaryDNS    string         `json:"secondaryDns,omitempty"`
	NetworkID       string         `json:"networkId,omitempty"`
	IPaddress       string         `json:"ipAddress,omitempty"`
	Password        string         `json:"password,omitempty"`
	CPU             int            `json:"cpu"`
	MemoryGB        int            `json:"memoryGB"`
	Type            string         `json:"type"`
	Storagetype     string         `json:"storageType,omitempty"`
	Customfields    []Customfields `json:"customFields,omitempty"`
	Additionaldisks []struct {
		Path   string `json:"path"`
		SizeGB int    `json:"sizeGB"`
		Type   string `json:"type"`
	} `json:"additionalDisks,omitempty"`
}

func (s *Server) Valid() bool {
	return s.Name != "" && s.CPU != 0 && s.MemoryGB != 0 && s.GroupID != "" && s.SourceServerID != ""
}

type ServerResponse struct {
	ID          string `json:"id"`
	Name        string `json:"name"`
	Description string `json:"description"`
	GroupID     string `json:"groupId"`
	IsTemplate  bool   `json:"isTemplate"`
	LocationID  string `json:"locationId"`
	OStype      string `json:"osType"`
	Status      string `json:"status"`
	Details     struct {
		IPaddresses []struct {
			Internal string `json:"internal"`
		} `json:"ipAddresses"`
		AlertPolicies []struct {
			ID    string `json:"id"`
			Name  string `json:"name"`
			Links []Link `json:"links"`
		} `json:"alertPolicies"`
		CPU               int    `json:"cpu"`
		Diskcount         int    `json:"diskCount"`
		Hostname          string `json:"hostName"`
		InMaintenanceMode bool   `json:"inMaintenanceMode"`
		MemoryMB          int    `json:"memoryMB"`
		Powerstate        string `json:"powerState"`
		Storagegb         int    `json:"storageGB"`
		Disks             []struct {
			ID             string        `json:"id"`
			SizeGB         int           `json:"sizeGB"`
			PartitionPaths []interface{} `json:"partitionPaths"`
		} `json:"disks"`
		Partitions []struct {
			SizeGB float64 `json:"sizeGB"`
			Path   string  `json:"path"`
		} `json:"partitions"`
		Snapshots []struct {
			Name  string `json:"name"`
			Links []Link `json:"links"`
		} `json:"snapshots"`
		Customfields []Customfields `json:"customFields,omitempty"`
	} `json:"details"`
	Type        string `json:"type"`
	Storagetype string `json:"storageType"`
	ChangeInfo  struct {
		CreatedDate  string `json:"createdDate"`
		CreatedBy    string `json:"createdBy"`
		ModifiedDate string `json:"modifiedDate"`
		ModifiedBy   string `json:"modifiedBy"`
	} `json:"changeInfo"`
	Links Links `json:"links"`
}

type Customfields struct {
	ID           string `json:"id,omitempty"`
	Name         string `json:"name,omitempty"`
	Value        string `json:"value,omitempty"`
	Displayvalue string `json:"displayValue,omitempty"`
}

type ServerQueuedResponse struct {
	Server   string `json:"server"`
	IsQueued bool   `json:"isQueued"`
	Links    Links  `json:"links"`
}
<|endoftext|>