<commit_before>package sudoku

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

//The actual techniques are intialized in hs_techniques.go, and actually defined in hst_*.go files.
//Techniques is ALL technies. CheapTechniques is techniques that are reasonably cheap to compute.
//ExpensiveTechniques is techniques that should only be used if all else has failed.
var Techniques []SolveTechnique
var CheapTechniques []SolveTechnique
var ExpensiveTechniques []SolveTechnique

var GuessTechnique SolveTechnique

//EVERY technique, even the weird one like Guess
var AllTechniques []SolveTechnique

//Worst case scenario, how many times we'd call HumanSolve to get a difficulty.
const MAX_DIFFICULTY_ITERATIONS = 50

//This number is the 'Constant' term from the multiple linear regression to learn the weights.
var difficultyConstant float64

//How close we have to get to the average to feel comfortable our difficulty is converging.
const DIFFICULTY_CONVERGENCE = 0.0005

type SolveDirections []*SolveStep

type SolveStep struct {
	//The cells that will be affected by the techinque
	TargetCells CellList
	//The cells that together lead the techinque to being valid
	PointerCells CellList
	//The numbers we will remove (or, in the case of Fill, add)
	//TODO: shouldn't this be renamed TargetNums?
	TargetNums IntSlice
	//The numbers in pointerCells that lead us to remove TargetNums from TargetCells.
	//This is only very rarely needed (at this time only for hiddenSubset techniques)
	PointerNums IntSlice
	//The general technique that underlies this step.
	Technique SolveTechnique
}

func (self *SolveStep) IsUseful(grid *Grid) bool {
	//Returns true IFF calling Apply with this step and the given grid would result in some useful work. Does not modify the gri.d

	//All of this logic is substantially recreated in Apply.

	if self.Technique == nil {
		return false
	}

	//TODO: test this.
	if self.Technique.IsFill() {
		if len(self.TargetCells) == 0 || len(self.TargetNums) == 0 {
			return false
		}
		cell := self.TargetCells[0].InGrid(grid)
		return self.TargetNums[0] != cell.Number()
	} else {
		useful := false
		for _, cell := range self.TargetCells {
			gridCell := cell.InGrid(grid)
			for _, exclude := range self.TargetNums {
				//It's right to use Possible because it includes the logic of "it's not possible if there's a number in there already"
				//TODO: ensure the comment above is correct logically.
				if gridCell.Possible(exclude) {
					useful = true
				}
			}
		}
		return useful
	}
}

func (self *SolveStep) Apply(grid *Grid) {
	//All of this logic is substantially recreated in IsUseful.
	if self.Technique.IsFill() {
		if len(self.TargetCells) == 0 || len(self.TargetNums) == 0 {
			return
		}
		cell := self.TargetCells[0].InGrid(grid)
		cell.SetNumber(self.TargetNums[0])
	} else {
		for _, cell := range self.TargetCells {
			gridCell := cell.InGrid(grid)
			for _, exclude := range self.TargetNums {
				gridCell.setExcluded(exclude, true)
			}
		}
	}
}

func (self *SolveStep) Description() string {
	result := ""
	if self.Technique.IsFill() {
		result += fmt.Sprintf("We put %s in cell %s ", self.TargetNums.Description(), self.TargetCells.Description())
	} else {
		//TODO: pluralize based on length of lists.
		result += fmt.Sprintf("We remove the possibilities %s from cells %s ", self.TargetNums.Description(), self.TargetCells.Description())
	}
	result += "because " + self.Technique.Description(self) + "."
	return result
}

func (self *SolveStep) normalize() {
	//Puts the solve step in its normal status. In practice this means that the various slices are sorted, so that the Description of them is stable.
	self.PointerCells.Sort()
	self.TargetCells.Sort()
	self.TargetNums.Sort()
	self.PointerNums.Sort()
}

func (self SolveDirections) Stats() []string {
	//TODO: test this.
	techniqueCount := make(map[string]int)
	for _, step := range self {
		techniqueCount[step.Technique.Name()] += 1
	}
	var result []string

	//TODO: use a standard divider across the codebase
	divider := "-------------------------"

	result = append(result, divider)
	result = append(result, fmt.Sprintf("Difficulty : %f", self.Difficulty()))
	result = append(result, divider)
	result = append(result, fmt.Sprintf("Step count: %d", len(self)))
	result = append(result, divider)

	//We want a stable ordering for technique counts.
	for _, technique := range AllTechniques {
		result = append(result, fmt.Sprintf("%s : %d", technique.Name(), techniqueCount[technique.Name()]))
	}

	result = append(result, divider)

	return result
}

func (self SolveDirections) Description() []string {

	if len(self) == 0 {
		return []string{""}
	}

	descriptions := make([]string, len(self))

	for i, step := range self {
		intro := ""
		switch i {
		case 0:
			intro = "First, "
		case len(self) - 1:
			intro = "Finally, "
		default:
			//TODO: switch between "then" and "next" randomly.
			intro = "Next, "
		}
		descriptions[i] = intro + strings.ToLower(step.Description())

	}
	return descriptions
}

func (self SolveDirections) Difficulty() float64 {
	//How difficult the solve directions described are. The measure of difficulty we use is
	//just summing up weights we see; this captures:
	//* Number of steps
	//* Average difficulty of steps
	//* Number of hard steps
	//* (kind of) the hardest step: because the difficulties go up expontentionally.

	//This method assumes the weights have been calibrated empirically to give scores between 0.0 and 1.0
	//without normalization here.

	if len(self) == 0 {
		//The puzzle was not able to be solved, apparently.
		return 1.0
	}

	accum := difficultyConstant
	for _, step := range self {
		accum += step.Technique.Difficulty()
	}

	if accum < 0.0 {
		log.Println("Accumuldated difficulty snapped to 0.0:", accum)
		accum = 0.0
	}

	if accum > 1.0 {
		log.Println("Accumulated difficulty snapped to 1.0:", accum)
		accum = 1.0
	}

	return accum
}

func (self SolveDirections) Walkthrough(grid *Grid) string {

	//TODO: test this.

	clone := grid.Copy()
	defer clone.Done()

	DIVIDER := "\n\n--------------------------------------------\n\n"

	intro := fmt.Sprintf("This will take %d steps to solve.", len(self))

	intro += "\nWhen you start, your grid looks like this:\n"

	intro += clone.Diagram()

	intro += "\n"

	intro += DIVIDER

	descriptions := self.Description()

	results := make([]string, len(self))

	for i, description := range descriptions {

		result := description + "\n"
		result += "After doing that, your grid will look like: \n\n"

		self[i].Apply(clone)

		result += clone.Diagram()

		results[i] = result
	}

	return intro + strings.Join(results, DIVIDER) + DIVIDER + "Now the puzzle is solved."
}

func (self *Grid) HumanWalkthrough() string {
	steps := self.HumanSolution()
	return steps.Walkthrough(self)
}

func (self *Grid) HumanSolution() SolveDirections {
	clone := self.Copy()
	defer clone.Done()
	return clone.HumanSolve()
}

func (self *Grid) HumanSolve() SolveDirections {

	var results []*SolveStep

	//TODO: this supports just a single branch point, but in theory we should be able to branch an arbitrary number of times if necessary.
	//The point at which we branched for a guess. non-nil if we are in a branch.
	var branchPoint *Grid

	//The step we'll apply to get us into the branch point.
	var branchPointStep *SolveStep

	//Ther other numbers to try from the branch point.
	var otherNums IntSlice

	//The steps we've taken since the branch point.
	var branchSteps []*SolveStep

	//Note: trying these all in parallel is much slower (~15x) than doing them in sequence.
	//The reason is that in sequence we bailed early as soon as we found one step; now we try them all.

	for !self.Solved() {

		var possibilities []*SolveStep

		if branchPoint != nil && self.Invalid() {
			//We're in a branch, and got to a point where we found an invalidity.
			//We chose the wrong branch. We should unwind to the branch point and go down the other branch.

			//Unwind ourselves
			self.Load(branchPoint.DataString())

			//Throwout the steps down the wrong branch we took.
			branchSteps = nil

			if len(otherNums) > 0 {

				//Pop off the nextNum to do
				nextNum := otherNums[0]
				otherNums = otherNums[1:]

				//Stuff it into the TargetNums for the branch step.
				branchPointStep.TargetNums = IntSlice{nextNum}

				//Stuff the possibility list with the mangled branchPointStep.
				possibilities = []*SolveStep{branchPointStep}
			} else {
				//Well, crap. We're out of luck, nothing more for us to do.
				//TODO: pick a different guess operation at this grid state.
			}

		} else {

			//Normal operation; get potential solve steps by running them all.
			possibilities = runTechniques(CheapTechniques, self)
		}

		//TODO: provide hints to the techniques of where to look based on the last filled cell

		//Now pick one to apply.
		if len(possibilities) == 0 {
			//Okay, let's try the ExpensiveTechniques, as a hail mary.
			possibilities = runTechniques(ExpensiveTechniques, self)
			if len(possibilities) == 0 {
				//Hmm, didn't find any possivbilities. We're getting to be out of options...

				if branchPoint == nil {
					//Try to guess as a hail mary
					possibilities = runTechniques([]SolveTechnique{GuessTechnique}, self)

					if len(possibilities) == 0 {
						//Okay, we're well and truly done--not even any guesses came up with something. Nothing we can do.
						break
					} else {
						//Yay, found something! remember the branch point, so we can jump back to it.

						//We're just going to choose the first one.
						possibilities = possibilities[0:1]

						//TODO: this doesn't hold our special excludes, which we might have worked quite a bit to set up.
						//Ideally we'd have a way to keep those overrides.
						//The worst case is that we have a few unnecessary Cull steps just before the branch point.
						branchPoint = self.Copy()
						branchPointStep = possibilities[0]
						otherNums = branchPointStep.PointerNums

						//Null out the branchPointStep's pointerNums; their only point was to communicate out the other possibilities.
						//And from now on they'll just be confusing.
						branchPointStep.PointerNums = nil
					}
				} else {
					//looks like we got to a point where we're in a branch and would really like to branch again.
					//We can't handle that now, so just bail out in the worst possible way.
					//TODO: handle multiple nested branch points better
					panic("Human solve ran into a case where a double branch point would have been useful.")
				}
				break
			}
		}

		//TODO: consider if we should stop picking techniques based on their weight here.
		//Now that Find returns a slice instead of a single, we're already much more likely to select an "easy" technique. ... Right?

		possibilitiesWeights := make([]float64, len(possibilities))
		for i, possibility := range possibilities {
			possibilitiesWeights[i] = possibility.Technique.Difficulty()
		}
		step := possibilities[randomIndexWithInvertedWeights(possibilitiesWeights)]

		if branchPoint == nil {
			results = append(results, step)
		} else {
			//We're in a branch point; we don't know if it's the RIGHT branch
			//So keep the steps somewhere else so we can throw them out if we unwind.
			branchSteps = append(branchSteps, step)
		}
		step.Apply(self)

	}
	if !self.Solved() {
		//We couldn't solve the puzzle.
		return nil
	}

	if len(branchSteps) > 0 {
		//Apparently we're in the branch where the solution acutally lay. commit those steps and return them.
		results = append(results, branchSteps...)
	}

	return results
}

func runTechniques(techniques []SolveTechnique, grid *Grid) []*SolveStep {
	numTechniques := len(techniques)
	possibilitiesChan := make(chan []*SolveStep)

	var possibilities []*SolveStep

	for _, technique := range techniques {
		go func(theTechnique SolveTechnique) {
			possibilitiesChan <- theTechnique.Find(grid)
		}(technique)
	}

	//Collect all of the results
	for i := 0; i < numTechniques; i++ {
		for _, possibility := range <-possibilitiesChan {
			possibilities = append(possibilities, possibility)
		}
	}

	return possibilities
}

func (self *Grid) Difficulty() float64 {
	//This can be an extremely expensive method. Do not call repeatedly!
	//returns the difficulty of the grid, which is a number between 0.0 and 1.0.
	//This is a probabilistic measure; repeated calls may return different numbers, although generally we wait for the results to converge.

	//We solve the same puzzle N times, then ask each set of steps for their difficulty, and combine those to come up with the overall difficulty.

	accum := 0.0
	average := 0.0
	lastAverage := 0.0

	for i := 0; i < MAX_DIFFICULTY_ITERATIONS; i++ {
		grid := self.Copy()
		steps := grid.HumanSolve()
		difficulty := steps.Difficulty()

		accum += difficulty
		average = accum / (float64(i) + 1.0)

		if math.Abs(average-lastAverage) < DIFFICULTY_CONVERGENCE {
			//Okay, we've already converged. Just return early!
			return average
		}

		lastAverage = average
	}

	//We weren't converging... oh well!
	return average

}
<commit_msg>TESTS FAIL. Introduced a crasher. Removed an errant break statement in human solve that was leading to guess not finding things.<commit_after>package sudoku

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

//The actual techniques are intialized in hs_techniques.go, and actually defined in hst_*.go files.
//Techniques is ALL technies. CheapTechniques is techniques that are reasonably cheap to compute.
//ExpensiveTechniques is techniques that should only be used if all else has failed.
var Techniques []SolveTechnique
var CheapTechniques []SolveTechnique
var ExpensiveTechniques []SolveTechnique

var GuessTechnique SolveTechnique

//EVERY technique, even the weird one like Guess
var AllTechniques []SolveTechnique

//Worst case scenario, how many times we'd call HumanSolve to get a difficulty.
const MAX_DIFFICULTY_ITERATIONS = 50

//This number is the 'Constant' term from the multiple linear regression to learn the weights.
var difficultyConstant float64

//How close we have to get to the average to feel comfortable our difficulty is converging.
const DIFFICULTY_CONVERGENCE = 0.0005

type SolveDirections []*SolveStep

type SolveStep struct {
	//The cells that will be affected by the techinque
	TargetCells CellList
	//The cells that together lead the techinque to being valid
	PointerCells CellList
	//The numbers we will remove (or, in the case of Fill, add)
	//TODO: shouldn't this be renamed TargetNums?
	TargetNums IntSlice
	//The numbers in pointerCells that lead us to remove TargetNums from TargetCells.
	//This is only very rarely needed (at this time only for hiddenSubset techniques)
	PointerNums IntSlice
	//The general technique that underlies this step.
	Technique SolveTechnique
}

func (self *SolveStep) IsUseful(grid *Grid) bool {
	//Returns true IFF calling Apply with this step and the given grid would result in some useful work. Does not modify the gri.d

	//All of this logic is substantially recreated in Apply.

	if self.Technique == nil {
		return false
	}

	//TODO: test this.
	if self.Technique.IsFill() {
		if len(self.TargetCells) == 0 || len(self.TargetNums) == 0 {
			return false
		}
		cell := self.TargetCells[0].InGrid(grid)
		return self.TargetNums[0] != cell.Number()
	} else {
		useful := false
		for _, cell := range self.TargetCells {
			gridCell := cell.InGrid(grid)
			for _, exclude := range self.TargetNums {
				//It's right to use Possible because it includes the logic of "it's not possible if there's a number in there already"
				//TODO: ensure the comment above is correct logically.
				if gridCell.Possible(exclude) {
					useful = true
				}
			}
		}
		return useful
	}
}

func (self *SolveStep) Apply(grid *Grid) {
	//All of this logic is substantially recreated in IsUseful.
	if self.Technique.IsFill() {
		if len(self.TargetCells) == 0 || len(self.TargetNums) == 0 {
			return
		}
		cell := self.TargetCells[0].InGrid(grid)
		cell.SetNumber(self.TargetNums[0])
	} else {
		for _, cell := range self.TargetCells {
			gridCell := cell.InGrid(grid)
			for _, exclude := range self.TargetNums {
				gridCell.setExcluded(exclude, true)
			}
		}
	}
}

func (self *SolveStep) Description() string {
	result := ""
	if self.Technique.IsFill() {
		result += fmt.Sprintf("We put %s in cell %s ", self.TargetNums.Description(), self.TargetCells.Description())
	} else {
		//TODO: pluralize based on length of lists.
		result += fmt.Sprintf("We remove the possibilities %s from cells %s ", self.TargetNums.Description(), self.TargetCells.Description())
	}
	result += "because " + self.Technique.Description(self) + "."
	return result
}

func (self *SolveStep) normalize() {
	//Puts the solve step in its normal status. In practice this means that the various slices are sorted, so that the Description of them is stable.
	self.PointerCells.Sort()
	self.TargetCells.Sort()
	self.TargetNums.Sort()
	self.PointerNums.Sort()
}

func (self SolveDirections) Stats() []string {
	//TODO: test this.
	techniqueCount := make(map[string]int)
	for _, step := range self {
		techniqueCount[step.Technique.Name()] += 1
	}
	var result []string

	//TODO: use a standard divider across the codebase
	divider := "-------------------------"

	result = append(result, divider)
	result = append(result, fmt.Sprintf("Difficulty : %f", self.Difficulty()))
	result = append(result, divider)
	result = append(result, fmt.Sprintf("Step count: %d", len(self)))
	result = append(result, divider)

	//We want a stable ordering for technique counts.
	for _, technique := range AllTechniques {
		result = append(result, fmt.Sprintf("%s : %d", technique.Name(), techniqueCount[technique.Name()]))
	}

	result = append(result, divider)

	return result
}

func (self SolveDirections) Description() []string {

	if len(self) == 0 {
		return []string{""}
	}

	descriptions := make([]string, len(self))

	for i, step := range self {
		intro := ""
		switch i {
		case 0:
			intro = "First, "
		case len(self) - 1:
			intro = "Finally, "
		default:
			//TODO: switch between "then" and "next" randomly.
			intro = "Next, "
		}
		descriptions[i] = intro + strings.ToLower(step.Description())

	}
	return descriptions
}

func (self SolveDirections) Difficulty() float64 {
	//How difficult the solve directions described are. The measure of difficulty we use is
	//just summing up weights we see; this captures:
	//* Number of steps
	//* Average difficulty of steps
	//* Number of hard steps
	//* (kind of) the hardest step: because the difficulties go up expontentionally.

	//This method assumes the weights have been calibrated empirically to give scores between 0.0 and 1.0
	//without normalization here.

	if len(self) == 0 {
		//The puzzle was not able to be solved, apparently.
		return 1.0
	}

	accum := difficultyConstant
	for _, step := range self {
		accum += step.Technique.Difficulty()
	}

	if accum < 0.0 {
		log.Println("Accumuldated difficulty snapped to 0.0:", accum)
		accum = 0.0
	}

	if accum > 1.0 {
		log.Println("Accumulated difficulty snapped to 1.0:", accum)
		accum = 1.0
	}

	return accum
}

func (self SolveDirections) Walkthrough(grid *Grid) string {

	//TODO: test this.

	clone := grid.Copy()
	defer clone.Done()

	DIVIDER := "\n\n--------------------------------------------\n\n"

	intro := fmt.Sprintf("This will take %d steps to solve.", len(self))

	intro += "\nWhen you start, your grid looks like this:\n"

	intro += clone.Diagram()

	intro += "\n"

	intro += DIVIDER

	descriptions := self.Description()

	results := make([]string, len(self))

	for i, description := range descriptions {

		result := description + "\n"
		result += "After doing that, your grid will look like: \n\n"

		self[i].Apply(clone)

		result += clone.Diagram()

		results[i] = result
	}

	return intro + strings.Join(results, DIVIDER) + DIVIDER + "Now the puzzle is solved."
}

func (self *Grid) HumanWalkthrough() string {
	steps := self.HumanSolution()
	return steps.Walkthrough(self)
}

func (self *Grid) HumanSolution() SolveDirections {
	clone := self.Copy()
	defer clone.Done()
	return clone.HumanSolve()
}

func (self *Grid) HumanSolve() SolveDirections {

	var results []*SolveStep

	//TODO: this supports just a single branch point, but in theory we should be able to branch an arbitrary number of times if necessary.
	//The point at which we branched for a guess. non-nil if we are in a branch.
	var branchPoint *Grid

	//The step we'll apply to get us into the branch point.
	var branchPointStep *SolveStep

	//Ther other numbers to try from the branch point.
	var otherNums IntSlice

	//The steps we've taken since the branch point.
	var branchSteps []*SolveStep

	//Note: trying these all in parallel is much slower (~15x) than doing them in sequence.
	//The reason is that in sequence we bailed early as soon as we found one step; now we try them all.

	for !self.Solved() {

		var possibilities []*SolveStep

		if branchPoint != nil && self.Invalid() {
			//We're in a branch, and got to a point where we found an invalidity.
			//We chose the wrong branch. We should unwind to the branch point and go down the other branch.

			//Unwind ourselves
			self.Load(branchPoint.DataString())

			//Throwout the steps down the wrong branch we took.
			branchSteps = nil

			if len(otherNums) > 0 {

				//Pop off the nextNum to do
				nextNum := otherNums[0]
				otherNums = otherNums[1:]

				//Stuff it into the TargetNums for the branch step.
				branchPointStep.TargetNums = IntSlice{nextNum}

				//Stuff the possibility list with the mangled branchPointStep.
				possibilities = []*SolveStep{branchPointStep}
			} else {
				//Well, crap. We're out of luck, nothing more for us to do.
				//TODO: pick a different guess operation at this grid state.
			}

		} else {

			//Normal operation; get potential solve steps by running them all.
			possibilities = runTechniques(CheapTechniques, self)
		}

		//TODO: provide hints to the techniques of where to look based on the last filled cell

		//Now pick one to apply.
		if len(possibilities) == 0 {
			//Okay, let's try the ExpensiveTechniques, as a hail mary.
			possibilities = runTechniques(ExpensiveTechniques, self)
			if len(possibilities) == 0 {
				//Hmm, didn't find any possivbilities. We're getting to be out of options...

				if branchPoint == nil {
					//Try to guess as a hail mary
					possibilities = runTechniques([]SolveTechnique{GuessTechnique}, self)

					if len(possibilities) == 0 {
						//Okay, we're well and truly done--not even any guesses came up with something. Nothing we can do.
						break
					} else {
						//Yay, found something! remember the branch point, so we can jump back to it.

						//We're just going to choose the first one.
						possibilities = possibilities[0:1]

						//TODO: this doesn't hold our special excludes, which we might have worked quite a bit to set up.
						//Ideally we'd have a way to keep those overrides.
						//The worst case is that we have a few unnecessary Cull steps just before the branch point.
						branchPoint = self.Copy()
						branchPointStep = possibilities[0]
						otherNums = branchPointStep.PointerNums

						//Null out the branchPointStep's pointerNums; their only point was to communicate out the other possibilities.
						//And from now on they'll just be confusing.
						branchPointStep.PointerNums = nil
					}
				} else {
					//looks like we got to a point where we're in a branch and would really like to branch again.
					//We can't handle that now, so just bail out in the worst possible way.
					//TODO: handle multiple nested branch points better
					panic("Human solve ran into a case where a double branch point would have been useful.")
				}
			}
		}

		//TODO: consider if we should stop picking techniques based on their weight here.
		//Now that Find returns a slice instead of a single, we're already much more likely to select an "easy" technique. ... Right?

		possibilitiesWeights := make([]float64, len(possibilities))
		for i, possibility := range possibilities {
			possibilitiesWeights[i] = possibility.Technique.Difficulty()
		}
		step := possibilities[randomIndexWithInvertedWeights(possibilitiesWeights)]

		if branchPoint == nil {
			results = append(results, step)
		} else {
			//We're in a branch point; we don't know if it's the RIGHT branch
			//So keep the steps somewhere else so we can throw them out if we unwind.
			branchSteps = append(branchSteps, step)
		}
		step.Apply(self)

	}
	if !self.Solved() {
		//We couldn't solve the puzzle.
		return nil
	}

	if len(branchSteps) > 0 {
		//Apparently we're in the branch where the solution acutally lay. commit those steps and return them.
		results = append(results, branchSteps...)
	}

	return results
}

func runTechniques(techniques []SolveTechnique, grid *Grid) []*SolveStep {
	numTechniques := len(techniques)
	possibilitiesChan := make(chan []*SolveStep)

	var possibilities []*SolveStep

	for _, technique := range techniques {
		go func(theTechnique SolveTechnique) {
			possibilitiesChan <- theTechnique.Find(grid)
		}(technique)
	}

	//Collect all of the results
	for i := 0; i < numTechniques; i++ {
		for _, possibility := range <-possibilitiesChan {
			possibilities = append(possibilities, possibility)
		}
	}

	return possibilities
}

func (self *Grid) Difficulty() float64 {
	//This can be an extremely expensive method. Do not call repeatedly!
	//returns the difficulty of the grid, which is a number between 0.0 and 1.0.
	//This is a probabilistic measure; repeated calls may return different numbers, although generally we wait for the results to converge.

	//We solve the same puzzle N times, then ask each set of steps for their difficulty, and combine those to come up with the overall difficulty.

	accum := 0.0
	average := 0.0
	lastAverage := 0.0

	for i := 0; i < MAX_DIFFICULTY_ITERATIONS; i++ {
		grid := self.Copy()
		steps := grid.HumanSolve()
		difficulty := steps.Difficulty()

		accum += difficulty
		average = accum / (float64(i) + 1.0)

		if math.Abs(average-lastAverage) < DIFFICULTY_CONVERGENCE {
			//Okay, we've already converged. Just return early!
			return average
		}

		lastAverage = average
	}

	//We weren't converging... oh well!
	return average

}
<|endoftext|>


<commit_before>package punchcard

/* Functions for dealing with a punchcard-log formatted stream (file, pipe)
 *
 * A punchcard-log stream consists of lines with the following format:
 * IN	2006-01-02T15:04:05Z07:00	project name
 * OUT	2006-01-02T15:04:05Z07:00
 *
 * Any IN line *MUST* be followed by an OUT line. OUT lines only have 2 elements,
 * whereas IN lines have 3.
 */

import (
	"bufio"
	"errors"
	"io"
	"strings"
	"time"
)

type Log struct {
	in  *io.Reader
	out *io.Writer
}

func NewLog(in io.Reader, out io.Writer) *Log {
	return &Log{&in, &out}
}

func (log Log) allLogLines() ([]LogLine, error) {
	var lines []LogLine

	scanner := bufio.NewScanner(*log.in)

	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		if 0 == len(line) {
			continue // ignore empty lines
		}
		logline, err := parseLogLine(line)
		if err != nil {
			return nil, err
		}
		lines = append(lines, logline)
	}

	return lines, nil
}

func (log Log) AllEntries() ([]*Entry, error) {
	var entries []*Entry
	loglines, err := log.allLogLines()

	if err != nil {
		return nil, err
	}

	for _, logline := range loglines {
		var entry *Entry
		// if last entry has IN but not OUT, next line should be OUT
		if len(entries) > 0 && entries[len(entries)-1].timeOut.IsZero() {
			entry = entries[len(entries)-1]
		} else {
			entry = NewEntry()
		}
		if err := entry.pushLogLine(logline); err != nil {
			return nil, err
		}
		if len(entries) == 0 || entry != entries[len(entries)-1] {
			entries = append(entries, entry)
		}
	}

	return entries, nil
}

func (log Log) LastEntry() (*Entry, error) {
	allEntries, err := log.AllEntries()
	if err != nil {
		return nil, err
	} else if 0 == len(allEntries) {
		return nil, nil
	}
	return allEntries[len(allEntries)-1], nil
}

// write an IN line to the log (if valid)
func (log Log) PunchIn(time time.Time, projectName string) error {
	lastEntry, err := log.LastEntry()
	if err != nil {
		return err
	} else if lastEntry != nil && lastEntry.timeOut.IsZero() {
		return errors.New("last entry should have timeOut")
	}
	logline := LogLine{IN, time, projectName}
	line := logline.String() + "\n"
	bytes, err := (*log.out).Write([]byte(line))
	if err != nil {
		return err
	} else if bytes != len(line) {
		return errors.New("Wrong number of bytes written")
	}
	return nil
}

// write an OUT line to the log (if valid)
func (log Log) PunchOut(time time.Time) error {
	lastEntry, err := log.LastEntry()
	if err != nil {
		return err
	} else if lastEntry == nil || lastEntry.IsZero() {
		return errors.New("Entry should not be empty")
	}
	logline := LogLine{OUT, time, lastEntry.project}
	line := logline.String() + "\n"
	bytes, err := (*log.out).Write([]byte(line))
	if err != nil {
		return err
	} else if bytes != len(line) {
		return errors.New("Wrong number of bytes written")
	}
	return nil
}
<commit_msg>doc update<commit_after>package punchcard

/* Functions for dealing with a punchcard-log formatted stream (file, pipe)
 *
 * A punchcard-log stream consists of lines with the following format:
 * IN	2006-01-02T15:04:05Z07:00	project name
 * OUT	2006-01-02T15:04:05Z07:00	project name
 *
 * An IN line *MUST* be followed by an OUT line. The project name field of an
 * OUT line *MUST* match the project name on the IN line before it.
 */

import (
	"bufio"
	"errors"
	"io"
	"strings"
	"time"
)

type Log struct {
	in  *io.Reader
	out *io.Writer
}

func NewLog(in io.Reader, out io.Writer) *Log {
	return &Log{&in, &out}
}

func (log Log) allLogLines() ([]LogLine, error) {
	var lines []LogLine

	scanner := bufio.NewScanner(*log.in)

	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		if 0 == len(line) {
			continue // ignore empty lines
		}
		logline, err := parseLogLine(line)
		if err != nil {
			return nil, err
		}
		lines = append(lines, logline)
	}

	return lines, nil
}

func (log Log) AllEntries() ([]*Entry, error) {
	var entries []*Entry
	loglines, err := log.allLogLines()

	if err != nil {
		return nil, err
	}

	for _, logline := range loglines {
		var entry *Entry
		// if last entry has IN but not OUT, next line should be OUT
		if len(entries) > 0 && entries[len(entries)-1].timeOut.IsZero() {
			entry = entries[len(entries)-1]
		} else {
			entry = NewEntry()
		}
		if err := entry.pushLogLine(logline); err != nil {
			return nil, err
		}
		if len(entries) == 0 || entry != entries[len(entries)-1] {
			entries = append(entries, entry)
		}
	}

	return entries, nil
}

func (log Log) LastEntry() (*Entry, error) {
	allEntries, err := log.AllEntries()
	if err != nil {
		return nil, err
	} else if 0 == len(allEntries) {
		return nil, nil
	}
	return allEntries[len(allEntries)-1], nil
}

// write an IN line to the log (if valid)
func (log Log) PunchIn(time time.Time, projectName string) error {
	lastEntry, err := log.LastEntry()
	if err != nil {
		return err
	} else if lastEntry != nil && lastEntry.timeOut.IsZero() {
		return errors.New("last entry should have timeOut")
	}
	logline := LogLine{IN, time, projectName}
	line := logline.String() + "\n"
	bytes, err := (*log.out).Write([]byte(line))
	if err != nil {
		return err
	} else if bytes != len(line) {
		return errors.New("Wrong number of bytes written")
	}
	return nil
}

// write an OUT line to the log (if valid)
func (log Log) PunchOut(time time.Time) error {
	lastEntry, err := log.LastEntry()
	if err != nil {
		return err
	} else if lastEntry == nil || lastEntry.IsZero() {
		return errors.New("Entry should not be empty")
	}
	logline := LogLine{OUT, time, lastEntry.project}
	line := logline.String() + "\n"
	bytes, err := (*log.out).Write([]byte(line))
	if err != nil {
		return err
	} else if bytes != len(line) {
		return errors.New("Wrong number of bytes written")
	}
	return nil
}
<|endoftext|>


<commit_before>package bitset

type word uint64

const (
	bitsPerWord = 64
)

type Bitset struct {
	set   []word
	count int
}

func New() Bitset {
	bs := new(Bitset)
	bs.set = make([]word, 1)
	return *bs
}

func (bs *Bitset) Add(i int) {
	setlen := len(bs.set)
	if i >= setlen*bitsPerWord {
		var newSet = make([]word, setlen+i/bitsPerWord+1)
		copy(newSet, bs.set)
		bs.set = newSet
	}
	bs.set[i/bitsPerWord] |= 1 << uint(i%bitsPerWord)
	bs.count++
}

func (bs *Bitset) Del(i int) {
	bs.set[i/bitsPerWord] &= ^(1 << uint(i%bitsPerWord))
	bs.count--
}

func (bs *Bitset) Test(i int) bool {
	return (bs.set[i/bitsPerWord] & (1 << uint(i%bitsPerWord))) != 0
}

func (bs *Bitset) SetAll() {
	for i := range bs.set {
		bs.set[i] = ^word(0)
	}
	bs.count = len(bs.set) * bitsPerWord
}

func (bs *Bitset) ClearAll() {
	for i := range bs.set {
		bs.set[i] = 0
	}
	bs.count = 0
}

func (bs *Bitset) GetCount() int {
	return bs.count
}

func (bs *Bitset) GetAll(s []int) {
	for i, set := range bs.set {
		if set == 0 {
			continue
		}
		for bit := 0; bit < bitsPerWord; bit++ {
			if set&(1<<uint(bit)) != 0 {
				s = append(s, i*bitsPerWord+bit)
			}
		}
	}
	return
}
<commit_msg>Readability fixes<commit_after>package bitset

type word uint64

const (
	bitsPerWord = 64
)

type Bitset struct {
	word  []word
	count int
}

func New() Bitset {
	bs := new(Bitset)
	bs.word = make([]word, 1)
	return *bs
}

func (bs *Bitset) Add(i int) {
	if i >= len(bs.word)*bitsPerWord {
		var newSet = make([]word, len(bs.word)+i/bitsPerWord+1)
		copy(newSet, bs.word)
		bs.word = newSet
	}
	bs.word[i/bitsPerWord] |= 1 << uint(i%bitsPerWord)
	bs.count++
}

func (bs *Bitset) Del(i int) {
	bs.word[i/bitsPerWord] &= ^(1 << uint(i%bitsPerWord))
	bs.count--
}

func (bs *Bitset) Test(i int) bool {
	return (bs.word[i/bitsPerWord] & (1 << uint(i%bitsPerWord))) != 0
}

func (bs *Bitset) SetAll() {
	for i := range bs.word {
		bs.word[i] = ^word(0)
	}
	bs.count = len(bs.word) * bitsPerWord
}

func (bs *Bitset) ClearAll() {
	for i := range bs.word {
		bs.word[i] = 0
	}
	bs.count = 0
}

func (bs *Bitset) GetCount() int {
	return bs.count
}

func (bs *Bitset) GetAll(s []int) {
	for i, w := range bs.word {
		if w == 0 {
			continue
		}
		for bit := 0; bit < bitsPerWord; bit++ {
			if w&(1<<uint(bit)) != 0 {
				s = append(s, i*bitsPerWord+bit)
			}
		}
	}
	return
}
<|endoftext|>


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

package app

import (
	"errors"
	"sync"
	"sync/atomic"
)

const (
	closed int32 = iota
	open
)

var listeners = struct {
	m map[string][]*LogListener
	sync.RWMutex
}{
	m: make(map[string][]*LogListener),
}

type LogListener struct {
	C       <-chan Applog
	c       chan Applog
	state   int32
	appname string
}

func NewLogListener(a *App) *LogListener {
	c := make(chan Applog)
	l := LogListener{C: c, c: c, state: open, appname: a.Name}
	listeners.Lock()
	list := listeners.m[l.appname]
	list = append(list, &l)
	listeners.m[a.Name] = list
	listeners.Unlock()
	return &l
}

func (l *LogListener) Close() error {
	if !atomic.CompareAndSwapInt32(&l.state, open, closed) {
		return errors.New("Already closed.")
	}
	close(l.c)
	listeners.Lock()
	defer listeners.Unlock()
	list := listeners.m[l.appname]
	index := -1
	for i, listener := range list {
		if listener == l {
			index = i
			break
		}
	}
	if index > -1 {
		list[index], list[len(list)-1] = list[len(list)-1], list[index]
		listeners.m[l.appname] = list[:len(list)-1]
	}
	return nil
}

func notify(appName string, messages []Applog) {
	var wg sync.WaitGroup
	listeners.RLock()
	ls := listeners.m[appName]
	listeners.RUnlock()
	for _, l := range ls {
		wg.Add(1)
		go func(l *LogListener) {
			for _, msg := range messages {
				l.c <- msg
			}
			wg.Done()
		}(l)
	}
	wg.Wait()
}
<commit_msg>app: use a buffered channel to notify logs in LogListener<commit_after>// Copyright 2013 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package app

import (
	"errors"
	"sync"
	"sync/atomic"
)

const (
	closed int32 = iota
	open
)

var listeners = struct {
	m map[string][]*LogListener
	sync.RWMutex
}{
	m: make(map[string][]*LogListener),
}

type LogListener struct {
	C       <-chan Applog
	c       chan Applog
	state   int32
	appname string
}

func NewLogListener(a *App) *LogListener {
	c := make(chan Applog, 10)
	l := LogListener{C: c, c: c, state: open, appname: a.Name}
	listeners.Lock()
	list := listeners.m[l.appname]
	list = append(list, &l)
	listeners.m[a.Name] = list
	listeners.Unlock()
	return &l
}

func (l *LogListener) Close() error {
	if !atomic.CompareAndSwapInt32(&l.state, open, closed) {
		return errors.New("Already closed.")
	}
	close(l.c)
	listeners.Lock()
	defer listeners.Unlock()
	list := listeners.m[l.appname]
	index := -1
	for i, listener := range list {
		if listener == l {
			index = i
			break
		}
	}
	if index > -1 {
		list[index], list[len(list)-1] = list[len(list)-1], list[index]
		listeners.m[l.appname] = list[:len(list)-1]
	}
	return nil
}

func notify(appName string, messages []Applog) {
	var wg sync.WaitGroup
	listeners.RLock()
	ls := listeners.m[appName]
	listeners.RUnlock()
	for _, l := range ls {
		wg.Add(1)
		go func(l *LogListener) {
			for _, msg := range messages {
				l.c <- msg
			}
			wg.Done()
		}(l)
	}
	wg.Wait()
}
<|endoftext|>


<commit_before>package hydra

import (
	"bytes"
	"encoding/json"
	"strings"
	"time"

	"github.com/fujiwara/fluent-agent-hydra/fluent"
)

const (
	MessageChannelBufferLen = 1
	MonitorChannelBufferLen = 256
	LineSeparatorStr        = "\n"
	LTSVColSeparatorStr     = "\t"
	LTSVDataSeparatorStr    = ":"
)

var (
	LineSeparator = []byte{'\n'}
)

type ShutdownType struct {
	message string
}

func (s *ShutdownType) Error() string { return s.message }

// NewChannel create channel for using by OutForward() and InTail().
func NewChannel() (chan *fluent.FluentRecordSet, chan Stat) {
	messageCh := make(chan *fluent.FluentRecordSet, MessageChannelBufferLen)
	monitorCh := make(chan Stat, MonitorChannelBufferLen)
	return messageCh, monitorCh
}

func NewFluentRecordSet(tag string, key string, buffer []byte) *fluent.FluentRecordSet {
	timestamp := time.Now().Unix()
	messages := bytes.Split(buffer, LineSeparator)
	records := make([]fluent.FluentRecordType, len(messages))
	for i, m := range messages {
		records[i] = &fluent.TinyFluentMessage{
			Timestamp: timestamp,
			FieldName: key,
			Message:   m,
		}
	}
	return &fluent.FluentRecordSet{
		Tag:     tag,
		Records: records,
	}
}

func NewFluentRecordSetLTSV(tag string, key string, mod *RecordModifier, buffer []byte) *fluent.FluentRecordSet {
	timestamp := time.Now().Unix()
	lines := strings.Split(string(buffer), LineSeparatorStr)
	records := make([]fluent.FluentRecordType, len(lines))
	for i, line := range lines {
		data := make(map[string]interface{})
		for _, col := range strings.Split(line, LTSVColSeparatorStr) {
			pair := strings.SplitN(col, LTSVDataSeparatorStr, 2)
			if len(pair) == 2 {
				data[pair[0]] = pair[1]
			} else {
				// invalid LTSV format.
				data[key] = line
			}
		}
		r := &fluent.TinyFluentRecord{
			Timestamp: timestamp,
			Data:      data,
		}
		if mod != nil {
			mod.Modify(r)
		}
		records[i] = r
	}
	return &fluent.FluentRecordSet{
		Tag:     tag,
		Records: records,
	}
}

func NewFluentRecordSetJSON(tag string, key string, mod *RecordModifier, buffer []byte) *fluent.FluentRecordSet {
	timestamp := time.Now().Unix()
	lines := bytes.Split(buffer, LineSeparator)
	records := make([]fluent.FluentRecordType, 0)
	for _, line := range lines {
		data := make(map[string]interface{})
		err := json.Unmarshal(line, &data)
		if err != nil {
			// invalid JSON format.
			data[key] = string(line)
		}
		r := &fluent.TinyFluentRecord{
			Timestamp: timestamp,
			Data:      data,
		}
		if mod != nil {
			mod.Modify(r)
		}
		records = append(records, r)
	}
	return &fluent.FluentRecordSet{
		Tag:     tag,
		Records: records,
	}
}
<commit_msg>optimization: reduced memory allocations for append().<commit_after>package hydra

import (
	"bytes"
	"encoding/json"
	"strings"
	"time"

	"github.com/fujiwara/fluent-agent-hydra/fluent"
)

const (
	MessageChannelBufferLen = 1
	MonitorChannelBufferLen = 256
	LineSeparatorStr        = "\n"
	LTSVColSeparatorStr     = "\t"
	LTSVDataSeparatorStr    = ":"
)

var (
	LineSeparator = []byte{'\n'}
)

type ShutdownType struct {
	message string
}

func (s *ShutdownType) Error() string { return s.message }

// NewChannel create channel for using by OutForward() and InTail().
func NewChannel() (chan *fluent.FluentRecordSet, chan Stat) {
	messageCh := make(chan *fluent.FluentRecordSet, MessageChannelBufferLen)
	monitorCh := make(chan Stat, MonitorChannelBufferLen)
	return messageCh, monitorCh
}

func NewFluentRecordSet(tag string, key string, buffer []byte) *fluent.FluentRecordSet {
	timestamp := time.Now().Unix()
	messages := bytes.Split(buffer, LineSeparator)
	records := make([]fluent.FluentRecordType, len(messages))
	for i, m := range messages {
		records[i] = &fluent.TinyFluentMessage{
			Timestamp: timestamp,
			FieldName: key,
			Message:   m,
		}
	}
	return &fluent.FluentRecordSet{
		Tag:     tag,
		Records: records,
	}
}

func NewFluentRecordSetLTSV(tag string, key string, mod *RecordModifier, buffer []byte) *fluent.FluentRecordSet {
	timestamp := time.Now().Unix()
	lines := strings.Split(string(buffer), LineSeparatorStr)
	records := make([]fluent.FluentRecordType, len(lines))
	for i, line := range lines {
		data := make(map[string]interface{})
		for _, col := range strings.Split(line, LTSVColSeparatorStr) {
			pair := strings.SplitN(col, LTSVDataSeparatorStr, 2)
			if len(pair) == 2 {
				data[pair[0]] = pair[1]
			} else {
				// invalid LTSV format.
				data[key] = line
			}
		}
		r := &fluent.TinyFluentRecord{
			Timestamp: timestamp,
			Data:      data,
		}
		if mod != nil {
			mod.Modify(r)
		}
		records[i] = r
	}
	return &fluent.FluentRecordSet{
		Tag:     tag,
		Records: records,
	}
}

func NewFluentRecordSetJSON(tag string, key string, mod *RecordModifier, buffer []byte) *fluent.FluentRecordSet {
	timestamp := time.Now().Unix()
	lines := bytes.Split(buffer, LineSeparator)
	records := make([]fluent.FluentRecordType, 0, len(lines))
	for _, line := range lines {
		data := make(map[string]interface{})
		err := json.Unmarshal(line, &data)
		if err != nil {
			// invalid JSON format.
			data[key] = string(line)
		}
		r := &fluent.TinyFluentRecord{
			Timestamp: timestamp,
			Data:      data,
		}
		if mod != nil {
			mod.Modify(r)
		}
		records = append(records, r)
	}
	return &fluent.FluentRecordSet{
		Tag:     tag,
		Records: records,
	}
}
<|endoftext|>


<commit_before>// Copyright 2017 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"flag"
	"fmt"
	"os"
	"strings"
	"time"

	"github.com/bazelbuild/bazel-watcher/ibazel/log"
)

var Version = "Development"

var overrideableStartupFlags []string = []string{
	"--bazelrc",
}

var overrideableBazelFlags []string = []string{
	"--action_env",
	"--announce_rc",
	"--aspects",
	"--build_tag_filters=",
	"--build_tests_only",
	"--compilation_mode",
	"--compile_one_dependency",
	"--config=",
	"--copt=",
	"--curses=no",
	"--cxxopt",
	"-c",
	"--define=",
	"--dynamic_mode=",
	"--features=",
	"--flaky_test_attempts=",
	"--keep_going",
	"-k",
	"--nocache_test_results",
	"--nostamp",
	"--output_groups=",
	"--override_repository=",
	"--platforms",
	"--repo_env",
	"--runs_per_test=",
	"--run_under=",
	"--stamp",
	"--strategy=",
	"--test_arg=",
	"--test_env=",
	"--test_filter=",
	"--test_output=",
	"--test_tag_filters=",
	"--test_timeout=",
	// Custom Starlark build settings
	// https://docs.bazel.build/versions/master/skylark/config.html#using-build-settings-on-the-command-line
	"--//",
	"--no//",
}

var debounceDuration = flag.Duration("debounce", 100*time.Millisecond, "Debounce duration")
var logToFile = flag.String("log_to_file", "-", "Log iBazel stderr to a file instead of os.Stderr")

func usage() {
	fmt.Fprintf(os.Stderr, `iBazel - Version %s

A file watcher for Bazel. Whenever a source file used in a specified
target, run, build, or test the specified targets.

Usage:

ibazel build|test|run [flags] targets...

Example:

ibazel test //path/to/my/testing:target
ibazel test //path/to/my/testing/targets/...
ibazel run //path/to/my/runnable:target -- --arguments --for_your=binary
ibazel build //path/to/my/buildable:target

Supported Bazel startup flags:
  %s

Supported Bazel command flags:
  %s

To add to this list, edit
https://github.com/bazelbuild/bazel-watcher/blob/master/ibazel/main.go

iBazel flags:
`, Version, strings.Join(overrideableStartupFlags, "\n  "), strings.Join(overrideableBazelFlags, "\n  "))
	flag.PrintDefaults()
}

func isOverrideable(arg string, overrideables []string) bool {
	for _, overrideable := range overrideables {
		if strings.HasPrefix(arg, overrideable) {
			return true
		}
	}
	return false
}

func isOverrideableStartupFlag(arg string) bool {
	return isOverrideable(arg, overrideableStartupFlags)
}

func isOverrideableBazelFlag(arg string) bool {
	return isOverrideable(arg, overrideableBazelFlags)
}

func parseArgs(in []string) (targets, startupArgs, bazelArgs, args []string) {
	afterDoubleDash := false
	for _, arg := range in {
		if afterDoubleDash {
			// Put it in the extra args section if we are after a double dash.
			args = append(args, arg)
		} else {
			// Check to see if this token is a double dash.
			if arg == "--" {
				afterDoubleDash = true
				continue
			}

			// Check to see if this startup option or command flag is on the bazel whitelist of flags.
			if isOverrideableStartupFlag(arg) {
				startupArgs = append(startupArgs, arg)
			} else if isOverrideableBazelFlag(arg) {
				bazelArgs = append(bazelArgs, arg)
			} else {
				// If none of those things then it's probably a target.
				targets = append(targets, arg)
			}
		}
	}
	return
}

// main entrypoint for IBazel.
func main() {
	flag.Usage = usage
	flag.Parse()

	if *logToFile != "-" {
		var err error
		logFile, err := os.OpenFile(*logToFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
		if err != nil {
			panic(err)
		}
		log.SetWriter(logFile)
	}

	if len(flag.Args()) < 2 {
		usage()
		return
	}

	command := strings.ToLower(flag.Args()[0])
	args := flag.Args()[1:]
	os.Setenv("IBAZEL", "true")

	i, err := New()
	if err != nil {
		log.Fatalf("Error creating iBazel: %s", err)
	}
	i.SetDebounceDuration(*debounceDuration)
	defer i.Cleanup()

	// increase the number of files that this process can
	// have open.
	err = setUlimit()
	if err != nil {
		log.Errorf("error setting higher file descriptor limit for this process: %v", err)
	}

	handle(i, command, args)
}

func handle(i *IBazel, command string, args []string) {
	targets, startupArgs, bazelArgs, args := parseArgs(args)
	i.SetStartupArgs(startupArgs)
	i.SetBazelArgs(bazelArgs)

	switch command {
	case "build":
		i.Build(targets...)
	case "test":
		i.Test(targets...)
	case "run":
		// Run only takes one argument
		i.Run(targets[0], args)
	default:
		fmt.Fprintf(os.Stderr, "Asked me to perform %s. I don't know how to do that.", command)
		usage()
		return
	}
}
<commit_msg>chore(NA): adds --show_result into the iBazel proxied flags list (#471)<commit_after>// Copyright 2017 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"flag"
	"fmt"
	"os"
	"strings"
	"time"

	"github.com/bazelbuild/bazel-watcher/ibazel/log"
)

var Version = "Development"

var overrideableStartupFlags []string = []string{
	"--bazelrc",
}

var overrideableBazelFlags []string = []string{
	"--action_env",
	"--announce_rc",
	"--aspects",
	"--build_tag_filters=",
	"--build_tests_only",
	"--compilation_mode",
	"--compile_one_dependency",
	"--config=",
	"--copt=",
	"--curses=no",
	"--cxxopt",
	"-c",
	"--define=",
	"--dynamic_mode=",
	"--features=",
	"--flaky_test_attempts=",
	"--keep_going",
	"-k",
	"--nocache_test_results",
	"--nostamp",
	"--output_groups=",
	"--override_repository=",
	"--platforms",
	"--repo_env",
	"--runs_per_test=",
	"--run_under=",
	"--show_result=",
	"--stamp",
	"--strategy=",
	"--test_arg=",
	"--test_env=",
	"--test_filter=",
	"--test_output=",
	"--test_tag_filters=",
	"--test_timeout=",
	// Custom Starlark build settings
	// https://docs.bazel.build/versions/master/skylark/config.html#using-build-settings-on-the-command-line
	"--//",
	"--no//",
}

var debounceDuration = flag.Duration("debounce", 100*time.Millisecond, "Debounce duration")
var logToFile = flag.String("log_to_file", "-", "Log iBazel stderr to a file instead of os.Stderr")

func usage() {
	fmt.Fprintf(os.Stderr, `iBazel - Version %s

A file watcher for Bazel. Whenever a source file used in a specified
target, run, build, or test the specified targets.

Usage:

ibazel build|test|run [flags] targets...

Example:

ibazel test //path/to/my/testing:target
ibazel test //path/to/my/testing/targets/...
ibazel run //path/to/my/runnable:target -- --arguments --for_your=binary
ibazel build //path/to/my/buildable:target

Supported Bazel startup flags:
  %s

Supported Bazel command flags:
  %s

To add to this list, edit
https://github.com/bazelbuild/bazel-watcher/blob/master/ibazel/main.go

iBazel flags:
`, Version, strings.Join(overrideableStartupFlags, "\n  "), strings.Join(overrideableBazelFlags, "\n  "))
	flag.PrintDefaults()
}

func isOverrideable(arg string, overrideables []string) bool {
	for _, overrideable := range overrideables {
		if strings.HasPrefix(arg, overrideable) {
			return true
		}
	}
	return false
}

func isOverrideableStartupFlag(arg string) bool {
	return isOverrideable(arg, overrideableStartupFlags)
}

func isOverrideableBazelFlag(arg string) bool {
	return isOverrideable(arg, overrideableBazelFlags)
}

func parseArgs(in []string) (targets, startupArgs, bazelArgs, args []string) {
	afterDoubleDash := false
	for _, arg := range in {
		if afterDoubleDash {
			// Put it in the extra args section if we are after a double dash.
			args = append(args, arg)
		} else {
			// Check to see if this token is a double dash.
			if arg == "--" {
				afterDoubleDash = true
				continue
			}

			// Check to see if this startup option or command flag is on the bazel whitelist of flags.
			if isOverrideableStartupFlag(arg) {
				startupArgs = append(startupArgs, arg)
			} else if isOverrideableBazelFlag(arg) {
				bazelArgs = append(bazelArgs, arg)
			} else {
				// If none of those things then it's probably a target.
				targets = append(targets, arg)
			}
		}
	}
	return
}

// main entrypoint for IBazel.
func main() {
	flag.Usage = usage
	flag.Parse()

	if *logToFile != "-" {
		var err error
		logFile, err := os.OpenFile(*logToFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
		if err != nil {
			panic(err)
		}
		log.SetWriter(logFile)
	}

	if len(flag.Args()) < 2 {
		usage()
		return
	}

	command := strings.ToLower(flag.Args()[0])
	args := flag.Args()[1:]
	os.Setenv("IBAZEL", "true")

	i, err := New()
	if err != nil {
		log.Fatalf("Error creating iBazel: %s", err)
	}
	i.SetDebounceDuration(*debounceDuration)
	defer i.Cleanup()

	// increase the number of files that this process can
	// have open.
	err = setUlimit()
	if err != nil {
		log.Errorf("error setting higher file descriptor limit for this process: %v", err)
	}

	handle(i, command, args)
}

func handle(i *IBazel, command string, args []string) {
	targets, startupArgs, bazelArgs, args := parseArgs(args)
	i.SetStartupArgs(startupArgs)
	i.SetBazelArgs(bazelArgs)

	switch command {
	case "build":
		i.Build(targets...)
	case "test":
		i.Test(targets...)
	case "run":
		// Run only takes one argument
		i.Run(targets[0], args)
	default:
		fmt.Fprintf(os.Stderr, "Asked me to perform %s. I don't know how to do that.", command)
		usage()
		return
	}
}
<|endoftext|>


<commit_before>package asserts

import (
	"fmt"
	"testing"
)

func Equals (t *testing.T, name string , got string, expected string ) {
   if got != expected {
      t.Errorf("Failed %s\ngot\n%s\n\nexpected\n%s\n\n", name, got, expected )
		t.FailNow()
   }
}

func NotEquals (t *testing.T, name string , got string, expected string ) {
   if got == expected {
      t.Errorf("Failed %s\ngot\n%s\n\nexpected something different\n%s\n\n", name, got, expected )
		t.FailNow()
   }
}

func IntEquals (t *testing.T, name string , got int, expected int ) {
   if got != expected {
		fmt.Printf("in IntEquals with failure for test %v, got %v, expected %v\n", name, got ,expected)
      t.Errorf("Faild %s\ngot\n%d\n\nexpected\n%d\n\n", name, got, expected )
		//t.FailNow()
   }
}

func Float64Equals (t *testing.T, name string , got float64, expected float64 ) {
   if got != expected {
      t.Errorf("Failed %s\ngot\n%v\n\nexpected\n%v\n\n", name, got, expected )
		t.FailNow()
   }
}

func True (t *testing.T, name string , got bool ) {
   if !got {
      t.Errorf("Failed %s\ngot\n%s\n\nexpected\n%s\n\n", name, got, true)
		t.FailNow()
   }
}
var Ok func (*testing.T, string , bool ) = True

func False (t *testing.T, name string , got bool ) {
   if got {
      t.Errorf("Failed %s\ngot\n%s\n\nexpected\n%s\n\n", name, got, false)
		t.FailNow()
   }
}
var NotOk func (*testing.T, string , bool ) = False

func Nil (t *testing.T, name string , got ...interface{}) {
   if got == nil {
      t.Errorf("Failed %s\ngot\n%s\n\nexpected\n%s\n\n", name, got, nil)
		t.FailNow()
   }
}

func NotNil (t *testing.T, name string , got ...interface{}) {
   if got != nil {
      t.Errorf("Failed %s\ngot\n%s\n\nexpected\n(not nil)\n\n", name, got)
		t.FailNow()
   }
}
<commit_msg>Adding godoc<commit_after>package asserts

import (
	"fmt"
	"testing"
)

// Test a string value matches another string
func Equals (t *testing.T, name string , got string, expected string ) {
   if got != expected {
      t.Errorf("Failed %s\ngot\n%s\n\nexpected\n%s\n\n", name, got, expected )
		t.FailNow()
   }
}

// Test a string value does not match another string
func NotEquals (t *testing.T, name string , got string, expected string ) {
   if got == expected {
      t.Errorf("Failed %s\ngot\n%s\n\nexpected something different\n%s\n\n", name, got, expected )
		t.FailNow()
   }
}

// Test an int value
func IntEquals (t *testing.T, name string , got int, expected int ) {
   if got != expected {
		fmt.Printf("in IntEquals with failure for test %v, got %v, expected %v\n", name, got ,expected)
      t.Errorf("Faild %s\ngot\n%d\n\nexpected\n%d\n\n", name, got, expected )
		//t.FailNow()
   }
}

// Test a float64 value
func Float64Equals (t *testing.T, name string , got float64, expected float64 ) {
   if got != expected {
      t.Errorf("Failed %s\ngot\n%v\n\nexpected\n%v\n\n", name, got, expected )
		t.FailNow()
   }
}

// Given a value, test that it falls inclusively within (>=) start and (<=) end. This is the opposite of Outside
func Bounded( t *testing.T, name string, value ,start, end interface{}) {
	valueI := value.(int64) / 1
	startI := start.(int64) / 1
	endI := end.(int64) / 1
	if startI > endI {
		tmp := endI
		endI = startI
		startI = tmp
	}
	if valueI < startI || valueI > endI {
      t.Errorf("Failed %s\n%v is out of bounds(%v,%v)\n\n", name, value, start, end)
		t.FailNow()
	}
}

// Given a value, test that it falls exclusively outside of the interval >= start and <= end.  This is the opposite of Bounded.
func Outside( t *testing.T, name string, value ,start, end interface{}) {
	valueI := value.(int64) / 1
	startI := start.(int64) / 1
	endI := end.(int64) / 1
	if startI > endI {
		tmp := endI
		endI = startI
		startI = tmp
	}
	if valueI >= startI || valueI <= endI {
      t.Errorf("Failed %s\n%v is within bounds(%v,%v)\n\n", name, value, start, end)
		t.FailNow()
	}
}

// Test that a value is true.   Synonym of Ok and Is
func True (t *testing.T, name string , got bool ) {
   if !got {
      t.Errorf("Failed %s\ngot\n%s\n\nexpected\n%s\n\n", name, got, true)
		t.FailNow()
   }
}

// Test that a value is true.   Synonym of True and Is
var Ok func (*testing.T, string , bool ) = True

// Test that a value is true.   Synonym of True and Ok
var Is func (*testing.T, string , bool ) = True

// Test that a value is false.   Synonym of NotOk and Isnt
func False (t *testing.T, name string , got bool ) {
   if got {
      t.Errorf("Failed %s\ngot\n%s\n\nexpected\n%s\n\n", name, got, false)
		t.FailNow()
   }
}

// Test that a value is false. Synonyms with False and Isnt
var NotOk func (*testing.T, string , bool ) = False

// Test that a value is false. Synonyms with False and NotOk
var Isnt  func (*testing.T, string , bool ) = False

// Test that a value is nil.
func Nil (t *testing.T, name string , got ...interface{}) {
   if got == nil {
      t.Errorf("Failed %s\ngot\n%s\n\nexpected\n%s\n\n", name, got, nil)
		t.FailNow()
   }
}

// Test that a value is not nil.
func NotNil (t *testing.T, name string , got ...interface{}) {
   if got != nil {
      t.Errorf("Failed %s\ngot\n%s\n\nexpected\n(not nil)\n\n", name, got)
		t.FailNow()
   }
}
<|endoftext|>


<commit_before>// This file is subject to a 1-clause BSD license.
// Its contents can be found in the enclosed LICENSE file.

package imghash

import "image"

// Average computes a Perceptual Hash using a naive, but very fast method.
// It holds up to minor colour changes, changing brightness and contrast and
// is indifferent to aspect ratio and image size differences.
//
// Average Hash is a great algorithm if you are looking for something specific.
// For example, if we have a small thumbnail of an image and we wish to know
// if the big one exists somewhere in our collection. Average Hash will find
// it very quickly. However, if there are modifications -- like text was added
// or a head was spliced into place, then Average Hash probably won't do the job.
// The Average Hash is quick and easy, but it can generate false-misses if
// gamma correction or color histogram is applied to the image. This is
// because the colors move along a non-linear scale -- changing where the
// "average" is located and therefore changing which bits are above/below the
// average.
func Average(img image.Image) uint64 {
	img = resize(img, 8, 8)
	img = grayscale(img)
	mean := avg_computeMean(img)
	return avg_computeHash(img, mean)
}

// avg_computeMean computes the mean of all pixels.
func avg_computeMean(img image.Image) uint32 {
	var x, y int
	var r, m uint32

	rect := img.Bounds()
	w := rect.Max.X - rect.Min.X
	h := rect.Max.Y - rect.Min.Y
	c := uint32(w * h)

	if c == 0 {
		return 0
	}

	for y = rect.Min.Y; y < rect.Max.Y; y++ {
		for x = rect.Min.X; x < rect.Max.X; x++ {
			r, _, _, _ = img.At(x, y).RGBA()
			m += r
		}
	}

	return m / c
}

// avg_computeHash computes the hash bits for the given image and mean.
// It sets individual bits in a 64-bit integer. A bit is set of the
// pixel value is larger than the mean.
func avg_computeHash(img image.Image, mean uint32) uint64 {
	var x, y int
	var value, bit uint64
	var r uint32

	rect := img.Bounds()

	for y = rect.Min.Y; y < rect.Max.Y; y++ {
		for x = rect.Min.X; x < rect.Max.X; x++ {
			r, _, _, _ = img.At(x, y).RGBA()

			if r > mean {
				value |= 1 << bit
			}

			bit++
		}
	}

	return value
}
<commit_msg>Refactors some code for more consistent naming.<commit_after>// This file is subject to a 1-clause BSD license.
// Its contents can be found in the enclosed LICENSE file.

package imghash

import "image"

// Average computes a Perceptual Hash using a naive, but very fast method.
// It holds up to minor colour changes, changing brightness and contrast and
// is indifferent to aspect ratio and image size differences.
//
// Average Hash is a great algorithm if you are looking for something specific.
// For example, if we have a small thumbnail of an image and we wish to know
// if the big one exists somewhere in our collection. Average Hash will find
// it very quickly. However, if there are modifications -- like text was added
// or a head was spliced into place, then Average Hash probably won't do the job.
//
// The Average Hash is quick and easy, but it can generate false-misses if
// gamma correction or color histogram is applied to the image. This is
// because the colors move along a non-linear scale -- changing where the
// "average" is located and therefore changing which bits are above/below the
// average.
func Average(img image.Image) uint64 {
	img = resize(img, 8, 8)
	img = grayscale(img)
	mean := avgMean(img)
	return avgHash(img, mean)
}

// avgMean computes the mean of all pixels.
func avgMean(img image.Image) uint32 {
	var x, y int
	var r, m uint32

	rect := img.Bounds()
	w := rect.Max.X - rect.Min.X
	h := rect.Max.Y - rect.Min.Y
	c := uint32(w * h)

	if c == 0 {
		return 0
	}

	for y = rect.Min.Y; y < rect.Max.Y; y++ {
		for x = rect.Min.X; x < rect.Max.X; x++ {
			r, _, _, _ = img.At(x, y).RGBA()
			m += r
		}
	}

	return m / c
}

// avgHash computes the hash bits for the given image and mean.
// It sets individual bits in a 64-bit integer. A bit is set of the
// pixel value is larger than the mean.
func avgHash(img image.Image, mean uint32) uint64 {
	var x, y int
	var value, bit uint64
	var r uint32

	rect := img.Bounds()

	for y = rect.Min.Y; y < rect.Max.Y; y++ {
		for x = rect.Min.X; x < rect.Max.X; x++ {
			r, _, _, _ = img.At(x, y).RGBA()

			if r > mean {
				value |= 1 << bit
			}

			bit++
		}
	}

	return value
}
<|endoftext|>


<commit_before>package main

import (
    "fmt"
)

type AVLNode struct {
    key int
    value int
    // height counts nodes (not edges)
    height int
    left *AVLNode
    right *AVLNode
}

func max(a int, b int) int {
    if a > b {
        return a
    }
    return b
}

func height(node *AVLNode) int {
    if node == nil {
        return 0
    }
    return node.height
}

func recalculateHeight(node *AVLNode) {
    node.height = 1 + max(height(node.left), height(node.right))
}

func add(node *AVLNode, key int, value int) *AVLNode {
    if node == nil {
        return &AVLNode{key, value, 1, nil, nil}
    }

    if key < node.key {
        node.left = add(node.left, key, value)
    } else if key > node.key {
        node.right = add(node.right, key, value)
    } else {
        // if same key exists update value
        node.value = value
    }
    return rebalanceTree(node)
}

func rebalanceTree(node *AVLNode) *AVLNode {
    if node == nil {
        return node
    }
    recalculateHeight(node)

    // check balance factor and rotateLeft if right-heavy and rotateRight if left-heavy
    balanceFactor := height(node.left) - height(node.right)
    if balanceFactor == -2 {
        // check if child is left-heavy and rotateRight first
        if height(node.right.left) > height(node.right.right) {
            node.right = rotateRight(node.right)
        }
        return rotateLeft(node)
    } else if balanceFactor == 2 {
        // check if child is right-heavy and rotateLeft first
        if height(node.left.right) > height(node.left.left) {
            node.left = rotateLeft(node.left)
        }
        return rotateRight(node)
    }
    return node
}

func rotateLeft(node *AVLNode) *AVLNode {
    newRoot := node.right
    node.right = newRoot.left
    newRoot.left = node

    recalculateHeight(node)
    recalculateHeight(newRoot)
    return newRoot
}

func rotateRight(node *AVLNode) *AVLNode {
    newRoot := node.left
    node.left = newRoot.right
    newRoot.right = node

    recalculateHeight(node)
    recalculateHeight(newRoot)
    return newRoot
}

func search(node *AVLNode, key int) *AVLNode {
    if node == nil {
        return nil
    }
    if key < node.key {
        return search(node.left, key)
    } else if key > node.key {
        return search(node.right, key)
    } else {
        return node
    }
}

func remove(node *AVLNode, key int) *AVLNode {
    if node == nil {
        return nil
    }
    if key < node.key {
        node.left = remove(node.left, key)
    } else if key > node.key {
        node.right = remove(node.right, key)
    } else {
        if node.left != nil && node.right != nil {
           // node to delete found with both children;
           // replace values with smallest node of the right sub-tree
           rightMinNode := findSmallest(node.right)
           node.key = rightMinNode.key
           node.value = rightMinNode.value
           // delete smallest node that we replaced
           //node.right = remove(node.right, rightMinNode.key)
           node.right = remove(node.right, rightMinNode.key)
        } else if node.left != nil {
           // node only has left child
           node = node.left
        } else if node.right != nil {
           // node only has right child
           node = node.right
        } else {
           // node has no children
           node = nil
           return node
        }

    }
    return rebalanceTree(node)
}

func findSmallest(node *AVLNode) *AVLNode {
    if node.left != nil {
        return findSmallest(node.left)
    } else {
        return node
    }
}

func displayTreeInOrder(node *AVLNode) {
    if node.left != nil {
        displayTreeInOrder(node.left)
    }
    fmt.Print(node.key, " ")
    if node.right != nil {
        displayTreeInOrder(node.right)
    }
}

func main() {
    var root *AVLNode
    //keys := []int{3,2,4,1,5}
    //keys := []int{1,2,3,4,5,6,7,8,9}
    keys := []int{15,3,9,44,4,8,13}
    for _, key := range keys {
        root = add(root, key, key*key)
    }

    remove(root, 15)
    displayTreeInOrder(root)
    fmt.Println("\n", search(root, 44))
}

<commit_msg>make reusable lib<commit_after>package avltree

import (
    "fmt"
)

type AVLNode struct {
    key int
    value int
    // height counts nodes (not edges)
    height int
    left *AVLNode
    right *AVLNode
}

func max(a int, b int) int {
    if a > b {
        return a
    }
    return b
}

func height(node *AVLNode) int {
    if node == nil {
        return 0
    }
    return node.height
}

func recalculateHeight(node *AVLNode) {
    node.height = 1 + max(height(node.left), height(node.right))
}

func add(node *AVLNode, key int, value int) *AVLNode {
    if node == nil {
        return &AVLNode{key, value, 1, nil, nil}
    }

    if key < node.key {
        node.left = add(node.left, key, value)
    } else if key > node.key {
        node.right = add(node.right, key, value)
    } else {
        // if same key exists update value
        node.value = value
    }
    return rebalanceTree(node)
}

func rebalanceTree(node *AVLNode) *AVLNode {
    if node == nil {
        return node
    }
    recalculateHeight(node)

    // check balance factor and rotateLeft if right-heavy and rotateRight if left-heavy
    balanceFactor := height(node.left) - height(node.right)
    if balanceFactor == -2 {
        // check if child is left-heavy and rotateRight first
        if height(node.right.left) > height(node.right.right) {
            node.right = rotateRight(node.right)
        }
        return rotateLeft(node)
    } else if balanceFactor == 2 {
        // check if child is right-heavy and rotateLeft first
        if height(node.left.right) > height(node.left.left) {
            node.left = rotateLeft(node.left)
        }
        return rotateRight(node)
    }
    return node
}

func rotateLeft(node *AVLNode) *AVLNode {
    newRoot := node.right
    node.right = newRoot.left
    newRoot.left = node

    recalculateHeight(node)
    recalculateHeight(newRoot)
    return newRoot
}

func rotateRight(node *AVLNode) *AVLNode {
    newRoot := node.left
    node.left = newRoot.right
    newRoot.right = node

    recalculateHeight(node)
    recalculateHeight(newRoot)
    return newRoot
}

func search(node *AVLNode, key int) *AVLNode {
    if node == nil {
        return nil
    }
    if key < node.key {
        return search(node.left, key)
    } else if key > node.key {
        return search(node.right, key)
    } else {
        return node
    }
}

func remove(node *AVLNode, key int) *AVLNode {
    if node == nil {
        return nil
    }
    if key < node.key {
        node.left = remove(node.left, key)
    } else if key > node.key {
        node.right = remove(node.right, key)
    } else {
        if node.left != nil && node.right != nil {
           // node to delete found with both children;
           // replace values with smallest node of the right sub-tree
           rightMinNode := findSmallest(node.right)
           node.key = rightMinNode.key
           node.value = rightMinNode.value
           // delete smallest node that we replaced
           //node.right = remove(node.right, rightMinNode.key)
           node.right = remove(node.right, rightMinNode.key)
        } else if node.left != nil {
           // node only has left child
           node = node.left
        } else if node.right != nil {
           // node only has right child
           node = node.right
        } else {
           // node has no children
           node = nil
           return node
        }

    }
    return rebalanceTree(node)
}

func findSmallest(node *AVLNode) *AVLNode {
    if node.left != nil {
        return findSmallest(node.left)
    } else {
        return node
    }
}

func displayTreeInOrder(node *AVLNode) {
    if node.left != nil {
        displayTreeInOrder(node.left)
    }
    fmt.Print(node.key, " ")
    if node.right != nil {
        displayTreeInOrder(node.right)
    }
}

<|endoftext|>


<commit_before>// Copyright 2015 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package rafthttp

import (
	"sync"
	"time"

	"github.com/coreos/etcd/etcdserver/stats"
	"github.com/coreos/etcd/pkg/types"
	"github.com/coreos/etcd/raft"
	"github.com/coreos/etcd/raft/raftpb"
	"github.com/coreos/etcd/snap"
	"golang.org/x/net/context"
)

const (
	// ConnReadTimeout and ConnWriteTimeout are the i/o timeout set on each connection rafthttp pkg creates.
	// A 5 seconds timeout is good enough for recycling bad connections. Or we have to wait for
	// tcp keepalive failing to detect a bad connection, which is at minutes level.
	// For long term streaming connections, rafthttp pkg sends application level linkHeartbeatMessage
	// to keep the connection alive.
	// For short term pipeline connections, the connection MUST be killed to avoid it being
	// put back to http pkg connection pool.
	ConnReadTimeout  = 5 * time.Second
	ConnWriteTimeout = 5 * time.Second

	recvBufSize = 4096
	// maxPendingProposals holds the proposals during one leader election process.
	// Generally one leader election takes at most 1 sec. It should have
	// 0-2 election conflicts, and each one takes 0.5 sec.
	// We assume the number of concurrent proposers is smaller than 4096.
	// One client blocks on its proposal for at least 1 sec, so 4096 is enough
	// to hold all proposals.
	maxPendingProposals = 4096

	streamAppV2 = "streamMsgAppV2"
	streamMsg   = "streamMsg"
	pipelineMsg = "pipeline"
	sendSnap    = "sendMsgSnap"
)

type Peer interface {
	// send sends the message to the remote peer. The function is non-blocking
	// and has no promise that the message will be received by the remote.
	// When it fails to send message out, it will report the status to underlying
	// raft.
	send(m raftpb.Message)

	// sendSnap sends the merged snapshot message to the remote peer. Its behavior
	// is similar to send.
	sendSnap(m snap.Message)

	// update updates the urls of remote peer.
	update(urls types.URLs)

	// attachOutgoingConn attaches the outgoing connection to the peer for
	// stream usage. After the call, the ownership of the outgoing
	// connection hands over to the peer. The peer will close the connection
	// when it is no longer used.
	attachOutgoingConn(conn *outgoingConn)
	// activeSince returns the time that the connection with the
	// peer becomes active.
	activeSince() time.Time
	// stop performs any necessary finalization and terminates the peer
	// elegantly.
	stop()
}

// peer is the representative of a remote raft node. Local raft node sends
// messages to the remote through peer.
// Each peer has two underlying mechanisms to send out a message: stream and
// pipeline.
// A stream is a receiver initialized long-polling connection, which
// is always open to transfer messages. Besides general stream, peer also has
// a optimized stream for sending msgApp since msgApp accounts for large part
// of all messages. Only raft leader uses the optimized stream to send msgApp
// to the remote follower node.
// A pipeline is a series of http clients that send http requests to the remote.
// It is only used when the stream has not been established.
type peer struct {
	// id of the remote raft peer node
	id types.ID
	r  Raft

	status *peerStatus

	picker *urlPicker

	msgAppV2Writer *streamWriter
	writer         *streamWriter
	pipeline       *pipeline
	snapSender     *snapshotSender // snapshot sender to send v3 snapshot messages
	msgAppV2Reader *streamReader
	msgAppReader   *streamReader

	sendc chan raftpb.Message
	recvc chan raftpb.Message
	propc chan raftpb.Message

	mu     sync.Mutex
	paused bool

	cancel context.CancelFunc // cancel pending works in go routine created by peer.
	stopc  chan struct{}
}

func startPeer(transport *Transport, urls types.URLs, local, to, cid types.ID, r Raft, fs *stats.FollowerStats, errorc chan error) *peer {
	status := newPeerStatus(to)
	picker := newURLPicker(urls)
	p := &peer{
		id:             to,
		r:              r,
		status:         status,
		picker:         picker,
		msgAppV2Writer: startStreamWriter(to, status, fs, r),
		writer:         startStreamWriter(to, status, fs, r),
		pipeline:       newPipeline(transport, picker, local, to, cid, status, fs, r, errorc),
		snapSender:     newSnapshotSender(transport, picker, local, to, cid, status, r, errorc),
		sendc:          make(chan raftpb.Message),
		recvc:          make(chan raftpb.Message, recvBufSize),
		propc:          make(chan raftpb.Message, maxPendingProposals),
		stopc:          make(chan struct{}),
	}

	ctx, cancel := context.WithCancel(context.Background())
	p.cancel = cancel
	go func() {
		for {
			select {
			case mm := <-p.propc:
				if err := r.Process(ctx, mm); err != nil {
					plog.Warningf("failed to process raft message (%v)", err)
				}
			case mm := <-p.recvc:
				if err := r.Process(ctx, mm); err != nil {
					plog.Warningf("failed to process raft message (%v)", err)
				}
			case <-p.stopc:
				return
			}
		}
	}()

	p.msgAppV2Reader = startStreamReader(transport, picker, streamTypeMsgAppV2, local, to, cid, status, p.recvc, p.propc, errorc)
	p.msgAppReader = startStreamReader(transport, picker, streamTypeMessage, local, to, cid, status, p.recvc, p.propc, errorc)

	return p
}

func (p *peer) send(m raftpb.Message) {
	p.mu.Lock()
	paused := p.paused
	p.mu.Unlock()

	if paused {
		return
	}

	writec, name := p.pick(m)
	select {
	case writec <- m:
	default:
		p.r.ReportUnreachable(m.To)
		if isMsgSnap(m) {
			p.r.ReportSnapshot(m.To, raft.SnapshotFailure)
		}
		if p.status.isActive() {
			plog.MergeWarningf("dropped internal raft message to %s since %s's sending buffer is full (bad/overloaded network)", p.id, name)
		}
		plog.Debugf("dropped %s to %s since %s's sending buffer is full", m.Type, p.id, name)
	}
}

func (p *peer) sendSnap(m snap.Message) {
	go p.snapSender.send(m)
}

func (p *peer) update(urls types.URLs) {
	p.picker.update(urls)
}

func (p *peer) attachOutgoingConn(conn *outgoingConn) {
	var ok bool
	switch conn.t {
	case streamTypeMsgAppV2:
		ok = p.msgAppV2Writer.attach(conn)
	case streamTypeMessage:
		ok = p.writer.attach(conn)
	default:
		plog.Panicf("unhandled stream type %s", conn.t)
	}
	if !ok {
		conn.Close()
	}
}

func (p *peer) activeSince() time.Time { return p.status.activeSince }

// Pause pauses the peer. The peer will simply drops all incoming
// messages without returning an error.
func (p *peer) Pause() {
	p.mu.Lock()
	defer p.mu.Unlock()
	p.paused = true
	p.msgAppReader.pause()
	p.msgAppV2Reader.pause()
}

// Resume resumes a paused peer.
func (p *peer) Resume() {
	p.mu.Lock()
	defer p.mu.Unlock()
	p.paused = false
	p.msgAppReader.resume()
	p.msgAppV2Reader.resume()
}

func (p *peer) stop() {
	close(p.stopc)
	p.cancel()
	p.msgAppV2Writer.stop()
	p.writer.stop()
	p.pipeline.stop()
	p.snapSender.stop()
	p.msgAppV2Reader.stop()
	p.msgAppReader.stop()
}

// pick picks a chan for sending the given message. The picked chan and the picked chan
// string name are returned.
func (p *peer) pick(m raftpb.Message) (writec chan<- raftpb.Message, picked string) {
	var ok bool
	// Considering MsgSnap may have a big size, e.g., 1G, and will block
	// stream for a long time, only use one of the N pipelines to send MsgSnap.
	if isMsgSnap(m) {
		return p.pipeline.msgc, pipelineMsg
	} else if writec, ok = p.msgAppV2Writer.writec(); ok && isMsgApp(m) {
		return writec, streamAppV2
	} else if writec, ok = p.writer.writec(); ok {
		return writec, streamMsg
	}
	return p.pipeline.msgc, pipelineMsg
}

func isMsgApp(m raftpb.Message) bool { return m.Type == raftpb.MsgApp }

func isMsgSnap(m raftpb.Message) bool { return m.Type == raftpb.MsgSnap }
<commit_msg>rafthttp: do not block on proposal<commit_after>// Copyright 2015 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package rafthttp

import (
	"sync"
	"time"

	"github.com/coreos/etcd/etcdserver/stats"
	"github.com/coreos/etcd/pkg/types"
	"github.com/coreos/etcd/raft"
	"github.com/coreos/etcd/raft/raftpb"
	"github.com/coreos/etcd/snap"
	"golang.org/x/net/context"
)

const (
	// ConnReadTimeout and ConnWriteTimeout are the i/o timeout set on each connection rafthttp pkg creates.
	// A 5 seconds timeout is good enough for recycling bad connections. Or we have to wait for
	// tcp keepalive failing to detect a bad connection, which is at minutes level.
	// For long term streaming connections, rafthttp pkg sends application level linkHeartbeatMessage
	// to keep the connection alive.
	// For short term pipeline connections, the connection MUST be killed to avoid it being
	// put back to http pkg connection pool.
	ConnReadTimeout  = 5 * time.Second
	ConnWriteTimeout = 5 * time.Second

	recvBufSize = 4096
	// maxPendingProposals holds the proposals during one leader election process.
	// Generally one leader election takes at most 1 sec. It should have
	// 0-2 election conflicts, and each one takes 0.5 sec.
	// We assume the number of concurrent proposers is smaller than 4096.
	// One client blocks on its proposal for at least 1 sec, so 4096 is enough
	// to hold all proposals.
	maxPendingProposals = 4096

	streamAppV2 = "streamMsgAppV2"
	streamMsg   = "streamMsg"
	pipelineMsg = "pipeline"
	sendSnap    = "sendMsgSnap"
)

type Peer interface {
	// send sends the message to the remote peer. The function is non-blocking
	// and has no promise that the message will be received by the remote.
	// When it fails to send message out, it will report the status to underlying
	// raft.
	send(m raftpb.Message)

	// sendSnap sends the merged snapshot message to the remote peer. Its behavior
	// is similar to send.
	sendSnap(m snap.Message)

	// update updates the urls of remote peer.
	update(urls types.URLs)

	// attachOutgoingConn attaches the outgoing connection to the peer for
	// stream usage. After the call, the ownership of the outgoing
	// connection hands over to the peer. The peer will close the connection
	// when it is no longer used.
	attachOutgoingConn(conn *outgoingConn)
	// activeSince returns the time that the connection with the
	// peer becomes active.
	activeSince() time.Time
	// stop performs any necessary finalization and terminates the peer
	// elegantly.
	stop()
}

// peer is the representative of a remote raft node. Local raft node sends
// messages to the remote through peer.
// Each peer has two underlying mechanisms to send out a message: stream and
// pipeline.
// A stream is a receiver initialized long-polling connection, which
// is always open to transfer messages. Besides general stream, peer also has
// a optimized stream for sending msgApp since msgApp accounts for large part
// of all messages. Only raft leader uses the optimized stream to send msgApp
// to the remote follower node.
// A pipeline is a series of http clients that send http requests to the remote.
// It is only used when the stream has not been established.
type peer struct {
	// id of the remote raft peer node
	id types.ID
	r  Raft

	status *peerStatus

	picker *urlPicker

	msgAppV2Writer *streamWriter
	writer         *streamWriter
	pipeline       *pipeline
	snapSender     *snapshotSender // snapshot sender to send v3 snapshot messages
	msgAppV2Reader *streamReader
	msgAppReader   *streamReader

	sendc chan raftpb.Message
	recvc chan raftpb.Message
	propc chan raftpb.Message

	mu     sync.Mutex
	paused bool

	cancel context.CancelFunc // cancel pending works in go routine created by peer.
	stopc  chan struct{}
}

func startPeer(transport *Transport, urls types.URLs, local, to, cid types.ID, r Raft, fs *stats.FollowerStats, errorc chan error) *peer {
	status := newPeerStatus(to)
	picker := newURLPicker(urls)
	p := &peer{
		id:             to,
		r:              r,
		status:         status,
		picker:         picker,
		msgAppV2Writer: startStreamWriter(to, status, fs, r),
		writer:         startStreamWriter(to, status, fs, r),
		pipeline:       newPipeline(transport, picker, local, to, cid, status, fs, r, errorc),
		snapSender:     newSnapshotSender(transport, picker, local, to, cid, status, r, errorc),
		sendc:          make(chan raftpb.Message),
		recvc:          make(chan raftpb.Message, recvBufSize),
		propc:          make(chan raftpb.Message, maxPendingProposals),
		stopc:          make(chan struct{}),
	}

	ctx, cancel := context.WithCancel(context.Background())
	p.cancel = cancel
	go func() {
		for {
			select {
			case mm := <-p.recvc:
				if err := r.Process(ctx, mm); err != nil {
					plog.Warningf("failed to process raft message (%v)", err)
				}
			case <-p.stopc:
				return
			}
		}
	}()

	// r.Process might block for processing proposal when there is no leader.
	// Thus propc must be put into a separate routine with recvc to avoid blocking
	// processing other raft messages.
	go func() {
		for {
			select {
			case mm := <-p.propc:
				if err := r.Process(ctx, mm); err != nil {
					plog.Warningf("failed to process raft message (%v)", err)
				}
			case <-p.stopc:
				return
			}
		}
	}()

	p.msgAppV2Reader = startStreamReader(transport, picker, streamTypeMsgAppV2, local, to, cid, status, p.recvc, p.propc, errorc)
	p.msgAppReader = startStreamReader(transport, picker, streamTypeMessage, local, to, cid, status, p.recvc, p.propc, errorc)

	return p
}

func (p *peer) send(m raftpb.Message) {
	p.mu.Lock()
	paused := p.paused
	p.mu.Unlock()

	if paused {
		return
	}

	writec, name := p.pick(m)
	select {
	case writec <- m:
	default:
		p.r.ReportUnreachable(m.To)
		if isMsgSnap(m) {
			p.r.ReportSnapshot(m.To, raft.SnapshotFailure)
		}
		if p.status.isActive() {
			plog.MergeWarningf("dropped internal raft message to %s since %s's sending buffer is full (bad/overloaded network)", p.id, name)
		}
		plog.Debugf("dropped %s to %s since %s's sending buffer is full", m.Type, p.id, name)
	}
}

func (p *peer) sendSnap(m snap.Message) {
	go p.snapSender.send(m)
}

func (p *peer) update(urls types.URLs) {
	p.picker.update(urls)
}

func (p *peer) attachOutgoingConn(conn *outgoingConn) {
	var ok bool
	switch conn.t {
	case streamTypeMsgAppV2:
		ok = p.msgAppV2Writer.attach(conn)
	case streamTypeMessage:
		ok = p.writer.attach(conn)
	default:
		plog.Panicf("unhandled stream type %s", conn.t)
	}
	if !ok {
		conn.Close()
	}
}

func (p *peer) activeSince() time.Time { return p.status.activeSince }

// Pause pauses the peer. The peer will simply drops all incoming
// messages without returning an error.
func (p *peer) Pause() {
	p.mu.Lock()
	defer p.mu.Unlock()
	p.paused = true
	p.msgAppReader.pause()
	p.msgAppV2Reader.pause()
}

// Resume resumes a paused peer.
func (p *peer) Resume() {
	p.mu.Lock()
	defer p.mu.Unlock()
	p.paused = false
	p.msgAppReader.resume()
	p.msgAppV2Reader.resume()
}

func (p *peer) stop() {
	close(p.stopc)
	p.cancel()
	p.msgAppV2Writer.stop()
	p.writer.stop()
	p.pipeline.stop()
	p.snapSender.stop()
	p.msgAppV2Reader.stop()
	p.msgAppReader.stop()
}

// pick picks a chan for sending the given message. The picked chan and the picked chan
// string name are returned.
func (p *peer) pick(m raftpb.Message) (writec chan<- raftpb.Message, picked string) {
	var ok bool
	// Considering MsgSnap may have a big size, e.g., 1G, and will block
	// stream for a long time, only use one of the N pipelines to send MsgSnap.
	if isMsgSnap(m) {
		return p.pipeline.msgc, pipelineMsg
	} else if writec, ok = p.msgAppV2Writer.writec(); ok && isMsgApp(m) {
		return writec, streamAppV2
	} else if writec, ok = p.writer.writec(); ok {
		return writec, streamMsg
	}
	return p.pipeline.msgc, pipelineMsg
}

func isMsgApp(m raftpb.Message) bool { return m.Type == raftpb.MsgApp }

func isMsgSnap(m raftpb.Message) bool { return m.Type == raftpb.MsgSnap }
<|endoftext|>


<commit_before>package openrtb_test

import (
	"encoding/json"

	"github.com/mxmCherry/openrtb"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("RawJSON", func() {

	var _ json.Marshaler = (openrtb.RawJSON)(nil)
	var _ json.Unmarshaler = (*openrtb.RawJSON)(nil)

	It("should encode JSON", func() {
		subject := openrtb.RawJSON(`true`)

		actual, err := subject.MarshalJSON()
		Expect(err).NotTo(HaveOccurred())
		Expect(actual).To(Equal([]byte(`true`)))
	})

	It("should decode JSON", func() {
		subject := openrtb.RawJSON(nil)

		err := subject.UnmarshalJSON([]byte(`true`))
		Expect(err).NotTo(HaveOccurred())
		Expect(subject).To(Equal(openrtb.RawJSON(`true`)))
	})

	It("should decode JSON when embedded into struct", func() {
		wrapper := struct {
			Raw openrtb.RawJSON `json:"raw"`
		}{
			Raw: nil,
		}

		err := json.Unmarshal([]byte(`{"raw":true}`), &wrapper)
		Expect(err).NotTo(HaveOccurred())
		Expect(wrapper.Raw).To(Equal(openrtb.RawJSON(`true`)))
	})

	It("should encode JSON when embedded into struct", func() {
		wrapper := struct {
			Raw openrtb.RawJSON `json:"raw"`
		}{
			Raw: openrtb.RawJSON(`true`),
		}

		actual, err := json.Marshal(wrapper)
		Expect(err).NotTo(HaveOccurred())
		Expect(actual).To(MatchJSON(`{"raw":true}`))
	})

})
<commit_msg>More test cosmetics<commit_after>package openrtb_test

import (
	"encoding/json"

	. "github.com/mxmCherry/openrtb"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("RawJSON", func() {

	var _ json.Marshaler = (RawJSON)(nil)
	var _ json.Unmarshaler = (*RawJSON)(nil)

	It("should encode JSON", func() {
		subject := RawJSON(`true`)

		actual, err := subject.MarshalJSON()
		Expect(err).NotTo(HaveOccurred())
		Expect(actual).To(Equal([]byte(`true`)))
	})

	It("should decode JSON", func() {
		subject := RawJSON(nil)

		err := subject.UnmarshalJSON([]byte(`true`))
		Expect(err).NotTo(HaveOccurred())
		Expect(subject).To(Equal(RawJSON(`true`)))
	})

	It("should decode JSON when embedded into struct", func() {
		wrapper := struct {
			Raw RawJSON `json:"raw"`
		}{
			Raw: nil,
		}

		err := json.Unmarshal([]byte(`{"raw":true}`), &wrapper)
		Expect(err).NotTo(HaveOccurred())
		Expect(wrapper.Raw).To(Equal(RawJSON(`true`)))
	})

	It("should encode JSON when embedded into struct", func() {
		wrapper := struct {
			Raw RawJSON `json:"raw"`
		}{
			Raw: RawJSON(`true`),
		}

		actual, err := json.Marshal(wrapper)
		Expect(err).NotTo(HaveOccurred())
		Expect(actual).To(MatchJSON(`{"raw":true}`))
	})

})
<|endoftext|>


<commit_before>package quic

import (
	"crypto/cipher"
	"crypto/rand"
	"errors"
	"time"

	quic "github.com/lucas-clemente/quic-go"
	"v2ray.com/core/common"
	"v2ray.com/core/common/buf"
	"v2ray.com/core/common/net"
	"v2ray.com/core/transport/internet"
)

type sysConn struct {
	conn   net.PacketConn
	header internet.PacketHeader
	auth   cipher.AEAD
}

func wrapSysConn(rawConn net.PacketConn, config *Config) (*sysConn, error) {
	header, err := getHeader(config)
	if err != nil {
		return nil, err
	}
	auth, err := getAuth(config)
	if err != nil {
		return nil, err
	}
	return &sysConn{
		conn:   rawConn,
		header: header,
		auth:   auth,
	}, nil
}

var errCipherError = errors.New("cipher error")

func (c *sysConn) readFromInternal(p []byte) (int, net.Addr, error) {
	buffer := getBuffer()
	defer putBuffer(buffer)

	nBytes, addr, err := c.conn.ReadFrom(buffer)
	if err != nil {
		return 0, nil, err
	}

	payload := buffer[:nBytes]
	if c.header != nil {
		payload = payload[c.header.Size():]
	}

	if c.auth == nil {
		n := copy(p, payload)
		return n, addr, nil
	}

	nonce := payload[:c.auth.NonceSize()]
	payload = payload[c.auth.NonceSize():]

	p, err = c.auth.Open(p[:0], nonce, payload, nil)
	if err != nil {
		return 0, nil, errCipherError
	}

	return len(p), addr, nil
}

func (c *sysConn) ReadFrom(p []byte) (int, net.Addr, error) {
	if c.header == nil && c.auth == nil {
		return c.conn.ReadFrom(p)
	}

	for {
		n, addr, err := c.readFromInternal(p)
		if err != nil && err != errCipherError {
			return 0, nil, err
		}
		if err == nil {
			return n, addr, nil
		}
	}
}

func (c *sysConn) WriteTo(p []byte, addr net.Addr) (int, error) {
	if c.header == nil && c.auth == nil {
		return c.conn.WriteTo(p, addr)
	}

	buffer := getBuffer()
	defer putBuffer(buffer)

	payload := buffer
	n := 0
	if c.header != nil {
		c.header.Serialize(payload)
		n = int(c.header.Size())
	}

	if c.auth == nil {
		nBytes := copy(payload[n:], p)
		n += nBytes
	} else {
		nounce := payload[n : n+c.auth.NonceSize()]
		common.Must2(rand.Read(nounce))
		n += c.auth.NonceSize()
		pp := c.auth.Seal(payload[:n], nounce, p, nil)
		n = len(pp)
	}

	return c.conn.WriteTo(payload[:n], addr)
}

func (c *sysConn) Close() error {
	return c.conn.Close()
}

func (c *sysConn) LocalAddr() net.Addr {
	return c.conn.LocalAddr()
}

func (c *sysConn) SetDeadline(t time.Time) error {
	return c.conn.SetDeadline(t)
}

func (c *sysConn) SetReadDeadline(t time.Time) error {
	return c.conn.SetReadDeadline(t)
}

func (c *sysConn) SetWriteDeadline(t time.Time) error {
	return c.conn.SetWriteDeadline(t)
}

type interConn struct {
	stream quic.Stream
	local  net.Addr
	remote net.Addr
}

func (c *interConn) Read(b []byte) (int, error) {
	return c.stream.Read(b)
}

func (c *interConn) WriteMultiBuffer(mb buf.MultiBuffer) error {
	if mb.IsEmpty() {
		return nil
	}

	if len(mb) == 1 {
		_, err := c.Write(mb[0].Bytes())
		buf.ReleaseMulti(mb)
		return err
	}

	b := getBuffer()
	defer putBuffer(b)

	reader := buf.MultiBufferContainer{
		MultiBuffer: mb,
	}
	defer reader.Close()

	for {
		nBytes, err := reader.Read(b[:1200])
		if err != nil {
			break
		}
		if nBytes == 0 {
			continue
		}
		if _, err := c.Write(b[:nBytes]); err != nil {
			return err
		}
	}

	return nil
}

func (c *interConn) Write(b []byte) (int, error) {
	return c.stream.Write(b)
}

func (c *interConn) Close() error {
	c.stream.CancelRead(1)
	c.stream.CancelWrite(1)
	return nil
}

func (c *interConn) LocalAddr() net.Addr {
	return c.local
}

func (c *interConn) RemoteAddr() net.Addr {
	return c.remote
}

func (c *interConn) SetDeadline(t time.Time) error {
	return c.stream.SetDeadline(t)
}

func (c *interConn) SetReadDeadline(t time.Time) error {
	return c.stream.SetReadDeadline(t)
}

func (c *interConn) SetWriteDeadline(t time.Time) error {
	return c.stream.SetWriteDeadline(t)
}
<commit_msg>close connection without error<commit_after>package quic

import (
	"crypto/cipher"
	"crypto/rand"
	"errors"
	"time"

	quic "github.com/lucas-clemente/quic-go"
	"v2ray.com/core/common"
	"v2ray.com/core/common/buf"
	"v2ray.com/core/common/net"
	"v2ray.com/core/transport/internet"
)

type sysConn struct {
	conn   net.PacketConn
	header internet.PacketHeader
	auth   cipher.AEAD
}

func wrapSysConn(rawConn net.PacketConn, config *Config) (*sysConn, error) {
	header, err := getHeader(config)
	if err != nil {
		return nil, err
	}
	auth, err := getAuth(config)
	if err != nil {
		return nil, err
	}
	return &sysConn{
		conn:   rawConn,
		header: header,
		auth:   auth,
	}, nil
}

var errCipherError = errors.New("cipher error")

func (c *sysConn) readFromInternal(p []byte) (int, net.Addr, error) {
	buffer := getBuffer()
	defer putBuffer(buffer)

	nBytes, addr, err := c.conn.ReadFrom(buffer)
	if err != nil {
		return 0, nil, err
	}

	payload := buffer[:nBytes]
	if c.header != nil {
		payload = payload[c.header.Size():]
	}

	if c.auth == nil {
		n := copy(p, payload)
		return n, addr, nil
	}

	nonce := payload[:c.auth.NonceSize()]
	payload = payload[c.auth.NonceSize():]

	p, err = c.auth.Open(p[:0], nonce, payload, nil)
	if err != nil {
		return 0, nil, errCipherError
	}

	return len(p), addr, nil
}

func (c *sysConn) ReadFrom(p []byte) (int, net.Addr, error) {
	if c.header == nil && c.auth == nil {
		return c.conn.ReadFrom(p)
	}

	for {
		n, addr, err := c.readFromInternal(p)
		if err != nil && err != errCipherError {
			return 0, nil, err
		}
		if err == nil {
			return n, addr, nil
		}
	}
}

func (c *sysConn) WriteTo(p []byte, addr net.Addr) (int, error) {
	if c.header == nil && c.auth == nil {
		return c.conn.WriteTo(p, addr)
	}

	buffer := getBuffer()
	defer putBuffer(buffer)

	payload := buffer
	n := 0
	if c.header != nil {
		c.header.Serialize(payload)
		n = int(c.header.Size())
	}

	if c.auth == nil {
		nBytes := copy(payload[n:], p)
		n += nBytes
	} else {
		nounce := payload[n : n+c.auth.NonceSize()]
		common.Must2(rand.Read(nounce))
		n += c.auth.NonceSize()
		pp := c.auth.Seal(payload[:n], nounce, p, nil)
		n = len(pp)
	}

	return c.conn.WriteTo(payload[:n], addr)
}

func (c *sysConn) Close() error {
	return c.conn.Close()
}

func (c *sysConn) LocalAddr() net.Addr {
	return c.conn.LocalAddr()
}

func (c *sysConn) SetDeadline(t time.Time) error {
	return c.conn.SetDeadline(t)
}

func (c *sysConn) SetReadDeadline(t time.Time) error {
	return c.conn.SetReadDeadline(t)
}

func (c *sysConn) SetWriteDeadline(t time.Time) error {
	return c.conn.SetWriteDeadline(t)
}

type interConn struct {
	stream quic.Stream
	local  net.Addr
	remote net.Addr
}

func (c *interConn) Read(b []byte) (int, error) {
	return c.stream.Read(b)
}

func (c *interConn) WriteMultiBuffer(mb buf.MultiBuffer) error {
	if mb.IsEmpty() {
		return nil
	}

	if len(mb) == 1 {
		_, err := c.Write(mb[0].Bytes())
		buf.ReleaseMulti(mb)
		return err
	}

	b := getBuffer()
	defer putBuffer(b)

	reader := buf.MultiBufferContainer{
		MultiBuffer: mb,
	}
	defer reader.Close()

	for {
		nBytes, err := reader.Read(b[:1200])
		if err != nil {
			break
		}
		if nBytes == 0 {
			continue
		}
		if _, err := c.Write(b[:nBytes]); err != nil {
			return err
		}
	}

	return nil
}

func (c *interConn) Write(b []byte) (int, error) {
	return c.stream.Write(b)
}

func (c *interConn) Close() error {
	c.stream.CancelRead(0x00)
	return c.stream.Close()
}

func (c *interConn) LocalAddr() net.Addr {
	return c.local
}

func (c *interConn) RemoteAddr() net.Addr {
	return c.remote
}

func (c *interConn) SetDeadline(t time.Time) error {
	return c.stream.SetDeadline(t)
}

func (c *interConn) SetReadDeadline(t time.Time) error {
	return c.stream.SetReadDeadline(t)
}

func (c *interConn) SetWriteDeadline(t time.Time) error {
	return c.stream.SetWriteDeadline(t)
}
<|endoftext|>