<commit_before>package som

import (
	"fmt"
	"math"

	"github.com/gonum/matrix/mat64"
)

// Distance calculates a distance metric between vectors a and b.
// If unsupported metric is requested DistVector returns euclidean ddistance.
// It returns error if the supplied vectors are either nil are different dimension
func Distance(metric string, a, b *mat64.Vector) (float64, error) {
	switch metric {
	case "euclidean":
		return euclideanVec(a, b)
	default:
		return euclideanVec(a, b)
	}
}

// DistanceMx calculates a distance matrix for the given matrix using the given method.
// It returns a hollow symmetric matrix where an item x_ij contains the distance between
// vectors stored in rows i and j. You can request different distance metrics via metric
// parameter. If an unknown metric is supplied Euclidean distance is computed.
func DistanceMx(metric string, matrix *mat64.Dense) (*mat64.Dense, error) {
	switch metric {
	case "euclidean":
		return euclideanMx(matrix)
	default:
		return euclideanMx(matrix)
	}
}

// euclideanVec computes euclidean distances between vectors a and b.
// It returns error if the supplied vectors are either nil are different dimension
func euclideanVec(a, b *mat64.Vector) (float64, error) {
	if a == nil || b == nil {
		return 0.0, fmt.Errorf("Invalid vectors supplied. a: %v, b: %v\n", a, b)
	}
	if a.Len() != b.Len() {
		return 0.0, fmt.Errorf("Incorrect vector dims. a: %d, b: %d\n", a.Len(), b.Len())
	}

	d := mat64.NewVector(a.Len(), nil)
	d.ScaleVec(-1.0, b)
	d.AddVec(a, d)
	d.MulElemVec(d, d)

	return math.Sqrt(mat64.Sum(d)), nil
}

func euclideanMx(in *mat64.Dense) (*mat64.Dense, error) {
	if in == nil {
		return nil, fmt.Errorf("Invalid matrix supplied: %v\n", in)
	}

	rows, _ := in.Dims()
	out := mat64.NewDense(rows, rows, nil)

	for row := 0; row < rows-1; row++ {
		dist := 0.0
		a := in.RowView(row)
		for i := row + 1; i < rows; i++ {
			if i != row {
				b := in.RowView(i)
				dist, _ = euclideanVec(a, b)
				out.Set(row, i, dist)
				out.Set(i, row, dist)
			}
		}
	}

	return out, nil
}
<commit_msg>Distance calculation optimization - avoiding allocation<commit_after>package som

import (
	"fmt"
	"math"

	"github.com/gonum/matrix/mat64"
)

// Distance calculates a distance metric between vectors a and b.
// If unsupported metric is requested DistVector returns euclidean ddistance.
// It returns error if the supplied vectors are either nil are different dimension
func Distance(metric string, a, b *mat64.Vector) (float64, error) {
	switch metric {
	case "euclidean":
		return euclideanVec(a, b)
	default:
		return euclideanVec(a, b)
	}
}

// DistanceMx calculates a distance matrix for the given matrix using the given method.
// It returns a hollow symmetric matrix where an item x_ij contains the distance between
// vectors stored in rows i and j. You can request different distance metrics via metric
// parameter. If an unknown metric is supplied Euclidean distance is computed.
func DistanceMx(metric string, matrix *mat64.Dense) (*mat64.Dense, error) {
	switch metric {
	case "euclidean":
		return euclideanMx(matrix)
	default:
		return euclideanMx(matrix)
	}
}

// euclideanVec computes euclidean distances between vectors a and b.
// It returns error if the supplied vectors are either nil are different dimension
func euclideanVec(a, b *mat64.Vector) (float64, error) {
	if a == nil || b == nil {
		return 0.0, fmt.Errorf("Invalid vectors supplied. a: %v, b: %v\n", a, b)
	}
	if a.Len() != b.Len() {
		return 0.0, fmt.Errorf("Incorrect vector dims. a: %d, b: %d\n", a.Len(), b.Len())
	}

	aData := a.RawVector().Data
	bData := b.RawVector().Data
	d := 0.0
	for i := 0; i < a.Len(); i++ {
		d += (aData[i] - bData[i]) * (aData[i] - bData[i])
	}
	return math.Sqrt(d), nil
}

func euclideanMx(in *mat64.Dense) (*mat64.Dense, error) {
	if in == nil {
		return nil, fmt.Errorf("Invalid matrix supplied: %v\n", in)
	}

	rows, _ := in.Dims()
	out := mat64.NewDense(rows, rows, nil)

	for row := 0; row < rows-1; row++ {
		dist := 0.0
		a := in.RowView(row)
		for i := row + 1; i < rows; i++ {
			if i != row {
				b := in.RowView(i)
				dist, _ = euclideanVec(a, b)
				out.Set(row, i, dist)
				out.Set(i, row, dist)
			}
		}
	}

	return out, nil
}
<|endoftext|>


<commit_before>package beater

import (
	"time"

	"github.com/e-travel/cloudwatchlogsbeat/config"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/cloudwatchlogs"
	"github.com/aws/aws-sdk-go/service/cloudwatchlogs/cloudwatchlogsiface"
	"github.com/elastic/beats/libbeat/logp"
)

type Group struct {
	Name           string
	Prospector     *config.Prospector
	Client         cloudwatchlogsiface.CloudWatchLogsAPI
	Beat           *Cloudwatchlogsbeat
	Streams        map[string]*Stream
	newStreams     int
	removedStreams int
}

func NewGroup(name string, prospector *config.Prospector, beat *Cloudwatchlogsbeat) *Group {
	return &Group{
		Name:       name,
		Prospector: prospector,
		Client:     beat.AWSClient,
		Beat:       beat,
		Streams:    make(map[string]*Stream),
	}
}

func (group *Group) RefreshStreams() {
	params := &cloudwatchlogs.DescribeLogStreamsInput{
		LogGroupName: aws.String(group.Name),
		Descending:   aws.Bool(true),
		OrderBy:      aws.String("LastEventTime"),
	}

	err := group.Client.DescribeLogStreamsPages(
		params,
		func(page *cloudwatchlogs.DescribeLogStreamsOutput, lastPage bool) bool {
			for _, logStream := range page.LogStreams {
				name := aws.StringValue(logStream.LogStreamName)
				// are we monitoring the stream already?
				stream, ok := group.Streams[name]
				// is this an empty stream?
				if logStream.LastEventTimestamp == nil {
					logp.Debug("GROUP", "%s/%s has a nil timestamp", group.Name, name)
					continue
				}
				// is the stream expired?
				expired := IsBefore(group.Prospector.StreamLastEventHorizon,
					*logStream.LastEventTimestamp)
				//expired := isStreamExpired(timeHorizon, logStream.LastEventTimestamp)
				// is this a stream that we're monitoring and it has expired?
				if ok && expired {
					stream.expired <- true
				}
				// is this a stream that we're not monitoring and it is not expired?
				if !ok && !expired {
					group.addNewStream(name)
				}
			}
			return true
		})
	if err != nil {
		logp.Err("%s %s", group.Name, err.Error())
	}
}

func (group *Group) removeStream(stream *Stream) {
	delete(group.Streams, stream.Name)
	group.removedStreams++
}

func (group *Group) addNewStream(name string) {
	finished := make(chan bool)
	expired := make(chan bool)
	stream := NewStream(name, group, group.Client, group.Beat.Registry, finished, expired)
	group.Streams[name] = stream
	go stream.Monitor()
	go func() {
		<-finished
		group.removeStream(stream)
	}()
	group.newStreams++
}

func (group *Group) Monitor() {
	logp.Info("[group] %s started", group.Name)
	defer logp.Info("[group] %s stopped", group.Name)
	reportTicker := time.NewTicker(reportFrequency)
	defer reportTicker.Stop()
	streamRefreshTicker := time.NewTicker(group.Beat.Config.StreamRefreshFrequency)
	defer streamRefreshTicker.Stop()
	for {
		select {
		case <-streamRefreshTicker.C:
			group.RefreshStreams()
		case <-reportTicker.C:
			group.report()
		}
	}
}

func (group *Group) report() {
	n := len(group.Streams)
	logp.Info("report[group] %d %d %d %s %s", n, group.newStreams, group.removedStreams, group.Name, reportFrequency)
	group.newStreams = 0
	group.removedStreams = 0
}
<commit_msg>Revert "Removes sync from group's streams map operations"<commit_after>package beater

import (
	"sync"
	"time"

	"github.com/e-travel/cloudwatchlogsbeat/config"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/cloudwatchlogs"
	"github.com/aws/aws-sdk-go/service/cloudwatchlogs/cloudwatchlogsiface"
	"github.com/elastic/beats/libbeat/logp"
)

type Group struct {
	Name       string
	Prospector *config.Prospector
	Client     cloudwatchlogsiface.CloudWatchLogsAPI
	Beat       *Cloudwatchlogsbeat
	Streams    map[string]*Stream
	// we'll use this mutex to synchronize access to the Streams map
	mutex          *sync.RWMutex
	newStreams     int
	removedStreams int
}

func NewGroup(name string, prospector *config.Prospector, beat *Cloudwatchlogsbeat) *Group {
	return &Group{
		Name:       name,
		Prospector: prospector,
		Client:     beat.AWSClient,
		Beat:       beat,
		Streams:    make(map[string]*Stream),
		mutex:      &sync.RWMutex{},
	}
}

func (group *Group) RefreshStreams() {
	params := &cloudwatchlogs.DescribeLogStreamsInput{
		LogGroupName: aws.String(group.Name),
		Descending:   aws.Bool(true),
		OrderBy:      aws.String("LastEventTime"),
	}

	err := group.Client.DescribeLogStreamsPages(
		params,
		func(page *cloudwatchlogs.DescribeLogStreamsOutput, lastPage bool) bool {
			for _, logStream := range page.LogStreams {
				name := aws.StringValue(logStream.LogStreamName)
				// are we monitoring the stream already?
				group.mutex.RLock()
				stream, ok := group.Streams[name]
				group.mutex.RUnlock()
				// is this an empty stream?
				if logStream.LastEventTimestamp == nil {
					logp.Debug("GROUP", "%s/%s has a nil timestamp", group.Name, name)
					continue
				}
				// is the stream expired?
				expired := IsBefore(group.Prospector.StreamLastEventHorizon,
					*logStream.LastEventTimestamp)
				//expired := isStreamExpired(timeHorizon, logStream.LastEventTimestamp)
				// is this a stream that we're monitoring and it has expired?
				if ok && expired {
					stream.expired <- true
				}
				// is this a stream that we're not monitoring and it is not expired?
				if !ok && !expired {
					group.addNewStream(name)
				}
			}
			return true
		})
	if err != nil {
		logp.Err("%s %s", group.Name, err.Error())
	}
}

func (group *Group) removeStream(stream *Stream) {
	logp.Info("Stop monitoring stream %s for group %s", stream.Name, group.Name)
	group.mutex.Lock()
	delete(group.Streams, stream.Name)
	group.mutex.Unlock()
	group.removedStreams++
}

func (group *Group) addNewStream(name string) {
	finished := make(chan bool)
	expired := make(chan bool)
	stream := NewStream(name, group, group.Client, group.Beat.Registry, finished, expired)
	logp.Info("Start monitoring stream %s for group %s", stream.Name, group.Name)
	group.mutex.Lock()
	group.Streams[name] = stream
	group.mutex.Unlock()
	go stream.Monitor()
	go func() {
		<-finished
		group.removeStream(stream)
	}()
	group.newStreams++
}

func (group *Group) Monitor() {
	logp.Info("[group] %s started", group.Name)
	defer logp.Info("[group] %s stopped", group.Name)
	reportTicker := time.NewTicker(reportFrequency)
	defer reportTicker.Stop()
	streamRefreshTicker := time.NewTicker(group.Beat.Config.StreamRefreshFrequency)
	defer streamRefreshTicker.Stop()
	for {
		select {
		case <-streamRefreshTicker.C:
			group.RefreshStreams()
		case <-reportTicker.C:
			group.report()
		}
	}
}

func (group *Group) report() {
	n := len(group.Streams)
	logp.Info("report[group] %d %d %d %s %s", n, group.newStreams, group.removedStreams, group.Name, reportFrequency)
	group.newStreams = 0
	group.removedStreams = 0
}
<|endoftext|>


<commit_before>// Package markdown implements a Markdown template converter.
//
// To enable it, import gnd.la/template/markdown like e.g.
//
//  import (
//	_ "gnd.la/template/markdown"
//  )
//
// Any templates with the .md extension will be converted to HTML
// interpreting their contents as Markdown.
// Since Go's template syntax needs to be escaping while using Markdown, any
// '{' or '}' character not inside a quoted or code block (delimited by
// either a single ` or three ```) will be automatically escaped.
// For example:
//
//  {{ fun .Foo .Bar }}
//
// Will be passed to Markdown  as:
//
//  \{\{ fun .Foo .Bar \}\}
//
// But the following won't be altered:
//
//  `{{ fun .Foo .Bar }}`
//
// Neither will:
//
//  ```
//  {{ fun .Foo .Bar }}
//  ```
//
package markdown

import (
	"bytes"
	"github.com/russross/blackfriday"
	"gnd.la/template"
	"regexp"
)

const (
	flags = blackfriday.HTML_USE_SMARTYPANTS | blackfriday.HTML_SMARTYPANTS_FRACTIONS |
		blackfriday.HTML_SMARTYPANTS_LATEX_DASHES
	//| blackfriday.HTML_SAFELINK - safe link breaks commands as link targets
	extensions = blackfriday.EXTENSION_NO_INTRA_EMPHASIS | blackfriday.EXTENSION_TABLES |
		blackfriday.EXTENSION_FENCED_CODE | blackfriday.EXTENSION_AUTOLINK |
		blackfriday.EXTENSION_STRIKETHROUGH | blackfriday.EXTENSION_SPACE_HEADERS
)

type unescape struct {
	escaped   []byte
	unescaped []byte
}

var (
	renderer     = blackfriday.HtmlRenderer(flags, "", "")
	beginComment = []byte("{{/*")
	endComment   = []byte("*/}}")

	// these need to be done in order, so
	// & is the last one. Otherwise we would
	// also replace instances where the user
	// originally typed an escape sequence.
	unescapes = []*unescape{
		{[]byte("""), []byte("\"")},
		{[]byte(">"), []byte(">")},
		{[]byte("<"), []byte("<")},
		{[]byte("&"), []byte("&")},
	}
	commandRe = regexp.MustCompile(`\{\{.*?\}\}`)
)

func toMarkdown(data []byte) ([]byte, error) {
	var out bytes.Buffer
	if bytes.HasPrefix(data, beginComment) {
		if end := bytes.Index(data, endComment); end >= 0 {
			prefix := data[:end+len(endComment)]
			out.Write(prefix)
			out.WriteByte('\n')
			data = data[end+len(endComment):]
		}
	}
	// Escape { and }, unless they're inside a quoted block
	var buf bytes.Buffer
	var quoted bool
	for ii := 0; ii < len(data); ii++ {
		v := data[ii]
		switch v {
		case '`':
			if ii < len(data)-2 && data[ii+1] == '`' && data[ii+2] == '`' {
				buf.WriteByte('`')
				buf.WriteByte('`')
				ii += 2
			}
			quoted = !quoted
			buf.WriteByte(v)
		case '{', '}':
			if !quoted {
				buf.WriteByte('\\')
			}
			fallthrough
		default:
			buf.WriteByte(v)
		}
	}
	md := blackfriday.Markdown(buf.Bytes(), renderer, extensions)
	// blackfriday escapes some characters inside commands, so we must
	// undo those escapes
	md = commandRe.ReplaceAllFunc(md, func(b []byte) []byte {
		for _, v := range unescapes {
			b = bytes.Replace(b, v.escaped, v.unescaped, -1)
		}
		return b
	})
	out.Write(md)
	return out.Bytes(), nil
}

func init() {
	template.RegisterConverter("md", toMarkdown)
}
<commit_msg>Unescape “ and ” in commands<commit_after>// Package markdown implements a Markdown template converter.
//
// To enable it, import gnd.la/template/markdown like e.g.
//
//  import (
//	_ "gnd.la/template/markdown"
//  )
//
// Any templates with the .md extension will be converted to HTML
// interpreting their contents as Markdown.
// Since Go's template syntax needs to be escaping while using Markdown, any
// '{' or '}' character not inside a quoted or code block (delimited by
// either a single ` or three ```) will be automatically escaped.
// For example:
//
//  {{ fun .Foo .Bar }}
//
// Will be passed to Markdown  as:
//
//  \{\{ fun .Foo .Bar \}\}
//
// But the following won't be altered:
//
//  `{{ fun .Foo .Bar }}`
//
// Neither will:
//
//  ```
//  {{ fun .Foo .Bar }}
//  ```
//
package markdown

import (
	"bytes"
	"regexp"

	"gnd.la/template"

	"github.com/russross/blackfriday"
)

const (
	flags = blackfriday.HTML_USE_SMARTYPANTS | blackfriday.HTML_SMARTYPANTS_FRACTIONS |
		blackfriday.HTML_SMARTYPANTS_LATEX_DASHES
	//| blackfriday.HTML_SAFELINK - safe link breaks commands as link targets
	extensions = blackfriday.EXTENSION_NO_INTRA_EMPHASIS | blackfriday.EXTENSION_TABLES |
		blackfriday.EXTENSION_FENCED_CODE | blackfriday.EXTENSION_AUTOLINK |
		blackfriday.EXTENSION_STRIKETHROUGH | blackfriday.EXTENSION_SPACE_HEADERS
)

type unescape struct {
	escaped   []byte
	unescaped []byte
}

var (
	renderer     = blackfriday.HtmlRenderer(flags, "", "")
	beginComment = []byte("{{/*")
	endComment   = []byte("*/}}")

	// these need to be done in order, so
	// & is the last one. Otherwise we would
	// also replace instances where the user
	// originally typed an escape sequence.
	unescapes = []*unescape{
		{[]byte("""), []byte("\"")},
		{[]byte("“"), []byte("\"")},
		{[]byte("”"), []byte("\"")},
		{[]byte(">"), []byte(">")},
		{[]byte("<"), []byte("<")},
		{[]byte("&"), []byte("&")},
	}
	commandRe = regexp.MustCompile(`\{\{.*?\}\}`)
)

func toMarkdown(data []byte) ([]byte, error) {
	var out bytes.Buffer
	if bytes.HasPrefix(data, beginComment) {
		if end := bytes.Index(data, endComment); end >= 0 {
			prefix := data[:end+len(endComment)]
			out.Write(prefix)
			out.WriteByte('\n')
			data = data[end+len(endComment):]
		}
	}
	// Escape { and }, unless they're inside a quoted block
	var buf bytes.Buffer
	var quoted bool
	for ii := 0; ii < len(data); ii++ {
		v := data[ii]
		switch v {
		case '`':
			if ii < len(data)-2 && data[ii+1] == '`' && data[ii+2] == '`' {
				buf.WriteByte('`')
				buf.WriteByte('`')
				ii += 2
			}
			quoted = !quoted
			buf.WriteByte(v)
		case '{', '}':
			if !quoted {
				buf.WriteByte('\\')
			}
			fallthrough
		default:
			buf.WriteByte(v)
		}
	}
	md := blackfriday.Markdown(buf.Bytes(), renderer, extensions)
	// blackfriday escapes some characters inside commands, so we must
	// undo those escapes
	md = commandRe.ReplaceAllFunc(md, func(b []byte) []byte {
		for _, v := range unescapes {
			b = bytes.Replace(b, v.escaped, v.unescaped, -1)
		}
		return b
	})
	out.Write(md)
	return out.Bytes(), nil
}

func init() {
	template.RegisterConverter("md", toMarkdown)
}
<|endoftext|>


<commit_before>package main

import (
    "bufio"
    "encoding/csv"
    "flag"
    "fmt"
    "io/ioutil"
    "net/smtp"
    "os"
    "regexp"
)

func main() {
    var toFilePath string
    var msgFilePath string
    var senderEmail string
    var senderPassword string
    var smtpHost string
    var smtpPort string
    var quiet bool
    var force bool

    flag.StringVar(&toFilePath, "to", "", "Path to file containing recipients in CSV format. See http://github.com/aspyrx/blast-mailer for format specifications.")
    flag.StringVar(&msgFilePath, "msg", "", "Path to file containing the message, including headers. See http://github.com/aspyrx/blast-mailer for special replaceable identifiers.")
    flag.StringVar(&senderEmail, "email", "", "The sender's email address.")
    flag.StringVar(&senderPassword, "password", "", "The sender's password.")
    flag.StringVar(&smtpHost, "host", "", "The hostname of the SMTP server to use.")
    flag.StringVar(&smtpPort, "port", "", "The SMTP server's port (without the colon).")
    flag.BoolVar(&quiet, "quiet", false, "Quiet mode - names and email addresses will not be logged. Default: off.")
    flag.BoolVar(&force, "force", false, "Force mode - all prompts and non-fatal errors will be ignored. Default: off.")

    flag.Parse()

    msg, err := ioutil.ReadFile(msgFilePath)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    toFile, err := os.Open(toFilePath)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    r := csv.NewReader(toFile)
    r.FieldsPerRecord = 0
    r.TrimLeadingSpace = true

    tags, err := r.Read()
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    to, err := r.ReadAll()
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    if err := toFile.Close(); err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    if !quiet {
        fmt.Printf("Sender email: %s\n", senderEmail)
        fmt.Printf("SMTP server: %s:%s\n", smtpHost, smtpPort)
    }

    if !force {
        fmt.Printf("Are you sure you want to send an email to %d recipients? (y/N): ", len(to))
        if !isOk() {
            fmt.Println("Sending cancelled.")
            os.Exit(1)
        }
    }

    auth := smtp.PlainAuth("", senderEmail, senderPassword, smtpHost)
    success := 0
    for _, v := range to {
        newMsg := msg
        for i, tag := range tags {
            newMsg = regexp.MustCompile(fmt.Sprintf(`\Q$%s$\E`, tag)).ReplaceAll(newMsg, []byte(v[i]))
        }

        if !quiet {
            fmt.Println(v)
        }

        recipEmail := v[0]
        err = smtp.SendMail(fmt.Sprintf("%s:%s", smtpHost, smtpPort), auth, senderEmail, []string{recipEmail}, newMsg)

        if err != nil && !force {
            fmt.Printf("Error sending email to '%s'. Continue? (y/N): ", recipEmail)
            if !isOk() {
                fmt.Printf("Sending cancelled. Emails sent: %d\n", success)
                os.Exit(1)
            }
        }

        success++
    }

    fmt.Printf("Sending complete. Emails sent: %d\n", success)
    return
}

func isOk() bool {
    buf := bufio.NewReader(os.Stdin)
    in, err := buf.ReadString('\n')
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    return regexp.MustCompile(`(?i)^y|yes`).MatchString(in)
}
<commit_msg>Added support for public SMTP (no authentication)<commit_after>package main

import (
    "bufio"
    "encoding/csv"
    "flag"
    "fmt"
    "io/ioutil"
    "net/smtp"
    "os"
    "regexp"
)

func main() {
    var toFilePath string
    var msgFilePath string
    var shouldAuth bool
    var senderEmail string
    var senderPassword string
    var smtpHost string
    var smtpPort string
    var quiet bool
    var force bool

    flag.StringVar(&toFilePath, "to", "", "Path to file containing recipients in CSV format. See http://github.com/aspyrx/blast-mailer for format specifications.")
    flag.StringVar(&msgFilePath, "msg", "", "Path to file containing the message, including headers. See http://github.com/aspyrx/blast-mailer for special replaceable identifiers.")
    flag.BoolVar(&shouldAuth, "auth", false, "Whether or not authentication is required.")
    flag.StringVar(&senderEmail, "email", "", "The sender's email address, for authentication.")
    flag.StringVar(&senderPassword, "password", "", "The sender's password, for authentication.")
    flag.StringVar(&smtpHost, "host", "", "The hostname of the SMTP server to use.")
    flag.StringVar(&smtpPort, "port", "", "The SMTP server's port (without the colon).")
    flag.BoolVar(&quiet, "quiet", false, "Quiet mode - names and email addresses will not be logged. Default: off.")
    flag.BoolVar(&force, "force", false, "Force mode - all prompts and non-fatal errors will be ignored. Default: off.")

    flag.Parse()

    msg, err := ioutil.ReadFile(msgFilePath)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    toFile, err := os.Open(toFilePath)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    r := csv.NewReader(toFile)
    r.FieldsPerRecord = 0
    r.TrimLeadingSpace = true

    tags, err := r.Read()
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    to, err := r.ReadAll()
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    if err := toFile.Close(); err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    if !quiet {
        if shouldAuth {
            fmt.Printf("Sender email: %s\n", senderEmail)
        }

        fmt.Printf("SMTP server: %s:%s\n", smtpHost, smtpPort)
    }

    if !force {
        fmt.Printf("Are you sure you want to send an email to %d recipients? (y/N): ", len(to))
        if !isOk() {
            fmt.Println("Sending cancelled.")
            os.Exit(1)
        }
    }

    var auth smtp.Auth
    if shouldAuth {
        auth = smtp.PlainAuth("", senderEmail, senderPassword, smtpHost)
    }

    success := 0
    for _, v := range to {
        newMsg := msg
        for i, tag := range tags {
            newMsg = regexp.MustCompile(fmt.Sprintf(`\Q$%s$\E`, tag)).ReplaceAll(newMsg, []byte(v[i]))
        }

        if !quiet {
            fmt.Println(v)
        }

        recipEmail := v[0]
        err = smtp.SendMail(fmt.Sprintf("%s:%s", smtpHost, smtpPort), auth, senderEmail, []string{recipEmail}, newMsg)

        if err != nil && !force {
            fmt.Printf("Error sending email to '%s':\n%v\nContinue? (y/N): ", recipEmail, err)
            if !isOk() {
                fmt.Printf("Sending cancelled. Emails sent: %d\n", success)
                os.Exit(1)
            }
        }

        success++
    }

    fmt.Printf("Sending complete. Emails sent: %d\n", success)
    return
}

func isOk() bool {
    buf := bufio.NewReader(os.Stdin)
    in, err := buf.ReadString('\n')
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    return regexp.MustCompile(`(?i)^y|yes`).MatchString(in)
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2018 VMware, Inc. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package vslm

import (
	"context"
	"errors"

	"github.com/vmware/govmomi/object"
	"github.com/vmware/govmomi/vim25"
	"github.com/vmware/govmomi/vim25/methods"
	"github.com/vmware/govmomi/vim25/mo"
	"github.com/vmware/govmomi/vim25/types"
)

// ObjectManager wraps VStorageObjectManagerBase.
type ObjectManager struct {
	types.ManagedObjectReference
	c    *vim25.Client
	isVC bool
}

// NewObjectManager returns an ObjectManager referencing the VcenterVStorageObjectManager singleton when connected to vCenter or
// the HostVStorageObjectManager singleton when connected to an ESX host.  The optional ref param can be used to specify a ESX
// host instead, when connected to vCenter.
func NewObjectManager(client *vim25.Client, ref ...types.ManagedObjectReference) *ObjectManager {
	mref := *client.ServiceContent.VStorageObjectManager

	if len(ref) == 1 {
		mref = ref[0]
	}

	m := ObjectManager{
		ManagedObjectReference: mref,
		c:                      client,
		isVC:                   mref.Type == "VcenterVStorageObjectManager",
	}

	return &m
}

// PlaceDisk uses StorageResourceManager datastore placement recommendations to choose a Datastore from a Datastore cluster.
// If the given spec backing Datastore field is not that of type StoragePod, the spec is unmodifed.
// Otherwise, the backing Datastore field is replaced with a Datastore suggestion.
func (m ObjectManager) PlaceDisk(ctx context.Context, spec *types.VslmCreateSpec, pool types.ManagedObjectReference) error {
	backing := spec.BackingSpec.GetVslmCreateSpecBackingSpec()
	if backing.Datastore.Type != "StoragePod" {
		return nil
	}

	device := &types.VirtualDisk{
		VirtualDevice: types.VirtualDevice{
			Key: 0,
			Backing: &types.VirtualDiskFlatVer2BackingInfo{
				DiskMode:        string(types.VirtualDiskModePersistent),
				ThinProvisioned: types.NewBool(true),
			},
			UnitNumber: types.NewInt32(0),
		},
		CapacityInKB: spec.CapacityInMB * 1024,
	}

	storage := types.StoragePlacementSpec{
		Type:         string(types.StoragePlacementSpecPlacementTypeCreate),
		ResourcePool: &pool,
		PodSelectionSpec: types.StorageDrsPodSelectionSpec{
			StoragePod: &backing.Datastore,
			InitialVmConfig: []types.VmPodConfigForPlacement{
				{
					StoragePod: backing.Datastore,
					Disk: []types.PodDiskLocator{
						{
							DiskId:          device.Key,
							DiskBackingInfo: device.Backing,
						},
					},
				},
			},
		},
		ConfigSpec: &types.VirtualMachineConfigSpec{
			Name: spec.Name,
			DeviceChange: []types.BaseVirtualDeviceConfigSpec{
				&types.VirtualDeviceConfigSpec{
					Operation:     types.VirtualDeviceConfigSpecOperationAdd,
					FileOperation: types.VirtualDeviceConfigSpecFileOperationCreate,
					Device:        device,
				},
			},
		},
	}

	req := types.RecommendDatastores{
		This:        *m.c.ServiceContent.StorageResourceManager,
		StorageSpec: storage,
	}

	res, err := methods.RecommendDatastores(ctx, m.c, &req)
	if err != nil {
		return err
	}

	r := res.Returnval.Recommendations
	if len(r) == 0 {
		return errors.New("no storage placement recommendations")
	}

	backing.Datastore = r[0].Action[0].(*types.StoragePlacementAction).Destination

	return nil
}

func (m ObjectManager) CreateDisk(ctx context.Context, spec types.VslmCreateSpec) (*object.Task, error) {
	req := types.CreateDisk_Task{
		This: m.Reference(),
		Spec: spec,
	}

	if m.isVC {
		res, err := methods.CreateDisk_Task(ctx, m.c, &req)
		if err != nil {
			return nil, err
		}

		return object.NewTask(m.c, res.Returnval), nil
	}

	res, err := methods.HostCreateDisk_Task(ctx, m.c, (*types.HostCreateDisk_Task)(&req))
	if err != nil {
		return nil, err
	}

	return object.NewTask(m.c, res.Returnval), nil
}

func (m ObjectManager) Rename(ctx context.Context, ds mo.Reference, id, name string) error {
	req := types.RenameVStorageObject{
		This:      m.Reference(),
		Datastore: ds.Reference(),
		Id:        types.ID{Id: id},
		Name:      name,
	}

	if m.isVC {
		_, err := methods.RenameVStorageObject(ctx, m.c, &req)
		return err
	}

	_, err := methods.HostRenameVStorageObject(ctx, m.c, (*types.HostRenameVStorageObject)(&req))
	return err
}

func (m ObjectManager) Delete(ctx context.Context, ds mo.Reference, id string) (*object.Task, error) {
	req := types.DeleteVStorageObject_Task{
		This:      m.Reference(),
		Datastore: ds.Reference(),
		Id:        types.ID{Id: id},
	}

	if m.isVC {
		res, err := methods.DeleteVStorageObject_Task(ctx, m.c, &req)
		if err != nil {
			return nil, err
		}

		return object.NewTask(m.c, res.Returnval), nil
	}

	res, err := methods.HostDeleteVStorageObject_Task(ctx, m.c, (*types.HostDeleteVStorageObject_Task)(&req))
	if err != nil {
		return nil, err
	}

	return object.NewTask(m.c, res.Returnval), nil
}

func (m ObjectManager) Retrieve(ctx context.Context, ds mo.Reference, id string) (*types.VStorageObject, error) {
	req := types.RetrieveVStorageObject{
		This:      m.Reference(),
		Datastore: ds.Reference(),
		Id:        types.ID{Id: id},
	}

	if m.isVC {
		res, err := methods.RetrieveVStorageObject(ctx, m.c, &req)
		if err != nil {
			return nil, err
		}

		return &res.Returnval, nil
	}

	res, err := methods.HostRetrieveVStorageObject(ctx, m.c, (*types.HostRetrieveVStorageObject)(&req))
	if err != nil {
		return nil, err
	}

	return &res.Returnval, nil
}

func (m ObjectManager) List(ctx context.Context, ds mo.Reference) ([]types.ID, error) {
	req := types.ListVStorageObject{
		This:      m.Reference(),
		Datastore: ds.Reference(),
	}

	if m.isVC {
		res, err := methods.ListVStorageObject(ctx, m.c, &req)
		if err != nil {
			return nil, err
		}

		return res.Returnval, nil
	}

	res, err := methods.HostListVStorageObject(ctx, m.c, (*types.HostListVStorageObject)(&req))
	if err != nil {
		return nil, err
	}

	return res.Returnval, nil
}

func (m ObjectManager) RegisterDisk(ctx context.Context, path, name string) (*types.VStorageObject, error) {
	req := types.RegisterDisk{
		This: m.Reference(),
		Path: path,
		Name: name,
	}

	if m.isVC {
		res, err := methods.RegisterDisk(ctx, m.c, &req)
		if err != nil {
			return nil, err
		}

		return &res.Returnval, nil
	}

	res, err := methods.HostRegisterDisk(ctx, m.c, (*types.HostRegisterDisk)(&req))
	if err != nil {
		return nil, err
	}

	return &res.Returnval, nil
}

func (m ObjectManager) Clone(ctx context.Context, ds mo.Reference, id string, spec types.VslmCloneSpec) (*object.Task, error) {
	req := types.CloneVStorageObject_Task{
		This:      m.Reference(),
		Datastore: ds.Reference(),
		Id:        types.ID{Id: id},
		Spec:      spec,
	}

	if m.isVC {
		res, err := methods.CloneVStorageObject_Task(ctx, m.c, &req)
		if err != nil {
			return nil, err
		}

		return object.NewTask(m.c, res.Returnval), nil
	}

	res, err := methods.HostCloneVStorageObject_Task(ctx, m.c, (*types.HostCloneVStorageObject_Task)(&req))
	if err != nil {
		return nil, err
	}

	return object.NewTask(m.c, res.Returnval), nil
}

func (m ObjectManager) CreateSnapshot(ctx context.Context, ds mo.Reference, id, desc string) (*object.Task, error) {
	req := types.VStorageObjectCreateSnapshot_Task{
		This:        m.Reference(),
		Id:          types.ID{Id: id},
		Description: desc,
		Datastore:   ds.Reference(),
	}

	if m.isVC {
		res, err := methods.VStorageObjectCreateSnapshot_Task(ctx, m.c, &req)
		if err != nil {
			return nil, err
		}

		return object.NewTask(m.c, res.Returnval), nil
	}

	res, err := methods.HostVStorageObjectCreateSnapshot_Task(ctx, m.c, (*types.HostVStorageObjectCreateSnapshot_Task)(&req))
	if err != nil {
		return nil, err
	}

	return object.NewTask(m.c, res.Returnval), nil
}

func (m ObjectManager) DeleteSnapshot(ctx context.Context, ds mo.Reference, id, sid string) (*object.Task, error) {
	req := types.DeleteSnapshot_Task{
		This:       m.Reference(),
		Datastore:  ds.Reference(),
		Id:         types.ID{Id: id},
		SnapshotId: types.ID{Id: sid},
	}

	if m.isVC {
		res, err := methods.DeleteSnapshot_Task(ctx, m.c, &req)
		if err != nil {
			return nil, err
		}

		return object.NewTask(m.c, res.Returnval), nil
	}

	res, err := methods.HostVStorageObjectDeleteSnapshot_Task(ctx, m.c, (*types.HostVStorageObjectDeleteSnapshot_Task)(&req))
	if err != nil {
		return nil, err
	}

	return object.NewTask(m.c, res.Returnval), nil
}

func (m ObjectManager) RetrieveSnapshotInfo(ctx context.Context, ds mo.Reference, id string) (*types.VStorageObjectSnapshotInfo, error) {
	req := types.RetrieveSnapshotInfo{
		This:      m.Reference(),
		Datastore: ds.Reference(),
		Id:        types.ID{Id: id},
	}

	if m.isVC {
		res, err := methods.RetrieveSnapshotInfo(ctx, m.c, &req)
		if err != nil {
			return nil, err
		}

		return &res.Returnval, nil
	}

	res, err := methods.HostVStorageObjectRetrieveSnapshotInfo(ctx, m.c, (*types.HostVStorageObjectRetrieveSnapshotInfo)(&req))
	if err != nil {
		return nil, err
	}

	return &res.Returnval, nil
}

func (m ObjectManager) AttachTag(ctx context.Context, id string, tag types.VslmTagEntry) error {
	req := &types.AttachTagToVStorageObject{
		This:     m.ManagedObjectReference,
		Id:       types.ID{Id: id},
		Category: tag.ParentCategoryName,
		Tag:      tag.TagName,
	}

	_, err := methods.AttachTagToVStorageObject(ctx, m.c, req)
	return err
}

func (m ObjectManager) DetachTag(ctx context.Context, id string, tag types.VslmTagEntry) error {
	req := &types.DetachTagFromVStorageObject{
		This:     m.ManagedObjectReference,
		Id:       types.ID{Id: id},
		Category: tag.ParentCategoryName,
		Tag:      tag.TagName,
	}

	_, err := methods.DetachTagFromVStorageObject(ctx, m.c, req)
	return err
}

func (m ObjectManager) ListAttachedObjects(ctx context.Context, category, tag string) ([]types.ID, error) {
	req := &types.ListVStorageObjectsAttachedToTag{
		This:     m.ManagedObjectReference,
		Category: category,
		Tag:      tag,
	}

	res, err := methods.ListVStorageObjectsAttachedToTag(ctx, m.c, req)
	if err != nil {
		return nil, err
	}
	return res.Returnval, nil
}

func (m ObjectManager) ListAttachedTags(ctx context.Context, id string) ([]types.VslmTagEntry, error) {
	req := &types.ListTagsAttachedToVStorageObject{
		This: m.ManagedObjectReference,
		Id:   types.ID{Id: id},
	}

	res, err := methods.ListTagsAttachedToVStorageObject(ctx, m.c, req)
	if err != nil {
		return nil, err
	}
	return res.Returnval, nil
}

func (m ObjectManager) ReconcileDatastoreInventory(ctx context.Context, ds mo.Reference) (*object.Task, error) {
	req := &types.ReconcileDatastoreInventory_Task{
		This:      m.Reference(),
		Datastore: ds.Reference(),
	}

	res, err := methods.ReconcileDatastoreInventory_Task(ctx, m.c, req)
	if err != nil {
		return nil, err
	}
	return object.NewTask(m.c, res.Returnval), nil
}
<commit_msg>Add ExtendDisk and InflateDisk wrappers to vlsm/object_manager<commit_after>/*
Copyright (c) 2018 VMware, Inc. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package vslm

import (
	"context"
	"errors"

	"github.com/vmware/govmomi/object"
	"github.com/vmware/govmomi/vim25"
	"github.com/vmware/govmomi/vim25/methods"
	"github.com/vmware/govmomi/vim25/mo"
	"github.com/vmware/govmomi/vim25/types"
)

// ObjectManager wraps VStorageObjectManagerBase.
type ObjectManager struct {
	types.ManagedObjectReference
	c    *vim25.Client
	isVC bool
}

// NewObjectManager returns an ObjectManager referencing the VcenterVStorageObjectManager singleton when connected to vCenter or
// the HostVStorageObjectManager singleton when connected to an ESX host.  The optional ref param can be used to specify a ESX
// host instead, when connected to vCenter.
func NewObjectManager(client *vim25.Client, ref ...types.ManagedObjectReference) *ObjectManager {
	mref := *client.ServiceContent.VStorageObjectManager

	if len(ref) == 1 {
		mref = ref[0]
	}

	m := ObjectManager{
		ManagedObjectReference: mref,
		c:                      client,
		isVC:                   mref.Type == "VcenterVStorageObjectManager",
	}

	return &m
}

// PlaceDisk uses StorageResourceManager datastore placement recommendations to choose a Datastore from a Datastore cluster.
// If the given spec backing Datastore field is not that of type StoragePod, the spec is unmodifed.
// Otherwise, the backing Datastore field is replaced with a Datastore suggestion.
func (m ObjectManager) PlaceDisk(ctx context.Context, spec *types.VslmCreateSpec, pool types.ManagedObjectReference) error {
	backing := spec.BackingSpec.GetVslmCreateSpecBackingSpec()
	if backing.Datastore.Type != "StoragePod" {
		return nil
	}

	device := &types.VirtualDisk{
		VirtualDevice: types.VirtualDevice{
			Key: 0,
			Backing: &types.VirtualDiskFlatVer2BackingInfo{
				DiskMode:        string(types.VirtualDiskModePersistent),
				ThinProvisioned: types.NewBool(true),
			},
			UnitNumber: types.NewInt32(0),
		},
		CapacityInKB: spec.CapacityInMB * 1024,
	}

	storage := types.StoragePlacementSpec{
		Type:         string(types.StoragePlacementSpecPlacementTypeCreate),
		ResourcePool: &pool,
		PodSelectionSpec: types.StorageDrsPodSelectionSpec{
			StoragePod: &backing.Datastore,
			InitialVmConfig: []types.VmPodConfigForPlacement{
				{
					StoragePod: backing.Datastore,
					Disk: []types.PodDiskLocator{
						{
							DiskId:          device.Key,
							DiskBackingInfo: device.Backing,
						},
					},
				},
			},
		},
		ConfigSpec: &types.VirtualMachineConfigSpec{
			Name: spec.Name,
			DeviceChange: []types.BaseVirtualDeviceConfigSpec{
				&types.VirtualDeviceConfigSpec{
					Operation:     types.VirtualDeviceConfigSpecOperationAdd,
					FileOperation: types.VirtualDeviceConfigSpecFileOperationCreate,
					Device:        device,
				},
			},
		},
	}

	req := types.RecommendDatastores{
		This:        *m.c.ServiceContent.StorageResourceManager,
		StorageSpec: storage,
	}

	res, err := methods.RecommendDatastores(ctx, m.c, &req)
	if err != nil {
		return err
	}

	r := res.Returnval.Recommendations
	if len(r) == 0 {
		return errors.New("no storage placement recommendations")
	}

	backing.Datastore = r[0].Action[0].(*types.StoragePlacementAction).Destination

	return nil
}

func (m ObjectManager) CreateDisk(ctx context.Context, spec types.VslmCreateSpec) (*object.Task, error) {
	req := types.CreateDisk_Task{
		This: m.Reference(),
		Spec: spec,
	}

	if m.isVC {
		res, err := methods.CreateDisk_Task(ctx, m.c, &req)
		if err != nil {
			return nil, err
		}

		return object.NewTask(m.c, res.Returnval), nil
	}

	res, err := methods.HostCreateDisk_Task(ctx, m.c, (*types.HostCreateDisk_Task)(&req))
	if err != nil {
		return nil, err
	}

	return object.NewTask(m.c, res.Returnval), nil
}

func (m ObjectManager) Rename(ctx context.Context, ds mo.Reference, id, name string) error {
	req := types.RenameVStorageObject{
		This:      m.Reference(),
		Datastore: ds.Reference(),
		Id:        types.ID{Id: id},
		Name:      name,
	}

	if m.isVC {
		_, err := methods.RenameVStorageObject(ctx, m.c, &req)
		return err
	}

	_, err := methods.HostRenameVStorageObject(ctx, m.c, (*types.HostRenameVStorageObject)(&req))
	return err
}

func (m ObjectManager) Delete(ctx context.Context, ds mo.Reference, id string) (*object.Task, error) {
	req := types.DeleteVStorageObject_Task{
		This:      m.Reference(),
		Datastore: ds.Reference(),
		Id:        types.ID{Id: id},
	}

	if m.isVC {
		res, err := methods.DeleteVStorageObject_Task(ctx, m.c, &req)
		if err != nil {
			return nil, err
		}

		return object.NewTask(m.c, res.Returnval), nil
	}

	res, err := methods.HostDeleteVStorageObject_Task(ctx, m.c, (*types.HostDeleteVStorageObject_Task)(&req))
	if err != nil {
		return nil, err
	}

	return object.NewTask(m.c, res.Returnval), nil
}

func (m ObjectManager) Retrieve(ctx context.Context, ds mo.Reference, id string) (*types.VStorageObject, error) {
	req := types.RetrieveVStorageObject{
		This:      m.Reference(),
		Datastore: ds.Reference(),
		Id:        types.ID{Id: id},
	}

	if m.isVC {
		res, err := methods.RetrieveVStorageObject(ctx, m.c, &req)
		if err != nil {
			return nil, err
		}

		return &res.Returnval, nil
	}

	res, err := methods.HostRetrieveVStorageObject(ctx, m.c, (*types.HostRetrieveVStorageObject)(&req))
	if err != nil {
		return nil, err
	}

	return &res.Returnval, nil
}

func (m ObjectManager) List(ctx context.Context, ds mo.Reference) ([]types.ID, error) {
	req := types.ListVStorageObject{
		This:      m.Reference(),
		Datastore: ds.Reference(),
	}

	if m.isVC {
		res, err := methods.ListVStorageObject(ctx, m.c, &req)
		if err != nil {
			return nil, err
		}

		return res.Returnval, nil
	}

	res, err := methods.HostListVStorageObject(ctx, m.c, (*types.HostListVStorageObject)(&req))
	if err != nil {
		return nil, err
	}

	return res.Returnval, nil
}

func (m ObjectManager) RegisterDisk(ctx context.Context, path, name string) (*types.VStorageObject, error) {
	req := types.RegisterDisk{
		This: m.Reference(),
		Path: path,
		Name: name,
	}

	if m.isVC {
		res, err := methods.RegisterDisk(ctx, m.c, &req)
		if err != nil {
			return nil, err
		}

		return &res.Returnval, nil
	}

	res, err := methods.HostRegisterDisk(ctx, m.c, (*types.HostRegisterDisk)(&req))
	if err != nil {
		return nil, err
	}

	return &res.Returnval, nil
}

func (m ObjectManager) ExtendDisk(ctx context.Context, ds mo.Reference, id string, newCapacityInMB int64) (*object.Task, error) {
	req := types.HostExtendDisk_Task{
		This:            m.Reference(),
		Id:              types.ID{Id: id},
		Datastore:       ds.Reference(),
		NewCapacityInMB: newCapacityInMB,
	}

	res, err := methods.HostExtendDisk_Task(ctx, m.c, &req)
	if err != nil {
		return nil, err
	}

	return object.NewTask(m.c, res.Returnval), nil
}

func (m ObjectManager) InflateDisk(ctx context.Context, ds mo.Reference, id string) (*object.Task, error) {
	req := types.HostInflateDisk_Task{
		This:      m.Reference(),
		Id:        types.ID{Id: id},
		Datastore: ds.Reference(),
	}

	res, err := methods.HostInflateDisk_Task(ctx, m.c, &req)
	if err != nil {
		return nil, err
	}

	return object.NewTask(m.c, res.Returnval), nil
}

func (m ObjectManager) Clone(ctx context.Context, ds mo.Reference, id string, spec types.VslmCloneSpec) (*object.Task, error) {
	req := types.CloneVStorageObject_Task{
		This:      m.Reference(),
		Datastore: ds.Reference(),
		Id:        types.ID{Id: id},
		Spec:      spec,
	}

	if m.isVC {
		res, err := methods.CloneVStorageObject_Task(ctx, m.c, &req)
		if err != nil {
			return nil, err
		}

		return object.NewTask(m.c, res.Returnval), nil
	}

	res, err := methods.HostCloneVStorageObject_Task(ctx, m.c, (*types.HostCloneVStorageObject_Task)(&req))
	if err != nil {
		return nil, err
	}

	return object.NewTask(m.c, res.Returnval), nil
}

func (m ObjectManager) CreateSnapshot(ctx context.Context, ds mo.Reference, id, desc string) (*object.Task, error) {
	req := types.VStorageObjectCreateSnapshot_Task{
		This:        m.Reference(),
		Id:          types.ID{Id: id},
		Description: desc,
		Datastore:   ds.Reference(),
	}

	if m.isVC {
		res, err := methods.VStorageObjectCreateSnapshot_Task(ctx, m.c, &req)
		if err != nil {
			return nil, err
		}

		return object.NewTask(m.c, res.Returnval), nil
	}

	res, err := methods.HostVStorageObjectCreateSnapshot_Task(ctx, m.c, (*types.HostVStorageObjectCreateSnapshot_Task)(&req))
	if err != nil {
		return nil, err
	}

	return object.NewTask(m.c, res.Returnval), nil
}

func (m ObjectManager) DeleteSnapshot(ctx context.Context, ds mo.Reference, id, sid string) (*object.Task, error) {
	req := types.DeleteSnapshot_Task{
		This:       m.Reference(),
		Datastore:  ds.Reference(),
		Id:         types.ID{Id: id},
		SnapshotId: types.ID{Id: sid},
	}

	if m.isVC {
		res, err := methods.DeleteSnapshot_Task(ctx, m.c, &req)
		if err != nil {
			return nil, err
		}

		return object.NewTask(m.c, res.Returnval), nil
	}

	res, err := methods.HostVStorageObjectDeleteSnapshot_Task(ctx, m.c, (*types.HostVStorageObjectDeleteSnapshot_Task)(&req))
	if err != nil {
		return nil, err
	}

	return object.NewTask(m.c, res.Returnval), nil
}

func (m ObjectManager) RetrieveSnapshotInfo(ctx context.Context, ds mo.Reference, id string) (*types.VStorageObjectSnapshotInfo, error) {
	req := types.RetrieveSnapshotInfo{
		This:      m.Reference(),
		Datastore: ds.Reference(),
		Id:        types.ID{Id: id},
	}

	if m.isVC {
		res, err := methods.RetrieveSnapshotInfo(ctx, m.c, &req)
		if err != nil {
			return nil, err
		}

		return &res.Returnval, nil
	}

	res, err := methods.HostVStorageObjectRetrieveSnapshotInfo(ctx, m.c, (*types.HostVStorageObjectRetrieveSnapshotInfo)(&req))
	if err != nil {
		return nil, err
	}

	return &res.Returnval, nil
}

func (m ObjectManager) AttachTag(ctx context.Context, id string, tag types.VslmTagEntry) error {
	req := &types.AttachTagToVStorageObject{
		This:     m.ManagedObjectReference,
		Id:       types.ID{Id: id},
		Category: tag.ParentCategoryName,
		Tag:      tag.TagName,
	}

	_, err := methods.AttachTagToVStorageObject(ctx, m.c, req)
	return err
}

func (m ObjectManager) DetachTag(ctx context.Context, id string, tag types.VslmTagEntry) error {
	req := &types.DetachTagFromVStorageObject{
		This:     m.ManagedObjectReference,
		Id:       types.ID{Id: id},
		Category: tag.ParentCategoryName,
		Tag:      tag.TagName,
	}

	_, err := methods.DetachTagFromVStorageObject(ctx, m.c, req)
	return err
}

func (m ObjectManager) ListAttachedObjects(ctx context.Context, category, tag string) ([]types.ID, error) {
	req := &types.ListVStorageObjectsAttachedToTag{
		This:     m.ManagedObjectReference,
		Category: category,
		Tag:      tag,
	}

	res, err := methods.ListVStorageObjectsAttachedToTag(ctx, m.c, req)
	if err != nil {
		return nil, err
	}
	return res.Returnval, nil
}

func (m ObjectManager) ListAttachedTags(ctx context.Context, id string) ([]types.VslmTagEntry, error) {
	req := &types.ListTagsAttachedToVStorageObject{
		This: m.ManagedObjectReference,
		Id:   types.ID{Id: id},
	}

	res, err := methods.ListTagsAttachedToVStorageObject(ctx, m.c, req)
	if err != nil {
		return nil, err
	}
	return res.Returnval, nil
}

func (m ObjectManager) ReconcileDatastoreInventory(ctx context.Context, ds mo.Reference) (*object.Task, error) {
	req := &types.ReconcileDatastoreInventory_Task{
		This:      m.Reference(),
		Datastore: ds.Reference(),
	}

	res, err := methods.ReconcileDatastoreInventory_Task(ctx, m.c, req)
	if err != nil {
		return nil, err
	}
	return object.NewTask(m.c, res.Returnval), nil
}
<|endoftext|>


<commit_before>package bnet

import (
	"github.com/HearthSim/hs-proto/go"
	"github.com/golang/protobuf/proto"
	"log"
	"net"
	"sync"
	"time"
)

const (
	StateDisconnected = iota
	StateConnecting
	StateConnected
	StateLoggingIn
	StateAuthenticationFailed
	StateReady
)

type Session struct {
	server *Server
	conn   net.Conn

	// Exports contain methods the client may invoke on the server; the client
	// refers to these as imports.
	exports []Service
	// Imports contain methods the server may invoke on the client; the client
	// refers to these as exports.
	imports []Service
	// Maps an imported service hash to an index into imports.
	importMap map[uint32]int

	// A request registers itself for a response by assigning to this map a
	// channel on which it will listen for the response.
	responses map[uint32]chan []byte
	// The token used for request/response pairs increments sequentially.
	lastToken uint32

	// This channel contains outgoing packets.
	packetQueue chan []byte

	// stateMutex protects Session.State
	stateMutex  sync.Mutex
	stateChange *sync.Cond
	// state is the current state of the session; it may be any of the State
	// consts defined above.
	state int

	game           GameSession
	startedPlaying time.Time
}

func NewSession(s *Server, c net.Conn) *Session {
	sess := &Session{}
	sess.server = s
	sess.conn = c
	sess.importMap = map[uint32]int{}
	sess.responses = map[uint32]chan []byte{}
	sess.packetQueue = make(chan []byte)
	sess.stateChange = sync.NewCond(&sess.stateMutex)
	sess.state = StateConnecting
	// The connection service export is implicity bound at index 0:
	sess.BindExport(0, Hash("bnet.protocol.connection.ConnectionService"))
	sess.BindImport(0, Hash("bnet.protocol.connection.ConnectionService"))
	go sess.pumpPacketQueue()
	return sess
}

func (s *Session) BindExport(index int, hash uint32) {
	var service Service = nil
	binder, ok := s.server.registeredServices[hash]
	if !ok {
		log.Printf("warn: Session.BindExport: unknown service: %d=%x", index, hash)
		// We still want to put a nil in the slot, so that we panic when the
		// service is invoked.
	} else {
		service = binder.Bind(s)
	}
	if index >= len(s.exports) {
		padLen := (1 + index) - len(s.exports)
		s.exports = append(s.exports, make([]Service, padLen)...)
	}
	s.exports[index] = service
}

func (s *Session) BindImport(index int, hash uint32) {
	var service Service = nil
	binder, ok := s.server.registeredServices[hash]
	if !ok {
		log.Printf("warn: Session.BindImport: unknown service: %d=%x", index, hash)
	} else {
		service = binder.Bind(s)
	}
	if index >= len(s.imports) {
		padLen := (1 + index) - len(s.imports)
		s.imports = append(s.imports, make([]Service, padLen)...)
	}
	s.imports[index] = service
	s.importMap[hash] = index
}

func (s *Session) ImportedService(name string) Service {
	for _, imp := range s.imports {
		if imp.Name() == name {
			return imp
		}
	}
	return nil
}

func (s *Session) QueuePacket(header *hsproto.BnetProtocol_Header, buf []byte) error {
	packet, err := MakePacket(header, buf)
	if err != nil {
		return err
	}
	s.packetQueue <- packet
	return nil
}

// Goroutine to pump the outgoing packet queue
func (s *Session) pumpPacketQueue() {
	for {
		packet := <-s.packetQueue
		_, err := s.conn.Write(packet)
		log.Printf("Wrote %d bytes", len(packet))
		if err != nil {
			log.Panicf("error: Session.WritePacketQueue failed: %v", err)
		}
	}
}

func (s *Session) MakeRequestHeader(service Service, methodId, size int) *hsproto.BnetProtocol_Header {
	serviceId, ok := s.importMap[Hash(service.Name())]
	if !ok {
		log.Panicf("Client didn't export service %s", service.Name())
	}
	token := s.lastToken
	s.lastToken++
	return &hsproto.BnetProtocol_Header{
		ServiceId: proto.Uint32(uint32(serviceId)),
		MethodId:  proto.Uint32(uint32(methodId)),
		Token:     proto.Uint32(token),
		Size:      proto.Uint32(uint32(size)),
	}
}

func (s *Session) HandlePacket(header *hsproto.BnetProtocol_Header, body []byte) {
	serviceId := int(header.GetServiceId())
	methodId := int(header.GetMethodId())

	if serviceId == 254 {
		s.HandleResponse(header.GetToken(), body)
	} else {
		resp := s.HandleRequest(serviceId, methodId, body)
		if resp != nil {
			respHead := hsproto.BnetProtocol_Header{
				ServiceId: proto.Uint32(254),
				Token:     header.Token,
				Size:      proto.Uint32(uint32(len(resp))),
			}
			err := s.QueuePacket(&respHead, resp)
			if err != nil {
				log.Panicf("error: Session.HandlePacket: respond: %v", err)
			}
		}
	}
}

func (s *Session) HandleResponse(token uint32, body []byte) {
	if ch, ok := s.responses[token]; ok {
		// Note: don't use unbuffered channels for response channels, please...
		ch <- body
	} else {
		log.Printf(" warn: Session.HandleResponse: token not found: %v", token)
	}
}

func (s *Session) HandleRequest(serviceId, methodId int, body []byte) (resp []byte) {
	var service Service
	if serviceId < len(s.exports) {
		service = s.exports[serviceId]
	}
	if service == nil {
		log.Panicf("error: Session.HandleRequest: Unknown serviceId %v", serviceId)
	}
	serviceName := service.Name()
	methodNames := service.Methods()
	methodName := "(unknown)"
	if len(methodNames) > methodId {
		methodName = methodNames[methodId]
	}
	log.Printf("Session.HandleRequest: invoking %s.%s", serviceName, methodName)
	resp, err := service.Invoke(methodId, body)
	if err != nil {
		log.Panicf("error: Session.HandleRequest: Invoke: %v", err)
	}
	return resp
}

// Transition updates the session's state with the value provided, and notifies
// any listeners of that state update.
func (s *Session) Transition(state int) {
	s.stateMutex.Lock()
	currState := s.state
	s.state = state
	s.stateMutex.Unlock()
	if state != currState {
		s.stateChange.Broadcast()
	}
}

// WaitForTransition blocks until the session state matches the value provided.
func (s *Session) WaitForTransition(state int) {
	s.stateMutex.Lock()
	defer s.stateMutex.Unlock()
	for s.state != state {
		s.stateChange.Wait()
	}
}
<commit_msg>bnet: Don't dereference nil imports<commit_after>package bnet

import (
	"github.com/HearthSim/hs-proto/go"
	"github.com/golang/protobuf/proto"
	"log"
	"net"
	"sync"
	"time"
)

const (
	StateDisconnected = iota
	StateConnecting
	StateConnected
	StateLoggingIn
	StateAuthenticationFailed
	StateReady
)

type Session struct {
	server *Server
	conn   net.Conn

	// Exports contain methods the client may invoke on the server; the client
	// refers to these as imports.
	exports []Service
	// Imports contain methods the server may invoke on the client; the client
	// refers to these as exports.
	imports []Service
	// Maps an imported service hash to an index into imports.
	importMap map[uint32]int

	// A request registers itself for a response by assigning to this map a
	// channel on which it will listen for the response.
	responses map[uint32]chan []byte
	// The token used for request/response pairs increments sequentially.
	lastToken uint32

	// This channel contains outgoing packets.
	packetQueue chan []byte

	// stateMutex protects Session.State
	stateMutex  sync.Mutex
	stateChange *sync.Cond
	// state is the current state of the session; it may be any of the State
	// consts defined above.
	state int

	game           GameSession
	startedPlaying time.Time
}

func NewSession(s *Server, c net.Conn) *Session {
	sess := &Session{}
	sess.server = s
	sess.conn = c
	sess.importMap = map[uint32]int{}
	sess.responses = map[uint32]chan []byte{}
	sess.packetQueue = make(chan []byte)
	sess.stateChange = sync.NewCond(&sess.stateMutex)
	sess.state = StateConnecting
	// The connection service export is implicity bound at index 0:
	sess.BindExport(0, Hash("bnet.protocol.connection.ConnectionService"))
	sess.BindImport(0, Hash("bnet.protocol.connection.ConnectionService"))
	go sess.pumpPacketQueue()
	return sess
}

func (s *Session) BindExport(index int, hash uint32) {
	var service Service = nil
	binder, ok := s.server.registeredServices[hash]
	if !ok {
		log.Printf("warn: Session.BindExport: unknown service: %d=%x", index, hash)
		// We still want to put a nil in the slot, so that we panic when the
		// service is invoked.
	} else {
		service = binder.Bind(s)
	}
	if index >= len(s.exports) {
		padLen := (1 + index) - len(s.exports)
		s.exports = append(s.exports, make([]Service, padLen)...)
	}
	s.exports[index] = service
}

func (s *Session) BindImport(index int, hash uint32) {
	var service Service = nil
	binder, ok := s.server.registeredServices[hash]
	if !ok {
		log.Printf("warn: Session.BindImport: unknown service: %d=%x", index, hash)
	} else {
		service = binder.Bind(s)
	}
	if index >= len(s.imports) {
		padLen := (1 + index) - len(s.imports)
		s.imports = append(s.imports, make([]Service, padLen)...)
	}
	s.imports[index] = service
	s.importMap[hash] = index
}

func (s *Session) ImportedService(name string) Service {
	for _, imp := range s.imports {
		if imp != nil && imp.Name() == name {
			return imp
		}
	}
	return nil
}

func (s *Session) QueuePacket(header *hsproto.BnetProtocol_Header, buf []byte) error {
	packet, err := MakePacket(header, buf)
	if err != nil {
		return err
	}
	s.packetQueue <- packet
	return nil
}

// Goroutine to pump the outgoing packet queue
func (s *Session) pumpPacketQueue() {
	for {
		packet := <-s.packetQueue
		_, err := s.conn.Write(packet)
		log.Printf("Wrote %d bytes", len(packet))
		if err != nil {
			log.Panicf("error: Session.WritePacketQueue failed: %v", err)
		}
	}
}

func (s *Session) MakeRequestHeader(service Service, methodId, size int) *hsproto.BnetProtocol_Header {
	serviceId, ok := s.importMap[Hash(service.Name())]
	if !ok {
		log.Panicf("Client didn't export service %s", service.Name())
	}
	token := s.lastToken
	s.lastToken++
	return &hsproto.BnetProtocol_Header{
		ServiceId: proto.Uint32(uint32(serviceId)),
		MethodId:  proto.Uint32(uint32(methodId)),
		Token:     proto.Uint32(token),
		Size:      proto.Uint32(uint32(size)),
	}
}

func (s *Session) HandlePacket(header *hsproto.BnetProtocol_Header, body []byte) {
	serviceId := int(header.GetServiceId())
	methodId := int(header.GetMethodId())

	if serviceId == 254 {
		s.HandleResponse(header.GetToken(), body)
	} else {
		resp := s.HandleRequest(serviceId, methodId, body)
		if resp != nil {
			respHead := hsproto.BnetProtocol_Header{
				ServiceId: proto.Uint32(254),
				Token:     header.Token,
				Size:      proto.Uint32(uint32(len(resp))),
			}
			err := s.QueuePacket(&respHead, resp)
			if err != nil {
				log.Panicf("error: Session.HandlePacket: respond: %v", err)
			}
		}
	}
}

func (s *Session) HandleResponse(token uint32, body []byte) {
	if ch, ok := s.responses[token]; ok {
		// Note: don't use unbuffered channels for response channels, please...
		ch <- body
	} else {
		log.Printf(" warn: Session.HandleResponse: token not found: %v", token)
	}
}

func (s *Session) HandleRequest(serviceId, methodId int, body []byte) (resp []byte) {
	var service Service
	if serviceId < len(s.exports) {
		service = s.exports[serviceId]
	}
	if service == nil {
		log.Panicf("error: Session.HandleRequest: Unknown serviceId %v", serviceId)
	}
	serviceName := service.Name()
	methodNames := service.Methods()
	methodName := "(unknown)"
	if len(methodNames) > methodId {
		methodName = methodNames[methodId]
	}
	log.Printf("Session.HandleRequest: invoking %s.%s", serviceName, methodName)
	resp, err := service.Invoke(methodId, body)
	if err != nil {
		log.Panicf("error: Session.HandleRequest: Invoke: %v", err)
	}
	return resp
}

// Transition updates the session's state with the value provided, and notifies
// any listeners of that state update.
func (s *Session) Transition(state int) {
	s.stateMutex.Lock()
	currState := s.state
	s.state = state
	s.stateMutex.Unlock()
	if state != currState {
		s.stateChange.Broadcast()
	}
}

// WaitForTransition blocks until the session state matches the value provided.
func (s *Session) WaitForTransition(state int) {
	s.stateMutex.Lock()
	defer s.stateMutex.Unlock()
	for s.state != state {
		s.stateChange.Wait()
	}
}
<|endoftext|>


<commit_before>package surf

import (
	"fmt"
	"github.com/headzoo/surf/element"
	ut "github.com/headzoo/surf/unittest"
	"net/http"
	"net/http/httptest"
	"testing"
	"bytes"
)

func TestBrowserGet(t *testing.T) {
	ut.Run(t)
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
		fmt.Fprint(w, html)
	}))
	defer ts.Close()

	b, _ := NewBrowser()
	var _ element.Browsable = b

	err := b.Open(ts.URL)
	ut.AssertNil(err)
	ut.AssertEquals("Surf", b.Title())
	ut.AssertContains("
Hello, Surf!
", b.Body())

	buff := &bytes.Buffer{}
	l, err := b.Write(buff)
	ut.AssertNil(err)
	ut.AssertGreaterThan(0, l)
	ut.AssertEquals(l, buff.Len())
}

func TestBrowserBookmarks(t *testing.T) {
	ut.Run(t)
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
		fmt.Fprint(w, html)
	}))
	defer ts.Close()

	b, _ := NewBrowser()
	b.Bookmarks.Save("test1", ts.URL)
	b.OpenBookmark("test1")
	ut.AssertEquals("Surf", b.Title())
	ut.AssertContains("
Hello, Surf!
", b.Body())

	err := b.BookmarkPage("test2")
	ut.AssertNil(err)
	b.OpenBookmark("test2")
	ut.AssertEquals("Surf", b.Title())
}

func TestBrowserClick(t *testing.T) {
	ut.Run(t)
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/" {
			fmt.Fprint(w, htmlLinks)
		} else if r.URL.Path == "/page2" {
			fmt.Fprint(w, html)
		}
	}))
	defer ts.Close()

	b, _ := NewBrowser()
	err := b.Open(ts.URL)
	ut.AssertNil(err)

	err = b.Click("a:contains('click')")
	ut.AssertNil(err)
	ut.AssertContains("
Hello, Surf!
", b.Body())
}

func TestBrowserLinks(t *testing.T) {
	ut.Run(t)
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
		fmt.Fprint(w, htmlLinks)
	}))
	defer ts.Close()

	b, _ := NewBrowser()
	err := b.Open(ts.URL)
	ut.AssertNil(err)

	links := b.Links()
	ut.AssertEquals(2, len(links))
	ut.AssertEquals("", links[0].ID)
	ut.AssertEquals(ts.URL+"/page2", links[0].Href)
	ut.AssertEquals("click", links[0].Text)
	ut.AssertEquals("page3", links[1].ID)
	ut.AssertEquals(ts.URL+"/page3", links[1].Href)
	ut.AssertEquals("no clicking", links[1].Text)
}

func TestBrowserImages(t *testing.T) {
	ut.Run(t)
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
		fmt.Fprint(w, html)
	}))
	defer ts.Close()

	b, _ := NewBrowser()
	err := b.Open(ts.URL)
	ut.AssertNil(err)

	images := b.Images()
	ut.AssertEquals(2, len(images))
	ut.AssertEquals("imgur-image", images[0].ID)
	ut.AssertEquals("http://i.imgur.com/HW4bJtY.jpg", images[0].Src)
	ut.AssertEquals("", images[0].Alt)
	ut.AssertEquals("It's a...", images[0].Title)

	ut.AssertEquals("", images[1].ID)
	ut.AssertEquals(ts.URL + "/Cxagv.jpg", images[1].Src)
	ut.AssertEquals("A picture", images[1].Alt)
	ut.AssertEquals("", images[1].Title)
}

func TestBrowserForm(t *testing.T) {
	ut.Run(t)
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "GET" {
			fmt.Fprint(w, htmlForm)
		} else {
			r.ParseForm()
			fmt.Fprint(w, r.Form.Encode())
		}
	}))
	defer ts.Close()

	b, _ := NewBrowser()
	err := b.Open(ts.URL)
	ut.AssertNil(err)

	f, err := b.Form("[name='default']")
	ut.AssertNil(err)

	f.Input("age", "55")
	f.Input("gender", "male")
	err = f.Click("submit2")
	ut.AssertNil(err)
	ut.AssertContains("age=55", b.Body())
	ut.AssertContains("gender=male", b.Body())
	ut.AssertContains("submit2=submitted2", b.Body())
}

var html = `<!doctype html>

		<title>Surf</title>

Hello, Surf!

`

var htmlLinks = `<!doctype html>

		<title>Surf</title>

Click the link below.

		click
		no clicking

`

var htmlForm = `<!doctype html>

		<title>Echo Form</title>

		<form method="post" action="/" name="default">
			<input type="text" name="age" value="" />
			<input type="radio" name="gender" value="male" />
			<input type="radio" name="gender" value="female" />
			<input type="submit" name="submit1" value="submitted1" />
			<input type="submit" name="submit2" value="submitted2" />
		</form>

`
<commit_msg>Added Image.Download()<commit_after>package surf

import (
	"fmt"
	"github.com/headzoo/surf/element"
	ut "github.com/headzoo/surf/unittest"
	"net/http"
	"net/http/httptest"
	"testing"
	"bytes"
)

func TestBrowserGet(t *testing.T) {
	ut.Run(t)
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
		fmt.Fprint(w, html)
	}))
	defer ts.Close()

	b, _ := NewBrowser()
	var _ element.Browsable = b

	err := b.Open(ts.URL)
	ut.AssertNil(err)
	ut.AssertEquals("Surf", b.Title())
	ut.AssertContains("
Hello, Surf!
", b.Body())

	buff := &bytes.Buffer{}
	l, err := b.Write(buff)
	ut.AssertNil(err)
	ut.AssertGreaterThan(0, l)
	ut.AssertEquals(l, buff.Len())
}

func TestBrowserBookmarks(t *testing.T) {
	ut.Run(t)
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
		fmt.Fprint(w, html)
	}))
	defer ts.Close()

	b, _ := NewBrowser()
	b.Bookmarks.Save("test1", ts.URL)
	b.OpenBookmark("test1")
	ut.AssertEquals("Surf", b.Title())
	ut.AssertContains("
Hello, Surf!
", b.Body())

	err := b.BookmarkPage("test2")
	ut.AssertNil(err)
	b.OpenBookmark("test2")
	ut.AssertEquals("Surf", b.Title())
}

func TestBrowserClick(t *testing.T) {
	ut.Run(t)
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/" {
			fmt.Fprint(w, htmlLinks)
		} else if r.URL.Path == "/page2" {
			fmt.Fprint(w, html)
		}
	}))
	defer ts.Close()

	b, _ := NewBrowser()
	err := b.Open(ts.URL)
	ut.AssertNil(err)

	err = b.Click("a:contains('click')")
	ut.AssertNil(err)
	ut.AssertContains("
Hello, Surf!
", b.Body())
}

func TestBrowserLinks(t *testing.T) {
	ut.Run(t)
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
		fmt.Fprint(w, htmlLinks)
	}))
	defer ts.Close()

	b, _ := NewBrowser()
	err := b.Open(ts.URL)
	ut.AssertNil(err)

	links := b.Links()
	ut.AssertEquals(2, len(links))
	ut.AssertEquals("", links[0].ID)
	ut.AssertEquals(ts.URL+"/page2", links[0].Href)
	ut.AssertEquals("click", links[0].Text)
	ut.AssertEquals("page3", links[1].ID)
	ut.AssertEquals(ts.URL+"/page3", links[1].Href)
	ut.AssertEquals("no clicking", links[1].Text)
}

func TestBrowserImages(t *testing.T) {
	ut.Run(t)
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
		fmt.Fprint(w, html)
	}))
	defer ts.Close()

	b, _ := NewBrowser()
	err := b.Open(ts.URL)
	ut.AssertNil(err)

	images := b.Images()
	ut.AssertEquals(2, len(images))
	ut.AssertEquals("imgur-image", images[0].ID)
	ut.AssertEquals("http://i.imgur.com/HW4bJtY.jpg", images[0].Src)
	ut.AssertEquals("", images[0].Alt)
	ut.AssertEquals("It's a...", images[0].Title)

	ut.AssertEquals("", images[1].ID)
	ut.AssertEquals(ts.URL + "/Cxagv.jpg", images[1].Src)
	ut.AssertEquals("A picture", images[1].Alt)
	ut.AssertEquals("", images[1].Title)

	buff := &bytes.Buffer{}
	l, err := images[0].Download(buff)
	ut.AssertNil(err)
	ut.AssertGreaterThan(0, buff.Len())
	ut.AssertEquals(int(l), buff.Len())
}

func TestBrowserForm(t *testing.T) {
	ut.Run(t)
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "GET" {
			fmt.Fprint(w, htmlForm)
		} else {
			r.ParseForm()
			fmt.Fprint(w, r.Form.Encode())
		}
	}))
	defer ts.Close()

	b, _ := NewBrowser()
	err := b.Open(ts.URL)
	ut.AssertNil(err)

	f, err := b.Form("[name='default']")
	ut.AssertNil(err)

	f.Input("age", "55")
	f.Input("gender", "male")
	err = f.Click("submit2")
	ut.AssertNil(err)
	ut.AssertContains("age=55", b.Body())
	ut.AssertContains("gender=male", b.Body())
	ut.AssertContains("submit2=submitted2", b.Body())
}

var html = `<!doctype html>

		<title>Surf</title>

Hello, Surf!

`

var htmlLinks = `<!doctype html>

		<title>Surf</title>

Click the link below.

		click
		no clicking

`

var htmlForm = `<!doctype html>

		<title>Echo Form</title>

		<form method="post" action="/" name="default">
			<input type="text" name="age" value="" />
			<input type="radio" name="gender" value="male" />
			<input type="radio" name="gender" value="female" />
			<input type="submit" name="submit1" value="submitted1" />
			<input type="submit" name="submit2" value="submitted2" />
		</form>

`
<|endoftext|>


<commit_before>package waterfall

const (
	WriteBufferSize = 256 * 1024
)
<commit_msg>add comment<commit_after>package waterfall

const (
	// WriteBufferSize specifies the buffer size used by gRPC
	WriteBufferSize = 256 * 1024
)
<|endoftext|>


<commit_before>package container

import (
	"io"
)

type AvroRecord interface {
	Serialize(io.Writer) error
	Schema() string
}
<commit_msg>Add godoc for AvroRecord<commit_after>package container

import (
	"io"
)
/*
  AvroRecord is an interface fulfilled by the structs generated by gogen-avro for Avro records.
*/
type AvroRecord interface {
	Serialize(io.Writer) error
	Schema() string
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/gob"
	"os"
	"syscall"

	"github.com/golang/glog"
	"github.com/hyperhq/runv/supervisor"
	"github.com/vishvananda/netlink"
)

func nsListenerDaemon() {
	/* create own netns */
	if err := syscall.Unshare(syscall.CLONE_NEWNET); err != nil {
		glog.Error(err)
		return
	}

	childPipe := os.NewFile(uintptr(3), "child")
	enc := gob.NewEncoder(childPipe)
	dec := gob.NewDecoder(childPipe)

	/* notify containerd to execute prestart hooks */
	if err := enc.Encode("init"); err != nil {
		glog.Error(err)
		return
	}

	/* after execute prestart hooks */
	var ready string
	if err := dec.Decode(&ready); err != nil {
		glog.Error(err)
		return
	}

	if ready != "init" {
		glog.Errorf("get incorrect init message: %s", ready)
		return
	}

	/* send interface info to containerd */
	infos := collectionInterfaceInfo()
	if err := enc.Encode(infos); err != nil {
		glog.Error(err)
		return
	}

	/* TODO: watch network setting */
	var exit string
	if err := dec.Decode(&exit); err != nil {
		glog.Error(err)
	}
}

func collectionInterfaceInfo() []supervisor.InterfaceInfo {
	infos := []supervisor.InterfaceInfo{}

	links, err := netlink.LinkList()
	if err != nil {
		glog.Error(err)
		return infos
	}

	for _, link := range links {
		if link.Type() != "veth" {
			// lo is here too
			continue
		}

		addrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
		if err != nil {
			glog.Error(err)
			return infos
		}

		for _, addr := range addrs {
			info := supervisor.InterfaceInfo{
				Ip:        addr.IPNet.String(),
				Index:     link.Attrs().Index,
				PeerIndex: link.Attrs().ParentIndex,
			}
			glog.Infof("get interface %v", info)
			infos = append(infos, info)
		}
	}
	return infos
}
<commit_msg>nslistener: set docker veth device down<commit_after>package main

import (
	"encoding/gob"
	"os"
	"syscall"

	"github.com/golang/glog"
	"github.com/hyperhq/runv/supervisor"
	"github.com/vishvananda/netlink"
)

func nsListenerDaemon() {
	/* create own netns */
	if err := syscall.Unshare(syscall.CLONE_NEWNET); err != nil {
		glog.Error(err)
		return
	}

	childPipe := os.NewFile(uintptr(3), "child")
	enc := gob.NewEncoder(childPipe)
	dec := gob.NewDecoder(childPipe)

	/* notify containerd to execute prestart hooks */
	if err := enc.Encode("init"); err != nil {
		glog.Error(err)
		return
	}

	/* after execute prestart hooks */
	var ready string
	if err := dec.Decode(&ready); err != nil {
		glog.Error(err)
		return
	}

	if ready != "init" {
		glog.Errorf("get incorrect init message: %s", ready)
		return
	}

	/* send interface info to containerd */
	infos := collectionInterfaceInfo()
	if err := enc.Encode(infos); err != nil {
		glog.Error(err)
		return
	}

	/* TODO: watch network setting */
	var exit string
	if err := dec.Decode(&exit); err != nil {
		glog.Error(err)
	}
}

func collectionInterfaceInfo() []supervisor.InterfaceInfo {
	infos := []supervisor.InterfaceInfo{}

	links, err := netlink.LinkList()
	if err != nil {
		glog.Error(err)
		return infos
	}

	for _, link := range links {
		if link.Type() != "veth" {
			// lo is here too
			continue
		}

		addrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
		if err != nil {
			glog.Error(err)
			return infos
		}

		for _, addr := range addrs {
			info := supervisor.InterfaceInfo{
				Ip:        addr.IPNet.String(),
				Index:     link.Attrs().Index,
				PeerIndex: link.Attrs().ParentIndex,
			}
			glog.Infof("get interface %v", info)
			infos = append(infos, info)
		}
		// set link down, tap device take over it
		netlink.LinkSetDown(link)
	}
	return infos
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Jetstack cert-manager contributors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package framework

import "sync"

type CleanupActionHandle *int

var cleanupActionsLock sync.Mutex
var cleanupActions = map[CleanupActionHandle]func(){}

// AddCleanupAction installs a function that will be called in the event of the
// whole test being terminated.  This allows arbitrary pieces of the overall
// test to hook into SynchronizedAfterSuite().
func AddCleanupAction(fn func()) CleanupActionHandle {
	p := CleanupActionHandle(new(int))
	cleanupActionsLock.Lock()
	defer cleanupActionsLock.Unlock()
	cleanupActions[p] = fn
	return p
}

// RemoveCleanupAction removes a function that was installed by
// AddCleanupAction.
func RemoveCleanupAction(p CleanupActionHandle) {
	cleanupActionsLock.Lock()
	defer cleanupActionsLock.Unlock()
	delete(cleanupActions, p)
}

// RunCleanupActions runs all functions installed by AddCleanupAction.  It does
// not remove them (see RemoveCleanupAction) but it does run unlocked, so they
// may remove themselves.
func RunCleanupActions() {
	list := []func(){}
	func() {
		cleanupActionsLock.Lock()
		defer cleanupActionsLock.Unlock()
		for _, fn := range cleanupActions {
			list = append(list, fn)
		}
	}()
	// Run unlocked.
	for _, fn := range list {
		fn()
	}
}
<commit_msg>Correct test/e2e/framework/cleanup.go license header<commit_after>// +skip_license_check

/*
Copyright 2016 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package framework

import "sync"

type CleanupActionHandle *int

var cleanupActionsLock sync.Mutex
var cleanupActions = map[CleanupActionHandle]func(){}

// AddCleanupAction installs a function that will be called in the event of the
// whole test being terminated.  This allows arbitrary pieces of the overall
// test to hook into SynchronizedAfterSuite().
func AddCleanupAction(fn func()) CleanupActionHandle {
	p := CleanupActionHandle(new(int))
	cleanupActionsLock.Lock()
	defer cleanupActionsLock.Unlock()
	cleanupActions[p] = fn
	return p
}

// RemoveCleanupAction removes a function that was installed by
// AddCleanupAction.
func RemoveCleanupAction(p CleanupActionHandle) {
	cleanupActionsLock.Lock()
	defer cleanupActionsLock.Unlock()
	delete(cleanupActions, p)
}

// RunCleanupActions runs all functions installed by AddCleanupAction.  It does
// not remove them (see RemoveCleanupAction) but it does run unlocked, so they
// may remove themselves.
func RunCleanupActions() {
	list := []func(){}
	func() {
		cleanupActionsLock.Lock()
		defer cleanupActionsLock.Unlock()
		for _, fn := range cleanupActions {
			list = append(list, fn)
		}
	}()
	// Run unlocked.
	for _, fn := range list {
		fn()
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2021 The cert-manager Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package validation

import (
	"context"
	"fmt"
	"strings"

	admissionv1 "k8s.io/api/admission/v1"
	authzv1 "k8s.io/api/authorization/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/util/validation/field"
	authzclient "k8s.io/client-go/kubernetes/typed/authorization/v1"

	"github.com/jetstack/cert-manager/pkg/apis/certmanager"
	cmapi "github.com/jetstack/cert-manager/pkg/internal/apis/certmanager"
	"github.com/jetstack/cert-manager/pkg/internal/apis/certmanager/validation/util"
)

// ReviewApproval will review whether the client is able to approve or deny the
// given request, if indeed they are attempting to. A SubjectAccessReview will
// be performed if the client is attempting to approve/deny the request. An
// error will be returned if the SubjectAccessReview fails, or if they do not
// have permissions to perform the approval/denial.
func ReviewApproval(client authzclient.SubjectAccessReviewInterface,
	req *admissionv1.AdmissionRequest, oldObj, newObj runtime.Object) field.ErrorList {
	oldCR := oldObj.(*cmapi.CertificateRequest)
	newCR := newObj.(*cmapi.CertificateRequest)

	if !isApprovalRequest(oldCR, newCR) {
		return nil
	}

	ok, err := reviewRequest(client, req, newCR)
	if err != nil {
		return field.ErrorList{
			field.InternalError(field.NewPath("status.conditions"), err),
		}
	}

	if !ok {
		return field.ErrorList{
			field.Forbidden(field.NewPath("status.conditions"),
				fmt.Sprintf("user %q does not have permissions to set approved/deny conditions for issuer %v", req.UserInfo.Username, newCR.Spec.IssuerRef),
			),
		}
	}

	return nil
}

// reviewRequest will perform a SubjectAccessReview with the UserInfo fields of
// the client against the issuer of the CertificateRequest. A client must have
// the "approve" verb, for the resource "signer", in the CertificateRequest
// namespace, for the name "<issuer-kind>.<issuer-group>/<issuer-name>".
func reviewRequest(client authzclient.SubjectAccessReviewInterface, req *admissionv1.AdmissionRequest, cr *cmapi.CertificateRequest) (bool, error) {
	extra := make(map[string]authzv1.ExtraValue)
	for k, v := range req.UserInfo.Extra {
		extra[k] = authzv1.ExtraValue(v)
	}

	kind := cr.Spec.IssuerRef.Kind
	if len(kind) == 0 {
		kind = cmapi.IssuerKind
	}

	group := cr.Spec.IssuerRef.Group
	if len(group) == 0 {
		group = certmanager.GroupName
	}

	for _, name := range []string{
		fmt.Sprintf("%s.%s/*", strings.ToLower(kind), group),
		fmt.Sprintf("%s.%s/%s", strings.ToLower(kind), group, cr.Spec.IssuerRef.Name),
	} {
		resp, err := client.Create(context.TODO(), &authzv1.SubjectAccessReview{
			Spec: authzv1.SubjectAccessReviewSpec{
				User:   req.UserInfo.Username,
				Groups: req.UserInfo.Groups,
				Extra:  extra,
				UID:    req.UserInfo.UID,

				ResourceAttributes: &authzv1.ResourceAttributes{
					Group:    certmanager.GroupName,
					Resource: "signers",
					Name:     name,
					Verb:     "approve",
					Version:  "*",
				},
			},
		}, metav1.CreateOptions{})
		if err != nil {
			return false, err
		}

		if resp.Status.Allowed {
			return true, nil
		}
	}

	return false, nil
}

// isApprovalRequest will return true if the request is given a new approved or
// denied condition. This check is strictly concerned with these conditions
// being _added_. We do this to reduce the number of SAR calls made, since
// removal or changing of these conditions will be rejected elsewhere in the
// validation chain locally.
func isApprovalRequest(oldCR, newCR *cmapi.CertificateRequest) bool {
	oldCRApproving := util.GetCertificateRequestCondition(oldCR.Status.Conditions, cmapi.CertificateRequestConditionApproved)
	newCRApproving := util.GetCertificateRequestCondition(newCR.Status.Conditions, cmapi.CertificateRequestConditionApproved)

	if oldCRApproving == nil && newCRApproving != nil {
		return true
	}

	oldCRDenying := util.GetCertificateRequestCondition(oldCR.Status.Conditions, cmapi.CertificateRequestConditionDenied)
	newCRDenying := util.GetCertificateRequestCondition(newCR.Status.Conditions, cmapi.CertificateRequestConditionDenied)

	if oldCRDenying == nil && newCRDenying != nil {
		return true
	}

	return false
}
<commit_msg>Change approved/denied forbidden error to read better for EU<commit_after>/*
Copyright 2021 The cert-manager Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package validation

import (
	"context"
	"fmt"
	"strings"

	admissionv1 "k8s.io/api/admission/v1"
	authzv1 "k8s.io/api/authorization/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/util/validation/field"
	authzclient "k8s.io/client-go/kubernetes/typed/authorization/v1"

	"github.com/jetstack/cert-manager/pkg/apis/certmanager"
	cmapi "github.com/jetstack/cert-manager/pkg/internal/apis/certmanager"
	"github.com/jetstack/cert-manager/pkg/internal/apis/certmanager/validation/util"
)

// ReviewApproval will review whether the client is able to approve or deny the
// given request, if indeed they are attempting to. A SubjectAccessReview will
// be performed if the client is attempting to approve/deny the request. An
// error will be returned if the SubjectAccessReview fails, or if they do not
// have permissions to perform the approval/denial.
func ReviewApproval(client authzclient.SubjectAccessReviewInterface,
	req *admissionv1.AdmissionRequest, oldObj, newObj runtime.Object) field.ErrorList {
	oldCR := oldObj.(*cmapi.CertificateRequest)
	newCR := newObj.(*cmapi.CertificateRequest)

	if !isApprovalRequest(oldCR, newCR) {
		return nil
	}

	ok, err := reviewRequest(client, req, newCR)
	if err != nil {
		return field.ErrorList{
			field.InternalError(field.NewPath("status.conditions"), err),
		}
	}

	if !ok {
		return field.ErrorList{
			field.Forbidden(field.NewPath("status.conditions"),
				fmt.Sprintf("user %q does not have permissions to set approved/denied conditions for issuer %v", req.UserInfo.Username, newCR.Spec.IssuerRef),
			),
		}
	}

	return nil
}

// reviewRequest will perform a SubjectAccessReview with the UserInfo fields of
// the client against the issuer of the CertificateRequest. A client must have
// the "approve" verb, for the resource "signer", in the CertificateRequest
// namespace, for the name "<issuer-kind>.<issuer-group>/<issuer-name>".
func reviewRequest(client authzclient.SubjectAccessReviewInterface, req *admissionv1.AdmissionRequest, cr *cmapi.CertificateRequest) (bool, error) {
	extra := make(map[string]authzv1.ExtraValue)
	for k, v := range req.UserInfo.Extra {
		extra[k] = authzv1.ExtraValue(v)
	}

	kind := cr.Spec.IssuerRef.Kind
	if len(kind) == 0 {
		kind = cmapi.IssuerKind
	}

	group := cr.Spec.IssuerRef.Group
	if len(group) == 0 {
		group = certmanager.GroupName
	}

	for _, name := range []string{
		fmt.Sprintf("%s.%s/*", strings.ToLower(kind), group),
		fmt.Sprintf("%s.%s/%s", strings.ToLower(kind), group, cr.Spec.IssuerRef.Name),
	} {
		resp, err := client.Create(context.TODO(), &authzv1.SubjectAccessReview{
			Spec: authzv1.SubjectAccessReviewSpec{
				User:   req.UserInfo.Username,
				Groups: req.UserInfo.Groups,
				Extra:  extra,
				UID:    req.UserInfo.UID,

				ResourceAttributes: &authzv1.ResourceAttributes{
					Group:    certmanager.GroupName,
					Resource: "signers",
					Name:     name,
					Verb:     "approve",
					Version:  "*",
				},
			},
		}, metav1.CreateOptions{})
		if err != nil {
			return false, err
		}

		if resp.Status.Allowed {
			return true, nil
		}
	}

	return false, nil
}

// isApprovalRequest will return true if the request is given a new approved or
// denied condition. This check is strictly concerned with these conditions
// being _added_. We do this to reduce the number of SAR calls made, since
// removal or changing of these conditions will be rejected elsewhere in the
// validation chain locally.
func isApprovalRequest(oldCR, newCR *cmapi.CertificateRequest) bool {
	oldCRApproving := util.GetCertificateRequestCondition(oldCR.Status.Conditions, cmapi.CertificateRequestConditionApproved)
	newCRApproving := util.GetCertificateRequestCondition(newCR.Status.Conditions, cmapi.CertificateRequestConditionApproved)

	if oldCRApproving == nil && newCRApproving != nil {
		return true
	}

	oldCRDenying := util.GetCertificateRequestCondition(oldCR.Status.Conditions, cmapi.CertificateRequestConditionDenied)
	newCRDenying := util.GetCertificateRequestCondition(newCR.Status.Conditions, cmapi.CertificateRequestConditionDenied)

	if oldCRDenying == nil && newCRDenying != nil {
		return true
	}

	return false
}
<|endoftext|>


<commit_before>package ui

import (
	"image"
	"image/color"
	"image/png"
	"os"
	"strings"

	"github.com/eaburns/gui/thread0"
	"github.com/eaburns/gui/ui/gl"
)

// A Canvas provides a high-level interface for drawing 2d graphics.
type Canvas struct {
	solid *gl.Program
	tex   *gl.Program
	rect  *gl.Buffer
}

// NewCanvas returns a new canvas.
func NewCanvas() *Canvas {
	c := new(Canvas)
	thread0.Do(func() {
		gl.Enable(gl.Texture2D)
		gl.Enable(gl.Blend)
		gl.BlendFunc(gl.SrcAlpha, gl.OneMinusSrcAlpha)
		c.solid = loadSolidShader()
		c.tex = loadTextureShader()
		c.rect = makeRectBuffer()
	})
	return c
}

func makeRectBuffer() *gl.Buffer {
	buf := gl.NewArrayBuffer()
	buf.SetData(
		gl.StaticDraw,
		0, 0, 0, 0,
		1, 0, 1, 0,
		0, 1, 0, 1,
		1, 1, 1, 1,
	)
	return buf
}

func loadSolidShader() *gl.Program {
	v := strings.NewReader(rectVertShader)
	f := strings.NewReader(solidFragShader)
	p, err := gl.NewProgram(v, f)
	if err != nil {
		panic(err)
	}
	return p
}

func loadTextureShader() *gl.Program {
	v := strings.NewReader(rectVertShader)
	f := strings.NewReader(texFragShader)
	p, err := gl.NewProgram(v, f)
	if err != nil {
		panic(err)
	}
	return p
}

// Close releases the resources for the canvas.
func (c *Canvas) Close() {
	thread0.Do(func() {
		c.solid.Delete()
		c.tex.Delete()
		c.rect.Delete()
	})
}

// Clear clears the canvas with the given color.
func (c *Canvas) Clear(col color.Color) {
	thread0.Do(func() {
		gl.ClearColor(col)
		gl.Clear(gl.ColorBufferBit)
	})
}

// FillRect fills a rectangle with the given color.
// X and y specify the upper-right corner of the rectangle.
func (c *Canvas) FillRect(x, y, w, h float32, col color.Color) {
	thread0.Do(func() {
		r, g, b, a := col.RGBA()
		c.solid.SetUniform("color",
			float32(r)/0xFFFF,
			float32(g)/0xFFFF,
			float32(b)/0xFFFF,
			float32(a)/0xFFFF,
		)

		c.rect.Bind()
		c.solid.SetVertexAttributeData("vert", 4, 0, 0)
		c.solid.SetUniform("loc", x, y)
		c.solid.SetUniform("size", w, h)
		c.solid.DrawArrays(gl.TriangleStrip, 0, 4)
		if err := gl.CheckError(); err != nil {
			panic(err)
		}
	})
}

// An Image can be drawn to a canvas.
type Image struct {
	tex           gl.Texture
	Width, Height float32
}

// NewImage returns a new *Image from a normalized RGBA image.
func NewImage(img *image.NRGBA) *Image {
	var t gl.Texture
	thread0.Do(func() { t = gl.MakeImageTexture(img) })
	return &Image{
		tex:    t,
		Width:  float32(img.Bounds().Dx()),
		Height: float32(img.Bounds().Dy()),
	}
}

// LoadPng returns an *Image loaded from a PNG file.
func LoadPng(path string) (*Image, error) {
	r, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer r.Close()

	img, err := png.Decode(r)
	if err != nil {
		return nil, err
	}
	return NewImage(img.(*image.NRGBA)), nil
}

// DrawImage draws an image at the given location on the canvas.
// X and y specify the upper-left corner of the image.
func (c *Canvas) DrawImage(x, y float32, img *Image) {
	thread0.Do(func() {
		img.tex.Bind(0)
		c.tex.SetUniform("tex", 0)

		c.rect.Bind()
		c.tex.SetVertexAttributeData("vert", 4, 0, 0)
		c.tex.SetUniform("loc", x, y)
		c.tex.SetUniform("size", img.Width, img.Height)
		c.tex.DrawArrays(gl.TriangleStrip, 0, 4)
		if err := gl.CheckError(); err != nil {
			panic(err)
		}
	})
}

var (
	rectVertShader = `
		#version 120
		attribute vec4 vert;
		uniform vec2 loc;
		uniform vec2 size;
		varying vec2 texCoord;
		void main(){
			vec2 p = vec2(vert.x*size.x, vert.y*size.y);
			texCoord = vert.zw;
			gl_Position = gl_ModelViewProjectionMatrix * vec4(p + loc, 0, 1);
		}`

	solidFragShader = `
		#version 120
		uniform vec4 color;
		varying vec2 texCoord;
		void main()
		{
			gl_FragColor = color;
		}`

	texFragShader = `
		#version 120
		uniform sampler2D tex;
		varying vec2 texCoord;
		void main()
		{
			gl_FragColor = texture2D(tex, texCoord);
		}`
)
<commit_msg>Reorder some functions.<commit_after>package ui

import (
	"image"
	"image/color"
	"image/png"
	"os"
	"strings"

	"github.com/eaburns/gui/thread0"
	"github.com/eaburns/gui/ui/gl"
)

// A Canvas provides a high-level interface for drawing 2d graphics.
type Canvas struct {
	solid *gl.Program
	tex   *gl.Program
	rect  *gl.Buffer
}

// NewCanvas returns a new canvas.
func NewCanvas() *Canvas {
	c := new(Canvas)
	thread0.Do(func() {
		gl.Enable(gl.Texture2D)
		gl.Enable(gl.Blend)
		gl.BlendFunc(gl.SrcAlpha, gl.OneMinusSrcAlpha)
		c.solid = loadSolidShader()
		c.tex = loadTextureShader()
		c.rect = makeRectBuffer()
	})
	return c
}

func loadSolidShader() *gl.Program {
	v := strings.NewReader(rectVertShader)
	f := strings.NewReader(solidFragShader)
	p, err := gl.NewProgram(v, f)
	if err != nil {
		panic(err)
	}
	return p
}

func loadTextureShader() *gl.Program {
	v := strings.NewReader(rectVertShader)
	f := strings.NewReader(texFragShader)
	p, err := gl.NewProgram(v, f)
	if err != nil {
		panic(err)
	}
	return p
}

func makeRectBuffer() *gl.Buffer {
	buf := gl.NewArrayBuffer()
	buf.SetData(
		gl.StaticDraw,
		0, 0, 0, 0,
		1, 0, 1, 0,
		0, 1, 0, 1,
		1, 1, 1, 1,
	)
	return buf
}

// Close releases the resources for the canvas.
func (c *Canvas) Close() {
	thread0.Do(func() {
		c.solid.Delete()
		c.tex.Delete()
		c.rect.Delete()
	})
}

// Clear clears the canvas with the given color.
func (c *Canvas) Clear(col color.Color) {
	thread0.Do(func() {
		gl.ClearColor(col)
		gl.Clear(gl.ColorBufferBit)
	})
}

// FillRect fills a rectangle with the given color.
// X and y specify the upper-right corner of the rectangle.
func (c *Canvas) FillRect(x, y, w, h float32, col color.Color) {
	thread0.Do(func() {
		r, g, b, a := col.RGBA()
		c.solid.SetUniform("color",
			float32(r)/0xFFFF,
			float32(g)/0xFFFF,
			float32(b)/0xFFFF,
			float32(a)/0xFFFF,
		)

		c.rect.Bind()
		c.solid.SetVertexAttributeData("vert", 4, 0, 0)
		c.solid.SetUniform("loc", x, y)
		c.solid.SetUniform("size", w, h)
		c.solid.DrawArrays(gl.TriangleStrip, 0, 4)
		if err := gl.CheckError(); err != nil {
			panic(err)
		}
	})
}

// An Image can be drawn to a canvas.
type Image struct {
	tex           gl.Texture
	Width, Height float32
}

// NewImage returns a new *Image from a normalized RGBA image.
func NewImage(img *image.NRGBA) *Image {
	var t gl.Texture
	thread0.Do(func() { t = gl.MakeImageTexture(img) })
	return &Image{
		tex:    t,
		Width:  float32(img.Bounds().Dx()),
		Height: float32(img.Bounds().Dy()),
	}
}

// LoadPng returns an *Image loaded from a PNG file.
func LoadPng(path string) (*Image, error) {
	r, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer r.Close()

	img, err := png.Decode(r)
	if err != nil {
		return nil, err
	}
	return NewImage(img.(*image.NRGBA)), nil
}

// DrawImage draws an image at the given location on the canvas.
// X and y specify the upper-left corner of the image.
func (c *Canvas) DrawImage(x, y float32, img *Image) {
	thread0.Do(func() {
		img.tex.Bind(0)
		c.tex.SetUniform("tex", 0)

		c.rect.Bind()
		c.tex.SetVertexAttributeData("vert", 4, 0, 0)
		c.tex.SetUniform("loc", x, y)
		c.tex.SetUniform("size", img.Width, img.Height)
		c.tex.DrawArrays(gl.TriangleStrip, 0, 4)
		if err := gl.CheckError(); err != nil {
			panic(err)
		}
	})
}

var (
	rectVertShader = `
		#version 120
		attribute vec4 vert;
		uniform vec2 loc;
		uniform vec2 size;
		varying vec2 texCoord;
		void main(){
			vec2 p = vec2(vert.x*size.x, vert.y*size.y);
			texCoord = vert.zw;
			gl_Position = gl_ModelViewProjectionMatrix * vec4(p + loc, 0, 1);
		}`

	solidFragShader = `
		#version 120
		uniform vec4 color;
		varying vec2 texCoord;
		void main()
		{
			gl_FragColor = color;
		}`

	texFragShader = `
		#version 120
		uniform sampler2D tex;
		varying vec2 texCoord;
		void main()
		{
			gl_FragColor = texture2D(tex, texCoord);
		}`
)
<|endoftext|>


<commit_before>package ui

import (
	"net/http"
	"os"

	"gopkg.in/mgo.v2/bson"

	"github.com/gophergala2016/papyrus/data"
	"github.com/gorilla/context"
	"github.com/gorilla/mux"
	"github.com/gorilla/sessions"
)

var Router = mux.NewRouter()

var store = sessions.NewCookieStore([]byte(os.Getenv("SECRET")))

type Server struct {
	Router *mux.Router
}

func (s Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	sess, err := store.Get(r, "s")
	if err != nil {
		ServeInternalServerError(w, r)
		return
	}

	accID, ok := sess.Values["accountID"].(string)
	if ok {
		if !bson.IsObjectIdHex(accID) {
			ServeBadRequest(w, r)
			return
		}
		acc, err := data.GetAccount(bson.ObjectIdHex(accID))
		if err != nil {
			ServeInternalServerError(w, r)
			return
		}

		ctx := Context{
			Request: r,
			Account: acc,
			Session: sess,
		}

		context.Set(r, "context", &ctx)
	}

	s.Router.ServeHTTP(w, r)
}

func NewServer() *Server {
	return &Server{
		Router: Router,
	}
}
<commit_msg>Fix bug in server context set<commit_after>package ui

import (
	"net/http"
	"os"

	"gopkg.in/mgo.v2/bson"

	"github.com/gophergala2016/papyrus/data"
	"github.com/gorilla/context"
	"github.com/gorilla/mux"
	"github.com/gorilla/sessions"
)

var Router = mux.NewRouter()

var store = sessions.NewCookieStore([]byte(os.Getenv("SECRET")))

type Server struct {
	Router *mux.Router
}

func (s Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	sess, err := store.Get(r, "s")
	if err != nil {
		ServeInternalServerError(w, r)
		return
	}

	ctx := Context{
		Request: r,
		Session: sess,
	}

	accID, ok := sess.Values["accountID"].(string)
	if ok {
		if !bson.IsObjectIdHex(accID) {
			ServeBadRequest(w, r)
			return
		}
		acc, err := data.GetAccount(bson.ObjectIdHex(accID))
		if err != nil {
			ServeInternalServerError(w, r)
			return
		}

		ctx.Account = acc
	}

	context.Set(r, "context", &ctx)

	s.Router.ServeHTTP(w, r)
}

func NewServer() *Server {
	return &Server{
		Router: Router,
	}
}
<|endoftext|>


<commit_before>package controllers

import (
	"net/http"
	"taap_project/helpers"
	"taap_project/models"
)

func NewDrillController(w http.ResponseWriter, r *http.Request) {
	if r.FormValue("submit") != "" {
		dbmap := helpers.GetGorpMap()
		drill := models.Drill{r.FormValue("title"), r.FormValue("category"), r.FormValue("imageId")}
		if err := dbmap.Insert(&drill); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
	}
}
<commit_msg>added parsing code for int ImageId<commit_after>package controllers

import (
	"net/http"
	"taap_project/helpers"
	"taap_project/models"

	"strconv"
)

func NewDrillController(w http.ResponseWriter, r *http.Request) {
	if r.FormValue("submit") != "" {
		var imageId int64
		imageId, err := strconv.ParseInt(r.FormValue("imageId"), 10, 64)
		if err != nil {
			imageId = 0
		}
		dbmap := helpers.GetGorpMap()
		drill := models.Drill{r.FormValue("title"), r.FormValue("category"), imageId}
		if err := dbmap.Insert(&drill); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
	}
}
<|endoftext|>