<commit_before>package admin

import (
	"regexp"
	"strconv"

	"github.com/jinzhu/gorm"
	"github.com/qor/qor"
)

type scopeFunc func(db *gorm.DB, context *qor.Context) *gorm.DB

type Pagination struct {
	Total       int
	Pages       int
	CurrentPage int
	PrePage     int
}

type Searcher struct {
	*Context
	scopes         []*Scope
	filters        map[string]string
	withPagination bool
	Pagination     Pagination
}

func (s *Searcher) WithPagination() *Searcher {
	s.withPagination = true
	return s
}

func (s *Searcher) Page(num int) *Searcher {
	s.Pagination.CurrentPage = num
	return s
}

func (s *Searcher) PrePage(num int) *Searcher {
	s.Pagination.PrePage = num
	return s
}

func (s *Searcher) clone() *Searcher {
	return &Searcher{Context: s.Context, scopes: s.scopes, filters: s.filters}
}

func (s *Searcher) Scope(names ...string) *Searcher {
	newSearcher := s.clone()
	for _, name := range names {
		for _, scope := range s.Resource.scopes {
			if scope.Name == name && !scope.Default {
				newSearcher.scopes = append(newSearcher.scopes, scope)
				break
			}
		}
	}
	return newSearcher
}

func (s *Searcher) Filter(name, query string) *Searcher {
	newSearcher := s.clone()
	if newSearcher.filters == nil {
		newSearcher.filters = map[string]string{}
	}
	newSearcher.filters[name] = query
	return newSearcher
}

var filterRegexp = regexp.MustCompile(`^filters\[(.*?)\]$`)

func (s *Searcher) callScopes(context *qor.Context) *qor.Context {
	db := context.GetDB()

	// call default scopes
	for _, scope := range s.Resource.scopes {
		if scope.Default {
			db = scope.Handle(db, context)
		}
	}

	// call scopes
	for _, scope := range s.scopes {
		db = scope.Handle(db, context)
	}

	// call filters
	if s.filters != nil {
		for key, value := range s.filters {
			filter := s.Resource.filters[key]
			if filter != nil && filter.Handler != nil {
				db = filter.Handler(key, value, db, context)
			} else {
				db = DefaultHandler(key, value, db, context)
			}
		}
	}

	context.SetDB(db)

	// call search
	if keyword := context.Request.Form.Get("keyword"); keyword != "" {
		if s.Resource.SearchHandler != nil {
			context.SetDB(s.Resource.SearchHandler(keyword, context))
		}
	}
	return context
}

func (s *Searcher) cloneContext() *qor.Context {
	context := s.Context.Context
	return &qor.Context{
		Request:    context.Request,
		Writer:     context.Writer,
		ResourceID: context.ResourceID,
		Config:     context.Config,
		DB:         context.DB,
	}
}

func (s *Searcher) parseContext() *qor.Context {
	var context = s.cloneContext()
	var searcher = s.clone()

	if context != nil && context.Request != nil {
		// parse scopes
		scopes := context.Request.Form["scopes"]
		searcher = searcher.Scope(scopes...)

		// parse filters
		for key, value := range context.Request.Form {
			if matches := filterRegexp.FindStringSubmatch(key); len(matches) > 0 {
				searcher = searcher.Filter(matches[1], value[0])
			}
		}
	}

	searcher.callScopes(context)

	// pagination
	db := context.GetDB()
	paginationDB := db.Select("count(*) total").Model(s.Resource.Value).Set("gorm:query_destination", &s.Pagination)
	context.SetDB(paginationDB)
	s.Resource.CallFindMany(s.Resource.Value, context)

	if s.Pagination.CurrentPage == 0 {
		if s.Context.Request != nil {
			if page, err := strconv.Atoi(s.Context.Request.Form.Get("page")); err == nil {
				s.Pagination.CurrentPage = page
			}
		}

		if s.Pagination.CurrentPage == 0 {
			s.Pagination.CurrentPage = 1
		}
	}

	if s.Pagination.PrePage == 0 {
		s.Pagination.PrePage = s.Resource.Config.PageCount
	}

	s.Pagination.Pages = (s.Pagination.Total-1)/s.Pagination.PrePage + 1

	if s.Pagination.CurrentPage > 0 {
		db = db.Limit(s.Pagination.PrePage).Offset((s.Pagination.CurrentPage - 1) * s.Pagination.PrePage)
	}

	context.SetDB(db)

	return context
}

func (s *Searcher) FindMany() (interface{}, error) {
	context := s.parseContext()
	result := s.Resource.NewSlice()
	err := s.Resource.CallFindMany(result, context)
	return result, err
}

func (s *Searcher) FindOne() (interface{}, error) {
	context := s.parseContext()
	result := s.Resource.NewStruct()
	err := s.Resource.CallFindOne(result, nil, context)
	return result, err
}
<commit_msg>Fix pagination<commit_after>package admin

import (
	"regexp"
	"strconv"

	"github.com/jinzhu/gorm"
	"github.com/qor/qor"
)

type scopeFunc func(db *gorm.DB, context *qor.Context) *gorm.DB

type Pagination struct {
	Total       int
	Pages       int
	CurrentPage int
	PrePage     int
}

type Searcher struct {
	*Context
	scopes         []*Scope
	filters        map[string]string
	withPagination bool
	Pagination     Pagination
}

func (s *Searcher) WithPagination() *Searcher {
	s.withPagination = true
	return s
}

func (s *Searcher) Page(num int) *Searcher {
	s.Pagination.CurrentPage = num
	return s
}

func (s *Searcher) PrePage(num int) *Searcher {
	s.Pagination.PrePage = num
	return s
}

func (s *Searcher) clone() *Searcher {
	return &Searcher{Context: s.Context, scopes: s.scopes, filters: s.filters}
}

func (s *Searcher) Scope(names ...string) *Searcher {
	newSearcher := s.clone()
	for _, name := range names {
		for _, scope := range s.Resource.scopes {
			if scope.Name == name && !scope.Default {
				newSearcher.scopes = append(newSearcher.scopes, scope)
				break
			}
		}
	}
	return newSearcher
}

func (s *Searcher) Filter(name, query string) *Searcher {
	newSearcher := s.clone()
	if newSearcher.filters == nil {
		newSearcher.filters = map[string]string{}
	}
	newSearcher.filters[name] = query
	return newSearcher
}

var filterRegexp = regexp.MustCompile(`^filters\[(.*?)\]$`)

func (s *Searcher) callScopes(context *qor.Context) *qor.Context {
	db := context.GetDB()

	// call default scopes
	for _, scope := range s.Resource.scopes {
		if scope.Default {
			db = scope.Handle(db, context)
		}
	}

	// call scopes
	for _, scope := range s.scopes {
		db = scope.Handle(db, context)
	}

	// call filters
	if s.filters != nil {
		for key, value := range s.filters {
			filter := s.Resource.filters[key]
			if filter != nil && filter.Handler != nil {
				db = filter.Handler(key, value, db, context)
			} else {
				db = DefaultHandler(key, value, db, context)
			}
		}
	}

	context.SetDB(db)

	// call search
	if keyword := context.Request.Form.Get("keyword"); keyword != "" {
		if s.Resource.SearchHandler != nil {
			context.SetDB(s.Resource.SearchHandler(keyword, context))
		}
	}
	return context
}

func (s *Searcher) cloneContext() *qor.Context {
	context := s.Context.Context
	return &qor.Context{
		Request:    context.Request,
		Writer:     context.Writer,
		ResourceID: context.ResourceID,
		Config:     context.Config,
		DB:         context.DB,
	}
}

func (s *Searcher) parseContext() *qor.Context {
	var context = s.cloneContext()
	var searcher = s.clone()

	if context != nil && context.Request != nil {
		// parse scopes
		scopes := context.Request.Form["scopes"]
		searcher = searcher.Scope(scopes...)

		// parse filters
		for key, value := range context.Request.Form {
			if matches := filterRegexp.FindStringSubmatch(key); len(matches) > 0 {
				searcher = searcher.Filter(matches[1], value[0])
			}
		}
	}

	searcher.callScopes(context)

	// pagination
	db := context.GetDB()
	paginationDB := db.Select("count(*) total").Model(s.Resource.Value).Set("gorm:query_destination", &s.Pagination)
	context.SetDB(paginationDB)
	s.Resource.CallFindMany(s.Resource.Value, context)

	if s.Pagination.CurrentPage == 0 {
		if s.Context.Request != nil {
			if page, err := strconv.Atoi(s.Context.Request.Form.Get("page")); err == nil {
				s.Pagination.CurrentPage = page
			}
		}

		if s.Pagination.CurrentPage == 0 {
			s.Pagination.CurrentPage = 1
		}
	}

	if s.Pagination.PrePage == 0 {
		s.Pagination.PrePage = s.Resource.Config.PageCount
	}

	if s.Pagination.CurrentPage > 0 {
		s.Pagination.Pages = (s.Pagination.Total-1)/s.Pagination.PrePage + 1

		db = db.Limit(s.Pagination.PrePage).Offset((s.Pagination.CurrentPage - 1) * s.Pagination.PrePage)
	}

	context.SetDB(db)

	return context
}

func (s *Searcher) FindMany() (interface{}, error) {
	context := s.parseContext()
	result := s.Resource.NewSlice()
	err := s.Resource.CallFindMany(result, context)
	return result, err
}

func (s *Searcher) FindOne() (interface{}, error) {
	context := s.parseContext()
	result := s.Resource.NewStruct()
	err := s.Resource.CallFindOne(result, nil, context)
	return result, err
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/garyburd/redigo/redis"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
)

type ConfigStruct struct {
	RedisNetwork  string
	RedisAddress  string
	RedisQueueKey string
	Tasks         []TaskStruct
	ErrorCmd      string
}

type TaskStruct struct {
	Type    string
	Script  string
	Workers int
}

type QueueTaskStruct struct {
	Args []string
}

var verbose bool

func init() {
	flag.BoolVar(&verbose, "v", false, "enable verbose/debugging output")
	flag.Parse()
}

func main() {
	basepath := Basepath{}
	err := basepath.Update()
	if err != nil {
		log.Fatal("basepath.Update(): ", err)
	}

	config, err := getConfig(basepath.GetAbsWith("./goophry.config.json"))
	if err != nil {
		log.Fatal("getConfig(): ", err)
	}

	var wg sync.WaitGroup

	for _, task := range config.Tasks {
		debugOutput(fmt.Sprintf("Creating %d workers for type %s", task.Workers, task.Type))
		queue := make(chan QueueTaskStruct)

		task.Script = basepath.GetAbsWith(task.Script)

		for i := 0; i < task.Workers; i++ {
			wg.Add(1)
			go taskWorker(config, task, queue)
			debugOutput("Started worker for type " + task.Type)
		}

		go taskQueueWorker(config, task, queue)
		debugOutput("Started queue worker for type " + task.Type)
	}

	wg.Wait()
}

func debugOutput(msg string) {
	if verbose == true {
		log.Println(msg)
	}
}

func getBasePath() (path string, err error) {
	path, err = filepath.Abs(filepath.Dir(os.Args[0]))
	return
}

func getConfig(path string) (c ConfigStruct, err error) {
	file, err := os.Open(path)
	if err != nil {
		return
	}
	defer file.Close()

	parser := json.NewDecoder(file)
	err = parser.Decode(&c)
	return
}

func taskWorker(config ConfigStruct, task TaskStruct, queue chan QueueTaskStruct) {
	for t := range queue {
		debugOutput("Executing task for type " + task.Type)
		err := executeTask(task.Script, t.Args)
		if err != nil {
			errorCmdTask(config.ErrorCmd, task.Script, t.Args, err)
		}
	}
}

func taskQueueWorker(config ConfigStruct, task TaskStruct, queue chan QueueTaskStruct) {
	rc, err := redis.Dial(config.RedisNetwork, config.RedisAddress)
	if err != nil {
		log.Fatal("redis.Dial(): ", err)
	}
	defer rc.Close()

	queueKey := config.RedisQueueKey + ":" + task.Type

	for {
		values, err := redis.Strings(rc.Do("BLPOP", queueKey, 0))
		if err != nil {
			errorCmdRedis(config.ErrorCmd, err)
			continue
		}
		if len(values) == 0 {
			continue
		}

		for _, value := range values {
			if value == queueKey {
				continue
			}

			debugOutput("Task from redis: " + value)

			t, err := parseQueueTask(value)
			if err != nil {
				errorCmd(config.ErrorCmd, fmt.Sprintf("parseQueueTask(): ", err))
				continue
			}

			debugOutput("Sending task for type " + task.Type)
			queue <- t
		}
	}
}

func parseQueueTask(value string) (task QueueTaskStruct, err error) {
	reader := strings.NewReader(value)
	parser := json.NewDecoder(reader)
	err = parser.Decode(&task)
	return
}

func executeTask(script string, args []string) error {
	out, err := exec.Command(script, args...).Output()

	if len(out) != 0 && err == nil {
		err = fmt.Errorf("%s", out)
	}

	return err
}

func errorCmdTask(cmd string, script string, args []string, err error) {
	msg := fmt.Sprintf("%s %s\n\n%s", script, strings.Join(args, " "), err)
	errorCmd(cmd, msg)
}

func errorCmdRedis(cmd string, err error) {
	msg := fmt.Sprintf("Redis Error:\n%s", err)
	errorCmd(cmd, msg)
}

func errorCmd(cmd string, msg string) {
	debugOutput(fmt.Sprintf("Calling ErrorCmd with: %s", msg))

	cmdExec := fmt.Sprintf(cmd, strconv.Quote(msg))
	out, err := exec.Command("sh", "-c", cmdExec).Output()

	if len(out) != 0 && err == nil {
		log.Println(fmt.Sprintf("Error calling ErrorCmd:\n%s\n\nOutput:\n%s", cmdExec, out))
	}

	if err != nil {
		log.Println(fmt.Sprintf("Error calling ErrorCmd:\n%s", err))
	}
}

type Basepath struct {
	Path string
}

func (b *Basepath) Update() (err error) {
	b.Path, err = filepath.Abs(filepath.Dir(os.Args[0]))
	return
}

func (b Basepath) GetAbsWith(file string) (string) {
	if !filepath.IsAbs(file) {
		file = b.Path + "/" + file
	}
	return file
}
<commit_msg>small textual change for verbose output<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/garyburd/redigo/redis"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
)

type ConfigStruct struct {
	RedisNetwork  string
	RedisAddress  string
	RedisQueueKey string
	Tasks         []TaskStruct
	ErrorCmd      string
}

type TaskStruct struct {
	Type    string
	Script  string
	Workers int
}

type QueueTaskStruct struct {
	Args []string
}

var verbose bool

func init() {
	flag.BoolVar(&verbose, "v", false, "enable verbose/debugging output")
	flag.Parse()
}

func main() {
	basepath := Basepath{}
	err := basepath.Update()
	if err != nil {
		log.Fatal("basepath.Update(): ", err)
	}

	config, err := getConfig(basepath.GetAbsWith("./goophry.config.json"))
	if err != nil {
		log.Fatal("getConfig(): ", err)
	}

	var wg sync.WaitGroup

	for _, task := range config.Tasks {
		debugOutput(fmt.Sprintf("Creating %d workers for type %s", task.Workers, task.Type))
		queue := make(chan QueueTaskStruct)

		task.Script = basepath.GetAbsWith(task.Script)

		for i := 0; i < task.Workers; i++ {
			wg.Add(1)
			go taskWorker(config, task, queue)
			debugOutput("Created worker for type " + task.Type)
		}

		go taskQueueWorker(config, task, queue)
		debugOutput("Created queue worker for type " + task.Type)
	}

	wg.Wait()
}

func debugOutput(msg string) {
	if verbose == true {
		log.Println(msg)
	}
}

func getBasePath() (path string, err error) {
	path, err = filepath.Abs(filepath.Dir(os.Args[0]))
	return
}

func getConfig(path string) (c ConfigStruct, err error) {
	file, err := os.Open(path)
	if err != nil {
		return
	}
	defer file.Close()

	parser := json.NewDecoder(file)
	err = parser.Decode(&c)
	return
}

func taskWorker(config ConfigStruct, task TaskStruct, queue chan QueueTaskStruct) {
	for t := range queue {
		debugOutput("Executing task for type " + task.Type)
		err := executeTask(task.Script, t.Args)
		if err != nil {
			errorCmdTask(config.ErrorCmd, task.Script, t.Args, err)
		}
	}
}

func taskQueueWorker(config ConfigStruct, task TaskStruct, queue chan QueueTaskStruct) {
	rc, err := redis.Dial(config.RedisNetwork, config.RedisAddress)
	if err != nil {
		log.Fatal("redis.Dial(): ", err)
	}
	defer rc.Close()

	queueKey := config.RedisQueueKey + ":" + task.Type

	for {
		values, err := redis.Strings(rc.Do("BLPOP", queueKey, 0))
		if err != nil {
			errorCmdRedis(config.ErrorCmd, err)
			continue
		}
		if len(values) == 0 {
			continue
		}

		for _, value := range values {
			if value == queueKey {
				continue
			}

			debugOutput("Task from redis: " + value)

			t, err := parseQueueTask(value)
			if err != nil {
				errorCmd(config.ErrorCmd, fmt.Sprintf("parseQueueTask(): ", err))
				continue
			}

			debugOutput("Sending task for type " + task.Type)
			queue <- t
		}
	}
}

func parseQueueTask(value string) (task QueueTaskStruct, err error) {
	reader := strings.NewReader(value)
	parser := json.NewDecoder(reader)
	err = parser.Decode(&task)
	return
}

func executeTask(script string, args []string) error {
	out, err := exec.Command(script, args...).Output()

	if len(out) != 0 && err == nil {
		err = fmt.Errorf("%s", out)
	}

	return err
}

func errorCmdTask(cmd string, script string, args []string, err error) {
	msg := fmt.Sprintf("%s %s\n\n%s", script, strings.Join(args, " "), err)
	errorCmd(cmd, msg)
}

func errorCmdRedis(cmd string, err error) {
	msg := fmt.Sprintf("Redis Error:\n%s", err)
	errorCmd(cmd, msg)
}

func errorCmd(cmd string, msg string) {
	debugOutput(fmt.Sprintf("Calling ErrorCmd with: %s", msg))

	cmdExec := fmt.Sprintf(cmd, strconv.Quote(msg))
	out, err := exec.Command("sh", "-c", cmdExec).Output()

	if len(out) != 0 && err == nil {
		log.Println(fmt.Sprintf("Error calling ErrorCmd:\n%s\n\nOutput:\n%s", cmdExec, out))
	}

	if err != nil {
		log.Println(fmt.Sprintf("Error calling ErrorCmd:\n%s", err))
	}
}

type Basepath struct {
	Path string
}

func (b *Basepath) Update() (err error) {
	b.Path, err = filepath.Abs(filepath.Dir(os.Args[0]))
	return
}

func (b Basepath) GetAbsWith(file string) (string) {
	if !filepath.IsAbs(file) {
		file = b.Path + "/" + file
	}
	return file
}
<|endoftext|>


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

package main

import (
	"fmt"
	"github.com/nsf/termbox-go"
	"math/rand"
	"os"
	"time"
)

const (
	author       string        = "Fredy Wijaya"
	leftX        int           = 1
	leftY        int           = 1
	rightX       int           = 60
	rightY       int           = 20
	snakeX       int           = rightX / 2
	snakeY       int           = rightY / 2
	idle         int           = -1
	left         int           = 0
	right        int           = 1
	up           int           = 2
	down         int           = 3
	initialSpeed time.Duration = 250
	xStep        int           = 2
	yStep        int           = 1
	numFood      int           = 15
	scoreWeight  int           = 10
	maxLevel     int           = 10
)

func drawTopLine() {
	colorDefault := termbox.ColorDefault
	for i := leftX; i <= rightX; i++ {
		var c rune
		if i == leftX {
			c = '\u250c'
		} else if i == rightX {
			c = '\u2510'
		} else {
			c = '\u2500'
		}
		termbox.SetCell(i, leftY, c, colorDefault, colorDefault)
	}
}

func drawLeftLine() {
	colorDefault := termbox.ColorDefault
	for i := leftY + 1; i <= rightY; i++ {
		c := '\u2502'
		termbox.SetCell(leftX, i, c, colorDefault, colorDefault)
	}
}

func drawRightLine() {
	colorDefault := termbox.ColorDefault
	for i := leftX; i <= rightX; i++ {
		var c rune
		if i == leftX {
			c = '\u2514'
		} else if i == rightX {
			c = '\u2518'
		} else {
			c = '\u2500'
		}
		termbox.SetCell(i, rightY+1, c, colorDefault, colorDefault)
	}
}

func drawBottomLine() {
	colorDefault := termbox.ColorDefault
	for i := leftY + 1; i <= rightY; i++ {
		c := '\u2502'
		termbox.SetCell(rightX, i, c, colorDefault, colorDefault)
	}
}

func drawBox() {
	drawTopLine()
	drawLeftLine()
	drawRightLine()
	drawBottomLine()
}

func drawSnake(snake *snake) {
	colorDefault := termbox.ColorDefault
	for idx, coordinate := range snake.coordinates {
		var ch rune
		if idx == 0 {
			ch = '@'
		} else {
			ch = '*'
		}
		termbox.SetCell(coordinate.x, coordinate.y, ch, colorDefault, colorDefault)
	}
}

func drawLevel(level int) {
	x := leftX + 1
	y := leftY - 1
	text := fmt.Sprintf("Level: %d", level)
	drawText(x, y, text)
}

func drawScore(score int) {
	x := rightX - 11
	y := leftY - 1
	text := fmt.Sprintf("Score: %d", score)
	drawText(x, y, text)
}

func drawText(x, y int, text string) {
	colorDefault := termbox.ColorDefault
	for _, ch := range text {
		termbox.SetCell(x, y, ch, colorDefault, colorDefault)
		x++
	}
}

func drawFood(food *food) {
	colorDefault := termbox.ColorDefault
	for _, coordinate := range food.coordinates {
		termbox.SetCell(coordinate.x, coordinate.y, '\u2665', colorDefault, colorDefault)
	}
}

func drawAuthor() {
	x := leftX + 1
	y := rightY + 2
	text := fmt.Sprintf("Created By: %s", author)
	drawText(x, y, text)
}

func redrawAll(game *game) {
	colorDefault := termbox.ColorDefault
	termbox.Clear(colorDefault, colorDefault)

	drawLevel(game.level)
	drawScore(game.score)
	drawBox()
	drawSnake(&game.snake)
	drawFood(&game.food)
	drawAuthor()

	termbox.Flush()
}

type game struct {
	score int
	level int
	speed time.Duration
	snake snake
	food  food
}

type food struct {
	coordinates []coordinate
}

type coordinate struct {
	x int
	y int
}

type snake struct {
	coordinates []coordinate
	direction   int
}

func (s *snake) update(moveHead func(idx int)) {
	// move the head
	idx := 0
	prev := s.coordinates[idx]
	moveHead(idx)
	// update the tail
	for i := idx + 1; i < len(s.coordinates); i++ {
		tmp := s.coordinates[i]
		s.coordinates[i].x = prev.x
		s.coordinates[i].y = prev.y
		prev = tmp
	}
}

func (s *snake) moveUpIdx(idx int) {
	s.coordinates[idx].y -= yStep
	if s.coordinates[idx].y <= leftY {
		s.coordinates[idx].y = rightY
	}
	s.direction = up
}

func (s *snake) moveUp() {
	s.update(s.moveUpIdx)
}

func (s *snake) moveDownIdx(idx int) {
	s.coordinates[idx].y += yStep
	if s.coordinates[idx].y >= rightY {
		s.coordinates[idx].y = leftY + yStep
	}
	s.direction = down
}

func (s *snake) moveDown() {
	s.update(s.moveDownIdx)
}

func (s *snake) moveLeftIdx(idx int) {
	s.coordinates[idx].x -= xStep
	if s.coordinates[idx].x <= leftX+1 {
		s.coordinates[idx].x = rightX - xStep
	}
	s.direction = left
}

func (s *snake) moveLeft() {
	s.update(s.moveLeftIdx)
}

func (s *snake) moveRightIdx(idx int) {
	s.coordinates[idx].x += xStep
	if s.coordinates[idx].x >= rightX-1 {
		s.coordinates[idx].x = leftX + xStep
	}
	s.direction = right
}

func (s *snake) moveRight() {
	s.update(s.moveRightIdx)
}

func (s *snake) setDirection(direction int) {
	if s.direction == idle {
		if direction == left || direction == right || direction == up || direction == down {
			s.direction = direction
		}
	} else {
		// the snake can't go backward
		if direction == left && !(s.direction == left || s.direction == right) {
			s.direction = left
		} else if direction == right && !(s.direction == left || s.direction == right) {
			s.direction = right
		} else if direction == up && !(s.direction == up || s.direction == down) {
			s.direction = up
		} else if direction == down && !(s.direction == up || s.direction == down) {
			s.direction = down
		}
	}
}

func (s *snake) move() {
	if s.direction == left {
		s.moveLeft()
	} else if s.direction == right {
		s.moveRight()
	} else if s.direction == up {
		s.moveUp()
	} else if s.direction == down {
		s.moveDown()
	}
}

func (g *game) isFoodEaten(snake *snake, food *food) bool {
	head := snake.coordinates[0]
	var newFood []coordinate
	eaten := false
	for _, foodCoord := range food.coordinates {
		if head.x == foodCoord.x && head.y == foodCoord.y {
			snake.coordinates = append([]coordinate{{x: head.x, y: head.y}},
				snake.coordinates...)
			eaten = true
		} else {
			newFood = append(newFood, foodCoord)
		}
	}
	food.coordinates = newFood
	return eaten
}

func (g *game) run() bool {
	g.snake.move()
	if g.isFoodEaten(&g.snake, &g.food) {
		g.score += scoreWeight
	}
	if len(g.food.coordinates) == 0 {
		return true
	}
	// TODO: snake will die if it eats its own body
	return false
}

func initSnake() *snake {
	// TODO: fix the initial snake position
	snake := &snake{
		coordinates: []coordinate{
			coordinate{x: snakeX, y: snakeY},
			coordinate{x: snakeX - xStep, y: snakeY},
			coordinate{x: snakeX - (xStep * 2), y: snakeY},
		},
		direction: idle,
	}
	return snake
}

func initFood(snake *snake) *food {
	var foodCoordinates []coordinate
	rand.Seed(time.Now().UTC().UnixNano())
	nFood := 0
	for nFood < numFood {
		x := rand.Intn((rightX-leftX)+1) + leftX
		y := rand.Intn((rightY-leftY)+1) + leftY
		if x%2 != 0 || x <= leftX+1 || x >= rightX {
			continue
		}
		if y <= leftY || y >= rightY {
			continue
		}
		good := true
		for _, snakeCoordinate := range snake.coordinates {
			if snakeCoordinate.x == x && snakeCoordinate.y == y {
				good = false
				break
			}
		}
		if good {
			foodCoordinates = append(foodCoordinates,
				coordinate{x: x, y: y})
			nFood++
		}
	}
	food := &food{coordinates: foodCoordinates}
	return food
}

func runGame() {
	err := termbox.Init()
	if err != nil {
		errorAndExit(err)
	}
	defer termbox.Close()

	eventQueue := make(chan termbox.Event)
	go func() {
		for {
			eventQueue <- termbox.PollEvent()
		}
	}()

	game := &game{
		score: 0,
		level: 0,
		speed: initialSpeed,
	}
exitGame:
	for {
		snake := initSnake()
		food := initFood(snake)
		game.snake = *snake
		game.food = *food
		game.speed -= time.Duration(20)
		game.level++
		ticker := time.NewTicker(game.speed * time.Millisecond)
		redrawAll(game)
	nextLevel:
		for {
			select {
			case ev := <-eventQueue:
				switch ev.Key {
				case termbox.KeyEsc:
					break exitGame
				case termbox.KeyArrowUp:
					game.snake.setDirection(up)
				case termbox.KeyArrowDown:
					game.snake.setDirection(down)
				case termbox.KeyArrowLeft:
					game.snake.setDirection(left)
				case termbox.KeyArrowRight:
					game.snake.setDirection(right)
				}
			case <-ticker.C:
				if game.run() {
					break nextLevel
				}
			}
			redrawAll(game)
		}
	}
}

func errorAndExit(message interface{}) {
	fmt.Println(message)
	os.Exit(1)
}

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

package main

import (
	"fmt"
	"github.com/nsf/termbox-go"
	"math/rand"
	"os"
	"time"
)

const (
	author       string        = "Fredy Wijaya"
	leftX        int           = 1
	leftY        int           = 1
	rightX       int           = 60
	rightY       int           = 20
	snakeX       int           = rightX / 2
	snakeY       int           = rightY / 2
	idle         int           = -1
	left         int           = 0
	right        int           = 1
	up           int           = 2
	down         int           = 3
	initialSpeed time.Duration = 250
	speedStep    time.Duration = 20
	xStep        int           = 2
	yStep        int           = 1
	numFood      int           = 15
	scoreWeight  int           = 10
	maxLevel     int           = 10
)

func drawTopLine() {
	colorDefault := termbox.ColorDefault
	for i := leftX; i <= rightX; i++ {
		var c rune
		if i == leftX {
			c = '\u250c'
		} else if i == rightX {
			c = '\u2510'
		} else {
			c = '\u2500'
		}
		termbox.SetCell(i, leftY, c, colorDefault, colorDefault)
	}
}

func drawLeftLine() {
	colorDefault := termbox.ColorDefault
	for i := leftY + 1; i <= rightY; i++ {
		c := '\u2502'
		termbox.SetCell(leftX, i, c, colorDefault, colorDefault)
	}
}

func drawRightLine() {
	colorDefault := termbox.ColorDefault
	for i := leftX; i <= rightX; i++ {
		var c rune
		if i == leftX {
			c = '\u2514'
		} else if i == rightX {
			c = '\u2518'
		} else {
			c = '\u2500'
		}
		termbox.SetCell(i, rightY+1, c, colorDefault, colorDefault)
	}
}

func drawBottomLine() {
	colorDefault := termbox.ColorDefault
	for i := leftY + 1; i <= rightY; i++ {
		c := '\u2502'
		termbox.SetCell(rightX, i, c, colorDefault, colorDefault)
	}
}

func drawBox() {
	drawTopLine()
	drawLeftLine()
	drawRightLine()
	drawBottomLine()
}

func drawSnake(snake *snake) {
	colorDefault := termbox.ColorDefault
	for idx, coordinate := range snake.coordinates {
		var ch rune
		if idx == 0 {
			ch = '@'
		} else {
			ch = '*'
		}
		termbox.SetCell(coordinate.x, coordinate.y, ch, colorDefault, colorDefault)
	}
}

func drawLevel(level int) {
	x := leftX + 1
	y := leftY - 1
	text := fmt.Sprintf("Level: %d", level)
	drawText(x, y, text)
}

func drawScore(score int) {
	x := rightX - 11
	y := leftY - 1
	text := fmt.Sprintf("Score: %d", score)
	drawText(x, y, text)
}

func drawText(x, y int, text string) {
	colorDefault := termbox.ColorDefault
	for _, ch := range text {
		termbox.SetCell(x, y, ch, colorDefault, colorDefault)
		x++
	}
}

func drawFood(food *food) {
	colorDefault := termbox.ColorDefault
	for _, coordinate := range food.coordinates {
		termbox.SetCell(coordinate.x, coordinate.y, '\u2665', colorDefault, colorDefault)
	}
}

func drawAuthor() {
	x := leftX + 1
	y := rightY + 2
	text := fmt.Sprintf("Created By: %s", author)
	drawText(x, y, text)
}

func redrawAll(game *game) {
	colorDefault := termbox.ColorDefault
	termbox.Clear(colorDefault, colorDefault)

	drawLevel(game.level)
	drawScore(game.score)
	drawBox()
	drawSnake(&game.snake)
	drawFood(&game.food)
	drawAuthor()

	termbox.Flush()
}

type game struct {
	score int
	level int
	speed time.Duration
	snake snake
	food  food
}

type food struct {
	coordinates []coordinate
}

type coordinate struct {
	x int
	y int
}

type snake struct {
	coordinates []coordinate
	direction   int
}

func (s *snake) update(moveHead func(idx int)) {
	// move the head
	idx := 0
	prev := s.coordinates[idx]
	moveHead(idx)
	// update the tail
	for i := idx + 1; i < len(s.coordinates); i++ {
		tmp := s.coordinates[i]
		s.coordinates[i].x = prev.x
		s.coordinates[i].y = prev.y
		prev = tmp
	}
}

func (s *snake) moveUpIdx(idx int) {
	s.coordinates[idx].y -= yStep
	if s.coordinates[idx].y <= leftY {
		s.coordinates[idx].y = rightY
	}
	s.direction = up
}

func (s *snake) moveUp() {
	s.update(s.moveUpIdx)
}

func (s *snake) moveDownIdx(idx int) {
	s.coordinates[idx].y += yStep
	if s.coordinates[idx].y >= rightY {
		s.coordinates[idx].y = leftY + yStep
	}
	s.direction = down
}

func (s *snake) moveDown() {
	s.update(s.moveDownIdx)
}

func (s *snake) moveLeftIdx(idx int) {
	s.coordinates[idx].x -= xStep
	if s.coordinates[idx].x <= leftX+1 {
		s.coordinates[idx].x = rightX - xStep
	}
	s.direction = left
}

func (s *snake) moveLeft() {
	s.update(s.moveLeftIdx)
}

func (s *snake) moveRightIdx(idx int) {
	s.coordinates[idx].x += xStep
	if s.coordinates[idx].x >= rightX-1 {
		s.coordinates[idx].x = leftX + xStep
	}
	s.direction = right
}

func (s *snake) moveRight() {
	s.update(s.moveRightIdx)
}

func (s *snake) setDirection(direction int) {
	if s.direction == idle {
		if direction == left || direction == right || direction == up || direction == down {
			s.direction = direction
		}
	} else {
		// the snake can't go backward
		if direction == left && !(s.direction == left || s.direction == right) {
			s.direction = left
		} else if direction == right && !(s.direction == left || s.direction == right) {
			s.direction = right
		} else if direction == up && !(s.direction == up || s.direction == down) {
			s.direction = up
		} else if direction == down && !(s.direction == up || s.direction == down) {
			s.direction = down
		}
	}
}

func (s *snake) move() {
	if s.direction == left {
		s.moveLeft()
	} else if s.direction == right {
		s.moveRight()
	} else if s.direction == up {
		s.moveUp()
	} else if s.direction == down {
		s.moveDown()
	}
}

func (g *game) isFoodEaten(snake *snake, food *food) bool {
	head := snake.coordinates[0]
	var newFood []coordinate
	eaten := false
	for _, foodCoord := range food.coordinates {
		if head.x == foodCoord.x && head.y == foodCoord.y {
			snake.coordinates = append([]coordinate{{x: head.x, y: head.y}},
				snake.coordinates...)
			eaten = true
		} else {
			newFood = append(newFood, foodCoord)
		}
	}
	food.coordinates = newFood
	return eaten
}

func (g *game) run() bool {
	g.snake.move()
	if g.isFoodEaten(&g.snake, &g.food) {
		g.score += scoreWeight
	}
	if len(g.food.coordinates) == 0 {
		return true
	}
	// TODO: snake will die if it eats its own body
	return false
}

func initSnake() *snake {
	// TODO: fix the initial snake position
	snake := &snake{
		coordinates: []coordinate{
			coordinate{x: snakeX, y: snakeY},
			coordinate{x: snakeX - xStep, y: snakeY},
			coordinate{x: snakeX - (xStep * 2), y: snakeY},
		},
		direction: idle,
	}
	return snake
}

func initFood(snake *snake) *food {
	var foodCoordinates []coordinate
	rand.Seed(time.Now().UTC().UnixNano())
	nFood := 0
	for nFood < numFood {
		x := rand.Intn((rightX-leftX)+1) + leftX
		y := rand.Intn((rightY-leftY)+1) + leftY
		if x%2 != 0 || x <= leftX+1 || x >= rightX {
			continue
		}
		if y <= leftY || y >= rightY {
			continue
		}
		good := true
		for _, snakeCoordinate := range snake.coordinates {
			if snakeCoordinate.x == x && snakeCoordinate.y == y {
				good = false
				break
			}
		}
		if good {
			foodCoordinates = append(foodCoordinates,
				coordinate{x: x, y: y})
			nFood++
		}
	}
	food := &food{coordinates: foodCoordinates}
	return food
}

func runGame() {
	err := termbox.Init()
	if err != nil {
		errorAndExit(err)
	}
	defer termbox.Close()

	eventQueue := make(chan termbox.Event)
	go func() {
		for {
			eventQueue <- termbox.PollEvent()
		}
	}()

	game := &game{
		score: 0,
		level: 0,
		speed: initialSpeed,
	}
exitGame:
	for {
		snake := initSnake()
		food := initFood(snake)
		game.snake = *snake
		game.food = *food
		game.speed -= speedStep
		game.level++
		ticker := time.NewTicker(game.speed * time.Millisecond)
		redrawAll(game)
	nextLevel:
		for {
			select {
			case ev := <-eventQueue:
				switch ev.Key {
				case termbox.KeyEsc:
					break exitGame
				case termbox.KeyArrowUp:
					game.snake.setDirection(up)
				case termbox.KeyArrowDown:
					game.snake.setDirection(down)
				case termbox.KeyArrowLeft:
					game.snake.setDirection(left)
				case termbox.KeyArrowRight:
					game.snake.setDirection(right)
				}
			case <-ticker.C:
				if game.run() {
					break nextLevel
				}
			}
			redrawAll(game)
		}
	}
}

func errorAndExit(message interface{}) {
	fmt.Println(message)
	os.Exit(1)
}

func main() {
	runGame()
}
<|endoftext|>


<commit_before>package fonts

type Font8x8 struct {
	Height int
	Width  int
	Bitmap [][]byte
}

func (f *Font8x8) Load() {
	f.Height = 8
	f.Width = 8
	f.Bitmap = [][]byte{
		// A
		{
			0x7E, // 01111110
			0x42, // 01000010
			0x42, // 01000010
			0x7E, // 01111110
			0x42, // 01000010
			0x42, // 01000010
			0x42, // 01000010
			0x00, // 00000000
		},
		// B
		{
			0x7C, // 01111100
			0x42, // 01000010
			0x42, // 01000010
			0x7C, // 01111100
			0x42, // 01000010
			0x42, // 01000010
			0x7C, // 01111100
			0x00, // 00000000
		},
		// C
		{
			0x7E, // 01111110
			0x40, // 01000000
			0x40, // 01000000
			0x40, // 01000000
			0x40, // 01000000
			0x40, // 01000000
			0x7E, // 01111110
			0x00, // 00000000
		},
	}
}
<commit_msg>update font<commit_after>/* Automatically generated, do not change manually. */

/*
Bitmap font 8x8 METAL BASIC 0.01
*/
package fonts

type Font8x8 struct {
	Height int
	Width  int
	Bitmap [][]byte
}

func (f *Font8x8) Load() {
	f.Height = 8
	f.Width = 8
	f.Bitmap = [][]byte{
		// blank or null
		{
			0x00, // 00000000
			0x00, // 00000000
			0x00, // 00000000
			0x00, // 00000000
			0x00, // 00000000
			0x00, // 00000000
			0x00, // 00000000
			0x00, // 00000000
		},
		// A
		{
			0x7E, // 01111110
			0x42, // 01000010
			0x42, // 01000010
			0x7E, // 01111110
			0x42, // 01000010
			0x42, // 01000010
			0x42, // 01000010
			0x00, // 00000000
		},
		// B
		{
			0x7C, // 01111100
			0x42, // 01000010
			0x42, // 01000010
			0x7C, // 01111100
			0x42, // 01000010
			0x42, // 01000010
			0x7C, // 01111100
			0x00, // 00000000
		},
		// C
		{
			0x7E, // 01111110
			0x40, // 01000000
			0x40, // 01000000
			0x40, // 01000000
			0x40, // 01000000
			0x40, // 01000000
			0x7E, // 01111110
			0x00, // 00000000
		},
	}
}

<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"

	"github.com/qiangxue/fasthttp-routing"
	"github.com/valyala/fasthttp"
)

type Server struct {
	requestHandler func(ctx *fasthttp.RequestCtx)
	conf           *Conf
	router         *routing.Router
	backend        IBackend
}

// Init
func (s *Server) init() {
	// Backend
	s.backend = newBackend(s.conf)

	// Router
	s.router = routing.New()

	// Upsert operation that writes data
	s.router.Put("/bloomfilter/<key>", func(c *routing.Context) error {
		// Params
		key := c.Param("key")
		body := c.PostBody()

		// Put
		res, resErr := s.backend.Put([]byte(key), []byte(body))

		// Log
		log.Printf("PUT %v %v %v %v", key, body, res, resErr)
		return nil
	})

	// Get
	s.router.Get("/bloomfilter/<key>", func(c *routing.Context) error {
		// Params
		key := c.Param("key")

		// Get
		res, resErr := s.backend.Get([]byte(key))

		// Log
		log.Printf("GET %v %v %v", key, res, resErr)

		// Output
		fmt.Fprintf(c, "%s", res)
		return nil
	})
}

// Start
func (s *Server) Start() {
	listenStr := fmt.Sprintf("%s:%d", s.conf.ListenHost, s.conf.ListenPort)
	log.Printf("Starting server at %s", listenStr)
	panic(fasthttp.ListenAndServe(listenStr, s.router.HandleRequest))
}

// Constructor
func newServer(conf *Conf) *Server {
	s := &Server{
		conf: conf,
	}
	s.init()
	return s
}
<commit_msg>Gzip compression in persistence server<commit_after>package main

import (
	"bytes"
	"compress/gzip"
	"fmt"
	"log"

	"github.com/qiangxue/fasthttp-routing"
	"github.com/valyala/fasthttp"
)

type Server struct {
	requestHandler func(ctx *fasthttp.RequestCtx)
	conf           *Conf
	router         *routing.Router
	backend        IBackend
}

// Init
func (s *Server) init() {
	// Backend
	s.backend = newBackend(s.conf)

	// Router
	s.router = routing.New()

	// Upsert operation that writes data
	s.router.Put("/bloomfilter/<key>", func(c *routing.Context) error {
		// Params
		key := c.Param("key")
		body := c.PostBody()

		// Compress with gzip in body
		var compressedBody bytes.Buffer
		w := gzip.NewWriter(&compressedBody)
		w.Write(body)
		w.Close()

		// Put
		res, resErr := s.backend.Put([]byte(key), compressedBody.Bytes())

		// Log
		log.Printf("PUT %v %d %v %v", key, len(body), res, resErr)
		return nil
	})

	// Get
	s.router.Get("/bloomfilter/<key>", func(c *routing.Context) error {
		// Params
		key := c.Param("key")

		// Get
		res, resErr := s.backend.Get([]byte(key))

		// Headers, because we compressed it during the acceptance
		c.Request.Header.Add("Content-Encoding", "gzip")

		// Output
		fmt.Fprintf(c, "%s", res)

		// Log
		log.Printf("GET %v %d %v", key, len(res), resErr)
		return nil
	})
}

// Start
func (s *Server) Start() {
	listenStr := fmt.Sprintf("%s:%d", s.conf.ListenHost, s.conf.ListenPort)
	log.Printf("Starting server at %s", listenStr)
	panic(fasthttp.ListenAndServe(listenStr, s.router.HandleRequest))
}

// Constructor
func newServer(conf *Conf) *Server {
	s := &Server{
		conf: conf,
	}
	s.init()
	return s
}
<|endoftext|>


<commit_before>// khan
// https://github.com/topfreegames/khan
//
// Licensed under the MIT license:
// http://www.opensource.org/licenses/mit-license
// Copyright © 2016 Top Free Games <backend@tfgco.com>

package util

// VERSION identifies Khan's current version
var VERSION = "2.1.1"
<commit_msg>Release v2.2.0<commit_after>// khan
// https://github.com/topfreegames/khan
//
// Licensed under the MIT license:
// http://www.opensource.org/licenses/mit-license
// Copyright © 2016 Top Free Games <backend@tfgco.com>

package util

// VERSION identifies Khan's current version
var VERSION = "2.2.0"
<|endoftext|>


<commit_before>//  Copyright 2016 The goscope Authors
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.

package main

import (
	"errors"
	"flag"
	"fmt"
	"image"
	"image/color"
	"image/png"
	"log"
	"os"
	"sort"
	"strconv"
	"strings"

	"github.com/zagrodzki/goscope/dummy"
	"github.com/zagrodzki/goscope/scope"
)

type aggrPoint struct {
	sumY  int
	sizeY int
}

func (p aggrPoint) add(y int) aggrPoint {
	p.sumY += y
	p.sizeY++
	return p
}

func (p aggrPoint) toPoint(x int) image.Point {
	return image.Point{x, p.sumY / p.sizeY}
}

// ChannelYRange represents a y-range of samples to be plotted
type ChannelYRange struct {
	Min float64
	Max float64
}

// Width returns the width of the range.
func (r ChannelYRange) Width() float64 {
	return r.Max - r.Min
}

func samplesToPoints(samples []scope.Sample, sampleRangeY ChannelYRange, start, end image.Point) []image.Point {
	if len(samples) == 0 {
		return nil
	}

	sampleWidthX := float64(len(samples) - 1)
	sampleWidthY := sampleRangeY.Width()

	pixelStartX := float64(start.X)
	pixelEndY := float64(end.Y)
	pixelWidthX := float64(end.X - start.X)
	pixelWidthY := float64(end.Y - start.Y)

	aggrPoints := make(map[int]aggrPoint)
	for i, y := range samples {
		mapX := int(pixelStartX + float64(i)/sampleWidthX*pixelWidthX)
		mapY := int(pixelEndY - float64(y-scope.Sample(sampleRangeY.Min))/sampleWidthY*pixelWidthY)
		aggrPoints[mapX] = aggrPoints[mapX].add(mapY)
	}
	var points []image.Point
	for x, p := range aggrPoints {
		points = append(points, p.toPoint(x))
	}

	return points
}

// Plot represents the entire plotting area.
type Plot struct {
	*image.RGBA
}

// Fill fills the plot with a color.
func (plot Plot) Fill(col color.RGBA) {
	bounds := plot.Bounds()
	for i := bounds.Min.X; i < bounds.Max.X; i++ {
		for j := bounds.Min.Y; j < bounds.Max.Y; j++ {
			plot.Set(i, j, col)
		}
	}
}

func isInside(x, y int, start, end image.Point) bool {
	return x >= start.X && x <= end.X && y >= start.Y && y <= end.Y
}

// DrawLine draws a straight line from pixel p1 to p2.
// Only the line fragment inside the image rectangle defined by
// starting (upper left) and ending (lower right) pixel is drawn.
func (plot Plot) DrawLine(p1, p2 image.Point, start, end image.Point, col color.RGBA) {
	if p1.X == p2.X { // vertical line
		for i := min(p1.Y, p2.Y); i <= max(p1.Y, p2.Y); i++ {
			plot.Set(p1.X, i, col)
		}
		return
	}

	// Calculating the parameters of the equation
	// of the straight line (in the form y=a*x+b)
	// passing through p1 and p2.

	// slope of the line
	a := float64(p1.Y-p2.Y) / float64(p1.X-p2.X)
	// intercept of the line
	b := float64(p1.Y) - float64(p1.X)*a

	// To avoid visual "gaps" between the pixels we switch on,
	// we draw the line in one of two ways.
	if abs(p1.X-p2.X) >= abs(p1.Y-p2.Y) {
		// If the line is more horizontal than vertical,
		// for every pixel column between p1 and p2
		// we find and switch on the pixel closest to y=a*x+b
		for i := min(p1.X, p2.X); i <= max(p1.X, p2.X); i++ {
			y := int(a*float64(i) + b)
			if isInside(i, y, start, end) {
				plot.Set(i, y, col)
			}
		}
	} else {
		// If the line is more vertical than horizontal,
		// for every pixel row between p1 and p2
		// we find and switch on the pixel closest to y=a*x+b
		for i := min(p1.Y, p2.Y); i <= max(p1.Y, p2.Y); i++ {
			x := int((float64(i) - b) / a)
			if isInside(x, i, start, end) {
				plot.Set(x, i, col)
			}
		}
	}
}

// DrawSamples draws samples in the image rectangle defined by
// starting (upper left) and ending (lower right) pixel.
func (plot Plot) DrawSamples(samples []scope.Sample, sampleRangeY ChannelYRange, start, end image.Point, col color.RGBA) {
	points := samplesToPoints(samples, sampleRangeY, start, end)
	sort.Sort(pointsByX(points))
	for i := 1; i < len(points); i++ {
		plot.DrawLine(points[i-1], points[i], start, end, col)
	}
}

// DrawAll draws samples from all the channels into one image.
func (plot Plot) DrawAll(samples map[scope.ChanID][]scope.Sample, ranges map[scope.ChanID]ChannelYRange, cols map[scope.ChanID]color.RGBA) {
	b := plot.Bounds()
	x1 := b.Min.X + 10
	x2 := b.Max.X - 10
	y1 := b.Min.Y + 10
	y2 := b.Min.Y + 10 + int((b.Max.Y-b.Min.Y-10*(len(samples)+1))/len(samples))
	step := y2 - b.Min.Y
	for id, v := range samples {
		plot.DrawSamples(v, ranges[id], image.Point{x1, y1}, image.Point{x2, y2}, cols[id])
		y1 = y1 + step
		y2 = y2 + step
	}
}

// CreatePlot plots samples from the device.
func CreatePlot(dev scope.Device, ranges map[scope.ChanID]ChannelYRange) (Plot, error) {
	plot := Plot{image.NewRGBA(image.Rect(0, 0, 800, 600))}

	data, stop, err := dev.StartSampling()
	defer stop()
	if err != nil {
		return plot, err
	}
	samples := (<-data).Samples

	colWhite := color.RGBA{255, 255, 255, 255}
	colRed := color.RGBA{255, 0, 0, 255}
	colGreen := color.RGBA{0, 255, 0, 255}
	colBlue := color.RGBA{0, 0, 255, 255}
	colBlack := color.RGBA{0, 0, 0, 255}
	chanCols := [4]color.RGBA{colRed, colGreen, colBlue, colBlack}

	plot.Fill(colWhite)

	cols := make(map[scope.ChanID]color.RGBA)
	next := 0
	for _, id := range dev.Channels() {
		if _, exists := ranges[id]; !exists {
			ranges[id] = ChannelYRange{-1, 1}
		}
		cols[id] = chanCols[next]
		next = (next + 1) % 4
	}
	plot.DrawAll(samples, ranges, cols)
	return plot, nil
}

// PlotToPng creates a plot of the samples from the device
// and saves it as PNG.
func PlotToPng(dev scope.Device, ranges map[scope.ChanID]ChannelYRange, outputFile string) error {
	plot, err := CreatePlot(dev, ranges)
	if err != nil {
		return err
	}

	f, err := os.Create(outputFile)
	if err != nil {
		return err
	}
	defer f.Close()
	png.Encode(f, plot)
	return nil
}

type pointsByX []image.Point

func (a pointsByX) Len() int {
	return len(a)
}

func (a pointsByX) Swap(i, j int) {
	a[i], a[j] = a[j], a[i]
}

func (a pointsByX) Less(i, j int) bool {
	return a[i].X < a[j].X
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func abs(a int) int {
	if a < 0 {
		return -a
	}
	return a
}

type channelYRanges map[scope.ChanID]ChannelYRange

func (i *channelYRanges) String() string {
	return fmt.Sprintf("%v", *i)
}

func (i *channelYRanges) Set(value string) error {
	parts := strings.Split(value, ":")
	if len(parts) != 2 {
		return errors.New("use format: \"chanID:lowerY,upperY\"")
	}
	numbers := strings.Split(parts[1], ",")
	if len(numbers) != 2 {
		return errors.New("use format: \"chanID:lowerY,upperY\"")
	}
	min, err := strconv.ParseFloat(numbers[0], 64)
	if err != nil {
		return err
	}
	max, err := strconv.ParseFloat(numbers[1], 64)
	if err != nil {
		return err
	}
	(*i)[scope.ChanID(parts[0])] = ChannelYRange{min, max}
	return nil
}

func main() {
	dev, err := dummy.Open("")
	if err != nil {
		log.Fatalf("Cannot open the device: %v", err)
	}

	fileName := flag.String("file", "draw.png", "output file name")
	ranges := channelYRanges{}
	flag.Var(&ranges, "range", "channel Y range, format: \"chanID:lowerY,upperY\"")
	flag.Parse()

	if err := PlotToPng(dev, ranges, *fileName); err != nil {
		log.Fatalf("Cannot plot samples: %v", err)
	}
}
<commit_msg>gui package introduced<commit_after>//  Copyright 2016 The goscope Authors
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.

package gui

import (
	"image"
	"image/color"
	"image/png"
	"os"
	"sort"

	"github.com/zagrodzki/goscope/scope"
)

type aggrPoint struct {
	sumY  int
	sizeY int
}

func (p aggrPoint) add(y int) aggrPoint {
	p.sumY += y
	p.sizeY++
	return p
}

func (p aggrPoint) toPoint(x int) image.Point {
	return image.Point{x, p.sumY / p.sizeY}
}

// ChannelYRange represents a y-range of samples to be plotted
type ChannelYRange struct {
	Min float64
	Max float64
}

// Width returns the width of the range.
func (r ChannelYRange) Width() float64 {
	return r.Max - r.Min
}

func samplesToPoints(samples []scope.Sample, sampleRangeY ChannelYRange, start, end image.Point) []image.Point {
	if len(samples) == 0 {
		return nil
	}

	sampleWidthX := float64(len(samples) - 1)
	sampleWidthY := sampleRangeY.Width()

	pixelStartX := float64(start.X)
	pixelEndY := float64(end.Y)
	pixelWidthX := float64(end.X - start.X)
	pixelWidthY := float64(end.Y - start.Y)

	aggrPoints := make(map[int]aggrPoint)
	for i, y := range samples {
		mapX := int(pixelStartX + float64(i)/sampleWidthX*pixelWidthX)
		mapY := int(pixelEndY - float64(y-scope.Sample(sampleRangeY.Min))/sampleWidthY*pixelWidthY)
		aggrPoints[mapX] = aggrPoints[mapX].add(mapY)
	}
	var points []image.Point
	for x, p := range aggrPoints {
		points = append(points, p.toPoint(x))
	}

	return points
}

// Plot represents the entire plotting area.
type Plot struct {
	*image.RGBA
}

// Fill fills the plot with a color.
func (plot Plot) Fill(col color.RGBA) {
	bounds := plot.Bounds()
	for i := bounds.Min.X; i < bounds.Max.X; i++ {
		for j := bounds.Min.Y; j < bounds.Max.Y; j++ {
			plot.Set(i, j, col)
		}
	}
}

func isInside(x, y int, start, end image.Point) bool {
	return x >= start.X && x <= end.X && y >= start.Y && y <= end.Y
}

// DrawLine draws a straight line from pixel p1 to p2.
// Only the line fragment inside the image rectangle defined by
// starting (upper left) and ending (lower right) pixel is drawn.
func (plot Plot) DrawLine(p1, p2 image.Point, start, end image.Point, col color.RGBA) {
	if p1.X == p2.X { // vertical line
		for i := min(p1.Y, p2.Y); i <= max(p1.Y, p2.Y); i++ {
			plot.Set(p1.X, i, col)
		}
		return
	}

	// Calculating the parameters of the equation
	// of the straight line (in the form y=a*x+b)
	// passing through p1 and p2.

	// slope of the line
	a := float64(p1.Y-p2.Y) / float64(p1.X-p2.X)
	// intercept of the line
	b := float64(p1.Y) - float64(p1.X)*a

	// To avoid visual "gaps" between the pixels we switch on,
	// we draw the line in one of two ways.
	if abs(p1.X-p2.X) >= abs(p1.Y-p2.Y) {
		// If the line is more horizontal than vertical,
		// for every pixel column between p1 and p2
		// we find and switch on the pixel closest to y=a*x+b
		for i := min(p1.X, p2.X); i <= max(p1.X, p2.X); i++ {
			y := int(a*float64(i) + b)
			if isInside(i, y, start, end) {
				plot.Set(i, y, col)
			}
		}
	} else {
		// If the line is more vertical than horizontal,
		// for every pixel row between p1 and p2
		// we find and switch on the pixel closest to y=a*x+b
		for i := min(p1.Y, p2.Y); i <= max(p1.Y, p2.Y); i++ {
			x := int((float64(i) - b) / a)
			if isInside(x, i, start, end) {
				plot.Set(x, i, col)
			}
		}
	}
}

// DrawSamples draws samples in the image rectangle defined by
// starting (upper left) and ending (lower right) pixel.
func (plot Plot) DrawSamples(samples []scope.Sample, sampleRangeY ChannelYRange, start, end image.Point, col color.RGBA) {
	points := samplesToPoints(samples, sampleRangeY, start, end)
	sort.Sort(pointsByX(points))
	for i := 1; i < len(points); i++ {
		plot.DrawLine(points[i-1], points[i], start, end, col)
	}
}

// DrawAll draws samples from all the channels into one image.
func (plot Plot) DrawAll(samples map[scope.ChanID][]scope.Sample, ranges map[scope.ChanID]ChannelYRange, cols map[scope.ChanID]color.RGBA) {
	b := plot.Bounds()
	x1 := b.Min.X + 10
	x2 := b.Max.X - 10
	y1 := b.Min.Y + 10
	y2 := b.Min.Y + 10 + int((b.Max.Y-b.Min.Y-10*(len(samples)+1))/len(samples))
	step := y2 - b.Min.Y
	for id, v := range samples {
		plot.DrawSamples(v, ranges[id], image.Point{x1, y1}, image.Point{x2, y2}, cols[id])
		y1 = y1 + step
		y2 = y2 + step
	}
}

// CreatePlot plots samples from the device.
func CreatePlot(dev scope.Device, ranges map[scope.ChanID]ChannelYRange) (Plot, error) {
	plot := Plot{image.NewRGBA(image.Rect(0, 0, 800, 600))}

	data, stop, err := dev.StartSampling()
	defer stop()
	if err != nil {
		return plot, err
	}
	samples := (<-data).Samples

	colWhite := color.RGBA{255, 255, 255, 255}
	colRed := color.RGBA{255, 0, 0, 255}
	colGreen := color.RGBA{0, 255, 0, 255}
	colBlue := color.RGBA{0, 0, 255, 255}
	colBlack := color.RGBA{0, 0, 0, 255}
	chanCols := [4]color.RGBA{colRed, colGreen, colBlue, colBlack}

	plot.Fill(colWhite)

	cols := make(map[scope.ChanID]color.RGBA)
	next := 0
	for _, id := range dev.Channels() {
		if _, exists := ranges[id]; !exists {
			ranges[id] = ChannelYRange{-1, 1}
		}
		cols[id] = chanCols[next]
		next = (next + 1) % 4
	}
	plot.DrawAll(samples, ranges, cols)
	return plot, nil
}

// PlotToPng creates a plot of the samples from the device
// and saves it as PNG.
func PlotToPng(dev scope.Device, ranges map[scope.ChanID]ChannelYRange, outputFile string) error {
	plot, err := CreatePlot(dev, ranges)
	if err != nil {
		return err
	}

	f, err := os.Create(outputFile)
	if err != nil {
		return err
	}
	defer f.Close()
	png.Encode(f, plot)
	return nil
}

type pointsByX []image.Point

func (a pointsByX) Len() int {
	return len(a)
}

func (a pointsByX) Swap(i, j int) {
	a[i], a[j] = a[j], a[i]
}

func (a pointsByX) Less(i, j int) bool {
	return a[i].X < a[j].X
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func abs(a int) int {
	if a < 0 {
		return -a
	}
	return a
}
<|endoftext|>


<commit_before>package pwshandler

import (
	"net/http"

	"github.com/gorilla/websocket"
	"golang.org/x/net/context"
)

// ConnPool is common interface for a structureы which merge websocket
// connections in a pools with access to common environment data such
// as context for starting other goroutines and something else
type ConnPool interface {
	// AddConn creates connection to pool and returns environment data
	// such as context and common data for selected connection pool
	AddConn(*websocket.Conn) (context.Context, interface{}, error)
	// DelConn removes passed connection from pool if exists
	DelConn(*websocket.Conn)
}

// RequestVerifier verifies request
type RequestVerifier interface {
	Verify(*http.Request) error
}

// ConnManager contains method for processing websocket connections
// with passed context and common data
type ConnManager interface {
	// Handle handles connection using passed environment data
	Handle(context.Context, *websocket.Conn, interface{}) error
	// HandleError processes an errors
	HandleError(http.ResponseWriter, error)
}

// PoolHandler is handler which receives websocket requests and joins
// connections in a pools with common data in order with passed
// pool manager encapsulated common data and context
type PoolHandler struct {
	verifier RequestVerifier
	manager  ConnManager
	pool     ConnPool
	upgrader *websocket.Upgrader
}

// NewPoolHandler creates new pool handler with passed connection
// manager and connection pool for storage and merging connections
func NewPoolHandler(manager ConnManager, pool ConnPool,
	upgrader *websocket.Upgrader) *PoolHandler {
	return &PoolHandler{nil, manager, pool, upgrader}
}

// SetupVerifier adds request verifier
func (ph *PoolHandler) SetupVerifier(verifier RequestVerifier) {
	if verifier != nil {
		ph.verifier = verifier
	}
}

// Implementing Handler interface
func (ph *PoolHandler) ServeHTTP(w http.ResponseWriter,
	r *http.Request) {

	var err error

	// Verify request
	if ph.verifier != nil {
		if err = ph.verifier.Verify(r); err != nil {
			ph.manager.HandleError(w, err)
			return
		}
	}

	// Upgrade connection to websocket
	var conn *websocket.Conn
	if conn, err = ph.upgrader.Upgrade(w, r, nil); err != nil {
		ph.manager.HandleError(w, err)
		return
	}

	// Create connection to pool and get envitonment data
	var (
		cxt  context.Context
		data interface{}
	)
	if cxt, data, err = ph.pool.AddConn(conn); err != nil {
		ph.manager.HandleError(w, err)
		return
	}

	// Handle connection
	if err = ph.manager.Handle(cxt, conn, data); err != nil {
		ph.manager.HandleError(w, err)
	}

	// Delete connection
	ph.pool.DelConn(conn)
}
<commit_msg>merging context and common data field<commit_after>package pwshandler

import (
	"net/http"

	"github.com/gorilla/websocket"
)

// ConnPool is common interface for a structures which merge websocket
// connections in a pools with access to common environment data such
// as context for starting other goroutines or something else
type ConnPool interface {
	// AddConn creates connection to pool and returns environment data
	AddConn(*websocket.Conn) (interface{}, error)
	// DelConn removes passed connection from pool if exists
	DelConn(*websocket.Conn)
}

// RequestVerifier verifies request
type RequestVerifier interface {
	Verify(*http.Request) error
}

// ConnManager contains methods for processing websocket connections
// with passed environment data
type ConnManager interface {
	// Handle handles connection using passed environment data
	Handle(*websocket.Conn, interface{}) error
	// HandleError processes an errors
	HandleError(http.ResponseWriter, error)
}

// PoolHandler is handler which receives websocket requests and joins
// connections in a pools with common data in order with passed pool
// manager
type PoolHandler struct {
	verifier RequestVerifier
	manager  ConnManager
	pool     ConnPool
	upgrader *websocket.Upgrader
}

// NewPoolHandler creates new pool handler with passed connection
// manager and connection pool for storage and merging connections
func NewPoolHandler(manager ConnManager, pool ConnPool,
	upgrader *websocket.Upgrader) *PoolHandler {
	return &PoolHandler{nil, manager, pool, upgrader}
}

// SetupVerifier adds request verifier
func (ph *PoolHandler) SetupVerifier(verifier RequestVerifier) {
	if verifier != nil {
		ph.verifier = verifier
	}
}

// Implementing http.Handler interface
func (ph *PoolHandler) ServeHTTP(w http.ResponseWriter,
	r *http.Request) {

	var err error
	// Verify request
	if ph.verifier != nil {
		if err = ph.verifier.Verify(r); err != nil {
			ph.manager.HandleError(w, err)
			return
		}
	}

	// Upgrade connection to websocket
	var conn *websocket.Conn
	if conn, err = ph.upgrader.Upgrade(w, r, nil); err != nil {
		ph.manager.HandleError(w, err)
		return
	}

	// Create connection to pool and get envitonment data
	var env interface{}
	if env, err = ph.pool.AddConn(conn); err != nil {
		ph.manager.HandleError(w, err)
		return
	}

	// Handle connection
	if err = ph.manager.Handle(conn, env); err != nil {
		ph.manager.HandleError(w, err)
	}

	// Delete connection from pool
	ph.pool.DelConn(conn)
}
<|endoftext|>


<commit_before>package main

import (
	"html/template"
	"io"
	"log"
	"net/http"
	"os"
	"path"
	"strings"

	"github.com/ajg/form"
	"github.com/blevesearch/bleve"
)

type fieldListHandler struct {
	config ServerSection
	index  *Index
}

func (h *fieldListHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fields := strings.SplitN(r.URL.Path, "/", 2)

	if fields[0] == "" {
		// to do if a field was not given
		response, err := h.index.ListField(h.config.Default)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		err = allTemplates.ExecuteTemplate(w, h.config.Template,
			struct{ AllFields []string }{AllFields: response})
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	} else {
		// to be done if a field was given
		response, err := h.index.ListFieldValues(h.config.Default, fields[0], 100, 1)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		modifiedSearchResponse := struct {
			SearchResponse
			AllFields []string
		}{
			SearchResponse: response,
			AllFields:      []string{},
		}

		err = allTemplates.ExecuteTemplate(w, h.config.Template, modifiedSearchResponse)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
	}
}

type fuzzySearchHandler struct {
	config ServerSection
	index  *Index
}

func (h *fuzzySearchHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	values := struct {
		s        string   `form:"s"`
		topics   []string `form:"topic"`
		authors  []string `form:"author"`
		page     int      `form:"page"`
		pageSize int      `form:"pageSize"`
	}{}

	err := form.Decode(&values, request.URL.Values)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	query := bleve.NewQueryStringQuery(values.s)
	searchRequest := bleve.NewSearchRequest(query)
	searchRequest.Fields = []string{"path", "title", "topic", "author", "modified"}
	searchRequest.Size = values.pageSize
	searchRequest.From = values.pageSize + values.page

	results, err := h.index.Query(searchRequest)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	err = allTemplates.ExecuteTemplate(w, h.config.Template, results)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

type querySearchHandler struct {
	config ServerSection
	index  *Index
}

func (h *querySearchHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	values := struct {
		s        string `form:"s"`
		page     int    `form:"page"`
		pageSize int    `form:"pageSize"`
	}{}

	err := form.Decode(&values, request.URL.Values)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	query := bleve.NewQueryStringQuery(values.s)
	searchRequest := bleve.NewSearchRequest(query)
	searchRequest.Fields = []string{"path", "title", "topic", "author", "modified"}
	searchRequest.Size = values.pageSize
	searchRequest.From = values.pageSize + values.page

	results, err := h.index.Query(searchRequest)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	err = allTemplates.ExecuteTemplate(w, h.config.Template, results)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

type parsedHandler struct {
	config ServerSection
}

func (h *parsedHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// If the request is empty, set it to the default.
	if requestPath == "/" {
		requestPath = path.Clean(h.serverConfig.Default)
	}

	// If the request doesn't end in .md, add that
	if path.Ext(requestPath) != "md" {
		requestPath = requestPath + ".md"
	}

	pdata := new(PageMetadata)
	err := pdata.LoadPage(serverConfig.Path + requestPath)
	if err != nil {
		log.Printf("request [ %s ] points to an bad file target [ %s ] sent to server %s",
			request.URL.Path, requestPath, serverConfig.Prefix)
		http.Error(responsePipe, "Page not Found", http.StatusNotFound)
		return
	}

	if pdata.MatchedTopic(serverConfig.Restricted) {
		log.Printf("request [ %s ] was against a page [ %s ] with a restricted tag",
			request.URL.Path, requestPath)
		http.Error(responsePipe, "Restricted Page", http.StatusNotFound)
		//http.Error(responsePipe, err.Error(), http.StatusForbidden)
		return
	}

	// parse any markdown in the input
	body := template.HTML(bodyParseMarkdown(pdata.Page))
	toc := template.HTML(tocParseMarkdown(pdata.Page))
	topics, keywords, authors := pdata.ListMeta()

	// ##TODO## put this template right in the function call
	// Then remove the Page Struct above
	response := Page{
		Title:    pdata.Title,
		ToC:      toc,
		Body:     body,
		Keywords: keywords,
		Topics:   topics,
		Authors:  authors,
	}
	err = allTemplates.ExecuteTemplate(responsePipe, serverConfig.Template, response)
	if err != nil {
		http.Error(responsePipe, err.Error(), 500)
	}
}

type rawHandler struct {
	config ServerSection
}

func (h *parsedHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// If the request is empty, set it to the default.
	if requestPath == "/" {
		requestPath = path.Clean(h.serverConfig.Default)
	}

	for _, restricted := range h.config.Restricted {
		if path.Ext(requestPath) == restricted {
			log.Printf("request %s was improperly routed to the file handler with an disallowed extension %s", request.URL.Path, restricted)
			http.Error(responsePipe, "Request not allowed", 403)
			return
		}
	}

	f, err := os.Open(filePath.Join(h.config.Path, requestPath))
	if err != nil {
		http.Error(w, err.Error, http.StatusForbidden)
		log.Print(err)
		return
	}

	_, err = io.Copy(w, f)
	if err != nil {
		http.Error(w, err.Error, http.StatusInternalServerError)
		log.Print(err)
	}
}
<commit_msg>moved the last of the stuff out of handler.go<commit_after>package main

import (
	"html/template"
	"io"
	"log"
	"net/http"
	"os"
	"path"
	"strings"

	"github.com/ajg/form"
	"github.com/blevesearch/bleve"
)

type fieldListHandler struct {
	config ServerSection
	index  *Index
}

func (h *fieldListHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fields := strings.SplitN(r.URL.Path, "/", 2)

	if fields[0] == "" {
		// to do if a field was not given
		response, err := h.index.ListField(h.config.Default)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		err = allTemplates.ExecuteTemplate(w, h.config.Template,
			struct{ AllFields []string }{AllFields: response})
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	} else {
		// to be done if a field was given
		response, err := h.index.ListFieldValues(h.config.Default, fields[0], 100, 1)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		modifiedSearchResponse := struct {
			SearchResponse
			AllFields []string
		}{
			SearchResponse: response,
			AllFields:      []string{},
		}

		err = allTemplates.ExecuteTemplate(w, h.config.Template, modifiedSearchResponse)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
	}
}

type fuzzySearchHandler struct {
	config ServerSection
	index  *Index
}

func (h *fuzzySearchHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	values := struct {
		s        string   `form:"s"`
		topics   []string `form:"topic"`
		authors  []string `form:"author"`
		page     int      `form:"page"`
		pageSize int      `form:"pageSize"`
	}{}

	err := form.Decode(&values, request.URL.Values)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	query := bleve.NewQueryStringQuery(values.s)
	searchRequest := bleve.NewSearchRequest(query)
	searchRequest.Fields = []string{"path", "title", "topic", "author", "modified"}
	searchRequest.Size = values.pageSize
	searchRequest.From = values.pageSize + values.page

	results, err := h.index.Query(searchRequest)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	err = allTemplates.ExecuteTemplate(w, h.config.Template, results)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

type querySearchHandler struct {
	config ServerSection
	index  *Index
}

func (h *querySearchHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	values := struct {
		s        string `form:"s"`
		page     int    `form:"page"`
		pageSize int    `form:"pageSize"`
	}{}

	err := form.Decode(&values, request.URL.Values)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	query := bleve.NewQueryStringQuery(values.s)
	searchRequest := bleve.NewSearchRequest(query)
	searchRequest.Fields = []string{"path", "title", "topic", "author", "modified"}
	searchRequest.Size = values.pageSize
	searchRequest.From = values.pageSize + values.page

	results, err := h.index.Query(searchRequest)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	err = allTemplates.ExecuteTemplate(w, h.config.Template, results)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

type parsedHandler struct {
	config ServerSection
}

type Page struct {
	Title    string
	ToC      template.HTML
	Body     template.HTML
	Topics   []string
	Keywords []string
	Authors  []string
}

func (h *parsedHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// If the request is empty, set it to the default.
	if requestPath == "/" {
		requestPath = path.Clean(h.serverConfig.Default)
	}

	// If the request doesn't end in .md, add that
	if path.Ext(requestPath) != "md" {
		requestPath = requestPath + ".md"
	}

	pdata := new(PageMetadata)
	err := pdata.LoadPage(serverConfig.Path + requestPath)
	if err != nil {
		log.Printf("request [ %s ] points to an bad file target [ %s ] sent to server %s",
			request.URL.Path, requestPath, serverConfig.Prefix)
		http.Error(responsePipe, "Page not Found", http.StatusNotFound)
		return
	}

	if pdata.MatchedTopic(serverConfig.Restricted) {
		log.Printf("request [ %s ] was against a page [ %s ] with a restricted tag",
			request.URL.Path, requestPath)
		http.Error(responsePipe, "Restricted Page", http.StatusNotFound)
		//http.Error(responsePipe, err.Error(), http.StatusForbidden)
		return
	}

	// parse any markdown in the input
	body := template.HTML(bodyParseMarkdown(pdata.Page))
	toc := template.HTML(tocParseMarkdown(pdata.Page))
	topics, keywords, authors := pdata.ListMeta()

	// ##TODO## put this template right in the function call
	// Then remove the Page Struct above
	response := Page{
		Title:    pdata.Title,
		ToC:      toc,
		Body:     body,
		Keywords: keywords,
		Topics:   topics,
		Authors:  authors,
	}
	err = allTemplates.ExecuteTemplate(responsePipe, serverConfig.Template, response)
	if err != nil {
		http.Error(responsePipe, err.Error(), 500)
	}
}

type rawHandler struct {
	config ServerSection
}

func (h *parsedHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// If the request is empty, set it to the default.
	if requestPath == "/" {
		requestPath = path.Clean(h.serverConfig.Default)
	}

	for _, restricted := range h.config.Restricted {
		if path.Ext(requestPath) == restricted {
			log.Printf("request %s was improperly routed to the file handler with an disallowed extension %s", request.URL.Path, restricted)
			http.Error(responsePipe, "Request not allowed", 403)
			return
		}
	}

	f, err := os.Open(filePath.Join(h.config.Path, requestPath))
	if err != nil {
		http.Error(w, err.Error, http.StatusForbidden)
		log.Print(err)
		return
	}

	_, err = io.Copy(w, f)
	if err != nil {
		http.Error(w, err.Error, http.StatusInternalServerError)
		log.Print(err)
	}
}
<|endoftext|>


<commit_before>package logging

import (
	"sync"
)

// An interface for dispatching logging events to specific destinations.
// Handler can optionally use formatter instances to format records as
// desired.
type Handler interface {
	// Return the name of Handler.
	GetName() string
	// Set the name of Handler.
	SetName(name string)
	// Return the log level of Handler.
	GetLevel() LogLevelType
	// Set the log level of Handler.
	SetLevel(level LogLevelType) error

	// For Formatter.
	// Format the specified record.
	Formatter
	// Set the formatter for this Handler.
	SetFormatter(formatter Formatter)

	// For Filter managing.
	Filterer

	// Do whatever it takes to actually log the specified logging record.
	Emit(record *LogRecord) error
	// Conditionally emit the specified logging record.
	Handle(record *LogRecord) int
	// Handle errors which occur during an Emit() call.
	HandleError(record *LogRecord, err error)
	// Ensure all logging output has been flushed.
	Flush() error
	// Tidy up any resources used by the handler.
	Close()
}

// The base handler class. Acts as a base parent of any concrete handler class.
// By default, no formatter is specified, in this case, the "raw" message as
// determined by record.Message is logged.
type BaseHandler struct {
	*StandardFilterer
	name          string
	nameLock      sync.RWMutex
	level         LogLevelType
	levelLock     sync.RWMutex
	formatter     Formatter
	formatterLock sync.RWMutex

	lock sync.Mutex
}

// Initialize the instance - basically setting the formatter to nil and the
// filterer without filter.
func NewBaseHandler(name string, level LogLevelType) *BaseHandler {
	return &BaseHandler{
		StandardFilterer: NewStandardFilterer(),
		name:             name,
		level:            level,
		formatter:        nil,
	}
}

func (self *BaseHandler) GetName() string {
	self.nameLock.RLock()
	defer self.nameLock.RUnlock()
	return self.name
}

func (self *BaseHandler) SetName(name string) {
	self.nameLock.Lock()
	defer self.nameLock.Unlock()
	self.name = name
}

func (self *BaseHandler) GetLevel() LogLevelType {
	self.levelLock.RLock()
	defer self.levelLock.RUnlock()
	return self.level
}

func (self *BaseHandler) SetLevel(level LogLevelType) error {
	self.levelLock.Lock()
	defer self.levelLock.Unlock()
	_, ok := getLevelName(level)
	if !ok {
		return ErrorNoSuchLevel
	}
	self.level = level
	return nil
}

func (self *BaseHandler) SetFormatter(formatter Formatter) {
	self.formatterLock.Lock()
	defer self.formatterLock.Unlock()
	self.formatter = formatter
}

// Acquire a lock for serializing access to the underlying I/O.
func (self *BaseHandler) Lock() {
	self.lock.Lock()
}

// Release the I/O lock.
func (self *BaseHandler) Unlock() {
	self.lock.Unlock()
}

// Format the specified record.
// If a formatter is set, use it. Otherwise, use the default formatter
// for the module.
func (self *BaseHandler) Format(record *LogRecord) string {
	self.formatterLock.RLock()
	self.formatterLock.RUnlock()
	var formatter Formatter
	if self.formatter != nil {
		formatter = self.formatter
	} else {
		formatter = defaultFormatter
	}
	return formatter.Format(record)
}

// A helper function for any subclass to define its Handle() method.
// Logging event emission depends on filters which may have heen added to
// the handler. Wrap the actual emission of the record and error handling
// with Lock()/Unlock() of the I/O lock. Returns non-zero if the filter passed
// the record for emission, else zero.
func (self *BaseHandler) Handle2(handler Handler, record *LogRecord) int {
	rv := handler.Filter(record)
	if rv > 0 {
		self.Lock()
		defer self.Unlock()
		err := handler.Emit(record)
		if err != nil {
			handler.HandleError(record, err)
		}
	}
	return rv
}

// A doing-nothing implementation as a stub for any subclass.
func (self *BaseHandler) HandleError(_ *LogRecord, _ error) {
	// Empty body
}

// A doing-nothing implementation as a stub for any subclass.
func (self *BaseHandler) Flush() error {
	// Empty body
	return nil
}

// A doing-nothing implementation as a stub for any subclass.
func (self *BaseHandler) Close() {
	// Empty body
}
<commit_msg>fix unlock call<commit_after>package logging

import (
	"sync"
)

// An interface for dispatching logging events to specific destinations.
// Handler can optionally use formatter instances to format records as
// desired.
type Handler interface {
	// Return the name of Handler.
	GetName() string
	// Set the name of Handler.
	SetName(name string)
	// Return the log level of Handler.
	GetLevel() LogLevelType
	// Set the log level of Handler.
	SetLevel(level LogLevelType) error

	// For Formatter.
	// Format the specified record.
	Formatter
	// Set the formatter for this Handler.
	SetFormatter(formatter Formatter)

	// For Filter managing.
	Filterer

	// Do whatever it takes to actually log the specified logging record.
	Emit(record *LogRecord) error
	// Conditionally emit the specified logging record.
	Handle(record *LogRecord) int
	// Handle errors which occur during an Emit() call.
	HandleError(record *LogRecord, err error)
	// Ensure all logging output has been flushed.
	Flush() error
	// Tidy up any resources used by the handler.
	Close()
}

// The base handler class. Acts as a base parent of any concrete handler class.
// By default, no formatter is specified, in this case, the "raw" message as
// determined by record.Message is logged.
type BaseHandler struct {
	*StandardFilterer
	name          string
	nameLock      sync.RWMutex
	level         LogLevelType
	levelLock     sync.RWMutex
	formatter     Formatter
	formatterLock sync.RWMutex

	lock sync.Mutex
}

// Initialize the instance - basically setting the formatter to nil and the
// filterer without filter.
func NewBaseHandler(name string, level LogLevelType) *BaseHandler {
	return &BaseHandler{
		StandardFilterer: NewStandardFilterer(),
		name:             name,
		level:            level,
		formatter:        nil,
	}
}

func (self *BaseHandler) GetName() string {
	self.nameLock.RLock()
	defer self.nameLock.RUnlock()
	return self.name
}

func (self *BaseHandler) SetName(name string) {
	self.nameLock.Lock()
	defer self.nameLock.Unlock()
	self.name = name
}

func (self *BaseHandler) GetLevel() LogLevelType {
	self.levelLock.RLock()
	defer self.levelLock.RUnlock()
	return self.level
}

func (self *BaseHandler) SetLevel(level LogLevelType) error {
	self.levelLock.Lock()
	defer self.levelLock.Unlock()
	_, ok := getLevelName(level)
	if !ok {
		return ErrorNoSuchLevel
	}
	self.level = level
	return nil
}

func (self *BaseHandler) SetFormatter(formatter Formatter) {
	self.formatterLock.Lock()
	defer self.formatterLock.Unlock()
	self.formatter = formatter
}

// Acquire a lock for serializing access to the underlying I/O.
func (self *BaseHandler) Lock() {
	self.lock.Lock()
}

// Release the I/O lock.
func (self *BaseHandler) Unlock() {
	self.lock.Unlock()
}

// Format the specified record.
// If a formatter is set, use it. Otherwise, use the default formatter
// for the module.
func (self *BaseHandler) Format(record *LogRecord) string {
	self.formatterLock.RLock()
	defer self.formatterLock.RUnlock()
	var formatter Formatter
	if self.formatter != nil {
		formatter = self.formatter
	} else {
		formatter = defaultFormatter
	}
	return formatter.Format(record)
}

// A helper function for any subclass to define its Handle() method.
// Logging event emission depends on filters which may have heen added to
// the handler. Wrap the actual emission of the record and error handling
// with Lock()/Unlock() of the I/O lock. Returns non-zero if the filter passed
// the record for emission, else zero.
func (self *BaseHandler) Handle2(handler Handler, record *LogRecord) int {
	rv := handler.Filter(record)
	if rv > 0 {
		self.Lock()
		defer self.Unlock()
		err := handler.Emit(record)
		if err != nil {
			handler.HandleError(record, err)
		}
	}
	return rv
}

// A doing-nothing implementation as a stub for any subclass.
func (self *BaseHandler) HandleError(_ *LogRecord, _ error) {
	// Empty body
}

// A doing-nothing implementation as a stub for any subclass.
func (self *BaseHandler) Flush() error {
	// Empty body
	return nil
}

// A doing-nothing implementation as a stub for any subclass.
func (self *BaseHandler) Close() {
	// Empty body
}
<|endoftext|>


<commit_before>// ************
// todo : https://semaphoreci.com/community/tutorials/building-and-testing-a-rest-api-in-go-with-gorilla-mux-and-postgresql
// ************

package main_test

import (
	"testing"
	"."
	"os"
	"net/http"
	"net/http/httptest"
	"log"
	"github.com/spf13/viper"
)

var a main.App

const tableCreationQuery = `CREATE TABLE IF NOT EXISTS orders
(
id SERIAL,
NAME TEXT NOT NULL,
price NUMERIC (10, 2) NOT NULL DEFAULT 0.00,
CONSTRAINT orders_pkey PRIMARY KEY (id)
)`

func TestMain(m *testing.M) {

	viper.SetConfigName("config")
	viper.AddConfigPath(".")
	viper.ReadInConfig()

	a = main.App{}
	a.Initialize(
		viper.GetString("testing.dbUser"),
		viper.GetString("testing.dbPass"),
		viper.GetString("testing.db"))

	a.PopulateRoutes()

	ensureTableExists()
	code := m.Run()
	clearTable()

	os.Exit(code)
}

func ensureTableExists() {
	if _, err := a.DB.Exec(tableCreationQuery); err != nil {
		log.Fatal(err)
	}
}

func clearTable() {
	a.DB.Exec("DELETE FROM orders")
	a.DB.Exec("ALTER SEQUENCE orders_id_seq RESTART WITH 1")
}

func TestEmptyTable(t *testing.T) {
	clearTable()

	req, _ := http.NewRequest("GET", "/orders", nil)
	response := executeRequest(req)

	checkResponseCode(t, http.StatusOK, response.Code)

	if body := response.Body.String(); body != "[]" {
		t.Errorf("Expected an empty array. Got %s", body)
	}
}

func executeRequest(req *http.Request) *httptest.ResponseRecorder {
	rr := httptest.NewRecorder()
	a.Router.ServeHTTP(rr, req)

	return rr
}

func checkResponseCode(t *testing.T, expected, actual int) {
	if expected != actual {
		t.Errorf("Expected response code %d. Got %d\n", expected, actual)
	}
}

func TestGetOrders(t *testing.T) {

	req, _ := http.NewRequest("GET", "/orders", nil)
	response := executeRequest(req)

	checkResponseCode(t, http.StatusOK, response.Code)
}

func TestGetTodos(t *testing.T) {

	req, _ := http.NewRequest("GET", "/todos", nil)
	response := executeRequest(req)

	checkResponseCode(t, http.StatusOK, response.Code)
}

<commit_msg>v2: Added Database backend<commit_after>// ************
// todo : https://semaphoreci.com/community/tutorials/building-and-testing-a-rest-api-in-go-with-gorilla-mux-and-postgresql
// ************

package main_test

import (
	"."
	"github.com/spf13/viper"
	"log"
	"net/http"
	"net/http/httptest"
	"os"
	"testing"
)

var a main.App

const tableCreationQuery = `CREATE TABLE IF NOT EXISTS orders
(
id SERIAL,
NAME TEXT NOT NULL,
price NUMERIC (10, 2) NOT NULL DEFAULT 0.00,
CONSTRAINT orders_pkey PRIMARY KEY (id)
)`

func TestMain(m *testing.M) {

	viper.SetConfigName("config")
	viper.AddConfigPath(".")
	viper.ReadInConfig()

	a = main.App{}
	a.Initialize(
		viper.GetString("testing.dbUser"),
		viper.GetString("testing.dbPass"),
		viper.GetString("testing.db"))

	ensureTableExists()
	code := m.Run()
	clearTable()

	os.Exit(code)
}

func ensureTableExists() {
	if _, err := a.DB.Exec(tableCreationQuery); err != nil {
		log.Fatal(err)
	}
}

func clearTable() {
	a.DB.Exec("DELETE FROM orders")
	a.DB.Exec("ALTER SEQUENCE orders_id_seq RESTART WITH 1")
}

func TestEmptyTable(t *testing.T) {
	clearTable()

	req, _ := http.NewRequest("GET", "/orders", nil)
	response := executeRequest(req)

	checkResponseCode(t, http.StatusOK, response.Code)

	if body := response.Body.String(); body != "[]" {
		t.Errorf("Expected an empty array. Got %s", body)
	}
}

func executeRequest(req *http.Request) *httptest.ResponseRecorder {
	rr := httptest.NewRecorder()
	a.Router.ServeHTTP(rr, req)

	return rr
}

func checkResponseCode(t *testing.T, expected, actual int) {
	if expected != actual {
		t.Errorf("Expected response code %d. Got %d\n", expected, actual)
	}
}

func TestGetOrders(t *testing.T) {

	req, _ := http.NewRequest("GET", "/orders", nil)
	response := executeRequest(req)

	checkResponseCode(t, http.StatusOK, response.Code)
}

func TestGetTodos(t *testing.T) {

	req, _ := http.NewRequest("GET", "/todos", nil)
	response := executeRequest(req)

	checkResponseCode(t, http.StatusOK, response.Code)
}
<|endoftext|>


<commit_before>package runner

import (
	"time"

	"github.com/Sirupsen/logrus"
	titancommon "github.com/iron-io/titan/common"
	"golang.org/x/net/context"
)

func LogMetricGauge(ctx context.Context, name string, value int) {
	log := titancommon.Logger(ctx)
	log.WithFields(logrus.Fields{
		"metric": name, "type": "count", "value": value}).Info()
}

func LogMetricCount(ctx context.Context, name string, value int) {
	log := titancommon.Logger(ctx)
	log.WithFields(logrus.Fields{
		"metric": name, "type": "count", "value": value}).Info()
}

func LogMetricTime(ctx context.Context, name string, time time.Duration) {
	log := titancommon.Logger(ctx)
	log.WithFields(logrus.Fields{
		"metric": name, "type": "time", "value": time}).Info()
}
<commit_msg>fix typo<commit_after>package runner

import (
	"time"

	"github.com/Sirupsen/logrus"
	titancommon "github.com/iron-io/titan/common"
	"golang.org/x/net/context"
)

func LogMetricGauge(ctx context.Context, name string, value int) {
	log := titancommon.Logger(ctx)
	log.WithFields(logrus.Fields{
		"metric": name, "type": "gauge", "value": value}).Info()
}

func LogMetricCount(ctx context.Context, name string, value int) {
	log := titancommon.Logger(ctx)
	log.WithFields(logrus.Fields{
		"metric": name, "type": "count", "value": value}).Info()
}

func LogMetricTime(ctx context.Context, name string, time time.Duration) {
	log := titancommon.Logger(ctx)
	log.WithFields(logrus.Fields{
		"metric": name, "type": "time", "value": time}).Info()
}
<|endoftext|>


<commit_before>package api

import (
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/unversioned"
)

const (
	ResourceCodeSnapshot = "snp"
	ResourceKindSnapshot = "Snapshot"
	ResourceNameSnapshot = "snapshot"
	ResourceTypeSnapshot = "snapshots"
)

type Snapshot struct {
	unversioned.TypeMeta `json:",inline,omitempty"`
	api.ObjectMeta       `json:"metadata,omitempty"`
	Spec                 SnapshotSpec   `json:"spec,omitempty"`
	Status               SnapshotStatus `json:"status,omitempty"`
}

type SnapshotSpec struct {
	// Database name
	DatabaseName string `json:"databaseName,omitempty"`
	// Snapshot Spec
	SnapshotStorageSpec `json:",inline,omitempty"`
}

type SnapshotPhase string

const (
	// used for Snapshots that are currently running
	SnapshotPhaseRunning SnapshotPhase = "Running"
	// used for Snapshots that are Succeeded
	SnapshotPhaseSuccessed SnapshotPhase = "Succeeded"
	// used for Snapshots that are Failed
	SnapshotPhaseFailed SnapshotPhase = "Failed"
)

type SnapshotStatus struct {
	StartTime      *unversioned.Time `json:"startTime,omitempty"`
	CompletionTime *unversioned.Time `json:"completionTime,omitempty"`
	Phase          SnapshotPhase     `json:"phase,omitempty"`
	Reason         string            `json:"reason,omitempty"`
}

type SnapshotList struct {
	unversioned.TypeMeta `json:",inline"`
	unversioned.ListMeta `json:"metadata,omitempty"`
	// Items is a list of Snapshot TPR objects
	Items []Snapshot `json:"items,omitempty"`
}
<commit_msg>Use snap as code for Snapshot types. (#73)<commit_after>package api

import (
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/unversioned"
)

const (
	ResourceCodeSnapshot = "snap"
	ResourceKindSnapshot = "Snapshot"
	ResourceNameSnapshot = "snapshot"
	ResourceTypeSnapshot = "snapshots"
)

type Snapshot struct {
	unversioned.TypeMeta `json:",inline,omitempty"`
	api.ObjectMeta       `json:"metadata,omitempty"`
	Spec                 SnapshotSpec   `json:"spec,omitempty"`
	Status               SnapshotStatus `json:"status,omitempty"`
}

type SnapshotSpec struct {
	// Database name
	DatabaseName string `json:"databaseName,omitempty"`
	// Snapshot Spec
	SnapshotStorageSpec `json:",inline,omitempty"`
}

type SnapshotPhase string

const (
	// used for Snapshots that are currently running
	SnapshotPhaseRunning SnapshotPhase = "Running"
	// used for Snapshots that are Succeeded
	SnapshotPhaseSuccessed SnapshotPhase = "Succeeded"
	// used for Snapshots that are Failed
	SnapshotPhaseFailed SnapshotPhase = "Failed"
)

type SnapshotStatus struct {
	StartTime      *unversioned.Time `json:"startTime,omitempty"`
	CompletionTime *unversioned.Time `json:"completionTime,omitempty"`
	Phase          SnapshotPhase     `json:"phase,omitempty"`
	Reason         string            `json:"reason,omitempty"`
}

type SnapshotList struct {
	unversioned.TypeMeta `json:",inline"`
	unversioned.ListMeta `json:"metadata,omitempty"`
	// Items is a list of Snapshot TPR objects
	Items []Snapshot `json:"items,omitempty"`
}
<|endoftext|>