<commit_before>package models

import (
	"errors"
	"fmt"
	"socialapi/config"
	"time"

	"github.com/VerbalExpressions/GoVerbalExpressions"
	"github.com/jinzhu/gorm"
	"github.com/koding/bongo"
)

var mentionRegex = verbalexpressions.New().
	Find("@").
	BeginCapture().
	Word().
	EndCapture().
	Regex()

type ChannelMessage struct {
	// unique identifier of the channel message
	Id int64 `json:"id,string"`

	// Body of the mesage
	Body string `json:"body"`

	// Generated Slug for body
	Slug string `json:"slug"                               sql:"NOT NULL;TYPE:VARCHAR(100);"`

	// type of the message
	TypeConstant string `json:"typeConstant"               sql:"NOT NULL;TYPE:VARCHAR(100);"`

	// Creator of the channel message
	AccountId int64 `json:"accountId,string"               sql:"NOT NULL"`

	// in which channel this message is created
	InitialChannelId int64 `json:"initialChannelId,string" sql:"NOT NULL"`

	// Creation date of the message
	CreatedAt time.Time `json:"createdAt"                  sql:"DEFAULT:CURRENT_TIMESTAMP"`

	// Modification date of the message
	UpdatedAt time.Time `json:"updatedAt"                  sql:"DEFAULT:CURRENT_TIMESTAMP"`

	// Deletion date of the channel message
	DeletedAt time.Time `json:"deletedAt"`

	// Extra data storage
	Payload gorm.Hstore `json:"payload,omitempty"`
}

func (c *ChannelMessage) BeforeCreate() {
	c.DeletedAt = ZeroDate()
}

func (c *ChannelMessage) AfterCreate() {
	bongo.B.AfterCreate(c)
}

func (c *ChannelMessage) AfterUpdate() {
	bongo.B.AfterUpdate(c)
}

func (c ChannelMessage) AfterDelete() {
	bongo.B.AfterDelete(c)
}

func (c ChannelMessage) GetId() int64 {
	return c.Id
}

func (c ChannelMessage) TableName() string {
	return "api.channel_message"
}

const (
	ChannelMessage_TYPE_POST            = "post"
	ChannelMessage_TYPE_REPLY           = "reply"
	ChannelMessage_TYPE_JOIN            = "join"
	ChannelMessage_TYPE_LEAVE           = "leave"
	ChannelMessage_TYPE_CHAT            = "chat"
	ChannelMessage_TYPE_PRIVATE_MESSAGE = "privatemessage"
)

func NewChannelMessage() *ChannelMessage {
	return &ChannelMessage{}
}

func (c *ChannelMessage) ById(id int64) error {
	return bongo.B.ById(c, id)
}

func (c *ChannelMessage) One(q *bongo.Query) error {
	return bongo.B.One(c, c, q)
}

func (c *ChannelMessage) Some(data interface{}, q *bongo.Query) error {
	return bongo.B.Some(c, data, q)
}

func bodyLenCheck(body string) error {
	if len(body) < config.Get().Limits.MessageBodyMinLen {
		return fmt.Errorf("Message Body Length should be greater than %d, yours is %d ", config.Get().Limits.MessageBodyMinLen, len(body))
	}

	return nil
}

// todo create a new message while updating the channel_message and delete other
// cases, since deletion is a soft delete, old instances will still be there
func (c *ChannelMessage) Update() error {
	if err := bodyLenCheck(c.Body); err != nil {
		return err
	}
	// only update body
	err := bongo.B.UpdatePartial(c,
		map[string]interface{}{
			"body": c.Body,
		},
	)
	return err
}

func (c *ChannelMessage) Create() error {
	if err := bodyLenCheck(c.Body); err != nil {
		return err
	}

	var err error
	c, err = Slugify(c)
	if err != nil {
		return err
	}

	return bongo.B.Create(c)
}

func (c *ChannelMessage) Delete() error {
	return bongo.B.Delete(c)
}

func (c *ChannelMessage) FetchByIds(ids []int64) ([]ChannelMessage, error) {
	var messages []ChannelMessage

	if len(ids) == 0 {
		return messages, nil
	}

	if err := bongo.B.FetchByIds(c, &messages, ids); err != nil {
		return nil, err
	}
	return messages, nil
}

func (c *ChannelMessage) BuildMessages(query *Query, messages []ChannelMessage) ([]*ChannelMessageContainer, error) {
	containers := make([]*ChannelMessageContainer, len(messages))
	if len(containers) == 0 {
		return containers, nil
	}

	for i, message := range messages {
		d := NewChannelMessage()
		*d = message
		data, err := d.BuildMessage(query)
		if err != nil {
			return containers, err
		}
		containers[i] = data
	}

	return containers, nil
}

func (c *ChannelMessage) BuildMessage(query *Query) (*ChannelMessageContainer, error) {
	cmc, err := c.FetchRelatives(query)
	if err != nil {
		return nil, err
	}

	mr := NewMessageReply()
	mr.MessageId = c.Id
	q := query
	q.Limit = 3
	replies, err := mr.List(query)
	if err != nil {
		return nil, err
	}

	repliesCount, err := mr.Count()
	if err != nil {
		return nil, err
	}
	cmc.RepliesCount = repliesCount

	cmc.IsFollowed, err = c.CheckIsMessageFollowed(query)
	if err != nil {
		return nil, err
	}

	populatedChannelMessagesReplies := make([]*ChannelMessageContainer, len(replies))
	for rl := 0; rl < len(replies); rl++ {
		cmrc, err := replies[rl].FetchRelatives(query)
		if err != nil {
			return nil, err
		}
		populatedChannelMessagesReplies[rl] = cmrc
	}

	cmc.Replies = populatedChannelMessagesReplies
	return cmc, nil
}

func (c *ChannelMessage) CheckIsMessageFollowed(query *Query) (bool, error) {
	channel := NewChannel()
	if err := channel.FetchPinnedActivityChannel(query.AccountId, query.GroupName); err != nil {
		if err == gorm.RecordNotFound {
			return false, nil
		}
		return false, err
	}

	cml := NewChannelMessageList()
	q := &bongo.Query{
		Selector: map[string]interface{}{
			"channel_id": channel.Id,
			"message_id": c.Id,
		},
	}
	if err := cml.One(q); err != nil {
		if err == gorm.RecordNotFound {
			return false, nil
		}

		return false, err
	}

	return true, nil
}

func (c *ChannelMessage) BuildEmptyMessageContainer() (*ChannelMessageContainer, error) {
	if c.Id == 0 {
		return nil, errors.New("Channel message id is not set")
	}
	container := NewChannelMessageContainer()
	container.Message = c

	oldId, err := AccountOldIdById(c.AccountId)
	if err != nil {
		return nil, err
	}

	container.AccountOldId = oldId

	interactionContainer := NewInteractionContainer()
	interactionContainer.ActorsPreview = make([]string, 0)
	interactionContainer.IsInteracted = false
	interactionContainer.ActorsCount = 0

	container.Interactions = make(map[string]*InteractionContainer)
	container.Interactions["like"] = interactionContainer

	return container, nil
}

func (c *ChannelMessage) FetchRelatives(query *Query) (*ChannelMessageContainer, error) {
	container, err := c.BuildEmptyMessageContainer()
	if err != nil {
		return nil, err
	}

	i := NewInteraction()
	i.MessageId = c.Id

	// get preview
	query.Type = "like"
	query.Limit = 3
	interactorIds, err := i.List(query)
	if err != nil {
		return nil, err
	}

	oldIds, err := FetchOldIdsByAccountIds(interactorIds)
	if err != nil {
		return nil, err
	}

	interactionContainer := NewInteractionContainer()
	interactionContainer.ActorsPreview = oldIds

	// check if the current user is interacted in this thread
	isInteracted, err := i.IsInteracted(query.AccountId)
	if err != nil {
		return nil, err
	}

	interactionContainer.IsInteracted = isInteracted

	// fetch interaction count
	count, err := i.Count(query.Type)
	if err != nil {
		return nil, err
	}

	interactionContainer.ActorsCount = count

	container.Interactions["like"] = interactionContainer
	return container, nil
}

func generateMessageListQuery(channelId int64, q *Query) *bongo.Query {
	messageType := q.Type
	if messageType == "" {
		messageType = ChannelMessage_TYPE_POST
	}

	return &bongo.Query{
		Selector: map[string]interface{}{
			"account_id":         q.AccountId,
			"initial_channel_id": channelId,
			"type_constant":      messageType,
		},
		Pagination: *bongo.NewPagination(q.Limit, q.Skip),
		Sort: map[string]string{
			"created_at": "DESC",
		},
	}
}

func (c *ChannelMessage) FetchMessagesByChannelId(channelId int64, q *Query) ([]ChannelMessage, error) {
	query := generateMessageListQuery(channelId, q)

	var messages []ChannelMessage
	if err := c.Some(&messages, query); err != nil {
		return nil, err
	}

	if messages == nil {
		return make([]ChannelMessage, 0), nil
	}
	return messages, nil
}

func (c *ChannelMessage) GetMentionedUsernames() []string {
	flattened := make([]string, 0)

	res := mentionRegex.FindAllStringSubmatch(c.Body, -1)
	if len(res) == 0 {
		return flattened
	}

	participants := map[string]struct{}{}
	// remove duplicate mentions
	for _, ele := range res {
		participants[ele[1]] = struct{}{}
	}

	for participant := range participants {
		flattened = append(flattened, participant)
	}

	return flattened
}
<commit_msg>Social: style issue<commit_after>package models

import (
	"errors"
	"fmt"
	"socialapi/config"
	"time"

	"github.com/VerbalExpressions/GoVerbalExpressions"
	"github.com/jinzhu/gorm"
	"github.com/koding/bongo"
)

var mentionRegex = verbalexpressions.New().
	Find("@").
	BeginCapture().
	Word().
	EndCapture().
	Regex()

type ChannelMessage struct {
	// unique identifier of the channel message
	Id int64 `json:"id,string"`

	// Body of the mesage
	Body string `json:"body"`

	// Generated Slug for body
	Slug string `json:"slug"                               sql:"NOT NULL;TYPE:VARCHAR(100);"`

	// type of the message
	TypeConstant string `json:"typeConstant"               sql:"NOT NULL;TYPE:VARCHAR(100);"`

	// Creator of the channel message
	AccountId int64 `json:"accountId,string"               sql:"NOT NULL"`

	// in which channel this message is created
	InitialChannelId int64 `json:"initialChannelId,string" sql:"NOT NULL"`

	// Creation date of the message
	CreatedAt time.Time `json:"createdAt"                  sql:"DEFAULT:CURRENT_TIMESTAMP"`

	// Modification date of the message
	UpdatedAt time.Time `json:"updatedAt"                  sql:"DEFAULT:CURRENT_TIMESTAMP"`

	// Deletion date of the channel message
	DeletedAt time.Time `json:"deletedAt"`

	// Extra data storage
	Payload gorm.Hstore `json:"payload,omitempty"`
}

func (c *ChannelMessage) BeforeCreate() {
	c.DeletedAt = ZeroDate()
}

func (c *ChannelMessage) AfterCreate() {
	bongo.B.AfterCreate(c)
}

func (c *ChannelMessage) AfterUpdate() {
	bongo.B.AfterUpdate(c)
}

func (c ChannelMessage) AfterDelete() {
	bongo.B.AfterDelete(c)
}

func (c ChannelMessage) GetId() int64 {
	return c.Id
}

func (c ChannelMessage) TableName() string {
	return "api.channel_message"
}

const (
	ChannelMessage_TYPE_POST            = "post"
	ChannelMessage_TYPE_REPLY           = "reply"
	ChannelMessage_TYPE_JOIN            = "join"
	ChannelMessage_TYPE_LEAVE           = "leave"
	ChannelMessage_TYPE_CHAT            = "chat"
	ChannelMessage_TYPE_PRIVATE_MESSAGE = "privatemessage"
)

func NewChannelMessage() *ChannelMessage {
	return &ChannelMessage{}
}

func (c *ChannelMessage) ById(id int64) error {
	return bongo.B.ById(c, id)
}

func (c *ChannelMessage) One(q *bongo.Query) error {
	return bongo.B.One(c, c, q)
}

func (c *ChannelMessage) Some(data interface{}, q *bongo.Query) error {
	return bongo.B.Some(c, data, q)
}

func bodyLenCheck(body string) error {
	if len(body) < config.Get().Limits.MessageBodyMinLen {
		return fmt.Errorf("Message Body Length should be greater than %d, yours is %d ", config.Get().Limits.MessageBodyMinLen, len(body))
	}

	return nil
}

// todo create a new message while updating the channel_message and delete other
// cases, since deletion is a soft delete, old instances will still be there
func (c *ChannelMessage) Update() error {
	if err := bodyLenCheck(c.Body); err != nil {
		return err
	}
	// only update body
	err := bongo.B.UpdatePartial(c,
		map[string]interface{}{
			"body": c.Body,
		},
	)
	return err
}

func (c *ChannelMessage) Create() error {
	if err := bodyLenCheck(c.Body); err != nil {
		return err
	}

	var err error
	c, err = Slugify(c)
	if err != nil {
		return err
	}

	return bongo.B.Create(c)
}

func (c *ChannelMessage) Delete() error {
	return bongo.B.Delete(c)
}

func (c *ChannelMessage) FetchByIds(ids []int64) ([]ChannelMessage, error) {
	var messages []ChannelMessage

	if len(ids) == 0 {
		return messages, nil
	}

	if err := bongo.B.FetchByIds(c, &messages, ids); err != nil {
		return nil, err
	}

	return messages, nil
}

func (c *ChannelMessage) BuildMessages(query *Query, messages []ChannelMessage) ([]*ChannelMessageContainer, error) {
	containers := make([]*ChannelMessageContainer, len(messages))
	if len(containers) == 0 {
		return containers, nil
	}

	for i, message := range messages {
		d := NewChannelMessage()
		*d = message
		data, err := d.BuildMessage(query)
		if err != nil {
			return containers, err
		}
		containers[i] = data
	}

	return containers, nil
}

func (c *ChannelMessage) BuildMessage(query *Query) (*ChannelMessageContainer, error) {
	cmc, err := c.FetchRelatives(query)
	if err != nil {
		return nil, err
	}

	mr := NewMessageReply()
	mr.MessageId = c.Id
	q := query
	q.Limit = 3
	replies, err := mr.List(query)
	if err != nil {
		return nil, err
	}

	repliesCount, err := mr.Count()
	if err != nil {
		return nil, err
	}
	cmc.RepliesCount = repliesCount

	cmc.IsFollowed, err = c.CheckIsMessageFollowed(query)
	if err != nil {
		return nil, err
	}

	populatedChannelMessagesReplies := make([]*ChannelMessageContainer, len(replies))
	for rl := 0; rl < len(replies); rl++ {
		cmrc, err := replies[rl].FetchRelatives(query)
		if err != nil {
			return nil, err
		}
		populatedChannelMessagesReplies[rl] = cmrc
	}

	cmc.Replies = populatedChannelMessagesReplies
	return cmc, nil
}

func (c *ChannelMessage) CheckIsMessageFollowed(query *Query) (bool, error) {
	channel := NewChannel()
	if err := channel.FetchPinnedActivityChannel(query.AccountId, query.GroupName); err != nil {
		if err == gorm.RecordNotFound {
			return false, nil
		}
		return false, err
	}

	cml := NewChannelMessageList()
	q := &bongo.Query{
		Selector: map[string]interface{}{
			"channel_id": channel.Id,
			"message_id": c.Id,
		},
	}
	if err := cml.One(q); err != nil {
		if err == gorm.RecordNotFound {
			return false, nil
		}

		return false, err
	}

	return true, nil
}

func (c *ChannelMessage) BuildEmptyMessageContainer() (*ChannelMessageContainer, error) {
	if c.Id == 0 {
		return nil, errors.New("Channel message id is not set")
	}
	container := NewChannelMessageContainer()
	container.Message = c

	oldId, err := AccountOldIdById(c.AccountId)
	if err != nil {
		return nil, err
	}

	container.AccountOldId = oldId

	interactionContainer := NewInteractionContainer()
	interactionContainer.ActorsPreview = make([]string, 0)
	interactionContainer.IsInteracted = false
	interactionContainer.ActorsCount = 0

	container.Interactions = make(map[string]*InteractionContainer)
	container.Interactions["like"] = interactionContainer

	return container, nil
}

func (c *ChannelMessage) FetchRelatives(query *Query) (*ChannelMessageContainer, error) {
	container, err := c.BuildEmptyMessageContainer()
	if err != nil {
		return nil, err
	}

	i := NewInteraction()
	i.MessageId = c.Id

	// get preview
	query.Type = "like"
	query.Limit = 3
	interactorIds, err := i.List(query)
	if err != nil {
		return nil, err
	}

	oldIds, err := FetchOldIdsByAccountIds(interactorIds)
	if err != nil {
		return nil, err
	}

	interactionContainer := NewInteractionContainer()
	interactionContainer.ActorsPreview = oldIds

	// check if the current user is interacted in this thread
	isInteracted, err := i.IsInteracted(query.AccountId)
	if err != nil {
		return nil, err
	}

	interactionContainer.IsInteracted = isInteracted

	// fetch interaction count
	count, err := i.Count(query.Type)
	if err != nil {
		return nil, err
	}

	interactionContainer.ActorsCount = count

	container.Interactions["like"] = interactionContainer
	return container, nil
}

func generateMessageListQuery(channelId int64, q *Query) *bongo.Query {
	messageType := q.Type
	if messageType == "" {
		messageType = ChannelMessage_TYPE_POST
	}

	return &bongo.Query{
		Selector: map[string]interface{}{
			"account_id":         q.AccountId,
			"initial_channel_id": channelId,
			"type_constant":      messageType,
		},
		Pagination: *bongo.NewPagination(q.Limit, q.Skip),
		Sort: map[string]string{
			"created_at": "DESC",
		},
	}
}

func (c *ChannelMessage) FetchMessagesByChannelId(channelId int64, q *Query) ([]ChannelMessage, error) {
	query := generateMessageListQuery(channelId, q)

	var messages []ChannelMessage
	if err := c.Some(&messages, query); err != nil {
		return nil, err
	}

	if messages == nil {
		return make([]ChannelMessage, 0), nil
	}
	return messages, nil
}

func (c *ChannelMessage) GetMentionedUsernames() []string {
	flattened := make([]string, 0)

	res := mentionRegex.FindAllStringSubmatch(c.Body, -1)
	if len(res) == 0 {
		return flattened
	}

	participants := map[string]struct{}{}
	// remove duplicate mentions
	for _, ele := range res {
		participants[ele[1]] = struct{}{}
	}

	for participant := range participants {
		flattened = append(flattened, participant)
	}

	return flattened
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"

	"github.com/RangelReale/osin"
	"github.com/osin-mongo-storage/mgostore"
	"gopkg.in/mgo.v2"
)

type Oauth struct {
	sconfig *osin.ServerConfig
	server  *osin.Server
	Storage *mgostore.MongoStorage
}

func (o *Oauth) AuthorizeClientAuthorizeClient(w http.ResponseWriter, r *http.Request) {
	server := oauth.server
	resp := server.NewResponse()
	if ar := server.HandleAuthorizeRequest(resp, r); ar != nil {
		// if !example.HandleLoginPage(ar, w, r) {
		// 	return
		// }
		// ar.UserData = UserData{"Login": "test"}
		// ar.Authorized = true
		// server.FinishAuthorizeRequest(resp, r, ar)

		//
		// HANDLE LOGIN PAGE HERE !!!
		//
	}
	if resp.IsError && resp.InternalError != nil {
		fmt.Printf("ERROR: %s\n", resp.InternalError)
	}
	if !resp.IsError {
		resp.Output["custom_parameter"] = 187723
	}
	osin.OutputJSON(resp, w, r)
}

func (o *Oauth) GenerateToken(w http.ResponseWriter, r *http.Request) {
	server := oauth.server
	resp := server.NewResponse()
	if ar := server.HandleAccessRequest(resp, r); ar != nil {
		switch ar.Type {
		case osin.AUTHORIZATION_CODE:
			ar.Authorized = true
		case osin.REFRESH_TOKEN:
			ar.Authorized = true
		case osin.CLIENT_CREDENTIALS:
			ar.Authorized = true
		}
		server.FinishAccessRequest(resp, r, ar)
	}
	if resp.IsError && resp.InternalError != nil {
		fmt.Printf("ERROR: %s\n", resp.InternalError)
	}
	if !resp.IsError {
		resp.Output["custom_parameter"] = 19923
	}
	osin.OutputJSON(resp, w, r)
}

func NewOAuthHandler(session *mgo.Session, dbName string) *Oauth {
	sconfig := osin.NewServerConfig()
	sconfig.AllowedAuthorizeTypes = osin.AllowedAuthorizeType{osin.CODE, osin.TOKEN}
	sconfig.AllowedAccessTypes = osin.AllowedAccessType{osin.AUTHORIZATION_CODE,
		osin.REFRESH_TOKEN, osin.PASSWORD, osin.CLIENT_CREDENTIALS, osin.ASSERTION}
	sconfig.AllowGetAccessRequest = true
	storage := mgostore.New(session, dbName)
	server := osin.NewServer(sconfig, storage)

	// return &Oauth{sconfig, server, storage}

	return &Oauth{
		sconfig: sconfig,
		server:  server,
		Storage: storage,
	}

}

///////

///////
/////
///////
//////
//////
/////
//////

//////

/// THIS PART IS JUST FOR TESTING
// WILL BE REMOVED !!
func main() {
	// TestStorage implements the "osin.Storage" interface
	server := osin.NewServer(osin.NewServerConfig(), &TestStorage{})

	// Authorization code endpoint
	http.HandleFunc("/authorize", func(w http.ResponseWriter, r *http.Request) {
		resp := server.NewResponse()
		defer resp.Close()

		if ar := server.HandleAuthorizeRequest(resp, r); ar != nil {

			// HANDLE LOGIN PAGE HERE

			ar.Authorized = true
			server.FinishAuthorizeRequest(resp, r, ar)
		}
		osin.OutputJSON(resp, w, r)
	})

	// Access token endpoint
	http.HandleFunc("/token", func(w http.ResponseWriter, r *http.Request) {
		resp := server.NewResponse()
		defer resp.Close()

		if ar := server.HandleAccessRequest(resp, r); ar != nil {
			ar.Authorized = true
			server.FinishAccessRequest(resp, r, ar)
		}
		osin.OutputJSON(resp, w, r)
	})

	http.ListenAndServe(":14000", nil)

}
<commit_msg>go/oauth: move oauthHandler to the handlers file<commit_after>package main

import (
	"fmt"
	"net/http"

	"github.com/RangelReale/osin"
	"github.com/osin-mongo-storage/mgostore"
)

type Oauth struct {
	sconfig *osin.ServerConfig
	server  *osin.Server
	Storage *mgostore.MongoStorage
}

func (o *Oauth) AuthorizeClientAuthorizeClient(w http.ResponseWriter, r *http.Request) {
	server := oauth.server
	resp := server.NewResponse()
	if ar := server.HandleAuthorizeRequest(resp, r); ar != nil {
		// if !example.HandleLoginPage(ar, w, r) {
		// 	return
		// }
		// ar.UserData = UserData{"Login": "test"}
		// ar.Authorized = true
		// server.FinishAuthorizeRequest(resp, r, ar)

		//
		// HANDLE LOGIN PAGE HERE !!!
		//
	}
	if resp.IsError && resp.InternalError != nil {
		fmt.Printf("ERROR: %s\n", resp.InternalError)
	}
	if !resp.IsError {
		resp.Output["custom_parameter"] = 187723
	}
	osin.OutputJSON(resp, w, r)
}

func (o *Oauth) GenerateToken(w http.ResponseWriter, r *http.Request) {
	server := oauth.server
	resp := server.NewResponse()
	if ar := server.HandleAccessRequest(resp, r); ar != nil {
		switch ar.Type {
		case osin.AUTHORIZATION_CODE:
			ar.Authorized = true
		case osin.REFRESH_TOKEN:
			ar.Authorized = true
		case osin.CLIENT_CREDENTIALS:
			ar.Authorized = true
		}
		server.FinishAccessRequest(resp, r, ar)
	}
	if resp.IsError && resp.InternalError != nil {
		fmt.Printf("ERROR: %s\n", resp.InternalError)
	}
	if !resp.IsError {
		resp.Output["custom_parameter"] = 19923
	}
	osin.OutputJSON(resp, w, r)
}

///////

///////
/////
///////
//////
//////
/////
//////

//////

/// THIS PART IS JUST FOR TESTING
// WILL BE REMOVED !!
func main() {
	// TestStorage implements the "osin.Storage" interface
	server := osin.NewServer(osin.NewServerConfig(), &TestStorage{})

	// Authorization code endpoint
	http.HandleFunc("/authorize", func(w http.ResponseWriter, r *http.Request) {
		resp := server.NewResponse()
		defer resp.Close()

		if ar := server.HandleAuthorizeRequest(resp, r); ar != nil {

			// HANDLE LOGIN PAGE HERE

			ar.Authorized = true
			server.FinishAuthorizeRequest(resp, r, ar)
		}
		osin.OutputJSON(resp, w, r)
	})

	// Access token endpoint
	http.HandleFunc("/token", func(w http.ResponseWriter, r *http.Request) {
		resp := server.NewResponse()
		defer resp.Close()

		if ar := server.HandleAccessRequest(resp, r); ar != nil {
			ar.Authorized = true
			server.FinishAccessRequest(resp, r, ar)
		}
		osin.OutputJSON(resp, w, r)
	})

	http.ListenAndServe(":14000", nil)

}
<|endoftext|>


<commit_before>package arel

type SqlAst interface {
	CreateTrue() *TrueNode
	CreateFalse() *FalseNode
	CreateTableAlias(*TableAliasNode, string) *TableAliasNode
	CreateJoin(string) *JoinNode
	CreateAnd([]interface{}) *AndNode
	CreateOn(string) *OnNode
	CreateGrouping(string) *GroupingNode
}

type FactoryMethods struct{}

func (f *FactoryMethods) CreateTrue() *TrueNode {
	return NewTrueNode()
}

func (f *FactoryMethods) CreateFalse() *FalseNode {
	return NewFalseNode()
}

func (f *FactoryMethods) CreateTableAlias(relation *Table, name string) *TableAliasNode {
	return NewTableAliasNode(relation, name)
}

func (f *FactoryMethods) CreateJoin(to string) *JoinNode {
	return &JoinNode{}
}

func (f *FactoryMethods) CreateAnd(clauses []interface{}) *AndNode {
	return NewAndNode()
}

func (f *FactoryMethods) CreateOn(expr string) *OnNode {
	return NewOnNode()
}

func (f *FactoryMethods) CreateGrouping(expr string) *GroupingNode {
	return NewGroupingNode()
}
<commit_msg>Saved file to update build<commit_after>package arel

type SqlAst interface {
	CreateTrue() *TrueNode
	CreateFalse() *FalseNode
	CreateTableAlias(*TableAliasNode, string) *TableAliasNode
	CreateJoin(string) *JoinNode
	CreateAnd([]interface{}) *AndNode
	CreateOn(string) *OnNode
	CreateGrouping(string) *GroupingNode
}
<|endoftext|>


<commit_before>package api

import (
	"encoding/json"
	"errors"
	"fmt"
	"koding/db/mongodb/modelhelper"
	"net/http"
	"net/url"
	"socialapi/models"
	"socialapi/workers/common/response"
	"strings"

	"github.com/nlopes/slack"

	"golang.org/x/oauth2"
	"gopkg.in/mgo.v2"
)

const slackAway = "away"

// Slack holds runtime config for slack OAuth system
type Slack struct {
	Hostname          string
	Protocol          string
	VerificationToken string
	OAuthConf         *oauth2.Config
}

// SlackMessageRequest carries message creation request from client side
type SlackMessageRequest struct {
	Channel string
	Text    string
	Params  slack.PostMessageParameters
}

// Send initiates Slack OAuth
func (s *Slack) Send(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) {
	if !context.IsLoggedIn() {
		return response.NewBadRequest(models.ErrNotLoggedIn)
	}

	session, err := models.Cache.Session.ById(context.Client.SessionID)
	if err != nil {
		return response.NewBadRequest(models.ErrNotLoggedIn)
	}

	url := s.OAuthConf.AuthCodeURL(session.Id.Hex(), oauth2.AccessTypeOffline)
	h.Set("Location", url)
	return http.StatusTemporaryRedirect, h, nil, nil

}

// Callback handler is used for handling redirection requests from Slack API
//
// If we can get the token successfully, then we store user's token in mongo in
// Callback handler
func (s *Slack) Callback(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) {
	state := u.Query().Get("state")
	if state == "" {
		return response.NewBadRequest(errors.New("state is not set"))
	}

	session, err := modelhelper.GetSessionById(state)
	if err != nil {
		return response.NewBadRequest(models.ErrNotLoggedIn)
	}

	redirectURL, err := url.Parse(s.OAuthConf.RedirectURL)
	if err != nil {
		return response.NewBadRequest(err)
	}

	// we want to redirect slacks redirection into our success handler with team
	// name included in the redirection url, this is required because user does
	// not need to be logged in plain koding.com doamin
	// eg: dev.koding.com:8090/api/social/slack/oauth/callback?<query params>
	// 			should be redirected to
	// 		teamname.dev.koding.com:8090/api/social/slack/oauth/success?<query params>

	// set incoming request's query params into redirected url
	redirectURL.RawQuery = u.Query().Encode()

	// change subdomain if not only it is koding
	if session.GroupName != models.Channel_KODING_NAME {
		// set team's subdomain
		redirectURL.Host = fmt.Sprintf("%s.%s", session.GroupName, redirectURL.Host)
	}

	// replace 'callback' with 'success'
	redirectURL.Path = strings.Replace(redirectURL.Path, "callback", "success", -1)

	h.Set("Location", redirectURL.String())
	return http.StatusTemporaryRedirect, h, nil, nil
}

// Success handler is used for handling redirection requests from Callback handler
//
// We need this for handling the internal redirection of team requests
func (s *Slack) Success(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) {
	// get session data from state
	state := u.Query().Get("state")
	if state == "" {
		return response.NewBadRequest(errors.New("state is not set"))
	}

	session, err := modelhelper.GetSessionById(state)
	if err != nil {
		return response.NewBadRequest(models.ErrNotLoggedIn)
	}

	// get user info
	user, err := modelhelper.GetUser(session.Username)
	if err != nil && err != mgo.ErrNotFound {
		return response.NewBadRequest(err)
	}

	if err == mgo.ErrNotFound {
		return response.NewBadRequest(err)
	}

	// start exchanging code for a token
	code := u.Query().Get("code")
	if code == "" {
		return response.NewBadRequest(errors.New("code is not set"))
	}

	token, err := s.OAuthConf.Exchange(oauth2.NoContext, code)
	if err != nil {
		return response.NewBadRequest(err)
	}

	// update the slack data
	if err := updateUserSlackToken(user, session.GroupName, token.AccessToken); err != nil {
		return response.NewBadRequest(err)
	}

	h.Set("Location", "/Admin/Invitations/Slack")
	return http.StatusTemporaryRedirect, h, nil, nil
}

// ListUsers lists users of a slack team
func (s *Slack) ListUsers(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) {
	if !context.IsLoggedIn() {
		return response.NewBadRequest(models.ErrNotLoggedIn)
	}

	token, err := getSlackToken(context)
	if err != nil {
		return response.NewBadRequest(err)
	}

	return response.HandleResultAndError(getUsers(token))
}

// ListChannels lists the channels of a slack team
func (s *Slack) ListChannels(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) {
	if !context.IsLoggedIn() {
		return response.NewBadRequest(models.ErrNotLoggedIn)
	}

	token, err := getSlackToken(context)
	if err != nil {
		return response.NewBadRequest(err)
	}

	return response.HandleResultAndError(getChannels(token))
}

// TeamInfo shows basic info regarding a slack team
func (s *Slack) TeamInfo(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) {
	if !context.IsLoggedIn() {
		return response.NewBadRequest(models.ErrNotLoggedIn)
	}

	token, err := getSlackToken(context)
	if err != nil {
		return response.NewBadRequest(err)
	}

	return response.HandleResultAndError(getTeamInfo(token))
}

// PostMessage posts a message to a slack channel/group
func (s *Slack) PostMessage(u *url.URL, h http.Header, req *SlackMessageRequest, context *models.Context) (int, http.Header, interface{}, error) {
	if !context.IsLoggedIn() {
		return response.NewBadRequest(models.ErrNotLoggedIn)
	}

	token, err := getSlackToken(context)
	if err != nil {
		return response.NewBadRequest(err)
	}
	return response.HandleResultAndError(postMessage(token, req))
}

// SlashCommand handles slash commands coming from slack
//
// Note: this is experimental, on prod instances this will just say hi,
// otherwise will output incoming request
func (s *Slack) SlashCommand(w http.ResponseWriter, req *http.Request) {
	if err := req.ParseForm(); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	command, err := newSlashCommandFromURLValues(req.PostForm)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	if command.Token != s.VerificationToken {
		errMessage := fmt.Sprintf("request from unidentified source: %s - %s", command.Token, req.Host)
		http.Error(w, errMessage, http.StatusBadRequest)
		return
	}

	fmt.Fprintln(w, "hi from koding bot!")

	if command.Robot != "koding" {
		fmt.Fprintln(w, "here is some debug log for non-prod requests")
		fmt.Fprintln(w)

		if err := json.NewEncoder(w).Encode(command); err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
	}
}
<commit_msg>socialapi/slack: if user has no token check its group<commit_after>package api

import (
	"encoding/json"
	"errors"
	"fmt"
	"koding/db/mongodb/modelhelper"
	"net/http"
	"net/url"
	"socialapi/models"
	"socialapi/workers/common/response"
	"strings"

	"github.com/nlopes/slack"

	"golang.org/x/oauth2"
	"gopkg.in/mgo.v2"
)

const slackAway = "away"

// Slack holds runtime config for slack OAuth system
type Slack struct {
	Hostname          string
	Protocol          string
	VerificationToken string
	OAuthConf         *oauth2.Config
}

// SlackMessageRequest carries message creation request from client side
type SlackMessageRequest struct {
	Channel string
	Text    string
	Params  slack.PostMessageParameters
}

// Send initiates Slack OAuth
func (s *Slack) Send(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) {
	if !context.IsLoggedIn() {
		return response.NewBadRequest(models.ErrNotLoggedIn)
	}

	session, err := models.Cache.Session.ById(context.Client.SessionID)
	if err != nil {
		return response.NewBadRequest(models.ErrNotLoggedIn)
	}

	url := s.OAuthConf.AuthCodeURL(session.Id.Hex(), oauth2.AccessTypeOffline)
	h.Set("Location", url)
	return http.StatusTemporaryRedirect, h, nil, nil

}

// Callback handler is used for handling redirection requests from Slack API
//
// If we can get the token successfully, then we store user's token in mongo in
// Callback handler
func (s *Slack) Callback(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) {
	state := u.Query().Get("state")
	if state == "" {
		return response.NewBadRequest(errors.New("state is not set"))
	}

	session, err := modelhelper.GetSessionById(state)
	if err != nil {
		return response.NewBadRequest(models.ErrNotLoggedIn)
	}

	redirectURL, err := url.Parse(s.OAuthConf.RedirectURL)
	if err != nil {
		return response.NewBadRequest(err)
	}

	// we want to redirect slacks redirection into our success handler with team
	// name included in the redirection url, this is required because user does
	// not need to be logged in plain koding.com doamin
	// eg: dev.koding.com:8090/api/social/slack/oauth/callback?<query params>
	// 			should be redirected to
	// 		teamname.dev.koding.com:8090/api/social/slack/oauth/success?<query params>

	// set incoming request's query params into redirected url
	redirectURL.RawQuery = u.Query().Encode()

	// change subdomain if not only it is koding
	if session.GroupName != models.Channel_KODING_NAME {
		// set team's subdomain
		redirectURL.Host = fmt.Sprintf("%s.%s", session.GroupName, redirectURL.Host)
	}

	// replace 'callback' with 'success'
	redirectURL.Path = strings.Replace(redirectURL.Path, "callback", "success", -1)

	h.Set("Location", redirectURL.String())
	return http.StatusTemporaryRedirect, h, nil, nil
}

// Success handler is used for handling redirection requests from Callback handler
//
// We need this for handling the internal redirection of team requests
func (s *Slack) Success(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) {
	// get session data from state
	state := u.Query().Get("state")
	if state == "" {
		return response.NewBadRequest(errors.New("state is not set"))
	}

	session, err := modelhelper.GetSessionById(state)
	if err != nil {
		return response.NewBadRequest(models.ErrNotLoggedIn)
	}

	// get user info
	user, err := modelhelper.GetUser(session.Username)
	if err != nil && err != mgo.ErrNotFound {
		return response.NewBadRequest(err)
	}

	if err == mgo.ErrNotFound {
		return response.NewBadRequest(err)
	}

	// start exchanging code for a token
	code := u.Query().Get("code")
	if code == "" {
		return response.NewBadRequest(errors.New("code is not set"))
	}

	token, err := s.OAuthConf.Exchange(oauth2.NoContext, code)
	if err != nil {
		return response.NewBadRequest(err)
	}

	// update the slack data
	if err := updateUserSlackToken(user, session.GroupName, token.AccessToken); err != nil {
		return response.NewBadRequest(err)
	}

	h.Set("Location", "/Admin/Invitations/Slack")
	return http.StatusTemporaryRedirect, h, nil, nil
}

// ListUsers lists users of a slack team
func (s *Slack) ListUsers(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) {
	if !context.IsLoggedIn() {
		return response.NewBadRequest(models.ErrNotLoggedIn)
	}

	var token string
	var groupToken string

	userToken, err := getSlackToken(context)
	if err != nil {
		groupToken, err = getAynUserTokenFromGroup(context)
		if err != nil {
			return response.NewBadRequest(err)
		}
	}

	if userToken != "" {
		token = userToken
	} else {
		token = groupToken
	}

	return response.HandleResultAndError(getUsers(token))
}

// ListChannels lists the channels of a slack team
func (s *Slack) ListChannels(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) {
	if !context.IsLoggedIn() {
		return response.NewBadRequest(models.ErrNotLoggedIn)
	}

	var token string
	var groupToken string

	userToken, err := getSlackToken(context)
	if err != nil || token == "" {
		groupToken, err = getAynUserTokenFromGroup(context)
		if err != nil {
			return response.NewBadRequest(err)
		}
	}

	if userToken != "" {
		token = userToken
	} else {
		token = groupToken
	}

	return response.HandleResultAndError(getChannels(token))
}

// TeamInfo shows basic info regarding a slack team
func (s *Slack) TeamInfo(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) {
	if !context.IsLoggedIn() {
		return response.NewBadRequest(models.ErrNotLoggedIn)
	}

	token, err := getSlackToken(context)
	if err != nil {
		return response.NewBadRequest(err)
	}

	return response.HandleResultAndError(getTeamInfo(token))
}

// PostMessage posts a message to a slack channel/group
func (s *Slack) PostMessage(u *url.URL, h http.Header, req *SlackMessageRequest, context *models.Context) (int, http.Header, interface{}, error) {
	if !context.IsLoggedIn() {
		return response.NewBadRequest(models.ErrNotLoggedIn)
	}

	token, err := getSlackToken(context)
	if err != nil {
		return response.NewBadRequest(err)
	}
	return response.HandleResultAndError(postMessage(token, req))
}

// SlashCommand handles slash commands coming from slack
//
// Note: this is experimental, on prod instances this will just say hi,
// otherwise will output incoming request
func (s *Slack) SlashCommand(w http.ResponseWriter, req *http.Request) {
	if err := req.ParseForm(); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	command, err := newSlashCommandFromURLValues(req.PostForm)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	if command.Token != s.VerificationToken {
		errMessage := fmt.Sprintf("request from unidentified source: %s - %s", command.Token, req.Host)
		http.Error(w, errMessage, http.StatusBadRequest)
		return
	}

	fmt.Fprintln(w, "hi from koding bot!")

	if command.Robot != "koding" {
		fmt.Fprintln(w, "here is some debug log for non-prod requests")
		fmt.Fprintln(w)

		if err := json.NewEncoder(w).Encode(command); err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
	}
}
<|endoftext|>


<commit_before>// +build OMIT

package main

import "fmt"

func main() {
	var a []int
	printSlice("a", a)

	// append works on nil slices.
	a = append(a, 0)
	printSlice("a", a)

	// the slice grows as needed.
	a = append(a, 1)
	printSlice("a", a)

	// we can add more than one element at a time.
	a = append(a, 2, 3, 4)
	printSlice("a", a)
}

func printSlice(s string, x []int) {
	fmt.Printf("%s len=%d cap=%d %v\n",
		s, len(x), cap(x), x)
}
<commit_msg>[x/tour] content: clarify append code example<commit_after>// +build OMIT

package main

import "fmt"

func main() {
	var s []int
	printSlice(s)

	// append works on nil slices.
	s = append(s, 0)
	printSlice(s)

	// The slice grows as needed.
	s = append(s, 1)
	printSlice(s)

	// We can add more than one element at a time.
	s = append(s, 2, 3, 4)
	printSlice(s)
}

func printSlice(s []int) {
	fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}
<|endoftext|>


<commit_before>package codegen

import (
	"strconv"

	"github.com/llir/llvm/ir"
	"github.com/llir/llvm/ir/value"
)

type ResultType int

const (
	VOID    ResultType = iota // fragment will not produce a value
	VALUE                     // fragment will produce a value
	POINTER                   // fragment will produce a pointer value
)

type FragmentType int

const (
	MODULE FragmentType = iota
	FUNCTIONS
	BLOCKS
	INSTRUCTIONS
)

// Fragment represents a fragment of instructions in asm
type Fragment interface {
	Append(fragment Fragment)
	AppendWithResultPropogation(fragment Fragment)
	GetResultType() ResultType
	GetResult() value.Value
}

type ModuleFragment struct {
	Module *ir.Module
}

func NewModuleFragment(module *ir.Module) *ModuleFragment {
	if module == nil {
		module = ir.NewModule()
	}

	return &ModuleFragment{Module: module}
}

func (moduleFragment *ModuleFragment) Append(fragment Fragment) {
	switch f := fragment.(type) {
	case *ModuleFragment:
		panic("Cannot append module to module")
	case *FunctionsFragment:
		moduleFragment.Module.Funcs = append(moduleFragment.Module.Funcs, f.Functions...)

		for _, function := range f.Functions {
			function.Parent = moduleFragment.Module
		}
	case *BlocksFragment:
		panic("Cannot append blocks to module")
	case *InstructionsFragment:
		panic("Cannot append instructions to module")
	}
}

func (moduleFragment *ModuleFragment) AppendWithResultPropogation(fragment Fragment) {
	moduleFragment.Append(fragment)
}

func (moduleFragment *ModuleFragment) GetResultType() ResultType {
	return VOID
}

func (moduleFragment *ModuleFragment) GetResult() value.Value {
	return nil
}

type FunctionsFragment struct {
	Functions       []*ir.Func
	currentFunction *ir.Func
}

func NewFunctionsFragment() *FunctionsFragment {
	functions := make([]*ir.Func, 0)

	return &FunctionsFragment{Functions: functions, currentFunction: nil}
}

func (functionsFragment *FunctionsFragment) AddFunc(function *ir.Func) {
	if function == nil {
		panic("Cannot add nil function")
	}

	functionsFragment.Functions = append(functionsFragment.Functions, function)
	functionsFragment.currentFunction = function
}

func (functionsFragment *FunctionsFragment) Append(fragment Fragment) {
	switch f := fragment.(type) {
	case *ModuleFragment:
		panic("Cannot append module to function")
	case *FunctionsFragment:
		if f.Functions != nil && len(f.Functions) > 0 {
			functionsFragment.Functions = append(functionsFragment.Functions, f.Functions...)

			functionsFragment.currentFunction = f.currentFunction
		}
	case *BlocksFragment:
		if functionsFragment.currentFunction == nil {
			panic("FunctionsFragment does not contain any function")
		}
		blocks := functionsFragment.currentFunction.Blocks

		// Chain new blocks to existing blocks
		numberOfBlocks := len(blocks)
		if numberOfBlocks > 0 && blocks[numberOfBlocks-1].Term == nil && len(f.Blocks) > 0 {
			blocks[numberOfBlocks-1].NewBr(f.Blocks[0])
		}

		functionsFragment.currentFunction.Blocks = append(blocks, f.Blocks...)

		for _, block := range f.Blocks {
			block.Parent = functionsFragment.currentFunction
		}
	case *InstructionsFragment:
		blockLength := len(functionsFragment.currentFunction.Blocks)
		lastBlock := functionsFragment.currentFunction.Blocks[blockLength-1]
		instructions := lastBlock.Insts

		lastBlock.Insts = append(instructions, f.Instructions...)
	}
}

func (functionsFragment *FunctionsFragment) AppendWithResultPropogation(fragment Fragment) {
	functionsFragment.Append(fragment)
}

func (functionsFragment *FunctionsFragment) GetResultType() ResultType {
	return VOID
}

func (functionsFragment *FunctionsFragment) GetResult() value.Value {
	return nil
}

type BlocksFragment struct {
	Blocks       []*ir.Block
	CurrentBlock *ir.Block
	resultType   ResultType
	resultValue  value.Value
}

func NewBlocksFragment(resultType ResultType) *BlocksFragment {
	blocks := make([]*ir.Block, 0)

	return &BlocksFragment{Blocks: blocks, CurrentBlock: nil, resultType: resultType, resultValue: nil}
}

func (blocksFragment *BlocksFragment) Append(fragment Fragment) {
	switch f := fragment.(type) {
	case *ModuleFragment:
		panic("Cannot append blocks to module")
	case *FunctionsFragment:
		panic("Cannot append blocks to functions")
	case *BlocksFragment:
		if len(f.Blocks) > 0 {
			blocksFragment.ChainBlocks(f.Blocks...)
			blocksFragment.Blocks = append(blocksFragment.Blocks, f.Blocks...)
			blocksFragment.CurrentBlock = f.CurrentBlock
		}

	case *InstructionsFragment:
		blocksFragment.CurrentBlock.Insts = append(blocksFragment.CurrentBlock.Insts, f.Instructions...)
	}
}

func (blocksFragment *BlocksFragment) AppendWithResultPropogation(fragment Fragment) {
	switch f := fragment.(type) {
	case *ModuleFragment:
		panic("Cannot append blocks to module")
	case *FunctionsFragment:
		panic("Cannot append blocks to functions")
	case *BlocksFragment:
		if len(f.Blocks) > 0 {
			blocksFragment.ChainBlocks(f.Blocks...)
			blocksFragment.Blocks = append(blocksFragment.Blocks, f.Blocks...)
			blocksFragment.CurrentBlock = f.CurrentBlock

			blocksFragment.resultType = f.resultType
			blocksFragment.resultValue = f.resultValue
		}

	case *InstructionsFragment:
		blocksFragment.CurrentBlock.Insts = append(blocksFragment.CurrentBlock.Insts, f.Instructions...)
	}
}

func (blocksFragment *BlocksFragment) GetResultType() ResultType {
	return blocksFragment.resultType
}

func (blocksFragment *BlocksFragment) GetResult() value.Value {
	switch blocksFragment.resultType {
	case VOID:
		return nil
	case VALUE, POINTER:
		return blocksFragment.resultValue
	default:
		panic("does not support other result type" + strconv.Itoa((int)(blocksFragment.resultType)))
	}
}

func (blocksFragment *BlocksFragment) NewBlock(name string) {
	newBlock := ir.NewBlock(name)

	blocksFragment.ChainBlocks(newBlock)
	blocksFragment.Blocks = append(blocksFragment.Blocks, newBlock)
	blocksFragment.CurrentBlock = newBlock
}

func (blocksFragment *BlocksFragment) AddBlock(block *ir.Block) {
	if block != nil {
		blocksFragment.ChainBlocks(block)
		blocksFragment.Blocks = append(blocksFragment.Blocks, block)
		blocksFragment.CurrentBlock = block
	}
}

func (blocksFragment *BlocksFragment) ChainBlocks(blocks ...*ir.Block) {
	if blocksFragment.CurrentBlock != nil && blocksFragment.CurrentBlock.Term == nil &&
		blocks != nil && len(blocks) > 0 {
		blocksFragment.CurrentBlock.NewBr(blocks[0])
	}
}

type InstructionsFragment struct {
	Instructions       []ir.Instruction
	currentInstruction *ir.Instruction
	resultType         ResultType
	resultValue        value.Value
}

func NewInstructionsFragment(resultType ResultType) *InstructionsFragment {
	instructions := make([]ir.Instruction, 0)

	return &InstructionsFragment{Instructions: instructions, currentInstruction: nil, resultType: resultType, resultValue: nil}
}

func (instructionsFragment *InstructionsFragment) Append(fragment Fragment) {
	switch f := fragment.(type) {
	case *ModuleFragment:
		panic("Cannot append instructions to module")
	case *FunctionsFragment:
		panic("Cannot append instructions to functions")
	case *BlocksFragment:
		panic("Cannot append instructions to blocks")
	case *InstructionsFragment:
		instructionsFragment.Instructions = append(instructionsFragment.Instructions, f.Instructions...)
		instructionsFragment.currentInstruction = f.currentInstruction
	}
}

func (instructionsFragment *InstructionsFragment) AppendWithResultPropogation(fragment Fragment) {

}

func (instructionsFragment *InstructionsFragment) GetResultType() ResultType {
	return instructionsFragment.resultType
}

func (instructionsFragment *InstructionsFragment) GetResult() value.Value {
	switch instructionsFragment.resultType {
	case VOID:
		return nil
	case VALUE:
		return instructionsFragment.resultValue
	default:
		panic("does not support other result type" + strconv.Itoa((int)(instructionsFragment.resultType)))
	}
}

func (instructionsFragment *InstructionsFragment) AddInstruction(instr ir.Instruction) {
	instructionsFragment.Instructions = append(instructionsFragment.Instructions, instr)
}
<commit_msg>refactoring<commit_after>package codegen

import (
	"strconv"

	"github.com/llir/llvm/ir"
	"github.com/llir/llvm/ir/value"
)

type ResultType int

const (
	VOID    ResultType = iota // fragment will not produce a value
	VALUE                     // fragment will produce a value
	POINTER                   // fragment will produce a pointer value
)

type FragmentType int

const (
	MODULE FragmentType = iota
	FUNCTIONS
	BLOCKS
	INSTRUCTIONS
)

// Fragment represents a fragment of instructions in asm
type Fragment interface {
	Append(fragment Fragment)
	AppendWithResultPropogation(fragment Fragment)
	GetResultType() ResultType
	GetResult() value.Value
}

type ModuleFragment struct {
	Module *ir.Module
}

func NewModuleFragment(module *ir.Module) *ModuleFragment {
	if module == nil {
		module = ir.NewModule()
	}

	return &ModuleFragment{Module: module}
}

func (moduleFragment *ModuleFragment) Append(fragment Fragment) {
	switch f := fragment.(type) {
	case *ModuleFragment:
		panic("Cannot append module to module")
	case *FunctionsFragment:
		moduleFragment.Module.Funcs = append(moduleFragment.Module.Funcs, f.Functions...)

		for _, function := range f.Functions {
			function.Parent = moduleFragment.Module
		}
	case *BlocksFragment:
		panic("Cannot append blocks to module")
	case *InstructionsFragment:
		panic("Cannot append instructions to module")
	}
}

func (moduleFragment *ModuleFragment) AppendWithResultPropogation(fragment Fragment) {
	moduleFragment.Append(fragment)
}

func (moduleFragment *ModuleFragment) GetResultType() ResultType {
	return VOID
}

func (moduleFragment *ModuleFragment) GetResult() value.Value {
	return nil
}

type FunctionsFragment struct {
	Functions       []*ir.Func
	currentFunction *ir.Func
}

func NewFunctionsFragment() *FunctionsFragment {
	functions := make([]*ir.Func, 0)

	return &FunctionsFragment{Functions: functions, currentFunction: nil}
}

func (functionsFragment *FunctionsFragment) AddFunc(function *ir.Func) {
	if function == nil {
		panic("Cannot add nil function")
	}

	functionsFragment.Functions = append(functionsFragment.Functions, function)
	functionsFragment.currentFunction = function
}

func (functionsFragment *FunctionsFragment) Append(fragment Fragment) {
	switch f := fragment.(type) {
	case *ModuleFragment:
		panic("Cannot append module to function")
	case *FunctionsFragment:
		if f.Functions != nil && len(f.Functions) > 0 {
			functionsFragment.Functions = append(functionsFragment.Functions, f.Functions...)

			functionsFragment.currentFunction = f.currentFunction
		}
	case *BlocksFragment:
		if functionsFragment.currentFunction == nil {
			panic("FunctionsFragment does not contain any function")
		}
		blocks := functionsFragment.currentFunction.Blocks

		// Chain new blocks to existing blocks
		numberOfBlocks := len(blocks)
		if numberOfBlocks > 0 && blocks[numberOfBlocks-1].Term == nil && len(f.Blocks) > 0 {
			blocks[numberOfBlocks-1].NewBr(f.Blocks[0])
		}

		functionsFragment.currentFunction.Blocks = append(blocks, f.Blocks...)

		for _, block := range f.Blocks {
			block.Parent = functionsFragment.currentFunction
		}
	case *InstructionsFragment:
		blockLength := len(functionsFragment.currentFunction.Blocks)
		lastBlock := functionsFragment.currentFunction.Blocks[blockLength-1]
		instructions := lastBlock.Insts

		lastBlock.Insts = append(instructions, f.Instructions...)
	}
}

func (functionsFragment *FunctionsFragment) AppendWithResultPropogation(fragment Fragment) {
	functionsFragment.Append(fragment)
}

func (functionsFragment *FunctionsFragment) GetResultType() ResultType {
	return VOID
}

func (functionsFragment *FunctionsFragment) GetResult() value.Value {
	return nil
}

type BlocksFragment struct {
	Blocks       []*ir.Block
	CurrentBlock *ir.Block
	resultType   ResultType
	resultValue  value.Value
}

func NewBlocksFragment(resultType ResultType) *BlocksFragment {
	blocks := make([]*ir.Block, 0)

	return &BlocksFragment{Blocks: blocks, CurrentBlock: nil, resultType: resultType, resultValue: nil}
}

func (blocksFragment *BlocksFragment) Append(fragment Fragment) {
	switch f := fragment.(type) {
	case *ModuleFragment:
		panic("Cannot append blocks to module")
	case *FunctionsFragment:
		panic("Cannot append blocks to functions")
	case *BlocksFragment:
		if len(f.Blocks) > 0 {
			blocksFragment.ChainBlocks(f.Blocks...)
			blocksFragment.Blocks = append(blocksFragment.Blocks, f.Blocks...)
			blocksFragment.CurrentBlock = f.CurrentBlock
		}

	case *InstructionsFragment:
		blocksFragment.CurrentBlock.Insts = append(blocksFragment.CurrentBlock.Insts, f.Instructions...)
	}
}

func (blocksFragment *BlocksFragment) AppendWithResultPropogation(fragment Fragment) {
	switch f := fragment.(type) {
	case *ModuleFragment:
		panic("Cannot append blocks to module")
	case *FunctionsFragment:
		panic("Cannot append blocks to functions")
	case *BlocksFragment:
		if len(f.Blocks) > 0 {
			blocksFragment.ChainBlocks(f.Blocks...)
			blocksFragment.Blocks = append(blocksFragment.Blocks, f.Blocks...)
			blocksFragment.CurrentBlock = f.CurrentBlock

			blocksFragment.resultType = f.resultType
			blocksFragment.resultValue = f.resultValue
		}

	case *InstructionsFragment:
		blocksFragment.CurrentBlock.Insts = append(blocksFragment.CurrentBlock.Insts, f.Instructions...)
	}
}

func (blocksFragment *BlocksFragment) GetResultType() ResultType {
	return blocksFragment.resultType
}

func (blocksFragment *BlocksFragment) GetResult() value.Value {
	switch blocksFragment.resultType {
	case VOID:
		return nil
	case VALUE, POINTER:
		return blocksFragment.resultValue
	default:
		panic("does not support other result type" + strconv.Itoa((int)(blocksFragment.resultType)))
	}
}

func (blocksFragment *BlocksFragment) NewBlock(name string) {
	newBlock := ir.NewBlock(name)

	blocksFragment.ChainBlocks(newBlock)
	blocksFragment.Blocks = append(blocksFragment.Blocks, newBlock)
	blocksFragment.CurrentBlock = newBlock
}

func (blocksFragment *BlocksFragment) AddBlock(block *ir.Block) {
	if block == nil {
		return
	}
	blocksFragment.ChainBlocks(block)
	blocksFragment.Blocks = append(blocksFragment.Blocks, block)
	blocksFragment.CurrentBlock = block

}

func (blocksFragment *BlocksFragment) ChainBlocks(blocks ...*ir.Block) {
	if blocksFragment.CurrentBlock != nil && blocksFragment.CurrentBlock.Term == nil &&
		blocks != nil && len(blocks) > 0 {
		blocksFragment.CurrentBlock.NewBr(blocks[0])
	}
}

type InstructionsFragment struct {
	Instructions       []ir.Instruction
	currentInstruction *ir.Instruction
	resultType         ResultType
	resultValue        value.Value
}

func NewInstructionsFragment(resultType ResultType) *InstructionsFragment {
	instructions := make([]ir.Instruction, 0)

	return &InstructionsFragment{Instructions: instructions, currentInstruction: nil, resultType: resultType, resultValue: nil}
}

func (instructionsFragment *InstructionsFragment) Append(fragment Fragment) {
	switch f := fragment.(type) {
	case *ModuleFragment:
		panic("Cannot append instructions to module")
	case *FunctionsFragment:
		panic("Cannot append instructions to functions")
	case *BlocksFragment:
		panic("Cannot append instructions to blocks")
	case *InstructionsFragment:
		instructionsFragment.Instructions = append(instructionsFragment.Instructions, f.Instructions...)
		instructionsFragment.currentInstruction = f.currentInstruction
	}
}

func (instructionsFragment *InstructionsFragment) AppendWithResultPropogation(fragment Fragment) {

}

func (instructionsFragment *InstructionsFragment) GetResultType() ResultType {
	return instructionsFragment.resultType
}

func (instructionsFragment *InstructionsFragment) GetResult() value.Value {
	switch instructionsFragment.resultType {
	case VOID:
		return nil
	case VALUE:
		return instructionsFragment.resultValue
	default:
		panic("does not support other result type" + strconv.Itoa((int)(instructionsFragment.resultType)))
	}
}

func (instructionsFragment *InstructionsFragment) AddInstruction(instr ir.Instruction) {
	instructionsFragment.Instructions = append(instructionsFragment.Instructions, instr)
}
<|endoftext|>


<commit_before>package rules

import (
	"github.com/gophercloud/gophercloud"
	"github.com/gophercloud/gophercloud/pagination"
)

// ListOpts allows the filtering and sorting of paginated collections through
// the API. Filtering is achieved by passing in struct field values that map to
// the security group attributes you want to see returned. SortKey allows you to
// sort by a particular network attribute. SortDir sets the direction, and is
// either `asc' or `desc'. Marker and Limit are used for pagination.
type ListOpts struct {
	Direction      string `q:"direction"`
	EtherType      string `q:"ethertype"`
	ID             string `q:"id"`
	PortRangeMax   int    `q:"port_range_max"`
	PortRangeMin   int    `q:"port_range_min"`
	Protocol       string `q:"protocol"`
	RemoteGroupID  string `q:"remote_group_id"`
	RemoteIPPrefix string `q:"remote_ip_prefix"`
	SecGroupID     string `q:"security_group_id"`
	TenantID       string `q:"tenant_id"`
	Limit          int    `q:"limit"`
	Marker         string `q:"marker"`
	SortKey        string `q:"sort_key"`
	SortDir        string `q:"sort_dir"`
}

// List returns a Pager which allows you to iterate over a collection of
// security group rules. It accepts a ListOpts struct, which allows you to filter
// and sort the returned collection for greater efficiency.
func List(c *gophercloud.ServiceClient, opts ListOpts) pagination.Pager {
	q, err := gophercloud.BuildQueryString(&opts)
	if err != nil {
		return pagination.Pager{Err: err}
	}
	u := rootURL(c) + q.String()
	return pagination.NewPager(c, u, func(r pagination.PageResult) pagination.Page {
		return SecGroupRulePage{pagination.LinkedPageBase{PageResult: r}}
	})
}

type RuleDirection string
type RuleProtocol string
type RuleEtherType string

// Constants useful for CreateOpts
const (
	DirIngress        RuleDirection = "ingress"
	DirEgress         RuleDirection = "egress"
	ProtocolTCP       RuleProtocol  = "tcp"
	ProtocolUDP       RuleProtocol  = "udp"
	ProtocolICMP      RuleProtocol  = "icmp"
	ProtocolAH        RuleProtocol  = "ah"
	ProtocolDCCP      RuleProtocol  = "dccp"
	ProtocolEGP       RuleProtocol  = "egp"
	ProtocolGRE       RuleProtocol  = "gre"
	ProtocolIGMP      RuleProtocol  = "igmp"
	ProtocolIPv6      RuleProtocol  = "ipv6-encap"
	ProtocolIPv6Frag  RuleProtocol  = "ipv6-frag"
	ProtocolIPv6ICMP  RuleProtocol  = "ipv6-icmp"
	ProtocolIPv6NoNxt RuleProtocol  = "ipv6-nonxt"
	ProtocolIPv6Opts  RuleProtocol  = "ipv6-opts"
	ProtocolOSPF      RuleProtocol  = "ospf"
	ProtocolPGM       RuleProtocol  = "pgm"
	ProtocolRSVP      RuleProtocol  = "rsvp"
	ProtocolSCTP      RuleProtocol  = "sctp"
	ProtocolUDPLite   RuleProtocol  = "udplite"
	ProtocolVRRP      RuleProtocol  = "vrrp"
	EtherType4        RuleEtherType = "IPv4"
	EtherType6        RuleEtherType = "IPv6"
)

// CreateOptsBuilder is what types must satisfy to be used as Create
// options.
type CreateOptsBuilder interface {
	ToSecGroupRuleCreateMap() (map[string]interface{}, error)
}

// CreateOpts contains all the values needed to create a new security group rule.
type CreateOpts struct {
	// Required. Must be either "ingress" or "egress": the direction in which the
	// security group rule is applied.
	Direction RuleDirection `json:"direction" required:"true"`
	// Required. Must be "IPv4" or "IPv6", and addresses represented in CIDR must
	// match the ingress or egress rules.
	EtherType RuleEtherType `json:"ethertype" required:"true"`
	// Required. The security group ID to associate with this security group rule.
	SecGroupID string `json:"security_group_id" required:"true"`
	// Optional. The maximum port number in the range that is matched by the
	// security group rule. The PortRangeMin attribute constrains the PortRangeMax
	// attribute. If the protocol is ICMP, this value must be an ICMP type.
	PortRangeMax int `json:"port_range_max,omitempty"`
	// Optional. The minimum port number in the range that is matched by the
	// security group rule. If the protocol is TCP or UDP, this value must be
	// less than or equal to the value of the PortRangeMax attribute. If the
	// protocol is ICMP, this value must be an ICMP type.
	PortRangeMin int `json:"port_range_min,omitempty"`
	// Optional. The protocol that is matched by the security group rule. Valid
	// values are "tcp", "udp", "icmp" or an empty string.
	Protocol RuleProtocol `json:"protocol,omitempty"`
	// Optional. The remote group ID to be associated with this security group
	// rule. You can specify either RemoteGroupID or RemoteIPPrefix.
	RemoteGroupID string `json:"remote_group_id,omitempty"`
	// Optional. The remote IP prefix to be associated with this security group
	// rule. You can specify either RemoteGroupID or RemoteIPPrefix. This
	// attribute matches the specified IP prefix as the source IP address of the
	// IP packet.
	RemoteIPPrefix string `json:"remote_ip_prefix,omitempty"`
	// Required for admins. Indicates the owner of the VIP.
	TenantID string `json:"tenant_id,omitempty"`
}

// ToSecGroupRuleCreateMap allows CreateOpts to satisfy the CreateOptsBuilder
// interface
func (opts CreateOpts) ToSecGroupRuleCreateMap() (map[string]interface{}, error) {
	return gophercloud.BuildRequestBody(opts, "security_group_rule")
}

// Create is an operation which adds a new security group rule and associates it
// with an existing security group (whose ID is specified in CreateOpts).
func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
	b, err := opts.ToSecGroupRuleCreateMap()
	if err != nil {
		r.Err = err
		return
	}
	_, r.Err = c.Post(rootURL(c), b, &r.Body, nil)
	return
}

// Get retrieves a particular security group rule based on its unique ID.
func Get(c *gophercloud.ServiceClient, id string) (r GetResult) {
	_, r.Err = c.Get(resourceURL(c, id), &r.Body, nil)
	return
}

// Delete will permanently delete a particular security group rule based on its unique ID.
func Delete(c *gophercloud.ServiceClient, id string) (r DeleteResult) {
	_, r.Err = c.Delete(resourceURL(c, id), nil)
	return
}
<commit_msg>update ipv3-encap protocol name<commit_after>package rules

import (
	"github.com/gophercloud/gophercloud"
	"github.com/gophercloud/gophercloud/pagination"
)

// ListOpts allows the filtering and sorting of paginated collections through
// the API. Filtering is achieved by passing in struct field values that map to
// the security group attributes you want to see returned. SortKey allows you to
// sort by a particular network attribute. SortDir sets the direction, and is
// either `asc' or `desc'. Marker and Limit are used for pagination.
type ListOpts struct {
	Direction      string `q:"direction"`
	EtherType      string `q:"ethertype"`
	ID             string `q:"id"`
	PortRangeMax   int    `q:"port_range_max"`
	PortRangeMin   int    `q:"port_range_min"`
	Protocol       string `q:"protocol"`
	RemoteGroupID  string `q:"remote_group_id"`
	RemoteIPPrefix string `q:"remote_ip_prefix"`
	SecGroupID     string `q:"security_group_id"`
	TenantID       string `q:"tenant_id"`
	Limit          int    `q:"limit"`
	Marker         string `q:"marker"`
	SortKey        string `q:"sort_key"`
	SortDir        string `q:"sort_dir"`
}

// List returns a Pager which allows you to iterate over a collection of
// security group rules. It accepts a ListOpts struct, which allows you to filter
// and sort the returned collection for greater efficiency.
func List(c *gophercloud.ServiceClient, opts ListOpts) pagination.Pager {
	q, err := gophercloud.BuildQueryString(&opts)
	if err != nil {
		return pagination.Pager{Err: err}
	}
	u := rootURL(c) + q.String()
	return pagination.NewPager(c, u, func(r pagination.PageResult) pagination.Page {
		return SecGroupRulePage{pagination.LinkedPageBase{PageResult: r}}
	})
}

type RuleDirection string
type RuleProtocol string
type RuleEtherType string

// Constants useful for CreateOpts
const (
	DirIngress        RuleDirection = "ingress"
	DirEgress         RuleDirection = "egress"
	ProtocolTCP       RuleProtocol  = "tcp"
	ProtocolUDP       RuleProtocol  = "udp"
	ProtocolICMP      RuleProtocol  = "icmp"
	ProtocolAH        RuleProtocol  = "ah"
	ProtocolDCCP      RuleProtocol  = "dccp"
	ProtocolEGP       RuleProtocol  = "egp"
	ProtocolGRE       RuleProtocol  = "gre"
	ProtocolIGMP      RuleProtocol  = "igmp"
	ProtocolIPv6Encap RuleProtocol  = "ipv6-encap"
	ProtocolIPv6Frag  RuleProtocol  = "ipv6-frag"
	ProtocolIPv6ICMP  RuleProtocol  = "ipv6-icmp"
	ProtocolIPv6NoNxt RuleProtocol  = "ipv6-nonxt"
	ProtocolIPv6Opts  RuleProtocol  = "ipv6-opts"
	ProtocolOSPF      RuleProtocol  = "ospf"
	ProtocolPGM       RuleProtocol  = "pgm"
	ProtocolRSVP      RuleProtocol  = "rsvp"
	ProtocolSCTP      RuleProtocol  = "sctp"
	ProtocolUDPLite   RuleProtocol  = "udplite"
	ProtocolVRRP      RuleProtocol  = "vrrp"
	EtherType4        RuleEtherType = "IPv4"
	EtherType6        RuleEtherType = "IPv6"
)

// CreateOptsBuilder is what types must satisfy to be used as Create
// options.
type CreateOptsBuilder interface {
	ToSecGroupRuleCreateMap() (map[string]interface{}, error)
}

// CreateOpts contains all the values needed to create a new security group rule.
type CreateOpts struct {
	// Required. Must be either "ingress" or "egress": the direction in which the
	// security group rule is applied.
	Direction RuleDirection `json:"direction" required:"true"`
	// Required. Must be "IPv4" or "IPv6", and addresses represented in CIDR must
	// match the ingress or egress rules.
	EtherType RuleEtherType `json:"ethertype" required:"true"`
	// Required. The security group ID to associate with this security group rule.
	SecGroupID string `json:"security_group_id" required:"true"`
	// Optional. The maximum port number in the range that is matched by the
	// security group rule. The PortRangeMin attribute constrains the PortRangeMax
	// attribute. If the protocol is ICMP, this value must be an ICMP type.
	PortRangeMax int `json:"port_range_max,omitempty"`
	// Optional. The minimum port number in the range that is matched by the
	// security group rule. If the protocol is TCP or UDP, this value must be
	// less than or equal to the value of the PortRangeMax attribute. If the
	// protocol is ICMP, this value must be an ICMP type.
	PortRangeMin int `json:"port_range_min,omitempty"`
	// Optional. The protocol that is matched by the security group rule. Valid
	// values are "tcp", "udp", "icmp" or an empty string.
	Protocol RuleProtocol `json:"protocol,omitempty"`
	// Optional. The remote group ID to be associated with this security group
	// rule. You can specify either RemoteGroupID or RemoteIPPrefix.
	RemoteGroupID string `json:"remote_group_id,omitempty"`
	// Optional. The remote IP prefix to be associated with this security group
	// rule. You can specify either RemoteGroupID or RemoteIPPrefix. This
	// attribute matches the specified IP prefix as the source IP address of the
	// IP packet.
	RemoteIPPrefix string `json:"remote_ip_prefix,omitempty"`
	// Required for admins. Indicates the owner of the VIP.
	TenantID string `json:"tenant_id,omitempty"`
}

// ToSecGroupRuleCreateMap allows CreateOpts to satisfy the CreateOptsBuilder
// interface
func (opts CreateOpts) ToSecGroupRuleCreateMap() (map[string]interface{}, error) {
	return gophercloud.BuildRequestBody(opts, "security_group_rule")
}

// Create is an operation which adds a new security group rule and associates it
// with an existing security group (whose ID is specified in CreateOpts).
func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
	b, err := opts.ToSecGroupRuleCreateMap()
	if err != nil {
		r.Err = err
		return
	}
	_, r.Err = c.Post(rootURL(c), b, &r.Body, nil)
	return
}

// Get retrieves a particular security group rule based on its unique ID.
func Get(c *gophercloud.ServiceClient, id string) (r GetResult) {
	_, r.Err = c.Get(resourceURL(c, id), &r.Body, nil)
	return
}

// Delete will permanently delete a particular security group rule based on its unique ID.
func Delete(c *gophercloud.ServiceClient, id string) (r DeleteResult) {
	_, r.Err = c.Delete(resourceURL(c, id), nil)
	return
}
<|endoftext|>


<commit_before>package azuread

import (
	"fmt"
	"log"

	"github.com/Azure/azure-sdk-for-go/services/graphrbac/1.6/graphrbac"
	"github.com/google/uuid"
	"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
	"github.com/hashicorp/terraform-plugin-sdk/helper/validation"

	"github.com/terraform-providers/terraform-provider-azuread/azuread/helpers/ar"
	"github.com/terraform-providers/terraform-provider-azuread/azuread/helpers/graph"
	"github.com/terraform-providers/terraform-provider-azuread/azuread/helpers/p"
	"github.com/terraform-providers/terraform-provider-azuread/azuread/helpers/slices"
	"github.com/terraform-providers/terraform-provider-azuread/azuread/helpers/tf"
	"github.com/terraform-providers/terraform-provider-azuread/azuread/helpers/validate"
)

func resourceGroup() *schema.Resource {
	return &schema.Resource{
		Create: resourceGroupCreate,
		Read:   resourceGroupRead,
		Update: resourceGroupUpdate,
		Delete: resourceGroupDelete,

		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"name": {
				Type:         schema.TypeString,
				Required:     true,
				ForceNew:     true,
				ValidateFunc: validation.NoZeroValues,
			},

			"description": {
				Type:     schema.TypeString,
				ForceNew: true, // there is no update method availible in the SDK
				Optional: true,
			},

			"members": {
				Type:     schema.TypeSet,
				Optional: true,
				Computed: true,
				Set:      schema.HashString,
				Elem: &schema.Schema{
					Type:         schema.TypeString,
					ValidateFunc: validate.UUID,
				},
			},

			"owners": {
				Type:     schema.TypeSet,
				Optional: true,
				Computed: true,
				Set:      schema.HashString,
				Elem: &schema.Schema{
					Type:         schema.TypeString,
					ValidateFunc: validate.UUID,
				},
			},

			"object_id": {
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

func resourceGroupCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*ArmClient).groupsClient
	ctx := meta.(*ArmClient).StopContext

	name := d.Get("name").(string)

	properties := graphrbac.GroupCreateParameters{
		DisplayName:          &name,
		MailEnabled:          p.Bool(false),                 // we're defaulting to false, as the API currently only supports the creation of non-mail enabled security groups.
		MailNickname:         p.String(uuid.New().String()), // this matches the portal behaviour
		SecurityEnabled:      p.Bool(true),                  // we're defaulting to true, as the API currently only supports the creation of non-mail enabled security groups.
		AdditionalProperties: make(map[string]interface{}),
	}

	if v, ok := d.GetOk("description"); ok {
		properties.AdditionalProperties["description"] = v.(string)
	}

	group, err := client.Create(ctx, properties)
	if err != nil {
		return fmt.Errorf("Error creating Group (%q): %+v", name, err)
	}
	if group.ObjectID == nil {
		return fmt.Errorf("nil Group ID for %q: %+v", name, err)
	}

	d.SetId(*group.ObjectID)

	// Add members if specified
	if v, ok := d.GetOk("members"); ok {
		members := tf.ExpandStringSlicePtr(v.(*schema.Set).List())

		// we could lock here against the group member resource, but they should not be used together (todo conflicts with at a resource level?)
		if err := graph.GroupAddMembers(client, ctx, *group.ObjectID, *members); err != nil {
			return err
		}
	}

	// Add owners if specified
	if v, ok := d.GetOk("owners"); ok {
		members := tf.ExpandStringSlicePtr(v.(*schema.Set).List())
		if err := graph.GroupAddOwners(client, ctx, *group.ObjectID, *members); err != nil {
			return err
		}
	}

	_, err = graph.WaitForCreationReplication(func() (interface{}, error) {
		return client.Get(ctx, *group.ObjectID)
	})
	if err != nil {
		return fmt.Errorf("Error waiting for Group (%s) with ObjectId %q: %+v", name, *group.ObjectID, err)
	}

	return resourceGroupRead(d, meta)
}

func resourceGroupRead(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*ArmClient).groupsClient
	ctx := meta.(*ArmClient).StopContext

	resp, err := client.Get(ctx, d.Id())
	if err != nil {
		if ar.ResponseWasNotFound(resp.Response) {
			log.Printf("[DEBUG] Azure AD group with id %q was not found - removing from state", d.Id())
			d.SetId("")
			return nil
		}

		return fmt.Errorf("Error retrieving Azure AD Group with ID %q: %+v", d.Id(), err)
	}

	d.Set("name", resp.DisplayName)
	d.Set("object_id", resp.ObjectID)

	if v, ok := resp.AdditionalProperties["description"]; ok {
		d.Set("description", v.(string))
	}

	members, err := graph.GroupAllMembers(client, ctx, d.Id())
	if err != nil {
		return err
	}
	d.Set("members", members)

	owners, err := graph.GroupAllOwners(client, ctx, d.Id())
	if err != nil {
		return err
	}
	d.Set("owners", owners)

	return nil
}

func resourceGroupUpdate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*ArmClient).groupsClient
	ctx := meta.(*ArmClient).StopContext

	if v, ok := d.GetOkExists("members"); ok && d.HasChange("members") {
		existingMembers, err := graph.GroupAllMembers(client, ctx, d.Id())
		if err != nil {
			return err
		}

		desiredMembers := *tf.ExpandStringSlicePtr(v.(*schema.Set).List())
		membersForRemoval := slices.Difference(existingMembers, desiredMembers)
		membersToAdd := slices.Difference(desiredMembers, existingMembers)

		for _, existingMember := range membersForRemoval {
			log.Printf("[DEBUG] Removing member with id %q from Azure AD group with id %q", existingMember, d.Id())
			if resp, err := client.RemoveMember(ctx, d.Id(), existingMember); err != nil {
				if !ar.ResponseWasNotFound(resp) {
					return fmt.Errorf("Error Deleting group member %q from Azure AD Group with ID %q: %+v", existingMember, d.Id(), err)
				}
			}
		}

		if err := graph.GroupAddMembers(client, ctx, d.Id(), membersToAdd); err != nil {
			return err
		}
	}

	if v, ok := d.GetOkExists("owners"); ok && d.HasChange("owners") {
		existingOwners, err := graph.GroupAllOwners(client, ctx, d.Id())
		if err != nil {
			return err
		}

		desiredOwners := *tf.ExpandStringSlicePtr(v.(*schema.Set).List())
		ownersForRemoval := slices.Difference(existingOwners, desiredOwners)
		ownersToAdd := slices.Difference(desiredOwners, existingOwners)

		for _, ownerToDelete := range ownersForRemoval {
			log.Printf("[DEBUG] Removing member with id %q from Azure AD group with id %q", ownerToDelete, d.Id())
			if resp, err := client.RemoveOwner(ctx, d.Id(), ownerToDelete); err != nil {
				if !ar.ResponseWasNotFound(resp) {
					return fmt.Errorf("Error Deleting group member %q from Azure AD Group with ID %q: %+v", ownerToDelete, d.Id(), err)
				}
			}
		}

		if err := graph.GroupAddOwners(client, ctx, d.Id(), ownersToAdd); err != nil {
			return err
		}
	}

	return resourceGroupRead(d, meta)
}

func resourceGroupDelete(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*ArmClient).groupsClient
	ctx := meta.(*ArmClient).StopContext

	if resp, err := client.Delete(ctx, d.Id()); err != nil {
		if !ar.ResponseWasNotFound(resp) {
			return fmt.Errorf("Error Deleting Azure AD Group with ID %q: %+v", d.Id(), err)
		}
	}

	return nil
}
<commit_msg>Update resource_group.go<commit_after>package azuread

import (
	"fmt"
	"log"

	"github.com/Azure/azure-sdk-for-go/services/graphrbac/1.6/graphrbac"
	"github.com/google/uuid"
	"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
	"github.com/hashicorp/terraform-plugin-sdk/helper/validation"

	"github.com/terraform-providers/terraform-provider-azuread/azuread/helpers/ar"
	"github.com/terraform-providers/terraform-provider-azuread/azuread/helpers/graph"
	"github.com/terraform-providers/terraform-provider-azuread/azuread/helpers/p"
	"github.com/terraform-providers/terraform-provider-azuread/azuread/helpers/slices"
	"github.com/terraform-providers/terraform-provider-azuread/azuread/helpers/tf"
	"github.com/terraform-providers/terraform-provider-azuread/azuread/helpers/validate"
)

func resourceGroup() *schema.Resource {
	return &schema.Resource{
		Create: resourceGroupCreate,
		Read:   resourceGroupRead,
		Update: resourceGroupUpdate,
		Delete: resourceGroupDelete,

		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"name": {
				Type:         schema.TypeString,
				Required:     true,
				ForceNew:     true,
				ValidateFunc: validation.NoZeroValues,
			},

			"description": {
				Type:     schema.TypeString,
				ForceNew: true, // there is no update method available in the SDK
				Optional: true,
			},

			"members": {
				Type:     schema.TypeSet,
				Optional: true,
				Computed: true,
				Set:      schema.HashString,
				Elem: &schema.Schema{
					Type:         schema.TypeString,
					ValidateFunc: validate.UUID,
				},
			},

			"owners": {
				Type:     schema.TypeSet,
				Optional: true,
				Computed: true,
				Set:      schema.HashString,
				Elem: &schema.Schema{
					Type:         schema.TypeString,
					ValidateFunc: validate.UUID,
				},
			},

			"object_id": {
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

func resourceGroupCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*ArmClient).groupsClient
	ctx := meta.(*ArmClient).StopContext

	name := d.Get("name").(string)

	properties := graphrbac.GroupCreateParameters{
		DisplayName:          &name,
		MailEnabled:          p.Bool(false),                 // we're defaulting to false, as the API currently only supports the creation of non-mail enabled security groups.
		MailNickname:         p.String(uuid.New().String()), // this matches the portal behaviour
		SecurityEnabled:      p.Bool(true),                  // we're defaulting to true, as the API currently only supports the creation of non-mail enabled security groups.
		AdditionalProperties: make(map[string]interface{}),
	}

	if v, ok := d.GetOk("description"); ok {
		properties.AdditionalProperties["description"] = v.(string)
	}

	group, err := client.Create(ctx, properties)
	if err != nil {
		return fmt.Errorf("Error creating Group (%q): %+v", name, err)
	}
	if group.ObjectID == nil {
		return fmt.Errorf("nil Group ID for %q: %+v", name, err)
	}

	d.SetId(*group.ObjectID)

	// Add members if specified
	if v, ok := d.GetOk("members"); ok {
		members := tf.ExpandStringSlicePtr(v.(*schema.Set).List())

		// we could lock here against the group member resource, but they should not be used together (todo conflicts with at a resource level?)
		if err := graph.GroupAddMembers(client, ctx, *group.ObjectID, *members); err != nil {
			return err
		}
	}

	// Add owners if specified
	if v, ok := d.GetOk("owners"); ok {
		members := tf.ExpandStringSlicePtr(v.(*schema.Set).List())
		if err := graph.GroupAddOwners(client, ctx, *group.ObjectID, *members); err != nil {
			return err
		}
	}

	_, err = graph.WaitForCreationReplication(func() (interface{}, error) {
		return client.Get(ctx, *group.ObjectID)
	})
	if err != nil {
		return fmt.Errorf("Error waiting for Group (%s) with ObjectId %q: %+v", name, *group.ObjectID, err)
	}

	return resourceGroupRead(d, meta)
}

func resourceGroupRead(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*ArmClient).groupsClient
	ctx := meta.(*ArmClient).StopContext

	resp, err := client.Get(ctx, d.Id())
	if err != nil {
		if ar.ResponseWasNotFound(resp.Response) {
			log.Printf("[DEBUG] Azure AD group with id %q was not found - removing from state", d.Id())
			d.SetId("")
			return nil
		}

		return fmt.Errorf("Error retrieving Azure AD Group with ID %q: %+v", d.Id(), err)
	}

	d.Set("name", resp.DisplayName)
	d.Set("object_id", resp.ObjectID)

	if v, ok := resp.AdditionalProperties["description"]; ok {
		d.Set("description", v.(string))
	}

	members, err := graph.GroupAllMembers(client, ctx, d.Id())
	if err != nil {
		return err
	}
	d.Set("members", members)

	owners, err := graph.GroupAllOwners(client, ctx, d.Id())
	if err != nil {
		return err
	}
	d.Set("owners", owners)

	return nil
}

func resourceGroupUpdate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*ArmClient).groupsClient
	ctx := meta.(*ArmClient).StopContext

	if v, ok := d.GetOkExists("members"); ok && d.HasChange("members") {
		existingMembers, err := graph.GroupAllMembers(client, ctx, d.Id())
		if err != nil {
			return err
		}

		desiredMembers := *tf.ExpandStringSlicePtr(v.(*schema.Set).List())
		membersForRemoval := slices.Difference(existingMembers, desiredMembers)
		membersToAdd := slices.Difference(desiredMembers, existingMembers)

		for _, existingMember := range membersForRemoval {
			log.Printf("[DEBUG] Removing member with id %q from Azure AD group with id %q", existingMember, d.Id())
			if resp, err := client.RemoveMember(ctx, d.Id(), existingMember); err != nil {
				if !ar.ResponseWasNotFound(resp) {
					return fmt.Errorf("Error Deleting group member %q from Azure AD Group with ID %q: %+v", existingMember, d.Id(), err)
				}
			}
		}

		if err := graph.GroupAddMembers(client, ctx, d.Id(), membersToAdd); err != nil {
			return err
		}
	}

	if v, ok := d.GetOkExists("owners"); ok && d.HasChange("owners") {
		existingOwners, err := graph.GroupAllOwners(client, ctx, d.Id())
		if err != nil {
			return err
		}

		desiredOwners := *tf.ExpandStringSlicePtr(v.(*schema.Set).List())
		ownersForRemoval := slices.Difference(existingOwners, desiredOwners)
		ownersToAdd := slices.Difference(desiredOwners, existingOwners)

		for _, ownerToDelete := range ownersForRemoval {
			log.Printf("[DEBUG] Removing member with id %q from Azure AD group with id %q", ownerToDelete, d.Id())
			if resp, err := client.RemoveOwner(ctx, d.Id(), ownerToDelete); err != nil {
				if !ar.ResponseWasNotFound(resp) {
					return fmt.Errorf("Error Deleting group member %q from Azure AD Group with ID %q: %+v", ownerToDelete, d.Id(), err)
				}
			}
		}

		if err := graph.GroupAddOwners(client, ctx, d.Id(), ownersToAdd); err != nil {
			return err
		}
	}

	return resourceGroupRead(d, meta)
}

func resourceGroupDelete(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*ArmClient).groupsClient
	ctx := meta.(*ArmClient).StopContext

	if resp, err := client.Delete(ctx, d.Id()); err != nil {
		if !ar.ResponseWasNotFound(resp) {
			return fmt.Errorf("Error Deleting Azure AD Group with ID %q: %+v", d.Id(), err)
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/grafana/grafana/pkg/log"
	"sort"
)

// represents a data "archive", i.e. the raw one, or an aggregated series
type archive struct {
	title      string
	interval   uint32
	pointCount uint32
	comment    string
}

func (b archive) String() string {
	return fmt.Sprintf("<archive %s> int:%d, comment: %s", b.title, b.interval, b.comment)
}

type archives []archive

func (a archives) Len() int           { return len(a) }
func (a archives) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a archives) Less(i, j int) bool { return a[i].interval < a[j].interval }

func findMetricsForRequests(reqs []Req, metaCache *MetaCache) error {
	for i := range reqs {
		err := metaCache.UpdateReq(&reqs[i])
		if err != nil {
			return err
		}
	}
	return nil
}

// updates the requests with all details for fetching, making sure all metrics are in the same, optimal interval
// luckily, all metrics still use the same aggSettings, making this a bit simpler
// for all requests, sets archive, numPoints, interval (and rawInterval as a side effect)
// note: it is assumed that all requests have the same from, to and maxdatapoints!
func alignRequests(reqs []Req, aggSettings []aggSetting) ([]Req, error) {

	// model all the archives for each requested metric
	// the 0th archive is always the raw series, with highest res (lowest interval)
	aggs := aggSettingsSpanAsc(aggSettings)
	sort.Sort(aggs)

	options := make([]archive, len(aggs)+1)

	minInterval := uint32(0)
	rawIntervals := make(map[uint32]bool)
	for _, req := range reqs {
		if minInterval == 0 || minInterval > req.rawInterval {
			minInterval = req.rawInterval
		}
		rawIntervals[req.rawInterval] = true
	}
	tsRange := (reqs[0].to - reqs[0].from)

	// note: not all series necessarily have the same raw settings, will be fixed further down
	options[0] = archive{"raw", minInterval, tsRange / minInterval, ""}
	// now model the archives we get from the aggregations
	for j, agg := range aggs {
		options[j+1] = archive{fmt.Sprintf("agg %d", j), agg.span, tsRange / agg.span, ""}
	}

	// find the first, i.e. highest-res option with a pointCount <= maxDataPoints
	selected := len(options) - 1
	for i, opt := range options {
		if opt.pointCount <= reqs[0].maxPoints {
			selected = i
			break
		}
	}

	/*
	   do a quick calculation of the ratio between pointCount and maxDatapoints of
	   the selected option, and the option before that.  eg. with a time range of 1hour,
	   our pointCounts for each option are:
	   10s   | 360
	   600s  | 6
	   7200s | 0

	   if maxPoints is 100, then selected will be 1, our 600s rollups.
	   We then calculate the ratio between maxPoints and our
	   selected pointCount "6" and the previous option "360".
	   belowMaxDataPointsRatio  =  16  #(100/6)
	   aboveMaxDataPointsRatio  =  3   #(360/100)

	   As the maxDataPoint requested is much closer to 360 then it is to 6,
	   we will use 360 and do runtime consolidation.
	*/
	runTimeConsolidate := false
	if selected > 0 {
		belowMaxDataPointsRatio := float64(reqs[0].maxPoints) / float64(options[selected].pointCount)
		aboveMaxDataPointsRatio := float64(options[selected-1].pointCount) / float64(reqs[0].maxPoints)

		if aboveMaxDataPointsRatio < belowMaxDataPointsRatio {
			selected--
			runTimeConsolidate = true
		}
	}

	chosenInterval := options[selected].interval

	// if we are using raw metrics, we need to find an interval that all request intervals work with.
	if selected == 0 && len(rawIntervals) > 1 {
		runTimeConsolidate = true
		var keys []int
		for k := range rawIntervals {
			keys = append(keys, int(k))
		}
		sort.Ints(keys)
		chosenInterval = uint32(keys[0])
		for i := 1; i < len(keys); i++ {
			a := max(uint32(keys[i]), chosenInterval)
			b := min(uint32(keys[i]), chosenInterval)
			r := a % b
			if r != 0 {
				for j := uint32(2); j <= b; j++ {
					if (j*a)%b == 0 {
						chosenInterval = j * a
						break
					}
				}
			} else {

				chosenInterval = a
			}
			options[0].pointCount = tsRange / chosenInterval
			options[0].interval = chosenInterval
		}
		//make sure that the calculated interval is not greater then the interval of the fist rollup.
		if len(options) > 1 && chosenInterval >= options[1].interval {
			selected = 1
			chosenInterval = options[1].interval
		}
	}

	options[selected].comment = "<-- chosen"
	for _, archive := range options {
		log.Debug("%-6s %-6d %-6d %s", archive.title, archive.interval, tsRange/archive.interval, archive.comment)
	}

	/* we now just need to update the archiveInterval, outInterval and aggNum of each req.
	   archInterval uint32 // the interval corresponding to the archive we'll fetch
	   outInterval  uint32 // the interval of the output data, after any runtime consolidation
	   aggNum       uint32 // how many points to consolidate together at runtime, after fetching from the archive
	*/
	for i, _ := range reqs {
		req := &reqs[i]
		req.archive = selected
		req.archInterval = options[selected].interval
		req.outInterval = chosenInterval
		aggNum := uint32(1)
		if runTimeConsolidate {
			ptCount := options[selected].pointCount

			aggNum = ptCount / req.maxPoints
			if ptCount%req.maxPoints != 0 {
				aggNum++
			}
			if selected == 0 {
				// Handle RAW interval
				req.archInterval = req.rawInterval

				// each request can have a different rawInterval. So the aggNum is variable.
				if chosenInterval != req.rawInterval {
					aggNum = aggNum * (chosenInterval / req.rawInterval)
				}
			}

			req.outInterval = req.archInterval * aggNum
		}

		req.aggNum = aggNum
	}
	return reqs, nil
}
<commit_msg>use map[x]struct{} for set<commit_after>package main

import (
	"fmt"
	"github.com/grafana/grafana/pkg/log"
	"sort"
)

// represents a data "archive", i.e. the raw one, or an aggregated series
type archive struct {
	title      string
	interval   uint32
	pointCount uint32
	comment    string
}

func (b archive) String() string {
	return fmt.Sprintf("<archive %s> int:%d, comment: %s", b.title, b.interval, b.comment)
}

type archives []archive

func (a archives) Len() int           { return len(a) }
func (a archives) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a archives) Less(i, j int) bool { return a[i].interval < a[j].interval }

func findMetricsForRequests(reqs []Req, metaCache *MetaCache) error {
	for i := range reqs {
		err := metaCache.UpdateReq(&reqs[i])
		if err != nil {
			return err
		}
	}
	return nil
}

// updates the requests with all details for fetching, making sure all metrics are in the same, optimal interval
// luckily, all metrics still use the same aggSettings, making this a bit simpler
// for all requests, sets archive, numPoints, interval (and rawInterval as a side effect)
// note: it is assumed that all requests have the same from, to and maxdatapoints!
func alignRequests(reqs []Req, aggSettings []aggSetting) ([]Req, error) {

	// model all the archives for each requested metric
	// the 0th archive is always the raw series, with highest res (lowest interval)
	aggs := aggSettingsSpanAsc(aggSettings)
	sort.Sort(aggs)

	options := make([]archive, len(aggs)+1)

	minInterval := uint32(0)
	rawIntervals := make(map[uint32]struct{})
	for _, req := range reqs {
		if minInterval == 0 || minInterval > req.rawInterval {
			minInterval = req.rawInterval
		}
		rawIntervals[req.rawInterval] = struct{}{}
	}
	tsRange := (reqs[0].to - reqs[0].from)

	// note: not all series necessarily have the same raw settings, will be fixed further down
	options[0] = archive{"raw", minInterval, tsRange / minInterval, ""}
	// now model the archives we get from the aggregations
	for j, agg := range aggs {
		options[j+1] = archive{fmt.Sprintf("agg %d", j), agg.span, tsRange / agg.span, ""}
	}

	// find the first, i.e. highest-res option with a pointCount <= maxDataPoints
	selected := len(options) - 1
	for i, opt := range options {
		if opt.pointCount <= reqs[0].maxPoints {
			selected = i
			break
		}
	}

	/*
	   do a quick calculation of the ratio between pointCount and maxDatapoints of
	   the selected option, and the option before that.  eg. with a time range of 1hour,
	   our pointCounts for each option are:
	   10s   | 360
	   600s  | 6
	   7200s | 0

	   if maxPoints is 100, then selected will be 1, our 600s rollups.
	   We then calculate the ratio between maxPoints and our
	   selected pointCount "6" and the previous option "360".
	   belowMaxDataPointsRatio  =  16  #(100/6)
	   aboveMaxDataPointsRatio  =  3   #(360/100)

	   As the maxDataPoint requested is much closer to 360 then it is to 6,
	   we will use 360 and do runtime consolidation.
	*/
	runTimeConsolidate := false
	if selected > 0 {
		belowMaxDataPointsRatio := float64(reqs[0].maxPoints) / float64(options[selected].pointCount)
		aboveMaxDataPointsRatio := float64(options[selected-1].pointCount) / float64(reqs[0].maxPoints)

		if aboveMaxDataPointsRatio < belowMaxDataPointsRatio {
			selected--
			runTimeConsolidate = true
		}
	}

	chosenInterval := options[selected].interval

	// if we are using raw metrics, we need to find an interval that all request intervals work with.
	if selected == 0 && len(rawIntervals) > 1 {
		runTimeConsolidate = true
		var keys []int
		for k := range rawIntervals {
			keys = append(keys, int(k))
		}
		sort.Ints(keys)
		chosenInterval = uint32(keys[0])
		for i := 1; i < len(keys); i++ {
			a := max(uint32(keys[i]), chosenInterval)
			b := min(uint32(keys[i]), chosenInterval)
			r := a % b
			if r != 0 {
				for j := uint32(2); j <= b; j++ {
					if (j*a)%b == 0 {
						chosenInterval = j * a
						break
					}
				}
			} else {

				chosenInterval = a
			}
			options[0].pointCount = tsRange / chosenInterval
			options[0].interval = chosenInterval
		}
		//make sure that the calculated interval is not greater then the interval of the fist rollup.
		if len(options) > 1 && chosenInterval >= options[1].interval {
			selected = 1
			chosenInterval = options[1].interval
		}
	}

	options[selected].comment = "<-- chosen"
	for _, archive := range options {
		log.Debug("%-6s %-6d %-6d %s", archive.title, archive.interval, tsRange/archive.interval, archive.comment)
	}

	/* we now just need to update the archiveInterval, outInterval and aggNum of each req.
	   archInterval uint32 // the interval corresponding to the archive we'll fetch
	   outInterval  uint32 // the interval of the output data, after any runtime consolidation
	   aggNum       uint32 // how many points to consolidate together at runtime, after fetching from the archive
	*/
	for i, _ := range reqs {
		req := &reqs[i]
		req.archive = selected
		req.archInterval = options[selected].interval
		req.outInterval = chosenInterval
		aggNum := uint32(1)
		if runTimeConsolidate {
			ptCount := options[selected].pointCount

			aggNum = ptCount / req.maxPoints
			if ptCount%req.maxPoints != 0 {
				aggNum++
			}
			if selected == 0 {
				// Handle RAW interval
				req.archInterval = req.rawInterval

				// each request can have a different rawInterval. So the aggNum is variable.
				if chosenInterval != req.rawInterval {
					aggNum = aggNum * (chosenInterval / req.rawInterval)
				}
			}

			req.outInterval = req.archInterval * aggNum
		}

		req.aggNum = aggNum
	}
	return reqs, nil
}
<|endoftext|>


<commit_before>package main

const version string = "2.0.4"
<commit_msg>Bumped version to 2.0.5<commit_after>package main

const version string = "2.0.5"
<|endoftext|>