<commit_before>package polygen

import (
	"fmt"
	"github.com/llgcode/draw2d/draw2dimg"
	"image"
	"image/color"
	"math/rand"
	"log"
)

const (
	MutationAlpha            = iota
	MutationColor            = iota
	MutationPoint            = iota
	MutationZOrder           = iota
	MutationAddOrDeletePoint = iota
)

const (
	MutationChance           = 0.25
	PopulationCount          = 10
	PolygonsPerIndividual    = 50
	MaxPolygonPoints         = 6
	MinPolygonPoints         = 3
	PointMutationMaxDistance = 5
)

var (
	Mutations = []int{MutationColor, MutationPoint, MutationZOrder, MutationAddOrDeletePoint, MutationAlpha}
)

func init() {
	log.Printf("MutationAlpha: %d", MutationAlpha)
	log.Printf("MutationColor: %d", MutationColor)
	log.Printf("MutationPoint: %d", MutationPoint)
	log.Printf("MutationZOrder: %d", MutationZOrder)
	log.Printf("MutationAddOrDeletePoint: %d", MutationAddOrDeletePoint)
}

type Candidate struct {
	w, h     int
	Polygons []*Polygon
	Fitness  int64
	img      *image.RGBA
}

type Point struct {
	X, Y int
}

type Polygon struct {
	Points []*Point
	color.Color
}

func RandomCandidate(w, h int) *Candidate {
	result := &Candidate{w: w, h: h, Polygons: make([]*Polygon, PolygonsPerIndividual)}
	for i := 0; i < len(result.Polygons); i++ {
		result.Polygons[i] = RandomPolygon(w, h)
	}

	result.RenderImage()

	return result
}

func RandomPolygon(maxW, maxH int) *Polygon {
	result := &Polygon{}
	result.Color = color.RGBA{uint8(rand.Intn(256)), uint8(rand.Intn(256)), uint8(rand.Intn(256)), uint8(rand.Intn(256))}

	numPoints := RandomInt(MinPolygonPoints, MaxPolygonPoints+1)

	for i := 0; i < numPoints; i++ {
		result.AddPoint(RandomPoint(maxW, maxH))
	}

	return result
}

func RandomPoint(maxW, maxH int) *Point {
	return &Point{rand.Intn(maxW), rand.Intn(maxH)}
}

func (m1 *Candidate) Mate(m2 *Candidate) *Candidate {
	w, h := m1.w, m1.h
	crossover := rand.Intn(len(m1.Polygons))
	polygons := make([]*Polygon, len(m1.Polygons))

	shouldShufflePolygons := false
	for i := 0; i < len(polygons); i++ {
		var p Polygon

		if i < crossover {
			p = *m1.Polygons[i] // NB copy the polygon, not the pointer
		} else {
			p = *m2.Polygons[i]
		}

		if shouldMutate() {
			switch randomMutation() {
			case MutationColor:
				p.Color = MutateColor(p.Color)

			case MutationAlpha:
				p.Color = MutateAlpha(p.Color)

			case MutationPoint:
				i := rand.Intn(len(p.Points))
				p.Points[i].MutateNearby(w, h)

			case MutationZOrder:
				shouldShufflePolygons = true

			case MutationAddOrDeletePoint:
				if len(p.Points) == MinPolygonPoints {
					// can't delete
					p.AddPoint(RandomPoint(w, h))
				} else if len(p.Points) == MaxPolygonPoints {
					// can't add
					p.DeleteRandomPoint()
				} else {
					// we can do either add or delete
					if NextBool() {
						p.AddPoint(RandomPoint(w, h))
					} else {
						p.DeleteRandomPoint()
					}
				}
			}
		}

		polygons[i] = &p
	}

	if shouldShufflePolygons {
		shufflePolygonZOrder(polygons)
	}

	result := &Candidate{w: w, h: h, Polygons: polygons}
	result.RenderImage()
	return result
}

func (c *Candidate) MutatedCopy() *Candidate {
	result := &Candidate{w: c.w, h: c.h, Polygons: make([]*Polygon, PolygonsPerIndividual)}
	polygons := result.Polygons

	for i := 0; i < len(result.Polygons); i++ {
		p := *c.Polygons[i]  // copy
		polygons[i] = &p
	}

	shouldShufflePolygons := false

	// make 3 mutations
	for i := 0; i < 3 ; i++ {
		locus := rand.Intn(len(polygons))
		p := polygons[locus]
		switch randomMutation() {
		case MutationColor:
			p.Color = MutateColor(p.Color)

		case MutationAlpha:
			p.Color = MutateAlpha(p.Color)

		case MutationPoint:
			i := rand.Intn(len(p.Points))
			p.Points[i].MutateNearby(c.w, c.h)

		case MutationZOrder:
			shouldShufflePolygons = true

		case MutationAddOrDeletePoint:
			if len(p.Points) == MinPolygonPoints {
				// can't delete
				p.AddPoint(RandomPoint(c.w, c.h))
			} else if len(p.Points) == MaxPolygonPoints {
				// can't add
				p.DeleteRandomPoint()
			} else {
				// we can do either add or delete
				if NextBool() {
					p.AddPoint(RandomPoint(c.w, c.h))
				} else {
					p.DeleteRandomPoint()
				}
			}
		}
	}

	if shouldShufflePolygons {
		shufflePolygonZOrder(polygons)
	}

	result.RenderImage()

	return result
}

func (p *Polygon) AddPoint(point *Point) {
	p.Points = append(p.Points, point)
}

func (p *Polygon) DeleteRandomPoint() {
	i := rand.Intn(len(p.Points))
	p.Points = append(p.Points[:i], p.Points[i+1:]...)
}

func (p *Point) MutateNearby(maxW, maxH int) {
	xDelta := rand.Intn(PointMutationMaxDistance + 1)
	if NextBool() {
		xDelta = -xDelta
	}

	x := p.X + xDelta
	if x < 0 {
		x = 0
	}

	if x >= maxW {
		x = maxW - 1
	}
	p.X = x

	yDelta := rand.Intn(PointMutationMaxDistance + 1)
	if NextBool() {
		yDelta = -yDelta
	}

	y := p.Y + yDelta
	if y < 0 {
		y = 0
	}

	if y >= maxH {
		y = maxH - 1
	}
	p.Y = y
}

func RandomColor() color.Color {
	c := color.NRGBA{R: uint8(rand.Intn(256)), G: uint8(rand.Intn(256)), B: uint8(rand.Intn(256)), A: uint8(rand.Intn(256)) }
	return color.RGBAModel.Convert(c)
}

func MutateColor(c color.Color) color.Color {
	// get the non-premultiplied rgba values
	nrgba := color.NRGBAModel.Convert(c).(color.NRGBA)

	// randomly select one of the r/g/b/a values to mutate
	i := rand.Intn(4)
	val := uint8(rand.Intn(256))

	switch i {
	case 0:
		nrgba.R = val
	case 1:
		nrgba.G = val
	case 2:
		nrgba.B = val
	case 3:
		nrgba.A = val
	}

	return color.RGBAModel.Convert(nrgba)
}

func MutateAlpha(c color.Color) color.Color {
	// get the non-premultiplied rgba values
	nrgba := color.NRGBAModel.Convert(c).(color.NRGBA)
	nrgba.A = uint8(rand.Intn(256))

	return color.RGBAModel.Convert(nrgba)
}

func randomMutation() int {
	return Mutations[rand.Intn(len(Mutations))]
}

func (cd *Candidate) RenderImage() {
	cd.img = image.NewRGBA(image.Rect(0, 0, cd.w, cd.h))
	gc := draw2dimg.NewGraphicContext(cd.img)

	// paint the whole thing black to start
	gc.SetFillColor(color.Black)
	gc.MoveTo(0, 0)
	gc.LineTo(float64(cd.w), 0)
	gc.LineTo(float64(cd.w), float64(cd.h))
	gc.LineTo(0, float64(cd.h))
	gc.Close()
	gc.Fill()

	gc.SetLineWidth(1)

	for _, polygon := range cd.Polygons {
		gc.SetStrokeColor(polygon.Color)
		gc.SetFillColor(polygon.Color)

		firstPoint := polygon.Points[0]
		gc.MoveTo(float64(firstPoint.X), float64(firstPoint.Y))

		for _, point := range polygon.Points[1:] {
			gc.LineTo(float64(point.X), float64(point.Y))
		}

		gc.Close()
		//gc.FillStroke()
		gc.Fill()
	}
}

func (cd *Candidate) DrawAndSave(destFile string) {
	draw2dimg.SaveToPngFile(destFile, cd.img)
}

func (cd *Candidate) String() string {
	return fmt.Sprintf("fitness: %d", cd.Fitness)
}

func shouldMutate() bool {
	return rand.Float32() < MutationChance
}

func shufflePolygonZOrder(polygons []*Polygon) {
	for i := range polygons {
		j := rand.Intn(i + 1)
		polygons[i], polygons[j] = polygons[j], polygons[i]
	}
}

type ByFitness []*Candidate

func (cds ByFitness) Len() int           { return len(cds) }
func (cds ByFitness) Swap(i, j int)      { cds[i], cds[j] = cds[j], cds[i] }
func (cds ByFitness) Less(i, j int) bool { return cds[i].Fitness < cds[j].Fitness }
<commit_msg>MutatedCopy()<commit_after>package polygen

import (
	"fmt"
	"github.com/llgcode/draw2d/draw2dimg"
	"image"
	"image/color"
	"math/rand"
	"log"
)

const (
	MutationAlpha            = iota
	MutationColor            = iota
	MutationPoint            = iota
	MutationZOrder           = iota
	MutationAddOrDeletePoint = iota
)

const (
	MutationChance           = 0.25
	PopulationCount          = 10
	PolygonsPerIndividual    = 50
	MaxPolygonPoints         = 6
	MinPolygonPoints         = 3
	PointMutationMaxDistance = 5
)

var (
	Mutations = []int{MutationColor, MutationPoint, MutationAlpha}
)

func init() {
	log.Printf("MutationAlpha: %d", MutationAlpha)
	log.Printf("MutationColor: %d", MutationColor)
	log.Printf("MutationPoint: %d", MutationPoint)
	log.Printf("MutationZOrder: %d", MutationZOrder)
	log.Printf("MutationAddOrDeletePoint: %d", MutationAddOrDeletePoint)
}

type Candidate struct {
	w, h     int
	Polygons []*Polygon
	Fitness  int64
	img      *image.RGBA
}

type Point struct {
	X, Y int
}

type Polygon struct {
	Points []*Point
	color.Color
}

func RandomCandidate(w, h int) *Candidate {
	result := &Candidate{w: w, h: h, Polygons: make([]*Polygon, PolygonsPerIndividual)}
	for i := 0; i < len(result.Polygons); i++ {
		result.Polygons[i] = RandomPolygon(w, h)
	}

	result.RenderImage()

	return result
}

func RandomPolygon(maxW, maxH int) *Polygon {
	result := &Polygon{}
	result.Color = color.RGBA{uint8(rand.Intn(256)), uint8(rand.Intn(256)), uint8(rand.Intn(256)), uint8(rand.Intn(256))}

	numPoints := RandomInt(MinPolygonPoints, MaxPolygonPoints+1)

	for i := 0; i < numPoints; i++ {
		result.AddPoint(RandomPoint(maxW, maxH))
	}

	return result
}

func RandomPoint(maxW, maxH int) *Point {
	return &Point{rand.Intn(maxW), rand.Intn(maxH)}
}

func (m1 *Candidate) Mate(m2 *Candidate) *Candidate {
	w, h := m1.w, m1.h
	crossover := rand.Intn(len(m1.Polygons))
	polygons := make([]*Polygon, len(m1.Polygons))

	shouldShufflePolygons := false
	for i := 0; i < len(polygons); i++ {
		var p Polygon

		if i < crossover {
			p = *m1.Polygons[i] // NB copy the polygon, not the pointer
		} else {
			p = *m2.Polygons[i]
		}

		if shouldMutate() {
			switch randomMutation() {
			case MutationColor:
				p.Color = MutateColor(p.Color)

			case MutationAlpha:
				p.Color = MutateAlpha(p.Color)

			case MutationPoint:
				i := rand.Intn(len(p.Points))
				p.Points[i].MutateNearby(w, h)

			case MutationZOrder:
				shouldShufflePolygons = true

			case MutationAddOrDeletePoint:
				if len(p.Points) == MinPolygonPoints {
					// can't delete
					p.AddPoint(RandomPoint(w, h))
				} else if len(p.Points) == MaxPolygonPoints {
					// can't add
					p.DeleteRandomPoint()
				} else {
					// we can do either add or delete
					if NextBool() {
						p.AddPoint(RandomPoint(w, h))
					} else {
						p.DeleteRandomPoint()
					}
				}
			}
		}

		polygons[i] = &p
	}

	if shouldShufflePolygons {
		shufflePolygonZOrder(polygons)
	}

	result := &Candidate{w: w, h: h, Polygons: polygons}
	result.RenderImage()
	return result
}

func (c *Candidate) MutatedCopy() *Candidate {
	polygons := make([]*Polygon, PolygonsPerIndividual)
	result := &Candidate{w: c.w, h: c.h, Polygons: polygons}

	for i := 0; i < len(result.Polygons); i++ {
		var p Polygon
		p = *c.Polygons[i]  // copy
		polygons[i] = &p
	}

	// make 3 mutations
	for i := 0; i < 3 ; i++ {
		locus := rand.Intn(len(polygons))
		pgon := polygons[locus]
		switch randomMutation() {
		case MutationColor:
			pgon.Color = MutateColor(pgon.Color)

		case MutationAlpha:
			pgon.Color = MutateAlpha(pgon.Color)

		case MutationPoint:
			pi := rand.Intn(len(pgon.Points))
			pgon.Points[pi].MutateNearby(c.w, c.h)

		default:
			log.Fatal("fell through")
		}
	}

	result.RenderImage()

	return result
}

func (p *Polygon) AddPoint(point *Point) {
	p.Points = append(p.Points, point)
}

func (p *Polygon) DeleteRandomPoint() {
	i := rand.Intn(len(p.Points))
	p.Points = append(p.Points[:i], p.Points[i+1:]...)
}

func (p *Point) MutateNearby(maxW, maxH int) {
	xDelta := rand.Intn(PointMutationMaxDistance + 1)
	if NextBool() {
		xDelta = -xDelta
	}

	x := p.X + xDelta
	if x < 0 {
		x = 0
	}

	if x >= maxW {
		x = maxW - 1
	}
	p.X = x

	yDelta := rand.Intn(PointMutationMaxDistance + 1)
	if NextBool() {
		yDelta = -yDelta
	}

	y := p.Y + yDelta
	if y < 0 {
		y = 0
	}

	if y >= maxH {
		y = maxH - 1
	}
	p.Y = y
}

func RandomColor() color.Color {
	c := color.NRGBA{R: uint8(rand.Intn(256)), G: uint8(rand.Intn(256)), B: uint8(rand.Intn(256)), A: uint8(rand.Intn(256)) }
	return color.RGBAModel.Convert(c)
}

func MutateColor(c color.Color) color.Color {
	// get the non-premultiplied rgba values
	nrgba := color.NRGBAModel.Convert(c).(color.NRGBA)

	// randomly select one of the r/g/b/a values to mutate
	i := rand.Intn(4)
	val := uint8(rand.Intn(256))

	switch i {
	case 0:
		nrgba.R = val
	case 1:
		nrgba.G = val
	case 2:
		nrgba.B = val
	case 3:
		nrgba.A = val
	}

	return color.RGBAModel.Convert(nrgba)
}

func MutateAlpha(c color.Color) color.Color {
	// get the non-premultiplied rgba values
	nrgba := color.NRGBAModel.Convert(c).(color.NRGBA)
	nrgba.A = uint8(rand.Intn(256))

	return color.RGBAModel.Convert(nrgba)
}

func randomMutation() int {
	return Mutations[rand.Intn(len(Mutations))]
}

func (cd *Candidate) RenderImage() {
	cd.img = image.NewRGBA(image.Rect(0, 0, cd.w, cd.h))
	gc := draw2dimg.NewGraphicContext(cd.img)

	// paint the whole thing black to start
	gc.SetFillColor(color.Black)
	gc.MoveTo(0, 0)
	gc.LineTo(float64(cd.w), 0)
	gc.LineTo(float64(cd.w), float64(cd.h))
	gc.LineTo(0, float64(cd.h))
	gc.Close()
	gc.Fill()

	gc.SetLineWidth(1)

	for _, polygon := range cd.Polygons {
		gc.SetStrokeColor(polygon.Color)
		gc.SetFillColor(polygon.Color)

		firstPoint := polygon.Points[0]
		gc.MoveTo(float64(firstPoint.X), float64(firstPoint.Y))

		for _, point := range polygon.Points[1:] {
			gc.LineTo(float64(point.X), float64(point.Y))
		}

		gc.Close()
		//gc.FillStroke()
		gc.Fill()
	}
}

func (cd *Candidate) DrawAndSave(destFile string) {
	draw2dimg.SaveToPngFile(destFile, cd.img)
}

func (cd *Candidate) String() string {
	return fmt.Sprintf("fitness: %d", cd.Fitness)
}

func shouldMutate() bool {
	return rand.Float32() < MutationChance
}

func shufflePolygonZOrder(polygons []*Polygon) {
	for i := range polygons {
		j := rand.Intn(i + 1)
		polygons[i], polygons[j] = polygons[j], polygons[i]
	}
}

type ByFitness []*Candidate

func (cds ByFitness) Len() int           { return len(cds) }
func (cds ByFitness) Swap(i, j int)      { cds[i], cds[j] = cds[j], cds[i] }
func (cds ByFitness) Less(i, j int) bool { return cds[i].Fitness < cds[j].Fitness }
<|endoftext|>


<commit_before>package ecs

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

type ResourceType string

const (
	ResourceTypeInstance            = ResourceType("Instance")
	ResourceTypeDisk                = ResourceType("Disk")
	ResourceTypeVSwitch             = ResourceType("VSwitch")
	ResourceTypeIOOptimizedInstance = ResourceType("IoOptimized")
)

// The sub-item of the type AvailableResourcesType
type SupportedResourceType string

const (
	SupportedInstanceType            = SupportedResourceType("supportedInstanceType")
	SupportedInstanceTypeFamily      = SupportedResourceType("supportedInstanceTypeFamily")
	SupportedInstanceGeneration      = SupportedResourceType("supportedInstanceGeneration")
	SupportedSystemDiskCategory      = SupportedResourceType("supportedSystemDiskCategory")
	SupportedDataDiskCategory        = SupportedResourceType("supportedDataDiskCategory")
	SupportedNetworkCategory         = SupportedResourceType("supportedNetworkCategory")

)
//
// You can read doc at https://help.aliyun.com/document_detail/25670.html?spm=5176.doc25640.2.1.J24zQt
type ResourcesInfoType struct {
	ResourcesInfo []AvailableResourcesType
}
// Because the sub-item of AvailableResourcesType starts with supported and golang struct cann't refer them, this uses map to parse ResourcesInfo
type AvailableResourcesType struct {
	IoOptimized          bool
	NetworkTypes         map[string][]string
	InstanceGenerations  map[string][]string
	InstanceTypeFamilies map[string][]string
	InstanceTypes        map[string][]string
	SystemDiskCategories map[string][]DiskCategory
	DataDiskCategories   map[string][]DiskCategory
}

type DescribeZonesArgs struct {
	RegionId common.Region
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&availableresourcecreationtype
type AvailableResourceCreationType struct {
	ResourceTypes []ResourceType //enum for Instance, Disk, VSwitch
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&availablediskcategoriestype
type AvailableDiskCategoriesType struct {
	DiskCategories []DiskCategory //enum for cloud, ephemeral, ephemeral_ssd
}

type AvailableInstanceTypesType struct {
	InstanceTypes []string
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&zonetype
type ZoneType struct {
	ZoneId                    string
	LocalName                 string
	AvailableResources 	  ResourcesInfoType
	AvailableInstanceTypes    AvailableInstanceTypesType
	AvailableResourceCreation AvailableResourceCreationType
	AvailableDiskCategories   AvailableDiskCategoriesType
}

type DescribeZonesResponse struct {
	common.Response
	Zones struct {
		Zone []ZoneType
	}
}

// DescribeZones describes zones
func (client *Client) DescribeZones(regionId common.Region) (zones []ZoneType, err error) {
	response, err := client.DescribeZonesWithRaw(regionId)
	if err == nil {
		return response.Zones.Zone, nil
	}

	return []ZoneType{}, err
}

func (client *Client) DescribeZonesWithRaw(regionId common.Region) (response *DescribeZonesResponse, err error) {
	args := DescribeZonesArgs{
		RegionId: regionId,
	}
	response = &DescribeZonesResponse{}

	err = client.Invoke("DescribeZones", &args, response)

	if err == nil {
		return response, nil
	}

	return nil, err
}
<commit_msg>modify avaliableResourceType map key to SupportedResourceType<commit_after>package ecs

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

type ResourceType string

const (
	ResourceTypeInstance            = ResourceType("Instance")
	ResourceTypeDisk                = ResourceType("Disk")
	ResourceTypeVSwitch             = ResourceType("VSwitch")
	ResourceTypeIOOptimizedInstance = ResourceType("IoOptimized")
)

// The sub-item of the type AvailableResourcesType
type SupportedResourceType string

const (
	SupportedInstanceType            = SupportedResourceType("supportedInstanceType")
	SupportedInstanceTypeFamily      = SupportedResourceType("supportedInstanceTypeFamily")
	SupportedInstanceGeneration      = SupportedResourceType("supportedInstanceGeneration")
	SupportedSystemDiskCategory      = SupportedResourceType("supportedSystemDiskCategory")
	SupportedDataDiskCategory        = SupportedResourceType("supportedDataDiskCategory")
	SupportedNetworkCategory         = SupportedResourceType("supportedNetworkCategory")

)
//
// You can read doc at https://help.aliyun.com/document_detail/25670.html?spm=5176.doc25640.2.1.J24zQt
type ResourcesInfoType struct {
	ResourcesInfo []AvailableResourcesType
}
// Because the sub-item of AvailableResourcesType starts with supported and golang struct cann't refer them, this uses map to parse ResourcesInfo
type AvailableResourcesType struct {
	IoOptimized          bool
	NetworkTypes         map[SupportedResourceType][]string
	InstanceGenerations  map[SupportedResourceType][]string
	InstanceTypeFamilies map[SupportedResourceType][]string
	InstanceTypes        map[SupportedResourceType][]string
	SystemDiskCategories map[SupportedResourceType][]DiskCategory
	DataDiskCategories   map[SupportedResourceType][]DiskCategory
}

type DescribeZonesArgs struct {
	RegionId common.Region
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&availableresourcecreationtype
type AvailableResourceCreationType struct {
	ResourceTypes []ResourceType //enum for Instance, Disk, VSwitch
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&availablediskcategoriestype
type AvailableDiskCategoriesType struct {
	DiskCategories []DiskCategory //enum for cloud, ephemeral, ephemeral_ssd
}

type AvailableInstanceTypesType struct {
	InstanceTypes []string
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&zonetype
type ZoneType struct {
	ZoneId                    string
	LocalName                 string
	AvailableResources 	  ResourcesInfoType
	AvailableInstanceTypes    AvailableInstanceTypesType
	AvailableResourceCreation AvailableResourceCreationType
	AvailableDiskCategories   AvailableDiskCategoriesType
}

type DescribeZonesResponse struct {
	common.Response
	Zones struct {
		Zone []ZoneType
	}
}

// DescribeZones describes zones
func (client *Client) DescribeZones(regionId common.Region) (zones []ZoneType, err error) {
	response, err := client.DescribeZonesWithRaw(regionId)
	if err == nil {
		return response.Zones.Zone, nil
	}

	return []ZoneType{}, err
}

func (client *Client) DescribeZonesWithRaw(regionId common.Region) (response *DescribeZonesResponse, err error) {
	args := DescribeZonesArgs{
		RegionId: regionId,
	}
	response = &DescribeZonesResponse{}

	err = client.Invoke("DescribeZones", &args, response)

	if err == nil {
		return response, nil
	}

	return nil, err
}
<|endoftext|>


<commit_before>// Copyright 2014 Manu Martinez-Almeida.  All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.

package egoS

import (
	"html/template"
	"net/http"
	"sync"

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

var once sync.Once
var internalEngine *Engine

func engine() *Engine {
	once.Do(func() {
		internalEngine = Default()
	})
	return internalEngine
}

func LoadHTMLGlob(pattern string) {
	engine().LoadHTMLGlob(pattern)
}

func LoadHTMLFiles(files ...string) {
	engine().LoadHTMLFiles(files...)
}

func SetHTMLTemplate(templ *template.Template) {
	engine().SetHTMLTemplate(templ)
}

// NoRoute adds handlers for NoRoute. It return a 404 code by default.
func NoRoute(handlers ...HandlerFunc) {
	engine().NoRoute(handlers...)
}

// NoMethod sets the handlers called when... TODO
func NoMethod(handlers ...HandlerFunc) {
	engine().NoMethod(handlers...)
}

// Group creates a new router group. You should add all the routes that have common middlwares or the same path prefix.
// For example, all the routes that use a common middlware for authorization could be grouped.
func Group(relativePath string, handlers ...HandlerFunc) *RouterGroup {
	return engine().Group(relativePath, handlers...)
}

func Handle(httpMethod, relativePath string, handlers ...HandlerFunc) IRoutes {
	return engine().Handle(httpMethod, relativePath, handlers...)
}

// POST is a shortcut for router.Handle("POST", path, handle)
func POST(relativePath string, handlers ...HandlerFunc) IRoutes {
	return engine().POST(relativePath, handlers...)
}

// GET is a shortcut for router.Handle("GET", path, handle)
func GET(relativePath string, handlers ...HandlerFunc) IRoutes {
	return engine().GET(relativePath, handlers...)
}

// DELETE is a shortcut for router.Handle("DELETE", path, handle)
func DELETE(relativePath string, handlers ...HandlerFunc) IRoutes {
	return engine().DELETE(relativePath, handlers...)
}

// PATCH is a shortcut for router.Handle("PATCH", path, handle)
func PATCH(relativePath string, handlers ...HandlerFunc) IRoutes {
	return engine().PATCH(relativePath, handlers...)
}

// PUT is a shortcut for router.Handle("PUT", path, handle)
func PUT(relativePath string, handlers ...HandlerFunc) IRoutes {
	return engine().PUT(relativePath, handlers...)
}

// OPTIONS is a shortcut for router.Handle("OPTIONS", path, handle)
func OPTIONS(relativePath string, handlers ...HandlerFunc) IRoutes {
	return engine().OPTIONS(relativePath, handlers...)
}

// HEAD is a shortcut for router.Handle("HEAD", path, handle)
func HEAD(relativePath string, handlers ...HandlerFunc) IRoutes {
	return engine().HEAD(relativePath, handlers...)
}

func Any(relativePath string, handlers ...HandlerFunc) IRoutes {
	return engine().Any(relativePath, handlers...)
}

func StaticFile(relativePath, filepath string) IRoutes {
	return engine().StaticFile(relativePath, filepath)
}

// Static serves files from the given file system root.
// Internally a http.FileServer is used, therefore http.NotFound is used instead
// of the Router's NotFound handler.
// To use the operating system's file system implementation,
// use :
//     router.Static("/static", "/var/www")
func Static(relativePath, root string) IRoutes {
	return engine().Static(relativePath, root)
}

func StaticFS(relativePath string, fs http.FileSystem) IRoutes {
	return engine().StaticFS(relativePath, fs)
}

// Use attachs a global middleware to the router. ie. the middlewares attached though Use() will be
// included in the handlers chain for every single request. Even 404, 405, static files...
// For example, this is the right place for a logger or error management middleware.
func Use(middlewares ...HandlerFunc) IRoutes {
	return engine().Use(middlewares...)
}

// Run : The router is attached to a http.Server and starts listening and serving HTTP requests.
// It is a shortcut for http.ListenAndServe(addr, router)
// Note: this method will block the calling goroutine undefinitelly unless an error happens.
func Run(addr ...string) (err error) {
	return engine().Run(addr...)
}

// RunTLS : The router is attached to a http.Server and starts listening and serving HTTPS requests.
// It is a shortcut for http.ListenAndServeTLS(addr, certFile, keyFile, router)
// Note: this method will block the calling goroutine undefinitelly unless an error happens.
func RunTLS(addr string, certFile string, keyFile string) (err error) {
	return engine().RunTLS(addr, certFile, keyFile)
}

// RunUnix : The router is attached to a http.Server and starts listening and serving HTTP requests
// through the specified unix socket (ie. a file)
// Note: this method will block the calling goroutine undefinitelly unless an error happens.
func RunUnix(file string) (err error) {
	return engine().RunUnix(file)
}
<commit_msg>not use dot when import<commit_after>// Copyright 2014 Manu Martinez-Almeida.  All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.

package egoS

import (
	"html/template"
	"net/http"
	"sync"

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

var once sync.Once
var internalEngine *ego.Engine

func engine() *ego.Engine {
	once.Do(func() {
		internalEngine = ego.Default()
	})
	return internalEngine
}

func LoadHTMLGlob(pattern string) {
	engine().LoadHTMLGlob(pattern)
}

func LoadHTMLFiles(files ...string) {
	engine().LoadHTMLFiles(files...)
}

func SetHTMLTemplate(templ *template.Template) {
	engine().SetHTMLTemplate(templ)
}

// NoRoute adds handlers for NoRoute. It return a 404 code by default.
func NoRoute(handlers ...HandlerFunc) {
	engine().NoRoute(handlers...)
}

// NoMethod sets the handlers called when... TODO
func NoMethod(handlers ...HandlerFunc) {
	engine().NoMethod(handlers...)
}

// Group creates a new router group. You should add all the routes that have common middlwares or the same path prefix.
// For example, all the routes that use a common middlware for authorization could be grouped.
func Group(relativePath string, handlers ...HandlerFunc) *RouterGroup {
	return engine().Group(relativePath, handlers...)
}

func Handle(httpMethod, relativePath string, handlers ...HandlerFunc) IRoutes {
	return engine().Handle(httpMethod, relativePath, handlers...)
}

// POST is a shortcut for router.Handle("POST", path, handle)
func POST(relativePath string, handlers ...HandlerFunc) IRoutes {
	return engine().POST(relativePath, handlers...)
}

// GET is a shortcut for router.Handle("GET", path, handle)
func GET(relativePath string, handlers ...HandlerFunc) IRoutes {
	return engine().GET(relativePath, handlers...)
}

// DELETE is a shortcut for router.Handle("DELETE", path, handle)
func DELETE(relativePath string, handlers ...HandlerFunc) IRoutes {
	return engine().DELETE(relativePath, handlers...)
}

// PATCH is a shortcut for router.Handle("PATCH", path, handle)
func PATCH(relativePath string, handlers ...HandlerFunc) IRoutes {
	return engine().PATCH(relativePath, handlers...)
}

// PUT is a shortcut for router.Handle("PUT", path, handle)
func PUT(relativePath string, handlers ...HandlerFunc) IRoutes {
	return engine().PUT(relativePath, handlers...)
}

// OPTIONS is a shortcut for router.Handle("OPTIONS", path, handle)
func OPTIONS(relativePath string, handlers ...HandlerFunc) IRoutes {
	return engine().OPTIONS(relativePath, handlers...)
}

// HEAD is a shortcut for router.Handle("HEAD", path, handle)
func HEAD(relativePath string, handlers ...HandlerFunc) IRoutes {
	return engine().HEAD(relativePath, handlers...)
}

func Any(relativePath string, handlers ...HandlerFunc) IRoutes {
	return engine().Any(relativePath, handlers...)
}

func StaticFile(relativePath, filepath string) IRoutes {
	return engine().StaticFile(relativePath, filepath)
}

// Static serves files from the given file system root.
// Internally a http.FileServer is used, therefore http.NotFound is used instead
// of the Router's NotFound handler.
// To use the operating system's file system implementation,
// use :
//     router.Static("/static", "/var/www")
func Static(relativePath, root string) IRoutes {
	return engine().Static(relativePath, root)
}

func StaticFS(relativePath string, fs http.FileSystem) IRoutes {
	return engine().StaticFS(relativePath, fs)
}

// Use attachs a global middleware to the router. ie. the middlewares attached though Use() will be
// included in the handlers chain for every single request. Even 404, 405, static files...
// For example, this is the right place for a logger or error management middleware.
func Use(middlewares ...HandlerFunc) IRoutes {
	return engine().Use(middlewares...)
}

// Run : The router is attached to a http.Server and starts listening and serving HTTP requests.
// It is a shortcut for http.ListenAndServe(addr, router)
// Note: this method will block the calling goroutine undefinitelly unless an error happens.
func Run(addr ...string) (err error) {
	return engine().Run(addr...)
}

// RunTLS : The router is attached to a http.Server and starts listening and serving HTTPS requests.
// It is a shortcut for http.ListenAndServeTLS(addr, certFile, keyFile, router)
// Note: this method will block the calling goroutine undefinitelly unless an error happens.
func RunTLS(addr string, certFile string, keyFile string) (err error) {
	return engine().RunTLS(addr, certFile, keyFile)
}

// RunUnix : The router is attached to a http.Server and starts listening and serving HTTP requests
// through the specified unix socket (ie. a file)
// Note: this method will block the calling goroutine undefinitelly unless an error happens.
func RunUnix(file string) (err error) {
	return engine().RunUnix(file)
}
<|endoftext|>


<commit_before>// Implementation of RFC 6143 §7.7 Encodings.

package vnc

import (
	"encoding/binary"
	"io"
)

const (
	Raw               = int32(0)
	CopyRect          = int32(1)
	RRE               = int32(2)
	Hextile           = int32(5)
	TRLE              = int32(15)
	ZRLE              = int32(16)
	ColorPseudo       = int32(-239)
	DesktopSizePseudo = int32(-223)
)

// An Encoding implements a method for encoding pixel data that is
// sent by the server to the client.
type Encoding interface {
	// The number that uniquely identifies this encoding type.
	Type() int32

	// Read the contents of the encoded pixel data from the reader.
	// This should return a new Encoding implementation that contains
	// the proper data.
	Read(*ClientConn, *Rectangle, io.Reader) (Encoding, error)
}

// RawEncoding is raw pixel data sent by the server.
// See RFC 6143 §7.7.1.
type RawEncoding struct {
	Colors []Color
}

// NewRawEncoding returns a new RawEncoding.
func NewRawEncoding(c []Color) *RawEncoding {
	return &RawEncoding{c}
}

func (*RawEncoding) Type() int32 {
	return Raw
}

func (*RawEncoding) Read(c *ClientConn, rect *Rectangle, r io.Reader) (Encoding, error) {
	bytesPerPixel := c.pixelFormat.BPP / 8
	pixelBytes := make([]uint8, bytesPerPixel)

	var byteOrder binary.ByteOrder = binary.LittleEndian
	if c.pixelFormat.BigEndian == RFBTrue {
		byteOrder = binary.BigEndian
	}

	colors := make([]Color, int(rect.Height)*int(rect.Width))
	for y := uint16(0); y < rect.Height; y++ {
		for x := uint16(0); x < rect.Width; x++ {
			if _, err := io.ReadFull(r, pixelBytes); err != nil {
				return nil, err
			}

			var rawPixel uint32
			if c.pixelFormat.BPP == 8 {
				rawPixel = uint32(pixelBytes[0])
			} else if c.pixelFormat.BPP == 16 {
				rawPixel = uint32(byteOrder.Uint16(pixelBytes))
			} else if c.pixelFormat.BPP == 32 {
				rawPixel = byteOrder.Uint32(pixelBytes)
			}

			color := &colors[int(y)*int(rect.Width)+int(x)]
			if c.pixelFormat.TrueColor == RFBTrue {
				color.R = uint16((rawPixel >> c.pixelFormat.RedShift) & uint32(c.pixelFormat.RedMax))
				color.G = uint16((rawPixel >> c.pixelFormat.GreenShift) & uint32(c.pixelFormat.GreenMax))
				color.B = uint16((rawPixel >> c.pixelFormat.BlueShift) & uint32(c.pixelFormat.BlueMax))
			} else {
				*color = c.colorMap[rawPixel]
			}
		}
	}

	return NewRawEncoding(colors), nil
}

// DesktopSizePseudoEncoding enables desktop resize support.
// See RFC 6143 §7.8.2.
type DesktopSizePseudoEncoding struct{}

func (*DesktopSizePseudoEncoding) Type() int32 {
	return DesktopSizePseudo
}

func (*DesktopSizePseudoEncoding) Read(c *ClientConn, rect *Rectangle, _ io.Reader) (Encoding, error) {
	c.fbWidth = rect.Width
	c.fbHeight = rect.Height

	return &DesktopSizePseudoEncoding{}, nil
}
<commit_msg>Added more debug logging<commit_after>// Implementation of RFC 6143 §7.7 Encodings.

package vnc

import (
	"encoding/binary"
	"io"
	"log"
)

const (
	Raw               = int32(0)
	CopyRect          = int32(1)
	RRE               = int32(2)
	Hextile           = int32(5)
	TRLE              = int32(15)
	ZRLE              = int32(16)
	ColorPseudo       = int32(-239)
	DesktopSizePseudo = int32(-223)
)

// An Encoding implements a method for encoding pixel data that is
// sent by the server to the client.
type Encoding interface {
	// The number that uniquely identifies this encoding type.
	Type() int32

	// Read the contents of the encoded pixel data from the reader.
	// This should return a new Encoding implementation that contains
	// the proper data.
	Read(*ClientConn, *Rectangle, io.Reader) (Encoding, error)
}

// RawEncoding is raw pixel data sent by the server.
// See RFC 6143 §7.7.1.
type RawEncoding struct {
	Colors []Color
}

// NewRawEncoding returns a new RawEncoding.
func NewRawEncoding(c []Color) *RawEncoding {
	return &RawEncoding{c}
}

func (*RawEncoding) Type() int32 {
	return Raw
}

func (*RawEncoding) Read(c *ClientConn, rect *Rectangle, r io.Reader) (Encoding, error) {
	if c.debug {
		log.Printf("RawEncoding.Read(): %v", rect)
	}
	bytesPerPixel := c.pixelFormat.BPP / 8
	pixelBytes := make([]uint8, bytesPerPixel)

	var byteOrder binary.ByteOrder = binary.LittleEndian
	if c.pixelFormat.BigEndian == RFBTrue {
		byteOrder = binary.BigEndian
	}

	colors := make([]Color, int(rect.Height)*int(rect.Width))
	for y := uint16(0); y < rect.Height; y++ {
		for x := uint16(0); x < rect.Width; x++ {
			if _, err := io.ReadFull(r, pixelBytes); err != nil {
				return nil, err
			}

			var rawPixel uint32
			if c.pixelFormat.BPP == 8 {
				rawPixel = uint32(pixelBytes[0])
			} else if c.pixelFormat.BPP == 16 {
				rawPixel = uint32(byteOrder.Uint16(pixelBytes))
			} else if c.pixelFormat.BPP == 32 {
				rawPixel = byteOrder.Uint32(pixelBytes)
			}

			color := &colors[int(y)*int(rect.Width)+int(x)]
			if c.pixelFormat.TrueColor == RFBTrue {
				color.R = uint16((rawPixel >> c.pixelFormat.RedShift) & uint32(c.pixelFormat.RedMax))
				color.G = uint16((rawPixel >> c.pixelFormat.GreenShift) & uint32(c.pixelFormat.GreenMax))
				color.B = uint16((rawPixel >> c.pixelFormat.BlueShift) & uint32(c.pixelFormat.BlueMax))
			} else {
				*color = c.colorMap[rawPixel]
			}
		}
	}

	return NewRawEncoding(colors), nil
}

// DesktopSizePseudoEncoding enables desktop resize support.
// See RFC 6143 §7.8.2.
type DesktopSizePseudoEncoding struct{}

func (*DesktopSizePseudoEncoding) Type() int32 {
	return DesktopSizePseudo
}

func (*DesktopSizePseudoEncoding) Read(c *ClientConn, rect *Rectangle, _ io.Reader) (Encoding, error) {
	c.fbWidth = rect.Width
	c.fbHeight = rect.Height

	return &DesktopSizePseudoEncoding{}, nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 Kelsey Hightower. All rights reserved.
// Use of this source code is governed by the MIT License that can be found in
// the LICENSE file.

package envconfig

import (
	"errors"
	"fmt"
	"reflect"
	"strconv"
	"strings"
	"syscall"
	"time"
)

// ErrInvalidSpecification indicates that a specification is of the wrong type.
var ErrInvalidSpecification = errors.New("invalid specification must be a struct")

// A ParseError occurs when an environment variable cannot be converted to
// the type required by a struct field during assignment.
type ParseError struct {
	KeyName   string
	FieldName string
	TypeName  string
	Value     string
}

func (e *ParseError) Error() string {
	return fmt.Sprintf("envconfig.Process: assigning %[1]s to %[2]s: converting '%[3]s' to type %[4]s", e.KeyName, e.FieldName, e.Value, e.TypeName)
}

// Process populates the specified struct based on environment variables
func Process(prefix string, spec interface{}) error {
	s := reflect.ValueOf(spec).Elem()
	if s.Kind() != reflect.Struct {
		return ErrInvalidSpecification
	}
	typeOfSpec := s.Type()
	for i := 0; i < s.NumField(); i++ {
		f := s.Field(i)
		if f.CanSet() {
			if typeOfSpec.Field(i).Anonymous && f.Kind() == reflect.Struct {
				embeddedPtr := f.Addr().Interface()
				if err := Process(prefix, embeddedPtr); err != nil {
					return err
				}
				f.Set(reflect.ValueOf(embeddedPtr).Elem())
			}

			alt := typeOfSpec.Field(i).Tag.Get("envconfig")
			fieldName := typeOfSpec.Field(i).Name
			if alt != "" {
				fieldName = alt
			}
			key := strings.ToUpper(fmt.Sprintf("%s_%s", prefix, fieldName))
			// `os.Getenv` cannot differentiate between an explicitly set empty value
			// and an unset value. `os.LookupEnv` is preferred to `syscall.Getenv`,
			// but it is only available in go1.5 or newer.
			value, ok := syscall.Getenv(key)
			if !ok && alt != "" {
				key := strings.ToUpper(fieldName)
				value, ok = syscall.Getenv(key)
			}

			def := typeOfSpec.Field(i).Tag.Get("default")
			if def != "" && !ok {
				value = def
			}

			req := typeOfSpec.Field(i).Tag.Get("required")
			if !ok && def == "" {
				if req == "true" {
					return fmt.Errorf("required key %s missing value", key)
				}
				continue
			}

			parser := getParser(f.Type(), f.Kind())
			if parser == nil {
				continue
			}

			parsedValue, err := parser.Parse(value)
			if err != nil {
				return &ParseError{
					KeyName:   key,
					FieldName: fieldName,
					TypeName:  f.Type().String(),
					Value:     value,
				}
			}
			parser.Set(&f, parsedValue)

		}
	}
	return nil
}

// MustProcess is the same as Process but panics if an error occurs
func MustProcess(prefix string, spec interface{}) {
	if err := Process(prefix, spec); err != nil {
		panic(err)
	}
}

// fieldParser represents a parsing function (conversion from string) and a
// setting function (to set the value using reflection)
type fieldParser struct {
	Parse func(v string) (interface{}, error)
	Set   func(f *reflect.Value, v interface{})
}

// getParser returns back a FieldParser instance for the given type
func getParser(t reflect.Type, k reflect.Kind) (parser *fieldParser) {
	switch k {
	case reflect.String:
		parser = &fieldParser{
			Parse: func(v string) (interface{}, error) {
				return v, nil
			},
			Set: func(f *reflect.Value, v interface{}) {
				f.SetString(v.(string))
			},
		}
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		parser = &fieldParser{
			Parse: func(v string) (interface{}, error) {
				var intValue int64
				var err error
				if k == reflect.Int64 && t.PkgPath() == "time" && t.Name() == "Duration" {
					var d time.Duration
					d, err = time.ParseDuration(v)
					intValue = int64(d)
				} else {
					intValue, err = strconv.ParseInt(v, 0, t.Bits())
				}
				if err != nil {
					return nil, err
				}

				return intValue, nil
			},
			Set: func(f *reflect.Value, v interface{}) {
				f.SetInt(v.(int64))
			},
		}
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		parser = &fieldParser{
			Parse: func(v string) (interface{}, error) {
				uintValue, err := strconv.ParseUint(v, 0, t.Bits())
				if err != nil {
					return nil, err
				}

				return uintValue, nil

			},
			Set: func(f *reflect.Value, v interface{}) {
				f.SetUint(v.(uint64))
			},
		}

	case reflect.Bool:
		parser = &fieldParser{
			Parse: func(v string) (interface{}, error) {
				boolValue, err := strconv.ParseBool(v)
				if err != nil {
					return nil, err
				}
				return boolValue, nil
			},
			Set: func(f *reflect.Value, v interface{}) {
				f.SetBool(v.(bool))
			},
		}

	case reflect.Float32, reflect.Float64:
		parser = &fieldParser{
			Parse: func(v string) (interface{}, error) {
				floatValue, err := strconv.ParseFloat(v, t.Bits())
				if err != nil {
					return nil, err
				}
				return floatValue, nil
			},
			Set: func(f *reflect.Value, v interface{}) {
				f.SetFloat(v.(float64))
			},
		}
	case reflect.Slice:
		parser = &fieldParser{
			Parse: func(v string) (interface{}, error) {
				elemType := t.Elem()
				parser := getParser(elemType, elemType.Kind())
				strValues := strings.Split(v, ",")

				slice := reflect.MakeSlice(reflect.SliceOf(elemType), 0, 0)
				for i := range strValues {
					value, err := parser.Parse(strValues[i])
					if err != nil {
						return nil, err
					}

					itmValue := reflect.ValueOf(value)
					itmValue = itmValue.Convert(elemType)

					slice = reflect.Append(slice, itmValue)
				}
				return slice.Interface(), nil
			},
			Set: func(f *reflect.Value, v interface{}) {
				f.Set(reflect.ValueOf(v))
			},
		}
	}
	return
}
<commit_msg>cleanup pass, simplifying field handling funcs<commit_after>// Copyright (c) 2013 Kelsey Hightower. All rights reserved.
// Use of this source code is governed by the MIT License that can be found in
// the LICENSE file.

package envconfig

import (
	"errors"
	"fmt"
	"reflect"
	"strconv"
	"strings"
	"syscall"
	"time"
)

// ErrInvalidSpecification indicates that a specification is of the wrong type.
var ErrInvalidSpecification = errors.New("invalid specification must be a struct")

// A ParseError occurs when an environment variable cannot be converted to
// the type required by a struct field during assignment.
type ParseError struct {
	KeyName   string
	FieldName string
	TypeName  string
	Value     string
}

func (e *ParseError) Error() string {
	return fmt.Sprintf("envconfig.Process: assigning %[1]s to %[2]s: converting '%[3]s' to type %[4]s", e.KeyName, e.FieldName, e.Value, e.TypeName)
}

// Process populates the specified struct based on environment variables
func Process(prefix string, spec interface{}) error {
	s := reflect.ValueOf(spec).Elem()
	if s.Kind() != reflect.Struct {
		return ErrInvalidSpecification
	}
	typeOfSpec := s.Type()
	for i := 0; i < s.NumField(); i++ {
		f := s.Field(i)
		if !f.CanSet() {
			continue
		}

		if typeOfSpec.Field(i).Anonymous && f.Kind() == reflect.Struct {
			embeddedPtr := f.Addr().Interface()
			if err := Process(prefix, embeddedPtr); err != nil {
				return err
			}
			f.Set(reflect.ValueOf(embeddedPtr).Elem())
		}

		alt := typeOfSpec.Field(i).Tag.Get("envconfig")
		fieldName := typeOfSpec.Field(i).Name
		if alt != "" {
			fieldName = alt
		}
		key := strings.ToUpper(fmt.Sprintf("%s_%s", prefix, fieldName))
		// `os.Getenv` cannot differentiate between an explicitly set empty value
		// and an unset value. `os.LookupEnv` is preferred to `syscall.Getenv`,
		// but it is only available in go1.5 or newer.
		value, ok := syscall.Getenv(key)
		if !ok && alt != "" {
			key := strings.ToUpper(fieldName)
			value, ok = syscall.Getenv(key)
		}

		def := typeOfSpec.Field(i).Tag.Get("default")
		if def != "" && !ok {
			value = def
		}

		req := typeOfSpec.Field(i).Tag.Get("required")
		if !ok && def == "" {
			if req == "true" {
				return fmt.Errorf("required key %s missing value", key)
			}
			continue
		}

		err := processField(value, f)
		if err != nil {
			return &ParseError{
				KeyName:   key,
				FieldName: fieldName,
				TypeName:  f.Type().String(),
				Value:     value,
			}
		}
	}
	return nil
}

// MustProcess is the same as Process but panics if an error occurs
func MustProcess(prefix string, spec interface{}) {
	if err := Process(prefix, spec); err != nil {
		panic(err)
	}
}

func processField(value string, field reflect.Value) error {
	typ := field.Type()

	switch typ.Kind() {
	case reflect.String:
		field.SetString(value)
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		var (
			val int64
			err error
		)
		if field.Kind() == reflect.Int64 && typ.PkgPath() == "time" && typ.Name() == "Duration" {
			var d time.Duration
			d, err = time.ParseDuration(value)
			val = int64(d)
		} else {
			val, err = strconv.ParseInt(value, 0, typ.Bits())
		}
		if err != nil {
			return err
		}

		field.SetInt(val)
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		val, err := strconv.ParseUint(value, 0, typ.Bits())
		if err != nil {
			return err
		}
		field.SetUint(val)
	case reflect.Bool:
		val, err := strconv.ParseBool(value)
		if err != nil {
			return err
		}
		field.SetBool(val)
	case reflect.Float32, reflect.Float64:
		val, err := strconv.ParseFloat(value, typ.Bits())
		if err != nil {
			return err
		}
		field.SetFloat(val)
	case reflect.Slice:
		vals := strings.Split(value, ",")
		sl := reflect.MakeSlice(typ, len(vals), len(vals))
		for i, val := range vals {
			err := processField(val, sl.Index(i))
			if err != nil {
				return err
			}
		}
		field.Set(sl)
	}

	return nil
}
<|endoftext|>


<commit_before>/*
(BSD 2-clause license)

Copyright (c) 2014, Shawn Webb
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

   * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
   * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package network

import (
    "fmt"
    "strconv"
    "errors"
    "strings"
    "os/exec"
    "github.com/coopernurse/gorp"
    "github.com/virtbsd/VirtualMachine"
    "github.com/virtbsd/util"
    "github.com/nu7hatch/gouuid"
)

type NetworkPhysical struct {
    NetworkPhysicalID int
    NetworkUUID string
    Device string
}

type DeviceAddress struct {
    DeviceAddressID int
    DeviceUUID string
    Address string
}

type DeviceOption struct {
    DeviceOptionID int
    DeviceUUID string
    OptionKey string
    OptionValue string
}

type Network struct {
    UUID string
    Name string
    DeviceID int
    Options map[string]string `db:"-"`
    Addresses []string `db:"-"`
    Physicals []string `db:"-"`
}

type NetworkDevice struct {
    UUID string
    DeviceID int
    Options map[string]string `db:"-"`
    Addresses []string `db:"-"`
    Network *Network `db:"-"`
    NetworkUUID string
    VmUUID string
}

type Route struct {
    RouteID int
    VmUUID string
    Source string
    Destination string
}

func GetNetworks(db *gorp.DbMap) []Network {
    var networks []Network
    _, err := db.Select(&networks, "select * from Network")

    if err != nil {
        panic(err)
        return []Network{}
    }

    return networks
}

func GetNetwork(db map[string]interface{}, uuid string) *Network {
    var obj interface{}
    var err error

    if _, ok := db["dbmap"]; ok == true {
        obj, err = db["dbmap"].(*gorp.DbMap).Get(Network{}, uuid)
        if err != nil {
            panic(err)
            return nil
        }
    } else {
        obj, err = db["sqlexecutor"].(gorp.SqlExecutor).Get(Network{}, uuid)
        if err != nil {
            panic(err);
            return nil
        }
    }

    return obj.(*Network)
}

func (network *Network) PostGet(s gorp.SqlExecutor) error {
    var physicals []NetworkPhysical
    var options []DeviceOption
    var addresses []DeviceAddress

    _, err := s.Select(&physicals, "select * from NetworkPhysical where NetworkUUID = ?", network.UUID)
    if err == nil {
        for i := 0; i < len(physicals); i++ {
            network.Physicals = append(network.Physicals, physicals[i].Device)
        }
    } else {
        panic(err)
    }

    _, err = s.Select(&options, "select * from DeviceOption where DeviceUUID = ?", network.UUID)
    if err == nil {
        for i := 0; i < len(options); i++ {
            network.Options[options[i].OptionKey] = options[i].OptionValue
        }
    } else {
        panic(err)
    }

    _, err = s.Select(&addresses, "select * from DeviceAddress where DeviceUUID = ?", network.UUID)
    if err == nil {
        for i := 0; i < len(addresses); i++ {
            network.Addresses = append(network.Addresses, addresses[i].Address)
        }
    } else {
        panic(err)
    }

    return nil
}

func (device *NetworkDevice) PostGet(s gorp.SqlExecutor) error {
    device.Network = GetNetwork(map[string]interface{}{"sqlexecutor": s}, device.NetworkUUID)
    return nil
}

func GetNetworkDevices(db map[string]interface{}, vm VirtualMachine.VirtualMachine) []*NetworkDevice {
    var devices []*NetworkDevice

    if _, ok := db["dbmap"]; ok == true {
        _, err := db["dbmap"].(*gorp.DbMap).Select(&devices, "select * from NetworkDevice where VmUUID = ?", vm.GetUUID())
        if err != nil {
            panic(err)
            return nil
        }
    } else {
        _, err := db["sqlexecutor"].(gorp.SqlExecutor).Select(&devices, "select * from NetworkDevice where VmUUID = ?", vm.GetUUID())
        if err != nil {
            panic(err);
            return nil
        }
    }

    return devices
}

func (network *Network) IsOnline() bool {
    id := strconv.Itoa(network.DeviceID)

    cmd := exec.Command("/sbin/ifconfig", "bridge" + id)
    err := cmd.Run()

    if err != nil {
        return false
    }

    return true
}

func (network *Network) Start() error {
    id := strconv.Itoa(network.DeviceID)

    if network.IsOnline() {
        return nil
    }

    cmd := exec.Command("/sbin/ifconfig", "bridge" + id, "create")
    for k, v := range network.Options {
        cmd.Args = append(cmd.Args, k)
        if len(v) > 0 {
            cmd.Args = append(cmd.Args, v)
        }
    }

    if rawoutput, err := cmd.CombinedOutput(); err != nil {
        return fmt.Errorf("ERROR: ifconfig bridge%s create: %s", id, virtbsdutil.ByteToString(rawoutput))
    }

    cmd = exec.Command("/sbin/ifconfig", "bridge" + id, "up")
    if rawoutput, err := cmd.CombinedOutput(); err != nil {
        return fmt.Errorf("ERROR: ifconfig bridge%s up: %s", id, virtbsdutil.ByteToString(rawoutput))
    }

    for i := range network.Physicals {
        cmd = exec.Command("/sbin/ifconfig", "bridge" + id, "addm", network.Physicals[i])
        if rawoutput, err := cmd.CombinedOutput(); err != nil {
            return fmt.Errorf("ERROR: ifconfig bridge%s addm %s: %s", id, network.Physicals[i], virtbsdutil.ByteToString(rawoutput))
        }
    }

    for i := range network.Addresses {
        proto := "inet"
        if strings.Index(network.Addresses[i], ":") >= 0 {
            proto = "inet6"
        }

        cmd = exec.Command("/sbin/ifconfig", "bridge" + id, proto, network.Addresses[i], "alias")
        if rawoutput, err := cmd.CombinedOutput(); err != nil {
            return fmt.Errorf("ERROR: ifconfig bridge%s %s %s alias: %s", id, proto, network.Addresses[i], virtbsdutil.ByteToString(rawoutput))
        }
    }

    return nil
}

func (network *Network) Stop() error {
    id := strconv.Itoa(network.DeviceID)

    if network.IsOnline() == false {
        return nil
    }

    cmd := exec.Command("/sbin/ifconfig", "bridge" + id, "destroy")
    err := cmd.Run()

    return err
}

func (device *NetworkDevice) IsOnline() bool {
    id := strconv.Itoa(device.DeviceID)

    cmd := exec.Command("/sbin/ifconfig", "epair" + id + "a")
    err := cmd.Run()

    if err != nil {
        return false
    }

    return true
}

func (device *NetworkDevice) BringHostOnline() error {
    id := strconv.Itoa(device.DeviceID)

    if device.Network.IsOnline() == false {
        if err := device.Network.Start(); err != nil {
            return err
        }
    }

    if device.IsOnline() == true {
        if err := device.BringOffline(); err != nil {
            return err
        }
    }

    cmd := exec.Command("/sbin/ifconfig", "epair" + id, "create")
    if rawoutput, err := cmd.CombinedOutput(); err != nil {
        return fmt.Errorf("ERROR: ifconfig epair%sa create: %s", id, virtbsdutil.ByteToString(rawoutput))
    }

    cmd = exec.Command("/sbin/ifconfig", "bridge" + strconv.Itoa(device.Network.DeviceID), "addm", "epair" + id + "a")
    if rawoutput, err := cmd.CombinedOutput(); err != nil {
        return fmt.Errorf("ERROR: ifconfig bridge%s addm epair%sa: %s", strconv.Itoa(device.Network.DeviceID), id, virtbsdutil.ByteToString(rawoutput))
    }

    return nil
}

func (device *NetworkDevice) BringGuestOnline(vm VirtualMachine.VirtualMachine) error {
    id := strconv.Itoa(device.DeviceID)
    vmid := vm.GetUUID()
    deviceid := "epair" + id + "b"

    if vm.IsOnline() == false {
        return errors.New("VM is turned off. VM must be turned on to have its networking stack brought online")
    }

    if device.IsOnline() == false {
        if err := device.BringHostOnline(); err != nil {
            return err
        }
    }

    cmd := exec.Command("/sbin/ifconfig", deviceid, "vnet", vmid)
    for k, v := range device.Options {
        cmd.Args = append(cmd.Args, k)
        if len(v) > 0 {
            cmd.Args = append(cmd.Args, v)
        }
    }

    err := cmd.Run()

    if err != nil {
        return err
    }

    for i := range device.Addresses {
        proto := "inet"
        if strings.Index(device.Addresses[i], ":") >= 0 {
            proto = "inet6"
        }

        cmd = exec.Command("/usr/sbin/jexec", vmid, "/sbin/ifconfig", deviceid, proto, device.Addresses[i], "alias")
        err = cmd.Run()

        if err != nil {
            device.BringOffline()
            return err
        }
    }

    cmd = exec.Command("/usr/sbin/jexec", vmid, "/sbin/ifconfig", deviceid, "up")

    return nil
}

func (device *NetworkDevice) BringOffline() error {
    id := strconv.Itoa(device.DeviceID)

    if device.IsOnline() == false {
        return nil
    }

    cmd := exec.Command("/sbin/ifconfig", "epair" + id + "a", "destroy")
    err := cmd.Run()

    return err
}

func (network *Network) Persist(db *gorp.DbMap) error {
    return nil
}

func (device *NetworkDevice) Persist(db *gorp.DbMap, vm VirtualMachine.VirtualMachine) error {
    device.Network.Persist(db)

    if len(device.UUID) == 0 {
        uuid, _ := uuid.NewV4()
        device.UUID = uuid.String()

        db.Insert(device)
        return nil
    } else {
        db.Update(device)
    }

    return nil
}
<commit_msg>Marshall to JSON better<commit_after>/*
(BSD 2-clause license)

Copyright (c) 2014, Shawn Webb
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

   * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
   * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package network

import (
    "fmt"
    "strconv"
    "errors"
    "strings"
    "os/exec"
    "encoding/json"
    "github.com/coopernurse/gorp"
    "github.com/virtbsd/VirtualMachine"
    "github.com/virtbsd/util"
    "github.com/nu7hatch/gouuid"
)

type NetworkPhysical struct {
    NetworkPhysicalID int
    NetworkUUID string
    Device string
}

type DeviceAddress struct {
    DeviceAddressID int
    DeviceUUID string
    Address string
}

type DeviceOption struct {
    DeviceOptionID int
    DeviceUUID string
    OptionKey string
    OptionValue string
}

type Network struct {
    UUID string
    Name string
    DeviceID int
    Options map[string]string `db:"-"`
    Addresses []string `db:"-"`
    Physicals []string `db:"-"`
}

type NetworkDevice struct {
    UUID string
    DeviceID int
    Options map[string]string `db:"-"`
    Addresses []string `db:"-"`
    Network *Network `db:"-"`
    NetworkUUID string
    VmUUID string
}

type Route struct {
    RouteID int
    VmUUID string
    Source string
    Destination string
}

type NetworkJSON struct {
    UUID string
    Name string
    Status string
    Options map[string]string
    Addresses []string
    Physicals []string
}

type NetworkDeviceJSON struct {
    UUID string
    Status string
    Options map[string]string
    Addresses []string
    Network *Network
}

func GetNetworks(db *gorp.DbMap) []Network {
    var networks []Network
    _, err := db.Select(&networks, "select * from Network")

    if err != nil {
        panic(err)
        return []Network{}
    }

    return networks
}

func GetNetwork(db map[string]interface{}, uuid string) *Network {
    var obj interface{}
    var err error

    if _, ok := db["dbmap"]; ok == true {
        obj, err = db["dbmap"].(*gorp.DbMap).Get(Network{}, uuid)
        if err != nil {
            panic(err)
            return nil
        }
    } else {
        obj, err = db["sqlexecutor"].(gorp.SqlExecutor).Get(Network{}, uuid)
        if err != nil {
            panic(err);
            return nil
        }
    }

    return obj.(*Network)
}

func (network *Network) PostGet(s gorp.SqlExecutor) error {
    var physicals []NetworkPhysical
    var options []DeviceOption
    var addresses []DeviceAddress

    _, err := s.Select(&physicals, "select * from NetworkPhysical where NetworkUUID = ?", network.UUID)
    if err == nil {
        for i := 0; i < len(physicals); i++ {
            network.Physicals = append(network.Physicals, physicals[i].Device)
        }
    } else {
        panic(err)
    }

    _, err = s.Select(&options, "select * from DeviceOption where DeviceUUID = ?", network.UUID)
    if err == nil {
        for i := 0; i < len(options); i++ {
            network.Options[options[i].OptionKey] = options[i].OptionValue
        }
    } else {
        panic(err)
    }

    _, err = s.Select(&addresses, "select * from DeviceAddress where DeviceUUID = ?", network.UUID)
    if err == nil {
        for i := 0; i < len(addresses); i++ {
            network.Addresses = append(network.Addresses, addresses[i].Address)
        }
    } else {
        panic(err)
    }

    return nil
}

func (device *NetworkDevice) PostGet(s gorp.SqlExecutor) error {
    device.Network = GetNetwork(map[string]interface{}{"sqlexecutor": s}, device.NetworkUUID)
    return nil
}

func GetNetworkDevices(db map[string]interface{}, vm VirtualMachine.VirtualMachine) []*NetworkDevice {
    var devices []*NetworkDevice

    if _, ok := db["dbmap"]; ok == true {
        _, err := db["dbmap"].(*gorp.DbMap).Select(&devices, "select * from NetworkDevice where VmUUID = ?", vm.GetUUID())
        if err != nil {
            panic(err)
            return nil
        }
    } else {
        _, err := db["sqlexecutor"].(gorp.SqlExecutor).Select(&devices, "select * from NetworkDevice where VmUUID = ?", vm.GetUUID())
        if err != nil {
            panic(err);
            return nil
        }
    }

    return devices
}

func (network *Network) IsOnline() bool {
    id := strconv.Itoa(network.DeviceID)

    cmd := exec.Command("/sbin/ifconfig", "bridge" + id)
    err := cmd.Run()

    if err != nil {
        return false
    }

    return true
}

func (network *Network) Start() error {
    id := strconv.Itoa(network.DeviceID)

    if network.IsOnline() {
        return nil
    }

    cmd := exec.Command("/sbin/ifconfig", "bridge" + id, "create")
    for k, v := range network.Options {
        cmd.Args = append(cmd.Args, k)
        if len(v) > 0 {
            cmd.Args = append(cmd.Args, v)
        }
    }

    if rawoutput, err := cmd.CombinedOutput(); err != nil {
        return fmt.Errorf("ERROR: ifconfig bridge%s create: %s", id, virtbsdutil.ByteToString(rawoutput))
    }

    cmd = exec.Command("/sbin/ifconfig", "bridge" + id, "up")
    if rawoutput, err := cmd.CombinedOutput(); err != nil {
        return fmt.Errorf("ERROR: ifconfig bridge%s up: %s", id, virtbsdutil.ByteToString(rawoutput))
    }

    for i := range network.Physicals {
        cmd = exec.Command("/sbin/ifconfig", "bridge" + id, "addm", network.Physicals[i])
        if rawoutput, err := cmd.CombinedOutput(); err != nil {
            return fmt.Errorf("ERROR: ifconfig bridge%s addm %s: %s", id, network.Physicals[i], virtbsdutil.ByteToString(rawoutput))
        }
    }

    for i := range network.Addresses {
        proto := "inet"
        if strings.Index(network.Addresses[i], ":") >= 0 {
            proto = "inet6"
        }

        cmd = exec.Command("/sbin/ifconfig", "bridge" + id, proto, network.Addresses[i], "alias")
        if rawoutput, err := cmd.CombinedOutput(); err != nil {
            return fmt.Errorf("ERROR: ifconfig bridge%s %s %s alias: %s", id, proto, network.Addresses[i], virtbsdutil.ByteToString(rawoutput))
        }
    }

    return nil
}

func (network *Network) Stop() error {
    id := strconv.Itoa(network.DeviceID)

    if network.IsOnline() == false {
        return nil
    }

    cmd := exec.Command("/sbin/ifconfig", "bridge" + id, "destroy")
    err := cmd.Run()

    return err
}

func (device *NetworkDevice) IsOnline() bool {
    id := strconv.Itoa(device.DeviceID)

    cmd := exec.Command("/sbin/ifconfig", "epair" + id + "a")
    err := cmd.Run()

    if err != nil {
        return false
    }

    return true
}

func (device *NetworkDevice) BringHostOnline() error {
    id := strconv.Itoa(device.DeviceID)

    if device.Network.IsOnline() == false {
        if err := device.Network.Start(); err != nil {
            return err
        }
    }

    if device.IsOnline() == true {
        if err := device.BringOffline(); err != nil {
            return err
        }
    }

    cmd := exec.Command("/sbin/ifconfig", "epair" + id, "create")
    if rawoutput, err := cmd.CombinedOutput(); err != nil {
        return fmt.Errorf("ERROR: ifconfig epair%sa create: %s", id, virtbsdutil.ByteToString(rawoutput))
    }

    cmd = exec.Command("/sbin/ifconfig", "bridge" + strconv.Itoa(device.Network.DeviceID), "addm", "epair" + id + "a")
    if rawoutput, err := cmd.CombinedOutput(); err != nil {
        return fmt.Errorf("ERROR: ifconfig bridge%s addm epair%sa: %s", strconv.Itoa(device.Network.DeviceID), id, virtbsdutil.ByteToString(rawoutput))
    }

    return nil
}

func (device *NetworkDevice) BringGuestOnline(vm VirtualMachine.VirtualMachine) error {
    id := strconv.Itoa(device.DeviceID)
    vmid := vm.GetUUID()
    deviceid := "epair" + id + "b"

    if vm.IsOnline() == false {
        return errors.New("VM is turned off. VM must be turned on to have its networking stack brought online")
    }

    if device.IsOnline() == false {
        if err := device.BringHostOnline(); err != nil {
            return err
        }
    }

    cmd := exec.Command("/sbin/ifconfig", deviceid, "vnet", vmid)
    for k, v := range device.Options {
        cmd.Args = append(cmd.Args, k)
        if len(v) > 0 {
            cmd.Args = append(cmd.Args, v)
        }
    }

    err := cmd.Run()

    if err != nil {
        return err
    }

    for i := range device.Addresses {
        proto := "inet"
        if strings.Index(device.Addresses[i], ":") >= 0 {
            proto = "inet6"
        }

        cmd = exec.Command("/usr/sbin/jexec", vmid, "/sbin/ifconfig", deviceid, proto, device.Addresses[i], "alias")
        err = cmd.Run()

        if err != nil {
            device.BringOffline()
            return err
        }
    }

    cmd = exec.Command("/usr/sbin/jexec", vmid, "/sbin/ifconfig", deviceid, "up")

    return nil
}

func (device *NetworkDevice) BringOffline() error {
    id := strconv.Itoa(device.DeviceID)

    if device.IsOnline() == false {
        return nil
    }

    cmd := exec.Command("/sbin/ifconfig", "epair" + id + "a", "destroy")
    err := cmd.Run()

    return err
}

func (network *Network) Persist(db *gorp.DbMap) error {
    return nil
}

func (device *NetworkDevice) Persist(db *gorp.DbMap, vm VirtualMachine.VirtualMachine) error {
    device.Network.Persist(db)

    if len(device.UUID) == 0 {
        uuid, _ := uuid.NewV4()
        device.UUID = uuid.String()

        db.Insert(device)
        return nil
    } else {
        db.Update(device)
    }

    return nil
}

func (network *Network) MarshalJSON() ([]byte, error) {
    obj := NetworkJSON{}
    obj.UUID = network.UUID
    obj.Name = network.Name
    obj.Options = network.Options
    obj.Addresses = network.Addresses
    obj.Physicals = network.Physicals

    if network.IsOnline() {
        obj.Status = "Online"
    } else {
        obj.Status = "Offline"
    }

    return json.MarshalIndent(obj, "", "    ")
}

func (device *NetworkDevice) MarshalJSON() ([]byte, error) {
    obj := NetworkDeviceJSON{}
    obj.UUID = device.UUID
    obj.Options = device.Options
    obj.Addresses = device.Addresses
    obj.Network = device.Network

    if device.IsOnline() {
        obj.Status = "Online"
    } else {
        obj.Status = "Offline"
    }

    bytes, err := json.MarshalIndent(obj, "", "    ")
    return bytes, err
}
<|endoftext|>


<commit_before>package libvirt

/*
#cgo LDFLAGS: -lvirt
#include <libvirt/libvirt.h>
#include <libvirt/virterror.h>
#include <stdlib.h>
*/
import "C"

import (
	"reflect"
	"time"
	"unsafe"
)

// virIPAddrType
const (
	VIR_IP_ADDR_TYPE_IPV4 = C.VIR_IP_ADDR_TYPE_IPV4
	VIR_IP_ADDR_TYPE_IPV6 = C.VIR_IP_ADDR_TYPE_IPV6
)

type VirNetwork struct {
	ptr C.virNetworkPtr
}

func (n *VirNetwork) Free() error {
	if result := C.virNetworkFree(n.ptr); result != 0 {
		return GetLastError()
	}
	return nil
}

func (n *VirNetwork) Create() error {
	result := C.virNetworkCreate(n.ptr)
	if result == -1 {
		return GetLastError()
	}
	return nil
}

func (n *VirNetwork) Destroy() error {
	result := C.virNetworkDestroy(n.ptr)
	if result == -1 {
		return GetLastError()
	}
	return nil
}

func (n *VirNetwork) IsActive() (bool, error) {
	result := C.virNetworkIsActive(n.ptr)
	if result == -1 {
		return false, GetLastError()
	}
	if result == 1 {
		return true, nil
	}
	return false, nil
}

func (n *VirNetwork) IsPersistent() (bool, error) {
	result := C.virNetworkIsPersistent(n.ptr)
	if result == -1 {
		return false, GetLastError()
	}
	if result == 1 {
		return true, nil
	}
	return false, nil
}

func (n *VirNetwork) GetAutostart() (bool, error) {
	var out C.int
	result := C.virNetworkGetAutostart(n.ptr, (*C.int)(unsafe.Pointer(&out)))
	if result == -1 {
		return false, GetLastError()
	}
	switch out {
	case 1:
		return true, nil
	default:
		return false, nil
	}
}

func (n *VirNetwork) SetAutostart(autostart bool) error {
	var cAutostart C.int
	switch autostart {
	case true:
		cAutostart = 1
	default:
		cAutostart = 0
	}
	result := C.virNetworkSetAutostart(n.ptr, cAutostart)
	if result == -1 {
		return GetLastError()
	}
	return nil
}

func (n *VirNetwork) GetName() (string, error) {
	name := C.virNetworkGetName(n.ptr)
	if name == nil {
		return "", GetLastError()
	}
	return C.GoString(name), nil
}

func (n *VirNetwork) GetUUID() ([]byte, error) {
	var cUuid [C.VIR_UUID_BUFLEN](byte)
	cuidPtr := unsafe.Pointer(&cUuid)
	result := C.virNetworkGetUUID(n.ptr, (*C.uchar)(cuidPtr))
	if result != 0 {
		return []byte{}, GetLastError()
	}
	return C.GoBytes(cuidPtr, C.VIR_UUID_BUFLEN), nil
}

func (n *VirNetwork) GetUUIDString() (string, error) {
	var cUuid [C.VIR_UUID_STRING_BUFLEN](C.char)
	cuidPtr := unsafe.Pointer(&cUuid)
	result := C.virNetworkGetUUIDString(n.ptr, (*C.char)(cuidPtr))
	if result != 0 {
		return "", GetLastError()
	}
	return C.GoString((*C.char)(cuidPtr)), nil
}

func (n *VirNetwork) GetBridgeName() (string, error) {
	result := C.virNetworkGetBridgeName(n.ptr)
	if result == nil {
		return "", GetLastError()
	}
	bridge := C.GoString(result)
	C.free(unsafe.Pointer(result))
	return bridge, nil
}

func (n *VirNetwork) GetXMLDesc(flags uint32) (string, error) {
	result := C.virNetworkGetXMLDesc(n.ptr, C.uint(flags))
	if result == nil {
		return "", GetLastError()
	}
	xml := C.GoString(result)
	C.free(unsafe.Pointer(result))
	return xml, nil
}

func (n *VirNetwork) Undefine() error {
	result := C.virNetworkUndefine(n.ptr)
	if result == -1 {
		return GetLastError()
	}
	return nil
}

func (n *VirNetwork) GetDHCPLeases() ([]VirNetworkDHCPLease, error) {
	var cLeases *C.virNetworkDHCPLeasePtr
	numLeases := C.virNetworkGetDHCPLeases(n.ptr, nil, (**C.virNetworkDHCPLeasePtr)(&cLeases), C.uint(0))
	if numLeases == -1 {
		return nil, GetLastError()
	}
	hdr := reflect.SliceHeader{
		Data: uintptr(unsafe.Pointer(cLeases)),
		Len:  int(numLeases),
		Cap:  int(numLeases),
	}
	var leases []VirNetworkDHCPLease
	slice := *(*[]C.virNetworkDHCPLeasePtr)(unsafe.Pointer(&hdr))
	for _, ptr := range slice {
		leases = append(leases, VirNetworkDHCPLease{ptr})
	}
	C.free(unsafe.Pointer(cLeases))
	return leases, nil
}

type VirNetworkDHCPLease struct {
	ptr C.virNetworkDHCPLeasePtr
}

func (l *VirNetworkDHCPLease) GetIface() string {
	return C.GoString(l.ptr.iface)
}

func (l *VirNetworkDHCPLease) GetExpiryTime() time.Time {
	return time.Unix(int64(l.ptr.expirytime), 0)
}

func (l *VirNetworkDHCPLease) GetMACAddress() string {
	return C.GoString(l.ptr.mac)
}

func (l *VirNetworkDHCPLease) GetIPAddress() string {
	return C.GoString(l.ptr.ipaddr)
}

func (l *VirNetworkDHCPLease) GetIPPrefix() uint {
	return uint(l.ptr.prefix)
}

func (l *VirNetworkDHCPLease) GetHostname() string {
	return C.GoString(l.ptr.hostname)
}

func (l *VirNetworkDHCPLease) GetClientID() string {
	return C.GoString(l.ptr.clientid)
}
<commit_msg>Use named types for network enum constants<commit_after>package libvirt

/*
#cgo LDFLAGS: -lvirt
#include <libvirt/libvirt.h>
#include <libvirt/virterror.h>
#include <stdlib.h>
*/
import "C"

import (
	"reflect"
	"time"
	"unsafe"
)

type VirIPAddrType int

const (
	VIR_IP_ADDR_TYPE_IPV4 = VirIPAddrType(C.VIR_IP_ADDR_TYPE_IPV4)
	VIR_IP_ADDR_TYPE_IPV6 = VirIPAddrType(C.VIR_IP_ADDR_TYPE_IPV6)
)

type VirNetwork struct {
	ptr C.virNetworkPtr
}

func (n *VirNetwork) Free() error {
	if result := C.virNetworkFree(n.ptr); result != 0 {
		return GetLastError()
	}
	return nil
}

func (n *VirNetwork) Create() error {
	result := C.virNetworkCreate(n.ptr)
	if result == -1 {
		return GetLastError()
	}
	return nil
}

func (n *VirNetwork) Destroy() error {
	result := C.virNetworkDestroy(n.ptr)
	if result == -1 {
		return GetLastError()
	}
	return nil
}

func (n *VirNetwork) IsActive() (bool, error) {
	result := C.virNetworkIsActive(n.ptr)
	if result == -1 {
		return false, GetLastError()
	}
	if result == 1 {
		return true, nil
	}
	return false, nil
}

func (n *VirNetwork) IsPersistent() (bool, error) {
	result := C.virNetworkIsPersistent(n.ptr)
	if result == -1 {
		return false, GetLastError()
	}
	if result == 1 {
		return true, nil
	}
	return false, nil
}

func (n *VirNetwork) GetAutostart() (bool, error) {
	var out C.int
	result := C.virNetworkGetAutostart(n.ptr, (*C.int)(unsafe.Pointer(&out)))
	if result == -1 {
		return false, GetLastError()
	}
	switch out {
	case 1:
		return true, nil
	default:
		return false, nil
	}
}

func (n *VirNetwork) SetAutostart(autostart bool) error {
	var cAutostart C.int
	switch autostart {
	case true:
		cAutostart = 1
	default:
		cAutostart = 0
	}
	result := C.virNetworkSetAutostart(n.ptr, cAutostart)
	if result == -1 {
		return GetLastError()
	}
	return nil
}

func (n *VirNetwork) GetName() (string, error) {
	name := C.virNetworkGetName(n.ptr)
	if name == nil {
		return "", GetLastError()
	}
	return C.GoString(name), nil
}

func (n *VirNetwork) GetUUID() ([]byte, error) {
	var cUuid [C.VIR_UUID_BUFLEN](byte)
	cuidPtr := unsafe.Pointer(&cUuid)
	result := C.virNetworkGetUUID(n.ptr, (*C.uchar)(cuidPtr))
	if result != 0 {
		return []byte{}, GetLastError()
	}
	return C.GoBytes(cuidPtr, C.VIR_UUID_BUFLEN), nil
}

func (n *VirNetwork) GetUUIDString() (string, error) {
	var cUuid [C.VIR_UUID_STRING_BUFLEN](C.char)
	cuidPtr := unsafe.Pointer(&cUuid)
	result := C.virNetworkGetUUIDString(n.ptr, (*C.char)(cuidPtr))
	if result != 0 {
		return "", GetLastError()
	}
	return C.GoString((*C.char)(cuidPtr)), nil
}

func (n *VirNetwork) GetBridgeName() (string, error) {
	result := C.virNetworkGetBridgeName(n.ptr)
	if result == nil {
		return "", GetLastError()
	}
	bridge := C.GoString(result)
	C.free(unsafe.Pointer(result))
	return bridge, nil
}

func (n *VirNetwork) GetXMLDesc(flags uint32) (string, error) {
	result := C.virNetworkGetXMLDesc(n.ptr, C.uint(flags))
	if result == nil {
		return "", GetLastError()
	}
	xml := C.GoString(result)
	C.free(unsafe.Pointer(result))
	return xml, nil
}

func (n *VirNetwork) Undefine() error {
	result := C.virNetworkUndefine(n.ptr)
	if result == -1 {
		return GetLastError()
	}
	return nil
}

func (n *VirNetwork) GetDHCPLeases() ([]VirNetworkDHCPLease, error) {
	var cLeases *C.virNetworkDHCPLeasePtr
	numLeases := C.virNetworkGetDHCPLeases(n.ptr, nil, (**C.virNetworkDHCPLeasePtr)(&cLeases), C.uint(0))
	if numLeases == -1 {
		return nil, GetLastError()
	}
	hdr := reflect.SliceHeader{
		Data: uintptr(unsafe.Pointer(cLeases)),
		Len:  int(numLeases),
		Cap:  int(numLeases),
	}
	var leases []VirNetworkDHCPLease
	slice := *(*[]C.virNetworkDHCPLeasePtr)(unsafe.Pointer(&hdr))
	for _, ptr := range slice {
		leases = append(leases, VirNetworkDHCPLease{ptr})
	}
	C.free(unsafe.Pointer(cLeases))
	return leases, nil
}

type VirNetworkDHCPLease struct {
	ptr C.virNetworkDHCPLeasePtr
}

func (l *VirNetworkDHCPLease) GetIface() string {
	return C.GoString(l.ptr.iface)
}

func (l *VirNetworkDHCPLease) GetExpiryTime() time.Time {
	return time.Unix(int64(l.ptr.expirytime), 0)
}

func (l *VirNetworkDHCPLease) GetMACAddress() string {
	return C.GoString(l.ptr.mac)
}

func (l *VirNetworkDHCPLease) GetIPAddress() string {
	return C.GoString(l.ptr.ipaddr)
}

func (l *VirNetworkDHCPLease) GetIPPrefix() uint {
	return uint(l.ptr.prefix)
}

func (l *VirNetworkDHCPLease) GetHostname() string {
	return C.GoString(l.ptr.hostname)
}

func (l *VirNetworkDHCPLease) GetClientID() string {
	return C.GoString(l.ptr.clientid)
}
<|endoftext|>


<commit_before>package main

import (
	"golang.org/x/exp/inotify"
	"io/ioutil"
	"log"
	"net"
	"strconv"
	"strings"
	"sync"
	"time"
)

type networkMessage struct {
	msg     []byte
	msgType uint8
}

type networkConnection struct {
	Conn       *net.UDPConn
	Ip         string
	Port       uint32
	Capability uint8
}

var messageQueue chan networkMessage
var outSockets map[string]networkConnection
var dhcpLeases map[string]string
var netMutex *sync.Mutex

const (
	NETWORK_GDL90_STANDARD   = 1
	NETWORK_AHRS_FFSIM    = 2
	NETWORK_AHRS_GDL90    = 4
	dhcp_lease_file = "/var/lib/dhcp/dhcpd.leases"
)

// Read the "dhcpd.leases" file and parse out IP/hostname.
func getDHCPLeases() (map[string]string, error) {
	dat, err := ioutil.ReadFile(dhcp_lease_file)
	ret := make(map[string]string)
	if err != nil {
		return ret, err
	}
	lines := strings.Split(string(dat), "\n")
	open_block := false
	block_ip := ""
	for _, line := range lines {
		spaced := strings.Split(line, " ")
		if len(spaced) > 2 && spaced[0] == "lease" {
			open_block = true
			block_ip = spaced[1]
		} else if open_block && len(spaced) >= 4 && spaced[2] == "client-hostname" {
			hostname := strings.TrimRight(strings.TrimLeft(strings.Join(spaced[3:], " "), "\""), "\";")
			ret[block_ip] = hostname
			open_block = false
		}
	}
	return ret, nil
}

func sendToAllConnectedClients(msg networkMessage) {
	netMutex.Lock()
	defer netMutex.Unlock()
	for _, netconn := range outSockets {
		if (netconn.Capability & msg.msgType) != 0 { // Check if this port is able to accept the type of message we're sending.
			netconn.Conn.Write(msg.msg)
		}
	}
}

// Just returns the number of DHCP leases for now.
func getNetworkStats() uint {
	ret := uint(len(dhcpLeases))
	globalStatus.Connected_Users = ret
	return ret
}

// See who has a DHCP lease and make a UDP connection to each of them.
func refreshConnectedClients() {
	netMutex.Lock()
	defer netMutex.Unlock()
	validConnections := make(map[string]bool)
	t, err := getDHCPLeases()
	if err != nil {
		log.Printf("getDHCPLeases(): %s\n", err.Error())
		return
	}
	dhcpLeases = t
	// Client connected that wasn't before.
	for ip, hostname := range dhcpLeases {
		for _, networkOutput := range globalSettings.NetworkOutputs {
			ipAndPort := ip + ":" + strconv.Itoa(int(networkOutput.Port))
			if _, ok := outSockets[ipAndPort]; !ok {
				log.Printf("client connected: %s:%d (%s).\n", ip, networkOutput.Port, hostname)
				addr, err := net.ResolveUDPAddr("udp", ipAndPort)
				if err != nil {
					log.Printf("ResolveUDPAddr(%s): %s\n", ipAndPort, err.Error())
					continue
				}
				outConn, err := net.DialUDP("udp", nil, addr)
				if err != nil {
					log.Printf("DialUDP(%s): %s\n", ipAndPort, err.Error())
					continue
				}
				outSockets[ipAndPort] = networkConnection{outConn, ip, networkOutput.Port, networkOutput.Capability}
			}
			validConnections[ipAndPort] = true
		}
	}
	// Client that was connected before that isn't.
	for ipAndPort, conn := range outSockets {
		if _, ok := validConnections[ipAndPort]; !ok {
			log.Printf("removed connection %s.\n", ipAndPort)
			conn.Conn.Close()
			delete(outSockets, ipAndPort)
		}
	}
}

func messageQueueSender() {
	secondTimer := time.NewTicker(5 * time.Second)
	for {
		select {
		case msg := <-messageQueue:
			sendToAllConnectedClients(msg)
		case <-secondTimer.C:
			getNetworkStats()
		}
	}
}

func sendMsg(msg []byte, msgType uint8) {
	messageQueue <- networkMessage{msg, msgType}
}

func sendGDL90(msg []byte) {
	sendMsg(msg, NETWORK_GDL90_STANDARD)
}

func monitorDHCPLeases() {
	watcher, err := inotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}
	err = watcher.AddWatch(dhcp_lease_file, inotify.IN_MODIFY)
	if err != nil {
		log.Fatal(err)
	}
	for {
		select {
		case <-watcher.Event:
			log.Println("file modified, attempting to refresh DHCP")
			refreshConnectedClients()
		case err := <-watcher.Error:
			log.Println("error with DHCP file system watcher:", err)
		}
	}
}

func initNetwork() {
	messageQueue = make(chan networkMessage, 1024) // Buffered channel, 1024 messages.
	outSockets = make(map[string]networkConnection)
	netMutex = &sync.Mutex{}
	refreshConnectedClients()
	go monitorDHCPLeases()
	go messageQueueSender()
}
<commit_msg>dhcpd removing files, causing refresh issues.<commit_after>package main

import (
	"io/ioutil"
	"log"
	"net"
	"strconv"
	"strings"
	"sync"
	"time"
)

type networkMessage struct {
	msg     []byte
	msgType uint8
}

type networkConnection struct {
	Conn       *net.UDPConn
	Ip         string
	Port       uint32
	Capability uint8
}

var messageQueue chan networkMessage
var outSockets map[string]networkConnection
var dhcpLeases map[string]string
var netMutex *sync.Mutex

const (
	NETWORK_GDL90_STANDARD   = 1
	NETWORK_AHRS_FFSIM    = 2
	NETWORK_AHRS_GDL90    = 4
	dhcp_lease_file = "/var/lib/dhcp/dhcpd.leases"
)

// Read the "dhcpd.leases" file and parse out IP/hostname.
func getDHCPLeases() (map[string]string, error) {
	dat, err := ioutil.ReadFile(dhcp_lease_file)
	ret := make(map[string]string)
	if err != nil {
		return ret, err
	}
	lines := strings.Split(string(dat), "\n")
	open_block := false
	block_ip := ""
	for _, line := range lines {
		spaced := strings.Split(line, " ")
		if len(spaced) > 2 && spaced[0] == "lease" {
			open_block = true
			block_ip = spaced[1]
		} else if open_block && len(spaced) >= 4 && spaced[2] == "client-hostname" {
			hostname := strings.TrimRight(strings.TrimLeft(strings.Join(spaced[3:], " "), "\""), "\";")
			ret[block_ip] = hostname
			open_block = false
		}
	}
	return ret, nil
}

func sendToAllConnectedClients(msg networkMessage) {
	netMutex.Lock()
	defer netMutex.Unlock()
	for _, netconn := range outSockets {
		if (netconn.Capability & msg.msgType) != 0 { // Check if this port is able to accept the type of message we're sending.
			netconn.Conn.Write(msg.msg)
		}
	}
}

// Just returns the number of DHCP leases for now.
func getNetworkStats() uint {
	ret := uint(len(dhcpLeases))
	globalStatus.Connected_Users = ret
	return ret
}

// See who has a DHCP lease and make a UDP connection to each of them.
func refreshConnectedClients() {
	netMutex.Lock()
	defer netMutex.Unlock()
	validConnections := make(map[string]bool)
	t, err := getDHCPLeases()
	if err != nil {
		log.Printf("getDHCPLeases(): %s\n", err.Error())
		return
	}
	dhcpLeases = t
	// Client connected that wasn't before.
	for ip, hostname := range dhcpLeases {
		for _, networkOutput := range globalSettings.NetworkOutputs {
			ipAndPort := ip + ":" + strconv.Itoa(int(networkOutput.Port))
			if _, ok := outSockets[ipAndPort]; !ok {
				log.Printf("client connected: %s:%d (%s).\n", ip, networkOutput.Port, hostname)
				addr, err := net.ResolveUDPAddr("udp", ipAndPort)
				if err != nil {
					log.Printf("ResolveUDPAddr(%s): %s\n", ipAndPort, err.Error())
					continue
				}
				outConn, err := net.DialUDP("udp", nil, addr)
				if err != nil {
					log.Printf("DialUDP(%s): %s\n", ipAndPort, err.Error())
					continue
				}
				outSockets[ipAndPort] = networkConnection{outConn, ip, networkOutput.Port, networkOutput.Capability}
			}
			validConnections[ipAndPort] = true
		}
	}
	// Client that was connected before that isn't.
	for ipAndPort, conn := range outSockets {
		if _, ok := validConnections[ipAndPort]; !ok {
			log.Printf("removed connection %s.\n", ipAndPort)
			conn.Conn.Close()
			delete(outSockets, ipAndPort)
		}
	}
}

func messageQueueSender() {
	secondTimer := time.NewTicker(5 * time.Second)
	for {
		select {
		case msg := <-messageQueue:
			sendToAllConnectedClients(msg)
		case <-secondTimer.C:
			getNetworkStats()
		}
	}
}

func sendMsg(msg []byte, msgType uint8) {
	messageQueue <- networkMessage{msg, msgType}
}

func sendGDL90(msg []byte) {
	sendMsg(msg, NETWORK_GDL90_STANDARD)
}

func monitorDHCPLeases() {
	//TODO: inotify or dhcp event hook.
	timer := time.NewTicker(30 * time.Second)
	for {
		select {
		case <-timer.C:
			refreshConnectedClients()
		}
	}
}

func initNetwork() {
	messageQueue = make(chan networkMessage, 1024) // Buffered channel, 1024 messages.
	outSockets = make(map[string]networkConnection)
	netMutex = &sync.Mutex{}
	refreshConnectedClients()
	go monitorDHCPLeases()
	go messageQueueSender()
}
<|endoftext|>


<commit_before>package main

import (
	"appengine"
	"appengine/datastore"
	"html/template"
	"net/http"
)

type Answer struct {
	Value string
}

type Password struct {
	Value string
}

func init() {
	http.HandleFunc("/", getAnswer)
	http.HandleFunc("/yes", setAnswer("yes"))
	http.HandleFunc("/no", setAnswer("no"))
}

func getAnswer(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	k := datastore.NewKey(c, "Answer", "answer", 0, nil)
	a := new(Answer)
	if err := datastore.Get(c, k, a); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	t := template.Must(template.ParseFiles("index.template"))
	if err := t.Execute(w, a); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func authorized(r *http.Request) bool {
  _, password, ok := r.BasicAuth()
  if !ok {
		return false
	}
	c := appengine.NewContext(r)
	k := datastore.NewKey(c, "Password", "password", 0, nil)
	p := new(Password)
	if err := datastore.Get(c, k, p); err != nil {
		// If password is not set, seed with whatever password was passed in.
		// See: http://golang.org/misc/dashboard/app/build/key.go
		dp := Password{
			Value: password,
		}
		if _, err := datastore.Put(c, k, &dp); err != nil {
			return false
		}
		return true
	}
	return p.Value == password
}

func setAnswer(answer string) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		if !authorized(r) {
			w.Header().Set("WWW-Authenticate", "Basic realm=\"novelty.go\"")
			http.Error(w, "Unauthorized", http.StatusUnauthorized)
			return
		}
		c := appengine.NewContext(r)
		k := datastore.NewKey(c, "Answer", "answer", 0, nil)
		a := Answer{
			Value: answer,
		}
		if _, err := datastore.Put(c, k, &a); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		http.Redirect(w, r, "/", http.StatusFound)
	}
}
<commit_msg>Leave out optional realm<commit_after>package main

import (
	"appengine"
	"appengine/datastore"
	"html/template"
	"net/http"
)

type Answer struct {
	Value string
}

type Password struct {
	Value string
}

func init() {
	http.HandleFunc("/", getAnswer)
	http.HandleFunc("/yes", setAnswer("yes"))
	http.HandleFunc("/no", setAnswer("no"))
}

func getAnswer(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	k := datastore.NewKey(c, "Answer", "answer", 0, nil)
	a := new(Answer)
	if err := datastore.Get(c, k, a); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	t := template.Must(template.ParseFiles("index.template"))
	if err := t.Execute(w, a); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func authorized(r *http.Request) bool {
  _, password, ok := r.BasicAuth()
  if !ok {
		return false
	}
	c := appengine.NewContext(r)
	k := datastore.NewKey(c, "Password", "password", 0, nil)
	p := new(Password)
	if err := datastore.Get(c, k, p); err != nil {
		// If password is not set, seed with whatever password was passed in.
		// See: http://golang.org/misc/dashboard/app/build/key.go
		dp := Password{
			Value: password,
		}
		if _, err := datastore.Put(c, k, &dp); err != nil {
			return false
		}
		return true
	}
	return p.Value == password
}

func setAnswer(answer string) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		if !authorized(r) {
			w.Header().Set("WWW-Authenticate", "Basic")
			http.Error(w, "Unauthorized", http.StatusUnauthorized)
			return
		}
		c := appengine.NewContext(r)
		k := datastore.NewKey(c, "Answer", "answer", 0, nil)
		a := Answer{
			Value: answer,
		}
		if _, err := datastore.Put(c, k, &a); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		http.Redirect(w, r, "/", http.StatusFound)
	}
}
<|endoftext|>


<commit_before>// Copyright 2014, David Howden
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package numerus is a simple implemetation of Roman Numerals.
package numerus

import (
	"errors"
	"fmt"
	"strings"
)

type numeral interface {
	Value() uint
	String() string
}

type sym struct {
	s string
	v uint
}

func (s sym) Value() uint {
	return s.v
}

func (s sym) String() string {
	return s.s
}

type comb struct {
	a, b sym // NB: a < b
}

func (c comb) Value() uint {
	return c.b.Value() - c.a.Value()
}

func (c comb) String() string {
	return c.a.String() + c.b.String()
}

var (
	_I = sym{"I", 1}
	_V = sym{"V", 5}
	_X = sym{"X", 10}
	_L = sym{"L", 50}
	_C = sym{"C", 100}
	_D = sym{"D", 500}
	_M = sym{"M", 1000}

	_IV = comb{_I, _V}
	_IX = comb{_I, _X}
	_XL = comb{_X, _L}
	_XC = comb{_X, _C}
	_CD = comb{_C, _D}
	_CM = comb{_C, _M}
)

var descNumerals = []numeral{_M, _CM, _D, _CD, _C, _XC, _L, _XL, _X, _IX, _V, _IV, _I}

// Limit is the upper bound of possible numerals allowed by this package
// (this limit is set by the rule which prohibits more than three consecutive Ms).
const Limit = Numeral(3999)

// Numeral represents a Roman Numeral value.
type Numeral uint

// String returns a string representing the underlying Numeral in standard
// Roman Numeral notation.
func (n Numeral) String() string {
	result := ""
	i := uint(n)

	for _, v := range descNumerals {
		for {
			if i < v.Value() {
				break
			}
			result += v.String()
			i -= v.Value()
		}
	}
	return result
}

// Value returns the underlying value of the numeral as a uint.
func (n Numeral) Value() uint {
	return uint(n)
}

// parse takes a string representation of a Roman Numeral (in standard form)
// and returns a uint and error value, which is set if the given input is not
// in the standard representation.
func parse(s string) (uint, error) {
	// As overflowing doesn't catch this, we test for it first
	if strings.Contains(s, "MMMM") {
		return 0, errors.New("invalid numeral near MMMM")
	}

	// Check the running totals so that we don't accept invalid input
	// i.e. MCMD should be MMCD
	check := make([]uint, len(descNumerals))

	n := uint(0)
	buf := s
	for i, v := range descNumerals {
		for {
			vs := v.String()
			if !strings.HasPrefix(buf, vs) {
				break
			}

			for j := 0; j < i; j++ {
				check[j] += v.Value()
				if check[j] >= descNumerals[j].Value() {
					return 0, fmt.Errorf("invalid numeral near %v", buf)
				}
			}
			n += v.Value()
			buf = buf[len(vs):]
		}
	}

	if len(buf) > 0 {
		return 0, fmt.Errorf("invalid numeral near %v", buf)
	}
	return n, nil
}

// Parse takes a string in standard Roman Numeral notation and returns a Numeral.
// If the given representation is invalid an error is returned.
func Parse(s string) (Numeral, error) {
	n, err := parse(s)
	if err != nil {
		return Numeral(0), err
	}
	return Numeral(n), err
}
<commit_msg>Further simplify main parse loop<commit_after>// Copyright 2014, David Howden
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package numerus is a simple implemetation of Roman Numerals.
package numerus

import (
	"errors"
	"fmt"
	"strings"
)

type numeral interface {
	Value() uint
	String() string
}

type sym struct {
	s string
	v uint
}

func (s sym) Value() uint {
	return s.v
}

func (s sym) String() string {
	return s.s
}

type comb struct {
	a, b sym // NB: a < b
}

func (c comb) Value() uint {
	return c.b.Value() - c.a.Value()
}

func (c comb) String() string {
	return c.a.String() + c.b.String()
}

var (
	_I = sym{"I", 1}
	_V = sym{"V", 5}
	_X = sym{"X", 10}
	_L = sym{"L", 50}
	_C = sym{"C", 100}
	_D = sym{"D", 500}
	_M = sym{"M", 1000}

	_IV = comb{_I, _V}
	_IX = comb{_I, _X}
	_XL = comb{_X, _L}
	_XC = comb{_X, _C}
	_CD = comb{_C, _D}
	_CM = comb{_C, _M}
)

var descNumerals = []numeral{_M, _CM, _D, _CD, _C, _XC, _L, _XL, _X, _IX, _V, _IV, _I}

// Limit is the upper bound of possible numerals allowed by this package
// (this limit is set by the rule which prohibits more than three consecutive Ms).
const Limit = Numeral(3999)

// Numeral represents a Roman Numeral value.
type Numeral uint

// String returns a string representing the underlying Numeral in standard
// Roman Numeral notation.
func (n Numeral) String() string {
	result := ""
	i := uint(n)

	for _, v := range descNumerals {
		for {
			if i < v.Value() {
				break
			}
			result += v.String()
			i -= v.Value()
		}
	}
	return result
}

// Value returns the underlying value of the numeral as a uint.
func (n Numeral) Value() uint {
	return uint(n)
}

// parse takes a string representation of a Roman Numeral (in standard form)
// and returns a uint and error value, which is set if the given input is not
// in the standard representation.
func parse(s string) (uint, error) {
	// As overflowing doesn't catch this, we test for it first
	if strings.Contains(s, "MMMM") {
		return 0, errors.New("invalid numeral near MMMM")
	}

	// Check the running totals so that we don't accept invalid input
	// i.e. MCMD should be MMCD
	check := make([]uint, len(descNumerals))

	n := uint(0)
	for i, v := range descNumerals {
		vs := v.String()
		for {
			if !strings.HasPrefix(s, vs) {
				break
			}

			for j := 0; j < i; j++ {
				check[j] += v.Value()
				if check[j] >= descNumerals[j].Value() {
					return 0, fmt.Errorf("invalid numeral near %v", s)
				}
			}
			n += v.Value()
			s = s[len(vs):]
		}
	}

	if len(s) > 0 {
		return 0, fmt.Errorf("invalid numeral near %v", s)
	}
	return n, nil
}

// Parse takes a string in standard Roman Numeral notation and returns a Numeral.
// If the given representation is invalid an error is returned.
func Parse(s string) (Numeral, error) {
	n, err := parse(s)
	if err != nil {
		return Numeral(0), err
	}
	return Numeral(n), err
}
<|endoftext|>