<commit_before>package command

import (
	"bufio"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"os"
	"os/signal"
	"strings"
	"sync"

	"github.com/docker/libcompose/docker"
	"github.com/docker/libcompose/project"
	"github.com/samalba/dockerclient"
	"github.com/tcnksm/boot2kubernetes/config"
)

type DestroyCommand struct {
	Meta
}

func (c *DestroyCommand) Run(args []string) int {

	var insecure bool
	flags := flag.NewFlagSet("destroy", flag.ContinueOnError)
	flags.BoolVar(&insecure, "insecure", false, "")
	flags.Usage = func() { c.Ui.Error(c.Help()) }

	errR, errW := io.Pipe()
	errScanner := bufio.NewScanner(errR)
	go func() {
		for errScanner.Scan() {
			c.Ui.Error(errScanner.Text())
		}
	}()

	flags.SetOutput(errW)

	if err := flags.Parse(args); err != nil {
		return 1
	}

	compose, err := config.Asset("k8s.yml")
	if err != nil {
		c.Ui.Error(fmt.Sprintf(
			"Failed to read k8s.yml: %s", err))
		return 1
	}

	// Setup new docker-compose project
	context := &docker.Context{
		Context: project.Context{
			Log:          false,
			ComposeBytes: compose,
			ProjectName:  "boot2k8s",
		},
		Tls: !insecure,
	}

	project, err := docker.NewProject(context)
	if err != nil {
		c.Ui.Error(fmt.Sprintf(
			"Failed to setup project: %s", err))
		return 1
	}

	if err := project.Delete(); err != nil {
		c.Ui.Error(fmt.Sprintf(
			"Failed to destroy project: %s", err))
		return 1
	}

	if err := context.CreateClient(); err != nil {
		c.Ui.Error("Failed to create client")
		return 1
	}

	filterLocalMaster := map[string][]string{
		"label": []string{"io.kubernetes.pod.name=default/k8s-master-127.0.0.1"},
	}

	// Marshaling to post filter as API request
	filterLocalMasterStr, err := json.Marshal(filterLocalMaster)
	if err != nil {
		return 1
	}

	// Get Container info from deamon based on fileter
	localMasters, err := context.Client.ListContainers(true, false, (string)(filterLocalMasterStr))
	if err != nil {
		return 1
	}

	if len(localMasters) > 0 {
		c.Ui.Output("Are you sure you want to destroy below containers?")
		for _, container := range localMasters {
			c.Ui.Output(fmt.Sprintf("  %s", container.Names[0]))
		}

		if yes, err := AskYesNo(); !yes || err != nil {
			if err == nil {
				c.Ui.Info("Containers will no be destroyed, since the confirmation")
				return 0
			}
			c.Ui.Error(fmt.Sprintf(
				"Terminate to destroy: %s", err.Error()))
			return 1
		}

		resultCh, errCh := removeContainers(context.Client, localMasters, true, true)
		go func() {
			for res := range resultCh {
				c.Ui.Output(fmt.Sprintf(
					"Successfully destroy %s", res.Names[0]))
			}
		}()

		for err := range errCh {
			c.Ui.Error(fmt.Sprintf("Error: %s", err))
		}
		c.Ui.Output("")
	}

	filterUnknown := map[string][]string{
		"label": []string{"io.kubernetes.pod.name"},
	}

	// Marshaling to post filter as API request
	filterUnknownStr, err := json.Marshal(filterUnknown)
	if err != nil {
		return 1
	}

	unknownContainers, err := context.Client.ListContainers(true, false, (string)(filterUnknownStr))
	if err != nil {
		return 1
	}

	if len(unknownContainers) < 1 {
		// Correctly clean all containers
		return 0
	}

	c.Ui.Output("Do you also remove these containers? (these are created by kubernetes)")
	c.Ui.Error("==> WARNING: boot2kubernetes can not detect below containers")
	c.Ui.Error("  are created by kubernetes which up by boot2kubernetes.")
	c.Ui.Error("  Be sure below these will not be used anymore!")
	for _, container := range unknownContainers {
		c.Ui.Output(fmt.Sprintf("  %s", container.Names[0]))
	}

	if yes, err := AskYesNo(); !yes || err != nil {
		if err == nil {
			c.Ui.Info("Containers will no be destroyed, since the confirmation")
			return 0
		}
		c.Ui.Error(fmt.Sprintf(
			"Terminate to destroy: %s", err.Error()))
		return 1
	}

	resultCh, errCh := removeContainers(context.Client, unknownContainers, true, true)
	go func() {
		for res := range resultCh {
			c.Ui.Output(fmt.Sprintf(
				"Successfully removed %s", res.Names[0]))
		}
	}()

	for err := range errCh {
		c.Ui.Error(fmt.Sprintf("Error: %s", err))
	}

	return 0
}

func (c *DestroyCommand) Synopsis() string {
	return "Destroy kubernetes cluster"
}

func (c *DestroyCommand) Help() string {
	helpText := `Destroy kubernetes cluseter.

Options:

  -insecure    Allow insecure non-TLS connection to docker client.
`
	return strings.TrimSpace(helpText)
}

// removeContainers removes all containers parallelly.
// It retuns error channel and if something wrong, error is sent there.
func removeContainers(client dockerclient.Client, containers []dockerclient.Container, force, delVolume bool) (chan dockerclient.Container, chan error) {

	var wg sync.WaitGroup
	resultCh, errCh := make(chan dockerclient.Container), make(chan error)
	for _, container := range containers {
		wg.Add(1)
		go func(c dockerclient.Container) {
			defer wg.Done()
			if err := client.RemoveContainer(c.Id, force, delVolume); err != nil {
				errCh <- fmt.Errorf(
					"failed to remove %s (%s): %s", c.Names[0], c.Id, err)
				return
			}
			resultCh <- c
		}(container)
	}

	go func() {
		// Wait until all remove task and close error channnel then
		wg.Wait()
		close(resultCh)
		close(errCh)
	}()

	return resultCh, errCh
}

func AskYesNo() (bool, error) {
	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, os.Interrupt)
	defer signal.Stop(sigCh)

	ansCh := make(chan bool, 1)
	go func() {
		for {
			fmt.Fprintf(os.Stderr, "Your choice? (Y/n) [default: n]: ")

			reader := bufio.NewReader(os.Stdin)
			line, _ := reader.ReadString('\n')
			line = strings.TrimRight(line, "\n")

			// Use Default value
			if line == "Y" {
				ansCh <- true
				break
			}

			if line == "n" || line == "" {
				ansCh <- false
				break
			}
		}
	}()

	select {
	case <-sigCh:
		return false, fmt.Errorf("interrupted")
	case yes := <-ansCh:
		return yes, nil
	}
}
<commit_msg>Refactoring<commit_after>package command

import (
	"bufio"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"os"
	"os/signal"
	"strings"
	"sync"

	"github.com/docker/libcompose/docker"
	"github.com/docker/libcompose/project"
	"github.com/samalba/dockerclient"
	"github.com/tcnksm/boot2kubernetes/config"
)

var FilterLocalMaster = map[string][]string{
	"label": []string{"io.kubernetes.pod.name=default/k8s-master-127.0.0.1"},
}

var FilterK8SRelated = map[string][]string{
	"label": []string{"io.kubernetes.pod.name"},
}

type DestroyCommand struct {
	Meta
}

func (c *DestroyCommand) Run(args []string) int {

	var insecure bool
	flags := flag.NewFlagSet("destroy", flag.ContinueOnError)
	flags.BoolVar(&insecure, "insecure", false, "")
	flags.Usage = func() { c.Ui.Error(c.Help()) }

	errR, errW := io.Pipe()
	errScanner := bufio.NewScanner(errR)
	go func() {
		for errScanner.Scan() {
			c.Ui.Error(errScanner.Text())
		}
	}()

	flags.SetOutput(errW)

	if err := flags.Parse(args); err != nil {
		return 1
	}

	compose, err := config.Asset("k8s.yml")
	if err != nil {
		c.Ui.Error(fmt.Sprintf(
			"Failed to read k8s.yml: %s", err))
		return 1
	}

	// Setup new docker-compose project
	context := &docker.Context{
		Context: project.Context{
			Log:          false,
			ComposeBytes: compose,
			ProjectName:  "boot2k8s",
		},
		Tls: !insecure,
	}

	project, err := docker.NewProject(context)
	if err != nil {
		c.Ui.Error(fmt.Sprintf(
			"Failed to setup project: %s", err))
		return 1
	}

	if err := project.Delete(); err != nil {
		c.Ui.Error(fmt.Sprintf(
			"Failed to destroy project: %s", err))
		return 1
	}

	if err := context.CreateClient(); err != nil {
		c.Ui.Error("Failed to create client")
		return 1
	}

	// Marshaling to post filter as API request
	filterLocalMasterStr, err := json.Marshal(FilterLocalMaster)
	if err != nil {
		return 1
	}

	// Get Container info from deamon based on fileter
	localMasters, err := context.Client.ListContainers(true, false, (string)(filterLocalMasterStr))
	if err != nil {
		return 1
	}

	if len(localMasters) > 0 {
		c.Ui.Output("Are you sure you want to destroy below containers?")
		for _, container := range localMasters {
			c.Ui.Output(fmt.Sprintf("  %s", container.Names[0]))
		}

		if yes, err := AskYesNo(); !yes || err != nil {
			if err == nil {
				c.Ui.Info("Containers will no be destroyed, since the confirmation")
				return 0
			}
			c.Ui.Error(fmt.Sprintf(
				"Terminate to destroy: %s", err.Error()))
			return 1
		}

		resultCh, errCh := removeContainers(context.Client, localMasters, true, true)
		go func() {
			for res := range resultCh {
				c.Ui.Output(fmt.Sprintf(
					"Successfully destroy %s", res.Names[0]))
			}
		}()

		for err := range errCh {
			c.Ui.Error(fmt.Sprintf("Error: %s", err))
		}
		c.Ui.Output("")
	}

	// Marshaling to post filter as API request
	filterK8SRelatedStr, err := json.Marshal(FilterK8SRelated)
	if err != nil {
		return 1
	}

	relatedContainers, err := context.Client.ListContainers(true, false, (string)(filterK8SRelatedStr))
	if err != nil {
		return 1
	}

	if len(relatedContainers) < 1 {
		// Correctly clean all containers
		return 0
	}

	c.Ui.Output("Do you also remove these containers? (these are created by kubernetes)")
	c.Ui.Error("==> WARNING: boot2kubernetes can not detect below containers")
	c.Ui.Error("  are created by kubernetes which up by boot2kubernetes.")
	c.Ui.Error("  Be sure below these will not be used anymore!")
	for _, container := range relatedContainers {
		c.Ui.Output(fmt.Sprintf("  %s", container.Names[0]))
	}

	if yes, err := AskYesNo(); !yes || err != nil {
		if err == nil {
			c.Ui.Info("Containers will no be destroyed, since the confirmation")
			return 0
		}
		c.Ui.Error(fmt.Sprintf(
			"Terminate to destroy: %s", err.Error()))
		return 1
	}

	resultCh, errCh := removeContainers(context.Client, relatedContainers, true, true)
	go func() {
		for res := range resultCh {
			c.Ui.Output(fmt.Sprintf(
				"Successfully removed %s", res.Names[0]))
		}
	}()

	for err := range errCh {
		c.Ui.Error(fmt.Sprintf("Error: %s", err))
	}

	return 0
}

func (c *DestroyCommand) Synopsis() string {
	return "Destroy kubernetes cluster"
}

func (c *DestroyCommand) Help() string {
	helpText := `Destroy kubernetes cluseter.

Options:

  -insecure    Allow insecure non-TLS connection to docker client.
`
	return strings.TrimSpace(helpText)
}

// removeContainers removes all containers parallelly.
// It retuns error channel and if something wrong, error is sent there.
func removeContainers(client dockerclient.Client, containers []dockerclient.Container, force, delVolume bool) (chan dockerclient.Container, chan error) {

	var wg sync.WaitGroup
	resultCh, errCh := make(chan dockerclient.Container), make(chan error)
	for _, container := range containers {
		wg.Add(1)
		go func(c dockerclient.Container) {
			defer wg.Done()
			if err := client.RemoveContainer(c.Id, force, delVolume); err != nil {
				errCh <- fmt.Errorf(
					"failed to remove %s (%s): %s", c.Names[0], c.Id, err)
				return
			}
			resultCh <- c
		}(container)
	}

	go func() {
		// Wait until all remove task and close error channnel then
		wg.Wait()
		close(resultCh)
		close(errCh)
	}()

	return resultCh, errCh
}

func AskYesNo() (bool, error) {
	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, os.Interrupt)
	defer signal.Stop(sigCh)

	ansCh := make(chan bool, 1)
	go func() {
		for {
			fmt.Fprintf(os.Stderr, "Your choice? (Y/n) [default: n]: ")

			reader := bufio.NewReader(os.Stdin)
			line, _ := reader.ReadString('\n')
			line = strings.TrimRight(line, "\n")

			// Use Default value
			if line == "Y" {
				ansCh <- true
				break
			}

			if line == "n" || line == "" {
				ansCh <- false
				break
			}
		}
	}()

	select {
	case <-sigCh:
		return false, fmt.Errorf("interrupted")
	case yes := <-ansCh:
		return yes, nil
	}
}
<|endoftext|>


<commit_before>package commands

import (
	"flag"
	"fmt"
	"github.com/jingweno/gh/cmd"
	"github.com/jingweno/gh/git"
	shellquote "github.com/kballard/go-shellquote"
	"os/exec"
	"syscall"
)

type ExecError struct {
	Err      error
	ExitCode int
}

func (execError *ExecError) Error() string {
	return execError.Err.Error()
}

func newExecError(err error) ExecError {
	exitCode := 0
	if err != nil {
		exitCode = 1
		if exitError, ok := err.(*exec.ExitError); ok {
			if status, ok := exitError.Sys().(syscall.WaitStatus); ok {
				exitCode = status.ExitStatus()
			}
		}
	}

	return ExecError{Err: err, ExitCode: exitCode}
}

type Runner struct {
	Args []string
}

func (r *Runner) Execute() ExecError {
	args := NewArgs(r.Args)
	if args.Command == "" {
		printUsage()
		return newExecError(nil)
	}

	expandAlias(args)
	slurpGlobalFlags(args)

	for _, cmd := range All() {
		if cmd.Name() == args.Command && cmd.Runnable() {
			if !cmd.GitExtension {
				cmd.Flag.Usage = func() {
					cmd.PrintUsage()
				}
				if err := cmd.Flag.Parse(args.Params); err != nil {
					if err == flag.ErrHelp {
						return newExecError(nil)
					} else {
						return newExecError(err)
					}
				}

				args.Params = cmd.Flag.Args()
			}

			cmd.Run(cmd, args)

			cmds := args.Commands()
			var err error
			if args.Noop {
				printCommands(cmds)
			} else {
				err = executeCommands(cmds)
			}

			return newExecError(err)
		}
	}

	err := git.Spawn(args.Command, args.Params...)
	return newExecError(err)
}

func slurpGlobalFlags(args *Args) {
	for i, p := range args.Params {
		if p == "--noop" {
			args.Noop = true
			args.RemoveParam(i)
		}
	}
}

func printCommands(cmds []*cmd.Cmd) {
	for _, c := range cmds {
		fmt.Println(c)
	}
}

func executeCommands(cmds []*cmd.Cmd) error {
	for _, c := range cmds {
		err := c.Exec()
		if err != nil {
			return err
		}
	}

	return nil
}

func expandAlias(args *Args) {
	cmd := args.Command
	expandedCmd, err := git.Config(fmt.Sprintf("alias.%s", cmd))
	if err == nil && expandedCmd != "" {
		words, err := shellquote.Split(expandedCmd)
		if err != nil {
			args.Command = words[0]
			args.PrependParams(words[1:]...)
		}
	}
}
<commit_msg>Remove unnecessary rename of package<commit_after>package commands

import (
	"flag"
	"fmt"
	"github.com/jingweno/gh/cmd"
	"github.com/jingweno/gh/git"
	"github.com/kballard/go-shellquote"
	"os/exec"
	"syscall"
)

type ExecError struct {
	Err      error
	ExitCode int
}

func (execError *ExecError) Error() string {
	return execError.Err.Error()
}

func newExecError(err error) ExecError {
	exitCode := 0
	if err != nil {
		exitCode = 1
		if exitError, ok := err.(*exec.ExitError); ok {
			if status, ok := exitError.Sys().(syscall.WaitStatus); ok {
				exitCode = status.ExitStatus()
			}
		}
	}

	return ExecError{Err: err, ExitCode: exitCode}
}

type Runner struct {
	Args []string
}

func (r *Runner) Execute() ExecError {
	args := NewArgs(r.Args)
	if args.Command == "" {
		printUsage()
		return newExecError(nil)
	}

	expandAlias(args)
	slurpGlobalFlags(args)

	for _, cmd := range All() {
		if cmd.Name() == args.Command && cmd.Runnable() {
			if !cmd.GitExtension {
				cmd.Flag.Usage = func() {
					cmd.PrintUsage()
				}
				if err := cmd.Flag.Parse(args.Params); err != nil {
					if err == flag.ErrHelp {
						return newExecError(nil)
					} else {
						return newExecError(err)
					}
				}

				args.Params = cmd.Flag.Args()
			}

			cmd.Run(cmd, args)

			cmds := args.Commands()
			var err error
			if args.Noop {
				printCommands(cmds)
			} else {
				err = executeCommands(cmds)
			}

			return newExecError(err)
		}
	}

	err := git.Spawn(args.Command, args.Params...)
	return newExecError(err)
}

func slurpGlobalFlags(args *Args) {
	for i, p := range args.Params {
		if p == "--noop" {
			args.Noop = true
			args.RemoveParam(i)
		}
	}
}

func printCommands(cmds []*cmd.Cmd) {
	for _, c := range cmds {
		fmt.Println(c)
	}
}

func executeCommands(cmds []*cmd.Cmd) error {
	for _, c := range cmds {
		err := c.Exec()
		if err != nil {
			return err
		}
	}

	return nil
}

func expandAlias(args *Args) {
	cmd := args.Command
	expandedCmd, err := git.Config(fmt.Sprintf("alias.%s", cmd))
	if err == nil && expandedCmd != "" {
		words, err := shellquote.Split(expandedCmd)
		if err != nil {
			args.Command = words[0]
			args.PrependParams(words[1:]...)
		}
	}
}
<|endoftext|>


<commit_before>package commands

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/zetamatta/go-mbcs"

	"../dos"
)

func cmd_source(cmd *exec.Cmd) (int, error) {
	args := cmd.Args
	verbose := false
	if len(args) >= 2 && args[1] == "-v" {
		verbose = true
		args = args[1:]
	}
	if len(cmd.Args) < 2 {
		return 255, nil
	}
	tempDir := os.TempDir()
	pid := os.Getpid()
	batchPath := filepath.Join(tempDir, fmt.Sprintf("nyagos-%d.cmd", pid))
	envTxtPath := filepath.Join(tempDir, fmt.Sprintf("nyagos-%d.tmp", pid))
	pwdTxtPath := filepath.Join(tempDir, fmt.Sprintf("nyagos_%d.tmp", pid))

	params := []string{
		os.Getenv("COMSPEC"),
		"/C",
		batchPath,
	}
	batchFd, batchFd_err := os.Create(batchPath)
	if batchFd_err != nil {
		return -1, batchFd_err
	}
	var batchWriter io.Writer
	if verbose {
		batchWriter = io.MultiWriter(batchFd, cmd.Stdout)
	} else {
		batchWriter = batchFd
	}
	fmt.Fprint(batchWriter, "@call")
	for _, v := range args[1:] {
		if strings.ContainsRune(v, ' ') {
			fmt.Fprintf(batchWriter, " \"%s\"", v)
		} else {
			fmt.Fprintf(batchWriter, " %s", v)
		}
	}
	fmt.Fprintf(batchWriter, "\n@set \"ERRORLEVEL_=%%ERRORLEVEL%%\"\n")
	fmt.Fprintf(batchWriter, "@set > \"%s\"\n", envTxtPath)
	fmt.Fprintf(batchWriter, "@cd > \"%s\"\n", pwdTxtPath)
	fmt.Fprintf(batchWriter, "@exit /b \"%%ERRORLEVEL_%%\"\n")
	batchFd.Close()
	defer os.Remove(batchPath)

	cmd2 := exec.Cmd{Path: params[0], Args: params}
	if err := cmd2.Run(); err != nil {
		return 1, err
	}
	errorlevel, errorlevelOk := dos.GetErrorLevel(&cmd2)
	if !errorlevelOk {
		errorlevel = 255
	}
	defer os.Remove(envTxtPath)
	defer os.Remove(pwdTxtPath)

	fp, err := os.Open(envTxtPath)
	if err != nil {
		return 1, err
	}
	defer fp.Close()

	br := bufio.NewReader(fp)
	for {
		lineB, readErr := br.ReadBytes(byte('\n'))
		if readErr != nil {
			if readErr != io.EOF {
				fmt.Fprintf(cmd.Stderr, "%s: %s (environment-readline error)\n", envTxtPath, readErr.Error())
			}
			break
		}
		line, atouErr := mbcs.AtoU(lineB)
		if atouErr != nil {
			fmt.Fprintf(cmd.Stderr, "%s: %s(environment-ansi-to-unicode error)\n", envTxtPath, atouErr.Error())
			continue
		}
		line = strings.TrimSpace(line)
		eqlPos := strings.Index(line, "=")
		if eqlPos > 0 {
			left := line[:eqlPos]
			right := line[eqlPos+1:]
			if left != "ERRORLEVEL_" {
				if verbose {
					fmt.Fprintf(cmd.Stdout, "%s=%s\n", left, right)
				}
				os.Setenv(left, right)
			}
		}
	}

	fp2, err2 := os.Open(pwdTxtPath)
	if err2 != nil {
		return 1, err2
	}
	defer fp2.Close()
	br2 := bufio.NewReader(fp2)
	lineB, lineErr := br2.ReadBytes(byte('\n'))
	if lineErr != nil {
		return 1, errors.New("source : could not get current-directory")
	}
	line, err := mbcs.AtoU(lineB)
	if err == nil {
		line = strings.TrimSpace(line)
		if verbose {
			fmt.Fprintf(cmd.Stdout, "cd \"%s\"\n", line)
		}
		os.Chdir(line)
	}
	return errorlevel, nil
}
<commit_msg>rewrite `source` command with bufio<commit_after>package commands

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/zetamatta/go-mbcs"

	"../dos"
)

func load_envfile(fname string, verbose io.Writer) error {
	fp, err := os.Open(fname)
	if err != nil {
		return err
	}
	defer fp.Close()

	scan := bufio.NewScanner(fp)
	for scan.Scan() {
		line, err := mbcs.AtoU(scan.Bytes())
		if err != nil {
			return err
		}
		line = strings.TrimSpace(line)
		eqlPos := strings.Index(line, "=")
		if eqlPos > 0 {
			left := line[:eqlPos]
			right := line[eqlPos+1:]
			if left != "ERRORLEVEL_" {
				if verbose != nil {
					fmt.Fprintf(verbose, "%s=%s\n", left, right)
				}
				os.Setenv(left, right)
			}
		}
	}
	if err := scan.Err(); err != nil {
		return err
	}
	return nil
}

func load_pwdfile(fname string, verbose io.Writer) error {
	fp, err := os.Open(fname)
	if err != nil {
		return err
	}
	defer fp.Close()
	scan := bufio.NewScanner(fp)
	if !scan.Scan() {
		return fmt.Errorf("Could not load the new current directory from %s", fname)
	}
	if err := scan.Err(); err != nil {
		return err
	}
	line, err := mbcs.AtoU(scan.Bytes())
	if err != nil {
		return err
	}
	line = strings.TrimSpace(line)
	if verbose != nil {
		fmt.Fprintf(verbose, "cd \"%s\"\n", line)
	}
	os.Chdir(line)
	return nil
}

func call_batch(batch string, args []string, env string, pwd string, verbose io.Writer) (int, error) {
	params := []string{
		os.Getenv("COMSPEC"),
		"/C",
		batch,
	}
	fd, err := os.Create(batch)
	if err != nil {
		return 1, err
	}
	var writer *bufio.Writer
	if verbose != nil {
		writer = bufio.NewWriter(io.MultiWriter(fd, verbose))
	} else {
		writer = bufio.NewWriter(fd)
	}
	fmt.Fprint(writer, "@call")
	for _, v := range args {
		if strings.ContainsRune(v, ' ') {
			fmt.Fprintf(writer, " \"%s\"", v)
		} else {
			fmt.Fprintf(writer, " %s", v)
		}
	}
	fmt.Fprintf(writer, "\n@set \"ERRORLEVEL_=%%ERRORLEVEL%%\"\n")
	fmt.Fprintf(writer, "@set > \"%s\"\n", env)
	fmt.Fprintf(writer, "@cd > \"%s\"\n", pwd)
	fmt.Fprintf(writer, "@exit /b \"%%ERRORLEVEL_%%\"\n")
	writer.Flush()
	fd.Close()

	cmd2 := exec.Cmd{Path: params[0], Args: params}
	if err := cmd2.Run(); err != nil {
		return 1, err
	}
	errorlevel, errorlevelOk := dos.GetErrorLevel(&cmd2)
	if !errorlevelOk {
		errorlevel = 255
	}
	return errorlevel, nil
}

func cmd_source(cmd *exec.Cmd) (int, error) {
	var verbose io.Writer
	args := make([]string, 0, len(cmd.Args))
	debug := false
	for _, arg1 := range cmd.Args[1:] {
		switch arg1 {
		case "-v":
			verbose = cmd.Stderr
		case "-d":
			debug = true
		default:
			args = append(args, arg1)
		}
	}
	if len(cmd.Args) <= 0 {
		return 255, nil
	}

	tempDir := os.TempDir()
	pid := os.Getpid()
	batch := filepath.Join(tempDir, fmt.Sprintf("nyagos-%d.cmd", pid))
	env := filepath.Join(tempDir, fmt.Sprintf("nyagos-%d.tmp", pid))
	pwd := filepath.Join(tempDir, fmt.Sprintf("nyagos_%d.tmp", pid))

	errorlevel, err := call_batch(batch, args, env, pwd, verbose)

	if !debug {
		defer os.Remove(env)
		defer os.Remove(pwd)
		defer os.Remove(batch)
	}

	if err != nil {
		return errorlevel, err
	}

	if err := load_envfile(env, verbose); err != nil {
		return 1, err
	}

	if err := load_pwdfile(pwd, verbose); err != nil {
		return 1, err
	}

	return errorlevel, nil
}
<|endoftext|>


<commit_before>package commands

import (
	"os"

	"github.com/Shopify/themekit/kit"
	"github.com/Shopify/themekit/theme"
)

// UploadCommand add file(s) to theme
func UploadCommand(args Args, done chan bool) {
	rawEvents, throttledEvents := prepareChannel(args)
	logs := args.ThemeClient.Process(throttledEvents, done)
	mergeEvents(args.EventLog, []chan kit.ThemeEvent{logs})
	enqueueUploadEvents(args.ThemeClient, args.Filenames, rawEvents)
}

func enqueueUploadEvents(client kit.ThemeClient, filenames []string, events chan kit.AssetEvent) {
	root, _ := os.Getwd()
	if len(filenames) == 0 {
		go fullUpload(client.LocalAssets(root), events)
		return
	}
	go func() {
		for _, filename := range filenames {
			asset, err := theme.LoadAsset(root, filename)
			if err == nil {
				events <- kit.NewUploadEvent(asset)
			}
		}
		close(events)
	}()
}

func fullUpload(localAssets []theme.Asset, events chan kit.AssetEvent) {
	assetsActions := map[string]kit.AssetEvent{}
	generateActions := func(assets []theme.Asset, assetEventFn func(asset theme.Asset) kit.SimpleAssetEvent) {
		for _, asset := range assets {
			assetsActions[asset.Key] = assetEventFn(asset)
		}
	}
	generateActions(localAssets, kit.NewUploadEvent)
	go func() {
		for _, event := range assetsActions {
			events <- event
		}
		close(events)
	}()
}
<commit_msg>simplify fullUpload, didn't need that bit of complexity<commit_after>package commands

import (
	"os"

	"github.com/Shopify/themekit/kit"
	"github.com/Shopify/themekit/theme"
)

// UploadCommand add file(s) to theme
func UploadCommand(args Args, done chan bool) {
	rawEvents, throttledEvents := prepareChannel(args)
	logs := args.ThemeClient.Process(throttledEvents, done)
	mergeEvents(args.EventLog, []chan kit.ThemeEvent{logs})
	enqueueUploadEvents(args.ThemeClient, args.Filenames, rawEvents)
}

func enqueueUploadEvents(client kit.ThemeClient, filenames []string, events chan kit.AssetEvent) {
	root, _ := os.Getwd()
	if len(filenames) == 0 {
		go fullUpload(client.LocalAssets(root), events)
		return
	}
	go func() {
		for _, filename := range filenames {
			asset, err := theme.LoadAsset(root, filename)
			if err == nil {
				events <- kit.NewUploadEvent(asset)
			}
		}
		close(events)
	}()
}

func fullUpload(localAssets []theme.Asset, events chan kit.AssetEvent) {
	assetsActions := map[string]kit.AssetEvent{}
	for _, asset := range localAssets {
		assetsActions[asset.Key] = kit.NewUploadEvent(asset)
	}
	go func() {
		for _, event := range assetsActions {
			events <- event
		}
		close(events)
	}()
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"io/ioutil"
	"strings"

	. "github.com/candid82/joker/core"
	_ "github.com/candid82/joker/std/string"
)

var template string = `// Generated by gen_data. Don't modify manually!

package core

func init() {
	{name}Data = []byte("{content}")
}
`

type FileInfo struct {
	name     string
	filename string
}

var files []FileInfo = []FileInfo{
	{
		name:     "<joker.core>",
		filename: "core.joke",
	},
	{
		name:     "<joker.time>",
		filename: "time.joke",
	},
	{
		name:     "<joker.math>",
		filename: "math.joke",
	},
	{
		name:     "<joker.repl>",
		filename: "repl.joke",
	},
	{
		name:     "<joker.walk>",
		filename: "walk.joke",
	},
	{
		name:     "<joker.template>",
		filename: "template.joke",
	},
	{
		name:     "<joker.core>",
		filename: "linter_all.joke",
	},
	{
		name:     "<joker.core>",
		filename: "linter_cljx.joke",
	},
	{
		name:     "<joker.core>",
		filename: "linter_clj.joke",
	},
	{
		name:     "<joker.core>",
		filename: "linter_cljs.joke",
	},
}

const hextable = "0123456789abcdef"

func main() {
	GLOBAL_ENV.FindNamespace(MakeSymbol("user")).ReferAll(GLOBAL_ENV.CoreNamespace)
	for _, f := range files {
		println("Generating " + f.filename)
		GLOBAL_ENV.SetCurrentNamespace(GLOBAL_ENV.CoreNamespace)
		content, err := ioutil.ReadFile("data/" + f.filename)
		if err != nil {
			panic(err)
		}
		content, err = PackReader(NewReader(bytes.NewReader(content), f.name), "")
		PanicOnErr(err)

		dst := make([]byte, len(content)*4)
		for i, v := range content {
			dst[i*4] = '\\'
			dst[i*4+1] = 'x'
			dst[i*4+2] = hextable[v>>4]
			dst[i*4+3] = hextable[v&0x0f]
		}
		name := f.filename[0 : len(f.filename)-5] // assumes .joke extension
		fileContent := strings.Replace(template, "{name}", name, 1)
		fileContent = strings.Replace(fileContent, "{content}", string(dst), 1)
		ioutil.WriteFile("a_"+name+"_data.go", []byte(fileContent), 0666)
	}
}
<commit_msg>Clarify ordering of files to be loaded<commit_after>package main

import (
	"bytes"
	"io/ioutil"
	"strings"

	. "github.com/candid82/joker/core"
	_ "github.com/candid82/joker/std/string"
)

var template string = `// Generated by gen_data. Don't modify manually!

package core

func init() {
	{name}Data = []byte("{content}")
}
`

type FileInfo struct {
	name     string
	filename string
}

/* The entries must be ordered such that a given namespace depends
/* only upon namespaces loaded above it. E.g. joker.template depends
/* on joker.walk, so is listed afterwards, not in alphabetical
/* order. */
var files []FileInfo = []FileInfo{
	{
		name:     "<joker.core>",
		filename: "core.joke",
	},
	{
		name:     "<joker.time>",
		filename: "time.joke",
	},
	{
		name:     "<joker.math>",
		filename: "math.joke",
	},
	{
		name:     "<joker.repl>",
		filename: "repl.joke",
	},
	{
		name:     "<joker.walk>",
		filename: "walk.joke",
	},
	{
		name:     "<joker.template>",
		filename: "template.joke",
	},
	{
		name:     "<joker.core>",
		filename: "linter_all.joke",
	},
	{
		name:     "<joker.core>",
		filename: "linter_cljx.joke",
	},
	{
		name:     "<joker.core>",
		filename: "linter_clj.joke",
	},
	{
		name:     "<joker.core>",
		filename: "linter_cljs.joke",
	},
}

const hextable = "0123456789abcdef"

func main() {
	GLOBAL_ENV.FindNamespace(MakeSymbol("user")).ReferAll(GLOBAL_ENV.CoreNamespace)
	for _, f := range files {
		println("Generating " + f.filename)
		GLOBAL_ENV.SetCurrentNamespace(GLOBAL_ENV.CoreNamespace)
		content, err := ioutil.ReadFile("data/" + f.filename)
		if err != nil {
			panic(err)
		}
		content, err = PackReader(NewReader(bytes.NewReader(content), f.name), "")
		PanicOnErr(err)

		dst := make([]byte, len(content)*4)
		for i, v := range content {
			dst[i*4] = '\\'
			dst[i*4+1] = 'x'
			dst[i*4+2] = hextable[v>>4]
			dst[i*4+3] = hextable[v&0x0f]
		}
		name := f.filename[0 : len(f.filename)-5] // assumes .joke extension
		fileContent := strings.Replace(template, "{name}", name, 1)
		fileContent = strings.Replace(fileContent, "{content}", string(dst), 1)
		ioutil.WriteFile("a_"+name+"_data.go", []byte(fileContent), 0666)
	}
}
<|endoftext|>


<commit_before>// +build windows

package cwriter

import (
	"io"
	"strings"
	"syscall"
	"unsafe"

	"github.com/mattn/go-isatty"
)

var kernel32 = syscall.NewLazyDLL("kernel32.dll")

var (
	procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
	procSetConsoleCursorPosition   = kernel32.NewProc("SetConsoleCursorPosition")
	procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW")
	procFillConsoleOutputAttribute = kernel32.NewProc("FillConsoleOutputAttribute")
)

type (
	short int16
	word  uint16
	dword uint32

	coord struct {
		x short
		y short
	}
	smallRect struct {
		left   short
		top    short
		right  short
		bottom short
	}
	consoleScreenBufferInfo struct {
		size              coord
		cursorPosition    coord
		attributes        word
		window            smallRect
		maximumWindowSize coord
	}
)

// FdWriter is a writer with a file descriptor.
type FdWriter interface {
	io.Writer
	Fd() uintptr
}

func (w *Writer) clearLines() error {
	f, ok := w.out.(FdWriter)
	if ok && !isatty.IsTerminal(f.Fd()) {
		_, err := io.WriteString(w.out, strings.Repeat(clearCursorAndLine, w.lineCount))
		return err
	}
	fd := f.Fd()
	var info consoleScreenBufferInfo
	procGetConsoleScreenBufferInfo.Call(fd, uintptr(unsafe.Pointer(&info)))

	for i := 0; i < w.lineCount; i++ {
		// move the cursor up
		info.cursorPosition.y--
		procSetConsoleCursorPosition.Call(fd, uintptr(*(*int32)(unsafe.Pointer(&info.cursorPosition))))
		// clear the line
		cursor := coord{
			x: info.window.left,
			y: info.window.top + info.cursorPosition.y,
		}
		var count, w dword
		count = dword(info.size.x)
		procFillConsoleOutputCharacter.Call(fd, uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&w)))
	}
	return nil
}
<commit_msg>goimports<commit_after>// +build windows

package cwriter

import (
	"io"
	"strings"
	"syscall"
	"unsafe"

	isatty "github.com/mattn/go-isatty"
)

var kernel32 = syscall.NewLazyDLL("kernel32.dll")

var (
	procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
	procSetConsoleCursorPosition   = kernel32.NewProc("SetConsoleCursorPosition")
	procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW")
	procFillConsoleOutputAttribute = kernel32.NewProc("FillConsoleOutputAttribute")
)

type (
	short int16
	word  uint16
	dword uint32

	coord struct {
		x short
		y short
	}
	smallRect struct {
		left   short
		top    short
		right  short
		bottom short
	}
	consoleScreenBufferInfo struct {
		size              coord
		cursorPosition    coord
		attributes        word
		window            smallRect
		maximumWindowSize coord
	}
)

// FdWriter is a writer with a file descriptor.
type FdWriter interface {
	io.Writer
	Fd() uintptr
}

func (w *Writer) clearLines() error {
	f, ok := w.out.(FdWriter)
	if ok && !isatty.IsTerminal(f.Fd()) {
		_, err := io.WriteString(w.out, strings.Repeat(clearCursorAndLine, w.lineCount))
		return err
	}
	fd := f.Fd()
	var info consoleScreenBufferInfo
	procGetConsoleScreenBufferInfo.Call(fd, uintptr(unsafe.Pointer(&info)))

	for i := 0; i < w.lineCount; i++ {
		// move the cursor up
		info.cursorPosition.y--
		procSetConsoleCursorPosition.Call(fd, uintptr(*(*int32)(unsafe.Pointer(&info.cursorPosition))))
		// clear the line
		cursor := coord{
			x: info.window.left,
			y: info.window.top + info.cursorPosition.y,
		}
		var count, w dword
		count = dword(info.size.x)
		procFillConsoleOutputCharacter.Call(fd, uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&w)))
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 by Michael Dvorkin. All Rights Reserved.
// Use of this source code is governed by a MIT-style license that can
// be found in the LICENSE file.

package donna

import(`sort`)

const (
        stepPrincipal = iota
        stepCaptures
        stepPromotions
        stepKillers
        stepRemaining
)

type MoveWithScore struct {
        move   Move
        score  int
}

type MoveGen struct {
        p     *Position
        list  [256]MoveWithScore
        head  int
        tail  int
        step  int
        ply   int
}

var moveList [MaxPly]MoveGen

func (p *Position) StartMoveGen(ply int) (gen *MoveGen) {
        gen = &moveList[ply]
        gen.p = p
        gen.list = [256]MoveWithScore{}
        gen.head, gen.tail = 0, 0
        gen.ply = ply
        return
}

func (gen *MoveGen) NextMove() (move Move) {
        if gen.head < gen.tail {
                move = gen.list[gen.head].move
                gen.head++
        }
        return
}

func (gen *MoveGen) rank() *MoveGen {
        if gen.tail - gen.head < 2 {
                return gen
        }
        for i := gen.head; i < gen.tail; i++ {
                move := gen.list[i].move
                if move == gen.p.game.bestLine[0][gen.ply] {
                        gen.list[i].score = 0xFFFF
                } else if move == gen.p.game.killers[gen.ply][0] {
                        gen.list[i].score = 0xFFFE
                } else if move == gen.p.game.killers[gen.ply][1] {
                        gen.list[i].score = 0xFFFD
                } else if move & isCapture != 0 {
                        gen.list[i].score = move.value()
                } else {
                        endgame, midgame := move.score()
                        gen.list[i].score = (midgame * gen.p.stage + endgame * (256 - gen.p.stage)) / 256
                }
        }
        sort.Sort(byScore{ gen.list[gen.head : gen.tail] })
        return gen
}

func (gen *MoveGen) GenerateQuiets() *MoveGen {
        return gen
}

func (gen *MoveGen) add(move Move) *MoveGen {
        gen.list[gen.tail].move = move
        gen.tail++
        return gen
}

// Return a list of generated moves by continuously calling the next move
// until the list is empty.
func (gen *MoveGen) allMoves() (moves []Move) {
	for move := gen.NextMove(); move != 0; move = gen.NextMove() {
		moves = append(moves, move)
	}
	return
}

// All moves.
func (p *Position) Moves(ply int) (moves []Move) {
        for square, piece := range p.pieces {
                if piece != 0 && piece.color() == p.color {
                        moves = append(moves, p.possibleMoves(square, piece)...)
                }
        }
        moves = p.reorderMoves(moves, p.game.bestLine[0][ply], p.game.killers[ply])
        Log("%d candidates for %s: %v\n", len(moves), C(p.color), moves)
        return
}

func (p *Position) Captures(ply int) (moves []Move) {
        for i, piece := range p.pieces {
                if piece != 0 && piece.color() == p.color {
                        moves = append(moves, p.possibleCaptures(i, piece)...)
                }
        }
        if bestMove := p.game.bestLine[0][ply]; bestMove != 0 && bestMove.capture() != 0 {
                moves = p.reorderCaptures(moves, bestMove)
        } else {
                //sort.Sort(byScore{moves})
        }

        Log("%d capture candidates for %s: %v\n", len(moves), C(p.color), moves)
        return
}

// All moves for the piece in certain square. This might include illegal
// moves that cause check to the king.
func (p *Position) possibleMoves(square int, piece Piece) (moves []Move) {
        targets := p.targets[square]

        for targets != 0 {
                target := targets.pop()
                //
                // For regular moves each target square represents one possible
                // move. For pawn promotion, however, we have to generate four
                // possible moves, one for each promoted piece.
                //
                if !p.isPawnPromotion(piece, target) {
                        moves = append(moves, p.NewMove(square, target))
                } else {
                        for _,name := range([]int{ QUEEN, ROOK, BISHOP, KNIGHT }) {
                                candidate := p.NewMove(square, target).promote(name)
                                moves = append(moves, candidate)
                        }
                }
        }
        return
}

// All capture moves for the piece in certain square. This might include
// illegal moves that cause check to the king.
func (p *Position) possibleCaptures(square int, piece Piece) (moves []Move) {
        targets := p.targets[square]

        for targets != 0 {
                target := targets.pop()
                capture := p.pieces[target]
                if capture != 0 {
                        if !p.isPawnPromotion(piece, target) {
                                moves = append(moves, p.NewMove(square, target))
                        } else {
                                for _,name := range([]int{ QUEEN, ROOK, BISHOP, KNIGHT }) {
                                        candidate := p.NewMove(square, target).promote(name)
                                        moves = append(moves, candidate)
                                }
                        }
                } else if p.flags.enpassant != 0 && target == p.flags.enpassant {
                        moves = append(moves, p.NewMove(square, target))
                }
        }
        return
}

func (p *Position) reorderMoves(moves []Move, bestMove Move, goodMove [2]Move) []Move {
        var principal, killers, captures, promotions, remaining []Move

        for _, move := range moves {
                if len(principal) == 0 && bestMove != 0 && move == bestMove {
                        principal = append(principal, move)
                } else if move.capture() != 0 {
                        captures = append(captures, move)
                } else if move.promo() != 0 {
                        promotions = append(promotions, move)
                } else if (goodMove[0] != 0 && move == goodMove[0]) || (goodMove[1] != 0 && move == goodMove[1]) {
                        killers = append(killers, move)
                } else {
                        remaining = append(remaining, move)
                }
        }
        if len(killers) > 1 && killers[0] == goodMove[1] {
                killers[0], killers[1] = killers[1], killers[0]
        }

        //sort.Sort(byScore{captures})
        //sort.Sort(byScore{remaining})
        return append(append(append(append(append(principal, captures...), promotions...), killers...), remaining...))
}

func (p *Position) reorderCaptures(moves []Move, bestMove Move) []Move {
        var principal, remaining []Move

        for _, move := range moves {
                if len(principal) == 0 && move == bestMove {
                        principal = append(principal, move)
                } else {
                        remaining = append(remaining, move)
                }
        }
        //sort.Sort(byScore{remaining})
        return append(principal, remaining...)
}

// Sorting moves by their relative score based on piece/square for regular moves
// or least valuaeable attacker/most valueable victim for captures.
type byScore struct {
        list []MoveWithScore
}
func (her byScore) Len() int           { return len(her.list)}
func (her byScore) Swap(i, j int)      { her.list[i], her.list[j] = her.list[j], her.list[i] }
func (her byScore) Less(i, j int) bool { return her.list[i].score > her.list[j].score }
<commit_msg>Clean up -- naive move generator gone<commit_after>// Copyright (c) 2013 by Michael Dvorkin. All Rights Reserved.
// Use of this source code is governed by a MIT-style license that can
// be found in the LICENSE file.

package donna

import(`sort`)

const (
        stepPrincipal = iota
        stepCaptures
        stepPromotions
        stepKillers
        stepRemaining
)

type MoveWithScore struct {
        move   Move
        score  int
}

type MoveGen struct {
        p     *Position
        list  [256]MoveWithScore
        head  int
        tail  int
        step  int
        ply   int
}

var moveList [MaxPly]MoveGen

func (p *Position) StartMoveGen(ply int) (gen *MoveGen) {
        gen = &moveList[ply]
        gen.p = p
        gen.list = [256]MoveWithScore{}
        gen.head, gen.tail = 0, 0
        gen.ply = ply
        return
}

func (gen *MoveGen) NextMove() (move Move) {
        if gen.head < gen.tail {
                move = gen.list[gen.head].move
                gen.head++
        }
        return
}

func (gen *MoveGen) rank() *MoveGen {
        if gen.tail - gen.head < 2 {
                return gen
        }
        for i := gen.head; i < gen.tail; i++ {
                move := gen.list[i].move
                if move == gen.p.game.bestLine[0][gen.ply] {
                        gen.list[i].score = 0xFFFF
                } else if move == gen.p.game.killers[gen.ply][0] {
                        gen.list[i].score = 0xFFFE
                } else if move == gen.p.game.killers[gen.ply][1] {
                        gen.list[i].score = 0xFFFD
                } else if move & isCapture != 0 {
                        gen.list[i].score = move.value()
                } else {
                        endgame, midgame := move.score()
                        gen.list[i].score = (midgame * gen.p.stage + endgame * (256 - gen.p.stage)) / 256
                }
        }
        sort.Sort(byScore{ gen.list[gen.head : gen.tail] })
        return gen
}

func (gen *MoveGen) GenerateQuiets() *MoveGen {
        return gen
}

func (gen *MoveGen) add(move Move) *MoveGen {
        gen.list[gen.tail].move = move
        gen.tail++
        return gen
}

// Return a list of generated moves by continuously calling the next move
// until the list is empty.
func (gen *MoveGen) allMoves() (moves []Move) {
	for move := gen.NextMove(); move != 0; move = gen.NextMove() {
		moves = append(moves, move)
	}
	return
}

// Sorting moves by their relative score based on piece/square for regular moves
// or least valuaeable attacker/most valueable victim for captures.
type byScore struct {
        list []MoveWithScore
}
func (her byScore) Len() int           { return len(her.list)}
func (her byScore) Swap(i, j int)      { her.list[i], her.list[j] = her.list[j], her.list[i] }
func (her byScore) Less(i, j int) bool { return her.list[i].score > her.list[j].score }
<|endoftext|>


<commit_before>package astar

import (
	"fmt"
	"testing"

	"github.com/wkhere/astar/graphs/geo"
)

// TODO:
// need more dense graph to test & benchmark non-trivial paths

func ExampleGeo() {
	g := Geo{}
	fmt.Println(Astar(g, "Wałcz", "Wałcz"))
	fmt.Println(Astar(g, "Wałcz", "Warszawa"))
	fmt.Println(Astar(g, "Warszawa", "Wałcz"))
	fmt.Println(Astar(g, "Wałcz", "Poznań"))
	// Output:
	// []
	// [Warszawa]
	// [Wałcz]
	// [Trzcianka Poznań]
}

func BenchmarkGeo(b *testing.B) {
	g := Geo{}
	for n := 0; n < b.N; n++ {
		Astar(g, "Wałcz", "Wałcz")
		Astar(g, "Wałcz", "Warszawa")
		Astar(g, "Wałcz", "Poznań")
	}
}

type Geo struct{}

func (g Geo) Nbs(node Node) []Node {
	return nbs[node]
}

func (g Geo) Dist(n1, n2 Node) (v Cost) {
	v, ok := distLookup(n1, n2)
	if !ok {
		panic(fmt.Sprintf("no dist for %v,%v", n1, n2))
	}
	return
}

func (g Geo) H(n1, n2 Node) Cost {
	return Cost(geo.H(coords[n1], coords[n2]))
}

var coords = map[Node]geo.Pt{
	"Wałcz":     geo.Pt{53.283853, 16.470173},
	"Trzcianka": geo.Pt{53.0427712, 16.3763841},
	"Piła":      geo.Pt{53.1347933, 16.6195561},
	"Poznań":    geo.Pt{52.408031, 16.920613},
	"Warszawa":  geo.Pt{52.230069, 21.018513},
}

type nodePair struct{ n1, n2 Node }

var distances = map[nodePair]Cost{
	// these are arbitrary distances taken from real maps
	nodePair{"Wałcz", "Trzcianka"}:  31,
	nodePair{"Trzcianka", "Poznań"}: 88,
	nodePair{"Wałcz", "Piła"}:       28,
	nodePair{"Piła", "Poznań"}:      96,
	nodePair{"Wałcz", "Warszawa"}:   421,
	nodePair{"Poznań", "Warszawa"}:  310,
}

var nbs = map[Node][]Node{}

func init() {
	for k := range distances {
		nbs[k.n1] = append(nbs[k.n1], k.n2)
		nbs[k.n2] = append(nbs[k.n2], k.n1)
	}
}

func distLookup(n1, n2 Node) (v Cost, ok bool) {
	v, ok = distances[nodePair{n1, n2}]
	if ok {
		return v, ok
	}
	v, ok = distances[nodePair{n2, n1}]
	return
}
<commit_msg>geo example: simplify literal structs (thx gofmt!)<commit_after>package astar

import (
	"fmt"
	"testing"

	"github.com/wkhere/astar/graphs/geo"
)

// TODO:
// need more dense graph to test & benchmark non-trivial paths

func ExampleGeo() {
	g := Geo{}
	fmt.Println(Astar(g, "Wałcz", "Wałcz"))
	fmt.Println(Astar(g, "Wałcz", "Warszawa"))
	fmt.Println(Astar(g, "Warszawa", "Wałcz"))
	fmt.Println(Astar(g, "Wałcz", "Poznań"))
	// Output:
	// []
	// [Warszawa]
	// [Wałcz]
	// [Trzcianka Poznań]
}

func BenchmarkGeo(b *testing.B) {
	g := Geo{}
	for n := 0; n < b.N; n++ {
		Astar(g, "Wałcz", "Wałcz")
		Astar(g, "Wałcz", "Warszawa")
		Astar(g, "Wałcz", "Poznań")
	}
}

type Geo struct{}

func (g Geo) Nbs(node Node) []Node {
	return nbs[node]
}

func (g Geo) Dist(n1, n2 Node) (v Cost) {
	v, ok := distLookup(n1, n2)
	if !ok {
		panic(fmt.Sprintf("no dist for %v,%v", n1, n2))
	}
	return
}

func (g Geo) H(n1, n2 Node) Cost {
	return Cost(geo.H(coords[n1], coords[n2]))
}

var coords = map[Node]geo.Pt{
	"Wałcz":     {53.283853, 16.470173},
	"Trzcianka": {53.0427712, 16.3763841},
	"Piła":      {53.1347933, 16.6195561},
	"Poznań":    {52.408031, 16.920613},
	"Warszawa":  {52.230069, 21.018513},
}

type nodePair struct{ n1, n2 Node }

var distances = map[nodePair]Cost{
	// these are arbitrary distances taken from real maps
	{"Wałcz", "Trzcianka"}:  31,
	{"Trzcianka", "Poznań"}: 88,
	{"Wałcz", "Piła"}:       28,
	{"Piła", "Poznań"}:      96,
	{"Wałcz", "Warszawa"}:   421,
	{"Poznań", "Warszawa"}:  310,
}

var nbs = map[Node][]Node{}

func init() {
	for k := range distances {
		nbs[k.n1] = append(nbs[k.n1], k.n2)
		nbs[k.n2] = append(nbs[k.n2], k.n1)
	}
}

func distLookup(n1, n2 Node) (v Cost, ok bool) {
	v, ok = distances[nodePair{n1, n2}]
	if ok {
		return v, ok
	}
	v, ok = distances[nodePair{n2, n1}]
	return
}
<|endoftext|>


<commit_before>// https://status.github.com/api

package ghstatus

import (
	"encoding/json"
	"io/ioutil"
	"net/http"
)

const StatusApiUrl = "https://status.github.com/api"

const (
	StatusGood  = "good"
	StatusMinor = "minor"
	StatusMajor = "major"
)

type Status struct {
	Status      string `json:"status"`
	LastUpdated string `json:"last_updated"`
}

type Message struct {
	Status    string `json:"status"`
	Body      string `json:"body"`
	CreatedOn string `json:"created_on"`
}

func sendRequest(endpoint string, v interface{}) error {
	resp, err := http.Get(StatusApiUrl + endpoint + ".json")
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	return json.Unmarshal(body, &v)
}

func GetStatus() (*Status, error) {
	var status *Status
	if err := sendRequest("/status", &status); err != nil {
		return nil, err
	}
	return status, nil
}

func GetMessages() ([]Message, error) {
	var messages []Message
	if err := sendRequest("/messages", &messages); err != nil {
		return nil, err
	}
	return messages, nil
}

func GetLastMessage() (*Message, error) {
	var message *Message
	if err := sendRequest("/last-message", &message); err != nil {
		return nil, err
	}
	return message, nil
}
<commit_msg>Add some API documentation<commit_after>// https://status.github.com/api

package ghstatus

import (
	"encoding/json"
	"io/ioutil"
	"net/http"
)

const StatusApiUrl = "https://status.github.com/api"

const (
	StatusGood  = "good"
	StatusMinor = "minor"
	StatusMajor = "major"
)

type Status struct {
	Status      string `json:"status"`
	LastUpdated string `json:"last_updated"`
}

type Message struct {
	Status    string `json:"status"`
	Body      string `json:"body"`
	CreatedOn string `json:"created_on"`
}

func sendRequest(endpoint string, v interface{}) error {
	resp, err := http.Get(StatusApiUrl + endpoint + ".json")
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	return json.Unmarshal(body, &v)
}

// Get current system status (one of good, minor, or major) and timestamp.
func GetStatus() (*Status, error) {
	var status *Status
	if err := sendRequest("/status", &status); err != nil {
		return nil, err
	}
	return status, nil
}

// Get most recent human communications with status and timestamp.
func GetMessages() ([]Message, error) {
	var messages []Message
	if err := sendRequest("/messages", &messages); err != nil {
		return nil, err
	}
	return messages, nil
}

// Get last human communication, status, and timestamp.
func GetLastMessage() (*Message, error) {
	var message *Message
	if err := sendRequest("/last-message", &message); err != nil {
		return nil, err
	}
	return message, nil
}
<|endoftext|>


<commit_before>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2019 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package lib

import (
	"encoding"
	"fmt"
	"math/big"
	"strings"
)

// ExecutionSegment represents a (start, end] partition of the total execution
// work for a specific test. For example, if we want the split the execution of a
// test in 2 different parts, we can split it in two segments (0, 0.5] and (0,5, 1].
//
// We use rational numbers so it's easier to verify the correctness and easier to
// reason about portions of indivisible things, like VUs. This way, we can easily
// split a test in thirds (i.e. (0, 1/3], (1/3, 2/3], (2/3, 1]), without fearing
// that we'll lose a VU along the way...
//
// The most important part is that if work is split between multiple k6 instances,
// each k6 instance can precisely and reproducably calculate its share of the work,
// just by knowing its own segment. There won't be a need to schedule the
// execution from a master node, or to even know how many other k6 instances are
// running!
type ExecutionSegment struct {
	// 0 <= from < to <= 1
	from *big.Rat
	to   *big.Rat

	// derived, equals to-from, but pre-calculated here for speed
	length *big.Rat
}

// Ensure we implement those interfaces
var _ encoding.TextUnmarshaler = &ExecutionSegment{}
var _ fmt.Stringer = &ExecutionSegment{}

// Helpful "constants" so we don't initialize them in every function call
var zeroRat, oneRat = big.NewRat(0, 1), big.NewRat(1, 1) //nolint:gochecknoglobals
var oneBigInt, twoBigInt = big.NewInt(1), big.NewInt(2)  //nolint:gochecknoglobals

// NewExecutionSegment validates the supplied arguments (basically, that 0 <=
// from < to <= 1) and either returns an error, or it returns a
// fully-initialized and usable execution segment.
func NewExecutionSegment(from, to *big.Rat) (*ExecutionSegment, error) {
	if from.Cmp(zeroRat) < 0 {
		return nil, fmt.Errorf("segment start value should be at least 0 but was %s", from.FloatString(2))
	}
	if from.Cmp(to) >= 0 {
		return nil, fmt.Errorf("segment start(%s) should be less than its end(%s)", from.FloatString(2), to.FloatString(2))
	}
	if to.Cmp(oneRat) > 0 {
		return nil, fmt.Errorf("segment end value shouldn't be more than 1 but was %s", to.FloatString(2))
	}
	return &ExecutionSegment{
		from:   from,
		to:     to,
		length: new(big.Rat).Sub(to, from),
	}, nil
}

// stringToRat is a helper function that tries to convert a string to a rational
// number while allowing percentage, decimal, and fraction values.
func stringToRat(s string) (*big.Rat, error) {
	if strings.HasSuffix(s, "%") {
		num, ok := new(big.Int).SetString(strings.TrimSuffix(s, "%"), 10)
		if !ok {
			return nil, fmt.Errorf("'%s' is not a valid percentage", s)
		}
		return new(big.Rat).SetFrac(num, big.NewInt(100)), nil
	}
	rat, ok := new(big.Rat).SetString(s)
	if !ok {
		return nil, fmt.Errorf("'%s' is not a valid percentage, decimal, fraction or interval value", s)
	}
	return rat, nil
}

// UnmarshalText implements the encoding.TextUnmarshaler interface, so that
// execution segments can be specified as CLI flags, environment variables, and
// JSON strings.
//
// We are able to parse both single percentage/float/fraction values, and actual
// (from; to] segments. For the single values, we just treat them as the
// beginning segment - thus the execution segment can be used as a shortcut for
// quickly running an arbitrarily scaled-down version of a test.
//
// The parsing logic is that values with a colon, i.e. ':', are full segments:
//  `1/2:3/4`, `0.5:0.75`, `50%:75%`, and even `2/4:75%` should be (1/2, 3/4]
// And values without a hyphen are the end of a first segment:
//  `20%`, `0.2`,  and `1/5` should be converted to (0, 1/5]
// empty values should probably be treated as "1", i.e. the whole execution
func (es *ExecutionSegment) UnmarshalText(text []byte) (err error) {
	from := zeroRat
	toStr := string(text)
	if strings.ContainsRune(toStr, ':') {
		fromToStr := strings.SplitN(toStr, ":", 2)
		toStr = fromToStr[1]
		if from, err = stringToRat(fromToStr[0]); err != nil {
			return err
		}
	}

	to, err := stringToRat(toStr)
	if err != nil {
		return err
	}

	segment, err := NewExecutionSegment(from, to)
	if err != nil {
		return err
	}
	*es = *segment
	return nil
}

func (es *ExecutionSegment) String() string {
	if es == nil {
		return "0:1"
	}
	return es.from.RatString() + ":" + es.to.RatString()
}

// FloatLength is a helper method for getting some more human-readable
// information about the execution segment.
func (es *ExecutionSegment) FloatLength() float64 {
	if es == nil {
		return 1.0
	}
	res, _ := es.length.Float64()
	return res
}

// Split evenly dividies the execution segment into the specified number of
// equal consecutive execution sub-segments.
func (es *ExecutionSegment) Split(numParts int64) ([]*ExecutionSegment, error) {
	if numParts < 1 {
		return nil, fmt.Errorf("the number of parts should be at least 1, %d received", numParts)
	}

	from, to := zeroRat, oneRat
	if es != nil {
		from, to = es.from, es.to
	}

	increment := new(big.Rat).Sub(to, from)
	increment.Denom().Mul(increment.Denom(), big.NewInt(numParts))

	results := make([]*ExecutionSegment, numParts)
	for i := int64(0); i < numParts; i++ {
		segmentTo := new(big.Rat).Add(from, increment)
		segment, err := NewExecutionSegment(from, segmentTo)
		if err != nil {
			return nil, err
		}
		results[i] = segment
		from = segmentTo
	}

	if from.Cmp(to) != 0 {
		return nil, fmt.Errorf("expected %s and %s to be equal", from, to)
	}

	return results, nil
}

//TODO: add a NewFromString() method

// Equal returns true only if the two execution segments have the same from and
// to values.
func (es *ExecutionSegment) Equal(other *ExecutionSegment) bool {
	if es == other {
		return true
	}
	thisFrom, otherFrom, thisTo, otherTo := zeroRat, zeroRat, oneRat, oneRat
	if es != nil {
		thisFrom, thisTo = es.from, es.to
	}
	if other != nil {
		otherFrom, otherTo = other.from, other.to
	}
	return thisFrom.Cmp(otherFrom) == 0 && thisTo.Cmp(otherTo) == 0
}

// SubSegment returns a new execution sub-segment - if a is (1/2:1] and b is
// (0:1/2], then a.SubSegment(b) will return a new segment (1/2, 3/4].
//
// The basic formula for c = a.SubSegment(b) is:
//    c.from = a.from + b.from * (a.to - a.from)
//    c.to = c.from + (b.to - b.from) * (a.to - a.from)
func (es *ExecutionSegment) SubSegment(child *ExecutionSegment) *ExecutionSegment {
	if child == nil {
		return es // 100% sub-segment is the original segment
	}

	parentFrom, parentLength := zeroRat, oneRat
	if es != nil {
		parentFrom, parentLength = es.from, es.length
	}

	resultFrom := new(big.Rat).Mul(parentLength, child.from)
	resultFrom.Add(resultFrom, parentFrom)

	resultLength := new(big.Rat).Mul(parentLength, child.length)
	return &ExecutionSegment{
		from:   resultFrom,
		length: resultLength,
		to:     new(big.Rat).Add(resultFrom, resultLength),
	}
}

// helper function for rounding (up) of rational numbers to big.Int values
func roundUp(rat *big.Rat) *big.Int {
	quo, rem := new(big.Int).QuoRem(rat.Num(), rat.Denom(), new(big.Int))

	if rem.Mul(rem, twoBigInt).Cmp(rat.Denom()) >= 0 {
		return quo.Add(quo, oneBigInt)
	}
	return quo
}

// Scale proportionally scales the supplied value, according to the execution
// segment's position and size of the work.
func (es *ExecutionSegment) Scale(value int64) int64 {
	if es == nil { // no execution segment, i.e. 100%
		return value
	}
	// Instead of the first proposal that used remainders and floor:
	//    floor( (value * from) % 1 + value * length )
	// We're using an alternative approach with rounding that (hopefully) has
	// the same properties, but it's simpler and has better precision:
	//    round( (value * from) - round(value * from) + (value * (to - from)) )?
	// which reduces to:
	//    round( (value * to) - round(value * from) )?

	toValue := big.NewRat(value, 1)
	toValue.Mul(toValue, es.to)

	fromValue := big.NewRat(value, 1)
	fromValue.Mul(fromValue, es.from)

	toValue.Sub(toValue, new(big.Rat).SetFrac(roundUp(fromValue), oneBigInt))

	return roundUp(toValue).Int64()
}

// InPlaceScaleRat scales rational numbers in-place - it changes the passed
// argument (and also returns it, to allow for chaining, like many other big.Rat
// methods).
func (es *ExecutionSegment) InPlaceScaleRat(value *big.Rat) *big.Rat {
	if es == nil { // no execution segment, i.e. 100%
		return value
	}
	return value.Mul(value, es.length)
}

// CopyScaleRat scales rational numbers without changing them - creates a new
// bit.Rat object and uses it for the calculation.
func (es *ExecutionSegment) CopyScaleRat(value *big.Rat) *big.Rat {
	if es == nil { // no execution segment, i.e. 100%
		return value
	}
	return new(big.Rat).Mul(value, es.length)
}
<commit_msg>Add text/JSON marshaling for execution segments<commit_after>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2019 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package lib

import (
	"encoding"
	"fmt"
	"math/big"
	"strings"
)

// ExecutionSegment represents a (start, end] partition of the total execution
// work for a specific test. For example, if we want the split the execution of a
// test in 2 different parts, we can split it in two segments (0, 0.5] and (0,5, 1].
//
// We use rational numbers so it's easier to verify the correctness and easier to
// reason about portions of indivisible things, like VUs. This way, we can easily
// split a test in thirds (i.e. (0, 1/3], (1/3, 2/3], (2/3, 1]), without fearing
// that we'll lose a VU along the way...
//
// The most important part is that if work is split between multiple k6 instances,
// each k6 instance can precisely and reproducably calculate its share of the work,
// just by knowing its own segment. There won't be a need to schedule the
// execution from a master node, or to even know how many other k6 instances are
// running!
type ExecutionSegment struct {
	// 0 <= from < to <= 1
	from *big.Rat
	to   *big.Rat

	// derived, equals to-from, but pre-calculated here for speed
	length *big.Rat
}

// Ensure we implement those interfaces
var _ encoding.TextUnmarshaler = &ExecutionSegment{}
var _ fmt.Stringer = &ExecutionSegment{}

// Helpful "constants" so we don't initialize them in every function call
var zeroRat, oneRat = big.NewRat(0, 1), big.NewRat(1, 1) //nolint:gochecknoglobals
var oneBigInt, twoBigInt = big.NewInt(1), big.NewInt(2)  //nolint:gochecknoglobals

// NewExecutionSegment validates the supplied arguments (basically, that 0 <=
// from < to <= 1) and either returns an error, or it returns a
// fully-initialized and usable execution segment.
func NewExecutionSegment(from, to *big.Rat) (*ExecutionSegment, error) {
	if from.Cmp(zeroRat) < 0 {
		return nil, fmt.Errorf("segment start value should be at least 0 but was %s", from.FloatString(2))
	}
	if from.Cmp(to) >= 0 {
		return nil, fmt.Errorf("segment start(%s) should be less than its end(%s)", from.FloatString(2), to.FloatString(2))
	}
	if to.Cmp(oneRat) > 0 {
		return nil, fmt.Errorf("segment end value shouldn't be more than 1 but was %s", to.FloatString(2))
	}
	return &ExecutionSegment{
		from:   from,
		to:     to,
		length: new(big.Rat).Sub(to, from),
	}, nil
}

// stringToRat is a helper function that tries to convert a string to a rational
// number while allowing percentage, decimal, and fraction values.
func stringToRat(s string) (*big.Rat, error) {
	if strings.HasSuffix(s, "%") {
		num, ok := new(big.Int).SetString(strings.TrimSuffix(s, "%"), 10)
		if !ok {
			return nil, fmt.Errorf("'%s' is not a valid percentage", s)
		}
		return new(big.Rat).SetFrac(num, big.NewInt(100)), nil
	}
	rat, ok := new(big.Rat).SetString(s)
	if !ok {
		return nil, fmt.Errorf("'%s' is not a valid percentage, decimal, fraction or interval value", s)
	}
	return rat, nil
}

// UnmarshalText implements the encoding.TextUnmarshaler interface, so that
// execution segments can be specified as CLI flags, environment variables, and
// JSON strings.
//
// We are able to parse both single percentage/float/fraction values, and actual
// (from; to] segments. For the single values, we just treat them as the
// beginning segment - thus the execution segment can be used as a shortcut for
// quickly running an arbitrarily scaled-down version of a test.
//
// The parsing logic is that values with a colon, i.e. ':', are full segments:
//  `1/2:3/4`, `0.5:0.75`, `50%:75%`, and even `2/4:75%` should be (1/2, 3/4]
// And values without a hyphen are the end of a first segment:
//  `20%`, `0.2`,  and `1/5` should be converted to (0, 1/5]
// empty values should probably be treated as "1", i.e. the whole execution
func (es *ExecutionSegment) UnmarshalText(text []byte) (err error) {
	from := zeroRat
	toStr := string(text)
	if strings.ContainsRune(toStr, ':') {
		fromToStr := strings.SplitN(toStr, ":", 2)
		toStr = fromToStr[1]
		if from, err = stringToRat(fromToStr[0]); err != nil {
			return err
		}
	}

	to, err := stringToRat(toStr)
	if err != nil {
		return err
	}

	segment, err := NewExecutionSegment(from, to)
	if err != nil {
		return err
	}
	*es = *segment
	return nil
}

func (es *ExecutionSegment) String() string {
	if es == nil {
		return "0:1"
	}
	return es.from.RatString() + ":" + es.to.RatString()
}

// MarshalText implements the encoding.TextMarshaler interface, so is used for
// text and JSON encoding of the execution segment.
func (es *ExecutionSegment) MarshalText() ([]byte, error) {
	if es == nil {
		return nil, nil
	}
	return []byte(es.String()), nil
}

// FloatLength is a helper method for getting some more human-readable
// information about the execution segment.
func (es *ExecutionSegment) FloatLength() float64 {
	if es == nil {
		return 1.0
	}
	res, _ := es.length.Float64()
	return res
}

// Split evenly dividies the execution segment into the specified number of
// equal consecutive execution sub-segments.
func (es *ExecutionSegment) Split(numParts int64) ([]*ExecutionSegment, error) {
	if numParts < 1 {
		return nil, fmt.Errorf("the number of parts should be at least 1, %d received", numParts)
	}

	from, to := zeroRat, oneRat
	if es != nil {
		from, to = es.from, es.to
	}

	increment := new(big.Rat).Sub(to, from)
	increment.Denom().Mul(increment.Denom(), big.NewInt(numParts))

	results := make([]*ExecutionSegment, numParts)
	for i := int64(0); i < numParts; i++ {
		segmentTo := new(big.Rat).Add(from, increment)
		segment, err := NewExecutionSegment(from, segmentTo)
		if err != nil {
			return nil, err
		}
		results[i] = segment
		from = segmentTo
	}

	if from.Cmp(to) != 0 {
		return nil, fmt.Errorf("expected %s and %s to be equal", from, to)
	}

	return results, nil
}

//TODO: add a NewFromString() method

// Equal returns true only if the two execution segments have the same from and
// to values.
func (es *ExecutionSegment) Equal(other *ExecutionSegment) bool {
	if es == other {
		return true
	}
	thisFrom, otherFrom, thisTo, otherTo := zeroRat, zeroRat, oneRat, oneRat
	if es != nil {
		thisFrom, thisTo = es.from, es.to
	}
	if other != nil {
		otherFrom, otherTo = other.from, other.to
	}
	return thisFrom.Cmp(otherFrom) == 0 && thisTo.Cmp(otherTo) == 0
}

// SubSegment returns a new execution sub-segment - if a is (1/2:1] and b is
// (0:1/2], then a.SubSegment(b) will return a new segment (1/2, 3/4].
//
// The basic formula for c = a.SubSegment(b) is:
//    c.from = a.from + b.from * (a.to - a.from)
//    c.to = c.from + (b.to - b.from) * (a.to - a.from)
func (es *ExecutionSegment) SubSegment(child *ExecutionSegment) *ExecutionSegment {
	if child == nil {
		return es // 100% sub-segment is the original segment
	}

	parentFrom, parentLength := zeroRat, oneRat
	if es != nil {
		parentFrom, parentLength = es.from, es.length
	}

	resultFrom := new(big.Rat).Mul(parentLength, child.from)
	resultFrom.Add(resultFrom, parentFrom)

	resultLength := new(big.Rat).Mul(parentLength, child.length)
	return &ExecutionSegment{
		from:   resultFrom,
		length: resultLength,
		to:     new(big.Rat).Add(resultFrom, resultLength),
	}
}

// helper function for rounding (up) of rational numbers to big.Int values
func roundUp(rat *big.Rat) *big.Int {
	quo, rem := new(big.Int).QuoRem(rat.Num(), rat.Denom(), new(big.Int))

	if rem.Mul(rem, twoBigInt).Cmp(rat.Denom()) >= 0 {
		return quo.Add(quo, oneBigInt)
	}
	return quo
}

// Scale proportionally scales the supplied value, according to the execution
// segment's position and size of the work.
func (es *ExecutionSegment) Scale(value int64) int64 {
	if es == nil { // no execution segment, i.e. 100%
		return value
	}
	// Instead of the first proposal that used remainders and floor:
	//    floor( (value * from) % 1 + value * length )
	// We're using an alternative approach with rounding that (hopefully) has
	// the same properties, but it's simpler and has better precision:
	//    round( (value * from) - round(value * from) + (value * (to - from)) )?
	// which reduces to:
	//    round( (value * to) - round(value * from) )?

	toValue := big.NewRat(value, 1)
	toValue.Mul(toValue, es.to)

	fromValue := big.NewRat(value, 1)
	fromValue.Mul(fromValue, es.from)

	toValue.Sub(toValue, new(big.Rat).SetFrac(roundUp(fromValue), oneBigInt))

	return roundUp(toValue).Int64()
}

// InPlaceScaleRat scales rational numbers in-place - it changes the passed
// argument (and also returns it, to allow for chaining, like many other big.Rat
// methods).
func (es *ExecutionSegment) InPlaceScaleRat(value *big.Rat) *big.Rat {
	if es == nil { // no execution segment, i.e. 100%
		return value
	}
	return value.Mul(value, es.length)
}

// CopyScaleRat scales rational numbers without changing them - creates a new
// bit.Rat object and uses it for the calculation.
func (es *ExecutionSegment) CopyScaleRat(value *big.Rat) *big.Rat {
	if es == nil { // no execution segment, i.e. 100%
		return value
	}
	return new(big.Rat).Mul(value, es.length)
}
<|endoftext|>


<commit_before>package middleware

import (
	"github.com/gin-gonic/gin"
	"strings"

	u "github.com/techjanitor/pram-get/utils"
)

// Cache will check for the key in Redis and serve it. If not found, it will
// take the marshalled JSON from the controller and set it in Redis
func Cache() gin.HandlerFunc {
	return func(c *gin.Context) {
		var result []byte
		var err error

		// Get request path
		path := c.Request.URL.Path

		// Trim leading / from path and split
		params := strings.Split(strings.Trim(path, "/"), "/")

		// Make key from path
		key := redisKey{}
		key.expireKey(params[0])

		// Create redis key
		key.Key = strings.Join(params, ":")

		// Initialize cache handle
		cache := u.RedisCache

		// Check to see if there is already a key we can serve
		result, err = cache.Get(key.Key)
		if err == u.ErrCacheMiss {
			c.Next()

			// Check if there was an error from the controller
			controllerError, _ := c.Get("controllerError")
			if controllerError != nil {
				c.Abort()
				return
			}

			// Get data from controller
			data := c.MustGet("data").([]byte)

			if key.Expire {

				// Set output to cache
				err = cache.SetEx(key.Key, 60, data)
				if err != nil {
					c.Error(err)
					c.Abort()
					return
				}

			} else {

				// Set output to cache
				err = cache.Set(key.Key, data)
				if err != nil {
					c.Error(err)
					c.Abort()
					return
				}

			}

		}

		if err != nil {
			c.Error(err)
			c.Abort()
			return
		}

		c.Writer.Header().Set("Content-Type", "application/json")
		c.Writer.Write(result)
		c.Abort()

	}

}

type redisKey struct {
	Key    string
	Expire bool
}

// Check if key should be expired
func (r *redisKey) expireKey(key string) {

	keyList := map[string]bool{
		"image": true,
		"pram":  true,
		"tag":   true,
	}

	if keyList[strings.ToLower(key)] {
		r.Expire = true
	}

	return

}
<commit_msg>simplify redis cache<commit_after>package middleware

import (
	"github.com/gin-gonic/gin"
	"strings"

	u "github.com/techjanitor/pram-get/utils"
)

// Cache will check for the key in Redis and serve it. If not found, it will
// take the marshalled JSON from the controller and set it in Redis
func Cache() gin.HandlerFunc {
	return func(c *gin.Context) {
		var result []byte
		var err error

		// Get request path
		path := c.Request.URL.Path

		// Trim leading / from path and split
		params := strings.Split(strings.Trim(path, "/"), "/")

		// Make key from path
		key := redisKey{}
		key.expireKey(params[0])
		key.generateKey(params...)

		// Initialize cache handle
		cache := u.RedisCache

		if key.Hash {
			// Check to see if there is already a key we can serve
			result, err = cache.HGet(key.Key, key.Field)
			if err == u.ErrCacheMiss {
				c.Next()

				// Check if there was an error from the controller
				controllerError, _ := c.Get("controllerError")
				if controllerError != nil {
					c.Abort()
					return
				}

				// Get data from controller
				data := c.MustGet("data").([]byte)

				// Set output to cache
				err = cache.HMSet(key.Key, key.Field, data)
				if err != nil {
					c.Error(err)
					c.Abort()
					return
				}

			}
			if err != nil {
				c.Error(err)
				c.Abort()
				return
			}

		}

		if !key.Hash {
			// Check to see if there is already a key we can serve
			result, err = cache.Get(key.Key)
			if err == u.ErrCacheMiss {
				c.Next()

				// Check if there was an error from the controller
				controllerError, _ := c.Get("controllerError")
				if controllerError != nil {
					c.Abort()
					return
				}

				// Get data from controller
				data := c.MustGet("data").([]byte)

				if key.Expire {

					// Set output to cache
					err = cache.SetEx(key.Key, 60, data)
					if err != nil {
						c.Error(err)
						c.Abort()
						return
					}

				} else {

					// Set output to cache
					err = cache.Set(key.Key, data)
					if err != nil {
						c.Error(err)
						c.Abort()
						return
					}

				}

			}
			if err != nil {
				c.Error(err)
				c.Abort()
				return
			}

		}

		c.Writer.Header().Set("Content-Type", "application/json")
		c.Writer.Write(result)
		c.Abort()

	}

}

type redisKey struct {
	Key    string
	Field  string
	Hash   bool
	Expire bool
}

// Will take the params from the request and turn them into a key
func (r *redisKey) generateKey(params ...string) {
	var keys []string

	for i, param := range params {
		// Add key
		if i == 0 || i == 1 {
			keys = append(keys, param)
		}
		// Add field for redis hash if present
		if i == 2 {
			r.Field = param
			r.Hash = true
		}

	}

	// Create redis key
	r.Key = strings.Join(keys, ":")

	return

}

// Check if key should be expired
func (r *redisKey) expireKey(key string) {

	keyList := map[string]bool{
		"image": true,
		"pram":  true,
		"tag":   true,
	}

	if keyList[strings.ToLower(key)] {
		r.Expire = true
	}

	return

}
<|endoftext|>


<commit_before>package gojison

import (
	"bytes"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/zenazn/goji/web"
)

func init() {
}

func TestResponse(t *testing.T) {
	w := httptest.NewRecorder()
	r := &http.Request{}
	Response(TestHandler{}).ServeHTTP(w, r)
	if w.Header().Get("Content-Type") != "application/json" {
		t.Error("Expected content-type to be set to application/json")
	}
}

func TestRequest(t *testing.T) {
	request := []byte(`
		{
			"one": 1,
			"nested":{
				"two": 2
			}
		}
	`)
	body := bytes.NewBuffer(request)
	w := httptest.NewRecorder()
	c := &web.C{Env: make(map[string]interface{})}
	r, err := http.NewRequest("POST", "/", body)

	if err != nil {
		t.Error(err)
	}

	r.Header = map[string][]string{
		"Content-Type": {"application/json"},
	}

	Request(c, TestHandler{}).ServeHTTP(w, r)
	paramsAsInterface, ok := c.Env["Params"]
	if !ok {
		t.Error("Expected params to be set into the context.")
	}

	params, ok := paramsAsInterface.(Params)
	if params == nil || !ok {
		t.Error("Expected params to be unmarshalled into the context.")
	}

	if c.Env["GojisonDecodeError"] != nil {
		t.Error("Expected params to be decoded without an error.")
	}

	if params.Get("one") != "1" {
		wrong(t, "Get on unmarshaled params", "1", params.Get("one"))
	}

	if params.GetP("nested").GetInt("two") != 2 {
		wrong(t, "GetP#GetInt on unmarshaled params", 2, params.GetP("nested").GetInt("two"))
	}
}

func TestRequestWithoutJSON(t *testing.T) {
	request := []byte{}
	body := bytes.NewBuffer(request)
	w := httptest.NewRecorder()
	c := &web.C{Env: make(map[string]interface{})}
	r, err := http.NewRequest("GET", "/", body)

	if err != nil {
		t.Error(err)
	}

	r.Header = map[string][]string{}

	Request(c, TestHandler{}).ServeHTTP(w, r)
	_, ok := c.Env["Params"]
	if ok {
		t.Error("Expected params to be empty when there is no application/json request.")
	}
}

func TestRequestWithInvalidBody(t *testing.T) {
	request := []byte(`
		{"one"}
	`)
	body := bytes.NewBuffer(request)
	w := httptest.NewRecorder()
	c := &web.C{Env: make(map[string]interface{})}
	r, err := http.NewRequest("POST", "/", body)

	if err != nil {
		t.Error(err)
	}

	r.Header = map[string][]string{
		"Content-Type": {"application/json"},
	}

	Request(c, TestHandler{}).ServeHTTP(w, r)
	_, ok := c.Env["Params"]
	if !ok {
		t.Error("Expected params to be set into the context.")
	}

	if c.Env["GojisonDecodeError"] == nil {
		t.Error("Expected to be an Error when decoding the params.")
	}
}

type TestHandler struct{}

func (th TestHandler) ServeHTTP(_ http.ResponseWriter, _ *http.Request) {
}
<commit_msg>Fix based on the new version of goji.<commit_after>package gojison

import (
	"bytes"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/zenazn/goji/web"
)

func init() {
}

func TestResponse(t *testing.T) {
	w := httptest.NewRecorder()
	r := &http.Request{}
	Response(TestHandler{}).ServeHTTP(w, r)
	if w.Header().Get("Content-Type") != "application/json" {
		t.Error("Expected content-type to be set to application/json")
	}
}

func TestRequest(t *testing.T) {
	request := []byte(`
		{
			"one": 1,
			"nested":{
				"two": 2
			}
		}
	`)
	body := bytes.NewBuffer(request)
	w := httptest.NewRecorder()
	c := &web.C{Env: make(map[interface{}]interface{})}
	r, err := http.NewRequest("POST", "/", body)

	if err != nil {
		t.Error(err)
	}

	r.Header = map[string][]string{
		"Content-Type": {"application/json"},
	}

	Request(c, TestHandler{}).ServeHTTP(w, r)
	paramsAsInterface, ok := c.Env["Params"]
	if !ok {
		t.Error("Expected params to be set into the context.")
	}

	params, ok := paramsAsInterface.(Params)
	if params == nil || !ok {
		t.Error("Expected params to be unmarshalled into the context.")
	}

	if c.Env["GojisonDecodeError"] != nil {
		t.Error("Expected params to be decoded without an error.")
	}

	if params.Get("one") != "1" {
		wrong(t, "Get on unmarshaled params", "1", params.Get("one"))
	}

	if params.GetP("nested").GetInt("two") != 2 {
		wrong(t, "GetP#GetInt on unmarshaled params", 2, params.GetP("nested").GetInt("two"))
	}
}

func TestRequestWithoutJSON(t *testing.T) {
	request := []byte{}
	body := bytes.NewBuffer(request)
	w := httptest.NewRecorder()
	c := &web.C{Env: make(map[interface{}]interface{})}
	r, err := http.NewRequest("GET", "/", body)

	if err != nil {
		t.Error(err)
	}

	r.Header = map[string][]string{}

	Request(c, TestHandler{}).ServeHTTP(w, r)
	_, ok := c.Env["Params"]
	if ok {
		t.Error("Expected params to be empty when there is no application/json request.")
	}
}

func TestRequestWithInvalidBody(t *testing.T) {
	request := []byte(`
		{"one"}
	`)
	body := bytes.NewBuffer(request)
	w := httptest.NewRecorder()
	c := &web.C{Env: make(map[interface{}]interface{})}
	r, err := http.NewRequest("POST", "/", body)

	if err != nil {
		t.Error(err)
	}

	r.Header = map[string][]string{
		"Content-Type": {"application/json"},
	}

	Request(c, TestHandler{}).ServeHTTP(w, r)
	_, ok := c.Env["Params"]
	if !ok {
		t.Error("Expected params to be set into the context.")
	}

	if c.Env["GojisonDecodeError"] == nil {
		t.Error("Expected to be an Error when decoding the params.")
	}
}

type TestHandler struct{}

func (th TestHandler) ServeHTTP(_ http.ResponseWriter, _ *http.Request) {
}
<|endoftext|>


<commit_before>package models

import (
	"database/sql"
	"time"

	"github.com/antihax/goesi"
	"github.com/guregu/null"
)

// Obtain an authenticated client from a stored access/refresh token.
func GetCRESTToken(characterID int64, tokenCharacterID int64) (*CRESTToken, error) {
	tok := &CRESTToken{}
	if err := database.QueryRowx(
		`SELECT expiry, tokenType, accessToken, refreshToken, tokenCharacterID, characterID, characterName
			FROM evedata.crestTokens
			WHERE characterID = ? AND tokenCharacterID = ?
			LIMIT 1`,
		characterID, tokenCharacterID).StructScan(tok); err != nil {

		return nil, err
	}

	return tok, nil
}

type CRESTToken struct {
	Expiry           time.Time   `db:"expiry" json:"expiry,omitempty"`
	CharacterID      int64       `db:"characterID" json:"characterID,omitempty"`
	TokenType        string      `db:"tokenType" json:"tokenType,omitempty"`
	TokenCharacterID int64       `db:"tokenCharacterID" json:"tokenCharacterID,omitempty"`
	CharacterName    string      `db:"characterName" json:"characterName,omitempty"`
	LastCode         int64       `db:"lastCode" json:"lastCode,omitempty"`
	LastStatus       null.String `db:"lastStatus" json:"lastStatus,omitempty"`
	AccessToken      string      `db:"accessToken" json:"accessToken,omitempty"`
	RefreshToken     string      `db:"refreshToken" json:"refreshToken,omitempty"`
	Scopes           string      `db:"scopes" json:"scopes,omitempty"`
}

// [BENCHMARK] 0.000 sec / 0.000 sec
func GetCRESTTokens(characterID int64) ([]CRESTToken, error) {
	tokens := []CRESTToken{}
	if err := database.Select(&tokens, `
		SELECT characterID, tokenCharacterID, characterName, lastCode, lastStatus, scopes
		FROM evedata.crestTokens
		WHERE characterID = ?;`, characterID); err != nil {

		return nil, err
	}
	return tokens, nil
}

// [BENCHMARK] TODO
func GetCharacterIDByName(character string) (int64, error) {
	var id int64
	if err := database.Get(&id, `
		SELECT characterID
		FROM evedata.characters C
		WHERE C.name = ? LIMIT 1;`, character); err != nil && err != sql.ErrNoRows {
		return id, err
	}
	return id, nil
}

type CursorCharacter struct {
	CursorCharacterID   int64  `db:"cursorCharacterID" json:"cursorCharacterID"`
	CursorCharacterName string `db:"cursorCharacterName" json:"cursorCharacterName"`
}

// [BENCHMARK] TODO
func GetCursorCharacter(characterID int64) (CursorCharacter, error) {
	cursor := CursorCharacter{}

	if err := database.Get(&cursor, `
		SELECT cursorCharacterID, T.characterName AS cursorCharacterName
		FROM evedata.cursorCharacter C
		INNER JOIN evedata.crestTokens T ON C.cursorCharacterID = T.tokenCharacterID AND C.characterID = T.characterID
		WHERE C.characterID = ?;`, characterID); err != nil {
		return cursor, err
	}
	return cursor, nil
}

// [BENCHMARK] TODO
func SetCursorCharacter(characterID int64, cursorCharacterID int64) error {
	if _, err := database.Exec(`
	INSERT INTO evedata.cursorCharacter (characterID, cursorCharacterID)
		SELECT characterID, tokenCharacterID AS cursorCharacterID
		FROM evedata.crestTokens WHERE characterID = ? AND tokenCharacterID = ? LIMIT 1
	ON DUPLICATE KEY UPDATE cursorCharacterID = VALUES(cursorCharacterID)
		;`, characterID, cursorCharacterID); err != nil {
		return err
	}
	return nil
}

func SetTokenError(characterID int64, tokenCharacterID int64, code int, status string, req []byte, res []byte) error {
	if _, err := database.Exec(`
		UPDATE evedata.crestTokens SET lastCode = ?, lastStatus = ?, request = ?, response = ?
		WHERE characterID = ? AND tokenCharacterID = ? `,
		code, status, req, res, characterID, tokenCharacterID); err != nil {
		return err
	}
	return nil
}

func AddCRESTToken(characterID int64, tokenCharacterID int64, characterName string, tok *goesi.CRESTToken, scopes string) error {
	if _, err := database.Exec(`
		INSERT INTO evedata.crestTokens	(characterID, tokenCharacterID, accessToken, refreshToken, expiry, tokenType, characterName, scopes, lastStatus)
			VALUES		(?,?,?,?,?,?,?,?,"Unused")
			ON DUPLICATE KEY UPDATE
				accessToken 	= VALUES(accessToken),
				refreshToken 	= VALUES(refreshToken),
				expiry 			= VALUES(expiry),
				tokenType 		= VALUES(tokenType),
				scopes 		= VALUES(scopes),
				lastStatus		= "Unused"`,
		characterID, tokenCharacterID, tok.AccessToken, tok.RefreshToken, tok.Expiry, tok.TokenType, characterName, scopes); err != nil {
		return err
	}

	return nil
}

func DeleteCRESTToken(characterID int64, tokenCharacterID int64) error {
	if _, err := database.Exec(`DELETE FROM evedata.crestTokens WHERE characterID = ? AND tokenCharacterID = ? LIMIT 1`,
		characterID, tokenCharacterID); err != nil {

		return err
	}
	return nil
}

func UpdateCharacter(characterID int32, name string, bloodlineID int32, ancestryID int32, corporationID int32, allianceID int32,
	race int32, gender string, securityStatus float32, cacheUntil time.Time) error {
	cacheUntil = time.Now().UTC().Add(time.Hour * 24 * 5)
	if _, err := database.Exec(`
		INSERT INTO evedata.characters (characterID,name,bloodlineID,ancestryID,corporationID,allianceID,race,gender,securityStatus,updated,cacheUntil)
			VALUES(?,?,?,?,?,?,evedata.raceByID(?),?,?,UTC_TIMESTAMP(),?)
			ON DUPLICATE KEY UPDATE
			corporationID=VALUES(corporationID), gender=VALUES(gender), allianceID=VALUES(allianceID), securityStatus=VALUES(securityStatus), updated = UTC_TIMESTAMP(), cacheUntil=VALUES(cacheUntil)
	`, characterID, name, bloodlineID, ancestryID, corporationID, allianceID, race, gender, securityStatus, cacheUntil); err != nil {
		return err
	}
	return nil
}

func UpdateCorporationHistory(characterID int32, corporationID int32, recordID int32, startDate time.Time) error {
	if _, err := database.Exec(`
		INSERT INTO evedata.corporationHistory (characterID,startDate,recordID,corporationID)
			VALUES(?,?,?,?)
			ON DUPLICATE KEY UPDATE
			startDate=VALUES(startDate)
	`, characterID, startDate, recordID, corporationID); err != nil {
		return err
	}
	return nil
}

type Character struct {
	CharacterID     int64       `db:"characterID" json:"characterID"`
	CharacterName   string      `db:"characterName" json:"characterName"`
	CorporationID   int64       `db:"corporationID" json:"corporationID"`
	CorporationName string      `db:"corporationName" json:"corporationName"`
	AllianceID      int64       `db:"allianceID" json:"allianceID"`
	AllianceName    null.String `db:"allianceName" json:"allianceName"`
	Race            string      `db:"race" json:"race"`
	SecurityStatus  float64     `db:"securityStatus" json:"securityStatus"`
}

// Obtain Character information by ID.
// [BENCHMARK] 0.000 sec / 0.000 sec
func GetCharacter(id int64) (*Character, error) {
	ref := Character{}
	if err := database.QueryRowx(`
		SELECT
			characterID,
			C.name AS characterName,
		    C.corporationID,
		    IFNULL("Unknown Name", Co.name) AS corporationName,
		    C.allianceID,
		    Al.name AS allianceName,
		    race,
		    securityStatus

		FROM evedata.characters C
		LEFT OUTER JOIN evedata.corporations Co ON Co.corporationID = C.corporationID
		LEFT OUTER JOIN evedata.alliances Al ON Al.allianceID = C.allianceID
		WHERE characterID = ?
		LIMIT 1`, id).StructScan(&ref); err != nil {
		return nil, err
	}
	return &ref, nil
}

type CorporationHistory struct {
	CorporationID   int64     `db:"corporationID" json:"id"`
	CorporationName string    `db:"corporationName" json:"name"`
	StartDate       time.Time `db:"startDate" json:"startDate"`
	Type            string    `db:"type" json:"type"`
}

// Obtain Character information by ID.
// [BENCHMARK] 0.000 sec / 0.000 sec
func GetCorporationHistory(id int64) ([]CorporationHistory, error) {
	ref := []CorporationHistory{}
	if err := database.Select(&ref, `
		SELECT
			C.corporationID,
			C.name AS corporationName,
			startDate

		FROM evedata.corporationHistory H
		INNER JOIN evedata.corporations C ON C.corporationID = H.corporationID
		WHERE H.characterID = ?
		ORDER BY startDate DESC
		`, id); err != nil {
		return nil, err
	}
	for i := range ref {
		ref[i].Type = "corporation"
	}
	return ref, nil
}
<commit_msg>Correct parameter order<commit_after>package models

import (
	"database/sql"
	"time"

	"github.com/antihax/goesi"
	"github.com/guregu/null"
)

// Obtain an authenticated client from a stored access/refresh token.
func GetCRESTToken(characterID int64, tokenCharacterID int64) (*CRESTToken, error) {
	tok := &CRESTToken{}
	if err := database.QueryRowx(
		`SELECT expiry, tokenType, accessToken, refreshToken, tokenCharacterID, characterID, characterName
			FROM evedata.crestTokens
			WHERE characterID = ? AND tokenCharacterID = ?
			LIMIT 1`,
		characterID, tokenCharacterID).StructScan(tok); err != nil {

		return nil, err
	}

	return tok, nil
}

type CRESTToken struct {
	Expiry           time.Time   `db:"expiry" json:"expiry,omitempty"`
	CharacterID      int64       `db:"characterID" json:"characterID,omitempty"`
	TokenType        string      `db:"tokenType" json:"tokenType,omitempty"`
	TokenCharacterID int64       `db:"tokenCharacterID" json:"tokenCharacterID,omitempty"`
	CharacterName    string      `db:"characterName" json:"characterName,omitempty"`
	LastCode         int64       `db:"lastCode" json:"lastCode,omitempty"`
	LastStatus       null.String `db:"lastStatus" json:"lastStatus,omitempty"`
	AccessToken      string      `db:"accessToken" json:"accessToken,omitempty"`
	RefreshToken     string      `db:"refreshToken" json:"refreshToken,omitempty"`
	Scopes           string      `db:"scopes" json:"scopes,omitempty"`
}

// [BENCHMARK] 0.000 sec / 0.000 sec
func GetCRESTTokens(characterID int64) ([]CRESTToken, error) {
	tokens := []CRESTToken{}
	if err := database.Select(&tokens, `
		SELECT characterID, tokenCharacterID, characterName, lastCode, lastStatus, scopes
		FROM evedata.crestTokens
		WHERE characterID = ?;`, characterID); err != nil {

		return nil, err
	}
	return tokens, nil
}

// [BENCHMARK] TODO
func GetCharacterIDByName(character string) (int64, error) {
	var id int64
	if err := database.Get(&id, `
		SELECT characterID
		FROM evedata.characters C
		WHERE C.name = ? LIMIT 1;`, character); err != nil && err != sql.ErrNoRows {
		return id, err
	}
	return id, nil
}

type CursorCharacter struct {
	CursorCharacterID   int64  `db:"cursorCharacterID" json:"cursorCharacterID"`
	CursorCharacterName string `db:"cursorCharacterName" json:"cursorCharacterName"`
}

// [BENCHMARK] TODO
func GetCursorCharacter(characterID int64) (CursorCharacter, error) {
	cursor := CursorCharacter{}

	if err := database.Get(&cursor, `
		SELECT cursorCharacterID, T.characterName AS cursorCharacterName
		FROM evedata.cursorCharacter C
		INNER JOIN evedata.crestTokens T ON C.cursorCharacterID = T.tokenCharacterID AND C.characterID = T.characterID
		WHERE C.characterID = ?;`, characterID); err != nil {
		return cursor, err
	}
	return cursor, nil
}

// [BENCHMARK] TODO
func SetCursorCharacter(characterID int64, cursorCharacterID int64) error {
	if _, err := database.Exec(`
	INSERT INTO evedata.cursorCharacter (characterID, cursorCharacterID)
		SELECT characterID, tokenCharacterID AS cursorCharacterID
		FROM evedata.crestTokens WHERE characterID = ? AND tokenCharacterID = ? LIMIT 1
	ON DUPLICATE KEY UPDATE cursorCharacterID = VALUES(cursorCharacterID)
		;`, characterID, cursorCharacterID); err != nil {
		return err
	}
	return nil
}

func SetTokenError(characterID int64, tokenCharacterID int64, code int, status string, req []byte, res []byte) error {
	if _, err := database.Exec(`
		UPDATE evedata.crestTokens SET lastCode = ?, lastStatus = ?, request = ?, response = ?
		WHERE characterID = ? AND tokenCharacterID = ? `,
		code, status, req, res, characterID, tokenCharacterID); err != nil {
		return err
	}
	return nil
}

func AddCRESTToken(characterID int64, tokenCharacterID int64, characterName string, tok *goesi.CRESTToken, scopes string) error {
	if _, err := database.Exec(`
		INSERT INTO evedata.crestTokens	(characterID, tokenCharacterID, accessToken, refreshToken, expiry, tokenType, characterName, scopes, lastStatus)
			VALUES		(?,?,?,?,?,?,?,?,"Unused")
			ON DUPLICATE KEY UPDATE
				accessToken 	= VALUES(accessToken),
				refreshToken 	= VALUES(refreshToken),
				expiry 			= VALUES(expiry),
				tokenType 		= VALUES(tokenType),
				scopes 		= VALUES(scopes),
				lastStatus		= "Unused"`,
		characterID, tokenCharacterID, tok.AccessToken, tok.RefreshToken, tok.Expiry, tok.TokenType, characterName, scopes); err != nil {
		return err
	}

	return nil
}

func DeleteCRESTToken(characterID int64, tokenCharacterID int64) error {
	if _, err := database.Exec(`DELETE FROM evedata.crestTokens WHERE characterID = ? AND tokenCharacterID = ? LIMIT 1`,
		characterID, tokenCharacterID); err != nil {

		return err
	}
	return nil
}

func UpdateCharacter(characterID int32, name string, bloodlineID int32, ancestryID int32, corporationID int32, allianceID int32,
	race int32, gender string, securityStatus float32, cacheUntil time.Time) error {
	cacheUntil = time.Now().UTC().Add(time.Hour * 24 * 5)
	if _, err := database.Exec(`
		INSERT INTO evedata.characters (characterID,name,bloodlineID,ancestryID,corporationID,allianceID,race,gender,securityStatus,updated,cacheUntil)
			VALUES(?,?,?,?,?,?,evedata.raceByID(?),?,?,UTC_TIMESTAMP(),?)
			ON DUPLICATE KEY UPDATE
			corporationID=VALUES(corporationID), gender=VALUES(gender), allianceID=VALUES(allianceID), securityStatus=VALUES(securityStatus), updated = UTC_TIMESTAMP(), cacheUntil=VALUES(cacheUntil)
	`, characterID, name, bloodlineID, ancestryID, corporationID, allianceID, race, gender, securityStatus, cacheUntil); err != nil {
		return err
	}
	return nil
}

func UpdateCorporationHistory(characterID int32, corporationID int32, recordID int32, startDate time.Time) error {
	if _, err := database.Exec(`
		INSERT INTO evedata.corporationHistory (characterID,startDate,recordID,corporationID)
			VALUES(?,?,?,?)
			ON DUPLICATE KEY UPDATE
			startDate=VALUES(startDate)
	`, characterID, startDate, recordID, corporationID); err != nil {
		return err
	}
	return nil
}

type Character struct {
	CharacterID     int64       `db:"characterID" json:"characterID"`
	CharacterName   string      `db:"characterName" json:"characterName"`
	CorporationID   int64       `db:"corporationID" json:"corporationID"`
	CorporationName string      `db:"corporationName" json:"corporationName"`
	AllianceID      int64       `db:"allianceID" json:"allianceID"`
	AllianceName    null.String `db:"allianceName" json:"allianceName"`
	Race            string      `db:"race" json:"race"`
	SecurityStatus  float64     `db:"securityStatus" json:"securityStatus"`
}

// Obtain Character information by ID.
// [BENCHMARK] 0.000 sec / 0.000 sec
func GetCharacter(id int64) (*Character, error) {
	ref := Character{}
	if err := database.QueryRowx(`
		SELECT
			characterID,
			C.name AS characterName,
		    C.corporationID,
		    IFNULL(Co.name, "Unknown Name") AS corporationName,
		    C.allianceID,
		    Al.name AS allianceName,
		    race,
		    securityStatus

		FROM evedata.characters C
		LEFT OUTER JOIN evedata.corporations Co ON Co.corporationID = C.corporationID
		LEFT OUTER JOIN evedata.alliances Al ON Al.allianceID = C.allianceID
		WHERE characterID = ?
		LIMIT 1`, id).StructScan(&ref); err != nil {
		return nil, err
	}
	return &ref, nil
}

type CorporationHistory struct {
	CorporationID   int64     `db:"corporationID" json:"id"`
	CorporationName string    `db:"corporationName" json:"name"`
	StartDate       time.Time `db:"startDate" json:"startDate"`
	Type            string    `db:"type" json:"type"`
}

// Obtain Character information by ID.
// [BENCHMARK] 0.000 sec / 0.000 sec
func GetCorporationHistory(id int64) ([]CorporationHistory, error) {
	ref := []CorporationHistory{}
	if err := database.Select(&ref, `
		SELECT
			C.corporationID,
			C.name AS corporationName,
			startDate

		FROM evedata.corporationHistory H
		INNER JOIN evedata.corporations C ON C.corporationID = H.corporationID
		WHERE H.characterID = ?
		ORDER BY startDate DESC
		`, id); err != nil {
		return nil, err
	}
	for i := range ref {
		ref[i].Type = "corporation"
	}
	return ref, nil
}
<|endoftext|>