<commit_before>/*
	Attar package provide simple way to get http user auth (via sessions and cookie).

	It use part of great Gorilla web toolkit, 'gorilla/sessions' package
	(http://github.com/gorilla/sessions).

	Usable example:
		import (
			"github.com/gorilla/mux"
			"html/template"
			"github.com/SpiritOfStallman/attar"
			"net/http"
		)

		// main page
		func mainPageHandler(res http.ResponseWriter, req *http.Request) {
			var mainPage string = `

HELLO!

			</form>
			`
			page := template.New("main")
			page, _ = page.Parse(mainPage)
			page.Execute(res, "")
		}

		// login page
		func loginPageHandler(res http.ResponseWriter, req *http.Request) {
			var loginPage string = `

			<form id="login_form" action="/login" method="POST" style="padding-top:15%;">
			<input type="text" name="login" placeholder="Login" autofocus>

			<input type="password" placeholder="Password" name="password">

			<input type="submit" value="LOGIN">
			</form>
			`
			page := template.New("main")
			page, _ = page.Parse(loginPage)
			page.Execute(res, "")
		}

		// auth provider function
		func checkAuth(u, p string) bool {
			if u == "user" && p == "qwerty" {
				return true
			}
			return false
		}

		func main() {

			a := attar.New()

			a.SetAuthProvider(checkAuth)
			a.SetLoginRoute("/login")

			// set options, with session & cookie lifetime == 30 sec
			options := &attar.AttarOptions{
				Path:                       "/",
				MaxAge:                     30,
				HttpOnly:                   true,
				SessionName:                "test-session",
				SessionLifeTime:            15,
				LoginFormUserFieldName:     "login",
				LoginFormPasswordFieldName: "password",
			}
			a.SetAttarOptions(options)

			// create mux router
			router := mux.NewRouter()
			router.HandleFunc("/", mainPageHandler)
			router.HandleFunc("/login", loginPageHandler).Methods("GET")
			// set attar.AuthHandler as handler func
			// for check login POST data
			router.HandleFunc("/login", a.AuthHandler).Methods("POST")

			// set auth proxy function
			http.Handle("/", a.GlobalAuthProxy(router))

			// start net/httm server at 8080 port
			http.ListenAndServe("127.0.0.1:8080", nil)
		}
	For more information - look at the pkg doc.
*/
package attar

import (
	"net/http"
	"time"

	"github.com/gorilla/sessions"
)

type Attar struct {
	authProviderFunc authProvider
	loginRoute       string
	cookieOptions    *AttarOptions
	cookieStore      *sessions.CookieStore
}

/*
	Primary attar options (except for basic settings also accommodates a
	'gorilla/sessions' options (http://www.gorillatoolkit.org/pkg/sessions#Options)).
*/
type AttarOptions struct {
	// 'gorilla/sessions' section:
	// description see on http://www.gorillatoolkit.org/pkg/sessions#Options
	// or source on github
	Path     string
	Domain   string
	MaxAge   int
	Secure   bool
	HttpOnly bool

	// attar section:
	// name of cookie browser session
	SessionName     string // default: "attar-session"
	SessionLifeTime int    // default: 86400; in sec

	// html field names, to retrieve
	// user name and password from
	// login form
	LoginFormUserFieldName     string // default: "login"
	LoginFormPasswordFieldName string // default: "password"
}

/*
	Set attar options (*AttarOptions).
*/
func (a *Attar) SetAttarOptions(o *AttarOptions) {
	a.cookieOptions = o
}

/*
	Function for check auth session.
*/
func (a *Attar) GlobalAuthProxy(next http.Handler) http.HandlerFunc {
	return func(res http.ResponseWriter, req *http.Request) {
		if req.URL.Path == a.loginRoute {
			next.ServeHTTP(res, req)
			return
		}

		var cookieStore = a.cookieStore

		cookieStore.Options = &sessions.Options{
			Path:     a.cookieOptions.Path,
			Domain:   a.cookieOptions.Domain,
			MaxAge:   a.cookieOptions.MaxAge,
			Secure:   a.cookieOptions.Secure,
			HttpOnly: a.cookieOptions.HttpOnly,
		}

		session, _ := cookieStore.Get(req, a.cookieOptions.SessionName)
		currentTime := time.Now().Local()

		if session.Values["loginTime"] != nil {
			userLoginTimeRFC3339 := session.Values["loginTime"]
			userLoginTime, _ := time.Parse(time.RFC3339, userLoginTimeRFC3339.(string))
			if int(currentTime.Sub(userLoginTime).Seconds()) > a.cookieOptions.SessionLifeTime {
				http.Redirect(res, req, a.loginRoute, http.StatusFound)
				return
			}
		} else {
			http.Redirect(res, req, a.loginRoute, http.StatusFound)
			return
		}

		next.ServeHTTP(res, req)
	}
}

/*
	Auth handler, for grub login form data, and init cookie session.
*/
func (a *Attar) AuthHandler(res http.ResponseWriter, req *http.Request) {
	user := req.FormValue(a.cookieOptions.LoginFormUserFieldName)
	password := req.FormValue(a.cookieOptions.LoginFormPasswordFieldName)

	auth := a.authProviderFunc(user, password)
	if auth == true {
		var cookieStore = a.cookieStore

		session, _ := cookieStore.Get(req, a.cookieOptions.SessionName)
		currentTime := time.Now().Local()

		session.Values["user"] = req.FormValue(a.cookieOptions.LoginFormUserFieldName)
		session.Values["loginTime"] = currentTime.Format(time.RFC3339)
		session.Save(req, res)

		http.Redirect(res, req, "/", http.StatusFound)
	} else {
		http.Redirect(res, req, a.loginRoute, http.StatusFound)
		return
	}
}

/*
	Get path for login redirect.
*/
func (a *Attar) SetLoginRoute(r string) {
	a.loginRoute = r
}

/*
	Set 'gorilla/sessions' session cookie keys.

	For more information about NewCookieStore() refer
	to http://www.gorillatoolkit.org/pkg/sessions#NewCookieStore.
*/
func (a *Attar) CookieSessionKeys(authKey, encryptionKey []byte) {
	a.cookieStore = sessions.NewCookieStore(
		authKey,
		encryptionKey,
	)
}

// type for auth provider function
type authProvider (func(u, p string) bool)

/*
	Method for set "auth provider" function, and user verification.

	User functon must take 'user' and 'password' arguments, and return
	true (if user auth successfully) or false (if auth data false).

	Example of auth provider function:
		// user code
		func checkAuth(u, p string) bool {
			if u == "user" && p == "qwerty" {
				return true
			}
			return false
		}

	And define it:
		// user code
		a := attar.New()
		a.SetAuthProvider(checkAuth)
*/
func (a *Attar) SetAuthProvider(f authProvider) {
	a.authProviderFunc = f
}

/*
	Return Attar struct with default options.

	By default contain pre-set keys to 'gorilla/sessions' NewCookieStore
	func (provide in *Attar.CookieSessionKeys).
	It is not secure.
	Keys must be changed!

	For more information about NewCookieStore() refer
	to http://www.gorillatoolkit.org/pkg/sessions#NewCookieStore.

*/
func New() *Attar {
	return &Attar{
		// default options
		cookieOptions: &AttarOptions{
			SessionName:                "attar-session",
			SessionLifeTime:            86400,
			LoginFormUserFieldName:     "login",
			LoginFormPasswordFieldName: "password",
		},
		// use default keys is not secure! :)
		cookieStore: sessions.NewCookieStore(
			[]byte("261AD9502C583BD7D8AA03083598653B"),
			[]byte("E9F6FDFAC2772D33FC5C7B3D6E4DDAFF"),
		),
	}
}
<commit_msg>don't ignore errors<commit_after>/*
	Attar package provide simple way to get http user auth (via sessions and cookie).

	It use part of great Gorilla web toolkit, 'gorilla/sessions' package
	(http://github.com/gorilla/sessions).

	Usable example:
		import (
			"github.com/gorilla/mux"
			"html/template"
			"github.com/SpiritOfStallman/attar"
			"net/http"
		)

		// main page
		func mainPageHandler(res http.ResponseWriter, req *http.Request) {
			var mainPage string = `

HELLO!

			</form>
			`
			page := template.New("main")
			page, _ = page.Parse(mainPage)
			page.Execute(res, "")
		}

		// login page
		func loginPageHandler(res http.ResponseWriter, req *http.Request) {
			var loginPage string = `

			<form id="login_form" action="/login" method="POST" style="padding-top:15%;">
			<input type="text" name="login" placeholder="Login" autofocus>

			<input type="password" placeholder="Password" name="password">

			<input type="submit" value="LOGIN">
			</form>
			`
			page := template.New("main")
			page, _ = page.Parse(loginPage)
			page.Execute(res, "")
		}

		// auth provider function
		func checkAuth(u, p string) bool {
			if u == "user" && p == "qwerty" {
				return true
			}
			return false
		}

		func main() {

			a := attar.New()

			a.SetAuthProvider(checkAuth)
			a.SetLoginRoute("/login")

			// set options, with session & cookie lifetime == 30 sec
			options := &attar.AttarOptions{
				Path:                       "/",
				MaxAge:                     30,
				HttpOnly:                   true,
				SessionName:                "test-session",
				SessionLifeTime:            15,
				LoginFormUserFieldName:     "login",
				LoginFormPasswordFieldName: "password",
			}
			a.SetAttarOptions(options)

			// create mux router
			router := mux.NewRouter()
			router.HandleFunc("/", mainPageHandler)
			router.HandleFunc("/login", loginPageHandler).Methods("GET")
			// set attar.AuthHandler as handler func
			// for check login POST data
			router.HandleFunc("/login", a.AuthHandler).Methods("POST")

			// set auth proxy function
			http.Handle("/", a.GlobalAuthProxy(router))

			// start net/httm server at 8080 port
			http.ListenAndServe("127.0.0.1:8080", nil)
		}
	For more information - look at the pkg doc.
*/
package attar

import (
	"net/http"
	"time"

	"github.com/gorilla/sessions"
)

type Attar struct {
	authProviderFunc authProvider
	loginRoute       string
	cookieOptions    *AttarOptions
	cookieStore      *sessions.CookieStore
}

/*
	Primary attar options (except for basic settings also accommodates a
	'gorilla/sessions' options (http://www.gorillatoolkit.org/pkg/sessions#Options)).
*/
type AttarOptions struct {
	// 'gorilla/sessions' section:
	// description see on http://www.gorillatoolkit.org/pkg/sessions#Options
	// or source on github
	Path     string
	Domain   string
	MaxAge   int
	Secure   bool
	HttpOnly bool

	// attar section:
	// name of cookie browser session
	SessionName     string // default: "attar-session"
	SessionLifeTime int    // default: 86400; in sec

	// html field names, to retrieve
	// user name and password from
	// login form
	LoginFormUserFieldName     string // default: "login"
	LoginFormPasswordFieldName string // default: "password"
}

/*
	Set attar options (*AttarOptions).
*/
func (a *Attar) SetAttarOptions(o *AttarOptions) {
	a.cookieOptions = o
}

/*
	Function for check auth session.
*/
func (a *Attar) GlobalAuthProxy(next http.Handler) http.HandlerFunc {
	return func(res http.ResponseWriter, req *http.Request) {
		if req.URL.Path == a.loginRoute {
			next.ServeHTTP(res, req)
			return
		}

		var cookieStore = a.cookieStore

		cookieStore.Options = &sessions.Options{
			Path:     a.cookieOptions.Path,
			Domain:   a.cookieOptions.Domain,
			MaxAge:   a.cookieOptions.MaxAge,
			Secure:   a.cookieOptions.Secure,
			HttpOnly: a.cookieOptions.HttpOnly,
		}

		session, err := cookieStore.Get(req, a.cookieOptions.SessionName)
		if err != nil {
			http.Error(res, err.Error(), http.StatusInternalServerError)
			return
		}
		currentTime := time.Now().Local()

		if session.Values["loginTime"] != nil {
			userLoginTimeRFC3339 := session.Values["loginTime"]
			userLoginTime, err := time.Parse(time.RFC3339, userLoginTimeRFC3339.(string))
			if err != nil {
				http.Error(res, err.Error(), http.StatusInternalServerError)
				return
			}
			if int(currentTime.Sub(userLoginTime).Seconds()) > a.cookieOptions.SessionLifeTime {
				http.Redirect(res, req, a.loginRoute, http.StatusFound)
				return
			}
		} else {
			http.Redirect(res, req, a.loginRoute, http.StatusFound)
			return
		}

		next.ServeHTTP(res, req)
	}
}

/*
	Auth handler, for grub login form data, and init cookie session.
*/
func (a *Attar) AuthHandler(res http.ResponseWriter, req *http.Request) {
	user := req.FormValue(a.cookieOptions.LoginFormUserFieldName)
	password := req.FormValue(a.cookieOptions.LoginFormPasswordFieldName)

	auth := a.authProviderFunc(user, password)
	if auth == true {
		var cookieStore = a.cookieStore

		session, err := cookieStore.Get(req, a.cookieOptions.SessionName)
		if err != nil {
			http.Error(res, err.Error(), http.StatusInternalServerError)
			return
		}
		currentTime := time.Now().Local()

		session.Values["user"] = req.FormValue(a.cookieOptions.LoginFormUserFieldName)
		session.Values["loginTime"] = currentTime.Format(time.RFC3339)
		session.Save(req, res)

		http.Redirect(res, req, "/", http.StatusFound)
	} else {
		http.Redirect(res, req, a.loginRoute, http.StatusFound)
		return
	}
}

/*
	Get path for login redirect.
*/
func (a *Attar) SetLoginRoute(r string) {
	a.loginRoute = r
}

/*
	Set 'gorilla/sessions' session cookie keys.

	For more information about NewCookieStore() refer
	to http://www.gorillatoolkit.org/pkg/sessions#NewCookieStore.
*/
func (a *Attar) CookieSessionKeys(authKey, encryptionKey []byte) {
	a.cookieStore = sessions.NewCookieStore(
		authKey,
		encryptionKey,
	)
}

// type for auth provider function
type authProvider (func(u, p string) bool)

/*
	Method for set "auth provider" function, and user verification.

	User functon must take 'user' and 'password' arguments, and return
	true (if user auth successfully) or false (if auth data false).

	Example of auth provider function:
		// user code
		func checkAuth(u, p string) bool {
			if u == "user" && p == "qwerty" {
				return true
			}
			return false
		}

	And define it:
		// user code
		a := attar.New()
		a.SetAuthProvider(checkAuth)
*/
func (a *Attar) SetAuthProvider(f authProvider) {
	a.authProviderFunc = f
}

/*
	Return Attar struct with default options.

	By default contain pre-set keys to 'gorilla/sessions' NewCookieStore
	func (provide in *Attar.CookieSessionKeys).
	It is not secure.
	Keys must be changed!

	For more information about NewCookieStore() refer
	to http://www.gorillatoolkit.org/pkg/sessions#NewCookieStore.

*/
func New() *Attar {
	return &Attar{
		// default options
		cookieOptions: &AttarOptions{
			SessionName:                "attar-session",
			SessionLifeTime:            86400,
			LoginFormUserFieldName:     "login",
			LoginFormPasswordFieldName: "password",
		},
		// use default keys is not secure! :)
		cookieStore: sessions.NewCookieStore(
			[]byte("261AD9502C583BD7D8AA03083598653B"),
			[]byte("E9F6FDFAC2772D33FC5C7B3D6E4DDAFF"),
		),
	}
}
<|endoftext|>


<commit_before>package dinero

import (
	"errors"
	"time"
)

// RatesService handles retrieving forex rates for a given currency, either from
// in-memory cache or by fetching fresh results.
type RatesService service

// RatesStore holds our forex rates for a given base currency
type RatesStore struct {
	Rates     map[string]float64 `json:"rates"`
	UpdatedAt *time.Time         `json:"updated_at"`
	Base      string             `json:"base"`
}

var baseCurrency string

// GetBaseCurrency will return the baseCurrency.
func (s *RatesService) GetBaseCurrency() string {
	return baseCurrency
}

// SetBaseCurrency will set the base currency to be used for requests.
func (s *RatesService) SetBaseCurrency(base string) {
	baseCurrency = base
}

// All will build and execute request to fetch the latest rates for given base
// currency either from the in-memory cache or OXR API.
func (s *RatesService) All() (*RatesStore, error) {
	// No base currency provided, let them know!
	if baseCurrency == "" {
		return nil, errors.New("please set a base currency.")
	}

	// If we have cached results, use them.
	results := s.client.Cache.Get(baseCurrency)
	if results != nil {
		return results, nil
	}

	// No cached results, go and fetch them.
	err := s.client.Update.LatestRates(baseCurrency)
	if err != nil {
		return nil, err
	}

	return s.All()
}

// Single will return forex rate for given base/code.
func (s *RatesService) Single(code string) (*float64, error) {
	// No base currency provided, let them know!
	if baseCurrency == "" || code == "" {
		return nil, errors.New("both the base currency and requested currency values must be set")
	}

	// If we have cached results, use them.
	results := s.client.Cache.Get(baseCurrency)
	if results != nil {
		single := results.Rates[code]
		return &single, nil
	}

	// No cached results, go and fetch them.
	err := s.client.Update.LatestRates(baseCurrency)
	if err != nil {
		return nil, err
	}

	return s.Single(code)
}
<commit_msg>Update rates.go<commit_after>package dinero

import (
	"errors"
	"time"
)

// RatesService handles retrieving forex rates for a given currency, either from
// in-memory cache or by fetching fresh results.
type RatesService service

// RatesStore holds our forex rates for a given base currency
type RatesStore struct {
	Rates     map[string]float64 `json:"rates"`
	UpdatedAt *time.Time         `json:"updated_at"`
	Base      string             `json:"base"`
}

var baseCurrency string

// GetBaseCurrency will return the baseCurrency.
func (s *RatesService) GetBaseCurrency() string {
	return baseCurrency
}

// SetBaseCurrency will set the base currency to be used for requests.
func (s *RatesService) SetBaseCurrency(base string) {
	baseCurrency = base
}

// All will build and execute request to fetch the latest rates for given base
// currency either from the in-memory cache or OXR API.
func (s *RatesService) All() (*RatesStore, error) {
	// No base currency provided, let them know!
	if baseCurrency == "" {
		return nil, errors.New("please set a base currency")
	}

	// If we have cached results, use them.
	results := s.client.Cache.Get(baseCurrency)
	if results != nil {
		return results, nil
	}

	// No cached results, go and fetch them.
	err := s.client.Update.LatestRates(baseCurrency)
	if err != nil {
		return nil, err
	}

	return s.All()
}

// Single will return forex rate for given base/code.
func (s *RatesService) Single(code string) (*float64, error) {
	// No base currency provided, let them know!
	if baseCurrency == "" || code == "" {
		return nil, errors.New("both the base currency and requested currency values must be set")
	}

	// If we have cached results, use them.
	results := s.client.Cache.Get(baseCurrency)
	if results != nil {
		single := results.Rates[code]
		return &single, nil
	}

	// No cached results, go and fetch them.
	err := s.client.Update.LatestRates(baseCurrency)
	if err != nil {
		return nil, err
	}

	return s.Single(code)
}
<|endoftext|>


<commit_before><commit_msg>feat: add contains method for arrays<commit_after><|endoftext|>


<commit_before>/*
Package ratio allows to make rate limited i/o.

To create a rate limited io.Writer:

	// Create a new rate-limited writer.
	rw := ratio.RateLimitedWriter(w, 10e6, time.Second)
	io.Copy(rw, reader)

*/
package ratio

import (
	"io"
	"time"
)

const (
	step = 1000
	KB   = iota * step
	MB   = KB * step
	GB   = MB * step
	TB   = GB * step
	PB   = TB * step
	EB   = PB * step
	ZB   = EB * step
	YB   = ZB * step
)

type values struct {
	n   int
	err error
}

type operation struct {
	p       []byte
	values  chan values
	written int
}

type rateLimiter struct {
	stop      chan bool
	worker    chan *operation
	action    func(p []byte) (int, error)
	limit     int
	remaining int
	written   int
	op        *operation
}

func (rl *rateLimiter) reset() {
	rl.remaining = rl.limit
}

func (rl *rateLimiter) run(duration time.Duration) {
	for {
		select {
		case <-rl.stop:
			rl.close()
			return
		case <-time.Tick(duration):
			rl.reset()
			rl.write()
		case op := <-rl.worker:
			rl.op = op
			rl.write()
		}
	}
}

func (rl *rateLimiter) write() {
	if rl.op == nil {
		return
	}

	p := rl.op.p
	if rl.remaining < len(rl.op.p) {
		p = rl.op.p[:rl.remaining]
	}
	rl.remaining -= len(p)

	n, err := rl.action(p)
	rl.op.p = rl.op.p[n:]
	rl.op.written += n

	if len(rl.op.p) == 0 || err != nil {
		rl.op.values <- values{rl.op.written, err}
		rl.op = nil
	}
}

func (rl *rateLimiter) record(p []byte) (int, error) {
	op := &operation{
		p:      p,
		values: make(chan values, 1),
	}
	select {
	case <-rl.stop:
		return 0, io.EOF
	case rl.worker <- op:
		val := <-op.values
		return val.n, val.err
	}
}

func (rl *rateLimiter) close() {
	if rl.op != nil {
		rl.op.values <- values{rl.op.written, io.EOF}
	}
}

// RateLimitedWriter returns a rate limited io.Writer, allowing to write up to size bytes per duration.
func RateLimitedWriter(w io.Writer, size int, duration time.Duration) io.WriteCloser {
	rl := &rateLimiter{
		action: func(p []byte) (int, error) {
			return w.Write(p)
		},
		limit:     size,
		remaining: size,
		stop:      make(chan bool),
		worker:    make(chan *operation),
	}
	go rl.run(duration)
	return rl
}

// RateLimitedReader returns a rate limited io.Reader, allowing to read up to size bytes per duration.
func RateLimitedReader(r io.Reader, size int, duration time.Duration) io.ReadCloser {
	rl := &rateLimiter{
		action: func(p []byte) (int, error) {
			return r.Read(p)
		},
		limit:     size,
		remaining: size,
		stop:      make(chan bool),
		worker:    make(chan *operation),
	}
	go rl.run(duration)
	return rl
}

func (rl *rateLimiter) Read(p []byte) (int, error) {
	return rl.record(p)
}

func (rl *rateLimiter) Write(p []byte) (int, error) {
	return rl.record(p)
}

func (rl *rateLimiter) Close() error {
	select {
	case <-rl.stop:
		return nil
	default:
	}
	close(rl.stop)
	return nil
}
<commit_msg>Improve wording<commit_after>/*
Package ratio allows to rate limits reads or writes.

To create a rate limited io.Writer:

	// Create a new rate-limited writer.
	rw := ratio.RateLimitedWriter(w, 10e6, time.Second)
	io.Copy(rw, reader)

*/
package ratio

import (
	"io"
	"time"
)

const (
	step = 1000
	KB   = iota * step
	MB   = KB * step
	GB   = MB * step
	TB   = GB * step
	PB   = TB * step
	EB   = PB * step
	ZB   = EB * step
	YB   = ZB * step
)

type values struct {
	n   int
	err error
}

type operation struct {
	p       []byte
	values  chan values
	written int
}

type rateLimiter struct {
	stop      chan bool
	worker    chan *operation
	action    func(p []byte) (int, error)
	limit     int
	remaining int
	written   int
	op        *operation
}

func (rl *rateLimiter) reset() {
	rl.remaining = rl.limit
}

func (rl *rateLimiter) run(duration time.Duration) {
	for {
		select {
		case <-rl.stop:
			rl.close()
			return
		case <-time.Tick(duration):
			rl.reset()
			rl.write()
		case op := <-rl.worker:
			rl.op = op
			rl.write()
		}
	}
}

func (rl *rateLimiter) write() {
	if rl.op == nil {
		return
	}

	p := rl.op.p
	if rl.remaining < len(rl.op.p) {
		p = rl.op.p[:rl.remaining]
	}
	rl.remaining -= len(p)

	n, err := rl.action(p)
	rl.op.p = rl.op.p[n:]
	rl.op.written += n

	if len(rl.op.p) == 0 || err != nil {
		rl.op.values <- values{rl.op.written, err}
		rl.op = nil
	}
}

func (rl *rateLimiter) record(p []byte) (int, error) {
	op := &operation{
		p:      p,
		values: make(chan values, 1),
	}
	select {
	case <-rl.stop:
		return 0, io.EOF
	case rl.worker <- op:
		val := <-op.values
		return val.n, val.err
	}
}

func (rl *rateLimiter) close() {
	if rl.op != nil {
		rl.op.values <- values{rl.op.written, io.EOF}
	}
}

// RateLimitedWriter returns a rate limited io.Writer, allowing to write up to size bytes per duration.
func RateLimitedWriter(w io.Writer, size int, duration time.Duration) io.WriteCloser {
	rl := &rateLimiter{
		action: func(p []byte) (int, error) {
			return w.Write(p)
		},
		limit:     size,
		remaining: size,
		stop:      make(chan bool),
		worker:    make(chan *operation),
	}
	go rl.run(duration)
	return rl
}

// RateLimitedReader returns a rate limited io.Reader, allowing to read up to size bytes per duration.
func RateLimitedReader(r io.Reader, size int, duration time.Duration) io.ReadCloser {
	rl := &rateLimiter{
		action: func(p []byte) (int, error) {
			return r.Read(p)
		},
		limit:     size,
		remaining: size,
		stop:      make(chan bool),
		worker:    make(chan *operation),
	}
	go rl.run(duration)
	return rl
}

func (rl *rateLimiter) Read(p []byte) (int, error) {
	return rl.record(p)
}

func (rl *rateLimiter) Write(p []byte) (int, error) {
	return rl.record(p)
}

func (rl *rateLimiter) Close() error {
	select {
	case <-rl.stop:
		return nil
	default:
	}
	close(rl.stop)
	return nil
}
<|endoftext|>


<commit_before><commit_msg>Use etcdclient.Config struct when creating new etcd clients<commit_after><|endoftext|>


<commit_before><commit_msg>Fix waitUpdates usage in TestFiltering<commit_after><|endoftext|>


<commit_before><commit_msg>the install command now installs the function runtimes by default too<commit_after><|endoftext|>


<commit_before>// Package sensu implements simple methods to interact with Sensu API.
package sensu

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
)

// Sensu struct contains the API details
type Sensu struct {
	Name    string
	Path    string
	URL     string
	Timeout int
	User    string
	Pass    string
}

// NoLimit do not specify a limit parameter
const NoLimit int = -1

// NoOffset do not specify an offset parameter
const NoOffset int = -1

// New Initialize a new Sensu API
func New(name string, path string, url string, timeout int, username string, password string) *Sensu {
	return &Sensu{name, path, url, timeout, username, password}
}

// Health The health endpoint checks to see if the api can connect to redis and rabbitmq. It takes parameters for minimum consumers and maximum messages and checks rabbitmq.
func (s *Sensu) Health(consumers int, messages int) (map[string]interface{}, error) {
	fmt.Printf("FIXME health args")
	return s.Get(fmt.Sprintf("health/%d/%d", consumers, messages))
}

// Info Will return the Sensu version along with rabbitmq and redis information.
func (s *Sensu) Info() (map[string]interface{}, error) {
	return s.Get("info")
}

// Get ...
func (s *Sensu) Get(endpoint string) (map[string]interface{}, error) {
	// Call a List with magic value of limit 0 and offset 0
	url := fmt.Sprintf("%s/%s", s.URL, endpoint)
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, fmt.Errorf("Parsing error: %q returned: %v", err, err)
	}

	res, err := s.doHTTP(req)
	if err != nil {
		return nil, fmt.Errorf("API call to %q returned: %v", url, err)
	}
	return s.doJSON(res)
}

// GetList Construct an API call and return the list of results
func (s *Sensu) GetList(endpoint string, limit int, offset int) ([]interface{}, error) {

	/*
		args := ""
		//ERROR GET LIST TODO deal with limit %d and offset %d", limit, offset
		if limit != NOLIMIT {
			args = fmt.Sprintf("%slimit=%d", args, limit)
		}
		if offset != NOOFFSET {
			args = fmt.Sprintf("%soffset=%d", args, limit)
		}
	*/
	url := fmt.Sprintf("%s/%s", s.URL, endpoint)
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, fmt.Errorf("URL Parsing error: %q returned: %v", url, err)
	}
	res, err := s.doHTTP(req)
	if err != nil {
		return nil, fmt.Errorf("API call to %q returned: %v", url, err)
	}
	return s.doJSONArray(res)
}

func (s *Sensu) doHTTP(req *http.Request) ([]byte, error) {

	if s.User != "" && s.Pass != "" {
		req.SetBasicAuth(s.User, s.Pass)
	}

	client := http.Client{}
	res, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("%v", err)
	}
	if res.StatusCode >= 400 {
		return nil, fmt.Errorf("%v", res.Status)
	}

	body, err := ioutil.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
		return nil, fmt.Errorf("Parsing response body returned: %v", err)
	}
	return body, nil
}

// doJsonArray Unmarshall JSON expecting an array
func (s *Sensu) doJSONArray(body []byte) ([]interface{}, error) {
	var results []interface{}
	if err := json.Unmarshal(body, &results); err != nil {
		return nil, fmt.Errorf("Parsing JSON-encoded response body: %v", err)
	}
	return results, nil
}

// doJsonArray Unmarshall JSON expecting a map
func (s *Sensu) doJSON(body []byte) (map[string]interface{}, error) {
	var results map[string]interface{}
	if err := json.Unmarshal(body, &results); err != nil {
		return nil, fmt.Errorf("Parsing JSON-encoded response body: %v", err)
	}

	fmt.Printf("\n hello do json, got: %v", results)

	return results, nil
}

// Post to endpoint
func (s *Sensu) Post(endpoint string) (map[string]interface{}, error) {
	// Call a List with magic value of limit 0 and offset 0

	//ERROR GET LIST TODO deal with limit %d and offset %d", limit, offset

	url := fmt.Sprintf("%s/%s", s.URL, endpoint)
	req, err := http.NewRequest("POST", url, nil)
	if err != nil {
		return nil, fmt.Errorf("Parsing error: %q returned: %v", url, err)
	}

	res, err := s.doHTTP(req)
	if err != nil {
		return nil, fmt.Errorf("API call to %q returned: %v", url, err)
	}
	return s.doJSON(res)
}

// PostPayload to endpoint
func (s *Sensu) PostPayload(endpoint string, payload string) (map[string]interface{}, error) {
	fmt.Printf("DEBUG: PostPayload = %s", payload)

	url := fmt.Sprintf("%s/%s", s.URL, endpoint)
	req, err := http.NewRequest("POST", url, strings.NewReader(payload))
	//      'Content-Type': 'application/json',
	//    'Content-Length': data.length
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Content-Length", fmt.Sprintf("%d", len(payload)))
	if err != nil {
		return nil, fmt.Errorf("Parsing error: %q returned: %v", url, err)
	}
	res, err := s.doHTTP(req)
	if err != nil {
		return nil, fmt.Errorf("API call to %q returned: %v", url, err)
	}
	return s.doJSON(res)
}

// Delete resource
func (s *Sensu) Delete(endpoint string) (map[string]interface{}, error) {
	url := fmt.Sprintf("%s/%s", s.URL, endpoint)
	req, err := http.NewRequest("DELETE", url, nil)
	if err != nil {
		return nil, fmt.Errorf("Parsing error: %q returned: %v", err, err)
	}

	res, err := s.doHTTP(req)
	if err != nil {
		return nil, fmt.Errorf("API call to %q returned: %v", url, err)
	}
	return s.doJSON(res)
}
<commit_msg>Apparently DELETE is not a valid method...<commit_after>// Package sensu implements simple methods to interact with Sensu API.
package sensu

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	//"bytes"
)

// Sensu struct contains the API details
type Sensu struct {
	Name    string
	Path    string
	URL     string
	Timeout int
	User    string
	Pass    string
}

// NoLimit do not specify a limit parameter
const NoLimit int = -1

// NoOffset do not specify an offset parameter
const NoOffset int = -1

// New Initialize a new Sensu API
func New(name string, path string, url string, timeout int, username string, password string) *Sensu {
	return &Sensu{name, path, url, timeout, username, password}
}

// Health The health endpoint checks to see if the api can connect to redis and rabbitmq. It takes parameters for minimum consumers and maximum messages and checks rabbitmq.
func (s *Sensu) Health(consumers int, messages int) (map[string]interface{}, error) {
	fmt.Printf("FIXME health args")
	return s.Get(fmt.Sprintf("health/%d/%d", consumers, messages))
}

// Info Will return the Sensu version along with rabbitmq and redis information.
func (s *Sensu) Info() (map[string]interface{}, error) {
	return s.Get("info")
}

// Get ...
func (s *Sensu) Get(endpoint string) (map[string]interface{}, error) {
	// Call a List with magic value of limit 0 and offset 0
	url := fmt.Sprintf("%s/%s", s.URL, endpoint)
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, fmt.Errorf("Parsing error: %q returned: %v", err, err)
	}

	res, err := s.doHTTP(req)
	if err != nil {
		return nil, fmt.Errorf("API call to %q returned: %v", url, err)
	}
	return s.doJSON(res)
}

// GetList Construct an API call and return the list of results
func (s *Sensu) GetList(endpoint string, limit int, offset int) ([]interface{}, error) {

	/*
		args := ""
		//ERROR GET LIST TODO deal with limit %d and offset %d", limit, offset
		if limit != NOLIMIT {
			args = fmt.Sprintf("%slimit=%d", args, limit)
		}
		if offset != NOOFFSET {
			args = fmt.Sprintf("%soffset=%d", args, limit)
		}
	*/
	url := fmt.Sprintf("%s/%s", s.URL, endpoint)
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, fmt.Errorf("URL Parsing error: %q returned: %v", url, err)
	}
	res, err := s.doHTTP(req)
	if err != nil {
		return nil, fmt.Errorf("API call to %q returned: %v", url, err)
	}
	return s.doJSONArray(res)
}

func (s *Sensu) doHTTP(req *http.Request) ([]byte, error) {

	if s.User != "" && s.Pass != "" {
		req.SetBasicAuth(s.User, s.Pass)
	}

	client := http.Client{}
	res, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("%v", err)
	}
	if res.StatusCode >= 400 {
		return nil, fmt.Errorf("%v", res.Status)
	}

	body, err := ioutil.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
		return nil, fmt.Errorf("Parsing response body returned: %v", err)
	}
	return body, nil
}

// doJsonArray Unmarshall JSON expecting an array
func (s *Sensu) doJSONArray(body []byte) ([]interface{}, error) {
	var results []interface{}
	if err := json.Unmarshal(body, &results); err != nil {
		return nil, fmt.Errorf("Parsing JSON-encoded response body: %v", err)
	}
	return results, nil
}

// doJsonArray Unmarshall JSON expecting a map
func (s *Sensu) doJSON(body []byte) (map[string]interface{}, error) {
	var results map[string]interface{}
	if err := json.Unmarshal(body, &results); err != nil {
		return nil, fmt.Errorf("Parsing JSON-encoded response body: %v", err)
	}
	return results, nil
}

// Post to endpoint
func (s *Sensu) Post(endpoint string) (map[string]interface{}, error) {
	// Call a List with magic value of limit 0 and offset 0

	//ERROR GET LIST TODO deal with limit %d and offset %d", limit, offset

	url := fmt.Sprintf("%s/%s", s.URL, endpoint)
	req, err := http.NewRequest("POST", url, nil)
	if err != nil {
		return nil, fmt.Errorf("Parsing error: %q returned: %v", url, err)
	}

	res, err := s.doHTTP(req)
	if err != nil {
		return nil, fmt.Errorf("API call to %q returned: %v", url, err)
	}
	return s.doJSON(res)
}

// PostPayload to endpoint
func (s *Sensu) PostPayload(endpoint string, payload string) (map[string]interface{}, error) {
	fmt.Printf("DEBUG: PostPayload = %s\n", payload)
	url := fmt.Sprintf("%s/%s", s.URL, endpoint)

	req, err := http.NewRequest("POST", url, strings.NewReader(fmt.Sprintf("%s\n\n", payload)))

	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Content-Length", fmt.Sprintf("%d", len(payload)))

	if err != nil {
		return nil, fmt.Errorf("Parsing error: %q returned: %v", url, err)
	}
	res, err := s.doHTTP(req)
	if err != nil {
		return nil, fmt.Errorf("API call to %q returned: %v", url, err)
	}
	return s.doJSON(res)
}

// Delete resource
func (s *Sensu) Delete(endpoint string) (map[string]interface{}, error) {
	url := fmt.Sprintf("%s/%s", s.URL, endpoint)
	req, err := http.NewRequest("DELETE", url, nil)
	if err != nil {
		return nil, fmt.Errorf("Parsing error: %q returned: %v", err, err)
	}

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("API call to %q returned: %v", url, err)
	}

	if err != nil {
		return nil, fmt.Errorf("%v", err)
	}
	if res.StatusCode >= 400 {
		return nil, fmt.Errorf("%v", res.Status)
	}

	body, err := ioutil.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
		return nil, fmt.Errorf("Parsing response body returned: %v", err)
	}
	return s.doJSON(body)
}
<|endoftext|>


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

package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os/exec"
	"sort"
	"strings"
	"time"

	"golang.org/x/tools/go/loader"
	"golang.org/x/tools/godoc"

	"github.com/fzipp/pythia/static"
)

var (
	indexView  = parseTemplate("index.html")
	sourceView = parseTemplate("source.html")
)

// serveIndex delivers the scope index page, which is the first
// page presented to the user.
func serveIndex(w http.ResponseWriter, req *http.Request) {
	err := indexView.Execute(w, struct {
		Scope    string
		Packages []*loader.PackageInfo
	}{
		Scope:    strings.Join(args, " "),
		Packages: packages,
	})
	if err != nil {
		log.Println(err)
	}
}

// serveSource delivers the source view page, which is the main
// workspace of the tool, where the user creates the queries to
// the guru and browses their results.
//
// The request parameter 'file' determines the source file to be
// shown initially, e.g. "/path/to/file.go". The contents of the
// file are not loaded in this request, but in a subsequent
// asynchronous request handled by serveFile.
//
// Returns a "403 Forbidden" status code if the requested file
// is not within the import scope.
func serveSource(w http.ResponseWriter, req *http.Request) {
	file := req.FormValue("file")
	if isForbidden(file) {
		errorForbidden(w)
		return
	}
	err := sourceView.Execute(w, file)
	if err != nil {
		log.Println(err)
	}
}

// serveFile delivers an HTML fragment of a Go source file with
// highlighted comments and an (optional) highlighted selection.
// The request parameters are:
//
//   path: "/path/to/file.go"
//   s: optional selection range like "line.col-line.col", e.g. "24.4-25.10"
//
// Returns a "403 Forbidden" status code if the requested file
// is not within the import scope, or a "404 Not Found" if the
// file can't be read.
func serveFile(w http.ResponseWriter, req *http.Request) {
	path := req.FormValue("path")
	if isForbidden(path) {
		errorForbidden(w)
		return
	}
	content, err := ioutil.ReadFile(path)
	if err != nil {
		log.Println(req.RemoteAddr, err)
		http.NotFound(w, req)
		return
	}

	var sel godoc.Selection
	s, err := parseSelection(req.FormValue("s"))
	if err == nil {
		offsets := s.byteOffsetsIn(content)
		sel = godoc.RangeSelection(offsets)
	}

	var buf bytes.Buffer
	godoc.FormatText(&buf, content, -1, true, "", sel)

	buf.WriteTo(w)
}

// isForbidden checks if the given file path is in the file set of the
// imported scope and returns true if not, otherwise false.
func isForbidden(path string) bool {
	// files must be sorted!
	i := sort.SearchStrings(files, path)
	return i >= len(files) || files[i] != path
}

func errorForbidden(w http.ResponseWriter) {
	http.Error(w, "Forbidden", 403)
}

// serveQuery executes a query to the guru and delivers the results
// in the specified format. The request parameters are:
//
//   mode: e.g. "describe", "callers", "freevars", ...
//   pos: file name with byte offset(s), e.g. "/path/to/file.go:#1457,#1462"
//   format: "json" or "plain", no "xml" at the moment
//
// If the application was launched in verbose mode, each query will be
// logged like an invocation of the guru command.
func serveQuery(w http.ResponseWriter, req *http.Request) {
	mode := req.FormValue("mode")
	pos := req.FormValue("pos")
	format := req.FormValue("format")
	if format != "json" && format != "plain" {
		fmt.Println("Warning: incorrect format:", mode, pos, format)
	}
	// Call guru
	args := []string{}
	if format == "json" {
		args = append(args, "-json")
	}
	args = append(args, mode)
	args = append(args, pos)
	if *verbose {
		log.Println(args)
	}
	out, err := exec.Command(guruPath, args...).Output()
	if err != nil {
		log.Fatal(err)
	}
	w.Write(out)
}

// serveStatic delivers the contents of a file from the static file map.
func serveStatic(w http.ResponseWriter, req *http.Request) {
	name := req.URL.Path
	data, ok := static.Files[name]
	if !ok {
		http.NotFound(w, req)
		return
	}
	http.ServeContent(w, req, name, time.Time{}, strings.NewReader(data))
}
<commit_msg>respond with http error status code instead of log.Fatal if guru command failed<commit_after>// Copyright 2013 Frederik Zipp.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os/exec"
	"sort"
	"strings"
	"time"

	"golang.org/x/tools/go/loader"
	"golang.org/x/tools/godoc"

	"github.com/fzipp/pythia/static"
)

var (
	indexView  = parseTemplate("index.html")
	sourceView = parseTemplate("source.html")
)

// serveIndex delivers the scope index page, which is the first
// page presented to the user.
func serveIndex(w http.ResponseWriter, req *http.Request) {
	err := indexView.Execute(w, struct {
		Scope    string
		Packages []*loader.PackageInfo
	}{
		Scope:    strings.Join(args, " "),
		Packages: packages,
	})
	if err != nil {
		log.Println(err)
	}
}

// serveSource delivers the source view page, which is the main
// workspace of the tool, where the user creates the queries to
// the guru and browses their results.
//
// The request parameter 'file' determines the source file to be
// shown initially, e.g. "/path/to/file.go". The contents of the
// file are not loaded in this request, but in a subsequent
// asynchronous request handled by serveFile.
//
// Returns a "403 Forbidden" status code if the requested file
// is not within the import scope.
func serveSource(w http.ResponseWriter, req *http.Request) {
	file := req.FormValue("file")
	if isForbidden(file) {
		errorForbidden(w)
		return
	}
	err := sourceView.Execute(w, file)
	if err != nil {
		log.Println(err)
	}
}

// serveFile delivers an HTML fragment of a Go source file with
// highlighted comments and an (optional) highlighted selection.
// The request parameters are:
//
//   path: "/path/to/file.go"
//   s: optional selection range like "line.col-line.col", e.g. "24.4-25.10"
//
// Returns a "403 Forbidden" status code if the requested file
// is not within the import scope, or a "404 Not Found" if the
// file can't be read.
func serveFile(w http.ResponseWriter, req *http.Request) {
	path := req.FormValue("path")
	if isForbidden(path) {
		errorForbidden(w)
		return
	}
	content, err := ioutil.ReadFile(path)
	if err != nil {
		log.Println(req.RemoteAddr, err)
		http.NotFound(w, req)
		return
	}

	var sel godoc.Selection
	s, err := parseSelection(req.FormValue("s"))
	if err == nil {
		offsets := s.byteOffsetsIn(content)
		sel = godoc.RangeSelection(offsets)
	}

	var buf bytes.Buffer
	godoc.FormatText(&buf, content, -1, true, "", sel)

	buf.WriteTo(w)
}

// isForbidden checks if the given file path is in the file set of the
// imported scope and returns true if not, otherwise false.
func isForbidden(path string) bool {
	// files must be sorted!
	i := sort.SearchStrings(files, path)
	return i >= len(files) || files[i] != path
}

func errorForbidden(w http.ResponseWriter) {
	http.Error(w, "Forbidden", 403)
}

// serveQuery executes a query to the guru and delivers the results
// in the specified format. The request parameters are:
//
//   mode: e.g. "describe", "callers", "freevars", ...
//   pos: file name with byte offset(s), e.g. "/path/to/file.go:#1457,#1462"
//   format: "json" or "plain", no "xml" at the moment
//
// If the application was launched in verbose mode, each query will be
// logged like an invocation of the guru command.
func serveQuery(w http.ResponseWriter, req *http.Request) {
	mode := req.FormValue("mode")
	pos := req.FormValue("pos")
	format := req.FormValue("format")
	if format != "json" && format != "plain" {
		fmt.Println("Warning: incorrect format:", mode, pos, format)
	}
	// Call guru
	args := []string{}
	if format == "json" {
		args = append(args, "-json")
	}
	args = append(args, mode)
	args = append(args, pos)
	if *verbose {
		log.Println(args)
	}
	out, err := exec.Command(guruPath, args...).Output()
	if err != nil {
		log.Println("launch guru command:", err)
		http.Error(w, "guru command failed", http.StatusInternalServerError)
		return
	}
	w.Write(out)
}

// serveStatic delivers the contents of a file from the static file map.
func serveStatic(w http.ResponseWriter, req *http.Request) {
	name := req.URL.Path
	data, ok := static.Files[name]
	if !ok {
		http.NotFound(w, req)
		return
	}
	http.ServeContent(w, req, name, time.Time{}, strings.NewReader(data))
}
<|endoftext|>


<commit_before>package goory

import (
	"github.com/bongo227/goory/instructions"
	"github.com/bongo227/goory/types"
	"github.com/bongo227/goory/value"
)

type nextName func() string

// Block is a seqential list of instructions
type Block struct {
	function     *Function
	name         string
	instructions []instructions.Instruction
	nextName     nextName
}

func newBlock(function *Function, name string) *Block {
	return &Block{
		function: function,
		name:     name,
		nextName: function.module.nextTempName,
	}
}

// Function returns the parent function
func (b *Block) Function() *Function {
	return b.function
}

// Name gets the name of the block
func (b *Block) Name() string {
	return b.name
}

// String gets the name of the block
func (b *Block) String() string {
	return b.name
}

func (b *Block) Type() types.Type {
	return types.NewBlockType()
}

// Ident gets the identifyer of the block
func (b *Block) Ident() string {
	return b.name
}

// Terminated returns true if the block is terminated (ends in branch or return)
func (b *Block) Terminated() bool {
	return b.instructions[len(b.instructions)-1].IsTerminator()
}

func (b *Block) IsGlobal() bool {
	return false
}

func (b *Block) IsBlock() bool {
	return true
}

// Add creates a new add instruction
func (b *Block) Add(lhs value.Value, rhs value.Value) value.Value {
	i := instructions.NewAdd(b.nextName(), lhs, rhs)
	b.instructions = append(b.instructions, i)
	return i
}

// And create a new and instruction
func (b *Block) And(lhs, rhs value.Value) value.Value {
	i := instructions.NewAnd(b.nextName(), lhs, rhs)
	b.instructions = append(b.instructions, i)
	return i
}

// Br creates a new br instruction
func (b *Block) Br(block value.Value) value.Value {
	i := instructions.NewBr(b.nextName(), block)
	b.instructions = append(b.instructions, i)
	return i
}

// Call creates a new call instruction
func (b *Block) Call(function value.Value, operands ...value.Value) value.Value {
	i := instructions.NewCall(b.nextName(), function, operands...)
	b.instructions = append(b.instructions, i)
	return i
}

// CondBr creates a new conditional branch instruction
func (b *Block) CondBr(condition, trueBlock, falseBlock value.Value) value.Value {
	i := instructions.NewCondBr(b.nextName(), condition, trueBlock, falseBlock)
	b.instructions = append(b.instructions, i)
	return i
}

// Div creates a new integer division instruction
func (b *Block) Div(lhs, rhs value.Value) value.Value {
	i := instructions.NewDiv(b.nextName(), lhs, rhs)
	b.instructions = append(b.instructions, i)
	return i
}

// Fadd creates a new float add instruction
func (b *Block) Fadd(lhs value.Value, rhs value.Value) value.Value {
	i := instructions.NewFadd(b.nextName(), lhs, rhs)
	b.instructions = append(b.instructions, i)
	return i
}

// Fcmp creates a new float add instruction
func (b *Block) Fcmp(mode string, lhs, rhs value.Value) value.Value {
	i := instructions.NewFcmp(b.nextName(), mode, lhs, rhs)
	b.instructions = append(b.instructions, i)
	return i
}

// Fdiv creates a new float add instruction
func (b *Block) Fdiv(lhs value.Value, rhs value.Value) value.Value {
	i := instructions.NewFdiv(b.nextName(), lhs, rhs)
	b.instructions = append(b.instructions, i)
	return i
}

// Fmul creates a new float add instruction
func (b *Block) Fmul(lhs value.Value, rhs value.Value) value.Value {
	i := instructions.NewFmul(b.nextName(), lhs, rhs)
	b.instructions = append(b.instructions, i)
	return i
}

// Fpext creates a new float add instruction
func (b *Block) Fpext(value value.Value, cast types.Type) value.Value {
	i := instructions.NewFpext(b.nextName(), value, cast)
	b.instructions = append(b.instructions, i)
	return i
}

// Fptosi creates a new float add instruction
func (b *Block) Fptosi(value value.Value, cast types.Type) value.Value {
	i := instructions.NewFptosi(b.nextName(), value, cast)
	b.instructions = append(b.instructions, i)
	return i
}

// Fptrunc creates a new float add instruction
func (b *Block) Fptrunc(value value.Value, cast types.Type) value.Value {
	i := instructions.NewFptrunc(b.nextName(), value, cast)
	b.instructions = append(b.instructions, i)
	return i
}

// Fsub creates a new float add instruction
func (b *Block) Fsub(lhs value.Value, rhs value.Value) value.Value {
	i := instructions.NewFsub(b.nextName(), lhs, rhs)
	b.instructions = append(b.instructions, i)
	return i
}

var (
	// IntEq is an integer equals comparison
	IntEq = "eq"

	// IntUlt is an integer unordered less than comparison
	IntUlt = "ult"
)

// Icmp creates a new float add instruction
func (b *Block) Icmp(mode string, lhs, rhs value.Value) value.Value {
	i := instructions.NewIcmp(b.nextName(), mode, lhs, rhs)
	b.instructions = append(b.instructions, i)
	return i
}

// Mul creates a new float add instruction
func (b *Block) Mul(lhs value.Value, rhs value.Value) value.Value {
	i := instructions.NewMul(b.nextName(), lhs, rhs)
	b.instructions = append(b.instructions, i)
	return i
}

// Or creates a new float add instruction
func (b *Block) Or(lhs value.Value, rhs value.Value) value.Value {
	i := instructions.NewOr(b.nextName(), lhs, rhs)
	b.instructions = append(b.instructions, i)
	return i
}

// Ret creates a new return instruction
func (b *Block) Ret(value value.Value) {
	i := instructions.NewRet(b.nextName(), value)
	b.instructions = append(b.instructions, i)
}

// Sitofp creates a new float add instruction
func (b *Block) Sitofp(value value.Value, cast types.Type) value.Value {
	i := instructions.NewSitofp(b.nextName(), value, cast)
	b.instructions = append(b.instructions, i)
	return i
}

// Sub creates a new float add instruction
func (b *Block) Sub(lhs value.Value, rhs value.Value) value.Value {
	i := instructions.NewSub(b.nextName(), lhs, rhs)
	b.instructions = append(b.instructions, i)
	return i
}

// Trunc creates a new float add instruction
func (b *Block) Trunc(value value.Value, cast types.Type) value.Value {
	i := instructions.NewTrunc(b.nextName(), value, cast)
	b.instructions = append(b.instructions, i)
	return i
}

// Xor creates a new float add instruction
func (b *Block) Xor(lhs value.Value, rhs value.Value) value.Value {
	i := instructions.NewXor(b.nextName(), lhs, rhs)
	b.instructions = append(b.instructions, i)
	return i
}

// Zext creates a new float add instruction
func (b *Block) Zext(value value.Value, cast types.Type) value.Value {
	i := instructions.NewZext(b.nextName(), value, cast)
	b.instructions = append(b.instructions, i)
	return i
}

// // Cast creates a cast for value to type cast
// func (b *Block) Cast(value Value, cast Atomic) Instruction {
// 	atomic, isAtomic := value.Type().(Atomic)

// 	if !isAtomic {
// 		panic("Value is not an atomic type")
// 	}

// 	// Value type is the same as cast type so return an empty instruction
// 	if atomic == cast {
// 		return &none{value}
// 	}

// 	// Cast integer to integer
// 	if atomic.IsInteger() && cast.IsInteger() {
// 		if Compare(atomic, cast) == 1 {
// 			// Cast is bigger so expand value
// 			i := &zext{b.nextName(), value, cast}
// 			b.instructions = append(b.instructions, i)
// 			return i
// 		}
// 		// Cast is smaller so truncate value
// 		i := &trunc{b.nextName(), value, cast}
// 		b.instructions = append(b.instructions, i)
// 		return i
// 	}

// 	// Cast float to float
// 	if atomic.IsFloat() && cast.IsFloat() {
// 		if Compare(atomic, cast) == 1 {
// 			// Cast is bigger so expand value
// 			i := &fpext{b.nextName(), value, cast}
// 			b.instructions = append(b.instructions, i)
// 			return i
// 		}
// 		// Cast is smaller so truncate value
// 		i := &fptrunc{b.nextName(), value, cast}
// 		b.instructions = append(b.instructions, i)
// 		return i
// 	}

// 	// Cast integer to float
// 	if atomic.IsInteger() && cast.IsFloat() {
// 		i := &sitofp{b.nextName(), value, cast}
// 		b.instructions = append(b.instructions, i)
// 		return i
// 	}

// 	// Cast float to integer
// 	if atomic.IsFloat() && cast.IsInteger() {
// 		i := &fptosi{b.nextName(), value, cast}
// 		b.instructions = append(b.instructions, i)
// 		return i
// 	}

// 	panic("Cannot cast non integer or pointer value")
// }
<commit_msg>Added/changed documentation for all instructions<commit_after>package goory

import (
	"github.com/bongo227/goory/instructions"
	"github.com/bongo227/goory/types"
	"github.com/bongo227/goory/value"
)

type nextName func() string

// Block is a seqential list of instructions ending with a terminator instruction
type Block struct {
	function     *Function
	name         string
	instructions []instructions.Instruction
	nextName     nextName
}

func newBlock(function *Function, name string) *Block {
	return &Block{
		function: function,
		name:     name,
		nextName: function.module.nextTempName,
	}
}

// Function returns the parent function
func (b *Block) Function() *Function {
	return b.function
}

// Name gets the name of the block
func (b *Block) Name() string {
	return b.name
}

// String gets the name of the block
func (b *Block) String() string {
	return b.name
}

// Type returns new block type
func (b *Block) Type() types.Type {
	return types.NewBlockType()
}

// Ident gets the identifyer of the block
func (b *Block) Ident() string {
	return b.name
}

// Terminated returns true if the block is terminated (ends in branch or return)
func (b *Block) Terminated() bool {
	return b.instructions[len(b.instructions)-1].IsTerminator()
}

func (b *Block) IsGlobal() bool {
	return false
}

func (b *Block) IsBlock() bool {
	return true
}

// Add creates a new add instruction.
// lhs and rhs must be integer types of the same size.
// Add returns the result of this instruction with the same type as lhs and rhs.
func (b *Block) Add(lhs value.Value, rhs value.Value) value.Value {
	i := instructions.NewAdd(b.nextName(), lhs, rhs)
	b.instructions = append(b.instructions, i)
	return i
}

// And create a new and instruction.
// lhs and rhs must be boolean types.
// And returns the result of the instruction as a boolean type.
func (b *Block) And(lhs, rhs value.Value) value.Value {
	i := instructions.NewAnd(b.nextName(), lhs, rhs)
	b.instructions = append(b.instructions, i)
	return i
}

// Br creates a new br instruction.
// block must be a block type.
func (b *Block) Br(block value.Value) {
	i := instructions.NewBr(b.nextName(), block)
	b.instructions = append(b.instructions, i)
}

// Call creates a new call instruction.
// function must be a function type.
// operands must match the types of the function arguments.
// Call returns the result of the instruction with the same type as the function return type.
func (b *Block) Call(function value.Value, operands ...value.Value) value.Value {
	i := instructions.NewCall(b.nextName(), function, operands...)
	b.instructions = append(b.instructions, i)
	return i
}

// CondBr creates a new conditional branch instruction.
// condition must be a boolean type.
// trueBlock and falseBlock must be block types.
func (b *Block) CondBr(condition, trueBlock, falseBlock value.Value) {
	i := instructions.NewCondBr(b.nextName(), condition, trueBlock, falseBlock)
	b.instructions = append(b.instructions, i)
}

// Div creates a new integer division instruction.
// lhs and rhs must be integer types.
// Div returns the result of the instruction with the same type as lhs and rhs.
func (b *Block) Div(lhs, rhs value.Value) value.Value {
	i := instructions.NewDiv(b.nextName(), lhs, rhs)
	b.instructions = append(b.instructions, i)
	return i
}

// Fadd creates a new float add instruction.
// lhs and rhs must be float or double types.
// Fadd returns the result of the instruction with the same type as lhs and rhs.
func (b *Block) Fadd(lhs value.Value, rhs value.Value) value.Value {
	i := instructions.NewFadd(b.nextName(), lhs, rhs)
	b.instructions = append(b.instructions, i)
	return i
}

// Fcmp creates a new float add instruction.
// mode controls the behavior of the comparison, see https://godoc.org/github.com/bongo227/goory#pkg-variables.
// lhs and rhs must be float or double types.
// Fcmp returns the result of the instruction as a boolean type.
func (b *Block) Fcmp(mode string, lhs, rhs value.Value) value.Value {
	i := instructions.NewFcmp(b.nextName(), mode, lhs, rhs)
	b.instructions = append(b.instructions, i)
	return i
}

// Fdiv creates a new float add instruction.
// lhs and rhs must be float or double types.
// Fdiv returns the result of the instruction with the same type as lhs and rhs.
func (b *Block) Fdiv(lhs value.Value, rhs value.Value) value.Value {
	i := instructions.NewFdiv(b.nextName(), lhs, rhs)
	b.instructions = append(b.instructions, i)
	return i
}

// Fmul creates a new float add instruction.
// lhs and rhs must be float or double types.
// Fmul returns the result of the instruction with the same type as lhs and rhs.
func (b *Block) Fmul(lhs value.Value, rhs value.Value) value.Value {
	i := instructions.NewFmul(b.nextName(), lhs, rhs)
	b.instructions = append(b.instructions, i)
	return i
}

// Fpext creates a new float extention instruction.
// value must be a float or double type.
// cast must be a type larger than value.
// Fpext returns the result of the instruction with the same type as cast.
func (b *Block) Fpext(value value.Value, cast types.Type) value.Value {
	// TODO: add support for fp128 etc
	i := instructions.NewFpext(b.nextName(), value, cast)
	b.instructions = append(b.instructions, i)
	return i
}

// Fptosi creates a new float to signed integer type.
// value must be a float of double type.
// cast must be an integer type.
// Fptosi returns the result of the instruction with the same type as cast.
func (b *Block) Fptosi(value value.Value, cast types.Type) value.Value {
	i := instructions.NewFptosi(b.nextName(), value, cast)
	b.instructions = append(b.instructions, i)
	return i
}

// Fptrunc creates a new float truncation.
// value must be a float or double type.
// cast must be a type smaller than value.
// Fptrunc returns the result of the instruction with the same type as cast.
func (b *Block) Fptrunc(value value.Value, cast types.Type) value.Value {
	i := instructions.NewFptrunc(b.nextName(), value, cast)
	b.instructions = append(b.instructions, i)
	return i
}

// Fsub creates a new float subtraction instruction.
// lhs and rhs must be float or double types.
// Fsub returns the result of the instruction with the same type as lhs and rhs.
func (b *Block) Fsub(lhs value.Value, rhs value.Value) value.Value {
	i := instructions.NewFsub(b.nextName(), lhs, rhs)
	b.instructions = append(b.instructions, i)
	return i
}

var (
	// IntEq is an integer equals comparison
	IntEq = "eq"

	// IntUlt is an integer unordered less than comparison
	IntUlt = "ult"
)

// Icmp creates a new integer comparison instruction.
// mode controls the behavior of the comparison, see: https://godoc.org/github.com/bongo227/goory#pkg-variables.
// lhs and rhs must be integer types of the the same size.
// Icmp returns the result of the instruction as a boolean type.
func (b *Block) Icmp(mode string, lhs, rhs value.Value) value.Value {
	i := instructions.NewIcmp(b.nextName(), mode, lhs, rhs)
	b.instructions = append(b.instructions, i)
	return i
}

// Mul creates a new integer multiplication instruction.
// lhs and rhs must be integer types of the the same size.
// Mul returns the result of the instruction with the same type as lhs and rhs.
func (b *Block) Mul(lhs value.Value, rhs value.Value) value.Value {
	i := instructions.NewMul(b.nextName(), lhs, rhs)
	b.instructions = append(b.instructions, i)
	return i
}

// Or creates a new bitwise or instruction.
// lhs and rhs must be boolean types.
// Or returns the result of the instruction as a boolean type.
func (b *Block) Or(lhs value.Value, rhs value.Value) value.Value {
	i := instructions.NewOr(b.nextName(), lhs, rhs)
	b.instructions = append(b.instructions, i)
	return i
}

// Ret creates a new return instruction.
// value must be the same type as the function return type.
func (b *Block) Ret(value value.Value) {
	i := instructions.NewRet(b.nextName(), value)
	b.instructions = append(b.instructions, i)
}

// Sitofp creates a new signed integer to float instruction.
// value must be an integer type.
// cast must be a float type.
// Sitofp returns the result of the instruction with the same type as cast.
func (b *Block) Sitofp(value value.Value, cast types.Type) value.Value {
	i := instructions.NewSitofp(b.nextName(), value, cast)
	b.instructions = append(b.instructions, i)
	return i
}

// Sub creates a new float sub instruction.
// lhs and rhs must be float or double types.
// Sub retruns the result of the instruction with the same type as lhs and rhs.
func (b *Block) Sub(lhs value.Value, rhs value.Value) value.Value {
	i := instructions.NewSub(b.nextName(), lhs, rhs)
	b.instructions = append(b.instructions, i)
	return i
}

// Trunc creates a new integer truncation instruction.
// value must be an integer type.
// cast must be a integer type smaller than value.
// Trunc returns the result of the instruction with the same type as cast.
func (b *Block) Trunc(value value.Value, cast types.Type) value.Value {
	i := instructions.NewTrunc(b.nextName(), value, cast)
	b.instructions = append(b.instructions, i)
	return i
}

// Xor creates a new float exclusive or instruction.
// lhs and rhs must be boolean types.
// Xor returns the result of the instruction as a boolean type.
func (b *Block) Xor(lhs value.Value, rhs value.Value) value.Value {
	i := instructions.NewXor(b.nextName(), lhs, rhs)
	b.instructions = append(b.instructions, i)
	return i
}

// Zext creates a new zero extention instruction.
// value must be an integer type.
// cast must be a integer type larger than value.
// Zext returns the result of the instruction with the same type as cast.
func (b *Block) Zext(value value.Value, cast types.Type) value.Value {
	i := instructions.NewZext(b.nextName(), value, cast)
	b.instructions = append(b.instructions, i)
	return i
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strconv"
	"time"

	"github.com/go-redis/redis"
)

// A RedisBackend implements Backend and connects to redis
// with a 24h expiration on stored entries
type RedisBackend struct {
	ssdb   bool
	client *redis.Client
}

// Implements Backend
func (b *RedisBackend) Init(host string, port int) error {
	b.client = redis.NewClient(&redis.Options{
		Addr:     fmt.Sprintf("%s:%d", host, port),
		Password: "", // no password set
		DB:       0,  // use default DB
	})
	_, err := b.client.Ping().Result()
	return err
}

// Implements RecordedTape
func (b RedisBackend) RecordedTape(name string, i Incrementer) *RecordedTape {
	return &RecordedTape{
		tape: &RedisTape{
			name:   name,
			i:      i,
			client: b.client,
		},
	}
}

// Implements BlankTape
func (b RedisBackend) BlankTape(name string, i Incrementer) *BlankTape {
	return &BlankTape{
		tape: &RedisTape{
			ssdb:   b.ssdb,
			name:   name,
			i:      i,
			client: b.client,
		},
	}
}

// A RedisTape implements BlankTape and RecordedTape
// and stores entries with an expiration according to TTL
type RedisTape struct {
	ssdb   bool
	name   string
	i      Incrementer
	client *redis.Client
}

func (t *RedisTape) Write(data []byte) error {
	k := fmt.Sprintf("chunk:%s:%s", t.name, t.i.Key())
	if t.ssdb {
		ttl := strconv.Itoa(int(TTL / time.Second))
		if err := SSDBSetx(t.client, k, string(data), ttl).Err(); err != nil {
			return err
		}
	} else {
		if err := t.client.Set(k, data, TTL).Err(); err != nil {
			return err
		}
	}
	return nil
}

func (t *RedisTape) Read() ([]byte, error) {
	k := fmt.Sprintf("chunk:%s:%s", t.name, t.i.Key())
	return t.client.Get(k).Bytes()
}

// Implements PresetBackend
func (b RedisBackend) ReadPreset(name string) (data []byte, err error) {
	k := fmt.Sprintf("preset:%s", name)
	return b.client.Get(k).Bytes()
}

func (b RedisBackend) ReadAllPresets() (data [][]byte, err error) {
	var keys []string
	if b.ssdb {
		keys, err = SSDBKeys(b.client, "preset:", "preset:zzz", "1000").Result()
	} else {
		keys, err = b.client.Keys("preset:*").Result()
	}
	if err != nil {
		return
	}

	for _, key := range keys {
		d, e := b.client.Get(key).Bytes()
		if e != nil {
			err = e
			return
		}
		data = append(data, d)
	}

	return
}

func (b RedisBackend) WritePreset(name string, data []byte) error {
	k := fmt.Sprintf("preset:%s", name)
	if err := b.client.Set(k, data, 0).Err(); err != nil {
		return err
	}
	return nil
}

// ssdb command support
func SSDBSetx(client *redis.Client, key, value, ttl string) *redis.StatusCmd {
	cmd := redis.NewStatusCmd("setx", key, value, ttl)
	client.Process(cmd)
	return cmd
}

func SSDBKeys(client *redis.Client, start, end, limit string) *redis.StringSliceCmd {
	cmd := redis.NewStringSliceCmd("keys", start, end, limit)
	client.Process(cmd)
	return cmd
}
<commit_msg>Fixing weird issue with SSDB<commit_after>package main

import (
	"fmt"
	"time"

	"github.com/go-redis/redis"
)

// A RedisBackend implements Backend and connects to redis
// with a 24h expiration on stored entries
type RedisBackend struct {
	ssdb   bool
	client *redis.Client
}

// Implements Backend
func (b *RedisBackend) Init(host string, port int) error {
	b.client = redis.NewClient(&redis.Options{
		Addr:     fmt.Sprintf("%s:%d", host, port),
		Password: "", // no password set
		DB:       0,  // use default DB
	})
	_, err := b.client.Ping().Result()
	return err
}

// Implements RecordedTape
func (b RedisBackend) RecordedTape(name string, i Incrementer) *RecordedTape {
	return &RecordedTape{
		tape: &RedisTape{
			name:   name,
			i:      i,
			client: b.client,
		},
	}
}

// Implements BlankTape
func (b RedisBackend) BlankTape(name string, i Incrementer) *BlankTape {
	return &BlankTape{
		tape: &RedisTape{
			ssdb:   b.ssdb,
			name:   name,
			i:      i,
			client: b.client,
		},
	}
}

// A RedisTape implements BlankTape and RecordedTape
// and stores entries with an expiration according to TTL
type RedisTape struct {
	ssdb   bool
	name   string
	i      Incrementer
	client *redis.Client
}

func (t *RedisTape) Write(data []byte) error {
	k := fmt.Sprintf("chunk:%s:%s", t.name, t.i.Key())
	if t.ssdb {
		ttl := int(TTL / time.Second)
		if err := SSDBSetx(t.client, k, string(data), ttl).Err(); err != nil {
			return err
		}
	} else {
		if err := t.client.Set(k, data, TTL).Err(); err != nil {
			return err
		}
	}
	return nil
}

func (t *RedisTape) Read() ([]byte, error) {
	k := fmt.Sprintf("chunk:%s:%s", t.name, t.i.Key())
	return t.client.Get(k).Bytes()
}

// Implements PresetBackend
func (b RedisBackend) ReadPreset(name string) (data []byte, err error) {
	k := fmt.Sprintf("preset:%s", name)
	return b.client.Get(k).Bytes()
}

func (b RedisBackend) ReadAllPresets() (data [][]byte, err error) {
	var keys []string
	if b.ssdb {
		keys, err = SSDBKeys(b.client, "preset:", "preset:zzz", "1000").Result()
	} else {
		keys, err = b.client.Keys("preset:*").Result()
	}
	if err != nil {
		return
	}

	for _, key := range keys {
		d, e := b.client.Get(key).Bytes()
		if e != nil {
			err = e
			return
		}
		data = append(data, d)
	}

	return
}

func (b RedisBackend) WritePreset(name string, data []byte) error {
	k := fmt.Sprintf("preset:%s", name)
	if err := b.client.Set(k, data, 0).Err(); err != nil {
		return err
	}
	return nil
}

// ssdb command support
// this is very weird. why does it need a stringslicecommand?
func SSDBSetx(client *redis.Client, key, value string, ttl int) *redis.StringSliceCmd {
	cmd := redis.NewStringSliceCmd("setx", key, value, ttl)
	client.Process(cmd)
	return cmd
}

func SSDBKeys(client *redis.Client, start, end, limit string) *redis.StringSliceCmd {
	cmd := redis.NewStringSliceCmd("keys", start, end, limit)
	client.Process(cmd)
	return cmd
}
<|endoftext|>


<commit_before>//
// Use and distribution licensed under the Apache license version 2.
//
// See the COPYING file in the root project directory for full text.
//

package ghw

import (
	"fmt"
	"math"
	"strings"
)

// DriveType describes the general category of drive device
type DriveType int

const (
	DRIVE_TYPE_UNKNOWN DriveType = iota
	DRIVE_TYPE_HDD               // Hard disk drive
	DRIVE_TYPE_FDD               // Floppy disk drive
	DRIVE_TYPE_ODD               // Optical disk drive
	DRIVE_TYPE_SSD               // Solid-state drive
)

var (
	driveTypeString = map[DriveType]string{
		DRIVE_TYPE_UNKNOWN: "Unknown",
		DRIVE_TYPE_HDD:     "HDD",
		DRIVE_TYPE_FDD:     "FDD",
		DRIVE_TYPE_ODD:     "ODD",
		DRIVE_TYPE_SSD:     "SSD",
	}
)

func (dt DriveType) String() string {
	return driveTypeString[dt]
}

// NOTE(jaypipes): since serialized output is as "official" as we're going to
// get, let's lowercase the string output when serializing, in order to
// "normalize" the expected serialized output
func (dt DriveType) MarshalJSON() ([]byte, error) {
	return []byte("\"" + strings.ToLower(dt.String()) + "\""), nil
}

// StorageController is a category of block storage controller/driver. It
// represents more of the physical hardware interface than the storage
// protocol, which represents more of the software interface.
//
// See discussion on https://github.com/jaypipes/ghw/issues/117
type StorageController int

const (
	STORAGE_CONTROLLER_UNKNOWN StorageController = iota
	STORAGE_CONTROLLER_IDE                       // Integrated Drive Electronics
	STORAGE_CONTROLLER_SCSI                      // Small computer system interface
	STORAGE_CONTROLLER_NVME                      // Non-volatile Memory Express
	STORAGE_CONTROLLER_VIRTIO                    // Virtualized storage controller/driver
)

var (
	storageControllerString = map[StorageController]string{
		STORAGE_CONTROLLER_UNKNOWN: "Unknown",
		STORAGE_CONTROLLER_IDE:     "IDE",
		STORAGE_CONTROLLER_SCSI:    "SCSI",
		STORAGE_CONTROLLER_NVME:    "NVMe",
		STORAGE_CONTROLLER_VIRTIO:  "virtio",
	}
)

func (sc StorageController) String() string {
	return storageControllerString[sc]
}

// NOTE(jaypipes): since serialized output is as "official" as we're going to
// get, let's lowercase the string output when serializing, in order to
// "normalize" the expected serialized output
func (sc StorageController) MarshalJSON() ([]byte, error) {
	return []byte("\"" + strings.ToLower(sc.String()) + "\""), nil
}

// Disk describes a single disk drive on the host system. Disk drives provide
// raw block storage resources.
type Disk struct {
	Name                   string            `json:"name"`
	SizeBytes              uint64            `json:"size_bytes"`
	PhysicalBlockSizeBytes uint64            `json:"physical_block_size_bytes"`
	DriveType              DriveType         `json:"drive_type"`
	StorageController      StorageController `json:"storage_controller"`
	// NOTE(jaypipes): BusType is DEPRECATED. Use the DriveType and
	// StorageProtocol fields instead
	BusType BusType `json:"-"`
	BusPath string  `json:"bus_path"`
	// TODO(jaypipes): Convert this to a TopologyNode struct pointer and then
	// add to serialized output as "numa_node,omitempty"
	NUMANodeID   int          `json:"-"`
	Vendor       string       `json:"vendor"`
	Model        string       `json:"model"`
	SerialNumber string       `json:"serial_number"`
	WWN          string       `json:"wwn"`
	Partitions   []*Partition `json:"partitions"`
}

// Partition describes a logical division of a Disk.
type Partition struct {
	Disk       *Disk  `json:"-"`
	Name       string `json:"name"`
	Label      string `json:"label"`
	MountPoint string `json:"mount_point"`
	SizeBytes  uint64 `json:"size_bytes"`
	Type       string `json:"type"`
	IsReadOnly bool   `json:"read_only"`
}

// BlockInfo describes all disk drives and partitions in the host system.
type BlockInfo struct {
	// TODO(jaypipes): Deprecate this field and replace with TotalSizeBytes
	TotalPhysicalBytes uint64       `json:"total_size_bytes"`
	Disks              []*Disk      `json:"disks"`
	Partitions         []*Partition `json:"-"`
}

// Block returns a BlockInfo struct that describes the block storage resources
// of the host system.
func Block(opts ...*WithOption) (*BlockInfo, error) {
	mergeOpts := mergeOptions(opts...)
	ctx := &context{
		chroot: *mergeOpts.Chroot,
	}
	info := &BlockInfo{}
	if err := ctx.blockFillInfo(info); err != nil {
		return nil, err
	}
	return info, nil
}

func (i *BlockInfo) String() string {
	tpbs := UNKNOWN
	if i.TotalPhysicalBytes > 0 {
		tpb := i.TotalPhysicalBytes
		unit, unitStr := unitWithString(int64(tpb))
		tpb = uint64(math.Ceil(float64(tpb) / float64(unit)))
		tpbs = fmt.Sprintf("%d%s", tpb, unitStr)
	}
	dplural := "disks"
	if len(i.Disks) == 1 {
		dplural = "disk"
	}
	return fmt.Sprintf("block storage (%d %s, %s physical storage)",
		len(i.Disks), dplural, tpbs)
}

func (d *Disk) String() string {
	sizeStr := UNKNOWN
	if d.SizeBytes > 0 {
		size := d.SizeBytes
		unit, unitStr := unitWithString(int64(size))
		size = uint64(math.Ceil(float64(size) / float64(unit)))
		sizeStr = fmt.Sprintf("%d%s", size, unitStr)
	}
	atNode := ""
	if d.NUMANodeID >= 0 {
		atNode = fmt.Sprintf(" (node #%d)", d.NUMANodeID)
	}
	vendor := ""
	if d.Vendor != "" {
		vendor = " vendor=" + d.Vendor
	}
	model := ""
	if d.Model != UNKNOWN {
		model = " model=" + d.Model
	}
	serial := ""
	if d.SerialNumber != UNKNOWN {
		serial = " serial=" + d.SerialNumber
	}
	wwn := ""
	if d.WWN != UNKNOWN {
		wwn = " WWN=" + d.WWN
	}
	return fmt.Sprintf(
		"/dev/%s %s (%s) %s [@%s%s]%s%s%s%s",
		d.Name,
		d.DriveType.String(),
		sizeStr,
		d.StorageController.String(),
		d.BusPath,
		atNode,
		vendor,
		model,
		serial,
		wwn,
	)
}

func (p *Partition) String() string {
	typeStr := ""
	if p.Type != "" {
		typeStr = fmt.Sprintf("[%s]", p.Type)
	}
	mountStr := ""
	if p.MountPoint != "" {
		mountStr = fmt.Sprintf(" mounted@%s", p.MountPoint)
	}
	sizeStr := UNKNOWN
	if p.SizeBytes > 0 {
		size := p.SizeBytes
		unit, unitStr := unitWithString(int64(size))
		size = uint64(math.Ceil(float64(size) / float64(unit)))
		sizeStr = fmt.Sprintf("%d%s", size, unitStr)
	}
	return fmt.Sprintf(
		"/dev/%s (%s) %s%s",
		p.Name,
		sizeStr,
		typeStr,
		mountStr,
	)
}

// simple private struct used to encapsulate block information in a top-level
// "block" YAML/JSON map/object key
type blockPrinter struct {
	Info *BlockInfo `json:"block" yaml:"block"`
}

// YAMLString returns a string with the block information formatted as YAML
// under a top-level "block:" key
func (i *BlockInfo) YAMLString() string {
	return safeYAML(blockPrinter{i})
}

// JSONString returns a string with the block information formatted as JSON
// under a top-level "block:" key
func (i *BlockInfo) JSONString(indent bool) string {
	return safeJSON(blockPrinter{i}, indent)
}
<commit_msg>StorageProtocol -> StorageController<commit_after>//
// Use and distribution licensed under the Apache license version 2.
//
// See the COPYING file in the root project directory for full text.
//

package ghw

import (
	"fmt"
	"math"
	"strings"
)

// DriveType describes the general category of drive device
type DriveType int

const (
	DRIVE_TYPE_UNKNOWN DriveType = iota
	DRIVE_TYPE_HDD               // Hard disk drive
	DRIVE_TYPE_FDD               // Floppy disk drive
	DRIVE_TYPE_ODD               // Optical disk drive
	DRIVE_TYPE_SSD               // Solid-state drive
)

var (
	driveTypeString = map[DriveType]string{
		DRIVE_TYPE_UNKNOWN: "Unknown",
		DRIVE_TYPE_HDD:     "HDD",
		DRIVE_TYPE_FDD:     "FDD",
		DRIVE_TYPE_ODD:     "ODD",
		DRIVE_TYPE_SSD:     "SSD",
	}
)

func (dt DriveType) String() string {
	return driveTypeString[dt]
}

// NOTE(jaypipes): since serialized output is as "official" as we're going to
// get, let's lowercase the string output when serializing, in order to
// "normalize" the expected serialized output
func (dt DriveType) MarshalJSON() ([]byte, error) {
	return []byte("\"" + strings.ToLower(dt.String()) + "\""), nil
}

// StorageController is a category of block storage controller/driver. It
// represents more of the physical hardware interface than the storage
// protocol, which represents more of the software interface.
//
// See discussion on https://github.com/jaypipes/ghw/issues/117
type StorageController int

const (
	STORAGE_CONTROLLER_UNKNOWN StorageController = iota
	STORAGE_CONTROLLER_IDE                       // Integrated Drive Electronics
	STORAGE_CONTROLLER_SCSI                      // Small computer system interface
	STORAGE_CONTROLLER_NVME                      // Non-volatile Memory Express
	STORAGE_CONTROLLER_VIRTIO                    // Virtualized storage controller/driver
)

var (
	storageControllerString = map[StorageController]string{
		STORAGE_CONTROLLER_UNKNOWN: "Unknown",
		STORAGE_CONTROLLER_IDE:     "IDE",
		STORAGE_CONTROLLER_SCSI:    "SCSI",
		STORAGE_CONTROLLER_NVME:    "NVMe",
		STORAGE_CONTROLLER_VIRTIO:  "virtio",
	}
)

func (sc StorageController) String() string {
	return storageControllerString[sc]
}

// NOTE(jaypipes): since serialized output is as "official" as we're going to
// get, let's lowercase the string output when serializing, in order to
// "normalize" the expected serialized output
func (sc StorageController) MarshalJSON() ([]byte, error) {
	return []byte("\"" + strings.ToLower(sc.String()) + "\""), nil
}

// Disk describes a single disk drive on the host system. Disk drives provide
// raw block storage resources.
type Disk struct {
	Name                   string            `json:"name"`
	SizeBytes              uint64            `json:"size_bytes"`
	PhysicalBlockSizeBytes uint64            `json:"physical_block_size_bytes"`
	DriveType              DriveType         `json:"drive_type"`
	StorageController      StorageController `json:"storage_controller"`
	// NOTE(jaypipes): BusType is DEPRECATED. Use the DriveType and
	// StorageController fields instead
	BusType BusType `json:"-"`
	BusPath string  `json:"bus_path"`
	// TODO(jaypipes): Convert this to a TopologyNode struct pointer and then
	// add to serialized output as "numa_node,omitempty"
	NUMANodeID   int          `json:"-"`
	Vendor       string       `json:"vendor"`
	Model        string       `json:"model"`
	SerialNumber string       `json:"serial_number"`
	WWN          string       `json:"wwn"`
	Partitions   []*Partition `json:"partitions"`
}

// Partition describes a logical division of a Disk.
type Partition struct {
	Disk       *Disk  `json:"-"`
	Name       string `json:"name"`
	Label      string `json:"label"`
	MountPoint string `json:"mount_point"`
	SizeBytes  uint64 `json:"size_bytes"`
	Type       string `json:"type"`
	IsReadOnly bool   `json:"read_only"`
}

// BlockInfo describes all disk drives and partitions in the host system.
type BlockInfo struct {
	// TODO(jaypipes): Deprecate this field and replace with TotalSizeBytes
	TotalPhysicalBytes uint64       `json:"total_size_bytes"`
	Disks              []*Disk      `json:"disks"`
	Partitions         []*Partition `json:"-"`
}

// Block returns a BlockInfo struct that describes the block storage resources
// of the host system.
func Block(opts ...*WithOption) (*BlockInfo, error) {
	mergeOpts := mergeOptions(opts...)
	ctx := &context{
		chroot: *mergeOpts.Chroot,
	}
	info := &BlockInfo{}
	if err := ctx.blockFillInfo(info); err != nil {
		return nil, err
	}
	return info, nil
}

func (i *BlockInfo) String() string {
	tpbs := UNKNOWN
	if i.TotalPhysicalBytes > 0 {
		tpb := i.TotalPhysicalBytes
		unit, unitStr := unitWithString(int64(tpb))
		tpb = uint64(math.Ceil(float64(tpb) / float64(unit)))
		tpbs = fmt.Sprintf("%d%s", tpb, unitStr)
	}
	dplural := "disks"
	if len(i.Disks) == 1 {
		dplural = "disk"
	}
	return fmt.Sprintf("block storage (%d %s, %s physical storage)",
		len(i.Disks), dplural, tpbs)
}

func (d *Disk) String() string {
	sizeStr := UNKNOWN
	if d.SizeBytes > 0 {
		size := d.SizeBytes
		unit, unitStr := unitWithString(int64(size))
		size = uint64(math.Ceil(float64(size) / float64(unit)))
		sizeStr = fmt.Sprintf("%d%s", size, unitStr)
	}
	atNode := ""
	if d.NUMANodeID >= 0 {
		atNode = fmt.Sprintf(" (node #%d)", d.NUMANodeID)
	}
	vendor := ""
	if d.Vendor != "" {
		vendor = " vendor=" + d.Vendor
	}
	model := ""
	if d.Model != UNKNOWN {
		model = " model=" + d.Model
	}
	serial := ""
	if d.SerialNumber != UNKNOWN {
		serial = " serial=" + d.SerialNumber
	}
	wwn := ""
	if d.WWN != UNKNOWN {
		wwn = " WWN=" + d.WWN
	}
	return fmt.Sprintf(
		"/dev/%s %s (%s) %s [@%s%s]%s%s%s%s",
		d.Name,
		d.DriveType.String(),
		sizeStr,
		d.StorageController.String(),
		d.BusPath,
		atNode,
		vendor,
		model,
		serial,
		wwn,
	)
}

func (p *Partition) String() string {
	typeStr := ""
	if p.Type != "" {
		typeStr = fmt.Sprintf("[%s]", p.Type)
	}
	mountStr := ""
	if p.MountPoint != "" {
		mountStr = fmt.Sprintf(" mounted@%s", p.MountPoint)
	}
	sizeStr := UNKNOWN
	if p.SizeBytes > 0 {
		size := p.SizeBytes
		unit, unitStr := unitWithString(int64(size))
		size = uint64(math.Ceil(float64(size) / float64(unit)))
		sizeStr = fmt.Sprintf("%d%s", size, unitStr)
	}
	return fmt.Sprintf(
		"/dev/%s (%s) %s%s",
		p.Name,
		sizeStr,
		typeStr,
		mountStr,
	)
}

// simple private struct used to encapsulate block information in a top-level
// "block" YAML/JSON map/object key
type blockPrinter struct {
	Info *BlockInfo `json:"block" yaml:"block"`
}

// YAMLString returns a string with the block information formatted as YAML
// under a top-level "block:" key
func (i *BlockInfo) YAMLString() string {
	return safeYAML(blockPrinter{i})
}

// JSONString returns a string with the block information formatted as JSON
// under a top-level "block:" key
func (i *BlockInfo) JSONString(indent bool) string {
	return safeJSON(blockPrinter{i}, indent)
}
<|endoftext|>


<commit_before>package bongo

import (
	"os"

	"github.com/bongo-contrib/loaders"
	"github.com/bongo-contrib/matters"
	"github.com/bongo-contrib/models"
	"github.com/bongo-contrib/renderers"
)

type defaultApp struct {
	loaders.DefaultLoader
	*matters.Matter
	renderers.DefaultRenderer
}

func newDefaultApp() *defaultApp {
	app := &defaultApp{}
	app.Matter = matters.NewYAML()
	return app
}

//App is the main bongo application
type App struct {
	gene models.Generator
}

//New creates a new App which uses default models.Generator implementation
func New() *App {
	return NewApp(newDefaultApp())
}

//NewApp creates a new app, that uses g as the generator
func NewApp(g models.Generator) *App {
	return &App{gene: g}
}

// Run runs the app
func (g *App) Run(root string) error {
	files, err := g.gene.Load(root)
	if err != nil {
		return err
	}
	var pages models.PageList
	send := make(chan *models.Page)
	errs := make(chan error)
	for _, f := range files {
		go func(file string) {
			f, err := os.Open(file)
			if err != nil {
				errs <- err
				return
			}
			defer f.Close()
			front, body, err := g.gene.Parse(f)
			if err != nil {
				errs <- err
				return
			}
			stat, err := f.Stat()
			if err != nil {
				errs <- err
				return
			}
			send <- &models.Page{Path: file, Body: body, Data: front, ModTime: stat.ModTime()}
		}(f)
	}
	n := 0
	var fish error
END:
	for {
		select {
		case pg := <-send:
			pages = append(pages, pg)
			n++
		case perr := <-errs:
			fish = perr
			break END

		default:
			if len(files) <= n {
				break END
			}
		}

	}
	if fish != nil {
		return fish
	}
	err = g.gene.Render(root, pages)
	if err != nil {
		renderers.Rollback(root) // roll back before exiting
		return err
	}
	return nil

}
<commit_msg>refactored defalutApp<commit_after>package bongo

import (
	"os"

	"github.com/bongo-contrib/loaders"
	"github.com/bongo-contrib/matters"
	"github.com/bongo-contrib/models"
	"github.com/bongo-contrib/renderers"
)

type defaultApp struct {
	loaders.DefaultLoader
	*matters.Matter
	*renderers.DefaultRenderer
}

func newDefaultApp() *defaultApp {
	app := &defaultApp{}
	app.Matter = matters.NewYAML()
	return app
}

//App is the main bongo application
type App struct {
	gene models.Generator
}

//New creates a new App which uses default models.Generator implementation
func New() *App {
	return NewApp(newDefaultApp())
}

//NewApp creates a new app, that uses g as the generator
func NewApp(g models.Generator) *App {
	return &App{gene: g}
}

// Run runs the app
func (g *App) Run(root string) error {
	files, err := g.gene.Load(root)
	if err != nil {
		return err
	}
	var pages models.PageList
	send := make(chan *models.Page)
	errs := make(chan error)
	for _, f := range files {
		go func(file string) {
			f, err := os.Open(file)
			if err != nil {
				errs <- err
				return
			}
			defer f.Close()
			front, body, err := g.gene.Parse(f)
			if err != nil {
				errs <- err
				return
			}
			stat, err := f.Stat()
			if err != nil {
				errs <- err
				return
			}
			send <- &models.Page{Path: file, Body: body, Data: front, ModTime: stat.ModTime()}
		}(f)
	}
	n := 0
	var fish error
END:
	for {
		select {
		case pg := <-send:
			pages = append(pages, pg)
			n++
		case perr := <-errs:
			fish = perr
			break END

		default:
			if len(files) <= n {
				break END
			}
		}

	}
	if fish != nil {
		return fish
	}
	err = g.gene.Render(root, pages)
	if err != nil {
		renderers.Rollback(root) // roll back before exiting
		return err
	}
	return nil

}
<|endoftext|>


<commit_before>package collector

import (
	"github.com/henrylee2cn/pholcus/logs"
	"io"
	"os"
	"time"
)

//文件输出管理
func (self *Collector) SaveFile() {
	for !(self.CtrlLen() == 0 && len(self.FileChan) == 0) {
		select {
		case file := <-self.FileChan:
			self.outCount[2]++

			// 统计输出文件数
			self.setFileSum(1)

			// 路径： file/"RuleName"/"time"/"Name"
			dir := `result/file/` + self.Spider.GetName() + `/` + file["RuleName"].(string) + `/` + self.startTime.Format("2006年01月02日 15时04分05秒") + `/`

			// 创建/打开目录
			d, err := os.Stat(dir)
			if err != nil || !d.IsDir() {
				if err := os.MkdirAll(dir, 0777); err != nil {
					logs.Log.Error("Error: %v\n", err)
				}
			}

			// 创建文件
			f, _ := os.Create(dir + file["Name"].(string))
			io.Copy(f, file["Body"].(io.ReadCloser))
			defer func() {
				f.Close()
				file["Body"].(io.ReadCloser).Close()
			}()

			// 打印报告
			logs.Log.Informational(" * ")
			logs.Log.Notice(" *     [任务：%v | 关键词：%v]   成功下载文件： %v \n", self.Spider.GetName(), self.Spider.GetKeyword(), dir+file["Name"].(string))
			logs.Log.Informational(" * ")

			self.outCount[3]++
		default:
			time.Sleep(1e7) //0.1秒
		}
	}
}
<commit_msg>修复下载文件时Body未关闭的bug<commit_after>package collector

import (
	"github.com/henrylee2cn/pholcus/logs"
	"io"
	"os"
	"time"
)

//文件输出管理
func (self *Collector) SaveFile() {
	for !(self.CtrlLen() == 0 && len(self.FileChan) == 0) {
		select {
		case file := <-self.FileChan:
			self.outCount[2]++

			// 统计输出文件数
			self.setFileSum(1)

			// 路径： file/"RuleName"/"time"/"Name"
			dir := `result/file/` + self.Spider.GetName() + `/` + file["RuleName"].(string) + `/` + self.startTime.Format("2006年01月02日 15时04分05秒") + `/`

			// 创建/打开目录
			d, err := os.Stat(dir)
			if err != nil || !d.IsDir() {
				if err := os.MkdirAll(dir, 0777); err != nil {
					logs.Log.Error("Error: %v\n", err)
				}
			}

			// 创建文件
			f, _ := os.Create(dir + file["Name"].(string))
			io.Copy(f, file["Body"].(io.ReadCloser))
			f.Close()
			file["Body"].(io.ReadCloser).Close()

			// 打印报告
			logs.Log.Informational(" * ")
			logs.Log.Notice(" *     [任务：%v | 关键词：%v]   成功下载文件： %v \n", self.Spider.GetName(), self.Spider.GetKeyword(), dir+file["Name"].(string))
			logs.Log.Informational(" * ")

			self.outCount[3]++
		default:
			time.Sleep(1e7) //0.1秒
		}
	}
}
<|endoftext|>