<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package main

import (
	"fmt"
	"github.com/szabba/md/newton"
	"github.com/szabba/md/vect"
	"io"
	"os"
)

// A constant force
type ConstForce vect.Vector

func (f ConstForce) Accel(bs []*newton.Body, i int) (a vect.Vector) {

	return vect.Vector(f).Scale(1 / bs[i].Mass())
}

// A 'picky' force, that doesn't affect some bodies
type PickyForce struct {
	force   newton.Force
	zeroFor []int
}

// Creates a picky version of a force
func NewPicky(f newton.Force, zeroFor ...int) newton.Force {

	return &PickyForce{force: f, zeroFor: zeroFor}
}

func (picky *PickyForce) Accel(bs []*newton.Body, i int) (a vect.Vector) {

	for _, ignored := range picky.zeroFor {

		if ignored == i {

			return vect.Zero
		}
	}

	return picky.force.Accel(bs, i)
}

type ParticleRect struct {
	*newton.System
	rows, cols int
}

// Creates a rectangular grid of particles
//
// The program's behaviour when rows or cols are less than 1 is unspecified
func NewRect(rows, cols int) *ParticleRect {

	rect := &ParticleRect{
		rows: rows, cols: cols,
	}

	rect.System = newton.NewSystem(newton.Verlet, rows*cols)

	for i := 0; i < rect.Bodies(); i++ {

		b := rect.Body(i)

		b.SetMass(1)

		pos := rect.RestingPosition(i)

		b.Shift(pos, vect.Zero)
		b.Shift(pos, vect.Zero)

	}

	rect.SetForce(ConstForce(vect.Zero))

	return rect
}

// The row and column in which the i-th particle is
func (rect *ParticleRect) RowAndColumn(ith int) (row, col int) {

	return ith % rect.rows, ith / rect.rows
}

// Initial, resting position of the i-th particle
func (rect *ParticleRect) RestingPosition(ith int) vect.Vector {

	row, col := rect.RowAndColumn(ith)

	return vect.UnitX.Scale(float64(row)).Plus(
		vect.UnitY.Scale(float64(col)),
	)
}

// Dimmensions of the rectangle
func (rect *ParticleRect) Size() (rows, cols int) {

	return rect.rows, rect.cols
}

// Are the i-th and j-th particles neighbours?
func (rect *ParticleRect) Neighbours(i, j int) bool {

	xI, yI := rect.RowAndColumn(i)
	xJ, yJ := rect.RowAndColumn(j)

	nearInX := xI-1 == xJ || xJ == xI+1
	nearInY := yI-1 == yJ || yJ == yI+1

	sameX := xI == xJ
	sameY := yI == yJ

	colNeighbour := sameX && nearInY
	rowNeighbour := sameY && nearInX

	return colNeighbour || rowNeighbour
}

// Prepare a Hooke's force bidning neihbouring particles
func (rect *ParticleRect) Hooke(k float64) newton.Force {

	var h newton.Hooke

	h.Springs = make([][]newton.Spring, rect.Bodies())
	for i, _ := range h.Springs {

		h.Springs[i] = make([]newton.Spring, rect.Bodies())
		for j, _ := range h.Springs[i] {

			if rect.Neighbours(i, j) {

				h.Springs[i][j].K = k

			}
			h.Springs[i][j].L0 = 1
		}
	}

	return h
}

// Prepare a constant force that only affect the center of the rectangle
//
// Depending on the shape of the rectangle this will pull 1, 2 or 4 particles.
// The force applied per particle will be divided by this number.
func (rect *ParticleRect) CentralPull(pull vect.Vector) newton.Force {

	rows, cols := rect.Size()

	xRange, yRange := make([]int, rows%2), make([]int, cols%2)
	for i, x := 0, rows/2; i < len(xRange); i, x = i+1, x+1 {

		xRange[i] = x
	}
	for i, y := 0, cols/2; i < len(yRange); i, y = i+1, y+1 {

		yRange[i] = y
	}

	i, picked := 0, make([]int, len(xRange)*len(yRange))
	for _, x := range xRange {
		for _, y := range yRange {

			picked[i] = y*cols + x
			i++
		}
	}

	return NewPicky(
		ConstForce(pull.Scale(1/float64(len(picked)))),
		picked...,
	)
}

// Runs the simulation for the given number of steps at a time step of dt
// printing to writeTo
func (rect *ParticleRect) Run(writeTo io.Writer, dt float64, steps int) {

	format := &Formatter{rect: rect, writeTo: writeTo}

	format.Header()

	for i := 0; i < steps; i++ {

		format.Frame()

		rect.Step(dt)
	}
}

// An output formatting type
type Formatter struct {
	rect    *ParticleRect
	writeTo io.Writer
}

// Formats a data header
func (f Formatter) Header() {

	fmt.Fprintf(f.writeTo, "%d\n\n", f.rect.Bodies())
}

// Formats the description of ball states
func (f Formatter) Frame() {

	for i := 0; i < f.rect.Bodies(); i++ {

		b := f.rect.Body(i)

		x, v := b.Now()

		fmt.Fprintf(
			f.writeTo, "%d %f %f %f %f %f %f\n", i,
			x[0], x[1], x[2],
			v[0], v[1], v[2],
		)

	}
	fmt.Fprintf(f.writeTo, "\n")
}

func main() {

	rect := NewRect(2, 4)
	rect.AddForce(rect.Hooke(1))
	rect.Run(os.Stdout, 0.05, 3)
}
<commit_msg>Handle command line options and arguments in cmd/square<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package main

import (
	"flag"
	"fmt"
	"github.com/szabba/md/newton"
	"github.com/szabba/md/vect"
	"io"
	"log"
	"os"
	"strconv"
)

// A constant force
type ConstForce vect.Vector

func (f ConstForce) Accel(bs []*newton.Body, i int) (a vect.Vector) {

	return vect.Vector(f).Scale(1 / bs[i].Mass())
}

// A 'picky' force, that doesn't affect some bodies
type PickyForce struct {
	force   newton.Force
	zeroFor []int
}

// Creates a picky version of a force
func NewPicky(f newton.Force, zeroFor ...int) newton.Force {

	return &PickyForce{force: f, zeroFor: zeroFor}
}

func (picky *PickyForce) Accel(bs []*newton.Body, i int) (a vect.Vector) {

	for _, ignored := range picky.zeroFor {

		if ignored == i {

			return vect.Zero
		}
	}

	return picky.force.Accel(bs, i)
}

type ParticleRect struct {
	*newton.System
	rows, cols int
}

// Creates a rectangular grid of particles
//
// The program's behaviour when rows or cols are less than 1 is unspecified
func NewRect(rows, cols int) *ParticleRect {

	rect := &ParticleRect{
		rows: rows, cols: cols,
	}

	rect.System = newton.NewSystem(newton.Verlet, rows*cols)

	for i := 0; i < rect.Bodies(); i++ {

		b := rect.Body(i)

		b.SetMass(1)

		pos := rect.RestingPosition(i)

		b.Shift(pos, vect.Zero)
		b.Shift(pos, vect.Zero)

	}

	rect.SetForce(ConstForce(vect.Zero))

	return rect
}

// The row and column in which the i-th particle is
func (rect *ParticleRect) RowAndColumn(ith int) (row, col int) {

	return ith % rect.rows, ith / rect.rows
}

// Initial, resting position of the i-th particle
func (rect *ParticleRect) RestingPosition(ith int) vect.Vector {

	row, col := rect.RowAndColumn(ith)

	return vect.UnitX.Scale(float64(row)).Plus(
		vect.UnitY.Scale(float64(col)),
	)
}

// Dimmensions of the rectangle
func (rect *ParticleRect) Size() (rows, cols int) {

	return rect.rows, rect.cols
}

// Are the i-th and j-th particles neighbours?
func (rect *ParticleRect) Neighbours(i, j int) bool {

	xI, yI := rect.RowAndColumn(i)
	xJ, yJ := rect.RowAndColumn(j)

	nearInX := xI-1 == xJ || xJ == xI+1
	nearInY := yI-1 == yJ || yJ == yI+1

	sameX := xI == xJ
	sameY := yI == yJ

	colNeighbour := sameX && nearInY
	rowNeighbour := sameY && nearInX

	return colNeighbour || rowNeighbour
}

// Prepare a Hooke's force bidning neihbouring particles
func (rect *ParticleRect) Hooke(k float64) newton.Force {

	var h newton.Hooke

	h.Springs = make([][]newton.Spring, rect.Bodies())
	for i, _ := range h.Springs {

		h.Springs[i] = make([]newton.Spring, rect.Bodies())
		for j, _ := range h.Springs[i] {

			if rect.Neighbours(i, j) {

				h.Springs[i][j].K = k

			}
			h.Springs[i][j].L0 = 1
		}
	}

	return h
}

// Prepare a constant force that only affect the center of the rectangle
//
// Depending on the shape of the rectangle this will pull 1, 2 or 4 particles.
// The force applied per particle will be divided by this number.
func (rect *ParticleRect) CentralPull(pull vect.Vector) newton.Force {

	rows, cols := rect.Size()

	xRange, yRange := make([]int, rows%2), make([]int, cols%2)
	for i, x := 0, rows/2; i < len(xRange); i, x = i+1, x+1 {

		xRange[i] = x
	}
	for i, y := 0, cols/2; i < len(yRange); i, y = i+1, y+1 {

		yRange[i] = y
	}

	i, picked := 0, make([]int, len(xRange)*len(yRange))
	for _, x := range xRange {
		for _, y := range yRange {

			picked[i] = y*cols + x
			i++
		}
	}

	return NewPicky(
		ConstForce(pull.Scale(1/float64(len(picked)))),
		picked...,
	)
}

// Runs the simulation for the given number of steps at a time step of dt
// printing to writeTo
func (rect *ParticleRect) Run(writeTo io.Writer, dt float64, steps int) {

	format := &Formatter{rect: rect, writeTo: writeTo}

	format.Header()

	for i := 0; i < steps; i++ {

		format.Frame()

		rect.Step(dt)
	}
}

// An output formatting type
type Formatter struct {
	rect    *ParticleRect
	writeTo io.Writer
}

// Formats a data header
func (f Formatter) Header() {

	fmt.Fprintf(f.writeTo, "%d\n\n", f.rect.Bodies())
}

// Formats the description of ball states
func (f Formatter) Frame() {

	for i := 0; i < f.rect.Bodies(); i++ {

		b := f.rect.Body(i)

		x, v := b.Now()

		fmt.Fprintf(
			f.writeTo, "%d %f %f %f %f %f %f\n", i,
			x[0], x[1], x[2],
			v[0], v[1], v[2],
		)

	}
	fmt.Fprintf(f.writeTo, "\n")
}

const usage string = `Usage of %s:

	Simulate a rectangular surface made of particles interconnected with
	strings.

		%s [options] ROWS COLS

	ROWS and COLS determines the shape and size of the rectangle. They must
	both be at least 1.

Options:
`

func Help() {

	program := os.Args[0]

	fmt.Fprintf(os.Stderr, usage, program, program)

	flag.PrintDefaults()
}

func main() {

	var (
		usage    bool
		p, k, dt float64
		steps    int
	)

	log.SetFlags(0)

	flag.Float64Var(
		&p, "pull", 1,
		"Magnitude of the vertical pulling force. When negative, the force pulls down.",
	)
	flag.Float64Var(&dt, "dt", 0.05, "Time step")
	flag.Float64Var(&k, "k", 1, "Hooke's constant")
	flag.IntVar(&steps, "steps", 5, "Simulation steps to perform")
	flag.BoolVar(&usage, "help", false, "Print usage string")

	flag.Parse()

	if usage {

		Help()

	} else if len(flag.Args()) != 2 {

		log.Fatal("Both ROWS and COLS need to be specified")

	} else {

		var (
			rows, cols int
			err        error
		)

		rows, err = strconv.Atoi(flag.Arg(0))
		if err != nil {

			log.Print("ROWS needs to be an integer")
			log.Fatal(err.Error())
		}
		cols, err = strconv.Atoi(flag.Arg(1))
		if err != nil {

			log.Print("COLS needs to be an integer")
			log.Fatal(err.Error())
		}

		rect := NewRect(rows, cols)
		rect.AddForce(rect.Hooke(k))
		rect.AddForce(rect.CentralPull(vect.UnitZ.Scale(p)))
		rect.Run(os.Stdout, dt, steps)
	}
}
<|endoftext|>


<commit_before>// Copyright 2013 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This is a blog server for articles written in present format.
// It powers blog.golang.org.
package main

import (
	"bytes"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
	"sort"
	"time"

	"code.google.com/p/go.blog/pkg/atom"
	_ "code.google.com/p/go.talks/pkg/playground"
	"code.google.com/p/go.talks/pkg/present"
)

const (
	hostname     = "blog.golang.org"
	baseURL      = "http://" + hostname
	homeArticles = 5  // articles to display on the home page
	feedArticles = 10 // articles to include in Atom and JSON feeds
)

var validJSONPFunc = regexp.MustCompile(`(?i)^[a-z_][a-z0-9_.]*$`)

// Doc represents an article, adorned with presentation data:
// its absolute path and related articles.
type Doc struct {
	*present.Doc
	Permalink    string
	Path         string
	Related      []*Doc
	Newer, Older *Doc
	HTML         template.HTML // rendered article
}

// Server implements an http.Handler that serves blog articles.
type Server struct {
	docs     []*Doc
	tags     []string
	docPaths map[string]*Doc
	docTags  map[string][]*Doc
	template struct {
		home, index, article, doc *template.Template
	}
	atomFeed []byte // pre-rendered Atom feed
	jsonFeed []byte // pre-rendered JSON feed
	content  http.Handler
}

// NewServer constructs a new Server, serving articles from the specified
// contentPath generated from templates from templatePath.
func NewServer(contentPath, templatePath string) (*Server, error) {
	present.PlayEnabled = true

	root := filepath.Join(templatePath, "root.tmpl")
	parse := func(name string) (*template.Template, error) {
		t := template.New("").Funcs(funcMap)
		return t.ParseFiles(root, filepath.Join(templatePath, name))
	}

	s := &Server{}

	// Parse templates.
	var err error
	s.template.home, err = parse("home.tmpl")
	if err != nil {
		return nil, err
	}
	s.template.index, err = parse("index.tmpl")
	if err != nil {
		return nil, err
	}
	s.template.article, err = parse("article.tmpl")
	if err != nil {
		return nil, err
	}
	p := present.Template().Funcs(funcMap)
	s.template.doc, err = p.ParseFiles(filepath.Join(templatePath, "doc.tmpl"))
	if err != nil {
		return nil, err
	}

	// Load content.
	err = s.loadDocs(filepath.Clean(contentPath))
	if err != nil {
		return nil, err
	}

	err = s.renderAtomFeed()
	if err != nil {
		return nil, err
	}

	err = s.renderJSONFeed()
	if err != nil {
		return nil, err
	}

	// Set up content file server.
	s.content = http.FileServer(http.Dir(contentPath))

	return s, nil
}

var funcMap = template.FuncMap{
	"sectioned": sectioned,
	"authors":   authors,
}

// sectioned returns true if the provided Doc contains more than one section.
// This is used to control whether to display the table of contents and headings.
func sectioned(d *present.Doc) bool {
	return len(d.Sections) > 1
}

// authors returns a comma-separated list of author names.
func authors(authors []present.Author) string {
	var b bytes.Buffer
	last := len(authors) - 1
	for i, a := range authors {
		if i > 0 {
			if i == last {
				b.WriteString(" and ")
			} else {
				b.WriteString(", ")
			}
		}
		b.WriteString(authorName(a))
	}
	return b.String()
}

// authorName returns the first line of the Author text: the author's name.
func authorName(a present.Author) string {
	el := a.TextElem()
	if len(el) == 0 {
		return ""
	}
	text, ok := el[0].(present.Text)
	if !ok || len(text.Lines) == 0 {
		return ""
	}
	return text.Lines[0]
}

// loadDocs reads all content from the provided file system root, renders all
// the articles it finds, adds them to the Server's docs field, computes the
// denormalized docPaths, docTags, and tags fields, and populates the various
// helper fields (Next, Previous, Related) for each Doc.
func (s *Server) loadDocs(root string) error {
	// Read content into docs field.
	const ext = ".article"
	fn := func(p string, info os.FileInfo, err error) error {
		if filepath.Ext(p) != ext {
			return nil
		}
		f, err := os.Open(p)
		if err != nil {
			return err
		}
		defer f.Close()
		d, err := present.Parse(f, p, 0)
		if err != nil {
			return err
		}
		html := new(bytes.Buffer)
		err = d.Render(html, s.template.doc)
		if err != nil {
			return err
		}
		p = p[len(root) : len(p)-len(ext)] // trim root and extension
		s.docs = append(s.docs, &Doc{
			Doc:       d,
			Path:      p,
			Permalink: baseURL + p,
			HTML:      template.HTML(html.String()),
		})
		return nil
	}
	err := filepath.Walk(root, fn)
	if err != nil {
		return err
	}
	sort.Sort(docsByTime(s.docs))

	// Pull out doc paths and tags and put in reverse-associating maps.
	s.docPaths = make(map[string]*Doc)
	s.docTags = make(map[string][]*Doc)
	for _, d := range s.docs {
		s.docPaths[d.Path] = d
		for _, t := range d.Tags {
			s.docTags[t] = append(s.docTags[t], d)
		}
	}

	// Pull out unique sorted list of tags.
	for t := range s.docTags {
		s.tags = append(s.tags, t)
	}
	sort.Strings(s.tags)

	// Set up presentation-related fields, Newer, Older, and Related.
	for _, doc := range s.docs {
		// Newer, Older: docs adjacent to doc
		for i := range s.docs {
			if s.docs[i] != doc {
				continue
			}
			if i > 0 {
				doc.Newer = s.docs[i-1]
			}
			if i+1 < len(s.docs) {
				doc.Older = s.docs[i+1]
			}
			break
		}

		// Related: all docs that share tags with doc.
		related := make(map[*Doc]bool)
		for _, t := range doc.Tags {
			for _, d := range s.docTags[t] {
				if d != doc {
					related[d] = true
				}
			}
		}
		for d := range related {
			doc.Related = append(doc.Related, d)
		}
		sort.Sort(docsByTime(doc.Related))
	}

	return nil
}

// renderAtomFeed generates an XML Atom feed and stores it in the Server's
// atomFeed field.
func (s *Server) renderAtomFeed() error {
	var updated time.Time
	if len(s.docs) > 1 {
		updated = s.docs[0].Time
	}
	feed := atom.Feed{
		Title:   "The Go Programming Language Blog",
		ID:      "tag:" + hostname + ",2013:" + hostname,
		Updated: atom.Time(updated),
		Link: []atom.Link{{
			Rel:  "self",
			Href: baseURL + "/feed.atom",
		}},
	}
	for i, doc := range s.docs {
		if i >= feedArticles {
			break
		}
		e := &atom.Entry{
			Title: doc.Title,
			ID:    feed.ID + doc.Path,
			Link: []atom.Link{{
				Rel:  "alternate",
				Href: baseURL + doc.Path,
			}},
			Published: atom.Time(doc.Time),
			Updated:   atom.Time(doc.Time),
			Summary: &atom.Text{
				Type: "html",
				Body: summary(doc),
			},
			Content: &atom.Text{
				Type: "html",
				Body: string(doc.HTML),
			},
			Author: &atom.Person{
				Name: authors(doc.Authors),
			},
		}
		feed.Entry = append(feed.Entry, e)
	}
	data, err := xml.Marshal(&feed)
	if err != nil {
		return err
	}
	s.atomFeed = data
	return nil
}

type jsonItem struct {
	Title   string
	Link    string
	Time    time.Time
	Summary string
	Content string
	Author  string
}

// renderJSONFeed generates a JSON feed and stores it in the Server's jsonFeed
// field.
func (s *Server) renderJSONFeed() error {
	var feed []jsonItem
	for i, doc := range s.docs {
		if i >= feedArticles {
			break
		}
		item := jsonItem{
			Title:   doc.Title,
			Link:    baseURL + doc.Path,
			Time:    doc.Time,
			Summary: summary(doc),
			Content: string(doc.HTML),
			Author:  authors(doc.Authors),
		}
		feed = append(feed, item)
	}
	data, err := json.Marshal(feed)
	if err != nil {
		return err
	}
	s.jsonFeed = data
	return nil
}

// summary returns the first paragraph of text from the provided Doc.
func summary(d *Doc) string {
	if len(d.Sections) == 0 {
		return ""
	}
	for _, elem := range d.Sections[0].Elem {
		text, ok := elem.(present.Text)
		if !ok || text.Pre {
			// skip everything but non-text elements
			continue
		}
		var buf bytes.Buffer
		for _, s := range text.Lines {
			buf.WriteString(string(present.Style(s)))
			buf.WriteByte('\n')
		}
		return buf.String()
	}
	return ""
}

// rootData encapsulates data destined for the root template.
type rootData struct {
	Doc  *Doc
	Data interface{}
}

// ServeHTTP servers either an article list or a single article.
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	var (
		d rootData
		t *template.Template
	)
	switch p := r.URL.Path; p {
	case "/":
		d.Data = s.docs
		if len(s.docs) > homeArticles {
			d.Data = s.docs[:homeArticles]
		}
		t = s.template.home
	case "/index":
		d.Data = s.docs
		t = s.template.index
	case "/feed.atom", "/feeds/posts/default":
		w.Header().Set("Content-type", "application/atom+xml; charset=utf-8")
		w.Write(s.atomFeed)
		return
	case "/.json":
		if p := r.FormValue("jsonp"); validJSONPFunc.MatchString(p) {
			w.Header().Set("Content-type", "application/javascript; charset=utf-8")
			fmt.Fprintf(w, "%v(%s)", p, s.jsonFeed)
			return
		}
		w.Header().Set("Content-type", "application/json; charset=utf-8")
		w.Write(s.jsonFeed)
		return
	default:
		doc, ok := s.docPaths[p]
		if !ok {
			// Not a doc; try to just serve static content.
			s.content.ServeHTTP(w, r)
			return
		}
		d.Doc = doc
		t = s.template.article
	}
	err := t.ExecuteTemplate(w, "root", d)
	if err != nil {
		log.Println(err)
	}
}

// docsByTime implements sort.Interface, sorting Docs by their Time field.
type docsByTime []*Doc

func (s docsByTime) Len() int           { return len(s) }
func (s docsByTime) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s docsByTime) Less(i, j int) bool { return s[i].Time.After(s[j].Time) }
<commit_msg>[x/blog] go.blog/cmd/blog: use playground package from go.tools<commit_after>// Copyright 2013 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This is a blog server for articles written in present format.
// It powers blog.golang.org.
package main

import (
	"bytes"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
	"sort"
	"time"

	"code.google.com/p/go.blog/pkg/atom"
	"code.google.com/p/go.talks/pkg/present"

	_ "code.google.com/p/go.tools/godoc/playground"
)

const (
	hostname     = "blog.golang.org"
	baseURL      = "http://" + hostname
	homeArticles = 5  // articles to display on the home page
	feedArticles = 10 // articles to include in Atom and JSON feeds
)

var validJSONPFunc = regexp.MustCompile(`(?i)^[a-z_][a-z0-9_.]*$`)

// Doc represents an article, adorned with presentation data:
// its absolute path and related articles.
type Doc struct {
	*present.Doc
	Permalink    string
	Path         string
	Related      []*Doc
	Newer, Older *Doc
	HTML         template.HTML // rendered article
}

// Server implements an http.Handler that serves blog articles.
type Server struct {
	docs     []*Doc
	tags     []string
	docPaths map[string]*Doc
	docTags  map[string][]*Doc
	template struct {
		home, index, article, doc *template.Template
	}
	atomFeed []byte // pre-rendered Atom feed
	jsonFeed []byte // pre-rendered JSON feed
	content  http.Handler
}

// NewServer constructs a new Server, serving articles from the specified
// contentPath generated from templates from templatePath.
func NewServer(contentPath, templatePath string) (*Server, error) {
	present.PlayEnabled = true

	root := filepath.Join(templatePath, "root.tmpl")
	parse := func(name string) (*template.Template, error) {
		t := template.New("").Funcs(funcMap)
		return t.ParseFiles(root, filepath.Join(templatePath, name))
	}

	s := &Server{}

	// Parse templates.
	var err error
	s.template.home, err = parse("home.tmpl")
	if err != nil {
		return nil, err
	}
	s.template.index, err = parse("index.tmpl")
	if err != nil {
		return nil, err
	}
	s.template.article, err = parse("article.tmpl")
	if err != nil {
		return nil, err
	}
	p := present.Template().Funcs(funcMap)
	s.template.doc, err = p.ParseFiles(filepath.Join(templatePath, "doc.tmpl"))
	if err != nil {
		return nil, err
	}

	// Load content.
	err = s.loadDocs(filepath.Clean(contentPath))
	if err != nil {
		return nil, err
	}

	err = s.renderAtomFeed()
	if err != nil {
		return nil, err
	}

	err = s.renderJSONFeed()
	if err != nil {
		return nil, err
	}

	// Set up content file server.
	s.content = http.FileServer(http.Dir(contentPath))

	return s, nil
}

var funcMap = template.FuncMap{
	"sectioned": sectioned,
	"authors":   authors,
}

// sectioned returns true if the provided Doc contains more than one section.
// This is used to control whether to display the table of contents and headings.
func sectioned(d *present.Doc) bool {
	return len(d.Sections) > 1
}

// authors returns a comma-separated list of author names.
func authors(authors []present.Author) string {
	var b bytes.Buffer
	last := len(authors) - 1
	for i, a := range authors {
		if i > 0 {
			if i == last {
				b.WriteString(" and ")
			} else {
				b.WriteString(", ")
			}
		}
		b.WriteString(authorName(a))
	}
	return b.String()
}

// authorName returns the first line of the Author text: the author's name.
func authorName(a present.Author) string {
	el := a.TextElem()
	if len(el) == 0 {
		return ""
	}
	text, ok := el[0].(present.Text)
	if !ok || len(text.Lines) == 0 {
		return ""
	}
	return text.Lines[0]
}

// loadDocs reads all content from the provided file system root, renders all
// the articles it finds, adds them to the Server's docs field, computes the
// denormalized docPaths, docTags, and tags fields, and populates the various
// helper fields (Next, Previous, Related) for each Doc.
func (s *Server) loadDocs(root string) error {
	// Read content into docs field.
	const ext = ".article"
	fn := func(p string, info os.FileInfo, err error) error {
		if filepath.Ext(p) != ext {
			return nil
		}
		f, err := os.Open(p)
		if err != nil {
			return err
		}
		defer f.Close()
		d, err := present.Parse(f, p, 0)
		if err != nil {
			return err
		}
		html := new(bytes.Buffer)
		err = d.Render(html, s.template.doc)
		if err != nil {
			return err
		}
		p = p[len(root) : len(p)-len(ext)] // trim root and extension
		s.docs = append(s.docs, &Doc{
			Doc:       d,
			Path:      p,
			Permalink: baseURL + p,
			HTML:      template.HTML(html.String()),
		})
		return nil
	}
	err := filepath.Walk(root, fn)
	if err != nil {
		return err
	}
	sort.Sort(docsByTime(s.docs))

	// Pull out doc paths and tags and put in reverse-associating maps.
	s.docPaths = make(map[string]*Doc)
	s.docTags = make(map[string][]*Doc)
	for _, d := range s.docs {
		s.docPaths[d.Path] = d
		for _, t := range d.Tags {
			s.docTags[t] = append(s.docTags[t], d)
		}
	}

	// Pull out unique sorted list of tags.
	for t := range s.docTags {
		s.tags = append(s.tags, t)
	}
	sort.Strings(s.tags)

	// Set up presentation-related fields, Newer, Older, and Related.
	for _, doc := range s.docs {
		// Newer, Older: docs adjacent to doc
		for i := range s.docs {
			if s.docs[i] != doc {
				continue
			}
			if i > 0 {
				doc.Newer = s.docs[i-1]
			}
			if i+1 < len(s.docs) {
				doc.Older = s.docs[i+1]
			}
			break
		}

		// Related: all docs that share tags with doc.
		related := make(map[*Doc]bool)
		for _, t := range doc.Tags {
			for _, d := range s.docTags[t] {
				if d != doc {
					related[d] = true
				}
			}
		}
		for d := range related {
			doc.Related = append(doc.Related, d)
		}
		sort.Sort(docsByTime(doc.Related))
	}

	return nil
}

// renderAtomFeed generates an XML Atom feed and stores it in the Server's
// atomFeed field.
func (s *Server) renderAtomFeed() error {
	var updated time.Time
	if len(s.docs) > 1 {
		updated = s.docs[0].Time
	}
	feed := atom.Feed{
		Title:   "The Go Programming Language Blog",
		ID:      "tag:" + hostname + ",2013:" + hostname,
		Updated: atom.Time(updated),
		Link: []atom.Link{{
			Rel:  "self",
			Href: baseURL + "/feed.atom",
		}},
	}
	for i, doc := range s.docs {
		if i >= feedArticles {
			break
		}
		e := &atom.Entry{
			Title: doc.Title,
			ID:    feed.ID + doc.Path,
			Link: []atom.Link{{
				Rel:  "alternate",
				Href: baseURL + doc.Path,
			}},
			Published: atom.Time(doc.Time),
			Updated:   atom.Time(doc.Time),
			Summary: &atom.Text{
				Type: "html",
				Body: summary(doc),
			},
			Content: &atom.Text{
				Type: "html",
				Body: string(doc.HTML),
			},
			Author: &atom.Person{
				Name: authors(doc.Authors),
			},
		}
		feed.Entry = append(feed.Entry, e)
	}
	data, err := xml.Marshal(&feed)
	if err != nil {
		return err
	}
	s.atomFeed = data
	return nil
}

type jsonItem struct {
	Title   string
	Link    string
	Time    time.Time
	Summary string
	Content string
	Author  string
}

// renderJSONFeed generates a JSON feed and stores it in the Server's jsonFeed
// field.
func (s *Server) renderJSONFeed() error {
	var feed []jsonItem
	for i, doc := range s.docs {
		if i >= feedArticles {
			break
		}
		item := jsonItem{
			Title:   doc.Title,
			Link:    baseURL + doc.Path,
			Time:    doc.Time,
			Summary: summary(doc),
			Content: string(doc.HTML),
			Author:  authors(doc.Authors),
		}
		feed = append(feed, item)
	}
	data, err := json.Marshal(feed)
	if err != nil {
		return err
	}
	s.jsonFeed = data
	return nil
}

// summary returns the first paragraph of text from the provided Doc.
func summary(d *Doc) string {
	if len(d.Sections) == 0 {
		return ""
	}
	for _, elem := range d.Sections[0].Elem {
		text, ok := elem.(present.Text)
		if !ok || text.Pre {
			// skip everything but non-text elements
			continue
		}
		var buf bytes.Buffer
		for _, s := range text.Lines {
			buf.WriteString(string(present.Style(s)))
			buf.WriteByte('\n')
		}
		return buf.String()
	}
	return ""
}

// rootData encapsulates data destined for the root template.
type rootData struct {
	Doc  *Doc
	Data interface{}
}

// ServeHTTP servers either an article list or a single article.
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	var (
		d rootData
		t *template.Template
	)
	switch p := r.URL.Path; p {
	case "/":
		d.Data = s.docs
		if len(s.docs) > homeArticles {
			d.Data = s.docs[:homeArticles]
		}
		t = s.template.home
	case "/index":
		d.Data = s.docs
		t = s.template.index
	case "/feed.atom", "/feeds/posts/default":
		w.Header().Set("Content-type", "application/atom+xml; charset=utf-8")
		w.Write(s.atomFeed)
		return
	case "/.json":
		if p := r.FormValue("jsonp"); validJSONPFunc.MatchString(p) {
			w.Header().Set("Content-type", "application/javascript; charset=utf-8")
			fmt.Fprintf(w, "%v(%s)", p, s.jsonFeed)
			return
		}
		w.Header().Set("Content-type", "application/json; charset=utf-8")
		w.Write(s.jsonFeed)
		return
	default:
		doc, ok := s.docPaths[p]
		if !ok {
			// Not a doc; try to just serve static content.
			s.content.ServeHTTP(w, r)
			return
		}
		d.Doc = doc
		t = s.template.article
	}
	err := t.ExecuteTemplate(w, "root", d)
	if err != nil {
		log.Println(err)
	}
}

// docsByTime implements sort.Interface, sorting Docs by their Time field.
type docsByTime []*Doc

func (s docsByTime) Len() int           { return len(s) }
func (s docsByTime) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s docsByTime) Less(i, j int) bool { return s[i].Time.After(s[j].Time) }
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"time"

	"github.com/ecc1/medtronic"
	"github.com/ecc1/medtronic/packet"
)

var (
	count            = flag.Int("n", 0, "send only `count` packets")
	minPacketSize    = flag.Int("min", 1, "minimum packet `size` in bytes")
	maxPacketSize    = flag.Int("max", 70, "maximum packet `size` in bytes")
	interPacketDelay = flag.Duration("delay", time.Second, "inter-packet delay")
)

func main() {
	flag.Parse()
	pump := medtronic.Open()
	defer pump.Close()
	n := *minPacketSize
	i := 0
	for pump.Error() == nil {
		if *count != 0 && i == *count {
			return
		}
		data := make([]byte, n+1) // leave space for CRC
		for i := range data {
			data[i] = byte(i + 1)
		}
		packet := packet.Encode(data)
		log.Printf("data:   % X", data)
		log.Printf("packet: % X", packet)
		pump.Radio.Send(packet)
		i++
		n++
		if n > *maxPacketSize {
			n = *minPacketSize
		}
		time.Sleep(*interPacketDelay)
	}
	log.Fatal(pump.Error())
}
<commit_msg>Reuse a single buffer for packets of varying size<commit_after>package main

import (
	"flag"
	"log"
	"time"

	"github.com/ecc1/medtronic"
	"github.com/ecc1/medtronic/packet"
)

var (
	count            = flag.Int("n", 0, "send only `count` packets")
	minPacketSize    = flag.Int("min", 1, "minimum packet `size` in bytes")
	maxPacketSize    = flag.Int("max", 70, "maximum packet `size` in bytes")
	interPacketDelay = flag.Duration("delay", time.Second, "inter-packet delay")
)

func main() {
	flag.Parse()
	pump := medtronic.Open()
	defer pump.Close()
	n := *minPacketSize
	pkts := 0
	data := make([]byte, *maxPacketSize)
	for pump.Error() == nil {
		if *count != 0 && pkts == *count {
			return
		}
		for i := 0; i < n; i++ {
			data[i] = byte(i + 1)
		}
		packet := packet.Encode(data[:n])
		log.Printf("data:   % X", data[:n])
		log.Printf("packet: % X", packet)
		pump.Radio.Send(packet)
		pkts++
		n++
		if n > *maxPacketSize {
			n = *minPacketSize
		}
		time.Sleep(*interPacketDelay)
	}
	log.Fatal(pump.Error())
}
<|endoftext|>


<commit_before>package score

import (
	"encoding/json"
	"errors"
	"strings"
)

// hiddenSecret is used to replace the global secret when parsing.
var hiddenSecret = "hidden"

// ErrScoreNotFound is returned if the parse string did not contain a
// JSON score string.
var ErrScoreNotFound = errors.New("score not found in string")

// Parse returns a score object for the provided JSON string s
// which contains secret.
func Parse(s, secret string) (*Score, error) {
	if strings.Contains(s, secret) {
		var sc Score
		err := json.Unmarshal([]byte(s), &sc)
		if err == nil {
			if sc.Secret == secret {
				sc.Secret = hiddenSecret // overwrite secret
			}
			return &sc, nil
		}
		if strings.Contains(err.Error(), secret) {
			// this is probably not necessary, but to be safe
			return nil, errors.New("error suppressed to avoid revealing secret")
		}
		return nil, err
	}
	return nil, ErrScoreNotFound
}
<commit_msg>added new function to check if string has correct prefix.<commit_after>package score

import (
	"encoding/json"
	"errors"
	"strings"
)

// hiddenSecret is used to replace the global secret when parsing.
var hiddenSecret = "hidden"

// ErrScoreNotFound is returned if the parse string did not contain a
// JSON score string.
var ErrScoreNotFound = errors.New("score not found in string")

// Parse returns a score object for the provided JSON string s
// which contains secret.
func Parse(s, secret string) (*Score, error) {
	if strings.Contains(s, secret) {
		var sc Score
		err := json.Unmarshal([]byte(s), &sc)
		if err == nil {
			if sc.Secret == secret {
				sc.Secret = hiddenSecret // overwrite secret
			}
			return &sc, nil
		}
		if strings.Contains(err.Error(), secret) {
			// this is probably not necessary, but to be safe
			return nil, errors.New("error suppressed to avoid revealing secret")
		}
		return nil, err
	}
	return nil, ErrScoreNotFound
}

// HasPrefix returns true if the provided string s has a parsable prefix string.
func HasPrefix(s string) bool {
	return strings.HasPrefix(s, `{"Secret":`)
}
<|endoftext|>


<commit_before>package mackerel

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"reflect"
	"testing"
)

func TestCreateGraphAnnotation(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
		if req.URL.Path != "/api/v0/graph-annotations" {
			t.Error("request URL should be /api/v0/graph-annotations but :", req.URL.Path)
		}

		if req.Method != "POST" {
			t.Error("request method should be GET but :", req.Method)
		}
		body, _ := ioutil.ReadAll(req.Body)

		var data struct {
			Service     string   `json:"service,omitempty"`
			Roles       []string `json:"roles,omitempty"`
			From        int64    `json:"from,omitempty"`
			To          int64    `json:"to,omitempty"`
			Title       string   `json:"title,omitempty"`
			Description string   `json:"description,omitempty"`
		}

		err := json.Unmarshal(body, &data)
		if err != nil {
			t.Fatal("request body should be decoded as json", string(body))
		}
		if data.Service != "My-Blog" {
			t.Errorf("request sends json including Service but: %s", data.Service)
		}
		if !reflect.DeepEqual(data.Roles, []string{"Role1", "Role2"}) {
			t.Error("request sends json including Roles but: ", data.Roles)
		}
		if data.From != 1485675275 {
			t.Errorf("request sends json including From but: %d", data.From)
		}
		if data.To != 1485675299 {
			t.Errorf("request sends json including To but: %d", data.To)
		}
		if data.Title != "Deployed" {
			t.Errorf("request sends json including Title but: %s", data.Title)
		}
		if data.Description != "Deployed my blog" {
			t.Errorf("request sends json including Description but: %s", data.Description)
		}
		respJSON, _ := json.Marshal(map[string]interface{}{
			"service":     "My-Blog",
			"roles":       []string{"Role1", "Role2"},
			"from":        1485675275,
			"to":          1485675299,
			"title":       "Deployed",
			"description": "Deployed my blog",
		})
		res.Header()["Content-Type"] = []string{"application/json"}
		fmt.Fprint(res, string(respJSON))
	}))
	defer ts.Close()

	client, _ := NewClientWithOptions("dummy-key", ts.URL, false)
	annotation, err := client.CreateGraphAnnotation(&GraphAnnotation{
		Service:     "My-Blog",
		Roles:       []string{"Role1", "Role2"},
		From:        1485675275,
		To:          1485675299,
		Title:       "Deployed",
		Description: "Deployed my blog",
	})

	if err != nil {
		t.Error("err shoud be nil but: ", err)
	}

	if annotation.Service != "My-Blog" {
		t.Error("request sends json including Service but: ", annotation.Service)
	}

	if !reflect.DeepEqual(annotation.Roles, []string{"Role1", "Role2"}) {
		t.Error("request sends json including Roles but: ", annotation.Roles)
	}

	if annotation.From != 1485675275 {
		t.Error("request sends json including From but: ", annotation.From)
	}

	if annotation.To != 1485675299 {
		t.Error("request sends json including To but: ", annotation.To)
	}

	if annotation.Title != "Deployed" {
		t.Error("request sends json including Title but: ", annotation.Title)
	}

	if annotation.Description != "Deployed my blog" {
		t.Error("request sends json including Description but: ", annotation.Description)
	}
}

func TestFindGraphAnnotations(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
		if req.URL.Path != "/api/v0/graph-annotations" {
			t.Error("request URL should be /api/v0/graph-annotations but :", req.URL.Path)
		}
		if req.Method != "GET" {
			t.Error("request method should be GET but :", req.Method)
		}

		query := req.URL.Query()
		if query.Get("service") != "My-Blog" {
			t.Error("request query 'service' param should be My-Blog but :", query.Get("service"))
		}
		if query.Get("from") != "1485675275" {
			t.Error("request query 'from' param should be 1485675275 but :", query.Get("from"))
		}
		if query.Get("to") != "1485675299" {
			t.Error("request query 'from' param should be 1485675299 but :", query.Get("from"))
		}

		respJSON, _ := json.Marshal(map[string][]map[string]interface{}{
			"graphAnnotations": {
				{
					"service":     "My-Blog",
					"roles":       []string{"Role1", "Role2"},
					"from":        1485675275,
					"to":          1485675299,
					"title":       "Deployed",
					"description": "Deployed my blog",
				},
			},
		})

		res.Header()["Content-Type"] = []string{"application/json"}
		fmt.Fprint(res, string(respJSON))
	}))
	defer ts.Close()

	client, _ := NewClientWithOptions("dummy-key", ts.URL, false)
	annotations, err := client.FindGraphAnnotations("My-Blog", 1485675275, 1485675299)

	if err != nil {
		t.Error("err shoud be nil but: ", err)
	}

	if annotations[0].Service != "My-Blog" {
		t.Error("request sends json including Service but: ", annotations[0].Service)
	}

	if !reflect.DeepEqual(annotations[0].Roles, []string{"Role1", "Role2"}) {
		t.Error("request sends json including Roles but: ", annotations[0].Roles)
	}

	if annotations[0].From != 1485675275 {
		t.Error("request sends json including From but: ", annotations[0].From)
	}

	if annotations[0].To != 1485675299 {
		t.Error("request sends json including To but: ", annotations[0].To)
	}

	if annotations[0].Title != "Deployed" {
		t.Error("request sends json including Title but: ", annotations[0].Title)
	}

	if annotations[0].Description != "Deployed my blog" {
		t.Error("request sends json including Description but: ", annotations[0].Description)
	}
}

func TestUpdateGraphAnnotations(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
		if req.URL.Path != "/api/v0/graph-annotations/123456789" {
			t.Error("request URL should be /api/v0/graph-annotations/123456789 but :", req.URL.Path)
		}
		if req.Method != "PUT" {
			t.Error("request method should be PUT but :", req.Method)
		}

		respJSON, _ := json.Marshal(map[string]interface{}{
			"service":     "My-Blog",
			"roles":       []string{"Role1", "Role2"},
			"from":        1485675275,
			"to":          1485675299,
			"title":       "Deployed",
			"description": "Deployed my blog",
		})

		res.Header()["Content-Type"] = []string{"application/json"}
		fmt.Fprint(res, string(respJSON))
	}))
	defer ts.Close()

	client, _ := NewClientWithOptions("dummy-key", ts.URL, false)
	annotation, err := client.UpdateGraphAnnotation("123456789",
		&GraphAnnotation{
			Service:     "My-Blog",
			Roles:       []string{"Role1", "Role2"},
			From:        1485675275,
			To:          1485675299,
			Title:       "Deployed",
			Description: "Deployed my blog",
		})

	if err != nil {
		t.Error("err shoud be nil but: ", err)
	}

	if annotation.Service != "My-Blog" {
		t.Error("request sends json including Service but: ", annotation.Service)
	}

	if !reflect.DeepEqual(annotation.Roles, []string{"Role1", "Role2"}) {
		t.Error("request sends json including Roles but: ", annotation.Roles)
	}

	if annotation.From != 1485675275 {
		t.Error("request sends json including From but: ", annotation.From)
	}

	if annotation.To != 1485675299 {
		t.Error("request sends json including To but: ", annotation.To)
	}

	if annotation.Title != "Deployed" {
		t.Error("request sends json including Title but: ", annotation.Title)
	}

	if annotation.Description != "Deployed my blog" {
		t.Error("request sends json including Description but: ", annotation.Description)
	}
}

func TestDeleteGraphAnnotations(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
		if req.URL.Path != "/api/v0/graph-annotations/123456789" {
			t.Error("request URL should be /api/v0/graph-annotations/123456789 but :", req.URL.Path)
		}
		if req.Method != "DELETE" {
			t.Error("request method should be PUT but :", req.Method)
		}

		respJSON, _ := json.Marshal(map[string]interface{}{
			"service":     "My-Blog",
			"roles":       []string{"Role1", "Role2"},
			"from":        1485675275,
			"to":          1485675299,
			"title":       "Deployed",
			"description": "Deployed my blog",
		})

		res.Header()["Content-Type"] = []string{"application/json"}
		fmt.Fprint(res, string(respJSON))
	}))
	defer ts.Close()

	client, _ := NewClientWithOptions("dummy-key", ts.URL, false)
	annotation, err := client.DeleteGraphAnnotation("123456789")

	if err != nil {
		t.Error("err shoud be nil but: ", err)
	}

	if annotation.Service != "My-Blog" {
		t.Error("request sends json including Service but: ", annotation.Service)
	}

	if !reflect.DeepEqual(annotation.Roles, []string{"Role1", "Role2"}) {
		t.Error("request sends json including Roles but: ", annotation.Roles)
	}

	if annotation.From != 1485675275 {
		t.Error("request sends json including From but: ", annotation.From)
	}

	if annotation.To != 1485675299 {
		t.Error("request sends json including To but: ", annotation.To)
	}

	if annotation.Title != "Deployed" {
		t.Error("request sends json including Title but: ", annotation.Title)
	}

	if annotation.Description != "Deployed my blog" {
		t.Error("request sends json including Description but: ", annotation.Description)
	}
}

func TestDeleteGraphAnnotations_NotFound(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
		if req.URL.Path != "/api/v0/graph-annotations/123456789" {
			t.Error("request URL should be /api/v0/graph-annotations/123456789 but :", req.URL.Path)
		}
		if req.Method != "DELETE" {
			t.Error("request method should be DELETE but: ", req.Method)
		}

		respJSON, _ := json.Marshal(map[string]map[string]string{
			"error": {"message": "Graph annotation not found"},
		})

		res.Header()["Content-Type"] = []string{"application/json"}
		res.WriteHeader(http.StatusNotFound)
		fmt.Fprint(res, string(respJSON))
	}))
	defer ts.Close()

	client, _ := NewClientWithOptions("dummy-key", ts.URL, false)
	_, err := client.DeleteGraphAnnotation("123456789")

	if err == nil {
		t.Error("err should not be nil but: ", err)
	}

	apiErr := err.(*APIError)
	if expected := 404; apiErr.StatusCode != expected {
		t.Errorf("api error StatusCode should be %d but got: %d", expected, apiErr.StatusCode)
	}
	if expected := "API request failed: Graph annotation not found"; apiErr.Error() != expected {
		t.Errorf("api error string should be %s but got: %s", expected, apiErr.Error())
	}
}
<commit_msg>fix spacing in error messages of tests<commit_after>package mackerel

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"reflect"
	"testing"
)

func TestCreateGraphAnnotation(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
		if req.URL.Path != "/api/v0/graph-annotations" {
			t.Error("request URL should be /api/v0/graph-annotations but :", req.URL.Path)
		}

		if req.Method != "POST" {
			t.Error("request method should be GET but :", req.Method)
		}
		body, _ := ioutil.ReadAll(req.Body)

		var data struct {
			Service     string   `json:"service,omitempty"`
			Roles       []string `json:"roles,omitempty"`
			From        int64    `json:"from,omitempty"`
			To          int64    `json:"to,omitempty"`
			Title       string   `json:"title,omitempty"`
			Description string   `json:"description,omitempty"`
		}

		err := json.Unmarshal(body, &data)
		if err != nil {
			t.Fatal("request body should be decoded as json", string(body))
		}
		if data.Service != "My-Blog" {
			t.Errorf("request sends json including Service but: %s", data.Service)
		}
		if !reflect.DeepEqual(data.Roles, []string{"Role1", "Role2"}) {
			t.Error("request sends json including Roles but: ", data.Roles)
		}
		if data.From != 1485675275 {
			t.Errorf("request sends json including From but: %d", data.From)
		}
		if data.To != 1485675299 {
			t.Errorf("request sends json including To but: %d", data.To)
		}
		if data.Title != "Deployed" {
			t.Errorf("request sends json including Title but: %s", data.Title)
		}
		if data.Description != "Deployed my blog" {
			t.Errorf("request sends json including Description but: %s", data.Description)
		}
		respJSON, _ := json.Marshal(map[string]interface{}{
			"service":     "My-Blog",
			"roles":       []string{"Role1", "Role2"},
			"from":        1485675275,
			"to":          1485675299,
			"title":       "Deployed",
			"description": "Deployed my blog",
		})
		res.Header()["Content-Type"] = []string{"application/json"}
		fmt.Fprint(res, string(respJSON))
	}))
	defer ts.Close()

	client, _ := NewClientWithOptions("dummy-key", ts.URL, false)
	annotation, err := client.CreateGraphAnnotation(&GraphAnnotation{
		Service:     "My-Blog",
		Roles:       []string{"Role1", "Role2"},
		From:        1485675275,
		To:          1485675299,
		Title:       "Deployed",
		Description: "Deployed my blog",
	})

	if err != nil {
		t.Error("err shoud be nil but: ", err)
	}

	if annotation.Service != "My-Blog" {
		t.Error("request sends json including Service but: ", annotation.Service)
	}

	if !reflect.DeepEqual(annotation.Roles, []string{"Role1", "Role2"}) {
		t.Error("request sends json including Roles but: ", annotation.Roles)
	}

	if annotation.From != 1485675275 {
		t.Error("request sends json including From but: ", annotation.From)
	}

	if annotation.To != 1485675299 {
		t.Error("request sends json including To but: ", annotation.To)
	}

	if annotation.Title != "Deployed" {
		t.Error("request sends json including Title but: ", annotation.Title)
	}

	if annotation.Description != "Deployed my blog" {
		t.Error("request sends json including Description but: ", annotation.Description)
	}
}

func TestFindGraphAnnotations(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
		if req.URL.Path != "/api/v0/graph-annotations" {
			t.Error("request URL should be /api/v0/graph-annotations but :", req.URL.Path)
		}
		if req.Method != "GET" {
			t.Error("request method should be GET but :", req.Method)
		}

		query := req.URL.Query()
		if query.Get("service") != "My-Blog" {
			t.Error("request query 'service' param should be My-Blog but :", query.Get("service"))
		}
		if query.Get("from") != "1485675275" {
			t.Error("request query 'from' param should be 1485675275 but :", query.Get("from"))
		}
		if query.Get("to") != "1485675299" {
			t.Error("request query 'from' param should be 1485675299 but :", query.Get("from"))
		}

		respJSON, _ := json.Marshal(map[string][]map[string]interface{}{
			"graphAnnotations": {
				{
					"service":     "My-Blog",
					"roles":       []string{"Role1", "Role2"},
					"from":        1485675275,
					"to":          1485675299,
					"title":       "Deployed",
					"description": "Deployed my blog",
				},
			},
		})

		res.Header()["Content-Type"] = []string{"application/json"}
		fmt.Fprint(res, string(respJSON))
	}))
	defer ts.Close()

	client, _ := NewClientWithOptions("dummy-key", ts.URL, false)
	annotations, err := client.FindGraphAnnotations("My-Blog", 1485675275, 1485675299)

	if err != nil {
		t.Error("err shoud be nil but: ", err)
	}

	if annotations[0].Service != "My-Blog" {
		t.Error("request sends json including Service but: ", annotations[0].Service)
	}

	if !reflect.DeepEqual(annotations[0].Roles, []string{"Role1", "Role2"}) {
		t.Error("request sends json including Roles but: ", annotations[0].Roles)
	}

	if annotations[0].From != 1485675275 {
		t.Error("request sends json including From but: ", annotations[0].From)
	}

	if annotations[0].To != 1485675299 {
		t.Error("request sends json including To but: ", annotations[0].To)
	}

	if annotations[0].Title != "Deployed" {
		t.Error("request sends json including Title but: ", annotations[0].Title)
	}

	if annotations[0].Description != "Deployed my blog" {
		t.Error("request sends json including Description but: ", annotations[0].Description)
	}
}

func TestUpdateGraphAnnotations(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
		if req.URL.Path != "/api/v0/graph-annotations/123456789" {
			t.Error("request URL should be /api/v0/graph-annotations/123456789 but :", req.URL.Path)
		}
		if req.Method != "PUT" {
			t.Error("request method should be PUT but :", req.Method)
		}

		respJSON, _ := json.Marshal(map[string]interface{}{
			"service":     "My-Blog",
			"roles":       []string{"Role1", "Role2"},
			"from":        1485675275,
			"to":          1485675299,
			"title":       "Deployed",
			"description": "Deployed my blog",
		})

		res.Header()["Content-Type"] = []string{"application/json"}
		fmt.Fprint(res, string(respJSON))
	}))
	defer ts.Close()

	client, _ := NewClientWithOptions("dummy-key", ts.URL, false)
	annotation, err := client.UpdateGraphAnnotation("123456789",
		&GraphAnnotation{
			Service:     "My-Blog",
			Roles:       []string{"Role1", "Role2"},
			From:        1485675275,
			To:          1485675299,
			Title:       "Deployed",
			Description: "Deployed my blog",
		})

	if err != nil {
		t.Error("err shoud be nil but: ", err)
	}

	if annotation.Service != "My-Blog" {
		t.Error("request sends json including Service but: ", annotation.Service)
	}

	if !reflect.DeepEqual(annotation.Roles, []string{"Role1", "Role2"}) {
		t.Error("request sends json including Roles but: ", annotation.Roles)
	}

	if annotation.From != 1485675275 {
		t.Error("request sends json including From but: ", annotation.From)
	}

	if annotation.To != 1485675299 {
		t.Error("request sends json including To but: ", annotation.To)
	}

	if annotation.Title != "Deployed" {
		t.Error("request sends json including Title but: ", annotation.Title)
	}

	if annotation.Description != "Deployed my blog" {
		t.Error("request sends json including Description but: ", annotation.Description)
	}
}

func TestDeleteGraphAnnotations(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
		if req.URL.Path != "/api/v0/graph-annotations/123456789" {
			t.Error("request URL should be /api/v0/graph-annotations/123456789 but :", req.URL.Path)
		}
		if req.Method != "DELETE" {
			t.Error("request method should be PUT but :", req.Method)
		}

		respJSON, _ := json.Marshal(map[string]interface{}{
			"service":     "My-Blog",
			"roles":       []string{"Role1", "Role2"},
			"from":        1485675275,
			"to":          1485675299,
			"title":       "Deployed",
			"description": "Deployed my blog",
		})

		res.Header()["Content-Type"] = []string{"application/json"}
		fmt.Fprint(res, string(respJSON))
	}))
	defer ts.Close()

	client, _ := NewClientWithOptions("dummy-key", ts.URL, false)
	annotation, err := client.DeleteGraphAnnotation("123456789")

	if err != nil {
		t.Error("err shoud be nil but: ", err)
	}

	if annotation.Service != "My-Blog" {
		t.Error("request sends json including Service but: ", annotation.Service)
	}

	if !reflect.DeepEqual(annotation.Roles, []string{"Role1", "Role2"}) {
		t.Error("request sends json including Roles but: ", annotation.Roles)
	}

	if annotation.From != 1485675275 {
		t.Error("request sends json including From but: ", annotation.From)
	}

	if annotation.To != 1485675299 {
		t.Error("request sends json including To but: ", annotation.To)
	}

	if annotation.Title != "Deployed" {
		t.Error("request sends json including Title but: ", annotation.Title)
	}

	if annotation.Description != "Deployed my blog" {
		t.Error("request sends json including Description but: ", annotation.Description)
	}
}

func TestDeleteGraphAnnotations_NotFound(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
		if req.URL.Path != "/api/v0/graph-annotations/123456789" {
			t.Error("request URL should be /api/v0/graph-annotations/123456789 but: ", req.URL.Path)
		}
		if req.Method != "DELETE" {
			t.Error("request method should be DELETE but: ", req.Method)
		}

		respJSON, _ := json.Marshal(map[string]map[string]string{
			"error": {"message": "Graph annotation not found"},
		})

		res.Header()["Content-Type"] = []string{"application/json"}
		res.WriteHeader(http.StatusNotFound)
		fmt.Fprint(res, string(respJSON))
	}))
	defer ts.Close()

	client, _ := NewClientWithOptions("dummy-key", ts.URL, false)
	_, err := client.DeleteGraphAnnotation("123456789")

	if err == nil {
		t.Error("err should not be nil but: ", err)
	}

	apiErr := err.(*APIError)
	if expected := 404; apiErr.StatusCode != expected {
		t.Errorf("api error StatusCode should be %d but got: %d", expected, apiErr.StatusCode)
	}
	if expected := "API request failed: Graph annotation not found"; apiErr.Error() != expected {
		t.Errorf("api error string should be %s but got: %s", expected, apiErr.Error())
	}
}
<|endoftext|>


<commit_before>package graphite

import (
	"bufio"
	"log"
	"net"
	"os"
	"strings"
	"sync"

	"github.com/influxdb/influxdb"
)

// TCPServer processes Graphite data received over TCP connections.
type TCPServer struct {
	writer   SeriesWriter
	parser   *Parser
	database string
	listener *net.Listener

	done chan struct{}
	wg   sync.WaitGroup

	Logger *log.Logger
}

// NewTCPServer returns a new instance of a TCPServer.
func NewTCPServer(p *Parser, w SeriesWriter, db string) *TCPServer {
	return &TCPServer{
		parser:   p,
		writer:   w,
		database: db,
		Logger:   log.New(os.Stderr, "[graphite] ", log.LstdFlags),
		done:     make(chan struct{}),
	}
}

// ListenAndServe instructs the TCPServer to start processing Graphite data
// on the given interface. iface must be in the form host:port
func (t *TCPServer) ListenAndServe(iface string) error {
	if iface == "" { // Make sure we have an address
		return ErrBindAddressRequired
	}

	ln, err := net.Listen("tcp", iface)
	if err != nil {
		return err
	}
	t.listener = &ln

	t.Logger.Println("listening on TCP connection", ln.Addr().String())
	t.wg.Add(1)
	go func() {
		defer t.wg.Done()
		for {
			select {
			case <-t.done:
				return
			default:
				// Keep processing.
			}
			conn, err := ln.Accept()
			if err != nil {
				t.Logger.Println("error accepting TCP connection", err.Error())
				continue
			}

			t.wg.Add(1)
			go t.handleConnection(conn)
		}
	}()
	return nil
}

func (t *TCPServer) Host() string {
	l := *t.listener
	return l.Addr().String()
}

func (t *TCPServer) Close() error {
	close(t.done)
	t.wg.Wait()
	t.done = nil

	if t.listener != nil {
		l := *t.listener
		err := l.Close()
		t.listener = nil
		return err
	} else {
		return nil
	}
}

// handleConnection services an individual TCP connection.
func (t *TCPServer) handleConnection(conn net.Conn) {
	defer conn.Close()
	defer t.wg.Done()

	reader := bufio.NewReader(conn)
	for {
		select {
		case <-t.done:
			log.Println("disconnecting", conn.RemoteAddr())
			return
		default:
		}

		// Read up to the next newline.
		buf, err := reader.ReadBytes('\n')
		if err != nil {
			return
		}

		// Trim the buffer, even though there should be no padding
		line := strings.TrimSpace(string(buf))

		// Parse it.
		point, err := t.parser.Parse(line)
		if err != nil {
			t.Logger.Printf("unable to parse data: %s", err)
			continue
		}

		// Send the data to the writer.
		_, e := t.writer.WriteSeries(t.database, "", []influxdb.Point{point})
		if e != nil {
			t.Logger.Printf("failed to write data point to database %q: %s\n", t.database, e)
		}
	}
}
<commit_msg>ust use Wait Groups to shutdown Graphite<commit_after>package graphite

import (
	"bufio"
	"log"
	"net"
	"os"
	"strings"
	"sync"

	"github.com/influxdb/influxdb"
)

// TCPServer processes Graphite data received over TCP connections.
type TCPServer struct {
	writer   SeriesWriter
	parser   *Parser
	database string
	listener *net.Listener

	wg sync.WaitGroup

	Logger *log.Logger
}

// NewTCPServer returns a new instance of a TCPServer.
func NewTCPServer(p *Parser, w SeriesWriter, db string) *TCPServer {
	return &TCPServer{
		parser:   p,
		writer:   w,
		database: db,
		Logger:   log.New(os.Stderr, "[graphite] ", log.LstdFlags),
	}
}

// ListenAndServe instructs the TCPServer to start processing Graphite data
// on the given interface. iface must be in the form host:port
func (t *TCPServer) ListenAndServe(iface string) error {
	if iface == "" { // Make sure we have an address
		return ErrBindAddressRequired
	}

	ln, err := net.Listen("tcp", iface)
	if err != nil {
		return err
	}
	t.listener = &ln

	t.Logger.Println("listening on TCP connection", ln.Addr().String())
	t.wg.Add(1)
	go func() {
		defer t.wg.Done()
		for {
			conn, err := ln.Accept()
			if err != nil {
				t.Logger.Println("error accepting TCP connection", err.Error())
				return
			}

			t.wg.Add(1)
			go t.handleConnection(conn)
		}
	}()
	return nil
}

func (t *TCPServer) Host() string {
	l := *t.listener
	return l.Addr().String()
}

func (t *TCPServer) Close() error {
	var err error
	if t.listener != nil {
		err = (*t.listener).Close()
	}
	t.wg.Wait()
	t.listener = nil
	return err
}

// handleConnection services an individual TCP connection.
func (t *TCPServer) handleConnection(conn net.Conn) {
	defer conn.Close()
	defer t.wg.Done()

	reader := bufio.NewReader(conn)
	for {
		// Read up to the next newline.
		buf, err := reader.ReadBytes('\n')
		if err != nil {
			return
		}

		// Trim the buffer, even though there should be no padding
		line := strings.TrimSpace(string(buf))

		// Parse it.
		point, err := t.parser.Parse(line)
		if err != nil {
			t.Logger.Printf("unable to parse data: %s", err)
			continue
		}

		// Send the data to the writer.
		_, e := t.writer.WriteSeries(t.database, "", []influxdb.Point{point})
		if e != nil {
			t.Logger.Printf("failed to write data point to database %q: %s\n", t.database, e)
		}
	}
}
<|endoftext|>


<commit_before>package main

import "gitlab.informatik.haw-hamburg.de/icc/gl-k8s-integrator/graylog"

func main() {
	graylog.DeleteAllRulesForAllStreams()
}

<commit_msg>deleted 2nd main instance<commit_after><|endoftext|>


<commit_before>// Package sixbit implements a 6-bit ASCII encoding.
package sixbit

import (
	"fmt"
)

// EncodedLen returns the encoded length (in bytes) of text in 6-bit ASCII.
func EncodedLen(text []byte) (int, error) {
	var chars int
	for _, c := range text {
		if 32 <= c && c <= 95 {
			chars++
		} else {
			return 0, fmt.Errorf("sixbit: cannot encode '%c' as 6-bit ASCII", c)
		}
	}
	bytes := chars * 6 / 8
	if chars*6%8 > 0 {
		return bytes + 1, nil
	}
	return bytes, nil
}

// Encode text in 6-bit ASCII (one byte per character).
func Encode(text []byte) ([]byte, error) {
	buf := make([]byte, len(text))
	for i, c := range text {
		if 32 <= c && c <= 95 {
			buf[i] = c - 32
		} else {
			return nil, fmt.Errorf("sixbit: cannot encode '%c' as 6-bit ASCII", c)
		}
	}
	return buf, nil
}

// DecodeChar decodes a single 6-bit encode character.
func DecodeChar(c byte) (byte, error) {
	switch {
	case c < 64:
		return c + 32, nil
	default:
		return 0, fmt.Errorf("sixbit: %d is not a 6-bit character", c)
	}
}
<commit_msg>sixbit: switch to code used in AIS<commit_after>// Package sixbit implements a 6-bit ASCII encoding.
package sixbit

import (
	"fmt"
)

// EncodedLen returns the encoded length (in bytes) of text in 6-bit ASCII.
func EncodedLen(text []byte) (int, error) {
	var chars int
	for _, c := range text {
		if 32 <= c && c <= 95 {
			chars++
		} else {
			return 0, fmt.Errorf("sixbit: cannot encode '%c' as 6-bit ASCII", c)
		}
	}
	bytes := chars * 6 / 8
	if chars*6%8 > 0 {
		return bytes + 1, nil
	}
	return bytes, nil
}

// Encode text in 6-bit ASCII (one byte per character).
func Encode(text []byte) ([]byte, error) {
	buf := make([]byte, len(text))
	for i, c := range text {
		if 32 <= c && c < 64 {
			buf[i] = c
		} else if 64 <= c && c <= 95 {
			buf[i] = c - 64
		} else {
			return nil, fmt.Errorf("sixbit: cannot encode '%c' as 6-bit ASCII", c)
		}
	}
	return buf, nil
}

// DecodeChar decodes a single 6-bit encode character.
func DecodeChar(c byte) (byte, error) {
	switch {
	case c < 32:
		return c + 64, nil
	case c < 64:
		return c, nil
	default:
		return 0, fmt.Errorf("sixbit: %d is not a 6-bit character", c)
	}
}
<|endoftext|>


<commit_before>package raft

import (
	"encoding/json"
	golog "log"
)

type Interface interface {
	Step(m Message)
	Msgs() []Message
}

type tick int

type config struct {
	NodeId  int
	Address string
}

type Node struct {
	// election timeout and heartbeat timeout in tick
	election  tick
	heartbeat tick

	// elapsed ticks after the last reset
	elapsed tick
	sm      *stateMachine
}

func New(id int, heartbeat, election tick) *Node {
	if election < heartbeat*3 {
		panic("election is least three times as heartbeat [election: %d, heartbeat: %d]")
	}

	n := &Node{
		heartbeat: heartbeat,
		election:  election,
		sm:        newStateMachine(id, []int{id}),
	}

	return n
}

func Dictate(n *Node) *Node {
	n.Step(Message{Type: msgHup})
	n.Add(n.Id())
	return n
}

func (n *Node) Id() int { return n.sm.id }

// Propose asynchronously proposes data be applied to the underlying state machine.
func (n *Node) Propose(data []byte) { n.propose(normal, data) }

func (n *Node) propose(t int, data []byte) {
	n.Step(Message{Type: msgProp, Entries: []Entry{{Type: t, Data: data}}})
}

func (n *Node) Add(id int) { n.updateConf(configAdd, &config{NodeId: id}) }

func (n *Node) Remove(id int) { n.updateConf(configRemove, &config{NodeId: id}) }

func (n *Node) Msgs() []Message { return n.sm.Msgs() }

func (n *Node) Step(m Message) {
	l := len(n.sm.msgs)
	n.sm.Step(m)
	for _, m := range n.sm.msgs[l:] {
		// reset elapsed in two cases:
		// msgAppResp -> heard from the leader of the same term
		// msgVoteResp with grant -> heard from the candidate the node voted for
		switch m.Type {
		case msgAppResp:
			n.elapsed = 0
		case msgVoteResp:
			if m.Index >= 0 {
				n.elapsed = 0
			}
		}
	}
}

// Next applies all available committed commands.
func (n *Node) Next() []Entry {
	ents := n.sm.nextEnts()
	nents := make([]Entry, 0)
	for i := range ents {
		switch ents[i].Type {
		case normal:
			// dispatch to the application state machine
			nents = append(nents, ents[i])
		case configAdd:
			c := new(config)
			if err := json.Unmarshal(ents[i].Data, c); err != nil {
				golog.Println(err)
				continue
			}
			n.sm.Add(c.NodeId)
		case configRemove:
			c := new(config)
			if err := json.Unmarshal(ents[i].Data, c); err != nil {
				golog.Println(err)
				continue
			}
			n.sm.Remove(c.NodeId)
		default:
			panic("unexpected entry type")
		}
	}
	return nents
}

// Tick triggers the node to do a tick.
// If the current elapsed is greater or equal than the timeout,
// node will send corresponding message to the statemachine.
func (n *Node) Tick() {
	timeout, msgType := n.election, msgHup
	if n.sm.state == stateLeader {
		timeout, msgType = n.heartbeat, msgBeat
	}
	if n.elapsed >= timeout {
		n.Step(Message{Type: msgType})
		n.elapsed = 0
	} else {
		n.elapsed++
	}
}

func (n *Node) updateConf(t int, c *config) {
	data, err := json.Marshal(c)
	if err != nil {
		panic(err)
	}
	n.propose(t, data)
}
<commit_msg>raft: return all the appliable entries<commit_after>package raft

import (
	"encoding/json"
	golog "log"
)

type Interface interface {
	Step(m Message)
	Msgs() []Message
}

type tick int

type config struct {
	NodeId  int
	Address string
}

type Node struct {
	// election timeout and heartbeat timeout in tick
	election  tick
	heartbeat tick

	// elapsed ticks after the last reset
	elapsed tick
	sm      *stateMachine
}

func New(id int, heartbeat, election tick) *Node {
	if election < heartbeat*3 {
		panic("election is least three times as heartbeat [election: %d, heartbeat: %d]")
	}

	n := &Node{
		heartbeat: heartbeat,
		election:  election,
		sm:        newStateMachine(id, []int{id}),
	}

	return n
}

func Dictate(n *Node) *Node {
	n.Step(Message{Type: msgHup})
	n.Add(n.Id())
	return n
}

func (n *Node) Id() int { return n.sm.id }

// Propose asynchronously proposes data be applied to the underlying state machine.
func (n *Node) Propose(data []byte) { n.propose(normal, data) }

func (n *Node) propose(t int, data []byte) {
	n.Step(Message{Type: msgProp, Entries: []Entry{{Type: t, Data: data}}})
}

func (n *Node) Add(id int) { n.updateConf(configAdd, &config{NodeId: id}) }

func (n *Node) Remove(id int) { n.updateConf(configRemove, &config{NodeId: id}) }

func (n *Node) Msgs() []Message { return n.sm.Msgs() }

func (n *Node) Step(m Message) {
	l := len(n.sm.msgs)
	n.sm.Step(m)
	for _, m := range n.sm.msgs[l:] {
		// reset elapsed in two cases:
		// msgAppResp -> heard from the leader of the same term
		// msgVoteResp with grant -> heard from the candidate the node voted for
		switch m.Type {
		case msgAppResp:
			n.elapsed = 0
		case msgVoteResp:
			if m.Index >= 0 {
				n.elapsed = 0
			}
		}
	}
}

// Next applies all available committed commands.
func (n *Node) Next() []Entry {
	ents := n.sm.nextEnts()
	for i := range ents {
		switch ents[i].Type {
		case normal:
		case configAdd:
			c := new(config)
			if err := json.Unmarshal(ents[i].Data, c); err != nil {
				golog.Println(err)
				continue
			}
			n.sm.Add(c.NodeId)
		case configRemove:
			c := new(config)
			if err := json.Unmarshal(ents[i].Data, c); err != nil {
				golog.Println(err)
				continue
			}
			n.sm.Remove(c.NodeId)
		default:
			panic("unexpected entry type")
		}
	}
	return ents
}

// Tick triggers the node to do a tick.
// If the current elapsed is greater or equal than the timeout,
// node will send corresponding message to the statemachine.
func (n *Node) Tick() {
	timeout, msgType := n.election, msgHup
	if n.sm.state == stateLeader {
		timeout, msgType = n.heartbeat, msgBeat
	}
	if n.elapsed >= timeout {
		n.Step(Message{Type: msgType})
		n.elapsed = 0
	} else {
		n.elapsed++
	}
}

func (n *Node) updateConf(t int, c *config) {
	data, err := json.Marshal(c)
	if err != nil {
		panic(err)
	}
	n.propose(t, data)
}
<|endoftext|>


<commit_before>// Copyright 2013 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package service

import (
	"errors"
	"github.com/globocom/tsuru/action"
)

// createServiceInstance in an action that calls the service endpoint
// to creates the service instance.
//
// The first argument in the context must be an Service.
// The second argument in the context must be an ServiceInstance.
var createServiceInstance = action.Action{
	Name: "create-service-instance",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		var (
			service  Service
			instance ServiceInstance
		)
		switch ctx.Params[0].(type) {
		case Service:
			service = ctx.Params[0].(Service)
		default:
			return nil, errors.New("First parameter must be a Service.")
		}
		switch ctx.Params[1].(type) {
		case ServiceInstance:
			instance = ctx.Params[1].(ServiceInstance)
		default:
			return nil, errors.New("Second parameter must be a ServiceInstance.")
		}
		endpoint, err := service.getClient("production")
		if err != nil {
			return nil, err
		}
		err = endpoint.Create(&instance)
		if err != nil {
			return nil, err
		}
		return instance, nil
	},
	Backward: func(ctx action.BWContext) {
		service, ok := ctx.Params[0].(Service)
		if !ok {
			return
		}
		endpoint, err := service.getClient("production")
		if err != nil {
			return
		}
		instance, ok := ctx.Params[1].(ServiceInstance)
		if !ok {
			return
		}
		endpoint.Destroy(&instance)
	},
	MinParams: 2,
}
<commit_msg>service: refactoring create service instance foward.<commit_after>// Copyright 2013 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package service

import (
	"errors"
	"github.com/globocom/tsuru/action"
)

// createServiceInstance in an action that calls the service endpoint
// to creates the service instance.
//
// The first argument in the context must be an Service.
// The second argument in the context must be an ServiceInstance.
var createServiceInstance = action.Action{
	Name: "create-service-instance",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		service, ok := ctx.Params[0].(Service)
		if !ok {
			return nil, errors.New("First parameter must be a Service.")
		}
		endpoint, err := service.getClient("production")
		if err != nil {
			return nil, err
		}
		instance, ok := ctx.Params[1].(ServiceInstance)
		if !ok {
			return nil, errors.New("Second parameter must be a ServiceInstance.")
		}
		err = endpoint.Create(&instance)
		if err != nil {
			return nil, err
		}
		return instance, nil
	},
	Backward: func(ctx action.BWContext) {
		service, ok := ctx.Params[0].(Service)
		if !ok {
			return
		}
		endpoint, err := service.getClient("production")
		if err != nil {
			return
		}
		instance, ok := ctx.Params[1].(ServiceInstance)
		if !ok {
			return
		}
		endpoint.Destroy(&instance)
	},
	MinParams: 2,
}
<|endoftext|>


<commit_before>package services

import (
	"github.com/pufferpanel/pufferpanel/database"
	"github.com/pufferpanel/pufferpanel/models"
	"github.com/pufferpanel/pufferpanel/models/view"
	o2 "github.com/pufferpanel/pufferpanel/oauth2"
	"gopkg.in/oauth2.v3/errors"
	"gopkg.in/oauth2.v3/manage"
	"gopkg.in/oauth2.v3/server"
	"log"
	"net/http"
)

type OAuthService interface {
	HandleHTTPTokenRequest(writer http.ResponseWriter, request *http.Request)

	GetInfo(token string) (info *view.OAuthTokenInfoViewModel, valid bool, err error)

	Create(user *models.User, server *models.Server, clientId string) (clientSecret string, err error)

	UpdateScopes(clientId string, scopes []string) (err error)

	Delete(clientId string) (err error)

	GetByClientId(clientId string) (client *models.ClientInfo, err error)

	GetByUserServer(user *models.User, server *models.Server) (client *models.ClientInfo, err error)
}

type oauthService struct {
	server *server.Server
}

var _oauthService *oauthService

func GetOAuthService() (service OAuthService, err error) {
	if _oauthService == nil {
		err = configureServer()
	}
	return _oauthService, err
}

func configureServer() error {
	manager := manage.NewDefaultManager()
	manager.MapClientStorage(&o2.ClientStore{})
	manager.MapTokenStorage(&o2.TokenStore{})

	srv := server.NewServer(server.NewConfig(), manager)
	srv.SetClientInfoHandler(server.ClientFormHandler)

	srv.SetInternalErrorHandler(func(err error) (re *errors.Response) {
		log.Println("Internal Error:", err.Error())
		return
	})

	srv.SetResponseErrorHandler(func(re *errors.Response) {
		log.Println("Response Error:", re.Error.Error())
	})

	_oauthService = &oauthService{server: srv}
	return nil
}

func (oauth2 *oauthService) HandleHTTPTokenRequest(writer http.ResponseWriter, request *http.Request) {
	err := oauth2.server.HandleTokenRequest(writer, request)
	if err != nil {
		http.Error(writer, err.Error(), http.StatusInternalServerError)
	}
}

func (oauth2 *oauthService) GetInfo(token string) (info *view.OAuthTokenInfoViewModel, valid bool, err error) {
	ts := &o2.TokenStore{}
	info = &view.OAuthTokenInfoViewModel{Active: false}

	item, err := ts.GetByAccess(token)

	if err != nil {
		return
	}

	db, err := database.GetConnection()
	if err != nil {
		return
	}

	client := &models.ClientInfo{
		ClientID: item.GetClientID(),
	}
	err = db.Set("gorm:auto_preload", true).Where(client).First(client).Error
	if err != nil {
		return
	}

	//see if the access token expiration is after now
	info = view.FromTokenInfo(item, client)
	valid = info.Active

	return
}

func (oauth2 *oauthService) Create(user *models.User, server *models.Server, clientId string) (clientSecret string, err error) {
	return
}

func (oauth2 *oauthService) UpdateScopes(clientId string, scopes []string) (err error) {
	return
}

func (oauth2 *oauthService) Delete(clientId string) (err error) {
	return
}

func (oauth2 *oauthService) GetByClientId(clientId string) (client *models.ClientInfo, err error) {
	return
}

func (oauth2 *oauthService) GetByUserServer(user *models.User, server *models.Server) (client *models.ClientInfo, err error) {
	return
}
<commit_msg>Add some other stuff<commit_after>package services

import (
	"github.com/pufferpanel/pufferpanel/database"
	"github.com/pufferpanel/pufferpanel/models"
	"github.com/pufferpanel/pufferpanel/models/view"
	o2 "github.com/pufferpanel/pufferpanel/oauth2"
	"gopkg.in/oauth2.v3/errors"
	"gopkg.in/oauth2.v3/manage"
	"gopkg.in/oauth2.v3/server"
	"log"
	"net/http"
)

type OAuthService interface {
	HandleHTTPTokenRequest(writer http.ResponseWriter, request *http.Request)

	GetInfo(token string) (info *view.OAuthTokenInfoViewModel, valid bool, err error)

	Create(user *models.User, server *models.Server, clientId string) (clientSecret string, err error)

	UpdateScopes(client *models.ClientInfo, server *models.Server, scopes []string) (err error)

	Delete(clientId string) (err error)

	GetByClientId(clientId string) (client *models.ClientInfo, exists bool, err error)

	GetByUser(user *models.User) (client *models.ClientInfo, exists bool, err error)
}

type oauthService struct {
	server *server.Server
}

var _oauthService *oauthService

func GetOAuthService() (service OAuthService, err error) {
	if _oauthService == nil {
		err = configureServer()
	}
	return _oauthService, err
}

func configureServer() error {
	manager := manage.NewDefaultManager()
	manager.MapClientStorage(&o2.ClientStore{})
	manager.MapTokenStorage(&o2.TokenStore{})

	srv := server.NewServer(server.NewConfig(), manager)
	srv.SetClientInfoHandler(server.ClientFormHandler)

	srv.SetInternalErrorHandler(func(err error) (re *errors.Response) {
		log.Println("Internal Error:", err.Error())
		return
	})

	srv.SetResponseErrorHandler(func(re *errors.Response) {
		log.Println("Response Error:", re.Error.Error())
	})

	_oauthService = &oauthService{server: srv}
	return nil
}

func (oauth2 *oauthService) HandleHTTPTokenRequest(writer http.ResponseWriter, request *http.Request) {
	err := oauth2.server.HandleTokenRequest(writer, request)
	if err != nil {
		http.Error(writer, err.Error(), http.StatusInternalServerError)
	}
}

func (oauth2 *oauthService) GetInfo(token string) (info *view.OAuthTokenInfoViewModel, valid bool, err error) {
	ts := &o2.TokenStore{}
	info = &view.OAuthTokenInfoViewModel{Active: false}

	item, err := ts.GetByAccess(token)

	if err != nil {
		return
	}

	db, err := database.GetConnection()
	if err != nil {
		return
	}

	client := &models.ClientInfo{
		ClientID: item.GetClientID(),
	}
	err = db.Set("gorm:auto_preload", true).Where(client).First(client).Error
	if err != nil {
		return
	}

	//see if the access token expiration is after now
	info = view.FromTokenInfo(item, client)
	valid = info.Active

	return
}

func (oauth2 *oauthService) Create(user *models.User, server *models.Server, clientId string) (clientSecret string, err error) {
	return
}

func (oauth2 *oauthService) UpdateScopes(client *models.ClientInfo, server *models.Server, scopes []string) (err error) {
	db, err := database.GetConnection()
	if err != nil {
		return err
	}

	deleteIds := make([]int, 0)
	for k, v := range client.ServerScopes {
		if v.Server.ID == server.ID {
			deleteIds = append(deleteIds, k)
		}
	}

	for index := len(deleteIds) - 1; index >= 0; index-- {
		client.ServerScopes = append(client.ServerScopes[:index], client.ServerScopes[index+1:]...)
	}

	//re-add new values
	for _, v := range scopes {
		replacement := &models.ClientServerScopes{
			ServerId: server.ID,
			Scope: v,
			ClientInfoID: client.ID,
		}

		db.Create(replacement)
		client.ServerScopes = append(client.ServerScopes, *replacement)
	}

	db.Save(client)

	return
}

func (oauth2 *oauthService) Delete(clientId string) (err error) {
	db, err := database.GetConnection()
	if err != nil {
		return err
	}

	model := &models.ClientInfo{ClientID: clientId}

	return db.Delete(model).Error
}

func (oauth2 *oauthService) GetByClientId(clientId string) (client *models.ClientInfo, exists bool, err error) {
	db, err := database.GetConnection()
	if err != nil {
		return nil, false, err
	}

	model := &models.ClientInfo{ClientID: clientId}

	res := db.Where(model).First(model)

	return model, model.ID != 0, res.Error
}

func (oauth2 *oauthService) GetByUser(user *models.User) (client *models.ClientInfo, exists bool, err error) {
	db, err := database.GetConnection()
	if err != nil {
		return nil, false, err
	}

	model := &models.ClientInfo{UserID: user.ID}

	res := db.Where(model).First(model)

	return model, model.ID != 0, res.Error
}
<|endoftext|>


<commit_before>package ratt

import (
	"github.com/fabioxgn/go-bot"
	"math/rand"
	"regexp"
)

var (
	re          = regexp.MustCompile("(?i)\\b(ratt)\\b")
	ratt_lyrics = []string{
		"What goes around comes around",
		"Dance dance dance",
		"Round and round",
		"You should know, by now",
	}
)

func ratt(command *bot.PassiveCmd) (msg string, err error) {
	if re.MatchString(command.Raw) {
		return ratt_lyrics[rand.Intn(len(ratt_lyrics))], nil
	}
	return "", nil
}

func init() {
	bot.RegisterCommand("ratt", "Spouts out lyrics from the band Ratt", "whatever", ratt)
}
<commit_msg>Wrong command<commit_after>package ratt

import (
	"github.com/fabioxgn/go-bot"
	"math/rand"
	"regexp"
)

var (
	re          = regexp.MustCompile("(?i)\\b(ratt)\\b")
	ratt_lyrics = []string{
		"What goes around comes around",
		"Dance dance dance",
		"Round and round",
		"You should know, by now",
	}
)

func ratt(command *bot.PassiveCmd) (msg string, err error) {
	if re.MatchString(command.Raw) {
		return ratt_lyrics[rand.Intn(len(ratt_lyrics))], nil
	}
	return "", nil
}

func init() {
	bot.RegisterPassiveCommand("ratt", ratt)
}
<|endoftext|>


<commit_before>package session

import (
	"fmt"
	"io"
	"kmud/database"
	"kmud/model"
	"kmud/utils"
	"labix.org/v2/mgo/bson"
	"log"
	"os"
	"strings"
	"time"
)

type Session struct {
	conn   io.ReadWriter
	user   *database.User
	player *database.Character
	room   *database.Room
	zone   *database.Zone

	userInputChannel chan string
	promptChannel    chan string
	inputModeChannel chan userInputMode
	panicChannel     chan interface{}
	eventChannel     chan model.Event

	logger *log.Logger
}

func NewSession(conn io.ReadWriter, user *database.User, player *database.Character) Session {
	var session Session
	session.conn = conn
	session.user = user
	session.player = player
	session.room = model.M.GetRoom(player.GetRoomId())
	session.zone = model.M.GetZone(session.room.GetZoneId())

	session.userInputChannel = make(chan string)
	session.promptChannel = make(chan string)
	session.inputModeChannel = make(chan userInputMode)
	session.panicChannel = make(chan interface{})
	session.eventChannel = model.Register(session.player)

	file, err := os.OpenFile(player.PrettyName()+".log", os.O_WRONLY|os.O_TRUNC|os.O_CREATE, os.ModePerm)
	utils.PanicIfError(err)

	session.logger = log.New(file, player.PrettyName()+" ", log.LstdFlags)

	return session
}

type userInputMode int

const (
	CleanUserInput userInputMode = iota
	RawUserInput   userInputMode = iota
)

func toggleExitMenu(cm utils.ColorMode, room *database.Room) utils.Menu {
	onOrOff := func(direction database.ExitDirection) string {
		text := "Off"
		if room.HasExit(direction) {
			text = "On"
		}
		return utils.Colorize(cm, utils.ColorBlue, text)
	}

	menu := utils.NewMenu("Edit Exits")

	menu.AddAction("n", "[N]orth: "+onOrOff(database.DirectionNorth))
	menu.AddAction("ne", "[NE]North East: "+onOrOff(database.DirectionNorthEast))
	menu.AddAction("e", "[E]ast: "+onOrOff(database.DirectionEast))
	menu.AddAction("se", "[SE]South East: "+onOrOff(database.DirectionSouthEast))
	menu.AddAction("s", "[S]outh: "+onOrOff(database.DirectionSouth))
	menu.AddAction("sw", "[SW]South West: "+onOrOff(database.DirectionSouthWest))
	menu.AddAction("w", "[W]est: "+onOrOff(database.DirectionWest))
	menu.AddAction("nw", "[NW]North West: "+onOrOff(database.DirectionNorthWest))
	menu.AddAction("u", "[U]p: "+onOrOff(database.DirectionUp))
	menu.AddAction("d", "[D]own: "+onOrOff(database.DirectionDown))

	return menu
}

func npcMenu(room *database.Room) utils.Menu {
	npcs := model.M.NpcsIn(room)

	menu := utils.NewMenu("NPCs")

	menu.AddAction("n", "[N]ew")

	for i, npc := range npcs {
		index := i + 1
		actionText := fmt.Sprintf("[%v]%v", index, npc.PrettyName())
		menu.AddActionData(index, actionText, npc.GetId())
	}

	return menu
}

func specificNpcMenu(npcId bson.ObjectId) utils.Menu {
	npc := model.M.GetCharacter(npcId)
	menu := utils.NewMenu(npc.PrettyName())
	menu.AddAction("r", "[R]ename")
	menu.AddAction("d", "[D]elete")
	menu.AddAction("c", "[C]onversation")
	return menu
}

func (session *Session) Exec() {
	defer model.Unregister(session.eventChannel)

	session.printLineColor(utils.ColorWhite, "Welcome, "+session.player.PrettyName())
	session.printRoom()

	// Main routine in charge of actually reading input from the connection object,
	// also has built in throttling to limit how fast we are allowed to process
	// commands from the user.
	go func() {
		defer func() {
			if r := recover(); r != nil {
				session.panicChannel <- r
			}
		}()

		lastTime := time.Now()

		delay := time.Duration(200) * time.Millisecond

		for {
			mode := <-session.inputModeChannel
			prompt := utils.Colorize(session.user.GetColorMode(), utils.ColorWhite, <-session.promptChannel)
			input := ""

			switch mode {
			case CleanUserInput:
				input = utils.GetUserInput(session.conn, prompt)
			case RawUserInput:
				input = utils.GetRawUserInput(session.conn, prompt)
			default:
				panic("Unhandled case in switch statement (userInputMode)")
			}

			diff := time.Since(lastTime)

			if diff < delay {
				time.Sleep(delay - diff)
			}

			session.userInputChannel <- input
			lastTime = time.Now()
		}
	}()

	// Main loop
	for {
		input := session.getUserInput(RawUserInput, prompt())
		if input == "" || input == "logout" {
			return
		}
		if strings.HasPrefix(input, "/") {
			session.handleCommand(utils.Argify(input[1:]))
		} else {
			session.handleAction(utils.Argify(input))
		}
	}
}

func (session *Session) printString(data string) {
	io.WriteString(session.conn, data)
}

func (session *Session) printLineColor(color utils.Color, line string, a ...interface{}) {
	utils.WriteLine(session.conn, utils.Colorize(session.user.GetColorMode(), color, fmt.Sprintf(line, a...)))
}

func (session *Session) printLine(line string, a ...interface{}) {
	session.printLineColor(utils.ColorWhite, line, a...)
}

func (session *Session) printError(err string, a ...interface{}) {
	session.printLineColor(utils.ColorRed, err, a...)
}

func (session *Session) printRoom() {
	playerList := model.M.PlayersIn(session.room, session.player)
	npcList := model.M.NpcsIn(session.room)
	session.printLine(session.room.ToString(database.ReadMode, session.user.GetColorMode(),
		playerList, npcList, model.M.GetItems(session.room.GetItemIds())))
}

func (session *Session) printRoomEditor() {
	session.printLine(session.room.ToString(database.EditMode, session.user.GetColorMode(), nil, nil, nil))
}

func (session *Session) clearLine() {
	utils.ClearLine(session.conn)
}

func prompt() string {
	return "> "
}

// Same behavior as menu.Exec(), except that it uses getUserInput
// which doesn't block the event loop while waiting for input
func (session *Session) execMenu(menu utils.Menu) (string, bson.ObjectId) {
	choice := ""
	var data bson.ObjectId

	for {
		menu.Print(session.conn, session.user.GetColorMode())
		choice = session.getUserInput(CleanUserInput, menu.GetPrompt())
		if menu.HasAction(choice) || choice == "" {
			data = menu.GetData(choice)
			break
		}
	}
	return choice, data
}

// getUserInput allows us to retrieve user input in a way that doesn't block the
// event loop by using channels and a separate Go routine to grab
// either the next user input or the next event.
func (session *Session) getUserInput(inputMode userInputMode, prompt string) string {
	session.inputModeChannel <- inputMode
	session.promptChannel <- prompt

	for {
		select {
		case input := <-session.userInputChannel:
			return input
		case event := <-session.eventChannel:
			message := session.processEvent(event)
			if message != "" {
				session.clearLine()
				session.printLine(message)
				session.printString(prompt)
			}
		case quitMessage := <-session.panicChannel:
			panic(quitMessage)
		}
	}
	panic("Unexpected code path")
}

func (session *Session) processEvent(event model.Event) string {
	message := event.ToString(session.player)

	switch event.Type() {
	case model.RoomUpdateEventType:
		roomEvent := event.(model.RoomUpdateEvent)
		if roomEvent.Room.GetId() == session.room.GetId() {
			session.room = roomEvent.Room
		}
	}

	return message
}

// vim: nocindent
<commit_msg>Comment out log creation for the moment<commit_after>package session

import (
	"fmt"
	"io"
	"kmud/database"
	"kmud/model"
	"kmud/utils"
	"labix.org/v2/mgo/bson"
	// "log"
	// "os"
	"strings"
	"time"
)

type Session struct {
	conn   io.ReadWriter
	user   *database.User
	player *database.Character
	room   *database.Room
	zone   *database.Zone

	userInputChannel chan string
	promptChannel    chan string
	inputModeChannel chan userInputMode
	panicChannel     chan interface{}
	eventChannel     chan model.Event

	// logger *log.Logger
}

func NewSession(conn io.ReadWriter, user *database.User, player *database.Character) Session {
	var session Session
	session.conn = conn
	session.user = user
	session.player = player
	session.room = model.M.GetRoom(player.GetRoomId())
	session.zone = model.M.GetZone(session.room.GetZoneId())

	session.userInputChannel = make(chan string)
	session.promptChannel = make(chan string)
	session.inputModeChannel = make(chan userInputMode)
	session.panicChannel = make(chan interface{})
	session.eventChannel = model.Register(session.player)

	// file, err := os.OpenFile(player.PrettyName()+".log", os.O_WRONLY|os.O_TRUNC|os.O_CREATE, os.ModePerm)
	// utils.PanicIfError(err)

	// session.logger = log.New(file, player.PrettyName()+" ", log.LstdFlags)

	return session
}

type userInputMode int

const (
	CleanUserInput userInputMode = iota
	RawUserInput   userInputMode = iota
)

func toggleExitMenu(cm utils.ColorMode, room *database.Room) utils.Menu {
	onOrOff := func(direction database.ExitDirection) string {
		text := "Off"
		if room.HasExit(direction) {
			text = "On"
		}
		return utils.Colorize(cm, utils.ColorBlue, text)
	}

	menu := utils.NewMenu("Edit Exits")

	menu.AddAction("n", "[N]orth: "+onOrOff(database.DirectionNorth))
	menu.AddAction("ne", "[NE]North East: "+onOrOff(database.DirectionNorthEast))
	menu.AddAction("e", "[E]ast: "+onOrOff(database.DirectionEast))
	menu.AddAction("se", "[SE]South East: "+onOrOff(database.DirectionSouthEast))
	menu.AddAction("s", "[S]outh: "+onOrOff(database.DirectionSouth))
	menu.AddAction("sw", "[SW]South West: "+onOrOff(database.DirectionSouthWest))
	menu.AddAction("w", "[W]est: "+onOrOff(database.DirectionWest))
	menu.AddAction("nw", "[NW]North West: "+onOrOff(database.DirectionNorthWest))
	menu.AddAction("u", "[U]p: "+onOrOff(database.DirectionUp))
	menu.AddAction("d", "[D]own: "+onOrOff(database.DirectionDown))

	return menu
}

func npcMenu(room *database.Room) utils.Menu {
	npcs := model.M.NpcsIn(room)

	menu := utils.NewMenu("NPCs")

	menu.AddAction("n", "[N]ew")

	for i, npc := range npcs {
		index := i + 1
		actionText := fmt.Sprintf("[%v]%v", index, npc.PrettyName())
		menu.AddActionData(index, actionText, npc.GetId())
	}

	return menu
}

func specificNpcMenu(npcId bson.ObjectId) utils.Menu {
	npc := model.M.GetCharacter(npcId)
	menu := utils.NewMenu(npc.PrettyName())
	menu.AddAction("r", "[R]ename")
	menu.AddAction("d", "[D]elete")
	menu.AddAction("c", "[C]onversation")
	return menu
}

func (session *Session) Exec() {
	defer model.Unregister(session.eventChannel)

	session.printLineColor(utils.ColorWhite, "Welcome, "+session.player.PrettyName())
	session.printRoom()

	// Main routine in charge of actually reading input from the connection object,
	// also has built in throttling to limit how fast we are allowed to process
	// commands from the user.
	go func() {
		defer func() {
			if r := recover(); r != nil {
				session.panicChannel <- r
			}
		}()

		lastTime := time.Now()

		delay := time.Duration(200) * time.Millisecond

		for {
			mode := <-session.inputModeChannel
			prompt := utils.Colorize(session.user.GetColorMode(), utils.ColorWhite, <-session.promptChannel)
			input := ""

			switch mode {
			case CleanUserInput:
				input = utils.GetUserInput(session.conn, prompt)
			case RawUserInput:
				input = utils.GetRawUserInput(session.conn, prompt)
			default:
				panic("Unhandled case in switch statement (userInputMode)")
			}

			diff := time.Since(lastTime)

			if diff < delay {
				time.Sleep(delay - diff)
			}

			session.userInputChannel <- input
			lastTime = time.Now()
		}
	}()

	// Main loop
	for {
		input := session.getUserInput(RawUserInput, prompt())
		if input == "" || input == "logout" {
			return
		}
		if strings.HasPrefix(input, "/") {
			session.handleCommand(utils.Argify(input[1:]))
		} else {
			session.handleAction(utils.Argify(input))
		}
	}
}

func (session *Session) printString(data string) {
	io.WriteString(session.conn, data)
}

func (session *Session) printLineColor(color utils.Color, line string, a ...interface{}) {
	utils.WriteLine(session.conn, utils.Colorize(session.user.GetColorMode(), color, fmt.Sprintf(line, a...)))
}

func (session *Session) printLine(line string, a ...interface{}) {
	session.printLineColor(utils.ColorWhite, line, a...)
}

func (session *Session) printError(err string, a ...interface{}) {
	session.printLineColor(utils.ColorRed, err, a...)
}

func (session *Session) printRoom() {
	playerList := model.M.PlayersIn(session.room, session.player)
	npcList := model.M.NpcsIn(session.room)
	session.printLine(session.room.ToString(database.ReadMode, session.user.GetColorMode(),
		playerList, npcList, model.M.GetItems(session.room.GetItemIds())))
}

func (session *Session) printRoomEditor() {
	session.printLine(session.room.ToString(database.EditMode, session.user.GetColorMode(), nil, nil, nil))
}

func (session *Session) clearLine() {
	utils.ClearLine(session.conn)
}

func prompt() string {
	return "> "
}

// Same behavior as menu.Exec(), except that it uses getUserInput
// which doesn't block the event loop while waiting for input
func (session *Session) execMenu(menu utils.Menu) (string, bson.ObjectId) {
	choice := ""
	var data bson.ObjectId

	for {
		menu.Print(session.conn, session.user.GetColorMode())
		choice = session.getUserInput(CleanUserInput, menu.GetPrompt())
		if menu.HasAction(choice) || choice == "" {
			data = menu.GetData(choice)
			break
		}
	}
	return choice, data
}

// getUserInput allows us to retrieve user input in a way that doesn't block the
// event loop by using channels and a separate Go routine to grab
// either the next user input or the next event.
func (session *Session) getUserInput(inputMode userInputMode, prompt string) string {
	session.inputModeChannel <- inputMode
	session.promptChannel <- prompt

	for {
		select {
		case input := <-session.userInputChannel:
			return input
		case event := <-session.eventChannel:
			message := session.processEvent(event)
			if message != "" {
				session.clearLine()
				session.printLine(message)
				session.printString(prompt)
			}
		case quitMessage := <-session.panicChannel:
			panic(quitMessage)
		}
	}
	panic("Unexpected code path")
}

func (session *Session) processEvent(event model.Event) string {
	message := event.ToString(session.player)

	switch event.Type() {
	case model.RoomUpdateEventType:
		roomEvent := event.(model.RoomUpdateEvent)
		if roomEvent.Room.GetId() == session.room.GetId() {
			session.room = roomEvent.Room
		}
	}

	return message
}

// vim: nocindent
<|endoftext|>


<commit_before>package session

import (
	"github.com/gin-gonic/gin"
	"github.com/gorilla/sessions"
	"github.com/iiinsomnia/yiigo"
)

const gosessid = "GOSESSID"

var store *sessions.CookieStore

// Start start session
func Start() {
	store = sessions.NewCookieStore([]byte(yiigo.Env.String("session.secret", "N0awmAuS2OziVFu^9!*0LY7MeCRgQ&z0")))
}

// Get get session key - value
func Get(c *gin.Context, key string, defaultValule ...interface{}) (interface{}, error) {
	session, err := store.Get(c.Request, gosessid)

	if err != nil {
		return nil, err
	}

	// Get some session values.
	v, ok := session.Values[key]

	if !ok {
		if len(defaultValule) > 0 {
			return defaultValule, nil
		}

		return nil, nil
	}

	return v, nil
}

// Set set session key - value, duration: seconds
func Set(c *gin.Context, key string, data interface{}, duration ...int) error {
	session, err := store.Get(c.Request, gosessid)

	if err != nil {
		return err
	}

	if len(duration) > 0 {
		session.Options = &sessions.Options{
			Path:   "/",
			MaxAge: duration[0],
		}
	}

	// Set some session values.
	session.Values[key] = data
	// Save it before we write to the response/return from the handler.
	err = session.Save(c.Request, c.Writer)

	return err
}

// Delete delete session key
func Delete(c *gin.Context, key string) error {
	session, err := store.Get(c.Request, gosessid)

	if err != nil {
		return err
	}

	delete(session.Values, key)

	err = session.Save(c.Request, c.Writer)

	return err
}

// Destroy destroy session
func Destroy(c *gin.Context) error {
	session, err := store.Get(c.Request, gosessid)

	if err != nil {
		return err
	}

	session.Options = &sessions.Options{
		Path:   "/",
		MaxAge: -1,
	}

	err = session.Save(c.Request, c.Writer)

	return err
}
<commit_msg>update session<commit_after>package session

import (
	"github.com/gin-gonic/gin"
	"github.com/gorilla/sessions"
	"github.com/iiinsomnia/yiigo"
)

const gosessid = "GOSESSID"

var store *sessions.CookieStore

// Start start session
func Start() {
	store = sessions.NewCookieStore([]byte(yiigo.Env.String("session.secret", "N0awmAuS2OziVFu^9!*0LY7MeCRgQ&z0")))
}

// Get get session key - value
func Get(c *gin.Context, key string, defaultValule ...interface{}) (interface{}, error) {
	session, err := store.Get(c.Request, gosessid)

	if err != nil {
		return nil, err
	}

	// Get some session values.
	v, ok := session.Values[key]

	if !ok {
		if len(defaultValule) > 0 {
			return defaultValule[0], nil
		}

		return nil, nil
	}

	return v, nil
}

// Set set session key - value, duration: seconds
func Set(c *gin.Context, key string, data interface{}, duration ...int) error {
	session, err := store.Get(c.Request, gosessid)

	if err != nil {
		return err
	}

	if len(duration) > 0 {
		session.Options = &sessions.Options{
			Path:   "/",
			MaxAge: duration[0],
		}
	}

	// Set some session values.
	session.Values[key] = data
	// Save it before we write to the response/return from the handler.
	err = session.Save(c.Request, c.Writer)

	return err
}

// Delete delete session key
func Delete(c *gin.Context, key string) error {
	session, err := store.Get(c.Request, gosessid)

	if err != nil {
		return err
	}

	delete(session.Values, key)

	err = session.Save(c.Request, c.Writer)

	return err
}

// Destroy destroy session
func Destroy(c *gin.Context) error {
	session, err := store.Get(c.Request, gosessid)

	if err != nil {
		return err
	}

	session.Options = &sessions.Options{
		Path:   "/",
		MaxAge: -1,
	}

	err = session.Save(c.Request, c.Writer)

	return err
}
<|endoftext|>