<commit_before>package main

// This script polls ETCD and executes Chef knife solo cook.

import (
	"bufio"
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"strings"

	"code.google.com/p/goauth2/oauth"
	"github.com/coreos/go-etcd/etcd"
	"github.com/gengo/goship/lib"
	"github.com/google/go-github/github"
	"github.com/kylelemons/go-gypsy/yaml"
)

var (
	deployProj = flag.String("p", "", "project (required)")
	deployEnv  = flag.String("e", "", "environment (required)")
	configFile = flag.String("g", "/tmp/deploy.yaml", "shared config setting ( default ./deploy.yaml)")
	pullOnly   = flag.Bool("o", false, "chef update only (default false)")
	skipUpdate = flag.Bool("m", false, "skip the chef update (default false)")
	bootstrap  = flag.Bool("b", false, "bootstrap a server ( default false)")
)

// gitHubPaginationLimit is the default pagination limit for requests to the GitHub API that return multiple items.
const (
	gitHubPaginationLimit = 30
	gitHubAPITokenEnvVar  = "GITHUB_API_TOKEN"
)

// config contains the information from config.yml.
type config struct {
	chefRepo   string
	chefPath   string
	knifePath  string
	pemKey     string
	deployUser string
}

func checkMissingConf(s, v, f string) {
	if len(s) < 1 {
		log.Fatalf("Warning: Missing %s in config file [%s]", v, f)
	}
}

func parseConfig() (c config) {
	config, err := yaml.ReadFile(*configFile)
	if err != nil {
		log.Fatalf("Fatal: Can't parse conf file %s", *configFile)
	}
	c.chefPath, err = config.Get("chef_path")
	checkMissingConf(c.chefPath, "chef_path", *configFile)
	c.knifePath, _ = config.Get("knife_path")
	checkMissingConf(c.knifePath, "knife_path", *configFile)
	c.pemKey, err = config.Get("pem_key")
	checkMissingConf(c.pemKey, "pem_key", *configFile)
	c.deployUser, err = config.Get("deploy_user")
	checkMissingConf(c.deployUser, "deploy_user", *configFile)
	return c
}

// updateChefRepo ensures the lates chef cookbooks are pulled before deploying.
// Checks github first and ignores pull if already up to date.
func updateChefRepo(conf config) {
	githubToken := os.Getenv(gitHubAPITokenEnvVar)
	t := &oauth.Transport{
		Token: &oauth.Token{AccessToken: githubToken},
	}
	client := github.NewClient(t.Client())
	s := "git --git-dir=" + conf.chefRepo + "/.git rev-parse HEAD"
	localHash, _ := execCmd(s, conf)
	commits, _, err := client.Repositories.ListCommits("Gengo", "devops-tools", nil)
	if err != nil {
		log.Fatal("ERROR:  failed to get commits from GitHub: Please try again later ", err)
	}
	remoteHash := *commits[0].SHA
	if localHash == remoteHash {
		log.Printf("Local Chef is up to date: Skipping Sync")
	} else {
		log.Printf("Chef is not up to date: \n %s does not equal %s", localHash, remoteHash)
		log.Println("Updating devops-tools")
		os.Setenv("GIT_SSH", "/tmp/private_code/wrap-ssh4git.sh")
		gitcmd := "/usr/bin/git --git-dir=" + conf.chefRepo + "/.git --work-tree=" + conf.chefRepo + " pull origin master"
		s := gitcmd
		_, err := execCmd(s, conf)
		if err != nil {
			log.Fatal("ERROR:  Failed to pull latest devops_tools: ", err)
		}
		log.Println("Devops Tools Updated")
	}
}

func execCmd(icmd string, conf config) (output string, err error) {
	os.Chdir(conf.chefPath)

	parts := strings.Fields(icmd)
	head := parts[0]
	parts = parts[1:len(parts)]

	cmd := exec.Command(head, parts...)
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		log.Fatal(err)
	}
	stderr, err := cmd.StderrPipe()
	if err != nil {
		log.Fatal(err)
	}
	if err := cmd.Start(); err != nil {
		log.Fatal(err)
	}
	scanner := bufio.NewScanner(stdout)
	for scanner.Scan() {
		o := scanner.Text()
		output += o
		fmt.Println(o)

	}
	if err := scanner.Err(); err != nil {
		log.Printf("Error reading standard output stream: %s", err)
	}
	scanner = bufio.NewScanner(stderr)
	for scanner.Scan() {
		log.Println(scanner.Text())
	}
	if err := scanner.Err(); err != nil {
		log.Printf("Error reading standard error stream: %s", err)
	}
	if err := cmd.Wait(); err != nil {
		log.Fatalf("Error waiting for Chef to complete %s", err)
	}
	return output, err
}

func main() {
	flag.Parse()
	conf := parseConfig()
	if *skipUpdate == false {
		updateChefRepo(conf)
	}
	if *pullOnly == false {
		c, err := goship.ParseETCD(etcd.NewClient([]string{"http://127.0.0.1:4001"}))
		if err != nil {
			log.Fatalf("Error parsing ETCD: %s", err)
		}
		projectEnv, err := goship.EnvironmentFromName(c.Projects, *deployProj, *deployEnv)
		if err != nil {
			log.Fatalf("Error getting project %s %s %s", *deployProj, *deployEnv, err)
		}
		log.Printf("Deploying project name: %s environment Name: %s", *deployEnv, projectEnv.Name)
		servers := projectEnv.Hosts
		var d string
		for _, h := range servers {
			if *bootstrap == true {
				d = "knife solo bootstrap -c " + conf.knifePath + " -i " + conf.pemKey + " --no-host-key-verify " + conf.deployUser + "@" + h.URI
			} else {
				d = "knife solo cook -c " + conf.knifePath + " -i " + conf.pemKey + " --no-host-key-verify " + conf.deployUser + "@" + h.URI
			}
			log.Printf("Deploying to server: %s", h.URI)
			log.Printf("Preparing Knife command: %s", d)
			_, err := execCmd(d, conf)
			if err != nil {
				log.Fatalf("Error Executing command %s", err)
			}
		}
	}

}
<commit_msg>Fix missing config setting and add default /tmp to deploy<commit_after>package main

// This script polls ETCD and executes Chef knife solo cook.

import (
	"bufio"
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"strings"

	"code.google.com/p/goauth2/oauth"
	"github.com/coreos/go-etcd/etcd"
	"github.com/gengo/goship/lib"
	"github.com/google/go-github/github"
	"github.com/kylelemons/go-gypsy/yaml"
)

var (
	deployProj = flag.String("p", "", "project (required)")
	deployEnv  = flag.String("e", "", "environment (required)")
	configFile = flag.String("g", "/tmp/deploy.yaml", "shared config setting ( default /tmp/deploy.yaml)")
	pullOnly   = flag.Bool("o", false, "chef update only (default false)")
	skipUpdate = flag.Bool("m", false, "skip the chef update (default false)")
	bootstrap  = flag.Bool("b", false, "bootstrap a server ( default false)")
)

// gitHubPaginationLimit is the default pagination limit for requests to the GitHub API that return multiple items.
const (
	gitHubPaginationLimit = 30
	gitHubAPITokenEnvVar  = "GITHUB_API_TOKEN"
)

// config contains the information from config.yml.
type config struct {
	chefRepo   string
	chefPath   string
	knifePath  string
	pemKey     string
	deployUser string
}

func checkMissingConf(s, v, f string) {
	if len(s) < 1 {
		log.Fatalf("Warning: Missing %s in config file [%s]", v, f)
	}
}

func parseConfig() (c config) {
	config, err := yaml.ReadFile(*configFile)
	if err != nil {
		log.Fatalf("Fatal: Can't parse conf file %s", *configFile)
	}
	c.chefRepo, err = config.Get("chef_repo")
	checkMissingConf(c.chefRepo, "chef_repo", *configFile)
	c.chefPath, err = config.Get("chef_path")
	checkMissingConf(c.chefPath, "chef_path", *configFile)
	c.knifePath, _ = config.Get("knife_path")
	checkMissingConf(c.knifePath, "knife_path", *configFile)
	c.pemKey, err = config.Get("pem_key")
	checkMissingConf(c.pemKey, "pem_key", *configFile)
	c.deployUser, err = config.Get("deploy_user")
	checkMissingConf(c.deployUser, "deploy_user", *configFile)
	return c
}

// updateChefRepo ensures the lates chef cookbooks are pulled before deploying.
// Checks github first and ignores pull if already up to date.
func updateChefRepo(conf config) {
	githubToken := os.Getenv(gitHubAPITokenEnvVar)
	t := &oauth.Transport{
		Token: &oauth.Token{AccessToken: githubToken},
	}
	client := github.NewClient(t.Client())
	s := "git --git-dir=" + conf.chefRepo + "/.git rev-parse HEAD"
	localHash, _ := execCmd(s, conf)
	commits, _, err := client.Repositories.ListCommits("Gengo", "devops-tools", nil)
	if err != nil {
		log.Fatal("ERROR:  failed to get commits from GitHub: Please try again later ", err)
	}
	remoteHash := *commits[0].SHA
	if localHash == remoteHash {
		log.Printf("Local Chef is up to date: Skipping Sync")
	} else {
		log.Printf("Chef is not up to date: \n %s does not equal %s", localHash, remoteHash)
		log.Println("Updating devops-tools")
		os.Setenv("GIT_SSH", "/tmp/private_code/wrap-ssh4git.sh")
		gitcmd := "/usr/bin/git --git-dir=" + conf.chefRepo + "/.git --work-tree=" + conf.chefRepo + " pull origin master"
		s := gitcmd
		_, err := execCmd(s, conf)
		if err != nil {
			log.Fatal("ERROR:  Failed to pull latest devops_tools: ", err)
		}
		log.Println("Devops Tools Updated")
	}
}

func execCmd(icmd string, conf config) (output string, err error) {
	os.Chdir(conf.chefPath)

	parts := strings.Fields(icmd)
	head := parts[0]
	parts = parts[1:len(parts)]

	cmd := exec.Command(head, parts...)
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		log.Fatal(err)
	}
	stderr, err := cmd.StderrPipe()
	if err != nil {
		log.Fatal(err)
	}
	if err := cmd.Start(); err != nil {
		log.Fatal(err)
	}
	scanner := bufio.NewScanner(stdout)
	for scanner.Scan() {
		o := scanner.Text()
		output += o
		fmt.Println(o)

	}
	if err := scanner.Err(); err != nil {
		log.Printf("Error reading standard output stream: %s", err)
	}
	scanner = bufio.NewScanner(stderr)
	for scanner.Scan() {
		log.Println(scanner.Text())
	}
	if err := scanner.Err(); err != nil {
		log.Printf("Error reading standard error stream: %s", err)
	}
	if err := cmd.Wait(); err != nil {
		log.Fatalf("Error waiting for Chef to complete %s", err)
	}
	return output, err
}

func main() {
	flag.Parse()
	conf := parseConfig()
	if *skipUpdate == false {
		updateChefRepo(conf)
	}
	if *pullOnly == false {
		c, err := goship.ParseETCD(etcd.NewClient([]string{"http://127.0.0.1:4001"}))
		if err != nil {
			log.Fatalf("Error parsing ETCD: %s", err)
		}
		projectEnv, err := goship.EnvironmentFromName(c.Projects, *deployProj, *deployEnv)
		if err != nil {
			log.Fatalf("Error getting project %s %s %s", *deployProj, *deployEnv, err)
		}
		log.Printf("Deploying project name: %s environment Name: %s", *deployEnv, projectEnv.Name)
		servers := projectEnv.Hosts
		var d string
		for _, h := range servers {
			if *bootstrap == true {
				d = "knife solo bootstrap -c " + conf.knifePath + " -i " + conf.pemKey + " --no-host-key-verify " + conf.deployUser + "@" + h.URI
			} else {
				d = "knife solo cook -c " + conf.knifePath + " -i " + conf.pemKey + " --no-host-key-verify " + conf.deployUser + "@" + h.URI
			}
			log.Printf("Deploying to server: %s", h.URI)
			log.Printf("Preparing Knife command: %s", d)
			_, err := execCmd(d, conf)
			if err != nil {
				log.Fatalf("Error Executing command %s", err)
			}
		}
	}

}
<|endoftext|>


<commit_before>/*

		ernst.go
		A very unfriendly IRC bot

*/

package main

import (
	"github.com/thoj/go-ircevent"
	"github.com/boltdb/bolt"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"time"
	"math/rand"
	"strings"
	"strconv"
	elib "github.com/bnaucler/ernst/elib"
)

const dbname = "./ernst.db"
const erresp = "Vad fan är det frågan om?"

func askymf(db *bolt.DB, irccon *irc.Connection, event *irc.Event,
	rnd *rand.Rand, settings elib.Settings, skymf string) int {

	settings.Numln++
	senc, _ := json.Marshal(settings)
	err := elib.Wrdb(db, settings.Numln, []byte(skymf))

	if err == nil {
		err := elib.Wrdb(db, 0, senc)
		elib.Cherr(err)
		resp := fmt.Sprintf("%v: lade till \"%v\"", event.Nick, skymf)
		time.Sleep(time.Duration(len(resp) * settings.Kdel +
			rnd.Intn(settings.Randel)) * time.Millisecond)
		irccon.Privmsg(settings.Channel, resp)
	} else {
		elib.Cherr(err)
	}
	return settings.Numln
}

func rskymf(irccon *irc.Connection, db *bolt.DB, event *irc.Event,
	rnd *rand.Rand, settings *elib.Settings, lastsk []int) []int {

	resp := "Kunde ej ta bort skymf"
	dbch := false
	var rsk string

	bar, err := elib.Rdb(db, lastsk[0])
	rsk = string(bar)
	irccon.Privmsg(settings.Channel, rsk)

	if lastsk[0] != settings.Numln && lastsk[0] != 0 && err == nil {
		tmps, err := elib.Rdb(db, settings.Numln)

		if err == nil {
			err = elib.Wrdb(db, lastsk[0], tmps)
			dbch = true
		}
	} else if lastsk[0] == settings.Numln {
		dbch = true
	}

	if dbch {
		settings.Numln--;
		senc, _ := json.Marshal(settings)
		err = elib.Wrdb(db, 0, senc)
		resp = fmt.Sprintf("Skymf \"%v\" borttagen.", rsk)

		for a := 0; a < elib.Dnrmemmax - 1; a++ { lastsk[a] = lastsk[(a + 1)] }
	}

	time.Sleep(time.Duration(len(resp) * settings.Kdel +
		rnd.Intn(settings.Randel)) * time.Millisecond)
	irccon.Privmsg(settings.Channel, resp)

	return lastsk
}

func sskymf(irccon *irc.Connection, db *bolt.DB, rnd *rand.Rand,
	target string, settings elib.Settings, lastsk []int, ln int) []int {

	if ln == 0 && settings.Dnrmem > 0 {
		inmem := true
		for inmem {
			ln = rnd.Intn(settings.Numln - 1) + 1
			inmem = false
			for a := 0; a < settings.Dnrmem; a++ {
				if ln == lastsk[a] {
					inmem = true
				}
			}
		}
	}

	skymf, err := elib.Rdb(db, ln)
	elib.Cherr(err)
	time.Sleep(time.Duration(len(skymf) *
		settings.Kdel + rnd.Intn(settings.Randel)) * time.Millisecond)

	resp := fmt.Sprintf("%v: %v", target, string(skymf))
	irccon.Privmsg(settings.Channel, resp)

	if settings.Dnrmem > 0 {
		for a := settings.Dnrmem - 1; a > 0; a-- { lastsk[a] = lastsk[(a - 1)] }
		lastsk[0] = ln
	}

	return lastsk
}

func fskymf(irccon *irc.Connection, db *bolt.DB, rnd *rand.Rand,
	target string, kw []string, settings elib.Settings, lastsk []int) []int {

	kwln := len(kw)
	var (reqnum, cqual, tqual int)
	lckw := make([]string, kwln)

	for a := 0; a < kwln; a++ { lckw[a] = strings.ToLower(kw[a]) }

	for k := 0; k <= settings.Numln; k++ {
		v, err := elib.Rdb(db, k)
		cqual = 0
		cstr := string(v)
		for a := 0; a < kwln; a++ {
			if strings.Contains(cstr, lckw[a]) {
				cqual++
				if cqual > tqual {
					tqual = cqual
					reqnum = k
				}
			}
		}
		elib.Cherr(err)
	}

	return sskymf(irccon, db, rnd, target, settings, lastsk, reqnum)
}

func csetshow(event *irc.Event, settings *elib.Settings, setvar string) (resp string) {

	if setvar == "rate" {
		resp = fmt.Sprintf("%v: %v: %d/%d", event.Nick,
			setvar, settings.Rate, elib.Ratemax)
	} else if setvar == "kdel" {
		resp = fmt.Sprintf("%v: %v: %d/%d", event.Nick,
			setvar, settings.Kdel, elib.Kdelmax)
	} else if setvar == "randel" {
		resp = fmt.Sprintf("%v: %v: %d/%d", event.Nick,
			setvar, settings.Randel, elib.Randelmax)
	} else if setvar == "dnrmem" {
		resp = fmt.Sprintf("%v: %v: %d/%d", event.Nick,
			setvar, settings.Dnrmem, elib.Dnrmemmax)
	} else {
		resp = fmt.Sprintf("%v: %v", event.Nick, erresp)
	}

	return
}

func csetset(event *irc.Event, settings *elib.Settings, setvar,
	setval string) (resp string, dbchange bool) {

	nval, nerr := strconv.Atoi(setval)

	if setvar == "rate"  && nerr == nil && nval > -1 && nval <= elib.Ratemax {
		if settings.Rate != nval { dbchange = true }
		settings.Rate = nval
		resp = fmt.Sprintf("%v: %s: %d/%d", event.Nick, setvar, settings.Rate, elib.Ratemax)

	} else if setvar == "kdel" && nerr == nil && nval > -1 && nval <= elib.Kdelmax {
		if settings.Kdel != nval { dbchange = true }
		settings.Kdel = nval
		resp = fmt.Sprintf("%v: %s: %d/%d", event.Nick, setvar, settings.Kdel, elib.Kdelmax)

	} else if setvar == "randel" && nerr == nil && nval > -1 && nval <= elib.Randelmax {
		if settings.Randel != nval { dbchange = true }
		settings.Randel = nval
		resp = fmt.Sprintf("%v: %s: %d/%d", event.Nick, setvar, settings.Randel, elib.Randelmax)

	} else if setvar == "dnrmem" && nerr == nil && nval > -1 && nval <= elib.Dnrmemmax {
		if settings.Dnrmem != nval { dbchange = true }
		settings.Dnrmem = nval
		resp = fmt.Sprintf("%v: %s: %d/%d", event.Nick, setvar, settings.Dnrmem, elib.Dnrmemmax)
	} else {
		resp = fmt.Sprintf("%v: %v", event.Nick, erresp)
	}

	return
}

func cset(irccon *irc.Connection, db *bolt.DB, rnd *rand.Rand,
	event *irc.Event, settings *elib.Settings) bool {

	ssp := strings.Split(event.Arguments[1], " ")

	var (
		setvar, setval, resp string
		dbchange bool
	)

	if len(ssp) > 1 { setvar = strings.ToLower(ssp[1]) }
	if len(ssp) > 2 { setval = ssp[2] }

	if len(ssp) == 1 { resp = csetlist(event, settings)
	} else if len(ssp) == 2 { resp = csetshow(event, settings, setvar)
	} else if len(ssp) == 3 {
		resp, dbchange = csetset (event, settings, setvar, setval)
	}

	if len(resp) != 0 {
		if dbchange {
			s, err:= json.Marshal(settings)
			elib.Cherr(err)
			err = elib.Wrdb(db, 0, s)
			elib.Cherr(err)
		}
		irccon.Privmsg(settings.Channel, resp)
	}

	return true
}

func main() {

    rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
	settings := elib.Settings{}
	incrt := 0

	db, err := bolt.Open(dbname, 0640, nil)
	elib.Cherr(err)
	defer db.Close()

	tmp, err := elib.Rdb(db, 0)
	elib.Cherr(err)
	json.Unmarshal(tmp, &settings)

	var lastsk = make([]int, elib.Dnrmemmax)

	irccon := irc.IRC(settings.Ircnick, settings.Uname)

	irccon.VerboseCallbackHandler = true
	irccon.Debug = true
	irccon.UseTLS = true
	irccon.TLSConfig = &tls.Config{InsecureSkipVerify: true}
	irccon.AddCallback("001", func(e *irc.Event) { irccon.Join(settings.Channel) })

	irccon.AddCallback("PRIVMSG", func(event *irc.Event) {
		go func(event *irc.Event) {

			lcnick := strings.ToLower(settings.Ircnick)
			lcstr := strings.ToLower(event.Arguments[1])
			keytr := fmt.Sprintf("%s ", elib.Addkey)

			if event.Arguments[0] == settings.Channel && strings.HasPrefix(lcstr, keytr) {

				keytr := fmt.Sprintf("%s ", elib.Addkey)
				skymf := strings.TrimPrefix(event.Arguments[1], keytr)
				settings.Numln = askymf(db, irccon, event, rnd, settings, skymf)

			} else if event.Arguments[0] == settings.Channel &&
				strings.HasPrefix(lcstr, elib.Statkey) {

				resp := fmt.Sprintf("Jag kan %d skymfer.", settings.Numln)
				time.Sleep(time.Duration(len(resp) * settings.Kdel +
					rnd.Intn(settings.Randel)) * time.Millisecond)
				irccon.Privmsg(settings.Channel, resp)

			} else if event.Arguments[0] == settings.Channel &&
				strings.HasPrefix(lcstr, elib.Setkey) {

				cset(irccon, db, rnd, event, &settings)

			} else if event.Arguments[0] == settings.Channel &&
				strings.HasPrefix(lcstr, elib.Rmkey) {

				lastsk = rskymf(irccon, db, event, rnd, &settings, lastsk)

			} else if event.Arguments[0] == settings.Channel &&
				strings.Contains(lcstr, lcnick) {

				kw := strings.Split(event.Arguments[1], " ")

				if strings.Contains(kw[0], lcnick) {
					lastsk = fskymf(irccon, db, rnd, event.Nick, kw[1:], settings, lastsk)
				} else {
					lastsk = sskymf(irccon, db, rnd, event.Nick, settings, lastsk, 0)
				}
				incrt = 0

			} else if event.Arguments[0] == settings.Channel &&
				rnd.Intn(elib.Ratemax) < settings.Rate + incrt &&
				event.Nick != settings.Ircnick {

				lastsk = sskymf(irccon, db, rnd, event.Nick, settings, lastsk, 0)
				incrt = 0

			} else if event.Arguments[0] == settings.Ircnick {
				var nval int

				target := strings.Split(event.Arguments[1], " ")
				if len(target) > 1 {
					nval, err = strconv.Atoi(target[1])

					if err == nil && nval > 0 && nval <= settings.Numln {
						lastsk = sskymf(irccon, db, rnd, target[0], settings, lastsk, nval)
						incrt = 0
					} else if nval == 0 {
						lastsk = fskymf(irccon, db, rnd, target[0], target[1:], settings, lastsk)
						incrt = 0
					}

				} else {

					lastsk = sskymf(irccon, db, rnd, target[0], settings, lastsk, 0)
					incrt = 0
				}
			} else {

				incrt++
			}

		}(event)
	});

	err = irccon.Connect(settings.Server)
	elib.Cherr(err)

	irccon.Loop()
}
<commit_msg>Readding csetlist<commit_after>/*

		ernst.go
		A very unfriendly IRC bot

*/

package main

import (
	"github.com/thoj/go-ircevent"
	"github.com/boltdb/bolt"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"time"
	"math/rand"
	"strings"
	"strconv"
	elib "github.com/bnaucler/ernst/elib"
)

const dbname = "./ernst.db"
const erresp = "Vad fan är det frågan om?"

func askymf(db *bolt.DB, irccon *irc.Connection, event *irc.Event,
	rnd *rand.Rand, settings elib.Settings, skymf string) int {

	settings.Numln++
	senc, _ := json.Marshal(settings)
	err := elib.Wrdb(db, settings.Numln, []byte(skymf))

	if err == nil {
		err := elib.Wrdb(db, 0, senc)
		elib.Cherr(err)
		resp := fmt.Sprintf("%v: lade till \"%v\"", event.Nick, skymf)
		time.Sleep(time.Duration(len(resp) * settings.Kdel +
			rnd.Intn(settings.Randel)) * time.Millisecond)
		irccon.Privmsg(settings.Channel, resp)
	} else {
		elib.Cherr(err)
	}
	return settings.Numln
}

func rskymf(irccon *irc.Connection, db *bolt.DB, event *irc.Event,
	rnd *rand.Rand, settings *elib.Settings, lastsk []int) []int {

	resp := "Kunde ej ta bort skymf"
	dbch := false
	var rsk string

	bar, err := elib.Rdb(db, lastsk[0])
	rsk = string(bar)
	irccon.Privmsg(settings.Channel, rsk)

	if lastsk[0] != settings.Numln && lastsk[0] != 0 && err == nil {
		tmps, err := elib.Rdb(db, settings.Numln)

		if err == nil {
			err = elib.Wrdb(db, lastsk[0], tmps)
			dbch = true
		}
	} else if lastsk[0] == settings.Numln {
		dbch = true
	}

	if dbch {
		settings.Numln--;
		senc, _ := json.Marshal(settings)
		err = elib.Wrdb(db, 0, senc)
		resp = fmt.Sprintf("Skymf \"%v\" borttagen.", rsk)

		for a := 0; a < elib.Dnrmemmax - 1; a++ { lastsk[a] = lastsk[(a + 1)] }
	}

	time.Sleep(time.Duration(len(resp) * settings.Kdel +
		rnd.Intn(settings.Randel)) * time.Millisecond)
	irccon.Privmsg(settings.Channel, resp)

	return lastsk
}

func sskymf(irccon *irc.Connection, db *bolt.DB, rnd *rand.Rand,
	target string, settings elib.Settings, lastsk []int, ln int) []int {

	if ln == 0 && settings.Dnrmem > 0 {
		inmem := true
		for inmem {
			ln = rnd.Intn(settings.Numln - 1) + 1
			inmem = false
			for a := 0; a < settings.Dnrmem; a++ {
				if ln == lastsk[a] {
					inmem = true
				}
			}
		}
	}

	skymf, err := elib.Rdb(db, ln)
	elib.Cherr(err)
	time.Sleep(time.Duration(len(skymf) *
		settings.Kdel + rnd.Intn(settings.Randel)) * time.Millisecond)

	resp := fmt.Sprintf("%v: %v", target, string(skymf))
	irccon.Privmsg(settings.Channel, resp)

	if settings.Dnrmem > 0 {
		for a := settings.Dnrmem - 1; a > 0; a-- { lastsk[a] = lastsk[(a - 1)] }
		lastsk[0] = ln
	}

	return lastsk
}

func fskymf(irccon *irc.Connection, db *bolt.DB, rnd *rand.Rand,
	target string, kw []string, settings elib.Settings, lastsk []int) []int {

	kwln := len(kw)
	var (reqnum, cqual, tqual int)
	lckw := make([]string, kwln)

	for a := 0; a < kwln; a++ { lckw[a] = strings.ToLower(kw[a]) }

	for k := 0; k <= settings.Numln; k++ {
		v, err := elib.Rdb(db, k)
		cqual = 0
		cstr := string(v)
		for a := 0; a < kwln; a++ {
			if strings.Contains(cstr, lckw[a]) {
				cqual++
				if cqual > tqual {
					tqual = cqual
					reqnum = k
				}
			}
		}
		elib.Cherr(err)
	}

	return sskymf(irccon, db, rnd, target, settings, lastsk, reqnum)
}

func csetlist(event *irc.Event, settings *elib.Settings) (resp string) {

	resp = fmt.Sprintf("%v: rate: %d/%d, kdel: %d/%d, randel: %d/%d, dnrmem: %d/%d",
		event.Nick, settings.Rate, elib.Ratemax,
		settings.Kdel, elib.Kdelmax, settings.Randel, elib.Randelmax,
		settings.Dnrmem, elib.Dnrmemmax)

	return
}

func csetshow(event *irc.Event, settings *elib.Settings, setvar string) (resp string) {

	if setvar == "rate" {
		resp = fmt.Sprintf("%v: %v: %d/%d", event.Nick,
			setvar, settings.Rate, elib.Ratemax)
	} else if setvar == "kdel" {
		resp = fmt.Sprintf("%v: %v: %d/%d", event.Nick,
			setvar, settings.Kdel, elib.Kdelmax)
	} else if setvar == "randel" {
		resp = fmt.Sprintf("%v: %v: %d/%d", event.Nick,
			setvar, settings.Randel, elib.Randelmax)
	} else if setvar == "dnrmem" {
		resp = fmt.Sprintf("%v: %v: %d/%d", event.Nick,
			setvar, settings.Dnrmem, elib.Dnrmemmax)
	} else {
		resp = fmt.Sprintf("%v: %v", event.Nick, erresp)
	}

	return
}

func csetset(event *irc.Event, settings *elib.Settings, setvar,
	setval string) (resp string, dbchange bool) {

	nval, nerr := strconv.Atoi(setval)

	if setvar == "rate"  && nerr == nil && nval > -1 && nval <= elib.Ratemax {
		if settings.Rate != nval { dbchange = true }
		settings.Rate = nval
		resp = fmt.Sprintf("%v: %s: %d/%d", event.Nick, setvar, settings.Rate, elib.Ratemax)

	} else if setvar == "kdel" && nerr == nil && nval > -1 && nval <= elib.Kdelmax {
		if settings.Kdel != nval { dbchange = true }
		settings.Kdel = nval
		resp = fmt.Sprintf("%v: %s: %d/%d", event.Nick, setvar, settings.Kdel, elib.Kdelmax)

	} else if setvar == "randel" && nerr == nil && nval > -1 && nval <= elib.Randelmax {
		if settings.Randel != nval { dbchange = true }
		settings.Randel = nval
		resp = fmt.Sprintf("%v: %s: %d/%d", event.Nick, setvar, settings.Randel, elib.Randelmax)

	} else if setvar == "dnrmem" && nerr == nil && nval > -1 && nval <= elib.Dnrmemmax {
		if settings.Dnrmem != nval { dbchange = true }
		settings.Dnrmem = nval
		resp = fmt.Sprintf("%v: %s: %d/%d", event.Nick, setvar, settings.Dnrmem, elib.Dnrmemmax)
	} else {
		resp = fmt.Sprintf("%v: %v", event.Nick, erresp)
	}

	return
}

func cset(irccon *irc.Connection, db *bolt.DB, rnd *rand.Rand,
	event *irc.Event, settings *elib.Settings) bool {

	ssp := strings.Split(event.Arguments[1], " ")

	var (
		setvar, setval, resp string
		dbchange bool
	)

	if len(ssp) > 1 { setvar = strings.ToLower(ssp[1]) }
	if len(ssp) > 2 { setval = ssp[2] }

	if len(ssp) == 1 { resp = csetlist(event, settings)
	} else if len(ssp) == 2 { resp = csetshow(event, settings, setvar)
	} else if len(ssp) == 3 {
		resp, dbchange = csetset (event, settings, setvar, setval)
	}

	if len(resp) != 0 {
		if dbchange {
			s, err:= json.Marshal(settings)
			elib.Cherr(err)
			err = elib.Wrdb(db, 0, s)
			elib.Cherr(err)
		}
		irccon.Privmsg(settings.Channel, resp)
	}

	return true
}

func main() {

    rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
	settings := elib.Settings{}
	incrt := 0

	db, err := bolt.Open(dbname, 0640, nil)
	elib.Cherr(err)
	defer db.Close()

	tmp, err := elib.Rdb(db, 0)
	elib.Cherr(err)
	json.Unmarshal(tmp, &settings)

	var lastsk = make([]int, elib.Dnrmemmax)

	irccon := irc.IRC(settings.Ircnick, settings.Uname)

	irccon.VerboseCallbackHandler = true
	irccon.Debug = true
	irccon.UseTLS = true
	irccon.TLSConfig = &tls.Config{InsecureSkipVerify: true}
	irccon.AddCallback("001", func(e *irc.Event) { irccon.Join(settings.Channel) })

	irccon.AddCallback("PRIVMSG", func(event *irc.Event) {
		go func(event *irc.Event) {

			lcnick := strings.ToLower(settings.Ircnick)
			lcstr := strings.ToLower(event.Arguments[1])
			keytr := fmt.Sprintf("%s ", elib.Addkey)

			if event.Arguments[0] == settings.Channel && strings.HasPrefix(lcstr, keytr) {

				keytr := fmt.Sprintf("%s ", elib.Addkey)
				skymf := strings.TrimPrefix(event.Arguments[1], keytr)
				settings.Numln = askymf(db, irccon, event, rnd, settings, skymf)

			} else if event.Arguments[0] == settings.Channel &&
				strings.HasPrefix(lcstr, elib.Statkey) {

				resp := fmt.Sprintf("Jag kan %d skymfer.", settings.Numln)
				time.Sleep(time.Duration(len(resp) * settings.Kdel +
					rnd.Intn(settings.Randel)) * time.Millisecond)
				irccon.Privmsg(settings.Channel, resp)

			} else if event.Arguments[0] == settings.Channel &&
				strings.HasPrefix(lcstr, elib.Setkey) {

				cset(irccon, db, rnd, event, &settings)

			} else if event.Arguments[0] == settings.Channel &&
				strings.HasPrefix(lcstr, elib.Rmkey) {

				lastsk = rskymf(irccon, db, event, rnd, &settings, lastsk)

			} else if event.Arguments[0] == settings.Channel &&
				strings.Contains(lcstr, lcnick) {

				kw := strings.Split(event.Arguments[1], " ")

				if strings.Contains(kw[0], lcnick) {
					lastsk = fskymf(irccon, db, rnd, event.Nick, kw[1:], settings, lastsk)
				} else {
					lastsk = sskymf(irccon, db, rnd, event.Nick, settings, lastsk, 0)
				}
				incrt = 0

			} else if event.Arguments[0] == settings.Channel &&
				rnd.Intn(elib.Ratemax) < settings.Rate + incrt &&
				event.Nick != settings.Ircnick {

				lastsk = sskymf(irccon, db, rnd, event.Nick, settings, lastsk, 0)
				incrt = 0

			} else if event.Arguments[0] == settings.Ircnick {
				var nval int

				target := strings.Split(event.Arguments[1], " ")
				if len(target) > 1 {
					nval, err = strconv.Atoi(target[1])

					if err == nil && nval > 0 && nval <= settings.Numln {
						lastsk = sskymf(irccon, db, rnd, target[0], settings, lastsk, nval)
						incrt = 0
					} else if nval == 0 {
						lastsk = fskymf(irccon, db, rnd, target[0], target[1:], settings, lastsk)
						incrt = 0
					}

				} else {

					lastsk = sskymf(irccon, db, rnd, target[0], settings, lastsk, 0)
					incrt = 0
				}
			} else {

				incrt++
			}

		}(event)
	});

	err = irccon.Connect(settings.Server)
	elib.Cherr(err)

	irccon.Loop()
}
<|endoftext|>


<commit_before>package vkapi

import "fmt"

type Error struct {
	ErrorCode  uint64 `json:"error_code"`
	ErrorMsg   string `json:"error_msg"`
	CaptchaSID string `json:"captcha_sid"`
	CaptchaImg string `json:"captcha_sid"`
}

func (err Error) Error() string {
	if err.CaptchaSID != "" {
		return fmt.Sprintf("vkapi: %s (%d); captcha_sid: %s, captcha_img: %s",
			err.ErrorMsg, err.ErrorCode, err.CaptchaSID, err.CaptchaImg)
	} else {
		return fmt.Sprintf("vkapi: %s (%d)", err.ErrorMsg, err.ErrorCode)
	}
}
<commit_msg>Fixed Error.CaptchaImg JSON tag, added godoc comments for Error<commit_after>package vkapi

import "fmt"

// Error represents vk.com API error: https://vk.com/dev/errors
type Error struct {
	ErrorCode uint64 `json:"error_code"`
	ErrorMsg  string `json:"error_msg"`

	// https://vk.com/dev/captcha_error
	CaptchaSID string `json:"captcha_sid"`
	CaptchaImg string `json:"captcha_img"`
}

// Error returns human-readable error description.
func (err Error) Error() string {
	if err.CaptchaSID != "" {
		return fmt.Sprintf("vkapi: %s (%d); captcha_sid: %s, captcha_img: %s",
			err.ErrorMsg, err.ErrorCode, err.CaptchaSID, err.CaptchaImg)
	} else {
		return fmt.Sprintf("vkapi: %s (%d)", err.ErrorMsg, err.ErrorCode)
	}
}
<|endoftext|>


<commit_before>// Package goa standardizes on structured error responses: a request that fails because of
// invalid input or unexpected condition produces a response that contains one or more structured
// error(s). Each error object has three keys: a id (number), a title and a message. The title
// for a given id is always the same, the intent is to provide a human friendly categorization.
// The message is specific to the error occurrence and provides additional details that often
// include contextual information (name of parameters etc.).
//
// The basic data structure backing errors is TypedError which simply contains the id and message.
// Multiple errors (not just TypedError instances) can be encapsulated in a MultiError. Both
// TypedError and MultiError implement the error interface, the Error methods return valid JSON
// that can be written directly to a response body.
//
// The code generated by goagen calls the helper functions exposed in this file when it encounters
// invalid data (wrong type, validation errors etc.) such as InvalidParamTypeError,
// InvalidAttributeTypeError etc. These methods take and return an error which is a MultiError that
// gets built over time. The final MultiError object then gets serialized into the response and sent
// back to the client. The response status code is inferred from the type wrapping the error object:
// a BadRequestError produces a 400 status code while any other error produce a 500. This behavior
// can be overridden by setting a custom ErrorHandler in the application.
package goa

import (
	"fmt"
	"strings"
)

var (
	// ErrInvalidParamType is the class of errors produced by the generated code when
	// a request parameter type does not match the design.
	ErrInvalidParamType = NewErrorClass("invalid_parameter_type", 400)

	// ErrMissingParam is the error produced by the generated code when a
	// required request parameter is missing.
	ErrMissingParam = NewErrorClass("missing_parameter", 400)

	// ErrInvalidAttributeType is the error produced by the generated
	// code when a data structure attribute type does not match the design
	// definition.
	ErrInvalidAttributeType = NewErrorClass("invalid_attribute", 400)

	// ErrMissingAttribute is the error produced by the generated
	// code when a data structure attribute required by the design
	// definition is missing.
	ErrMissingAttribute = NewErrorClass("missing_attribute", 400)

	// ErrInvalidEnumValue is the error produced by the generated code when
	// a values does not match one of the values listed in the attribute
	// definition as being valid (i.e. not part of the enum).
	ErrInvalidEnumValue = NewErrorClass("invalid_value", 400)

	// ErrMissingHeader is the error produced by the generated code when a
	// required header is missing.
	ErrMissingHeader = NewErrorClass("missing_header", 400)

	// ErrInvalidFormat is the error produced by the generated code when
	// a value does not match the format specified in the attribute
	// definition.
	ErrInvalidFormat = NewErrorClass("invalid_format", 400)

	// ErrInvalidPattern is the error produced by the generated code when
	// a value does not match the regular expression specified in the
	// attribute definition.
	ErrInvalidPattern = NewErrorClass("invalid_pattern", 400)

	// ErrInvalidRange is the error produced by the generated code when
	// a value is less than the minimum specified in the design definition
	// or more than the maximum.
	ErrInvalidRange = NewErrorClass("invalid_range", 400)

	// ErrInvalidLength is the error produced by the generated code when
	// a value is a slice with less elements than the minimum length
	// specified in the design definition or more elements than the
	// maximum length.
	ErrInvalidLength = NewErrorClass("invalid_length", 400)

	// ErrInvalidEncoding is the error produced when a request body fails
	// to be decoded.
	ErrInvalidEncoding = NewErrorClass("invalid_encoding", 400)

	// ErrNoSecurityScheme is the error produced when no security scheme can
	// be found with the given name.
	ErrNoSecurityScheme = NewErrorClass("no_security_scheme", 500)

	// ErrInternal is the class of error used for non HTTPError.
	ErrInternal = NewErrorClass("internal", 500)
)

type (
	// HTTPError describes an error that can be returned in a response.
	HTTPError struct {
		// Code identifies the class of errors for client programs.
		Code string `json:"code" xml:"code"`
		// Status is the HTTP status code used by responses that cary the error.
		Status int `json:"status" xml:"status"`
		// Detail describes the specific error occurrence.
		Detail string `json:"detail" xml:"detail"`
		// MetaValues contains additional key/value pairs useful to clients.
		MetaValues map[string]interface{} `json:"meta,omitempty" xml:"meta,omitempty"`
	}

	// ErrorClass is an error generating function.
	// It accepts a format and values and produces errors with the resulting string.
	// If the format is a string or a Stringer then the string value is used.
	// If the format is an error then the string returned by Error() is used.
	// Otherwise the string produced using fmt.Sprintf("%v") is used.
	ErrorClass func(fm interface{}, v ...interface{}) *HTTPError

	// MultiError is an error composed of potentially multiple errors.
	MultiError []error
)

// NewErrorClass creates a new error class.
// It is the responsability of the client to guarantee uniqueness of code.
func NewErrorClass(code string, status int) ErrorClass {
	return func(fm interface{}, v ...interface{}) *HTTPError {
		var f string
		switch actual := fm.(type) {
		case string:
			f = actual
		case error:
			f = actual.Error()
		case fmt.Stringer:
			f = actual.String()
		default:
			f = fmt.Sprintf("%v", actual)
		}
		return &HTTPError{Code: code, Status: status, Detail: fmt.Sprintf(f, v...)}
	}
}

// InvalidParamTypeError creates a HTTPError with class ID ErrInvalidParamType
func InvalidParamTypeError(name string, val interface{}, expected string) *HTTPError {
	return ErrInvalidParamType("invalid value %#v for parameter %#v, must be a %s", val, name, expected)
}

// MissingParamError creates a HTTPError with class ID ErrMissingParam
func MissingParamError(name string) *HTTPError {
	return ErrMissingParam("missing required parameter %#v", name)
}

// InvalidAttributeTypeError creates a HTTPError with class ID ErrInvalidAttributeType
func InvalidAttributeTypeError(ctx string, val interface{}, expected string) *HTTPError {
	return ErrInvalidAttributeType("type of %s must be %s but got value %#v", ctx, expected, val)
}

// MissingAttributeError creates a HTTPError with class ID ErrMissingAttribute
func MissingAttributeError(ctx, name string) *HTTPError {
	return ErrMissingAttribute("attribute %#v of %s is missing and required", name, ctx)
}

// MissingHeaderError creates a HTTPError with class ID ErrMissingHeader
func MissingHeaderError(name string) *HTTPError {
	return ErrMissingHeader("missing required HTTP header %#v", name)
}

// InvalidEnumValueError creates a HTTPError with class ID ErrInvalidEnumValue
func InvalidEnumValueError(ctx string, val interface{}, allowed []interface{}) *HTTPError {
	elems := make([]string, len(allowed))
	for i, a := range allowed {
		elems[i] = fmt.Sprintf("%#v", a)
	}
	return ErrInvalidEnumValue("value of %s must be one of %s but got value %#v", ctx, strings.Join(elems, ", "), val)
}

// InvalidFormatError creates a HTTPError with class ID ErrInvalidFormat
func InvalidFormatError(ctx, target string, format Format, formatError error) *HTTPError {
	return ErrInvalidFormat("%s must be formatted as a %s but got value %#v, %s", ctx, format, target, formatError.Error())
}

// InvalidPatternError creates a HTTPError with class ID ErrInvalidPattern
func InvalidPatternError(ctx, target string, pattern string) *HTTPError {
	return ErrInvalidPattern("%s must match the regexp %#v but got value %#v", ctx, pattern, target)
}

// InvalidRangeError creates a HTTPError with class ID ErrInvalidRange
func InvalidRangeError(ctx string, target interface{}, value int, min bool) *HTTPError {
	comp := "greater or equal"
	if !min {
		comp = "lesser or equal"
	}
	return ErrInvalidRange("%s must be %s than %d but got value %#v", ctx, comp, value, target)
}

// InvalidLengthError creates a HTTPError with class ID ErrInvalidLength
func InvalidLengthError(ctx string, target interface{}, ln, value int, min bool) *HTTPError {
	comp := "greater or equal"
	if !min {
		comp = "lesser or equal"
	}
	return ErrInvalidLength("length of %s must be %s than %d but got value %#v (len=%d)", ctx, comp, value, target, ln)
}

// NoSecurityScheme creates a HTTPError with class ID ErrNoSecurityScheme
func NoSecurityScheme(schemeName string) *HTTPError {
	return ErrNoSecurityScheme("invalid security scheme %s", schemeName)
}

// Error returns the error occurrence details.
func (e *HTTPError) Error() string {
	return e.Detail
}

// Meta adds to the error metadata.
func (e *HTTPError) Meta(keyvals ...interface{}) *HTTPError {
	for i := 0; i < len(keyvals); i += 2 {
		k := keyvals[i]
		var v interface{} = "MISSING"
		if i+1 < len(keyvals) {
			v = keyvals[i+1]
		}
		e.MetaValues[fmt.Sprintf("%v", k)] = v
	}
	return e
}

// Error returns the multiple error messages.
func (m MultiError) Error() string {
	errs := make([]string, len(m))
	for i, err := range m {
		errs[i] = err.Error()
	}
	return strings.Join(errs, ", ")
}

// Status computes a status from all the HTTP errors.
// The algorithms returns 500 if any error in the multi error is not a HTTPError or has status 500.
// If all errors are http errors and they all have the same status that status is returned.
// Otherwise Status returns 400.
func (m MultiError) Status() int {
	if len(m) == 0 {
		return 500 // bug
	}
	var status int
	if he, ok := m[0].(*HTTPError); ok {
		status = he.Status
	} else {
		return 500
	}
	if len(m) == 1 {
		return status
	}
	for _, e := range m[1:] {
		if he, ok := e.(*HTTPError); ok {
			if he.Status == 500 {
				return 500
			}
			if he.Status != status {
				status = 400
			}
		} else {
			return 500
		}
	}
	return status
}

// StackErrors coerces the first argument into a MultiError then appends the second argument and
// returns the resulting MultiError.
func StackErrors(err error, err2 error) error {
	if err == nil {
		if err2 == nil {
			return MultiError{}
		}
		if _, ok := err2.(MultiError); ok {
			return err2
		}
		return MultiError{err2}
	}
	merr, ok := err.(MultiError)
	if err2 == nil {
		if ok {
			return merr
		}
		return MultiError{err}
	}
	merr2, ok2 := err2.(MultiError)
	if ok {
		if ok2 {
			return append(merr, merr2...)
		}
		return append(merr, err2)
	}
	merr = MultiError{err}
	if ok2 {
		return append(merr, merr2...)
	}
	return append(merr, err2)
}
<commit_msg>Add generic bad request error<commit_after>// Package goa standardizes on structured error responses: a request that fails because of
// invalid input or unexpected condition produces a response that contains one or more structured
// error(s). Each error object has three keys: a id (number), a title and a message. The title
// for a given id is always the same, the intent is to provide a human friendly categorization.
// The message is specific to the error occurrence and provides additional details that often
// include contextual information (name of parameters etc.).
//
// The basic data structure backing errors is TypedError which simply contains the id and message.
// Multiple errors (not just TypedError instances) can be encapsulated in a MultiError. Both
// TypedError and MultiError implement the error interface, the Error methods return valid JSON
// that can be written directly to a response body.
//
// The code generated by goagen calls the helper functions exposed in this file when it encounters
// invalid data (wrong type, validation errors etc.) such as InvalidParamTypeError,
// InvalidAttributeTypeError etc. These methods take and return an error which is a MultiError that
// gets built over time. The final MultiError object then gets serialized into the response and sent
// back to the client. The response status code is inferred from the type wrapping the error object:
// a BadRequestError produces a 400 status code while any other error produce a 500. This behavior
// can be overridden by setting a custom ErrorHandler in the application.
package goa

import (
	"fmt"
	"strings"
)

var (
	// ErrInvalidParamType is the class of errors produced by the generated code when
	// a request parameter type does not match the design.
	ErrInvalidParamType = NewErrorClass("invalid_parameter_type", 400)

	// ErrMissingParam is the error produced by the generated code when a
	// required request parameter is missing.
	ErrMissingParam = NewErrorClass("missing_parameter", 400)

	// ErrInvalidAttributeType is the error produced by the generated
	// code when a data structure attribute type does not match the design
	// definition.
	ErrInvalidAttributeType = NewErrorClass("invalid_attribute", 400)

	// ErrMissingAttribute is the error produced by the generated
	// code when a data structure attribute required by the design
	// definition is missing.
	ErrMissingAttribute = NewErrorClass("missing_attribute", 400)

	// ErrInvalidEnumValue is the error produced by the generated code when
	// a values does not match one of the values listed in the attribute
	// definition as being valid (i.e. not part of the enum).
	ErrInvalidEnumValue = NewErrorClass("invalid_value", 400)

	// ErrMissingHeader is the error produced by the generated code when a
	// required header is missing.
	ErrMissingHeader = NewErrorClass("missing_header", 400)

	// ErrInvalidFormat is the error produced by the generated code when
	// a value does not match the format specified in the attribute
	// definition.
	ErrInvalidFormat = NewErrorClass("invalid_format", 400)

	// ErrInvalidPattern is the error produced by the generated code when
	// a value does not match the regular expression specified in the
	// attribute definition.
	ErrInvalidPattern = NewErrorClass("invalid_pattern", 400)

	// ErrInvalidRange is the error produced by the generated code when
	// a value is less than the minimum specified in the design definition
	// or more than the maximum.
	ErrInvalidRange = NewErrorClass("invalid_range", 400)

	// ErrInvalidLength is the error produced by the generated code when
	// a value is a slice with less elements than the minimum length
	// specified in the design definition or more elements than the
	// maximum length.
	ErrInvalidLength = NewErrorClass("invalid_length", 400)

	// ErrInvalidEncoding is the error produced when a request body fails
	// to be decoded.
	ErrInvalidEncoding = NewErrorClass("invalid_encoding", 400)

	// ErrNoSecurityScheme is the error produced when no security scheme can
	// be found with the given name.
	ErrNoSecurityScheme = NewErrorClass("no_security_scheme", 500)

	// ErrBadRequest is a generic bad request error.
	ErrBadRequest = NewErrorClass("bad_request", 400)

	// ErrInternal is the class of error used for non HTTPError.
	ErrInternal = NewErrorClass("internal", 500)
)

type (
	// HTTPError describes an error that can be returned in a response.
	HTTPError struct {
		// Code identifies the class of errors for client programs.
		Code string `json:"code" xml:"code"`
		// Status is the HTTP status code used by responses that cary the error.
		Status int `json:"status" xml:"status"`
		// Detail describes the specific error occurrence.
		Detail string `json:"detail" xml:"detail"`
		// MetaValues contains additional key/value pairs useful to clients.
		MetaValues map[string]interface{} `json:"meta,omitempty" xml:"meta,omitempty"`
	}

	// ErrorClass is an error generating function.
	// It accepts a format and values and produces errors with the resulting string.
	// If the format is a string or a Stringer then the string value is used.
	// If the format is an error then the string returned by Error() is used.
	// Otherwise the string produced using fmt.Sprintf("%v") is used.
	ErrorClass func(fm interface{}, v ...interface{}) *HTTPError

	// MultiError is an error composed of potentially multiple errors.
	MultiError []error
)

// NewErrorClass creates a new error class.
// It is the responsability of the client to guarantee uniqueness of code.
func NewErrorClass(code string, status int) ErrorClass {
	return func(fm interface{}, v ...interface{}) *HTTPError {
		var f string
		switch actual := fm.(type) {
		case string:
			f = actual
		case error:
			f = actual.Error()
		case fmt.Stringer:
			f = actual.String()
		default:
			f = fmt.Sprintf("%v", actual)
		}
		return &HTTPError{Code: code, Status: status, Detail: fmt.Sprintf(f, v...)}
	}
}

// InvalidParamTypeError creates a HTTPError with class ID ErrInvalidParamType
func InvalidParamTypeError(name string, val interface{}, expected string) *HTTPError {
	return ErrInvalidParamType("invalid value %#v for parameter %#v, must be a %s", val, name, expected)
}

// MissingParamError creates a HTTPError with class ID ErrMissingParam
func MissingParamError(name string) *HTTPError {
	return ErrMissingParam("missing required parameter %#v", name)
}

// InvalidAttributeTypeError creates a HTTPError with class ID ErrInvalidAttributeType
func InvalidAttributeTypeError(ctx string, val interface{}, expected string) *HTTPError {
	return ErrInvalidAttributeType("type of %s must be %s but got value %#v", ctx, expected, val)
}

// MissingAttributeError creates a HTTPError with class ID ErrMissingAttribute
func MissingAttributeError(ctx, name string) *HTTPError {
	return ErrMissingAttribute("attribute %#v of %s is missing and required", name, ctx)
}

// MissingHeaderError creates a HTTPError with class ID ErrMissingHeader
func MissingHeaderError(name string) *HTTPError {
	return ErrMissingHeader("missing required HTTP header %#v", name)
}

// InvalidEnumValueError creates a HTTPError with class ID ErrInvalidEnumValue
func InvalidEnumValueError(ctx string, val interface{}, allowed []interface{}) *HTTPError {
	elems := make([]string, len(allowed))
	for i, a := range allowed {
		elems[i] = fmt.Sprintf("%#v", a)
	}
	return ErrInvalidEnumValue("value of %s must be one of %s but got value %#v", ctx, strings.Join(elems, ", "), val)
}

// InvalidFormatError creates a HTTPError with class ID ErrInvalidFormat
func InvalidFormatError(ctx, target string, format Format, formatError error) *HTTPError {
	return ErrInvalidFormat("%s must be formatted as a %s but got value %#v, %s", ctx, format, target, formatError.Error())
}

// InvalidPatternError creates a HTTPError with class ID ErrInvalidPattern
func InvalidPatternError(ctx, target string, pattern string) *HTTPError {
	return ErrInvalidPattern("%s must match the regexp %#v but got value %#v", ctx, pattern, target)
}

// InvalidRangeError creates a HTTPError with class ID ErrInvalidRange
func InvalidRangeError(ctx string, target interface{}, value int, min bool) *HTTPError {
	comp := "greater or equal"
	if !min {
		comp = "lesser or equal"
	}
	return ErrInvalidRange("%s must be %s than %d but got value %#v", ctx, comp, value, target)
}

// InvalidLengthError creates a HTTPError with class ID ErrInvalidLength
func InvalidLengthError(ctx string, target interface{}, ln, value int, min bool) *HTTPError {
	comp := "greater or equal"
	if !min {
		comp = "lesser or equal"
	}
	return ErrInvalidLength("length of %s must be %s than %d but got value %#v (len=%d)", ctx, comp, value, target, ln)
}

// NoSecurityScheme creates a HTTPError with class ID ErrNoSecurityScheme
func NoSecurityScheme(schemeName string) *HTTPError {
	return ErrNoSecurityScheme("invalid security scheme %s", schemeName)
}

// Error returns the error occurrence details.
func (e *HTTPError) Error() string {
	return e.Detail
}

// Meta adds to the error metadata.
func (e *HTTPError) Meta(keyvals ...interface{}) *HTTPError {
	for i := 0; i < len(keyvals); i += 2 {
		k := keyvals[i]
		var v interface{} = "MISSING"
		if i+1 < len(keyvals) {
			v = keyvals[i+1]
		}
		e.MetaValues[fmt.Sprintf("%v", k)] = v
	}
	return e
}

// Error returns the multiple error messages.
func (m MultiError) Error() string {
	errs := make([]string, len(m))
	for i, err := range m {
		errs[i] = err.Error()
	}
	return strings.Join(errs, ", ")
}

// Status computes a status from all the HTTP errors.
// The algorithms returns 500 if any error in the multi error is not a HTTPError or has status 500.
// If all errors are http errors and they all have the same status that status is returned.
// Otherwise Status returns 400.
func (m MultiError) Status() int {
	if len(m) == 0 {
		return 500 // bug
	}
	var status int
	if he, ok := m[0].(*HTTPError); ok {
		status = he.Status
	} else {
		return 500
	}
	if len(m) == 1 {
		return status
	}
	for _, e := range m[1:] {
		if he, ok := e.(*HTTPError); ok {
			if he.Status == 500 {
				return 500
			}
			if he.Status != status {
				status = 400
			}
		} else {
			return 500
		}
	}
	return status
}

// StackErrors coerces the first argument into a MultiError then appends the second argument and
// returns the resulting MultiError.
func StackErrors(err error, err2 error) error {
	if err == nil {
		if err2 == nil {
			return MultiError{}
		}
		if _, ok := err2.(MultiError); ok {
			return err2
		}
		return MultiError{err2}
	}
	merr, ok := err.(MultiError)
	if err2 == nil {
		if ok {
			return merr
		}
		return MultiError{err}
	}
	merr2, ok2 := err2.(MultiError)
	if ok {
		if ok2 {
			return append(merr, merr2...)
		}
		return append(merr, err2)
	}
	merr = MultiError{err}
	if ok2 {
		return append(merr, merr2...)
	}
	return append(merr, err2)
}
<|endoftext|>


<commit_before>package gosql

import "errors"

var (
	ErrTypeNil    error = errors.New("gosql: interface{} must not be nil")
	ErrTypeMap          = errors.New("gosql: interface{} is`t type of map[string]interface{}")
	ErrTypeString       = errors.New("gosql: interface{} is`t type of string")
)
<commit_msg>feat: new error<commit_after>package gosql

import "errors"

var (
	ErrTypeNil    error = errors.New("gosql: interface{} must not be nil")
	ErrTypeMap          = errors.New("gosql: interface{} must be type of map[string]interface{}")
	ErrTypeString       = errors.New("gosql: interface{} must be type of string")
	ErrTypeInt          = errors.New("gosql: interface{} must be type of int")
	ErrTypeValue        = errors.New("gosql: invalid value")
)
<|endoftext|>


<commit_before>package http3

import (
	"bytes"
	"fmt"
	"github.com/imroc/req/v3/internal/dump"
	"github.com/imroc/req/v3/internal/header"
	"io"
	"net"
	"net/http"
	"strconv"
	"strings"
	"sync"

	"github.com/imroc/req/v3/internal/utils"
	"github.com/lucas-clemente/quic-go"
	"github.com/marten-seemann/qpack"
	"golang.org/x/net/http/httpguts"
	"golang.org/x/net/http2/hpack"
	"golang.org/x/net/idna"
)

const bodyCopyBufferSize = 8 * 1024

type requestWriter struct {
	mutex     sync.Mutex
	encoder   *qpack.Encoder
	headerBuf *bytes.Buffer

	logger utils.Logger
}

func newRequestWriter(logger utils.Logger) *requestWriter {
	headerBuf := &bytes.Buffer{}
	encoder := qpack.NewEncoder(headerBuf)
	return &requestWriter{
		encoder:   encoder,
		headerBuf: headerBuf,
		logger:    logger,
	}
}

func (w *requestWriter) WriteRequestHeader(str quic.Stream, req *http.Request, gzip bool, dumps []*dump.Dumper) error {
	// TODO: figure out how to add support for trailers
	buf := &bytes.Buffer{}
	if err := w.writeHeaders(buf, req, gzip, dumps); err != nil {
		return err
	}
	_, err := str.Write(buf.Bytes())
	return err
}

func (w *requestWriter) writeHeaders(wr io.Writer, req *http.Request, gzip bool, dumps []*dump.Dumper) error {
	w.mutex.Lock()
	defer w.mutex.Unlock()
	defer w.encoder.Close()
	defer w.headerBuf.Reset()

	if err := w.encodeHeaders(req, gzip, "", actualContentLength(req), dumps); err != nil {
		return err
	}

	buf := &bytes.Buffer{}
	hf := headersFrame{Length: uint64(w.headerBuf.Len())}
	hf.Write(buf)
	if _, err := wr.Write(buf.Bytes()); err != nil {
		return err
	}
	_, err := wr.Write(w.headerBuf.Bytes())
	return err
}

// copied from net/transport.go
// Modified to support Extended CONNECT:
// Contrary to what the godoc for the http.Request says,
// we do respect the Proto field if the method is CONNECT.
func (w *requestWriter) encodeHeaders(req *http.Request, addGzipHeader bool, trailers string, contentLength int64, dumps []*dump.Dumper) error {
	host := req.Host
	if host == "" {
		host = req.URL.Host
	}
	host, err := httpguts.PunycodeHostPort(host)
	if err != nil {
		return err
	}

	// http.NewRequest sets this field to HTTP/1.1
	isExtendedConnect := req.Method == http.MethodConnect && req.Proto != "" && req.Proto != "HTTP/1.1"

	var path string
	if req.Method != http.MethodConnect || isExtendedConnect {
		path = req.URL.RequestURI()
		if !validPseudoPath(path) {
			orig := path
			path = strings.TrimPrefix(path, req.URL.Scheme+"://"+host)
			if !validPseudoPath(path) {
				if req.URL.Opaque != "" {
					return fmt.Errorf("invalid request :path %q from URL.Opaque = %q", orig, req.URL.Opaque)
				} else {
					return fmt.Errorf("invalid request :path %q", orig)
				}
			}
		}
	}

	// Check for any invalid headers and return an error before we
	// potentially pollute our hpack state. (We want to be able to
	// continue to reuse the hpack encoder for future requests)
	for k, vv := range req.Header {
		if !httpguts.ValidHeaderFieldName(k) {
			return fmt.Errorf("invalid HTTP header name %q", k)
		}
		for _, v := range vv {
			if !httpguts.ValidHeaderFieldValue(v) {
				return fmt.Errorf("invalid HTTP header value %q for header %q", v, k)
			}
		}
	}

	enumerateHeaders := func(f func(name, value string)) {
		// 8.1.2.3 Request Pseudo-Header Fields
		// The :path pseudo-header field includes the path and query parts of the
		// target URI (the path-absolute production and optionally a '?' character
		// followed by the query production (see Sections 3.3 and 3.4 of
		// [RFC3986]).
		f(":authority", host)
		f(":method", req.Method)
		if req.Method != http.MethodConnect || isExtendedConnect {
			f(":path", path)
			f(":scheme", req.URL.Scheme)
		}
		if isExtendedConnect {
			f(":protocol", req.Proto)
		}
		if trailers != "" {
			f("trailer", trailers)
		}

		var didUA bool
		for k, vv := range req.Header {
			if strings.EqualFold(k, "host") || strings.EqualFold(k, "content-length") {
				// Host is :authority, already sent.
				// Content-Length is automatic, set below.
				continue
			} else if strings.EqualFold(k, "connection") || strings.EqualFold(k, "proxy-connection") ||
				strings.EqualFold(k, "transfer-encoding") || strings.EqualFold(k, "upgrade") ||
				strings.EqualFold(k, "keep-alive") {
				// Per 8.1.2.2 Connection-Specific Header
				// Fields, don't send connection-specific
				// fields. We have already checked if any
				// are error-worthy so just ignore the rest.
				continue
			} else if strings.EqualFold(k, "user-agent") {
				// Match Go's http1 behavior: at most one
				// User-Agent. If set to nil or empty string,
				// then omit it. Otherwise if not mentioned,
				// include the default (below).
				didUA = true
				if len(vv) < 1 {
					continue
				}
				vv = vv[:1]
				if vv[0] == "" {
					continue
				}

			}

			for _, v := range vv {
				f(k, v)
			}
		}
		if shouldSendReqContentLength(req.Method, contentLength) {
			f("content-length", strconv.FormatInt(contentLength, 10))
		}
		if addGzipHeader {
			f("accept-encoding", "gzip")
		}
		if !didUA {
			f("user-agent", header.DefaultUserAgent)
		}
	}

	// Do a first pass over the headers counting bytes to ensure
	// we don't exceed cc.peerMaxHeaderListSize. This is done as a
	// separate pass before encoding the headers to prevent
	// modifying the hpack state.
	hlSize := uint64(0)
	enumerateHeaders(func(name, value string) {
		for _, dump := range dumps {
			dump.Dump([]byte(fmt.Sprintf("%s: %s\r\n", name, value)))
		}
		hf := hpack.HeaderField{Name: name, Value: value}
		hlSize += uint64(hf.Size())
	})

	// TODO: check maximum header list size
	// if hlSize > cc.peerMaxHeaderListSize {
	// 	return errRequestHeaderListSize
	// }

	// trace := httptrace.ContextClientTrace(req.Context())
	// traceHeaders := traceHasWroteHeaderField(trace)

	// Header list size is ok. Write the headers.
	enumerateHeaders(func(name, value string) {
		name = strings.ToLower(name)
		for _, dump := range dumps {
			dump.Dump([]byte(fmt.Sprintf("%s: %s\r\n", name, value)))
		}
		w.encoder.WriteField(qpack.HeaderField{Name: name, Value: value})
		// if traceHeaders {
		// 	traceWroteHeaderField(trace, name, value)
		// }
	})

	return nil
}

// authorityAddr returns a given authority (a host/IP, or host:port / ip:port)
// and returns a host:port. The port 443 is added if needed.
func authorityAddr(scheme string, authority string) (addr string) {
	host, port, err := net.SplitHostPort(authority)
	if err != nil { // authority didn't have a port
		port = "443"
		if scheme == "http" {
			port = "80"
		}
		host = authority
	}
	if a, err := idna.ToASCII(host); err == nil {
		host = a
	}
	// IPv6 address literal, without a port:
	if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") {
		return host + ":" + port
	}
	return net.JoinHostPort(host, port)
}

// validPseudoPath reports whether v is a valid :path pseudo-header
// value. It must be either:
//
//     *) a non-empty string starting with '/'
//     *) the string '*', for OPTIONS requests.
//
// For now this is only used a quick check for deciding when to clean
// up Opaque URLs before sending requests from the Transport.
// See golang.org/issue/16847
//
// We used to enforce that the path also didn't start with "//", but
// Google's GFE accepts such paths and Chrome sends them, so ignore
// that part of the spec. See golang.org/issue/19103.
func validPseudoPath(v string) bool {
	return (len(v) > 0 && v[0] == '/') || v == "*"
}

// actualContentLength returns a sanitized version of
// req.ContentLength, where 0 actually means zero (not unknown) and -1
// means unknown.
func actualContentLength(req *http.Request) int64 {
	if req.Body == nil {
		return 0
	}
	if req.ContentLength != 0 {
		return req.ContentLength
	}
	return -1
}

// shouldSendReqContentLength reports whether the http2.Transport should send
// a "content-length" request header. This logic is basically a copy of the net/http
// transferWriter.shouldSendContentLength.
// The contentLength is the corrected contentLength (so 0 means actually 0, not unknown).
// -1 means unknown.
func shouldSendReqContentLength(method string, contentLength int64) bool {
	if contentLength > 0 {
		return true
	}
	if contentLength < 0 {
		return false
	}
	// For zero bodies, whether we send a content-length depends on the method.
	// It also kinda doesn't matter for http2 either way, with END_STREAM.
	switch method {
	case "POST", "PUT", "PATCH":
		return true
	default:
		return false
	}
}
<commit_msg>remove duplicate header dump<commit_after>package http3

import (
	"bytes"
	"fmt"
	"github.com/imroc/req/v3/internal/dump"
	"github.com/imroc/req/v3/internal/header"
	"io"
	"net"
	"net/http"
	"strconv"
	"strings"
	"sync"

	"github.com/imroc/req/v3/internal/utils"
	"github.com/lucas-clemente/quic-go"
	"github.com/marten-seemann/qpack"
	"golang.org/x/net/http/httpguts"
	"golang.org/x/net/http2/hpack"
	"golang.org/x/net/idna"
)

const bodyCopyBufferSize = 8 * 1024

type requestWriter struct {
	mutex     sync.Mutex
	encoder   *qpack.Encoder
	headerBuf *bytes.Buffer

	logger utils.Logger
}

func newRequestWriter(logger utils.Logger) *requestWriter {
	headerBuf := &bytes.Buffer{}
	encoder := qpack.NewEncoder(headerBuf)
	return &requestWriter{
		encoder:   encoder,
		headerBuf: headerBuf,
		logger:    logger,
	}
}

func (w *requestWriter) WriteRequestHeader(str quic.Stream, req *http.Request, gzip bool, dumps []*dump.Dumper) error {
	// TODO: figure out how to add support for trailers
	buf := &bytes.Buffer{}
	if err := w.writeHeaders(buf, req, gzip, dumps); err != nil {
		return err
	}
	_, err := str.Write(buf.Bytes())
	return err
}

func (w *requestWriter) writeHeaders(wr io.Writer, req *http.Request, gzip bool, dumps []*dump.Dumper) error {
	w.mutex.Lock()
	defer w.mutex.Unlock()
	defer w.encoder.Close()
	defer w.headerBuf.Reset()

	if err := w.encodeHeaders(req, gzip, "", actualContentLength(req), dumps); err != nil {
		return err
	}

	buf := &bytes.Buffer{}
	hf := headersFrame{Length: uint64(w.headerBuf.Len())}
	hf.Write(buf)
	if _, err := wr.Write(buf.Bytes()); err != nil {
		return err
	}
	_, err := wr.Write(w.headerBuf.Bytes())
	return err
}

// copied from net/transport.go
// Modified to support Extended CONNECT:
// Contrary to what the godoc for the http.Request says,
// we do respect the Proto field if the method is CONNECT.
func (w *requestWriter) encodeHeaders(req *http.Request, addGzipHeader bool, trailers string, contentLength int64, dumps []*dump.Dumper) error {
	host := req.Host
	if host == "" {
		host = req.URL.Host
	}
	host, err := httpguts.PunycodeHostPort(host)
	if err != nil {
		return err
	}

	// http.NewRequest sets this field to HTTP/1.1
	isExtendedConnect := req.Method == http.MethodConnect && req.Proto != "" && req.Proto != "HTTP/1.1"

	var path string
	if req.Method != http.MethodConnect || isExtendedConnect {
		path = req.URL.RequestURI()
		if !validPseudoPath(path) {
			orig := path
			path = strings.TrimPrefix(path, req.URL.Scheme+"://"+host)
			if !validPseudoPath(path) {
				if req.URL.Opaque != "" {
					return fmt.Errorf("invalid request :path %q from URL.Opaque = %q", orig, req.URL.Opaque)
				} else {
					return fmt.Errorf("invalid request :path %q", orig)
				}
			}
		}
	}

	// Check for any invalid headers and return an error before we
	// potentially pollute our hpack state. (We want to be able to
	// continue to reuse the hpack encoder for future requests)
	for k, vv := range req.Header {
		if !httpguts.ValidHeaderFieldName(k) {
			return fmt.Errorf("invalid HTTP header name %q", k)
		}
		for _, v := range vv {
			if !httpguts.ValidHeaderFieldValue(v) {
				return fmt.Errorf("invalid HTTP header value %q for header %q", v, k)
			}
		}
	}

	enumerateHeaders := func(f func(name, value string)) {
		// 8.1.2.3 Request Pseudo-Header Fields
		// The :path pseudo-header field includes the path and query parts of the
		// target URI (the path-absolute production and optionally a '?' character
		// followed by the query production (see Sections 3.3 and 3.4 of
		// [RFC3986]).
		f(":authority", host)
		f(":method", req.Method)
		if req.Method != http.MethodConnect || isExtendedConnect {
			f(":path", path)
			f(":scheme", req.URL.Scheme)
		}
		if isExtendedConnect {
			f(":protocol", req.Proto)
		}
		if trailers != "" {
			f("trailer", trailers)
		}

		var didUA bool
		for k, vv := range req.Header {
			if strings.EqualFold(k, "host") || strings.EqualFold(k, "content-length") {
				// Host is :authority, already sent.
				// Content-Length is automatic, set below.
				continue
			} else if strings.EqualFold(k, "connection") || strings.EqualFold(k, "proxy-connection") ||
				strings.EqualFold(k, "transfer-encoding") || strings.EqualFold(k, "upgrade") ||
				strings.EqualFold(k, "keep-alive") {
				// Per 8.1.2.2 Connection-Specific Header
				// Fields, don't send connection-specific
				// fields. We have already checked if any
				// are error-worthy so just ignore the rest.
				continue
			} else if strings.EqualFold(k, "user-agent") {
				// Match Go's http1 behavior: at most one
				// User-Agent. If set to nil or empty string,
				// then omit it. Otherwise if not mentioned,
				// include the default (below).
				didUA = true
				if len(vv) < 1 {
					continue
				}
				vv = vv[:1]
				if vv[0] == "" {
					continue
				}

			}

			for _, v := range vv {
				f(k, v)
			}
		}
		if shouldSendReqContentLength(req.Method, contentLength) {
			f("content-length", strconv.FormatInt(contentLength, 10))
		}
		if addGzipHeader {
			f("accept-encoding", "gzip")
		}
		if !didUA {
			f("user-agent", header.DefaultUserAgent)
		}
	}

	// Do a first pass over the headers counting bytes to ensure
	// we don't exceed cc.peerMaxHeaderListSize. This is done as a
	// separate pass before encoding the headers to prevent
	// modifying the hpack state.
	hlSize := uint64(0)
	enumerateHeaders(func(name, value string) {
		hf := hpack.HeaderField{Name: name, Value: value}
		hlSize += uint64(hf.Size())
	})

	// TODO: check maximum header list size
	// if hlSize > cc.peerMaxHeaderListSize {
	// 	return errRequestHeaderListSize
	// }

	// trace := httptrace.ContextClientTrace(req.Context())
	// traceHeaders := traceHasWroteHeaderField(trace)

	// Header list size is ok. Write the headers.
	enumerateHeaders(func(name, value string) {
		name = strings.ToLower(name)
		for _, dump := range dumps {
			dump.Dump([]byte(fmt.Sprintf("%s: %s\r\n", name, value)))
		}
		w.encoder.WriteField(qpack.HeaderField{Name: name, Value: value})
		// if traceHeaders {
		// 	traceWroteHeaderField(trace, name, value)
		// }
	})

	return nil
}

// authorityAddr returns a given authority (a host/IP, or host:port / ip:port)
// and returns a host:port. The port 443 is added if needed.
func authorityAddr(scheme string, authority string) (addr string) {
	host, port, err := net.SplitHostPort(authority)
	if err != nil { // authority didn't have a port
		port = "443"
		if scheme == "http" {
			port = "80"
		}
		host = authority
	}
	if a, err := idna.ToASCII(host); err == nil {
		host = a
	}
	// IPv6 address literal, without a port:
	if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") {
		return host + ":" + port
	}
	return net.JoinHostPort(host, port)
}

// validPseudoPath reports whether v is a valid :path pseudo-header
// value. It must be either:
//
//     *) a non-empty string starting with '/'
//     *) the string '*', for OPTIONS requests.
//
// For now this is only used a quick check for deciding when to clean
// up Opaque URLs before sending requests from the Transport.
// See golang.org/issue/16847
//
// We used to enforce that the path also didn't start with "//", but
// Google's GFE accepts such paths and Chrome sends them, so ignore
// that part of the spec. See golang.org/issue/19103.
func validPseudoPath(v string) bool {
	return (len(v) > 0 && v[0] == '/') || v == "*"
}

// actualContentLength returns a sanitized version of
// req.ContentLength, where 0 actually means zero (not unknown) and -1
// means unknown.
func actualContentLength(req *http.Request) int64 {
	if req.Body == nil {
		return 0
	}
	if req.ContentLength != 0 {
		return req.ContentLength
	}
	return -1
}

// shouldSendReqContentLength reports whether the http2.Transport should send
// a "content-length" request header. This logic is basically a copy of the net/http
// transferWriter.shouldSendContentLength.
// The contentLength is the corrected contentLength (so 0 means actually 0, not unknown).
// -1 means unknown.
func shouldSendReqContentLength(method string, contentLength int64) bool {
	if contentLength > 0 {
		return true
	}
	if contentLength < 0 {
		return false
	}
	// For zero bodies, whether we send a content-length depends on the method.
	// It also kinda doesn't matter for http2 either way, with END_STREAM.
	switch method {
	case "POST", "PUT", "PATCH":
		return true
	default:
		return false
	}
}
<|endoftext|>


<commit_before>package go_koans

func aboutStructs() {
	var bob struct {
		name string
		age  int
	}
	bob.name = "bob"
	bob.age = 30

	assert(bob.name == __string__) // structs are collections of named variables
	assert(bob.age == __int__)     // each field has both setter and getter behavior

	type person struct {
		name string
		age  int
	}

	var john person
	john.name = "bob"
	john.age = __int__

	assert(bob == john) // assuredly, bob is certainly not john.. yet
}
<commit_msg>Structs Koan<commit_after>package go_koans

func aboutStructs() {
	var bob struct {
		name string
		age  int
	}
	bob.name = "bob"
	bob.age = 30

	assert(bob.name == "bob") // structs are collections of named variables
	assert(bob.age == 30)     // each field has both setter and getter behavior

	type person struct {
		name string
		age  int
	}

	var john person
	john.name = "bob"
	john.age = 30

	assert(bob == john) // assuredly, bob is certainly not john.. yet
}
<|endoftext|>


<commit_before>package raindrops

import "strconv"

// Convert converts input number to a raindrops string
func Convert(n int) string {
	var s string
	if n%3 == 0 {
		s += "Pling"
	}
	if n%5 == 0 {
		s += "Plang"
	}
	if n%7 == 0 {
		s += "Plong"
	}
	if s == "" {
		s = strconv.Itoa(n)
	}
	return s
}
<commit_msg>go / raindrops<commit_after>package raindrops

import "strconv"

// Convert converts input number to a raindrops string
func Convert(n int) (s string) {
	if n%3 == 0 {
		s += "Pling"
	}
	if n%5 == 0 {
		s += "Plang"
	}
	if n%7 == 0 {
		s += "Plong"
	}
	if s == "" {
		s = strconv.Itoa(n)
	}
	return s
}
<|endoftext|>


<commit_before>package virt

import (
	"errors"
	"os/exec"
	"strconv"
	"strings"
	"time"

	"labix.org/v2/mgo/bson"
)

func (vm *VM) Start() error {
	if out, err := exec.Command("/usr/bin/lxc-start", "--name", vm.String(), "--daemon").CombinedOutput(); err != nil {
		return commandError("lxc-start failed.", err, out)
	}
	return vm.WaitForState("RUNNING", time.Second)
}

func (vm *VM) Stop() error {
	if out, err := exec.Command("/usr/bin/lxc-stop", "--name", vm.String()).CombinedOutput(); err != nil {
		return commandError("lxc-stop failed.", err, out)
	}
	return vm.WaitForState("STOPPED", time.Second)
}

func (vm *VM) Shutdown() error {
	if out, err := exec.Command("/usr/bin/lxc-shutdown", "--name", vm.String()).CombinedOutput(); err != nil {
		if vm.GetState() != "STOPPED" {
			return commandError("lxc-shutdown failed.", err, out)
		}
	}
	vm.WaitForState("STOPPED", 5*time.Second) // may time out, then vm is force stopped
	return vm.Stop()
}

func (vm *VM) AttachCommand(uid int, tty string, command ...string) *exec.Cmd {
	args := []string{"--name", vm.String()}
	if tty != "" {
		args = append(args, "--tty", tty)
	}
	args = append(args, "--", "/usr/bin/sudo", "-i", "-u", "#"+strconv.Itoa(uid), "--")
	args = append(args, command...)
	cmd := exec.Command("/usr/bin/lxc-attach", args...)
	cmd.Env = []string{"TERM=xterm-256color"}
	return cmd
}

func GetVMState(vmId bson.ObjectId) string {
	out, err := exec.Command("/usr/bin/lxc-info", "--name", VMName(vmId), "--state").CombinedOutput()
	if err != nil {
		lastError = commandError("lxc-info failed ", err, out)
		return "UNKNOWN"
	}
	return strings.TrimSpace(string(out)[6:])
}

func (vm *VM) GetState() string {
	return GetVMState(vm.Id)
}

func (vm *VM) WaitForState(state string, timeout time.Duration) error {
	tryUntil := time.Now().Add(timeout)
	for vm.GetState() != state {
		if time.Now().After(tryUntil) {
			return errors.New("Timeout while waiting for VM state.")
		}
		time.Sleep(time.Second / 10)
	}
	return nil
}

func (vm *VM) SendMessageToVMUsers(message string) error {
	cmd := exec.Command("/usr/bin/lxc-attach", "--name", vm.String(), "--", "/usr/bin/wall", "--nobanner")
	cmd.Stdin = strings.NewReader(message)
	if out, err := cmd.CombinedOutput(); err != nil {
		return commandError("wall failed.", err, out)
	}
	return nil
}

func (vm *VM) WaitForNetwork() error {
	timeout := time.Second * 5
	isNetworkUp := func() bool {
		// neglect error because it's not important and we also going to timeout
		out, _ := exec.Command("/usr/bin/lxc-attach", "--name", vm.String(),
			"--", "/bin/cat", "/sys/class/net/eth0/operstate").CombinedOutput()

		if strings.TrimSpace(string(out)) == "up" {
			if out, err := exec.Command("/usr/bin/lxc-attach", "--name", vm.String(),
				"--", "/usr/bin/stat", "/usr/bin/screen").CombinedOutput(); err != nil {
				return false
			} else {
				return true
			}
			return false
		}
	}
	tryUntil := time.Now().Add(timeout)
	for {
		if up := isNetworkUp(); up {
			return nil
		}

		if time.Now().After(tryUntil) {
			return errors.New("Timeout while waiting for VM Network state.")
		}

		time.Sleep(time.Millisecond * 100)
	}
}
<commit_msg>We dont need to hammer for state 500ms granularity is more than enough<commit_after>package virt

import (
	"errors"
	"os/exec"
	"strconv"
	"strings"
	"time"

	"labix.org/v2/mgo/bson"
)

func (vm *VM) Start() error {
	if out, err := exec.Command("/usr/bin/lxc-start", "--name", vm.String(), "--daemon").CombinedOutput(); err != nil {
		return commandError("lxc-start failed.", err, out)
	}
	return vm.WaitForState("RUNNING", time.Second)
}

func (vm *VM) Stop() error {
	if out, err := exec.Command("/usr/bin/lxc-stop", "--name", vm.String()).CombinedOutput(); err != nil {
		return commandError("lxc-stop failed.", err, out)
	}
	return vm.WaitForState("STOPPED", time.Second)
}

func (vm *VM) Shutdown() error {
	if out, err := exec.Command("/usr/bin/lxc-shutdown", "--name", vm.String()).CombinedOutput(); err != nil {
		if vm.GetState() != "STOPPED" {
			return commandError("lxc-shutdown failed.", err, out)
		}
	}
	vm.WaitForState("STOPPED", 5*time.Second) // may time out, then vm is force stopped
	return vm.Stop()
}

func (vm *VM) AttachCommand(uid int, tty string, command ...string) *exec.Cmd {
	args := []string{"--name", vm.String()}
	if tty != "" {
		args = append(args, "--tty", tty)
	}
	args = append(args, "--", "/usr/bin/sudo", "-i", "-u", "#"+strconv.Itoa(uid), "--")
	args = append(args, command...)
	cmd := exec.Command("/usr/bin/lxc-attach", args...)
	cmd.Env = []string{"TERM=xterm-256color"}
	return cmd
}

func GetVMState(vmId bson.ObjectId) string {
	out, err := exec.Command("/usr/bin/lxc-info", "--name", VMName(vmId), "--state").CombinedOutput()
	if err != nil {
		lastError = commandError("lxc-info failed ", err, out)
		return "UNKNOWN"
	}
	return strings.TrimSpace(string(out)[6:])
}

func (vm *VM) GetState() string {
	return GetVMState(vm.Id)
}

func (vm *VM) WaitForState(state string, timeout time.Duration) error {
	tryUntil := time.Now().Add(timeout)
	for vm.GetState() != state {
		if time.Now().After(tryUntil) {
			return errors.New("Timeout while waiting for VM state.")
		}
		time.Sleep(time.Millisecond * 500)
	}
	return nil
}

func (vm *VM) SendMessageToVMUsers(message string) error {
	cmd := exec.Command("/usr/bin/lxc-attach", "--name", vm.String(), "--", "/usr/bin/wall", "--nobanner")
	cmd.Stdin = strings.NewReader(message)
	if out, err := cmd.CombinedOutput(); err != nil {
		return commandError("wall failed.", err, out)
	}
	return nil
}

func (vm *VM) WaitForNetwork() error {
	timeout := time.Second * 5
	isNetworkUp := func() bool {
		// neglect error because it's not important and we also going to timeout
		out, _ := exec.Command("/usr/bin/lxc-attach", "--name", vm.String(),
			"--", "/bin/cat", "/sys/class/net/eth0/operstate").CombinedOutput()

		if strings.TrimSpace(string(out)) == "up" {
			if out, err := exec.Command("/usr/bin/lxc-attach", "--name", vm.String(),
				"--", "/usr/bin/stat", "/usr/bin/screen").CombinedOutput(); err != nil {
				return false
			} else {
				return true
			}
			return false
		}
	}
	tryUntil := time.Now().Add(timeout)
	for {
		if up := isNetworkUp(); up {
			return nil
		}

		if time.Now().After(tryUntil) {
			return errors.New("Timeout while waiting for VM Network state.")
		}

		time.Sleep(time.Millisecond * 100)
	}
}
<|endoftext|>


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

// This package provides basic interfaces to I/O primitives.
// Its primary job is to wrap existing implementations of such primitives,
// such as those in package os, into shared public interfaces that
// abstract the functionality, plus some other related primitives.
package io

import "os"

// Error represents an unexpected I/O behavior.
type Error struct {
	os.ErrorString
}

// ErrShortWrite means that a write accepted fewer bytes than requested
// but failed to return an explicit error.
var ErrShortWrite os.Error = &Error{"short write"}

// ErrUnexpectedEOF means that os.EOF was encountered in the
// middle of reading a fixed-size block or data structure.
var ErrUnexpectedEOF os.Error = &Error{"unexpected EOF"}

// Reader is the interface that wraps the basic Read method.
//
// Read reads up to len(p) bytes into p.  It returns the number of bytes
// read (0 <= n <= len(p)) and any error encountered.
// Even if Read returns n < len(p),
// it may use all of p as scratch space during the call.
// If some data is available but not len(p) bytes, Read conventionally
// returns what is available rather than block waiting for more.
//
// At the end of the input stream, Read returns 0, os.EOF.
// Read may return a non-zero number of bytes with a non-nil err.
// In particular, a Read that exhausts the input may return n > 0, os.EOF.
type Reader interface {
	Read(p []byte) (n int, err os.Error)
}

// Writer is the interface that wraps the basic Write method.
//
// Write writes len(p) bytes from p to the underlying data stream.
// It returns the number of bytes written from p (0 <= n <= len(p))
// and any error encountered that caused the write to stop early.
// Write must return a non-nil error if it returns n < len(p).
type Writer interface {
	Write(p []byte) (n int, err os.Error)
}

// Closer is the interface that wraps the basic Close method.
type Closer interface {
	Close() os.Error
}

// Seeker is the interface that wraps the basic Seek method.
//
// Seek sets the offset for the next Read or Write to offset,
// interpreted according to whence: 0 means relative to the origin of
// the file, 1 means relative to the current offset, and 2 means
// relative to the end.  Seek returns the new offset and an Error, if
// any.
type Seeker interface {
	Seek(offset int64, whence int) (ret int64, err os.Error)
}

// ReadWriter is the interface that groups the basic Read and Write methods.
type ReadWriter interface {
	Reader
	Writer
}

// ReadCloser is the interface that groups the basic Read and Close methods.
type ReadCloser interface {
	Reader
	Closer
}

// WriteCloser is the interface that groups the basic Write and Close methods.
type WriteCloser interface {
	Writer
	Closer
}

// ReadWriteCloser is the interface that groups the basic Read, Write and Close methods.
type ReadWriteCloser interface {
	Reader
	Writer
	Closer
}

// ReadSeeker is the interface that groups the basic Read and Seek methods.
type ReadSeeker interface {
	Reader
	Seeker
}

// WriteSeeker is the interface that groups the basic Write and Seek methods.
type WriteSeeker interface {
	Writer
	Seeker
}

// ReadWriteSeeker is the interface that groups the basic Read, Write and Seek methods.
type ReadWriteSeeker interface {
	Reader
	Writer
	Seeker
}

// ReaderFrom is the interface that wraps the ReadFrom method.
type ReaderFrom interface {
	ReadFrom(r Reader) (n int64, err os.Error)
}

// WriterTo is the interface that wraps the WriteTo method.
type WriterTo interface {
	WriteTo(w Writer) (n int64, err os.Error)
}

// ReaderAt is the interface that wraps the basic ReadAt method.
//
// ReadAt reads len(p) bytes into p starting at offset off in the
// underlying data stream.  It returns the number of bytes
// read (0 <= n <= len(p)) and any error encountered.
//
// Even if ReadAt returns n < len(p),
// it may use all of p as scratch space during the call.
// If some data is available but not len(p) bytes, ReadAt blocks
// until either all the data is available or an error occurs.
//
// At the end of the input stream, ReadAt returns 0, os.EOF.
// ReadAt may return a non-zero number of bytes with a non-nil err.
// In particular, a ReadAt that exhausts the input may return n > 0, os.EOF.
type ReaderAt interface {
	ReadAt(p []byte, off int64) (n int, err os.Error)
}

// WriterAt is the interface that wraps the basic WriteAt method.
//
// WriteAt writes len(p) bytes from p to the underlying data stream
// at offset off.  It returns the number of bytes written from p (0 <= n <= len(p))
// and any error encountered that caused the write to stop early.
// WriteAt must return a non-nil error if it returns n < len(p).
type WriterAt interface {
	WriteAt(p []byte, off int64) (n int, err os.Error)
}

// ReadByter is the interface that wraps the ReadByte method.
//
// ReadByte reads and returns the next byte from the input.
// If no byte is available, err will be set.
type ReadByter interface {
	ReadByte() (c byte, err os.Error)
}

// WriteString writes the contents of the string s to w, which accepts an array of bytes.
func WriteString(w Writer, s string) (n int, err os.Error) {
	return w.Write([]byte(s))
}

// ReadAtLeast reads from r into buf until it has read at least min bytes.
// It returns the number of bytes copied and an error if fewer bytes were read.
// The error is os.EOF only if no bytes were read.
// If an EOF happens after reading fewer than min bytes,
// ReadAtLeast returns ErrUnexpectedEOF.
func ReadAtLeast(r Reader, buf []byte, min int) (n int, err os.Error) {
	n = 0
	for n < min {
		nn, e := r.Read(buf[n:])
		if nn > 0 {
			n += nn
		}
		if e != nil {
			if e == os.EOF && n > 0 {
				e = ErrUnexpectedEOF
			}
			return n, e
		}
	}
	return n, nil
}

// ReadFull reads exactly len(buf) bytes from r into buf.
// It returns the number of bytes copied and an error if fewer bytes were read.
// The error is os.EOF only if no bytes were read.
// If an EOF happens after reading some but not all the bytes,
// ReadFull returns ErrUnexpectedEOF.
func ReadFull(r Reader, buf []byte) (n int, err os.Error) {
	return ReadAtLeast(r, buf, len(buf))
}

// Copyn copies n bytes (or until an error) from src to dst.
// It returns the number of bytes copied and the error, if any.
//
// If dst implements the ReaderFrom interface,
// the copy is implemented by calling dst.ReadFrom(src).
func Copyn(dst Writer, src Reader, n int64) (written int64, err os.Error) {
	// If the writer has a ReadFrom method, use it to to do the copy.
	// Avoids a buffer allocation and a copy.
	if rt, ok := dst.(ReaderFrom); ok {
		return rt.ReadFrom(LimitReader(src, n))
	}
	buf := make([]byte, 32*1024)
	for written < n {
		l := len(buf)
		if d := n - written; d < int64(l) {
			l = int(d)
		}
		nr, er := src.Read(buf[0:l])
		if nr > 0 {
			nw, ew := dst.Write(buf[0:nr])
			if nw > 0 {
				written += int64(nw)
			}
			if ew != nil {
				err = ew
				break
			}
			if nr != nw {
				err = ErrShortWrite
				break
			}
		}
		if er != nil {
			err = er
			break
		}
	}
	return written, err
}

// Copy copies from src to dst until either EOF is reached
// on src or an error occurs.  It returns the number of bytes
// copied and the error, if any.
//
// If dst implements the ReaderFrom interface,
// the copy is implemented by calling dst.ReadFrom(src).
// Otherwise, if src implements the WriterTo interface,
// the copy is implemented by calling src.WriteTo(dst).
func Copy(dst Writer, src Reader) (written int64, err os.Error) {
	// If the writer has a ReadFrom method, use it to to do the copy.
	// Avoids an allocation and a copy.
	if rt, ok := dst.(ReaderFrom); ok {
		return rt.ReadFrom(src)
	}
	// Similarly, if the reader has a WriteTo method, use it to to do the copy.
	if wt, ok := src.(WriterTo); ok {
		return wt.WriteTo(dst)
	}
	buf := make([]byte, 32*1024)
	for {
		nr, er := src.Read(buf)
		if nr > 0 {
			nw, ew := dst.Write(buf[0:nr])
			if nw > 0 {
				written += int64(nw)
			}
			if ew != nil {
				err = ew
				break
			}
			if nr != nw {
				err = ErrShortWrite
				break
			}
		}
		if er == os.EOF {
			break
		}
		if er != nil {
			err = er
			break
		}
	}
	return written, err
}

// LimitReader returns a Reader that reads from r
// but stops with os.EOF after n bytes.
func LimitReader(r Reader, n int64) Reader { return &limitedReader{r, n} }

type limitedReader struct {
	r Reader
	n int64
}

func (l *limitedReader) Read(p []byte) (n int, err os.Error) {
	if l.n <= 0 {
		return 0, os.EOF
	}
	if int64(len(p)) > l.n {
		p = p[0:l.n]
	}
	n, err = l.r.Read(p)
	l.n -= int64(n)
	return
}

// NewSectionReader returns a SectionReader that reads from r
// starting at offset off and stops with os.EOF after n bytes.
func NewSectionReader(r ReaderAt, off int64, n int64) *SectionReader {
	return &SectionReader{r, off, off, off + n}
}

// SectionReader implements Read, Seek, and ReadAt on a section
// of an underlying ReaderAt.
type SectionReader struct {
	r     ReaderAt
	base  int64
	off   int64
	limit int64
}

func (s *SectionReader) Read(p []byte) (n int, err os.Error) {
	if s.off >= s.limit {
		return 0, os.EOF
	}
	if max := s.limit - s.off; int64(len(p)) > max {
		p = p[0:max]
	}
	n, err = s.r.ReadAt(p, s.off)
	s.off += int64(n)
	return
}

func (s *SectionReader) Seek(offset int64, whence int) (ret int64, err os.Error) {
	switch whence {
	default:
		return 0, os.EINVAL
	case 0:
		offset += s.base
	case 1:
		offset += s.off
	case 2:
		offset += s.limit
	}
	if offset < s.off || offset > s.limit {
		return 0, os.EINVAL
	}
	s.off = offset
	return offset - s.base, nil
}

func (s *SectionReader) ReadAt(p []byte, off int64) (n int, err os.Error) {
	if off < 0 || off >= s.limit-s.base {
		return 0, os.EOF
	}
	off += s.base
	if max := s.limit - off; int64(len(p)) > max {
		p = p[0:max]
	}
	return s.r.ReadAt(p, off)
}

// Size returns the size of the section in bytes.
func (s *SectionReader) Size() int64 { return s.limit - s.base }
<commit_msg>io: fix SectionReader Seek to seek backwards<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This package provides basic interfaces to I/O primitives.
// Its primary job is to wrap existing implementations of such primitives,
// such as those in package os, into shared public interfaces that
// abstract the functionality, plus some other related primitives.
package io

import "os"

// Error represents an unexpected I/O behavior.
type Error struct {
	os.ErrorString
}

// ErrShortWrite means that a write accepted fewer bytes than requested
// but failed to return an explicit error.
var ErrShortWrite os.Error = &Error{"short write"}

// ErrUnexpectedEOF means that os.EOF was encountered in the
// middle of reading a fixed-size block or data structure.
var ErrUnexpectedEOF os.Error = &Error{"unexpected EOF"}

// Reader is the interface that wraps the basic Read method.
//
// Read reads up to len(p) bytes into p.  It returns the number of bytes
// read (0 <= n <= len(p)) and any error encountered.
// Even if Read returns n < len(p),
// it may use all of p as scratch space during the call.
// If some data is available but not len(p) bytes, Read conventionally
// returns what is available rather than block waiting for more.
//
// At the end of the input stream, Read returns 0, os.EOF.
// Read may return a non-zero number of bytes with a non-nil err.
// In particular, a Read that exhausts the input may return n > 0, os.EOF.
type Reader interface {
	Read(p []byte) (n int, err os.Error)
}

// Writer is the interface that wraps the basic Write method.
//
// Write writes len(p) bytes from p to the underlying data stream.
// It returns the number of bytes written from p (0 <= n <= len(p))
// and any error encountered that caused the write to stop early.
// Write must return a non-nil error if it returns n < len(p).
type Writer interface {
	Write(p []byte) (n int, err os.Error)
}

// Closer is the interface that wraps the basic Close method.
type Closer interface {
	Close() os.Error
}

// Seeker is the interface that wraps the basic Seek method.
//
// Seek sets the offset for the next Read or Write to offset,
// interpreted according to whence: 0 means relative to the origin of
// the file, 1 means relative to the current offset, and 2 means
// relative to the end.  Seek returns the new offset and an Error, if
// any.
type Seeker interface {
	Seek(offset int64, whence int) (ret int64, err os.Error)
}

// ReadWriter is the interface that groups the basic Read and Write methods.
type ReadWriter interface {
	Reader
	Writer
}

// ReadCloser is the interface that groups the basic Read and Close methods.
type ReadCloser interface {
	Reader
	Closer
}

// WriteCloser is the interface that groups the basic Write and Close methods.
type WriteCloser interface {
	Writer
	Closer
}

// ReadWriteCloser is the interface that groups the basic Read, Write and Close methods.
type ReadWriteCloser interface {
	Reader
	Writer
	Closer
}

// ReadSeeker is the interface that groups the basic Read and Seek methods.
type ReadSeeker interface {
	Reader
	Seeker
}

// WriteSeeker is the interface that groups the basic Write and Seek methods.
type WriteSeeker interface {
	Writer
	Seeker
}

// ReadWriteSeeker is the interface that groups the basic Read, Write and Seek methods.
type ReadWriteSeeker interface {
	Reader
	Writer
	Seeker
}

// ReaderFrom is the interface that wraps the ReadFrom method.
type ReaderFrom interface {
	ReadFrom(r Reader) (n int64, err os.Error)
}

// WriterTo is the interface that wraps the WriteTo method.
type WriterTo interface {
	WriteTo(w Writer) (n int64, err os.Error)
}

// ReaderAt is the interface that wraps the basic ReadAt method.
//
// ReadAt reads len(p) bytes into p starting at offset off in the
// underlying data stream.  It returns the number of bytes
// read (0 <= n <= len(p)) and any error encountered.
//
// Even if ReadAt returns n < len(p),
// it may use all of p as scratch space during the call.
// If some data is available but not len(p) bytes, ReadAt blocks
// until either all the data is available or an error occurs.
//
// At the end of the input stream, ReadAt returns 0, os.EOF.
// ReadAt may return a non-zero number of bytes with a non-nil err.
// In particular, a ReadAt that exhausts the input may return n > 0, os.EOF.
type ReaderAt interface {
	ReadAt(p []byte, off int64) (n int, err os.Error)
}

// WriterAt is the interface that wraps the basic WriteAt method.
//
// WriteAt writes len(p) bytes from p to the underlying data stream
// at offset off.  It returns the number of bytes written from p (0 <= n <= len(p))
// and any error encountered that caused the write to stop early.
// WriteAt must return a non-nil error if it returns n < len(p).
type WriterAt interface {
	WriteAt(p []byte, off int64) (n int, err os.Error)
}

// ReadByter is the interface that wraps the ReadByte method.
//
// ReadByte reads and returns the next byte from the input.
// If no byte is available, err will be set.
type ReadByter interface {
	ReadByte() (c byte, err os.Error)
}

// WriteString writes the contents of the string s to w, which accepts an array of bytes.
func WriteString(w Writer, s string) (n int, err os.Error) {
	return w.Write([]byte(s))
}

// ReadAtLeast reads from r into buf until it has read at least min bytes.
// It returns the number of bytes copied and an error if fewer bytes were read.
// The error is os.EOF only if no bytes were read.
// If an EOF happens after reading fewer than min bytes,
// ReadAtLeast returns ErrUnexpectedEOF.
func ReadAtLeast(r Reader, buf []byte, min int) (n int, err os.Error) {
	n = 0
	for n < min {
		nn, e := r.Read(buf[n:])
		if nn > 0 {
			n += nn
		}
		if e != nil {
			if e == os.EOF && n > 0 {
				e = ErrUnexpectedEOF
			}
			return n, e
		}
	}
	return n, nil
}

// ReadFull reads exactly len(buf) bytes from r into buf.
// It returns the number of bytes copied and an error if fewer bytes were read.
// The error is os.EOF only if no bytes were read.
// If an EOF happens after reading some but not all the bytes,
// ReadFull returns ErrUnexpectedEOF.
func ReadFull(r Reader, buf []byte) (n int, err os.Error) {
	return ReadAtLeast(r, buf, len(buf))
}

// Copyn copies n bytes (or until an error) from src to dst.
// It returns the number of bytes copied and the error, if any.
//
// If dst implements the ReaderFrom interface,
// the copy is implemented by calling dst.ReadFrom(src).
func Copyn(dst Writer, src Reader, n int64) (written int64, err os.Error) {
	// If the writer has a ReadFrom method, use it to to do the copy.
	// Avoids a buffer allocation and a copy.
	if rt, ok := dst.(ReaderFrom); ok {
		return rt.ReadFrom(LimitReader(src, n))
	}
	buf := make([]byte, 32*1024)
	for written < n {
		l := len(buf)
		if d := n - written; d < int64(l) {
			l = int(d)
		}
		nr, er := src.Read(buf[0:l])
		if nr > 0 {
			nw, ew := dst.Write(buf[0:nr])
			if nw > 0 {
				written += int64(nw)
			}
			if ew != nil {
				err = ew
				break
			}
			if nr != nw {
				err = ErrShortWrite
				break
			}
		}
		if er != nil {
			err = er
			break
		}
	}
	return written, err
}

// Copy copies from src to dst until either EOF is reached
// on src or an error occurs.  It returns the number of bytes
// copied and the error, if any.
//
// If dst implements the ReaderFrom interface,
// the copy is implemented by calling dst.ReadFrom(src).
// Otherwise, if src implements the WriterTo interface,
// the copy is implemented by calling src.WriteTo(dst).
func Copy(dst Writer, src Reader) (written int64, err os.Error) {
	// If the writer has a ReadFrom method, use it to to do the copy.
	// Avoids an allocation and a copy.
	if rt, ok := dst.(ReaderFrom); ok {
		return rt.ReadFrom(src)
	}
	// Similarly, if the reader has a WriteTo method, use it to to do the copy.
	if wt, ok := src.(WriterTo); ok {
		return wt.WriteTo(dst)
	}
	buf := make([]byte, 32*1024)
	for {
		nr, er := src.Read(buf)
		if nr > 0 {
			nw, ew := dst.Write(buf[0:nr])
			if nw > 0 {
				written += int64(nw)
			}
			if ew != nil {
				err = ew
				break
			}
			if nr != nw {
				err = ErrShortWrite
				break
			}
		}
		if er == os.EOF {
			break
		}
		if er != nil {
			err = er
			break
		}
	}
	return written, err
}

// LimitReader returns a Reader that reads from r
// but stops with os.EOF after n bytes.
func LimitReader(r Reader, n int64) Reader { return &limitedReader{r, n} }

type limitedReader struct {
	r Reader
	n int64
}

func (l *limitedReader) Read(p []byte) (n int, err os.Error) {
	if l.n <= 0 {
		return 0, os.EOF
	}
	if int64(len(p)) > l.n {
		p = p[0:l.n]
	}
	n, err = l.r.Read(p)
	l.n -= int64(n)
	return
}

// NewSectionReader returns a SectionReader that reads from r
// starting at offset off and stops with os.EOF after n bytes.
func NewSectionReader(r ReaderAt, off int64, n int64) *SectionReader {
	return &SectionReader{r, off, off, off + n}
}

// SectionReader implements Read, Seek, and ReadAt on a section
// of an underlying ReaderAt.
type SectionReader struct {
	r     ReaderAt
	base  int64
	off   int64
	limit int64
}

func (s *SectionReader) Read(p []byte) (n int, err os.Error) {
	if s.off >= s.limit {
		return 0, os.EOF
	}
	if max := s.limit - s.off; int64(len(p)) > max {
		p = p[0:max]
	}
	n, err = s.r.ReadAt(p, s.off)
	s.off += int64(n)
	return
}

func (s *SectionReader) Seek(offset int64, whence int) (ret int64, err os.Error) {
	switch whence {
	default:
		return 0, os.EINVAL
	case 0:
		offset += s.base
	case 1:
		offset += s.off
	case 2:
		offset += s.limit
	}
	if offset < s.base || offset > s.limit {
		return 0, os.EINVAL
	}
	s.off = offset
	return offset - s.base, nil
}

func (s *SectionReader) ReadAt(p []byte, off int64) (n int, err os.Error) {
	if off < 0 || off >= s.limit-s.base {
		return 0, os.EOF
	}
	off += s.base
	if max := s.limit - off; int64(len(p)) > max {
		p = p[0:max]
	}
	return s.r.ReadAt(p, off)
}

// Size returns the size of the section in bytes.
func (s *SectionReader) Size() int64 { return s.limit - s.base }
<|endoftext|>