<commit_before>// Package stages_latency holds the routines which manage the stages table.
package stages_latency

import (
	"database/sql"
	"fmt"
	"sort"
	"time"

	"github.com/sjmudd/ps-top/context"
	"github.com/sjmudd/ps-top/lib"
	"github.com/sjmudd/ps-top/model/stages_latency"
)

// Wrapper wraps a Stages struct
type Wrapper struct {
	sl *stages_latency.StagesLatency
}

// NewStages creates a wrapper around Stages
func NewStagesLatency(ctx *context.Context, db *sql.DB) *Wrapper {
	return &Wrapper{
		sl: stages_latency.NewStagesLatency(ctx, db),
	}
}

// SetFirstFromLast resets the statistics to last values
func (slw *Wrapper) SetFirstFromLast() {
	slw.sl.SetFirstFromLast()
}

// Collect data from the db, then merge it in.
func (slw *Wrapper) Collect() {
	slw.sl.Collect()
	sort.Sort(byLatency(slw.sl.Results))
}

// Headings returns the headings for a table
func (slw Wrapper) Headings() string {
	return fmt.Sprintf("%10s %6s %8s|%s", "Latency", "%", "Counter", "Stage Name")

}

// RowContent returns the rows we need for displaying
func (slw Wrapper) RowContent() []string {
	rows := make([]string, 0, len(slw.sl.Results))

	for i := range slw.sl.Results {
		rows = append(rows, slw.content(slw.sl.Results[i], slw.sl.Totals))
	}

	return rows
}

// TotalRowContent returns all the totals
func (slw Wrapper) TotalRowContent() string {
	return slw.content(slw.sl.Totals, slw.sl.Totals)
}

// Len return the length of the result set
func (slw Wrapper) Len() int {
	return len(slw.sl.Results)
}

// EmptyRowContent returns an empty string of data (for filling in)
func (slw Wrapper) EmptyRowContent() string {
	var empty stages_latency.Row

	return slw.content(empty, empty)
}

// Description describe the stages
func (slw Wrapper) Description() string {
	var count int
	for row := range slw.sl.Results {
		if slw.sl.Results[row].SumTimerWait > 0 {
			count++
		}
	}

	return fmt.Sprintf("SQL Stage Latency (events_stages_summary_global_by_event_name) %d rows", count)
}

// HaveRelativeStats is true for this object
func (slw Wrapper) HaveRelativeStats() bool {
	return slw.sl.HaveRelativeStats()
}

// FirstCollectTime returns the time the first value was collected
func (slw Wrapper) FirstCollectTime() time.Time {
	return slw.sl.FirstCollectTime()
}

// LastCollectTime returns the time the last value was collected
func (slw Wrapper) LastCollectTime() time.Time {
	return slw.sl.LastCollectTime()
}

// WantRelativeStats indiates if we want relative statistics
func (slw Wrapper) WantRelativeStats() bool {
	return slw.sl.WantRelativeStats()
}

// generate a printable result
func (slw Wrapper) content(row, totals stages_latency.Row) string {
	name := row.Name
	if row.CountStar == 0 && name != "Totals" {
		name = ""
	}

	return fmt.Sprintf("%10s %6s %8s|%s",
		lib.FormatTime(row.SumTimerWait),
		lib.FormatPct(lib.Divide(row.SumTimerWait, totals.SumTimerWait)),
		lib.FormatAmount(row.CountStar),
		name)
}

type byLatency stages_latency.Rows

func (rows byLatency) Len() int      { return len(rows) }
func (rows byLatency) Swap(i, j int) { rows[i], rows[j] = rows[j], rows[i] }

// sort by value (descending) but also by "name" (ascending) if the values are the same
func (rows byLatency) Less(i, j int) bool {
	return (rows[i].SumTimerWait > rows[j].SumTimerWait) ||
		((rows[i].SumTimerWait == rows[j].SumTimerWait) && (rows[i].Name < rows[j].Name))
}
<commit_msg>golintify<commit_after>// Package stages_latency holds the routines which manage the stages table.
package stages_latency

import (
	"database/sql"
	"fmt"
	"sort"
	"time"

	"github.com/sjmudd/ps-top/context"
	"github.com/sjmudd/ps-top/lib"
	"github.com/sjmudd/ps-top/model/stages_latency"
)

// Wrapper wraps a Stages struct
type Wrapper struct {
	sl *stages_latency.StagesLatency
}

// NewStagesLatency creates a wrapper around stages_latency
func NewStagesLatency(ctx *context.Context, db *sql.DB) *Wrapper {
	return &Wrapper{
		sl: stages_latency.NewStagesLatency(ctx, db),
	}
}

// SetFirstFromLast resets the statistics to last values
func (slw *Wrapper) SetFirstFromLast() {
	slw.sl.SetFirstFromLast()
}

// Collect data from the db, then merge it in.
func (slw *Wrapper) Collect() {
	slw.sl.Collect()
	sort.Sort(byLatency(slw.sl.Results))
}

// Headings returns the headings for a table
func (slw Wrapper) Headings() string {
	return fmt.Sprintf("%10s %6s %8s|%s", "Latency", "%", "Counter", "Stage Name")

}

// RowContent returns the rows we need for displaying
func (slw Wrapper) RowContent() []string {
	rows := make([]string, 0, len(slw.sl.Results))

	for i := range slw.sl.Results {
		rows = append(rows, slw.content(slw.sl.Results[i], slw.sl.Totals))
	}

	return rows
}

// TotalRowContent returns all the totals
func (slw Wrapper) TotalRowContent() string {
	return slw.content(slw.sl.Totals, slw.sl.Totals)
}

// Len return the length of the result set
func (slw Wrapper) Len() int {
	return len(slw.sl.Results)
}

// EmptyRowContent returns an empty string of data (for filling in)
func (slw Wrapper) EmptyRowContent() string {
	var empty stages_latency.Row

	return slw.content(empty, empty)
}

// Description describe the stages
func (slw Wrapper) Description() string {
	var count int
	for row := range slw.sl.Results {
		if slw.sl.Results[row].SumTimerWait > 0 {
			count++
		}
	}

	return fmt.Sprintf("SQL Stage Latency (events_stages_summary_global_by_event_name) %d rows", count)
}

// HaveRelativeStats is true for this object
func (slw Wrapper) HaveRelativeStats() bool {
	return slw.sl.HaveRelativeStats()
}

// FirstCollectTime returns the time the first value was collected
func (slw Wrapper) FirstCollectTime() time.Time {
	return slw.sl.FirstCollectTime()
}

// LastCollectTime returns the time the last value was collected
func (slw Wrapper) LastCollectTime() time.Time {
	return slw.sl.LastCollectTime()
}

// WantRelativeStats indiates if we want relative statistics
func (slw Wrapper) WantRelativeStats() bool {
	return slw.sl.WantRelativeStats()
}

// generate a printable result
func (slw Wrapper) content(row, totals stages_latency.Row) string {
	name := row.Name
	if row.CountStar == 0 && name != "Totals" {
		name = ""
	}

	return fmt.Sprintf("%10s %6s %8s|%s",
		lib.FormatTime(row.SumTimerWait),
		lib.FormatPct(lib.Divide(row.SumTimerWait, totals.SumTimerWait)),
		lib.FormatAmount(row.CountStar),
		name)
}

type byLatency stages_latency.Rows

func (rows byLatency) Len() int      { return len(rows) }
func (rows byLatency) Swap(i, j int) { rows[i], rows[j] = rows[j], rows[i] }

// sort by value (descending) but also by "name" (ascending) if the values are the same
func (rows byLatency) Less(i, j int) bool {
	return (rows[i].SumTimerWait > rows[j].SumTimerWait) ||
		((rows[i].SumTimerWait == rows[j].SumTimerWait) && (rows[i].Name < rows[j].Name))
}
<|endoftext|>


<commit_before>package state

import (
	"fmt"
	"sync"

	"github.com/Sirupsen/logrus"
)

type StateScaleDown struct {
	Name string
	App  *App

	CurrentSlot      *Slot
	CurrentSlotIndex int
	TargetSlotIndex  int
	lock             sync.Mutex
}

func NewStateScaleDown(app *App) *StateScaleDown {
	return &StateScaleDown{
		App:  app,
		Name: APP_STATE_SCALE_DOWN,
	}
}

func (scaleDown *StateScaleDown) OnEnter() {
	logrus.Debug("state scaleDown OnEnter")

	scaleDown.App.EmitAppEvent(scaleDown.Name)

	scaleDown.CurrentSlotIndex = len(scaleDown.App.GetSlots()) - 1

	fmt.Println("xxxxxxxxxxxxxxxxxxxxx")
	fmt.Println("xxxxxxxxxxxxxxxxxxxxx")
	fmt.Println("xxxxxxxxxxxxxxxxxxxxx")
	fmt.Println("xxxxxxxxxxxxxxxxxxxxx")
	fmt.Println(scaleDown.App.IsFixed())
	if scaleDown.App.IsFixed() {
		scaleDown.App.CurrentVersion.IP = scaleDown.App.CurrentVersion.IP[:scaleDown.CurrentSlotIndex]
	}
	fmt.Println(scaleDown.App.CurrentVersion.IP)
	scaleDown.TargetSlotIndex = int(scaleDown.App.CurrentVersion.Instances)

	scaleDown.CurrentSlot, _ = scaleDown.App.GetSlot(scaleDown.CurrentSlotIndex)
	if scaleDown.CurrentSlot != nil {
		scaleDown.CurrentSlot.KillTask()
	}
}

func (scaleDown *StateScaleDown) OnExit() {
	logrus.Debug("state scaleDown OnExit")
}

func (scaleDown *StateScaleDown) Step() {
	logrus.Debug("state scaleDown step")

	if scaleDown.SlotSafeToRemoveFromApp(scaleDown.CurrentSlot) && scaleDown.CurrentSlotIndex == scaleDown.TargetSlotIndex {
		scaleDown.App.RemoveSlot(scaleDown.CurrentSlotIndex)
		scaleDown.App.TransitTo(APP_STATE_NORMAL)
	} else if scaleDown.SlotSafeToRemoveFromApp(scaleDown.CurrentSlot) && (scaleDown.CurrentSlotIndex > scaleDown.TargetSlotIndex) {
		scaleDown.lock.Lock()

		scaleDown.App.RemoveSlot(scaleDown.CurrentSlotIndex)
		scaleDown.CurrentSlotIndex -= 1
		fmt.Println("xxxxxxxxxxxxxxxxxxxxx")
		fmt.Println("xxxxxxxxxxxxxxxxxxxxx")
		fmt.Println("xxxxxxxxxxxxxxxxxxxxx")
		fmt.Println("xxxxxxxxxxxxxxxxxxxxx")
		fmt.Println(scaleDown.App.IsFixed())
		if scaleDown.App.IsFixed() {
			scaleDown.App.CurrentVersion.IP = scaleDown.App.CurrentVersion.IP[:scaleDown.CurrentSlotIndex]
		}
		fmt.Println(scaleDown.App.CurrentVersion.IP)
		scaleDown.CurrentSlot, _ = scaleDown.App.GetSlot(scaleDown.CurrentSlotIndex)
		scaleDown.CurrentSlot.KillTask()

		scaleDown.lock.Unlock()
	} else {
		logrus.Info("state scaleDown step, do nothing")
	}
}

func (scaleDown *StateScaleDown) SlotSafeToRemoveFromApp(slot *Slot) bool {
	return slot.StateIs(SLOT_STATE_REAP) || slot.Abnormal()
}

func (scaleDown *StateScaleDown) StateName() string {
	return scaleDown.Name
}

// state machine can transit to any state if current state is scaleDown
func (scaleDown *StateScaleDown) CanTransitTo(targetState string) bool {
	logrus.Debugf("state scaleDown CanTransitTo %s", targetState)

	return true
}
<commit_msg>remove debug statment<commit_after>package state

import (
	"sync"

	"github.com/Sirupsen/logrus"
)

type StateScaleDown struct {
	Name string
	App  *App

	CurrentSlot      *Slot
	CurrentSlotIndex int
	TargetSlotIndex  int
	lock             sync.Mutex
}

func NewStateScaleDown(app *App) *StateScaleDown {
	return &StateScaleDown{
		App:  app,
		Name: APP_STATE_SCALE_DOWN,
	}
}

func (scaleDown *StateScaleDown) OnEnter() {
	logrus.Debug("state scaleDown OnEnter")

	scaleDown.App.EmitAppEvent(scaleDown.Name)

	scaleDown.CurrentSlotIndex = len(scaleDown.App.GetSlots()) - 1

	if scaleDown.App.IsFixed() {
		scaleDown.App.CurrentVersion.IP = scaleDown.App.CurrentVersion.IP[:scaleDown.CurrentSlotIndex]
	}
	scaleDown.TargetSlotIndex = int(scaleDown.App.CurrentVersion.Instances)

	scaleDown.CurrentSlot, _ = scaleDown.App.GetSlot(scaleDown.CurrentSlotIndex)
	if scaleDown.CurrentSlot != nil {
		scaleDown.CurrentSlot.KillTask()
	}
}

func (scaleDown *StateScaleDown) OnExit() {
	logrus.Debug("state scaleDown OnExit")
}

func (scaleDown *StateScaleDown) Step() {
	logrus.Debug("state scaleDown step")

	if scaleDown.SlotSafeToRemoveFromApp(scaleDown.CurrentSlot) && scaleDown.CurrentSlotIndex == scaleDown.TargetSlotIndex {
		scaleDown.App.RemoveSlot(scaleDown.CurrentSlotIndex)
		scaleDown.App.TransitTo(APP_STATE_NORMAL)
	} else if scaleDown.SlotSafeToRemoveFromApp(scaleDown.CurrentSlot) && (scaleDown.CurrentSlotIndex > scaleDown.TargetSlotIndex) {
		scaleDown.lock.Lock()

		scaleDown.App.RemoveSlot(scaleDown.CurrentSlotIndex)
		scaleDown.CurrentSlotIndex -= 1
		if scaleDown.App.IsFixed() {
			scaleDown.App.CurrentVersion.IP = scaleDown.App.CurrentVersion.IP[:scaleDown.CurrentSlotIndex]
		}
		scaleDown.CurrentSlot, _ = scaleDown.App.GetSlot(scaleDown.CurrentSlotIndex)
		scaleDown.CurrentSlot.KillTask()

		scaleDown.lock.Unlock()
	} else {
		logrus.Info("state scaleDown step, do nothing")
	}
}

func (scaleDown *StateScaleDown) SlotSafeToRemoveFromApp(slot *Slot) bool {
	return slot.StateIs(SLOT_STATE_REAP) || slot.Abnormal()
}

func (scaleDown *StateScaleDown) StateName() string {
	return scaleDown.Name
}

// state machine can transit to any state if current state is scaleDown
func (scaleDown *StateScaleDown) CanTransitTo(targetState string) bool {
	logrus.Debugf("state scaleDown CanTransitTo %s", targetState)

	return true
}
<|endoftext|>


<commit_before>package usecases

import (
	"gitlab.informatik.haw-hamburg.de/icc/gl-k8s-integrator/gitlabclient"
	"gitlab.informatik.haw-hamburg.de/icc/gl-k8s-integrator/k8sclient"
	"log"
	"time"
)

/*
What to fetch from k8s api
- Get all namespaces with gitlab-origin field (ns without that field won't be gitlab created)
- Get all rolebindings of these namespaces

What to get from gitlab
- get all groups
- get all projects
- get all users (private namespace)

Algo:
1. Delete all namespaces which are not in the gitlab Set
2. Iterate all gitlab namespaces
   if namespace is present in k8s set:
	2.1 Iterate all rolebindings
	2.2 Compare to rolebindings from k8s set by using the gitlab-origin field as key and
		2.2.1 Delete every rolebinding not present in the gitlab set
		2.2.1 Create every rolebinding not present in the k8s set
   else:
	2.1 Create namespace
		2.1.1 If namespace is present by name, but does not have a gitlab-origin label attached
		AND is not(!) labeled with 'gitlab-ignored' it get's labeled with its origin name.
		Otherwise the naming collision is solved by suffixing the name with a counter
	2.2 Create all rolebindings

 done

*/

// TODO : Cache Webhooks while Sync is running and execute them later!

func PerformGlK8sSync() {
	log.Println("Starting new Synchronization run!")
	gitlabContent, err := gitlabclient.GetFullGitlabContent()
	if check(err) {
		return
	}

	// 1. delete all Namespaces which are not in the gitlab set
	log.Println("Getting Gitlab Contents...")
	gitlabNamespacesInK8s := k8sclient.GetAllGitlabOriginNamesFromNamespacesWithOriginLabel()

	log.Println("Deleting all namespaces which are no longer in the gitlab namespace...")
	for _, originalName := range gitlabNamespacesInK8s {
		delete := true

		for _, user := range gitlabContent.Users {
			if originalName == user.Username {
				delete = false
				break
			}
		}

		if delete == true {
			for _, project := range gitlabContent.Projects {
				if originalName == project.PathWithNameSpace {
					delete = false
					break
				}
			}
		}

		if delete == true {
			for _, group := range gitlabContent.Groups {
				if originalName == group.FullPath {
					delete = false
					break
				}
			}
		}

		if delete {
			k8sclient.DeleteNamespace(originalName)
		}
	}

	log.Println("Syncing Gitlab Users...")
	// 2. iterate all gitlab "namespaces"
	for _, user := range gitlabContent.Users {
		actualNamespace := k8sclient.GetActualNameSpaceNameByGitlabName(user.Username)
		if actualNamespace != "" {
			// namespace is present, check rolebindings
			k8sRoleBindings := k8sclient.GetRoleBindingsByNamespace(actualNamespace)

			expectedGitlabRolebindingName := k8sclient.ConstructRoleBindingName(user.Username, k8sclient.GetGroupRoleName("Master"), actualNamespace)
			// 2.1 Iterate all roleBindings
			for rb := range k8sRoleBindings {
				if rb != expectedGitlabRolebindingName {
					k8sclient.DeleteGroupRoleBindingByName(rb, actualNamespace)
				}
			}
			// make sure the project's role binding is present
			if !k8sRoleBindings[expectedGitlabRolebindingName] {
				k8sclient.CreateGroupRoleBinding(user.Username, user.Username, "Master")
			}

		} else {
			// create Namespace & RoleBinding
			k8sclient.CreateNamespace(user.Username)
			k8sclient.CreateGroupRoleBinding(user.Username, user.Username, "Master")
		}
	}

	log.Println("Syncing Gitlab Groups...")
	// same same for Groups
	for _, group := range gitlabContent.Groups {
		actualNamespace := k8sclient.GetActualNameSpaceNameByGitlabName(group.FullPath)
		if actualNamespace != "" {
			// namespace is present, check rolebindings
			k8sRoleBindings := k8sclient.GetRoleBindingsByNamespace(actualNamespace)

			// get expectedRoleBindings by retrieved Members
			expectedRoleBindings := map[string]bool{}
			for _, member := range group.Members {
				accessLevel := gitlabclient.TranslateIntAccessLevels(member.AccessLevel)
				roleName := k8sclient.GetGroupRoleName(accessLevel)
				rbName := k8sclient.ConstructRoleBindingName(member.Username, roleName, actualNamespace)
				expectedRoleBindings[rbName] = true

				// make sure the project's expected rolebindings are present
				if !k8sRoleBindings[rbName] {
					k8sclient.CreateGroupRoleBinding(member.Username, group.FullPath, accessLevel)
				}
			}

			// 2.1 Iterate all roleBindings and delete those which are not anymore present in gitlab
			for rb := range k8sRoleBindings {
				if !expectedRoleBindings[rb] {
					k8sclient.DeleteGroupRoleBindingByName(rb, actualNamespace)
				}
			}

		} else {
			// create Namespace & RoleBinding
			k8sclient.CreateNamespace(group.FullPath)
			for _, member := range group.Members {
				accessLevel := gitlabclient.TranslateIntAccessLevels(member.AccessLevel)
				k8sclient.CreateGroupRoleBinding(member.Username, group.FullPath, accessLevel)
			}
		}
	}

	log.Println("Syncing Gitlab Projects...")
	// same same for Projects
	for _, project := range gitlabContent.Projects {
		actualNamespace := k8sclient.GetActualNameSpaceNameByGitlabName(project.PathWithNameSpace)
		if actualNamespace != "" {
			// namespace is present, check rolebindings
			k8sRoleBindings := k8sclient.GetRoleBindingsByNamespace(actualNamespace)

			// get expectedRoleBindings by retrieved Members
			expectedRoleBindings := map[string]bool{}
			for _, member := range project.Members {
				accessLevel := gitlabclient.TranslateIntAccessLevels(member.AccessLevel)
				roleName := k8sclient.GetGroupRoleName(accessLevel)
				rbName := k8sclient.ConstructRoleBindingName(member.Username, roleName, actualNamespace)
				expectedRoleBindings[rbName] = true

				// make sure the project's expected rolebindings are present
				if !k8sRoleBindings[rbName] {
					k8sclient.CreateProjectRoleBinding(member.Username, project.PathWithNameSpace, accessLevel)
				}
			}

			// 2.1 Iterate all roleBindings and delete those which are not anymore present in gitlab
			for rb := range k8sRoleBindings {
				if !expectedRoleBindings[rb] {
					k8sclient.DeleteProjectRoleBindingByName(rb, actualNamespace)
				}
			}

		} else {
			// create Namespace & RoleBinding
			k8sclient.CreateNamespace(project.PathWithNameSpace)
			for _, member := range project.Members {
				accessLevel := gitlabclient.TranslateIntAccessLevels(member.AccessLevel)
				k8sclient.CreateProjectRoleBinding(member.Username, project.PathWithNameSpace, accessLevel)
			}
		}
	}

}

func StartRecurringSyncTimer() {
	log.Println("Starting Sync Timer...")
	ticker := time.NewTicker(time.Hour * 3)
	go func() {
		for range ticker.C {
			go PerformGlK8sSync()
		}
	}()
}
<commit_msg>added output for finished synchronization run<commit_after>package usecases

import (
	"gitlab.informatik.haw-hamburg.de/icc/gl-k8s-integrator/gitlabclient"
	"gitlab.informatik.haw-hamburg.de/icc/gl-k8s-integrator/k8sclient"
	"log"
	"time"
)

/*
What to fetch from k8s api
- Get all namespaces with gitlab-origin field (ns without that field won't be gitlab created)
- Get all rolebindings of these namespaces

What to get from gitlab
- get all groups
- get all projects
- get all users (private namespace)

Algo:
1. Delete all namespaces which are not in the gitlab Set
2. Iterate all gitlab namespaces
   if namespace is present in k8s set:
	2.1 Iterate all rolebindings
	2.2 Compare to rolebindings from k8s set by using the gitlab-origin field as key and
		2.2.1 Delete every rolebinding not present in the gitlab set
		2.2.1 Create every rolebinding not present in the k8s set
   else:
	2.1 Create namespace
		2.1.1 If namespace is present by name, but does not have a gitlab-origin label attached
		AND is not(!) labeled with 'gitlab-ignored' it get's labeled with its origin name.
		Otherwise the naming collision is solved by suffixing the name with a counter
	2.2 Create all rolebindings

 done

*/

// TODO : Cache Webhooks while Sync is running and execute them later!

func PerformGlK8sSync() {
	log.Println("Starting new Synchronization run!")
	gitlabContent, err := gitlabclient.GetFullGitlabContent()
	if check(err) {
		return
	}

	// 1. delete all Namespaces which are not in the gitlab set
	log.Println("Getting Gitlab Contents...")
	gitlabNamespacesInK8s := k8sclient.GetAllGitlabOriginNamesFromNamespacesWithOriginLabel()

	log.Println("Deleting all namespaces which are no longer in the gitlab namespace...")
	for _, originalName := range gitlabNamespacesInK8s {
		delete := true

		for _, user := range gitlabContent.Users {
			if originalName == user.Username {
				delete = false
				break
			}
		}

		if delete == true {
			for _, project := range gitlabContent.Projects {
				if originalName == project.PathWithNameSpace {
					delete = false
					break
				}
			}
		}

		if delete == true {
			for _, group := range gitlabContent.Groups {
				if originalName == group.FullPath {
					delete = false
					break
				}
			}
		}

		if delete {
			k8sclient.DeleteNamespace(originalName)
		}
	}

	log.Println("Syncing Gitlab Users...")
	// 2. iterate all gitlab "namespaces"
	for _, user := range gitlabContent.Users {
		actualNamespace := k8sclient.GetActualNameSpaceNameByGitlabName(user.Username)
		if actualNamespace != "" {
			// namespace is present, check rolebindings
			k8sRoleBindings := k8sclient.GetRoleBindingsByNamespace(actualNamespace)

			expectedGitlabRolebindingName := k8sclient.ConstructRoleBindingName(user.Username, k8sclient.GetGroupRoleName("Master"), actualNamespace)
			// 2.1 Iterate all roleBindings
			for rb := range k8sRoleBindings {
				if rb != expectedGitlabRolebindingName {
					k8sclient.DeleteGroupRoleBindingByName(rb, actualNamespace)
				}
			}
			// make sure the project's role binding is present
			if !k8sRoleBindings[expectedGitlabRolebindingName] {
				k8sclient.CreateGroupRoleBinding(user.Username, user.Username, "Master")
			}

		} else {
			// create Namespace & RoleBinding
			k8sclient.CreateNamespace(user.Username)
			k8sclient.CreateGroupRoleBinding(user.Username, user.Username, "Master")
		}
	}

	log.Println("Syncing Gitlab Groups...")
	// same same for Groups
	for _, group := range gitlabContent.Groups {
		actualNamespace := k8sclient.GetActualNameSpaceNameByGitlabName(group.FullPath)
		if actualNamespace != "" {
			// namespace is present, check rolebindings
			k8sRoleBindings := k8sclient.GetRoleBindingsByNamespace(actualNamespace)

			// get expectedRoleBindings by retrieved Members
			expectedRoleBindings := map[string]bool{}
			for _, member := range group.Members {
				accessLevel := gitlabclient.TranslateIntAccessLevels(member.AccessLevel)
				roleName := k8sclient.GetGroupRoleName(accessLevel)
				rbName := k8sclient.ConstructRoleBindingName(member.Username, roleName, actualNamespace)
				expectedRoleBindings[rbName] = true

				// make sure the project's expected rolebindings are present
				if !k8sRoleBindings[rbName] {
					k8sclient.CreateGroupRoleBinding(member.Username, group.FullPath, accessLevel)
				}
			}

			// 2.1 Iterate all roleBindings and delete those which are not anymore present in gitlab
			for rb := range k8sRoleBindings {
				if !expectedRoleBindings[rb] {
					k8sclient.DeleteGroupRoleBindingByName(rb, actualNamespace)
				}
			}

		} else {
			// create Namespace & RoleBinding
			k8sclient.CreateNamespace(group.FullPath)
			for _, member := range group.Members {
				accessLevel := gitlabclient.TranslateIntAccessLevels(member.AccessLevel)
				k8sclient.CreateGroupRoleBinding(member.Username, group.FullPath, accessLevel)
			}
		}
	}

	log.Println("Syncing Gitlab Projects...")
	// same same for Projects
	for _, project := range gitlabContent.Projects {
		actualNamespace := k8sclient.GetActualNameSpaceNameByGitlabName(project.PathWithNameSpace)
		if actualNamespace != "" {
			// namespace is present, check rolebindings
			k8sRoleBindings := k8sclient.GetRoleBindingsByNamespace(actualNamespace)

			// get expectedRoleBindings by retrieved Members
			expectedRoleBindings := map[string]bool{}
			for _, member := range project.Members {
				accessLevel := gitlabclient.TranslateIntAccessLevels(member.AccessLevel)
				roleName := k8sclient.GetGroupRoleName(accessLevel)
				rbName := k8sclient.ConstructRoleBindingName(member.Username, roleName, actualNamespace)
				expectedRoleBindings[rbName] = true

				// make sure the project's expected rolebindings are present
				if !k8sRoleBindings[rbName] {
					k8sclient.CreateProjectRoleBinding(member.Username, project.PathWithNameSpace, accessLevel)
				}
			}

			// 2.1 Iterate all roleBindings and delete those which are not anymore present in gitlab
			for rb := range k8sRoleBindings {
				if !expectedRoleBindings[rb] {
					k8sclient.DeleteProjectRoleBindingByName(rb, actualNamespace)
				}
			}

		} else {
			// create Namespace & RoleBinding
			k8sclient.CreateNamespace(project.PathWithNameSpace)
			for _, member := range project.Members {
				accessLevel := gitlabclient.TranslateIntAccessLevels(member.AccessLevel)
				k8sclient.CreateProjectRoleBinding(member.Username, project.PathWithNameSpace, accessLevel)
			}
		}
	}
	log.Println("Finished Synchronization run.")

}

func StartRecurringSyncTimer() {
	log.Println("Starting Sync Timer...")
	ticker := time.NewTicker(time.Hour * 3)
	go func() {
		for range ticker.C {
			go PerformGlK8sSync()
		}
	}()
}
<|endoftext|>


<commit_before>// Copyright (C) 2019-2022, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package hashing

import (
	"crypto/sha256"
	"fmt"
	"io"

	"golang.org/x/crypto/ripemd160"
)

const (
	HashLen = sha256.Size
	AddrLen = ripemd160.Size
)

// Hash256 A 256 bit long hash value.
type Hash256 = [HashLen]byte

// Hash160 A 160 bit long hash value.
type Hash160 = [ripemd160.Size]byte

// ComputeHash256Array Compute a cryptographically strong 256 bit hash of the
//                     input byte slice.
func ComputeHash256Array(buf []byte) Hash256 {
	return sha256.Sum256(buf)
}

// ComputeHash256 Compute a cryptographically strong 256 bit hash of the input
//                byte slice.
func ComputeHash256(buf []byte) []byte {
	arr := ComputeHash256Array(buf)
	return arr[:]
}

// ComputeHash256Ranges Compute a cryptographically strong 256 bit hash of the input
//                      byte slice in the ranges specified.
// Example: ComputeHash256Ranges({1, 2, 4, 8, 16}, {{1, 2},
//                                                  {3, 5}})
//          is equivalent to ComputeHash256({2, 8, 16}).
func ComputeHash256Ranges(buf []byte, ranges [][2]int) []byte {
	hashBuilder := sha256.New()
	for _, r := range ranges {
		_, err := hashBuilder.Write(buf[r[0]:r[1]])
		if err != nil {
			panic(err)
		}
	}
	return hashBuilder.Sum(nil)
}

// ComputeHash160Array Compute a cryptographically strong 160 bit hash of the
//                     input byte slice.
func ComputeHash160Array(buf []byte) Hash160 {
	h, err := ToHash160(ComputeHash160(buf))
	if err != nil {
		panic(err)
	}
	return h
}

// ComputeHash160 Compute a cryptographically strong 160 bit hash of the input
//                byte slice.
func ComputeHash160(buf []byte) []byte {
	ripe := ripemd160.New()
	_, err := io.Writer(ripe).Write(buf)
	if err != nil {
		panic(err)
	}
	return ripe.Sum(nil)
}

// Checksum Create checksum of [length] bytes from the 256 bit hash of the byte slice.
//          Returns the lower [length] bytes of the hash
//          Errors if length > 32.
func Checksum(bytes []byte, length int) []byte {
	hash := ComputeHash256Array(bytes)
	return hash[len(hash)-length:]
}

func ToHash256(bytes []byte) (Hash256, error) {
	hash := Hash256{}
	if bytesLen := len(bytes); bytesLen != HashLen {
		return hash, fmt.Errorf("expected 32 bytes but got %d", bytesLen)
	}
	copy(hash[:], bytes)
	return hash, nil
}

func ToHash160(bytes []byte) (Hash160, error) {
	hash := Hash160{}
	if bytesLen := len(bytes); bytesLen != ripemd160.Size {
		return hash, fmt.Errorf("expected 20 bytes but got %d", bytesLen)
	}
	copy(hash[:], bytes)
	return hash, nil
}

func PubkeyBytesToAddress(key []byte) []byte {
	return ComputeHash160(ComputeHash256(key))
}
<commit_msg>Cleanup hashing comments (#2251)<commit_after>// Copyright (C) 2019-2022, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package hashing

import (
	"crypto/sha256"
	"fmt"
	"io"

	"golang.org/x/crypto/ripemd160"
)

const (
	HashLen = sha256.Size
	AddrLen = ripemd160.Size
)

// Hash256 A 256 bit long hash value.
type Hash256 = [HashLen]byte

// Hash160 A 160 bit long hash value.
type Hash160 = [ripemd160.Size]byte

// ComputeHash256Array computes a cryptographically strong 256 bit hash of the
// input byte slice.
func ComputeHash256Array(buf []byte) Hash256 {
	return sha256.Sum256(buf)
}

// ComputeHash256 computes a cryptographically strong 256 bit hash of the input
// byte slice.
func ComputeHash256(buf []byte) []byte {
	arr := ComputeHash256Array(buf)
	return arr[:]
}

// ComputeHash256Ranges computes a cryptographically strong 256 bit hash of the input
// byte slice in the ranges specified.
// Example:
// ComputeHash256Ranges({1, 2, 4, 8, 16}, {{1, 2}, {3, 5}}) is equivalent to
// ComputeHash256({2, 8, 16}).
func ComputeHash256Ranges(buf []byte, ranges [][2]int) []byte {
	hashBuilder := sha256.New()
	for _, r := range ranges {
		_, err := hashBuilder.Write(buf[r[0]:r[1]])
		if err != nil {
			panic(err)
		}
	}
	return hashBuilder.Sum(nil)
}

// ComputeHash160Array computes a cryptographically strong 160 bit hash of the
// input byte slice.
func ComputeHash160Array(buf []byte) Hash160 {
	h, err := ToHash160(ComputeHash160(buf))
	if err != nil {
		panic(err)
	}
	return h
}

// ComputeHash160 computes a cryptographically strong 160 bit hash of the input
// byte slice.
func ComputeHash160(buf []byte) []byte {
	ripe := ripemd160.New()
	_, err := io.Writer(ripe).Write(buf)
	if err != nil {
		panic(err)
	}
	return ripe.Sum(nil)
}

// Checksum creates a checksum of [length] bytes from the 256 bit hash of the
// byte slice.
//
// Returns: the lower [length] bytes of the hash
// Panics if length > 32.
func Checksum(bytes []byte, length int) []byte {
	hash := ComputeHash256Array(bytes)
	return hash[len(hash)-length:]
}

func ToHash256(bytes []byte) (Hash256, error) {
	hash := Hash256{}
	if bytesLen := len(bytes); bytesLen != HashLen {
		return hash, fmt.Errorf("expected 32 bytes but got %d", bytesLen)
	}
	copy(hash[:], bytes)
	return hash, nil
}

func ToHash160(bytes []byte) (Hash160, error) {
	hash := Hash160{}
	if bytesLen := len(bytes); bytesLen != ripemd160.Size {
		return hash, fmt.Errorf("expected 20 bytes but got %d", bytesLen)
	}
	copy(hash[:], bytes)
	return hash, nil
}

func PubkeyBytesToAddress(key []byte) []byte {
	return ComputeHash160(ComputeHash256(key))
}
<|endoftext|>


<commit_before>// Copyright 2016 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package resource

// TODO(ericsnow) Move ModelResource to an internal package?

// ModelResource represents the full information about a resource
// in a Juju model.
type ModelResource struct {
	// ID uniquely identifies a resource-service pair within the model.
	// Note that the model ignores pending resources (those with a
	// pending ID) except for in a few clearly pending-related places.
	ID string

	// PendingID identifies that this resource is pending and
	// distinguishes it from other pending resources with the same model
	// ID (and from the active resource).
	PendingID string

	// ServiceID identifies the service for the resource.
	ServiceID string

	// Resource is the general info for the resource.
	Resource Resource

	// TODO(ericsnow) Use StoragePath for the directory path too?

	// StoragePath is the path to where the resource content is stored.
	StoragePath string
}
<commit_msg>Drop ModelResource.<commit_after><|endoftext|>


<commit_before>// Copyright 2017 Authors of Cilium
//
// 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 config

import (
	"flag"
	"time"
)

// CiliumTestConfigType holds all of the configurable elements of the testsuite
type CiliumTestConfigType struct {
	Reprovision bool
	// HoldEnvironment leaves the test infrastructure in place on failure
	HoldEnvironment bool
	// PassCLIEnvironment passes through the environment invoking the gingko
	// tests. When false all subcommands are executed with an empty environment,
	// including PATH.
	PassCLIEnvironment  bool
	SSHConfig           string
	ShowCommands        bool
	TestScope           string
	SkipLogGathering    bool
	CiliumImage         string
	CiliumOperatorImage string
	ProvisionK8s        bool
	Timeout             time.Duration
	Kubeconfig          string
	Registry            string
}

// CiliumTestConfig holds the global configuration of commandline flags
// in the ginkgo-based testing environment.
var CiliumTestConfig = CiliumTestConfigType{}

// ParseFlags parses commandline flags relevant to testing.
func (c *CiliumTestConfigType) ParseFlags() {
	flag.BoolVar(&c.Reprovision, "cilium.provision", true,
		"Provision Vagrant boxes and Cilium before running test")
	flag.BoolVar(&c.HoldEnvironment, "cilium.holdEnvironment", false,
		"On failure, hold the environment in its current state")
	flag.BoolVar(&c.PassCLIEnvironment, "cilium.passCLIEnvironment", false,
		"Pass the environment invoking ginkgo, including PATH, to subcommands")
	flag.BoolVar(&c.SkipLogGathering, "cilium.skipLogs", false,
		"skip gathering logs if a test fails")
	flag.StringVar(&c.SSHConfig, "cilium.SSHConfig", "",
		"Specify a custom command to fetch SSH configuration (eg: 'vagrant ssh-config')")
	flag.BoolVar(&c.ShowCommands, "cilium.showCommands", false,
		"Output which commands are ran to stdout")
	flag.StringVar(&c.TestScope, "cilium.testScope", "",
		"Specifies scope of test to be ran (k8s, Nightly, runtime)")
	flag.StringVar(&c.CiliumImage, "cilium.image", "",
		"Specifies which image of cilium to use during tests")
	flag.StringVar(&c.CiliumOperatorImage, "cilium.operator-image", "",
		"Specifies which image of cilium-operator to use during tests")
	flag.BoolVar(&c.ProvisionK8s, "cilium.provision-k8s", true,
		"Specifies whether Kubernetes should be deployed and installed via kubeadm or not")
	flag.DurationVar(&c.Timeout, "cilium.timeout", 24*time.Hour,
		"Specifies timeout for test run")
	flag.StringVar(&c.Kubeconfig, "cilium.kubeconfig", "",
		"Kubeconfig to be used for k8s tests")
	flag.StringVar(&c.Kubeconfig, "cilium.registry", "k8s1:5000", "docker registry hostname for Cilium image")
}
<commit_msg>CI: Fix typo setting kubeconfig variable from registry<commit_after>// Copyright 2017 Authors of Cilium
//
// 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 config

import (
	"flag"
	"time"
)

// CiliumTestConfigType holds all of the configurable elements of the testsuite
type CiliumTestConfigType struct {
	Reprovision bool
	// HoldEnvironment leaves the test infrastructure in place on failure
	HoldEnvironment bool
	// PassCLIEnvironment passes through the environment invoking the gingko
	// tests. When false all subcommands are executed with an empty environment,
	// including PATH.
	PassCLIEnvironment  bool
	SSHConfig           string
	ShowCommands        bool
	TestScope           string
	SkipLogGathering    bool
	CiliumImage         string
	CiliumOperatorImage string
	ProvisionK8s        bool
	Timeout             time.Duration
	Kubeconfig          string
	Registry            string
}

// CiliumTestConfig holds the global configuration of commandline flags
// in the ginkgo-based testing environment.
var CiliumTestConfig = CiliumTestConfigType{}

// ParseFlags parses commandline flags relevant to testing.
func (c *CiliumTestConfigType) ParseFlags() {
	flag.BoolVar(&c.Reprovision, "cilium.provision", true,
		"Provision Vagrant boxes and Cilium before running test")
	flag.BoolVar(&c.HoldEnvironment, "cilium.holdEnvironment", false,
		"On failure, hold the environment in its current state")
	flag.BoolVar(&c.PassCLIEnvironment, "cilium.passCLIEnvironment", false,
		"Pass the environment invoking ginkgo, including PATH, to subcommands")
	flag.BoolVar(&c.SkipLogGathering, "cilium.skipLogs", false,
		"skip gathering logs if a test fails")
	flag.StringVar(&c.SSHConfig, "cilium.SSHConfig", "",
		"Specify a custom command to fetch SSH configuration (eg: 'vagrant ssh-config')")
	flag.BoolVar(&c.ShowCommands, "cilium.showCommands", false,
		"Output which commands are ran to stdout")
	flag.StringVar(&c.TestScope, "cilium.testScope", "",
		"Specifies scope of test to be ran (k8s, Nightly, runtime)")
	flag.StringVar(&c.CiliumImage, "cilium.image", "",
		"Specifies which image of cilium to use during tests")
	flag.StringVar(&c.CiliumOperatorImage, "cilium.operator-image", "",
		"Specifies which image of cilium-operator to use during tests")
	flag.BoolVar(&c.ProvisionK8s, "cilium.provision-k8s", true,
		"Specifies whether Kubernetes should be deployed and installed via kubeadm or not")
	flag.DurationVar(&c.Timeout, "cilium.timeout", 24*time.Hour,
		"Specifies timeout for test run")
	flag.StringVar(&c.Kubeconfig, "cilium.kubeconfig", "",
		"Kubeconfig to be used for k8s tests")
	flag.StringVar(&c.Registry, "cilium.registry", "k8s1:5000", "docker registry hostname for Cilium image")
}
<|endoftext|>


<commit_before>// cmplximg provides simple ways of displaying functions of one complex number
// as an image.
package cmplximage

import (
	"image"
	"image/color"
	"math"
	"math/cmplx"
)

// ComplexRect is a rectangle in the complex plane.
type ComplexRect struct {
	a complex128
	b complex128
}

func NewCmplxRect(Min, Max complex128) *ComplexRect {
	rect := new(ComplexRect)
	rect.a = Min
	rect.b = Max
	return rect
}

func (cr ComplexRect) dx() float64 {
	return math.Abs(real(cr.a) - real(cr.b))
}

func (cr ComplexRect) dy() float64 {
	return math.Abs(imag(cr.a) - real(cr.b))
}

// Other ComplexRect methods are not needed and are superfluous.
func (cr ComplexRect) bottom() float64 {
	if imag(cr.a) < imag(cr.b) {
		return imag(cr.a)
	} else {
		return imag(cr.b)
	}
}

func (cr ComplexRect) left() float64 {
	if real(cr.a) < real(cr.b) {
		return real(cr.a)
	} else {
		return real(cr.b)
	}
}

// ComplexMap is a function in the complex plane.
type ComplexMap func(point complex128) (complex128)

// ColorMap maps a point on the complex plane to a color.
type ColorMap func(point complex128) (color.Color)

// Draw creates an image of the function in the domain.
func Draw(fnc ColorMap, size image.Rectangle, domain ComplexRectangle) image.Image {
	size = size.Canon()
	// Clever vector hack to move the Min corner to 0,0
	size = size.Sub(size.Min)
	// For now, use RGBA as image type
	img := image.NewRGBA(size)
	// max x and y guaranteed to be size of rectangle
	x := size.Dx()
	y := size.Dy()
	dx := domain.dx() / x
	dy := domain.dy() / y
	// Get the initial x vals
	base_x := domain.left()
	base_y := domain.bottom()
	for i := 0; i <= x; i++ {
		for j := 0; j <= y; j++ {
			point := complex128(base_x + i*dx, base_y + j*dy)
			img.Set(i, j, fnc(point))
		}
	}
	return img
}

// RiemannMap generates a ColorMap from a ComplexMap, using the Riemann sphere.
// Red, green, and blue are respectively set to the x, y, and z coordinates.
func RiemannMap(fnc ComplexMap) ColorMap {
	return func(point complex128) color.Color {
		val := fnc(point)
		// Convert val to points on Riemann sphere, then set colors.
		// All will be in range [-1,1]
		add := math.Pow(cmplx.Abs(val), 2)
		div := 1.0 + add
		x := (2*real(val)) / div
		y := (2*imag(val)) / div
		z := (add - 1.0) / div
		// Now with the calculations out of the way, convert to standard color.
		// Uniformly map from [-1,1] to [0,255]
		r := math.Round(255 * ((x + 1) / 2))
		g := math.Round(255 * ((y + 1) / 2))
		b := math.Round(255 * ((z + 1) / 2))

		return color.RGBA(r, g, b, 255)
	}
}

<commit_msg>Fix implementation of RiemannMap and Draw.<commit_after>// cmplximg provides simple ways of displaying functions of one complex number
// as an image.
package cmplximage

import (
	"image"
	"image/color"
	"math"
	"math/cmplx"
)

// ComplexRect is a rectangle in the complex plane.
type ComplexRect struct {
	a complex128
	b complex128
}

func NewCmplxRect(Min, Max complex128) *ComplexRect {
	rect := new(ComplexRect)
	rect.a = Min
	rect.b = Max
	return rect
}

func (cr ComplexRect) dx() float64 {
	return math.Abs(real(cr.a) - real(cr.b))
}

func (cr ComplexRect) dy() float64 {
	return math.Abs(imag(cr.a) - real(cr.b))
}

// Other ComplexRect methods are not needed and are superfluous.
func (cr ComplexRect) bottom() float64 {
	if imag(cr.a) < imag(cr.b) {
		return imag(cr.a)
	} else {
		return imag(cr.b)
	}
}

func (cr ComplexRect) left() float64 {
	if real(cr.a) < real(cr.b) {
		return real(cr.a)
	} else {
		return real(cr.b)
	}
}

// ComplexMap is a function in the complex plane.
type ComplexMap func(point complex128) complex128

// ColorMap maps a point on the complex plane to a color.
type ColorMap func(point complex128) color.Color

// Draw creates an image of the function in the domain.
func Draw(fnc ColorMap, size image.Rectangle, domain *ComplexRect) image.Image {
	size = size.Canon()
	// Clever vector hack to move the Min corner to 0,0
	size = size.Sub(size.Min)
	// For now, use RGBA as image type
	img := image.NewRGBA(size)
	// max x and y guaranteed to be size of rectangle
	x := size.Dx()
	y := size.Dy()
	dx := domain.dx() / float64(x)
	dy := domain.dy() / float64(y)
	// Get the initial x vals
	base_x := domain.left()
	base_y := domain.bottom()
	for i := 0; i <= x; i++ {
		for j := 0; j <= y; j++ {
			point := complex(base_x+float64(i)*dx, base_y+float64(j)*dy)
			img.Set(i, j, fnc(point))
		}
	}
	return img
}

// Needed because Go doesn't have a floating point round function.
// Either way, guaranteed to fit in a uint8 and be positive.
func round(num float64) uint8 {
	return uint8(math.Floor(num + 0.5))
}

// RiemannMap generates a ColorMap from a ComplexMap, using the Riemann sphere.
// Red, green, and blue are respectively set to the x, y, and z coordinates.
func RiemannMap(fnc ComplexMap) ColorMap {
	return func(point complex128) color.Color {
		val := fnc(point)
		// Convert val to points on Riemann sphere, then set colors.
		// All will be in range [-1,1]
		add := math.Pow(cmplx.Abs(val), 2)
		div := 1.0 + add
		x := (2 * real(val)) / div
		y := (2 * imag(val)) / div
		z := (add - 1.0) / div
		// Now with the calculations out of the way, convert to standard color.
		// Uniformly map from [-1,1] to [0,255]
		r := round(255 * ((x + 1) / 2))
		g := round(255 * ((y + 1) / 2))
		b := round(255 * ((z + 1) / 2))

		return color.RGBA{r, g, b, 255}
	}
}
<|endoftext|>


<commit_before>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package timestampvm

import (
	"errors"
	"time"

	"github.com/ava-labs/gecko/vms/components/core"
)

var (
	errTimestampTooEarly = errors.New("block's timestamp is later than its parent's timestamp")
	errDatabase          = errors.New("error while retrieving data from database")
	errTimestampTooLate  = errors.New("block's timestamp is more than 1 hour ahead of local time")
)

// Block is a block on the chain.
// Each block contains:
// 1) A piece of data (a string)
// 2) A timestamp
type Block struct {
	*core.Block `serialize:"true"`
	Data        [dataLen]byte `serialize:"true"`
	Timestamp   int64         `serialize:"true"`
}

// Verify returns nil iff this block is valid.
// To be valid, it must be that:
// b.parent.Timestamp < b.Timestamp <= [local time] + 1 hour
func (b *Block) Verify() error {
	if accepted, err := b.Block.Verify(); err != nil || accepted {
		return err
	}

	// Get [b]'s parent
	parent, ok := b.Parent().(*Block)
	if !ok {
		return errDatabase
	}

	if b.Timestamp < time.Unix(parent.Timestamp, 0).Unix() {
		return errTimestampTooEarly
	}

	if b.Timestamp >= time.Now().Add(time.Hour).Unix() {
		return errTimestampTooLate
	}

	// Persist the block
	b.VM.SaveBlock(b.VM.DB, b)
	return b.VM.DB.Commit()
}
<commit_msg>Correct block timestamp error message<commit_after>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package timestampvm

import (
	"errors"
	"time"

	"github.com/ava-labs/gecko/vms/components/core"
)

var (
	errTimestampTooEarly = errors.New("block's timestamp is earlier than its parent's timestamp")
	errDatabase          = errors.New("error while retrieving data from database")
	errTimestampTooLate  = errors.New("block's timestamp is more than 1 hour ahead of local time")
)

// Block is a block on the chain.
// Each block contains:
// 1) A piece of data (a string)
// 2) A timestamp
type Block struct {
	*core.Block `serialize:"true"`
	Data        [dataLen]byte `serialize:"true"`
	Timestamp   int64         `serialize:"true"`
}

// Verify returns nil iff this block is valid.
// To be valid, it must be that:
// b.parent.Timestamp < b.Timestamp <= [local time] + 1 hour
func (b *Block) Verify() error {
	if accepted, err := b.Block.Verify(); err != nil || accepted {
		return err
	}

	// Get [b]'s parent
	parent, ok := b.Parent().(*Block)
	if !ok {
		return errDatabase
	}

	if b.Timestamp < time.Unix(parent.Timestamp, 0).Unix() {
		return errTimestampTooEarly
	}

	if b.Timestamp >= time.Now().Add(time.Hour).Unix() {
		return errTimestampTooLate
	}

	// Persist the block
	b.VM.SaveBlock(b.VM.DB, b)
	return b.VM.DB.Commit()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"github.com/hashicorp/terraform/helper/schema"
	"github.com/iron-io/iron_go3/config"
	"github.com/iron-io/iron_go3/mq"
)

func queueSchema() *schema.Resource {
	return &schema.Resource{
		Create: createQueue,
		Read:   readQueue,
		//Update: updateQueue,
		Delete: deleteQueue,
		Schema: map[string]*schema.Schema{
			"name": {
				Type:        schema.TypeString,
				Required:    true,
				ForceNew:    true,
				Description: "name of the queue",
			},
		},
	}
}

func createQueue(data *schema.ResourceData, meta interface{}) error {
	cfg := meta.(config.Settings)
	name := data.Get("name").(string)
	_, err := mq.ConfigCreateQueue(mq.QueueInfo{
		Name: name,
	}, &cfg)
	if err != nil {
		return err
	}
	if err := readQueue(data, meta); err != nil {
		return err
	}
	return nil
}

func updateQueue(data *schema.ResourceData, meta interface{}) error {
	return nil
}

func readQueue(data *schema.ResourceData, meta interface{}) error {
	cfg := meta.(config.Settings)
	name := data.Get("name").(string)
	data.SetId(fmt.Sprintf("%s/%s", cfg.ProjectId, name))
	return nil
}

func deleteQueue(data *schema.ResourceData, ironcfg interface{}) error {
	return nil
}
<commit_msg>Support deletion of queues<commit_after>package main

import (
	"fmt"

	"github.com/hashicorp/terraform/helper/schema"
	"github.com/iron-io/iron_go3/config"
	"github.com/iron-io/iron_go3/mq"
)

func queueSchema() *schema.Resource {
	return &schema.Resource{
		Create: createQueue,
		Read:   readQueue,
		//Update: updateQueue,
		Delete: deleteQueue,
		Schema: map[string]*schema.Schema{
			"name": {
				Type:        schema.TypeString,
				Required:    true,
				ForceNew:    true,
				Description: "name of the queue",
			},
		},
	}
}

func createQueue(data *schema.ResourceData, meta interface{}) error {
	cfg := meta.(config.Settings)
	name := data.Get("name").(string)
	_, err := mq.ConfigCreateQueue(mq.QueueInfo{
		Name: name,
	}, &cfg)
	if err != nil {
		return err
	}
	if err := readQueue(data, meta); err != nil {
		return err
	}
	return nil
}

func updateQueue(data *schema.ResourceData, meta interface{}) error {
	return nil
}

func readQueue(data *schema.ResourceData, meta interface{}) error {
	cfg := meta.(config.Settings)
	name := data.Get("name").(string)
	data.SetId(fmt.Sprintf("%s/%s", cfg.ProjectId, name))
	return nil
}

func deleteQueue(data *schema.ResourceData, meta interface{}) error {
	cfg := meta.(config.Settings)
	name := data.Get("name").(string)
	q := mq.ConfigNew(name, &cfg)
	return q.Delete()
}
<|endoftext|>


<commit_before>// Copyright ©2018 The Gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package dualquat_test

import (
	"fmt"
	"math"

	"gonum.org/v1/gonum/floats"
	"gonum.org/v1/gonum/num/dualquat"
	"gonum.org/v1/gonum/num/quat"
)

// point is a 3-dimensional point/vector.
type point struct {
	x, y, z float64
}

// raise raises the dimensionality of a point to a quaternion.
func raise(p point) quat.Number {
	return quat.Number{Imag: p.x, Jmag: p.y, Kmag: p.z}
}

// raiseDual raises the dimensionality of a point to a dual quaternion.
func raiseDual(p point) dualquat.Number {
	return dualquat.Number{
		Real: quat.Number{Real: 1},
		Dual: raise(p),
	}
}

// transform performs the quaternion rotation of p by the given quaternion
// and scaling by the scale factor. The rotations are normalized to unit
// vectors.
func transform(p point, by ...dualquat.Number) point {
	if len(by) == 0 {
		return p
	}

	// Ensure the modulus of by is correctly scaled.
	for i := range by {
		if len := quat.Abs(by[i].Real); len != 1 {
			by[i].Real = quat.Scale(1/len, by[i].Real)
		}
	}

	// Perform the transformations.
	q := by[0]
	for _, o := range by[1:] {
		q = dualquat.Mul(o, q)
	}
	pp := dualquat.Mul(dualquat.Mul(q, raiseDual(p)), dualquat.Conj(q))

	// Extract the point.
	return point{x: pp.Dual.Imag, y: pp.Dual.Jmag, z: pp.Dual.Kmag}
}

func Example() {
	// Translate a 1×1×1 cube by [3, 4, 5] and rotate it 120° around the
	// diagonal vector [1, 1, 1].
	fmt.Println("cube:")

	// Construct a displacement.
	displace := dualquat.Number{
		Real: quat.Number{Real: 1},
		Dual: quat.Scale(0.5, raise(point{3, 4, 5})),
	}

	// Construct a rotations.
	alpha := 2 * math.Pi / 3
	axis := raise(point{1, 1, 1})
	rotate := dualquat.Number{Real: axis}
	rotate.Real = quat.Scale(math.Sin(alpha/2)/quat.Abs(rotate.Real), rotate.Real)
	rotate.Real.Real += math.Cos(alpha / 2)

	for i, p := range []point{
		{x: 0, y: 0, z: 0},
		{x: 0, y: 0, z: 1},
		{x: 0, y: 1, z: 0},
		{x: 0, y: 1, z: 1},
		{x: 1, y: 0, z: 0},
		{x: 1, y: 0, z: 1},
		{x: 1, y: 1, z: 0},
		{x: 1, y: 1, z: 1},
	} {
		pp := transform(p,
			displace, rotate,
		)

		// Clean up floating point error for clarity.
		pp.x = floats.Round(pp.x, 2)
		pp.y = floats.Round(pp.y, 2)
		pp.z = floats.Round(pp.z, 2)

		fmt.Printf(" %d %+v -> %+v\n", i, p, pp)
	}

	// Rotate a line segment from {[2, 1, 1], [2, 1, 2]} 120° around
	// the diagonal vector [1, 1, 1] at its lower end.
	fmt.Println("\nline segment:")

	// Construct an displacement to the origin from the lower end...
	origin := dualquat.Number{
		Real: quat.Number{Real: 1},
		Dual: quat.Scale(0.5, raise(point{-2, -1, -1})),
	}
	// ... and back from the origin to the lower end.
	replace := dualquat.Number{
		Real: quat.Number{Real: 1},
		Dual: quat.Scale(-1, origin.Dual),
	}

	for i, p := range []point{
		{x: 2, y: 1, z: 1},
		{x: 2, y: 1, z: 2},
	} {
		pp := transform(p,
			origin,  // Displace to origin.
			rotate,  // Rotate around axis.
			replace, // Displace back to original location.
		)

		// Clean up floating point error for clarity.
		pp.x = floats.Round(pp.x, 2)
		pp.y = floats.Round(pp.y, 2)
		pp.z = floats.Round(pp.z, 2)

		fmt.Printf(" %d %+v -> %+v\n", i, p, pp)
	}

	// Output:
	//
	// cube:
	//  0 {x:0 y:0 z:0} -> {x:5 y:3 z:4}
	//  1 {x:0 y:0 z:1} -> {x:6 y:3 z:4}
	//  2 {x:0 y:1 z:0} -> {x:5 y:3 z:5}
	//  3 {x:0 y:1 z:1} -> {x:6 y:3 z:5}
	//  4 {x:1 y:0 z:0} -> {x:5 y:4 z:4}
	//  5 {x:1 y:0 z:1} -> {x:6 y:4 z:4}
	//  6 {x:1 y:1 z:0} -> {x:5 y:4 z:5}
	//  7 {x:1 y:1 z:1} -> {x:6 y:4 z:5}
	//
	// line segment:
	//  0 {x:2 y:1 z:1} -> {x:2 y:1 z:1}
	//  1 {x:2 y:1 z:2} -> {x:3 y:1 z:1}
}
<commit_msg>dualquat: fix example documentation<commit_after>// Copyright ©2018 The Gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package dualquat_test

import (
	"fmt"
	"math"

	"gonum.org/v1/gonum/floats"
	"gonum.org/v1/gonum/num/dualquat"
	"gonum.org/v1/gonum/num/quat"
)

// point is a 3-dimensional point/vector.
type point struct {
	x, y, z float64
}

// raise raises the dimensionality of a point to a quaternion.
func raise(p point) quat.Number {
	return quat.Number{Imag: p.x, Jmag: p.y, Kmag: p.z}
}

// raiseDual raises the dimensionality of a point to a dual quaternion.
func raiseDual(p point) dualquat.Number {
	return dualquat.Number{
		Real: quat.Number{Real: 1},
		Dual: raise(p),
	}
}

// transform performs the transformation of p by the given dual quaternions.
// The transformations are normalized to unit vectors.
func transform(p point, by ...dualquat.Number) point {
	if len(by) == 0 {
		return p
	}

	// Ensure the modulus of by is correctly scaled.
	for i := range by {
		if len := quat.Abs(by[i].Real); len != 1 {
			by[i].Real = quat.Scale(1/len, by[i].Real)
		}
	}

	// Perform the transformations.
	q := by[0]
	for _, o := range by[1:] {
		q = dualquat.Mul(o, q)
	}
	pp := dualquat.Mul(dualquat.Mul(q, raiseDual(p)), dualquat.Conj(q))

	// Extract the point.
	return point{x: pp.Dual.Imag, y: pp.Dual.Jmag, z: pp.Dual.Kmag}
}

func Example() {
	// Translate a 1×1×1 cube by [3, 4, 5] and rotate it 120° around the
	// diagonal vector [1, 1, 1].
	fmt.Println("cube:")

	// Construct a displacement.
	displace := dualquat.Number{
		Real: quat.Number{Real: 1},
		Dual: quat.Scale(0.5, raise(point{3, 4, 5})),
	}

	// Construct a rotations.
	alpha := 2 * math.Pi / 3
	axis := raise(point{1, 1, 1})
	rotate := dualquat.Number{Real: axis}
	rotate.Real = quat.Scale(math.Sin(alpha/2)/quat.Abs(rotate.Real), rotate.Real)
	rotate.Real.Real += math.Cos(alpha / 2)

	for i, p := range []point{
		{x: 0, y: 0, z: 0},
		{x: 0, y: 0, z: 1},
		{x: 0, y: 1, z: 0},
		{x: 0, y: 1, z: 1},
		{x: 1, y: 0, z: 0},
		{x: 1, y: 0, z: 1},
		{x: 1, y: 1, z: 0},
		{x: 1, y: 1, z: 1},
	} {
		pp := transform(p,
			displace, rotate,
		)

		// Clean up floating point error for clarity.
		pp.x = floats.Round(pp.x, 2)
		pp.y = floats.Round(pp.y, 2)
		pp.z = floats.Round(pp.z, 2)

		fmt.Printf(" %d %+v -> %+v\n", i, p, pp)
	}

	// Rotate a line segment from {[2, 1, 1], [2, 1, 2]} 120° around
	// the diagonal vector [1, 1, 1] at its lower end.
	fmt.Println("\nline segment:")

	// Construct an displacement to the origin from the lower end...
	origin := dualquat.Number{
		Real: quat.Number{Real: 1},
		Dual: quat.Scale(0.5, raise(point{-2, -1, -1})),
	}
	// ... and back from the origin to the lower end.
	replace := dualquat.Number{
		Real: quat.Number{Real: 1},
		Dual: quat.Scale(-1, origin.Dual),
	}

	for i, p := range []point{
		{x: 2, y: 1, z: 1},
		{x: 2, y: 1, z: 2},
	} {
		pp := transform(p,
			origin,  // Displace to origin.
			rotate,  // Rotate around axis.
			replace, // Displace back to original location.
		)

		// Clean up floating point error for clarity.
		pp.x = floats.Round(pp.x, 2)
		pp.y = floats.Round(pp.y, 2)
		pp.z = floats.Round(pp.z, 2)

		fmt.Printf(" %d %+v -> %+v\n", i, p, pp)
	}

	// Output:
	//
	// cube:
	//  0 {x:0 y:0 z:0} -> {x:5 y:3 z:4}
	//  1 {x:0 y:0 z:1} -> {x:6 y:3 z:4}
	//  2 {x:0 y:1 z:0} -> {x:5 y:3 z:5}
	//  3 {x:0 y:1 z:1} -> {x:6 y:3 z:5}
	//  4 {x:1 y:0 z:0} -> {x:5 y:4 z:4}
	//  5 {x:1 y:0 z:1} -> {x:6 y:4 z:4}
	//  6 {x:1 y:1 z:0} -> {x:5 y:4 z:5}
	//  7 {x:1 y:1 z:1} -> {x:6 y:4 z:5}
	//
	// line segment:
	//  0 {x:2 y:1 z:1} -> {x:2 y:1 z:1}
	//  1 {x:2 y:1 z:2} -> {x:3 y:1 z:1}
}
<|endoftext|>


<commit_before>package indicsoundex

import "testing"

func TestCalculate(t *testing.T) {
	inArray := []string{"vasudeva", "kamath", "ವಾಸುದೇವ", "वासुदॆव"}
	outArray := []string{"v231", "k53", "ವASCKDR0", "वASCKDR0"}

	for index, value := range inArray {
		if x, output := Calculate(value, 8), outArray[index]; x != output {
			t.Errorf("Calculate(%s) = %s was expecting %s", value, x, output)
		}
	}
}
<commit_msg>Test cases for Compare algorithms are added<commit_after>package indicsoundex

import "testing"

func TestCalculate(t *testing.T) {
	inArray := []string{"vasudeva", "kamath", "ವಾಸುದೇವ", "वासुदॆव"}
	outArray := []string{"v231", "k53", "ವASCKDR0", "वASCKDR0"}

	for index, value := range inArray {
		if x, output := Calculate(value, 8), outArray[index]; x != output {
			t.Errorf("Calculate(%s) = %s was expecting %s", value,
				x, output)
		}
	}
}

func TestCompare(t *testing.T) {
	inArray := []string{"vasudev", "ವಾಸುದೇವ", "वासुदॆव", "vasudev",
		"vasudev"}
	outArray := []string{"kamath", "വാസുദേവ", "వాసుదేవ", "vaasudev",
		"vasudev"}
	resultArray := []int{SOUNDEX_STRING_NOMATCH, SOUNDEX_STRINGS_MATCH,
		SOUNDEX_STRINGS_MATCH, SOUNDEX_STRINGS_MATCH,
		SOUNDEX_SAME_STRING}

	for index, value := range inArray {
		if x := Compare(value, outArray[index]); x != resultArray[index] {
			t.Errorf("Compare(%s, %s) = %d was expecting %d", value,
				outArray[index], x, resultArray[index])
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package sysdll is an internal leaf package that records and reports
// which Windows DLL names are used by Go itself. These DLLs are then
// only loaded from the System32 directory. See Issue 14959.
package sysdll

// IsSystemDLL reports whether the named dll key (a base name, like
// "foo.dll") is a system DLL which should only be loaded from the
// Windows SYSTEM32 directory.
//
// Filenames are case sensitive, but that doesn't matter because
// the case registered with Add is also the same case used with
// LoadDLL later.
//
// It has no associated mutex and should only be mutated serially
// (currently: during init), and not concurrent with DLL loading.
var IsSystemDLL = map[string]bool{}

// Add notes that dll is a system32 DLL which should only be loaded
// from the Windows SYSTEM32 directory. It returns its argument back,
// for ease of use in generated code.
func Add(dll string) string {
	IsSystemDLL[dll] = true
	return dll
}
<commit_msg>internal/syscall/windows/sysdll: mark package as Windows-only<commit_after>// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build windows

// Package sysdll is an internal leaf package that records and reports
// which Windows DLL names are used by Go itself. These DLLs are then
// only loaded from the System32 directory. See Issue 14959.
package sysdll

// IsSystemDLL reports whether the named dll key (a base name, like
// "foo.dll") is a system DLL which should only be loaded from the
// Windows SYSTEM32 directory.
//
// Filenames are case sensitive, but that doesn't matter because
// the case registered with Add is also the same case used with
// LoadDLL later.
//
// It has no associated mutex and should only be mutated serially
// (currently: during init), and not concurrent with DLL loading.
var IsSystemDLL = map[string]bool{}

// Add notes that dll is a system32 DLL which should only be loaded
// from the Windows SYSTEM32 directory. It returns its argument back,
// for ease of use in generated code.
func Add(dll string) string {
	IsSystemDLL[dll] = true
	return dll
}
<|endoftext|>


<commit_before>// Copyright (c) 2020 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

// Package prom provides custom handlers that support the prometheus
// query endpoints.
package prom

import (
	"context"
	"errors"
	"net/http"

	"github.com/m3db/m3/src/query/api/v1/handler/prometheus/handleroptions"
	"github.com/m3db/m3/src/query/api/v1/handler/prometheus/native"
	"github.com/m3db/m3/src/query/api/v1/options"
	"github.com/m3db/m3/src/query/block"
	queryerrors "github.com/m3db/m3/src/query/errors"
	"github.com/m3db/m3/src/query/models"
	"github.com/m3db/m3/src/query/storage"
	"github.com/m3db/m3/src/query/storage/prometheus"
	xerrors "github.com/m3db/m3/src/x/errors"
	xhttp "github.com/m3db/m3/src/x/net/http"

	errs "github.com/pkg/errors"
	"github.com/prometheus/prometheus/promql"
	"github.com/prometheus/prometheus/promql/parser"
	promstorage "github.com/prometheus/prometheus/storage"
	"github.com/uber-go/tally"
	"go.uber.org/zap"
)

// NewQueryFn creates a new promql Query.
type NewQueryFn func(params models.RequestParams) (promql.Query, error)

var (
	newRangeQueryFn = func(
		engine *promql.Engine,
		queryable promstorage.Queryable,
	) NewQueryFn {
		return func(params models.RequestParams) (promql.Query, error) {
			return engine.NewRangeQuery(
				queryable,
				params.Query,
				params.Start.ToTime(),
				params.End.ToTime(),
				params.Step)
		}
	}

	newInstantQueryFn = func(
		engine *promql.Engine,
		queryable promstorage.Queryable,
	) NewQueryFn {
		return func(params models.RequestParams) (promql.Query, error) {
			return engine.NewInstantQuery(
				queryable,
				params.Query,
				params.Now)
		}
	}
)

type readHandler struct {
	hOpts               options.HandlerOptions
	scope               tally.Scope
	logger              *zap.Logger
	opts                opts
	returnedDataMetrics native.PromReadReturnedDataMetrics
}

func newReadHandler(
	hOpts options.HandlerOptions,
	options opts,
) (http.Handler, error) {
	scope := hOpts.InstrumentOpts().MetricsScope().Tagged(
		map[string]string{"handler": "prometheus-read"},
	)
	return &readHandler{
		hOpts:               hOpts,
		opts:                options,
		scope:               scope,
		logger:              hOpts.InstrumentOpts().Logger(),
		returnedDataMetrics: native.NewPromReadReturnedDataMetrics(scope),
	}, nil
}

func (h *readHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	ctx, request, err := native.ParseRequest(ctx, r, h.opts.instant, h.hOpts)
	if err != nil {
		xhttp.WriteError(w, err)
		return
	}

	params := request.Params
	fetchOptions := request.FetchOpts

	// NB (@shreyas): We put the FetchOptions in context so it can be
	// retrieved in the queryable object as there is no other way to pass
	// that through.
	var resultMetadata block.ResultMetadata
	ctx = context.WithValue(ctx, prometheus.FetchOptionsContextKey, fetchOptions)
	ctx = context.WithValue(ctx, prometheus.BlockResultMetadataKey, &resultMetadata)

	qry, err := h.opts.newQueryFn(params)
	if err != nil {
		h.logger.Error("error creating query",
			zap.Error(err), zap.String("query", params.Query),
			zap.Bool("instant", h.opts.instant))
		xhttp.WriteError(w, xerrors.NewInvalidParamsError(err))
		return
	}
	defer qry.Close()

	res := qry.Exec(ctx)
	if res.Err != nil {
		h.logger.Error("error executing query",
			zap.Error(res.Err), zap.String("query", params.Query),
			zap.Bool("instant", h.opts.instant))
		var sErr *prometheus.StorageErr
		if errors.As(res.Err, &sErr) {
			// If the error happened in the m3 storage layer, propagate the causing error as is.
			err := sErr.Unwrap()
			if queryerrors.IsTimeout(err) {
				xhttp.WriteError(w, queryerrors.NewErrQueryTimeout(err))
			} else {
				xhttp.WriteError(w, err)
			}
		} else {
			promErr := errs.Cause(res.Err)
			switch promErr.(type) { //nolint:errorlint
			case promql.ErrQueryTimeout:
				promErr = queryerrors.NewErrQueryTimeout(promErr)
			case promql.ErrQueryCanceled:
			default:
				// Assume any prometheus library error is a 4xx, since there are no remote calls.
				promErr = xerrors.NewInvalidParamsError(res.Err)
			}
			xhttp.WriteError(w, promErr)
		}
		return
	}

	for _, warn := range resultMetadata.Warnings {
		res.Warnings = append(res.Warnings, errors.New(warn.Message))
	}

	query := params.Query
	err = ApplyRangeWarnings(query, &resultMetadata)
	if err != nil {
		h.logger.Warn("error applying range warnings",
			zap.Error(err), zap.String("query", query),
			zap.Bool("instant", h.opts.instant))
	}

	err = handleroptions.AddDBResultResponseHeaders(w, resultMetadata, fetchOptions)
	if err != nil {
		h.logger.Error("error writing database limit headers", zap.Error(err))
		xhttp.WriteError(w, err)
		return
	}

	returnedDataLimited := h.limitReturnedData(query, res, fetchOptions)
	h.returnedDataMetrics.FetchDatapoints.RecordValue(float64(returnedDataLimited.Datapoints))
	h.returnedDataMetrics.FetchSeries.RecordValue(float64(returnedDataLimited.Series))

	limited := &handleroptions.ReturnedDataLimited{
		Limited:     returnedDataLimited.Limited,
		Series:      returnedDataLimited.Series,
		TotalSeries: returnedDataLimited.TotalSeries,
		Datapoints:  returnedDataLimited.Datapoints,
	}
	err = handleroptions.AddReturnedLimitResponseHeaders(w, limited, nil)
	if err != nil {
		h.logger.Error("error writing response headers",
			zap.Error(err), zap.String("query", query),
			zap.Bool("instant", h.opts.instant))
		xhttp.WriteError(w, err)
		return
	}

	err = Respond(w, &QueryData{
		Result:     res.Value,
		ResultType: res.Value.Type(),
	}, res.Warnings)
	if err != nil {
		h.logger.Error("error writing prom response",
			zap.Error(res.Err), zap.String("query", params.Query),
			zap.Bool("instant", h.opts.instant))
	}
}

func (h *readHandler) limitReturnedData(query string,
	res *promql.Result,
	fetchOpts *storage.FetchOptions,
) native.ReturnedDataLimited {
	var (
		seriesLimit     = fetchOpts.ReturnedSeriesLimit
		datapointsLimit = fetchOpts.ReturnedDatapointsLimit

		limited     = false
		series      int
		datapoints  int
		seriesTotal int
	)
	switch res.Value.Type() {
	case parser.ValueTypeVector:
		v, err := res.Vector()
		if err != nil {
			h.logger.Error("error parsing vector for returned data limits",
				zap.Error(err), zap.String("query", query),
				zap.Bool("instant", h.opts.instant))
			break
		}

		// Determine maxSeries based on either series or datapoints limit. Vector has one datapoint per
		// series and so the datapoint limit behaves the same way as the series one.
		switch {
		case seriesLimit > 0 && datapointsLimit == 0:
			series = seriesLimit
		case seriesLimit == 0 && datapointsLimit > 0:
			series = datapointsLimit
		case seriesLimit == 0 && datapointsLimit == 0:
			// Set max to the actual size if no limits.
			series = len(v)
		default:
			// Take the min of the two limits if both present.
			series = seriesLimit
			if seriesLimit > datapointsLimit {
				series = datapointsLimit
			}
		}

		seriesTotal = len(v)
		limited = series < seriesTotal

		if limited {
			limitedSeries := v[:series]
			res.Value = limitedSeries
			datapoints = len(limitedSeries)
		} else {
			series = seriesTotal
			datapoints = seriesTotal
		}
	case parser.ValueTypeMatrix:
		m, err := res.Matrix()
		if err != nil {
			h.logger.Error("error parsing vector for returned data limits",
				zap.Error(err), zap.String("query", query),
				zap.Bool("instant", h.opts.instant))
			break
		}

		for _, d := range m {
			datapointCount := len(d.Points)
			if fetchOpts.ReturnedSeriesLimit > 0 && series+1 > fetchOpts.ReturnedSeriesLimit {
				limited = true
				break
			}
			if fetchOpts.ReturnedDatapointsLimit > 0 && datapoints+datapointCount > fetchOpts.ReturnedDatapointsLimit {
				limited = true
				break
			}
			series++
			datapoints += datapointCount
		}
		seriesTotal = len(m)

		if series < seriesTotal {
			res.Value = m[:series]
		}
	default:
	}

	return native.ReturnedDataLimited{
		Limited:     limited,
		Series:      series,
		Datapoints:  datapoints,
		TotalSeries: seriesTotal,
	}
}
<commit_msg>[query] Fix log statement that obscures error returned when failed to write Prom response to client (#3638)<commit_after>// Copyright (c) 2020 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

// Package prom provides custom handlers that support the prometheus
// query endpoints.
package prom

import (
	"context"
	"errors"
	"net/http"

	"github.com/m3db/m3/src/query/api/v1/handler/prometheus/handleroptions"
	"github.com/m3db/m3/src/query/api/v1/handler/prometheus/native"
	"github.com/m3db/m3/src/query/api/v1/options"
	"github.com/m3db/m3/src/query/block"
	queryerrors "github.com/m3db/m3/src/query/errors"
	"github.com/m3db/m3/src/query/models"
	"github.com/m3db/m3/src/query/storage"
	"github.com/m3db/m3/src/query/storage/prometheus"
	xerrors "github.com/m3db/m3/src/x/errors"
	xhttp "github.com/m3db/m3/src/x/net/http"

	errs "github.com/pkg/errors"
	"github.com/prometheus/prometheus/promql"
	"github.com/prometheus/prometheus/promql/parser"
	promstorage "github.com/prometheus/prometheus/storage"
	"github.com/uber-go/tally"
	"go.uber.org/zap"
)

// NewQueryFn creates a new promql Query.
type NewQueryFn func(params models.RequestParams) (promql.Query, error)

var (
	newRangeQueryFn = func(
		engine *promql.Engine,
		queryable promstorage.Queryable,
	) NewQueryFn {
		return func(params models.RequestParams) (promql.Query, error) {
			return engine.NewRangeQuery(
				queryable,
				params.Query,
				params.Start.ToTime(),
				params.End.ToTime(),
				params.Step)
		}
	}

	newInstantQueryFn = func(
		engine *promql.Engine,
		queryable promstorage.Queryable,
	) NewQueryFn {
		return func(params models.RequestParams) (promql.Query, error) {
			return engine.NewInstantQuery(
				queryable,
				params.Query,
				params.Now)
		}
	}
)

type readHandler struct {
	hOpts               options.HandlerOptions
	scope               tally.Scope
	logger              *zap.Logger
	opts                opts
	returnedDataMetrics native.PromReadReturnedDataMetrics
}

func newReadHandler(
	hOpts options.HandlerOptions,
	options opts,
) (http.Handler, error) {
	scope := hOpts.InstrumentOpts().MetricsScope().Tagged(
		map[string]string{"handler": "prometheus-read"},
	)
	return &readHandler{
		hOpts:               hOpts,
		opts:                options,
		scope:               scope,
		logger:              hOpts.InstrumentOpts().Logger(),
		returnedDataMetrics: native.NewPromReadReturnedDataMetrics(scope),
	}, nil
}

func (h *readHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	ctx, request, err := native.ParseRequest(ctx, r, h.opts.instant, h.hOpts)
	if err != nil {
		xhttp.WriteError(w, err)
		return
	}

	params := request.Params
	fetchOptions := request.FetchOpts

	// NB (@shreyas): We put the FetchOptions in context so it can be
	// retrieved in the queryable object as there is no other way to pass
	// that through.
	var resultMetadata block.ResultMetadata
	ctx = context.WithValue(ctx, prometheus.FetchOptionsContextKey, fetchOptions)
	ctx = context.WithValue(ctx, prometheus.BlockResultMetadataKey, &resultMetadata)

	qry, err := h.opts.newQueryFn(params)
	if err != nil {
		h.logger.Error("error creating query",
			zap.Error(err), zap.String("query", params.Query),
			zap.Bool("instant", h.opts.instant))
		xhttp.WriteError(w, xerrors.NewInvalidParamsError(err))
		return
	}
	defer qry.Close()

	res := qry.Exec(ctx)
	if res.Err != nil {
		h.logger.Error("error executing query",
			zap.Error(res.Err), zap.String("query", params.Query),
			zap.Bool("instant", h.opts.instant))
		var sErr *prometheus.StorageErr
		if errors.As(res.Err, &sErr) {
			// If the error happened in the m3 storage layer, propagate the causing error as is.
			err := sErr.Unwrap()
			if queryerrors.IsTimeout(err) {
				xhttp.WriteError(w, queryerrors.NewErrQueryTimeout(err))
			} else {
				xhttp.WriteError(w, err)
			}
		} else {
			promErr := errs.Cause(res.Err)
			switch promErr.(type) { //nolint:errorlint
			case promql.ErrQueryTimeout:
				promErr = queryerrors.NewErrQueryTimeout(promErr)
			case promql.ErrQueryCanceled:
			default:
				// Assume any prometheus library error is a 4xx, since there are no remote calls.
				promErr = xerrors.NewInvalidParamsError(res.Err)
			}
			xhttp.WriteError(w, promErr)
		}
		return
	}

	for _, warn := range resultMetadata.Warnings {
		res.Warnings = append(res.Warnings, errors.New(warn.Message))
	}

	query := params.Query
	err = ApplyRangeWarnings(query, &resultMetadata)
	if err != nil {
		h.logger.Warn("error applying range warnings",
			zap.Error(err), zap.String("query", query),
			zap.Bool("instant", h.opts.instant))
	}

	err = handleroptions.AddDBResultResponseHeaders(w, resultMetadata, fetchOptions)
	if err != nil {
		h.logger.Error("error writing database limit headers", zap.Error(err))
		xhttp.WriteError(w, err)
		return
	}

	returnedDataLimited := h.limitReturnedData(query, res, fetchOptions)
	h.returnedDataMetrics.FetchDatapoints.RecordValue(float64(returnedDataLimited.Datapoints))
	h.returnedDataMetrics.FetchSeries.RecordValue(float64(returnedDataLimited.Series))

	limited := &handleroptions.ReturnedDataLimited{
		Limited:     returnedDataLimited.Limited,
		Series:      returnedDataLimited.Series,
		TotalSeries: returnedDataLimited.TotalSeries,
		Datapoints:  returnedDataLimited.Datapoints,
	}
	err = handleroptions.AddReturnedLimitResponseHeaders(w, limited, nil)
	if err != nil {
		h.logger.Error("error writing response headers",
			zap.Error(err), zap.String("query", query),
			zap.Bool("instant", h.opts.instant))
		xhttp.WriteError(w, err)
		return
	}

	if err := Respond(w, &QueryData{
		Result:     res.Value,
		ResultType: res.Value.Type(),
	}, res.Warnings); err != nil {
		h.logger.Error("error writing prom response",
			zap.Error(err),
			zap.String("query", params.Query),
			zap.Bool("instant", h.opts.instant))
	}
}

func (h *readHandler) limitReturnedData(query string,
	res *promql.Result,
	fetchOpts *storage.FetchOptions,
) native.ReturnedDataLimited {
	var (
		seriesLimit     = fetchOpts.ReturnedSeriesLimit
		datapointsLimit = fetchOpts.ReturnedDatapointsLimit

		limited     = false
		series      int
		datapoints  int
		seriesTotal int
	)
	switch res.Value.Type() {
	case parser.ValueTypeVector:
		v, err := res.Vector()
		if err != nil {
			h.logger.Error("error parsing vector for returned data limits",
				zap.Error(err), zap.String("query", query),
				zap.Bool("instant", h.opts.instant))
			break
		}

		// Determine maxSeries based on either series or datapoints limit. Vector has one datapoint per
		// series and so the datapoint limit behaves the same way as the series one.
		switch {
		case seriesLimit > 0 && datapointsLimit == 0:
			series = seriesLimit
		case seriesLimit == 0 && datapointsLimit > 0:
			series = datapointsLimit
		case seriesLimit == 0 && datapointsLimit == 0:
			// Set max to the actual size if no limits.
			series = len(v)
		default:
			// Take the min of the two limits if both present.
			series = seriesLimit
			if seriesLimit > datapointsLimit {
				series = datapointsLimit
			}
		}

		seriesTotal = len(v)
		limited = series < seriesTotal

		if limited {
			limitedSeries := v[:series]
			res.Value = limitedSeries
			datapoints = len(limitedSeries)
		} else {
			series = seriesTotal
			datapoints = seriesTotal
		}
	case parser.ValueTypeMatrix:
		m, err := res.Matrix()
		if err != nil {
			h.logger.Error("error parsing vector for returned data limits",
				zap.Error(err), zap.String("query", query),
				zap.Bool("instant", h.opts.instant))
			break
		}

		for _, d := range m {
			datapointCount := len(d.Points)
			if fetchOpts.ReturnedSeriesLimit > 0 && series+1 > fetchOpts.ReturnedSeriesLimit {
				limited = true
				break
			}
			if fetchOpts.ReturnedDatapointsLimit > 0 && datapoints+datapointCount > fetchOpts.ReturnedDatapointsLimit {
				limited = true
				break
			}
			series++
			datapoints += datapointCount
		}
		seriesTotal = len(m)

		if series < seriesTotal {
			res.Value = m[:series]
		}
	default:
	}

	return native.ReturnedDataLimited{
		Limited:     limited,
		Series:      series,
		Datapoints:  datapoints,
		TotalSeries: seriesTotal,
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 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.

//go:build !android && !darwin && !js && !ios && !windows
// +build !android,!darwin,!js,!ios,!windows

package glfw

import (
	"fmt"
	"math"
	"runtime"

	"github.com/hajimehoshi/ebiten/v2/internal/driver"
	"github.com/hajimehoshi/ebiten/v2/internal/glfw"
	"github.com/jezek/xgb"
	"github.com/jezek/xgb/randr"
	"github.com/jezek/xgb/xproto"
)

type videoModeScaleCacheKey struct{ X, Y int }

var videoModeScaleCache = map[videoModeScaleCacheKey]float64{}

// clearVideoModeScaleCache must be called from the main thread.
func clearVideoModeScaleCache() {
	for k := range videoModeScaleCache {
		delete(videoModeScaleCache, k)
	}
}

// videoModeScale must be called from the main thread.
func videoModeScale(m *glfw.Monitor) float64 {
	// Caching wrapper for videoModeScaleUncached as
	// videoModeScaleUncached may be expensive (uses blocking calls on X connection)
	// and public ScreenSizeInFullscreen API needs the videoModeScale.
	monitorX, monitorY := m.GetPos()
	cacheKey := videoModeScaleCacheKey{X: monitorX, Y: monitorY}
	if cached, ok := videoModeScaleCache[cacheKey]; ok {
		return cached
	}

	scale := videoModeScaleUncached(m)
	videoModeScaleCache[cacheKey] = scale
	return scale
}

// videoModeScaleUncached must be called from the main thread.
func videoModeScaleUncached(m *glfw.Monitor) float64 {
	// TODO: if glfw/glfw#1961 gets fixed, this function may need revising.
	// In case GLFW decides to switch to returning logical pixels, we can just return 1.

	// Note: GLFW currently returns physical pixel sizes,
	// but we need to predict the window system-side size of the fullscreen window
	// for Ebiten's `ScreenSizeInFullscreen` public API.
	// Also at the moment we need this prior to switching to fullscreen, but that might be replacable.
	// So this function computes the ratio of physical per logical pixels.
	xconn, err := xgb.NewConn()
	if err != nil {
		// No X11 connection?
		// Assume we're on pure Wayland then.
		// GLFW/Wayland shouldn't be having this issue.
		return 1
	}
	defer xconn.Close()

	if err := randr.Init(xconn); err != nil {
		// No RANDR extension? No problem.
		return 1
	}

	root := xproto.Setup(xconn).DefaultScreen(xconn).Root
	res, err := randr.GetScreenResourcesCurrent(xconn, root).Reply()
	if err != nil {
		// Likely means RANDR is not working. No problem.
		return 1
	}

	monitorX, monitorY := m.GetPos()

	for _, crtc := range res.Crtcs[:res.NumCrtcs] {
		info, err := randr.GetCrtcInfo(xconn, crtc, res.ConfigTimestamp).Reply()
		if err != nil {
			// This Crtc is bad. Maybe just got disconnected?
			continue
		}
		if info.NumOutputs == 0 {
			// This Crtc is not connected to any output.
			// In other words, a disabled monitor.
			continue
		}
		if int(info.X) == monitorX && int(info.Y) == monitorY {
			xWidth, xHeight := info.Width, info.Height
			vm := m.GetVideoMode()
			physWidth, physHeight := vm.Width, vm.Height
			// Return one scale, even though there may be separate X and Y scales.
			// Return the _larger_ scale, as this would yield a letterboxed display on mismatch, rather than a cut-off one.
			scale := math.Max(float64(physWidth)/float64(xWidth), float64(physHeight)/float64(xHeight))
			return scale
		}
	}

	// Monitor not known to XRandR. Weird.
	return 1
}

// dipFromGLFWMonitorPixel must be called from the main thread.
func (u *UserInterface) dipFromGLFWMonitorPixel(x float64, monitor *glfw.Monitor) float64 {
	return x / (videoModeScale(monitor) * u.deviceScaleFactor(monitor))
}

// dipFromGLFWPixel must be called from the main thread.
func (u *UserInterface) dipFromGLFWPixel(x float64, monitor *glfw.Monitor) float64 {
	return x / u.deviceScaleFactor(monitor)
}

// dipToGLFWPixel must be called from the main thread.
func (u *UserInterface) dipToGLFWPixel(x float64, monitor *glfw.Monitor) float64 {
	return x * u.deviceScaleFactor(monitor)
}

func (u *UserInterface) adjustWindowPosition(x, y int) (int, int) {
	return x, y
}

func initialMonitorByOS() *glfw.Monitor {
	return nil
}

func currentMonitorByOS(_ *glfw.Window) *glfw.Monitor {
	// TODO: Implement this correctly. (#1119).
	return nil
}

func (u *UserInterface) nativeWindow() uintptr {
	// TODO: Implement this.
	return 0
}

func (u *UserInterface) isNativeFullscreen() bool {
	return false
}

func (u *UserInterface) setNativeCursor(shape driver.CursorShape) {
	// TODO: Use native API in the future (#1571)
	u.window.SetCursor(glfwSystemCursors[shape])
}

func (u *UserInterface) isNativeFullscreenAvailable() bool {
	return false
}

func (u *UserInterface) setNativeFullscreen(fullscreen bool) {
	panic(fmt.Sprintf("glfw: setNativeFullscreen is not implemented in this environment: %s", runtime.GOOS))
}

func (u *UserInterface) adjustViewSize() {
}

func initializeWindowAfterCreation(w *glfw.Window) {
	// Show the window once before getting the position of the window.
	// On Linux/Unix, the window position is not reliable before showing.
	w.Show()

	// Hiding the window makes the position unreliable again. Do not call w.Hide() here (#1829)
	// Calling Hide is problematic especially on XWayland and/or Sway.
	// Apparently the window state is inconsistent just after the window is created, but we are not sure.
	// For more details, see the discussion in #1829.
}
<commit_msg>internal/uidriver/glfw: Clean up build tags<commit_after>// Copyright 2016 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.

//go:build !android && !darwin && !js && !windows
// +build !android,!darwin,!js,!windows

package glfw

import (
	"fmt"
	"math"
	"runtime"

	"github.com/hajimehoshi/ebiten/v2/internal/driver"
	"github.com/hajimehoshi/ebiten/v2/internal/glfw"
	"github.com/jezek/xgb"
	"github.com/jezek/xgb/randr"
	"github.com/jezek/xgb/xproto"
)

type videoModeScaleCacheKey struct{ X, Y int }

var videoModeScaleCache = map[videoModeScaleCacheKey]float64{}

// clearVideoModeScaleCache must be called from the main thread.
func clearVideoModeScaleCache() {
	for k := range videoModeScaleCache {
		delete(videoModeScaleCache, k)
	}
}

// videoModeScale must be called from the main thread.
func videoModeScale(m *glfw.Monitor) float64 {
	// Caching wrapper for videoModeScaleUncached as
	// videoModeScaleUncached may be expensive (uses blocking calls on X connection)
	// and public ScreenSizeInFullscreen API needs the videoModeScale.
	monitorX, monitorY := m.GetPos()
	cacheKey := videoModeScaleCacheKey{X: monitorX, Y: monitorY}
	if cached, ok := videoModeScaleCache[cacheKey]; ok {
		return cached
	}

	scale := videoModeScaleUncached(m)
	videoModeScaleCache[cacheKey] = scale
	return scale
}

// videoModeScaleUncached must be called from the main thread.
func videoModeScaleUncached(m *glfw.Monitor) float64 {
	// TODO: if glfw/glfw#1961 gets fixed, this function may need revising.
	// In case GLFW decides to switch to returning logical pixels, we can just return 1.

	// Note: GLFW currently returns physical pixel sizes,
	// but we need to predict the window system-side size of the fullscreen window
	// for Ebiten's `ScreenSizeInFullscreen` public API.
	// Also at the moment we need this prior to switching to fullscreen, but that might be replacable.
	// So this function computes the ratio of physical per logical pixels.
	xconn, err := xgb.NewConn()
	if err != nil {
		// No X11 connection?
		// Assume we're on pure Wayland then.
		// GLFW/Wayland shouldn't be having this issue.
		return 1
	}
	defer xconn.Close()

	if err := randr.Init(xconn); err != nil {
		// No RANDR extension? No problem.
		return 1
	}

	root := xproto.Setup(xconn).DefaultScreen(xconn).Root
	res, err := randr.GetScreenResourcesCurrent(xconn, root).Reply()
	if err != nil {
		// Likely means RANDR is not working. No problem.
		return 1
	}

	monitorX, monitorY := m.GetPos()

	for _, crtc := range res.Crtcs[:res.NumCrtcs] {
		info, err := randr.GetCrtcInfo(xconn, crtc, res.ConfigTimestamp).Reply()
		if err != nil {
			// This Crtc is bad. Maybe just got disconnected?
			continue
		}
		if info.NumOutputs == 0 {
			// This Crtc is not connected to any output.
			// In other words, a disabled monitor.
			continue
		}
		if int(info.X) == monitorX && int(info.Y) == monitorY {
			xWidth, xHeight := info.Width, info.Height
			vm := m.GetVideoMode()
			physWidth, physHeight := vm.Width, vm.Height
			// Return one scale, even though there may be separate X and Y scales.
			// Return the _larger_ scale, as this would yield a letterboxed display on mismatch, rather than a cut-off one.
			scale := math.Max(float64(physWidth)/float64(xWidth), float64(physHeight)/float64(xHeight))
			return scale
		}
	}

	// Monitor not known to XRandR. Weird.
	return 1
}

// dipFromGLFWMonitorPixel must be called from the main thread.
func (u *UserInterface) dipFromGLFWMonitorPixel(x float64, monitor *glfw.Monitor) float64 {
	return x / (videoModeScale(monitor) * u.deviceScaleFactor(monitor))
}

// dipFromGLFWPixel must be called from the main thread.
func (u *UserInterface) dipFromGLFWPixel(x float64, monitor *glfw.Monitor) float64 {
	return x / u.deviceScaleFactor(monitor)
}

// dipToGLFWPixel must be called from the main thread.
func (u *UserInterface) dipToGLFWPixel(x float64, monitor *glfw.Monitor) float64 {
	return x * u.deviceScaleFactor(monitor)
}

func (u *UserInterface) adjustWindowPosition(x, y int) (int, int) {
	return x, y
}

func initialMonitorByOS() *glfw.Monitor {
	return nil
}

func currentMonitorByOS(_ *glfw.Window) *glfw.Monitor {
	// TODO: Implement this correctly. (#1119).
	return nil
}

func (u *UserInterface) nativeWindow() uintptr {
	// TODO: Implement this.
	return 0
}

func (u *UserInterface) isNativeFullscreen() bool {
	return false
}

func (u *UserInterface) setNativeCursor(shape driver.CursorShape) {
	// TODO: Use native API in the future (#1571)
	u.window.SetCursor(glfwSystemCursors[shape])
}

func (u *UserInterface) isNativeFullscreenAvailable() bool {
	return false
}

func (u *UserInterface) setNativeFullscreen(fullscreen bool) {
	panic(fmt.Sprintf("glfw: setNativeFullscreen is not implemented in this environment: %s", runtime.GOOS))
}

func (u *UserInterface) adjustViewSize() {
}

func initializeWindowAfterCreation(w *glfw.Window) {
	// Show the window once before getting the position of the window.
	// On Linux/Unix, the window position is not reliable before showing.
	w.Show()

	// Hiding the window makes the position unreliable again. Do not call w.Hide() here (#1829)
	// Calling Hide is problematic especially on XWayland and/or Sway.
	// Apparently the window state is inconsistent just after the window is created, but we are not sure.
	// For more details, see the discussion in #1829.
}
<|endoftext|>