<commit_before>package main

import (
	"errors"
	"fmt"
	"image"
	"image/color"
	"image/jpeg"
	_ "image/png"
	"math"
	"os"
	"time"
)

var (
	aspect                  = 0
	cropWidth               = 0.0
	cropHeight              = 0.0
	detailWeight            = 0.2
	skinColor               = [3]float64{0.78, 0.57, 0.44}
	skinBias                = 0.01
	skinBrightnessMin       = 0.2
	skinBrightnessMax       = 1.0
	skinThreshold           = 0.8
	skinWeight              = 1.8
	saturationBrightnessMin = 0.25
	saturationBrightnessMax = 0.9
	saturationThreshold     = 0.4
	saturationBias          = 0.2
	saturationWeight        = 0.3
	// step * minscale rounded down to the next power of two should be good
	scoreDownSample   = 8
	step              = 8
	scaleStep         = 0.1
	minScale          = 0.9
	maxScale          = 1.0
	edgeRadius        = 0.4
	edgeWeight        = -20.0
	outsideImportance = -0.5
	ruleOfThirds      = true
	prescale          = true
	debug             = false
)

type Score struct {
	Detail     float64
	Saturation float64
	Skin       float64
	Total      float64
}

type Crop struct {
	X      int
	Y      int
	Width  int
	Height int
	Score  Score
}

type SubImager interface {
	SubImage(r image.Rectangle) image.Image
}

func thirds(x float64) float64 {
	x1 := int(x - (1.0 / 3.0) + 1.0)
	res := (float64(x1%2.0) * 0.5) - 0.5
	return res * 16.0
}

func importance(crop *Crop, x, y int) float64 {
	if crop.X > x || x >= crop.X+crop.Width || crop.Y > y || y >= crop.Y+crop.Height {
		return outsideImportance
	}

	xf := float64(x-crop.X) / float64(crop.Width)
	yf := float64(y-crop.Y) / float64(crop.Height)

	px := math.Abs(0.5-xf) * 2.0
	py := math.Abs(0.5-yf) * 2.0

	dx := math.Max(px-1.0+edgeRadius, 0.0)
	dy := math.Max(py-1.0+edgeRadius, 0.0)
	d := (math.Pow(dx, 2) + math.Pow(dy, 2)) * edgeWeight

	s := 1.41 - math.Sqrt(math.Pow(px, 2)+math.Pow(py, 2))
	if ruleOfThirds {
		s += (math.Max(0.0, s+d+0.5) * 1.2) * (thirds(px) + thirds(py))
	}

	return s + d
}

func score(output *image.Image, crop *Crop) Score {
	o := (*output).(*image.RGBA)
	height := (*output).Bounds().Size().Y
	width := (*output).Bounds().Size().X
	score := Score{}

	for y := 0; y < height; y++ {
		yoffset := y * width
		for x := 0; x < width; x++ {
			//			now := time.Now()
			imp := importance(crop, x*scoreDownSample, y*scoreDownSample)
			//			fmt.Println("Time elapsed single-imp:", time.Since(now))

			p := yoffset + x * 4

			r8 := float64(o.Pix[p]) / 255.0
			g8 := float64(o.Pix[p+1]) / 255.0
			b8 := float64(o.Pix[p+2]) / 255.0

			score.Skin += r8 * (g8 + skinBias) * imp
			score.Detail += g8 * imp
			score.Saturation += b8 * (g8 + saturationBias) * imp
		}
	}

	score.Total = (score.Detail*detailWeight + score.Skin*skinWeight + score.Saturation*saturationWeight) / float64(crop.Width) / float64(crop.Height)
	return score
}

func writeImage(img *image.Image, name string) {
	fso, err := os.Create(name)
	if err != nil {
		panic(err)
	}
	defer fso.Close()

	jpeg.Encode(fso, (*img), &jpeg.Options{Quality: 90})
	fso.Close()
}

func analyse(img image.Image) Crop {
	o := image.Image(image.NewRGBA(img.Bounds()))

	now := time.Now()
	edgeDetect(&img, &o)
	fmt.Println("Time elapsed edge:", time.Since(now))
	writeImage(&o, "/tmp/foo_step1.jpg")

	now = time.Now()
	skinDetect(&img, &o)
	fmt.Println("Time elapsed skin:", time.Since(now))
	writeImage(&o, "/tmp/foo_step2.jpg")

	now = time.Now()
	saturationDetect(&img, &o)
	fmt.Println("Time elapsed sat:", time.Since(now))
	writeImage(&o, "/tmp/foo_step3.jpg")

	now = time.Now()
	var topCrop Crop
	topScore := -1.0
	cs := crops(&o)
	fmt.Println("Time elapsed crops:", time.Since(now), len(cs))

	now = time.Now()
	for _, crop := range cs {
		//		nowIn := time.Now()
		crop.Score = score(&o, &crop)
		//		fmt.Println("Time elapsed single-score:", time.Since(nowIn))
		if crop.Score.Total > topScore {
			topCrop = crop
			topScore = crop.Score.Total
		}
	}
	fmt.Printf("Top crop: %+v\n", topCrop)
	fmt.Println("Time elapsed score:", time.Since(now))

	cropImage := img.(SubImager).SubImage(image.Rect(topCrop.X, topCrop.Y, topCrop.Width+topCrop.X, topCrop.Height+topCrop.Y))
	writeImage(&cropImage, "/tmp/foo_topcrop.jpg")

	return topCrop
}

func crop(img image.Image, width, height int) error {
	if width == 0 && height == 0 {
		return errors.New("Expect either a height or width")
	}

	scale := math.Min(float64(img.Bounds().Size().X)/float64(width), float64(img.Bounds().Size().Y)/float64(height))
	cropWidth, cropHeight = math.Floor(float64(width)*scale), math.Floor(float64(height)*scale)
	minScale = math.Min(maxScale, math.Max(1.0/scale, minScale))

	fmt.Printf("original resolution: %dx%d\n", img.Bounds().Size().X, img.Bounds().Size().Y)
	fmt.Printf("scale: %f, cropw: %f, croph: %f, minscale: %f\n", scale, cropWidth, cropHeight, minScale)

	now := time.Now()
	analyse(img)
	fmt.Println("Time elapsed:", time.Since(now))

	return nil
}

func saturation(c color.Color) float64 {
	r, g, b, _ := c.RGBA()
	r8 := float64(r >> 8)
	g8 := float64(g >> 8)
	b8 := float64(b >> 8)

	maximum := math.Max(math.Max(r8/255.0, g8/255.0), b8/255.0)
	minimum := math.Min(math.Min(r8/255.0, g8/255.0), b8/255.0)

	if maximum == minimum {
		return 0
	}

	l := (maximum + minimum) / 2.0
	d := maximum - minimum

	if l > 0.5 {
		return d / (2.0 - maximum - minimum)
	} else {
		return d / (maximum + minimum)
	}
}

func cie(c color.Color) float64 {
	r, g, b, _ := c.RGBA()
	r8 := float64(r >> 8)
	g8 := float64(g >> 8)
	b8 := float64(b >> 8)

	return 0.5126*b8 + 0.7152*g8 + 0.0722*r8
}

func skinCol(c color.Color) float64 {
	r, g, b, _ := c.RGBA()
	r8 := float64(r >> 8)
	g8 := float64(g >> 8)
	b8 := float64(b >> 8)

	mag := math.Sqrt(math.Pow(r8, 2) + math.Pow(g8, 2) + math.Pow(b8, 2))
	rd := r8/mag - skinColor[0]
	gd := g8/mag - skinColor[1]
	bd := b8/mag - skinColor[2]

	d := math.Sqrt(math.Pow(rd, 2) + math.Pow(gd, 2) + math.Pow(bd, 2))
	return 1.0 - d
}

func edgeDetect(i *image.Image, o *image.Image) {
	w := (*i).Bounds().Size().X
	h := (*i).Bounds().Size().Y

	for y := 0; y < h; y++ {
		for x := 0; x < w; x++ {
			var lightness float64

			if x == 0 || x >= w-1 || y == 0 || y >= h-1 {
				lightness = cie((*i).At(x, y))
			} else {
				lightness = cie((*i).At(x, y))*4.0 -
					cie((*i).At(x, y-1)) -
					cie((*i).At(x-1, y)) -
					cie((*i).At(x+1, y)) -
					cie((*i).At(x, y+1))
			}

			if lightness < 0 {
				continue
			}

			nc := color.RGBA{uint8(lightness), uint8(lightness), uint8(lightness), 255}
			(*o).(*image.RGBA).Set(x, y, nc)
		}
	}
}

func skinDetect(i *image.Image, o *image.Image) {
	w := (*i).Bounds().Size().X
	h := (*i).Bounds().Size().Y

	for y := 0; y < h; y++ {
		for x := 0; x < w; x++ {
			lightness := cie((*i).At(x, y)) / 255.0
			skin := skinCol((*i).At(x, y))

			if skin > skinThreshold && lightness >= skinBrightnessMin && lightness <= skinBrightnessMax {
				r := (skin - skinThreshold) * (255.0 / (1.0 - skinThreshold))
				_, g, b, _ := (*o).At(x, y).RGBA()
				nc := color.RGBA{uint8(r), uint8(g >> 8), uint8(b >> 8), 255}
				(*o).(*image.RGBA).Set(x, y, nc)
			} else {
				_, g, b, _ := (*o).At(x, y).RGBA()
				nc := color.RGBA{0, uint8(g >> 8), uint8(b >> 8), 255}
				(*o).(*image.RGBA).Set(x, y, nc)
			}
		}
	}
}

func saturationDetect(i *image.Image, o *image.Image) {
	w := (*i).Bounds().Size().X
	h := (*i).Bounds().Size().Y

	for y := 0; y < h; y++ {
		for x := 0; x < w; x++ {
			lightness := cie((*i).At(x, y)) / 255.0
			saturation := saturation((*i).At(x, y))

			if saturation > saturationThreshold && lightness >= saturationBrightnessMin && lightness <= saturationBrightnessMax {
				b := (saturation - saturationThreshold) * (255.0 / (1.0 - saturationThreshold))
				r, g, _, _ := (*o).At(x, y).RGBA()
				nc := color.RGBA{uint8(r >> 8), uint8(g >> 8), uint8(b), 255}
				(*o).(*image.RGBA).Set(x, y, nc)
			} else {
				r, g, _, _ := (*o).At(x, y).RGBA()
				nc := color.RGBA{uint8(r >> 8), uint8(g >> 8), 0, 255}
				(*o).(*image.RGBA).Set(x, y, nc)
			}
		}
	}
}

func crops(i *image.Image) []Crop {
	res := []Crop{}
	width := (*i).Bounds().Size().X
	height := (*i).Bounds().Size().Y

	//minDimension := math.Min(float64(width), float64(height))
	cropW := cropWidth  //|| minDimension
	cropH := cropHeight //|| minDimension

	for scale := maxScale; scale >= minScale; scale -= scaleStep {
		for y := 0; float64(y)+cropH*scale <= float64(height); y += step {
			for x := 0; float64(x)+cropW*scale <= float64(width); x += step {
				res = append(res, Crop{
					X:      x,
					Y:      y,
					Width:  int(cropW * scale),
					Height: int(cropH * scale),
				})
			}
		}
	}

	return res
}

func main() {
	fi, _ := os.Open("/tmp/foo.png")
	defer fi.Close()

	img, _, err := image.Decode(fi)
	if err != nil {
		panic(err)
		return
	}

	crop(img, 250, 250)
}
<commit_msg>* Make a proper go package out of smartcrop.<commit_after>package smartcrop

import (
	"errors"
	"fmt"
	"image"
	"image/color"
	"image/jpeg"
	_ "image/png"
	"math"
	"os"
	"time"
)

var (
	aspect                  = 0
	cropWidth               = 0.0
	cropHeight              = 0.0
	detailWeight            = 0.2
	skinColor               = [3]float64{0.78, 0.57, 0.44}
	skinBias                = 0.01
	skinBrightnessMin       = 0.2
	skinBrightnessMax       = 1.0
	skinThreshold           = 0.8
	skinWeight              = 1.8
	saturationBrightnessMin = 0.25
	saturationBrightnessMax = 0.9
	saturationThreshold     = 0.4
	saturationBias          = 0.2
	saturationWeight        = 0.3
	// step * minscale rounded down to the next power of two should be good
	scoreDownSample   = 8
	step              = 8
	scaleStep         = 0.1
	minScale          = 0.9
	maxScale          = 1.0
	edgeRadius        = 0.4
	edgeWeight        = -20.0
	outsideImportance = -0.5
	ruleOfThirds      = true
	prescale          = true
	debug             = false
)

type Score struct {
	Detail     float64
	Saturation float64
	Skin       float64
	Total      float64
}

type Crop struct {
	X      int
	Y      int
	Width  int
	Height int
	Score  Score
}

func SmartCrop(img *image.Image, width, height int) (Crop, error) {
	if width == 0 && height == 0 {
		return Crop{}, errors.New("Expect either a height or width")
	}

	scale := math.Min(float64((*img).Bounds().Size().X)/float64(width), float64((*img).Bounds().Size().Y)/float64(height))
	cropWidth, cropHeight = math.Floor(float64(width)*scale), math.Floor(float64(height)*scale)
	minScale = math.Min(maxScale, math.Max(1.0/scale, minScale))

	fmt.Printf("original resolution: %dx%d\n", (*img).Bounds().Size().X, (*img).Bounds().Size().Y)
	fmt.Printf("scale: %f, cropw: %f, croph: %f, minscale: %f\n", scale, cropWidth, cropHeight, minScale)

	topCrop := analyse(img)
	return topCrop, nil
}

func thirds(x float64) float64 {
	x1 := int(x - (1.0 / 3.0) + 1.0)
	res := (float64(x1%2.0) * 0.5) - 0.5
	return res * 16.0
}

func importance(crop *Crop, x, y int) float64 {
	if crop.X > x || x >= crop.X+crop.Width || crop.Y > y || y >= crop.Y+crop.Height {
		return outsideImportance
	}

	xf := float64(x-crop.X) / float64(crop.Width)
	yf := float64(y-crop.Y) / float64(crop.Height)

	px := math.Abs(0.5-xf) * 2.0
	py := math.Abs(0.5-yf) * 2.0

	dx := math.Max(px-1.0+edgeRadius, 0.0)
	dy := math.Max(py-1.0+edgeRadius, 0.0)
	d := (math.Pow(dx, 2) + math.Pow(dy, 2)) * edgeWeight

	s := 1.41 - math.Sqrt(math.Pow(px, 2)+math.Pow(py, 2))
	if ruleOfThirds {
		s += (math.Max(0.0, s+d+0.5) * 1.2) * (thirds(px) + thirds(py))
	}

	return s + d
}

func score(output *image.Image, crop *Crop) Score {
	o := (*output).(*image.RGBA)
	height := (*output).Bounds().Size().Y
	width := (*output).Bounds().Size().X
	score := Score{}

	for y := 0; y < height; y++ {
		yoffset := y * width
		ydownSample := y * scoreDownSample
		for x := 0; x < width; x++ {
			//			now := time.Now()
			imp := importance(crop, x*scoreDownSample, ydownSample)
			//			fmt.Println("Time elapsed single-imp:", time.Since(now))

			p := yoffset + x * 4

			r8 := float64(o.Pix[p]) / 255.0
			g8 := float64(o.Pix[p+1]) / 255.0
			b8 := float64(o.Pix[p+2]) / 255.0

			score.Skin += r8 * (g8 + skinBias) * imp
			score.Detail += g8 * imp
			score.Saturation += b8 * (g8 + saturationBias) * imp
		}
	}

	score.Total = (score.Detail*detailWeight + score.Skin*skinWeight + score.Saturation*saturationWeight) / float64(crop.Width) / float64(crop.Height)
	return score
}

func writeImage(img *image.Image, name string) {
	fso, err := os.Create(name)
	if err != nil {
		panic(err)
	}
	defer fso.Close()

	jpeg.Encode(fso, (*img), &jpeg.Options{Quality: 90})
	fso.Close()
}

func analyse(img *image.Image) Crop {
	o := image.Image(image.NewRGBA((*img).Bounds()))

	now := time.Now()
	edgeDetect(img, &o)
	fmt.Println("Time elapsed edge:", time.Since(now))
//	writeImage(&o, "/tmp/foo_step1.jpg")

	now = time.Now()
	skinDetect(img, &o)
	fmt.Println("Time elapsed skin:", time.Since(now))
//	writeImage(&o, "/tmp/foo_step2.jpg")

	now = time.Now()
	saturationDetect(img, &o)
	fmt.Println("Time elapsed sat:", time.Since(now))
//	writeImage(&o, "/tmp/foo_step3.jpg")

	now = time.Now()
	var topCrop Crop
	topScore := -1.0
	cs := crops(&o)
	fmt.Println("Time elapsed crops:", time.Since(now), len(cs))

	now = time.Now()
	for _, crop := range cs {
		//		nowIn := time.Now()
		crop.Score = score(&o, &crop)
		//		fmt.Println("Time elapsed single-score:", time.Since(nowIn))
		if crop.Score.Total > topScore {
			topCrop = crop
			topScore = crop.Score.Total
		}
	}
	fmt.Println("Time elapsed score:", time.Since(now))

	return topCrop
}

func saturation(c color.Color) float64 {
	r, g, b, _ := c.RGBA()
	r8 := float64(r >> 8)
	g8 := float64(g >> 8)
	b8 := float64(b >> 8)

	maximum := math.Max(math.Max(r8/255.0, g8/255.0), b8/255.0)
	minimum := math.Min(math.Min(r8/255.0, g8/255.0), b8/255.0)

	if maximum == minimum {
		return 0
	}

	l := (maximum + minimum) / 2.0
	d := maximum - minimum

	if l > 0.5 {
		return d / (2.0 - maximum - minimum)
	} else {
		return d / (maximum + minimum)
	}
}

func cie(c color.Color) float64 {
	r, g, b, _ := c.RGBA()
	r8 := float64(r >> 8)
	g8 := float64(g >> 8)
	b8 := float64(b >> 8)

	return 0.5126*b8 + 0.7152*g8 + 0.0722*r8
}

func skinCol(c color.Color) float64 {
	r, g, b, _ := c.RGBA()
	r8 := float64(r >> 8)
	g8 := float64(g >> 8)
	b8 := float64(b >> 8)

	mag := math.Sqrt(math.Pow(r8, 2) + math.Pow(g8, 2) + math.Pow(b8, 2))
	rd := r8/mag - skinColor[0]
	gd := g8/mag - skinColor[1]
	bd := b8/mag - skinColor[2]

	d := math.Sqrt(math.Pow(rd, 2) + math.Pow(gd, 2) + math.Pow(bd, 2))
	return 1.0 - d
}

func edgeDetect(i *image.Image, o *image.Image) {
	w := (*i).Bounds().Size().X
	h := (*i).Bounds().Size().Y

	for y := 0; y < h; y++ {
		for x := 0; x < w; x++ {
			var lightness float64

			if x == 0 || x >= w-1 || y == 0 || y >= h-1 {
				lightness = cie((*i).At(x, y))
			} else {
				lightness = cie((*i).At(x, y))*4.0 -
					cie((*i).At(x, y-1)) -
					cie((*i).At(x-1, y)) -
					cie((*i).At(x+1, y)) -
					cie((*i).At(x, y+1))
			}

			if lightness < 0 {
				continue
			}

			nc := color.RGBA{uint8(lightness), uint8(lightness), uint8(lightness), 255}
			(*o).(*image.RGBA).Set(x, y, nc)
		}
	}
}

func skinDetect(i *image.Image, o *image.Image) {
	w := (*i).Bounds().Size().X
	h := (*i).Bounds().Size().Y

	for y := 0; y < h; y++ {
		for x := 0; x < w; x++ {
			lightness := cie((*i).At(x, y)) / 255.0
			skin := skinCol((*i).At(x, y))

			if skin > skinThreshold && lightness >= skinBrightnessMin && lightness <= skinBrightnessMax {
				r := (skin - skinThreshold) * (255.0 / (1.0 - skinThreshold))
				_, g, b, _ := (*o).At(x, y).RGBA()
				nc := color.RGBA{uint8(r), uint8(g >> 8), uint8(b >> 8), 255}
				(*o).(*image.RGBA).Set(x, y, nc)
			} else {
				_, g, b, _ := (*o).At(x, y).RGBA()
				nc := color.RGBA{0, uint8(g >> 8), uint8(b >> 8), 255}
				(*o).(*image.RGBA).Set(x, y, nc)
			}
		}
	}
}

func saturationDetect(i *image.Image, o *image.Image) {
	w := (*i).Bounds().Size().X
	h := (*i).Bounds().Size().Y

	for y := 0; y < h; y++ {
		for x := 0; x < w; x++ {
			lightness := cie((*i).At(x, y)) / 255.0
			saturation := saturation((*i).At(x, y))

			if saturation > saturationThreshold && lightness >= saturationBrightnessMin && lightness <= saturationBrightnessMax {
				b := (saturation - saturationThreshold) * (255.0 / (1.0 - saturationThreshold))
				r, g, _, _ := (*o).At(x, y).RGBA()
				nc := color.RGBA{uint8(r >> 8), uint8(g >> 8), uint8(b), 255}
				(*o).(*image.RGBA).Set(x, y, nc)
			} else {
				r, g, _, _ := (*o).At(x, y).RGBA()
				nc := color.RGBA{uint8(r >> 8), uint8(g >> 8), 0, 255}
				(*o).(*image.RGBA).Set(x, y, nc)
			}
		}
	}
}

func crops(i *image.Image) []Crop {
	res := []Crop{}
	width := (*i).Bounds().Size().X
	height := (*i).Bounds().Size().Y

	//minDimension := math.Min(float64(width), float64(height))
	cropW := cropWidth  //|| minDimension
	cropH := cropHeight //|| minDimension

	for scale := maxScale; scale >= minScale; scale -= scaleStep {
		for y := 0; float64(y)+cropH*scale <= float64(height); y += step {
			for x := 0; float64(x)+cropW*scale <= float64(width); x += step {
				res = append(res, Crop{
					X:      x,
					Y:      y,
					Width:  int(cropW * scale),
					Height: int(cropH * scale),
				})
			}
		}
	}

	return res
}
<|endoftext|>


<commit_before>package main

import(
	"errors"
	"image"
	"image/color"
	"image/jpeg"
	_ "image/png"
	"fmt"
	"math"
	"os"
)

var(
    aspect = 0
    cropWidth = 0.0
    cropHeight = 0.0
    detailWeight = 0.2
    skinColor = [3]float64{0.78, 0.57, 0.44}
    skinBias = 0.01
    skinBrightnessMin = 0.2
    skinBrightnessMax = 1.0
    skinThreshold = 0.8
    skinWeight = 1.8
    saturationBrightnessMin = 0.25
    saturationBrightnessMax = 0.9
    saturationThreshold = 0.4
    saturationBias = 0.2
    saturationWeight = 0.3
    // step * minscale rounded down to the next power of two should be good
    scoreDownSample = 8
    step = 8
    scaleStep = 0.1
    minScale = 0.9
    maxScale = 1.0
    edgeRadius = 0.4
    edgeWeight = -20.0
    outsideImportance = -0.5
    ruleOfThirds = true
    prescale = true
    debug = false
)

type Score struct {
	Detail float64
	Saturation float64
	Skin float64
	Total float64
}

type Crop struct {
	X int
	Y int
	Width int
	Height int
	Score Score
}

type SubImager interface {
	SubImage(r image.Rectangle) image.Image
}

func thirds(x float64) float64 {
	x1 := int(x-(1.0/3.0) + 1.0)
	res := (float64(x1 % 2.0) * 0.5) - 0.5
	return res * 16.0
}

func importance(crop Crop, x, y int) float64 {
	if crop.X > x || x >= crop.X + crop.Width || crop.Y > y || y >= crop.Y + crop.Height {
		return outsideImportance
	}

	xf := float64(x - crop.X) / float64(crop.Width)
	yf := float64(y - crop.Y) / float64(crop.Height)

	px := math.Abs(0.5 - xf) * 2.0
	py := math.Abs(0.5 - yf) * 2.0

	dx := math.Max(px - 1.0 + edgeRadius, 0.0)
	dy := math.Max(py - 1.0 + edgeRadius, 0.0)
	d := (dx*dx + dy*dy) * edgeWeight

	s := 1.41 - math.Sqrt(px*px + py*py)
	if ruleOfThirds {
		s += (math.Max(0.0, s+d+0.5) * 1.2) * (thirds(px) + thirds(py))
	}

	return s + d
}

func score(output *image.Image, crop Crop) Score {
	invDownSample := 1.0 / float64(scoreDownSample)
	height := (*output).Bounds().Size().Y
	width := (*output).Bounds().Size().X
	score := Score{}

	for y := 0; y < height * scoreDownSample; y += scoreDownSample {
		for x := 0; x < width * scoreDownSample; x += scoreDownSample {
			p := int(math.Floor(float64(y) * invDownSample)) * width + int(math.Floor(float64(x) * invDownSample))
			imp := importance(crop, x, y)

			ny := int(math.Floor(float64(p) / float64(width)))
			nx := 0
			if ny > 0 {
				nx = p % width
			} else {
				nx = p
			}

			r, g, b, _ := (*output).At(nx, ny).RGBA()
			r8 := float64(r>>8)
			g8 := float64(g>>8)
			b8 := float64(b>>8)

			score.Skin += (r8/255.0) * (g8/255.0 + skinBias) * imp
			score.Detail += (g8/255.0) * imp
			score.Saturation += (b8/255.0) * (g8/255.0 + saturationBias) * imp
		}
	}

	score.Total = (score.Detail * detailWeight + score.Skin * skinWeight + score.Saturation * saturationWeight) / float64(crop.Width) / float64(crop.Height)
	return score
}

func writeImage(img *image.Image, name string) {
	fso, err := os.Create(name)
	if err != nil {
		panic(err)
	}
	defer fso.Close()

	jpeg.Encode(fso, (*img), &jpeg.Options{Quality: 90})
	fso.Close()
}

func analyse(img image.Image) Crop {
	o := image.Image(image.NewRGBA(img.Bounds()))

	edgeDetect(&img, &o)
	writeImage(&o, "/tmp/foo_step1.jpg")
	skinDetect(&img, &o)
	writeImage(&o, "/tmp/foo_step2.jpg")
	saturationDetect(&img, &o)
	writeImage(&o, "/tmp/foo_step3.jpg")

	var topCrop Crop
	topScore := -1.0
	cs := crops(&o)

	for _, crop := range cs {
		crop.Score = score(&o, crop)
		if crop.Score.Total > topScore {
			topCrop = crop
			topScore = crop.Score.Total
		}
	}

	fmt.Printf("Top crop: %+v\n", topCrop)

	cropImage := img.(SubImager).SubImage(image.Rect(topCrop.X, topCrop.Y, topCrop.Width+topCrop.X, topCrop.Height+topCrop.Y))
	writeImage(&cropImage, "/tmp/foo_topcrop.jpg")

	return topCrop
}

func crop(img image.Image, width, height int) error {
	if width == 0 && height == 0 {
		return errors.New("Expect either a height or width")
	}

	scale := math.Min(float64(img.Bounds().Size().X) / float64(width), float64(img.Bounds().Size().Y) / float64(height))
	cropWidth, cropHeight = math.Floor(float64(width) * scale), math.Floor(float64(height) * scale)
	minScale = math.Min(maxScale, math.Max(1.0 / scale, minScale))

	fmt.Printf("original resolution: %dx%d\n", img.Bounds().Size().X, img.Bounds().Size().Y)
	fmt.Printf("scale: %f, cropw: %f, croph: %f, minscale: %f\n", scale, cropWidth, cropHeight, minScale)

	analyse(img)

	return nil
}

func saturation(c color.Color) float64 {
	r, g, b, _ := c.RGBA()

	maximum := math.Max(math.Max(float64(r)/255, float64(g)/255), float64(b)/255)
	minimum := math.Min(math.Min(float64(r)/255, float64(g)/255), float64(b)/255)

	if (maximum == minimum) {
		return 0
	}

	l := (maximum + minimum) / 2
	d := maximum - minimum

	if l > 0.5 {
		return d / (2-maximum-minimum)
	} else {
		return d / (maximum+minimum)
	}
}

func cie(c color.Color) float64 {
	r, g, b, _ := c.RGBA()
	r8 := float64(r>>8)
	g8 := float64(g>>8)
	b8 := float64(b>>8)

	return 0.5126*b8 + 0.7152*g8 + 0.0722*r8
}

func skinCol(c color.Color) float64 {
	r, g, b, _ := c.RGBA()
	r8 := float64(r>>8)
	g8 := float64(g>>8)
	b8 := float64(b>>8)

	mag := math.Sqrt(r8*r8 + g8*g8 + b8*b8)
	rd := r8/mag - skinColor[0]
	gd := g8/mag - skinColor[1]
	bd := b8/mag - skinColor[2]

	d := math.Sqrt(rd*rd + gd*gd + bd*bd)
	return 1.0 - d
}

func edgeDetect(i *image.Image, o *image.Image) {
	w := (*i).Bounds().Size().X
	h := (*i).Bounds().Size().Y

	for y := 0; y < h; y++ {
		for x := 0; x < w; x++ {
			var lightness float64

			if x == 0 || x >= w-1 || y == 0 || y >= h-1 {
				lightness = cie((*i).At(x, y))
			} else {
				lightness = cie((*i).At(x, y)) * 4.0 -
							cie((*i).At(x, y-1)) -
							cie((*i).At(x-1, y)) -
							cie((*i).At(x+1, y)) -
							cie((*i).At(x, y+1))
			}

			if lightness < 0 {
				continue
			}

			nc := color.RGBA{uint8(lightness), uint8(lightness), uint8(lightness), 255}
			(*o).(*image.RGBA).Set(x, y, nc)
		}
	}
}

func skinDetect(i *image.Image, o *image.Image) {
	w := (*i).Bounds().Size().X
	h := (*i).Bounds().Size().Y

	for y := 0; y < h; y++ {
		for x := 0; x < w; x++ {
			lightness := cie((*i).At(x, y)) / 255.0
			skin := skinCol((*i).At(x, y))

			if skin > skinThreshold && lightness >= skinBrightnessMin && lightness <= skinBrightnessMax {
				r := (skin - skinThreshold) * (255.0/(1.0 - skinThreshold))
				_, g, b, _ := (*o).At(x, y).RGBA()
				nc := color.RGBA{uint8(r), uint8(g>>8), uint8(b>>8), 255}
				(*o).(*image.RGBA).Set(x, y, nc)
			} else {
				_, g, b, _ := (*o).At(x, y).RGBA()
				nc := color.RGBA{0, uint8(g>>8), uint8(b>>8), 255}
				(*o).(*image.RGBA).Set(x, y, nc)
			}
		}
	}
}

func saturationDetect(i *image.Image, o *image.Image) {
	w := (*i).Bounds().Size().X
	h := (*i).Bounds().Size().Y

	for y := 0; y < h; y++ {
		for x := 0; x < w; x++ {
			lightness := cie((*i).At(x, y)) / 255.0
			saturation := saturation((*i).At(x, y))

			if saturation > saturationThreshold && lightness >= saturationBrightnessMin && lightness <= saturationBrightnessMax {
				b := (saturation - saturationThreshold) * (255.0/(1.0 - saturationThreshold))
				r, g, _, _ := (*o).At(x, y).RGBA()
				nc := color.RGBA{uint8(r>>8), uint8(g>>8), uint8(b), 255}
				(*o).(*image.RGBA).Set(x, y, nc)
			} else {
				r, g, _, _ := (*o).At(x, y).RGBA()
				nc := color.RGBA{uint8(r>>8), uint8(g>>8), 0, 255}
				(*o).(*image.RGBA).Set(x, y, nc)
			}
		}
	}
}

func crops(i *image.Image) []Crop {
	res := []Crop{}
	width := (*i).Bounds().Size().X
	height := (*i).Bounds().Size().Y

	//minDimension := math.Min(float64(width), float64(height))
	cropW := cropWidth //|| minDimension
	cropH := cropHeight //|| minDimension

	for scale := maxScale; scale >= minScale; scale -= scaleStep {
		for y := 0; float64(y)+cropH*scale <= float64(height); y += step {
			for x := 0; float64(x)+cropW*scale <= float64(width); x += step {
				res = append(res, Crop{
					X: x,
					Y: y,
					Width: int(cropW*scale),
					Height: int(cropH*scale),
				})
			}
		}
	}

	return res
}

func main() {
	fi, _ := os.Open("/tmp/foo.png")
	defer fi.Close()

	img, _, err := image.Decode(fi)
	if err != nil {
		panic(err)
		return
	}

	crop(img, 250, 250)
}
<commit_msg>* Fixed saturation more and go fmt'd.<commit_after>package main

import (
	"errors"
	"fmt"
	"image"
	"image/color"
	"image/jpeg"
	_ "image/png"
	"math"
	"os"
	"time"
)

var (
	aspect                  = 0
	cropWidth               = 0.0
	cropHeight              = 0.0
	detailWeight            = 0.2
	skinColor               = [3]float64{0.78, 0.57, 0.44}
	skinBias                = 0.01
	skinBrightnessMin       = 0.2
	skinBrightnessMax       = 1.0
	skinThreshold           = 0.8
	skinWeight              = 1.8
	saturationBrightnessMin = 0.25
	saturationBrightnessMax = 0.9
	saturationThreshold     = 0.4
	saturationBias          = 0.2
	saturationWeight        = 0.3
	// step * minscale rounded down to the next power of two should be good
	scoreDownSample   = 8
	invDownSample     = 1.0 / float64(scoreDownSample)
	step              = 8
	scaleStep         = 0.1
	minScale          = 0.9
	maxScale          = 1.0
	edgeRadius        = 0.4
	edgeWeight        = -20.0
	outsideImportance = -0.5
	ruleOfThirds      = true
	prescale          = true
	debug             = false
)

type Score struct {
	Detail     float64
	Saturation float64
	Skin       float64
	Total      float64
}

type Crop struct {
	X      int
	Y      int
	Width  int
	Height int
	Score  Score
}

type SubImager interface {
	SubImage(r image.Rectangle) image.Image
}

func thirds(x float64) float64 {
	x1 := int(x - (1.0 / 3.0) + 1.0)
	res := (float64(x1%2.0) * 0.5) - 0.5
	return res * 16.0
}

func importance(crop *Crop, x, y int) float64 {
	if crop.X > x || x >= crop.X+crop.Width || crop.Y > y || y >= crop.Y+crop.Height {
		return outsideImportance
	}

	xf := float64(x-crop.X) / float64(crop.Width)
	yf := float64(y-crop.Y) / float64(crop.Height)

	px := math.Abs(0.5-xf) * 2.0
	py := math.Abs(0.5-yf) * 2.0

	dx := math.Max(px-1.0+edgeRadius, 0.0)
	dy := math.Max(py-1.0+edgeRadius, 0.0)
	d := (math.Pow(dx, 2) + math.Pow(dy, 2)) * edgeWeight

	s := 1.41 - math.Sqrt(math.Pow(px, 2)+math.Pow(py, 2))
	if ruleOfThirds {
		s += (math.Max(0.0, s+d+0.5) * 1.2) * (thirds(px) + thirds(py))
	}

	return s + d
}

func score(output *image.Image, crop *Crop) Score {
	height := (*output).Bounds().Size().Y
	width := (*output).Bounds().Size().X
	score := Score{}

	for y := 0; y < height*scoreDownSample; y += scoreDownSample {
		for x := 0; x < width*scoreDownSample; x += scoreDownSample {
			//			now := time.Now()
			imp := importance(crop, x, y)
			//			fmt.Println("Time elapsed single-imp:", time.Since(now))

			ny := int(float64(y) * invDownSample)
			nx := int(float64(x) * invDownSample)

			r, g, b, _ := (*output).At(nx, ny).RGBA()
			r8 := float64(r >> 8)
			g8 := float64(g >> 8)
			b8 := float64(b >> 8)

			score.Skin += (r8 / 255.0) * (g8/255.0 + skinBias) * imp
			score.Detail += (g8 / 255.0) * imp
			score.Saturation += (b8 / 255.0) * (g8/255.0 + saturationBias) * imp
		}
	}

	score.Total = (score.Detail*detailWeight + score.Skin*skinWeight + score.Saturation*saturationWeight) / float64(crop.Width) / float64(crop.Height)
	return score
}

func writeImage(img *image.Image, name string) {
	fso, err := os.Create(name)
	if err != nil {
		panic(err)
	}
	defer fso.Close()

	jpeg.Encode(fso, (*img), &jpeg.Options{Quality: 90})
	fso.Close()
}

func analyse(img image.Image) Crop {
	o := image.Image(image.NewRGBA(img.Bounds()))

	now := time.Now()
	edgeDetect(&img, &o)
	fmt.Println("Time elapsed edge:", time.Since(now))
	writeImage(&o, "/tmp/foo_step1.jpg")

	now = time.Now()
	skinDetect(&img, &o)
	fmt.Println("Time elapsed skin:", time.Since(now))
	writeImage(&o, "/tmp/foo_step2.jpg")

	now = time.Now()
	saturationDetect(&img, &o)
	fmt.Println("Time elapsed sat:", time.Since(now))
	writeImage(&o, "/tmp/foo_step3.jpg")

	now = time.Now()
	var topCrop Crop
	topScore := -1.0
	cs := crops(&o)
	fmt.Println("Time elapsed crops:", time.Since(now), len(cs))

	now = time.Now()
	for _, crop := range cs {
		//		nowIn := time.Now()
		crop.Score = score(&o, &crop)
		//		fmt.Println("Time elapsed single-score:", time.Since(nowIn))
		if crop.Score.Total > topScore {
			topCrop = crop
			topScore = crop.Score.Total
		}
	}
	fmt.Printf("Top crop: %+v\n", topCrop)
	fmt.Println("Time elapsed score:", time.Since(now))

	cropImage := img.(SubImager).SubImage(image.Rect(topCrop.X, topCrop.Y, topCrop.Width+topCrop.X, topCrop.Height+topCrop.Y))
	writeImage(&cropImage, "/tmp/foo_topcrop.jpg")

	return topCrop
}

func crop(img image.Image, width, height int) error {
	if width == 0 && height == 0 {
		return errors.New("Expect either a height or width")
	}

	scale := math.Min(float64(img.Bounds().Size().X)/float64(width), float64(img.Bounds().Size().Y)/float64(height))
	cropWidth, cropHeight = math.Floor(float64(width)*scale), math.Floor(float64(height)*scale)
	minScale = math.Min(maxScale, math.Max(1.0/scale, minScale))

	fmt.Printf("original resolution: %dx%d\n", img.Bounds().Size().X, img.Bounds().Size().Y)
	fmt.Printf("scale: %f, cropw: %f, croph: %f, minscale: %f\n", scale, cropWidth, cropHeight, minScale)

	now := time.Now()
	analyse(img)
	fmt.Println("Time elapsed:", time.Since(now))

	return nil
}

func saturation(c color.Color) float64 {
	r, g, b, _ := c.RGBA()
	r8 := float64(r >> 8)
	g8 := float64(g >> 8)
	b8 := float64(b >> 8)

	maximum := math.Max(math.Max(r8/255.0, g8/255.0), b8/255.0)
	minimum := math.Min(math.Min(r8/255.0, g8/255.0), b8/255.0)

	if maximum == minimum {
		return 0
	}

	l := (maximum + minimum) / 2.0
	d := maximum - minimum

	if l > 0.5 {
		return d / (2.0 - maximum - minimum)
	} else {
		return d / (maximum + minimum)
	}
}

func cie(c color.Color) float64 {
	r, g, b, _ := c.RGBA()
	r8 := float64(r >> 8)
	g8 := float64(g >> 8)
	b8 := float64(b >> 8)

	return 0.5126*b8 + 0.7152*g8 + 0.0722*r8
}

func skinCol(c color.Color) float64 {
	r, g, b, _ := c.RGBA()
	r8 := float64(r >> 8)
	g8 := float64(g >> 8)
	b8 := float64(b >> 8)

	mag := math.Sqrt(math.Pow(r8, 2) + math.Pow(g8, 2) + math.Pow(b8, 2))
	rd := r8/mag - skinColor[0]
	gd := g8/mag - skinColor[1]
	bd := b8/mag - skinColor[2]

	d := math.Sqrt(math.Pow(rd, 2) + math.Pow(gd, 2) + math.Pow(bd, 2))
	return 1.0 - d
}

func edgeDetect(i *image.Image, o *image.Image) {
	w := (*i).Bounds().Size().X
	h := (*i).Bounds().Size().Y

	for y := 0; y < h; y++ {
		for x := 0; x < w; x++ {
			var lightness float64

			if x == 0 || x >= w-1 || y == 0 || y >= h-1 {
				lightness = cie((*i).At(x, y))
			} else {
				lightness = cie((*i).At(x, y))*4.0 -
					cie((*i).At(x, y-1)) -
					cie((*i).At(x-1, y)) -
					cie((*i).At(x+1, y)) -
					cie((*i).At(x, y+1))
			}

			if lightness < 0 {
				continue
			}

			nc := color.RGBA{uint8(lightness), uint8(lightness), uint8(lightness), 255}
			(*o).(*image.RGBA).Set(x, y, nc)
		}
	}
}

func skinDetect(i *image.Image, o *image.Image) {
	w := (*i).Bounds().Size().X
	h := (*i).Bounds().Size().Y

	for y := 0; y < h; y++ {
		for x := 0; x < w; x++ {
			lightness := cie((*i).At(x, y)) / 255.0
			skin := skinCol((*i).At(x, y))

			if skin > skinThreshold && lightness >= skinBrightnessMin && lightness <= skinBrightnessMax {
				r := (skin - skinThreshold) * (255.0 / (1.0 - skinThreshold))
				_, g, b, _ := (*o).At(x, y).RGBA()
				nc := color.RGBA{uint8(r), uint8(g >> 8), uint8(b >> 8), 255}
				(*o).(*image.RGBA).Set(x, y, nc)
			} else {
				_, g, b, _ := (*o).At(x, y).RGBA()
				nc := color.RGBA{0, uint8(g >> 8), uint8(b >> 8), 255}
				(*o).(*image.RGBA).Set(x, y, nc)
			}
		}
	}
}

func saturationDetect(i *image.Image, o *image.Image) {
	w := (*i).Bounds().Size().X
	h := (*i).Bounds().Size().Y

	for y := 0; y < h; y++ {
		for x := 0; x < w; x++ {
			lightness := cie((*i).At(x, y)) / 255.0
			saturation := saturation((*i).At(x, y))

			if saturation > saturationThreshold && lightness >= saturationBrightnessMin && lightness <= saturationBrightnessMax {
				b := (saturation - saturationThreshold) * (255.0 / (1.0 - saturationThreshold))
				r, g, _, _ := (*o).At(x, y).RGBA()
				nc := color.RGBA{uint8(r >> 8), uint8(g >> 8), uint8(b), 255}
				(*o).(*image.RGBA).Set(x, y, nc)
			} else {
				r, g, _, _ := (*o).At(x, y).RGBA()
				nc := color.RGBA{uint8(r >> 8), uint8(g >> 8), 0, 255}
				(*o).(*image.RGBA).Set(x, y, nc)
			}
		}
	}
}

func crops(i *image.Image) []Crop {
	res := []Crop{}
	width := (*i).Bounds().Size().X
	height := (*i).Bounds().Size().Y

	//minDimension := math.Min(float64(width), float64(height))
	cropW := cropWidth  //|| minDimension
	cropH := cropHeight //|| minDimension

	for scale := maxScale; scale >= minScale; scale -= scaleStep {
		for y := 0; float64(y)+cropH*scale <= float64(height); y += step {
			for x := 0; float64(x)+cropW*scale <= float64(width); x += step {
				res = append(res, Crop{
					X:      x,
					Y:      y,
					Width:  int(cropW * scale),
					Height: int(cropH * scale),
				})
			}
		}
	}

	return res
}

func main() {
	fi, _ := os.Open("/tmp/foo.png")
	defer fi.Close()

	img, _, err := image.Decode(fi)
	if err != nil {
		panic(err)
		return
	}

	crop(img, 250, 250)
}
<|endoftext|>


<commit_before>// Package csrf (goji/csrf) provides Cross Site Request Forgery
// protection middleware for the Goji microframework (https://goji.io).
package csrf

import (
	"errors"
	"fmt"
	"net/http"
	"net/url"

	"golang.org/x/net/context"

	"goji.io"

	"github.com/gorilla/securecookie"
)

// CSRF token length in bytes.
const tokenLength = 32

// Context/session keys & prefixes
const (
	tokenKey    string = "goji.csrf.Token"
	formKey     string = "goji.csrf.Form"
	errorKey    string = "goji.csrf.Error"
	cookieName  string = "_goji_csrf"
	errorPrefix string = "goji/csrf: "
)

var (
	// The name value used in form fields.
	fieldName = tokenKey
	// The default HTTP request header to inspect
	headerName = "X-CSRF-Token"
	// Idempotent (safe) methods as defined by RFC7231 section 4.2.2.
	safeMethods = []string{"GET", "HEAD", "OPTIONS", "TRACE"}
)

// TemplateTag provides a default template tag - e.g. {{ .csrfField }} - for use
// with the TemplateField function.
var TemplateTag = "csrfField"

var (
	// ErrNoReferer is returned when a HTTPS request provides an empty Referer
	// header.
	ErrNoReferer = errors.New("referer not supplied")
	// ErrBadReferer is returned when the scheme & host in the URL do not match
	// the supplied Referer header.
	ErrBadReferer = errors.New("referer invalid")
	// ErrNoToken is returned if no CSRF token is supplied in the request.
	ErrNoToken = errors.New("CSRF token not found in request")
	// ErrBadToken is returned if the CSRF token in the request does not match
	// the token in the session, or is otherwise malformed.
	ErrBadToken = errors.New("CSRF token invalid")
)

type csrf struct {
	h    goji.Handler
	sc   *securecookie.SecureCookie
	st   store
	opts options
}

// options contains the optional settings for the CSRF middleware.
type options struct {
	MaxAge int
	Domain string
	Path   string
	// Note that the function and field names match the case of the associated
	// http.Cookie field instead of the "correct" HTTPOnly name that golint suggests.
	HttpOnly      bool
	Secure        bool
	RequestHeader string
	FieldName     string
	ErrorHandler  goji.Handler
	CookieName    string
}

// Protect is HTTP middleware that provides Cross-Site Request Forgery
// protection.
//
// It securely generates a masked (unique-per-request) token that
// can be embedded in the HTTP response (e.g. form field or HTTP header).
// The original (unmasked) token is stored in the session, which is inaccessible
// by an attacker (provided you are using HTTPS). Subsequent requests are
// expected to include this token, which is compared against the session token.
// Requests that do not provide a matching token are served with a HTTP 403
// 'Forbidden' error response.
//
// Example:
//	package main
//
//	import (
//	    "html/template"
//	    "net/http"
//
//	    "goji.io"
//	    "github.com/goji/ctx-csrf"
//	    "github.com/zenazn/goji/graceful"
//	)
//
//	func main() {
//	    m := goji.NewMux()
//	    // Add the middleware to your router.
//	    m.UseC(csrf.Protect([]byte("32-byte-long-auth-key")))
//	    m.HandleFuncC(pat.Get("/signup"), ShowSignupForm)
//	    // POST requests without a valid token will return a HTTP 403 Forbidden.
//	    m.HandleFuncC(pat.Post("/signup/post"), SubmitSignupForm)
//
//	    graceful.ListenAndServe(":8000", m)
//	}
//
//	func ShowSignupForm(ctx context.Context, w http.ResponseWriter, r *http.Request) {
//	    // signup_form.tmpl just needs a {{ .csrfField }} template tag for
//	    // csrf.TemplateField to inject the CSRF token into. Easy!
//	    t.ExecuteTemplate(w, "signup_form.tmpl", map[string]interface{
//	        csrf.TemplateTag: csrf.TemplateField(ctx, r),
//	    })
//	    // We could also retrieve the token directly from csrf.Token(c, r) and
//	    // set it in the request header - w.Header.Set("X-CSRF-Token", token)
//	    // This is useful if your sending JSON to clients or a front-end JavaScript
//	    // framework.
//	}
//
//	func SubmitSignupForm(ctx context.Context, w http.ResponseWriter, r *http.Request) {
//	    // We can trust that requests making it this far have satisfied
//	    // our CSRF protection requirements.
//	}
//
func Protect(authKey []byte, opts ...Option) func(goji.Handler) goji.Handler {
	return func(h goji.Handler) goji.Handler {
		cs := parseOptions(h, opts...)

		// Set the defaults if no options have been specified
		if cs.opts.ErrorHandler == nil {
			cs.opts.ErrorHandler = goji.HandlerFunc(unauthorizedHandler)
		}

		if cs.opts.MaxAge < 1 {
			// Default of 12 hours
			cs.opts.MaxAge = 3600 * 12
		}

		if cs.opts.FieldName == "" {
			cs.opts.FieldName = fieldName
		}

		if cs.opts.CookieName == "" {
			cs.opts.CookieName = cookieName
		}

		if cs.opts.RequestHeader == "" {
			cs.opts.RequestHeader = headerName
		}

		// Create an authenticated securecookie instance.
		if cs.sc == nil {
			cs.sc = securecookie.New(authKey, nil)
			// Use JSON serialization (faster than one-off gob encoding)
			cs.sc.SetSerializer(securecookie.JSONEncoder{})
			// Set the MaxAge of the underlying securecookie.
			cs.sc.MaxAge(cs.opts.MaxAge)
		}

		if cs.st == nil {
			// Default to the cookieStore
			cs.st = &cookieStore{
				name:     cs.opts.CookieName,
				maxAge:   cs.opts.MaxAge,
				secure:   cs.opts.Secure,
				httpOnly: cs.opts.HttpOnly,
				path:     cs.opts.Path,
				domain:   cs.opts.Domain,
				sc:       cs.sc,
			}
		}

		return *cs
	}
}

// Implements goji.Handler for the csrf type.
func (cs csrf) ServeHTTPC(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	// Retrieve the token from the session.
	// An error represents either a cookie that failed HMAC validation
	// or that doesn't exist.
	realToken, err := cs.st.Get(r)
	if err != nil || len(realToken) != tokenLength {
		// If there was an error retrieving the token, the token doesn't exist
		// yet, or it's the wrong length, generate a new token.
		// Note that the new token will (correctly) fail validation downstream
		// as it will no longer match the request token.
		realToken, err = generateRandomBytes(tokenLength)
		if err != nil {
			ctx = setEnvError(ctx, err)
			cs.opts.ErrorHandler.ServeHTTPC(ctx, w, r)
			return
		}

		// Save the new (real) token in the session store.
		err = cs.st.Save(realToken, w)
		if err != nil {
			ctx = setEnvError(ctx, err)
			cs.opts.ErrorHandler.ServeHTTPC(ctx, w, r)
			return
		}
	}

	// Save the masked token to the request context
	ctx = context.WithValue(ctx, tokenKey, mask(realToken, r))
	// Save the field name to the request context
	ctx = context.WithValue(ctx, formKey, cs.opts.FieldName)

	// HTTP methods not defined as idempotent ("safe") under RFC7231 require
	// inspection.
	if !contains(safeMethods, r.Method) {
		// Enforce an origin check for HTTPS connections. As per the Django CSRF
		// implementation (https://goo.gl/vKA7GE) the Referer header is almost
		// always present for same-domain HTTP requests.
		if r.URL.Scheme == "https" {
			// Fetch the Referer value. Call the error handler if it's empty or
			// otherwise fails to parse.
			referer, err := url.Parse(r.Referer())
			if err != nil || referer.String() == "" {
				ctx = setEnvError(ctx, ErrNoReferer)
				cs.opts.ErrorHandler.ServeHTTPC(ctx, w, r)
				return
			}

			if sameOrigin(r.URL, referer) == false {
				ctx = setEnvError(ctx, ErrBadReferer)
				cs.opts.ErrorHandler.ServeHTTPC(ctx, w, r)
				return
			}
		}

		// If the token returned from the session store is nil for non-idempotent
		// ("unsafe") methods, call the error handler.
		if realToken == nil {
			ctx = setEnvError(ctx, ErrNoToken)
			cs.opts.ErrorHandler.ServeHTTPC(ctx, w, r)
			return
		}

		// If the token returned from the session store is nil for non-idempotent
		// ("unsafe") methods, call the error handler.
		if realToken == nil {
			ctx = setEnvError(ctx, ErrNoToken)
			cs.opts.ErrorHandler.ServeHTTPC(ctx, w, r)
			return
		}

		// Retrieve the combined token (pad + masked) token and unmask it.
		requestToken := unmask(cs.requestToken(r))

		// Compare the request token against the real token
		if !compareTokens(requestToken, realToken) {
			ctx = setEnvError(ctx, ErrBadToken)
			cs.opts.ErrorHandler.ServeHTTPC(ctx, w, r)
			return
		}

	}

	// Set the Vary: Cookie header to protect clients from caching the response.
	w.Header().Add("Vary", "Cookie")

	// Call the wrapped handler/router on success
	cs.h.ServeHTTPC(ctx, w, r)
}

// unauthorizedhandler sets a HTTP 403 Forbidden status and writes the
// CSRF failure reason to the response.
func unauthorizedHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	http.Error(w, fmt.Sprintf("%s - %s",
		http.StatusText(http.StatusForbidden), FailureReason(ctx, r)),
		http.StatusForbidden)
	return
}
<commit_msg>Remove some duplicated code<commit_after>// Package csrf (goji/csrf) provides Cross Site Request Forgery
// protection middleware for the Goji microframework (https://goji.io).
package csrf

import (
	"errors"
	"fmt"
	"net/http"
	"net/url"

	"golang.org/x/net/context"

	"goji.io"

	"github.com/gorilla/securecookie"
)

// CSRF token length in bytes.
const tokenLength = 32

// Context/session keys & prefixes
const (
	tokenKey    string = "goji.csrf.Token"
	formKey     string = "goji.csrf.Form"
	errorKey    string = "goji.csrf.Error"
	cookieName  string = "_goji_csrf"
	errorPrefix string = "goji/csrf: "
)

var (
	// The name value used in form fields.
	fieldName = tokenKey
	// The default HTTP request header to inspect
	headerName = "X-CSRF-Token"
	// Idempotent (safe) methods as defined by RFC7231 section 4.2.2.
	safeMethods = []string{"GET", "HEAD", "OPTIONS", "TRACE"}
)

// TemplateTag provides a default template tag - e.g. {{ .csrfField }} - for use
// with the TemplateField function.
var TemplateTag = "csrfField"

var (
	// ErrNoReferer is returned when a HTTPS request provides an empty Referer
	// header.
	ErrNoReferer = errors.New("referer not supplied")
	// ErrBadReferer is returned when the scheme & host in the URL do not match
	// the supplied Referer header.
	ErrBadReferer = errors.New("referer invalid")
	// ErrNoToken is returned if no CSRF token is supplied in the request.
	ErrNoToken = errors.New("CSRF token not found in request")
	// ErrBadToken is returned if the CSRF token in the request does not match
	// the token in the session, or is otherwise malformed.
	ErrBadToken = errors.New("CSRF token invalid")
)

type csrf struct {
	h    goji.Handler
	sc   *securecookie.SecureCookie
	st   store
	opts options
}

// options contains the optional settings for the CSRF middleware.
type options struct {
	MaxAge int
	Domain string
	Path   string
	// Note that the function and field names match the case of the associated
	// http.Cookie field instead of the "correct" HTTPOnly name that golint suggests.
	HttpOnly      bool
	Secure        bool
	RequestHeader string
	FieldName     string
	ErrorHandler  goji.Handler
	CookieName    string
}

// Protect is HTTP middleware that provides Cross-Site Request Forgery
// protection.
//
// It securely generates a masked (unique-per-request) token that
// can be embedded in the HTTP response (e.g. form field or HTTP header).
// The original (unmasked) token is stored in the session, which is inaccessible
// by an attacker (provided you are using HTTPS). Subsequent requests are
// expected to include this token, which is compared against the session token.
// Requests that do not provide a matching token are served with a HTTP 403
// 'Forbidden' error response.
//
// Example:
//	package main
//
//	import (
//	    "html/template"
//	    "net/http"
//
//	    "goji.io"
//	    "github.com/goji/ctx-csrf"
//	    "github.com/zenazn/goji/graceful"
//	)
//
//	func main() {
//	    m := goji.NewMux()
//	    // Add the middleware to your router.
//	    m.UseC(csrf.Protect([]byte("32-byte-long-auth-key")))
//	    m.HandleFuncC(pat.Get("/signup"), ShowSignupForm)
//	    // POST requests without a valid token will return a HTTP 403 Forbidden.
//	    m.HandleFuncC(pat.Post("/signup/post"), SubmitSignupForm)
//
//	    graceful.ListenAndServe(":8000", m)
//	}
//
//	func ShowSignupForm(ctx context.Context, w http.ResponseWriter, r *http.Request) {
//	    // signup_form.tmpl just needs a {{ .csrfField }} template tag for
//	    // csrf.TemplateField to inject the CSRF token into. Easy!
//	    t.ExecuteTemplate(w, "signup_form.tmpl", map[string]interface{
//	        csrf.TemplateTag: csrf.TemplateField(ctx, r),
//	    })
//	    // We could also retrieve the token directly from csrf.Token(c, r) and
//	    // set it in the request header - w.Header.Set("X-CSRF-Token", token)
//	    // This is useful if your sending JSON to clients or a front-end JavaScript
//	    // framework.
//	}
//
//	func SubmitSignupForm(ctx context.Context, w http.ResponseWriter, r *http.Request) {
//	    // We can trust that requests making it this far have satisfied
//	    // our CSRF protection requirements.
//	}
//
func Protect(authKey []byte, opts ...Option) func(goji.Handler) goji.Handler {
	return func(h goji.Handler) goji.Handler {
		cs := parseOptions(h, opts...)

		// Set the defaults if no options have been specified
		if cs.opts.ErrorHandler == nil {
			cs.opts.ErrorHandler = goji.HandlerFunc(unauthorizedHandler)
		}

		if cs.opts.MaxAge < 1 {
			// Default of 12 hours
			cs.opts.MaxAge = 3600 * 12
		}

		if cs.opts.FieldName == "" {
			cs.opts.FieldName = fieldName
		}

		if cs.opts.CookieName == "" {
			cs.opts.CookieName = cookieName
		}

		if cs.opts.RequestHeader == "" {
			cs.opts.RequestHeader = headerName
		}

		// Create an authenticated securecookie instance.
		if cs.sc == nil {
			cs.sc = securecookie.New(authKey, nil)
			// Use JSON serialization (faster than one-off gob encoding)
			cs.sc.SetSerializer(securecookie.JSONEncoder{})
			// Set the MaxAge of the underlying securecookie.
			cs.sc.MaxAge(cs.opts.MaxAge)
		}

		if cs.st == nil {
			// Default to the cookieStore
			cs.st = &cookieStore{
				name:     cs.opts.CookieName,
				maxAge:   cs.opts.MaxAge,
				secure:   cs.opts.Secure,
				httpOnly: cs.opts.HttpOnly,
				path:     cs.opts.Path,
				domain:   cs.opts.Domain,
				sc:       cs.sc,
			}
		}

		return *cs
	}
}

// Implements goji.Handler for the csrf type.
func (cs csrf) ServeHTTPC(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	// Retrieve the token from the session.
	// An error represents either a cookie that failed HMAC validation
	// or that doesn't exist.
	realToken, err := cs.st.Get(r)
	if err != nil || len(realToken) != tokenLength {
		// If there was an error retrieving the token, the token doesn't exist
		// yet, or it's the wrong length, generate a new token.
		// Note that the new token will (correctly) fail validation downstream
		// as it will no longer match the request token.
		realToken, err = generateRandomBytes(tokenLength)
		if err != nil {
			ctx = setEnvError(ctx, err)
			cs.opts.ErrorHandler.ServeHTTPC(ctx, w, r)
			return
		}

		// Save the new (real) token in the session store.
		err = cs.st.Save(realToken, w)
		if err != nil {
			ctx = setEnvError(ctx, err)
			cs.opts.ErrorHandler.ServeHTTPC(ctx, w, r)
			return
		}
	}

	// Save the masked token to the request context
	ctx = context.WithValue(ctx, tokenKey, mask(realToken, r))
	// Save the field name to the request context
	ctx = context.WithValue(ctx, formKey, cs.opts.FieldName)

	// HTTP methods not defined as idempotent ("safe") under RFC7231 require
	// inspection.
	if !contains(safeMethods, r.Method) {
		// Enforce an origin check for HTTPS connections. As per the Django CSRF
		// implementation (https://goo.gl/vKA7GE) the Referer header is almost
		// always present for same-domain HTTP requests.
		if r.URL.Scheme == "https" {
			// Fetch the Referer value. Call the error handler if it's empty or
			// otherwise fails to parse.
			referer, err := url.Parse(r.Referer())
			if err != nil || referer.String() == "" {
				ctx = setEnvError(ctx, ErrNoReferer)
				cs.opts.ErrorHandler.ServeHTTPC(ctx, w, r)
				return
			}

			if sameOrigin(r.URL, referer) == false {
				ctx = setEnvError(ctx, ErrBadReferer)
				cs.opts.ErrorHandler.ServeHTTPC(ctx, w, r)
				return
			}
		}

		// If the token returned from the session store is nil for non-idempotent
		// ("unsafe") methods, call the error handler.
		if realToken == nil {
			ctx = setEnvError(ctx, ErrNoToken)
			cs.opts.ErrorHandler.ServeHTTPC(ctx, w, r)
			return
		}

		// Retrieve the combined token (pad + masked) token and unmask it.
		requestToken := unmask(cs.requestToken(r))

		// Compare the request token against the real token
		if !compareTokens(requestToken, realToken) {
			ctx = setEnvError(ctx, ErrBadToken)
			cs.opts.ErrorHandler.ServeHTTPC(ctx, w, r)
			return
		}

	}

	// Set the Vary: Cookie header to protect clients from caching the response.
	w.Header().Add("Vary", "Cookie")

	// Call the wrapped handler/router on success
	cs.h.ServeHTTPC(ctx, w, r)
}

// unauthorizedhandler sets a HTTP 403 Forbidden status and writes the
// CSRF failure reason to the response.
func unauthorizedHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	http.Error(w, fmt.Sprintf("%s - %s",
		http.StatusText(http.StatusForbidden), FailureReason(ctx, r)),
		http.StatusForbidden)
	return
}
<|endoftext|>


<commit_before>package chart

import "math"

// BollingerBandsSeries draws bollinger bands for an inner series.
// Bollinger bands are defined by two lines, one at SMA+k*stddev, one at SMA-k*stdev.
type BollingerBandsSeries struct {
	Name  string
	Style Style
	YAxis YAxisType

	WindowSize  int
	K           float64
	InnerSeries ValueProvider

	valueBuffer *RingBuffer
}

// GetName returns the name of the time series.
func (bbs BollingerBandsSeries) GetName() string {
	return bbs.Name
}

// GetStyle returns the line style.
func (bbs BollingerBandsSeries) GetStyle() Style {
	return bbs.Style
}

// GetYAxis returns which YAxis the series draws on.
func (bbs BollingerBandsSeries) GetYAxis() YAxisType {
	return bbs.YAxis
}

// GetWindowSize returns the window size.
func (bbs BollingerBandsSeries) GetWindowSize(defaults ...int) int {
	if bbs.WindowSize == 0 {
		if len(defaults) > 0 {
			return defaults[0]
		}
		return DefaultSimpleMovingAveragePeriod
	}
	return bbs.WindowSize
}

// GetK returns the K value.
func (bbs BollingerBandsSeries) GetK(defaults ...float64) float64 {
	if bbs.K == 0 {
		if len(defaults) > 0 {
			return defaults[0]
		}
		return 2.0
	}
	return bbs.K
}

// Len returns the number of elements in the series.
func (bbs *BollingerBandsSeries) Len() int {
	return bbs.InnerSeries.Len()
}

// GetBoundedValue gets the bounded value for the series.
func (bbs *BollingerBandsSeries) GetBoundedValue(index int) (x, y1, y2 float64) {
	if bbs.InnerSeries == nil {
		return
	}
	if bbs.valueBuffer == nil || index == 0 {
		bbs.valueBuffer = NewRingBufferWithCapacity(bbs.GetWindowSize())
	}
	if bbs.valueBuffer.Len() >= bbs.GetWindowSize() {
		bbs.valueBuffer.Dequeue()
	}
	px, py := bbs.InnerSeries.GetValue(index)
	bbs.valueBuffer.Enqueue(py)
	x = px

	ay := bbs.getAverage(bbs.valueBuffer)
	std := bbs.getStdDev(bbs.valueBuffer)

	y1 = ay + (bbs.GetK() * std)
	y2 = ay - (bbs.GetK() * std)
	return
}

// GetLastBoundedValue returns the last bounded value for the series.
func (bbs *BollingerBandsSeries) GetLastBoundedValue() (x, y1, y2 float64) {
	if bbs.InnerSeries == nil {
		return
	}
	windowSize := bbs.GetWindowSize()
	seriesLength := bbs.InnerSeries.Len()
	startAt := seriesLength - windowSize
	if startAt < 0 {
		startAt = 0
	}

	vb := NewRingBufferWithCapacity(windowSize)
	for index := startAt; index < seriesLength; index++ {
		xn, yn := bbs.InnerSeries.GetValue(index)
		vb.Enqueue(yn)
		x = xn
	}

	ay := bbs.getAverage(vb)
	std := bbs.getStdDev(vb)

	y1 = ay + (bbs.GetK() * std)
	y2 = ay - (bbs.GetK() * std)

	return
}

// Render renders the series.
func (bbs *BollingerBandsSeries) Render(r Renderer, canvasBox Box, xrange, yrange Range, defaults Style) {
	s := bbs.Style.WithDefaultsFrom(defaults.WithDefaultsFrom(Style{
		StrokeWidth: 1.0,
		StrokeColor: DefaultAxisColor.WithAlpha(64),
		FillColor:   DefaultAxisColor.WithAlpha(32),
	}))

	DrawBoundedSeries(r, canvasBox, xrange, yrange, s, bbs, bbs.GetWindowSize())
}

func (bbs BollingerBandsSeries) getAverage(valueBuffer *RingBuffer) float64 {
	var accum float64
	valueBuffer.Each(func(v interface{}) {
		if typed, isTyped := v.(float64); isTyped {
			accum += typed
		}
	})
	return accum / float64(valueBuffer.Len())
}

func (bbs BollingerBandsSeries) getVariance(valueBuffer *RingBuffer) float64 {
	if valueBuffer.Len() == 0 {
		return 0
	}

	var variance float64
	m := bbs.getAverage(valueBuffer)

	valueBuffer.Each(func(v interface{}) {
		if n, isTyped := v.(float64); isTyped {
			variance += (float64(n) - m) * (float64(n) - m)
		}
	})

	return variance / float64(valueBuffer.Len())
}

func (bbs BollingerBandsSeries) getStdDev(valueBuffer *RingBuffer) float64 {
	return math.Pow(bbs.getVariance(valueBuffer), 0.5)
}
<commit_msg>s/window/period/g<commit_after>package chart

import "math"

// BollingerBandsSeries draws bollinger bands for an inner series.
// Bollinger bands are defined by two lines, one at SMA+k*stddev, one at SMA-k*stdev.
type BollingerBandsSeries struct {
	Name  string
	Style Style
	YAxis YAxisType

	Period      int
	K           float64
	InnerSeries ValueProvider

	valueBuffer *RingBuffer
}

// GetName returns the name of the time series.
func (bbs BollingerBandsSeries) GetName() string {
	return bbs.Name
}

// GetStyle returns the line style.
func (bbs BollingerBandsSeries) GetStyle() Style {
	return bbs.Style
}

// GetYAxis returns which YAxis the series draws on.
func (bbs BollingerBandsSeries) GetYAxis() YAxisType {
	return bbs.YAxis
}

// GetPeriod returns the window size.
func (bbs BollingerBandsSeries) GetPeriod() int {
	if bbs.Period == 0 {
		return DefaultSimpleMovingAveragePeriod
	}
	return bbs.Period
}

// GetK returns the K value.
func (bbs BollingerBandsSeries) GetK(defaults ...float64) float64 {
	if bbs.K == 0 {
		if len(defaults) > 0 {
			return defaults[0]
		}
		return 2.0
	}
	return bbs.K
}

// Len returns the number of elements in the series.
func (bbs *BollingerBandsSeries) Len() int {
	return bbs.InnerSeries.Len()
}

// GetBoundedValue gets the bounded value for the series.
func (bbs *BollingerBandsSeries) GetBoundedValue(index int) (x, y1, y2 float64) {
	if bbs.InnerSeries == nil {
		return
	}
	if bbs.valueBuffer == nil || index == 0 {
		bbs.valueBuffer = NewRingBufferWithCapacity(bbs.GetPeriod())
	}
	if bbs.valueBuffer.Len() >= bbs.GetPeriod() {
		bbs.valueBuffer.Dequeue()
	}
	px, py := bbs.InnerSeries.GetValue(index)
	bbs.valueBuffer.Enqueue(py)
	x = px

	ay := bbs.getAverage(bbs.valueBuffer)
	std := bbs.getStdDev(bbs.valueBuffer)

	y1 = ay + (bbs.GetK() * std)
	y2 = ay - (bbs.GetK() * std)
	return
}

// GetLastBoundedValue returns the last bounded value for the series.
func (bbs *BollingerBandsSeries) GetLastBoundedValue() (x, y1, y2 float64) {
	if bbs.InnerSeries == nil {
		return
	}
	period := bbs.GetPeriod()
	seriesLength := bbs.InnerSeries.Len()
	startAt := seriesLength - period
	if startAt < 0 {
		startAt = 0
	}

	vb := NewRingBufferWithCapacity(period)
	for index := startAt; index < seriesLength; index++ {
		xn, yn := bbs.InnerSeries.GetValue(index)
		vb.Enqueue(yn)
		x = xn
	}

	ay := bbs.getAverage(vb)
	std := bbs.getStdDev(vb)

	y1 = ay + (bbs.GetK() * std)
	y2 = ay - (bbs.GetK() * std)

	return
}

// Render renders the series.
func (bbs *BollingerBandsSeries) Render(r Renderer, canvasBox Box, xrange, yrange Range, defaults Style) {
	s := bbs.Style.WithDefaultsFrom(defaults.WithDefaultsFrom(Style{
		StrokeWidth: 1.0,
		StrokeColor: DefaultAxisColor.WithAlpha(64),
		FillColor:   DefaultAxisColor.WithAlpha(32),
	}))

	DrawBoundedSeries(r, canvasBox, xrange, yrange, s, bbs, bbs.GetPeriod())
}

func (bbs BollingerBandsSeries) getAverage(valueBuffer *RingBuffer) float64 {
	var accum float64
	valueBuffer.Each(func(v interface{}) {
		if typed, isTyped := v.(float64); isTyped {
			accum += typed
		}
	})
	return accum / float64(valueBuffer.Len())
}

func (bbs BollingerBandsSeries) getVariance(valueBuffer *RingBuffer) float64 {
	if valueBuffer.Len() == 0 {
		return 0
	}

	var variance float64
	m := bbs.getAverage(valueBuffer)

	valueBuffer.Each(func(v interface{}) {
		if n, isTyped := v.(float64); isTyped {
			variance += (float64(n) - m) * (float64(n) - m)
		}
	})

	return variance / float64(valueBuffer.Len())
}

func (bbs BollingerBandsSeries) getStdDev(valueBuffer *RingBuffer) float64 {
	return math.Pow(bbs.getVariance(valueBuffer), 0.5)
}
<|endoftext|>


<commit_before>package dash

import (
	"os"
	"sync"
)

type Dash struct {
	store  map[string]string
	mutex  *sync.Mutex
	wQueue chan pair
	dbFile string
}

type pair struct {
	key   string
	value string
}

//create a new Dash instance
func New() (*Dash, error) {
	d := Dash{store: make(map[string]string), mutex: new(sync.Mutex), wQueue: make(chan pair), dbFile: "dash.db"}
	err := d.startQueue()
	return &d, err
}

//add a value to the store
func (d *Dash) Set(key, value string) {
	d.mutex.Lock()
	d.store[key] = value
	d.mutex.Unlock()
	d.wQueue <- pair{key: key, value: value}
}

//get a value from the store
func (d *Dash) Get(key string) string {
	return d.store[key]
}

//private things related to disk persistence

//start the disk writing queue
func (d *Dash) startQueue() error {
	f, err := os.OpenFile(d.dbFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		return err
	}
	go d.runQueue(f)
	return nil
}

//the running queue
func (d *Dash) runQueue(f *os.File) {
	defer f.Close()
	for {
		select {
		case pair := <-d.wQueue:
			f.Write([]byte(pair.key + "=" + pair.value + "\n")) //need to figure out the right delimiters
		}
	}
}

//loads the data stored in the db file
func (d *Dash) loadData() {
	f, err := os.OpenFile(d.dbFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	defer f.Close()
	for {
		//need to figure out the right delimiter characters...
		//b := make([]byte, 1024)
		//f.Read(b)

		return
	}
}
<commit_msg>disk work<commit_after>package dash

import (
	"fmt"
	"os"
	"sync"
)

type Dash struct {
	store  map[string]string
	mutex  *sync.Mutex
	wQueue chan pair
	dbFile string
}

type pair struct {
	key   string
	value string
}

//create a new Dash instance
func New() (*Dash, error) {
	d := Dash{store: make(map[string]string), mutex: new(sync.Mutex), wQueue: make(chan pair), dbFile: "dash.db"}
	err := d.startQueue()
	return &d, err
}

//add a value to the store
func (d *Dash) Set(key, value string) {
	d.mutex.Lock()
	d.store[key] = value
	d.mutex.Unlock()
	d.wQueue <- pair{key: key, value: value}
}

//get a value from the store
func (d *Dash) Get(key string) string {
	return d.store[key]
}

//private things related to disk persistence

//start the disk writing queue
func (d *Dash) startQueue() error {
	f, err := os.OpenFile(d.dbFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		return err
	}
	go d.runQueue(f)
	return nil
}

//the running queue
func (d *Dash) runQueue(f *os.File) {
	defer f.Close()
	for {
		select {
		case pair := <-d.wQueue:
			f.Write([]byte(fmt.Sprintf("%d%s%d%s", len(pair.key), pair.key, len(pair.value), pair.value)))
		}
	}
}

//loads the data stored in the db file
func (d *Dash) loadData() error {
	f, err := os.OpenFile(d.dbFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		return err
	}
	defer f.Close()
	// b := make([]byte, 1)
	// f.Read(b)
	// count := Int(b)
	for {
		//read each key & value out in this loop
	}
	return nil
}
<|endoftext|>


<commit_before>package marvel

import (
	"time"
)

// DataWrapper provides the common wrapper attributes to unmarshal the API's response.
// It is used to compose more specific wrappers, e.g., CharacterDataWrapper.
type DataWrapper struct {
	Code            int    `json:"code,omitempty"`
	Status          string `json:"status,omitempty"`
	Copyright       string `json:"copyright,omitempty"`
	AttributionText string `json:"attributionText,omitempty"`
	AttributionHTML string `json:"attributionHTML,omitempty"`
	ETag            string `json:"etag,omitempty"`
}

// DataContainer provides the common container attributes to unmarshal the API's response.
// It is used to compose more specific containers, e.g., CharacterDataContainer.
type DataContainer struct {
	Offset int `json:"offset,omitempty"`
	Limit  int `json:"limit,omitempty"`
	Total  int `json:"total,omitempty"`
	Count  int `json:"count,omitempty"`
}

// URL represents a public website related to the parent entity.
type URL struct {
	Type string `json:"type,omitempty"`
	URL  string `json:"url,omitempty"`
}

// Image represents the available graphics related to the parent entity. This information
// is the basis for constructing paths to specific image variants. See
// https://developer.marvel.com/documentation/images for details.
type Image struct {
	Path      string `json:"path,omitempty"`
	Extension string `json:"extension,omitempty"`
}

// Time allows unique parsing of the time format given in the API's responses.
type Time struct{ time.Time }

// UnmarshalJSON implements the json.Unmarshaler interface. The timezone format
// returned by the API does not parse using any of the default formats in the time
// package.
func (tm *Time) UnmarshalJSON(b []byte) (err error) {
	if tempTime, err := time.Parse(`"2006-01-02T15:04:05Z0700"`, string(b)); err == nil {
		tm.Time = tempTime
	}
	return
}

// TextObject represents a descriptive text blurb for the parent entity.
type TextObject struct {
	Type     string
	Language string
	Text     string
}

// List provides the common list attributes to unmarshal the API's response.
// It is used to compose more specific containers, e.g., CharacterList.
type List struct {
	Available     int    `json:"available,omitempty"`
	Returned      int    `json:"returned,omitempty"`
	CollectionURI string `json:"collectionURI,omitempty"`
}

// Summary provides the common summary attributes to unmarshal the API's response.
// It is used to compose more specific containers, e.g., CharacterSummary.
type Summary struct {
	ResourceURI string `json:"resourceURI,omitempty"`
	Name        string `json:"name,omitempty"`
}
<commit_msg>Give TextObject struct tags<commit_after>package marvel

import (
	"time"
)

// DataWrapper provides the common wrapper attributes to unmarshal the API's response.
// It is used to compose more specific wrappers, e.g., CharacterDataWrapper.
type DataWrapper struct {
	Code            int    `json:"code,omitempty"`
	Status          string `json:"status,omitempty"`
	Copyright       string `json:"copyright,omitempty"`
	AttributionText string `json:"attributionText,omitempty"`
	AttributionHTML string `json:"attributionHTML,omitempty"`
	ETag            string `json:"etag,omitempty"`
}

// DataContainer provides the common container attributes to unmarshal the API's response.
// It is used to compose more specific containers, e.g., CharacterDataContainer.
type DataContainer struct {
	Offset int `json:"offset,omitempty"`
	Limit  int `json:"limit,omitempty"`
	Total  int `json:"total,omitempty"`
	Count  int `json:"count,omitempty"`
}

// URL represents a public website related to the parent entity.
type URL struct {
	Type string `json:"type,omitempty"`
	URL  string `json:"url,omitempty"`
}

// Image represents the available graphics related to the parent entity. This information
// is the basis for constructing paths to specific image variants. See
// https://developer.marvel.com/documentation/images for details.
type Image struct {
	Path      string `json:"path,omitempty"`
	Extension string `json:"extension,omitempty"`
}

// Time allows unique parsing of the time format given in the API's responses.
type Time struct{ time.Time }

// UnmarshalJSON implements the json.Unmarshaler interface. The timezone format
// returned by the API does not parse using any of the default formats in the time
// package.
func (tm *Time) UnmarshalJSON(b []byte) (err error) {
	if tempTime, err := time.Parse(`"2006-01-02T15:04:05Z0700"`, string(b)); err == nil {
		tm.Time = tempTime
	}
	return
}

// TextObject represents a descriptive text blurb for the parent entity.
type TextObject struct {
	Type     string `json:"type,omitempty"`
	Language string `json:"language,omitempty"`
	Text     string `json:"text,omitempty"`
}

// List provides the common list attributes to unmarshal the API's response.
// It is used to compose more specific containers, e.g., CharacterList.
type List struct {
	Available     int    `json:"available,omitempty"`
	Returned      int    `json:"returned,omitempty"`
	CollectionURI string `json:"collectionURI,omitempty"`
}

// Summary provides the common summary attributes to unmarshal the API's response.
// It is used to compose more specific containers, e.g., CharacterSummary.
type Summary struct {
	ResourceURI string `json:"resourceURI,omitempty"`
	Name        string `json:"name,omitempty"`
}
<|endoftext|>


<commit_before>package dbus

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

var (
	byteType        = reflect.TypeOf(byte(0))
	boolType        = reflect.TypeOf(false)
	uint8Type       = reflect.TypeOf(uint8(0))
	int16Type       = reflect.TypeOf(int16(0))
	uint16Type      = reflect.TypeOf(uint16(0))
	intType         = reflect.TypeOf(int(0))
	uintType        = reflect.TypeOf(uint(0))
	int32Type       = reflect.TypeOf(int32(0))
	uint32Type      = reflect.TypeOf(uint32(0))
	int64Type       = reflect.TypeOf(int64(0))
	uint64Type      = reflect.TypeOf(uint64(0))
	float64Type     = reflect.TypeOf(float64(0))
	stringType      = reflect.TypeOf("")
	signatureType   = reflect.TypeOf(Signature{""})
	objectPathType  = reflect.TypeOf(ObjectPath(""))
	variantType     = reflect.TypeOf(Variant{Signature{""}, nil})
	interfacesType  = reflect.TypeOf([]interface{}{})
	interfaceType   = reflect.TypeOf((*interface{})(nil)).Elem()
	unixFDType      = reflect.TypeOf(UnixFD(0))
	unixFDIndexType = reflect.TypeOf(UnixFDIndex(0))
)

// An InvalidTypeError signals that a value which cannot be represented in the
// D-Bus wire format was passed to a function.
type InvalidTypeError struct {
	Type reflect.Type
}

func (e InvalidTypeError) Error() string {
	return "dbus: invalid type " + e.Type.String()
}

// Store copies the values contained in src to dest, which must be a slice of
// pointers. It converts slices of interfaces from src to corresponding structs
// in dest. An error is returned if the lengths of src and dest or the types of
// their elements don't match.
func Store(src []interface{}, dest ...interface{}) error {
	if len(src) != len(dest) {
		return errors.New("dbus.Store: length mismatch")
	}

	for i := range src {
		if err := storeInterfaces(src[i], dest[i]); err != nil {
			return err
		}
	}
	return nil
}

func storeInterfaces(src, dest interface{}) error {
	return store(reflect.ValueOf(dest), reflect.ValueOf(src))
}

func store(dest, src reflect.Value) error {
	if dest.Kind() == reflect.Ptr {
		return store(dest.Elem(), src)
	}
	switch src.Kind() {
	case reflect.Slice:
		return storeSlice(dest, src)
	case reflect.Map:
		return storeMap(dest, src)
	default:
		return storeBase(dest, src)
	}
}

func storeBase(dest, src reflect.Value) error {
	return setDest(dest, src)
}

func setDest(dest, src reflect.Value) error {
	if !isVariant(src.Type()) && isVariant(dest.Type()) {
		//special conversion for dbus.Variant
		dest.Set(reflect.ValueOf(MakeVariant(src.Interface())))
		return nil
	}
	if isVariant(src.Type()) && !isVariant(dest.Type()) {
		src = getVariantValue(src)
	}
	if !src.Type().ConvertibleTo(dest.Type()) {
		return fmt.Errorf(
			"dbus.Store: type mismatch: cannot convert %s to %s",
			src.Type(), dest.Type())
	}
	dest.Set(src.Convert(dest.Type()))
	return nil
}

func kindsAreCompatible(dest, src reflect.Type) bool {
	switch {
	case isVariant(dest):
		return true
	case dest.Kind() == reflect.Interface:
		return true
	default:
		return dest.Kind() == src.Kind()
	}
}

func isConvertibleTo(dest, src reflect.Type) bool {
	switch {
	case isVariant(dest):
		return true
	case dest.Kind() == reflect.Interface:
		return true
	case dest.Kind() == reflect.Slice:
		return src.Kind() == reflect.Slice &&
			isConvertibleTo(dest.Elem(), src.Elem())
	case dest.Kind() == reflect.Struct:
		return src == interfacesType
	default:
		return src.ConvertibleTo(dest)
	}
}

func storeMap(dest, src reflect.Value) error {
	switch {
	case !kindsAreCompatible(dest.Type(), src.Type()):
		return fmt.Errorf(
			"dbus.Store: type mismatch: "+
				"map: cannot store a value of %s into %s",
			src.Type(), dest.Type())
	case isVariant(dest.Type()):
		return storeMapIntoVariant(dest, src)
	case dest.Kind() == reflect.Interface:
		return storeMapIntoInterface(dest, src)
	case isConvertibleTo(dest.Type().Key(), src.Type().Key()) &&
		isConvertibleTo(dest.Type().Elem(), src.Type().Elem()):
		return storeMapIntoMap(dest, src)
	default:
		return fmt.Errorf(
			"dbus.Store: type mismatch: "+
				"map: cannot convert a value of %s into %s",
			src.Type(), dest.Type())
	}
}

func storeMapIntoVariant(dest, src reflect.Value) error {
	dv := reflect.MakeMap(src.Type())
	err := store(dv, src)
	if err != nil {
		return err
	}
	return storeBase(dest, dv)
}

func storeMapIntoInterface(dest, src reflect.Value) error {
	var dv reflect.Value
	if isVariant(src.Type().Elem()) {
		//Convert variants to interface{} recursively when converting
		//to interface{}
		dv = reflect.MakeMap(
			reflect.MapOf(src.Type().Key(), interfaceType))
	} else {
		dv = reflect.MakeMap(src.Type())
	}
	err := store(dv, src)
	if err != nil {
		return err
	}
	return storeBase(dest, dv)
}

func storeMapIntoMap(dest, src reflect.Value) error {
	if dest.IsNil() {
		dest.Set(reflect.MakeMap(dest.Type()))
	}
	keys := src.MapKeys()
	for _, key := range keys {
		dkey := key.Convert(dest.Type().Key())
		dval := reflect.New(dest.Type().Elem()).Elem()
		err := store(dval, getVariantValue(src.MapIndex(key)))
		if err != nil {
			return err
		}
		dest.SetMapIndex(dkey, dval)
	}
	return nil
}

func storeSlice(dest, src reflect.Value) error {
	switch {
	case src.Type() == interfacesType && dest.Kind() == reflect.Struct:
		//The decoder always decodes structs as slices of interface{}
		return storeStruct(dest, src)
	case !kindsAreCompatible(dest.Type(), src.Type()):
		return fmt.Errorf(
			"dbus.Store: type mismatch: "+
				"slice: cannot store a value of %s into %s",
			src.Type(), dest.Type())
	case isVariant(dest.Type()):
		return storeSliceIntoVariant(dest, src)
	case dest.Kind() == reflect.Interface:
		return storeSliceIntoInterface(dest, src)
	case isConvertibleTo(dest.Type().Elem(), src.Type().Elem()):
		return storeSliceIntoSlice(dest, src)
	default:
		return fmt.Errorf(
			"dbus.Store: type mismatch: "+
				"slice: cannot convert a value of %s into %s",
			src.Type(), dest.Type())
	}
}

func storeStruct(dest, src reflect.Value) error {
	if isVariant(dest.Type()) {
		return storeBase(dest, src)
	}
	dval := make([]interface{}, 0, dest.NumField())
	dtype := dest.Type()
	for i := 0; i < dest.NumField(); i++ {
		field := dest.Field(i)
		ftype := dtype.Field(i)
		if ftype.PkgPath != "" {
			continue
		}
		if ftype.Tag.Get("dbus") == "-" {
			continue
		}
		dval = append(dval, field.Addr().Interface())
	}
	if src.Len() != len(dval) {
		return fmt.Errorf(
			"dbus.Store: type mismatch: "+
				"destination struct does not have "+
				"enough fields need: %d have: %d",
			src.Len(), len(dval))
	}
	return Store(src.Interface().([]interface{}), dval...)
}

func storeSliceIntoVariant(dest, src reflect.Value) error {
	dv := reflect.MakeSlice(src.Type(), src.Len(), src.Cap())
	err := store(dv, src)
	if err != nil {
		return err
	}
	return storeBase(dest, dv)
}

func storeSliceIntoInterface(dest, src reflect.Value) error {
	var dv reflect.Value
	if isVariant(src.Type().Elem()) {
		//Convert variants to interface{} recursively when converting
		//to interface{}
		dv = reflect.MakeSlice(reflect.SliceOf(interfaceType),
			src.Len(), src.Cap())
	} else {
		dv = reflect.MakeSlice(src.Type(), src.Len(), src.Cap())
	}
	err := store(dv, src)
	if err != nil {
		return err
	}
	return storeBase(dest, dv)
}

func storeSliceIntoSlice(dest, src reflect.Value) error {
	if dest.IsNil() || dest.Len() < src.Len() {
		dest.Set(reflect.MakeSlice(dest.Type(), src.Len(), src.Cap()))
	}
	if dest.Len() != src.Len() {
		return fmt.Errorf(
			"dbus.Store: type mismatch: "+
				"slices are different lengths "+
				"need: %d have: %d",
			src.Len(), dest.Len())
	}
	for i := 0; i < src.Len(); i++ {
		err := store(dest.Index(i), getVariantValue(src.Index(i)))
		if err != nil {
			return err
		}
	}
	return nil
}

func getVariantValue(in reflect.Value) reflect.Value {
	if isVariant(in.Type()) {
		return reflect.ValueOf(in.Interface().(Variant).Value())
	}
	return in
}

func isVariant(t reflect.Type) bool {
	return t == variantType
}

// An ObjectPath is an object path as defined by the D-Bus spec.
type ObjectPath string

// IsValid returns whether the object path is valid.
func (o ObjectPath) IsValid() bool {
	s := string(o)
	if len(s) == 0 {
		return false
	}
	if s[0] != '/' {
		return false
	}
	if s[len(s)-1] == '/' && len(s) != 1 {
		return false
	}
	// probably not used, but technically possible
	if s == "/" {
		return true
	}
	split := strings.Split(s[1:], "/")
	for _, v := range split {
		if len(v) == 0 {
			return false
		}
		for _, c := range v {
			if !isMemberChar(c) {
				return false
			}
		}
	}
	return true
}

// A UnixFD is a Unix file descriptor sent over the wire. See the package-level
// documentation for more information about Unix file descriptor passsing.
type UnixFD int32

// A UnixFDIndex is the representation of a Unix file descriptor in a message.
type UnixFDIndex uint32

// alignment returns the alignment of values of type t.
func alignment(t reflect.Type) int {
	switch t {
	case variantType:
		return 1
	case objectPathType:
		return 4
	case signatureType:
		return 1
	case interfacesType:
		return 4
	}
	switch t.Kind() {
	case reflect.Uint8:
		return 1
	case reflect.Uint16, reflect.Int16:
		return 2
	case reflect.Uint, reflect.Int, reflect.Uint32, reflect.Int32, reflect.String, reflect.Array, reflect.Slice, reflect.Map:
		return 4
	case reflect.Uint64, reflect.Int64, reflect.Float64, reflect.Struct:
		return 8
	case reflect.Ptr:
		return alignment(t.Elem())
	}
	return 1
}

// isKeyType returns whether t is a valid type for a D-Bus dict.
func isKeyType(t reflect.Type) bool {
	switch t.Kind() {
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
		reflect.Int16, reflect.Int32, reflect.Int64, reflect.Float64,
		reflect.String, reflect.Uint, reflect.Int:

		return true
	}
	return false
}

// isValidInterface returns whether s is a valid name for an interface.
func isValidInterface(s string) bool {
	if len(s) == 0 || len(s) > 255 || s[0] == '.' {
		return false
	}
	elem := strings.Split(s, ".")
	if len(elem) < 2 {
		return false
	}
	for _, v := range elem {
		if len(v) == 0 {
			return false
		}
		if v[0] >= '0' && v[0] <= '9' {
			return false
		}
		for _, c := range v {
			if !isMemberChar(c) {
				return false
			}
		}
	}
	return true
}

// isValidMember returns whether s is a valid name for a member.
func isValidMember(s string) bool {
	if len(s) == 0 || len(s) > 255 {
		return false
	}
	i := strings.Index(s, ".")
	if i != -1 {
		return false
	}
	if s[0] >= '0' && s[0] <= '9' {
		return false
	}
	for _, c := range s {
		if !isMemberChar(c) {
			return false
		}
	}
	return true
}

func isMemberChar(c rune) bool {
	return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') ||
		(c >= 'a' && c <= 'z') || c == '_'
}
<commit_msg>Support variants of structs<commit_after>package dbus

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

var (
	byteType        = reflect.TypeOf(byte(0))
	boolType        = reflect.TypeOf(false)
	uint8Type       = reflect.TypeOf(uint8(0))
	int16Type       = reflect.TypeOf(int16(0))
	uint16Type      = reflect.TypeOf(uint16(0))
	intType         = reflect.TypeOf(int(0))
	uintType        = reflect.TypeOf(uint(0))
	int32Type       = reflect.TypeOf(int32(0))
	uint32Type      = reflect.TypeOf(uint32(0))
	int64Type       = reflect.TypeOf(int64(0))
	uint64Type      = reflect.TypeOf(uint64(0))
	float64Type     = reflect.TypeOf(float64(0))
	stringType      = reflect.TypeOf("")
	signatureType   = reflect.TypeOf(Signature{""})
	objectPathType  = reflect.TypeOf(ObjectPath(""))
	variantType     = reflect.TypeOf(Variant{Signature{""}, nil})
	interfacesType  = reflect.TypeOf([]interface{}{})
	interfaceType   = reflect.TypeOf((*interface{})(nil)).Elem()
	unixFDType      = reflect.TypeOf(UnixFD(0))
	unixFDIndexType = reflect.TypeOf(UnixFDIndex(0))
)

// An InvalidTypeError signals that a value which cannot be represented in the
// D-Bus wire format was passed to a function.
type InvalidTypeError struct {
	Type reflect.Type
}

func (e InvalidTypeError) Error() string {
	return "dbus: invalid type " + e.Type.String()
}

// Store copies the values contained in src to dest, which must be a slice of
// pointers. It converts slices of interfaces from src to corresponding structs
// in dest. An error is returned if the lengths of src and dest or the types of
// their elements don't match.
func Store(src []interface{}, dest ...interface{}) error {
	if len(src) != len(dest) {
		return errors.New("dbus.Store: length mismatch")
	}

	for i := range src {
		if err := storeInterfaces(src[i], dest[i]); err != nil {
			return err
		}
	}
	return nil
}

func storeInterfaces(src, dest interface{}) error {
	return store(reflect.ValueOf(dest), reflect.ValueOf(src))
}

func store(dest, src reflect.Value) error {
	if dest.Kind() == reflect.Ptr {
		return store(dest.Elem(), src)
	}
	switch src.Kind() {
	case reflect.Slice:
		return storeSlice(dest, src)
	case reflect.Map:
		return storeMap(dest, src)
	default:
		return storeBase(dest, src)
	}
}

func storeBase(dest, src reflect.Value) error {
	return setDest(dest, src)
}

func setDest(dest, src reflect.Value) error {
	if !isVariant(src.Type()) && isVariant(dest.Type()) {
		//special conversion for dbus.Variant
		dest.Set(reflect.ValueOf(MakeVariant(src.Interface())))
		return nil
	}
	if isVariant(src.Type()) && !isVariant(dest.Type()) {
		src = getVariantValue(src)
		return store(dest, src)
	}
	if !src.Type().ConvertibleTo(dest.Type()) {
		return fmt.Errorf(
			"dbus.Store: type mismatch: cannot convert %s to %s",
			src.Type(), dest.Type())
	}
	dest.Set(src.Convert(dest.Type()))
	return nil
}

func kindsAreCompatible(dest, src reflect.Type) bool {
	switch {
	case isVariant(dest):
		return true
	case dest.Kind() == reflect.Interface:
		return true
	default:
		return dest.Kind() == src.Kind()
	}
}

func isConvertibleTo(dest, src reflect.Type) bool {
	switch {
	case isVariant(dest):
		return true
	case dest.Kind() == reflect.Interface:
		return true
	case dest.Kind() == reflect.Slice:
		return src.Kind() == reflect.Slice &&
			isConvertibleTo(dest.Elem(), src.Elem())
	case dest.Kind() == reflect.Struct:
		return src == interfacesType
	default:
		return src.ConvertibleTo(dest)
	}
}

func storeMap(dest, src reflect.Value) error {
	switch {
	case !kindsAreCompatible(dest.Type(), src.Type()):
		return fmt.Errorf(
			"dbus.Store: type mismatch: "+
				"map: cannot store a value of %s into %s",
			src.Type(), dest.Type())
	case isVariant(dest.Type()):
		return storeMapIntoVariant(dest, src)
	case dest.Kind() == reflect.Interface:
		return storeMapIntoInterface(dest, src)
	case isConvertibleTo(dest.Type().Key(), src.Type().Key()) &&
		isConvertibleTo(dest.Type().Elem(), src.Type().Elem()):
		return storeMapIntoMap(dest, src)
	default:
		return fmt.Errorf(
			"dbus.Store: type mismatch: "+
				"map: cannot convert a value of %s into %s",
			src.Type(), dest.Type())
	}
}

func storeMapIntoVariant(dest, src reflect.Value) error {
	dv := reflect.MakeMap(src.Type())
	err := store(dv, src)
	if err != nil {
		return err
	}
	return storeBase(dest, dv)
}

func storeMapIntoInterface(dest, src reflect.Value) error {
	var dv reflect.Value
	if isVariant(src.Type().Elem()) {
		//Convert variants to interface{} recursively when converting
		//to interface{}
		dv = reflect.MakeMap(
			reflect.MapOf(src.Type().Key(), interfaceType))
	} else {
		dv = reflect.MakeMap(src.Type())
	}
	err := store(dv, src)
	if err != nil {
		return err
	}
	return storeBase(dest, dv)
}

func storeMapIntoMap(dest, src reflect.Value) error {
	if dest.IsNil() {
		dest.Set(reflect.MakeMap(dest.Type()))
	}
	keys := src.MapKeys()
	for _, key := range keys {
		dkey := key.Convert(dest.Type().Key())
		dval := reflect.New(dest.Type().Elem()).Elem()
		err := store(dval, getVariantValue(src.MapIndex(key)))
		if err != nil {
			return err
		}
		dest.SetMapIndex(dkey, dval)
	}
	return nil
}

func storeSlice(dest, src reflect.Value) error {
	switch {
	case src.Type() == interfacesType && dest.Kind() == reflect.Struct:
		//The decoder always decodes structs as slices of interface{}
		return storeStruct(dest, src)
	case !kindsAreCompatible(dest.Type(), src.Type()):
		return fmt.Errorf(
			"dbus.Store: type mismatch: "+
				"slice: cannot store a value of %s into %s",
			src.Type(), dest.Type())
	case isVariant(dest.Type()):
		return storeSliceIntoVariant(dest, src)
	case dest.Kind() == reflect.Interface:
		return storeSliceIntoInterface(dest, src)
	case isConvertibleTo(dest.Type().Elem(), src.Type().Elem()):
		return storeSliceIntoSlice(dest, src)
	default:
		return fmt.Errorf(
			"dbus.Store: type mismatch: "+
				"slice: cannot convert a value of %s into %s",
			src.Type(), dest.Type())
	}
}

func storeStruct(dest, src reflect.Value) error {
	if isVariant(dest.Type()) {
		return storeBase(dest, src)
	}
	dval := make([]interface{}, 0, dest.NumField())
	dtype := dest.Type()
	for i := 0; i < dest.NumField(); i++ {
		field := dest.Field(i)
		ftype := dtype.Field(i)
		if ftype.PkgPath != "" {
			continue
		}
		if ftype.Tag.Get("dbus") == "-" {
			continue
		}
		dval = append(dval, field.Addr().Interface())
	}
	if src.Len() != len(dval) {
		return fmt.Errorf(
			"dbus.Store: type mismatch: "+
				"destination struct does not have "+
				"enough fields need: %d have: %d",
			src.Len(), len(dval))
	}
	return Store(src.Interface().([]interface{}), dval...)
}

func storeSliceIntoVariant(dest, src reflect.Value) error {
	dv := reflect.MakeSlice(src.Type(), src.Len(), src.Cap())
	err := store(dv, src)
	if err != nil {
		return err
	}
	return storeBase(dest, dv)
}

func storeSliceIntoInterface(dest, src reflect.Value) error {
	var dv reflect.Value
	if isVariant(src.Type().Elem()) {
		//Convert variants to interface{} recursively when converting
		//to interface{}
		dv = reflect.MakeSlice(reflect.SliceOf(interfaceType),
			src.Len(), src.Cap())
	} else {
		dv = reflect.MakeSlice(src.Type(), src.Len(), src.Cap())
	}
	err := store(dv, src)
	if err != nil {
		return err
	}
	return storeBase(dest, dv)
}

func storeSliceIntoSlice(dest, src reflect.Value) error {
	if dest.IsNil() || dest.Len() < src.Len() {
		dest.Set(reflect.MakeSlice(dest.Type(), src.Len(), src.Cap()))
	}
	if dest.Len() != src.Len() {
		return fmt.Errorf(
			"dbus.Store: type mismatch: "+
				"slices are different lengths "+
				"need: %d have: %d",
			src.Len(), dest.Len())
	}
	for i := 0; i < src.Len(); i++ {
		err := store(dest.Index(i), getVariantValue(src.Index(i)))
		if err != nil {
			return err
		}
	}
	return nil
}

func getVariantValue(in reflect.Value) reflect.Value {
	if isVariant(in.Type()) {
		return reflect.ValueOf(in.Interface().(Variant).Value())
	}
	return in
}

func isVariant(t reflect.Type) bool {
	return t == variantType
}

// An ObjectPath is an object path as defined by the D-Bus spec.
type ObjectPath string

// IsValid returns whether the object path is valid.
func (o ObjectPath) IsValid() bool {
	s := string(o)
	if len(s) == 0 {
		return false
	}
	if s[0] != '/' {
		return false
	}
	if s[len(s)-1] == '/' && len(s) != 1 {
		return false
	}
	// probably not used, but technically possible
	if s == "/" {
		return true
	}
	split := strings.Split(s[1:], "/")
	for _, v := range split {
		if len(v) == 0 {
			return false
		}
		for _, c := range v {
			if !isMemberChar(c) {
				return false
			}
		}
	}
	return true
}

// A UnixFD is a Unix file descriptor sent over the wire. See the package-level
// documentation for more information about Unix file descriptor passsing.
type UnixFD int32

// A UnixFDIndex is the representation of a Unix file descriptor in a message.
type UnixFDIndex uint32

// alignment returns the alignment of values of type t.
func alignment(t reflect.Type) int {
	switch t {
	case variantType:
		return 1
	case objectPathType:
		return 4
	case signatureType:
		return 1
	case interfacesType:
		return 4
	}
	switch t.Kind() {
	case reflect.Uint8:
		return 1
	case reflect.Uint16, reflect.Int16:
		return 2
	case reflect.Uint, reflect.Int, reflect.Uint32, reflect.Int32, reflect.String, reflect.Array, reflect.Slice, reflect.Map:
		return 4
	case reflect.Uint64, reflect.Int64, reflect.Float64, reflect.Struct:
		return 8
	case reflect.Ptr:
		return alignment(t.Elem())
	}
	return 1
}

// isKeyType returns whether t is a valid type for a D-Bus dict.
func isKeyType(t reflect.Type) bool {
	switch t.Kind() {
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
		reflect.Int16, reflect.Int32, reflect.Int64, reflect.Float64,
		reflect.String, reflect.Uint, reflect.Int:

		return true
	}
	return false
}

// isValidInterface returns whether s is a valid name for an interface.
func isValidInterface(s string) bool {
	if len(s) == 0 || len(s) > 255 || s[0] == '.' {
		return false
	}
	elem := strings.Split(s, ".")
	if len(elem) < 2 {
		return false
	}
	for _, v := range elem {
		if len(v) == 0 {
			return false
		}
		if v[0] >= '0' && v[0] <= '9' {
			return false
		}
		for _, c := range v {
			if !isMemberChar(c) {
				return false
			}
		}
	}
	return true
}

// isValidMember returns whether s is a valid name for a member.
func isValidMember(s string) bool {
	if len(s) == 0 || len(s) > 255 {
		return false
	}
	i := strings.Index(s, ".")
	if i != -1 {
		return false
	}
	if s[0] >= '0' && s[0] <= '9' {
		return false
	}
	for _, c := range s {
		if !isMemberChar(c) {
			return false
		}
	}
	return true
}

func isMemberChar(c rune) bool {
	return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') ||
		(c >= 'a' && c <= 'z') || c == '_'
}
<|endoftext|>