<commit_before>package hg

import (
	"os/exec"
	"fmt"
	"strings"
	"os"
	"encoding/json"
	"time"
)

type Repository struct {
	Path                string
	Branch              string
	IncludePaths        []string
	ExcludePaths        []string
	TagFilter           string
	SkipSslVerification bool
}

type HgMetadata struct {
	Name  string `json:"name"`
	Value string `json:"value"`
	Type  string `json:"type,omitempty"`
}

type HgChangeset struct {
	Rev        int `json:"rev"`
	Node       string `json:"node"`
	Branch     string `json:"branch"`
	Phase      string `json:"phase"`
	User       string `json:"user"`
	Date       []int64 `json:"date"`
	Desc       string `json:"desc"`
	Booksmarks []string `json:"bookmarks"`
	Tags       []string `json:"tags"`
	Parents    []string `json:"parents"`
}

type HgChangesetList []HgChangeset

func (self *Repository) CloneOrPull(sourceUri string, insecure bool) ([]byte, error) {
	if len(self.Path) == 0 {
		return []byte{}, fmt.Errorf("CloneOrPull: repository path must be set")
	}

	if len(self.Branch) == 0 {
		return []byte{}, fmt.Errorf("CloneOrPull: branch must be set")
	}

	dirInfo, errIfNotExists := os.Stat(self.Path)
	if errIfNotExists != nil || !dirInfo.IsDir() {
		return self.clone(sourceUri, insecure)
	} else {
		return self.pull(insecure)
	}
}

func (self *Repository) clone(sourceUri string, insecure bool) (output []byte, err error) {
	err = os.RemoveAll(self.Path)
	if err != nil {
		err = fmt.Errorf("CloneOrUpdate: %s", err)
		return
	}

	_, output, err = self.run("clone", []string{
		"-q",
		"--branch", self.Branch,
		sourceUri,
		self.Path,
	})
	if err != nil {
		err = fmt.Errorf("Error cloning repository from %s: %s", sourceUri, err)
	}

	return
}

func (self *Repository) pull(insecure bool) (output []byte, err error) {
	_, output, err = self.run("pull", []string{
		"-q",
		"--cwd", self.Path,
	})
	if err != nil {
		err = fmt.Errorf("Error pulling changes from repository: %s\nStderr", err)
		return
	}

	_, checkoutOutput, err := self.run("checkout", []string{
		"-q",
		"--cwd", self.Path,
		"--clean",
		"--rev", "tip",
	})
	output = append(output, checkoutOutput...)
	if err != nil {
		err = fmt.Errorf("Error updating working directory to tip: %s", err)
	}

	return
}

func (self *Repository) PullWithRebase(sourceUri string, branch string) (output []byte, err error) {
	_, output, err = self.run("pull", []string{
		"-q",
		"--cwd", self.Path,
		"--config", "extensions.rebase=",
		"--config", "paths.push-target=" + sourceUri,
		"--rebase",
		"--branch", branch,
		"push-target",
	})
	if err != nil {
		err = fmt.Errorf("Error pulling/rebasing from: %s: %s", sourceUri, err)
	}
	return
}

func (self *Repository) CloneAtCommit(sourceUri string, commitId string) (output []byte, err error) {
	_, output, err = self.run("clone", []string{
		"-q",
		"--rev", commitId,
		sourceUri,
		self.Path,
	})
	if err != nil {
		err = fmt.Errorf("Error cloning repository %s@%s: %s", sourceUri, commitId, err)
	}

	return
}

func (self *Repository) SetDraftPhase() (output []byte, err error) {
	_, output, err = self.run("phase", []string{
		"--cwd", self.Path,
		"--force",
		"--draft",
	})
	if err != nil {
		err = fmt.Errorf("Error setting repo phase to draft: %s", err)
	}

	return
}

func (self *Repository) Push(destUri string, branch string) (output []byte, err error) {
	_, output, err = self.run("push", []string{
		"--cwd", self.Path,
		"--config", "paths.push-target=" + destUri,
		"--branch", branch,
		"push-target",
	})
	if err != nil {
		err = fmt.Errorf("Error pushing to %s: %s", destUri, err)
	}

	return
}

func (self *Repository) Tag(tagValue string) (output []byte, err error) {
	_, output, err = self.run("tag", []string{
		"--cwd", self.Path,
		tagValue,
	})
	if err != nil {
		err = fmt.Errorf("Error tagging current commit: %s", err)
	}

	return
}

func (self *Repository) Delete() error {
	err := os.RemoveAll(self.Path)
	if err != nil {
		return fmt.Errorf("Error deleting repository: %s", err)
	}

	return nil
}

func (self *Repository) Checkout(commitId string) (output []byte, err error) {
	_, output, err = self.run("checkout", []string{
		"-q",
		"--cwd", self.Path,
		"--clean",
		"--rev", commitId,
	})
	if err != nil {
		err = fmt.Errorf("Error checking out %s: %s", commitId, err)
	}

	return
}

func (self *Repository) Purge() (output []byte, err error) {
	_, output, err = self.run("purge", []string{
		"--config", "extensions.purge=",
		"--cwd", self.Path,
		"--all",
	})
	if err != nil {
		err = fmt.Errorf("Error purging repository: %s", err)
	}

	return
}

func (self *Repository) GetLatestCommitId() (output string, err error) {
	include := self.makeIncludeQueryFragment()
	exclude := self.makeExcludeQueryFragment()
	tagFilter := self.maybeTagFilter()
	revSet := fmt.Sprintf("last((((%s) - (%s)) & %s) - desc('[ci skip]'))", include, exclude, tagFilter)

	_, outBytes, err := self.run("log", []string{
		"--cwd", self.Path,
		"--rev", revSet,
		"--template", "{node}",
	})
	output = string(outBytes)
	if err != nil {
		err = fmt.Errorf("Error getting latest commit id: %s", err)
	}

	return
}

func (self *Repository) GetCurrentCommitId() (output string, err error) {
	_, outBytes, err := self.run("log", []string{
		"--cwd", self.Path,
		"--rev", ".",
		"--template", "{node}",
	})
	output = string(outBytes)
	if err != nil {
		err = fmt.Errorf("Error getting current commit id: %s", err)
	}

	return
}

func (self *Repository) GetDescendantsOf(commitId string) ([]string, error) {
	include := self.makeIncludeQueryFragment()
	exclude := self.makeExcludeQueryFragment()
	tagFilter := self.maybeTagFilter()
	revSet := fmt.Sprintf("(descendants(%s) - %s) & %s & ((%s) - (%s)) - desc('[ci skip]')",
		commitId, commitId, tagFilter, include, exclude)

	_, outBytes, err := self.run("log", []string{
		"--cwd", self.Path,
		"--rev", revSet,
		"--template", "{node}\n",
	})

	output := string(outBytes)
	if err != nil {
		return []string{}, fmt.Errorf("Error getting descendant commits of %s: %s\n%s", commitId, err, output)
	}

	trimmed := strings.Trim(output, "\n\r ")
	if len(trimmed) == 0 {
		return []string{}, nil
	}

	commits := strings.Split(trimmed, "\n")
	return commits, nil
}

func (self *Repository) maybeTagFilter() string {
	if len(self.TagFilter) > 0 {
		return "tag('re:" + escapePath(self.TagFilter) + "')"
	} else {
		return "all()"
	}
}

func (self *Repository) Metadata(commitId string) (metadata []HgMetadata, err error) {
	_, outBytes, err := self.run("log", []string{
		"--cwd", self.Path,
		"--rev", commitId,
		"--template", "json",
	})
	if err != nil {
		err = fmt.Errorf("Error getting metadata for commit %s: %s\n%s", commitId, err, string(outBytes))
	}

	metadata, err = parseMetadata(outBytes)
	return
}

func parseHgTime(hgTime []int64) (parsedTime time.Time, err error) {
	if len(hgTime) != 2 {
		err = fmt.Errorf("parseHgTime: expected slice hgTime to have 2 elements")
	}
	utcEpoch := hgTime[0]
	offset := hgTime[1]

	utcTime := time.Unix(utcEpoch, 0)

	// for some reason, mercurial uses the inverse sign on the offset
	zone := time.FixedZone("internet time", -1 * int(offset))

	parsedTime = utcTime.In(zone)
	return
}

func timeToIso8601(timestamp time.Time) string {
	return timestamp.Format("2006-01-02 15:04:05 -0700")
}

func (commit *HgChangeset) toCommitProperties() (metadata []HgMetadata, err error) {
	timestamp, err := parseHgTime(commit.Date)
	if err != nil {
		return
	}

	metadata = append(metadata,
		HgMetadata{
			Name: "commit",
			Value: commit.Node,
		},
		HgMetadata{
			Name: "author",
			Value: commit.User,
		},
		HgMetadata{
			Name: "author_date",
			Value: timeToIso8601(timestamp),
			Type: "time",
		},
		HgMetadata{
			Name: "message",
			Value: commit.Desc,
			Type: "message",
		},
		HgMetadata{
			Name: "tags",
			Value: strings.Join(commit.Tags, ", "),
		},
	)

	return
}

func parseMetadata(hgJsonOutput []byte) (metadata []HgMetadata, err error) {
	commits := HgChangesetList{}
	err = json.Unmarshal(hgJsonOutput, &commits)
	if err != nil {
		return
	}

	if len(commits) != 1 {
		err = fmt.Errorf("parseMetadata: expected 1 commit, found %d", len(commits))
		return
	}

	metadata, err = commits[0].toCommitProperties()
	return
}

func (self *Repository) run(command string, args []string) (cmd *exec.Cmd, output []byte, err error) {
	hgArgs := make([]string, 1, len(args) + 1)
	hgArgs[0] = command

	if self.SkipSslVerification && commandTakesInsecureOption(command) {
		hgArgs = append(hgArgs, "--insecure")
	}
	hgArgs = append(hgArgs, args...)

	cmd = exec.Command("hg", hgArgs...)

	output, err = cmd.CombinedOutput()
	return
}

func commandTakesInsecureOption(command string) bool {
	eligibleCommands := []string{
		"clone",
		"pull",
		"push",
	}
	for _, eligibleCommand := range (eligibleCommands) {
		if command == eligibleCommand {
			return true
		}
	}
	return false
}

func (self *Repository) makeIncludeQueryFragment() string {
	if len(self.IncludePaths) == 0 {
		return "all()"
	} else {
		return unionOfPaths(self.IncludePaths)
	}
}

func (self *Repository) makeExcludeQueryFragment() string {
	if len(self.ExcludePaths) == 0 {
		return "not all()"
	} else {
		return unionOfPaths(self.ExcludePaths)
	}
}

func unionOfPaths(paths []string) string {
	escapedPaths := make([]string, len(paths))
	for i, path := range (paths) {
		escapedPaths[i] = "file('re:" + escapePath(path) + "')"
	}
	return strings.Join(escapedPaths, "|")
}

func escapePath(path string) string {
	backslashesEscaped := strings.Replace(path, "\\", "\\\\\\\\", -1)
	quotesEscaped := strings.Replace(backslashesEscaped, "'", "\\'", -1)
	return quotesEscaped
}<commit_msg>hg: fix typo<commit_after>package hg

import (
	"os/exec"
	"fmt"
	"strings"
	"os"
	"encoding/json"
	"time"
)

type Repository struct {
	Path                string
	Branch              string
	IncludePaths        []string
	ExcludePaths        []string
	TagFilter           string
	SkipSslVerification bool
}

type HgMetadata struct {
	Name  string `json:"name"`
	Value string `json:"value"`
	Type  string `json:"type,omitempty"`
}

type HgChangeset struct {
	Rev       int `json:"rev"`
	Node      string `json:"node"`
	Branch    string `json:"branch"`
	Phase     string `json:"phase"`
	User      string `json:"user"`
	Date      []int64 `json:"date"`
	Desc      string `json:"desc"`
	Bookmarks []string `json:"bookmarks"`
	Tags      []string `json:"tags"`
	Parents   []string `json:"parents"`
}

type HgChangesetList []HgChangeset

func (self *Repository) CloneOrPull(sourceUri string, insecure bool) ([]byte, error) {
	if len(self.Path) == 0 {
		return []byte{}, fmt.Errorf("CloneOrPull: repository path must be set")
	}

	if len(self.Branch) == 0 {
		return []byte{}, fmt.Errorf("CloneOrPull: branch must be set")
	}

	dirInfo, errIfNotExists := os.Stat(self.Path)
	if errIfNotExists != nil || !dirInfo.IsDir() {
		return self.clone(sourceUri, insecure)
	} else {
		return self.pull(insecure)
	}
}

func (self *Repository) clone(sourceUri string, insecure bool) (output []byte, err error) {
	err = os.RemoveAll(self.Path)
	if err != nil {
		err = fmt.Errorf("CloneOrUpdate: %s", err)
		return
	}

	_, output, err = self.run("clone", []string{
		"-q",
		"--branch", self.Branch,
		sourceUri,
		self.Path,
	})
	if err != nil {
		err = fmt.Errorf("Error cloning repository from %s: %s", sourceUri, err)
	}

	return
}

func (self *Repository) pull(insecure bool) (output []byte, err error) {
	_, output, err = self.run("pull", []string{
		"-q",
		"--cwd", self.Path,
	})
	if err != nil {
		err = fmt.Errorf("Error pulling changes from repository: %s\nStderr", err)
		return
	}

	_, checkoutOutput, err := self.run("checkout", []string{
		"-q",
		"--cwd", self.Path,
		"--clean",
		"--rev", "tip",
	})
	output = append(output, checkoutOutput...)
	if err != nil {
		err = fmt.Errorf("Error updating working directory to tip: %s", err)
	}

	return
}

func (self *Repository) PullWithRebase(sourceUri string, branch string) (output []byte, err error) {
	_, output, err = self.run("pull", []string{
		"-q",
		"--cwd", self.Path,
		"--config", "extensions.rebase=",
		"--config", "paths.push-target=" + sourceUri,
		"--rebase",
		"--branch", branch,
		"push-target",
	})
	if err != nil {
		err = fmt.Errorf("Error pulling/rebasing from: %s: %s", sourceUri, err)
	}
	return
}

func (self *Repository) CloneAtCommit(sourceUri string, commitId string) (output []byte, err error) {
	_, output, err = self.run("clone", []string{
		"-q",
		"--rev", commitId,
		sourceUri,
		self.Path,
	})
	if err != nil {
		err = fmt.Errorf("Error cloning repository %s@%s: %s", sourceUri, commitId, err)
	}

	return
}

func (self *Repository) SetDraftPhase() (output []byte, err error) {
	_, output, err = self.run("phase", []string{
		"--cwd", self.Path,
		"--force",
		"--draft",
	})
	if err != nil {
		err = fmt.Errorf("Error setting repo phase to draft: %s", err)
	}

	return
}

func (self *Repository) Push(destUri string, branch string) (output []byte, err error) {
	_, output, err = self.run("push", []string{
		"--cwd", self.Path,
		"--config", "paths.push-target=" + destUri,
		"--branch", branch,
		"push-target",
	})
	if err != nil {
		err = fmt.Errorf("Error pushing to %s: %s", destUri, err)
	}

	return
}

func (self *Repository) Tag(tagValue string) (output []byte, err error) {
	_, output, err = self.run("tag", []string{
		"--cwd", self.Path,
		tagValue,
	})
	if err != nil {
		err = fmt.Errorf("Error tagging current commit: %s", err)
	}

	return
}

func (self *Repository) Delete() error {
	err := os.RemoveAll(self.Path)
	if err != nil {
		return fmt.Errorf("Error deleting repository: %s", err)
	}

	return nil
}

func (self *Repository) Checkout(commitId string) (output []byte, err error) {
	_, output, err = self.run("checkout", []string{
		"-q",
		"--cwd", self.Path,
		"--clean",
		"--rev", commitId,
	})
	if err != nil {
		err = fmt.Errorf("Error checking out %s: %s", commitId, err)
	}

	return
}

func (self *Repository) Purge() (output []byte, err error) {
	_, output, err = self.run("purge", []string{
		"--config", "extensions.purge=",
		"--cwd", self.Path,
		"--all",
	})
	if err != nil {
		err = fmt.Errorf("Error purging repository: %s", err)
	}

	return
}

func (self *Repository) GetLatestCommitId() (output string, err error) {
	include := self.makeIncludeQueryFragment()
	exclude := self.makeExcludeQueryFragment()
	tagFilter := self.maybeTagFilter()
	revSet := fmt.Sprintf("last((((%s) - (%s)) & %s) - desc('[ci skip]'))", include, exclude, tagFilter)

	_, outBytes, err := self.run("log", []string{
		"--cwd", self.Path,
		"--rev", revSet,
		"--template", "{node}",
	})
	output = string(outBytes)
	if err != nil {
		err = fmt.Errorf("Error getting latest commit id: %s", err)
	}

	return
}

func (self *Repository) GetCurrentCommitId() (output string, err error) {
	_, outBytes, err := self.run("log", []string{
		"--cwd", self.Path,
		"--rev", ".",
		"--template", "{node}",
	})
	output = string(outBytes)
	if err != nil {
		err = fmt.Errorf("Error getting current commit id: %s", err)
	}

	return
}

func (self *Repository) GetDescendantsOf(commitId string) ([]string, error) {
	include := self.makeIncludeQueryFragment()
	exclude := self.makeExcludeQueryFragment()
	tagFilter := self.maybeTagFilter()
	revSet := fmt.Sprintf("(descendants(%s) - %s) & %s & ((%s) - (%s)) - desc('[ci skip]')",
		commitId, commitId, tagFilter, include, exclude)

	_, outBytes, err := self.run("log", []string{
		"--cwd", self.Path,
		"--rev", revSet,
		"--template", "{node}\n",
	})

	output := string(outBytes)
	if err != nil {
		return []string{}, fmt.Errorf("Error getting descendant commits of %s: %s\n%s", commitId, err, output)
	}

	trimmed := strings.Trim(output, "\n\r ")
	if len(trimmed) == 0 {
		return []string{}, nil
	}

	commits := strings.Split(trimmed, "\n")
	return commits, nil
}

func (self *Repository) maybeTagFilter() string {
	if len(self.TagFilter) > 0 {
		return "tag('re:" + escapePath(self.TagFilter) + "')"
	} else {
		return "all()"
	}
}

func (self *Repository) Metadata(commitId string) (metadata []HgMetadata, err error) {
	_, outBytes, err := self.run("log", []string{
		"--cwd", self.Path,
		"--rev", commitId,
		"--template", "json",
	})
	if err != nil {
		err = fmt.Errorf("Error getting metadata for commit %s: %s\n%s", commitId, err, string(outBytes))
	}

	metadata, err = parseMetadata(outBytes)
	return
}

func parseHgTime(hgTime []int64) (parsedTime time.Time, err error) {
	if len(hgTime) != 2 {
		err = fmt.Errorf("parseHgTime: expected slice hgTime to have 2 elements")
	}
	utcEpoch := hgTime[0]
	offset := hgTime[1]

	utcTime := time.Unix(utcEpoch, 0)

	// for some reason, mercurial uses the inverse sign on the offset
	zone := time.FixedZone("internet time", -1 * int(offset))

	parsedTime = utcTime.In(zone)
	return
}

func timeToIso8601(timestamp time.Time) string {
	return timestamp.Format("2006-01-02 15:04:05 -0700")
}

func (commit *HgChangeset) toCommitProperties() (metadata []HgMetadata, err error) {
	timestamp, err := parseHgTime(commit.Date)
	if err != nil {
		return
	}

	metadata = append(metadata,
		HgMetadata{
			Name: "commit",
			Value: commit.Node,
		},
		HgMetadata{
			Name: "author",
			Value: commit.User,
		},
		HgMetadata{
			Name: "author_date",
			Value: timeToIso8601(timestamp),
			Type: "time",
		},
		HgMetadata{
			Name: "message",
			Value: commit.Desc,
			Type: "message",
		},
		HgMetadata{
			Name: "tags",
			Value: strings.Join(commit.Tags, ", "),
		},
	)

	return
}

func parseMetadata(hgJsonOutput []byte) (metadata []HgMetadata, err error) {
	commits := HgChangesetList{}
	err = json.Unmarshal(hgJsonOutput, &commits)
	if err != nil {
		return
	}

	if len(commits) != 1 {
		err = fmt.Errorf("parseMetadata: expected 1 commit, found %d", len(commits))
		return
	}

	metadata, err = commits[0].toCommitProperties()
	return
}

func (self *Repository) run(command string, args []string) (cmd *exec.Cmd, output []byte, err error) {
	hgArgs := make([]string, 1, len(args) + 1)
	hgArgs[0] = command

	if self.SkipSslVerification && commandTakesInsecureOption(command) {
		hgArgs = append(hgArgs, "--insecure")
	}
	hgArgs = append(hgArgs, args...)

	cmd = exec.Command("hg", hgArgs...)

	output, err = cmd.CombinedOutput()
	return
}

func commandTakesInsecureOption(command string) bool {
	eligibleCommands := []string{
		"clone",
		"pull",
		"push",
	}
	for _, eligibleCommand := range (eligibleCommands) {
		if command == eligibleCommand {
			return true
		}
	}
	return false
}

func (self *Repository) makeIncludeQueryFragment() string {
	if len(self.IncludePaths) == 0 {
		return "all()"
	} else {
		return unionOfPaths(self.IncludePaths)
	}
}

func (self *Repository) makeExcludeQueryFragment() string {
	if len(self.ExcludePaths) == 0 {
		return "not all()"
	} else {
		return unionOfPaths(self.ExcludePaths)
	}
}

func unionOfPaths(paths []string) string {
	escapedPaths := make([]string, len(paths))
	for i, path := range (paths) {
		escapedPaths[i] = "file('re:" + escapePath(path) + "')"
	}
	return strings.Join(escapedPaths, "|")
}

func escapePath(path string) string {
	backslashesEscaped := strings.Replace(path, "\\", "\\\\\\\\", -1)
	quotesEscaped := strings.Replace(backslashesEscaped, "'", "\\'", -1)
	return quotesEscaped
}<|endoftext|>


<commit_before>package cc

import "fmt"

// Piece is the interface used to be able to use different implementation details
// for the different kinds of pieces.
type Piece interface {
	String() string
	Threatening(b *Board, x, y uint8) []Position
}

type blank Cell
type dead Cell
type king Cell
type queen Cell
type bishop Cell
type rook Cell
type knight Cell

// The pieces available
// Since they don't carry state use one instace
const (
	Blank  blank  = 0 //"."
	Dead   dead   = 1 //"X"
	King   king   = 5 //"K" //"♚"
	Queen  queen  = 6 //"Q" //"♛"
	Bishop bishop = 7 //"B" //"♝"
	Rook   rook   = 8 //"R" //"♜"
	Knight knight = 9 //"N" //"♞"
)

func (p rook) Threatening(b *Board, x, y uint8) []Position {
	if x < 0 || y < 0 || x >= b.columns || y >= b.rows {
		return []Position{}
	}
	ret := make([]Position, 0)
	for i := uint8(0); i < b.columns; i++ {
		for j := uint8(0); j < b.rows; j++ {
			if i == x && j != y {
				ret = append(ret, Position{x: i, y: j})
			}
			if i != x && j == y {
				ret = append(ret, Position{x: i, y: j})
			}
		}
	}
	return ret
}

func (p rook) String() string {
	return "R"
}

func (p king) Threatening(b *Board, x, y uint8) []Position {
	if x < 0 || y < 0 || x >= b.columns || y >= b.rows {
		return []Position{}
	}
	t := []Position{
		{x: x - 1, y: y},
		{x: x - 1, y: y - 1},
		{x: x, y: y - 1},
		{x: x + 1, y: y - 1},
		{x: x + 1, y: y},
		{x: x + 1, y: y + 1},
		{x: x, y: y + 1},
		{x: x - 1, y: y + 1},
	}
	ret := make([]Position, 0)
	for _, c := range t {
		if c.x < 0 || c.y < 0 || c.x >= b.columns || c.y >= b.rows {
			continue
		}
		ret = append(ret, c)
	}
	return ret
}

func (p king) String() string {
	return "K"
}

func (p knight) Threatening(b *Board, x, y uint8) []Position {
	if x < 0 || y < 0 || x >= b.columns || y >= b.rows {
		return []Position{} // TODO: Should be error
	}
	t := []Position{
		{x: x - 1, y: y - 2},
		{x: x + 1, y: y - 2},
		{x: x - 2, y: y - 1},
		{x: x + 2, y: y - 1},
		{x: x - 2, y: y + 1},
		{x: x + 2, y: y + 1},
		{x: x - 1, y: y + 2},
		{x: x + 1, y: y + 2},
	}
	ret := make([]Position, 0)
	for _, c := range t {
		if c.x < 0 || c.y < 0 || c.x >= b.columns || c.y >= b.rows {
			continue
		}
		ret = append(ret, c)
	}
	return ret
}

func (p knight) String() string {
	return "N"
}

func (p queen) Threatening(b *Board, x, y uint8) []Position {
	if x < 0 || y < 0 || x >= b.columns || y >= b.rows {
		return []Position{}
	}

	ret := make([]Position, 0, b.columns*b.rows)
	ret = append(ret, Rook.Threatening(b, x, y)...)
	ret = append(ret, Bishop.Threatening(b, x, y)...)
	return ret
}

func (p queen) String() string {
	return "Q"
}

func (p bishop) Threatening(b *Board, x, y uint8) []Position {
	if x < 0 || y < 0 || x >= b.columns || y >= b.rows {
		return []Position{}
	}
	m := make(map[string]Position)
	i := x
	j := y
	for {
		if i < 0 || i >= b.columns {
			break
		}
		if j < 0 || j >= b.rows {
			break
		}
		i++
		j++
		m[fmt.Sprintf("%d,%d", i, j)] = Position{x: i, y: j}
	}
	i = x
	j = y
	for {
		if i < 0 || i >= b.columns {
			break
		}
		if j < 0 || j >= b.rows {
			break
		}
		i++
		j--
		m[fmt.Sprintf("%d,%d", i, j)] = Position{x: i, y: j}
	}
	i = x
	j = y
	for {
		if i < 0 || i >= b.columns {
			break
		}
		if j < 0 || j >= b.rows {
			break
		}
		i--
		j--
		m[fmt.Sprintf("%d,%d", i, j)] = Position{x: i, y: j}
	}
	i = x
	j = y
	for {
		if i < 0 || i >= b.columns {
			break
		}
		if j < 0 || j >= b.rows {
			break
		}
		i--
		j++
		m[fmt.Sprintf("%d,%d", i, j)] = Position{x: i, y: j}
	}

	ret := make([]Position, 0, b.columns*b.rows)
	for _, c := range m {
		if c.x < 0 || c.y < 0 || c.x >= b.columns || c.y >= b.rows {
			continue
		}
		ret = append(ret, c)
	}
	return ret
}

func (p bishop) String() string {
	return "B"
}

func (p blank) String() string {
	return "."
}

func (p blank) Threatening(b *Board, x, y uint8) []Position {
	return []Position{}
}

func (p dead) String() string {
	return "X"
}

func (p dead) Threatening(b *Board, x, y uint8) []Position {
	return []Position{}
}
<commit_msg>Fix linting error<commit_after>package cc

import "fmt"

// Piece is the interface used to be able to use different implementation details
// for the different kinds of pieces.
type Piece interface {
	String() string
	Threatening(b *Board, x, y uint8) []Position
}

type blank Cell
type dead Cell
type king Cell
type queen Cell
type bishop Cell
type rook Cell
type knight Cell

// The pieces available
// Since they don't carry state use one instace
const (
	Blank  blank  = 0 //"."
	Dead   dead   = 1 //"X"
	King   king   = 5 //"K" //"♚"
	Queen  queen  = 6 //"Q" //"♛"
	Bishop bishop = 7 //"B" //"♝"
	Rook   rook   = 8 //"R" //"♜"
	Knight knight = 9 //"N" //"♞"
)

func (p rook) Threatening(b *Board, x, y uint8) []Position {
	if x < 0 || y < 0 || x >= b.columns || y >= b.rows {
		return []Position{}
	}
	var ret []Position
	for i := uint8(0); i < b.columns; i++ {
		for j := uint8(0); j < b.rows; j++ {
			if i == x && j != y {
				ret = append(ret, Position{x: i, y: j})
			}
			if i != x && j == y {
				ret = append(ret, Position{x: i, y: j})
			}
		}
	}
	return ret
}

func (p rook) String() string {
	return "R"
}

func (p king) Threatening(b *Board, x, y uint8) []Position {
	if x < 0 || y < 0 || x >= b.columns || y >= b.rows {
		return []Position{}
	}
	t := []Position{
		{x: x - 1, y: y},
		{x: x - 1, y: y - 1},
		{x: x, y: y - 1},
		{x: x + 1, y: y - 1},
		{x: x + 1, y: y},
		{x: x + 1, y: y + 1},
		{x: x, y: y + 1},
		{x: x - 1, y: y + 1},
	}
	var ret []Position
	for _, c := range t {
		if c.x < 0 || c.y < 0 || c.x >= b.columns || c.y >= b.rows {
			continue
		}
		ret = append(ret, c)
	}
	return ret
}

func (p king) String() string {
	return "K"
}

func (p knight) Threatening(b *Board, x, y uint8) []Position {
	if x < 0 || y < 0 || x >= b.columns || y >= b.rows {
		return []Position{} // TODO: Should be error
	}
	t := []Position{
		{x: x - 1, y: y - 2},
		{x: x + 1, y: y - 2},
		{x: x - 2, y: y - 1},
		{x: x + 2, y: y - 1},
		{x: x - 2, y: y + 1},
		{x: x + 2, y: y + 1},
		{x: x - 1, y: y + 2},
		{x: x + 1, y: y + 2},
	}
	var ret []Position
	for _, c := range t {
		if c.x < 0 || c.y < 0 || c.x >= b.columns || c.y >= b.rows {
			continue
		}
		ret = append(ret, c)
	}
	return ret
}

func (p knight) String() string {
	return "N"
}

func (p queen) Threatening(b *Board, x, y uint8) []Position {
	if x < 0 || y < 0 || x >= b.columns || y >= b.rows {
		return []Position{}
	}

	ret := make([]Position, 0, b.columns*b.rows)
	ret = append(ret, Rook.Threatening(b, x, y)...)
	ret = append(ret, Bishop.Threatening(b, x, y)...)
	return ret
}

func (p queen) String() string {
	return "Q"
}

func (p bishop) Threatening(b *Board, x, y uint8) []Position {
	if x < 0 || y < 0 || x >= b.columns || y >= b.rows {
		return []Position{}
	}
	m := make(map[string]Position)
	i := x
	j := y
	for {
		if i < 0 || i >= b.columns {
			break
		}
		if j < 0 || j >= b.rows {
			break
		}
		i++
		j++
		m[fmt.Sprintf("%d,%d", i, j)] = Position{x: i, y: j}
	}
	i = x
	j = y
	for {
		if i < 0 || i >= b.columns {
			break
		}
		if j < 0 || j >= b.rows {
			break
		}
		i++
		j--
		m[fmt.Sprintf("%d,%d", i, j)] = Position{x: i, y: j}
	}
	i = x
	j = y
	for {
		if i < 0 || i >= b.columns {
			break
		}
		if j < 0 || j >= b.rows {
			break
		}
		i--
		j--
		m[fmt.Sprintf("%d,%d", i, j)] = Position{x: i, y: j}
	}
	i = x
	j = y
	for {
		if i < 0 || i >= b.columns {
			break
		}
		if j < 0 || j >= b.rows {
			break
		}
		i--
		j++
		m[fmt.Sprintf("%d,%d", i, j)] = Position{x: i, y: j}
	}

	ret := make([]Position, 0, b.columns*b.rows)
	for _, c := range m {
		if c.x < 0 || c.y < 0 || c.x >= b.columns || c.y >= b.rows {
			continue
		}
		ret = append(ret, c)
	}
	return ret
}

func (p bishop) String() string {
	return "B"
}

func (p blank) String() string {
	return "."
}

func (p blank) Threatening(b *Board, x, y uint8) []Position {
	return []Position{}
}

func (p dead) String() string {
	return "X"
}

func (p dead) Threatening(b *Board, x, y uint8) []Position {
	return []Position{}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
)

func main() {
	sS, _ := json.Marshal([]string{"broccoli", "almonds", "banana"})
	fmt.Println(string(sS))

	var s []string
	if err := json.Unmarshal(sS, &s); err != nil {
		panic(err)
	}
	fmt.Println("unmarshaled []string:", s)

	variedEncodedSlice := []byte(`["broccoli", 25]`)
	var s2 []string
	if err := json.Unmarshal(variedEncodedSlice, &s2); err != nil {
		panic(err)
	}
	fmt.Println("unmarshaled []string:", s2)
}
<commit_msg>More complete slice with varying types example<commit_after>package main

import (
	"encoding/json"
	"fmt"
)

func main() {
	sS, _ := json.Marshal([]string{"broccoli", "almonds", "banana"})
	fmt.Println(string(sS))

	var s []string
	if err := json.Unmarshal(sS, &s); err != nil {
		panic(err)
	}
	fmt.Println("unmarshaled []string:", s)

	variedEncodedSlice := []byte(`["broccoli", true]`)

	// This will panic if uncommented!
	//var s2 []string
	//if err := json.Unmarshal(variedEncodedSlice, &s2); err != nil {
	//panic(err)
	//}
	//fmt.Println("unmarshaled []string:", s2)

	var iis []interface{}
	if err := json.Unmarshal(variedEncodedSlice, &iis); err != nil {
		panic(err)
	}
	fmt.Println("unmarshalled slice of length:", len(iis))
	for i, e := range iis {
		fmt.Printf("decoding element %d\n", i)
		switch v := e.(type) {
		case bool:
			fmt.Println("  it's a bool:", v)
		case string:
			fmt.Println("  it's a string:", v)
		// other possible types enumerated...
		default:
			panic("can't figure out the type")
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"strconv"

	"github.com/jyggen/advent-of-go/internal/solver"
	"github.com/jyggen/advent-of-go/internal/utils"
)

func main() {
	p1, p2, err := solver.SolveFromFile(os.Stdin, SolvePart1, SolvePart2)
	if err != nil {
		panic(err)
	}

	fmt.Println(p1)
	fmt.Println(p2)
}

func SolvePart1(input string) (string, error) {
	best, _ := simulate(input)

	return strconv.Itoa(best), nil
}

func SolvePart2(input string) (string, error) {
	_, result := simulate(input)

	return strconv.Itoa(result), nil
}

func simulate(input string) (int, int) {
	parts := utils.ToStringSlice(input, ", ")
	xParts := utils.ToStringSlice(parts[0][15:], "..")
	yParts := utils.ToStringSlice(parts[1][2:], "..")
	x1, _ := strconv.Atoi(xParts[0])
	x2, _ := strconv.Atoi(xParts[1])
	y1, _ := strconv.Atoi(yParts[0])
	y2, _ := strconv.Atoi(yParts[1])
	xVelInit := 0
	xSum := 0

	for xSum < x1 {
		xVelInit++
		xSum += xVelInit
	}

	bestY := 0
	validInits := 0

	for xVelInit <= x2 {
		yVelInit := y1

		for yVelInit <= -y1 {
			probe := [2]int{0, 0}
			xVel := xVelInit
			yVel := yVelInit
			highest := 0

			for probe[0] < x2 && probe[1] > y1 {
				probe[0] += xVel
				probe[1] += yVel

				if xVel > 0 {
					xVel--
				} else if xVel < 0 {
					xVel++
				}

				if probe[1] > highest {
					highest = probe[1]
				}

				yVel--

				if probe[0] >= x1 && probe[0] <= x2 && probe[1] >= y1 && probe[1] <= y2 {
					validInits++

					if highest > bestY {
						bestY = highest
					}
					break
				}
			}

			yVelInit++
		}

		xVelInit++
	}

	return bestY, validInits
}
<commit_msg>refactor(2021.17): better min/max calculations<commit_after>package main

import (
	"fmt"
	"math"
	"os"
	"strconv"

	"github.com/jyggen/advent-of-go/internal/solver"
	"github.com/jyggen/advent-of-go/internal/utils"
)

func main() {
	p1, p2, err := solver.SolveFromFile(os.Stdin, SolvePart1, SolvePart2)
	if err != nil {
		panic(err)
	}

	fmt.Println(p1)
	fmt.Println(p2)
}

func SolvePart1(input string) (string, error) {
	best, _ := simulate(input)

	return strconv.Itoa(best), nil
}

func SolvePart2(input string) (string, error) {
	_, result := simulate(input)

	return strconv.Itoa(result), nil
}

func simulate(input string) (int, int) {
	parts := utils.ToStringSlice(input, ", ")
	xParts := utils.ToStringSlice(parts[0][15:], "..")
	yParts := utils.ToStringSlice(parts[1][2:], "..")
	x1, _ := strconv.Atoi(xParts[0])
	x2, _ := strconv.Atoi(xParts[1])
	y1, _ := strconv.Atoi(yParts[0])
	y2, _ := strconv.Atoi(yParts[1])
	validInits := 0
	bestY := 0

	for xInit := int(math.Sqrt(float64(x1 * 2))); xInit <= x2; xInit++ {
		for yInit := y1; yInit < -y1+1; yInit++ {
			probe := [2]int{0, 0}
			xVel := xInit
			yVel := yInit
			highest := 0

			for probe[0] < x2 && probe[1] > y1 {
				probe[0] += xVel
				probe[1] += yVel

				if xVel > 0 {
					xVel--
				} else if xVel < 0 {
					xVel++
				}

				if probe[1] > highest {
					highest = probe[1]
				}

				yVel--

				if probe[0] >= x1 && probe[0] <= x2 && probe[1] >= y1 && probe[1] <= y2 {
					validInits++

					if highest > bestY {
						bestY = highest
					}
					break
				}
			}
		}
	}

	return bestY, validInits
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"math/rand"
	"net/http"
	"time"
)

//checks the user provided device id and returns the same. If none,
//generates a new one and returns the same
func GetDeviceId(deviceId int) int {
	if deviceId == 0 {
		return rand.Intn(time.Now().Nanosecond())
	} else {
		return deviceId
	}
}

func main() {

	//input parameters
	url := flag.String("l", "http://localhost:8080", "hono rest adapter url. Default is http://localhost:8080")
	tenant := flag.String("t", "DEFAULT_TENANT", "default value is DEFAULT_TENANT")
	inputDeviceId := flag.Int("d", 0, "test device id. Leave it to default 0 to generate a random device id")
	register := flag.Bool("r", false, "set to true to register a new device, default is false")
	telemetry := flag.Bool("tm", false, "sends random telemetry data when set to true, default is false")

	flag.Parse()

	httpClient := http.DefaultClient
	honoClient := NewHonoRestClient(httpClient, *url)
	var device = new(DEVICE)
	deviceId := GetDeviceId(*inputDeviceId)

	//Register a new device
	if *register {
		resp, err := CreateDevice(honoClient, *tenant, deviceId)

		if err == nil && resp.StatusCode != http.StatusNotFound {
			honoClient := NewHonoRestClient(httpClient, *url)
			//Get the registered device
			device, _, _ = GetDevice(honoClient, *tenant, deviceId)
		}
	} else if *inputDeviceId != 0 {
		honoClient := NewHonoRestClient(httpClient, *url)
		//Get the registered device
		device, _, _ = GetDevice(honoClient, *tenant, *inputDeviceId)
	} else {
		fmt.Println("Not a valid Device Id is provided to retrieve")
	}

	if *telemetry && device.DATA.ENABLED {
		//send telemetry data
		honoClient := NewHonoRestClient(httpClient, *url)

		resp, err := SendTelemetry(honoClient, *tenant, deviceId)
		for err == nil && resp.StatusCode == http.StatusAccepted {
			time.Sleep(time.Second * 3)
			SendTelemetry(honoClient, *tenant, deviceId)
		}

	}
}
<commit_msg>Exit sending telemetry if data is not accepted by Hono<commit_after>package main

import (
	"flag"
	"fmt"
	"math/rand"
	"net/http"
	"time"
)

//checks the user provided device id and returns the same. If none,
//generates a new one and returns the same
func GetDeviceId(deviceId int) int {
	if deviceId == 0 {
		return rand.Intn(time.Now().Nanosecond())
	} else {
		return deviceId
	}
}

func main() {

	//input parameters
	url := flag.String("l", "http://localhost:8080", "hono rest adapter url. Default is http://localhost:8080")
	tenant := flag.String("t", "DEFAULT_TENANT", "default value is DEFAULT_TENANT")
	inputDeviceId := flag.Int("d", 0, "test device id. Leave it to default 0 to generate a random device id")
	register := flag.Bool("r", false, "set to true to register a new device, default is false")
	telemetry := flag.Bool("tm", false, "sends random telemetry data when set to true, default is false")

	flag.Parse()

	httpClient := http.DefaultClient
	honoClient := NewHonoRestClient(httpClient, *url)
	var device = new(DEVICE)
	deviceId := GetDeviceId(*inputDeviceId)

	//Register a new device
	if *register {
		resp, err := CreateDevice(honoClient, *tenant, deviceId)

		if err == nil && resp.StatusCode != http.StatusNotFound {
			honoClient := NewHonoRestClient(httpClient, *url)
			//Get the registered device
			device, _, _ = GetDevice(honoClient, *tenant, deviceId)
		}
	} else if *inputDeviceId != 0 {
		honoClient := NewHonoRestClient(httpClient, *url)
		//Get the registered device
		device, _, _ = GetDevice(honoClient, *tenant, *inputDeviceId)
	} else {
		fmt.Println("Not a valid Device Id is provided to retrieve")
	}

	if *telemetry && device.DATA.ENABLED {
		//send telemetry data
		honoClient := NewHonoRestClient(httpClient, *url)

		resp, err := SendTelemetry(honoClient, *tenant, deviceId)
		for err == nil && resp.StatusCode == http.StatusAccepted {
			time.Sleep(time.Second * 3)
			resp, err = SendTelemetry(honoClient, *tenant, deviceId)
		}

	}
}
<|endoftext|>


<commit_before>package goproxy

import (
	"bufio"
	"crypto/tls"
	"errors"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"sync/atomic"
)

type ConnectActionLiteral int

const (
	ConnectAccept = iota
	ConnectReject
	ConnectMitm
	ConnectHijack
	ConnectHTTPMitm
)

var (
	OkConnect       = &ConnectAction{Action: ConnectAccept}
	MitmConnect     = &ConnectAction{Action: ConnectMitm}
	HTTPMitmConnect = &ConnectAction{Action: ConnectHTTPMitm}
	RejectConnect   = &ConnectAction{Action: ConnectReject}
)

type ConnectAction struct {
	Action    ConnectActionLiteral
	TlsConfig *tls.Config
	Ca        *tls.Certificate
	Hijack    func(req *http.Request, client net.Conn, ctx *ProxyCtx)
}

func stripPort(s string) string {
	ix := strings.IndexRune(s, ':')
	if ix == -1 {
		return s
	}
	return s[:ix]
}

func (proxy *ProxyHttpServer) dial(network, addr string) (c net.Conn, err error) {
	if proxy.Tr.Dial != nil {
		return proxy.Tr.Dial(network, addr)
	}
	return net.Dial(network, addr)
}

func (proxy *ProxyHttpServer) connectDial(network, addr string) (c net.Conn, err error) {
	if proxy.ConnectDial == nil {
		return proxy.dial(network, addr)
	}
	return proxy.ConnectDial(network, addr)
}

func (proxy *ProxyHttpServer) handleHttps(w http.ResponseWriter, r *http.Request) {
	ctx := &ProxyCtx{Req: r, Session: atomic.AddInt64(&proxy.sess, 1), proxy: proxy}

	hij, ok := w.(http.Hijacker)
	if !ok {
		panic("httpserver does not support hijacking")
	}

	proxyClient, _, e := hij.Hijack()
	if e != nil {
		panic("Cannot hijack connection " + e.Error())
	}

	ctx.Logf("Running %d CONNECT handlers", len(proxy.httpsHandlers))
	todo, host := OkConnect, r.URL.Host
	ctx.Req = r
	for _, h := range proxy.httpsHandlers {
		newtodo, newhost := h.HandleConnect(host, ctx)
		if newtodo != nil {
			todo, host = newtodo, newhost
		}
		ctx.Logf("handler: %v %s", todo, host)
	}
	switch todo.Action {
	case ConnectAccept:
		if !hasPort.MatchString(host) {
			host += ":80"
		}
		targetSiteCon, err := proxy.connectDial("tcp", host)
		if err != nil {
			if _, err := io.WriteString(proxyClient, "HTTP/1.1 502 Bad Gateway\r\n\r\n"); err != nil {
				ctx.Warnf("Error responding to client: %s", err)
			}
			ctx.Warnf("Error dialing to %s: %s", host, err.Error())
			if err := proxyClient.Close(); err != nil {
				ctx.Warnf("Error closing client connection: %s", err)
			}
			return
		}
		ctx.Logf("Accepting CONNECT to %s", host)
		proxyClient.Write([]byte("HTTP/1.0 200 OK\r\n\r\n"))
		go proxy.copyAndClose(targetSiteCon, proxyClient)
		go proxy.copyAndClose(proxyClient, targetSiteCon)
	case ConnectHijack:
		ctx.Logf("Hijacking CONNECT to %s", host)
		proxyClient.Write([]byte("HTTP/1.0 200 OK\r\n\r\n"))
		todo.Hijack(r, proxyClient, ctx)
	case ConnectHTTPMitm:
		proxyClient.Write([]byte("HTTP/1.0 200 OK\r\n\r\n"))
		ctx.Logf("Assuming CONNECT is plain HTTP tunneling, mitm proxying it")
		targetSiteCon, err := proxy.connectDial("tcp", host)
		if err != nil {
			if _, err := io.WriteString(proxyClient, "HTTP/1.1 502 Bad Gateway\r\n\r\n"); err != nil {
				ctx.Warnf("Error responding to client: %s", err)
			}
			ctx.Warnf("Error dialing to %s: %s", host, err.Error())
			if err := proxyClient.Close(); err != nil {
				ctx.Warnf("Error closing client connection: %s", err)
			}
			return
		}
		for {
			client := bufio.NewReader(proxyClient)
			remote := bufio.NewReader(targetSiteCon)
			req, err := http.ReadRequest(client)
			if err != nil && err != io.EOF {
				ctx.Warnf("cannot read request of MITM HTTP client: %+#v", err)
			}
			if err != nil {
				return
			}
			req, resp := proxy.filterRequest(req, ctx)
			if resp == nil {
				if err := req.Write(targetSiteCon); err != nil {
					if _, err := io.WriteString(proxyClient, "HTTP/1.1 502 Bad Gateway\r\n\r\n"); err != nil {
						ctx.Warnf("Error writing to remote: %s", err)
					}
					if err := proxyClient.Close(); err != nil {
						ctx.Warnf("Error closing client connection: %s", err)
					}
					return
				}
				resp, err = http.ReadResponse(remote, req)
				if err != nil {
					if _, err := io.WriteString(proxyClient, "HTTP/1.1 502 Bad Gateway\r\n\r\n"); err != nil {
						ctx.Warnf("Error reading from remote: %s", err)
					}
					if err := proxyClient.Close(); err != nil {
						ctx.Warnf("Error closing client connection: %s", err)
					}
					return
				}
			}
			resp = proxy.filterResponse(resp, ctx)
			if err := resp.Write(proxyClient); err != nil {
				if _, err := io.WriteString(proxyClient, "HTTP/1.1 502 Bad Gateway\r\n\r\n"); err != nil {
					ctx.Warnf("Error writing response to client: %s", err)
				}
				if err := proxyClient.Close(); err != nil {
					ctx.Warnf("Error closing client connection: %s", err)
				}
				return
			}
		}
	case ConnectMitm:
		proxyClient.Write([]byte("HTTP/1.0 200 OK\r\n\r\n"))
		ctx.Logf("Assuming CONNECT is TLS, mitm proxying it")
		// this goes in a separate goroutine, so that the net/http server won't think we're
		// still handling the request even after hijacking the connection. Those HTTP CONNECT
		// request can take forever, and the server will be stuck when "closed".
		// TODO: Allow Server.Close() mechanism to shut down this connection as nicely as possible
		ca := todo.Ca
		if ca == nil {
			ca = &GoproxyCa
		}
		cert, err := signHost(*ca, []string{stripPort(host)})
		if err != nil {
			ctx.Warnf("Cannot sign host certificate with provided CA: %s", err)
			return
		}
		tlsConfig := tls.Config{}
		if todo.TlsConfig != nil {
			tlsConfig = *todo.TlsConfig
		} else {
			tlsConfig = *defaultTlsConfig
		}
		tlsConfig.Certificates = append(tlsConfig.Certificates, cert)
		go func() {
			//TODO: cache connections to the remote website
			rawClientTls := tls.Server(proxyClient, &tlsConfig)
			if err := rawClientTls.Handshake(); err != nil {
				ctx.Warnf("Cannot handshake client %v %v", r.Host, err)
				return
			}
			defer rawClientTls.Close()
			clientTlsReader := bufio.NewReader(rawClientTls)
			for !isEof(clientTlsReader) {
				req, err := http.ReadRequest(clientTlsReader)
				if err != nil {
					ctx.Warnf("Cannot read TLS request from mitm'd client %v %v", r.Host, err)
					return
				}
				ctx.Logf("req %v", r.Host)
				req.URL, err = url.Parse("https://" + r.Host + req.URL.String())
				req, resp := proxy.filterRequest(req, ctx)
				if resp == nil {
					if err != nil {
						ctx.Warnf("Illegal URL %s", "https://"+r.Host+req.URL.Path)
						return
					}
					removeProxyHeaders(ctx, req)
					resp, err = proxy.Tr.RoundTrip(req)
					if err != nil {
						ctx.Warnf("Cannot read TLS response from mitm'd server %v", err)
						return
					}
					ctx.Logf("resp %v", resp.Status)
				}
				resp = proxy.filterResponse(resp, ctx)
				text := resp.Status
				statusCode := strconv.Itoa(resp.StatusCode) + " "
				if strings.HasPrefix(text, statusCode) {
					text = text[len(statusCode):]
				}
				// always use 1.1 to support chunked encoding
				if _, err := io.WriteString(rawClientTls, "HTTP/1.1"+" "+statusCode+text+"\r\n"); err != nil {
					ctx.Warnf("Cannot write TLS response HTTP status from mitm'd client: %v", err)
					return
				}
				// Since we don't know the length of resp, return chunked encoded response
				// TODO: use a more reasonable scheme
				resp.Header.Del("Content-Length")
				resp.Header.Set("Transfer-Encoding", "chunked")
				if err := resp.Header.Write(rawClientTls); err != nil {
					ctx.Warnf("Cannot write TLS response header from mitm'd client: %v", err)
					return
				}
				if _, err = io.WriteString(rawClientTls, "\r\n"); err != nil {
					ctx.Warnf("Cannot write TLS response header end from mitm'd client: %v", err)
					return
				}
				chunked := newChunkedWriter(rawClientTls)
				if _, err := io.Copy(chunked, resp.Body); err != nil {
					ctx.Warnf("Cannot write TLS response body from mitm'd client: %v", err)
					return
				}
				if err := chunked.Close(); err != nil {
					ctx.Warnf("Cannot write TLS chunked EOF from mitm'd client: %v", err)
					return
				}
				if _, err = io.WriteString(rawClientTls, "\r\n"); err != nil {
					ctx.Warnf("Cannot write TLS response chunked trailer from mitm'd client: %v", err)
					return
				}
			}
			ctx.Logf("Exiting on EOF")
		}()
	case ConnectReject:
		if ctx.Resp != nil {
			if err := ctx.Resp.Write(proxyClient); err != nil {
				ctx.Warnf("Cannot write response that reject http CONNECT: %v", err)
			}
		}
		proxyClient.Close()
	}
}

func dialerFromEnv(proxy *ProxyHttpServer) func(network, addr string) (net.Conn, error) {
	https_proxy := os.Getenv("HTTPS_PROXY")
	if https_proxy == "" {
		https_proxy = os.Getenv("https_proxy")
	}
	if https_proxy == "" {
		return nil
	}
	return proxy.NewConnectDialToProxy(https_proxy)
}

func (proxy *ProxyHttpServer) NewConnectDialToProxy(https_proxy string) func(network, addr string) (net.Conn, error) {
	u, err := url.Parse(https_proxy)
	if err != nil {
		return nil
	}
	if u.Scheme == "" || u.Scheme == "http" {
		if strings.IndexRune(u.Host, ':') == -1 {
			u.Host += ":80"
		}
		return func(network, addr string) (net.Conn, error) {
			connectReq := &http.Request{
				Method: "CONNECT",
				URL:    &url.URL{Opaque: addr},
				Host:   addr,
				Header: make(http.Header),
			}
			c, err := proxy.dial(network, u.Host)
			if err != nil {
				return nil, err
			}
			connectReq.Write(c)
			// Read response.
			// Okay to use and discard buffered reader here, because
			// TLS server will not speak until spoken to.
			br := bufio.NewReader(c)
			resp, err := http.ReadResponse(br, connectReq)
			if err != nil {
				c.Close()
				return nil, err
			}
			if resp.StatusCode != 200 {
				resp, _ := ioutil.ReadAll(resp.Body)
				c.Close()
				return nil, errors.New("proxy refused connection" + string(resp))
			}
			return c, nil
		}
	}
	if u.Scheme == "https" {
		if strings.IndexRune(u.Host, ':') == -1 {
			u.Host += ":443"
		}
		return func(network, addr string) (net.Conn, error) {
			c, err := proxy.dial(network, u.Host)
			if err != nil {
				return nil, err
			}
			c = tls.Client(c, proxy.Tr.TLSClientConfig)
			connectReq := &http.Request{
				Method: "CONNECT",
				URL:    &url.URL{Opaque: addr},
				Host:   addr,
				Header: make(http.Header),
			}
			connectReq.Write(c)
			// Read response.
			// Okay to use and discard buffered reader here, because
			// TLS server will not speak until spoken to.
			br := bufio.NewReader(c)
			resp, err := http.ReadResponse(br, connectReq)
			if err != nil {
				c.Close()
				return nil, err
			}
			if resp.StatusCode != 200 {
				body, _ := ioutil.ReadAll(io.LimitReader(resp.Body, 500))
				resp.Body.Close()
				c.Close()
				return nil, errors.New("proxy refused connection" + string(body))
			}
			return c, nil
		}
	}
	return nil
}
<commit_msg>refactor: httpError to write error to socket<commit_after>package goproxy

import (
	"bufio"
	"crypto/tls"
	"errors"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"sync/atomic"
)

type ConnectActionLiteral int

const (
	ConnectAccept = iota
	ConnectReject
	ConnectMitm
	ConnectHijack
	ConnectHTTPMitm
)

var (
	OkConnect       = &ConnectAction{Action: ConnectAccept}
	MitmConnect     = &ConnectAction{Action: ConnectMitm}
	HTTPMitmConnect = &ConnectAction{Action: ConnectHTTPMitm}
	RejectConnect   = &ConnectAction{Action: ConnectReject}
)

type ConnectAction struct {
	Action    ConnectActionLiteral
	TlsConfig *tls.Config
	Ca        *tls.Certificate
	Hijack    func(req *http.Request, client net.Conn, ctx *ProxyCtx)
}

func stripPort(s string) string {
	ix := strings.IndexRune(s, ':')
	if ix == -1 {
		return s
	}
	return s[:ix]
}

func (proxy *ProxyHttpServer) dial(network, addr string) (c net.Conn, err error) {
	if proxy.Tr.Dial != nil {
		return proxy.Tr.Dial(network, addr)
	}
	return net.Dial(network, addr)
}

func (proxy *ProxyHttpServer) connectDial(network, addr string) (c net.Conn, err error) {
	if proxy.ConnectDial == nil {
		return proxy.dial(network, addr)
	}
	return proxy.ConnectDial(network, addr)
}

func (proxy *ProxyHttpServer) handleHttps(w http.ResponseWriter, r *http.Request) {
	ctx := &ProxyCtx{Req: r, Session: atomic.AddInt64(&proxy.sess, 1), proxy: proxy}

	hij, ok := w.(http.Hijacker)
	if !ok {
		panic("httpserver does not support hijacking")
	}

	proxyClient, _, e := hij.Hijack()
	if e != nil {
		panic("Cannot hijack connection " + e.Error())
	}

	ctx.Logf("Running %d CONNECT handlers", len(proxy.httpsHandlers))
	todo, host := OkConnect, r.URL.Host
	ctx.Req = r
	for _, h := range proxy.httpsHandlers {
		newtodo, newhost := h.HandleConnect(host, ctx)
		if newtodo != nil {
			todo, host = newtodo, newhost
		}
		ctx.Logf("handler: %v %s", todo, host)
	}
	switch todo.Action {
	case ConnectAccept:
		if !hasPort.MatchString(host) {
			host += ":80"
		}
		targetSiteCon, err := proxy.connectDial("tcp", host)
		if err != nil {
			return
		}
		ctx.Logf("Accepting CONNECT to %s", host)
		proxyClient.Write([]byte("HTTP/1.0 200 OK\r\n\r\n"))
		go proxy.copyAndClose(targetSiteCon, proxyClient)
		go proxy.copyAndClose(proxyClient, targetSiteCon)
	case ConnectHijack:
		ctx.Logf("Hijacking CONNECT to %s", host)
		proxyClient.Write([]byte("HTTP/1.0 200 OK\r\n\r\n"))
		todo.Hijack(r, proxyClient, ctx)
	case ConnectHTTPMitm:
		proxyClient.Write([]byte("HTTP/1.0 200 OK\r\n\r\n"))
		ctx.Logf("Assuming CONNECT is plain HTTP tunneling, mitm proxying it")
		targetSiteCon, err := proxy.connectDial("tcp", host)
		if err != nil {
			ctx.Warnf("Error dialing to %s: %s", host, err.Error())
			return
		}
		for {
			client := bufio.NewReader(proxyClient)
			remote := bufio.NewReader(targetSiteCon)
			req, err := http.ReadRequest(client)
			if err != nil && err != io.EOF {
				ctx.Warnf("cannot read request of MITM HTTP client: %+#v", err)
			}
			if err != nil {
				return
			}
			req, resp := proxy.filterRequest(req, ctx)
			if resp == nil {
				if err := req.Write(targetSiteCon); err != nil {
					httpError(proxyClient, ctx)
					return
				}
				resp, err = http.ReadResponse(remote, req)
				if err != nil {
					httpError(proxyClient, ctx)
					return
				}
			}
			resp = proxy.filterResponse(resp, ctx)
			if err := resp.Write(proxyClient); err != nil {
				httpError(proxyClient, ctx)
				return
			}
		}
	case ConnectMitm:
		proxyClient.Write([]byte("HTTP/1.0 200 OK\r\n\r\n"))
		ctx.Logf("Assuming CONNECT is TLS, mitm proxying it")
		// this goes in a separate goroutine, so that the net/http server won't think we're
		// still handling the request even after hijacking the connection. Those HTTP CONNECT
		// request can take forever, and the server will be stuck when "closed".
		// TODO: Allow Server.Close() mechanism to shut down this connection as nicely as possible
		ca := todo.Ca
		if ca == nil {
			ca = &GoproxyCa
		}
		cert, err := signHost(*ca, []string{stripPort(host)})
		if err != nil {
			ctx.Warnf("Cannot sign host certificate with provided CA: %s", err)
			return
		}
		tlsConfig := tls.Config{}
		if todo.TlsConfig != nil {
			tlsConfig = *todo.TlsConfig
		} else {
			tlsConfig = *defaultTlsConfig
		}
		tlsConfig.Certificates = append(tlsConfig.Certificates, cert)
		go func() {
			//TODO: cache connections to the remote website
			rawClientTls := tls.Server(proxyClient, &tlsConfig)
			if err := rawClientTls.Handshake(); err != nil {
				ctx.Warnf("Cannot handshake client %v %v", r.Host, err)
				return
			}
			defer rawClientTls.Close()
			clientTlsReader := bufio.NewReader(rawClientTls)
			for !isEof(clientTlsReader) {
				req, err := http.ReadRequest(clientTlsReader)
				if err != nil {
					ctx.Warnf("Cannot read TLS request from mitm'd client %v %v", r.Host, err)
					return
				}
				ctx.Logf("req %v", r.Host)
				req.URL, err = url.Parse("https://" + r.Host + req.URL.String())
				req, resp := proxy.filterRequest(req, ctx)
				if resp == nil {
					if err != nil {
						ctx.Warnf("Illegal URL %s", "https://"+r.Host+req.URL.Path)
						return
					}
					removeProxyHeaders(ctx, req)
					resp, err = proxy.Tr.RoundTrip(req)
					if err != nil {
						ctx.Warnf("Cannot read TLS response from mitm'd server %v", err)
						return
					}
					ctx.Logf("resp %v", resp.Status)
				}
				resp = proxy.filterResponse(resp, ctx)
				text := resp.Status
				statusCode := strconv.Itoa(resp.StatusCode) + " "
				if strings.HasPrefix(text, statusCode) {
					text = text[len(statusCode):]
				}
				// always use 1.1 to support chunked encoding
				if _, err := io.WriteString(rawClientTls, "HTTP/1.1"+" "+statusCode+text+"\r\n"); err != nil {
					ctx.Warnf("Cannot write TLS response HTTP status from mitm'd client: %v", err)
					return
				}
				// Since we don't know the length of resp, return chunked encoded response
				// TODO: use a more reasonable scheme
				resp.Header.Del("Content-Length")
				resp.Header.Set("Transfer-Encoding", "chunked")
				if err := resp.Header.Write(rawClientTls); err != nil {
					ctx.Warnf("Cannot write TLS response header from mitm'd client: %v", err)
					return
				}
				if _, err = io.WriteString(rawClientTls, "\r\n"); err != nil {
					ctx.Warnf("Cannot write TLS response header end from mitm'd client: %v", err)
					return
				}
				chunked := newChunkedWriter(rawClientTls)
				if _, err := io.Copy(chunked, resp.Body); err != nil {
					ctx.Warnf("Cannot write TLS response body from mitm'd client: %v", err)
					return
				}
				if err := chunked.Close(); err != nil {
					ctx.Warnf("Cannot write TLS chunked EOF from mitm'd client: %v", err)
					return
				}
				if _, err = io.WriteString(rawClientTls, "\r\n"); err != nil {
					ctx.Warnf("Cannot write TLS response chunked trailer from mitm'd client: %v", err)
					return
				}
			}
			ctx.Logf("Exiting on EOF")
		}()
	case ConnectReject:
		if ctx.Resp != nil {
			if err := ctx.Resp.Write(proxyClient); err != nil {
				ctx.Warnf("Cannot write response that reject http CONNECT: %v", err)
			}
		}
		proxyClient.Close()
	}
}

func httpError(w io.WriteCloser, ctx *ProxyCtx) {
	if _, err := io.WriteString(w, "HTTP/1.1 502 Bad Gateway\r\n\r\n"); err != nil {
		ctx.Warnf("Error responding to client: %s", err)
	}
	if err := w.Close(); err != nil {
		ctx.Warnf("Error closing client connection: %s", err)
	}
}

func dialerFromEnv(proxy *ProxyHttpServer) func(network, addr string) (net.Conn, error) {
	https_proxy := os.Getenv("HTTPS_PROXY")
	if https_proxy == "" {
		https_proxy = os.Getenv("https_proxy")
	}
	if https_proxy == "" {
		return nil
	}
	return proxy.NewConnectDialToProxy(https_proxy)
}

func (proxy *ProxyHttpServer) NewConnectDialToProxy(https_proxy string) func(network, addr string) (net.Conn, error) {
	u, err := url.Parse(https_proxy)
	if err != nil {
		return nil
	}
	if u.Scheme == "" || u.Scheme == "http" {
		if strings.IndexRune(u.Host, ':') == -1 {
			u.Host += ":80"
		}
		return func(network, addr string) (net.Conn, error) {
			connectReq := &http.Request{
				Method: "CONNECT",
				URL:    &url.URL{Opaque: addr},
				Host:   addr,
				Header: make(http.Header),
			}
			c, err := proxy.dial(network, u.Host)
			if err != nil {
				return nil, err
			}
			connectReq.Write(c)
			// Read response.
			// Okay to use and discard buffered reader here, because
			// TLS server will not speak until spoken to.
			br := bufio.NewReader(c)
			resp, err := http.ReadResponse(br, connectReq)
			if err != nil {
				c.Close()
				return nil, err
			}
			if resp.StatusCode != 200 {
				resp, _ := ioutil.ReadAll(resp.Body)
				c.Close()
				return nil, errors.New("proxy refused connection" + string(resp))
			}
			return c, nil
		}
	}
	if u.Scheme == "https" {
		if strings.IndexRune(u.Host, ':') == -1 {
			u.Host += ":443"
		}
		return func(network, addr string) (net.Conn, error) {
			c, err := proxy.dial(network, u.Host)
			if err != nil {
				return nil, err
			}
			c = tls.Client(c, proxy.Tr.TLSClientConfig)
			connectReq := &http.Request{
				Method: "CONNECT",
				URL:    &url.URL{Opaque: addr},
				Host:   addr,
				Header: make(http.Header),
			}
			connectReq.Write(c)
			// Read response.
			// Okay to use and discard buffered reader here, because
			// TLS server will not speak until spoken to.
			br := bufio.NewReader(c)
			resp, err := http.ReadResponse(br, connectReq)
			if err != nil {
				c.Close()
				return nil, err
			}
			if resp.StatusCode != 200 {
				body, _ := ioutil.ReadAll(io.LimitReader(resp.Body, 500))
				resp.Body.Close()
				c.Close()
				return nil, errors.New("proxy refused connection" + string(body))
			}
			return c, nil
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package m

import (
	"sync"

	"github.com/emicklei/melrose"
)

func Sequence(notation string) melrose.Sequenceable {
	return melrose.MustParseSequence(notation)
}

func Repeat(times int, s melrose.Sequenceable) melrose.Sequenceable {
	return melrose.Repeat{Target: s, Times: times}
}

func Pitch(semitones int, s melrose.Sequenceable) melrose.Sequenceable {
	return melrose.Pitch{Target: s, Semitones: melrose.On(semitones)}
}

func Parallel(s melrose.Sequenceable) melrose.Sequenceable {
	return melrose.Parallel{Target: s}
}

func Note(s string) melrose.Note { return melrose.MustParseNote(s) }

func Join(s ...melrose.Sequenceable) melrose.Sequenceable {
	return melrose.Join{List: s}
}

func Go(a melrose.AudioDevice, s ...melrose.Sequenceable) {
	wg := new(sync.WaitGroup)
	for _, each := range s {
		wg.Add(1)
		go func(p melrose.Sequenceable) {
			a.Play(p, true)
			wg.Done()
		}(each)
	}
	wg.Wait()
}

// IndexMap creates a IndexMapper from indices.
// Example of indices: "1 (2 3 4) 5 (6 7)". One-based indexes.
func IndexMap(s melrose.Sequenceable, indices string) melrose.Sequenceable {
	return melrose.NewIndexMapper(s, indices)
}

// Chord creates a new Chord by parsing the input. See Chord for the syntax.
func Chord(s string) melrose.Chord {
	return melrose.MustParseChord(s)
}

// Serial returns a new object that serialises all the notes of the argument.
func Serial(s melrose.Sequenceable) melrose.Sequenceable {
	return melrose.Serial{Target: s}
}

func Channel(nr int, s melrose.Sequenceable) melrose.ChannelSelector {
	return melrose.ChannelSelector{Target: s, Number: melrose.On(nr)}
}
<commit_msg>change return types in m<commit_after>package m

import (
	"sync"

	"github.com/emicklei/melrose"
)

func Sequence(notation string) melrose.Sequence {
	return melrose.MustParseSequence(notation)
}

func Repeat(times int, s melrose.Sequenceable) melrose.Repeat {
	return melrose.Repeat{Target: s, Times: times}
}

func Pitch(semitones int, s melrose.Sequenceable) melrose.Pitch {
	return melrose.Pitch{Target: s, Semitones: melrose.On(semitones)}
}

func Parallel(s melrose.Sequenceable) melrose.Parallel {
	return melrose.Parallel{Target: s}
}

func Note(s string) melrose.Note { return melrose.MustParseNote(s) }

func Join(s ...melrose.Sequenceable) melrose.Join {
	return melrose.Join{List: s}
}

func Go(a melrose.AudioDevice, s ...melrose.Sequenceable) {
	wg := new(sync.WaitGroup)
	for _, each := range s {
		wg.Add(1)
		go func(p melrose.Sequenceable) {
			a.Play(p, true)
			wg.Done()
		}(each)
	}
	wg.Wait()
}

// IndexMap creates a IndexMapper from indices.
// Example of indices: "1 (2 3 4) 5 (6 7)". One-based indexes.
func IndexMap(s melrose.Sequenceable, indices string) melrose.IndexMapper {
	return melrose.NewIndexMapper(s, indices)
}

// Chord creates a new Chord by parsing the input. See Chord for the syntax.
func Chord(s string) melrose.Chord {
	return melrose.MustParseChord(s)
}

// Serial returns a new object that serialises all the notes of the argument.
func Serial(s melrose.Sequenceable) melrose.Serial {
	return melrose.Serial{Target: s}
}

func Channel(nr int, s melrose.Sequenceable) melrose.ChannelSelector {
	return melrose.ChannelSelector{Target: s, Number: melrose.On(nr)}
}
<|endoftext|>


<commit_before>package proxmox

import (
	"errors"
	"net/url"
	"strconv"
	"strings"
	"time"

	_ "github.com/davecgh/go-spew/spew"
)

type QemuVM struct {
	Mem       float64 `json:"mem"`
	CPUs      float64 `json:"cpus"`
	NetOut    float64 `json:"netout"`
	PID       string  `json:"pid"`
	Disk      float64 `json:"disk"`
	MaxMem    float64 `json:"maxmem"`
	Status    string  `json:"status"`
	Template  float64 `json:"template"`
	NetIn     float64 `json:"netin"`
	MaxDisk   float64 `json:"maxdisk"`
	Name      string  `json:"name"`
	DiskWrite float64 `json:"diskwrite"`
	CPU       float64 `json:"cpu"`
	VMId      float64 `json:"vmid"`
	DiskRead  float64 `json:"diskread"`
	Uptime    float64 `json:"uptime"`
	Node      Node
}

type QemuList map[string]QemuVM

type QemuNet map[string]string

type QemuConfig struct {
	Bootdisk    string  `json:"bootdisk"`
	Cores       float64 `json:"cores"`
	Digest      string  `json:"digest"`
	Memory      float64 `json:"memory"`
	Net         map[string]QemuNet
	SMBios1     string            `json:"smbios1"`
	Sockets     float64           `json:"sockets"`
	Disks       map[string]string `json:"disks"`
	Description string            `json:"description"`
}

type QemuStatus struct {
	CPU       float64 `json:"cpu"`
	CPUs      float64 `json:"cpus"`
	Mem       float64 `json:"mem"`
	MaxMem    float64 `json:"maxmem"`
	Disk      float64 `json:"disk"`
	MaxDisk   float64 `json:"maxdisk"`
	DiskWrite float64 `json:"diskwrite"`
	DiskRead  float64 `json:"diskread"`
	NetIn     float64 `json:"netin"`
	NetOut    float64 `json:"netout"`
	Uptime    float64 `json:"uptime"`
	QmpStatus string  `json:"qmpstatus"`
	Status    string  `json:"status"`
	Template  string  `json:"template"`
}

func (qemu QemuVM) Delete() (map[string]interface{}, error) {
	var target string
	var data map[string]interface{}
	var err error

	//fmt.Print("!QemuDelete ", qemu.VMId)

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64)
	data, err = qemu.Node.Proxmox.Delete(target)
	if err != nil {
		return nil, err
	}
	return data, nil
}

func stringToMap(data string, itemSeparator string, kvSeparator string) map[string]string {
	var result map[string]string

	result = make(map[string]string)
	list := strings.Split(data, itemSeparator)
	for _, item := range list {
		kv := strings.Split(item, kvSeparator)
		result[kv[0]] = kv[1]
	}
	return result
}

func (qemu QemuVM) Config() (QemuConfig, error) {
	var target string
	var data map[string]interface{}
	var results map[string]interface{}
	var config QemuConfig
	var err error

	//fmt.Print("!QemuConfig ", qemu.VMId)

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/config"
	data, err = qemu.Node.Proxmox.Get(target)
	results = data["data"].(map[string]interface{})
	if err != nil {
		return config, err
	}
	config = QemuConfig{
		Bootdisk:    results["bootdisk"].(string),
		Cores:       results["cores"].(float64),
		Digest:      results["digest"].(string),
		Memory:      results["memory"].(float64),
		Sockets:     results["sockets"].(float64),
		SMBios1:     results["smbios1"].(string),
		Description: results["description"].(string),
	}
	disktype := [3]string{"virtio", "sata", "ide"}
	disknum := [4]string{"0", "1", "2", "3"}
	config.Disks = make(map[string]string)
	for _, d := range disktype {
		for _, i := range disknum {
			id := d + i
			if disk, ok := results[id]; ok {
				config.Disks[id] = disk.(string)
			}
		}
	}
	config.Net = make(map[string]QemuNet)
	netnum := [4]string{"0", "1", "2", "3"}
	for _, n := range netnum {
		if net, ok := results["net"+n]; ok {
			config.Net["net"+n] = stringToMap(net.(string), ",", "=")
		}
	}

	return config, nil
}

func (qemu QemuVM) CurrentStatus() (QemuStatus, error) {
	var target string
	var err error
	var data map[string]interface{}
	var results map[string]interface{}
	var status QemuStatus

	//fmt.Println("!QemuStatus ", strconv.FormatFloat(qemu.VMId, 'f', 0, 64))

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/status/current"
	data, err = qemu.Node.Proxmox.Get(target)
	if err != nil {
		return status, err
	}
	results = data["data"].(map[string]interface{})
	status = QemuStatus{
		CPU:       results["cpu"].(float64),
		CPUs:      results["cpus"].(float64),
		Mem:       results["mem"].(float64),
		MaxMem:    results["maxmem"].(float64),
		Disk:      results["disk"].(float64),
		MaxDisk:   results["maxdisk"].(float64),
		DiskWrite: results["diskwrite"].(float64),
		DiskRead:  results["diskread"].(float64),
		NetIn:     results["netin"].(float64),
		NetOut:    results["netout"].(float64),
		Uptime:    results["uptime"].(float64),
		QmpStatus: results["qmpstatus"].(string),
		Status:    results["status"].(string),
		Template:  results["template"].(string),
	}
	return status, nil
}

func (qemu QemuVM) WaitForStatus(status string, timeout int) error {
	var i int
	var err error
	var qStatus QemuStatus
	for i = 0; i < timeout; i++ {
		qStatus, err = qemu.CurrentStatus()
		if err != nil {
			return err
		}

		if qStatus.Status == status {
			return nil
		}
		time.Sleep(time.Second * 1)
	}
	return errors.New("Timeout reached")
}

func (qemu QemuVM) Start() error {
	var target string
	var err error

	//fmt.Println("!QemuStart ", strconv.FormatFloat(qemu.VMId, 'f', 0, 64))

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/status/start"
	_, err = qemu.Node.Proxmox.Post(target, "")
	return err
}

func (qemu QemuVM) Stop() error {
	var target string
	var err error

	//fmt.Print("!QemuStop ", qemu.VMId)

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/status/stop"
	_, err = qemu.Node.Proxmox.Post(target, "")
	return err
}

func (qemu QemuVM) Shutdown() (Task, error) {
	var target string
	var err error

	//fmt.Print("!QemuShutdown ", qemu.VMId)

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/status/shutdown"
	data, err := qemu.Node.Proxmox.Post(target, "")

	if err != err {
		return Task{}, err
	}

	t := Task{
		UPid:    data["data"].(string),
		proxmox: qemu.Node.Proxmox,
	}

	return t, err
}

func (qemu QemuVM) Suspend() error {
	var target string
	var err error

	//fmt.Print("!QemuSuspend ", qemu.VMId)

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/status/suspend"
	_, err = qemu.Node.Proxmox.Post(target, "")
	return err
}

func (qemu QemuVM) Resume() error {
	var target string
	var err error

	//fmt.Print("!QemuResume ", qemu.VMId)

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/status/resume"
	_, err = qemu.Node.Proxmox.Post(target, "")
	return err
}

func (qemu QemuVM) Clone(newId float64, name string, targetName string) (Task, error) {
	var target string
	var err error

	newVMID := strconv.FormatFloat(newId, 'f', 0, 64)

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/clone"

	form := url.Values{
		"newid":  {newVMID},
		"name":   {name},
		"target": {targetName},
		"full":   {"1"},
	}

	data, err := qemu.Node.Proxmox.PostForm(target, form)
	if err != err {
		return Task{}, err
	}

	t := Task{
		UPid:    data["data"].(string),
		proxmox: qemu.Node.Proxmox,
	}

	return t, nil
}

func (qemu QemuVM) SetIPSet(ip string) error {
	var target string
	var err error

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/firewall/options"

	form := url.Values{
		"dhcp":          {"1"},
		"enable":        {"1"},
		"log_level_in":  {"nolog"},
		"log_level_out": {"nolog"},
		"macfilter":     {"1"},
		"ipfilter":      {"1"},
		"ndp":           {"1"},
		"policy_in":     {"ACCEPT"},
		"policy_out":    {"ACCEPT"},
	}

	_, err = qemu.Node.Proxmox.PutForm(target, form)
	if err != nil {
		return err
	}

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/firewall/ipset"

	form = url.Values{
		"name": {"ipfilter-net0"},
	}

	_, err = qemu.Node.Proxmox.PostForm(target, form)
	if err != nil {
		return err
	}

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/firewall/ipset/ipfilter-net0"

	form = url.Values{
		"cidr": {ip},
	}

	_, err = qemu.Node.Proxmox.PostForm(target, form)
	if err != nil {
		return err
	}

	config, err := qemu.Config()
	if err != nil {
		return err
	}

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/config"

	net := ""

	for k, v := range config.Net["net0"] {
		net += k + "=" + v + ","
	}

	form = url.Values{
		"net0": {net + ",firewall=1"},
	}

	_, err = qemu.Node.Proxmox.PutForm(target, form)
	if err != nil {
		return err
	}

	return nil
}

func (qemu QemuVM) ResizeDisk(size string) error {
	var target string
	var err error

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/resize"

	form := url.Values{
		"disk": {"scsi1"},
		"size": {size + "G"},
	}

	_, err = qemu.Node.Proxmox.PutForm(target, form)
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>add function to set description<commit_after>package proxmox

import (
	"errors"
	"net/url"
	"strconv"
	"strings"
	"time"

	_ "github.com/davecgh/go-spew/spew"
)

type QemuVM struct {
	Mem       float64 `json:"mem"`
	CPUs      float64 `json:"cpus"`
	NetOut    float64 `json:"netout"`
	PID       string  `json:"pid"`
	Disk      float64 `json:"disk"`
	MaxMem    float64 `json:"maxmem"`
	Status    string  `json:"status"`
	Template  float64 `json:"template"`
	NetIn     float64 `json:"netin"`
	MaxDisk   float64 `json:"maxdisk"`
	Name      string  `json:"name"`
	DiskWrite float64 `json:"diskwrite"`
	CPU       float64 `json:"cpu"`
	VMId      float64 `json:"vmid"`
	DiskRead  float64 `json:"diskread"`
	Uptime    float64 `json:"uptime"`
	Node      Node
}

type QemuList map[string]QemuVM

type QemuNet map[string]string

type QemuConfig struct {
	Bootdisk    string  `json:"bootdisk"`
	Cores       float64 `json:"cores"`
	Digest      string  `json:"digest"`
	Memory      float64 `json:"memory"`
	Net         map[string]QemuNet
	SMBios1     string            `json:"smbios1"`
	Sockets     float64           `json:"sockets"`
	Disks       map[string]string `json:"disks"`
	Description string            `json:"description"`
}

type QemuStatus struct {
	CPU       float64 `json:"cpu"`
	CPUs      float64 `json:"cpus"`
	Mem       float64 `json:"mem"`
	MaxMem    float64 `json:"maxmem"`
	Disk      float64 `json:"disk"`
	MaxDisk   float64 `json:"maxdisk"`
	DiskWrite float64 `json:"diskwrite"`
	DiskRead  float64 `json:"diskread"`
	NetIn     float64 `json:"netin"`
	NetOut    float64 `json:"netout"`
	Uptime    float64 `json:"uptime"`
	QmpStatus string  `json:"qmpstatus"`
	Status    string  `json:"status"`
	Template  string  `json:"template"`
}

func (qemu QemuVM) Delete() (map[string]interface{}, error) {
	var target string
	var data map[string]interface{}
	var err error

	//fmt.Print("!QemuDelete ", qemu.VMId)

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64)
	data, err = qemu.Node.Proxmox.Delete(target)
	if err != nil {
		return nil, err
	}
	return data, nil
}

func stringToMap(data string, itemSeparator string, kvSeparator string) map[string]string {
	var result map[string]string

	result = make(map[string]string)
	list := strings.Split(data, itemSeparator)
	for _, item := range list {
		kv := strings.Split(item, kvSeparator)
		result[kv[0]] = kv[1]
	}
	return result
}

func (qemu QemuVM) Config() (QemuConfig, error) {
	var target string
	var data map[string]interface{}
	var results map[string]interface{}
	var config QemuConfig
	var err error

	//fmt.Print("!QemuConfig ", qemu.VMId)

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/config"
	data, err = qemu.Node.Proxmox.Get(target)
	results = data["data"].(map[string]interface{})
	if err != nil {
		return config, err
	}
	config = QemuConfig{
		Bootdisk:    results["bootdisk"].(string),
		Cores:       results["cores"].(float64),
		Digest:      results["digest"].(string),
		Memory:      results["memory"].(float64),
		Sockets:     results["sockets"].(float64),
		SMBios1:     results["smbios1"].(string),
		Description: results["description"].(string),
	}
	disktype := [3]string{"virtio", "sata", "ide"}
	disknum := [4]string{"0", "1", "2", "3"}
	config.Disks = make(map[string]string)
	for _, d := range disktype {
		for _, i := range disknum {
			id := d + i
			if disk, ok := results[id]; ok {
				config.Disks[id] = disk.(string)
			}
		}
	}
	config.Net = make(map[string]QemuNet)
	netnum := [4]string{"0", "1", "2", "3"}
	for _, n := range netnum {
		if net, ok := results["net"+n]; ok {
			config.Net["net"+n] = stringToMap(net.(string), ",", "=")
		}
	}

	return config, nil
}

func (qemu QemuVM) CurrentStatus() (QemuStatus, error) {
	var target string
	var err error
	var data map[string]interface{}
	var results map[string]interface{}
	var status QemuStatus

	//fmt.Println("!QemuStatus ", strconv.FormatFloat(qemu.VMId, 'f', 0, 64))

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/status/current"
	data, err = qemu.Node.Proxmox.Get(target)
	if err != nil {
		return status, err
	}
	results = data["data"].(map[string]interface{})
	status = QemuStatus{
		CPU:       results["cpu"].(float64),
		CPUs:      results["cpus"].(float64),
		Mem:       results["mem"].(float64),
		MaxMem:    results["maxmem"].(float64),
		Disk:      results["disk"].(float64),
		MaxDisk:   results["maxdisk"].(float64),
		DiskWrite: results["diskwrite"].(float64),
		DiskRead:  results["diskread"].(float64),
		NetIn:     results["netin"].(float64),
		NetOut:    results["netout"].(float64),
		Uptime:    results["uptime"].(float64),
		QmpStatus: results["qmpstatus"].(string),
		Status:    results["status"].(string),
		Template:  results["template"].(string),
	}
	return status, nil
}

func (qemu QemuVM) WaitForStatus(status string, timeout int) error {
	var i int
	var err error
	var qStatus QemuStatus
	for i = 0; i < timeout; i++ {
		qStatus, err = qemu.CurrentStatus()
		if err != nil {
			return err
		}

		if qStatus.Status == status {
			return nil
		}
		time.Sleep(time.Second * 1)
	}
	return errors.New("Timeout reached")
}

func (qemu QemuVM) Start() error {
	var target string
	var err error

	//fmt.Println("!QemuStart ", strconv.FormatFloat(qemu.VMId, 'f', 0, 64))

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/status/start"
	_, err = qemu.Node.Proxmox.Post(target, "")
	return err
}

func (qemu QemuVM) Stop() error {
	var target string
	var err error

	//fmt.Print("!QemuStop ", qemu.VMId)

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/status/stop"
	_, err = qemu.Node.Proxmox.Post(target, "")
	return err
}

func (qemu QemuVM) Shutdown() (Task, error) {
	var target string
	var err error

	//fmt.Print("!QemuShutdown ", qemu.VMId)

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/status/shutdown"
	data, err := qemu.Node.Proxmox.Post(target, "")

	if err != err {
		return Task{}, err
	}

	t := Task{
		UPid:    data["data"].(string),
		proxmox: qemu.Node.Proxmox,
	}

	return t, err
}

func (qemu QemuVM) Suspend() error {
	var target string
	var err error

	//fmt.Print("!QemuSuspend ", qemu.VMId)

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/status/suspend"
	_, err = qemu.Node.Proxmox.Post(target, "")
	return err
}

func (qemu QemuVM) Resume() error {
	var target string
	var err error

	//fmt.Print("!QemuResume ", qemu.VMId)

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/status/resume"
	_, err = qemu.Node.Proxmox.Post(target, "")
	return err
}

func (qemu QemuVM) Clone(newId float64, name string, targetName string) (Task, error) {
	var target string
	var err error

	newVMID := strconv.FormatFloat(newId, 'f', 0, 64)

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/clone"

	form := url.Values{
		"newid":  {newVMID},
		"name":   {name},
		"target": {targetName},
		"full":   {"1"},
	}

	data, err := qemu.Node.Proxmox.PostForm(target, form)
	if err != err {
		return Task{}, err
	}

	t := Task{
		UPid:    data["data"].(string),
		proxmox: qemu.Node.Proxmox,
	}

	return t, nil
}

func (qemu QemuVM) SetDescription(description string) (error) {
	var target string
	var err error

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/config"

	form := url.Values{
		"description":  {description},
	}

	data, err := qemu.Node.Proxmox.PutForm(target, form)
	if err != err {
		return err
	}

	return nil
}

func (qemu QemuVM) SetIPSet(ip string) error {
	var target string
	var err error

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/firewall/options"

	form := url.Values{
		"dhcp":          {"1"},
		"enable":        {"1"},
		"log_level_in":  {"nolog"},
		"log_level_out": {"nolog"},
		"macfilter":     {"1"},
		"ipfilter":      {"1"},
		"ndp":           {"1"},
		"policy_in":     {"ACCEPT"},
		"policy_out":    {"ACCEPT"},
	}

	_, err = qemu.Node.Proxmox.PutForm(target, form)
	if err != nil {
		return err
	}

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/firewall/ipset"

	form = url.Values{
		"name": {"ipfilter-net0"},
	}

	_, err = qemu.Node.Proxmox.PostForm(target, form)
	if err != nil {
		return err
	}

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/firewall/ipset/ipfilter-net0"

	form = url.Values{
		"cidr": {ip},
	}

	_, err = qemu.Node.Proxmox.PostForm(target, form)
	if err != nil {
		return err
	}

	config, err := qemu.Config()
	if err != nil {
		return err
	}

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/config"

	net := ""

	for k, v := range config.Net["net0"] {
		net += k + "=" + v + ","
	}

	form = url.Values{
		"net0": {net + ",firewall=1"},
	}

	_, err = qemu.Node.Proxmox.PutForm(target, form)
	if err != nil {
		return err
	}

	return nil
}

func (qemu QemuVM) ResizeDisk(size string) error {
	var target string
	var err error

	target = "nodes/" + qemu.Node.Node + "/qemu/" + strconv.FormatFloat(qemu.VMId, 'f', 0, 64) + "/resize"

	form := url.Values{
		"disk": {"scsi1"},
		"size": {size + "G"},
	}

	_, err = qemu.Node.Proxmox.PutForm(target, form)
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before><commit_msg>implement Priority's Evaluation<commit_after><|endoftext|>


<commit_before>package indextest

import (
<<<<<<< HEAD
	"fmt"
=======
>>>>>>> klient/machine: move index test helpers to reusable test package
	"io"
	"io/ioutil"
	"math/rand"
	"os"
	"path/filepath"
	"time"
<<<<<<< HEAD

	"koding/klient/machine/index"

	"github.com/djherbis/times"
)

// Compare is a helper function that compares the content of two provided
// directories. The detected changes will be returned as index change slice.
// First argument is treated as base index data.
func Compare(rootA, rootB string) (cs index.ChangeSlice, err error) {
	idx, err := index.NewIndexFiles(rootA)
	if err != nil {
		return nil, err
	}

	// Merge ony adds files so it will make remote add instead of local delete
	// we need to fix this.
	mra := index.ChangeMetaAdd | index.ChangeMetaRemote
	for _, c := range idx.Merge(rootB) {
		if c.Meta()&mra == mra {
			c = index.NewChange(c.Path(), index.ChangeMetaRemove)
		}
		cs = append(cs, c)
	}

	return cs, nil
}

// GenerateMirrorTrees generates two identical file trees using GenerateTree
// helper function. This function ensures that ComparePath of two generated
// directories will not produce any index changes.
func GenerateMirrorTrees(filetree map[string]int64) (string, string, func(), error) {
	rootA, cleanA, err := GenerateTree(filetree)
	if err != nil {
		return "", "", nil, err
	}

	rootB, cleanB, err := GenerateTree(filetree)
	if err != nil {
		cleanA()
		return "", "", nil, err
	}

	clean := func() {
		cleanB()
		cleanA()
	}

	for path := range filetree {
		if err := makeSimilarTimes(rootA, rootB, path); err != nil {
			clean()
			return "", "", nil, err
		}
	}

	cs, err := Compare(rootA, rootB)
	if len(cs) != 0 {
		err = fmt.Errorf("generated paths are not identical: %v", cs)
	}

	if err != nil {
		clean()
		return "", "", nil, err
	}

	return rootA, rootB, clean, nil
}

func makeSimilarTimes(rootA, rootB, path string) error {
	t, err := times.Stat(filepath.Join(rootA, path))
	if err != nil {
		return err
	}

	if err := os.Chtimes(filepath.Join(rootB, path), t.AccessTime(), t.ModTime()); err != nil {
		return err
	}

	// Changing mtime also modifies ctime. Files stored inside rootA may have
	// different mtime and ctime values so it's needed to Chtimes them as well.
	return os.Chtimes(filepath.Join(rootA, path), t.AccessTime(), t.ModTime())
}

=======
)

>>>>>>> klient/machine: move index test helpers to reusable test package
// GenerateTree generates a file tree inside a temporary directory. The filetree
// map has relative paths as keys and file size as value. Clean function must
// be called in order to clean up resources.
func GenerateTree(filetree map[string]int64) (root string, clean func(), err error) {
	root, err = ioutil.TempDir("", "mount.index")
	if err != nil {
		return "", nil, err
	}
	clean = func() { os.RemoveAll(root) }

	for file, size := range filetree {
		if err := AddDir(file)(root); err != nil {
			clean()
			return "", nil, err
		}
		if err := WriteFile(file, size)(root); err != nil {
			clean()
			return "", nil, err
		}
	}

	return root, clean, nil
}

// AddDir creates a functor which, when invoked on provided root, will create
// new directory specified by file argument.
func AddDir(file string) func(string) error {
	return func(root string) error {
		defer Sync()

		dir := filepath.Join(root, filepath.FromSlash(file))
		if filepath.Ext(dir) != "" {
			dir = filepath.Dir(dir)
		}

		return os.MkdirAll(dir, 0777)
	}
}

// WriteFile creates a functor which, when invoked on provided root, will create
// a new file specified by file and size arguments. The content of the file will
// be randomized.
func WriteFile(file string, size int64) func(string) error {
	return func(root string) error {
		defer Sync()

		if filepath.Ext(file) == "" {
			return nil
		}

		lr := io.LimitReader(rand.New(rand.NewSource(time.Now().UnixNano())), size)
		content, err := ioutil.ReadAll(lr)
		if err != nil {
			return err
		}

		file := filepath.Join(root, filepath.FromSlash(file))
		return ioutil.WriteFile(file, content, 0666)
	}
}

// RmAllFile creates a functor which, when invoked on provided root, will
// remove all files inside in directory specified by file argument. If the
// argument describes regural file it will be removed.
func RmAllFile(file string) func(string) error {
	return func(root string) error {
		defer Sync()

		return os.RemoveAll(filepath.Join(root, filepath.FromSlash(file)))
	}
}

// MvFile creates a functor which, when invoked on provided root, will move
// oldpath file to newpath file.
func MvFile(oldpath, newpath string) func(string) error {
	return func(root string) error {
		defer Sync()

		var (
			oldpath = filepath.Join(root, filepath.FromSlash(oldpath))
			newpath = filepath.Join(root, filepath.FromSlash(newpath))
		)

		return os.Rename(oldpath, newpath)
	}
}

// ChmodFile creates a functor which, when invoked on provided root, will change
// mode bits of the file specified by file argument.
func ChmodFile(file string, mode os.FileMode) func(string) error {
	return func(root string) error {
		defer Sync()

		return os.Chmod(filepath.Join(root, filepath.FromSlash(file)), mode)
	}
}
<commit_msg>klient/machine: add index compare and generate test helpers<commit_after>package indextest

import (
	"fmt"
	"io"
	"io/ioutil"
	"math/rand"
	"os"
	"path/filepath"
	"time"

	"koding/klient/machine/index"

	"github.com/djherbis/times"
)

// Compare is a helper function that compares the content of two provided
// directories. The detected changes will be returned as index change slice.
// First argument is treated as base index data.
func Compare(rootA, rootB string) (cs index.ChangeSlice, err error) {
	idx, err := index.NewIndexFiles(rootA)
	if err != nil {
		return nil, err
	}

	// Merge ony adds files so it will make remote add instead of local delete
	// we need to fix this.
	mra := index.ChangeMetaAdd | index.ChangeMetaRemote
	for _, c := range idx.Merge(rootB) {
		if c.Meta()&mra == mra {
			c = index.NewChange(c.Path(), index.ChangeMetaRemove)
		}
		cs = append(cs, c)
	}

	return cs, nil
}

// GenerateMirrorTrees generates two identical file trees using GenerateTree
// helper function. This function ensures that ComparePath of two generated
// directories will not produce any index changes.
func GenerateMirrorTrees(filetree map[string]int64) (string, string, func(), error) {
	rootA, cleanA, err := GenerateTree(filetree)
	if err != nil {
		return "", "", nil, err
	}

	rootB, cleanB, err := GenerateTree(filetree)
	if err != nil {
		cleanA()
		return "", "", nil, err
	}

	clean := func() {
		cleanB()
		cleanA()
	}

	for path := range filetree {
		if err := makeSimilarTimes(rootA, rootB, path); err != nil {
			clean()
			return "", "", nil, err
		}
	}

	cs, err := Compare(rootA, rootB)
	if len(cs) != 0 {
		err = fmt.Errorf("generated paths are not identical: %v", cs)
	}

	if err != nil {
		clean()
		return "", "", nil, err
	}

	return rootA, rootB, clean, nil
}

func makeSimilarTimes(rootA, rootB, path string) error {
	t, err := times.Stat(filepath.Join(rootA, path))
	if err != nil {
		return err
	}

	if err := os.Chtimes(filepath.Join(rootB, path), t.AccessTime(), t.ModTime()); err != nil {
		return err
	}

	// Changing mtime also modifies ctime. Files stored inside rootA may have
	// different mtime and ctime values so it's needed to Chtimes them as well.
	return os.Chtimes(filepath.Join(rootA, path), t.AccessTime(), t.ModTime())
}

// GenerateTree generates a file tree inside a temporary directory. The filetree
// map has relative paths as keys and file size as value. Clean function must
// be called in order to clean up resources.
func GenerateTree(filetree map[string]int64) (root string, clean func(), err error) {
	root, err = ioutil.TempDir("", "mount.index")
	if err != nil {
		return "", nil, err
	}
	clean = func() { os.RemoveAll(root) }

	for file, size := range filetree {
		if err := AddDir(file)(root); err != nil {
			clean()
			return "", nil, err
		}
		if err := WriteFile(file, size)(root); err != nil {
			clean()
			return "", nil, err
		}
	}

	return root, clean, nil
}

// AddDir creates a functor which, when invoked on provided root, will create
// new directory specified by file argument.
func AddDir(file string) func(string) error {
	return func(root string) error {
		defer Sync()

		dir := filepath.Join(root, filepath.FromSlash(file))
		if filepath.Ext(dir) != "" {
			dir = filepath.Dir(dir)
		}

		return os.MkdirAll(dir, 0777)
	}
}

// WriteFile creates a functor which, when invoked on provided root, will create
// a new file specified by file and size arguments. The content of the file will
// be randomized.
func WriteFile(file string, size int64) func(string) error {
	return func(root string) error {
		defer Sync()

		if filepath.Ext(file) == "" {
			return nil
		}

		lr := io.LimitReader(rand.New(rand.NewSource(time.Now().UnixNano())), size)
		content, err := ioutil.ReadAll(lr)
		if err != nil {
			return err
		}

		file := filepath.Join(root, filepath.FromSlash(file))
		return ioutil.WriteFile(file, content, 0666)
	}
}

// RmAllFile creates a functor which, when invoked on provided root, will
// remove all files inside in directory specified by file argument. If the
// argument describes regural file it will be removed.
func RmAllFile(file string) func(string) error {
	return func(root string) error {
		defer Sync()

		return os.RemoveAll(filepath.Join(root, filepath.FromSlash(file)))
	}
}

// MvFile creates a functor which, when invoked on provided root, will move
// oldpath file to newpath file.
func MvFile(oldpath, newpath string) func(string) error {
	return func(root string) error {
		defer Sync()

		var (
			oldpath = filepath.Join(root, filepath.FromSlash(oldpath))
			newpath = filepath.Join(root, filepath.FromSlash(newpath))
		)

		return os.Rename(oldpath, newpath)
	}
}

// ChmodFile creates a functor which, when invoked on provided root, will change
// mode bits of the file specified by file argument.
func ChmodFile(file string, mode os.FileMode) func(string) error {
	return func(root string) error {
		defer Sync()

		return os.Chmod(filepath.Join(root, filepath.FromSlash(file)), mode)
	}
}
<|endoftext|>


<commit_before>// Package sender provides an API for mail sending operations
package emailsender

import (
	"fmt"
	"socialapi/config"
	"text/template"

	"github.com/koding/bongo"
	"github.com/koding/eventexporter"
	"github.com/koding/logging"
	"github.com/streadway/amqp"
)

var SendEmailEventName = "send"

// Controller holds required instances for processing events
type Controller struct {
	log                     logging.Logger
	emailer                 eventexporter.Exporter
	forcedRecipientUsername string
	forcedRecipientEmail    string
	env                     string
	host                    string
}

// New Creates a new controller for mail worker
// func New(exporter eventexporter.Exporter, log logging.Logger, conf runner.Config) *Controller {
func New(exporter eventexporter.Exporter, log logging.Logger, conf *config.Config) *Controller {
	return &Controller{
		emailer:                 exporter,
		log:                     log,
		env:                     conf.Environment,
		host:                    conf.Hostname,
		forcedRecipientEmail:    conf.Email.ForcedRecipientEmail,
		forcedRecipientUsername: conf.Email.ForcedRecipientUsername,
	}
}

// Send gets the mail struct that includes the message
// when we call this function, it sends the given mail to the
// address that will be sent.
func Send(m *Mail) error {
	return bongo.B.PublishEvent(SendEmailEventName, m)
}

// Process creates and sets the message that will be sent,
// and sends the message according to the mail adress
// its a helper method to send message
func (c *Controller) Process(m *Mail) error {
	var to = m.To

	if c.forcedRecipientEmail != "" {
		to = c.forcedRecipientEmail
	}

	user := &eventexporter.User{Email: to}
	if m.Properties == nil {
		m.Properties = NewProperties()
	}

	user.Username = m.Properties.Username
	if c.forcedRecipientUsername != "" {
		user.Username = c.forcedRecipientUsername
	}

	m.SetOption("subject", m.Subject)

	// set default properties
	m.SetOption("env", c.env)
	m.SetOption("host", c.host)

	escapedBody := template.HTMLEscapeString(m.HTML)
	event := &eventexporter.Event{
		Name:       m.Subject,
		User:       user,
		Body:       &eventexporter.Body{Content: escapedBody},
		Properties: m.Properties.Options,
	}

	fmt.Println("FORCEDRECIPIENTFORCEDRECIPIENT:", c.forcedRecipientEmail)
	fmt.Println("FORCEDRECIPIENTFORCEDRECIPIENT:", c.forcedRecipientUsername)
	fmt.Println("FORCEDRECIPIENTFORCEDRECIPIENTtototototo:", to)
	return nil
	return c.emailer.Send(event)
}

func (c *Controller) Close() {
	if err := c.emailer.Close(); err != nil {
		c.log.Error("Could not close emailer successfully: %s", err)
	}
}

// DefaultErrHandler controls the errors, return false if an error occurred
func (c *Controller) DefaultErrHandler(delivery amqp.Delivery, err error) bool {
	if delivery.Redelivered {
		c.log.Error("Redelivered message gave error again, putting to maintenance queue", err)
		delivery.Ack(false)

		return true
	}

	c.log.Error("an error occurred while sending email error as %+v ", err.Error())
	delivery.Nack(false, true)

	return false
}

func isForceRecipient(email string) bool {
	return email != ""
}
<commit_msg>socialapi: remove 'fmt' lines<commit_after>// Package sender provides an API for mail sending operations
package emailsender

import (
	"socialapi/config"
	"text/template"

	"github.com/koding/bongo"
	"github.com/koding/eventexporter"
	"github.com/koding/logging"
	"github.com/streadway/amqp"
)

var SendEmailEventName = "send"

// Controller holds required instances for processing events
type Controller struct {
	log                     logging.Logger
	emailer                 eventexporter.Exporter
	forcedRecipientUsername string
	forcedRecipientEmail    string
	env                     string
	host                    string
}

// New Creates a new controller for mail worker
// func New(exporter eventexporter.Exporter, log logging.Logger, conf runner.Config) *Controller {
func New(exporter eventexporter.Exporter, log logging.Logger, conf *config.Config) *Controller {
	return &Controller{
		emailer:                 exporter,
		log:                     log,
		env:                     conf.Environment,
		host:                    conf.Hostname,
		forcedRecipientEmail:    conf.Email.ForcedRecipientEmail,
		forcedRecipientUsername: conf.Email.ForcedRecipientUsername,
	}
}

// Send gets the mail struct that includes the message
// when we call this function, it sends the given mail to the
// address that will be sent.
func Send(m *Mail) error {
	return bongo.B.PublishEvent(SendEmailEventName, m)
}

// Process creates and sets the message that will be sent,
// and sends the message according to the mail adress
// its a helper method to send message
func (c *Controller) Process(m *Mail) error {
	var to = m.To

	if c.forcedRecipientEmail != "" {
		to = c.forcedRecipientEmail
	}

	user := &eventexporter.User{Email: to}
	if m.Properties == nil {
		m.Properties = NewProperties()
	}

	user.Username = m.Properties.Username
	if c.forcedRecipientUsername != "" {
		user.Username = c.forcedRecipientUsername
	}

	m.SetOption("subject", m.Subject)

	// set default properties
	m.SetOption("env", c.env)
	m.SetOption("host", c.host)

	escapedBody := template.HTMLEscapeString(m.HTML)
	event := &eventexporter.Event{
		Name:       m.Subject,
		User:       user,
		Body:       &eventexporter.Body{Content: escapedBody},
		Properties: m.Properties.Options,
	}

	return c.emailer.Send(event)
}

func (c *Controller) Close() {
	if err := c.emailer.Close(); err != nil {
		c.log.Error("Could not close emailer successfully: %s", err)
	}
}

// DefaultErrHandler controls the errors, return false if an error occurred
func (c *Controller) DefaultErrHandler(delivery amqp.Delivery, err error) bool {
	if delivery.Redelivered {
		c.log.Error("Redelivered message gave error again, putting to maintenance queue", err)
		delivery.Ack(false)

		return true
	}

	c.log.Error("an error occurred while sending email error as %+v ", err.Error())
	delivery.Nack(false, true)

	return false
}

func isForceRecipient(email string) bool {
	return email != ""
}
<|endoftext|>