<commit_before>package twitlistserver

import (
	"encoding/json"
	"log"
	"net/http"
)

// TwitterUser holds limited details about a Twitter list member.
// Only essential details are used, since the UI does not need to have
// everything to maintain the lists.
type TwitterUser struct {
	ID          int64  `json:"id"`
	Name        string `json:"name"`
	Description string `json:"description"`
}

// TwitterFriends is
type TwitterFriends struct {
	Friends []TwitterUser `json:"friends"`
}

// FriendsHandler handles GET requests on /users.
// It returns all contacts of the current user on Twitter.
// This allows the UI to offer a list of users to add to a list.
func FriendsHandler(w http.ResponseWriter, r *http.Request, tc TwitterClient) error {
	log.Println("Getting all users")
	users, err := tc.GetAllFriends()
	if err != nil {
		return err
	}
	log.Println("Got all users")
	var allUsers []TwitterUser
	for _, u := range users {
		allUsers = append(allUsers, TwitterUser{ID: u.Id, Name: u.Name, Description: u.Description})
	}
	render := TwitterFriends{Friends: allUsers}
	log.Println("ready to render")
	SetHeader(w, "GET")
	return json.NewEncoder(w).Encode(render)
}
<commit_msg>Removed unused logs<commit_after>package twitlistserver

import (
	"encoding/json"
	"net/http"
)

// TwitterUser holds limited details about a Twitter list member.
// Only essential details are used, since the UI does not need to have
// everything to maintain the lists.
type TwitterUser struct {
	ID          int64  `json:"id"`
	Name        string `json:"name"`
	Description string `json:"description"`
}

// TwitterFriends is
type TwitterFriends struct {
	Friends []TwitterUser `json:"friends"`
}

// FriendsHandler handles GET requests on /users.
// It returns all contacts of the current user on Twitter.
// This allows the UI to offer a list of users to add to a list.
func FriendsHandler(w http.ResponseWriter, r *http.Request, tc TwitterClient) error {
	users, err := tc.GetAllFriends()
	if err != nil {
		return err
	}
	allUsers := make([]TwitterUser, 0)
	for _, u := range users {
		allUsers = append(allUsers, TwitterUser{ID: u.Id, Name: u.Name, Description: u.Description})
	}
	render := TwitterFriends{Friends: allUsers}
	SetHeader(w, "GET")
	return json.NewEncoder(w).Encode(render)
}
<|endoftext|>


<commit_before>package build

import (
	"fmt"
	"github.com/mattn/anko/core"
	"github.com/mattn/anko/packages"
	"github.com/mattn/anko/parser"
	"github.com/mattn/anko/vm"
	"io/ioutil"
	"os"
	"reflect"
	"regexp"
	"runtime"
	"sort"
	"strings"
)

const (
	propertyOs     = "_OS"
	propertyArch   = "_ARCH"
	propertyNcpu   = "_NCPU"
	propertyBase   = "_BASE"
	propertyHere   = "_HERE"
	propertyThread = "_thread"
	propertyInput  = "_input"
	environmentSep = "="
	environmentVar = "$"
)

var (
	regexpExp   = regexp.MustCompile(`\\*[#=]{.*?([^\\])}`)
	regexpEnv   = regexp.MustCompile(`\\*[#=$]{.*?}`)
	regexpParts = regexp.MustCompile(`(\\*)([#=$]){(.*)}`)
	regexpClose = regexp.MustCompile(`\\*}`)
)

// Context is the context of the build
// - VM: Anko VM that holds build properties
// - Build: the current build
// - Index: tracks steps index while running build
// - Stack: tracks targets calls
type Context struct {
	VM    *vm.Env
	Build *Build
	Stack *Stack
}

// NewContext make a new build context
// Return: a pointer to the context
func NewContext(build *Build) *Context {
	v := vm.NewEnv()
	core.Import(v)
	packages.DefineImport(v)
	LoadBuiltins(v)
	context := &Context{
		VM:    v,
		Build: build,
		Stack: NewStack(),
	}
	return context
}

// NewThreadContext builds a context for a thread by copying the build context
// - thread: the number of the thread, starting with 0
// - input: the thread input
// - output: the thread output
// Return: a pointer to the context
func (context *Context) NewThreadContext(thread int, input interface{}, output interface{}) *Context {
	another := &Context{
		VM:    context.VM.Copy(),
		Build: context.Build,
		Stack: context.Stack.Copy(),
	}
	another.SetProperty(propertyThread, thread)
	another.SetProperty(propertyInput, input)
	return another
}

// Init initializes context with build
// Return: an error if something went wrong
func (context *Context) Init() error {
	err := context.InitScripts()
	if err != nil {
		return fmt.Errorf("loading scripts: %v", err)
	}
	err = context.InitProperties()
	if err != nil {
		return fmt.Errorf("evaluating properties: %v", err)
	}
	return nil
}

// InitScripts loads build scripts in context
// Return: an error if something went wrong
func (context *Context) InitScripts() error {
	for _, script := range context.Build.Scripts {
		source, err := ioutil.ReadFile(script)
		if err != nil {
			return fmt.Errorf("reading script '%s': %v", script, err)
		}
		_, err = context.VM.Execute(string(source))
		if err != nil {
			return fmt.Errorf("evaluating script '%s': %v", script, FormatScriptError(err))
		}
	}
	return nil
}

// InitProperties sets build properties
// Return: an error if something went wrong
func (context *Context) InitProperties() error {
	context.SetProperty(propertyOs, runtime.GOOS)
	context.SetProperty(propertyArch, runtime.GOARCH)
	context.SetProperty(propertyNcpu, runtime.NumCPU())
	context.SetProperty(propertyBase, context.Build.Dir)
	context.SetProperty(propertyHere, context.Build.Here)
	todo := context.Build.Properties.Fields()
	var crash error
	for len(todo) > 0 {
		var done []string
		for _, name := range todo {
			value := context.Build.Properties[name]
			eval, err := context.EvaluateObject(value)
			if err == nil {
				context.SetProperty(name, eval)
				done = append(done, name)
			} else {
				crash = err
			}
		}
		if len(done) == 0 {
			return crash
		}
		var next []string
		for _, name := range todo {
			found := false
			for _, n := range done {
				if name == n {
					found = true
				}
			}
			if !found {
				next = append(next, name)
			}
		}
		todo = next
	}
	return nil
}

// SetProperty sets given property in context
// - name: the name of the property
// - value: the value of the property
func (context *Context) SetProperty(name string, value interface{}) {
	context.VM.Define(name, value)
}

// GetProperty returns value of given property
// - name: the name of the property
// Return:
// - the value of the property
// - an error if something went wrong
func (context *Context) GetProperty(name string) (interface{}, error) {
	value, err := context.VM.Get(name)
	if err != nil {
		return nil, err
	}
	return value, nil
}

// EvaluateExpression evaluate given expression in the context
// - expression: the expression to evaluate
// Return:
// - the return value of the expression
// - an error if something went wrong
func (context *Context) EvaluateExpression(expression string) (interface{}, error) {
	value, err := context.VM.Execute(expression)
	if err != nil {
		return nil, FormatScriptError(err)
	}
	// TODO: check that this is not necessary anymore
	// if !value.IsValid() {
	// 	return nil, nil
	// }
	return value, nil
}

// EvaluateString replaces '#{expression}' with the value of the expression
// - text: the string to evaluate
// Return:
// - evaluated string
// - an error if something went wrong
func (context *Context) EvaluateString(text string) (string, error) {
	var errors []error
	replaced := regexpExp.ReplaceAllStringFunc(text, func(expression string) string {
		parts := regexpParts.FindStringSubmatch(expression)
		prefix := parts[1]
		char := parts[2]
		source := parts[3]
		// expression was escaped
		if len(prefix)%2 == 1 {
			return strings.Repeat(`\`, len(prefix)/2) + char + `{` + source + `}`
		}
		// expression not escaped
		if len(prefix)%2 == 0 {
			prefix = strings.Repeat(`\`, len(prefix)/2)
		}
		// replace escaped closing curly braces "\}"" in expression
		source = regexpClose.ReplaceAllStringFunc(source, func(text string) string {
			text = text[:len(text)-1]
			slash := strings.Repeat(`\`, len(text)/2)
			return slash + `}`
		})
		value, err := context.EvaluateExpression(source)
		if err != nil {
			errors = append(errors, err)
			return ""
		}
		var str string
		str, err = PropertyToString(value, false)
		if err != nil {
			errors = append(errors, err)
			return ""
		}
		return prefix + str
	})
	if len(errors) > 0 {
		return replaced, errors[0]
	}
	return replaced, nil
}

// EvaluateObject recursively evaluates strings in a structure
// - object: the object to evaluate
// Return:
// - evaluated copy of object
// - an error if something went wrong
func (context *Context) EvaluateObject(object interface{}) (interface{}, error) {
	// if nil, return nil
	if object == nil {
		return nil, nil
	} else
	// we replace expressions in strings
	if reflect.TypeOf(object).Kind() == reflect.String {
		str := object.(string)
		if IsExpression(str) {
			value, err := context.EvaluateExpression(strings.TrimSpace(str[1:]))
			if err != nil {
				return nil, err
			}
			return value, nil
		}
		evaluated, err := context.EvaluateString(object.(string))
		if err != nil {
			return nil, err
		}
		return evaluated, nil
	}
	// we copy slices in a new slice with evaluated values
	if reflect.TypeOf(object).Kind() == reflect.Slice {
		source := reflect.ValueOf(object)
		dest := reflect.MakeSlice(reflect.SliceOf(reflect.TypeOf(object).Elem()), source.Len(), source.Len())
		for i := 0; i < source.Len(); i++ {
			index := source.Index(i)
			evaluated, err := context.EvaluateObject(index.Interface())
			if err != nil {
				return nil, err
			}
			dest.Index(i).Set(reflect.ValueOf(evaluated))
		}
		return dest.Interface(), nil
	}
	// we copy maps in a new map with evaluated keys and values
	if reflect.TypeOf(object).Kind() == reflect.Map {
		source := reflect.ValueOf(object)
		dest := reflect.MakeMap(reflect.MapOf(reflect.TypeOf(object).Key(), reflect.TypeOf(object).Elem()))
		keys := source.MapKeys()
		for i := 0; i < len(keys); i++ {
			key := keys[i]
			keyEval, err := context.EvaluateObject(key.Interface())
			if err != nil {
				return nil, err
			}
			val := source.MapIndex(key)
			valEval, err := context.EvaluateObject(val.Interface())
			if err != nil {
				return nil, err
			}
			dest.SetMapIndex(reflect.ValueOf(keyEval), reflect.ValueOf(valEval))
		}
		return dest.Interface(), nil
	}
	// else we do nothing
	return object, nil
}

// EvaluateEnvironment evaluates environment variables in the context
// Return:
// - evaluated environment as a slice of strings
// - an error if something went wrong
func (context *Context) EvaluateEnvironment() ([]string, error) {
	environment := make(map[string]string)
	for _, line := range os.Environ() {
		index := strings.Index(line, environmentSep)
		name := line[:index]
		value := line[index+1:]
		environment[name] = value
	}
	environment[propertyBase] = context.Build.Dir
	environment[propertyHere] = context.Build.Here
	var variables []string
	for name := range context.Build.Environment {
		variables = append(variables, name)
	}
	sort.Strings(variables)
	for _, name := range variables {
		value := context.Build.Environment[name]
		var replaced string
		if IsExpression(value) {
			val, err := context.EvaluateExpression(value[1:])
			if err != nil {
				return nil, err
			}
			if val == nil || reflect.TypeOf(val).Kind() != reflect.String {
				return nil, fmt.Errorf("expression in environment must return a string")
			}
			replaced = val.(string)
		} else {
			replaced = regexpEnv.ReplaceAllStringFunc(value, func(expression string) string {
				parts := regexpParts.FindStringSubmatch(expression)
				prefix := parts[1]
				char := parts[2]
				source := parts[3]
				// expression was escaped
				if prefix == `\` {
					return char + `{` + source + `}`
				}
				// expression not escaped
				if prefix == `\\` {
					prefix = `\`
				}
				if char == environmentVar {
					val, ok := environment[source]
					if !ok {
						return prefix + `{` + source + `}`
					}
					return prefix + val
				}
				val, err := context.EvaluateExpression(source)
				if err != nil {
					return prefix + `{` + source + `}`
				}
				str, _ := PropertyToString(val, false)
				return prefix + str
			})
		}
		environment[name] = replaced
	}
	var lines []string
	for name, value := range environment {
		// unset variables with empty string value
		if value != "" {
			line := name + environmentSep + value
			lines = append(lines, line)
		}
	}
	return lines, nil
}

// Message print a message on the console
// - text: the text to print on console
// - args: a slice of string arguments (as for fmt.Printf())
func (context *Context) Message(text string, args ...interface{}) {
	Message(text, args...)
}

// FormatScriptError adds line and column numbers on parser or vm errors.
// - err: the error to process
// Return: the processed error
func FormatScriptError(err error) error {
	if e, ok := err.(*parser.Error); ok {
		return fmt.Errorf("%s (at line %d, column %d)", err, e.Pos.Line, e.Pos.Column)
	} else if e, ok := err.(*vm.Error); ok {
		return fmt.Errorf("%s (at line %d, column %d)", err, e.Pos.Line, e.Pos.Column)
	} else {
		return err
	}
}
<commit_msg>Fixed Anko VM copy<commit_after>package build

import (
	"fmt"
	"github.com/mattn/anko/core"
	"github.com/mattn/anko/packages"
	"github.com/mattn/anko/parser"
	"github.com/mattn/anko/vm"
	"io/ioutil"
	"os"
	"reflect"
	"regexp"
	"runtime"
	"sort"
	"strings"
)

const (
	propertyOs     = "_OS"
	propertyArch   = "_ARCH"
	propertyNcpu   = "_NCPU"
	propertyBase   = "_BASE"
	propertyHere   = "_HERE"
	propertyThread = "_thread"
	propertyInput  = "_input"
	environmentSep = "="
	environmentVar = "$"
)

var (
	regexpExp   = regexp.MustCompile(`\\*[#=]{.*?([^\\])}`)
	regexpEnv   = regexp.MustCompile(`\\*[#=$]{.*?}`)
	regexpParts = regexp.MustCompile(`(\\*)([#=$]){(.*)}`)
	regexpClose = regexp.MustCompile(`\\*}`)
)

// Context is the context of the build
// - VM: Anko VM that holds build properties
// - Build: the current build
// - Index: tracks steps index while running build
// - Stack: tracks targets calls
type Context struct {
	VM    *vm.Env
	Build *Build
	Stack *Stack
}

// NewContext make a new build context
// Return: a pointer to the context
func NewContext(build *Build) *Context {
	v := vm.NewEnv()
	core.Import(v)
	packages.DefineImport(v)
	LoadBuiltins(v)
	context := &Context{
		VM:    v,
		Build: build,
		Stack: NewStack(),
	}
	return context
}

// NewThreadContext builds a context for a thread by copying the build context
// - thread: the number of the thread, starting with 0
// - input: the thread input
// - output: the thread output
// Return: a pointer to the context
func (context *Context) NewThreadContext(thread int, input interface{}, output interface{}) *Context {
	another := &Context{
		VM:    context.VM.DeepCopy(),
		Build: context.Build,
		Stack: context.Stack.Copy(),
	}
	another.SetProperty(propertyThread, thread)
	another.SetProperty(propertyInput, input)
	return another
}

// Init initializes context with build
// Return: an error if something went wrong
func (context *Context) Init() error {
	err := context.InitScripts()
	if err != nil {
		return fmt.Errorf("loading scripts: %v", err)
	}
	err = context.InitProperties()
	if err != nil {
		return fmt.Errorf("evaluating properties: %v", err)
	}
	return nil
}

// InitScripts loads build scripts in context
// Return: an error if something went wrong
func (context *Context) InitScripts() error {
	for _, script := range context.Build.Scripts {
		source, err := ioutil.ReadFile(script)
		if err != nil {
			return fmt.Errorf("reading script '%s': %v", script, err)
		}
		_, err = context.VM.Execute(string(source))
		if err != nil {
			return fmt.Errorf("evaluating script '%s': %v", script, FormatScriptError(err))
		}
	}
	return nil
}

// InitProperties sets build properties
// Return: an error if something went wrong
func (context *Context) InitProperties() error {
	context.SetProperty(propertyOs, runtime.GOOS)
	context.SetProperty(propertyArch, runtime.GOARCH)
	context.SetProperty(propertyNcpu, runtime.NumCPU())
	context.SetProperty(propertyBase, context.Build.Dir)
	context.SetProperty(propertyHere, context.Build.Here)
	todo := context.Build.Properties.Fields()
	var crash error
	for len(todo) > 0 {
		var done []string
		for _, name := range todo {
			value := context.Build.Properties[name]
			eval, err := context.EvaluateObject(value)
			if err == nil {
				context.SetProperty(name, eval)
				done = append(done, name)
			} else {
				crash = err
			}
		}
		if len(done) == 0 {
			return crash
		}
		var next []string
		for _, name := range todo {
			found := false
			for _, n := range done {
				if name == n {
					found = true
				}
			}
			if !found {
				next = append(next, name)
			}
		}
		todo = next
	}
	return nil
}

// SetProperty sets given property in context
// - name: the name of the property
// - value: the value of the property
func (context *Context) SetProperty(name string, value interface{}) {
	context.VM.Define(name, value)
}

// GetProperty returns value of given property
// - name: the name of the property
// Return:
// - the value of the property
// - an error if something went wrong
func (context *Context) GetProperty(name string) (interface{}, error) {
	value, err := context.VM.Get(name)
	if err != nil {
		return nil, err
	}
	return value, nil
}

// EvaluateExpression evaluate given expression in the context
// - expression: the expression to evaluate
// Return:
// - the return value of the expression
// - an error if something went wrong
func (context *Context) EvaluateExpression(expression string) (interface{}, error) {
	value, err := context.VM.Execute(expression)
	if err != nil {
		return nil, FormatScriptError(err)
	}
	// TODO: check that this is not necessary anymore
	// if !value.IsValid() {
	// 	return nil, nil
	// }
	return value, nil
}

// EvaluateString replaces '#{expression}' with the value of the expression
// - text: the string to evaluate
// Return:
// - evaluated string
// - an error if something went wrong
func (context *Context) EvaluateString(text string) (string, error) {
	var errors []error
	replaced := regexpExp.ReplaceAllStringFunc(text, func(expression string) string {
		parts := regexpParts.FindStringSubmatch(expression)
		prefix := parts[1]
		char := parts[2]
		source := parts[3]
		// expression was escaped
		if len(prefix)%2 == 1 {
			return strings.Repeat(`\`, len(prefix)/2) + char + `{` + source + `}`
		}
		// expression not escaped
		if len(prefix)%2 == 0 {
			prefix = strings.Repeat(`\`, len(prefix)/2)
		}
		// replace escaped closing curly braces "\}"" in expression
		source = regexpClose.ReplaceAllStringFunc(source, func(text string) string {
			text = text[:len(text)-1]
			slash := strings.Repeat(`\`, len(text)/2)
			return slash + `}`
		})
		value, err := context.EvaluateExpression(source)
		if err != nil {
			errors = append(errors, err)
			return ""
		}
		var str string
		str, err = PropertyToString(value, false)
		if err != nil {
			errors = append(errors, err)
			return ""
		}
		return prefix + str
	})
	if len(errors) > 0 {
		return replaced, errors[0]
	}
	return replaced, nil
}

// EvaluateObject recursively evaluates strings in a structure
// - object: the object to evaluate
// Return:
// - evaluated copy of object
// - an error if something went wrong
func (context *Context) EvaluateObject(object interface{}) (interface{}, error) {
	// if nil, return nil
	if object == nil {
		return nil, nil
	} else
	// we replace expressions in strings
	if reflect.TypeOf(object).Kind() == reflect.String {
		str := object.(string)
		if IsExpression(str) {
			value, err := context.EvaluateExpression(strings.TrimSpace(str[1:]))
			if err != nil {
				return nil, err
			}
			return value, nil
		}
		evaluated, err := context.EvaluateString(object.(string))
		if err != nil {
			return nil, err
		}
		return evaluated, nil
	}
	// we copy slices in a new slice with evaluated values
	if reflect.TypeOf(object).Kind() == reflect.Slice {
		source := reflect.ValueOf(object)
		dest := reflect.MakeSlice(reflect.SliceOf(reflect.TypeOf(object).Elem()), source.Len(), source.Len())
		for i := 0; i < source.Len(); i++ {
			index := source.Index(i)
			evaluated, err := context.EvaluateObject(index.Interface())
			if err != nil {
				return nil, err
			}
			dest.Index(i).Set(reflect.ValueOf(evaluated))
		}
		return dest.Interface(), nil
	}
	// we copy maps in a new map with evaluated keys and values
	if reflect.TypeOf(object).Kind() == reflect.Map {
		source := reflect.ValueOf(object)
		dest := reflect.MakeMap(reflect.MapOf(reflect.TypeOf(object).Key(), reflect.TypeOf(object).Elem()))
		keys := source.MapKeys()
		for i := 0; i < len(keys); i++ {
			key := keys[i]
			keyEval, err := context.EvaluateObject(key.Interface())
			if err != nil {
				return nil, err
			}
			val := source.MapIndex(key)
			valEval, err := context.EvaluateObject(val.Interface())
			if err != nil {
				return nil, err
			}
			dest.SetMapIndex(reflect.ValueOf(keyEval), reflect.ValueOf(valEval))
		}
		return dest.Interface(), nil
	}
	// else we do nothing
	return object, nil
}

// EvaluateEnvironment evaluates environment variables in the context
// Return:
// - evaluated environment as a slice of strings
// - an error if something went wrong
func (context *Context) EvaluateEnvironment() ([]string, error) {
	environment := make(map[string]string)
	for _, line := range os.Environ() {
		index := strings.Index(line, environmentSep)
		name := line[:index]
		value := line[index+1:]
		environment[name] = value
	}
	environment[propertyBase] = context.Build.Dir
	environment[propertyHere] = context.Build.Here
	var variables []string
	for name := range context.Build.Environment {
		variables = append(variables, name)
	}
	sort.Strings(variables)
	for _, name := range variables {
		value := context.Build.Environment[name]
		var replaced string
		if IsExpression(value) {
			val, err := context.EvaluateExpression(value[1:])
			if err != nil {
				return nil, err
			}
			if val == nil || reflect.TypeOf(val).Kind() != reflect.String {
				return nil, fmt.Errorf("expression in environment must return a string")
			}
			replaced = val.(string)
		} else {
			replaced = regexpEnv.ReplaceAllStringFunc(value, func(expression string) string {
				parts := regexpParts.FindStringSubmatch(expression)
				prefix := parts[1]
				char := parts[2]
				source := parts[3]
				// expression was escaped
				if prefix == `\` {
					return char + `{` + source + `}`
				}
				// expression not escaped
				if prefix == `\\` {
					prefix = `\`
				}
				if char == environmentVar {
					val, ok := environment[source]
					if !ok {
						return prefix + `{` + source + `}`
					}
					return prefix + val
				}
				val, err := context.EvaluateExpression(source)
				if err != nil {
					return prefix + `{` + source + `}`
				}
				str, _ := PropertyToString(val, false)
				return prefix + str
			})
		}
		environment[name] = replaced
	}
	var lines []string
	for name, value := range environment {
		// unset variables with empty string value
		if value != "" {
			line := name + environmentSep + value
			lines = append(lines, line)
		}
	}
	return lines, nil
}

// Message print a message on the console
// - text: the text to print on console
// - args: a slice of string arguments (as for fmt.Printf())
func (context *Context) Message(text string, args ...interface{}) {
	Message(text, args...)
}

// FormatScriptError adds line and column numbers on parser or vm errors.
// - err: the error to process
// Return: the processed error
func FormatScriptError(err error) error {
	if e, ok := err.(*parser.Error); ok {
		return fmt.Errorf("%s (at line %d, column %d)", err, e.Pos.Line, e.Pos.Column)
	} else if e, ok := err.(*vm.Error); ok {
		return fmt.Errorf("%s (at line %d, column %d)", err, e.Pos.Line, e.Pos.Column)
	} else {
		return err
	}
}
<|endoftext|>


<commit_before>package rkecluster

import (
	"context"

	v1 "github.com/rancher/rancher/pkg/apis/rke.cattle.io/v1"
	rkecontroller "github.com/rancher/rancher/pkg/generated/controllers/rke.cattle.io/v1"
	"github.com/rancher/rancher/pkg/wrangler"
	"github.com/rancher/wrangler/pkg/condition"
	"github.com/rancher/wrangler/pkg/relatedresource"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/runtime"
)

var (
	Provisioned condition.Cond = "Provisioned"
)

type handler struct {
	clusterClient    rkecontroller.RKEClusterClient
	rkeControlPlanes rkecontroller.RKEControlPlaneCache
}

func Register(ctx context.Context, clients *wrangler.Context) {
	h := handler{
		clusterClient:    clients.RKE.RKECluster(),
		rkeControlPlanes: clients.RKE.RKEControlPlane().Cache(),
	}

	clients.RKE.RKECluster().OnChange(ctx, "rke", h.UpdateSpec)
	rkecontroller.RegisterRKEClusterStatusHandler(ctx,
		clients.RKE.RKECluster(),
		"Defined",
		"rke-cluster-status",
		h.OnChange)
	relatedresource.Watch(ctx, "rke-cluster-trigger", func(namespace, name string, obj runtime.Object) ([]relatedresource.Key, error) {
		return []relatedresource.Key{{
			Namespace: namespace,
			Name:      name,
		}}, nil
	}, clients.RKE.RKECluster(), clients.RKE.RKEControlPlane())
}

func (h *handler) UpdateSpec(key string, cluster *v1.RKECluster) (*v1.RKECluster, error) {
	if cluster == nil {
		return nil, nil
	}

	if cluster.Spec.ControlPlaneEndpoint == nil {
		cluster := cluster.DeepCopy()
		cluster.Spec.ControlPlaneEndpoint = &v1.Endpoint{
			Host: "localhost",
			Port: 6443,
		}
		return h.clusterClient.Update(cluster)
	}

	return cluster, nil
}

func (h *handler) OnChange(obj *v1.RKECluster, status v1.RKEClusterStatus) (v1.RKEClusterStatus, error) {
	cp, err := h.rkeControlPlanes.Get(obj.Namespace, obj.Name)
	if err == nil {
		Provisioned.SetStatus(&status, Provisioned.GetStatus(cp))
		Provisioned.Reason(&status, Provisioned.GetReason(cp))
		Provisioned.Message(&status, Provisioned.GetMessage(cp))
	} else if !apierrors.IsNotFound(err) {
		return status, err
	}

	status.Ready = condition.Cond("Provisioned").IsTrue(&status)
	return status, nil
}
<commit_msg>Update observedGeneration<commit_after>package rkecluster

import (
	"context"

	v1 "github.com/rancher/rancher/pkg/apis/rke.cattle.io/v1"
	rkecontroller "github.com/rancher/rancher/pkg/generated/controllers/rke.cattle.io/v1"
	"github.com/rancher/rancher/pkg/wrangler"
	"github.com/rancher/wrangler/pkg/condition"
	"github.com/rancher/wrangler/pkg/relatedresource"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/runtime"
)

var (
	Provisioned condition.Cond = "Provisioned"
)

type handler struct {
	clusterClient    rkecontroller.RKEClusterClient
	rkeControlPlanes rkecontroller.RKEControlPlaneCache
}

func Register(ctx context.Context, clients *wrangler.Context) {
	h := handler{
		clusterClient:    clients.RKE.RKECluster(),
		rkeControlPlanes: clients.RKE.RKEControlPlane().Cache(),
	}

	clients.RKE.RKECluster().OnChange(ctx, "rke", h.UpdateSpec)
	rkecontroller.RegisterRKEClusterStatusHandler(ctx,
		clients.RKE.RKECluster(),
		"Defined",
		"rke-cluster-status",
		h.OnChange)
	relatedresource.Watch(ctx, "rke-cluster-trigger", func(namespace, name string, obj runtime.Object) ([]relatedresource.Key, error) {
		return []relatedresource.Key{{
			Namespace: namespace,
			Name:      name,
		}}, nil
	}, clients.RKE.RKECluster(), clients.RKE.RKEControlPlane())
}

func (h *handler) UpdateSpec(key string, cluster *v1.RKECluster) (*v1.RKECluster, error) {
	if cluster == nil {
		return nil, nil
	}

	if cluster.Spec.ControlPlaneEndpoint == nil {
		cluster := cluster.DeepCopy()
		cluster.Spec.ControlPlaneEndpoint = &v1.Endpoint{
			Host: "localhost",
			Port: 6443,
		}
		return h.clusterClient.Update(cluster)
	}

	return cluster, nil
}

func (h *handler) OnChange(obj *v1.RKECluster, status v1.RKEClusterStatus) (v1.RKEClusterStatus, error) {
	cp, err := h.rkeControlPlanes.Get(obj.Namespace, obj.Name)
	if err == nil {
		Provisioned.SetStatus(&status, Provisioned.GetStatus(cp))
		Provisioned.Reason(&status, Provisioned.GetReason(cp))
		Provisioned.Message(&status, Provisioned.GetMessage(cp))
	} else if !apierrors.IsNotFound(err) {
		return status, err
	}

	status.Ready = condition.Cond("Provisioned").IsTrue(&status)
	status.ObservedGeneration = obj.Generation
	return status, nil
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/djthorpe/gopi/rpi/egl"
	"log"
	"os"
)

func main() {
	egl.BCMHostInit()

	// Initalize display
	display := egl.GetDisplay(egl.DEFAULT_DISPLAY)
	if ok := egl.Initialize(display,nil,nil); ok != true {
		log.Errorf("Unable to initalize display")
		return -1
	}

	// Terminate display
	if ok := egl.Terminate(display); ok != true {
		log.Errorf("Unable to terminate display")
		return -1
	}

	return 0
}

<commit_msg>Updated<commit_after>package main

import (
	"github.com/djthorpe/gopi/rpi/egl"
	"log"
)

func main() {
	egl.BCMHostInit()

	// Initalize display
	display := egl.GetDisplay()
	if ok := egl.Initialize(display,nil,nil); ok != true {
		log.Printf("Unable to initalize display")
		return -1
	}

	// Terminate display
	if ok := egl.Terminate(display); ok != true {
		log.Printf("Unable to terminate display")
		return -1
	}

	return 0
}

<|endoftext|>


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

// Package unicode provides data and functions to test some properties of
// Unicode code points.
package unicode

const (
	MaxRune         = 0x10FFFF // Maximum valid Unicode code point.
	ReplacementChar = 0xFFFD   // Represents invalid code points.
	MaxASCII        = 0x7F     // maximum ASCII value.
	MaxLatin1       = 0xFF     // maximum Latin-1 value.
)

// RangeTable defines a set of Unicode code points by listing the ranges of
// code points within the set. The ranges are listed in two slices
// to save space: a slice of 16-bit ranges and a slice of 32-bit ranges.
// The two slices must be in sorted order and non-overlapping.
// Also, R32 should contain only values >= 0x10000 (1<<16).
type RangeTable struct {
	R16 []Range16
	R32 []Range32
}

// Range16 represents of a range of 16-bit Unicode code points.  The range runs from Lo to Hi
// inclusive and has the specified stride.
type Range16 struct {
	Lo     uint16
	Hi     uint16
	Stride uint16
}

// Range32 represents of a range of Unicode code points and is used when one or
//  more of the values will not fit in 16 bits.  The range runs from Lo to Hi
// inclusive and has the specified stride. Lo and Hi must always be >= 1<<16.
type Range32 struct {
	Lo     uint32
	Hi     uint32
	Stride uint32
}

// CaseRange represents a range of Unicode code points for simple (one
// code point to one code point) case conversion.
// The range runs from Lo to Hi inclusive, with a fixed stride of 1.  Deltas
// are the number to add to the code point to reach the code point for a
// different case for that character.  They may be negative.  If zero, it
// means the character is in the corresponding case. There is a special
// case representing sequences of alternating corresponding Upper and Lower
// pairs.  It appears with a fixed Delta of
//	{UpperLower, UpperLower, UpperLower}
// The constant UpperLower has an otherwise impossible delta value.
type CaseRange struct {
	Lo    uint32
	Hi    uint32
	Delta d
}

// SpecialCase represents language-specific case mappings such as Turkish.
// Methods of SpecialCase customize (by overriding) the standard mappings.
type SpecialCase []CaseRange

//BUG(r): Provide a mechanism for full case folding (those that involve
// multiple runes in the input or output).

// Indices into the Delta arrays inside CaseRanges for case mapping.
const (
	UpperCase = iota
	LowerCase
	TitleCase
	MaxCase
)

type d [MaxCase]int32 // to make the CaseRanges text shorter

// If the Delta field of a CaseRange is UpperLower or LowerUpper, it means
// this CaseRange represents a sequence of the form (say)
// Upper Lower Upper Lower.
const (
	UpperLower = MaxRune + 1 // (Cannot be a valid delta.)
)

// is16 uses binary search to test whether rune is in the specified slice of 16-bit ranges.
func is16(ranges []Range16, rune uint16) bool {
	// binary search over ranges
	lo := 0
	hi := len(ranges)
	for lo < hi {
		m := lo + (hi-lo)/2
		r := ranges[m]
		if r.Lo <= rune && rune <= r.Hi {
			return (rune-r.Lo)%r.Stride == 0
		}
		if rune < r.Lo {
			hi = m
		} else {
			lo = m + 1
		}
	}
	return false
}

// is32 uses binary search to test whether rune is in the specified slice of 32-bit ranges.
func is32(ranges []Range32, rune uint32) bool {
	// binary search over ranges
	lo := 0
	hi := len(ranges)
	for lo < hi {
		m := lo + (hi-lo)/2
		r := ranges[m]
		if r.Lo <= rune && rune <= r.Hi {
			return (rune-r.Lo)%r.Stride == 0
		}
		if rune < r.Lo {
			hi = m
		} else {
			lo = m + 1
		}
	}
	return false
}

// Is tests whether rune is in the specified table of ranges.
func Is(rangeTab *RangeTable, rune int) bool {
	// common case: rune is ASCII or Latin-1.
	if uint32(rune) <= MaxLatin1 {
		// Only need to check R16, since R32 is always >= 1<<16.
		r16 := uint16(rune)
		for _, r := range rangeTab.R16 {
			if r16 > r.Hi {
				continue
			}
			if r16 < r.Lo {
				return false
			}
			return (r16-r.Lo)%r.Stride == 0
		}
		return false
	}
	r16 := rangeTab.R16
	if len(r16) > 0 && rune <= int(r16[len(r16)-1].Hi) {
		return is16(r16, uint16(rune))
	}
	r32 := rangeTab.R32
	if len(r32) > 0 && rune >= int(r32[0].Lo) {
		return is32(r32, uint32(rune))
	}
	return false
}

// IsUpper reports whether the rune is an upper case letter.
func IsUpper(rune int) bool {
	// See comment in IsGraphic.
	if uint32(rune) <= MaxLatin1 {
		return properties[uint8(rune)]&pLu != 0
	}
	return Is(Upper, rune)
}

// IsLower reports whether the rune is a lower case letter.
func IsLower(rune int) bool {
	// See comment in IsGraphic.
	if uint32(rune) <= MaxLatin1 {
		return properties[uint8(rune)]&pLl != 0
	}
	return Is(Lower, rune)
}

// IsTitle reports whether the rune is a title case letter.
func IsTitle(rune int) bool {
	if rune <= MaxLatin1 {
		return false
	}
	return Is(Title, rune)
}

// to maps the rune using the specified case mapping.
func to(_case int, rune int, caseRange []CaseRange) int {
	if _case < 0 || MaxCase <= _case {
		return ReplacementChar // as reasonable an error as any
	}
	// binary search over ranges
	lo := 0
	hi := len(caseRange)
	for lo < hi {
		m := lo + (hi-lo)/2
		r := caseRange[m]
		if int(r.Lo) <= rune && rune <= int(r.Hi) {
			delta := int(r.Delta[_case])
			if delta > MaxRune {
				// In an Upper-Lower sequence, which always starts with
				// an UpperCase letter, the real deltas always look like:
				//	{0, 1, 0}    UpperCase (Lower is next)
				//	{-1, 0, -1}  LowerCase (Upper, Title are previous)
				// The characters at even offsets from the beginning of the
				// sequence are upper case; the ones at odd offsets are lower.
				// The correct mapping can be done by clearing or setting the low
				// bit in the sequence offset.
				// The constants UpperCase and TitleCase are even while LowerCase
				// is odd so we take the low bit from _case.
				return int(r.Lo) + ((rune-int(r.Lo))&^1 | _case&1)
			}
			return rune + delta
		}
		if rune < int(r.Lo) {
			hi = m
		} else {
			lo = m + 1
		}
	}
	return rune
}

// To maps the rune to the specified case: UpperCase, LowerCase, or TitleCase.
func To(_case int, rune int) int {
	return to(_case, rune, CaseRanges)
}

// ToUpper maps the rune to upper case.
func ToUpper(rune int) int {
	if rune <= MaxASCII {
		if 'a' <= rune && rune <= 'z' {
			rune -= 'a' - 'A'
		}
		return rune
	}
	return To(UpperCase, rune)
}

// ToLower maps the rune to lower case.
func ToLower(rune int) int {
	if rune <= MaxASCII {
		if 'A' <= rune && rune <= 'Z' {
			rune += 'a' - 'A'
		}
		return rune
	}
	return To(LowerCase, rune)
}

// ToTitle maps the rune to title case.
func ToTitle(rune int) int {
	if rune <= MaxASCII {
		if 'a' <= rune && rune <= 'z' { // title case is upper case for ASCII
			rune -= 'a' - 'A'
		}
		return rune
	}
	return To(TitleCase, rune)
}

// ToUpper maps the rune to upper case giving priority to the special mapping.
func (special SpecialCase) ToUpper(rune int) int {
	r := to(UpperCase, rune, []CaseRange(special))
	if r == rune {
		r = ToUpper(rune)
	}
	return r
}

// ToTitle maps the rune to title case giving priority to the special mapping.
func (special SpecialCase) ToTitle(rune int) int {
	r := to(TitleCase, rune, []CaseRange(special))
	if r == rune {
		r = ToTitle(rune)
	}
	return r
}

// ToLower maps the rune to lower case giving priority to the special mapping.
func (special SpecialCase) ToLower(rune int) int {
	r := to(LowerCase, rune, []CaseRange(special))
	if r == rune {
		r = ToLower(rune)
	}
	return r
}

// caseOrbit is defined in tables.go as []foldPair.  Right now all the
// entries fit in uint16, so use uint16.  If that changes, compilation
// will fail (the constants in the composite literal will not fit in uint16)
// and the types here can change to uint32.
type foldPair struct {
	From uint16
	To   uint16
}

// SimpleFold iterates over Unicode code points equivalent under
// the Unicode-defined simple case folding.  Among the code points
// equivalent to rune (including rune itself), SimpleFold returns the
// smallest r >= rune if one exists, or else the smallest r >= 0.
//
// For example:
//	SimpleFold('A') = 'a'
//	SimpleFold('a') = 'A'
//
//	SimpleFold('K') = 'k'
//	SimpleFold('k') = '\u212A' (Kelvin symbol, K)
//	SimpleFold('\u212A') = 'K'
//
//	SimpleFold('1') = '1'
//
func SimpleFold(rune int) int {
	// Consult caseOrbit table for special cases.
	lo := 0
	hi := len(caseOrbit)
	for lo < hi {
		m := lo + (hi-lo)/2
		if int(caseOrbit[m].From) < rune {
			lo = m + 1
		} else {
			hi = m
		}
	}
	if lo < len(caseOrbit) && int(caseOrbit[lo].From) == rune {
		return int(caseOrbit[lo].To)
	}

	// No folding specified.  This is a one- or two-element
	// equivalence class containing rune and ToLower(rune)
	// and ToUpper(rune) if they are different from rune.
	if l := ToLower(rune); l != rune {
		return l
	}
	return ToUpper(rune)
}
<commit_msg>unicode: fix doc comment for Range32<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package unicode provides data and functions to test some properties of
// Unicode code points.
package unicode

const (
	MaxRune         = 0x10FFFF // Maximum valid Unicode code point.
	ReplacementChar = 0xFFFD   // Represents invalid code points.
	MaxASCII        = 0x7F     // maximum ASCII value.
	MaxLatin1       = 0xFF     // maximum Latin-1 value.
)

// RangeTable defines a set of Unicode code points by listing the ranges of
// code points within the set. The ranges are listed in two slices
// to save space: a slice of 16-bit ranges and a slice of 32-bit ranges.
// The two slices must be in sorted order and non-overlapping.
// Also, R32 should contain only values >= 0x10000 (1<<16).
type RangeTable struct {
	R16 []Range16
	R32 []Range32
}

// Range16 represents of a range of 16-bit Unicode code points.  The range runs from Lo to Hi
// inclusive and has the specified stride.
type Range16 struct {
	Lo     uint16
	Hi     uint16
	Stride uint16
}

// Range32 represents of a range of Unicode code points and is used when one or
// more of the values will not fit in 16 bits.  The range runs from Lo to Hi
// inclusive and has the specified stride. Lo and Hi must always be >= 1<<16.
type Range32 struct {
	Lo     uint32
	Hi     uint32
	Stride uint32
}

// CaseRange represents a range of Unicode code points for simple (one
// code point to one code point) case conversion.
// The range runs from Lo to Hi inclusive, with a fixed stride of 1.  Deltas
// are the number to add to the code point to reach the code point for a
// different case for that character.  They may be negative.  If zero, it
// means the character is in the corresponding case. There is a special
// case representing sequences of alternating corresponding Upper and Lower
// pairs.  It appears with a fixed Delta of
//	{UpperLower, UpperLower, UpperLower}
// The constant UpperLower has an otherwise impossible delta value.
type CaseRange struct {
	Lo    uint32
	Hi    uint32
	Delta d
}

// SpecialCase represents language-specific case mappings such as Turkish.
// Methods of SpecialCase customize (by overriding) the standard mappings.
type SpecialCase []CaseRange

//BUG(r): Provide a mechanism for full case folding (those that involve
// multiple runes in the input or output).

// Indices into the Delta arrays inside CaseRanges for case mapping.
const (
	UpperCase = iota
	LowerCase
	TitleCase
	MaxCase
)

type d [MaxCase]int32 // to make the CaseRanges text shorter

// If the Delta field of a CaseRange is UpperLower or LowerUpper, it means
// this CaseRange represents a sequence of the form (say)
// Upper Lower Upper Lower.
const (
	UpperLower = MaxRune + 1 // (Cannot be a valid delta.)
)

// is16 uses binary search to test whether rune is in the specified slice of 16-bit ranges.
func is16(ranges []Range16, rune uint16) bool {
	// binary search over ranges
	lo := 0
	hi := len(ranges)
	for lo < hi {
		m := lo + (hi-lo)/2
		r := ranges[m]
		if r.Lo <= rune && rune <= r.Hi {
			return (rune-r.Lo)%r.Stride == 0
		}
		if rune < r.Lo {
			hi = m
		} else {
			lo = m + 1
		}
	}
	return false
}

// is32 uses binary search to test whether rune is in the specified slice of 32-bit ranges.
func is32(ranges []Range32, rune uint32) bool {
	// binary search over ranges
	lo := 0
	hi := len(ranges)
	for lo < hi {
		m := lo + (hi-lo)/2
		r := ranges[m]
		if r.Lo <= rune && rune <= r.Hi {
			return (rune-r.Lo)%r.Stride == 0
		}
		if rune < r.Lo {
			hi = m
		} else {
			lo = m + 1
		}
	}
	return false
}

// Is tests whether rune is in the specified table of ranges.
func Is(rangeTab *RangeTable, rune int) bool {
	// common case: rune is ASCII or Latin-1.
	if uint32(rune) <= MaxLatin1 {
		// Only need to check R16, since R32 is always >= 1<<16.
		r16 := uint16(rune)
		for _, r := range rangeTab.R16 {
			if r16 > r.Hi {
				continue
			}
			if r16 < r.Lo {
				return false
			}
			return (r16-r.Lo)%r.Stride == 0
		}
		return false
	}
	r16 := rangeTab.R16
	if len(r16) > 0 && rune <= int(r16[len(r16)-1].Hi) {
		return is16(r16, uint16(rune))
	}
	r32 := rangeTab.R32
	if len(r32) > 0 && rune >= int(r32[0].Lo) {
		return is32(r32, uint32(rune))
	}
	return false
}

// IsUpper reports whether the rune is an upper case letter.
func IsUpper(rune int) bool {
	// See comment in IsGraphic.
	if uint32(rune) <= MaxLatin1 {
		return properties[uint8(rune)]&pLu != 0
	}
	return Is(Upper, rune)
}

// IsLower reports whether the rune is a lower case letter.
func IsLower(rune int) bool {
	// See comment in IsGraphic.
	if uint32(rune) <= MaxLatin1 {
		return properties[uint8(rune)]&pLl != 0
	}
	return Is(Lower, rune)
}

// IsTitle reports whether the rune is a title case letter.
func IsTitle(rune int) bool {
	if rune <= MaxLatin1 {
		return false
	}
	return Is(Title, rune)
}

// to maps the rune using the specified case mapping.
func to(_case int, rune int, caseRange []CaseRange) int {
	if _case < 0 || MaxCase <= _case {
		return ReplacementChar // as reasonable an error as any
	}
	// binary search over ranges
	lo := 0
	hi := len(caseRange)
	for lo < hi {
		m := lo + (hi-lo)/2
		r := caseRange[m]
		if int(r.Lo) <= rune && rune <= int(r.Hi) {
			delta := int(r.Delta[_case])
			if delta > MaxRune {
				// In an Upper-Lower sequence, which always starts with
				// an UpperCase letter, the real deltas always look like:
				//	{0, 1, 0}    UpperCase (Lower is next)
				//	{-1, 0, -1}  LowerCase (Upper, Title are previous)
				// The characters at even offsets from the beginning of the
				// sequence are upper case; the ones at odd offsets are lower.
				// The correct mapping can be done by clearing or setting the low
				// bit in the sequence offset.
				// The constants UpperCase and TitleCase are even while LowerCase
				// is odd so we take the low bit from _case.
				return int(r.Lo) + ((rune-int(r.Lo))&^1 | _case&1)
			}
			return rune + delta
		}
		if rune < int(r.Lo) {
			hi = m
		} else {
			lo = m + 1
		}
	}
	return rune
}

// To maps the rune to the specified case: UpperCase, LowerCase, or TitleCase.
func To(_case int, rune int) int {
	return to(_case, rune, CaseRanges)
}

// ToUpper maps the rune to upper case.
func ToUpper(rune int) int {
	if rune <= MaxASCII {
		if 'a' <= rune && rune <= 'z' {
			rune -= 'a' - 'A'
		}
		return rune
	}
	return To(UpperCase, rune)
}

// ToLower maps the rune to lower case.
func ToLower(rune int) int {
	if rune <= MaxASCII {
		if 'A' <= rune && rune <= 'Z' {
			rune += 'a' - 'A'
		}
		return rune
	}
	return To(LowerCase, rune)
}

// ToTitle maps the rune to title case.
func ToTitle(rune int) int {
	if rune <= MaxASCII {
		if 'a' <= rune && rune <= 'z' { // title case is upper case for ASCII
			rune -= 'a' - 'A'
		}
		return rune
	}
	return To(TitleCase, rune)
}

// ToUpper maps the rune to upper case giving priority to the special mapping.
func (special SpecialCase) ToUpper(rune int) int {
	r := to(UpperCase, rune, []CaseRange(special))
	if r == rune {
		r = ToUpper(rune)
	}
	return r
}

// ToTitle maps the rune to title case giving priority to the special mapping.
func (special SpecialCase) ToTitle(rune int) int {
	r := to(TitleCase, rune, []CaseRange(special))
	if r == rune {
		r = ToTitle(rune)
	}
	return r
}

// ToLower maps the rune to lower case giving priority to the special mapping.
func (special SpecialCase) ToLower(rune int) int {
	r := to(LowerCase, rune, []CaseRange(special))
	if r == rune {
		r = ToLower(rune)
	}
	return r
}

// caseOrbit is defined in tables.go as []foldPair.  Right now all the
// entries fit in uint16, so use uint16.  If that changes, compilation
// will fail (the constants in the composite literal will not fit in uint16)
// and the types here can change to uint32.
type foldPair struct {
	From uint16
	To   uint16
}

// SimpleFold iterates over Unicode code points equivalent under
// the Unicode-defined simple case folding.  Among the code points
// equivalent to rune (including rune itself), SimpleFold returns the
// smallest r >= rune if one exists, or else the smallest r >= 0.
//
// For example:
//	SimpleFold('A') = 'a'
//	SimpleFold('a') = 'A'
//
//	SimpleFold('K') = 'k'
//	SimpleFold('k') = '\u212A' (Kelvin symbol, K)
//	SimpleFold('\u212A') = 'K'
//
//	SimpleFold('1') = '1'
//
func SimpleFold(rune int) int {
	// Consult caseOrbit table for special cases.
	lo := 0
	hi := len(caseOrbit)
	for lo < hi {
		m := lo + (hi-lo)/2
		if int(caseOrbit[m].From) < rune {
			lo = m + 1
		} else {
			hi = m
		}
	}
	if lo < len(caseOrbit) && int(caseOrbit[lo].From) == rune {
		return int(caseOrbit[lo].To)
	}

	// No folding specified.  This is a one- or two-element
	// equivalence class containing rune and ToLower(rune)
	// and ToUpper(rune) if they are different from rune.
	if l := ToLower(rune); l != rune {
		return l
	}
	return ToUpper(rune)
}
<|endoftext|>


<commit_before>// freenovel project freenovel.go
package freenovel

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"strings"

	"github.com/PuerkitoBio/goquery"
	"github.com/axgle/mahonia"
)

type Novel struct {
	wetsite         string
	charset         string
	menuRefer       string
	noveName        string
	menuList        string
	chtRefer        string
	chtTitle        string
	chtContent      string
	chtContentStrip string
}

type bookInfo struct {
	name        string
	chtNameList []string
	chtUrlList  []string
}

var mapNovel map[string]*Novel = make(map[string]*Novel)
var chtReplacer = strings.NewReplacer("
", "\r\n", "
", "\r\n", "
", "\r\n")

func init() {
	mapNovel["www.xxbiquge.com"] = &Novel{
		wetsite:         "www.xxbiquge.com",
		charset:         "utf-8",
		menuRefer:       "",
		noveName:        "#info h1",
		menuList:        "#list dl dd a",
		chtRefer:        "",
		chtTitle:        "div.bookname h1",
		chtContent:      "#content",
		chtContentStrip: "",
	}

	mapNovel["www.zwdu.com"] = &Novel{
		wetsite:         "www.zwdu.com",
		charset:         "gbk",
		menuRefer:       "",
		noveName:        "#info h1",
		menuList:        "#list dl dd a",
		chtRefer:        "",
		chtTitle:        "div.bookname h1",
		chtContent:      "#content",
		chtContentStrip: "",
	}

	mapNovel["www.23us.com"] = &Novel{
		wetsite:         "www.23us.com",
		charset:         "gbk",
		menuRefer:       "",
		noveName:        "div.bdsub dl dd h1",
		menuList:        "#at tbody tr td a",
		chtRefer:        "",
		chtTitle:        "div.bdsub dl dd",
		chtContent:      "#contents",
		chtContentStrip: "顶点小说 ２３ＵＳ．ＣＯＭ更新最快",
	}

	mapNovel["www.88dushu.com"] = &Novel{
		wetsite:         "www.88dushu.com",
		charset:         "gbk",
		menuRefer:       "",
		noveName:        "div.rt h1",
		menuList:        "div.mulu ul li a",
		chtRefer:        "",
		chtTitle:        "div.novel h1",
		chtContent:      "div.yd_text2",
		chtContentStrip: "",
	}

	mapNovel["www.qu.la"] = &Novel{
		wetsite:         "www.qu.la",
		charset:         "utf-8",
		menuRefer:       "",
		noveName:        "#info h1",
		menuList:        "#list dl dd a",
		chtRefer:        "",
		chtTitle:        "div.bookname h1",
		chtContent:      "#content",
		chtContentStrip: "",
	}

	mapNovel["www.biqudao.com"] = &Novel{
		wetsite:         "www.biqudao.com",
		charset:         "utf-8",
		menuRefer:       "",
		noveName:        "#info h1",
		menuList:        "#list dl dd a",
		chtRefer:        "",
		chtTitle:        "div.bookname h1",
		chtContent:      "#content",
		chtContentStrip: "",
	}

	mapNovel["www.shoujikanshu.org"] = &Novel{
		wetsite:         "www.shoujikanshu.org",
		charset:         "gbk",
		menuRefer:       "",
		noveName:        "div.box-artic h1",
		menuList:        "div.list li a",
		chtRefer:        "",
		chtTitle:        "div.subNav h1",
		chtContent:      "div.content",
		chtContentStrip: "",
	}

}

func viewSource(strUrl, charset string, outBuf *bytes.Buffer, hc *http.Client, tryCount int) {
	outBuf.Reset()
	nTry := 0
	if tryCount < 1 {
		tryCount = 1
	}
RETRYGET:
	func() {
		rsp, err := hc.Get(strUrl)
		if err != nil {
			fmt.Println(err)
			return
		}
		defer rsp.Body.Close()

		p, err := ioutil.ReadAll(rsp.Body)
		if err != nil {
			fmt.Println(err)
			return
		}

		switch charset {
		case "gbk":
			outBuf.WriteString(mahonia.NewDecoder("gbk").ConvertByte(p))
		case "gb18030":
			outBuf.WriteString(mahonia.NewDecoder("gb18030").ConvertByte(p))
		case "utf-16":
			outBuf.WriteString(mahonia.NewDecoder("utf-16").ConvertByte(p))
		default:
			outBuf.Write(p)
		}
	}()

	if outBuf.Len() == 0 && nTry < tryCount {
		nTry += 1
		goto RETRYGET
	}
}

func getBookInfo(bi *bookInfo, nl *Novel, noveUrl string) bool {
	hc := &http.Client{}
	buf := &bytes.Buffer{}
	viewSource(noveUrl, nl.charset, buf, hc, 3)

	doc, err := goquery.NewDocumentFromReader(buf)
	if err != nil {
		fmt.Println(err)
		return false
	}

	bi.name = doc.Find(nl.noveName).Text()
	nodes := doc.Find(nl.menuList)

	itemCount := nodes.Length()
	if itemCount <= 0 {
		return false
	}

	strPreUrl := ""
	strItemLink := "href"
	if strUrl, ok := nodes.Eq(0).Attr(strItemLink); ok {
		if strUrl[0] == '/' {
			strPreUrl = "http://" + nl.wetsite
		} else {
			urlIdx := strings.LastIndex(noveUrl, "/")
			strPreUrl = noveUrl[0 : urlIdx+1]
		}
	}

	for i := 0; i < itemCount; i++ {
		v := nodes.Eq(i)
		strTitle := v.Text()
		strUrl, _ := v.Attr(strItemLink)
		if strTitle != "" {
			bi.chtUrlList = append(bi.chtUrlList, strPreUrl+strUrl)
			bi.chtNameList = append(bi.chtNameList, strTitle)
		}
	}

	return true
}

func NovelDownload(noveUrl string) bool {
	u, err := url.Parse(noveUrl)
	if err != nil {
		fmt.Println(err)
		return false
	}

	nitem, ok := mapNovel[u.Host]
	if !ok {
		fmt.Println("not supported website:", noveUrl)
		return false
	}

	bi := bookInfo{}

	if !getBookInfo(&bi, nitem, noveUrl) {
		fmt.Println("parse website tag err")
		return false
	}

	hc := &http.Client{}
	buf := &bytes.Buffer{}

	f, err := os.Create(bi.name + ".txt")
	if err != nil {
		fmt.Println(err)
		return false
	}
	defer f.Close()

	nChapter := len(bi.chtUrlList)
	for i := 0; i < nChapter; i++ {
		func(strTitle, strUrl string) {
			viewSource(strUrl, nitem.charset, buf, hc, 3)
			doc, err := goquery.NewDocumentFromReader(buf)
			if err != nil {
				fmt.Println(err)
				return
			}

			strContentHtml, _ := doc.Find(nitem.chtContent).Html()
			strContent := chtReplacer.Replace(strContentHtml)
			if nitem.chtContentStrip != "" {
				strContent = strings.Replace(strContent, nitem.chtContentStrip, "", -1)
			}

			if strContent == "" {
				fmt.Println("get charpter error:", strTitle, strUrl)
			}

			f.WriteString(strTitle + "\r\n\r\n")
			f.WriteString(strContent)
			f.WriteString("\r\n")
			fmt.Println(i+1, "/", nChapter, strTitle, strUrl)
			f.Sync()
		}(bi.chtNameList[i], bi.chtUrlList[i])
	}

	return true
}
<commit_msg>add decoder gb2312<commit_after>// freenovel project freenovel.go
package freenovel

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"strings"

	"github.com/PuerkitoBio/goquery"
	"github.com/axgle/mahonia"
)

type Novel struct {
	wetsite         string
	charset         string
	menuRefer       string
	noveName        string
	menuList        string
	chtRefer        string
	chtTitle        string
	chtContent      string
	chtContentStrip string
}

type bookInfo struct {
	name        string
	chtNameList []string
	chtUrlList  []string
}

var mapNovel map[string]*Novel = make(map[string]*Novel)
var chtReplacer = strings.NewReplacer("
", "\r\n", "
", "\r\n", "
", "\r\n")

func init() {
	mapNovel["www.xxbiquge.com"] = &Novel{
		wetsite:         "www.xxbiquge.com",
		charset:         "utf-8",
		menuRefer:       "",
		noveName:        "#info h1",
		menuList:        "#list dl dd a",
		chtRefer:        "",
		chtTitle:        "div.bookname h1",
		chtContent:      "#content",
		chtContentStrip: "",
	}

	mapNovel["www.zwdu.com"] = &Novel{
		wetsite:         "www.zwdu.com",
		charset:         "gbk",
		menuRefer:       "",
		noveName:        "#info h1",
		menuList:        "#list dl dd a",
		chtRefer:        "",
		chtTitle:        "div.bookname h1",
		chtContent:      "#content",
		chtContentStrip: "",
	}

	mapNovel["www.23us.com"] = &Novel{
		wetsite:         "www.23us.com",
		charset:         "gbk",
		menuRefer:       "",
		noveName:        "div.bdsub dl dd h1",
		menuList:        "#at tbody tr td a",
		chtRefer:        "",
		chtTitle:        "div.bdsub dl dd",
		chtContent:      "#contents",
		chtContentStrip: "顶点小说 ２３ＵＳ．ＣＯＭ更新最快",
	}

	mapNovel["www.88dushu.com"] = &Novel{
		wetsite:         "www.88dushu.com",
		charset:         "gbk",
		menuRefer:       "",
		noveName:        "div.rt h1",
		menuList:        "div.mulu ul li a",
		chtRefer:        "",
		chtTitle:        "div.novel h1",
		chtContent:      "div.yd_text2",
		chtContentStrip: "",
	}

	mapNovel["www.qu.la"] = &Novel{
		wetsite:         "www.qu.la",
		charset:         "utf-8",
		menuRefer:       "",
		noveName:        "#info h1",
		menuList:        "#list dl dd a",
		chtRefer:        "",
		chtTitle:        "div.bookname h1",
		chtContent:      "#content",
		chtContentStrip: "",
	}

	mapNovel["www.biqudao.com"] = &Novel{
		wetsite:         "www.biqudao.com",
		charset:         "utf-8",
		menuRefer:       "",
		noveName:        "#info h1",
		menuList:        "#list dl dd a",
		chtRefer:        "",
		chtTitle:        "div.bookname h1",
		chtContent:      "#content",
		chtContentStrip: "",
	}

	mapNovel["www.shoujikanshu.org"] = &Novel{
		wetsite:         "www.shoujikanshu.org",
		charset:         "gb2312",
		menuRefer:       "",
		noveName:        "div.box-artic h1",
		menuList:        "div.list li a",
		chtRefer:        "",
		chtTitle:        "div.subNav h1",
		chtContent:      "div.content",
		chtContentStrip: "",
	}

}

func viewSource(strUrl, charset string, outBuf *bytes.Buffer, hc *http.Client, tryCount int) {
	outBuf.Reset()
	nTry := 0
	if tryCount < 1 {
		tryCount = 1
	}
RETRYGET:
	func() {
		rsp, err := hc.Get(strUrl)
		if err != nil {
			fmt.Println(err)
			return
		}
		defer rsp.Body.Close()

		p, err := ioutil.ReadAll(rsp.Body)
		if err != nil {
			fmt.Println(err)
			return
		}

		switch charset {
		case "gb2312":
			outBuf.WriteString(mahonia.NewDecoder("gbk").ConvertByte(p))
		case "gbk":
			outBuf.WriteString(mahonia.NewDecoder("gbk").ConvertByte(p))
		case "gb18030":
			outBuf.WriteString(mahonia.NewDecoder("gb18030").ConvertByte(p))
		case "utf-16":
			outBuf.WriteString(mahonia.NewDecoder("utf-16").ConvertByte(p))
		default:
			outBuf.Write(p)
		}
	}()

	if outBuf.Len() == 0 && nTry < tryCount {
		nTry += 1
		goto RETRYGET
	}
}

func getBookInfo(bi *bookInfo, nl *Novel, noveUrl string) bool {
	hc := &http.Client{}
	buf := &bytes.Buffer{}
	viewSource(noveUrl, nl.charset, buf, hc, 3)

	doc, err := goquery.NewDocumentFromReader(buf)
	if err != nil {
		fmt.Println(err)
		return false
	}

	bi.name = doc.Find(nl.noveName).Text()
	nodes := doc.Find(nl.menuList)

	itemCount := nodes.Length()
	if itemCount <= 0 {
		return false
	}

	strPreUrl := ""
	strItemLink := "href"
	if strUrl, ok := nodes.Eq(0).Attr(strItemLink); ok {
		if strUrl[0] == '/' {
			strPreUrl = "http://" + nl.wetsite
		} else {
			urlIdx := strings.LastIndex(noveUrl, "/")
			strPreUrl = noveUrl[0 : urlIdx+1]
		}
	}

	for i := 0; i < itemCount; i++ {
		v := nodes.Eq(i)
		strTitle := v.Text()
		strUrl, _ := v.Attr(strItemLink)
		if strTitle != "" {
			bi.chtUrlList = append(bi.chtUrlList, strPreUrl+strUrl)
			bi.chtNameList = append(bi.chtNameList, strTitle)
		}
	}

	return true
}

func NovelDownload(noveUrl string) bool {
	u, err := url.Parse(noveUrl)
	if err != nil {
		fmt.Println(err)
		return false
	}

	nitem, ok := mapNovel[u.Host]
	if !ok {
		fmt.Println("not supported website:", noveUrl)
		return false
	}

	bi := bookInfo{}

	if !getBookInfo(&bi, nitem, noveUrl) {
		fmt.Println("parse website tag err")
		return false
	}

	hc := &http.Client{}
	buf := &bytes.Buffer{}

	f, err := os.Create(bi.name + ".txt")
	if err != nil {
		fmt.Println(err)
		return false
	}
	defer f.Close()

	nChapter := len(bi.chtUrlList)
	for i := 0; i < nChapter; i++ {
		func(strTitle, strUrl string) {
			viewSource(strUrl, nitem.charset, buf, hc, 3)
			doc, err := goquery.NewDocumentFromReader(buf)
			if err != nil {
				fmt.Println(err)
				return
			}

			strContentHtml, _ := doc.Find(nitem.chtContent).Html()
			strContent := chtReplacer.Replace(strContentHtml)
			if nitem.chtContentStrip != "" {
				strContent = strings.Replace(strContent, nitem.chtContentStrip, "", -1)
			}

			if strContent == "" {
				fmt.Println("get charpter error:", strTitle, strUrl)
			}

			f.WriteString(strTitle + "\r\n\r\n")
			f.WriteString(strContent)
			f.WriteString("\r\n")
			fmt.Println(i+1, "/", nChapter, strTitle, strUrl)
			f.Sync()
		}(bi.chtNameList[i], bi.chtUrlList[i])
	}

	return true
}
<|endoftext|>


<commit_before>package umbrella

import (
	"bytes"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/json"
	"encoding/pem"
	"strings"
	"testing"
	"time"

	"github.com/asjoyner/shade"
	"github.com/asjoyner/shade/drive"
	"github.com/asjoyner/shade/drive/compare"
	"github.com/asjoyner/shade/drive/encrypt"
	"github.com/asjoyner/shade/drive/memory"
)

const chunkSize uint64 = 100 * 256

func newMemoryClient(t *testing.T) drive.Client {
	mc, err := memory.NewClient(drive.Config{Provider: "memory"})
	if err != nil {
		t.Fatalf("could not initilize test client: %s", err)
	}
	return mc
}

func TestFetchingFiles(t *testing.T) {
	mc := newMemoryClient(t)

	// Make a new file with 1 chunk
	file := shade.NewFile("testfile")

	// Put the original copy of the file in the client
	putFile(t, mc, *file)

	// Push a version of the file with a newer mtime
	file.ModifiedTime = file.ModifiedTime.Add(1 * time.Minute)
	putFile(t, mc, *file)

	// Push an even newer version of the file that is deleted
	file.ModifiedTime = file.ModifiedTime.Add(1 * time.Minute)
	file.Deleted = true
	putFile(t, mc, *file)

	inUse, obsolete, err := FetchFiles(mc)
	if err != nil {
		t.Fatal(err)
	}

	if len(inUse) != 1 {
		t.Errorf("in use files unexpected, want: 1, got %d", len(inUse))
	}
	if len(obsolete) != 2 {
		t.Errorf("obsolete files unexpected, want: 2, got %d", len(obsolete))
	}

}

func TestRemovingOrphanedFiles(t *testing.T) {
	mc := newMemoryClient(t)
	expected := newMemoryClient(t)

	// Make a new file with 1 chunk
	file := shade.NewFile("testfile")
	sum, data := drive.RandChunk()
	chunk := shade.NewChunk()
	chunk.Index = 0
	chunk.Sha256 = []byte(sum)
	file.Chunks = append(file.Chunks, chunk)
	file.LastChunksize = int(chunkSize)

	if err := mc.PutChunk(sum, data, file); err != nil {
		t.Fatal(err)
	}
	if err := expected.PutChunk(sum, data, file); err != nil {
		t.Fatal(err)
	}

	// Put the original copy of the file in the client
	putFile(t, mc, *file)

	// Push a version of the file with a newer mtime
	file.ModifiedTime = file.ModifiedTime.Add(1 * time.Minute)
	putFile(t, mc, *file)

	// Push an even newer version of the file that is deleted
	file.ModifiedTime = file.ModifiedTime.Add(1 * time.Minute)
	file.Deleted = true
	putFile(t, mc, *file)
	putFile(t, expected, *file)

	err := Cleanup(mc)
	if err == nil {
		t.Errorf("want: 'more files are obsolete', got: nil")
	}
	if !strings.Contains(err.Error(), "more files are obsolete") {
		t.Errorf("want: 'more files are obsolete', got: %s", err)
	}

	// Push another file (similar content) to satisfy the safety threshold
	file.Filename = "testFile2"
	putFile(t, mc, *file)
	putFile(t, expected, *file)
	if err := Cleanup(mc); err != nil {
		t.Error(err)
	}

	// assert the actual class types to be able to check the internals
	if err := expected.(*memory.Drive).Equal(mc.(*memory.Drive)); err != nil {
		t.Fatal(err)
	}
}

func TestRemovingOrphanedChunks(t *testing.T) {
	mc := newMemoryClient(t)
	expected := newMemoryClient(t)

	// Make a new file with 1 chunk
	file := shade.NewFile("testfile")
	sum, data := drive.RandChunk()
	chunk := shade.NewChunk()
	chunk.Index = 0
	chunk.Sha256 = []byte(sum)
	file.Chunks = append(file.Chunks, chunk)
	file.LastChunksize = int(chunkSize)

	if err := mc.PutChunk(sum, data, file); err != nil {
		t.Fatal(err)
	}
	if err := expected.PutChunk(sum, data, file); err != nil {
		t.Fatal(err)
	}
	// Put some random unreferenced chunks, to be cleaned up
	for x := 0; x < 10; x++ {
		sum, data := drive.RandChunk()
		if err := mc.PutChunk(sum, data, file); err != nil {
			t.Fatal(err)
		}
	}

	// Put the original copy of the file in the client
	putFile(t, mc, *file)
	putFile(t, expected, *file)

	if err := Cleanup(mc); err != nil {
		t.Error(err)
	}

	// assert the actual class types to be able to check the internals
	if err := expected.(*memory.Drive).Equal(mc.(*memory.Drive)); err != nil {
		t.Fatal(err)
	}
}

func TestEncryptedClients(t *testing.T) {
	privkey, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		t.Fatal(err)
	}
	derBytes := x509.MarshalPKCS1PrivateKey(privkey)
	b := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: derBytes}
	pemPrivKey := string(pem.EncodeToMemory(b))
	testClient, err := encrypt.NewClient(drive.Config{
		Provider:      "encrypt",
		RsaPrivateKey: pemPrivKey,
		Children:      []drive.Config{{Provider: "memory", Write: true}},
	})
	if err != nil {
		t.Fatalf("could not initilize test client: %s", err)
	}
	expected, err := encrypt.NewClient(drive.Config{
		Provider:      "encrypt",
		RsaPrivateKey: pemPrivKey,
		Children:      []drive.Config{{Provider: "memory", Write: true}},
	})
	if err != nil {
		t.Fatalf("could not initilize test client: %s", err)
	}
	unencrypted := newMemoryClient(t)

	numFiles := 4
	var keptFile *shade.File
	for f := 0; f <= numFiles; f++ {
		// Make a new file
		file := shade.NewFile("testfile")
		file.LastChunksize = int(chunkSize)
		// Add 4 chunks
		for x := 0; x < 4; x++ {
			sum, data := drive.RandChunk()
			chunk := shade.NewChunk()
			chunk.Index = x
			chunk.Sha256 = []byte(sum)
			file.Chunks = append(file.Chunks, chunk)
			if err := testClient.PutChunk(sum, data, file); err != nil {
				t.Fatal(err)
			}
			// Put only the chunks of the last file in the expected clients
			if f == numFiles {
				if err := expected.PutChunk(sum, data, file); err != nil {
					t.Fatal(err)
				}
				if err := unencrypted.PutChunk(sum, data, file); err != nil {
					t.Fatal(err)
				}
			}
		}
		// Put only the last file in the client(s)
		if f == numFiles {
			putFile(t, testClient, *file)
			putFile(t, expected, *file)
			putFile(t, unencrypted, *file)
			keptFile = file
		}

	}

	if err := Cleanup(testClient); err != nil {
		t.Error(err)
	}

	// quick check to see if everything was okay
	ok, err := compare.Equal(expected, testClient)
	if err != nil {
		t.Fatal(err)
	}
	if !ok {
		t.Errorf("expected and test client are not equal!")
	}

	expectedExtras, testClientExtras, err := compare.GetDelta(expected, testClient)
	if err != nil {
		t.Fatal(err)
	}
	for _, sum := range testClientExtras.Files {
		t.Errorf("file was not cleaned up: %x", sum)
	}
	for _, sum := range testClientExtras.Chunks {
		t.Errorf("chunk was not cleaned up: %x", sum)
	}
	for _, sum := range expectedExtras.Files {
		t.Errorf("in-use file was deleted: %x", sum)
	}
	for _, sum := range expectedExtras.Chunks {
		t.Errorf("in-use chunk was deleted: %x", sum)
	}

	unencryptedExtras, testClientExtras, err := compare.GetDelta(unencrypted, testClient)
	// since we have the data handy, double-check that files coming back from the
	// encrypted client and unencrypted clients are ethe same.
	for _, sum := range testClientExtras.Files {
		t.Errorf("file was not cleaned up: %x", sum)
	}
	for _, sum := range unencryptedExtras.Files {
		t.Errorf("in-use file was deleted: %x", sum)
	}
	// check that each unencrypted chunk that wasn't the same actually matches
	// the encrypted chunk sum of the last file pushed
	for _, sum := range unencryptedExtras.Chunks {
		t.Logf("considering unencryptedExtra chunk: %x", sum)
		var found bool
		for _, esum := range testClientExtras.Chunks {
			s, err := encrypt.GetEncryptedSum(sum, keptFile)
			if err != nil {
				continue
			}
			if bytes.Equal(s, esum) {
				found = true
				t.Logf("matched unencryptedExtra chunk %x to %x", sum, esum)
			}
		}
		if !found {
			t.Errorf("in-use encrypted chunk sum was deleted: %x", sum)
		}
	}
}

// putFile wraps up the boilerplate to push a snapshot of a file into a given
// client.  It calls t.Fatalf if it encounters any unexpected errors.
func putFile(t *testing.T, client drive.Client, file shade.File) {
	jm, err := json.Marshal(file)
	if err != nil {
		t.Fatal(err)
	}
	sum := shade.Sum(jm)
	t.Logf("Putting file with sum: %x", sum)
	if err := client.PutFile(sum, jm); err != nil {
		t.Fatal(err)
	}
}
<commit_msg>Push more orphaned files, out of order<commit_after>package umbrella

import (
	"bytes"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/json"
	"encoding/pem"
	"fmt"
	"strings"
	"testing"
	"time"

	"github.com/asjoyner/shade"
	"github.com/asjoyner/shade/drive"
	"github.com/asjoyner/shade/drive/compare"
	"github.com/asjoyner/shade/drive/encrypt"
	"github.com/asjoyner/shade/drive/memory"
)

const chunkSize uint64 = 100 * 256

func newMemoryClient(t *testing.T) drive.Client {
	mc, err := memory.NewClient(drive.Config{Provider: "memory"})
	if err != nil {
		t.Fatalf("could not initilize test client: %s", err)
	}
	return mc
}

func TestFetchingFiles(t *testing.T) {
	mc := newMemoryClient(t)

	// Make a new file with 1 chunk
	file := shade.NewFile("testfile")

	// Put the original copy of the file in the client
	putFile(t, mc, *file)

	// Push a version of the file with a newer mtime
	file.ModifiedTime = file.ModifiedTime.Add(1 * time.Minute)
	putFile(t, mc, *file)

	// Push an even newer version of the file that is deleted
	file.ModifiedTime = file.ModifiedTime.Add(1 * time.Minute)
	file.Deleted = true
	putFile(t, mc, *file)

	inUse, obsolete, err := FetchFiles(mc)
	if err != nil {
		t.Fatal(err)
	}

	if len(inUse) != 1 {
		t.Errorf("in use files unexpected, want: 1, got %d", len(inUse))
	}
	if len(obsolete) != 2 {
		t.Errorf("obsolete files unexpected, want: 2, got %d", len(obsolete))
	}
}

func TestRemovingOrphanedFiles(t *testing.T) {
	mc := newMemoryClient(t)
	expected := newMemoryClient(t)

	// Make a new file with 1 chunk
	file := shade.NewFile("testfile")
	sum, data := drive.RandChunk()
	chunk := shade.NewChunk()
	chunk.Index = 0
	chunk.Sha256 = []byte(sum)
	file.Chunks = append(file.Chunks, chunk)
	file.LastChunksize = int(chunkSize)

	if err := mc.PutChunk(sum, data, file); err != nil {
		t.Fatal(err)
	}
	if err := expected.PutChunk(sum, data, file); err != nil {
		t.Fatal(err)
	}

	// Push a version of the file with the current mtime
	file.ModifiedTime = time.Now()
	putFile(t, mc, *file)

	// Push several versions of the file with a much older mtime
	file.ModifiedTime = file.ModifiedTime.Add(-6 * time.Hour)
	for x := 0; x < 5; x++ {
		file.ModifiedTime = file.ModifiedTime.Add(1 * time.Minute)
		putFile(t, mc, *file)
	}

	// Push a version of the file with a newer mtime
	file.ModifiedTime = time.Now().Add(1 * time.Minute)
	putFile(t, mc, *file)

	// Push an even newer version of the file that is deleted
	file.ModifiedTime = file.ModifiedTime.Add(6 * time.Minute)
	file.Deleted = true
	putFile(t, mc, *file)
	putFile(t, expected, *file)

	err := Cleanup(mc)
	if err == nil {
		t.Errorf("want: 'more files are obsolete', got: nil")
	}
	if !strings.Contains(err.Error(), "more files are obsolete") {
		t.Errorf("want: 'more files are obsolete', got: %s", err)
	}

	// Push more files (similar content) to satisfy the safety threshold
	for x := 2; x < 12; x++ {
		file.Filename = fmt.Sprintf("testFile%d", x)
		putFile(t, mc, *file)
		putFile(t, expected, *file)
	}
	if err := Cleanup(mc); err != nil {
		t.Error(err)
	}

	expectedExtras, testClientExtras, err := compare.GetDelta(expected, mc)
	if err != nil {
		t.Fatal(err)
	}
	deltaErrors(t, expectedExtras, testClientExtras)
}

func TestRemovingOrphanedChunks(t *testing.T) {
	mc := newMemoryClient(t)
	expected := newMemoryClient(t)

	// Make a new file with 1 chunk
	file := shade.NewFile("testfile")
	sum, data := drive.RandChunk()
	chunk := shade.NewChunk()
	chunk.Index = 0
	chunk.Sha256 = []byte(sum)
	file.Chunks = append(file.Chunks, chunk)
	file.LastChunksize = int(chunkSize)

	if err := mc.PutChunk(sum, data, file); err != nil {
		t.Fatal(err)
	}
	if err := expected.PutChunk(sum, data, file); err != nil {
		t.Fatal(err)
	}
	// Put some random unreferenced chunks, to be cleaned up
	for x := 0; x < 10; x++ {
		sum, data := drive.RandChunk()
		if err := mc.PutChunk(sum, data, file); err != nil {
			t.Fatal(err)
		}
	}

	// Put the original copy of the file in the client
	putFile(t, mc, *file)
	putFile(t, expected, *file)

	if err := Cleanup(mc); err != nil {
		t.Error(err)
	}

	// assert the actual class types to be able to check the internals
	if err := expected.(*memory.Drive).Equal(mc.(*memory.Drive)); err != nil {
		t.Fatal(err)
	}
}

func TestEncryptedClients(t *testing.T) {
	privkey, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		t.Fatal(err)
	}
	derBytes := x509.MarshalPKCS1PrivateKey(privkey)
	b := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: derBytes}
	pemPrivKey := string(pem.EncodeToMemory(b))
	testClient, err := encrypt.NewClient(drive.Config{
		Provider:      "encrypt",
		RsaPrivateKey: pemPrivKey,
		Children:      []drive.Config{{Provider: "memory", Write: true}},
	})
	if err != nil {
		t.Fatalf("could not initilize test client: %s", err)
	}
	expected, err := encrypt.NewClient(drive.Config{
		Provider:      "encrypt",
		RsaPrivateKey: pemPrivKey,
		Children:      []drive.Config{{Provider: "memory", Write: true}},
	})
	if err != nil {
		t.Fatalf("could not initilize test client: %s", err)
	}
	unencrypted := newMemoryClient(t)

	numFiles := 4
	var keptFile *shade.File
	for f := 0; f <= numFiles; f++ {
		// Make a new file
		file := shade.NewFile("testfile")
		file.LastChunksize = int(chunkSize)
		// Add 4 chunks
		for x := 0; x < 4; x++ {
			sum, data := drive.RandChunk()
			chunk := shade.NewChunk()
			chunk.Index = x
			chunk.Sha256 = []byte(sum)
			file.Chunks = append(file.Chunks, chunk)
			if err := testClient.PutChunk(sum, data, file); err != nil {
				t.Fatal(err)
			}
			// Put only the chunks of the last file in the expected clients
			if f == numFiles {
				if err := expected.PutChunk(sum, data, file); err != nil {
					t.Fatal(err)
				}
				if err := unencrypted.PutChunk(sum, data, file); err != nil {
					t.Fatal(err)
				}
			}
		}
		// Put only the last file in the client(s)
		if f == numFiles {
			putFile(t, testClient, *file)
			putFile(t, expected, *file)
			putFile(t, unencrypted, *file)
			keptFile = file
		}

	}

	if err := Cleanup(testClient); err != nil {
		t.Error(err)
	}

	// quick check to see if everything was okay
	ok, err := compare.Equal(expected, testClient)
	if err != nil {
		t.Fatal(err)
	}
	if !ok {
		t.Errorf("expected and test client are not equal!")
	}

	expectedExtras, testClientExtras, err := compare.GetDelta(expected, testClient)
	if err != nil {
		t.Fatal(err)
	}
	for _, sum := range testClientExtras.Files {
		t.Errorf("file was not cleaned up: %x", sum)
	}
	for _, sum := range testClientExtras.Chunks {
		t.Errorf("chunk was not cleaned up: %x", sum)
	}
	for _, sum := range expectedExtras.Files {
		t.Errorf("in-use file was deleted: %x", sum)
	}
	for _, sum := range expectedExtras.Chunks {
		t.Errorf("in-use chunk was deleted: %x", sum)
	}

	unencryptedExtras, testClientExtras, err := compare.GetDelta(unencrypted, testClient)
	// since we have the data handy, double-check that files coming back from the
	// encrypted client and unencrypted clients are ethe same.
	for _, sum := range testClientExtras.Files {
		t.Errorf("file was not cleaned up: %x", sum)
	}
	for _, sum := range unencryptedExtras.Files {
		t.Errorf("in-use file was deleted: %x", sum)
	}
	// check that each unencrypted chunk that wasn't the same actually matches
	// the encrypted chunk sum of the last file pushed
	for _, sum := range unencryptedExtras.Chunks {
		t.Logf("considering unencryptedExtra chunk: %x", sum)
		var found bool
		for _, esum := range testClientExtras.Chunks {
			s, err := encrypt.GetEncryptedSum(sum, keptFile)
			if err != nil {
				continue
			}
			if bytes.Equal(s, esum) {
				found = true
				t.Logf("matched unencryptedExtra chunk %x to %x", sum, esum)
			}
		}
		if !found {
			t.Errorf("in-use encrypted chunk sum was deleted: %x", sum)
		}
	}
}

// putFile wraps up the boilerplate to push a snapshot of a file into a given
// client.  It calls t.Fatalf if it encounters any unexpected errors.
func putFile(t *testing.T, client drive.Client, file shade.File) {
	jm, err := json.Marshal(file)
	if err != nil {
		t.Fatal(err)
	}
	sum := shade.Sum(jm)
	t.Logf("Putting file with sum: %x", sum)
	if err := client.PutFile(sum, jm); err != nil {
		t.Fatal(err)
	}
}

func deltaErrors(t *testing.T, expectedExtras, testClientExtras compare.Delta) {
	for _, sum := range testClientExtras.Files {
		t.Errorf("file was not cleaned up: %x", sum)
	}
	for _, sum := range testClientExtras.Chunks {
		t.Errorf("chunk was not cleaned up: %x", sum)
	}
	for _, sum := range expectedExtras.Files {
		t.Errorf("in-use file was deleted: %x", sum)
	}
	for _, sum := range expectedExtras.Chunks {
		t.Errorf("in-use chunk was deleted: %x", sum)
	}
}
<|endoftext|>


<commit_before>package collectd

import (
	"strings"
	"time"

	"github.com/signalfuse/com_signalfuse_metrics_protobuf"
	"github.com/signalfuse/signalfxproxy/datapoint"
)

// JSONWriteBody is the full POST body of collectd's write_http format
type JSONWriteBody []*JSONWriteFormat

// JSONWriteFormat is the format for collectd json datapoints
type JSONWriteFormat struct {
	Dsnames        []*string  `json:"dsnames"`
	Dstypes        []*string  `json:"dstypes"`
	Host           *string    `json:"host"`
	Interval       *float64   `json:"interval"`
	Plugin         *string    `json:"plugin"`
	PluginInstance *string    `json:"plugin_instance"`
	Time           *float64   `json:"time"`
	TypeS          *string    `json:"type"`
	TypeInstance   *string    `json:"type_instance"`
	Values         []*float64 `json:"values"`
}

func metricTypeFromDsType(dstype *string) com_signalfuse_metrics_protobuf.MetricType {
	if dstype == nil {
		return com_signalfuse_metrics_protobuf.MetricType_GAUGE
	}

	m := map[string]com_signalfuse_metrics_protobuf.MetricType{
		"gauge":    com_signalfuse_metrics_protobuf.MetricType_GAUGE,
		"derive":   com_signalfuse_metrics_protobuf.MetricType_CUMULATIVE_COUNTER,
		"counter":  com_signalfuse_metrics_protobuf.MetricType_CUMULATIVE_COUNTER,
		"absolute": com_signalfuse_metrics_protobuf.MetricType_COUNTER,
	}
	v, ok := m[*dstype]
	if ok {
		return v
	}
	return com_signalfuse_metrics_protobuf.MetricType_GAUGE
}

func isNilOrEmpty(str *string) bool {
	return str == nil || *str == ""
}

// NewCollectdDatapoint creates a new datapoint from collectd's write_http endpoint JSON format
func NewCollectdDatapoint(point *JSONWriteFormat, index uint) datapoint.Datapoint {
	dstype, val, dsname := point.Dstypes[index], point.Values[index], point.Dsnames[index]
	dimensions := make(map[string]string)
	metricType := metricTypeFromDsType(dstype)
	metricName, usedParts := getReasonableMetricName(point, index)
	if point.Host != nil {
		dimensions["host"] = *point.Host
	}
	if point.Plugin != nil {
		dimensions["plugin"] = *point.Plugin
	}
	if point.PluginInstance != nil {
		dimensions["plugin_instance"] = *point.PluginInstance
	}
	if point.TypeInstance != nil {
		_, usedInMetricName := usedParts["type_instance"]
		if !usedInMetricName {
			dimensions["type_instance"] = *point.TypeInstance
		}
	}
	if point.TypeS != nil {
		_, usedInMetricName := usedParts["type"]
		if !usedInMetricName {
			dimensions["type"] = *point.TypeS
		}
	}
	if dsname != nil {
		_, usedInMetricName := usedParts["dsname"]
		if !usedInMetricName {
			dimensions["dsname"] = *dsname
		}
	}
	timestamp := time.Unix(0, int64(float64(time.Second)**point.Time))
	return datapoint.NewAbsoluteTime(metricName, dimensions, datapoint.NewFloatValue(*val), metricType, timestamp)
}

func getReasonableMetricName(point *JSONWriteFormat, index uint) (string, map[string]struct{}) {
	parts := []string{}
	usedParts := make(map[string]struct{})
	if !isNilOrEmpty(point.TypeS) {
		parts = append(parts, *point.TypeS)
		usedParts["type"] = struct{}{}
	}
	if !isNilOrEmpty(point.TypeInstance) {
		parts = append(parts, *point.TypeInstance)
		usedParts["type_instance"] = struct{}{}
	}
	if !isNilOrEmpty(point.Dsnames[index]) && len(point.Dsnames) > 1 {
		parts = append(parts, *point.Dsnames[index])
		usedParts["dsname"] = struct{}{}
	}
	return strings.Join(parts, "."), usedParts
}
<commit_msg>Update collectd listener to not send empty dimensions<commit_after>package collectd

import (
	"strings"
	"time"

	"github.com/signalfuse/com_signalfuse_metrics_protobuf"
	"github.com/signalfuse/signalfxproxy/datapoint"
)

// JSONWriteBody is the full POST body of collectd's write_http format
type JSONWriteBody []*JSONWriteFormat

// JSONWriteFormat is the format for collectd json datapoints
type JSONWriteFormat struct {
	Dsnames        []*string  `json:"dsnames"`
	Dstypes        []*string  `json:"dstypes"`
	Host           *string    `json:"host"`
	Interval       *float64   `json:"interval"`
	Plugin         *string    `json:"plugin"`
	PluginInstance *string    `json:"plugin_instance"`
	Time           *float64   `json:"time"`
	TypeS          *string    `json:"type"`
	TypeInstance   *string    `json:"type_instance"`
	Values         []*float64 `json:"values"`
}

func metricTypeFromDsType(dstype *string) com_signalfuse_metrics_protobuf.MetricType {
	if dstype == nil {
		return com_signalfuse_metrics_protobuf.MetricType_GAUGE
	}

	m := map[string]com_signalfuse_metrics_protobuf.MetricType{
		"gauge":    com_signalfuse_metrics_protobuf.MetricType_GAUGE,
		"derive":   com_signalfuse_metrics_protobuf.MetricType_CUMULATIVE_COUNTER,
		"counter":  com_signalfuse_metrics_protobuf.MetricType_CUMULATIVE_COUNTER,
		"absolute": com_signalfuse_metrics_protobuf.MetricType_COUNTER,
	}
	v, ok := m[*dstype]
	if ok {
		return v
	}
	return com_signalfuse_metrics_protobuf.MetricType_GAUGE
}

func isNilOrEmpty(str *string) bool {
	return str == nil || *str == ""
}

// NewCollectdDatapoint creates a new datapoint from collectd's write_http endpoint JSON format
func NewCollectdDatapoint(point *JSONWriteFormat, index uint) datapoint.Datapoint {
	dstype, val, dsname := point.Dstypes[index], point.Values[index], point.Dsnames[index]
	dimensions := make(map[string]string)
	metricType := metricTypeFromDsType(dstype)
	metricName, usedParts := getReasonableMetricName(point, index)
	// Don't add empty dimensions
	addIfNotNullOrEmpty(dimensions, "host", true, point.Host)
	addIfNotNullOrEmpty(dimensions, "plugin", true, point.Plugin)
	addIfNotNullOrEmpty(dimensions, "plugin_instance", true, point.PluginInstance)

	_, usedInMetricName := usedParts["type_instance"]
	addIfNotNullOrEmpty(dimensions, "type_instance", usedInMetricName, point.TypeInstance)

	_, usedInMetricName = usedParts["type"]
	addIfNotNullOrEmpty(dimensions, "type", usedInMetricName, point.TypeS)

	_, usedInMetricName = usedParts["dsname"]
	addIfNotNullOrEmpty(dimensions, "dsname", usedInMetricName, dsname)

	timestamp := time.Unix(0, int64(float64(time.Second)**point.Time))
	return datapoint.NewAbsoluteTime(metricName, dimensions, datapoint.NewFloatValue(*val), metricType, timestamp)
}

func addIfNotNullOrEmpty(dimensions map[string]string, key string, cond bool, val *string) {
	if cond && val != nil && *val != "" {
		dimensions[key] = *val
	}
}

func getReasonableMetricName(point *JSONWriteFormat, index uint) (string, map[string]struct{}) {
	parts := []string{}
	usedParts := make(map[string]struct{})
	if !isNilOrEmpty(point.TypeS) {
		parts = append(parts, *point.TypeS)
		usedParts["type"] = struct{}{}
	}
	if !isNilOrEmpty(point.TypeInstance) {
		parts = append(parts, *point.TypeInstance)
		usedParts["type_instance"] = struct{}{}
	}
	if !isNilOrEmpty(point.Dsnames[index]) && len(point.Dsnames) > 1 {
		parts = append(parts, *point.Dsnames[index])
		usedParts["dsname"] = struct{}{}
	}
	return strings.Join(parts, "."), usedParts
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"os/exec"
	"regexp"
	"strconv"
	"strings"

	mp "github.com/mackerelio/go-mackerel-plugin-helper"
	"github.com/mackerelio/mackerel-agent/logging"
)

var logger = logging.GetLogger("metrics.plugin.inode")

// InodePlugin plugin
type InodePlugin struct{}

var dfHeaderPattern = regexp.MustCompile(
	`^Filesystem\s+`,
)

var dfColumnsPattern = regexp.MustCompile(
	`^(.+?)\s+(?:(?:\d+)\s+(?:\d+)\s+(?:\d+)\s+(?:\d+%)\s+|(?:\d+)\s+)?(\d+)\s+(\d+)\s+(\d+%)\s+(.+)$`,
)

var devicePattern = regexp.MustCompile(
	`^/dev/(.*)$`,
)

var deviceUnacceptablePattern = regexp.MustCompile(
	`[^A-Za-z0-9_-]`,
)

//  $ df -i
// Filesystem      Inodes  IUsed   IFree IUse% Mounted on
// /dev/xvda1     1310720 131197 1179523   11% /
//  $ df -i # on Mac OSX (impossible to display only inode information)
// Filesystem 512-blocks      Used Available Capacity  iused    ifree %iused  Mounted on
// /dev/disk1  974737408 176727800 797497608    19% 22154973 99687201   18%   /

// FetchMetrics interface for mackerelplugin
func (p InodePlugin) FetchMetrics() (map[string]interface{}, error) {
	cmd := exec.Command("df", "-i")
	cmd.Env = append(os.Environ(), "LANG=C")
	out, err := cmd.Output()
	if err != nil {
		logger.Warningf("'df -i' command exited with a non-zero status: '%s'", err)
		return nil, err
	}
	result := make(map[string]interface{})
	for _, line := range strings.Split(string(out), "\n") {
		if dfHeaderPattern.MatchString(line) {
			continue
		} else if matches := dfColumnsPattern.FindStringSubmatch(line); matches != nil {
			name := matches[1]
			// https://github.com/docker/docker/blob/v1.5.0/daemon/graphdriver/devmapper/deviceset.go#L981
			if regexp.MustCompile(`^/dev/mapper/docker-`).FindStringSubmatch(name) != nil {
				continue
			}
			if nameMatches := devicePattern.FindStringSubmatch(name); nameMatches != nil {
				device := deviceUnacceptablePattern.ReplaceAllString(nameMatches[1], "_")
				iused, err := strconv.ParseInt(matches[2], 0, 64)
				if err != nil {
					logger.Warningf("Failed to parse value: [%s]", matches[2])
					continue
				}
				ifree, err := strconv.ParseInt(matches[3], 0, 64)
				if err != nil {
					logger.Warningf("Failed to parse value: [%s]", matches[3])
					continue
				}
				result["inode.count."+device+".used"] = uint64(iused)
				result["inode.count."+device+".free"] = uint64(ifree)
				result["inode.count."+device+".total"] = uint64(iused + ifree)
				usedPercentage := 100.0 // 100% if both iused and ifree are 0
				if iused+ifree > 0 {
					usedPercentage = float64(iused) * 100 / float64(iused+ifree)
				}
				result["inode.percentage."+device+".used"] = usedPercentage
			}
		}
	}
	return result, nil
}

// GraphDefinition interface for mackerelplugin
func (p InodePlugin) GraphDefinition() map[string]mp.Graphs {
	return map[string]mp.Graphs{
		"inode.count.#": mp.Graphs{
			Label: "Inode",
			Unit:  "integer",
			Metrics: []mp.Metrics{
				mp.Metrics{Name: "used", Label: "used"},
				mp.Metrics{Name: "free", Label: "free"},
				mp.Metrics{Name: "total", Label: "total"},
			},
		},
		"inode.percentage.#": mp.Graphs{
			Label: "Inode Percentage",
			Unit:  "percentage",
			Metrics: []mp.Metrics{
				mp.Metrics{Name: "used", Label: "used %"},
			},
		},
	}
}

func main() {
	inode := InodePlugin{}
	helper := mp.NewMackerelPlugin(inode)
	helper.Run()
}
<commit_msg>use `df -iP` in inode plugin on linux (care line break)<commit_after>package main

import (
	"os"
	"os/exec"
	"regexp"
	"runtime"
	"strconv"
	"strings"

	mp "github.com/mackerelio/go-mackerel-plugin-helper"
	"github.com/mackerelio/mackerel-agent/logging"
)

var logger = logging.GetLogger("metrics.plugin.inode")

// InodePlugin plugin
type InodePlugin struct{}

var dfHeaderPattern = regexp.MustCompile(
	`^Filesystem\s+`,
)

var dfColumnsPattern = regexp.MustCompile(
	`^(.+?)\s+(?:(?:\d+)\s+(?:\d+)\s+(?:\d+)\s+(?:\d+%)\s+|(?:\d+)\s+)?(\d+)\s+(\d+)\s+(\d+%)\s+(.+)$`,
)

var devicePattern = regexp.MustCompile(
	`^/dev/(.*)$`,
)

var deviceUnacceptablePattern = regexp.MustCompile(
	`[^A-Za-z0-9_-]`,
)

//  $ df -iP
// Filesystem      Inodes  IUsed   IFree IUse% Mounted on
// /dev/xvda1     1310720 131197 1179523   11% /
//  $ df -i # on Mac OSX (impossible to display only inode information)
// Filesystem 512-blocks      Used Available Capacity  iused    ifree %iused  Mounted on
// /dev/disk1  974737408 176727800 797497608    19% 22154973 99687201   18%   /

// FetchMetrics interface for mackerelplugin
func (p InodePlugin) FetchMetrics() (map[string]interface{}, error) {
	dfOpt := "-i"
	if runtime.GOOS == "linux" {
		dfOpt = "-iP"
	}
	cmd := exec.Command("df", dfOpt)
	cmd.Env = append(os.Environ(), "LANG=C")
	out, err := cmd.Output()
	if err != nil {
		logger.Warningf("'df -i' command exited with a non-zero status: '%s'", err)
		return nil, err
	}
	result := make(map[string]interface{})
	for _, line := range strings.Split(string(out), "\n") {
		if dfHeaderPattern.MatchString(line) {
			continue
		} else if matches := dfColumnsPattern.FindStringSubmatch(line); matches != nil {
			name := matches[1]
			// https://github.com/docker/docker/blob/v1.5.0/daemon/graphdriver/devmapper/deviceset.go#L981
			if regexp.MustCompile(`^/dev/mapper/docker-`).FindStringSubmatch(name) != nil {
				continue
			}
			if nameMatches := devicePattern.FindStringSubmatch(name); nameMatches != nil {
				device := deviceUnacceptablePattern.ReplaceAllString(nameMatches[1], "_")
				iused, err := strconv.ParseInt(matches[2], 0, 64)
				if err != nil {
					logger.Warningf("Failed to parse value: [%s]", matches[2])
					continue
				}
				ifree, err := strconv.ParseInt(matches[3], 0, 64)
				if err != nil {
					logger.Warningf("Failed to parse value: [%s]", matches[3])
					continue
				}
				result["inode.count."+device+".used"] = uint64(iused)
				result["inode.count."+device+".free"] = uint64(ifree)
				result["inode.count."+device+".total"] = uint64(iused + ifree)
				usedPercentage := 100.0 // 100% if both iused and ifree are 0
				if iused+ifree > 0 {
					usedPercentage = float64(iused) * 100 / float64(iused+ifree)
				}
				result["inode.percentage."+device+".used"] = usedPercentage
			}
		}
	}
	return result, nil
}

// GraphDefinition interface for mackerelplugin
func (p InodePlugin) GraphDefinition() map[string]mp.Graphs {
	return map[string]mp.Graphs{
		"inode.count.#": mp.Graphs{
			Label: "Inode",
			Unit:  "integer",
			Metrics: []mp.Metrics{
				mp.Metrics{Name: "used", Label: "used"},
				mp.Metrics{Name: "free", Label: "free"},
				mp.Metrics{Name: "total", Label: "total"},
			},
		},
		"inode.percentage.#": mp.Graphs{
			Label: "Inode Percentage",
			Unit:  "percentage",
			Metrics: []mp.Metrics{
				mp.Metrics{Name: "used", Label: "used %"},
			},
		},
	}
}

func main() {
	inode := InodePlugin{}
	helper := mp.NewMackerelPlugin(inode)
	helper.Run()
}
<|endoftext|>


<commit_before>package freedom

import (
	"bytes"
	"fmt"
	"net"
	"testing"

	"golang.org/x/net/proxy"

	"github.com/v2ray/v2ray-core/app"
	"github.com/v2ray/v2ray-core/app/dispatcher"
	"github.com/v2ray/v2ray-core/common/alloc"
	v2io "github.com/v2ray/v2ray-core/common/io"
	v2net "github.com/v2ray/v2ray-core/common/net"
	v2nettesting "github.com/v2ray/v2ray-core/common/net/testing"
	v2proxy "github.com/v2ray/v2ray-core/proxy"
	_ "github.com/v2ray/v2ray-core/proxy/socks"
	proxytesting "github.com/v2ray/v2ray-core/proxy/testing"
	proxymocks "github.com/v2ray/v2ray-core/proxy/testing/mocks"
	"github.com/v2ray/v2ray-core/shell/point"
	v2testing "github.com/v2ray/v2ray-core/testing"
	"github.com/v2ray/v2ray-core/testing/assert"
	"github.com/v2ray/v2ray-core/testing/servers/tcp"
	"github.com/v2ray/v2ray-core/testing/servers/udp"
)

func TestUDPSend(t *testing.T) {
	v2testing.Current(t)

	data2Send := "Data to be sent to remote"

	udpServer := &udp.Server{
		Port: 0,
		MsgProcessor: func(data []byte) []byte {
			buffer := make([]byte, 0, 2048)
			buffer = append(buffer, []byte("Processed: ")...)
			buffer = append(buffer, data...)
			return buffer
		},
	}

	udpServerAddr, err := udpServer.Start()
	assert.Error(err).IsNil()

	connOutput := bytes.NewBuffer(make([]byte, 0, 1024))
	ich := &proxymocks.InboundConnectionHandler{
		ConnInput:  bytes.NewReader([]byte("Not Used")),
		ConnOutput: connOutput,
	}

	protocol, err := proxytesting.RegisterInboundConnectionHandlerCreator("mock_ich",
		func(space app.Space, config interface{}) (v2proxy.InboundHandler, error) {
			ich.PacketDispatcher = space.GetApp(dispatcher.APP_ID).(dispatcher.PacketDispatcher)
			return ich, nil
		})
	assert.Error(err).IsNil()

	pointPort := v2nettesting.PickPort()
	config := &point.Config{
		Port: pointPort,
		InboundConfig: &point.ConnectionConfig{
			Protocol: protocol,
			Settings: nil,
		},
		OutboundConfig: &point.ConnectionConfig{
			Protocol: "freedom",
			Settings: nil,
		},
	}

	point, err := point.NewPoint(config)
	assert.Error(err).IsNil()

	err = point.Start()
	assert.Error(err).IsNil()

	data2SendBuffer := alloc.NewBuffer().Clear()
	data2SendBuffer.Append([]byte(data2Send))
	ich.Communicate(v2net.NewPacket(udpServerAddr, data2SendBuffer, false))
	assert.Bytes(connOutput.Bytes()).Equals([]byte("Processed: Data to be sent to remote"))
}

func TestSocksTcpConnect(t *testing.T) {
	v2testing.Current(t)
	port := v2nettesting.PickPort()

	data2Send := "Data to be sent to remote"

	tcpServer := &tcp.Server{
		Port: port,
		MsgProcessor: func(data []byte) []byte {
			buffer := make([]byte, 0, 2048)
			buffer = append(buffer, []byte("Processed: ")...)
			buffer = append(buffer, data...)
			return buffer
		},
	}
	_, err := tcpServer.Start()
	assert.Error(err).IsNil()

	pointPort := v2nettesting.PickPort()
	config := &point.Config{
		Port: pointPort,
		InboundConfig: &point.ConnectionConfig{
			Protocol: "socks",
			Settings: []byte(`{"auth": "noauth"}`),
		},
		OutboundConfig: &point.ConnectionConfig{
			Protocol: "freedom",
			Settings: nil,
		},
	}

	point, err := point.NewPoint(config)
	assert.Error(err).IsNil()

	err = point.Start()
	assert.Error(err).IsNil()

	socks5Client, err := proxy.SOCKS5("tcp", fmt.Sprintf("127.0.0.1:%d", pointPort), nil, proxy.Direct)
	assert.Error(err).IsNil()

	targetServer := fmt.Sprintf("127.0.0.1:%d", port)
	conn, err := socks5Client.Dial("tcp", targetServer)
	assert.Error(err).IsNil()

	conn.Write([]byte(data2Send))
	if tcpConn, ok := conn.(*net.TCPConn); ok {
		tcpConn.CloseWrite()
	}

	dataReturned, err := v2io.ReadFrom(conn, nil)
	assert.Error(err).IsNil()
	conn.Close()

	assert.Bytes(dataReturned.Value).Equals([]byte("Processed: Data to be sent to remote"))
}
<commit_msg>remove out dated test case<commit_after>package freedom

import (
	"fmt"
	"net"
	"testing"

	"golang.org/x/net/proxy"

	v2io "github.com/v2ray/v2ray-core/common/io"
	v2nettesting "github.com/v2ray/v2ray-core/common/net/testing"
	_ "github.com/v2ray/v2ray-core/proxy/socks"
	"github.com/v2ray/v2ray-core/shell/point"
	v2testing "github.com/v2ray/v2ray-core/testing"
	"github.com/v2ray/v2ray-core/testing/assert"
	"github.com/v2ray/v2ray-core/testing/servers/tcp"
)

func TestSocksTcpConnect(t *testing.T) {
	v2testing.Current(t)
	port := v2nettesting.PickPort()

	data2Send := "Data to be sent to remote"

	tcpServer := &tcp.Server{
		Port: port,
		MsgProcessor: func(data []byte) []byte {
			buffer := make([]byte, 0, 2048)
			buffer = append(buffer, []byte("Processed: ")...)
			buffer = append(buffer, data...)
			return buffer
		},
	}
	_, err := tcpServer.Start()
	assert.Error(err).IsNil()

	pointPort := v2nettesting.PickPort()
	config := &point.Config{
		Port: pointPort,
		InboundConfig: &point.ConnectionConfig{
			Protocol: "socks",
			Settings: []byte(`{"auth": "noauth"}`),
		},
		OutboundConfig: &point.ConnectionConfig{
			Protocol: "freedom",
			Settings: nil,
		},
	}

	point, err := point.NewPoint(config)
	assert.Error(err).IsNil()

	err = point.Start()
	assert.Error(err).IsNil()

	socks5Client, err := proxy.SOCKS5("tcp", fmt.Sprintf("127.0.0.1:%d", pointPort), nil, proxy.Direct)
	assert.Error(err).IsNil()

	targetServer := fmt.Sprintf("127.0.0.1:%d", port)
	conn, err := socks5Client.Dial("tcp", targetServer)
	assert.Error(err).IsNil()

	conn.Write([]byte(data2Send))
	if tcpConn, ok := conn.(*net.TCPConn); ok {
		tcpConn.CloseWrite()
	}

	dataReturned, err := v2io.ReadFrom(conn, nil)
	assert.Error(err).IsNil()
	conn.Close()

	assert.Bytes(dataReturned.Value).Equals([]byte("Processed: Data to be sent to remote"))
}
<|endoftext|>