<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"net/url"
	"os"
	"sort"
	"strings"
)

const packageTemplateString = `<!DOCTYPE html>

		<meta charset="utf-8">
		<title>{{.Repo.PackageName}}.{{.Repo.MajorVersion}}{{.Repo.SubPath}} - {{.Repo.GopkgPath}}</title>
		<link href='//fonts.googleapis.com/css?family=Ubuntu+Mono|Ubuntu' rel='stylesheet' >
		<link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet" >
		<link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet" >

{{.Repo.GopkgPath}}

							{{.Synopsis}}

						 Source Code
						 API Documentation

Getting started

To get the package, execute:

go get {{.Repo.GopkgPath}}

To import this package, add the following line to your code:

import "{{.Repo.GopkgPath}}"

								{{if .CleanPackageName}}
Refer to it as {{.CleanPackageName}}.{{end}}

For more details, see the API documentation.

Versions

						{{ if .LatestVersions }}
							{{ range .LatestVersions }}

									v{{.Major}}
									→
									{{.}}

							{{ end }}
						{{ else }}

								v0
								→
								master

						{{ end }}

gopkg.in

`

var packageTemplate *template.Template

func gopkgVersionRoot(repo *Repo, version Version) string {
	return repo.GopkgVersionRoot(version)
}

var packageFuncs = template.FuncMap{
	"gopkgVersionRoot": gopkgVersionRoot,
}

func init() {
	var err error
	packageTemplate, err = template.New("page").Funcs(packageFuncs).Parse(packageTemplateString)
	if err != nil {
		fmt.Fprintf(os.Stderr, "fatal: parsing package template failed: %s\n", err)
		os.Exit(1)
	}
}

type packageData struct {
	Repo             *Repo
	LatestVersions   VersionList // Contains only the latest version for each major
	FullVersion      Version     // Version that the major requested resolves to
	CleanPackageName string
	Synopsis         string
}

// SearchResults is used with the GDDO (godoc.org) search API
type SearchResults struct {
	Results []struct {
		Path     string `json:"path"`
		Synopsis string `json:"synopsis"`
	} `json:"results"`
}

func renderPackagePage(resp http.ResponseWriter, req *http.Request, repo *Repo) {
	data := &packageData{
		Repo: repo,
	}

	// calculate version mapping
	latestVersionsMap := make(map[int]Version)
	for _, v := range repo.AllVersions {
		v2, exists := latestVersionsMap[v.Major]
		if !exists || v2.Less(v) {
			latestVersionsMap[v.Major] = v
		}
	}
	data.FullVersion = latestVersionsMap[repo.MajorVersion.Major]
	data.LatestVersions = make(VersionList, 0, len(latestVersionsMap))
	for _, v := range latestVersionsMap {
		data.LatestVersions = append(data.LatestVersions, v)
	}
	sort.Sort(sort.Reverse(data.LatestVersions))

	// find clean package name
	data.CleanPackageName = repo.PackageName
	if strings.HasPrefix(data.CleanPackageName, "go-") {
		data.CleanPackageName = data.CleanPackageName[3:]
	}
	if strings.HasSuffix(data.CleanPackageName, "-go") {
		data.CleanPackageName = data.CleanPackageName[:len(data.CleanPackageName)-3]
	}
	for i, c := range data.CleanPackageName {
		if c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' {
			continue
		}
		if i > 0 && (c == '_' || c >= '0' && c <= '9') {
			continue
		}
		data.CleanPackageName = ""
		break
	}

	// retrieve synopsis
	str := `http://api.godoc.org/search?q=` + url.QueryEscape(repo.GopkgPath())
	fmt.Println(str)
	searchResp, err := http.Get(str)
	if err == nil {
		searchResults := &SearchResults{}
		err = json.NewDecoder(searchResp.Body).Decode(&searchResults)
		searchResp.Body.Close()
		if err == nil {
			gopkgPath := repo.GopkgPath()
			for _, apiPkg := range searchResults.Results {
				if apiPkg.Path == gopkgPath {
					data.Synopsis = apiPkg.Synopsis
					break
				}
			}
		}
	}

	err = packageTemplate.Execute(resp, data)
	if err != nil {
		log.Printf("error executing tmplPackage: %s\n", err)
	}
}
<commit_msg>s/apiPkg/result<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"net/url"
	"os"
	"sort"
	"strings"
)

const packageTemplateString = `<!DOCTYPE html>

		<meta charset="utf-8">
		<title>{{.Repo.PackageName}}.{{.Repo.MajorVersion}}{{.Repo.SubPath}} - {{.Repo.GopkgPath}}</title>
		<link href='//fonts.googleapis.com/css?family=Ubuntu+Mono|Ubuntu' rel='stylesheet' >
		<link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet" >
		<link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet" >

{{.Repo.GopkgPath}}

							{{.Synopsis}}

						 Source Code
						 API Documentation

Getting started

To get the package, execute:

go get {{.Repo.GopkgPath}}

To import this package, add the following line to your code:

import "{{.Repo.GopkgPath}}"

								{{if .CleanPackageName}}
Refer to it as {{.CleanPackageName}}.{{end}}

For more details, see the API documentation.

Versions

						{{ if .LatestVersions }}
							{{ range .LatestVersions }}

									v{{.Major}}
									→
									{{.}}

							{{ end }}
						{{ else }}

								v0
								→
								master

						{{ end }}

gopkg.in

`

var packageTemplate *template.Template

func gopkgVersionRoot(repo *Repo, version Version) string {
	return repo.GopkgVersionRoot(version)
}

var packageFuncs = template.FuncMap{
	"gopkgVersionRoot": gopkgVersionRoot,
}

func init() {
	var err error
	packageTemplate, err = template.New("page").Funcs(packageFuncs).Parse(packageTemplateString)
	if err != nil {
		fmt.Fprintf(os.Stderr, "fatal: parsing package template failed: %s\n", err)
		os.Exit(1)
	}
}

type packageData struct {
	Repo             *Repo
	LatestVersions   VersionList // Contains only the latest version for each major
	FullVersion      Version     // Version that the major requested resolves to
	CleanPackageName string
	Synopsis         string
}

// SearchResults is used with the GDDO (godoc.org) search API
type SearchResults struct {
	Results []struct {
		Path     string `json:"path"`
		Synopsis string `json:"synopsis"`
	} `json:"results"`
}

func renderPackagePage(resp http.ResponseWriter, req *http.Request, repo *Repo) {
	data := &packageData{
		Repo: repo,
	}

	// calculate version mapping
	latestVersionsMap := make(map[int]Version)
	for _, v := range repo.AllVersions {
		v2, exists := latestVersionsMap[v.Major]
		if !exists || v2.Less(v) {
			latestVersionsMap[v.Major] = v
		}
	}
	data.FullVersion = latestVersionsMap[repo.MajorVersion.Major]
	data.LatestVersions = make(VersionList, 0, len(latestVersionsMap))
	for _, v := range latestVersionsMap {
		data.LatestVersions = append(data.LatestVersions, v)
	}
	sort.Sort(sort.Reverse(data.LatestVersions))

	// find clean package name
	data.CleanPackageName = repo.PackageName
	if strings.HasPrefix(data.CleanPackageName, "go-") {
		data.CleanPackageName = data.CleanPackageName[3:]
	}
	if strings.HasSuffix(data.CleanPackageName, "-go") {
		data.CleanPackageName = data.CleanPackageName[:len(data.CleanPackageName)-3]
	}
	for i, c := range data.CleanPackageName {
		if c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' {
			continue
		}
		if i > 0 && (c == '_' || c >= '0' && c <= '9') {
			continue
		}
		data.CleanPackageName = ""
		break
	}

	// retrieve synopsis
	str := `http://api.godoc.org/search?q=` + url.QueryEscape(repo.GopkgPath())
	fmt.Println(str)
	searchResp, err := http.Get(str)
	if err == nil {
		searchResults := &SearchResults{}
		err = json.NewDecoder(searchResp.Body).Decode(&searchResults)
		searchResp.Body.Close()
		if err == nil {
			gopkgPath := repo.GopkgPath()
			for _, result := range searchResults.Results {
				if result.Path == gopkgPath {
					data.Synopsis = result.Synopsis
					break
				}
			}
		}
	}

	err = packageTemplate.Execute(resp, data)
	if err != nil {
		log.Printf("error executing tmplPackage: %s\n", err)
	}
}
<|endoftext|>


<commit_before>package invdapi

import (
	"errors"

	"github.com/Invoiced/invoiced-go/invdendpoint"
)

type Plan struct {
	*Connection
	*invdendpoint.Plan
}

type Plans []*Plan

func (c *Connection) NewPlan() *Plan {
	plan := new(invdendpoint.Plan)
	return &Plan{c, plan}
}

func (c *Plan) Create(plan *Plan) (*Plan, error) {
	endpoint := invdendpoint.PlanEndpoint

	planResp := new(Plan)

	if plan == nil {
		return nil, errors.New("plan is nil")
	}

	// safe prune file data for creation
	invdPlanDataToCreate, err := SafePlanForCreation(plan.Plan)
	if err != nil {
		return nil, err
	}

	apiErr := c.create(endpoint, invdPlanDataToCreate, planResp)

	if apiErr != nil {
		return nil, apiErr
	}

	planResp.Connection = c.Connection

	return planResp, nil
}

func (c *Plan) Save() error {
	endpoint := invdendpoint.PlanEndpoint + "/" + c.Id

	planResp := new(Plan)

	planDataToUpdate, err := SafePlanForUpdating(c.Plan)
	if err != nil {
		return err
	}

	apiErr := c.update(endpoint, planDataToUpdate, planResp)

	if apiErr != nil {
		return apiErr
	}

	c.Plan = planResp.Plan

	return nil
}

func (c *Plan) Delete() error {
	endpoint := invdendpoint.PlanEndpoint + "/" + c.Id

	err := c.delete(endpoint)
	if err != nil {
		return err
	}

	return nil
}

func (c *Plan) Retrieve(id string) (*Plan, error) {
	endpoint := invdendpoint.PlanEndpoint + "/" + id

	planEndpoint := new(invdendpoint.Plan)

	plan := &Plan{c.Connection, planEndpoint}

	_, err := c.retrieveDataFromAPI(endpoint, plan)
	if err != nil {
		return nil, err
	}

	return plan, nil
}

func (c *Plan) ListAll(filter *invdendpoint.Filter, sort *invdendpoint.Sort) (Plans, error) {
	endpoint := invdendpoint.PlanEndpoint

	endpoint = addFilterAndSort(endpoint, filter, sort)

	plans := make(Plans, 0)

NEXT:
	tmpPlans := make(Plans, 0)

	endpointTmp, apiErr := c.retrieveDataFromAPI(endpoint, &tmpPlans)

	if apiErr != nil {
		return nil, apiErr
	}

	plans = append(plans, tmpPlans...)

	if endpointTmp != "" {
		goto NEXT
	}

	for _, plan := range plans {
		plan.Connection = c.Connection
	}

	return plans, nil
}

// SafeCustomerForCreation prunes plan data for just fields that can be used for creation of a plan
func SafePlanForCreation(plan *invdendpoint.Plan) (*invdendpoint.Plan, error) {
	if plan == nil {
		return nil, errors.New("plan is nil")
	}

	planData := new(invdendpoint.Plan)
	planData.Id = plan.Id
	planData.Object = plan.Object
	planData.Item = plan.Item
	planData.Name = plan.Name
	planData.Currency = plan.Currency
	planData.Amount = plan.Amount
	planData.PricingMode = plan.PricingMode
	planData.QuantityType = plan.QuantityType
	planData.Interval = plan.Interval
	planData.IntervalCount = plan.IntervalCount
	planData.Tiers = plan.Tiers
	planData.CreatedAt = plan.CreatedAt
	planData.Metadata = plan.Metadata

	return planData, nil
}

// SafeTaskForUpdating prunes plan data for just fields that can be used for updating of a plan
func SafePlanForUpdating(plan *invdendpoint.Plan) (*invdendpoint.Plan, error) {
	if plan == nil {
		return nil, errors.New("plan is nil")
	}

	planData := new(invdendpoint.Plan)

	planData.Name = plan.Name
	planData.Metadata = plan.Metadata

	return planData, nil
}
<commit_msg>fix listall plan bug and add other listall methods for plans<commit_after>package invdapi

import (
	"errors"
	"github.com/Invoiced/invoiced-go/invdendpoint"
	"strings"
)

type Plan struct {
	*Connection
	*invdendpoint.Plan
}

type Plans []*Plan

func (c *Connection) NewPlan() *Plan {
	plan := new(invdendpoint.Plan)
	return &Plan{c, plan}
}

func (c *Plan) Create(plan *Plan) (*Plan, error) {
	endpoint := invdendpoint.PlanEndpoint

	planResp := new(Plan)

	if plan == nil {
		return nil, errors.New("plan is nil")
	}

	// safe prune file data for creation
	invdPlanDataToCreate, err := SafePlanForCreation(plan.Plan)
	if err != nil {
		return nil, err
	}

	apiErr := c.create(endpoint, invdPlanDataToCreate, planResp)

	if apiErr != nil {
		return nil, apiErr
	}

	planResp.Connection = c.Connection

	return planResp, nil
}

func (c *Plan) Save() error {
	endpoint := invdendpoint.PlanEndpoint + "/" + c.Id

	planResp := new(Plan)

	planDataToUpdate, err := SafePlanForUpdating(c.Plan)
	if err != nil {
		return err
	}

	apiErr := c.update(endpoint, planDataToUpdate, planResp)

	if apiErr != nil {
		return apiErr
	}

	c.Plan = planResp.Plan

	return nil
}

func (c *Plan) Delete() error {
	endpoint := invdendpoint.PlanEndpoint + "/" + c.Id

	err := c.delete(endpoint)
	if err != nil {
		return err
	}

	return nil
}

func (c *Plan) Retrieve(id string) (*Plan, error) {
	endpoint := invdendpoint.PlanEndpoint + "/" + id
	planEndpoint := new(invdendpoint.Plan)

	plan := &Plan{c.Connection, planEndpoint}

	_, err := c.retrieveDataFromAPI(endpoint, plan)
	if err != nil {
		return nil, err
	}

	return plan, nil
}

func (c *Plan) RetrieveWithSubNumber(id string) (*Plan, error) {
	endpoint := invdendpoint.PlanEndpoint + "/" + id + "?include=num_subscriptions"

	planEndpoint := new(invdendpoint.Plan)

	plan := &Plan{c.Connection, planEndpoint}

	_, err := c.retrieveDataFromAPI(endpoint, plan)
	if err != nil {
		return nil, err
	}

	return plan, nil
}

func (c *Plan) ListAllSubNumber(filter *invdendpoint.Filter, sort *invdendpoint.Sort) (Plans, error) {
	endpoint := invdendpoint.PlanEndpoint

	endpoint = addFilterAndSort(endpoint, filter, sort)

	if strings.Contains(endpoint,"?") {
		endpoint = endpoint + "&include=num_subscriptions"
	} else {
		endpoint = endpoint + "?include=num_subscriptions"
	}

	plans := make(Plans, 0)

NEXT:
	tmpPlans := make(Plans, 0)

	endpoint, apiErr := c.retrieveDataFromAPI(endpoint, &tmpPlans)

	if apiErr != nil {
		return nil, apiErr
	}

	plans = append(plans, tmpPlans...)

	if endpoint != "" {
		goto NEXT
	}

	for _, plan := range plans {
		plan.Connection = c.Connection
	}

	return plans, nil
}

func (c *Plan) ListAll(filter *invdendpoint.Filter, sort *invdendpoint.Sort) (Plans, error) {
	endpoint := invdendpoint.PlanEndpoint

	endpoint = addFilterAndSort(endpoint, filter, sort)

	plans := make(Plans, 0)

NEXT:
	tmpPlans := make(Plans, 0)

	endpoint, apiErr := c.retrieveDataFromAPI(endpoint, &tmpPlans)

	if apiErr != nil {
		return nil, apiErr
	}

	plans = append(plans, tmpPlans...)

	if endpoint != "" {
		goto NEXT
	}

	for _, plan := range plans {
		plan.Connection = c.Connection
	}

	return plans, nil
}

// SafeCustomerForCreation prunes plan data for just fields that can be used for creation of a plan
func SafePlanForCreation(plan *invdendpoint.Plan) (*invdendpoint.Plan, error) {
	if plan == nil {
		return nil, errors.New("plan is nil")
	}

	planData := new(invdendpoint.Plan)
	planData.Id = plan.Id
	planData.Object = plan.Object
	planData.Item = plan.Item
	planData.Name = plan.Name
	planData.Currency = plan.Currency
	planData.Amount = plan.Amount
	planData.PricingMode = plan.PricingMode
	planData.QuantityType = plan.QuantityType
	planData.Interval = plan.Interval
	planData.IntervalCount = plan.IntervalCount
	planData.Tiers = plan.Tiers
	planData.CreatedAt = plan.CreatedAt
	planData.Metadata = plan.Metadata

	return planData, nil
}

// SafeTaskForUpdating prunes plan data for just fields that can be used for updating of a plan
func SafePlanForUpdating(plan *invdendpoint.Plan) (*invdendpoint.Plan, error) {
	if plan == nil {
		return nil, errors.New("plan is nil")
	}

	planData := new(invdendpoint.Plan)

	planData.Name = plan.Name
	planData.Metadata = plan.Metadata

	return planData, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"math"
	"time"
)

type Line struct {
	Moves []Move
}

const INFINITY int = int(math.MaxInt32) // I win!
const MATE int = INFINITY - 10          // Value of a checkmate in 1

var nodecount uint64
var abort bool

func Evaluate(board *Board) int {
	phase := calcphase(board)
	opening := MaterialCount(board, false)
	endgame := MaterialCount(board, true)
	score := ((opening * (256 - phase)) + (endgame * phase)) / 256
	if board.ToMove == BLACK {
		score = -score
	}
	return score
}

func calcphase(board *Board) int {
	TotalPhase := 24 // PawnPhase*16 + KnightPhase*4 + BishopPhase*4 + RookPhase*4 + QueenPhase*2
	phase := TotalPhase
	for _, i := range board.PieceList {
		phase -= PValue[GetPiece(board.Data[i])]
	}
	return (phase*256 + (TotalPhase / 2)) / TotalPhase
}

func MaterialCount(b *Board, endgame bool) int {
	var retval int
	for _, i := range b.PieceList {
		if OnBoard(i) && GetPiece(b.Data[i]) != EMPTY {
			if GetSide(b.Data[i]) == WHITE {
				retval += Value[GetPiece(b.Data[i])] + Pst(GetPiece(b.Data[i]), WHITE, i, endgame)
			} else {
				retval -= (Value[GetPiece(b.Data[i])] + Pst(GetPiece(b.Data[i]), BLACK, i, endgame))
			}
		}
	}
	return retval
}

func Pst(piece, side, index byte, endgame bool) int {
	switch piece {
	case PAWN:
		return GetPst(index, side, pstPawnMg[:], pstPawnEg[:], endgame)
	case KNIGHT:
		return GetPst(index, side, pstKnightMg[:], pstKnightEg[:], endgame)
	case BISHOP:
		return GetPst(index, side, pstBishopMg[:], pstBishopEg[:], endgame)
	case ROOK:
		return GetPst(index, side, pstRookMg[:], pstRookEg[:], endgame)
	case QUEEN:
		return GetPst(index, side, pstQueenMg[:], pstQueenEg[:], endgame)
	case KING:
		return GetPst(index, side, pstKingMg[:], pstKingEg[:], endgame)
	default:
		return 0
	}
}

func GetPst(index, side byte, tableMg []int, tableEg []int, endgame bool) int {
	var table []int
	if endgame {
		table = tableEg[:]
	} else {
		table = tableMg[:]
	}
	file, rank := IndexToCartesian(index)
	var tableindex byte
	if side == BLACK {
		tableindex = (8 * (7 - rank)) + file
	} else {
		tableindex = (8 * rank) + file
	}
	return table[tableindex]
}

func Quies(board *Board, alpha, beta int) int {
	nodecount++
	if abort {
		return 0
	}
	eval := Evaluate(board)
	if eval >= beta {
		return beta
	}
	if eval > alpha {
		alpha = eval
	}
	moves := FilterCaptures(MoveGen(board))
	for _, move := range moves {
		undo := MakeMove(board, &move)
		if Illegal(board) {
			UnmakeMove(board, &move, undo)
			continue
		}
		val := -Quies(board, -beta, -alpha)
		UnmakeMove(board, &move, undo)
		if abort {
			return 0
		}
		if val >= beta {
			return beta
		}
		if val > alpha {
			alpha = val
		}
	}
	return alpha
}

func AlphaBeta(board *Board, depth, alpha, beta, mate int, pline *Line) int {
	nodecount++
	if abort {
		return 0
	}
	legal := 0
	if depth <= 0 {
		return Quies(board, alpha, beta)
	}
	line := new(Line)
	moves := MoveGen(board)
	for _, move := range moves {
		undo := MakeMove(board, &move)
		if Illegal(board) {
			UnmakeMove(board, &move, undo)
			continue
		}
		val := -AlphaBeta(board, depth-1, -beta, -alpha, mate-1, line)
		UnmakeMove(board, &move, undo)
		if abort {
			return 0
		}
		if val >= beta {
			return beta
		}
		if val > alpha {
			alpha = val
			pline.Moves = append([]Move{move}, pline.Moves...)
			line.Moves = append(pline.Moves, move)
		}
		legal++
	}
	if legal == 0 {
		if !InCheck(board) {
			return 0
		}
		return -mate
	}
	return alpha
}

func AllotTime(board *Board) time.Duration {
	repeat := TimeRepeat
	if repeat <= 0 {
		repeat = 40
	}
	moves := repeat - board.Moves
	for moves <= 0 {
		moves += repeat
	}
	return (Clock/time.Duration(moves+1) - 20*time.Millisecond)
}

func ThinkingOutput(depth, score int, start time.Time, pv *Line) {
	fmt.Println(depth, score, int64(time.Since(start)/time.Millisecond)/10, nodecount, pv)
}

func SleepThread(board *Board, start time.Time) {
	bedoneby := AllotTime(board)
	fmt.Println("# ", Clock, ": allocated ", bedoneby)
	time.Sleep(bedoneby)
	abort = true
}

func FindMove(board *Board) *Move {
	start := time.Now()
	abort = false
	nodecount = 0
	retval := new(Move)
	for depth := 1; ; depth++ {
		line := new(Line)
		score := AlphaBeta(board, depth, -INFINITY, INFINITY, MATE, line)
		ThinkingOutput(depth, score, start, line)
		if !abort {
			retval = &line.Moves[0]
		} else {
			break
		}

		if depth == 1 {
			Clock -= time.Since(start)
			go SleepThread(board, start)
		}
	}
	return retval
}
<commit_msg>Fix PV handling<commit_after>package main

import (
	"fmt"
	"math"
	"time"
)

const INFINITY int = int(math.MaxInt32) // I win!
const MATE int = INFINITY - 10          // Value of a checkmate in 1

var nodecount uint64
var abort bool

func Evaluate(board *Board) int {
	phase := calcphase(board)
	opening := MaterialCount(board, false)
	endgame := MaterialCount(board, true)
	score := ((opening * (256 - phase)) + (endgame * phase)) / 256
	if board.ToMove == BLACK {
		score = -score
	}
	return score
}

func calcphase(board *Board) int {
	TotalPhase := 24 // PawnPhase*16 + KnightPhase*4 + BishopPhase*4 + RookPhase*4 + QueenPhase*2
	phase := TotalPhase
	for _, i := range board.PieceList {
		phase -= PValue[GetPiece(board.Data[i])]
	}
	return (phase*256 + (TotalPhase / 2)) / TotalPhase
}

func MaterialCount(b *Board, endgame bool) int {
	var retval int
	for _, i := range b.PieceList {
		if OnBoard(i) && GetPiece(b.Data[i]) != EMPTY {
			if GetSide(b.Data[i]) == WHITE {
				retval += Value[GetPiece(b.Data[i])] + Pst(GetPiece(b.Data[i]), WHITE, i, endgame)
			} else {
				retval -= (Value[GetPiece(b.Data[i])] + Pst(GetPiece(b.Data[i]), BLACK, i, endgame))
			}
		}
	}
	return retval
}

func Pst(piece, side, index byte, endgame bool) int {
	switch piece {
	case PAWN:
		return GetPst(index, side, pstPawnMg[:], pstPawnEg[:], endgame)
	case KNIGHT:
		return GetPst(index, side, pstKnightMg[:], pstKnightEg[:], endgame)
	case BISHOP:
		return GetPst(index, side, pstBishopMg[:], pstBishopEg[:], endgame)
	case ROOK:
		return GetPst(index, side, pstRookMg[:], pstRookEg[:], endgame)
	case QUEEN:
		return GetPst(index, side, pstQueenMg[:], pstQueenEg[:], endgame)
	case KING:
		return GetPst(index, side, pstKingMg[:], pstKingEg[:], endgame)
	default:
		return 0
	}
}

func GetPst(index, side byte, tableMg []int, tableEg []int, endgame bool) int {
	var table []int
	if endgame {
		table = tableEg[:]
	} else {
		table = tableMg[:]
	}
	file, rank := IndexToCartesian(index)
	var tableindex byte
	if side == BLACK {
		tableindex = (8 * (7 - rank)) + file
	} else {
		tableindex = (8 * rank) + file
	}
	return table[tableindex]
}

func Quies(board *Board, alpha, beta int) int {
	nodecount++
	if abort {
		return 0
	}
	eval := Evaluate(board)
	if eval >= beta {
		return beta
	}
	if eval > alpha {
		alpha = eval
	}
	moves := FilterCaptures(MoveGen(board))
	for _, move := range moves {
		undo := MakeMove(board, &move)
		if Illegal(board) {
			UnmakeMove(board, &move, undo)
			continue
		}
		val := -Quies(board, -beta, -alpha)
		UnmakeMove(board, &move, undo)
		if abort {
			return 0
		}
		if val >= beta {
			return beta
		}
		if val > alpha {
			alpha = val
		}
	}
	return alpha
}

func AlphaBeta(board *Board, depth, alpha, beta, mate int, pline *[]Move) int {
	nodecount++

	if abort {
		return 0
	}

	legal := 0

	if depth <= 0 {
		*pline = nil
		return Quies(board, alpha, beta)
	}

	var line []Move

	moves := MoveGen(board)

	for _, move := range moves {

		undo := MakeMove(board, &move)

		if Illegal(board) {
			UnmakeMove(board, &move, undo)
			continue
		}

		line = nil

		val := -AlphaBeta(board, depth-1, -beta, -alpha, mate-1, &line)

		UnmakeMove(board, &move, undo)

		if abort {
			return 0
		}

		if val >= beta {
			return beta
		}

		if val > alpha {
			alpha = val
			*pline = append([]Move{move}, line...)
		}

		legal++
	}

	if legal == 0 {

		if !InCheck(board) {
			return 0
		}

		return -mate
	}

	return alpha
}

func AllotTime(board *Board) time.Duration {
	repeat := TimeRepeat
	if repeat <= 0 {
		repeat = 40
	}
	moves := repeat - board.Moves
	for moves <= 0 {
		moves += repeat
	}
	return (Clock/time.Duration(moves+1) - 20*time.Millisecond)
}

func ThinkingOutput(depth, score int, start time.Time, pv []Move) {
	fmt.Println(depth, score, int64(time.Since(start)/time.Millisecond)/10, nodecount, pv)
}

func SleepThread(board *Board, start time.Time) {
	bedoneby := AllotTime(board)
	fmt.Println("# ", Clock, ": allocated ", bedoneby)
	time.Sleep(bedoneby)
	abort = true
}

func FindMove(board *Board) *Move {
	start := time.Now()
	abort = false
	nodecount = 0
	retval := new(Move)
	for depth := 1; ; depth++ {
		var line []Move
		score := AlphaBeta(board, depth, -INFINITY, INFINITY, MATE, &line)
		ThinkingOutput(depth, score, start, line)
		if !abort {
			retval = &line[0]
		} else {
			break
		}

		if depth == 1 {
			Clock -= time.Since(start)
			go SleepThread(board, start)
		}
	}
	return retval
}
<|endoftext|>


<commit_before>package villa

import (
	"os"
	"os/exec"
	"path/filepath"
	"io/ioutil"
)

// Path is a wrapper for a path in the OS
type Path string

/*
	filepath package
*/

func (p Path) Abs() (pth Path, err error) {
	pt, err := filepath.Abs(string(p))
	return Path(pt), err
}

func (p Path) Join(elem ...interface{}) Path {
	els := make(StringSlice, 0, len(elem) + 1)
	els.Add(p).Add(elem...)
	return Path(filepath.Join(els...))
}

func (p Path) Ext() string {
	return filepath.Ext(string(p))
}

/*
	os
*/

// Create is a wrapper to os.Create
func (p Path) Create() (file *os.File, err error) {
	return os.Create(string(p))
}

// Open is a wrapper to os.Open
func (p Path) Open() (file *os.File, err error) {
	return os.Open(string(p))

}
// Open is a wrapper to os.OpenFile
func (p Path) OpenFile(flag int, perm os.FileMode) (file *os.File, err error) {
	return os.OpenFile(string(p), flag, perm)
}

// Mkdir is a wrappter to os.Mkdir
func (p Path) Mkdir(perm os.FileMode) error {
	return os.Mkdir(string(p), perm)
}

// MkdirAll is a wrappter to os.MkdirAll
func (p Path) MkdirAll(perm os.FileMode) error {
	return os.MkdirAll(string(p), perm)
}

// Stat is a wrappter to os.Stat
func (p Path) Stat() (fi os.FileInfo, err error) {
	return os.Stat(string(p))
}

// Symlink is a wrappter to os.Symlink
func (p Path) Symlink(dst Path) error {
	return os.Symlink(string(p), string(dst))
}

/*
	ioutil package
*/

func (p Path) ReadDir() (fi []os.FileInfo, err error) {
	return ioutil.ReadDir(string(p))
}

func (p Path) ReadFile() ([]byte, error) {
	return ioutil.ReadFile(string(p))
}

func (p Path) WriteFile(data []byte, perm os.FileMode) error {
	return ioutil.WriteFile(string(p), data, perm)
}

func (p Path) TempDir(prefix string) (name Path, err error) {
	nm, err := ioutil.TempDir(string(p), prefix)
	return Path(nm), err
}

/*
	exec package
*/

// Command is a wrappter to exec.Command
func (p Path) Command(arg ...string) *exec.Cmd {
	return exec.Command(string(p), arg...)
}

/*
	Composite
*/

// Exists checks whether the file exists
func (p Path) Exists() bool {
	_, err := p.Stat()
	return err == nil
}

// S converts Path back to string
func (p Path) S() string {
	return string(p)
}
<commit_msg>ADD some methods for Path<commit_after>package villa

import (
	"os"
	"os/exec"
	"path/filepath"
	"io/ioutil"
)

// Path is a wrapper for a path in the OS
type Path string

/*
	filepath package
*/

func (p Path) Abs() (pth Path, err error) {
	pt, err := filepath.Abs(string(p))
	return Path(pt), err
}

func (p Path) Join(elem ...interface{}) Path {
	els := make(StringSlice, 0, len(elem) + 1)
	els.Add(p).Add(elem...)
	return Path(filepath.Join(els...))
}

func (p Path) Ext() string {
	return filepath.Ext(string(p))
}

/*
	os
*/

// Create is a wrapper to os.Create
func (p Path) Create() (file *os.File, err error) {
	return os.Create(string(p))
}

// Open is a wrapper to os.Open
func (p Path) Open() (file *os.File, err error) {
	return os.Open(string(p))

}
// Open is a wrapper to os.OpenFile
func (p Path) OpenFile(flag int, perm os.FileMode) (file *os.File, err error) {
	return os.OpenFile(string(p), flag, perm)
}

// Mkdir is a wrappter to os.Mkdir
func (p Path) Mkdir(perm os.FileMode) error {
	return os.Mkdir(string(p), perm)
}

// MkdirAll is a wrappter to os.MkdirAll
func (p Path) MkdirAll(perm os.FileMode) error {
	return os.MkdirAll(string(p), perm)
}

// Remove is a wrappter to os.Remove
func (p Path) Remove() error {
	return os.Remove(string(p))
}

// RemoveAll is a wrappter to os.RemoveAll
func (p Path) RemoveAll() error {
	return os.RemoveAll(string(p))
}

// Rename is a wrappter to os.Rename
func (p Path) Rename(newname Path) error {
	return os.Rename(string(p), string(newname))
}

// Stat is a wrappter to os.Stat
func (p Path) Stat() (fi os.FileInfo, err error) {
	return os.Stat(string(p))
}

// Symlink is a wrappter to os.Symlink
func (p Path) Symlink(dst Path) error {
	return os.Symlink(string(p), string(dst))
}

/*
	ioutil package
*/

func (p Path) ReadDir() (fi []os.FileInfo, err error) {
	return ioutil.ReadDir(string(p))
}

func (p Path) ReadFile() ([]byte, error) {
	return ioutil.ReadFile(string(p))
}

func (p Path) WriteFile(data []byte, perm os.FileMode) error {
	return ioutil.WriteFile(string(p), data, perm)
}

func (p Path) TempDir(prefix string) (name Path, err error) {
	nm, err := ioutil.TempDir(string(p), prefix)
	return Path(nm), err
}

/*
	exec package
*/

// Command is a wrappter to exec.Command
func (p Path) Command(arg ...string) *exec.Cmd {
	return exec.Command(string(p), arg...)
}

/*
	Composite
*/

// Exists checks whether the file exists
func (p Path) Exists() bool {
	_, err := p.Stat()
	return err == nil
}

// S converts Path back to string
func (p Path) S() string {
	return string(p)
}
<|endoftext|>


<commit_before>package gontpd

import (
	"context"
	"fmt"
	"math/bits"
	"time"

	"github.com/beevik/ntp"
)

const (
	ReplyCount           = 8
	MaxRootDelay         = 10 * time.Second
	MaxStratum     uint8 = 15
	minFilterCount       = 3
	maxInterval          = 1024 * time.Second
	minInterval          = 4 * time.Second
	reachStable    uint8 = 1<<8 - 1
	phi                  = 15 * time.Microsecond
)

const (
	stateInit = iota
	stateInvalid
	stateTemporaryDown
	stateSyncing
	stateStable
)

const (
	NoLeap uint8 = iota
	LeapIns
	LeapDel
	NotSync
)

const (
	queryMinInterval = 5 * time.Second
	queryMaxInterval = (1 << 12) * time.Minute
)

var (
	peerTransTable []peerTransitionFunc
	epoch          = time.Unix(0, 0)
)

type peer struct {
	addr       string
	filter     [ReplyCount]*filter
	referTime  time.Time
	updateAt   time.Time
	interval   time.Duration
	offset     time.Duration
	delay      time.Duration
	rootDelay  time.Duration
	rootDisp   time.Duration
	dispersion time.Duration

	filterIndex int
	best        int
	queryCount  int
	referId     uint32
	poll        int8
	leap        uint8
	reach       uint8
	stratum     uint8
	state       uint8
}

type filter struct {
	updateAt   time.Time
	offset     time.Duration
	delay      time.Duration
	dispersion time.Duration
	resp       *ntp.Response
}

func peerInit(p *peer, resp *ntp.Response, err error) {
	if p.queryCount < minFilterCount {
		// keep init
		Debug.Printf("query Count:%d keep initing", p.queryCount)
		return
	}

	if p.reach > 1 {
		p.state = stateSyncing
		Info.Printf("%s init -> syncing", p.addr)
		return
	}

	Warn.Printf("peer:%s has no good query while initing", p.addr)
	p.state = stateInvalid
	Info.Printf("%s init -> invalid", p.addr)
}

func peerInvalid(p *peer, resp *ntp.Response, err error) {
	Error.Fatal("we should not go into here")
}

func peerTemporaryDown(p *peer, resp *ntp.Response, err error) {
	Info.Printf("%s temporary down", p.addr)
	if p.reach&3 != 0 {
		p.state = stateSyncing
		Info.Printf("%s down -> syncing", p.addr)
		return
	}

	p.interval = time.Duration(8-bits.OnesCount8(p.reach)) * time.Minute
}

func peerSyncing(p *peer, resp *ntp.Response, err error) {
	if p.reach&3 == 0 {
		p.state = stateTemporaryDown
		Info.Printf("%s syncing -> temporary down", p.addr)
		p.interval = minInterval
		return
	}

	if p.reach == reachStable {
		Info.Printf("%s syncing -> stable", p.addr)
		p.state = stateStable
	}

	if p.checkFilter() {
		syncClock(p)
	}
	p.interval = time.Duration(bits.OnesCount8(p.reach)) * (10 * time.Second)
}
func peerStable(p *peer, resp *ntp.Response, err error) {

	if err != nil || p.reach != reachStable {
		p.state = stateSyncing
		Info.Printf("%s stable -> syncing", p.addr)
		return
	}

	if p.checkFilter() {
		syncClock(p)
	}
	// offset     interval
	// 0.128s  -> 1024s
	// 0.005s  -> 4s
	p.interval = secondToDuration(absDuration(p.offset).Seconds()*-8992.68 + 1065.46)
}

func syncClock(p *peer) {
	if DebugFlag&NoSyncClock != 0 {
		Debug.Printf("syncClock to:%s, offset:%s", p.addr, p.offset)
		return
	}
	// find median offset from all peers
	select {
	case syncLock <- struct{}{}:
	default:
	}
}

func init() {
	peerTransTable = []peerTransitionFunc{
		stateInit:          peerInit,
		stateInvalid:       peerInvalid,
		stateTemporaryDown: peerTemporaryDown,
		stateSyncing:       peerSyncing,
		stateStable:        peerStable,
	}
}

type peerTransitionFunc func(*peer, *ntp.Response, error)

func newPeer(addr string) *peer {
	p := &peer{
		addr:       addr,
		interval:   queryMinInterval,
		best:       -1,
		offset:     time.Duration(0),
		delay:      time.Minute,
		dispersion: time.Minute,
	}
	for i := 0; i < ReplyCount; i++ {
		p.filter[i] = &filter{
			updateAt:   epoch,
			dispersion: MaxRootDelay,
			delay:      MaxRootDelay,
			offset:     MaxRootDelay,
		}
	}
	return p
}

func (p *peer) insertFilter(resp *ntp.Response) {
	// the fisrt filter is the newest
	for i := ReplyCount - 1; i > 0; i-- {
		if p.filter[i].updateAt.Equal(epoch) {
			continue
		}
		interval := time.Now().Sub(p.filter[i].updateAt)
		p.filter[i] = p.filter[i-1]
		p.filter[i].updateAt = time.Now()
		p.filter[i].dispersion += phi * interval // add up dispersion
	}
	p.filter[0].delay = resp.RTT + resp.RootDelay
	p.filter[0].offset = resp.ClockOffset
	p.filter[0].updateAt = time.Now()
	p.filter[0].dispersion = resp.RootDispersion + p.filter[0].delay/2
	p.filter[0].resp = resp
}

func (p *peer) run(pctx context.Context) {
	ctx, cancel := context.WithCancel(pctx)
	defer cancel()

	Info.Printf("%s started %s", p.addr, p.interval)
	defer Info.Printf("%s stopped", p.addr)

	var timer *time.Timer

	for {
		resp, err := ntp.Query(p.addr)
		p.reach <<= 1
		p.queryCount++
		if err == nil {
			p.reach |= 1
			p.insertFilter(resp)
		}

		peerTransTable[p.state](p, resp, err)

		if p.state == stateInvalid {
			Warn.Printf("peer %s invalid, exited looping", p.addr)
			return
		}
		if p.interval > maxInterval {
			p.interval = maxInterval
		}
		if p.interval < minInterval {
			p.interval = minInterval
		}
		p.interval += randDuration()
		Debug.Printf("%s will sleep %s", p.addr, p.interval)
		timer = time.NewTimer(p.interval)
		select {
		case <-timer.C:
		case <-ctx.Done():
			return
		}
		timer.Stop()
	}
}

func (p *peer) checkFilter() (valid bool) {

	bestIndex := -1
	bestDisp := time.Minute
	validCount := 0

	for i, r := range p.filter {
		if r == nil {
			continue
		}
		if r.dispersion >= MaxRootDelay {
			continue
		}
		validCount += 1
		if r.dispersion < bestDisp {
			bestIndex = i
		}
	}

	if validCount == 0 {
		valid = false
		return
	}

	p.best = bestIndex
	r := p.filter[bestIndex]
	p.dispersion = r.dispersion
	p.rootDelay = r.resp.RootDelay + r.resp.RTT
	p.delay = r.delay
	p.rootDisp = r.resp.RootDispersion
	p.offset = r.resp.ClockOffset
	p.interval = r.resp.Poll
	p.referTime = r.resp.ReferenceTime
	p.referId = r.resp.ReferenceID
	p.stratum = r.resp.Stratum
	p.updateAt = time.Now()
	Debug.Printf("%s choice new filter %d offset=%s", p.addr, bestIndex, p.offset)
	valid = true
	return
}

func (p *peer) String() string {
	return fmt.Sprintf("%s[%s]%s", p.addr, stateToString(p.state), p.offset)
}

func stateToString(u uint8) string {
	switch u {
	case stateInit:
		return "Init"
	case stateStable:
		return "stable"
	case stateInvalid:
		return "invalid"
	case stateTemporaryDown:
		return "down"
	case stateSyncing:
		return "syncing"
	}
	return "unknown"
}
<commit_msg>add validate<commit_after>package gontpd

import (
	"context"
	"fmt"
	"math/bits"
	"time"

	"github.com/beevik/ntp"
)

const (
	ReplyCount           = 8
	MaxRootDelay         = 10 * time.Second
	MaxStratum     uint8 = 15
	minFilterCount       = 3
	maxInterval          = 1024 * time.Second
	minInterval          = 4 * time.Second
	reachStable    uint8 = 1<<8 - 1
	phi                  = 15 * time.Microsecond
)

const (
	stateInit = iota
	stateInvalid
	stateTemporaryDown
	stateSyncing
	stateStable
)

const (
	NoLeap uint8 = iota
	LeapIns
	LeapDel
	NotSync
)

const (
	queryMinInterval = 5 * time.Second
	queryMaxInterval = (1 << 12) * time.Minute
)

var (
	peerTransTable []peerTransitionFunc
	epoch          = time.Unix(0, 0)
)

type peer struct {
	addr       string
	filter     [ReplyCount]*filter
	referTime  time.Time
	updateAt   time.Time
	interval   time.Duration
	offset     time.Duration
	delay      time.Duration
	rootDelay  time.Duration
	rootDisp   time.Duration
	dispersion time.Duration

	filterIndex int
	best        int
	queryCount  int
	referId     uint32
	poll        int8
	leap        uint8
	reach       uint8
	stratum     uint8
	state       uint8
}

type filter struct {
	updateAt   time.Time
	offset     time.Duration
	delay      time.Duration
	dispersion time.Duration
	resp       *ntp.Response
}

func peerInit(p *peer, resp *ntp.Response, err error) {
	if p.queryCount < minFilterCount {
		// keep init
		Debug.Printf("query Count:%d keep initing", p.queryCount)
		return
	}

	if p.reach > 1 {
		p.state = stateSyncing
		Info.Printf("%s init -> syncing", p.addr)
		return
	}

	Warn.Printf("peer:%s has no good query while initing", p.addr)
	p.state = stateInvalid
	Info.Printf("%s init -> invalid", p.addr)
}

func peerInvalid(p *peer, resp *ntp.Response, err error) {
	Error.Fatal("we should not go into here")
}

func peerTemporaryDown(p *peer, resp *ntp.Response, err error) {
	Info.Printf("%s temporary down", p.addr)
	if p.reach&3 != 0 {
		p.state = stateSyncing
		Info.Printf("%s down -> syncing", p.addr)
		return
	}

	p.interval = time.Duration(8-bits.OnesCount8(p.reach)) * time.Minute
}

func peerSyncing(p *peer, resp *ntp.Response, err error) {
	if p.reach&3 == 0 {
		p.state = stateTemporaryDown
		Info.Printf("%s syncing -> temporary down", p.addr)
		p.interval = minInterval
		return
	}

	if p.reach == reachStable {
		Info.Printf("%s syncing -> stable", p.addr)
		p.state = stateStable
	}

	if p.checkFilter() {
		syncClock(p)
	}
	p.interval = time.Duration(bits.OnesCount8(p.reach)) * (10 * time.Second)
}
func peerStable(p *peer, resp *ntp.Response, err error) {

	if err != nil || p.reach != reachStable {
		p.state = stateSyncing
		Info.Printf("%s stable -> syncing", p.addr)
		return
	}

	if p.checkFilter() {
		syncClock(p)
	}
	// offset     interval
	// 0.128s  -> 1024s
	// 0.005s  -> 4s
	p.interval = secondToDuration(absDuration(p.offset).Seconds()*-8992.68 + 1065.46)
}

func syncClock(p *peer) {
	if DebugFlag&NoSyncClock != 0 {
		Debug.Printf("syncClock to:%s, offset:%s", p.addr, p.offset)
		return
	}
	// find median offset from all peers
	select {
	case syncLock <- struct{}{}:
	default:
	}
}

func init() {
	peerTransTable = []peerTransitionFunc{
		stateInit:          peerInit,
		stateInvalid:       peerInvalid,
		stateTemporaryDown: peerTemporaryDown,
		stateSyncing:       peerSyncing,
		stateStable:        peerStable,
	}
}

type peerTransitionFunc func(*peer, *ntp.Response, error)

func newPeer(addr string) *peer {
	p := &peer{
		addr:       addr,
		interval:   queryMinInterval,
		best:       -1,
		offset:     time.Duration(0),
		delay:      time.Minute,
		dispersion: time.Minute,
	}
	for i := 0; i < ReplyCount; i++ {
		p.filter[i] = &filter{
			updateAt:   epoch,
			dispersion: MaxRootDelay,
			delay:      MaxRootDelay,
			offset:     MaxRootDelay,
		}
	}
	return p
}

func (p *peer) insertFilter(resp *ntp.Response) {
	// the fisrt filter is the newest
	for i := ReplyCount - 1; i > 0; i-- {
		if p.filter[i].updateAt.Equal(epoch) {
			continue
		}
		interval := time.Now().Sub(p.filter[i].updateAt)
		p.filter[i] = p.filter[i-1]
		p.filter[i].updateAt = time.Now()
		p.filter[i].dispersion += phi * interval // add up dispersion
	}
	p.filter[0].delay = resp.RTT + resp.RootDelay
	p.filter[0].offset = resp.ClockOffset
	p.filter[0].updateAt = time.Now()
	p.filter[0].dispersion = resp.RootDispersion + p.filter[0].delay/2
	p.filter[0].resp = resp
}

func (p *peer) run(pctx context.Context) {
	ctx, cancel := context.WithCancel(pctx)
	defer cancel()

	Info.Printf("%s started %s", p.addr, p.interval)
	defer Info.Printf("%s stopped", p.addr)

	var timer *time.Timer

	for {
		resp, err := ntp.Query(p.addr)
		p.reach <<= 1
		p.queryCount++
		if verr := resp.Validate(); err == nil && verr == nil {
			p.reach |= 1
			p.insertFilter(resp)
		} else {
			Warn.Print(verr, err)
		}

		peerTransTable[p.state](p, resp, err)

		if p.state == stateInvalid {
			Warn.Printf("peer %s invalid, exited looping", p.addr)
			return
		}
		if p.interval > maxInterval {
			p.interval = maxInterval
		}
		if p.interval < minInterval {
			p.interval = minInterval
		}
		p.interval += randDuration()
		Debug.Printf("%s will sleep %s", p.addr, p.interval)
		timer = time.NewTimer(p.interval)
		select {
		case <-timer.C:
		case <-ctx.Done():
			return
		}
		timer.Stop()
	}
}

func (p *peer) checkFilter() (valid bool) {

	bestIndex := -1
	bestDisp := time.Minute
	validCount := 0

	for i, r := range p.filter {
		if r == nil {
			continue
		}
		if r.dispersion >= MaxRootDelay {
			continue
		}
		validCount += 1
		if r.dispersion < bestDisp {
			bestIndex = i
		}
	}

	if validCount == 0 {
		valid = false
		return
	}

	p.best = bestIndex
	r := p.filter[bestIndex]
	p.dispersion = r.dispersion
	p.rootDelay = r.resp.RootDelay + r.resp.RTT
	p.delay = r.delay
	p.rootDisp = r.resp.RootDispersion
	p.offset = r.resp.ClockOffset
	p.interval = r.resp.Poll
	p.referTime = r.resp.ReferenceTime
	p.referId = r.resp.ReferenceID
	p.stratum = r.resp.Stratum
	p.updateAt = time.Now()
	Debug.Printf("%s choice new filter %d offset=%s", p.addr, bestIndex, p.offset)
	valid = true
	return
}

func (p *peer) String() string {
	return fmt.Sprintf("%s[%s]%s", p.addr, stateToString(p.state), p.offset)
}

func stateToString(u uint8) string {
	switch u {
	case stateInit:
		return "Init"
	case stateStable:
		return "stable"
	case stateInvalid:
		return "invalid"
	case stateTemporaryDown:
		return "down"
	case stateSyncing:
		return "syncing"
	}
	return "unknown"
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package tchannel

import (
	"container/heap"
	"errors"
	"sync"
	"sync/atomic"
	"time"

	"golang.org/x/net/context"
)

var (
	// ErrInvalidConnectionState indicates that the connection is not in a valid state.
	ErrInvalidConnectionState = errors.New("connection is in an invalid state")

	// ErrNoPeers indicates that there are no peers.
	ErrNoPeers = errors.New("no peers available")

	peerRng = NewRand(time.Now().UnixNano())
)

// Connectable is the interface used by peers to create connections.
type Connectable interface {
	// Connect tries to connect to the given hostPort.
	Connect(ctx context.Context, hostPort string) (*Connection, error)
	// Logger returns the logger to use.
	Logger() Logger
}

// PeerList maintains a list of Peers.
type PeerList struct {
	sync.RWMutex

	parent          *RootPeerList
	peersByHostPort map[string]*peerScore
	peerHeap        *PeerHeap
	scoreCalculator ScoreCalculator
	lastSelected    uint64
}

func newPeerList(root *RootPeerList) *PeerList {
	return &PeerList{
		parent:          root,
		peersByHostPort: make(map[string]*peerScore),
		scoreCalculator: newPreferIncomingCalculator(),
		peerHeap:        newPeerHeap(),
	}
}

// SetStrategy sets customized peer selection stratedgy.
func (l *PeerList) SetStrategy(sc ScoreCalculator) {
	l.scoreCalculator = sc
}

// Siblings don't share peer lists (though they take care not to double-connect
// to the same hosts).
func (l *PeerList) newSibling() *PeerList {
	sib := newPeerList(l.parent)
	return sib
}

// Add adds a peer to the list if it does not exist, or returns any existing peer.
func (l *PeerList) Add(hostPort string) *Peer {
	if ps, ok := l.exists(hostPort); ok {
		return ps.Peer
	}
	l.Lock()
	defer l.Unlock()

	if p, ok := l.peersByHostPort[hostPort]; ok {
		return p.Peer
	}

	p := l.parent.Add(hostPort)
	ps := newPeerScore(p, l.scoreCalculator.GetScore(p))

	l.peersByHostPort[hostPort] = ps
	l.peerHeap.PushPeer(ps)
	return p
}

// Get returns a peer from the peer list, or nil if none can be found.
func (l *PeerList) Get(prevSelected map[string]struct{}) (*Peer, error) {
	l.Lock()
	if l.peerHeap.Len() == 0 {
		l.Unlock()
		return nil, ErrNoPeers
	}

	// Select a peer, avoiding previously selected peers. If all peers have been previously
	// selected, then it's OK to repick them.
	peer := l.choosePeer(prevSelected)
	if peer == nil {
		peer = l.choosePeer(nil)
	}
	l.Unlock()
	return peer, nil
}

func (l *PeerList) choosePeer(prevSelected map[string]struct{}) *Peer {
	var psPopList []*peerScore
	var ps *peerScore

	size := l.peerHeap.Len()
	for i := 0; i < size; i++ {
		ps = l.peerHeap.PopPeer()
		if _, ok := prevSelected[ps.Peer.HostPort()]; !ok {
			break
		}
		psPopList = append(psPopList, ps)
	}

	for _, p := range psPopList {
		heap.Push(l.peerHeap, p)
	}

	if ps == nil {
		return nil
	}

	l.peerHeap.PushPeer(ps)
	atomic.AddUint64(&ps.chosenCount, 1)
	return ps.Peer
}

// GetOrAdd returns a peer for the given hostPort, creating one if it doesn't yet exist.
func (l *PeerList) GetOrAdd(hostPort string) *Peer {
	if ps, ok := l.exists(hostPort); ok {
		return ps.Peer
	}
	return l.Add(hostPort)
}

// Copy returns a map of the peer list. This method should only be used for testing.
func (l *PeerList) Copy() map[string]*Peer {
	l.RLock()
	defer l.RUnlock()

	listCopy := make(map[string]*Peer)
	for k, v := range l.peersByHostPort {
		listCopy[k] = v.Peer
	}
	return listCopy
}

// exists checks if a hostport exists in the peer list.
func (l *PeerList) exists(hostPort string) (*peerScore, bool) {
	l.RLock()
	ps, ok := l.peersByHostPort[hostPort]
	l.RUnlock()

	return ps, ok
}

// UpdatePeer is called when there is a change that may cause the peer's score to change.
// The new score is calculated, and the peer heap is updated with the new score if the score changes.
func (l *PeerList) UpdatePeer(p *Peer) {
	ps, ok := l.exists(p.hostPort)
	if !ok {
		return
	}

	newScore := l.scoreCalculator.GetScore(p)
	if newScore == ps.readScore() {
		return
	}

	ps.setScore(newScore)
	l.Lock()
	l.peerHeap.UpdatePeer(ps)
	l.Unlock()
}

type peerScore struct {
	sync.RWMutex
	*Peer

	score uint64
	index int
	order uint64
}

func newPeerScore(p *Peer, score uint64) *peerScore {
	return &peerScore{
		Peer:  p,
		score: score,
		index: -1,
	}
}

func (ps *peerScore) readScore() uint64 {
	ps.RLock()
	score := ps.score
	ps.RUnlock()
	return score
}

func (ps *peerScore) setScore(score uint64) {
	ps.Lock()
	ps.score = score
	ps.Unlock()
}

// Peer represents a single autobahn service or client with a unique host:port.
type Peer struct {
	channel      Connectable
	hostPort     string
	onConnChange func(*Peer)

	// scCount is the number of subchannels that this peer is added to.
	scCount uint32

	mut                 sync.RWMutex // mut protects connections.
	inboundConnections  []*Connection
	outboundConnections []*Connection
	chosenCount         uint64
}

func newPeer(channel Connectable, hostPort string, onConnChange func(*Peer)) *Peer {
	if hostPort == "" {
		panic("Cannot create peer with blank hostPort")
	}
	return &Peer{
		channel:      channel,
		hostPort:     hostPort,
		onConnChange: onConnChange,
	}
}

// HostPort returns the host:port used to connect to this peer.
func (p *Peer) HostPort() string {
	return p.hostPort
}

// getActive returns a list of active connections.
// TODO(prashant): Should we clear inactive connections?
func (p *Peer) getActive() []*Connection {
	var active []*Connection
	p.runWithConnections(func(c *Connection) {
		if c.IsActive() {
			active = append(active, c)
		}
	})
	return active
}

func randConn(conns []*Connection) *Connection {
	return conns[peerRng.Intn(len(conns))]
}

// GetConnection returns an active connection to this peer. If no active connections
// are found, it will create a new outbound connection and return it.
func (p *Peer) GetConnection(ctx context.Context) (*Connection, error) {
	// TODO(prashant): Use some sort of scoring to pick a connection.
	if activeConns := p.getActive(); len(activeConns) > 0 {
		return randConn(activeConns), nil
	}

	// No active connections, make a new outgoing connection.
	c, err := p.Connect(ctx)
	if err != nil {
		return nil, err
	}
	return c, nil
}

// AddInboundConnection adds an active inbound connection to the peer's connection list.
// If a connection is not active, ErrInvalidConnectionState will be returned.
func (p *Peer) AddInboundConnection(c *Connection) error {
	switch c.readState() {
	case connectionActive, connectionStartClose:
		// TODO(prashantv): Block inbound connections when the connection is not active.
		break
	default:
		return ErrInvalidConnectionState
	}

	p.mut.Lock()
	p.inboundConnections = append(p.inboundConnections, c)
	p.mut.Unlock()

	p.connectionStateChanged(c)
	return nil
}

// canRemove returns whether this peer can be safely removed from the root peer list.
func (p *Peer) canRemove() bool {
	p.mut.RLock()
	count := len(p.inboundConnections) + len(p.outboundConnections) + int(p.scCount)
	p.mut.RUnlock()
	return count == 0
}

// AddOutboundConnection adds an active outbound connection to the peer's connection list.
// If a connection is not active, ErrInvalidConnectionState will be returned.
func (p *Peer) AddOutboundConnection(c *Connection) error {
	switch c.readState() {
	case connectionActive, connectionStartClose:
		break
	default:
		return ErrInvalidConnectionState
	}

	p.mut.Lock()
	p.outboundConnections = append(p.outboundConnections, c)
	p.mut.Unlock()

	p.connectionStateChanged(c)
	return nil
}

// checkInboundConnection will check whether the changed connection is an inbound
// connection, and will remove any closed connections.
func (p *Peer) checkInboundConnection(changed *Connection) (updated bool, isInbound bool) {
	newConns := p.inboundConnections[:0]
	for _, c := range p.inboundConnections {
		if c == changed {
			isInbound = true
		}

		if c.readState() != connectionClosed {
			newConns = append(newConns, c)
		} else {
			updated = true
		}
	}
	if updated {
		p.inboundConnections = newConns
	}

	return updated, isInbound
}

// connectionStateChanged is called when one of the peers' connections states changes.
func (p *Peer) connectionStateChanged(changed *Connection) {
	p.mut.Lock()
	updated, _ := p.checkInboundConnection(changed)
	p.mut.Unlock()

	if updated {
		p.onConnChange(p)
	}
}

// Connect adds a new outbound connection to the peer.
func (p *Peer) Connect(ctx context.Context) (*Connection, error) {
	c, err := p.channel.Connect(ctx, p.hostPort)
	if err != nil {
		return nil, err
	}

	if err := p.AddOutboundConnection(c); err != nil {
		return nil, err
	}

	return c, nil
}

// BeginCall starts a new call to this specific peer, returning an OutboundCall that can
// be used to write the arguments of the call.
func (p *Peer) BeginCall(ctx context.Context, serviceName string, operationName string, callOptions *CallOptions) (*OutboundCall, error) {
	if callOptions == nil {
		callOptions = defaultCallOptions
	}
	callOptions.RequestState.AddSelectedPeer(p.HostPort())

	conn, err := p.GetConnection(ctx)
	if err != nil {
		return nil, err
	}

	if callOptions == nil {
		callOptions = defaultCallOptions
	}
	call, err := conn.beginCall(ctx, serviceName, callOptions, operationName)
	if err != nil {
		return nil, err
	}

	return call, err
}

// NumConnections returns the number of inbound and outbound connections for this peer.
func (p *Peer) NumConnections() (inbound int, outbound int) {
	p.mut.RLock()
	inbound = len(p.inboundConnections)
	outbound = len(p.outboundConnections)
	p.mut.RUnlock()
	return inbound, outbound
}

// NumPendingOutbound returns the number of pending outbound calls.
func (p *Peer) NumPendingOutbound() int {
	count := 0
	p.mut.RLock()
	for _, c := range p.outboundConnections {
		count += c.outbound.count()
	}

	for _, c := range p.inboundConnections {
		count += c.outbound.count()
	}
	p.mut.RUnlock()
	return count
}

func (p *Peer) runWithConnections(f func(*Connection)) {
	p.mut.RLock()
	for _, c := range p.inboundConnections {
		f(c)
	}

	for _, c := range p.outboundConnections {
		f(c)
	}
	p.mut.RUnlock()
}
<commit_msg>Update subchannel reference count<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package tchannel

import (
	"container/heap"
	"errors"
	"sync"
	"sync/atomic"
	"time"

	"golang.org/x/net/context"
)

var (
	// ErrInvalidConnectionState indicates that the connection is not in a valid state.
	ErrInvalidConnectionState = errors.New("connection is in an invalid state")

	// ErrNoPeers indicates that there are no peers.
	ErrNoPeers = errors.New("no peers available")

	peerRng = NewRand(time.Now().UnixNano())
)

// Connectable is the interface used by peers to create connections.
type Connectable interface {
	// Connect tries to connect to the given hostPort.
	Connect(ctx context.Context, hostPort string) (*Connection, error)
	// Logger returns the logger to use.
	Logger() Logger
}

// PeerList maintains a list of Peers.
type PeerList struct {
	sync.RWMutex

	parent          *RootPeerList
	peersByHostPort map[string]*peerScore
	peerHeap        *PeerHeap
	scoreCalculator ScoreCalculator
	lastSelected    uint64
}

func newPeerList(root *RootPeerList) *PeerList {
	return &PeerList{
		parent:          root,
		peersByHostPort: make(map[string]*peerScore),
		scoreCalculator: newPreferIncomingCalculator(),
		peerHeap:        newPeerHeap(),
	}
}

// SetStrategy sets customized peer selection stratedgy.
func (l *PeerList) SetStrategy(sc ScoreCalculator) {
	l.scoreCalculator = sc
}

// Siblings don't share peer lists (though they take care not to double-connect
// to the same hosts).
func (l *PeerList) newSibling() *PeerList {
	sib := newPeerList(l.parent)
	return sib
}

// Add adds a peer to the list if it does not exist, or returns any existing peer.
func (l *PeerList) Add(hostPort string) *Peer {
	if ps, ok := l.exists(hostPort); ok {
		return ps.Peer
	}
	l.Lock()
	defer l.Unlock()

	if p, ok := l.peersByHostPort[hostPort]; ok {
		return p.Peer
	}

	p := l.parent.Add(hostPort)
	p.addSC()
	ps := newPeerScore(p, l.scoreCalculator.GetScore(p))

	l.peersByHostPort[hostPort] = ps
	l.peerHeap.PushPeer(ps)
	return p
}

// Get returns a peer from the peer list, or nil if none can be found.
func (l *PeerList) Get(prevSelected map[string]struct{}) (*Peer, error) {
	l.Lock()
	if l.peerHeap.Len() == 0 {
		l.Unlock()
		return nil, ErrNoPeers
	}

	// Select a peer, avoiding previously selected peers. If all peers have been previously
	// selected, then it's OK to repick them.
	peer := l.choosePeer(prevSelected)
	if peer == nil {
		peer = l.choosePeer(nil)
	}
	l.Unlock()
	return peer, nil
}

func (l *PeerList) choosePeer(prevSelected map[string]struct{}) *Peer {
	var psPopList []*peerScore
	var ps *peerScore

	size := l.peerHeap.Len()
	for i := 0; i < size; i++ {
		ps = l.peerHeap.PopPeer()
		if _, ok := prevSelected[ps.Peer.HostPort()]; !ok {
			break
		}
		psPopList = append(psPopList, ps)
	}

	for _, p := range psPopList {
		heap.Push(l.peerHeap, p)
	}

	if ps == nil {
		return nil
	}

	l.peerHeap.PushPeer(ps)
	atomic.AddUint64(&ps.chosenCount, 1)
	return ps.Peer
}

// GetOrAdd returns a peer for the given hostPort, creating one if it doesn't yet exist.
func (l *PeerList) GetOrAdd(hostPort string) *Peer {
	if ps, ok := l.exists(hostPort); ok {
		return ps.Peer
	}
	return l.Add(hostPort)
}

// Copy returns a map of the peer list. This method should only be used for testing.
func (l *PeerList) Copy() map[string]*Peer {
	l.RLock()
	defer l.RUnlock()

	listCopy := make(map[string]*Peer)
	for k, v := range l.peersByHostPort {
		listCopy[k] = v.Peer
	}
	return listCopy
}

// exists checks if a hostport exists in the peer list.
func (l *PeerList) exists(hostPort string) (*peerScore, bool) {
	l.RLock()
	ps, ok := l.peersByHostPort[hostPort]
	l.RUnlock()

	return ps, ok
}

// UpdatePeer is called when there is a change that may cause the peer's score to change.
// The new score is calculated, and the peer heap is updated with the new score if the score changes.
func (l *PeerList) UpdatePeer(p *Peer) {
	ps, ok := l.exists(p.hostPort)
	if !ok {
		return
	}

	newScore := l.scoreCalculator.GetScore(p)
	if newScore == ps.readScore() {
		return
	}

	ps.setScore(newScore)
	l.Lock()
	l.peerHeap.UpdatePeer(ps)
	l.Unlock()
}

type peerScore struct {
	sync.RWMutex
	*Peer

	score uint64
	index int
	order uint64
}

func newPeerScore(p *Peer, score uint64) *peerScore {
	return &peerScore{
		Peer:  p,
		score: score,
		index: -1,
	}
}

func (ps *peerScore) readScore() uint64 {
	ps.RLock()
	score := ps.score
	ps.RUnlock()
	return score
}

func (ps *peerScore) setScore(score uint64) {
	ps.Lock()
	ps.score = score
	ps.Unlock()
}

// Peer represents a single autobahn service or client with a unique host:port.
type Peer struct {
	channel      Connectable
	hostPort     string
	onConnChange func(*Peer)

	// scCount is the number of subchannels that this peer is added to.
	scCount uint32

	mut                 sync.RWMutex // mut protects connections.
	inboundConnections  []*Connection
	outboundConnections []*Connection
	chosenCount         uint64
}

func newPeer(channel Connectable, hostPort string, onConnChange func(*Peer)) *Peer {
	if hostPort == "" {
		panic("Cannot create peer with blank hostPort")
	}
	return &Peer{
		channel:      channel,
		hostPort:     hostPort,
		onConnChange: onConnChange,
	}
}

// HostPort returns the host:port used to connect to this peer.
func (p *Peer) HostPort() string {
	return p.hostPort
}

// getActive returns a list of active connections.
// TODO(prashant): Should we clear inactive connections?
func (p *Peer) getActive() []*Connection {
	var active []*Connection
	p.runWithConnections(func(c *Connection) {
		if c.IsActive() {
			active = append(active, c)
		}
	})
	return active
}

func randConn(conns []*Connection) *Connection {
	return conns[peerRng.Intn(len(conns))]
}

// GetConnection returns an active connection to this peer. If no active connections
// are found, it will create a new outbound connection and return it.
func (p *Peer) GetConnection(ctx context.Context) (*Connection, error) {
	// TODO(prashant): Use some sort of scoring to pick a connection.
	if activeConns := p.getActive(); len(activeConns) > 0 {
		return randConn(activeConns), nil
	}

	// No active connections, make a new outgoing connection.
	c, err := p.Connect(ctx)
	if err != nil {
		return nil, err
	}
	return c, nil
}

// AddInboundConnection adds an active inbound connection to the peer's connection list.
// If a connection is not active, ErrInvalidConnectionState will be returned.
func (p *Peer) AddInboundConnection(c *Connection) error {
	switch c.readState() {
	case connectionActive, connectionStartClose:
		// TODO(prashantv): Block inbound connections when the connection is not active.
		break
	default:
		return ErrInvalidConnectionState
	}

	p.mut.Lock()
	p.inboundConnections = append(p.inboundConnections, c)
	p.mut.Unlock()

	p.connectionStateChanged(c)
	return nil
}

// addSC adds a reference to a peer from a subchannel (e.g. peer list).
func (p *Peer) addSC() {
	p.mut.Lock()
	p.scCount++
	p.mut.Unlock()
}

// canRemove returns whether this peer can be safely removed from the root peer list.
func (p *Peer) canRemove() bool {
	p.mut.RLock()
	count := len(p.inboundConnections) + len(p.outboundConnections) + int(p.scCount)
	p.mut.RUnlock()
	return count == 0
}

// AddOutboundConnection adds an active outbound connection to the peer's connection list.
// If a connection is not active, ErrInvalidConnectionState will be returned.
func (p *Peer) AddOutboundConnection(c *Connection) error {
	switch c.readState() {
	case connectionActive, connectionStartClose:
		break
	default:
		return ErrInvalidConnectionState
	}

	p.mut.Lock()
	p.outboundConnections = append(p.outboundConnections, c)
	p.mut.Unlock()

	p.connectionStateChanged(c)
	return nil
}

// checkInboundConnection will check whether the changed connection is an inbound
// connection, and will remove any closed connections.
func (p *Peer) checkInboundConnection(changed *Connection) (updated bool, isInbound bool) {
	newConns := p.inboundConnections[:0]
	for _, c := range p.inboundConnections {
		if c == changed {
			isInbound = true
		}

		if c.readState() != connectionClosed {
			newConns = append(newConns, c)
		} else {
			updated = true
		}
	}
	if updated {
		p.inboundConnections = newConns
	}

	return updated, isInbound
}

// connectionStateChanged is called when one of the peers' connections states changes.
func (p *Peer) connectionStateChanged(changed *Connection) {
	p.mut.Lock()
	updated, _ := p.checkInboundConnection(changed)
	p.mut.Unlock()

	if updated {
		p.onConnChange(p)
	}
}

// Connect adds a new outbound connection to the peer.
func (p *Peer) Connect(ctx context.Context) (*Connection, error) {
	c, err := p.channel.Connect(ctx, p.hostPort)
	if err != nil {
		return nil, err
	}

	if err := p.AddOutboundConnection(c); err != nil {
		return nil, err
	}

	return c, nil
}

// BeginCall starts a new call to this specific peer, returning an OutboundCall that can
// be used to write the arguments of the call.
func (p *Peer) BeginCall(ctx context.Context, serviceName string, operationName string, callOptions *CallOptions) (*OutboundCall, error) {
	if callOptions == nil {
		callOptions = defaultCallOptions
	}
	callOptions.RequestState.AddSelectedPeer(p.HostPort())

	conn, err := p.GetConnection(ctx)
	if err != nil {
		return nil, err
	}

	if callOptions == nil {
		callOptions = defaultCallOptions
	}
	call, err := conn.beginCall(ctx, serviceName, callOptions, operationName)
	if err != nil {
		return nil, err
	}

	return call, err
}

// NumConnections returns the number of inbound and outbound connections for this peer.
func (p *Peer) NumConnections() (inbound int, outbound int) {
	p.mut.RLock()
	inbound = len(p.inboundConnections)
	outbound = len(p.outboundConnections)
	p.mut.RUnlock()
	return inbound, outbound
}

// NumPendingOutbound returns the number of pending outbound calls.
func (p *Peer) NumPendingOutbound() int {
	count := 0
	p.mut.RLock()
	for _, c := range p.outboundConnections {
		count += c.outbound.count()
	}

	for _, c := range p.inboundConnections {
		count += c.outbound.count()
	}
	p.mut.RUnlock()
	return count
}

func (p *Peer) runWithConnections(f func(*Connection)) {
	p.mut.RLock()
	for _, c := range p.inboundConnections {
		f(c)
	}

	for _, c := range p.outboundConnections {
		f(c)
	}
	p.mut.RUnlock()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"net/http"
	"net/url"
	"time"

	"github.com/parkr/ping/analytics"
	"github.com/zenazn/goji"
)

const returnedJavaScript = "(function(){})();"
const lengthOfJavaScript = "17"

func ping(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/javascript")
	w.Header().Set("Content-Length", lengthOfJavaScript)
	fmt.Fprintf(w, returnedJavaScript)

	referrer := r.Referer()
	if referrer == "" {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	url, err := url.Parse(referrer)

	if err != nil {
		http.Error(w, "Couldn't parse "+referrer+": "+err.Error(), 500)
		return
	}

	var ip string
	if res := r.Header.Get("X-Forwarded-For"); res != "" {
		log.Println("Fetching IP from proxy:", res)
		ip = res
	} else {
		ip = r.RemoteAddr
	}

	visit := &Visit{
		IP:        ip,
		Host:      url.Host,
		Path:      url.Path,
		CreatedAt: time.Now().UTC().Format(time.RFC3339),
	}
	log.Println("Logging visit:", visit.String())

	err = visit.Save()

	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}

	w.WriteHeader(http.StatusCreated)
}

func counts(w http.ResponseWriter, r *http.Request) {
	path := r.FormValue("path")

	var err error
	var views, visitors int
	if path == "" {
		http.Error(w, "Missing param", 400)
	} else {
		views, err = analytics.ViewsForPath(db, path)
		if err != nil {
			http.Error(w, err.Error(), 500)
			return
		}

		visitors, err = analytics.VisitorsForPath(db, path)
		if err != nil {
			http.Error(w, err.Error(), 500)
			return
		}

		writeJsonResponse(w, map[string]int{
			"views":    views,
			"visitors": visitors,
		})
	}
}

func all(w http.ResponseWriter, r *http.Request) {
	thing := r.FormValue("type")

	if thing == "path" || thing == "host" {
		entries, err := analytics.ListDistinctColumn(db, thing)

		if err != nil {
			http.Error(w, err.Error(), 500)
			return
		}

		writeJsonResponse(w, map[string][]string{"entries": entries})
	} else {
		http.Error(w, "Missing param", 400)
		return
	}
}

func main() {
	goji.Get("/ping", ping)
	goji.Get("/ping.js", ping)
	goji.Get("/counts", counts)
	goji.Get("/all", all)
	goji.Serve()
}
<commit_msg>add useful method for constructing a javascript response<commit_after>package main

import (
	"fmt"
	"log"
	"net/http"
	"net/url"
	"strconv"
	"time"

	"github.com/parkr/ping/analytics"
	"github.com/zenazn/goji"
)

const returnedJavaScript = "(function(){})();"
const lengthOfJavaScript = "17"

func javascriptRespond(w http.ResponseWriter, code int, err string) {
	w.WriteHeader(code)

	var content string
	if err == "" {
		content = returnedJavaScript
	} else {
		content = fmt.Sprintf(`(function(){console.error("%s")})();`, err)
	}

	w.Header().Set("Content-Type", "application/javascript")
	w.Header().Set("Content-Length", strconv.Itoa(len(content)))
	fmt.Fprintf(w, content)
}

func ping(w http.ResponseWriter, r *http.Request) {
	referrer := r.Referer()
	if referrer == "" {
		log.Println("empty referrer")
		javascriptRespond(w, http.StatusBadRequest, "empty referrer")
		return
	}

	url, err := url.Parse(referrer)

	if err != nil {
		log.Println("invalid referrer:", referrer)
		javascriptRespond(w, 500, "Couldn't parse referrer: "+err.Error())
		return
	}

	var ip string
	if res := r.Header.Get("X-Forwarded-For"); res != "" {
		log.Println("Fetching IP from proxy:", res)
		ip = res
	} else {
		ip = r.RemoteAddr
	}

	visit := &Visit{
		IP:        ip,
		Host:      url.Host,
		Path:      url.Path,
		CreatedAt: time.Now().UTC().Format(time.RFC3339),
	}
	log.Println("Logging visit:", visit.String())

	err = visit.Save()

	if err != nil {
		javascriptRespond(w, 500, err.Error())
		return
	}

	javascriptRespond(w, 201, "")
}

func counts(w http.ResponseWriter, r *http.Request) {
	path := r.FormValue("path")

	var err error
	var views, visitors int
	if path == "" {
		http.Error(w, "Missing param", 400)
	} else {
		views, err = analytics.ViewsForPath(db, path)
		if err != nil {
			http.Error(w, err.Error(), 500)
			return
		}

		visitors, err = analytics.VisitorsForPath(db, path)
		if err != nil {
			http.Error(w, err.Error(), 500)
			return
		}

		writeJsonResponse(w, map[string]int{
			"views":    views,
			"visitors": visitors,
		})
	}
}

func all(w http.ResponseWriter, r *http.Request) {
	thing := r.FormValue("type")

	if thing == "path" || thing == "host" {
		entries, err := analytics.ListDistinctColumn(db, thing)

		if err != nil {
			http.Error(w, err.Error(), 500)
			return
		}

		writeJsonResponse(w, map[string][]string{"entries": entries})
	} else {
		http.Error(w, "Missing param", 400)
		return
	}
}

func main() {
	goji.Get("/ping", ping)
	goji.Get("/ping.js", ping)
	goji.Get("/counts", counts)
	goji.Get("/all", all)
	goji.Serve()
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"context"
	"encoding/gob"
	"io"
)

// Pipe reads and writes on a connection, results are sent over channels
type Pipe interface {
	Wait(ctx context.Context, rw io.ReadWriter)
	receive(ctx context.Context, r io.Reader)
	send(ctx context.Context, w io.Writer)
}

// Node represents a Pipe connected to an inside or outside service
type Node struct {
	from, to chan Message       // In/Out messages
	addr     string             // Where the Node is connected
	cancel   context.CancelFunc // Cancel the connections, linked to the Context
}

// OutNode represents a Pipe connected to an outside service
type OutNode struct {
	Node
	firstMessage *Message
}

func (p OutNode) receive(ctx context.Context, r io.Reader) {
	b := make([]byte, 4096)
	lastMessageEmptyEOF := true
	for {
		n, err := r.Read(b)
		if err != nil {
			select {
			case <-ctx.Done():
				return
			default:
				break
			}
		}
		debugLog.Printf("read %v bytes on %s with err: %v\n", n, p.addr, err)
		if err != nil {
			if err != io.EOF {
				errorLog.Printf("received %v on %s", err, p.addr)
			}
			if !lastMessageEmptyEOF {
				msg := Message{Payload: []byte{}, EOF: true}
				lastMessageEmptyEOF = true
				p.to <- msg
			}
			p.cancel()
			return
		}
		if n > 0 {
			data := make([]byte, n)
			copy(data, b[:n])
			p.to <- Message{Payload: data}
			lastMessageEmptyEOF = false
		}
	}
}

func (p OutNode) sendData(ctx context.Context, w io.Writer, msg Message) error {
	data := msg.Payload
	debugLog.Printf("send %v bytes on %s\n", len(data), p.addr)
	buf := bytes.NewBuffer(data)
	if _, err := io.Copy(w, buf); err != nil {
		errorLog.Printf("could not write %v bytes on %s", len(data), p.addr)
		p.cancel()
		return err
	}
	if msg.EOF {
		p.cancel()
		return io.EOF
	}
	return nil
}

func (p OutNode) send(ctx context.Context, w io.Writer) {
	if p.firstMessage != nil {
		if err := p.sendData(ctx, w, *p.firstMessage); err != nil {
			return
		}
	}
	for {
		select {
		case msg := <-p.from:
			if err := p.sendData(ctx, w, msg); err != nil {
				return
			}
		case <-ctx.Done():
			return
		}
	}
}

// Wait will read data on connection and write back results
func (p OutNode) Wait(ctx context.Context, rw io.ReadWriter) {
	go p.receive(ctx, rw)
	go p.send(ctx, rw)
}

// InNode represents a Pipe connected to another InNode, with custom messages
type InNode Node

func (p InNode) receive(ctx context.Context, r io.Reader) {
	decoder := gob.NewDecoder(r)
	for {
		msg := Message{}
		err := decoder.Decode(&msg)
		debugLog.Printf("decode message of %v bytes on %s with err: %v\n", msg.Size(), p.addr, err)
		if err != nil {
			if err != io.EOF {
				errorLog.Printf("received %v on %s", err, p.addr)
			}
			p.cancel()
			return
		}
		p.to <- msg
	}
}

func (p InNode) send(ctx context.Context, w io.Writer) {
	encoder := gob.NewEncoder(w)
	for {
		select {
		case msg := <-p.from:
			debugLog.Printf("send message %v bytes on %s\n", msg.Size(), p.addr)
			if err := encoder.Encode(msg); err != nil {
				errorLog.Printf("could not encode message on %s with error %v", p.addr, err)
				p.from <- msg
				return
			}
		case <-ctx.Done():
			return
		}
	}
}

// Wait will read data on connection and write back results
func (p InNode) Wait(ctx context.Context, rw io.ReadWriter) {
	go p.receive(ctx, rw)
	go p.send(ctx, rw)
}
<commit_msg>Simplify OutNode.receive<commit_after>package main

import (
	"bytes"
	"context"
	"encoding/gob"
	"io"
)

// Pipe reads and writes on a connection, results are sent over channels
type Pipe interface {
	Wait(ctx context.Context, rw io.ReadWriter)
	receive(ctx context.Context, r io.Reader)
	send(ctx context.Context, w io.Writer)
}

// Node represents a Pipe connected to an inside or outside service
type Node struct {
	from, to chan Message       // In/Out messages
	addr     string             // Where the Node is connected
	cancel   context.CancelFunc // Cancel the connections, linked to the Context
}

// OutNode represents a Pipe connected to an outside service
type OutNode struct {
	Node
	firstMessage *Message
}

func (p OutNode) receive(ctx context.Context, r io.Reader) {
	b := make([]byte, 4096)
	for {
		n, err := r.Read(b)
		if n == 0 && ctx.Err() != nil {
			return
		}
		data := make([]byte, n)
		copy(data, b[:n])
		p.to <- Message{Payload: data, EOF: err == io.EOF}
		debugLog.Printf("read %v bytes on %s with err: %v\n", n, p.addr, err)
		if err != nil {
			if err != io.EOF && ctx.Err() == nil {
				errorLog.Printf("received %v on %s", err, p.addr)
			}
			p.cancel()
			return
		}
	}
}

func (p OutNode) sendData(ctx context.Context, w io.Writer, msg Message) error {
	data := msg.Payload
	debugLog.Printf("send %v bytes on %s\n", len(data), p.addr)
	buf := bytes.NewBuffer(data)
	if _, err := io.Copy(w, buf); err != nil {
		errorLog.Printf("could not write %v bytes on %s", len(data), p.addr)
		p.cancel()
		return err
	}
	if msg.EOF {
		p.cancel()
		return io.EOF
	}
	return nil
}

func (p OutNode) send(ctx context.Context, w io.Writer) {
	if p.firstMessage != nil {
		if err := p.sendData(ctx, w, *p.firstMessage); err != nil {
			return
		}
	}
	for {
		select {
		case msg := <-p.from:
			if err := p.sendData(ctx, w, msg); err != nil {
				return
			}
		case <-ctx.Done():
			return
		}
	}
}

// Wait will read data on connection and write back results
func (p OutNode) Wait(ctx context.Context, rw io.ReadWriter) {
	go p.receive(ctx, rw)
	go p.send(ctx, rw)
}

// InNode represents a Pipe connected to another InNode, with custom messages
type InNode Node

func (p InNode) receive(ctx context.Context, r io.Reader) {
	decoder := gob.NewDecoder(r)
	for {
		msg := Message{}
		err := decoder.Decode(&msg)
		debugLog.Printf("decode message of %v bytes on %s with err: %v\n", msg.Size(), p.addr, err)
		if err != nil {
			if err != io.EOF {
				errorLog.Printf("received %v on %s", err, p.addr)
			}
			p.cancel()
			return
		}
		p.to <- msg
	}
}

func (p InNode) send(ctx context.Context, w io.Writer) {
	encoder := gob.NewEncoder(w)
	for {
		select {
		case msg := <-p.from:
			debugLog.Printf("send message %v bytes on %s\n", msg.Size(), p.addr)
			if err := encoder.Encode(msg); err != nil {
				errorLog.Printf("could not encode message on %s with error %v", p.addr, err)
				p.from <- msg
				return
			}
		case <-ctx.Done():
			return
		}
	}
}

// Wait will read data on connection and write back results
func (p InNode) Wait(ctx context.Context, rw io.ReadWriter) {
	go p.receive(ctx, rw)
	go p.send(ctx, rw)
}
<|endoftext|>


<commit_before>package testrail

import "strconv"

// Plan represents a Plan
type Plan struct {
	AssignedToID  int     `json:"assignedto_id"`
	BlockedCount  int     `json:"blocked_count"`
	CompletedOn   int     `json:"completed_on"`
	CreatedBy     int     `json:"created_by"`
	CreatedOn     int     `json:"created_on"`
	Description   string  `json:"description"`
	Entries       []Entry `json:"entries"`
	FailedCount   int     `json:"failed_count"`
	ID            int     `json:"id"`
	IsCompleted   bool    `json:"is_completed"`
	MilestoneID   int     `json:"milestone_id"`
	Name          string  `json:"name"`
	PassedCount   int     `json:"passed_count"`
	ProjectID     int     `json:"project_id"`
	RetestCount   int     `json:"retest_count"`
	UntestedCount int     `json:"untested_count"`
	URL           string  `json:"url"`
}

// Entry represents the entry a Plan can have
type Entry struct {
	ID      string `json:"id"`
	Name    string `json:"name"`
	Runs    []Run  `json:"runs"`
	SuiteID int    `json:"suite_id"`
}

// RequestFilterForPlan represents the filters
// usable to get the plan
type RequestFilterForPlan struct {
	CreatedAfter  string `json:"created_after"`
	CreatedBefore string `json:"created_before"`
	CreatedBy     []int  `json:"created_by"`
	IsCompleted   *bool  `json:"is_completed"`
	Limit         *int   `json:"limit"`
	Offset        *int   `json:"offset"`
	MilestoneID   []int  `json:"milestone_id"`
}

// SendablePlan represents a Plan
// that can be created or updated via the api
type SendablePlan struct {
	Name        string          `json:"name,omitempty"`
	Description string          `json:"description,omitempty"`
	MilestoneID int             `json:"milestone_id,omitempty"`
	Entries     []SendableEntry `json:"entries,omitempty"`
}

// SendableEntry represents an Entry
// that can be created or updated via the api
type SendableEntry struct {
	SuiteID      int    `json:"suite_id"`
	Name         string `json:"name,omitempty"`
	AssignedtoID int    `json:"assignedto_id,omitempty"`
	IncludeAll   bool   `json:"include_all,omitempty"`
	CaseIDs      []int  `json:"case_ids,omitempty"`
	ConfigIDs    []int  `json:"config_ids,omitempty"`
	Runs         []Run  `json:"runs,omitempty"`
}

// GetPlan returns the existing plan planID
func (c *Client) GetPlan(planID int) (Plan, error) {
	returnPlan := Plan{}
	err := c.sendRequest("GET", "get_plan/"+strconv.Itoa(planID), nil, &returnPlan)
	return returnPlan, err
}

// GetPlans returns the list of plans for the project projectID
// validating the filters
func (c *Client) GetPlans(projectID int, filters ...RequestFilterForPlan) ([]Plan, error) {
	uri := "get_plans/" + strconv.Itoa(projectID)
	if len(filters) > 0 {
		uri = applyFiltersForPlan(uri, filters[0])
	}

	returnPlans := []Plan{}
	err := c.sendRequest("GET", uri, nil, &returnPlans)
	return returnPlans, err
}

// AddPlan creates a new plan on project projectID and returns it
func (c *Client) AddPlan(projectID int, newPlan SendablePlan) (Plan, error) {
	createdPlan := Plan{}
	err := c.sendRequest("POST", "add_plan/"+strconv.Itoa(projectID), newPlan, &createdPlan)
	return createdPlan, err
}

// AddPlanEntry creates a new entry on plan planID and returns it
func (c *Client) AddPlanEntry(planID int, newEntry SendableEntry) (Entry, error) {
	createdEntry := Entry{}
	err := c.sendRequest("POST", "add_plan_entry/"+strconv.Itoa(planID), newEntry, &createdEntry)
	return createdEntry, err
}

// UpdatePlan updates the existing plan planID and returns it
func (c *Client) UpdatePlan(planID int, updates SendablePlan) (Plan, error) {
	updatedPlan := Plan{}
	err := c.sendRequest("POST", "update_plan/"+strconv.Itoa(planID), updates, &updatedPlan)
	return updatedPlan, err
}

// UpdatePlanEntry updates the entry entryID on plan planID and returns it
func (c *Client) UpdatePlanEntry(planID int, entryID string, updates SendableEntry) (Entry, error) {
	uri := "update_plan_entry/" + strconv.Itoa(planID) + "/" + entryID
	updatedEntry := Entry{}
	err := c.sendRequest("POST", uri, updates, &updatedEntry)
	return updatedEntry, err
}

// ClosePlan closes the plan planID and returns it
func (c *Client) ClosePlan(planID int) (Plan, error) {
	deletedPlan := Plan{}
	err := c.sendRequest("POST", "close_plan/"+strconv.Itoa(planID), nil, &deletedPlan)
	return deletedPlan, err
}

// DeletePlan deletes the plan planID
func (c *Client) DeletePlan(planID int) error {
	return c.sendRequest("POST", "delete_plan/"+strconv.Itoa(planID), nil, nil)
}

// DeletePlanEntry delete the entry entryID on plan planID
func (c *Client) DeletePlanEntry(planID int, entryID string) error {
	uri := "delete_plan_entry/" + strconv.Itoa(planID) + "/" + entryID
	return c.sendRequest("POST", uri, nil, nil)
}

// applyFiltersForPlan go through each possible filters and create the
// uri for the wanted ones
func applyFiltersForPlan(uri string, filters RequestFilterForPlan) string {
	if filters.CreatedAfter != "" {
		uri = uri + "&created_after=" + filters.CreatedAfter
	}
	if filters.CreatedBefore != "" {
		uri = uri + "&created_before=" + filters.CreatedBefore
	}
	if len(filters.CreatedBy) != 0 {
		uri = applySpecificFilter(uri, "created_by", filters.CreatedBy)
	}
	if len(filters.MilestoneID) != 0 {
		uri = applySpecificFilter(uri, "milestone_id", filters.MilestoneID)
	}
	if filters.IsCompleted != nil {
		uri = uri + "&is_completed=" + btoitos(*filters.IsCompleted)
	}
	if filters.Limit != nil {
		uri = uri + "&limit=" + strconv.Itoa(*filters.Limit)
	}
	if filters.Offset != nil {
		uri = uri + "&offset=" + strconv.Itoa(*filters.Offset)
	}

	return uri
}
<commit_msg>Remove omitempty json field tag from SendableEntry.IncludeAll<commit_after>package testrail

import "strconv"

// Plan represents a Plan
type Plan struct {
	AssignedToID  int     `json:"assignedto_id"`
	BlockedCount  int     `json:"blocked_count"`
	CompletedOn   int     `json:"completed_on"`
	CreatedBy     int     `json:"created_by"`
	CreatedOn     int     `json:"created_on"`
	Description   string  `json:"description"`
	Entries       []Entry `json:"entries"`
	FailedCount   int     `json:"failed_count"`
	ID            int     `json:"id"`
	IsCompleted   bool    `json:"is_completed"`
	MilestoneID   int     `json:"milestone_id"`
	Name          string  `json:"name"`
	PassedCount   int     `json:"passed_count"`
	ProjectID     int     `json:"project_id"`
	RetestCount   int     `json:"retest_count"`
	UntestedCount int     `json:"untested_count"`
	URL           string  `json:"url"`
}

// Entry represents the entry a Plan can have
type Entry struct {
	ID      string `json:"id"`
	Name    string `json:"name"`
	Runs    []Run  `json:"runs"`
	SuiteID int    `json:"suite_id"`
}

// RequestFilterForPlan represents the filters
// usable to get the plan
type RequestFilterForPlan struct {
	CreatedAfter  string `json:"created_after"`
	CreatedBefore string `json:"created_before"`
	CreatedBy     []int  `json:"created_by"`
	IsCompleted   *bool  `json:"is_completed"`
	Limit         *int   `json:"limit"`
	Offset        *int   `json:"offset"`
	MilestoneID   []int  `json:"milestone_id"`
}

// SendablePlan represents a Plan
// that can be created or updated via the api
type SendablePlan struct {
	Name        string          `json:"name,omitempty"`
	Description string          `json:"description,omitempty"`
	MilestoneID int             `json:"milestone_id,omitempty"`
	Entries     []SendableEntry `json:"entries,omitempty"`
}

// SendableEntry represents an Entry
// that can be created or updated via the api
type SendableEntry struct {
	SuiteID      int    `json:"suite_id"`
	Name         string `json:"name,omitempty"`
	AssignedtoID int    `json:"assignedto_id,omitempty"`
	IncludeAll   bool   `json:"include_all"`
	CaseIDs      []int  `json:"case_ids,omitempty"`
	ConfigIDs    []int  `json:"config_ids,omitempty"`
	Runs         []Run  `json:"runs,omitempty"`
}

// GetPlan returns the existing plan planID
func (c *Client) GetPlan(planID int) (Plan, error) {
	returnPlan := Plan{}
	err := c.sendRequest("GET", "get_plan/"+strconv.Itoa(planID), nil, &returnPlan)
	return returnPlan, err
}

// GetPlans returns the list of plans for the project projectID
// validating the filters
func (c *Client) GetPlans(projectID int, filters ...RequestFilterForPlan) ([]Plan, error) {
	uri := "get_plans/" + strconv.Itoa(projectID)
	if len(filters) > 0 {
		uri = applyFiltersForPlan(uri, filters[0])
	}

	returnPlans := []Plan{}
	err := c.sendRequest("GET", uri, nil, &returnPlans)
	return returnPlans, err
}

// AddPlan creates a new plan on project projectID and returns it
func (c *Client) AddPlan(projectID int, newPlan SendablePlan) (Plan, error) {
	createdPlan := Plan{}
	err := c.sendRequest("POST", "add_plan/"+strconv.Itoa(projectID), newPlan, &createdPlan)
	return createdPlan, err
}

// AddPlanEntry creates a new entry on plan planID and returns it
func (c *Client) AddPlanEntry(planID int, newEntry SendableEntry) (Entry, error) {
	createdEntry := Entry{}
	err := c.sendRequest("POST", "add_plan_entry/"+strconv.Itoa(planID), newEntry, &createdEntry)
	return createdEntry, err
}

// UpdatePlan updates the existing plan planID and returns it
func (c *Client) UpdatePlan(planID int, updates SendablePlan) (Plan, error) {
	updatedPlan := Plan{}
	err := c.sendRequest("POST", "update_plan/"+strconv.Itoa(planID), updates, &updatedPlan)
	return updatedPlan, err
}

// UpdatePlanEntry updates the entry entryID on plan planID and returns it
func (c *Client) UpdatePlanEntry(planID int, entryID string, updates SendableEntry) (Entry, error) {
	uri := "update_plan_entry/" + strconv.Itoa(planID) + "/" + entryID
	updatedEntry := Entry{}
	err := c.sendRequest("POST", uri, updates, &updatedEntry)
	return updatedEntry, err
}

// ClosePlan closes the plan planID and returns it
func (c *Client) ClosePlan(planID int) (Plan, error) {
	deletedPlan := Plan{}
	err := c.sendRequest("POST", "close_plan/"+strconv.Itoa(planID), nil, &deletedPlan)
	return deletedPlan, err
}

// DeletePlan deletes the plan planID
func (c *Client) DeletePlan(planID int) error {
	return c.sendRequest("POST", "delete_plan/"+strconv.Itoa(planID), nil, nil)
}

// DeletePlanEntry delete the entry entryID on plan planID
func (c *Client) DeletePlanEntry(planID int, entryID string) error {
	uri := "delete_plan_entry/" + strconv.Itoa(planID) + "/" + entryID
	return c.sendRequest("POST", uri, nil, nil)
}

// applyFiltersForPlan go through each possible filters and create the
// uri for the wanted ones
func applyFiltersForPlan(uri string, filters RequestFilterForPlan) string {
	if filters.CreatedAfter != "" {
		uri = uri + "&created_after=" + filters.CreatedAfter
	}
	if filters.CreatedBefore != "" {
		uri = uri + "&created_before=" + filters.CreatedBefore
	}
	if len(filters.CreatedBy) != 0 {
		uri = applySpecificFilter(uri, "created_by", filters.CreatedBy)
	}
	if len(filters.MilestoneID) != 0 {
		uri = applySpecificFilter(uri, "milestone_id", filters.MilestoneID)
	}
	if filters.IsCompleted != nil {
		uri = uri + "&is_completed=" + btoitos(*filters.IsCompleted)
	}
	if filters.Limit != nil {
		uri = uri + "&limit=" + strconv.Itoa(*filters.Limit)
	}
	if filters.Offset != nil {
		uri = uri + "&offset=" + strconv.Itoa(*filters.Offset)
	}

	return uri
}
<|endoftext|>