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

// +build example

package main

import (
	"fmt"
	"image/color"
	"io/ioutil"
	"log"
	"time"

	"github.com/hajimehoshi/ebiten"
	"github.com/hajimehoshi/ebiten/audio"
	"github.com/hajimehoshi/ebiten/audio/vorbis"
	"github.com/hajimehoshi/ebiten/audio/wav"
	"github.com/hajimehoshi/ebiten/ebitenutil"
)

const (
	screenWidth  = 320
	screenHeight = 240
)

var (
	playerBarImage     *ebiten.Image
	playerCurrentImage *ebiten.Image
)

func init() {
	var err error
	playerBarImage, err = ebiten.NewImage(300, 4, ebiten.FilterNearest)
	if err != nil {
		log.Fatal(err)
	}
	if err := playerBarImage.Fill(&color.RGBA{0x80, 0x80, 0x80, 0xff}); err != nil {
		log.Fatal(err)
	}

	playerCurrentImage, err = ebiten.NewImage(4, 10, ebiten.FilterNearest)
	if err != nil {
		log.Fatal(err)
	}
	if err := playerCurrentImage.Fill(&color.RGBA{0xff, 0xff, 0xff, 0xff}); err != nil {
		log.Fatal(err)
	}
}

type Player struct {
	audioPlayer *audio.Player
	total       time.Duration
}

var (
	audioContext     *audio.Context
	musicPlayer      *Player
	seBytes          []byte
	musicCh          = make(chan *Player)
	seCh             = make(chan []byte)
	mouseButtonState = map[ebiten.MouseButton]int{}
	keyState         = map[ebiten.Key]int{}
	volume128        = 128
)

func playerBarRect() (x, y, w, h int) {
	w, h = playerBarImage.Size()
	x = (screenWidth - w) / 2
	y = screenHeight - h - 16
	return
}

func (p *Player) updateSE() error {
	if seBytes == nil {
		return nil
	}
	if !ebiten.IsKeyPressed(ebiten.KeyP) {
		keyState[ebiten.KeyP] = 0
		return nil
	}
	keyState[ebiten.KeyP]++
	if keyState[ebiten.KeyP] != 1 {
		return nil
	}
	sePlayer, err := audio.NewPlayerFromBytes(audioContext, seBytes)
	if err != nil {
		return err
	}
	return sePlayer.Play()
}

func (p *Player) updateVolume() error {
	if p.audioPlayer == nil {
		return nil
	}
	if ebiten.IsKeyPressed(ebiten.KeyZ) {
		volume128--
	}
	if ebiten.IsKeyPressed(ebiten.KeyX) {
		volume128++
	}
	if volume128 < 0 {
		volume128 = 0
	}
	if 128 < volume128 {
		volume128 = 128
	}
	p.audioPlayer.SetVolume(float64(volume128) / 128)
	return nil
}

func (p *Player) updatePlayPause() error {
	if p.audioPlayer == nil {
		return nil
	}
	if !ebiten.IsKeyPressed(ebiten.KeyS) {
		keyState[ebiten.KeyS] = 0
		return nil
	}
	keyState[ebiten.KeyS]++
	if keyState[ebiten.KeyS] != 1 {
		return nil
	}
	if p.audioPlayer.IsPlaying() {
		return p.audioPlayer.Pause()
	}
	return p.audioPlayer.Play()
}

func (p *Player) updateBar() error {
	if p.audioPlayer == nil {
		return nil
	}
	if !ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) {
		mouseButtonState[ebiten.MouseButtonLeft] = 0
		return nil
	}
	mouseButtonState[ebiten.MouseButtonLeft]++
	if mouseButtonState[ebiten.MouseButtonLeft] != 1 {
		return nil
	}
	x, y := ebiten.CursorPosition()
	bx, by, bw, bh := playerBarRect()
	const padding = 4
	if y < by-padding || by+bh+padding <= y {
		return nil
	}
	if x < bx || bx+bw <= x {
		return nil
	}
	pos := time.Duration(x-bx) * p.total / time.Duration(bw)
	return p.audioPlayer.Seek(pos)
}

func (p *Player) close() error {
	return p.audioPlayer.Close()
}

func update(screen *ebiten.Image) error {
	if musicPlayer == nil {
		select {
		case musicPlayer = <-musicCh:
		default:
		}
	}
	if seBytes == nil {
		select {
		case seBytes = <-seCh:
		default:
		}
	}
	if musicPlayer != nil {
		if err := musicPlayer.updateBar(); err != nil {
			return err
		}
		if err := musicPlayer.updatePlayPause(); err != nil {
			return err
		}
		if err := musicPlayer.updateSE(); err != nil {
			return err
		}
		if err := musicPlayer.updateVolume(); err != nil {
			return err
		}
	}

	op := &ebiten.DrawImageOptions{}
	x, y, w, h := playerBarRect()
	op.GeoM.Translate(float64(x), float64(y))
	if err := screen.DrawImage(playerBarImage, op); err != nil {
		return err
	}
	currentTimeStr := "00:00"
	if musicPlayer != nil {
		c := musicPlayer.audioPlayer.Current()

		// Current Time
		m := (c / time.Minute) % 100
		s := (c / time.Second) % 60
		currentTimeStr = fmt.Sprintf("%02d:%02d", m, s)

		// Bar
		cw, ch := playerCurrentImage.Size()
		cx := int(time.Duration(w)*c/musicPlayer.total) + x - cw/2
		cy := y - (ch-h)/2
		op := &ebiten.DrawImageOptions{}
		op.GeoM.Translate(float64(cx), float64(cy))
		if err := screen.DrawImage(playerCurrentImage, op); err != nil {
			return err
		}
	}

	msg := fmt.Sprintf(`FPS: %0.2f
Press S to toggle Play/Pause
Press P to play SE
Press Z or X to change volume of the music
%s`, ebiten.CurrentFPS(), currentTimeStr)
	if musicPlayer == nil {
		msg += "\nNow Loading..."
	}
	if err := ebitenutil.DebugPrint(screen, msg); err != nil {
		return err
	}
	if err := audioContext.Update(); err != nil {
		return err
	}
	return nil
}

func main() {
	wavF, err := ebitenutil.OpenFile("_resources/audio/jab.wav")
	if err != nil {
		log.Fatal(err)
	}
	oggF, err := ebitenutil.OpenFile("_resources/audio/game.ogg")
	if err != nil {
		log.Fatal(err)
	}
	const sampleRate = 44100
	const bytesPerSample = 4 // TODO: This should be defined in audio package
	audioContext, err = audio.NewContext(sampleRate)
	if err != nil {
		log.Fatal(err)
	}
	go func() {
		s, err := wav.Decode(audioContext, wavF)
		if err != nil {
			log.Fatal(err)
			return
		}
		b, err := ioutil.ReadAll(s)
		if err != nil {
			log.Fatal(err)
			return
		}
		seCh <- b
		close(seCh)
	}()
	go func() {
		s, err := vorbis.Decode(audioContext, oggF)
		if err != nil {
			log.Fatal(err)
			return
		}
		p, err := audio.NewPlayer(audioContext, s)
		if err != nil {
			log.Fatal(err)
			return
		}
		musicCh <- &Player{
			audioPlayer: p,
			total:       time.Second * time.Duration(s.Size()) / bytesPerSample / sampleRate,
		}
		close(musicCh)
		// TODO: Is this goroutine-safe?
		if err := p.Play(); err != nil {
			log.Fatal(err)
			return
		}
	}()
	if err := ebiten.Run(update, screenWidth, screenHeight, 2, "Audio (Ebiten Demo)"); err != nil {
		log.Fatal(err)
	}
	if musicPlayer != nil {
		if err := musicPlayer.close(); err != nil {
			log.Fatal(err)
		}
	}
}
<commit_msg>examples/audio: Async seeking<commit_after>// Copyright 2016 Hajime Hoshi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// +build example

package main

import (
	"fmt"
	"image/color"
	"io/ioutil"
	"log"
	"time"

	"github.com/hajimehoshi/ebiten"
	"github.com/hajimehoshi/ebiten/audio"
	"github.com/hajimehoshi/ebiten/audio/vorbis"
	"github.com/hajimehoshi/ebiten/audio/wav"
	"github.com/hajimehoshi/ebiten/ebitenutil"
)

const (
	screenWidth  = 320
	screenHeight = 240
)

var (
	playerBarImage     *ebiten.Image
	playerCurrentImage *ebiten.Image
)

func init() {
	var err error
	playerBarImage, err = ebiten.NewImage(300, 4, ebiten.FilterNearest)
	if err != nil {
		log.Fatal(err)
	}
	if err := playerBarImage.Fill(&color.RGBA{0x80, 0x80, 0x80, 0xff}); err != nil {
		log.Fatal(err)
	}

	playerCurrentImage, err = ebiten.NewImage(4, 10, ebiten.FilterNearest)
	if err != nil {
		log.Fatal(err)
	}
	if err := playerCurrentImage.Fill(&color.RGBA{0xff, 0xff, 0xff, 0xff}); err != nil {
		log.Fatal(err)
	}
}

type Player struct {
	audioPlayer *audio.Player
	total       time.Duration
	seekedCh    chan error
}

var (
	audioContext     *audio.Context
	musicPlayer      *Player
	seBytes          []byte
	musicCh          = make(chan *Player)
	seCh             = make(chan []byte)
	mouseButtonState = map[ebiten.MouseButton]int{}
	keyState         = map[ebiten.Key]int{}
	volume128        = 128
)

func playerBarRect() (x, y, w, h int) {
	w, h = playerBarImage.Size()
	x = (screenWidth - w) / 2
	y = screenHeight - h - 16
	return
}

func (p *Player) updateSE() error {
	if seBytes == nil {
		return nil
	}
	if !ebiten.IsKeyPressed(ebiten.KeyP) {
		keyState[ebiten.KeyP] = 0
		return nil
	}
	keyState[ebiten.KeyP]++
	if keyState[ebiten.KeyP] != 1 {
		return nil
	}
	sePlayer, err := audio.NewPlayerFromBytes(audioContext, seBytes)
	if err != nil {
		return err
	}
	return sePlayer.Play()
}

func (p *Player) updateVolume() error {
	if p.audioPlayer == nil {
		return nil
	}
	if ebiten.IsKeyPressed(ebiten.KeyZ) {
		volume128--
	}
	if ebiten.IsKeyPressed(ebiten.KeyX) {
		volume128++
	}
	if volume128 < 0 {
		volume128 = 0
	}
	if 128 < volume128 {
		volume128 = 128
	}
	p.audioPlayer.SetVolume(float64(volume128) / 128)
	return nil
}

func (p *Player) updatePlayPause() error {
	if p.audioPlayer == nil {
		return nil
	}
	if !ebiten.IsKeyPressed(ebiten.KeyS) {
		keyState[ebiten.KeyS] = 0
		return nil
	}
	keyState[ebiten.KeyS]++
	if keyState[ebiten.KeyS] != 1 {
		return nil
	}
	if p.audioPlayer.IsPlaying() {
		return p.audioPlayer.Pause()
	}
	return p.audioPlayer.Play()
}

func (p *Player) updateBar() error {
	if p.audioPlayer == nil {
		return nil
	}
	if p.seekedCh != nil {
		return nil
	}
	if !ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) {
		mouseButtonState[ebiten.MouseButtonLeft] = 0
		return nil
	}
	mouseButtonState[ebiten.MouseButtonLeft]++
	if mouseButtonState[ebiten.MouseButtonLeft] != 1 {
		return nil
	}
	x, y := ebiten.CursorPosition()
	bx, by, bw, bh := playerBarRect()
	const padding = 4
	if y < by-padding || by+bh+padding <= y {
		return nil
	}
	if x < bx || bx+bw <= x {
		return nil
	}
	pos := time.Duration(x-bx) * p.total / time.Duration(bw)
	p.seekedCh = make(chan error, 1)
	go func() {
		// This can't be done parallely! !?!?
		p.seekedCh <- p.audioPlayer.Seek(pos)
	}()
	return nil
}

func (p *Player) close() error {
	return p.audioPlayer.Close()
}

func update(screen *ebiten.Image) error {
	if musicPlayer == nil {
		select {
		case musicPlayer = <-musicCh:
		default:
		}
	}
	if seBytes == nil {
		select {
		case seBytes = <-seCh:
		default:
		}
	}
	if musicPlayer != nil {
		if err := musicPlayer.updateBar(); err != nil {
			return err
		}
		if err := musicPlayer.updatePlayPause(); err != nil {
			return err
		}
		if err := musicPlayer.updateSE(); err != nil {
			return err
		}
		if err := musicPlayer.updateVolume(); err != nil {
			return err
		}
	}

	op := &ebiten.DrawImageOptions{}
	x, y, w, h := playerBarRect()
	op.GeoM.Translate(float64(x), float64(y))
	if err := screen.DrawImage(playerBarImage, op); err != nil {
		return err
	}
	currentTimeStr := "00:00"
	if musicPlayer != nil {
		c := musicPlayer.audioPlayer.Current()

		// Current Time
		m := (c / time.Minute) % 100
		s := (c / time.Second) % 60
		currentTimeStr = fmt.Sprintf("%02d:%02d", m, s)

		// Bar
		cw, ch := playerCurrentImage.Size()
		cx := int(time.Duration(w)*c/musicPlayer.total) + x - cw/2
		cy := y - (ch-h)/2
		op := &ebiten.DrawImageOptions{}
		op.GeoM.Translate(float64(cx), float64(cy))
		if err := screen.DrawImage(playerCurrentImage, op); err != nil {
			return err
		}
	}

	msg := fmt.Sprintf(`FPS: %0.2f
Press S to toggle Play/Pause
Press P to play SE
Press Z or X to change volume of the music
%s`, ebiten.CurrentFPS(), currentTimeStr)
	if musicPlayer == nil {
		msg += "\nNow Loading..."
	} else if musicPlayer.seekedCh != nil {
		select {
		case err := <-musicPlayer.seekedCh:
			if err != nil {
				return err
			}
			close(musicPlayer.seekedCh)
			musicPlayer.seekedCh = nil
		default:
			msg += "\nSeeking..."
		}
	}
	if err := ebitenutil.DebugPrint(screen, msg); err != nil {
		return err
	}
	if err := audioContext.Update(); err != nil {
		return err
	}
	return nil
}

func main() {
	wavF, err := ebitenutil.OpenFile("_resources/audio/jab.wav")
	if err != nil {
		log.Fatal(err)
	}
	oggF, err := ebitenutil.OpenFile("_resources/audio/game.ogg")
	if err != nil {
		log.Fatal(err)
	}
	const sampleRate = 44100
	const bytesPerSample = 4 // TODO: This should be defined in audio package
	audioContext, err = audio.NewContext(sampleRate)
	if err != nil {
		log.Fatal(err)
	}
	go func() {
		s, err := wav.Decode(audioContext, wavF)
		if err != nil {
			log.Fatal(err)
			return
		}
		b, err := ioutil.ReadAll(s)
		if err != nil {
			log.Fatal(err)
			return
		}
		seCh <- b
		close(seCh)
	}()
	go func() {
		s, err := vorbis.Decode(audioContext, oggF)
		if err != nil {
			log.Fatal(err)
			return
		}
		p, err := audio.NewPlayer(audioContext, s)
		if err != nil {
			log.Fatal(err)
			return
		}
		musicCh <- &Player{
			audioPlayer: p,
			total:       time.Second * time.Duration(s.Size()) / bytesPerSample / sampleRate,
		}
		close(musicCh)
		// TODO: Is this goroutine-safe?
		if err := p.Play(); err != nil {
			log.Fatal(err)
			return
		}
	}()
	if err := ebiten.Run(update, screenWidth, screenHeight, 2, "Audio (Ebiten Demo)"); err != nil {
		log.Fatal(err)
	}
	if musicPlayer != nil {
		if err := musicPlayer.close(); err != nil {
			log.Fatal(err)
		}
	}
}
<|endoftext|>


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

package main

import (
	"errors"
	"github.com/headwindfly/clevergo"
	"os"
	"path"
	"strconv"
)

type project struct {
	Name    string `json:"name" xml:"name"`
	Version string `json:"version" xml:"version"`
}

var (
	helloString   = "Hello CleverGo!"
	resourcesPath = path.Join(os.Getenv("GOPATH"), "src", "github.com", "headwindfly", "clevergo")

	project = project{
		Name:    "CleverGo",
		Version: clevergo.Version,
	}
)

func index(ctx *clevergo.Context) {
	ctx.HTML(`

		<title>CleverGo Basic Usage</title>

HTML

HTML With Code: 404

JSON

JSON With Code: 404

JSONP

JSONP With Code: 404

XML

XML With Code: 404

Param

Multiple Params

Static Resources

	`)
}

func getCode(b []byte) (int, error) {
	if len(b) == 0 {
		return 0, errors.New("No code.")
	}
	return strconv.Atoi(string(b))
}

func html(ctx *clevergo.Context) {
	code, err := getCode(ctx.FormValue("code"))
	if err == nil {
		ctx.HTMLWithCode(code, helloString)
		return
	}

	ctx.HTML(helloString)
}

func json(ctx *clevergo.Context) {
	code, err := getCode(ctx.FormValue("code"))
	if err == nil {
		ctx.JSONWithCode(code, project)
		return
	}

	ctx.JSON(project)
}

func jsonp(ctx *clevergo.Context) {
	callback := ctx.FormValue("callback")

	code, err := getCode(ctx.FormValue("code"))
	if err == nil {
		ctx.JSONPWithCode(code, project, callback)
		return
	}

	ctx.JSONP(project, callback)
}

func xml(ctx *clevergo.Context) {
	code, err := getCode(ctx.FormValue("code"))
	if err == nil {
		ctx.XMLWithCode(code, project)
		return
	}

	ctx.XML(project)
}

func params(ctx *clevergo.Context) {
	name := ctx.RouterParams.ByName("name")
	ctx.Textf("Hello %s.", name)
}

func multiParams(ctx *clevergo.Context) {
	param1 := ctx.RouterParams.ByName("param1")
	param2 := ctx.RouterParams.ByName("param2")
	ctx.Textf("Your params is %s and %s", param1, param2)
}

func main() {
	// Create a application.
	app := clevergo.NewApplication()

	// Create a router instance.
	router := clevergo.NewRouter()
	app.AddRouter("", router)

	// Register route handler.
	router.GET("/", clevergo.HandlerFunc(index))

	// HTML
	router.GET("/html", clevergo.HandlerFunc(html))

	// JSON
	router.GET("/json", clevergo.HandlerFunc(json))

	// JSONP
	router.GET("/jsonp", clevergo.HandlerFunc(jsonp))

	// XML
	router.GET("/xml", clevergo.HandlerFunc(xml))

	// Router Params.
	// Navigate to http://127.0.0.1:8080/params/yourname.
	router.GET("/params/:name", clevergo.HandlerFunc(params))
	// Navigate to http://127.0.0.1:8080/multi-params/param1/param2.
	router.GET("/multi-params/:param1/:param2", clevergo.HandlerFunc(multiParams))

	// Static resource files.
	// Navigate to http://127.0.0.1:8080/resources/README.md
	router.ServeFiles("/resources/*filepath", resourcesPath)

	// Start server.
	app.Run()
}
<commit_msg>Fixed bug of basic example<commit_after>// Copyright 2016 HeadwindFly. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"errors"
	"github.com/headwindfly/clevergo"
	"os"
	"path"
	"strconv"
)

type project struct {
	Name    string `json:"name" xml:"name"`
	Version string `json:"version" xml:"version"`
}

var (
	helloString   = "Hello CleverGo!"
	resourcesPath = path.Join(os.Getenv("GOPATH"), "src", "github.com", "headwindfly", "clevergo")

	p = project{
		Name:    "CleverGo",
		Version: clevergo.Version,
	}
)

func index(ctx *clevergo.Context) {
	ctx.HTML(`

		<title>CleverGo Basic Usage</title>

HTML

HTML With Code: 404

JSON

JSON With Code: 404

JSONP

JSONP With Code: 404

XML

XML With Code: 404

Param

Multiple Params

Static Resources

	`)
}

func getCode(b []byte) (int, error) {
	if len(b) == 0 {
		return 0, errors.New("No code.")
	}
	return strconv.Atoi(string(b))
}

func html(ctx *clevergo.Context) {
	code, err := getCode(ctx.FormValue("code"))
	if err == nil {
		ctx.HTMLWithCode(code, helloString)
		return
	}

	ctx.HTML(helloString)
}

func json(ctx *clevergo.Context) {
	code, err := getCode(ctx.FormValue("code"))
	if err == nil {
		ctx.JSONWithCode(code, p)
		return
	}

	ctx.JSON(p)
}

func jsonp(ctx *clevergo.Context) {
	callback := ctx.FormValue("callback")

	code, err := getCode(ctx.FormValue("code"))
	if err == nil {
		ctx.JSONPWithCode(code, p, callback)
		return
	}

	ctx.JSONP(p, callback)
}

func xml(ctx *clevergo.Context) {
	code, err := getCode(ctx.FormValue("code"))
	if err == nil {
		ctx.XMLWithCode(code, p)
		return
	}

	ctx.XML(p)
}

func params(ctx *clevergo.Context) {
	name := ctx.RouterParams.ByName("name")
	ctx.Textf("Hello %s.", name)
}

func multiParams(ctx *clevergo.Context) {
	param1 := ctx.RouterParams.ByName("param1")
	param2 := ctx.RouterParams.ByName("param2")
	ctx.Textf("Your params is %s and %s", param1, param2)
}

func main() {
	// Create a application.
	app := clevergo.NewApplication()

	// Create a router instance.
	router := clevergo.NewRouter()
	app.AddRouter("", router)

	// Register route handler.
	router.GET("/", clevergo.HandlerFunc(index))

	// HTML
	router.GET("/html", clevergo.HandlerFunc(html))

	// JSON
	router.GET("/json", clevergo.HandlerFunc(json))

	// JSONP
	router.GET("/jsonp", clevergo.HandlerFunc(jsonp))

	// XML
	router.GET("/xml", clevergo.HandlerFunc(xml))

	// Router Params.
	// Navigate to http://127.0.0.1:8080/params/yourname.
	router.GET("/params/:name", clevergo.HandlerFunc(params))
	// Navigate to http://127.0.0.1:8080/multi-params/param1/param2.
	router.GET("/multi-params/:param1/:param2", clevergo.HandlerFunc(multiParams))

	// Static resource files.
	// Navigate to http://127.0.0.1:8080/resources/README.md
	router.ServeFiles("/resources/*filepath", resourcesPath)

	// Start server.
	app.Run()
}
<|endoftext|>


<commit_before>package middleware

import (
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/go-chi/chi"
)

func TestContentCharset(t *testing.T) {
	t.Parallel()

	var tests = []struct {
		name                string
		inputValue          string
		inputContentCharset []string
		want                int
	}{
		{
			"should accept requests with a matching charset",
			"application/json; charset=UTF-8",
			[]string{"UTF-8"},
			http.StatusOK,
		},
		{
			"should be case-insensitive",
			"application/json; charset=utf-8",
			[]string{"UTF-8"},
			http.StatusOK,
		},
		{
			"should accept requests with a matching charset with extra values",
			"application/json; foo=bar; charset=UTF-8; spam=eggs",
			[]string{"UTF-8"},
			http.StatusOK,
		},
		{
			"should accept requests with a matching charset when multiple charsets are supported",
			"text/xml; charset=UTF-8",
			[]string{"UTF-8", "Latin-1"},
			http.StatusOK,
		},
		{
			"should accept requests with no charset if empty charset headers are allowed",
			"text/xml",
			[]string{"UTF-8", ""},
			http.StatusOK,
		},
		{
			"should not accept requests with no charset if empty charset headers are not allowed",
			"text/xml",
			[]string{"UTF-8"},
			http.StatusUnsupportedMediaType,
		},
		{
			"should not accept requests with a mismatching charset",
			"text/plain; charset=Latin-1",
			[]string{"UTF-8"},
			http.StatusUnsupportedMediaType,
		},
		{
			"should not accept requests with a mismatching charset even if empty charsets are allowed",
			"text/plain; charset=Latin-1",
			[]string{"UTF-8", ""},
			http.StatusUnsupportedMediaType,
		},
	}

	for _, tt := range tests {
		var tt = tt
		t.Run(tt.name, func(t *testing.T) {
			t.Parallel()

			var recorder = httptest.NewRecorder()

			var r = chi.NewRouter()
			r.Use(ContentCharset(tt.inputContentCharset...))
			r.Get("/", func(w http.ResponseWriter, r *http.Request) {})

			var req, _ = http.NewRequest("GET", "/", nil)
			req.Header.Set("Content-Type", tt.inputValue)

			r.ServeHTTP(recorder, req)
			var res = recorder.Result()

			if res.StatusCode != tt.want {
				t.Errorf("response is incorrect, got %d, want %d", recorder.Code, tt.want)
			}
		})
	}
}

func TestSplit(t *testing.T) {
	t.Parallel()

	var s1, s2 = split("  type1;type2  ", ";")

	if s1 != "type1" || s2 != "type2" {
		t.Errorf("Want type1, type2 got %s, %s", s1, s2)
	}

	s1, s2 = split("type1  ", ";")

	if s1 != "type1" {
		t.Errorf("Want \"type1\" got \"%s\"", s1)
	}
}

func TestContentEncoding(t *testing.T) {
	t.Parallel()

	if !contentEncoding("application/json; foo=bar; charset=utf-8; spam=eggs", []string{"utf-8"}...) {
		t.Error("Want true, got false")
	}

	if contentEncoding("text/plain; charset=latin-1", []string{"utf-8"}...) {
		t.Error("Want false, got true")
	}

	if !contentEncoding("text/xml; charset=UTF-8", []string{"latin-1", "utf-8"}...) {
		t.Error("Want true, got false")
	}
}
<commit_msg>Check returned value in test<commit_after>package middleware

import (
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/go-chi/chi"
)

func TestContentCharset(t *testing.T) {
	t.Parallel()

	var tests = []struct {
		name                string
		inputValue          string
		inputContentCharset []string
		want                int
	}{
		{
			"should accept requests with a matching charset",
			"application/json; charset=UTF-8",
			[]string{"UTF-8"},
			http.StatusOK,
		},
		{
			"should be case-insensitive",
			"application/json; charset=utf-8",
			[]string{"UTF-8"},
			http.StatusOK,
		},
		{
			"should accept requests with a matching charset with extra values",
			"application/json; foo=bar; charset=UTF-8; spam=eggs",
			[]string{"UTF-8"},
			http.StatusOK,
		},
		{
			"should accept requests with a matching charset when multiple charsets are supported",
			"text/xml; charset=UTF-8",
			[]string{"UTF-8", "Latin-1"},
			http.StatusOK,
		},
		{
			"should accept requests with no charset if empty charset headers are allowed",
			"text/xml",
			[]string{"UTF-8", ""},
			http.StatusOK,
		},
		{
			"should not accept requests with no charset if empty charset headers are not allowed",
			"text/xml",
			[]string{"UTF-8"},
			http.StatusUnsupportedMediaType,
		},
		{
			"should not accept requests with a mismatching charset",
			"text/plain; charset=Latin-1",
			[]string{"UTF-8"},
			http.StatusUnsupportedMediaType,
		},
		{
			"should not accept requests with a mismatching charset even if empty charsets are allowed",
			"text/plain; charset=Latin-1",
			[]string{"UTF-8", ""},
			http.StatusUnsupportedMediaType,
		},
	}

	for _, tt := range tests {
		var tt = tt
		t.Run(tt.name, func(t *testing.T) {
			t.Parallel()

			var recorder = httptest.NewRecorder()

			var r = chi.NewRouter()
			r.Use(ContentCharset(tt.inputContentCharset...))
			r.Get("/", func(w http.ResponseWriter, r *http.Request) {})

			var req, _ = http.NewRequest("GET", "/", nil)
			req.Header.Set("Content-Type", tt.inputValue)

			r.ServeHTTP(recorder, req)
			var res = recorder.Result()

			if res.StatusCode != tt.want {
				t.Errorf("response is incorrect, got %d, want %d", recorder.Code, tt.want)
			}
		})
	}
}

func TestSplit(t *testing.T) {
	t.Parallel()

	var s1, s2 = split("  type1;type2  ", ";")

	if s1 != "type1" || s2 != "type2" {
		t.Errorf("Want type1, type2 got %s, %s", s1, s2)
	}

	s1, s2 = split("type1  ", ";")

	if s1 != "type1" {
		t.Errorf("Want \"type1\" got \"%s\"", s1)
	}
	if s2 != "" {
		t.Errorf("Want empty string got \"%s\"", s2)
	}
}

func TestContentEncoding(t *testing.T) {
	t.Parallel()

	if !contentEncoding("application/json; foo=bar; charset=utf-8; spam=eggs", []string{"utf-8"}...) {
		t.Error("Want true, got false")
	}

	if contentEncoding("text/plain; charset=latin-1", []string{"utf-8"}...) {
		t.Error("Want false, got true")
	}

	if !contentEncoding("text/xml; charset=UTF-8", []string{"latin-1", "utf-8"}...) {
		t.Error("Want true, got false")
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 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 dockercommon

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

	"github.com/fsouza/go-dockerclient"
	"github.com/fsouza/go-dockerclient/testing"
	"github.com/tsuru/tsuru/app"
	"github.com/tsuru/tsuru/app/image"
	"gopkg.in/check.v1"
)

func (s *S) TestPrepareImageForDeploy(c *check.C) {
	srv, err := testing.NewServer("0.0.0.0:0", nil, nil)
	c.Assert(err, check.IsNil)
	defer srv.Stop()
	a := &app.App{Name: "myapp"}
	cli, err := docker.NewClient(srv.URL())
	c.Assert(err, check.IsNil)
	baseImgName := "baseImg"
	err = cli.PullImage(docker.PullImageOptions{Repository: baseImgName}, docker.AuthConfiguration{})
	c.Assert(err, check.IsNil)
	buf := bytes.Buffer{}
	args := PrepareImageArgs{
		Client:      cli,
		App:         a,
		ProcfileRaw: "web: myapp run",
		ImageId:     baseImgName,
		Out:         &buf,
	}
	newImg, err := PrepareImageForDeploy(args)
	c.Assert(err, check.IsNil)
	c.Assert(newImg, check.Equals, "my.registry/tsuru/app-myapp:v1")
	c.Assert(buf.String(), check.Equals, `---- Inspecting image "baseImg" ----
  ---> Process "web" found with commands: ["myapp run"]
---- Pushing image "my.registry/tsuru/app-myapp:v1" to tsuru ----
Pushing...
Pushed
`)
	imd, err := image.GetImageCustomData(newImg)
	c.Assert(err, check.IsNil)
	c.Assert(imd, check.DeepEquals, image.ImageMetadata{
		Name:       "my.registry/tsuru/app-myapp:v1",
		Processes:  map[string][]string{"web": {"myapp run"}},
		CustomData: map[string]interface{}{},
	})
}

func (s *S) TestPrepareImageForDeployNoProcfile(c *check.C) {
	srv, err := testing.NewServer("0.0.0.0:0", nil, nil)
	c.Assert(err, check.IsNil)
	defer srv.Stop()
	a := &app.App{Name: "myapp"}
	cli, err := docker.NewClient(srv.URL())
	c.Assert(err, check.IsNil)
	baseImgName := "baseImg"
	err = cli.PullImage(docker.PullImageOptions{Repository: baseImgName}, docker.AuthConfiguration{})
	c.Assert(err, check.IsNil)
	srv.CustomHandler(fmt.Sprintf("/images/%s/json", baseImgName), http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		response := docker.Image{
			Config: &docker.Config{
				Entrypoint:   []string{"/bin/sh"},
				Cmd:          []string{"python", "test file.py"},
				ExposedPorts: map[docker.Port]struct{}{"3000/tcp": {}},
			},
		}
		j, _ := json.Marshal(response)
		w.Write(j)
	}))
	buf := bytes.Buffer{}
	args := PrepareImageArgs{
		Client:      cli,
		App:         a,
		ProcfileRaw: "",
		ImageId:     baseImgName,
		Out:         &buf,
	}
	newImg, err := PrepareImageForDeploy(args)
	c.Assert(err, check.IsNil)
	c.Assert(newImg, check.Equals, "my.registry/tsuru/app-myapp:v1")
	c.Assert(buf.String(), check.Equals, `---- Inspecting image "baseImg" ----
  ---> Procfile not found, using entrypoint and cmd
  ---> Process "web" found with commands: ["/bin/sh" "python" "test file.py"]
---- Pushing image "my.registry/tsuru/app-myapp:v1" to tsuru ----
Pushing...
Pushed
`)
	imd, err := image.GetImageCustomData(newImg)
	c.Assert(err, check.IsNil)
	c.Assert(imd, check.DeepEquals, image.ImageMetadata{
		Name:        "my.registry/tsuru/app-myapp:v1",
		Processes:   map[string][]string{"web": {"/bin/sh", "python", "test file.py"}},
		CustomData:  map[string]interface{}{},
		ExposedPort: "3000/tcp",
	})
}
<commit_msg>provision/dockercommon: fix tests reading image custom data<commit_after>// Copyright 2016 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 dockercommon

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

	"github.com/fsouza/go-dockerclient"
	"github.com/fsouza/go-dockerclient/testing"
	"github.com/tsuru/tsuru/app"
	"github.com/tsuru/tsuru/app/image"
	"gopkg.in/check.v1"
)

func (s *S) TestPrepareImageForDeploy(c *check.C) {
	srv, err := testing.NewServer("0.0.0.0:0", nil, nil)
	c.Assert(err, check.IsNil)
	defer srv.Stop()
	a := &app.App{Name: "myapp"}
	cli, err := docker.NewClient(srv.URL())
	c.Assert(err, check.IsNil)
	baseImgName := "baseImg"
	err = cli.PullImage(docker.PullImageOptions{Repository: baseImgName}, docker.AuthConfiguration{})
	c.Assert(err, check.IsNil)
	buf := bytes.Buffer{}
	args := PrepareImageArgs{
		Client:      cli,
		App:         a,
		ProcfileRaw: "web: myapp run",
		ImageId:     baseImgName,
		Out:         &buf,
	}
	newImg, err := PrepareImageForDeploy(args)
	c.Assert(err, check.IsNil)
	c.Assert(newImg, check.Equals, "my.registry/tsuru/app-myapp:v1")
	c.Assert(buf.String(), check.Equals, `---- Inspecting image "baseImg" ----
  ---> Process "web" found with commands: ["myapp run"]
---- Pushing image "my.registry/tsuru/app-myapp:v1" to tsuru ----
Pushing...
Pushed
`)
	imd, err := image.GetImageCustomData(newImg)
	c.Assert(err, check.IsNil)
	c.Assert(imd, check.DeepEquals, image.ImageMetadata{
		Name:            "my.registry/tsuru/app-myapp:v1",
		Processes:       map[string][]string{"web": {"myapp run"}},
		CustomData:      map[string]interface{}{},
		LegacyProcesses: map[string]string{},
	})
}

func (s *S) TestPrepareImageForDeployNoProcfile(c *check.C) {
	srv, err := testing.NewServer("0.0.0.0:0", nil, nil)
	c.Assert(err, check.IsNil)
	defer srv.Stop()
	a := &app.App{Name: "myapp"}
	cli, err := docker.NewClient(srv.URL())
	c.Assert(err, check.IsNil)
	baseImgName := "baseImg"
	err = cli.PullImage(docker.PullImageOptions{Repository: baseImgName}, docker.AuthConfiguration{})
	c.Assert(err, check.IsNil)
	srv.CustomHandler(fmt.Sprintf("/images/%s/json", baseImgName), http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		response := docker.Image{
			Config: &docker.Config{
				Entrypoint:   []string{"/bin/sh"},
				Cmd:          []string{"python", "test file.py"},
				ExposedPorts: map[docker.Port]struct{}{"3000/tcp": {}},
			},
		}
		j, _ := json.Marshal(response)
		w.Write(j)
	}))
	buf := bytes.Buffer{}
	args := PrepareImageArgs{
		Client:      cli,
		App:         a,
		ProcfileRaw: "",
		ImageId:     baseImgName,
		Out:         &buf,
	}
	newImg, err := PrepareImageForDeploy(args)
	c.Assert(err, check.IsNil)
	c.Assert(newImg, check.Equals, "my.registry/tsuru/app-myapp:v1")
	c.Assert(buf.String(), check.Equals, `---- Inspecting image "baseImg" ----
  ---> Procfile not found, using entrypoint and cmd
  ---> Process "web" found with commands: ["/bin/sh" "python" "test file.py"]
---- Pushing image "my.registry/tsuru/app-myapp:v1" to tsuru ----
Pushing...
Pushed
`)
	imd, err := image.GetImageCustomData(newImg)
	c.Assert(err, check.IsNil)
	c.Assert(imd, check.DeepEquals, image.ImageMetadata{
		Name:            "my.registry/tsuru/app-myapp:v1",
		Processes:       map[string][]string{"web": {"/bin/sh", "python", "test file.py"}},
		CustomData:      map[string]interface{}{},
		LegacyProcesses: map[string]string{},
		ExposedPort:     "3000/tcp",
	})
}
<|endoftext|>


<commit_before>package outbound

import (
	"sync"
	"time"

	"github.com/v2ray/v2ray-core/common/dice"
	v2net "github.com/v2ray/v2ray-core/common/net"
	"github.com/v2ray/v2ray-core/proxy/vmess"
)

type Receiver struct {
	sync.RWMutex
	Destination v2net.Destination
	Accounts    []*vmess.User
}

func NewReceiver(dest v2net.Destination, users ...*vmess.User) *Receiver {
	return &Receiver{
		Destination: dest,
		Accounts:    users,
	}
}

func (this *Receiver) HasUser(user *vmess.User) bool {
	this.RLock()
	defer this.RUnlock()
	for _, u := range this.Accounts {
		// TODO: handle AlterIds difference.
		if u.ID.Equals(user.ID) {
			return true
		}
	}
	return false
}

func (this *Receiver) AddUser(user *vmess.User) {
	if this.HasUser(user) {
		return
	}
	this.Lock()
	this.Accounts = append(this.Accounts, user)
	this.Unlock()
}

func (this *Receiver) PickUser() *vmess.User {
	return this.Accounts[dice.Roll(len(this.Accounts))]
}

type ExpiringReceiver struct {
	*Receiver
	until time.Time
}

func (this *ExpiringReceiver) Expired() bool {
	return this.until.Before(time.Now())
}

type ReceiverManager struct {
	receivers    []*Receiver
	detours      []*ExpiringReceiver
	detourAccess sync.RWMutex
}

func NewReceiverManager(receivers []*Receiver) *ReceiverManager {
	return &ReceiverManager{
		receivers: receivers,
		detours:   make([]*ExpiringReceiver, 0, 16),
	}
}

func (this *ReceiverManager) AddDetour(rec *Receiver, availableMin byte) {
	if availableMin < 2 {
		return
	}
	this.detourAccess.RLock()
	destExists := false
	for _, r := range this.detours {
		if r.Destination == rec.Destination {
			destExists = true
			// Destination exists, add new user if necessary
			for _, u := range rec.Accounts {
				r.AddUser(u)
			}
			break
		}
	}

	this.detourAccess.RUnlock()
	if !destExists {
		expRec := &ExpiringReceiver{
			Receiver: rec,
			until:    time.Now().Add(time.Duration(availableMin-1) * time.Minute),
		}
		this.detourAccess.Lock()
		this.detours = append(this.detours, expRec)
		this.detourAccess.Unlock()
	}
}

func (this *ReceiverManager) pickDetour() *Receiver {
	if len(this.detours) == 0 {
		return nil
	}
	this.detourAccess.RLock()
	idx := dice.Roll(len(this.detours))
	rec := this.detours[idx]
	this.detourAccess.RUnlock()

	if rec.Expired() {
		this.detourAccess.Lock()
		detourLen := len(this.detours)
		this.detours[idx] = this.detours[detourLen-1]
		this.detours = this.detours[:detourLen-1]
		this.detourAccess.Unlock()
		return nil
	}

	return rec.Receiver
}

func (this *ReceiverManager) pickStdReceiver() *Receiver {
	return this.receivers[dice.Roll(len(this.receivers))]
}

func (this *ReceiverManager) PickReceiver() (v2net.Destination, *vmess.User) {
	rec := this.pickDetour()
	if rec == nil {
		rec = this.pickStdReceiver()
	}
	user := rec.PickUser()

	return rec.Destination, user
}
<commit_msg>ensure that detour list has not changed<commit_after>package outbound

import (
	"sync"
	"time"

	"github.com/v2ray/v2ray-core/common/dice"
	v2net "github.com/v2ray/v2ray-core/common/net"
	"github.com/v2ray/v2ray-core/proxy/vmess"
)

type Receiver struct {
	sync.RWMutex
	Destination v2net.Destination
	Accounts    []*vmess.User
}

func NewReceiver(dest v2net.Destination, users ...*vmess.User) *Receiver {
	return &Receiver{
		Destination: dest,
		Accounts:    users,
	}
}

func (this *Receiver) HasUser(user *vmess.User) bool {
	this.RLock()
	defer this.RUnlock()
	for _, u := range this.Accounts {
		// TODO: handle AlterIds difference.
		if u.ID.Equals(user.ID) {
			return true
		}
	}
	return false
}

func (this *Receiver) AddUser(user *vmess.User) {
	if this.HasUser(user) {
		return
	}
	this.Lock()
	this.Accounts = append(this.Accounts, user)
	this.Unlock()
}

func (this *Receiver) PickUser() *vmess.User {
	return this.Accounts[dice.Roll(len(this.Accounts))]
}

type ExpiringReceiver struct {
	*Receiver
	until time.Time
}

func (this *ExpiringReceiver) Expired() bool {
	return this.until.Before(time.Now())
}

type ReceiverManager struct {
	receivers    []*Receiver
	detours      []*ExpiringReceiver
	detourAccess sync.RWMutex
}

func NewReceiverManager(receivers []*Receiver) *ReceiverManager {
	return &ReceiverManager{
		receivers: receivers,
		detours:   make([]*ExpiringReceiver, 0, 16),
	}
}

func (this *ReceiverManager) AddDetour(rec *Receiver, availableMin byte) {
	if availableMin < 2 {
		return
	}
	this.detourAccess.RLock()
	destExists := false
	for _, r := range this.detours {
		if r.Destination == rec.Destination {
			destExists = true
			// Destination exists, add new user if necessary
			for _, u := range rec.Accounts {
				r.AddUser(u)
			}
			break
		}
	}

	this.detourAccess.RUnlock()
	if !destExists {
		expRec := &ExpiringReceiver{
			Receiver: rec,
			until:    time.Now().Add(time.Duration(availableMin-1) * time.Minute),
		}
		this.detourAccess.Lock()
		this.detours = append(this.detours, expRec)
		this.detourAccess.Unlock()
	}
}

func (this *ReceiverManager) pickDetour() *Receiver {
	if len(this.detours) == 0 {
		return nil
	}
	this.detourAccess.RLock()
	idx := dice.Roll(len(this.detours))
	rec := this.detours[idx]
	this.detourAccess.RUnlock()

	if rec.Expired() {
		this.detourAccess.Lock()
		detourLen := len(this.detours)
		if detourLen > idx && this.detours[idx].Expired() {
			this.detours[idx] = this.detours[detourLen-1]
			this.detours = this.detours[:detourLen-1]
		}
		this.detourAccess.Unlock()
		return nil
	}

	return rec.Receiver
}

func (this *ReceiverManager) pickStdReceiver() *Receiver {
	return this.receivers[dice.Roll(len(this.receivers))]
}

func (this *ReceiverManager) PickReceiver() (v2net.Destination, *vmess.User) {
	rec := this.pickDetour()
	if rec == nil {
		rec = this.pickStdReceiver()
	}
	user := rec.PickUser()

	return rec.Destination, user
}
<|endoftext|>


<commit_before>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

// TODO(wallyworld) bug http://pad.lv/1408459
// Re-enable tests for i386 when these tests are fixed to work on that architecture.

// +build !386

package apiserver_test

import (
	"time"

	"github.com/juju/loggo"
	gitjujutesting "github.com/juju/testing"
	jc "github.com/juju/testing/checkers"
	"github.com/juju/utils"
	gc "gopkg.in/check.v1"

	"github.com/juju/juju/api"
	"github.com/juju/juju/apiserver"
	"github.com/juju/juju/juju/testing"
	"github.com/juju/juju/rpc"
	coretesting "github.com/juju/juju/testing"
)

type pingerSuite struct {
	testing.JujuConnSuite
}

var _ = gc.Suite(&pingerSuite{})

var testPingPeriod = 100 * time.Millisecond

func (s *pingerSuite) TestConnectionBrokenDetection(c *gc.C) {
	s.PatchValue(&api.PingPeriod, testPingPeriod)

	st, _ := s.OpenAPIAsNewMachine(c)

	// Connection still alive
	select {
	case <-time.After(testPingPeriod):
	case <-st.Broken():
		c.Fatalf("connection should be alive still")
	}

	// Close the connection and see if we detect this
	go st.Close()

	// Check it's detected
	select {
	case <-time.After(testPingPeriod + time.Second):
		c.Fatalf("connection not closed as expected")
	case <-st.Broken():
		return
	}
}

func (s *pingerSuite) TestPing(c *gc.C) {
	tw := &loggo.TestWriter{}
	c.Assert(loggo.RegisterWriter("ping-tester", tw, loggo.DEBUG), gc.IsNil)
	defer loggo.RemoveWriter("ping-tester")

	st, _ := s.OpenAPIAsNewMachine(c)
	err := st.Ping()
	c.Assert(err, jc.ErrorIsNil)
	err = st.Close()
	c.Assert(err, jc.ErrorIsNil)
	err = st.Ping()
	c.Assert(err, gc.Equals, rpc.ErrShutdown)

	// Make sure that ping messages have not been logged.
	for _, m := range tw.Log() {
		c.Logf("checking %q", m.Message)
		c.Check(m.Message, gc.Not(gc.Matches), `.*"Request":"Ping".*`)
	}
}

func (s *pingerSuite) TestClientNoNeedToPing(c *gc.C) {
	s.PatchValue(apiserver.MaxClientPingInterval, time.Duration(0))
	st, err := api.Open(s.APIInfo(c), api.DefaultDialOpts())
	c.Assert(err, jc.ErrorIsNil)
	defer st.Close()
	time.Sleep(coretesting.ShortWait)
	err = st.Ping()
	c.Assert(err, jc.ErrorIsNil)
}

func (s *pingerSuite) TestAgentConnectionShutsDownWithNoPing(c *gc.C) {
	s.PatchValue(apiserver.MaxClientPingInterval, time.Duration(0))
	st, _ := s.OpenAPIAsNewMachine(c)
	time.Sleep(coretesting.ShortWait)
	err := st.Ping()
	c.Assert(err, gc.ErrorMatches, "connection is shut down")
}

func (s *pingerSuite) TestAgentConnectionDelaysShutdownWithPing(c *gc.C) {
	const (
		longTimeout  = 30 * time.Minute
		shortTimeout = 10 * time.Millisecond
	)
	timer := time.NewTimer(longTimeout)
	s.PatchValue(apiserver.NewTimer, func(time.Duration) *time.Timer { return timer })

	st, _ := s.OpenAPIAsNewMachine(c)
	err := st.Ping()
	c.Assert(err, jc.ErrorIsNil)
	timer.Reset(longTimeout)
	// As long as we don't wait too long, the connection stays open
	for i := 0; i < 10; i++ {
		time.Sleep(10 * time.Millisecond)
		err = st.Ping()
		c.Assert(err, jc.ErrorIsNil)
		timer.Reset(longTimeout)
	}
	// However, once we stop pinging for too long, the connection dies
	timer.Reset(shortTimeout)
	time.Sleep(2 * shortTimeout)
	err = st.Ping()
	c.Assert(err, gc.ErrorMatches, "connection is shut down")
}

type mongoPingerSuite struct {
	testing.JujuConnSuite
}

var _ = gc.Suite(&mongoPingerSuite{})

func (s *mongoPingerSuite) SetUpSuite(c *gc.C) {
	s.JujuConnSuite.SetUpSuite(c)
	// We need to set the ping interval before the server is started in test setup.
	restore := gitjujutesting.PatchValue(apiserver.MongoPingInterval, coretesting.ShortWait)
	s.AddSuiteCleanup(func(*gc.C) { restore() })
}

func (s *mongoPingerSuite) TestAgentConnectionsShutDownWhenStateDies(c *gc.C) {
	st, _ := s.OpenAPIAsNewMachine(c)
	err := st.Ping()
	c.Assert(err, jc.ErrorIsNil)
	gitjujutesting.MgoServer.Destroy()

	attempt := utils.AttemptStrategy{
		Total: coretesting.LongWait,
		Delay: coretesting.ShortWait,
	}
	for a := attempt.Start(); a.Next(); {
		if err := st.Ping(); err != nil {
			c.Assert(err, gc.ErrorMatches, "connection is shut down")
			return
		}
	}
	c.Fatalf("timed out waiting for API server to die")
}
<commit_msg>Drop longTimeout.<commit_after>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

// TODO(wallyworld) bug http://pad.lv/1408459
// Re-enable tests for i386 when these tests are fixed to work on that architecture.

// +build !386

package apiserver_test

import (
	"time"

	"github.com/juju/loggo"
	gitjujutesting "github.com/juju/testing"
	jc "github.com/juju/testing/checkers"
	"github.com/juju/utils"
	gc "gopkg.in/check.v1"

	"github.com/juju/juju/api"
	"github.com/juju/juju/apiserver"
	"github.com/juju/juju/juju/testing"
	"github.com/juju/juju/rpc"
	coretesting "github.com/juju/juju/testing"
)

type pingerSuite struct {
	testing.JujuConnSuite
}

var _ = gc.Suite(&pingerSuite{})

var testPingPeriod = 100 * time.Millisecond

func (s *pingerSuite) TestConnectionBrokenDetection(c *gc.C) {
	s.PatchValue(&api.PingPeriod, testPingPeriod)

	st, _ := s.OpenAPIAsNewMachine(c)

	// Connection still alive
	select {
	case <-time.After(testPingPeriod):
	case <-st.Broken():
		c.Fatalf("connection should be alive still")
	}

	// Close the connection and see if we detect this
	go st.Close()

	// Check it's detected
	select {
	case <-time.After(testPingPeriod + time.Second):
		c.Fatalf("connection not closed as expected")
	case <-st.Broken():
		return
	}
}

func (s *pingerSuite) TestPing(c *gc.C) {
	tw := &loggo.TestWriter{}
	c.Assert(loggo.RegisterWriter("ping-tester", tw, loggo.DEBUG), gc.IsNil)
	defer loggo.RemoveWriter("ping-tester")

	st, _ := s.OpenAPIAsNewMachine(c)
	err := st.Ping()
	c.Assert(err, jc.ErrorIsNil)
	err = st.Close()
	c.Assert(err, jc.ErrorIsNil)
	err = st.Ping()
	c.Assert(err, gc.Equals, rpc.ErrShutdown)

	// Make sure that ping messages have not been logged.
	for _, m := range tw.Log() {
		c.Logf("checking %q", m.Message)
		c.Check(m.Message, gc.Not(gc.Matches), `.*"Request":"Ping".*`)
	}
}

func (s *pingerSuite) TestClientNoNeedToPing(c *gc.C) {
	s.PatchValue(apiserver.MaxClientPingInterval, time.Duration(0))
	st, err := api.Open(s.APIInfo(c), api.DefaultDialOpts())
	c.Assert(err, jc.ErrorIsNil)
	defer st.Close()
	time.Sleep(coretesting.ShortWait)
	err = st.Ping()
	c.Assert(err, jc.ErrorIsNil)
}

func (s *pingerSuite) TestAgentConnectionShutsDownWithNoPing(c *gc.C) {
	s.PatchValue(apiserver.MaxClientPingInterval, time.Duration(0))
	st, _ := s.OpenAPIAsNewMachine(c)
	time.Sleep(coretesting.ShortWait)
	err := st.Ping()
	c.Assert(err, gc.ErrorMatches, "connection is shut down")
}

func (s *pingerSuite) TestAgentConnectionDelaysShutdownWithPing(c *gc.C) {
	var timer *time.Timer
	s.PatchValue(apiserver.NewTimer, func(d time.Duration) *time.Timer {
		timer = time.NewTimer(d)
		return timer
	})

	st, _ := s.OpenAPIAsNewMachine(c)
	err := st.Ping()
	c.Assert(err, jc.ErrorIsNil)
	// As long as we don't wait too long, the connection stays open
	for i := 0; i < 10; i++ {
		time.Sleep(10 * time.Millisecond)
		err = st.Ping()
		c.Assert(err, jc.ErrorIsNil)
	}
	// However, once we stop pinging for too long, the connection dies
	const shortTimeout = 10 * time.Millisecond
	timer.Reset(shortTimeout)
	time.Sleep(2 * shortTimeout) // Exceed the timeout.
	err = st.Ping()
	c.Assert(err, gc.ErrorMatches, "connection is shut down")
}

type mongoPingerSuite struct {
	testing.JujuConnSuite
}

var _ = gc.Suite(&mongoPingerSuite{})

func (s *mongoPingerSuite) SetUpSuite(c *gc.C) {
	s.JujuConnSuite.SetUpSuite(c)
	// We need to set the ping interval before the server is started in test setup.
	restore := gitjujutesting.PatchValue(apiserver.MongoPingInterval, coretesting.ShortWait)
	s.AddSuiteCleanup(func(*gc.C) { restore() })
}

func (s *mongoPingerSuite) TestAgentConnectionsShutDownWhenStateDies(c *gc.C) {
	st, _ := s.OpenAPIAsNewMachine(c)
	err := st.Ping()
	c.Assert(err, jc.ErrorIsNil)
	gitjujutesting.MgoServer.Destroy()

	attempt := utils.AttemptStrategy{
		Total: coretesting.LongWait,
		Delay: coretesting.ShortWait,
	}
	for a := attempt.Start(); a.Next(); {
		if err := st.Ping(); err != nil {
			c.Assert(err, gc.ErrorMatches, "connection is shut down")
			return
		}
	}
	c.Fatalf("timed out waiting for API server to die")
}
<|endoftext|>


<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/.
//
// Contributor: Julien Vehent jvehent@mozilla.com [:ulfr]
package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"mig"
	"mig/pgp/sign"
	"net/http"
	"net/url"
	"os"
	"os/user"
	"runtime"
	"time"
)

func main() {

	var Usage = func() {
		fmt.Fprintf(os.Stderr,
			"Mozilla InvestiGator Action Generator\n"+
				"usage: %s -k=<key id> (-i <input file)\n\n"+
				"Command line to generate and sign MIG Actions.\n"+
				"The resulting actions are display on stdout.\n\n"+
				"Options:\n",
			os.Args[0])
		flag.PrintDefaults()
	}

	// command line options
	var key = flag.String("k", "key identifier", "Key identifier used to sign the action (ex: B75C2346)")
	var pretty = flag.Bool("p", false, "Print signed action in pretty JSON format")
	var urlencode = flag.Bool("urlencode", false, "URL Encode marshalled JSON before output")
	var posturl = flag.String("posturl", "", "POST action to <url> (enforces urlencode)")
	var file = flag.String("i", "/path/to/file", "Load action from file")
	var target = flag.String("t", "some.target.example.net", "Set the target of the action")
	var validfrom = flag.String("validfrom", "now", "(optional) set an ISO8601 date the action will be valid from. If unset, use 'now'.")
	var expireafter = flag.String("expireafter", "30m", "(optional) set a validity duration for the action. If unset, use '30m'.")
	flag.Parse()

	// We need a key, if none is set on the command line, fail
	if *key == "key identifier" {
		Usage()
		os.Exit(-1)
	}

	var err error

	// if a file is defined, load action from that
	if *file == "/path/to/file" {
		fmt.Println("Missing action file")
		os.Exit(1)
	}
	a, err := mig.ActionFromFile(*file)
	if err != nil {
		panic(err)
	}

	// set the dates
	if *validfrom == "now" {
		// for immediate execution, set validity one minute in the past
		a.ValidFrom = time.Now().Add(-60 * time.Second).UTC()
	} else {
		a.ValidFrom, err = time.Parse("2014-01-01T00:00:00.0Z", *validfrom)
		if err != nil {
			panic(err)
		}
	}
	period, err := time.ParseDuration(*expireafter)
	if err != nil {
		log.Fatal(err)
	}
	a.ExpireAfter = a.ValidFrom.Add(period)

	if *target != "some.target.example.net" {
		a.Target = *target
	}

	// find homedir
	var homedir string
	if runtime.GOOS == "darwin" {
		homedir = os.Getenv("HOME")
	} else {
		// find keyring in default location
		u, err := user.Current()
		if err != nil {
			panic(err)
		}
		homedir = u.HomeDir
	}
	// load keyrings
	var gnupghome string
	gnupghome = os.Getenv("GNUPGHOME")
	if gnupghome == "" {
		gnupghome = "/.gnupg"
	}
	pubringFile, err := os.Open(homedir + gnupghome + "/pubring.gpg")

	if err != nil {
		panic(err)
	}
	defer pubringFile.Close()

	secringFile, err := os.Open(homedir + gnupghome + "/secring.gpg")
	if err != nil {
		panic(err)
	}
	defer secringFile.Close()

	// compute the signature
	str, err := a.String()
	if err != nil {
		panic(err)
	}
	pgpsig, err := sign.Sign(str, *key, secringFile)
	if err != nil {
		panic(err)
	}

	// store the signature in the action signature array
	a.PGPSignatures = append(a.PGPSignatures, pgpsig)

	// syntax checking
	err = a.Validate()
	if err != nil {
		panic(err)
	}

	// signature checking
	err = a.VerifySignatures(pubringFile)
	if err != nil {
		panic(err)
	}

	// if asked, pretty print the action
	var jsonAction []byte
	if *pretty {
		jsonAction, err = json.MarshalIndent(a, "", "\t")
		fmt.Printf("%s\n", jsonAction)
	} else {
		jsonAction, err = json.Marshal(a)
	}
	if err != nil {
		panic(err)
	}

	// if asked, url encode the action before marshaling it
	actionstr := string(jsonAction)
	if *urlencode {
		strJsonAction := string(jsonAction)
		actionstr = url.QueryEscape(strJsonAction)
		if *pretty {
			fmt.Println(actionstr)
		}
	}

	// http post the action to the posturl endpoint
	if *posturl != "" {
		resp, err := http.PostForm(*posturl, url.Values{"action": {actionstr}})
		defer resp.Body.Close()
		if err != nil {
			panic(err)
		}
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			panic(err)
		}
		fmt.Printf("%s", body)
	}
}
<commit_msg>[minor] fix validfrom timestamp creation in action generator<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/.
//
// Contributor: Julien Vehent jvehent@mozilla.com [:ulfr]
package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"mig"
	"mig/pgp/sign"
	"net/http"
	"net/url"
	"os"
	"os/user"
	"runtime"
	"time"
)

func main() {

	var Usage = func() {
		fmt.Fprintf(os.Stderr,
			"Mozilla InvestiGator Action Generator\n"+
				"usage: %s -k=<key id> (-i <input file)\n\n"+
				"Command line to generate and sign MIG Actions.\n"+
				"The resulting actions are display on stdout.\n\n"+
				"Options:\n",
			os.Args[0])
		flag.PrintDefaults()
	}

	// command line options
	var key = flag.String("k", "key identifier", "Key identifier used to sign the action (ex: B75C2346)")
	var pretty = flag.Bool("p", false, "Print signed action in pretty JSON format")
	var urlencode = flag.Bool("urlencode", false, "URL Encode marshalled JSON before output")
	var posturl = flag.String("posturl", "", "POST action to <url> (enforces urlencode)")
	var file = flag.String("i", "/path/to/file", "Load action from file")
	var target = flag.String("t", "some.target.example.net", "Set the target of the action")
	var validfrom = flag.String("validfrom", "now", "(optional) set an ISO8601 date the action will be valid from. If unset, use 'now'.")
	var expireafter = flag.String("expireafter", "30m", "(optional) set a validity duration for the action. If unset, use '30m'.")
	flag.Parse()

	// We need a key, if none is set on the command line, fail
	if *key == "key identifier" {
		Usage()
		os.Exit(-1)
	}

	var err error

	// if a file is defined, load action from that
	if *file == "/path/to/file" {
		fmt.Println("Missing action file")
		os.Exit(1)
	}
	a, err := mig.ActionFromFile(*file)
	if err != nil {
		panic(err)
	}

	// set the dates
	if *validfrom == "now" {
		// for immediate execution, set validity one minute in the past
		a.ValidFrom = time.Now().Add(-60 * time.Second).UTC()
	} else {
		a.ValidFrom, err = time.Parse(time.RFC3339, *validfrom)
		if err != nil {
			panic(err)
		}
	}
	period, err := time.ParseDuration(*expireafter)
	if err != nil {
		log.Fatal(err)
	}
	a.ExpireAfter = a.ValidFrom.Add(period)

	if *target != "some.target.example.net" {
		a.Target = *target
	}

	// find homedir
	var homedir string
	if runtime.GOOS == "darwin" {
		homedir = os.Getenv("HOME")
	} else {
		// find keyring in default location
		u, err := user.Current()
		if err != nil {
			panic(err)
		}
		homedir = u.HomeDir
	}
	// load keyrings
	var gnupghome string
	gnupghome = os.Getenv("GNUPGHOME")
	if gnupghome == "" {
		gnupghome = "/.gnupg"
	}
	pubringFile, err := os.Open(homedir + gnupghome + "/pubring.gpg")

	if err != nil {
		panic(err)
	}
	defer pubringFile.Close()

	secringFile, err := os.Open(homedir + gnupghome + "/secring.gpg")
	if err != nil {
		panic(err)
	}
	defer secringFile.Close()

	// compute the signature
	str, err := a.String()
	if err != nil {
		panic(err)
	}
	pgpsig, err := sign.Sign(str, *key, secringFile)
	if err != nil {
		panic(err)
	}

	// store the signature in the action signature array
	a.PGPSignatures = append(a.PGPSignatures, pgpsig)

	// syntax checking
	err = a.Validate()
	if err != nil {
		panic(err)
	}

	// signature checking
	err = a.VerifySignatures(pubringFile)
	if err != nil {
		panic(err)
	}

	// if asked, pretty print the action
	var jsonAction []byte
	if *pretty {
		jsonAction, err = json.MarshalIndent(a, "", "\t")
		fmt.Printf("%s\n", jsonAction)
	} else {
		jsonAction, err = json.Marshal(a)
	}
	if err != nil {
		panic(err)
	}

	// if asked, url encode the action before marshaling it
	actionstr := string(jsonAction)
	if *urlencode {
		strJsonAction := string(jsonAction)
		actionstr = url.QueryEscape(strJsonAction)
		if *pretty {
			fmt.Println(actionstr)
		}
	}

	// http post the action to the posturl endpoint
	if *posturl != "" {
		resp, err := http.PostForm(*posturl, url.Values{"action": {actionstr}})
		defer resp.Body.Close()
		if err != nil {
			panic(err)
		}
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			panic(err)
		}
		fmt.Printf("%s", body)
	}
}
<|endoftext|>


<commit_before>package messageApp

import (
	"fmt"
	"strings"
	"strconv"
)

type IntervalBit struct {
	sInterval	string
	name	string
	boundary Bits
	intervals	[]Bits
	duration	int
}

type Bits struct {
	all	bool
	min	int
	max	int
}

// Definition of types of IntervalBit, used with pos to determine the kind of interval
var (
	bitsDef = []IntervalBit{
		IntervalBit{"2000-3000",	"Year",			Bits{false, 2000, 3000},	[]Bits{},	365},
		IntervalBit{"1-12",		"Month",			Bits{false, 1, 12},		[]Bits{},	31},
		IntervalBit{"1-31",		"Day of month",	Bits{false, 1, 31},		[]Bits{},	24},
		IntervalBit{"1-7",		"Day of week",		Bits{false, 1, 7},			[]Bits{},	24},
		IntervalBit{"0-23",		"Hour",			Bits{false, 0, 23},		[]Bits{},	60},
		IntervalBit{"0-59",		"Minute",			Bits{false, 0, 59},		[]Bits{},	1},
	}
)

// String conversion for a Bits
func (b Bits) String() string {
	if b.all == true {
		return "*"
	}
	s :=  fmt.Sprintf("%d-%d", b.min, b.max)
	return s
}

// String conversion for an IntervalBit
func (ib *IntervalBit) String() string {
	s := "<" + ib.name +":"
	for _, val := range ib.intervals {
		s += val.String() + ","
	}
	s = s[0:len(s)-1] + ">"
	return s
}

// create an IntervalBit using an intervalString and a position
func NewIntervalBit(s string, pos int) *IntervalBit {
	ib := new(IntervalBit)
	pos = pos-1
	ib.sInterval = s
	ib.name = bitsDef[pos].name
	ib.boundary = bitsDef[pos].boundary
	ib.duration = bitsDef[pos].duration
	ib.createIntervals(s)

	return ib
}

func (ib *IntervalBit) createIntervals(s string) {
	bits := strings.Split(s, ",")
	l := len(bits)
	allBits := make([]Bits, l)
	for i, val := range bits {
		thisBit := Bits{false, 0, 0}
		if val == "*" {
			thisBit.all = true
			allBits[i] = thisBit
			continue
		}
		parts := strings.Split(val, "-")
		thisBit.min, _ = strconv.Atoi(strings.Trim(parts[0], " "))
		if len(parts) == 1 {
			thisBit.max = thisBit.min
		} else {
			thisBit.max, _ = strconv.Atoi(strings.Trim(parts[1], " "))
		}
		// TODO: this should exclude the Bits to be in ib.intervals
		if ib.boundary.min<=thisBit.min && thisBit.min<=ib.boundary.max && ib.boundary.min<=thisBit.max && thisBit.max<=ib.boundary.max {
			allBits[i] = thisBit
		} else {
			fmt.Printf("%s: %s could not fit in boundary %s\n", ib, val, ib.boundary)
		}
	}
	ib.intervals = allBits
}

func (ib *IntervalBit)  DoesItFit(time int) bool {
	for _, bit := range ib.intervals {
		if bit.all == true || (bit.min <= time && time <= bit.max) {
			return true
		}
	}
	return false
}<commit_msg>IntervalBits: do not create empty bits from invalid string<commit_after>package messageApp

import (
	"fmt"
	"strings"
	"strconv"
)

type IntervalBit struct {
	sInterval	string
	name	string
	boundary Bits
	intervals	[]Bits
	duration	int
}

type Bits struct {
	all	bool
	min	int
	max	int
}

// Definition of types of IntervalBit, used with pos to determine the kind of interval
var (
	bitsDef = []IntervalBit{
		IntervalBit{"2000-3000",	"Year",			Bits{false, 2000, 3000},	[]Bits{},	365},
		IntervalBit{"1-12",		"Month",			Bits{false, 1, 12},		[]Bits{},	31},
		IntervalBit{"1-31",		"Day of month",	Bits{false, 1, 31},		[]Bits{},	24},
		IntervalBit{"1-7",		"Day of week",		Bits{false, 1, 7},			[]Bits{},	24},
		IntervalBit{"0-23",		"Hour",			Bits{false, 0, 23},		[]Bits{},	60},
		IntervalBit{"0-59",		"Minute",			Bits{false, 0, 59},		[]Bits{},	1},
	}
)

func (ib *IntervalBit) DoesItFit(time int) bool {
	for _, bit := range ib.intervals {
		if bit.all == true || (bit.min <= time && time <= bit.max) {
			return true
		}
	}
	return false
}

// create an IntervalBit using an intervalString and a position
func NewIntervalBit(s string, pos int) *IntervalBit {
	ib := new(IntervalBit)
	pos = pos-1
	ib.sInterval = s
	ib.name = bitsDef[pos].name
	ib.boundary = bitsDef[pos].boundary
	ib.duration = bitsDef[pos].duration
	ib.createIntervals(s)
	return ib
}

// create an array of intervals from a string like '6,45-50,*'
func (ib *IntervalBit) createIntervals(s string) {
	bits := strings.Split(s, ",")
	allBits := make([]Bits, len(bits))
	nValidBits := 0
	for _, val := range bits {
		thisBit := Bits{false, 0, 0}
		if val == "*" {
			thisBit.all = true
			allBits[nValidBits] = thisBit
			nValidBits++
			continue
		}
		parts := strings.Split(val, "-")
		thisBit.min, _ = strconv.Atoi(strings.Trim(parts[0], " "))
		if len(parts) == 1 {
			thisBit.max = thisBit.min
		} else {
			thisBit.max, _ = strconv.Atoi(strings.Trim(parts[1], " "))
		}
		if ib.boundary.min<=thisBit.min && thisBit.min<=ib.boundary.max &&
		   ib.boundary.min<=thisBit.max && thisBit.max<=ib.boundary.max {
			allBits[nValidBits] = thisBit
			nValidBits++
		} else {
			fmt.Printf("%s: %s could not fit in boundary %s\n", ib, val, ib.boundary)
		}
	}
	ib.intervals = allBits[0:nValidBits]
}

// Pretty print for a Bits
func (b Bits) String() string {
	if b.all == true {
		return "*"
	}
	s :=  fmt.Sprintf("%d-%d", b.min, b.max)
	return s
}

// Pretty print for an IntervalBit
func (ib *IntervalBit) String() string {
	s := "<" + ib.name +": "
	for _, val := range ib.intervals {
		s += val.String() + ","
	}
	s = s[0:len(s)-1] + ">"
	return s
}

<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"net/url"
	"os"
	"os/exec"
	"strings"

	"github.com/coreos/go-etcd/etcd"
)

func ParseDiscovery() (discoveryHost, discoveryPath string) {
	// Pull the ETCD_DISCOVERY env var and parse it for the etcd client usage
	file := "/mnt/20-cloudinit.conf"
	cmd := fmt.Sprintf("cat %s | grep ETCD_DISCOVERY | cut -d '=' -f 3 | cut -d '\"' -f 1", file)
	out, err := exec.Command("sh", "-c", cmd).Output()

	discoveryURL := string(out)

	u, err := url.Parse(discoveryURL)
	if err != nil {
		panic(err)
	}

	discoveryHost = fmt.Sprintf("%s://%s", u.Scheme, u.Host)

	path := strings.Split(u.Path, "/keys/")[1]
	path = strings.Replace(path, "\n", "", -1)
	discoveryPath = path

	return discoveryHost, discoveryPath
}

func main() {
	discoveryHost, discoveryPath := ParseDiscovery()

	// Connect to the etcd discovery to pull the nodes
	client := etcd.NewClient([]string{discoveryHost})
	resp, err := client.Get(discoveryPath, true, false)

	if err != nil {
		log.Printf("%s", err)
		os.Exit(2)
	}

	for _, n := range resp.Node.Nodes {
		log.Printf("%s: %s\n", n.Key, n.Value)
	}
}
<commit_msg>Pull the nodes in cluster via local etcd API<commit_after>package main

import (
	"encoding/json"
	"log"

	"github.com/coreos/go-etcd/etcd"
)

type ETCDMachine map[string]interface{}

type ETCDMachines []ETCDMachine

func checkForErrors(err error) {
	if err != nil {
		panic(err)
	}
}

func main() {
	discoveryHost := "http://127.0.0.1:7001"
	discoveryPath := "admin/machines"

	// Connect to the etcd discovery to pull the nodes
	client := etcd.NewClient([]string{discoveryHost})
	req := etcd.NewRawRequest("GET", discoveryPath, nil, nil)
	rawRespPtr, err := client.SendRequest(req)
	checkForErrors(err)

	jsonResponse := rawRespPtr.Body

	var etcdMachines ETCDMachines
	err = json.Unmarshal(jsonResponse, &etcdMachines)

	checkForErrors(err)

	for _, etcdMachine := range etcdMachines {
		log.Printf("%s -- %s -- %s -- %s\n", etcdMachine["name"], etcdMachine["state"], etcdMachine["clientURL"], etcdMachine["peerURL"])
	}

}
<|endoftext|>


<commit_before>package google

import (
	"fmt"
	"io/ioutil"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/docker/machine/ssh"
	raw "google.golang.org/api/compute/v1"
)

// ComputeUtil is used to wrap the raw GCE API code and store common parameters.
type ComputeUtil struct {
	zone         string
	instanceName string
	userName     string
	project      string
	service      *raw.Service
	zoneURL      string
	globalURL    string
	ipAddress    string
}

const (
	apiURL = "https://www.googleapis.com/compute/v1/projects/"
	//imageName          = "https://www.googleapis.com/compute/v1/projects/google-containers/global/images/container-vm-v20141016"
	imageName          = "https://www.googleapis.com/compute/v1/projects/ubuntu-os-cloud/global/images/ubuntu-1404-trusty-v20141212"
	firewallRule       = "docker-machines"
	port               = "2376"
	firewallTargetTag  = "docker-machine"
	dockerStartCommand = "sudo service docker start"
	dockerStopCommand  = "sudo service docker stop"
)

const ()

// NewComputeUtil creates and initializes a ComputeUtil.
func newComputeUtil(driver *Driver) (*ComputeUtil, error) {
	service, err := newGCEService(driver.storePath)
	if err != nil {
		return nil, err
	}
	c := ComputeUtil{
		zone:         driver.Zone,
		instanceName: driver.MachineName,
		userName:     driver.UserName,
		project:      driver.Project,
		service:      service,
		zoneURL:      apiURL + driver.Project + "/zones/" + driver.Zone,
		globalURL:    apiURL + driver.Project + "/global",
	}
	return &c, nil
}

func (c *ComputeUtil) diskName() string {
	return c.instanceName + "-disk"
}

// disk returns the gce Disk.
func (c *ComputeUtil) disk() (*raw.Disk, error) {
	return c.service.Disks.Get(c.project, c.zone, c.diskName()).Do()
}

// deleteDisk deletes the persistent disk.
func (c *ComputeUtil) deleteDisk() error {
	log.Infof("Deleting disk.")
	op, err := c.service.Disks.Delete(c.project, c.zone, c.diskName()).Do()
	if err != nil {
		return err
	}
	log.Infof("Waiting for disk to delete.")
	return c.waitForRegionalOp(op.Name)
}

func (c *ComputeUtil) firewallRule() (*raw.Firewall, error) {
	return c.service.Firewalls.Get(c.project, firewallRule).Do()
}

func (c *ComputeUtil) createFirewallRule() error {
	log.Infof("Creating firewall rule.")
	rule := &raw.Firewall{
		Allowed: []*raw.FirewallAllowed{
			{
				IPProtocol: "tcp",
				Ports: []string{
					port,
				},
			},
		},
		SourceRanges: []string{
			"0.0.0.0/0",
		},
		TargetTags: []string{
			firewallTargetTag,
		},
		Name: firewallRule,
	}
	op, err := c.service.Firewalls.Insert(c.project, rule).Do()
	if err != nil {
		return err
	}
	return c.waitForGlobalOp(op.Name)
}

// instance retrieves the instance.
func (c *ComputeUtil) instance() (*raw.Instance, error) {
	return c.service.Instances.Get(c.project, c.zone, c.instanceName).Do()
}

// createInstance creates a GCE VM instance.
func (c *ComputeUtil) createInstance(d *Driver) error {
	log.Infof("Creating instance.")
	// The rule will either exist or be nil in case of an error.
	if rule, _ := c.firewallRule(); rule == nil {
		if err := c.createFirewallRule(); err != nil {
			return err
		}
	}

	instance := &raw.Instance{
		Name:        c.instanceName,
		Description: "docker host vm",
		MachineType: c.zoneURL + "/machineTypes/" + d.MachineType,
		Disks: []*raw.AttachedDisk{
			{
				Boot:       true,
				AutoDelete: false,
				Type:       "PERSISTENT",
				Mode:       "READ_WRITE",
			},
		},
		NetworkInterfaces: []*raw.NetworkInterface{
			{
				AccessConfigs: []*raw.AccessConfig{
					{Type: "ONE_TO_ONE_NAT"},
				},
				Network: c.globalURL + "/networks/default",
			},
		},
		Tags: &raw.Tags{
			Items: []string{
				firewallTargetTag,
			},
		},
	}
	disk, err := c.disk()
	if disk == nil || err != nil {
		instance.Disks[0].InitializeParams = &raw.AttachedDiskInitializeParams{
			DiskName:    c.diskName(),
			SourceImage: imageName,
			// The maximum supported disk size is 1000GB, the cast should be fine.
			DiskSizeGb: int64(d.DiskSize),
		}
	} else {
		instance.Disks[0].Source = c.zoneURL + "/disks/" + c.instanceName + "-disk"
	}
	op, err := c.service.Instances.Insert(c.project, c.zone, instance).Do()

	if err != nil {
		return err
	}
	log.Infof("Waiting for Instance...")
	if err = c.waitForRegionalOp(op.Name); err != nil {
		return err
	}

	instance, err = c.instance()
	if err != nil {
		return err
	}
	ip := instance.NetworkInterfaces[0].AccessConfigs[0].NatIP
	c.waitForSSH(ip)

	// Update the SSH Key
	sshKey, err := ioutil.ReadFile(d.publicSSHKeyPath)
	if err != nil {
		return err
	}
	log.Infof("Uploading SSH Key")
	op, err = c.service.Instances.SetMetadata(c.project, c.zone, c.instanceName, &raw.Metadata{
		Fingerprint: instance.Metadata.Fingerprint,
		Items: []*raw.MetadataItems{
			{
				Key:   "sshKeys",
				Value: c.userName + ":" + string(sshKey) + "\n",
			},
		},
	}).Do()
	if err != nil {
		return err
	}
	log.Infof("Waiting for SSH Key")
	err = c.waitForRegionalOp(op.Name)
	if err != nil {
		return err
	}

	log.Debugf("Setting hostname: %s", d.MachineName)
	cmd, err := d.GetSSHCommand(fmt.Sprintf(
		"echo \"127.0.0.1 %s\" | sudo tee -a /etc/hosts && sudo hostname %s && echo \"%s\" | sudo tee /etc/hostname",
		d.MachineName,
		d.MachineName,
		d.MachineName,
	))

	if err != nil {
		return err
	}
	if err := cmd.Run(); err != nil {
		return err
	}

	log.Debugf("Installing Docker")

	cmd, err = d.GetSSHCommand("if [ ! -e /usr/bin/docker ]; then curl -sL https://get.docker.com | sudo sh -; fi")
	if err != nil {
		return err

	}
	if err := cmd.Run(); err != nil {
		return err

	}

	return nil
}

func (c *ComputeUtil) updateDocker(d *Driver) error {
	log.Debugf("Upgrading Docker")

	cmd, err := d.GetSSHCommand("sudo apt-get update && sudo apt-get install --upgrade lxc-docker")
	if err != nil {
		return err

	}
	if err := cmd.Run(); err != nil {
		return err

	}

	return nil
}

// deleteInstance deletes the instance, leaving the persistent disk.
func (c *ComputeUtil) deleteInstance() error {
	log.Infof("Deleting instance.")
	op, err := c.service.Instances.Delete(c.project, c.zone, c.instanceName).Do()
	if err != nil {
		return err
	}
	log.Infof("Waiting for instance to delete.")
	return c.waitForRegionalOp(op.Name)
}

func (c *ComputeUtil) executeCommands(commands []string, ip, sshKeyPath string) error {
	for _, command := range commands {
		cmd := ssh.GetSSHCommand(ip, 22, c.userName, sshKeyPath, command)
		if err := cmd.Run(); err != nil {
			return fmt.Errorf("error executing command: %v %v", command, err)
		}
	}
	return nil
}

func (c *ComputeUtil) waitForOp(opGetter func() (*raw.Operation, error)) error {
	for {
		op, err := opGetter()
		if err != nil {
			return err
		}
		log.Debugf("operation %q status: %s", op.Name, op.Status)
		if op.Status == "DONE" {
			if op.Error != nil {
				return fmt.Errorf("Operation error: %v", *op.Error.Errors[0])
			}
			break
		}
		time.Sleep(1 * time.Second)
	}
	return nil
}

// waitForOp waits for the GCE Operation to finish.
func (c *ComputeUtil) waitForRegionalOp(name string) error {
	return c.waitForOp(func() (*raw.Operation, error) {
		return c.service.ZoneOperations.Get(c.project, c.zone, name).Do()
	})
}

func (c *ComputeUtil) waitForGlobalOp(name string) error {
	return c.waitForOp(func() (*raw.Operation, error) {
		return c.service.GlobalOperations.Get(c.project, name).Do()
	})
}

// waitForSSH waits for SSH to become ready on the instance.
func (c *ComputeUtil) waitForSSH(ip string) error {
	log.Infof("Waiting for SSH...")
	return ssh.WaitForTCP(fmt.Sprintf("%s:22", ip))
}

// ip retrieves and returns the external IP address of the instance.
func (c *ComputeUtil) ip() (string, error) {
	if c.ipAddress == "" {
		instance, err := c.service.Instances.Get(c.project, c.zone, c.instanceName).Do()
		if err != nil {
			return "", err
		}
		c.ipAddress = instance.NetworkInterfaces[0].AccessConfigs[0].NatIP
	}
	return c.ipAddress, nil
}
<commit_msg>Update GCE VM images to latest release versions.<commit_after>package google

import (
	"fmt"
	"io/ioutil"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/docker/machine/ssh"
	raw "google.golang.org/api/compute/v1"
)

// ComputeUtil is used to wrap the raw GCE API code and store common parameters.
type ComputeUtil struct {
	zone         string
	instanceName string
	userName     string
	project      string
	service      *raw.Service
	zoneURL      string
	globalURL    string
	ipAddress    string
}

const (
	apiURL = "https://www.googleapis.com/compute/v1/projects/"
	//imageName          = "https://www.googleapis.com/compute/v1/projects/google-containers/global/images/container-vm-v20150129"
	imageName          = "https://www.googleapis.com/compute/v1/projects/ubuntu-os-cloud/global/images/ubuntu-1404-trusty-v20150128"
	firewallRule       = "docker-machines"
	port               = "2376"
	firewallTargetTag  = "docker-machine"
	dockerStartCommand = "sudo service docker start"
	dockerStopCommand  = "sudo service docker stop"
)

const ()

// NewComputeUtil creates and initializes a ComputeUtil.
func newComputeUtil(driver *Driver) (*ComputeUtil, error) {
	service, err := newGCEService(driver.storePath)
	if err != nil {
		return nil, err
	}
	c := ComputeUtil{
		zone:         driver.Zone,
		instanceName: driver.MachineName,
		userName:     driver.UserName,
		project:      driver.Project,
		service:      service,
		zoneURL:      apiURL + driver.Project + "/zones/" + driver.Zone,
		globalURL:    apiURL + driver.Project + "/global",
	}
	return &c, nil
}

func (c *ComputeUtil) diskName() string {
	return c.instanceName + "-disk"
}

// disk returns the gce Disk.
func (c *ComputeUtil) disk() (*raw.Disk, error) {
	return c.service.Disks.Get(c.project, c.zone, c.diskName()).Do()
}

// deleteDisk deletes the persistent disk.
func (c *ComputeUtil) deleteDisk() error {
	log.Infof("Deleting disk.")
	op, err := c.service.Disks.Delete(c.project, c.zone, c.diskName()).Do()
	if err != nil {
		return err
	}
	log.Infof("Waiting for disk to delete.")
	return c.waitForRegionalOp(op.Name)
}

func (c *ComputeUtil) firewallRule() (*raw.Firewall, error) {
	return c.service.Firewalls.Get(c.project, firewallRule).Do()
}

func (c *ComputeUtil) createFirewallRule() error {
	log.Infof("Creating firewall rule.")
	rule := &raw.Firewall{
		Allowed: []*raw.FirewallAllowed{
			{
				IPProtocol: "tcp",
				Ports: []string{
					port,
				},
			},
		},
		SourceRanges: []string{
			"0.0.0.0/0",
		},
		TargetTags: []string{
			firewallTargetTag,
		},
		Name: firewallRule,
	}
	op, err := c.service.Firewalls.Insert(c.project, rule).Do()
	if err != nil {
		return err
	}
	return c.waitForGlobalOp(op.Name)
}

// instance retrieves the instance.
func (c *ComputeUtil) instance() (*raw.Instance, error) {
	return c.service.Instances.Get(c.project, c.zone, c.instanceName).Do()
}

// createInstance creates a GCE VM instance.
func (c *ComputeUtil) createInstance(d *Driver) error {
	log.Infof("Creating instance.")
	// The rule will either exist or be nil in case of an error.
	if rule, _ := c.firewallRule(); rule == nil {
		if err := c.createFirewallRule(); err != nil {
			return err
		}
	}

	instance := &raw.Instance{
		Name:        c.instanceName,
		Description: "docker host vm",
		MachineType: c.zoneURL + "/machineTypes/" + d.MachineType,
		Disks: []*raw.AttachedDisk{
			{
				Boot:       true,
				AutoDelete: false,
				Type:       "PERSISTENT",
				Mode:       "READ_WRITE",
			},
		},
		NetworkInterfaces: []*raw.NetworkInterface{
			{
				AccessConfigs: []*raw.AccessConfig{
					{Type: "ONE_TO_ONE_NAT"},
				},
				Network: c.globalURL + "/networks/default",
			},
		},
		Tags: &raw.Tags{
			Items: []string{
				firewallTargetTag,
			},
		},
	}
	disk, err := c.disk()
	if disk == nil || err != nil {
		instance.Disks[0].InitializeParams = &raw.AttachedDiskInitializeParams{
			DiskName:    c.diskName(),
			SourceImage: imageName,
			// The maximum supported disk size is 1000GB, the cast should be fine.
			DiskSizeGb: int64(d.DiskSize),
		}
	} else {
		instance.Disks[0].Source = c.zoneURL + "/disks/" + c.instanceName + "-disk"
	}
	op, err := c.service.Instances.Insert(c.project, c.zone, instance).Do()

	if err != nil {
		return err
	}
	log.Infof("Waiting for Instance...")
	if err = c.waitForRegionalOp(op.Name); err != nil {
		return err
	}

	instance, err = c.instance()
	if err != nil {
		return err
	}
	ip := instance.NetworkInterfaces[0].AccessConfigs[0].NatIP
	c.waitForSSH(ip)

	// Update the SSH Key
	sshKey, err := ioutil.ReadFile(d.publicSSHKeyPath)
	if err != nil {
		return err
	}
	log.Infof("Uploading SSH Key")
	op, err = c.service.Instances.SetMetadata(c.project, c.zone, c.instanceName, &raw.Metadata{
		Fingerprint: instance.Metadata.Fingerprint,
		Items: []*raw.MetadataItems{
			{
				Key:   "sshKeys",
				Value: c.userName + ":" + string(sshKey) + "\n",
			},
		},
	}).Do()
	if err != nil {
		return err
	}
	log.Infof("Waiting for SSH Key")
	err = c.waitForRegionalOp(op.Name)
	if err != nil {
		return err
	}

	log.Debugf("Setting hostname: %s", d.MachineName)
	cmd, err := d.GetSSHCommand(fmt.Sprintf(
		"echo \"127.0.0.1 %s\" | sudo tee -a /etc/hosts && sudo hostname %s && echo \"%s\" | sudo tee /etc/hostname",
		d.MachineName,
		d.MachineName,
		d.MachineName,
	))

	if err != nil {
		return err
	}
	if err := cmd.Run(); err != nil {
		return err
	}

	log.Debugf("Installing Docker")

	cmd, err = d.GetSSHCommand("if [ ! -e /usr/bin/docker ]; then curl -sL https://get.docker.com | sudo sh -; fi")
	if err != nil {
		return err

	}
	if err := cmd.Run(); err != nil {
		return err

	}

	return nil
}

func (c *ComputeUtil) updateDocker(d *Driver) error {
	log.Debugf("Upgrading Docker")

	cmd, err := d.GetSSHCommand("sudo apt-get update && sudo apt-get install --upgrade lxc-docker")
	if err != nil {
		return err

	}
	if err := cmd.Run(); err != nil {
		return err

	}

	return nil
}

// deleteInstance deletes the instance, leaving the persistent disk.
func (c *ComputeUtil) deleteInstance() error {
	log.Infof("Deleting instance.")
	op, err := c.service.Instances.Delete(c.project, c.zone, c.instanceName).Do()
	if err != nil {
		return err
	}
	log.Infof("Waiting for instance to delete.")
	return c.waitForRegionalOp(op.Name)
}

func (c *ComputeUtil) executeCommands(commands []string, ip, sshKeyPath string) error {
	for _, command := range commands {
		cmd := ssh.GetSSHCommand(ip, 22, c.userName, sshKeyPath, command)
		if err := cmd.Run(); err != nil {
			return fmt.Errorf("error executing command: %v %v", command, err)
		}
	}
	return nil
}

func (c *ComputeUtil) waitForOp(opGetter func() (*raw.Operation, error)) error {
	for {
		op, err := opGetter()
		if err != nil {
			return err
		}
		log.Debugf("operation %q status: %s", op.Name, op.Status)
		if op.Status == "DONE" {
			if op.Error != nil {
				return fmt.Errorf("Operation error: %v", *op.Error.Errors[0])
			}
			break
		}
		time.Sleep(1 * time.Second)
	}
	return nil
}

// waitForOp waits for the GCE Operation to finish.
func (c *ComputeUtil) waitForRegionalOp(name string) error {
	return c.waitForOp(func() (*raw.Operation, error) {
		return c.service.ZoneOperations.Get(c.project, c.zone, name).Do()
	})
}

func (c *ComputeUtil) waitForGlobalOp(name string) error {
	return c.waitForOp(func() (*raw.Operation, error) {
		return c.service.GlobalOperations.Get(c.project, name).Do()
	})
}

// waitForSSH waits for SSH to become ready on the instance.
func (c *ComputeUtil) waitForSSH(ip string) error {
	log.Infof("Waiting for SSH...")
	return ssh.WaitForTCP(fmt.Sprintf("%s:22", ip))
}

// ip retrieves and returns the external IP address of the instance.
func (c *ComputeUtil) ip() (string, error) {
	if c.ipAddress == "" {
		instance, err := c.service.Instances.Get(c.project, c.zone, c.instanceName).Do()
		if err != nil {
			return "", err
		}
		c.ipAddress = instance.NetworkInterfaces[0].AccessConfigs[0].NatIP
	}
	return c.ipAddress, nil
}
<|endoftext|>


<commit_before>package kview

import (
    "os"
    "io"
    "log"
    "path"
    "reflect"
    "fmt"
    "github.com/ziutek/kasia.go"
)

var (
    // You can modify this, if you store templates in a different directory.
    TemplatesDir = "templates"

    // You can modify this, if want a different error handling.
    ErrorHandler = func(name string, err os.Error) {
        log.Printf("%%View '%s' error. %s\n", name, err.String())
    }
)

type View interface {
    Copy() View
    Strict(bool)
    Div(string, View)
    Exec(io.Writer, ...interface{})
    Render(...interface{}) *kasia.NestedTemplate
}

// View definition
type KView struct {
    name    string
    tpl     *kasia.Template
    globals map[string]interface{}
}

// Returns a pointer to a page
func New(name string, globals ...map[string]interface{}) *KView {
    var (
        pg  KView
        err os.Error
    )
    pg.name = name
    pg.tpl, err = kasia.ParseFile(path.Join(TemplatesDir, name))
    if err != nil {
        ErrorHandler(name, err)
    }
    pg.globals = make(map[string]interface{})
    // First some default utils
    for k, v := range utils {
        pg.globals[k] = v
    }
    // globals may redefine utils
    for _, g := range globals {
        for k, v := range g {
            pg.globals[k] = v
        }
    }
    return &pg
}

// Returns a pointer to a copy of the page
func (pg *KView) Copy() View {
    new_pg := *pg
    // Make a copy of globals
    new_pg.globals = make(map[string]interface{})
    for k, v := range pg.globals {
        new_pg.globals[k] = v
    }
    return &new_pg
}

// Set strig render flag
func (pg *KView) Strict(strict bool) {
    pg.tpl.Strict = strict
}

// Add subview
func (pg *KView) Div(name string, view View) {
    pg.globals[name] = view
}

func prepend(slice []interface{}, pre ...interface{}) (ret []interface{}) {
    ret = make([]interface{}, len(slice) + len(pre))
    copy(ret, pre)
    copy(ret[len(pre):], slice)
    return
}

// Render view to wr with data
func (pg *KView) Exec(wr io.Writer, ctx ...interface{}) {
    // Add globals to the bottom of the context stack
    ctx = prepend(ctx, pg.globals)
    err := pg.tpl.Run(wr, ctx...)
    if err != nil {
        ErrorHandler(pg.name, err)
    }
}

// Use this method in template text to render page inside other page.
func (pg *KView) Render(ctx ...interface{}) *kasia.NestedTemplate {
    if len(ctx) > 0 {
        // Check if render was called with full template context as first arg
        if ci, ok := ctx[0].(kasia.ContextItself); ok {
            // Rearange context, remove old globals
            ctx = append(ci[1:], ctx[1:])
        }
    }
    // Add globals to the bottom of the context stack
    ctx = prepend(ctx, pg.globals)
    return pg.tpl.Nested(ctx...)
}

// Some useful functions for globals
var utils = map[string]interface{} {
    "len": func(a interface{}) int {
        v := reflect.ValueOf(a)
        if v.Kind() == reflect.Array || v.Kind() == reflect.Slice {
            return v.Len()
        }
        return -1
    },
    "fmt": fmt.Sprintf,
}
<commit_msg>Package doc comment added<commit_after>// Wrapper for kasia.go templates designed for easy writing web applications.
package kview

import (
    "os"
    "io"
    "log"
    "path"
    "reflect"
    "fmt"
    "github.com/ziutek/kasia.go"
)

var (
    // You can modify this, if you store templates in a different directory.
    TemplatesDir = "templates"

    // You can modify this, if want a different error handling.
    ErrorHandler = func(name string, err os.Error) {
        log.Printf("%%View '%s' error. %s\n", name, err.String())
    }
)

type View interface {
    Copy() View
    Strict(bool)
    Div(string, View)
    Exec(io.Writer, ...interface{})
    Render(...interface{}) *kasia.NestedTemplate
}

// View definition
type KView struct {
    name    string
    tpl     *kasia.Template
    globals map[string]interface{}
}

// Returns a pointer to a page
func New(name string, globals ...map[string]interface{}) *KView {
    var (
        pg  KView
        err os.Error
    )
    pg.name = name
    pg.tpl, err = kasia.ParseFile(path.Join(TemplatesDir, name))
    if err != nil {
        ErrorHandler(name, err)
    }
    pg.globals = make(map[string]interface{})
    // First some default utils
    for k, v := range utils {
        pg.globals[k] = v
    }
    // globals may redefine utils
    for _, g := range globals {
        for k, v := range g {
            pg.globals[k] = v
        }
    }
    return &pg
}

// Returns a pointer to a copy of the page
func (pg *KView) Copy() View {
    new_pg := *pg
    // Make a copy of globals
    new_pg.globals = make(map[string]interface{})
    for k, v := range pg.globals {
        new_pg.globals[k] = v
    }
    return &new_pg
}

// Set strig render flag
func (pg *KView) Strict(strict bool) {
    pg.tpl.Strict = strict
}

// Add subview
func (pg *KView) Div(name string, view View) {
    pg.globals[name] = view
}

func prepend(slice []interface{}, pre ...interface{}) (ret []interface{}) {
    ret = make([]interface{}, len(slice) + len(pre))
    copy(ret, pre)
    copy(ret[len(pre):], slice)
    return
}

// Render view to wr with data
func (pg *KView) Exec(wr io.Writer, ctx ...interface{}) {
    // Add globals to the bottom of the context stack
    ctx = prepend(ctx, pg.globals)
    err := pg.tpl.Run(wr, ctx...)
    if err != nil {
        ErrorHandler(pg.name, err)
    }
}

// Use this method in template text to render page inside other page.
func (pg *KView) Render(ctx ...interface{}) *kasia.NestedTemplate {
    if len(ctx) > 0 {
        // Check if render was called with full template context as first arg
        if ci, ok := ctx[0].(kasia.ContextItself); ok {
            // Rearange context, remove old globals
            ctx = append(ci[1:], ctx[1:])
        }
    }
    // Add globals to the bottom of the context stack
    ctx = prepend(ctx, pg.globals)
    return pg.tpl.Nested(ctx...)
}

// Some useful functions for globals
var utils = map[string]interface{} {
    "len": func(a interface{}) int {
        v := reflect.ValueOf(a)
        if v.Kind() == reflect.Array || v.Kind() == reflect.Slice {
            return v.Len()
        }
        return -1
    },
    "fmt": fmt.Sprintf,
}
<|endoftext|>