<commit_before>package golet

import (
	"bufio"
	"context"
	"errors"
	"fmt"
	"io"
	"os"
	"os/exec"
	"os/signal"
	"runtime"
	"sync"
	"syscall"
	"time"

	"github.com/Code-Hex/golet/internal/port"
	colorable "github.com/mattn/go-colorable"
	"github.com/robfig/cron"
)

type color int

const (
	red color = iota // + 31
	green
	yellow
	blue
	magenta
	cyan

	colornum int = 5
)

// config is main struct.
// struct comments from http://search.cpan.org/dist/Proclet/lib/Proclet.pm
// Proclet is a great module!!
type config struct {
	interval   time.Duration // interval in seconds between spawning services unless a service exits abnormally.
	color      bool          // colored log.
	logger     io.Writer     // sets the output destination file. use stderr by default.
	logWorker  bool          // enable worker for format logs. If disabled this option, cannot use logger opt too.
	execNotice bool          // enable start and exec notice message like: `16:38:12 worker.1 | Start callback: worker``.

	services   []Service
	wg         sync.WaitGroup
	once       sync.Once
	cancel     func()
	ctx        context.Context
	serviceNum int
	tags       map[string]bool
	cron       *cron.Cron
}

var shell []string

func init() {
	if runtime.GOOS == "windows" {
		path, err := exec.LookPath("cmd")
		if err != nil {
			panic("Could not find `cmd` command")
		}
		shell = []string{path, "/c"}
	} else {
		path, err := exec.LookPath("bash")
		if err != nil {
			panic("Could not find `bash` command")
		}
		shell = []string{path, "-c"}
	}
}

// Runner interface have methods for configuration and to run services.
type Runner interface {
	SetInterval(time.Duration)
	EnableColor()
	SetLogger(io.Writer)
	DisableLogger()
	DisableExecNotice()
	Env(map[string]string) error
	Add(...Service) error
	Run() error
}

// for settings
// SetInterval can specify the interval at which the command is executed.
func (c *config) SetInterval(t time.Duration) { c.interval = t }

// EnableColor can output colored log.
func (c *config) EnableColor() { c.color = true }

// SetLogger can specify the *os.File
// for example in https://github.com/lestrrat/go-file-rotatelogs
/*
      logf, _ := rotatelogs.New(
  	    "/path/to/access_log.%Y%m%d%H%M",
  	    rotatelogs.WithLinkName("/path/to/access_log"),
  	    rotatelogs.WithMaxAge(24 * time.Hour),
  	    rotatelogs.WithRotationTime(time.Hour),
      )

	  golet.New(context.Background()).SetLogger(logf)
*/
func (c *config) SetLogger(f io.Writer) { c.logger = f }

// DisableLogger is prevent to output log
func (c *config) DisableLogger() { c.logWorker = false }

// DisableExecNotice is disable execute notifications
func (c *config) DisableExecNotice() { c.execNotice = false }

// New to create struct of golet.
func New(c context.Context) Runner {
	ctx, cancel := context.WithCancel(c)
	return &config{
		interval:   0,
		color:      false,
		logger:     colorable.NewColorableStderr(),
		logWorker:  true,
		execNotice: true,

		ctx:    ctx,
		cancel: cancel,
		tags:   map[string]bool{},
		cron:   cron.New(),
	}
}

// Env can add temporary environment variables.
func (c *config) Env(envs map[string]string) error {
	for k := range envs {
		if e := os.Setenv(k, envs[k]); e != nil {
			return e
		}
	}
	return nil
}

// Add can add runnable services
func (c *config) Add(services ...Service) error {
	for _, service := range services {
		c.serviceNum++

		if service.Tag == "" {
			service.Tag = fmt.Sprintf("%d", c.serviceNum)
		}

		if service.Worker <= 0 {
			service.Worker = 1
		} else if service.Worker > 100 {
			service.Worker = 100
		}

		if _, ok := c.tags[service.Tag]; ok {
			return errors.New("tag: " + service.Tag + " is already exists")
		}
		c.tags[service.Tag] = true

		n, err := port.GetPort()
		if err != nil {
			return err
		}

		service.tmpPort = n
		service.color = color(c.serviceNum%colornum + 32)

		c.services = append(c.services, service)
	}
	return nil
}

// Run just like the name.
func (c *config) Run() error {
	services := make(map[string]Service)

	order := make([]string, 0, c.calcCapacitySize())

	// Assign services.
	if err := c.assign(&order, services); err != nil {
		return err
	}

	chps := make(chan *os.Process, 1)
	signals := make(chan os.Signal, 1)
	signal.Notify(signals, syscall.SIGHUP, syscall.SIGTERM, syscall.SIGINT)

	go c.waitSignals(signals, chps, len(order))

	// Invoke workers.
	for _, sid := range order {
		service := services[sid]
		if service.isExecute() {
			// Execute the command with cron or goroutine
			if service.isCron() {
				c.addCmd(service, chps)
			} else {
				c.wg.Add(1)

				go func() {
					defer func() {
						service.ctx.Close()
						c.wg.Done()
					}()

					for {
						// Notify you have executed the command
						if c.execNotice {
							service.Printf("Exec command: %s\n", service.Exec)
						}
						select {
						case <-c.ctx.Done():
							return
						default:
							run(service.prepare(), chps)
						}
					}
				}()
			}
		}

		if service.isCode() {
			// Run callback with cron or goroutine
			if service.isCron() {
				c.addTask(service)
			} else {
				c.wg.Add(1)

				go func() {
					defer func() {
						service.ctx.Close()
						c.wg.Done()
					}()
					// If this callback is dead, we should restart it. (like a supervisor)
					// So, this loop for that.
					for {
						// Notify you have run the callback
						if c.execNotice {
							service.Printf("Callback: %s\n", service.Tag)
						}
						select {
						case <-c.ctx.Done():
							return
						default:
							service.Code(c.ctx, service.ctx)
						}
					}
				}()
			}
		}

		// Enable log worker if logWorker is true.
		if c.logWorker && (service.Code != nil || service.Exec != "") {
			rd := service.reader
			go c.logging(bufio.NewScanner(rd), sid, service.color)
		}

		// When the task is cron, it does not cause wait time.
		if service.Every == "" {
			time.Sleep(c.interval)
		}
	}

	c.wait(chps, signals)

	return nil
}

// Calculate of the number of workers.
func (c *config) calcCapacitySize() (cap int) {
	for _, service := range c.services {
		cap += service.Worker
	}
	return
}

// Assign the service ID.
// It also make `order` slice to keep key order of `map[string]Service`.
func (c *config) assign(order *[]string, services map[string]Service) error {
	for _, service := range c.services {
		worker := service.Worker
		for i := 1; i <= worker; i++ {
			s := service
			if err := s.createContext(i); err != nil {
				return err
			}
			sid := fmt.Sprintf("%s.%d", s.Tag, i)
			services[sid] = s
			*order = append(*order, sid)
		}
	}
	return nil
}

// Receive process ID to be executed. or
// It traps the signal relate to parent process. sends a signal to the received process ID.
func (c *config) waitSignals(signals <-chan os.Signal, chps <-chan *os.Process, cap int) {
	procs := make([]*os.Process, 0, cap)
Loop:
	for {
		select {
		case proc := <-chps:
			// Replace the used process(nil) with the newly generated process.
			// This run to reduce the memory allocation frequency.
			for i, p := range procs {
				if p == nil {
					procs[i] = proc
					continue Loop
				}
			}
			// If not used all processes, allocated newly.
			procs = append(procs, proc)
		case s := <-signals:
			switch s {
			case syscall.SIGTERM, syscall.SIGHUP:
				c.once.Do(func() {
					if c.cancel != nil {
						c.cancel()
					}
					time.Sleep(time.Second * 1)
				})
				sendSignal2Procs(syscall.SIGTERM, procs)
			case syscall.SIGINT:
				sendSignal2Procs(syscall.SIGINT, procs)
			}
		case <-c.ctx.Done():
			c.cron.Stop()
			return
		}
	}
}

// sendSignal2Procs can send signal and replace os.Process struct of the terminated process with nil
func sendSignal2Procs(sig syscall.Signal, procs []*os.Process) {
	for i, p := range procs {
		if p != nil {
			p.Signal(sig)
			// In case of error, the process has already finished.
			if _, err := p.Wait(); err != nil {
				procs[i] = nil
			}
		}
	}
}

// Execute the command and send its process ID.
func run(c *exec.Cmd, chps chan<- *os.Process) error {
	if err := c.Start(); err != nil {
		return err
	}
	chps <- c.Process
	return c.Wait()
}

// Add a task to execute the command to cron.
func (c *config) addCmd(s Service, chps chan<- *os.Process) {
	// Notify you have executed the command
	if c.execNotice {
		s.Printf("Exec command: %s\n", s.Exec)
	}
	c.cron.AddFunc(s.Every, func() {
		run(s.prepare(), chps)
	})
}

// Add a task to execute the code block to cron.
func (c *config) addTask(s Service) {
	// Notify you have run the callback
	if c.execNotice {
		s.Printf("Callback: %s\n", s.Tag)
	}

	c.cron.AddFunc(s.Every, func() {
		s.Code(c.ctx, s.ctx)
	})
}

// Wait services
func (c *config) wait(chps chan<- *os.Process, sig chan<- os.Signal) {
	c.cron.Start()
	c.wg.Wait()
	signal.Stop(sig)
}

// Logging
func (c *config) logging(sc *bufio.Scanner, sid string, clr color) {
	for sc.Scan() {
		hour, min, sec := time.Now().Clock()
		if c.color {
			fmt.Fprintf(c.logger, "\x1b[%dm%02d:%02d:%02d %-10s |\x1b[0m %s\n",
				clr,
				hour, min, sec, sid,
				sc.Text(),
			)
		} else {
			fmt.Fprintf(c.logger, "%02d:%02d:%02d %-10s | %s\n", hour, min, sec, sid, sc.Text())
		}
	}
}
<commit_msg>Removed some lines<commit_after>package golet

import (
	"bufio"
	"context"
	"errors"
	"fmt"
	"io"
	"os"
	"os/exec"
	"os/signal"
	"runtime"
	"sync"
	"syscall"
	"time"

	"github.com/Code-Hex/golet/internal/port"
	colorable "github.com/mattn/go-colorable"
	"github.com/robfig/cron"
)

type color int

const (
	red color = iota // + 31
	green
	yellow
	blue
	magenta
	cyan

	colornum int = 5
)

// config is main struct.
// struct comments from http://search.cpan.org/dist/Proclet/lib/Proclet.pm
// Proclet is a great module!!
type config struct {
	interval   time.Duration // interval in seconds between spawning services unless a service exits abnormally.
	color      bool          // colored log.
	logger     io.Writer     // sets the output destination file. use stderr by default.
	logWorker  bool          // enable worker for format logs. If disabled this option, cannot use logger opt too.
	execNotice bool          // enable start and exec notice message like: `16:38:12 worker.1 | Start callback: worker``.

	services   []Service
	wg         sync.WaitGroup
	once       sync.Once
	cancel     func()
	ctx        context.Context
	serviceNum int
	tags       map[string]bool
	cron       *cron.Cron
}

var shell []string

func init() {
	if runtime.GOOS == "windows" {
		path, err := exec.LookPath("cmd")
		if err != nil {
			panic("Could not find `cmd` command")
		}
		shell = []string{path, "/c"}
	} else {
		path, err := exec.LookPath("bash")
		if err != nil {
			panic("Could not find `bash` command")
		}
		shell = []string{path, "-c"}
	}
}

// Runner interface have methods for configuration and to run services.
type Runner interface {
	SetInterval(time.Duration)
	EnableColor()
	SetLogger(io.Writer)
	DisableLogger()
	DisableExecNotice()
	Env(map[string]string) error
	Add(...Service) error
	Run() error
}

// for settings
// SetInterval can specify the interval at which the command is executed.
func (c *config) SetInterval(t time.Duration) { c.interval = t }

// EnableColor can output colored log.
func (c *config) EnableColor() { c.color = true }

// SetLogger can specify the *os.File
// for example in https://github.com/lestrrat/go-file-rotatelogs
/*
      logf, _ := rotatelogs.New(
  	    "/path/to/access_log.%Y%m%d%H%M",
  	    rotatelogs.WithLinkName("/path/to/access_log"),
  	    rotatelogs.WithMaxAge(24 * time.Hour),
  	    rotatelogs.WithRotationTime(time.Hour),
      )

	  golet.New(context.Background()).SetLogger(logf)
*/
func (c *config) SetLogger(f io.Writer) { c.logger = f }

// DisableLogger is prevent to output log
func (c *config) DisableLogger() { c.logWorker = false }

// DisableExecNotice is disable execute notifications
func (c *config) DisableExecNotice() { c.execNotice = false }

// New to create struct of golet.
func New(c context.Context) Runner {
	ctx, cancel := context.WithCancel(c)
	return &config{
		interval:   0,
		color:      false,
		logger:     colorable.NewColorableStderr(),
		logWorker:  true,
		execNotice: true,

		ctx:    ctx,
		cancel: cancel,
		tags:   map[string]bool{},
		cron:   cron.New(),
	}
}

// Env can add temporary environment variables.
func (c *config) Env(envs map[string]string) error {
	for k := range envs {
		if e := os.Setenv(k, envs[k]); e != nil {
			return e
		}
	}
	return nil
}

// Add can add runnable services
func (c *config) Add(services ...Service) error {
	for _, service := range services {
		c.serviceNum++
		if service.Tag == "" {
			service.Tag = fmt.Sprintf("%d", c.serviceNum)
		}
		if service.Worker <= 0 {
			service.Worker = 1
		}
		if _, ok := c.tags[service.Tag]; ok {
			return errors.New("tag: " + service.Tag + " is already exists")
		}
		c.tags[service.Tag] = true

		n, err := port.GetPort()
		if err != nil {
			return err
		}

		service.tmpPort = n
		service.color = color(c.serviceNum%colornum + 32)

		c.services = append(c.services, service)
	}
	return nil
}

// Run just like the name.
func (c *config) Run() error {
	services := make(map[string]Service)

	order := make([]string, 0, c.calcCapacitySize())

	// Assign services.
	if err := c.assign(&order, services); err != nil {
		return err
	}

	chps := make(chan *os.Process, 1)
	signals := make(chan os.Signal, 1)
	signal.Notify(signals, syscall.SIGHUP, syscall.SIGTERM, syscall.SIGINT)

	go c.waitSignals(signals, chps, len(order))

	// Invoke workers.
	for _, sid := range order {
		service := services[sid]
		if service.isExecute() {
			// Execute the command with cron or goroutine
			if service.isCron() {
				c.addCmd(service, chps)
			} else {
				c.wg.Add(1)
				go func() {
					defer func() {
						service.ctx.Close()
						c.wg.Done()
					}()
					for {
						// Notify you have executed the command
						if c.execNotice {
							service.Printf("Exec command: %s\n", service.Exec)
						}
						select {
						case <-c.ctx.Done():
							return
						default:
							run(service.prepare(), chps)
						}
					}
				}()
			}
		}

		if service.isCode() {
			// Run callback with cron or goroutine
			if service.isCron() {
				c.addTask(service)
			} else {
				c.wg.Add(1)
				go func() {
					defer func() {
						service.ctx.Close()
						c.wg.Done()
					}()
					// If this callback is dead, we should restart it. (like a supervisor)
					// So, this loop for that.
					for {
						// Notify you have run the callback
						if c.execNotice {
							service.Printf("Callback: %s\n", service.Tag)
						}
						select {
						case <-c.ctx.Done():
							return
						default:
							service.Code(c.ctx, service.ctx)
						}
					}
				}()
			}
		}
		// Enable log worker if logWorker is true.
		if c.logWorker && (service.Code != nil || service.Exec != "") {
			rd := service.reader
			go c.logging(bufio.NewScanner(rd), sid, service.color)
		}
		// When the task is cron, it does not cause wait time.
		if service.Every == "" {
			time.Sleep(c.interval)
		}
	}

	c.wait(chps, signals)

	return nil
}

// Calculate of the number of workers.
func (c *config) calcCapacitySize() (cap int) {
	for _, service := range c.services {
		cap += service.Worker
	}
	return
}

// Assign the service ID.
// It also make `order` slice to keep key order of `map[string]Service`.
func (c *config) assign(order *[]string, services map[string]Service) error {
	for _, service := range c.services {
		worker := service.Worker
		for i := 1; i <= worker; i++ {
			s := service
			if err := s.createContext(i); err != nil {
				return err
			}
			sid := fmt.Sprintf("%s.%d", s.Tag, i)
			services[sid] = s
			*order = append(*order, sid)
		}
	}
	return nil
}

// Receive process ID to be executed. or
// It traps the signal relate to parent process. sends a signal to the received process ID.
func (c *config) waitSignals(signals <-chan os.Signal, chps <-chan *os.Process, cap int) {
	procs := make([]*os.Process, 0, cap)
Loop:
	for {
		select {
		case proc := <-chps:
			// Replace the used process(nil) with the newly generated process.
			// This run to reduce the memory allocation frequency.
			for i, p := range procs {
				if p == nil {
					procs[i] = proc
					continue Loop
				}
			}
			// If not used all processes, allocated newly.
			procs = append(procs, proc)
		case s := <-signals:
			switch s {
			case syscall.SIGTERM, syscall.SIGHUP:
				c.once.Do(func() {
					if c.cancel != nil {
						c.cancel()
					}
					time.Sleep(time.Second * 1)
				})
				sendSignal2Procs(syscall.SIGTERM, procs)
			case syscall.SIGINT:
				sendSignal2Procs(syscall.SIGINT, procs)
			}
		case <-c.ctx.Done():
			c.cron.Stop()
			return
		}
	}
}

// sendSignal2Procs can send signal and replace os.Process struct of the terminated process with nil
func sendSignal2Procs(sig syscall.Signal, procs []*os.Process) {
	for i, p := range procs {
		if p != nil {
			p.Signal(sig)
			// In case of error, the process has already finished.
			if _, err := p.Wait(); err != nil {
				procs[i] = nil
			}
		}
	}
}

// Execute the command and send its process ID.
func run(c *exec.Cmd, chps chan<- *os.Process) error {
	if err := c.Start(); err != nil {
		return err
	}
	chps <- c.Process
	return c.Wait()
}

// Add a task to execute the command to cron.
func (c *config) addCmd(s Service, chps chan<- *os.Process) {
	// Notify you have executed the command
	if c.execNotice {
		s.Printf("Exec command: %s\n", s.Exec)
	}
	c.cron.AddFunc(s.Every, func() {
		run(s.prepare(), chps)
	})
}

// Add a task to execute the code block to cron.
func (c *config) addTask(s Service) {
	// Notify you have run the callback
	if c.execNotice {
		s.Printf("Callback: %s\n", s.Tag)
	}
	c.cron.AddFunc(s.Every, func() {
		s.Code(c.ctx, s.ctx)
	})
}

// Wait services
func (c *config) wait(chps chan<- *os.Process, sig chan<- os.Signal) {
	c.cron.Start()
	c.wg.Wait()
	signal.Stop(sig)
}

// Logging
func (c *config) logging(sc *bufio.Scanner, sid string, clr color) {
	for sc.Scan() {
		hour, min, sec := time.Now().Clock()
		if c.color {
			fmt.Fprintf(c.logger, "\x1b[%dm%02d:%02d:%02d %-10s |\x1b[0m %s\n",
				clr,
				hour, min, sec, sid,
				sc.Text(),
			)
		} else {
			fmt.Fprintf(c.logger, "%02d:%02d:%02d %-10s | %s\n", hour, min, sec, sid, sc.Text())
		}
	}
}
<|endoftext|>


<commit_before>package gorma

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"github.com/raphael/goa/design"
	"github.com/raphael/goa/goagen/codegen"
	"gopkg.in/alecthomas/kingpin.v2"
)

// Generator is the application code generator.
type Generator struct {
	genfiles []string
}

// Generate is the generator entry point called by the meta generator.
func Generate(api *design.APIDefinition) ([]string, error) {
	g, err := NewGenerator()
	if err != nil {
		return nil, err
	}
	return g.Generate(api)
}

// NewGenerator returns the application code generator.
func NewGenerator() (*Generator, error) {
	return new(Generator), nil
}

// Generate produces the skeleton main.
func (g *Generator) Generate(api *design.APIDefinition) ([]string, error) {

	os.RemoveAll(ModelDir() + "*genmodel.go")
	os.MkdirAll(ModelDir(), 0755)
	app := kingpin.New("Model generator", "model generator")
	codegen.RegisterFlags(app)
	_, err := app.Parse(os.Args[1:])
	if err != nil {
		panic(err)
	}
	var outPkg string
	// going to hell for this == HELP Wanted (windows)
	outPkg = codegen.DesignPackagePath[0:strings.LastIndex(codegen.DesignPackagePath, "/")]
	if err != nil {
		panic(err)
	}
	outPkg = strings.TrimPrefix(outPkg, "src/")
	appPkg := filepath.Join(outPkg, "app")
	imports := []*codegen.ImportSpec{
		codegen.SimpleImport(appPkg),
		codegen.SimpleImport("github.com/jinzhu/gorm"),
		codegen.SimpleImport("github.com/jinzhu/copier"),
		codegen.SimpleImport("time"),
	}

	rbacimports := []*codegen.ImportSpec{
		codegen.SimpleImport(appPkg),
		codegen.SimpleImport("github.com/mikespook/gorbac"),
	}

	rbactitle := fmt.Sprintf("%s: RBAC", api.Name)
	_, dorbac := api.Metadata["github.com/bketelsen/gorma#rbac"]

	err = api.IterateUserTypes(func(res *design.UserTypeDefinition) error {
		if res.Type.IsObject() {
			title := fmt.Sprintf("%s: Models", api.Name)
			modelname := strings.ToLower(DeModel(res.TypeName))
			filename := filepath.Join(ModelDir(), modelname+"_genmodel.go")
			mtw, err := NewModelWriter(filename)
			if err != nil {
				panic(err)
			}
			mtw.WriteHeader(title, "models", imports)
			if md, ok := res.Metadata["github.com/bketelsen/gorma"]; ok && md == "Model" {
				fmt.Println("Found Gorma Metadata:", md)
				err = mtw.Execute(res)
				if err != nil {
					g.Cleanup()
					return err
				}
			}
			if err := mtw.FormatCode(); err != nil {
				g.Cleanup()

			}
			if err != nil {
				g.genfiles = append(g.genfiles, filename)
			}
			return nil
		}

		return nil

	})
	if dorbac {
		rbacfilename := filepath.Join(ModelDir(), "rbac_genmodel.go")
		rbacw, err := NewRbacWriter(rbacfilename)
		if err != nil {
			panic(err)
		}
		rbacw.WriteHeader(rbactitle, "models", rbacimports)
		err = rbacw.Execute(api)
		if err != nil {
			g.Cleanup()
			return g.genfiles, err
		}
		if err := rbacw.FormatCode(); err != nil {
			g.Cleanup()
			return nil, err
		}
		if err != nil {
			g.genfiles = append(g.genfiles, rbacfilename)
		}

	}

	return g.genfiles, err
}

// Cleanup removes all the files generated by this generator during the last invokation of Generate.
func (g *Generator) Cleanup() {
	for _, f := range g.genfiles {
		os.Remove(f)
	}
	g.genfiles = nil
}
<commit_msg>decouple contexts<commit_after>package gorma

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"github.com/raphael/goa/design"
	"github.com/raphael/goa/goagen/codegen"
	"gopkg.in/alecthomas/kingpin.v2"
)

// Generator is the application code generator.
type Generator struct {
	genfiles []string
}

// Generate is the generator entry point called by the meta generator.
func Generate(api *design.APIDefinition) ([]string, error) {
	g, err := NewGenerator()
	if err != nil {
		return nil, err
	}
	return g.Generate(api)
}

// NewGenerator returns the application code generator.
func NewGenerator() (*Generator, error) {
	return new(Generator), nil
}

// Generate produces the skeleton main.
func (g *Generator) Generate(api *design.APIDefinition) ([]string, error) {

	os.MkdirAll(ModelDir(), 0755)
	app := kingpin.New("Model generator", "model generator")
	codegen.RegisterFlags(app)
	_, err := app.Parse(os.Args[1:])
	if err != nil {
		panic(err)
	}
	var outPkg string
	// going to hell for this == HELP Wanted (windows)
	outPkg = codegen.DesignPackagePath[0:strings.LastIndex(codegen.DesignPackagePath, "/")]
	if err != nil {
		panic(err)
	}
	outPkg = strings.TrimPrefix(outPkg, "src/")
	appPkg := filepath.Join(outPkg, "app")
	imports := []*codegen.ImportSpec{
		codegen.SimpleImport(appPkg),
		codegen.SimpleImport("github.com/jinzhu/gorm"),
		codegen.SimpleImport("github.com/jinzhu/copier"),
		codegen.SimpleImport("time"),
	}

	rbacimports := []*codegen.ImportSpec{
		codegen.SimpleImport(appPkg),
		codegen.SimpleImport("github.com/mikespook/gorbac"),
	}

	rbactitle := fmt.Sprintf("%s: RBAC", api.Name)
	_, dorbac := api.Metadata["github.com/bketelsen/gorma#rbac"]

	err = api.IterateUserTypes(func(res *design.UserTypeDefinition) error {
		if res.Type.IsObject() {
			title := fmt.Sprintf("%s: Models", api.Name)
			modelname := strings.ToLower(DeModel(res.TypeName))

			filename := filepath.Join(ModelDir(), modelname+"_genmodel.go")
			os.Remove(filename)
			mtw, err := NewModelWriter(filename)
			if err != nil {
				panic(err)
			}
			mtw.WriteHeader(title, "models", imports)
			if md, ok := res.Metadata["github.com/bketelsen/gorma"]; ok && md == "Model" {
				fmt.Println("Found Gorma Metadata:", md)
				err = mtw.Execute(res)
				if err != nil {
					g.Cleanup()
					return err
				}
			}
			if err := mtw.FormatCode(); err != nil {
				g.Cleanup()

			}
			if err != nil {
				g.genfiles = append(g.genfiles, filename)
			}
			return nil
		}

		return nil

	})
	if dorbac {
		rbacfilename := filepath.Join(ModelDir(), "rbac_genmodel.go")
		rbacw, err := NewRbacWriter(rbacfilename)
		if err != nil {
			panic(err)
		}
		rbacw.WriteHeader(rbactitle, "models", rbacimports)
		err = rbacw.Execute(api)
		if err != nil {
			g.Cleanup()
			return g.genfiles, err
		}
		if err := rbacw.FormatCode(); err != nil {
			g.Cleanup()
			return nil, err
		}
		if err != nil {
			g.genfiles = append(g.genfiles, rbacfilename)
		}

	}

	return g.genfiles, err
}

// Cleanup removes all the files generated by this generator during the last invokation of Generate.
func (g *Generator) Cleanup() {
	for _, f := range g.genfiles {
		os.Remove(f)
	}
	g.genfiles = nil
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2015 Romain LÉTENDART
//
// See LICENSE file.
package main

import (
	"flag"
	"fmt"
	"github.com/thoj/go-ircevent"
	"golang.org/x/net/html"
	"net/http"
	"net/url"
	"os"
	"regexp"
)

func getOptions() (nick, server, channel, channelKey string, success bool) {
	flag.StringVar(&channel, "channel", "", "IRC channel name")
	flag.StringVar(&channelKey, "key", "", "IRC channel key (optional)")
	flag.StringVar(&nick, "nick", "goxxx", "the bot's nickname (optional)")
	flag.StringVar(&server, "server", "chat.freenode.net:6697", "IRC_SERVER[:PORT] (optional)")
	flag.Usage = func() {
		fmt.Println("Usage:", os.Args[0], "-channel CHANNEL [ARGUMENTS]")
		fmt.Println()
		fmt.Println("Arguments description:")
		flag.PrintDefaults()
	}
	flag.Parse()

	if channel == "" {
		flag.Usage()
		success = false
	} else {
		success = true
	}

	return
}

func getTitleFromHTML(document *html.Node) (title string, found bool) {
	if document.Type != html.DocumentNode {
		// Didn't find a document node as first node, exit
		return
	}

	// Try to find the <html> inside the document
	child := document.FirstChild
	for child != nil && !(child.Type == html.ElementNode && child.Data == "html") {
		child = child.NextSibling
	}
	if child == nil {
		// Didn't find <html>, exit
		return
	}

	// Try to find the <head> inside the document
	currentNode := child
	for child = currentNode.FirstChild; child != nil && !(child.Type == html.ElementNode && child.Data == "head"); child = child.NextSibling {
	}
	if child == nil {
		// Didn't find <head>, exit
		return
	}

	// Try to find the <title> inside the <head>
	currentNode = child
	for child = currentNode.FirstChild; child != nil && !(child.Type == html.ElementNode && child.Data == "title"); child = child.NextSibling {
	}
	if child == nil || child.FirstChild == nil {
		// Didn't find <title> or it is empty, exit
		return
	}

	// Retrieve the content inside the <title>
	title = child.FirstChild.Data
	found = true

	return
}

func findUrls(message string) (urls []*url.URL) {
	const maxUrlsCount int = 10

	// Source of the regular expression:
	// http://daringfireball.net/2010/07/improved_regex_for_matching_urls
	re := regexp.MustCompile("(?:https?://|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}/)(?:[^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\))+(?:\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s`!()\\[\\]{};:'\".,<>?«»“”‘’])")
	urlCandidates := re.FindAllString(message, maxUrlsCount)

	for _, candidate := range urlCandidates {
		url, err := url.Parse(candidate)
		if err != nil {
			break
		}
		if url.Scheme == "" {
			url.Scheme = "https"
		}
		urls = append(urls, url)
	}

	return
}

func main() {
	nick, server, channel, channelKey, success := getOptions()

	if !success {
		return
	}

	ircConn := irc.IRC(nick, nick)
	ircConn.UseTLS = true
	ircConn.Connect(server)
	ircConn.Join(channel + " " + channelKey)
	ircConn.AddCallback("PRIVMSG", func(event *irc.Event) {
		allUrls := findUrls(event.Message())
		for _, url := range allUrls {
			fmt.Println("Detected URL:", url.String())
			response, err := http.Get(url.String())
			if err != nil {
				// TODO Do proper logging
				fmt.Println(err)
				return
			}
			doc, err := html.Parse(response.Body)
			response.Body.Close()
			if err != nil {
				// TODO Do proper logging
				fmt.Println(err)
				return
			}
			title, found := getTitleFromHTML(doc)
			if found {
				ircConn.Privmsg(channel, title)
			}
		}
	})

	ircConn.Loop()
}
<commit_msg>Added support for Unicode hostnames<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2015 Romain LÉTENDART
//
// See LICENSE file.
package main

import (
	"flag"
	"fmt"
	"github.com/thoj/go-ircevent"
	"golang.org/x/net/html"
	"golang.org/x/net/idna"
	"net/http"
	"net/url"
	"os"
	"regexp"
)

func getOptions() (nick, server, channel, channelKey string, success bool) {
	flag.StringVar(&channel, "channel", "", "IRC channel name")
	flag.StringVar(&channelKey, "key", "", "IRC channel key (optional)")
	flag.StringVar(&nick, "nick", "goxxx", "the bot's nickname (optional)")
	flag.StringVar(&server, "server", "chat.freenode.net:6697", "IRC_SERVER[:PORT] (optional)")
	flag.Usage = func() {
		fmt.Println("Usage:", os.Args[0], "-channel CHANNEL [ARGUMENTS]")
		fmt.Println()
		fmt.Println("Arguments description:")
		flag.PrintDefaults()
	}
	flag.Parse()

	if channel == "" {
		flag.Usage()
		success = false
	} else {
		success = true
	}

	return
}

func getTitleFromHTML(document *html.Node) (title string, found bool) {
	if document.Type != html.DocumentNode {
		// Didn't find a document node as first node, exit
		return
	}

	// Try to find the <html> inside the document
	child := document.FirstChild
	for child != nil && !(child.Type == html.ElementNode && child.Data == "html") {
		child = child.NextSibling
	}
	if child == nil {
		// Didn't find <html>, exit
		return
	}

	// Try to find the <head> inside the document
	currentNode := child
	for child = currentNode.FirstChild; child != nil && !(child.Type == html.ElementNode && child.Data == "head"); child = child.NextSibling {
	}
	if child == nil {
		// Didn't find <head>, exit
		return
	}

	// Try to find the <title> inside the <head>
	currentNode = child
	for child = currentNode.FirstChild; child != nil && !(child.Type == html.ElementNode && child.Data == "title"); child = child.NextSibling {
	}
	if child == nil || child.FirstChild == nil {
		// Didn't find <title> or it is empty, exit
		return
	}

	// Retrieve the content inside the <title>
	title = child.FirstChild.Data
	found = true

	return
}

func findUrls(message string) (urls []*url.URL) {
	const maxUrlsCount int = 10

	// Source of the regular expression:
	// http://daringfireball.net/2010/07/improved_regex_for_matching_urls
	re := regexp.MustCompile("(?:https?://|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}/)(?:[^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\))+(?:\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s`!()\\[\\]{};:'\".,<>?«»“”‘’])")
	urlCandidates := re.FindAllString(message, maxUrlsCount)

	for _, candidate := range urlCandidates {
		url, err := url.Parse(candidate)
		if err != nil {
			break
		}
		// Scheme is required to query a URL
		if url.Scheme == "" {
			url.Scheme = "https"
		}
		// Conversion to ASCII is needed for Unicode hostnames
		asciiHost, err := idna.ToASCII(url.Host)
		if err == nil {
			url.Host = asciiHost
		}
		urls = append(urls, url)
	}

	return
}

func main() {
	nick, server, channel, channelKey, success := getOptions()

	if !success {
		return
	}

	ircConn := irc.IRC(nick, nick)
	ircConn.UseTLS = true
	ircConn.Connect(server)
	ircConn.Join(channel + " " + channelKey)
	ircConn.AddCallback("PRIVMSG", func(event *irc.Event) {
		allUrls := findUrls(event.Message())
		for _, url := range allUrls {
			fmt.Println("Detected URL:", url.String())
			response, err := http.Get(url.String())
			if err != nil {
				// TODO Do proper logging
				fmt.Println(err)
				return
			}
			doc, err := html.Parse(response.Body)
			response.Body.Close()
			if err != nil {
				// TODO Do proper logging
				fmt.Println(err)
				return
			}
			title, found := getTitleFromHTML(doc)
			if found {
				ircConn.Privmsg(channel, title)
			}
		}
	})

	ircConn.Loop()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"sort"
	"strconv"
	"strings"

	"github.com/gonum/stat"
)

var (
	colors = []string{
		"rgba(31,119,180,1)",
		"rgba(255,127,14,1)",
		"rgba(44,160,44,1)",
		"rgba(214,39,40,1)",
		"rgba(148,103,189,1)",
		"rgba(140,86,75,1)",
		"rgba(227,119,194,1)",
	}
)

const (
	maxBallNum       = 59
	balls            = 7
	avgMarkerSize    = 8
	regressionLinear = "linear"
	regressionPoly   = "polynomial"
	graphTypeScatter = "scatter"
	graphTypeBar     = "bar"
	graphTypeLine    = "line"
)

/*
   Why are all axes strings? Because it's more flexible. I'm passing this data to
	 Plotly.js which interprets it accordingly and where strconv has no value it returns
	 an empty string which plotly ignores but maintains the correct number of elements
	 in the set. This removes useless visual noise from the graph and allows me to make
	 my axes anything. Yes, there's a performance overhead to the conversion but it is
	 on the scale of a fraction of a fraction of a second, which I see as a reasonable
	 compromise
*/

// standard dataset for most graphs
type dataset struct {
	X           []string `json:"x"`
	Y           []string `json:"y"`
	Z           []string `json:"z"`
	Name        string   `json:"name"`
	Mode        string   `json:"mode"`
	Type        string   `json:"type"`
	Line        line     `json:"line"`
	Marker      marker   `json:"marker"`
	ConnectGaps bool     `json:"connectgaps"`
}

// datasetB is specifically for bubble graphs because it requires a distinctly different
// marker object
type datasetB struct {
	X           []string `json:"x"`
	Y           []string `json:"y"`
	Z           []string `json:"z"`
	Name        string   `json:"name"`
	Mode        string   `json:"mode"`
	Type        string   `json:"type"`
	Line        line     `json:"line"`
	Marker      markerB  `json:"marker"`
	ConnectGaps bool     `json:"connectgaps"`
}

type marker struct {
	Colour  string  `json:"color"`
	Size    float64 `json:"size"`
	Line    line    `json:"line"`
	Opacity float64 `json:"opacity"`
	Symbol  string  `json:"symbol"`
}

type markerB struct {
	Colour   string    `json:"color"`
	Size     []float64 `json:"size"`
	SizeMode string    `json:"sizemode"`
	SizeRef  float64   `json:"sizeref"`
	Line     line      `json:"line"`
	Opacity  float64   `json:"opacity"`
	Symbol   string    `json:"symbol"`
}

type line struct {
	Width   float64 `json:"width"`
	Colour  string  `json:"color"`
	Shape   string  `json:"shape"`
	Dash    string  `json:"dash"`
	Opacity float64 `json:"opacity"`
}

func graphResultsTimeSeries(records <-chan dbRow, bestFit bool, t string) []dataset {
	data := make([]dataset, balls)

	i := 0
	for row := range records {
		for ball := 0; ball < balls; ball++ {
			if i == 0 {

				switch t {
				case graphTypeScatter:
					data[ball] = dataset{
						Mode: "markers",
						Marker: marker{
							Colour:  colors[ball],
							Size:    avgMarkerSize,
							Opacity: 1,
						},
					}

				case graphTypeLine:
					data[ball] = dataset{
						Mode: "lines",
						Line: line{
							Width: 1,
							Shape: "spline",
						},
					}
				} // END SWITCH

				data[ball].Name = label(ball)
			}
			data[ball].X = append(data[ball].X, fmt.Sprintf("%s:%d:%s", row.Date.Format(formatYYYYMMDD), row.Set, row.Machine))
			data[ball].Y = append(data[ball].Y, strconv.Itoa(row.Num[ball]))
		}

		i++
	}

	// Best fit lines only really suit scatter graphs so far
	if bestFit && t == graphTypeScatter {
		data = append(data, regressionSet(data, regressionLinear)...)
	}

	return data
}

func graphResultsFreqDist(records <-chan dbRow, bestFit bool, t string) []dataset {
	data := make([]dataset, balls)

	i := 0
	for row := range records {
		for ball := 0; ball < balls; ball++ {
			if i == 0 {

				switch t {
				case graphTypeScatter:
					data[ball] = dataset{
						Mode: "markers",
						Marker: marker{
							Colour:  colors[ball],
							Size:    avgMarkerSize,
							Opacity: 1,
						},
						X: freqDistXLabels(),
						Y: make([]string, maxBallNum),
					}

				case graphTypeBar:
					data[ball] = dataset{
						Type: graphTypeBar,
						X:    freqDistXLabels(),
						Y:    make([]string, maxBallNum),
					}

				} // END SWITCH

				data[ball].Name = label(ball)
			}

			n, _ := strconv.Atoi(data[ball].Y[row.Num[ball]-1]) // I don't care about this error because it actually eliminates useless 0 values
			data[ball].Y[row.Num[ball]-1] = strconv.Itoa(n + 1)
		}
		i++
	}

	/* currently not working because I have yet to work out how to do non-linear best fit lines
	if bestFit && t != graphTypeBar {
		data = append(data, regressionSet(data, regressionPoly)...)
	}
	*/

	return data
}

func graphResultsRawScatter3D(records <-chan dbRow) []dataset {
	data := make([]dataset, balls)

	i := 0
	for row := range records {
		for ball := 0; ball < balls; ball++ {
			if i == 0 {
				data[ball] = dataset{
					Mode: "markers",
					Type: "scatter3d",
					Marker: marker{
						Size:    avgMarkerSize / 2,
						Opacity: 0.9,
						Line:    line{Width: 0.1},
					},
				}

				data[ball].Name = label(ball)
			}
			data[ball].X = append(data[ball].X, row.Machine)
			data[ball].Y = append(data[ball].Y, strconv.Itoa(row.Set))
			data[ball].Z = append(data[ball].Z, strconv.Itoa(row.Num[ball]))
		}
		i++
	}

	return data
}

func graphMSFreqDistScatter3D(m map[string]int) []dataset {
	data := dataset{
		Type: "scatter3d",
		Mode: "markers",
		Marker: marker{
			Size:    avgMarkerSize,
			Opacity: 0.9,
			Line: line{
				Width: 0.1,
			},
		},
	}

	l := []string{}
	for k := range m {
		l = append(l, k)
	}
	sort.Strings(l)

	for _, k := range l {
		s := strings.Split(k, ":")

		data.X = append(data.X, s[0])               // Machine
		data.Y = append(data.Y, s[1])               // Set
		data.Z = append(data.Z, strconv.Itoa(m[k])) // Frequency
	}

	return []dataset{data}
}

func graphMSFreqDistBubble(m map[string]int) []datasetB {
	data := datasetB{
		Type: "scatter",
		Mode: "markers",
		Marker: markerB{
			Opacity: 0.8,
			Line:    line{Width: 0.1},
		},
	}

	l := []string{}
	for k := range m {
		l = append(l, k)
	}
	sort.Strings(l)

	for _, k := range l {
		s := strings.Split(k, ":")

		data.X = append(data.X, s[0])                                // Machine
		data.Y = append(data.Y, s[1])                                // Set
		data.Marker.Size = append(data.Marker.Size, float64(m[k])*2) // Frequency
	}

	return []datasetB{data}
}

func regressionSet(data []dataset, t string) []dataset {
	// Calculate and append regressionLinear regressions for each set
	r, rX := make([]dataset, balls), make([]float64, len(data[0].Y))

	// Generate numerical X axis data
	for i := range rX {
		rX[i] = float64(i) + 1
	}

	// Iterate existing sets and create new regression sets
	for i, set := range data {
		r[i] = dataset{
			Name: set.Name,
			Mode: "lines",
			Line: line{
				Dash:   "dot",
				Width:  2,
				Colour: colors[i],
			},
			ConnectGaps: true,
			X:           set.X,
		}

		// Translate Y axis to numerical data
		rY := make([]float64, len(data[0].Y))
		for j := range rY {
			rY[j], _ = strconv.ParseFloat(data[i].Y[j], 64)
		}
		switch t {
		case regressionLinear:
			r[i].Y = linRegYData(rX, rY, false)

		case regressionPoly:
			r[i].Y = polRegYData(rX, rY, false) // Not currently working because I suck at maths

		}
	}

	return r
}

func polRegYData(prX, prY []float64, subzero bool) []string {
	// @TODO: polynomial regression sets for non-linear best fits
	y := make([]string, len(prX))
	//a, b := stat.LinearRegression(prX, prY, nil, false)
	//r2 := stat.RSquared(prX, prY, nil, a, b)
	//log.Println(r2)

	return y
}

func linRegYData(lrX, lrY []float64, subzero bool) []string {
	a, b := stat.LinearRegression(lrX, lrY, nil, false)

	y := make([]string, len(lrX))
	for idx, x := range lrX {
		n := a + (b * x)
		f := strconv.FormatFloat(n, 'f', -1, 64)
		if subzero {
			y[idx] = f
		} else if n < 0 {
			y[idx] = "0"
		} else {
			y[idx] = f
		}

	}
	return y
}

func freqDistXLabels() []string {
	var x []string
	for i := 0; i < maxBallNum; i++ {
		x = append(x, strconv.Itoa(i+1))
	}
	return x
}

func label(ball int) string {
	if ball < 6 {
		return fmt.Sprintf("Ball %d", ball+1)
	}

	return "Bonus"
}
<commit_msg>use pltlytypes lib<commit_after>package main

import (
	"fmt"
	"sort"
	"strconv"
	"strings"

	"github.com/gonum/stat"
	pt "github.com/nboughton/go-plotlytypes"
)

var (
	colors = []string{
		"rgba(31,119,180,1)",
		"rgba(255,127,14,1)",
		"rgba(44,160,44,1)",
		"rgba(214,39,40,1)",
		"rgba(148,103,189,1)",
		"rgba(140,86,75,1)",
		"rgba(227,119,194,1)",
	}
)

const (
	maxBallNum       = 59
	balls            = 7
	avgMarkerSize    = 8
	regressionLinear = "linear"
	regressionPoly   = "polynomial"
	graphTypeScatter = "scatter"
	graphTypeBar     = "bar"
	graphTypeLine    = "line"
)

func graphResultsTimeSeries(records <-chan dbRow, bestFit bool, t string) []pt.Dataset {
	data := make([]pt.Dataset, balls)

	i := 0
	for row := range records {
		for ball := 0; ball < balls; ball++ {
			if i == 0 {

				switch t {
				case graphTypeScatter:
					data[ball] = pt.Dataset{
						Mode: "markers",
						Marker: pt.Marker{
							Colour:  colors[ball],
							Size:    avgMarkerSize,
							Opacity: 1,
						},
					}

				case graphTypeLine:
					data[ball] = pt.Dataset{
						Mode: "lines",
						Line: pt.Line{
							Width: 1,
							Shape: "spline",
						},
					}
				} // END SWITCH

				data[ball].Name = label(ball)
			}
			data[ball].X = append(data[ball].X, fmt.Sprintf("%s:%d:%s", row.Date.Format(formatYYYYMMDD), row.Set, row.Machine))
			data[ball].Y = append(data[ball].Y, strconv.Itoa(row.Num[ball]))
		}

		i++
	}

	// Best fit lines only really suit scatter graphs so far
	if bestFit && t == graphTypeScatter {
		data = append(data, regressionSet(data, regressionLinear)...)
	}

	return data
}

func graphResultsFreqDist(records <-chan dbRow, bestFit bool, t string) []pt.Dataset {
	data := make([]pt.Dataset, balls)

	i := 0
	for row := range records {
		for ball := 0; ball < balls; ball++ {
			if i == 0 {

				switch t {
				case graphTypeScatter:
					data[ball] = pt.Dataset{
						Mode: "markers",
						Marker: pt.Marker{
							Colour:  colors[ball],
							Size:    avgMarkerSize,
							Opacity: 1,
						},
						X: freqDistXLabels(),
						Y: make([]string, maxBallNum),
					}

				case graphTypeBar:
					data[ball] = pt.Dataset{
						Type: graphTypeBar,
						X:    freqDistXLabels(),
						Y:    make([]string, maxBallNum),
					}

				} // END SWITCH

				data[ball].Name = label(ball)
			}

			n, _ := strconv.Atoi(data[ball].Y[row.Num[ball]-1]) // I don't care about this error because it actually eliminates useless 0 values
			data[ball].Y[row.Num[ball]-1] = strconv.Itoa(n + 1)
		}
		i++
	}

	/* currently not working because I have yet to work out how to do non-linear best fit lines
	if bestFit && t != graphTypeBar {
		data = append(data, regressionSet(data, regressionPoly)...)
	}
	*/

	return data
}

func graphResultsRawScatter3D(records <-chan dbRow) []pt.Dataset {
	data := make([]pt.Dataset, balls)

	i := 0
	for row := range records {
		for ball := 0; ball < balls; ball++ {
			if i == 0 {
				data[ball] = pt.Dataset{
					Mode: "markers",
					Type: "scatter3d",
					Marker: pt.Marker{
						Size:    avgMarkerSize / 2,
						Opacity: 0.9,
						Line:    pt.Line{Width: 0.1},
					},
				}

				data[ball].Name = label(ball)
			}
			data[ball].X = append(data[ball].X, row.Machine)
			data[ball].Y = append(data[ball].Y, strconv.Itoa(row.Set))
			data[ball].Z = append(data[ball].Z, strconv.Itoa(row.Num[ball]))
		}
		i++
	}

	return data
}

func graphMSFreqDistScatter3D(m map[string]int) []pt.Dataset {
	data := pt.Dataset{
		Type: "scatter3d",
		Mode: "markers",
		Marker: pt.Marker{
			Size:    avgMarkerSize,
			Opacity: 0.9,
			Line: pt.Line{
				Width: 0.1,
			},
		},
	}

	l := []string{}
	for k := range m {
		l = append(l, k)
	}
	sort.Strings(l)

	for _, k := range l {
		s := strings.Split(k, ":")

		data.X = append(data.X, s[0])               // Machine
		data.Y = append(data.Y, s[1])               // Set
		data.Z = append(data.Z, strconv.Itoa(m[k])) // Frequency
	}

	return []pt.Dataset{data}
}

func graphMSFreqDistBubble(m map[string]int) []pt.DatasetB {
	data := pt.DatasetB{
		Type: "scatter",
		Mode: "markers",
		Marker: pt.MarkerB{
			Opacity: 0.8,
			Line:    pt.Line{Width: 0.1},
		},
	}

	l := []string{}
	for k := range m {
		l = append(l, k)
	}
	sort.Strings(l)

	for _, k := range l {
		s := strings.Split(k, ":")

		data.X = append(data.X, s[0])                                // Machine
		data.Y = append(data.Y, s[1])                                // Set
		data.Marker.Size = append(data.Marker.Size, float64(m[k])*2) // Frequency
	}

	return []pt.DatasetB{data}
}

func regressionSet(data []pt.Dataset, t string) []pt.Dataset {
	// Calculate and append regressionLinear regressions for each set
	r, rX := make([]pt.Dataset, balls), make([]float64, len(data[0].Y))

	// Generate numerical X axis data
	for i := range rX {
		rX[i] = float64(i) + 1
	}

	// Iterate existing sets and create new regression sets
	for i, set := range data {
		r[i] = pt.Dataset{
			Name: set.Name,
			Mode: "lines",
			Line: pt.Line{
				Dash:   "dot",
				Width:  2,
				Colour: colors[i],
			},
			ConnectGaps: true,
			X:           set.X,
		}

		// Translate Y axis to numerical data
		rY := make([]float64, len(data[0].Y))
		for j := range rY {
			rY[j], _ = strconv.ParseFloat(data[i].Y[j], 64)
		}
		switch t {
		case regressionLinear:
			r[i].Y = linRegYData(rX, rY, false)

		case regressionPoly:
			r[i].Y = polRegYData(rX, rY, false) // Not currently working because I suck at maths

		}
	}

	return r
}

func polRegYData(prX, prY []float64, subzero bool) []string {
	// @TODO: polynomial regression sets for non-linear best fits
	y := make([]string, len(prX))
	//a, b := stat.LinearRegression(prX, prY, nil, false)
	//r2 := stat.RSquared(prX, prY, nil, a, b)
	//log.Println(r2)

	return y
}

func linRegYData(lrX, lrY []float64, subzero bool) []string {
	a, b := stat.LinearRegression(lrX, lrY, nil, false)

	y := make([]string, len(lrX))
	for idx, x := range lrX {
		n := a + (b * x)
		f := strconv.FormatFloat(n, 'f', -1, 64)
		if subzero {
			y[idx] = f
		} else if n < 0 {
			y[idx] = "0"
		} else {
			y[idx] = f
		}

	}
	return y
}

func freqDistXLabels() []string {
	var x []string
	for i := 0; i < maxBallNum; i++ {
		x = append(x, strconv.Itoa(i+1))
	}
	return x
}

func label(ball int) string {
	if ball < 6 {
		return fmt.Sprintf("Ball %d", ball+1)
	}

	return "Bonus"
}
<|endoftext|>


<commit_before>package vault

import (
	"bytes"
	"reflect"
	"testing"
	"time"
)

func TestKeyring(t *testing.T) {
	k := NewKeyring()

	// Term should be 0
	if term := k.ActiveTerm(); term != 0 {
		t.Fatalf("bad: %d", term)
	}

	// Should have no key
	if key := k.ActiveKey(); key != nil {
		t.Fatalf("bad: %v", key)
	}

	// Add a key
	testKey := []byte("testing")
	key1 := &Key{Term: 1, Version: 1, Value: testKey, InstallTime: time.Now()}
	k, err := k.AddKey(key1)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	// Term should be 1
	if term := k.ActiveTerm(); term != 1 {
		t.Fatalf("bad: %d", term)
	}

	// Should have key
	key := k.ActiveKey()
	if key == nil {
		t.Fatalf("bad: %v", key)
	}
	if !bytes.Equal(key.Value, testKey) {
		t.Fatalf("bad: %v", key)
	}
	if tKey := k.TermKey(1); tKey != key {
		t.Fatalf("bad: %v", tKey)
	}

	// Should handle idempotent set
	k, err = k.AddKey(key1)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	// Should not allow conficting set
	testConflict := []byte("nope")
	key1Conf := &Key{Term: 1, Version: 1, Value: testConflict, InstallTime: time.Now()}
	_, err = k.AddKey(key1Conf)
	if err == nil {
		t.Fatalf("err: %v", err)
	}

	// Add a new key
	testSecond := []byte("second")
	key2 := &Key{Term: 2, Version: 1, Value: testSecond, InstallTime: time.Now()}
	k, err = k.AddKey(key2)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	// Term should be 2
	if term := k.ActiveTerm(); term != 2 {
		t.Fatalf("bad: %d", term)
	}

	// Should have key
	newKey := k.ActiveKey()
	if newKey == nil {
		t.Fatalf("bad: %v", key)
	}
	if !bytes.Equal(newKey.Value, testSecond) {
		t.Fatalf("bad: %v", key)
	}
	if tKey := k.TermKey(2); tKey != newKey {
		t.Fatalf("bad: %v", tKey)
	}

	// Read of old key should work
	if tKey := k.TermKey(1); tKey != key {
		t.Fatalf("bad: %v", tKey)
	}

	// Remove the old key
	k, err = k.RemoveKey(1)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	// Read of old key should not work
	if tKey := k.TermKey(1); tKey != nil {
		t.Fatalf("bad: %v", tKey)
	}

	// Remove the active key should fail
	k, err = k.RemoveKey(2)
	if err == nil {
		t.Fatalf("err: %v", err)
	}
}

func TestKeyring_MasterKey(t *testing.T) {
	k := NewKeyring()
	master := []byte("test")
	master2 := []byte("test2")

	// Check no master
	out := k.MasterKey()
	if out != nil {
		t.Fatalf("bad: %v", out)
	}

	// Set master
	k = k.SetMasterKey(master)
	out = k.MasterKey()
	if !bytes.Equal(out, master) {
		t.Fatalf("bad: %v", out)
	}

	// Update master
	k = k.SetMasterKey(master2)
	out = k.MasterKey()
	if !bytes.Equal(out, master2) {
		t.Fatalf("bad: %v", out)
	}
}

func TestKeyring_Serialize(t *testing.T) {
	k := NewKeyring()
	master := []byte("test")
	k = k.SetMasterKey(master)

	now := time.Now()
	testKey := []byte("testing")
	testSecond := []byte("second")
	k, _ = k.AddKey(&Key{Term: 1, Version: 1, Value: testKey, InstallTime: now})
	k, _ = k.AddKey(&Key{Term: 2, Version: 1, Value: testSecond, InstallTime: now})

	buf, err := k.Serialize()
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	k2, err := DeserializeKeyring(buf)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	out := k2.MasterKey()
	if !bytes.Equal(out, master) {
		t.Fatalf("bad: %v", out)
	}

	if k2.ActiveTerm() != k.ActiveTerm() {
		t.Fatalf("Term mismatch")
	}

	var i uint32
	for i = 1; i < k.ActiveTerm(); i++ {
		key1 := k2.TermKey(i)
		key2 := k.TermKey(i)
		if !reflect.DeepEqual(key1, key2) {
			t.Fatalf("bad: key 1:\n%#v\nkey 2:\n%#v", key1, key2)
		}
	}
}

func TestKey_Serialize(t *testing.T) {
	k := &Key{
		Term:        10,
		Version:     1,
		Value:       []byte("foobarbaz"),
		InstallTime: time.Now(),
	}

	buf, err := k.Serialize()
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	out, err := DeserializeKey(buf)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	if !reflect.DeepEqual(k, out) {
		t.Fatalf("bad: %#v", out)
	}
}
<commit_msg>Fix keyring tests, working around Go nil timezone bug in DeepEqual<commit_after>package vault

import (
	"bytes"
	"reflect"
	"testing"
	"time"
)

func TestKeyring(t *testing.T) {
	k := NewKeyring()

	// Term should be 0
	if term := k.ActiveTerm(); term != 0 {
		t.Fatalf("bad: %d", term)
	}

	// Should have no key
	if key := k.ActiveKey(); key != nil {
		t.Fatalf("bad: %v", key)
	}

	// Add a key
	testKey := []byte("testing")
	key1 := &Key{Term: 1, Version: 1, Value: testKey, InstallTime: time.Now()}
	k, err := k.AddKey(key1)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	// Term should be 1
	if term := k.ActiveTerm(); term != 1 {
		t.Fatalf("bad: %d", term)
	}

	// Should have key
	key := k.ActiveKey()
	if key == nil {
		t.Fatalf("bad: %v", key)
	}
	if !bytes.Equal(key.Value, testKey) {
		t.Fatalf("bad: %v", key)
	}
	if tKey := k.TermKey(1); tKey != key {
		t.Fatalf("bad: %v", tKey)
	}

	// Should handle idempotent set
	k, err = k.AddKey(key1)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	// Should not allow conficting set
	testConflict := []byte("nope")
	key1Conf := &Key{Term: 1, Version: 1, Value: testConflict, InstallTime: time.Now()}
	_, err = k.AddKey(key1Conf)
	if err == nil {
		t.Fatalf("err: %v", err)
	}

	// Add a new key
	testSecond := []byte("second")
	key2 := &Key{Term: 2, Version: 1, Value: testSecond, InstallTime: time.Now()}
	k, err = k.AddKey(key2)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	// Term should be 2
	if term := k.ActiveTerm(); term != 2 {
		t.Fatalf("bad: %d", term)
	}

	// Should have key
	newKey := k.ActiveKey()
	if newKey == nil {
		t.Fatalf("bad: %v", key)
	}
	if !bytes.Equal(newKey.Value, testSecond) {
		t.Fatalf("bad: %v", key)
	}
	if tKey := k.TermKey(2); tKey != newKey {
		t.Fatalf("bad: %v", tKey)
	}

	// Read of old key should work
	if tKey := k.TermKey(1); tKey != key {
		t.Fatalf("bad: %v", tKey)
	}

	// Remove the old key
	k, err = k.RemoveKey(1)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	// Read of old key should not work
	if tKey := k.TermKey(1); tKey != nil {
		t.Fatalf("bad: %v", tKey)
	}

	// Remove the active key should fail
	k, err = k.RemoveKey(2)
	if err == nil {
		t.Fatalf("err: %v", err)
	}
}

func TestKeyring_MasterKey(t *testing.T) {
	k := NewKeyring()
	master := []byte("test")
	master2 := []byte("test2")

	// Check no master
	out := k.MasterKey()
	if out != nil {
		t.Fatalf("bad: %v", out)
	}

	// Set master
	k = k.SetMasterKey(master)
	out = k.MasterKey()
	if !bytes.Equal(out, master) {
		t.Fatalf("bad: %v", out)
	}

	// Update master
	k = k.SetMasterKey(master2)
	out = k.MasterKey()
	if !bytes.Equal(out, master2) {
		t.Fatalf("bad: %v", out)
	}
}

func TestKeyring_Serialize(t *testing.T) {
	k := NewKeyring()
	master := []byte("test")
	k = k.SetMasterKey(master)

	now := time.Now()
	testKey := []byte("testing")
	testSecond := []byte("second")
	k, _ = k.AddKey(&Key{Term: 1, Version: 1, Value: testKey, InstallTime: now})
	k, _ = k.AddKey(&Key{Term: 2, Version: 1, Value: testSecond, InstallTime: now})

	buf, err := k.Serialize()
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	k2, err := DeserializeKeyring(buf)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	out := k2.MasterKey()
	if !bytes.Equal(out, master) {
		t.Fatalf("bad: %v", out)
	}

	if k2.ActiveTerm() != k.ActiveTerm() {
		t.Fatalf("Term mismatch")
	}

	var i uint32
	for i = 1; i < k.ActiveTerm(); i++ {
		key1 := k2.TermKey(i)
		key2 := k.TermKey(i)
		// Work around timezone bug due to DeepEqual using == for comparison
		if !key1.InstallTime.Equal(key2.InstallTime) {
			t.Fatalf("bad: key 1:\n%#v\nkey 2:\n%#v", key1, key2)
		}
		key1.InstallTime = key2.InstallTime
		if !reflect.DeepEqual(key1, key2) {
			t.Fatalf("bad: key 1:\n%#v\nkey 2:\n%#v", key1, key2)
		}
	}
}

func TestKey_Serialize(t *testing.T) {
	k := &Key{
		Term:        10,
		Version:     1,
		Value:       []byte("foobarbaz"),
		InstallTime: time.Now(),
	}

	buf, err := k.Serialize()
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	out, err := DeserializeKey(buf)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	// Work around timezone bug due to DeepEqual using == for comparison
	if !k.InstallTime.Equal(out.InstallTime) {
		t.Fatalf("bad: key 1:\n%#v\nkey 2:\n%#v", key1, key2)
	}

	if !reflect.DeepEqual(k, out) {
		t.Fatalf("bad: %#v", out)
	}
}
<|endoftext|>


<commit_before>package fire

import (
	"net/http"
	"strings"

	"github.com/256dpi/jsonapi"
	"github.com/256dpi/stack"
	"gopkg.in/mgo.v2/bson"
)

// TODO: Pull in CORS from wood an make it a first class citizen.

// TODO: Add custom resources.

// A Group manages access to multiple controllers and their interconnections.
type Group struct {
	prefix      string
	controllers map[string]*Controller

	// The function gets invoked by the controller with occurring fatal errors.
	Reporter func(error)

	// The function that should be used to log debugging information.
	Logger func(string)
}

// NewGroup creates and returns a new group.
func NewGroup(prefix string) *Group {
	return &Group{
		prefix:      prefix,
		controllers: make(map[string]*Controller),
	}
}

// Add will add a controller to the group.
func (g *Group) Add(controllers ...*Controller) {
	for _, controller := range controllers {
		// prepare controller
		controller.prepare()

		// get name
		name := controller.Model.Meta().PluralName

		// create entry in controller map
		g.controllers[name] = controller
	}
}

// List will return a list of all added controllers.
func (g *Group) List() []*Controller {
	list := make([]*Controller, 0, len(g.controllers))

	for _, c := range g.controllers {
		list = append(list, c)
	}

	return list
}

// Find will return the controller with the matching plural name if found.
func (g *Group) Find(pluralName string) *Controller {
	return g.controllers[pluralName]
}

// Endpoint will return an http handler that serves requests for this controller
// group. The specified prefix is used to parse the requests and generate urls
// for the resources.
func (g *Group) Endpoint() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// create tracer
		tracer := NewTracerFromRequest(r, "fire/Group.Endpoint")
		defer tracer.Finish(true)

		// continue any previous aborts
		defer stack.Resume(func(err error) {
			// directly write jsonapi errors
			if jsonapiError, ok := err.(*jsonapi.Error); ok {
				jsonapi.WriteError(w, jsonapiError)
				return
			}

			// set critical error on last span
			tracer.Tag("error", true)
			tracer.Log("error", err.Error())
			tracer.Log("stack", stack.Trace())

			// report critical errors if possible
			if g.Reporter != nil {
				g.Reporter(err)
			}

			// ignore errors caused by writing critical errors
			jsonapi.WriteError(w, jsonapi.InternalServerError(""))
		})

		// trim and split path
		s := strings.Split(strings.Trim(strings.TrimPrefix(r.URL.Path, g.prefix), "/"), "/")

		// check segments
		if len(s) == 0 {
			stack.Abort(jsonapi.NotFound("resource not found"))
		}

		// get controller
		controller, ok := g.controllers[s[0]]
		if !ok {
			stack.Abort(jsonapi.NotFound("resource not found"))
		}

		// call controller with context
		controller.generalHandler(&Context{
			Selector:       bson.M{},
			Filter:         bson.M{},
			HTTPRequest:    r,
			ResponseWriter: w,
			Controller:     controller,
			Group:          g,
			Tracer:         tracer,
			Logger:         g.Logger,
		})
	})
}
<commit_msg>updated docs<commit_after>package fire

import (
	"net/http"
	"strings"

	"github.com/256dpi/jsonapi"
	"github.com/256dpi/stack"
	"gopkg.in/mgo.v2/bson"
)

// TODO: Pull in CORS from wood an make it a first class citizen.

// TODO: Add custom resources.

// A Group manages access to multiple controllers and their interconnections.
type Group struct {
	prefix      string
	controllers map[string]*Controller

	// The function gets invoked by the controller with occurring fatal errors.
	Reporter func(error)

	// The function that should be used to log debugging information.
	Logger func(string)
}

// NewGroup creates and returns a new group. The specified prefix is used to
// parse the requests and generate urls for the resources.
func NewGroup(prefix string) *Group {
	return &Group{
		prefix:      prefix,
		controllers: make(map[string]*Controller),
	}
}

// Add will add a controller to the group.
func (g *Group) Add(controllers ...*Controller) {
	for _, controller := range controllers {
		// prepare controller
		controller.prepare()

		// get name
		name := controller.Model.Meta().PluralName

		// create entry in controller map
		g.controllers[name] = controller
	}
}

// List will return a list of all added controllers.
func (g *Group) List() []*Controller {
	list := make([]*Controller, 0, len(g.controllers))

	for _, c := range g.controllers {
		list = append(list, c)
	}

	return list
}

// Find will return the controller with the matching plural name if found.
func (g *Group) Find(pluralName string) *Controller {
	return g.controllers[pluralName]
}

// Endpoint will return an http handler that serves requests for this group.
func (g *Group) Endpoint() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// create tracer
		tracer := NewTracerFromRequest(r, "fire/Group.Endpoint")
		defer tracer.Finish(true)

		// continue any previous aborts
		defer stack.Resume(func(err error) {
			// directly write jsonapi errors
			if jsonapiError, ok := err.(*jsonapi.Error); ok {
				jsonapi.WriteError(w, jsonapiError)
				return
			}

			// set critical error on last span
			tracer.Tag("error", true)
			tracer.Log("error", err.Error())
			tracer.Log("stack", stack.Trace())

			// report critical errors if possible
			if g.Reporter != nil {
				g.Reporter(err)
			}

			// ignore errors caused by writing critical errors
			jsonapi.WriteError(w, jsonapi.InternalServerError(""))
		})

		// trim and split path
		s := strings.Split(strings.Trim(strings.TrimPrefix(r.URL.Path, g.prefix), "/"), "/")

		// check segments
		if len(s) == 0 {
			stack.Abort(jsonapi.NotFound("resource not found"))
		}

		// get controller
		controller, ok := g.controllers[s[0]]
		if !ok {
			stack.Abort(jsonapi.NotFound("resource not found"))
		}

		// call controller with context
		controller.generalHandler(&Context{
			Selector:       bson.M{},
			Filter:         bson.M{},
			HTTPRequest:    r,
			ResponseWriter: w,
			Controller:     controller,
			Group:          g,
			Tracer:         tracer,
			Logger:         g.Logger,
		})
	})
}
<|endoftext|>


<commit_before>package main

import (
    "fmt"
    "net/http"
    "strings"
    "google.golang.org/appengine"
)

// Trivially routes requests to the correct response function.
func IndexHandler(w http.ResponseWriter, r *http.Request) {
    switch r.URL.Path {
        case "/":
            switch r.Method {
                case http.MethodGet:
                    GetIndex(w, r)
                default:
                    NotFound(w, r)
            }
        default:
            NotFound(w, r)
    }
}

// Returns the client's IP address.
func GetIndex(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusOK)
    w.Header().Set("Content-Type", "text/plain")

    // RemoteAddr is formatted as host:port, so we just trim off the port here
    // and return the IP.
    fmt.Fprint(w, strings.Split(r.RemoteAddr, ":")[0])
}

// Returns a 404 Not Found page.
func NotFound(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusNotFound)
    w.Header().Set("Content-Type", "text/plain")
    fmt.Fprintf(w, "%d Not Found", http.StatusNotFound)
}

// appengine.Main() expects packages to register HTTP handlers in their init()
// functions.
func init() {
    http.HandleFunc("/", IndexHandler)
}

func main() {
    // Starts listening on port 8080 (or $PORT), and never returns.
    // https://godoc.org/google.golang.org/appengine#Main
    appengine.Main()
}
<commit_msg>Set charset to UTF-8<commit_after>package main

import (
    "fmt"
    "net/http"
    "strings"
    "google.golang.org/appengine"
)

// Trivially routes requests to the correct response function.
func IndexHandler(w http.ResponseWriter, r *http.Request) {
    switch r.URL.Path {
        case "/":
            switch r.Method {
                case http.MethodGet:
                    GetIndex(w, r)
                default:
                    NotFound(w, r)
            }
        default:
            NotFound(w, r)
    }
}

// Returns the client's IP address.
func GetIndex(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusOK)
    w.Header().Set("Content-Type", "text/plain; charset=UTF-8")

    // RemoteAddr is formatted as host:port, so we just trim off the port here
    // and return the IP.
    fmt.Fprint(w, strings.Split(r.RemoteAddr, ":")[0])
}

// Returns a 404 Not Found page.
func NotFound(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusNotFound)
    w.Header().Set("Content-Type", "text/plain; charset=UTF-8")
    fmt.Fprintf(w, "%d Not Found", http.StatusNotFound)
}

// appengine.Main() expects packages to register HTTP handlers in their init()
// functions.
func init() {
    http.HandleFunc("/", IndexHandler)
}

func main() {
    // Starts listening on port 8080 (or $PORT), and never returns.
    // https://godoc.org/google.golang.org/appengine#Main
    appengine.Main()
}
<|endoftext|>


<commit_before>package goselenium

// Keyboard keys converted from the ASCII code.
const (
	UnidentifiedKey   = string('\uE000')
	CancelKey         = string('\uE001')
	HelpKey           = string('\uE002')
	BackspaceKey      = string('\uE003')
	TabKey            = string('\uE004')
	ClearKey          = string('\uE005')
	ReturnKey         = string('\uE006')
	EnterKey          = string('\uE007')
	ShiftKey          = string('\uE008')
	ControlKey        = string('\uE009')
	AltKey            = string('\uE00A')
	PauseKey          = string('\uE00B')
	EscapeKey         = string('\uE00C')
	SpaceKey          = string('\uE00D')
	PageUpKey         = string('\uE00E')
	PageDownKey       = string('\uE00F')
	EndKey            = string('\uE010')
	HomeKey           = string('\uE011')
	ArrowLeftKey      = string('\uE012')
	ArrowUpKey        = string('\uE013')
	ArrowRightKey     = string('\uE014')
	ArrowDownKey      = string('\uE015')
	InsertKey         = string('\uE016')
	DeleteKey         = string('\uE017')
	SemiColonKey      = string('\uE018')
	EqualsKey         = string('\uE019')
	AsteriskKey       = string('\uE024')
	PlusKey           = string('\uE025')
	CommaKey          = string('\uE026')
	MinusKey          = string('\uE027')
	PeriodKey         = string('\uE028')
	ForwardSlashKey   = string('\uE029')
	F1Key             = string('\uE031')
	F2Key             = string('\uE032')
	F3Key             = string('\uE033')
	F4Key             = string('\uE034')
	F5Key             = string('\uE035')
	F6Key             = string('\uE036')
	F7Key             = string('\uE037')
	F8Key             = string('\uE038')
	F9Key             = string('\uE039')
	F10Key            = string('\uE03A')
	F11Key            = string('\uE03B')
	F12Key            = string('\uE03C')
	MetaKey           = string('\uE03D')
	ZenkakuHankakuKey = string('\uE040')
)

// Error codes that are returned from Selenium. Infer that the
// type of the error returned is CommunicationError, then do a comparison
// on the err.Response.State field to one of the below constants.
const (
	ElementNotSelectable   = "element not selectable"
	ElementNotInteractable = "element not interactable"
	InsecureCertificate    = "insecure certificate"
	InvalidArgument        = "invalid argument"
	InvalidCookieDomain    = "invalid cookie domain"
	InvalidCoordinates     = "invalid coordinates"
	InvalidElementState    = "invalid element state"
	InvalidSelector        = "invalid selector"
	InvalidSessionID       = "invalid session id"
	JavascriptError        = "javascript error"
	MoveTargetOutOfBounds  = "move target out of bounds"
	NoSuchAlert            = "no such alert"
	NoSuchCookie           = "no such cookie"
	NoSuchElement          = "no such element"
	NoSuchFrame            = "no such frame"
	NoSuchWindow           = "no such window"
	ScriptTimeout          = "script timeout"
	SessionNotCreated      = "session not created"
	StaleElementReference  = "stale element reference"
	TimeoutError           = "timeout"
	UnableToSetCookie      = "unable to set cookie"
	UnableToCaptureScreen  = "unable to capture screen"
	UnexpectedAlertOpen    = "unexpected alert open"
	UnknownCommand         = "unknown command"
	UnknownError           = "unknown error"
	UnknownMethod          = "unknown method"
	UnsupportedOperation   = "unsupported operation"
)

// WebDriver is an interface which adheres to the W3C specification
// for WebDrivers (https://w3c.github.io/webdriver/webdriver-spec.html).
type WebDriver interface {
	/*
		PROPERTY ACCESS METHODS
	*/

	// DriverURL returns the URL where the W3C compliant web driver is hosted.
	DriverURL() string

	/*
		SESSION METHODS
	*/

	// CreateSession creates a session in the remote driver with the
	// desired capabilities.
	CreateSession() (*CreateSessionResponse, error)

	// DeleteSession deletes the current session associated with the web driver.
	DeleteSession() (*DeleteSessionResponse, error)

	// SessionStatus gets the status about whether a remove end is in a state
	// which it can create new sessions.
	SessionStatus() (*SessionStatusResponse, error)

	// SetSessionTimeout sets a timeout for one of the 3 options.
	// Call SessionScriptTimeout() to generate a script timeout.
	// Call SessionPageLoadTimeout() to generate a page load timeout.
	// Call SessionImplicitWaitTimeout() to generate an implicit wait timeout.
	SetSessionTimeout(to Timeout) (*SetSessionTimeoutResponse, error)

	/*
		NAVIGATION METHODS
	*/

	// Go forces the browser to perform a GET request on a URL.
	Go(url string) (*GoResponse, error)

	// CurrentURL returns the current URL of the top level browsing context.
	CurrentURL() (*CurrentURLResponse, error)

	// Back instructs the web driver to go one step back in the page history.
	Back() (*BackResponse, error)

	// Forward instructs the web driver to go one step forward in the page history.
	Forward() (*ForwardResponse, error)

	// Refresh instructs the web driver to refresh the page that it is currently on.
	Refresh() (*RefreshResponse, error)

	// Title gets the title of the current page of the web driver.
	Title() (*TitleResponse, error)

	/*
		COMMAND METHODS
	*/

	// WindowHandle retrieves the current active browsing string for the current session.
	WindowHandle() (*WindowHandleResponse, error)

	// CloseWindow closes the current active window (see WindowHandle() for what
	// window that will be).
	CloseWindow() (*CloseWindowResponse, error)

	// SwitchToWindow switches the current browsing context to a specified window
	// handle.
	SwitchToWindow(handle string) (*SwitchToWindowResponse, error)

	// WindowHandles gets all of the window handles for the current session.
	// To retrieve the currently active window handle, see WindowHandle().
	WindowHandles() (*WindowHandlesResponse, error)

	// SwitchToFrame switches to a frame determined by the "by" parameter.
	// You can use ByIndex to find the frame to switch to. Any other
	// By implementation will yield an InvalidByParameter error.
	SwitchToFrame(by By) (*SwitchToFrameResponse, error)

	// SwitchToParentFrame switches to the parent of the current top level
	// browsing context.
	SwitchToParentFrame() (*SwitchToParentFrameResponse, error)

	// WindowSize retrieves the current browser window size for the
	// active session.
	WindowSize() (*WindowSizeResponse, error)

	// SetWindowSize sets the current browser window size for the active
	// session.
	SetWindowSize(dimensions *Dimensions) (*SetWindowSizeResponse, error)

	// Maximize increases the current browser window to its maximum size.
	MaximizeWindow() (*MaximizeWindowResponse, error)

	/*
		ELEMENT METHODS
	*/

	// FindElement finds an element via a By implementation (i.e. CSS selector,
	// x-path). Attempting to find via index will result in an argument error
	// being thrown.
	FindElement(by By) (Element, error)

	// FindElements works the same way as FindElement but can return more than
	// one result.
	FindElements(by By) ([]Element, error)

	/*
		DOCUMENT HANDLING METHODS
	*/

	// PageSource retrieves the outerHTML value of the current URL.
	PageSource() (*PageSourceResponse, error)

	// ExecuteScript executes a Javascript script on the currently active
	// page.
	ExecuteScript(script string) (*ExecuteScriptResponse, error)

	// ExecuteScriptAsync executes a Javascript script asynchronously on the
	// currently active page. If you do not have experience with this call,
	// there is an example below.
	//
	// The async handler runs on the concept of a callback; meaning it will run
	// your code asynchronously and if it completes, will call the callback.
	//
	// Selenium helpfully provides a callback function which is passed in
	// to the 'arguments' array that you can access within your script. The
	// callback function is always the LAST element of the array. You can
	// access it like the below:
	//		var callback = arguments[arguments.length - 1];
	// The callback function also accepts one argument as a parameter, this
	// can be anything and will be assigned to the Response property of
	// ExecuteScriptResponse.
	//
	// An example:
	//		var callback = arguments[arguments.length - 1];
	//		doLongWindedTask();
	//		callback();
	ExecuteScriptAsync(script string) (*ExecuteScriptResponse, error)

	/*
		COOKIE METHODS
	*/

	// AllCookies returns all cookies associated with the active URL of the
	// current browsing context.
	AllCookies() (*AllCookiesResponse, error)

	// Cookie gets a single named cookie associated with the active URL of the
	// current browsing context.
	Cookie(name string) (*CookieResponse, error)

	// AddCookie adds a cookie to the current browsing context.
	AddCookie(c *Cookie) (*AddCookieResponse, error)

	// DeleteCookie deletes a cookie from the current browsing session. If name
	// is passed as an empty string, all cookies for the current address will
	// be deleted.
	DeleteCookie(name string) (*DeleteCookieResponse, error)

	/*
		ALERT METHODS
	*/

	// DismissAlert dismisses an alert if there is one present. If not, it will
	// throw an error.
	DismissAlert() (*DismissAlertResponse, error)

	// AcceptAlertResponse accepts an alert if there is one present. If not,
	// it will throw an error.
	AcceptAlert() (*AcceptAlertResponse, error)

	// AlertText gets the text associated with the current alert. If there is
	// not an alert, it will throw an error.
	AlertText() (*AlertTextResponse, error)

	// SendAlertText enters the text specified into the value box.
	//
	// If the prompt is of type 'alert' or 'confirm', a communication error
	// with code 'element not interactable' will be returned.
	//
	// If the prompt is anything other than 'prompt', a communication error with
	// code 'unsupported operation' will be returned.
	SendAlertText(text string) (*SendAlertTextResponse, error)

	/*
		SCREEN CAPTURE METHODS
	*/

	// Screenshot takes a screenshot of the window of the current top level
	// browsing context.
	Screenshot() (*ScreenshotResponse, error)
}

// Element is an interface which specifies what all WebDriver elements
// must do. Any requests which involve this element (i.e. FindElements that
// are children of the current element) will be specified. Anything not related
// will exist within the WebDriver interface/implementation.
type Element interface {
	// ID is the assigned ID for the element returned from the Selenium driver.
	ID() string

	// Selected gets whether or not the current element is selected. This only
	// makes sense for inputs such as radio buttons and checkboxes.
	Selected() (*ElementSelectedResponse, error)

	// Attribute retrieves an attribute (i.e. href, class) of the current
	// active element.
	Attribute(att string) (*ElementAttributeResponse, error)

	// CSSValue retrieves a CSS property associated with the current element.
	// As an example, this could be the 'background' or 'font-family' properties.
	CSSValue(prop string) (*ElementCSSValueResponse, error)

	// Text gets the value of element.innerText for the current element.
	Text() (*ElementTextResponse, error)

	// TagName gets the HTML element name (i.e. p, div) of the currently selected
	// element.
	TagName() (*ElementTagNameResponse, error)

	// Rectangle gets the dimensions and co-ordinates of the currently selected
	// element.
	Rectangle() (*ElementRectangleResponse, error)

	// Enabled gets whether or not the current selected elemented is enabled.
	Enabled() (*ElementEnabledResponse, error)

	// Click clicks the currently selected element. Please note, you may have to
	// implement your own wait to ensure the page actually navigates. This is due to
	// Selenium having no idea whether or not your click will be interrupted by JS.
	// Alternatively, you can use the WaitUntil(TitleEquals("title"), 20) to
	// automatically wait until the page title has changed.
	Click() (*ElementClickResponse, error)

	// Clear clears the currently selected element according to the specification.
	Clear() (*ElementClearResponse, error)

	// SendKeys sends a set of keystrokes to the currently selected element.
	SendKeys(keys string) (*ElementSendKeysResponse, error)

	// Screenshot takes a screenshot of the currently selected element.
	Screenshot() (*ScreenshotResponse, error)
}

// Timeout is an interface which specifies what all timeout requests must follow.
type Timeout interface {
	// Type is the type of the timeout that is being used.
	Type() string

	// Timeout is the timeout in milliseconds.
	Timeout() int
}

// By is an interface that defines what all 'ByX' methods must return.
type By interface {
	// Type is the type of by (i.e. id, xpath, class, name, index).
	Type() string

	// Value is the actual value to retrieve something by (i.e. #test, 1).
	Value() interface{}
}
<commit_msg>Remove Element screenshot functionality as it does not exist via the web driver.<commit_after>package goselenium

// Keyboard keys converted from the ASCII code.
const (
	UnidentifiedKey   = string('\uE000')
	CancelKey         = string('\uE001')
	HelpKey           = string('\uE002')
	BackspaceKey      = string('\uE003')
	TabKey            = string('\uE004')
	ClearKey          = string('\uE005')
	ReturnKey         = string('\uE006')
	EnterKey          = string('\uE007')
	ShiftKey          = string('\uE008')
	ControlKey        = string('\uE009')
	AltKey            = string('\uE00A')
	PauseKey          = string('\uE00B')
	EscapeKey         = string('\uE00C')
	SpaceKey          = string('\uE00D')
	PageUpKey         = string('\uE00E')
	PageDownKey       = string('\uE00F')
	EndKey            = string('\uE010')
	HomeKey           = string('\uE011')
	ArrowLeftKey      = string('\uE012')
	ArrowUpKey        = string('\uE013')
	ArrowRightKey     = string('\uE014')
	ArrowDownKey      = string('\uE015')
	InsertKey         = string('\uE016')
	DeleteKey         = string('\uE017')
	SemiColonKey      = string('\uE018')
	EqualsKey         = string('\uE019')
	AsteriskKey       = string('\uE024')
	PlusKey           = string('\uE025')
	CommaKey          = string('\uE026')
	MinusKey          = string('\uE027')
	PeriodKey         = string('\uE028')
	ForwardSlashKey   = string('\uE029')
	F1Key             = string('\uE031')
	F2Key             = string('\uE032')
	F3Key             = string('\uE033')
	F4Key             = string('\uE034')
	F5Key             = string('\uE035')
	F6Key             = string('\uE036')
	F7Key             = string('\uE037')
	F8Key             = string('\uE038')
	F9Key             = string('\uE039')
	F10Key            = string('\uE03A')
	F11Key            = string('\uE03B')
	F12Key            = string('\uE03C')
	MetaKey           = string('\uE03D')
	ZenkakuHankakuKey = string('\uE040')
)

// Error codes that are returned from Selenium. Infer that the
// type of the error returned is CommunicationError, then do a comparison
// on the err.Response.State field to one of the below constants.
const (
	ElementNotSelectable   = "element not selectable"
	ElementNotInteractable = "element not interactable"
	InsecureCertificate    = "insecure certificate"
	InvalidArgument        = "invalid argument"
	InvalidCookieDomain    = "invalid cookie domain"
	InvalidCoordinates     = "invalid coordinates"
	InvalidElementState    = "invalid element state"
	InvalidSelector        = "invalid selector"
	InvalidSessionID       = "invalid session id"
	JavascriptError        = "javascript error"
	MoveTargetOutOfBounds  = "move target out of bounds"
	NoSuchAlert            = "no such alert"
	NoSuchCookie           = "no such cookie"
	NoSuchElement          = "no such element"
	NoSuchFrame            = "no such frame"
	NoSuchWindow           = "no such window"
	ScriptTimeout          = "script timeout"
	SessionNotCreated      = "session not created"
	StaleElementReference  = "stale element reference"
	TimeoutError           = "timeout"
	UnableToSetCookie      = "unable to set cookie"
	UnableToCaptureScreen  = "unable to capture screen"
	UnexpectedAlertOpen    = "unexpected alert open"
	UnknownCommand         = "unknown command"
	UnknownError           = "unknown error"
	UnknownMethod          = "unknown method"
	UnsupportedOperation   = "unsupported operation"
)

// WebDriver is an interface which adheres to the W3C specification
// for WebDrivers (https://w3c.github.io/webdriver/webdriver-spec.html).
type WebDriver interface {
	/*
		PROPERTY ACCESS METHODS
	*/

	// DriverURL returns the URL where the W3C compliant web driver is hosted.
	DriverURL() string

	/*
		SESSION METHODS
	*/

	// CreateSession creates a session in the remote driver with the
	// desired capabilities.
	CreateSession() (*CreateSessionResponse, error)

	// DeleteSession deletes the current session associated with the web driver.
	DeleteSession() (*DeleteSessionResponse, error)

	// SessionStatus gets the status about whether a remove end is in a state
	// which it can create new sessions.
	SessionStatus() (*SessionStatusResponse, error)

	// SetSessionTimeout sets a timeout for one of the 3 options.
	// Call SessionScriptTimeout() to generate a script timeout.
	// Call SessionPageLoadTimeout() to generate a page load timeout.
	// Call SessionImplicitWaitTimeout() to generate an implicit wait timeout.
	SetSessionTimeout(to Timeout) (*SetSessionTimeoutResponse, error)

	/*
		NAVIGATION METHODS
	*/

	// Go forces the browser to perform a GET request on a URL.
	Go(url string) (*GoResponse, error)

	// CurrentURL returns the current URL of the top level browsing context.
	CurrentURL() (*CurrentURLResponse, error)

	// Back instructs the web driver to go one step back in the page history.
	Back() (*BackResponse, error)

	// Forward instructs the web driver to go one step forward in the page history.
	Forward() (*ForwardResponse, error)

	// Refresh instructs the web driver to refresh the page that it is currently on.
	Refresh() (*RefreshResponse, error)

	// Title gets the title of the current page of the web driver.
	Title() (*TitleResponse, error)

	/*
		COMMAND METHODS
	*/

	// WindowHandle retrieves the current active browsing string for the current session.
	WindowHandle() (*WindowHandleResponse, error)

	// CloseWindow closes the current active window (see WindowHandle() for what
	// window that will be).
	CloseWindow() (*CloseWindowResponse, error)

	// SwitchToWindow switches the current browsing context to a specified window
	// handle.
	SwitchToWindow(handle string) (*SwitchToWindowResponse, error)

	// WindowHandles gets all of the window handles for the current session.
	// To retrieve the currently active window handle, see WindowHandle().
	WindowHandles() (*WindowHandlesResponse, error)

	// SwitchToFrame switches to a frame determined by the "by" parameter.
	// You can use ByIndex to find the frame to switch to. Any other
	// By implementation will yield an InvalidByParameter error.
	SwitchToFrame(by By) (*SwitchToFrameResponse, error)

	// SwitchToParentFrame switches to the parent of the current top level
	// browsing context.
	SwitchToParentFrame() (*SwitchToParentFrameResponse, error)

	// WindowSize retrieves the current browser window size for the
	// active session.
	WindowSize() (*WindowSizeResponse, error)

	// SetWindowSize sets the current browser window size for the active
	// session.
	SetWindowSize(dimensions *Dimensions) (*SetWindowSizeResponse, error)

	// Maximize increases the current browser window to its maximum size.
	MaximizeWindow() (*MaximizeWindowResponse, error)

	/*
		ELEMENT METHODS
	*/

	// FindElement finds an element via a By implementation (i.e. CSS selector,
	// x-path). Attempting to find via index will result in an argument error
	// being thrown.
	FindElement(by By) (Element, error)

	// FindElements works the same way as FindElement but can return more than
	// one result.
	FindElements(by By) ([]Element, error)

	/*
		DOCUMENT HANDLING METHODS
	*/

	// PageSource retrieves the outerHTML value of the current URL.
	PageSource() (*PageSourceResponse, error)

	// ExecuteScript executes a Javascript script on the currently active
	// page.
	ExecuteScript(script string) (*ExecuteScriptResponse, error)

	// ExecuteScriptAsync executes a Javascript script asynchronously on the
	// currently active page. If you do not have experience with this call,
	// there is an example below.
	//
	// The async handler runs on the concept of a callback; meaning it will run
	// your code asynchronously and if it completes, will call the callback.
	//
	// Selenium helpfully provides a callback function which is passed in
	// to the 'arguments' array that you can access within your script. The
	// callback function is always the LAST element of the array. You can
	// access it like the below:
	//		var callback = arguments[arguments.length - 1];
	// The callback function also accepts one argument as a parameter, this
	// can be anything and will be assigned to the Response property of
	// ExecuteScriptResponse.
	//
	// An example:
	//		var callback = arguments[arguments.length - 1];
	//		doLongWindedTask();
	//		callback();
	ExecuteScriptAsync(script string) (*ExecuteScriptResponse, error)

	/*
		COOKIE METHODS
	*/

	// AllCookies returns all cookies associated with the active URL of the
	// current browsing context.
	AllCookies() (*AllCookiesResponse, error)

	// Cookie gets a single named cookie associated with the active URL of the
	// current browsing context.
	Cookie(name string) (*CookieResponse, error)

	// AddCookie adds a cookie to the current browsing context.
	AddCookie(c *Cookie) (*AddCookieResponse, error)

	// DeleteCookie deletes a cookie from the current browsing session. If name
	// is passed as an empty string, all cookies for the current address will
	// be deleted.
	DeleteCookie(name string) (*DeleteCookieResponse, error)

	/*
		ALERT METHODS
	*/

	// DismissAlert dismisses an alert if there is one present. If not, it will
	// throw an error.
	DismissAlert() (*DismissAlertResponse, error)

	// AcceptAlertResponse accepts an alert if there is one present. If not,
	// it will throw an error.
	AcceptAlert() (*AcceptAlertResponse, error)

	// AlertText gets the text associated with the current alert. If there is
	// not an alert, it will throw an error.
	AlertText() (*AlertTextResponse, error)

	// SendAlertText enters the text specified into the value box.
	//
	// If the prompt is of type 'alert' or 'confirm', a communication error
	// with code 'element not interactable' will be returned.
	//
	// If the prompt is anything other than 'prompt', a communication error with
	// code 'unsupported operation' will be returned.
	SendAlertText(text string) (*SendAlertTextResponse, error)

	/*
		SCREEN CAPTURE METHODS
	*/

	// Screenshot takes a screenshot of the window of the current top level
	// browsing context.
	Screenshot() (*ScreenshotResponse, error)
}

// Element is an interface which specifies what all WebDriver elements
// must do. Any requests which involve this element (i.e. FindElements that
// are children of the current element) will be specified. Anything not related
// will exist within the WebDriver interface/implementation.
type Element interface {
	// ID is the assigned ID for the element returned from the Selenium driver.
	ID() string

	// Selected gets whether or not the current element is selected. This only
	// makes sense for inputs such as radio buttons and checkboxes.
	Selected() (*ElementSelectedResponse, error)

	// Attribute retrieves an attribute (i.e. href, class) of the current
	// active element.
	Attribute(att string) (*ElementAttributeResponse, error)

	// CSSValue retrieves a CSS property associated with the current element.
	// As an example, this could be the 'background' or 'font-family' properties.
	CSSValue(prop string) (*ElementCSSValueResponse, error)

	// Text gets the value of element.innerText for the current element.
	Text() (*ElementTextResponse, error)

	// TagName gets the HTML element name (i.e. p, div) of the currently selected
	// element.
	TagName() (*ElementTagNameResponse, error)

	// Rectangle gets the dimensions and co-ordinates of the currently selected
	// element.
	Rectangle() (*ElementRectangleResponse, error)

	// Enabled gets whether or not the current selected elemented is enabled.
	Enabled() (*ElementEnabledResponse, error)

	// Click clicks the currently selected element. Please note, you may have to
	// implement your own wait to ensure the page actually navigates. This is due to
	// Selenium having no idea whether or not your click will be interrupted by JS.
	// Alternatively, you can use the WaitUntil(TitleEquals("title"), 20) to
	// automatically wait until the page title has changed.
	Click() (*ElementClickResponse, error)

	// Clear clears the currently selected element according to the specification.
	Clear() (*ElementClearResponse, error)

	// SendKeys sends a set of keystrokes to the currently selected element.
	SendKeys(keys string) (*ElementSendKeysResponse, error)
}

// Timeout is an interface which specifies what all timeout requests must follow.
type Timeout interface {
	// Type is the type of the timeout that is being used.
	Type() string

	// Timeout is the timeout in milliseconds.
	Timeout() int
}

// By is an interface that defines what all 'ByX' methods must return.
type By interface {
	// Type is the type of by (i.e. id, xpath, class, name, index).
	Type() string

	// Value is the actual value to retrieve something by (i.e. #test, 1).
	Value() interface{}
}
<|endoftext|>


<commit_before>package vm

import (
	"fmt"
	"github.com/goby-lang/goby/bytecode"
	"github.com/goby-lang/goby/parser"
	"io/ioutil"
	"path"
	"strconv"
	"strings"
)

// bytecodeParser is responsible for parsing bytecodes
type bytecodeParser struct {
	line       int
	labelTable map[labelType]map[string][]*instructionSet
	vm         *VM
	filename   filename
	blockTable map[string]*instructionSet
	program    *instructionSet
}

// newBytecodeParser initializes bytecodeParser and its label table then returns it
func newBytecodeParser(file filename) *bytecodeParser {
	p := &bytecodeParser{filename: file}
	p.blockTable = make(map[string]*instructionSet)
	p.labelTable = map[labelType]map[string][]*instructionSet{
		bytecode.LabelDef:      make(map[string][]*instructionSet),
		bytecode.LabelDefClass: make(map[string][]*instructionSet),
	}

	return p
}

// parseBytecode parses given bytecodes and transfer them into a sequence of instruction set.
func (p *bytecodeParser) parseBytecode(bytecodes string) []*instructionSet {
	iss := []*instructionSet{}
	bytecodes = strings.TrimSpace(bytecodes)
	bytecodesByLine := strings.Split(bytecodes, "\n")

	defer func() {
		if p := recover(); p != nil {
			switch p.(type) {
			case errorMessage:
				return
			default:
				panic(p)
			}
		}
	}()

	p.parseSection(iss, bytecodesByLine)

	return iss
}

func (p *bytecodeParser) parseSection(iss []*instructionSet, bytecodesByLine []string) {
	is := &instructionSet{filename: p.filename}
	count := 0

	// First line is label
	p.parseLabel(is, bytecodesByLine[0])

	for _, text := range bytecodesByLine[1:] {
		count++
		l := strings.TrimSpace(text)
		if strings.HasPrefix(l, "<") {
			p.parseSection(iss, bytecodesByLine[count:])
			break
		} else {
			p.parseInstruction(is, l)
		}
	}

	iss = append(iss, is)
}

func (p *bytecodeParser) parseLabel(is *instructionSet, line string) {
	line = strings.Trim(line, "<")
	line = strings.Trim(line, ">")
	p.setLabel(is, line)
}

func (p *bytecodeParser) setLabel(is *instructionSet, name string) {
	var l *label
	var ln string
	var lt labelType

	if name == bytecode.Program {
		p.program = is
		return
	} else {
		ln = strings.Split(name, ":")[1]
		lt = labelType(strings.Split(name, ":")[0])
	}

	l = &label{name: name, Type: lt}
	is.label = l

	if lt == bytecode.Block {
		p.blockTable[ln] = is
		return
	}

	p.labelTable[lt][ln] = append(p.labelTable[lt][ln], is)
}

// parseInstruction transfer a line of bytecode into an instruction and append it into given instruction set.
func (p *bytecodeParser) parseInstruction(is *instructionSet, line string) {
	var params []interface{}
	var rawParams []string

	tokens := strings.Split(line, " ")
	lineNum, act := tokens[0], tokens[1]
	ln, _ := strconv.ParseInt(lineNum, 0, 64)
	action := builtInActions[operationType(act)]

	if act == bytecode.PutString {
		text := strings.Split(line, "\"")[1]
		params = append(params, text)
	} else if act == bytecode.RequireRelative {
		filepath := tokens[2]
		filepath = path.Join(p.vm.fileDir, filepath)

		file, err := ioutil.ReadFile(filepath + ".gb")

		if err != nil {
			panic(err)
		}

		p.execRequiredFile(filepath, file)
		return
	} else if act == bytecode.Require {
		libName := tokens[2]
		initFunc, ok := standardLibraris[libName]

		if !ok {
			msg := "Can't require \"" + libName + "\""
			p.vm.returnError(msg)
		}

		initFunc(p.vm)
		return
	} else if len(tokens) > 2 {
		rawParams = tokens[2:]

		for _, param := range rawParams {
			params = append(params, p.parseParam(param))
		}
	} else if action == nil {
		panic(fmt.Sprintf("Unknown command: %s. line: %d", act, ln))
	}

	is.define(int(ln), action, params...)
}

func (p *bytecodeParser) parseParam(param string) interface{} {
	integer, e := strconv.ParseInt(param, 0, 64)
	if e != nil {
		return param
	}

	i := int(integer)

	return i
}

func (p *bytecodeParser) execRequiredFile(filepath string, file []byte) {
	program := parser.BuildAST(file)
	g := bytecode.NewGenerator(program)
	bytecodes := g.GenerateByteCode(program)
	p.vm.ExecBytecodes(bytecodes, filepath)
}
<commit_msg>fix typo in bytecode_parser.go as well<commit_after>package vm

import (
	"fmt"
	"github.com/goby-lang/goby/bytecode"
	"github.com/goby-lang/goby/parser"
	"io/ioutil"
	"path"
	"strconv"
	"strings"
)

// bytecodeParser is responsible for parsing bytecodes
type bytecodeParser struct {
	line       int
	labelTable map[labelType]map[string][]*instructionSet
	vm         *VM
	filename   filename
	blockTable map[string]*instructionSet
	program    *instructionSet
}

// newBytecodeParser initializes bytecodeParser and its label table then returns it
func newBytecodeParser(file filename) *bytecodeParser {
	p := &bytecodeParser{filename: file}
	p.blockTable = make(map[string]*instructionSet)
	p.labelTable = map[labelType]map[string][]*instructionSet{
		bytecode.LabelDef:      make(map[string][]*instructionSet),
		bytecode.LabelDefClass: make(map[string][]*instructionSet),
	}

	return p
}

// parseBytecode parses given bytecodes and transfer them into a sequence of instruction set.
func (p *bytecodeParser) parseBytecode(bytecodes string) []*instructionSet {
	iss := []*instructionSet{}
	bytecodes = strings.TrimSpace(bytecodes)
	bytecodesByLine := strings.Split(bytecodes, "\n")

	defer func() {
		if p := recover(); p != nil {
			switch p.(type) {
			case errorMessage:
				return
			default:
				panic(p)
			}
		}
	}()

	p.parseSection(iss, bytecodesByLine)

	return iss
}

func (p *bytecodeParser) parseSection(iss []*instructionSet, bytecodesByLine []string) {
	is := &instructionSet{filename: p.filename}
	count := 0

	// First line is label
	p.parseLabel(is, bytecodesByLine[0])

	for _, text := range bytecodesByLine[1:] {
		count++
		l := strings.TrimSpace(text)
		if strings.HasPrefix(l, "<") {
			p.parseSection(iss, bytecodesByLine[count:])
			break
		} else {
			p.parseInstruction(is, l)
		}
	}

	iss = append(iss, is)
}

func (p *bytecodeParser) parseLabel(is *instructionSet, line string) {
	line = strings.Trim(line, "<")
	line = strings.Trim(line, ">")
	p.setLabel(is, line)
}

func (p *bytecodeParser) setLabel(is *instructionSet, name string) {
	var l *label
	var ln string
	var lt labelType

	if name == bytecode.Program {
		p.program = is
		return
	} else {
		ln = strings.Split(name, ":")[1]
		lt = labelType(strings.Split(name, ":")[0])
	}

	l = &label{name: name, Type: lt}
	is.label = l

	if lt == bytecode.Block {
		p.blockTable[ln] = is
		return
	}

	p.labelTable[lt][ln] = append(p.labelTable[lt][ln], is)
}

// parseInstruction transfer a line of bytecode into an instruction and append it into given instruction set.
func (p *bytecodeParser) parseInstruction(is *instructionSet, line string) {
	var params []interface{}
	var rawParams []string

	tokens := strings.Split(line, " ")
	lineNum, act := tokens[0], tokens[1]
	ln, _ := strconv.ParseInt(lineNum, 0, 64)
	action := builtInActions[operationType(act)]

	if act == bytecode.PutString {
		text := strings.Split(line, "\"")[1]
		params = append(params, text)
	} else if act == bytecode.RequireRelative {
		filepath := tokens[2]
		filepath = path.Join(p.vm.fileDir, filepath)

		file, err := ioutil.ReadFile(filepath + ".gb")

		if err != nil {
			panic(err)
		}

		p.execRequiredFile(filepath, file)
		return
	} else if act == bytecode.Require {
		libName := tokens[2]
		initFunc, ok := standardLibraries[libName]

		if !ok {
			msg := "Can't require \"" + libName + "\""
			p.vm.returnError(msg)
		}

		initFunc(p.vm)
		return
	} else if len(tokens) > 2 {
		rawParams = tokens[2:]

		for _, param := range rawParams {
			params = append(params, p.parseParam(param))
		}
	} else if action == nil {
		panic(fmt.Sprintf("Unknown command: %s. line: %d", act, ln))
	}

	is.define(int(ln), action, params...)
}

func (p *bytecodeParser) parseParam(param string) interface{} {
	integer, e := strconv.ParseInt(param, 0, 64)
	if e != nil {
		return param
	}

	i := int(integer)

	return i
}

func (p *bytecodeParser) execRequiredFile(filepath string, file []byte) {
	program := parser.BuildAST(file)
	g := bytecode.NewGenerator(program)
	bytecodes := g.GenerateByteCode(program)
	p.vm.ExecBytecodes(bytecodes, filepath)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"log"
	"os/exec"

	"github.com/gophergala/go_ne/core"
)

type Local struct {
}

func NewLocalRunner() (*Local, error) {
	return &Local{}, nil
}

func (l *Local) Run(task core.Task) {
	cmd := exec.Command(task.Name(), task.Args()...)
	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run(); if err != nil {
		log.Fatal(err)
	}
	fmt.Println(out.String())
}
<commit_msg>Added log for each step<commit_after>package main

import (
	"bytes"
	"fmt"
	"log"
	"os/exec"
	"strings"

	"github.com/gophergala/go_ne/core"
)

type Local struct {
}

func NewLocalRunner() (*Local, error) {
	return &Local{}, nil
}

func (l *Local) Run(task core.Task) {
	log.Printf("Running task: %v %v\n", task.Name(), strings.Join(task.Args(), " "))

	cmd := exec.Command(task.Name(), task.Args()...)
	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(out.String())
}
<|endoftext|>