<commit_before>// Copyright 2015 Dorival de Moraes Pedroso. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package goga

import (
	"github.com/cpmech/gosl/chk"
	"github.com/cpmech/gosl/graph"
	"github.com/cpmech/gosl/io"
	"github.com/cpmech/gosl/la"
	"github.com/cpmech/gosl/plt"
	"github.com/cpmech/gosl/rnd"
	"github.com/cpmech/gosl/utl"
)

// Evolver realises the evolutionary process
type Evolver struct {

	// data
	C       *ConfParams // configuration parameters
	Islands []*Island   // islands
	Best    *Individual // best individual among all in all islands

	// callbacks
	OutFcn func(t int, evo *Evolver) // output function callback

	// migration
	OvaMin []float64     // min ova
	OvaMax []float64     // max ova
	Mdist  [][]float64   // match distances
	Match  graph.Munkres // matches
}

// NewEvolverPop creates a new evolver based on given populations
func NewEvolver(C *ConfParams) (o *Evolver) {

	// check input
	C.check_input()

	// data
	o = new(Evolver)
	o.C = C
	o.Islands = make([]*Island, o.C.Nisl)
	if o.C.Pll {
		done := make(chan int, o.C.Nisl)
		for i := 0; i < o.C.Nisl; i++ {
			go func(idx int) {
				o.Islands[idx] = NewIsland(idx, o.C)
				done <- 1
			}(i)
		}
		for i := 0; i < o.C.Nisl; i++ {
			<-done
		}
	} else {
		for i := 0; i < o.C.Nisl; i++ {
			o.Islands[i] = NewIsland(i, o.C)
		}
	}
	o.Best = o.Islands[0].Pop[0]

	// migration
	o.OvaMin = make([]float64, o.C.Nova)
	o.OvaMax = make([]float64, o.C.Nova)
	o.Mdist = la.MatAlloc(o.C.Nimig, o.C.Nimig)
	o.Match.Init(o.C.Nimig, o.C.Nimig)
	return
}

// Run runs the evolution process
func (o *Evolver) Run() {

	// check
	if o.C.Nisl < 1 {
		return
	}
	if o.C.Ninds < o.C.Nisl {
		chk.Panic("number of individuals must be greater than the number of islands")
	}

	// first output
	t := 0
	for _, isl := range o.Islands {
		isl.WritePopToReport(t, 0)
	}
	if o.C.Verbose {
		o.print_legend()
		io.Pf("\nrunning ...\n")
	}
	if o.C.PostProc != nil {
		for _, isl := range o.Islands {
			o.C.PostProc(isl.Id, 0, isl.Pop)
		}
	}

	// time loop
	t = 1
	tmig := o.C.Dtmig
	nomig := false
	if tmig > o.C.Tf {
		tmig = o.C.Tf
		nomig = true
	}
	done := make(chan int, o.C.Nisl)
	for t < o.C.Tf {

		// evolve up to migration time
		if o.C.Pll {
			for i := 0; i < o.C.Nisl; i++ {
				go func(isl *Island) {
					for time := t; time < tmig; time++ {
						report := o.calc_report(time)
						isl.Run(time, report, (o.C.Verbose && isl.Id == 0))
						if o.C.Verbose && isl.Id == 0 {
							o.print_time(time, report)
						}
					}
					Metrics(isl.OvaMin, isl.OvaMax, isl.Fsizes, isl.Fronts, isl.Pop)
					done <- 1
				}(o.Islands[i])
			}
			for i := 0; i < o.C.Nisl; i++ {
				<-done
			}
		} else {
			for _, isl := range o.Islands {
				for time := t; time < tmig; time++ {
					report := o.calc_report(time)
					isl.Run(time, report, (o.C.Verbose && isl.Id == 0))
					if o.C.Verbose && isl.Id == 0 {
						o.print_time(time, report)
					}
				}
			}
		}

		// update time
		t = tmig
		tmig += o.C.Dtmig
		if tmig > o.C.Tf {
			tmig = o.C.Tf
			nomig = true
		}

		// output
		if o.OutFcn != nil {
			o.OutFcn(t, o)
		}

		// skip migration
		if nomig {
			continue
		}

		// migration
		if o.C.Verbose {
			io.Pfyel(" %d", t)
		}
		o.migration(t)
	}

	// best individual
	o.FindBestFromAll()

	// message
	if o.C.Verbose {
		io.Pf("\n... end\n\n")
	}

	// write reports
	if o.C.DoReport {
		for _, isl := range o.Islands {
			isl.SaveReport(true)
		}
	}
	return
}

// FindBestFromAll finds best individual from all islands
//  Output: o.Best will point to the best individual
func (o *Evolver) FindBestFromAll() {
	if len(o.Islands) < 1 {
		return
	}
	o.Best = o.Islands[0].Pop[0]
	for i := 1; i < o.C.Nisl; i++ {
		_, other_is_better := IndCompareDet(o.Best, o.Islands[i].Pop[0])
		if other_is_better {
			o.Best = o.Islands[i].Pop[0]
		}
	}
}

// GetFeasible returns all feasible individuals from all islands
func (o *Evolver) GetFeasible() (feasible []*Individual) {
	for _, isl := range o.Islands {
		for _, ind := range isl.Pop {
			unfeasible := false
			for _, oor := range ind.Oors {
				if oor > 0 {
					unfeasible = true
				}
			}
			if !unfeasible {
				feasible = append(feasible, ind)
			}
		}
	}
	return
}

// GetResults returns all ovas and oors from a subset of individuals
//  Output:
//   ovas -- [len(subset)][nova] objective values
//   oors -- [len(subset)][noor] out-of-range values
func (o *Evolver) GetResults(subset []*Individual) (ovas, oors [][]float64) {
	ninds := len(subset)
	ovas = utl.DblsAlloc(ninds, o.C.Nova)
	oors = utl.DblsAlloc(ninds, o.C.Noor)
	for i, ind := range subset {
		for j := 0; j < o.C.Nova; j++ {
			ovas[i][j] = ind.Ovas[j]
		}
		for j := 0; j < o.C.Noor; j++ {
			oors[i][j] = ind.Oors[j]
		}
	}
	return
}

// GetParetoFront returns all feasible individuals on the Pareto front
// Note: input data can be obtained from GetFeasible and GetResults
func (o *Evolver) GetParetoFront(feasible []*Individual, ovas, oors [][]float64) (ovafront, oorfront []*Individual) {
	chk.IntAssert(len(feasible), len(ovas))
	ovaf := utl.ParetoFront(ovas)
	ovafront = make([]*Individual, len(ovaf))
	for i, id := range ovaf {
		ovafront[i] = feasible[id]
	}
	if len(oors) > 0 {
		chk.IntAssert(len(feasible), len(oors))
		oorf := utl.ParetoFront(oors)
		oorfront = make([]*Individual, len(oorf))
		for i, id := range oorf {
			oorfront[i] = feasible[id]
		}
	}
	return
}

// GetFrontOvas collects 2 ova results from Pareto front
//  Input:
//   r and s -- 2 selected objective functions; e.g. r=0 and s=1 for 2D problems
func (o *Evolver) GetFrontOvas(r, s int, front []*Individual) (x, y []float64) {
	x = make([]float64, len(front))
	y = make([]float64, len(front))
	for i, ind := range front {
		x[i] = ind.Ovas[r]
		y[i] = ind.Ovas[s]
	}
	return
}

// GetPopulations returns all populations from all islands
func (o *Evolver) GetPopulations() (pops []Population) {
	pops = make([]Population, o.C.Nisl)
	for i, isl := range o.Islands {
		pops[i] = isl.Pop.GetCopy()
	}
	return
}

// PlotPareto plots pareto front for i and j objectives
func (o *Evolver) PlotPareto(i, j int) {
	feasible := o.GetFeasible()
	ovas, _ := o.GetResults(feasible)
	ovafront, _ := o.GetParetoFront(feasible, ovas, nil)
	f0front, f1front := o.GetFrontOvas(i, j, ovafront)
	f0fin := utl.DblsGetColumn(i, ovas)
	f1fin := utl.DblsGetColumn(j, ovas)
	plt.Plot(f0fin, f1fin, "'r.', clip_on=0, ms=3")
	plt.Plot(f0front, f1front, "'ko',markerfacecolor='none',ms=4, clip_on=0")
}

// GetNfeval returns the number of evaluations
func (o *Evolver) GetNfeval() (nfeval int) {
	for _, isl := range o.Islands {
		nfeval += isl.Nfeval
	}
	return
}

// auxiliary //////////////////////////////////////////////////////////////////////////////////////

func (o *Evolver) migration_(t int) {
	for i := 0; i < o.C.Nisl; i++ {
		for j := i + 1; j < o.C.Nisl; j++ {
			selA := rnd.IntGetUniqueN(0, o.C.Ninds, o.C.Nimig)
			selB := rnd.IntGetUniqueN(0, o.C.Ninds, o.C.Nimig)
			for _, m := range selA {
				A := o.Islands[i].Pop[m]
				for _, n := range selB {
					B := o.Islands[j].Pop[n]
					if A.Fight(B) {
						A.CopyInto(B)
					} else {
						B.CopyInto(A)
					}
				}
			}
		}
	}
}

func (o *Evolver) migration(t int) {

	// compute metrics in each island and compute global ova range
	for i, isl := range o.Islands {
		isl.Pop.SortByRank()
		if i == 0 {
			for j := 0; j < o.C.Nova; j++ {
				o.OvaMin[j] = isl.OvaMin[j]
				o.OvaMax[j] = isl.OvaMax[j]
			}
		} else {
			for j := 0; j < o.C.Nova; j++ {
				o.OvaMin[j] = utl.Min(o.OvaMin[j], isl.OvaMin[j])
				o.OvaMax[j] = utl.Max(o.OvaMax[j], isl.OvaMax[j])
			}
		}
	}

	// loop over pair of islands
	l := o.C.Ninds - o.C.Nimig
	for I := 0; I < o.C.Nisl; I++ {
		Pbest := o.Islands[I].Pop[:o.C.Nimig]
		Pwors := o.Islands[I].Pop[l:]
		for J := I + 1; J < o.C.Nisl; J++ {
			Qbest := o.Islands[J].Pop[:o.C.Nimig]
			Qwors := o.Islands[J].Pop[l:]

			// compute match distances
			for i := 0; i < o.C.Nimig; i++ {
				A := Pbest[i]
				for j := 0; j < o.C.Nimig; j++ {
					B := Qbest[j]
					o.Mdist[i][j] = IndDistance(A, B, o.OvaMin, o.OvaMax)
				}
			}

			// match competitors
			o.Match.SetCostMatrix(o.Mdist)
			o.Match.Run()

			// matches
			for i := 0; i < o.C.Nimig; i++ {
				A := Pbest[i]
				B := Qbest[o.Match.Links[i]]
				if A.Fight(B) {
					A.CopyInto(Qwors[i])
				} else {
					B.CopyInto(Pwors[i])
				}
			}
		}
	}
}

func (o Evolver) calc_report(t int) bool {
	return t%o.C.Dtout == 0
}

func (o Evolver) print_legend() {
	io.Pf("\nLEGEND\n")
	io.Pfgrey(" 00 -- generation number (time)\n")
	io.Pfblue(" 00 -- reporting time\n")
	io.Pfyel(" 00 -- migration time\n")
}

func (o Evolver) print_time(time int, report bool) {
	io.Pf(" ")
	if report {
		io.Pfblue("%v", time)
		return
	}
	io.Pfgrey("%v", time)
}
<commit_msg>another mig method added (not working)<commit_after>// Copyright 2015 Dorival de Moraes Pedroso. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package goga

import (
	"github.com/cpmech/gosl/chk"
	"github.com/cpmech/gosl/graph"
	"github.com/cpmech/gosl/io"
	"github.com/cpmech/gosl/la"
	"github.com/cpmech/gosl/plt"
	"github.com/cpmech/gosl/rnd"
	"github.com/cpmech/gosl/utl"
)

// Evolver realises the evolutionary process
type Evolver struct {

	// data
	C       *ConfParams // configuration parameters
	Islands []*Island   // islands
	Best    *Individual // best individual among all in all islands

	// callbacks
	OutFcn func(t int, evo *Evolver) // output function callback

	// migration
	OvaMin []float64     // min ova
	OvaMax []float64     // max ova
	Mdist  [][]float64   // match distances
	Match  graph.Munkres // matches
}

// NewEvolverPop creates a new evolver based on given populations
func NewEvolver(C *ConfParams) (o *Evolver) {

	// check input
	C.check_input()

	// data
	o = new(Evolver)
	o.C = C
	o.Islands = make([]*Island, o.C.Nisl)
	if o.C.Pll {
		done := make(chan int, o.C.Nisl)
		for i := 0; i < o.C.Nisl; i++ {
			go func(idx int) {
				o.Islands[idx] = NewIsland(idx, o.C)
				done <- 1
			}(i)
		}
		for i := 0; i < o.C.Nisl; i++ {
			<-done
		}
	} else {
		for i := 0; i < o.C.Nisl; i++ {
			o.Islands[i] = NewIsland(i, o.C)
		}
	}
	o.Best = o.Islands[0].Pop[0]

	// migration
	o.OvaMin = make([]float64, o.C.Nova)
	o.OvaMax = make([]float64, o.C.Nova)
	o.Mdist = la.MatAlloc(o.C.Nimig, o.C.Nimig)
	o.Match.Init(o.C.Nimig, o.C.Nimig)
	return
}

// Run runs the evolution process
func (o *Evolver) Run() {

	// check
	if o.C.Nisl < 1 {
		return
	}
	if o.C.Ninds < o.C.Nisl {
		chk.Panic("number of individuals must be greater than the number of islands")
	}

	// first output
	t := 0
	for _, isl := range o.Islands {
		isl.WritePopToReport(t, 0)
	}
	if o.C.Verbose {
		o.print_legend()
		io.Pf("\nrunning ...\n")
	}
	if o.C.PostProc != nil {
		for _, isl := range o.Islands {
			o.C.PostProc(isl.Id, 0, isl.Pop)
		}
	}

	// time loop
	t = 1
	tmig := o.C.Dtmig
	nomig := false
	if tmig > o.C.Tf {
		tmig = o.C.Tf
		nomig = true
	}
	done := make(chan int, o.C.Nisl)
	for t < o.C.Tf {

		// evolve up to migration time
		if o.C.Pll {
			for i := 0; i < o.C.Nisl; i++ {
				go func(isl *Island) {
					for time := t; time < tmig; time++ {
						report := o.calc_report(time)
						isl.Run(time, report, (o.C.Verbose && isl.Id == 0))
						if o.C.Verbose && isl.Id == 0 {
							o.print_time(time, report)
						}
					}
					Metrics(isl.OvaMin, isl.OvaMax, isl.Fsizes, isl.Fronts, isl.Pop)
					done <- 1
				}(o.Islands[i])
			}
			for i := 0; i < o.C.Nisl; i++ {
				<-done
			}
		} else {
			for _, isl := range o.Islands {
				for time := t; time < tmig; time++ {
					report := o.calc_report(time)
					isl.Run(time, report, (o.C.Verbose && isl.Id == 0))
					if o.C.Verbose && isl.Id == 0 {
						o.print_time(time, report)
					}
				}
			}
		}

		// update time
		t = tmig
		tmig += o.C.Dtmig
		if tmig > o.C.Tf {
			tmig = o.C.Tf
			nomig = true
		}

		// output
		if o.OutFcn != nil {
			o.OutFcn(t, o)
		}

		// skip migration
		if nomig {
			continue
		}

		// migration
		if o.C.Verbose {
			io.Pfyel(" %d", t)
		}
		o.migration(t)
	}

	// best individual
	o.FindBestFromAll()

	// message
	if o.C.Verbose {
		io.Pf("\n... end\n\n")
	}

	// write reports
	if o.C.DoReport {
		for _, isl := range o.Islands {
			isl.SaveReport(true)
		}
	}
	return
}

// FindBestFromAll finds best individual from all islands
//  Output: o.Best will point to the best individual
func (o *Evolver) FindBestFromAll() {
	if len(o.Islands) < 1 {
		return
	}
	o.Best = o.Islands[0].Pop[0]
	for i := 1; i < o.C.Nisl; i++ {
		_, other_is_better := IndCompareDet(o.Best, o.Islands[i].Pop[0])
		if other_is_better {
			o.Best = o.Islands[i].Pop[0]
		}
	}
}

// GetFeasible returns all feasible individuals from all islands
func (o *Evolver) GetFeasible() (feasible []*Individual) {
	for _, isl := range o.Islands {
		for _, ind := range isl.Pop {
			unfeasible := false
			for _, oor := range ind.Oors {
				if oor > 0 {
					unfeasible = true
				}
			}
			if !unfeasible {
				feasible = append(feasible, ind)
			}
		}
	}
	return
}

// GetResults returns all ovas and oors from a subset of individuals
//  Output:
//   ovas -- [len(subset)][nova] objective values
//   oors -- [len(subset)][noor] out-of-range values
func (o *Evolver) GetResults(subset []*Individual) (ovas, oors [][]float64) {
	ninds := len(subset)
	ovas = utl.DblsAlloc(ninds, o.C.Nova)
	oors = utl.DblsAlloc(ninds, o.C.Noor)
	for i, ind := range subset {
		for j := 0; j < o.C.Nova; j++ {
			ovas[i][j] = ind.Ovas[j]
		}
		for j := 0; j < o.C.Noor; j++ {
			oors[i][j] = ind.Oors[j]
		}
	}
	return
}

// GetParetoFront returns all feasible individuals on the Pareto front
// Note: input data can be obtained from GetFeasible and GetResults
func (o *Evolver) GetParetoFront(feasible []*Individual, ovas, oors [][]float64) (ovafront, oorfront []*Individual) {
	chk.IntAssert(len(feasible), len(ovas))
	ovaf := utl.ParetoFront(ovas)
	ovafront = make([]*Individual, len(ovaf))
	for i, id := range ovaf {
		ovafront[i] = feasible[id]
	}
	if len(oors) > 0 {
		chk.IntAssert(len(feasible), len(oors))
		oorf := utl.ParetoFront(oors)
		oorfront = make([]*Individual, len(oorf))
		for i, id := range oorf {
			oorfront[i] = feasible[id]
		}
	}
	return
}

// GetFrontOvas collects 2 ova results from Pareto front
//  Input:
//   r and s -- 2 selected objective functions; e.g. r=0 and s=1 for 2D problems
func (o *Evolver) GetFrontOvas(r, s int, front []*Individual) (x, y []float64) {
	x = make([]float64, len(front))
	y = make([]float64, len(front))
	for i, ind := range front {
		x[i] = ind.Ovas[r]
		y[i] = ind.Ovas[s]
	}
	return
}

// GetPopulations returns all populations from all islands
func (o *Evolver) GetPopulations() (pops []Population) {
	pops = make([]Population, o.C.Nisl)
	for i, isl := range o.Islands {
		pops[i] = isl.Pop.GetCopy()
	}
	return
}

// PlotPareto plots pareto front for i and j objectives
func (o *Evolver) PlotPareto(i, j int) {
	feasible := o.GetFeasible()
	ovas, _ := o.GetResults(feasible)
	ovafront, _ := o.GetParetoFront(feasible, ovas, nil)
	f0front, f1front := o.GetFrontOvas(i, j, ovafront)
	f0fin := utl.DblsGetColumn(i, ovas)
	f1fin := utl.DblsGetColumn(j, ovas)
	plt.Plot(f0fin, f1fin, "'r.', clip_on=0, ms=3")
	plt.Plot(f0front, f1front, "'ko',markerfacecolor='none',ms=4, clip_on=0")
}

// GetNfeval returns the number of evaluations
func (o *Evolver) GetNfeval() (nfeval int) {
	for _, isl := range o.Islands {
		nfeval += isl.Nfeval
	}
	return
}

// auxiliary //////////////////////////////////////////////////////////////////////////////////////

func (o *Evolver) migration_(t int) {
	for i := 0; i < o.C.Nisl; i++ {
		for j := i + 1; j < o.C.Nisl; j++ {
			selA := rnd.IntGetUniqueN(0, o.C.Ninds, o.C.Nimig)
			selB := rnd.IntGetUniqueN(0, o.C.Ninds, o.C.Nimig)
			for _, m := range selA {
				A := o.Islands[i].Pop[m]
				for _, n := range selB {
					B := o.Islands[j].Pop[n]
					if A.Fight(B) {
						A.CopyInto(B)
					} else {
						B.CopyInto(A)
					}
				}
			}
		}
	}
}

func (o *Evolver) migration__(t int) {
	B_cpy := o.Islands[0].Pop[0].GetCopy()
	count := make([]int, o.C.Nisl)
	l := o.C.Ninds - o.C.Nimig
	for m := 0; m < o.C.Nimig; m++ {
		for i := 0; i < o.C.Nisl; i++ {
			I := count[i]
			if I >= l {
				continue
			}
			A := o.Islands[i].Pop[I]
			for j := i + 1; j < o.C.Nisl; j++ {
				J := count[j]
				if J >= l {
					continue
				}
				B := o.Islands[j].Pop[J]
				B.CopyInto(B_cpy)
				A.CopyInto(B)
				B_cpy.CopyInto(A)
				count[i]++
				count[j]++
			}
		}
	}
}

func (o *Evolver) migration(t int) {

	// compute metrics in each island and compute global ova range
	for i, isl := range o.Islands {
		isl.Pop.SortByRank()
		if i == 0 {
			for j := 0; j < o.C.Nova; j++ {
				o.OvaMin[j] = isl.OvaMin[j]
				o.OvaMax[j] = isl.OvaMax[j]
			}
		} else {
			for j := 0; j < o.C.Nova; j++ {
				o.OvaMin[j] = utl.Min(o.OvaMin[j], isl.OvaMin[j])
				o.OvaMax[j] = utl.Max(o.OvaMax[j], isl.OvaMax[j])
			}
		}
	}

	// loop over pair of islands
	l := o.C.Ninds - o.C.Nimig
	for I := 0; I < o.C.Nisl; I++ {
		Pbest := o.Islands[I].Pop[:o.C.Nimig]
		Pwors := o.Islands[I].Pop[l:]
		for J := I + 1; J < o.C.Nisl; J++ {
			Qbest := o.Islands[J].Pop[:o.C.Nimig]
			Qwors := o.Islands[J].Pop[l:]

			// compute match distances
			for i := 0; i < o.C.Nimig; i++ {
				A := Pbest[i]
				for j := 0; j < o.C.Nimig; j++ {
					B := Qbest[j]
					o.Mdist[i][j] = IndDistance(A, B, o.OvaMin, o.OvaMax)
				}
			}

			// match competitors
			o.Match.SetCostMatrix(o.Mdist)
			o.Match.Run()

			// matches
			for i := 0; i < o.C.Nimig; i++ {
				A := Pbest[i]
				B := Qbest[o.Match.Links[i]]
				if A.Fight(B) {
					A.CopyInto(Qwors[i])
				} else {
					B.CopyInto(Pwors[i])
				}
			}
		}
	}
}

func (o Evolver) calc_report(t int) bool {
	return t%o.C.Dtout == 0
}

func (o Evolver) print_legend() {
	io.Pf("\nLEGEND\n")
	io.Pfgrey(" 00 -- generation number (time)\n")
	io.Pfblue(" 00 -- reporting time\n")
	io.Pfyel(" 00 -- migration time\n")
}

func (o Evolver) print_time(time int, report bool) {
	io.Pf(" ")
	if report {
		io.Pfblue("%v", time)
		return
	}
	io.Pfgrey("%v", time)
}
<|endoftext|>


<commit_before>// TODO: it would be nice to move these into the top level folder so people can use these with the "functions" package, eg: functions.AddMiddleware(...)
package server

import (
	"context"
	"net/http"

	"github.com/Sirupsen/logrus"
	"github.com/gin-gonic/gin"
	"gitlab-odx.oracle.com/odx/functions/api/models"
)

// Middleware is the interface required for implementing functions middlewar
type Middleware interface {
	// Serve is what the Middleware must implement. Can modify the request, write output, etc.
	// todo: should we abstract the HTTP out of this?  In case we want to support other protocols.
	Serve(ctx MiddlewareContext, w http.ResponseWriter, r *http.Request, app *models.App) error
}

// MiddlewareFunc func form of Middleware
type MiddlewareFunc func(ctx MiddlewareContext, w http.ResponseWriter, r *http.Request, app *models.App) error

// Serve wrapper
func (f MiddlewareFunc) Serve(ctx MiddlewareContext, w http.ResponseWriter, r *http.Request, app *models.App) error {
	return f(ctx, w, r, app)
}

// MiddlewareContext extends context.Context for Middleware
type MiddlewareContext interface {
	context.Context
	// Middleware can call Next() explicitly to call the next middleware in the chain. If Next() is not called and an error is not returned, Next() will automatically be called.
	Next()
	// Index returns the index of where we're at in the chain
	Index() int
}

type middlewareContextImpl struct {
	context.Context

	ginContext  *gin.Context
	nextCalled  bool
	index       int
	middlewares []Middleware
}

// Set is used to store a new key/value pair exclusively for this context.
// This is different than WithValue(), as it does not make a copy of the context with the new value, it will be available up the chain as well.
func (c *middlewareContextImpl) Set(key string, value interface{}) {
	c.ginContext.Set(key, value)
}

// Get returns the value for the given key, ie: (value, true).
// If the value does not exists it returns (nil, false)
func (c *middlewareContextImpl) Get(key string) (value interface{}, exists bool) {
	return c.ginContext.Get(key)
}

// MustGet returns the value for the given key if it exists, otherwise it panics.
func (c *middlewareContextImpl) MustGet(key string) interface{} {
	return c.ginContext.MustGet(key)
}

func (c *middlewareContextImpl) Next() {
	c.nextCalled = true
	c.index++
	c.serveNext()
}

func (c *middlewareContextImpl) serveNext() {
	if c.Index() >= len(c.middlewares) {
		return
	}
	// make shallow copy:
	fctx2 := *c
	fctx2.nextCalled = false
	r := c.ginContext.Request.WithContext(fctx2)
	err := c.middlewares[c.Index()].Serve(&fctx2, c.ginContext.Writer, r, nil)
	if err != nil {
		logrus.WithError(err).Warnln("Middleware error")
		// todo: might be a good idea to check if anything is written yet, and if not, output the error: simpleError(err)
		// see: http://stackoverflow.com/questions/39415827/golang-http-check-if-responsewriter-has-been-written
		c.ginContext.Abort()
		return
	}
	if !fctx2.nextCalled {
		// then we automatically call next
		fctx2.Next()
	}

}

func (c *middlewareContextImpl) Index() int {
	return c.index
}

func (s *Server) middlewareWrapperFunc(ctx context.Context) gin.HandlerFunc {
	return func(c *gin.Context) {
		if len(s.middlewares) == 0 {
			return
		}
		ctx = c.MustGet("ctx").(context.Context)
		fctx := &middlewareContextImpl{Context: ctx}
		// add this context to gin context so we can grab it later
		c.Set("mctx", fctx)
		fctx.index = -1
		fctx.ginContext = c
		fctx.middlewares = s.middlewares
		// start the chain:
		fctx.Next()
	}
}

// AddMiddleware add middleware
func (s *Server) AddMiddleware(m Middleware) {
	s.middlewares = append(s.middlewares, m)
}

// AddMiddlewareFunc adds middleware function
func (s *Server) AddMiddlewareFunc(m func(ctx MiddlewareContext, w http.ResponseWriter, r *http.Request, app *models.App) error) {
	s.AddMiddleware(MiddlewareFunc(m))
}
<commit_msg>Added functions to MiddlewareContext interface<commit_after>// TODO: it would be nice to move these into the top level folder so people can use these with the "functions" package, eg: functions.AddMiddleware(...)
package server

import (
	"context"
	"net/http"

	"github.com/Sirupsen/logrus"
	"github.com/gin-gonic/gin"
	"gitlab-odx.oracle.com/odx/functions/api/models"
)

// Middleware is the interface required for implementing functions middlewar
type Middleware interface {
	// Serve is what the Middleware must implement. Can modify the request, write output, etc.
	// todo: should we abstract the HTTP out of this?  In case we want to support other protocols.
	Serve(ctx MiddlewareContext, w http.ResponseWriter, r *http.Request, app *models.App) error
}

// MiddlewareFunc func form of Middleware
type MiddlewareFunc func(ctx MiddlewareContext, w http.ResponseWriter, r *http.Request, app *models.App) error

// Serve wrapper
func (f MiddlewareFunc) Serve(ctx MiddlewareContext, w http.ResponseWriter, r *http.Request, app *models.App) error {
	return f(ctx, w, r, app)
}

// MiddlewareContext extends context.Context for Middleware
type MiddlewareContext interface {
	context.Context

	// Set is used to store a new key/value pair exclusively for this context.
	// This is different than WithValue(), as it does not make a copy of the context with the new value, it will be available up the chain as well.
	Set(key string, value interface{})

	// Get returns the value for the given key, ie: (value, true).
	// If the value does not exists it returns (nil, false)
	Get(key string) (value interface{}, exists bool)

	// MustGet returns the value for the given key if it exists, otherwise it panics.
	MustGet(key string) interface{}

	// Middleware can call Next() explicitly to call the next middleware in the chain. If Next() is not called and an error is not returned, Next() will automatically be called.
	Next()
	// Index returns the index of where we're at in the chain
	Index() int
}

type middlewareContextImpl struct {
	context.Context

	ginContext  *gin.Context
	nextCalled  bool
	index       int
	middlewares []Middleware
}

// Set is used to store a new key/value pair exclusively for this context.
// This is different than WithValue(), as it does not make a copy of the context with the new value, it will be available up the chain as well.
func (c *middlewareContextImpl) Set(key string, value interface{}) {
	c.ginContext.Set(key, value)
}

// Get returns the value for the given key, ie: (value, true).
// If the value does not exists it returns (nil, false)
func (c *middlewareContextImpl) Get(key string) (value interface{}, exists bool) {
	return c.ginContext.Get(key)
}

// MustGet returns the value for the given key if it exists, otherwise it panics.
func (c *middlewareContextImpl) MustGet(key string) interface{} {
	return c.ginContext.MustGet(key)
}

func (c *middlewareContextImpl) Next() {
	c.nextCalled = true
	c.index++
	c.serveNext()
}

func (c *middlewareContextImpl) serveNext() {
	if c.Index() >= len(c.middlewares) {
		return
	}
	// make shallow copy:
	fctx2 := *c
	fctx2.nextCalled = false
	r := c.ginContext.Request.WithContext(fctx2)
	err := c.middlewares[c.Index()].Serve(&fctx2, c.ginContext.Writer, r, nil)
	if err != nil {
		logrus.WithError(err).Warnln("Middleware error")
		// todo: might be a good idea to check if anything is written yet, and if not, output the error: simpleError(err)
		// see: http://stackoverflow.com/questions/39415827/golang-http-check-if-responsewriter-has-been-written
		c.ginContext.Abort()
		return
	}
	if !fctx2.nextCalled {
		// then we automatically call next
		fctx2.Next()
	}

}

func (c *middlewareContextImpl) Index() int {
	return c.index
}

func (s *Server) middlewareWrapperFunc(ctx context.Context) gin.HandlerFunc {
	return func(c *gin.Context) {
		if len(s.middlewares) == 0 {
			return
		}
		ctx = c.MustGet("ctx").(context.Context)
		fctx := &middlewareContextImpl{Context: ctx}
		// add this context to gin context so we can grab it later
		c.Set("mctx", fctx)
		fctx.index = -1
		fctx.ginContext = c
		fctx.middlewares = s.middlewares
		// start the chain:
		fctx.Next()
	}
}

// AddMiddleware add middleware
func (s *Server) AddMiddleware(m Middleware) {
	s.middlewares = append(s.middlewares, m)
}

// AddMiddlewareFunc adds middleware function
func (s *Server) AddMiddlewareFunc(m func(ctx MiddlewareContext, w http.ResponseWriter, r *http.Request, app *models.App) error) {
	s.AddMiddleware(MiddlewareFunc(m))
}
<|endoftext|>


<commit_before>// Package fun contains Fun language AST and means to prettyprint its source code.
package fun

import (
	"bytes"
	"fmt"
	"strings"
)

const (
	lf            = "\n"
	undefined     = "undefined"
	arrow         = " -> "
	typeSeparator = " :: "
	unit          = "()"
	space         = " "
	comma         = ", "
	binding       = " = "
	dot           = "."
	intendation   = "    "
	doDecl        = "do" + lf
	openBracket   = "("
	closeBracket  = ")"
)

// Module represents single source file.
type Module struct {
	Name    string
	Imports []Import
	Decls   []Decl
}

// Import represents import.
type Import struct {
	Path  string
	Alias string
}

// Decl represents declaration.
type Decl interface {
	String() string
	declMarker()
}

func (fd FuncDecl) declMarker() {}

// FuncBody represents function body.
type FuncBody interface {
	String() string
	funcBodyMarker()
}

func (fa FuncApplication) funcBodyMarker() {}
func (do DoBlock) funcBodyMarker()         {}
func (u Undef) funcBodyMarker()            {}

// Undef represents function body placeholder.
type Undef bool

// Undefined is an Undef singleton.
const Undefined Undef = true

func (u Undef) String() string {
	return undefined
}

// FuncDecl represents function declaration.
type FuncDecl struct {
	Name    string
	Params  Parameters
	Results Results
	Body    FuncBody
}

// Parameter represents function parameter.
type Parameter struct {
	Name string
	Type Type
}

// Type represents type.
type Type string

func (imp Import) String() string {
	if imp.Alias == "" {
		return fmt.Sprintf("import \"%s\"", imp.Path)
	}
	return fmt.Sprintf("import \"%s\" as \"%s\"", imp.Path, imp.Alias)
}

func (mod Module) String() string {
	topLevels := make([]string, 1+1+len(mod.Decls))

	// Module name
	topLevels[0] = fmt.Sprintf("module %s where\n", mod.Name)

	// Imports
	imports := make([]string, len(mod.Imports))
	for i, imp := range mod.Imports {
		imports[i] = imp.String()
	}
	topLevels[1] = strings.Join(imports, lf) + lf

	// Top-level declarations
	for i, decl := range mod.Decls {
		topLevels[2+i] = decl.String()
	}

	return strings.Join(topLevels, lf) + lf
}

func (fd FuncDecl) String() string {
	var out bytes.Buffer
	// Type signature
	fmt.Fprint(&out, fd.Name)
	fmt.Fprint(&out, typeSeparator)
	fmt.Fprint(&out, fd.Params)
	if len(fd.Params) > 0 {
		fmt.Fprint(&out, arrow)
	}
	fmt.Fprint(&out, fd.Results, lf)

	// Name and parameters
	fmt.Fprint(&out, fd.Name)
	if len(fd.Params) > 0 {
		fmt.Fprint(&out, space, fd.Params.Names())
	}
	fmt.Fprint(&out, binding)

	// TODO implement body
	if fd.Body == nil {
		fmt.Fprint(&out, undefined)
	} else {
		fmt.Fprint(&out, fd.Body)
	}

	return out.String() + lf
}

// Parameters represents function parameters.
type Parameters []Parameter // TODO not only types

func (ps Parameters) String() string {
	ss := make([]string, len(ps))
	for i := 0; i < len(ps); i++ {
		ss[i] = string(ps[i].Type)
	}
	return strings.Join(ss, arrow)
}

// Names build parameter list for binding.
func (ps Parameters) Names() string {
	ss := make([]string, len(ps))
	for i := 0; i < len(ps); i++ {
		ss[i] = string(ps[i].Name)
	}
	return strings.Join(ss, space)
}

// Results represents function result list.
type Results []Type

func (ts Results) String() string {
	switch len(ts) {
	case 0:
		return unit
	case 1:
		return string(ts[0])
	default:
		ss := make([]string, len(ts))
		for i := 0; i < len(ts); i++ {
			ss[i] = string(ts[i])
		}
		return openBracket + strings.Join(ss, comma) + closeBracket
	}
}

// Expression is a pure function.
type Expression interface {
	funcBodyMarker()
	// expressionMarker()
}

// Statement just performs side effects.
type Statement interface {
	funcBodyMarker()
	// statementMarker()
}

// DoBlock represents raw Go code as a function body.
type DoBlock struct {
	Text []string
}

// FuncApplication represents function application.
// At least for now it may be both Statement and Expression.
type FuncApplication struct {
	Name      string
	Module    string
	Arguments []Argument
	Kind      funcApplicationKind
}

type funcApplicationKind uint8

// Kinds of a FuncApplication
const (
	EXPRESSION funcApplicationKind = iota
	STATEMENT  funcApplicationKind = iota
)

func (fa FuncApplication) String() string {
	var buf bytes.Buffer
	if fa.Module != "" {
		fmt.Fprint(&buf, fa.Module, dot)
	}
	fmt.Fprint(&buf, fa.Name)
	if len(fa.Arguments) > 0 {
		args := make([]string, len(fa.Arguments))
		for i := 0; i < len(args); i++ {
			switch arg := fa.Arguments[i].(type) {
			case FuncApplication:
				args[i] = fmt.Sprintf("(%s)", arg)
			default:
				args[i] = fmt.Sprint(arg)
			}
		}
		fmt.Fprint(&buf, space, strings.Join(args, space))
	}
	return buf.String()
}

// Assuming non-empty body, empty do block does not really makes sense.
func (do DoBlock) String() string {
	buf := bytes.NewBufferString(doDecl)
	for _, line := range do.Text {
		fmt.Fprint(buf, intendation, line, lf)
	}
	return strings.TrimSuffix(buf.String(), lf)
}

// Argument represents argument to which a function is applied.
type Argument interface {
	argumentMarker()
}

// Literal represents language literals.
type Literal interface {
	argumentMarker()
	literalMarker()
}

func (fa FuncApplication) argumentMarker() {}

// Int maps to Go int.
type Int string

func (t Int) literalMarker()  {}
func (t Int) argumentMarker() {}

// Float maps to Go float32.
type Float string

func (t Float) literalMarker()  {}
func (t Float) argumentMarker() {}

// Double maps to Go float64.
type Double string

func (t Double) literalMarker()  {}
func (t Double) argumentMarker() {}

// String wraps Go string.
type String string

func (t String) literalMarker()  {}
func (t String) argumentMarker() {}

func (t String) String() string {
	return fmt.Sprintf("%#v", t)
}

// Bool maps to Go bool.
type Bool string

func (t Bool) literalMarker()  {}
func (t Bool) argumentMarker() {}

// Char maps to Go char.
type Char string

func (t Char) literalMarker()  {}
func (t Char) argumentMarker() {}

// Var represents something passed by name.
type Var string

func (v Var) argumentMarker() {}
<commit_msg>Imaginary literal<commit_after>// Package fun contains Fun language AST and means to prettyprint its source code.
package fun

import (
	"bytes"
	"fmt"
	"strings"
)

const (
	lf            = "\n"
	undefined     = "undefined"
	arrow         = " -> "
	typeSeparator = " :: "
	unit          = "()"
	space         = " "
	comma         = ", "
	binding       = " = "
	dot           = "."
	intendation   = "    "
	doDecl        = "do" + lf
	openBracket   = "("
	closeBracket  = ")"
)

// Module represents single source file.
type Module struct {
	Name    string
	Imports []Import
	Decls   []Decl
}

// Import represents import.
type Import struct {
	Path  string
	Alias string
}

// Decl represents declaration.
type Decl interface {
	String() string
	declMarker()
}

func (fd FuncDecl) declMarker() {}

// FuncBody represents function body.
type FuncBody interface {
	String() string
	funcBodyMarker()
}

func (fa FuncApplication) funcBodyMarker() {}
func (do DoBlock) funcBodyMarker()         {}
func (u Undef) funcBodyMarker()            {}

// Undef represents function body placeholder.
type Undef bool

// Undefined is an Undef singleton.
const Undefined Undef = true

func (u Undef) String() string {
	return undefined
}

// FuncDecl represents function declaration.
type FuncDecl struct {
	Name    string
	Params  Parameters
	Results Results
	Body    FuncBody
}

// Parameter represents function parameter.
type Parameter struct {
	Name string
	Type Type
}

// Type represents type.
type Type string

func (imp Import) String() string {
	if imp.Alias == "" {
		return fmt.Sprintf("import \"%s\"", imp.Path)
	}
	return fmt.Sprintf("import \"%s\" as \"%s\"", imp.Path, imp.Alias)
}

func (mod Module) String() string {
	topLevels := make([]string, 1+1+len(mod.Decls))

	// Module name
	topLevels[0] = fmt.Sprintf("module %s where\n", mod.Name)

	// Imports
	imports := make([]string, len(mod.Imports))
	for i, imp := range mod.Imports {
		imports[i] = imp.String()
	}
	topLevels[1] = strings.Join(imports, lf) + lf

	// Top-level declarations
	for i, decl := range mod.Decls {
		topLevels[2+i] = decl.String()
	}

	return strings.Join(topLevels, lf) + lf
}

func (fd FuncDecl) String() string {
	var out bytes.Buffer
	// Type signature
	fmt.Fprint(&out, fd.Name)
	fmt.Fprint(&out, typeSeparator)
	fmt.Fprint(&out, fd.Params)
	if len(fd.Params) > 0 {
		fmt.Fprint(&out, arrow)
	}
	fmt.Fprint(&out, fd.Results, lf)

	// Name and parameters
	fmt.Fprint(&out, fd.Name)
	if len(fd.Params) > 0 {
		fmt.Fprint(&out, space, fd.Params.Names())
	}
	fmt.Fprint(&out, binding)

	// TODO implement body
	if fd.Body == nil {
		fmt.Fprint(&out, undefined)
	} else {
		fmt.Fprint(&out, fd.Body)
	}

	return out.String() + lf
}

// Parameters represents function parameters.
type Parameters []Parameter // TODO not only types

func (ps Parameters) String() string {
	ss := make([]string, len(ps))
	for i := 0; i < len(ps); i++ {
		ss[i] = string(ps[i].Type)
	}
	return strings.Join(ss, arrow)
}

// Names build parameter list for binding.
func (ps Parameters) Names() string {
	ss := make([]string, len(ps))
	for i := 0; i < len(ps); i++ {
		ss[i] = string(ps[i].Name)
	}
	return strings.Join(ss, space)
}

// Results represents function result list.
type Results []Type

func (ts Results) String() string {
	switch len(ts) {
	case 0:
		return unit
	case 1:
		return string(ts[0])
	default:
		ss := make([]string, len(ts))
		for i := 0; i < len(ts); i++ {
			ss[i] = string(ts[i])
		}
		return openBracket + strings.Join(ss, comma) + closeBracket
	}
}

// Expression is a pure function.
type Expression interface {
	funcBodyMarker()
	// expressionMarker()
}

// Statement just performs side effects.
type Statement interface {
	funcBodyMarker()
	// statementMarker()
}

// DoBlock represents raw Go code as a function body.
type DoBlock struct {
	Text []string
}

// FuncApplication represents function application.
// At least for now it may be both Statement and Expression.
type FuncApplication struct {
	Name      string
	Module    string
	Arguments []Argument
	Kind      funcApplicationKind
}

type funcApplicationKind uint8

// Kinds of a FuncApplication
const (
	EXPRESSION funcApplicationKind = iota
	STATEMENT  funcApplicationKind = iota
)

func (fa FuncApplication) String() string {
	var buf bytes.Buffer
	if fa.Module != "" {
		fmt.Fprint(&buf, fa.Module, dot)
	}
	fmt.Fprint(&buf, fa.Name)
	if len(fa.Arguments) > 0 {
		args := make([]string, len(fa.Arguments))
		for i := 0; i < len(args); i++ {
			switch arg := fa.Arguments[i].(type) {
			case FuncApplication:
				args[i] = fmt.Sprintf("(%s)", arg)
			default:
				args[i] = fmt.Sprint(arg)
			}
		}
		fmt.Fprint(&buf, space, strings.Join(args, space))
	}
	return buf.String()
}

// Assuming non-empty body, empty do block does not really makes sense.
func (do DoBlock) String() string {
	buf := bytes.NewBufferString(doDecl)
	for _, line := range do.Text {
		fmt.Fprint(buf, intendation, line, lf)
	}
	return strings.TrimSuffix(buf.String(), lf)
}

// Argument represents argument to which a function is applied.
type Argument interface {
	argumentMarker()
}

// Literal represents language literals.
type Literal interface {
	argumentMarker()
	literalMarker()
}

func (fa FuncApplication) argumentMarker() {}

// Int maps to Go int.
type Int string

func (t Int) literalMarker()  {}
func (t Int) argumentMarker() {}

// Float maps to Go float32.
type Float string

func (t Float) literalMarker()  {}
func (t Float) argumentMarker() {}

// Double maps to Go float64.
type Double string

func (t Double) literalMarker()  {}
func (t Double) argumentMarker() {}

// String wraps Go string.
type String string

func (t String) literalMarker()  {}
func (t String) argumentMarker() {}

func (t String) String() string {
	return fmt.Sprintf("%#v", t)
}

// Bool maps to Go bool.
type Bool string

func (t Bool) literalMarker()  {}
func (t Bool) argumentMarker() {}

// Char maps to Go char.
type Char string

func (t Char) literalMarker()  {}
func (t Char) argumentMarker() {}

// Imaginary maps to Go imaginary double.
type Imaginary string

func (t Imaginary) literalMarker()  {}
func (t Imaginary) argumentMarker() {}

// Var represents something passed by name.
type Var string

func (v Var) argumentMarker() {}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"github.com/SudoQ/ganache/service"
	"log"
	"runtime"
)

func check(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

var configFile string

func init() {
	flag.StringVar(&configFile, "f", "config.json", "Path to configuration file")
	runtime.GOMAXPROCS(runtime.NumCPU())
}

func main() {
	flag.Parse()

	srv, _ := service.NewFromFile(configFile)
	log.Println(srv.Info())
	config, err := srv.JSON()
	log.Println(string(config))
	check(err)
	err = srv.SaveConfig("config.json")
	check(err)
	err = srv.LoadConfig("config.json")
	check(err)
	srv.Run()
}
<commit_msg>Added extended flag handling, providing config file will override other parameters<commit_after>package main

import (
	"flag"
	"github.com/SudoQ/ganache/service"
	"log"
	"runtime"
)

func check(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

var configFilename string
var url string
var port string
var limit uint

func init() {
	flag.StringVar(&configFilename, "f", "config.json", "Path to configuration file")
	flag.StringVar(&url, "url", "http://whatthecommit.com/index.txt", "URL to cache")
	flag.StringVar(&port, "p", "8080", "Port number of the ganache service")
	flag.UintVar(&limit, "l", 60 ,"Limit of requests per hour")
	runtime.GOMAXPROCS(runtime.NumCPU())
}

func main() {
	flag.Parse()

	useConfig := false
	flag.Visit(func(flg *flag.Flag){
		if flg.Name == "f" {
			useConfig = true
		}
	})

	var srv *service.Service
	if useConfig {
		var err error
		srv, err = service.NewFromFile(configFilename)
		if err != nil {
			log.Fatal(err)
			return
		}
	} else {
		srv = service.New(url, port, limit)
	}
	log.Println(srv.Info())
	srv.Run()
}
<|endoftext|>


<commit_before>//
// Usage of herokuname:
//   -digits int
//        	how many digits after the names. (default 4)
//   -hex
//        	use hexadecimal values instead of decimals.
//   -http string
//        	start HTTP server.
//   -separator string
//        	word separator. (default "-")
//   -ubuntu string
//        	match initial letters (Ubuntu-style).
//
package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"strings"

	"cirello.io/goherokuname"
)

var hex = flag.Bool(`hex`, false, `use hexadecimal values instead of decimals.`)
var digits = flag.Int(`digits`, 4, `how many digits after the names.`)
var separator = flag.String(`separator`, "-", `word separator.`)
var ubuntu = flag.String(`ubuntu`, "", `match initial letters (Ubuntu-style).`)
var listenHTTP = flag.String(`http`, "", `start HTTP server.`)

func main() {
	flag.Parse()

	if *listenHTTP != "" {
		http.HandleFunc("/about", serveAbout)
		http.HandleFunc("/ubuntu/", serveUbuntu)
		http.HandleFunc("/long", serveHerokuLong)
		http.HandleFunc("/short", serveHerokuShort)
		http.HandleFunc("/", serveIndex)
		if err := http.ListenAndServe(*listenHTTP, nil); err != nil {
			log.SetPrefix("")
			log.SetFlags(0)
			log.Fatal(err)
		}
		os.Exit(0)
	}

	tokchars := "0123456789"
	if *hex {
		tokchars = tokchars + "abcdef"
	}

	if *ubuntu != "" {
		name, err := goherokuname.Ubuntu(*separator, *ubuntu)
		if err != nil {
			fmt.Fprintln(os.Stderr, "error:", err)
			os.Exit(1)
		}
		fmt.Println(name)
	} else {
		fmt.Println(goherokuname.HaikunateCustom(*separator, *digits, tokchars))
	}

	os.Exit(0)
}

func serveAbout(w http.ResponseWriter, r *http.Request) {
	http.Redirect(w, r, "http://godoc.org/cirello.io/goherokuname", http.StatusSeeOther)
}

func serveUbuntu(w http.ResponseWriter, r *http.Request) {
	letter := strings.TrimPrefix(r.URL.String(), "/ubuntu/")
	name, err := goherokuname.Ubuntu("-", letter)
	if err != nil {
		http.Error(w, fmt.Sprintln(http.StatusText(http.StatusBadRequest), err), http.StatusBadRequest)
		return
	}
	fmt.Fprintln(w, name)
}

func serveHerokuLong(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, goherokuname.HaikunateCustom("-", 8, "0123456789abcdef"))
}

func serveHerokuShort(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, goherokuname.HaikunateHex())
}

func serveIndex(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, `

about

ubuntu (e.g.: propellant-pomatomus)

long (e.g.: overnice-minah-86758bf5)

short (e.g.: cutaneal-muhammadanism-313e)

	`)
}
<commit_msg>Improve index page for http interface<commit_after>//
// Usage of herokuname:
//   -digits int
//        	how many digits after the names. (default 4)
//   -hex
//        	use hexadecimal values instead of decimals.
//   -http string
//        	start HTTP server.
//   -separator string
//        	word separator. (default "-")
//   -ubuntu string
//        	match initial letters (Ubuntu-style).
//
package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"strings"

	"cirello.io/goherokuname"
)

var hex = flag.Bool(`hex`, false, `use hexadecimal values instead of decimals.`)
var digits = flag.Int(`digits`, 4, `how many digits after the names.`)
var separator = flag.String(`separator`, "-", `word separator.`)
var ubuntu = flag.String(`ubuntu`, "", `match initial letters (Ubuntu-style).`)
var listenHTTP = flag.String(`http`, "", `start HTTP server.`)

func main() {
	flag.Parse()

	if *listenHTTP != "" {
		http.HandleFunc("/about", serveAbout)
		http.HandleFunc("/ubuntu/", serveUbuntu)
		http.HandleFunc("/long", serveHerokuLong)
		http.HandleFunc("/short", serveHerokuShort)
		http.HandleFunc("/", serveIndex)
		if err := http.ListenAndServe(*listenHTTP, nil); err != nil {
			log.SetPrefix("")
			log.SetFlags(0)
			log.Fatal(err)
		}
		os.Exit(0)
	}

	tokchars := "0123456789"
	if *hex {
		tokchars = tokchars + "abcdef"
	}

	if *ubuntu != "" {
		name, err := goherokuname.Ubuntu(*separator, *ubuntu)
		if err != nil {
			fmt.Fprintln(os.Stderr, "error:", err)
			os.Exit(1)
		}
		fmt.Println(name)
	} else {
		fmt.Println(goherokuname.HaikunateCustom(*separator, *digits, tokchars))
	}

	os.Exit(0)
}

func serveAbout(w http.ResponseWriter, r *http.Request) {
	http.Redirect(w, r, "http://godoc.org/cirello.io/goherokuname", http.StatusSeeOther)
}

func serveUbuntu(w http.ResponseWriter, r *http.Request) {
	letter := strings.TrimPrefix(r.URL.String(), "/ubuntu/")
	name, err := goherokuname.Ubuntu("-", letter)
	if err != nil {
		http.Error(w, fmt.Sprintln(http.StatusText(http.StatusBadRequest), err), http.StatusBadRequest)
		return
	}
	fmt.Fprintln(w, name)
}

func serveHerokuLong(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, goherokuname.HaikunateCustom("-", 8, "0123456789abcdef"))
}

func serveHerokuShort(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, goherokuname.HaikunateHex())
}

func serveIndex(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, `

Name generator as a service

about

ubuntu (e.g.: propellant-pomatomus)

long (e.g.: overnice-minah-86758bf5)

short (e.g.: cutaneal-muhammadanism-313e)

	`)
}
<|endoftext|>


<commit_before>// Copyright 2020 The LUCI Authors.
//
// 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 backend

import (
	"crypto/sha512"
	"encoding/hex"
	"time"

	"cloud.google.com/go/bigquery"

	"go.chromium.org/luci/resultdb/internal/span"
	"go.chromium.org/luci/resultdb/pbutil"
	pb "go.chromium.org/luci/resultdb/proto/rpc/v1"
	typepb "go.chromium.org/luci/resultdb/proto/type"
)

// Row size limit is 1Mib according to
// https://cloud.google.com/bigquery/quotas#streaming_inserts
// Cap the summaryHTML's length to 0.6M to ensure the row size is under
// limit.
const maxSummaryLength = 6e5

// StringPair is a copy of typepb.StringPair, suitable for representing a
// key:value pair in a BQ table.
// Inferred to be a field of type RECORD with Key and Value string fields.
type StringPair struct {
	Key   string `bigquery:"key"`
	Value string `bigquery:"value"`
}

// Invocation is a subset of pb.Invocation for the invocation fields that need
// to be saved in a BQ table.
type Invocation struct {
	// ID is the ID of the invocation.
	ID string `bigquery:"id"`

	// Interrupted is a flag indicating whether the invocation is interrupted or not.
	// For more details, refer to pb.Invocation.Interrupted.
	Interrupted bool `bigquery:"interrupted"`

	// Tags represents Invocation-level string key-value pairs.
	// A key can be repeated.
	Tags []StringPair `bigquery:"tags"`
}

// TestResultRow represents a row in a BigQuery table for result of a functional
// test case.
type TestResultRow struct {
	// ExportedInvocation contains info of the exported invocation.
	// Note that it's possible that this invocation is not the result's
	// immediate parent invocation, but the including invocation.
	ExportedInvocation Invocation `bigquery:"exported"`

	// ParentInvocation contains info of the result's immediate parent
	// invocation.
	ParentInvocation Invocation `bigquery:"parent"`

	// TestID is a unique identifier of the test in a LUCI project.
	// Refer to pb.TestResult.TestId for details.
	TestID string `bigquery:"test_id"`

	// ResultID identifies a test result in a given invocation and test id.
	ResultID string `bigquery:"result_id"`

	// Variant describes one specific way of running the test,
	//  e.g. a specific bucket, builder and a test suite.
	Variant []StringPair `bigquery:"variant"`

	// A hex-encoded sha256 of concatenated "<key>:<value>\n" variant pairs.
	VariantHash string `bigquery:"variant_hash"`

	// Expected is a flag indicating whether the result of test case execution is expected.
	// Refer to pb.TestResult.Expected for details.
	Expected bool `bigquery:"expected"`

	// Status of the test result.
	Status string `bigquery:"status"`

	// SummaryHTML is a human-readable explanation of the result, in HTML.
	SummaryHTML string `bigquery:"summary_html"`

	// StartTime is the point in time when the test case started to execute.
	StartTime bigquery.NullTimestamp `bigquery:"start_time"`

	// Duration of the test case execution in seconds.
	Duration bigquery.NullFloat64 `bigquery:"duration"`

	// Tags contains metadata for this test result.
	// It might describe this particular execution or the test case.
	Tags []StringPair `bigquery:"tags"`

	// If the failures of the test variant are exonerated.
	// Note: the exoneration is at the test variant level, not result level.
	Exonerated bool `bigquery:"exonerated"`

	// PartitionTime is used to partition the table.
	// It is the time when exported invocation was created.
	// https://cloud.google.com/bigquery/docs/creating-column-partitions#limitations
	// mentions "The partitioning column must be a top-level field."
	// So we keep this column here instead of adding the CreateTime to Invocation.
	PartitionTime time.Time `bigquery:"partition_time"`
}

// Name returns test result name.
func (tr *TestResultRow) Name() string {
	return pbutil.TestResultName(tr.ParentInvocation.ID, tr.TestID, tr.ResultID)
}

// stringPairProtosToStringPairs returns a slice of StringPair derived from *typepb.StringPair.
func stringPairProtosToStringPairs(pairs []*typepb.StringPair) []StringPair {
	if len(pairs) == 0 {
		return nil
	}

	sp := make([]StringPair, len(pairs))
	for i, p := range pairs {
		sp[i] = StringPair{
			Key:   p.Key,
			Value: p.Value,
		}
	}
	return sp
}

// variantToStringPairs returns a slice of StringPair derived from *typepb.Variant.
func variantToStringPairs(vr *typepb.Variant) []StringPair {
	defMap := vr.GetDef()
	if len(defMap) == 0 {
		return nil
	}

	keys := pbutil.SortedVariantKeys(vr)
	sp := make([]StringPair, len(keys))
	for i, k := range keys {
		sp[i] = StringPair{
			Key:   k,
			Value: defMap[k],
		}
	}
	return sp
}

func invocationProtoToInvocation(inv *pb.Invocation) Invocation {
	return Invocation{
		ID:          string(span.MustParseInvocationName(inv.Name)),
		Interrupted: inv.Interrupted,
		Tags:        stringPairProtosToStringPairs(inv.Tags),
	}
}

// generateBQRow returns a *bigquery.StructSaver to be inserted into BQ.
func (b *bqExporter) generateBQRow(exported, parent *pb.Invocation, tr *pb.TestResult, exonerated bool, variantHash string) *bigquery.StructSaver {
	trr := &TestResultRow{
		ExportedInvocation: invocationProtoToInvocation(exported),
		ParentInvocation:   invocationProtoToInvocation(parent),
		TestID:             tr.TestId,
		ResultID:           tr.ResultId,
		Variant:            variantToStringPairs(tr.Variant),
		VariantHash:        variantHash,
		Expected:           tr.Expected,
		Status:             tr.Status.String(),
		SummaryHTML:        tr.SummaryHtml,
		Tags:               stringPairProtosToStringPairs(tr.Tags),
		Exonerated:         exonerated,
		PartitionTime:      pbutil.MustTimestamp(exported.CreateTime),
	}

	if tr.StartTime != nil {
		trr.StartTime = bigquery.NullTimestamp{
			Timestamp: pbutil.MustTimestamp(tr.StartTime),
			Valid:     true,
		}
	}

	if tr.Duration != nil {
		trr.Duration = bigquery.NullFloat64{
			Float64: pbutil.MustDuration(tr.Duration).Seconds(),
			Valid:   true,
		}
	}

	if len(trr.SummaryHTML) > maxSummaryLength {
		trr.SummaryHTML = "[Trimmed] " + trr.SummaryHTML[:maxSummaryLength]
	}

	ret := &bigquery.StructSaver{Struct: trr}

	if b.useInsertIDs {
		// InsertID cannot exceed 128 bytes.
		// https://cloud.google.com/bigquery/quotas#streaming_inserts
		// Use SHA512 which is exactly 128 bytes in hex.
		hash := sha512.Sum512([]byte(tr.Name))
		ret.InsertID = hex.EncodeToString(hash[:])
	}

	return ret
}
<commit_msg>[resultdb] Use bigquery.NoDedupID<commit_after>// Copyright 2020 The LUCI Authors.
//
// 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 backend

import (
	"crypto/sha512"
	"encoding/hex"
	"time"

	"cloud.google.com/go/bigquery"

	"go.chromium.org/luci/resultdb/internal/span"
	"go.chromium.org/luci/resultdb/pbutil"
	pb "go.chromium.org/luci/resultdb/proto/rpc/v1"
	typepb "go.chromium.org/luci/resultdb/proto/type"
)

// Row size limit is 1Mib according to
// https://cloud.google.com/bigquery/quotas#streaming_inserts
// Cap the summaryHTML's length to 0.6M to ensure the row size is under
// limit.
const maxSummaryLength = 6e5

// StringPair is a copy of typepb.StringPair, suitable for representing a
// key:value pair in a BQ table.
// Inferred to be a field of type RECORD with Key and Value string fields.
type StringPair struct {
	Key   string `bigquery:"key"`
	Value string `bigquery:"value"`
}

// Invocation is a subset of pb.Invocation for the invocation fields that need
// to be saved in a BQ table.
type Invocation struct {
	// ID is the ID of the invocation.
	ID string `bigquery:"id"`

	// Interrupted is a flag indicating whether the invocation is interrupted or not.
	// For more details, refer to pb.Invocation.Interrupted.
	Interrupted bool `bigquery:"interrupted"`

	// Tags represents Invocation-level string key-value pairs.
	// A key can be repeated.
	Tags []StringPair `bigquery:"tags"`
}

// TestResultRow represents a row in a BigQuery table for result of a functional
// test case.
type TestResultRow struct {
	// ExportedInvocation contains info of the exported invocation.
	// Note that it's possible that this invocation is not the result's
	// immediate parent invocation, but the including invocation.
	ExportedInvocation Invocation `bigquery:"exported"`

	// ParentInvocation contains info of the result's immediate parent
	// invocation.
	ParentInvocation Invocation `bigquery:"parent"`

	// TestID is a unique identifier of the test in a LUCI project.
	// Refer to pb.TestResult.TestId for details.
	TestID string `bigquery:"test_id"`

	// ResultID identifies a test result in a given invocation and test id.
	ResultID string `bigquery:"result_id"`

	// Variant describes one specific way of running the test,
	//  e.g. a specific bucket, builder and a test suite.
	Variant []StringPair `bigquery:"variant"`

	// A hex-encoded sha256 of concatenated "<key>:<value>\n" variant pairs.
	VariantHash string `bigquery:"variant_hash"`

	// Expected is a flag indicating whether the result of test case execution is expected.
	// Refer to pb.TestResult.Expected for details.
	Expected bool `bigquery:"expected"`

	// Status of the test result.
	Status string `bigquery:"status"`

	// SummaryHTML is a human-readable explanation of the result, in HTML.
	SummaryHTML string `bigquery:"summary_html"`

	// StartTime is the point in time when the test case started to execute.
	StartTime bigquery.NullTimestamp `bigquery:"start_time"`

	// Duration of the test case execution in seconds.
	Duration bigquery.NullFloat64 `bigquery:"duration"`

	// Tags contains metadata for this test result.
	// It might describe this particular execution or the test case.
	Tags []StringPair `bigquery:"tags"`

	// If the failures of the test variant are exonerated.
	// Note: the exoneration is at the test variant level, not result level.
	Exonerated bool `bigquery:"exonerated"`

	// PartitionTime is used to partition the table.
	// It is the time when exported invocation was created.
	// https://cloud.google.com/bigquery/docs/creating-column-partitions#limitations
	// mentions "The partitioning column must be a top-level field."
	// So we keep this column here instead of adding the CreateTime to Invocation.
	PartitionTime time.Time `bigquery:"partition_time"`
}

// Name returns test result name.
func (tr *TestResultRow) Name() string {
	return pbutil.TestResultName(tr.ParentInvocation.ID, tr.TestID, tr.ResultID)
}

// stringPairProtosToStringPairs returns a slice of StringPair derived from *typepb.StringPair.
func stringPairProtosToStringPairs(pairs []*typepb.StringPair) []StringPair {
	if len(pairs) == 0 {
		return nil
	}

	sp := make([]StringPair, len(pairs))
	for i, p := range pairs {
		sp[i] = StringPair{
			Key:   p.Key,
			Value: p.Value,
		}
	}
	return sp
}

// variantToStringPairs returns a slice of StringPair derived from *typepb.Variant.
func variantToStringPairs(vr *typepb.Variant) []StringPair {
	defMap := vr.GetDef()
	if len(defMap) == 0 {
		return nil
	}

	keys := pbutil.SortedVariantKeys(vr)
	sp := make([]StringPair, len(keys))
	for i, k := range keys {
		sp[i] = StringPair{
			Key:   k,
			Value: defMap[k],
		}
	}
	return sp
}

func invocationProtoToInvocation(inv *pb.Invocation) Invocation {
	return Invocation{
		ID:          string(span.MustParseInvocationName(inv.Name)),
		Interrupted: inv.Interrupted,
		Tags:        stringPairProtosToStringPairs(inv.Tags),
	}
}

// generateBQRow returns a *bigquery.StructSaver to be inserted into BQ.
func (b *bqExporter) generateBQRow(exported, parent *pb.Invocation, tr *pb.TestResult, exonerated bool, variantHash string) *bigquery.StructSaver {
	trr := &TestResultRow{
		ExportedInvocation: invocationProtoToInvocation(exported),
		ParentInvocation:   invocationProtoToInvocation(parent),
		TestID:             tr.TestId,
		ResultID:           tr.ResultId,
		Variant:            variantToStringPairs(tr.Variant),
		VariantHash:        variantHash,
		Expected:           tr.Expected,
		Status:             tr.Status.String(),
		SummaryHTML:        tr.SummaryHtml,
		Tags:               stringPairProtosToStringPairs(tr.Tags),
		Exonerated:         exonerated,
		PartitionTime:      pbutil.MustTimestamp(exported.CreateTime),
	}

	if tr.StartTime != nil {
		trr.StartTime = bigquery.NullTimestamp{
			Timestamp: pbutil.MustTimestamp(tr.StartTime),
			Valid:     true,
		}
	}

	if tr.Duration != nil {
		trr.Duration = bigquery.NullFloat64{
			Float64: pbutil.MustDuration(tr.Duration).Seconds(),
			Valid:   true,
		}
	}

	if len(trr.SummaryHTML) > maxSummaryLength {
		trr.SummaryHTML = "[Trimmed] " + trr.SummaryHTML[:maxSummaryLength]
	}

	ret := &bigquery.StructSaver{Struct: trr}

	if b.useInsertIDs {
		// InsertID cannot exceed 128 bytes.
		// https://cloud.google.com/bigquery/quotas#streaming_inserts
		// Use SHA512 which is exactly 128 bytes in hex.
		hash := sha512.Sum512([]byte(tr.Name))
		ret.InsertID = hex.EncodeToString(hash[:])
	} else {
		ret.InsertID = bigquery.NoDedupeID
	}

	return ret
}
<|endoftext|>


<commit_before>package gat

import (
	"log"
	"os"
	"os/exec"
	"path/filepath"
)

type Run struct {
	Tags string
}

func (run Run) RunAll() {
	run.goTest("./...")
}

func (run Run) RunOnChange(file string) {
	if isGoFile(file) {
		// TODO: optimization, skip if no test files exist
		packageDir := "./" + filepath.Dir(file) // watchDir = ./
		run.goTest(packageDir)
	}
}

func (run Run) goTest(test_files string) {
	args := []string{"test"}
	if len(run.Tags) > 0 {
		args = append(args, []string{"-tags", run.Tags}...)
	}
	args = append(args, test_files)

	command := "go"

	if _, err := os.Stat("Godeps/Godeps.json"); err == nil {
		args = append([]string{"go"}, args...)
		command = "godep"
	}

	cmd := exec.Command(command, args...)
	// cmd.Dir watchDir = ./

	PrintCommand(cmd.Args) // includes "go"

	out, err := cmd.CombinedOutput()
	if err != nil {
		log.Println(err)
	}
	PrintCommandOutput(out)

	RedGreen(cmd.ProcessState.Success())
	ShowDuration(cmd.ProcessState.UserTime())
}

func isGoFile(file string) bool {
	return filepath.Ext(file) == ".go"
}
<commit_msg>Skip /vendor/ folder on full test run<commit_after>package gat

import (
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

// IgnoreVendor if using Go 1.5 vendor experiment
var IgnoreVendor = (os.Getenv("GO15VENDOREXPERIMENT") == "1")

type Run struct {
	Tags string
}

func (run Run) RunAll() {
	if IgnoreVendor {
		pkgs := goList()
		run.goTest(pkgs...)
	} else {
		run.goTest("./...")
	}
}

func (run Run) RunOnChange(file string) {
	if isGoFile(file) {
		// TODO: optimization, skip if no test files exist
		packageDir := "./" + filepath.Dir(file) // watchDir = ./
		run.goTest(packageDir)
	}
}

func (run Run) goTest(pkgs ...string) {
	args := []string{"test"}
	if len(run.Tags) > 0 {
		args = append(args, []string{"-tags", run.Tags}...)
	}
	args = append(args, pkgs...)

	command := "go"

	if _, err := os.Stat("Godeps/Godeps.json"); err == nil {
		args = append([]string{"go"}, args...)
		command = "godep"
	}

	cmd := exec.Command(command, args...)
	// cmd.Dir watchDir = ./

	PrintCommand(cmd.Args) // includes "go"

	out, err := cmd.CombinedOutput()
	if err != nil {
		log.Println(err)
	}
	PrintCommandOutput(out)

	RedGreen(cmd.ProcessState.Success())
	ShowDuration(cmd.ProcessState.UserTime())
}

func goList() []string {
	cmd := exec.Command("go", "list", "./...")
	out, err := cmd.Output()
	if err != nil {
		log.Println(err)
	}
	allPkgs := strings.Split(string(out), "\n")

	pkgs := []string{}
	// remove packages that contain /vendor/ or are blank (last newline)
	for _, pkg := range allPkgs {
		if len(pkg) != 0 && !strings.Contains(pkg, "/vendor/") {
			pkgs = append(pkgs, pkg)
		}
	}
	return pkgs
}

func isGoFile(file string) bool {
	return filepath.Ext(file) == ".go"
}
<|endoftext|>


<commit_before><commit_msg>Fix getting the commit hash<commit_after><|endoftext|>


<commit_before>package main

import (
	"fmt"
	"math"
	"math/rand"
	"time"
)

type Chromosome struct {
	s       string
	fitness int
	mutant  bool
}

var poolSize = 250
var totalGenerations = 10000
var mutationRate = 0.002
var crossoverRate = 0.75

var pool = make([]Chromosome, poolSize)
var newPool = make([]Chromosome, poolSize)
var mutationRateInt = int(mutationRate * 1000)
var crossoverRateInt = int(crossoverRate * 1000)
var maxFitness = 0

var totalFitness int

func main() {

	if math.Mod(float64(poolSize), 2.0) > 0 {
		fmt.Println("Invalid pool size. Pool size must be even.")
		return
	}

	rand.Seed(time.Now().Unix())

	initializePool()
	computeFitness()

	var generation int

	for generation = 2; generation <= totalGenerations && maxFitness != 13; generation++ {
		populateNewPool()
		computeFitness()
	}

	fmt.Printf("Generation %d\n", generation-1)
	printPool()
	fmt.Printf("maxFitness: %d\n", maxFitness)

}

func randomChromosome() string {

	temp := ""

	for c := 0; c < 24; c++ {
		v := rand.Intn(2)

		if v > 0 {
			temp += "1"
		} else {
			temp += "0"
		}
	}

	return temp

}

func initializePool() {
	for i := 0; i < poolSize; i++ {
		pool[i].s = randomChromosome()
	}
}

func printPool() {
	for i := 0; i < poolSize; i++ {

		mutant := ""
		if pool[i].mutant {
			mutant = "M"
		}

		fmt.Printf("%d: %s [%d, %d, %d, %d, %d, %d, %d, %d] (%d) %f%% %s\n",
			i, pool[i].s,
			binStringToInt(pool[i].s[0:3]),
			binStringToInt(pool[i].s[3:6]),
			binStringToInt(pool[i].s[6:9]),
			binStringToInt(pool[i].s[9:12]),
			binStringToInt(pool[i].s[12:15]),
			binStringToInt(pool[i].s[15:18]),
			binStringToInt(pool[i].s[18:21]),
			binStringToInt(pool[i].s[21:24]),
			pool[i].fitness,
			float64(pool[i].fitness)/float64(totalFitness),
			mutant)
	}
	fmt.Printf("Total Fitness: %d\n", totalFitness)
}

func computeFitness() {
	totalFitness = 0

	for i := 0; i < poolSize; i++ {
		fitness := getFitness(&pool[i])
		totalFitness += fitness
		if fitness > maxFitness {
			maxFitness = fitness
		}
	}
}

func getFitness(chromosome *Chromosome) int {

	fitness := 0

	var g = make([]int, 8)

	g[0] = binStringToInt(chromosome.s[0:3])
	g[1] = binStringToInt(chromosome.s[3:6])
	g[2] = binStringToInt(chromosome.s[6:9])
	g[3] = binStringToInt(chromosome.s[9:12])
	g[4] = binStringToInt(chromosome.s[12:15])
	g[5] = binStringToInt(chromosome.s[15:18])
	g[6] = binStringToInt(chromosome.s[18:21])
	g[7] = binStringToInt(chromosome.s[21:24])

	for c := 0; c < 7; c++ {
		for d := c + 1; d < 8; d++ {
			if g[c] == g[d] {
				fitness++
				break
			}
		}
	}

	// diagonals

	for c := 0; c < 7; c++ {
		for d := c + 1; d < 8; d++ {

			e := int(math.Abs(float64(c - d)))

			if g[c]+e == g[d] || g[c]-e == g[d] {
				fitness++
				break
			}

		}
	}

	chromosome.fitness = 13 - fitness

	return chromosome.fitness
}

func binStringToInt(s string) int {
	i := 0
	for c := len(s) - 1; c >= 0; c-- {
		if s[c] == '1' {
			i += int(math.Pow(2, float64(len(s)-c-1)))
		}

	}
	return i
}

func selectParent() Chromosome {
	randomNumber := rand.Intn(totalFitness)
	accumulatedFitness := 0

	var index = 0

	for c := 0; accumulatedFitness < randomNumber; c++ {
		index = int(math.Mod(float64(c), float64(poolSize)))
		accumulatedFitness += pool[index].fitness
	}

	return pool[index]
}

func populateNewPool() {

	for c := 0; c < poolSize; c += 2 {

		p1 := selectParent()
		p2 := selectParent()

		r := rand.Intn(1000)
		if r < crossoverRateInt {
			newPool[c], newPool[c+1] = crossover(p1, p2)
		} else {
			newPool[c], newPool[c+1] = p1, p2
		}

		mutate(&newPool[c])
		mutate(&newPool[c+1])
	}
	copy(pool, newPool)
}

func mutate(a *Chromosome) {

	newString := ""

	for i := 0; i < len(a.s); i++ {
		c := a.s[i]
		r := rand.Intn(1000)
		if r < mutationRateInt {
			if c == '0' {
				c = '1'
			} else {
				c = '0'
			}
			a.mutant = true
		}
		newString = newString + string(c)
	}

	a.s = newString

}

func crossover(a Chromosome, b Chromosome) (Chromosome, Chromosome) {
	xop := rand.Intn(len(a.s))

	var d, e Chromosome

	d.s = a.s[0:xop] + b.s[xop:]
	e.s = b.s[0:xop] + a.s[xop:]

	return d, e
}
<commit_msg>go fmt'd<commit_after>// genetic algorithm to solve 8 queens problem
package main

import (
	"fmt"
	"math"
	"math/rand"
	"time"
)

type Chromosome struct {
	s       string
	fitness int
	mutant  bool
}

var (
	poolSize = 250
	totalGenerations = 10000
	mutationRate = 0.002
	crossoverRate = 0.75
	pool = make([]Chromosome, poolSize)
	newPool = make([]Chromosome, poolSize)
	mutationRateInt = int(mutationRate * 1000)
	crossoverRateInt = int(crossoverRate * 1000)
	maxFitness = 0
	totalFitness int
)

func main() {

	if math.Mod(float64(poolSize), 2.0) > 0 {
		fmt.Println("Invalid pool size. Pool size must be even.")
		return
	}

	rand.Seed(time.Now().Unix())

	initializePool()
	computeFitness()

	var generation int

	for generation = 2; generation <= totalGenerations && maxFitness != 13; generation++ {
		populateNewPool()
		computeFitness()
	}

	fmt.Printf("Generation %d\n", generation-1)
	printPool()
	fmt.Printf("maxFitness: %d\n", maxFitness)

}

func randomChromosome() string {

	temp := ""

	for c := 0; c < 24; c++ {
		v := rand.Intn(2)

		if v > 0 {
			temp += "1"
		} else {
			temp += "0"
		}
	}

	return temp

}

func initializePool() {
	for i := 0; i < poolSize; i++ {
		pool[i].s = randomChromosome()
	}
}

func printPool() {
	for i := 0; i < poolSize; i++ {

		mutant := ""
		if pool[i].mutant {
			mutant = "M"
		}

		fmt.Printf("%d: %s [%d, %d, %d, %d, %d, %d, %d, %d] (%d) %f%% %s\n",
			i, pool[i].s,
			binStringToInt(pool[i].s[0:3]),
			binStringToInt(pool[i].s[3:6]),
			binStringToInt(pool[i].s[6:9]),
			binStringToInt(pool[i].s[9:12]),
			binStringToInt(pool[i].s[12:15]),
			binStringToInt(pool[i].s[15:18]),
			binStringToInt(pool[i].s[18:21]),
			binStringToInt(pool[i].s[21:24]),
			pool[i].fitness,
			float64(pool[i].fitness)/float64(totalFitness),
			mutant)
	}
	fmt.Printf("Total Fitness: %d\n", totalFitness)
}

func computeFitness() {
	totalFitness = 0

	for i := 0; i < poolSize; i++ {
		fitness := getFitness(&pool[i])
		totalFitness += fitness
		if fitness > maxFitness {
			maxFitness = fitness
		}
	}
}

func getFitness(chromosome *Chromosome) int {

	fitness := 0

	var g = make([]int, 8)

	g[0] = binStringToInt(chromosome.s[0:3])
	g[1] = binStringToInt(chromosome.s[3:6])
	g[2] = binStringToInt(chromosome.s[6:9])
	g[3] = binStringToInt(chromosome.s[9:12])
	g[4] = binStringToInt(chromosome.s[12:15])
	g[5] = binStringToInt(chromosome.s[15:18])
	g[6] = binStringToInt(chromosome.s[18:21])
	g[7] = binStringToInt(chromosome.s[21:24])

	for c := 0; c < 7; c++ {
		for d := c + 1; d < 8; d++ {
			if g[c] == g[d] {
				fitness++
				break
			}
		}
	}

	// diagonals

	for c := 0; c < 7; c++ {
		for d := c + 1; d < 8; d++ {

			e := int(math.Abs(float64(c - d)))

			if g[c]+e == g[d] || g[c]-e == g[d] {
				fitness++
				break
			}

		}
	}

	chromosome.fitness = 13 - fitness

	return chromosome.fitness
}

func binStringToInt(s string) int {
	i := 0
	for c := len(s) - 1; c >= 0; c-- {
		if s[c] == '1' {
			i += int(math.Pow(2, float64(len(s)-c-1)))
		}

	}
	return i
}

func selectParent() Chromosome {
	randomNumber := rand.Intn(totalFitness)
	accumulatedFitness := 0

	var index = 0

	for c := 0; accumulatedFitness < randomNumber; c++ {
		index = int(math.Mod(float64(c), float64(poolSize)))
		accumulatedFitness += pool[index].fitness
	}

	return pool[index]
}

func populateNewPool() {

	for c := 0; c < poolSize; c += 2 {

		p1 := selectParent()
		p2 := selectParent()

		r := rand.Intn(1000)
		if r < crossoverRateInt {
			newPool[c], newPool[c+1] = crossover(p1, p2)
		} else {
			newPool[c], newPool[c+1] = p1, p2
		}

		mutate(&newPool[c])
		mutate(&newPool[c+1])
	}
	copy(pool, newPool)
}

func mutate(a *Chromosome) {

	newString := ""

	for i := 0; i < len(a.s); i++ {
		c := a.s[i]
		r := rand.Intn(1000)
		if r < mutationRateInt {
			if c == '0' {
				c = '1'
			} else {
				c = '0'
			}
			a.mutant = true
		}
		newString = newString + string(c)
	}

	a.s = newString

}

func crossover(a Chromosome, b Chromosome) (Chromosome, Chromosome) {
	xop := rand.Intn(len(a.s))

	var d, e Chromosome

	d.s = a.s[0:xop] + b.s[xop:]
	e.s = b.s[0:xop] + a.s[xop:]

	return d, e
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2011 Matt Jibson <matt.jibson@gmail.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

// Package fft provides forward and inverse fast Fourier transform functions.
package fft

import (
	"math"
	"os"
	"sync"
)

var factors_lock sync.RWMutex

// radix-2 factors
var factors = map[int][]complex128{}

// bluestein factors
var n2_factors = map[int][]complex128{}
var n2_inv_factors = map[int][]complex128{}

// Ensures the complex multiplication factors exist for an input array of length input_len.
func ensureFactors(input_len int) {
	var cos, sin float64

	factors_lock.Lock()

	for i := 4; i <= input_len; i <<= 1 {
		if _, present := factors[i]; !present {
			factors[i] = make([]complex128, i)
			for n := 0; n < i; n++ {
				if n == 0 {
					sin, cos = 0, 1
				} else if n*4 == i {
					sin, cos = -1, 0
				} else {
					sin, cos = math.Sincos(-2 * math.Pi / float64(i) * float64(n))
				}
				factors[i][n] = complex(cos, sin)
			}
		}
	}

	if _, present := n2_factors[input_len]; !present {
		n2_factors[input_len] = make([]complex128, input_len)
		n2_inv_factors[input_len] = make([]complex128, input_len)

		for i := 0; i < input_len; i++ {
			if i == 0 {
				sin, cos = 0, 1
			} else {
				sin, cos = math.Sincos(math.Pi / float64(input_len) * float64(i*i))
			}
			n2_factors[input_len][i] = complex(cos, sin)
			n2_inv_factors[input_len][i] = complex(cos, -sin)
		}
	}

	factors_lock.Unlock()
}

// FFTReal returns the forward FFT of the real-valued slice.
func FFTReal(x []float64) []complex128 {
	return FFT(toComplex(x))
}

// IFFTReal returns the inverse FFT of the real-valued slice.
func IFFTReal(x []float64) []complex128 {
	return IFFT(toComplex(x))
}

// toComplex returns the complex equivalent of the real-valued slice.
func toComplex(x []float64) []complex128 {
	y := make([]complex128, len(x))
	for n, v := range x {
		y[n] = complex(v, 0)
	}
	return y
}

// IFFT returns the inverse FFT of the complex-valued slice.
func IFFT(x []complex128) []complex128 {
	lx := len(x)
	r := make([]complex128, lx)

	// Reverse inputs, which is calculated with modulo N, hence x[0] as an outlier
	r[0] = x[0]
	for i := 1; i < lx; i++ {
		r[i] = x[lx-i]
	}

	r = FFT(r)

	N := complex(float64(lx), 0)
	for n, _ := range r {
		r[n] /= N
	}
	return r
}

// Convolve returns the convolution of x * y.
func Convolve(x, y []complex128) ([]complex128, os.Error) {
	if len(x) != len(y) {
		return []complex128{}, os.NewError("fft: input arrays are not of equal length")
	}

	fft_x := FFT(x)
	fft_y := FFT(y)

	r := make([]complex128, len(x))
	for i := 0; i < len(r); i++ {
		r[i] = fft_x[i] * fft_y[i]
	}

	return IFFT(r), nil
}

// FFT returns the forward FFT of the complex-valued slice.
func FFT(x []complex128) []complex128 {
	lx := len(x)

	// todo: non-hack handling length <= 1 cases
	if lx <= 1 {
		r := make([]complex128, lx)
		copy(r, x)
		return r
	}

	if isPowerOf2(lx) {
		return radix2FFT(x)
	}

	return bluesteinFFT(x)
}

// radix2FFT returns the FFT calculated using the radix-2 DIT Cooley-Tukey algorithm.
func radix2FFT(x []complex128) []complex128 {
	lx := len(x)
	ensureFactors(lx)

	lx_2 := lx / 2
	r := make([]complex128, lx) // result
	t := make([]complex128, lx) // temp
	copy(r, x)

	// split into even and odd parts for each stage
	for block_sz := lx; block_sz > 1; block_sz >>= 1 {
		i := 0
		bs_2 := block_sz / 2
		for block := 0; block < lx/block_sz; block++ {
			for n := 0; n < bs_2; n++ {
				bn := block_sz*block + n
				t[bn] = r[i]
				i++
				t[bn+bs_2] = r[i]
				i++
			}
		}
		copy(r, t)
	}

	for stage := 2; stage <= lx; stage <<= 1 {
		if stage == 2 { // 2-point transforms
			for n := 0; n < lx_2; n++ {
				t[n*2] = r[n*2] + r[n*2+1]
				t[n*2+1] = r[n*2] - r[n*2+1]
			}
		} else { // >2-point transforms
			blocks := lx / stage
			s_2 := stage / 2

			for n := 0; n < blocks; n++ {
				nb := n * stage
				for j := 0; j < s_2; j++ {
					w_n := r[j+nb+s_2] * factors[stage][j]
					t[j+nb] = r[j+nb] + w_n
					t[j+nb+s_2] = r[j+nb] - w_n
				}
			}
		}

		copy(r, t)
	}

	return r
}

// bluesteinFFT returns the FFT calculated using the Bluestein algorithm.
func bluesteinFFT(x []complex128) []complex128 {
	lx := len(x)
	a := zeroPad(x, nextPowerOf2(lx*2-1))
	la := len(a)
	ensureFactors(lx)

	for n, v := range x {
		a[n] = v * n2_inv_factors[lx][n]
	}

	b := make([]complex128, la)
	for i := 0; i < lx; i++ {
		b[i] = n2_factors[lx][i]

		if i != 0 {
			b[la-i] = n2_factors[lx][i]
		}
	}

	r, _ := Convolve(a, b)

	for i := 0; i < lx; i++ {
		r[i] *= n2_inv_factors[lx][i]
	}

	return r[:lx]
}

// isPowerOf2 returns true if x is a power of 2, else false.
func isPowerOf2(x int) bool {
	return x&(x-1) == 0
}

// nextPowerOf2 returns the next power of 2 >= x.
func nextPowerOf2(x int) int {
	if isPowerOf2(x) {
		return x
	}

	return int(math.Pow(2, math.Ceil(math.Log2(float64(x)))))
}

// zeroPad returns x with zeros appended to the end to the specified length.
// If len(x) == length, x is returned.
func zeroPad(x []complex128, length int) []complex128 {
	if len(x) == length {
		return x
	}

	r := make([]complex128, length)
	copy(r, x)
	return r
}

// zeroPad2 returns zeroPad of x, with the length as next power of 2 >= len(x).
func zeroPad2(x []complex128) []complex128 {
	return zeroPad(x, nextPowerOf2(len(x)))
}
<commit_msg>Better factor detection<commit_after>/*
 * Copyright (c) 2011 Matt Jibson <matt.jibson@gmail.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

// Package fft provides forward and inverse fast Fourier transform functions.
package fft

import (
	"math"
	"os"
	"sync"
)

var factors_lock sync.RWMutex

// radix-2 factors
var factors = map[int][]complex128{}

// bluestein factors
var n2_factors = map[int][]complex128{}
var n2_inv_factors = map[int][]complex128{}

// Ensures the complex multiplication factors exist for an input array of length input_len.
func ensureFactors(input_len int) {
	var cos, sin float64

	factors_lock.Lock()

	for i := 4; i <= input_len; i <<= 1 {
		if factors[i] == nil {
			factors[i] = make([]complex128, i)
			for n := 0; n < i; n++ {
				if n == 0 {
					sin, cos = 0, 1
				} else if n*4 == i {
					sin, cos = -1, 0
				} else {
					sin, cos = math.Sincos(-2 * math.Pi / float64(i) * float64(n))
				}
				factors[i][n] = complex(cos, sin)
			}
		}
	}

	if n2_factors[input_len] == nil {
		n2_factors[input_len] = make([]complex128, input_len)
		n2_inv_factors[input_len] = make([]complex128, input_len)

		for i := 0; i < input_len; i++ {
			if i == 0 {
				sin, cos = 0, 1
			} else {
				sin, cos = math.Sincos(math.Pi / float64(input_len) * float64(i*i))
			}
			n2_factors[input_len][i] = complex(cos, sin)
			n2_inv_factors[input_len][i] = complex(cos, -sin)
		}
	}

	factors_lock.Unlock()
}

// FFTReal returns the forward FFT of the real-valued slice.
func FFTReal(x []float64) []complex128 {
	return FFT(toComplex(x))
}

// IFFTReal returns the inverse FFT of the real-valued slice.
func IFFTReal(x []float64) []complex128 {
	return IFFT(toComplex(x))
}

// toComplex returns the complex equivalent of the real-valued slice.
func toComplex(x []float64) []complex128 {
	y := make([]complex128, len(x))
	for n, v := range x {
		y[n] = complex(v, 0)
	}
	return y
}

// IFFT returns the inverse FFT of the complex-valued slice.
func IFFT(x []complex128) []complex128 {
	lx := len(x)
	r := make([]complex128, lx)

	// Reverse inputs, which is calculated with modulo N, hence x[0] as an outlier
	r[0] = x[0]
	for i := 1; i < lx; i++ {
		r[i] = x[lx-i]
	}

	r = FFT(r)

	N := complex(float64(lx), 0)
	for n, _ := range r {
		r[n] /= N
	}
	return r
}

// Convolve returns the convolution of x * y.
func Convolve(x, y []complex128) ([]complex128, os.Error) {
	if len(x) != len(y) {
		return []complex128{}, os.NewError("fft: input arrays are not of equal length")
	}

	fft_x := FFT(x)
	fft_y := FFT(y)

	r := make([]complex128, len(x))
	for i := 0; i < len(r); i++ {
		r[i] = fft_x[i] * fft_y[i]
	}

	return IFFT(r), nil
}

// FFT returns the forward FFT of the complex-valued slice.
func FFT(x []complex128) []complex128 {
	lx := len(x)

	// todo: non-hack handling length <= 1 cases
	if lx <= 1 {
		r := make([]complex128, lx)
		copy(r, x)
		return r
	}

	if isPowerOf2(lx) {
		return radix2FFT(x)
	}

	return bluesteinFFT(x)
}

// radix2FFT returns the FFT calculated using the radix-2 DIT Cooley-Tukey algorithm.
func radix2FFT(x []complex128) []complex128 {
	lx := len(x)
	ensureFactors(lx)

	lx_2 := lx / 2
	r := make([]complex128, lx) // result
	t := make([]complex128, lx) // temp
	copy(r, x)

	// split into even and odd parts for each stage
	for block_sz := lx; block_sz > 1; block_sz >>= 1 {
		i := 0
		bs_2 := block_sz / 2
		for block := 0; block < lx/block_sz; block++ {
			for n := 0; n < bs_2; n++ {
				bn := block_sz*block + n
				t[bn] = r[i]
				i++
				t[bn+bs_2] = r[i]
				i++
			}
		}
		copy(r, t)
	}

	for stage := 2; stage <= lx; stage <<= 1 {
		if stage == 2 { // 2-point transforms
			for n := 0; n < lx_2; n++ {
				t[n*2] = r[n*2] + r[n*2+1]
				t[n*2+1] = r[n*2] - r[n*2+1]
			}
		} else { // >2-point transforms
			blocks := lx / stage
			s_2 := stage / 2

			for n := 0; n < blocks; n++ {
				nb := n * stage
				for j := 0; j < s_2; j++ {
					w_n := r[j+nb+s_2] * factors[stage][j]
					t[j+nb] = r[j+nb] + w_n
					t[j+nb+s_2] = r[j+nb] - w_n
				}
			}
		}

		copy(r, t)
	}

	return r
}

// bluesteinFFT returns the FFT calculated using the Bluestein algorithm.
func bluesteinFFT(x []complex128) []complex128 {
	lx := len(x)
	a := zeroPad(x, nextPowerOf2(lx*2-1))
	la := len(a)
	ensureFactors(lx)

	for n, v := range x {
		a[n] = v * n2_inv_factors[lx][n]
	}

	b := make([]complex128, la)
	for i := 0; i < lx; i++ {
		b[i] = n2_factors[lx][i]

		if i != 0 {
			b[la-i] = n2_factors[lx][i]
		}
	}

	r, _ := Convolve(a, b)

	for i := 0; i < lx; i++ {
		r[i] *= n2_inv_factors[lx][i]
	}

	return r[:lx]
}

// isPowerOf2 returns true if x is a power of 2, else false.
func isPowerOf2(x int) bool {
	return x&(x-1) == 0
}

// nextPowerOf2 returns the next power of 2 >= x.
func nextPowerOf2(x int) int {
	if isPowerOf2(x) {
		return x
	}

	return int(math.Pow(2, math.Ceil(math.Log2(float64(x)))))
}

// zeroPad returns x with zeros appended to the end to the specified length.
// If len(x) == length, x is returned.
func zeroPad(x []complex128, length int) []complex128 {
	if len(x) == length {
		return x
	}

	r := make([]complex128, length)
	copy(r, x)
	return r
}

// zeroPad2 returns zeroPad of x, with the length as next power of 2 >= len(x).
func zeroPad2(x []complex128) []complex128 {
	return zeroPad(x, nextPowerOf2(len(x)))
}
<|endoftext|>


<commit_before>// Copyright 2017 The Ebiten Authors
//
// 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 convert

import (
	"io"
	"math"

	"github.com/hajimehoshi/ebiten/audio"
	"github.com/hajimehoshi/ebiten/internal/web"
)

func sinc(x float64) float64 {
	if x == 0 {
		return 1
	}
	return math.Sin(x) / x
}

type Resampling struct {
	source       audio.ReadSeekCloser
	size         int64
	from         int
	to           int
	pos          int64
	srcBlock     int64
	srcBufL      map[int64][]float64
	srcBufR      map[int64][]float64
	lruSrcBlocks []int64
}

const resamplingBufferSize = 4096

func NewResampling(source audio.ReadSeekCloser, size int64, from, to int) *Resampling {
	r := &Resampling{
		source:   source,
		size:     size,
		from:     from,
		to:       to,
		srcBlock: -1,
		srcBufL:  map[int64][]float64{},
		srcBufR:  map[int64][]float64{},
	}
	return r
}

func (r *Resampling) Size() int64 {
	s := int64(float64(r.size) * float64(r.to) / float64(r.from))
	return s / 4 * 4
}

func (r *Resampling) src(i int) (float64, float64, error) {
	// Use int here since int64 is very slow on browsers.
	// TODO: Resampling is too heavy on browsers. How about using OfflineAudioContext?
	if i < 0 {
		return 0, 0, nil
	}
	if r.size/4 <= int64(i) {
		return 0, 0, nil
	}
	nextPos := int64(i) / resamplingBufferSize
	if _, ok := r.srcBufL[nextPos]; !ok {
		if r.srcBlock+1 != nextPos {
			if _, err := r.source.Seek(nextPos*resamplingBufferSize*4, io.SeekStart); err != nil {
				return 0, 0, err
			}
		}
		buf := make([]uint8, resamplingBufferSize*4)
		c := 0
		for c < len(buf) {
			n, err := r.source.Read(buf[c:])
			c += n
			if err != nil {
				if err == io.EOF {
					break
				}
				return 0, 0, err
			}
		}
		buf = buf[:c]
		sl := make([]float64, resamplingBufferSize)
		sr := make([]float64, resamplingBufferSize)
		for i := 0; i < len(buf)/4; i++ {
			sl[i] = float64(int16(buf[4*i])|(int16(buf[4*i+1])<<8)) / (1<<15 - 1)
			sr[i] = float64(int16(buf[4*i+2])|(int16(buf[4*i+3])<<8)) / (1<<15 - 1)
		}
		r.srcBlock = nextPos
		r.srcBufL[r.srcBlock] = sl
		r.srcBufR[r.srcBlock] = sr
		// To keep srcBufL/R not too big, let's remove the least used buffers.
		if len(r.lruSrcBlocks) >= 4 {
			p := r.lruSrcBlocks[0]
			delete(r.srcBufL, p)
			delete(r.srcBufR, p)
			r.lruSrcBlocks = r.lruSrcBlocks[1:]
		}
		r.lruSrcBlocks = append(r.lruSrcBlocks, r.srcBlock)
	} else {
		r.srcBlock = nextPos
		idx := -1
		for i, p := range r.lruSrcBlocks {
			if p == r.srcBlock {
				idx = i
				break
			}
		}
		if idx == -1 {
			panic("not reach")
		}
		r.lruSrcBlocks = append(r.lruSrcBlocks[:idx], r.lruSrcBlocks[idx+1:]...)
		r.lruSrcBlocks = append(r.lruSrcBlocks, r.srcBlock)
	}
	ii := i % resamplingBufferSize
	return r.srcBufL[r.srcBlock][ii], r.srcBufR[r.srcBlock][ii], nil
}

func (r *Resampling) at(t int64) (float64, float64, error) {
	windowSize := 8
	if web.IsBrowser() {
		windowSize = 4
	}
	tInSrc := float64(t) * float64(r.from) / float64(r.to)
	startN := int64(tInSrc) - int64(windowSize)
	if startN < 0 {
		startN = 0
	}
	if r.size/4 <= startN {
		startN = r.size/4 - 1
	}
	endN := int64(tInSrc) + int64(windowSize) + 1
	if r.size/4 <= endN {
		endN = r.size/4 - 1
	}
	lv := 0.0
	rv := 0.0
	for n := startN; n < endN; n++ {
		srcL, srcR, err := r.src(int(n))
		if err != nil {
			return 0, 0, err
		}
		w := 0.5 + 0.5*math.Cos(2*math.Pi*(tInSrc-float64(n))/(float64(windowSize)*2+1))
		s := sinc(math.Pi*(tInSrc-float64(n))) * w
		lv += srcL * s
		rv += srcR * s
	}
	if lv < -1 {
		lv = -1
	}
	if lv > 1 {
		lv = 1
	}
	if rv < -1 {
		rv = -1
	}
	if rv > 1 {
		rv = 1
	}
	return lv, rv, nil
}

func (r *Resampling) Read(b []uint8) (int, error) {
	if r.pos == r.Size() {
		return 0, io.EOF
	}
	n := len(b) / 4 * 4
	if r.Size()-r.pos <= int64(n) {
		n = int(r.Size() - r.pos)
	}
	for i := 0; i < n/4; i++ {
		l, r, err := r.at(r.pos/4 + int64(i))
		if err != nil {
			return 0, err
		}
		l16 := int16(l * (1<<15 - 1))
		r16 := int16(r * (1<<15 - 1))
		b[4*i] = uint8(l16)
		b[4*i+1] = uint8(l16 >> 8)
		b[4*i+2] = uint8(r16)
		b[4*i+3] = uint8(r16 >> 8)
	}
	r.pos += int64(n)
	return n, nil
}

func (r *Resampling) Seek(offset int64, whence int) (int64, error) {
	switch whence {
	case io.SeekStart:
		r.pos = offset
	case io.SeekCurrent:
		r.pos += offset
	case io.SeekEnd:
		r.pos += r.Size() + offset
	}
	if r.pos < 0 {
		r.pos = 0
	}
	if r.Size() <= r.pos {
		r.pos = r.Size()
	}
	return r.pos, nil
}

func (r *Resampling) Close() error {
	return r.source.Close()
}
<commit_msg>audio/internal/convert: Use float64 for positions<commit_after>// Copyright 2017 The Ebiten Authors
//
// 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 convert

import (
	"io"
	"math"

	"github.com/hajimehoshi/ebiten/audio"
	"github.com/hajimehoshi/ebiten/internal/web"
)

func sinc(x float64) float64 {
	if x == 0 {
		return 1
	}
	return math.Sin(x) / x
}

type Resampling struct {
	source       audio.ReadSeekCloser
	size         int64
	from         int
	to           int
	pos          int64
	srcBlock     int64
	srcBufL      map[int64][]float64
	srcBufR      map[int64][]float64
	lruSrcBlocks []int64
}

const resamplingBufferSize = 4096

func NewResampling(source audio.ReadSeekCloser, size int64, from, to int) *Resampling {
	r := &Resampling{
		source:   source,
		size:     size,
		from:     from,
		to:       to,
		srcBlock: -1,
		srcBufL:  map[int64][]float64{},
		srcBufR:  map[int64][]float64{},
	}
	return r
}

func (r *Resampling) Size() int64 {
	s := int64(float64(r.size) * float64(r.to) / float64(r.from))
	return s / 4 * 4
}

func (r *Resampling) src(i int) (float64, float64, error) {
	// Use int here since int64 is very slow on browsers.
	// TODO: Resampling is too heavy on browsers. How about using OfflineAudioContext?
	if i < 0 {
		return 0, 0, nil
	}
	if r.size/4 <= int64(i) {
		return 0, 0, nil
	}
	nextPos := int64(i) / resamplingBufferSize
	if _, ok := r.srcBufL[nextPos]; !ok {
		if r.srcBlock+1 != nextPos {
			if _, err := r.source.Seek(nextPos*resamplingBufferSize*4, io.SeekStart); err != nil {
				return 0, 0, err
			}
		}
		buf := make([]uint8, resamplingBufferSize*4)
		c := 0
		for c < len(buf) {
			n, err := r.source.Read(buf[c:])
			c += n
			if err != nil {
				if err == io.EOF {
					break
				}
				return 0, 0, err
			}
		}
		buf = buf[:c]
		sl := make([]float64, resamplingBufferSize)
		sr := make([]float64, resamplingBufferSize)
		for i := 0; i < len(buf)/4; i++ {
			sl[i] = float64(int16(buf[4*i])|(int16(buf[4*i+1])<<8)) / (1<<15 - 1)
			sr[i] = float64(int16(buf[4*i+2])|(int16(buf[4*i+3])<<8)) / (1<<15 - 1)
		}
		r.srcBlock = nextPos
		r.srcBufL[r.srcBlock] = sl
		r.srcBufR[r.srcBlock] = sr
		// To keep srcBufL/R not too big, let's remove the least used buffers.
		if len(r.lruSrcBlocks) >= 4 {
			p := r.lruSrcBlocks[0]
			delete(r.srcBufL, p)
			delete(r.srcBufR, p)
			r.lruSrcBlocks = r.lruSrcBlocks[1:]
		}
		r.lruSrcBlocks = append(r.lruSrcBlocks, r.srcBlock)
	} else {
		r.srcBlock = nextPos
		idx := -1
		for i, p := range r.lruSrcBlocks {
			if p == r.srcBlock {
				idx = i
				break
			}
		}
		if idx == -1 {
			panic("not reach")
		}
		r.lruSrcBlocks = append(r.lruSrcBlocks[:idx], r.lruSrcBlocks[idx+1:]...)
		r.lruSrcBlocks = append(r.lruSrcBlocks, r.srcBlock)
	}
	ii := i % resamplingBufferSize
	return r.srcBufL[r.srcBlock][ii], r.srcBufR[r.srcBlock][ii], nil
}

func (r *Resampling) at(t int64) (float64, float64, error) {
	windowSize := 8.0
	if web.IsBrowser() {
		windowSize = 4.0
	}
	tInSrc := float64(t) * float64(r.from) / float64(r.to)
	startN := tInSrc - windowSize
	if startN < 0 {
		startN = 0
	}
	if float64(r.size/4) <= startN {
		startN = float64(r.size/4) - 1
	}
	endN := tInSrc + windowSize + 1
	if float64(r.size/4) <= endN {
		endN = float64(r.size/4) - 1
	}
	lv := 0.0
	rv := 0.0
	for n := startN; n < endN; n++ {
		srcL, srcR, err := r.src(int(n))
		if err != nil {
			return 0, 0, err
		}
		w := 0.5 + 0.5*math.Cos(2*math.Pi*(tInSrc-n)/(windowSize*2+1))
		s := sinc(math.Pi*(tInSrc-n)) * w
		lv += srcL * s
		rv += srcR * s
	}
	if lv < -1 {
		lv = -1
	}
	if lv > 1 {
		lv = 1
	}
	if rv < -1 {
		rv = -1
	}
	if rv > 1 {
		rv = 1
	}
	return lv, rv, nil
}

func (r *Resampling) Read(b []uint8) (int, error) {
	if r.pos == r.Size() {
		return 0, io.EOF
	}
	n := len(b) / 4 * 4
	if r.Size()-r.pos <= int64(n) {
		n = int(r.Size() - r.pos)
	}
	for i := 0; i < n/4; i++ {
		l, r, err := r.at(r.pos/4 + int64(i))
		if err != nil {
			return 0, err
		}
		l16 := int16(l * (1<<15 - 1))
		r16 := int16(r * (1<<15 - 1))
		b[4*i] = uint8(l16)
		b[4*i+1] = uint8(l16 >> 8)
		b[4*i+2] = uint8(r16)
		b[4*i+3] = uint8(r16 >> 8)
	}
	r.pos += int64(n)
	return n, nil
}

func (r *Resampling) Seek(offset int64, whence int) (int64, error) {
	switch whence {
	case io.SeekStart:
		r.pos = offset
	case io.SeekCurrent:
		r.pos += offset
	case io.SeekEnd:
		r.pos += r.Size() + offset
	}
	if r.pos < 0 {
		r.pos = 0
	}
	if r.Size() <= r.pos {
		r.pos = r.Size()
	}
	return r.pos, nil
}

func (r *Resampling) Close() error {
	return r.source.Close()
}
<|endoftext|>