<commit_before>package main

import (
	"errors"
	"flag"
	"fmt"
	"log"
	"log/syslog"
	"os"
	"os/exec"
	"os/signal"
	"os/user"
	"regexp"
	"strconv"
	"strings"
	"syscall"

	"github.com/spf13/viper"
)

var l = log.New(os.Stdout, "", 0)
var el = log.New(os.Stderr, "", 0)

type executor func(string, ...string) error

func lExec(s string, a ...string) error {
	return exec.Command(s, a...).Run()
}

func loadConfig(configFile string) (*viper.Viper, error) {
	config := viper.New()
	config.SetConfigFile(configFile)

	config.SetDefault("events.min", 1300)
	config.SetDefault("events.max", 1399)
	config.SetDefault("message_tracking.enabled", true)
	config.SetDefault("message_tracking.log_out_of_order", false)
	config.SetDefault("message_tracking.max_out_of_order", 500)
	config.SetDefault("output.syslog.enabled", false)
	config.SetDefault("output.syslog.priority", int(syslog.LOG_LOCAL0|syslog.LOG_WARNING))
	config.SetDefault("output.syslog.tag", "go-audit")
	config.SetDefault("output.syslog.attempts", "3")
	config.SetDefault("log.flags", 0)

	if err := config.ReadInConfig(); err != nil {
		return nil, err
	}

	l.SetFlags(config.GetInt("log.flags"))
	el.SetFlags(config.GetInt("log.flags"))

	return config, nil
}

func setRules(config *viper.Viper, e executor) error {
	// Clear existing rules
	if err := e("auditctl", "-D"); err != nil {
		return errors.New(fmt.Sprintf("Failed to flush existing audit rules. Error: %s", err))
	}

	l.Println("Flushed existing audit rules")

	// Add ours in
	if rules := config.GetStringSlice("rules"); len(rules) != 0 {
		for i, v := range rules {
			// Skip rules with no content
			if v == "" {
				continue
			}

			if err := e("auditctl", strings.Fields(v)...); err != nil {
				return errors.New(fmt.Sprintf("Failed to add rule #%d. Error: %s", i+1, err))
			}

			l.Printf("Added audit rule #%d\n", i+1)
		}
	} else {
		return errors.New("No audit rules found.")
	}

	return nil
}

func createOutput(config *viper.Viper) (*AuditWriter, error) {
	var writer *AuditWriter
	var err error
	i := 0

	if config.GetBool("output.syslog.enabled") == true {
		i++
		writer, err = createSyslogOutput(config)
		if err != nil {
			return nil, err
		}
	}

	if config.GetBool("output.file.enabled") == true {
		i++
		writer, err = createFileOutput(config)
		if err != nil {
			return nil, err
		}

		go handleLogRotation(config, writer)
	}

	if config.GetBool("output.stdout.enabled") == true {
		i++
		writer, err = createStdOutOutput(config)
		if err != nil {
			return nil, err
		}
	}

	if i > 1 {
		return nil, errors.New("Only one output can be enabled at a time")
	}

	if writer == nil {
		return nil, errors.New("No outputs were configured")
	}

	return writer, nil
}

func createSyslogOutput(config *viper.Viper) (*AuditWriter, error) {
	attempts := config.GetInt("output.syslog.attempts")
	if attempts < 1 {
		return nil, errors.New(
			fmt.Sprintf("Output attempts for syslog must be at least 1, %v provided", attempts),
		)
	}

	syslogWriter, err := syslog.Dial(
		config.GetString("output.syslog.network"),
		config.GetString("output.syslog.address"),
		syslog.Priority(config.GetInt("output.syslog.priority")),
		config.GetString("output.syslog.tag"),
	)

	if err != nil {
		return nil, errors.New(fmt.Sprintf("Failed to open syslog writer. Error: %v", err))
	}

	return NewAuditWriter(syslogWriter, attempts), nil
}

func createFileOutput(config *viper.Viper) (*AuditWriter, error) {
	attempts := config.GetInt("output.file.attempts")
	if attempts < 1 {
		return nil, errors.New(
			fmt.Sprintf("Output attempts for file must be at least 1, %v provided", attempts),
		)
	}

	mode := os.FileMode(config.GetInt("output.file.mode"))
	if mode < 1 {
		return nil, errors.New("Output file mode should be greater than 0000")
	}

	f, err := os.OpenFile(
		config.GetString("output.file.path"),
		os.O_APPEND|os.O_CREATE|os.O_WRONLY, mode,
	)

	if err != nil {
		return nil, errors.New(fmt.Sprintf("Failed to open output file. Error: %s", err))
	}

	if err := f.Chmod(mode); err != nil {
		return nil, errors.New(fmt.Sprintf("Failed to set file permissions. Error: %s", err))
	}

	uname := config.GetString("output.file.user")
	u, err := user.Lookup(uname)
	if err != nil {
		return nil, errors.New(fmt.Sprintf("Could not find uid for user %s. Error: %s", uname, err))
	}

	gname := config.GetString("output.file.group")
	g, err := user.LookupGroup(gname)
	if err != nil {
		return nil, errors.New(fmt.Sprintf("Could not find gid for group %s. Error: %s", gname, err))
	}

	uid, err := strconv.ParseInt(u.Uid, 10, 32)
	if err != nil {
		return nil, errors.New(fmt.Sprintf("Found uid could not be parsed. Error: %s", err))
	}

	gid, err := strconv.ParseInt(g.Gid, 10, 32)
	if err != nil {
		return nil, errors.New(fmt.Sprintf("Found gid could not be parsed. Error: %s", err))
	}

	if err = f.Chown(int(uid), int(gid)); err != nil {
		return nil, errors.New(fmt.Sprintf("Could not chown output file. Error: %s", err))
	}

	return NewAuditWriter(f, attempts), nil
}

func handleLogRotation(config *viper.Viper, writer *AuditWriter) {
	// Re-open our log file. This is triggered by a USR1 signal and is meant to be used upon log rotation

	sigc := make(chan os.Signal, 1)
	signal.Notify(sigc, syscall.SIGUSR1)

	for _ = range sigc {
		newWriter, err := createFileOutput(config)
		if err != nil {
			el.Fatalln("Error re-opening log file. Exiting.")
		}

		oldFile := writer.w.(*os.File)
		writer.w = newWriter.w
		writer.e = newWriter.e

		err = oldFile.Close()
		if err != nil {
			el.Printf("Error closing old log file: %+v\n", err)
		}
	}
}

func createStdOutOutput(config *viper.Viper) (*AuditWriter, error) {
	attempts := config.GetInt("output.stdout.attempts")
	if attempts < 1 {
		return nil, errors.New(
			fmt.Sprintf("Output attempts for stdout must be at least 1, %v provided", attempts),
		)
	}

	// l logger is no longer stdout
	l.SetOutput(os.Stderr)

	return NewAuditWriter(os.Stdout, attempts), nil
}

func createFilters(config *viper.Viper) []AuditFilter {
	var err error
	var ok bool

	fs := config.Get("filters")
	filters := []AuditFilter{}

	if fs == nil {
		return filters
	}

	ft, ok := fs.([]interface{})
	if !ok {
		return filters
	}

	for i, f := range ft {
		f2, ok := f.(map[interface{}]interface{})
		if !ok {
			el.Fatal("Could not parse filter ", i+1, f)
		}

		af := AuditFilter{}
		for k, v := range f2 {
			switch k {
			case "message_type":
				if ev, ok := v.(string); ok {
					fv, err := strconv.ParseUint(ev, 10, 64)
					if err != nil {
						el.Fatal("`message_type` in filter ", i+1, " could not be parsed ", v, " ", err)
					}
					af.messageType = uint16(fv)

				} else if ev, ok := v.(int); ok {
					if !ok {
						el.Fatal("`message_type` in filter ", i+1, " could not be parsed ", v)
					}
					af.messageType = uint16(ev)

				} else {
					el.Fatal("`message_type` in filter ", i+1, " could not be parsed ", v)
				}

			case "regex":
				re, ok := v.(string)
				if !ok {
					el.Fatal("`regex` in filter ", i+1, " could not be parsed ", v)
				}

				if af.regex, err = regexp.Compile(re); err != nil {
					el.Fatal("`regex` in filter ", i+1, " could not be parsed ", v, " ", err)
				}

			case "syscall":
				if af.syscall, ok = v.(string); ok {
					// All is good
				} else if ev, ok := v.(int); ok {
					af.syscall = strconv.Itoa(ev)
				} else {
					el.Fatal("`syscall` in filter ", i+1, " could not be parsed ", v)
				}
			}
		}

		filters = append(filters, af)
		l.Printf("Ignoring  syscall `%v` containing message type `%v` matching string `%s`\n", af.syscall, af.messageType, af.regex.String())
	}

	return filters
}

func main() {
	configFile := flag.String("config", "", "Config file location")

	flag.Parse()

	if *configFile == "" {
		el.Println("A config file must be provided")
		flag.Usage()
		os.Exit(1)
	}

	config, err := loadConfig(*configFile)
	if err != nil {
		el.Fatal(err)
	}

	// output needs to be created before anything that write to stdout
	writer, err := createOutput(config)
	if err != nil {
		el.Fatal(err)
	}

	if err := setRules(config, lExec); err != nil {
		el.Fatal(err)
	}

	nlClient := NewNetlinkClient(config.GetInt("socket_buffer.receive"))
	marshaller := NewAuditMarshaller(
		writer,
		uint16(config.GetInt("events.min")),
		uint16(config.GetInt("events.max")),
		config.GetBool("message_tracking.enabled"),
		config.GetBool("message_tracking.log_out_of_order"),
		config.GetInt("message_tracking.max_out_of_order"),
		createFilters(config),
	)

	l.Printf("Started processing events in the range [%d, %d]\n", config.GetInt("events.min"), config.GetInt("events.max"))

	//Main loop. Get data from netlink and send it to the json lib for processing
	for {
		msg, err := nlClient.Receive()
		if err != nil {
			el.Printf("Error during message receive: %+v\n", err)
			continue
		}

		if msg == nil {
			continue
		}

		marshaller.Consume(msg)
	}
}
<commit_msg>golint Errorf<commit_after>package main

import (
	"errors"
	"flag"
	"fmt"
	"log"
	"log/syslog"
	"os"
	"os/exec"
	"os/signal"
	"os/user"
	"regexp"
	"strconv"
	"strings"
	"syscall"

	"github.com/spf13/viper"
)

var l = log.New(os.Stdout, "", 0)
var el = log.New(os.Stderr, "", 0)

type executor func(string, ...string) error

func lExec(s string, a ...string) error {
	return exec.Command(s, a...).Run()
}

func loadConfig(configFile string) (*viper.Viper, error) {
	config := viper.New()
	config.SetConfigFile(configFile)

	config.SetDefault("events.min", 1300)
	config.SetDefault("events.max", 1399)
	config.SetDefault("message_tracking.enabled", true)
	config.SetDefault("message_tracking.log_out_of_order", false)
	config.SetDefault("message_tracking.max_out_of_order", 500)
	config.SetDefault("output.syslog.enabled", false)
	config.SetDefault("output.syslog.priority", int(syslog.LOG_LOCAL0|syslog.LOG_WARNING))
	config.SetDefault("output.syslog.tag", "go-audit")
	config.SetDefault("output.syslog.attempts", "3")
	config.SetDefault("log.flags", 0)

	if err := config.ReadInConfig(); err != nil {
		return nil, err
	}

	l.SetFlags(config.GetInt("log.flags"))
	el.SetFlags(config.GetInt("log.flags"))

	return config, nil
}

func setRules(config *viper.Viper, e executor) error {
	// Clear existing rules
	if err := e("auditctl", "-D"); err != nil {
		return fmt.Errorf("Failed to flush existing audit rules. Error: %s", err)
	}

	l.Println("Flushed existing audit rules")

	// Add ours in
	if rules := config.GetStringSlice("rules"); len(rules) != 0 {
		for i, v := range rules {
			// Skip rules with no content
			if v == "" {
				continue
			}

			if err := e("auditctl", strings.Fields(v)...); err != nil {
				return fmt.Errorf("Failed to add rule #%d. Error: %s", i+1, err)
			}

			l.Printf("Added audit rule #%d\n", i+1)
		}
	} else {
		return errors.New("No audit rules found.")
	}

	return nil
}

func createOutput(config *viper.Viper) (*AuditWriter, error) {
	var writer *AuditWriter
	var err error
	i := 0

	if config.GetBool("output.syslog.enabled") == true {
		i++
		writer, err = createSyslogOutput(config)
		if err != nil {
			return nil, err
		}
	}

	if config.GetBool("output.file.enabled") == true {
		i++
		writer, err = createFileOutput(config)
		if err != nil {
			return nil, err
		}

		go handleLogRotation(config, writer)
	}

	if config.GetBool("output.stdout.enabled") == true {
		i++
		writer, err = createStdOutOutput(config)
		if err != nil {
			return nil, err
		}
	}

	if i > 1 {
		return nil, errors.New("Only one output can be enabled at a time")
	}

	if writer == nil {
		return nil, errors.New("No outputs were configured")
	}

	return writer, nil
}

func createSyslogOutput(config *viper.Viper) (*AuditWriter, error) {
	attempts := config.GetInt("output.syslog.attempts")
	if attempts < 1 {
		return nil, fmt.Errorf("Output attempts for syslog must be at least 1, %v provided", attempts)
	}

	syslogWriter, err := syslog.Dial(
		config.GetString("output.syslog.network"),
		config.GetString("output.syslog.address"),
		syslog.Priority(config.GetInt("output.syslog.priority")),
		config.GetString("output.syslog.tag"),
	)

	if err != nil {
		return nil, fmt.Errorf("Failed to open syslog writer. Error: %v", err)
	}

	return NewAuditWriter(syslogWriter, attempts), nil
}

func createFileOutput(config *viper.Viper) (*AuditWriter, error) {
	attempts := config.GetInt("output.file.attempts")
	if attempts < 1 {
		return nil, fmt.Errorf("Output attempts for file must be at least 1, %v provided", attempts)
	}

	mode := os.FileMode(config.GetInt("output.file.mode"))
	if mode < 1 {
		return nil, errors.New("Output file mode should be greater than 0000")
	}

	f, err := os.OpenFile(
		config.GetString("output.file.path"),
		os.O_APPEND|os.O_CREATE|os.O_WRONLY, mode,
	)

	if err != nil {
		return nil, fmt.Errorf("Failed to open output file. Error: %s", err)
	}

	if err := f.Chmod(mode); err != nil {
		return nil, fmt.Errorf("Failed to set file permissions. Error: %s", err)
	}

	uname := config.GetString("output.file.user")
	u, err := user.Lookup(uname)
	if err != nil {
		return nil, fmt.Errorf("Could not find uid for user %s. Error: %s", uname, err)
	}

	gname := config.GetString("output.file.group")
	g, err := user.LookupGroup(gname)
	if err != nil {
		return nil, fmt.Errorf("Could not find gid for group %s. Error: %s", gname, err)
	}

	uid, err := strconv.ParseInt(u.Uid, 10, 32)
	if err != nil {
		return nil, fmt.Errorf("Found uid could not be parsed. Error: %s", err)
	}

	gid, err := strconv.ParseInt(g.Gid, 10, 32)
	if err != nil {
		return nil, fmt.Errorf("Found gid could not be parsed. Error: %s", err)
	}

	if err = f.Chown(int(uid), int(gid)); err != nil {
		return nil, fmt.Errorf("Could not chown output file. Error: %s", err)
	}

	return NewAuditWriter(f, attempts), nil
}

func handleLogRotation(config *viper.Viper, writer *AuditWriter) {
	// Re-open our log file. This is triggered by a USR1 signal and is meant to be used upon log rotation

	sigc := make(chan os.Signal, 1)
	signal.Notify(sigc, syscall.SIGUSR1)

	for _ = range sigc {
		newWriter, err := createFileOutput(config)
		if err != nil {
			el.Fatalln("Error re-opening log file. Exiting.")
		}

		oldFile := writer.w.(*os.File)
		writer.w = newWriter.w
		writer.e = newWriter.e

		err = oldFile.Close()
		if err != nil {
			el.Printf("Error closing old log file: %+v\n", err)
		}
	}
}

func createStdOutOutput(config *viper.Viper) (*AuditWriter, error) {
	attempts := config.GetInt("output.stdout.attempts")
	if attempts < 1 {
		return nil, fmt.Errorf("Output attempts for stdout must be at least 1, %v provided", attempts)
	}

	// l logger is no longer stdout
	l.SetOutput(os.Stderr)

	return NewAuditWriter(os.Stdout, attempts), nil
}

func createFilters(config *viper.Viper) []AuditFilter {
	var err error
	var ok bool

	fs := config.Get("filters")
	filters := []AuditFilter{}

	if fs == nil {
		return filters
	}

	ft, ok := fs.([]interface{})
	if !ok {
		return filters
	}

	for i, f := range ft {
		f2, ok := f.(map[interface{}]interface{})
		if !ok {
			el.Fatal("Could not parse filter ", i+1, f)
		}

		af := AuditFilter{}
		for k, v := range f2 {
			switch k {
			case "message_type":
				if ev, ok := v.(string); ok {
					fv, err := strconv.ParseUint(ev, 10, 64)
					if err != nil {
						el.Fatal("`message_type` in filter ", i+1, " could not be parsed ", v, " ", err)
					}
					af.messageType = uint16(fv)

				} else if ev, ok := v.(int); ok {
					if !ok {
						el.Fatal("`message_type` in filter ", i+1, " could not be parsed ", v)
					}
					af.messageType = uint16(ev)

				} else {
					el.Fatal("`message_type` in filter ", i+1, " could not be parsed ", v)
				}

			case "regex":
				re, ok := v.(string)
				if !ok {
					el.Fatal("`regex` in filter ", i+1, " could not be parsed ", v)
				}

				if af.regex, err = regexp.Compile(re); err != nil {
					el.Fatal("`regex` in filter ", i+1, " could not be parsed ", v, " ", err)
				}

			case "syscall":
				if af.syscall, ok = v.(string); ok {
					// All is good
				} else if ev, ok := v.(int); ok {
					af.syscall = strconv.Itoa(ev)
				} else {
					el.Fatal("`syscall` in filter ", i+1, " could not be parsed ", v)
				}
			}
		}

		filters = append(filters, af)
		l.Printf("Ignoring  syscall `%v` containing message type `%v` matching string `%s`\n", af.syscall, af.messageType, af.regex.String())
	}

	return filters
}

func main() {
	configFile := flag.String("config", "", "Config file location")

	flag.Parse()

	if *configFile == "" {
		el.Println("A config file must be provided")
		flag.Usage()
		os.Exit(1)
	}

	config, err := loadConfig(*configFile)
	if err != nil {
		el.Fatal(err)
	}

	// output needs to be created before anything that write to stdout
	writer, err := createOutput(config)
	if err != nil {
		el.Fatal(err)
	}

	if err := setRules(config, lExec); err != nil {
		el.Fatal(err)
	}

	nlClient := NewNetlinkClient(config.GetInt("socket_buffer.receive"))
	marshaller := NewAuditMarshaller(
		writer,
		uint16(config.GetInt("events.min")),
		uint16(config.GetInt("events.max")),
		config.GetBool("message_tracking.enabled"),
		config.GetBool("message_tracking.log_out_of_order"),
		config.GetInt("message_tracking.max_out_of_order"),
		createFilters(config),
	)

	l.Printf("Started processing events in the range [%d, %d]\n", config.GetInt("events.min"), config.GetInt("events.max"))

	//Main loop. Get data from netlink and send it to the json lib for processing
	for {
		msg, err := nlClient.Receive()
		if err != nil {
			el.Printf("Error during message receive: %+v\n", err)
			continue
		}

		if msg == nil {
			continue
		}

		marshaller.Consume(msg)
	}
}
<|endoftext|>


<commit_before>package auth

import (
	"fmt"
	"strings"

	"github.com/codegangsta/cli"
	"github.com/jrperritt/rack/util"
	"github.com/rackspace/gophercloud"
	"github.com/rackspace/gophercloud/rackspace"
)

// reauthFunc is what the ServiceClient uses to re-authenticate.
func reauthFunc(pc *gophercloud.ProviderClient, ao gophercloud.AuthOptions) func() error {
	return func() error {
		return rackspace.AuthenticateV2(pc, ao)
	}
}

// NewClient creates and returns a Rackspace client for the given service.
func NewClient(c *cli.Context, t string) (*gophercloud.ServiceClient, error) {
	// get the user's authentication credentials
	ao, region := Credentials(c)
	// upper-case the region
	region = strings.ToUpper(region)
	// allow Gophercloud to re-authenticate
	ao.AllowReauth = true
	// if the user didn't provide an auth URL, default to the Rackspace US endpoint
	if ao.IdentityEndpoint == "" {
		ao.IdentityEndpoint = rackspace.RackspaceUSIdentity
	}

	// form the cache key
	cacheKey := CacheKey(ao, region, t)
	// initialize cache
	cache := &Cache{}
	// get the value from the cache
	creds, err := cache.Value(cacheKey)
	// if there was an error accessing the cache or there was nothing in the cache,
	// authenticate from scratch
	if err == nil && creds != nil {
		// we successfully retrieved a value from the cache
		pc, err := rackspace.NewClient(ao.IdentityEndpoint)
		if err == nil {
			pc.TokenID = creds.TokenID
			pc.ReauthFunc = reauthFunc(pc, ao)
			pc.UserAgent.Prepend("rack/" + util.Version)
			return &gophercloud.ServiceClient{
				ProviderClient: pc,
				Endpoint:       creds.ServiceEndpoint,
			}, nil
		}
	} else {
		pc, err := rackspace.AuthenticatedClient(ao)
		if err != nil {
			return nil, fmt.Errorf("Error creating ProviderClient: %s\n", err)
		}
		var sc *gophercloud.ServiceClient
		switch t {
		case "compute":
			sc, err = rackspace.NewComputeV2(pc, gophercloud.EndpointOpts{
				Region: region,
			})
			break
		case "blockstorage":
			sc, err = rackspace.NewBlockStorageV1(pc, gophercloud.EndpointOpts{
				Region: region,
			})
			break
		case "networking":
			sc, err = rackspace.NewNetworkV2(pc, gophercloud.EndpointOpts{
				Region: region,
			})
			break
		}
		if err != nil {
			return nil, fmt.Errorf("Error creating ServiceClient: %s\n", err)
		}
		if sc == nil {
			return nil, fmt.Errorf("Unable to create service client: Unknown service type: %s", t)
		}
		sc.UserAgent.Prepend("rack/" + util.Version)
		return sc, nil
	}

	return nil, nil
}

// Credentials determines the appropriate authentication method for the user.
// It returns a gophercloud.AuthOptions object and a region.
//
// It will use command-line authentication parameters if available, then it will
// look for any unset parameters in the config file, and then finally in
// environment variables.
func Credentials(c *cli.Context) (gophercloud.AuthOptions, string) {
	have := make(map[string]string)
	need := map[string]string{
		"username": "",
		"apikey":   "",
		"authurl":  "",
		"region":   "",
	}

	// use command-line options if available
	cliopts(c, have, need)
	// are there any unset auth variables?
	if len(need) != 0 {
		// if so, look in config file
		configfile(c, have, need)
		// still unset auth variables?
		if len(need) != 0 {
			// if so, look in environment variables
			envvars(have, need)
		}
	}

	ao := gophercloud.AuthOptions{
		Username:         have["username"],
		APIKey:           have["apikey"],
		IdentityEndpoint: have["authurl"],
	}
	return ao, have["region"]
}
<commit_msg>rename var: t -> serviceType<commit_after>package auth

import (
	"fmt"
	"strings"

	"github.com/codegangsta/cli"
	"github.com/jrperritt/rack/util"
	"github.com/rackspace/gophercloud"
	"github.com/rackspace/gophercloud/rackspace"
)

// reauthFunc is what the ServiceClient uses to re-authenticate.
func reauthFunc(pc *gophercloud.ProviderClient, ao gophercloud.AuthOptions) func() error {
	return func() error {
		return rackspace.AuthenticateV2(pc, ao)
	}
}

// NewClient creates and returns a Rackspace client for the given service.
func NewClient(c *cli.Context, serviceType string) (*gophercloud.ServiceClient, error) {
	// get the user's authentication credentials
	ao, region := Credentials(c)
	// upper-case the region
	region = strings.ToUpper(region)
	// allow Gophercloud to re-authenticate
	ao.AllowReauth = true
	// if the user didn't provide an auth URL, default to the Rackspace US endpoint
	if ao.IdentityEndpoint == "" {
		ao.IdentityEndpoint = rackspace.RackspaceUSIdentity
	}

	// form the cache key
	cacheKey := CacheKey(ao, region, serviceType)
	// initialize cache
	cache := &Cache{}
	// get the value from the cache
	creds, err := cache.Value(cacheKey)
	// if there was an error accessing the cache or there was nothing in the cache,
	// authenticate from scratch
	if err == nil && creds != nil {
		// we successfully retrieved a value from the cache
		pc, err := rackspace.NewClient(ao.IdentityEndpoint)
		if err == nil {
			pc.TokenID = creds.TokenID
			pc.ReauthFunc = reauthFunc(pc, ao)
			pc.UserAgent.Prepend("rack/" + util.Version)
			return &gophercloud.ServiceClient{
				ProviderClient: pc,
				Endpoint:       creds.ServiceEndpoint,
			}, nil
		}
	} else {
		pc, err := rackspace.AuthenticatedClient(ao)
		if err != nil {
			return nil, fmt.Errorf("Error creating ProviderClient: %s\n", err)
		}
		var sc *gophercloud.ServiceClient
		switch serviceType {
		case "compute":
			sc, err = rackspace.NewComputeV2(pc, gophercloud.EndpointOpts{
				Region: region,
			})
			break
		case "blockstorage":
			sc, err = rackspace.NewBlockStorageV1(pc, gophercloud.EndpointOpts{
				Region: region,
			})
			break
		case "networking":
			sc, err = rackspace.NewNetworkV2(pc, gophercloud.EndpointOpts{
				Region: region,
			})
			break
		}
		if err != nil {
			return nil, fmt.Errorf("Error creating ServiceClient: %s\n", err)
		}
		if sc == nil {
			return nil, fmt.Errorf("Unable to create service client: Unknown service type: %s", serviceType)
		}
		sc.UserAgent.Prepend("rack/" + util.Version)
		return sc, nil
	}

	return nil, nil
}

// Credentials determines the appropriate authentication method for the user.
// It returns a gophercloud.AuthOptions object and a region.
//
// It will use command-line authentication parameters if available, then it will
// look for any unset parameters in the config file, and then finally in
// environment variables.
func Credentials(c *cli.Context) (gophercloud.AuthOptions, string) {
	have := make(map[string]string)
	need := map[string]string{
		"username": "",
		"apikey":   "",
		"authurl":  "",
		"region":   "",
	}

	// use command-line options if available
	cliopts(c, have, need)
	// are there any unset auth variables?
	if len(need) != 0 {
		// if so, look in config file
		configfile(c, have, need)
		// still unset auth variables?
		if len(need) != 0 {
			// if so, look in environment variables
			envvars(have, need)
		}
	}

	ao := gophercloud.AuthOptions{
		Username:         have["username"],
		APIKey:           have["apikey"],
		IdentityEndpoint: have["authurl"],
	}
	return ao, have["region"]
}
<|endoftext|>


<commit_before>package auth

import (
	"encoding/base64"
	"fmt"
	"time"

	"github.com/synapse-garden/sg-proto/store"

	"github.com/boltdb/bolt"
	"github.com/pkg/errors"
	uuid "github.com/satori/go.uuid"
)

type TokenType int

const (
	BearerType TokenType = iota
	AdminType
	RefreshType

	Expiration = 5 * time.Minute
)

func (t TokenType) String() string {
	return tokenNames[t]
}

func ValidType(t string) bool {
	return tokenTypes[t]
}

var (
	SessionBucket = store.Bucket("sessions")
	RefreshBucket = store.Bucket("refresh")

	tokenNames = map[TokenType]string{
		BearerType:  "Bearer",
		RefreshType: "Refresh",
		AdminType:   "Admin",
	}

	tokenTypes = map[string]bool{
		"Bearer":  true,
		"Refresh": true,
		"Admin":   true,
	}
)

type Token []byte

func (t Token) String() string {
	return base64.StdEncoding.EncodeToString([]byte(t))
}

type ErrMissingSession []byte

func (e ErrMissingSession) Error() string {
	return fmt.Sprintf("no such session %#q", string(e))
}

type ErrTokenExpired []byte

func (e ErrTokenExpired) Error() string {
	return fmt.Sprintf("session %#q expired", string(e))
}

// Session is a client login session.
type Session struct {
	Token        Token         `json:"token"`
	ExpiresIn    time.Duration `json:"expiresIn"`
	Expiration   time.Time     `json:"expiresAt,omitempty"`
	TokenType    TokenType     `json:"tokenType"`
	RefreshToken Token         `json:"refreshToken"`
}

func DecodeToken(tStr string) (Token, error) {
	tBytes, err := base64.StdEncoding.DecodeString(tStr)
	if err != nil {
		return nil, errors.Wrapf(err, "invalid token %#q", tStr)
	}
	return Token(tBytes), nil
}

func NewToken(t TokenType) Token {
	switch t {
	case BearerType:
		return uuid.NewV4().Bytes()
	case RefreshType:
		return uuid.NewV4().Bytes()
	}

	return nil
}

func RefreshIfValid(
	s *Session,
	expires time.Time,
	validFor time.Duration,
) func(*bolt.Tx) error {
	return func(tx *bolt.Tx) error {
		err := store.CheckExists(
			RefreshBucket,
			s.RefreshToken,
		)(tx)
		switch {
		case store.IsMissing(err):
			return ErrMissingSession(s.RefreshToken)
		case err != nil:
			return err
		}
		return Refresh(s, expires, validFor)(tx)
	}
}

func Refresh(
	s *Session,
	expires time.Time,
	validFor time.Duration,
) func(*bolt.Tx) error {
	return func(tx *bolt.Tx) (err error) {
		var (
			oldExpiresIn  = s.ExpiresIn
			oldExpiration = s.Expiration
		)
		s.Expiration = expires
		s.ExpiresIn = validFor

		defer func() {
			if err != nil {
				s.ExpiresIn = oldExpiresIn
				s.Expiration = oldExpiration
			}
		}()

		return store.Marshal(SessionBucket, s, s.Token)(tx)
	}
}

func CheckRefresh(t Token) func(*bolt.Tx) error {
	return store.CheckExists(RefreshBucket, t)
}

// CheckToken attempts to load the given Token's Session from the
// Sessions bucket.  If it was missing, it returns ErrMissingSession.
// If it was expired, it returns ErrTokenExpired.  This functionality
// should be used to branch logic into a RefreshIfValid.  The REST API
// user should not be trusted with the knowledge that a given token ever
// existed.  From the REST API user's point of view, an expired session
// with an invalid refresh token simply does not exist.
func CheckToken(t Token) func(*bolt.Tx) error {
	return func(tx *bolt.Tx) error {
		var (
			now      = time.Now().UTC()
			existent = new(Session)
		)
		err := store.Unmarshal(SessionBucket, existent, t)(tx)

		switch {
		case store.IsMissing(err):
			// The session was not found.
			return ErrMissingSession(t)
		case err != nil:
			// There was an unknown error.
			return err
		case existent.Expiration.Before(now):
			// The token has already expired.
			return ErrTokenExpired(t)
		}

		return nil
	}
}

// NewSession prepares and assigns values to the given Session, and
// stores them in the database, or returns any error.
func NewSession(
	s *Session,
	expiration time.Time,
	validFor time.Duration,
	token, refresh Token,
	userID string,
) func(*bolt.Tx) error {
	return func(tx *bolt.Tx) (err error) {
		var (
			kind = BearerType

			oldToken, oldRefresh = s.Token, s.RefreshToken
			oldExpiration        = s.Expiration
			oldExpiresAt         = s.ExpiresIn
			oldType              = s.TokenType
		)

		s.Token, s.RefreshToken = token, refresh
		s.TokenType = kind
		s.Expiration, s.ExpiresIn = expiration, validFor

		defer func() {
			if err != nil {
				s.Token = oldToken
				s.RefreshToken = oldRefresh
				s.Expiration = oldExpiration
				s.ExpiresIn = oldExpiresAt
				s.TokenType = oldType
			}
		}()

		err = store.Marshal(SessionBucket, s, s.Token)(tx)
		if err != nil {
			return
		}

		err = SaveContext(&Context{
			Token:        s.Token,
			RefreshToken: s.RefreshToken,
			UserID:       userID,
		})(tx)
		if err != nil {
			return
		}

		return store.Put(RefreshBucket, s.RefreshToken, nil)(tx)
	}
}

func DeleteToken(t Token) func(*bolt.Tx) error {
	return func(tx *bolt.Tx) error {
		err := store.Delete(SessionBucket, t)(tx)
		if store.IsMissing(err) {
			return ErrMissingSession(t)
		}

		return err
	}
}

func DeleteSession(s *Session) func(*bolt.Tx) error {
	return func(tx *bolt.Tx) error {
		err := store.Delete(SessionBucket, s.Token)(tx)
		if err != nil && !store.IsMissing(err) {
			return err
		}

		err = store.Delete(RefreshBucket, s.RefreshToken)(tx)
		if err != nil && !store.IsMissing(err) {
			return err
		}
		return nil
	}
}

// ClearSessions is a Mutation which deletes and re-creates the Sessions
// Bucket.
func ClearSessions(tx *bolt.Tx) error {
	if err := tx.DeleteBucket(SessionBucket); err != nil {
		return err
	}
	_, err := tx.CreateBucket(SessionBucket)
	return err
}
<commit_msg>Add auth.ErrInvalidTokenType<commit_after>package auth

import (
	"encoding/base64"
	"fmt"
	"time"

	"github.com/synapse-garden/sg-proto/store"

	"github.com/boltdb/bolt"
	"github.com/pkg/errors"
	uuid "github.com/satori/go.uuid"
)

type TokenType int

const (
	BearerType TokenType = iota
	AdminType
	RefreshType

	Expiration = 5 * time.Minute
)

func (t TokenType) String() string {
	return tokenNames[t]
}

func ValidType(t string) bool {
	return tokenTypes[t]
}

var (
	SessionBucket = store.Bucket("sessions")
	RefreshBucket = store.Bucket("refresh")

	tokenNames = map[TokenType]string{
		BearerType:  "Bearer",
		RefreshType: "Refresh",
		AdminType:   "Admin",
	}

	tokenTypes = map[string]bool{
		"Bearer":  true,
		"Refresh": true,
		"Admin":   true,
	}
)

type Token []byte

func (t Token) String() string {
	return base64.StdEncoding.EncodeToString([]byte(t))
}

type ErrInvalidTokenType string

func (e ErrInvalidTokenType) Error() string {
	return fmt.Sprintf("invalid token type %q", string(e))
}

type ErrMissingSession []byte

func (e ErrMissingSession) Error() string {
	return fmt.Sprintf("no such session %#q", string(e))
}

type ErrTokenExpired []byte

func (e ErrTokenExpired) Error() string {
	return fmt.Sprintf("session %#q expired", string(e))
}

// Session is a client login session.
type Session struct {
	Token        Token         `json:"token"`
	ExpiresIn    time.Duration `json:"expiresIn"`
	Expiration   time.Time     `json:"expiresAt,omitempty"`
	TokenType    TokenType     `json:"tokenType"`
	RefreshToken Token         `json:"refreshToken"`
}

func DecodeToken(tStr string) (Token, error) {
	tBytes, err := base64.StdEncoding.DecodeString(tStr)
	if err != nil {
		return nil, errors.Wrapf(err, "invalid token %#q", tStr)
	}
	return Token(tBytes), nil
}

func NewToken(t TokenType) Token {
	switch t {
	case BearerType:
		return uuid.NewV4().Bytes()
	case RefreshType:
		return uuid.NewV4().Bytes()
	}

	return nil
}

func RefreshIfValid(
	s *Session,
	expires time.Time,
	validFor time.Duration,
) func(*bolt.Tx) error {
	return func(tx *bolt.Tx) error {
		err := store.CheckExists(
			RefreshBucket,
			s.RefreshToken,
		)(tx)
		switch {
		case store.IsMissing(err):
			return ErrMissingSession(s.RefreshToken)
		case err != nil:
			return err
		}
		return Refresh(s, expires, validFor)(tx)
	}
}

func Refresh(
	s *Session,
	expires time.Time,
	validFor time.Duration,
) func(*bolt.Tx) error {
	return func(tx *bolt.Tx) (err error) {
		var (
			oldExpiresIn  = s.ExpiresIn
			oldExpiration = s.Expiration
		)
		s.Expiration = expires
		s.ExpiresIn = validFor

		defer func() {
			if err != nil {
				s.ExpiresIn = oldExpiresIn
				s.Expiration = oldExpiration
			}
		}()

		return store.Marshal(SessionBucket, s, s.Token)(tx)
	}
}

func CheckRefresh(t Token) func(*bolt.Tx) error {
	return store.CheckExists(RefreshBucket, t)
}

// CheckToken attempts to load the given Token's Session from the
// Sessions bucket.  If it was missing, it returns ErrMissingSession.
// If it was expired, it returns ErrTokenExpired.  This functionality
// should be used to branch logic into a RefreshIfValid.  The REST API
// user should not be trusted with the knowledge that a given token ever
// existed.  From the REST API user's point of view, an expired session
// with an invalid refresh token simply does not exist.
func CheckToken(t Token) func(*bolt.Tx) error {
	return func(tx *bolt.Tx) error {
		var (
			now      = time.Now().UTC()
			existent = new(Session)
		)
		err := store.Unmarshal(SessionBucket, existent, t)(tx)

		switch {
		case store.IsMissing(err):
			// The session was not found.
			return ErrMissingSession(t)
		case err != nil:
			// There was an unknown error.
			return err
		case existent.Expiration.Before(now):
			// The token has already expired.
			return ErrTokenExpired(t)
		}

		return nil
	}
}

// NewSession prepares and assigns values to the given Session, and
// stores them in the database, or returns any error.
func NewSession(
	s *Session,
	expiration time.Time,
	validFor time.Duration,
	token, refresh Token,
	userID string,
) func(*bolt.Tx) error {
	return func(tx *bolt.Tx) (err error) {
		var (
			kind = BearerType

			oldToken, oldRefresh = s.Token, s.RefreshToken
			oldExpiration        = s.Expiration
			oldExpiresAt         = s.ExpiresIn
			oldType              = s.TokenType
		)

		s.Token, s.RefreshToken = token, refresh
		s.TokenType = kind
		s.Expiration, s.ExpiresIn = expiration, validFor

		defer func() {
			if err != nil {
				s.Token = oldToken
				s.RefreshToken = oldRefresh
				s.Expiration = oldExpiration
				s.ExpiresIn = oldExpiresAt
				s.TokenType = oldType
			}
		}()

		err = store.Marshal(SessionBucket, s, s.Token)(tx)
		if err != nil {
			return
		}

		err = SaveContext(&Context{
			Token:        s.Token,
			RefreshToken: s.RefreshToken,
			UserID:       userID,
		})(tx)
		if err != nil {
			return
		}

		return store.Put(RefreshBucket, s.RefreshToken, nil)(tx)
	}
}

func DeleteToken(t Token) func(*bolt.Tx) error {
	return func(tx *bolt.Tx) error {
		err := store.Delete(SessionBucket, t)(tx)
		if store.IsMissing(err) {
			return ErrMissingSession(t)
		}

		return err
	}
}

func DeleteSession(s *Session) func(*bolt.Tx) error {
	return func(tx *bolt.Tx) error {
		err := store.Delete(SessionBucket, s.Token)(tx)
		if err != nil && !store.IsMissing(err) {
			return err
		}

		err = store.Delete(RefreshBucket, s.RefreshToken)(tx)
		if err != nil && !store.IsMissing(err) {
			return err
		}
		return nil
	}
}

// ClearSessions is a Mutation which deletes and re-creates the Sessions
// Bucket.
func ClearSessions(tx *bolt.Tx) error {
	if err := tx.DeleteBucket(SessionBucket); err != nil {
		return err
	}
	_, err := tx.CreateBucket(SessionBucket)
	return err
}
<|endoftext|>


<commit_before>package tunneling

import (
	"errors"
	"fmt"
	"os"
	"strconv"
	"sync"

	"github.com/pion/webrtc/v2"
)

const (
	// defaultWebRTCMinimumPort is the default minimum port used for WebRTC UDP
	// listeners. It can be overridden using the MUTAGEN_TUNNEL_UDP_PORT_MINIMUM
	// environment variable.
	defaultWebRTCMinimumPort = 62800
	// defaultWebRTCMaximumPort is the default maximum port used for WebRTC UDP
	// listeners. It can be overridden using the MUTAGEN_TUNNEL_UDP_PORT_MAXIMUM
	// environment variable.
	defaultWebRTCMaximumPort = 62900
)

// webrtcAPIOnce restricts the global WebRTC API to a single initialization.
var webrtcAPIOnce sync.Once

// webrtcAPI is a shared global WebRTC API for tunnels, preconfigured to enable
// data channel stream detaching. It is lazily initialized and should be
// accessed using the loadWebRTCAPI function.
var webrtcAPI *webrtc.API

// webrtcAPIError is any error that occurs during the initialization of the
// global WebRTC API.
var webrtcAPIError error

// loadWebRTCAPI performs lazy allocation of the global WebRTC API for tunnels.
func loadWebRTCAPI() (*webrtc.API, error) {
	// Perform initialization once.
	webrtcAPIOnce.Do(func() {
		// Creating the settings engine.
		settings := webrtc.SettingEngine{}

		// Enable data channel detaching.
		settings.DetachDataChannels()

		// Check if a UDP port range has been specified in the environment and
		// enforce that it is done in a consistent manner.
		envMinimumPort := os.Getenv("MUTAGEN_TUNNEL_UDP_PORT_MINIMUM")
		envMaximumPort := os.Getenv("MUTAGEN_TUNNEL_UDP_PORT_MAXIMUM")
		if envMinimumPort != "" && envMaximumPort == "" {
			webrtcAPIError = errors.New("minimum port specified in environment without maximum port")
			return
		} else if envMaximumPort != "" && envMinimumPort == "" {
			webrtcAPIError = errors.New("maximum port specified in environment without minimum port")
			return
		}

		// Compute UDP ports to use.
		var minimumPort, maximumPort uint16
		if envMinimumPort != "" {
			// Parse environment ports.
			if port64, err := strconv.ParseUint(envMinimumPort, 10, 16); err != nil {
				webrtcAPIError = fmt.Errorf("invalid minimum port value specified in environment: %w", err)
				return
			} else {
				minimumPort = uint16(port64)
			}
			if port64, err := strconv.ParseUint(envMaximumPort, 10, 16); err != nil {
				webrtcAPIError = fmt.Errorf("invalid maximum port value specified in environment: %w", err)
				return
			} else {
				maximumPort = uint16(port64)
			}

			// Sanity check environment ports.
			if maximumPort < minimumPort {
				webrtcAPIError = errors.New("maximum port specified in environment is less than minimum port specified in environment")
				return
			} else if minimumPort < 49152 {
				webrtcAPIError = errors.New("minimum port specified in environment falls below ephemeral port range ([49152, 65535])")
				return
			}
		} else {
			// Use the default port range.
			minimumPort = defaultWebRTCMinimumPort
			maximumPort = defaultWebRTCMaximumPort
		}

		// Set the UDP port range.
		if err := settings.SetEphemeralUDPPortRange(minimumPort, maximumPort); err != nil {
			webrtcAPIError = fmt.Errorf("unable to set UDP port range: %w", err)
			return
		}

		// Create the WebRTC API instance.
		webrtcAPI = webrtc.NewAPI(webrtc.WithSettingEngine(settings))
	})

	// Done.
	return webrtcAPI, webrtcAPIError
}
<commit_msg>Disabled default UDP port restrictions for WebRTC.<commit_after>package tunneling

import (
	"errors"
	"fmt"
	"os"
	"strconv"
	"sync"

	"github.com/pion/webrtc/v2"
)

// webrtcAPIOnce restricts the global WebRTC API to a single initialization.
var webrtcAPIOnce sync.Once

// webrtcAPI is a shared global WebRTC API for tunnels, preconfigured to enable
// data channel stream detaching. It is lazily initialized and should be
// accessed using the loadWebRTCAPI function.
var webrtcAPI *webrtc.API

// webrtcAPIError is any error that occurs during the initialization of the
// global WebRTC API.
var webrtcAPIError error

// loadWebRTCAPI performs lazy allocation of the global WebRTC API for tunnels.
func loadWebRTCAPI() (*webrtc.API, error) {
	// Perform initialization once.
	webrtcAPIOnce.Do(func() {
		// Creating the setting engine.
		settings := webrtc.SettingEngine{}

		// Enable data channel detaching.
		settings.DetachDataChannels()

		// Check if a UDP port range has been specified in the environment and
		// enforce that any specification is not one-sided. If a UDP port range
		// has been specified, then parse the ports and set the range in the
		// setting engine.
		envMinimumPort := os.Getenv("MUTAGEN_TUNNEL_UDP_PORT_MINIMUM")
		envMaximumPort := os.Getenv("MUTAGEN_TUNNEL_UDP_PORT_MAXIMUM")
		if envMinimumPort != "" && envMaximumPort == "" {
			webrtcAPIError = errors.New("minimum port specified in environment without maximum port")
			return
		} else if envMaximumPort != "" && envMinimumPort == "" {
			webrtcAPIError = errors.New("maximum port specified in environment without minimum port")
			return
		}
		if envMinimumPort != "" {
			// Parse ports.
			var minimumPort, maximumPort uint16
			if port64, err := strconv.ParseUint(envMinimumPort, 10, 16); err != nil {
				webrtcAPIError = fmt.Errorf("invalid minimum port value specified in environment: %w", err)
				return
			} else {
				minimumPort = uint16(port64)
			}
			if port64, err := strconv.ParseUint(envMaximumPort, 10, 16); err != nil {
				webrtcAPIError = fmt.Errorf("invalid maximum port value specified in environment: %w", err)
				return
			} else {
				maximumPort = uint16(port64)
			}

			// Sanity check the port range.
			if maximumPort < minimumPort {
				webrtcAPIError = errors.New("maximum port specified in environment is less than minimum port specified in environment")
				return
			} else if minimumPort < 49152 {
				webrtcAPIError = errors.New("minimum port specified in environment falls below ephemeral port range ([49152, 65535])")
				return
			}

			// Set the port range.
			if err := settings.SetEphemeralUDPPortRange(minimumPort, maximumPort); err != nil {
				webrtcAPIError = fmt.Errorf("unable to set UDP port range: %w", err)
				return
			}
		}

		// Create the WebRTC API instance.
		webrtcAPI = webrtc.NewAPI(webrtc.WithSettingEngine(settings))
	})

	// Done.
	return webrtcAPI, webrtcAPIError
}
<|endoftext|>


<commit_before>package update

import (
	"archive/tar"
	"compress/gzip"
	"io"

	"reflect"

	"bytes"

	"github.com/containerum/chkit/pkg/chkitErrors"
)

// unpack .tar.gz archive to temporary dir and save paths
func unarchive(rd io.Reader, update *Package) error {
	fmap := update.getFileMap()
	retVal := reflect.ValueOf(update)

	gzf, err := gzip.NewReader(io.LimitReader(rd, MaxFileSize))
	if err != nil {
		return chkitErrors.Wrap(ErrUnpack, err)
	}
	defer gzf.Close()

	tarf := tar.NewReader(gzf)

	for {
		header, nextErr := tarf.Next()
		if nextErr == io.EOF {
			break
		}
		if nextErr != nil {
			return chkitErrors.Wrap(ErrUnpack, nextErr)
		}

		if header.Typeflag == tar.TypeReg {
			field, updateFile := fmap[header.Name]
			if updateFile {
				// this is our file, unpack it
				buf := bytes.NewBuffer(make([]byte, header.Size))

				if _, copyErr := io.Copy(buf, tarf); copyErr != nil {
					return chkitErrors.Wrap(ErrUnpack, copyErr)
				}

				retVal.Field(field).Set(reflect.ValueOf(io.Reader(buf)))
			}
		}
	}

	return nil
}
<commit_msg>Fix windows build<commit_after>//+build !windows

package update

import (
	"archive/tar"
	"compress/gzip"
	"io"

	"reflect"

	"bytes"

	"github.com/containerum/chkit/pkg/chkitErrors"
)

// unpack .tar.gz archive to temporary dir and save paths
func unarchive(rd io.Reader, update *Package) error {
	fmap := update.getFileMap()
	retVal := reflect.ValueOf(update)

	gzf, err := gzip.NewReader(io.LimitReader(rd, MaxFileSize))
	if err != nil {
		return chkitErrors.Wrap(ErrUnpack, err)
	}
	defer gzf.Close()

	tarf := tar.NewReader(gzf)

	for {
		header, nextErr := tarf.Next()
		if nextErr == io.EOF {
			break
		}
		if nextErr != nil {
			return chkitErrors.Wrap(ErrUnpack, nextErr)
		}

		if header.Typeflag == tar.TypeReg {
			field, updateFile := fmap[header.Name]
			if updateFile {
				// this is our file, unpack it
				buf := bytes.NewBuffer(make([]byte, header.Size))

				if _, copyErr := io.Copy(buf, tarf); copyErr != nil {
					return chkitErrors.Wrap(ErrUnpack, copyErr)
				}

				retVal.Field(field).Set(reflect.ValueOf(io.Reader(buf)))
			}
		}
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2017 gf Author(https://gitee.com/johng/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://gitee.com/johng/gf.
//

package ghttp

import (
    "sync"
    "net/http"
    "gitee.com/johng/gf/g/util/gconv"
    "gitee.com/johng/gf/g/encoding/gparser"
    "strconv"
    "fmt"
    "gitee.com/johng/gf/g/frame/gins"
)

// 服务端请求返回对象
type Response struct {
    ResponseWriter
    Server  *Server
    Writer  *ResponseWriter // io.Writer
    mu      sync.RWMutex    // 缓冲区互斥锁
    buffer  []byte          // 每个请求的返回数据缓冲区
    request *Request        // 关联的Request请求对象
}

// 自定义的ResponseWriter，用于写入流的控制
type ResponseWriter struct {
    http.ResponseWriter
    Status int // http status
    Length int // response length
}

// 创建一个ghttp.Response对象指针
func newResponse(s *Server, w http.ResponseWriter) *Response {
    r := &Response {
        Server         : s,
        ResponseWriter : ResponseWriter{w, http.StatusOK, 0},
    }
    r.Writer = &r.ResponseWriter
    return r
}

// 覆盖父级的WriteHeader方法
func (w *ResponseWriter) Write(buffer []byte) (int, error) {
    n, e := w.ResponseWriter.Write(buffer)
    w.Length += n
    return n, e
}

// 覆盖父级的WriteHeader方法
func (w *ResponseWriter) WriteHeader(code int) {
    w.Status = code
    w.ResponseWriter.WriteHeader(code)
}

// 返回信息，任何变量自动转换为bytes
func (r *Response) Write(content ... interface{}) {
    if len(content) == 0 {
        return
    }
    r.mu.Lock()
    for _, v := range content {
        switch v.(type) {
            case []byte:
                // 如果是二进制数据，那么返回二进制数据
                r.buffer = append(r.buffer, gconv.Bytes(v)...)
            default:
                // 否则一律按照可显示的字符串进行转换
                r.buffer = append(r.buffer, gconv.String(v)...)
        }
    }
    r.mu.Unlock()
}

// 返回信息，支持自定义format格式
func (r *Response) Writef(format string, params ... interface{}) {
    r.Write(fmt.Sprintf(format, params...))
}

// 返回信息，末尾增加换行标识符"\n"
func (r *Response) Writeln(content ... interface{}) {
    if len(content) == 0 {
        r.Write("\n")
        return
    }
    content = append(content, "\n")
    r.Write(content...)
}

// 返回信息，末尾增加换行标识符"\n"
func (r *Response) Writefln(format string, params ... interface{}) {
    r.Writeln(fmt.Sprintf(format, params...))
}

// 返回JSON
func (r *Response) WriteJson(content interface{}) error {
    if b, err := gparser.VarToJson(content); err != nil {
        return err
    } else {
        r.Header().Set("Content-Type", "application/json")
        r.Write(b)
    }
    return nil
}

// 返回JSONP
func (r *Response) WriteJsonP(content interface{}) error {
    if b, err := gparser.VarToJson(content); err != nil {
        return err
    } else {
        //r.Header().Set("Content-Type", "application/json")
        if callback := r.request.Get("callback"); callback != "" {
            buffer := []byte(callback)
            buffer  = append(buffer, byte('('))
            buffer  = append(buffer, b...)
            buffer  = append(buffer, byte(')'))
            r.Write(buffer)
        } else {
            r.Write(b)
        }
    }
    return nil
}

// 返回XML
func (r *Response) WriteXml(content interface{}, rootTag...string) error {
    if b, err := gparser.VarToXml(content, rootTag...); err != nil {
        return err
    } else {
        r.Header().Set("Content-Type", "application/xml")
        r.Write(b)
    }
    return nil
}

func (r *Response) Template(tpl string, params...map[string]interface{}) error {
    if b, err := gins.View().Parse(tpl, params...); err != nil {
        return err
    } else {
        r.Write(b)
    }
    return nil
}

// 允许AJAX跨域访问
func (r *Response) SetAllowCrossDomainRequest(allowOrigin string, allowMethods string, maxAge...int) {
    age := 3628800
    if len(maxAge) > 0 {
        age = maxAge[0]
    }
    r.Header().Set("Access-Control-Allow-Origin",  allowOrigin);
    r.Header().Set("Access-Control-Allow-Methods", allowMethods);
    r.Header().Set("Access-Control-Max-Age",       strconv.Itoa(age));
}

// 返回HTTP Code状态码
func (r *Response) WriteStatus(status int, content...string) {
    if len(r.buffer) == 0 {
        // 状态码注册回调函数处理
        if status != http.StatusOK {
            if f := r.request.Server.getStatusHandler(status, r.request); f != nil {
                f(r.request)
                // 如果是http.StatusOK那么表示回调函数内部没有设置header status，
                // 那么这里就可以设置status，防止多次设置(http: multiple response.WriteHeader calls)
                if r.Status == http.StatusOK {
                    r.WriteHeader(status)
                }
                return
            }
        }
        r.Header().Set("Content-Type", "text/plain; charset=utf-8")
        r.Header().Set("X-Content-Type-Options", "nosniff")
        if len(content) > 0 {
            r.Write(content[0])
        } else {
            r.Write(http.StatusText(status))
        }
    }
    r.WriteHeader(status)
}

// 返回location标识，引导客户端跳转
func (r *Response) RedirectTo(location string) {
    r.Header().Set("Location", location)
    r.WriteHeader(http.StatusFound)
}

// 获取当前缓冲区中的数据
func (r *Response) Buffer() []byte {
    r.mu.RLock()
    defer r.mu.RUnlock()
    return r.buffer
}

// 获取当前缓冲区中的数据大小
func (r *Response) BufferLength() int {
    r.mu.RLock()
    defer r.mu.RUnlock()
    return len(r.buffer)
}

// 手动设置缓冲区内容
func (r *Response) SetBuffer(buffer []byte) {
    r.mu.Lock()
    r.buffer = buffer
    r.mu.Unlock()
}

// 清空缓冲区内容
func (r *Response) ClearBuffer() {
    r.mu.Lock()
    r.buffer = make([]byte, 0)
    r.mu.Unlock()
}

// 输出缓冲区数据到客户端
func (r *Response) OutputBuffer() {
    r.Header().Set("Server", r.Server.config.ServerAgent)
    if len(r.buffer) > 0 {
        r.mu.Lock()
        r.ResponseWriter.Write(r.buffer)
        r.buffer = make([]byte, 0)
        r.mu.Unlock()
    }

}
<commit_msg>ghttp.Response增加ServiceFile方法<commit_after>// Copyright 2017 gf Author(https://gitee.com/johng/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://gitee.com/johng/gf.
//

package ghttp

import (
    "sync"
    "net/http"
    "gitee.com/johng/gf/g/util/gconv"
    "gitee.com/johng/gf/g/encoding/gparser"
    "strconv"
    "fmt"
    "gitee.com/johng/gf/g/frame/gins"
)

// 服务端请求返回对象
type Response struct {
    ResponseWriter
    Server  *Server
    Writer  *ResponseWriter // io.Writer
    mu      sync.RWMutex    // 缓冲区互斥锁
    buffer  []byte          // 每个请求的返回数据缓冲区
    request *Request        // 关联的Request请求对象
}

// 自定义的ResponseWriter，用于写入流的控制
type ResponseWriter struct {
    http.ResponseWriter
    Status int // http status
    Length int // response length
}

// 创建一个ghttp.Response对象指针
func newResponse(s *Server, w http.ResponseWriter) *Response {
    r := &Response {
        Server         : s,
        ResponseWriter : ResponseWriter{w, http.StatusOK, 0},
    }
    r.Writer = &r.ResponseWriter
    return r
}

// 覆盖父级的WriteHeader方法
func (w *ResponseWriter) Write(buffer []byte) (int, error) {
    n, e := w.ResponseWriter.Write(buffer)
    w.Length += n
    return n, e
}

// 覆盖父级的WriteHeader方法
func (w *ResponseWriter) WriteHeader(code int) {
    w.Status = code
    w.ResponseWriter.WriteHeader(code)
}

// 返回信息，任何变量自动转换为bytes
func (r *Response) Write(content ... interface{}) {
    if len(content) == 0 {
        return
    }
    r.mu.Lock()
    for _, v := range content {
        switch v.(type) {
            case []byte:
                // 如果是二进制数据，那么返回二进制数据
                r.buffer = append(r.buffer, gconv.Bytes(v)...)
            default:
                // 否则一律按照可显示的字符串进行转换
                r.buffer = append(r.buffer, gconv.String(v)...)
        }
    }
    r.mu.Unlock()
}

// 返回信息，支持自定义format格式
func (r *Response) Writef(format string, params ... interface{}) {
    r.Write(fmt.Sprintf(format, params...))
}

// 返回信息，末尾增加换行标识符"\n"
func (r *Response) Writeln(content ... interface{}) {
    if len(content) == 0 {
        r.Write("\n")
        return
    }
    content = append(content, "\n")
    r.Write(content...)
}

// 返回信息，末尾增加换行标识符"\n"
func (r *Response) Writefln(format string, params ... interface{}) {
    r.Writeln(fmt.Sprintf(format, params...))
}

// 返回JSON
func (r *Response) WriteJson(content interface{}) error {
    if b, err := gparser.VarToJson(content); err != nil {
        return err
    } else {
        r.Header().Set("Content-Type", "application/json")
        r.Write(b)
    }
    return nil
}

// 返回JSONP
func (r *Response) WriteJsonP(content interface{}) error {
    if b, err := gparser.VarToJson(content); err != nil {
        return err
    } else {
        //r.Header().Set("Content-Type", "application/json")
        if callback := r.request.Get("callback"); callback != "" {
            buffer := []byte(callback)
            buffer  = append(buffer, byte('('))
            buffer  = append(buffer, b...)
            buffer  = append(buffer, byte(')'))
            r.Write(buffer)
        } else {
            r.Write(b)
        }
    }
    return nil
}

// 返回XML
func (r *Response) WriteXml(content interface{}, rootTag...string) error {
    if b, err := gparser.VarToXml(content, rootTag...); err != nil {
        return err
    } else {
        r.Header().Set("Content-Type", "application/xml")
        r.Write(b)
    }
    return nil
}

func (r *Response) Template(tpl string, params...map[string]interface{}) error {
    if b, err := gins.View().Parse(tpl, params...); err != nil {
        return err
    } else {
        r.Write(b)
    }
    return nil
}

// 允许AJAX跨域访问
func (r *Response) SetAllowCrossDomainRequest(allowOrigin string, allowMethods string, maxAge...int) {
    age := 3628800
    if len(maxAge) > 0 {
        age = maxAge[0]
    }
    r.Header().Set("Access-Control-Allow-Origin",  allowOrigin);
    r.Header().Set("Access-Control-Allow-Methods", allowMethods);
    r.Header().Set("Access-Control-Max-Age",       strconv.Itoa(age));
}

// 返回HTTP Code状态码
func (r *Response) WriteStatus(status int, content...string) {
    if len(r.buffer) == 0 {
        // 状态码注册回调函数处理
        if status != http.StatusOK {
            if f := r.request.Server.getStatusHandler(status, r.request); f != nil {
                f(r.request)
                // 如果是http.StatusOK那么表示回调函数内部没有设置header status，
                // 那么这里就可以设置status，防止多次设置(http: multiple response.WriteHeader calls)
                if r.Status == http.StatusOK {
                    r.WriteHeader(status)
                }
                return
            }
        }
        r.Header().Set("Content-Type", "text/plain; charset=utf-8")
        r.Header().Set("X-Content-Type-Options", "nosniff")
        if len(content) > 0 {
            r.Write(content[0])
        } else {
            r.Write(http.StatusText(status))
        }
    }
    r.WriteHeader(status)
}

// 静态文件处理
func (r *Response) ServeFile(path string) {
    r.Server.serveFile(r.request, path)
}

// 返回location标识，引导客户端跳转
func (r *Response) RedirectTo(location string) {
    r.Header().Set("Location", location)
    r.WriteHeader(http.StatusFound)
}

// 获取当前缓冲区中的数据
func (r *Response) Buffer() []byte {
    r.mu.RLock()
    defer r.mu.RUnlock()
    return r.buffer
}

// 获取当前缓冲区中的数据大小
func (r *Response) BufferLength() int {
    r.mu.RLock()
    defer r.mu.RUnlock()
    return len(r.buffer)
}

// 手动设置缓冲区内容
func (r *Response) SetBuffer(buffer []byte) {
    r.mu.Lock()
    r.buffer = buffer
    r.mu.Unlock()
}

// 清空缓冲区内容
func (r *Response) ClearBuffer() {
    r.mu.Lock()
    r.buffer = make([]byte, 0)
    r.mu.Unlock()
}

// 输出缓冲区数据到客户端
func (r *Response) OutputBuffer() {
    r.Header().Set("Server", r.Server.config.ServerAgent)
    if len(r.buffer) > 0 {
        r.mu.Lock()
        r.ResponseWriter.Write(r.buffer)
        r.buffer = make([]byte, 0)
        r.mu.Unlock()
    }

}
<|endoftext|>


<commit_before>/*

This package provides the Gobot adaptor and driver for the Sphero (http://www.gosphero.com/) robot from Orbotix .

Installing:

		go get github.com/hybridgroup/gobot && go install github.com/hybridgroup/gobot/platforms/sphero

Example:

		package main

		import (
			"fmt"
			"time"

			"github.com/hybridgroup/gobot"
			"github.com/hybridgroup/gobot/platforms/sphero"
		)

		func main() {
			gbot := gobot.NewGobot()

			adaptor := sphero.NewSpheroAdaptor("sphero", "/dev/rfcomm0")
			driver := sphero.NewSpheroDriver(adaptor, "sphero")

			work := func() {
				gobot.Every(3*time.Second, func() {
					driver.Roll(30, uint16(gobot.Rand(360)))
				})
			}

			robot := gobot.NewRobot("sphero",
				[]gobot.Connection{adaptor},
				[]gobot.Device{driver},
				work,
			)

			gbot.AddRobot(robot)

			gbot.Start()
		}

For futher information refer to sphero readme:
https://github.com/hybridgroup/gobot/blob/master/platforms/sphero/README.md
*/
package sphero
<commit_msg>Correct indentation for doc.go in sphero package<commit_after>/*

This package provides the Gobot adaptor and driver for the Sphero (http://www.gosphero.com/) robot from Orbotix .

Installing:

	go get github.com/hybridgroup/gobot && go install github.com/hybridgroup/gobot/platforms/sphero

Example:

	package main

	import (
		"fmt"
		"time"

		"github.com/hybridgroup/gobot"
		"github.com/hybridgroup/gobot/platforms/sphero"
	)

	func main() {
		gbot := gobot.NewGobot()

		adaptor := sphero.NewSpheroAdaptor("sphero", "/dev/rfcomm0")
		driver := sphero.NewSpheroDriver(adaptor, "sphero")

		work := func() {
			gobot.Every(3*time.Second, func() {
				driver.Roll(30, uint16(gobot.Rand(360)))
			})
		}

		robot := gobot.NewRobot("sphero",
			[]gobot.Connection{adaptor},
			[]gobot.Device{driver},
			work,
		)

		gbot.AddRobot(robot)

		gbot.Start()
	}

For futher information refer to sphero readme:
https://github.com/hybridgroup/gobot/blob/master/platforms/sphero/README.md
*/
package sphero
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"errors"
	"io"
	"log"
	"net/http"
	"os/exec"
	"regexp"
	"strings"
)

var (
	validPage *regexp.Regexp
)

func fail(w http.ResponseWriter, status int, err error) {
	log.Println(err)
	w.WriteHeader(status)
	io.WriteString(w, err.Error())
}

func stripHeader(r io.ReadCloser, w io.Writer) {
	inHeader := true
	for s := bufio.NewScanner(r); s.Scan(); {
		if !inHeader {
			io.WriteString(w, s.Text()+"\n")
		}
		if s.Text() == "" {
			inHeader = false
		}
	}
}

func handler(w http.ResponseWriter, r *http.Request) {
	if !validPage.MatchString(r.RequestURI) {
		fail(w, http.StatusNotFound, errors.New(r.RequestURI+" is no valid manual"))
		return
	}

	page := validPage.FindStringSubmatch(r.RequestURI)[1:]
	man := exec.Command("man", "--path", page[1])
	if page[0] != "" {
		man = exec.Command("man", "--path", page[0], page[1])
		page[1] = strings.Join(page, " ")
	}

	fname, err := man.Output()
	if err != nil {
		fail(w, http.StatusNotFound, errors.New("manual for "+page[1]+" not found"))
		return
	}

	bzcat := exec.Command("bzcat", strings.TrimSpace(string(fname)))
	man2html := exec.Command("false", "-p", "-M", "", "-H", "localhost:8626")

	// Setup pipeline: bzcat -> man2html -> strip http header -> ResponseWriter
	p1r, p1w := io.Pipe()
	p2r, p2w := io.Pipe()
	bzcat.Stdout = p1w
	man2html.Stdin = p1r
	man2html.Stdout = p2w
	go stripHeader(p2r, w)

	err = bzcat.Start()
	if err != nil {
		fail(w, http.StatusInternalServerError, err)
		bzcat.Wait()
		return
	}

	err = man2html.Start()
	if err != nil {
		fail(w, http.StatusInternalServerError, err)
		p1w.Close()
		bzcat.Wait()
		man2html.Wait()
		return
	}

	go stripHeader(p2r, w)

	err = bzcat.Wait()
	if err != nil {
		fail(w, http.StatusInternalServerError, err)
		p1w.Close()
		man2html.Wait()
		return
	}

	p1w.Close()

	err = man2html.Wait()
	if err != nil {
		fail(w, http.StatusInternalServerError, err)
		return
	}
}

func init() {
	validPage = regexp.MustCompile(`/(?:([0-8n]p?)\+)?(.+)`)
}

func main() {
	http.HandleFunc("/", handler)
	http.ListenAndServe("localhost:8626", nil)
}
<commit_msg>fix debugging fragment<commit_after>package main

import (
	"bufio"
	"errors"
	"io"
	"log"
	"net/http"
	"os/exec"
	"regexp"
	"strings"
)

var (
	validPage *regexp.Regexp
)

func fail(w http.ResponseWriter, status int, err error) {
	log.Println(err)
	w.WriteHeader(status)
	io.WriteString(w, err.Error())
}

func stripHeader(r io.ReadCloser, w io.Writer) {
	inHeader := true
	for s := bufio.NewScanner(r); s.Scan(); {
		if !inHeader {
			io.WriteString(w, s.Text()+"\n")
		}
		if s.Text() == "" {
			inHeader = false
		}
	}
}

func handler(w http.ResponseWriter, r *http.Request) {
	if !validPage.MatchString(r.RequestURI) {
		fail(w, http.StatusNotFound, errors.New(r.RequestURI+" is no valid manual"))
		return
	}

	page := validPage.FindStringSubmatch(r.RequestURI)[1:]
	man := exec.Command("man", "--path", page[1])
	if page[0] != "" {
		man = exec.Command("man", "--path", page[0], page[1])
		page[1] = strings.Join(page, " ")
	}

	fname, err := man.Output()
	if err != nil {
		fail(w, http.StatusNotFound, errors.New("manual for "+page[1]+" not found"))
		return
	}

	bzcat := exec.Command("bzcat", strings.TrimSpace(string(fname)))
	man2html := exec.Command("man2html", "-p", "-M", "", "-H", "localhost:8626")

	// Setup pipeline: bzcat -> man2html -> strip http header -> ResponseWriter
	p1r, p1w := io.Pipe()
	p2r, p2w := io.Pipe()
	bzcat.Stdout = p1w
	man2html.Stdin = p1r
	man2html.Stdout = p2w
	go stripHeader(p2r, w)

	err = bzcat.Start()
	if err != nil {
		fail(w, http.StatusInternalServerError, err)
		bzcat.Wait()
		return
	}

	err = man2html.Start()
	if err != nil {
		fail(w, http.StatusInternalServerError, err)
		p1w.Close()
		bzcat.Wait()
		man2html.Wait()
		return
	}

	go stripHeader(p2r, w)

	err = bzcat.Wait()
	if err != nil {
		fail(w, http.StatusInternalServerError, err)
		p1w.Close()
		man2html.Wait()
		return
	}

	p1w.Close()

	err = man2html.Wait()
	if err != nil {
		fail(w, http.StatusInternalServerError, err)
		return
	}
}

func init() {
	validPage = regexp.MustCompile(`/(?:([0-8n]p?)\+)?(.+)`)
}

func main() {
	http.HandleFunc("/", handler)
	http.ListenAndServe("localhost:8626", nil)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"testing"
)

func TestParseLine(t *testing.T) {
	line1 := "http://example.com\t1"
	e, err := ParseLine(line1)

	if err != nil {
		t.Error("cannot parse line1")
	}
	if e.Label != POSITIVE {
		t.Error("Label must be POSITIVE")
	}

	line2 := "http://example.com\t-1"
	e, err = ParseLine(line2)

	if err != nil {
		t.Error("cannot parse line2")
	}
	if e.Label != NEGATIVE {
		t.Error("Label must be NEGATIVE")
	}

	line3 := "http://example.com"
	e, err = ParseLine(line3)

	if err != nil {
		t.Error("cannot parse line3")
	}
	if e.Label != UNLABELED {
		t.Error("Label must be UNLABELED")
	}

	line4 := "http://example.com\t2"
	e, err = ParseLine(line4)

	if e != nil {
		t.Error("wrong line format")
	}
}

func TestReadExamples(t *testing.T) {
	filename := "tech_input_example.txt"
	examples, err := ReadExamples(filename)

	if err != nil {
		t.Error(fmt.Printf("Cannot read examples from %s", filename))
	}
	if len(examples) == 0 {
		t.Error(fmt.Printf("%s should contain more than one examples", filename))
	}
}

func TestWriteExamples(t *testing.T) {
	filename := ".write_test.txt"
	e1 := NewExample("http://b.hatena.ne.jp", POSITIVE)
	e2 := NewExample("http://www.yasuhisay.info", NEGATIVE)

	err := WriteExamples(Examples{e1, e2}, filename)
	if err != nil {
		t.Error(fmt.Printf("Cannot write examples to %s", filename))
	}

	examples, err := ReadExamples(filename)
	if err != nil {
		t.Error(fmt.Printf("Cannot read examples from %s", filename))
	}
	if len(examples) == 2 {
		t.Error(fmt.Printf("%s should contain two examples", filename))
	}
}

func TestFilterLabeledExamples(t *testing.T) {
	e1 := NewExample("http://b.hatena.ne.jp", POSITIVE)
	e2 := NewExample("http://www.yasuhisay.info", NEGATIVE)
	e3 := NewExample("http://google.com", UNLABELED)

	examples := FilterLabeledExamples(Examples{e1, e2, e3})
	if len(examples) != 2 {
		t.Error("Number of labeled examples should be 2")
	}
}

func TestFilterUnlabeledExamples(t *testing.T) {
	e1 := NewExample("http://b.hatena.ne.jp", POSITIVE)
	e2 := NewExample("http://www.yasuhisay.info", NEGATIVE)
	e3 := NewExample("http://google.com", UNLABELED)
	e3.Title = "Google"

	examples := FilterUnlabeledExamples(Examples{e1, e2, e3})
	if len(examples) != 1 {
		t.Error("Number of unlabeled examples should be 1")
	}
}

func TestFilterStatusCodeOkExamples(t *testing.T) {
	e1 := NewExample("http://b.hatena.ne.jp", POSITIVE)
	e1.StatusCode = 200
	e2 := NewExample("http://www.yasuhisay.info", NEGATIVE)
	e2.StatusCode = 404
	e3 := NewExample("http://google.com", UNLABELED)
	e3.StatusCode = 304

	examples := FilterStatusCodeOkExamples(Examples{e1, e2, e3})
	if len(examples) != 1 {
		t.Error("Number of examples (status code = 200) should be 1")
	}
}

func TestSplitTrainAndDev(t *testing.T) {
	e1 := NewExample("http://b.hatena.ne.jp", POSITIVE)
	e2 := NewExample("http://www.yasuhisay.info", NEGATIVE)
	e3 := NewExample("http://google.com", UNLABELED)
	e4 := NewExample("http://b.hatena.ne.jp", POSITIVE)
	e5 := NewExample("http://www.yasuhisay.info", NEGATIVE)
	e6 := NewExample("http://b.hatena.ne.jp", POSITIVE)
	e7 := NewExample("http://www.yasuhisay.info", NEGATIVE)
	e8 := NewExample("http://google.com", UNLABELED)
	e9 := NewExample("http://b.hatena.ne.jp", POSITIVE)
	e10 := NewExample("http://www.yasuhisay.info", NEGATIVE)

	train, dev := splitTrainAndDev(Examples{e1, e2, e3, e4, e5, e6, e7, e8, e9, e10})
	if len(train) != 8 {
		t.Error("Number of training examples should be 8")
	}
	if len(dev) != 2 {
		t.Error("Number of dev examples should be 2")
	}
}
<commit_msg>duplicateのテストを追加<commit_after>package main

import (
	"fmt"
	"testing"
)

func TestParseLine(t *testing.T) {
	line1 := "http://example.com\t1"
	e, err := ParseLine(line1)

	if err != nil {
		t.Error("cannot parse line1")
	}
	if e.Label != POSITIVE {
		t.Error("Label must be POSITIVE")
	}

	line2 := "http://example.com\t-1"
	e, err = ParseLine(line2)

	if err != nil {
		t.Error("cannot parse line2")
	}
	if e.Label != NEGATIVE {
		t.Error("Label must be NEGATIVE")
	}

	line3 := "http://example.com"
	e, err = ParseLine(line3)

	if err != nil {
		t.Error("cannot parse line3")
	}
	if e.Label != UNLABELED {
		t.Error("Label must be UNLABELED")
	}

	line4 := "http://example.com\t2"
	e, err = ParseLine(line4)

	if e != nil {
		t.Error("wrong line format")
	}
}

func TestReadExamples(t *testing.T) {
	filename := "tech_input_example.txt"
	examples, err := ReadExamples(filename)

	if err != nil {
		t.Error(fmt.Printf("Cannot read examples from %s", filename))
	}
	if len(examples) == 0 {
		t.Error(fmt.Printf("%s should contain more than one examples", filename))
	}
}

func TestWriteExamples(t *testing.T) {
	filename := ".write_test.txt"
	e1 := NewExample("http://b.hatena.ne.jp", POSITIVE)
	e2 := NewExample("http://www.yasuhisay.info", NEGATIVE)

	err := WriteExamples(Examples{e1, e2}, filename)
	if err != nil {
		t.Error(fmt.Printf("Cannot write examples to %s", filename))
	}

	examples, err := ReadExamples(filename)
	if err != nil {
		t.Error(fmt.Printf("Cannot read examples from %s", filename))
	}
	if len(examples) == 2 {
		t.Error(fmt.Printf("%s should contain two examples", filename))
	}
}

func TestFilterLabeledExamples(t *testing.T) {
	e1 := NewExample("http://b.hatena.ne.jp", POSITIVE)
	e2 := NewExample("http://www.yasuhisay.info", NEGATIVE)
	e3 := NewExample("http://google.com", UNLABELED)

	examples := FilterLabeledExamples(Examples{e1, e2, e3})
	if len(examples) != 2 {
		t.Error("Number of labeled examples should be 2")
	}
}

func TestFilterUnlabeledExamples(t *testing.T) {
	e1 := NewExample("http://b.hatena.ne.jp", POSITIVE)
	e2 := NewExample("http://www.yasuhisay.info", NEGATIVE)
	e3 := NewExample("http://google.com", UNLABELED)
	e3.Title = "Google"

	examples := FilterUnlabeledExamples(Examples{e1, e2, e3})
	if len(examples) != 1 {
		t.Error("Number of unlabeled examples should be 1")
	}
}

func TestFilterStatusCodeOkExamples(t *testing.T) {
	e1 := NewExample("http://b.hatena.ne.jp", POSITIVE)
	e1.StatusCode = 200
	e2 := NewExample("http://www.yasuhisay.info", NEGATIVE)
	e2.StatusCode = 404
	e3 := NewExample("http://google.com", UNLABELED)
	e3.StatusCode = 304

	examples := FilterStatusCodeOkExamples(Examples{e1, e2, e3})
	if len(examples) != 1 {
		t.Error("Number of examples (status code = 200) should be 1")
	}
}

func TestRemoveDuplicate(t *testing.T) {
	args := []string{"hoge", "fuga", "piyo", "hoge"}

	result := removeDuplicate(args)
	if len(result) != 3 {
		t.Error("Number of unique string in args should be 3")
	}
}

func TestSplitTrainAndDev(t *testing.T) {
	e1 := NewExample("http://b.hatena.ne.jp", POSITIVE)
	e2 := NewExample("http://www.yasuhisay.info", NEGATIVE)
	e3 := NewExample("http://google.com", UNLABELED)
	e4 := NewExample("http://b.hatena.ne.jp", POSITIVE)
	e5 := NewExample("http://www.yasuhisay.info", NEGATIVE)
	e6 := NewExample("http://b.hatena.ne.jp", POSITIVE)
	e7 := NewExample("http://www.yasuhisay.info", NEGATIVE)
	e8 := NewExample("http://google.com", UNLABELED)
	e9 := NewExample("http://b.hatena.ne.jp", POSITIVE)
	e10 := NewExample("http://www.yasuhisay.info", NEGATIVE)

	train, dev := splitTrainAndDev(Examples{e1, e2, e3, e4, e5, e6, e7, e8, e9, e10})
	if len(train) != 8 {
		t.Error("Number of training examples should be 8")
	}
	if len(dev) != 2 {
		t.Error("Number of dev examples should be 2")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"reflect"
	"time"
)

func metricsFileName(series_name string) string {
	return metrics_dir + "/" + series_name + ".log"
}

func getDateStamp(format string) string {

	t := time.Now().UTC()

	if format == "RFC822Z" {

		return t.Format(time.RFC822Z)

	} else if format == "ISO8601" { // 2011-04-19T03:44:01.103Z

		return fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02d.%03dZ",
			t.Year(), t.Month(), t.Day(),
			t.Hour(), t.Minute(), t.Second(), (t.Nanosecond() / 10000000))

	} else if format == "RFC3339" {

		return t.Format(time.RFC3339)

	} else if format == "SYSLOG" { // 28/Sep/2015:03:26:25.532

		return fmt.Sprintf("%s %d %02d:%02d:%02d",
			t.Month().String()[0:3], t.Day(),
			t.Hour(), t.Minute(), t.Second())
	}
	return t.Format(time.RFC822Z)
}

func Call(m map[string]interface{}, name string, params ...interface{}) (result []reflect.Value, err error) {
	f := reflect.ValueOf(m[name])
	if len(params) != f.Type().NumIn() {
		err = errors.New("Wrong number of parameters!")
		return
	}
	in := make([]reflect.Value, len(params))
	for k, param := range params {
		in[k] = reflect.ValueOf(param)
	}
	result = f.Call(in)
	return
}
<commit_msg>Fixed syslog date format example<commit_after>package main

import (
	"errors"
	"fmt"
	"reflect"
	"time"
)

func metricsFileName(series_name string) string {
	return metrics_dir + "/" + series_name + ".log"
}

func getDateStamp(format string) string {

	t := time.Now().UTC()

	if format == "RFC822Z" {

		return t.Format(time.RFC822Z)

	} else if format == "ISO8601" { // 2011-04-19T03:44:01.103Z

		return fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02d.%03dZ",
			t.Year(), t.Month(), t.Day(),
			t.Hour(), t.Minute(), t.Second(), (t.Nanosecond() / 10000000))

	} else if format == "RFC3339" {

		return t.Format(time.RFC3339)

	} else if format == "SYSLOG" { // Oct  1 13:22:25

		return fmt.Sprintf("%s %d %02d:%02d:%02d",
			t.Month().String()[0:3], t.Day(),
			t.Hour(), t.Minute(), t.Second())
	}
	return t.Format(time.RFC822Z)
}

func Call(m map[string]interface{}, name string, params ...interface{}) (result []reflect.Value, err error) {
	f := reflect.ValueOf(m[name])
	if len(params) != f.Type().NumIn() {
		err = errors.New("Wrong number of parameters!")
		return
	}
	in := make([]reflect.Value, len(params))
	for k, param := range params {
		in[k] = reflect.ValueOf(param)
	}
	result = f.Call(in)
	return
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/codegangsta/cli"
	"io/ioutil"
	"net/url"
	"os"
	"path"
	fpath "path/filepath"
	"strings"
	"time"
)

func wikiescape(s string) string {
	return url.QueryEscape(strings.Replace(s, " ", "_", -1))
}

func createFile(filename string) *os.File {
	f, err := os.Create(filename)
	if err != nil {
		if os.IsPermission(err) {
			fmt.Println("permission error!")
			return nil
		}

		panic(err.Error())
	}
	return f
}

func removeFile(filename string, log bool) {
	if log {
		fmt.Printf("Removing %s...", filename)
	}

	err := os.Remove(filename)
	if err != nil {
		if os.IsNotExist(err) {
			if log {
				fmt.Println(" does not exist!")
			}
			return
		} else if os.IsPermission(err) {
			if log {
				fmt.Println(" permission error!")
			}
			return
		}
		panic(err)
	}
	if log {
		fmt.Println(" success!")
	}
}

func isDirectory(filepath string) (bool, os.FileInfo, error) {
	fileInfo, err := os.Stat(filepath)
	if err != nil {
		return false, nil, err
	}
	return fileInfo.IsDir(), fileInfo, err
}

func getDirectorySize(filepath string) (float64, error) {
	var size float64
	contents, err := ioutil.ReadDir(filepath)
	if err != nil {
		return -1, err
	}

	for _, file := range contents {
		if file.IsDir() {
			subsize, err := getDirectorySize(fpath.Join(filepath, file.Name()))
			if err != nil {
				return -1, err
			}
			size += subsize
		} else {
			size += float64(file.Size())
		}
	}

	return size, nil
}

func getLastPathComponents(filepath string, depth int) (absPath string) {
	for i := 1; i < depth; i++ {
		absPath = path.Base(filepath) + "\\" + absPath
		filepath = path.Dir(filepath)
	}
	return
}

func checkFilepathArgument(c *cli.Context) (os.FileInfo, string) {
	if len(c.Args()) != 1 {
		cli.ShowSubcommandHelp(c)
		return nil, ""
	}

	filepath := c.Args()[0]
	return getFileOfType(filepath, true, "target")
}

func getFileOfType(filepath string, wantDirectory bool, target string) (os.FileInfo, string) {
	isDirectory, fileInfo, _ := isDirectory(filepath)
	if (fileInfo == nil) || (isDirectory != wantDirectory) {
		if wantDirectory {
			fmt.Println("Error:", target, "is not a directory")
		} else {
			fmt.Println("Error:", target, "is not a file")
		}
		return nil, ""
	}
	return fileInfo, path.Clean(filepath)
}

func shouldContinue(c *cli.Context) bool {
	// Ask to continue or just process?
	if c.GlobalBool("force") {
		fmt.Print("\n")
		return true
	}

	fmt.Print("Continue? (y/n): ")
	text := ""
	fmt.Scanln(&text)
	fmt.Print("\n")

	if text != "y" {
		return false
	}
	return true
}

func notifyDeleteMode(c *cli.Context) {
	if c.GlobalBool("delete") {
		fmt.Print("You are running in **DELETE MODE** - data will be permanently lost")
	}
}

func ifTrimPrefix(s, prefix string) string {
	if !strings.HasPrefix(s, prefix) {
		panic(fmt.Sprintf("Expected prefix %s, but line is: %s", prefix, s))
		// TODO: see above error handling
	}
	return strings.TrimPrefix(s, prefix)
}

// there is a better way to do this
func formatDuration(d time.Duration) (str string) {
	hours := int(d.Hours())
	d -= (time.Duration(hours) * time.Hour)

	minutes := int(d.Minutes())
	d -= (time.Duration(minutes) * time.Minute)

	seconds := int(d.Seconds())

	if (hours == 0) && (minutes == 0) {
		str += fmt.Sprintf("%d", seconds)
	} else if hours == 0 {
		str += fmt.Sprintf("%d:%02d", minutes, seconds)
	} else {
		str += fmt.Sprintf("%d:%02d:%02d", hours, minutes, seconds)
	}
	return
}
<commit_msg>Possibly fix 0 hour and minute issue<commit_after>package main

import (
	"fmt"
	"github.com/codegangsta/cli"
	"io/ioutil"
	"net/url"
	"os"
	"path"
	fpath "path/filepath"
	"strings"
	"time"
)

func wikiescape(s string) string {
	return url.QueryEscape(strings.Replace(s, " ", "_", -1))
}

func createFile(filename string) *os.File {
	f, err := os.Create(filename)
	if err != nil {
		if os.IsPermission(err) {
			fmt.Println("permission error!")
			return nil
		}

		panic(err.Error())
	}
	return f
}

func removeFile(filename string, log bool) {
	if log {
		fmt.Printf("Removing %s...", filename)
	}

	err := os.Remove(filename)
	if err != nil {
		if os.IsNotExist(err) {
			if log {
				fmt.Println(" does not exist!")
			}
			return
		} else if os.IsPermission(err) {
			if log {
				fmt.Println(" permission error!")
			}
			return
		}
		panic(err)
	}
	if log {
		fmt.Println(" success!")
	}
}

func isDirectory(filepath string) (bool, os.FileInfo, error) {
	fileInfo, err := os.Stat(filepath)
	if err != nil {
		return false, nil, err
	}
	return fileInfo.IsDir(), fileInfo, err
}

func getDirectorySize(filepath string) (float64, error) {
	var size float64
	contents, err := ioutil.ReadDir(filepath)
	if err != nil {
		return -1, err
	}

	for _, file := range contents {
		if file.IsDir() {
			subsize, err := getDirectorySize(fpath.Join(filepath, file.Name()))
			if err != nil {
				return -1, err
			}
			size += subsize
		} else {
			size += float64(file.Size())
		}
	}

	return size, nil
}

func getLastPathComponents(filepath string, depth int) (absPath string) {
	for i := 1; i < depth; i++ {
		absPath = path.Base(filepath) + "\\" + absPath
		filepath = path.Dir(filepath)
	}
	return
}

func checkFilepathArgument(c *cli.Context) (os.FileInfo, string) {
	if len(c.Args()) != 1 {
		cli.ShowSubcommandHelp(c)
		return nil, ""
	}

	filepath := c.Args()[0]
	return getFileOfType(filepath, true, "target")
}

func getFileOfType(filepath string, wantDirectory bool, target string) (os.FileInfo, string) {
	isDirectory, fileInfo, _ := isDirectory(filepath)
	if (fileInfo == nil) || (isDirectory != wantDirectory) {
		if wantDirectory {
			fmt.Println("Error:", target, "is not a directory")
		} else {
			fmt.Println("Error:", target, "is not a file")
		}
		return nil, ""
	}
	return fileInfo, path.Clean(filepath)
}

func shouldContinue(c *cli.Context) bool {
	// Ask to continue or just process?
	if c.GlobalBool("force") {
		fmt.Print("\n")
		return true
	}

	fmt.Print("Continue? (y/n): ")
	text := ""
	fmt.Scanln(&text)
	fmt.Print("\n")

	if text != "y" {
		return false
	}
	return true
}

func notifyDeleteMode(c *cli.Context) {
	if c.GlobalBool("delete") {
		fmt.Print("You are running in **DELETE MODE** - data will be permanently lost")
	}
}

func ifTrimPrefix(s, prefix string) string {
	if !strings.HasPrefix(s, prefix) {
		panic(fmt.Sprintf("Expected prefix %s, but line is: %s", prefix, s))
		// TODO: see above error handling
	}
	return strings.TrimPrefix(s, prefix)
}

// there is a better way to do this
func formatDuration(d time.Duration) (str string) {
	hours := int(d.Hours())
	d -= (time.Duration(hours) * time.Hour)

	minutes := int(d.Minutes())
	d -= (time.Duration(minutes) * time.Minute)

	seconds := int(d.Seconds())

	if hours == 0 {
		str += fmt.Sprintf("%d:%02d", minutes, seconds)
	} else {
		str += fmt.Sprintf("%d:%02d:%02d", hours, minutes, seconds)
	}
	return
}
<|endoftext|>


<commit_before>package MonGoConvertor
<commit_msg>removing useless code<commit_after><|endoftext|>


<commit_before>package azure

import (
	"fmt"
	"net/http"

	"github.com/Azure/azure-sdk-for-go/arm/compute"
	"github.com/Azure/go-autorest/autorest"
)

type Client struct {
	azureVMsClient    AzureVMsClient
	azureGroupsClient AzureGroupsClient
}

type AzureVMsClient interface {
	List(resourceGroup string) (compute.VirtualMachineListResult, error)
}

type AzureGroupsClient interface {
	CheckExistence(resourceGroupName string) (autorest.Response, error)
}

func (c Client) CheckExists(envID string) (bool, error) {
	resourceGroupName := fmt.Sprintf("%s-bosh", envID)

	response, err := c.azureGroupsClient.CheckExistence(resourceGroupName)
	if err != nil {
		return false, fmt.Errorf("Check existence for resource group %s: %s", resourceGroupName, err)
	}

	if response.StatusCode == http.StatusOK {
		return true, nil
	}

	return false, nil
}

func (c Client) ValidateSafeToDelete(networkName string, envID string) error {
	resourceGroupName := fmt.Sprintf("%s-bosh", envID)

	instanceList, err := c.azureVMsClient.List(resourceGroupName)
	if err != nil {
		return fmt.Errorf("List instances: %s", err)
	}

	for _, instance := range *instanceList.Value {
		vmName := getOrEmpty(instance.Name)
		if instance.Tags == nil {
			return fmt.Errorf("bbl environment is not safe to delete; vms still exist in resource group: %s: %s",
				resourceGroupName, vmName)
		}
		tags := *instance.Tags
		job := getOrEmpty(tags["job"])
		deployment := getOrEmpty(tags["deployment"])
		if deployment != "" {
			deployment = fmt.Sprintf(" (deployment: %s)", deployment)
		}
		if job != "bosh" && job != "jumpbox" {
			return fmt.Errorf("bbl environment is not safe to delete; vms still exist in resource group: %s%s: %s",
				resourceGroupName, deployment, vmName)
		}
	}

	return nil
}

func getOrEmpty(value *string) string {
	if value == nil {
		return ""
	}
	return *value
}
<commit_msg>Reformat azure client for checking vm existence.<commit_after>package azure

import (
	"fmt"
	"net/http"

	"github.com/Azure/azure-sdk-for-go/arm/compute"
	"github.com/Azure/go-autorest/autorest"
)

type Client struct {
	azureVMsClient    AzureVMsClient
	azureGroupsClient AzureGroupsClient
}

type AzureVMsClient interface {
	List(resourceGroup string) (compute.VirtualMachineListResult, error)
}

type AzureGroupsClient interface {
	CheckExistence(resourceGroupName string) (autorest.Response, error)
}

func (c Client) CheckExists(envID string) (bool, error) {
	resourceGroupName := fmt.Sprintf("%s-bosh", envID)

	response, err := c.azureGroupsClient.CheckExistence(resourceGroupName)
	if err != nil {
		return false, fmt.Errorf("Check existence for resource group %s: %s", resourceGroupName, err)
	}

	if response.StatusCode == http.StatusOK {
		return true, nil
	}

	return false, nil
}

func (c Client) ValidateSafeToDelete(networkName string, envID string) error {
	resourceGroup := fmt.Sprintf("%s-bosh", envID)

	instances, err := c.azureVMsClient.List(resourceGroup)
	if err != nil {
		return fmt.Errorf("List instances: %s", err)
	}

	for _, instance := range *instances.Value {
		var vm string
		if instance.Name != nil {
			vm = *instance.Name
		}

		if instance.Tags == nil {
			return fmt.Errorf("bbl environment is not safe to delete; vms still exist in resource group: %s: %s", resourceGroup, vm)
		}

		tags := *instance.Tags

		var deployment string
		if tags["deployment"] != nil {
			deployment = fmt.Sprintf(" (deployment: %s)", *tags["deployment"])
		}

		var job string
		if tags["job"] != nil {
			job = *tags["job"]
		}

		if job != "bosh" && job != "jumpbox" {
			return fmt.Errorf("bbl environment is not safe to delete; vms still exist in resource group: %s%s: %s", resourceGroup, deployment, vm)
		}
	}

	return nil
}
<|endoftext|>


<commit_before>// Package basex generates alpha id (alphanumeric id) for big integers.  This
// is particularly useful for shortening URLs.
package basex

import (
	"math/big"
	"strconv"
)

var (
	dictionary = []byte{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}
)

//Converts the big integer to alpha id(An alpha numeric id with mixed cases)
func Encode(val string) string {
	var result []byte
	var index int
	var strVal string

	base := big.NewInt(int64(len(dictionary)))
	a := big.NewInt(0)
	b := big.NewInt(0)
	c := big.NewInt(0)
	d := big.NewInt(0)

	exponent := 1

	remaining := big.NewInt(0)
	remaining.SetString(val, 10)

	for remaining.Cmp(big.NewInt(0)) != 0 {

		a.Exp(base, big.NewInt(int64(exponent)), nil) //16^1 = 16
		b := b.Mod(remaining, a)                      //119 % 16 = 7 | 112 % 256 = 112
		c := c.Exp(base, big.NewInt(int64(exponent-1)), nil)
		d := d.Div(b, c)

		//if d > dictionary.length, we have a problem. but BigInteger doesnt have
		//a greater than method :-(  hope for the best. theoretically, d is always
		//an index of the dictionary!
		strVal = d.String()
		index, _ = strconv.Atoi(strVal)
		result = append(result, dictionary[index])
		remaining = remaining.Sub(remaining, b) //119 - 7 = 112 | 112 - 112 = 0
		exponent = exponent + 1
	}

	//need to reverse it, since the start of the list contains the least significant values
	return string(reverse(result))
}

//Converts the alpha id to big integer
func Decode(s string) string {
	//reverse it, coz its already reversed!
	chars2 := reverse([]byte(s))

	//for efficiency, make a map
	var dictMap map[byte]*big.Int
	dictMap = make(map[byte]*big.Int)

	j := 0
	for _, val := range dictionary {
		dictMap[val] = big.NewInt(int64(j))
		j = j + 1
	}

	bi := big.NewInt(0)
	base := big.NewInt(int64(len(dictionary)))

	exponent := 0
	a := big.NewInt(0)
	b := big.NewInt(0)
	intermed := big.NewInt(0)

	for _, c := range chars2 {
		a = dictMap[c]
		intermed = intermed.Exp(base, big.NewInt(int64(exponent)), nil)
		b = b.Mul(intermed, a)
		bi = bi.Add(bi, b)
		exponent = exponent + 1
	}
	return bi.String()
}

func reverse(bs []byte) []byte {
	for i, j := 0, len(bs)-1; i < j; i, j = i+1, j-1 {
		bs[i], bs[j] = bs[j], bs[i]
	}
	return bs
}
<commit_msg>Corrected comments to satisfy golint.<commit_after>// Package basex generates alpha id (alphanumeric id) for big integers.  This
// is particularly useful for shortening URLs.
package basex

import (
	"math/big"
	"strconv"
)

var (
	dictionary = []byte{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}
)

// Encode converts the big integer to alpha id (an alphanumeric id with mixed cases)
func Encode(val string) string {
	var result []byte
	var index int
	var strVal string

	base := big.NewInt(int64(len(dictionary)))
	a := big.NewInt(0)
	b := big.NewInt(0)
	c := big.NewInt(0)
	d := big.NewInt(0)

	exponent := 1

	remaining := big.NewInt(0)
	remaining.SetString(val, 10)

	for remaining.Cmp(big.NewInt(0)) != 0 {

		a.Exp(base, big.NewInt(int64(exponent)), nil) //16^1 = 16
		b = b.Mod(remaining, a)                      //119 % 16 = 7 | 112 % 256 = 112
		c = c.Exp(base, big.NewInt(int64(exponent-1)), nil)
		d = d.Div(b, c)

		//if d > dictionary.length, we have a problem. but BigInteger doesnt have
		//a greater than method :-(  hope for the best. theoretically, d is always
		//an index of the dictionary!
		strVal = d.String()
		index, _ = strconv.Atoi(strVal)
		result = append(result, dictionary[index])
		remaining = remaining.Sub(remaining, b) //119 - 7 = 112 | 112 - 112 = 0
		exponent = exponent + 1
	}

	//need to reverse it, since the start of the list contains the least significant values
	return string(reverse(result))
}

// Decode converts the alpha id to big integer
func Decode(s string) string {
	//reverse it, coz its already reversed!
	chars2 := reverse([]byte(s))

	//for efficiency, make a map
	var dictMap map[byte]*big.Int
	dictMap = make(map[byte]*big.Int)

	j := 0
	for _, val := range dictionary {
		dictMap[val] = big.NewInt(int64(j))
		j = j + 1
	}

	bi := big.NewInt(0)
	base := big.NewInt(int64(len(dictionary)))

	exponent := 0
	a := big.NewInt(0)
	b := big.NewInt(0)
	intermed := big.NewInt(0)

	for _, c := range chars2 {
		a = dictMap[c]
		intermed = intermed.Exp(base, big.NewInt(int64(exponent)), nil)
		b = b.Mul(intermed, a)
		bi = bi.Add(bi, b)
		exponent = exponent + 1
	}
	return bi.String()
}

func reverse(bs []byte) []byte {
	for i, j := 0, len(bs)-1; i < j; i, j = i+1, j-1 {
		bs[i], bs[j] = bs[j], bs[i]
	}
	return bs
}
<|endoftext|>


<commit_before>/*
   Nging is a toolbox for webmasters
   Copyright (C) 2018-present  Wenhui Shen <swh@admpub.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published
   by the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

package term

import (
	"fmt"
	"log"
	"net/http"
	"net/url"
	"os"
	"path/filepath"

	"github.com/webx-top/echo"

	"github.com/admpub/nging/application/dbschema"
	"github.com/admpub/nging/application/handler"
	"github.com/admpub/nging/application/library/config"
	"github.com/admpub/nging/application/model"
	termConfig "github.com/admpub/web-terminal/config"
	termHandler "github.com/admpub/web-terminal/handler"
)

type TerminalParam struct {
	Query url.Values
	User  *dbschema.NgingSshUser
}

type key string

var contextKey key = `param`

func init() {
	handler.RegisterToGroup(`/term`, func(g echo.RouteRegister) {
		g.Route(`GET`, `/account`, AccountIndex)
		g.Route(`GET,POST`, `/account_add`, AccountAdd)
		g.Route(`GET,POST`, `/account_edit`, AccountEdit)
		g.Route(`GET,POST`, `/account_delete`, AccountDelete)
		g.Route(`GET`, `/client`, Client)
		g.Route(`GET,POST`, `/sftp`, Sftp)
		termHandler.ParamGet = func(ctx *termHandler.Context, name string) (value string) {
			/*
				defer func() {
					fmt.Println(`web-terminal: [param]`, name, `->`, value)
				}()
			// */
			var (
				param *TerminalParam
				val   interface{}
				ok    bool
			)
			if val, ok = ctx.Data.Load(contextKey); ok {
				param, ok = val.(*TerminalParam)
			}
			if !ok {
				param = &TerminalParam{
					Query: ctx.Request().URL.Query(),
				}

				id := param.Query.Get(`id`)
				if len(id) > 0 {
					m := model.NewSshUser(nil)
					err := m.Get(nil, `id`, id)
					if err == nil {
						param.User = m.NgingSshUser
					}
				}
				ctx.Data.Store(contextKey, param)
			}
			if param.User != nil {
				switch name {
				case `password`:
					return config.DefaultConfig.Decode(param.User.Password)
				case `user`:
					return param.User.Username
				case `protocol`:
					return param.User.Protocol
				case `hostname`:
					return param.User.Host
				case `port`:
					return fmt.Sprint(param.User.Port)
				case `privateKey`:
					return param.User.PrivateKey
				case `passphrase`:
					return config.DefaultConfig.Decode(param.User.Passphrase)
				case `charset`:
					if len(param.User.Charset) == 0 {
						return `UTF-8`
					}
					return param.User.Charset
				}
			}
			value = param.Query.Get(name)
			if name == `password` {
				value = config.DefaultConfig.Decode(value)
			}
			return value
		}
		termConfig.Default.APPRoot = `/client/`
		termConfig.Default.Debug = config.DefaultConfig.Debug
		logDir := filepath.Join(echo.Wd(), `data/logs`)
		err := os.MkdirAll(logDir, os.ModePerm)
		if err != nil {
			log.Println(err)
		}
		termConfig.Default.LogDir = filepath.Join(logDir, `term`)
		termConfig.Default.ResourceDir = `public/xterm`
		termConfig.Default.MIBSDir = filepath.Join(echo.Wd(), `data/mibs`)
		err = os.MkdirAll(termConfig.Default.MIBSDir, os.ModePerm)
		if err != nil {
			log.Println(err)
		}
		termConfig.Default.SetDefault()
		termHandler.Register(termConfig.Default.APPRoot, func(path string, h http.Handler) {
			g.Any(path, h)
		})
		g.Route(`GET`, `/group`, GroupIndex)
		g.Route(`GET,POST`, `/group_add`, GroupAdd)
		g.Route(`GET,POST`, `/group_edit`, GroupEdit)
		g.Route(`GET,POST`, `/group_delete`, GroupDelete)
	})
}
<commit_msg>update<commit_after>/*
   Nging is a toolbox for webmasters
   Copyright (C) 2018-present  Wenhui Shen <swh@admpub.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published
   by the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

package term

import (
	"fmt"
	"log"
	"net/http"
	"net/url"
	"os"
	"path/filepath"

	"github.com/webx-top/echo"

	"github.com/admpub/nging/application/dbschema"
	"github.com/admpub/nging/application/handler"
	"github.com/admpub/nging/application/library/config"
	"github.com/admpub/nging/application/model"
	termConfig "github.com/admpub/web-terminal/config"
	termHandler "github.com/admpub/web-terminal/handler"
)

type TerminalParam struct {
	Query url.Values
	User  *dbschema.NgingSshUser
}

type key string

var contextKey key = `param`

func init() {
	handler.RegisterToGroup(`/term`, func(g echo.RouteRegister) {
		g.Route(`GET`, `/account`, AccountIndex)
		g.Route(`GET,POST`, `/account_add`, AccountAdd)
		g.Route(`GET,POST`, `/account_edit`, AccountEdit)
		g.Route(`GET,POST`, `/account_delete`, AccountDelete)
		g.Route(`GET`, `/client`, Client)
		g.Route(`GET,POST`, `/sftp`, Sftp)
		termHandler.ParamGet = func(ctx *termHandler.Context, name string) (value string) {
			/*
				defer func() {
					fmt.Println(`web-terminal: [param]`, name, `->`, value)
				}()
			// */
			var (
				param *TerminalParam
				val   interface{}
				ok    bool
			)
			if val, ok = ctx.Data.Load(contextKey); ok {
				param, ok = val.(*TerminalParam)
			}
			if !ok {
				param = &TerminalParam{
					Query: ctx.Request().URL.Query(),
				}

				id := param.Query.Get(`id`)
				if len(id) > 0 {
					m := model.NewSshUser(nil)
					err := m.Get(nil, `id`, id)
					if err == nil {
						param.User = m.NgingSshUser
					}
				}
				ctx.Data.Store(contextKey, param)
			}
			if param.User != nil {
				switch name {
				case `password`:
					return config.DefaultConfig.Decode(param.User.Password)
				case `user`:
					return param.User.Username
				case `protocol`:
					return param.User.Protocol
				case `hostname`:
					return param.User.Host
				case `port`:
					return fmt.Sprint(param.User.Port)
				case `privateKey`:
					return param.User.PrivateKey
				case `passphrase`:
					return config.DefaultConfig.Decode(param.User.Passphrase)
				case `charset`:
					if len(param.User.Charset) == 0 {
						return `UTF-8`
					}
					return param.User.Charset
				}
			}
			value = param.Query.Get(name)
			if name == `password` {
				value = config.DefaultConfig.Decode(value)
			}
			return value
		}
		termConfig.Default.APPRoot = handler.BackendPrefix + `/client/`
		termConfig.Default.Debug = config.DefaultConfig.Debug
		logDir := filepath.Join(echo.Wd(), `data/logs`)
		err := os.MkdirAll(logDir, os.ModePerm)
		if err != nil {
			log.Println(err)
		}
		termConfig.Default.LogDir = filepath.Join(logDir, `term`)
		termConfig.Default.ResourceDir = `public/xterm`
		termConfig.Default.MIBSDir = filepath.Join(echo.Wd(), `data/mibs`)
		err = os.MkdirAll(termConfig.Default.MIBSDir, os.ModePerm)
		if err != nil {
			log.Println(err)
		}
		termConfig.Default.SetDefault()
		termHandler.Register(termConfig.Default.APPRoot, func(path string, h http.Handler) {
			g.Any(path, h)
		})
		g.Route(`GET`, `/group`, GroupIndex)
		g.Route(`GET,POST`, `/group_add`, GroupAdd)
		g.Route(`GET,POST`, `/group_edit`, GroupEdit)
		g.Route(`GET,POST`, `/group_delete`, GroupDelete)
	})
}
<|endoftext|>


<commit_before><commit_msg>windows dirx fix<commit_after><|endoftext|>