<commit_before>package selfwatch

import (
	"database/sql"
	"log"
	"time"

	_ "github.com/mattn/go-sqlite3"
)

var keysSchema = `
CREATE TABLE keys (
	id INTEGER NOT NULL,
	created_at DATETIME,
	nrkeys INTEGER,
	PRIMARY KEY (id)
);
CREATE INDEX ix_keys_nrkeys ON keys (nrkeys);
CREATE INDEX ix_keys_created_at ON keys (created_at);
`

type WatchStorage struct {
	fname string
	db    *sql.DB
}

func NewWatchStorage(fname string) (*WatchStorage, error) {
	db, err := sql.Open("sqlite3", fname)

	if err != nil {
		return nil, err
	}

	return &WatchStorage{
		fname: fname,
		db:    db,
	}, nil
}

func (s *WatchStorage) CreateSchema() error {
	_, err := s.db.Exec(keysSchema)
	if err != nil {
		log.Fatal(err.Error())
	}
	return nil
}

func (s *WatchStorage) SchemaExists() bool {
	rows, err := s.db.Query(`SELECT 1 FROM sqlite_master WHERE type='table' AND name='keys';`)
	if err != nil {
		log.Fatal(err.Error())
	}
	defer rows.Close()
	for rows.Next() {
		return true
	}
	return false
}

func (s *WatchStorage) WriteKeys(keys int) error {
	tx, err := s.db.Begin()
	if err != nil {
		log.Fatal(err)
	}

	defer tx.Commit()

	stmt, err := tx.Prepare("insert into keys(created_at, nrkeys) values(?, ?)")

	if err != nil {
		log.Fatal(err)
	}

	defer stmt.Close()

	_, err = stmt.Exec(time.Now(), keys)
	if err != nil {
		log.Fatal(err)
	}

	return nil
}
<commit_msg>key counts after id<commit_after>package selfwatch

import (
	"database/sql"
	"log"
	"time"

	_ "github.com/mattn/go-sqlite3"
)

var keysSchema = `
CREATE TABLE keys (
	id INTEGER NOT NULL,
	created_at DATETIME,
	nrkeys INTEGER,
	PRIMARY KEY (id)
);
CREATE INDEX ix_keys_nrkeys ON keys (nrkeys);
CREATE INDEX ix_keys_created_at ON keys (created_at);
`

type WatchStorage struct {
	fname string
	db    *sql.DB
}

func NewWatchStorage(fname string) (*WatchStorage, error) {
	db, err := sql.Open("sqlite3", fname)

	if err != nil {
		return nil, err
	}

	return &WatchStorage{
		fname: fname,
		db:    db,
	}, nil
}

func (s *WatchStorage) CreateSchema() error {
	_, err := s.db.Exec(keysSchema)
	if err != nil {
		log.Fatal(err.Error())
	}
	return nil
}

func (s *WatchStorage) SchemaExists() bool {
	rows, err := s.db.Query(`SELECT 1 FROM sqlite_master WHERE type='table' AND name='keys';`)
	if err != nil {
		log.Fatal(err.Error())
	}
	defer rows.Close()
	for rows.Next() {
		return true
	}
	return false
}

func (s *WatchStorage) WriteKeys(keys int) error {
	tx, err := s.db.Begin()
	if err != nil {
		log.Fatal(err)
	}

	defer tx.Commit()

	stmt, err := tx.Prepare("insert into keys(created_at, nrkeys) values(?, ?)")

	if err != nil {
		log.Fatal(err)
	}

	defer stmt.Close()

	_, err = stmt.Exec(time.Now(), keys)
	if err != nil {
		log.Fatal(err)
	}

	return nil
}

func (s *WatchStorage) KeyCountsAfterId(id int64) error {
	rows, err := s.db.Query(`select nrkeys from keys where id > ?;`, id)

	if err != nil {
		return err
	}

	defer rows.Close()

	for rows.Next() {
		var keys int64
		err = rows.Scan(&keys)
		if err != nil {
			return err
		}
		log.Print(keys)
	}

	return nil
}
<|endoftext|>


<commit_before>package server

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

	"github.com/bouk/httprouter"
	"github.com/influxdata/chronograf"
)

type dashboardLinks struct {
	Self string `json:"self"` // Self link mapping to this resource
}

type dashboardResponse struct {
	chronograf.Dashboard
	Links dashboardLinks `json:"links"`
}

type getDashboardsResponse struct {
	Dashboards []dashboardResponse `json:"dashboards"`
}

func newDashboardResponse(d chronograf.Dashboard) dashboardResponse {
	base := "/chronograf/v1/dashboards"
	return dashboardResponse{
		Dashboard: d,
		Links: dashboardLinks{
			Self: fmt.Sprintf("%s/%d", base, d.ID),
		},
	}
}

// Dashboards returns all dashboards within the store
func (s *Service) Dashboards(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	dashboards, err := s.DashboardsStore.All(ctx)
	if err != nil {
		Error(w, http.StatusInternalServerError, "Error loading layouts", s.Logger)
		return
	}

	res := getDashboardsResponse{
		Dashboards: []dashboardResponse{},
	}

	for _, dashboard := range dashboards {
		res.Dashboards = append(res.Dashboards, newDashboardResponse(dashboard))
	}

	encodeJSON(w, http.StatusOK, res, s.Logger)
}

// DashboardID returns a single specified dashboard
func (s *Service) DashboardID(w http.ResponseWriter, r *http.Request) {
	id, err := paramID("id", r)
	if err != nil {
		Error(w, http.StatusUnprocessableEntity, err.Error(), s.Logger)
		return
	}

	ctx := r.Context()
	e, err := s.DashboardsStore.Get(ctx, chronograf.DashboardID(id))
	if err != nil {
		notFound(w, id, s.Logger)
		return
	}

	res := newDashboardResponse(*e)
	encodeJSON(w, http.StatusOK, res, s.Logger)
}

// NewDashboard creates and returns a new dashboard object
func (s *Service) NewDashboard(w http.ResponseWriter, r *http.Request) {
	var dashboard *chronograf.Dashboard
	if err := json.NewDecoder(r.Body).Decode(&dashboard); err != nil {
		invalidJSON(w, s.Logger)
		return
	}

	var err error
	if dashboard, err = s.DashboardsStore.Add(r.Context(), dashboard); err != nil {
		msg := fmt.Errorf("Error storing layout %v: %v", dashboard, err)
		unknownErrorWithMessage(w, msg, s.Logger)
		return
	}

	res := newDashboardResponse(*dashboard)
	w.Header().Add("Location", res.Links.Self)
	encodeJSON(w, http.StatusCreated, res, s.Logger)
}

// RemoveDashboard deletes a dashboard
func (s *Service) RemoveDashboard(w http.ResponseWriter, r *http.Request) {
	id, err := paramID("id", r)
	if err != nil {
		Error(w, http.StatusUnprocessableEntity, err.Error(), s.Logger)
		return
	}

	ctx := r.Context()
	e, err := s.DashboardsStore.Get(ctx, chronograf.DashboardID(id))
	if err != nil {
		notFound(w, id, s.Logger)
		return
	}

	if err := s.DashboardsStore.Delete(ctx, e); err != nil {
		unknownErrorWithMessage(w, err, s.Logger)
		return
	}
	w.WriteHeader(http.StatusNoContent)
}

// UpdateDashboard replaces a dashboard
func (s *Service) UpdateDashboard(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	idParam, err := strconv.Atoi(httprouter.GetParamFromContext(ctx, "id"))
	if err != nil {
		msg := fmt.Sprintf("Could not parse dashboard ID: %s", err)
		Error(w, http.StatusInternalServerError, msg, s.Logger)
	}
	id := chronograf.DashboardID(idParam)

	_, err = s.DashboardsStore.Get(ctx, id)
	if err != nil {
		Error(w, http.StatusNotFound, fmt.Sprintf("ID %s not found", id), s.Logger)
		return
	}

	var req *chronograf.Dashboard
	if err := json.NewDecoder(r.Body).Decode(req); err != nil {
		invalidJSON(w, s.Logger)
		return
	}
	req.ID = id

	if err := s.DashboardsStore.Update(ctx, req); err != nil {
		msg := fmt.Sprintf("Error updating dashboard ID %s: %v", id, err)
		Error(w, http.StatusInternalServerError, msg, s.Logger)
		return
	}

	res := newDashboardResponse(*req)
	encodeJSON(w, http.StatusOK, res, s.Logger)
}
<commit_msg>wording<commit_after>package server

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

	"github.com/bouk/httprouter"
	"github.com/influxdata/chronograf"
)

type dashboardLinks struct {
	Self string `json:"self"` // Self link mapping to this resource
}

type dashboardResponse struct {
	chronograf.Dashboard
	Links dashboardLinks `json:"links"`
}

type getDashboardsResponse struct {
	Dashboards []dashboardResponse `json:"dashboards"`
}

func newDashboardResponse(d chronograf.Dashboard) dashboardResponse {
	base := "/chronograf/v1/dashboards"
	return dashboardResponse{
		Dashboard: d,
		Links: dashboardLinks{
			Self: fmt.Sprintf("%s/%d", base, d.ID),
		},
	}
}

// Dashboards returns all dashboards within the store
func (s *Service) Dashboards(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	dashboards, err := s.DashboardsStore.All(ctx)
	if err != nil {
		Error(w, http.StatusInternalServerError, "Error loading dashboards", s.Logger)
		return
	}

	res := getDashboardsResponse{
		Dashboards: []dashboardResponse{},
	}

	for _, dashboard := range dashboards {
		res.Dashboards = append(res.Dashboards, newDashboardResponse(dashboard))
	}

	encodeJSON(w, http.StatusOK, res, s.Logger)
}

// DashboardID returns a single specified dashboard
func (s *Service) DashboardID(w http.ResponseWriter, r *http.Request) {
	id, err := paramID("id", r)
	if err != nil {
		Error(w, http.StatusUnprocessableEntity, err.Error(), s.Logger)
		return
	}

	ctx := r.Context()
	e, err := s.DashboardsStore.Get(ctx, chronograf.DashboardID(id))
	if err != nil {
		notFound(w, id, s.Logger)
		return
	}

	res := newDashboardResponse(*e)
	encodeJSON(w, http.StatusOK, res, s.Logger)
}

// NewDashboard creates and returns a new dashboard object
func (s *Service) NewDashboard(w http.ResponseWriter, r *http.Request) {
	var dashboard *chronograf.Dashboard
	if err := json.NewDecoder(r.Body).Decode(&dashboard); err != nil {
		invalidJSON(w, s.Logger)
		return
	}

	var err error
	if dashboard, err = s.DashboardsStore.Add(r.Context(), dashboard); err != nil {
		msg := fmt.Errorf("Error storing dashboard %v: %v", dashboard, err)
		unknownErrorWithMessage(w, msg, s.Logger)
		return
	}

	res := newDashboardResponse(*dashboard)
	w.Header().Add("Location", res.Links.Self)
	encodeJSON(w, http.StatusCreated, res, s.Logger)
}

// RemoveDashboard deletes a dashboard
func (s *Service) RemoveDashboard(w http.ResponseWriter, r *http.Request) {
	id, err := paramID("id", r)
	if err != nil {
		Error(w, http.StatusUnprocessableEntity, err.Error(), s.Logger)
		return
	}

	ctx := r.Context()
	e, err := s.DashboardsStore.Get(ctx, chronograf.DashboardID(id))
	if err != nil {
		notFound(w, id, s.Logger)
		return
	}

	if err := s.DashboardsStore.Delete(ctx, e); err != nil {
		unknownErrorWithMessage(w, err, s.Logger)
		return
	}
	w.WriteHeader(http.StatusNoContent)
}

// UpdateDashboard replaces a dashboard
func (s *Service) UpdateDashboard(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	idParam, err := strconv.Atoi(httprouter.GetParamFromContext(ctx, "id"))
	if err != nil {
		msg := fmt.Sprintf("Could not parse dashboard ID: %s", err)
		Error(w, http.StatusInternalServerError, msg, s.Logger)
	}
	id := chronograf.DashboardID(idParam)

	_, err = s.DashboardsStore.Get(ctx, id)
	if err != nil {
		Error(w, http.StatusNotFound, fmt.Sprintf("ID %s not found", id), s.Logger)
		return
	}

	var req *chronograf.Dashboard
	if err := json.NewDecoder(r.Body).Decode(req); err != nil {
		invalidJSON(w, s.Logger)
		return
	}
	req.ID = id

	if err := s.DashboardsStore.Update(ctx, req); err != nil {
		msg := fmt.Sprintf("Error updating dashboard ID %s: %v", id, err)
		Error(w, http.StatusInternalServerError, msg, s.Logger)
		return
	}

	res := newDashboardResponse(*req)
	encodeJSON(w, http.StatusOK, res, s.Logger)
}
<|endoftext|>


<commit_before>package model

import (
	"strings"
	"time"

	"github.com/jinzhu/gorm"
	"github.com/oinume/lekcije/server/errors"
	"golang.org/x/net/context"
)

const (
	contextKeyLoggedInUser = "loggedInUser"
)

type User struct {
	Id        uint32 `gorm:"primary_key;AUTO_INCREMENT"`
	Name      string
	Email     Email
	EmailVerified bool
	CreatedAt time.Time
	UpdatedAt time.Time
}

func (*User) TableName() string {
	return "user"
}

type UserServiceType struct {
	db *gorm.DB
}

var UserService UserServiceType

func (s *UserServiceType) TableName() string {
	return (&User{}).TableName()
}

func (s *UserServiceType) FindByPk(id uint32) (*User, error) {
	user := &User{}
	if err := s.db.First(user, &User{Id: id}).Error; err != nil {
		return nil, err
	}
	return user, nil
}

func (s *UserServiceType) FindOrCreate(name string, email Email) (*User, error) {
	user := User{
		Name: name,
		Email: email,
		EmailVerified: true, // TODO: set false after implement email verification
	}
	if err := s.db.FirstOrCreate(&user, User{Email: email}).Error; err != nil {
		return nil, errors.InternalWrapf(err, "Failed to get or create User: email=%v", email)
	}
	return &user, nil
}

func (s *UserServiceType) Create(name, email string) (*User, error) {
	e, err := NewEmailFromRaw(email)
	if err != nil {
		return nil, err
	}
	user := &User{
		Name:  name,
		Email: e,
	}
	if result := s.db.Create(user); result.Error != nil {
		return nil, errors.InternalWrapf(result.Error, "")
	}
	return user, nil
}

func (s *UserServiceType) UpdateEmail(user *User, newEmail string) error {
	email, err := NewEmailFromRaw(newEmail)
	if err != nil {
		return err
	}
	result := s.db.Exec("UPDATE user SET email = ? WHERE id = ?", email, user.Id)
	if result.Error != nil {
		return errors.InternalWrapf(
			result.Error,
			"Failed to update email: id=%v, email=%v", user.Id, email,
		)
	}
	return nil
}

func FindLoggedInUserAndSetToContext(token string, ctx context.Context) (*User, context.Context, error) {
	db := MustDb(ctx)
	user := &User{}
	sql := `
		SELECT * FROM user AS u
		INNER JOIN user_api_token AS uat ON u.id = uat.user_id
		WHERE uat.token = ?
		`
	result := db.Model(&User{}).Raw(strings.TrimSpace(sql), token).Scan(user)
	if result.Error != nil {
		if result.RecordNotFound() {
			return nil, nil, errors.NotFoundWrapf(result.Error, "Failed to find user: token=%s", token)
		}
		return nil, nil, errors.InternalWrapf(result.Error, "find user: token=%s", token)
	}
	c := context.WithValue(ctx, contextKeyLoggedInUser, user)
	return user, c, nil
}

// TODO: Move somewhere else model
func GetLoggedInUser(ctx context.Context) (*User, error) {
	value := ctx.Value(contextKeyLoggedInUser)
	if user, ok := value.(*User); ok {
		return user, nil
	}
	return nil, errors.NotFoundf("Logged in user not found in context")
}

func MustLoggedInUser(ctx context.Context) *User {
	user, err := GetLoggedInUser(ctx)
	if err != nil {
		panic(err)
	}
	return user
}
<commit_msg>gofmt<commit_after>package model

import (
	"strings"
	"time"

	"github.com/jinzhu/gorm"
	"github.com/oinume/lekcije/server/errors"
	"golang.org/x/net/context"
)

const (
	contextKeyLoggedInUser = "loggedInUser"
)

type User struct {
	Id            uint32 `gorm:"primary_key;AUTO_INCREMENT"`
	Name          string
	Email         Email
	EmailVerified bool
	CreatedAt     time.Time
	UpdatedAt     time.Time
}

func (*User) TableName() string {
	return "user"
}

type UserServiceType struct {
	db *gorm.DB
}

var UserService UserServiceType

func (s *UserServiceType) TableName() string {
	return (&User{}).TableName()
}

func (s *UserServiceType) FindByPk(id uint32) (*User, error) {
	user := &User{}
	if err := s.db.First(user, &User{Id: id}).Error; err != nil {
		return nil, err
	}
	return user, nil
}

func (s *UserServiceType) FindOrCreate(name string, email Email) (*User, error) {
	user := User{
		Name:          name,
		Email:         email,
		EmailVerified: true, // TODO: set false after implement email verification
	}
	if err := s.db.FirstOrCreate(&user, User{Email: email}).Error; err != nil {
		return nil, errors.InternalWrapf(err, "Failed to get or create User: email=%v", email)
	}
	return &user, nil
}

func (s *UserServiceType) Create(name, email string) (*User, error) {
	e, err := NewEmailFromRaw(email)
	if err != nil {
		return nil, err
	}
	user := &User{
		Name:  name,
		Email: e,
	}
	if result := s.db.Create(user); result.Error != nil {
		return nil, errors.InternalWrapf(result.Error, "")
	}
	return user, nil
}

func (s *UserServiceType) UpdateEmail(user *User, newEmail string) error {
	email, err := NewEmailFromRaw(newEmail)
	if err != nil {
		return err
	}
	result := s.db.Exec("UPDATE user SET email = ? WHERE id = ?", email, user.Id)
	if result.Error != nil {
		return errors.InternalWrapf(
			result.Error,
			"Failed to update email: id=%v, email=%v", user.Id, email,
		)
	}
	return nil
}

func FindLoggedInUserAndSetToContext(token string, ctx context.Context) (*User, context.Context, error) {
	db := MustDb(ctx)
	user := &User{}
	sql := `
		SELECT * FROM user AS u
		INNER JOIN user_api_token AS uat ON u.id = uat.user_id
		WHERE uat.token = ?
		`
	result := db.Model(&User{}).Raw(strings.TrimSpace(sql), token).Scan(user)
	if result.Error != nil {
		if result.RecordNotFound() {
			return nil, nil, errors.NotFoundWrapf(result.Error, "Failed to find user: token=%s", token)
		}
		return nil, nil, errors.InternalWrapf(result.Error, "find user: token=%s", token)
	}
	c := context.WithValue(ctx, contextKeyLoggedInUser, user)
	return user, c, nil
}

// TODO: Move somewhere else model
func GetLoggedInUser(ctx context.Context) (*User, error) {
	value := ctx.Value(contextKeyLoggedInUser)
	if user, ok := value.(*User); ok {
		return user, nil
	}
	return nil, errors.NotFoundf("Logged in user not found in context")
}

func MustLoggedInUser(ctx context.Context) *User {
	user, err := GetLoggedInUser(ctx)
	if err != nil {
		panic(err)
	}
	return user
}
<|endoftext|>


<commit_before>package questagbot

import (
	"encoding/json"
	"image"
	"math/rand"
	"net/http"
	"os"
	"strings"
	"time"

	"golang.org/x/net/context"

	"github.com/blan4/QuestagBot/telegram"
	hexapic "github.com/blan4/hexapic/core"
	"github.com/codegangsta/martini"
	"github.com/codegangsta/martini-contrib/binding"
	"github.com/joho/godotenv"

	"fmt"
	"google.golang.org/appengine"
	"google.golang.org/appengine/datastore"
	"google.golang.org/appengine/log"
	"google.golang.org/appengine/urlfetch"
)

const HelpText string = "Guess as more instagram tags as you can!\n/start - begin a quizz\n/stop - stop current quiz\n/status - see your results\n/top - show top 10 players"

// Global is struct for saving state
type Global struct {
	InstagramClientID string
	Tags              []string
	TelegramKey       string
}

// Question is struct to store question object
type Question struct {
	Answer   string   `json:"answer"`
	Variants []string `json:"variants"`
}

// Gamer is object to store in appengine datastore
type Gamer struct {
	ChatID          int        `json:"chat_id"`
	Questions       []Question `json:"questions"`
	CurrentQuestion int        `json:"current_question"`
	RightAnswers    int        `json:"right_answers"`
	WrongAnswers    int        `json:"wrong_answers"`
	Username        string     `json:"username"`
}

// GamerData is wrapper for appengine data store
type GamerData struct {
	GamerBlob    string
	RightAnswers int64
	WrongAnswers int64
	Gamer        *Gamer `datastore:"-"`
}

// Load is google store Question struct loader
func (data *GamerData) Load(p []datastore.Property) error {
	if err := datastore.LoadStruct(data, p); err != nil {
		return err
	}
	data.Gamer = new(Gamer)
	return json.Unmarshal([]byte(data.GamerBlob), data.Gamer)
}

// Save is google store Question struct saver
func (data *GamerData) Save() ([]datastore.Property, error) {
	blob, err := json.Marshal(data.Gamer)
	if err != nil {
		panic(err)
	}

	return []datastore.Property{
		datastore.Property{
			Name:    "GamerBlob",
			Value:   string(blob),
			NoIndex: true,
		},
		datastore.Property{
			Name:    "RightAnswers",
			Value:   int64(data.RightAnswers),
			NoIndex: false,
		},
		datastore.Property{
			Name:    "WrongAnswers",
			Value:   int64(data.WrongAnswers),
			NoIndex: false,
		},
	}, nil
}

func findGamer(c context.Context, id int64) (*Gamer, error) {
	data := new(GamerData)
	key := datastore.NewKey(c, "Gamer", "", id, nil)
	if err := datastore.Get(c, key, data); err != nil {
		return new(Gamer), err
	}
	return data.Gamer, nil
}

func saveGamer(c context.Context, gamer *Gamer) (err error) {
	log.Infof(c, "Saving %v", gamer)
	data := new(GamerData)
	data.Gamer = gamer
	data.RightAnswers = int64(gamer.RightAnswers)
	data.WrongAnswers = int64(gamer.WrongAnswers)
	log.Infof(c, "Data: %v", data)
	key := datastore.NewKey(c, "Gamer", "", int64(gamer.ChatID), nil)
	_, err = datastore.Put(c, key, data)
	return
}

func appEngine(c martini.Context, r *http.Request) {
	c.Map(appengine.NewContext(r))
}

var global Global

func init() {
	rand.Seed(time.Now().UTC().UnixNano())
	godotenv.Load("secrets.env")
	global.Tags = strings.Split(os.Getenv("TAGS"), ",")
	global.InstagramClientID = os.Getenv("INSTAGRAM_CLIENT_ID")
	global.TelegramKey = os.Getenv("TELEGRAM_KEY")

	m := martini.Classic()
	m.Use(appEngine)
	m.Use(martini.Logger())
	m.Get("/", func() string {
		return "Hello world"
	})
	m.Post("/bothook", binding.Bind(telegram.Update{}), func(c context.Context, update telegram.Update, w http.ResponseWriter) {
		httpClient := urlfetch.Client(c)
		tele := telegram.NewTelegram(httpClient, global.TelegramKey)
		log.Infof(c, "%v", update)
		gamer, err := findOrCreateGamer(update, c)
		defer saveGamer(c, gamer)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			log.Errorf(c, "Can't find or create gamer: %v", err)
			return
		}
		log.Infof(c, "Gamer : %v", gamer.ChatID)

		if strings.Index(update.Message.Text, "/start") == 0 {
			log.Infof(c, "Start game with %v, %v", gamer.ChatID, update.Message.From.Username)
			gamer.handleStart()
			tele.SendPhoto(update.Message.Chat.ID, generateImage(gamer.GetCurrentQuestion(), httpClient), "", 0, gamer.GetKeyboard())
			return
		}
		if strings.Index(update.Message.Text, "/stop") == 0 {
			log.Infof(c, "Stop game with %v, %v", gamer.ChatID, update.Message.From.Username)
			gamer.handleStop()
			tele.SendMessage(update.Message.Chat.ID, "Game over", true, 0, nil)
			return
		}
		if strings.Index(update.Message.Text, "/status") == 0 {
			log.Infof(c, "Show game status for %v, %v", gamer.ChatID, update.Message.From.Username)
			gamer.handleTop()
			tele.SendMessage(update.Message.Chat.ID, fmt.Sprintf("Your personal score:\nRight answers: %v\nWrong answers: %v\n%v accuracy", gamer.RightAnswers, gamer.WrongAnswers, gamer.GetAccuracy()*100), true, 0, nil)
			return
		}
		if strings.Index(update.Message.Text, "/top") == 0 {
			log.Infof(c, "Show top for %v, %v", gamer.ChatID, update.Message.From.Username)
			gamer.handleTop()
			tele.SendMessage(update.Message.Chat.ID, "Top 10 gamers", true, 0, nil)
			return
		}
		if strings.Index(update.Message.Text, "/help") == 0 {
			log.Infof(c, "Show help for %v, %v", gamer.ChatID, update.Message.From.Username)
			tele.SendMessage(update.Message.Chat.ID, HelpText, true, 0, nil)
			return
		}
		if gamer.isPlaying() {
			log.Infof(c, "Get answer from %v, %v on question %v", gamer.ChatID, update.Message.From.Username, gamer.GetCurrentQuestion())
			if gamer.handleAnswer(update.Message.Text) {
				log.Infof(c, "Right answer, gamer: %v, %v", gamer.ChatID, update.Message.From.Username)
				tele.SendMessage(update.Message.Chat.ID, "👍 Right!", true, 0, nil)
			} else {
				log.Infof(c, "Wrong answer, gamer: %v, %v", gamer.ChatID, update.Message.From.Username)
				tele.SendMessage(update.Message.Chat.ID, "😕 Wrong, "+gamer.GetCurrentQuestion().Answer, true, 0, nil)
			}
			tele.SendPhoto(update.Message.Chat.ID, generateImage(gamer.NextQuestion(), httpClient), "", 0, gamer.GetKeyboard())
			return
		}
		log.Infof(c, "Show help for %v, %v", gamer.ChatID, update.Message.From.Username)
		tele.SendMessage(update.Message.Chat.ID, HelpText, true, 0, nil)
	})
	http.Handle("/", m)
}

func findOrCreateGamer(update telegram.Update, c context.Context) (gamer *Gamer, err error) {
	chatID := update.Message.Chat.ID
	username := update.Message.From.Username
	if gamer, err = findGamer(c, int64(chatID)); err != nil {
		log.Infof(c, "Can't find gamer object for this chat: %v, %v", chatID, err)
		gamer.handleStart()
		gamer.ChatID = chatID
		gamer.Username = username
		if err := saveGamer(c, gamer); err != nil {
			log.Errorf(c, "Can't store in DB new gamer %v: %v", gamer, err)
			return nil, err
		}
		log.Infof(c, "Saved: %v", gamer.ChatID)
	} else {
		log.Infof(c, "Find gamer with id %v", chatID)
	}
	gamer.Username = username
	return gamer, nil
}

func generateImage(question Question, httpClient *http.Client) (img image.Image) {
	hexapicAPI := hexapic.NewSearchApi(global.InstagramClientID, httpClient)
	hexapicAPI.Count = 4
	imgs := hexapicAPI.SearchByTag(question.Answer)
	img = hexapic.GenerateCollage(imgs, 2, 2)
	return
}

// GetKeyboard helper to generate keyboard markup
func (gamer *Gamer) GetKeyboard() *telegram.ReplyKeyboardMarkup {
	question := gamer.GetCurrentQuestion()
	kb := &telegram.ReplyKeyboardMarkup{
		OneTimeKeyboard: true,
		ResizeKeyboard:  true,
		Keyboard: [][]string{
			[]string{question.Variants[0], question.Variants[1]},
			[]string{question.Variants[2], question.Variants[3]},
		},
	}
	return kb
}

// GetAccuracy - return persentage of right answers
func (gamer *Gamer) GetAccuracy() float32 {
	return float32(gamer.RightAnswers) / float32(gamer.RightAnswers+gamer.WrongAnswers)
}

// GetCurrentQuestion is helper method to get current question
func (gamer *Gamer) GetCurrentQuestion() Question {
	return gamer.Questions[gamer.CurrentQuestion]
}
func (gamer *Gamer) handleStart() {
	gamer.Questions = generateQuestionsQueue()
	gamer.CurrentQuestion = 0
}
func (gamer *Gamer) handleStop() {
	gamer.Questions = nil
	gamer.CurrentQuestion = 0
}
func (gamer *Gamer) handleTop()  {}
func (gamer *Gamer) handleHelp() {}
func (gamer *Gamer) handleAnswer(answer string) (isRight bool) {
	currentQuestion := gamer.GetCurrentQuestion()
	if currentQuestion.Answer == answer {
		gamer.RightAnswers++
		isRight = true
	} else {
		gamer.WrongAnswers++
		isRight = false
	}

	return
}

func (gamer *Gamer) isPlaying() bool {
	return gamer.Questions != nil
}

// NextQuestion return next question
func (gamer *Gamer) NextQuestion() Question {
	gamer.CurrentQuestion++
	if gamer.CurrentQuestion == len(global.Tags) {
		gamer.CurrentQuestion = 0
	}
	return gamer.GetCurrentQuestion()
}

func generateQuestionsQueue() []Question {
	tags := global.Tags
	answers := rand.Perm(len(tags))
	questions := make([]Question, 0, len(tags))
	for answer := range answers {
		variants := perm(4, len(tags), answer)

		variantsStr := make([]string, len(variants))
		for i, variant := range variants {
			variantsStr[i] = tags[variant]
		}

		question := Question{
			Answer:   tags[answer],
			Variants: variantsStr,
		}

		questions = append(questions, question)
	}

	return questions
}

func perm(size int, limit int, exclude int) []int {
	array := make([]int, size)
	i := 0
	for i < size-1 {
		r := rand.Intn(limit)
		if r != exclude {
			array[i] = r
			i++
		}
	}
	array[size-1] = exclude
	return array
}
<commit_msg>fix typo<commit_after>package questagbot

import (
	"encoding/json"
	"image"
	"math/rand"
	"net/http"
	"os"
	"strings"
	"time"

	"golang.org/x/net/context"

	"github.com/blan4/QuestagBot/telegram"
	hexapic "github.com/blan4/hexapic/core"
	"github.com/codegangsta/martini"
	"github.com/codegangsta/martini-contrib/binding"
	"github.com/joho/godotenv"

	"fmt"
	"google.golang.org/appengine"
	"google.golang.org/appengine/datastore"
	"google.golang.org/appengine/log"
	"google.golang.org/appengine/urlfetch"
)

const HelpText string = "Guess as more instagram tags as you can!\n/start - begin a quizz\n/stop - stop current quiz\n/status - see your results\n/top - show top 10 players"

// Global is struct for saving state
type Global struct {
	InstagramClientID string
	Tags              []string
	TelegramKey       string
}

// Question is struct to store question object
type Question struct {
	Answer   string   `json:"answer"`
	Variants []string `json:"variants"`
}

// Gamer is object to store in appengine datastore
type Gamer struct {
	ChatID          int        `json:"chat_id"`
	Questions       []Question `json:"questions"`
	CurrentQuestion int        `json:"current_question"`
	RightAnswers    int        `json:"right_answers"`
	WrongAnswers    int        `json:"wrong_answers"`
	Username        string     `json:"username"`
}

// GamerData is wrapper for appengine data store
type GamerData struct {
	GamerBlob    string
	RightAnswers int64
	WrongAnswers int64
	Gamer        *Gamer `datastore:"-"`
}

// Load is google store Question struct loader
func (data *GamerData) Load(p []datastore.Property) error {
	if err := datastore.LoadStruct(data, p); err != nil {
		return err
	}
	data.Gamer = new(Gamer)
	return json.Unmarshal([]byte(data.GamerBlob), data.Gamer)
}

// Save is google store Question struct saver
func (data *GamerData) Save() ([]datastore.Property, error) {
	blob, err := json.Marshal(data.Gamer)
	if err != nil {
		panic(err)
	}

	return []datastore.Property{
		datastore.Property{
			Name:    "GamerBlob",
			Value:   string(blob),
			NoIndex: true,
		},
		datastore.Property{
			Name:    "RightAnswers",
			Value:   int64(data.RightAnswers),
			NoIndex: false,
		},
		datastore.Property{
			Name:    "WrongAnswers",
			Value:   int64(data.WrongAnswers),
			NoIndex: false,
		},
	}, nil
}

func findGamer(c context.Context, id int64) (*Gamer, error) {
	data := new(GamerData)
	key := datastore.NewKey(c, "Gamer", "", id, nil)
	if err := datastore.Get(c, key, data); err != nil {
		return new(Gamer), err
	}
	return data.Gamer, nil
}

func saveGamer(c context.Context, gamer *Gamer) (err error) {
	log.Infof(c, "Saving %v", gamer)
	data := new(GamerData)
	data.Gamer = gamer
	data.RightAnswers = int64(gamer.RightAnswers)
	data.WrongAnswers = int64(gamer.WrongAnswers)
	log.Infof(c, "Data: %v", data)
	key := datastore.NewKey(c, "Gamer", "", int64(gamer.ChatID), nil)
	_, err = datastore.Put(c, key, data)
	return
}

func appEngine(c martini.Context, r *http.Request) {
	c.Map(appengine.NewContext(r))
}

var global Global

func init() {
	rand.Seed(time.Now().UTC().UnixNano())
	godotenv.Load("secrets.env")
	global.Tags = strings.Split(os.Getenv("TAGS"), ",")
	global.InstagramClientID = os.Getenv("INSTAGRAM_CLIENT_ID")
	global.TelegramKey = os.Getenv("TELEGRAM_KEY")

	m := martini.Classic()
	m.Use(appEngine)
	m.Use(martini.Logger())
	m.Get("/", func() string {
		return "Hello world"
	})
	m.Post("/bothook", binding.Bind(telegram.Update{}), func(c context.Context, update telegram.Update, w http.ResponseWriter) {
		httpClient := urlfetch.Client(c)
		tele := telegram.NewTelegram(httpClient, global.TelegramKey)
		log.Infof(c, "%v", update)
		gamer, err := findOrCreateGamer(update, c)
		defer saveGamer(c, gamer)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			log.Errorf(c, "Can't find or create gamer: %v", err)
			return
		}
		log.Infof(c, "Gamer : %v", gamer.ChatID)

		if strings.Index(update.Message.Text, "/start") == 0 {
			log.Infof(c, "Start game with %v, %v", gamer.ChatID, update.Message.From.Username)
			gamer.handleStart()
			tele.SendPhoto(update.Message.Chat.ID, generateImage(gamer.GetCurrentQuestion(), httpClient), "", 0, gamer.GetKeyboard())
			return
		}
		if strings.Index(update.Message.Text, "/stop") == 0 {
			log.Infof(c, "Stop game with %v, %v", gamer.ChatID, update.Message.From.Username)
			gamer.handleStop()
			tele.SendMessage(update.Message.Chat.ID, "Game over", true, 0, nil)
			return
		}
		if strings.Index(update.Message.Text, "/status") == 0 {
			log.Infof(c, "Show game status for %v, %v", gamer.ChatID, update.Message.From.Username)
			gamer.handleTop()
			tele.SendMessage(update.Message.Chat.ID, fmt.Sprintf("Your personal score:\nRight answers: %v\nWrong answers: %v\n%v accuracy", gamer.RightAnswers, gamer.WrongAnswers, gamer.GetAccuracy()*100), true, 0, nil)
			return
		}
		if strings.Index(update.Message.Text, "/top") == 0 {
			log.Infof(c, "Show top for %v, %v", gamer.ChatID, update.Message.From.Username)
			gamer.handleTop()
			tele.SendMessage(update.Message.Chat.ID, "Top 10 gamers", true, 0, nil)
			return
		}
		if strings.Index(update.Message.Text, "/help") == 0 {
			log.Infof(c, "Show help for %v, %v", gamer.ChatID, update.Message.From.Username)
			tele.SendMessage(update.Message.Chat.ID, HelpText, true, 0, nil)
			return
		}
		if gamer.isPlaying() {
			log.Infof(c, "Get answer from %v, %v on question %v", gamer.ChatID, update.Message.From.Username, gamer.GetCurrentQuestion())
			if gamer.handleAnswer(update.Message.Text) {
				log.Infof(c, "Right answer, gamer: %v, %v", gamer.ChatID, update.Message.From.Username)
				tele.SendMessage(update.Message.Chat.ID, "👍 Right!", true, 0, nil)
			} else {
				log.Infof(c, "Wrong answer, gamer: %v, %v", gamer.ChatID, update.Message.From.Username)
				tele.SendMessage(update.Message.Chat.ID, "😕 Wrong, "+gamer.GetCurrentQuestion().Answer, true, 0, nil)
			}
			tele.SendPhoto(update.Message.Chat.ID, generateImage(gamer.NextQuestion(), httpClient), "", 0, gamer.GetKeyboard())
			return
		}
		log.Infof(c, "Show help for %v, %v", gamer.ChatID, update.Message.From.Username)
		tele.SendMessage(update.Message.Chat.ID, HelpText, true, 0, nil)
	})
	http.Handle("/", m)
}

func findOrCreateGamer(update telegram.Update, c context.Context) (gamer *Gamer, err error) {
	chatID := update.Message.Chat.ID
	username := update.Message.From.Username
	if gamer, err = findGamer(c, int64(chatID)); err != nil {
		log.Infof(c, "Can't find gamer object for this chat: %v, %v", chatID, err)
		gamer.handleStart()
		gamer.ChatID = chatID
		gamer.Username = username
		if err := saveGamer(c, gamer); err != nil {
			log.Errorf(c, "Can't store in DB new gamer %v: %v", gamer, err)
			return nil, err
		}
		log.Infof(c, "Saved: %v", gamer.ChatID)
	} else {
		log.Infof(c, "Find gamer with id %v", chatID)
	}
	gamer.Username = username
	return gamer, nil
}

func generateImage(question Question, httpClient *http.Client) (img image.Image) {
	hexapicAPI := hexapic.NewSearchApi(global.InstagramClientID, httpClient)
	hexapicAPI.Count = 4
	imgs := hexapicAPI.SearchByTag(question.Answer)
	img = hexapic.GenerateCollage(imgs, 2, 2)
	return
}

// GetKeyboard helper to generate keyboard markup
func (gamer *Gamer) GetKeyboard() *telegram.ReplyKeyboardMarkup {
	question := gamer.GetCurrentQuestion()
	kb := &telegram.ReplyKeyboardMarkup{
		OneTimeKeyboard: true,
		ResizeKeyboard:  true,
		Keyboard: [][]string{
			[]string{question.Variants[0], question.Variants[1]},
			[]string{question.Variants[2], question.Variants[3]},
		},
	}
	return kb
}

// GetAccuracy - return persentage of right answers
func (gamer *Gamer) GetAccuracy() float32 {
	if gamer.RightAnswers+gamer.WrongAnswers == 0 {
		return 0.0
	}
	return float32(gamer.RightAnswers) / float32(gamer.RightAnswers+gamer.WrongAnswers)
}

// GetCurrentQuestion is helper method to get current question
func (gamer *Gamer) GetCurrentQuestion() Question {
	return gamer.Questions[gamer.CurrentQuestion]
}
func (gamer *Gamer) handleStart() {
	gamer.Questions = generateQuestionsQueue()
	gamer.CurrentQuestion = 0
}
func (gamer *Gamer) handleStop() {
	gamer.Questions = nil
	gamer.CurrentQuestion = 0
}
func (gamer *Gamer) handleTop()  {}
func (gamer *Gamer) handleHelp() {}
func (gamer *Gamer) handleAnswer(answer string) (isRight bool) {
	currentQuestion := gamer.GetCurrentQuestion()
	if currentQuestion.Answer == answer {
		gamer.RightAnswers++
		isRight = true
	} else {
		gamer.WrongAnswers++
		isRight = false
	}

	return
}

func (gamer *Gamer) isPlaying() bool {
	return gamer.Questions != nil
}

// NextQuestion return next question
func (gamer *Gamer) NextQuestion() Question {
	gamer.CurrentQuestion++
	if gamer.CurrentQuestion == len(global.Tags) {
		gamer.CurrentQuestion = 0
	}
	return gamer.GetCurrentQuestion()
}

func generateQuestionsQueue() []Question {
	tags := global.Tags
	answers := rand.Perm(len(tags))
	questions := make([]Question, 0, len(tags))
	for answer := range answers {
		variants := perm(4, len(tags), answer)

		variantsStr := make([]string, len(variants))
		for i, variant := range variants {
			variantsStr[i] = tags[variant]
		}

		question := Question{
			Answer:   tags[answer],
			Variants: variantsStr,
		}

		questions = append(questions, question)
	}

	return questions
}

func perm(size int, limit int, exclude int) []int {
	array := make([]int, size)
	i := 0
	for i < size-1 {
		r := rand.Intn(limit)
		if r != exclude {
			array[i] = r
			i++
		}
	}
	array[size-1] = exclude
	return array
}
<|endoftext|>


<commit_before>package slurpylog

import (
	"bytes"
	"errors"
	"regexp"
	"fmt"
	"strconv"
	"time"
)

var matcher = regexp.MustCompile(
	`^(?:<(\d+)>)?(\w{3}  ?\d{1,2} \d{2}:\d{2}:\d{2}) ([^ ]+) ([^ \[\]]+)(?:\[(\d+)\])?:(.*)`)
const dateformat = "2006 Jan _2 15:04:05"

var severityMap = map[int]string{
	0: "EMERG",
	1: "ALERT",
	2: "CRIT",
	3: "ERR",
	4: "WARNING",
	5: "NOTICE",
	6: "INFO",
	7: "DEBUG",
}

var facilityMap = map[int]string{
	0:   "KERN",
	8:   "USER",
	16:  "MAIL",
	24:  "DAEMON",
	32:  "AUTH",
	40:  "SYSLOG",
	48:  "LPR",
	56:  "NEWS",
	64:  "UUCP",
	72:  "CRON",
	80:  "AUTHPRIV",
	88:  "FTP",
	128: "LOCAL0",
	136: "LOCAL1",
	144: "LOCAL2",
	152: "LOCAL3",
	160: "LOCAL4",
	168: "LOCAL5",
	176: "LOCAL6",
	184: "LOCAL7",
}

func FacilityGetName(facility int) (string, error) {
	name, ok := facilityMap[facility]
	if !ok {
		return "", errors.New("Out of range")
	}
	return name, nil
}

func SeverityGetName(severity int) (string, error) {
	name, ok := severityMap[severity]
	if !ok {
		return "", errors.New("Out of range")
	}
	return name, nil
}

type SyslogMsg struct {
	Priority    int
	Facility    int
	Severity    int
	Pid         int
	Host        string
	DateTime    time.Time
	ProcName    string
	Msg         string
	OriginalTxt []byte
}

func parseSyslogMsg(buf []byte) (*SyslogMsg, error) {
	matches := matcher.FindSubmatch(buf)
	if len(matches) == 0 {
		return nil, errors.New("No match")
	}

	var prio int
	var err error
	if len(matches[2]) != 0 {
		prio, err = strconv.Atoi(string(matches[1]))
		if err != nil {
			return nil, errors.New("prio failed to convert")
		}
	} else {
		// default prio a relay must write if none is readable
		prio = 13
	}

	var datetime time.Time
	if len(matches[2]) != 0 {
		dateWithYear := fmt.Sprintf("%d %s", time.Now().Year(), string(matches[2]))
		datetime, _ = time.Parse(dateformat, dateWithYear)
	}

	var host string
	if len(matches[3]) != 0 {
		host = string(matches[3])
	}

	var procname string
	if len(matches[4]) != 0 {
		procname = string(matches[4])
	}

	var pid int
	if len(matches[5]) != 0 {
		pid, err = strconv.Atoi(string(matches[5]))
		if err != nil {
			return nil, errors.New("pid failed to convert")
		}
	}

	msg := string(bytes.TrimSpace(matches[6]))

	m := &SyslogMsg{
		Priority: prio,
		Severity: prio % 8,
		Facility: prio - (prio % 8),
		Host: host,
		DateTime: datetime,
		ProcName: procname,
		Pid: pid,
		Msg: msg,
		OriginalTxt: matches[0]}
	return m, nil
}
<commit_msg>do not add year -- syslog spec compliance<commit_after>package slurpylog

import (
	"bytes"
	"errors"
	"regexp"
	"strconv"
	"time"
)

var matcher = regexp.MustCompile(
	`^(?:<(\d+)>)?(\w{3}  ?\d{1,2} \d{2}:\d{2}:\d{2}) ([^ ]+) ([^ \[\]]+)(?:\[(\d+)\])?:(.*)`)
const dateformat = "Jan _2 15:04:05"

var severityMap = map[int]string{
	0: "EMERG",
	1: "ALERT",
	2: "CRIT",
	3: "ERR",
	4: "WARNING",
	5: "NOTICE",
	6: "INFO",
	7: "DEBUG",
}

var facilityMap = map[int]string{
	0:   "KERN",
	8:   "USER",
	16:  "MAIL",
	24:  "DAEMON",
	32:  "AUTH",
	40:  "SYSLOG",
	48:  "LPR",
	56:  "NEWS",
	64:  "UUCP",
	72:  "CRON",
	80:  "AUTHPRIV",
	88:  "FTP",
	128: "LOCAL0",
	136: "LOCAL1",
	144: "LOCAL2",
	152: "LOCAL3",
	160: "LOCAL4",
	168: "LOCAL5",
	176: "LOCAL6",
	184: "LOCAL7",
}

func FacilityGetName(facility int) (string, error) {
	name, ok := facilityMap[facility]
	if !ok {
		return "", errors.New("Out of range")
	}
	return name, nil
}

func SeverityGetName(severity int) (string, error) {
	name, ok := severityMap[severity]
	if !ok {
		return "", errors.New("Out of range")
	}
	return name, nil
}

type SyslogMsg struct {
	Priority    int
	Facility    int
	Severity    int
	Pid         int
	Host        string
	DateTime    time.Time
	ProcName    string
	Msg         string
	OriginalTxt []byte
}

func parseSyslogMsg(buf []byte) (*SyslogMsg, error) {
	matches := matcher.FindSubmatch(buf)
	if len(matches) == 0 {
		return nil, errors.New("No match")
	}

	var prio int
	var err error
	if len(matches[2]) != 0 {
		prio, err = strconv.Atoi(string(matches[1]))
		if err != nil {
			return nil, errors.New("prio failed to convert")
		}
	} else {
		// default prio a relay must write if none is readable
		prio = 13
	}

	var datetime time.Time
	if len(matches[2]) != 0 {
		datetime, _ = time.Parse(dateformat, string(matches[2]))
	}

	var host string
	if len(matches[3]) != 0 {
		host = string(matches[3])
	}

	var procname string
	if len(matches[4]) != 0 {
		procname = string(matches[4])
	}

	var pid int
	if len(matches[5]) != 0 {
		pid, err = strconv.Atoi(string(matches[5]))
		if err != nil {
			return nil, errors.New("pid failed to convert")
		}
	}

	msg := string(bytes.TrimSpace(matches[6]))

	m := &SyslogMsg{
		Priority: prio,
		Severity: prio % 8,
		Facility: prio - (prio % 8),
		Host: host,
		DateTime: datetime,
		ProcName: procname,
		Pid: pid,
		Msg: msg,
		OriginalTxt: matches[0]}
	return m, nil
}
<|endoftext|>


<commit_before>package tls

import (
	"crypto/tls"
	"net/http"
	"os"
	"path"
	"path/filepath"
	"strings"
	"time"
)

func (m *Module) loadTLSConfig() (*tls.Config, error) {
	tlsConfig := &tls.Config{
		NextProtos: []string{"h2"}, // http/2
	}

	// keys are stored in a different place currently
	// extra dot is a hack to skip over session key
	glob := m.Config.DataPath("*.key", "")
	m.Logger.Infof("loading certs from %s", glob)
	matches, err := filepath.Glob(glob)
	if err != nil {
		return nil, err
	}
	if len(matches) == 0 {
		return nil, nil
	}

	for _, keyFile := range matches {
		crtFile := path.Base(strings.TrimSuffix(keyFile, ".key") + ".crt")
		cert, err := tls.LoadX509KeyPair(m.tlsDirPath(crtFile), keyFile)
		if err != nil {
			if os.IsNotExist(err) {
				continue
			}
			return nil, err
		}
		m.Logger.Infof("found certs %s %s", keyFile, crtFile)
		tlsConfig.Certificates = append(tlsConfig.Certificates, cert)
	}
	tlsConfig.BuildNameToCertificate()
	return tlsConfig, nil
}

// StartTLSProxy starts the tls proxy
func (m *Module) StartTLSProxy() error {
	tlsConfig, err := m.loadTLSConfig()
	if err != nil {
		return err
	}
	if tlsConfig == nil {
		return nil
	}
	l, err := tls.Listen("tcp", ":443", tlsConfig)
	if err != nil {
		return err
	}
	server := &http.Server{
		ReadTimeout:  10 * time.Second,
		WriteTimeout: 10 * time.Second,
		Handler:      m.Router,
		TLSConfig:    tlsConfig, // needed for http/2
	}
	return server.Serve(l)
}
<commit_msg>tls: Fix incorrect dir for .key files.<commit_after>package tls

import (
	"crypto/tls"
	"net/http"
	"os"
	"path"
	"path/filepath"
	"strings"
	"time"
)

func (m *Module) loadTLSConfig() (*tls.Config, error) {
	tlsConfig := &tls.Config{
		NextProtos: []string{"h2"}, // http/2
	}

	// keys are stored in a different place currently
	// extra dot is a hack to skip over session key
	glob := m.Config.DataPath("*.key", "")
	glob := m.tlsDirPath("*.key")
	m.Logger.Infof("loading certs from %s", glob)
	matches, err := filepath.Glob(glob)
	if err != nil {
		return nil, err
	}
	if len(matches) == 0 {
		return nil, nil
	}

	for _, keyFile := range matches {
		crtFile := path.Base(strings.TrimSuffix(keyFile, ".key") + ".crt")
		cert, err := tls.LoadX509KeyPair(m.tlsDirPath(crtFile), keyFile)
		if err != nil {
			if os.IsNotExist(err) {
				continue
			}
			return nil, err
		}
		m.Logger.Infof("found certs %s %s", keyFile, crtFile)
		tlsConfig.Certificates = append(tlsConfig.Certificates, cert)
	}
	tlsConfig.BuildNameToCertificate()
	return tlsConfig, nil
}

// StartTLSProxy starts the tls proxy
func (m *Module) StartTLSProxy() error {
	tlsConfig, err := m.loadTLSConfig()
	if err != nil {
		return err
	}
	if tlsConfig == nil {
		return nil
	}
	l, err := tls.Listen("tcp", ":443", tlsConfig)
	if err != nil {
		return err
	}
	server := &http.Server{
		ReadTimeout:  10 * time.Second,
		WriteTimeout: 10 * time.Second,
		Handler:      m.Router,
		TLSConfig:    tlsConfig, // needed for http/2
	}
	return server.Serve(l)
}
<|endoftext|>


<commit_before>// Package mucp initialises a mucp service
package mucp

import (
	// TODO: change to go-micro/service
	"github.com/micro/go-micro"
	"github.com/micro/go-micro/client/mucp"
	"github.com/micro/go-micro/server/mucp"
)

// NewService returns a new mucp service
func NewService(opts ...micro.Option) micro.Service {
	options := []micro.Option{
		micro.Client(mucp.NewClient()),
		micro.Server(mucp.NewServer()),
	}

	options = append(options, opts...)

	return micro.NewService(opts...)
}
<commit_msg>update import names for mucp<commit_after>// Package mucp initialises a mucp service
package mucp

import (
	// TODO: change to go-micro/service
	"github.com/micro/go-micro"
	cmucp "github.com/micro/go-micro/client/mucp"
	smucp "github.com/micro/go-micro/server/mucp"
)

// NewService returns a new mucp service
func NewService(opts ...micro.Option) micro.Service {
	options := []micro.Option{
		micro.Client(cmucp.NewClient()),
		micro.Server(smucp.NewServer()),
	}

	options = append(options, opts...)

	return micro.NewService(opts...)
}
<|endoftext|>


<commit_before>package pixur

import (
	"bytes"
	"database/sql"
	"fmt"
	"image"
	"image/draw"
	"io"
	"io/ioutil"
	"log"
	"mime/multipart"
	"net/http"
	"os"
	"strings"
	"sync"
	"unicode"

	"github.com/nfnt/resize"

	_ "image/gif"
	"image/jpeg"
	_ "image/png"
)

const (
	thumbnailWidth  = 160
	thumbnailHeight = 160
)

var (
	errTagNotFound   = fmt.Errorf("Unable to find Tag")
	errDuplicateTags = fmt.Errorf("Data Corruption: Duplicate tags found")
)

type CreatePicTask struct {
	// Deps
	pixPath string
	db      *sql.DB

	// Inputs
	Filename string
	FileData multipart.File
	TagNames []string

	// Alternatively, a url can be uploaded
	FileURL string

	// State
	// The file that was created to hold the upload.
	tempFilename string
	tx           *sql.Tx

	// Results
	CreatedPic *Pic
}

func (t *CreatePicTask) Reset() {
	if t.tempFilename != "" {
		if err := os.Remove(t.tempFilename); err != nil {
			log.Println("ERROR Unable to remove image in CreatePicTask", t.tempFilename, err)
		}
	}
	if t.tx != nil {
		if err := t.tx.Rollback(); err != nil && err != sql.ErrTxDone {
			log.Println("ERROR Unable to rollback in CreatePicTask", err)
		}
	}
}

func (t *CreatePicTask) Run() error {
	wf, err := ioutil.TempFile(t.pixPath, "__")
	if err != nil {
		return err
	}
	defer wf.Close()
	t.tempFilename = wf.Name()

	var p = new(Pic)
	fillTimestamps(p)

	if t.FileData != nil {
		if err := t.moveUploadedFile(wf, p); err != nil {
			return err
		}
	} else if t.FileURL != "" {
		if err := t.downloadFile(wf, p); err != nil {
			return err
		}
	} else {
		return fmt.Errorf("No file uploaded")
	}

	img, err := t.fillImageConfig(wf, p)
	if err != nil {
		return err
	}
	thumbnail := makeThumbnail(img)
	if err := t.beginTransaction(); err != nil {
		return err
	}
	if err := t.insertPic(p); err != nil {
		return err
	}
	if err := t.renameTempFile(p); err != nil {
		return err
	}

	// If there is a problem creating the thumbnail, just continue on.
	if err := t.saveThumbnail(thumbnail, p); err != nil {
		log.Println("WARN Failed to create thumbnail", err)
	}

	tags, err := t.insertOrFindTags()
	if err != nil {
		return err
	}
	// must happen after pic is created, because it depends on pic id
	if err := t.addTagsForPic(p, tags); err != nil {
		return err
	}

	if err := t.tx.Commit(); err != nil {
		return err
	}

	// The upload succeeded
	t.tempFilename = ""
	t.CreatedPic = p
	return nil
}

// Moves the uploaded file and records the file size.  It might not be possible to just move the
// file in the event that the uploaded location is on a different partition than persistent dir.
func (t *CreatePicTask) moveUploadedFile(tempFile io.Writer, p *Pic) error {
	// TODO: check if the t.FileData is an os.File, and then try moving it.
	if bytesWritten, err := io.Copy(tempFile, t.FileData); err != nil {
		return err
	} else {
		p.FileSize = bytesWritten
	}
	return nil
}

func (t *CreatePicTask) downloadFile(tempFile io.Writer, p *Pic) error {
	resp, err := http.Get(t.FileURL)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	// TODO: check the response code

	if bytesWritten, err := io.Copy(tempFile, resp.Body); err != nil {
		return err
	} else {
		p.FileSize = bytesWritten
	}
	return nil
}

func (t *CreatePicTask) fillImageConfig(tempFile io.ReadSeeker, p *Pic) (image.Image, error) {
	if _, err := tempFile.Seek(0, os.SEEK_SET); err != nil {
		return nil, err
	}

	img, imgType, err := image.Decode(tempFile)

	if err != nil {
		return nil, err
	}

	// TODO: handle this error
	p.Mime, _ = FromImageFormat(imgType)
	p.Width = int64(img.Bounds().Dx())
	p.Height = int64(img.Bounds().Dy())
	return img, nil
}

func (t *CreatePicTask) beginTransaction() error {
	if tx, err := t.db.Begin(); err != nil {
		return err
	} else {
		t.tx = tx
	}
	return nil
}

func (t *CreatePicTask) insertPic(p *Pic) error {
	res, err := t.tx.Exec(p.BuildInsert(), p.ColumnPointers(p.GetColumnNames())...)
	if err != nil {
		return err
	}
	if insertId, err := res.LastInsertId(); err != nil {
		return err
	} else {
		p.Id = insertId
	}
	return nil
}

func (t *CreatePicTask) renameTempFile(p *Pic) error {
	if err := os.Rename(t.tempFilename, p.Path(t.pixPath)); err != nil {
		return err
	}
	// point this at the new file, incase the overall transaction fails
	t.tempFilename = p.Path(t.pixPath)
	return nil
}

func (t *CreatePicTask) saveThumbnail(img image.Image, p *Pic) error {
	f, err := os.Create(p.ThumbnailPath(t.pixPath))
	if err != nil {
		return err
	}
	defer f.Close()
	return jpeg.Encode(f, img, nil)
}

// This function is not really transactional, because it hits multiple entity roots.
// TODO: test this.
func (t *CreatePicTask) insertOrFindTags() ([]*Tag, error) {
	type findTagResult struct {
		tag *Tag
		err error
	}

	var cleanedTags = cleanTagNames(t.TagNames)

	var resultMap = make(map[string]*findTagResult, len(cleanedTags))
	var lock sync.Mutex

	now := getNowMillis()

	var wg sync.WaitGroup
	for _, tagName := range cleanedTags {
		wg.Add(1)
		go func(name string) {
			defer wg.Done()

			tx, err := t.db.Begin()
			if err != nil {
				lock.Lock()
				defer lock.Unlock()
				resultMap[name] = &findTagResult{
					tag: nil,
					err: err,
				}
				return
			}

			tag, err := findAndUpsertTag(name, now, tx)
			if err != nil {
				// TODO: maybe do something with this error?
				tx.Rollback()
			} else {
				err = tx.Commit()
			}

			lock.Lock()
			defer lock.Unlock()
			resultMap[name] = &findTagResult{
				tag: tag,
				err: err,
			}
		}(tagName)
	}
	wg.Wait()

	var allTags []*Tag
	for _, result := range resultMap {
		if result.err != nil {
			return nil, result.err
		}
		allTags = append(allTags, result.tag)
	}

	return allTags, nil
}

// findAndUpsertTag looks for an existing tag by name.  If it finds it, it updates the modified
// time and usage counter.  Otherwise, it creates a new tag with an initial count of 1.
func findAndUpsertTag(tagName string, now int64, tx *sql.Tx) (*Tag, error) {
	tag, err := findTagByName(tagName, tx)
	if err == errTagNotFound {
		tag, err = createTag(tagName, now, tx)
	} else if err != nil {
		return nil, err
	} else {
		tag.ModifiedTime = now
		tag.Count += 1
		err = tag.Update(tx)
	}

	if err != nil {
		return nil, err
	}

	return tag, nil
}

func createTag(tagName string, now int64, tx *sql.Tx) (*Tag, error) {
	tag := &Tag{
		Name:         tagName,
		Count:        1,
		CreatedTime:  now,
		ModifiedTime: now,
	}

	if err := tag.Insert(tx); err != nil {
		return nil, err
	}
	return tag, nil
}

func findTagByName(tagName string, tx *sql.Tx) (*Tag, error) {
	tags, err := findTags(tx, "SELECT * FROM tags WHERE name = ?;", tagName)
	if err != nil {
		return nil, err
	}
	switch len(tags) {
	case 0:
		return nil, errTagNotFound
	case 1:
		return tags[0], nil
	default:
		return nil, errDuplicateTags
	}
}

func findTags(tx *sql.Tx, query string, args ...interface{}) ([]*Tag, error) {
	rows, err := tx.Query(query, args...)
	if err != nil {
		return nil, err
	}

	defer rows.Close()
	columnNames, err := rows.Columns()
	if err != nil {
		return nil, err
	}

	var tags []*Tag
	for rows.Next() {
		t := new(Tag)
		if err := rows.Scan(t.ColumnPointers(columnNames)...); err != nil {
			return nil, err
		}
		tags = append(tags, t)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return tags, nil
}

func findPicTagsByPicId(picId int64, db *sql.DB) ([]*PicTag, error) {
	return findPicTags(db, "SELECT * FROM pictags WHERE pic_id = ?;", picId)
}

func findPicTags(db *sql.DB, query string, args ...interface{}) ([]*PicTag, error) {
	rows, err := db.Query(query, args...)
	if err != nil {
		return nil, err
	}

	defer rows.Close()
	columnNames, err := rows.Columns()
	if err != nil {
		return nil, err
	}

	var picTags []*PicTag
	for rows.Next() {
		pt := new(PicTag)
		if err := rows.Scan(pt.ColumnPointers(columnNames)...); err != nil {
			return nil, err
		}
		picTags = append(picTags, pt)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return picTags, nil
}

func (t *CreatePicTask) addTagsForPic(p *Pic, tags []*Tag) error {
	for _, tag := range tags {
		picTag := &PicTag{
			PicId:        p.Id,
			TagId:        tag.Id,
			Name:         tag.Name,
			CreatedTime:  p.CreatedTime,
			ModifiedTime: p.ModifiedTime,
		}
		_, err := t.db.Exec(picTag.BuildInsert(), picTag.ColumnPointers(picTag.GetColumnNames())...)
		if err != nil {
			return err
		}
	}
	return nil
}

// TODO: interpret image rotation metadata
func makeThumbnail(img image.Image) image.Image {
	bounds := findMaxSquare(img.Bounds())
	largeSquareImage := image.NewNRGBA(bounds)
	draw.Draw(largeSquareImage, bounds, img, bounds.Min, draw.Src)
	return resize.Resize(thumbnailWidth, thumbnailHeight, largeSquareImage, resize.NearestNeighbor)
}

func findMaxSquare(bounds image.Rectangle) image.Rectangle {
	width := bounds.Dx()
	height := bounds.Dy()
	if height < width {
		missingSpace := width - height
		return image.Rectangle{
			Min: image.Point{
				X: bounds.Min.X + missingSpace/2,
				Y: bounds.Min.Y,
			},
			Max: image.Point{
				X: bounds.Min.X + missingSpace/2 + height,
				Y: bounds.Max.Y,
			},
		}
	} else {
		missingSpace := height - width
		return image.Rectangle{
			Min: image.Point{
				X: bounds.Min.X,
				Y: bounds.Min.Y + missingSpace/2,
			},
			Max: image.Point{
				X: bounds.Max.X,
				Y: bounds.Min.Y + missingSpace/2 + width,
			},
		}
	}
}

func cleanTagNames(rawTagNames []string) []string {
	var trimmed []string
	for _, tagName := range rawTagNames {
		trimmed = append(trimmed, strings.TrimSpace(tagName))
	}

	var noInvalidRunes []string
	for _, tagName := range trimmed {
		var buf bytes.Buffer
		for _, runeValue := range tagName {
			if runeValue == unicode.ReplacementChar || !unicode.IsPrint(runeValue) {
				continue
			}
			buf.WriteRune(runeValue)
		}
		noInvalidRunes = append(noInvalidRunes, buf.String())
	}

	// We keep track of which are duplicates, but maintain order otherwise
	var seen = make(map[string]struct{}, len(noInvalidRunes))

	var uniqueNonEmptyTags []string
	for _, tagName := range noInvalidRunes {
		if len(tagName) == 0 {
			continue
		}
		if _, present := seen[tagName]; present {
			continue
		}
		seen[tagName] = struct{}{}
		uniqueNonEmptyTags = append(uniqueNonEmptyTags, tagName)
	}

	return uniqueNonEmptyTags
}

func fillTimestamps(p *Pic) {
	p.CreatedTime = getNowMillis()
	p.ModifiedTime = p.CreatedTime
}
<commit_msg>Try to sync temp files in upload.  Also handle http error codes<commit_after>package pixur

import (
	"bytes"
	"database/sql"
	"fmt"
	"image"
	"image/draw"
	"io"
	"io/ioutil"
	"log"
	"mime/multipart"
	"net/http"
	"os"
	"strings"
	"sync"
	"unicode"

	"github.com/nfnt/resize"

	_ "image/gif"
	"image/jpeg"
	_ "image/png"
)

const (
	thumbnailWidth  = 160
	thumbnailHeight = 160
)

var (
	errTagNotFound   = fmt.Errorf("Unable to find Tag")
	errDuplicateTags = fmt.Errorf("Data Corruption: Duplicate tags found")
)

type CreatePicTask struct {
	// Deps
	pixPath string
	db      *sql.DB

	// Inputs
	Filename string
	FileData multipart.File
	TagNames []string

	// Alternatively, a url can be uploaded
	FileURL string

	// State
	// The file that was created to hold the upload.
	tempFilename string
	tx           *sql.Tx

	// Results
	CreatedPic *Pic
}

func (t *CreatePicTask) Reset() {
	if t.tempFilename != "" {
		if err := os.Remove(t.tempFilename); err != nil {
			log.Println("ERROR Unable to remove image in CreatePicTask", t.tempFilename, err)
		}
	}
	if t.tx != nil {
		if err := t.tx.Rollback(); err != nil && err != sql.ErrTxDone {
			log.Println("ERROR Unable to rollback in CreatePicTask", err)
		}
	}
}

func (t *CreatePicTask) Run() error {
	wf, err := ioutil.TempFile(t.pixPath, "__")
	if err != nil {
		return err
	}
	defer wf.Close()
	t.tempFilename = wf.Name()

	var p = new(Pic)
	fillTimestamps(p)

	if t.FileData != nil {
		if err := t.moveUploadedFile(wf, p); err != nil {
			return err
		}
	} else if t.FileURL != "" {
		if err := t.downloadFile(wf, p); err != nil {
			return err
		}
	} else {
		return fmt.Errorf("No file uploaded")
	}

	img, err := t.fillImageConfig(wf, p)
	if err != nil {
		return err
	}
	thumbnail := makeThumbnail(img)
	if err := t.beginTransaction(); err != nil {
		return err
	}
	if err := t.insertPic(p); err != nil {
		return err
	}
	if err := t.renameTempFile(p); err != nil {
		return err
	}

	// If there is a problem creating the thumbnail, just continue on.
	if err := t.saveThumbnail(thumbnail, p); err != nil {
		log.Println("WARN Failed to create thumbnail", err)
	}

	tags, err := t.insertOrFindTags()
	if err != nil {
		return err
	}
	// must happen after pic is created, because it depends on pic id
	if err := t.addTagsForPic(p, tags); err != nil {
		return err
	}

	if err := t.tx.Commit(); err != nil {
		return err
	}

	// The upload succeeded
	t.tempFilename = ""
	t.CreatedPic = p
	return nil
}

// Moves the uploaded file and records the file size.  It might not be possible to just move the
// file in the event that the uploaded location is on a different partition than persistent dir.
func (t *CreatePicTask) moveUploadedFile(tempFile io.Writer, p *Pic) error {
	// TODO: check if the t.FileData is an os.File, and then try moving it.
	if bytesWritten, err := io.Copy(tempFile, t.FileData); err != nil {
		return err
	} else {
		p.FileSize = bytesWritten
	}
	// Attempt to flush the file incase an outside program needs to read from it.
	if f, ok := tempFile.(*os.File); ok {
		// If there was a failure, just give up.  The enclosing task will fail.
		if err := f.Sync(); err != nil {
			log.Println("Failed to sync file, continuing anwyays", err)
		}
	}
	return nil
}

func (t *CreatePicTask) downloadFile(tempFile io.Writer, p *Pic) error {
	resp, err := http.Get(t.FileURL)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("Failed to Download Pic %s [%d]", t.FileURL, resp.StatusCode)
	}

	if bytesWritten, err := io.Copy(tempFile, resp.Body); err != nil {
		return err
	} else {
		p.FileSize = bytesWritten
	}
	// Attempt to flush the file incase an outside program needs to read from it.
	if f, ok := tempFile.(*os.File); ok {
		// If there was a failure, just give up.  The enclosing task will fail.
		if err := f.Sync(); err != nil {
			log.Println("Failed to sync file, continuing anwyays", err)
		}
	}
	return nil
}

func (t *CreatePicTask) fillImageConfig(tempFile io.ReadSeeker, p *Pic) (image.Image, error) {
	if _, err := tempFile.Seek(0, os.SEEK_SET); err != nil {
		return nil, err
	}

	img, imgType, err := image.Decode(tempFile)

	if err != nil {
		return nil, err
	}

	// TODO: handle this error
	p.Mime, _ = FromImageFormat(imgType)
	p.Width = int64(img.Bounds().Dx())
	p.Height = int64(img.Bounds().Dy())
	return img, nil
}

func (t *CreatePicTask) beginTransaction() error {
	if tx, err := t.db.Begin(); err != nil {
		return err
	} else {
		t.tx = tx
	}
	return nil
}

func (t *CreatePicTask) insertPic(p *Pic) error {
	res, err := t.tx.Exec(p.BuildInsert(), p.ColumnPointers(p.GetColumnNames())...)
	if err != nil {
		return err
	}
	if insertId, err := res.LastInsertId(); err != nil {
		return err
	} else {
		p.Id = insertId
	}
	return nil
}

func (t *CreatePicTask) renameTempFile(p *Pic) error {
	if err := os.Rename(t.tempFilename, p.Path(t.pixPath)); err != nil {
		return err
	}
	// point this at the new file, incase the overall transaction fails
	t.tempFilename = p.Path(t.pixPath)
	return nil
}

func (t *CreatePicTask) saveThumbnail(img image.Image, p *Pic) error {
	f, err := os.Create(p.ThumbnailPath(t.pixPath))
	if err != nil {
		return err
	}
	defer f.Close()
	return jpeg.Encode(f, img, nil)
}

// This function is not really transactional, because it hits multiple entity roots.
// TODO: test this.
func (t *CreatePicTask) insertOrFindTags() ([]*Tag, error) {
	type findTagResult struct {
		tag *Tag
		err error
	}

	var cleanedTags = cleanTagNames(t.TagNames)

	var resultMap = make(map[string]*findTagResult, len(cleanedTags))
	var lock sync.Mutex

	now := getNowMillis()

	var wg sync.WaitGroup
	for _, tagName := range cleanedTags {
		wg.Add(1)
		go func(name string) {
			defer wg.Done()

			tx, err := t.db.Begin()
			if err != nil {
				lock.Lock()
				defer lock.Unlock()
				resultMap[name] = &findTagResult{
					tag: nil,
					err: err,
				}
				return
			}

			tag, err := findAndUpsertTag(name, now, tx)
			if err != nil {
				// TODO: maybe do something with this error?
				tx.Rollback()
			} else {
				err = tx.Commit()
			}

			lock.Lock()
			defer lock.Unlock()
			resultMap[name] = &findTagResult{
				tag: tag,
				err: err,
			}
		}(tagName)
	}
	wg.Wait()

	var allTags []*Tag
	for _, result := range resultMap {
		if result.err != nil {
			return nil, result.err
		}
		allTags = append(allTags, result.tag)
	}

	return allTags, nil
}

// findAndUpsertTag looks for an existing tag by name.  If it finds it, it updates the modified
// time and usage counter.  Otherwise, it creates a new tag with an initial count of 1.
func findAndUpsertTag(tagName string, now int64, tx *sql.Tx) (*Tag, error) {
	tag, err := findTagByName(tagName, tx)
	if err == errTagNotFound {
		tag, err = createTag(tagName, now, tx)
	} else if err != nil {
		return nil, err
	} else {
		tag.ModifiedTime = now
		tag.Count += 1
		err = tag.Update(tx)
	}

	if err != nil {
		return nil, err
	}

	return tag, nil
}

func createTag(tagName string, now int64, tx *sql.Tx) (*Tag, error) {
	tag := &Tag{
		Name:         tagName,
		Count:        1,
		CreatedTime:  now,
		ModifiedTime: now,
	}

	if err := tag.Insert(tx); err != nil {
		return nil, err
	}
	return tag, nil
}

func findTagByName(tagName string, tx *sql.Tx) (*Tag, error) {
	tags, err := findTags(tx, "SELECT * FROM tags WHERE name = ?;", tagName)
	if err != nil {
		return nil, err
	}
	switch len(tags) {
	case 0:
		return nil, errTagNotFound
	case 1:
		return tags[0], nil
	default:
		return nil, errDuplicateTags
	}
}

func findTags(tx *sql.Tx, query string, args ...interface{}) ([]*Tag, error) {
	rows, err := tx.Query(query, args...)
	if err != nil {
		return nil, err
	}

	defer rows.Close()
	columnNames, err := rows.Columns()
	if err != nil {
		return nil, err
	}

	var tags []*Tag
	for rows.Next() {
		t := new(Tag)
		if err := rows.Scan(t.ColumnPointers(columnNames)...); err != nil {
			return nil, err
		}
		tags = append(tags, t)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return tags, nil
}

func findPicTagsByPicId(picId int64, db *sql.DB) ([]*PicTag, error) {
	return findPicTags(db, "SELECT * FROM pictags WHERE pic_id = ?;", picId)
}

func findPicTags(db *sql.DB, query string, args ...interface{}) ([]*PicTag, error) {
	rows, err := db.Query(query, args...)
	if err != nil {
		return nil, err
	}

	defer rows.Close()
	columnNames, err := rows.Columns()
	if err != nil {
		return nil, err
	}

	var picTags []*PicTag
	for rows.Next() {
		pt := new(PicTag)
		if err := rows.Scan(pt.ColumnPointers(columnNames)...); err != nil {
			return nil, err
		}
		picTags = append(picTags, pt)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return picTags, nil
}

func (t *CreatePicTask) addTagsForPic(p *Pic, tags []*Tag) error {
	for _, tag := range tags {
		picTag := &PicTag{
			PicId:        p.Id,
			TagId:        tag.Id,
			Name:         tag.Name,
			CreatedTime:  p.CreatedTime,
			ModifiedTime: p.ModifiedTime,
		}
		_, err := t.db.Exec(picTag.BuildInsert(), picTag.ColumnPointers(picTag.GetColumnNames())...)
		if err != nil {
			return err
		}
	}
	return nil
}

// TODO: interpret image rotation metadata
func makeThumbnail(img image.Image) image.Image {
	bounds := findMaxSquare(img.Bounds())
	largeSquareImage := image.NewNRGBA(bounds)
	draw.Draw(largeSquareImage, bounds, img, bounds.Min, draw.Src)
	return resize.Resize(thumbnailWidth, thumbnailHeight, largeSquareImage, resize.NearestNeighbor)
}

func findMaxSquare(bounds image.Rectangle) image.Rectangle {
	width := bounds.Dx()
	height := bounds.Dy()
	if height < width {
		missingSpace := width - height
		return image.Rectangle{
			Min: image.Point{
				X: bounds.Min.X + missingSpace/2,
				Y: bounds.Min.Y,
			},
			Max: image.Point{
				X: bounds.Min.X + missingSpace/2 + height,
				Y: bounds.Max.Y,
			},
		}
	} else {
		missingSpace := height - width
		return image.Rectangle{
			Min: image.Point{
				X: bounds.Min.X,
				Y: bounds.Min.Y + missingSpace/2,
			},
			Max: image.Point{
				X: bounds.Max.X,
				Y: bounds.Min.Y + missingSpace/2 + width,
			},
		}
	}
}

func cleanTagNames(rawTagNames []string) []string {
	var trimmed []string
	for _, tagName := range rawTagNames {
		trimmed = append(trimmed, strings.TrimSpace(tagName))
	}

	var noInvalidRunes []string
	for _, tagName := range trimmed {
		var buf bytes.Buffer
		for _, runeValue := range tagName {
			if runeValue == unicode.ReplacementChar || !unicode.IsPrint(runeValue) {
				continue
			}
			buf.WriteRune(runeValue)
		}
		noInvalidRunes = append(noInvalidRunes, buf.String())
	}

	// We keep track of which are duplicates, but maintain order otherwise
	var seen = make(map[string]struct{}, len(noInvalidRunes))

	var uniqueNonEmptyTags []string
	for _, tagName := range noInvalidRunes {
		if len(tagName) == 0 {
			continue
		}
		if _, present := seen[tagName]; present {
			continue
		}
		seen[tagName] = struct{}{}
		uniqueNonEmptyTags = append(uniqueNonEmptyTags, tagName)
	}

	return uniqueNonEmptyTags
}

func fillTimestamps(p *Pic) {
	p.CreatedTime = getNowMillis()
	p.ModifiedTime = p.CreatedTime
}
<|endoftext|>


<commit_before>package critters

import (
	"fmt"
	"github.com/BenLubar/Rnoadm/world"
	"math/rand"
	"sync"
)

type Slime struct {
	world.CombatObject

	slimupation Slimupation
	gelTone     string

	facing         uint   // not saved
	animation      string // not saved
	animationTicks uint   // not saved

	mtx sync.Mutex
}

func init() {
	world.Register("hero", HeroLike((*Hero)(nil)))

	world.RegisterSpawnFunc(func(s string) world.Visible {
		for i := range raceInfo {
			r := Race(i)
			if r.Name() == s {
				return GenerateHeroRace(rand.New(rand.NewSource(rand.Int63())), r)
			}
		}
		return nil
	})
}

func (s *Slime) Save() (uint, interface{}, []world.ObjectLike) {
	s.mtx.Lock()
	defer s.mtx.Unlock()

	attached := []world.ObjectLike{&s.CombatObject}

	return 0, map[string]interface{}{
		"slimupation": uint64(s.slimupation),
		"tone":        s.gelTone,
	}, attached
}

func (s *Slime) Load(version uint, data interface{}, attached []world.ObjectLike) {
	s.mtx.Lock()
	defer s.mtx.Unlock()

	switch version {
	case 0:
		dataMap := data.(map[string]interface{})
		s.CombatObject = *attached[0].(*world.CombatObject)
		s.slimupation = Occupation(dataMap["slimupation"].(uint64))
		var ok bool
		s.gelTone, ok = dataMap["tone"].(string)
		if !ok {
			s.gelTone = "#0f0"
		}

	default:
		panic(fmt.Sprintf("version %d unknown", version))
	}

}

func (s *Slime) Name() string {
	s.mtx.Lock()
	defer s.mtx.Unlock()

	return "Slime " + s.slimupation.Name()
}

func (s *Slime) Examine() string {
	return "a slime " + s.slimupation.ExamineFlavor()
}

func (h *Hero) Slimupation() Slimupation {
	s.mtx.Lock()
	defer s.mtx.Unlock()

	return s.slimupation
}

func (s *Slime) Sprite() string {
	return "critter_slime"
}

func (h *Hero) Think() {
	s.CombatObject.Think()

	s.mtx.Lock()
	if s.animationTicks > 0 {
		s.animationTicks--
		if s.animationTicks == 0 {
			s.animation = ""
			if t := s.Position(); t != nil {
				s.mtx.Unlock()
				t.Zone().Update(t, s.Outer())
				return
			}
		}
	}
	s.mtx.Unlock()
}

func (s *Slime) AnimationType() string {
	s.mtx.Lock()
	defer s.mtx.Unlock()

	return s.animation
}

func (s *Slime) SpritePos() (uint, uint) {
	s.mtx.Lock()
	defer s.mtx.Unlock()

	return s.facing, 0
}

func (h *Hero) MaxHealth() uint64 {
	return 50
}

func (s *Slime) NotifyPosition(old, new *world.Tile) {
	if old == nil || new == nil {
		s.mtx.Lock()
		s.animationTicks = 0
		s.animation = ""
		s.facing = 0
		s.mtx.Unlock()
		return
	}
	ox, oy := old.Position()
	nx, ny := new.Position()

	s.mtx.Lock()
	switch {
	case ox-1 == nx && oy == ny:
		s.animationTicks = 3
		s.animation = "wa" // walk (alternating)
		s.facing = 6
	case ox+1 == nx && oy == ny:
		s.animationTicks = 3
		s.animation = "wa" // walk (alternating)
		s.facing = 9
	case ox == nx && oy-1 == ny:
		s.animationTicks = 3
		s.animation = "wa" // walk (alternating)
		s.facing = 3
	case ox == nx && oy+1 == ny:
		s.animationTicks = 3
		s.animation = "wa" // walk (alternating)
		s.facing = 0
	}
	s.mtx.Unlock()

	new.Zone().Update(new, s.Outer())
}
<commit_msg>whoops, critter isn't plural<commit_after>package critter

import (
	"fmt"
	"github.com/BenLubar/Rnoadm/world"
	"math/rand"
	"sync"
)

type Slime struct {
	world.CombatObject

	slimupation Slimupation
	gelTone     string

	facing         uint   // not saved
	animation      string // not saved
	animationTicks uint   // not saved

	mtx sync.Mutex
}

func init() {
	world.Register("hero", HeroLike((*Hero)(nil)))

	world.RegisterSpawnFunc(func(s string) world.Visible {
		for i := range raceInfo {
			r := Race(i)
			if r.Name() == s {
				return GenerateHeroRace(rand.New(rand.NewSource(rand.Int63())), r)
			}
		}
		return nil
	})
}

func (s *Slime) Save() (uint, interface{}, []world.ObjectLike) {
	s.mtx.Lock()
	defer s.mtx.Unlock()

	attached := []world.ObjectLike{&s.CombatObject}

	return 0, map[string]interface{}{
		"slimupation": uint64(s.slimupation),
		"tone":        s.gelTone,
	}, attached
}

func (s *Slime) Load(version uint, data interface{}, attached []world.ObjectLike) {
	s.mtx.Lock()
	defer s.mtx.Unlock()

	switch version {
	case 0:
		dataMap := data.(map[string]interface{})
		s.CombatObject = *attached[0].(*world.CombatObject)
		s.slimupation = Occupation(dataMap["slimupation"].(uint64))
		var ok bool
		s.gelTone, ok = dataMap["tone"].(string)
		if !ok {
			s.gelTone = "#0f0"
		}

	default:
		panic(fmt.Sprintf("version %d unknown", version))
	}

}

func (s *Slime) Name() string {
	s.mtx.Lock()
	defer s.mtx.Unlock()

	return "Slime " + s.slimupation.Name()
}

func (s *Slime) Examine() string {
	return "a slime " + s.slimupation.ExamineFlavor()
}

func (h *Hero) Slimupation() Slimupation {
	s.mtx.Lock()
	defer s.mtx.Unlock()

	return s.slimupation
}

func (s *Slime) Sprite() string {
	return "critter_slime"
}

func (h *Hero) Think() {
	s.CombatObject.Think()

	s.mtx.Lock()
	if s.animationTicks > 0 {
		s.animationTicks--
		if s.animationTicks == 0 {
			s.animation = ""
			if t := s.Position(); t != nil {
				s.mtx.Unlock()
				t.Zone().Update(t, s.Outer())
				return
			}
		}
	}
	s.mtx.Unlock()
}

func (s *Slime) AnimationType() string {
	s.mtx.Lock()
	defer s.mtx.Unlock()

	return s.animation
}

func (s *Slime) SpritePos() (uint, uint) {
	s.mtx.Lock()
	defer s.mtx.Unlock()

	return s.facing, 0
}

func (h *Hero) MaxHealth() uint64 {
	return 50
}

func (s *Slime) NotifyPosition(old, new *world.Tile) {
	if old == nil || new == nil {
		s.mtx.Lock()
		s.animationTicks = 0
		s.animation = ""
		s.facing = 0
		s.mtx.Unlock()
		return
	}
	ox, oy := old.Position()
	nx, ny := new.Position()

	s.mtx.Lock()
	switch {
	case ox-1 == nx && oy == ny:
		s.animationTicks = 3
		s.animation = "wa" // walk (alternating)
		s.facing = 6
	case ox+1 == nx && oy == ny:
		s.animationTicks = 3
		s.animation = "wa" // walk (alternating)
		s.facing = 9
	case ox == nx && oy-1 == ny:
		s.animationTicks = 3
		s.animation = "wa" // walk (alternating)
		s.facing = 3
	case ox == nx && oy+1 == ny:
		s.animationTicks = 3
		s.animation = "wa" // walk (alternating)
		s.facing = 0
	}
	s.mtx.Unlock()

	new.Zone().Update(new, s.Outer())
}
<|endoftext|>


<commit_before>package crypto

import (
	"crypto/md5"
	"crypto/sha1"
	"fmt"
	"strings"

	"github.com/go-chat-bot/bot"
)

const (
	invalidAmountOfParams = "Invalid amount of parameters"
	invalidParams         = "Invalid parameters"
)

func crypto(command *bot.Cmd) (string, error) {

	if len(command.Args) < 2 {
		return invalidAmountOfParams, nil
	}

	var hash string
	inputData := []byte(strings.Join(command.Args[1:], " "))
	switch strings.ToUpper(command.Args[0]) {
	case "MD5":
		hash = encryptMD5(inputData)
	case "SHA1", "SHA-1":
		hash = encryptSHA1(inputData)
	default:
		return invalidParams, nil
	}

	return hash, nil
}

func encryptMD5(data []byte) string {
	return fmt.Sprintf("%x", md5.Sum(data))
}

func encryptSHA1(data []byte) string {
	return fmt.Sprintf("%x", sha1.Sum(data))
}

func init() {
	bot.RegisterCommand(
		"crypto",
		"Encrypts the input data from its hash value",
		"md5|sha-1 enter here text to encrypt",
		crypto)
}
<commit_msg>Refactored returns<commit_after>package crypto

import (
	"crypto/md5"
	"crypto/sha1"
	"fmt"
	"strings"

	"github.com/go-chat-bot/bot"
)

const (
	invalidAmountOfParams = "Invalid amount of parameters"
	invalidParams         = "Invalid parameters"
)

func crypto(command *bot.Cmd) (string, error) {

	if len(command.Args) < 2 {
		return invalidAmountOfParams, nil
	}

	inputData := []byte(strings.Join(command.Args[1:], " "))
	switch strings.ToUpper(command.Args[0]) {
	case "MD5":
		return encryptMD5(inputData), nil
	case "SHA1", "SHA-1":
		return encryptSHA1(inputData), nil
	default:
		return invalidParams, nil
	}
}

func encryptMD5(data []byte) string {
	return fmt.Sprintf("%x", md5.Sum(data))
}

func encryptSHA1(data []byte) string {
	return fmt.Sprintf("%x", sha1.Sum(data))
}

func init() {
	bot.RegisterCommand(
		"crypto",
		"Encrypts the input data from its hash value",
		"md5|sha-1 enter here text to encrypt",
		crypto)
}
<|endoftext|>


<commit_before>package main

import "fmt"

func main() {
    fmt.Printf("hello, world\n")
}
<commit_msg>update go<commit_after>package main

import "fmt"

func main() {
    fmt.Printf("Hello, world!\n")
}
<|endoftext|>


<commit_before>package sisparse

import (
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"

	"github.com/yhat/scrape"
	"golang.org/x/net/html"
	"golang.org/x/net/html/atom"
)

const sisUrl = "https://is.cuni.cz/studium/predmety/index.php?do=predmet&kod=%s"

// Returns a two-dimensional array containing groups of events.
// Each group is a slice of events which must be enrolled together,
// the groups represent different times/teachers of the same course.
// Also, lectures and seminars/practicals are in separate groups.
func GetCourseEvents(courseCode string) ([][]Event, error) {
	resp, err := http.Get(fmt.Sprintf(sisUrl, courseCode))
	if err != nil {
		return nil, err
	}
	// It is difficult to directly convert an event code to a schedule link,
	// because SIS requires the faculty number. Therefore we first open the course
	// in the "Subjects" SIS module and then go to a link which takes
	// us to the schedule.
	relativeScheduleUrl, err := getRelativeScheduleUrl(resp.Body)
	if err != nil {
		return nil, err
	}
	scheduleUrl := getAbsoluteUrl(sisUrl, relativeScheduleUrl)

	resp, err = http.Get(scheduleUrl)
	if err != nil {
		return nil, err
	}
	return parseCourseEvents(resp.Body), nil
}

func getRelativeScheduleUrl(body io.ReadCloser) (string, error) {
	const scheduleLinkText = "Rozvrh"

	root, err := html.Parse(body)
	if err != nil {
		panic(err)
	}

	matcher := func(n *html.Node) bool {
		if n.DataAtom == atom.A {
			return scrape.Text(n) == scheduleLinkText
		}
		return false
	}

	scheduleLink, ok := scrape.Find(root, matcher)
	if !ok {
		return "", errors.New("Couldn't find schedule URL")
	}
	return scrape.Attr(scheduleLink, "href"), nil
}

func parseCourseEvents(body io.ReadCloser) [][]Event {
	root, err := html.Parse(body)
	if err != nil {
		panic(err)
	}

	matcher := func(n *html.Node) bool {
		if n.DataAtom == atom.Tr && n.Parent != nil && n.Parent.Parent != nil {
			return scrape.Attr(n.Parent.Parent, "id") == "table1" &&
				scrape.Attr(n, "class") != "head1" // ignore table header
		}
		return false
	}

	eventsTable := scrape.FindAll(root, matcher)
	if len(eventsTable) == 0 {
		// The event table is not present at all (possibly SIS returned an error message)
		return [][]Event{}
	}

	res := [][]Event{}
	group := []Event{}
	for _, row := range eventsTable {
		event := parseEvent(row)
		if (event == Event{}) {
			continue
		}
		// A non-empty name means the start of a new group;
		// names are omitted in all but the first event of a group.
		if event.Name != "" {
			if len(group) > 0 {
				res = append(res, group)
			}
			group = []Event{}
		} else {
			// Add the missing fields based on the group's first event
			event.Name = group[0].Name
			event.Teacher = group[0].Teacher
		}
		group = append(group, event)
	}
	if len(group) > 0 {
		res = append(res, group)
	}
	return res
}

func parseEvent(event *html.Node) Event {
	var cols []string
	for col := event.FirstChild; col != nil; col = col.NextSibling {
		// For some reason we also get siblings with no tag and no data?
		if len(strings.TrimSpace(col.Data)) > 0 {
			cols = append(cols, scrape.Text(col))
		}
	}

	e := Event{
		Type:    cols[1],
		Name:    cols[2],
		Teacher: cols[3],
	}

	if (e.Teacher == "") {
		return Event{}
	}

	addEventScheduling(&e, cols[4], cols[6])
	return e
}

func addEventScheduling(e *Event, daytime string, dur string) {
	// For strings such as "Út 12:20"
	daytimeRunes := []rune(daytime)
	e.Day = parseDay(string(daytimeRunes[:2]))

	timeFrom, err := time.Parse("15:04", string(daytimeRunes[3:]))
	if err != nil {
		panic(fmt.Sprintf("Unable to parse time: %s", string(daytimeRunes[3:])))
	}

	d, parity := parseDurationAndWeekParity(dur)

	e.TimeFrom = timeFrom
	e.TimeTo = timeFrom.Add(time.Minute * time.Duration(d))
	e.WeekParity = parity
}

func parseDurationAndWeekParity(dur string) (int, int) {
	// Strings like "90" or "240 Sudé týdny (liché kalendářní)"
	w := strings.Fields(dur)
	d, err := strconv.Atoi(w[0])
	if err != nil {
		panic(fmt.Sprintf("Unable to parse duration: %s", err))
	}
	parity := 0
	if len(w) > 1 {
		if w[1] == "Liché" {
			parity = 1
		} else {
			parity = 2
		}
	}
	return d, parity
}

func parseDay(day string) int {
	days := []string{"Po", "Út", "St", "Čt", "Pá"}
	for i, d := range days {
		if d == day {
			return i
		}
	}
	panic(fmt.Sprintf("Unknown day \"%s\"", day))
}

func getAbsoluteUrl(base, relative string) string {
	baseUrl, err := url.Parse(base)
	if err != nil {
		panic(err)
	}
	relativeUrl, err := url.Parse(relative)
	if err != nil {
		panic(err)
	}
	return baseUrl.ResolveReference(relativeUrl).String()
}
<commit_msg>sisparse: more robust handling of non-scheduled events<commit_after>package sisparse

import (
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"

	"github.com/yhat/scrape"
	"golang.org/x/net/html"
	"golang.org/x/net/html/atom"
)

const sisUrl = "https://is.cuni.cz/studium/predmety/index.php?do=predmet&kod=%s"

// Returns a two-dimensional array containing groups of events.
// Each group is a slice of events which must be enrolled together,
// the groups represent different times/teachers of the same course.
// Also, lectures and seminars/practicals are in separate groups.
func GetCourseEvents(courseCode string) ([][]Event, error) {
	resp, err := http.Get(fmt.Sprintf(sisUrl, courseCode))
	if err != nil {
		return nil, err
	}
	// It is difficult to directly convert an event code to a schedule link,
	// because SIS requires the faculty number. Therefore we first open the course
	// in the "Subjects" SIS module and then go to a link which takes
	// us to the schedule.
	relativeScheduleUrl, err := getRelativeScheduleUrl(resp.Body)
	if err != nil {
		return nil, err
	}
	scheduleUrl := getAbsoluteUrl(sisUrl, relativeScheduleUrl)

	resp, err = http.Get(scheduleUrl)
	if err != nil {
		return nil, err
	}
	return parseCourseEvents(resp.Body), nil
}

func getRelativeScheduleUrl(body io.ReadCloser) (string, error) {
	const scheduleLinkText = "Rozvrh"

	root, err := html.Parse(body)
	if err != nil {
		panic(err)
	}

	matcher := func(n *html.Node) bool {
		if n.DataAtom == atom.A {
			return scrape.Text(n) == scheduleLinkText
		}
		return false
	}

	scheduleLink, ok := scrape.Find(root, matcher)
	if !ok {
		return "", errors.New("Couldn't find schedule URL")
	}
	return scrape.Attr(scheduleLink, "href"), nil
}

func parseCourseEvents(body io.ReadCloser) [][]Event {
	root, err := html.Parse(body)
	if err != nil {
		panic(err)
	}

	matcher := func(n *html.Node) bool {
		if n.DataAtom == atom.Tr && n.Parent != nil && n.Parent.Parent != nil {
			return scrape.Attr(n.Parent.Parent, "id") == "table1" &&
				scrape.Attr(n, "class") != "head1" // ignore table header
		}
		return false
	}

	eventsTable := scrape.FindAll(root, matcher)
	if len(eventsTable) == 0 {
		// The event table is not present at all (possibly SIS returned an error message)
		return [][]Event{}
	}

	res := [][]Event{}
	group := []Event{}
	for _, row := range eventsTable {
		event, err := parseEvent(row)
		if (err != nil) {
			continue
		}
		// A non-empty name means the start of a new group;
		// names are omitted in all but the first event of a group.
		if event.Name != "" {
			if len(group) > 0 {
				res = append(res, group)
			}
			group = []Event{}
		} else {
			// Add the missing fields based on the group's first event
			event.Name = group[0].Name
			event.Teacher = group[0].Teacher
		}
		group = append(group, event)
	}
	if len(group) > 0 {
		res = append(res, group)
	}
	return res
}

func parseEvent(event *html.Node) (Event, error) {
	var cols []string
	for col := event.FirstChild; col != nil; col = col.NextSibling {
		// For some reason we also get siblings with no tag and no data?
		if len(strings.TrimSpace(col.Data)) > 0 {
			cols = append(cols, scrape.Text(col))
		}
	}

	e := Event{
		Type:    cols[1],
		Name:    cols[2],
		Teacher: cols[3],
	}

	err := addEventScheduling(&e, cols[4], cols[6])
	return e, err;
}

func addEventScheduling(e *Event, daytime string, dur string) error {
	// For strings such as "Út 12:20"
	if (len(daytime) == 0) {
		return errors.New("The daytime field is empty")
	}

	daytimeRunes := []rune(daytime)
	e.Day = parseDay(string(daytimeRunes[:2]))

	timeFrom, err := time.Parse("15:04", string(daytimeRunes[3:]))
	if err != nil {
		panic(fmt.Sprintf("Unable to parse time: %s", string(daytimeRunes[3:])))
	}

	d, parity := parseDurationAndWeekParity(dur)

	e.TimeFrom = timeFrom
	e.TimeTo = timeFrom.Add(time.Minute * time.Duration(d))
	e.WeekParity = parity
	return nil
}

func parseDurationAndWeekParity(dur string) (int, int) {
	// Strings like "90" or "240 Sudé týdny (liché kalendářní)"
	w := strings.Fields(dur)
	d, err := strconv.Atoi(w[0])
	if err != nil {
		panic(fmt.Sprintf("Unable to parse duration: %s", err))
	}
	parity := 0
	if len(w) > 1 {
		if w[1] == "Liché" {
			parity = 1
		} else {
			parity = 2
		}
	}
	return d, parity
}

func parseDay(day string) int {
	days := []string{"Po", "Út", "St", "Čt", "Pá"}
	for i, d := range days {
		if d == day {
			return i
		}
	}
	panic(fmt.Sprintf("Unknown day \"%s\"", day))
}

func getAbsoluteUrl(base, relative string) string {
	baseUrl, err := url.Parse(base)
	if err != nil {
		panic(err)
	}
	relativeUrl, err := url.Parse(relative)
	if err != nil {
		panic(err)
	}
	return baseUrl.ResolveReference(relativeUrl).String()
}
<|endoftext|>


<commit_before>package slb

import (
	"github.com/denverdino/aliyungo/common"
)

type VBackendServerType struct {
	ServerId    string
	Weight      int
	Port        int
	Type        string
	ServerIp    string
	Description string
}

type VServerGroup struct {
	RegionId         common.Region
	VServerGroupName string
	VServerGroupId   string
}

type VBackendServers struct {
	BackendServer []VBackendServerType
}

type CreateVServerGroupArgs struct {
	LoadBalancerId   string
	RegionId         common.Region
	VServerGroupName string
	VServerGroupId   string
	BackendServers   string
}

type SetVServerGroupAttributeArgs struct {
	LoadBalancerId   string
	RegionId         common.Region
	VServerGroupName string
	VServerGroupId   string
	BackendServers   string
}

type AddVServerGroupBackendServersArgs CreateVServerGroupArgs
type RemoveVServerGroupBackendServersArgs CreateVServerGroupArgs
type ModifyVServerGroupBackendServersArgs struct {
	VServerGroupId    string
	RegionId          common.Region
	OldBackendServers string
	NewBackendServers string
}

type DeleteVServerGroupArgs struct {
	VServerGroupId string
	RegionId       common.Region
}

type DescribeVServerGroupsArgs struct {
	LoadBalancerId  string
	RegionId        common.Region
	IncludeRule     bool
	IncludeListener bool
}

type DescribeVServerGroupAttributeArgs struct {
	VServerGroupId string
	RegionId       common.Region
}

type CreateVServerGroupResponse struct {
	common.Response
	VServerGroupId   string
	VServerGroupName string
	BackendServers   VBackendServers
}

type SetVServerGroupAttributeResponse struct {
	common.Response
	VServerGroupId   string
	VServerGroupName string
	BackendServers   VBackendServers
}

type AddVServerGroupBackendServersResponse CreateVServerGroupResponse
type RemoveVServerGroupBackendServersResponse CreateVServerGroupResponse
type ModifyVServerGroupBackendServersResponse CreateVServerGroupResponse
type DeleteVServerGroupResponse struct{ common.Response }
type DescribeVServerGroupsResponse struct {
	common.Response
	VServerGroups struct {
		VServerGroup []VServerGroup
	}
	AssociatedObjects struct {
		Listeners string
		Rules     string
	}
}
type DescribeVServerGroupAttributeResponse CreateVServerGroupResponse

func (client *Client) CreateVServerGroup(args *CreateVServerGroupArgs) (response *CreateVServerGroupResponse, err error) {
	response = &CreateVServerGroupResponse{}
	err = client.Invoke("CreateVServerGroup", args, response)
	if err != nil {
		return nil, err
	}
	return response, err
}

func (client *Client) SetVServerGroupAttribute(args *SetVServerGroupAttributeArgs) (response *SetVServerGroupAttributeResponse, err error) {
	response = &SetVServerGroupAttributeResponse{}
	err = client.Invoke("SetVServerGroupAttribute", args, response)
	if err != nil {
		return nil, err
	}
	return response, err
}

func (client *Client) AddVServerGroupBackendServers(args *AddVServerGroupBackendServersArgs) (response *AddVServerGroupBackendServersResponse, err error) {
	response = &AddVServerGroupBackendServersResponse{}
	err = client.Invoke("AddVServerGroupBackendServers", args, response)
	if err != nil {
		return nil, err
	}
	return response, err
}

func (client *Client) RemoveVServerGroupBackendServers(args *RemoveVServerGroupBackendServersArgs) (response *RemoveVServerGroupBackendServersResponse, err error) {
	response = &RemoveVServerGroupBackendServersResponse{}
	err = client.Invoke("RemoveVServerGroupBackendServers", args, response)
	if err != nil {
		return nil, err
	}
	return response, err
}

func (client *Client) ModifyVServerGroupBackendServers(args *ModifyVServerGroupBackendServersArgs) (response *ModifyVServerGroupBackendServersResponse, err error) {
	response = &ModifyVServerGroupBackendServersResponse{}
	err = client.Invoke("ModifyVServerGroupBackendServers", args, response)
	if err != nil {
		return nil, err
	}
	return response, err
}

func (client *Client) DeleteVServerGroup(args *DeleteVServerGroupArgs) (response *DeleteVServerGroupResponse, err error) {
	response = &DeleteVServerGroupResponse{}
	err = client.Invoke("DeleteVServerGroup", args, response)
	if err != nil {
		return nil, err
	}
	return response, err
}

func (client *Client) DescribeVServerGroups(args *DescribeVServerGroupsArgs) (response *DescribeVServerGroupsResponse, err error) {
	response = &DescribeVServerGroupsResponse{}
	err = client.Invoke("DescribeVServerGroups", args, response)
	if err != nil {
		return nil, err
	}
	return response, err
}

func (client *Client) DescribeVServerGroupAttribute(args *DescribeVServerGroupAttributeArgs) (response *DescribeVServerGroupAttributeResponse, err error) {
	response = &DescribeVServerGroupAttributeResponse{}
	err = client.Invoke("DescribeVServerGroupAttribute", args, response)
	if err != nil {
		return nil, err
	}
	return response, err
}
<commit_msg>add loadbalancer id in struct DescribeVServerGroupAttributeResponse<commit_after>package slb

import (
	"github.com/denverdino/aliyungo/common"
)

type VBackendServerType struct {
	ServerId    string
	Weight      int
	Port        int
	Type        string
	ServerIp    string
	Description string
}

type VServerGroup struct {
	RegionId         common.Region
	VServerGroupName string
	VServerGroupId   string
}

type VBackendServers struct {
	BackendServer []VBackendServerType
}

type CreateVServerGroupArgs struct {
	LoadBalancerId   string
	RegionId         common.Region
	VServerGroupName string
	VServerGroupId   string
	BackendServers   string
}

type SetVServerGroupAttributeArgs struct {
	LoadBalancerId   string
	RegionId         common.Region
	VServerGroupName string
	VServerGroupId   string
	BackendServers   string
}

type AddVServerGroupBackendServersArgs CreateVServerGroupArgs
type RemoveVServerGroupBackendServersArgs CreateVServerGroupArgs
type ModifyVServerGroupBackendServersArgs struct {
	VServerGroupId    string
	RegionId          common.Region
	OldBackendServers string
	NewBackendServers string
}

type DeleteVServerGroupArgs struct {
	VServerGroupId string
	RegionId       common.Region
}

type DescribeVServerGroupsArgs struct {
	LoadBalancerId  string
	RegionId        common.Region
	IncludeRule     bool
	IncludeListener bool
}

type DescribeVServerGroupAttributeArgs struct {
	VServerGroupId string
	RegionId       common.Region
}

type CreateVServerGroupResponse struct {
	common.Response
	VServerGroupId   string
	VServerGroupName string
	BackendServers   VBackendServers
}

type SetVServerGroupAttributeResponse struct {
	common.Response
	VServerGroupId   string
	VServerGroupName string
	BackendServers   VBackendServers
}

type AddVServerGroupBackendServersResponse CreateVServerGroupResponse
type RemoveVServerGroupBackendServersResponse CreateVServerGroupResponse
type ModifyVServerGroupBackendServersResponse CreateVServerGroupResponse
type DeleteVServerGroupResponse struct{ common.Response }
type DescribeVServerGroupsResponse struct {
	common.Response
	VServerGroups struct {
		VServerGroup []VServerGroup
	}
	AssociatedObjects struct {
		Listeners string
		Rules     string
	}
}
type DescribeVServerGroupAttributeResponse struct {
	common.Response
	VServerGroupId   string
	VServerGroupName string
	LoadBalancerId   string
	BackendServers   VBackendServers
}

func (client *Client) CreateVServerGroup(args *CreateVServerGroupArgs) (response *CreateVServerGroupResponse, err error) {
	response = &CreateVServerGroupResponse{}
	err = client.Invoke("CreateVServerGroup", args, response)
	if err != nil {
		return nil, err
	}
	return response, err
}

func (client *Client) SetVServerGroupAttribute(args *SetVServerGroupAttributeArgs) (response *SetVServerGroupAttributeResponse, err error) {
	response = &SetVServerGroupAttributeResponse{}
	err = client.Invoke("SetVServerGroupAttribute", args, response)
	if err != nil {
		return nil, err
	}
	return response, err
}

func (client *Client) AddVServerGroupBackendServers(args *AddVServerGroupBackendServersArgs) (response *AddVServerGroupBackendServersResponse, err error) {
	response = &AddVServerGroupBackendServersResponse{}
	err = client.Invoke("AddVServerGroupBackendServers", args, response)
	if err != nil {
		return nil, err
	}
	return response, err
}

func (client *Client) RemoveVServerGroupBackendServers(args *RemoveVServerGroupBackendServersArgs) (response *RemoveVServerGroupBackendServersResponse, err error) {
	response = &RemoveVServerGroupBackendServersResponse{}
	err = client.Invoke("RemoveVServerGroupBackendServers", args, response)
	if err != nil {
		return nil, err
	}
	return response, err
}

func (client *Client) ModifyVServerGroupBackendServers(args *ModifyVServerGroupBackendServersArgs) (response *ModifyVServerGroupBackendServersResponse, err error) {
	response = &ModifyVServerGroupBackendServersResponse{}
	err = client.Invoke("ModifyVServerGroupBackendServers", args, response)
	if err != nil {
		return nil, err
	}
	return response, err
}

func (client *Client) DeleteVServerGroup(args *DeleteVServerGroupArgs) (response *DeleteVServerGroupResponse, err error) {
	response = &DeleteVServerGroupResponse{}
	err = client.Invoke("DeleteVServerGroup", args, response)
	if err != nil {
		return nil, err
	}
	return response, err
}

func (client *Client) DescribeVServerGroups(args *DescribeVServerGroupsArgs) (response *DescribeVServerGroupsResponse, err error) {
	response = &DescribeVServerGroupsResponse{}
	err = client.Invoke("DescribeVServerGroups", args, response)
	if err != nil {
		return nil, err
	}
	return response, err
}

func (client *Client) DescribeVServerGroupAttribute(args *DescribeVServerGroupAttributeArgs) (response *DescribeVServerGroupAttributeResponse, err error) {
	response = &DescribeVServerGroupAttributeResponse{}
	err = client.Invoke("DescribeVServerGroupAttribute", args, response)
	if err != nil {
		return nil, err
	}
	return response, err
}
<|endoftext|>


<commit_before>package main

import (
	"collectd.org/api"
	"collectd.org/network"

	"flag"
	"fmt"
	"math/rand"
	"os"
	"strconv"
	"time"
)

var nMeasurments = flag.Int("m", 1, "Number of measurements")
var tagVariance = flag.Int("v", 1, "Number of values per tag. Client is fixed at one tag")
var rate = flag.Int("r", 1, "Number of points per second")
var total = flag.Int("t", 1, "Total number of points to send")
var host = flag.String("u", "127.0.0.1:25826", "Destination host in the form host:port")

func main() {
	flag.Parse()

	conn, err := network.Dial(*host, network.ClientOptions{})
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	defer conn.Close()

	rateLimiter := make(chan int, *rate)

	go func() {
		ticker := time.NewTicker(time.Second)
		for {
			select {
			case <-ticker.C:
				for i := 0; i < *rate; i++ {
					rateLimiter <- i
				}
			}
		}
	}()

	nSent := 0
	for nSent < *total {
		<-rateLimiter

		vl := api.ValueList{
			Identifier: api.Identifier{
				Host:   "tagvalue" + strconv.Itoa(int(rand.Int31n(int32(*tagVariance)))),
				Plugin: "golang" + strconv.Itoa(int(rand.Int31n(int32(*nMeasurments)))),
				Type:   "gauge",
			},
			Time:     time.Now(),
			Interval: 10 * time.Second,
			Values:   []api.Value{api.Gauge(42.0)},
		}
		if err := conn.Write(vl); err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		conn.Flush()
		nSent = nSent + 1
	}

	fmt.Println("Number of points sent:", nSent)
}
<commit_msg>collectd test client defaults to no limit points<commit_after>package main

import (
	"collectd.org/api"
	"collectd.org/network"

	"flag"
	"fmt"
	"math/rand"
	"os"
	"strconv"
	"time"
)

var nMeasurments = flag.Int("m", 1, "Number of measurements")
var tagVariance = flag.Int("v", 1, "Number of values per tag. Client is fixed at one tag")
var rate = flag.Int("r", 1, "Number of points per second")
var total = flag.Int("t", -1, "Total number of points to send (default is no limit)")
var host = flag.String("u", "127.0.0.1:25826", "Destination host in the form host:port")

func main() {
	flag.Parse()

	conn, err := network.Dial(*host, network.ClientOptions{})
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	defer conn.Close()

	rateLimiter := make(chan int, *rate)

	go func() {
		ticker := time.NewTicker(time.Second)
		for {
			select {
			case <-ticker.C:
				for i := 0; i < *rate; i++ {
					rateLimiter <- i
				}
			}
		}
	}()

	nSent := 0
	for {
		if nSent >= *total && *total > 0 {
			break
		}
		<-rateLimiter

		vl := api.ValueList{
			Identifier: api.Identifier{
				Host:   "tagvalue" + strconv.Itoa(int(rand.Int31n(int32(*tagVariance)))),
				Plugin: "golang" + strconv.Itoa(int(rand.Int31n(int32(*nMeasurments)))),
				Type:   "gauge",
			},
			Time:     time.Now(),
			Interval: 10 * time.Second,
			Values:   []api.Value{api.Gauge(42.0)},
		}
		if err := conn.Write(vl); err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		conn.Flush()
		nSent = nSent + 1
	}

	fmt.Println("Number of points sent:", nSent)
}
<|endoftext|>