<commit_before>package impl

import (
	"errors"
	"net/url"
	"time"

	log "github.com/macarrie/flemzerd/logging"
	. "github.com/macarrie/flemzerd/objects"
	provider "github.com/macarrie/flemzerd/providers"
	"github.com/pioz/tvdb"
)

type TVDBProvider struct {
	Client tvdb.Client
}

// Create new instance of the TVDB info provider
func New(apiKey string) (tvdbProvider TVDBProvider, err error) {
	client := tvdb.Client{Apikey: apiKey}
	err = client.Login()
	log.WithFields(log.Fields{
		"provider": "THE TVDB",
	}).Debug("Checking connection to TheTVDB")

	if err != nil {
		if tvdb.HaveCodeError(401, err) {
			log.Error("Can not connect to thetvdb (API key not valid). Please check your API key and try again")
		} else {
			log.WithFields(log.Fields{
				"details":  err,
				"provider": "THE TVDB",
			}).Error("Cannot connect to thetvdb")
		}
		return TVDBProvider{}, err
	} else {
		log.Debug("Connection to TheTVDB successful")
		return TVDBProvider{Client: client}, nil
	}
}

// Get show from name
func (tvdbProvider TVDBProvider) GetShow(tvShowName string) (TvShow, error) {
	log.WithFields(log.Fields{
		"name":     tvShowName,
		"provider": "THE TVDB",
	}).Debug("Searching show")

	tvShow, err := tvdbProvider.Client.BestSearch(tvShowName)
	if err != nil {
		return TvShow{}, handleTvShowNotFoundError(tvShowName, err)
	} else {
		log.WithFields(log.Fields{
			"name":     tvShow.SeriesName,
			"TVDB-ID":  tvShow.ID,
			"provider": "THE TVDB",
		}).Debug("TV show found")
		return convertShow(tvShow), nil

	}
}

// Get list of episodes of a given show
func (tvdbProvider TVDBProvider) GetEpisodes(tvShow TvShow) ([]Episode, error) {
	log.WithFields(log.Fields{
		"id":       tvShow.Id,
		"name":     tvShow.Name,
		"provider": "THE TVDB",
	}).Debug("Retrieving episodes list for a tv show")

	tvShowSearchResult, err := tvdbProvider.Client.BestSearch(tvShow.Name)
	if err != nil {
		return []Episode{}, handleTvShowNotFoundError(tvShow.Name, err)
	} else {
		err := tvdbProvider.Client.GetSeriesEpisodes(&tvShowSearchResult, url.Values{})
		if err != nil {
			log.WithFields(log.Fields{
				"TV-show-name": tvShow.Name,
				"id":           tvShow.Id,
				"provider":     "THE TVDB",
			}).Warn("Can not retrieve episodes of tv show")
			return []Episode{}, err
		} else {
			log.WithFields(log.Fields{
				"name":       tvShow.Name,
				"tv show id": tvShow.Id,
				"provider":   "THE TVDB",
			}).Debug("Episodes found")

			var retVal []Episode
			for _, episode := range tvShowSearchResult.Episodes {
				retVal = append(retVal, convertEpisode(episode))

			}
			return retVal, nil
		}
	}
}

// Get all episodes of a tv show that haven't been aired yet for a given show
func (tvdbProvider TVDBProvider) GetNextEpisodes(tvShow TvShow) ([]Episode, error) {
	episodes, err := tvdbProvider.GetEpisodes(tvShow)
	if err != nil {
		log.WithFields(log.Fields{
			"TV-show-name": tvShow.Name,
			"id":           tvShow.Id,
			"provider":     "THE TVDB",
		}).Warn("Cannot get next aired episodes of the tv show")
		return []Episode{}, err
	} else {
		log.WithFields(log.Fields{
			"TV-show-name": tvShow.Name,
			"id":           tvShow.Id,
			"provider":     "THE TVDB",
		}).Debug("Getting list of episodes that haven't be aired yet")
		now := time.Now()
		futureEpisodes := filterEpisodesAiredBetweenDates(episodes, &now, nil)

		log.WithFields(log.Fields{
			"TV-show-name":   tvShow.Name,
			"id":             tvShow.Id,
			"nb of episodes": len(futureEpisodes),
			"provider":       "THE TVDB",
		}).Debug("Successfully filtered list of episodes that haven't be aired yet")
		return futureEpisodes, nil
	}
}

// Get list of episodes of a show aired less than provider.RECENTLY_AIRED_EPISODES_INTERVAL days ago
func (tvdbProvider TVDBProvider) GetRecentlyAiredEpisodes(tvShow TvShow) ([]Episode, error) {
	episodes, err := tvdbProvider.GetEpisodes(tvShow)
	if err != nil {
		log.WithFields(log.Fields{
			"TV-show-name": tvShow.Name,
			"id":           tvShow.Id,
			"provider":     "THE TVDB",
		}).Warn("Can not get recently aired episodes of the tv show")
		return []Episode{}, err
	} else {
		log.WithFields(log.Fields{
			"TV-show-name": tvShow.Name,
			"id":           tvShow.Id,
			"provider":     "THE TVDB",
		}).Debug("Getting list of episodes that haven recently been aired")

		// Current date minus RECENTLY_AIRED_EPISODES_INTERVAL days
		oldestDate := time.Now().AddDate(0, 0, -provider.RECENTLY_AIRED_EPISODES_INTERVAL)
		now := time.Now()
		recentlyAiredEpisodes := filterEpisodesAiredBetweenDates(episodes, &oldestDate, &now)

		log.WithFields(log.Fields{
			"TV-show-name":   tvShow.Name,
			"id":             tvShow.Id,
			"nb of episodes": len(recentlyAiredEpisodes),
			"provider":       "THE TVDB",
		}).Debug("Successfully filtered list of episodes that have been recently aired")
		return recentlyAiredEpisodes, nil
	}
}

func filterEpisodesAiredBetweenDates(episodes []Episode, beginning *time.Time, end *time.Time) []Episode {
	// Set beginning date to zero time if beginning date is nil
	if beginning == nil {
		*beginning = time.Date(0, time.January, 1, 0, 0, 0, 0, time.UTC)
	}
	// Set end date to year 100,000 if end date is nil
	if end == nil {
		*end = time.Date(100000, time.January, 1, 0, 0, 0, 0, time.UTC)
	}

	log.WithFields(log.Fields{
		"start-date": beginning,
		"end-date":   end,
	}).Debug("Filtering episodes list by airing date")
	var retVal []Episode
	for _, episode := range episodes {
		if episode.Date.After(*beginning) && episode.Date.Before(*end) {
			retVal = append(retVal, episode)
		}
	}

	log.WithFields(log.Fields{
		"start date":     beginning,
		"end date":       end,
		"nb of episodes": len(retVal),
	}).Debug("Successfully filtered episodes list by airing date")

	return retVal
}

func handleTvShowNotFoundError(tvShowName string, err error) error {
	if tvdb.HaveCodeError(404, err) {
		// The request response is a 404: this means no results have been found
		log.WithFields(log.Fields{
			"TV-show-name": tvShowName,
			"provider":     "THE TVDB",
		}).Warn("TV show not found")
		return errors.New("TV show '" + tvShowName + "' not found")
	} else if tvdb.HaveCodeError(401, err) {
		// The request response is a 401: Authentication failure
		log.WithFields(log.Fields{
			"provider": "THE TVDB",
		}).Warn("Could not connect to provider, authentication failed for unkonwn reasons")
		return err
	} else {
		log.WithFields(log.Fields{
			"provider": "THE TVDB",
		}).Error("Unknown error encountered while getting show information from The TVDB")
		return err
	}
}

// Convert a github.com/pioz/tvdb series object to flemzerd tvShow object
func convertShow(tvShow tvdb.Series) TvShow {
	firstAired, err := time.Parse("2006-01-02", tvShow.FirstAired)
	if err != nil {
		firstAired = time.Time{}
	}

	return TvShow{
		Aliases:    tvShow.Aliases,
		Banner:     tvShow.Banner,
		FirstAired: firstAired,
		Id:         tvShow.ID,
		Overview:   tvShow.Overview,
		Name:       tvShow.SeriesName,
		Status:     tvShow.Status,
	}
}

// Convert a github.com/pioz/tvdb episode object to flemzerd episode object
func convertEpisode(episode tvdb.Episode) Episode {
	firstAired, err := time.Parse("2006-01-02", episode.FirstAired)
	if err != nil {
		firstAired = time.Time{}
	}

	return Episode{
		AbsoluteNumber: episode.AbsoluteNumber,
		Number:         episode.AiredEpisodeNumber,
		Season:         episode.AiredSeason,
		Name:           episode.EpisodeName,
		Date:           firstAired,
		Id:             episode.ID,
		Overview:       episode.Overview,
	}
}
<commit_msg>Modified labels in logs to get rid of spaces<commit_after>package impl

import (
	"errors"
	"net/url"
	"time"

	log "github.com/macarrie/flemzerd/logging"
	. "github.com/macarrie/flemzerd/objects"
	provider "github.com/macarrie/flemzerd/providers"
	"github.com/pioz/tvdb"
)

type TVDBProvider struct {
	Client tvdb.Client
}

// Create new instance of the TVDB info provider
func New(apiKey string) (tvdbProvider TVDBProvider, err error) {
	client := tvdb.Client{Apikey: apiKey}
	err = client.Login()
	log.WithFields(log.Fields{
		"provider": "THE TVDB",
	}).Debug("Checking connection to TheTVDB")

	if err != nil {
		if tvdb.HaveCodeError(401, err) {
			log.Error("Can not connect to thetvdb (API key not valid). Please check your API key and try again")
		} else {
			log.WithFields(log.Fields{
				"details":  err,
				"provider": "THE TVDB",
			}).Error("Cannot connect to thetvdb")
		}
		return TVDBProvider{}, err
	} else {
		log.Debug("Connection to TheTVDB successful")
		return TVDBProvider{Client: client}, nil
	}
}

// Get show from name
func (tvdbProvider TVDBProvider) GetShow(tvShowName string) (TvShow, error) {
	log.WithFields(log.Fields{
		"name":     tvShowName,
		"provider": "THE TVDB",
	}).Debug("Searching show")

	tvShow, err := tvdbProvider.Client.BestSearch(tvShowName)
	if err != nil {
		return TvShow{}, handleTvShowNotFoundError(tvShowName, err)
	} else {
		log.WithFields(log.Fields{
			"name":     tvShow.SeriesName,
			"TVDB-ID":  tvShow.ID,
			"provider": "THE TVDB",
		}).Debug("TV show found")
		return convertShow(tvShow), nil

	}
}

// Get list of episodes of a given show
func (tvdbProvider TVDBProvider) GetEpisodes(tvShow TvShow) ([]Episode, error) {
	log.WithFields(log.Fields{
		"id":       tvShow.Id,
		"name":     tvShow.Name,
		"provider": "THE TVDB",
	}).Debug("Retrieving episodes list for a tv show")

	tvShowSearchResult, err := tvdbProvider.Client.BestSearch(tvShow.Name)
	if err != nil {
		return []Episode{}, handleTvShowNotFoundError(tvShow.Name, err)
	} else {
		err := tvdbProvider.Client.GetSeriesEpisodes(&tvShowSearchResult, url.Values{})
		if err != nil {
			log.WithFields(log.Fields{
				"tvshow_name": tvShow.Name,
				"id":          tvShow.Id,
				"provider":    "THE TVDB",
			}).Warn("Can not retrieve episodes of tv show")
			return []Episode{}, err
		} else {
			log.WithFields(log.Fields{
				"name":      tvShow.Name,
				"tvshow_id": tvShow.Id,
				"provider":  "THE TVDB",
			}).Debug("Episodes found")

			var retVal []Episode
			for _, episode := range tvShowSearchResult.Episodes {
				retVal = append(retVal, convertEpisode(episode))

			}
			return retVal, nil
		}
	}
}

// Get all episodes of a tv show that haven't been aired yet for a given show
func (tvdbProvider TVDBProvider) GetNextEpisodes(tvShow TvShow) ([]Episode, error) {
	episodes, err := tvdbProvider.GetEpisodes(tvShow)
	if err != nil {
		log.WithFields(log.Fields{
			"tvshow_name": tvShow.Name,
			"id":          tvShow.Id,
			"provider":    "THE TVDB",
		}).Warn("Cannot get next aired episodes of the tv show")
		return []Episode{}, err
	} else {
		log.WithFields(log.Fields{
			"tvshow_name": tvShow.Name,
			"id":          tvShow.Id,
			"provider":    "THE TVDB",
		}).Debug("Getting list of episodes that haven't be aired yet")
		now := time.Now()
		futureEpisodes := filterEpisodesAiredBetweenDates(episodes, &now, nil)

		log.WithFields(log.Fields{
			"tvshow_name":    tvShow.Name,
			"id":             tvShow.Id,
			"nb_of_episodes": len(futureEpisodes),
			"provider":       "THE TVDB",
		}).Debug("Successfully filtered list of episodes that haven't be aired yet")
		return futureEpisodes, nil
	}
}

// Get list of episodes of a show aired less than provider.RECENTLY_AIRED_EPISODES_INTERVAL days ago
func (tvdbProvider TVDBProvider) GetRecentlyAiredEpisodes(tvShow TvShow) ([]Episode, error) {
	episodes, err := tvdbProvider.GetEpisodes(tvShow)
	if err != nil {
		log.WithFields(log.Fields{
			"tvshow_name": tvShow.Name,
			"id":          tvShow.Id,
			"provider":    "THE TVDB",
		}).Warn("Can not get recently aired episodes of the tv show")
		return []Episode{}, err
	} else {
		log.WithFields(log.Fields{
			"tvshow_name": tvShow.Name,
			"id":          tvShow.Id,
			"provider":    "THE TVDB",
		}).Debug("Getting list of episodes that haven recently been aired")

		// Current date minus RECENTLY_AIRED_EPISODES_INTERVAL days
		oldestDate := time.Now().AddDate(0, 0, -provider.RECENTLY_AIRED_EPISODES_INTERVAL)
		now := time.Now()
		recentlyAiredEpisodes := filterEpisodesAiredBetweenDates(episodes, &oldestDate, &now)

		log.WithFields(log.Fields{
			"tvshow_name":    tvShow.Name,
			"id":             tvShow.Id,
			"nb_of_episodes": len(recentlyAiredEpisodes),
			"provider":       "THE TVDB",
		}).Debug("Successfully filtered list of episodes that have been recently aired")
		return recentlyAiredEpisodes, nil
	}
}

func filterEpisodesAiredBetweenDates(episodes []Episode, beginning *time.Time, end *time.Time) []Episode {
	// Set beginning date to zero time if beginning date is nil
	if beginning == nil {
		*beginning = time.Date(0, time.January, 1, 0, 0, 0, 0, time.UTC)
	}
	// Set end date to year 100,000 if end date is nil
	if end == nil {
		*end = time.Date(100000, time.January, 1, 0, 0, 0, 0, time.UTC)
	}

	log.WithFields(log.Fields{
		"start_date": beginning,
		"end_date":   end,
	}).Debug("Filtering episodes list by airing date")
	var retVal []Episode
	for _, episode := range episodes {
		if episode.Date.After(*beginning) && episode.Date.Before(*end) {
			retVal = append(retVal, episode)
		}
	}

	log.WithFields(log.Fields{
		"start_date":     beginning,
		"end_date":       end,
		"nb_of_episodes": len(retVal),
	}).Debug("Successfully filtered episodes list by airing date")

	return retVal
}

func handleTvShowNotFoundError(tvShowName string, err error) error {
	if tvdb.HaveCodeError(404, err) {
		// The request response is a 404: this means no results have been found
		log.WithFields(log.Fields{
			"tvshow_name": tvShowName,
			"provider":    "THE TVDB",
		}).Warn("TV show not found")
		return errors.New("TV show '" + tvShowName + "' not found")
	} else if tvdb.HaveCodeError(401, err) {
		// The request response is a 401: Authentication failure
		log.WithFields(log.Fields{
			"provider": "THE TVDB",
		}).Warn("Could not connect to provider, authentication failed for unkonwn reasons")
		return err
	} else {
		log.WithFields(log.Fields{
			"provider": "THE TVDB",
		}).Error("Unknown error encountered while getting show information from The TVDB")
		return err
	}
}

// Convert a github.com/pioz/tvdb series object to flemzerd tvShow object
func convertShow(tvShow tvdb.Series) TvShow {
	firstAired, err := time.Parse("2006-01-02", tvShow.FirstAired)
	if err != nil {
		firstAired = time.Time{}
	}

	return TvShow{
		Aliases:    tvShow.Aliases,
		Banner:     tvShow.Banner,
		FirstAired: firstAired,
		Id:         tvShow.ID,
		Overview:   tvShow.Overview,
		Name:       tvShow.SeriesName,
		Status:     tvShow.Status,
	}
}

// Convert a github.com/pioz/tvdb episode object to flemzerd episode object
func convertEpisode(episode tvdb.Episode) Episode {
	firstAired, err := time.Parse("2006-01-02", episode.FirstAired)
	if err != nil {
		firstAired = time.Time{}
	}

	return Episode{
		AbsoluteNumber: episode.AbsoluteNumber,
		Number:         episode.AiredEpisodeNumber,
		Season:         episode.AiredSeason,
		Name:           episode.EpisodeName,
		Date:           firstAired,
		Id:             episode.ID,
		Overview:       episode.Overview,
	}
}
<|endoftext|>


<commit_before>package MQTTg

import (
	"net"
	"strconv"
)

type Broker struct {
	Bt *Transport
	// TODO: check whether not good to use addr as key
	Clients   map[*net.UDPAddr]*Client // map[addr]*Client
	ClientIDs map[string]*Client       // map[clientID]*Client
	TopicRoot *TopicNode
}

func (self *Broker) ApplyDummyClientID() string {
	return "DummyClientID:" + strconv.Itoa(len(self.ClientIDs)+1)
}

func (self *Broker) ReadLoop() error {
	for {
		m, addr, err := self.Bt.ReadMessageFrom()
		if err != nil {
			EmitError(err)
			continue
		}
		switch message := m.(type) {
		case *ConnectMessage:
			if message.Protocol.Level != MQTT_3_1_1.Level {
				// CHECK: Is false correct?
				err = self.Bt.SendMessage(NewConnackMessage(false, UnacceptableProtocolVersion), addr)
				EmitError(INVALID_PROTOCOL_LEVEL)
				continue
			}

			_, ok := self.ClientIDs[message.ClientID]
			if ok {
				// TODO: this might cause problem
				err = self.Bt.SendMessage(NewConnackMessage(false, IdentifierRejected), addr)
				EmitError(CLIENT_ID_IS_USED_ALREADY)
				continue
			}
			if len(message.ClientID) == 0 {
				message.ClientID = self.ApplyDummyClientID()
			}

			if message.Flags&Reserved_Flag == Reserved_Flag {
				// TODO: disconnect the connection
				continue
			}

			// if message.User.Name and if message.User.Password
			// self.Bt.SendMessage(NewConnackMessage(false, BadUserNameOrPassword), addr)
			// continue

			// if authorized
			// self.Bt.SendMessage(NewConnackMessage(false, NotAuthorized), addr)
			// continue

			// CHECK: Is self.Bt needed?. Is nil enough?

			_, ok = self.Clients[addr]
			sessionPresent := false
			if message.Flags&CleanSession_Flag == CleanSession_Flag || !ok {
				// TODO: need to manage QoS base processing
				client := NewClient(self.Bt, addr, message.ClientID,
					message.User, message.KeepAlive, message.Will)
				self.Clients[addr] = client
				self.ClientIDs[message.ClientID] = client
			} else if message.Flags&CleanSession_Flag != CleanSession_Flag || ok {
				sessionPresent = true
			}

			err = self.Bt.SendMessage(NewConnackMessage(sessionPresent, Accepted), addr)
		case *PublishMessage:
			if message.QoS == 3 {
				// error
				// close connection
				continue
			}

			if message.Dup {
				// re-delivered
			} else {
				// first time delivery
			}

			if message.Retain {
				// store the application message to designated topic
				if len(message.Payload) == 0 {
					// discard(remove) retained message
				}

				if message.QoS == 0 {
					// discard retained message
				}
			}

			switch message.QoS {
			// in any case, Dub must be 0
			case 0:
			case 1:
				err = self.Bt.SendMessage(NewPubackMessage(message.PacketID), addr)
			case 2:
				err = self.Bt.SendMessage(NewPubrecMessage(message.PacketID), addr)
			}
		case *PubackMessage:
			// acknowledge the sent Publish packet
		case *PubrecMessage:
			// acknowledge the sent Publish packet
			err = self.Bt.SendMessage(NewPubrelMessage(message.PacketID), addr)
		case *PubrelMessage:
			err = self.Bt.SendMessage(NewPubcompMessage(message.PacketID), addr)
		case *PubcompMessage:
			// acknowledge the sent Pubrel packet
		case *SubscribeMessage:
			// TODO: check The wild card is permitted
			codes := make([]SubscribeReturnCode, len(message.SubscribeTopics))
			for i, subTopic := range message.SubscribeTopics {
				// TODO: need to validate wheter there are same topics or not
				client, ok := self.Clients[addr]
				if ok {
					retains, code := self.TopicRoot.ApplySubscriber(client.ID, string(subTopic.Topic), subTopic.QoS)
					codes[i] = code
					client.SubTopics = append(client.SubTopics,
						SubscribeTopic{SubscribeAck,
							subTopic.Topic,
							uint8(code),
						})
					if len(retains) > 0 {
						for k, v := range retains {
							//Publish(k,v)
						}
					}
				} else {
					codes[i] = SubscribeFailure // TODO: correct?
				}

			}
			err = self.Bt.SendMessage(NewSubackMessage(message.PacketID, codes), addr)
		case *UnsubscribeMessage:
			client, ok := self.Clients[addr]
			if !ok {
				EmitError(CLIENT_NOT_EXIST)
				continue // TODO: ?
			}
			if len(message.TopicNames) == 0 {
				// protocol violation
			}
			// TODO: optimize here
			result := []SubscribeTopic{}
			for _, t := range client.SubTopics {
				del := false
				for _, name := range message.TopicNames {
					if string(t.Topic) == string(name) {
						del = true
					}
				}
				if !del {
					result = append(result, t)
				}
			}
			client.SubTopics = result
			err = self.Bt.SendMessage(NewUnsubackMessage(message.PacketID), addr)
		case *PingreqMessage:
			// Pingresp
			err = self.Bt.SendMessage(NewPingrespMessage(), addr)
		case *DisconnectMessage:
			client, ok := self.Clients[addr]
			if !ok {
				// TODO: emit error/warnning
				EmitError(CLIENT_NOT_EXIST)
				continue
			}
			client.IsConnecting = false

			// close the client
			// MUST discard WILL message
			// associate with the connection
		default:
			// when invalid messages come
			err = INVALID_MESSAGE_CAME
		}
		if err != nil {
			EmitError(err)
		}
	}
}
<commit_msg>fix variable usage<commit_after>package MQTTg

import (
	"net"
	"strconv"
)

type Broker struct {
	Bt *Transport
	// TODO: check whether not good to use addr as key
	Clients   map[*net.UDPAddr]*Client // map[addr]*Client
	ClientIDs map[string]*Client       // map[clientID]*Client
	TopicRoot *TopicNode
}

func (self *Broker) ApplyDummyClientID() string {
	return "DummyClientID:" + strconv.Itoa(len(self.ClientIDs)+1)
}

func (self *Broker) ReadLoop() error {
	for {
		m, addr, err := self.Bt.ReadMessageFrom()
		if err != nil {
			EmitError(err)
			continue
		}
		switch message := m.(type) {
		case *ConnectMessage:
			if message.Protocol.Level != MQTT_3_1_1.Level {
				// CHECK: Is false correct?
				err = self.Bt.SendMessage(NewConnackMessage(false, UnacceptableProtocolVersion), addr)
				EmitError(INVALID_PROTOCOL_LEVEL)
				continue
			}

			client, ok := self.ClientIDs[message.ClientID]
			if ok {
				// TODO: this might cause problem
				err = self.Bt.SendMessage(NewConnackMessage(false, IdentifierRejected), addr)
				EmitError(CLIENT_ID_IS_USED_ALREADY)
				continue
			}
			if len(message.ClientID) == 0 {
				message.ClientID = self.ApplyDummyClientID()
			}

			if message.Flags&Reserved_Flag == Reserved_Flag {
				// TODO: disconnect the connection
				continue
			}

			// if message.User.Name and if message.User.Password
			// self.Bt.SendMessage(NewConnackMessage(false, BadUserNameOrPassword), addr)
			// continue

			// if authorized
			// self.Bt.SendMessage(NewConnackMessage(false, NotAuthorized), addr)
			// continue

			// CHECK: Is self.Bt needed?. Is nil enough?

			client, ok = self.Clients[addr]
			sessionPresent := false
			if message.Flags&CleanSession_Flag == CleanSession_Flag || !ok {
				// TODO: need to manage QoS base processing
				client = NewClient(self.Bt, addr, message.ClientID,
					message.User, message.KeepAlive, message.Will)
				self.Clients[addr] = client
				self.ClientIDs[message.ClientID] = client
			} else if message.Flags&CleanSession_Flag != CleanSession_Flag || ok {
				sessionPresent = true
			}

			err = self.Bt.SendMessage(NewConnackMessage(sessionPresent, Accepted), addr)
		case *PublishMessage:
			if message.QoS == 3 {
				// error
				// close connection
				continue
			}

			if message.Dup {
				// re-delivered
			} else {
				// first time delivery
			}

			if message.Retain {
				// store the application message to designated topic
				if len(message.Payload) == 0 {
					// discard(remove) retained message
				}

				if message.QoS == 0 {
					// discard retained message
				}
			}

			switch message.QoS {
			// in any case, Dub must be 0
			case 0:
			case 1:
				err = self.Bt.SendMessage(NewPubackMessage(message.PacketID), addr)
			case 2:
				err = self.Bt.SendMessage(NewPubrecMessage(message.PacketID), addr)
			}
		case *PubackMessage:
			// acknowledge the sent Publish packet
		case *PubrecMessage:
			// acknowledge the sent Publish packet
			err = self.Bt.SendMessage(NewPubrelMessage(message.PacketID), addr)
		case *PubrelMessage:
			err = self.Bt.SendMessage(NewPubcompMessage(message.PacketID), addr)
		case *PubcompMessage:
			// acknowledge the sent Pubrel packet
		case *SubscribeMessage:
			// TODO: check The wild card is permitted
			codes := make([]SubscribeReturnCode, len(message.SubscribeTopics))
			for i, subTopic := range message.SubscribeTopics {
				// TODO: need to validate wheter there are same topics or not
				client, ok := self.Clients[addr]
				if ok {
					retains, code := self.TopicRoot.ApplySubscriber(client.ID, string(subTopic.Topic), subTopic.QoS)
					codes[i] = code
					client.SubTopics = append(client.SubTopics,
						SubscribeTopic{SubscribeAck,
							subTopic.Topic,
							uint8(code),
						})
					if len(retains) > 0 {
						for k, v := range retains {
							//Publish(k,v)
						}
					}
				} else {
					codes[i] = SubscribeFailure // TODO: correct?
				}

			}
			err = self.Bt.SendMessage(NewSubackMessage(message.PacketID, codes), addr)
		case *UnsubscribeMessage:
			client, ok := self.Clients[addr]
			if !ok {
				EmitError(CLIENT_NOT_EXIST)
				continue // TODO: ?
			}
			if len(message.TopicNames) == 0 {
				// protocol violation
			}
			// TODO: optimize here
			result := []SubscribeTopic{}
			for _, t := range client.SubTopics {
				del := false
				for _, name := range message.TopicNames {
					if string(t.Topic) == string(name) {
						del = true
					}
				}
				if !del {
					result = append(result, t)
				}
			}
			client.SubTopics = result
			err = self.Bt.SendMessage(NewUnsubackMessage(message.PacketID), addr)
		case *PingreqMessage:
			// Pingresp
			err = self.Bt.SendMessage(NewPingrespMessage(), addr)
		case *DisconnectMessage:
			client, ok := self.Clients[addr]
			if !ok {
				// TODO: emit error/warnning
				EmitError(CLIENT_NOT_EXIST)
				continue
			}
			client.IsConnecting = false

			// close the client
			// MUST discard WILL message
			// associate with the connection
		default:
			// when invalid messages come
			err = INVALID_MESSAGE_CAME
		}
		if err != nil {
			EmitError(err)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"math"
	"net/http"
	"os"
	"path/filepath"
	"strconv"

	"time"

	"strings"

	. "github.com/claudetech/loggo/default"
	"github.com/fujiwara/shapeio"
	"github.com/orcaman/concurrent-map"
)

var instances cmap.ConcurrentMap
var chunkPath string
var chunkSize int64
var chunkDirMaxSize int64
var speedLimit int64

func init() {
	instances = cmap.New()
}

// Buffer is a buffered stream
type Buffer struct {
	numberOfInstances int
	client            *http.Client
	object            *APIObject
	tempDir           string
	preload           bool
	chunks            cmap.ConcurrentMap
}

// GetBufferInstance gets a singleton instance of buffer
func GetBufferInstance(client *http.Client, object *APIObject) (*Buffer, error) {
	if !instances.Has(object.ObjectID) {
		i, err := newBuffer(client, object)
		if nil != err {
			return nil, err
		}

		instances.Set(object.ObjectID, i)
	}

	instance, ok := instances.Get(object.ObjectID)
	// if buffer allocation failed due to race conditions it will try to fetch a new one
	if !ok {
		i, err := GetBufferInstance(client, object)
		if nil != err {
			return nil, err
		}
		instance = i
	}
	instance.(*Buffer).numberOfInstances++
	return instance.(*Buffer), nil
}

// SetChunkPath sets the global chunk path
func SetChunkPath(path string) {
	chunkPath = path
}

// SetChunkSize sets the global chunk size
func SetChunkSize(size int64) {
	chunkSize = size
}

// SetChunkDirMaxSize sets the maximum size of the chunk directory
func SetChunkDirMaxSize(size int64) {
	chunkDirMaxSize = size
}

// SetDownloadSpeedLimit sets the maximum bytes per seconds to be downloaded
func SetDownloadSpeedLimit(limit int64) {
	speedLimit = limit
}

// NewBuffer creates a new buffer instance
func newBuffer(client *http.Client, object *APIObject) (*Buffer, error) {
	Log.Infof("Starting playback of %v", object.Name)
	Log.Debugf("Creating buffer for object %v", object.ObjectID)

	tempDir := filepath.Join(chunkPath, object.ObjectID)
	if err := os.MkdirAll(tempDir, 0777); nil != err {
		Log.Debugf("%v", err)
		return nil, fmt.Errorf("Could not create temp path for object %v", object.ObjectID)
	}

	if 0 == chunkSize {
		Log.Debugf("ChunkSize was 0, setting to default (5 MB)")
		chunkSize = 5 * 1024 * 1024
	}

	buffer := Buffer{
		numberOfInstances: 0,
		client:            client,
		object:            object,
		tempDir:           tempDir,
		preload:           true,
		chunks:            cmap.New(),
	}

	return &buffer, nil
}

// Close all handles
func (b *Buffer) Close() error {
	b.numberOfInstances--
	if 0 == b.numberOfInstances {
		Log.Infof("Stopping playback of %v", b.object.Name)
		Log.Debugf("Stop buffering for object %v", b.object.ObjectID)

		b.preload = false
		instances.Remove(b.object.ObjectID)
	}
	return nil
}

// ReadBytes on a specific location
func (b *Buffer) ReadBytes(start, size int64, isPreload bool, delay int32) ([]byte, error) {
	fOffset := start % chunkSize
	offset := start - fOffset
	offsetEnd := offset + chunkSize

	Log.Tracef("Getting object %v - chunk %v - offset %v for %v bytes (is preload: %v)",
		b.object.ObjectID, strconv.Itoa(int(offset)), fOffset, size, isPreload)

	if b.preload && uint64(offsetEnd) < b.object.Size {
		defer func() {
			go func() {
				preloadStart := strconv.Itoa(int(offsetEnd))
				if !b.chunks.Has(preloadStart) {
					b.chunks.Set(preloadStart, true)
					b.ReadBytes(offsetEnd, size, true, 0)
				}
			}()
		}()
	}

	filename := filepath.Join(b.tempDir, strconv.Itoa(int(offset)))
	if f, err := os.Open(filename); nil == err {
		defer f.Close()

		buf := make([]byte, size)
		if n, err := f.ReadAt(buf, fOffset); n > 0 && (nil == err || io.EOF == err) {
			Log.Tracef("Found file %s bytes %v - %v in cache", filename, offset, offsetEnd)

			// update the last modified time for files that are often in use
			if err := os.Chtimes(filename, time.Now(), time.Now()); nil != err {
				Log.Warningf("Could not update last modified time for %v", filename)
			}

			return buf[:size], nil
		}

		Log.Debugf("%v", err)
		Log.Debugf("Could not read file %s at %v", filename, fOffset)
	}

	if chunkDirMaxSize > 0 {
		go func() {
			if err := cleanChunkDir(chunkPath); nil != err {
				Log.Debugf("%v", err)
				Log.Warningf("Could not delete oldest chunk")
			}
		}()
	}

	// sleep if request is throttled
	if delay > 0 {
		time.Sleep(time.Duration(delay) * time.Second)
	}

	Log.Debugf("Requesting object %v bytes %v - %v from API", b.object.ObjectID, offset, offsetEnd)
	req, err := http.NewRequest("GET", b.object.DownloadURL, nil)
	if nil != err {
		Log.Debugf("%v", err)
		return nil, fmt.Errorf("Could not create request object %v from API", b.object.ObjectID)
	}

	req.Header.Add("Range", fmt.Sprintf("bytes=%v-%v", offset, offsetEnd))

	Log.Tracef("Sending HTTP Request %v", req)

	res, err := b.client.Do(req)
	if nil != err {
		Log.Debugf("%v", err)
		return nil, fmt.Errorf("Could not request object %v from API", b.object.ObjectID)
	}
	defer res.Body.Close()
	reader := shapeio.NewReader(res.Body)

	// set the speed limit
	if speedLimit > 0 {
		reader.SetRateLimit(float64(speedLimit))
	}

	if res.StatusCode != 206 {
		if res.StatusCode != 403 {
			return nil, fmt.Errorf("Wrong status code %v", res)
		}

		// throttle requests
		if delay > 8 {
			return nil, fmt.Errorf("Maximum throttle interval has been reached")
		}
		bytes, err := ioutil.ReadAll(reader)
		if nil != err {
			Log.Debugf("%v", err)
			return nil, fmt.Errorf("Could not read body of 403 error")
		}
		body := string(bytes)
		if strings.Contains(body, "dailyLimitExceeded") ||
			strings.Contains(body, "userRateLimitExceeded") ||
			strings.Contains(body, "rateLimitExceeded") ||
			strings.Contains(body, "backendError") {
			if 0 == delay {
				delay = 1
			} else {
				delay = delay * 2
			}
			return b.ReadBytes(start, size, isPreload, delay)
		}
	}

	bytes, err := ioutil.ReadAll(reader)
	if nil != err {
		Log.Debugf("%v", err)
		return nil, fmt.Errorf("Could not read objects %v API response", b.object.ObjectID)
	}

	f, err := os.Create(filename)
	if nil != err {
		Log.Debugf("%v", err)
		return nil, fmt.Errorf("Could not create chunk temp file %v", filename)
	}
	defer f.Close()

	_, err = f.Write(bytes)
	if nil != err {
		Log.Debugf("%v", err)
		return nil, fmt.Errorf("Could not write chunk data to temp file %v", filename)
	}

	sOffset := int64(math.Min(float64(fOffset), float64(len(bytes))))
	eOffset := int64(math.Min(float64(fOffset+size), float64(len(bytes))))
	return bytes[sOffset:eOffset], nil
}

// cleanChunkDir checks if the chunk folder is grown to big and clears the oldest file if necessary
func cleanChunkDir(chunkPath string) error {
	chunkDirSize, err := dirSize(chunkPath)
	if nil != err {
		return err
	}

	if chunkDirSize+chunkSize*2 > chunkDirMaxSize {
		if err := deleteOldestFile(chunkPath); nil != err {
			return err
		}
	}

	return nil
}

// deleteOldestFile deletes the oldest file in the directory
func deleteOldestFile(path string) error {
	var fpath string
	lastMod := time.Now()

	err := filepath.Walk(path, func(file string, info os.FileInfo, err error) error {
		if !info.IsDir() {
			modTime := info.ModTime()
			if modTime.Before(lastMod) {
				lastMod = modTime
				fpath = file
			}
		}
		return err
	})

	os.Remove(fpath)

	return err
}

// dirSize gets the total directory size
func dirSize(path string) (int64, error) {
	var size int64
	err := filepath.Walk(path, func(_ string, info os.FileInfo, err error) error {
		if nil != err && nil != info && !info.IsDir() {
			size += info.Size()
		}
		return err
	})
	return size, err
}
<commit_msg>removed isPreload flag<commit_after>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"math"
	"net/http"
	"os"
	"path/filepath"
	"strconv"

	"time"

	"strings"

	. "github.com/claudetech/loggo/default"
	"github.com/fujiwara/shapeio"
	"github.com/orcaman/concurrent-map"
)

var instances cmap.ConcurrentMap
var chunkPath string
var chunkSize int64
var chunkDirMaxSize int64
var speedLimit int64

func init() {
	instances = cmap.New()
}

// Buffer is a buffered stream
type Buffer struct {
	numberOfInstances int
	client            *http.Client
	object            *APIObject
	tempDir           string
	preload           bool
	chunks            cmap.ConcurrentMap
}

// GetBufferInstance gets a singleton instance of buffer
func GetBufferInstance(client *http.Client, object *APIObject) (*Buffer, error) {
	if !instances.Has(object.ObjectID) {
		i, err := newBuffer(client, object)
		if nil != err {
			return nil, err
		}

		instances.Set(object.ObjectID, i)
	}

	instance, ok := instances.Get(object.ObjectID)
	// if buffer allocation failed due to race conditions it will try to fetch a new one
	if !ok {
		i, err := GetBufferInstance(client, object)
		if nil != err {
			return nil, err
		}
		instance = i
	}
	instance.(*Buffer).numberOfInstances++
	return instance.(*Buffer), nil
}

// SetChunkPath sets the global chunk path
func SetChunkPath(path string) {
	chunkPath = path
}

// SetChunkSize sets the global chunk size
func SetChunkSize(size int64) {
	chunkSize = size
}

// SetChunkDirMaxSize sets the maximum size of the chunk directory
func SetChunkDirMaxSize(size int64) {
	chunkDirMaxSize = size
}

// SetDownloadSpeedLimit sets the maximum bytes per seconds to be downloaded
func SetDownloadSpeedLimit(limit int64) {
	speedLimit = limit
}

// NewBuffer creates a new buffer instance
func newBuffer(client *http.Client, object *APIObject) (*Buffer, error) {
	Log.Infof("Starting playback of %v", object.Name)
	Log.Debugf("Creating buffer for object %v", object.ObjectID)

	tempDir := filepath.Join(chunkPath, object.ObjectID)
	if err := os.MkdirAll(tempDir, 0777); nil != err {
		Log.Debugf("%v", err)
		return nil, fmt.Errorf("Could not create temp path for object %v", object.ObjectID)
	}

	if 0 == chunkSize {
		Log.Debugf("ChunkSize was 0, setting to default (5 MB)")
		chunkSize = 5 * 1024 * 1024
	}

	buffer := Buffer{
		numberOfInstances: 0,
		client:            client,
		object:            object,
		tempDir:           tempDir,
		preload:           true,
		chunks:            cmap.New(),
	}

	return &buffer, nil
}

// Close all handles
func (b *Buffer) Close() error {
	b.numberOfInstances--
	if 0 == b.numberOfInstances {
		Log.Infof("Stopping playback of %v", b.object.Name)
		Log.Debugf("Stop buffering for object %v", b.object.ObjectID)

		b.preload = false
		instances.Remove(b.object.ObjectID)
	}
	return nil
}

// ReadBytes on a specific location
func (b *Buffer) ReadBytes(start, size int64, delay int32) ([]byte, error) {
	fOffset := start % chunkSize
	offset := start - fOffset
	offsetEnd := offset + chunkSize

	Log.Tracef("Getting object %v - chunk %v - offset %v for %v bytes",
		b.object.ObjectID, strconv.Itoa(int(offset)), fOffset, size)

	if b.preload && uint64(offsetEnd) < b.object.Size {
		defer func() {
			go func() {
				preloadStart := strconv.Itoa(int(offsetEnd))
				if !b.chunks.Has(preloadStart) {
					b.chunks.Set(preloadStart, true)
					b.ReadBytes(offsetEnd, size, 0)
				}
			}()
		}()
	}

	filename := filepath.Join(b.tempDir, strconv.Itoa(int(offset)))
	if f, err := os.Open(filename); nil == err {
		defer f.Close()

		buf := make([]byte, size)
		if n, err := f.ReadAt(buf, fOffset); n > 0 && (nil == err || io.EOF == err) {
			Log.Tracef("Found file %s bytes %v - %v in cache", filename, offset, offsetEnd)

			// update the last modified time for files that are often in use
			if err := os.Chtimes(filename, time.Now(), time.Now()); nil != err {
				Log.Warningf("Could not update last modified time for %v", filename)
			}

			return buf[:size], nil
		}

		Log.Debugf("%v", err)
		Log.Debugf("Could not read file %s at %v", filename, fOffset)
	}

	if chunkDirMaxSize > 0 {
		go func() {
			if err := cleanChunkDir(chunkPath); nil != err {
				Log.Debugf("%v", err)
				Log.Warningf("Could not delete oldest chunk")
			}
		}()
	}

	// sleep if request is throttled
	if delay > 0 {
		time.Sleep(time.Duration(delay) * time.Second)
	}

	Log.Debugf("Requesting object %v bytes %v - %v from API", b.object.ObjectID, offset, offsetEnd)
	req, err := http.NewRequest("GET", b.object.DownloadURL, nil)
	if nil != err {
		Log.Debugf("%v", err)
		return nil, fmt.Errorf("Could not create request object %v from API", b.object.ObjectID)
	}

	req.Header.Add("Range", fmt.Sprintf("bytes=%v-%v", offset, offsetEnd))

	Log.Tracef("Sending HTTP Request %v", req)

	res, err := b.client.Do(req)
	if nil != err {
		Log.Debugf("%v", err)
		return nil, fmt.Errorf("Could not request object %v from API", b.object.ObjectID)
	}
	defer res.Body.Close()
	reader := shapeio.NewReader(res.Body)

	// set the speed limit
	if speedLimit > 0 {
		reader.SetRateLimit(float64(speedLimit))
	}

	if res.StatusCode != 206 {
		if res.StatusCode != 403 {
			return nil, fmt.Errorf("Wrong status code %v", res)
		}

		// throttle requests
		if delay > 8 {
			return nil, fmt.Errorf("Maximum throttle interval has been reached")
		}
		bytes, err := ioutil.ReadAll(reader)
		if nil != err {
			Log.Debugf("%v", err)
			return nil, fmt.Errorf("Could not read body of 403 error")
		}
		body := string(bytes)
		if strings.Contains(body, "dailyLimitExceeded") ||
			strings.Contains(body, "userRateLimitExceeded") ||
			strings.Contains(body, "rateLimitExceeded") ||
			strings.Contains(body, "backendError") {
			if 0 == delay {
				delay = 1
			} else {
				delay = delay * 2
			}
			return b.ReadBytes(start, size, delay)
		}
	}

	bytes, err := ioutil.ReadAll(reader)
	if nil != err {
		Log.Debugf("%v", err)
		return nil, fmt.Errorf("Could not read objects %v API response", b.object.ObjectID)
	}

	f, err := os.Create(filename)
	if nil != err {
		Log.Debugf("%v", err)
		return nil, fmt.Errorf("Could not create chunk temp file %v", filename)
	}
	defer f.Close()

	_, err = f.Write(bytes)
	if nil != err {
		Log.Debugf("%v", err)
		return nil, fmt.Errorf("Could not write chunk data to temp file %v", filename)
	}

	sOffset := int64(math.Min(float64(fOffset), float64(len(bytes))))
	eOffset := int64(math.Min(float64(fOffset+size), float64(len(bytes))))
	return bytes[sOffset:eOffset], nil
}

// cleanChunkDir checks if the chunk folder is grown to big and clears the oldest file if necessary
func cleanChunkDir(chunkPath string) error {
	chunkDirSize, err := dirSize(chunkPath)
	if nil != err {
		return err
	}

	if chunkDirSize+chunkSize*2 > chunkDirMaxSize {
		if err := deleteOldestFile(chunkPath); nil != err {
			return err
		}
	}

	return nil
}

// deleteOldestFile deletes the oldest file in the directory
func deleteOldestFile(path string) error {
	var fpath string
	lastMod := time.Now()

	err := filepath.Walk(path, func(file string, info os.FileInfo, err error) error {
		if !info.IsDir() {
			modTime := info.ModTime()
			if modTime.Before(lastMod) {
				lastMod = modTime
				fpath = file
			}
		}
		return err
	})

	os.Remove(fpath)

	return err
}

// dirSize gets the total directory size
func dirSize(path string) (int64, error) {
	var size int64
	err := filepath.Walk(path, func(_ string, info os.FileInfo, err error) error {
		if nil != err && nil != info && !info.IsDir() {
			size += info.Size()
		}
		return err
	})
	return size, err
}
<|endoftext|>


<commit_before>package sql_test

import (
	"fmt"
	"testing"
	"time"

	"github.com/stretchr/testify/require"

	"github.com/ory/hydra/jwk"

	"github.com/ory/hydra/client"
	"github.com/ory/hydra/consent"
	"github.com/ory/hydra/driver"
	"github.com/ory/hydra/driver/configuration"
	"github.com/ory/hydra/internal"
	"github.com/ory/viper"
)

func TestManagers(t *testing.T) {
	conf := internal.NewConfigurationWithDefaults()
	viper.Set(configuration.ViperKeyAccessTokenLifespan, time.Hour)
	registries := map[string]driver.Registry{
		"memory": internal.NewRegistryMemory(t, conf),
	}

	if !testing.Short() {
		registries["postgres"], registries["mysql"], registries["cockroach"], _ = internal.ConnectDatabases(t)
	}

	for k, m := range registries {
		t.Run("package=client/manager="+k, func(t *testing.T) {
			t.Run("case=create-get-update-delete", client.TestHelperCreateGetUpdateDeleteClient(k, m.ClientManager()))

			t.Run("case=autogenerate-key", client.TestHelperClientAutoGenerateKey(k, m.ClientManager()))

			t.Run("case=auth-client", client.TestHelperClientAuthenticate(k, m.ClientManager()))
		})

		t.Run("package=consent/manager="+k, consent.ManagerTests(m.ConsentManager(), m.ClientManager(), m.OAuth2Storage()))

		t.Run("package=jwk/manager="+k, func(t *testing.T) {
			var testGenerator = &jwk.RS256Generator{}

			t.Run("TestManagerKey", func(t *testing.T) {
				ks, err := testGenerator.Generate("TestManagerKey", "sig")
				require.NoError(t, err)

				for name, r := range registries {
					t.Run(fmt.Sprintf("case=%s", name), jwk.TestHelperManagerKey(r.KeyManager(), ks, "TestManagerKey"))
				}
			})

			t.Run("TestManagerKeySet", func(t *testing.T) {
				ks, err := testGenerator.Generate("TestManagerKeySet", "sig")
				require.NoError(t, err)
				ks.Key("private")

				for name, r := range registries {
					t.Run(fmt.Sprintf("case=%s", name), jwk.TestHelperManagerKeySet(r.KeyManager(), ks, "TestManagerKeySet"))
				}
			})
		})
	}
}
<commit_msg>fix: run tests only once<commit_after>package sql_test

import (
	"testing"
	"time"

	"github.com/pborman/uuid"

	"github.com/stretchr/testify/require"

	"github.com/ory/hydra/jwk"

	"github.com/ory/hydra/client"
	"github.com/ory/hydra/consent"
	"github.com/ory/hydra/driver"
	"github.com/ory/hydra/driver/configuration"
	"github.com/ory/hydra/internal"
	"github.com/ory/viper"
)

func TestManagers(t *testing.T) {
	conf := internal.NewConfigurationWithDefaults()
	viper.Set(configuration.ViperKeyAccessTokenLifespan, time.Hour)
	registries := map[string]driver.Registry{
		"memory": internal.NewRegistryMemory(t, conf),
	}

	if !testing.Short() {
		registries["postgres"], registries["mysql"], registries["cockroach"], _ = internal.ConnectDatabases(t)
	}

	for k, m := range registries {
		t.Run("package=client/manager="+k, func(t *testing.T) {
			t.Run("case=create-get-update-delete", client.TestHelperCreateGetUpdateDeleteClient(k, m.ClientManager()))

			t.Run("case=autogenerate-key", client.TestHelperClientAutoGenerateKey(k, m.ClientManager()))

			t.Run("case=auth-client", client.TestHelperClientAuthenticate(k, m.ClientManager()))
		})

		t.Run("package=consent/manager="+k, consent.ManagerTests(m.ConsentManager(), m.ClientManager(), m.OAuth2Storage()))

		t.Run("package=jwk/manager="+k, func(t *testing.T) {
			var testGenerator = &jwk.RS256Generator{}

			t.Run("TestManagerKey", func(t *testing.T) {
				ks, err := testGenerator.Generate("TestManagerKey", "sig")
				require.NoError(t, err)

				jwk.TestHelperManagerKey(m.KeyManager(), ks, uuid.New())
			})

			t.Run("TestManagerKeySet", func(t *testing.T) {
				ks, err := testGenerator.Generate("TestManagerKeySet", "sig")
				require.NoError(t, err)
				ks.Key("private")

				jwk.TestHelperManagerKeySet(m.KeyManager(), ks, uuid.New())
			})
		})
	}
}
<|endoftext|>


<commit_before>package notebook

// Notebook is an interface which represents
// a collection of notes
type Notebook interface {
    // List returns the list of notes holding in the notebook
    List() Notes

    // Get returns a note from the notebook according to its name
    Get(string) (Note, error)

    // Set adds or updates a note in the notebook
    Set(string, []byte) error

    // Delete deletes a note from the notebook according to its name
    Delete(string) error
}
<commit_msg>fix(notebook): fixes the type of the return when getting a note from a notebook<commit_after>package notebook

// Notebook is an interface which represents
// a collection of notes
type Notebook interface {
    // List returns the list of notes holding in the notebook
    List() Notes

    // Get returns a note from the notebook according to its name
    Get(string) (*Note, error)

    // Set adds or updates a note in the notebook
    Set(string, []byte) error

    // Delete deletes a note from the notebook according to its name
    Delete(string) error
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	sdl "github.com/veandco/go-sdl2/sdl"
	ttf "github.com/veandco/go-sdl2/sdl_ttf"
	"os"
	"strconv"
)

type Cell struct {
	x    int32
	y    int32
	size int32
	val  int
	mark bool
}

type Board [81]Cell

type Ctx struct {
	window     *sdl.Window
	renderer   *sdl.Renderer
	board      *Board
	font       *ttf.Font
	charWidth  int
	charHeight int
}

func run() int {
	font, charWidth, charHeight := initFont()

	cellSize := int32(30)
	cellPadding := int32(6)
	startX := int32(20)
	startY := int32(20)

	winSize := int((cellSize + cellPadding) * 10)

	window := createWindow("Sugoku", winSize, winSize)
	renderer := createRenderer(window)
	board := initBoard(cellSize, startX, startY, cellPadding)
	ctx := Ctx{window, renderer, &board, font, charWidth, charHeight}

	drawBoard(&ctx)

	running := true
	for running {
		if event := sdl.WaitEvent(); event != nil {
			switch t := event.(type) {
			case *sdl.QuitEvent:
				running = false
			case *sdl.MouseButtonEvent:
				if t.State == 1 {
					clickButton(&ctx, t.X, t.Y)
				}
			case *sdl.KeyDownEvent:
				handleKey(&ctx, t.Keysym)
			}
		}
	}

	close(&ctx)

	return 0
}

func main() {
	os.Exit(run())
}

func initFont() (*ttf.Font, int, int) {
	if err := ttf.Init(); err != nil {
		panic(err)
	}

	font, err := ttf.OpenFont("/Library/Fonts/Courier New.ttf", 16)
	if err != nil {
		panic(err)
	}

	fW, fH, err := font.SizeUTF8("0")
	if err != nil {
		panic(err)
	}

	return font, fW, fH
}

func createWindow(title string, width int, height int) *sdl.Window {
	window, err := sdl.CreateWindow(
		title, sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED,
		width, height, sdl.WINDOW_SHOWN)

	if err != nil {
		panic(fmt.Sprintf("Failed to create window: %s\n", err))
	}

	return window
}

func createRenderer(window *sdl.Window) *sdl.Renderer {
	renderer, err := sdl.CreateRenderer(window, -1, sdl.RENDERER_ACCELERATED)

	if err != nil {
		panic(fmt.Sprintf("Failed to create renderer: %s\n", err))
	}

	return renderer
}

func initBoard(size int32, startX int32, startY int32, gap int32) Board {
	var board Board

	i := 0

	for y := int32(0); y < 9; y++ {
		sx := startX

		for x := int32(0); x < 9; x++ {
			nx := (x * size) + sx
			ny := (y * size) + startY

			board[i] = Cell{nx, ny, size, 0, false}

			sx += gap
			i += 1
		}

		startY += gap
	}

	return board
}

func drawBoard(ctx *Ctx) {
	ctx.renderer.SetDrawColor(0, 0, 0, 0)
	ctx.renderer.Clear()

	i := 0
	for i < 81 {
		cell := ctx.board[i]
		rect := sdl.Rect{cell.x, cell.y, cell.size, cell.size}
		innerRect := sdl.Rect{
			cell.x + ((cell.size / 2) - int32(ctx.charWidth/2)),
			cell.y + ((cell.size / 2) - int32(ctx.charHeight/2)),
			int32(ctx.charWidth),
			int32(ctx.charHeight),
		}

		ctx.renderer.SetDrawColor(80, 80, 80, 0)
		ctx.renderer.DrawRect(&rect)
		ctx.renderer.SetDrawColor(0, 0, 0, 0)
		ctx.renderer.DrawRect(&innerRect)

		if cell.mark {
			ctx.renderer.SetDrawColor(80, 80, 80, 0)
			ctx.renderer.FillRect(&rect)
		}

		text := " "
		if cell.val != 0 {
			text = strconv.Itoa(cell.val)
		}

		color := sdl.Color{255, 255, 255, 255}
		textSurface, err := ctx.font.RenderUTF8_Solid(text, color)
		if err != nil {
			panic(err)
		}

		texture, err := ctx.renderer.CreateTextureFromSurface(textSurface)
		if err != nil {
			panic(err)
		}

		textSurface.Free()

		ctx.renderer.Copy(texture, nil, &innerRect)

		i += 1
	}

	ctx.renderer.Present()
}

func clickButton(ctx *Ctx, x int32, y int32) {
	i := 0

	for i < 81 {
		cell := ctx.board[i]
		ctx.board[i].mark = false
		if x > cell.x && x < (cell.x+cell.size) {
			if y > cell.y && y < (cell.y+cell.size) {
				ctx.board[i].mark = true
			}
		}
		i += 1
	}

	drawBoard(ctx)
}

func handleKey(ctx *Ctx, key sdl.Keysym) {
	if key.Sym == 8 || (key.Sym >= 49 && key.Sym <= 57) {
		i := 0

		for i < 81 {
			if ctx.board[i].mark {
				if key.Sym == 8 {
					ctx.board[i].val = 0
				} else {
					ctx.board[i].val = int(key.Sym) - 48
				}
				break
			}

			i += 1
		}

	} else if key.Scancode == sdl.SCANCODE_DOWN ||
		key.Scancode == sdl.SCANCODE_UP ||
		key.Scancode == sdl.SCANCODE_LEFT ||
		key.Scancode == sdl.SCANCODE_RIGHT {

		i := 0
		found := -1

		for i < 81 {
			if ctx.board[i].mark {
				found = i
				break
			}
			i += 1
		}

		if found > -1 {
			mark := found

			if key.Scancode == sdl.SCANCODE_DOWN {
				mark += 9

				if mark > 80 {
					mark = found % 9
				}

			} else if key.Scancode == sdl.SCANCODE_RIGHT {
				mark += 1

				if mark%9 == 0 {
					mark -= 9
				}

			} else if key.Scancode == sdl.SCANCODE_UP {
				mark -= 9

				if mark < 0 {
					mark = (80 - 9) + ((found % 9) + 1)
				}
			} else if key.Scancode == sdl.SCANCODE_LEFT {
				mark -= 1

				if mark%9 == 8 {
					mark += 9
				}
			}

			ctx.board[i].mark = false
			ctx.board[mark].mark = true

		} else {
			ctx.board[0].mark = true
		}
	}

	drawBoard(ctx)
}

func close(ctx *Ctx) {
	ctx.window.Destroy()
	ctx.renderer.Destroy()
	ctx.font.Close()
}
<commit_msg>Populating initial values<commit_after>package main

import (
	"fmt"
	sdl "github.com/veandco/go-sdl2/sdl"
	ttf "github.com/veandco/go-sdl2/sdl_ttf"
	"math/rand"
	"os"
	"strconv"
	"time"
)

type Cell struct {
	x    int32
	y    int32
	size int32
	val  int
	mark bool
}

type Board [81]Cell

type Ctx struct {
	window     *sdl.Window
	renderer   *sdl.Renderer
	board      *Board
	font       *ttf.Font
	charWidth  int
	charHeight int
}

func run() int {
	font, charWidth, charHeight := initFont()

	cellSize := int32(30)
	cellPadding := int32(6)
	startX := int32(20)
	startY := int32(20)

	winSize := int((cellSize + cellPadding) * 10)

	window := createWindow("Sugoku", winSize, winSize)
	renderer := createRenderer(window)
	board := initBoard(cellSize, startX, startY, cellPadding)
	ctx := Ctx{window, renderer, &board, font, charWidth, charHeight}

	drawBoard(&ctx)

	running := true
	for running {
		if event := sdl.WaitEvent(); event != nil {
			switch t := event.(type) {
			case *sdl.QuitEvent:
				running = false
			case *sdl.MouseButtonEvent:
				if t.State == 1 {
					clickButton(&ctx, t.X, t.Y)
				}
			case *sdl.KeyDownEvent:
				handleKey(&ctx, t.Keysym)
			}
		}
	}

	close(&ctx)

	return 0
}

func main() {
	os.Exit(run())
}

func initFont() (*ttf.Font, int, int) {
	if err := ttf.Init(); err != nil {
		panic(err)
	}

	font, err := ttf.OpenFont("/Library/Fonts/Courier New.ttf", 16)
	if err != nil {
		panic(err)
	}

	fW, fH, err := font.SizeUTF8("0")
	if err != nil {
		panic(err)
	}

	return font, fW, fH
}

func createWindow(title string, width int, height int) *sdl.Window {
	window, err := sdl.CreateWindow(
		title, sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED,
		width, height, sdl.WINDOW_SHOWN)

	if err != nil {
		panic(fmt.Sprintf("Failed to create window: %s\n", err))
	}

	return window
}

func createRenderer(window *sdl.Window) *sdl.Renderer {
	renderer, err := sdl.CreateRenderer(window, -1, sdl.RENDERER_ACCELERATED)

	if err != nil {
		panic(fmt.Sprintf("Failed to create renderer: %s\n", err))
	}

	return renderer
}

func initBoard(size int32, startX int32, startY int32, gap int32) Board {
	var board Board

	i := 0
	initNums := make(map[int]bool, 20)

	// seed rand
	src := rand.NewSource(time.Now().UnixNano())
	rnd := rand.New(src)

	for _, v := range rnd.Perm(81)[:20] {
		initNums[v] = true
	}

	for y := int32(0); y < 9; y++ {
		sx := startX

		for x := int32(0); x < 9; x++ {
			nx := (x * size) + sx
			ny := (y * size) + startY

			val := 0

			if _, ok := initNums[i]; ok {
				val = randomValueForLine(&board, i)
			}

			board[i] = Cell{nx, ny, size, val, false}

			sx += gap
			i += 1
		}

		startY += gap
	}

	return board
}

func drawBoard(ctx *Ctx) {
	ctx.renderer.SetDrawColor(0, 0, 0, 0)
	ctx.renderer.Clear()

	i := 0
	for i < 81 {
		cell := ctx.board[i]
		rect := sdl.Rect{cell.x, cell.y, cell.size, cell.size}
		innerRect := sdl.Rect{
			cell.x + ((cell.size / 2) - int32(ctx.charWidth/2)),
			cell.y + ((cell.size / 2) - int32(ctx.charHeight/2)),
			int32(ctx.charWidth),
			int32(ctx.charHeight),
		}

		ctx.renderer.SetDrawColor(80, 80, 80, 0)
		ctx.renderer.DrawRect(&rect)
		ctx.renderer.SetDrawColor(0, 0, 0, 0)
		ctx.renderer.DrawRect(&innerRect)

		if cell.mark {
			ctx.renderer.SetDrawColor(80, 80, 80, 0)
			ctx.renderer.FillRect(&rect)
		}

		text := " "
		if cell.val != 0 {
			text = strconv.Itoa(cell.val)
		}

		color := sdl.Color{255, 255, 255, 255}
		textSurface, err := ctx.font.RenderUTF8_Solid(text, color)
		if err != nil {
			panic(err)
		}

		texture, err := ctx.renderer.CreateTextureFromSurface(textSurface)
		if err != nil {
			panic(err)
		}

		textSurface.Free()

		ctx.renderer.Copy(texture, nil, &innerRect)

		i += 1
	}

	ctx.renderer.Present()
}

func clickButton(ctx *Ctx, x int32, y int32) {
	i := 0

	for i < 81 {
		cell := ctx.board[i]
		ctx.board[i].mark = false
		if x > cell.x && x < (cell.x+cell.size) {
			if y > cell.y && y < (cell.y+cell.size) {
				ctx.board[i].mark = true
			}
		}
		i += 1
	}

	drawBoard(ctx)
}

func handleKey(ctx *Ctx, key sdl.Keysym) {
	if key.Sym == 8 || (key.Sym >= 49 && key.Sym <= 57) {
		i := 0

		for i < 81 {
			if ctx.board[i].mark {
				if key.Sym == 8 {
					ctx.board[i].val = 0
				} else {
					ctx.board[i].val = int(key.Sym) - 48
				}
				break
			}

			i += 1
		}

	} else if key.Scancode == sdl.SCANCODE_DOWN ||
		key.Scancode == sdl.SCANCODE_UP ||
		key.Scancode == sdl.SCANCODE_LEFT ||
		key.Scancode == sdl.SCANCODE_RIGHT {

		i := 0
		found := -1

		for i < 81 {
			if ctx.board[i].mark {
				found = i
				break
			}
			i += 1
		}

		if found > -1 {
			mark := found

			if key.Scancode == sdl.SCANCODE_DOWN {
				mark += 9

				if mark > 80 {
					mark = found % 9
				}

			} else if key.Scancode == sdl.SCANCODE_RIGHT {
				mark += 1

				if mark%9 == 0 {
					mark -= 9
				}

			} else if key.Scancode == sdl.SCANCODE_UP {
				mark -= 9

				if mark < 0 {
					mark = (80 - 9) + ((found % 9) + 1)
				}
			} else if key.Scancode == sdl.SCANCODE_LEFT {
				mark -= 1

				if mark%9 == 8 {
					mark += 9
				}
			}

			ctx.board[i].mark = false
			ctx.board[mark].mark = true

		} else {
			ctx.board[0].mark = true
		}
	}

	drawBoard(ctx)
}

func randomValueForLine(board *Board, pos int) int {
	var numbers [9]bool
	var i int

	number := -1

	// get numbers from x and y
	x := pos - (pos % 9)
	y := pos % 9

	i = 0
	for i < 9 {
		xv := board[x+i].val
		yv := board[y+(i*9)].val

		if xv > 0 {
			xv -= 1
			numbers[xv] = true
		}

		if yv > 0 {
			yv -= 1
			numbers[yv] = true
		}

		i += 1
	}

	// get numbers from the square
	sx := (pos / 9) / 3
	sy := (pos % 9) / 3

	a := 0
	for a < 3 {
		b := 0
		for b < 3 {
			p := (((sx * 3) + a) * 9) + ((sy * 3) + b)
			bp := board[p]
			if bp.val > 0 {
				numbers[bp.val-1] = true
			}
			b += 1
		}
		a += 1
	}

	// pick one unused random number
	src := rand.NewSource(time.Now().UnixNano())
	rnd := rand.New(src)

	i = 0
	for i < 9 {
		j := rnd.Intn(9)
		if !numbers[j] {
			number = j + 1
		}
		i += 1
	}

	return number
}

func close(ctx *Ctx) {
	ctx.window.Destroy()
	ctx.renderer.Destroy()
	ctx.font.Close()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	sdl "github.com/veandco/go-sdl2/sdl"
	ttf "github.com/veandco/go-sdl2/sdl_ttf"
	"math/rand"
	"os"
	"strconv"
	"time"
)

type Cell struct {
	x     int32
	y     int32
	size  int32
	val   int
	mark  bool
	fixed bool
}

type Board [81]Cell

type Ctx struct {
	window     *sdl.Window
	renderer   *sdl.Renderer
	board      *Board
	font       *ttf.Font
	charWidth  int
	charHeight int
}

func run() int {
	font, charWidth, charHeight := initFont()

	cellSize := int32(30)
	cellPadding := int32(6)
	startX := int32(20)
	startY := int32(20)

	winSize := int(
		((cellSize + cellPadding) * 10) +
			(cellPadding * 2), // extra padding separating squares
	)

	window := createWindow("Sugoku", winSize, winSize)
	renderer := createRenderer(window)
	board := initBoard(cellSize, startX, startY, cellPadding)
	ctx := Ctx{window, renderer, &board, font, charWidth, charHeight}

	drawBoard(&ctx)

	running := true
	for running {
		if event := sdl.WaitEvent(); event != nil {
			switch t := event.(type) {
			case *sdl.QuitEvent:
				running = false
			case *sdl.MouseButtonEvent:
				if t.State == 1 {
					clickButton(&ctx, t.X, t.Y)
				}
			case *sdl.KeyDownEvent:
				handleKey(&ctx, t.Keysym)
			}
		}
	}

	close(&ctx)

	return 0
}

func main() {
	os.Exit(run())
}

func initFont() (*ttf.Font, int, int) {
	if err := ttf.Init(); err != nil {
		panic(err)
	}

	font, err := ttf.OpenFont("/Library/Fonts/Courier New.ttf", 16)
	if err != nil {
		panic(err)
	}

	fW, fH, err := font.SizeUTF8("0")
	if err != nil {
		panic(err)
	}

	return font, fW, fH
}

func createWindow(title string, width int, height int) *sdl.Window {
	window, err := sdl.CreateWindow(
		title, sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED,
		width, height, sdl.WINDOW_SHOWN)

	if err != nil {
		panic(fmt.Sprintf("Failed to create window: %s\n", err))
	}

	return window
}

func createRenderer(window *sdl.Window) *sdl.Renderer {
	renderer, err := sdl.CreateRenderer(window, -1, sdl.RENDERER_ACCELERATED)

	if err != nil {
		panic(fmt.Sprintf("Failed to create renderer: %s\n", err))
	}

	return renderer
}

func initBoard(size int32, startX int32, startY int32, gap int32) Board {
	var board Board

	i := 0
	initNums := make(map[int]bool, 20)

	// seed rand
	src := rand.NewSource(time.Now().UnixNano())
	rnd := rand.New(src)

	for _, v := range rnd.Perm(81)[:20] {
		initNums[v] = true
	}

	for y := int32(0); y < 9; y++ {
		sx := startX

		for x := int32(0); x < 9; x++ {
			nx := (x * size) + sx
			ny := (y * size) + startY

			if _, ok := initNums[i]; ok {
				val := randomValueForLine(&board, i)
				board[i] = Cell{nx, ny, size, val, false, true}
			} else {
				board[i] = Cell{nx, ny, size, 0, false, false}
			}

			sx += gap

			if (x+1)%3 == 0 {
				sx += gap
			}

			i += 1
		}

		startY += gap

		if (y+1)%3 == 0 {
			startY += gap
		}
	}

	return board
}

func drawBoard(ctx *Ctx) {
	ctx.renderer.SetDrawColor(0, 0, 0, 0)
	ctx.renderer.Clear()

	highlightValue := getValueToHighlight(ctx.board)

	i := 0
	for i < 81 {
		cell := ctx.board[i]
		rect := sdl.Rect{cell.x, cell.y, cell.size, cell.size}
		innerRect := sdl.Rect{
			cell.x + ((cell.size / 2) - int32(ctx.charWidth/2)),
			cell.y + ((cell.size / 2) - int32(ctx.charHeight/2)),
			int32(ctx.charWidth),
			int32(ctx.charHeight),
		}

		ctx.renderer.SetDrawColor(80, 80, 80, 0)
		ctx.renderer.DrawRect(&rect)
		ctx.renderer.SetDrawColor(0, 0, 0, 0)
		ctx.renderer.DrawRect(&innerRect)

		if cell.mark {
			ctx.renderer.SetDrawColor(80, 80, 80, 0)
		} else if cell.fixed {
			ctx.renderer.SetDrawColor(40, 40, 40, 0)
		}

		if cell.mark || cell.fixed {
			ctx.renderer.FillRect(&rect)
		}

		text := " "
		color := sdl.Color{255, 255, 255, 0}

		if cell.val != 0 {
			text = strconv.Itoa(cell.val)
			isConflict := isConflictingNumber(ctx.board, i, cell.val)

			if !cell.fixed {
				if isConflict {
					color = sdl.Color{255, 0, 0, 0}
				}
			}

			if !isConflict && (cell.val == highlightValue) {
				color = sdl.Color{255, 255, 0, 0}
			}
		}

		textSurface, err := ctx.font.RenderUTF8_Solid(text, color)
		if err != nil {
			panic(err)
		}

		texture, err := ctx.renderer.CreateTextureFromSurface(textSurface)
		if err != nil {
			panic(err)
		}

		textSurface.Free()

		ctx.renderer.Copy(texture, nil, &innerRect)

		i += 1
	}

	ctx.renderer.Present()
}

func clickButton(ctx *Ctx, x int32, y int32) {
	i := 0

	for i < 81 {
		cell := ctx.board[i]
		ctx.board[i].mark = false
		if x > cell.x && x < (cell.x+cell.size) {
			if y > cell.y && y < (cell.y+cell.size) {
				ctx.board[i].mark = true
			}
		}
		i += 1
	}

	drawBoard(ctx)
}

func handleKey(ctx *Ctx, key sdl.Keysym) {
	if key.Sym == 8 || (key.Sym >= 49 && key.Sym <= 57) {
		i := 0

		for i < 81 {
			if ctx.board[i].mark {
				if !ctx.board[i].fixed {
					if key.Sym == 8 {
						ctx.board[i].val = 0
					} else {
						ctx.board[i].val = int(key.Sym) - 48
					}
				}
				break
			}

			i += 1
		}

	} else if key.Scancode == sdl.SCANCODE_DOWN ||
		key.Scancode == sdl.SCANCODE_UP ||
		key.Scancode == sdl.SCANCODE_LEFT ||
		key.Scancode == sdl.SCANCODE_RIGHT {

		i := 0
		found := -1

		for i < 81 {
			if ctx.board[i].mark {
				found = i
				break
			}
			i += 1
		}

		if found > -1 {
			mark := found

			if key.Scancode == sdl.SCANCODE_DOWN {
				mark += 9

				if mark > 80 {
					mark = found % 9
				}

			} else if key.Scancode == sdl.SCANCODE_RIGHT {
				mark += 1

				if mark%9 == 0 {
					mark -= 9
				}

			} else if key.Scancode == sdl.SCANCODE_UP {
				mark -= 9

				if mark < 0 {
					mark = (80 - 9) + ((found % 9) + 1)
				}
			} else if key.Scancode == sdl.SCANCODE_LEFT {
				mark -= 1

				if mark < 0 || mark%9 == 8 {
					mark += 9
				}
			}

			ctx.board[i].mark = false
			ctx.board[mark].mark = true

		} else {
			ctx.board[0].mark = true
		}
	}

	drawBoard(ctx)
}

func getConflictingNumbers(board *Board, pos int) [9]bool {
	var numbers [9]bool

	// get numbers from x and y
	x := pos - (pos % 9)
	y := pos % 9

	i := 0
	for i < 9 {
		xp := x + i
		yp := y + (i * 9)

		xv := board[xp].val
		yv := board[yp].val

		if xv > 0 {
			xv -= 1
			numbers[xv] = numbers[xv] || xp != pos
		}

		if yv > 0 {
			yv -= 1
			numbers[yv] = numbers[yv] || yp != pos
		}

		i += 1
	}

	// get numbers from the square
	sx := (pos / 9) / 3
	sy := (pos % 9) / 3

	a := 0
	for a < 3 {
		b := 0
		for b < 3 {
			p := (((sx * 3) + a) * 9) + ((sy * 3) + b)
			bp := board[p]
			if bp.val > 0 {
				pv := bp.val - 1
				numbers[pv] = numbers[pv] || p != pos
			}
			b += 1
		}
		a += 1
	}

	return numbers
}

func isConflictingNumber(board *Board, pos int, number int) bool {
	numbers := getConflictingNumbers(board, pos)
	return numbers[number-1]
}

func randomValueForLine(board *Board, pos int) int {
	numbers := getConflictingNumbers(board, pos)

	// pick one unused random number
	src := rand.NewSource(time.Now().UnixNano())
	rnd := rand.New(src)

	number := -1

	i := 0
	for i < 9 {
		j := rnd.Intn(9)
		if !numbers[j] {
			number = j + 1
		}
		i += 1
	}

	return number
}

func getValueToHighlight(board *Board) int {
	for _, v := range board {
		if v.mark {
			return v.val
		}
	}

	return -1
}

func close(ctx *Ctx) {
	ctx.window.Destroy()
	ctx.renderer.Destroy()
	ctx.font.Close()
}
<commit_msg>Added few instructions<commit_after>package main

import (
	"fmt"
	sdl "github.com/veandco/go-sdl2/sdl"
	ttf "github.com/veandco/go-sdl2/sdl_ttf"
	"math/rand"
	"os"
	"strconv"
	"time"
	"unicode/utf8"
)

type Cell struct {
	x     int32
	y     int32
	size  int32
	val   int
	mark  bool
	fixed bool
}

type Board [81]Cell

type Ctx struct {
	window      *sdl.Window
	renderer    *sdl.Renderer
	board       *Board
	cellSize    int32
	cellPadding int32
	font        *ttf.Font
	charWidth   int
	charHeight  int
}

func run() int {
	font, charWidth, charHeight := initFont()

	cellSize := int32(30)
	cellPadding := int32(6)
	startX := int32(20)
	startY := int32(20)

	winSize := int(
		((cellSize + cellPadding) * 10) +
			(cellPadding * 2), // extra padding separating squares
	)

	menuHeight := 30

	window := createWindow("Sugoku", winSize, winSize+menuHeight)
	renderer := createRenderer(window)
	board := initBoard(cellSize, startX, startY, cellPadding)
	ctx := Ctx{
		window, renderer, &board,
		cellSize, cellPadding,
		font, charWidth, charHeight,
	}

	drawBoard(&ctx)

	running := true
	for running {
		if event := sdl.WaitEvent(); event != nil {
			switch t := event.(type) {
			case *sdl.QuitEvent:
				running = false
			case *sdl.MouseButtonEvent:
				if t.State == 1 {
					clickButton(&ctx, t.X, t.Y)
				}
			case *sdl.KeyDownEvent:
				handleKey(&ctx, t.Keysym)
			}
		}
	}

	close(&ctx)

	return 0
}

func main() {
	os.Exit(run())
}

func initFont() (*ttf.Font, int, int) {
	if err := ttf.Init(); err != nil {
		panic(err)
	}

	font, err := ttf.OpenFont("/Library/Fonts/Courier New.ttf", 16)
	if err != nil {
		panic(err)
	}

	tfW := 0
	tfH := 0

	for _, v := range "0 " {
		fW, fH, err := font.SizeUTF8(fmt.Sprintf("%c", v))
		if err != nil {
			panic(err)
		}
		tfW += fW
		tfH = fH
	}

	return font, tfW / 2, tfH
}

func createWindow(title string, width int, height int) *sdl.Window {
	window, err := sdl.CreateWindow(
		title, sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED,
		width, height, sdl.WINDOW_SHOWN)

	if err != nil {
		panic(fmt.Sprintf("Failed to create window: %s\n", err))
	}

	return window
}

func createRenderer(window *sdl.Window) *sdl.Renderer {
	renderer, err := sdl.CreateRenderer(window, -1, sdl.RENDERER_ACCELERATED)

	if err != nil {
		panic(fmt.Sprintf("Failed to create renderer: %s\n", err))
	}

	return renderer
}

func initBoard(size int32, startX int32, startY int32, gap int32) Board {
	var board Board

	i := 0
	initNums := make(map[int]bool, 20)

	// seed rand
	src := rand.NewSource(time.Now().UnixNano())
	rnd := rand.New(src)

	for _, v := range rnd.Perm(81)[:20] {
		initNums[v] = true
	}

	for y := int32(0); y < 9; y++ {
		sx := startX

		for x := int32(0); x < 9; x++ {
			nx := (x * size) + sx
			ny := (y * size) + startY

			if _, ok := initNums[i]; ok {
				val := randomValueForLine(&board, i)
				board[i] = Cell{nx, ny, size, val, false, true}
			} else {
				board[i] = Cell{nx, ny, size, 0, false, false}
			}

			sx += gap

			if (x+1)%3 == 0 {
				sx += gap
			}

			i += 1
		}

		startY += gap

		if (y+1)%3 == 0 {
			startY += gap
		}
	}

	return board
}

func drawBoard(ctx *Ctx) {
	ctx.renderer.SetDrawColor(0, 0, 0, 0)
	ctx.renderer.Clear()

	highlightValue := getValueToHighlight(ctx.board)

	i := 0
	for i < 81 {
		cell := ctx.board[i]
		rect := sdl.Rect{cell.x, cell.y, cell.size, cell.size}
		innerRect := sdl.Rect{
			cell.x + ((cell.size / 2) - int32(ctx.charWidth/2)),
			cell.y + ((cell.size / 2) - int32(ctx.charHeight/2)),
			int32(ctx.charWidth),
			int32(ctx.charHeight),
		}

		ctx.renderer.SetDrawColor(80, 80, 80, 0)
		ctx.renderer.DrawRect(&rect)
		ctx.renderer.SetDrawColor(0, 0, 0, 0)
		ctx.renderer.DrawRect(&innerRect)

		if cell.mark {
			ctx.renderer.SetDrawColor(80, 80, 80, 0)
		} else if cell.fixed {
			ctx.renderer.SetDrawColor(40, 40, 40, 0)
		}

		if cell.mark || cell.fixed {
			ctx.renderer.FillRect(&rect)
		}

		text := " "
		color := sdl.Color{255, 255, 255, 0}

		if cell.val != 0 {
			text = strconv.Itoa(cell.val)
			isConflict := isConflictingNumber(ctx.board, i, cell.val)

			if !cell.fixed {
				if isConflict {
					color = sdl.Color{255, 0, 0, 0}
				}
			}

			if !isConflict && (cell.val == highlightValue) {
				color = sdl.Color{255, 255, 0, 0}
			}
		}

		textSurface, err := ctx.font.RenderUTF8_Solid(text, color)
		if err != nil {
			panic(err)
		}

		texture, err := ctx.renderer.CreateTextureFromSurface(textSurface)
		if err != nil {
			panic(err)
		}

		textSurface.Free()

		ctx.renderer.Copy(texture, nil, &innerRect)

		i += 1
	}

	drawMenu(ctx)

	ctx.renderer.Present()
}

func drawMenu(ctx *Ctx) {
	text := "Move: ↑ ↓ ← →"
	color := sdl.Color{80, 80, 80, 200}
	textSurface, err := ctx.font.RenderUTF8_Solid(text, color)
	if err != nil {
		panic(err)
	}

	texture, err := ctx.renderer.CreateTextureFromSurface(textSurface)
	if err != nil {
		panic(err)
	}

	textSurface.Free()

	textWidth := utf8.RuneCountInString(text) * ctx.charWidth

	X := int32(20)
	Y := int32(20) + (ctx.cellSize * 9) + (ctx.cellPadding * (4 + 4 + 2 + 2))
	W := int32(textWidth)
	H := int32(ctx.charHeight)

	innerRect := sdl.Rect{X, Y, W, H}

	ctx.renderer.SetDrawColor(0, 0, 0, 0)
	ctx.renderer.DrawRect(&innerRect)

	ctx.renderer.Copy(texture, nil, &innerRect)
}

func clickButton(ctx *Ctx, x int32, y int32) {
	i := 0

	for i < 81 {
		cell := ctx.board[i]
		ctx.board[i].mark = false
		if x > cell.x && x < (cell.x+cell.size) {
			if y > cell.y && y < (cell.y+cell.size) {
				ctx.board[i].mark = true
			}
		}
		i += 1
	}

	drawBoard(ctx)
}

func handleKey(ctx *Ctx, key sdl.Keysym) {
	if key.Sym == 8 || (key.Sym >= 49 && key.Sym <= 57) {
		i := 0

		for i < 81 {
			if ctx.board[i].mark {
				if !ctx.board[i].fixed {
					if key.Sym == 8 {
						ctx.board[i].val = 0
					} else {
						ctx.board[i].val = int(key.Sym) - 48
					}
				}
				break
			}

			i += 1
		}

	} else if key.Scancode == sdl.SCANCODE_DOWN ||
		key.Scancode == sdl.SCANCODE_UP ||
		key.Scancode == sdl.SCANCODE_LEFT ||
		key.Scancode == sdl.SCANCODE_RIGHT {

		i := 0
		found := -1

		for i < 81 {
			if ctx.board[i].mark {
				found = i
				break
			}
			i += 1
		}

		if found > -1 {
			mark := found

			if key.Scancode == sdl.SCANCODE_DOWN {
				mark += 9

				if mark > 80 {
					mark = found % 9
				}

			} else if key.Scancode == sdl.SCANCODE_RIGHT {
				mark += 1

				if mark%9 == 0 {
					mark -= 9
				}

			} else if key.Scancode == sdl.SCANCODE_UP {
				mark -= 9

				if mark < 0 {
					mark = (80 - 9) + ((found % 9) + 1)
				}
			} else if key.Scancode == sdl.SCANCODE_LEFT {
				mark -= 1

				if mark < 0 || mark%9 == 8 {
					mark += 9
				}
			}

			ctx.board[i].mark = false
			ctx.board[mark].mark = true

		} else {
			ctx.board[0].mark = true
		}
	}

	drawBoard(ctx)
}

func getConflictingNumbers(board *Board, pos int) [9]bool {
	var numbers [9]bool

	// get numbers from x and y
	x := pos - (pos % 9)
	y := pos % 9

	i := 0
	for i < 9 {
		xp := x + i
		yp := y + (i * 9)

		xv := board[xp].val
		yv := board[yp].val

		if xv > 0 {
			xv -= 1
			numbers[xv] = numbers[xv] || xp != pos
		}

		if yv > 0 {
			yv -= 1
			numbers[yv] = numbers[yv] || yp != pos
		}

		i += 1
	}

	// get numbers from the square
	sx := (pos / 9) / 3
	sy := (pos % 9) / 3

	a := 0
	for a < 3 {
		b := 0
		for b < 3 {
			p := (((sx * 3) + a) * 9) + ((sy * 3) + b)
			bp := board[p]
			if bp.val > 0 {
				pv := bp.val - 1
				numbers[pv] = numbers[pv] || p != pos
			}
			b += 1
		}
		a += 1
	}

	return numbers
}

func isConflictingNumber(board *Board, pos int, number int) bool {
	numbers := getConflictingNumbers(board, pos)
	return numbers[number-1]
}

func randomValueForLine(board *Board, pos int) int {
	numbers := getConflictingNumbers(board, pos)

	// pick one unused random number
	src := rand.NewSource(time.Now().UnixNano())
	rnd := rand.New(src)

	number := -1

	i := 0
	for i < 9 {
		j := rnd.Intn(9)
		if !numbers[j] {
			number = j + 1
		}
		i += 1
	}

	return number
}

func getValueToHighlight(board *Board) int {
	for _, v := range board {
		if v.mark {
			return v.val
		}
	}

	return -1
}

func close(ctx *Ctx) {
	ctx.window.Destroy()
	ctx.renderer.Destroy()
	ctx.font.Close()
}
<|endoftext|>


<commit_before>package surfbeam

import (
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"strconv"
	"strings"
)

// The default URI used to access the modem.
const DefaultModemURI string = "http://192.168.100.1"
const modemStatusPath string = "/index.cgi?page=modemStatusData"
const triaStatusPath string = "/index.cgi?page=triaStatusData"

// A Client is used to query the modem for status information.
type Client struct {
	modemURI string
	client   *http.Client
}

// New creates a new Client with the default http client.
func New(modemURI string) *Client {
	return &Client{modemURI, http.DefaultClient}
}

// NewWithClient creates a new Client with the given http client.
func NewWithClient(modemURI string, client *http.Client) *Client {
	return &Client{modemURI, client}
}

// ModemStatus retrieves information describing the state of the modem.
func (c *Client) ModemStatus() (*ModemStatus, error) {
	resp, err := c.client.Get(c.modemStatusURI())
	if err != nil {
		return nil, err
	}

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("HTTP response was not ok: %d", resp.StatusCode)
	}

	contents, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	return parseModemStatus(string(contents))
}

func (c *Client) modemStatusURI() string {
	return c.modemURI + modemStatusPath
}

func (c *Client) triaStatusURI() string {
	return c.modemURI + triaStatusPath
}

func parseModemStatus(str string) (*ModemStatus, error) {
	parts := strings.Split(str, "##")
	var status ModemStatus
	status.IPAddress = net.ParseIP(parts[0])
	if mac, err := net.ParseMAC(parts[1]); err != nil {
		return nil, err
	} else {
		status.MACAddress = mac
	}
	status.SoftwareVersion = parts[2]
	status.HardwareVersion = parts[3]
	status.Status = parts[4]
	if err := parseInt64(parts[5], &status.TransmittedPackets); err != nil {
		return nil, err
	}
	if err := parseInt64(parts[6], &status.TransmittedBytes); err != nil {
		return nil, err
	}
	if err := parseInt64(parts[7], &status.ReceivedPackets); err != nil {
		return nil, err
	}
	if err := parseInt64(parts[8], &status.ReceivedBytes); err != nil {
		return nil, err
	}
	status.OnlineTime = parts[9]
	if err := parseInt64(parts[10], &status.LossOfSyncCount); err != nil {
		return nil, err
	}
	if err := parseFloat64(parts[11], &status.RxSNR); err != nil {
		return nil, err
	}
	if err := parsePercentage(parts[12], &status.RxSNRPercentage); err != nil {
		return nil, err
	}
	status.SerialNumber = parts[13]
	if err := parseFloat64(parts[14], &status.RxPower); err != nil {
		return nil, err
	}
	if err := parsePercentage(parts[15], &status.RxPowerPercentage); err != nil {
		return nil, err
	}
	if err := parseFloat64(parts[16], &status.CableResistance); err != nil {
		return nil, err
	}
	if err := parsePercentage(parts[17], &status.CableResistancePercentage); err != nil {
		return nil, err
	}
	status.ODUTelemetryStatus = parts[18]
	if err := parseFloat64(parts[19], &status.CableAttenuation); err != nil {
		return nil, err
	}
	if err := parsePercentage(parts[20], &status.CableAttenuationPercentage); err != nil {
		return nil, err
	}
	status.IFLType = parts[21]
	status.PartNumber = parts[22]
	status.StatusImageURI = parts[23]
	status.SatelliteStatusURI = parts[24]
	status.Unknown25 = parts[25]
	status.StatusHTML = parts[26]
	status.HealthHTML = parts[27]
	status.Unknown28 = parts[28]
	status.Unknown29 = parts[29]
	status.LastPageLoadDuration = parts[30]
	status.Unknown31 = parts[31]
	status.Unknown32 = parts[32]
	return &status, nil
}

// Parses an integer from the given string. Can handle leading/trailing spaces
// as well as embedded commas.
func parseInt64(str string, dest *int64) error {
	str = strings.TrimSpace(str)
	if len(str) == 0 {
		*dest = 0
		return nil
	}

	str = strings.Replace(str, ",", "", -1) // Remove commas
	if val, err := strconv.ParseInt(str, 10, 64); err != nil {
		return err
	} else {
		*dest = val
		return nil
	}
}

// Parses a float from the given string. Can handle leading/trailing spaces as
// well as embedded commas.
func parseFloat64(str string, dest *float64) error {
	str = strings.TrimSpace(str)
	if len(str) == 0 {
		*dest = 0
		return nil
	}

	str = strings.Replace(str, ",", "", -1) // Remove commas
	if val, err := strconv.ParseFloat(str, 64); err != nil {
		return err
	} else {
		*dest = val
		return nil
	}
}

// Parses a float from the given string. This method works the same as
// parseFloat64 except that it also trims percentage signs (%).
func parsePercentage(str string, dest *float64) error {
	str = strings.Replace(str, "%", "", -1)
	return parseFloat64(str, dest)
}

// ModemStatus provides information describing the state of the modem.
type ModemStatus struct {
	IPAddress                  net.IP
	MACAddress                 net.HardwareAddr
	SoftwareVersion            string
	HardwareVersion            string
	Status                     string
	TransmittedPackets         int64
	TransmittedBytes           int64
	ReceivedPackets            int64
	ReceivedBytes              int64
	OnlineTime                 string // TODO: use time.Duration
	LossOfSyncCount            int64
	RxSNR                      float64
	RxSNRPercentage            float64
	SerialNumber               string
	RxPower                    float64
	RxPowerPercentage          float64
	CableResistance            float64
	CableResistancePercentage  float64
	ODUTelemetryStatus         string
	CableAttenuation           float64
	CableAttenuationPercentage float64
	IFLType                    string
	PartNumber                 string
	StatusImageURI             string
	SatelliteStatusURI         string
	Unknown25                  string
	StatusHTML                 string
	HealthHTML                 string
	Unknown28                  string
	Unknown29                  string
	LastPageLoadDuration       string
	Unknown31                  string
	Unknown32                  string
}
<commit_msg>go lint<commit_after>package surfbeam

import (
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"strconv"
	"strings"
)

// The default URI used to access the modem.
const DefaultModemURI string = "http://192.168.100.1"
const modemStatusPath string = "/index.cgi?page=modemStatusData"
const triaStatusPath string = "/index.cgi?page=triaStatusData"

// A Client is used to query the modem for status information.
type Client struct {
	modemURI string
	client   *http.Client
}

// New creates a new Client with the default http client.
func New(modemURI string) *Client {
	return &Client{modemURI, http.DefaultClient}
}

// NewWithClient creates a new Client with the given http client.
func NewWithClient(modemURI string, client *http.Client) *Client {
	return &Client{modemURI, client}
}

// ModemStatus retrieves information describing the state of the modem.
func (c *Client) ModemStatus() (*ModemStatus, error) {
	resp, err := c.client.Get(c.modemStatusURI())
	if err != nil {
		return nil, err
	}

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("HTTP response was not ok: %d", resp.StatusCode)
	}

	contents, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	return parseModemStatus(string(contents))
}

func (c *Client) modemStatusURI() string {
	return c.modemURI + modemStatusPath
}

func (c *Client) triaStatusURI() string {
	return c.modemURI + triaStatusPath
}

func parseModemStatus(str string) (*ModemStatus, error) {
	parts := strings.Split(str, "##")
	var status ModemStatus
	status.IPAddress = net.ParseIP(parts[0])
	mac, err := net.ParseMAC(parts[1])
	if err != nil {
		return nil, err
	}
	status.MACAddress = mac
	status.SoftwareVersion = parts[2]
	status.HardwareVersion = parts[3]
	status.Status = parts[4]
	if err := parseInt64(parts[5], &status.TransmittedPackets); err != nil {
		return nil, err
	}
	if err := parseInt64(parts[6], &status.TransmittedBytes); err != nil {
		return nil, err
	}
	if err := parseInt64(parts[7], &status.ReceivedPackets); err != nil {
		return nil, err
	}
	if err := parseInt64(parts[8], &status.ReceivedBytes); err != nil {
		return nil, err
	}
	status.OnlineTime = parts[9]
	if err := parseInt64(parts[10], &status.LossOfSyncCount); err != nil {
		return nil, err
	}
	if err := parseFloat64(parts[11], &status.RxSNR); err != nil {
		return nil, err
	}
	if err := parsePercentage(parts[12], &status.RxSNRPercentage); err != nil {
		return nil, err
	}
	status.SerialNumber = parts[13]
	if err := parseFloat64(parts[14], &status.RxPower); err != nil {
		return nil, err
	}
	if err := parsePercentage(parts[15], &status.RxPowerPercentage); err != nil {
		return nil, err
	}
	if err := parseFloat64(parts[16], &status.CableResistance); err != nil {
		return nil, err
	}
	if err := parsePercentage(parts[17], &status.CableResistancePercentage); err != nil {
		return nil, err
	}
	status.ODUTelemetryStatus = parts[18]
	if err := parseFloat64(parts[19], &status.CableAttenuation); err != nil {
		return nil, err
	}
	if err := parsePercentage(parts[20], &status.CableAttenuationPercentage); err != nil {
		return nil, err
	}
	status.IFLType = parts[21]
	status.PartNumber = parts[22]
	status.StatusImageURI = parts[23]
	status.SatelliteStatusURI = parts[24]
	status.Unknown25 = parts[25]
	status.StatusHTML = parts[26]
	status.HealthHTML = parts[27]
	status.Unknown28 = parts[28]
	status.Unknown29 = parts[29]
	status.LastPageLoadDuration = parts[30]
	status.Unknown31 = parts[31]
	status.Unknown32 = parts[32]
	return &status, nil
}

// Parses an integer from the given string. Can handle leading/trailing spaces
// as well as embedded commas.
func parseInt64(str string, dest *int64) error {
	str = strings.TrimSpace(str)
	if len(str) == 0 {
		*dest = 0
		return nil
	}

	str = strings.Replace(str, ",", "", -1) // Remove commas
	val, err := strconv.ParseInt(str, 10, 64)
	if err != nil {
		return err
	}

	*dest = val
	return nil
}

// Parses a float from the given string. Can handle leading/trailing spaces as
// well as embedded commas.
func parseFloat64(str string, dest *float64) error {
	str = strings.TrimSpace(str)
	if len(str) == 0 {
		*dest = 0
		return nil
	}

	str = strings.Replace(str, ",", "", -1) // Remove commas
	val, err := strconv.ParseFloat(str, 64)
	if err != nil {
		return err
	}

	*dest = val
	return nil
}

// Parses a float from the given string. This method works the same as
// parseFloat64 except that it also trims percentage signs (%).
func parsePercentage(str string, dest *float64) error {
	str = strings.Replace(str, "%", "", -1)
	return parseFloat64(str, dest)
}

// ModemStatus provides information describing the state of the modem.
type ModemStatus struct {
	IPAddress                  net.IP
	MACAddress                 net.HardwareAddr
	SoftwareVersion            string
	HardwareVersion            string
	Status                     string
	TransmittedPackets         int64
	TransmittedBytes           int64
	ReceivedPackets            int64
	ReceivedBytes              int64
	OnlineTime                 string // TODO: use time.Duration
	LossOfSyncCount            int64
	RxSNR                      float64
	RxSNRPercentage            float64
	SerialNumber               string
	RxPower                    float64
	RxPowerPercentage          float64
	CableResistance            float64
	CableResistancePercentage  float64
	ODUTelemetryStatus         string
	CableAttenuation           float64
	CableAttenuationPercentage float64
	IFLType                    string
	PartNumber                 string
	StatusImageURI             string
	SatelliteStatusURI         string
	Unknown25                  string
	StatusHTML                 string
	HealthHTML                 string
	Unknown28                  string
	Unknown29                  string
	LastPageLoadDuration       string
	Unknown31                  string
	Unknown32                  string
}
<|endoftext|>