<commit_before>package daemon

import (
    "os"
    "time"
    "fmt"
    "github.com/sevlyar/go-daemon"
    "github.com/Sirupsen/logrus"
    "github.com/BluePecker/JwtAuth/server/types/token"
    "github.com/BluePecker/JwtAuth/server"
    "github.com/BluePecker/JwtAuth/storage"
    //"github.com/BluePecker/JwtAuth/server/router"
    _ "github.com/BluePecker/JwtAuth/storage/redis"
    //_ "github.com/BluePecker/JwtAuth/storage/ram"
    "github.com/dgrijalva/jwt-go"
    RouteToken "github.com/BluePecker/JwtAuth/server/router/token"
    "github.com/kataras/iris"
    "github.com/kataras/iris/core/netutil"
)

const (
    TOKEN_TTL = 2 * 3600

    VERSION = "1.0.0"

    ALLOW_LOGIN_NUM = 3
)

type Storage struct {
    Driver string
    Opts   string
}

type Security struct {
    Verify bool
    TLS    bool
    Key    string
    Cert   string
}

type Options struct {
    PidFile  string
    LogFile  string
    LogLevel string
    Port     int
    Host     string
    Daemon   bool
    Version  bool
    Security Security
    Storage  Storage
    Secret   string
}

type Daemon struct {
    Options *Options
    Front   *server.Server
    Backend *server.Server
    Storage *storage.Driver
}

type (
    CustomClaims struct {
        Device    string `json:"device"`
        Unique    string `json:"unique"`
        Timestamp int64  `json:"timestamp"`
        Addr      string `json:"addr"`
        jwt.StandardClaims
    }
)

func (d *Daemon) NewStorage() (err error) {
    conf := d.Options.Storage
    d.Storage, err = storage.New(conf.Driver, conf.Opts)
    return err
}

func (d *Daemon) NewFront() (err error) {
    d.Front = &server.Server{}
    Addr := fmt.Sprintf("%s:%d", d.Options.Host, d.Options.Port)
    if !d.Options.Security.TLS && !d.Options.Security.Verify {
        err = d.Front.Run(iris.Addr(Addr))
    } else {
        runner := iris.TLS(Addr, d.Options.Security.Cert, d.Options.Security.Key)
        err = d.Front.Run(runner)
    }
    if err == nil {
        d.Front.AddRouter(RouteToken.NewRouter(d))
    }
    return err
}

func (d *Daemon) NewBackend() (err error) {
    d.Backend = &server.Server{}
    l, err := netutil.UNIX("/tmp/srv.sock", 0666)
    if err != nil {
        return err
    }
    err = d.Backend.Run(iris.Listener(l))
    if err == nil {
        // todo add backend router
    }
    return err
}

func (d *Daemon) Generate(req token.GenerateRequest) (string, error) {
    Claims := CustomClaims{
        req.Device,
        req.Unique,
        time.Now().Unix(),
        req.Addr,
        jwt.StandardClaims{
            ExpiresAt: time.Now().Add(time.Second * TOKEN_TTL).Unix(),
            Issuer: "shuc324@gmail.com",
        },
    }
    Token := jwt.NewWithClaims(jwt.SigningMethodHS256, Claims)
    if Signed, err := Token.SignedString([]byte(d.Options.Secret)); err != nil {
        return "", err
    } else {
        err := (*d.Storage).LKeep(req.Unique, Signed, ALLOW_LOGIN_NUM, TOKEN_TTL)
        if err != nil {
            return "", err
        }
        return Signed, err
    }
}

func (d *Daemon) Auth(req token.AuthRequest) (interface{}, error) {
    Token, err := jwt.ParseWithClaims(
        req.JsonWebToken,
        &CustomClaims{},
        func(token *jwt.Token) (interface{}, error) {
            if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
                return nil, fmt.Errorf("Unexpected signing method %v", token.Header["alg"])
            }
            return []byte(d.Options.Secret), nil
        })
    if err == nil && Token.Valid {
        if Claims, ok := Token.Claims.(*CustomClaims); ok {
            if (*d.Storage).LExist(Claims.Unique, req.JsonWebToken) {
                return Claims, nil
            }
        }
    }
    return nil, err
}

func NewDaemon(background bool, args Options) *Daemon {
    if background {
        ctx := daemon.Context{
            PidFileName: args.PidFile,
            PidFilePerm: 0644,
            LogFilePerm: 0640,
            Umask:       027,
            WorkDir:     "/",
            LogFileName: args.LogFile,
        }
        if rank, err := logrus.ParseLevel(args.LogLevel); err != nil {
            fmt.Println(err)
            os.Exit(0)
        } else {
            logrus.SetFormatter(&logrus.TextFormatter{
                TimestampFormat: "2006-01-02 15:04:05",
            })
            logrus.SetLevel(rank)
        }
        if process, err := ctx.Reborn(); err == nil {
            defer ctx.Release()
            if process != nil {
                return nil
            }
        } else {
            if err == daemon.ErrWouldBlock {
                fmt.Println("daemon already exists.")
            } else {
                fmt.Println("Unable to run: ", err)
            }
            os.Exit(0)
        }
    }
    return &Daemon{Options: &args}
}

func NewStart(args Options) {
    var err error;

    if args.Version == true {
        fmt.Printf("JwtAuth version %s.\n", VERSION)
        os.Exit(0)
    }

    Process := NewDaemon(args.Daemon, args)

    if Process == nil {
        return
    }

    if Process.Options.Secret == "" {
        fmt.Println("please specify the key.")
        os.Exit(0)
    }

    if err = Process.NewStorage(); err != nil {
        fmt.Println(err)
        os.Exit(0)
    }

    go func() {
        if err = Process.NewBackend(); err != nil {
            fmt.Printf("backend server listen error: %s", err)
            os.Exit(0)
        }
    }()

    if err = Process.NewFront(); err != nil {
        fmt.Printf("front server listen error: %s", err)
        os.Exit(0)
    }
}<commit_msg>fix bug<commit_after>package daemon

import (
    "os"
    "time"
    "fmt"
    "github.com/sevlyar/go-daemon"
    "github.com/Sirupsen/logrus"
    "github.com/BluePecker/JwtAuth/server/types/token"
    "github.com/BluePecker/JwtAuth/server"
    "github.com/BluePecker/JwtAuth/storage"
    //"github.com/BluePecker/JwtAuth/server/router"
    _ "github.com/BluePecker/JwtAuth/storage/redis"
    //_ "github.com/BluePecker/JwtAuth/storage/ram"
    "github.com/dgrijalva/jwt-go"
    RouteToken "github.com/BluePecker/JwtAuth/server/router/token"
    "github.com/kataras/iris"
    "github.com/kataras/iris/core/netutil"
)

const (
    TOKEN_TTL = 2 * 3600

    VERSION = "1.0.0"

    ALLOW_LOGIN_NUM = 3
)

type Storage struct {
    Driver string
    Opts   string
}

type Security struct {
    Verify bool
    TLS    bool
    Key    string
    Cert   string
}

type Options struct {
    PidFile  string
    LogFile  string
    LogLevel string
    Port     int
    Host     string
    Daemon   bool
    Version  bool
    Security Security
    Storage  Storage
    Secret   string
}

type Daemon struct {
    Options *Options
    Front   *server.Server
    Backend *server.Server
    Storage *storage.Driver
}

type (
    CustomClaims struct {
        Device    string `json:"device"`
        Unique    string `json:"unique"`
        Timestamp int64  `json:"timestamp"`
        Addr      string `json:"addr"`
        jwt.StandardClaims
    }
)

func (d *Daemon) NewStorage() (err error) {
    conf := d.Options.Storage
    d.Storage, err = storage.New(conf.Driver, conf.Opts)
    return err
}

func (d *Daemon) NewFront() (err error) {
    d.Front = &server.Server{}
    Addr := fmt.Sprintf("%s:%d", d.Options.Host, d.Options.Port)
    if !d.Options.Security.TLS && !d.Options.Security.Verify {
        err = d.Front.Run(iris.Addr(Addr))
    } else {
        runner := iris.TLS(Addr, d.Options.Security.Cert, d.Options.Security.Key)
        err = d.Front.Run(runner)
    }
    if err == nil {
        d.Front.AddRouter(RouteToken.NewRouter(d))
    }
    return err
}

func (d *Daemon) NewBackend() (err error) {
    d.Backend = &server.Server{}
    l, err := netutil.UNIX("/tmp/srv.sock", 0666)
    if err != nil {
        return err
    }
    err = d.Backend.Run(iris.Listener(l))
    if err == nil {
        // todo add backend router
    }
    return err
}

func (d *Daemon) Generate(req token.GenerateRequest) (string, error) {
    Claims := CustomClaims{
        req.Device,
        req.Unique,
        time.Now().Unix(),
        req.Addr,
        jwt.StandardClaims{
            ExpiresAt: time.Now().Add(time.Second * TOKEN_TTL).Unix(),
            Issuer: "shuc324@gmail.com",
        },
    }
    Token := jwt.NewWithClaims(jwt.SigningMethodHS256, Claims)
    if Signed, err := Token.SignedString([]byte(d.Options.Secret)); err != nil {
        return "", err
    } else {
        err := (*d.Storage).LKeep(req.Unique, Signed, ALLOW_LOGIN_NUM, TOKEN_TTL)
        if err != nil {
            return "", err
        }
        return Signed, err
    }
}

func (d *Daemon) Auth(req token.AuthRequest) (interface{}, error) {
    Token, err := jwt.ParseWithClaims(
        req.JsonWebToken,
        &CustomClaims{},
        func(token *jwt.Token) (interface{}, error) {
            if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
                return nil, fmt.Errorf("Unexpected signing method %v", token.Header["alg"])
            }
            return []byte(d.Options.Secret), nil
        })
    if err == nil && Token.Valid {
        if Claims, ok := Token.Claims.(*CustomClaims); ok {
            if (*d.Storage).LExist(Claims.Unique, req.JsonWebToken) {
                return Claims, nil
            }
        }
    }
    return nil, err
}

func NewDaemon(background bool, args Options) *Daemon {
    if background {
        ctx := daemon.Context{
            PidFileName: args.PidFile,
            PidFilePerm: 0644,
            LogFilePerm: 0640,
            Umask:       027,
            WorkDir:     "/",
            LogFileName: args.LogFile,
        }
        if rank, err := logrus.ParseLevel(args.LogLevel); err != nil {
            fmt.Println(err)
            os.Exit(0)
        } else {
            logrus.SetFormatter(&logrus.TextFormatter{
                TimestampFormat: "2006-01-02 15:04:05",
            })
            logrus.SetLevel(rank)
        }
        if process, err := ctx.Reborn(); err == nil {
            defer ctx.Release()
            if process != nil {
                return nil
            }
        } else {
            if err == daemon.ErrWouldBlock {
                fmt.Println("daemon already exists.")
            } else {
                fmt.Println("Unable to run: ", err)
            }
            os.Exit(0)
        }
    }
    return &Daemon{Options: &args}
}

func NewStart(args Options) {
    var err error;

    if args.Version == true {
        fmt.Printf("JwtAuth version %s.\n", VERSION)
        os.Exit(0)
    }

    Process := NewDaemon(args.Daemon, args)

    if Process == nil {
        return
    }

    if Process.Options.Secret == "" {
        fmt.Println("please specify the key.")
        os.Exit(0)
    }

    if err = Process.NewStorage(); err != nil {
        fmt.Println(err)
        os.Exit(0)
    }

    go func() {
        if err = Process.NewBackend(); err != nil {
            fmt.Printf("backend server listen error: %s", err)
            os.Exit(0)
        } else {
            logrus.Info("Now listening on: backend")
        }
    }()

    if err = Process.NewFront(); err != nil {
        fmt.Printf("front server listen error: %s", err)
        os.Exit(0)
    } else {
        logrus.Info("Now listening on: front")
    }
}<|endoftext|>


<commit_before>package main

import (
	"os"
	"os/exec"
	"syscall"

	log "github.com/sirupsen/logrus"
)

func daemon() {
	if *godaemon {
		args := os.Args[1:]
		args = append(args, "-daemon=false")
		cmd := exec.Command(os.Args[0], args...)
		//cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
		cmd.Start()
		log.Info("[PID]:", cmd.Process.Pid)
		os.Exit(0)
	}
}
<commit_msg>fix darwin build<commit_after>package main

import (
	"os"
	"os/exec"

	log "github.com/sirupsen/logrus"
)

func daemon() {
	if *godaemon {
		args := os.Args[1:]
		args = append(args, "-daemon=false")
		cmd := exec.Command(os.Args[0], args...)
		cmd.Start()
		log.Info("[PID]:", cmd.Process.Pid)
		os.Exit(0)
	}
}
<|endoftext|>


<commit_before>package classifier

import "errors"

var errNotFound = errors.New("Classifier key not found")

// Classifier type contains a key/value pair repsenting a classifier
type Classifier struct {
	// Classifier key
	Key string `json:"key"`

	// Classifier value
	Value string `json:"value"`
}

// Type of classifier providers
// A classifier provider is what does the
// actual evaluation of a classifier
type provider func() (string, error)

// Registry provides a global registry for all classifiers
var Registry = make(map[string]provider)

// Register registers a new classifier to the registry
func Register(key string, p provider) error {
	Registry[key] = p

	return nil
}

// Get retrieves a classifier from the registry by looking up its key
func Get(key string) (*Classifier, error) {
	c := new(Classifier)

	p, ok := Registry[key]
	if ok {
		// Evaluate the classifier provider
		value, err := p()
		c := &Classifier{
			Key:   key,
			Value: value,
		}
		return c, err
	}

	return c, errNotFound
}
<commit_msg>Export ErrClassifierNotFound error<commit_after>package classifier

import "errors"

// ErrClassifierNotFound is returned if the requested classifier was
// not found in the classifier registry
var ErrClassifierNotFound = errors.New("Classifier key not found")

// Classifier type contains a key/value pair repsenting a classifier
type Classifier struct {
	// Classifier key
	Key string `json:"key"`

	// Classifier value
	Value string `json:"value"`
}

// Type of classifier providers
// A classifier provider is what does the
// actual evaluation of a classifier
type provider func() (string, error)

// Registry provides a global registry for all classifiers
var Registry = make(map[string]provider)

// Register registers a new classifier to the registry
func Register(key string, p provider) error {
	Registry[key] = p

	return nil
}

// Get retrieves a classifier from the registry by looking up its key
func Get(key string) (*Classifier, error) {
	c := new(Classifier)

	p, ok := Registry[key]
	if ok {
		// Evaluate the classifier provider
		value, err := p()
		c := &Classifier{
			Key:   key,
			Value: value,
		}
		return c, err
	}

	return c, ErrClassifierNotFound
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"path/filepath"
	"strings"
	"sync"
	"text/template"

	"github.com/99designs/smartling"
	"github.com/99designs/smartling/Godeps/_workspace/src/github.com/codegangsta/cli"
)

var ProjectCommand = cli.Command{
	Name:  "project",
	Usage: "manage local project files",
	Before: func(c *cli.Context) error {
		err := cmdBefore(c)
		if err != nil {
			return nil
		}

		return loadProjectErr
	},
	After: func(c *cli.Context) error {
		cleanupTempFiles()
		return nil
	},
	Subcommands: []cli.Command{
		projectFilesCommand,
		projectStatusCommand,
		projectPullCommand,
		projectPushCommand,
	},
}

func fetchRemoteFileList() stringSlice {
	files := stringSlice{}
	listFiles, err := client.List(smartling.ListRequest{})
	logAndQuitIfError(err)

	for _, fs := range listFiles {
		files = append(files, fs.FileUri)
	}

	return files
}

func fetchLocales() []string {
	ll := []string{}
	locales, err := client.Locales()
	logAndQuitIfError(err)
	for _, l := range locales {
		ll = append(ll, l.Locale)
	}

	return ll
}

var projectFilesCommand = cli.Command{
	Name:        "files",
	Usage:       "lists the local files",
	Description: "files",
	Action: func(c *cli.Context) {
		if len(c.Args()) != 0 {
			log.Println("Wrong number of arguments")
			log.Fatalln("Usage: files")
		}

		for _, projectFilepath := range ProjectConfig.Files() {
			fmt.Println(projectFilepath)
		}
	},
}

var projectStatusCommand = cli.Command{
	Name:        "status",
	Usage:       "show the status of the project's remote files",
	Description: "status [<prefix>]",
	Flags: []cli.Flag{
		cli.BoolFlag{
			Name:  "awaiting-auth",
			Usage: "Output the number of strings Awaiting Authorization",
		},
	},
	Action: func(c *cli.Context) {
		if len(c.Args()) > 1 {
			log.Println("Wrong number of arguments")
			log.Fatalln("Usage: status [<prefix>]")
		}

		prefix := prefixOrGitPrefix(c.Args().Get(0))
		locales := fetchLocales()
		statuses := GetProjectStatus(prefix, locales)

		if c.Bool("awaiting-auth") {
			fmt.Println(statuses.AwaitingAuthorizationCount())
		} else {
			fmt.Print("\n")
			PrintProjectStatusTable(statuses, locales)
			fmt.Print("\n")
			fmt.Printf("Awaiting Authorization: %4d\n", statuses.AwaitingAuthorizationCount())
			fmt.Printf("Total:                  %4d\n", statuses.TotalStringsCount())
		}

	},
}

var projectPullCommand = cli.Command{
	Name:  "pull",
	Usage: "translate local project files using Smartling as a translation memory",

	Action: func(c *cli.Context) {
		if len(c.Args()) != 0 {
			log.Println("Wrong number of arguments")
			log.Fatalln("Usage: project pull")
		}

		locales, err := client.Locales()
		logAndQuitIfError(err)

		var wg sync.WaitGroup
		for _, projectFilepath := range ProjectConfig.Files() {
			for _, l := range locales {
				wg.Add(1)
				go func(locale, projectFilepath string) {
					defer wg.Done()

					hit, b, err, _ := translateViaCache(
						locale,
						localRelativeFilePath(projectFilepath),
						filetypeForProjectFile(projectFilepath),
						ProjectConfig.ParserConfig,
					)
					logAndQuitIfError(err)

					fp := localPullFilePath(projectFilepath, locale)
					cached := ""
					if hit {
						cached = "(using cache)"
					}
					fmt.Println(fp, cached)
					err = ioutil.WriteFile(fp, b, 0644)
					logAndQuitIfError(err)
				}(l.Locale, projectFilepath)
			}
		}
		wg.Wait()
	},
}

func cleanPrefix(s string) string {
	s = filepath.Clean("/" + s)
	if s == "/" {
		return ""
	}
	return s
}

func prefixOrGitPrefix(prefix string) string {
	if prefix == "" {
		prefix = pushPrefix()
	}

	if prefix == "/branch/master" {
		prefix = "/"
	}

	prefix = cleanPrefix(prefix)

	if prefix != "" {
		log.Println("Using prefix", prefix)
	}
	return prefix
}

type RemoteFileStatus struct {
	RemoteFilePath string
	Statuses       map[string]*smartling.FileStatus
}

func (r *RemoteFileStatus) NotCompletedStringCount() int {
	c := 0
	for _, fs := range r.Statuses {
		c += fs.NotCompletedStringCount()
	}
	return c
}

func fetchStatusForLocales(remoteFilePath string, locales []string) RemoteFileStatus {
	ss := RemoteFileStatus{
		RemoteFilePath: remoteFilePath,
		Statuses:       map[string]*smartling.FileStatus{},
	}

	var wg sync.WaitGroup
	for _, locale := range locales {
		wg.Add(1)
		go func(f, l string) {
			defer wg.Done()

			s, err := client.Status(f, l)
			logAndQuitIfError(err)
			ss.Statuses[l] = &s

		}(remoteFilePath, locale)
	}
	wg.Wait()

	return ss
}

var projectPushCommand = cli.Command{
	Name:  "push",
	Usage: "upload local project files that contain untranslated strings",
	Description: `push [<prefix>]
Outputs the uploaded files for the given prefix
`,
	Action: func(c *cli.Context) {
		if len(c.Args()) > 1 {
			log.Println("Wrong number of arguments")
			log.Fatalln("Usage: push [<prefix>]")
		}

		prefix := prefixOrGitPrefix(c.Args().Get(0))
		locales := fetchLocales()

		var wg sync.WaitGroup
		for _, projectFilepath := range ProjectConfig.Files() {
			wg.Add(1)
			go func(prefix, projectFilepath string) {
				defer wg.Done()

				remoteFile := filepath.Clean(prefix + "/" + projectFilepath)

				_, err := client.Upload(projectFilepath, &smartling.UploadRequest{
					FileUri:      remoteFile,
					FileType:     filetypeForProjectFile(projectFilepath),
					ParserConfig: ProjectConfig.ParserConfig,
				})
				logAndQuitIfError(err)

				remoteFileStatuses := fetchStatusForLocales(remoteFile, locales)

				// when using a prefix, we don't want to see files with
				// completely translated content
				if prefix != "" && remoteFileStatuses.NotCompletedStringCount() == 0 {
					err := client.Delete(remoteFile)
					logAndQuitIfError(err)
				} else {
					fmt.Println(remoteFile)
				}
			}(prefix, projectFilepath)
		}
		wg.Wait()
	},
}

func filetypeForProjectFile(projectFilepath string) smartling.FileType {
	ft := smartling.FileTypeByExtension(filepath.Ext(projectFilepath))
	if ft == "" {
		ft = ProjectConfig.FileType
	}
	if ft == "" {
		log.Panicln("Can't determine file type for " + projectFilepath)
	}

	return ft
}

type FilenameParts struct {
	Path           string
	Base           string
	Dir            string
	Ext            string
	PathWithoutExt string
	Locale         string
}

func localRelativeFilePath(remotepath string) string {
	fp, err := filepath.Rel(".", filepath.Join(ProjectConfig.path, remotepath))
	logAndQuitIfError(err)
	return fp
}

func localPullFilePath(p, locale string) string {
	parts := FilenameParts{
		Path:   p,
		Dir:    filepath.Dir(p),
		Base:   filepath.Base(p),
		Ext:    filepath.Ext(p),
		Locale: locale,
	}

	dt := defaultPullDestination
	if dt != "" {
		dt = ProjectConfig.PullFilePath
	}

	out := bytes.NewBufferString("")
	tmpl := template.New("name")
	tmpl.Funcs(template.FuncMap{
		"TrimSuffix": strings.TrimSuffix,
		"Truncate": func(s string, n int) string {
			return s[:n]
		},
	})
	_, err := tmpl.Parse(dt)
	logAndQuitIfError(err)

	err = tmpl.Execute(out, parts)
	logAndQuitIfError(err)

	return localRelativeFilePath(out.String())
}
<commit_msg>Move push to own func<commit_after>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"path/filepath"
	"strings"
	"sync"
	"text/template"

	"github.com/99designs/smartling"
	"github.com/99designs/smartling/Godeps/_workspace/src/github.com/codegangsta/cli"
)

var ProjectCommand = cli.Command{
	Name:  "project",
	Usage: "manage local project files",
	Before: func(c *cli.Context) error {
		err := cmdBefore(c)
		if err != nil {
			return nil
		}

		return loadProjectErr
	},
	After: func(c *cli.Context) error {
		cleanupTempFiles()
		return nil
	},
	Subcommands: []cli.Command{
		projectFilesCommand,
		projectStatusCommand,
		projectPullCommand,
		projectPushCommand,
	},
}

func fetchRemoteFileList() stringSlice {
	files := stringSlice{}
	listFiles, err := client.List(smartling.ListRequest{})
	logAndQuitIfError(err)

	for _, fs := range listFiles {
		files = append(files, fs.FileUri)
	}

	return files
}

func fetchLocales() []string {
	ll := []string{}
	locales, err := client.Locales()
	logAndQuitIfError(err)
	for _, l := range locales {
		ll = append(ll, l.Locale)
	}

	return ll
}

var projectFilesCommand = cli.Command{
	Name:        "files",
	Usage:       "lists the local files",
	Description: "files",
	Action: func(c *cli.Context) {
		if len(c.Args()) != 0 {
			log.Println("Wrong number of arguments")
			log.Fatalln("Usage: files")
		}

		for _, projectFilepath := range ProjectConfig.Files() {
			fmt.Println(projectFilepath)
		}
	},
}

var projectStatusCommand = cli.Command{
	Name:        "status",
	Usage:       "show the status of the project's remote files",
	Description: "status [<prefix>]",
	Flags: []cli.Flag{
		cli.BoolFlag{
			Name:  "awaiting-auth",
			Usage: "Output the number of strings Awaiting Authorization",
		},
	},
	Action: func(c *cli.Context) {
		if len(c.Args()) > 1 {
			log.Println("Wrong number of arguments")
			log.Fatalln("Usage: status [<prefix>]")
		}

		prefix := prefixOrGitPrefix(c.Args().Get(0))
		locales := fetchLocales()
		statuses := GetProjectStatus(prefix, locales)

		if c.Bool("awaiting-auth") {
			fmt.Println(statuses.AwaitingAuthorizationCount())
		} else {
			fmt.Print("\n")
			PrintProjectStatusTable(statuses, locales)
			fmt.Print("\n")
			fmt.Printf("Awaiting Authorization: %4d\n", statuses.AwaitingAuthorizationCount())
			fmt.Printf("Total:                  %4d\n", statuses.TotalStringsCount())
		}

	},
}

var projectPullCommand = cli.Command{
	Name:  "pull",
	Usage: "translate local project files using Smartling as a translation memory",

	Action: func(c *cli.Context) {
		if len(c.Args()) != 0 {
			log.Println("Wrong number of arguments")
			log.Fatalln("Usage: project pull")
		}

		locales, err := client.Locales()
		logAndQuitIfError(err)

		var wg sync.WaitGroup
		for _, projectFilepath := range ProjectConfig.Files() {
			for _, l := range locales {
				wg.Add(1)
				go func(locale, projectFilepath string) {
					defer wg.Done()

					hit, b, err, _ := translateViaCache(
						locale,
						localRelativeFilePath(projectFilepath),
						filetypeForProjectFile(projectFilepath),
						ProjectConfig.ParserConfig,
					)
					logAndQuitIfError(err)

					fp := localPullFilePath(projectFilepath, locale)
					cached := ""
					if hit {
						cached = "(using cache)"
					}
					fmt.Println(fp, cached)
					err = ioutil.WriteFile(fp, b, 0644)
					logAndQuitIfError(err)
				}(l.Locale, projectFilepath)
			}
		}
		wg.Wait()
	},
}

func cleanPrefix(s string) string {
	s = filepath.Clean("/" + s)
	if s == "/" {
		return ""
	}
	return s
}

func prefixOrGitPrefix(prefix string) string {
	if prefix == "" {
		prefix = pushPrefix()
	}

	if prefix == "/branch/master" {
		prefix = "/"
	}

	prefix = cleanPrefix(prefix)

	if prefix != "" {
		log.Println("Using prefix", prefix)
	}
	return prefix
}

type RemoteFileStatus struct {
	RemoteFilePath string
	Statuses       map[string]*smartling.FileStatus
}

func (r *RemoteFileStatus) NotCompletedStringCount() int {
	c := 0
	for _, fs := range r.Statuses {
		c += fs.NotCompletedStringCount()
	}
	return c
}

func fetchStatusForLocales(remoteFilePath string, locales []string) RemoteFileStatus {
	ss := RemoteFileStatus{
		RemoteFilePath: remoteFilePath,
		Statuses:       map[string]*smartling.FileStatus{},
	}

	var wg sync.WaitGroup
	for _, locale := range locales {
		wg.Add(1)
		go func(f, l string) {
			defer wg.Done()

			s, err := client.Status(f, l)
			logAndQuitIfError(err)
			ss.Statuses[l] = &s

		}(remoteFilePath, locale)
	}
	wg.Wait()

	return ss
}

var projectPushCommand = cli.Command{
	Name:  "push",
	Usage: "upload local project files that contain untranslated strings",
	Description: `push [<prefix>]
Outputs the uploaded files for the given prefix
`,
	Action: func(c *cli.Context) {
		if len(c.Args()) > 1 {
			log.Println("Wrong number of arguments")
			log.Fatalln("Usage: push [<prefix>]")
		}

		prefix := prefixOrGitPrefix(c.Args().Get(0))
		locales := fetchLocales()

		push(prefix, locales)
	},
}

func push(prefix string, locales []string) {
	var wg sync.WaitGroup
	for _, projectFilepath := range ProjectConfig.Files() {
		wg.Add(1)
		go func(prefix, projectFilepath string) {
			defer wg.Done()

			remoteFile := filepath.Clean(prefix + "/" + projectFilepath)

			_, err := client.Upload(projectFilepath, &smartling.UploadRequest{
				FileUri:      remoteFile,
				FileType:     filetypeForProjectFile(projectFilepath),
				ParserConfig: ProjectConfig.ParserConfig,
			})
			logAndQuitIfError(err)

			remoteFileStatuses := fetchStatusForLocales(remoteFile, locales)

			// when using a prefix, we don't want to see files with
			// completely translated content
			if prefix != "" && remoteFileStatuses.NotCompletedStringCount() == 0 {
				err := client.Delete(remoteFile)
				logAndQuitIfError(err)
			} else {
				fmt.Println(remoteFile)
			}
		}(prefix, projectFilepath)
	}
	wg.Wait()
}

func filetypeForProjectFile(projectFilepath string) smartling.FileType {
	ft := smartling.FileTypeByExtension(filepath.Ext(projectFilepath))
	if ft == "" {
		ft = ProjectConfig.FileType
	}
	if ft == "" {
		log.Panicln("Can't determine file type for " + projectFilepath)
	}

	return ft
}

type FilenameParts struct {
	Path           string
	Base           string
	Dir            string
	Ext            string
	PathWithoutExt string
	Locale         string
}

func localRelativeFilePath(remotepath string) string {
	fp, err := filepath.Rel(".", filepath.Join(ProjectConfig.path, remotepath))
	logAndQuitIfError(err)
	return fp
}

func localPullFilePath(p, locale string) string {
	parts := FilenameParts{
		Path:   p,
		Dir:    filepath.Dir(p),
		Base:   filepath.Base(p),
		Ext:    filepath.Ext(p),
		Locale: locale,
	}

	dt := defaultPullDestination
	if dt != "" {
		dt = ProjectConfig.PullFilePath
	}

	out := bytes.NewBufferString("")
	tmpl := template.New("name")
	tmpl.Funcs(template.FuncMap{
		"TrimSuffix": strings.TrimSuffix,
		"Truncate": func(s string, n int) string {
			return s[:n]
		},
	})
	_, err := tmpl.Parse(dt)
	logAndQuitIfError(err)

	err = tmpl.Execute(out, parts)
	logAndQuitIfError(err)

	return localRelativeFilePath(out.String())
}
<|endoftext|>


<commit_before>package main

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

	"github.com/gorilla/mux"
)

func main() {
	r := mux.NewRouter()

	file := r.Path("/files/{id}").Subrouter()
	file.Methods("GET").HandlerFunc(FileGetHandler)
	file.Methods("POST").HandlerFunc(FileCreateHandler)

	http.ListenAndServe(":"+os.Getenv("PORT"), r)
}

func FileCreateHandler(rw http.ResponseWriter, r *http.Request) {
	id := mux.Vars(r)["id"]
	path := "/Users/sebastian/" + id
	body, _ := ioutil.ReadAll(r.Body)

	file, err := os.Create(path)
	if err != nil {
		rw.WriteHeader(http.StatusInternalServerError)
		rw.Write([]byte("Error: " + err.Error()))
	}
	defer file.Close()

	file.Write(body)
	file.Sync()

	fmt.Printf("Created file with id: %s", id)
	rw.WriteHeader(http.StatusOK)
}

func FileGetHandler(rw http.ResponseWriter, r *http.Request) {
	id := mux.Vars(r)["id"]
	path := "/Users/sebastian/" + id

	data, err := ioutil.ReadFile(path)
	if err != nil {
		rw.WriteHeader(http.StatusNotFound)
		return
	}

	rw.WriteHeader(http.StatusOK)
	rw.Write(data)
}
<commit_msg>Added missing return statement<commit_after>package main

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

	"github.com/gorilla/mux"
)

func main() {
	r := mux.NewRouter()

	file := r.Path("/files/{id}").Subrouter()
	file.Methods("GET").HandlerFunc(FileGetHandler)
	file.Methods("POST").HandlerFunc(FileCreateHandler)

	http.ListenAndServe(":"+os.Getenv("PORT"), r)
}

func FileCreateHandler(rw http.ResponseWriter, r *http.Request) {
	id := mux.Vars(r)["id"]
	path := "/Users/sebastian/" + id
	body, _ := ioutil.ReadAll(r.Body)

	file, err := os.Create(path)
	if err != nil {
		rw.WriteHeader(http.StatusInternalServerError)
		rw.Write([]byte("Error: " + err.Error()))
		return
	}
	defer file.Close()

	file.Write(body)
	file.Sync()

	fmt.Printf("Created file with id: %s", id)
	rw.WriteHeader(http.StatusOK)
}

func FileGetHandler(rw http.ResponseWriter, r *http.Request) {
	id := mux.Vars(r)["id"]
	path := "/Users/sebastian/" + id

	data, err := ioutil.ReadFile(path)
	if err != nil {
		rw.WriteHeader(http.StatusNotFound)
		return
	}

	rw.WriteHeader(http.StatusOK)
	rw.Write(data)
}
<|endoftext|>


<commit_before>package netevents

import (
	"context"
	"net"

	"github.com/segmentio/events"
)

// DialFunc returns a wrapper for dial which logs opening and closing events
// that occur on the connections returned by the function.
//
// The logger may be nil, in that case the default logger is used to report
// the connection events.
func DialFunc(logger *events.Logger, dial func(string, string) (net.Conn, error)) func(string, string) (net.Conn, error) {
	dialContext := dialContextFunc(1, logger,
		func(ctx context.Context, network string, address string) (net.Conn, error) {
			return dial(network, address)
		},
	)
	return func(network string, address string) (net.Conn, error) {
		return dialContext(context.Background(), network, address)
	}
}

// DialContextFunc returns a wrapper for dial which logs opening and closing
// events that occur on the connections returned by the function.
//
// The logger may be nil, in that case the default logger is used to report
// the connection events.
func DialContextFunc(logger *events.Logger, dial func(context.Context, string, string) (net.Conn, error)) func(context.Context, string, string) (net.Conn, error) {
	return dialContextFunc(0, logger, dial)
}

func dialContextFunc(depth int, logger *events.Logger, dial func(context.Context, string, string) (net.Conn, error)) func(context.Context, string, string) (net.Conn, error) {
	if logger == nil {
		logger = events.DefaultLogger
	}
	return func(ctx context.Context, network string, address string) (conn net.Conn, err error) {
		if conn, err = dial(ctx, network, address); err == nil {
			c := &connLogger{Conn: conn, Logger: logger, typ: "client"}
			c.open(depth + 1)
			conn = c
		}
		return
	}
}
<commit_msg>add finalizer to client connections<commit_after>package netevents

import (
	"context"
	"net"
	"runtime"

	"github.com/segmentio/events"
)

// DialFunc returns a wrapper for dial which logs opening and closing events
// that occur on the connections returned by the function.
//
// The logger may be nil, in that case the default logger is used to report
// the connection events.
func DialFunc(logger *events.Logger, dial func(string, string) (net.Conn, error)) func(string, string) (net.Conn, error) {
	dialContext := dialContextFunc(1, logger,
		func(ctx context.Context, network string, address string) (net.Conn, error) {
			return dial(network, address)
		},
	)
	return func(network string, address string) (net.Conn, error) {
		return dialContext(context.Background(), network, address)
	}
}

// DialContextFunc returns a wrapper for dial which logs opening and closing
// events that occur on the connections returned by the function.
//
// The logger may be nil, in that case the default logger is used to report
// the connection events.
func DialContextFunc(logger *events.Logger, dial func(context.Context, string, string) (net.Conn, error)) func(context.Context, string, string) (net.Conn, error) {
	return dialContextFunc(0, logger, dial)
}

func dialContextFunc(depth int, logger *events.Logger, dial func(context.Context, string, string) (net.Conn, error)) func(context.Context, string, string) (net.Conn, error) {
	if logger == nil {
		logger = events.DefaultLogger
	}
	return func(ctx context.Context, network string, address string) (conn net.Conn, err error) {
		if conn, err = dial(ctx, network, address); err == nil {
			c := &connLogger{Conn: conn, Logger: logger, typ: "client"}
			c.open(depth + 1)
			conn = c
			// Ensure the connection emits a close event if it's closed by the
			// garbage collector.
			runtime.SetFinalizer(c, func(c *connLogger) { c.close(0) })
		}
		return
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"os"
	"strings"

	"github.com/urfave/cli/v2"

	"github.com/gotgenes/getignore/getters"
	"github.com/gotgenes/getignore/list"
	"github.com/gotgenes/getignore/writers"
)

// Version is the version of getignore
const Version string = "1.0.0"

func main() {
	log.SetFlags(0)
	app := creatCLI()
	app.RunAndExitOnError()
}

func creatCLI() *cli.App {
	app := cli.NewApp()
	app.Name = "getignore"
	app.Version = Version
	app.Usage = "Bootstraps gitignore files from central sources"

	app.Commands = []*cli.Command{
		&cli.Command{
			Name:  "get",
			Usage: "Retrieves gitignore patterns files from a central source and concatenates them",
			Flags: []cli.Flag{
				&cli.StringFlag{
					Name:    "base-url",
					Aliases: []string{"u"},
					Usage:   "The URL under which gitignore files can be found",
					Value:   "https://raw.githubusercontent.com/github/gitignore/master",
				},
				&cli.StringFlag{
					Name:    "default-extension",
					Aliases: []string{"e"},
					Usage:   "The default file extension appended to names when retrieving them",
					Value:   ".gitignore",
				},
				&cli.IntFlag{
					Name:  "max-connections",
					Usage: "The number of maximum connections to open for HTTP requests",
					Value: 8,
				},
				&cli.StringFlag{
					Name:    "names-file",
					Aliases: []string{"n"},
					Usage:   "Path to file containing names of gitignore patterns files",
				},
				&cli.StringFlag{
					Name:    "output-file",
					Aliases: []string{"o"},
					Usage:   "Path to output file (default: STDOUT)",
				},
			},
			ArgsUsage: "[gitignore_name] [gitignore_name …]",
			Action:    downloadAllIgnoreFiles,
		},
		&cli.Command{
			Name:  "list",
			Usage: "Retrieves and prints a list of available ignore files",
			Flags: []cli.Flag{
				&cli.StringFlag{
					Name:    "api-url",
					Aliases: []string{"u"},
					Usage:   "The GitHub Tree API-compatible URL to the repository of ignore files",
					Value:   "https://api.github.com/repos/github/gitignore/git/trees/master?recursive=1",
				},
				&cli.StringFlag{
					Name:    "suffix",
					Aliases: []string{"s"},
					Usage:   "The suffix to use to identify ignore files",
					Value:   ".gitignore",
				},
			},
			ArgsUsage: "",
			Action:    listIgnoreFiles,
		},
	}

	return app
}

func downloadAllIgnoreFiles(context *cli.Context) error {
	names := getNamesFromArguments(context)
	getter := getters.HTTPGetter{
		BaseURL:          context.String("base-url"),
		DefaultExtension: context.String("default-extension"),
		MaxConnections:   context.Int("max-connections"),
	}
	contents, err := getter.GetIgnoreFiles(names)
	if err != nil {
		return err
	}
	outputFilePath, outputFile, err := getOutputFile(context)
	if err != nil {
		return err
	}
	log.Println("Writing contents to", outputFilePath)
	err = writers.WriteIgnoreFile(outputFile, contents)
	if err != nil {
		return err
	}
	return err
}

func getNamesFromArguments(context *cli.Context) []string {
	names := context.Args().Slice()

	if context.String("names-file") != "" {
		namesFile, _ := os.Open(context.String("names-file"))
		names = append(names, ParseNamesFile(namesFile)...)
	}
	return names
}

// ParseNamesFile reads a file containing one name of a gitignore patterns file per line
func ParseNamesFile(namesFile io.Reader) []string {
	var a []string
	scanner := bufio.NewScanner(namesFile)
	for scanner.Scan() {
		name := strings.TrimSpace(scanner.Text())
		if len(name) > 0 {
			a = append(a, name)
		}
	}
	return a
}

func getOutputFile(context *cli.Context) (outputFilePath string, outputFile io.Writer, err error) {
	outputFilePath = context.String("o")
	if outputFilePath == "" {
		outputFilePath = "STDOUT"
		outputFile = os.Stdout
	} else {
		outputFile, err = os.Create(outputFilePath)
	}
	return
}

func listIgnoreFiles(context *cli.Context) error {
	outputString, err := list.ListIgnoreFiles(context.String("api-url"), Version, context.String("suffix"))
	if err != nil {
		return err
	}
	_, err = fmt.Println(outputString)
	return err
}
<commit_msg>Remove redundant struct name.<commit_after>package main

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"os"
	"strings"

	"github.com/urfave/cli/v2"

	"github.com/gotgenes/getignore/getters"
	"github.com/gotgenes/getignore/list"
	"github.com/gotgenes/getignore/writers"
)

// Version is the version of getignore
const Version string = "1.0.0"

func main() {
	log.SetFlags(0)
	app := creatCLI()
	app.RunAndExitOnError()
}

func creatCLI() *cli.App {
	app := cli.NewApp()
	app.Name = "getignore"
	app.Version = Version
	app.Usage = "Bootstraps gitignore files from central sources"

	app.Commands = []*cli.Command{
		{
			Name:  "get",
			Usage: "Retrieves gitignore patterns files from a central source and concatenates them",
			Flags: []cli.Flag{
				&cli.StringFlag{
					Name:    "base-url",
					Aliases: []string{"u"},
					Usage:   "The URL under which gitignore files can be found",
					Value:   "https://raw.githubusercontent.com/github/gitignore/master",
				},
				&cli.StringFlag{
					Name:    "default-extension",
					Aliases: []string{"e"},
					Usage:   "The default file extension appended to names when retrieving them",
					Value:   ".gitignore",
				},
				&cli.IntFlag{
					Name:  "max-connections",
					Usage: "The number of maximum connections to open for HTTP requests",
					Value: 8,
				},
				&cli.StringFlag{
					Name:    "names-file",
					Aliases: []string{"n"},
					Usage:   "Path to file containing names of gitignore patterns files",
				},
				&cli.StringFlag{
					Name:    "output-file",
					Aliases: []string{"o"},
					Usage:   "Path to output file (default: STDOUT)",
				},
			},
			ArgsUsage: "[gitignore_name] [gitignore_name …]",
			Action:    downloadAllIgnoreFiles,
		},
		{
			Name:  "list",
			Usage: "Retrieves and prints a list of available ignore files",
			Flags: []cli.Flag{
				&cli.StringFlag{
					Name:    "api-url",
					Aliases: []string{"u"},
					Usage:   "The GitHub Tree API-compatible URL to the repository of ignore files",
					Value:   "https://api.github.com/repos/github/gitignore/git/trees/master?recursive=1",
				},
				&cli.StringFlag{
					Name:    "suffix",
					Aliases: []string{"s"},
					Usage:   "The suffix to use to identify ignore files",
					Value:   ".gitignore",
				},
			},
			ArgsUsage: "",
			Action:    listIgnoreFiles,
		},
	}

	return app
}

func downloadAllIgnoreFiles(context *cli.Context) error {
	names := getNamesFromArguments(context)
	getter := getters.HTTPGetter{
		BaseURL:          context.String("base-url"),
		DefaultExtension: context.String("default-extension"),
		MaxConnections:   context.Int("max-connections"),
	}
	contents, err := getter.GetIgnoreFiles(names)
	if err != nil {
		return err
	}
	outputFilePath, outputFile, err := getOutputFile(context)
	if err != nil {
		return err
	}
	log.Println("Writing contents to", outputFilePath)
	err = writers.WriteIgnoreFile(outputFile, contents)
	if err != nil {
		return err
	}
	return err
}

func getNamesFromArguments(context *cli.Context) []string {
	names := context.Args().Slice()

	if context.String("names-file") != "" {
		namesFile, _ := os.Open(context.String("names-file"))
		names = append(names, ParseNamesFile(namesFile)...)
	}
	return names
}

// ParseNamesFile reads a file containing one name of a gitignore patterns file per line
func ParseNamesFile(namesFile io.Reader) []string {
	var a []string
	scanner := bufio.NewScanner(namesFile)
	for scanner.Scan() {
		name := strings.TrimSpace(scanner.Text())
		if len(name) > 0 {
			a = append(a, name)
		}
	}
	return a
}

func getOutputFile(context *cli.Context) (outputFilePath string, outputFile io.Writer, err error) {
	outputFilePath = context.String("o")
	if outputFilePath == "" {
		outputFilePath = "STDOUT"
		outputFile = os.Stdout
	} else {
		outputFile, err = os.Create(outputFilePath)
	}
	return
}

func listIgnoreFiles(context *cli.Context) error {
	outputString, err := list.ListIgnoreFiles(context.String("api-url"), Version, context.String("suffix"))
	if err != nil {
		return err
	}
	_, err = fmt.Println(outputString)
	return err
}
<|endoftext|>


<commit_before>package netmux

import (
	"fmt"
	"net"
	"os"
)

type PipeOutput struct {
	in   chan []byte
	out  *os.File
	quit chan bool
}

type UDPOutput struct {
	in   chan []byte
	out  *net.UDPAddr
	quit chan bool
	conn *net.UDPConn
}

type UnixOutput struct {
	in   chan []byte
	out  *net.UnixAddr
	quit chan bool
	conn *net.UnixConn
}

type TCPOutput struct {
	in   chan []byte
	out  *net.TCPAddr
	quit chan bool
	conn *net.TCPConn
}

type Output interface {
	send([]byte)
	teardown()
}

func (o *PipeOutput) send(chunk []byte) {
	o.in <- chunk
}

func (o *UDPOutput) send(chunk []byte) {
	o.in <- chunk
}

func (o *UnixOutput) send(chunk []byte) {
	o.in <- chunk
}

func (o *TCPOutput) send(chunk []byte) {
	o.in <- chunk
}

func (o *PipeOutput) read() {
	for {
		select {
		case chunk := <-o.in:
			if _, err := o.out.Write(chunk); err != nil {
				fmt.Println("Error writing to outfile! Terminating output")
				o.quit <- true
			}
		case <-o.quit:
			return
		}
	}
}

func (o *PipeOutput) teardown() {}

func (o *UDPOutput) read() {
	conn, err := net.DialUDP("udp", nil, o.out)
	if err != nil {
		fmt.Printf("Couldn't dial address %s: %s\n", o.out, err)
		return
	}
	o.conn = conn
	defer o.conn.Close()
	for {
		select {
		case chunk := <-o.in:
			if _, err := conn.Write(chunk); err != nil {
				conn, err := o.tryReconnect(chunk)
				if err != nil {
					fmt.Println("Error writing to remote addr! Terminating output")
					o.quit <- true
				}
				o.conn = conn
			}
		case <-o.quit:
			return
		}
	}
}

func (o *UDPOutput) tryReconnect(chunk []byte) (*net.UDPConn, error) {
	var err error
	for i := 0; i < 5; i++ {
		conn, err := net.DialUDP("udp", nil, o.out)
		if err == nil {
			conn.Write(chunk)
			return conn, nil
		}
	}
	return nil, err
}

func (o *UDPOutput) teardown() {
}

func (o *UnixOutput) read() {
	conn, err := net.DialUnix("unix", nil, o.out)
	if err != nil {
		fmt.Printf("Couldn't dial address %s: %s\n", o.out, err)
		return
	}
	o.conn = conn
	defer o.conn.Close()
	for {
		select {
		case chunk := <-o.in:
			if _, err := conn.Write(chunk); err != nil {
				conn, err := o.tryReconnect(chunk)
				if err != nil {
					fmt.Println("Error writing to remote addr! Terminating output")
					o.quit <- true
				}
				o.conn = conn
			}
		case <-o.quit:
			return
		}
	}
}

func (o *UnixOutput) tryReconnect(chunk []byte) (*net.UnixConn, error) {
	var err error
	for i := 0; i < 5; i++ {
		conn, err := net.DialUnix("udp", nil, o.out)
		if err == nil {
			conn.Write(chunk)
			return conn, nil
		}
	}
	return nil, err
}

func (o *UnixOutput) teardown() {
	os.Remove(o.out.String())
}

func (o *TCPOutput) read() {
	conn, err := net.DialTCP("tcp", nil, o.out)
	if err != nil {
		fmt.Printf("Couldn't dial address %s: %s\n", o.out, err)
		return
	}
	o.conn = conn
	defer o.conn.Close()
	for {
		select {
		case chunk := <-o.in:
			if _, err := conn.Write(chunk); err != nil {
				conn, err := o.tryReconnect(chunk)
				if err != nil {
					fmt.Println("Error writing to remote addr! Terminating output")
					o.quit <- true
				}
				o.conn = conn
			}
		case <-o.quit:
			return
		}
	}
}

func (o *TCPOutput) tryReconnect(chunk []byte) (*net.TCPConn, error) {
	var err error
	for i := 0; i < 5; i++ {
		conn, err := net.DialTCP("udp", nil, o.out)
		if err == nil {
			conn.Write(chunk)
			return conn, nil
		}
	}
	return nil, err
}

func (o *TCPOutput) teardown() {
	os.Remove(o.out.String())
}
<commit_msg>Close connections on teardown<commit_after>package netmux

import (
	"fmt"
	"net"
	"os"
)

type PipeOutput struct {
	in   chan []byte
	out  *os.File
	quit chan bool
}

type UDPOutput struct {
	in   chan []byte
	out  *net.UDPAddr
	quit chan bool
	conn *net.UDPConn
}

type UnixOutput struct {
	in   chan []byte
	out  *net.UnixAddr
	quit chan bool
	conn *net.UnixConn
}

type TCPOutput struct {
	in   chan []byte
	out  *net.TCPAddr
	quit chan bool
	conn *net.TCPConn
}

type Output interface {
	send([]byte)
	teardown()
}

func (o *PipeOutput) send(chunk []byte) {
	o.in <- chunk
}

func (o *UDPOutput) send(chunk []byte) {
	o.in <- chunk
}

func (o *UnixOutput) send(chunk []byte) {
	o.in <- chunk
}

func (o *TCPOutput) send(chunk []byte) {
	o.in <- chunk
}

func (o *PipeOutput) read() {
	for {
		select {
		case chunk := <-o.in:
			if _, err := o.out.Write(chunk); err != nil {
				fmt.Println("Error writing to outfile! Terminating output")
				o.quit <- true
			}
			o.out.Write([]byte("\n===\n"))
		case <-o.quit:
			return
		}
	}
}

func (o *PipeOutput) teardown() {
}

func (o *UDPOutput) read() {
	conn, err := net.DialUDP("udp", nil, o.out)
	if err != nil {
		fmt.Printf("Couldn't dial address %s: %s\n", o.out, err)
		return
	}
	o.conn = conn
	defer o.conn.Close()
	for {
		select {
		case chunk := <-o.in:
			if _, err := conn.Write(chunk); err != nil {
				conn, err := o.tryReconnect(chunk)
				if err != nil {
					fmt.Println("Error writing to remote addr! Terminating output")
					o.quit <- true
				}
				o.conn = conn
			}
		case <-o.quit:
			return
		}
	}
}

func (o *UDPOutput) tryReconnect(chunk []byte) (*net.UDPConn, error) {
	var err error
	for i := 0; i < 5; i++ {
		conn, err := net.DialUDP("udp", nil, o.out)
		if err == nil {
			conn.Write(chunk)
			return conn, nil
		}
	}
	return nil, err
}

func (o *UDPOutput) teardown() {
	if o.conn != nil {
		o.conn.Close()
	}
}

func (o *UnixOutput) read() {
	conn, err := net.DialUnix("unix", nil, o.out)
	if err != nil {
		fmt.Printf("Couldn't dial address %s: %s\n", o.out, err)
		return
	}
	o.conn = conn
	defer o.conn.Close()
	for {
		select {
		case chunk := <-o.in:
			if _, err := conn.Write(chunk); err != nil {
				conn, err := o.tryReconnect(chunk)
				if err != nil {
					fmt.Println("Error writing to remote addr! Terminating output")
					o.quit <- true
				}
				o.conn = conn
			}
		case <-o.quit:
			return
		}
	}
}

func (o *UnixOutput) tryReconnect(chunk []byte) (*net.UnixConn, error) {
	var err error
	for i := 0; i < 5; i++ {
		conn, err := net.DialUnix("udp", nil, o.out)
		if err == nil {
			conn.Write(chunk)
			return conn, nil
		}
	}
	return nil, err
}

func (o *UnixOutput) teardown() {
	if o.conn != nil {
		o.conn.Close()
	}
	os.Remove(o.out.String())
}

func (o *TCPOutput) read() {
	conn, err := net.DialTCP("tcp", nil, o.out)
	if err != nil {
		fmt.Printf("Couldn't dial address %s: %s\n", o.out, err)
		return
	}
	o.conn = conn
	defer o.conn.Close()
	for {
		select {
		case chunk := <-o.in:
			if _, err := conn.Write(chunk); err != nil {
				conn, err := o.tryReconnect(chunk)
				if err != nil {
					fmt.Println("Error writing to remote addr! Terminating output")
					o.quit <- true
				}
				o.conn = conn
			}
		case <-o.quit:
			return
		}
	}
}

func (o *TCPOutput) tryReconnect(chunk []byte) (*net.TCPConn, error) {
	var err error
	for i := 0; i < 5; i++ {
		conn, err := net.DialTCP("udp", nil, o.out)
		if err == nil {
			conn.Write(chunk)
			return conn, nil
		}
	}
	return nil, err
}

func (o *TCPOutput) teardown() {
	if o.conn != nil {
		o.conn.Close()
	}
}
<|endoftext|>


<commit_before>package unionfs

import (
	"github.com/hanwen/go-fuse/fuse"
)

type attrResponse struct {
	*fuse.Attr
	fuse.Status
}

type dirResponse struct {
	entries []fuse.DirEntry
	fuse.Status
}

type linkResponse struct {
	linkContent string
	fuse.Status
}

// Caches readdir and getattr()
type CachingFileSystem struct {
	fuse.FileSystem

	attributes *TimedCache
	dirs       *TimedCache
	links      *TimedCache
}

func readDir(fs fuse.FileSystem, name string) *dirResponse {
	origStream, code := fs.OpenDir(name)

	r := &dirResponse{nil, code}
	if code != fuse.OK {
		return r
	}

	for {
		d, ok := <-origStream
		if !ok {
			break
		}
		r.entries = append(r.entries, d)
	}

	return r
}

func getAttr(fs fuse.FileSystem, name string) *attrResponse {
	a, code := fs.GetAttr(name)
	return &attrResponse{
		Attr:   a,
		Status: code,
	}
}

func readLink(fs fuse.FileSystem, name string) *linkResponse {
	a, code := fs.Readlink(name)
	return &linkResponse{
		linkContent: a,
		Status:      code,
	}
}

func NewCachingFileSystem(fs fuse.FileSystem, ttlNs int64) *CachingFileSystem {
	c := new(CachingFileSystem)
	c.FileSystem = fs
	c.attributes = NewTimedCache(func(n string) interface{} { return getAttr(fs, n) }, ttlNs)
	c.dirs = NewTimedCache(func(n string) interface{} { return readDir(fs, n) }, ttlNs)
	c.links = NewTimedCache(func(n string) interface{} { return readLink(fs, n) }, ttlNs)
	return c
}

func (me *CachingFileSystem) GetAttr(name string) (*fuse.Attr, fuse.Status) {
	r := me.attributes.Get(name).(attrResponse)
	return r.Attr, r.Status
}

func (me *CachingFileSystem) Readlink(name string) (string, fuse.Status) {
	r := me.attributes.Get(name).(linkResponse)
	return r.linkContent, r.Status
}

func (me *CachingFileSystem) OpenDir(name string) (stream chan fuse.DirEntry, status fuse.Status) {
	r := me.dirs.Get(name).(dirResponse)
	if r.Status == fuse.OK {
		stream = make(chan fuse.DirEntry, len(r.entries))
		for _, d := range r.entries {
			stream <- d
		}
		close(stream)
		return stream, r.Status
	}

	return nil, r.Status
}
<commit_msg>Fixes for CachingFileSystem.<commit_after>package unionfs

import (
	"fmt"
	"github.com/hanwen/go-fuse/fuse"
)
var _ = fmt.Println
type attrResponse struct {
	*fuse.Attr
	fuse.Status
}

type dirResponse struct {
	entries []fuse.DirEntry
	fuse.Status
}

type linkResponse struct {
	linkContent string
	fuse.Status
}

// Caches readdir and getattr()
type CachingFileSystem struct {
	fuse.FileSystem

	attributes *TimedCache
	dirs       *TimedCache
	links      *TimedCache
}

func readDir(fs fuse.FileSystem, name string) *dirResponse {
	origStream, code := fs.OpenDir(name)

	r := &dirResponse{nil, code}
	if code != fuse.OK {
		return r
	}

	for {
		d, ok := <-origStream
		if !ok {
			break
		}
		r.entries = append(r.entries, d)
	}
	return r
}

func getAttr(fs fuse.FileSystem, name string) *attrResponse {
	a, code := fs.GetAttr(name)
	return &attrResponse{
		Attr:   a,
		Status: code,
	}
}

func readLink(fs fuse.FileSystem, name string) *linkResponse {
	a, code := fs.Readlink(name)
	return &linkResponse{
		linkContent: a,
		Status:      code,
	}
}

func NewCachingFileSystem(fs fuse.FileSystem, ttlNs int64) *CachingFileSystem {
	c := new(CachingFileSystem)
	c.FileSystem = fs
	c.attributes = NewTimedCache(func(n string) interface{} { return getAttr(fs, n) }, ttlNs)
	c.dirs = NewTimedCache(func(n string) interface{} { return readDir(fs, n) }, ttlNs)
	c.links = NewTimedCache(func(n string) interface{} { return readLink(fs, n) }, ttlNs)
	return c
}

func (me *CachingFileSystem) GetAttr(name string) (*fuse.Attr, fuse.Status) {
	r := me.attributes.Get(name).(*attrResponse)
	return r.Attr, r.Status
}

func (me *CachingFileSystem) Readlink(name string) (string, fuse.Status) {
	r := me.attributes.Get(name).(*linkResponse)
	return r.linkContent, r.Status
}

func (me *CachingFileSystem) OpenDir(name string) (stream chan fuse.DirEntry, status fuse.Status) {
	r := me.dirs.Get(name).(*dirResponse)
	if r.Status == fuse.OK {
		stream = make(chan fuse.DirEntry, len(r.entries))
		for _, d := range r.entries {
			stream <- d
		}
		close(stream)
		return stream, r.Status
	}

	return nil, r.Status
}
<|endoftext|>


<commit_before>package testutil

import (
	crand "crypto/rand"
	peer "github.com/jbenet/go-ipfs/peer"
	u "github.com/jbenet/go-ipfs/util"
)

func RandPeer() peer.Peer {
	id := make([]byte, 16)
	crand.Read(id)
	mhid := u.Hash(id)
	return NewPeerWithID(peer.ID(mhid))
}
<commit_msg>testutil: gen peers with keys<commit_after>package testutil

import (
	crand "crypto/rand"
	ci "github.com/jbenet/go-ipfs/crypto"
	peer "github.com/jbenet/go-ipfs/peer"
	u "github.com/jbenet/go-ipfs/util"
)

func RandPeer() peer.Peer {
	id := make([]byte, 16)
	crand.Read(id)
	mhid := u.Hash(id)
	return NewPeerWithID(peer.ID(mhid))
}

func PeerWithNewKeys() (peer.Peer, error) {
	sk, pk, err := ci.GenerateKeyPair(ci.RSA, 512)
	if err != nil {
		return nil, err
	}

	return NewPeerWithKeyPair(sk, pk)
}
<|endoftext|>


<commit_before>package json

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"strconv"
	"strings"
	"time"

	"github.com/influxdata/telegraf"
	"github.com/influxdata/telegraf/filter"
	"github.com/influxdata/telegraf/internal"
	"github.com/influxdata/telegraf/metric"
	"github.com/tidwall/gjson"
)

var (
	utf8BOM      = []byte("\xef\xbb\xbf")
	ErrWrongType = errors.New("must be an object or an array of objects")
)

type Config struct {
	MetricName   string
	TagKeys      []string
	NameKey      string
	StringFields []string
	Query        string
	TimeKey      string
	TimeFormat   string
	Timezone     string
	DefaultTags  map[string]string
}

type Parser struct {
	metricName   string
	tagKeys      []string
	stringFields filter.Filter
	nameKey      string
	query        string
	timeKey      string
	timeFormat   string
	timezone     string
	defaultTags  map[string]string
}

func New(config *Config) (*Parser, error) {
	stringFilter, err := filter.Compile(config.StringFields)
	if err != nil {
		return nil, err
	}

	return &Parser{
		metricName:   config.MetricName,
		tagKeys:      config.TagKeys,
		nameKey:      config.NameKey,
		stringFields: stringFilter,
		query:        config.Query,
		timeKey:      config.TimeKey,
		timeFormat:   config.TimeFormat,
		timezone:     config.Timezone,
		defaultTags:  config.DefaultTags,
	}, nil
}

func (p *Parser) parseArray(data []interface{}) ([]telegraf.Metric, error) {
	results := make([]telegraf.Metric, 0)

	for _, item := range data {
		switch v := item.(type) {
		case map[string]interface{}:
			metrics, err := p.parseObject(v)
			if err != nil {
				return nil, err
			}
			results = append(results, metrics...)
		default:
			return nil, ErrWrongType

		}
	}

	return results, nil
}

func (p *Parser) parseObject(data map[string]interface{}) ([]telegraf.Metric, error) {
	tags := make(map[string]string)
	for k, v := range p.defaultTags {
		tags[k] = v
	}

	f := JSONFlattener{}
	err := f.FullFlattenJSON("", data, true, true)
	if err != nil {
		return nil, err
	}

	name := p.metricName

	//checks if json_name_key is set
	if p.nameKey != "" {
		switch field := f.Fields[p.nameKey].(type) {
		case string:
			name = field
		}
	}

	//if time key is specified, set it to nTime
	nTime := time.Now().UTC()
	if p.timeKey != "" {
		if p.timeFormat == "" {
			err := fmt.Errorf("use of 'json_time_key' requires 'json_time_format'")
			return nil, err
		}

		if f.Fields[p.timeKey] == nil {
			err := fmt.Errorf("JSON time key could not be found")
			return nil, err
		}

		nTime, err = internal.ParseTimestampWithLocation(f.Fields[p.timeKey], p.timeFormat, p.timezone)
		if err != nil {
			return nil, err
		}

		delete(f.Fields, p.timeKey)

		//if the year is 0, set to current year
		if nTime.Year() == 0 {
			nTime = nTime.AddDate(time.Now().Year(), 0, 0)
		}
	}

	tags, nFields := p.switchFieldToTag(tags, f.Fields)
	metric, err := metric.New(name, tags, nFields, nTime)
	if err != nil {
		return nil, err
	}
	return []telegraf.Metric{metric}, nil
}

//will take in field map with strings and bools,
//search for TagKeys that match fieldnames and add them to tags
//will delete any strings/bools that shouldn't be fields
//assumes that any non-numeric values in TagKeys should be displayed as tags
func (p *Parser) switchFieldToTag(tags map[string]string, fields map[string]interface{}) (map[string]string, map[string]interface{}) {
	for _, name := range p.tagKeys {
		//switch any fields in tagkeys into tags
		if fields[name] == nil {
			continue
		}
		switch value := fields[name].(type) {
		case string:
			tags[name] = value
			delete(fields, name)
		case bool:
			tags[name] = strconv.FormatBool(value)
			delete(fields, name)
		case float64:
			tags[name] = strconv.FormatFloat(value, 'f', -1, 64)
			delete(fields, name)
		default:
			log.Printf("E! [parsers.json] Unrecognized type %T", value)
		}
	}

	//remove any additional string/bool values from fields
	for fk := range fields {
		switch fields[fk].(type) {
		case string:
			if p.stringFields != nil && p.stringFields.Match(fk) {
				continue
			}
			delete(fields, fk)
		case bool:
			delete(fields, fk)
		}
	}
	return tags, fields
}

func (p *Parser) Parse(buf []byte) ([]telegraf.Metric, error) {
	if p.query != "" {
		result := gjson.GetBytes(buf, p.query)
		buf = []byte(result.Raw)
		if !result.IsArray() && !result.IsObject() {
			err := fmt.Errorf("E! Query path must lead to a JSON object or array of objects, but lead to: %v", result.Type)
			return nil, err
		}
	}

	buf = bytes.TrimSpace(buf)
	buf = bytes.TrimPrefix(buf, utf8BOM)
	if len(buf) == 0 {
		return make([]telegraf.Metric, 0), nil
	}

	var data interface{}
	err := json.Unmarshal(buf, &data)
	if err != nil {
		return nil, err
	}

	switch v := data.(type) {
	case map[string]interface{}:
		return p.parseObject(v)
	case []interface{}:
		return p.parseArray(v)
	default:
		return nil, ErrWrongType
	}
}

func (p *Parser) ParseLine(line string) (telegraf.Metric, error) {
	metrics, err := p.Parse([]byte(line + "\n"))

	if err != nil {
		return nil, err
	}

	if len(metrics) < 1 {
		return nil, fmt.Errorf("can not parse the line: %s, for data format: json ", line)
	}

	return metrics[0], nil
}

func (p *Parser) SetDefaultTags(tags map[string]string) {
	p.defaultTags = tags
}

type JSONFlattener struct {
	Fields map[string]interface{}
}

// FlattenJSON flattens nested maps/interfaces into a fields map (ignoring bools and string)
func (f *JSONFlattener) FlattenJSON(
	fieldname string,
	v interface{}) error {
	if f.Fields == nil {
		f.Fields = make(map[string]interface{})
	}

	return f.FullFlattenJSON(fieldname, v, false, false)
}

// FullFlattenJSON flattens nested maps/interfaces into a fields map (including bools and string)
func (f *JSONFlattener) FullFlattenJSON(
	fieldname string,
	v interface{},
	convertString bool,
	convertBool bool,
) error {
	if f.Fields == nil {
		f.Fields = make(map[string]interface{})
	}
	fieldname = strings.Trim(fieldname, "_")
	switch t := v.(type) {
	case map[string]interface{}:
		for k, v := range t {
			err := f.FullFlattenJSON(fieldname+"_"+k+"_", v, convertString, convertBool)
			if err != nil {
				return err
			}
		}
	case []interface{}:
		for i, v := range t {
			k := strconv.Itoa(i)
			err := f.FullFlattenJSON(fieldname+"_"+k+"_", v, convertString, convertBool)
			if err != nil {
				return nil
			}
		}
	case float64:
		f.Fields[fieldname] = t
	case string:
		if convertString {
			f.Fields[fieldname] = v.(string)
		} else {
			return nil
		}
	case bool:
		if convertBool {
			f.Fields[fieldname] = v.(bool)
		} else {
			return nil
		}
	case nil:
		return nil
	default:
		return fmt.Errorf("JSON Flattener: got unexpected type %T with value %v (%s)",
			t, t, fieldname)
	}
	return nil
}
<commit_msg>Keep boolean when listed in json_string_fields (#6400)<commit_after>package json

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"strconv"
	"strings"
	"time"

	"github.com/influxdata/telegraf"
	"github.com/influxdata/telegraf/filter"
	"github.com/influxdata/telegraf/internal"
	"github.com/influxdata/telegraf/metric"
	"github.com/tidwall/gjson"
)

var (
	utf8BOM      = []byte("\xef\xbb\xbf")
	ErrWrongType = errors.New("must be an object or an array of objects")
)

type Config struct {
	MetricName   string
	TagKeys      []string
	NameKey      string
	StringFields []string
	Query        string
	TimeKey      string
	TimeFormat   string
	Timezone     string
	DefaultTags  map[string]string
}

type Parser struct {
	metricName   string
	tagKeys      []string
	stringFields filter.Filter
	nameKey      string
	query        string
	timeKey      string
	timeFormat   string
	timezone     string
	defaultTags  map[string]string
}

func New(config *Config) (*Parser, error) {
	stringFilter, err := filter.Compile(config.StringFields)
	if err != nil {
		return nil, err
	}

	return &Parser{
		metricName:   config.MetricName,
		tagKeys:      config.TagKeys,
		nameKey:      config.NameKey,
		stringFields: stringFilter,
		query:        config.Query,
		timeKey:      config.TimeKey,
		timeFormat:   config.TimeFormat,
		timezone:     config.Timezone,
		defaultTags:  config.DefaultTags,
	}, nil
}

func (p *Parser) parseArray(data []interface{}) ([]telegraf.Metric, error) {
	results := make([]telegraf.Metric, 0)

	for _, item := range data {
		switch v := item.(type) {
		case map[string]interface{}:
			metrics, err := p.parseObject(v)
			if err != nil {
				return nil, err
			}
			results = append(results, metrics...)
		default:
			return nil, ErrWrongType

		}
	}

	return results, nil
}

func (p *Parser) parseObject(data map[string]interface{}) ([]telegraf.Metric, error) {
	tags := make(map[string]string)
	for k, v := range p.defaultTags {
		tags[k] = v
	}

	f := JSONFlattener{}
	err := f.FullFlattenJSON("", data, true, true)
	if err != nil {
		return nil, err
	}

	name := p.metricName

	//checks if json_name_key is set
	if p.nameKey != "" {
		switch field := f.Fields[p.nameKey].(type) {
		case string:
			name = field
		}
	}

	//if time key is specified, set it to nTime
	nTime := time.Now().UTC()
	if p.timeKey != "" {
		if p.timeFormat == "" {
			err := fmt.Errorf("use of 'json_time_key' requires 'json_time_format'")
			return nil, err
		}

		if f.Fields[p.timeKey] == nil {
			err := fmt.Errorf("JSON time key could not be found")
			return nil, err
		}

		nTime, err = internal.ParseTimestampWithLocation(f.Fields[p.timeKey], p.timeFormat, p.timezone)
		if err != nil {
			return nil, err
		}

		delete(f.Fields, p.timeKey)

		//if the year is 0, set to current year
		if nTime.Year() == 0 {
			nTime = nTime.AddDate(time.Now().Year(), 0, 0)
		}
	}

	tags, nFields := p.switchFieldToTag(tags, f.Fields)
	metric, err := metric.New(name, tags, nFields, nTime)
	if err != nil {
		return nil, err
	}
	return []telegraf.Metric{metric}, nil
}

//will take in field map with strings and bools,
//search for TagKeys that match fieldnames and add them to tags
//will delete any strings/bools that shouldn't be fields
//assumes that any non-numeric values in TagKeys should be displayed as tags
func (p *Parser) switchFieldToTag(tags map[string]string, fields map[string]interface{}) (map[string]string, map[string]interface{}) {
	for _, name := range p.tagKeys {
		//switch any fields in tagkeys into tags
		if fields[name] == nil {
			continue
		}
		switch value := fields[name].(type) {
		case string:
			tags[name] = value
			delete(fields, name)
		case bool:
			tags[name] = strconv.FormatBool(value)
			delete(fields, name)
		case float64:
			tags[name] = strconv.FormatFloat(value, 'f', -1, 64)
			delete(fields, name)
		default:
			log.Printf("E! [parsers.json] Unrecognized type %T", value)
		}
	}

	//remove any additional string/bool values from fields
	for fk := range fields {
		switch fields[fk].(type) {
		case string, bool:
			if p.stringFields != nil && p.stringFields.Match(fk) {
				continue
			}
			delete(fields, fk)
		}
	}
	return tags, fields
}

func (p *Parser) Parse(buf []byte) ([]telegraf.Metric, error) {
	if p.query != "" {
		result := gjson.GetBytes(buf, p.query)
		buf = []byte(result.Raw)
		if !result.IsArray() && !result.IsObject() {
			err := fmt.Errorf("E! Query path must lead to a JSON object or array of objects, but lead to: %v", result.Type)
			return nil, err
		}
	}

	buf = bytes.TrimSpace(buf)
	buf = bytes.TrimPrefix(buf, utf8BOM)
	if len(buf) == 0 {
		return make([]telegraf.Metric, 0), nil
	}

	var data interface{}
	err := json.Unmarshal(buf, &data)
	if err != nil {
		return nil, err
	}

	switch v := data.(type) {
	case map[string]interface{}:
		return p.parseObject(v)
	case []interface{}:
		return p.parseArray(v)
	default:
		return nil, ErrWrongType
	}
}

func (p *Parser) ParseLine(line string) (telegraf.Metric, error) {
	metrics, err := p.Parse([]byte(line + "\n"))

	if err != nil {
		return nil, err
	}

	if len(metrics) < 1 {
		return nil, fmt.Errorf("can not parse the line: %s, for data format: json ", line)
	}

	return metrics[0], nil
}

func (p *Parser) SetDefaultTags(tags map[string]string) {
	p.defaultTags = tags
}

type JSONFlattener struct {
	Fields map[string]interface{}
}

// FlattenJSON flattens nested maps/interfaces into a fields map (ignoring bools and string)
func (f *JSONFlattener) FlattenJSON(
	fieldname string,
	v interface{}) error {
	if f.Fields == nil {
		f.Fields = make(map[string]interface{})
	}

	return f.FullFlattenJSON(fieldname, v, false, false)
}

// FullFlattenJSON flattens nested maps/interfaces into a fields map (including bools and string)
func (f *JSONFlattener) FullFlattenJSON(
	fieldname string,
	v interface{},
	convertString bool,
	convertBool bool,
) error {
	if f.Fields == nil {
		f.Fields = make(map[string]interface{})
	}
	fieldname = strings.Trim(fieldname, "_")
	switch t := v.(type) {
	case map[string]interface{}:
		for k, v := range t {
			err := f.FullFlattenJSON(fieldname+"_"+k+"_", v, convertString, convertBool)
			if err != nil {
				return err
			}
		}
	case []interface{}:
		for i, v := range t {
			k := strconv.Itoa(i)
			err := f.FullFlattenJSON(fieldname+"_"+k+"_", v, convertString, convertBool)
			if err != nil {
				return nil
			}
		}
	case float64:
		f.Fields[fieldname] = t
	case string:
		if convertString {
			f.Fields[fieldname] = v.(string)
		} else {
			return nil
		}
	case bool:
		if convertBool {
			f.Fields[fieldname] = v.(bool)
		} else {
			return nil
		}
	case nil:
		return nil
	default:
		return fmt.Errorf("JSON Flattener: got unexpected type %T with value %v (%s)",
			t, t, fieldname)
	}
	return nil
}
<|endoftext|>


<commit_before>package utils

import (
	"bytes"
	"strings"
)

// FilterIntoGroups filters []byte slices into two groups, depending on the given filter function
func FilterIntoGroups(bytelines [][]byte, filterfunc func([]byte) bool) ([][]byte, [][]byte) {
	var special, regular [][]byte
	for _, byteline := range bytelines {
		if filterfunc(byteline) {
			// Special
			special = append(special, byteline)
		} else {
			// Regular
			regular = append(regular, byteline)
		}
	}
	return special, regular
}

/*ExtractKeywords takes a source file as `data` and a list of keywords to
 * look for. Lines without keywords are returned, together with a map
 * from keywords to []bytes from the source `data`.
 *
 * The keywords in the data must be on the form "keyword: value",
 * and can be within single-line HTML comments (<-- ... -->).
 */
func ExtractKeywords(data []byte, keywordsToLookFor []string) ([]byte, map[string][]byte) {
	var (
		keywordColon      []byte
		inCommentBlock    bool
		singleLineComment bool
		lineCounter       uint64
	)
	bnl := []byte("\n")
	commentStart := []byte("<!--")
	commentEnd := []byte("-->")
	backtick := []byte("`")
	found := make(map[string][]byte)

	if bytes.Contains(data, backtick) {
	}

	var stopLooking = false
	// Find and separate the lines starting with one of the keywords in the special map
	_, regular := FilterIntoGroups(bytes.Split(data, bnl), func(byteline []byte) bool {
		lineCounter++
		if stopLooking {
			return false
		}
		// Check if the current line has one of the special keywords
		for _, keyword := range keywordsToLookFor {
			strippedLine := bytes.TrimSpace(byteline)
			if len(strippedLine) == 0 {
				// Empty line
				return false
			}

			// If we encounter a backtick (`), stop looking for keywords (due to Markdown formatting of code)
			if bytes.Contains(strippedLine, backtick) {
				// Contains a backtick
				stopLooking = true
				return false
			}

			// Check if we are in a HTML comment block
			singleLineComment = false
			switch {
			case bytes.HasPrefix(strippedLine, commentStart) && bytes.HasSuffix(strippedLine, commentEnd):
				inCommentBlock = false
				strippedLine = bytes.TrimSpace(strippedLine[len(commentStart) : len(strippedLine)-len(commentEnd)])
				singleLineComment = true
			case bytes.HasPrefix(strippedLine, commentStart):
				inCommentBlock = true
			case bytes.HasSuffix(strippedLine, commentEnd):
				inCommentBlock = false
			}
			//fmt.Println("LINE", string(strippedLine), "IN COMMENT BLOCK", inCommentBlock, "SINGLE LINE COMMENT", singleLineComment)

			keywordColon = append([]byte(keyword), ':')
			// Lines starting with "% " can be used for specifying a title, ref pandoc
			if bytes.HasPrefix(strippedLine, []byte("% ")) {
				newTitle := bytes.TrimSpace(strippedLine[2:])
				if len(newTitle) > 0 {
					found["title"] = newTitle
					return true
				}
			}
			// Check for lines that starts with "<!--", ends with "-->" and contains the keyword and a ":"
			if singleLineComment {
				// Check if one of the relevant keywords are present
				if bytes.HasPrefix(strippedLine, keywordColon) {
					// Set (possibly overwrite) the value in the map, if the keyword is found.
					// Trim the surrounding whitespace and skip the letters of the keyword itself.
					found[keyword] = bytes.TrimSpace(strippedLine[len(keyword)+1:])
					return true
				}
				// Check for lines starting with the keyword and a ":"
			} else if bytes.HasPrefix(strippedLine, keywordColon) {
				// Check if the keyword was found either in a comment block, or on the first 10 lines
				if inCommentBlock || lineCounter < 10 {
					// Set (possibly overwrite) the value in the map, if the keyword is found.
					// Trim the surrounding whitespace and skip the letters of the keyword itself.
					found[keyword] = bytes.TrimSpace(strippedLine[len(keywordColon):])
					return true
				}
			}
		}
		// Not special
		return false
	})
	// Use the regular lines as the new data (remove the special lines)
	return bytes.Join(regular, bnl), found
}

// Infostring builds up a string on the form "functionname(arg1, arg2, arg3)"
func Infostring(functionName string, args []string) string {
	s := functionName + "("
	if len(args) > 0 {
		s += "\"" + strings.Join(args, "\", \"") + "\""
	}
	return s + ")"
}

// WriteStatus writes status messages to a string Builder
// The flags argument contains the flag names, and if they are enabled or not
func WriteStatus(sb *strings.Builder, title string, flags map[string]bool) {

	// Check that at least one of the bools are true
	found := false
	for _, value := range flags {
		if value {
			found = true
			break
		}
	}
	if !found {
		return
	}

	// Write the overview to the buffer
	sb.WriteString(title)
	sb.WriteString(":")

	// Spartan way of lining up the columns
	if len(title) < 7 {
		sb.WriteString("\t")
	}
	sb.WriteString("\t\t[")

	var enabledFlags []string
	// Add all enabled flags to the list
	for name, enabled := range flags {
		if enabled {
			enabledFlags = append(enabledFlags, name)
		}
	}
	sb.WriteString(strings.Join(enabledFlags, ", "))
	sb.WriteString("]\n")
}
<commit_msg>Remove unused code<commit_after>package utils

import (
	"bytes"
	"strings"
)

// FilterIntoGroups filters []byte slices into two groups, depending on the given filter function
func FilterIntoGroups(bytelines [][]byte, filterfunc func([]byte) bool) ([][]byte, [][]byte) {
	var special, regular [][]byte
	for _, byteline := range bytelines {
		if filterfunc(byteline) {
			// Special
			special = append(special, byteline)
		} else {
			// Regular
			regular = append(regular, byteline)
		}
	}
	return special, regular
}

/*ExtractKeywords takes a source file as `data` and a list of keywords to
 * look for. Lines without keywords are returned, together with a map
 * from keywords to []bytes from the source `data`.
 *
 * The keywords in the data must be on the form "keyword: value",
 * and can be within single-line HTML comments (<-- ... -->).
 */
func ExtractKeywords(data []byte, keywordsToLookFor []string) ([]byte, map[string][]byte) {
	var (
		keywordColon      []byte
		inCommentBlock    bool
		singleLineComment bool
		lineCounter       uint64
	)
	bnl := []byte("\n")
	commentStart := []byte("<!--")
	commentEnd := []byte("-->")
	backtick := []byte("`")
	found := make(map[string][]byte)

	//if bytes.Contains(data, backtick) {
	//}

	var stopLooking = false
	// Find and separate the lines starting with one of the keywords in the special map
	_, regular := FilterIntoGroups(bytes.Split(data, bnl), func(byteline []byte) bool {
		lineCounter++
		if stopLooking {
			return false
		}
		// Check if the current line has one of the special keywords
		for _, keyword := range keywordsToLookFor {
			strippedLine := bytes.TrimSpace(byteline)
			if len(strippedLine) == 0 {
				// Empty line
				return false
			}

			// If we encounter a backtick (`), stop looking for keywords (due to Markdown formatting of code)
			if bytes.Contains(strippedLine, backtick) {
				// Contains a backtick
				stopLooking = true
				return false
			}

			// Check if we are in a HTML comment block
			singleLineComment = false
			switch {
			case bytes.HasPrefix(strippedLine, commentStart) && bytes.HasSuffix(strippedLine, commentEnd):
				inCommentBlock = false
				strippedLine = bytes.TrimSpace(strippedLine[len(commentStart) : len(strippedLine)-len(commentEnd)])
				singleLineComment = true
			case bytes.HasPrefix(strippedLine, commentStart):
				inCommentBlock = true
			case bytes.HasSuffix(strippedLine, commentEnd):
				inCommentBlock = false
			}
			//fmt.Println("LINE", string(strippedLine), "IN COMMENT BLOCK", inCommentBlock, "SINGLE LINE COMMENT", singleLineComment)

			keywordColon = append([]byte(keyword), ':')
			// Lines starting with "% " can be used for specifying a title, ref pandoc
			if bytes.HasPrefix(strippedLine, []byte("% ")) {
				newTitle := bytes.TrimSpace(strippedLine[2:])
				if len(newTitle) > 0 {
					found["title"] = newTitle
					return true
				}
			}
			// Check for lines that starts with "<!--", ends with "-->" and contains the keyword and a ":"
			if singleLineComment {
				// Check if one of the relevant keywords are present
				if bytes.HasPrefix(strippedLine, keywordColon) {
					// Set (possibly overwrite) the value in the map, if the keyword is found.
					// Trim the surrounding whitespace and skip the letters of the keyword itself.
					found[keyword] = bytes.TrimSpace(strippedLine[len(keyword)+1:])
					return true
				}
				// Check for lines starting with the keyword and a ":"
			} else if bytes.HasPrefix(strippedLine, keywordColon) {
				// Check if the keyword was found either in a comment block, or on the first 10 lines
				if inCommentBlock || lineCounter < 10 {
					// Set (possibly overwrite) the value in the map, if the keyword is found.
					// Trim the surrounding whitespace and skip the letters of the keyword itself.
					found[keyword] = bytes.TrimSpace(strippedLine[len(keywordColon):])
					return true
				}
			}
		}
		// Not special
		return false
	})
	// Use the regular lines as the new data (remove the special lines)
	return bytes.Join(regular, bnl), found
}

// Infostring builds up a string on the form "functionname(arg1, arg2, arg3)"
func Infostring(functionName string, args []string) string {
	s := functionName + "("
	if len(args) > 0 {
		s += "\"" + strings.Join(args, "\", \"") + "\""
	}
	return s + ")"
}

// WriteStatus writes status messages to a string Builder
// The flags argument contains the flag names, and if they are enabled or not
func WriteStatus(sb *strings.Builder, title string, flags map[string]bool) {

	// Check that at least one of the bools are true
	found := false
	for _, value := range flags {
		if value {
			found = true
			break
		}
	}
	if !found {
		return
	}

	// Write the overview to the buffer
	sb.WriteString(title)
	sb.WriteString(":")

	// Spartan way of lining up the columns
	if len(title) < 7 {
		sb.WriteString("\t")
	}
	sb.WriteString("\t\t[")

	var enabledFlags []string
	// Add all enabled flags to the list
	for name, enabled := range flags {
		if enabled {
			enabledFlags = append(enabledFlags, name)
		}
	}
	sb.WriteString(strings.Join(enabledFlags, ", "))
	sb.WriteString("]\n")
}
<|endoftext|>


<commit_before>package extensions

import (
	"github.com/mitchellh/mapstructure"
	"github.com/rackspace/gophercloud"
	common "github.com/rackspace/gophercloud/openstack/common/extensions"
	"github.com/rackspace/gophercloud/pagination"
)

// Extension is a single OpenStack extension.
type Extension struct {
	common.Extension
}

// GetResult wraps a GetResult from common.
type GetResult struct {
	common.GetResult
}

// ExtensionPage is a single page of Extension results.
type ExtensionPage struct {
	common.ExtensionPage
}

// IsEmpty returns true if the current page contains at least one Extension.
func (page ExtensionPage) IsEmpty() (bool, error) {
	is, err := ExtractExtensions(page)
	if err != nil {
		return true, err
	}
	return len(is) == 0, nil
}

// ExtractExtensions accepts a Page struct, specifically an ExtensionPage struct, and extracts the
// elements into a slice of Extension structs.
func ExtractExtensions(page pagination.Page) ([]Extension, error) {
	// Identity v2 adds an intermediate "values" object.

	type extension struct {
		Updated     string        `mapstructure:"updated"`
		Name        string        `mapstructure:"name"`
		Namespace   string        `mapstructure:"namespace"`
		Alias       string        `mapstructure:"alias"`
		Description string        `mapstructure:"description"`
		Links       []interface{} `mapstructure:"links"`
	}

	var resp struct {
		Extensions struct {
			Values []extension `mapstructure:"values"`
		} `mapstructure:"extensions"`
	}

	err := mapstructure.Decode(page.(ExtensionPage).Body, &resp)
	if err != nil {
		return nil, err
	}

	exts := make([]Extension, len(resp.Extensions.Values))
	for i, original := range resp.Extensions.Values {
		exts[i] = Extension{common.Extension{
			Updated:     original.Updated,
			Name:        original.Name,
			Namespace:   original.Namespace,
			Alias:       original.Alias,
			Description: original.Description,
			Links:       original.Links,
		}}
	}

	return exts, err
}

// Get retrieves information for a specific extension using its alias.
func Get(c *gophercloud.ServiceClient, alias string) GetResult {
	return GetResult{common.Get(c, alias)}
}

// List returns a Pager which allows you to iterate over the full collection of extensions.
// It does not accept query parameters.
func List(c *gophercloud.ServiceClient) pagination.Pager {
	return pagination.NewPager(c, common.ListExtensionURL(c), func(r pagination.LastHTTPResponse) pagination.Page {
		return ExtensionPage{common.ExtensionPage{SinglePageBase: pagination.SinglePageBase(r)}}
	})
}
<commit_msg>Override the List call without reimplementing.<commit_after>package extensions

import (
	"github.com/mitchellh/mapstructure"
	"github.com/rackspace/gophercloud"
	common "github.com/rackspace/gophercloud/openstack/common/extensions"
	"github.com/rackspace/gophercloud/pagination"
)

// Extension is a single OpenStack extension.
type Extension struct {
	common.Extension
}

// GetResult wraps a GetResult from common.
type GetResult struct {
	common.GetResult
}

// ExtensionPage is a single page of Extension results.
type ExtensionPage struct {
	common.ExtensionPage
}

// IsEmpty returns true if the current page contains at least one Extension.
func (page ExtensionPage) IsEmpty() (bool, error) {
	is, err := ExtractExtensions(page)
	if err != nil {
		return true, err
	}
	return len(is) == 0, nil
}

// ExtractExtensions accepts a Page struct, specifically an ExtensionPage struct, and extracts the
// elements into a slice of Extension structs.
func ExtractExtensions(page pagination.Page) ([]Extension, error) {
	// Identity v2 adds an intermediate "values" object.

	type extension struct {
		Updated     string        `mapstructure:"updated"`
		Name        string        `mapstructure:"name"`
		Namespace   string        `mapstructure:"namespace"`
		Alias       string        `mapstructure:"alias"`
		Description string        `mapstructure:"description"`
		Links       []interface{} `mapstructure:"links"`
	}

	var resp struct {
		Extensions struct {
			Values []extension `mapstructure:"values"`
		} `mapstructure:"extensions"`
	}

	err := mapstructure.Decode(page.(ExtensionPage).Body, &resp)
	if err != nil {
		return nil, err
	}

	exts := make([]Extension, len(resp.Extensions.Values))
	for i, original := range resp.Extensions.Values {
		exts[i] = Extension{common.Extension{
			Updated:     original.Updated,
			Name:        original.Name,
			Namespace:   original.Namespace,
			Alias:       original.Alias,
			Description: original.Description,
			Links:       original.Links,
		}}
	}

	return exts, err
}

// Get retrieves information for a specific extension using its alias.
func Get(c *gophercloud.ServiceClient, alias string) GetResult {
	return GetResult{common.Get(c, alias)}
}

// List returns a Pager which allows you to iterate over the full collection of extensions.
// It does not accept query parameters.
func List(c *gophercloud.ServiceClient) pagination.Pager {
	pager := common.List(c)
	pager.CreatePage = func(r pagination.LastHTTPResponse) pagination.Page {
		return ExtensionPage{
			ExtensionPage: common.ExtensionPage{SinglePageBase: pagination.SinglePageBase(r)},
		}
	}
	return pager
}
<|endoftext|>


<commit_before>package glplus

import (
	"fmt"
	"image"
	"image/color"
	"unsafe"

	gl "github.com/go-gl/gl/v4.1-core/gl"
)

// RenderTarget ...
type RenderTarget struct {
	fbuffer uint32
	rbuffer uint32
}

// Delete ...
func (r *RenderTarget) Delete() {
	if r.fbuffer != 0 {
		gl.DeleteFramebuffers(1, &r.fbuffer)
	}
	if r.rbuffer != 0 {
		gl.DeleteRenderbuffers(1, &r.rbuffer)
	}
}

func checkFramebufferStatus() string {
	status := gl.CheckFramebufferStatus(gl.FRAMEBUFFER)
	switch status {
	case gl.FRAMEBUFFER_COMPLETE:
		return "OK"
	case gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
		return "Framebuffer incomplete, incomplete attachment!"
	case gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
		return "Framebuffer incomplete, missing attachment!"
	case gl.FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
		return "Framebuffer incomplete, missing draw buffer!"
	case gl.FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
		return "Framebuffer incomplete, missing read buffer!"
	case gl.FRAMEBUFFER_UNSUPPORTED:
		return "Unsupported framebuffer format!"
	}
	panic(fmt.Errorf("Unknown error %d", status))
}

// Bind ...
func (r *RenderTarget) Bind(tex *Texture) {
	// Bind the frame-buffer object and attach to it a render-buffer object set up as a depth-buffer.
	gl.BindFramebuffer(gl.FRAMEBUFFER, r.fbuffer)

	gl.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex.Handle(), 0)

	// Set the render target - primary surface
	gl.DrawBuffer(gl.COLOR_ATTACHMENT0)

	status := checkFramebufferStatus()
	if status != "OK" {
		gl.BindFramebuffer(gl.FRAMEBUFFER, 0)
		panic(fmt.Errorf("Canot continue error %s", status))
	}
}

// Unbind ...
func (r *RenderTarget) Unbind(tex *Texture) {
	gl.BindFramebuffer(gl.FRAMEBUFFER, 0)
	gl.Flush()
}

// ReadBuffer ...
func (r *RenderTarget) ReadBuffer(w, h int) (newImage *image.RGBA) {
	gl.Flush()
	gl.ReadBuffer(gl.COLOR_ATTACHMENT0)

	var pix = make([]float32, w*h*4)
	gl.ReadPixels(0, 0, int32(w), int32(h), gl.RGBA, gl.FLOAT, unsafe.Pointer(&pix[0]))

	newImage = image.NewRGBA(image.Rect(0, 0, w, h))
	for j := 0; j < h; j++ {
		for i := 0; i < w; i++ {
			ind := j*w*4 + i*4
			newImage.SetRGBA(i, j, color.RGBA{uint8(pix[ind+0] * 255), uint8(pix[ind+1] * 255), uint8(pix[ind+2] * 255), uint8(pix[ind+3] * 255)})
		}
	}
	return newImage
}

// NewRenderTarget ...
func NewRenderTarget() (r *RenderTarget) {
	var fbuffer uint32
	//create the color buffer to render to
	gl.GenFramebuffers(1, &fbuffer)
	gl.BindFramebuffer(gl.FRAMEBUFFER, fbuffer)

	var rbuffer uint32
	//now create the color render buffer
	gl.GenRenderbuffers(1, &rbuffer)
	gl.BindRenderbuffer(gl.RENDERBUFFER, rbuffer)

	gl.BindFramebuffer(gl.FRAMEBUFFER, 0)

	r = &RenderTarget{
		fbuffer: fbuffer,
		rbuffer: rbuffer,
	}
	return r
}
<commit_msg>EnsureSize<commit_after>package glplus

import (
	"fmt"
	"image"
	"image/color"
	"unsafe"

	gl "github.com/go-gl/gl/v4.1-core/gl"
)

// RenderTarget ...
type RenderTarget struct {
	fbuffer uint32
	rbuffer uint32
	Tex     *Texture
}

// Delete ...
func (r *RenderTarget) Delete() {
	if r.fbuffer != 0 {
		gl.DeleteFramebuffers(1, &r.fbuffer)
	}
	if r.rbuffer != 0 {
		gl.DeleteRenderbuffers(1, &r.rbuffer)
	}
	if r.Tex != nil {
		r.Tex.DeleteTexture()
	}
}

// EnsureSize ...
func (r *RenderTarget) EnsureSize(size image.Point) {
	if r.Tex == nil || r.Tex.Size.X != size.X || r.Tex.Size.Y != size.Y {
		if r.Tex != nil {
			r.Tex.DeleteTexture()
		}
		r.Tex = GenTexture(image.Point{size.X, size.Y})
		r.Tex.BindTexture(0)
		gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
		gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
		gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
		gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
		gl.TexImage2D(
			gl.TEXTURE_2D,
			0,
			gl.RGBA,
			int32(size.X),
			int32(size.Y),
			0,
			gl.RGBA,
			gl.UNSIGNED_BYTE,
			nil)
		r.Tex.UnbindTexture(0)
	}
}

func checkFramebufferStatus() string {
	status := gl.CheckFramebufferStatus(gl.FRAMEBUFFER)
	switch status {
	case gl.FRAMEBUFFER_COMPLETE:
		return "OK"
	case gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
		return "Framebuffer incomplete, incomplete attachment!"
	case gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
		return "Framebuffer incomplete, missing attachment!"
	case gl.FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
		return "Framebuffer incomplete, missing draw buffer!"
	case gl.FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
		return "Framebuffer incomplete, missing read buffer!"
	case gl.FRAMEBUFFER_UNSUPPORTED:
		return "Unsupported framebuffer format!"
	}
	panic(fmt.Errorf("Unknown error %d", status))
}

// Bind ...
func (r *RenderTarget) Bind(tex *Texture) {
	// Bind the frame-buffer object and attach to it a render-buffer object set up as a depth-buffer.
	gl.BindFramebuffer(gl.FRAMEBUFFER, r.fbuffer)

	gl.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex.Handle(), 0)

	// Set the render target - primary surface
	gl.DrawBuffer(gl.COLOR_ATTACHMENT0)

	status := checkFramebufferStatus()
	if status != "OK" {
		gl.BindFramebuffer(gl.FRAMEBUFFER, 0)
		panic(fmt.Errorf("Canot continue error %s", status))
	}
}

// Unbind ...
func (r *RenderTarget) Unbind(tex *Texture) {
	gl.BindFramebuffer(gl.FRAMEBUFFER, 0)
	gl.Flush()
}

// ReadBuffer ...
func (r *RenderTarget) ReadBuffer(w, h int) (newImage *image.RGBA) {
	gl.Flush()
	gl.ReadBuffer(gl.COLOR_ATTACHMENT0)

	var pix = make([]float32, w*h*4)
	gl.ReadPixels(0, 0, int32(w), int32(h), gl.RGBA, gl.FLOAT, unsafe.Pointer(&pix[0]))

	newImage = image.NewRGBA(image.Rect(0, 0, w, h))
	for j := 0; j < h; j++ {
		for i := 0; i < w; i++ {
			ind := j*w*4 + i*4
			newImage.SetRGBA(i, j, color.RGBA{uint8(pix[ind+0] * 255), uint8(pix[ind+1] * 255), uint8(pix[ind+2] * 255), uint8(pix[ind+3] * 255)})
		}
	}
	return newImage
}

// NewRenderTarget ...
func NewRenderTarget() (r *RenderTarget) {
	var fbuffer uint32
	//create the color buffer to render to
	gl.GenFramebuffers(1, &fbuffer)
	gl.BindFramebuffer(gl.FRAMEBUFFER, fbuffer)

	var rbuffer uint32
	//now create the color render buffer
	gl.GenRenderbuffers(1, &rbuffer)
	gl.BindRenderbuffer(gl.RENDERBUFFER, rbuffer)

	gl.BindFramebuffer(gl.FRAMEBUFFER, 0)

	r = &RenderTarget{
		fbuffer: fbuffer,
		rbuffer: rbuffer,
	}
	return r
}
<|endoftext|>


<commit_before>package todolist

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"sort"
)

type FileStore struct {
	FileLocation string
	Data         []*Todo
	Loaded       bool
}

func NewFileStore() *FileStore {
	return &FileStore{FileLocation: ".todos.json", Loaded: false}
}

func (f *FileStore) Add(todo *Todo) {
	f.Load()
	todo.Id = f.NextId()
	f.Data = append(f.Data, todo)
}

func (f *FileStore) FindById(id int) *Todo {
	f.Load()
	for _, todo := range f.Data {
		if todo.Id == id {
			return todo
		}
	}
	return nil
}

func (f *FileStore) Delete(id int) {
	f.Load()
	i := -1
	for index, todo := range f.Data {
		if todo.Id == id {
			i = index
		}
	}

	f.Data = append(f.Data[:i], f.Data[i+1:]...)
}

func (f *FileStore) Complete(id int) {
	f.Load()
	todo := f.FindById(id)
	todo.Completed = true
	f.Delete(id)
	f.Data = append(f.Data, todo)
}

func (f *FileStore) Uncomplete(id int) {
	f.Load()
	todo := f.FindById(id)
	todo.Completed = false
	f.Delete(id)
	f.Data = append(f.Data, todo)
}

func (f *FileStore) Archive(id int) {
	f.Load()
	todo := f.FindById(id)
	todo.Archived = true
	f.Delete(id)
	f.Data = append(f.Data, todo)
}

func (f *FileStore) Unarchive(id int) {
	f.Load()
	todo := f.FindById(id)
	todo.Archived = false
	f.Delete(id)
	f.Data = append(f.Data, todo)
}

func (f *FileStore) IndexOf(todoToFind *Todo) int {
	for i, todo := range f.Data {
		if todo.Id == todoToFind.Id {
			return i
		}
	}
	return -1
}

func (f *FileStore) Load() {
	if f.Loaded {
		return
	}

	data, err := ioutil.ReadFile(f.FileLocation)
	if err != nil {
		fmt.Println("No todo file found!")
		fmt.Println("Initialize a new todo repo by running 'todo init'")
		os.Exit(0)
	}

	jerr := json.Unmarshal(data, &f.Data)
	if jerr != nil {
		fmt.Println("Error reading json data", jerr)
		os.Exit(1)
	}
	f.Loaded = true
}

func (f *FileStore) Initialize() {
	if err := ioutil.WriteFile(f.FileLocation, []byte("[]"), 0644); err != nil {
		fmt.Println("Error writing json file", err)
	}
}

func (f *FileStore) Save() {
	data, _ := json.Marshal(f.Data)
	if err := ioutil.WriteFile(f.FileLocation, []byte(data), 0644); err != nil {
		fmt.Println("Error writing json file", err)
	}
}

type ByDate []*Todo

func (a ByDate) Len() int      { return len(a) }
func (a ByDate) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByDate) Less(i, j int) bool {
	t1Due := a[i].CalculateDueTime()
	t2Due := a[j].CalculateDueTime()
	return t1Due.Before(t2Due)
}

func (f *FileStore) Todos() []*Todo {
	f.Load()
	sort.Sort(ByDate(f.Data))
	return f.Data
}

func (f *FileStore) NextId() int {
	maxId := 0
	for _, todo := range f.Data {
		if todo.Id > maxId {
			maxId = todo.Id
		}
	}
	return maxId + 1
}
<commit_msg>Ensure we don't destroy an existing .todos.json<commit_after>package todolist

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"sort"
)

type FileStore struct {
	FileLocation string
	Data         []*Todo
	Loaded       bool
}

func NewFileStore() *FileStore {
	return &FileStore{FileLocation: ".todos.json", Loaded: false}
}

func (f *FileStore) Add(todo *Todo) {
	f.Load()
	todo.Id = f.NextId()
	f.Data = append(f.Data, todo)
}

func (f *FileStore) FindById(id int) *Todo {
	f.Load()
	for _, todo := range f.Data {
		if todo.Id == id {
			return todo
		}
	}
	return nil
}

func (f *FileStore) Delete(id int) {
	f.Load()
	i := -1
	for index, todo := range f.Data {
		if todo.Id == id {
			i = index
		}
	}

	f.Data = append(f.Data[:i], f.Data[i+1:]...)
}

func (f *FileStore) Complete(id int) {
	f.Load()
	todo := f.FindById(id)
	todo.Completed = true
	f.Delete(id)
	f.Data = append(f.Data, todo)
}

func (f *FileStore) Uncomplete(id int) {
	f.Load()
	todo := f.FindById(id)
	todo.Completed = false
	f.Delete(id)
	f.Data = append(f.Data, todo)
}

func (f *FileStore) Archive(id int) {
	f.Load()
	todo := f.FindById(id)
	todo.Archived = true
	f.Delete(id)
	f.Data = append(f.Data, todo)
}

func (f *FileStore) Unarchive(id int) {
	f.Load()
	todo := f.FindById(id)
	todo.Archived = false
	f.Delete(id)
	f.Data = append(f.Data, todo)
}

func (f *FileStore) IndexOf(todoToFind *Todo) int {
	for i, todo := range f.Data {
		if todo.Id == todoToFind.Id {
			return i
		}
	}
	return -1
}

func (f *FileStore) Load() {
	if f.Loaded {
		return
	}

	data, err := ioutil.ReadFile(f.FileLocation)
	if err != nil {
		fmt.Println("No todo file found!")
		fmt.Println("Initialize a new todo repo by running 'todo init'")
		os.Exit(0)
	}

	jerr := json.Unmarshal(data, &f.Data)
	if jerr != nil {
		fmt.Println("Error reading json data", jerr)
		os.Exit(1)
	}
	f.Loaded = true
}

func (f *FileStore) Initialize() {
	_, err := ioutil.ReadFile(f.FileLocation)
	if err == nil {
		fmt.Println("It looks like a .todos.json file already exists!  Doing nothing.")
		os.Exit(0)
	}
	if err := ioutil.WriteFile(f.FileLocation, []byte("[]"), 0644); err != nil {
		fmt.Println("Error writing json file", err)
	}
}

func (f *FileStore) Save() {
	data, _ := json.Marshal(f.Data)
	if err := ioutil.WriteFile(f.FileLocation, []byte(data), 0644); err != nil {
		fmt.Println("Error writing json file", err)
	}
}

type ByDate []*Todo

func (a ByDate) Len() int      { return len(a) }
func (a ByDate) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByDate) Less(i, j int) bool {
	t1Due := a[i].CalculateDueTime()
	t2Due := a[j].CalculateDueTime()
	return t1Due.Before(t2Due)
}

func (f *FileStore) Todos() []*Todo {
	f.Load()
	sort.Sort(ByDate(f.Data))
	return f.Data
}

func (f *FileStore) NextId() int {
	maxId := 0
	for _, todo := range f.Data {
		if todo.Id > maxId {
			maxId = todo.Id
		}
	}
	return maxId + 1
}
<|endoftext|>