<commit_before>package runtime

import (
    "log"
    "strings"
    "time"

//  "github.com/ChimeraCoder/anaconda"
    "github.com/remeh/wcie/db"
)

const (
    TASK_COUNT_DONE_EACH_ITERATION = 50
)

// Our crawler.
type Cruncher struct {
    App *App
}

func NewCruncher(app *App) *Cruncher {
    return &Cruncher{App: app}
}

// Takes some task to do and crunch the data
func (c *Cruncher) Crunch() {
    taskDAO := db.NewCrunchingTaskDAO(c.App.Mongo)
    tasks, err := taskDAO.GetNext(TASK_COUNT_DONE_EACH_ITERATION)
    if err != nil {
        log.Printf("[error] While retrieving some tasks to do : %s\n", err.Error())
        return
    }

    crunched := make([]db.CrunchingTask, 0)

    // Look whether its a minute or an hour to compute.
    for _, task := range tasks {
        done := false
        // Special case for hours.
        if task.Id.Minute() == 0 {
            done = c.crunch(task.Id, true)
        }
        // Minutes computing
        done = c.crunch(task.Id, false)

        if done {
            crunched = append(crunched, task)
        }
    }

    err = taskDAO.RemoveAll(crunched)
    if err != nil {
        log.Printf("[err] [crunch] Error while removing crunched tasks : %s\n", err.Error())
    }
}

// Crunches the data for the given minute.
// Returns whether or not this data has been crunched
func (c *Cruncher) crunch(t time.Time, hour bool) bool {
    dao := db.NewTweetDAO(c.App.Mongo)
    crunchType := "minute"
    if hour {
        crunchType = "hour"
    }
    log.Printf("[info] [crunch] [%s] Will crunch the minute : %s\n", crunchType, t)

    // Checks if it's time to compute this bucket
    if isOver(t, hour) {
        return false
    }

    var tweets []db.Tweet
    var err error
    if hour {
        tweets, err = dao.GetHourBucket(t)
    } else {
        tweets, err = dao.GetMinuteBucket(t)
    }

    if err != nil {
        log.Printf("[err] [crunch] While retrieving the bucket for time %s : %s\n", crunchType, t, err.Error())
        return false
    }

    log.Printf("[info] [crunch] [%s] Retrieved %d tweets to crunch\n", crunchType, len(tweets))

    // Do the math.
    err = c.aggregateTweets(tweets)

    if err != nil {
        log.Printf("[err] [crunch] [%s] Error while computing data for tweets of : %s\n", crunchType, t)
        return false
    }

    return true
}

// To be sure that the hour / minute is finished
func (c *Cruncher) isOver(t time.Time, bool hour) bool {
    var plusOne time.Time
    if hour {
        plusOne := t.Add(time.Duration(1)*time.Hour)
        plusOne = time.Date(plusOne.Year(), plusOne.Month(), plusOne.Day(), plusOne.Hour(), 0, 0, 0, t.Location())
    } else {
        plusOne := t.Add(time.Duration(1)*time.Minute)
        plusOne = time.Date(plusOne.Year(), plusOne.Month(), plusOne.Day(), plusOne.Hour(), plusOne.Minute(), 0, 0, t.Location())
    }

    // Test that it's time to compute it
    if plusOne.isAfter(time.Now()) {
        return true
    }
    return false:
}

func (c *Cruncher) aggregateTweets(tweets []db.Tweet) error {
    // TODO This method could be speed up by
    // ordering the tweets with their query
    // and using regexp for the query.

    // In this map, I'll store the number of occurences
    // of each word located just after the query
    data := make(map[string]int)

    // This algorithm could be speed up
    // Too many Trim call
    for _, tweet := range tweets {
        parts := strings.Split(strings.ToLower(tweet.Text), tweet.Query)
        if len(parts) == 1 {
            log.Printf("[warn] [crunch] Unable to explode the query with id '%d', text '%s'\n", tweet.TweetId, tweet.Text)
            continue
        }
        trimmed := strings.Trim(parts[1], " .,!?")
        nextSpace := strings.Index(trimmed, " ")
        word := ""
        if nextSpace == -1 {
            word = trimmed
        } else {
            word = strings.Trim(trimmed[0:nextSpace], ".!?,")
        }

        if data[word] != 0 {
            data[word] = data[word] + 1
        } else {
            data[word] = 1
        }
    }

    // TODO save this data.

    return nil
}
<commit_msg>Wait for the end of minute / hour to compute it<commit_after>package runtime

import (
    "log"
    "strings"
    "time"

//  "github.com/ChimeraCoder/anaconda"
    "github.com/remeh/wcie/db"
)

const (
    TASK_COUNT_DONE_EACH_ITERATION = 50
)

// Our crawler.
type Cruncher struct {
    App *App
}

func NewCruncher(app *App) *Cruncher {
    return &Cruncher{App: app}
}

// Takes some task to do and crunch the data
func (c *Cruncher) Crunch() {
    taskDAO := db.NewCrunchingTaskDAO(c.App.Mongo)
    tasks, err := taskDAO.GetNext(TASK_COUNT_DONE_EACH_ITERATION)
    if err != nil {
        log.Printf("[error] While retrieving some tasks to do : %s\n", err.Error())
        return
    }

    crunched := make([]db.CrunchingTask, 0)

    // Look whether its a minute or an hour to compute.
    for _, task := range tasks {
        done := false
        // Special case for hours.
        if task.Id.Minute() == 0 {
            // Crunch as minute and hour
            done = (c.crunch(task.Id, false) && c.crunch(task.Id, true))
        } else {
            // Minutes computing
            done = c.crunch(task.Id, false)
        }

        if done {
            crunched = append(crunched, task)
        }
    }

    err = taskDAO.RemoveAll(crunched)
    if err != nil {
        log.Printf("[err] [crunch] Error while removing crunched tasks : %s\n", err.Error())
    }
}

// Crunches the data for the given minute.
// Returns whether or not this data has been crunched
func (c *Cruncher) crunch(t time.Time, hour bool) bool {
    dao := db.NewTweetDAO(c.App.Mongo)
    crunchType := "minute"
    if hour {
        crunchType = "hour"
    }

    // Checks if it's time to compute this bucket
    if !c.isOver(t, hour) {
        return false
    }

    log.Printf("[info] [crunch] [%s] Will crunch the %s : %s\n", crunchType, crunchType, t)

    var tweets []db.Tweet
    var err error
    if hour {
        tweets, err = dao.GetHourBucket(t)
    } else {
        tweets, err = dao.GetMinuteBucket(t)
    }

    if err != nil {
        log.Printf("[err] [crunch] While retrieving the bucket for time %s : %s\n", crunchType, t, err.Error())
        return false
    }

    log.Printf("[info] [crunch] [%s] Retrieved %d tweets to crunch\n", crunchType, len(tweets))

    // Do the math.
    err = c.aggregateTweets(tweets)

    if err != nil {
        log.Printf("[err] [crunch] [%s] Error while computing data for tweets of : %s\n", crunchType, t)
        return false
    }

    return true
}

// To be sure that the hour / minute is finished
func (c *Cruncher) isOver(t time.Time, hour bool) bool {
    var plusOne time.Time
    if hour {
        plusOne = t.Add(time.Duration(1)*time.Hour)
        plusOne = time.Date(plusOne.Year(), plusOne.Month(), plusOne.Day(), plusOne.Hour(), 0, 0, 0, t.Location())
    } else {
        plusOne = t.Add(time.Duration(1)*time.Minute)
        plusOne = time.Date(plusOne.Year(), plusOne.Month(), plusOne.Day(), plusOne.Hour(), plusOne.Minute(), 0, 0, t.Location())
    }

    // Test that it's time to compute it
    if plusOne.Before(time.Now()) {
        return true
    }
    return false
}

func (c *Cruncher) aggregateTweets(tweets []db.Tweet) error {
    // TODO This method could be speed up by
    // ordering the tweets with their query
    // and using regexp for the query.

    // In this map, I'll store the number of occurences
    // of each word located just after the query
    data := make(map[string]int)

    // This algorithm could be speed up
    // Too many Trim call
    for _, tweet := range tweets {
        parts := strings.Split(strings.ToLower(tweet.Text), tweet.Query)
        if len(parts) == 1 {
            log.Printf("[warn] [crunch] Unable to explode the query with id '%d', text '%s'\n", tweet.TweetId, tweet.Text)
            continue
        }
        trimmed := strings.Trim(parts[1], " .,!?")
        nextSpace := strings.Index(trimmed, " ")
        word := ""
        if nextSpace == -1 {
            word = trimmed
        } else {
            word = strings.Trim(trimmed[0:nextSpace], ".!?,")
        }

        if data[word] != 0 {
            data[word] = data[word] + 1
        } else {
            data[word] = 1
        }
    }

    // TODO save this data.

    return nil
}
<|endoftext|>


<commit_before>package integration

import (
	"testing"

	"github.com/docker/docker/pkg/testutil/assert"
	"github.com/zorkian/go-datadog-api"
)

func init() {
	client = initTest()
}

func TestInvalidAuth(t *testing.T) {
	// Override the correct credentials
	c := datadog.NewClient("INVALID", "INVALID")

	valid, err := c.Validate()
	if err != nil {
		t.Fatalf("Testing authentication failed when it shouldn't: %s", err)
	}

	assert.Equal(t, valid, false)
}

func TestValidAuth(t *testing.T) {
	valid, err := client.Validate()

	if err != nil {
		t.Fatalf("Testing authentication failed when it shouldn't: %s", err)
	}

	assert.Equal(t, valid, true)
}
<commit_msg>Accidentally used the Docker assert package instead of the already vendored testify package.<commit_after>package integration

import (
	"testing"

	"github.com/zorkian/go-datadog-api"
	"github.com/stretchr/testify/assert"
)

func init() {
	client = initTest()
}

func TestInvalidAuth(t *testing.T) {
	// Override the correct credentials
	c := datadog.NewClient("INVALID", "INVALID")

	valid, err := c.Validate()
	if err != nil {
		t.Fatalf("Testing authentication failed when it shouldn't: %s", err)
	}

	assert.Equal(t, valid, false)
}

func TestValidAuth(t *testing.T) {
	valid, err := client.Validate()

	if err != nil {
		t.Fatalf("Testing authentication failed when it shouldn't: %s", err)
	}

	assert.Equal(t, valid, true)
}
<|endoftext|>


<commit_before>package floatgeom

import (
	"math"

	"github.com/oakmound/oak/alg"
)

// Point2 represents a 2D point in space.
type Point2 [2]float64

// Point3 represents a 3D point in space.
type Point3 [3]float64

// Point4 represents a 4D point, in space + some additional dimension.
type Point4 [4]float64

// AnglePoint creates a unit vector from the given angle in degrees as a Point2.
func AnglePoint(angle float64) Point2 {
	return RadianPoint(angle * math.Pi / 180)
}

// RadianPoint creates a unit vector from the given angle in radians as a Point2.
func RadianPoint(radians float64) Point2 {
	return Point2{math.Cos(radians), math.Sin(radians)}
}

// Dim returns the value of p in the ith dimension.
// Panics if i > 1. No check is made for efficiency's sake, pending benchmarks,
// but adding an error here would significantly worsen the API.
func (p Point2) Dim(i int) float64 {
	return p[i]
}

// Dim returns the value of p in the ith dimension.
// Panics if i > 2. No check is made for efficiency's sake, pending benchmarks,
// but adding an error here would significantly worsen the API.
func (p Point3) Dim(i int) float64 {
	return p[i]
}

// Dim returns the value of p in the ith dimension.
// Panics if i > 3. No check is made for efficiency's sake, pending benchmarks,
// but adding an error here would significantly worsen the API.
func (p Point4) Dim(i int) float64 {
	return p[i]
}

// X returns p's value on the X axis.
func (p Point2) X() float64 {
	return p.Dim(0)
}

// Y returns p's value on the Y axis.
func (p Point2) Y() float64 {
	return p.Dim(1)
}

// X returns p's value on the X axis.
func (p Point3) X() float64 {
	return p.Dim(0)
}

// Y returns p's value on the Y axis.
func (p Point3) Y() float64 {
	return p.Dim(1)
}

// Z returns p's value on the Z axis.
func (p Point3) Z() float64 {
	return p.Dim(2)
}

// X returns p's value on the X axis.
func (p Point4) X() float64 {
	return p.Dim(0)
}

// Y returns p's value on the Y axis.
func (p Point4) Y() float64 {
	return p.Dim(1)
}

// Z returns p's value on the Z axis.
func (p Point4) Z() float64 {
	return p.Dim(2)
}

// W returns p's value on the W axis.
func (p Point4) W() float64 {
	return p.Dim(3)
}

// Distance calculates the distance between this Point2 and another.
func (p Point2) Distance(p2 Point2) float64 {
	return Distance2(p.X(), p.Y(), p2.X(), p2.Y())
}

// Distance calculates the distance between this Point3 and another.
func (p Point3) Distance(p2 Point3) float64 {
	return Distance3(p.X(), p.Y(), p.Z(), p2.X(), p2.Y(), p2.Z())
}

// Distance2 calculates the euclidean distance between two points, as two (x,y) pairs
func Distance2(x1, y1, x2, y2 float64) float64 {
	return math.Sqrt(
		math.Pow(x1-x2, 2) +
			math.Pow(y1-y2, 2))
}

// Distance3 calculates the euclidean distance between two points, as two (x,y,z) triplets
func Distance3(x1, y1, z1, x2, y2, z2 float64) float64 {
	return math.Sqrt(
		math.Pow(x1-x2, 2) +
			math.Pow(y1-y2, 2) +
			math.Pow(z1-z2, 2))
}

// LesserOf returns the lowest values on each axis of the input points as a point.
func (p Point2) LesserOf(ps ...Point2) Point2 {
	for _, p2 := range ps {
		p[0] = math.Min(p[0], p2[0])
		p[1] = math.Min(p[1], p2[1])
	}
	return p
}

// LesserOf returns the lowest values on each axis of the input points as a point.
func (p Point3) LesserOf(ps ...Point3) Point3 {
	for _, p2 := range ps {
		p[0] = math.Min(p[0], p2[0])
		p[1] = math.Min(p[1], p2[1])
		p[2] = math.Min(p[2], p2[2])
	}
	return p
}

// GreaterOf returns the highest values on each axis of the input points as a point.
func (p Point2) GreaterOf(ps ...Point2) Point2 {
	for _, p2 := range ps {
		p[0] = math.Max(p[0], p2[0])
		p[1] = math.Max(p[1], p2[1])
	}
	return p
}

// GreaterOf returns the highest values on each axis of the input points as a point.
func (p Point3) GreaterOf(ps ...Point3) Point3 {
	for _, p2 := range ps {
		p[0] = math.Max(p[0], p2[0])
		p[1] = math.Max(p[1], p2[1])
		p[2] = math.Max(p[2], p2[2])
	}
	return p
}

// Add combines the input points via addition.
func (p Point2) Add(ps ...Point2) Point2 {
	for _, p2 := range ps {
		p[0] += p2[0]
		p[1] += p2[1]
	}
	return p
}

// Sub combines the input points via subtraction.
func (p Point2) Sub(ps ...Point2) Point2 {
	for _, p2 := range ps {
		p[0] -= p2[0]
		p[1] -= p2[1]
	}
	return p
}

// Mul combines in the input points via multiplication.
func (p Point2) Mul(ps ...Point2) Point2 {
	for _, p2 := range ps {
		p[0] *= p2[0]
		p[1] *= p2[1]
	}
	return p
}

// MulConst multiplies all elements of a point by the input floats
func (p Point2) MulConst(fs ...float64) Point2 {
	for _, f := range fs {
		p[0] *= f
		p[1] *= f
	}
	return p
}

// Cross gets the cross product of two Point 3s
func (p Point3) Cross(p2 Point3) Point3 {
	return Point3{p.Y()*p2.Z() - p.Z()*p2.Y(), p.Z()*p2.X() - p.X()*p2.Z(), p.X()*p2.Y() - p.Y()*p2.X()}
}

// Div combines the input points via division.
// Div does not check that the inputs are non zero before operating,
// and can panic if that is not true.
func (p Point2) Div(ps ...Point2) Point2 {
	for _, p2 := range ps {
		p[0] /= p2[0]
		p[1] /= p2[1]
	}
	return p
}

// DivConst divides all elements of a point by the input floats
// DivConst does not check that the inputs are non zero before operating,
// and can panic if that is not true.
func (p Point2) DivConst(fs ...float64) Point2 {
	for _, f := range fs {
		p[0] /= f
		p[1] /= f
	}
	return p
}

// Add combines the input points via addition.
func (p Point3) Add(ps ...Point3) Point3 {
	for _, p2 := range ps {
		p[0] += p2[0]
		p[1] += p2[1]
		p[2] += p2[2]
	}
	return p
}

// Sub combines the input points via subtraction.
func (p Point3) Sub(ps ...Point3) Point3 {
	for _, p2 := range ps {
		p[0] -= p2[0]
		p[1] -= p2[1]
		p[2] -= p2[2]
	}
	return p
}

// Mul combines in the input points via multiplication.
func (p Point3) Mul(ps ...Point3) Point3 {
	for _, p2 := range ps {
		p[0] *= p2[0]
		p[1] *= p2[1]
		p[2] *= p2[2]
	}
	return p
}

// MulConst multiplies all elements of a point by the input floats
func (p Point3) MulConst(fs ...float64) Point3 {
	for _, f := range fs {
		p[0] *= f
		p[1] *= f
		p[2] *= f
	}
	return p
}

// Div combines the input points via division.
// Div does not check that the inputs are non zero before operating,
// and can panic if that is not true.
func (p Point3) Div(ps ...Point3) Point3 {
	for _, p2 := range ps {
		p[0] /= p2[0]
		p[1] /= p2[1]
		p[2] /= p2[2]
	}
	return p
}

// DivConst divides all elements of a point by the input floats
// DivConst does not check that the inputs are non zero before operating,
// and can panic if that is not true.
func (p Point3) DivConst(fs ...float64) Point3 {
	for _, f := range fs {
		p[0] /= f
		p[1] /= f
		p[2] /= f
	}
	return p
}

// Dot returns the dot product of the input points
func (p Point2) Dot(p2 Point2) float64 {
	return p[0]*p2[0] + p[1]*p2[1]
}

// Dot returns the dot product of the input points
func (p Point3) Dot(p2 Point3) float64 {
	return p[0]*p2[0] + p[1]*p2[1] + p[2]*p2[2]
}

// Magnitude returns the magnitude of the combined components of a Point
func (p Point2) Magnitude() float64 {
	return math.Sqrt(p.Dot(p))
}

// Magnitude returns the magnitude of the combined components of a Point
func (p Point3) Magnitude() float64 {
	return math.Sqrt(p.Dot(p))
}

// Normalize converts this point into a unit vector.
func (p Point2) Normalize() Point2 {
	mgn := p.Magnitude()
	if mgn == 0 {
		return p
	}
	return p.DivConst(mgn)
}

// Normalize converts this point into a unit vector.
func (p Point3) Normalize() Point3 {
	mgn := p.Magnitude()
	if mgn == 0 {
		return p
	}
	return p.DivConst(mgn)
}

// Rotate takes in a set of angles and rotates v by their sum
// the input angles are expected to be in degrees.
func (p Point2) Rotate(fs ...float64) Point2 {
	angle := 0.0
	for _, f := range fs {
		angle += f
	}
	mgn := p.Magnitude()
	angle = p.ToRadians() + (angle * alg.DegToRad)

	return Point2{math.Cos(angle) * mgn, math.Sin(angle) * mgn}
}

// RotateRadians takes in a set of angles and rotates v by their sum
// the input angles are expected to be in radians.
func (p Point2) RotateRadians(fs ...float64) Point2 {
	angle := p.ToRadians()
	for _, f := range fs {
		angle += f
	}
	mgn := p.Magnitude()

	return Point2{math.Cos(angle) * mgn, math.Sin(angle) * mgn}
}

// ToRect converts this point into a rectangle spanning span distance
// in each axis.
func (p Point2) ToRect(span float64) Rect2 {
	return NewRect2WH(p[0], p[1], span, span)
}

// ToRect converts this point into a rectangle spanning span distance
// in each axis.
func (p Point3) ToRect(span float64) Rect3 {
	return NewRect3WH(p[0], p[1], p[2], span, span, span)
}

// ProjectX projects the Point3 onto the x axis, removing it's
// x component and returning a Point2
// todo: I'm not sure about this (these) function name
func (p Point3) ProjectX() Point2 {
	return Point2{p[1], p[2]}
}

// ProjectY projects the Point3 onto the y axis, removing it's
// y component and returning a Point2
func (p Point3) ProjectY() Point2 {
	return Point2{p[0], p[2]}
}

// ProjectZ projects the Point3 onto the z axis, removing it's
// z component and returning a Point2
func (p Point3) ProjectZ() Point2 {
	return Point2{p[0], p[1]}
}

// ToAngle returns this point as an angle in degrees.
func (p Point2) ToAngle() float64 {
	return p.ToRadians() * alg.RadToDeg
}

// ToRadians returns this point as an angle in radians.
func (p Point2) ToRadians() float64 {
	return math.Atan2(p[1], p[0])
}

// AngleTo returns the angle from p to p2 in degrees.
func (p Point2) AngleTo(p2 Point2) float64 {
	return p.Sub(p2).ToAngle()
}

// RadiansTo returns the angle from p to p2 in radians.
func (p Point2) RadiansTo(p2 Point2) float64 {
	return p.Sub(p2).ToRadians()
}
<commit_msg>Condense / specify docs in floatgeom points<commit_after>package floatgeom

import (
	"math"

	"github.com/oakmound/oak/alg"
)

// Point2 represents a 2D point on a plane.
type Point2 [2]float64

// Point3 represents a 3D point in space.
type Point3 [3]float64

// Point4 represents a 4D point, in space + some additional dimension.
type Point4 [4]float64

// AnglePoint creates a unit vector from the given angle in degrees as a Point2.
func AnglePoint(angle float64) Point2 {
	return RadianPoint(angle * math.Pi / 180)
}

// RadianPoint creates a unit vector from the given angle in radians as a Point2.
func RadianPoint(radians float64) Point2 {
	return Point2{math.Cos(radians), math.Sin(radians)}
}

// Dim returns the value of p in the ith dimension.
// Panics if i > 1.
func (p Point2) Dim(i int) float64 {
	return p[i]
}

// Dim returns the value of p in the ith dimension.
// Panics if i > 2.
func (p Point3) Dim(i int) float64 {
	return p[i]
}

// Dim returns the value of p in the ith dimension.
// Panics if i > 3.
func (p Point4) Dim(i int) float64 {
	return p[i]
}

// X returns p's value on the X axis.
func (p Point2) X() float64 {
	return p.Dim(0)
}

// Y returns p's value on the Y axis.
func (p Point2) Y() float64 {
	return p.Dim(1)
}

// X returns p's value on the X axis.
func (p Point3) X() float64 {
	return p.Dim(0)
}

// Y returns p's value on the Y axis.
func (p Point3) Y() float64 {
	return p.Dim(1)
}

// Z returns p's value on the Z axis.
func (p Point3) Z() float64 {
	return p.Dim(2)
}

// X returns p's value on the X axis.
func (p Point4) X() float64 {
	return p.Dim(0)
}

// Y returns p's value on the Y axis.
func (p Point4) Y() float64 {
	return p.Dim(1)
}

// Z returns p's value on the Z axis.
func (p Point4) Z() float64 {
	return p.Dim(2)
}

// W returns p's value on the W axis.
func (p Point4) W() float64 {
	return p.Dim(3)
}

// Distance calculates the distance between this Point2 and another.
func (p Point2) Distance(p2 Point2) float64 {
	return Distance2(p.X(), p.Y(), p2.X(), p2.Y())
}

// Distance calculates the distance between this Point3 and another.
func (p Point3) Distance(p2 Point3) float64 {
	return Distance3(p.X(), p.Y(), p.Z(), p2.X(), p2.Y(), p2.Z())
}

// Distance2 calculates the euclidean distance between two points, as two (x,y) pairs
func Distance2(x1, y1, x2, y2 float64) float64 {
	return math.Sqrt(
		math.Pow(x1-x2, 2) +
			math.Pow(y1-y2, 2))
}

// Distance3 calculates the euclidean distance between two points, as two (x,y,z) triplets
func Distance3(x1, y1, z1, x2, y2, z2 float64) float64 {
	return math.Sqrt(
		math.Pow(x1-x2, 2) +
			math.Pow(y1-y2, 2) +
			math.Pow(z1-z2, 2))
}

// LesserOf returns the lowest values on each axis of the input points as a point.
func (p Point2) LesserOf(ps ...Point2) Point2 {
	for _, p2 := range ps {
		p[0] = math.Min(p[0], p2[0])
		p[1] = math.Min(p[1], p2[1])
	}
	return p
}

// LesserOf returns the lowest values on each axis of the input points as a point.
func (p Point3) LesserOf(ps ...Point3) Point3 {
	for _, p2 := range ps {
		p[0] = math.Min(p[0], p2[0])
		p[1] = math.Min(p[1], p2[1])
		p[2] = math.Min(p[2], p2[2])
	}
	return p
}

// GreaterOf returns the highest values on each axis of the input points as a point.
func (p Point2) GreaterOf(ps ...Point2) Point2 {
	for _, p2 := range ps {
		p[0] = math.Max(p[0], p2[0])
		p[1] = math.Max(p[1], p2[1])
	}
	return p
}

// GreaterOf returns the highest values on each axis of the input points as a point.
func (p Point3) GreaterOf(ps ...Point3) Point3 {
	for _, p2 := range ps {
		p[0] = math.Max(p[0], p2[0])
		p[1] = math.Max(p[1], p2[1])
		p[2] = math.Max(p[2], p2[2])
	}
	return p
}

// Add combines the input points via addition.
func (p Point2) Add(ps ...Point2) Point2 {
	for _, p2 := range ps {
		p[0] += p2[0]
		p[1] += p2[1]
	}
	return p
}

// Sub combines the input points via subtraction.
func (p Point2) Sub(ps ...Point2) Point2 {
	for _, p2 := range ps {
		p[0] -= p2[0]
		p[1] -= p2[1]
	}
	return p
}

// Mul combines in the input points via multiplication.
func (p Point2) Mul(ps ...Point2) Point2 {
	for _, p2 := range ps {
		p[0] *= p2[0]
		p[1] *= p2[1]
	}
	return p
}

// MulConst multiplies all elements of a point by the input floats
func (p Point2) MulConst(fs ...float64) Point2 {
	for _, f := range fs {
		p[0] *= f
		p[1] *= f
	}
	return p
}

// Cross gets the cross product of two Point 3s
func (p Point3) Cross(p2 Point3) Point3 {
	return Point3{p.Y()*p2.Z() - p.Z()*p2.Y(), p.Z()*p2.X() - p.X()*p2.Z(), p.X()*p2.Y() - p.Y()*p2.X()}
}

// Div combines the input points via division.
// Div does not check that the inputs are non zero before operating,
// and can panic if that is not true.
func (p Point2) Div(ps ...Point2) Point2 {
	for _, p2 := range ps {
		p[0] /= p2[0]
		p[1] /= p2[1]
	}
	return p
}

// DivConst divides all elements of a point by the input floats
// DivConst does not check that the inputs are non zero before operating,
// and can panic if that is not true.
func (p Point2) DivConst(fs ...float64) Point2 {
	for _, f := range fs {
		p[0] /= f
		p[1] /= f
	}
	return p
}

// Add combines the input points via addition.
func (p Point3) Add(ps ...Point3) Point3 {
	for _, p2 := range ps {
		p[0] += p2[0]
		p[1] += p2[1]
		p[2] += p2[2]
	}
	return p
}

// Sub combines the input points via subtraction.
func (p Point3) Sub(ps ...Point3) Point3 {
	for _, p2 := range ps {
		p[0] -= p2[0]
		p[1] -= p2[1]
		p[2] -= p2[2]
	}
	return p
}

// Mul combines in the input points via multiplication.
func (p Point3) Mul(ps ...Point3) Point3 {
	for _, p2 := range ps {
		p[0] *= p2[0]
		p[1] *= p2[1]
		p[2] *= p2[2]
	}
	return p
}

// MulConst multiplies all elements of a point by the input floats
func (p Point3) MulConst(fs ...float64) Point3 {
	for _, f := range fs {
		p[0] *= f
		p[1] *= f
		p[2] *= f
	}
	return p
}

// Div combines the input points via division.
// Div does not check that the inputs are non zero before operating,
// and can panic if that is not true.
func (p Point3) Div(ps ...Point3) Point3 {
	for _, p2 := range ps {
		p[0] /= p2[0]
		p[1] /= p2[1]
		p[2] /= p2[2]
	}
	return p
}

// DivConst divides all elements of a point by the input floats
// DivConst does not check that the inputs are non zero before operating,
// and can panic if that is not true.
func (p Point3) DivConst(fs ...float64) Point3 {
	for _, f := range fs {
		p[0] /= f
		p[1] /= f
		p[2] /= f
	}
	return p
}

// Dot returns the dot product of the input points
func (p Point2) Dot(p2 Point2) float64 {
	return p[0]*p2[0] + p[1]*p2[1]
}

// Dot returns the dot product of the input points
func (p Point3) Dot(p2 Point3) float64 {
	return p[0]*p2[0] + p[1]*p2[1] + p[2]*p2[2]
}

// Magnitude returns the magnitude of the combined components of a Point
func (p Point2) Magnitude() float64 {
	return math.Sqrt(p.Dot(p))
}

// Magnitude returns the magnitude of the combined components of a Point
func (p Point3) Magnitude() float64 {
	return math.Sqrt(p.Dot(p))
}

// Normalize converts this point into a unit vector.
func (p Point2) Normalize() Point2 {
	mgn := p.Magnitude()
	if mgn == 0 {
		return p
	}
	return p.DivConst(mgn)
}

// Normalize converts this point into a unit vector.
func (p Point3) Normalize() Point3 {
	mgn := p.Magnitude()
	if mgn == 0 {
		return p
	}
	return p.DivConst(mgn)
}

// Rotate takes in a set of angles and rotates v by their sum
// the input angles are expected to be in degrees.
func (p Point2) Rotate(fs ...float64) Point2 {
	angle := 0.0
	for _, f := range fs {
		angle += f
	}
	mgn := p.Magnitude()
	angle = p.ToRadians() + (angle * alg.DegToRad)

	return Point2{math.Cos(angle) * mgn, math.Sin(angle) * mgn}
}

// RotateRadians takes in a set of angles and rotates v by their sum
// the input angles are expected to be in radians.
func (p Point2) RotateRadians(fs ...float64) Point2 {
	angle := p.ToRadians()
	for _, f := range fs {
		angle += f
	}
	mgn := p.Magnitude()

	return Point2{math.Cos(angle) * mgn, math.Sin(angle) * mgn}
}

// ToRect converts this point into a rectangle spanning span distance
// in each axis.
func (p Point2) ToRect(span float64) Rect2 {
	return NewRect2WH(p[0], p[1], span, span)
}

// ToRect converts this point into a rectangle spanning span distance
// in each axis.
func (p Point3) ToRect(span float64) Rect3 {
	return NewRect3WH(p[0], p[1], p[2], span, span, span)
}

// ProjectX projects the Point3 onto the x axis, removing it's
// x component and returning a Point2
// todo: I'm not sure about this (these) function name
func (p Point3) ProjectX() Point2 {
	return Point2{p[1], p[2]}
}

// ProjectY projects the Point3 onto the y axis, removing it's
// y component and returning a Point2
func (p Point3) ProjectY() Point2 {
	return Point2{p[0], p[2]}
}

// ProjectZ projects the Point3 onto the z axis, removing it's
// z component and returning a Point2
func (p Point3) ProjectZ() Point2 {
	return Point2{p[0], p[1]}
}

// ToAngle returns this point as an angle in degrees.
func (p Point2) ToAngle() float64 {
	return p.ToRadians() * alg.RadToDeg
}

// ToRadians returns this point as an angle in radians.
func (p Point2) ToRadians() float64 {
	return math.Atan2(p[1], p[0])
}

// AngleTo returns the angle from p to p2 in degrees.
func (p Point2) AngleTo(p2 Point2) float64 {
	return p.Sub(p2).ToAngle()
}

// RadiansTo returns the angle from p to p2 in radians.
func (p Point2) RadiansTo(p2 Point2) float64 {
	return p.Sub(p2).ToRadians()
}
<|endoftext|>


<commit_before>/*
Copyright 2021 The Ceph-CSI 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 kms

import (
	"context"
	"encoding/base64"
	"errors"
	"fmt"

	"github.com/ceph/ceph-csi/internal/util/k8s"
	"github.com/ceph/ceph-csi/internal/util/log"

	kp "github.com/IBM/keyprotect-go-client"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

const (
	kmsTypeKeyProtectMetadata    = "ibmkeyprotect"
	kmsTypeKeyProtectMetadataOld = "kp-metadata"
	// keyProtectMetadataDefaultSecretsName is the default name of the Kubernetes Secret
	// that contains the credentials to access the Key Protect KMS. The name of
	// the Secret can be configured by setting the `IBM_KP_SECRET_NAME`
	// option.
	//
	// #nosec:G101, value not credential, just references token.
	keyProtectMetadataDefaultSecretsName = "ceph-csi-kp-credentials"

	// keyProtectSecretNameKey contains the name of the Kubernetes Secret that has
	// the credentials to access the Key ProtectKMS.
	//
	// #nosec:G101, no hardcoded secret, this is a configuration key.
	keyProtectSecretNameKey = "IBM_KP_SECRET_NAME"
	keyProtectRegionKey     = "IBM_KP_REGION"

	keyProtectServiceInstanceID = "IBM_KP_SERVICE_INSTANCE_ID"
	keyProtectServiceBaseURL    = "IBM_KP_BASE_URL"
	keyProtectServiceTokenURL   = "IBM_KP_TOKEN_URL" //nolint:gosec // only configuration key
	// The following options are part of the Kubernetes Secrets.
	// #nosec:G101, no hardcoded secrets, only configuration keys.
	keyProtectServiceAPIKey   = "IBM_KP_SERVICE_API_KEY"
	KeyProtectCustomerRootKey = "IBM_KP_CUSTOMER_ROOT_KEY"
	keyProtectSessionToken    = "IBM_KP_SESSION_TOKEN" //nolint:gosec // only configuration key
	keyProtectCRK             = "IBM_KP_CRK_ARN"
)

var _ = RegisterProvider(Provider{
	UniqueID:    kmsTypeKeyProtectMetadata,
	Initializer: initKeyProtectKMS,
})

// RegisterProvider for kmsTypeKeyProtectMetadataOld is kept here for backward compatibility.
var _ = RegisterProvider(Provider{
	UniqueID:    kmsTypeKeyProtectMetadataOld,
	Initializer: initKeyProtectKMSOld,
})

// initKeyProtectKMSOld is the wrapper with a warning log.
func initKeyProtectKMSOld(args ProviderInitArgs) (EncryptionKMS, error) {
	log.WarningLogMsg("%q is deprecated provider for IBM key Protect,"+
		"use new provider name %q in the configuration, proceeding with %q",
		kmsTypeKeyProtectMetadataOld, kmsTypeKeyProtectMetadata, kmsTypeKeyProtectMetadata)

	return initKeyProtectKMS(args)
}

// KeyProtectKMS store the KMS connection information retrieved from the kms configmap.
type keyProtectKMS struct {
	// basic options to get the secret
	namespace  string
	secretName string

	// standard KeyProtect configuration options
	client            *kp.Client
	serviceAPIKey     string
	customerRootKey   string
	serviceInstanceID string
	baseURL           string
	tokenURL          string
	region            string
	sessionToken      string
	crk               string
}

func initKeyProtectKMS(args ProviderInitArgs) (EncryptionKMS, error) {
	kms := &keyProtectKMS{
		namespace: args.Namespace,
	}
	// required options for further configuration (getting secrets)
	err := setConfigString(&kms.secretName, args.Config, keyProtectSecretNameKey)
	if errors.Is(err, errConfigOptionInvalid) {
		return nil, err
	} else if errors.Is(err, errConfigOptionMissing) {
		kms.secretName = keyProtectMetadataDefaultSecretsName
	}

	err = setConfigString(&kms.serviceInstanceID, args.Config, keyProtectServiceInstanceID)
	if err != nil {
		return nil, err
	}

	err = setConfigString(&kms.baseURL, args.Config, keyProtectServiceBaseURL)
	if errors.Is(err, errConfigOptionInvalid) {
		return nil, err
	} else if errors.Is(err, errConfigOptionMissing) {
		kms.baseURL = kp.DefaultBaseURL
	}

	err = setConfigString(&kms.tokenURL, args.Config, keyProtectServiceTokenURL)
	if errors.Is(err, errConfigOptionInvalid) {
		return nil, err
	} else if errors.Is(err, errConfigOptionMissing) {
		kms.tokenURL = kp.DefaultTokenURL
	}

	// read the Kubernetes Secret with credentials
	secrets, err := kms.getSecrets()
	if err != nil {
		return nil, fmt.Errorf("failed to get secrets for %T: %w", kms,
			err)
	}

	err = setConfigString(&kms.serviceAPIKey, secrets, keyProtectServiceAPIKey)
	if err != nil {
		return nil, err
	}
	err = setConfigString(&kms.customerRootKey, secrets, KeyProtectCustomerRootKey)
	if err != nil {
		return nil, err
	}

	// keyProtectSessionToken is optional
	err = setConfigString(&kms.sessionToken, secrets, keyProtectSessionToken)
	if errors.Is(err, errConfigOptionInvalid) {
		return nil, err
	}

	// KeyProtect Region is optional
	err = setConfigString(&kms.region, args.Config, keyProtectRegionKey)
	if errors.Is(err, errConfigOptionInvalid) {
		return nil, err
	}

	// crk arn is optional
	err = setConfigString(&kms.crk, secrets, keyProtectCRK)
	if errors.Is(err, errConfigOptionInvalid) {
		return nil, err
	}

	return kms, nil
}

func (kms *keyProtectKMS) getSecrets() (map[string]interface{}, error) {
	c, err := k8s.NewK8sClient()
	if err != nil {
		return nil, fmt.Errorf("failed to connect to Kubernetes to "+
			"get Secret %s/%s: %w", kms.namespace, kms.secretName, err)
	}

	secret, err := c.CoreV1().Secrets(kms.namespace).Get(context.TODO(),
		kms.secretName, metav1.GetOptions{})
	if err != nil {
		return nil, fmt.Errorf("failed to get Secret %s/%s: %w",
			kms.namespace, kms.secretName, err)
	}

	config := make(map[string]interface{})

	for k, v := range secret.Data {
		switch k {
		case keyProtectServiceAPIKey, KeyProtectCustomerRootKey, keyProtectSessionToken, keyProtectCRK:
			config[k] = string(v)
		default:
			return nil, fmt.Errorf("unsupported option for KMS "+
				"provider %q: %s", kmsTypeKeyProtectMetadata, k)
		}
	}

	return config, nil
}

func (kms *keyProtectKMS) Destroy() {
	// Nothing to do.
}

func (kms *keyProtectKMS) RequiresDEKStore() DEKStoreType {
	return DEKStoreMetadata
}

func (kms *keyProtectKMS) getService() error {
	// Use your Service API Key and your KeyProtect Service Instance ID to create a ClientConfig
	cc := kp.ClientConfig{
		BaseURL:    kms.baseURL,
		TokenURL:   kms.tokenURL,
		APIKey:     kms.serviceAPIKey,
		InstanceID: kms.serviceInstanceID,
	}

	// Build a new client from the config
	client, err := kp.New(cc, kp.DefaultTransport())
	if err != nil {
		return fmt.Errorf("failed to create keyprotect client: %w", err)
	}
	kms.client = client

	return nil
}

// EncryptDEK uses the KeyProtect KMS and the configured CRK to encrypt the DEK.
func (kms *keyProtectKMS) EncryptDEK(volumeID, plainDEK string) (string, error) {
	if err := kms.getService(); err != nil {
		return "", fmt.Errorf("could not get KMS service: %w", err)
	}

	dekByteSlice := []byte(plainDEK)
	aadVolID := []string{volumeID}
	result, err := kms.client.Wrap(context.TODO(), kms.customerRootKey, dekByteSlice, &aadVolID)
	if err != nil {
		return "", fmt.Errorf("failed to wrap the DEK: %w", err)
	}

	// base64 encode the encrypted DEK, so that storing it should not have
	// issues

	return base64.StdEncoding.EncodeToString(result), nil
}

// DecryptDEK uses the Key protect KMS and the configured CRK to decrypt the DEK.
func (kms *keyProtectKMS) DecryptDEK(volumeID, encryptedDEK string) (string, error) {
	if err := kms.getService(); err != nil {
		return "", fmt.Errorf("could not get KMS service: %w", err)
	}

	ciphertextBlob, err := base64.StdEncoding.DecodeString(encryptedDEK)
	if err != nil {
		return "", fmt.Errorf("failed to decode base64 cipher: %w",
			err)
	}

	aadVolID := []string{volumeID}
	result, err := kms.client.Unwrap(context.TODO(), kms.customerRootKey, ciphertextBlob, &aadVolID)
	if err != nil {
		return "", fmt.Errorf("failed to unwrap the DEK: %w", err)
	}

	return string(result), nil
}
<commit_msg>rbd: remove kp-metadata register functions of HPCS/Key Protect<commit_after>/*
Copyright 2021 The Ceph-CSI 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 kms

import (
	"context"
	"encoding/base64"
	"errors"
	"fmt"

	"github.com/ceph/ceph-csi/internal/util/k8s"

	kp "github.com/IBM/keyprotect-go-client"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

const (
	kmsTypeKeyProtectMetadata = "ibmkeyprotect"
	// keyProtectMetadataDefaultSecretsName is the default name of the Kubernetes Secret
	// that contains the credentials to access the Key Protect KMS. The name of
	// the Secret can be configured by setting the `IBM_KP_SECRET_NAME`
	// option.
	//
	// #nosec:G101, value not credential, just references token.
	keyProtectMetadataDefaultSecretsName = "ceph-csi-kp-credentials"

	// keyProtectSecretNameKey contains the name of the Kubernetes Secret that has
	// the credentials to access the Key ProtectKMS.
	//
	// #nosec:G101, no hardcoded secret, this is a configuration key.
	keyProtectSecretNameKey = "IBM_KP_SECRET_NAME"
	keyProtectRegionKey     = "IBM_KP_REGION"

	keyProtectServiceInstanceID = "IBM_KP_SERVICE_INSTANCE_ID"
	keyProtectServiceBaseURL    = "IBM_KP_BASE_URL"
	keyProtectServiceTokenURL   = "IBM_KP_TOKEN_URL" //nolint:gosec // only configuration key
	// The following options are part of the Kubernetes Secrets.
	// #nosec:G101, no hardcoded secrets, only configuration keys.
	keyProtectServiceAPIKey   = "IBM_KP_SERVICE_API_KEY"
	KeyProtectCustomerRootKey = "IBM_KP_CUSTOMER_ROOT_KEY"
	keyProtectSessionToken    = "IBM_KP_SESSION_TOKEN" //nolint:gosec // only configuration key
	keyProtectCRK             = "IBM_KP_CRK_ARN"
)

var _ = RegisterProvider(Provider{
	UniqueID:    kmsTypeKeyProtectMetadata,
	Initializer: initKeyProtectKMS,
})

// KeyProtectKMS store the KMS connection information retrieved from the kms configmap.
type keyProtectKMS struct {
	// basic options to get the secret
	namespace  string
	secretName string

	// standard KeyProtect configuration options
	client            *kp.Client
	serviceAPIKey     string
	customerRootKey   string
	serviceInstanceID string
	baseURL           string
	tokenURL          string
	region            string
	sessionToken      string
	crk               string
}

func initKeyProtectKMS(args ProviderInitArgs) (EncryptionKMS, error) {
	kms := &keyProtectKMS{
		namespace: args.Namespace,
	}
	// required options for further configuration (getting secrets)
	err := setConfigString(&kms.secretName, args.Config, keyProtectSecretNameKey)
	if errors.Is(err, errConfigOptionInvalid) {
		return nil, err
	} else if errors.Is(err, errConfigOptionMissing) {
		kms.secretName = keyProtectMetadataDefaultSecretsName
	}

	err = setConfigString(&kms.serviceInstanceID, args.Config, keyProtectServiceInstanceID)
	if err != nil {
		return nil, err
	}

	err = setConfigString(&kms.baseURL, args.Config, keyProtectServiceBaseURL)
	if errors.Is(err, errConfigOptionInvalid) {
		return nil, err
	} else if errors.Is(err, errConfigOptionMissing) {
		kms.baseURL = kp.DefaultBaseURL
	}

	err = setConfigString(&kms.tokenURL, args.Config, keyProtectServiceTokenURL)
	if errors.Is(err, errConfigOptionInvalid) {
		return nil, err
	} else if errors.Is(err, errConfigOptionMissing) {
		kms.tokenURL = kp.DefaultTokenURL
	}

	// read the Kubernetes Secret with credentials
	secrets, err := kms.getSecrets()
	if err != nil {
		return nil, fmt.Errorf("failed to get secrets for %T: %w", kms,
			err)
	}

	err = setConfigString(&kms.serviceAPIKey, secrets, keyProtectServiceAPIKey)
	if err != nil {
		return nil, err
	}
	err = setConfigString(&kms.customerRootKey, secrets, KeyProtectCustomerRootKey)
	if err != nil {
		return nil, err
	}

	// keyProtectSessionToken is optional
	err = setConfigString(&kms.sessionToken, secrets, keyProtectSessionToken)
	if errors.Is(err, errConfigOptionInvalid) {
		return nil, err
	}

	// KeyProtect Region is optional
	err = setConfigString(&kms.region, args.Config, keyProtectRegionKey)
	if errors.Is(err, errConfigOptionInvalid) {
		return nil, err
	}

	// crk arn is optional
	err = setConfigString(&kms.crk, secrets, keyProtectCRK)
	if errors.Is(err, errConfigOptionInvalid) {
		return nil, err
	}

	return kms, nil
}

func (kms *keyProtectKMS) getSecrets() (map[string]interface{}, error) {
	c, err := k8s.NewK8sClient()
	if err != nil {
		return nil, fmt.Errorf("failed to connect to Kubernetes to "+
			"get Secret %s/%s: %w", kms.namespace, kms.secretName, err)
	}

	secret, err := c.CoreV1().Secrets(kms.namespace).Get(context.TODO(),
		kms.secretName, metav1.GetOptions{})
	if err != nil {
		return nil, fmt.Errorf("failed to get Secret %s/%s: %w",
			kms.namespace, kms.secretName, err)
	}

	config := make(map[string]interface{})

	for k, v := range secret.Data {
		switch k {
		case keyProtectServiceAPIKey, KeyProtectCustomerRootKey, keyProtectSessionToken, keyProtectCRK:
			config[k] = string(v)
		default:
			return nil, fmt.Errorf("unsupported option for KMS "+
				"provider %q: %s", kmsTypeKeyProtectMetadata, k)
		}
	}

	return config, nil
}

func (kms *keyProtectKMS) Destroy() {
	// Nothing to do.
}

func (kms *keyProtectKMS) RequiresDEKStore() DEKStoreType {
	return DEKStoreMetadata
}

func (kms *keyProtectKMS) getService() error {
	// Use your Service API Key and your KeyProtect Service Instance ID to create a ClientConfig
	cc := kp.ClientConfig{
		BaseURL:    kms.baseURL,
		TokenURL:   kms.tokenURL,
		APIKey:     kms.serviceAPIKey,
		InstanceID: kms.serviceInstanceID,
	}

	// Build a new client from the config
	client, err := kp.New(cc, kp.DefaultTransport())
	if err != nil {
		return fmt.Errorf("failed to create keyprotect client: %w", err)
	}
	kms.client = client

	return nil
}

// EncryptDEK uses the KeyProtect KMS and the configured CRK to encrypt the DEK.
func (kms *keyProtectKMS) EncryptDEK(volumeID, plainDEK string) (string, error) {
	if err := kms.getService(); err != nil {
		return "", fmt.Errorf("could not get KMS service: %w", err)
	}

	dekByteSlice := []byte(plainDEK)
	aadVolID := []string{volumeID}
	result, err := kms.client.Wrap(context.TODO(), kms.customerRootKey, dekByteSlice, &aadVolID)
	if err != nil {
		return "", fmt.Errorf("failed to wrap the DEK: %w", err)
	}

	// base64 encode the encrypted DEK, so that storing it should not have
	// issues

	return base64.StdEncoding.EncodeToString(result), nil
}

// DecryptDEK uses the Key protect KMS and the configured CRK to decrypt the DEK.
func (kms *keyProtectKMS) DecryptDEK(volumeID, encryptedDEK string) (string, error) {
	if err := kms.getService(); err != nil {
		return "", fmt.Errorf("could not get KMS service: %w", err)
	}

	ciphertextBlob, err := base64.StdEncoding.DecodeString(encryptedDEK)
	if err != nil {
		return "", fmt.Errorf("failed to decode base64 cipher: %w",
			err)
	}

	aadVolID := []string{volumeID}
	result, err := kms.client.Unwrap(context.TODO(), kms.customerRootKey, ciphertextBlob, &aadVolID)
	if err != nil {
		return "", fmt.Errorf("failed to unwrap the DEK: %w", err)
	}

	return string(result), nil
}
<|endoftext|>


<commit_before>package cache

import (
	"context"
	"fmt"
	"go/parser"

	"golang.org/x/tools/go/packages"
	"golang.org/x/tools/internal/span"
)

func (v *view) loadParseTypecheck(ctx context.Context, f *goFile) ([]packages.Error, error) {
	v.mcache.mu.Lock()
	defer v.mcache.mu.Unlock()

	// If the AST for this file is trimmed, and we are explicitly type-checking it,
	// don't ignore function bodies.
	if f.astIsTrimmed() {
		f.invalidateAST()
	}

	// Save the metadata's current missing imports, if any.
	var originalMissingImports map[string]struct{}
	if f.meta != nil {
		originalMissingImports = f.meta.missingImports
	}
	// Check if we need to run go/packages.Load for this file's package.
	if errs, err := v.checkMetadata(ctx, f); err != nil {
		return errs, err
	}
	// If `go list` failed to get data for the file in question (this should never happen).
	if f.meta == nil {
		return nil, fmt.Errorf("loadParseTypecheck: no metadata found for %v", f.filename())
	}
	// If we have already seen these missing imports before, and we still have type information,
	// there is no need to continue.
	if sameSet(originalMissingImports, f.meta.missingImports) && f.pkg != nil {
		return nil, nil
	}

	imp := &importer{
		view:          v,
		seen:          make(map[string]struct{}),
		ctx:           ctx,
		fset:          f.FileSet(),
		topLevelPkgID: f.meta.id,
	}

	// Start prefetching direct imports.
	for importPath := range f.meta.children {
		go imp.Import(importPath)
	}
	// Type-check package.
	pkg, err := imp.getPkg(f.meta.pkgPath)
	if pkg == nil || pkg.IsIllTyped() {
		return nil, err
	}
	// If we still have not found the package for the file, something is wrong.
	if f.pkg == nil {
		return nil, fmt.Errorf("loadParseTypeCheck: no package found for %v", f.filename())
	}
	return nil, nil
}

func sameSet(x, y map[string]struct{}) bool {
	if len(x) != len(y) {
		return false
	}
	for k := range x {
		if _, ok := y[k]; !ok {
			return false
		}
	}
	return true
}

// checkMetadata determines if we should run go/packages.Load for this file.
// If yes, update the metadata for the file and its package.
func (v *view) checkMetadata(ctx context.Context, f *goFile) ([]packages.Error, error) {
	if !v.parseImports(ctx, f) {
		return nil, nil
	}
	pkgs, err := packages.Load(v.buildConfig(), fmt.Sprintf("file=%s", f.filename()))
	if len(pkgs) == 0 {
		if err == nil {
			err = fmt.Errorf("no packages found for %s", f.filename())
		}
		// Return this error as a diagnostic to the user.
		return []packages.Error{
			{
				Msg:  err.Error(),
				Kind: packages.ListError,
			},
		}, err
	}
	for _, pkg := range pkgs {
		// If the package comes back with errors from `go list`,
		// don't bother type-checking it.
		if len(pkg.Errors) > 0 {
			return pkg.Errors, fmt.Errorf("package %s has errors, skipping type-checking", pkg.PkgPath)
		}
		// Build the import graph for this package.
		v.link(ctx, pkg.PkgPath, pkg, nil)
	}
	return nil, nil
}

// reparseImports reparses a file's package and import declarations to
// determine if they have changed.
func (v *view) parseImports(ctx context.Context, f *goFile) bool {
	if f.meta == nil || len(f.meta.missingImports) > 0 {
		return true
	}
	// Get file content in case we don't already have it.
	data, _, err := f.Handle(ctx).Read(ctx)
	if err != nil {
		return true
	}
	parsed, _ := parser.ParseFile(f.FileSet(), f.filename(), data, parser.ImportsOnly)
	if parsed == nil {
		return true
	}

	// If the package name has changed, re-run `go list`.
	if f.meta.name != parsed.Name.Name {
		return true
	}
	// If the package's imports have changed, re-run `go list`.
	if len(f.imports) != len(parsed.Imports) {
		return true
	}
	for i, importSpec := range f.imports {
		if importSpec.Path.Value != f.imports[i].Path.Value {
			return true
		}
	}
	return false
}

func (v *view) link(ctx context.Context, pkgPath string, pkg *packages.Package, parent *metadata) *metadata {
	m, ok := v.mcache.packages[pkgPath]
	if !ok {
		m = &metadata{
			pkgPath:        pkgPath,
			id:             pkg.ID,
			typesSizes:     pkg.TypesSizes,
			parents:        make(map[string]bool),
			children:       make(map[string]bool),
			missingImports: make(map[string]struct{}),
		}
		v.mcache.packages[pkgPath] = m
	}
	// Reset any field that could have changed across calls to packages.Load.
	m.name = pkg.Name
	m.files = pkg.CompiledGoFiles
	for _, filename := range m.files {
		if f, _ := v.getFile(span.FileURI(filename)); f != nil {
			if gof, ok := f.(*goFile); ok {
				gof.meta = m
			} else {
				v.Session().Logger().Errorf(ctx, "not a Go file: %s", f.URI())
			}
		}
	}
	// Connect the import graph.
	if parent != nil {
		m.parents[parent.pkgPath] = true
		parent.children[pkgPath] = true
	}
	for importPath, importPkg := range pkg.Imports {
		if len(importPkg.Errors) > 0 {
			m.missingImports[pkg.PkgPath] = struct{}{}
		}
		if _, ok := m.children[importPath]; !ok {
			v.link(ctx, importPath, importPkg, m)
		}
	}
	// Clear out any imports that have been removed.
	for importPath := range m.children {
		if _, ok := pkg.Imports[importPath]; !ok {
			delete(m.children, importPath)
			if child, ok := v.mcache.packages[importPath]; ok {
				delete(child.parents, pkgPath)
			}
		}
	}
	return m
}
<commit_msg>internal/lsp: fix check for changed imports<commit_after>package cache

import (
	"context"
	"fmt"
	"go/parser"

	"golang.org/x/tools/go/packages"
	"golang.org/x/tools/internal/span"
)

func (v *view) loadParseTypecheck(ctx context.Context, f *goFile) ([]packages.Error, error) {
	v.mcache.mu.Lock()
	defer v.mcache.mu.Unlock()

	// If the AST for this file is trimmed, and we are explicitly type-checking it,
	// don't ignore function bodies.
	if f.astIsTrimmed() {
		f.invalidateAST()
	}

	// Save the metadata's current missing imports, if any.
	var originalMissingImports map[string]struct{}
	if f.meta != nil {
		originalMissingImports = f.meta.missingImports
	}
	// Check if we need to run go/packages.Load for this file's package.
	if errs, err := v.checkMetadata(ctx, f); err != nil {
		return errs, err
	}
	// If `go list` failed to get data for the file in question (this should never happen).
	if f.meta == nil {
		return nil, fmt.Errorf("loadParseTypecheck: no metadata found for %v", f.filename())
	}
	// If we have already seen these missing imports before, and we still have type information,
	// there is no need to continue.
	if sameSet(originalMissingImports, f.meta.missingImports) && f.pkg != nil {
		return nil, nil
	}

	imp := &importer{
		view:          v,
		seen:          make(map[string]struct{}),
		ctx:           ctx,
		fset:          f.FileSet(),
		topLevelPkgID: f.meta.id,
	}

	// Start prefetching direct imports.
	for importPath := range f.meta.children {
		go imp.Import(importPath)
	}
	// Type-check package.
	pkg, err := imp.getPkg(f.meta.pkgPath)
	if pkg == nil || pkg.IsIllTyped() {
		return nil, err
	}
	// If we still have not found the package for the file, something is wrong.
	if f.pkg == nil {
		return nil, fmt.Errorf("loadParseTypeCheck: no package found for %v", f.filename())
	}
	return nil, nil
}

func sameSet(x, y map[string]struct{}) bool {
	if len(x) != len(y) {
		return false
	}
	for k := range x {
		if _, ok := y[k]; !ok {
			return false
		}
	}
	return true
}

// checkMetadata determines if we should run go/packages.Load for this file.
// If yes, update the metadata for the file and its package.
func (v *view) checkMetadata(ctx context.Context, f *goFile) ([]packages.Error, error) {
	if !v.parseImports(ctx, f) {
		return nil, nil
	}
	pkgs, err := packages.Load(v.buildConfig(), fmt.Sprintf("file=%s", f.filename()))
	if len(pkgs) == 0 {
		if err == nil {
			err = fmt.Errorf("no packages found for %s", f.filename())
		}
		// Return this error as a diagnostic to the user.
		return []packages.Error{
			{
				Msg:  err.Error(),
				Kind: packages.ListError,
			},
		}, err
	}
	for _, pkg := range pkgs {
		// If the package comes back with errors from `go list`,
		// don't bother type-checking it.
		if len(pkg.Errors) > 0 {
			return pkg.Errors, fmt.Errorf("package %s has errors, skipping type-checking", pkg.PkgPath)
		}
		// Build the import graph for this package.
		v.link(ctx, pkg.PkgPath, pkg, nil)
	}
	return nil, nil
}

// reparseImports reparses a file's package and import declarations to
// determine if they have changed.
func (v *view) parseImports(ctx context.Context, f *goFile) bool {
	if f.meta == nil || len(f.meta.missingImports) > 0 {
		return true
	}
	// Get file content in case we don't already have it.
	data, _, err := f.Handle(ctx).Read(ctx)
	if err != nil {
		return true
	}
	parsed, _ := parser.ParseFile(f.FileSet(), f.filename(), data, parser.ImportsOnly)
	if parsed == nil {
		return true
	}

	// If the package name has changed, re-run `go list`.
	if f.meta.name != parsed.Name.Name {
		return true
	}
	// If the package's imports have changed, re-run `go list`.
	if len(f.imports) != len(parsed.Imports) {
		return true
	}
	for i, importSpec := range f.imports {
		if importSpec.Path.Value != parsed.Imports[i].Path.Value {
			return true
		}
	}
	return false
}

func (v *view) link(ctx context.Context, pkgPath string, pkg *packages.Package, parent *metadata) *metadata {
	m, ok := v.mcache.packages[pkgPath]
	if !ok {
		m = &metadata{
			pkgPath:        pkgPath,
			id:             pkg.ID,
			typesSizes:     pkg.TypesSizes,
			parents:        make(map[string]bool),
			children:       make(map[string]bool),
			missingImports: make(map[string]struct{}),
		}
		v.mcache.packages[pkgPath] = m
	}
	// Reset any field that could have changed across calls to packages.Load.
	m.name = pkg.Name
	m.files = pkg.CompiledGoFiles
	for _, filename := range m.files {
		if f, _ := v.getFile(span.FileURI(filename)); f != nil {
			if gof, ok := f.(*goFile); ok {
				gof.meta = m
			} else {
				v.Session().Logger().Errorf(ctx, "not a Go file: %s", f.URI())
			}
		}
	}
	// Connect the import graph.
	if parent != nil {
		m.parents[parent.pkgPath] = true
		parent.children[pkgPath] = true
	}
	for importPath, importPkg := range pkg.Imports {
		if len(importPkg.Errors) > 0 {
			m.missingImports[pkg.PkgPath] = struct{}{}
		}
		if _, ok := m.children[importPath]; !ok {
			v.link(ctx, importPath, importPkg, m)
		}
	}
	// Clear out any imports that have been removed.
	for importPath := range m.children {
		if _, ok := pkg.Imports[importPath]; !ok {
			delete(m.children, importPath)
			if child, ok := v.mcache.packages[importPath]; ok {
				delete(child.parents, pkgPath)
			}
		}
	}
	return m
}
<|endoftext|>


<commit_before>// Copyright 2014 Hajime Hoshi
//
// 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 opengl

import (
	"fmt"

	"github.com/hajimehoshi/ebiten/internal/affine"
	"github.com/hajimehoshi/ebiten/internal/graphics"
	emath "github.com/hajimehoshi/ebiten/internal/math"
	"github.com/hajimehoshi/ebiten/internal/web"
)

// arrayBufferLayoutPart is a part of an array buffer layout.
type arrayBufferLayoutPart struct {
	// TODO: This struct should belong to a program and know it.
	name     string
	dataType DataType
	num      int
}

// arrayBufferLayout is an array buffer layout.
//
// An array buffer in OpenGL is a buffer representing vertices and
// is passed to a vertex shader.
type arrayBufferLayout struct {
	parts []arrayBufferLayoutPart
	total int
}

// totalBytes returns the size in bytes for one element of the array buffer.
func (a *arrayBufferLayout) totalBytes() int {
	if a.total != 0 {
		return a.total
	}
	t := 0
	for _, p := range a.parts {
		t += p.dataType.SizeInBytes() * p.num
	}
	a.total = t
	return a.total
}

// newArrayBuffer creates OpenGL's buffer object for the array buffer.
func (a *arrayBufferLayout) newArrayBuffer() buffer {
	return GetContext().newArrayBuffer(a.totalBytes() * IndicesNum)
}

// enable binds the array buffer the given program to use the array buffer.
func (a *arrayBufferLayout) enable(program program) {
	for _, p := range a.parts {
		GetContext().enableVertexAttribArray(program, p.name)
	}
	total := a.totalBytes()
	offset := 0
	for _, p := range a.parts {
		GetContext().vertexAttribPointer(program, p.name, p.num, p.dataType, total, offset)
		offset += p.dataType.SizeInBytes() * p.num
	}
}

// disable stops using the array buffer.
func (a *arrayBufferLayout) disable(program program) {
	// TODO: Disabling should be done in reversed order?
	for _, p := range a.parts {
		GetContext().disableVertexAttribArray(program, p.name)
	}
}

// theArrayBufferLayout is the array buffer layout for Ebiten.
var theArrayBufferLayout arrayBufferLayout

func initializeArrayBuferLayout() {
	theArrayBufferLayout = arrayBufferLayout{
		// Note that GL_MAX_VERTEX_ATTRIBS is at least 16.
		parts: []arrayBufferLayoutPart{
			{
				name:     "vertex",
				dataType: Float,
				num:      2,
			},
			{
				name:     "tex_coord",
				dataType: Float,
				num:      4,
			},
			{
				name:     "color_scale",
				dataType: Float,
				num:      4,
			},
		},
	}
}

func ArrayBufferLayoutTotalBytes() int {
	return theArrayBufferLayout.totalBytes()
}

// openGLState is a state for
type openGLState struct {
	// arrayBuffer is OpenGL's array buffer (vertices data).
	arrayBuffer buffer

	// elementArrayBuffer is OpenGL's element array buffer (indices data).
	elementArrayBuffer buffer

	// programNearest is OpenGL's program for rendering a texture with nearest filter.
	programNearest program

	// programLinear is OpenGL's program for rendering a texture with linear filter.
	programLinear program

	programScreen program

	lastProgram                program
	lastProjectionMatrix       []float32
	lastColorMatrix            []float32
	lastColorMatrixTranslation []float32
	lastSourceWidth            int
	lastSourceHeight           int
}

var (
	// theOpenGLState is the OpenGL state in the current process.
	theOpenGLState openGLState

	zeroBuffer  buffer
	zeroProgram program
)

const (
	IndicesNum   = (1 << 16) / 3 * 3 // Adjust num for triangles.
	maxTriangles = IndicesNum / 3
	maxQuads     = maxTriangles / 2
)

// Reset resets or initializes the current OpenGL state.
func Reset() error {
	return theOpenGLState.reset()
}

// reset resets or initializes the OpenGL state.
func (s *openGLState) reset() error {
	if err := GetContext().reset(); err != nil {
		return err
	}

	s.lastProgram = zeroProgram
	s.lastProjectionMatrix = nil
	s.lastColorMatrix = nil
	s.lastColorMatrixTranslation = nil
	s.lastSourceWidth = 0
	s.lastSourceHeight = 0

	// When context lost happens, deleting programs or buffers is not necessary.
	// However, it is not assumed that reset is called only when context lost happens.
	// Let's delete them explicitly.
	if s.programNearest != zeroProgram {
		GetContext().deleteProgram(s.programNearest)
	}
	if s.programLinear != zeroProgram {
		GetContext().deleteProgram(s.programLinear)
	}
	if s.programScreen != zeroProgram {
		GetContext().deleteProgram(s.programScreen)
	}

	// On browsers (at least Chrome), buffers are already detached from the context
	// and must not be deleted by DeleteBuffer.
	if !web.IsBrowser() {
		if s.arrayBuffer != zeroBuffer {
			GetContext().deleteBuffer(s.arrayBuffer)
		}
		if s.elementArrayBuffer != zeroBuffer {
			GetContext().deleteBuffer(s.elementArrayBuffer)
		}
	}

	shaderVertexModelviewNative, err := GetContext().newShader(vertexShader, shaderStr(shaderVertexModelview))
	if err != nil {
		panic(fmt.Sprintf("graphics: shader compiling error:\n%s", err))
	}
	defer GetContext().deleteShader(shaderVertexModelviewNative)

	shaderFragmentNearestNative, err := GetContext().newShader(fragmentShader, shaderStr(shaderFragmentNearest))
	if err != nil {
		panic(fmt.Sprintf("graphics: shader compiling error:\n%s", err))
	}
	defer GetContext().deleteShader(shaderFragmentNearestNative)

	shaderFragmentLinearNative, err := GetContext().newShader(fragmentShader, shaderStr(shaderFragmentLinear))
	if err != nil {
		panic(fmt.Sprintf("graphics: shader compiling error:\n%s", err))
	}
	defer GetContext().deleteShader(shaderFragmentLinearNative)

	shaderFragmentScreenNative, err := GetContext().newShader(fragmentShader, shaderStr(shaderFragmentScreen))
	if err != nil {
		panic(fmt.Sprintf("graphics: shader compiling error:\n%s", err))
	}
	defer GetContext().deleteShader(shaderFragmentScreenNative)

	s.programNearest, err = GetContext().newProgram([]shader{
		shaderVertexModelviewNative,
		shaderFragmentNearestNative,
	})
	if err != nil {
		return err
	}

	s.programLinear, err = GetContext().newProgram([]shader{
		shaderVertexModelviewNative,
		shaderFragmentLinearNative,
	})
	if err != nil {
		return err
	}

	s.programScreen, err = GetContext().newProgram([]shader{
		shaderVertexModelviewNative,
		shaderFragmentScreenNative,
	})
	if err != nil {
		return err
	}

	s.arrayBuffer = theArrayBufferLayout.newArrayBuffer()

	// Note that the indices passed to NewElementArrayBuffer is not under GC management
	// in opengl package due to unsafe-way.
	// See NewElementArrayBuffer in context_mobile.go.
	s.elementArrayBuffer = GetContext().newElementArrayBuffer(IndicesNum * 2)

	return nil
}

// areSameFloat32Array returns a boolean indicating if a and b are deeply equal.
func areSameFloat32Array(a, b []float32) bool {
	if len(a) != len(b) {
		return false
	}
	for i := 0; i < len(a); i++ {
		if a[i] != b[i] {
			return false
		}
	}
	return true
}

func BufferSubData(vertices []float32, indices []uint16) {
	c := GetContext()
	c.arrayBufferSubData(vertices)
	c.elementArrayBufferSubData(indices)
}

func UseProgram(proj []float32, src *Image, dstW, dstH, srcW, srcH int, colorM *affine.ColorM, filter graphics.Filter) {
	theOpenGLState.useProgram(proj, src.textureNative, dstW, dstH, srcW, srcH, colorM, filter)
}

// useProgram uses the program (programTexture).
func (s *openGLState) useProgram(proj []float32, texture textureNative, dstW, dstH, srcW, srcH int, colorM *affine.ColorM, filter graphics.Filter) {
	c := GetContext()

	var program program
	switch filter {
	case graphics.FilterNearest:
		program = s.programNearest
	case graphics.FilterLinear:
		program = s.programLinear
	case graphics.FilterScreen:
		program = s.programScreen
	default:
		panic("not reached")
	}

	if s.lastProgram != program {
		c.useProgram(program)
		if s.lastProgram != zeroProgram {
			theArrayBufferLayout.disable(s.lastProgram)
		}
		theArrayBufferLayout.enable(program)

		if s.lastProgram == zeroProgram {
			c.bindBuffer(arrayBuffer, s.arrayBuffer)
			c.bindBuffer(elementArrayBuffer, s.elementArrayBuffer)
			c.uniformInt(program, "texture", 0)
		}

		s.lastProgram = program
		s.lastProjectionMatrix = nil
		s.lastColorMatrix = nil
		s.lastColorMatrixTranslation = nil
		s.lastSourceWidth = 0
		s.lastSourceHeight = 0
	}

	if !areSameFloat32Array(s.lastProjectionMatrix, proj) {
		c.uniformFloats(program, "projection_matrix", proj)
		if s.lastProjectionMatrix == nil {
			s.lastProjectionMatrix = make([]float32, 16)
		}
		// (*framebuffer).projectionMatrix is always same for the same framebuffer.
		// It's OK to hold the reference without copying.
		s.lastProjectionMatrix = proj
	}

	esBody, esTranslate := colorM.UnsafeElements()

	if !areSameFloat32Array(s.lastColorMatrix, esBody) {
		c.uniformFloats(program, "color_matrix_body", esBody)
		if s.lastColorMatrix == nil {
			s.lastColorMatrix = make([]float32, 16)
		}
		// ColorM's elements are immutable. It's OK to hold the reference without copying.
		s.lastColorMatrix = esBody
	}
	if !areSameFloat32Array(s.lastColorMatrixTranslation, esTranslate) {
		c.uniformFloats(program, "color_matrix_translation", esTranslate)
		if s.lastColorMatrixTranslation == nil {
			s.lastColorMatrixTranslation = make([]float32, 4)
		}
		// ColorM's elements are immutable. It's OK to hold the reference without copying.
		s.lastColorMatrixTranslation = esTranslate
	}

	sw := emath.NextPowerOf2Int(srcW)
	sh := emath.NextPowerOf2Int(srcH)

	if s.lastSourceWidth != sw || s.lastSourceHeight != sh {
		c.uniformFloats(program, "source_size", []float32{float32(sw), float32(sh)})
		s.lastSourceWidth = sw
		s.lastSourceHeight = sh
	}

	if program == s.programScreen {
		scale := float32(dstW) / float32(srcW)
		c.uniformFloat(program, "scale", scale)
	}

	// We don't have to call gl.ActiveTexture here: GL_TEXTURE0 is the default active texture
	// See also: https://www.opengl.org/sdk/docs/man2/xhtml/glActiveTexture.xml
	c.bindTexture(texture)
}
<commit_msg>opengl: Remove arrayBufferLayoutPart.dataType<commit_after>// Copyright 2014 Hajime Hoshi
//
// 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 opengl

import (
	"fmt"

	"github.com/hajimehoshi/ebiten/internal/affine"
	"github.com/hajimehoshi/ebiten/internal/graphics"
	emath "github.com/hajimehoshi/ebiten/internal/math"
	"github.com/hajimehoshi/ebiten/internal/web"
)

// arrayBufferLayoutPart is a part of an array buffer layout.
type arrayBufferLayoutPart struct {
	// TODO: This struct should belong to a program and know it.
	name string
	num  int
}

// arrayBufferLayout is an array buffer layout.
//
// An array buffer in OpenGL is a buffer representing vertices and
// is passed to a vertex shader.
type arrayBufferLayout struct {
	parts []arrayBufferLayoutPart
	total int
}

// totalBytes returns the size in bytes for one element of the array buffer.
func (a *arrayBufferLayout) totalBytes() int {
	if a.total != 0 {
		return a.total
	}
	t := 0
	for _, p := range a.parts {
		t += Float.SizeInBytes() * p.num
	}
	a.total = t
	return a.total
}

// newArrayBuffer creates OpenGL's buffer object for the array buffer.
func (a *arrayBufferLayout) newArrayBuffer() buffer {
	return GetContext().newArrayBuffer(a.totalBytes() * IndicesNum)
}

// enable binds the array buffer the given program to use the array buffer.
func (a *arrayBufferLayout) enable(program program) {
	for _, p := range a.parts {
		GetContext().enableVertexAttribArray(program, p.name)
	}
	total := a.totalBytes()
	offset := 0
	for _, p := range a.parts {
		GetContext().vertexAttribPointer(program, p.name, p.num, Float, total, offset)
		offset += Float.SizeInBytes() * p.num
	}
}

// disable stops using the array buffer.
func (a *arrayBufferLayout) disable(program program) {
	// TODO: Disabling should be done in reversed order?
	for _, p := range a.parts {
		GetContext().disableVertexAttribArray(program, p.name)
	}
}

// theArrayBufferLayout is the array buffer layout for Ebiten.
var theArrayBufferLayout arrayBufferLayout

func initializeArrayBuferLayout() {
	theArrayBufferLayout = arrayBufferLayout{
		// Note that GL_MAX_VERTEX_ATTRIBS is at least 16.
		parts: []arrayBufferLayoutPart{
			{
				name: "vertex",
				num:  2,
			},
			{
				name: "tex_coord",
				num:  4,
			},
			{
				name: "color_scale",
				num:  4,
			},
		},
	}
}

func ArrayBufferLayoutTotalBytes() int {
	return theArrayBufferLayout.totalBytes()
}

// openGLState is a state for
type openGLState struct {
	// arrayBuffer is OpenGL's array buffer (vertices data).
	arrayBuffer buffer

	// elementArrayBuffer is OpenGL's element array buffer (indices data).
	elementArrayBuffer buffer

	// programNearest is OpenGL's program for rendering a texture with nearest filter.
	programNearest program

	// programLinear is OpenGL's program for rendering a texture with linear filter.
	programLinear program

	programScreen program

	lastProgram                program
	lastProjectionMatrix       []float32
	lastColorMatrix            []float32
	lastColorMatrixTranslation []float32
	lastSourceWidth            int
	lastSourceHeight           int
}

var (
	// theOpenGLState is the OpenGL state in the current process.
	theOpenGLState openGLState

	zeroBuffer  buffer
	zeroProgram program
)

const (
	IndicesNum   = (1 << 16) / 3 * 3 // Adjust num for triangles.
	maxTriangles = IndicesNum / 3
	maxQuads     = maxTriangles / 2
)

// Reset resets or initializes the current OpenGL state.
func Reset() error {
	return theOpenGLState.reset()
}

// reset resets or initializes the OpenGL state.
func (s *openGLState) reset() error {
	if err := GetContext().reset(); err != nil {
		return err
	}

	s.lastProgram = zeroProgram
	s.lastProjectionMatrix = nil
	s.lastColorMatrix = nil
	s.lastColorMatrixTranslation = nil
	s.lastSourceWidth = 0
	s.lastSourceHeight = 0

	// When context lost happens, deleting programs or buffers is not necessary.
	// However, it is not assumed that reset is called only when context lost happens.
	// Let's delete them explicitly.
	if s.programNearest != zeroProgram {
		GetContext().deleteProgram(s.programNearest)
	}
	if s.programLinear != zeroProgram {
		GetContext().deleteProgram(s.programLinear)
	}
	if s.programScreen != zeroProgram {
		GetContext().deleteProgram(s.programScreen)
	}

	// On browsers (at least Chrome), buffers are already detached from the context
	// and must not be deleted by DeleteBuffer.
	if !web.IsBrowser() {
		if s.arrayBuffer != zeroBuffer {
			GetContext().deleteBuffer(s.arrayBuffer)
		}
		if s.elementArrayBuffer != zeroBuffer {
			GetContext().deleteBuffer(s.elementArrayBuffer)
		}
	}

	shaderVertexModelviewNative, err := GetContext().newShader(vertexShader, shaderStr(shaderVertexModelview))
	if err != nil {
		panic(fmt.Sprintf("graphics: shader compiling error:\n%s", err))
	}
	defer GetContext().deleteShader(shaderVertexModelviewNative)

	shaderFragmentNearestNative, err := GetContext().newShader(fragmentShader, shaderStr(shaderFragmentNearest))
	if err != nil {
		panic(fmt.Sprintf("graphics: shader compiling error:\n%s", err))
	}
	defer GetContext().deleteShader(shaderFragmentNearestNative)

	shaderFragmentLinearNative, err := GetContext().newShader(fragmentShader, shaderStr(shaderFragmentLinear))
	if err != nil {
		panic(fmt.Sprintf("graphics: shader compiling error:\n%s", err))
	}
	defer GetContext().deleteShader(shaderFragmentLinearNative)

	shaderFragmentScreenNative, err := GetContext().newShader(fragmentShader, shaderStr(shaderFragmentScreen))
	if err != nil {
		panic(fmt.Sprintf("graphics: shader compiling error:\n%s", err))
	}
	defer GetContext().deleteShader(shaderFragmentScreenNative)

	s.programNearest, err = GetContext().newProgram([]shader{
		shaderVertexModelviewNative,
		shaderFragmentNearestNative,
	})
	if err != nil {
		return err
	}

	s.programLinear, err = GetContext().newProgram([]shader{
		shaderVertexModelviewNative,
		shaderFragmentLinearNative,
	})
	if err != nil {
		return err
	}

	s.programScreen, err = GetContext().newProgram([]shader{
		shaderVertexModelviewNative,
		shaderFragmentScreenNative,
	})
	if err != nil {
		return err
	}

	s.arrayBuffer = theArrayBufferLayout.newArrayBuffer()

	// Note that the indices passed to NewElementArrayBuffer is not under GC management
	// in opengl package due to unsafe-way.
	// See NewElementArrayBuffer in context_mobile.go.
	s.elementArrayBuffer = GetContext().newElementArrayBuffer(IndicesNum * 2)

	return nil
}

// areSameFloat32Array returns a boolean indicating if a and b are deeply equal.
func areSameFloat32Array(a, b []float32) bool {
	if len(a) != len(b) {
		return false
	}
	for i := 0; i < len(a); i++ {
		if a[i] != b[i] {
			return false
		}
	}
	return true
}

func BufferSubData(vertices []float32, indices []uint16) {
	c := GetContext()
	c.arrayBufferSubData(vertices)
	c.elementArrayBufferSubData(indices)
}

func UseProgram(proj []float32, src *Image, dstW, dstH, srcW, srcH int, colorM *affine.ColorM, filter graphics.Filter) {
	theOpenGLState.useProgram(proj, src.textureNative, dstW, dstH, srcW, srcH, colorM, filter)
}

// useProgram uses the program (programTexture).
func (s *openGLState) useProgram(proj []float32, texture textureNative, dstW, dstH, srcW, srcH int, colorM *affine.ColorM, filter graphics.Filter) {
	c := GetContext()

	var program program
	switch filter {
	case graphics.FilterNearest:
		program = s.programNearest
	case graphics.FilterLinear:
		program = s.programLinear
	case graphics.FilterScreen:
		program = s.programScreen
	default:
		panic("not reached")
	}

	if s.lastProgram != program {
		c.useProgram(program)
		if s.lastProgram != zeroProgram {
			theArrayBufferLayout.disable(s.lastProgram)
		}
		theArrayBufferLayout.enable(program)

		if s.lastProgram == zeroProgram {
			c.bindBuffer(arrayBuffer, s.arrayBuffer)
			c.bindBuffer(elementArrayBuffer, s.elementArrayBuffer)
			c.uniformInt(program, "texture", 0)
		}

		s.lastProgram = program
		s.lastProjectionMatrix = nil
		s.lastColorMatrix = nil
		s.lastColorMatrixTranslation = nil
		s.lastSourceWidth = 0
		s.lastSourceHeight = 0
	}

	if !areSameFloat32Array(s.lastProjectionMatrix, proj) {
		c.uniformFloats(program, "projection_matrix", proj)
		if s.lastProjectionMatrix == nil {
			s.lastProjectionMatrix = make([]float32, 16)
		}
		// (*framebuffer).projectionMatrix is always same for the same framebuffer.
		// It's OK to hold the reference without copying.
		s.lastProjectionMatrix = proj
	}

	esBody, esTranslate := colorM.UnsafeElements()

	if !areSameFloat32Array(s.lastColorMatrix, esBody) {
		c.uniformFloats(program, "color_matrix_body", esBody)
		if s.lastColorMatrix == nil {
			s.lastColorMatrix = make([]float32, 16)
		}
		// ColorM's elements are immutable. It's OK to hold the reference without copying.
		s.lastColorMatrix = esBody
	}
	if !areSameFloat32Array(s.lastColorMatrixTranslation, esTranslate) {
		c.uniformFloats(program, "color_matrix_translation", esTranslate)
		if s.lastColorMatrixTranslation == nil {
			s.lastColorMatrixTranslation = make([]float32, 4)
		}
		// ColorM's elements are immutable. It's OK to hold the reference without copying.
		s.lastColorMatrixTranslation = esTranslate
	}

	sw := emath.NextPowerOf2Int(srcW)
	sh := emath.NextPowerOf2Int(srcH)

	if s.lastSourceWidth != sw || s.lastSourceHeight != sh {
		c.uniformFloats(program, "source_size", []float32{float32(sw), float32(sh)})
		s.lastSourceWidth = sw
		s.lastSourceHeight = sh
	}

	if program == s.programScreen {
		scale := float32(dstW) / float32(srcW)
		c.uniformFloat(program, "scale", scale)
	}

	// We don't have to call gl.ActiveTexture here: GL_TEXTURE0 is the default active texture
	// See also: https://www.opengl.org/sdk/docs/man2/xhtml/glActiveTexture.xml
	c.bindTexture(texture)
}
<|endoftext|>


<commit_before>/*
Copyright 2021 The Ceph-CSI 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 rbd

import (
	"context"

	"github.com/ceph/ceph-csi/internal/util"

	"github.com/container-storage-interface/spec/lib/go/csi"
	v1 "k8s.io/api/core/v1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	k8s "k8s.io/client-go/kubernetes"
)

const (
	fsTypeBlockName = "block"
)

// accessModeStrToInt convert access mode type string to int32.
// Makesure to update this function as and when there are new modes introduced.
func accessModeStrToInt(mode v1.PersistentVolumeAccessMode) csi.VolumeCapability_AccessMode_Mode {
	switch mode {
	case v1.ReadWriteOnce:
		return csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER
	case v1.ReadOnlyMany:
		return csi.VolumeCapability_AccessMode_MULTI_NODE_READER_ONLY
	case v1.ReadWriteMany:
		return csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER
	}
	return csi.VolumeCapability_AccessMode_UNKNOWN
}

// getSecret get the secret details by name.
func getSecret(c *k8s.Clientset, ns, name string) (map[string]string, error) {
	deviceSecret := make(map[string]string)

	secret, err := c.CoreV1().Secrets(ns).Get(context.TODO(), name, metav1.GetOptions{})
	if err != nil {
		util.ErrorLogMsg("get secret failed, err: %v", err)
		return nil, err
	}

	for k, v := range secret.Data {
		deviceSecret[k] = string(v)
	}

	return deviceSecret, nil
}

func callNodeStageVolume(ns *NodeServer, c *k8s.Clientset, pv *v1.PersistentVolume, stagingPath string) error {
	publishContext := make(map[string]string)

	volID := pv.Spec.PersistentVolumeSource.CSI.VolumeHandle
	stagingParentPath := stagingPath + pv.Name + "/globalmount"

	util.DefaultLog("sending nodeStageVolume for volID: %s, stagingPath: %s",
		volID, stagingParentPath)

	deviceSecret, err := getSecret(c,
		pv.Spec.PersistentVolumeSource.CSI.NodeStageSecretRef.Namespace,
		pv.Spec.PersistentVolumeSource.CSI.NodeStageSecretRef.Name)
	if err != nil {
		util.ErrorLogMsg("getSecret failed for volID: %s, err: %v", volID, err)
		return err
	}

	volumeContext := pv.Spec.PersistentVolumeSource.CSI.VolumeAttributes
	volumeContext["volumeHealerContext"] = "true"

	req := &csi.NodeStageVolumeRequest{
		VolumeId:          volID,
		PublishContext:    publishContext,
		StagingTargetPath: stagingParentPath,
		VolumeCapability: &csi.VolumeCapability{
			AccessMode: &csi.VolumeCapability_AccessMode{
				Mode: accessModeStrToInt(pv.Spec.AccessModes[0]),
			},
		},
		Secrets:       deviceSecret,
		VolumeContext: volumeContext,
	}
	if pv.Spec.PersistentVolumeSource.CSI.FSType == fsTypeBlockName {
		req.VolumeCapability.AccessType = &csi.VolumeCapability_Block{
			Block: &csi.VolumeCapability_BlockVolume{},
		}
	} else {
		req.VolumeCapability.AccessType = &csi.VolumeCapability_Mount{
			Mount: &csi.VolumeCapability_MountVolume{
				FsType:     pv.Spec.PersistentVolumeSource.CSI.FSType,
				MountFlags: pv.Spec.MountOptions,
			},
		}
	}

	_, err = ns.NodeStageVolume(context.TODO(), req)
	if err != nil {
		util.ErrorLogMsg("nodeStageVolume request failed, volID: %s, stagingPath: %s, err: %v",
			volID, stagingParentPath, err)
		return err
	}

	return nil
}

// runVolumeHealer heal the volumes attached on a node.
func runVolumeHealer(ns *NodeServer, conf *util.Config) error {
	c := util.NewK8sClient()
	val, err := c.StorageV1().VolumeAttachments().List(context.TODO(), metav1.ListOptions{})
	if err != nil {
		util.ErrorLogMsg("list volumeAttachments failed, err: %v", err)
		return err
	}

	for i := range val.Items {
		// skip if the volumeattachments doesn't belong to current node or driver
		if val.Items[i].Spec.NodeName != conf.NodeID || val.Items[i].Spec.Attacher != conf.DriverName {
			continue
		}
		pvName := *val.Items[i].Spec.Source.PersistentVolumeName
		pv, err := c.CoreV1().PersistentVolumes().Get(context.TODO(), pvName, metav1.GetOptions{})
		if err != nil {
			// skip if volume doesn't exist
			if !apierrors.IsNotFound(err) {
				util.ErrorLogMsg("get persistentVolumes failed for pv: %s, err: %v", pvName, err)
			}
			continue
		}
		// TODO: check with pv delete annotations, for eg: what happens when the pv is marked for delete
		// skip this volumeattachment if its pv is not bound
		if pv.Status.Phase != v1.VolumeBound {
			continue
		}
		// skip if mounter is not rbd-nbd
		if pv.Spec.PersistentVolumeSource.CSI.VolumeAttributes["mounter"] != "rbd-nbd" {
			continue
		}

		// ensure that the volume is still in attached state
		va, err := c.StorageV1().VolumeAttachments().Get(context.TODO(), val.Items[i].Name, metav1.GetOptions{})
		if err != nil {
			// skip if volume attachment doesn't exist
			if !apierrors.IsNotFound(err) {
				util.ErrorLogMsg("get volumeAttachments failed for volumeAttachment: %s, volID: %s, err: %v",
					val.Items[i].Name, pv.Spec.PersistentVolumeSource.CSI.VolumeHandle, err)
			}
			continue
		}
		if !va.Status.Attached {
			continue
		}

		err = callNodeStageVolume(ns, c, pv, conf.StagingPath)
		if err != nil {
			util.ErrorLogMsg("callNodeStageVolume failed for VolID: %s, err: %v",
				pv.Spec.PersistentVolumeSource.CSI.VolumeHandle, err)
		}
	}

	return nil
}
<commit_msg>rbd: improve healer to run multiple NodeStageVolume req concurrently<commit_after>/*
Copyright 2021 The Ceph-CSI 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 rbd

import (
	"context"
	"sync"

	"github.com/ceph/ceph-csi/internal/util"

	"github.com/container-storage-interface/spec/lib/go/csi"
	v1 "k8s.io/api/core/v1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	k8s "k8s.io/client-go/kubernetes"
)

const (
	fsTypeBlockName = "block"
)

// accessModeStrToInt convert access mode type string to int32.
// Makesure to update this function as and when there are new modes introduced.
func accessModeStrToInt(mode v1.PersistentVolumeAccessMode) csi.VolumeCapability_AccessMode_Mode {
	switch mode {
	case v1.ReadWriteOnce:
		return csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER
	case v1.ReadOnlyMany:
		return csi.VolumeCapability_AccessMode_MULTI_NODE_READER_ONLY
	case v1.ReadWriteMany:
		return csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER
	}
	return csi.VolumeCapability_AccessMode_UNKNOWN
}

// getSecret get the secret details by name.
func getSecret(c *k8s.Clientset, ns, name string) (map[string]string, error) {
	deviceSecret := make(map[string]string)

	secret, err := c.CoreV1().Secrets(ns).Get(context.TODO(), name, metav1.GetOptions{})
	if err != nil {
		util.ErrorLogMsg("get secret failed, err: %v", err)
		return nil, err
	}

	for k, v := range secret.Data {
		deviceSecret[k] = string(v)
	}

	return deviceSecret, nil
}

func callNodeStageVolume(ns *NodeServer, c *k8s.Clientset, pv *v1.PersistentVolume, stagingPath string) error {
	publishContext := make(map[string]string)

	volID := pv.Spec.PersistentVolumeSource.CSI.VolumeHandle
	stagingParentPath := stagingPath + pv.Name + "/globalmount"

	util.DefaultLog("sending nodeStageVolume for volID: %s, stagingPath: %s",
		volID, stagingParentPath)

	deviceSecret, err := getSecret(c,
		pv.Spec.PersistentVolumeSource.CSI.NodeStageSecretRef.Namespace,
		pv.Spec.PersistentVolumeSource.CSI.NodeStageSecretRef.Name)
	if err != nil {
		util.ErrorLogMsg("getSecret failed for volID: %s, err: %v", volID, err)
		return err
	}

	volumeContext := pv.Spec.PersistentVolumeSource.CSI.VolumeAttributes
	volumeContext["volumeHealerContext"] = "true"

	req := &csi.NodeStageVolumeRequest{
		VolumeId:          volID,
		PublishContext:    publishContext,
		StagingTargetPath: stagingParentPath,
		VolumeCapability: &csi.VolumeCapability{
			AccessMode: &csi.VolumeCapability_AccessMode{
				Mode: accessModeStrToInt(pv.Spec.AccessModes[0]),
			},
		},
		Secrets:       deviceSecret,
		VolumeContext: volumeContext,
	}
	if pv.Spec.PersistentVolumeSource.CSI.FSType == fsTypeBlockName {
		req.VolumeCapability.AccessType = &csi.VolumeCapability_Block{
			Block: &csi.VolumeCapability_BlockVolume{},
		}
	} else {
		req.VolumeCapability.AccessType = &csi.VolumeCapability_Mount{
			Mount: &csi.VolumeCapability_MountVolume{
				FsType:     pv.Spec.PersistentVolumeSource.CSI.FSType,
				MountFlags: pv.Spec.MountOptions,
			},
		}
	}

	_, err = ns.NodeStageVolume(context.TODO(), req)
	if err != nil {
		util.ErrorLogMsg("nodeStageVolume request failed, volID: %s, stagingPath: %s, err: %v",
			volID, stagingParentPath, err)
		return err
	}

	return nil
}

// runVolumeHealer heal the volumes attached on a node.
func runVolumeHealer(ns *NodeServer, conf *util.Config) error {
	c := util.NewK8sClient()
	val, err := c.StorageV1().VolumeAttachments().List(context.TODO(), metav1.ListOptions{})
	if err != nil {
		util.ErrorLogMsg("list volumeAttachments failed, err: %v", err)
		return err
	}

	var wg sync.WaitGroup
	channel := make(chan error)
	for i := range val.Items {
		// skip if the volumeattachments doesn't belong to current node or driver
		if val.Items[i].Spec.NodeName != conf.NodeID || val.Items[i].Spec.Attacher != conf.DriverName {
			continue
		}
		pvName := *val.Items[i].Spec.Source.PersistentVolumeName
		pv, err := c.CoreV1().PersistentVolumes().Get(context.TODO(), pvName, metav1.GetOptions{})
		if err != nil {
			// skip if volume doesn't exist
			if !apierrors.IsNotFound(err) {
				util.ErrorLogMsg("get persistentVolumes failed for pv: %s, err: %v", pvName, err)
			}
			continue
		}
		// TODO: check with pv delete annotations, for eg: what happens when the pv is marked for delete
		// skip this volumeattachment if its pv is not bound
		if pv.Status.Phase != v1.VolumeBound {
			continue
		}
		// skip if mounter is not rbd-nbd
		if pv.Spec.PersistentVolumeSource.CSI.VolumeAttributes["mounter"] != "rbd-nbd" {
			continue
		}

		// ensure that the volume is still in attached state
		va, err := c.StorageV1().VolumeAttachments().Get(context.TODO(), val.Items[i].Name, metav1.GetOptions{})
		if err != nil {
			// skip if volume attachment doesn't exist
			if !apierrors.IsNotFound(err) {
				util.ErrorLogMsg("get volumeAttachments failed for volumeAttachment: %s, volID: %s, err: %v",
					val.Items[i].Name, pv.Spec.PersistentVolumeSource.CSI.VolumeHandle, err)
			}
			continue
		}
		if !va.Status.Attached {
			continue
		}

		wg.Add(1)
		// run multiple NodeStageVolume calls concurrently
		go func(wg *sync.WaitGroup, ns *NodeServer, c *k8s.Clientset, pv *v1.PersistentVolume, stagingPath string) {
			defer wg.Done()
			channel <- callNodeStageVolume(ns, c, pv, stagingPath)
		}(&wg, ns, c, pv, conf.StagingPath)
	}

	go func() {
		wg.Wait()
		close(channel)
	}()

	for s := range channel {
		if s != nil {
			util.ErrorLogMsg("callNodeStageVolume failed, err: %v", s)
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package version

import (
	"fmt"

	"github.com/github/hub/git"
	"github.com/github/hub/utils"
)

var Version = "2.3.0-pre6"

func FullVersion() string {
	gitVersion, err := git.Version()
	utils.Check(err)
	return fmt.Sprintf("%s\nhub version %s", gitVersion, Version)
}
<commit_msg>hub 2.3.0-pre7<commit_after>package version

import (
	"fmt"

	"github.com/github/hub/git"
	"github.com/github/hub/utils"
)

var Version = "2.3.0-pre7"

func FullVersion() string {
	gitVersion, err := git.Version()
	utils.Check(err)
	return fmt.Sprintf("%s\nhub version %s", gitVersion, Version)
}
<|endoftext|>


<commit_before>// The version package provides a location to set the release versions for all
// packages to consume, without creating import cycles.
//
// This package should not import any other terraform packages.
package version

import (
	"fmt"

	version "github.com/hashicorp/go-version"
)

// The main version number that is being run at the moment.
var Version = "1.3.0"

// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
// such as "dev" (in development), "beta", "rc1", etc.
var Prerelease = "alpha20220803"

// SemVer is an instance of version.Version. This has the secondary
// benefit of verifying during tests and init time that our version is a
// proper semantic version, which should always be the case.
var SemVer *version.Version

func init() {
	SemVer = version.Must(version.NewVersion(Version))
}

// Header is the header name used to send the current terraform version
// in http requests.
const Header = "Terraform-Version"

// String returns the complete version string, including prerelease
func String() string {
	if Prerelease != "" {
		return fmt.Sprintf("%s-%s", Version, Prerelease)
	}
	return Version
}
<commit_msg>Cleanup after v1.3.0-alpha20220803 release<commit_after>// The version package provides a location to set the release versions for all
// packages to consume, without creating import cycles.
//
// This package should not import any other terraform packages.
package version

import (
	"fmt"

	version "github.com/hashicorp/go-version"
)

// The main version number that is being run at the moment.
var Version = "1.3.0"

// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
// such as "dev" (in development), "beta", "rc1", etc.
var Prerelease = "dev"

// SemVer is an instance of version.Version. This has the secondary
// benefit of verifying during tests and init time that our version is a
// proper semantic version, which should always be the case.
var SemVer *version.Version

func init() {
	SemVer = version.Must(version.NewVersion(Version))
}

// Header is the header name used to send the current terraform version
// in http requests.
const Header = "Terraform-Version"

// String returns the complete version string, including prerelease
func String() string {
	if Prerelease != "" {
		return fmt.Sprintf("%s-%s", Version, Prerelease)
	}
	return Version
}
<|endoftext|>


<commit_before>package version

var (
	// Package is filled at linking time
	Package = "github.com/containerd/containerd"

	// Version holds the complete version number. Filled in at linking time.
	Version = "1.0.0-alpha6+unknown"

	// Revision is filled with the VCS (e.g. git) revision being used to build
	// the program at linking time.
	Revision = ""
)
<commit_msg>release: prepare 1.0.0-beta.0<commit_after>package version

var (
	// Package is filled at linking time
	Package = "github.com/containerd/containerd"

	// Version holds the complete version number. Filled in at linking time.
	Version = "1.0.0-beta.0+unknown"

	// Revision is filled with the VCS (e.g. git) revision being used to build
	// the program at linking time.
	Revision = ""
)
<|endoftext|>


<commit_before>package version

import "fmt"

const (
	// VersionMajor is for an API incompatible changes
	VersionMajor = 5
	// VersionMinor is for functionality in a backwards-compatible manner
	VersionMinor = 21
	// VersionPatch is for backwards-compatible bug fixes
	VersionPatch = 1

	// VersionDev indicates development branch. Releases will be empty string.
	VersionDev = "-dev"
)

// Version is the specification version that the package types support.
var Version = fmt.Sprintf("%d.%d.%d%s", VersionMajor, VersionMinor, VersionPatch, VersionDev)
<commit_msg>Bump to v5.21.1<commit_after>package version

import "fmt"

const (
	// VersionMajor is for an API incompatible changes
	VersionMajor = 5
	// VersionMinor is for functionality in a backwards-compatible manner
	VersionMinor = 21
	// VersionPatch is for backwards-compatible bug fixes
	VersionPatch = 1

	// VersionDev indicates development branch. Releases will be empty string.
	VersionDev = ""
)

// Version is the specification version that the package types support.
var Version = fmt.Sprintf("%d.%d.%d%s", VersionMajor, VersionMinor, VersionPatch, VersionDev)
<|endoftext|>


<commit_before>package version

// Version is the version of the build.
const Version = "1.5.3-dev"
<commit_msg>Release v1.6.0<commit_after>package version

// Version is the version of the build.
const Version = "1.6.0"
<|endoftext|>


<commit_before>package version

const Version = "1.3.0"
<commit_msg>chore: bump to 1.3.0 was mistake, move version back to 1.2.0<commit_after>package version

const Version = "1.2.0"
<|endoftext|>


<commit_before>package hotspots

import (
	"appengine"
	"encoding/json"
	"strings"

	"lib/city"
	"lib/position"
	"lib/spreadsheet"
	"lib/translation"
)

type Hotspot struct {
	Category     string                    `json:"category,omitempty"`
	Name         string                    `json:"name,omitempty"`
	Address      string                    `json:"address,omitempty"`
	Position     position.Position         `json:"position"`
	Contact      string                    `json:"contact,omitempty"`
	OpeningHours string                    `json:"openingHours,omitempty"`
	Translations []translation.Translation `json:"translations"`
}

var nonTranslationKeys = map[string]struct{}{
	"Visible":       {},
	"Category":      {},
	"Name":          {},
	"Address":       {},
	"Latitude":      {},
	"Longitude":     {},
	"Contact":       {},
	"Opening Hours": {},
	"Description":   {},
}

// Get the hotspots as JSON
func GetAsJSON(c appengine.Context, selectedCity city.City) (hotspotsJSON []byte) {
	hotspots := Get(c, selectedCity)

	hotspotsJSON, jsonError := json.Marshal(hotspots)
	if jsonError != nil {
		c.Errorf("hotspots.GetAsJSON marshal: %v", jsonError)
		return
	}

	return
}

// Load and parse the hotspots
func Get(c appengine.Context, selectedCity city.City) (hotspots []Hotspot) {
	headerRow := 1
	hotspotsData := spreadsheet.Get(c, selectedCity.SpreadsheetId, selectedCity.SheetId, headerRow)

	for _, hotspotData := range hotspotsData {
		if hotspotData["Visible"] != "y" {
			continue
		}

		var translations []translation.Translation
		translations = append(translations, translation.Translation{"english", hotspotData["Description"]})

		for key, value := range hotspotData {
			_, exists := nonTranslationKeys[key]
			if exists || key == "" {
				continue
			}

			translations = append(translations, translation.Translation{strings.ToLower(key), value})
		}

		hotspots = append(hotspots, Hotspot{
			Category:     mapEmoji(hotspotData["Category"]),
			Name:         hotspotData["Name"],
			Address:      hotspotData["Address"],
			Position:     position.Create(c, hotspotData["Latitude"], hotspotData["Longitude"]),
			Contact:      hotspotData["Contact"],
			OpeningHours: hotspotData["OpeningHours"],
			Translations: translations,
		})
	}

	return
}
<commit_msg>feat(hotspots): require name<commit_after>package hotspots

import (
	"appengine"
	"encoding/json"
	"strings"

	"lib/city"
	"lib/position"
	"lib/spreadsheet"
	"lib/translation"
)

type Hotspot struct {
	Category     string                    `json:"category,omitempty"`
	Name         string                    `json:"name,omitempty"`
	Address      string                    `json:"address,omitempty"`
	Position     position.Position         `json:"position"`
	Contact      string                    `json:"contact,omitempty"`
	OpeningHours string                    `json:"openingHours,omitempty"`
	Translations []translation.Translation `json:"translations"`
}

var nonTranslationKeys = map[string]struct{}{
	"Visible":       {},
	"Category":      {},
	"Name":          {},
	"Address":       {},
	"Latitude":      {},
	"Longitude":     {},
	"Contact":       {},
	"Opening Hours": {},
	"Description":   {},
}

// Get the hotspots as JSON
func GetAsJSON(c appengine.Context, selectedCity city.City) (hotspotsJSON []byte) {
	hotspots := Get(c, selectedCity)

	hotspotsJSON, jsonError := json.Marshal(hotspots)
	if jsonError != nil {
		c.Errorf("hotspots.GetAsJSON marshal: %v", jsonError)
		return
	}

	return
}

// Load and parse the hotspots
func Get(c appengine.Context, selectedCity city.City) (hotspots []Hotspot) {
	headerRow := 1
	hotspotsData := spreadsheet.Get(c, selectedCity.SpreadsheetId, selectedCity.SheetId, headerRow)

	for _, hotspotData := range hotspotsData {
		if hotspotData["Visible"] != "y" || hotspotData["Name"] == "" {
			continue
		}

		var translations []translation.Translation
		translations = append(translations, translation.Translation{"english", hotspotData["Description"]})

		for key, value := range hotspotData {
			_, exists := nonTranslationKeys[key]
			if exists || key == "" {
				continue
			}

			translations = append(translations, translation.Translation{strings.ToLower(key), value})
		}

		hotspots = append(hotspots, Hotspot{
			Category:     mapEmoji(hotspotData["Category"]),
			Name:         hotspotData["Name"],
			Address:      hotspotData["Address"],
			Position:     position.Create(c, hotspotData["Latitude"], hotspotData["Longitude"]),
			Contact:      hotspotData["Contact"],
			OpeningHours: hotspotData["OpeningHours"],
			Translations: translations,
		})
	}

	return
}
<|endoftext|>