<commit_before>//
// mod.go
// post moderation
//
package srnd

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"strings"
)

// regenerate pages function
type RegenFunc func(newsgroup, msgid, root string, page int)

// does an action for the administrator
// takes in json
type AdminFunc func(param map[string]interface{}) (interface{}, error)

// interface for moderation ui
type ModUI interface {

	// channel for daemon to poll for nntp articles from the mod ui
	MessageChan() chan NNTPMessage

	// check if this key is allowed to access
	// return true if it can otherwise false
	CheckKey(privkey, scope string) (bool, error)

	// serve the base page
	ServeModPage(wr http.ResponseWriter, r *http.Request)
	// handle a login POST request
	HandleLogin(wr http.ResponseWriter, r *http.Request)
	// handle a delete article request
	HandleDeletePost(wr http.ResponseWriter, r *http.Request)
	// handle a ban address request
	HandleBanAddress(wr http.ResponseWriter, r *http.Request)
	// handle an unban address request
	HandleUnbanAddress(wr http.ResponseWriter, r *http.Request)
	// handle add a pubkey
	HandleAddPubkey(wr http.ResponseWriter, r *http.Request)
	// handle removing a pubkey
	HandleDelPubkey(wr http.ResponseWriter, r *http.Request)
	// handle key generation
	HandleKeyGen(wr http.ResponseWriter, r *http.Request)
	// handle admin command
	HandleAdminCommand(wr http.ResponseWriter, r *http.Request)
}

type ModEvent interface {
	// turn it into a string for putting into an article
	String() string
	// what type of mod event
	Action() string
	// what reason for the event
	Reason() string
	// what is the event acting on
	Target() string
	// scope of the event, regex of newsgroup
	Scope() string
	// when this mod event expires, unix nano
	Expires() int64
}

type simpleModEvent string

func (self simpleModEvent) String() string {
	return string(self)
}

func (self simpleModEvent) Action() string {
	return strings.Split(string(self), " ")[0]
}

func (self simpleModEvent) Reason() string {
	return ""
}

func (self simpleModEvent) Target() string {
	return strings.Split(string(self), " ")[1]
}

func (self simpleModEvent) Scope() string {
	// TODO: hard coded
	return "overchan.*"
}

func (self simpleModEvent) Expires() int64 {
	// no expiration
	return -1
}

// create an overchan-delete mod event
func overchanDelete(msgid string) ModEvent {
	return simpleModEvent(fmt.Sprintf("delete %s", msgid))
}

// create an overchan-inet-ban mod event
func overchanInetBan(encAddr, key string, expire int64) ModEvent {
	return simpleModEvent(fmt.Sprintf("overchan-inet-ban %s:%s:%d", encAddr, key, expire))
}

// moderation message
// wraps multiple mod events
// is turned into an NNTPMessage later
type ModMessage []ModEvent

// write this mod message's body
func (self ModMessage) WriteTo(wr io.Writer, delim []byte) (err error) {
	// write body
	for _, ev := range self {
		_, err = io.WriteString(wr, ev.String())
		_, err = wr.Write(delim)
	}
	return
}

func ParseModEvent(line string) ModEvent {
	return simpleModEvent(line)
}

// wrap mod message in an nntp message
// does not sign
func wrapModMessage(mm ModMessage) NNTPMessage {
	pathname := "nntpchan.censor"
	nntp := &nntpArticle{
		headers: make(ArticleHeaders),
	}
	nntp.headers.Set("Newsgroups", "ctl")
	nntp.headers.Set("Content-Type", "text/plain; charset=UTF-8")
	nntp.headers.Set("Message-ID", genMessageID(pathname))
	nntp.headers.Set("Date", timeNowStr())
	nntp.headers.Set("Path", pathname)
	// todo: set these maybe?
	nntp.headers.Set("From", "anon <a@n.on>")
	nntp.headers.Set("Subject", "censor")

	var buff bytes.Buffer
	// crlf delimited
	_ = mm.WriteTo(&buff, []byte{10})
	// create plaintext attachment, cut off last 2 bytes
	nntp.message = createPlaintextAttachment(buff.Bytes())
	buff.Reset()
	return nntp
}

type ModEngine interface {
	// chan to send the mod engine posts given message_id
	MessageChan() chan string
	// delete post of a poster
	DeletePost(msgid string, regen RegenFunc) error
	// ban a cidr
	BanAddress(cidr string) error
	// do we allow this public key to delete this message-id ?
	AllowDelete(pubkey, msgid string) bool
	// do we allow this public key to do inet-ban?
	AllowBan(pubkey string) bool
	// load a mod message
	LoadMessage(msgid string) NNTPMessage
}

type modEngine struct {
	database Database
	store    ArticleStore
	chnl     chan string
}

func (self modEngine) LoadMessage(msgid string) NNTPMessage {
	return self.store.GetMessage(msgid)
}

func (self modEngine) MessageChan() chan string {
	return self.chnl
}

func (self modEngine) BanAddress(cidr string) (err error) {
	return self.database.BanAddr(cidr)
}

func (self modEngine) DeletePost(msgid string, regen RegenFunc) (err error) {
	hdr, err := self.database.GetHeadersForMessage(msgid)
	var delposts []string
	var page int64
	var ref, group string
	if hdr == nil {
		log.Println("failed to get headers for article", msgid, err)
	} else {
		ref = hdr.Get("References", "")
		group = hdr.Get("Newsgroups", "")
		if ref == "" || ref == msgid {
			// is root post
			// delete replies too
			repls := self.database.GetThreadReplies(msgid, 0, 0)
			if repls == nil {
				log.Println("cannot get thread replies for", msgid)
			} else {
				delposts = append(delposts, repls...)
			}

			_, page, err = self.database.GetPageForRootMessage(msgid)
			// delete thread presence
			self.database.DeleteThread(msgid)
			ref = msgid
		} else {
			_, page, err = self.database.GetPageForRootMessage(ref)
		}
	}
	delposts = append(delposts, msgid)
	// get list of files to delete
	var delfiles []string
	for _, delmsg := range delposts {
		article := self.store.GetFilename(delmsg)
		delfiles = append(delfiles, article)
		// get attachments for post
		atts := self.database.GetPostAttachments(delmsg)
		if atts != nil {
			for _, att := range atts {
				img := self.store.AttachmentFilepath(att)
				thm := self.store.ThumbnailFilepath(att)
				delfiles = append(delfiles, img, thm)
			}
		}
		log.Println("delete", delmsg)
		// delete article from post database
		err = self.database.DeleteArticle(delmsg)
		if err != nil {
			log.Println(err)
		}
		// ban article
		self.database.BanArticle(delmsg, "deleted by moderator")
	}
	// delete all files
	for _, f := range delfiles {
		log.Printf("delete file: %s", f)
		os.Remove(f)
	}
	regen(group, msgid, ref, int(page))
	return nil
}

func (self modEngine) AllowBan(pubkey string) bool {
	is_admin, _ := self.database.CheckAdminPubkey(pubkey)
	if is_admin {
		// admins can do whatever
		return true
	}
	return self.database.CheckModPubkeyGlobal(pubkey)
}

func (self modEngine) AllowDelete(pubkey, msgid string) (allow bool) {
	is_admin, _ := self.database.CheckAdminPubkey(pubkey)
	if is_admin {
		// admins can do whatever
		return true
	}
	if self.database.CheckModPubkeyGlobal(pubkey) {
		// globals can delete as they wish
		return true
	}
	// check for scoped permissions
	_, group, _, err := self.database.GetInfoForMessage(msgid)
	if err == nil && newsgroupValidFormat(group) {
		allow = self.database.CheckModPubkeyCanModGroup(pubkey, group)
	} else if err != nil {
		log.Println("db error in mod engine while checking permissions", err)
	}
	return
}

// run a mod engine logic mainloop
func RunModEngine(mod ModEngine, regen RegenFunc) {

	chnl := mod.MessageChan()
	for {
		msgid := <-chnl
		nntp := mod.LoadMessage(msgid)
		if nntp == nil {
			log.Println("failed to load mod message", msgid)
			continue
		}
		// sanity check
		if nntp.Newsgroup() == "ctl" {
			pubkey := nntp.Pubkey()
			for _, line := range strings.Split(nntp.Message(), "\n") {
				line = strings.Trim(line, "\r\t\n")
				ev := ParseModEvent(line)
				action := ev.Action()
				if action == "delete" {
					msgid := ev.Target()
					if !ValidMessageID(msgid) {
						// invalid message-id
						log.Println("invalid message-id for mod delete", msgid, "from", pubkey)
						continue
					}
					// this is a delete action
					if mod.AllowDelete(pubkey, msgid) {
						err := mod.DeletePost(msgid, regen)
						if err != nil {
							log.Println(msgid, err)
						}
					} else {
						log.Printf("pubkey=%s will not delete %s not trusted", pubkey, msgid)
					}
				} else if action == "overchan-inet-ban" {
					// ban action
					target := ev.Target()
					if target[0] == '[' {
						// probably a literal ipv6 rangeban
						if mod.AllowBan(pubkey) {
							err := mod.BanAddress(target)
							if err != nil {
								log.Println("failed to do literal ipv6 range ban on", target, err)
							}
						} else {
							log.Println("ignoring literal ipv6 rangeban from", pubkey, "as they are not allowed to ban")
						}
						continue
					}
					parts := strings.Split(target, ":")
					if len(parts) == 3 {
						// encrypted ip
						encaddr, key := parts[0], parts[1]
						cidr := decAddr(encaddr, key)
						if cidr == "" {
							log.Println("failed to decrypt inet ban")
						} else if mod.AllowBan(pubkey) {
							err := mod.BanAddress(cidr)
							if err != nil {
								log.Println("failed to do range ban on", cidr, err)
							}
						} else {
							log.Println("ingoring encrypted-ip inet ban from", pubkey, "as they are not allowed to ban")
						}
					} else if len(parts) == 1 {
						// literal cidr
						cidr := parts[0]
						if mod.AllowBan(pubkey) {
							err := mod.BanAddress(cidr)
							if err != nil {
								log.Println("failed to do literal range ban on", cidr, err)
							}
						} else {
							log.Println("ingoring literal cidr range ban from", pubkey, "as they are not allowed to ban")
						}
					} else {
						log.Printf("invalid overchan-inet-ban: target=%s", target)
					}
				} else {
					log.Println("invalid mod action", action, "from", pubkey)
				}
			}
		}
	}
}
<commit_msg>make sure files are delete when mod makes them when using redis as database<commit_after>//
// mod.go
// post moderation
//
package srnd

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"strings"
)

// regenerate pages function
type RegenFunc func(newsgroup, msgid, root string, page int)

// does an action for the administrator
// takes in json
type AdminFunc func(param map[string]interface{}) (interface{}, error)

// interface for moderation ui
type ModUI interface {

	// channel for daemon to poll for nntp articles from the mod ui
	MessageChan() chan NNTPMessage

	// check if this key is allowed to access
	// return true if it can otherwise false
	CheckKey(privkey, scope string) (bool, error)

	// serve the base page
	ServeModPage(wr http.ResponseWriter, r *http.Request)
	// handle a login POST request
	HandleLogin(wr http.ResponseWriter, r *http.Request)
	// handle a delete article request
	HandleDeletePost(wr http.ResponseWriter, r *http.Request)
	// handle a ban address request
	HandleBanAddress(wr http.ResponseWriter, r *http.Request)
	// handle an unban address request
	HandleUnbanAddress(wr http.ResponseWriter, r *http.Request)
	// handle add a pubkey
	HandleAddPubkey(wr http.ResponseWriter, r *http.Request)
	// handle removing a pubkey
	HandleDelPubkey(wr http.ResponseWriter, r *http.Request)
	// handle key generation
	HandleKeyGen(wr http.ResponseWriter, r *http.Request)
	// handle admin command
	HandleAdminCommand(wr http.ResponseWriter, r *http.Request)
}

type ModEvent interface {
	// turn it into a string for putting into an article
	String() string
	// what type of mod event
	Action() string
	// what reason for the event
	Reason() string
	// what is the event acting on
	Target() string
	// scope of the event, regex of newsgroup
	Scope() string
	// when this mod event expires, unix nano
	Expires() int64
}

type simpleModEvent string

func (self simpleModEvent) String() string {
	return string(self)
}

func (self simpleModEvent) Action() string {
	return strings.Split(string(self), " ")[0]
}

func (self simpleModEvent) Reason() string {
	return ""
}

func (self simpleModEvent) Target() string {
	return strings.Split(string(self), " ")[1]
}

func (self simpleModEvent) Scope() string {
	// TODO: hard coded
	return "overchan.*"
}

func (self simpleModEvent) Expires() int64 {
	// no expiration
	return -1
}

// create an overchan-delete mod event
func overchanDelete(msgid string) ModEvent {
	return simpleModEvent(fmt.Sprintf("delete %s", msgid))
}

// create an overchan-inet-ban mod event
func overchanInetBan(encAddr, key string, expire int64) ModEvent {
	return simpleModEvent(fmt.Sprintf("overchan-inet-ban %s:%s:%d", encAddr, key, expire))
}

// moderation message
// wraps multiple mod events
// is turned into an NNTPMessage later
type ModMessage []ModEvent

// write this mod message's body
func (self ModMessage) WriteTo(wr io.Writer, delim []byte) (err error) {
	// write body
	for _, ev := range self {
		_, err = io.WriteString(wr, ev.String())
		_, err = wr.Write(delim)
	}
	return
}

func ParseModEvent(line string) ModEvent {
	return simpleModEvent(line)
}

// wrap mod message in an nntp message
// does not sign
func wrapModMessage(mm ModMessage) NNTPMessage {
	pathname := "nntpchan.censor"
	nntp := &nntpArticle{
		headers: make(ArticleHeaders),
	}
	nntp.headers.Set("Newsgroups", "ctl")
	nntp.headers.Set("Content-Type", "text/plain; charset=UTF-8")
	nntp.headers.Set("Message-ID", genMessageID(pathname))
	nntp.headers.Set("Date", timeNowStr())
	nntp.headers.Set("Path", pathname)
	// todo: set these maybe?
	nntp.headers.Set("From", "anon <a@n.on>")
	nntp.headers.Set("Subject", "censor")

	var buff bytes.Buffer
	// crlf delimited
	_ = mm.WriteTo(&buff, []byte{10})
	// create plaintext attachment, cut off last 2 bytes
	nntp.message = createPlaintextAttachment(buff.Bytes())
	buff.Reset()
	return nntp
}

type ModEngine interface {
	// chan to send the mod engine posts given message_id
	MessageChan() chan string
	// delete post of a poster
	DeletePost(msgid string, regen RegenFunc) error
	// ban a cidr
	BanAddress(cidr string) error
	// do we allow this public key to delete this message-id ?
	AllowDelete(pubkey, msgid string) bool
	// do we allow this public key to do inet-ban?
	AllowBan(pubkey string) bool
	// load a mod message
	LoadMessage(msgid string) NNTPMessage
}

type modEngine struct {
	database Database
	store    ArticleStore
	chnl     chan string
}

func (self modEngine) LoadMessage(msgid string) NNTPMessage {
	return self.store.GetMessage(msgid)
}

func (self modEngine) MessageChan() chan string {
	return self.chnl
}

func (self modEngine) BanAddress(cidr string) (err error) {
	return self.database.BanAddr(cidr)
}

func (self modEngine) DeletePost(msgid string, regen RegenFunc) (err error) {
	hdr, err := self.database.GetHeadersForMessage(msgid)
	var delposts []string
	var page int64
	var ref, group string
	rootmsgid := ""
	if hdr == nil {
		log.Println("failed to get headers for article", msgid, err)
	} else {
		ref = hdr.Get("References", "")
		group = hdr.Get("Newsgroups", "")
		if ref == "" || ref == msgid {
			// is root post
			// delete replies too
			repls := self.database.GetThreadReplies(msgid, 0, 0)
			if repls == nil {
				log.Println("cannot get thread replies for", msgid)
			} else {
				delposts = append(delposts, repls...)
			}

			_, page, err = self.database.GetPageForRootMessage(msgid)
			ref = msgid
			rootmsgid = msgid
		} else {
			_, page, err = self.database.GetPageForRootMessage(ref)
		}
	}
	delposts = append(delposts, msgid)
	// get list of files to delete
	var delfiles []string
	for _, delmsg := range delposts {
		article := self.store.GetFilename(delmsg)
		delfiles = append(delfiles, article)
		// get attachments for post
		atts := self.database.GetPostAttachments(delmsg)
		if atts != nil {
			for _, att := range atts {
				img := self.store.AttachmentFilepath(att)
				thm := self.store.ThumbnailFilepath(att)
				delfiles = append(delfiles, img, thm)
			}
		}
	}
	// delete all files
	for _, f := range delfiles {
		log.Printf("delete file: %s", f)
		os.Remove(f)
	}

	if rootmsgid != "" {
		self.database.DeleteThread(rootmsgid)
	}

	for _, delmsg := range delposts {
		// delete article from post database
		err = self.database.DeleteArticle(delmsg)
		if err != nil {
			log.Println(err)
		}
		// ban article
		self.database.BanArticle(delmsg, "deleted by moderator")
	}
	regen(group, msgid, ref, int(page))
	return nil
}

func (self modEngine) AllowBan(pubkey string) bool {
	is_admin, _ := self.database.CheckAdminPubkey(pubkey)
	if is_admin {
		// admins can do whatever
		return true
	}
	return self.database.CheckModPubkeyGlobal(pubkey)
}

func (self modEngine) AllowDelete(pubkey, msgid string) (allow bool) {
	is_admin, _ := self.database.CheckAdminPubkey(pubkey)
	if is_admin {
		// admins can do whatever
		return true
	}
	if self.database.CheckModPubkeyGlobal(pubkey) {
		// globals can delete as they wish
		return true
	}
	// check for scoped permissions
	_, group, _, err := self.database.GetInfoForMessage(msgid)
	if err == nil && newsgroupValidFormat(group) {
		allow = self.database.CheckModPubkeyCanModGroup(pubkey, group)
	} else if err != nil {
		log.Println("db error in mod engine while checking permissions", err)
	}
	return
}

// run a mod engine logic mainloop
func RunModEngine(mod ModEngine, regen RegenFunc) {

	chnl := mod.MessageChan()
	for {
		msgid := <-chnl
		nntp := mod.LoadMessage(msgid)
		if nntp == nil {
			log.Println("failed to load mod message", msgid)
			continue
		}
		// sanity check
		if nntp.Newsgroup() == "ctl" {
			pubkey := nntp.Pubkey()
			for _, line := range strings.Split(nntp.Message(), "\n") {
				line = strings.Trim(line, "\r\t\n ")
				ev := ParseModEvent(line)
				action := ev.Action()
				if action == "delete" {
					msgid := ev.Target()
					if !ValidMessageID(msgid) {
						// invalid message-id
						log.Println("invalid message-id for mod delete", msgid, "from", pubkey)
						continue
					}
					// this is a delete action
					if mod.AllowDelete(pubkey, msgid) {
						err := mod.DeletePost(msgid, regen)
						if err != nil {
							log.Println(msgid, err)
						}
					} else {
						log.Printf("pubkey=%s will not delete %s not trusted", pubkey, msgid)
					}
				} else if action == "overchan-inet-ban" {
					// ban action
					target := ev.Target()
					if target[0] == '[' {
						// probably a literal ipv6 rangeban
						if mod.AllowBan(pubkey) {
							err := mod.BanAddress(target)
							if err != nil {
								log.Println("failed to do literal ipv6 range ban on", target, err)
							}
						} else {
							log.Println("ignoring literal ipv6 rangeban from", pubkey, "as they are not allowed to ban")
						}
						continue
					}
					parts := strings.Split(target, ":")
					if len(parts) == 3 {
						// encrypted ip
						encaddr, key := parts[0], parts[1]
						cidr := decAddr(encaddr, key)
						if cidr == "" {
							log.Println("failed to decrypt inet ban")
						} else if mod.AllowBan(pubkey) {
							err := mod.BanAddress(cidr)
							if err != nil {
								log.Println("failed to do range ban on", cidr, err)
							}
						} else {
							log.Println("ingoring encrypted-ip inet ban from", pubkey, "as they are not allowed to ban")
						}
					} else if len(parts) == 1 {
						// literal cidr
						cidr := parts[0]
						if mod.AllowBan(pubkey) {
							err := mod.BanAddress(cidr)
							if err != nil {
								log.Println("failed to do literal range ban on", cidr, err)
							}
						} else {
							log.Println("ingoring literal cidr range ban from", pubkey, "as they are not allowed to ban")
						}
					} else {
						log.Printf("invalid overchan-inet-ban: target=%s", target)
					}
				} else {
					log.Println("invalid mod action", action, "from", pubkey)
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>package model

import (
	"github.com/jinzhu/gorm"
)

// Project represends a backup project
type Project struct {
	gorm.Model
	Title string `gorm:"size:255"`
	Name  string `gorm:"size:255"`
}

// AddProject is the action to add a new project to the database
func AddProject(project Project) (err error) {

	// Start transaction
	tx := DB.Begin()

	if err := tx.Create(&project).Error; err != nil {
		tx.Rollback()
		return err
	}

	tx.Commit()

	return nil

}

// AllProjects return a collection of Project
func AllProjects() []Project {
	var projects []Project
	DB.Find(&projects)

	return projects
}

// GetProject by ID
func GetProject(id string) Project {
	var project Project
	DB.First(&project, id)
	return project
}
<commit_msg>📝 Add comments<commit_after>package model

import (
	"github.com/jinzhu/gorm"
)

// Project represends a backup project
type Project struct {
	gorm.Model
	Title string `gorm:"size:255"`
	Name  string `gorm:"size:255"`
}

// AddProject is the action to add a new project to the database
func AddProject(project Project) (err error) {

	// Start transaction
	tx := DB.Begin()

	// Rollback if error occurs
	if err := tx.Create(&project).Error; err != nil {
		tx.Rollback()
		return err
	}

	// Commit transaction
	tx.Commit()

	return nil

}

// AllProjects return a collection of Project
func AllProjects() []Project {
	var projects []Project
	DB.Find(&projects)

	return projects
}

// GetProject by ID
func GetProject(id string) Project {
	var project Project
	DB.First(&project, id)
	return project
}
<|endoftext|>


<commit_before>package backend

import (
	"context"
	"fmt"
	"log"
	"time"

	"github.com/buildkite/buildkite-agent-metrics/collector"
	"github.com/golang/protobuf/ptypes/timestamp"
	"google.golang.org/genproto/googleapis/api/label"

	monitoring "cloud.google.com/go/monitoring/apiv3"
	"google.golang.org/genproto/googleapis/api/metric"
	monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3"
)

const (
	metricTotalPrefix = "custom.googleapis.com/buildkite/total/%s"
	queueLabelKey     = "Queue"
	queueDescription  = "Queue Descriptor"
	totalMetricsQueue = "Total"
)

// StackDriverBackend sends metrics to GCP Stackdriver
type StackDriverBackend struct {
	projectID   string
	client      *monitoring.MetricClient
	metricTypes map[string]string
}

// NewStackDriverBackend returns a new StackDriverBackend for the specified project
func NewStackDriverBackend(gcpProjectID string) (*StackDriverBackend, error) {
	ctx := context.Background()
	c, err := monitoring.NewMetricClient(ctx)
	if err != nil {
		return nil, fmt.Errorf("[NewStackDriverBackend] could not create stackdriver client: %v", err)
	}

	return &StackDriverBackend{
		projectID:   gcpProjectID,
		client:      c,
		metricTypes: make(map[string]string),
	}, nil
}

// Collect metrics
func (sd *StackDriverBackend) Collect(r *collector.Result) error {
	ctx := context.Background()
	now := &timestamp.Timestamp{
		Seconds: time.Now().Unix(),
	}
	for name, value := range r.Totals {
		mt, present := sd.metricTypes[name]
		if !present {
			mt = fmt.Sprintf(metricTotalPrefix, name)
			metricReq := createCustomMetricRequest(&sd.projectID, &mt)
			_, err := sd.client.CreateMetricDescriptor(ctx, metricReq)
			if err != nil {
				retErr := fmt.Errorf("[Collect] could not create custom metric [%s]: %v", mt, err)
				log.Println(retErr)
				return retErr
			}
			log.Printf("[Collect] created custom metric [%s]", mt)
			sd.metricTypes[name] = mt
		}
		req := createTimeSeriesValueRequest(&sd.projectID, &mt, totalMetricsQueue, value, now)
		err := sd.client.CreateTimeSeries(ctx, req)
		if err != nil {
			retErr := fmt.Errorf("[Collect] could not write metric [%s] value [%d], %v ", mt, value, err)
			log.Println(retErr)
			return retErr
		}
	}

	for queue, counts := range r.Queues {
		for name, value := range counts {
			mt := fmt.Sprintf(metricTotalPrefix, name)
			req := createTimeSeriesValueRequest(&sd.projectID, &mt, queue, value, now)
			err := sd.client.CreateTimeSeries(ctx, req)
			if err != nil {
				retErr := fmt.Errorf("[Collect] could not write metric [%s] value [%d], %v ", mt, value, err)
				log.Println(retErr)
				return retErr
			}
		}
	}

	return nil
}

// createCustomMetricRequest creates a custom metric request as specified by the metric type.
func createCustomMetricRequest(projectID *string, metricType *string) *monitoringpb.CreateMetricDescriptorRequest {
	l := &label.LabelDescriptor{
		Key:         queueLabelKey,
		ValueType:   label.LabelDescriptor_STRING,
		Description: queueDescription,
	}
	labels := []*label.LabelDescriptor{l}
	md := &metric.MetricDescriptor{
		Name:        *metricType,
		Type:        *metricType,
		MetricKind:  metric.MetricDescriptor_GAUGE,
		ValueType:   metric.MetricDescriptor_INT64,
		Description: fmt.Sprintf("Buildkite metric: [%s]", *metricType),
		DisplayName: *metricType,
		Labels:      labels,
	}
	req := &monitoringpb.CreateMetricDescriptorRequest{
		Name:             "projects/" + *projectID,
		MetricDescriptor: md,
	}

	return req
}

// createTimeSeriesValueRequest creates a StackDriver value request for the specified metric
func createTimeSeriesValueRequest(projectID *string, metricType *string, queue string, value int, time *timestamp.Timestamp) *monitoringpb.CreateTimeSeriesRequest {
	req := &monitoringpb.CreateTimeSeriesRequest{
		Name: "projects/" + *projectID,
		TimeSeries: []*monitoringpb.TimeSeries{{
			Metric: &metric.Metric{
				Type:   *metricType,
				Labels: map[string]string{queueLabelKey: queue},
			},
			Points: []*monitoringpb.Point{{
				Interval: &monitoringpb.TimeInterval{
					StartTime: time,
					EndTime:   time,
				},
				Value: &monitoringpb.TypedValue{
					Value: &monitoringpb.TypedValue_Int64Value{
						Int64Value: int64(value),
					},
				},
			}},
		}},
	}
	return req
}
<commit_msg>Use org-specific metric names<commit_after>package backend

import (
	"context"
	"fmt"
	"log"
	"strings"
	"time"

	"github.com/buildkite/buildkite-agent-metrics/collector"
	"github.com/golang/protobuf/ptypes/timestamp"
	"google.golang.org/genproto/googleapis/api/label"

	monitoring "cloud.google.com/go/monitoring/apiv3"
	"google.golang.org/genproto/googleapis/api/metric"
	monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3"
)

const (
	metricName        = "custom.googleapis.com/buildkite/%s/%s"
	queueLabelKey     = "Queue"
	queueDescription  = "Queue Descriptor"
	totalMetricsQueue = "Total"
)

// Stackdriver does not allow dashes in metric names
var dashReplacer = strings.NewReplacer("-", "_")

// StackDriverBackend sends metrics to GCP Stackdriver
type StackDriverBackend struct {
	projectID   string
	client      *monitoring.MetricClient
	metricTypes map[string]string
}

// NewStackDriverBackend returns a new StackDriverBackend for the specified project
func NewStackDriverBackend(gcpProjectID string) (*StackDriverBackend, error) {
	ctx := context.Background()
	c, err := monitoring.NewMetricClient(ctx)
	if err != nil {
		return nil, fmt.Errorf("[NewStackDriverBackend] could not create stackdriver client: %v", err)
	}

	return &StackDriverBackend{
		projectID:   gcpProjectID,
		client:      c,
		metricTypes: make(map[string]string),
	}, nil
}

// Collect metrics
func (sd *StackDriverBackend) Collect(r *collector.Result) error {
	ctx := context.Background()
	now := &timestamp.Timestamp{
		Seconds: time.Now().Unix(),
	}
	orgName := dashReplacer.Replace(r.Org)
	for name, value := range r.Totals {
		mt, present := sd.metricTypes[name]
		if !present {
			mt = fmt.Sprintf(metricName, orgName, name)
			metricReq := createCustomMetricRequest(&sd.projectID, &mt)
			_, err := sd.client.CreateMetricDescriptor(ctx, metricReq)
			if err != nil {
				retErr := fmt.Errorf("[Collect] could not create custom metric [%s]: %v", mt, err)
				log.Println(retErr)
				return retErr
			}
			log.Printf("[Collect] created custom metric [%s]", mt)
			sd.metricTypes[name] = mt
		}
		req := createTimeSeriesValueRequest(&sd.projectID, &mt, totalMetricsQueue, value, now)
		err := sd.client.CreateTimeSeries(ctx, req)
		if err != nil {
			retErr := fmt.Errorf("[Collect] could not write metric [%s] value [%d], %v ", mt, value, err)
			log.Println(retErr)
			return retErr
		}
	}

	for queue, counts := range r.Queues {
		for name, value := range counts {
			mt := fmt.Sprintf(metricName, orgName, name)
			req := createTimeSeriesValueRequest(&sd.projectID, &mt, queue, value, now)
			err := sd.client.CreateTimeSeries(ctx, req)
			if err != nil {
				retErr := fmt.Errorf("[Collect] could not write metric [%s] value [%d], %v ", mt, value, err)
				log.Println(retErr)
				return retErr
			}
		}
	}

	return nil
}

// createCustomMetricRequest creates a custom metric request as specified by the metric type.
func createCustomMetricRequest(projectID *string, metricType *string) *monitoringpb.CreateMetricDescriptorRequest {
	l := &label.LabelDescriptor{
		Key:         queueLabelKey,
		ValueType:   label.LabelDescriptor_STRING,
		Description: queueDescription,
	}
	labels := []*label.LabelDescriptor{l}
	md := &metric.MetricDescriptor{
		Name:        *metricType,
		Type:        *metricType,
		MetricKind:  metric.MetricDescriptor_GAUGE,
		ValueType:   metric.MetricDescriptor_INT64,
		Description: fmt.Sprintf("Buildkite metric: [%s]", *metricType),
		DisplayName: *metricType,
		Labels:      labels,
	}
	req := &monitoringpb.CreateMetricDescriptorRequest{
		Name:             "projects/" + *projectID,
		MetricDescriptor: md,
	}

	return req
}

// createTimeSeriesValueRequest creates a StackDriver value request for the specified metric
func createTimeSeriesValueRequest(projectID *string, metricType *string, queue string, value int, time *timestamp.Timestamp) *monitoringpb.CreateTimeSeriesRequest {
	req := &monitoringpb.CreateTimeSeriesRequest{
		Name: "projects/" + *projectID,
		TimeSeries: []*monitoringpb.TimeSeries{{
			Metric: &metric.Metric{
				Type:   *metricType,
				Labels: map[string]string{queueLabelKey: queue},
			},
			Points: []*monitoringpb.Point{{
				Interval: &monitoringpb.TimeInterval{
					StartTime: time,
					EndTime:   time,
				},
				Value: &monitoringpb.TypedValue{
					Value: &monitoringpb.TypedValue_Int64Value{
						Int64Value: int64(value),
					},
				},
			}},
		}},
	}
	return req
}
<|endoftext|>


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

package models

import (
	"context"
	"database/sql"
	"errors"
	"fmt"

	"code.gitea.io/gitea/modules/setting"

	// Needed for the MySQL driver
	_ "github.com/go-sql-driver/mysql"
	"xorm.io/xorm"
	"xorm.io/xorm/names"
	"xorm.io/xorm/schemas"

	// Needed for the Postgresql driver
	_ "github.com/lib/pq"

	// Needed for the MSSSQL driver
	_ "github.com/denisenkom/go-mssqldb"
)

// Engine represents a xorm engine or session.
type Engine interface {
	Table(tableNameOrBean interface{}) *xorm.Session
	Count(...interface{}) (int64, error)
	Decr(column string, arg ...interface{}) *xorm.Session
	Delete(interface{}) (int64, error)
	Exec(...interface{}) (sql.Result, error)
	Find(interface{}, ...interface{}) error
	Get(interface{}) (bool, error)
	ID(interface{}) *xorm.Session
	In(string, ...interface{}) *xorm.Session
	Incr(column string, arg ...interface{}) *xorm.Session
	Insert(...interface{}) (int64, error)
	InsertOne(interface{}) (int64, error)
	Iterate(interface{}, xorm.IterFunc) error
	Join(joinOperator string, tablename interface{}, condition string, args ...interface{}) *xorm.Session
	SQL(interface{}, ...interface{}) *xorm.Session
	Where(interface{}, ...interface{}) *xorm.Session
	Asc(colNames ...string) *xorm.Session
	Limit(limit int, start ...int) *xorm.Session
	SumInt(bean interface{}, columnName string) (res int64, err error)
}

const (
	// When queries are broken down in parts because of the number
	// of parameters, attempt to break by this amount
	maxQueryParameters = 300
)

var (
	x      *xorm.Engine
	tables []interface{}

	// HasEngine specifies if we have a xorm.Engine
	HasEngine bool
)

func init() {
	tables = append(tables,
		new(User),
		new(PublicKey),
		new(AccessToken),
		new(Repository),
		new(DeployKey),
		new(Collaboration),
		new(Access),
		new(Upload),
		new(Watch),
		new(Star),
		new(Follow),
		new(Action),
		new(Issue),
		new(PullRequest),
		new(Comment),
		new(Attachment),
		new(Label),
		new(IssueLabel),
		new(Milestone),
		new(Mirror),
		new(Release),
		new(LoginSource),
		new(Webhook),
		new(HookTask),
		new(Team),
		new(OrgUser),
		new(TeamUser),
		new(TeamRepo),
		new(Notice),
		new(EmailAddress),
		new(Notification),
		new(IssueUser),
		new(LFSMetaObject),
		new(TwoFactor),
		new(GPGKey),
		new(GPGKeyImport),
		new(RepoUnit),
		new(RepoRedirect),
		new(ExternalLoginUser),
		new(ProtectedBranch),
		new(UserOpenID),
		new(IssueWatch),
		new(CommitStatus),
		new(Stopwatch),
		new(TrackedTime),
		new(DeletedBranch),
		new(RepoIndexerStatus),
		new(IssueDependency),
		new(LFSLock),
		new(Reaction),
		new(IssueAssignees),
		new(U2FRegistration),
		new(TeamUnit),
		new(Review),
		new(OAuth2Application),
		new(OAuth2AuthorizationCode),
		new(OAuth2Grant),
		new(Task),
		new(LanguageStat),
	)

	gonicNames := []string{"SSL", "UID"}
	for _, name := range gonicNames {
		names.LintGonicMapper[name] = true
	}
}

func getEngine() (*xorm.Engine, error) {
	connStr, err := setting.DBConnStr()
	if err != nil {
		return nil, err
	}

	engine, err := xorm.NewEngine(setting.Database.Type, connStr)
	if err != nil {
		return nil, err
	}
	engine.SetSchema(setting.Database.Schema)
	return engine, nil
}

// NewTestEngine sets a new test xorm.Engine
func NewTestEngine(x *xorm.Engine) (err error) {
	x, err = getEngine()
	if err != nil {
		return fmt.Errorf("Connect to database: %v", err)
	}

	x.SetMapper(names.GonicMapper{})
	x.SetLogger(NewXORMLogger(!setting.ProdMode))
	x.ShowSQL(!setting.ProdMode)
	return x.StoreEngine("InnoDB").Sync2(tables...)
}

// SetEngine sets the xorm.Engine
func SetEngine() (err error) {
	x, err = getEngine()
	if err != nil {
		return fmt.Errorf("Failed to connect to database: %v", err)
	}

	x.SetMapper(names.GonicMapper{})
	// WARNING: for serv command, MUST remove the output to os.stdout,
	// so use log file to instead print to stdout.
	x.SetLogger(NewXORMLogger(setting.Database.LogSQL))
	x.ShowSQL(setting.Database.LogSQL)
	x.SetMaxOpenConns(setting.Database.MaxOpenConns)
	x.SetMaxIdleConns(setting.Database.MaxIdleConns)
	x.SetConnMaxLifetime(setting.Database.ConnMaxLifetime)
	return nil
}

// NewEngine initializes a new xorm.Engine
func NewEngine(ctx context.Context, migrateFunc func(*xorm.Engine) error) (err error) {
	if err = SetEngine(); err != nil {
		return err
	}

	x.SetDefaultContext(ctx)

	if err = x.Ping(); err != nil {
		return err
	}

	if err = migrateFunc(x); err != nil {
		return fmt.Errorf("migrate: %v", err)
	}

	if err = x.StoreEngine("InnoDB").Sync2(tables...); err != nil {
		return fmt.Errorf("sync database struct error: %v", err)
	}

	return nil
}

// Statistic contains the database statistics
type Statistic struct {
	Counter struct {
		User, Org, PublicKey,
		Repo, Watch, Star, Action, Access,
		Issue, Comment, Oauth, Follow,
		Mirror, Release, LoginSource, Webhook,
		Milestone, Label, HookTask,
		Team, UpdateTask, Attachment int64
	}
}

// GetStatistic returns the database statistics
func GetStatistic() (stats Statistic) {
	stats.Counter.User = CountUsers()
	stats.Counter.Org = CountOrganizations()
	stats.Counter.PublicKey, _ = x.Count(new(PublicKey))
	stats.Counter.Repo = CountRepositories(true)
	stats.Counter.Watch, _ = x.Count(new(Watch))
	stats.Counter.Star, _ = x.Count(new(Star))
	stats.Counter.Action, _ = x.Count(new(Action))
	stats.Counter.Access, _ = x.Count(new(Access))
	stats.Counter.Issue, _ = x.Count(new(Issue))
	stats.Counter.Comment, _ = x.Count(new(Comment))
	stats.Counter.Oauth = 0
	stats.Counter.Follow, _ = x.Count(new(Follow))
	stats.Counter.Mirror, _ = x.Count(new(Mirror))
	stats.Counter.Release, _ = x.Count(new(Release))
	stats.Counter.LoginSource = CountLoginSources()
	stats.Counter.Webhook, _ = x.Count(new(Webhook))
	stats.Counter.Milestone, _ = x.Count(new(Milestone))
	stats.Counter.Label, _ = x.Count(new(Label))
	stats.Counter.HookTask, _ = x.Count(new(HookTask))
	stats.Counter.Team, _ = x.Count(new(Team))
	stats.Counter.Attachment, _ = x.Count(new(Attachment))
	return
}

// Ping tests if database is alive
func Ping() error {
	if x != nil {
		return x.Ping()
	}
	return errors.New("database not configured")
}

// DumpDatabase dumps all data from database according the special database SQL syntax to file system.
func DumpDatabase(filePath string, dbType string) error {
	var tbs []*schemas.Table
	for _, t := range tables {
		t, err := x.TableInfo(t)
		if err != nil {
			return err
		}
		tbs = append(tbs, t)
	}
	if len(dbType) > 0 {
		return x.DumpTablesToFile(tbs, filePath, schemas.DBType(dbType))
	}
	return x.DumpTablesToFile(tbs, filePath)
}

// MaxBatchInsertSize returns the table's max batch insert size
func MaxBatchInsertSize(bean interface{}) int {
	t, err := x.TableInfo(bean)
	if err != nil {
		return 50
	}
	return 999 / len(t.ColumnsSeq())
}

// Count returns records number according struct's fields as database query conditions
func Count(bean interface{}) (int64, error) {
	return x.Count(bean)
}

// IsTableNotEmpty returns true if table has at least one record
func IsTableNotEmpty(tableName string) (bool, error) {
	return x.Table(tableName).Exist()
}

// DeleteAllRecords will delete all the records of this table
func DeleteAllRecords(tableName string) error {
	_, err := x.Exec(fmt.Sprintf("DELETE FROM %s", tableName))
	return err
}

// GetMaxID will return max id of the table
func GetMaxID(beanOrTableName interface{}) (maxID int64, err error) {
	_, err = x.Select("MAX(id)").Table(beanOrTableName).Get(&maxID)
	return
}

// FindByMaxID filled results as the condition from database
func FindByMaxID(maxID int64, limit int, results interface{}) error {
	return x.Where("id <= ?", maxID).
		OrderBy("id DESC").
		Limit(limit).
		Find(results)
}
<commit_msg>Set MySQL rowtype to dynamic for new tables (#10833)<commit_after>// Copyright 2014 The Gogs Authors. All rights reserved.
// Copyright 2018 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package models

import (
	"context"
	"database/sql"
	"errors"
	"fmt"

	"code.gitea.io/gitea/modules/setting"

	// Needed for the MySQL driver
	_ "github.com/go-sql-driver/mysql"
	"xorm.io/xorm"
	"xorm.io/xorm/names"
	"xorm.io/xorm/schemas"

	// Needed for the Postgresql driver
	_ "github.com/lib/pq"

	// Needed for the MSSSQL driver
	_ "github.com/denisenkom/go-mssqldb"
)

// Engine represents a xorm engine or session.
type Engine interface {
	Table(tableNameOrBean interface{}) *xorm.Session
	Count(...interface{}) (int64, error)
	Decr(column string, arg ...interface{}) *xorm.Session
	Delete(interface{}) (int64, error)
	Exec(...interface{}) (sql.Result, error)
	Find(interface{}, ...interface{}) error
	Get(interface{}) (bool, error)
	ID(interface{}) *xorm.Session
	In(string, ...interface{}) *xorm.Session
	Incr(column string, arg ...interface{}) *xorm.Session
	Insert(...interface{}) (int64, error)
	InsertOne(interface{}) (int64, error)
	Iterate(interface{}, xorm.IterFunc) error
	Join(joinOperator string, tablename interface{}, condition string, args ...interface{}) *xorm.Session
	SQL(interface{}, ...interface{}) *xorm.Session
	Where(interface{}, ...interface{}) *xorm.Session
	Asc(colNames ...string) *xorm.Session
	Limit(limit int, start ...int) *xorm.Session
	SumInt(bean interface{}, columnName string) (res int64, err error)
}

const (
	// When queries are broken down in parts because of the number
	// of parameters, attempt to break by this amount
	maxQueryParameters = 300
)

var (
	x      *xorm.Engine
	tables []interface{}

	// HasEngine specifies if we have a xorm.Engine
	HasEngine bool
)

func init() {
	tables = append(tables,
		new(User),
		new(PublicKey),
		new(AccessToken),
		new(Repository),
		new(DeployKey),
		new(Collaboration),
		new(Access),
		new(Upload),
		new(Watch),
		new(Star),
		new(Follow),
		new(Action),
		new(Issue),
		new(PullRequest),
		new(Comment),
		new(Attachment),
		new(Label),
		new(IssueLabel),
		new(Milestone),
		new(Mirror),
		new(Release),
		new(LoginSource),
		new(Webhook),
		new(HookTask),
		new(Team),
		new(OrgUser),
		new(TeamUser),
		new(TeamRepo),
		new(Notice),
		new(EmailAddress),
		new(Notification),
		new(IssueUser),
		new(LFSMetaObject),
		new(TwoFactor),
		new(GPGKey),
		new(GPGKeyImport),
		new(RepoUnit),
		new(RepoRedirect),
		new(ExternalLoginUser),
		new(ProtectedBranch),
		new(UserOpenID),
		new(IssueWatch),
		new(CommitStatus),
		new(Stopwatch),
		new(TrackedTime),
		new(DeletedBranch),
		new(RepoIndexerStatus),
		new(IssueDependency),
		new(LFSLock),
		new(Reaction),
		new(IssueAssignees),
		new(U2FRegistration),
		new(TeamUnit),
		new(Review),
		new(OAuth2Application),
		new(OAuth2AuthorizationCode),
		new(OAuth2Grant),
		new(Task),
		new(LanguageStat),
	)

	gonicNames := []string{"SSL", "UID"}
	for _, name := range gonicNames {
		names.LintGonicMapper[name] = true
	}
}

func getEngine() (*xorm.Engine, error) {
	connStr, err := setting.DBConnStr()
	if err != nil {
		return nil, err
	}

	engine, err := xorm.NewEngine(setting.Database.Type, connStr)
	if err != nil {
		return nil, err
	}
	if setting.Database.Type == "mysql" {
		engine.Dialect().SetParams(map[string]string{"rowFormat": "DYNAMIC"})
	}
	engine.SetSchema(setting.Database.Schema)
	return engine, nil
}

// NewTestEngine sets a new test xorm.Engine
func NewTestEngine(x *xorm.Engine) (err error) {
	x, err = getEngine()
	if err != nil {
		return fmt.Errorf("Connect to database: %v", err)
	}

	x.SetMapper(names.GonicMapper{})
	x.SetLogger(NewXORMLogger(!setting.ProdMode))
	x.ShowSQL(!setting.ProdMode)
	return x.StoreEngine("InnoDB").Sync2(tables...)
}

// SetEngine sets the xorm.Engine
func SetEngine() (err error) {
	x, err = getEngine()
	if err != nil {
		return fmt.Errorf("Failed to connect to database: %v", err)
	}

	x.SetMapper(names.GonicMapper{})
	// WARNING: for serv command, MUST remove the output to os.stdout,
	// so use log file to instead print to stdout.
	x.SetLogger(NewXORMLogger(setting.Database.LogSQL))
	x.ShowSQL(setting.Database.LogSQL)
	x.SetMaxOpenConns(setting.Database.MaxOpenConns)
	x.SetMaxIdleConns(setting.Database.MaxIdleConns)
	x.SetConnMaxLifetime(setting.Database.ConnMaxLifetime)
	return nil
}

// NewEngine initializes a new xorm.Engine
func NewEngine(ctx context.Context, migrateFunc func(*xorm.Engine) error) (err error) {
	if err = SetEngine(); err != nil {
		return err
	}

	x.SetDefaultContext(ctx)

	if err = x.Ping(); err != nil {
		return err
	}

	if err = migrateFunc(x); err != nil {
		return fmt.Errorf("migrate: %v", err)
	}

	if err = x.StoreEngine("InnoDB").Sync2(tables...); err != nil {
		return fmt.Errorf("sync database struct error: %v", err)
	}

	return nil
}

// Statistic contains the database statistics
type Statistic struct {
	Counter struct {
		User, Org, PublicKey,
		Repo, Watch, Star, Action, Access,
		Issue, Comment, Oauth, Follow,
		Mirror, Release, LoginSource, Webhook,
		Milestone, Label, HookTask,
		Team, UpdateTask, Attachment int64
	}
}

// GetStatistic returns the database statistics
func GetStatistic() (stats Statistic) {
	stats.Counter.User = CountUsers()
	stats.Counter.Org = CountOrganizations()
	stats.Counter.PublicKey, _ = x.Count(new(PublicKey))
	stats.Counter.Repo = CountRepositories(true)
	stats.Counter.Watch, _ = x.Count(new(Watch))
	stats.Counter.Star, _ = x.Count(new(Star))
	stats.Counter.Action, _ = x.Count(new(Action))
	stats.Counter.Access, _ = x.Count(new(Access))
	stats.Counter.Issue, _ = x.Count(new(Issue))
	stats.Counter.Comment, _ = x.Count(new(Comment))
	stats.Counter.Oauth = 0
	stats.Counter.Follow, _ = x.Count(new(Follow))
	stats.Counter.Mirror, _ = x.Count(new(Mirror))
	stats.Counter.Release, _ = x.Count(new(Release))
	stats.Counter.LoginSource = CountLoginSources()
	stats.Counter.Webhook, _ = x.Count(new(Webhook))
	stats.Counter.Milestone, _ = x.Count(new(Milestone))
	stats.Counter.Label, _ = x.Count(new(Label))
	stats.Counter.HookTask, _ = x.Count(new(HookTask))
	stats.Counter.Team, _ = x.Count(new(Team))
	stats.Counter.Attachment, _ = x.Count(new(Attachment))
	return
}

// Ping tests if database is alive
func Ping() error {
	if x != nil {
		return x.Ping()
	}
	return errors.New("database not configured")
}

// DumpDatabase dumps all data from database according the special database SQL syntax to file system.
func DumpDatabase(filePath string, dbType string) error {
	var tbs []*schemas.Table
	for _, t := range tables {
		t, err := x.TableInfo(t)
		if err != nil {
			return err
		}
		tbs = append(tbs, t)
	}
	if len(dbType) > 0 {
		return x.DumpTablesToFile(tbs, filePath, schemas.DBType(dbType))
	}
	return x.DumpTablesToFile(tbs, filePath)
}

// MaxBatchInsertSize returns the table's max batch insert size
func MaxBatchInsertSize(bean interface{}) int {
	t, err := x.TableInfo(bean)
	if err != nil {
		return 50
	}
	return 999 / len(t.ColumnsSeq())
}

// Count returns records number according struct's fields as database query conditions
func Count(bean interface{}) (int64, error) {
	return x.Count(bean)
}

// IsTableNotEmpty returns true if table has at least one record
func IsTableNotEmpty(tableName string) (bool, error) {
	return x.Table(tableName).Exist()
}

// DeleteAllRecords will delete all the records of this table
func DeleteAllRecords(tableName string) error {
	_, err := x.Exec(fmt.Sprintf("DELETE FROM %s", tableName))
	return err
}

// GetMaxID will return max id of the table
func GetMaxID(beanOrTableName interface{}) (maxID int64, err error) {
	_, err = x.Select("MAX(id)").Table(beanOrTableName).Get(&maxID)
	return
}

// FindByMaxID filled results as the condition from database
func FindByMaxID(maxID int64, limit int, results interface{}) error {
	return x.Where("id <= ?", maxID).
		OrderBy("id DESC").
		Limit(limit).
		Find(results)
}
<|endoftext|>


<commit_before>package models

import (
	"database/sql"
	"github.com/go-sql-driver/mysql"
	"time"

	"github.com/eirka/eirka-libs/db"
	e "github.com/eirka/eirka-libs/errors"
)

// UserModel holds the parameters from the request and also the key for the cache
type UserModel struct {
	User   uint
	Ib     uint
	Result UserType
}

// UserType is the top level of the JSON response
type UserType struct {
	Body UserInfo `json:"user"`
}

// UserInfo holds all the user metadata
type UserInfo struct {
	Id         uint      `json:"id"`
	Name       string    `json:"name"`
	Email      string    `json:"email"`
	Group      uint      `json:"group"`
	LastActive time.Time `json:"last_active"`
}

// Get will gather the information from the database and return it as JSON serialized data
func (i *UserModel) Get() (err error) {

	if i.Ib == 0 || i.User == 0 || i.User == 1 {
		return e.ErrNotFound
	}

	// Initialize response header
	response := UserType{}

	r := UserInfo{}

	// set our user id
	r.Id = i.User

	// Get Database handle
	dbase, err := db.GetDb()
	if err != nil {
		return
	}

	// get data from users table
	err = dbase.QueryRow(`SELECT COALESCE((SELECT MAX(role_id) FROM user_ib_role_map WHERE user_ib_role_map.user_id = users.user_id AND ib_id = ?),user_role_map.role_id) as role,
    user_name,user_email FROM users
    INNER JOIN user_role_map ON (user_role_map.user_id = users.user_id)
    WHERE users.user_id = ?`, i.Ib, i.User).Scan(&r.Group, &r.Name, &r.Email)
	if err != nil {
		return
	}

	var lastactive mysql.NullTime

	// get the time the user was last active
	err = dbase.QueryRow(`SELECT request_time FROM analytics
    WHERE user_id = ? AND ib_id = ? ORDER BY analytics_id DESC LIMIT 1`, i.User, i.Ib).Scan(&lastactive)
	if err != sql.ErrNoRows && err != nil {
		return
	}

	// set the last active time
	if lastactive.Valid {
		r.LastActive = lastactive.Time
	} else {
		r.LastActive = time.Now()
	}

	response.Body = r

	// This is the data we will serialize
	i.Result = response

	return

}
<commit_msg>add last active time to whois<commit_after>package models

import (
	"database/sql"
	"github.com/go-sql-driver/mysql"
	"time"

	"github.com/eirka/eirka-libs/db"
	e "github.com/eirka/eirka-libs/errors"
)

// UserModel holds the parameters from the request and also the key for the cache
type UserModel struct {
	User   uint
	Ib     uint
	Result UserType
}

// UserType is the top level of the JSON response
type UserType struct {
	Body UserInfo `json:"user"`
}

// UserInfo holds all the user metadata
type UserInfo struct {
	Id         uint      `json:"id"`
	Name       string    `json:"name"`
	Email      string    `json:"email"`
	Group      uint      `json:"group"`
	LastActive time.Time `json:"last_active"`
}

// Get will gather the information from the database and return it as JSON serialized data
func (i *UserModel) Get() (err error) {

	if i.Ib == 0 || i.User == 0 || i.User == 1 {
		return e.ErrNotFound
	}

	// Initialize response header
	response := UserType{}

	r := UserInfo{}

	// set our user id
	r.Id = i.User

	// Get Database handle
	dbase, err := db.GetDb()
	if err != nil {
		return
	}

	// get data from users table
	err = dbase.QueryRow(`SELECT COALESCE((SELECT MAX(role_id) FROM user_ib_role_map WHERE user_ib_role_map.user_id = users.user_id AND ib_id = ?),user_role_map.role_id) as role,
    user_name,user_email FROM users
    INNER JOIN user_role_map ON (user_role_map.user_id = users.user_id)
    WHERE users.user_id = ?`, i.Ib, i.User).Scan(&r.Group, &r.Name, &r.Email)
	if err != nil {
		return
	}

	var lastactive mysql.NullTime

	// get the time the user was last active
	err = dbase.QueryRow(`SELECT request_time FROM analytics
    WHERE user_id = ? AND ib_id = ? ORDER BY analytics_id DESC LIMIT 1`, i.User, i.Ib).Scan(&lastactive)
	// we dont care if there were no rows
	if err == sql.ErrNoRows {
		err = nil
	} else if err != nil {
		return
	}

	// set the last active time
	if lastactive.Valid {
		r.LastActive = lastactive.Time
	} else {
		r.LastActive = time.Now()
	}

	response.Body = r

	// This is the data we will serialize
	i.Result = response

	return

}
<|endoftext|>


<commit_before>// +build us_902_928

package band

import (
	"fmt"
	"time"
)

func init() {
	// initialize uplink channel 0 - 63
	for i := 0; i < 64; i++ {
		UplinkChannelConfiguration[i] = Channel{
			Frequency: 902300000 + (i * 200000),
			DataRates: []int{0, 1, 2, 3},
		}
	}

	// initialize uplink channel 64 - 71
	for i := 0; i < 8; i++ {
		UplinkChannelConfiguration[i+64] = Channel{
			Frequency: 903000000 + (i * 1600000),
			DataRates: []int{4},
		}
	}

	// initialize downlink channel 0 - 7
	for i := 0; i < 8; i++ {
		DownlinkChannelConfiguration[i] = Channel{
			Frequency: 923300000 + (i * 600000),
			DataRates: []int{10, 11, 12, 13},
		}
	}
}

// Name defines the name of the band
const Name = "US 902-928"

// DataRateConfiguration defines the available data rates
var DataRateConfiguration = [...]DataRate{
	{Modulation: LoRaModulation, SpreadFactor: 12, Bandwidth: 125},
	{Modulation: LoRaModulation, SpreadFactor: 9, Bandwidth: 125},
	{Modulation: LoRaModulation, SpreadFactor: 8, Bandwidth: 125},
	{Modulation: LoRaModulation, SpreadFactor: 7, Bandwidth: 125},
	{Modulation: LoRaModulation, SpreadFactor: 8, Bandwidth: 500},
	{}, // RFU
	{}, // RFU
	{}, // RFU
	{Modulation: LoRaModulation, SpreadFactor: 12, Bandwidth: 500},
	{Modulation: LoRaModulation, SpreadFactor: 11, Bandwidth: 500},
	{Modulation: LoRaModulation, SpreadFactor: 10, Bandwidth: 500},
	{Modulation: LoRaModulation, SpreadFactor: 9, Bandwidth: 500},
	{Modulation: LoRaModulation, SpreadFactor: 8, Bandwidth: 500},
	{Modulation: LoRaModulation, SpreadFactor: 7, Bandwidth: 500},
	{}, // RFU
	{}, // RFU
}

// DefaultTXPower defines the default TX power in dBm
const DefaultTXPower = 20

// CFListAllowed defines if the optional JoinAccept CFList is allowed for this band
const CFListAllowed = false

// TXPowerConfiguration defines the available TXPower settings in dBm
var TXPowerConfiguration = [...]int{
	30,
	28,
	26,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	10,
	0,
	0,
	0,
	0,
	0,
}

// MACPayloadSizeConfiguration defines the maximum payload size for each data rate
var MACPayloadSizeConfiguration = [...]MaxPayloadSize{
	{M: 19, N: 11},
	{M: 61, N: 53},
	{M: 137, N: 129},
	{M: 250, N: 242},
	{M: 250, N: 242},
	{}, // Not defined
	{}, // Not defined
	{}, // Not defined
	{M: 41, N: 33},
	{M: 117, N: 109},
	{M: 230, N: 222},
	{M: 230, N: 222},
	{M: 230, N: 222},
	{M: 230, N: 222},
	{}, // Not defined
	{}, // Not defined
}

// RX1DROffsetConfiguration defines the available RX1DROffset configurations
// per data rate.
var RX1DROffsetConfiguration = [...][4]int{
	{10, 9, 8, 8},
	{11, 10, 9, 8},
	{12, 11, 10, 9},
	{13, 12, 11, 10},
	{13, 13, 12, 11},
	{}, // Not defined
	{}, // Not defined
	{}, // Not defined
	{8, 8, 8, 8},
	{9, 8, 8, 8},
	{10, 9, 8, 8},
	{11, 10, 9, 8},
	{12, 11, 10, 9},
	{13, 12, 11, 10},
}

// RX2Frequency defines the RX2 receive window frequency to use (in Hz)
const RX2Frequency = 923300000

// RX2DataRate defines the RX2 receive window data rate to use
const RX2DataRate = 8

// UplinkChannelConfiguration defines the (default) available uplink channels.
var UplinkChannelConfiguration = [72]Channel{}

// DownlinkChannelConfiguration defines the (default) available downlink channels.
var DownlinkChannelConfiguration = [8]Channel{}

// GetRX1Frequency returns the frequency to be used for RX1 given
// the uplink frequency and data rate.
func GetRX1Frequency(frequency, dataRate int) (int, error) {
	if dataRate > len(DataRateConfiguration) {
		return 0, fmt.Errorf("lorawan/band: given data rate: %d does not exist", dataRate)
	}

	chanNum, err := getChannelNumber(frequency, dataRate)
	if err != nil {
		return 0, err
	}

	return DownlinkChannelConfiguration[chanNum%8].Frequency, nil
}

func getChannelNumber(frequency, dataRate int) (int, error) {
	for chanNum, channel := range UplinkChannelConfiguration {
		if frequency == channel.Frequency {
			for _, dr := range channel.DataRates {
				if dr == dataRate {
					return chanNum, nil
				}
			}
		}
	}

	return 0, fmt.Errorf("lorawan/band: could not get channel number for frequency: %d, data rate: %d", frequency, dataRate)
}

// Default settings for this band
const (
	ReceiveDelay1    time.Duration = 1
	ReceiveDelay2    time.Duration = 2
	JoinAcceptDelay1 time.Duration = 5
	JoinAcceptDelay2 time.Duration = 6
	MaxFCntGap       uint32        = 16384
	ADRAckLimit                    = 64
	ADRAckDelay                    = 32
	AckTimeoutMin    time.Duration = 1
	AckTimeoutMax    time.Duration = 3
)
<commit_msg>Fix TXPowerConfiguration.<commit_after>// +build us_902_928

package band

import (
	"fmt"
	"time"
)

func init() {
	// initialize uplink channel 0 - 63
	for i := 0; i < 64; i++ {
		UplinkChannelConfiguration[i] = Channel{
			Frequency: 902300000 + (i * 200000),
			DataRates: []int{0, 1, 2, 3},
		}
	}

	// initialize uplink channel 64 - 71
	for i := 0; i < 8; i++ {
		UplinkChannelConfiguration[i+64] = Channel{
			Frequency: 903000000 + (i * 1600000),
			DataRates: []int{4},
		}
	}

	// initialize downlink channel 0 - 7
	for i := 0; i < 8; i++ {
		DownlinkChannelConfiguration[i] = Channel{
			Frequency: 923300000 + (i * 600000),
			DataRates: []int{10, 11, 12, 13},
		}
	}
}

// Name defines the name of the band
const Name = "US 902-928"

// DataRateConfiguration defines the available data rates
var DataRateConfiguration = [...]DataRate{
	{Modulation: LoRaModulation, SpreadFactor: 12, Bandwidth: 125},
	{Modulation: LoRaModulation, SpreadFactor: 9, Bandwidth: 125},
	{Modulation: LoRaModulation, SpreadFactor: 8, Bandwidth: 125},
	{Modulation: LoRaModulation, SpreadFactor: 7, Bandwidth: 125},
	{Modulation: LoRaModulation, SpreadFactor: 8, Bandwidth: 500},
	{}, // RFU
	{}, // RFU
	{}, // RFU
	{Modulation: LoRaModulation, SpreadFactor: 12, Bandwidth: 500},
	{Modulation: LoRaModulation, SpreadFactor: 11, Bandwidth: 500},
	{Modulation: LoRaModulation, SpreadFactor: 10, Bandwidth: 500},
	{Modulation: LoRaModulation, SpreadFactor: 9, Bandwidth: 500},
	{Modulation: LoRaModulation, SpreadFactor: 8, Bandwidth: 500},
	{Modulation: LoRaModulation, SpreadFactor: 7, Bandwidth: 500},
	{}, // RFU
	{}, // RFU
}

// DefaultTXPower defines the default TX power in dBm
const DefaultTXPower = 20

// CFListAllowed defines if the optional JoinAccept CFList is allowed for this band
const CFListAllowed = false

// TXPowerConfiguration defines the available TXPower settings in dBm
var TXPowerConfiguration = [...]int{
	30,
	28,
	26,
	24,
	22,
	20,
	18,
	16,
	14,
	12,
	10,
	0,
	0,
	0,
	0,
	0,
}

// MACPayloadSizeConfiguration defines the maximum payload size for each data rate
var MACPayloadSizeConfiguration = [...]MaxPayloadSize{
	{M: 19, N: 11},
	{M: 61, N: 53},
	{M: 137, N: 129},
	{M: 250, N: 242},
	{M: 250, N: 242},
	{}, // Not defined
	{}, // Not defined
	{}, // Not defined
	{M: 41, N: 33},
	{M: 117, N: 109},
	{M: 230, N: 222},
	{M: 230, N: 222},
	{M: 230, N: 222},
	{M: 230, N: 222},
	{}, // Not defined
	{}, // Not defined
}

// RX1DROffsetConfiguration defines the available RX1DROffset configurations
// per data rate.
var RX1DROffsetConfiguration = [...][4]int{
	{10, 9, 8, 8},
	{11, 10, 9, 8},
	{12, 11, 10, 9},
	{13, 12, 11, 10},
	{13, 13, 12, 11},
	{}, // Not defined
	{}, // Not defined
	{}, // Not defined
	{8, 8, 8, 8},
	{9, 8, 8, 8},
	{10, 9, 8, 8},
	{11, 10, 9, 8},
	{12, 11, 10, 9},
	{13, 12, 11, 10},
}

// RX2Frequency defines the RX2 receive window frequency to use (in Hz)
const RX2Frequency = 923300000

// RX2DataRate defines the RX2 receive window data rate to use
const RX2DataRate = 8

// UplinkChannelConfiguration defines the (default) available uplink channels.
var UplinkChannelConfiguration = [72]Channel{}

// DownlinkChannelConfiguration defines the (default) available downlink channels.
var DownlinkChannelConfiguration = [8]Channel{}

// GetRX1Frequency returns the frequency to be used for RX1 given
// the uplink frequency and data rate.
func GetRX1Frequency(frequency, dataRate int) (int, error) {
	if dataRate > len(DataRateConfiguration) {
		return 0, fmt.Errorf("lorawan/band: given data rate: %d does not exist", dataRate)
	}

	chanNum, err := getChannelNumber(frequency, dataRate)
	if err != nil {
		return 0, err
	}

	return DownlinkChannelConfiguration[chanNum%8].Frequency, nil
}

func getChannelNumber(frequency, dataRate int) (int, error) {
	for chanNum, channel := range UplinkChannelConfiguration {
		if frequency == channel.Frequency {
			for _, dr := range channel.DataRates {
				if dr == dataRate {
					return chanNum, nil
				}
			}
		}
	}

	return 0, fmt.Errorf("lorawan/band: could not get channel number for frequency: %d, data rate: %d", frequency, dataRate)
}

// Default settings for this band
const (
	ReceiveDelay1    time.Duration = 1
	ReceiveDelay2    time.Duration = 2
	JoinAcceptDelay1 time.Duration = 5
	JoinAcceptDelay2 time.Duration = 6
	MaxFCntGap       uint32        = 16384
	ADRAckLimit                    = 64
	ADRAckDelay                    = 32
	AckTimeoutMin    time.Duration = 1
	AckTimeoutMax    time.Duration = 3
)
<|endoftext|>


<commit_before>package wavs

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strings"
	"time"

	"github.com/gordonklaus/portaudio"
	log "github.com/sirupsen/logrus"
	"github.com/youpy/go-wav"
)

const (
	WAVS = "./wavs"
	BUF  = 128
)

type Wavs struct {
	wavs    map[string]*wavFile
	stream  *portaudio.Stream
	stopAll chan struct{}
}

type wavFile struct {
	name      string
	buf       []float32
	length    int
	active    chan struct{}
	remaining int
}

func InitWavs() *Wavs {
	err := portaudio.Initialize()
	if err != nil {
		panic(err)
	}

	files, _ := ioutil.ReadDir(WAVS)

	wavs := &Wavs{
		wavs:    map[string]*wavFile{},
		stopAll: make(chan struct{}),
	}

	for _, f := range files {
		if strings.HasSuffix(f.Name(), ".wav") {
			wavs.wavs[f.Name()] = initWav(f)
		}
	}

	wavs.stream, err = portaudio.OpenDefaultStream(0, 1, 44100, BUF, wavs.cb)
	if err != nil {
		panic(err)
	}
	err = wavs.stream.Start()
	if err != nil {
		panic(err)
	}

	return wavs
}

func initWav(f os.FileInfo) *wavFile {
	file, _ := os.Open(WAVS + "/" + f.Name())
	reader := wav.NewReader(file)
	defer file.Close()

	buf := make([]float32, f.Size())
	loc := 0
	for {
		samples, err := reader.ReadSamples()
		if err != nil {
			if err == io.EOF {
				break
			} else {
				panic(fmt.Sprintf("ReadSamples failed on file %s with error: %s", f.Name(), err))
			}
		}

		for _, sample := range samples {
			buf[loc] = float32(reader.FloatValue(sample, 0))
			loc += 1
		}
	}

	w := wavFile{
		name:   f.Name(),
		buf:    make([]float32, loc),
		length: loc,
		active: make(chan struct{}),
	}
	copy(w.buf, buf[:])

	return &w
}

func (w *Wavs) cb(output [][]float32) {
	for _, wv := range w.wavs {
		select {
		case <-wv.active:
			wv.remaining = wv.length
		default:
		}
	}

	select {
	case <-w.stopAll:
		for _, wv := range w.wavs {
			wv.remaining = 0
		}
	default:
	}

	out := make([]float32, BUF)
	for _, wv := range w.wavs {
		for i := 0; i < BUF; i++ {
			if wv.remaining > i {
				// TODO: do this correctly
				// add dynamic range compressor
				out[i] += wv.buf[wv.length-wv.remaining+i]
			}
		}
		wv.remaining -= BUF
	}
	copy(output[0], out)
}

func (w *Wavs) Play(name string) {
	wav, ok := w.wavs[name]
	if !ok {
		log.Debugf("Unknown wav file: %s", name)
		return
	}

	wav.active <- struct{}{}
}

func (w *Wavs) StopAll() {
	w.stopAll <- struct{}{}
}

func (w *Wavs) Durations() map[string]time.Duration {
	durations := map[string]time.Duration{}

	for name, wav := range w.wavs {
		durations[name] = time.Duration(wav.length*1000/44100) * time.Millisecond
	}

	return durations
}

func (w *Wavs) Close() {
	w.stream.Stop()
	w.stream.Close()
	portaudio.Terminate()

	log.Debugf("Wavs Closed")
}
<commit_msg>fix 32-bit overflow when calculating wave file duration<commit_after>package wavs

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strings"
	"time"

	"github.com/gordonklaus/portaudio"
	log "github.com/sirupsen/logrus"
	"github.com/youpy/go-wav"
)

const (
	WAVS = "./wavs"
	BUF  = 128
)

type Wavs struct {
	wavs    map[string]*wavFile
	stream  *portaudio.Stream
	stopAll chan struct{}
}

type wavFile struct {
	name      string
	buf       []float32
	length    int
	active    chan struct{}
	remaining int
}

func InitWavs() *Wavs {
	err := portaudio.Initialize()
	if err != nil {
		panic(err)
	}

	files, _ := ioutil.ReadDir(WAVS)

	wavs := &Wavs{
		wavs:    map[string]*wavFile{},
		stopAll: make(chan struct{}),
	}

	for _, f := range files {
		if strings.HasSuffix(f.Name(), ".wav") {
			wavs.wavs[f.Name()] = initWav(f)
		}
	}

	wavs.stream, err = portaudio.OpenDefaultStream(0, 1, 44100, BUF, wavs.cb)
	if err != nil {
		panic(err)
	}
	err = wavs.stream.Start()
	if err != nil {
		panic(err)
	}

	return wavs
}

func initWav(f os.FileInfo) *wavFile {
	file, _ := os.Open(WAVS + "/" + f.Name())
	reader := wav.NewReader(file)
	defer file.Close()

	buf := make([]float32, f.Size())
	loc := 0
	for {
		samples, err := reader.ReadSamples()
		if err != nil {
			if err == io.EOF {
				break
			} else {
				panic(fmt.Sprintf("ReadSamples failed on file %s with error: %s", f.Name(), err))
			}
		}

		for _, sample := range samples {
			buf[loc] = float32(reader.FloatValue(sample, 0))
			loc += 1
		}
	}

	w := wavFile{
		name:   f.Name(),
		buf:    make([]float32, loc),
		length: loc,
		active: make(chan struct{}),
	}
	copy(w.buf, buf[:])

	return &w
}

func (w *Wavs) cb(output [][]float32) {
	for _, wv := range w.wavs {
		select {
		case <-wv.active:
			wv.remaining = wv.length
		default:
		}
	}

	select {
	case <-w.stopAll:
		for _, wv := range w.wavs {
			wv.remaining = 0
		}
	default:
	}

	out := make([]float32, BUF)
	for _, wv := range w.wavs {
		for i := 0; i < BUF; i++ {
			if wv.remaining > i {
				// TODO: do this correctly
				// add dynamic range compressor
				out[i] += wv.buf[wv.length-wv.remaining+i]
			}
		}
		wv.remaining -= BUF
	}
	copy(output[0], out)
}

func (w *Wavs) Play(name string) {
	wav, ok := w.wavs[name]
	if !ok {
		log.Debugf("Unknown wav file: %s", name)
		return
	}

	wav.active <- struct{}{}
}

func (w *Wavs) StopAll() {
	w.stopAll <- struct{}{}
}

func (w *Wavs) Durations() map[string]time.Duration {
	durations := map[string]time.Duration{}

	for name, wav := range w.wavs {
		durations[name] = time.Duration(float64(wav.length)/44.1) * time.Millisecond
	}

	return durations
}

func (w *Wavs) Close() {
	w.stream.Stop()
	w.stream.Close()
	portaudio.Terminate()

	log.Debugf("Wavs Closed")
}
<|endoftext|>


<commit_before>package roles

import (
	"encoding/json"
	"net/http"

	h "github.com/ernestio/api-gateway/helpers"
	"github.com/ernestio/api-gateway/models"
)

// Create : responds to POST /roles/ by creating a
// role on the data store
func Create(au models.User, body []byte) (int, []byte) {
	var err error
	var d models.Role

	if d.Map(body) != nil {
		return 400, []byte("Input is not valid")
	}

	err = d.Validate()
	if err != nil {
		h.L.Error(err.Error())
		return http.StatusBadRequest, []byte(err.Error())
	}

	if !d.ResourceExists() {
		return 404, []byte("Specified resource not found")
	}

	if !d.UserExists() {
		return 404, []byte("Specified user not found")
	}

	if !au.Admin {
		if ok := au.IsOwner(d.ResourceType, d.ResourceID); !ok {
			return 403, []byte("You're not authorized to perform this action")
		}
	}

	existing, err := d.Get(d.UserID, d.ResourceID, d.ResourceType)
	if err != nil || existing != nil {
		return 409, []byte("Specified role already exists")
	}

	if err = d.Save(); err != nil {
		h.L.Error(err.Error())
		return 500, []byte("Internal server error")
	}

	if body, err = json.Marshal(d); err != nil {
		h.L.Error(err.Error())
		return 500, []byte("Internal server error")
	}

	return http.StatusOK, body
}
<commit_msg>Allow user roles to be modificable<commit_after>package roles

import (
	"encoding/json"
	"net/http"

	h "github.com/ernestio/api-gateway/helpers"
	"github.com/ernestio/api-gateway/models"
)

// Create : responds to POST /roles/ by creating a
// role on the data store
func Create(au models.User, body []byte) (int, []byte) {
	var err error
	var d models.Role

	if d.Map(body) != nil {
		return 400, []byte("Input is not valid")
	}

	err = d.Validate()
	if err != nil {
		h.L.Error(err.Error())
		return http.StatusBadRequest, []byte(err.Error())
	}

	if !d.ResourceExists() {
		return 404, []byte("Specified resource not found")
	}

	if !d.UserExists() {
		return 404, []byte("Specified user not found")
	}

	if !au.Admin {
		if ok := au.IsOwner(d.ResourceType, d.ResourceID); !ok {
			return 403, []byte("You're not authorized to perform this action")
		}
	}

	existing, err := d.Get(d.UserID, d.ResourceID, d.ResourceType)
	if err == nil && existing != nil {
		d.ID = existing.ID
	}

	if err = d.Save(); err != nil {
		h.L.Error(err.Error())
		return 500, []byte("Internal server error")
	}

	if body, err = json.Marshal(d); err != nil {
		h.L.Error(err.Error())
		return 500, []byte("Internal server error")
	}

	return http.StatusOK, body
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Knative 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 runtime

import (
	"context"
	"encoding/json"
	"fmt"
	"testing"

	pkgTest "knative.dev/pkg/test"
	v1 "knative.dev/serving/pkg/apis/serving/v1"
	"knative.dev/serving/test"
	"knative.dev/serving/test/types"

	v1testing "knative.dev/serving/pkg/testing/v1"
	v1test "knative.dev/serving/test/v1"
)

// fetchRuntimeInfo creates a Service that uses the 'runtime' test image, and extracts the returned output into the
// RuntimeInfo object. The 'runtime' image uses uid 65532.
func fetchRuntimeInfo(
	t *testing.T,
	clients *test.Clients,
	opts ...interface{}) (*test.ResourceNames, *types.RuntimeInfo, error) {

	names := &test.ResourceNames{Image: test.Runtime}
	t.Helper()
	names.Service = test.ObjectNameForTest(t)

	test.EnsureTearDown(t, clients, names)

	serviceOpts, reqOpts, err := splitOpts(opts...)
	if err != nil {
		return nil, nil, err
	}

	serviceOpts = append(serviceOpts, func(svc *v1.Service) {
		// Always fetch the latest runtime image.
		svc.Spec.Template.Spec.Containers[0].ImagePullPolicy = "Always"
	})

	objects, err := v1test.CreateServiceReady(t, clients, names,
		serviceOpts...)
	if err != nil {
		return nil, nil, err
	}

	resp, err := pkgTest.WaitForEndpointState(
		context.Background(),
		clients.KubeClient,
		t.Logf,
		objects.Service.Status.URL.URL(),
		v1test.RetryingRouteInconsistency(pkgTest.IsStatusOK),
		"RuntimeInfo",
		test.ServingFlags.ResolvableDomain,
		append(reqOpts, test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.Https))...)
	if err != nil {
		return nil, nil, err
	}

	var ri types.RuntimeInfo
	err = json.Unmarshal(resp.Body, &ri)
	return names, &ri, err
}

func splitOpts(opts ...interface{}) ([]v1testing.ServiceOption, []interface{}, error) {
	serviceOpts := []v1testing.ServiceOption{}
	reqOpts := []interface{}{}
	for _, opt := range opts {
		switch t := opt.(type) {
		case v1testing.ServiceOption:
			serviceOpts = append(serviceOpts, opt.(v1testing.ServiceOption))
		case pkgTest.RequestOption:
			reqOpts = append(reqOpts, opt.(pkgTest.RequestOption))
		default:
			return nil, nil, fmt.Errorf("invalid option type: %T", t)
		}

	}
	return serviceOpts, reqOpts, nil
}
<commit_msg>Revert "Set imagePullPolicy to always (#4486)" (#9390)<commit_after>/*
Copyright 2019 The Knative 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 runtime

import (
	"context"
	"encoding/json"
	"fmt"
	"testing"

	pkgTest "knative.dev/pkg/test"
	"knative.dev/serving/test"
	"knative.dev/serving/test/types"

	v1testing "knative.dev/serving/pkg/testing/v1"
	v1test "knative.dev/serving/test/v1"
)

// fetchRuntimeInfo creates a Service that uses the 'runtime' test image, and extracts the returned output into the
// RuntimeInfo object. The 'runtime' image uses uid 65532.
func fetchRuntimeInfo(
	t *testing.T,
	clients *test.Clients,
	opts ...interface{}) (*test.ResourceNames, *types.RuntimeInfo, error) {

	names := &test.ResourceNames{Image: test.Runtime}
	t.Helper()
	names.Service = test.ObjectNameForTest(t)

	test.EnsureTearDown(t, clients, names)

	serviceOpts, reqOpts, err := splitOpts(opts...)
	if err != nil {
		return nil, nil, err
	}

	objects, err := v1test.CreateServiceReady(t, clients, names,
		serviceOpts...)
	if err != nil {
		return nil, nil, err
	}

	resp, err := pkgTest.WaitForEndpointState(
		context.Background(),
		clients.KubeClient,
		t.Logf,
		objects.Service.Status.URL.URL(),
		v1test.RetryingRouteInconsistency(pkgTest.IsStatusOK),
		"RuntimeInfo",
		test.ServingFlags.ResolvableDomain,
		append(reqOpts, test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.Https))...)
	if err != nil {
		return nil, nil, err
	}

	var ri types.RuntimeInfo
	err = json.Unmarshal(resp.Body, &ri)
	return names, &ri, err
}

func splitOpts(opts ...interface{}) ([]v1testing.ServiceOption, []interface{}, error) {
	serviceOpts := []v1testing.ServiceOption{}
	reqOpts := []interface{}{}
	for _, opt := range opts {
		switch t := opt.(type) {
		case v1testing.ServiceOption:
			serviceOpts = append(serviceOpts, opt.(v1testing.ServiceOption))
		case pkgTest.RequestOption:
			reqOpts = append(reqOpts, opt.(pkgTest.RequestOption))
		default:
			return nil, nil, fmt.Errorf("invalid option type: %T", t)
		}

	}
	return serviceOpts, reqOpts, nil
}
<|endoftext|>


<commit_before>/*
 Brassica is a simple and resource efficient CMS for low dynamic
 private and small business sites with mostly static pages and simple
 structure.

 monsti/monsti-serve contains a command to start a httpd.
*/
package main

// Settings for the application and the site.
type settings struct {
	// Settings for sending mail (outgoing SMTP).
	Mail struct {
		// Host may be specified as address:port
		Host, Username, Password string
	}
	// Absolute paths to used directories.
	Directories struct {
		// Config files
		Config string
		// Site content
		Data string
		// Monsti's static files
		Statics string
		// Site specific static files
		SiteStatics string
		// HTML Templates
		Templates string
		// Locales, i.e. the gettext machine objects (.mo)
		Locales string
	}
	// Site title
	Title string
	// Name and email address of site owner.
	//
	// The owner's address is used as recipient of contact form submissions.
	Owner struct {
		Name, Email string
	}
	// List of node types to be activated.
	NodeTypes []string
	// Key to authenticate session cookies.
	SessionAuthKey string
}
<commit_msg>Fix doc.<commit_after>/*
 Brassica is a simple and resource efficient CMS for low dynamic
 private and small business sites with mostly static pages and simple
 structure.

 This package implements the main application and http server.
*/
package main

// Settings for the application and the site.
type settings struct {
	// Settings for sending mail (outgoing SMTP).
	Mail struct {
		// Host may be specified as address:port
		Host, Username, Password string
	}
	// Absolute paths to used directories.
	Directories struct {
		// Config files
		Config string
		// Site content
		Data string
		// Monsti's static files
		Statics string
		// Site specific static files
		SiteStatics string
		// HTML Templates
		Templates string
		// Locales, i.e. the gettext machine objects (.mo)
		Locales string
	}
	// Site title
	Title string
	// Name and email address of site owner.
	//
	// The owner's address is used as recipient of contact form submissions.
	Owner struct {
		Name, Email string
	}
	// List of node types to be activated.
	NodeTypes []string
	// Key to authenticate session cookies.
	SessionAuthKey string
}
<|endoftext|>


<commit_before>package msgs

import (
	"fmt"
	"github.com/golang/glog"
	"sync"
)

type FailureNotifier struct {
	up         []bool
	mutex      sync.RWMutex
	subscribed [](chan bool)
	n          int
}

func NewFailureNotifier(n int) *FailureNotifier {
	return &FailureNotifier{
		make([]bool, n),
		sync.RWMutex{},
		make([](chan bool), n),
		n}
}

func (f *FailureNotifier) NotifyOnFailure(id int) chan bool {
	note := make(chan bool, 1)
	f.subscribed[id] = note
	// if !f.up[id] {
	// 	note <- true
	// }
	return note
}

func (f *FailureNotifier) IsConnected(id int) bool {
	f.mutex.RLock()
	up := f.up[id]
	f.mutex.RUnlock()
	return up
}

// Return the ID of the next connected node
func (f *FailureNotifier) NextConnected(id int) int {
	f.mutex.RLock()
	id++
	if id == f.n {
		id = 0
	}
	for !f.up[id] {
		id++
		if id == f.n {
			id = 0
		}
	}
	f.mutex.RUnlock()
	return id
}

func (f *FailureNotifier) NowConnected(id int) error {
	f.mutex.Lock()
	if f.up[id] {
		f.mutex.Unlock()
		return fmt.Errorf("Possible multiple connections to peer %d", id)
	}
	f.up[id] = true
	f.mutex.Unlock()
	return nil
}

func (f *FailureNotifier) NowDisconnected(id int) {
	f.mutex.Lock()
	if !f.up[id] {
		glog.Fatal("Possible multiple connections to one peer")
	}
	f.up[id] = false
	f.subscribed[id] <- true
	f.mutex.Unlock()
}
<commit_msg>allowing multiple peer connections<commit_after>package msgs

import (
	"fmt"
	"github.com/golang/glog"
	"sync"
)

type FailureNotifier struct {
	up         []bool
	mutex      sync.RWMutex
	subscribed [](chan bool)
	n          int
}

func NewFailureNotifier(n int) *FailureNotifier {
	return &FailureNotifier{
		make([]bool, n),
		sync.RWMutex{},
		make([](chan bool), n),
		n}
}

func (f *FailureNotifier) NotifyOnFailure(id int) chan bool {
	note := make(chan bool, 1)
	f.subscribed[id] = note
	// if !f.up[id] {
	// 	note <- true
	// }
	return note
}

func (f *FailureNotifier) IsConnected(id int) bool {
	f.mutex.RLock()
	up := f.up[id]
	f.mutex.RUnlock()
	return up
}

// Return the ID of the next connected node
func (f *FailureNotifier) NextConnected(id int) int {
	f.mutex.RLock()
	id++
	if id == f.n {
		id = 0
	}
	for !f.up[id] {
		id++
		if id == f.n {
			id = 0
		}
	}
	f.mutex.RUnlock()
	return id
}

func (f *FailureNotifier) NowConnected(id int) error {
	f.mutex.Lock()
	if f.up[id] {
		f.mutex.Unlock()
		return fmt.Errorf("Possible multiple connections to peer %d", id)
	}
	f.up[id] = true
	f.mutex.Unlock()
	return nil
}

func (f *FailureNotifier) NowDisconnected(id int) {
	f.mutex.Lock()
	if !f.up[id] {
		glog.Warning("Possible multiple connections to one peer")
	}
	f.up[id] = false
	f.subscribed[id] <- true
	f.mutex.Unlock()
}
<|endoftext|>


<commit_before>package view

import (
	"bytes"
	"encoding/json"
	"github.com/zaolab/sunnified/mvc"
	"github.com/zaolab/sunnified/web"
)

type JsonView struct {
	mvc.VM
}

func (this *JsonView) ContentType(ctxt *web.Context) string {
	return "application/json; charset=utf-8"
}

func (this *JsonView) Render(ctxt *web.Context) ([]byte, error) {
	if this.VM == nil {
		this.VM = mvc.VM{}
	}
	buf := bytes.NewBuffer(make([]byte, 0, 100))
	jsone := json.NewEncoder(buf)
	if err := jsone.Encode(this.VM); err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

func (this *JsonView) RenderString(ctxt *web.Context) (string, error) {
	b, err := this.Render(ctxt)
	if err == nil {
		return string(b), nil
	}
	return "", err
}

func (this *JsonView) Publish(ctxt *web.Context) error {
	if this.VM == nil {
		this.VM = mvc.VM{}
	}
	ctxt.SetHeader("Content-Type", "application/json; charset=utf-8")
	jsone := json.NewEncoder(ctxt.Response)
	if err := jsone.Encode(this.VM); err != nil {
		return err
	}
	return nil
}

type FullJsonView struct {
	*JsonView
}

func (this *FullJsonView) SetVMap(vmap ...mvc.VM) {
	if this.JsonView == nil {
		this.JsonView = NewJsonView(nil)
	}
	for _, vm := range vmap {
		for k, v := range vm {
			this.VM[k] = v
		}
	}
}

func (this *FullJsonView) SetData(name string, value interface{}) {
	if this.JsonView == nil {
		this.JsonView = NewJsonView(nil)
	}
	this.VM[name] = value
}

func NewJsonView(vmap mvc.VM) *JsonView {
	if vmap == nil {
		vmap = mvc.VM{}
	}
	return &JsonView{vmap}
}

func NewFullJsonView(vmap mvc.VM) *FullJsonView {
	if vmap == nil {
		vmap = mvc.VM{}
	}
	return &FullJsonView{NewJsonView(vmap)}
}
<commit_msg>changed jsonview from struct to map<commit_after>package view

import (
	"bytes"
	"encoding/json"
	"github.com/zaolab/sunnified/mvc"
	"github.com/zaolab/sunnified/web"
	"reflect"
)

type JsonView mvc.VM

func (this JsonView) ContentType(ctxt *web.Context) string {
	return "application/json; charset=utf-8"
}

func (this JsonView) Render(ctxt *web.Context) ([]byte, error) {
	if this == nil || len(this) == 0 {
		return []byte{'{', '}'}, nil
	}

	buf := bytes.NewBuffer(make([]byte, 0, 100))
	jsone := json.NewEncoder(buf)
	if err := jsone.Encode(this.getEncodingInterface()); err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

func (this JsonView) RenderString(ctxt *web.Context) (string, error) {
	b, err := this.Render(ctxt)
	if err == nil {
		return string(b), nil
	}
	return "", err
}

func (this JsonView) Publish(ctxt *web.Context) error {
	ctxt.SetHeader("Content-Type", "application/json; charset=utf-8")

	if this == nil || len(this) == 0 {
		ctxt.Response.Write([]byte{'{', '}'})
		return nil
	}

	jsone := json.NewEncoder(ctxt.Response)
	if err := jsone.Encode(this.getEncodingInterface()); err != nil {
		return err
	}
	return nil
}

func (this JsonView) getEncodingInterface() (i interface{}) {
	i = this

	if len(this) == 1 && this[""] != nil {
		t := reflect.TypeOf(this[""])

		if kind := t.Kind(); kind == reflect.Map || kind == reflect.Struct ||
			(kind == reflect.Ptr && t.Elem().Kind() == reflect.Struct) {
			i = this[""]
		}
	}

	return
}

type FullJsonView JsonView

func (this FullJsonView) ContentType(ctxt *web.Context) string {
	return JsonView(this).ContentType(ctxt)
}

func (this FullJsonView) Render(ctxt *web.Context) ([]byte, error) {
	return JsonView(this).Render(ctxt)
}

func (this FullJsonView) RenderString(ctxt *web.Context) (string, error) {
	return JsonView(this).RenderString(ctxt)
}

func (this FullJsonView) Publish(ctxt *web.Context) error {
	return JsonView(this).Publish(ctxt)
}

func (this *FullJsonView) SetVMap(vmap ...mvc.VM) {
	if *this == nil {
		*this = NewFullJsonView(nil)
	}

	_vmap := *this

	for _, vm := range vmap {
		for k, v := range vm {
			_vmap[k] = v
		}
	}
}

func (this *FullJsonView) SetData(name string, value interface{}) {
	if *this == nil {
		*this = NewFullJsonView(nil)
	}

	_vmap := *this
	_vmap[name] = value
}

func NewJsonView(vmap mvc.VM) JsonView {
	if vmap == nil {
		vmap = mvc.VM{}
	}
	return JsonView(vmap)
}

func NewFullJsonView(vmap mvc.VM) FullJsonView {
	if vmap == nil {
		vmap = mvc.VM{}
	}
	return FullJsonView(NewJsonView(vmap))
}
<|endoftext|>


<commit_before>// Copyright ©2015 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 native

// Ilaenv returns algorithm tuning parameters for the algorithm given by the
// input string. ispec specifies the parameter to return.
//  1: The optimal block size
//  2: The minimum block size for which the algorithm should be used.
//  3: The crossover point below which an unblocked routine should be used.
//  4: The number of shifts.
//  5: The minimum column dimension for blocking to be used.
//  6: The crossover point for SVD (to use QR factorization or not).
//  7: The number of processors.
//  8: The crossover point for multi-shift in QR and QZ methods for non-symmetric eigenvalue problems.
//  9: Maximum size of the subproblems in divide-and-conquer algorithms.
//  10: ieee NaN arithmetic can be trusted not to trap.
//  11: infinity arithmetic can be trusted not to trap.
//
// Ilaenv is an internal routine. It is exported for testing purposes.
func (Implementation) Ilaenv(ispec int, s string, opts string, n1, n2, n3, n4 int) int {
	// TODO(btracey): Replace this with a constant lookup? A list of constants?
	// TODO: What is the difference between 2 and 3?
	sname := s[0] == 'S' || s[0] == 'D'
	cname := s[0] == 'C' || s[0] == 'Z'
	if !sname && !cname {
		panic("lapack: bad name")
	}
	c2 := s[1:3]
	c3 := s[3:6]
	c4 := c3[1:3]

	switch ispec {
	default:
		panic("lapack: bad ispec")
	case 1:
		switch c2 {
		default:
			panic("lapack: bad function name")
		case "GE":
			switch c3 {
			default:
				panic("lapack: bad function name")
			case "TRF":
				if sname {
					return 64
				}
				return 64
			case "QRF", "RQF", "LQF", "QLF":
				if sname {
					return 32
				}
				return 32
			case "HRD":
				if sname {
					return 32
				}
				return 32
			case "BRD":
				if sname {
					return 32
				}
				return 32
			case "TRI":
				if sname {
					return 64
				}
				return 64
			}
		case "PO":
			switch c3 {
			default:
				panic("lapack: bad function name")
			case "TRF":
				if sname {
					return 64
				}
				return 64
			}
		case "SY":
			switch c3 {
			default:
				panic("lapack: bad function name")
			case "TRF":
				if sname {
					return 64
				}
				return 64
			case "TRD":
				return 32
			case "GST":
				return 64
			}
		case "HE":
			switch c3 {
			default:
				panic("lapack: bad function name")
			case "TRF":
				return 64
			case "TRD":
				return 32
			case "GST":
				return 64
			}
		case "OR":
			switch c3[0] {
			default:
				panic("lapack: bad function name")
			case 'G':
				switch c3[1:] {
				default:
					panic("lapack: bad function name")
				case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR":
					return 32
				}
			case 'M':
				switch c3[1:] {
				default:
					panic("lapack: bad function name")
				case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR":
					return 32
				}
			}
		case "UN":
			switch c3[0] {
			default:
				panic("lapack: bad function name")
			case 'G':
				switch c3[1:] {
				default:
					panic("lapack: bad function name")
				case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR":
					return 32
				}
			case 'M':
				switch c3[1:] {
				default:
					panic("lapack: bad function name")
				case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR":
					return 32
				}
			}
		case "GB":
			switch c3 {
			default:
				panic("lapack: bad function name")
			case "TRF":
				if sname {
					if n4 <= 64 {
						return 1
					}
					return 32
				}
				if n4 <= 64 {
					return 1
				}
				return 32
			}
		case "PB":
			switch c3 {
			default:
				panic("lapack: bad function name")
			case "TRF":
				if sname {
					if n4 <= 64 {
						return 1
					}
					return 32
				}
				if n4 <= 64 {
					return 1
				}
				return 32
			}
		case "TR":
			switch c3 {
			default:
				panic("lapack: bad function name")
			case "TRI":
				if sname {
					return 64
				}
				return 64
			}
		case "LA":
			switch c3 {
			default:
				panic("lapack: bad function name")
			case "UUM":
				if sname {
					return 64
				}
				return 64
			}
		case "ST":
			if sname && c3 == "EBZ" {
				return 1
			}
			panic("lapack: bad function name")
		}
	case 2:
		switch c2 {
		default:
			panic("lapack: bad function name")
		case "GE":
			switch c3 {
			default:
				panic("lapack: bad function name")
			case "QRF", "RQF", "LQF", "QLF":
				if sname {
					return 2
				}
				return 2
			case "HRD":
				if sname {
					return 2
				}
				return 2
			case "BRD":
				if sname {
					return 2
				}
				return 2
			case "TRI":
				if sname {
					return 2
				}
				return 2
			}
		case "SY":
			switch c3 {
			default:
				panic("lapack: bad function name")
			case "TRF":
				if sname {
					return 8
				}
				return 8
			case "TRD":
				if sname {
					return 2
				}
				panic("lapack: bad function name")
			}
		case "HE":
			if c3 == "TRD" {
				return 2
			}
			panic("lapack: bad function name")
		case "OR":
			if !sname {
				panic("lapack: bad function name")
			}
			switch c3[0] {
			default:
				panic("lapack: bad function name")
			case 'G':
				switch c4 {
				default:
					panic("lapack: bad function name")
				case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR":
					return 2
				}
			case 'M':
				switch c4 {
				default:
					panic("lapack: bad function name")
				case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR":
					return 2
				}
			}
		case "UN":
			switch c3[0] {
			default:
				panic("lapack: bad function name")
			case 'G':
				switch c4 {
				default:
					panic("lapack: bad function name")
				case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR":
					return 2
				}
			case 'M':
				switch c4 {
				default:
					panic("lapack: bad function name")
				case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR":
					return 2
				}
			}
		}
	case 3:
		switch c2 {
		default:
			panic("lapack: bad function name")
		case "GE":
			switch c3 {
			default:
				panic("lapack: bad function name")
			case "QRF", "RQF", "LQF", "QLF":
				if sname {
					return 128
				}
				return 128
			case "HRD":
				if sname {
					return 128
				}
				return 128
			case "BRD":
				if sname {
					return 128
				}
				return 128
			}
		case "SY":
			if sname && c3 == "TRD" {
				return 32
			}
			panic("lapack: bad function name")
		case "HE":
			if c3 == "TRD" {
				return 32
			}
			panic("lapack: bad function name")
		case "OR":
			switch c3[0] {
			default:
				panic("lapack: bad function name")
			case 'G':
				switch c4 {
				default:
					panic("lapack: bad function name")
				case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR":
					return 128
				}
			}
		case "UN":
			switch c3[0] {
			default:
				panic("lapack: bad function name")
			case 'G':
				switch c4 {
				default:
					panic("lapack: bad function name")
				case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR":
					return 128
				}
			}
		}
	case 4:
		// Used by xHSEQR
		return 6
	case 5:
		// Not used
		return 2
	case 6:
		// Used by xGELSS and xGESVD
		return int(float64(min(n1, n2)) * 1.6)
	case 7:
		// Not used
		return 1
	case 8:
		// Used by xHSEQR
		return 50
	case 9:
		// used by xGELSD and xGESDD
		return 25
	case 10:
		// Go guarantees ieee
		return 1
	case 11:
		// Go guarantees ieee
		return 1
	}
}
<commit_msg>native: clarify comment for Ilaenv<commit_after>// Copyright ©2015 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 native

// Ilaenv returns algorithm tuning parameters for the algorithm given by the
// input string. ispec specifies the parameter to return:
//  1: The optimal block size for a blocked algorithm.
//  2: The minimum block size for a blocked algorithm.
//  3: The block size of unprocessed data at which a blocked algorithm should
//     crossover to an unblocked version.
//  4: The number of shifts.
//  5: The minimum column dimension for blocking to be used.
//  6: The crossover point for SVD (to use QR factorization or not).
//  7: The number of processors.
//  8: The crossover point for multi-shift in QR and QZ methods for non-symmetric eigenvalue problems.
//  9: Maximum size of the subproblems in divide-and-conquer algorithms.
//  10: ieee NaN arithmetic can be trusted not to trap.
//  11: infinity arithmetic can be trusted not to trap.
//
// Ilaenv is an internal routine. It is exported for testing purposes.
func (Implementation) Ilaenv(ispec int, s string, opts string, n1, n2, n3, n4 int) int {
	// TODO(btracey): Replace this with a constant lookup? A list of constants?
	sname := s[0] == 'S' || s[0] == 'D'
	cname := s[0] == 'C' || s[0] == 'Z'
	if !sname && !cname {
		panic("lapack: bad name")
	}
	c2 := s[1:3]
	c3 := s[3:6]
	c4 := c3[1:3]

	switch ispec {
	default:
		panic("lapack: bad ispec")
	case 1:
		switch c2 {
		default:
			panic("lapack: bad function name")
		case "GE":
			switch c3 {
			default:
				panic("lapack: bad function name")
			case "TRF":
				if sname {
					return 64
				}
				return 64
			case "QRF", "RQF", "LQF", "QLF":
				if sname {
					return 32
				}
				return 32
			case "HRD":
				if sname {
					return 32
				}
				return 32
			case "BRD":
				if sname {
					return 32
				}
				return 32
			case "TRI":
				if sname {
					return 64
				}
				return 64
			}
		case "PO":
			switch c3 {
			default:
				panic("lapack: bad function name")
			case "TRF":
				if sname {
					return 64
				}
				return 64
			}
		case "SY":
			switch c3 {
			default:
				panic("lapack: bad function name")
			case "TRF":
				if sname {
					return 64
				}
				return 64
			case "TRD":
				return 32
			case "GST":
				return 64
			}
		case "HE":
			switch c3 {
			default:
				panic("lapack: bad function name")
			case "TRF":
				return 64
			case "TRD":
				return 32
			case "GST":
				return 64
			}
		case "OR":
			switch c3[0] {
			default:
				panic("lapack: bad function name")
			case 'G':
				switch c3[1:] {
				default:
					panic("lapack: bad function name")
				case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR":
					return 32
				}
			case 'M':
				switch c3[1:] {
				default:
					panic("lapack: bad function name")
				case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR":
					return 32
				}
			}
		case "UN":
			switch c3[0] {
			default:
				panic("lapack: bad function name")
			case 'G':
				switch c3[1:] {
				default:
					panic("lapack: bad function name")
				case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR":
					return 32
				}
			case 'M':
				switch c3[1:] {
				default:
					panic("lapack: bad function name")
				case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR":
					return 32
				}
			}
		case "GB":
			switch c3 {
			default:
				panic("lapack: bad function name")
			case "TRF":
				if sname {
					if n4 <= 64 {
						return 1
					}
					return 32
				}
				if n4 <= 64 {
					return 1
				}
				return 32
			}
		case "PB":
			switch c3 {
			default:
				panic("lapack: bad function name")
			case "TRF":
				if sname {
					if n4 <= 64 {
						return 1
					}
					return 32
				}
				if n4 <= 64 {
					return 1
				}
				return 32
			}
		case "TR":
			switch c3 {
			default:
				panic("lapack: bad function name")
			case "TRI":
				if sname {
					return 64
				}
				return 64
			}
		case "LA":
			switch c3 {
			default:
				panic("lapack: bad function name")
			case "UUM":
				if sname {
					return 64
				}
				return 64
			}
		case "ST":
			if sname && c3 == "EBZ" {
				return 1
			}
			panic("lapack: bad function name")
		}
	case 2:
		switch c2 {
		default:
			panic("lapack: bad function name")
		case "GE":
			switch c3 {
			default:
				panic("lapack: bad function name")
			case "QRF", "RQF", "LQF", "QLF":
				if sname {
					return 2
				}
				return 2
			case "HRD":
				if sname {
					return 2
				}
				return 2
			case "BRD":
				if sname {
					return 2
				}
				return 2
			case "TRI":
				if sname {
					return 2
				}
				return 2
			}
		case "SY":
			switch c3 {
			default:
				panic("lapack: bad function name")
			case "TRF":
				if sname {
					return 8
				}
				return 8
			case "TRD":
				if sname {
					return 2
				}
				panic("lapack: bad function name")
			}
		case "HE":
			if c3 == "TRD" {
				return 2
			}
			panic("lapack: bad function name")
		case "OR":
			if !sname {
				panic("lapack: bad function name")
			}
			switch c3[0] {
			default:
				panic("lapack: bad function name")
			case 'G':
				switch c4 {
				default:
					panic("lapack: bad function name")
				case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR":
					return 2
				}
			case 'M':
				switch c4 {
				default:
					panic("lapack: bad function name")
				case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR":
					return 2
				}
			}
		case "UN":
			switch c3[0] {
			default:
				panic("lapack: bad function name")
			case 'G':
				switch c4 {
				default:
					panic("lapack: bad function name")
				case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR":
					return 2
				}
			case 'M':
				switch c4 {
				default:
					panic("lapack: bad function name")
				case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR":
					return 2
				}
			}
		}
	case 3:
		switch c2 {
		default:
			panic("lapack: bad function name")
		case "GE":
			switch c3 {
			default:
				panic("lapack: bad function name")
			case "QRF", "RQF", "LQF", "QLF":
				if sname {
					return 128
				}
				return 128
			case "HRD":
				if sname {
					return 128
				}
				return 128
			case "BRD":
				if sname {
					return 128
				}
				return 128
			}
		case "SY":
			if sname && c3 == "TRD" {
				return 32
			}
			panic("lapack: bad function name")
		case "HE":
			if c3 == "TRD" {
				return 32
			}
			panic("lapack: bad function name")
		case "OR":
			switch c3[0] {
			default:
				panic("lapack: bad function name")
			case 'G':
				switch c4 {
				default:
					panic("lapack: bad function name")
				case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR":
					return 128
				}
			}
		case "UN":
			switch c3[0] {
			default:
				panic("lapack: bad function name")
			case 'G':
				switch c4 {
				default:
					panic("lapack: bad function name")
				case "QR", "RQ", "LQ", "QL", "HR", "TR", "BR":
					return 128
				}
			}
		}
	case 4:
		// Used by xHSEQR
		return 6
	case 5:
		// Not used
		return 2
	case 6:
		// Used by xGELSS and xGESVD
		return int(float64(min(n1, n2)) * 1.6)
	case 7:
		// Not used
		return 1
	case 8:
		// Used by xHSEQR
		return 50
	case 9:
		// used by xGELSD and xGESDD
		return 25
	case 10:
		// Go guarantees ieee
		return 1
	case 11:
		// Go guarantees ieee
		return 1
	}
}
<|endoftext|>