<commit_before>package utils

import (
	"bytes"
	"crypto/md5"
	"database/sql"
	"encoding/hex"
	"errors"
	"fmt"
	"image"
	_ "image/gif"
	_ "image/jpeg"
	_ "image/png"
	"io"
	"math/rand"
	"mime/multipart"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	"github.com/eirka/eirka-libs/amazon"
	"github.com/eirka/eirka-libs/config"
	"github.com/eirka/eirka-libs/db"
	_ "github.com/eirka/eirka-libs/errors"

	local "github.com/eirka/eirka-post/config"
)

// valid file extensions
var validExt = map[string]bool{
	".jpg":  true,
	".jpeg": true,
	".png":  true,
	".gif":  true,
	".webm": true,
}

type ImageType struct {
	File        multipart.File
	Header      *multipart.FileHeader
	Ib          uint
	Filename    string
	Thumbnail   string
	Filepath    string
	Thumbpath   string
	Ext         string
	MD5         string
	OrigWidth   int
	OrigHeight  int
	ThumbWidth  int
	ThumbHeight int
	image       *bytes.Buffer
	mime        string
	duration    int
	video       bool
	avatar      bool
}

func (i *ImageType) IsValid() bool {

	if i.Filename == "" {
		return false
	}

	if i.Filepath == "" {
		return false
	}

	if i.Thumbnail == "" {
		return false
	}

	if i.Thumbpath == "" {
		return false
	}

	if i.Ib == 0 {
		return false
	}

	if i.Ext == "" {
		return false
	}

	if i.MD5 == "" {
		return false
	}

	if i.mime == "" {
		return false
	}

	return true
}

func (i *ImageType) IsValidPost() bool {
	if i.OrigWidth == 0 {
		return false
	}

	if i.OrigHeight == 0 {
		return false
	}

	if i.ThumbWidth == 0 {
		return false
	}

	if i.ThumbHeight == 0 {
		return false
	}

	return true
}

// save an image file
func (i *ImageType) SaveImage() (err error) {

	// check given file ext
	err = i.checkReqExt()
	if err != nil {
		return
	}

	// get file md5
	err = i.getMD5()
	if err != nil {
		return
	}

	// check to see if the file already exists
	err = i.checkDuplicate()
	if err != nil {
		return
	}

	// check file magic sig
	err = i.checkMagic()
	if err != nil {
		return
	}

	// check image stats
	err = i.getStats()
	if err != nil {
		return
	}

	// save the file to disk
	err = i.saveFile()
	if err != nil {
		return
	}

	// process a webm
	if i.video {
		// check the webm info
		err = i.checkWebM()
		if err != nil {
			return
		}

		// create thumbnail from webm
		err = i.createWebMThumbnail()
		if err != nil {
			return
		}

	}

	// create a thumbnail
	err = i.createThumbnail(config.Settings.Limits.ThumbnailMaxWidth, config.Settings.Limits.ThumbnailMaxHeight)
	if err != nil {
		return
	}

	// copy the file to s3
	err = i.copyToS3()
	if err != nil {
		return
	}

	// check final state
	if !i.IsValidPost() {
		return errors.New("ImageType is not valid")
	}

	return

}

// Get file extension from request header
func (i *ImageType) checkReqExt() (err error) {
	// Get ext from request header
	name := i.Header.Filename
	ext := filepath.Ext(name)

	if ext == "" {
		return errors.New("No file extension")
	}

	// Check to see if extension is allowed
	if !isAllowedExt(ext) {
		return errors.New("Format not supported")
	}

	return

}

// Check if file ext allowed
func isAllowedExt(ext string) bool {
	return validExt[strings.ToLower(ext)]
}

// Get image MD5 and write file into buffer
func (i *ImageType) getMD5() (err error) {

	defer i.File.Close()

	hasher := md5.New()

	i.image = new(bytes.Buffer)

	// Save file and also read into hasher for md5
	_, err = io.Copy(i.image, io.TeeReader(i.File, hasher))
	if err != nil {
		return errors.New("Problem copying file")
	}

	// Set md5sum from hasher
	i.MD5 = hex.EncodeToString(hasher.Sum(nil))

	return

}

// check if the md5 is already in the database
func (i *ImageType) checkDuplicate() (err error) {

	// Get Database handle
	dbase, err := db.GetDb()
	if err != nil {
		return
	}

	if i.Ib == 0 {
		return errors.New("No imageboard set on duplicate check")
	}

	var check bool
	var thread, post sql.NullInt64

	err = dbase.QueryRow(`select count(1),posts.post_num,threads.thread_id from threads
	LEFT JOIN posts on threads.thread_id = posts.thread_id
	LEFT JOIN images on posts.post_id = images.post_id
	WHERE image_hash = ? AND ib_id = ?`, i.MD5, i.Ib).Scan(&check, &post, &thread)
	if err != nil {
		return
	}

	// return error if it exists
	if check {
		return fmt.Errorf("Image has already been posted. Thread: %d Post: %d", thread.Int64, post.Int64)
	}

	return
}

func (i *ImageType) checkMagic() (err error) {

	// detect the mime type
	i.mime = http.DetectContentType(i.image.Bytes())

	switch i.mime {
	case "image/png":
		i.Ext = ".png"
	case "image/jpeg":
		i.Ext = ".jpg"
	case "image/gif":
		i.Ext = ".gif"
	case "video/webm":
		i.Ext = ".webm"
		i.video = true
	default:
		return errors.New("Unknown file type")
	}

	// Check to see if extension is allowed
	if !isAllowedExt(i.Ext) {
		return errors.New("Format not supported")
	}

	return

}

func (i *ImageType) getStats() (err error) {

	// skip if its a video since we cant decode it
	if i.video {
		return
	}

	// decode image config
	img, _, err := image.DecodeConfig(bytes.NewReader(i.image.Bytes()))
	if err != nil {
		return errors.New("Problem decoding image")
	}

	// set original width
	i.OrigWidth = img.Width
	// set original height
	i.OrigHeight = img.Height

	// Check against maximum sizes
	switch {
	case i.OrigWidth > config.Settings.Limits.ImageMaxWidth:
		return errors.New("Image width too large")
	case img.Width < config.Settings.Limits.ImageMinWidth:
		return errors.New("Image width too small")
	case i.OrigHeight > config.Settings.Limits.ImageMaxHeight:
		return errors.New("Image height too large")
	case img.Height < config.Settings.Limits.ImageMinHeight:
		return errors.New("Image height too small")
	case i.image.Len() > config.Settings.Limits.ImageMaxSize:
		return errors.New("Image size too large")
	}

	return

}

func (i *ImageType) saveFile() (err error) {

	defer i.image.Reset()

	i.makeFilenames()

	// avatar filename is the users id
	if i.avatar {
		i.Thumbnail = fmt.Sprintf("%d.png", i.Ib)
		i.Thumbpath = filepath.Join(local.Settings.Directories.ThumbnailDir, i.Thumbnail)
	}

	if !i.IsValid() {
		return errors.New("ImageType is not valid")
	}

	imagefile := filepath.Join(local.Settings.Directories.ImageDir, i.Filename)

	image, err := os.Create(imagefile)
	if err != nil {
		return errors.New("Problem saving file")
	}
	defer image.Close()

	_, err = io.Copy(image, bytes.NewReader(i.image.Bytes()))
	if err != nil {
		return errors.New("Problem saving file")
	}

	return

}

// Make a random unix time filename
func (i *ImageType) makeFilenames() {

	// Create seed for random
	rand.Seed(time.Now().UnixNano())

	// Get random 3 digit int to append to unix time
	rand_t := rand.Intn(899) + 100

	// Get current unix time
	time_t := time.Now().Unix()

	// Append random int to unix time
	file_t := fmt.Sprintf("%d%d", time_t, rand_t)

	// Append ext to filename
	i.Filename = fmt.Sprintf("%s%s", file_t, i.Ext)

	// Append jpg to thumbnail name because it is always a jpg
	i.Thumbnail = fmt.Sprintf("%ss.jpg", file_t)

	// set the full file path
	i.Filepath = filepath.Join(local.Settings.Directories.ImageDir, i.Filename)

	// set the full thumbnail path
	i.Thumbpath = filepath.Join(local.Settings.Directories.ThumbnailDir, i.Thumbnail)

	return

}

func (i *ImageType) createThumbnail(maxwidth, maxheight int) (err error) {

	var imagef string

	if i.video {
		imagef = fmt.Sprintf("%s[0]", i.Thumbpath)
	} else {
		imagef = fmt.Sprintf("%s[0]", i.Filepath)
	}

	orig_dimensions := fmt.Sprintf("%dx%d", i.OrigWidth, i.OrigHeight)

	var args []string

	// different options for avatars
	if i.avatar {
		args = []string{
			"-size",
			orig_dimensions,
			imagef,
			"-background",
			"none",
			"-thumbnail",
			fmt.Sprintf("%dx%d^", maxwidth, maxheight),
			"-gravity",
			"center",
			"-extent",
			fmt.Sprintf("%dx%d", maxwidth, maxheight),
			i.Thumbpath,
		}
	} else {
		args = []string{
			"-background",
			"white",
			"-flatten",
			"-size",
			orig_dimensions,
			"-resize",
			fmt.Sprintf("%dx%d>", maxwidth, maxheight),
			"-quality",
			"90",
			imagef,
			i.Thumbpath,
		}
	}

	_, err = exec.Command("convert", args...).Output()
	if err != nil {
		return errors.New("Problem making thumbnail")
	}

	thumb, err := os.Open(i.Thumbpath)
	if err != nil {
		return errors.New("Problem creating thumbnail file")
	}
	defer thumb.Close()

	img, _, err := image.DecodeConfig(thumb)
	if err != nil {
		return errors.New("Problem decoding thumbnail")
	}

	i.ThumbWidth = img.Width
	i.ThumbHeight = img.Height

	return

}

func (i *ImageType) copyToS3() (err error) {

	s3 := amazon.New()

	err = s3.Save(i.Filepath, fmt.Sprintf("src/%s", i.Filename), i.mime, false)
	if err != nil {
		return
	}

	err = s3.Save(i.Thumbpath, fmt.Sprintf("thumb/%s", i.Thumbnail), "image/jpeg", false)
	if err != nil {
		return
	}

	return
}
<commit_msg>image interface<commit_after>package utils

import (
	"bytes"
	"crypto/md5"
	"database/sql"
	"encoding/hex"
	"errors"
	"fmt"
	"image"
	_ "image/gif"
	_ "image/jpeg"
	_ "image/png"
	"io"
	"math/rand"
	"mime/multipart"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	"github.com/eirka/eirka-libs/amazon"
	"github.com/eirka/eirka-libs/config"
	"github.com/eirka/eirka-libs/db"
	_ "github.com/eirka/eirka-libs/errors"

	local "github.com/eirka/eirka-post/config"
)

// valid file extensions
var validExt = map[string]bool{
	".jpg":  true,
	".jpeg": true,
	".png":  true,
	".gif":  true,
	".webm": true,
}

type FileUploader interface {
	// struct integrity
	IsValid() bool
	IsValidPost() bool

	// image processing
	SaveImage() (err error)
	checkReqExt() (err error)
	getMD5() (err error)
	checkDuplicate() (err error)
	checkMagic() (err error)
	getStats() (err error)
	saveFile() (err error)
	makeFilenames()
	createThumbnail(maxwidth, maxheight int) (err error)
	copyToS3() (err error)

	// webm specific functions
	checkWebM() (err error)
	createWebMThumbnail() (err error)

	// avatar functions
	SaveAvatar() (err error)
	avatarToS3() (err error)
}

type ImageType struct {
	File        multipart.File
	Header      *multipart.FileHeader
	Ib          uint
	Filename    string
	Thumbnail   string
	Filepath    string
	Thumbpath   string
	Ext         string
	MD5         string
	OrigWidth   int
	OrigHeight  int
	ThumbWidth  int
	ThumbHeight int
	image       *bytes.Buffer
	mime        string
	duration    int
	video       bool
	avatar      bool
}

var _ = FileUploader(&ImageType)

func (i *ImageType) IsValid() bool {

	if i.Filename == "" {
		return false
	}

	if i.Filepath == "" {
		return false
	}

	if i.Thumbnail == "" {
		return false
	}

	if i.Thumbpath == "" {
		return false
	}

	if i.Ib == 0 {
		return false
	}

	if i.Ext == "" {
		return false
	}

	if i.MD5 == "" {
		return false
	}

	if i.mime == "" {
		return false
	}

	return true
}

func (i *ImageType) IsValidPost() bool {
	if i.OrigWidth == 0 {
		return false
	}

	if i.OrigHeight == 0 {
		return false
	}

	if i.ThumbWidth == 0 {
		return false
	}

	if i.ThumbHeight == 0 {
		return false
	}

	return true
}

// save an image file
func (i *ImageType) SaveImage() (err error) {

	// check given file ext
	err = i.checkReqExt()
	if err != nil {
		return
	}

	// get file md5
	err = i.getMD5()
	if err != nil {
		return
	}

	// check to see if the file already exists
	err = i.checkDuplicate()
	if err != nil {
		return
	}

	// check file magic sig
	err = i.checkMagic()
	if err != nil {
		return
	}

	// check image stats
	err = i.getStats()
	if err != nil {
		return
	}

	// save the file to disk
	err = i.saveFile()
	if err != nil {
		return
	}

	// process a webm
	if i.video {
		// check the webm info
		err = i.checkWebM()
		if err != nil {
			return
		}

		// create thumbnail from webm
		err = i.createWebMThumbnail()
		if err != nil {
			return
		}

	}

	// create a thumbnail
	err = i.createThumbnail(config.Settings.Limits.ThumbnailMaxWidth, config.Settings.Limits.ThumbnailMaxHeight)
	if err != nil {
		return
	}

	// copy the file to s3
	err = i.copyToS3()
	if err != nil {
		return
	}

	// check final state
	if !i.IsValidPost() {
		return errors.New("ImageType is not valid")
	}

	return

}

// Get file extension from request header
func (i *ImageType) checkReqExt() (err error) {
	// Get ext from request header
	name := i.Header.Filename
	ext := filepath.Ext(name)

	if ext == "" {
		return errors.New("No file extension")
	}

	// Check to see if extension is allowed
	if !isAllowedExt(ext) {
		return errors.New("Format not supported")
	}

	return

}

// Check if file ext allowed
func isAllowedExt(ext string) bool {
	return validExt[strings.ToLower(ext)]
}

// Get image MD5 and write file into buffer
func (i *ImageType) getMD5() (err error) {

	defer i.File.Close()

	hasher := md5.New()

	i.image = new(bytes.Buffer)

	// Save file and also read into hasher for md5
	_, err = io.Copy(i.image, io.TeeReader(i.File, hasher))
	if err != nil {
		return errors.New("Problem copying file")
	}

	// Set md5sum from hasher
	i.MD5 = hex.EncodeToString(hasher.Sum(nil))

	return

}

// check if the md5 is already in the database
func (i *ImageType) checkDuplicate() (err error) {

	// Get Database handle
	dbase, err := db.GetDb()
	if err != nil {
		return
	}

	if i.Ib == 0 {
		return errors.New("No imageboard set on duplicate check")
	}

	var check bool
	var thread, post sql.NullInt64

	err = dbase.QueryRow(`select count(1),posts.post_num,threads.thread_id from threads
	LEFT JOIN posts on threads.thread_id = posts.thread_id
	LEFT JOIN images on posts.post_id = images.post_id
	WHERE image_hash = ? AND ib_id = ?`, i.MD5, i.Ib).Scan(&check, &post, &thread)
	if err != nil {
		return
	}

	// return error if it exists
	if check {
		return fmt.Errorf("Image has already been posted. Thread: %d Post: %d", thread.Int64, post.Int64)
	}

	return
}

func (i *ImageType) checkMagic() (err error) {

	// detect the mime type
	i.mime = http.DetectContentType(i.image.Bytes())

	switch i.mime {
	case "image/png":
		i.Ext = ".png"
	case "image/jpeg":
		i.Ext = ".jpg"
	case "image/gif":
		i.Ext = ".gif"
	case "video/webm":
		i.Ext = ".webm"
		i.video = true
	default:
		return errors.New("Unknown file type")
	}

	// Check to see if extension is allowed
	if !isAllowedExt(i.Ext) {
		return errors.New("Format not supported")
	}

	return

}

func (i *ImageType) getStats() (err error) {

	// skip if its a video since we cant decode it
	if i.video {
		return
	}

	// decode image config
	img, _, err := image.DecodeConfig(bytes.NewReader(i.image.Bytes()))
	if err != nil {
		return errors.New("Problem decoding image")
	}

	// set original width
	i.OrigWidth = img.Width
	// set original height
	i.OrigHeight = img.Height

	// Check against maximum sizes
	switch {
	case i.OrigWidth > config.Settings.Limits.ImageMaxWidth:
		return errors.New("Image width too large")
	case img.Width < config.Settings.Limits.ImageMinWidth:
		return errors.New("Image width too small")
	case i.OrigHeight > config.Settings.Limits.ImageMaxHeight:
		return errors.New("Image height too large")
	case img.Height < config.Settings.Limits.ImageMinHeight:
		return errors.New("Image height too small")
	case i.image.Len() > config.Settings.Limits.ImageMaxSize:
		return errors.New("Image size too large")
	}

	return

}

func (i *ImageType) saveFile() (err error) {

	defer i.image.Reset()

	i.makeFilenames()

	// avatar filename is the users id
	if i.avatar {
		i.Thumbnail = fmt.Sprintf("%d.png", i.Ib)
		i.Thumbpath = filepath.Join(local.Settings.Directories.ThumbnailDir, i.Thumbnail)
	}

	if !i.IsValid() {
		return errors.New("ImageType is not valid")
	}

	imagefile := filepath.Join(local.Settings.Directories.ImageDir, i.Filename)

	image, err := os.Create(imagefile)
	if err != nil {
		return errors.New("Problem saving file")
	}
	defer image.Close()

	_, err = io.Copy(image, bytes.NewReader(i.image.Bytes()))
	if err != nil {
		return errors.New("Problem saving file")
	}

	return

}

// Make a random unix time filename
func (i *ImageType) makeFilenames() {

	// Create seed for random
	rand.Seed(time.Now().UnixNano())

	// Get random 3 digit int to append to unix time
	rand_t := rand.Intn(899) + 100

	// Get current unix time
	time_t := time.Now().Unix()

	// Append random int to unix time
	file_t := fmt.Sprintf("%d%d", time_t, rand_t)

	// Append ext to filename
	i.Filename = fmt.Sprintf("%s%s", file_t, i.Ext)

	// Append jpg to thumbnail name because it is always a jpg
	i.Thumbnail = fmt.Sprintf("%ss.jpg", file_t)

	// set the full file path
	i.Filepath = filepath.Join(local.Settings.Directories.ImageDir, i.Filename)

	// set the full thumbnail path
	i.Thumbpath = filepath.Join(local.Settings.Directories.ThumbnailDir, i.Thumbnail)

	return

}

func (i *ImageType) createThumbnail(maxwidth, maxheight int) (err error) {

	var imagef string

	if i.video {
		imagef = fmt.Sprintf("%s[0]", i.Thumbpath)
	} else {
		imagef = fmt.Sprintf("%s[0]", i.Filepath)
	}

	orig_dimensions := fmt.Sprintf("%dx%d", i.OrigWidth, i.OrigHeight)

	var args []string

	// different options for avatars
	if i.avatar {
		args = []string{
			"-size",
			orig_dimensions,
			imagef,
			"-background",
			"none",
			"-thumbnail",
			fmt.Sprintf("%dx%d^", maxwidth, maxheight),
			"-gravity",
			"center",
			"-extent",
			fmt.Sprintf("%dx%d", maxwidth, maxheight),
			i.Thumbpath,
		}
	} else {
		args = []string{
			"-background",
			"white",
			"-flatten",
			"-size",
			orig_dimensions,
			"-resize",
			fmt.Sprintf("%dx%d>", maxwidth, maxheight),
			"-quality",
			"90",
			imagef,
			i.Thumbpath,
		}
	}

	_, err = exec.Command("convert", args...).Output()
	if err != nil {
		return errors.New("Problem making thumbnail")
	}

	thumb, err := os.Open(i.Thumbpath)
	if err != nil {
		return errors.New("Problem creating thumbnail file")
	}
	defer thumb.Close()

	img, _, err := image.DecodeConfig(thumb)
	if err != nil {
		return errors.New("Problem decoding thumbnail")
	}

	i.ThumbWidth = img.Width
	i.ThumbHeight = img.Height

	return

}

func (i *ImageType) copyToS3() (err error) {

	s3 := amazon.New()

	err = s3.Save(i.Filepath, fmt.Sprintf("src/%s", i.Filename), i.mime, false)
	if err != nil {
		return
	}

	err = s3.Save(i.Thumbpath, fmt.Sprintf("thumb/%s", i.Thumbnail), "image/jpeg", false)
	if err != nil {
		return
	}

	return
}
<|endoftext|>


<commit_before>package utils

import (
	"io/ioutil"
	"path"

	"github.com/codegangsta/cli"
	"github.com/enaml-ops/omg-cli/bosh"
	"github.com/enaml-ops/pluginlib/registry"
	"github.com/enaml-ops/pluginlib/util"
	"github.com/xchapter7x/lo"
)

// ClearDefaultStringSliceValue - this is simply to work around a defect in the
// cli package, where the default is appended to rather than replaced by user
// defined flags for StringSliceFlag values.
func ClearDefaultStringSliceValue(stringSliceArgs ...string) (res []string) {
	if isJustDefault(stringSliceArgs) {
		res = stringSliceArgs

	} else {
		res = stringSliceArgs[1:]
	}
	return
}

func isJustDefault(stringSliceArgs []string) bool {
	return len(stringSliceArgs) == 1
}

// GetCloudConfigCommands builds a list of CLI commands depending on
// which cloud config plugins are installed.
func GetCloudConfigCommands(target string) (commands []cli.Command) {
	files, _ := ioutil.ReadDir(target)
	for _, f := range files {
		lo.G.Debug("registering: ", f.Name())
		pluginPath := path.Join(target, f.Name())
		flags, _ := registry.RegisterCloudConfig(pluginPath)

		commands = append(commands, cli.Command{
			Name:  f.Name(),
			Usage: "deploy the " + f.Name() + " cloud config",
			Flags: flags,
			Action: func(c *cli.Context) error {
				lo.G.Debug("running the cloud config plugin")
				client, cc := registry.GetCloudConfigReference(pluginPath)
				defer client.Kill()
				lo.G.Debug("we found client and cloud config: ", client, cc)
				lo.G.Debug("meta", cc.GetMeta())
				lo.G.Debug("args: ", c.Parent().Args())

				return bosh.CloudConfigAction(c.Parent(), cc)
			},
		})
	}
	lo.G.Debug("registered cloud configs: ", registry.ListCloudConfigs())
	return
}

// GetProductCommands builds a list of CLI commands depending on which
// product plugins are installed.
func GetProductCommands(target string) (commands []cli.Command) {
	files, _ := ioutil.ReadDir(target)
	for _, f := range files {
		lo.G.Debug("registering: ", f.Name())
		pluginPath := path.Join(target, f.Name())
		flags, _ := registry.RegisterProduct(pluginPath)

		commands = append(commands, cli.Command{
			Name:  f.Name(),
			Usage: "deploy the " + f.Name() + " product",
			Flags: pluginutil.ToCliFlagArray(flags),
			Action: func(c *cli.Context) (err error) {
				client, productDeployment := registry.GetProductReference(target)
				defer client.Kill()
				return bosh.ProductAction(c.Parent(), productDeployment)
			},
		})
	}
	lo.G.Debug("registered product plugins: ", registry.ListProducts())
	return
}
<commit_msg>[#126155215] exec the plugin, not the plugin directory<commit_after>package utils

import (
	"io/ioutil"
	"path"

	"github.com/codegangsta/cli"
	"github.com/enaml-ops/omg-cli/bosh"
	"github.com/enaml-ops/pluginlib/registry"
	"github.com/enaml-ops/pluginlib/util"
	"github.com/xchapter7x/lo"
)

// ClearDefaultStringSliceValue - this is simply to work around a defect in the
// cli package, where the default is appended to rather than replaced by user
// defined flags for StringSliceFlag values.
func ClearDefaultStringSliceValue(stringSliceArgs ...string) (res []string) {
	if isJustDefault(stringSliceArgs) {
		res = stringSliceArgs

	} else {
		res = stringSliceArgs[1:]
	}
	return
}

func isJustDefault(stringSliceArgs []string) bool {
	return len(stringSliceArgs) == 1
}

// GetCloudConfigCommands builds a list of CLI commands depending on
// which cloud config plugins are installed.
func GetCloudConfigCommands(target string) (commands []cli.Command) {
	files, _ := ioutil.ReadDir(target)
	for _, f := range files {
		lo.G.Debug("registering: ", f.Name())
		pluginPath := path.Join(target, f.Name())
		flags, _ := registry.RegisterCloudConfig(pluginPath)

		commands = append(commands, cli.Command{
			Name:  f.Name(),
			Usage: "deploy the " + f.Name() + " cloud config",
			Flags: flags,
			Action: func(c *cli.Context) error {
				lo.G.Debug("running the cloud config plugin")
				client, cc := registry.GetCloudConfigReference(pluginPath)
				defer client.Kill()
				lo.G.Debug("we found client and cloud config: ", client, cc)
				lo.G.Debug("meta", cc.GetMeta())
				lo.G.Debug("args: ", c.Parent().Args())

				return bosh.CloudConfigAction(c.Parent(), cc)
			},
		})
	}
	lo.G.Debug("registered cloud configs: ", registry.ListCloudConfigs())
	return
}

// GetProductCommands builds a list of CLI commands depending on which
// product plugins are installed.
func GetProductCommands(target string) (commands []cli.Command) {
	files, _ := ioutil.ReadDir(target)
	for _, f := range files {
		lo.G.Debug("registering: ", f.Name())
		pluginPath := path.Join(target, f.Name())
		flags, _ := registry.RegisterProduct(pluginPath)

		commands = append(commands, cli.Command{
			Name:  f.Name(),
			Usage: "deploy the " + f.Name() + " product",
			Flags: pluginutil.ToCliFlagArray(flags),
			Action: func(c *cli.Context) (err error) {
				client, productDeployment := registry.GetProductReference(pluginPath)
				defer client.Kill()
				return bosh.ProductAction(c.Parent(), productDeployment)
			},
		})
	}
	lo.G.Debug("registered product plugins: ", registry.ListProducts())
	return
}
<|endoftext|>


<commit_before>package datadog

import (
	"bytes"
	"fmt"
	"log"
	"strconv"
	"strings"
	"time"

	"github.com/zorkian/go-datadog-api"

	"github.com/hashicorp/terraform/helper/hashcode"
	"github.com/hashicorp/terraform/helper/schema"
)

// GraphDefintionRequests works around the nested struct in
// https://github.com/zorkian/go-datadog-api/blob/master/dashboards.go#L16
type GraphDefintionRequests struct {
	Query   string `json:"q"`
	Stacked bool   `json:"stacked"`
}

func resourceDatadogGraph() *schema.Resource {
	return &schema.Resource{
		Create: resourceDatadogGraphCreate,
		Exists: resourceDatadogGraphExists,
		Read:   resourceDatadogGraphRead,
		Delete: resourceDatadogGraphDelete,
		Update: resourceDatadogGraphUpdate,

		Schema: map[string]*schema.Schema{
			"dashboard_id": &schema.Schema{
				Type: schema.TypeInt,
				//Computed: true,
				Required: true,
				ForceNew: true,
			},
			"title": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"viz": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"request": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				ForceNew: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"query": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
						"stacked": &schema.Schema{
							Type:     schema.TypeBool,
							Required: true,
						},
					},
				},
				Set: resourceDatadogRequestHash,
			},

			// TODO: support events.
		},
	}
}

func resourceDatadogGraphCreate(d *schema.ResourceData, meta interface{}) error {
	// This should create graphs associated with dashboards.
	// it's a virtual resource, a la "resource_vpn_connection_route"
	// hence we will need to do a bit of hacking to find out what dashboard.

	// TODO: Delete placeholder graph. See https://github.com/ojongerius/terraform-provider-datadog/issues/8

	if d.Id() == "" {
		ID := int(time.Now().Unix())
		d.SetId(strconv.Itoa(ID)) // Use seconds since Epoch, needs to be a string when saving.

		log.Printf("[INFO] Graph ID: %d", ID)
	}

	resourceDatadogGraphUpdate(d, meta)

	err := resourceDatadogGraphRetrieve(d, meta)

	if err != nil {
		return err
	}

	return nil
}

func resourceDatadogGraphExists(d *schema.ResourceData, meta interface{}) (bool, error) {
	client := meta.(*datadog.Client)

	// Verify our Dashboard(s) exist
	_, err := client.GetDashboard(d.Get("dashboard_id").(int))

	if err != nil {
		if strings.EqualFold(err.Error(), "API error: 404 Not Found") {
			return false, nil
		}

		return false, fmt.Errorf("Error retrieving dashboard: %s", err)
	}

	// Verify we exist
	err = resourceDatadogGraphRead(d, meta)

	if err != nil {
		return false, err
	}

	return true, nil
}

func resourceDatadogGraphRead(d *schema.ResourceData, meta interface{}) error {
	err := resourceDatadogGraphRetrieve(d, meta)

	if err != nil {
		return err
	}

	return nil
}

func resourceDatadogGraphRetrieve(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*datadog.Client)

	// Get the dashboard(s)
	dashBoard, err := client.GetDashboard(d.Get("dashboard_id").(int))

	if err != nil {
		return fmt.Errorf("Error retrieving associated dashboard: %s", err)
	}

	// Walk through the graphs
	for _, g := range dashBoard.Graphs {
		// If it ends with our ID, it's us:
		if strings.HasSuffix(g.Title, fmt.Sprintf("(%s)", d.Id())) {
			log.Printf("[DEBUG] Found matching graph. Start setting/saving state.")
			d.Set("dashboard_id", d.Get("dashboard_id"))
			// Save title to state, but strip ID
			d.Set("title", strings.Replace(g.Title, fmt.Sprintf(" (%s)", d.Id()), "", 1))
			d.Set("viz", g.Definition.Viz)

			// Create an empty schema to hold all the requests.
			request := &schema.Set{F: resourceDatadogRequestHash}

			for _, r := range g.Definition.Requests {
				m := make(map[string]interface{})

				if r.Query != "" {
					m["query"] = r.Query
				}

				m["stacked"] = r.Stacked

				request.Add(m)
			}

			d.Set("request", request)

			return nil

		}
	}

	// If we are still around we've not found ourselves. Set SetId to empty and Terraform will create the resource for us.
	d.SetId("")

	return nil
}

func resourceDatadogGraphUpdate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*datadog.Client)

	// Get the dashboard
	dashboard, err := client.GetDashboard(d.Get("dashboard_id").(int))

	// Make sure the mandatory placeholder is not in there
	dashboard = buildGraph("Mandatory placeholder graph", dashboard)

	if err != nil {
		return err
	}

	// Check if there are changes
	if d.HasChange("request") {
		graphDefinition := datadog.Graph{}.Definition
		graphRequests := datadog.Graph{}.Definition.Requests
		graphDefinition.Viz = d.Get("viz").(string)

		log.Printf("[DEBUG] Request has changed.")
		o, n := d.GetChange("request")
		ors := o.(*schema.Set).Difference(n.(*schema.Set))
		nrs := n.(*schema.Set).Difference(o.(*schema.Set))

		// Loop through all the old requests and delete any obsolete ones
		for _, request := range ors.List() {
			m := request.(map[string]interface{})

			// TODO: implement
			// Delete the query as it no longer exists in the config
			log.Printf("[DEBUG] Deleting graph query %s", m["query"].(string))
			log.Printf("[DEBUG] Deleting graph stacked %t", m["stacked"].(bool))

		}
		// Loop through all the new requests and append them
		for _, request := range nrs.List() {
			m := request.(map[string]interface{})

			// Add the request
			log.Printf("[DEBUG] Adding graph query %s", m["query"].(string))
			log.Printf("[DEBUG] Adding graph stacked %t", m["stacked"].(bool))
			graphRequests = append(graphRequests, GraphDefintionRequests{Query: m["query"].(string),
				Stacked: m["stacked"].(bool)})
		}

		// Add requests to the graph definition
		graphDefinition.Requests = graphRequests
		title := d.Get("title").(string) + fmt.Sprintf(" (%s)", d.Id())
		g := datadog.Graph{Title: title, Definition: graphDefinition}

		dashboard.Graphs = append(dashboard.Graphs, g) // Should be done for each
	}

	// Update/commit
	err = client.UpdateDashboard(dashboard)

	if err != nil {
		return err
	}

	return nil
}

func resourceDatadogGraphDelete(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*datadog.Client)

	// Get the dashboard
	dashboard, err := client.GetDashboard(d.Get("dashboard_id").(int))

	if err != nil {
		return fmt.Errorf("Error retrieving associated dashboard: %s", err)
	}

	// Get the dashboard without the Graph to delete
	dashboard = buildGraph(fmt.Sprintf("(%s)", d.Id()), dashboard)

	// Test if we need to reinsert the Mandatory graph
	if len(dashboard.Graphs) < 2 {
		dashboard.Graphs = createPlaceholderGraph()
	}

	// Update/commit
	err = client.UpdateDashboard(dashboard)

	if err != nil {
		return err
	}

	err = resourceDatadogGraphRetrieve(d, meta)

	if err != nil {
		return err
	}

	return nil
}

func resourceDatadogRequestHash(v interface{}) int {
	var buf bytes.Buffer
	m := v.(map[string]interface{})

	if v, ok := m["query"]; ok {
		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
	}

	if v, ok := m["stacked"]; ok {
		buf.WriteString(fmt.Sprintf("%t-", v.(bool)))
	}

	return hashcode.String(buf.String())
}

func buildGraph(title string, dashboard *datadog.Dashboard) *datadog.Dashboard {
	// Build a new slice of graphs, excluding graphs matching title.
	g := []datadog.Graph{}
	for _, r := range dashboard.Graphs {
		if r.Title == title {
			continue
		} else {
			 g = append(g, r)
		}
	}

	dashboard.Graphs = g

	return dashboard
}
<commit_msg>Make gofmt happy :)<commit_after>package datadog

import (
	"bytes"
	"fmt"
	"log"
	"strconv"
	"strings"
	"time"

	"github.com/zorkian/go-datadog-api"

	"github.com/hashicorp/terraform/helper/hashcode"
	"github.com/hashicorp/terraform/helper/schema"
)

// GraphDefintionRequests works around the nested struct in
// https://github.com/zorkian/go-datadog-api/blob/master/dashboards.go#L16
type GraphDefintionRequests struct {
	Query   string `json:"q"`
	Stacked bool   `json:"stacked"`
}

func resourceDatadogGraph() *schema.Resource {
	return &schema.Resource{
		Create: resourceDatadogGraphCreate,
		Exists: resourceDatadogGraphExists,
		Read:   resourceDatadogGraphRead,
		Delete: resourceDatadogGraphDelete,
		Update: resourceDatadogGraphUpdate,

		Schema: map[string]*schema.Schema{
			"dashboard_id": &schema.Schema{
				Type: schema.TypeInt,
				//Computed: true,
				Required: true,
				ForceNew: true,
			},
			"title": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"viz": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"request": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				ForceNew: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"query": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
						"stacked": &schema.Schema{
							Type:     schema.TypeBool,
							Required: true,
						},
					},
				},
				Set: resourceDatadogRequestHash,
			},

			// TODO: support events.
		},
	}
}

func resourceDatadogGraphCreate(d *schema.ResourceData, meta interface{}) error {
	// This should create graphs associated with dashboards.
	// it's a virtual resource, a la "resource_vpn_connection_route"
	// hence we will need to do a bit of hacking to find out what dashboard.

	// TODO: Delete placeholder graph. See https://github.com/ojongerius/terraform-provider-datadog/issues/8

	if d.Id() == "" {
		ID := int(time.Now().Unix())
		d.SetId(strconv.Itoa(ID)) // Use seconds since Epoch, needs to be a string when saving.

		log.Printf("[INFO] Graph ID: %d", ID)
	}

	resourceDatadogGraphUpdate(d, meta)

	err := resourceDatadogGraphRetrieve(d, meta)

	if err != nil {
		return err
	}

	return nil
}

func resourceDatadogGraphExists(d *schema.ResourceData, meta interface{}) (bool, error) {
	client := meta.(*datadog.Client)

	// Verify our Dashboard(s) exist
	_, err := client.GetDashboard(d.Get("dashboard_id").(int))

	if err != nil {
		if strings.EqualFold(err.Error(), "API error: 404 Not Found") {
			return false, nil
		}

		return false, fmt.Errorf("Error retrieving dashboard: %s", err)
	}

	// Verify we exist
	err = resourceDatadogGraphRead(d, meta)

	if err != nil {
		return false, err
	}

	return true, nil
}

func resourceDatadogGraphRead(d *schema.ResourceData, meta interface{}) error {
	err := resourceDatadogGraphRetrieve(d, meta)

	if err != nil {
		return err
	}

	return nil
}

func resourceDatadogGraphRetrieve(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*datadog.Client)

	// Get the dashboard(s)
	dashBoard, err := client.GetDashboard(d.Get("dashboard_id").(int))

	if err != nil {
		return fmt.Errorf("Error retrieving associated dashboard: %s", err)
	}

	// Walk through the graphs
	for _, g := range dashBoard.Graphs {
		// If it ends with our ID, it's us:
		if strings.HasSuffix(g.Title, fmt.Sprintf("(%s)", d.Id())) {
			log.Printf("[DEBUG] Found matching graph. Start setting/saving state.")
			d.Set("dashboard_id", d.Get("dashboard_id"))
			// Save title to state, but strip ID
			d.Set("title", strings.Replace(g.Title, fmt.Sprintf(" (%s)", d.Id()), "", 1))
			d.Set("viz", g.Definition.Viz)

			// Create an empty schema to hold all the requests.
			request := &schema.Set{F: resourceDatadogRequestHash}

			for _, r := range g.Definition.Requests {
				m := make(map[string]interface{})

				if r.Query != "" {
					m["query"] = r.Query
				}

				m["stacked"] = r.Stacked

				request.Add(m)
			}

			d.Set("request", request)

			return nil

		}
	}

	// If we are still around we've not found ourselves. Set SetId to empty and Terraform will create the resource for us.
	d.SetId("")

	return nil
}

func resourceDatadogGraphUpdate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*datadog.Client)

	// Get the dashboard
	dashboard, err := client.GetDashboard(d.Get("dashboard_id").(int))

	// Make sure the mandatory placeholder is not in there
	dashboard = buildGraph("Mandatory placeholder graph", dashboard)

	if err != nil {
		return err
	}

	// Check if there are changes
	if d.HasChange("request") {
		graphDefinition := datadog.Graph{}.Definition
		graphRequests := datadog.Graph{}.Definition.Requests
		graphDefinition.Viz = d.Get("viz").(string)

		log.Printf("[DEBUG] Request has changed.")
		o, n := d.GetChange("request")
		ors := o.(*schema.Set).Difference(n.(*schema.Set))
		nrs := n.(*schema.Set).Difference(o.(*schema.Set))

		// Loop through all the old requests and delete any obsolete ones
		for _, request := range ors.List() {
			m := request.(map[string]interface{})

			// TODO: implement
			// Delete the query as it no longer exists in the config
			log.Printf("[DEBUG] Deleting graph query %s", m["query"].(string))
			log.Printf("[DEBUG] Deleting graph stacked %t", m["stacked"].(bool))

		}
		// Loop through all the new requests and append them
		for _, request := range nrs.List() {
			m := request.(map[string]interface{})

			// Add the request
			log.Printf("[DEBUG] Adding graph query %s", m["query"].(string))
			log.Printf("[DEBUG] Adding graph stacked %t", m["stacked"].(bool))
			graphRequests = append(graphRequests, GraphDefintionRequests{Query: m["query"].(string),
				Stacked: m["stacked"].(bool)})
		}

		// Add requests to the graph definition
		graphDefinition.Requests = graphRequests
		title := d.Get("title").(string) + fmt.Sprintf(" (%s)", d.Id())
		g := datadog.Graph{Title: title, Definition: graphDefinition}

		dashboard.Graphs = append(dashboard.Graphs, g) // Should be done for each
	}

	// Update/commit
	err = client.UpdateDashboard(dashboard)

	if err != nil {
		return err
	}

	return nil
}

func resourceDatadogGraphDelete(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*datadog.Client)

	// Get the dashboard
	dashboard, err := client.GetDashboard(d.Get("dashboard_id").(int))

	if err != nil {
		return fmt.Errorf("Error retrieving associated dashboard: %s", err)
	}

	// Get the dashboard without the Graph to delete
	dashboard = buildGraph(fmt.Sprintf("(%s)", d.Id()), dashboard)

	// Test if we need to reinsert the Mandatory graph
	if len(dashboard.Graphs) < 2 {
		dashboard.Graphs = createPlaceholderGraph()
	}

	// Update/commit
	err = client.UpdateDashboard(dashboard)

	if err != nil {
		return err
	}

	err = resourceDatadogGraphRetrieve(d, meta)

	if err != nil {
		return err
	}

	return nil
}

func resourceDatadogRequestHash(v interface{}) int {
	var buf bytes.Buffer
	m := v.(map[string]interface{})

	if v, ok := m["query"]; ok {
		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
	}

	if v, ok := m["stacked"]; ok {
		buf.WriteString(fmt.Sprintf("%t-", v.(bool)))
	}

	return hashcode.String(buf.String())
}

func buildGraph(title string, dashboard *datadog.Dashboard) *datadog.Dashboard {
	// Build a new slice of graphs, excluding graphs matching title.
	g := []datadog.Graph{}
	for _, r := range dashboard.Graphs {
		if r.Title == title {
			continue
		} else {
			g = append(g, r)
		}
	}

	dashboard.Graphs = g

	return dashboard
}
<|endoftext|>


<commit_before>package nsq

const VERSION = "0.1.21"
<commit_msg>bump to 0.1.22<commit_after>package nsq

const VERSION = "0.1.22"
<|endoftext|>


<commit_before>package data

import (
	"encoding/csv"
	"time"
	"fmt"
	"strconv"
	"io"
)

func CSVParse(file io.Reader) (labels []string, data []Record) {
	labels, data = csvParse(file)
	return
}

func csvParse(file io.Reader) (labels []string, data []Record) {
	reader := csv.NewReader (file)
	tmpdata, err := reader.ReadAll()
	if  err != nil {
		fmt.Println(err)
	}
	labels = make([]string, 6)
	//labels = tmpdata[0]
	data = make([]Record, len(tmpdata)-1)
	for i := 1; i<len(tmpdata)-1; i++ {
		data[i-1].Time, _ = time.Parse(ISO, tmpdata[i][0])
		data[i-1].Radiation, err = strconv.ParseFloat(tmpdata[i][1], 64)
		if err != nil {
			data[i-1].empty = true
		}
		data[i-1].Humidity, err = strconv.ParseFloat(tmpdata[i][2], 64)
		if err != nil {
			data[i-1].empty = true
		}
		data[i-1].Temperature, err = strconv.ParseFloat(tmpdata[i][2], 64)
		if err != nil {
			data[i-1].empty = true
		}
		data[i-1].Wind, err = strconv.ParseFloat(tmpdata[i][2], 64)
		if err != nil {
			data[i-1].empty = true
		}
		data[i-1].Power, err = strconv.ParseFloat(tmpdata[i][2], 64)
		if err != nil {
			data[i-1].Null = true
		}
	}
	data = fillRecords (data)
	return
}

func fillRecords (emptyData []Record) (data []Record){
	gradRad, gradHumidity, gradTemp, gradWind := 0.0, 0.0, 0.0, 0.0
	for i := 0; i<len(emptyData); i++ {
		if emptyData[i].empty && i > 0 {
			emptyData[i].Radiation = emptyData[i-1].Radiation + gradRad
			emptyData[i].Humidity = emptyData[i-1].Humidity + gradHumidity
			emptyData[i].Temperature = emptyData[i-1].Temperature + gradTemp
			emptyData[i].Wind = emptyData[i-1].Wind + gradWind
			emptyData[i].empty = false
		} else {
			if i + 4 < len (emptyData) {
				gradRad = (emptyData[i+4].Radiation - emptyData[i].Radiation)/4
				gradHumidity = (emptyData[i+4].Humidity - emptyData[i].Humidity)/4
				gradTemp = (emptyData[i+4].Temperature - emptyData[i].Temperature)/4
				gradWind = (emptyData[i+4].Wind - emptyData[i].Wind)/4
			} else {
				gradRad = 0
				gradHumidity = 0
				gradTemp = 0
				gradWind = 0
			}
		}
	}
	return
}
<commit_msg>why oh why is there a bounds error<commit_after>package data

import (
	"encoding/csv"
	"time"
	"fmt"
	"strconv"
	"io"
)

func CSVParse(file io.Reader) (labels []string, data []Record) {
	labels, data = csvParse(file)
	return
}

func csvParse(file io.Reader) (labels []string, data []Record) {
	reader := csv.NewReader (file)
	tmpdata, err := reader.ReadAll()
	if  err != nil {
		fmt.Println(err)
	}
	labels = make([]string, 6)
	//labels = tmpdata[0]
	val data []Record
	for i := 1; i<len(tmpdata)-1; i++ {
		rec := new(Record)
		rec[i-1].Time, _ = time.Parse(ISO, tmpdata[i][0])
		rec[i-1].Radiation, err = strconv.ParseFloat(tmpdata[i][1], 64)
		if err != nil {
			data[i-1].empty = true
		}
		rec[i-1].Humidity, err = strconv.ParseFloat(tmpdata[i][2], 64)
		if err != nil {
			data[i-1].empty = true
		}
		rec[i-1].Temperature, err = strconv.ParseFloat(tmpdata[i][2], 64)
		if err != nil {
			data[i-1].empty = true
		}
		rec[i-1].Wind, err = strconv.ParseFloat(tmpdata[i][2], 64)
		if err != nil {
			data[i-1].empty = true
		}
		rec[i-1].Power, err = strconv.ParseFloat(tmpdata[i][2], 64)
		if err != nil {
			data[i-1].Null = true
		}
		data = append(data, rec)
	}
	data = fillRecords (data)
	return
}

func fillRecords (emptyData []Record) (data []Record){
	gradRad, gradHumidity, gradTemp, gradWind := 0.0, 0.0, 0.0, 0.0
	for i := 0; i<len(emptyData); i++ {
		if emptyData[i].empty && i > 0 {
			emptyData[i].Radiation = emptyData[i-1].Radiation + gradRad
			emptyData[i].Humidity = emptyData[i-1].Humidity + gradHumidity
			emptyData[i].Temperature = emptyData[i-1].Temperature + gradTemp
			emptyData[i].Wind = emptyData[i-1].Wind + gradWind
			emptyData[i].empty = false
		} else {
			if i + 4 < len (emptyData) {
				gradRad = (emptyData[i+4].Radiation - emptyData[i].Radiation)/4
				gradHumidity = (emptyData[i+4].Humidity - emptyData[i].Humidity)/4
				gradTemp = (emptyData[i+4].Temperature - emptyData[i].Temperature)/4
				gradWind = (emptyData[i+4].Wind - emptyData[i].Wind)/4
			} else {
				gradRad = 0
				gradHumidity = 0
				gradTemp = 0
				gradWind = 0
			}
		}
	}
	return
}
<|endoftext|>


<commit_before>package fastly

import (
	"fmt"
	"sort"
)

// Version represents a distinct configuration version.
type Version struct {
	Number    string     `mapstructure:"number"`
	Comment   string     `mapstructure:"comment"`
	ServiceID string     `mapstructure:"service_id"`
	Active    bool       `mapstructure:"active"`
	Locked    bool       `mapstructure:"locked"`
	Deployed  bool       `mapstructure:"deployed"`
	Staging   bool       `mapstructure:"staging"`
	Testing   bool       `mapstructure:"testing"`
}

// versionsByNumber is a sortable list of versions. This is used by the version
// `List()` function to sort the API responses.
type versionsByNumber []*Version

// Len, Swap, and Less implement the sortable interface.
func (s versionsByNumber) Len() int      { return len(s) }
func (s versionsByNumber) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s versionsByNumber) Less(i, j int) bool {
	return s[i].Number < s[j].Number
}

// ListVersionsInput is the input to the ListVersions function.
type ListVersionsInput struct {
	// Service is the ID of the service (required).
	Service string
}

// ListVersions returns the full list of all versions of the given service.
func (c *Client) ListVersions(i *ListVersionsInput) ([]*Version, error) {
	if i.Service == "" {
		return nil, ErrMissingService
	}

	path := fmt.Sprintf("/service/%s/version", i.Service)
	resp, err := c.Get(path, nil)
	if err != nil {
		return nil, err
	}

	var e []*Version
	if err := decodeJSON(&e, resp.Body); err != nil {
		return nil, err
	}
	sort.Sort(versionsByNumber(e))

	return e, nil
}

// LatestVersionInput is the input to the LatestVersion function.
type LatestVersionInput struct {
	// Service is the ID of the service (required).
	Service string
}

// LatestVersion fetches the latest version. If there are no versions, this
// function will return nil (but not an error).
func (c *Client) LatestVersion(i *LatestVersionInput) (*Version, error) {
	if i.Service == "" {
		return nil, ErrMissingService
	}

	list, err := c.ListVersions(&ListVersionsInput{Service: i.Service})
	if err != nil {
		return nil, err
	}
	if len(list) < 1 {
		return nil, nil
	}

	e := list[len(list)-1]
	return e, nil
}

// CreateVersionInput is the input to the CreateVersion function.
type CreateVersionInput struct {
	// Service is the ID of the service (required).
	Service string
}

// CreateVersion constructs a new version. There are no request parameters, but
// you should consult the resulting version number. Note that `CloneVersion` is
// preferred in almost all scenarios, since `Create()` creates a _blank_
// configuration where `Clone()` builds off of an existing configuration.
func (c *Client) CreateVersion(i *CreateVersionInput) (*Version, error) {
	if i.Service == "" {
		return nil, ErrMissingService
	}

	path := fmt.Sprintf("/service/%s/version", i.Service)
	resp, err := c.Post(path, nil)
	if err != nil {
		return nil, err
	}

	var e *Version
	if err := decodeJSON(&e, resp.Body); err != nil {
		return nil, err
	}
	return e, nil
}

// GetVersionInput is the input to the GetVersion function.
type GetVersionInput struct {
	// Service is the ID of the service (required).
	Service string

	// Version is the version number to fetch (required).
	Version string
}

// GetVersion fetches a version with the given information.
func (c *Client) GetVersion(i *GetVersionInput) (*Version, error) {
	if i.Service == "" {
		return nil, ErrMissingService
	}

	if i.Version == "" {
		return nil, ErrMissingVersion
	}

	path := fmt.Sprintf("/service/%s/version/%s", i.Service, i.Version)
	resp, err := c.Get(path, nil)
	if err != nil {
		return nil, err
	}

	var e *Version
	if err := decodeJSON(&e, resp.Body); err != nil {
		return nil, err
	}
	return e, nil
}

// UpdateVersionInput is the input to the UpdateVersion function.
type UpdateVersionInput struct {
	// Service is the ID of the service. Version is the specific configuration
	// version. Both fields are required.
	Service string
	Version string

	Comment string `form:"comment,omitempty"`
}

// UpdateVersion updates the given version
func (c *Client) UpdateVersion(i *UpdateVersionInput) (*Version, error) {
	if i.Service == "" {
		return nil, ErrMissingService
	}

	if i.Version == "" {
		return nil, ErrMissingVersion
	}

	path := fmt.Sprintf("/service/%s/version/%s", i.Service, i.Version)
	resp, err := c.PutForm(path, i, nil)
	if err != nil {
		return nil, err
	}

	var e *Version
	if err := decodeJSON(&e, resp.Body); err != nil {
		return nil, err
	}
	return e, nil
}

// ActivateVersionInput is the input to the ActivateVersion function.
type ActivateVersionInput struct {
	// Service is the ID of the service. Version is the specific configuration
	// version. Both fields are required.
	Service string
	Version string
}

// ActivateVersion activates the given version.
func (c *Client) ActivateVersion(i *ActivateVersionInput) (*Version, error) {
	if i.Service == "" {
		return nil, ErrMissingService
	}

	if i.Version == "" {
		return nil, ErrMissingVersion
	}

	path := fmt.Sprintf("/service/%s/version/%s/activate", i.Service, i.Version)
	resp, err := c.Put(path, nil)
	if err != nil {
		return nil, err
	}

	var e *Version
	if err := decodeJSON(&e, resp.Body); err != nil {
		return nil, err
	}
	return e, nil
}

// DeactivateVersionInput is the input to the DeactivateVersion function.
type DeactivateVersionInput struct {
	// Service is the ID of the service. Version is the specific configuration
	// version. Both fields are required.
	Service string
	Version string
}

// DeactivateVersion deactivates the given version.
func (c *Client) DeactivateVersion(i *DeactivateVersionInput) (*Version, error) {
	if i.Service == "" {
		return nil, ErrMissingService
	}

	if i.Version == "" {
		return nil, ErrMissingVersion
	}

	path := fmt.Sprintf("/service/%s/version/%s/deactivate", i.Service, i.Version)
	resp, err := c.Put(path, nil)
	if err != nil {
		return nil, err
	}

	var e *Version
	if err := decodeJSON(&e, resp.Body); err != nil {
		return nil, err
	}
	return e, nil
}

// CloneVersionInput is the input to the CloneVersion function.
type CloneVersionInput struct {
	// Service is the ID of the service. Version is the specific configuration
	// version. Both fields are required.
	Service string
	Version string
}

// CloneVersion creates a clone of the version with and returns a new
// configuration version with all the same configuration options, but an
// incremented number.
func (c *Client) CloneVersion(i *CloneVersionInput) (*Version, error) {
	if i.Service == "" {
		return nil, ErrMissingService
	}

	if i.Version == "" {
		return nil, ErrMissingVersion
	}

	path := fmt.Sprintf("/service/%s/version/%s/clone", i.Service, i.Version)
	resp, err := c.Put(path, nil)
	if err != nil {
		return nil, err
	}

	var e *Version
	if err := decodeJSON(&e, resp.Body); err != nil {
		return nil, err
	}
	return e, nil
}

// ValidateVersionInput is the input to the ValidateVersion function.
type ValidateVersionInput struct {
	// Service is the ID of the service. Version is the specific configuration
	// version. Both fields are required.
	Service string
	Version string
}

// ValidateVersion validates if the given version is okay.
func (c *Client) ValidateVersion(i *ValidateVersionInput) (bool, string, error) {
	var msg string

	if i.Service == "" {
		return false, msg, ErrMissingService
	}

	if i.Version == "" {
		return false, msg, ErrMissingVersion
	}

	path := fmt.Sprintf("/service/%s/version/%s/validate", i.Service, i.Version)
	resp, err := c.Get(path, nil)
	if err != nil {
		return false, msg, err
	}

	var r *statusResp
	if err := decodeJSON(&r, resp.Body); err != nil {
		return false, msg, err
	}

	msg = r.Msg
	return r.Ok(), msg, nil
}

// LockVersionInput is the input to the LockVersion function.
type LockVersionInput struct {
	// Service is the ID of the service. Version is the specific configuration
	// version. Both fields are required.
	Service string
	Version string
}

// LockVersion locks the specified version.
func (c *Client) LockVersion(i *LockVersionInput) (*Version, error) {
	if i.Service == "" {
		return nil, ErrMissingService
	}

	if i.Version == "" {
		return nil, ErrMissingVersion
	}

	path := fmt.Sprintf("/service/%s/version/%s/lock", i.Service, i.Version)
	resp, err := c.Put(path, nil)
	if err != nil {
		return nil, err
	}

	var e *Version
	if err := decodeJSON(&e, resp.Body); err != nil {
		return nil, err
	}
	return e, nil
}
<commit_msg>Add Created and Updated field to Version.<commit_after>package fastly

import (
	"fmt"
	"sort"
)

// Version represents a distinct configuration version.
type Version struct {
	Number    string `mapstructure:"number"`
	Comment   string `mapstructure:"comment"`
	ServiceID string `mapstructure:"service_id"`
	Active    bool   `mapstructure:"active"`
	Locked    bool   `mapstructure:"locked"`
	Deployed  bool   `mapstructure:"deployed"`
	Staging   bool   `mapstructure:"staging"`
	Testing   bool   `mapstructure:"testing"`
	Created   string `mapstructure:"created_at"`
	Updated   string `mapstructure:"updated_at"`
}

// versionsByNumber is a sortable list of versions. This is used by the version
// `List()` function to sort the API responses.
type versionsByNumber []*Version

// Len, Swap, and Less implement the sortable interface.
func (s versionsByNumber) Len() int      { return len(s) }
func (s versionsByNumber) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s versionsByNumber) Less(i, j int) bool {
	return s[i].Number < s[j].Number
}

// ListVersionsInput is the input to the ListVersions function.
type ListVersionsInput struct {
	// Service is the ID of the service (required).
	Service string
}

// ListVersions returns the full list of all versions of the given service.
func (c *Client) ListVersions(i *ListVersionsInput) ([]*Version, error) {
	if i.Service == "" {
		return nil, ErrMissingService
	}

	path := fmt.Sprintf("/service/%s/version", i.Service)
	resp, err := c.Get(path, nil)
	if err != nil {
		return nil, err
	}

	var e []*Version
	if err := decodeJSON(&e, resp.Body); err != nil {
		return nil, err
	}
	sort.Sort(versionsByNumber(e))

	return e, nil
}

// LatestVersionInput is the input to the LatestVersion function.
type LatestVersionInput struct {
	// Service is the ID of the service (required).
	Service string
}

// LatestVersion fetches the latest version. If there are no versions, this
// function will return nil (but not an error).
func (c *Client) LatestVersion(i *LatestVersionInput) (*Version, error) {
	if i.Service == "" {
		return nil, ErrMissingService
	}

	list, err := c.ListVersions(&ListVersionsInput{Service: i.Service})
	if err != nil {
		return nil, err
	}
	if len(list) < 1 {
		return nil, nil
	}

	e := list[len(list)-1]
	return e, nil
}

// CreateVersionInput is the input to the CreateVersion function.
type CreateVersionInput struct {
	// Service is the ID of the service (required).
	Service string
}

// CreateVersion constructs a new version. There are no request parameters, but
// you should consult the resulting version number. Note that `CloneVersion` is
// preferred in almost all scenarios, since `Create()` creates a _blank_
// configuration where `Clone()` builds off of an existing configuration.
func (c *Client) CreateVersion(i *CreateVersionInput) (*Version, error) {
	if i.Service == "" {
		return nil, ErrMissingService
	}

	path := fmt.Sprintf("/service/%s/version", i.Service)
	resp, err := c.Post(path, nil)
	if err != nil {
		return nil, err
	}

	var e *Version
	if err := decodeJSON(&e, resp.Body); err != nil {
		return nil, err
	}
	return e, nil
}

// GetVersionInput is the input to the GetVersion function.
type GetVersionInput struct {
	// Service is the ID of the service (required).
	Service string

	// Version is the version number to fetch (required).
	Version string
}

// GetVersion fetches a version with the given information.
func (c *Client) GetVersion(i *GetVersionInput) (*Version, error) {
	if i.Service == "" {
		return nil, ErrMissingService
	}

	if i.Version == "" {
		return nil, ErrMissingVersion
	}

	path := fmt.Sprintf("/service/%s/version/%s", i.Service, i.Version)
	resp, err := c.Get(path, nil)
	if err != nil {
		return nil, err
	}

	var e *Version
	if err := decodeJSON(&e, resp.Body); err != nil {
		return nil, err
	}
	return e, nil
}

// UpdateVersionInput is the input to the UpdateVersion function.
type UpdateVersionInput struct {
	// Service is the ID of the service. Version is the specific configuration
	// version. Both fields are required.
	Service string
	Version string

	Comment string `form:"comment,omitempty"`
}

// UpdateVersion updates the given version
func (c *Client) UpdateVersion(i *UpdateVersionInput) (*Version, error) {
	if i.Service == "" {
		return nil, ErrMissingService
	}

	if i.Version == "" {
		return nil, ErrMissingVersion
	}

	path := fmt.Sprintf("/service/%s/version/%s", i.Service, i.Version)
	resp, err := c.PutForm(path, i, nil)
	if err != nil {
		return nil, err
	}

	var e *Version
	if err := decodeJSON(&e, resp.Body); err != nil {
		return nil, err
	}
	return e, nil
}

// ActivateVersionInput is the input to the ActivateVersion function.
type ActivateVersionInput struct {
	// Service is the ID of the service. Version is the specific configuration
	// version. Both fields are required.
	Service string
	Version string
}

// ActivateVersion activates the given version.
func (c *Client) ActivateVersion(i *ActivateVersionInput) (*Version, error) {
	if i.Service == "" {
		return nil, ErrMissingService
	}

	if i.Version == "" {
		return nil, ErrMissingVersion
	}

	path := fmt.Sprintf("/service/%s/version/%s/activate", i.Service, i.Version)
	resp, err := c.Put(path, nil)
	if err != nil {
		return nil, err
	}

	var e *Version
	if err := decodeJSON(&e, resp.Body); err != nil {
		return nil, err
	}
	return e, nil
}

// DeactivateVersionInput is the input to the DeactivateVersion function.
type DeactivateVersionInput struct {
	// Service is the ID of the service. Version is the specific configuration
	// version. Both fields are required.
	Service string
	Version string
}

// DeactivateVersion deactivates the given version.
func (c *Client) DeactivateVersion(i *DeactivateVersionInput) (*Version, error) {
	if i.Service == "" {
		return nil, ErrMissingService
	}

	if i.Version == "" {
		return nil, ErrMissingVersion
	}

	path := fmt.Sprintf("/service/%s/version/%s/deactivate", i.Service, i.Version)
	resp, err := c.Put(path, nil)
	if err != nil {
		return nil, err
	}

	var e *Version
	if err := decodeJSON(&e, resp.Body); err != nil {
		return nil, err
	}
	return e, nil
}

// CloneVersionInput is the input to the CloneVersion function.
type CloneVersionInput struct {
	// Service is the ID of the service. Version is the specific configuration
	// version. Both fields are required.
	Service string
	Version string
}

// CloneVersion creates a clone of the version with and returns a new
// configuration version with all the same configuration options, but an
// incremented number.
func (c *Client) CloneVersion(i *CloneVersionInput) (*Version, error) {
	if i.Service == "" {
		return nil, ErrMissingService
	}

	if i.Version == "" {
		return nil, ErrMissingVersion
	}

	path := fmt.Sprintf("/service/%s/version/%s/clone", i.Service, i.Version)
	resp, err := c.Put(path, nil)
	if err != nil {
		return nil, err
	}

	var e *Version
	if err := decodeJSON(&e, resp.Body); err != nil {
		return nil, err
	}
	return e, nil
}

// ValidateVersionInput is the input to the ValidateVersion function.
type ValidateVersionInput struct {
	// Service is the ID of the service. Version is the specific configuration
	// version. Both fields are required.
	Service string
	Version string
}

// ValidateVersion validates if the given version is okay.
func (c *Client) ValidateVersion(i *ValidateVersionInput) (bool, string, error) {
	var msg string

	if i.Service == "" {
		return false, msg, ErrMissingService
	}

	if i.Version == "" {
		return false, msg, ErrMissingVersion
	}

	path := fmt.Sprintf("/service/%s/version/%s/validate", i.Service, i.Version)
	resp, err := c.Get(path, nil)
	if err != nil {
		return false, msg, err
	}

	var r *statusResp
	if err := decodeJSON(&r, resp.Body); err != nil {
		return false, msg, err
	}

	msg = r.Msg
	return r.Ok(), msg, nil
}

// LockVersionInput is the input to the LockVersion function.
type LockVersionInput struct {
	// Service is the ID of the service. Version is the specific configuration
	// version. Both fields are required.
	Service string
	Version string
}

// LockVersion locks the specified version.
func (c *Client) LockVersion(i *LockVersionInput) (*Version, error) {
	if i.Service == "" {
		return nil, ErrMissingService
	}

	if i.Version == "" {
		return nil, ErrMissingVersion
	}

	path := fmt.Sprintf("/service/%s/version/%s/lock", i.Service, i.Version)
	resp, err := c.Put(path, nil)
	if err != nil {
		return nil, err
	}

	var e *Version
	if err := decodeJSON(&e, resp.Body); err != nil {
		return nil, err
	}
	return e, nil
}
<|endoftext|>


<commit_before>package main

// The git commit that was compiled. This will be filled in by the compiler.
var GitCommit string
var GitDescribe string

// The main version number that is being run at the moment.
const Version = "0.2.0"

// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
// such as "dev" (in development), "beta", "rc1", etc.
const VersionPrerelease = ""
<commit_msg>Bump version<commit_after>package main

// The git commit that was compiled. This will be filled in by the compiler.
var GitCommit string
var GitDescribe string

// The main version number that is being run at the moment.
const Version = "0.2.1"

// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
// such as "dev" (in development), "beta", "rc1", etc.
const VersionPrerelease = ""
<|endoftext|>


<commit_before>package main

const VERSION = "0.9.0-alpha1"
<commit_msg>:+1: Bump up the version to 0.9.0<commit_after>package main

const VERSION = "0.9.0"
<|endoftext|>


<commit_before>// Copyright ©2011-2013 The bíogo 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 biogo

const Version = "beta"
<commit_msg>biogo: bump version<commit_after>// Copyright ©2011-2013 The bíogo 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 biogo

const Version = "v1.0.0"
<|endoftext|>


<commit_before>package main

const VERSION = "0.9.2-alpha2"
<commit_msg>:+1: Bump up the version to 0.9.2<commit_after>package main

const VERSION = "0.9.2"
<|endoftext|>


<commit_before>package dataProcess

import (
	"../autils"
	"../config"
	"bytes"
	"database/sql"
	"github.com/gin-gonic/gin"
	"net/http"
	"strconv"
	"strings"
	"time"
)

type detailInfo struct {
	Domian       string `json:"domain"`
	TotalPv      string `json:"totalPv"`
	Pv           string `json:"pv"`
	PvRate       string `json:"pvRate"`
	EstPv        string `json:"estPv"`
	EstPvRate    string `json:"estPvRate"`
	PatternEstPv string `json:"patternEstPv"`
	Urls         string `json:"urls"`
	RecordUrl    string `json:"recordUrl"`
	RecordRate   string `json:"recordRate"`
	PassUrl      string `json:"passUrl"`
	PassRate     string `json:"passRate"`
	RelativeUrl  string `json:"relativeUrl"`
	EffectUrl    string `json:"effectUrl"`
	EffectPv     string `json:"effectPv"`
	IneffectUrl  string `json:"ineffectUrl"`
	IneffectPv   string `json:"ineffectPv"`
	ShieldUrl    string `json:"shieldUrl"`
}

type detailData struct {
	Columns []tStruct    `json:"columns"`
	Rows    []detailInfo `json:"rows"`
}

// 获取流量信息
func GetSDetail(c *gin.Context, db *sql.DB, q interface{}) {
	ts := tStruct{}
	td := detailData{}

	for i, v := range config.Titles {
		ts.Name = v
		ts.TextAlign = "center"
		ts.Id = config.Ids[i]
		td.Columns = append(td.Columns, ts)
	}

	var startDate string
	theDay := time.Now().AddDate(0, 0, -3)
	startDate = autils.GetCurrentData(theDay)

	sDate, _ := autils.AnaDate(q)
	if sDate != "" {
		vas, _ := time.Parse(shortForm, sDate)
		vasDate := autils.GetCurrentData(vas)
		startDate = vasDate
	}

	dn := autils.AnaSelect(q)

	var domain, totalPv, pv, pvRate, /*estPv, estPvRate, patternEstPv,*/
		urls, recordUrl, recordRate, passUrl, passRate, relativeUrl, effectUrl, effectPv, ineffectUrl, ineffectPv, shieldUrl string

	max := c.Query("max")
	var sqlStr bytes.Buffer
	sqlStr.WriteString("select " + strings.Join(config.Field, ",") + " from site_detail where date = ? ")
	if strings.Contains(dn, ".") {
		sqlStr.WriteString("and domain = '" + dn + "' ")
	}
	_, err := strconv.Atoi(max)
	if err == nil {
		sqlStr.WriteString(" limit " + max + "")
	}

	rows, err := db.Query(sqlStr.String(), startDate)

	autils.ErrHadle(err)
	di := detailInfo{}
	for rows.Next() {
		err := rows.Scan(&domain, &totalPv, &pv, &pvRate, /*&estPv, &estPvRate, &patternEstPv,*/
			&urls, &recordUrl, &recordRate, &passUrl, &passRate, &relativeUrl, &effectUrl, &effectPv, &ineffectUrl, &ineffectPv, &shieldUrl)
		autils.ErrHadle(err)
		di.Domian = domain
		di.TotalPv = totalPv
		di.Pv = pv
		di.PvRate = clearZero(pvRate) + "%"
		/*di.EstPvRate = estPv
		di.EstPvRate = estPvRate
		di.PatternEstPv = patternEstPv*/
		di.Urls = urls
		di.RecordUrl = recordUrl
		di.RecordRate = clearZero(recordRate) + "%"
		di.PassUrl = passUrl
		di.PassRate = clearZero(passRate) + "%"
		di.RelativeUrl = relativeUrl
		di.EffectUrl = effectUrl
		di.EffectPv = effectPv
		di.IneffectUrl = ineffectUrl
		di.IneffectPv = ineffectPv
		di.ShieldUrl = shieldUrl
		td.Rows = append(td.Rows, di)

	}
	err = rows.Err()
	autils.ErrHadle(err)

	defer rows.Close()

	c.JSON(http.StatusOK, gin.H{
		"status": 0,
		"msg":    "ok",
		"data":   td,
	})
}

func clearZero(s string) string {
	if strings.Contains(s, "0.0") {
		return "0"
	}
	return s
}
<commit_msg>add page parameters.<commit_after>package dataProcess

import (
	"../autils"
	"../config"
	"bytes"
	"database/sql"
	"github.com/gin-gonic/gin"
	"net/http"
	"strconv"
	"strings"
	"time"
)

type detailInfo struct {
	Domian       string `json:"domain"`
	TotalPv      string `json:"totalPv"`
	Pv           string `json:"pv"`
	PvRate       string `json:"pvRate"`
	EstPv        string `json:"estPv"`
	EstPvRate    string `json:"estPvRate"`
	PatternEstPv string `json:"patternEstPv"`
	Urls         string `json:"urls"`
	RecordUrl    string `json:"recordUrl"`
	RecordRate   string `json:"recordRate"`
	PassUrl      string `json:"passUrl"`
	PassRate     string `json:"passRate"`
	RelativeUrl  string `json:"relativeUrl"`
	EffectUrl    string `json:"effectUrl"`
	EffectPv     string `json:"effectPv"`
	IneffectUrl  string `json:"ineffectUrl"`
	IneffectPv   string `json:"ineffectPv"`
	ShieldUrl    string `json:"shieldUrl"`
}

type detailData struct {
	Columns []tStruct    `json:"columns"`
	Rows    []detailInfo `json:"rows"`
}

// 获取流量信息
func GetSDetail(c *gin.Context, db *sql.DB, q interface{}) {
	ts := tStruct{}
	td := detailData{}

	start := c.Query("start")
	limit := c.Query("limit")

	for i, v := range config.Titles {
		ts.Name = v
		ts.TextAlign = "center"
		ts.Id = config.Ids[i]
		td.Columns = append(td.Columns, ts)
	}

	var startDate string
	theDay := time.Now().AddDate(0, 0, -3)
	startDate = autils.GetCurrentData(theDay)

	sDate, _ := autils.AnaDate(q)
	if sDate != "" {
		vas, _ := time.Parse(shortForm, sDate)
		vasDate := autils.GetCurrentData(vas)
		startDate = vasDate
	}

	dn := autils.AnaSelect(q)

	var domain, totalPv, pv, pvRate, /*estPv, estPvRate, patternEstPv,*/
		urls, recordUrl, recordRate, passUrl, passRate, relativeUrl, effectUrl, effectPv, ineffectUrl, ineffectPv, shieldUrl string

	var sqlStr bytes.Buffer
	sqlStr.WriteString("select " + strings.Join(config.Field, ",") + " from site_detail where date = ? ")
	if strings.Contains(dn, ".") {
		sqlStr.WriteString("and domain = '" + dn + "' ")
	}
	_, err := strconv.Atoi(limit)
	if err == nil {
		sqlStr.WriteString(" limit " + limit + "")
	}

	_, err = strconv.Atoi(start)
	if err == nil {
		sqlStr.WriteString(" offset " + start + "")
	}

	rows, err := db.Query(sqlStr.String(), "'"+startDate+"'")

	autils.ErrHadle(err)
	di := detailInfo{}
	for rows.Next() {
		err := rows.Scan(&domain, &totalPv, &pv, &pvRate, /*&estPv, &estPvRate, &patternEstPv,*/
			&urls, &recordUrl, &recordRate, &passUrl, &passRate, &relativeUrl, &effectUrl, &effectPv, &ineffectUrl, &ineffectPv, &shieldUrl)
		autils.ErrHadle(err)
		di.Domian = domain
		di.TotalPv = totalPv
		di.Pv = pv
		di.PvRate = clearZero(pvRate) + "%"
		/*di.EstPvRate = estPv
		di.EstPvRate = estPvRate
		di.PatternEstPv = patternEstPv*/
		di.Urls = urls
		di.RecordUrl = recordUrl
		di.RecordRate = clearZero(recordRate) + "%"
		di.PassUrl = passUrl
		di.PassRate = clearZero(passRate) + "%"
		di.RelativeUrl = relativeUrl
		di.EffectUrl = effectUrl
		di.EffectPv = effectPv
		di.IneffectUrl = ineffectUrl
		di.IneffectPv = ineffectPv
		di.ShieldUrl = shieldUrl
		td.Rows = append(td.Rows, di)

	}
	err = rows.Err()
	autils.ErrHadle(err)

	defer rows.Close()

	c.JSON(http.StatusOK, gin.H{
		"status": 0,
		"msg":    "ok",
		"data":   td,
	})
}

func clearZero(s string) string {
	if strings.Contains(s, "0.0") {
		return "0"
	}
	return s
}
<|endoftext|>


<commit_before>package exec

import (
	"fmt"

	"github.com/Sirupsen/logrus"
	"github.com/docker/swarmkit/api"
	"github.com/docker/swarmkit/log"
	"github.com/pkg/errors"
	"golang.org/x/net/context"
)

// Controller controls execution of a task.
type Controller interface {
	// Update the task definition seen by the controller. Will return
	// ErrTaskUpdateFailed if the provided task definition changes fields that
	// cannot be changed.
	//
	// Will be ignored if the task has exited.
	Update(ctx context.Context, t *api.Task) error

	// Prepare the task for execution. This should ensure that all resources
	// are created such that a call to start should execute immediately.
	Prepare(ctx context.Context) error

	// Start the target and return when it has started successfully.
	Start(ctx context.Context) error

	// Wait blocks until the target has exited.
	Wait(ctx context.Context) error

	// Shutdown requests to exit the target gracefully.
	Shutdown(ctx context.Context) error

	// Terminate the target.
	Terminate(ctx context.Context) error

	// Remove all resources allocated by the controller.
	Remove(ctx context.Context) error

	// Close closes any ephemeral resources associated with controller instance.
	Close() error
}

// ContainerStatuser reports status of a container.
//
// This can be implemented by controllers or error types.
type ContainerStatuser interface {
	// ContainerStatus returns the status of the target container, if
	// available. When the container is not available, the status will be nil.
	ContainerStatus(ctx context.Context) (*api.ContainerStatus, error)
}

// Resolve attempts to get a controller from the executor and reports the
// correct status depending on the tasks current state according to the result.
//
// Unlike Do, if an error is returned, the status should still be reported. The
// error merely reports the
func Resolve(ctx context.Context, task *api.Task, executor Executor) (Controller, *api.TaskStatus, error) {
	status := task.Status.Copy()

	defer func() {
		logStateChange(ctx, task.DesiredState, task.Status.State, status.State)
	}()

	ctlr, err := executor.Controller(task)

	// depending on the tasks state, a failed controller resolution has varying
	// impact. The following expresses that impact.
	if task.Status.State < api.TaskStateStarting {
		if err != nil {
			// before the task has been started, we consider it a rejection.
			status.Message = "resolving controller failed"
			status.Err = err.Error()
			status.State = api.TaskStateRejected
		} else if task.Status.State < api.TaskStateAccepted {
			// we always want to proceed to accepted when we resolve the contoller
			status.Message = "accepted"
			status.State = api.TaskStateAccepted
		}
	}

	return ctlr, status, err
}

// Do progresses the task state using the controller performing a single
// operation on the controller. The return TaskStatus should be marked as the
// new state of the task.
//
// The returned status should be reported and placed back on to task
// before the next call. The operation can be cancelled by creating a
// cancelling context.
//
// Errors from the task controller will reported on the returned status. Any
// errors coming from this function should not be reported as related to the
// individual task.
//
// If ErrTaskNoop is returned, it means a second call to Do will result in no
// change. If ErrTaskDead is returned, calls to Do will no longer result in any
// action.
func Do(ctx context.Context, task *api.Task, ctlr Controller) (*api.TaskStatus, error) {
	status := task.Status.Copy()

	// stay in the current state.
	noop := func(errs ...error) (*api.TaskStatus, error) {
		return status, ErrTaskNoop
	}

	retry := func() (*api.TaskStatus, error) {
		// while we retry on all errors, this allows us to explicitly declare
		// retry cases.
		return status, ErrTaskRetry
	}

	// transition moves the task to the next state.
	transition := func(state api.TaskState, msg string) (*api.TaskStatus, error) {
		current := status.State
		status.State = state
		status.Message = msg

		if current > state {
			panic("invalid state transition")
		}
		return status, nil
	}

	// containerStatus exitCode keeps track of whether or not we've set it in
	// this particular method. Eventually, we assemble this as part of a defer.
	var (
		containerStatus *api.ContainerStatus
		exitCode        int
	)

	// returned when a fatal execution of the task is fatal. In this case, we
	// proceed to a terminal error state and set the appropriate fields.
	//
	// Common checks for the nature of an error should be included here. If the
	// error is determined not to be fatal for the task,
	fatal := func(err error) (*api.TaskStatus, error) {
		if err == nil {
			panic("err must not be nil when fatal")
		}

		if cs, ok := err.(ContainerStatuser); ok {
			var err error
			containerStatus, err = cs.ContainerStatus(ctx)
			if err != nil {
				log.G(ctx).WithError(err).Error("error resolving container status on fatal")
			}
		}

		// make sure we've set the *correct* exit code
		if ec, ok := err.(ExitCoder); ok {
			exitCode = ec.ExitCode()
		}

		if cause := errors.Cause(err); cause == context.DeadlineExceeded || cause == context.Canceled {
			return retry()
		}

		status.Err = err.Error() // still reported on temporary
		if IsTemporary(err) {
			return retry()
		}

		// only at this point do we consider the error fatal to the task.
		log.G(ctx).WithError(err).Error("fatal task error")

		// NOTE(stevvooe): The following switch dictates the terminal failure
		// state based on the state in which the failure was encountered.
		switch {
		case status.State < api.TaskStateStarting:
			status.State = api.TaskStateRejected
		case status.State >= api.TaskStateStarting:
			status.State = api.TaskStateFailed
		}

		return status, nil
	}

	// below, we have several callbacks that are run after the state transition
	// is completed.
	defer func() {
		logStateChange(ctx, task.DesiredState, task.Status.State, status.State)
	}()

	// extract the container status from the container, if supported.
	defer func() {
		// only do this if in an active state
		if status.State < api.TaskStateStarting {
			return
		}

		if containerStatus == nil {
			// collect this, if we haven't
			cctlr, ok := ctlr.(ContainerStatuser)
			if !ok {
				return
			}

			var err error
			containerStatus, err = cctlr.ContainerStatus(ctx)
			if err != nil {
				log.G(ctx).WithError(err).Error("container status unavailable")
			}

			// at this point, things have gone fairly wrong. Remain positive
			// and let's get something out the door.
			if containerStatus == nil {
				containerStatus = new(api.ContainerStatus)
				containerStatusTask := task.Status.GetContainer()
				if containerStatusTask != nil {
					*containerStatus = *containerStatusTask // copy it over.
				}
			}
		}

		// at this point, we *must* have a containerStatus.
		if exitCode != 0 {
			containerStatus.ExitCode = int32(exitCode)
		}

		status.RuntimeStatus = &api.TaskStatus_Container{
			Container: containerStatus,
		}
	}()

	if task.DesiredState == api.TaskStateShutdown {
		if status.State >= api.TaskStateCompleted {
			return noop()
		}

		if err := ctlr.Shutdown(ctx); err != nil {
			return fatal(err)
		}

		return transition(api.TaskStateShutdown, "shutdown")
	}

	if status.State > task.DesiredState {
		return noop() // way beyond desired state, pause
	}

	// the following states may proceed past desired state.
	switch status.State {
	case api.TaskStatePreparing:
		if err := ctlr.Prepare(ctx); err != nil && err != ErrTaskPrepared {
			return fatal(err)
		}

		return transition(api.TaskStateReady, "prepared")
	case api.TaskStateStarting:
		if err := ctlr.Start(ctx); err != nil && err != ErrTaskStarted {
			return fatal(err)
		}

		return transition(api.TaskStateRunning, "started")
	case api.TaskStateRunning:
		if err := ctlr.Wait(ctx); err != nil {
			return fatal(err)
		}

		return transition(api.TaskStateCompleted, "finished")
	}

	// The following represent "pause" states. We can only proceed when the
	// desired state is beyond our current state.
	if status.State >= task.DesiredState {
		return noop()
	}

	switch status.State {
	case api.TaskStateNew, api.TaskStateAllocated, api.TaskStateAssigned:
		return transition(api.TaskStateAccepted, "accepted")
	case api.TaskStateAccepted:
		return transition(api.TaskStatePreparing, "preparing")
	case api.TaskStateReady:
		return transition(api.TaskStateStarting, "starting")
	default: // terminal states
		return noop()
	}
}

func logStateChange(ctx context.Context, desired, previous, next api.TaskState) {
	if previous != next {
		fields := logrus.Fields{
			"state.transition": fmt.Sprintf("%v->%v", previous, next),
			"state.desired":    desired,
		}
		log.G(ctx).WithFields(fields).Debug("state changed")
	}
}
<commit_msg>Fix the comment of Resolve function<commit_after>package exec

import (
	"fmt"

	"github.com/Sirupsen/logrus"
	"github.com/docker/swarmkit/api"
	"github.com/docker/swarmkit/log"
	"github.com/pkg/errors"
	"golang.org/x/net/context"
)

// Controller controls execution of a task.
type Controller interface {
	// Update the task definition seen by the controller. Will return
	// ErrTaskUpdateFailed if the provided task definition changes fields that
	// cannot be changed.
	//
	// Will be ignored if the task has exited.
	Update(ctx context.Context, t *api.Task) error

	// Prepare the task for execution. This should ensure that all resources
	// are created such that a call to start should execute immediately.
	Prepare(ctx context.Context) error

	// Start the target and return when it has started successfully.
	Start(ctx context.Context) error

	// Wait blocks until the target has exited.
	Wait(ctx context.Context) error

	// Shutdown requests to exit the target gracefully.
	Shutdown(ctx context.Context) error

	// Terminate the target.
	Terminate(ctx context.Context) error

	// Remove all resources allocated by the controller.
	Remove(ctx context.Context) error

	// Close closes any ephemeral resources associated with controller instance.
	Close() error
}

// ContainerStatuser reports status of a container.
//
// This can be implemented by controllers or error types.
type ContainerStatuser interface {
	// ContainerStatus returns the status of the target container, if
	// available. When the container is not available, the status will be nil.
	ContainerStatus(ctx context.Context) (*api.ContainerStatus, error)
}

// Resolve attempts to get a controller from the executor and reports the
// correct status depending on the tasks current state according to the result.
//
// Unlike Do, if an error is returned, the status should still be reported. The
// error merely reports the failure at getting the controller.
func Resolve(ctx context.Context, task *api.Task, executor Executor) (Controller, *api.TaskStatus, error) {
	status := task.Status.Copy()

	defer func() {
		logStateChange(ctx, task.DesiredState, task.Status.State, status.State)
	}()

	ctlr, err := executor.Controller(task)

	// depending on the tasks state, a failed controller resolution has varying
	// impact. The following expresses that impact.
	if task.Status.State < api.TaskStateStarting {
		if err != nil {
			// before the task has been started, we consider it a rejection.
			status.Message = "resolving controller failed"
			status.Err = err.Error()
			status.State = api.TaskStateRejected
		} else if task.Status.State < api.TaskStateAccepted {
			// we always want to proceed to accepted when we resolve the contoller
			status.Message = "accepted"
			status.State = api.TaskStateAccepted
		}
	}

	return ctlr, status, err
}

// Do progresses the task state using the controller performing a single
// operation on the controller. The return TaskStatus should be marked as the
// new state of the task.
//
// The returned status should be reported and placed back on to task
// before the next call. The operation can be cancelled by creating a
// cancelling context.
//
// Errors from the task controller will reported on the returned status. Any
// errors coming from this function should not be reported as related to the
// individual task.
//
// If ErrTaskNoop is returned, it means a second call to Do will result in no
// change. If ErrTaskDead is returned, calls to Do will no longer result in any
// action.
func Do(ctx context.Context, task *api.Task, ctlr Controller) (*api.TaskStatus, error) {
	status := task.Status.Copy()

	// stay in the current state.
	noop := func(errs ...error) (*api.TaskStatus, error) {
		return status, ErrTaskNoop
	}

	retry := func() (*api.TaskStatus, error) {
		// while we retry on all errors, this allows us to explicitly declare
		// retry cases.
		return status, ErrTaskRetry
	}

	// transition moves the task to the next state.
	transition := func(state api.TaskState, msg string) (*api.TaskStatus, error) {
		current := status.State
		status.State = state
		status.Message = msg

		if current > state {
			panic("invalid state transition")
		}
		return status, nil
	}

	// containerStatus exitCode keeps track of whether or not we've set it in
	// this particular method. Eventually, we assemble this as part of a defer.
	var (
		containerStatus *api.ContainerStatus
		exitCode        int
	)

	// returned when a fatal execution of the task is fatal. In this case, we
	// proceed to a terminal error state and set the appropriate fields.
	//
	// Common checks for the nature of an error should be included here. If the
	// error is determined not to be fatal for the task,
	fatal := func(err error) (*api.TaskStatus, error) {
		if err == nil {
			panic("err must not be nil when fatal")
		}

		if cs, ok := err.(ContainerStatuser); ok {
			var err error
			containerStatus, err = cs.ContainerStatus(ctx)
			if err != nil {
				log.G(ctx).WithError(err).Error("error resolving container status on fatal")
			}
		}

		// make sure we've set the *correct* exit code
		if ec, ok := err.(ExitCoder); ok {
			exitCode = ec.ExitCode()
		}

		if cause := errors.Cause(err); cause == context.DeadlineExceeded || cause == context.Canceled {
			return retry()
		}

		status.Err = err.Error() // still reported on temporary
		if IsTemporary(err) {
			return retry()
		}

		// only at this point do we consider the error fatal to the task.
		log.G(ctx).WithError(err).Error("fatal task error")

		// NOTE(stevvooe): The following switch dictates the terminal failure
		// state based on the state in which the failure was encountered.
		switch {
		case status.State < api.TaskStateStarting:
			status.State = api.TaskStateRejected
		case status.State >= api.TaskStateStarting:
			status.State = api.TaskStateFailed
		}

		return status, nil
	}

	// below, we have several callbacks that are run after the state transition
	// is completed.
	defer func() {
		logStateChange(ctx, task.DesiredState, task.Status.State, status.State)
	}()

	// extract the container status from the container, if supported.
	defer func() {
		// only do this if in an active state
		if status.State < api.TaskStateStarting {
			return
		}

		if containerStatus == nil {
			// collect this, if we haven't
			cctlr, ok := ctlr.(ContainerStatuser)
			if !ok {
				return
			}

			var err error
			containerStatus, err = cctlr.ContainerStatus(ctx)
			if err != nil {
				log.G(ctx).WithError(err).Error("container status unavailable")
			}

			// at this point, things have gone fairly wrong. Remain positive
			// and let's get something out the door.
			if containerStatus == nil {
				containerStatus = new(api.ContainerStatus)
				containerStatusTask := task.Status.GetContainer()
				if containerStatusTask != nil {
					*containerStatus = *containerStatusTask // copy it over.
				}
			}
		}

		// at this point, we *must* have a containerStatus.
		if exitCode != 0 {
			containerStatus.ExitCode = int32(exitCode)
		}

		status.RuntimeStatus = &api.TaskStatus_Container{
			Container: containerStatus,
		}
	}()

	if task.DesiredState == api.TaskStateShutdown {
		if status.State >= api.TaskStateCompleted {
			return noop()
		}

		if err := ctlr.Shutdown(ctx); err != nil {
			return fatal(err)
		}

		return transition(api.TaskStateShutdown, "shutdown")
	}

	if status.State > task.DesiredState {
		return noop() // way beyond desired state, pause
	}

	// the following states may proceed past desired state.
	switch status.State {
	case api.TaskStatePreparing:
		if err := ctlr.Prepare(ctx); err != nil && err != ErrTaskPrepared {
			return fatal(err)
		}

		return transition(api.TaskStateReady, "prepared")
	case api.TaskStateStarting:
		if err := ctlr.Start(ctx); err != nil && err != ErrTaskStarted {
			return fatal(err)
		}

		return transition(api.TaskStateRunning, "started")
	case api.TaskStateRunning:
		if err := ctlr.Wait(ctx); err != nil {
			return fatal(err)
		}

		return transition(api.TaskStateCompleted, "finished")
	}

	// The following represent "pause" states. We can only proceed when the
	// desired state is beyond our current state.
	if status.State >= task.DesiredState {
		return noop()
	}

	switch status.State {
	case api.TaskStateNew, api.TaskStateAllocated, api.TaskStateAssigned:
		return transition(api.TaskStateAccepted, "accepted")
	case api.TaskStateAccepted:
		return transition(api.TaskStatePreparing, "preparing")
	case api.TaskStateReady:
		return transition(api.TaskStateStarting, "starting")
	default: // terminal states
		return noop()
	}
}

func logStateChange(ctx context.Context, desired, previous, next api.TaskState) {
	if previous != next {
		fields := logrus.Fields{
			"state.transition": fmt.Sprintf("%v->%v", previous, next),
			"state.desired":    desired,
		}
		log.G(ctx).WithFields(fields).Debug("state changed")
	}
}
<|endoftext|>