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

package main

import (
	"flag"
	"fmt"
	"go/ast"
	"go/parser"
	"go/types"
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/kisielk/gotool"
	"golang.org/x/tools/go/loader"
)

func isComparable(tt types.Type) bool {
	t := tt.Underlying()
	switch typ := t.(type) {
	case *types.Basic:
		return typ.Kind() != types.UntypedNil
	case *types.Struct:
		for i := 0; i < typ.NumFields(); i++ {
			f := typ.Field(i)
			ft := f.Type()
			if !isComparable(ft) {
				return false
			}
		}
		return true
	case *types.Array:
		return isComparable(typ.Elem())
	}
	return false
}

type p struct {
	w              io.Writer
	qual           types.Qualifier
	generatedFuncs map[string]bool
	funcsToType    map[string]types.Type
}

func (p *p) And(format string, a ...interface{}) {
	fmt.Fprintf(p.w, "&&\n")
	fmt.Fprintf(p.w, format, a...)
}

func (p *p) P(format string, a ...interface{}) {
	fmt.Fprintf(p.w, format, a...)
}

func load(paths ...string) (*loader.Program, error) {
	conf := loader.Config{
		ParserMode:  parser.ParseComments,
		AllowErrors: true,
	}
	rest, err := conf.FromArgs(paths, true)
	if err != nil {
		return nil, fmt.Errorf("could not parse arguments: %s", err)
	}
	if len(rest) > 0 {
		return nil, fmt.Errorf("unhandled extra arguments: %v", rest)
	}
	return conf.Load()
}

func main() {
	flag.Parse()
	paths := gotool.ImportPaths(flag.Args())
	program, err := load(paths...)
	derivedFilename := "derived.gen.go"
	if err != nil {
		log.Fatal(err) // load error
	}
	for _, pkgInfo := range program.InitialPackages() {
		pkgpath := filepath.Join(filepath.Join(gotool.DefaultContext.BuildContext.GOPATH, "src"), pkgInfo.Pkg.Path())

		qual := types.RelativeTo(pkgInfo.Pkg)
		var typs []types.Type
		for i, f := range pkgInfo.Files {
			_, fname := filepath.Split(program.Fset.File(f.Pos()).Name())
			if fname == derivedFilename {
				continue
			}
			newtyps := findObjectsUsingFunction(pkgInfo, pkgInfo.Files[i], eqFuncPrefix)
			typs = append(typs, newtyps...)
		}
		if len(typs) == 0 {
			continue
		}

		f, err := os.Create(filepath.Join(pkgpath, derivedFilename))
		if err != nil {
			log.Fatal(err)
		}
		defer f.Close()
		generate(f, qual, pkgInfo.Pkg.Name(), typs)
	}
}

func generate(w io.Writer, qual types.Qualifier, pkgName string, typs []types.Type) {
	p := &p{
		w:              w,
		qual:           qual,
		generatedFuncs: make(map[string]bool),
		funcsToType:    make(map[string]types.Type),
	}
	p.P("//DO NOT EDIT generated by goderive\n")
	p.P("\n")
	p.P("package %s\n", pkgName)
	p.P("\n")
	p.P("import (\n")
	p.P("\t\"bytes\"\n")
	p.P(")\n")
	p.P("\n")
	p.P("var _ = bytes.MinRead\n")
	p.P("\n")
	for i := range typs {
		p.newFunc(typs[i])
		p.genFunc(typs[i])
		p.funcGenerated(typs[i])
	}
	for name, generated := range p.generatedFuncs {
		if generated {
			continue
		}
		p.genFunc(p.funcsToType[name])
	}
}

const eqFuncPrefix = "deriveEqual"

func funcName(typ types.Type, qual types.Qualifier) string {
	return eqFuncPrefix + typeName(typ, qual)
}

func (p *p) newFunc(typ types.Type) {
	fName := funcName(typ, p.qual)
	p.funcsToType[fName] = typ
	p.generatedFuncs[fName] = false
}

func typeName(typ types.Type, qual types.Qualifier) string {
	switch t := typ.(type) {
	case *types.Pointer:
		return "PtrTo" + typeName(t.Elem(), qual)
	case *types.Array:
		return "ArrayOf" + typeName(t.Elem(), qual)
	case *types.Slice:
		return "SliceOf" + typeName(t.Elem(), qual)
	case *types.Map:
		return "MapOf" + typeName(t.Key(), qual) + "To" + typeName(t.Elem(), qual)
	}
	return types.TypeString(typ, qual)
}

func (p *p) funcGenerated(typ types.Type) {
	fName := funcName(typ, p.qual)
	p.generatedFuncs[fName] = true
}

func (p *p) genFunc(typ types.Type) {
	p.funcGenerated(typ)
	typeStr := types.TypeString(typ, p.qual)
	p.P("func %s(this, that %s) bool {\n", funcName(typ, p.qual), typeStr)
	switch ttyp := typ.(type) {
	case *types.Pointer:
		ref := ttyp.Elem()
		switch tttyp := ref.Underlying().(type) {
		case *types.Struct:
			p.P("return (%s == nil && %s == nil) ||\n", "this", "that")
			p.P("(%s != nil && %s != nil)", "this", "that")
			numFields := tttyp.NumFields()
			for i := 0; i < numFields; i++ {
				field := tttyp.Field(i)
				fieldType := field.Type()
				fieldName := field.Name()
				this := "this." + fieldName
				that := "that." + fieldName
				fieldStr, err := p.genField(this, that, fieldType)
				if err != nil {
					fmt.Fprintf(os.Stderr, err.Error())
					return
				}
				p.And(fieldStr)
			}
		default:
			fmt.Fprintf(os.Stderr, "unsupported: pointer is not a named struct, but %#v\n", ref)
			return
		}
	case *types.Slice:
		p.P("if this == nil {\n")
		p.P("if that == nil {\n")
		p.P("return true\n")
		p.P("} else {\n")
		p.P("return false\n")
		p.P("}\n")
		p.P("} else if that == nil {\n")
		p.P("return false\n")
		p.P("}\n")
		p.P("if len(this) != len(that) {\n")
		p.P("return false\n")
		p.P("}\n")
		p.P("for i := 0; i < len(this); i++ {\n")
		eqStr, err := p.genField("this[i]", "that[i]", ttyp.Elem())
		if err != nil {
			fmt.Fprintf(os.Stderr, err.Error())
			return
		}
		p.P("if !(%s) {\n", eqStr)
		p.P("return false\n")
		p.P("}\n")
		p.P("}\n")
		p.P("return true\n")
	// TODO case *types.Array:

	case *types.Map:
		p.P("if this == nil {\n")
		p.P("if that == nil {\n")
		p.P("return true\n")
		p.P("} else {\n")
		p.P("return false\n")
		p.P("}\n")
		p.P("} else if that == nil {\n")
		p.P("return false\n")
		p.P("}\n")
		p.P("if len(this) != len(that) {\n")
		p.P("return false\n")
		p.P("}\n")
		p.P("for k, v := range this {\n")
		p.P("thatv, ok := that[k]\n")
		p.P("if !ok {\n")
		p.P("return false\n")
		p.P("}\n")
		eqStr, err := p.genField("v", "thatv", ttyp.Elem())
		if err != nil {
			fmt.Fprintf(os.Stderr, err.Error())
			return
		}
		p.P("if !(%s) {\n", eqStr)
		p.P("return false\n")
		p.P("}\n")
		p.P("}\n")
		p.P("return true\n")
	default:
		fmt.Fprintf(os.Stderr, "unsupported type: %#v", typ)
		return
	}
	p.P("\n}\n")
}

func (p *p) genField(this, that string, fieldType types.Type) (string, error) {
	if isComparable(fieldType) {
		return fmt.Sprintf("%s == %s", this, that), nil
	}
	switch typ := fieldType.(type) {
	case *types.Pointer:
		ref := typ.Elem()
		if _, ok := ref.(*types.Named); ok {
			return fmt.Sprintf("%s.Equal(%s)", this, that), nil
		}
		eqStr, err := p.genField("*"+this, "*"+that, ref)
		if err != nil {
			return "", err
		}
		return fmt.Sprintf("((%[1]s == nil && %[2]s == nil) || (%[1]s != nil && %[2]s != nil && %[3]s))", this, that, eqStr), nil
	// TODO case *types.Array:
	// 	p.newFunc(typ)
	// 	return fmt.Sprintf("%s(%s, %s)", funcName(typ, p.qual), this, that), nil
	case *types.Slice:
		if b, ok := typ.Elem().(*types.Basic); ok && b.Kind() == types.Byte {
			return fmt.Sprintf("bytes.Equal(%s, %s)", this, that), nil
		}
		p.newFunc(typ)
		return fmt.Sprintf("%s(%s, %s)", funcName(typ, p.qual), this, that), nil
	case *types.Map:
		p.newFunc(typ)
		return fmt.Sprintf("%s(%s, %s)", funcName(typ, p.qual), this, that), nil
	case *types.Named:
		return fmt.Sprintf("%s.Equal(&%s)", this, that), nil
	default: // *Chan, *Tuple, *Signature, *Interface, *types.Basic.Kind() == types.UntypedNil, *Struct
		return "", fmt.Errorf("unsupported type %#v", fieldType)
	}
}

type findFunction struct {
	pkgInfo    *loader.PackageInfo
	funcPrefix string
	typs       []types.Type
}

func (this *findFunction) Visit(node ast.Node) (w ast.Visitor) {
	if call, ok := node.(*ast.CallExpr); ok {
		if fn, ok := call.Fun.(*ast.Ident); ok {
			if strings.HasPrefix(fn.Name, this.funcPrefix) {
				if len(call.Args) != 2 {
					fmt.Fprintf(os.Stderr, "%s does not have two arguments\n", fn.Name)
					return this
				}
				t0 := this.pkgInfo.TypeOf(call.Args[0])
				t1 := this.pkgInfo.TypeOf(call.Args[1])
				if types.Identical(t0, t1) {
					name := strings.TrimPrefix(fn.Name, this.funcPrefix)
					qual := types.RelativeTo(this.pkgInfo.Pkg)
					typeStr := typeName(t0, qual)
					if typeStr != name {
						fmt.Fprintf(os.Stderr, "%s's suffix %s does not match the type %s\n",
							fn.Name, name, typeStr)
						return this
					}
					this.typs = append(this.typs, t0)
					return this
				} else {
					fmt.Fprintf(os.Stderr, "%s has two arguments, but they are of different types %s != %s\n",
						fn.Name, t0, t1)
				}
			}
		}
	}
	return this
}

func findObjectsUsingFunction(pkgInfo *loader.PackageInfo, f *ast.File, funcName string) []types.Type {
	var typs []types.Type
	for _, d := range f.Decls {
		finder := &findFunction{pkgInfo, funcName, nil}
		ast.Walk(finder, d)
		typs = append(typs, finder.typs...)
	}
	return typs
}
<commit_msg>removed And method<commit_after>//  Copyright 2017 Walter Schulze
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.

package main

import (
	"flag"
	"fmt"
	"go/ast"
	"go/parser"
	"go/types"
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/kisielk/gotool"
	"golang.org/x/tools/go/loader"
)

func isComparable(tt types.Type) bool {
	t := tt.Underlying()
	switch typ := t.(type) {
	case *types.Basic:
		return typ.Kind() != types.UntypedNil
	case *types.Struct:
		for i := 0; i < typ.NumFields(); i++ {
			f := typ.Field(i)
			ft := f.Type()
			if !isComparable(ft) {
				return false
			}
		}
		return true
	case *types.Array:
		return isComparable(typ.Elem())
	}
	return false
}

type p struct {
	w              io.Writer
	qual           types.Qualifier
	generatedFuncs map[string]bool
	funcsToType    map[string]types.Type
}

func (p *p) P(format string, a ...interface{}) {
	fmt.Fprintf(p.w, format, a...)
}

func load(paths ...string) (*loader.Program, error) {
	conf := loader.Config{
		ParserMode:  parser.ParseComments,
		AllowErrors: true,
	}
	rest, err := conf.FromArgs(paths, true)
	if err != nil {
		return nil, fmt.Errorf("could not parse arguments: %s", err)
	}
	if len(rest) > 0 {
		return nil, fmt.Errorf("unhandled extra arguments: %v", rest)
	}
	return conf.Load()
}

func main() {
	flag.Parse()
	paths := gotool.ImportPaths(flag.Args())
	program, err := load(paths...)
	derivedFilename := "derived.gen.go"
	if err != nil {
		log.Fatal(err) // load error
	}
	for _, pkgInfo := range program.InitialPackages() {
		pkgpath := filepath.Join(filepath.Join(gotool.DefaultContext.BuildContext.GOPATH, "src"), pkgInfo.Pkg.Path())

		qual := types.RelativeTo(pkgInfo.Pkg)
		var typs []types.Type
		for i, f := range pkgInfo.Files {
			_, fname := filepath.Split(program.Fset.File(f.Pos()).Name())
			if fname == derivedFilename {
				continue
			}
			newtyps := findObjectsUsingFunction(pkgInfo, pkgInfo.Files[i], eqFuncPrefix)
			typs = append(typs, newtyps...)
		}
		if len(typs) == 0 {
			continue
		}

		f, err := os.Create(filepath.Join(pkgpath, derivedFilename))
		if err != nil {
			log.Fatal(err)
		}
		defer f.Close()
		generate(f, qual, pkgInfo.Pkg.Name(), typs)
	}
}

func generate(w io.Writer, qual types.Qualifier, pkgName string, typs []types.Type) {
	p := &p{
		w:              w,
		qual:           qual,
		generatedFuncs: make(map[string]bool),
		funcsToType:    make(map[string]types.Type),
	}
	p.P("//DO NOT EDIT generated by goderive\n")
	p.P("\n")
	p.P("package %s\n", pkgName)
	p.P("\n")
	p.P("import (\n")
	p.P("\t\"bytes\"\n")
	p.P(")\n")
	p.P("\n")
	p.P("var _ = bytes.MinRead\n")
	p.P("\n")
	for i := range typs {
		p.newFunc(typs[i])
		p.genFunc(typs[i])
		p.funcGenerated(typs[i])
	}
	for name, generated := range p.generatedFuncs {
		if generated {
			continue
		}
		p.genFunc(p.funcsToType[name])
	}
}

const eqFuncPrefix = "deriveEqual"

func funcName(typ types.Type, qual types.Qualifier) string {
	return eqFuncPrefix + typeName(typ, qual)
}

func (p *p) newFunc(typ types.Type) {
	fName := funcName(typ, p.qual)
	p.funcsToType[fName] = typ
	p.generatedFuncs[fName] = false
}

func typeName(typ types.Type, qual types.Qualifier) string {
	switch t := typ.(type) {
	case *types.Pointer:
		return "PtrTo" + typeName(t.Elem(), qual)
	case *types.Array:
		return "ArrayOf" + typeName(t.Elem(), qual)
	case *types.Slice:
		return "SliceOf" + typeName(t.Elem(), qual)
	case *types.Map:
		return "MapOf" + typeName(t.Key(), qual) + "To" + typeName(t.Elem(), qual)
	}
	return types.TypeString(typ, qual)
}

func (p *p) funcGenerated(typ types.Type) {
	fName := funcName(typ, p.qual)
	p.generatedFuncs[fName] = true
}

func (p *p) genFunc(typ types.Type) {
	p.funcGenerated(typ)
	typeStr := types.TypeString(typ, p.qual)
	p.P("func %s(this, that %s) bool {\n", funcName(typ, p.qual), typeStr)
	switch ttyp := typ.(type) {
	case *types.Pointer:
		ref := ttyp.Elem()
		switch tttyp := ref.Underlying().(type) {
		case *types.Struct:
			p.P("return (%s == nil && %s == nil) ||\n", "this", "that")
			p.P("(%s != nil && %s != nil)", "this", "that")
			numFields := tttyp.NumFields()
			for i := 0; i < numFields; i++ {
				field := tttyp.Field(i)
				fieldType := field.Type()
				fieldName := field.Name()
				this := "this." + fieldName
				that := "that." + fieldName
				fieldStr, err := p.genField(this, that, fieldType)
				if err != nil {
					fmt.Fprintf(os.Stderr, err.Error())
					return
				}
				p.P("&&\n")
				p.P(fieldStr)
			}
		default:
			fmt.Fprintf(os.Stderr, "unsupported: pointer is not a named struct, but %#v\n", ref)
			return
		}
	case *types.Slice:
		p.P("if this == nil {\n")
		p.P("if that == nil {\n")
		p.P("return true\n")
		p.P("} else {\n")
		p.P("return false\n")
		p.P("}\n")
		p.P("} else if that == nil {\n")
		p.P("return false\n")
		p.P("}\n")
		p.P("if len(this) != len(that) {\n")
		p.P("return false\n")
		p.P("}\n")
		p.P("for i := 0; i < len(this); i++ {\n")
		eqStr, err := p.genField("this[i]", "that[i]", ttyp.Elem())
		if err != nil {
			fmt.Fprintf(os.Stderr, err.Error())
			return
		}
		p.P("if !(%s) {\n", eqStr)
		p.P("return false\n")
		p.P("}\n")
		p.P("}\n")
		p.P("return true\n")
	// TODO case *types.Array:

	case *types.Map:
		p.P("if this == nil {\n")
		p.P("if that == nil {\n")
		p.P("return true\n")
		p.P("} else {\n")
		p.P("return false\n")
		p.P("}\n")
		p.P("} else if that == nil {\n")
		p.P("return false\n")
		p.P("}\n")
		p.P("if len(this) != len(that) {\n")
		p.P("return false\n")
		p.P("}\n")
		p.P("for k, v := range this {\n")
		p.P("thatv, ok := that[k]\n")
		p.P("if !ok {\n")
		p.P("return false\n")
		p.P("}\n")
		eqStr, err := p.genField("v", "thatv", ttyp.Elem())
		if err != nil {
			fmt.Fprintf(os.Stderr, err.Error())
			return
		}
		p.P("if !(%s) {\n", eqStr)
		p.P("return false\n")
		p.P("}\n")
		p.P("}\n")
		p.P("return true\n")
	default:
		fmt.Fprintf(os.Stderr, "unsupported type: %#v", typ)
		return
	}
	p.P("\n}\n")
}

func (p *p) genField(this, that string, fieldType types.Type) (string, error) {
	if isComparable(fieldType) {
		return fmt.Sprintf("%s == %s", this, that), nil
	}
	switch typ := fieldType.(type) {
	case *types.Pointer:
		ref := typ.Elem()
		if _, ok := ref.(*types.Named); ok {
			return fmt.Sprintf("%s.Equal(%s)", this, that), nil
		}
		eqStr, err := p.genField("*"+this, "*"+that, ref)
		if err != nil {
			return "", err
		}
		return fmt.Sprintf("((%[1]s == nil && %[2]s == nil) || (%[1]s != nil && %[2]s != nil && %[3]s))", this, that, eqStr), nil
	// TODO case *types.Array:
	// 	p.newFunc(typ)
	// 	return fmt.Sprintf("%s(%s, %s)", funcName(typ, p.qual), this, that), nil
	case *types.Slice:
		if b, ok := typ.Elem().(*types.Basic); ok && b.Kind() == types.Byte {
			return fmt.Sprintf("bytes.Equal(%s, %s)", this, that), nil
		}
		p.newFunc(typ)
		return fmt.Sprintf("%s(%s, %s)", funcName(typ, p.qual), this, that), nil
	case *types.Map:
		p.newFunc(typ)
		return fmt.Sprintf("%s(%s, %s)", funcName(typ, p.qual), this, that), nil
	case *types.Named:
		return fmt.Sprintf("%s.Equal(&%s)", this, that), nil
	default: // *Chan, *Tuple, *Signature, *Interface, *types.Basic.Kind() == types.UntypedNil, *Struct
		return "", fmt.Errorf("unsupported type %#v", fieldType)
	}
}

type findFunction struct {
	pkgInfo    *loader.PackageInfo
	funcPrefix string
	typs       []types.Type
}

func (this *findFunction) Visit(node ast.Node) (w ast.Visitor) {
	if call, ok := node.(*ast.CallExpr); ok {
		if fn, ok := call.Fun.(*ast.Ident); ok {
			if strings.HasPrefix(fn.Name, this.funcPrefix) {
				if len(call.Args) != 2 {
					fmt.Fprintf(os.Stderr, "%s does not have two arguments\n", fn.Name)
					return this
				}
				t0 := this.pkgInfo.TypeOf(call.Args[0])
				t1 := this.pkgInfo.TypeOf(call.Args[1])
				if types.Identical(t0, t1) {
					name := strings.TrimPrefix(fn.Name, this.funcPrefix)
					qual := types.RelativeTo(this.pkgInfo.Pkg)
					typeStr := typeName(t0, qual)
					if typeStr != name {
						fmt.Fprintf(os.Stderr, "%s's suffix %s does not match the type %s\n",
							fn.Name, name, typeStr)
						return this
					}
					this.typs = append(this.typs, t0)
					return this
				} else {
					fmt.Fprintf(os.Stderr, "%s has two arguments, but they are of different types %s != %s\n",
						fn.Name, t0, t1)
				}
			}
		}
	}
	return this
}

func findObjectsUsingFunction(pkgInfo *loader.PackageInfo, f *ast.File, funcName string) []types.Type {
	var typs []types.Type
	for _, d := range f.Decls {
		finder := &findFunction{pkgInfo, funcName, nil}
		ast.Walk(finder, d)
		typs = append(typs, finder.typs...)
	}
	return typs
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io"
	"os"

	"github.com/kusabashira/alita"
)

func shortUsage() {
	os.Stderr.WriteString(`
Usage: alita [OPTION]... [FILE]...
Try 'alita --help' for more information.
`[1:])
}

func longUsage() {
	os.Stderr.WriteString(`
Usage: alita [OPTION]... [FILE]...
Align FILE(s), or standard input.

Delimiter control:
  -c, --count=COUNT        delimit line COUNT times
  -r, --regexp             DELIM is a regular expression
  -d, --delimiter=DELIM    delimit line by DELIM

Output control:
  -m, --margin=FORMAT      join cells by FORMAT
  -j, --justfy=SEQUENCE    justfy cells by SEQUENCE

Miscellaneous:
  -h, --help               show this help message
      --version            print the version
`[1:])
}

func version() {
	os.Stderr.WriteString(`
v0.6.0
`[1:])
}

func do(a *alita.Aligner, r io.Reader) error {
	if err := a.ReadAll(r); err != nil {
		return err
	}
	return a.Flush()
}

func _main() error {
	a := alita.NewAligner(os.Stdout)
	flag.IntVar(&a.Delimiter.Count, "c", -1, "")
	flag.IntVar(&a.Delimiter.Count, "count", -1, "")
	flag.BoolVar(&a.Delimiter.UseRegexp, "r", false, "")
	flag.BoolVar(&a.Delimiter.UseRegexp, "regexp", false, "")
	flag.Var(a.Delimiter, "d", "")
	flag.Var(a.Delimiter, "delimiter", "")
	flag.Var(a.Margin, "m", "")
	flag.Var(a.Margin, "margin", "")
	flag.Var(a.Padding, "j", "")
	flag.Var(a.Padding, "justfy", "")

	var isHelp, isVersion bool
	flag.BoolVar(&isHelp, "h", false, "")
	flag.BoolVar(&isHelp, "help", false, "")
	flag.BoolVar(&isVersion, "version", false, "")
	flag.Usage = shortUsage
	flag.Parse()
	switch {
	case isHelp:
		longUsage()
		return nil
	case isVersion:
		version()
		return nil
	}

	if flag.NArg() < 1 {
		return do(a, os.Stdin)
	}

	var input []io.Reader
	for _, fname := range flag.Args() {
		f, err := os.Open(fname)
		if err != nil {
			return err
		}
		defer f.Close()
		input = append(input, f)
	}
	return do(a, io.MultiReader(input...))
}

func main() {
	if err := _main(); err != nil {
		fmt.Fprintln(os.Stderr, "alita:", err)
		os.Exit(1)
	}
}
<commit_msg>Enable compile<commit_after>package main

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

func shortUsage() {
	os.Stderr.WriteString(`
Usage: alita [OPTION]... [FILE]...
Try 'alita --help' for more information.
`[1:])
}

func longUsage() {
	os.Stderr.WriteString(`
Usage: alita [OPTION]... [FILE]...
Align FILE(s), or standard input.

Delimiter control:
  -c, --count=COUNT        delimit line COUNT times
  -r, --regexp             DELIM is a regular expression
  -d, --delimiter=DELIM    delimit line by DELIM

Output control:
  -m, --margin=FORMAT      join cells by FORMAT
  -j, --justfy=SEQUENCE    justfy cells by SEQUENCE

Miscellaneous:
  -h, --help               show this help message
      --version            print the version
`[1:])
}

func version() {
	os.Stderr.WriteString(`
v0.6.0
`[1:])
}

func do(a *Aligner, r io.Reader) error {
	if err := a.ReadAll(r); err != nil {
		return err
	}
	return a.Flush()
}

func _main() error {
	a := NewAligner(os.Stdout)
	flag.IntVar(&a.Delimiter.Count, "c", -1, "")
	flag.IntVar(&a.Delimiter.Count, "count", -1, "")
	flag.BoolVar(&a.Delimiter.UseRegexp, "r", false, "")
	flag.BoolVar(&a.Delimiter.UseRegexp, "regexp", false, "")
	flag.Var(a.Delimiter, "d", "")
	flag.Var(a.Delimiter, "delimiter", "")
	flag.Var(a.Margin, "m", "")
	flag.Var(a.Margin, "margin", "")
	flag.Var(a.Padding, "j", "")
	flag.Var(a.Padding, "justfy", "")

	var isHelp, isVersion bool
	flag.BoolVar(&isHelp, "h", false, "")
	flag.BoolVar(&isHelp, "help", false, "")
	flag.BoolVar(&isVersion, "version", false, "")
	flag.Usage = shortUsage
	flag.Parse()
	switch {
	case isHelp:
		longUsage()
		return nil
	case isVersion:
		version()
		return nil
	}

	if flag.NArg() < 1 {
		return do(a, os.Stdin)
	}

	var input []io.Reader
	for _, fname := range flag.Args() {
		f, err := os.Open(fname)
		if err != nil {
			return err
		}
		defer f.Close()
		input = append(input, f)
	}
	return do(a, io.MultiReader(input...))
}

func main() {
	if err := _main(); err != nil {
		fmt.Fprintln(os.Stderr, "alita:", err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"net/http"
	"os"
)

var config configuration

func main() {
	file, err := os.Open("config.json")
	if err != nil {
		panic(err)
	}

	config, err = configure(file)
	if err != nil {
		panic(err)
	}

	auth, err := NewAuthenticator(config.auth)

	if err != nil {
		panic(err)
	}

	server := server{config: config, authenticator: auth}
	http.HandleFunc("/", server.rootHandler)
	http.HandleFunc("/key", server.keyHandler)

	http.ListenAndServe(":3456", nil)
}
<commit_msg>close the file, duh.<commit_after>package main

import (
	"net/http"
	"os"
)

var config configuration

func main() {
	file, err := os.Open("config.json")
	if err != nil {
		panic(err)
	}
	defer file.Close()

	config, err = configure(file)
	if err != nil {
		panic(err)
	}

	auth, err := NewAuthenticator(config.auth)

	if err != nil {
		panic(err)
	}

	server := server{config: config, authenticator: auth}
	http.HandleFunc("/", server.rootHandler)
	http.HandleFunc("/key", server.keyHandler)

	http.ListenAndServe(":3456", nil)
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/13pinj/todoapp/Godeps/_workspace/src/github.com/gin-gonic/gin"
	"github.com/13pinj/todoapp/controllers/page"
	"github.com/13pinj/todoapp/controllers/todos"
	"github.com/13pinj/todoapp/controllers/users"
	"github.com/13pinj/todoapp/core/log"
)

func main() {
	r := gin.New()
	r.Use(gin.LoggerWithWriter(log.Writer()))
	r.Use(gin.RecoveryWithWriter(log.Writer()))

	r.LoadHTMLGlob("templates/*")
	r.Static("/s", "public")
	r.GET("/", page.Home)

	r.POST("/login", users.Login)
	r.GET("/register", users.RegistrationForm)
	r.POST("/register", users.Register)
	r.POST("/logout", users.Logout)

	r.POST("/list-create", todos.CreateList)
	r.GET("/list/:id", todos.ShowList)
	r.POST("/list/:id/update", todos.UpdateList)
	r.POST("/list/:id/destroy", todos.DestroyList)
	r.POST("/list/:id/add", todos.CreateTask)
	r.POST("/task/:id/update", todos.UpdateTask)
	r.POST("/task/:id/destroy", todos.DestroyTask)

	r.Run(":8080")
}
<commit_msg>Bind to heroku port<commit_after>package main

import (
	"os"

	"github.com/13pinj/todoapp/Godeps/_workspace/src/github.com/gin-gonic/gin"
	"github.com/13pinj/todoapp/controllers/page"
	"github.com/13pinj/todoapp/controllers/todos"
	"github.com/13pinj/todoapp/controllers/users"
	"github.com/13pinj/todoapp/core/log"
)

func main() {
	r := gin.New()
	r.Use(gin.LoggerWithWriter(log.Writer()))
	r.Use(gin.RecoveryWithWriter(log.Writer()))

	r.LoadHTMLGlob("templates/*")
	r.Static("/s", "public")
	r.GET("/", page.Home)

	r.POST("/login", users.Login)
	r.GET("/register", users.RegistrationForm)
	r.POST("/register", users.Register)
	r.POST("/logout", users.Logout)

	r.POST("/list-create", todos.CreateList)
	r.GET("/list/:id", todos.ShowList)
	r.POST("/list/:id/update", todos.UpdateList)
	r.POST("/list/:id/destroy", todos.DestroyList)
	r.POST("/list/:id/add", todos.CreateTask)
	r.POST("/task/:id/update", todos.UpdateTask)
	r.POST("/task/:id/destroy", todos.DestroyTask)

	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}
	r.Run(":" + port)
}
<|endoftext|>


<commit_before>package pongo2

import (
	"github.com/astaxie/beego/context"
	p2 "github.com/flosch/pongo2"
	"sync"
)

type Context map[string]interface{}

var templates = map[string]*p2.Template{}
var mutex = &sync.RWMutex{}

// Render takes a Beego context, template name and a Context (map[string]interface{}).
// The template is parsed and cached, and gets executed into beegoCtx's ResponseWriter.
//
// Templates are looked up in `templates/` instead of Beego's default `views/` so that
// Beego doesn't attempt to load and parse our templates with `html/template`.
func Render(beegoCtx *context.Context, tmpl string, ctx Context) {
	mutex.RLock()
	template, ok := templates[tmpl]
	mutex.RUnlock()
	if !ok {
		var err error
		template, err = p2.FromFile("templates/" + tmpl)
		if err != nil {
			panic(err)
		}
		mutex.Lock()
		templates[tmpl] = template
		mutex.Unlock()
	}

	err := template.ExecuteRW(beegoCtx.ResponseWriter, p2.Context(ctx))
	if err != nil {
		panic(err)
	}
}
<commit_msg>Reload templates on every page load when in Beego is in dev mode.<commit_after>package pongo2

import (
	"github.com/astaxie/beego"
	"github.com/astaxie/beego/context"
	p2 "github.com/flosch/pongo2"
	"sync"
)

type Context map[string]interface{}

var templates = map[string]*p2.Template{}
var mutex = &sync.RWMutex{}

var devMode = beego.AppConfig.String("runmode") == "dev"

// Render takes a Beego context, template name and a Context (map[string]interface{}).
// The template is parsed and cached, and gets executed into beegoCtx's ResponseWriter.
//
// Templates are looked up in `templates/` instead of Beego's default `views/` so that
// Beego doesn't attempt to load and parse our templates with `html/template`.
func Render(beegoCtx *context.Context, tmpl string, ctx Context) {
	mutex.RLock()
	template, ok := templates[tmpl]
	mutex.RUnlock()

	if !ok || devMode {
		var err error
		template, err = p2.FromFile("templates/" + tmpl)
		if err != nil {
			panic(err)
		}
		mutex.Lock()
		templates[tmpl] = template
		mutex.Unlock()
	}

	err := template.ExecuteRW(beegoCtx.ResponseWriter, p2.Context(ctx))
	if err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"path"
	"strings"
	"text/template"
	"time"

	"github.com/goreleaser/goreleaser/config"
	"github.com/goreleaser/goreleaser/context"
	"github.com/goreleaser/goreleaser/pipeline/defaults"

	"github.com/apex/log"
	"github.com/apex/log/handlers/cli"
	"gopkg.in/alecthomas/kingpin.v2"
)

var (
	version = "dev"
	commit  = "none"
	datestr = "unknown"
)

func init() {
	log.SetHandler(cli.Default)
}

// given a template, and a config, generate shell script
func makeShell(tplsrc string, cfg *config.Project) ([]byte, error) {

	// if we want to add a timestamp in the templates this
	//  function will generate it
	funcMap := template.FuncMap{
		"timestamp": func() string {
			return time.Now().UTC().Format(time.RFC3339)
		},
	}

	out := bytes.Buffer{}
	t, err := template.New("shell").Funcs(funcMap).Parse(tplsrc)
	if err != nil {
		return nil, err
	}
	err = t.Execute(&out, cfg)
	return out.Bytes(), err
}

// converts the given name template to it's equivalent in shell
// except for the default goreleaser templates, templates with
// conditionals will return an error
//
// {{ .Binary }} --->  [prefix]${BINARY}, etc.
//
func makeName(prefix, target string) (string, error) {
	// armv6 is the default in the shell script
	// so do not need special template condition for ARM
	armversion := "{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
	target = strings.Replace(target, armversion, "{{ .Arch }}", -1)

	// otherwise if it contains a conditional, we can't (easily)
	// translate that to bash.  Ask for bug report.
	if strings.Contains(target, "{{ if") || strings.Contains(target, "{{if") || strings.Contains(target, "{{ .Arm") || strings.Contains(target, "{{.Arm") {
		return "", fmt.Errorf("name_template %q contains unknown conditional or ARM format.  Please file bug at https://github.com/goreleaser/godownloader", target)
	}

	varmap := map[string]string{
		"Os":          "${OS}",
		"Arch":        "${ARCH}",
		"Version":     "${VERSION}",
		"Tag":         "${TAG}",
		"Binary":      "${BINARY}",
		"ProjectName": "${PROJECT_NAME}",
	}

	out := bytes.Buffer{}
	out.WriteString(prefix)
	t, err := template.New("name").Parse(target)
	if err != nil {
		return "", err
	}
	err = t.Execute(&out, varmap)
	return out.String(), err
}

// returns the owner/name repo from input
//
// see https://github.com/goreleaser/godownloader/issues/55
func normalizeRepo(repo string) string {
	// handle full or partial URLs
	repo = strings.TrimPrefix(repo, "https://github.com/")
	repo = strings.TrimPrefix(repo, "http://github.com/")
	repo = strings.TrimPrefix(repo, "github.com/")

	// hande /name/repo or name/repo/ cases
	repo = strings.Trim(repo, "/")

	return repo
}

func loadURLs(path string) (*config.Project, error) {
	for _, file := range []string{"goreleaser.yml", ".goreleaser.yml", "goreleaser.yaml", ".goreleaser.yaml"} {
		url := fmt.Sprintf("%s/%s", path, file)
		log.Infof("reading %s", url)
		project, err := loadURL(url)
		if err != nil {
			return nil, err
		}
		if project != nil {
			return project, nil
		}
	}
	return nil, fmt.Errorf("could not fetch a goreleaser configuration file")
}

func loadURL(file string) (*config.Project, error) {
	resp, err := http.Get(file)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode != 200 {
		log.Errorf("reading %s returned %d %s\n", file, resp.StatusCode, http.StatusText(resp.StatusCode))
		return nil, nil
	}
	p, err := config.LoadReader(resp.Body)

	// to make errcheck happy
	errc := resp.Body.Close()
	if errc != nil {
		return nil, errc
	}
	return &p, err
}

func loadFile(file string) (*config.Project, error) {
	p, err := config.Load(file)
	return &p, err
}

// Load project configuration from a given repo name or filepath/url.
func Load(repo string, file string) (project *config.Project, err error) {
	if repo == "" && file == "" {
		return nil, fmt.Errorf("repo or file not specified")
	}
	if file == "" {
		repo = normalizeRepo(repo)
		log.Infof("reading repo %q on github", repo)
		project, err = loadURLs(
			fmt.Sprintf("https://raw.githubusercontent.com/%s/master", repo),
		)
	} else {
		log.Infof("reading file %q", file)
		project, err = loadFile(file)
	}
	if err != nil {
		return nil, err
	}

	// if not specified add in GitHub owner/repo info
	if project.Release.GitHub.Owner == "" {
		if repo == "" {
			return nil, fmt.Errorf("owner/name repo not specified")
		}
		project.Release.GitHub.Owner = path.Dir(repo)
		project.Release.GitHub.Name = path.Base(repo)
	}

	ctx := context.New(*project)
	err = defaults.Pipe{}.Run(ctx)
	project = &ctx.Config

	// set default binary name
	if len(project.Builds) == 0 {
		project.Builds = []config.Build{
			{Binary: path.Base(repo)},
		}
	}
	if project.Builds[0].Binary == "" {
		project.Builds[0].Binary = path.Base(repo)
	}

	return project, err
}

func main() {
	var (
		repo        = kingpin.Flag("repo", "owner/name or URL of GitHub repository").Required().String()
		source      = kingpin.Flag("source", "source type [godownloader|raw|equinoxio]").Default("godownloader").String()
		output      = kingpin.Flag("output", "output file, default stdout").String()
		force       = kingpin.Flag("force", "force writing of output").Short('f').Bool()
		exe         = kingpin.Flag("exe", "name of binary, used only in raw").String()
		nametpl     = kingpin.Flag("nametpl", "name template, used only in raw").String()
		showVersion = kingpin.Flag("version", "show version and exit").Short('v').Bool()
		file        = kingpin.Arg("file", "??").String()
	)

	var (
		out []byte
		err error
	)

	kingpin.Parse()

	if *showVersion {
		fmt.Printf("%v, commit %v, built at %v", version, commit, datestr)
		os.Exit(0)
	}

	switch *source {
	case "godownloader":
		// https://github.com/goreleaser/godownloader
		out, err = processGodownloader(*repo, *file)
	case "equinoxio":
		// https://equinox.io
		out, err = processEquinoxio(*repo)
	case "raw":
		// raw mode is when people upload direct binaries
		// to GitHub releases that are not  not tar'ed or zip'ed.
		// For example:
		//   https://github.com/mvdan/sh/releases
		out, err = processRaw(*repo, *exe, *nametpl)
	default:
		log.Errorf("unknown source %q", *source)
		os.Exit(1)
	}

	if err != nil {
		log.WithError(err).Error("failed")
		os.Exit(1)
	}

	// stdout case
	if *output == "" {
		if _, err = os.Stdout.Write(out); err != nil {
			log.WithError(err).Error("unable to write")
			os.Exit(1)
		}
		return
	}

	// overwrite any existing file
	if *force {
		if err = ioutil.WriteFile(*output, out, 0666); err != nil {
			log.WithError(err).Errorf("unable to write to %s: %s", *output)
			os.Exit(1)
		}
		return
	}

	// Conditional Write -- only write file if different than current
	//
	// read in current file
	// if err
	//    ignore
	// else if not a shell file
	//    error
	// compare current file with new output
	//   if same, then exit
	//   if different, then overwrite
	checkOrig := true
	orig, err := ioutil.ReadFile(*output)
	if err != nil {
		checkOrig = false
	}
	// todo -- is shell file?
	if checkOrig && shellEqual(orig, out) {
		return
	}
	if err := ioutil.WriteFile(*output, out, 0666); err != nil {
		log.WithError(err).Errorf("unable to write to %s", *output)
		os.Exit(1)
	}
}
<commit_msg>issue #56 show version info like goreleaser<commit_after>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"path"
	"strings"
	"text/template"
	"time"

	"github.com/goreleaser/goreleaser/config"
	"github.com/goreleaser/goreleaser/context"
	"github.com/goreleaser/goreleaser/pipeline/defaults"

	"github.com/apex/log"
	"github.com/apex/log/handlers/cli"
	"gopkg.in/alecthomas/kingpin.v2"
)

var (
	version = "dev"
	commit  = "none"
	datestr = "unknown"
)

func init() {
	log.SetHandler(cli.Default)
}

// given a template, and a config, generate shell script
func makeShell(tplsrc string, cfg *config.Project) ([]byte, error) {

	// if we want to add a timestamp in the templates this
	//  function will generate it
	funcMap := template.FuncMap{
		"timestamp": func() string {
			return time.Now().UTC().Format(time.RFC3339)
		},
	}

	out := bytes.Buffer{}
	t, err := template.New("shell").Funcs(funcMap).Parse(tplsrc)
	if err != nil {
		return nil, err
	}
	err = t.Execute(&out, cfg)
	return out.Bytes(), err
}

// converts the given name template to it's equivalent in shell
// except for the default goreleaser templates, templates with
// conditionals will return an error
//
// {{ .Binary }} --->  [prefix]${BINARY}, etc.
//
func makeName(prefix, target string) (string, error) {
	// armv6 is the default in the shell script
	// so do not need special template condition for ARM
	armversion := "{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
	target = strings.Replace(target, armversion, "{{ .Arch }}", -1)

	// otherwise if it contains a conditional, we can't (easily)
	// translate that to bash.  Ask for bug report.
	if strings.Contains(target, "{{ if") || strings.Contains(target, "{{if") || strings.Contains(target, "{{ .Arm") || strings.Contains(target, "{{.Arm") {
		return "", fmt.Errorf("name_template %q contains unknown conditional or ARM format.  Please file bug at https://github.com/goreleaser/godownloader", target)
	}

	varmap := map[string]string{
		"Os":          "${OS}",
		"Arch":        "${ARCH}",
		"Version":     "${VERSION}",
		"Tag":         "${TAG}",
		"Binary":      "${BINARY}",
		"ProjectName": "${PROJECT_NAME}",
	}

	out := bytes.Buffer{}
	out.WriteString(prefix)
	t, err := template.New("name").Parse(target)
	if err != nil {
		return "", err
	}
	err = t.Execute(&out, varmap)
	return out.String(), err
}

// returns the owner/name repo from input
//
// see https://github.com/goreleaser/godownloader/issues/55
func normalizeRepo(repo string) string {
	// handle full or partial URLs
	repo = strings.TrimPrefix(repo, "https://github.com/")
	repo = strings.TrimPrefix(repo, "http://github.com/")
	repo = strings.TrimPrefix(repo, "github.com/")

	// hande /name/repo or name/repo/ cases
	repo = strings.Trim(repo, "/")

	return repo
}

func loadURLs(path string) (*config.Project, error) {
	for _, file := range []string{"goreleaser.yml", ".goreleaser.yml", "goreleaser.yaml", ".goreleaser.yaml"} {
		url := fmt.Sprintf("%s/%s", path, file)
		log.Infof("reading %s", url)
		project, err := loadURL(url)
		if err != nil {
			return nil, err
		}
		if project != nil {
			return project, nil
		}
	}
	return nil, fmt.Errorf("could not fetch a goreleaser configuration file")
}

func loadURL(file string) (*config.Project, error) {
	resp, err := http.Get(file)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode != 200 {
		log.Errorf("reading %s returned %d %s\n", file, resp.StatusCode, http.StatusText(resp.StatusCode))
		return nil, nil
	}
	p, err := config.LoadReader(resp.Body)

	// to make errcheck happy
	errc := resp.Body.Close()
	if errc != nil {
		return nil, errc
	}
	return &p, err
}

func loadFile(file string) (*config.Project, error) {
	p, err := config.Load(file)
	return &p, err
}

// Load project configuration from a given repo name or filepath/url.
func Load(repo string, file string) (project *config.Project, err error) {
	if repo == "" && file == "" {
		return nil, fmt.Errorf("repo or file not specified")
	}
	if file == "" {
		repo = normalizeRepo(repo)
		log.Infof("reading repo %q on github", repo)
		project, err = loadURLs(
			fmt.Sprintf("https://raw.githubusercontent.com/%s/master", repo),
		)
	} else {
		log.Infof("reading file %q", file)
		project, err = loadFile(file)
	}
	if err != nil {
		return nil, err
	}

	// if not specified add in GitHub owner/repo info
	if project.Release.GitHub.Owner == "" {
		if repo == "" {
			return nil, fmt.Errorf("owner/name repo not specified")
		}
		project.Release.GitHub.Owner = path.Dir(repo)
		project.Release.GitHub.Name = path.Base(repo)
	}

	ctx := context.New(*project)
	err = defaults.Pipe{}.Run(ctx)
	project = &ctx.Config

	// set default binary name
	if len(project.Builds) == 0 {
		project.Builds = []config.Build{
			{Binary: path.Base(repo)},
		}
	}
	if project.Builds[0].Binary == "" {
		project.Builds[0].Binary = path.Base(repo)
	}

	return project, err
}

func main() {
	var (
		repo    = kingpin.Flag("repo", "owner/name or URL of GitHub repository").Short('r').String()
		output  = kingpin.Flag("output", "output file, default stdout").Short('o').String()
		force   = kingpin.Flag("force", "force writing of output").Short('f').Bool()
		source  = kingpin.Flag("source", "source type [godownloader|raw|equinoxio]").Default("godownloader").String()
		exe     = kingpin.Flag("exe", "name of binary, used only in raw").String()
		nametpl = kingpin.Flag("nametpl", "name template, used only in raw").String()
		file    = kingpin.Arg("file", "??").String()
	)

	var (
		out []byte
		err error
	)

	kingpin.CommandLine.Version(fmt.Sprintf("%v, commit %v, built at %v", version, commit, datestr))
	kingpin.CommandLine.VersionFlag.Short('v')
	kingpin.CommandLine.HelpFlag.Short('h')
	kingpin.Parse()

	switch *source {
	case "godownloader":
		// https://github.com/goreleaser/godownloader
		out, err = processGodownloader(*repo, *file)
	case "equinoxio":
		// https://equinox.io
		out, err = processEquinoxio(*repo)
	case "raw":
		// raw mode is when people upload direct binaries
		// to GitHub releases that are not  not tar'ed or zip'ed.
		// For example:
		//   https://github.com/mvdan/sh/releases
		out, err = processRaw(*repo, *exe, *nametpl)
	default:
		log.Errorf("unknown source %q", *source)
		os.Exit(1)
	}

	if err != nil {
		log.WithError(err).Error("failed")
		os.Exit(1)
	}

	// stdout case
	if *output == "" {
		if _, err = os.Stdout.Write(out); err != nil {
			log.WithError(err).Error("unable to write")
			os.Exit(1)
		}
		return
	}

	// overwrite any existing file
	if *force {
		if err = ioutil.WriteFile(*output, out, 0666); err != nil {
			log.WithError(err).Errorf("unable to write to %s: %s", *output)
			os.Exit(1)
		}
		return
	}

	// Conditional Write -- only write file if different than current
	//
	// read in current file
	// if err
	//    ignore
	// else if not a shell file
	//    error
	// compare current file with new output
	//   if same, then exit
	//   if different, then overwrite
	checkOrig := true
	orig, err := ioutil.ReadFile(*output)
	if err != nil {
		checkOrig = false
	}
	// todo -- is shell file?
	if checkOrig && shellEqual(orig, out) {
		return
	}
	if err := ioutil.WriteFile(*output, out, 0666); err != nil {
		log.WithError(err).Errorf("unable to write to %s", *output)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"os"

	"github.com/antoniou/go-crawler/client"
)

func main() {
	client.New().Run(os.Args)
}
<commit_msg>Catch errors bubbling up to main<commit_after>package main

import (
	"log"
	"os"

	"github.com/antoniou/go-crawler/client"
)

func main() {
	err := client.New().Run(os.Args)
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"mime"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/ONSdigital/florence/assets"
	"github.com/ONSdigital/go-ns/handlers/reverseProxy"
	"github.com/ONSdigital/go-ns/log"
	"github.com/ONSdigital/go-ns/server"
	"github.com/gorilla/pat"
	"github.com/gorilla/websocket"
)

var bindAddr = ":8080"
var babbageURL = "http://localhost:8080"
var zebedeeURL = "http://localhost:8082"
var tableRendererURL = "http://localhost:23300"
var enableNewApp = false
var mongoURI = "localhost:27017"

var getAsset = assets.Asset
var getAssetETag = assets.GetAssetETag
var upgrader = websocket.Upgrader{}

// Version is set by the make target
var Version string

func main() {
	log.Debug("florence version", log.Data{"version": Version})

	if v := os.Getenv("BIND_ADDR"); len(v) > 0 {
		bindAddr = v
	}
	if v := os.Getenv("BABBAGE_URL"); len(v) > 0 {
		babbageURL = v
	}
	if v := os.Getenv("ZEBEDEE_URL"); len(v) > 0 {
		zebedeeURL = v
	}
	if v := os.Getenv("TABLE_RENDERER_URL"); len(v) > 0 {
		tableRendererURL = v
	}

	log.Namespace = "florence"

	/*
		NOTE:
		If there's any issues with this Florence server proxying redirects
		from either Babbage or Zebedee then the code in the previous Java
		Florence server might give some clues for a solution: https://github.com/ONSdigital/florence/blob/b13df0708b30493b98e9ce239103c59d7f409f98/src/main/java/com/github/onsdigital/florence/filter/Proxy.java#L125-L135

		The code has purposefully not been included in this Go replacement
		because we can't see what issue it's fixing and whether it's necessary.
	*/

	babbageURL, err := url.Parse(babbageURL)
	if err != nil {
		log.Error(err, nil)
		os.Exit(1)
	}
	babbageProxy := reverseProxy.Create(babbageURL, nil)

	zebedeeURL, err := url.Parse(zebedeeURL)
	if err != nil {
		log.Error(err, nil)
		os.Exit(1)
	}
	zebedeeProxy := reverseProxy.Create(zebedeeURL, zebedeeDirector)

	tableURL, err := url.Parse(tableRendererURL)
	if err != nil {
		log.Error(err, nil)
		os.Exit(1)
	}

	tableProxy := reverseProxy.Create(tableURL, tableDirector)

	router := pat.New()

	router.Handle("/zebedee/{uri:.*}", zebedeeProxy)
	router.Handle("/table/{uri:.*}", tableProxy)
	router.HandleFunc("/florence/dist/{uri:.*}", staticFiles)
	router.HandleFunc("/florence", legacyIndexFile)
	router.HandleFunc("/florence/", redirectToFlorence)
	router.HandleFunc("/florence/index.html", redirectToFlorence)
	router.HandleFunc("/florence/collections", legacyIndexFile)
	router.HandleFunc("/florence/publishing-queue", legacyIndexFile)
	router.HandleFunc("/florence/reports", legacyIndexFile)
	router.HandleFunc("/florence/users-and-access", legacyIndexFile)
	router.HandleFunc("/florence/workspace", legacyIndexFile)
	router.HandleFunc("/florence/websocket", websocketHandler)
	router.HandleFunc("/florence{uri:/.*}", refactoredIndexFile)
	router.Handle("/{uri:.*}", babbageProxy)

	log.Debug("Starting server", log.Data{
		"bind_addr":          bindAddr,
		"babbage_url":        babbageURL,
		"zebedee_url":        zebedeeURL,
		"table_renderer_url": tableRendererURL,
		"enable_new_app":     enableNewApp,
	})

	s := server.New(bindAddr, router)
	// TODO need to reconsider default go-ns server timeouts
	s.Server.IdleTimeout = 120 * time.Second
	s.Server.WriteTimeout = 120 * time.Second
	s.Server.ReadTimeout = 30 * time.Second
	s.MiddlewareOrder = []string{"RequestID", "Log"}

	// FIXME temporary hack to remove timeout middleware (doesn't support hijacker interface)
	mo := s.MiddlewareOrder
	var newMo []string
	for _, mw := range mo {
		if mw != "Timeout" {
			newMo = append(newMo, mw)
		}
	}
	s.MiddlewareOrder = newMo

	if err := s.ListenAndServe(); err != nil {
		log.Error(err, nil)
		os.Exit(2)
	}
}

func redirectToFlorence(w http.ResponseWriter, req *http.Request) {
	http.Redirect(w, req, "/florence", 301)
}

func staticFiles(w http.ResponseWriter, req *http.Request) {
	path := req.URL.Query().Get(":uri")
	assetPath := "../dist/" + path

	etag, err := getAssetETag(assetPath)

	if hdr := req.Header.Get("If-None-Match"); len(hdr) > 0 && hdr == etag {
		w.WriteHeader(http.StatusNotModified)
		return
	}

	b, err := getAsset(assetPath)
	if err != nil {
		log.Error(err, nil)
		w.WriteHeader(404)
		return
	}

	w.Header().Set(`ETag`, etag)
	w.Header().Set(`Cache-Control`, "no-cache")
	w.Header().Set(`Content-Type`, mime.TypeByExtension(filepath.Ext(path)))
	w.WriteHeader(200)
	w.Write(b)
}

func legacyIndexFile(w http.ResponseWriter, req *http.Request) {
	log.Debug("Getting legacy HTML file", nil)

	b, err := getAsset("../dist/legacy-assets/index.html")
	if err != nil {
		log.Error(err, nil)
		w.WriteHeader(404)
		return
	}

	w.Header().Set(`Content-Type`, "text/html")
	w.WriteHeader(200)
	w.Write(b)
}

func refactoredIndexFile(w http.ResponseWriter, req *http.Request) {
	log.Debug("Getting refactored HTML file", nil)

	b, err := getAsset("../dist/refactored.html")
	if err != nil {
		log.Error(err, nil)
		w.WriteHeader(404)
		return
	}

	w.Header().Set(`Content-Type`, "text/html")
	w.WriteHeader(200)
	w.Write(b)
}

func zebedeeDirector(req *http.Request) {
	if c, err := req.Cookie(`access_token`); err == nil && len(c.Value) > 0 {
		req.Header.Set(`X-Florence-Token`, c.Value)
	}
	req.URL.Path = strings.TrimPrefix(req.URL.Path, "/zebedee")
}

func tableDirector(req *http.Request) {
	req.URL.Path = strings.TrimPrefix(req.URL.Path, "/table")
}

func websocketHandler(w http.ResponseWriter, req *http.Request) {
	c, err := upgrader.Upgrade(w, req, nil)
	if err != nil {
		log.ErrorR(req, err, nil)
		return
	}

	defer c.Close()

	err = c.WriteJSON(florenceServerEvent{"version", florenceVersionPayload{Version: Version}})
	if err != nil {
		log.ErrorR(req, err, nil)
		return
	}

	for {
		_, message, err := c.ReadMessage()
		if err != nil {
			log.ErrorR(req, err, nil)
			break
		}

		rdr := bufio.NewReader(bytes.NewReader(message))
		b, err := rdr.ReadBytes('{')
		if err != nil {
			log.ErrorR(req, err, log.Data{"bytes": string(b)})
			continue
		}

		tags := strings.Split(string(b), ":")
		eventID := tags[0]
		eventType := tags[1]
		eventData := message[len(eventID)+len(eventType)+2:]

		switch eventType {
		case "log":
			var e florenceLogEvent
			e.ServerTimestamp = time.Now().UTC().Format("2006-01-02T15:04:05.000-0700Z")
			err = json.Unmarshal(eventData, &e)
			if err != nil {
				log.ErrorR(req, err, log.Data{"data": string(eventData)})
				continue
			}
			log.Debug("client log", log.Data{"data": e})

			err = c.WriteJSON(florenceServerEvent{"ack", eventID})
			if err != nil {
				log.ErrorR(req, err, nil)
			}
		default:
			log.DebugR(req, "unknown event type", log.Data{"type": eventType, "data": string(eventData)})
		}

		// err = c.WriteMessage(mt, message)
		// if err != nil {
		// 	log.ErrorR(req, err, nil)
		// 	break
		// }
	}
}

type florenceLogEvent struct {
	ServerTimestamp string      `json:"-"`
	ClientTimestamp time.Time   `json:"clientTimestamp"`
	Type            string      `json:"type"`
	Location        string      `json:"location"`
	InstanceID      string      `json:"instanceID"`
	Payload         interface{} `json:"payload"`
}

type florenceServerEvent struct {
	Type    string      `json:"type"`
	Payload interface{} `json:"payload"`
}

type florenceVersionPayload struct {
	Version string `json:"version"`
}
<commit_msg>Set up new proxy for Babbage<commit_after>package main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"mime"
	"net"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/ONSdigital/florence/assets"
	"github.com/ONSdigital/go-ns/handlers/reverseProxy"
	"github.com/ONSdigital/go-ns/log"
	"github.com/ONSdigital/go-ns/server"
	"github.com/gorilla/pat"
	"github.com/gorilla/websocket"
)

var bindAddr = ":8080"
var babbageURL = "http://localhost:8080"
var zebedeeURL = "http://localhost:8082"
var tableRendererURL = "http://localhost:23300"
var enableNewApp = false
var mongoURI = "localhost:27017"

var getAsset = assets.Asset
var getAssetETag = assets.GetAssetETag
var upgrader = websocket.Upgrader{}

// Version is set by the make target
var Version string

func main() {
	log.Debug("florence version", log.Data{"version": Version})

	if v := os.Getenv("BIND_ADDR"); len(v) > 0 {
		bindAddr = v
	}
	if v := os.Getenv("BABBAGE_URL"); len(v) > 0 {
		babbageURL = v
	}
	if v := os.Getenv("ZEBEDEE_URL"); len(v) > 0 {
		zebedeeURL = v
	}
	if v := os.Getenv("TABLE_RENDERER_URL"); len(v) > 0 {
		tableRendererURL = v
	}

	log.Namespace = "florence"

	/*
		NOTE:
		If there's any issues with this Florence server proxying redirects
		from either Babbage or Zebedee then the code in the previous Java
		Florence server might give some clues for a solution: https://github.com/ONSdigital/florence/blob/b13df0708b30493b98e9ce239103c59d7f409f98/src/main/java/com/github/onsdigital/florence/filter/Proxy.java#L125-L135

		The code has purposefully not been included in this Go replacement
		because we can't see what issue it's fixing and whether it's necessary.
	*/

	babbageURL, err := url.Parse(babbageURL)
	if err != nil {
		log.Error(err, nil)
		os.Exit(1)
	}

	babbageProxy := createBabbageProxy(babbageURL, nil)

	zebedeeURL, err := url.Parse(zebedeeURL)
	if err != nil {
		log.Error(err, nil)
		os.Exit(1)
	}
	zebedeeProxy := reverseProxy.Create(zebedeeURL, zebedeeDirector)

	tableURL, err := url.Parse(tableRendererURL)
	if err != nil {
		log.Error(err, nil)
		os.Exit(1)
	}

	tableProxy := reverseProxy.Create(tableURL, tableDirector)

	router := pat.New()

	router.Handle("/zebedee/{uri:.*}", zebedeeProxy)
	router.Handle("/table/{uri:.*}", tableProxy)
	router.HandleFunc("/florence/dist/{uri:.*}", staticFiles)
	router.HandleFunc("/florence", legacyIndexFile)
	router.HandleFunc("/florence/", redirectToFlorence)
	router.HandleFunc("/florence/index.html", redirectToFlorence)
	router.HandleFunc("/florence/collections", legacyIndexFile)
	router.HandleFunc("/florence/publishing-queue", legacyIndexFile)
	router.HandleFunc("/florence/reports", legacyIndexFile)
	router.HandleFunc("/florence/users-and-access", legacyIndexFile)
	router.HandleFunc("/florence/workspace", legacyIndexFile)
	router.HandleFunc("/florence/websocket", websocketHandler)
	router.HandleFunc("/florence{uri:/.*}", refactoredIndexFile)
	router.Handle("/{uri:.*}", babbageProxy)

	log.Debug("Starting server", log.Data{
		"bind_addr":          bindAddr,
		"babbage_url":        babbageURL,
		"zebedee_url":        zebedeeURL,
		"table_renderer_url": tableRendererURL,
		"enable_new_app":     enableNewApp,
	})

	s := server.New(bindAddr, router)
	// TODO need to reconsider default go-ns server timeouts
	s.Server.IdleTimeout = 120 * time.Second
	s.Server.WriteTimeout = 120 * time.Second
	s.Server.ReadTimeout = 30 * time.Second
	s.MiddlewareOrder = []string{"RequestID", "Log"}

	// FIXME temporary hack to remove timeout middleware (doesn't support hijacker interface)
	mo := s.MiddlewareOrder
	var newMo []string
	for _, mw := range mo {
		if mw != "Timeout" {
			newMo = append(newMo, mw)
		}
	}
	s.MiddlewareOrder = newMo

	if err := s.ListenAndServe(); err != nil {
		log.Error(err, nil)
		os.Exit(2)
	}
}

func redirectToFlorence(w http.ResponseWriter, req *http.Request) {
	http.Redirect(w, req, "/florence", 301)
}

func staticFiles(w http.ResponseWriter, req *http.Request) {
	path := req.URL.Query().Get(":uri")
	assetPath := "../dist/" + path

	etag, err := getAssetETag(assetPath)

	if hdr := req.Header.Get("If-None-Match"); len(hdr) > 0 && hdr == etag {
		w.WriteHeader(http.StatusNotModified)
		return
	}

	b, err := getAsset(assetPath)
	if err != nil {
		log.Error(err, nil)
		w.WriteHeader(404)
		return
	}

	w.Header().Set(`ETag`, etag)
	w.Header().Set(`Cache-Control`, "no-cache")
	w.Header().Set(`Content-Type`, mime.TypeByExtension(filepath.Ext(path)))
	w.WriteHeader(200)
	w.Write(b)
}

func legacyIndexFile(w http.ResponseWriter, req *http.Request) {
	log.Debug("Getting legacy HTML file", nil)

	b, err := getAsset("../dist/legacy-assets/index.html")
	if err != nil {
		log.Error(err, nil)
		w.WriteHeader(404)
		return
	}

	w.Header().Set(`Content-Type`, "text/html")
	w.WriteHeader(200)
	w.Write(b)
}

func refactoredIndexFile(w http.ResponseWriter, req *http.Request) {
	log.Debug("Getting refactored HTML file", nil)

	b, err := getAsset("../dist/refactored.html")
	if err != nil {
		log.Error(err, nil)
		w.WriteHeader(404)
		return
	}

	w.Header().Set(`Content-Type`, "text/html")
	w.WriteHeader(200)
	w.Write(b)
}

func zebedeeDirector(req *http.Request) {
	if c, err := req.Cookie(`access_token`); err == nil && len(c.Value) > 0 {
		req.Header.Set(`X-Florence-Token`, c.Value)
	}
	req.URL.Path = strings.TrimPrefix(req.URL.Path, "/zebedee")
}

func tableDirector(req *http.Request) {
	req.URL.Path = strings.TrimPrefix(req.URL.Path, "/table")
}

func websocketHandler(w http.ResponseWriter, req *http.Request) {
	c, err := upgrader.Upgrade(w, req, nil)
	if err != nil {
		log.ErrorR(req, err, nil)
		return
	}

	defer c.Close()

	err = c.WriteJSON(florenceServerEvent{"version", florenceVersionPayload{Version: Version}})
	if err != nil {
		log.ErrorR(req, err, nil)
		return
	}

	for {
		_, message, err := c.ReadMessage()
		if err != nil {
			log.ErrorR(req, err, nil)
			break
		}

		rdr := bufio.NewReader(bytes.NewReader(message))
		b, err := rdr.ReadBytes('{')
		if err != nil {
			log.ErrorR(req, err, log.Data{"bytes": string(b)})
			continue
		}

		tags := strings.Split(string(b), ":")
		eventID := tags[0]
		eventType := tags[1]
		eventData := message[len(eventID)+len(eventType)+2:]

		switch eventType {
		case "log":
			var e florenceLogEvent
			e.ServerTimestamp = time.Now().UTC().Format("2006-01-02T15:04:05.000-0700Z")
			err = json.Unmarshal(eventData, &e)
			if err != nil {
				log.ErrorR(req, err, log.Data{"data": string(eventData)})
				continue
			}
			log.Debug("client log", log.Data{"data": e})

			err = c.WriteJSON(florenceServerEvent{"ack", eventID})
			if err != nil {
				log.ErrorR(req, err, nil)
			}
		default:
			log.DebugR(req, "unknown event type", log.Data{"type": eventType, "data": string(eventData)})
		}

		// err = c.WriteMessage(mt, message)
		// if err != nil {
		// 	log.ErrorR(req, err, nil)
		// 	break
		// }
	}
}

// FIXME this is to fix go-ns reverse proxy replacing host name so that
// babbage has correct values when using {{location.hostname}} in handlebars
func createBabbageProxy(proxyURL *url.URL, directorFunc func(*http.Request)) http.Handler {
	proxy := httputil.NewSingleHostReverseProxy(proxyURL)
	director := proxy.Director
	proxy.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		DialContext: (&net.Dialer{
			Timeout:   5 * time.Second,
			KeepAlive: 30 * time.Second,
		}).DialContext,
		MaxIdleConns:          100,
		IdleConnTimeout:       90 * time.Second,
		TLSHandshakeTimeout:   5 * time.Second,
		ExpectContinueTimeout: 1 * time.Second,
	}
	proxy.Director = func(req *http.Request) {
		director(req)
		//req.Host = proxyURL.Host
		if directorFunc != nil {
			directorFunc(req)
		}
	}

	return proxy
}

type florenceLogEvent struct {
	ServerTimestamp string      `json:"-"`
	ClientTimestamp time.Time   `json:"clientTimestamp"`
	Type            string      `json:"type"`
	Location        string      `json:"location"`
	InstanceID      string      `json:"instanceID"`
	Payload         interface{} `json:"payload"`
}

type florenceServerEvent struct {
	Type    string      `json:"type"`
	Payload interface{} `json:"payload"`
}

type florenceVersionPayload struct {
	Version string `json:"version"`
}
<|endoftext|>


<commit_before>package plugin

import (
	"io/ioutil"
	"path/filepath"
	"strings"

	"github.com/pkg/errors"
	"github.com/yuin/gopher-lua"
	"layeh.com/gopher-luar"
)

// L is the lua state
// This is the VM that runs the plugins
var (
	L       *lua.LState
	plugins map[string]Plugin
)

// SetFn ...
// Plugin ...
type Plugin struct {
	Path string
	Name string
}

// Call a function for the specific plugin
func (p *Plugin) Call(fn string, args ...interface{}) (lua.LValue, error) {
	return Call(p.Name+"."+fn, args...)
}

// Unload a specific plugin
func (p *Plugin) Unload() error {
	return Unload(p.Path)
}
func Set(name string, val interface{}) {
	L.SetGlobal(name, luar.New(L, val))
}

func IsLoaded(path string) bool {
	filePath, err := filepath.Abs(path)
	if err != nil {
		return false
	}
	_, ok := plugins[filePath]
	return ok
}

// Unload remove plugin functions from lua VM
func Unload(path string) error {
	filePath, _ := filepath.Abs(path)
	_, fileName := filepath.Split(filePath)
	fileExt := filepath.Ext(fileName)
	pluginName := strings.TrimSuffix(fileName, fileExt)
	str := "\nlocal P = {}\n" + pluginName + " = P\nsetmetatable(" + pluginName + ", {__index = _G})\nsetfenv(1, P)\n"
	if err := L.DoString(str); err != nil {
		return errors.Wrap(err, "Unload: Failed to unload plugin")
	}
	delete(plugins, filePath)
	return nil
}

func Load(path string) (Plugin, error) {
	var newPlugin Plugin
	filePath, _ := filepath.Abs(path)
	_, fileName := filepath.Split(filePath)
	fileExt := filepath.Ext(fileName)
	pluginName := strings.TrimSuffix(fileName, fileExt)
	data, err := ioutil.ReadFile(filePath)
	if err != nil {
		return newPlugin, errors.Wrap(err, "Load: Unable to read file")
	}
	pluginDef := "\nlocal P = {}\n" + pluginName + " = P\nsetmetatable(" + pluginName + ", {__index = _G})\nsetfenv(1, P)\n"
	if err := L.DoString(pluginDef + string(data)); err != nil {
		return newPlugin, errors.Wrap(err, "Load: Unable to execute lua string")
	}
	newPlugin = Plugin{filePath, pluginName}
	plugins[filePath] = newPlugin
	return newPlugin, nil
}

func Call(fn string, args ...interface{}) (lua.LValue, error) {
	var luaFunc lua.LValue
	if strings.Contains(fn, ".") {
		plugin := L.GetGlobal(strings.Split(fn, ".")[0])
		if plugin.String() == "nil" {
			return nil, errors.New("function does not exist: " + fn)
		}
		luaFunc = L.GetField(plugin, strings.Split(fn, ".")[1])
	} else {
		luaFunc = L.GetGlobal(fn)
	}
	if luaFunc.String() == "nil" {
		return nil, errors.New("function does not exist: " + fn)
	}
	var luaArgs []lua.LValue
	for _, v := range args {
		luaArgs = append(luaArgs, luar.New(L, v))
	}
	err := L.CallByParam(lua.P{
		Fn:      luaFunc,
		NRet:    1,
		Protect: true,
	}, luaArgs...)
	if err != nil {
		return nil, err
	}
	ret := L.Get(-1) // returned value
	L.Pop(1)         // remove received value
	return ret, nil
}
}

func Init() {
	L = lua.NewState()
	plugins = make(map[string]Plugin)
}

func Close() {
	L.Close()
}
<commit_msg>Add doc<commit_after>package plugin

import (
	"io/ioutil"
	"path/filepath"
	"strings"

	"github.com/pkg/errors"
	"github.com/yuin/gopher-lua"
	"layeh.com/gopher-luar"
)

// L is the lua state
// This is the VM that runs the plugins
var (
	L       *lua.LState
	plugins map[string]Plugin
)

// Plugin ...
type Plugin struct {
	Path string
	Name string
}

// Call a function for the specific plugin
func (p *Plugin) Call(fn string, args ...interface{}) (lua.LValue, error) {
	return Call(p.Name+"."+fn, args...)
}

// Unload a specific plugin
func (p *Plugin) Unload() error {
	return Unload(p.Path)
}

// Set a global variable in lua VM
func Set(name string, val interface{}) {
	L.SetGlobal(name, luar.New(L, val))
}

// IsLoaded returns whether the file is loaded or not in the lua VM
func IsLoaded(path string) bool {
	filePath, err := filepath.Abs(path)
	if err != nil {
		return false
	}
	_, ok := plugins[filePath]
	return ok
}

// Unload remove plugin functions from lua VM
func Unload(path string) error {
	filePath, _ := filepath.Abs(path)
	_, fileName := filepath.Split(filePath)
	fileExt := filepath.Ext(fileName)
	pluginName := strings.TrimSuffix(fileName, fileExt)
	str := "\nlocal P = {}\n" + pluginName + " = P\nsetmetatable(" + pluginName + ", {__index = _G})\nsetfenv(1, P)\n"
	if err := L.DoString(str); err != nil {
		return errors.Wrap(err, "Unload: Failed to unload plugin")
	}
	delete(plugins, filePath)
	return nil
}

// Load plugin functions in lua VM
func Load(path string) (Plugin, error) {
	var newPlugin Plugin
	filePath, _ := filepath.Abs(path)
	_, fileName := filepath.Split(filePath)
	fileExt := filepath.Ext(fileName)
	pluginName := strings.TrimSuffix(fileName, fileExt)
	data, err := ioutil.ReadFile(filePath)
	if err != nil {
		return newPlugin, errors.Wrap(err, "Load: Unable to read file")
	}
	pluginDef := "\nlocal P = {}\n" + pluginName + " = P\nsetmetatable(" + pluginName + ", {__index = _G})\nsetfenv(1, P)\n"
	if err := L.DoString(pluginDef + string(data)); err != nil {
		return newPlugin, errors.Wrap(err, "Load: Unable to execute lua string")
	}
	newPlugin = Plugin{filePath, pluginName}
	plugins[filePath] = newPlugin
	return newPlugin, nil
}

// Call a function in the lua VM
func Call(fn string, args ...interface{}) (lua.LValue, error) {
	var luaFunc lua.LValue
	if strings.Contains(fn, ".") {
		plugin := L.GetGlobal(strings.Split(fn, ".")[0])
		if plugin.String() == "nil" {
			return nil, errors.New("function does not exist: " + fn)
		}
		luaFunc = L.GetField(plugin, strings.Split(fn, ".")[1])
	} else {
		luaFunc = L.GetGlobal(fn)
	}
	if luaFunc.String() == "nil" {
		return nil, errors.New("function does not exist: " + fn)
	}
	var luaArgs []lua.LValue
	for _, v := range args {
		luaArgs = append(luaArgs, luar.New(L, v))
	}
	err := L.CallByParam(lua.P{
		Fn:      luaFunc,
		NRet:    1,
		Protect: true,
	}, luaArgs...)
	if err != nil {
		return nil, err
	}
	ret := L.Get(-1) // returned value
	L.Pop(1)         // remove received value
	return ret, nil
}
}

// Init the lua VM
func Init() {
	L = lua.NewState()
	plugins = make(map[string]Plugin)
}

// Close lua VM
func Close() {
	L.Close()
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"flag"
	"fmt"
	"os"
	"strings"

	"github.com/jessfraz/weather/forecast"
	"github.com/jessfraz/weather/geocode"
	"github.com/jessfraz/weather/version"
	"github.com/mitchellh/colorstring"
)

const (
	defaultServerURI string = "https://geocode.jessfraz.com"
)

var (
	location     string
	units        string
	days         int
	ignoreAlerts bool
	hideIcon     bool
	noForecast   bool
	server       string
	vrsn         bool
	client       bool
	geo          geocode.Geocode
)

func printError(err error) {
	fmt.Println(colorstring.Color("[red]" + err.Error()))
	os.Exit(1)
}

func init() {
	// parse flags
	flag.BoolVar(&vrsn, "version", false, "print version and exit")
	flag.BoolVar(&vrsn, "v", false, "print version and exit (shorthand)")
	flag.StringVar(&location, "location", "", "Location to get the weather")
	flag.StringVar(&location, "l", "", "Location to get the weather (shorthand)")
	flag.BoolVar(&client, "client", false, "Get location for the ssh client")
	flag.BoolVar(&client, "c", false, "Get location for the ssh client (shorthand)")
	flag.StringVar(&units, "units", "auto", "System of units")
	flag.StringVar(&units, "u", "auto", "System of units (shorthand)")
	flag.StringVar(&server, "server", defaultServerURI, "Weather API server uri")
	flag.StringVar(&server, "s", defaultServerURI, "Weather API server uri (shorthand)")
	flag.IntVar(&days, "days", 0, "No. of days to get forecast")
	flag.IntVar(&days, "d", 0, "No. of days to get forecast (shorthand)")
	flag.BoolVar(&ignoreAlerts, "ignore-alerts", false, "Ignore alerts in weather output")
	flag.BoolVar(&hideIcon, "hide-icon", false, "Hide the weather icons from being output")
	flag.BoolVar(&noForecast, "no-forecast", false, "Hide the forecast for the next 16 hourse")

	flag.Usage = func() {
		flag.PrintDefaults()
	}

	flag.Parse()

	if server == "" {
		usageAndExit("Please enter a Weather API server uri or leave blank to use the default.", 0)
	}
}

//go:generate go run icons/generate.go

func main() {
	if vrsn {
		fmt.Printf("weather version %s, build %s", version.VERSION, version.GITCOMMIT)
		return
	}

	var err error
	if location == "" {
		sshConn := os.Getenv("SSH_CONNECTION")
		if client && len(sshConn) > 0 {
			// use their ssh connection to locate them
			ipports := strings.Split(sshConn, " ")
			geo, err = geocode.IPLocate(ipports[0])
			if err != nil {
				printError(err)
			}

		} else {
			// auto locate them
			geo, err = geocode.Autolocate()
			if err != nil {
				printError(err)
			}

			if geo.Latitude == 0 || geo.Longitude == 0 {
				printError(errors.New("Latitude and Longitude could not be determined from your IP so the weather will not be accurate\nTry: weather -l <your_zipcode> OR weather -l \"your city, state\""))
			}
		}
	} else {
		// get geolocation data for the given location
		geo, err = geocode.Locate(location, server)
		if err != nil {
			printError(err)
		}
	}

	if geo.Latitude == 0 || geo.Longitude == 0 {
		printError(errors.New("Latitude and Longitude could not be determined so the weather will not be accurate"))
	}

	data := forecast.Request{
		Latitude:  geo.Latitude,
		Longitude: geo.Longitude,
		Units:     units,
		Exclude:   []string{"minutely"},
	}
	if noForecast {
		data.Exclude = append(data.Exclude, "hourly")
	}

	fc, err := forecast.Get(fmt.Sprintf("%s/forecast", server), data)
	if err != nil {
		printError(err)
	}

	if err := forecast.PrintCurrent(fc, geo, ignoreAlerts, hideIcon); err != nil {
		printError(err)
	}

	if days > 0 {
		forecast.PrintDaily(fc, days)
	}
}

func usageAndExit(message string, exitCode int) {
	if message != "" {
		fmt.Fprintf(os.Stderr, message)
		fmt.Fprintf(os.Stderr, "\n\n")
	}
	flag.Usage()
	fmt.Fprintf(os.Stderr, "\n")
	os.Exit(exitCode)
}
<commit_msg>Quick typo fix (#43)<commit_after>package main

import (
	"errors"
	"flag"
	"fmt"
	"os"
	"strings"

	"github.com/jessfraz/weather/forecast"
	"github.com/jessfraz/weather/geocode"
	"github.com/jessfraz/weather/version"
	"github.com/mitchellh/colorstring"
)

const (
	defaultServerURI string = "https://geocode.jessfraz.com"
)

var (
	location     string
	units        string
	days         int
	ignoreAlerts bool
	hideIcon     bool
	noForecast   bool
	server       string
	vrsn         bool
	client       bool
	geo          geocode.Geocode
)

func printError(err error) {
	fmt.Println(colorstring.Color("[red]" + err.Error()))
	os.Exit(1)
}

func init() {
	// parse flags
	flag.BoolVar(&vrsn, "version", false, "print version and exit")
	flag.BoolVar(&vrsn, "v", false, "print version and exit (shorthand)")
	flag.StringVar(&location, "location", "", "Location to get the weather")
	flag.StringVar(&location, "l", "", "Location to get the weather (shorthand)")
	flag.BoolVar(&client, "client", false, "Get location for the ssh client")
	flag.BoolVar(&client, "c", false, "Get location for the ssh client (shorthand)")
	flag.StringVar(&units, "units", "auto", "System of units")
	flag.StringVar(&units, "u", "auto", "System of units (shorthand)")
	flag.StringVar(&server, "server", defaultServerURI, "Weather API server uri")
	flag.StringVar(&server, "s", defaultServerURI, "Weather API server uri (shorthand)")
	flag.IntVar(&days, "days", 0, "No. of days to get forecast")
	flag.IntVar(&days, "d", 0, "No. of days to get forecast (shorthand)")
	flag.BoolVar(&ignoreAlerts, "ignore-alerts", false, "Ignore alerts in weather output")
	flag.BoolVar(&hideIcon, "hide-icon", false, "Hide the weather icons from being output")
	flag.BoolVar(&noForecast, "no-forecast", false, "Hide the forecast for the next 16 hours")

	flag.Usage = func() {
		flag.PrintDefaults()
	}

	flag.Parse()

	if server == "" {
		usageAndExit("Please enter a Weather API server uri or leave blank to use the default.", 0)
	}
}

//go:generate go run icons/generate.go

func main() {
	if vrsn {
		fmt.Printf("weather version %s, build %s", version.VERSION, version.GITCOMMIT)
		return
	}

	var err error
	if location == "" {
		sshConn := os.Getenv("SSH_CONNECTION")
		if client && len(sshConn) > 0 {
			// use their ssh connection to locate them
			ipports := strings.Split(sshConn, " ")
			geo, err = geocode.IPLocate(ipports[0])
			if err != nil {
				printError(err)
			}

		} else {
			// auto locate them
			geo, err = geocode.Autolocate()
			if err != nil {
				printError(err)
			}

			if geo.Latitude == 0 || geo.Longitude == 0 {
				printError(errors.New("Latitude and Longitude could not be determined from your IP so the weather will not be accurate\nTry: weather -l <your_zipcode> OR weather -l \"your city, state\""))
			}
		}
	} else {
		// get geolocation data for the given location
		geo, err = geocode.Locate(location, server)
		if err != nil {
			printError(err)
		}
	}

	if geo.Latitude == 0 || geo.Longitude == 0 {
		printError(errors.New("Latitude and Longitude could not be determined so the weather will not be accurate"))
	}

	data := forecast.Request{
		Latitude:  geo.Latitude,
		Longitude: geo.Longitude,
		Units:     units,
		Exclude:   []string{"minutely"},
	}
	if noForecast {
		data.Exclude = append(data.Exclude, "hourly")
	}

	fc, err := forecast.Get(fmt.Sprintf("%s/forecast", server), data)
	if err != nil {
		printError(err)
	}

	if err := forecast.PrintCurrent(fc, geo, ignoreAlerts, hideIcon); err != nil {
		printError(err)
	}

	if days > 0 {
		forecast.PrintDaily(fc, days)
	}
}

func usageAndExit(message string, exitCode int) {
	if message != "" {
		fmt.Fprintf(os.Stderr, message)
		fmt.Fprintf(os.Stderr, "\n\n")
	}
	flag.Usage()
	fmt.Fprintf(os.Stderr, "\n")
	os.Exit(exitCode)
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"flag"
	"fmt"
	"log"
	"net"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"sync"
	"sync/atomic"
	"time"
)

type Service struct {
	Name    string
	Address string
	Port    int
}

func (s Service) AddressAndPort() string {
	return fmt.Sprintf("%s:%d", s.Address, s.Port)
}

var timeout = flag.Int64("timeout", 60, "time to wait for all services to be up (seconds)")
var httpPort = flag.Int("httpport", 0, "wait for an http request if target port is given port")
var ignorePort = flag.Int("ignoreport", 0, "don't wait for services on this port to be up")

func main() {
	setupUsage()
	flag.Parse()

	services := loadServicesFromEnv()

	var wg sync.WaitGroup
	cancel := make(chan struct{})

	for _, service := range services {
		if service.Port == *ignorePort {
			continue
		}
		wg.Add(1)
		go func(service Service) {
			waitForTcpConn(service, cancel)
			if *httpPort == service.Port {
				waitForHttpRequest(service, cancel)
			}
			wg.Done()
		}(service)
	}

	timer := time.AfterFunc(time.Duration(*timeout)*time.Second, func() {
		close(cancel)
	})

	wg.Wait()

	// There's a race here that might result in assuming that a timeout happend
	// although none happend. It appears when the timer fires after the connection
	// succeeded, but before the check via Stop() below.
	// That shouldn't happen very often and the service was pretty short of timing out
	// anyway, so I guess that's ok for now.
	if !timer.Stop() {
		log.Printf("Error: One or more services timed out after %d second(s)", *timeout)
		os.Exit(1)
	}
	log.Printf("All services are up!")
}

func setupUsage() {
	flag.CommandLine.Usage = func() {
		flag.Usage()
		fmt.Fprint(os.Stderr, `
Attempt to connect to all TCP services linked to a Docker container (found
via their env vars) and wait for them to accept a TCP connection.

When an <httpport> is specified, for services running on <httpport>, after
a successful TCP connect, do an HTTP request and wait until it's done. This
is useful for slow-starting services that only start up when they receive
their first request.

When timeout is over and TCP connect or HTTP request were unsucecssful, exit
with status 1.
`)
	}
}

func loadServicesFromEnv() []Service {
	services := make([]Service, 0)
	for _, line := range os.Environ() {
		keyAndValue := strings.SplitN(line, "=", 2)
		addrKey := keyAndValue[0]
		if strings.HasSuffix(addrKey, "_TCP_ADDR") {
			addr := os.Getenv(addrKey)
			name := addrKey[:len(addrKey)-9] // cut off "_TCP_ADDR"

			portKey := name + "_TCP_PORT"
			portStr := os.Getenv(portKey)
			port, err := strconv.Atoi(portStr)
			if err != nil {
				log.Printf("Failed to convert %v to int, value: '%v' - skipping service '%v'",
					portKey, portStr, name)
				continue
			}
			services = append(services, Service{Name: name, Address: addr, Port: port})
		}
	}
	return services
}

func waitForTcpConn(service Service, cancel <-chan struct{}) {
	var cancelled int32 = 0
	go func() {
		<-cancel
		atomic.StoreInt32(&cancelled, 1)
	}()

	var conn net.Conn
	err := errors.New("init")
	for err != nil {
		conn, err = net.DialTimeout("tcp", service.AddressAndPort(), 1*time.Second)

		if cancelled == 1 && err != nil {
			log.Printf("TCP: Service %v (%v) timed out. Last error: %v",
				service.Name, service.AddressAndPort(), err)
			return
		}

		time.Sleep(200 * time.Millisecond)
	}
	conn.Close()
	log.Printf("TCP: Service %v (%v) is up", service.Name, service.AddressAndPort())
}

func waitForHttpRequest(service Service, cancel <-chan struct{}) {
	url := url.URL{
		Scheme: "http",
		Host:   service.AddressAndPort(),
		Path:   "/",
	}

	err := errors.New("init")
	for err != nil {
		req, reqErr := http.NewRequest("GET", url.String(), nil)
		if reqErr != nil {
			log.Printf("Warning: Failed to create request for URL '%s' -  skipping service '%s'",
				url.String(), service.Name)
			return
		}

		tr := &http.Transport{}
		client := &http.Client{Transport: tr}
		c := make(chan error, 1)
		go func() {
			_, err := client.Do(req)
			c <- err
		}()

		select {
		case <-cancel:
			tr.CancelRequest(req)
			log.Printf("HTTP: Service %v (%v) timed out. Last error: %v",
				service.Name, service.AddressAndPort(), err)
			<-c
			return
		case err = <-c:
		}
		time.Sleep(200 * time.Millisecond)
	}

	log.Printf("HTTP: Service %v (%v) is up", service.Name, service.AddressAndPort())
}
<commit_msg>Log when beginning to wait and log wait duration on success<commit_after>package main

import (
	"errors"
	"flag"
	"fmt"
	"log"
	"net"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"sync"
	"sync/atomic"
	"time"
)

type Service struct {
	Name    string
	Address string
	Port    int
}

func (s Service) AddressAndPort() string {
	return fmt.Sprintf("%s:%d", s.Address, s.Port)
}

var timeout = flag.Int64("timeout", 60, "time to wait for all services to be up (seconds)")
var httpPort = flag.Int("httpport", 0, "wait for an http request if target port is given port")
var ignorePort = flag.Int("ignoreport", 0, "don't wait for services on this port to be up")

func main() {
	setupUsage()
	flag.Parse()

	services := loadServicesFromEnv()

	log.Printf("Waiting for %d services to be ready...", len(services))
	begin := time.Now()

	var wg sync.WaitGroup
	cancel := make(chan struct{})

	for _, service := range services {
		if service.Port == *ignorePort {
			continue
		}
		wg.Add(1)
		go func(service Service) {
			waitForTcpConn(service, cancel)
			if *httpPort == service.Port {
				waitForHttpRequest(service, cancel)
			}
			wg.Done()
		}(service)
	}

	timer := time.AfterFunc(time.Duration(*timeout)*time.Second, func() {
		close(cancel)
	})

	wg.Wait()

	// There's a race here that might result in assuming that a timeout happend
	// although none happend. It appears when the timer fires after the connection
	// succeeded, but before the check via Stop() below.
	// That shouldn't happen very often and the service was pretty short of timing out
	// anyway, so I guess that's ok for now.
	if !timer.Stop() {
		log.Printf("Error: One or more services timed out after %d second(s)", *timeout)
		os.Exit(1)
	}
	log.Printf("All services are up after %v!", time.Now().Sub(begin))
}

func setupUsage() {
	flag.CommandLine.Usage = func() {
		flag.Usage()
		fmt.Fprint(os.Stderr, `
Attempt to connect to all TCP services linked to a Docker container (found
via their env vars) and wait for them to accept a TCP connection.

When an <httpport> is specified, for services running on <httpport>, after
a successful TCP connect, do an HTTP request and wait until it's done. This
is useful for slow-starting services that only start up when they receive
their first request.

When timeout is over and TCP connect or HTTP request were unsucecssful, exit
with status 1.
`)
	}
}

func loadServicesFromEnv() []Service {
	services := make([]Service, 0)
	for _, line := range os.Environ() {
		keyAndValue := strings.SplitN(line, "=", 2)
		addrKey := keyAndValue[0]
		if strings.HasSuffix(addrKey, "_TCP_ADDR") {
			addr := os.Getenv(addrKey)
			name := addrKey[:len(addrKey)-9] // cut off "_TCP_ADDR"

			portKey := name + "_TCP_PORT"
			portStr := os.Getenv(portKey)
			port, err := strconv.Atoi(portStr)
			if err != nil {
				log.Printf("Failed to convert %v to int, value: '%v' - skipping service '%v'",
					portKey, portStr, name)
				continue
			}
			services = append(services, Service{Name: name, Address: addr, Port: port})
		}
	}
	return services
}

func waitForTcpConn(service Service, cancel <-chan struct{}) {
	var cancelled int32 = 0
	go func() {
		<-cancel
		atomic.StoreInt32(&cancelled, 1)
	}()

	var conn net.Conn
	err := errors.New("init")
	for err != nil {
		conn, err = net.DialTimeout("tcp", service.AddressAndPort(), 1*time.Second)

		if cancelled == 1 && err != nil {
			log.Printf("TCP: Service %v (%v) timed out. Last error: %v",
				service.Name, service.AddressAndPort(), err)
			return
		}

		time.Sleep(200 * time.Millisecond)
	}
	conn.Close()
	log.Printf("TCP: Service %v (%v) is up", service.Name, service.AddressAndPort())
}

func waitForHttpRequest(service Service, cancel <-chan struct{}) {
	url := url.URL{
		Scheme: "http",
		Host:   service.AddressAndPort(),
		Path:   "/",
	}

	err := errors.New("init")
	for err != nil {
		req, reqErr := http.NewRequest("GET", url.String(), nil)
		if reqErr != nil {
			log.Printf("Warning: Failed to create request for URL '%s' -  skipping service '%s'",
				url.String(), service.Name)
			return
		}

		tr := &http.Transport{}
		client := &http.Client{Transport: tr}
		c := make(chan error, 1)
		go func() {
			_, err := client.Do(req)
			c <- err
		}()

		select {
		case <-cancel:
			tr.CancelRequest(req)
			log.Printf("HTTP: Service %v (%v) timed out. Last error: %v",
				service.Name, service.AddressAndPort(), err)
			<-c
			return
		case err = <-c:
		}
		time.Sleep(200 * time.Millisecond)
	}

	log.Printf("HTTP: Service %v (%v) is up", service.Name, service.AddressAndPort())
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"image/color"
	"math"
	"os"
)

type Vec struct {
	x, y, z float32
}

func (v *Vec) LenSq() float32 {
	return v.x*v.x + v.y*v.y + v.z*v.z
}

func (v *Vec) Len() float32 {
	return float32(math.Sqrt(float64(v.LenSq())))
}

func (v *Vec) Normalize() {
	l := v.Len()
	v.x /= l
	v.y /= l
	v.z /= l
}

type Ray struct {
	dir, origin Vec
}

type Shape interface {
	Intersect(Ray) (bool, pt Vec, n Vec)
}

type Sphere struct {
	pos      Vec
	radius   float32
	material Material
}

func (s *Sphere) Intersect(ray Ray) (bool, Vec, Vec) {
	return false, Vec{}, Vec{}
}

type Cylinder struct {
	center   Vec
	dir      Vec
	height   float32
	material Material
}

func (c *Cylinder) Intersect(ray Ray) (bool, Vec, Vec) {
	return false, Vec{}, Vec{}
}

type Camera struct {
	pos, dir Vec
}

type Material struct {
	color color.Color
}

type Atom struct {
	name   string
	sphere Sphere
}

type Bond struct {
	a, b     *Atom
	cylinder Cylinder
}

type Element struct {
	material Material
	radius   float32
}

var elements map[string]Element = map[string]Element{
	"H":  {Material{color: color.RGBA{255, 255, 255, 255}}, 1.0},
	"He": {Material{color: color.RGBA{255, 255, 255, 255}}, 1.0},
	"O":  {Material{color: color.RGBA{255, 255, 255, 255}}, 1.0},
	"N":  {Material{color: color.RGBA{255, 255, 255, 255}}, 1.0},
	"P":  {Material{color: color.RGBA{255, 255, 255, 255}}, 1.0},
}

type Molecule struct {
	atoms []Atom
	bonds []Bond
}

func (m *Molecule) MakeBonds() {
}

func (m *Molecule) Intersect(ray Ray) (bool, Vec, Vec) {
	return false, Vec{}, Vec{}
}

func NewMolecule(path string) (error, *Molecule) {
	f, err := os.Open(path)
	if err != nil {
		return err, nil
	}
	defer f.Close()
	m := new(Molecule)
	sc := bufio.NewScanner(f)
	sc.Scan() // skip atom count
	sc.Scan() // skip comment
	for sc.Scan() {
		var v Vec
		var s string
		fmt.Sscanf(sc.Text(), "%s %f %f %f", &s, &v.x, &v.y, &v.z)
		e, ok := elements[s]
		if !ok {
			return fmt.Errorf("unknown element: %s", s), nil
		}
		atom := Atom{s, Sphere{v, e.radius, e.material}}
		m.atoms = append(m.atoms, atom)
	}
	if err = sc.Err(); err != nil {
		return err, nil
	}
	if len(m.atoms) == 0 {
		return fmt.Errorf("%s: no atoms found", path), nil
	}
	m.MakeBonds()
	return nil, m
}

type Color color.RGBA

func (c *Color) Set(val string) error {
	_, err := fmt.Sscanf(val, "{%d,%d,%d}", &c.R, &c.G, &c.B)
	return err
}

func (c Color) String() string {
	return fmt.Sprintf("{%d,%d,%d}", c.R, c.G, c.B)
}

var iFlag *string = flag.String("i", "input.xyz", "input file")
var oFlag *string = flag.String("o", "output.gif", "output file")
var wFlag *int = flag.Int("w", 300, "output image width")
var hFlag *int = flag.Int("h", 200, "output image height")
var xFlag *int = flag.Int("x", 0, "rotation speed along x axis")
var yFlag *int = flag.Int("y", 100, "rotation speed along y axis")
var zFlag *int = flag.Int("z", 0, "rotation speed along z axis")
var bFlag Color

func main() {
	flag.Var(&bFlag, "b", "background color")
	flag.Parse()
	err, m := NewMolecule(*iFlag)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Printf("%v\n", m)
	fmt.Println(bFlag)
}
<commit_msg>Add some bond-related functionality.<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"image/color"
	"math"
	"os"
)

type Vec struct {
	x, y, z float32
}

func (v *Vec) LenSq() float32 {
	return v.x*v.x + v.y*v.y + v.z*v.z
}

func (v *Vec) Len() float32 {
	return float32(math.Sqrt(float64(v.LenSq())))
}

func VecAdd(a, b Vec) Vec {
	a.Add(b)
	return a
}

func VecSub(a, b Vec) Vec {
	a.Sub(b)
	return a
}

func (v *Vec) Add(a Vec) {
	v.x += a.x
	v.y += a.y
	v.z += a.z
}

func (v *Vec) Sub(a Vec) {
	v.x -= a.x
	v.y -= a.y
	v.z -= a.z
}

func (v *Vec) Mul(s float32) {
	v.x *= s
	v.y *= s
	v.z *= s
}

func (v *Vec) Div(s float32) {
	v.x /= s
	v.y /= s
	v.z /= s
}

func (v *Vec) Normalize() {
	v.Div(v.Len())
}

type Ray struct {
	dir, origin Vec
}

type Shape interface {
	Intersect(Ray) (bool, pt Vec, n Vec)
}

type Sphere struct {
	pos      Vec
	radius   float32
	material Material
}

func (s *Sphere) Intersect(ray Ray) (bool, Vec, Vec) {
	return false, Vec{}, Vec{}
}

type Cylinder struct {
	center   Vec
	dir      Vec
	height   float32
	material Material
}

func NewCylinder(a, b Vec) Cylinder {
	return Cylinder{}
}

func (c *Cylinder) Intersect(ray Ray) (bool, Vec, Vec) {
	return false, Vec{}, Vec{}
}

type Camera struct {
	pos, dir Vec
}

type Material struct {
	color color.Color
}

type Atom struct {
	name   string
	sphere Sphere
}

type Bond struct {
	a, b     *Atom
	cylinder Cylinder
}

type Element struct {
	material Material
	radius   float32
}

var elements map[string]Element = map[string]Element{
	"H":  {Material{color: color.RGBA{255, 255, 255, 255}}, 1.0},
	"He": {Material{color: color.RGBA{255, 255, 255, 255}}, 1.0},
	"O":  {Material{color: color.RGBA{255, 255, 255, 255}}, 1.0},
	"N":  {Material{color: color.RGBA{255, 255, 255, 255}}, 1.0},
	"P":  {Material{color: color.RGBA{255, 255, 255, 255}}, 1.0},
}

type Molecule struct {
	atoms []*Atom
	bonds []*Bond
}

func (m *Molecule) Center() {
	var c Vec
	for _, a := range m.atoms {
		c.Add(a.sphere.pos)
	}
	c.Div(float32(len(m.atoms)))
	for _, a := range m.atoms {
		a.sphere.pos.Sub(c)
	}
}

func (m *Molecule) MakeBonds() {
	const bndist = 1.6
	const bndist2 = bndist * bndist
	for _, a := range m.atoms {
		for _, b := range m.atoms {
			pa := a.sphere.pos
			pb := b.sphere.pos
			if d := VecSub(pa, pb); d.LenSq() < bndist2 {
				bnd := Bond{a, b, NewCylinder(pa, pb)}
				m.bonds = append(m.bonds, &bnd)
			}
		}
	}
}

func (m *Molecule) Intersect(ray Ray) (bool, Vec, Vec) {
	return false, Vec{}, Vec{}
}

func NewMolecule(path string) (error, *Molecule) {
	f, err := os.Open(path)
	if err != nil {
		return err, nil
	}
	defer f.Close()
	m := new(Molecule)
	sc := bufio.NewScanner(f)
	sc.Scan() // skip atom count
	sc.Scan() // skip comment
	for sc.Scan() {
		var v Vec
		var s string
		fmt.Sscanf(sc.Text(), "%s %f %f %f", &s, &v.x, &v.y, &v.z)
		e, ok := elements[s]
		if !ok {
			return fmt.Errorf("unknown element: %s", s), nil
		}
		atom := Atom{s, Sphere{v, e.radius, e.material}}
		m.atoms = append(m.atoms, &atom)
	}
	if err = sc.Err(); err != nil {
		return err, nil
	}
	if len(m.atoms) == 0 {
		return fmt.Errorf("%s: no atoms found", path), nil
	}
	m.Center()
	m.MakeBonds()
	return nil, m
}

type Color color.RGBA

func (c *Color) Set(val string) error {
	_, err := fmt.Sscanf(val, "{%d,%d,%d}", &c.R, &c.G, &c.B)
	return err
}

func (c Color) String() string {
	return fmt.Sprintf("{%d,%d,%d}", c.R, c.G, c.B)
}

var iFlag *string = flag.String("i", "input.xyz", "input file")
var oFlag *string = flag.String("o", "output.gif", "output file")
var wFlag *int = flag.Int("w", 300, "output image width")
var hFlag *int = flag.Int("h", 200, "output image height")
var xFlag *int = flag.Int("x", 0, "rotation speed along x axis")
var yFlag *int = flag.Int("y", 100, "rotation speed along y axis")
var zFlag *int = flag.Int("z", 0, "rotation speed along z axis")
var bFlag Color

func main() {
	flag.Var(&bFlag, "b", "background color")
	flag.Parse()
	err, m := NewMolecule(*iFlag)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Printf("%v\n", m)
	fmt.Println(bFlag)
}
<|endoftext|>


<commit_before>package auth

import (
	"bytes"
	"crypto/md5"
	"crypto/rand"
	"encoding/base64"
	"fmt"
	"net/http"
	"strings"
)

// RandomKey returns a random 16-byte base64 alphabet string
func RandomKey() string {
	k := make([]byte, 12)
	for bytes := 0; bytes < len(k); {
		n, err := rand.Read(k[bytes:])
		if err != nil {
			panic("rand.Read() failed")
		}
		bytes += n
	}
	return base64.StdEncoding.EncodeToString(k)
}

// H function for MD5 algorithm (returns a lower-case hex MD5 digest)
func H(data string) string {
	digest := md5.New()
	digest.Write([]byte(data))
	return fmt.Sprintf("%x", digest.Sum(nil))
}

// ParseList parses a comma-separated list of values as described by
// RFC 2068 and returns list elements.
//
// Lifted from https://code.google.com/p/gorilla/source/browse/http/parser/parser.go
// which was ported from urllib2.parse_http_list, from the Python
// standard library.
func ParseList(value string) []string {
	var list []string
	var escape, quote bool
	b := new(bytes.Buffer)
	for _, r := range value {
		switch {
		case escape:
			b.WriteRune(r)
			escape = false
		case quote:
			if r == '\\' {
				escape = true
			} else {
				if r == '"' {
					quote = false
				}
				b.WriteRune(r)
			}
		case r == ',':
			list = append(list, strings.TrimSpace(b.String()))
			b.Reset()
		case r == '"':
			quote = true
			b.WriteRune(r)
		default:
			b.WriteRune(r)
		}
	}
	// Append last part.
	if s := b.String(); s != "" {
		list = append(list, strings.TrimSpace(s))
	}
	return list
}

// ParsePairs extracts key/value pairs from a comma-separated list of
// values as described by RFC 2068 and returns a map[key]value. The
// resulting values are unquoted. If a list element doesn't contain a
// "=", the key is the element itself and the value is an empty
// string.
//
// Lifted from https://code.google.com/p/gorilla/source/browse/http/parser/parser.go
func ParsePairs(value string) map[string]string {
	m := make(map[string]string)
	for _, pair := range ParseList(strings.TrimSpace(value)) {
		if i := strings.Index(pair, "="); i < 0 || i == len(pair)-1{
			m[pair] = ""
		} else {
			v := pair[i+1:]
			if v[0] == '"' && v[len(v)-1] == '"' {
				// Unquote it.
				v = v[1 : len(v)-1]
			}
			m[pair[:i]] = v
		}
	}
	return m
}

// Headers contains header and error codes used by authenticator.
type Headers struct {
	Authenticate      string // WWW-Authenticate
	Authorization     string // Authorization
	AuthInfo          string // Authentication-Info
	UnauthCode        int    // 401
	UnauthContentType string // text/plain
	UnauthResponse    string // Unauthorized.
}

// V returns NormalHeaders when h is nil, or h otherwise. Allows to
// use uninitialized *Headers values in structs.
func (h *Headers) V() *Headers {
	if h == nil {
		return NormalHeaders
	}
	return h
}

var (
	// NormalHeaders are the regular Headers used by an HTTP Server for
	// request authentication.
	NormalHeaders = &Headers{
		Authenticate:      "WWW-Authenticate",
		Authorization:     "Authorization",
		AuthInfo:          "Authentication-Info",
		UnauthCode:        http.StatusUnauthorized,
		UnauthContentType: "text/plain",
		UnauthResponse:    fmt.Sprintf("%d %s\n", http.StatusUnauthorized, http.StatusText(http.StatusUnauthorized)),
	}

	// ProxyHeaders are Headers used by an HTTP Proxy server for proxy
	// access authentication.
	ProxyHeaders = &Headers{
		Authenticate:      "Proxy-Authenticate",
		Authorization:     "Proxy-Authorization",
		AuthInfo:          "Proxy-Authentication-Info",
		UnauthCode:        http.StatusProxyAuthRequired,
		UnauthContentType: "text/plain",
		UnauthResponse:    fmt.Sprintf("%d %s\n", http.StatusProxyAuthRequired, http.StatusText(http.StatusProxyAuthRequired)),
	}
)

const contentType = "Content-Type"
<commit_msg>gofmt pull/73<commit_after>package auth

import (
	"bytes"
	"crypto/md5"
	"crypto/rand"
	"encoding/base64"
	"fmt"
	"net/http"
	"strings"
)

// RandomKey returns a random 16-byte base64 alphabet string
func RandomKey() string {
	k := make([]byte, 12)
	for bytes := 0; bytes < len(k); {
		n, err := rand.Read(k[bytes:])
		if err != nil {
			panic("rand.Read() failed")
		}
		bytes += n
	}
	return base64.StdEncoding.EncodeToString(k)
}

// H function for MD5 algorithm (returns a lower-case hex MD5 digest)
func H(data string) string {
	digest := md5.New()
	digest.Write([]byte(data))
	return fmt.Sprintf("%x", digest.Sum(nil))
}

// ParseList parses a comma-separated list of values as described by
// RFC 2068 and returns list elements.
//
// Lifted from https://code.google.com/p/gorilla/source/browse/http/parser/parser.go
// which was ported from urllib2.parse_http_list, from the Python
// standard library.
func ParseList(value string) []string {
	var list []string
	var escape, quote bool
	b := new(bytes.Buffer)
	for _, r := range value {
		switch {
		case escape:
			b.WriteRune(r)
			escape = false
		case quote:
			if r == '\\' {
				escape = true
			} else {
				if r == '"' {
					quote = false
				}
				b.WriteRune(r)
			}
		case r == ',':
			list = append(list, strings.TrimSpace(b.String()))
			b.Reset()
		case r == '"':
			quote = true
			b.WriteRune(r)
		default:
			b.WriteRune(r)
		}
	}
	// Append last part.
	if s := b.String(); s != "" {
		list = append(list, strings.TrimSpace(s))
	}
	return list
}

// ParsePairs extracts key/value pairs from a comma-separated list of
// values as described by RFC 2068 and returns a map[key]value. The
// resulting values are unquoted. If a list element doesn't contain a
// "=", the key is the element itself and the value is an empty
// string.
//
// Lifted from https://code.google.com/p/gorilla/source/browse/http/parser/parser.go
func ParsePairs(value string) map[string]string {
	m := make(map[string]string)
	for _, pair := range ParseList(strings.TrimSpace(value)) {
		if i := strings.Index(pair, "="); i < 0 || i == len(pair)-1 {
			m[pair] = ""
		} else {
			v := pair[i+1:]
			if v[0] == '"' && v[len(v)-1] == '"' {
				// Unquote it.
				v = v[1 : len(v)-1]
			}
			m[pair[:i]] = v
		}
	}
	return m
}

// Headers contains header and error codes used by authenticator.
type Headers struct {
	Authenticate      string // WWW-Authenticate
	Authorization     string // Authorization
	AuthInfo          string // Authentication-Info
	UnauthCode        int    // 401
	UnauthContentType string // text/plain
	UnauthResponse    string // Unauthorized.
}

// V returns NormalHeaders when h is nil, or h otherwise. Allows to
// use uninitialized *Headers values in structs.
func (h *Headers) V() *Headers {
	if h == nil {
		return NormalHeaders
	}
	return h
}

var (
	// NormalHeaders are the regular Headers used by an HTTP Server for
	// request authentication.
	NormalHeaders = &Headers{
		Authenticate:      "WWW-Authenticate",
		Authorization:     "Authorization",
		AuthInfo:          "Authentication-Info",
		UnauthCode:        http.StatusUnauthorized,
		UnauthContentType: "text/plain",
		UnauthResponse:    fmt.Sprintf("%d %s\n", http.StatusUnauthorized, http.StatusText(http.StatusUnauthorized)),
	}

	// ProxyHeaders are Headers used by an HTTP Proxy server for proxy
	// access authentication.
	ProxyHeaders = &Headers{
		Authenticate:      "Proxy-Authenticate",
		Authorization:     "Proxy-Authorization",
		AuthInfo:          "Proxy-Authentication-Info",
		UnauthCode:        http.StatusProxyAuthRequired,
		UnauthContentType: "text/plain",
		UnauthResponse:    fmt.Sprintf("%d %s\n", http.StatusProxyAuthRequired, http.StatusText(http.StatusProxyAuthRequired)),
	}
)

const contentType = "Content-Type"
<|endoftext|>