<commit_before>package interpreter

import (
	"errors"
	"fmt"
	"io"
	"os"
	"os/exec"
	"sync"
	"syscall"
)

var dbg = false

type CommandNotFound struct {
	Name string
	Err  error
}

// from "TDM-GCC-64/x86_64-w64-mingw32/include/winbase.h"
const (
	CREATE_NEW_CONSOLE       = 0x10
	CREATE_NEW_PROCESS_GROUP = 0x200
)

func (this CommandNotFound) Stringer() string {
	return fmt.Sprintf("'%s' is not recognized as an internal or external command,\noperable program or batch file", this.Name)
}

func (this CommandNotFound) Error() string {
	return this.Stringer()
}

type ErrorLevel int

const (
	NOERROR  ErrorLevel = 0
	THROUGH  ErrorLevel = -1
	SHUTDOWN ErrorLevel = -2
)

func (this ErrorLevel) HasValue() bool {
	return this >= NOERROR
}

func (this ErrorLevel) HasError() bool {
	return this > NOERROR
}

func (this ErrorLevel) String() string {
	switch this {
	case THROUGH:
		return "THROUGH"
	case SHUTDOWN:
		return "SHUTDOWN"
	default:
		return fmt.Sprintf("%d", this)
	}
}

type Interpreter struct {
	exec.Cmd
	Stdio        [3]*os.File
	HookCount    int
	Closer       []io.Closer
	Tag          interface{}
	PipeSeq      [2]uint
	IsBackGround bool

	CloneHook func(*Interpreter) error
	CloseHook func(*Interpreter)
}

func (this *Interpreter) closeAtEnd() {
	if this.Closer != nil {
		for _, c := range this.Closer {
			c.Close()
		}
		this.Closer = nil
	}
}

func (this *Interpreter) Close() {
	if this.CloseHook != nil {
		this.CloseHook(this)
		this.CloseHook = nil
	}
}

func New() *Interpreter {
	this := Interpreter{
		Stdio: [3]*os.File{os.Stdin, os.Stdout, os.Stderr},
	}
	this.Stdin = os.Stdin
	this.Stdout = os.Stdout
	this.Stderr = os.Stderr
	this.PipeSeq[0] = pipeSeq
	this.PipeSeq[1] = 0
	this.Tag = nil
	return &this
}

func (this *Interpreter) SetStdin(f *os.File) {
	this.Stdio[0] = f
	this.Stdin = f
}
func (this *Interpreter) SetStdout(f *os.File) {
	this.Stdio[1] = f
	this.Stdout = f
}
func (this *Interpreter) SetStderr(f *os.File) {
	this.Stdio[2] = f
	this.Stderr = f
}

func (this *Interpreter) Clone() (*Interpreter, error) {
	rv := new(Interpreter)
	rv.Stdio[0] = this.Stdio[0]
	rv.Stdio[1] = this.Stdio[1]
	rv.Stdio[2] = this.Stdio[2]
	rv.Stdin = this.Stdin
	rv.Stdout = this.Stdout
	rv.Stderr = this.Stderr
	rv.HookCount = this.HookCount
	rv.Tag = this.Tag
	rv.PipeSeq = rv.PipeSeq
	rv.Closer = nil
	rv.CloseHook = this.CloseHook
	rv.CloneHook = this.CloneHook
	if this.CloneHook != nil {
		if err := this.CloneHook(rv); err != nil {
			return nil, err
		}
	}
	return rv, nil
}

type ArgsHookT func(it *Interpreter, args []string) ([]string, error)

var argsHook = func(it *Interpreter, args []string) ([]string, error) {
	return args, nil
}

func SetArgsHook(argsHook_ ArgsHookT) (rv ArgsHookT) {
	rv, argsHook = argsHook, argsHook_
	return
}

type HookT func(*Interpreter) (ErrorLevel, error)

var hook = func(*Interpreter) (ErrorLevel, error) {
	return THROUGH, nil
}

func SetHook(hook_ HookT) (rv HookT) {
	rv, hook = hook, hook_
	return
}

var OnCommandNotFound = func(this *Interpreter, err error) error {
	err = &CommandNotFound{this.Args[0], err}
	return err
}

var ErrorLevelStr string

func nvl(a *os.File, b *os.File) *os.File {
	if a != nil {
		return a
	} else {
		return b
	}
}

func GetErrorLevel(processState *os.ProcessState) (int, bool) {
	if processState == nil {
		return 255, false
	} else if processState.Success() {
		return 0, true
	} else if t, ok := processState.Sys().(syscall.WaitStatus); ok {
		return t.ExitStatus(), true
	} else {
		return 255, false
	}
}

func (this *Interpreter) spawnvp_noerrmsg() (ErrorLevel, error) {
	// command is empty.
	if len(this.Args) <= 0 {
		return NOERROR, nil
	}
	if dbg {
		print("spawnvp_noerrmsg('", this.Args[0], "')\n")
	}

	// aliases and lua-commands
	if errorlevel, err := hook(this); errorlevel != THROUGH || err != nil {
		return errorlevel, err
	}

	// command not found hook
	var err error
	this.Path, err = exec.LookPath(this.Args[0])
	if err != nil {
		return ErrorLevel(255), OnCommandNotFound(this, err)
	}

	// executable-file
	if this.SysProcAttr != nil && (this.SysProcAttr.CreationFlags&CREATE_NEW_CONSOLE) != 0 {
		err = this.Start()
		return ErrorLevel(0), err
	}
	err = this.Run()

	errorlevel, errorlevelOk := GetErrorLevel(this.ProcessState)
	if errorlevelOk {
		return ErrorLevel(errorlevel), err
	} else {
		return ErrorLevel(255), err
	}
}

func (this *Interpreter) Spawnvp() (ErrorLevel, error) {
	errorlevel, err := this.spawnvp_noerrmsg()
	if err != nil {
		fmt.Fprintln(this.Stderr, err.Error())
	}
	return errorlevel, err
}

type result_t struct {
	NextValue ErrorLevel
	Error     error
}

var pipeSeq uint = 0

func (this *Interpreter) Interpret(text string) (errorlevel ErrorLevel, err error) {
	if dbg {
		print("Interpret('", text, "')\n")
	}
	if this == nil {
		return ErrorLevel(255), errors.New("Fatal Error: Interpret: instance is nil")
	}
	errorlevel = NOERROR
	err = nil

	statements, statementsErr := Parse(text)
	if statementsErr != nil {
		if dbg {
			print("Parse Error:", statementsErr.Error(), "\n")
		}
		return NOERROR, statementsErr
	}
	if argsHook != nil {
		if dbg {
			print("call argsHook\n")
		}
		for _, pipeline := range statements {
			for _, state := range pipeline {
				state.Argv, err = argsHook(this, state.Argv)
				if err != nil {
					return ErrorLevel(255), err
				}
			}
		}
		if dbg {
			print("done argsHook\n")
		}
	}
	for _, pipeline := range statements {
		for i, state := range pipeline {
			if state.Term == "|" && (i+1 >= len(pipeline) || len(pipeline[i+1].Argv) <= 0) {
				return ErrorLevel(255), errors.New("The syntax of the command is incorrect.")
			}
		}
	}

	for _, pipeline := range statements {

		var pipeIn *os.File = nil
		pipeSeq++
		isBackGround := this.IsBackGround
		for _, state := range pipeline {
			if state.Term == "&" {
				isBackGround = true
				break
			}
		}
		var wg sync.WaitGroup
		for i, state := range pipeline {
			if dbg {
				print(i, ": pipeline loop(", state.Argv[0], ")\n")
			}
			cmd := new(Interpreter)
			cmd.PipeSeq[0] = pipeSeq
			cmd.PipeSeq[1] = uint(1 + i)
			cmd.IsBackGround = isBackGround
			cmd.Tag = this.Tag
			cmd.HookCount = this.HookCount
			cmd.SetStdin(nvl(this.Stdio[0], os.Stdin))
			cmd.SetStdout(nvl(this.Stdio[1], os.Stdout))
			cmd.SetStderr(nvl(this.Stdio[2], os.Stderr))
			cmd.CloneHook = this.CloneHook
			if this.CloneHook != nil {
				if err := this.CloneHook(cmd); err != nil {
					return ErrorLevel(255), err
				}
			}

			var err error = nil

			if pipeIn != nil {
				cmd.SetStdin(pipeIn)
				cmd.Closer = append(cmd.Closer, pipeIn)
				pipeIn = nil
			}

			if state.Term[0] == '|' {
				var pipeOut *os.File
				pipeIn, pipeOut, err = os.Pipe()
				cmd.SetStdout(pipeOut)
				if state.Term == "|&" {
					cmd.SetStderr(pipeOut)
				}
				cmd.Closer = append(cmd.Closer, pipeOut)
			}

			for _, red := range state.Redirect {
				var fd *os.File
				fd, err = red.OpenOn(cmd)
				if err != nil {
					return NOERROR, err
				}
				defer fd.Close()
			}

			cmd.Args = state.Argv
			if i > 0 {
				cmd.IsBackGround = true
			}
			if i == len(pipeline)-1 && state.Term != "&" {
				errorlevel, err = cmd.Spawnvp()
				cmd.closeAtEnd()
				ErrorLevelStr = errorlevel.String()
				cmd.Close()
			} else {
				if !isBackGround {
					wg.Add(1)
				}
				go func(cmd1 *Interpreter) {
					if isBackGround {
						if len(pipeline) == 1 {
							cmd1.SysProcAttr = &syscall.SysProcAttr{
								CreationFlags: CREATE_NEW_CONSOLE |
									CREATE_NEW_PROCESS_GROUP,
							}
						}
					} else {
						defer wg.Done()
					}
					cmd1.Spawnvp()
					cmd1.closeAtEnd()
					cmd1.Close()
				}(cmd)
			}
		}
		if !isBackGround {
			wg.Wait()
		}
	}
	return
}
<commit_msg>Disable new feature to merge into master branch.<commit_after>package interpreter

import (
	"errors"
	"fmt"
	"io"
	"os"
	"os/exec"
	"sync"
	"syscall"
)

const FLAG_AMP2NEWCONSOLE = false

var dbg = false

type CommandNotFound struct {
	Name string
	Err  error
}

// from "TDM-GCC-64/x86_64-w64-mingw32/include/winbase.h"
const (
	CREATE_NEW_CONSOLE       = 0x10
	CREATE_NEW_PROCESS_GROUP = 0x200
)

func (this CommandNotFound) Stringer() string {
	return fmt.Sprintf("'%s' is not recognized as an internal or external command,\noperable program or batch file", this.Name)
}

func (this CommandNotFound) Error() string {
	return this.Stringer()
}

type ErrorLevel int

const (
	NOERROR  ErrorLevel = 0
	THROUGH  ErrorLevel = -1
	SHUTDOWN ErrorLevel = -2
)

func (this ErrorLevel) HasValue() bool {
	return this >= NOERROR
}

func (this ErrorLevel) HasError() bool {
	return this > NOERROR
}

func (this ErrorLevel) String() string {
	switch this {
	case THROUGH:
		return "THROUGH"
	case SHUTDOWN:
		return "SHUTDOWN"
	default:
		return fmt.Sprintf("%d", this)
	}
}

type Interpreter struct {
	exec.Cmd
	Stdio        [3]*os.File
	HookCount    int
	Closer       []io.Closer
	Tag          interface{}
	PipeSeq      [2]uint
	IsBackGround bool

	CloneHook func(*Interpreter) error
	CloseHook func(*Interpreter)
}

func (this *Interpreter) closeAtEnd() {
	if this.Closer != nil {
		for _, c := range this.Closer {
			c.Close()
		}
		this.Closer = nil
	}
}

func (this *Interpreter) Close() {
	if this.CloseHook != nil {
		this.CloseHook(this)
		this.CloseHook = nil
	}
}

func New() *Interpreter {
	this := Interpreter{
		Stdio: [3]*os.File{os.Stdin, os.Stdout, os.Stderr},
	}
	this.Stdin = os.Stdin
	this.Stdout = os.Stdout
	this.Stderr = os.Stderr
	this.PipeSeq[0] = pipeSeq
	this.PipeSeq[1] = 0
	this.Tag = nil
	return &this
}

func (this *Interpreter) SetStdin(f *os.File) {
	this.Stdio[0] = f
	this.Stdin = f
}
func (this *Interpreter) SetStdout(f *os.File) {
	this.Stdio[1] = f
	this.Stdout = f
}
func (this *Interpreter) SetStderr(f *os.File) {
	this.Stdio[2] = f
	this.Stderr = f
}

func (this *Interpreter) Clone() (*Interpreter, error) {
	rv := new(Interpreter)
	rv.Stdio[0] = this.Stdio[0]
	rv.Stdio[1] = this.Stdio[1]
	rv.Stdio[2] = this.Stdio[2]
	rv.Stdin = this.Stdin
	rv.Stdout = this.Stdout
	rv.Stderr = this.Stderr
	rv.HookCount = this.HookCount
	rv.Tag = this.Tag
	rv.PipeSeq = rv.PipeSeq
	rv.Closer = nil
	rv.CloseHook = this.CloseHook
	rv.CloneHook = this.CloneHook
	if this.CloneHook != nil {
		if err := this.CloneHook(rv); err != nil {
			return nil, err
		}
	}
	return rv, nil
}

type ArgsHookT func(it *Interpreter, args []string) ([]string, error)

var argsHook = func(it *Interpreter, args []string) ([]string, error) {
	return args, nil
}

func SetArgsHook(argsHook_ ArgsHookT) (rv ArgsHookT) {
	rv, argsHook = argsHook, argsHook_
	return
}

type HookT func(*Interpreter) (ErrorLevel, error)

var hook = func(*Interpreter) (ErrorLevel, error) {
	return THROUGH, nil
}

func SetHook(hook_ HookT) (rv HookT) {
	rv, hook = hook, hook_
	return
}

var OnCommandNotFound = func(this *Interpreter, err error) error {
	err = &CommandNotFound{this.Args[0], err}
	return err
}

var ErrorLevelStr string

func nvl(a *os.File, b *os.File) *os.File {
	if a != nil {
		return a
	} else {
		return b
	}
}

func GetErrorLevel(processState *os.ProcessState) (int, bool) {
	if processState == nil {
		return 255, false
	} else if processState.Success() {
		return 0, true
	} else if t, ok := processState.Sys().(syscall.WaitStatus); ok {
		return t.ExitStatus(), true
	} else {
		return 255, false
	}
}

func (this *Interpreter) spawnvp_noerrmsg() (ErrorLevel, error) {
	// command is empty.
	if len(this.Args) <= 0 {
		return NOERROR, nil
	}
	if dbg {
		print("spawnvp_noerrmsg('", this.Args[0], "')\n")
	}

	// aliases and lua-commands
	if errorlevel, err := hook(this); errorlevel != THROUGH || err != nil {
		return errorlevel, err
	}

	// command not found hook
	var err error
	this.Path, err = exec.LookPath(this.Args[0])
	if err != nil {
		return ErrorLevel(255), OnCommandNotFound(this, err)
	}

	// executable-file
	if FLAG_AMP2NEWCONSOLE {
		if this.SysProcAttr != nil && (this.SysProcAttr.CreationFlags&CREATE_NEW_CONSOLE) != 0 {
			err = this.Start()
			return ErrorLevel(0), err
		}
	}
	err = this.Run()

	errorlevel, errorlevelOk := GetErrorLevel(this.ProcessState)
	if errorlevelOk {
		return ErrorLevel(errorlevel), err
	} else {
		return ErrorLevel(255), err
	}
}

func (this *Interpreter) Spawnvp() (ErrorLevel, error) {
	errorlevel, err := this.spawnvp_noerrmsg()
	if err != nil {
		fmt.Fprintln(this.Stderr, err.Error())
	}
	return errorlevel, err
}

type result_t struct {
	NextValue ErrorLevel
	Error     error
}

var pipeSeq uint = 0

func (this *Interpreter) Interpret(text string) (errorlevel ErrorLevel, err error) {
	if dbg {
		print("Interpret('", text, "')\n")
	}
	if this == nil {
		return ErrorLevel(255), errors.New("Fatal Error: Interpret: instance is nil")
	}
	errorlevel = NOERROR
	err = nil

	statements, statementsErr := Parse(text)
	if statementsErr != nil {
		if dbg {
			print("Parse Error:", statementsErr.Error(), "\n")
		}
		return NOERROR, statementsErr
	}
	if argsHook != nil {
		if dbg {
			print("call argsHook\n")
		}
		for _, pipeline := range statements {
			for _, state := range pipeline {
				state.Argv, err = argsHook(this, state.Argv)
				if err != nil {
					return ErrorLevel(255), err
				}
			}
		}
		if dbg {
			print("done argsHook\n")
		}
	}
	for _, pipeline := range statements {
		for i, state := range pipeline {
			if state.Term == "|" && (i+1 >= len(pipeline) || len(pipeline[i+1].Argv) <= 0) {
				return ErrorLevel(255), errors.New("The syntax of the command is incorrect.")
			}
		}
	}

	for _, pipeline := range statements {

		var pipeIn *os.File = nil
		pipeSeq++
		isBackGround := this.IsBackGround
		for _, state := range pipeline {
			if state.Term == "&" {
				isBackGround = true
				break
			}
		}
		var wg sync.WaitGroup
		for i, state := range pipeline {
			if dbg {
				print(i, ": pipeline loop(", state.Argv[0], ")\n")
			}
			cmd := new(Interpreter)
			cmd.PipeSeq[0] = pipeSeq
			cmd.PipeSeq[1] = uint(1 + i)
			cmd.IsBackGround = isBackGround
			cmd.Tag = this.Tag
			cmd.HookCount = this.HookCount
			cmd.SetStdin(nvl(this.Stdio[0], os.Stdin))
			cmd.SetStdout(nvl(this.Stdio[1], os.Stdout))
			cmd.SetStderr(nvl(this.Stdio[2], os.Stderr))
			cmd.CloneHook = this.CloneHook
			if this.CloneHook != nil {
				if err := this.CloneHook(cmd); err != nil {
					return ErrorLevel(255), err
				}
			}

			var err error = nil

			if pipeIn != nil {
				cmd.SetStdin(pipeIn)
				cmd.Closer = append(cmd.Closer, pipeIn)
				pipeIn = nil
			}

			if state.Term[0] == '|' {
				var pipeOut *os.File
				pipeIn, pipeOut, err = os.Pipe()
				cmd.SetStdout(pipeOut)
				if state.Term == "|&" {
					cmd.SetStderr(pipeOut)
				}
				cmd.Closer = append(cmd.Closer, pipeOut)
			}

			for _, red := range state.Redirect {
				var fd *os.File
				fd, err = red.OpenOn(cmd)
				if err != nil {
					return NOERROR, err
				}
				defer fd.Close()
			}

			cmd.Args = state.Argv
			if i > 0 {
				cmd.IsBackGround = true
			}
			if i == len(pipeline)-1 && state.Term != "&" {
				errorlevel, err = cmd.Spawnvp()
				cmd.closeAtEnd()
				ErrorLevelStr = errorlevel.String()
				cmd.Close()
			} else {
				if !isBackGround {
					wg.Add(1)
				}
				go func(cmd1 *Interpreter) {
					if isBackGround {
						if FLAG_AMP2NEWCONSOLE {
							if len(pipeline) == 1 {
								cmd1.SysProcAttr = &syscall.SysProcAttr{
									CreationFlags: CREATE_NEW_CONSOLE |
										CREATE_NEW_PROCESS_GROUP,
								}
							}
						}
					} else {
						defer wg.Done()
					}
					cmd1.Spawnvp()
					cmd1.closeAtEnd()
					cmd1.Close()
				}(cmd)
			}
		}
		if !isBackGround {
			wg.Wait()
		}
	}
	return
}
<|endoftext|>


<commit_before>package practice

func SelectionSort(arr []int) {
	if arr == nil || len(arr) < 2 {
		return
	}

	for i := 0; i < len(arr)-1; i++ {
		minIndex := i

		j := i + 1
		for j < len(arr) {
			if arr[j] < arr[minIndex] {
				minIndex = j
			}

			j++
		}

		arr[i], arr[minIndex] = arr[minIndex], arr[i]
	}
}

---

package practice_test

import (
	"practice"
	"testing"
)

func TestSelectionSort(t *testing.T) {
	tests := []struct {
		Values   []int
		Expected []int
	}{
		{Values: nil, Expected: nil},
		{Values: []int{}, Expected: []int{}},
		{Values: []int{1}, Expected: []int{1}},
		{Values: []int{2, 1}, Expected: []int{1, 2}},
		{Values: []int{3, 2, 1}, Expected: []int{1, 2, 3}},
		{Values: []int{4, 3, 2, 1, 0, -1}, Expected: []int{-1, 0, 1, 2, 3, 4}},
	}

	for _, test := range tests {
		practice.SelectionSort(test.Values)
		for i := 0; i < len(test.Values); i++ {
			if test.Values[i] != test.Expected[i] {
				t.Errorf("Expected: %v, Actual: %v", test.Expected, test.Values)
			}
		}
	}
}
<commit_msg>Update selection sort with benchmark<commit_after>package practice

func SelectionSort(arr []int) {
	if arr == nil || len(arr) < 2 {
		return
	}

	for i := 0; i < len(arr)-1; i++ {
		minIndex := i

		j := i + 1
		for j < len(arr) {
			if arr[j] < arr[minIndex] {
				minIndex = j
			}

			j++
		}

		arr[i], arr[minIndex] = arr[minIndex], arr[i]
	}
}

---

package practice_test

import (
	"practice"
	"testing"
)

func TestSelectionSort(t *testing.T) {
	tests := []struct {
		Values   []int
		Expected []int
	}{
		{Values: nil, Expected: nil},
		{Values: []int{}, Expected: []int{}},
		{Values: []int{1}, Expected: []int{1}},
		{Values: []int{2, 1}, Expected: []int{1, 2}},
		{Values: []int{3, 2, 1}, Expected: []int{1, 2, 3}},
		{Values: []int{4, 3, 2, 1, 0, -1}, Expected: []int{-1, 0, 1, 2, 3, 4}},
	}

	for _, test := range tests {
		practice.SelectionSort(test.Values)
		for i := 0; i < len(test.Values); i++ {
			if test.Values[i] != test.Expected[i] {
				t.Errorf("Expected: %v, Actual: %v", test.Expected, test.Values)
			}
		}
	}
}

func BenchmarkSelectionSort(b *testing.B) {
	var tests [][]int
	var values []int

	// Seed pseudo random generator
	rand.Seed(99)

	// Generate 100 random integers
	for i := 0; i < 100; i++ {
		values = append(values, rand.Int())
	}

	// Create N slices of same 100 values
	for i := 0; i < b.N; i++ {
		newSlice := append([]int(nil), values...)
		tests = append(tests, newSlice)
	}

	// Ignore all the time spent above
	b.ResetTimer()

	// Go!
	for n := 0; n < b.N; n++ {
		practice.SelectionSort(tests[n])
	}
}
<|endoftext|>


<commit_before>package blackfish

import (
	"errors"
	"math/rand"
	"net"
	"strconv"
	"strings"
)

// A scalar value used to calculate a variety of limits
const LAMBDA = 2.5

// Currenty active nodes.
var liveNodes nodeMap = nodeMap{}

// Recently dead nodes. Periodically a random dead node will be allowed to
// rejoin the living.
var deadNodes nodeMap = nodeMap{}

var recentlyUpdated []*Node = make([]*Node, 0, 64)

func init() {
	liveNodes.init()
	deadNodes.init()
}

/******************************************************************************
 * Exported functions (for public consumption)
 *****************************************************************************/

// Adds a node. Returns node, error.
// Updates node heartbeat in the process, but DOES NOT implicitly update the
// node's status; you need to do this explicitly.
func AddNode(node *Node) (*Node, error) {
	if !liveNodes.contains(node) {
		logfInfo("Adding host: %s (status=%s)\n", node.Address(), node.status)

		if node.status == STATUS_NONE {
			logWarn(node.Address(), "does not have a status!")
		} else if node.status == STATUS_FORWARD_TO {
			panic("Invalid status: " + STATUS_FORWARD_TO.String())
		}

		node.Touch()

		_, n, err := liveNodes.add(node)

		return n, err
	} else {
		return node, nil
	}
}

// Given a node address ("ip:port" string), creates and returns a new node
// instance.
func CreateNodeByAddress(address string) (*Node, error) {
	ip, port, err := parseNodeAddress(address)

	if err == nil {
		node := Node{ip: ip, port: port, timestamp: GetNowInMillis()}

		return &node, nil
	}

	return nil, err
}

// Given a node address IP address and port, this function creates and returns
// a new node instance.
func CreateNodeByIP(ip net.IP, port uint16) (*Node, error) {
	return &Node{ip: ip, port: port, timestamp: GetNowInMillis()}, nil
}

// Queries the host interface to determine the local IPv4 of this machine.
func GetLocalIP() (net.IP, error) {
	var ip net.IP

	addrs, err := net.InterfaceAddrs()
	if err != nil {
		return ip, err
	}

	for _, a := range addrs {
		if ipnet, ok := a.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
			if ipnet.IP.To4() != nil {
				ip = ipnet.IP.To4()
				break
			}
		}
	}

	return ip, nil
}

// Removes a node. Returns node, error.
// Updates node heartbeat in the process, but DOES NOT implicitly update the
// node's status; you need to do this explicitly.
func RemoveNode(node *Node) (*Node, error) {
	if !liveNodes.contains(node) {
		logfInfo("Removing host: %s (status=%s)\n", node.Address(), node.status)

		node.Touch()

		_, n, err := liveNodes.delete(node)

		return n, err
	} else {
		return node, nil
	}
}

// Assigns a new status for the specified node, and adds that node to the
// recentlyUpdated list.
func UpdateNodeStatus(n *Node, status NodeStatus) {
	if n.status != status {
		n.timestamp = GetNowInMillis()
		n.status = status
		n.broadcastCounter = byte(announceCount())

		if n.status == STATUS_DIED {
			logfInfo("Node removed: %s\n", n.Address())

			RemoveNode(n)
			deadNodes.add(n)
		}

		// If this isn't in the recently updated list, add it.
		// TODO Replace with a map

		contains := false

		for _, ru := range recentlyUpdated {
			if ru.Address() == n.Address() {
				contains = true
				break
			}
		}

		if !contains {
			recentlyUpdated = append(recentlyUpdated, n)
		}

		doStatusUpdate(n, status)
	}
}

/******************************************************************************
 * Private functions (for internal use only)
 *****************************************************************************/

func getRandomUpdatedNodes(size int, exclude ...*Node) []*Node {
	// First, prune those with broadcast counters of zero from the list

	pruned := make([]*Node, 0, len(recentlyUpdated))
	for _, n := range recentlyUpdated {
		if n.broadcastCounter > 0 {
			pruned = append(pruned, n)
		} else {
			logInfo("Removing", n.Address(), "from recently updated list")
		}
	}
	recentlyUpdated = pruned

	// Make a copy of the recently update nodes slice

	updated_copy := make([]*Node, len(recentlyUpdated), len(recentlyUpdated))
	copy(updated_copy, recentlyUpdated)

	// Exclude the exclusions
	// TODO This is stupid inefficient. Use a set implementation of
	// some kind instead.

Outer:
	for _, nout := range exclude {
		for i, nin := range updated_copy {
			if nout.Address() == nin.Address() {
				tmp := updated_copy[0:i]

				for j := i + 1; j < len(updated_copy); j++ {
					tmp = append(tmp, updated_copy[j])
				}

				updated_copy = tmp

				continue Outer
			}
		}
	}

	// Shuffle the copy

	for i := range updated_copy {
		j := rand.Intn(i + 1)
		updated_copy[i], updated_copy[j] = updated_copy[j], updated_copy[i]
	}

	// Grab and return the top N

	if size > len(updated_copy) {
		size = len(updated_copy)
	}

	return updated_copy[:size]
}

func parseNodeAddress(hostAndMaybePort string) (net.IP, uint16, error) {
	var host string
	var ip net.IP
	var port uint16
	var err error

	if strings.Contains(hostAndMaybePort, ":") {
		splode := strings.Split(hostAndMaybePort, ":")

		if len(splode) == 2 {
			p, e := strconv.ParseUint(splode[1], 10, 16)

			host = splode[0]
			port = uint16(p)
			err = e
		} else {
			err = errors.New("too many colons in argument " + hostAndMaybePort)
		}
	} else {
		host = hostAndMaybePort
		port = uint16(GetListenPort())
	}

	ips, err := net.LookupIP(host)
	if err != nil {
		return ip, port, err
	}

	for _, i := range ips {
		if i.To4() != nil {
			ip = i.To4()
		}
	}

	if ip.IsLoopback() {
		ip, err = GetLocalIP()
	}

	return ip, port, err
}

// Returns a random dead node to the liveNodes map.
func resurrectDeadNode() {
	randomDeadNode := deadNodes.getRandomNode()

	deadNodes.delete(randomDeadNode)
	AddNode(randomDeadNode)
}
<commit_msg>Converting recently updated slice to a nodeMap<commit_after>package blackfish

import (
	"errors"
	"math/rand"
	"net"
	"strconv"
	"strings"
)

// A scalar value used to calculate a variety of limits
const LAMBDA = 2.5

// Currenty active nodes.
var liveNodes nodeMap = nodeMap{}

// Recently dead nodes. Periodically a random dead node will be allowed to
// rejoin the living.
var deadNodes nodeMap = nodeMap{}

// A collection of all nodes that have been updated "recently".
var recentlyUpdated nodeMap = nodeMap{}

func init() {
	liveNodes.init()
	deadNodes.init()
}

/******************************************************************************
 * Exported functions (for public consumption)
 *****************************************************************************/

// Adds a node. Returns node, error.
// Updates node heartbeat in the process, but DOES NOT implicitly update the
// node's status; you need to do this explicitly.
func AddNode(node *Node) (*Node, error) {
	if !liveNodes.contains(node) {
		logfInfo("Adding host: %s (status=%s)\n", node.Address(), node.status)

		if node.status == STATUS_NONE {
			logWarn(node.Address(), "does not have a status!")
		} else if node.status == STATUS_FORWARD_TO {
			panic("Invalid status: " + STATUS_FORWARD_TO.String())
		}

		node.Touch()

		_, n, err := liveNodes.add(node)

		return n, err
	} else {
		return node, nil
	}
}

// Given a node address ("ip:port" string), creates and returns a new node
// instance.
func CreateNodeByAddress(address string) (*Node, error) {
	ip, port, err := parseNodeAddress(address)

	if err == nil {
		node := Node{ip: ip, port: port, timestamp: GetNowInMillis()}

		return &node, nil
	}

	return nil, err
}

// Given a node address IP address and port, this function creates and returns
// a new node instance.
func CreateNodeByIP(ip net.IP, port uint16) (*Node, error) {
	return &Node{ip: ip, port: port, timestamp: GetNowInMillis()}, nil
}

// Queries the host interface to determine the local IPv4 of this machine.
func GetLocalIP() (net.IP, error) {
	var ip net.IP

	addrs, err := net.InterfaceAddrs()
	if err != nil {
		return ip, err
	}

	for _, a := range addrs {
		if ipnet, ok := a.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
			if ipnet.IP.To4() != nil {
				ip = ipnet.IP.To4()
				break
			}
		}
	}

	return ip, nil
}

// Removes a node. Returns node, error.
// Updates node heartbeat in the process, but DOES NOT implicitly update the
// node's status; you need to do this explicitly.
func RemoveNode(node *Node) (*Node, error) {
	if !liveNodes.contains(node) {
		logfInfo("Removing host: %s (status=%s)\n", node.Address(), node.status)

		node.Touch()

		_, n, err := liveNodes.delete(node)

		return n, err
	} else {
		return node, nil
	}
}

// Assigns a new status for the specified node, and adds that node to the
// recentlyUpdated list.
func UpdateNodeStatus(n *Node, status NodeStatus) {
	if n.status != status {
		n.timestamp = GetNowInMillis()
		n.status = status
		n.broadcastCounter = byte(announceCount())

		if n.status == STATUS_DIED {
			logfInfo("Node removed: %s\n", n.Address())

			RemoveNode(n)
			deadNodes.add(n)
		}

		// If this isn't in the recently updated list, add it.

		if !recentlyUpdated.contains(n) {
			recentlyUpdated.add(n)
		}

		doStatusUpdate(n, status)
	}
}

/******************************************************************************
 * Private functions (for internal use only)
 *****************************************************************************/

func getRandomUpdatedNodes(size int, exclude ...*Node) []*Node {
	// Prune nodes with broadcast counters of 0 (or less) from the list
	for _, n := range recentlyUpdated.values() {
		if n.broadcastCounter <= 0 {
			logInfo("Removing", n.Address(), "from recently updated list")
			recentlyUpdated.delete(n)
		}
	}

	// Make a copy of the recently update nodes slice

	updated_copy := recentlyUpdated.values()

	// Exclude the exclusions
	// TODO This is stupid inefficient. Use a set implementation of
	// some kind instead.

Outer:
	for _, nout := range exclude {
		for i, nin := range updated_copy {
			if nout.Address() == nin.Address() {
				tmp := updated_copy[0:i]

				for j := i + 1; j < len(updated_copy); j++ {
					tmp = append(tmp, updated_copy[j])
				}

				updated_copy = tmp

				continue Outer
			}
		}
	}

	// Shuffle the copy

	for i := range updated_copy {
		j := rand.Intn(i + 1)
		updated_copy[i], updated_copy[j] = updated_copy[j], updated_copy[i]
	}

	// Grab and return the top N

	if size > len(updated_copy) {
		size = len(updated_copy)
	}

	return updated_copy[:size]
}

func parseNodeAddress(hostAndMaybePort string) (net.IP, uint16, error) {
	var host string
	var ip net.IP
	var port uint16
	var err error

	if strings.Contains(hostAndMaybePort, ":") {
		splode := strings.Split(hostAndMaybePort, ":")

		if len(splode) == 2 {
			p, e := strconv.ParseUint(splode[1], 10, 16)

			host = splode[0]
			port = uint16(p)
			err = e
		} else {
			err = errors.New("too many colons in argument " + hostAndMaybePort)
		}
	} else {
		host = hostAndMaybePort
		port = uint16(GetListenPort())
	}

	ips, err := net.LookupIP(host)
	if err != nil {
		return ip, port, err
	}

	for _, i := range ips {
		if i.To4() != nil {
			ip = i.To4()
		}
	}

	if ip.IsLoopback() {
		ip, err = GetLocalIP()
	}

	return ip, port, err
}

// Returns a random dead node to the liveNodes map.
func resurrectDeadNode() {
	randomDeadNode := deadNodes.getRandomNode()

	deadNodes.delete(randomDeadNode)
	AddNode(randomDeadNode)
}
<|endoftext|>


<commit_before>package webhooks

import (
	"encoding/xml"
	"fmt"
	"io"
	"io/ioutil"

	"github.com/blacklightcms/go-recurly/recurly"
)

// Webhook notification constants.
const (
	SuccessfulPayment = "successful_payment_notification"
	FailedPayment     = "failed_payment_notification"
	PastDueInvoice    = "past_due_invoice_notification"
)

type notificationName struct {
	XMLName xml.Name
}

type (
	// SuccessfulPaymentNotification is sent when a payment is successful.
	SuccessfulPaymentNotification struct {
		Account     recurly.Account     `xml:"account"`
		Transaction recurly.Transaction `xml:"transaction"`
	}

	// FailedPaymentNotification is sent when a payment fails.
	FailedPaymentNotification struct {
		Account     recurly.Account     `xml:"account"`
		Transaction recurly.Transaction `xml:"transaction"`
	}

	// PastDueInvoiceNotification is sent when an invoice is past due.
	PastDueInvoiceNotification struct {
		Account recurly.Account `xml:"account"`
		Invoice recurly.Invoice `xml:"invoice"`
	}
)

// transactionHolder allows the uuid and invoice number fields to be set.
// The UUID field is labeled id in notifications and the invoice number
// is not included on the existing transaction struct.
type transactionHolder interface {
	setTransactionFields(id string, in int)
}

// setTransactionFields sets fields on the transaction struct.
func (n *SuccessfulPaymentNotification) setTransactionFields(id string, invoiceNumber int) {
	n.Transaction.UUID = id
	n.Transaction.InvoiceNumber = invoiceNumber
}

func (n *FailedPaymentNotification) setTransactionFields(id string, invoiceNumber int) {
	n.Transaction.UUID = id
	n.Transaction.InvoiceNumber = invoiceNumber
}

// transaction allows the transaction id and invoice number to be unmarshalled
// so they can be set on the notification struct.
type transaction struct {
	ID            string `xml:"transaction>id"`
	InvoiceNumber int    `xml:"transaction>invoice_number,omitempty"`
}

// ErrUnknownNotification is used when the incoming webhook does not match a
// predefined notification type. It implements the error interface.
type ErrUnknownNotification struct {
	name string
}

// Error implements the error interface.
func (e ErrUnknownNotification) Error() string {
	return fmt.Sprintf("unknown notification: %s", e.name)
}

// Name returns the name of the unknown notification.
func (e ErrUnknownNotification) Name() string {
	return e.name
}

// Parse parses an incoming webhook and returns the notification.
func Parse(r io.Reader) (interface{}, error) {
	if closer, ok := r.(io.Closer); ok {
		defer closer.Close()
	}

	notification, err := ioutil.ReadAll(r)
	if err != nil {
		return nil, err
	}

	var n notificationName
	if err := xml.Unmarshal(notification, &n); err != nil {
		return nil, err
	}

	var dst interface{}
	switch n.XMLName.Local {
	case SuccessfulPayment:
		dst = &SuccessfulPaymentNotification{}
	case FailedPayment:
		dst = &FailedPaymentNotification{}
	case PastDueInvoice:
		dst = &PastDueInvoiceNotification{}
	default:
		var unknown ErrUnknownNotification
		if err := xml.Unmarshal(notification, &unknown); err != nil {
			return nil, err
		}
		return nil, ErrUnknownNotification{name: n.XMLName.Local}
	}

	if err := xml.Unmarshal(notification, dst); err != nil {
		return nil, err
	}

	if th, ok := dst.(transactionHolder); ok {
		var t transaction
		if err := xml.Unmarshal(notification, &t); err != nil {
			return nil, err
		}
		th.setTransactionFields(t.ID, t.InvoiceNumber)
	}

	return dst, nil
}
<commit_msg>Removed extra code<commit_after>package webhooks

import (
	"encoding/xml"
	"fmt"
	"io"
	"io/ioutil"

	"github.com/blacklightcms/go-recurly/recurly"
)

// Webhook notification constants.
const (
	SuccessfulPayment = "successful_payment_notification"
	FailedPayment     = "failed_payment_notification"
	PastDueInvoice    = "past_due_invoice_notification"
)

type notificationName struct {
	XMLName xml.Name
}

type (
	// SuccessfulPaymentNotification is sent when a payment is successful.
	SuccessfulPaymentNotification struct {
		Account     recurly.Account     `xml:"account"`
		Transaction recurly.Transaction `xml:"transaction"`
	}

	// FailedPaymentNotification is sent when a payment fails.
	FailedPaymentNotification struct {
		Account     recurly.Account     `xml:"account"`
		Transaction recurly.Transaction `xml:"transaction"`
	}

	// PastDueInvoiceNotification is sent when an invoice is past due.
	PastDueInvoiceNotification struct {
		Account recurly.Account `xml:"account"`
		Invoice recurly.Invoice `xml:"invoice"`
	}
)

// transactionHolder allows the uuid and invoice number fields to be set.
// The UUID field is labeled id in notifications and the invoice number
// is not included on the existing transaction struct.
type transactionHolder interface {
	setTransactionFields(id string, in int)
}

// setTransactionFields sets fields on the transaction struct.
func (n *SuccessfulPaymentNotification) setTransactionFields(id string, invoiceNumber int) {
	n.Transaction.UUID = id
	n.Transaction.InvoiceNumber = invoiceNumber
}

func (n *FailedPaymentNotification) setTransactionFields(id string, invoiceNumber int) {
	n.Transaction.UUID = id
	n.Transaction.InvoiceNumber = invoiceNumber
}

// transaction allows the transaction id and invoice number to be unmarshalled
// so they can be set on the notification struct.
type transaction struct {
	ID            string `xml:"transaction>id"`
	InvoiceNumber int    `xml:"transaction>invoice_number,omitempty"`
}

// ErrUnknownNotification is used when the incoming webhook does not match a
// predefined notification type. It implements the error interface.
type ErrUnknownNotification struct {
	name string
}

// Error implements the error interface.
func (e ErrUnknownNotification) Error() string {
	return fmt.Sprintf("unknown notification: %s", e.name)
}

// Name returns the name of the unknown notification.
func (e ErrUnknownNotification) Name() string {
	return e.name
}

// Parse parses an incoming webhook and returns the notification.
func Parse(r io.Reader) (interface{}, error) {
	if closer, ok := r.(io.Closer); ok {
		defer closer.Close()
	}

	notification, err := ioutil.ReadAll(r)
	if err != nil {
		return nil, err
	}

	var n notificationName
	if err := xml.Unmarshal(notification, &n); err != nil {
		return nil, err
	}

	var dst interface{}
	switch n.XMLName.Local {
	case SuccessfulPayment:
		dst = &SuccessfulPaymentNotification{}
	case FailedPayment:
		dst = &FailedPaymentNotification{}
	case PastDueInvoice:
		dst = &PastDueInvoiceNotification{}
	default:
		return nil, ErrUnknownNotification{name: n.XMLName.Local}
	}

	if err := xml.Unmarshal(notification, dst); err != nil {
		return nil, err
	}

	if th, ok := dst.(transactionHolder); ok {
		var t transaction
		if err := xml.Unmarshal(notification, &t); err != nil {
			return nil, err
		}
		th.setTransactionFields(t.ID, t.InvoiceNumber)
	}

	return dst, nil
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"encoding/json"
	"fmt"
	"os/exec"
	"strconv"
	"strings"
	"time"

	"os"

	"github.com/google/go-github/github"
)

type MirroredPR struct {
	DownstreamID int
	UpstreamID   int
}

type PRMirror struct {
	GitHubClient  *github.Client
	Context       *context.Context
	Configuration *Config
	Database      *Database
}

func (p PRMirror) HandlePREvent(prEvent *github.PullRequestEvent) {

	prAction := prEvent.GetAction()

	log.Debugf("%s\n", prEvent.PullRequest.GetURL())

	if prAction == "closed" {
		if prEvent.PullRequest.GetMerged() == true {
			prID, err := p.MirrorPR(prEvent.PullRequest)
			if err != nil {
				log.Errorf("Error while creating a new PR: %s\n", err.Error())
			} else {
				p.AddLabels(prID, []string{"Upstream PR Merged"})
				p.Database.StoreMirror(prID, prEvent.PullRequest.GetNumber())
			}
		}
	}
}

func (p PRMirror) isRatelimit(err error) bool {
	if _, ok := err.(*github.RateLimitError); ok {
		// TODO: Maybe add some context here
		log.Error("The github.com rate limit has been hit")
		return true
	}
	return false
}

func (p PRMirror) GetRepoEvents() ([]*github.Event, int64, error) {
	var allEvents []*github.Event
	var pollInterval = int64(0)

	opt := &github.ListOptions{
		PerPage: 100,
	}

	for {
		log.Debugf("Getting RepoEvents Page %d\n", opt.Page)

		events, resp, err := p.GitHubClient.Activity.ListRepositoryEvents(*p.Context, p.Configuration.UpstreamOwner, p.Configuration.UpstreamRepo, opt)
		if err != nil {
			log.Errorf("Error while listing repository events. %s", err.Error())
			return nil, 60, err
		}

		allEvents = append(allEvents, events...)
		if resp.NextPage == 0 {
			pollInterval, err = strconv.ParseInt(resp.Response.Header.Get("X-Poll-Interval"), 10, 64)
			if err != nil {
				panic(err)
			}
			break
		}
		opt.Page = resp.NextPage
	}

	return allEvents, pollInterval, nil
}

func (p PRMirror) GetOpenPRs() ([]*github.PullRequest, error) {
	var allPrs []*github.PullRequest

	opt := &github.PullRequestListOptions{
		ListOptions: github.ListOptions{PerPage: 100},
	}

	for {
		log.Debugf("Getting OpenPRs Page %d\n", opt.ListOptions.Page)

		prs, resp, err := p.GitHubClient.PullRequests.List(*p.Context, p.Configuration.UpstreamOwner, p.Configuration.UpstreamRepo, opt)
		if p.isRatelimit(err) {
			return nil, err
		}

		allPrs = append(allPrs, prs...)
		if resp.NextPage == 0 {
			break
		}
		opt.ListOptions.Page = resp.NextPage
	}

	return allPrs, nil
}

func (p PRMirror) InitialImport() {
	prs, err := p.GetOpenPRs()
	if p.isRatelimit(err) {
		return
	}

	for _, pr := range prs {
		prNum, err := p.Database.GetDownstreamID(pr.GetNumber())
		if err != nil {
			panic(err)
		}

		if prNum != 0 {
			log.Infof("DUP: [%d] - %s\n", pr.GetNumber(), pr.GetTitle())
		} else {
			log.Infof("NEW: [%d] - %s\n", pr.GetNumber(), pr.GetTitle())
			prID, err := p.MirrorPR(pr)
			if err != nil {
				log.Errorf("Error while creating a new PR: %s\n", err.Error())
			} else {
				p.Database.StoreMirror(prID, pr.GetNumber())
				p.AddLabels(prID, []string{"Upstream PR Open"})
			}
			time.Sleep(2 * time.Second)
		}
	}
}

func (p PRMirror) Run() {
	for {
		events, pollInterval, err := p.GetRepoEvents()
		if err == nil {
			for _, event := range events {
				seenEvent, _ := p.Database.SeenEvent(event.GetID())

				if !seenEvent {
					eventType := event.GetType()

					if eventType == "PullRequestEvent" {
						prEvent := github.PullRequestEvent{}
						err = json.Unmarshal(event.GetRawPayload(), &prEvent)
						if err != nil {
							panic(err)
						}

						p.HandlePREvent(&prEvent)
						p.Database.AddEvent(event.GetID())
					}
				}
			}
		}

		log.Debugf("Sleeping for %d as specified by GitHub\n", pollInterval)
		time.Sleep(time.Duration(pollInterval) * time.Second)
	}
}

func (p PRMirror) MirrorPR(pr *github.PullRequest) (int, error) {
	log.Infof("Mirroring PR [%d]: %s from %s\n", pr.GetNumber(), pr.GetTitle(), pr.User.GetLogin())

	cmd := exec.Command(fmt.Sprintf("%s%s", p.Configuration.RepoPath, p.Configuration.ToolPath), strconv.Itoa(pr.GetNumber()), pr.GetTitle())
	cmd.Dir = p.Configuration.RepoPath
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err := cmd.Start()
	if err != nil {
		panic(err)
	}
	err = cmd.Wait()
	if err != nil {
		panic(err)
	}

	base := "master"
	head := fmt.Sprintf("upstream-merge-%d", pr.GetNumber())
	maintainerCanModify := true // we own it so yes
	title := fmt.Sprintf("[MIRROR] %s", pr.GetTitle())
	body := fmt.Sprintf("Original PR: %s\n--------------------\n%s", pr.GetHTMLURL(), strings.Replace(pr.GetBody(), "@", "@ ", -1))

	newPR := github.NewPullRequest{}
	newPR.Title = &title
	newPR.Body = &body
	newPR.Base = &base
	newPR.Head = &head
	newPR.MaintainerCanModify = &maintainerCanModify

	pr, _, err = p.GitHubClient.PullRequests.Create(*p.Context, p.Configuration.DownstreamOwner, p.Configuration.DownstreamRepo, &newPR)
	if err != nil {
		return 0, err
	}

	return pr.GetNumber(), nil
}

func (p PRMirror) CreateLabel(labelText string, labelColour string) bool {
	label := github.Label{
		Name:  &labelText,
		Color: &labelColour,
	}

	_, _, err := p.GitHubClient.Issues.CreateLabel(*p.Context, p.Configuration.DownstreamOwner, p.Configuration.DownstreamRepo, &label)
	if err != nil {
		log.Errorf("Error while creating a label - %s", err.Error())
		return false
	}

	return true
}

func (p PRMirror) AddLabels(id int, labels []string) bool {
	_, _, err := p.GitHubClient.Issues.AddLabelsToIssue(*p.Context, p.Configuration.DownstreamOwner, p.Configuration.DownstreamRepo, id, labels)
	if err != nil {
		log.Errorf("Error while adding a label on issue#:%d - %s", id, err.Error())
		return false
	}

	return true
}

func (p PRMirror) RemoveLabel(id int, labels string) bool {
	_, err := p.GitHubClient.Issues.RemoveLabelForIssue(*p.Context, p.Configuration.DownstreamOwner, p.Configuration.DownstreamRepo, id, labels)
	if err != nil {
		log.Errorf("Error while removing a label on issue#:%d - %s", id, err.Error())
		return false
	}

	return true
}

func (p PRMirror) AddComment(id int, comment string) bool {
	issueComment := github.IssueComment{}
	issueComment.Body = &comment

	_, _, err := p.GitHubClient.Issues.CreateComment(*p.Context, p.Configuration.DownstreamOwner, p.Configuration.DownstreamRepo, id, &issueComment)
	if err != nil {
		log.Errorf("Error while adding a comment to issue#:%d - %s", id, err.Error())
		return false
	}

	return true
}
<commit_msg>Try that!<commit_after>package main

import (
	"context"
	"encoding/json"
	"fmt"
	"os/exec"
	"strconv"
	"strings"
	"time"

	"os"

	"github.com/google/go-github/github"
)

type MirroredPR struct {
	DownstreamID int
	UpstreamID   int
}

type PRMirror struct {
	GitHubClient  *github.Client
	Context       *context.Context
	Configuration *Config
	Database      *Database
}

func (p PRMirror) HandlePREvent(prEvent *github.PullRequestEvent) {

	prAction := prEvent.GetAction()

	log.Debugf("%s\n", prEvent.PullRequest.GetURL())

	if prAction == "closed" {
		if prEvent.PullRequest.GetMerged() == true {
			prID, err := p.MirrorPR(prEvent.PullRequest)
			if err != nil {
				log.Errorf("Error while creating a new PR: %s\n", err.Error())
			} else {
				p.AddLabels(prID, []string{"Upstream PR Merged"})
				p.Database.StoreMirror(prID, prEvent.PullRequest.GetNumber())
			}
		}
	}
}

func (p PRMirror) isRatelimit(err error) bool {
	if _, ok := err.(*github.RateLimitError); ok {
		// TODO: Maybe add some context here
		log.Error("The github.com rate limit has been hit")
		return true
	}
	return false
}

func (p PRMirror) GetRepoEvents() ([]*github.Event, int64, error) {
	var allEvents []*github.Event
	var pollInterval = int64(0)

	opt := &github.ListOptions{
		PerPage: 100,
	}

	for {
		log.Debugf("Getting RepoEvents Page %d\n", opt.Page)

		events, resp, err := p.GitHubClient.Activity.ListRepositoryEvents(*p.Context, p.Configuration.UpstreamOwner, p.Configuration.UpstreamRepo, opt)
		if err != nil {
			log.Errorf("Error while listing repository events. %s", err.Error())
			return nil, 60, err
		}

		allEvents = append(allEvents, events...)
		if resp.NextPage == 0 {
			pollInterval, err = strconv.ParseInt(resp.Response.Header.Get("X-Poll-Interval"), 10, 64)
			if err != nil {
				panic(err)
			}
			break
		}
		opt.Page = resp.NextPage
	}

	return allEvents, pollInterval, nil
}

func (p PRMirror) GetOpenPRs() ([]*github.PullRequest, error) {
	var allPrs []*github.PullRequest

	opt := &github.PullRequestListOptions{
		ListOptions: github.ListOptions{PerPage: 100},
	}

	for {
		log.Debugf("Getting OpenPRs Page %d\n", opt.ListOptions.Page)

		prs, resp, err := p.GitHubClient.PullRequests.List(*p.Context, p.Configuration.UpstreamOwner, p.Configuration.UpstreamRepo, opt)
		if p.isRatelimit(err) {
			return nil, err
		}

		allPrs = append(allPrs, prs...)
		if resp.NextPage == 0 {
			break
		}
		opt.ListOptions.Page = resp.NextPage
	}

	return allPrs, nil
}

func (p PRMirror) InitialImport() {
	prs, err := p.GetOpenPRs()
	if p.isRatelimit(err) {
		return
	}

	for _, pr := range prs {
		prNum, err := p.Database.GetDownstreamID(pr.GetNumber())
		if err != nil {
			panic(err)
		}

		if prNum != 0 {
			log.Infof("DUP: [%d] - %s\n", pr.GetNumber(), pr.GetTitle())
		} else {
			log.Infof("NEW: [%d] - %s\n", pr.GetNumber(), pr.GetTitle())
			prID, err := p.MirrorPR(pr)
			if err != nil {
				log.Errorf("Error while creating a new PR: %s\n", err.Error())
			} else {
				p.Database.StoreMirror(prID, pr.GetNumber())
				p.AddLabels(prID, []string{"Upstream PR Open"})
			}
			time.Sleep(2 * time.Second)
		}
	}
}

func (p PRMirror) Run() {
	for {
		events, pollInterval, err := p.GetRepoEvents()
		if err == nil {
			for _, event := range events {
				seenEvent, _ := p.Database.SeenEvent(event.GetID())

				if !seenEvent {
					eventType := event.GetType()

					if eventType == "PullRequestEvent" {
						prEvent := github.PullRequestEvent{}
						err = json.Unmarshal(event.GetRawPayload(), &prEvent)
						if err != nil {
							panic(err)
						}

						p.HandlePREvent(&prEvent)
						p.Database.AddEvent(event.GetID())
					}
				}
			}
		}

		log.Debugf("Sleeping for %d as specified by GitHub\n", pollInterval)
		time.Sleep(time.Duration(pollInterval) * time.Second)
	}
}

func (p PRMirror) MirrorPR(pr *github.PullRequest) (int, error) {
	log.Infof("Mirroring PR [%d]: %s from %s\n", pr.GetNumber(), pr.GetTitle(), pr.User.GetLogin())

	cmd := exec.Command(fmt.Sprintf("%s%s", p.Configuration.RepoPath, p.Configuration.ToolPath), strconv.Itoa(pr.GetNumber()), pr.GetTitle())
	cmd.Dir = p.Configuration.RepoPath
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err := cmd.Start()
	if err != nil {
		panic(err)
	}
	err = cmd.Wait()
	if err != nil {
		panic(err)
	}

	cmdoutput, err := cmd.Output()

	base := "master"
	head := fmt.Sprintf("upstream-merge-%d", pr.GetNumber())
	maintainerCanModify := true // we own it so yes
	title := fmt.Sprintf("[MIRROR] %s", pr.GetTitle())
	body := fmt.Sprintf("Original PR: %s\n--------------------\n%s", pr.GetHTMLURL(), strings.Replace(pr.GetBody(), "@", "@ ", -1))

	newPR := github.NewPullRequest{}
	newPR.Title = &title
	newPR.Body = &body
	newPR.Base = &base
	newPR.Head = &head
	newPR.MaintainerCanModify = &maintainerCanModify

	pr, _, err = p.GitHubClient.PullRequests.Create(*p.Context, p.Configuration.DownstreamOwner, p.Configuration.DownstreamRepo, &newPR)
	if err != nil {
		return 0, err
	}

	if strings.Contains(string(cmdoutput), "Rejected hunk") {
		p.AddLabels(pr.GetNumber(), []string{"Auto Merge Rejections"})
	}

	return pr.GetNumber(), nil
}

func (p PRMirror) CreateLabel(labelText string, labelColour string) bool {
	label := github.Label{
		Name:  &labelText,
		Color: &labelColour,
	}

	_, _, err := p.GitHubClient.Issues.CreateLabel(*p.Context, p.Configuration.DownstreamOwner, p.Configuration.DownstreamRepo, &label)
	if err != nil {
		log.Errorf("Error while creating a label - %s", err.Error())
		return false
	}

	return true
}

func (p PRMirror) AddLabels(id int, labels []string) bool {
	_, _, err := p.GitHubClient.Issues.AddLabelsToIssue(*p.Context, p.Configuration.DownstreamOwner, p.Configuration.DownstreamRepo, id, labels)
	if err != nil {
		log.Errorf("Error while adding a label on issue#:%d - %s", id, err.Error())
		return false
	}

	return true
}

func (p PRMirror) RemoveLabel(id int, labels string) bool {
	_, err := p.GitHubClient.Issues.RemoveLabelForIssue(*p.Context, p.Configuration.DownstreamOwner, p.Configuration.DownstreamRepo, id, labels)
	if err != nil {
		log.Errorf("Error while removing a label on issue#:%d - %s", id, err.Error())
		return false
	}

	return true
}

func (p PRMirror) AddComment(id int, comment string) bool {
	issueComment := github.IssueComment{}
	issueComment.Body = &comment

	_, _, err := p.GitHubClient.Issues.CreateComment(*p.Context, p.Configuration.DownstreamOwner, p.Configuration.DownstreamRepo, id, &issueComment)
	if err != nil {
		log.Errorf("Error while adding a comment to issue#:%d - %s", id, err.Error())
		return false
	}

	return true
}
<|endoftext|>


<commit_before>// Package referrer analyzes and classifies different kinds of referrer URLs (search, social, ...).
package referrer

import (
	"net/url"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
)

var (
	SearchRules   map[string]SearchRule // domain mapping of known rules for search engines.
	SocialRules   map[string]SocialRule // domain mapping of known rules for social sites.
	EmailRules    map[string]EmailRule  // domain mapping of known rules for email sites.
	SearchEngines map[string]SearchRule // list of search engines used for fuzzy matching
	once          sync.Once
)

// Indirect is a referrer that doesn't match any of the other referrer types.
type Indirect struct {
	URL    string // original referrer URL
	Domain string // domain of original referrer URL
}

// Direct is an internal referrer.
// It can only be obtained by calling the extended ParseWithDirect()
type Direct struct {
	URL    string // direct referrer URL
	Domain string // domain of direct referrer URL
}

// Search is a referrer from a set of well known search engines as defined by Google Analytics.
// https://developers.google.com/analytics/devguides/collection/gajs/gaTrackingTraffic.
type Search struct {
	URL    string // search engine referrer URL
	Domain string // matched domain of the search engine, e.g. google.com
	Label  string // search engine label, e.g. Google
	Query  string // decoded search query
}

// Social is a referrer from a set of well know social sites.
type Social struct {
	URL    string // social referrer URL
	Domain string // matched domain of the social site, e.g. twitter.com or t.co
	Label  string // social site label, e.g. Twitter
}

// Email is a referrer from a set of well know email sites.
type Email struct {
	Url    string // email referrer URL
	Domain string // matched domain of the email site, e.g. mail.google.com.com
	Label  string // email site label, e.g. Gmail
}

func init() {
	_, filename, _, _ := runtime.Caller(1)
	once.Do(func() {
		rulesPath := path.Join(path.Dir(filename), path.Join(DataDir, RulesFilename))
		err := InitRules(rulesPath)
		if err != nil {
			panic(err)
		}
		enginesPath := path.Join(path.Dir(filename), path.Join(DataDir, EnginesFilename))
		err = InitSearchEngines(enginesPath)
		if err != nil {
			panic(err)
		}
	})
}

// Parse takes a URL string and turns it into one of the supported referrer types.
// It returns an error if the input is not a valid URL input.
func Parse(url string) (interface{}, error) {
	refURL, err := parseURL(url)
	if err != nil {
		return nil, err
	}
	return parse(url, refUrl, nil)
}

// ParseWithDirect is an extended version of Parse that adds Direct to the set of possible results.
// The additional arguments specify the domains that are to be considered "direct".
func ParseWithDirect(url string, directDomains ...string) (interface{}, error) {
	refURL, err := parseURL(url)
	if err != nil {
		return nil, err
	}
	return parse(url, refUrl, directDomains)
}

func parse(u string, refUrl *url.URL, directDomains []string) (interface{}, error) {

	// Parse as direct url
	if directDomains != nil {
		direct, err := parseDirect(u, refUrl, directDomains)
		if err != nil {
			return nil, err
		}
		if direct != nil {
			return direct, nil
		}
	}

	// Parse as email referrer.
	email, err := parseEmail(u, refUrl)
	if err != nil {
		return nil, err
	}
	if email != nil {
		return email, nil
	}

	// Parse as social referrer.
	social, err := parseSocial(u, refUrl)
	if err != nil {
		return nil, err
	}
	if social != nil {
		return social, nil
	}

	// Parse as search referrer.
	engine, err := parseSearch(u, refUrl)
	if err != nil {
		return nil, err
	}
	if engine != nil {
		return engine, nil
	}

	engine, err = fuzzyParseSearch(refUrl)
	if err != nil {
		return nil, err
	}
	if engine != nil {
		return engine, nil
	}

	// Parse and return as indirect referrer.
	return &Indirect{Url: u, Domain: refUrl.Host}, nil
}

func parseURL(u string) (*url.URL, error) {
	refURL, err := url.Parse(u)
	if err != nil {
		return nil, err
	}
	return refURL, nil
}

func parseDirect(rawUrl string, u *url.URL, directDomains []string) (*Direct, error) {
	for _, host := range directDomains {
		if host == u.Host {
			return &Direct{Url: rawUrl, Domain: u.Host}, nil
		}
	}
	return nil, nil
}

func parseSocial(rawUrl string, u *url.URL) (*Social, error) {
	if rule, ok := SocialRules[u.Host]; ok {
		return &Social{Url: rawUrl, Domain: rule.Domain, Label: rule.Label}, nil
	}
	return nil, nil
}

func parseEmail(rawUrl string, u *url.URL) (*Email, error) {
	if rule, ok := EmailRules[u.Host]; ok {
		return &Email{Url: rawUrl, Domain: rule.Domain, Label: rule.Label}, nil
	}
	return nil, nil
}

func parseSearch(rawUrl string, u *url.URL) (*Search, error) {
	query := u.Query()
	if rule, ok := SearchRules[u.Host]; ok {
		for _, param := range rule.Parameters {
			if query := query.Get(param); query != "" {
				return &Search{Url: rawUrl, Domain: rule.Domain, Label: rule.Label, Query: query}, nil
			}
		}
	}
	return nil, nil
}

func fuzzyParseSearch(u *url.URL) (*Search, error) {
	hostParts := strings.Split(u.Host, ".")
	query := u.Query()
	for _, hostPart := range hostParts {
		if engine, present := SearchEngines[hostPart]; present {
			for _, param := range engine.Parameters {
				if search, ok := query[param]; ok && search[0] != "" {
					return &Search{Label: engine.Label, Query: search[0], Domain: u.Host}, nil
				}
			}
		}
	}
	return nil, nil
}
<commit_msg>simplify error checking<commit_after>// Package referrer analyzes and classifies different kinds of referrer URLs (search, social, ...).
package referrer

import (
	"net/url"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
)

var (
	SearchRules   map[string]SearchRule // domain mapping of known rules for search engines.
	SocialRules   map[string]SocialRule // domain mapping of known rules for social sites.
	EmailRules    map[string]EmailRule  // domain mapping of known rules for email sites.
	SearchEngines map[string]SearchRule // list of search engines used for fuzzy matching
	once          sync.Once
)

// Indirect is a referrer that doesn't match any of the other referrer types.
type Indirect struct {
	URL    string // original referrer URL
	Domain string // domain of original referrer URL
}

// Direct is an internal referrer.
// It can only be obtained by calling the extended ParseWithDirect()
type Direct struct {
	URL    string // direct referrer URL
	Domain string // domain of direct referrer URL
}

// Search is a referrer from a set of well known search engines as defined by Google Analytics.
// https://developers.google.com/analytics/devguides/collection/gajs/gaTrackingTraffic.
type Search struct {
	URL    string // search engine referrer URL
	Domain string // matched domain of the search engine, e.g. google.com
	Label  string // search engine label, e.g. Google
	Query  string // decoded search query
}

// Social is a referrer from a set of well know social sites.
type Social struct {
	URL    string // social referrer URL
	Domain string // matched domain of the social site, e.g. twitter.com or t.co
	Label  string // social site label, e.g. Twitter
}

// Email is a referrer from a set of well know email sites.
type Email struct {
	Url    string // email referrer URL
	Domain string // matched domain of the email site, e.g. mail.google.com.com
	Label  string // email site label, e.g. Gmail
}

func init() {
	_, filename, _, _ := runtime.Caller(1)
	once.Do(func() {
		rulesPath := path.Join(path.Dir(filename), path.Join(DataDir, RulesFilename))
		err := InitRules(rulesPath)
		if err != nil {
			panic(err)
		}
		enginesPath := path.Join(path.Dir(filename), path.Join(DataDir, EnginesFilename))
		err = InitSearchEngines(enginesPath)
		if err != nil {
			panic(err)
		}
	})
}

// Parse takes a URL string and turns it into one of the supported referrer types.
// It returns an error if the input is not a valid URL input.
func Parse(url string) (interface{}, error) {
	refURL, err := parseURL(url)
	if err != nil {
		return nil, err
	}
	return parse(url, refUrl, nil)
}

// ParseWithDirect is an extended version of Parse that adds Direct to the set of possible results.
// The additional arguments specify the domains that are to be considered "direct".
func ParseWithDirect(url string, directDomains ...string) (interface{}, error) {
	refURL, err := parseURL(url)
	if err != nil {
		return nil, err
	}
	return parse(url, refUrl, directDomains)
}

func parse(u string, refUrl *url.URL, directDomains []string) (interface{}, error) {

	// Parse as direct url
	if directDomains != nil {
		direct, err := parseDirect(u, refUrl, directDomains)
		if !(err == nil && direct == nil) {
			return direct, err
		}
	}

	// Parse as email referrer.
	email, err := parseEmail(u, refUrl)
	if !(err == nil && email == nil) {
		return email, err
	}

	// Parse as social referrer.
	social, err := parseSocial(u, refUrl)
	if !(err == nil && social == nil) {
		return social, err
	}

	// Parse as search referrer.
	engine, err := parseSearch(u, refUrl)
	if !(err == nil && engine == nil) {
		return engine, err
	}

	engine, err = fuzzyParseSearch(refUrl)
	if !(err == nil && engine == nil) {
		return engine, err
	}

	// Parse and return as indirect referrer.
	return &Indirect{Url: u, Domain: refUrl.Host}, nil
}

func parseURL(u string) (*url.URL, error) {
	refURL, err := url.Parse(u)
	if err != nil {
		return nil, err
	}
	return refURL, nil
}

func parseDirect(rawUrl string, u *url.URL, directDomains []string) (*Direct, error) {
	for _, host := range directDomains {
		if host == u.Host {
			return &Direct{Url: rawUrl, Domain: u.Host}, nil
		}
	}
	return nil, nil
}

func parseSocial(rawUrl string, u *url.URL) (*Social, error) {
	if rule, ok := SocialRules[u.Host]; ok {
		return &Social{Url: rawUrl, Domain: rule.Domain, Label: rule.Label}, nil
	}
	return nil, nil
}

func parseEmail(rawUrl string, u *url.URL) (*Email, error) {
	if rule, ok := EmailRules[u.Host]; ok {
		return &Email{Url: rawUrl, Domain: rule.Domain, Label: rule.Label}, nil
	}
	return nil, nil
}

func parseSearch(rawUrl string, u *url.URL) (*Search, error) {
	query := u.Query()
	if rule, ok := SearchRules[u.Host]; ok {
		for _, param := range rule.Parameters {
			if query := query.Get(param); query != "" {
				return &Search{Url: rawUrl, Domain: rule.Domain, Label: rule.Label, Query: query}, nil
			}
		}
	}
	return nil, nil
}

func fuzzyParseSearch(u *url.URL) (*Search, error) {
	hostParts := strings.Split(u.Host, ".")
	query := u.Query()
	for _, hostPart := range hostParts {
		if engine, present := SearchEngines[hostPart]; present {
			for _, param := range engine.Parameters {
				if search, ok := query[param]; ok && search[0] != "" {
					return &Search{Label: engine.Label, Query: search[0], Domain: u.Host}, nil
				}
			}
		}
	}
	return nil, nil
}
<|endoftext|>


<commit_before>package cookies

import (
	"encoding/json"
	"net/http"
	"time"

	"github.com/divoxx/goRailsYourself/crypto"
)

// CookieEncryptor implements cookie encryption and signing to allow securely storing sensitive
// information on the user-agent.
type CookieEncryptor struct {
	messageEncryptor crypto.MessageEncryptor
}

// NewCookieEncryptor creates a new instance of CookieEncryptor. Creating this instance is expensive
// since it has to derives the keys.
func NewCookieEncryptor(secret string, iterations int) *CookieEncryptor {
	var (
		kg      = crypto.KeyGenerator{Secret: secret, Iterations: iterations}
		key     = kg.CacheGenerate([]byte("encrypted cookie"), 32)
		signKey = kg.CacheGenerate([]byte("signed encrypted cookie"), 64)
	)

	ce := &CookieEncryptor{
		messageEncryptor: crypto.MessageEncryptor{Key: key, SignKey: signKey, Serializer: crypto.NullMsgSerializer{}},
	}

	return ce
}

// Encrypt takes an http.Cookie instance and encrypts and sign it's value, replacing it.
func (ce *CookieEncryptor) Encrypt(cookie *http.Cookie) error {
	encValue, err := ce.messageEncryptor.EncryptAndSign(cookie.Value)
	if err != nil {
		return err
	}

	cookie.Value = encValue
	return nil
}

// Decrypt takes an encrypted http.Cookie instance and decrypts it.
func (ce *CookieEncryptor) Decrypt(cookie *http.Cookie) error {
	var value string

	if cookie.Value == "" {
		return nil
	}

	err := ce.messageEncryptor.DecryptAndVerify(cookie.Value, &value)
	if err != nil {
		return err
	}

	cookie.Value = value
	return nil
}

// CookieEncoder encodes/decodes a specific data structure into a cookie's content.
type CookieEncoder interface {
	Encode(v interface{}, c *http.Cookie) error
	Decode(v interface{}, c *http.Cookie) error
}

// JSONCookieEncoder encodes/decodes cookies using encoding/json
type JSONCookieEncoder struct{}

func (e JSONCookieEncoder) Encode(v interface{}, c *http.Cookie) error {
	b, err := json.Marshal(v)
	if err != nil {
		return err
	}

	c.Value = string(b)
	return nil
}

func (e JSONCookieEncoder) Decode(v interface{}, c *http.Cookie) error {
	if err := json.Unmarshal([]byte(c.Value), v); err != nil {
		return err
	}

	return nil
}

type SecureCookieManager struct {
	Encryptor *CookieEncryptor
	Encoder   CookieEncoder
}

type CookieOptions struct {
	Domain   string
	Path     string
	HTTPOnly bool
	Secure   bool
	MaxAge   time.Duration
}

// Set a cookie with the data set to the encrypted version of the serialization of v.
// Returns the http.Cookie generated.
func (cm *SecureCookieManager) Set(w http.ResponseWriter, name string, opts *CookieOptions, v interface{}) (*http.Cookie, error) {
	var err error

	if opts == nil {
		opts = &CookieOptions{}
	}

	cookie := http.Cookie{
		Name:     name,
		Domain:   opts.Domain,
		Path:     opts.Path,
		HttpOnly: opts.HTTPOnly,
		Secure:   opts.Secure,
		MaxAge:   int(opts.MaxAge.Seconds()),
	}

	if err := cm.Encoder.Encode(v, &cookie); err != nil {
		return &cookie, err
	}

	if err = cm.Encryptor.Encrypt(&cookie); err != nil {
		return &cookie, err
	}

	http.SetCookie(w, &cookie)
	return &cookie, nil
}

// Get gets the Cookie, decrypted it and deserialized it into v.
// Returns the decrypted cookie.
func (cm *SecureCookieManager) Get(req *http.Request, name string, v interface{}) (*http.Cookie, error) {
	cookie, err := req.Cookie(name)
	if err != nil {
		return nil, err
	}

	if err := cm.Encryptor.Decrypt(cookie); err != nil {
		return cookie, err
	}

	if err := cm.Encoder.Decode(v, cookie); err != nil {
		return cookie, err
	}

	return cookie, nil
}

// Deletes the Cookie, setting value to empty and expiring in the past.
func (cm *SecureCookieManager) Delete(w http.ResponseWriter, name string, opts *CookieOptions) (*http.Cookie, error) {
	if opts == nil {
		opts = &CookieOptions{}
	}

	cookie := http.Cookie{
		Name:     name,
		HttpOnly: opts.HTTPOnly,
		Domain:   opts.Domain,
		Secure:   opts.Secure,
		Path:     opts.Path,
		MaxAge:   -1,
	}

	http.SetCookie(w, &cookie)
	return &cookie, nil
}
<commit_msg>treat empty cookie as non-existing cookie<commit_after>package cookies

import (
	"encoding/json"
	"net/http"
	"time"

	"github.com/divoxx/goRailsYourself/crypto"
)

// CookieEncryptor implements cookie encryption and signing to allow securely storing sensitive
// information on the user-agent.
type CookieEncryptor struct {
	messageEncryptor crypto.MessageEncryptor
}

// NewCookieEncryptor creates a new instance of CookieEncryptor. Creating this instance is expensive
// since it has to derives the keys.
func NewCookieEncryptor(secret string, iterations int) *CookieEncryptor {
	var (
		kg      = crypto.KeyGenerator{Secret: secret, Iterations: iterations}
		key     = kg.CacheGenerate([]byte("encrypted cookie"), 32)
		signKey = kg.CacheGenerate([]byte("signed encrypted cookie"), 64)
	)

	ce := &CookieEncryptor{
		messageEncryptor: crypto.MessageEncryptor{Key: key, SignKey: signKey, Serializer: crypto.NullMsgSerializer{}},
	}

	return ce
}

// Encrypt takes an http.Cookie instance and encrypts and sign it's value, replacing it.
func (ce *CookieEncryptor) Encrypt(cookie *http.Cookie) error {
	encValue, err := ce.messageEncryptor.EncryptAndSign(cookie.Value)
	if err != nil {
		return err
	}

	cookie.Value = encValue
	return nil
}

// Decrypt takes an encrypted http.Cookie instance and decrypts it.
func (ce *CookieEncryptor) Decrypt(cookie *http.Cookie) error {
	var value string

	if cookie.Value == "" {
		return http.ErrNoCookie
	}

	err := ce.messageEncryptor.DecryptAndVerify(cookie.Value, &value)
	if err != nil {
		return err
	}

	cookie.Value = value
	return nil
}

// CookieEncoder encodes/decodes a specific data structure into a cookie's content.
type CookieEncoder interface {
	Encode(v interface{}, c *http.Cookie) error
	Decode(v interface{}, c *http.Cookie) error
}

// JSONCookieEncoder encodes/decodes cookies using encoding/json
type JSONCookieEncoder struct{}

func (e JSONCookieEncoder) Encode(v interface{}, c *http.Cookie) error {
	b, err := json.Marshal(v)
	if err != nil {
		return err
	}

	c.Value = string(b)
	return nil
}

func (e JSONCookieEncoder) Decode(v interface{}, c *http.Cookie) error {
	if err := json.Unmarshal([]byte(c.Value), v); err != nil {
		return err
	}

	return nil
}

type SecureCookieManager struct {
	Encryptor *CookieEncryptor
	Encoder   CookieEncoder
}

type CookieOptions struct {
	Domain   string
	Path     string
	HTTPOnly bool
	Secure   bool
	MaxAge   time.Duration
}

// Set a cookie with the data set to the encrypted version of the serialization of v.
// Returns the http.Cookie generated.
func (cm *SecureCookieManager) Set(w http.ResponseWriter, name string, opts *CookieOptions, v interface{}) (*http.Cookie, error) {
	var err error

	if opts == nil {
		opts = &CookieOptions{}
	}

	cookie := http.Cookie{
		Name:     name,
		Domain:   opts.Domain,
		Path:     opts.Path,
		HttpOnly: opts.HTTPOnly,
		Secure:   opts.Secure,
		MaxAge:   int(opts.MaxAge.Seconds()),
	}

	if err := cm.Encoder.Encode(v, &cookie); err != nil {
		return &cookie, err
	}

	if err = cm.Encryptor.Encrypt(&cookie); err != nil {
		return &cookie, err
	}

	http.SetCookie(w, &cookie)
	return &cookie, nil
}

// Get gets the Cookie, decrypted it and deserialized it into v.
// Returns the decrypted cookie.
func (cm *SecureCookieManager) Get(req *http.Request, name string, v interface{}) (*http.Cookie, error) {
	cookie, err := req.Cookie(name)
	if err != nil {
		return nil, err
	}

	if err := cm.Encryptor.Decrypt(cookie); err != nil {
		return cookie, err
	}

	if err := cm.Encoder.Decode(v, cookie); err != nil {
		return cookie, err
	}

	return cookie, nil
}

// Deletes the Cookie, setting value to empty and expiring in the past.
func (cm *SecureCookieManager) Delete(w http.ResponseWriter, name string, opts *CookieOptions) (*http.Cookie, error) {
	if opts == nil {
		opts = &CookieOptions{}
	}

	cookie := http.Cookie{
		Name:     name,
		HttpOnly: opts.HTTPOnly,
		Domain:   opts.Domain,
		Secure:   opts.Secure,
		Path:     opts.Path,
		MaxAge:   -1,
	}

	http.SetCookie(w, &cookie)
	return &cookie, nil
}
<|endoftext|>


<commit_before>package folders

import (
	"os"
	"path"
)

var FolderStucture = []string{
	"workers",
	"workers/",
	"models",
	"app",
}

func EnsureFolders(root string, folderStucture []string) error {
	for _, folder := range folderStucture {
		path := path.Join(root, folder)
		exists, err := exists(path)
		if err != nil {
			return err
		}

		if exists {
			continue
		}

		if err := os.Mkdir(path, os.ModePerm); err != nil {
			return err
		}
	}

	return nil
}

// check if folder or file exists
func exists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}

	if os.IsNotExist(err) {
		return false, nil
	}

	return false, err
}
<commit_msg>Generators: make sure tests folder exists<commit_after>package folders

import (
	"os"
	"path"
)

var FolderStucture = []string{
	"workers",
	"workers/",
	"models",
	"tests",
	"app",
}

func EnsureFolders(root string, folderStucture []string) error {
	for _, folder := range folderStucture {
		path := path.Join(root, folder)
		exists, err := exists(path)
		if err != nil {
			return err
		}

		if exists {
			continue
		}

		if err := os.Mkdir(path, os.ModePerm); err != nil {
			return err
		}
	}

	return nil
}

// check if folder or file exists
func exists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}

	if os.IsNotExist(err) {
		return false, nil
	}

	return false, err
}
<|endoftext|>


<commit_before>//
// Copyright 2021, Sander van Harmelen
//
// 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 gitlab

import (
	"fmt"
	"net/http"
	"time"
)

// ReleasesService handles communication with the releases methods
// of the GitLab API.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/releases/index.html
type ReleasesService struct {
	client *Client
}

// Release represents a project release.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/releases/index.html#list-releases
type Release struct {
	TagName         string     `json:"tag_name"`
	Name            string     `json:"name"`
	Description     string     `json:"description,omitempty"`
	DescriptionHTML string     `json:"description_html,omitempty"`
	CreatedAt       *time.Time `json:"created_at,omitempty"`
	Author          struct {
		ID        int    `json:"id"`
		Name      string `json:"name"`
		Username  string `json:"username"`
		State     string `json:"state"`
		AvatarURL string `json:"avatar_url"`
		WebURL    string `json:"web_url"`
	} `json:"author"`
	Commit Commit `json:"commit"`
	Assets struct {
		Count   int `json:"count"`
		Sources []struct {
			Format string `json:"format"`
			URL    string `json:"url"`
		} `json:"sources"`
		Links []*ReleaseLink `json:"links"`
	} `json:"assets"`
}

// ListReleasesOptions represents ListReleases() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/releases/index.html#list-releases
type ListReleasesOptions ListOptions

// ListReleases gets a pagenated of releases accessible by the authenticated user.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/releases/index.html#list-releases
func (s *ReleasesService) ListReleases(pid interface{}, opt *ListReleasesOptions, options ...RequestOptionFunc) ([]*Release, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/releases", pathEscape(project))

	req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	var rs []*Release
	resp, err := s.client.Do(req, &rs)
	if err != nil {
		return nil, resp, err
	}

	return rs, resp, err
}

// GetRelease returns a single release, identified by a tag name.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/releases/index.html#get-a-release-by-a-tag-name
func (s *ReleasesService) GetRelease(pid interface{}, tagName string, options ...RequestOptionFunc) (*Release, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/releases/%s", pathEscape(project), tagName)

	req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	r := new(Release)
	resp, err := s.client.Do(req, r)
	if err != nil {
		return nil, resp, err
	}

	return r, resp, err
}

// ReleaseAssets represents release assets in CreateRelease() options
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/releases/index.html#create-a-release
type ReleaseAssets struct {
	Links []*ReleaseAssetLink `url:"links" json:"links"`
}

// ReleaseAssetLink represents release asset link in CreateRelease() options
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/releases/index.html#create-a-release
type ReleaseAssetLink struct {
	Name string `url:"name" json:"name"`
	URL  string `url:"url" json:"url"`
}

// CreateReleaseOptions represents CreateRelease() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/releases/index.html#create-a-release
type CreateReleaseOptions struct {
	Name        *string        `url:"name" json:"name"`
	TagName     *string        `url:"tag_name" json:"tag_name"`
	Description *string        `url:"description" json:"description"`
	Ref         *string        `url:"ref,omitempty" json:"ref,omitempty"`
	Milestones  []string       `url:"milestones,omitempty" json:"milestones,omitempty"`
	Assets      *ReleaseAssets `url:"assets,omitempty" json:"assets,omitempty"`
	ReleasedAt  *time.Time     `url:"released_at,omitempty" json:"released_at,omitempty"`
}

// CreateRelease creates a release.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/releases/index.html#create-a-release
func (s *ReleasesService) CreateRelease(pid interface{}, opts *CreateReleaseOptions, options ...RequestOptionFunc) (*Release, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/releases", pathEscape(project))

	req, err := s.client.NewRequest(http.MethodPost, u, opts, options)
	if err != nil {
		return nil, nil, err
	}

	r := new(Release)
	resp, err := s.client.Do(req, r)
	if err != nil {
		return nil, resp, err
	}

	return r, resp, err
}

// UpdateReleaseOptions represents UpdateRelease() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/releases/index.html#update-a-release
type UpdateReleaseOptions struct {
	Name        *string    `url:"name" json:"name"`
	Description *string    `url:"description" json:"description"`
	Milestones  []string   `url:"milestones,omitempty" json:"milestones,omitempty"`
	ReleasedAt  *time.Time `url:"released_at,omitempty" json:"released_at,omitempty"`
}

// UpdateRelease updates a release.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/releases/index.html#update-a-release
func (s *ReleasesService) UpdateRelease(pid interface{}, tagName string, opts *UpdateReleaseOptions, options ...RequestOptionFunc) (*Release, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/releases/%s", pathEscape(project), tagName)

	req, err := s.client.NewRequest(http.MethodPut, u, opts, options)
	if err != nil {
		return nil, nil, err
	}

	r := new(Release)
	resp, err := s.client.Do(req, &r)
	if err != nil {
		return nil, resp, err
	}

	return r, resp, err
}

// DeleteRelease deletes a release.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/releases/index.html#delete-a-release
func (s *ReleasesService) DeleteRelease(pid interface{}, tagName string, options ...RequestOptionFunc) (*Release, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/releases/%s", pathEscape(project), tagName)

	req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	r := new(Release)
	resp, err := s.client.Do(req, r)
	if err != nil {
		return nil, resp, err
	}

	return r, resp, err
}
<commit_msg>Add missing ReleasedAt field to Releases struct<commit_after>//
// Copyright 2021, Sander van Harmelen
//
// 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 gitlab

import (
	"fmt"
	"net/http"
	"time"
)

// ReleasesService handles communication with the releases methods
// of the GitLab API.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/releases/index.html
type ReleasesService struct {
	client *Client
}

// Release represents a project release.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/releases/index.html#list-releases
type Release struct {
	TagName         string     `json:"tag_name"`
	Name            string     `json:"name"`
	Description     string     `json:"description,omitempty"`
	DescriptionHTML string     `json:"description_html,omitempty"`
	CreatedAt       *time.Time `json:"created_at,omitempty"`
	ReleasedAt      *time.Time `json:"released_at,omitempty"`
	Author          struct {
		ID        int    `json:"id"`
		Name      string `json:"name"`
		Username  string `json:"username"`
		State     string `json:"state"`
		AvatarURL string `json:"avatar_url"`
		WebURL    string `json:"web_url"`
	} `json:"author"`
	Commit Commit `json:"commit"`
	Assets struct {
		Count   int `json:"count"`
		Sources []struct {
			Format string `json:"format"`
			URL    string `json:"url"`
		} `json:"sources"`
		Links []*ReleaseLink `json:"links"`
	} `json:"assets"`
}

// ListReleasesOptions represents ListReleases() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/releases/index.html#list-releases
type ListReleasesOptions ListOptions

// ListReleases gets a pagenated of releases accessible by the authenticated user.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/releases/index.html#list-releases
func (s *ReleasesService) ListReleases(pid interface{}, opt *ListReleasesOptions, options ...RequestOptionFunc) ([]*Release, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/releases", pathEscape(project))

	req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	var rs []*Release
	resp, err := s.client.Do(req, &rs)
	if err != nil {
		return nil, resp, err
	}

	return rs, resp, err
}

// GetRelease returns a single release, identified by a tag name.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/releases/index.html#get-a-release-by-a-tag-name
func (s *ReleasesService) GetRelease(pid interface{}, tagName string, options ...RequestOptionFunc) (*Release, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/releases/%s", pathEscape(project), tagName)

	req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	r := new(Release)
	resp, err := s.client.Do(req, r)
	if err != nil {
		return nil, resp, err
	}

	return r, resp, err
}

// ReleaseAssets represents release assets in CreateRelease() options
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/releases/index.html#create-a-release
type ReleaseAssets struct {
	Links []*ReleaseAssetLink `url:"links" json:"links"`
}

// ReleaseAssetLink represents release asset link in CreateRelease() options
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/releases/index.html#create-a-release
type ReleaseAssetLink struct {
	Name string `url:"name" json:"name"`
	URL  string `url:"url" json:"url"`
}

// CreateReleaseOptions represents CreateRelease() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/releases/index.html#create-a-release
type CreateReleaseOptions struct {
	Name        *string        `url:"name" json:"name"`
	TagName     *string        `url:"tag_name" json:"tag_name"`
	Description *string        `url:"description" json:"description"`
	Ref         *string        `url:"ref,omitempty" json:"ref,omitempty"`
	Milestones  []string       `url:"milestones,omitempty" json:"milestones,omitempty"`
	Assets      *ReleaseAssets `url:"assets,omitempty" json:"assets,omitempty"`
	ReleasedAt  *time.Time     `url:"released_at,omitempty" json:"released_at,omitempty"`
}

// CreateRelease creates a release.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/releases/index.html#create-a-release
func (s *ReleasesService) CreateRelease(pid interface{}, opts *CreateReleaseOptions, options ...RequestOptionFunc) (*Release, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/releases", pathEscape(project))

	req, err := s.client.NewRequest(http.MethodPost, u, opts, options)
	if err != nil {
		return nil, nil, err
	}

	r := new(Release)
	resp, err := s.client.Do(req, r)
	if err != nil {
		return nil, resp, err
	}

	return r, resp, err
}

// UpdateReleaseOptions represents UpdateRelease() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/releases/index.html#update-a-release
type UpdateReleaseOptions struct {
	Name        *string    `url:"name" json:"name"`
	Description *string    `url:"description" json:"description"`
	Milestones  []string   `url:"milestones,omitempty" json:"milestones,omitempty"`
	ReleasedAt  *time.Time `url:"released_at,omitempty" json:"released_at,omitempty"`
}

// UpdateRelease updates a release.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/releases/index.html#update-a-release
func (s *ReleasesService) UpdateRelease(pid interface{}, tagName string, opts *UpdateReleaseOptions, options ...RequestOptionFunc) (*Release, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/releases/%s", pathEscape(project), tagName)

	req, err := s.client.NewRequest(http.MethodPut, u, opts, options)
	if err != nil {
		return nil, nil, err
	}

	r := new(Release)
	resp, err := s.client.Do(req, &r)
	if err != nil {
		return nil, resp, err
	}

	return r, resp, err
}

// DeleteRelease deletes a release.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/releases/index.html#delete-a-release
func (s *ReleasesService) DeleteRelease(pid interface{}, tagName string, options ...RequestOptionFunc) (*Release, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/releases/%s", pathEscape(project), tagName)

	req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	r := new(Release)
	resp, err := s.client.Do(req, r)
	if err != nil {
		return nil, resp, err
	}

	return r, resp, err
}
<|endoftext|>


<commit_before>package graphs

import (
	"fmt"
	"sort"
)

// A Vertex can be just anything.
type Vertex interface{}

// An Edge connects two vertices with a cost.
type Edge struct {
	Start Vertex
	End   Vertex
	Cost  float64
}

// A Halfedge is an edge where just the end vertex is
// stored. The start vertex is inferred from the context.
type Halfedge struct {
	End  Vertex
	Cost float64
}

// A Graph is defined by its vertices and edges stored as
// an adjacency set.
type Graph struct {
	Adjacency map[Vertex]*Set
	Vertices  *Set
	Directed  bool
}

// NewGraph creates a new empty graph.
func NewGraph() *Graph {
	return &Graph{
		Adjacency: map[Vertex]*Set{},
		Vertices:  NewSet(),
		Directed:  false,
	}
}

// NewDigraph creates a new empty directed graph.
func NewDigraph() *Graph {
	graph := NewGraph()
	graph.Directed = true
	return graph
}

// AddEdge adds an edge to the graph. The edge connects
// vertex v1 and vertex v2 with cost c.
func (g *Graph) AddEdge(v1, v2 Vertex, c float64) {
	g.Vertices.Add(v1)
	g.Vertices.Add(v2)

	if _, exists := g.Adjacency[v1]; !exists {
		g.Adjacency[v1] = NewSet()
	}

	g.Adjacency[v1].Add(Halfedge{
		End:  v2,
		Cost: c,
	})

	if !g.Directed {
		if _, exists := g.Adjacency[v2]; !exists {
			g.Adjacency[v2] = NewSet()
		}

		g.Adjacency[v2].Add(Halfedge{
			End:  v1,
			Cost: c,
		})
	}
}

// Dump prints all edges with their cost to stdout.
func (g *Graph) Dump() {
	for v, s := range g.Adjacency {
		for vv, _ := range *s {
			he := vv.(Halfedge)
			fmt.Printf("(%v,%v,%f)\n", v, he.End, he.Cost)
		}
	}
}

// NVertices returns the number of vertices.
func (g *Graph) NVertices() int {
	return g.Vertices.Len()
}

// NEdges returns the number of edges.
func (g *Graph) NEdges() int {
	n := 0

	for _, v := range g.Adjacency {
		n += v.Len()
	}

	// Don’t count a-b and b-a edges for undirected graphs
	// as two separate edges.
	if !g.Directed {
		n /= 2
	}

	return n
}

// Equals returns whether the graph is equal to the given graph.
// Two graphs are equal of their adjacency is equal.
func (g *Graph) Equals(g2 *Graph) bool {
	// Two graphs with differnet vertices aren’t equal.
	if !g.Vertices.Equals(g2.Vertices) {
		return false
	}

	// Some for number of edges.
	if g.NEdges() != g2.NEdges() {
		return false
	}

	// Check if the adjacency for each vertex is equal
	// for both graphs.
	a1 := g.Adjacency
	a2 := g2.Adjacency

	for k, v := range a1 {
		if !v.Equals(a2[k]) {
			return false
		}
	}

	return true
}

// AdjacentVertices returns a set containing all
// adjacent vertices for a given vertex.
func (g *Graph) AdjacentVertices(v Vertex) *Set {
	vertices := NewSet()
	if _, exists := g.Adjacency[v]; exists {
		for vv, _ := range *g.Adjacency[v] {
			vertices.Add(vv.(Halfedge).End)
		}
	}
	return vertices
}

// SortedEdges is an array of edges that can be sorted
// by their cost.
type SortedEdges []Edge

func (se SortedEdges) Len() int {
	return len(se)
}

func (se SortedEdges) Less(i, j int) bool {
	return se[i].Cost < se[j].Cost
}

func (se SortedEdges) Swap(i, j int) {
	se[i], se[j] = se[j], se[i]
}

// SortedEdges returns an array of edges sorted by their cost.
func (g *Graph) SortedEdges() SortedEdges {
	set := NewSet()

	for v, s := range g.Adjacency {
		for vv, _ := range *s {
			he := vv.(Halfedge)
			set.Add(Edge{
				Start: v,
				End:   he.End,
				Cost:  he.Cost,
			})
		}
	}

	edges := make(SortedEdges, set.Len())
	for v, _ := range *set {
		edges = append(edges, v.(Edge))
	}

	sort.Sort(&edges)
	return edges
}
<commit_msg>Add AddVertex to graph<commit_after>package graphs

import (
	"fmt"
	"sort"
)

// A Vertex can be just anything.
type Vertex interface{}

// An Edge connects two vertices with a cost.
type Edge struct {
	Start Vertex
	End   Vertex
	Cost  float64
}

// A Halfedge is an edge where just the end vertex is
// stored. The start vertex is inferred from the context.
type Halfedge struct {
	End  Vertex
	Cost float64
}

// A Graph is defined by its vertices and edges stored as
// an adjacency set.
type Graph struct {
	Adjacency map[Vertex]*Set
	Vertices  *Set
	Directed  bool
}

// NewGraph creates a new empty graph.
func NewGraph() *Graph {
	return &Graph{
		Adjacency: map[Vertex]*Set{},
		Vertices:  NewSet(),
		Directed:  false,
	}
}

// NewDigraph creates a new empty directed graph.
func NewDigraph() *Graph {
	graph := NewGraph()
	graph.Directed = true
	return graph
}

// AddVertex adds the given vertex to the graph.
func (g *Graph) AddVertex(v Vertex) {
	g.Vertices.Add(v)
}

// AddEdge adds an edge to the graph. The edge connects
// vertex v1 and vertex v2 with cost c.
func (g *Graph) AddEdge(v1, v2 Vertex, c float64) {
	g.Vertices.Add(v1)
	g.Vertices.Add(v2)

	if _, exists := g.Adjacency[v1]; !exists {
		g.Adjacency[v1] = NewSet()
	}

	g.Adjacency[v1].Add(Halfedge{
		End:  v2,
		Cost: c,
	})

	if !g.Directed {
		if _, exists := g.Adjacency[v2]; !exists {
			g.Adjacency[v2] = NewSet()
		}

		g.Adjacency[v2].Add(Halfedge{
			End:  v1,
			Cost: c,
		})
	}
}

// Dump prints all edges with their cost to stdout.
func (g *Graph) Dump() {
	for v, s := range g.Adjacency {
		for vv, _ := range *s {
			he := vv.(Halfedge)
			fmt.Printf("(%v,%v,%f)\n", v, he.End, he.Cost)
		}
	}
}

// NVertices returns the number of vertices.
func (g *Graph) NVertices() int {
	return g.Vertices.Len()
}

// NEdges returns the number of edges.
func (g *Graph) NEdges() int {
	n := 0

	for _, v := range g.Adjacency {
		n += v.Len()
	}

	// Don’t count a-b and b-a edges for undirected graphs
	// as two separate edges.
	if !g.Directed {
		n /= 2
	}

	return n
}

// Equals returns whether the graph is equal to the given graph.
// Two graphs are equal of their adjacency is equal.
func (g *Graph) Equals(g2 *Graph) bool {
	// Two graphs with differnet vertices aren’t equal.
	if !g.Vertices.Equals(g2.Vertices) {
		return false
	}

	// Some for number of edges.
	if g.NEdges() != g2.NEdges() {
		return false
	}

	// Check if the adjacency for each vertex is equal
	// for both graphs.
	a1 := g.Adjacency
	a2 := g2.Adjacency

	for k, v := range a1 {
		if !v.Equals(a2[k]) {
			return false
		}
	}

	return true
}

// AdjacentVertices returns a set containing all
// adjacent vertices for a given vertex.
func (g *Graph) AdjacentVertices(v Vertex) *Set {
	vertices := NewSet()
	if _, exists := g.Adjacency[v]; exists {
		for vv, _ := range *g.Adjacency[v] {
			vertices.Add(vv.(Halfedge).End)
		}
	}
	return vertices
}

// SortedEdges is an array of edges that can be sorted
// by their cost.
type SortedEdges []Edge

func (se SortedEdges) Len() int {
	return len(se)
}

func (se SortedEdges) Less(i, j int) bool {
	return se[i].Cost < se[j].Cost
}

func (se SortedEdges) Swap(i, j int) {
	se[i], se[j] = se[j], se[i]
}

// SortedEdges returns an array of edges sorted by their cost.
func (g *Graph) SortedEdges() SortedEdges {
	set := NewSet()

	for v, s := range g.Adjacency {
		for vv, _ := range *s {
			he := vv.(Halfedge)
			set.Add(Edge{
				Start: v,
				End:   he.End,
				Cost:  he.Cost,
			})
		}
	}

	edges := make(SortedEdges, set.Len())
	for v, _ := range *set {
		edges = append(edges, v.(Edge))
	}

	sort.Sort(&edges)
	return edges
}
<|endoftext|>