<commit_before>package imagick

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/gographics/imagick/imagick"
	"github.com/pressly/imgry"
)

var (
	ErrEngineReleased = errors.New("imagick: engine has been released.")
	ErrEngineFailure  = errors.New("imagick: unable to request a MagickWand")
)

type Engine struct {
	tmpDir string
	// TODO: perhaps we have counter of wands here..
	// it ensures we'll always release them..
	// AvailableWands .. .. set to MaxSizers ..
	// then, NewMagickWand() will limit, or error..
	// perhaps we make a channel of these things..
	// then block.. + ctx will have a timeout if it wants to stop waiting..
	// we can log these timeouts etc..
}

func (ng Engine) Version() string {
	v, _ := imagick.GetVersion()
	return fmt.Sprintf("%s", v)
}

func (ng Engine) Initialize(tmpDir string) error {
	if tmpDir != "" {
		if err := os.MkdirAll(tmpDir, 0755); err != nil {
			return err
		}
		ng.tmpDir = tmpDir
		os.Setenv("MAGICK_TMPDIR", tmpDir)
		ng.SweepTmpDir()
	}
	imagick.Initialize()
	return nil
}

func (ng Engine) Terminate() {
	imagick.Terminate()
	ng.SweepTmpDir()
}

func (ng Engine) SweepTmpDir() error {
	if ng.tmpDir == "" {
		return nil
	}
	err := filepath.Walk(
		ng.tmpDir,
		func(path string, info os.FileInfo, err error) error {
			if ng.tmpDir == path {
				return nil // skip the root
			}
			if strings.Index(filepath.Base(path), "magick") >= 0 {
				if err = os.Remove(path); err != nil {
					return fmt.Errorf("failed to sweet engine tmpdir %s, because: %s", path, err)
				}
			}
			return nil
		},
	)
	if err != nil {
		return err
	}
	return nil
}

func (ng Engine) LoadFile(filename string, srcFormat ...string) (imgry.Image, error) {
	b, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	return ng.LoadBlob(b, srcFormat...)
}

func (ng Engine) LoadBlob(b []byte, srcFormat ...string) (imgry.Image, error) {
	if len(b) == 0 {
		return nil, imgry.ErrInvalidImageData
	}

	mw := imagick.NewMagickWand()
	if !mw.IsVerified() {
		return nil, ErrEngineFailure
	}

	// Offer a hint to the decoder of the file format
	if len(srcFormat) > 0 {
		f := srcFormat[0]
		if f != "" {
			mw.SetFormat(f)
		}
	}

	err := mw.ReadImageBlob(b)
	if err != nil {
		mw.Destroy()
		return nil, imgry.ErrInvalidImageData
	}

	// TODO: perhaps we pass the engine instance like Image{engine: i}
	im := &Image{mw: mw, data: b}
	if err := im.sync(); err != nil {
		mw.Destroy()
		return nil, err
	}

	return im, nil
}

func (ng Engine) GetImageInfo(b []byte, srcFormat ...string) (*imgry.ImageInfo, error) {
	if len(b) == 0 {
		return nil, imgry.ErrInvalidImageData
	}

	mw := imagick.NewMagickWand()
	defer mw.Destroy()

	if !mw.IsVerified() {
		return nil, ErrEngineFailure
	}

	err := mw.PingImageBlob(b)
	if err != nil {
		return nil, imgry.ErrInvalidImageData
	}

	w, h := int(mw.GetImageWidth()), int(mw.GetImageHeight())
	ar := float64(int(float64(w)/float64(h)*10000)) / 10000

	format := strings.ToLower(mw.GetImageFormat())
	if format == "jpeg" {
		format = "jpg"
	}

	imfo := &imgry.ImageInfo{
		Format: format, Width: w, Height: h,
		AspectRatio: ar, ContentLength: len(b),
	}

	return imfo, nil
}

type Image struct {
	mw *imagick.MagickWand

	data   []byte
	width  int
	height int
	format string
}

func (i *Image) Data() []byte {
	return i.data
}

func (i *Image) Width() int {
	return i.width
}

func (i *Image) Height() int {
	return i.height
}

func (i *Image) Format() string {
	return i.format
}

func (i *Image) SetFormat(format string) error {
	if i.Released() {
		return ErrEngineReleased
	}
	if err := i.mw.SetImageFormat(format); err != nil {
		return err
	}
	if err := i.sync(); err != nil {
		return err
	}
	return nil
}

func (i *Image) Released() bool {
	return i.mw == nil
}

func (i *Image) Release() {
	if i.mw != nil {
		i.mw.Destroy()
		i.mw = nil
	}
}

func (i *Image) Clone() imgry.Image {
	i2 := &Image{}
	i2.data = i.data
	i2.width = i.width
	i2.height = i.height
	i2.format = i.format
	if i.mw != nil && i.mw.IsVerified() {
		i2.mw = i.mw.Clone()
	}
	return i2
}

func (i *Image) SizeIt(sz *imgry.Sizing) error {
	if i.Released() {
		return ErrEngineReleased
	}

	if err := i.sizeFrames(sz); err != nil {
		return err
	}

	if sz.Format != "" {
		if err := i.mw.SetFormat(sz.Format); err != nil {
			return err
		}
	}

	if sz.Quality > 0 {
		if err := i.mw.SetImageCompressionQuality(uint(sz.Quality)); err != nil {
			return err
		}
	}

	if err := i.sync(sz.Flatten); err != nil {
		return err
	}

	return nil
}

func (i *Image) sizeFrames(sz *imgry.Sizing) error {
	var canvas *imagick.MagickWand
	var bg *imagick.PixelWand

	// Shortcut if there is nothing to size
	if sz.Size.Equal(imgry.ZeroRect) && sz.CropBox.Equal(imgry.ZeroFloatingRect) {
		return nil
	}

	coalesceAndDeconstruct := !sz.Flatten && i.mw.GetNumberImages() > 1
	if coalesceAndDeconstruct {
		i.mw = i.mw.CoalesceImages()
	}

	if sz.Canvas != nil {
		// If the user requested a canvas.
		canvas = imagick.NewMagickWand()
		bg = imagick.NewPixelWand()
		bg.SetColor("transparent")

		defer func() {
			bg.Destroy()
			if canvas != nil && canvas != i.mw {
				canvas.Destroy()
			}
		}()
	}

	i.mw.SetFirstIterator()
	for n := true; n; n = i.mw.NextImage() {
		pw, ph := int(i.mw.GetImageWidth()), int(i.mw.GetImageHeight())
		srcSize := imgry.NewRect(pw, ph)

		// Initial crop of the source image
		cropBox, cropOrigin, err := sz.CalcCropBox(srcSize)
		if err != nil {
			return err
		}

		if cropBox != nil && cropOrigin != nil && !cropBox.Equal(imgry.ZeroRect) {
			err := i.mw.CropImage(uint(cropBox.Width), uint(cropBox.Height), cropOrigin.X, cropOrigin.Y)
			if err != nil {
				return err
			}
			srcSize = cropBox
			i.mw.ResetImagePage("")
		}

		// Resize the image
		resizeRect, cropBox, cropOrigin := sz.CalcResizeRect(srcSize)
		if resizeRect != nil && !resizeRect.Equal(imgry.ZeroRect) {
			err := i.mw.ResizeImage(uint(resizeRect.Width), uint(resizeRect.Height), imagick.FILTER_LANCZOS, 1.0)
			if err != nil {
				return err
			}
			i.mw.ResetImagePage("")
		}

		// Perform any final crops from an operation
		if cropBox != nil && cropOrigin != nil && !cropBox.Equal(imgry.ZeroRect) {
			err := i.mw.CropImage(uint(cropBox.Width), uint(cropBox.Height), cropOrigin.X, cropOrigin.Y)
			if err != nil {
				return err
			}
			i.mw.ResetImagePage("")
		}

		// If we have a canvas we put the image at its center.
		if canvas != nil {
			canvas.NewImage(uint(sz.Canvas.Width), uint(sz.Canvas.Height), bg)
			canvas.SetImageBackgroundColor(bg)
			canvas.SetImageFormat(i.mw.GetImageFormat())

			x := (sz.Canvas.Width - int(i.mw.GetImageWidth())) / 2
			y := (sz.Canvas.Height - int(i.mw.GetImageHeight())) / 2
			canvas.CompositeImage(i.mw, imagick.COMPOSITE_OP_OVER, x, y)
			canvas.ResetImagePage("")
		}

		if sz.Flatten {
			break
		}
	}

	if canvas != nil {
		i.mw.Destroy()
		i.mw = canvas
	}

	if coalesceAndDeconstruct {
		// Compares each frame of the image, removes pixels that are already on the
		// background and updates offsets accordingly.
		i.mw = i.mw.DeconstructImages()
	}

	return nil
}

func (i *Image) WriteToFile(fn string) error {
	err := ioutil.WriteFile(fn, i.Data(), 0664)
	return err
}

func (i *Image) sync(optFlatten ...bool) error {
	if i.Released() {
		return ErrEngineReleased
	}

	var flatten bool
	if len(optFlatten) > 0 {
		flatten = optFlatten[0]
	}

	if flatten {
		i.data = i.mw.GetImageBlob()
	} else {
		i.data = i.mw.GetImagesBlob()
	}

	i.width = int(i.mw.GetImageWidth())
	i.height = int(i.mw.GetImageHeight())

	i.format = strings.ToLower(i.mw.GetImageFormat())
	if i.format == "jpeg" {
		i.format = "jpg"
	}

	return nil
}
<commit_msg>Makes jpegs progressive, strips exif and color profiles<commit_after>package imagick

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/gographics/imagick/imagick"
	"github.com/pressly/imgry"
)

var (
	ErrEngineReleased = errors.New("imagick: engine has been released.")
	ErrEngineFailure  = errors.New("imagick: unable to request a MagickWand")
)

type Engine struct {
	tmpDir string
	// TODO: perhaps we have counter of wands here..
	// it ensures we'll always release them..
	// AvailableWands .. .. set to MaxSizers ..
	// then, NewMagickWand() will limit, or error..
	// perhaps we make a channel of these things..
	// then block.. + ctx will have a timeout if it wants to stop waiting..
	// we can log these timeouts etc..
}

func (ng Engine) Version() string {
	v, _ := imagick.GetVersion()
	return fmt.Sprintf("%s", v)
}

func (ng Engine) Initialize(tmpDir string) error {
	if tmpDir != "" {
		if err := os.MkdirAll(tmpDir, 0755); err != nil {
			return err
		}
		ng.tmpDir = tmpDir
		os.Setenv("MAGICK_TMPDIR", tmpDir)
		ng.SweepTmpDir()
	}
	imagick.Initialize()
	return nil
}

func (ng Engine) Terminate() {
	imagick.Terminate()
	ng.SweepTmpDir()
}

func (ng Engine) SweepTmpDir() error {
	if ng.tmpDir == "" {
		return nil
	}
	err := filepath.Walk(
		ng.tmpDir,
		func(path string, info os.FileInfo, err error) error {
			if ng.tmpDir == path {
				return nil // skip the root
			}
			if strings.Index(filepath.Base(path), "magick") >= 0 {
				if err = os.Remove(path); err != nil {
					return fmt.Errorf("failed to sweet engine tmpdir %s, because: %s", path, err)
				}
			}
			return nil
		},
	)
	if err != nil {
		return err
	}
	return nil
}

func (ng Engine) LoadFile(filename string, srcFormat ...string) (imgry.Image, error) {
	b, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	return ng.LoadBlob(b, srcFormat...)
}

func (ng Engine) LoadBlob(b []byte, srcFormat ...string) (imgry.Image, error) {
	if len(b) == 0 {
		return nil, imgry.ErrInvalidImageData
	}

	mw := imagick.NewMagickWand()
	if !mw.IsVerified() {
		return nil, ErrEngineFailure
	}

	// Offer a hint to the decoder of the file format
	if len(srcFormat) > 0 {
		f := srcFormat[0]
		if f != "" {
			mw.SetFormat(f)
		}
	}

	err := mw.ReadImageBlob(b)
	if err != nil {
		mw.Destroy()
		return nil, imgry.ErrInvalidImageData
	}

	// TODO: perhaps we pass the engine instance like Image{engine: i}
	im := &Image{mw: mw, data: b}
	if err := im.sync(); err != nil {
		mw.Destroy()
		return nil, err
	}

	return im, nil
}

func (ng Engine) GetImageInfo(b []byte, srcFormat ...string) (*imgry.ImageInfo, error) {
	if len(b) == 0 {
		return nil, imgry.ErrInvalidImageData
	}

	mw := imagick.NewMagickWand()
	defer mw.Destroy()

	if !mw.IsVerified() {
		return nil, ErrEngineFailure
	}

	err := mw.PingImageBlob(b)
	if err != nil {
		return nil, imgry.ErrInvalidImageData
	}

	w, h := int(mw.GetImageWidth()), int(mw.GetImageHeight())
	ar := float64(int(float64(w)/float64(h)*10000)) / 10000

	format := strings.ToLower(mw.GetImageFormat())
	if format == "jpeg" {
		format = "jpg"
	}

	imfo := &imgry.ImageInfo{
		Format: format, Width: w, Height: h,
		AspectRatio: ar, ContentLength: len(b),
	}

	return imfo, nil
}

type Image struct {
	mw *imagick.MagickWand

	data   []byte
	width  int
	height int
	format string
}

func (i *Image) Data() []byte {
	return i.data
}

func (i *Image) Width() int {
	return i.width
}

func (i *Image) Height() int {
	return i.height
}

func (i *Image) Format() string {
	return i.format
}

func (i *Image) SetFormat(format string) error {
	if i.Released() {
		return ErrEngineReleased
	}
	if err := i.mw.SetImageFormat(format); err != nil {
		return err
	}
	if err := i.sync(); err != nil {
		return err
	}
	return nil
}

func (i *Image) Released() bool {
	return i.mw == nil
}

func (i *Image) Release() {
	if i.mw != nil {
		i.mw.Destroy()
		i.mw = nil
	}
}

func (i *Image) Clone() imgry.Image {
	i2 := &Image{}
	i2.data = i.data
	i2.width = i.width
	i2.height = i.height
	i2.format = i.format
	if i.mw != nil && i.mw.IsVerified() {
		i2.mw = i.mw.Clone()
	}
	return i2
}

func (i *Image) SizeIt(sz *imgry.Sizing) error {
	if i.Released() {
		return ErrEngineReleased
	}

	if err := i.sizeFrames(sz); err != nil {
		return err
	}

	if sz.Format != "" {
		if err := i.mw.SetFormat(sz.Format); err != nil {
			return err
		}
	}

	// progressive jpegs
	i.mw.SetInterlaceScheme(imagick.INTERLACE_PLANE)
	// exif and color profiles begone
	i.mw.StripImage()
	// compress it!
	if sz.Quality > 0 {
		if err := i.mw.SetImageCompressionQuality(uint(sz.Quality)); err != nil {
			return err
		}
	}

	if err := i.sync(sz.Flatten); err != nil {
		return err
	}

	return nil
}

func (i *Image) sizeFrames(sz *imgry.Sizing) error {
	var canvas *imagick.MagickWand
	var bg *imagick.PixelWand

	// Shortcut if there is nothing to size
	if sz.Size.Equal(imgry.ZeroRect) && sz.CropBox.Equal(imgry.ZeroFloatingRect) {
		return nil
	}

	coalesceAndDeconstruct := !sz.Flatten && i.mw.GetNumberImages() > 1
	if coalesceAndDeconstruct {
		i.mw = i.mw.CoalesceImages()
	}

	if sz.Canvas != nil {
		// If the user requested a canvas.
		canvas = imagick.NewMagickWand()
		bg = imagick.NewPixelWand()
		bg.SetColor("transparent")

		defer func() {
			bg.Destroy()
			if canvas != nil && canvas != i.mw {
				canvas.Destroy()
			}
		}()
	}

	i.mw.SetFirstIterator()
	for n := true; n; n = i.mw.NextImage() {
		pw, ph := int(i.mw.GetImageWidth()), int(i.mw.GetImageHeight())
		srcSize := imgry.NewRect(pw, ph)

		// Initial crop of the source image
		cropBox, cropOrigin, err := sz.CalcCropBox(srcSize)
		if err != nil {
			return err
		}

		if cropBox != nil && cropOrigin != nil && !cropBox.Equal(imgry.ZeroRect) {
			err := i.mw.CropImage(uint(cropBox.Width), uint(cropBox.Height), cropOrigin.X, cropOrigin.Y)
			if err != nil {
				return err
			}
			srcSize = cropBox
			i.mw.ResetImagePage("")
		}

		// Resize the image
		resizeRect, cropBox, cropOrigin := sz.CalcResizeRect(srcSize)
		if resizeRect != nil && !resizeRect.Equal(imgry.ZeroRect) {
			err := i.mw.ResizeImage(uint(resizeRect.Width), uint(resizeRect.Height), imagick.FILTER_LANCZOS, 1.0)
			if err != nil {
				return err
			}
			i.mw.ResetImagePage("")
		}

		// Perform any final crops from an operation
		if cropBox != nil && cropOrigin != nil && !cropBox.Equal(imgry.ZeroRect) {
			err := i.mw.CropImage(uint(cropBox.Width), uint(cropBox.Height), cropOrigin.X, cropOrigin.Y)
			if err != nil {
				return err
			}
			i.mw.ResetImagePage("")
		}

		// If we have a canvas we put the image at its center.
		if canvas != nil {
			canvas.NewImage(uint(sz.Canvas.Width), uint(sz.Canvas.Height), bg)
			canvas.SetImageBackgroundColor(bg)
			canvas.SetImageFormat(i.mw.GetImageFormat())

			x := (sz.Canvas.Width - int(i.mw.GetImageWidth())) / 2
			y := (sz.Canvas.Height - int(i.mw.GetImageHeight())) / 2
			canvas.CompositeImage(i.mw, imagick.COMPOSITE_OP_OVER, x, y)
			canvas.ResetImagePage("")
		}

		if sz.Flatten {
			break
		}
	}

	if canvas != nil {
		i.mw.Destroy()
		i.mw = canvas
	}

	if coalesceAndDeconstruct {
		// Compares each frame of the image, removes pixels that are already on the
		// background and updates offsets accordingly.
		i.mw = i.mw.DeconstructImages()
	}

	return nil
}

func (i *Image) WriteToFile(fn string) error {
	err := ioutil.WriteFile(fn, i.Data(), 0664)
	return err
}

func (i *Image) sync(optFlatten ...bool) error {
	if i.Released() {
		return ErrEngineReleased
	}

	var flatten bool
	if len(optFlatten) > 0 {
		flatten = optFlatten[0]
	}

	if flatten {
		i.data = i.mw.GetImageBlob()
	} else {
		i.data = i.mw.GetImagesBlob()
	}

	i.width = int(i.mw.GetImageWidth())
	i.height = int(i.mw.GetImageHeight())

	i.format = strings.ToLower(i.mw.GetImageFormat())
	if i.format == "jpeg" {
		i.format = "jpg"
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"archive/tar"
	"compress/gzip"
	"fmt"
	"io"

	"github.com/cozy/cozy-stack/client"
	"github.com/cozy/cozy-stack/client/auth"
	"github.com/cozy/cozy-stack/client/request"
)

func export(tw *tar.Writer, opts *request.Options, authReq *auth.Request) error {
	cClient := &client.Client{
		Domain: authReq.Domain,
		Scheme: opts.Scheme,
		Client: opts.Client,

		AuthClient: authReq.ClientParams,
		AuthScopes: authReq.Scopes,
		Authorizer: opts.Authorizer,
		UserAgent:  opts.UserAgent,
	}

	root := "/Documents"

	err := cClient.WalkByPath(root, func(path string, doc *client.DirOrFile, err error) error {
		fmt.Printf("Visited: %s  type: %s\n", path, doc.Attrs.Type)

		if doc.Attrs.Type == client.DirType {
			fmt.Println("directory")
		} else if doc.Attrs.Type == client.FileType {
			readCloser, err := cClient.DownloadByPath(path)
			if err != nil {
				return err
			}

			hdr := &tar.Header{
				Name: path,
				//Mode:       int64(doc.Attrs.Tags), //convertir doc.Attrs.Tags en int de permissions
				Size:       doc.Attrs.Size,
				ModTime:    doc.Attrs.CreatedAt,
				AccessTime: doc.Attrs.CreatedAt,
				ChangeTime: doc.Attrs.UpdatedAt,
			}
			if err := tw.WriteHeader(hdr); err != nil {
				return err
			}
			if _, err := io.Copy(tw, readCloser); err != nil {
				return err
			}

		} else {
			fmt.Println("type not found")
		}
		return err
	})

	if err != nil {
		return err
	}

	return nil
}

func tardir(w io.Writer, opts *request.Options, authReq *auth.Request) error {
	fmt.Println("tarball")
	//gzip writer
	gw := gzip.NewWriter(w)
	defer gw.Close()

	//tar writer
	tw := tar.NewWriter(gw)
	defer tw.Close()

	err := export(tw, opts, authReq)
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>permission mode<commit_after>package main

import (
	"archive/tar"
	"compress/gzip"
	"fmt"
	"io"

	"github.com/cozy/cozy-stack/client"
	"github.com/cozy/cozy-stack/client/auth"
	"github.com/cozy/cozy-stack/client/request"
)

func export(tw *tar.Writer, opts *request.Options, authReq *auth.Request) error {
	cClient := &client.Client{
		Domain: authReq.Domain,
		Scheme: opts.Scheme,
		Client: opts.Client,

		AuthClient: authReq.ClientParams,
		AuthScopes: authReq.Scopes,
		Authorizer: opts.Authorizer,
		UserAgent:  opts.UserAgent,
	}

	root := "/Documents"

	err := cClient.WalkByPath(root, func(path string, doc *client.DirOrFile, err error) error {
		fmt.Printf("Visited: %s  type: %s\n", path, doc.Attrs.Type)

		if doc.Attrs.Type == client.DirType {
			fmt.Println("directory")
		} else if doc.Attrs.Type == client.FileType {
			readCloser, err := cClient.DownloadByPath(path)
			if err != nil {
				return err
			}

			hdr := &tar.Header{
				Name:       path,
				Mode:       0644,
				Size:       doc.Attrs.Size,
				ModTime:    doc.Attrs.CreatedAt,
				AccessTime: doc.Attrs.CreatedAt,
				ChangeTime: doc.Attrs.UpdatedAt,
			}
			if doc.Attrs.Executable {
				hdr.Mode = 0755
			}

			if err := tw.WriteHeader(hdr); err != nil {
				return err
			}
			if _, err := io.Copy(tw, readCloser); err != nil {
				return err
			}

		} else {
			fmt.Println("type not found")
		}
		return nil
	})

	if err != nil {
		return err
	}

	return nil
}

func tardir(w io.Writer, opts *request.Options, authReq *auth.Request) error {
	fmt.Println("tarball")
	//gzip writer
	gw := gzip.NewWriter(w)
	defer gw.Close()

	//tar writer
	tw := tar.NewWriter(gw)
	defer tw.Close()

	err := export(tw, opts, authReq)
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
    "fmt";
    "http";
    "os";
    "flag";
    "bytes";
    "io";
)

func main() {
    flag.Parse(); // Parse command line args

    if flag.NArg() < 1 {
        fmt.Println("Cowardly refusing to shorten a blank URL");
        os.Exit(-1);
    }

    url, error := shortenURL(flag.Arg(0));
    if error != nil {
        fmt.Println(error);
        os.Exit(-1);
    }

    fmt.Println(url);

}

// Developed using the "API" listed here: http://is.gd/api_info.php
func shortenURL (url string) (shortURL string, err os.Error) {
    u := "http://is.gd/api.php?longurl=" + http.URLEscape(url);

    response, _, error := http.Get(u);

    // Make sure we can connect
    if error != nil {
        return "", error
    }

    // Make sure we get a 200 response code
    if response.StatusCode != 200 {
        return "", os.NewError("Could not shorted your URL. Perhaps it was malformed?");
    }

    var b []byte;
    b, err = io.ReadAll(response.Body);
    response.Body.Close();

    return bytes.NewBuffer(b).String(), nil;
}
<commit_msg>Cleaned up the implementation, removed superfluous code<commit_after>package main

import (
    "fmt";
    "http";
    "os";
    "flag";
    "io";
)

func main() {
    flag.Parse(); // Parse command line args

    if flag.NArg() < 1 {
        fmt.Println("Cowardly refusing to shorten a blank URL");
        os.Exit(-1);
    }

    url, error := shortenURL(flag.Arg(0));
    if error != nil {
        fmt.Println(error);
        os.Exit(-1);
    }

    fmt.Println(url);

}

// Developed using the "API" listed here: http://is.gd/api_info.php
func shortenURL (url string) (shortURL string, err os.Error) {
    u := "http://is.gd/api.php?longurl=" + http.URLEscape(url);

    response, _, err := http.Get(u);

    // Make sure we can connect
    if err != nil {
        return
    }

    // Make sure we get a 200 response code
    if response.StatusCode != 200 {
        return "", os.NewError("Could not shorted your URL. Perhaps it was malformed?");
    }

    b, err := io.ReadAll(response.Body);
    response.Body.Close();

    return string(b), nil;
}
<|endoftext|>


<commit_before>package commands

import (
	"fmt"
	"os"
	"path/filepath"

	"../conio"
	"../dos"
	"../interpreter"
)

type actionT struct {
	Do      func(src, dst string) error
	IsDirOk bool
}

func cmd_copy(cmd *interpreter.Interpreter) (interpreter.NextT, error) {
	return interpreter.CONTINUE,
		cmd_xxxx(cmd, actionT{
			func(src, dst string) error {
				return dos.Copy(src, dst, false)
			}, false})
}

func cmd_move(cmd *interpreter.Interpreter) (interpreter.NextT, error) {
	return interpreter.CONTINUE,
		cmd_xxxx(cmd, actionT{
			func(src, dst string) error {
				return dos.Move(src, dst)
			}, true})
}

func cmd_xxxx(cmd *interpreter.Interpreter, action actionT) error {
	switch len(cmd.Args) {
	case 0, 1, 2:
		fmt.Fprintf(cmd.Stderr,
			"Usage: %s SOURCE-FILENAME DESITINATE-FILENAME\n"+
				"       %s FILENAMES... DESINATE-DIRECTORY\n",
			cmd.Args[0], cmd.Args[0])
	case 3:
		src := cmd.Args[1]
		dst := cmd.Args[2]
		if !action.IsDirOk {
			fi, err := os.Stat(src)
			if err == nil && fi.Mode().IsDir() {
				fmt.Fprintf(cmd.Stderr, "%s is directory and passed.\n", src)
				return nil
			}
		}
		fi, err := os.Stat(dst)
		if err == nil && fi != nil && fi.Mode().IsDir() {
			dst = dos.Join(dst, filepath.Base(src))
			fi, err = os.Stat(dst)
		}
		fmt.Fprintf(cmd.Stderr, "%s -> %s\n", src, dst)
		if fi != nil && err == nil {
			fmt.Fprintf(cmd.Stderr, "%s: override? [Yes/No] ", dst)
			ch := conio.GetCh()
			fmt.Fprintf(cmd.Stderr, "%c\n", ch)
			if ch != 'y' || ch != 'Y' {
				return nil
			}
		}
		return action.Do(src, dst)
	default:
		all := false
		for i, n := 1, len(cmd.Args)-1; i < n; i++ {
			src := cmd.Args[i]
			dst := dos.Join(cmd.Args[n], filepath.Base(src))
			if !action.IsDirOk {
				fi, err := os.Stat(src)
				if err == nil && fi.Mode().IsDir() {
					fmt.Fprintf(cmd.Stderr, "%s is directory and passed.\n", src)
					continue
				}
			}

			fmt.Fprintf(cmd.Stderr, "%s -> %s\n", src, dst)
			if !all {
				fi, err := os.Stat(dst)
				if fi != nil && err == nil {
					fmt.Fprintf(cmd.Stderr,
						"%s: override? [Yes/No/All/Quit] ",
						dst)
					ch := conio.GetCh()
					fmt.Fprintf(cmd.Stderr, "%c\n", ch)
					switch ch {
					case 'y', 'Y':

					case 'a', 'A':
						all = true
					case 'q', 'Q':
						return nil
					default:
						continue
					}
				}
			}
			err := action.Do(src, dst)
			if err != nil {
				return err
			}
		}
	}
	return nil
}
<commit_msg>Fix: "copy A B" does not work when B exists.<commit_after>package commands

import (
	"fmt"
	"os"
	"path/filepath"

	"../conio"
	"../dos"
	"../interpreter"
)

type actionT struct {
	Do      func(src, dst string) error
	IsDirOk bool
}

func cmd_copy(cmd *interpreter.Interpreter) (interpreter.NextT, error) {
	return interpreter.CONTINUE,
		cmd_xxxx(cmd, actionT{
			func(src, dst string) error {
				return dos.Copy(src, dst, false)
			}, false})
}

func cmd_move(cmd *interpreter.Interpreter) (interpreter.NextT, error) {
	return interpreter.CONTINUE,
		cmd_xxxx(cmd, actionT{
			func(src, dst string) error {
				return dos.Move(src, dst)
			}, true})
}

func cmd_xxxx(cmd *interpreter.Interpreter, action actionT) error {
	switch len(cmd.Args) {
	case 0, 1, 2:
		fmt.Fprintf(cmd.Stderr,
			"Usage: %s SOURCE-FILENAME DESITINATE-FILENAME\n"+
				"       %s FILENAMES... DESINATE-DIRECTORY\n",
			cmd.Args[0], cmd.Args[0])
	case 3:
		src := cmd.Args[1]
		dst := cmd.Args[2]
		if !action.IsDirOk {
			fi, err := os.Stat(src)
			if err == nil && fi.Mode().IsDir() {
				fmt.Fprintf(cmd.Stderr, "%s is directory and passed.\n", src)
				return nil
			}
		}
		fi, err := os.Stat(dst)
		if err == nil && fi != nil && fi.Mode().IsDir() {
			dst = dos.Join(dst, filepath.Base(src))
			fi, err = os.Stat(dst)
		}
		fmt.Fprintf(cmd.Stderr, "%s -> %s\n", src, dst)
		if fi != nil && err == nil {
			fmt.Fprintf(cmd.Stderr, "%s: override? [Yes/No] ", dst)
			ch := conio.GetCh()
			fmt.Fprintf(cmd.Stderr, "%c\n", ch)
			if ch != 'y' && ch != 'Y' {
				return nil
			}
		}
		return action.Do(src, dst)
	default:
		all := false
		for i, n := 1, len(cmd.Args)-1; i < n; i++ {
			src := cmd.Args[i]
			dst := dos.Join(cmd.Args[n], filepath.Base(src))
			if !action.IsDirOk {
				fi, err := os.Stat(src)
				if err == nil && fi.Mode().IsDir() {
					fmt.Fprintf(cmd.Stderr, "%s is directory and passed.\n", src)
					continue
				}
			}

			fmt.Fprintf(cmd.Stderr, "%s -> %s\n", src, dst)
			if !all {
				fi, err := os.Stat(dst)
				if fi != nil && err == nil {
					fmt.Fprintf(cmd.Stderr,
						"%s: override? [Yes/No/All/Quit] ",
						dst)
					ch := conio.GetCh()
					fmt.Fprintf(cmd.Stderr, "%c\n", ch)
					switch ch {
					case 'y', 'Y':

					case 'a', 'A':
						all = true
					case 'q', 'Q':
						return nil
					default:
						continue
					}
				}
			}
			err := action.Do(src, dst)
			if err != nil {
				return err
			}
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import "github.com/ChimeraCoder/anaconda"
import "gopkg.in/gin-gonic/gin.v1"
import "net/http"
import "net/url"
import "os"
import "log"
import "strconv"

func setup() {
	anaconda.SetConsumerKey(os.Getenv("TW_CONSUMER_KEY"))
	anaconda.SetConsumerSecret(os.Getenv("TW_CONSUMER_SECRET"))
}

func extractTweets(c *gin.Context, timeline []anaconda.Tweet) []string {

	var tweets []string
	for _, tweet := range timeline {
		tweets = append(tweets, tweet.Text)
	}

	return tweets
}

// Get a list of friends from Twitter, put them in a map if setting,
// else add to a list if found in map
func getFriends(api *anaconda.TwitterApi, friends map[string]bool, userId string, setOrCheck bool) []string {

	var mutual []string

	values := url.Values{}
	values.Set("user_id", userId)

	ch := api.GetFriendsListAll(values)

	for friendPage := range ch {
		if friendPage.Error == nil {
			for _, user := range friendPage.Friends {
				id := strconv.FormatInt(user.Id, 10)
				log.Printf("name = %s, id = %s", user.Name, id)
				if setOrCheck {
					friends[id] = true
				} else {
					_, found := friends[id]
					if found {
						mutual = append(mutual, user.Name)
					}
				}
			}
		}
	}

	return mutual
}

func main() {
	setup()

	router := gin.Default()

	//Swagger docs
	router.Static("/docs", "../doc/dist")

	// This handler will match /tweets/john but will not match either /tweets/ or /tweets
	router.GET("/tweets/:name", func(c *gin.Context) {
		name := c.Param("name")
		api := anaconda.NewTwitterApi(os.Getenv("TW_ACCESS_TOKEN"), os.Getenv("TW_ACCESS_TOKEN_SECRET"))
		values := url.Values{}
		values.Add("screen_name", name)
		timeline, err := api.GetUserTimeline(values)
		if err != nil {
			log.Fatal(err)
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error})
			return
		}
		tweets := extractTweets(c, timeline)
		c.JSON(http.StatusOK, tweets)
	})

	// This route will match /common/abby/boris
	router.GET("/common/:name/:other", func(c *gin.Context) {
		names := c.Param("name")
		other := c.Param("other")
		names = names + ","
		names = names + other
		api := anaconda.NewTwitterApi(os.Getenv("TW_ACCESS_TOKEN"), os.Getenv("TW_ACCESS_TOKEN_SECRET"))
		values := url.Values{} // Would like to stringify ids but not sure if anaconda will handle that ...
		users, err := api.GetUsersLookup(names, values)
		if err != nil {
			log.Fatal(err)
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error}) // TODO Wrong status code!
			return
		}
		if len(users) < 2 {
			c.JSON(http.StatusNotFound, gin.H{"error": "Could not find both users by name"})
			return
		}
		if len(users) != 2 {
			c.JSON(http.StatusNotFound, gin.H{"error": "Too many users with those names"})
			return
		}

		// This map contains the names of the friends
		//
		var friends map[string]bool
		friends = make(map[string]bool)

		// Get the friends for the smaller of the two
		var getUserIndex = 1
		if users[0].FriendsCount < users[1].FriendsCount {
			getUserIndex = 0
		}

		userId := strconv.FormatInt(users[getUserIndex].Id, 10)
		log.Printf("Getting friends for index %d, user %s\n", getUserIndex, userId)
		_ = getFriends(api, friends, userId, true) // true = set value

		// Now get the other user's friends
		getUserIndex = (getUserIndex + 1) % 2

		userId = strconv.FormatInt(users[getUserIndex].Id, 10)
		log.Printf("Getting friends for index %d, user %s\n", getUserIndex, userId)
		mutual := getFriends(api, friends, userId, false) // false = check values

		c.JSON(http.StatusOK, mutual)
	})

	router.Run(":8000")
}
<commit_msg>Correct path to docs<commit_after>package main

import "github.com/ChimeraCoder/anaconda"
import "gopkg.in/gin-gonic/gin.v1"
import "net/http"
import "net/url"
import "os"
import "log"
import "strconv"

func setup() {
	anaconda.SetConsumerKey(os.Getenv("TW_CONSUMER_KEY"))
	anaconda.SetConsumerSecret(os.Getenv("TW_CONSUMER_SECRET"))
}

func extractTweets(c *gin.Context, timeline []anaconda.Tweet) []string {

	var tweets []string
	for _, tweet := range timeline {
		tweets = append(tweets, tweet.Text)
	}

	return tweets
}

// Get a list of friends from Twitter, put them in a map if setting,
// else add to a list if found in map
func getFriends(api *anaconda.TwitterApi, friends map[string]bool, userId string, setOrCheck bool) []string {

	var mutual []string

	values := url.Values{}
	values.Set("user_id", userId)

	ch := api.GetFriendsListAll(values)

	for friendPage := range ch {
		if friendPage.Error == nil {
			for _, user := range friendPage.Friends {
				id := strconv.FormatInt(user.Id, 10)
				log.Printf("name = %s, id = %s", user.Name, id)
				if setOrCheck {
					friends[id] = true
				} else {
					_, found := friends[id]
					if found {
						mutual = append(mutual, user.Name)
					}
				}
			}
		}
	}

	return mutual
}

func main() {
	setup()

	router := gin.Default()

	//Swagger docs
	router.Static("/doc", "./doc")

	// This handler will match /tweets/john but will not match either /tweets/ or /tweets
	router.GET("/tweets/:name", func(c *gin.Context) {
		name := c.Param("name")
		api := anaconda.NewTwitterApi(os.Getenv("TW_ACCESS_TOKEN"), os.Getenv("TW_ACCESS_TOKEN_SECRET"))
		values := url.Values{}
		values.Add("screen_name", name)
		timeline, err := api.GetUserTimeline(values)
		if err != nil {
			// log.Fatal(err)
			c.JSON(http.StatusBadRequest, gin.H{"error": "Could not find user"}) // TODO: Better error handling here
			return
		}
		tweets := extractTweets(c, timeline)
		c.JSON(http.StatusOK, tweets)
	})

	// This route will match /common/abby/boris
	router.GET("/common/:name/:other", func(c *gin.Context) {
		names := c.Param("name")
		other := c.Param("other")
		names = names + ","
		names = names + other
		api := anaconda.NewTwitterApi(os.Getenv("TW_ACCESS_TOKEN"), os.Getenv("TW_ACCESS_TOKEN_SECRET"))
		values := url.Values{} // Would like to stringify ids but not sure if anaconda will handle that ...
		users, err := api.GetUsersLookup(names, values)
		if err != nil {
			log.Fatal(err)
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error}) // TODO Wrong status code!
			return
		}
		if len(users) < 2 {
			c.JSON(http.StatusNotFound, gin.H{"error": "Could not find both users by name"})
			return
		}
		if len(users) != 2 {
			c.JSON(http.StatusNotFound, gin.H{"error": "Too many users with those names"})
			return
		}

		// This map contains the names of the friends
		//
		var friends map[string]bool
		friends = make(map[string]bool)

		// Get the friends for the smaller of the two
		var getUserIndex = 1
		if users[0].FriendsCount < users[1].FriendsCount {
			getUserIndex = 0
		}

		userId := strconv.FormatInt(users[getUserIndex].Id, 10)
		log.Printf("Getting friends for index %d, user %s\n", getUserIndex, userId)
		_ = getFriends(api, friends, userId, true) // true = set value

		// Now get the other user's friends
		getUserIndex = (getUserIndex + 1) % 2

		userId = strconv.FormatInt(users[getUserIndex].Id, 10)
		log.Printf("Getting friends for index %d, user %s\n", getUserIndex, userId)
		mutual := getFriends(api, friends, userId, false) // false = check values

		c.JSON(http.StatusOK, mutual)
	})

	router.Run(":8000")
}
<|endoftext|>


<commit_before>package wav

import (
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"time"

	"github.com/mattetti/audio"
	"github.com/mattetti/audio/riff"
)

// Decoder handles the decoding of wav files.
type Decoder struct {
	r      io.ReadSeeker
	parser *riff.Parser

	NumChans   uint16
	BitDepth   uint16
	SampleRate uint32

	AvgBytesPerSec uint32
	WavAudioFormat uint16

	err             error
	PCMSize         int
	pcmDataAccessed bool
	// pcmChunk is available so we can use the LimitReader
	PCMChunk *riff.Chunk
}

// NewDecoder creates a decoder for the passed wav reader.
// Note that the reader doesn't get rewinded as the container is processed.
func NewDecoder(r io.ReadSeeker) *Decoder {
	return &Decoder{
		r:      r,
		parser: riff.New(r),
	}
}

// PCMLen returns the total number of bytes in the PCM data chunk
func (d *Decoder) PCMLen() int64 {
	if d == nil {
		return 0
	}
	return int64(d.PCMSize)
}

// WasPCMAccessed returns positively if the PCM data was previously accessed.
func (d *Decoder) WasPCMAccessed() bool {
	if d == nil {
		return false
	}
	return d.pcmDataAccessed
}

// Err returns the first non-EOF error that was encountered by the Decoder.
func (d *Decoder) Err() error {
	if d.err == io.EOF {
		return nil
	}
	return d.err
}

// EOF returns positively if the underlying reader reached the end of file.
func (d *Decoder) EOF() bool {
	if d == nil || d.err == io.EOF {
		return true
	}
	return false
}

// IsValidFile verifies that the file is valid/readable.
func (d *Decoder) IsValidFile() bool {
	d.err = d.readHeaders()
	if d.err != nil {
		return false
	}
	if d.NumChans < 1 {
		return false
	}
	if d.BitDepth < 8 {
		return false
	}
	if d, err := d.Duration(); err != nil || d <= 0 {
		return false
	}

	return true
}

// ReadInfo reads the underlying reader until the comm header is parsed.
// This method is safe to call multiple times.
func (d *Decoder) ReadInfo() {
	d.err = d.readHeaders()
}

// Reset resets the decoder (and rewind the underlying reader)
func (d *Decoder) Reset() {
	d.err = nil
	d.pcmDataAccessed = false
	d.NumChans = 0
	d.BitDepth = 0
	d.SampleRate = 0
	d.AvgBytesPerSec = 0
	d.WavAudioFormat = 0
	d.PCMSize = 0
	d.r.Seek(0, 0)
	d.PCMChunk = nil
	d.parser = riff.New(d.r)
}

// Format returns the audio format of the decoded content.
func (d *Decoder) Format() *audio.Format {
	if d == nil {
		return nil
	}
	return &audio.Format{
		NumChannels: int(d.NumChans),
		SampleRate:  int(d.SampleRate),
		BitDepth:    int(d.BitDepth),
		Endianness:  binary.BigEndian,
	}
}

// FwdToPCM forwards the underlying reader until the start of the PCM chunk.
// If the PCM chunk was already read, no data will be found (you need to rewind).
func (d *Decoder) FwdToPCM() error {
	if d == nil {
		return fmt.Errorf("PCM data not found")
	}
	d.err = d.readHeaders()
	if d.err != nil {
		return nil
	}

	var chunk *riff.Chunk
	for d.err == nil {
		chunk, d.err = d.NextChunk()
		if d.err != nil {
			return d.err
		}
		if chunk.ID == riff.DataFormatID {
			d.PCMSize = chunk.Size
			d.PCMChunk = chunk
			break
		}
		chunk.Drain()
	}
	if chunk == nil {
		return fmt.Errorf("PCM data not found")
	}
	d.pcmDataAccessed = true

	return nil
}

// FullPCMBuffer is an inneficient way to access all the PCM data contained in the
// audio container. The entire PCM data is held in memory.
// Consider using Buffer() instead.
func (d *Decoder) FullPCMBuffer() (*audio.PCMBuffer, error) {
	if !d.WasPCMAccessed() {
		err := d.FwdToPCM()
		if err != nil {
			return nil, d.err
		}
	}
	if d.PCMChunk == nil {
		return nil, errors.New("PCM chunk not found")
	}
	format := d.Format()

	buf := audio.NewPCMIntBuffer(make([]int, 4096), format)
	bytesPerSample := (d.BitDepth-1)/8 + 1
	sampleBufData := make([]byte, bytesPerSample)
	decodeF, err := sampleDecodeFunc(int(d.BitDepth))
	if err != nil {
		return nil, fmt.Errorf("could not get sample decode func %v", err)
	}

	i := 0
	for err == nil {
		_, err = d.PCMChunk.Read(sampleBufData)
		if err != nil {
			break
		}
		buf.Ints[i] = decodeF(sampleBufData)
		i++
		// grow the underlying slice if needed
		if i == len(buf.Ints) {
			buf.Ints = append(buf.Ints, make([]int, 4096)...)
		}
	}
	buf.Ints = buf.Ints[:i]

	if err == io.EOF {
		err = nil
	}

	return buf, err
}

// PCMBuffer populates the passed PCM buffer
func (d *Decoder) PCMBuffer(buf *audio.PCMBuffer) error {
	if buf == nil {
		return nil
	}

	if !d.pcmDataAccessed {
		err := d.FwdToPCM()
		if err != nil {
			return d.err
		}
	}

	// TODO: avoid a potentially unecessary allocation
	format := &audio.Format{
		NumChannels: int(d.NumChans),
		SampleRate:  int(d.SampleRate),
		BitDepth:    int(d.BitDepth),
		Endianness:  binary.BigEndian,
	}

	bytesPerSample := (d.BitDepth-1)/8 + 1
	sampleBufData := make([]byte, bytesPerSample)
	decodeF, err := sampleDecodeFunc(int(d.BitDepth))
	if err != nil {
		return fmt.Errorf("could not get sample decode func %v", err)
	}

	// Note that we populate the buffer even if the
	// size of the buffer doesn't fit an even number of frames.
	for i := 0; i < len(buf.Ints); i++ {
		_, err = d.PCMChunk.Read(sampleBufData)
		if err != nil {
			break
		}
		buf.Ints[i] = decodeF(sampleBufData)
	}
	if err == io.EOF {
		err = nil
	}
	buf.Format = format
	if buf.DataType != audio.Integer {
		buf.DataType = audio.Integer
	}

	return err
}

// NextChunk returns the next available chunk
func (d *Decoder) NextChunk() (*riff.Chunk, error) {
	if d.err = d.readHeaders(); d.err != nil {
		d.err = fmt.Errorf("failed to read header - %v", d.err)
		return nil, d.err
	}

	var (
		id   [4]byte
		size uint32
	)

	id, size, d.err = d.parser.IDnSize()
	if d.err != nil {
		d.err = fmt.Errorf("error reading chunk header - %v", d.err)
		return nil, d.err
	}

	c := &riff.Chunk{
		ID:   id,
		Size: int(size),
		R:    io.LimitReader(d.r, int64(size)),
	}
	return c, d.err
}

// Duration returns the time duration for the current audio container
func (d *Decoder) Duration() (time.Duration, error) {
	if d == nil || d.parser == nil {
		return 0, errors.New("can't calculate the duration of a nil pointer")
	}
	return d.parser.Duration()
}

// String implements the Stringer interface.
func (d *Decoder) String() string {
	return d.parser.String()
}

// readHeaders is safe to call multiple times
func (d *Decoder) readHeaders() error {
	if d == nil || d.NumChans > 0 {
		return nil
	}

	id, size, err := d.parser.IDnSize()
	if err != nil {
		return err
	}
	d.parser.ID = id
	if d.parser.ID != riff.RiffID {
		return fmt.Errorf("%s - %s", d.parser.ID, riff.ErrFmtNotSupported)
	}
	d.parser.Size = size
	if err := binary.Read(d.r, binary.BigEndian, &d.parser.Format); err != nil {
		return err
	}

	var chunk *riff.Chunk
	var rewindBytes int64

	for err == nil {
		chunk, err = d.parser.NextChunk()
		if err != nil {
			break
		}
		if chunk.ID == riff.FmtID {
			chunk.DecodeWavHeader(d.parser)
			d.NumChans = d.parser.NumChannels
			d.BitDepth = d.parser.BitsPerSample
			d.SampleRate = d.parser.SampleRate
			d.WavAudioFormat = d.parser.WavAudioFormat
			d.AvgBytesPerSec = d.parser.AvgBytesPerSec

			if rewindBytes > 0 {
				d.r.Seek(-(rewindBytes + int64(chunk.Size)), 1)
			}
			break
		} else {
			// unexpected chunk order
			rewindBytes += int64(chunk.Size)
			chunk.Drain()
		}

	}

	return d.err
}

// sampleDecodeFunc returns a function that can be used to convert
// a byte range into an int value based on the amount of bits used per sample.
// Note that 8bit samples are unsigned, all other values are signed.
func sampleDecodeFunc(bitsPerSample int) (func([]byte) int, error) {
	// NOTE: WAV PCM data is stored using little-endian
	switch bitsPerSample {
	case 8:
		// 8bit values are unsigned
		return func(s []byte) int {
			return int(uint8(s[0]))
		}, nil
	case 16:
		// -32,768	(0x7FFF) to	32,767	(0x8000)
		return func(s []byte) int {
			return int(int16(binary.LittleEndian.Uint16(s)))
		}, nil
	case 24:
		// -34,359,738,367 (0x7FFFFF) to 34,359,738,368	(0x800000)
		return func(s []byte) int {
			ss := int32(s[0]) | int32(s[1])<<8 | int32(s[2])<<16
			if (ss & 0x800000) > 0 {
				ss |= ^0xffffff
			}
			return int(ss)
		}, nil
	case 32:
		return func(s []byte) int {
			return int(s[0]) + int(s[1])<<8 + int(s[2])<<16 + int(s[3])<<24
		}, nil
	default:
		return nil, fmt.Errorf("unhandled byte depth:%d", bitsPerSample)
	}
}

// sampleDecodeFloat64Func returns a function that can be used to convert
// a byte range into a float64 value based on the amount of bits used per sample.
func sampleFloat64DecodeFunc(bitsPerSample int) (func([]byte) float64, error) {
	bytesPerSample := bitsPerSample / 8
	switch bytesPerSample {
	case 1:
		// 8bit values are unsigned
		return func(s []byte) float64 {
			return float64(uint8(s[0]))
		}, nil
	case 2:
		return func(s []byte) float64 {
			return float64(int(s[0]) + int(s[1])<<8)
		}, nil
	case 3:
		return func(s []byte) float64 {
			var output int32
			output |= int32(s[2]) << 0
			output |= int32(s[1]) << 8
			output |= int32(s[0]) << 16
			return float64(output)
		}, nil
	case 4:
		// TODO: fix the float64 conversion (current int implementation)
		return func(s []byte) float64 {
			return float64(int(s[0]) + int(s[1])<<8 + int(s[2])<<16 + int(s[3])<<24)
		}, nil
	default:
		return nil, fmt.Errorf("unhandled byte depth:%d", bitsPerSample)
	}
}
<commit_msg>fix test suite<commit_after>package wav

import (
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"time"

	"github.com/mattetti/audio"
	"github.com/mattetti/audio/riff"
)

// Decoder handles the decoding of wav files.
type Decoder struct {
	r      io.ReadSeeker
	parser *riff.Parser

	NumChans   uint16
	BitDepth   uint16
	SampleRate uint32

	AvgBytesPerSec uint32
	WavAudioFormat uint16

	err             error
	PCMSize         int
	pcmDataAccessed bool
	// pcmChunk is available so we can use the LimitReader
	PCMChunk *riff.Chunk
}

// NewDecoder creates a decoder for the passed wav reader.
// Note that the reader doesn't get rewinded as the container is processed.
func NewDecoder(r io.ReadSeeker) *Decoder {
	return &Decoder{
		r:      r,
		parser: riff.New(r),
	}
}

// PCMLen returns the total number of bytes in the PCM data chunk
func (d *Decoder) PCMLen() int64 {
	if d == nil {
		return 0
	}
	return int64(d.PCMSize)
}

// WasPCMAccessed returns positively if the PCM data was previously accessed.
func (d *Decoder) WasPCMAccessed() bool {
	if d == nil {
		return false
	}
	return d.pcmDataAccessed
}

// Err returns the first non-EOF error that was encountered by the Decoder.
func (d *Decoder) Err() error {
	if d.err == io.EOF {
		return nil
	}
	return d.err
}

// EOF returns positively if the underlying reader reached the end of file.
func (d *Decoder) EOF() bool {
	if d == nil || d.err == io.EOF {
		return true
	}
	return false
}

// IsValidFile verifies that the file is valid/readable.
func (d *Decoder) IsValidFile() bool {
	d.err = d.readHeaders()
	if d.err != nil {
		return false
	}
	if d.NumChans < 1 {
		return false
	}
	if d.BitDepth < 8 {
		return false
	}
	if d, err := d.Duration(); err != nil || d <= 0 {
		return false
	}

	return true
}

// ReadInfo reads the underlying reader until the comm header is parsed.
// This method is safe to call multiple times.
func (d *Decoder) ReadInfo() {
	d.err = d.readHeaders()
}

// Reset resets the decoder (and rewind the underlying reader)
func (d *Decoder) Reset() {
	d.err = nil
	d.pcmDataAccessed = false
	d.NumChans = 0
	d.BitDepth = 0
	d.SampleRate = 0
	d.AvgBytesPerSec = 0
	d.WavAudioFormat = 0
	d.PCMSize = 0
	d.r.Seek(0, 0)
	d.PCMChunk = nil
	d.parser = riff.New(d.r)
}

// Format returns the audio format of the decoded content.
func (d *Decoder) Format() *audio.Format {
	if d == nil {
		return nil
	}
	return &audio.Format{
		NumChannels: int(d.NumChans),
		SampleRate:  int(d.SampleRate),
		BitDepth:    int(d.BitDepth),
		Endianness:  binary.BigEndian,
	}
}

// FwdToPCM forwards the underlying reader until the start of the PCM chunk.
// If the PCM chunk was already read, no data will be found (you need to rewind).
func (d *Decoder) FwdToPCM() error {
	if d == nil {
		return fmt.Errorf("PCM data not found")
	}
	d.err = d.readHeaders()
	if d.err != nil {
		return nil
	}

	var chunk *riff.Chunk
	for d.err == nil {
		chunk, d.err = d.NextChunk()
		if d.err != nil {
			return d.err
		}
		if chunk.ID == riff.DataFormatID {
			d.PCMSize = chunk.Size
			d.PCMChunk = chunk
			break
		}
		chunk.Drain()
	}
	if chunk == nil {
		return fmt.Errorf("PCM data not found")
	}
	d.pcmDataAccessed = true

	return nil
}

// FullPCMBuffer is an inneficient way to access all the PCM data contained in the
// audio container. The entire PCM data is held in memory.
// Consider using Buffer() instead.
func (d *Decoder) FullPCMBuffer() (*audio.PCMBuffer, error) {
	if !d.WasPCMAccessed() {
		err := d.FwdToPCM()
		if err != nil {
			return nil, d.err
		}
	}
	if d.PCMChunk == nil {
		return nil, errors.New("PCM chunk not found")
	}
	format := d.Format()

	buf := audio.NewPCMIntBuffer(make([]int, 4096), format)
	bytesPerSample := (d.BitDepth-1)/8 + 1
	sampleBufData := make([]byte, bytesPerSample)
	decodeF, err := sampleDecodeFunc(int(d.BitDepth))
	if err != nil {
		return nil, fmt.Errorf("could not get sample decode func %v", err)
	}

	i := 0
	for err == nil {
		_, err = d.PCMChunk.Read(sampleBufData)
		if err != nil {
			break
		}
		buf.Ints[i] = decodeF(sampleBufData)
		i++
		// grow the underlying slice if needed
		if i == len(buf.Ints) {
			buf.Ints = append(buf.Ints, make([]int, 4096)...)
		}
	}
	buf.Ints = buf.Ints[:i]

	if err == io.EOF {
		err = nil
	}

	return buf, err
}

// PCMBuffer populates the passed PCM buffer
func (d *Decoder) PCMBuffer(buf *audio.PCMBuffer) error {
	if buf == nil {
		return nil
	}

	if !d.pcmDataAccessed {
		err := d.FwdToPCM()
		if err != nil {
			return d.err
		}
	}

	// TODO: avoid a potentially unecessary allocation
	format := &audio.Format{
		NumChannels: int(d.NumChans),
		SampleRate:  int(d.SampleRate),
		BitDepth:    int(d.BitDepth),
		Endianness:  binary.BigEndian,
	}

	bytesPerSample := (d.BitDepth-1)/8 + 1
	sampleBufData := make([]byte, bytesPerSample)
	decodeF, err := sampleDecodeFunc(int(d.BitDepth))
	if err != nil {
		return fmt.Errorf("could not get sample decode func %v", err)
	}

	// Note that we populate the buffer even if the
	// size of the buffer doesn't fit an even number of frames.
	for i := 0; i < len(buf.Ints); i++ {
		_, err = d.PCMChunk.Read(sampleBufData)
		if err != nil {
			break
		}
		buf.Ints[i] = decodeF(sampleBufData)
	}
	if err == io.EOF {
		err = nil
	}
	buf.Format = format
	if buf.DataType != audio.Integer {
		buf.DataType = audio.Integer
	}

	return err
}

// NextChunk returns the next available chunk
func (d *Decoder) NextChunk() (*riff.Chunk, error) {
	if d.err = d.readHeaders(); d.err != nil {
		d.err = fmt.Errorf("failed to read header - %v", d.err)
		return nil, d.err
	}

	var (
		id   [4]byte
		size uint32
	)

	id, size, d.err = d.parser.IDnSize()
	if d.err != nil {
		d.err = fmt.Errorf("error reading chunk header - %v", d.err)
		return nil, d.err
	}

	c := &riff.Chunk{
		ID:   id,
		Size: int(size),
		R:    io.LimitReader(d.r, int64(size)),
	}
	return c, d.err
}

// Duration returns the time duration for the current audio container
func (d *Decoder) Duration() (time.Duration, error) {
	if d == nil || d.parser == nil {
		return 0, errors.New("can't calculate the duration of a nil pointer")
	}
	return d.parser.Duration()
}

// String implements the Stringer interface.
func (d *Decoder) String() string {
	return d.parser.String()
}

// readHeaders is safe to call multiple times
func (d *Decoder) readHeaders() error {
	if d == nil || d.NumChans > 0 {
		return nil
	}

	id, size, err := d.parser.IDnSize()
	if err != nil {
		return err
	}
	d.parser.ID = id
	if d.parser.ID != riff.RiffID {
		return fmt.Errorf("%s - %s", d.parser.ID, riff.ErrFmtNotSupported)
	}
	d.parser.Size = size
	if err := binary.Read(d.r, binary.BigEndian, &d.parser.Format); err != nil {
		return err
	}

	var chunk *riff.Chunk
	var rewindBytes int64

	for err == nil {
		chunk, err = d.parser.NextChunk()
		if err != nil {
			break
		}
		if chunk.ID == riff.FmtID {
			chunk.DecodeWavHeader(d.parser)
			d.NumChans = d.parser.NumChannels
			d.BitDepth = d.parser.BitsPerSample
			d.SampleRate = d.parser.SampleRate
			d.WavAudioFormat = d.parser.WavAudioFormat
			d.AvgBytesPerSec = d.parser.AvgBytesPerSec

			if rewindBytes > 0 {
				d.r.Seek(-(rewindBytes + int64(chunk.Size)), 1)
			}
			break
		} else {
			// unexpected chunk order
			rewindBytes += int64(chunk.Size)
			chunk.Drain()
		}

	}

	return d.err
}

// sampleDecodeFunc returns a function that can be used to convert
// a byte range into an int value based on the amount of bits used per sample.
// Note that 8bit samples are unsigned, all other values are signed.
func sampleDecodeFunc(bitsPerSample int) (func([]byte) int, error) {
	// NOTE: WAV PCM data is stored using little-endian
	switch bitsPerSample {
	case 8:
		// 8bit values are unsigned
		return func(s []byte) int {
			return int(uint8(s[0]))
		}, nil
	case 16:
		// -32,768	(0x7FFF) to	32,767	(0x8000)
		return func(s []byte) int {
			return int(int16(binary.LittleEndian.Uint16(s)))
		}, nil
	case 24:
		// -34,359,738,367 (0x7FFFFF) to 34,359,738,368	(0x800000)
		return func(s []byte) int {
			return int(int32(s[0])<<8 | int32(s[1])<<16 | int32(s[2])<<24)
			// ss := int32(s[0]) | int32(s[1])<<8 | int32(s[2])<<16
			// if (ss & 0x800000) > 0 {
			// 	ss |= ^0xffffff
			// }
			// return int(ss)
		}, nil
	case 32:
		return func(s []byte) int {
			return int(s[0]) + int(s[1])<<8 + int(s[2])<<16 + int(s[3])<<24
		}, nil
	default:
		return nil, fmt.Errorf("unhandled byte depth:%d", bitsPerSample)
	}
}

// sampleDecodeFloat64Func returns a function that can be used to convert
// a byte range into a float64 value based on the amount of bits used per sample.
func sampleFloat64DecodeFunc(bitsPerSample int) (func([]byte) float64, error) {
	bytesPerSample := bitsPerSample / 8
	switch bytesPerSample {
	case 1:
		// 8bit values are unsigned
		return func(s []byte) float64 {
			return float64(uint8(s[0]))
		}, nil
	case 2:
		return func(s []byte) float64 {
			return float64(int(s[0]) + int(s[1])<<8)
		}, nil
	case 3:
		return func(s []byte) float64 {
			var output int32
			output |= int32(s[2]) << 0
			output |= int32(s[1]) << 8
			output |= int32(s[0]) << 16
			return float64(output)
		}, nil
	case 4:
		// TODO: fix the float64 conversion (current int implementation)
		return func(s []byte) float64 {
			return float64(int(s[0]) + int(s[1])<<8 + int(s[2])<<16 + int(s[3])<<24)
		}, nil
	default:
		return nil, fmt.Errorf("unhandled byte depth:%d", bitsPerSample)
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 Mesosphere, Inc.
//
// 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 http

import (
	"fmt"
	"net"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/dcos/dcos-go/store"
	log "github.com/sirupsen/logrus"

	"github.com/dcos/dcos-metrics/producers"
	prodHelpers "github.com/dcos/dcos-metrics/util/producers"
)

var httpLog = log.WithFields(log.Fields{
	"producer": "http",
})

// Config for the HTTP producer
type Config struct {
	Port        int `yaml:"port"`
	IP          string
	CacheExpiry time.Duration
	DCOSRole    string
}

type producerImpl struct {
	config             Config
	store              store.Store
	metricsChan        chan producers.MetricsMessage
	janitorRunInterval time.Duration
}

// New creates a new instance of the HTTP producer with the provided configuration.
func New(cfg Config) (producers.MetricsProducer, chan producers.MetricsMessage) {
	p := producerImpl{
		config:             cfg,
		store:              store.New(),
		metricsChan:        make(chan producers.MetricsMessage),
		janitorRunInterval: 60 * time.Second,
	}
	return &p, p.metricsChan
}

// Run a HTTP server and serve the various metrics API endpoints.
// This function should be run in its own goroutine.
func (p *producerImpl) Run() error {
	httpLog.Info("Starting HTTP producer garbage collection service")
	go p.janitor()

	go func() {
		httpLog.Debug("HTTP producer listening for incoming messages on metricsChan")
		for {
			// read messages off the channel,
			// and give them a unique name in the store
			message := <-p.metricsChan
			httpLog.Debugf("Received message '%+v' with timestamp %s",
				message, time.Unix(message.Timestamp, 0).Format(time.RFC3339))

			var name string
			switch message.Name {
			case producers.NodeMetricPrefix:
				name = joinMetricName(message.Name, message.Dimensions.MesosID)

			case producers.ContainerMetricPrefix:
				name = joinMetricName(message.Name, message.Dimensions.ContainerID)

			case producers.AppMetricPrefix:
				name = joinMetricName(message.Name, message.Dimensions.ContainerID)
			}

			for _, d := range message.Datapoints {
				p.writeObjectToStore(d, message, name)
			}
		}
	}()

	r := newRouter(p)

	listeners, err := getListener()
	if err != nil {
		return fmt.Errorf("Unable to get listeners: %s", err)
	}
	// If a listener is available, use that. If it is not avialable,
	// listen on the default TCP socket and port.
	if len(listeners) == 1 {
		httpLog.Infof("http producer serving requests on systemd socket: %s", listeners[0].Addr().String())
		return http.Serve(listeners[0], r)
	}

	httpLog.Infof("http producer serving requests on tcp socket: %s", net.JoinHostPort(p.config.IP, strconv.Itoa(p.config.Port)))
	return http.ListenAndServe(fmt.Sprintf("%s:%d", p.config.IP, p.config.Port), r)
}

// writeObjectToStore writes a prefixed datapoint into the store.
func (p *producerImpl) writeObjectToStore(d producers.Datapoint, m producers.MetricsMessage, prefix string) {
	newMessage := producers.MetricsMessage{
		Name:       m.Name,
		Datapoints: []producers.Datapoint{d},
		Dimensions: m.Dimensions,
		Timestamp:  m.Timestamp,
	}
	// e.g. dcos.metrics.app.[ContainerId].kafka.server.ReplicaFetcherManager.MaxLag
	qualifiedName := joinMetricName(prefix, d.Name)
	for _, pair := range prodHelpers.SortTags(d.Tags) {
		k, v := pair[0], pair[1]
		// e.g. dcos.metrics.node.[MesosId].network.out.errors.#interface:eth0
		serializedTag := fmt.Sprintf("#%s:%s", k, v)
		qualifiedName = joinMetricName(qualifiedName, serializedTag)
	}
	httpLog.Debugf("Setting store object '%s' with timestamp %s",
		qualifiedName, time.Unix(newMessage.Timestamp, 0).Format(time.RFC3339))
	p.store.Set(qualifiedName, newMessage)
}

// joinMetricName concatenates its arguments using the metric name separator
func joinMetricName(segments ...string) string {
	return strings.Join(segments, producers.MetricNamespaceSep)
}

// janitor analyzes the objects in the store and removes stale objects. An
// object is considered stale when the top-level timestamp of its MetricsMessage
// has exceeded the CacheExpiry, which is calculated as a multiple of the
// collector's polling period. This function should be run in its own goroutine.
func (p *producerImpl) janitor() {
	ticker := time.NewTicker(p.janitorRunInterval)
	for {
		select {
		case _ = <-ticker.C:
			for k, v := range p.store.Objects() {
				o := v.(producers.MetricsMessage)

				age := time.Now().Sub(time.Unix(o.Timestamp, 0))
				if age > p.config.CacheExpiry {
					httpLog.Debugf("Removing stale object %s; last updated %d seconds ago", k, age/time.Second)
					p.store.Delete(k)
				}
			}
		}
	}
}
<commit_msg>Accept a listener in HTTP producer config<commit_after>// Copyright 2016 Mesosphere, Inc.
//
// 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 http

import (
	"fmt"
	"net"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/dcos/dcos-go/store"
	log "github.com/sirupsen/logrus"

	"github.com/dcos/dcos-metrics/producers"
	prodHelpers "github.com/dcos/dcos-metrics/util/producers"
)

var httpLog = log.WithFields(log.Fields{
	"producer": "http",
})

// Config for the HTTP producer
type Config struct {
	Port        int `yaml:"port"`
	IP          string
	CacheExpiry time.Duration
	DCOSRole    string
	Listener    net.Listener
}

type producerImpl struct {
	config             Config
	store              store.Store
	metricsChan        chan producers.MetricsMessage
	janitorRunInterval time.Duration
}

// New creates a new instance of the HTTP producer with the provided configuration.
func New(cfg Config) (producers.MetricsProducer, chan producers.MetricsMessage) {
	p := producerImpl{
		config:             cfg,
		store:              store.New(),
		metricsChan:        make(chan producers.MetricsMessage),
		janitorRunInterval: 60 * time.Second,
	}
	return &p, p.metricsChan
}

// Run a HTTP server and serve the various metrics API endpoints.
// This function should be run in its own goroutine.
func (p *producerImpl) Run() error {
	httpLog.Info("Starting HTTP producer garbage collection service")
	go p.janitor()

	go func() {
		httpLog.Debug("HTTP producer listening for incoming messages on metricsChan")
		for {
			// read messages off the channel,
			// and give them a unique name in the store
			message := <-p.metricsChan
			httpLog.Debugf("Received message '%+v' with timestamp %s",
				message, time.Unix(message.Timestamp, 0).Format(time.RFC3339))

			var name string
			switch message.Name {
			case producers.NodeMetricPrefix:
				name = joinMetricName(message.Name, message.Dimensions.MesosID)

			case producers.ContainerMetricPrefix:
				name = joinMetricName(message.Name, message.Dimensions.ContainerID)

			case producers.AppMetricPrefix:
				name = joinMetricName(message.Name, message.Dimensions.ContainerID)
			}

			for _, d := range message.Datapoints {
				p.writeObjectToStore(d, message, name)
			}
		}
	}()

	r := newRouter(p)

	// If a listener was provided directly in config, use it.
	if p.config.Listener != nil {
		httpLog.Infof("http producer serving requests on: %s", p.config.Listener.Addr().String())
		return http.Serve(p.config.Listener, r)
	}

	// If a listener from systemd is available, use it.
	listeners, err := getListener()
	if err != nil {
		return fmt.Errorf("Unable to get listeners: %s", err)
	}
	if len(listeners) == 1 {
		httpLog.Infof("http producer serving requests on systemd socket: %s", listeners[0].Addr().String())
		return http.Serve(listeners[0], r)
	}

	// Listen on the configured TCP port.
	httpLog.Infof("http producer serving requests on tcp socket: %s", net.JoinHostPort(p.config.IP, strconv.Itoa(p.config.Port)))
	return http.ListenAndServe(fmt.Sprintf("%s:%d", p.config.IP, p.config.Port), r)
}

// writeObjectToStore writes a prefixed datapoint into the store.
func (p *producerImpl) writeObjectToStore(d producers.Datapoint, m producers.MetricsMessage, prefix string) {
	newMessage := producers.MetricsMessage{
		Name:       m.Name,
		Datapoints: []producers.Datapoint{d},
		Dimensions: m.Dimensions,
		Timestamp:  m.Timestamp,
	}
	// e.g. dcos.metrics.app.[ContainerId].kafka.server.ReplicaFetcherManager.MaxLag
	qualifiedName := joinMetricName(prefix, d.Name)
	for _, pair := range prodHelpers.SortTags(d.Tags) {
		k, v := pair[0], pair[1]
		// e.g. dcos.metrics.node.[MesosId].network.out.errors.#interface:eth0
		serializedTag := fmt.Sprintf("#%s:%s", k, v)
		qualifiedName = joinMetricName(qualifiedName, serializedTag)
	}
	httpLog.Debugf("Setting store object '%s' with timestamp %s",
		qualifiedName, time.Unix(newMessage.Timestamp, 0).Format(time.RFC3339))
	p.store.Set(qualifiedName, newMessage)
}

// joinMetricName concatenates its arguments using the metric name separator
func joinMetricName(segments ...string) string {
	return strings.Join(segments, producers.MetricNamespaceSep)
}

// janitor analyzes the objects in the store and removes stale objects. An
// object is considered stale when the top-level timestamp of its MetricsMessage
// has exceeded the CacheExpiry, which is calculated as a multiple of the
// collector's polling period. This function should be run in its own goroutine.
func (p *producerImpl) janitor() {
	ticker := time.NewTicker(p.janitorRunInterval)
	for {
		select {
		case _ = <-ticker.C:
			for k, v := range p.store.Objects() {
				o := v.(producers.MetricsMessage)

				age := time.Now().Sub(time.Unix(o.Timestamp, 0))
				if age > p.config.CacheExpiry {
					httpLog.Debugf("Removing stale object %s; last updated %d seconds ago", k, age/time.Second)
					p.store.Delete(k)
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2018 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package prog

import (
	"reflect"
	"testing"
)

func TestNormalizePrio(t *testing.T) {
	prios := [][]float32{
		{2, 2, 2},
		{1, 2, 4},
		{1, 2, 0},
	}
	want := [][]float32{
		{1, 1, 1},
		{0.1, 0.4, 1},
		{0.4, 1, 0.1},
	}
	t.Logf("had:  %+v", prios)
	normalizePrio(prios)
	if !reflect.DeepEqual(prios, want) {
		t.Logf("got:  %+v", prios)
		t.Errorf("want: %+v", want)
	}
}
<commit_msg>prog: add a test for ChoiceTable<commit_after>// Copyright 2018 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package prog

import (
	"math/rand"
	"reflect"
	"testing"

	"github.com/google/go-cmp/cmp"
)

func TestNormalizePrio(t *testing.T) {
	prios := [][]float32{
		{2, 2, 2},
		{1, 2, 4},
		{1, 2, 0},
	}
	want := [][]float32{
		{1, 1, 1},
		{0.1, 0.4, 1},
		{0.4, 1, 0.1},
	}
	t.Logf("had:  %+v", prios)
	normalizePrio(prios)
	if !reflect.DeepEqual(prios, want) {
		t.Logf("got:  %+v", prios)
		t.Errorf("want: %+v", want)
	}
}

// TestPrioChoice tests that we select all syscalls with equal probability.
func TestPrioChoice(t *testing.T) {
	t.Parallel()
	target := &Target{
		Syscalls: []*Syscall{
			{ID: 0},
			{ID: 1},
			{ID: 2},
			{ID: 3},
		},
	}
	prios := [][]float32{
		{1, 1, 1, 1},
		{1, 1, 1, 1},
		{1, 1, 1, 1},
		{1, 1, 1, 1},
	}
	ct := target.BuildChoiceTable(prios, nil)
	r := rand.New(rand.NewSource(0))
	var res [4]int
	for i := 0; i < 10000; i++ {
		res[ct.Choose(r, 0)]++
	}
	// If this fails too frequently we can do some ranges, but for now it's just hardcoded.
	want := [4]int{2552, 2459, 2491, 2498}
	if diff := cmp.Diff(res, want); diff != "" {
		t.Fatal(diff)
	}
}
<|endoftext|>


<commit_before>// package Commands defines and implements command-line commands and flags
// used by devopsdays-cli. Commands and flags are implemented using Cobra.
package commands

import (
	"bytes"
	"fmt"
	"os"

	"github.com/devopsdays/devopsdays-cli/helpers/paths"
	"github.com/dimiro1/banner"
	"github.com/mattn/go-colorable"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var myBanner = `

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|d|e|v|o|p|s|d|a|y|s|-|c|l|i|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

`

// webdir is the path to the source files for the Hugo website
var webdir = paths.GetWebdir()

// const webdir = "/Users/mattstratton/src/devopsdays-web"

var cfgFile string

// Debug means should we run in debug mode. Duh.
var Debug bool

// City is the city we will be using - obtained via local flag
var City string

// Year is the year we will be using - obtained via local flag
var Year string

// All is used by a flag on Show commands to represent showing all of a thing
var All bool

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "devopsdays-cli",
	Short: "Run maintenance tasks for the devopsdays.org website",
	Long: `
Command-line utilities for the devopsdays.org website
built with love by mattstratton in Go.

Complete documentation is available at https://github.com/devopsdays/devopsdays-cli`,
	Run: func(cmd *cobra.Command, args []string) {
		mainPrompt()
	},
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}

func init() {
	cobra.OnInitialize(initConfig)
	isEnabled := true
	isColorEnabled := true
	banner.Init(colorable.NewColorableStdout(), isEnabled, isColorEnabled, bytes.NewBufferString(myBanner))

	RootCmd.PersistentFlags().BoolVarP(&Debug, "debug", "d", false, "enable debug mode")

}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
	if cfgFile != "" { // enable ability to specify config file via flag
		viper.SetConfigFile(cfgFile)
	}

	viper.SetConfigName(".devopsdays-cli") // name of config file (without extension)
	viper.AddConfigPath("$HOME")           // adding home directory as first search path
	viper.AutomaticEnv()                   // read in environment variables that match

	// If a config file is found, read it in.
	if err := viper.ReadInConfig(); err == nil {
		fmt.Println("Using config file:", viper.ConfigFileUsed())
	}
}

// func setWebdir() string {
// 	if os.Getenv("DODPATH") == "" {
// 		pwd, err := os.Getwd()
// 		if err != nil {
// 			fmt.Println(err)
// 			os.Exit(1)
// 		}
// 		return pwd
// 	}
// 	s := os.Getenv("DODPATH")
// 	s = strings.TrimSuffix(s, "/")
// 	s = strings.TrimSuffix(s, "\\")
// 	return s
// }

// func validateWebDir(webdir string) bool {
// 	filename := "a-nonexistent-file"
// 	if _, err := os.Stat(filename); os.IsNotExist(err) {
// 		fmt.Printf("file does not exist")
// 	}

// }
<commit_msg>Remove commented-out code<commit_after>// package Commands defines and implements command-line commands and flags
// used by devopsdays-cli. Commands and flags are implemented using Cobra.
package commands

import (
	"bytes"
	"fmt"
	"os"

	"github.com/devopsdays/devopsdays-cli/helpers/paths"
	"github.com/dimiro1/banner"
	"github.com/mattn/go-colorable"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var myBanner = `

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|d|e|v|o|p|s|d|a|y|s|-|c|l|i|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

`

// webdir is the path to the source files for the Hugo website
var webdir = paths.GetWebdir()

// const webdir = "/Users/mattstratton/src/devopsdays-web"

var cfgFile string

// Debug means should we run in debug mode. Duh.
var Debug bool

// City is the city we will be using - obtained via local flag
var City string

// Year is the year we will be using - obtained via local flag
var Year string

// All is used by a flag on Show commands to represent showing all of a thing
var All bool

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "devopsdays-cli",
	Short: "Run maintenance tasks for the devopsdays.org website",
	Long: `
Command-line utilities for the devopsdays.org website
built with love by mattstratton in Go.

Complete documentation is available at https://github.com/devopsdays/devopsdays-cli`,
	Run: func(cmd *cobra.Command, args []string) {
		mainPrompt()
	},
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}

func init() {
	cobra.OnInitialize(initConfig)
	isEnabled := true
	isColorEnabled := true
	banner.Init(colorable.NewColorableStdout(), isEnabled, isColorEnabled, bytes.NewBufferString(myBanner))

	RootCmd.PersistentFlags().BoolVarP(&Debug, "debug", "d", false, "enable debug mode")

}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
	if cfgFile != "" { // enable ability to specify config file via flag
		viper.SetConfigFile(cfgFile)
	}

	viper.SetConfigName(".devopsdays-cli") // name of config file (without extension)
	viper.AddConfigPath("$HOME")           // adding home directory as first search path
	viper.AutomaticEnv()                   // read in environment variables that match

	// If a config file is found, read it in.
	if err := viper.ReadInConfig(); err == nil {
		fmt.Println("Using config file:", viper.ConfigFileUsed())
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"io/ioutil"
	"net/url"
	"os"
	"path/filepath"

	"github.com/codegangsta/cli"
)

import (
	. "github.com/onsi/gomega"
	"testing"
)

func flagSet(name string, flags []cli.Flag) *flag.FlagSet {
	set := flag.NewFlagSet(name, flag.ContinueOnError)

	for _, f := range flags {
		f.Apply(set)
	}
	return set
}

func captureReader(block func()) (*os.File, *os.File, error) {
	rOut, wOut, err := os.Pipe()
	if err != nil {
		return nil, nil, err
	}

	rErr, wErr, err := os.Pipe()
	if err != nil {
		return nil, nil, err
	}

	defer wOut.Close()
	defer wErr.Close()

	var stdout, stderr *os.File
	os.Stdout, stdout = wOut, os.Stdout
	os.Stderr, stderr = wErr, os.Stderr

	defer func() {
		os.Stdout = stdout
		os.Stderr = stderr
	}()

	block()

	wOut.Close()
	wErr.Close()

	return rOut, rErr, nil
}

func capture(block func()) (string, string, error) {
	rOut, rErr, err := captureReader(block)
	if err != nil {
		return "", "", err
	}

	bufOut, err := ioutil.ReadAll(rOut)
	if err != nil {
		return "", "", err
	}

	bufErr, err := ioutil.ReadAll(rErr)
	if err != nil {
		return "", "", err
	}

	return string(bufOut), string(bufErr), nil
}

type _cloneArgs struct {
	remote  *url.URL
	local   string
	shallow bool
}

type _updateArgs struct {
	local string
}

func withFakeGitBackend(t *testing.T, block func(string, *_cloneArgs, *_updateArgs)) {
	tmpRoot, err := ioutil.TempDir("", "ghq")
	if err != nil {
		t.Fatalf("Could not create tempdir: %s", err)
	}
	defer func() { os.RemoveAll(tmpRoot) }()

	_localRepositoryRoots = []string{tmpRoot}
	defer func() { _localRepositoryRoots = []string{} }()

	var cloneArgs _cloneArgs
	var updateArgs _updateArgs

	var originalGitBackend = GitBackend
	GitBackend = &VCSBackend{
		Clone: func(remote *url.URL, local string, shallow bool) error {
			cloneArgs = _cloneArgs{
				remote:  remote,
				local:   local,
				shallow: shallow,
			}
			return nil
		},
		Update: func(local string) error {
			updateArgs = _updateArgs{
				local: local,
			}
			return nil
		},
	}
	defer func() { GitBackend = originalGitBackend }()

	block(tmpRoot, &cloneArgs, &updateArgs)
}

func TestCommandGet(t *testing.T) {
	RegisterTestingT(t)

	app := newApp()

	withFakeGitBackend(t, func(tmpRoot string, cloneArgs *_cloneArgs, updateArgs *_updateArgs) {
		localDir := filepath.Join(tmpRoot, "github.com", "motemen", "ghq-test-repo")

		app.Run([]string{"", "get", "motemen/ghq-test-repo"})

		Expect(cloneArgs.remote.String()).To(Equal("https://github.com/motemen/ghq-test-repo"))
		Expect(cloneArgs.local).To(Equal(localDir))
		Expect(cloneArgs.shallow).To(Equal(false))
	})

	withFakeGitBackend(t, func(tmpRoot string, cloneArgs *_cloneArgs, updateArgs *_updateArgs) {
		localDir := filepath.Join(tmpRoot, "github.com", "motemen", "ghq-test-repo")

		app.Run([]string{"", "get", "-p", "motemen/ghq-test-repo"})

		Expect(cloneArgs.remote.String()).To(Equal("ssh://git@github.com/motemen/ghq-test-repo"))
		Expect(cloneArgs.local).To(Equal(localDir))
	})

	withFakeGitBackend(t, func(tmpRoot string, cloneArgs *_cloneArgs, updateArgs *_updateArgs) {
		localDir := filepath.Join(tmpRoot, "github.com", "motemen", "ghq-test-repo")
		// mark as "already cloned", the condition may change later
		os.MkdirAll(filepath.Join(localDir, ".git"), 0755)

		app.Run([]string{"", "get", "-u", "motemen/ghq-test-repo"})

		Expect(updateArgs.local).To(Equal(localDir))
	})

	withFakeGitBackend(t, func(tmpRoot string, cloneArgs *_cloneArgs, updateArgs *_updateArgs) {
		localDir := filepath.Join(tmpRoot, "github.com", "motemen", "ghq-test-repo")
		app.Run([]string{"", "get", "-p", "motemen/ghq-test-repo"})

		Expect(cloneArgs.remote.String()).To(Equal("ssh://git@github.com/motemen/ghq-test-repo"))
		Expect(cloneArgs.local).To(Equal(localDir))
		Expect(cloneArgs.shallow).To(Equal(false))
	})

	withFakeGitBackend(t, func(tmpRoot string, cloneArgs *_cloneArgs, updateArgs *_updateArgs) {
		localDir := filepath.Join(tmpRoot, "github.com", "motemen", "ghq-test-repo")

		app.Run([]string{"", "get", "-shallow", "motemen/ghq-test-repo"})

		Expect(cloneArgs.remote.String()).To(Equal("https://github.com/motemen/ghq-test-repo"))
		Expect(cloneArgs.local).To(Equal(localDir))
		Expect(cloneArgs.shallow).To(Equal(true))
	})
}

func TestCommandList(t *testing.T) {
	RegisterTestingT(t)

	_, _, err := capture(func() {
		app := cli.NewApp()
		flagSet := flagSet("list", commandList.Flags)
		c := cli.NewContext(app, flagSet, flagSet)

		doList(c)
	})

	Expect(err).To(BeNil())
}

func TestCommandListUnique(t *testing.T) {
	RegisterTestingT(t)

	_, _, err := capture(func() {
		app := cli.NewApp()
		flagSet := flagSet("list", commandList.Flags)
		flagSet.Parse([]string{"--unique"})
		c := cli.NewContext(app, flagSet, flagSet)

		doList(c)
	})

	Expect(err).To(BeNil())
}

func TestCommandListUnknown(t *testing.T) {
	RegisterTestingT(t)

	_, _, err := capture(func() {
		app := cli.NewApp()
		flagSet := flagSet("list", commandList.Flags)
		flagSet.Parse([]string{"--unknown-flag"})
		c := cli.NewContext(app, flagSet, flagSet)

		doList(c)
	})

	Expect(err).To(BeNil())
}
<commit_msg>Add test<commit_after>package main

import (
	"flag"
	"io/ioutil"
	"net/url"
	"os"
	"path/filepath"

	"github.com/codegangsta/cli"
)

import (
	. "github.com/onsi/gomega"
	"testing"
)

func flagSet(name string, flags []cli.Flag) *flag.FlagSet {
	set := flag.NewFlagSet(name, flag.ContinueOnError)

	for _, f := range flags {
		f.Apply(set)
	}
	return set
}

func captureReader(block func()) (*os.File, *os.File, error) {
	rOut, wOut, err := os.Pipe()
	if err != nil {
		return nil, nil, err
	}

	rErr, wErr, err := os.Pipe()
	if err != nil {
		return nil, nil, err
	}

	defer wOut.Close()
	defer wErr.Close()

	var stdout, stderr *os.File
	os.Stdout, stdout = wOut, os.Stdout
	os.Stderr, stderr = wErr, os.Stderr

	defer func() {
		os.Stdout = stdout
		os.Stderr = stderr
	}()

	block()

	wOut.Close()
	wErr.Close()

	return rOut, rErr, nil
}

func capture(block func()) (string, string, error) {
	rOut, rErr, err := captureReader(block)
	if err != nil {
		return "", "", err
	}

	bufOut, err := ioutil.ReadAll(rOut)
	if err != nil {
		return "", "", err
	}

	bufErr, err := ioutil.ReadAll(rErr)
	if err != nil {
		return "", "", err
	}

	return string(bufOut), string(bufErr), nil
}

type _cloneArgs struct {
	remote  *url.URL
	local   string
	shallow bool
}

type _updateArgs struct {
	local string
}

func withFakeGitBackend(t *testing.T, block func(string, *_cloneArgs, *_updateArgs)) {
	tmpRoot, err := ioutil.TempDir("", "ghq")
	if err != nil {
		t.Fatalf("Could not create tempdir: %s", err)
	}
	defer func() { os.RemoveAll(tmpRoot) }()

	_localRepositoryRoots = []string{tmpRoot}
	defer func() { _localRepositoryRoots = []string{} }()

	var cloneArgs _cloneArgs
	var updateArgs _updateArgs

	var originalGitBackend = GitBackend
	GitBackend = &VCSBackend{
		Clone: func(remote *url.URL, local string, shallow bool) error {
			cloneArgs = _cloneArgs{
				remote:  remote,
				local:   local,
				shallow: shallow,
			}
			return nil
		},
		Update: func(local string) error {
			updateArgs = _updateArgs{
				local: local,
			}
			return nil
		},
	}
	defer func() { GitBackend = originalGitBackend }()

	block(tmpRoot, &cloneArgs, &updateArgs)
}

func TestCommandGet(t *testing.T) {
	RegisterTestingT(t)

	app := newApp()

	withFakeGitBackend(t, func(tmpRoot string, cloneArgs *_cloneArgs, updateArgs *_updateArgs) {
		localDir := filepath.Join(tmpRoot, "github.com", "motemen", "ghq-test-repo")

		app.Run([]string{"", "get", "motemen/ghq-test-repo"})

		Expect(cloneArgs.remote.String()).To(Equal("https://github.com/motemen/ghq-test-repo"))
		Expect(cloneArgs.local).To(Equal(localDir))
		Expect(cloneArgs.shallow).To(Equal(false))
	})

	withFakeGitBackend(t, func(tmpRoot string, cloneArgs *_cloneArgs, updateArgs *_updateArgs) {
		localDir := filepath.Join(tmpRoot, "github.com", "motemen", "ghq-test-repo")

		app.Run([]string{"", "get", "-p", "motemen/ghq-test-repo"})

		Expect(cloneArgs.remote.String()).To(Equal("ssh://git@github.com/motemen/ghq-test-repo"))
		Expect(cloneArgs.local).To(Equal(localDir))
	})

	withFakeGitBackend(t, func(tmpRoot string, cloneArgs *_cloneArgs, updateArgs *_updateArgs) {
		localDir := filepath.Join(tmpRoot, "github.com", "motemen", "ghq-test-repo")
		// mark as "already cloned", the condition may change later
		os.MkdirAll(filepath.Join(localDir, ".git"), 0755)

		app.Run([]string{"", "get", "-u", "motemen/ghq-test-repo"})

		Expect(updateArgs.local).To(Equal(localDir))
	})

	withFakeGitBackend(t, func(tmpRoot string, cloneArgs *_cloneArgs, updateArgs *_updateArgs) {
		localDir := filepath.Join(tmpRoot, "github.com", "motemen", "ghq-test-repo")
		app.Run([]string{"", "get", "-p", "motemen/ghq-test-repo"})

		Expect(cloneArgs.remote.String()).To(Equal("ssh://git@github.com/motemen/ghq-test-repo"))
		Expect(cloneArgs.local).To(Equal(localDir))
		Expect(cloneArgs.shallow).To(Equal(false))
	})

	withFakeGitBackend(t, func(tmpRoot string, cloneArgs *_cloneArgs, updateArgs *_updateArgs) {
		localDir := filepath.Join(tmpRoot, "github.com", "motemen", "ghq-test-repo")

		app.Run([]string{"", "get", "-shallow", "motemen/ghq-test-repo"})

		Expect(cloneArgs.remote.String()).To(Equal("https://github.com/motemen/ghq-test-repo"))
		Expect(cloneArgs.local).To(Equal(localDir))
		Expect(cloneArgs.shallow).To(Equal(true))
	})

	withFakeGitBackend(t, func(tmpRoot string, cloneArgs *_cloneArgs, updateArgs *_updateArgs) {
		localDir := filepath.Join(tmpRoot, "github.com", "motemen")
		os.MkdirAll(localDir, 0755)
		wd, _ := os.Getwd()
		defer os.Chdir(wd)
		os.Chdir(localDir)

		app.Run([]string{"", "get", "-u", "ghq-test-repo"})

		Expect(cloneArgs.remote.String()).To(Equal("https://github.com/motemen/ghq-test-repo"))
		Expect(cloneArgs.local).To(Equal(filepath.Join(localDir, "ghq-test-repo")))
	})
}

func TestCommandList(t *testing.T) {
	RegisterTestingT(t)

	_, _, err := capture(func() {
		app := cli.NewApp()
		flagSet := flagSet("list", commandList.Flags)
		c := cli.NewContext(app, flagSet, flagSet)

		doList(c)
	})

	Expect(err).To(BeNil())
}

func TestCommandListUnique(t *testing.T) {
	RegisterTestingT(t)

	_, _, err := capture(func() {
		app := cli.NewApp()
		flagSet := flagSet("list", commandList.Flags)
		flagSet.Parse([]string{"--unique"})
		c := cli.NewContext(app, flagSet, flagSet)

		doList(c)
	})

	Expect(err).To(BeNil())
}

func TestCommandListUnknown(t *testing.T) {
	RegisterTestingT(t)

	_, _, err := capture(func() {
		app := cli.NewApp()
		flagSet := flagSet("list", commandList.Flags)
		flagSet.Parse([]string{"--unknown-flag"})
		c := cli.NewContext(app, flagSet, flagSet)

		doList(c)
	})

	Expect(err).To(BeNil())
}
<|endoftext|>


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

package integration

import (
	"encoding/base64"
	"fmt"
	"io/ioutil"
	"os"
	"regexp"
	"time"
)

var clusterName = "integration-test"
var projectID = os.Getenv("GCE_PROJECT_ID")

type gceClusterManager struct {
	ipAddress string
}

func (g *gceClusterManager) Name() string {
	return "gce"
}

func (g *gceClusterManager) Provisioner() string {
	return "kubernetes"
}

func (g *gceClusterManager) IP(env *Environment) string {
	return g.ipAddress
}

func (g *gceClusterManager) Start(env *Environment) *Result {
	gcloud := NewCommand("gcloud").WithArgs
	res := gcloud("container", "clusters", "create", clusterName, "--project", projectID, "--num-nodes", "1").WithTimeout(15 * time.Minute).Run(env)
	regex := regexp.MustCompile(`\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}`)
	parts := regex.FindStringSubmatch(res.Stdout.String())
	if len(parts) == 1 {
		g.ipAddress = parts[0]
	}
	return res
}

func (g *gceClusterManager) Delete(env *Environment) *Result {
	gcloud := NewCommand("gcloud").WithArgs
	return gcloud("container", "clusters", "delete", clusterName, "--project", projectID, "--async").Run(env)
}

func (g *gceClusterManager) credentials(env *Environment) (map[string]string, error) {
	credentials := make(map[string]string)
	gcloud := NewCommand("gcloud").WithArgs
	res := gcloud("container", "clusters", "describe", clusterName, "--project", projectID).Run(env)
	regex := regexp.MustCompile(`username: (.*)`)
	parts := regex.FindStringSubmatch(res.Stdout.String())
	if len(parts) == 1 {
		credentials["username"] = parts[0]
	}
	regex = regexp.MustCompile(`password: (.*)`)
	parts = regex.FindStringSubmatch(res.Stdout.String())
	if len(parts) == 1 {
		credentials["password"] = parts[0]
	}
	regex = regexp.MustCompile(`clusterCaCertificate`)
	parts = regex.FindStringSubmatch(res.Stdout.String())
	if len(parts) == 1 {
		contents, err := base64.StdEncoding.DecodeString(parts[0])
		if err != nil {
			return credentials, err
		}
		tmpfile, err := ioutil.TempFile("", "gce-ca")
		if err != nil {
			return credentials, err
		}
		if _, err := tmpfile.Write(contents); err != nil {
			return credentials, err
		}
		if err := tmpfile.Close(); err != nil {
			return credentials, err
		}
		credentials["certificateFilename"] = tmpfile.Name()
	}
	return credentials, nil
}

func (g *gceClusterManager) UpdateParams(env *Environment) []string {
	address := fmt.Sprintf("https://%s", g.IP(env))
	credentials, err := g.credentials(env)
	if err != nil {
		return []string{}
	}
	return []string{"--addr", address, "--custom", "username=" + credentials["username"], "--custom", "password=" + credentials["password"], "--cacert", credentials["certificateFilename"]}
}
<commit_msg>integration: add confirmation for gce cluster deletion<commit_after>// Copyright 2017 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package integration

import (
	"encoding/base64"
	"fmt"
	"io/ioutil"
	"os"
	"regexp"
	"time"
)

var clusterName = "integration-test"
var projectID = os.Getenv("GCE_PROJECT_ID")

type gceClusterManager struct {
	ipAddress string
}

func (g *gceClusterManager) Name() string {
	return "gce"
}

func (g *gceClusterManager) Provisioner() string {
	return "kubernetes"
}

func (g *gceClusterManager) IP(env *Environment) string {
	return g.ipAddress
}

func (g *gceClusterManager) Start(env *Environment) *Result {
	gcloud := NewCommand("gcloud").WithArgs
	res := gcloud("container", "clusters", "create", clusterName, "--project", projectID, "--num-nodes", "1").WithTimeout(15 * time.Minute).Run(env)
	regex := regexp.MustCompile(`\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}`)
	parts := regex.FindStringSubmatch(res.Stdout.String())
	if len(parts) == 1 {
		g.ipAddress = parts[0]
	}
	return res
}

func (g *gceClusterManager) Delete(env *Environment) *Result {
	gcloud := NewCommand("gcloud").WithArgs
	return gcloud("container", "clusters", "delete", clusterName, "--project", projectID, "--async").WithInput("y").Run(env)
}

func (g *gceClusterManager) credentials(env *Environment) (map[string]string, error) {
	credentials := make(map[string]string)
	gcloud := NewCommand("gcloud").WithArgs
	res := gcloud("container", "clusters", "describe", clusterName, "--project", projectID).Run(env)
	regex := regexp.MustCompile(`username: (.*)`)
	parts := regex.FindStringSubmatch(res.Stdout.String())
	if len(parts) == 1 {
		credentials["username"] = parts[0]
	}
	regex = regexp.MustCompile(`password: (.*)`)
	parts = regex.FindStringSubmatch(res.Stdout.String())
	if len(parts) == 1 {
		credentials["password"] = parts[0]
	}
	regex = regexp.MustCompile(`clusterCaCertificate`)
	parts = regex.FindStringSubmatch(res.Stdout.String())
	if len(parts) == 1 {
		contents, err := base64.StdEncoding.DecodeString(parts[0])
		if err != nil {
			return credentials, err
		}
		tmpfile, err := ioutil.TempFile("", "gce-ca")
		if err != nil {
			return credentials, err
		}
		if _, err := tmpfile.Write(contents); err != nil {
			return credentials, err
		}
		if err := tmpfile.Close(); err != nil {
			return credentials, err
		}
		credentials["certificateFilename"] = tmpfile.Name()
	}
	return credentials, nil
}

func (g *gceClusterManager) UpdateParams(env *Environment) []string {
	address := fmt.Sprintf("https://%s", g.IP(env))
	credentials, err := g.credentials(env)
	if err != nil {
		return []string{}
	}
	return []string{"--addr", address, "--custom", "username=" + credentials["username"], "--custom", "password=" + credentials["password"], "--cacert", credentials["certificateFilename"]}
}
<|endoftext|>