<commit_before>package main

import (
	"encoding/binary"
	"flag"
	"fmt"
	"log"
	"io/ioutil"
	"os"
	"path"
	"strconv"
	"strings"

	"github.com/phil-mansfield/gotetra/cosmo"
	"github.com/phil-mansfield/gotetra/render/io"
	"github.com/phil-mansfield/gotetra/render/halo"
	rgeom "github.com/phil-mansfield/gotetra/render/geom"
	"github.com/phil-mansfield/gotetra/los/geom"
	"github.com/phil-mansfield/gotetra/los/analyze"
)

type Params struct {
	MaxMult float64
}

func main() {
	p := parseCmd()
	ids, snaps, coeffs, err := parseStdin()
	if err != nil { log.Fatal(err.Error()) }
	snapBins, coeffBins, idxBins := binBySnap(snaps, ids, coeffs)

	masses := make([]float64, len(ids))

	for snap, snapIDs := range snapBins {
		log.Println(snap)
		idxs := idxBins[snap]
		snapCoeffs := coeffBins[snap]
		if snap == -1 { continue }

		hds, files, err := readHeaders(snap)
		if err != nil { log.Fatal(err.Error()) }
		hBounds, err := boundingSpheres(snap, &hds[0], snapIDs, p)
		if err != nil { log.Fatal(err.Error()) }
		intrBins := binIntersections(hds, hBounds)

		xs := []rgeom.Vec{}
		for i := range hds {
			if len(intrBins[i]) == 0 { continue }
			hd := &hds[i]

			n := hd.GridWidth*hd.GridWidth*hd.GridWidth
			if len(xs) == 0 { xs = make([]rgeom.Vec, n) }
			err := io.ReadSheetPositionsAt(files[i], xs)
			if err != nil { log.Fatal(err.Error()) }

			for j := range idxs {
				masses[idxs[j]] += massContained(
					&hds[i], xs, snapCoeffs[j], hBounds[j],
				)
			}
			log.Printf("%.3g\n", masses)
		}
	}

	printMasses(ids, snaps, masses)
}

func parseStdin() (ids, snaps []int, coeffs [][]float64, err error) {
	ids, snaps, coeffs = []int{}, []int{}, [][]float64{}
	lines, err := stdinLines()
	if err != nil { return nil, nil, nil, err }
	for i, line := range lines {
		rawTokens := strings.Split(line, " ")
		tokens := make([]string, 0, len(rawTokens))
		for _, tok := range rawTokens {
			if len(tok) != 0 { tokens = append(tokens, tok) }
		}

		var (
			id, snap int
			hCoeffs []float64
			err error
		)
		switch {
		case len(tokens) == 0:
			continue
		case len(tokens) <= 2:
			if tokens[0] == "" { continue }
			return nil, nil, nil, fmt.Errorf(
				"Line %d of stdin has 1 token, but >2 are required.", i + 1,
			)
		case len(tokens) > 2:
			id, err = strconv.Atoi(tokens[0])
			if err != nil {
				return nil, nil, nil, fmt.Errorf(
					"One line %d of stdin, %s does not parse as an int.",
					i + 1, tokens[0],
				)
			}
			snap, err = strconv.Atoi(tokens[1])
			if err != nil {
				return nil, nil, nil, fmt.Errorf(
					"One line %d of stdin, %s does not parse as an int.",
					i + 1, tokens[1],
				)
			}

			hCoeffs = make([]float64, len(tokens) - 2)
			for i := range hCoeffs {
				hCoeffs[i], err = strconv.ParseFloat(tokens[i + 2], 64)
			}
		}

		ids = append(ids, id)
		snaps = append(snaps, snap)
		coeffs = append(coeffs, hCoeffs)
	}

	return ids, snaps, coeffs, nil
}

func stdinLines() ([]string, error) {
	bs, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		return nil, fmt.Errorf(
			"Error reading stdin: %s.", err.Error(),
		)
	}

	text := string(bs)
	return strings.Split(text, "\n"), nil
}

func parseCmd() *Params {
	p := &Params{}
	flag.Float64Var(&p.MaxMult, "MaxMult", 3,
		"Ending radius of LoSs as a multiple of R_200m. " +
			"Should be the same value as used in gtet_shell.")
	flag.Parse()
	return p
}

func binBySnap(
	snaps, ids []int, coeffs [][]float64,
) (snapBins map[int][]int,coeffBins map[int][][]float64,idxBins map[int][]int) {
	snapBins = make(map[int][]int)
	coeffBins = make(map[int][][]float64)
	idxBins = make(map[int][]int)
	for i, snap := range snaps {
		snapBins[snap] = append(snapBins[snap], ids[i])
		coeffBins[snap] = append(coeffBins[snap], coeffs[i])
		idxBins[snap] = append(idxBins[snap], i)
	}
	return snapBins, coeffBins, idxBins
}

func readHeaders(snap int) ([]io.SheetHeader, []string, error) {
	memoDir := os.Getenv("GTET_MEMO_DIR")
	if memoDir == "" {
		// You don't want to memoize? Fine. Deal with the consequences.
		return readHeadersFromSheet(snap)
	}
	if _, err := os.Stat(memoDir); err != nil {
		return nil, nil, err
	}

	memoFile := path.Join(memoDir, fmt.Sprintf("hd_snap%d.dat", snap))

	if _, err := os.Stat(memoFile); err != nil {
		// File not written yet.
		hds, files, err := readHeadersFromSheet(snap)
		if err != nil { return nil, nil, err }

        f, err := os.Create(memoFile)
        if err != nil { return nil, nil, err }
        defer f.Close()
        binary.Write(f, binary.LittleEndian, hds)

		return hds, files, nil
	} else {
		// File exists: read from it instead.

		f, err := os.Open(memoFile)
        if err != nil { return nil, nil, err }
        defer f.Close()

		n, err := sheetNum(snap)
		if err != nil { return nil, nil, err }
		hds := make([]io.SheetHeader, n)
        binary.Read(f, binary.LittleEndian, hds)

		gtetFmt := os.Getenv("GTET_FMT")
		dir := fmt.Sprintf(gtetFmt, snap)
		files, err := dirContents(dir)
		if err != nil { return nil, nil, err }

		return hds, files, nil
	}
}

func sheetNum(snap int) (int, error) {
	gtetFmt := os.Getenv("GTET_FMT")
	dir := fmt.Sprintf(gtetFmt, snap)
	files, err := dirContents(dir)
	if err != nil { return 0, err }
	return len(files), nil
}

func readHeadersFromSheet(snap int) ([]io.SheetHeader, []string, error) {
	gtetFmt := os.Getenv("GTET_FMT")
	dir := fmt.Sprintf(gtetFmt, snap)
	files, err := dirContents(dir)
	if err != nil { return nil, nil, err }

	hds := make([]io.SheetHeader, len(files))
	for i := range files {
		err = io.ReadSheetHeaderAt(files[i], &hds[i])
		if err != nil { return nil, nil, err }
	}
	return hds, files, nil
}

func dirContents(dir string) ([]string, error) {
	infos, err := ioutil.ReadDir(dir)
	if err != nil { return nil, err }

	files := make([]string, len(infos))
	for i := range infos {
		files[i] = path.Join(dir, infos[i].Name())
	}

	return files, nil
}

func wrapDist(x1, x2, width float32) float32 {
	dist := x1 - x2
	if dist > width / 2 {
		return dist - width
	} else if dist < width / -2 {
		return dist + width
	} else {
		return dist
	}
}

func inRange(x, r, low, width, tw float32) bool {
	return wrapDist(x, low, tw) > -r && wrapDist(x, low + width, tw) < r
}

// SheetIntersect returns true if the given halo and sheet intersect one another
// and false otherwise.
func sheetIntersect(s geom.Sphere, hd *io.SheetHeader) bool {
	tw := float32(hd.TotalWidth)
	return inRange(s.C[0], s.R, hd.Origin[0], hd.Width[0], tw) &&
		inRange(s.C[1], s.R, hd.Origin[1], hd.Width[1], tw) &&
		inRange(s.C[2], s.R, hd.Origin[2], hd.Width[2], tw)
}

func binIntersections(
	hds []io.SheetHeader, spheres []geom.Sphere,
) [][]geom.Sphere {
	bins := make([][]geom.Sphere, len(hds))
	for i := range hds {
		for si := range spheres {
			if sheetIntersect(spheres[si], &hds[i]) {
				bins[i] = append(bins[i], spheres[si])
			}
		}
	}
	return bins
}

func boundingSpheres(
	snap int, hd *io.SheetHeader, ids []int, p *Params,
) ([]geom.Sphere, error) {
	rockstarDir := os.Getenv("GTET_ROCKSTAR_DIR")
	if rockstarDir == "" {
		return nil, fmt.Errorf("$GTET_ROCKSTAR_DIR not set.")
	}

	hlists, err := dirContents(rockstarDir)
	if err != nil { return nil, err }
	rids, vals, err := halo.ReadRockstarVals(
		hlists[snap - 1], &hd.Cosmo, halo.X, halo.Y, halo.Z, halo.Rad200b,
	)
	xs, ys, zs, rs := vals[0], vals[1], vals[2], vals[3]

	spheres := make([]geom.Sphere, len(ids))
	for i := range spheres {
		j := -1
		for idx := range xs {
			if rids[idx] == ids[i] {
				j = idx
				break
			}
		}

		if j == -1 {
			return nil, fmt.Errorf("Halo %d not found in snap %d.",
				ids[i], snap)
		}
		spheres[i].C = geom.Vec{float32(xs[j]), float32(ys[j]), float32(zs[j])}
		spheres[i].R = float32(rs[j])
	}

	return spheres, nil
}

func findOrder(coeffs []float64) int {
	i := 1
	for {
		if 2*i*i == len(coeffs) {
			return i
		} else if 2*i*i > len(coeffs) {
			panic("Impossible")
		}
		i++
	}
}

func wrap(x, tw2 float32) float32 {
	if x > tw2 {
		return x - tw2
	} else if x < -tw2 {
		return x + tw2
	}
	return x
}

func coords(idx, cells int64) (x, y, z int64) {
    x = idx % cells
    y = (idx % (cells * cells)) / cells
    z = idx / (cells * cells)
    return x, y, z
}

func massContained(
	hd *io.SheetHeader, xs []rgeom.Vec, coeffs []float64, sphere geom.Sphere,
) float64 {
	c := &hd.Cosmo
	rhoM := cosmo.RhoAverage(c.H100 * 100, c.OmegaM, c.OmegaL, c.Z )
	dx := hd.TotalWidth / float64(hd.CountWidth) / (1 + c.Z)
	ptMass := rhoM * (dx*dx*dx)
	tw2 := float32(hd.TotalWidth) / 2

	order := findOrder(coeffs)
	shell := analyze.PennaFunc(coeffs, order, order, 2)

	// This prevents excess calls to the shell function:
	low, high := shell.RadialRange(10 * 1000)
	low2, high2 := float32(low*low), float32(high*high)

	sum := 0.0
	sw := hd.SegmentWidth
	for si := int64(0); si < sw*sw*sw; si++ {
		xi, yi, zi := coords(si, hd.SegmentWidth)
		i := xi + yi*sw + zi*sw*sw
		x, y, z := xs[i][0], xs[i][1], xs[i][2]
		x, y, z = x - sphere.C[0], y - sphere.C[1], z - sphere.C[2]
		x = wrap(x, tw2)
		y = wrap(y, tw2)
		z = wrap(z, tw2)

		r2 := x*x + y*y +z*z

		if r2 < low2 || ( r2 < high2 &&
			shell.Contains(float64(x), float64(y), float64(z))) {
			sum += ptMass
		}
	}
	return sum
}

func printMasses(ids, snaps []int, masses []float64) {
	idWidth, snapWidth, massWidth := 0, 0, 0
	for i := range ids {
		iWidth := len(fmt.Sprintf("%d", ids[i]))
		sWidth := len(fmt.Sprintf("%d", snaps[i]))
		mWidth := len(fmt.Sprintf("%.5g", masses[i]))
		if iWidth > idWidth { idWidth = iWidth }
		if sWidth > snapWidth { snapWidth = sWidth }
		if mWidth > massWidth { massWidth = mWidth }
	}

	rowFmt := fmt.Sprintf("%%%dd %%%dd %%%d.5g\n",
		idWidth, snapWidth, massWidth)
	for i := range ids { fmt.Printf(rowFmt, ids[i], snaps[i], masses[i]) }
}
<commit_msg>Removed print statements from gtet_mass.go<commit_after>package main

import (
	"encoding/binary"
	"flag"
	"fmt"
	"log"
	"io/ioutil"
	"os"
	"path"
	"strconv"
	"strings"

	"github.com/phil-mansfield/gotetra/cosmo"
	"github.com/phil-mansfield/gotetra/render/io"
	"github.com/phil-mansfield/gotetra/render/halo"
	rgeom "github.com/phil-mansfield/gotetra/render/geom"
	"github.com/phil-mansfield/gotetra/los/geom"
	"github.com/phil-mansfield/gotetra/los/analyze"
)

type Params struct {
	MaxMult float64
}

func main() {
	p := parseCmd()
	ids, snaps, coeffs, err := parseStdin()
	if err != nil { log.Fatal(err.Error()) }
	snapBins, coeffBins, idxBins := binBySnap(snaps, ids, coeffs)

	masses := make([]float64, len(ids))

	for snap, snapIDs := range snapBins {
		idxs := idxBins[snap]
		snapCoeffs := coeffBins[snap]
		if snap == -1 { continue }

		hds, files, err := readHeaders(snap)
		if err != nil { log.Fatal(err.Error()) }
		hBounds, err := boundingSpheres(snap, &hds[0], snapIDs, p)
		if err != nil { log.Fatal(err.Error()) }
		intrBins := binIntersections(hds, hBounds)

		xs := []rgeom.Vec{}
		for i := range hds {
			if len(intrBins[i]) == 0 { continue }
			hd := &hds[i]

			n := hd.GridWidth*hd.GridWidth*hd.GridWidth
			if len(xs) == 0 { xs = make([]rgeom.Vec, n) }
			err := io.ReadSheetPositionsAt(files[i], xs)
			if err != nil { log.Fatal(err.Error()) }

			for j := range idxs {
				masses[idxs[j]] += massContained(
					&hds[i], xs, snapCoeffs[j], hBounds[j],
				)
			}
		}
	}

	printMasses(ids, snaps, masses)
}

func parseStdin() (ids, snaps []int, coeffs [][]float64, err error) {
	ids, snaps, coeffs = []int{}, []int{}, [][]float64{}
	lines, err := stdinLines()
	if err != nil { return nil, nil, nil, err }
	for i, line := range lines {
		rawTokens := strings.Split(line, " ")
		tokens := make([]string, 0, len(rawTokens))
		for _, tok := range rawTokens {
			if len(tok) != 0 { tokens = append(tokens, tok) }
		}

		var (
			id, snap int
			hCoeffs []float64
			err error
		)
		switch {
		case len(tokens) == 0:
			continue
		case len(tokens) <= 2:
			if tokens[0] == "" { continue }
			return nil, nil, nil, fmt.Errorf(
				"Line %d of stdin has 1 token, but >2 are required.", i + 1,
			)
		case len(tokens) > 2:
			id, err = strconv.Atoi(tokens[0])
			if err != nil {
				return nil, nil, nil, fmt.Errorf(
					"One line %d of stdin, %s does not parse as an int.",
					i + 1, tokens[0],
				)
			}
			snap, err = strconv.Atoi(tokens[1])
			if err != nil {
				return nil, nil, nil, fmt.Errorf(
					"One line %d of stdin, %s does not parse as an int.",
					i + 1, tokens[1],
				)
			}

			hCoeffs = make([]float64, len(tokens) - 2)
			for i := range hCoeffs {
				hCoeffs[i], err = strconv.ParseFloat(tokens[i + 2], 64)
			}
		}

		ids = append(ids, id)
		snaps = append(snaps, snap)
		coeffs = append(coeffs, hCoeffs)
	}

	return ids, snaps, coeffs, nil
}

func stdinLines() ([]string, error) {
	bs, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		return nil, fmt.Errorf(
			"Error reading stdin: %s.", err.Error(),
		)
	}

	text := string(bs)
	return strings.Split(text, "\n"), nil
}

func parseCmd() *Params {
	p := &Params{}
	flag.Float64Var(&p.MaxMult, "MaxMult", 3,
		"Ending radius of LoSs as a multiple of R_200m. " +
			"Should be the same value as used in gtet_shell.")
	flag.Parse()
	return p
}

func binBySnap(
	snaps, ids []int, coeffs [][]float64,
) (snapBins map[int][]int,coeffBins map[int][][]float64,idxBins map[int][]int) {
	snapBins = make(map[int][]int)
	coeffBins = make(map[int][][]float64)
	idxBins = make(map[int][]int)
	for i, snap := range snaps {
		snapBins[snap] = append(snapBins[snap], ids[i])
		coeffBins[snap] = append(coeffBins[snap], coeffs[i])
		idxBins[snap] = append(idxBins[snap], i)
	}
	return snapBins, coeffBins, idxBins
}

func readHeaders(snap int) ([]io.SheetHeader, []string, error) {
	memoDir := os.Getenv("GTET_MEMO_DIR")
	if memoDir == "" {
		// You don't want to memoize? Fine. Deal with the consequences.
		return readHeadersFromSheet(snap)
	}
	if _, err := os.Stat(memoDir); err != nil {
		return nil, nil, err
	}

	memoFile := path.Join(memoDir, fmt.Sprintf("hd_snap%d.dat", snap))

	if _, err := os.Stat(memoFile); err != nil {
		// File not written yet.
		hds, files, err := readHeadersFromSheet(snap)
		if err != nil { return nil, nil, err }

        f, err := os.Create(memoFile)
        if err != nil { return nil, nil, err }
        defer f.Close()
        binary.Write(f, binary.LittleEndian, hds)

		return hds, files, nil
	} else {
		// File exists: read from it instead.

		f, err := os.Open(memoFile)
        if err != nil { return nil, nil, err }
        defer f.Close()

		n, err := sheetNum(snap)
		if err != nil { return nil, nil, err }
		hds := make([]io.SheetHeader, n)
        binary.Read(f, binary.LittleEndian, hds)

		gtetFmt := os.Getenv("GTET_FMT")
		dir := fmt.Sprintf(gtetFmt, snap)
		files, err := dirContents(dir)
		if err != nil { return nil, nil, err }

		return hds, files, nil
	}
}

func sheetNum(snap int) (int, error) {
	gtetFmt := os.Getenv("GTET_FMT")
	dir := fmt.Sprintf(gtetFmt, snap)
	files, err := dirContents(dir)
	if err != nil { return 0, err }
	return len(files), nil
}

func readHeadersFromSheet(snap int) ([]io.SheetHeader, []string, error) {
	gtetFmt := os.Getenv("GTET_FMT")
	dir := fmt.Sprintf(gtetFmt, snap)
	files, err := dirContents(dir)
	if err != nil { return nil, nil, err }

	hds := make([]io.SheetHeader, len(files))
	for i := range files {
		err = io.ReadSheetHeaderAt(files[i], &hds[i])
		if err != nil { return nil, nil, err }
	}
	return hds, files, nil
}

func dirContents(dir string) ([]string, error) {
	infos, err := ioutil.ReadDir(dir)
	if err != nil { return nil, err }

	files := make([]string, len(infos))
	for i := range infos {
		files[i] = path.Join(dir, infos[i].Name())
	}

	return files, nil
}

func wrapDist(x1, x2, width float32) float32 {
	dist := x1 - x2
	if dist > width / 2 {
		return dist - width
	} else if dist < width / -2 {
		return dist + width
	} else {
		return dist
	}
}

func inRange(x, r, low, width, tw float32) bool {
	return wrapDist(x, low, tw) > -r && wrapDist(x, low + width, tw) < r
}

// SheetIntersect returns true if the given halo and sheet intersect one another
// and false otherwise.
func sheetIntersect(s geom.Sphere, hd *io.SheetHeader) bool {
	tw := float32(hd.TotalWidth)
	return inRange(s.C[0], s.R, hd.Origin[0], hd.Width[0], tw) &&
		inRange(s.C[1], s.R, hd.Origin[1], hd.Width[1], tw) &&
		inRange(s.C[2], s.R, hd.Origin[2], hd.Width[2], tw)
}

func binIntersections(
	hds []io.SheetHeader, spheres []geom.Sphere,
) [][]geom.Sphere {
	bins := make([][]geom.Sphere, len(hds))
	for i := range hds {
		for si := range spheres {
			if sheetIntersect(spheres[si], &hds[i]) {
				bins[i] = append(bins[i], spheres[si])
			}
		}
	}
	return bins
}

func boundingSpheres(
	snap int, hd *io.SheetHeader, ids []int, p *Params,
) ([]geom.Sphere, error) {
	rockstarDir := os.Getenv("GTET_ROCKSTAR_DIR")
	if rockstarDir == "" {
		return nil, fmt.Errorf("$GTET_ROCKSTAR_DIR not set.")
	}

	hlists, err := dirContents(rockstarDir)
	if err != nil { return nil, err }
	rids, vals, err := halo.ReadRockstarVals(
		hlists[snap - 1], &hd.Cosmo, halo.X, halo.Y, halo.Z, halo.Rad200b,
	)
	xs, ys, zs, rs := vals[0], vals[1], vals[2], vals[3]

	spheres := make([]geom.Sphere, len(ids))
	for i := range spheres {
		j := -1
		for idx := range xs {
			if rids[idx] == ids[i] {
				j = idx
				break
			}
		}

		if j == -1 {
			return nil, fmt.Errorf("Halo %d not found in snap %d.",
				ids[i], snap)
		}
		spheres[i].C = geom.Vec{float32(xs[j]), float32(ys[j]), float32(zs[j])}
		spheres[i].R = float32(rs[j])
	}

	return spheres, nil
}

func findOrder(coeffs []float64) int {
	i := 1
	for {
		if 2*i*i == len(coeffs) {
			return i
		} else if 2*i*i > len(coeffs) {
			panic("Impossible")
		}
		i++
	}
}

func wrap(x, tw2 float32) float32 {
	if x > tw2 {
		return x - tw2
	} else if x < -tw2 {
		return x + tw2
	}
	return x
}

func coords(idx, cells int64) (x, y, z int64) {
    x = idx % cells
    y = (idx % (cells * cells)) / cells
    z = idx / (cells * cells)
    return x, y, z
}

func massContained(
	hd *io.SheetHeader, xs []rgeom.Vec, coeffs []float64, sphere geom.Sphere,
) float64 {
	c := &hd.Cosmo
	rhoM := cosmo.RhoAverage(c.H100 * 100, c.OmegaM, c.OmegaL, c.Z )
	dx := hd.TotalWidth / float64(hd.CountWidth) / (1 + c.Z)
	ptMass := rhoM * (dx*dx*dx)
	tw2 := float32(hd.TotalWidth) / 2

	order := findOrder(coeffs)
	shell := analyze.PennaFunc(coeffs, order, order, 2)

	// This prevents excess calls to the shell function:
	low, high := shell.RadialRange(10 * 1000)
	low2, high2 := float32(low*low), float32(high*high)

	sum := 0.0
	sw := hd.SegmentWidth
	for si := int64(0); si < sw*sw*sw; si++ {
		xi, yi, zi := coords(si, hd.SegmentWidth)
		i := xi + yi*sw + zi*sw*sw
		x, y, z := xs[i][0], xs[i][1], xs[i][2]
		x, y, z = x - sphere.C[0], y - sphere.C[1], z - sphere.C[2]
		x = wrap(x, tw2)
		y = wrap(y, tw2)
		z = wrap(z, tw2)

		r2 := x*x + y*y +z*z

		if r2 < low2 || ( r2 < high2 &&
			shell.Contains(float64(x), float64(y), float64(z))) {
			sum += ptMass
		}
	}
	return sum
}

func printMasses(ids, snaps []int, masses []float64) {
	idWidth, snapWidth, massWidth := 0, 0, 0
	for i := range ids {
		iWidth := len(fmt.Sprintf("%d", ids[i]))
		sWidth := len(fmt.Sprintf("%d", snaps[i]))
		mWidth := len(fmt.Sprintf("%.5g", masses[i]))
		if iWidth > idWidth { idWidth = iWidth }
		if sWidth > snapWidth { snapWidth = sWidth }
		if mWidth > massWidth { massWidth = mWidth }
	}

	rowFmt := fmt.Sprintf("%%%dd %%%dd %%%d.5g\n",
		idWidth, snapWidth, massWidth)
	for i := range ids { fmt.Printf(rowFmt, ids[i], snaps[i], masses[i]) }
}
<|endoftext|>


<commit_before>package api_v1

import (
	"time"

	. "github.com/ilius/ripo"
	"gopkg.in/mgo.v2/bson"

	"scal"
	"scal/event_lib"
	//"scal/settings"
	"scal/storage"
	. "scal/user_lib"
)

func init() {
	routeGroups = append(routeGroups, RouteGroup{
		Base: "user",
		Map: RouteMap{
			"SetUserFullName": {
				Method:  "PUT",
				Pattern: "full-name",
				Handler: SetUserFullName,
			},
			"UnsetUserFullName": {
				Method:  "DELETE",
				Pattern: "full-name",
				Handler: UnsetUserFullName,
			},
			"GetUserInfo": {
				Method:  "GET",
				Pattern: "info",
				Handler: GetUserInfo,
			},
			"SetUserDefaultGroupId": {
				Method:  "PUT",
				Pattern: "default-group",
				Handler: SetUserDefaultGroupId,
			},
			"UnsetUserDefaultGroupId": {
				Method:  "DELETE",
				Pattern: "default-group",
				Handler: UnsetUserDefaultGroupId,
			},
		},
	})
}

func SetUserFullName(req Request) (*Response, error) {
	userModel, err := CheckAuth(req)
	if err != nil {
		return nil, err
	}
	email := userModel.Email
	failed, unlock := resLock.User(email)
	if failed {
		return nil, NewError(ResourceLocked, "user is being modified by another request", err)
	}
	defer unlock()
	// -----------------------------------------------
	const attrName = "fullName"
	// -----------------------------------------------
	remoteIp, err := req.RemoteIP()
	if err != nil {
		return nil, err
	}

	db, err := storage.GetDB()
	if err != nil {
		return nil, NewError(Unavailable, "", err)
	}

	attrValue, err := req.GetString(attrName)
	if err != nil {
		return nil, err
	}

	err = db.Insert(UserChangeLogModel{
		Time:         time.Now(),
		RequestEmail: email,
		RemoteIp:     remoteIp,
		FuncName:     "SetUserFullName",
		FullName: &[2]*string{
			&userModel.FullName,
			attrValue,
		},
	})
	if err != nil {
		return nil, NewError(Internal, "", err)
	}

	userModel.FullName = *attrValue
	err = db.Update(userModel)
	if err != nil {
		return nil, NewError(Internal, "", err)
	}

	return &Response{}, nil
}

func UnsetUserFullName(req Request) (*Response, error) {
	userModel, err := CheckAuth(req)
	if err != nil {
		return nil, err
	}
	email := userModel.Email
	failed, unlock := resLock.User(email)
	if failed {
		return nil, NewError(ResourceLocked, "user is being modified by another request", err)
	}
	defer unlock()
	// -----------------------------------------------
	remoteIp, err := req.RemoteIP()
	if err != nil {
		return nil, err
	}

	db, err := storage.GetDB()
	if err != nil {
		return nil, NewError(Unavailable, "", err)
	}

	err = db.Insert(UserChangeLogModel{
		Time:         time.Now(),
		RequestEmail: email,
		RemoteIp:     remoteIp,
		FuncName:     "UnsetUserFullName",
		FullName: &[2]*string{
			&userModel.FullName,
			nil,
		},
	})
	if err != nil {
		return nil, NewError(Internal, "", err)
	}

	userModel.FullName = ""
	err = db.Update(userModel)
	if err != nil {
		return nil, NewError(Internal, "", err)
	}

	return &Response{}, nil
}

func SetUserDefaultGroupId(req Request) (*Response, error) {
	userModel, err := CheckAuth(req)
	if err != nil {
		return nil, err
	}
	email := userModel.Email
	failed, unlock := resLock.User(email)
	if failed {
		return nil, NewError(ResourceLocked, "user is being modified by another request", err)
	}
	defer unlock()
	// -----------------------------------------------
	const attrName = "defaultGroupId"
	// -----------------------------------------------
	remoteIp, err := req.RemoteIP()
	if err != nil {
		return nil, err
	}

	db, err := storage.GetDB()
	if err != nil {
		return nil, NewError(Unavailable, "", err)
	}

	attrValue, err := req.GetString(attrName)
	if err != nil {
		return nil, err
	}

	groupModel, err := event_lib.LoadGroupModelByIdHex(
		"defaultGroupId",
		db,
		*attrValue,
	)
	if err != nil {
		return nil, err
	}
	groupId := groupModel.Id

	if groupModel.OwnerEmail != email {
		return nil, NewError(InvalidArgument, "invalid 'defaultGroupId'", nil)
	}

	err = db.Insert(UserChangeLogModel{
		Time:         time.Now(),
		RequestEmail: email,
		RemoteIp:     remoteIp,
		FuncName:     "SetUserDefaultGroupId",
		DefaultGroupId: &[2]*bson.ObjectId{
			userModel.DefaultGroupId,
			&groupId,
		},
	})
	if err != nil {
		return nil, NewError(Internal, "", err)
	}

	userModel.DefaultGroupId = &groupId
	err = db.Update(userModel)
	if err != nil {
		return nil, NewError(Internal, "", err)
	}

	return &Response{}, nil
}

func UnsetUserDefaultGroupId(req Request) (*Response, error) {
	userModel, err := CheckAuth(req)
	if err != nil {
		return nil, err
	}
	email := userModel.Email
	failed, unlock := resLock.User(email)
	if failed {
		return nil, NewError(ResourceLocked, "user is being modified by another request", err)
	}
	defer unlock()
	// -----------------------------------------------
	remoteIp, err := req.RemoteIP()
	if err != nil {
		return nil, err
	}

	db, err := storage.GetDB()
	if err != nil {
		return nil, NewError(Unavailable, "", err)
	}

	err = db.Insert(UserChangeLogModel{
		Time:         time.Now(),
		RequestEmail: email,
		RemoteIp:     remoteIp,
		FuncName:     "UnsetUserDefaultGroupId",
		DefaultGroupId: &[2]*bson.ObjectId{
			userModel.DefaultGroupId,
			nil,
		},
	})
	if err != nil {
		return nil, NewError(Internal, "", err)
	}

	userModel.DefaultGroupId = nil
	err = db.Update(userModel)
	if err != nil {
		return nil, NewError(Internal, "", err)
	}

	return &Response{}, nil
}

func GetUserInfo(req Request) (*Response, error) {
	userModel, err := CheckAuth(req)
	if err != nil {
		return nil, err
	}
	email := userModel.Email
	// -----------------------------------------------
	return &Response{
		Data: scal.M{
			"email":          email,
			"fullName":       userModel.FullName,
			"defaultGroupId": userModel.DefaultGroupId,
			//"locked": userModel.Locked,
			"lastLogoutTime": userModel.LastLogoutTime,
			"emailConfirmed": userModel.EmailConfirmed,
		},
	}, nil
}
<commit_msg>fmt: user_handlers.go<commit_after>package api_v1

import (
	"scal"
	"scal/event_lib"
	"time"

	. "github.com/ilius/ripo"
	"gopkg.in/mgo.v2/bson"

	//"scal/settings"
	"scal/storage"
	. "scal/user_lib"
)

func init() {
	routeGroups = append(routeGroups, RouteGroup{
		Base: "user",
		Map: RouteMap{
			"SetUserFullName": {
				Method:  "PUT",
				Pattern: "full-name",
				Handler: SetUserFullName,
			},
			"UnsetUserFullName": {
				Method:  "DELETE",
				Pattern: "full-name",
				Handler: UnsetUserFullName,
			},
			"GetUserInfo": {
				Method:  "GET",
				Pattern: "info",
				Handler: GetUserInfo,
			},
			"SetUserDefaultGroupId": {
				Method:  "PUT",
				Pattern: "default-group",
				Handler: SetUserDefaultGroupId,
			},
			"UnsetUserDefaultGroupId": {
				Method:  "DELETE",
				Pattern: "default-group",
				Handler: UnsetUserDefaultGroupId,
			},
		},
	})
}

func SetUserFullName(req Request) (*Response, error) {
	userModel, err := CheckAuth(req)
	if err != nil {
		return nil, err
	}
	email := userModel.Email
	failed, unlock := resLock.User(email)
	if failed {
		return nil, NewError(ResourceLocked, "user is being modified by another request", err)
	}
	defer unlock()
	// -----------------------------------------------
	const attrName = "fullName"
	// -----------------------------------------------
	remoteIp, err := req.RemoteIP()
	if err != nil {
		return nil, err
	}

	db, err := storage.GetDB()
	if err != nil {
		return nil, NewError(Unavailable, "", err)
	}

	attrValue, err := req.GetString(attrName)
	if err != nil {
		return nil, err
	}

	err = db.Insert(UserChangeLogModel{
		Time:         time.Now(),
		RequestEmail: email,
		RemoteIp:     remoteIp,
		FuncName:     "SetUserFullName",
		FullName: &[2]*string{
			&userModel.FullName,
			attrValue,
		},
	})
	if err != nil {
		return nil, NewError(Internal, "", err)
	}

	userModel.FullName = *attrValue
	err = db.Update(userModel)
	if err != nil {
		return nil, NewError(Internal, "", err)
	}

	return &Response{}, nil
}

func UnsetUserFullName(req Request) (*Response, error) {
	userModel, err := CheckAuth(req)
	if err != nil {
		return nil, err
	}
	email := userModel.Email
	failed, unlock := resLock.User(email)
	if failed {
		return nil, NewError(ResourceLocked, "user is being modified by another request", err)
	}
	defer unlock()
	// -----------------------------------------------
	remoteIp, err := req.RemoteIP()
	if err != nil {
		return nil, err
	}

	db, err := storage.GetDB()
	if err != nil {
		return nil, NewError(Unavailable, "", err)
	}

	err = db.Insert(UserChangeLogModel{
		Time:         time.Now(),
		RequestEmail: email,
		RemoteIp:     remoteIp,
		FuncName:     "UnsetUserFullName",
		FullName: &[2]*string{
			&userModel.FullName,
			nil,
		},
	})
	if err != nil {
		return nil, NewError(Internal, "", err)
	}

	userModel.FullName = ""
	err = db.Update(userModel)
	if err != nil {
		return nil, NewError(Internal, "", err)
	}

	return &Response{}, nil
}

func SetUserDefaultGroupId(req Request) (*Response, error) {
	userModel, err := CheckAuth(req)
	if err != nil {
		return nil, err
	}
	email := userModel.Email
	failed, unlock := resLock.User(email)
	if failed {
		return nil, NewError(ResourceLocked, "user is being modified by another request", err)
	}
	defer unlock()
	// -----------------------------------------------
	const attrName = "defaultGroupId"
	// -----------------------------------------------
	remoteIp, err := req.RemoteIP()
	if err != nil {
		return nil, err
	}

	db, err := storage.GetDB()
	if err != nil {
		return nil, NewError(Unavailable, "", err)
	}

	attrValue, err := req.GetString(attrName)
	if err != nil {
		return nil, err
	}

	groupModel, err := event_lib.LoadGroupModelByIdHex(
		"defaultGroupId",
		db,
		*attrValue,
	)
	if err != nil {
		return nil, err
	}
	groupId := groupModel.Id

	if groupModel.OwnerEmail != email {
		return nil, NewError(InvalidArgument, "invalid 'defaultGroupId'", nil)
	}

	err = db.Insert(UserChangeLogModel{
		Time:         time.Now(),
		RequestEmail: email,
		RemoteIp:     remoteIp,
		FuncName:     "SetUserDefaultGroupId",
		DefaultGroupId: &[2]*bson.ObjectId{
			userModel.DefaultGroupId,
			&groupId,
		},
	})
	if err != nil {
		return nil, NewError(Internal, "", err)
	}

	userModel.DefaultGroupId = &groupId
	err = db.Update(userModel)
	if err != nil {
		return nil, NewError(Internal, "", err)
	}

	return &Response{}, nil
}

func UnsetUserDefaultGroupId(req Request) (*Response, error) {
	userModel, err := CheckAuth(req)
	if err != nil {
		return nil, err
	}
	email := userModel.Email
	failed, unlock := resLock.User(email)
	if failed {
		return nil, NewError(ResourceLocked, "user is being modified by another request", err)
	}
	defer unlock()
	// -----------------------------------------------
	remoteIp, err := req.RemoteIP()
	if err != nil {
		return nil, err
	}

	db, err := storage.GetDB()
	if err != nil {
		return nil, NewError(Unavailable, "", err)
	}

	err = db.Insert(UserChangeLogModel{
		Time:         time.Now(),
		RequestEmail: email,
		RemoteIp:     remoteIp,
		FuncName:     "UnsetUserDefaultGroupId",
		DefaultGroupId: &[2]*bson.ObjectId{
			userModel.DefaultGroupId,
			nil,
		},
	})
	if err != nil {
		return nil, NewError(Internal, "", err)
	}

	userModel.DefaultGroupId = nil
	err = db.Update(userModel)
	if err != nil {
		return nil, NewError(Internal, "", err)
	}

	return &Response{}, nil
}

func GetUserInfo(req Request) (*Response, error) {
	userModel, err := CheckAuth(req)
	if err != nil {
		return nil, err
	}
	email := userModel.Email
	// -----------------------------------------------
	return &Response{
		Data: scal.M{
			"email":          email,
			"fullName":       userModel.FullName,
			"defaultGroupId": userModel.DefaultGroupId,
			//"locked": userModel.Locked,
			"lastLogoutTime": userModel.LastLogoutTime,
			"emailConfirmed": userModel.EmailConfirmed,
		},
	}, nil
}
<|endoftext|>


<commit_before>package fuse

import (
	"bytes"
	"errors"
	"fmt"
	"net"
	"os"
	"os/exec"
	"syscall"

	"golang.org/x/sys/unix"
)

func fusermount(dir string, cfg *MountConfig) (*os.File, error) {
	// Create a socket pair.
	fds, err := syscall.Socketpair(syscall.AF_FILE, syscall.SOCK_STREAM, 0)
	if err != nil {
		return nil, fmt.Errorf("Socketpair: %v", err)
	}

	// Wrap the sockets into os.File objects that we will pass off to fusermount.
	writeFile := os.NewFile(uintptr(fds[0]), "fusermount-child-writes")
	defer writeFile.Close()

	readFile := os.NewFile(uintptr(fds[1]), "fusermount-parent-reads")
	defer readFile.Close()

	// Start fusermount, passing it a buffer in which to write stderr.
	var stderr bytes.Buffer

	cmd := exec.Command(
		"fusermount",
		"-o", cfg.toOptionsString(),
		"--",
		dir,
	)

	cmd.Env = append(os.Environ(), "_FUSE_COMMFD=3")
	cmd.ExtraFiles = []*os.File{writeFile}
	cmd.Stderr = &stderr

	// Run the command.
	err = cmd.Run()
	if err != nil {
		return nil, fmt.Errorf("running fusermount: %v\n\nstderr:\n%s", err, stderr.Bytes())
	}

	// Wrap the socket file in a connection.
	c, err := net.FileConn(readFile)
	if err != nil {
		return nil, fmt.Errorf("FileConn: %v", err)
	}
	defer c.Close()

	// We expect to have a Unix domain socket.
	uc, ok := c.(*net.UnixConn)
	if !ok {
		return nil, fmt.Errorf("Expected UnixConn, got %T", c)
	}

	// Read a message.
	buf := make([]byte, 32) // expect 1 byte
	oob := make([]byte, 32) // expect 24 bytes
	_, oobn, _, _, err := uc.ReadMsgUnix(buf, oob)
	if err != nil {
		return nil, fmt.Errorf("ReadMsgUnix: %v", err)
	}

	// Parse the message.
	scms, err := syscall.ParseSocketControlMessage(oob[:oobn])
	if err != nil {
		return nil, fmt.Errorf("ParseSocketControlMessage: %v", err)
	}

	// We expect one message.
	if len(scms) != 1 {
		return nil, fmt.Errorf("expected 1 SocketControlMessage; got scms = %#v", scms)
	}

	scm := scms[0]

	// Pull out the FD returned by fusermount
	gotFds, err := syscall.ParseUnixRights(&scm)
	if err != nil {
		return nil, fmt.Errorf("syscall.ParseUnixRights: %v", err)
	}

	if len(gotFds) != 1 {
		return nil, fmt.Errorf("wanted 1 fd; got %#v", gotFds)
	}

	// Turn the FD into an os.File.
	return os.NewFile(uintptr(gotFds[0]), "/dev/fuse"), nil
}

func enableFunc(flag uintptr) func(uintptr) uintptr {
	return func(v uintptr) uintptr {
		return v | flag
	}
}

func disableFunc(flag uintptr) func(uintptr) uintptr {
	return func(v uintptr) uintptr {
		return v &^ flag
	}
}

// As per libfuse/fusermount.c:602: https://bit.ly/2SgtWYM#L602
var mountflagopts = map[string]func(uintptr) uintptr{
	"rw":      enableFunc(unix.MS_RDONLY),
	"ro":      disableFunc(unix.MS_RDONLY),
	"suid":    disableFunc(unix.MS_NOSUID),
	"nosuid":  enableFunc(unix.MS_NOSUID),
	"dev":     disableFunc(unix.MS_NODEV),
	"nodev":   enableFunc(unix.MS_NODEV),
	"exec":    disableFunc(unix.MS_NOEXEC),
	"noexec":  enableFunc(unix.MS_NOEXEC),
	"async":   disableFunc(unix.MS_SYNCHRONOUS),
	"sync":    enableFunc(unix.MS_SYNCHRONOUS),
	"atime":   disableFunc(unix.MS_NOATIME),
	"noatime": enableFunc(unix.MS_NOATIME),
	"dirsync": enableFunc(unix.MS_DIRSYNC),
}

var errFallback = errors.New("sentinel: fallback to fusermount(1)")

func directmount(dir string, cfg *MountConfig) (*os.File, error) {
	// We use syscall.Open + os.NewFile instead of os.OpenFile so that the file
	// is opened in blocking mode. When opened in non-blocking mode, the Go
	// runtime tries to use poll(2), which does not work with /dev/fuse.
	fd, err := syscall.Open("/dev/fuse", syscall.O_RDWR, 0644)
	if err != nil {
		return nil, errFallback
	}
	dev := os.NewFile(uintptr(fd), "/dev/fuse")
	// As per libfuse/fusermount.c:847: https://bit.ly/2SgtWYM#L847
	data := fmt.Sprintf("fd=%d,rootmode=40000,user_id=%d,group_id=%d",
		dev.Fd(), os.Getuid(), os.Getgid())
	// As per libfuse/fusermount.c:749: https://bit.ly/2SgtWYM#L749
	mountflag := uintptr(unix.MS_NODEV | unix.MS_NOSUID)
	opts := cfg.toMap()
	for k := range opts {
		fn, ok := mountflagopts[k]
		if !ok {
			continue
		}
		mountflag = fn(mountflag)
		delete(opts, k)
	}
	delete(opts, "fsname") // handled via fstype mount(2) parameter
	data += "," + mapToOptionsString(opts)
	if err := unix.Mount(
		cfg.FSName, // source
		dir,        // target
		"fuse",     // fstype
		mountflag,  // mountflag
		data,       // data
	); err != nil {
		if err == syscall.EPERM {
			return nil, errFallback

		}
		return nil, err
	}
	return dev, nil
}

// Begin the process of mounting at the given directory, returning a connection
// to the kernel. Mounting continues in the background, and is complete when an
// error is written to the supplied channel. The file system may need to
// service the connection in order for mounting to complete.
func mount(dir string, cfg *MountConfig, ready chan<- error) (*os.File, error) {
	// On linux, mounting is never delayed.
	ready <- nil

	// Try mounting without fusermount(1) first: we might be running as root or
	// have the CAP_SYS_ADMIN capability.
	dev, err := directmount(dir, cfg)
	if err == errFallback {
		return fusermount(dir, cfg)
	}
	return dev, err
}
<commit_msg>make fstype be composed of "fuse" and subtype (#77)<commit_after>package fuse

import (
	"bytes"
	"errors"
	"fmt"
	"net"
	"os"
	"os/exec"
	"syscall"

	"golang.org/x/sys/unix"
)

func fusermount(dir string, cfg *MountConfig) (*os.File, error) {
	// Create a socket pair.
	fds, err := syscall.Socketpair(syscall.AF_FILE, syscall.SOCK_STREAM, 0)
	if err != nil {
		return nil, fmt.Errorf("Socketpair: %v", err)
	}

	// Wrap the sockets into os.File objects that we will pass off to fusermount.
	writeFile := os.NewFile(uintptr(fds[0]), "fusermount-child-writes")
	defer writeFile.Close()

	readFile := os.NewFile(uintptr(fds[1]), "fusermount-parent-reads")
	defer readFile.Close()

	// Start fusermount, passing it a buffer in which to write stderr.
	var stderr bytes.Buffer

	cmd := exec.Command(
		"fusermount",
		"-o", cfg.toOptionsString(),
		"--",
		dir,
	)

	cmd.Env = append(os.Environ(), "_FUSE_COMMFD=3")
	cmd.ExtraFiles = []*os.File{writeFile}
	cmd.Stderr = &stderr

	// Run the command.
	err = cmd.Run()
	if err != nil {
		return nil, fmt.Errorf("running fusermount: %v\n\nstderr:\n%s", err, stderr.Bytes())
	}

	// Wrap the socket file in a connection.
	c, err := net.FileConn(readFile)
	if err != nil {
		return nil, fmt.Errorf("FileConn: %v", err)
	}
	defer c.Close()

	// We expect to have a Unix domain socket.
	uc, ok := c.(*net.UnixConn)
	if !ok {
		return nil, fmt.Errorf("Expected UnixConn, got %T", c)
	}

	// Read a message.
	buf := make([]byte, 32) // expect 1 byte
	oob := make([]byte, 32) // expect 24 bytes
	_, oobn, _, _, err := uc.ReadMsgUnix(buf, oob)
	if err != nil {
		return nil, fmt.Errorf("ReadMsgUnix: %v", err)
	}

	// Parse the message.
	scms, err := syscall.ParseSocketControlMessage(oob[:oobn])
	if err != nil {
		return nil, fmt.Errorf("ParseSocketControlMessage: %v", err)
	}

	// We expect one message.
	if len(scms) != 1 {
		return nil, fmt.Errorf("expected 1 SocketControlMessage; got scms = %#v", scms)
	}

	scm := scms[0]

	// Pull out the FD returned by fusermount
	gotFds, err := syscall.ParseUnixRights(&scm)
	if err != nil {
		return nil, fmt.Errorf("syscall.ParseUnixRights: %v", err)
	}

	if len(gotFds) != 1 {
		return nil, fmt.Errorf("wanted 1 fd; got %#v", gotFds)
	}

	// Turn the FD into an os.File.
	return os.NewFile(uintptr(gotFds[0]), "/dev/fuse"), nil
}

func enableFunc(flag uintptr) func(uintptr) uintptr {
	return func(v uintptr) uintptr {
		return v | flag
	}
}

func disableFunc(flag uintptr) func(uintptr) uintptr {
	return func(v uintptr) uintptr {
		return v &^ flag
	}
}

// As per libfuse/fusermount.c:602: https://bit.ly/2SgtWYM#L602
var mountflagopts = map[string]func(uintptr) uintptr{
	"rw":      enableFunc(unix.MS_RDONLY),
	"ro":      disableFunc(unix.MS_RDONLY),
	"suid":    disableFunc(unix.MS_NOSUID),
	"nosuid":  enableFunc(unix.MS_NOSUID),
	"dev":     disableFunc(unix.MS_NODEV),
	"nodev":   enableFunc(unix.MS_NODEV),
	"exec":    disableFunc(unix.MS_NOEXEC),
	"noexec":  enableFunc(unix.MS_NOEXEC),
	"async":   disableFunc(unix.MS_SYNCHRONOUS),
	"sync":    enableFunc(unix.MS_SYNCHRONOUS),
	"atime":   disableFunc(unix.MS_NOATIME),
	"noatime": enableFunc(unix.MS_NOATIME),
	"dirsync": enableFunc(unix.MS_DIRSYNC),
}

var errFallback = errors.New("sentinel: fallback to fusermount(1)")

func directmount(dir string, cfg *MountConfig) (*os.File, error) {
	// We use syscall.Open + os.NewFile instead of os.OpenFile so that the file
	// is opened in blocking mode. When opened in non-blocking mode, the Go
	// runtime tries to use poll(2), which does not work with /dev/fuse.
	fd, err := syscall.Open("/dev/fuse", syscall.O_RDWR, 0644)
	if err != nil {
		return nil, errFallback
	}
	dev := os.NewFile(uintptr(fd), "/dev/fuse")
	// As per libfuse/fusermount.c:847: https://bit.ly/2SgtWYM#L847
	data := fmt.Sprintf("fd=%d,rootmode=40000,user_id=%d,group_id=%d",
		dev.Fd(), os.Getuid(), os.Getgid())
	// As per libfuse/fusermount.c:749: https://bit.ly/2SgtWYM#L749
	mountflag := uintptr(unix.MS_NODEV | unix.MS_NOSUID)
	opts := cfg.toMap()
	for k := range opts {
		fn, ok := mountflagopts[k]
		if !ok {
			continue
		}
		mountflag = fn(mountflag)
		delete(opts, k)
	}
	delete(opts, "fsname") // handled via fstype mount(2) parameter
	fstype := "fuse"
	if subtype, ok := opts["subtype"]; ok {
		fstype += "." + subtype
	}
	delete(opts, "subtype")
	data += "," + mapToOptionsString(opts)
	if err := unix.Mount(
		cfg.FSName, // source
		dir,        // target
		fstype,     // fstype
		mountflag,  // mountflag
		data,       // data
	); err != nil {
		if err == syscall.EPERM {
			return nil, errFallback

		}
		return nil, err
	}
	return dev, nil
}

// Begin the process of mounting at the given directory, returning a connection
// to the kernel. Mounting continues in the background, and is complete when an
// error is written to the supplied channel. The file system may need to
// service the connection in order for mounting to complete.
func mount(dir string, cfg *MountConfig, ready chan<- error) (*os.File, error) {
	// On linux, mounting is never delayed.
	ready <- nil

	// Try mounting without fusermount(1) first: we might be running as root or
	// have the CAP_SYS_ADMIN capability.
	dev, err := directmount(dir, cfg)
	if err == errFallback {
		return fusermount(dir, cfg)
	}
	return dev, err
}
<|endoftext|>


<commit_before>package mpdb

import (
	"database/sql"
	"github.com/kierdavis/mealplanner/mpdata"
	"log"
	"time"
)

// SQL statements to delete tables.
var DeleteTablesSQLs = []string{
	"DROP TABLE IF EXISTS meal",
	"DROP TABLE IF EXISTS tag",
	"DROP TABLE IF EXISTS mealplan",
	"DROP TABLE IF EXISTS serving",
}

// SQL statements to create tables.
var CreateTablesSQLs = []string{
	"CREATE TABLE IF NOT EXISTS meal ( " +
		"id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, " +
		"name VARCHAR(255) NOT NULL, " +
		"recipe TEXT, " +
		"favourite BOOLEAN NOT NULL, " +
		"PRIMARY KEY (id) " +
		")",
	"CREATE TABLE IF NOT EXISTS tag ( " +
		"mealid BIGINT UNSIGNED NOT NULL, " +
		"tag VARCHAR(64) NOT NULL, " +
		"PRIMARY KEY (mealid, tag) " +
		")",
	"CREATE TABLE IF NOT EXISTS mealplan ( " +
		"id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, " +
		"notes TEXT, " +
		"startdate DATE NOT NULL, " +
		"enddate DATE NOT NULL, " +
		"PRIMARY KEY (id) " +
		")",
	"CREATE TABLE IF NOT EXISTS serving ( " +
		"mealplanid BIGINT UNSIGNED NOT NULL, " +
		"dateserved DATE NOT NULL, " +
		"mealid BIGINT UNSIGNED NOT NULL, " +
		"PRIMARY KEY (mealplanid, dateserved) " +
		")",
}

// SQL statements to clear tables.
var ClearTablesSQLs = []string{
	"DELETE FROM meal",
	"DELETE FROM tag",
	"DELETE FROM mealplan",
	"DELETE FROM serving",
}

// execList runs a list of SQL statements, discarding the results.
func execList(q Queryable, queries []string) (err error) {
	for _, query := range queries {
		_, err = q.Exec(query)
		if err != nil {
			return err
		}
	}

	return nil
}

// DeleteTables drops the database tables if they exist.
func DeleteTables(q Queryable) (err error) {
	return execList(q, DeleteTablesSQLs)
}

// CreateTables creates the database tables if they do not exist.
func CreateTables(q Queryable) (err error) {
	return execList(q, CreateTablesSQLs)
}

func InitialiseVersion(q Queryable, debug bool) (err error) {
	var version uint
	err = q.QueryRow("SELECT version FROM version").Scan(&version)
	isNTE := isNonexistentTableError(err)

	if err == nil { // All is fine.
		if debug {
			log.Printf("Version check: OK, current version is %d\n", version)
		}
		return nil

	} else if isNTE || err == sql.ErrNoRows { // No version set.
		if debug {
			log.Printf("Version check: version not set yet\n")
		}

		if isNTE { // 'version' table does not exist.
			if debug {
				log.Printf("Version check: creating version table\n")
			}
			_, err = q.Exec("CREATE TABLE version (version INT UNSIGNED NOT NULL)")
			if err != nil {
				return err
			}
		}

		// Check if other tables exist.
		_, err = q.Exec("SELECT meal.id FROM meal LIMIT 1")
		if err == nil { // Table 'meal' exists.
			if debug {
				log.Printf("Version check: assuming first startup since introduction of versioning\n")
			}
			version = 0

		} else if isNonexistentTableError(err) { // Table 'meal' does not exist.
			if debug {
				log.Printf("Version check: assuming empty database\n")
			}
			version = LatestVersion

		} else { // Unknown error.
			return err
		}

	} else { // Unknown error.
		return err
	}

	if debug {
		log.Printf("Version check: setting version to %d\n", version)
	}
	_, err = q.Exec("INSERT INTO version VALUES (?)", version)
	return err
}

// ClearTables deletes all records from the entire database.
func ClearTables(q Queryable) (err error) {
	return execList(q, ClearTablesSQLs)
}

// InitDB creates the database tables if they don't exist. If 'debug' is true,
// debug messages are printed. If 'testData' is true, the tables are also
// cleared and test data are added to them.
func InitDB(debug bool, testData bool) (err error) {
	return WithConnection(func(db *sql.DB) (err error) {
		return WithTransaction(db, func(tx *sql.Tx) (err error) {
			err = InitialiseVersion(tx, debug)
			if err != nil {
				return err
			}

			err = CreateTables(tx)
			if err != nil {
				return err
			}

			err = Migrate(tx, LatestVersion, debug)
			if err != nil {
				return err
			}

			if testData {
				if debug {
					log.Printf("Clearing database and inserting test data.\n")
				}

				err = ClearTables(tx)
				if err != nil {
					return err
				}

				err = InsertTestData(tx)
				if err != nil {
					return err
				}
			}

			return nil
		})
	})
}

// InsertTestData inserts some predefined meals and meal plans into the
// database for testing purposes.
func InsertTestData(q Queryable) (err error) {
	err = AddMealWithTags(q, mpdata.MealWithTags{
		Meal: &mpdata.Meal{
			Name:      "Chilli con carne",
			RecipeURL: "http://example.net/chilli",
			Favourite: false,
		},
		Tags: []string{
			"spicy",
			"lentil",
			"rice",
		},
	})

	if err != nil {
		return err
	}

	err = AddMealWithTags(q, mpdata.MealWithTags{
		Meal: &mpdata.Meal{
			Name:      "Carrot and lentil soup",
			RecipeURL: "http://example.net/soup",
			Favourite: false,
		},
		Tags: []string{
			"lentil",
			"soup",
			"quick",
		},
	})

	if err != nil {
		return err
	}

	err = AddMealWithTags(q, mpdata.MealWithTags{
		Meal: &mpdata.Meal{
			Name:      "Nachos",
			RecipeURL: "http://example.net/nachos",
			Favourite: true,
		},
		Tags: []string{
			"spicy",
			"mexican",
		},
	})

	if err != nil {
		return err
	}

	mp1 := &mpdata.MealPlan{
		Notes:     "some notes",
		StartDate: time.Date(2014, time.January, 25, 0, 0, 0, 0, time.UTC),
		EndDate:   time.Date(2014, time.February, 4, 0, 0, 0, 0, time.UTC),
	}

	err = AddMealPlan(q, mp1)
	if err != nil {
		return err
	}

	mp2 := &mpdata.MealPlan{
		Notes:     "some other notes",
		StartDate: time.Date(2014, time.February, 5, 0, 0, 0, 0, time.UTC),
		EndDate:   time.Date(2014, time.February, 8, 0, 0, 0, 0, time.UTC),
	}

	err = AddMealPlan(q, mp2)
	if err != nil {
		return err
	}

	log.Printf("Test meal plans are %d and %d\n", mp1.ID, mp2.ID)

	return nil
}
<commit_msg>Fix new databases not having the searchtext column present in migrated databases<commit_after>package mpdb

import (
	"database/sql"
	"github.com/kierdavis/mealplanner/mpdata"
	"log"
	"time"
)

// SQL statements to delete tables.
var DeleteTablesSQLs = []string{
	"DROP TABLE IF EXISTS meal",
	"DROP TABLE IF EXISTS tag",
	"DROP TABLE IF EXISTS mealplan",
	"DROP TABLE IF EXISTS serving",
}

// SQL statements to create tables.
var CreateTablesSQLs = []string{
	"CREATE TABLE IF NOT EXISTS meal ( " +
		"id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, " +
		"name VARCHAR(255) NOT NULL, " +
		"recipe TEXT, " +
		"favourite BOOLEAN NOT NULL, " +
		"searchtext TEXT NOT NULL, " +
		"PRIMARY KEY (id) " +
		")",
	"CREATE TABLE IF NOT EXISTS tag ( " +
		"mealid BIGINT UNSIGNED NOT NULL, " +
		"tag VARCHAR(64) NOT NULL, " +
		"PRIMARY KEY (mealid, tag) " +
		")",
	"CREATE TABLE IF NOT EXISTS mealplan ( " +
		"id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, " +
		"notes TEXT, " +
		"startdate DATE NOT NULL, " +
		"enddate DATE NOT NULL, " +
		"PRIMARY KEY (id) " +
		")",
	"CREATE TABLE IF NOT EXISTS serving ( " +
		"mealplanid BIGINT UNSIGNED NOT NULL, " +
		"dateserved DATE NOT NULL, " +
		"mealid BIGINT UNSIGNED NOT NULL, " +
		"PRIMARY KEY (mealplanid, dateserved) " +
		")",
}

// SQL statements to clear tables.
var ClearTablesSQLs = []string{
	"DELETE FROM meal",
	"DELETE FROM tag",
	"DELETE FROM mealplan",
	"DELETE FROM serving",
}

// execList runs a list of SQL statements, discarding the results.
func execList(q Queryable, queries []string) (err error) {
	for _, query := range queries {
		_, err = q.Exec(query)
		if err != nil {
			return err
		}
	}

	return nil
}

// DeleteTables drops the database tables if they exist.
func DeleteTables(q Queryable) (err error) {
	return execList(q, DeleteTablesSQLs)
}

// CreateTables creates the database tables if they do not exist.
func CreateTables(q Queryable) (err error) {
	return execList(q, CreateTablesSQLs)
}

func InitialiseVersion(q Queryable, debug bool) (err error) {
	var version uint
	err = q.QueryRow("SELECT version FROM version").Scan(&version)
	isNTE := isNonexistentTableError(err)

	if err == nil { // All is fine.
		if debug {
			log.Printf("Version check: OK, current version is %d\n", version)
		}
		return nil

	} else if isNTE || err == sql.ErrNoRows { // No version set.
		if debug {
			log.Printf("Version check: version not set yet\n")
		}

		if isNTE { // 'version' table does not exist.
			if debug {
				log.Printf("Version check: creating version table\n")
			}
			_, err = q.Exec("CREATE TABLE version (version INT UNSIGNED NOT NULL)")
			if err != nil {
				return err
			}
		}

		// Check if other tables exist.
		_, err = q.Exec("SELECT meal.id FROM meal LIMIT 1")
		if err == nil { // Table 'meal' exists.
			if debug {
				log.Printf("Version check: assuming first startup since introduction of versioning\n")
			}
			version = 0

		} else if isNonexistentTableError(err) { // Table 'meal' does not exist.
			if debug {
				log.Printf("Version check: assuming empty database\n")
			}
			version = LatestVersion

		} else { // Unknown error.
			return err
		}

	} else { // Unknown error.
		return err
	}

	if debug {
		log.Printf("Version check: setting version to %d\n", version)
	}
	_, err = q.Exec("INSERT INTO version VALUES (?)", version)
	return err
}

// ClearTables deletes all records from the entire database.
func ClearTables(q Queryable) (err error) {
	return execList(q, ClearTablesSQLs)
}

// InitDB creates the database tables if they don't exist. If 'debug' is true,
// debug messages are printed. If 'testData' is true, the tables are also
// cleared and test data are added to them.
func InitDB(debug bool, testData bool) (err error) {
	return WithConnection(func(db *sql.DB) (err error) {
		return WithTransaction(db, func(tx *sql.Tx) (err error) {
			err = InitialiseVersion(tx, debug)
			if err != nil {
				return err
			}

			err = CreateTables(tx)
			if err != nil {
				return err
			}

			err = Migrate(tx, LatestVersion, debug)
			if err != nil {
				return err
			}

			if testData {
				if debug {
					log.Printf("Clearing database and inserting test data.\n")
				}

				err = ClearTables(tx)
				if err != nil {
					return err
				}

				err = InsertTestData(tx)
				if err != nil {
					return err
				}
			}

			return nil
		})
	})
}

// InsertTestData inserts some predefined meals and meal plans into the
// database for testing purposes.
func InsertTestData(q Queryable) (err error) {
	err = AddMealWithTags(q, mpdata.MealWithTags{
		Meal: &mpdata.Meal{
			Name:      "Chilli con carne",
			RecipeURL: "http://example.net/chilli",
			Favourite: false,
		},
		Tags: []string{
			"spicy",
			"lentil",
			"rice",
		},
	})

	if err != nil {
		return err
	}

	err = AddMealWithTags(q, mpdata.MealWithTags{
		Meal: &mpdata.Meal{
			Name:      "Carrot and lentil soup",
			RecipeURL: "http://example.net/soup",
			Favourite: false,
		},
		Tags: []string{
			"lentil",
			"soup",
			"quick",
		},
	})

	if err != nil {
		return err
	}

	err = AddMealWithTags(q, mpdata.MealWithTags{
		Meal: &mpdata.Meal{
			Name:      "Nachos",
			RecipeURL: "http://example.net/nachos",
			Favourite: true,
		},
		Tags: []string{
			"spicy",
			"mexican",
		},
	})

	if err != nil {
		return err
	}

	mp1 := &mpdata.MealPlan{
		Notes:     "some notes",
		StartDate: time.Date(2014, time.January, 25, 0, 0, 0, 0, time.UTC),
		EndDate:   time.Date(2014, time.February, 4, 0, 0, 0, 0, time.UTC),
	}

	err = AddMealPlan(q, mp1)
	if err != nil {
		return err
	}

	mp2 := &mpdata.MealPlan{
		Notes:     "some other notes",
		StartDate: time.Date(2014, time.February, 5, 0, 0, 0, 0, time.UTC),
		EndDate:   time.Date(2014, time.February, 8, 0, 0, 0, 0, time.UTC),
	}

	err = AddMealPlan(q, mp2)
	if err != nil {
		return err
	}

	log.Printf("Test meal plans are %d and %d\n", mp1.ID, mp2.ID)

	return nil
}
<|endoftext|>


<commit_before>// Package MPU9250 provides a stratux interface to the MPU9250 IMU
package mpu

import (
	"errors"
	"github.com/westphae/goflying/mpu9250"
	"log"
	"math"
	"time"
)

const (
	DECAY            = 0.98
	GYRORANGE        = 250
	ACCELRANGE       = 4
	UPDATEFREQ       = 100
)

type MPU9250 struct {
	mpu                  *mpu9250.MPU9250
	pitch, roll, heading float64
	headingMag           float64
	slipSkid             float64
	turnRate             float64
	gLoad                float64
	T                    int64
	valid                bool
	nextCalibrateT       int64
	quit                 chan struct{}
}

func NewMPU9250() (*MPU9250, error) {
	var (
		m   MPU9250
		mpu *mpu9250.MPU9250
		err error
	)

	mpu, err = mpu9250.NewMPU9250(GYRORANGE, ACCELRANGE, UPDATEFREQ, false, false)
	if err != nil {
		log.Println("AHRS Error: couldn't initialize MPU9250")
		return nil, err
	}

	m.mpu = mpu
	m.valid = true

	time.Sleep(100 * time.Millisecond)
	m.run()

	return &m, nil
}

func (m *MPU9250) run() {
	time.Sleep(100 * time.Millisecond)
	go func() {
		m.quit = make(chan struct{})
		clock := time.NewTicker(100 * time.Millisecond)

		for {
			select {
			case <-clock.C:
				data := <-m.mpu.CAvg

				if data.GAError == nil && data.N > 0 {
					m.T = data.T.UnixNano()
					smooth(&m.turnRate, data.G3)
					smooth(&m.gLoad, data.A3)
					smooth(&m.slipSkid, math.Asin(data.A2/data.A3)*180/math.Pi) //TODO westphae: Not sure if the sign is correct!

					// Quick and dirty calcs just to test - these are no good for pitch >> 0
					m.pitch += data.DT.Seconds() * data.G1
					m.roll += data.DT.Seconds() * data.G2
					m.heading -= data.DT.Seconds() * data.G3

					if m.pitch > 90 {
						m.pitch = 180 - m.pitch
					}
					if m.pitch < -90 {
						m.pitch = -180 - m.pitch
					}
					if (m.roll > 180) || (m.roll < -180) {
						m.roll = -m.roll
					}
					if m.heading > 360 {
						m.heading -= 360
					}
					if m.heading < 0 {
						m.heading += 360
					}
				}

				if data.MagError == nil && data.NM > 0 {
					smooth(&m.headingMag, math.Atan2(data.M2, data.M1))
				}
			case <-m.quit:
				m.mpu.CloseMPU()
				return
			}
		}
	}()
}

func smooth(val *float64, new float64) {
	*val = DECAY**val + (1-DECAY)*new
}

func (m *MPU9250) ResetHeading(newHeading float64, gain float64) {
	m.heading = newHeading
}

func (m *MPU9250) Pitch() (float64, error) {
	if m.valid {
		return m.pitch, nil
	} else {
		return 0, errors.New("MPU error: data not available")
	}
}

func (m *MPU9250) Roll() (float64, error) {
	if m.valid {
		return m.roll, nil
	} else {
		return 0, errors.New("MPU error: data not available")
	}
}

func (m *MPU9250) Heading() (float64, error) {
	if m.valid {
		return m.heading, nil
	} else {
		return 0, errors.New("MPU error: data not available")
	}
}

func (m *MPU9250) MagHeading() (float64, error) {
	if m.valid {
		return m.headingMag, nil
	} else {
		return 0, errors.New("MPU error: data not available")
	}
}

func (m *MPU9250) SlipSkid() (float64, error) {
	if m.valid {
		return m.slipSkid, nil
	} else {
		return 0, errors.New("MPU error: data not available")
	}
}

func (m *MPU9250) RateOfTurn() (float64, error) {
	if m.valid {
		return m.turnRate, nil
	} else {
		return 0, errors.New("MPU error: data not available")
	}
}

func (m *MPU9250) GLoad() (float64, error) {
	if m.valid {
		return m.gLoad, nil
	} else {
		return 0, errors.New("MPU error: data not available")
	}
}

func (m *MPU9250) ReadRaw() (T int64, G1, G2, G3, A1, A2, A3, M1, M2, M3 float64, GAError, MAGError error) {
	data := <-m.mpu.C
	T = data.T.UnixNano()
	G1 = data.G1
	G2 = data.G2
	G3 = data.G3
	A1 = data.A1
	A2 = data.A2
	A3 = data.A3
	M1 = data.M1
	M2 = data.M2
	M3 = data.M3
	GAError = data.GAError
	MAGError = data.MagError
	return
}

func (m *MPU9250) Calibrate(dur, retries int) (err error) {
	for i:=0; i<retries; i++ {
		m.mpu.CCal<- dur
		err = <-m.mpu.CCalResult
		if err == nil {
			break
		}
		time.Sleep(time.Duration(50) * time.Millisecond)
	}
	return
}

func (m *MPU9250) Close() {
	if m.quit != nil {
		m.quit <- struct{}{}
	}
}
<commit_msg>Measure magnetometer by default<commit_after>// Package MPU9250 provides a stratux interface to the MPU9250 IMU
package mpu

import (
	"errors"
	"github.com/westphae/goflying/mpu9250"
	"log"
	"math"
	"time"
)

const (
	DECAY            = 0.98
	GYRORANGE        = 250
	ACCELRANGE       = 4
	UPDATEFREQ       = 100
)

type MPU9250 struct {
	mpu                  *mpu9250.MPU9250
	pitch, roll, heading float64
	headingMag           float64
	slipSkid             float64
	turnRate             float64
	gLoad                float64
	T                    int64
	valid                bool
	nextCalibrateT       int64
	quit                 chan struct{}
}

func NewMPU9250() (*MPU9250, error) {
	var (
		m   MPU9250
		mpu *mpu9250.MPU9250
		err error
	)

	mpu, err = mpu9250.NewMPU9250(GYRORANGE, ACCELRANGE, UPDATEFREQ, true, false)
	if err != nil {
		log.Println("AHRS Error: couldn't initialize MPU9250")
		return nil, err
	}

	m.mpu = mpu
	m.valid = true

	time.Sleep(100 * time.Millisecond)
	m.run()

	return &m, nil
}

func (m *MPU9250) run() {
	time.Sleep(100 * time.Millisecond)
	go func() {
		m.quit = make(chan struct{})
		clock := time.NewTicker(100 * time.Millisecond)

		for {
			select {
			case <-clock.C:
				data := <-m.mpu.CAvg

				if data.GAError == nil && data.N > 0 {
					m.T = data.T.UnixNano()
					smooth(&m.turnRate, data.G3)
					smooth(&m.gLoad, data.A3)
					smooth(&m.slipSkid, math.Asin(data.A2/data.A3)*180/math.Pi) //TODO westphae: Not sure if the sign is correct!

					// Quick and dirty calcs just to test - these are no good for pitch >> 0
					m.pitch += data.DT.Seconds() * data.G1
					m.roll += data.DT.Seconds() * data.G2
					m.heading -= data.DT.Seconds() * data.G3

					if m.pitch > 90 {
						m.pitch = 180 - m.pitch
					}
					if m.pitch < -90 {
						m.pitch = -180 - m.pitch
					}
					if (m.roll > 180) || (m.roll < -180) {
						m.roll = -m.roll
					}
					if m.heading > 360 {
						m.heading -= 360
					}
					if m.heading < 0 {
						m.heading += 360
					}
				}

				if data.MagError == nil && data.NM > 0 {
					smooth(&m.headingMag, math.Atan2(data.M2, data.M1))
				}
			case <-m.quit:
				m.mpu.CloseMPU()
				return
			}
		}
	}()
}

func smooth(val *float64, new float64) {
	*val = DECAY**val + (1-DECAY)*new
}

func (m *MPU9250) ResetHeading(newHeading float64, gain float64) {
	m.heading = newHeading
}

func (m *MPU9250) Pitch() (float64, error) {
	if m.valid {
		return m.pitch, nil
	} else {
		return 0, errors.New("MPU error: data not available")
	}
}

func (m *MPU9250) Roll() (float64, error) {
	if m.valid {
		return m.roll, nil
	} else {
		return 0, errors.New("MPU error: data not available")
	}
}

func (m *MPU9250) Heading() (float64, error) {
	if m.valid {
		return m.heading, nil
	} else {
		return 0, errors.New("MPU error: data not available")
	}
}

func (m *MPU9250) MagHeading() (float64, error) {
	if m.valid {
		return m.headingMag, nil
	} else {
		return 0, errors.New("MPU error: data not available")
	}
}

func (m *MPU9250) SlipSkid() (float64, error) {
	if m.valid {
		return m.slipSkid, nil
	} else {
		return 0, errors.New("MPU error: data not available")
	}
}

func (m *MPU9250) RateOfTurn() (float64, error) {
	if m.valid {
		return m.turnRate, nil
	} else {
		return 0, errors.New("MPU error: data not available")
	}
}

func (m *MPU9250) GLoad() (float64, error) {
	if m.valid {
		return m.gLoad, nil
	} else {
		return 0, errors.New("MPU error: data not available")
	}
}

func (m *MPU9250) ReadRaw() (T int64, G1, G2, G3, A1, A2, A3, M1, M2, M3 float64, GAError, MAGError error) {
	data := <-m.mpu.C
	T = data.T.UnixNano()
	G1 = data.G1
	G2 = data.G2
	G3 = data.G3
	A1 = data.A1
	A2 = data.A2
	A3 = data.A3
	M1 = data.M1
	M2 = data.M2
	M3 = data.M3
	GAError = data.GAError
	MAGError = data.MagError
	return
}

func (m *MPU9250) Calibrate(dur, retries int) (err error) {
	for i:=0; i<retries; i++ {
		m.mpu.CCal<- dur
		err = <-m.mpu.CCalResult
		if err == nil {
			break
		}
		time.Sleep(time.Duration(50) * time.Millisecond)
	}
	return
}

func (m *MPU9250) Close() {
	if m.quit != nil {
		m.quit <- struct{}{}
	}
}
<|endoftext|>


<commit_before>package inject_test

import (
	"fmt"
	"net/http"
	"os"

	"github.com/daaku/go.inject"
)

// Our Awesome Application renders a message using two APIs in our fake world.
type AwesomeApp struct {
	// The tags below indicate to the inject library that these fields are
	// eligible for injection. They do not specify any options, and will result
	// in a singleton instance created for each of the APIs.

	NameAPI   *NameAPI   `inject:""`
	PlanetAPI *PlanetAPI `inject:""`
}

func (a *AwesomeApp) Render(id uint64) string {
	return fmt.Sprintf(
		"%s is from the planet %s.",
		a.NameAPI.Name(id),
		a.PlanetAPI.Planet(id),
	)
}

// Our fake Name API.
type NameAPI struct {
	// Here and below in PlanetAPI we add the tag to an interface value. This
	// value cannot automatically be created (by definition) and hence must be
	// explicitly provided to the graph.

	HttpTransport http.RoundTripper `inject:""`
}

func (n *NameAPI) Name(id uint64) string {
	// in the real world we would use f.HttpTransport and fetch the name
	return "Spock"
}

// Our fake Planet API.
type PlanetAPI struct {
	HttpTransport http.RoundTripper `inject:""`
}

func (p *PlanetAPI) Planet(id uint64) string {
	// in the real world we would use f.HttpTransport and fetch the planet
	return "Vulcan"
}

func Example() {
	// Typically an application will have exactly one object graph.
	// Traditionally you will create the graph and use it within a main function:
	var g inject.Graph

	// We Populate our world with two "seed" objects, one our empty AwesomeApp
	// instance which we're hoping to get filled out:
	var a AwesomeApp
	if err := g.Provide(inject.Object{Value: &a}); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	// And second our DefaultTransport to satisfiy our HttpTransport dependency.
	// We have to provide the DefaultTransport because the dependency is defined
	// in terms of the http.RoundTripper interface, and since it is an interface
	// the library cannot create an instance for it. Instead it will use the
	// given DefaultTransport to satisfy the dependency since it satisfies the
	// interface:
	if err := g.Provide(inject.Object{Value: http.DefaultTransport}); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	// Here the Populate call is creating instances of NameAPI & PlanetAPI, and
	// setting the HttpTransport on both to the http.DefaultTransport provided
	// above:
	if err := g.Populate(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	// There is a shorthand API for the simple case which combines the three
	// calls above and is available as inject.Populate:
	//
	//   inject.Populate(&a, http.DefaultTransport)
	//
	// The above API shows the main API and also allows the use of named
	// instances for more complex scenarios.

	fmt.Println(a.Render(42))

	// Output: Spock is from the planet Vulcan.
}
<commit_msg>more example nits<commit_after>package inject_test

import (
	"fmt"
	"net/http"
	"os"

	"github.com/daaku/go.inject"
)

// Our Awesome Application renders a message using two APIs in our fake world.
type AwesomeApp struct {
	// The tags below indicate to the inject library that these fields are
	// eligible for injection. They do not specify any options, and will result
	// in a singleton instance created for each of the APIs.

	NameAPI   *NameAPI   `inject:""`
	PlanetAPI *PlanetAPI `inject:""`
}

func (a *AwesomeApp) Render(id uint64) string {
	return fmt.Sprintf(
		"%s is from the planet %s.",
		a.NameAPI.Name(id),
		a.PlanetAPI.Planet(id),
	)
}

// Our fake Name API.
type NameAPI struct {
	// Here and below in PlanetAPI we add the tag to an interface value. This
	// value cannot automatically be created (by definition) and hence must be
	// explicitly provided to the graph.

	HttpTransport http.RoundTripper `inject:""`
}

func (n *NameAPI) Name(id uint64) string {
	// in the real world we would use f.HttpTransport and fetch the name
	return "Spock"
}

// Our fake Planet API.
type PlanetAPI struct {
	HttpTransport http.RoundTripper `inject:""`
}

func (p *PlanetAPI) Planet(id uint64) string {
	// in the real world we would use f.HttpTransport and fetch the planet
	return "Vulcan"
}

func Example() {
	// Typically an application will have exactly one object graph.
	// Traditionally you will create the graph and use it within a main function:
	var g inject.Graph

	// We Populate our world with two "seed" objects, one our empty AwesomeApp
	// instance which we're hoping to get filled out:
	var a AwesomeApp
	if err := g.Provide(inject.Object{Value: &a}); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	// And second our DefaultTransport to satisfiy our HttpTransport dependency.
	// We have to provide the DefaultTransport because the dependency is defined
	// in terms of the http.RoundTripper interface, and since it is an interface
	// the library cannot create an instance for it. Instead it will use the
	// given DefaultTransport to satisfy the dependency since it satisfies the
	// interface:
	if err := g.Provide(inject.Object{Value: http.DefaultTransport}); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	// Here the Populate call is creating instances of NameAPI & PlanetAPI, and
	// setting the HttpTransport on both to the http.DefaultTransport provided
	// above:
	if err := g.Populate(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	// There is a shorthand API for the simple case which combines the three
	// calls above is available as inject.Populate:
	//
	//   inject.Populate(&a, http.DefaultTransport)
	//
	// The above API shows the main API and also allows the use of named
	// instances for more complex scenarios.

	fmt.Println(a.Render(42))

	// Output: Spock is from the planet Vulcan.
}
<|endoftext|>


<commit_before>package youtube_test

import (
	"flag"
	"fmt"
	. "github.com/kkdai/youtube"
	"log"
	"os/user"
)

//ExampleDownload : Example code for how to use this package for download video.
func ExampleNewYoutube() {
	flag.Parse()
	log.Println(flag.Args())
	usr, _ := user.Current()
	currentDir := fmt.Sprintf("%v/Movies/youtubedr", usr.HomeDir)
	log.Println("download to dir=", currentDir)
	y := NewYoutube(true)
	arg := flag.Arg(0)
	if err := y.DecodeURL(arg); err != nil {
		fmt.Println("err:", err)
	}
	if err := y.StartDownload(currentDir, "dl.mp4", "", 0); err != nil {
		fmt.Println("err:", err)
	}
}
<commit_msg>format code<commit_after>package youtube_test

import (
	"flag"
	"fmt"
	"log"
	"os/user"

	"github.com/kkdai/youtube"
)

//ExampleDownload : Example code for how to use this package for download video.
func ExampleNewYoutube() {
	flag.Parse()
	log.Println(flag.Args())
	usr, _ := user.Current()
	currentDir := fmt.Sprintf("%v/Movies/youtubedr", usr.HomeDir)
	log.Println("download to dir=", currentDir)
	y := youtube.NewYoutube(true)
	arg := flag.Arg(0)
	if err := y.DecodeURL(arg); err != nil {
		fmt.Println("err:", err)
	}
	if err := y.StartDownload(currentDir, "dl.mp4", "", 0); err != nil {
		fmt.Println("err:", err)
	}
}
<|endoftext|>


<commit_before>package fscache

import (
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httptest"
	"os"
)

func Example() {
	// create the cache, keys expire after 1 hour.
	c, err := New("./cache", 0755, 1)
	if err != nil {
		log.Fatal(err.Error())
	}

	// wipe the cache when done
	defer c.Clean()

	// Get() and it's streams can be called concurrently but just for example:
	for i := 0; i < 3; i++ {
		r, w, err := c.Get("stream")
		if err != nil {
			log.Fatal(err.Error())
		}

		if w != nil { // a new stream, write to it.
			go func() {
				w.Write([]byte("hello world\n"))
				w.Close()
			}()
		}

		// the stream has started, read from it
		io.Copy(os.Stdout, r)
		r.Close()
	}
	// Output:
	// hello world
	// hello world
	// hello world
}

func ExampleHandler() {
	c, err := New("./server", 0700, 0)
	if err != nil {
		log.Fatal(err.Error())
	}
	defer c.Clean()

	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "Hello Client")
	})

	ts := httptest.NewServer(Handler(c, handler))
	defer ts.Close()

	resp, err := http.Get(ts.URL)
	if err != nil {
		log.Fatal(err.Error())
	}
	io.Copy(os.Stdout, resp.Body)
	resp.Body.Close()
	// Output:
	// Hello Client
}
<commit_msg>fixed time for example<commit_after>package fscache

import (
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httptest"
	"os"
	"time"
)

func Example() {
	// create the cache, keys expire after 1 hour.
	c, err := New("./cache", 0755, time.Hour)
	if err != nil {
		log.Fatal(err.Error())
	}

	// wipe the cache when done
	defer c.Clean()

	// Get() and it's streams can be called concurrently but just for example:
	for i := 0; i < 3; i++ {
		r, w, err := c.Get("stream")
		if err != nil {
			log.Fatal(err.Error())
		}

		if w != nil { // a new stream, write to it.
			go func() {
				w.Write([]byte("hello world\n"))
				w.Close()
			}()
		}

		// the stream has started, read from it
		io.Copy(os.Stdout, r)
		r.Close()
	}
	// Output:
	// hello world
	// hello world
	// hello world
}

func ExampleHandler() {
	c, err := New("./server", 0700, 0)
	if err != nil {
		log.Fatal(err.Error())
	}
	defer c.Clean()

	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "Hello Client")
	})

	ts := httptest.NewServer(Handler(c, handler))
	defer ts.Close()

	resp, err := http.Get(ts.URL)
	if err != nil {
		log.Fatal(err.Error())
	}
	io.Copy(os.Stdout, resp.Body)
	resp.Body.Close()
	// Output:
	// Hello Client
}
<|endoftext|>


<commit_before>package mpb_test

import (
	"io"
	"math/rand"
	"net/http"
	"time"

	"github.com/vbauerster/mpb"
	"github.com/vbauerster/mpb/decor"
)

func Example() {
	p := mpb.New(
		// override default (80) width
		mpb.WithWidth(100),
		// override default "[=>-]" format
		mpb.WithFormat("╢▌▌░╟"),
		// override default 120ms refresh rate
		mpb.WithRefreshRate(100*time.Millisecond),
	)

	total := 100
	name := "Single Bar:"
	// adding a single bar
	bar := p.AddBar(int64(total),
		mpb.PrependDecorators(
			// Display our static name with one space on the right
			decor.StaticName(name, len(name)+1, decor.DidentRight),
			// ETA decorator with width reservation of 3 runes
			decor.ETA(3, 0),
		),
		mpb.AppendDecorators(
			// Percentage decorator with width reservation of 5 runes
			decor.Percentage(5, 0),
		),
	)

	// simulating some work
	max := 100 * time.Millisecond
	for i := 0; i < total; i++ {
		time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10)
		// increment by 1 (there is bar.IncrBy(int) method, if needed)
		bar.Increment()
	}
	// wait for our bar to complete and flush
	p.Wait()
}

func ExampleBar_Completed() {
	p := mpb.New()
	bar := p.AddBar(100)

	max := 100 * time.Millisecond
	for !bar.Completed() {
		time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10)
		bar.Increment()
	}

	p.Wait()
}

func ExampleBar_ProxyReader() {
	p := mpb.New()
	// make http get request
	resp, err := http.Get(url)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	// Assuming ContentLength > 0
	bar := p.AddBar(resp.ContentLength,
		mpb.AppendDecorators(
			decor.CountersKibiByte("%6.1f / %6.1f", 12, 0),
		),
	)

	// create proxy reader
	reader := bar.ProxyReader(resp.Body)

	// and copy from reader, ignoring errors
	io.Copy(dest, reader)

	p.Wait()
}
<commit_msg>fix ExampleBar_ProxyReader<commit_after>package mpb_test

import (
	"io"
	"io/ioutil"
	"math/rand"
	"net/http"
	"time"

	"github.com/vbauerster/mpb"
	"github.com/vbauerster/mpb/decor"
)

func Example() {
	p := mpb.New(
		// override default (80) width
		mpb.WithWidth(100),
		// override default "[=>-]" format
		mpb.WithFormat("╢▌▌░╟"),
		// override default 120ms refresh rate
		mpb.WithRefreshRate(100*time.Millisecond),
	)

	total := 100
	name := "Single Bar:"
	// adding a single bar
	bar := p.AddBar(int64(total),
		mpb.PrependDecorators(
			// Display our static name with one space on the right
			decor.StaticName(name, len(name)+1, decor.DidentRight),
			// ETA decorator with width reservation of 3 runes
			decor.ETA(3, 0),
		),
		mpb.AppendDecorators(
			// Percentage decorator with width reservation of 5 runes
			decor.Percentage(5, 0),
		),
	)

	// simulating some work
	max := 100 * time.Millisecond
	for i := 0; i < total; i++ {
		time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10)
		// increment by 1 (there is bar.IncrBy(int) method, if needed)
		bar.Increment()
	}
	// wait for our bar to complete and flush
	p.Wait()
}

func ExampleBar_Completed() {
	p := mpb.New()
	bar := p.AddBar(100)

	max := 100 * time.Millisecond
	for !bar.Completed() {
		time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10)
		bar.Increment()
	}

	p.Wait()
}

func ExampleBar_ProxyReader() {
	p := mpb.New()
	// make http get request, ignoring errors
	resp, _ := http.Get("https://homebrew.bintray.com/bottles/libtiff-4.0.7.sierra.bottle.tar.gz")
	defer resp.Body.Close()

	// Assuming ContentLength > 0
	bar := p.AddBar(resp.ContentLength,
		mpb.AppendDecorators(
			decor.CountersKibiByte("%6.1f / %6.1f", 12, 0),
		),
	)

	// create proxy reader
	reader := bar.ProxyReader(resp.Body)

	// and copy from reader, ignoring errors
	io.Copy(ioutil.Discard, reader)

	p.Wait()
}
<|endoftext|>


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

package gousb_test

import (
	"fmt"
	"log"

	"github.com/google/gousb"
)

// This examples demonstrates the use of a few convenience functions that
// can be used in simple situations and with simple devices.
// It opens a device with a given VID/PID,
// claims the default interface (use the same config as currently active,
// interface 0, alternate setting 0) and tries to write 5 bytes of data
// to endpoint number 7.
func Example_simple() {
	// Initialize a new Context.
	ctx := gousb.NewContext()
	defer ctx.Close()

	// Open any device with a given VID/PID using a convenience function.
	dev, err := ctx.OpenDeviceWithVIDPID(0x046d, 0xc526)
	if err != nil {
		log.Fatalf("Could not open a device: %v", err)
	}
	defer dev.Close()

	// Claim the default interface using a convenience function.
	// The default interface is always #0 alt #0 in the currently active
	// config.
	intf, done, err := dev.DefaultInterface()
	if err != nil {
		log.Fatalf("%s.DefaultInterface(): %v", dev, err)
	}
	defer done()

	// Open an OUT endpoint.
	ep, err := intf.OutEndpoint(7)
	if err != nil {
		log.Fatalf("%s.OutEndpoint(7): %v", intf, err)
	}

	// Generate some data to write.
	data := make([]byte, 5)
	for i := range data {
		data[i] = byte(i)
	}

	// Write data to the USB device.
	numBytes, err := ep.Write(data)
	if numBytes != 5 {
		log.Fatalf("%s.Write([5]): only %d bytes written, returned error is %v", numBytes, err)
	}
	fmt.Println("5 bytes successfuly sent to the endpoint")
}

// This example demostrates the full API for accessing endpoints.
// It opens a device with a known VID/PID, switches the device to
// configuration #2, in that configuration it opens (claims) interface #3 with alternate setting #0.
// Within that interface setting it opens an IN endpoint number 6 and an OUT endpoint number 5, then starts copying
// data between them,
func Example_complex() {
	// Initialize a new Context.
	ctx := gousb.NewContext()
	defer ctx.Close()

	// Iterate through available Devices, finding all that match a known VID/PID.
	vid, pid := gousb.ID(0x04f2), gousb.ID(0xb531)
	devs, err := ctx.OpenDevices(func(desc *gousb.DeviceDesc) bool {
		// this function is called for every device present.
		// Returning true means the device should be opened.
		return desc.Vendor == vid && desc.Product == pid
	})
	// All returned devices are now open and will need to be closed.
	for _, d := range devs {
		defer d.Close()
	}
	if err != nil {
		log.Fatalf("OpenDevices(): %v", err)
	}
	if len(devs) == 0 {
		log.Fatalf("no devices found matching VID %s and PID %s", vid, pid)
	}

	// Pick the first device found.
	dev := devs[0]

	// Switch the configuration to #2.
	cfg, err := dev.Config(2)
	if err != nil {
		log.Fatalf("%s.Config(2): %v", dev, err)
	}
	defer cfg.Close()

	// In the config #2, claim interface #3 with alt setting #0.
	intf, err := cfg.Interface(3, 0)
	if err != nil {
		log.Fatalf("%s.Interface(3, 0): %v", cfg, err)
	}
	defer intf.Close()

	// In this interface open endpoint #6 for reading.
	epIn, err := intf.InEndpoint(6)
	if err != nil {
		log.Fatalf("%s.InEndpoint(6): %v", intf, err)
	}

	// And in the same interface open endpoint #5 for writing.
	epOut, err := intf.OutEndpoint(5)
	if err != nil {
		log.Fatalf("%s.OutEndpoint(5): %v", intf, err)
	}

	// Buffer large enough for 10 USB packets from endpoint 6.
	buf := make([]byte, 10*epIn.Desc.MaxPacketSize)
	total := 0
	// Repeat the read/write cycle 10 times.
	for i := 0; i < 10; i++ {
		// readBytes might be smaller than the buffer size. readBytes might be greater than zero even if err is not nil.
		readBytes, err := epIn.Read(buf)
		if err != nil {
			fmt.Println("Read returned an error:", err)
		}
		if readBytes == 0 {
			log.Fatalf("IN endpoint 6 returned 0 bytes of data.")
		}
		// writeBytes might be smaller than the buffer size if an error occured. writeBytes might be greater than zero even if err is not nil.
		writeBytes, err := epOut.Write(buf[:readBytes])
		if err != nil {
			fmt.Println("Write returned an error:", err)
		}
		if writeBytes != readBytes {
			log.Fatalf("IN endpoint 5 received only %d bytes of data out of %d sent", writeBytes, readBytes)
		}
		total += writeBytes
	}
	fmt.Printf("Total number of bytes copied: %d\n", total)
}
<commit_msg>Add missing endpoint argument to Fatalf.<commit_after>// Copyright 2017 the gousb Authors.  All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package gousb_test

import (
	"fmt"
	"log"

	"github.com/google/gousb"
)

// This examples demonstrates the use of a few convenience functions that
// can be used in simple situations and with simple devices.
// It opens a device with a given VID/PID,
// claims the default interface (use the same config as currently active,
// interface 0, alternate setting 0) and tries to write 5 bytes of data
// to endpoint number 7.
func Example_simple() {
	// Initialize a new Context.
	ctx := gousb.NewContext()
	defer ctx.Close()

	// Open any device with a given VID/PID using a convenience function.
	dev, err := ctx.OpenDeviceWithVIDPID(0x046d, 0xc526)
	if err != nil {
		log.Fatalf("Could not open a device: %v", err)
	}
	defer dev.Close()

	// Claim the default interface using a convenience function.
	// The default interface is always #0 alt #0 in the currently active
	// config.
	intf, done, err := dev.DefaultInterface()
	if err != nil {
		log.Fatalf("%s.DefaultInterface(): %v", dev, err)
	}
	defer done()

	// Open an OUT endpoint.
	ep, err := intf.OutEndpoint(7)
	if err != nil {
		log.Fatalf("%s.OutEndpoint(7): %v", intf, err)
	}

	// Generate some data to write.
	data := make([]byte, 5)
	for i := range data {
		data[i] = byte(i)
	}

	// Write data to the USB device.
	numBytes, err := ep.Write(data)
	if numBytes != 5 {
		log.Fatalf("%s.Write([5]): only %d bytes written, returned error is %v", ep, numBytes, err)
	}
	fmt.Println("5 bytes successfuly sent to the endpoint")
}

// This example demostrates the full API for accessing endpoints.
// It opens a device with a known VID/PID, switches the device to
// configuration #2, in that configuration it opens (claims) interface #3 with alternate setting #0.
// Within that interface setting it opens an IN endpoint number 6 and an OUT endpoint number 5, then starts copying
// data between them,
func Example_complex() {
	// Initialize a new Context.
	ctx := gousb.NewContext()
	defer ctx.Close()

	// Iterate through available Devices, finding all that match a known VID/PID.
	vid, pid := gousb.ID(0x04f2), gousb.ID(0xb531)
	devs, err := ctx.OpenDevices(func(desc *gousb.DeviceDesc) bool {
		// this function is called for every device present.
		// Returning true means the device should be opened.
		return desc.Vendor == vid && desc.Product == pid
	})
	// All returned devices are now open and will need to be closed.
	for _, d := range devs {
		defer d.Close()
	}
	if err != nil {
		log.Fatalf("OpenDevices(): %v", err)
	}
	if len(devs) == 0 {
		log.Fatalf("no devices found matching VID %s and PID %s", vid, pid)
	}

	// Pick the first device found.
	dev := devs[0]

	// Switch the configuration to #2.
	cfg, err := dev.Config(2)
	if err != nil {
		log.Fatalf("%s.Config(2): %v", dev, err)
	}
	defer cfg.Close()

	// In the config #2, claim interface #3 with alt setting #0.
	intf, err := cfg.Interface(3, 0)
	if err != nil {
		log.Fatalf("%s.Interface(3, 0): %v", cfg, err)
	}
	defer intf.Close()

	// In this interface open endpoint #6 for reading.
	epIn, err := intf.InEndpoint(6)
	if err != nil {
		log.Fatalf("%s.InEndpoint(6): %v", intf, err)
	}

	// And in the same interface open endpoint #5 for writing.
	epOut, err := intf.OutEndpoint(5)
	if err != nil {
		log.Fatalf("%s.OutEndpoint(5): %v", intf, err)
	}

	// Buffer large enough for 10 USB packets from endpoint 6.
	buf := make([]byte, 10*epIn.Desc.MaxPacketSize)
	total := 0
	// Repeat the read/write cycle 10 times.
	for i := 0; i < 10; i++ {
		// readBytes might be smaller than the buffer size. readBytes might be greater than zero even if err is not nil.
		readBytes, err := epIn.Read(buf)
		if err != nil {
			fmt.Println("Read returned an error:", err)
		}
		if readBytes == 0 {
			log.Fatalf("IN endpoint 6 returned 0 bytes of data.")
		}
		// writeBytes might be smaller than the buffer size if an error occured. writeBytes might be greater than zero even if err is not nil.
		writeBytes, err := epOut.Write(buf[:readBytes])
		if err != nil {
			fmt.Println("Write returned an error:", err)
		}
		if writeBytes != readBytes {
			log.Fatalf("IN endpoint 5 received only %d bytes of data out of %d sent", writeBytes, readBytes)
		}
		total += writeBytes
	}
	fmt.Printf("Total number of bytes copied: %d\n", total)
}
<|endoftext|>


<commit_before>package suffixtree

import (
	"bytes"
	"fmt"
	"math"
	"strings"
)

const Inf = math.MaxInt8

// pos denotes position in data string
type pos int8

// STree is a struct representing a suffix tree
type STree struct {
	data string
	root *state
}

var (
	root           *state
	auxiliaryState *state
)

// New creates new suffix tree
func New(data string) *STree {
	tree := &STree{data: data, root: newState(data)}

	root = tree.root
	auxiliaryState = newState(data)
	tree.root.linkState = auxiliaryState
	s := tree.root
	k := pos(0)
	for i := range data {
		s, k = update(s, k, pos(i))
		s, k = canonize(s, k, pos(i))
	}
	return tree
}

func (t *STree) String() string {
	buf := new(bytes.Buffer)
	printState(buf, t.root, 0)
	return buf.String()
}

func printState(buf *bytes.Buffer, s *state, ident int) {
	fmt.Fprint(buf, strings.Repeat("  ", ident))
	for _, tr := range s.trans {
		fmt.Fprint(buf, strings.Repeat("  ", ident))
		fmt.Fprintf(buf, "- tran: %d, %d;  '%s'\n", tr.start, tr.ActEnd(), s.data[tr.start:tr.ActEnd()+1])
		printState(buf, tr.state, ident+1)
	}
}

// state is an explicit state of the suffix tree
type state struct {
	data      string
	trans     []*tran
	linkState *state
}

func newState(data string) *state {
	return &state{
		data:      data,
		trans:     make([]*tran, 0),
		linkState: nil,
	}
}

func (s *state) addTran(start, end pos, r *state) {
	s.trans = append(s.trans, newTran(start, end, r))
}

func (s *state) fork(i pos) *state {
	r := newState(s.data)
	s.addTran(i, Inf, r)
	return r
}

func (s *state) findTran(c byte) *tran {
	for _, tran := range s.trans {
		if s.data[tran.start] == c {
			return tran
		}
	}
	return nil
}

// tran represents a state's transition
type tran struct {
	start, end pos
	state      *state
}

func newTran(start, end pos, s *state) *tran {
	return &tran{start, end, s}
}

func (t *tran) ActEnd() pos {
	if t.end == Inf {
		return pos(len(t.state.data)) - 1
	}
	return t.end
}

func update(s *state, start, end pos) (*state, pos) {
	// (s, (start, end-1)) is the canonical reference pair for the active point
	var oldr *state = root

	r, endPoint := testAndSplit(s, start, end-1, s.data[end])
	for !endPoint {
		r.fork(end)
		if oldr != root {
			oldr.linkState = r
		}
		oldr = r
		s, start = canonize(s.linkState, start, end-1)
		r, endPoint = testAndSplit(s, start, end-1, s.data[end])
	}
	if oldr != root {
		oldr.linkState = r
	}
	return s, start
}

// testAndSplit tests whether a state with canonical ref. pair
// (s, (start, end)) is the end point, that is, a state that have
// a c-transition. If not, then state (exs, (start, end)) is made
// explicit (if not already so).
func testAndSplit(s *state, start, end pos, c byte) (exs *state, endPoint bool) {
	if start <= end {
		tr := s.findTran(s.data[start])
		splitPoint := tr.start + end - start + 1
		if s.data[splitPoint] == c {
			return s, true
		}
		// make the (s, (start, end)) state explicit
		newSt := newState(s.data)
		newSt.addTran(splitPoint, tr.end, tr.state)
		tr.end = splitPoint - 1
		tr.state = newSt
		return newSt, false
	}
	if s != auxiliaryState && s.findTran(c) == nil {
		return s, false
	}
	return s, true
}

// canonize returns updated state and start position for ref. pair
// (s, (start, end)) of state r so the new ref. pair is canonical,
// that is, referenced from the closest explicit ancestor of r.
func canonize(s *state, start, end pos) (*state, pos) {
	if start > end {
		return s, start
	} else if s == auxiliaryState {
		return root, start + 1
	}

	tr := s.findTran(s.data[start])
	if tr == nil {
		panic(fmt.Sprintf("there should be some transition for '%c' at %d", s.data[start], start))
	}
	for tr.end-tr.start <= end-start {
		start += tr.end - tr.start + 1
		s = tr.state
		if start <= end {
			tr = s.findTran(s.data[start])
			if tr == nil {
				panic(fmt.Sprintf("there should be some transition for '%c' at %d", s.data[start], start))
			}
		}
	}
	if s == nil {
		panic("there should always be some suffix link resolution")
	}
	return s, start
}
<commit_msg>change printState<commit_after>package suffixtree

import (
	"bytes"
	"fmt"
	"math"
	"strings"
)

const Inf = math.MaxInt8

// pos denotes position in data string
type pos int8

// STree is a struct representing a suffix tree
type STree struct {
	data string
	root *state
}

var (
	root           *state
	auxiliaryState *state
)

// New creates new suffix tree
func New(data string) *STree {
	tree := &STree{data: data, root: newState(data)}

	root = tree.root
	auxiliaryState = newState(data)
	tree.root.linkState = auxiliaryState
	s := tree.root
	k := pos(0)
	for i := range data {
		s, k = update(s, k, pos(i))
		s, k = canonize(s, k, pos(i))
	}
	return tree
}

func (t *STree) String() string {
	buf := new(bytes.Buffer)
	printState(buf, t.root, 0)
	return buf.String()
}

func printState(buf *bytes.Buffer, s *state, ident int) {
	for _, tr := range s.trans {
		fmt.Fprint(buf, strings.Repeat("  ", ident))
		fmt.Fprintf(buf, "* (%d, %d) '%s'\n", tr.start, tr.ActEnd(), s.data[tr.start:tr.ActEnd()+1])
		printState(buf, tr.state, ident+1)
	}
}

// state is an explicit state of the suffix tree
type state struct {
	data      string
	trans     []*tran
	linkState *state
}

func newState(data string) *state {
	return &state{
		data:      data,
		trans:     make([]*tran, 0),
		linkState: nil,
	}
}

func (s *state) addTran(start, end pos, r *state) {
	s.trans = append(s.trans, newTran(start, end, r))
}

func (s *state) fork(i pos) *state {
	r := newState(s.data)
	s.addTran(i, Inf, r)
	return r
}

func (s *state) findTran(c byte) *tran {
	for _, tran := range s.trans {
		if s.data[tran.start] == c {
			return tran
		}
	}
	return nil
}

// tran represents a state's transition
type tran struct {
	start, end pos
	state      *state
}

func newTran(start, end pos, s *state) *tran {
	return &tran{start, end, s}
}

func (t *tran) ActEnd() pos {
	if t.end == Inf {
		return pos(len(t.state.data)) - 1
	}
	return t.end
}

func update(s *state, start, end pos) (*state, pos) {
	// (s, (start, end-1)) is the canonical reference pair for the active point
	var oldr *state = root

	r, endPoint := testAndSplit(s, start, end-1, s.data[end])
	for !endPoint {
		r.fork(end)
		if oldr != root {
			oldr.linkState = r
		}
		oldr = r
		s, start = canonize(s.linkState, start, end-1)
		r, endPoint = testAndSplit(s, start, end-1, s.data[end])
	}
	if oldr != root {
		oldr.linkState = r
	}
	return s, start
}

// testAndSplit tests whether a state with canonical ref. pair
// (s, (start, end)) is the end point, that is, a state that have
// a c-transition. If not, then state (exs, (start, end)) is made
// explicit (if not already so).
func testAndSplit(s *state, start, end pos, c byte) (exs *state, endPoint bool) {
	if start <= end {
		tr := s.findTran(s.data[start])
		splitPoint := tr.start + end - start + 1
		if s.data[splitPoint] == c {
			return s, true
		}
		// make the (s, (start, end)) state explicit
		newSt := newState(s.data)
		newSt.addTran(splitPoint, tr.end, tr.state)
		tr.end = splitPoint - 1
		tr.state = newSt
		return newSt, false
	}
	if s != auxiliaryState && s.findTran(c) == nil {
		return s, false
	}
	return s, true
}

// canonize returns updated state and start position for ref. pair
// (s, (start, end)) of state r so the new ref. pair is canonical,
// that is, referenced from the closest explicit ancestor of r.
func canonize(s *state, start, end pos) (*state, pos) {
	if start > end {
		return s, start
	} else if s == auxiliaryState {
		return root, start + 1
	}

	tr := s.findTran(s.data[start])
	if tr == nil {
		panic(fmt.Sprintf("there should be some transition for '%c' at %d", s.data[start], start))
	}
	for tr.end-tr.start <= end-start {
		start += tr.end - tr.start + 1
		s = tr.state
		if start <= end {
			tr = s.findTran(s.data[start])
			if tr == nil {
				panic(fmt.Sprintf("there should be some transition for '%c' at %d", s.data[start], start))
			}
		}
	}
	if s == nil {
		panic("there should always be some suffix link resolution")
	}
	return s, start
}
<|endoftext|>