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

// Package rename contains the implementation of the 'gorename' command
// whose main function is in code.google.com/p/go.tools/refactor/rename.
// See that package for the command documentation.
package rename

import (
	"errors"
	"fmt"
	"go/ast"
	"go/build"
	"go/format"
	"go/parser"
	"go/token"
	"os"
	"path/filepath"
	"sort"
	"strings"

	"code.google.com/p/go.tools/go/loader"
	"code.google.com/p/go.tools/go/types"
	"code.google.com/p/go.tools/refactor/importgraph"
	"code.google.com/p/go.tools/refactor/satisfy"
)

var (
	// Force enables patching of the source files even if conflicts were reported.
	// The resulting program may be ill-formed.
	// It may even cause gorename to crash.  TODO(adonovan): fix that.
	Force bool

	// DryRun causes the tool to report conflicts but not update any files.
	DryRun bool

	// ConflictError is returned by Main when it aborts the renaming due to conflicts.
	// (It is distinguished because the interesting errors are the conflicts themselves.)
	ConflictError = errors.New("renaming aborted due to conflicts")

	// Verbose enables extra logging.
	Verbose bool
)

type renamer struct {
	iprog              *loader.Program
	objsToUpdate       map[types.Object]bool
	hadConflicts       bool
	to                 string
	satisfyConstraints map[satisfy.Constraint]bool
	packages           map[*types.Package]*loader.PackageInfo // subset of iprog.AllPackages to inspect
}

var reportError = func(posn token.Position, message string) {
	fmt.Fprintf(os.Stderr, "%s: %s\n", posn, message)
}

func Main(ctxt *build.Context, offsetFlag, fromFlag, to string) error {
	// -- Parse the -from or -offset specifier ----------------------------

	if (offsetFlag == "") == (fromFlag == "") {
		return fmt.Errorf("exactly one of the -from and -offset flags must be specified")
	}

	if !isValidIdentifier(to) {
		return fmt.Errorf("-to %q: not a valid identifier", to)
	}

	var spec *spec
	var err error
	if fromFlag != "" {
		spec, err = parseFromFlag(ctxt, fromFlag)
	} else {
		spec, err = parseOffsetFlag(ctxt, offsetFlag)
	}
	if err != nil {
		return err
	}

	if spec.fromName == to {
		return fmt.Errorf("the old and new names are the same: %s", to)
	}

	// -- Load the program consisting of the initial package  -------------

	iprog, err := loadProgram(ctxt, map[string]bool{spec.pkg: true})
	if err != nil {
		return err
	}

	fromObjects, err := findFromObjects(iprog, spec)
	if err != nil {
		return err
	}

	// -- Load a larger program, for global renamings ---------------------

	if requiresGlobalRename(fromObjects, to) {
		// For a local refactoring, we needn't load more
		// packages, but if the renaming affects the package's
		// API, we we must load all packages that depend on the
		// package defining the object, plus their tests.

		if Verbose {
			fmt.Fprintln(os.Stderr, "Potentially global renaming; scanning workspace...")
		}

		// Scan the workspace and build the import graph.
		_, rev, errors := importgraph.Build(ctxt)
		if len(errors) > 0 {
			fmt.Fprintf(os.Stderr, "While scanning Go workspace:\n")
			for path, err := range errors {
				fmt.Fprintf(os.Stderr, "Package %q: %s.\n", path, err)
			}
		}

		// Enumerate the set of potentially affected packages.
		affectedPackages := make(map[string]bool)
		for _, obj := range fromObjects {
			// External test packages are never imported,
			// so they will never appear in the graph.
			for path := range rev.Search(obj.Pkg().Path()) {
				affectedPackages[path] = true
			}
		}

		// TODO(adonovan): allow the user to specify the scope,
		// or -ignore patterns?  Computing the scope when we
		// don't (yet) support inputs containing errors can make
		// the tool rather brittle.

		// Re-load the larger program.
		iprog, err = loadProgram(ctxt, affectedPackages)
		if err != nil {
			return err
		}

		fromObjects, err = findFromObjects(iprog, spec)
		if err != nil {
			return err
		}
	}

	// -- Do the renaming -------------------------------------------------

	r := renamer{
		iprog:        iprog,
		objsToUpdate: make(map[types.Object]bool),
		to:           to,
		packages:     make(map[*types.Package]*loader.PackageInfo),
	}

	// Only the initially imported packages (iprog.Imported) and
	// their external tests (iprog.Created) should be inspected or
	// modified, as only they have type-checked functions bodies.
	// The rest are just dependencies, needed only for package-level
	// type information.
	for _, info := range iprog.Imported {
		r.packages[info.Pkg] = info
	}
	for _, info := range iprog.Created { // (tests)
		r.packages[info.Pkg] = info
	}

	for _, from := range fromObjects {
		r.check(from)
	}
	if r.hadConflicts && !Force {
		return ConflictError
	}
	if DryRun {
		// TODO(adonovan): print the delta?
		return nil
	}
	return r.update()
}

// loadProgram loads the specified set of packages (plus their tests)
// and all their dependencies, from source, through the specified build
// context.  Only packages in pkgs will have their functions bodies typechecked.
func loadProgram(ctxt *build.Context, pkgs map[string]bool) (*loader.Program, error) {
	conf := loader.Config{
		Build:         ctxt,
		SourceImports: true,
		ParserMode:    parser.ParseComments,

		// TODO(adonovan): enable this.  Requires making a lot of code more robust!
		AllowErrors: false,
	}

	// Optimization: don't type-check the bodies of functions in our
	// dependencies, since we only need exported package members.
	conf.TypeCheckFuncBodies = func(p string) bool {
		return pkgs[p] || pkgs[strings.TrimSuffix(p, "_test")]
	}

	if Verbose {
		var list []string
		for pkg := range pkgs {
			list = append(list, pkg)
		}
		sort.Strings(list)
		for _, pkg := range list {
			fmt.Fprintf(os.Stderr, "Loading package: %s\n", pkg)
		}
	}

	for pkg := range pkgs {
		if err := conf.ImportWithTests(pkg); err != nil {
			return nil, err
		}
	}
	return conf.Load()
}

// requiresGlobalRename reports whether this renaming could potentially
// affect other packages in the Go workspace.
func requiresGlobalRename(fromObjects []types.Object, to string) bool {
	var tfm bool
	for _, from := range fromObjects {
		if from.Exported() {
			return true
		}
		switch objectKind(from) {
		case "type", "field", "method":
			tfm = true
		}
	}
	if ast.IsExported(to) && tfm {
		// A global renaming may be necessary even if we're
		// exporting a previous unexported name, since if it's
		// the name of a type, field or method, this could
		// change selections in other packages.
		// (We include "type" in this list because a type
		// used as an embedded struct field entails a field
		// renaming.)
		return true
	}
	return false
}

// update updates the input files.
func (r *renamer) update() error {
	// We use token.File, not filename, since a file may appear to
	// belong to multiple packages and be parsed more than once.
	// token.File captures this distinction; filename does not.
	var nidents int
	var filesToUpdate = make(map[*token.File]bool)
	for _, info := range r.packages {
		// Mutate the ASTs and note the filenames.
		for id, obj := range info.Defs {
			if r.objsToUpdate[obj] {
				nidents++
				id.Name = r.to
				filesToUpdate[r.iprog.Fset.File(id.Pos())] = true
			}
		}
		for id, obj := range info.Uses {
			if r.objsToUpdate[obj] {
				nidents++
				id.Name = r.to
				filesToUpdate[r.iprog.Fset.File(id.Pos())] = true
			}
		}
	}

	// TODO(adonovan): don't rewrite cgo + generated files.
	var nerrs, npkgs int
	for _, info := range r.packages {
		first := true
		for _, f := range info.Files {
			tokenFile := r.iprog.Fset.File(f.Pos())
			if filesToUpdate[tokenFile] {
				if first {
					npkgs++
					first = false
					if Verbose {
						fmt.Fprintf(os.Stderr, "Updating package %s\n",
							info.Pkg.Path())
					}
				}
				if err := rewriteFile(r.iprog.Fset, f, tokenFile.Name()); err != nil {
					fmt.Fprintf(os.Stderr, "Error: %s.\n", err)
					nerrs++
				}
			}
		}
	}
	fmt.Fprintf(os.Stderr, "Renamed %d occurrence%s in %d file%s in %d package%s.\n",
		nidents, plural(nidents),
		len(filesToUpdate), plural(len(filesToUpdate)),
		npkgs, plural(npkgs))
	if nerrs > 0 {
		return fmt.Errorf("failed to rewrite %d file%s", nerrs, plural(nerrs))
	}
	return nil
}

func plural(n int) string {
	if n != 1 {
		return "s"
	}
	return ""
}

var rewriteFile = func(fset *token.FileSet, f *ast.File, orig string) (err error) {
	backup := orig + ".prename"
	// TODO(adonovan): print packages and filenames in a form useful
	// to editors (so they can reload files).
	if Verbose {
		fmt.Fprintf(os.Stderr, "\t%s\n", orig)
	}
	if err := os.Rename(orig, backup); err != nil {
		return fmt.Errorf("failed to make backup %s -> %s: %s",
			orig, filepath.Base(backup), err)
	}
	out, err := os.Create(orig)
	if err != nil {
		// assume error includes the filename
		return fmt.Errorf("failed to open file: %s", err)
	}
	defer func() {
		if closeErr := out.Close(); err == nil {
			err = closeErr // don't clobber existing error
		}
	}()
	if err := format.Node(out, fset, f); err != nil {
		return fmt.Errorf("failed to write file: %s", err)
	}
	return nil
}
<commit_msg>refactor: don't litter the source tree with backup turdlets.<commit_after>// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package rename contains the implementation of the 'gorename' command
// whose main function is in code.google.com/p/go.tools/refactor/rename.
// See that package for the command documentation.
package rename

import (
	"errors"
	"fmt"
	"go/ast"
	"go/build"
	"go/format"
	"go/parser"
	"go/token"
	"os"
	"path/filepath"
	"sort"
	"strings"

	"code.google.com/p/go.tools/go/loader"
	"code.google.com/p/go.tools/go/types"
	"code.google.com/p/go.tools/refactor/importgraph"
	"code.google.com/p/go.tools/refactor/satisfy"
)

var (
	// Force enables patching of the source files even if conflicts were reported.
	// The resulting program may be ill-formed.
	// It may even cause gorename to crash.  TODO(adonovan): fix that.
	Force bool

	// DryRun causes the tool to report conflicts but not update any files.
	DryRun bool

	// ConflictError is returned by Main when it aborts the renaming due to conflicts.
	// (It is distinguished because the interesting errors are the conflicts themselves.)
	ConflictError = errors.New("renaming aborted due to conflicts")

	// Verbose enables extra logging.
	Verbose bool
)

type renamer struct {
	iprog              *loader.Program
	objsToUpdate       map[types.Object]bool
	hadConflicts       bool
	to                 string
	satisfyConstraints map[satisfy.Constraint]bool
	packages           map[*types.Package]*loader.PackageInfo // subset of iprog.AllPackages to inspect
}

var reportError = func(posn token.Position, message string) {
	fmt.Fprintf(os.Stderr, "%s: %s\n", posn, message)
}

func Main(ctxt *build.Context, offsetFlag, fromFlag, to string) error {
	// -- Parse the -from or -offset specifier ----------------------------

	if (offsetFlag == "") == (fromFlag == "") {
		return fmt.Errorf("exactly one of the -from and -offset flags must be specified")
	}

	if !isValidIdentifier(to) {
		return fmt.Errorf("-to %q: not a valid identifier", to)
	}

	var spec *spec
	var err error
	if fromFlag != "" {
		spec, err = parseFromFlag(ctxt, fromFlag)
	} else {
		spec, err = parseOffsetFlag(ctxt, offsetFlag)
	}
	if err != nil {
		return err
	}

	if spec.fromName == to {
		return fmt.Errorf("the old and new names are the same: %s", to)
	}

	// -- Load the program consisting of the initial package  -------------

	iprog, err := loadProgram(ctxt, map[string]bool{spec.pkg: true})
	if err != nil {
		return err
	}

	fromObjects, err := findFromObjects(iprog, spec)
	if err != nil {
		return err
	}

	// -- Load a larger program, for global renamings ---------------------

	if requiresGlobalRename(fromObjects, to) {
		// For a local refactoring, we needn't load more
		// packages, but if the renaming affects the package's
		// API, we we must load all packages that depend on the
		// package defining the object, plus their tests.

		if Verbose {
			fmt.Fprintln(os.Stderr, "Potentially global renaming; scanning workspace...")
		}

		// Scan the workspace and build the import graph.
		_, rev, errors := importgraph.Build(ctxt)
		if len(errors) > 0 {
			fmt.Fprintf(os.Stderr, "While scanning Go workspace:\n")
			for path, err := range errors {
				fmt.Fprintf(os.Stderr, "Package %q: %s.\n", path, err)
			}
		}

		// Enumerate the set of potentially affected packages.
		affectedPackages := make(map[string]bool)
		for _, obj := range fromObjects {
			// External test packages are never imported,
			// so they will never appear in the graph.
			for path := range rev.Search(obj.Pkg().Path()) {
				affectedPackages[path] = true
			}
		}

		// TODO(adonovan): allow the user to specify the scope,
		// or -ignore patterns?  Computing the scope when we
		// don't (yet) support inputs containing errors can make
		// the tool rather brittle.

		// Re-load the larger program.
		iprog, err = loadProgram(ctxt, affectedPackages)
		if err != nil {
			return err
		}

		fromObjects, err = findFromObjects(iprog, spec)
		if err != nil {
			return err
		}
	}

	// -- Do the renaming -------------------------------------------------

	r := renamer{
		iprog:        iprog,
		objsToUpdate: make(map[types.Object]bool),
		to:           to,
		packages:     make(map[*types.Package]*loader.PackageInfo),
	}

	// Only the initially imported packages (iprog.Imported) and
	// their external tests (iprog.Created) should be inspected or
	// modified, as only they have type-checked functions bodies.
	// The rest are just dependencies, needed only for package-level
	// type information.
	for _, info := range iprog.Imported {
		r.packages[info.Pkg] = info
	}
	for _, info := range iprog.Created { // (tests)
		r.packages[info.Pkg] = info
	}

	for _, from := range fromObjects {
		r.check(from)
	}
	if r.hadConflicts && !Force {
		return ConflictError
	}
	if DryRun {
		// TODO(adonovan): print the delta?
		return nil
	}
	return r.update()
}

// loadProgram loads the specified set of packages (plus their tests)
// and all their dependencies, from source, through the specified build
// context.  Only packages in pkgs will have their functions bodies typechecked.
func loadProgram(ctxt *build.Context, pkgs map[string]bool) (*loader.Program, error) {
	conf := loader.Config{
		Build:         ctxt,
		SourceImports: true,
		ParserMode:    parser.ParseComments,

		// TODO(adonovan): enable this.  Requires making a lot of code more robust!
		AllowErrors: false,
	}

	// Optimization: don't type-check the bodies of functions in our
	// dependencies, since we only need exported package members.
	conf.TypeCheckFuncBodies = func(p string) bool {
		return pkgs[p] || pkgs[strings.TrimSuffix(p, "_test")]
	}

	if Verbose {
		var list []string
		for pkg := range pkgs {
			list = append(list, pkg)
		}
		sort.Strings(list)
		for _, pkg := range list {
			fmt.Fprintf(os.Stderr, "Loading package: %s\n", pkg)
		}
	}

	for pkg := range pkgs {
		if err := conf.ImportWithTests(pkg); err != nil {
			return nil, err
		}
	}
	return conf.Load()
}

// requiresGlobalRename reports whether this renaming could potentially
// affect other packages in the Go workspace.
func requiresGlobalRename(fromObjects []types.Object, to string) bool {
	var tfm bool
	for _, from := range fromObjects {
		if from.Exported() {
			return true
		}
		switch objectKind(from) {
		case "type", "field", "method":
			tfm = true
		}
	}
	if ast.IsExported(to) && tfm {
		// A global renaming may be necessary even if we're
		// exporting a previous unexported name, since if it's
		// the name of a type, field or method, this could
		// change selections in other packages.
		// (We include "type" in this list because a type
		// used as an embedded struct field entails a field
		// renaming.)
		return true
	}
	return false
}

// update updates the input files.
func (r *renamer) update() error {
	// We use token.File, not filename, since a file may appear to
	// belong to multiple packages and be parsed more than once.
	// token.File captures this distinction; filename does not.
	var nidents int
	var filesToUpdate = make(map[*token.File]bool)
	for _, info := range r.packages {
		// Mutate the ASTs and note the filenames.
		for id, obj := range info.Defs {
			if r.objsToUpdate[obj] {
				nidents++
				id.Name = r.to
				filesToUpdate[r.iprog.Fset.File(id.Pos())] = true
			}
		}
		for id, obj := range info.Uses {
			if r.objsToUpdate[obj] {
				nidents++
				id.Name = r.to
				filesToUpdate[r.iprog.Fset.File(id.Pos())] = true
			}
		}
	}

	// TODO(adonovan): don't rewrite cgo + generated files.
	var nerrs, npkgs int
	for _, info := range r.packages {
		first := true
		for _, f := range info.Files {
			tokenFile := r.iprog.Fset.File(f.Pos())
			if filesToUpdate[tokenFile] {
				if first {
					npkgs++
					first = false
					if Verbose {
						fmt.Fprintf(os.Stderr, "Updating package %s\n",
							info.Pkg.Path())
					}
				}
				if err := rewriteFile(r.iprog.Fset, f, tokenFile.Name()); err != nil {
					fmt.Fprintf(os.Stderr, "Error: %s.\n", err)
					nerrs++
				}
			}
		}
	}
	fmt.Fprintf(os.Stderr, "Renamed %d occurrence%s in %d file%s in %d package%s.\n",
		nidents, plural(nidents),
		len(filesToUpdate), plural(len(filesToUpdate)),
		npkgs, plural(npkgs))
	if nerrs > 0 {
		return fmt.Errorf("failed to rewrite %d file%s", nerrs, plural(nerrs))
	}
	return nil
}

func plural(n int) string {
	if n != 1 {
		return "s"
	}
	return ""
}

func writeFile(name string, fset *token.FileSet, f *ast.File) error {
	out, err := os.Create(name)
	if err != nil {
		// assume error includes the filename
		return fmt.Errorf("failed to open file: %s", err)
	}
	if err := format.Node(out, fset, f); err != nil {
		out.Close() // ignore error
		return fmt.Errorf("failed to write file: %s", err)
	}
	return out.Close()
}

var rewriteFile = func(fset *token.FileSet, f *ast.File, orig string) (err error) {
	backup := orig + ".gorename.backup"
	// TODO(adonovan): print packages and filenames in a form useful
	// to editors (so they can reload files).
	if Verbose {
		fmt.Fprintf(os.Stderr, "\t%s\n", orig)
	}
	if err := os.Rename(orig, backup); err != nil {
		return fmt.Errorf("failed to make backup %s -> %s: %s",
			orig, filepath.Base(backup), err)
	}
	if err := writeFile(orig, fset, f); err != nil {
		// Restore the file from the backup.
		os.Remove(orig)         // ignore error
		os.Rename(backup, orig) // ignore error
		return err
	}
	os.Remove(backup) // ignore error
	return nil
}
<|endoftext|>


<commit_before>package rbac

import (
	"log"
)

// RoleManager is the interface to manage the roles in RBAC.
type RoleManager struct {
	allRoles map[string]*Role
	level    int
}

// The constructor for RoleManager.
func NewRoleManager(level int) *RoleManager {
	rm := RoleManager{}
	rm.allRoles = make(map[string]*Role)
	rm.level = level
	return &rm
}

func (rm *RoleManager) hasRole(name string) bool {
	_, ok := rm.allRoles[name]
	return ok
}

func (rm *RoleManager) createRole(name string) *Role {
	if !rm.hasRole(name) {
		rm.allRoles[name] = newRole(name)
	}

	return rm.allRoles[name]
}

// Add the link between role: name1 and role: name2.
// aka name1 inherits role: name2.
func (rm *RoleManager) AddLink(name1 string, name2 string) {
	role1 := rm.createRole(name1)
	role2 := rm.createRole(name2)
	role1.addRole(role2)
}

// Whether role: name1 inherits role: name2.
func (rm *RoleManager) HasLink(name1 string, name2 string) bool {
	if name1 == name2 {
		return true
	}

	if !rm.hasRole(name1) || !rm.hasRole(name2) {
		return false
	}

	role1 := rm.createRole(name1)
	return role1.hasRole(name2, rm.level)
}

// Get the roles that a subject inherits.
func (rm *RoleManager) GetRoles(name string) []string {
	if rm.hasRole(name) {
		return rm.createRole(name).getRoles()
	} else {
		return nil
	}
}

// Print all the roles.
func (rm *RoleManager) PrintRoles() {
	for _, role := range rm.allRoles {
		log.Print(role.toString())
	}
}

// Role is the data structure for a role in RBAC.
type Role struct {
	name  string
	roles []*Role
}

func newRole(name string) *Role {
	r := Role{}
	r.name = name
	return &r
}

func (r *Role) addRole(role *Role) {
	for _, rr := range r.roles {
		if rr.name == role.name {
			return
		}
	}

	r.roles = append(r.roles, role)
}

func (r *Role) hasRole(name string, level int) bool {
	if r.name == name {
		return true
	}

	if level <= 0 {
		return false
	}

	for _, role := range r.roles {
		if role.hasRole(name, level-1) {
			return true
		}
	}
	return false
}

func (r *Role) toString() string {
	names := ""
	for i, role := range r.roles {
		if i == 0 {
			names += role.name
		} else {
			names += ", " + role.name
		}
	}
	return r.name + " < " + names
}

func (r *Role) getRoles() []string {
	names := []string{}
	for _, role := range r.roles {
		names = append(names, role.name)
	}
	return names
}
<commit_msg>Add deleting role function to role manager.<commit_after>package rbac

import (
	"log"
)

// RoleManager is the interface to manage the roles in RBAC.
type RoleManager struct {
	allRoles map[string]*Role
	level    int
}

// The constructor for RoleManager.
func NewRoleManager(level int) *RoleManager {
	rm := RoleManager{}
	rm.allRoles = make(map[string]*Role)
	rm.level = level
	return &rm
}

func (rm *RoleManager) hasRole(name string) bool {
	_, ok := rm.allRoles[name]
	return ok
}

func (rm *RoleManager) createRole(name string) *Role {
	if !rm.hasRole(name) {
		rm.allRoles[name] = newRole(name)
	}

	return rm.allRoles[name]
}

// Add the inheritance link between role: name1 and role: name2.
// aka role: name1 inherits role: name2.
func (rm *RoleManager) AddLink(name1 string, name2 string) {
	role1 := rm.createRole(name1)
	role2 := rm.createRole(name2)
	role1.addRole(role2)
}

// Delete the inheritance link between role: name1 and role: name2.
// aka role: name1 does not inherit role: name2 any more.
func (rm *RoleManager) DeleteLink(name1 string, name2 string) {
	if !rm.hasRole(name1) || !rm.hasRole(name2) {
		return
	}

	role1 := rm.createRole(name1)
	role2 := rm.createRole(name2)
	role1.deleteRole(role2)
}

// Whether role: name1 inherits role: name2.
func (rm *RoleManager) HasLink(name1 string, name2 string) bool {
	if name1 == name2 {
		return true
	}

	if !rm.hasRole(name1) || !rm.hasRole(name2) {
		return false
	}

	role1 := rm.createRole(name1)
	return role1.hasRole(name2, rm.level)
}

// Get the roles that a subject inherits.
func (rm *RoleManager) GetRoles(name string) []string {
	if rm.hasRole(name) {
		return rm.createRole(name).getRoles()
	} else {
		return nil
	}
}

// Print all the roles.
func (rm *RoleManager) PrintRoles() {
	for _, role := range rm.allRoles {
		log.Print(role.toString())
	}
}

// Role is the data structure for a role in RBAC.
type Role struct {
	name  string
	roles []*Role
}

func newRole(name string) *Role {
	r := Role{}
	r.name = name
	return &r
}

func (r *Role) addRole(role *Role) {
	for _, rr := range r.roles {
		if rr.name == role.name {
			return
		}
	}

	r.roles = append(r.roles, role)
}

func (r *Role) deleteRole(role *Role) {
	for i, rr := range r.roles {
		if rr.name == role.name {
			r.roles = append(r.roles[:i], r.roles[i+1:]...)
			return
		}
	}
}

func (r *Role) hasRole(name string, level int) bool {
	if r.name == name {
		return true
	}

	if level <= 0 {
		return false
	}

	for _, role := range r.roles {
		if role.hasRole(name, level-1) {
			return true
		}
	}
	return false
}

func (r *Role) toString() string {
	names := ""
	for i, role := range r.roles {
		if i == 0 {
			names += role.name
		} else {
			names += ", " + role.name
		}
	}
	return r.name + " < " + names
}

func (r *Role) getRoles() []string {
	names := []string{}
	for _, role := range r.roles {
		names = append(names, role.name)
	}
	return names
}
<|endoftext|>


<commit_before>package writescript

import (
	"errors"
	"io/ioutil"
	"net/http"
	"net/url"
	"path/filepath"
	"strings"
)

const (
	KEYWORD_IMPORT = "#import "
)

type Plugin struct {
	ImportURLs      []string
	ImportCodeStack []string
	Js              []string // here we store the main plugin code
}

func (p *Plugin) ParseSource(src string) error {
	pluginLines := strings.Split(src, "\n")
	for _, v := range pluginLines {
		// fmt.Println("k", k, "v", v)

		if strings.Contains(v, KEYWORD_IMPORT) {
			// get the url...
			tmpUrl := strings.Split(v, KEYWORD_IMPORT)

			// check if import already exists, or is not at the list of known urls
			if len(p.ImportURLs) == 0 || !IsValueInList(tmpUrl[1], p.ImportURLs) {
				p.ImportURLs = append(p.ImportURLs, tmpUrl[1])
				data, err := p.request(tmpUrl[1])
				if err != nil {
					return err
				}
				p.ImportCodeStack = append(p.ImportCodeStack, string(data))
			}
		} else {
			p.Js = append(p.Js, v)
		}
	}
	return nil
}

func (p *Plugin) request(url string) ([]byte, error) {
	resp, errReq := http.Get(url)
	if errReq != nil {
		return []byte{}, errReq
	}
	defer resp.Body.Close()
	body, errBody := ioutil.ReadAll(resp.Body)
	if errBody != nil {
		return []byte{}, errBody
	}
	return body, nil
}

// LoadPlugin and return the source as a byte array
func LoadPlugin(src string) ([]byte, error) {
	var err error
	var dataReturn []byte

	switch PluginIsType(src) {

	case PluginTypeUnknown:
		dataReturn = []byte("")
		err = errors.New("No Plugin was set")
		break

	case PluginTypeFile:
		dataReturn, err = ioutil.ReadFile(src)
		break

	case PluginTypeURL:
		resp, errReq := http.Get(src)
		if errReq != nil {
			err = errReq
		}
		defer resp.Body.Close()
		body, errBody := ioutil.ReadAll(resp.Body)
		if errBody != nil {
			err = errBody
		}
		dataReturn = body
		break

	case PluginTypeString:
		dataReturn = []byte(src)
		break
	}

	// TODO: check if plugin keyword exists (in registry)
	// XXX: library of default plugins
	// fmt.Println("search if plugin is embedded...")
	// switch src {
	// case "golang-const":
	// 	// println("...golang-const")
	// 	dataReturn = PLUGIN_GOLANG_CONST
	// 	break
	// case "golang-cli":
	// 	// println("...golang-cli")
	// 	dataReturn = PLUGIN_GOLANG_CLI
	// 	break
	// default:
	// println("... default")
	// }

	// fmt.Println("==> pluginBytes:", string(pluginBytes))
	return dataReturn, err
}

const (
	PluginTypeUnknown = iota
	PluginTypeFile
	PluginTypeURL
	PluginTypeString
)

func PluginIsType(src string) int {
	theType := PluginTypeUnknown

	tmpExt := filepath.Ext(src)
	tmpURL, urlErr := url.Parse(src)

	if urlErr == nil && tmpURL.Scheme == "http" || tmpURL.Scheme == "https" {
		theType = PluginTypeURL
	} else if tmpExt == ".js" {
		theType = PluginTypeFile
	} else if src != "" {
		theType = PluginTypeString
	}

	return theType
}
<commit_msg>cleanup plugin.go<commit_after>package writescript

import (
	"errors"
	"io/ioutil"
	"net/http"
	"net/url"
	"path/filepath"
	"strings"
)

const (
	KEYWORD_IMPORT = "#import "
)

type Plugin struct {
	ImportURLs      []string
	ImportCodeStack []string
	Js              []string // here we store the main plugin code
}

func (p *Plugin) ParseSource(src string) error {
	pluginLines := strings.Split(src, "\n")
	for _, v := range pluginLines {
		// fmt.Println("k", k, "v", v)

		if strings.Contains(v, KEYWORD_IMPORT) {
			// get the url...
			tmpUrl := strings.Split(v, KEYWORD_IMPORT)

			// check if import already exists, or is not at the list of known urls
			if len(p.ImportURLs) == 0 || !IsValueInList(tmpUrl[1], p.ImportURLs) {
				p.ImportURLs = append(p.ImportURLs, tmpUrl[1])
				data, err := RequestPlugin(tmpUrl[1])
				if err != nil {
					return err
				}
				p.ImportCodeStack = append(p.ImportCodeStack, string(data))
			}
		} else {
			p.Js = append(p.Js, v)
		}
	}
	return nil
}

func RequestPlugin(url string) ([]byte, error) {
	resp, errReq := http.Get(url)
	if errReq != nil {
		return []byte{}, errReq
	}
	defer resp.Body.Close()
	body, errBody := ioutil.ReadAll(resp.Body)
	if errBody != nil {
		return []byte{}, errBody
	}
	return body, nil
}

// LoadPlugin and return the source as a byte array
func LoadPlugin(src string) ([]byte, error) {
	var err error
	var dataReturn []byte

	switch PluginIsType(src) {

	case PluginTypeUnknown:
		dataReturn = []byte("")
		err = errors.New("No Plugin was set")
		break

	case PluginTypeFile:
		dataReturn, err = ioutil.ReadFile(src)
		break

	case PluginTypeURL:
		dataReturn, err = RequestPlugin(src)
		break

	case PluginTypeString:
		dataReturn = []byte(src)
		break
	}

	// fmt.Println("==> pluginBytes:", string(pluginBytes))
	return dataReturn, err
}

const (
	PluginTypeUnknown = iota
	PluginTypeFile
	PluginTypeURL
	PluginTypeString
)

func PluginIsType(src string) int {
	theType := PluginTypeUnknown

	tmpExt := filepath.Ext(src)
	tmpURL, urlErr := url.Parse(src)

	if urlErr == nil && tmpURL.Scheme == "http" || tmpURL.Scheme == "https" {
		theType = PluginTypeURL
	} else if tmpExt == ".js" {
		theType = PluginTypeFile
	} else if src != "" {
		theType = PluginTypeString
	}

	return theType
}
<|endoftext|>


<commit_before>package main

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

	"github.com/appleboy/drone-facebook/template"
)

type (
	// Repo information
	Repo struct {
		Owner string
		Name  string
	}

	// Build information
	Build struct {
		Tag      string
		Event    string
		Number   int
		Commit   string
		Branch   string
		Author   string
		Avatar   string
		Message  string
		Email    string
		Status   string
		Link     string
		Started  float64
		Finished float64
	}

	// Config for the plugin.
	Config struct {
		WebhookID    string
		WebhookToken string
		Color        string
		Message      []string
	}

	// EmbedFooterObject for Embed Footer Structure.
	EmbedFooterObject struct {
		Text string `json:"text"`
	}

	// EmbedAuthorObject for Embed Author Structure
	EmbedAuthorObject struct {
		Name    string `json:"name"`
		URL     string `json:"url"`
		IconURL string `json:"icon_url"`
	}

	// EmbedFieldObject for Embed Field Structure
	EmbedFieldObject struct {
		Name  string `json:"name"`
		Value string `json:"value"`
	}

	// EmbedObject is for Embed Structure
	EmbedObject struct {
		Title       string             `json:"title"`
		Description string             `json:"description"`
		URL         string             `json:"url"`
		Color       int                `json:"color"`
		Footer      EmbedFooterObject  `json:"footer"`
		Author      EmbedAuthorObject  `json:"author"`
		Fields      []EmbedFieldObject `json:"fields"`
	}

	// Payload struct
	Payload struct {
		Wait      bool          `json:"wait"`
		Content   string        `json:"content"`
		Username  string        `json:"username"`
		AvatarURL string        `json:"avatar_url"`
		TTS       bool          `json:"tts"`
		Embeds    []EmbedObject `json:"embeds"`
	}

	// Plugin values.
	Plugin struct {
		Repo    Repo
		Build   Build
		Config  Config
		Payload Payload
	}
)

// Exec executes the plugin.
func (p *Plugin) Exec() error {
	if len(p.Config.WebhookID) == 0 || len(p.Config.WebhookToken) == 0 {
		log.Println("missing discord config")

		return errors.New("missing discord config")
	}

	if len(p.Config.Message) > 0 {
		for _, m := range p.Config.Message {
			txt, err := template.RenderTrim(m, p)
			if err != nil {
				return err
			}

			// update content
			p.Payload.Content = txt
			err = p.Send()
			if err != nil {
				return err
			}
		}
		return nil
	}

	// set default message
	p.Message()
	err := p.Send()
	if err != nil {
		return err
	}

	return nil
}

// Send discord message.
func (p *Plugin) Send() error {
	webhookURL := fmt.Sprintf("https://discordapp.com/api/webhooks/%s/%s", p.Config.WebhookID, p.Config.WebhookToken)
	b := new(bytes.Buffer)
	json.NewEncoder(b).Encode(p.Payload)
	_, err := http.Post(webhookURL, "application/json; charset=utf-8", b)

	if err != nil {
		return err
	}

	return nil
}

// Message is plugin default message.
func (p *Plugin) Message() {
	p.Payload.Embeds = []EmbedObject{
		{
			Title: p.Build.Message,
			URL:   p.Build.Link,
			Color: p.Color(),
			Author: EmbedAuthorObject{
				Name:    p.Build.Author,
				IconURL: p.Build.Avatar,
			},
			Footer: EmbedFooterObject{
				Text: "Power by Drone Discord Plugin",
			},
		},
	}
}

// Color code of the embed
func (p *Plugin) Color() int {
	if p.Config.Color != "" {
		p.Config.Color = strings.Replace(p.Config.Color, "#", "", -1)
		if s, err := strconv.ParseInt(p.Config.Color, 16, 32); err == nil {
			return int(s)
		}
	}

	switch p.Build.Status {
	case "success":
		// #1ac600 green
		return 1754624
	case "failure", "error", "killed":
		// #ff3232 red
		return 16724530
	default:
		// #ffd930 yellow
		return 16767280
	}
}
<commit_msg>fix bugs.<commit_after>package main

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

	"github.com/appleboy/drone-facebook/template"
)

type (
	// Repo information
	Repo struct {
		Owner string
		Name  string
	}

	// Build information
	Build struct {
		Tag      string
		Event    string
		Number   int
		Commit   string
		Branch   string
		Author   string
		Avatar   string
		Message  string
		Email    string
		Status   string
		Link     string
		Started  float64
		Finished float64
	}

	// Config for the plugin.
	Config struct {
		WebhookID    string
		WebhookToken string
		Color        string
		Message      []string
	}

	// EmbedFooterObject for Embed Footer Structure.
	EmbedFooterObject struct {
		Text string `json:"text"`
	}

	// EmbedAuthorObject for Embed Author Structure
	EmbedAuthorObject struct {
		Name    string `json:"name"`
		URL     string `json:"url"`
		IconURL string `json:"icon_url"`
	}

	// EmbedFieldObject for Embed Field Structure
	EmbedFieldObject struct {
		Name  string `json:"name"`
		Value string `json:"value"`
	}

	// EmbedObject is for Embed Structure
	EmbedObject struct {
		Title       string             `json:"title"`
		Description string             `json:"description"`
		URL         string             `json:"url"`
		Color       int                `json:"color"`
		Footer      EmbedFooterObject  `json:"footer"`
		Author      EmbedAuthorObject  `json:"author"`
		Fields      []EmbedFieldObject `json:"fields"`
	}

	// Payload struct
	Payload struct {
		Wait      bool          `json:"wait"`
		Content   string        `json:"content"`
		Username  string        `json:"username"`
		AvatarURL string        `json:"avatar_url"`
		TTS       bool          `json:"tts"`
		Embeds    []EmbedObject `json:"embeds"`
	}

	// Plugin values.
	Plugin struct {
		Repo    Repo
		Build   Build
		Config  Config
		Payload Payload
	}
)

// Exec executes the plugin.
func (p *Plugin) Exec() error {
	if len(p.Config.WebhookID) == 0 || len(p.Config.WebhookToken) == 0 {
		log.Println("missing discord config")

		return errors.New("missing discord config")
	}

	if len(p.Config.Message) > 0 {
		for _, m := range p.Config.Message {
			txt, err := template.RenderTrim(m, p)
			if err != nil {
				return err
			}

			// update content
			p.Payload.Content = txt
			err = p.Send()
			if err != nil {
				return err
			}
		}
		return nil
	}

	// set default message
	p.Payload.Content = ""
	p.Message()
	err := p.Send()
	if err != nil {
		return err
	}

	return nil
}

// Send discord message.
func (p *Plugin) Send() error {
	webhookURL := fmt.Sprintf("https://discordapp.com/api/webhooks/%s/%s", p.Config.WebhookID, p.Config.WebhookToken)
	b := new(bytes.Buffer)
	json.NewEncoder(b).Encode(p.Payload)
	_, err := http.Post(webhookURL, "application/json; charset=utf-8", b)

	if err != nil {
		return err
	}

	return nil
}

// Message is plugin default message.
func (p *Plugin) Message() {
	p.Payload.Embeds = []EmbedObject{
		{
			Title: p.Build.Message,
			URL:   p.Build.Link,
			Color: p.Color(),
			Author: EmbedAuthorObject{
				Name:    p.Build.Author,
				IconURL: p.Build.Avatar,
			},
			Footer: EmbedFooterObject{
				Text: "Power by Drone Discord Plugin",
			},
		},
	}
}

// Color code of the embed
func (p *Plugin) Color() int {
	if p.Config.Color != "" {
		p.Config.Color = strings.Replace(p.Config.Color, "#", "", -1)
		if s, err := strconv.ParseInt(p.Config.Color, 16, 32); err == nil {
			return int(s)
		}
	}

	switch p.Build.Status {
	case "success":
		// #1ac600 green
		return 1754624
	case "failure", "error", "killed":
		// #ff3232 red
		return 16724530
	default:
		// #ffd930 yellow
		return 16767280
	}
}
<|endoftext|>


<commit_before>package ai

import (
	"log"
	"reflect"
	"strconv"
	"strings"
	"time"

	"github.com/hysios/apiai-go"
)

type ApiAiOrder struct {
	AiResult apiai.Result
}

func (aa ApiAiOrder) Score() float64 {
	return aa.AiResult.Score
}

func (aa ApiAiOrder) Query() string {
	return aa.AiResult.ResolvedQuery
}

func (aa ApiAiOrder) Items() []Item {
	products := aa.Products()
	quantities := aa.Quantities()

	for i, q := range quantities {
		if len(products) >= i+1 {
			products[i].Quantity = q.Quantity
		}
	}

	return products
}

func (aa ApiAiOrder) Products() []Item {
	return aa.ExtractProducts("products")
}

func (aa ApiAiOrder) Quantities() []Item {
	return aa.ExtractQuantities("quantity")
}

func (aa ApiAiOrder) GiftItems() []Item {
	gifts := aa.GiftProducts()
	quantities := aa.GiftQuantities()

	for i, q := range quantities {
		if len(gifts) >= i+1 {
			gifts[i].Quantity = q.Quantity
		}
	}

	return gifts
}

func (aa ApiAiOrder) GiftProducts() []Item {
	return aa.ExtractProducts("gifts")
}

func (aa ApiAiOrder) GiftQuantities() []Item {
	return aa.ExtractQuantities("giftNumber")
}

func (aa ApiAiOrder) Address() string {
	if a, exist := aa.AiResult.Params["street-address"]; exist {

		rt := reflect.TypeOf(a)
		vals := reflect.ValueOf(a)

		switch rt.Kind() {
		case reflect.Slice:
			if vals.Len() > 0 {
				return vals.Index(0).Interface().(string)
			}
		case reflect.Array:
			if vals.Len() > 0 {
				return vals.Index(0).Interface().(string)
			}
		case reflect.String:
			return vals.Interface().(string)
		}
	}

	return ""
}

func (aa ApiAiOrder) Customer() string {
	if c, exist := aa.AiResult.Params["customer"]; exist {

		rt := reflect.TypeOf(c)
		vals := reflect.ValueOf(c)

		switch rt.Kind() {
		case reflect.Slice:
			if vals.Len() > 0 {
				return vals.Index(0).Interface().(string)
			}
		case reflect.Array:
			if vals.Len() > 0 {
				return vals.Index(0).Interface().(string)
			}
		case reflect.String:
			return vals.Interface().(string)
		}
	}

	return ""
}

func (aa ApiAiOrder) Time() time.Time {
	if t, exist := aa.AiResult.Params["date"]; exist {
		if aiTime, err := time.Parse("2006-01-02", t.(string)); err == nil {
			return aiTime
		}
	}

	return time.Time{}
}

func (aa ApiAiOrder) Fulfiled() bool {
	return true
}

func (aa ApiAiOrder) Note() string {
	if imp, exist := aa.AiResult.Params["important"]; exist {
		return imp.(string)
	}

	return ""
}

func (aa ApiAiOrder) ExtractProducts(t string) []Item {
	result := make([]Item, 0, 50)

	if products, exist := aa.AiResult.Params[t]; exist {
		ps := reflect.ValueOf(products)

		for i := 0; i < ps.Len(); i++ {
			p := ps.Index(i)
			name := p.Interface().(string)
			item := Item{Product: name}
			result = append(result, item)
		}
	}

	return result
}

func (aa ApiAiOrder) ExtractQuantities(t string) []Item {
	result := make([]Item, 0, 50)

	if quantities, exist := aa.AiResult.Params[t]; exist {
		qs := reflect.ValueOf(quantities)

		for i := 0; i < qs.Len(); i++ {
			q := qs.Index(i).Interface()

			switch t := q.(type) {
			case string:
				qs := q.(string)
				qi := extractQuantity(qs)
				item := Item{Quantity: qi}
				result = append(result, item)
			case float64:
				qf := q.(float64)
				item := Item{Quantity: int(qf)}
				result = append(result, item)
			case map[string]interface{}:
				log.Printf("....... quantity .........")
				qf := t["number"].(float64)
				quantity := int(qf)
				unit := t["unit"].(string)
				item := Item{Quantity: quantity, Unit: unit}
				result = append(result, item)
			default:
				log.Println("Unknown Quantity type: %v", t)
			}
		}
	}

	return result
}

func extractQuantity(s string) int {
	nums := strings.TrimFunc(s, TrimToNum)
	numsCgd := DBCtoSBC(nums)

	if len(numsCgd) > 0 {
		q, _ := strconv.Atoi(numsCgd)
		return q
	} else {
		return 0
	}
	// re := regexp.MustCompile("[0-9]+")
}

func TrimToNum(r rune) bool {
	if n := r - '0'; n >= 0 && n <= 9 {
		return false
	} else if m := r - '０'; m >= 0 && m <= 9 {
		return false
	}

	return true
}

func DBCtoSBC(s string) string {
	retstr := ""
	for _, i := range s {
		inside_code := i
		if inside_code == 12288 {
			inside_code = 32
		} else {
			inside_code -= 65248
		}
		if inside_code < 32 || inside_code > 126 {
			retstr += string(i)
		} else {
			retstr += string(inside_code)
		}
	}
	return retstr
}
<commit_msg>fix product unit<commit_after>package ai

import (
	"log"
	"reflect"
	"strconv"
	"strings"
	"time"

	"github.com/hysios/apiai-go"
)

type ApiAiOrder struct {
	AiResult apiai.Result
}

func (aa ApiAiOrder) Score() float64 {
	return aa.AiResult.Score
}

func (aa ApiAiOrder) Query() string {
	return aa.AiResult.ResolvedQuery
}

func (aa ApiAiOrder) Items() []Item {
	products := aa.Products()
	quantities := aa.Quantities()

	for i, q := range quantities {
		if len(products) >= i+1 {
			products[i].Quantity = q.Quantity
			products[i].Unit = q.Unit
		}
	}

	return products
}

func (aa ApiAiOrder) Products() []Item {
	return aa.ExtractProducts("products")
}

func (aa ApiAiOrder) Quantities() []Item {
	return aa.ExtractQuantities("quantity")
}

func (aa ApiAiOrder) GiftItems() []Item {
	gifts := aa.GiftProducts()
	quantities := aa.GiftQuantities()

	for i, q := range quantities {
		if len(gifts) >= i+1 {
			gifts[i].Quantity = q.Quantity
			products[i].Unit = q.Unit
		}
	}

	return gifts
}

func (aa ApiAiOrder) GiftProducts() []Item {
	return aa.ExtractProducts("gifts")
}

func (aa ApiAiOrder) GiftQuantities() []Item {
	return aa.ExtractQuantities("giftNumber")
}

func (aa ApiAiOrder) Address() string {
	if a, exist := aa.AiResult.Params["street-address"]; exist {

		rt := reflect.TypeOf(a)
		vals := reflect.ValueOf(a)

		switch rt.Kind() {
		case reflect.Slice:
			if vals.Len() > 0 {
				return vals.Index(0).Interface().(string)
			}
		case reflect.Array:
			if vals.Len() > 0 {
				return vals.Index(0).Interface().(string)
			}
		case reflect.String:
			return vals.Interface().(string)
		}
	}

	return ""
}

func (aa ApiAiOrder) Customer() string {
	if c, exist := aa.AiResult.Params["customer"]; exist {

		rt := reflect.TypeOf(c)
		vals := reflect.ValueOf(c)

		switch rt.Kind() {
		case reflect.Slice:
			if vals.Len() > 0 {
				return vals.Index(0).Interface().(string)
			}
		case reflect.Array:
			if vals.Len() > 0 {
				return vals.Index(0).Interface().(string)
			}
		case reflect.String:
			return vals.Interface().(string)
		}
	}

	return ""
}

func (aa ApiAiOrder) Time() time.Time {
	if t, exist := aa.AiResult.Params["date"]; exist {
		if aiTime, err := time.Parse("2006-01-02", t.(string)); err == nil {
			return aiTime
		}
	}

	return time.Time{}
}

func (aa ApiAiOrder) Fulfiled() bool {
	return true
}

func (aa ApiAiOrder) Note() string {
	if imp, exist := aa.AiResult.Params["important"]; exist {
		return imp.(string)
	}

	return ""
}

func (aa ApiAiOrder) ExtractProducts(t string) []Item {
	result := make([]Item, 0, 50)

	if products, exist := aa.AiResult.Params[t]; exist {
		ps := reflect.ValueOf(products)

		for i := 0; i < ps.Len(); i++ {
			p := ps.Index(i)
			name := p.Interface().(string)
			item := Item{Product: name}
			result = append(result, item)
		}
	}

	return result
}

func (aa ApiAiOrder) ExtractQuantities(t string) []Item {
	result := make([]Item, 0, 50)

	if quantities, exist := aa.AiResult.Params[t]; exist {
		qs := reflect.ValueOf(quantities)

		for i := 0; i < qs.Len(); i++ {
			q := qs.Index(i).Interface()

			switch t := q.(type) {
			case string:
				qs := q.(string)
				qi := extractQuantity(qs)
				item := Item{Quantity: qi}
				result = append(result, item)
			case float64:
				qf := q.(float64)
				item := Item{Quantity: int(qf)}
				result = append(result, item)
			case map[string]interface{}:
				log.Printf("....... quantity .........")
				qf := t["number"].(float64)
				quantity := int(qf)
				unit := t["unit"].(string)
				item := Item{Quantity: quantity, Unit: unit}
				result = append(result, item)
			default:
				log.Println("Unknown Quantity type: %v", t)
			}
		}
	}

	return result
}

func extractQuantity(s string) int {
	nums := strings.TrimFunc(s, TrimToNum)
	numsCgd := DBCtoSBC(nums)

	if len(numsCgd) > 0 {
		q, _ := strconv.Atoi(numsCgd)
		return q
	} else {
		return 0
	}
	// re := regexp.MustCompile("[0-9]+")
}

func TrimToNum(r rune) bool {
	if n := r - '0'; n >= 0 && n <= 9 {
		return false
	} else if m := r - '０'; m >= 0 && m <= 9 {
		return false
	}

	return true
}

func DBCtoSBC(s string) string {
	retstr := ""
	for _, i := range s {
		inside_code := i
		if inside_code == 12288 {
			inside_code = 32
		} else {
			inside_code -= 65248
		}
		if inside_code < 32 || inside_code > 126 {
			retstr += string(i)
		} else {
			retstr += string(inside_code)
		}
	}
	return retstr
}
<|endoftext|>


<commit_before>package state

import (
	"log"
	"os"

	"gopkg.in/fsnotify.v1"
)

type Watch struct{}

func (w Watch) Run(sm *StateMachine) {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}
	defer watcher.Close()

	err = watcher.Add(sm.Options.Dir)
	if err != nil {
		log.Fatal(err)
	}

	for {
		select {
		case event := <-watcher.Events:
			log.Println("Watch event: ", event.Op, event.Name)
			switch event.Op {
			case fsnotify.Create:
				info, err := os.Stat(event.Name)
				if err != nil {
					log.Println("Error stating file: ", event.Name, err)
				}
				sm.Add(&Create{Path: event.Name, Info: info})
			case fsnotify.Write:
			case fsnotify.Remove:
				sm.Add(&Remove{Path: event.Name})
			case fsnotify.Rename:
				log.Println("Rename file: ", event.Name)
			}
		case err := <-watcher.Errors:
			log.Println("Error watching directory:", err)
		}
	}
}
<commit_msg>Update watch to remove and create for modified files<commit_after>package state

import (
	"log"
	"os"

	"gopkg.in/fsnotify.v1"
)

type Watch struct{}

func (w Watch) Run(sm *StateMachine) {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}
	defer watcher.Close()

	err = watcher.Add(sm.Options.Dir)
	if err != nil {
		log.Fatal(err)
	}

	for {
		select {
		case event := <-watcher.Events:
			log.Println("Watch event: ", event.Op, event.Name)
			switch event.Op {
			case fsnotify.Create:
				info, err := os.Stat(event.Name)
				if err != nil {
					log.Println("Error stating file: ", event.Name, err)
				}
				sm.Add(&Create{Path: event.Name, Info: info})
			case fsnotify.Write:
				// TODO: This could be a race condition here
				sm.Add(&Remove{Path: event.Name})
				sm.Add(&Create{Path: event.Name})
			case fsnotify.Remove:
				sm.Add(&Remove{Path: event.Name})
			case fsnotify.Rename:
				// TODO: This could be a race condition here
				sm.Add(&Remove{Path: event.Name})
				sm.Add(&Create{Path: event.Name})
				log.Println("Rename file: ", event.Name)
			}
		case err := <-watcher.Errors:
			log.Println("Error watching directory:", err)
		}
	}
}
<|endoftext|>


<commit_before>package gmgmap

import (
	"math/rand"
)

type street struct {
	r          rect
	horizontal bool
	level      int
}

// NewBSPInterior - Create new BSP interior map
// Implementation of https://gamedev.stackexchange.com/questions/47917/procedural-house-with-rooms-generator/48216#48216
func NewBSPInterior(width, height, minRoomSize int) *Map {
	iterations := 4
	corridorWidth := 2
	corridorLevelDiffBlock := 1
	m := NewMap(width, height)

	// Split the map for a number of iterations, choosing alternating axis and random location
	var areas []bspRoom
	var streets []street
	hcount := rand.Intn(2)
	areas = append(areas, bspRoomRoot(width, height))
	for i := 0; i < len(areas); i++ {
		if areas[i].level == iterations {
			break
		}
		var r1, r2 bspRoom
		var err error = nil
		// Alternate splitting direction per level
		horizontal := ((hcount + areas[i].level) % 2) == 1
		if horizontal {
			r1, r2, err = bspSplitHorizontal(&areas[i], i, minRoomSize+corridorWidth/2)
		} else {
			r1, r2, err = bspSplitVertical(&areas[i], i, minRoomSize+corridorWidth/2)
		}
		if err == nil {
			// Resize rooms to allow space for street
			for j := 0; j < corridorWidth; j++ {
				if horizontal {
					if j%2 == 0 {
						r1.r.w--
					} else {
						r2.r.x++
						r2.r.w--
					}
				} else {
					if j%2 == 0 {
						r1.r.h--
					} else {
						r2.r.y++
						r2.r.h--
					}
				}
			}
			areas[i].child1 = len(areas)
			areas = append(areas, r1)
			areas[i].child2 = len(areas)
			areas = append(areas, r2)
			var s street
			if horizontal {
				s.r = rect{r1.r.x + r1.r.w, r1.r.y, corridorWidth, r1.r.h}
			} else {
				s.r = rect{r1.r.x, r1.r.y + r1.r.h, r1.r.w, corridorWidth}
			}
			s.level = r1.level
			s.horizontal = !horizontal
			streets = append(streets, s)
		}
	}

	g := m.Layer("Ground")
	s := m.Layer("Structures")
	// Turn the leaves into rooms
	for i := range areas {
		// Only place rooms in leaf nodes
		if areas[i].child1 >= 0 || areas[i].child2 >= 0 {
			continue
		}
		var r rect
		r.w = areas[i].r.w
		r.x = areas[i].r.x
		r.h = areas[i].r.h
		r.y = areas[i].r.y
		g.rectangleFilled(rect{r.x + 1, r.y + 1, r.w - 2, r.h - 2}, room)
		s.rectangleUnfilled(r, wall2)
	}
	// Fill streets
	for i := range streets {
		g.rectangleFilled(streets[i].r, room2)
		// Check ends of street - if next to much older street, block off with wall
		end1 := vec2{streets[i].r.x, streets[i].r.y}
		end2 := vec2{streets[i].r.x + streets[i].r.w - 1, streets[i].r.y + streets[i].r.h - 1}
		var dAlong, dAcross vec2
		if streets[i].horizontal {
			dAlong = vec2{1, 0}
			dAcross = vec2{0, 1}
		} else {
			dAlong = vec2{0, 1}
			dAcross = vec2{1, 0}
		}
		capStreet(g, s, streets, streets[i], end1, dAcross, dAlong, corridorWidth, corridorLevelDiffBlock)
		capStreet(g, s, streets, streets[i], end2, vec2{-dAcross.x, -dAcross.y}, vec2{-dAlong.x, -dAlong.y}, corridorWidth, corridorLevelDiffBlock)

		// Place stairs at one end of first (main) street and last street
		if i == 0 {
			s.setTile(streets[i].r.x+dAlong.x, streets[i].r.y+dAlong.y, stairsUp)
		} else if i == len(streets)-1 {
			s.setTile(streets[i].r.x+dAlong.x, streets[i].r.y+dAlong.y, stairsDown)
		}
	}

	return m
}

func capStreet(g, s *Layer, streets []street, st street, end, dAcross, dAlong vec2, corridorWidth, corridorLevelDiffBlock int) {
	// Check ends of street - if outside map, or next to much older street, block off with wall
	outside := vec2{end.x - dAlong.x, end.y - dAlong.y}
	doCap := false
	if !g.isIn(outside.x, outside.y) {
		doCap = true
	} else {
		for i := range streets {
			if streets[i].r.isIn(outside.x, outside.y) && st.level-streets[i].level > corridorLevelDiffBlock {
				doCap = true
				break
			}
		}
	}
	if doCap {
		for i := 0; i < corridorWidth; i++ {
			g.setTile(end.x+dAcross.x*i, end.y+dAcross.y*i, nothing)
			s.setTile(end.x+dAcross.x*i, end.y+dAcross.y*i, wall2)
		}
	}
}
<commit_msg>Doors<commit_after>package gmgmap

import (
	"math/rand"
)

type street struct {
	r          rect
	horizontal bool
	level      int
}

// NewBSPInterior - Create new BSP interior map
// Implementation of https://gamedev.stackexchange.com/questions/47917/procedural-house-with-rooms-generator/48216#48216
func NewBSPInterior(width, height, minRoomSize int) *Map {
	iterations := 4
	corridorWidth := 2
	corridorLevelDiffBlock := 1
	m := NewMap(width, height)

	// Split the map for a number of iterations, choosing alternating axis and random location
	var areas []bspRoom
	var streets []street
	hcount := rand.Intn(2)
	areas = append(areas, bspRoomRoot(width, height))
	for i := 0; i < len(areas); i++ {
		if areas[i].level == iterations {
			break
		}
		var r1, r2 bspRoom
		var err error = nil
		// Alternate splitting direction per level
		horizontal := ((hcount + areas[i].level) % 2) == 1
		if horizontal {
			r1, r2, err = bspSplitHorizontal(&areas[i], i, minRoomSize+corridorWidth/2)
		} else {
			r1, r2, err = bspSplitVertical(&areas[i], i, minRoomSize+corridorWidth/2)
		}
		if err == nil {
			// Resize rooms to allow space for street
			for j := 0; j < corridorWidth; j++ {
				if horizontal {
					if j%2 == 0 {
						r1.r.w--
					} else {
						r2.r.x++
						r2.r.w--
					}
				} else {
					if j%2 == 0 {
						r1.r.h--
					} else {
						r2.r.y++
						r2.r.h--
					}
				}
			}
			areas[i].child1 = len(areas)
			areas = append(areas, r1)
			areas[i].child2 = len(areas)
			areas = append(areas, r2)
			var s street
			if horizontal {
				s.r = rect{r1.r.x + r1.r.w, r1.r.y, corridorWidth, r1.r.h}
			} else {
				s.r = rect{r1.r.x, r1.r.y + r1.r.h, r1.r.w, corridorWidth}
			}
			s.level = r1.level
			s.horizontal = !horizontal
			streets = append(streets, s)
		}
	}

	g := m.Layer("Ground")
	s := m.Layer("Structures")
	// Turn the leaves into rooms
	for i := range areas {
		// Only place rooms in leaf nodes
		if areas[i].child1 >= 0 || areas[i].child2 >= 0 {
			continue
		}
		var r rect
		r.w = areas[i].r.w
		r.x = areas[i].r.x
		r.h = areas[i].r.h
		r.y = areas[i].r.y
		g.rectangleFilled(rect{r.x + 1, r.y + 1, r.w - 2, r.h - 2}, room)
		s.rectangleUnfilled(r, wall2)
		// Add doors leading to hallways
		for j := 0; j < 4; j++ {
			doorPos := vec2{areas[i].r.x + areas[i].r.w/2, areas[i].r.y + areas[i].r.h/2}
			var outsideDoor vec2
			if j == 0 {
				// top
				doorPos.y = areas[i].r.y
				outsideDoor = vec2{doorPos.x, doorPos.y - 1}
			} else if j == 1 {
				// right
				doorPos.x = areas[i].r.x + areas[i].r.w - 1
				outsideDoor = vec2{doorPos.x + 1, doorPos.y}
			} else if j == 2 {
				// bottom
				doorPos.y = areas[i].r.y + areas[i].r.h - 1
				outsideDoor = vec2{doorPos.x, doorPos.y + 1}
			} else {
				// left
				doorPos.x = areas[i].r.x
				outsideDoor = vec2{doorPos.x - 1, doorPos.y}
			}
			for i := range streets {
				if streets[i].r.isIn(outsideDoor.x, outsideDoor.y) {
					g.setTile(doorPos.x, doorPos.y, room)
					s.setTile(doorPos.x, doorPos.y, door)
					break
				}
			}
		}
	}
	// Fill streets
	for i := range streets {
		g.rectangleFilled(streets[i].r, room2)
		// Check ends of street - if next to much older street, block off with wall
		end1 := vec2{streets[i].r.x, streets[i].r.y}
		end2 := vec2{streets[i].r.x + streets[i].r.w - 1, streets[i].r.y + streets[i].r.h - 1}
		var dAlong, dAcross vec2
		if streets[i].horizontal {
			dAlong = vec2{1, 0}
			dAcross = vec2{0, 1}
		} else {
			dAlong = vec2{0, 1}
			dAcross = vec2{1, 0}
		}
		capStreet(g, s, streets, streets[i], end1, dAcross, dAlong, corridorWidth, corridorLevelDiffBlock)
		capStreet(g, s, streets, streets[i], end2, vec2{-dAcross.x, -dAcross.y}, vec2{-dAlong.x, -dAlong.y}, corridorWidth, corridorLevelDiffBlock)

		// Place stairs at one end of first (main) street and last street
		if i == 0 {
			s.setTile(streets[i].r.x+dAlong.x, streets[i].r.y+dAlong.y, stairsUp)
		} else if i == len(streets)-1 {
			s.setTile(streets[i].r.x+dAlong.x, streets[i].r.y+dAlong.y, stairsDown)
		}
	}

	return m
}

func capStreet(g, s *Layer, streets []street, st street, end, dAcross, dAlong vec2, corridorWidth, corridorLevelDiffBlock int) {
	// Check ends of street - if outside map, or next to much older street, block off with wall
	outside := vec2{end.x - dAlong.x, end.y - dAlong.y}
	doCap := false
	if !g.isIn(outside.x, outside.y) {
		doCap = true
	} else {
		for i := range streets {
			if streets[i].r.isIn(outside.x, outside.y) && st.level-streets[i].level > corridorLevelDiffBlock {
				doCap = true
				break
			}
		}
	}
	if doCap {
		for i := 0; i < corridorWidth; i++ {
			g.setTile(end.x+dAcross.x*i, end.y+dAcross.y*i, nothing)
			s.setTile(end.x+dAcross.x*i, end.y+dAcross.y*i, wall2)
		}
	}
}
<|endoftext|>


<commit_before>package anagram

import (
	"reflect"
	"strings"
)

func Detect(subject string, candidates []string) (anagrams []string) {
	occurences := getOccurences(strings.ToLower(subject))
	for _, c := range candidates {
		candidate := getOccurences(strings.ToLower(c))
		if reflect.DeepEqual(occurences, candidate) && strings.ToLower(subject) != strings.ToLower(c) {
			anagrams = append(anagrams, c)
		}
	}
	return anagrams
}

func getOccurences(input string) (occurences map[rune]int) {
	occurences = map[rune]int{}
	for _, r := range input {
		occurences[r] += 1
	}
	return occurences
}
<commit_msg>Refact: prefer strings.EqualFold for case insensitivity<commit_after>package anagram

import (
	"reflect"
	"strings"
)

func Detect(subject string, candidates []string) (anagrams []string) {
	occurences := getOccurences(strings.ToLower(subject))
	for _, c := range candidates {
		candidate := getOccurences(strings.ToLower(c))
		if reflect.DeepEqual(occurences, candidate) && !strings.EqualFold(subject, c) {
			anagrams = append(anagrams, c)
		}
	}
	return anagrams
}

func getOccurences(input string) (occurences map[rune]int) {
	occurences = map[rune]int{}
	for _, r := range input {
		occurences[r] += 1
	}
	return occurences
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"strconv"

	"github.com/gorilla/mux"
)

// error response contains everything we need to use http.Error
type handlerError struct {
	Error   error
	Message string
	Code    int
}

// ticket model
type ticket struct {
	FirstName string `json:"firstname"`
	LastName string `json:"lastname"`
	SourceCity  string `json:"arrivecity"`
	DepartCity  string `json:"departcity"`
	FlightID  string `json:"flightid"`
	FlightDate string `json:"flightdate"`
	Id        int    `json:"id"`
	BackgroundArrive string `json:"backgroundarrive"`
	BackgroundDepart string `json:"backgrounddepart"`
}

// list of all of the tickets
var tickets = make([]ticket, 0)
var selected_ticket_id = 0;

// a custom type that we can use for handling errors and formatting responses
type handler func(w http.ResponseWriter, r *http.Request) (interface{}, *handlerError)

// attach the standard ServeHTTP method to our handler so the http library can call it
func (fn handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// here we could do some prep work before calling the handler if we wanted to

	// call the actual handler
	response, err := fn(w, r)

	// check for errors
	if err != nil {
		log.Printf("ERROR: %v\n", err.Error)
		http.Error(w, fmt.Sprintf(`{"error":"%s"}`, err.Message), err.Code)
		return
	}
	if response == nil {
		log.Printf("ERROR: response from method is nil\n")
		http.Error(w, "Internal server error. Check the logs.", http.StatusInternalServerError)
		return
	}

	// turn the response into JSON
	bytes, e := json.Marshal(response)
	if e != nil {
		http.Error(w, "Error marshalling JSON", http.StatusInternalServerError)
		return
	}

	// send the response and log
	w.Header().Set("Content-Type", "application/json")
	w.Write(bytes)
	log.Printf("%s %s %s %d", r.RemoteAddr, r.Method, r.URL, 200)
}

func listTickets(w http.ResponseWriter, r *http.Request) (interface{}, *handlerError) {
	return tickets, nil
}

func getTicketID(w http.ResponseWriter, r *http.Request) (interface{}, *handlerError) {
	return selected_ticket_id, nil;
}

func getTickets(w http.ResponseWriter, r *http.Request) (interface{}, *handlerError) {
	// mux.Vars grabs variables from the path
	param := mux.Vars(r)["id"]
	id, e := strconv.Atoi(param)
	if e != nil {
		return nil, &handlerError{e, "Id should be an integer", http.StatusBadRequest}
	}
	b, index := getTicketById(id)

	if index < 0 {
		return nil, &handlerError{nil, "Could not find ticket " + param, http.StatusNotFound}
	}

	return b, nil
}

func parseTicketRequest(r *http.Request) (ticket, *handlerError) {
	// the ticket payload is in the request body
	data, e := ioutil.ReadAll(r.Body)
	if e != nil {
		return ticket{}, &handlerError{e, "Could not read request", http.StatusBadRequest}
	}

	// turn the request body (JSON) into a ticket object
	var payload ticket
	e = json.Unmarshal(data, &payload)
	if e != nil {
		return ticket{}, &handlerError{e, "Could not parse JSON", http.StatusBadRequest}
	}

	return payload, nil
}

func addTicket(w http.ResponseWriter, r *http.Request) (interface{}, *handlerError) {
	payload, e := parseTicketRequest(r)
	if e != nil {
		return nil, e
	}

	// it's our job to assign IDs, ignore what (if anything) the client sent
	payload.Id = getNextId()
	tickets = append(tickets, payload)

	// we return the ticket we just made so the client can see the ID if they want
	return payload, nil
}

func updateTicket(w http.ResponseWriter, r *http.Request) (interface{}, *handlerError) {
	payload, e := parseTicketRequest(r)
	if e != nil {
		return nil, e
	}

	_, index := getTicketById(payload.Id)
	tickets[index] = payload
	return make(map[string]string), nil
}

func removeTicket(w http.ResponseWriter, r *http.Request) (interface{}, *handlerError) {
	param := mux.Vars(r)["id"]
	id, e := strconv.Atoi(param)
	if e != nil {
		return nil, &handlerError{e, "Id should be an integer", http.StatusBadRequest}
	}
	// this is jsut to check to see if the ticket exists
	_, index := getTicketById(id)

	if index < 0 {
		return nil, &handlerError{nil, "Could not find entry " + param, http.StatusNotFound}
	}

	// remove a ticket from the list
	tickets = append(tickets[:index], tickets[index+1:]...)
	return make(map[string]string), nil
}

// searches the tickets for the ticket with `id` and returns the ticket and it's index, or -1 for 404
func getTicketById(id int) (ticket, int) {
	for i, b := range tickets {
		if b.Id == id {
			return b, i
		}
	}
	return ticket{}, -1
}

var id = 0

// increments id and returns the value
func getNextId() int {
	id += 1
	return id
}

func main() {
	// command line flags
	port := flag.Int("port", 80, "port to serve on")
	dir := flag.String("directory", "web/", "directory of web files")
	flag.Parse()

	// handle all requests by serving a file of the same name
	fs := http.Dir(*dir)
	fileHandler := http.FileServer(fs)

	// setup routes
	router := mux.NewRouter()
	router.Handle("/", http.RedirectHandler("/static/", 302))
	router.Handle("/tickets", handler(listTickets)).Methods("GET")
	router.Handle("/tickets", handler(addTicket)).Methods("POST")
	router.Handle("/selected_ticket_id", handler(getTicketID)).Methods("GET")
	router.Handle("/tickets/{id}", handler(getTickets)).Methods("GET")
	router.Handle("/tickets/{id}", handler(updateTicket)).Methods("POST")
	router.Handle("/tickets/{id}", handler(removeTicket)).Methods("DELETE")
	router.PathPrefix("/static/").Handler(http.StripPrefix("/static", fileHandler))
	http.Handle("/", router)

	// bootstrap some data
	tickets = append(tickets, ticket{"Nathan", "Acosta", "Albuquerque, NM", "Dallas, TX", "NMA4601", "12/4/2015", getNextId(), "./images/alb_flight_img.png", "./images/dal_flight_img.png"})
	tickets = append(tickets, ticket{"Nathan", "Acosta", "Dallas, TX", "Albuquerque, NM", "NMA4603", "12/5/2015", getNextId(), "./images/dal_flight_img.png", "./images/alb_flight_img.png"})
	tickets = append(tickets, ticket{"Nathan", "Acosta", "Albuquerque, NM", "Dallas, TX", "NMA4602", "12/8/2015", getNextId(), "./images/alb_flight_img.png", "./images/dal_flight_img.png"})

	log.Printf("Running on port %d\n", *port)

	addr := fmt.Sprintf("127.0.0.1:%d", *port)
	// this call blocks -- the progam runs here forever
	err := http.ListenAndServe(addr, nil)
	fmt.Println(err.Error())
}
<commit_msg>bind to all local IP's by default instead of just 127.0.0.1<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"strconv"

	"github.com/gorilla/mux"
)

// error response contains everything we need to use http.Error
type handlerError struct {
	Error   error
	Message string
	Code    int
}

// ticket model
type ticket struct {
	FirstName string `json:"firstname"`
	LastName string `json:"lastname"`
	SourceCity  string `json:"arrivecity"`
	DepartCity  string `json:"departcity"`
	FlightID  string `json:"flightid"`
	FlightDate string `json:"flightdate"`
	Id        int    `json:"id"`
	BackgroundArrive string `json:"backgroundarrive"`
	BackgroundDepart string `json:"backgrounddepart"`
}

// list of all of the tickets
var tickets = make([]ticket, 0)
var selected_ticket_id = 0;

// a custom type that we can use for handling errors and formatting responses
type handler func(w http.ResponseWriter, r *http.Request) (interface{}, *handlerError)

// attach the standard ServeHTTP method to our handler so the http library can call it
func (fn handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// here we could do some prep work before calling the handler if we wanted to

	// call the actual handler
	response, err := fn(w, r)

	// check for errors
	if err != nil {
		log.Printf("ERROR: %v\n", err.Error)
		http.Error(w, fmt.Sprintf(`{"error":"%s"}`, err.Message), err.Code)
		return
	}
	if response == nil {
		log.Printf("ERROR: response from method is nil\n")
		http.Error(w, "Internal server error. Check the logs.", http.StatusInternalServerError)
		return
	}

	// turn the response into JSON
	bytes, e := json.Marshal(response)
	if e != nil {
		http.Error(w, "Error marshalling JSON", http.StatusInternalServerError)
		return
	}

	// send the response and log
	w.Header().Set("Content-Type", "application/json")
	w.Write(bytes)
	log.Printf("%s %s %s %d", r.RemoteAddr, r.Method, r.URL, 200)
}

func listTickets(w http.ResponseWriter, r *http.Request) (interface{}, *handlerError) {
	return tickets, nil
}

func getTicketID(w http.ResponseWriter, r *http.Request) (interface{}, *handlerError) {
	return selected_ticket_id, nil;
}

func getTickets(w http.ResponseWriter, r *http.Request) (interface{}, *handlerError) {
	// mux.Vars grabs variables from the path
	param := mux.Vars(r)["id"]
	id, e := strconv.Atoi(param)
	if e != nil {
		return nil, &handlerError{e, "Id should be an integer", http.StatusBadRequest}
	}
	b, index := getTicketById(id)

	if index < 0 {
		return nil, &handlerError{nil, "Could not find ticket " + param, http.StatusNotFound}
	}

	return b, nil
}

func parseTicketRequest(r *http.Request) (ticket, *handlerError) {
	// the ticket payload is in the request body
	data, e := ioutil.ReadAll(r.Body)
	if e != nil {
		return ticket{}, &handlerError{e, "Could not read request", http.StatusBadRequest}
	}

	// turn the request body (JSON) into a ticket object
	var payload ticket
	e = json.Unmarshal(data, &payload)
	if e != nil {
		return ticket{}, &handlerError{e, "Could not parse JSON", http.StatusBadRequest}
	}

	return payload, nil
}

func addTicket(w http.ResponseWriter, r *http.Request) (interface{}, *handlerError) {
	payload, e := parseTicketRequest(r)
	if e != nil {
		return nil, e
	}

	// it's our job to assign IDs, ignore what (if anything) the client sent
	payload.Id = getNextId()
	tickets = append(tickets, payload)

	// we return the ticket we just made so the client can see the ID if they want
	return payload, nil
}

func updateTicket(w http.ResponseWriter, r *http.Request) (interface{}, *handlerError) {
	payload, e := parseTicketRequest(r)
	if e != nil {
		return nil, e
	}

	_, index := getTicketById(payload.Id)
	tickets[index] = payload
	return make(map[string]string), nil
}

func removeTicket(w http.ResponseWriter, r *http.Request) (interface{}, *handlerError) {
	param := mux.Vars(r)["id"]
	id, e := strconv.Atoi(param)
	if e != nil {
		return nil, &handlerError{e, "Id should be an integer", http.StatusBadRequest}
	}
	// this is jsut to check to see if the ticket exists
	_, index := getTicketById(id)

	if index < 0 {
		return nil, &handlerError{nil, "Could not find entry " + param, http.StatusNotFound}
	}

	// remove a ticket from the list
	tickets = append(tickets[:index], tickets[index+1:]...)
	return make(map[string]string), nil
}

// searches the tickets for the ticket with `id` and returns the ticket and it's index, or -1 for 404
func getTicketById(id int) (ticket, int) {
	for i, b := range tickets {
		if b.Id == id {
			return b, i
		}
	}
	return ticket{}, -1
}

var id = 0

// increments id and returns the value
func getNextId() int {
	id += 1
	return id
}

func main() {
	// command line flags
	port := flag.Int("port", 80, "port to serve on")
	dir := flag.String("directory", "web/", "directory of web files")
	flag.Parse()

	// handle all requests by serving a file of the same name
	fs := http.Dir(*dir)
	fileHandler := http.FileServer(fs)

	// setup routes
	router := mux.NewRouter()
	router.Handle("/", http.RedirectHandler("/static/", 302))
	router.Handle("/tickets", handler(listTickets)).Methods("GET")
	router.Handle("/tickets", handler(addTicket)).Methods("POST")
	router.Handle("/selected_ticket_id", handler(getTicketID)).Methods("GET")
	router.Handle("/tickets/{id}", handler(getTickets)).Methods("GET")
	router.Handle("/tickets/{id}", handler(updateTicket)).Methods("POST")
	router.Handle("/tickets/{id}", handler(removeTicket)).Methods("DELETE")
	router.PathPrefix("/static/").Handler(http.StripPrefix("/static", fileHandler))
	http.Handle("/", router)

	// bootstrap some data
	tickets = append(tickets, ticket{"Nathan", "Acosta", "Albuquerque, NM", "Dallas, TX", "NMA4601", "12/4/2015", getNextId(), "./images/alb_flight_img.png", "./images/dal_flight_img.png"})
	tickets = append(tickets, ticket{"Nathan", "Acosta", "Dallas, TX", "Albuquerque, NM", "NMA4603", "12/5/2015", getNextId(), "./images/dal_flight_img.png", "./images/alb_flight_img.png"})
	tickets = append(tickets, ticket{"Nathan", "Acosta", "Albuquerque, NM", "Dallas, TX", "NMA4602", "12/8/2015", getNextId(), "./images/alb_flight_img.png", "./images/dal_flight_img.png"})

	log.Printf("Running on port %d\n", *port)

	addr := fmt.Sprintf(":%d", *port)
	// this call blocks -- the progam runs here forever
	err := http.ListenAndServe(addr, nil)
	fmt.Println(err.Error())
}
<|endoftext|>


<commit_before>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package keybase1

import (
	"encoding/base64"
	"encoding/binary"
	"encoding/hex"
	"fmt"
	"strings"
	"time"

	jsonw "github.com/keybase/go-jsonw"
)

const (
	UID_LEN          = 16
	UID_SUFFIX       = 0x00
	UID_SUFFIX_2     = 0x19
	UID_SUFFIX_HEX   = "00"
	UID_SUFFIX_2_HEX = "19"
	PUBLIC_UID       = "ffffffffffffffffffffffffffffff00"
)

// UID for the special "public" user.
var PublicUID = UID(PUBLIC_UID)

const (
	SIG_ID_LEN         = 32
	SIG_ID_SUFFIX      = 0x0f
	SIG_SHORT_ID_BYTES = 27
	SigIDQueryMin      = 16
)

const (
	DeviceIDLen       = 16
	DeviceIDSuffix    = 0x18
	DeviceIDSuffixHex = "18"
)

const (
	KidLen     = 35   // bytes
	KidSuffix  = 0x0a // a byte
	KidVersion = 0x1
)

func Unquote(data []byte) string {
	return strings.Trim(string(data), "\"")
}

func Quote(s string) []byte {
	return []byte("\"" + s + "\"")
}

func KIDFromSlice(b []byte) KID {
	return KID(hex.EncodeToString(b))
}

func KIDFromStringChecked(s string) (KID, error) {

	// It's OK to have a 0-length KID. That means, no such key
	// (or NULL kid).
	if len(s) == 0 {
		return KID(""), nil
	}

	b, err := hex.DecodeString(s)
	if err != nil {
		return KID(""), err
	}

	if len(b) != KidLen {
		return KID(""), fmt.Errorf("KID wrong length; wanted %d but got %d bytes",
			KidLen, len(b))
	}
	if b[len(b)-1] != KidSuffix {
		return KID(""), fmt.Errorf("Bad KID suffix: got 0x%02x, wanted 0x%02x",
			b[len(b)-1], KidSuffix)
	}
	if b[0] != KidVersion {
		return KID(""), fmt.Errorf("Bad KID version; got 0x%02x but wanted 0x%02x",
			b[0], KidVersion)
	}
	return KID(s), nil
}

func KIDFromString(s string) KID {
	// there are no validations for KIDs (length, suffixes)
	return KID(s)
}

func (k KID) IsValid() bool {
	return len(k) > 0
}

func (k KID) String() string {
	return string(k)
}

func (k KID) IsNil() bool {
	return len(k) == 0
}

func (k KID) Exists() bool {
	return !k.IsNil()
}

func (k KID) Equal(v KID) bool {
	return k == v
}

func (k KID) NotEqual(v KID) bool {
	return !k.Equal(v)
}

func (k KID) Match(q string, exact bool) bool {
	if k.IsNil() {
		return false
	}

	if exact {
		return strings.ToLower(k.String()) == strings.ToLower(q)
	}

	if strings.HasPrefix(k.String(), strings.ToLower(q)) {
		return true
	}
	if strings.HasPrefix(k.ToShortIDString(), q) {
		return true
	}
	return false
}

func (k KID) ToBytes() []byte {
	b, err := hex.DecodeString(string(k))
	if err != nil {
		return nil
	}
	return b
}

func (k KID) GetKeyType() byte {
	raw := k.ToBytes()
	if len(raw) < 2 {
		return 0
	}
	return raw[1]
}

func (k KID) ToShortIDString() string {
	return encode(k.ToBytes()[0:12])
}

func (k KID) ToJsonw() *jsonw.Wrapper {
	if k.IsNil() {
		return jsonw.NewNil()
	}
	return jsonw.NewString(string(k))
}

func DeviceIDFromBytes(b [DeviceIDLen]byte) DeviceID {
	return DeviceID(hex.EncodeToString(b[:]))
}

func (d DeviceID) ToBytes(out []byte) error {
	tmp, err := hex.DecodeString(string(d))
	if err != nil {
		return err
	}
	if len(tmp) != DeviceIDLen {
		return fmt.Errorf("Bad device ID; wanted %d bytes but got %d", DeviceIDLen, len(tmp))
	}
	if len(out) != DeviceIDLen {
		return fmt.Errorf("Need to output to a slice with %d bytes", DeviceIDLen)
	}
	copy(out[:], tmp)
	return nil
}

func DeviceIDFromSlice(b []byte) (DeviceID, error) {
	if len(b) != DeviceIDLen {
		return "", fmt.Errorf("invalid byte slice for DeviceID: len == %d, expected %d", len(b), DeviceIDLen)
	}
	var x [DeviceIDLen]byte
	copy(x[:], b)
	return DeviceIDFromBytes(x), nil
}

func DeviceIDFromString(s string) (DeviceID, error) {
	if len(s) != hex.EncodedLen(DeviceIDLen) {
		return "", fmt.Errorf("Bad Device ID length: %d", len(s))
	}
	suffix := s[len(s)-2:]
	if suffix != DeviceIDSuffixHex {
		return "", fmt.Errorf("Bad suffix byte: %s", suffix)
	}
	return DeviceID(s), nil
}

func (d DeviceID) String() string {
	return string(d)
}

func (d DeviceID) IsNil() bool {
	return len(d) == 0
}

func (d DeviceID) Exists() bool {
	return !d.IsNil()
}

func (d DeviceID) Eq(d2 DeviceID) bool {
	return d.Eq(d2)
}

func UIDFromString(s string) (UID, error) {
	if len(s) != hex.EncodedLen(UID_LEN) {
		return "", fmt.Errorf("Bad UID '%s'; must be %d bytes long", s, UID_LEN)
	}
	suffix := s[len(s)-2:]
	if suffix != UID_SUFFIX_HEX && suffix != UID_SUFFIX_2_HEX {
		return "", fmt.Errorf("Bad UID '%s': must end in 0x%x or 0x%x", s, UID_SUFFIX, UID_SUFFIX_2)
	}
	return UID(s), nil
}

// Used by unit tests.
func MakeTestUID(n uint32) UID {
	b := make([]byte, 8)
	binary.LittleEndian.PutUint32(b, n)
	s := hex.EncodeToString(b)
	c := 2*UID_LEN - len(UID_SUFFIX_HEX) - len(s)
	s += strings.Repeat("0", c) + UID_SUFFIX_HEX
	uid, err := UIDFromString(s)
	if err != nil {
		panic(err)
	}
	return uid
}

func (u UID) String() string {
	return string(u)
}

func (u UID) ToBytes() []byte {
	b, err := hex.DecodeString(string(u))
	if err != nil {
		return nil
	}
	return b
}

func (u UID) IsNil() bool {
	return len(u) == 0
}

func (u UID) Exists() bool {
	return !u.IsNil()
}

func (u UID) Equal(v UID) bool {
	return u == v
}

func (u UID) NotEqual(v UID) bool {
	return !u.Equal(v)
}

func (u UID) Less(v UID) bool {
	return u < v
}

// Returns a number in [0, shardCount) which can be treated as roughly
// uniformly distributed. Used for things that need to shard by user.
func (u UID) GetShard(shardCount int) (int, error) {
	bytes, err := hex.DecodeString(string(u))
	if err != nil {
		return 0, err
	}
	n := binary.LittleEndian.Uint32(bytes)
	return int(n % uint32(shardCount)), nil
}

func (s SigID) IsNil() bool {
	return len(s) == 0
}

func (s SigID) Exists() bool {
	return !s.IsNil()
}

func (s SigID) Equal(t SigID) bool {
	return s == t
}

func (s SigID) Match(q string, exact bool) bool {
	if s.IsNil() {
		return false
	}

	if exact {
		return strings.ToLower(s.ToString(true)) == strings.ToLower(q)
	}

	if strings.HasPrefix(s.ToString(true), strings.ToLower(q)) {
		return true
	}

	return false
}

func (s SigID) NotEqual(t SigID) bool {
	return !s.Equal(t)
}

func (s SigID) ToDisplayString(verbose bool) string {
	if verbose {
		return string(s)
	}
	return fmt.Sprintf("%s...", s[0:SigIDQueryMin])
}

func (s SigID) ToString(suffix bool) string {
	if len(s) == 0 {
		return ""
	}
	if suffix {
		return string(s)
	}
	return string(s[0 : len(s)-2])
}

func SigIDFromString(s string, suffix bool) (SigID, error) {
	blen := SIG_ID_LEN
	if suffix {
		blen++
	}
	if len(s) != hex.EncodedLen(blen) {
		return "", fmt.Errorf("Invalid SigID string length: %d, expected %d (suffix = %v)", len(s), hex.EncodedLen(blen), suffix)
	}
	if suffix {
		return SigID(s), nil
	}
	return SigID(fmt.Sprintf("%s%02x", s, SIG_ID_SUFFIX)), nil
}

func SigIDFromBytes(b [SIG_ID_LEN]byte) SigID {
	s := hex.EncodeToString(b[:])
	return SigID(fmt.Sprintf("%s%02x", s, SIG_ID_SUFFIX))
}

func SigIDFromSlice(b []byte) (SigID, error) {
	if len(b) != SIG_ID_LEN {
		return "", fmt.Errorf("invalid byte slice for SigID: len == %d, expected %d", len(b), SIG_ID_LEN)
	}
	var x [SIG_ID_LEN]byte
	copy(x[:], b)
	return SigIDFromBytes(x), nil
}

func (s SigID) toBytes() []byte {
	b, err := hex.DecodeString(string(s))
	if err != nil {
		return nil
	}
	return b[0:SIG_ID_LEN]
}

func (s SigID) ToMediumID() string {
	return encode(s.toBytes())
}

func (s SigID) ToShortID() string {
	return encode(s.toBytes()[0:SIG_SHORT_ID_BYTES])
}

func encode(b []byte) string {
	return strings.TrimRight(base64.URLEncoding.EncodeToString(b), "=")
}

func FromTime(t Time) time.Time {
	return time.Unix(0, int64(t)*1000000)
}

func ToTime(t time.Time) Time {
	return Time(t.UnixNano() / 1000000)
}

func TimeFromSeconds(seconds int64) Time {
	return Time(seconds * 1000)
}

func (t Time) IsZero() bool        { return t == 0 }
func (t Time) After(t2 Time) bool  { return t > t2 }
func (t Time) Before(t2 Time) bool { return t < t2 }

func FormatTime(t Time) string {
	layout := "2006-01-02 15:04:05 MST"
	return FromTime(t).Format(layout)
}

func (s Status) Error() string {
	if s.Code == 0 {
		return ""
	}
	return fmt.Sprintf("%s (%s/%d)", s.Desc, s.Name, s.Code)
}

func (s InstallStatus) String() string {
	switch s {
	case InstallStatus_UNKNOWN:
		return "Unknown"
	case InstallStatus_ERROR:
		return "Error"
	case InstallStatus_NOT_INSTALLED:
		return "Not Installed"
	case InstallStatus_INSTALLED:
		return "Installed"
	}
	return ""
}

func (s InstallAction) String() string {
	switch s {
	case InstallAction_UNKNOWN:
		return "Unknown"
	case InstallAction_NONE:
		return "None"
	case InstallAction_UPGRADE:
		return "Upgrade"
	case InstallAction_REINSTALL:
		return "Re-Install"
	case InstallAction_INSTALL:
		return "Install"
	}
	return ""
}

func (s ServiceStatus) NeedsInstall() bool {
	return s.InstallAction == InstallAction_INSTALL ||
		s.InstallAction == InstallAction_REINSTALL ||
		s.InstallAction == InstallAction_UPGRADE
}

func (k *KID) UnmarshalJSON(b []byte) error {
	kid, err := KIDFromStringChecked(Unquote(b))
	if err != nil {
		return err
	}
	*k = KID(kid)
	return nil
}

func (k *KID) MarshalJSON() ([]byte, error) {
	return Quote(k.String()), nil
}

func (f Folder) ToString() string {
	prefix := "public/"
	if f.Private {
		prefix = "private/"
	}
	return prefix + f.Name
}

func (t TrackToken) String() string {
	return string(t)
}

func KIDFromRawKey(b []byte, keyType byte) KID {
	tmp := []byte{KidVersion, keyType}
	tmp = append(tmp, b...)
	tmp = append(tmp, byte(KidSuffix))
	return KIDFromSlice(tmp)
}

type APIStatus interface {
	Status() Status
}

type Error struct {
	code    StatusCode
	message string
}

func NewError(code StatusCode, message string) *Error {
	if code == StatusCode_SCOk {
		return nil
	}
	return &Error{code: code, message: message}
}

func FromError(err error) *Error {
	return &Error{code: StatusCode_SCGeneric, message: err.Error()}
}

func StatusOK() Status {
	return Status{Code: int(StatusCode_SCOk), Name: "OK", Desc: "OK"}
}

func StatusFromCode(code StatusCode, message string) Status {
	if code == StatusCode_SCOk {
		return StatusOK()
	}
	return NewError(code, message).Status()
}

func (e *Error) Error() string {
	return e.message
}

func (e *Error) Status() Status {
	return Status{Code: int(e.code), Name: "ERROR", Desc: e.message}
}
<commit_msg>Change SigIDQueryMin to 8 characters<commit_after>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package keybase1

import (
	"encoding/base64"
	"encoding/binary"
	"encoding/hex"
	"fmt"
	"strings"
	"time"

	jsonw "github.com/keybase/go-jsonw"
)

const (
	UID_LEN          = 16
	UID_SUFFIX       = 0x00
	UID_SUFFIX_2     = 0x19
	UID_SUFFIX_HEX   = "00"
	UID_SUFFIX_2_HEX = "19"
	PUBLIC_UID       = "ffffffffffffffffffffffffffffff00"
)

// UID for the special "public" user.
var PublicUID = UID(PUBLIC_UID)

const (
	SIG_ID_LEN         = 32
	SIG_ID_SUFFIX      = 0x0f
	SIG_SHORT_ID_BYTES = 27
	SigIDQueryMin      = 8
)

const (
	DeviceIDLen       = 16
	DeviceIDSuffix    = 0x18
	DeviceIDSuffixHex = "18"
)

const (
	KidLen     = 35   // bytes
	KidSuffix  = 0x0a // a byte
	KidVersion = 0x1
)

func Unquote(data []byte) string {
	return strings.Trim(string(data), "\"")
}

func Quote(s string) []byte {
	return []byte("\"" + s + "\"")
}

func KIDFromSlice(b []byte) KID {
	return KID(hex.EncodeToString(b))
}

func KIDFromStringChecked(s string) (KID, error) {

	// It's OK to have a 0-length KID. That means, no such key
	// (or NULL kid).
	if len(s) == 0 {
		return KID(""), nil
	}

	b, err := hex.DecodeString(s)
	if err != nil {
		return KID(""), err
	}

	if len(b) != KidLen {
		return KID(""), fmt.Errorf("KID wrong length; wanted %d but got %d bytes",
			KidLen, len(b))
	}
	if b[len(b)-1] != KidSuffix {
		return KID(""), fmt.Errorf("Bad KID suffix: got 0x%02x, wanted 0x%02x",
			b[len(b)-1], KidSuffix)
	}
	if b[0] != KidVersion {
		return KID(""), fmt.Errorf("Bad KID version; got 0x%02x but wanted 0x%02x",
			b[0], KidVersion)
	}
	return KID(s), nil
}

func KIDFromString(s string) KID {
	// there are no validations for KIDs (length, suffixes)
	return KID(s)
}

func (k KID) IsValid() bool {
	return len(k) > 0
}

func (k KID) String() string {
	return string(k)
}

func (k KID) IsNil() bool {
	return len(k) == 0
}

func (k KID) Exists() bool {
	return !k.IsNil()
}

func (k KID) Equal(v KID) bool {
	return k == v
}

func (k KID) NotEqual(v KID) bool {
	return !k.Equal(v)
}

func (k KID) Match(q string, exact bool) bool {
	if k.IsNil() {
		return false
	}

	if exact {
		return strings.ToLower(k.String()) == strings.ToLower(q)
	}

	if strings.HasPrefix(k.String(), strings.ToLower(q)) {
		return true
	}
	if strings.HasPrefix(k.ToShortIDString(), q) {
		return true
	}
	return false
}

func (k KID) ToBytes() []byte {
	b, err := hex.DecodeString(string(k))
	if err != nil {
		return nil
	}
	return b
}

func (k KID) GetKeyType() byte {
	raw := k.ToBytes()
	if len(raw) < 2 {
		return 0
	}
	return raw[1]
}

func (k KID) ToShortIDString() string {
	return encode(k.ToBytes()[0:12])
}

func (k KID) ToJsonw() *jsonw.Wrapper {
	if k.IsNil() {
		return jsonw.NewNil()
	}
	return jsonw.NewString(string(k))
}

func DeviceIDFromBytes(b [DeviceIDLen]byte) DeviceID {
	return DeviceID(hex.EncodeToString(b[:]))
}

func (d DeviceID) ToBytes(out []byte) error {
	tmp, err := hex.DecodeString(string(d))
	if err != nil {
		return err
	}
	if len(tmp) != DeviceIDLen {
		return fmt.Errorf("Bad device ID; wanted %d bytes but got %d", DeviceIDLen, len(tmp))
	}
	if len(out) != DeviceIDLen {
		return fmt.Errorf("Need to output to a slice with %d bytes", DeviceIDLen)
	}
	copy(out[:], tmp)
	return nil
}

func DeviceIDFromSlice(b []byte) (DeviceID, error) {
	if len(b) != DeviceIDLen {
		return "", fmt.Errorf("invalid byte slice for DeviceID: len == %d, expected %d", len(b), DeviceIDLen)
	}
	var x [DeviceIDLen]byte
	copy(x[:], b)
	return DeviceIDFromBytes(x), nil
}

func DeviceIDFromString(s string) (DeviceID, error) {
	if len(s) != hex.EncodedLen(DeviceIDLen) {
		return "", fmt.Errorf("Bad Device ID length: %d", len(s))
	}
	suffix := s[len(s)-2:]
	if suffix != DeviceIDSuffixHex {
		return "", fmt.Errorf("Bad suffix byte: %s", suffix)
	}
	return DeviceID(s), nil
}

func (d DeviceID) String() string {
	return string(d)
}

func (d DeviceID) IsNil() bool {
	return len(d) == 0
}

func (d DeviceID) Exists() bool {
	return !d.IsNil()
}

func (d DeviceID) Eq(d2 DeviceID) bool {
	return d.Eq(d2)
}

func UIDFromString(s string) (UID, error) {
	if len(s) != hex.EncodedLen(UID_LEN) {
		return "", fmt.Errorf("Bad UID '%s'; must be %d bytes long", s, UID_LEN)
	}
	suffix := s[len(s)-2:]
	if suffix != UID_SUFFIX_HEX && suffix != UID_SUFFIX_2_HEX {
		return "", fmt.Errorf("Bad UID '%s': must end in 0x%x or 0x%x", s, UID_SUFFIX, UID_SUFFIX_2)
	}
	return UID(s), nil
}

// Used by unit tests.
func MakeTestUID(n uint32) UID {
	b := make([]byte, 8)
	binary.LittleEndian.PutUint32(b, n)
	s := hex.EncodeToString(b)
	c := 2*UID_LEN - len(UID_SUFFIX_HEX) - len(s)
	s += strings.Repeat("0", c) + UID_SUFFIX_HEX
	uid, err := UIDFromString(s)
	if err != nil {
		panic(err)
	}
	return uid
}

func (u UID) String() string {
	return string(u)
}

func (u UID) ToBytes() []byte {
	b, err := hex.DecodeString(string(u))
	if err != nil {
		return nil
	}
	return b
}

func (u UID) IsNil() bool {
	return len(u) == 0
}

func (u UID) Exists() bool {
	return !u.IsNil()
}

func (u UID) Equal(v UID) bool {
	return u == v
}

func (u UID) NotEqual(v UID) bool {
	return !u.Equal(v)
}

func (u UID) Less(v UID) bool {
	return u < v
}

// Returns a number in [0, shardCount) which can be treated as roughly
// uniformly distributed. Used for things that need to shard by user.
func (u UID) GetShard(shardCount int) (int, error) {
	bytes, err := hex.DecodeString(string(u))
	if err != nil {
		return 0, err
	}
	n := binary.LittleEndian.Uint32(bytes)
	return int(n % uint32(shardCount)), nil
}

func (s SigID) IsNil() bool {
	return len(s) == 0
}

func (s SigID) Exists() bool {
	return !s.IsNil()
}

func (s SigID) Equal(t SigID) bool {
	return s == t
}

func (s SigID) Match(q string, exact bool) bool {
	if s.IsNil() {
		return false
	}

	if exact {
		return strings.ToLower(s.ToString(true)) == strings.ToLower(q)
	}

	if strings.HasPrefix(s.ToString(true), strings.ToLower(q)) {
		return true
	}

	return false
}

func (s SigID) NotEqual(t SigID) bool {
	return !s.Equal(t)
}

func (s SigID) ToDisplayString(verbose bool) string {
	if verbose {
		return string(s)
	}
	return fmt.Sprintf("%s...", s[0:SigIDQueryMin])
}

func (s SigID) ToString(suffix bool) string {
	if len(s) == 0 {
		return ""
	}
	if suffix {
		return string(s)
	}
	return string(s[0 : len(s)-2])
}

func SigIDFromString(s string, suffix bool) (SigID, error) {
	blen := SIG_ID_LEN
	if suffix {
		blen++
	}
	if len(s) != hex.EncodedLen(blen) {
		return "", fmt.Errorf("Invalid SigID string length: %d, expected %d (suffix = %v)", len(s), hex.EncodedLen(blen), suffix)
	}
	if suffix {
		return SigID(s), nil
	}
	return SigID(fmt.Sprintf("%s%02x", s, SIG_ID_SUFFIX)), nil
}

func SigIDFromBytes(b [SIG_ID_LEN]byte) SigID {
	s := hex.EncodeToString(b[:])
	return SigID(fmt.Sprintf("%s%02x", s, SIG_ID_SUFFIX))
}

func SigIDFromSlice(b []byte) (SigID, error) {
	if len(b) != SIG_ID_LEN {
		return "", fmt.Errorf("invalid byte slice for SigID: len == %d, expected %d", len(b), SIG_ID_LEN)
	}
	var x [SIG_ID_LEN]byte
	copy(x[:], b)
	return SigIDFromBytes(x), nil
}

func (s SigID) toBytes() []byte {
	b, err := hex.DecodeString(string(s))
	if err != nil {
		return nil
	}
	return b[0:SIG_ID_LEN]
}

func (s SigID) ToMediumID() string {
	return encode(s.toBytes())
}

func (s SigID) ToShortID() string {
	return encode(s.toBytes()[0:SIG_SHORT_ID_BYTES])
}

func encode(b []byte) string {
	return strings.TrimRight(base64.URLEncoding.EncodeToString(b), "=")
}

func FromTime(t Time) time.Time {
	return time.Unix(0, int64(t)*1000000)
}

func ToTime(t time.Time) Time {
	return Time(t.UnixNano() / 1000000)
}

func TimeFromSeconds(seconds int64) Time {
	return Time(seconds * 1000)
}

func (t Time) IsZero() bool        { return t == 0 }
func (t Time) After(t2 Time) bool  { return t > t2 }
func (t Time) Before(t2 Time) bool { return t < t2 }

func FormatTime(t Time) string {
	layout := "2006-01-02 15:04:05 MST"
	return FromTime(t).Format(layout)
}

func (s Status) Error() string {
	if s.Code == 0 {
		return ""
	}
	return fmt.Sprintf("%s (%s/%d)", s.Desc, s.Name, s.Code)
}

func (s InstallStatus) String() string {
	switch s {
	case InstallStatus_UNKNOWN:
		return "Unknown"
	case InstallStatus_ERROR:
		return "Error"
	case InstallStatus_NOT_INSTALLED:
		return "Not Installed"
	case InstallStatus_INSTALLED:
		return "Installed"
	}
	return ""
}

func (s InstallAction) String() string {
	switch s {
	case InstallAction_UNKNOWN:
		return "Unknown"
	case InstallAction_NONE:
		return "None"
	case InstallAction_UPGRADE:
		return "Upgrade"
	case InstallAction_REINSTALL:
		return "Re-Install"
	case InstallAction_INSTALL:
		return "Install"
	}
	return ""
}

func (s ServiceStatus) NeedsInstall() bool {
	return s.InstallAction == InstallAction_INSTALL ||
		s.InstallAction == InstallAction_REINSTALL ||
		s.InstallAction == InstallAction_UPGRADE
}

func (k *KID) UnmarshalJSON(b []byte) error {
	kid, err := KIDFromStringChecked(Unquote(b))
	if err != nil {
		return err
	}
	*k = KID(kid)
	return nil
}

func (k *KID) MarshalJSON() ([]byte, error) {
	return Quote(k.String()), nil
}

func (f Folder) ToString() string {
	prefix := "public/"
	if f.Private {
		prefix = "private/"
	}
	return prefix + f.Name
}

func (t TrackToken) String() string {
	return string(t)
}

func KIDFromRawKey(b []byte, keyType byte) KID {
	tmp := []byte{KidVersion, keyType}
	tmp = append(tmp, b...)
	tmp = append(tmp, byte(KidSuffix))
	return KIDFromSlice(tmp)
}

type APIStatus interface {
	Status() Status
}

type Error struct {
	code    StatusCode
	message string
}

func NewError(code StatusCode, message string) *Error {
	if code == StatusCode_SCOk {
		return nil
	}
	return &Error{code: code, message: message}
}

func FromError(err error) *Error {
	return &Error{code: StatusCode_SCGeneric, message: err.Error()}
}

func StatusOK() Status {
	return Status{Code: int(StatusCode_SCOk), Name: "OK", Desc: "OK"}
}

func StatusFromCode(code StatusCode, message string) Status {
	if code == StatusCode_SCOk {
		return StatusOK()
	}
	return NewError(code, message).Status()
}

func (e *Error) Error() string {
	return e.message
}

func (e *Error) Status() Status {
	return Status{Code: int(e.code), Name: "ERROR", Desc: e.message}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"os"
	"regexp"
	"sort"
	"strconv"
)

type Player struct {
	name string
	team string
	ppg  float64
}

func main() {
	players := make([]Player, 0)
	scanner := bufio.NewScanner(os.Stdin)
	re := regexp.MustCompile(`([^,]+),([^,]+),(\d+),(\d+)`)
	for scanner.Scan() {
		match := re.FindStringSubmatch(scanner.Text())
		games, _ := strconv.Atoi(match[3])
		points, _ := strconv.Atoi(match[4])
		if games >= 15 {
			ppg := float64(points) / float64(games)
			player := Player{match[2], match[1], ppg}
			players = append(players, player)
		}
	}
	sort.Slice(players, func(i, j int) bool {
		return players[i].ppg > players[j].ppg
	})
	for _, player := range players[:10] {
		format := "%-22s%-4s%8.2f\n"
		fmt.Printf(format, player.name, player.team, player.ppg)
	}
}
<commit_msg>Error handling for Go top ten scorers<commit_after>package main

import (
	"bufio"
	"fmt"
	"log"
	"os"
	"sort"
	"strconv"
	"strings"
)

type Player struct {
	name string
	team string
	ppg  float64
}

func main() {
	players := make([]Player, 0)
	scanner := bufio.NewScanner(os.Stdin)
	for scanner.Scan() {
		line := strings.Split(scanner.Text(), ",")
		if len(line) != 4 {
			log.Fatal("Malformed line")
		}
		games, err := strconv.Atoi(line[2])
		if err != nil {
			log.Fatal("Games value is malformed or out of range")
		}
		points, err := strconv.Atoi(line[3])
		if err != nil {
			log.Fatal("Points value is malformed or out of range")
		}
		if games >= 15 {
			ppg := float64(points) / float64(games)
			player := Player{line[1], line[0], ppg}
			players = append(players, player)
		}
	}
	sort.Slice(players, func(i, j int) bool {
		return players[i].ppg > players[j].ppg
	})
	for _, player := range players[:10] {
		format := "%-22s%-4s%8.2f\n"
		fmt.Printf(format, player.name, player.team, player.ppg)
	}
}
<|endoftext|>


<commit_before>// package goarmorlogs by chi example
// <https://github.com/pressly/chi/blob/master/_examples/logging/main.go>
package goarmorlogs

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

	"github.com/go-chi/chi/middleware"
	"github.com/sirupsen/logrus"
)

func NewStructuredLogger(logger *logrus.Logger) func(next http.Handler) http.Handler {
	return middleware.RequestLogger(&StructuredLogger{logger})
}

type StructuredLogger struct {
	Logger *logrus.Logger `json:"logger"`
}

func (l *StructuredLogger) NewLogEntry(r *http.Request) middleware.LogEntry {
	entry := &StructuredLoggerEntry{Logger: logrus.NewEntry(l.Logger)}
	logFields := logrus.Fields{}

	logFields["ts"] = time.Now().UTC().Format(time.RFC1123)

	if reqID := middleware.GetReqID(r.Context()); reqID != "" {
		logFields["reqID"] = reqID
	}

	scheme := "http"
	if r.TLS != nil {
		scheme = "https"
	}
	logFields["httpScheme"] = scheme
	logFields["httpProto"] = r.Proto
	logFields["httpMethod"] = r.Method

	logFields["remoteAddr"] = r.RemoteAddr
	logFields["userAgent"] = r.UserAgent()

	logFields["uri"] = fmt.Sprintf("%s://%s%s", scheme, r.Host, r.RequestURI)

	entry.Logger = entry.Logger.WithFields(logFields)

	entry.Logger.Debugln("request started")

	return entry
}

type StructuredLoggerEntry struct {
	Logger logrus.FieldLogger `json:"logger"`
}

func (l *StructuredLoggerEntry) Write(status, bytes int, elapsed time.Duration) {
	l.Logger = l.Logger.WithFields(logrus.Fields{
		"respStatus":      status,
		"respBytesLength": bytes,
		"respElaspedMs":   float64(elapsed.Nanoseconds()) / 1000000.0,
	})

	l.Logger.Debugln("request complete")
}

func (l *StructuredLoggerEntry) Panic(v interface{}, stack []byte) {
	l.Logger = l.Logger.WithFields(logrus.Fields{
		"stack": string(stack),
		"panic": fmt.Sprintf("%+v", v),
	})
}

// Helper methods used by the application to get the request-scoped
// logger entry and set additional fields between handlers.
//
// This is a useful pattern to use to set state on the entry as it
// passes through the handler chain, which at any point can be logged
// with a call to .Print(), .Info(), etc.

func GetLogEntry(r *http.Request) logrus.FieldLogger {
	entry, _ := middleware.GetLogEntry(r).(*StructuredLoggerEntry)
	return entry.Logger
}

func LogEntrySetField(r *http.Request, key string, value interface{}) {
	if entry, ok := r.Context().Value(middleware.LogEntryCtxKey).(*StructuredLoggerEntry); ok {
		entry.Logger = entry.Logger.WithField(key, value)
	}
}

func LogEntrySetFields(r *http.Request, fields map[string]interface{}) {
	if entry, ok := r.Context().Value(middleware.LogEntryCtxKey).(*StructuredLoggerEntry); ok {
		entry.Logger = entry.Logger.WithFields(fields)
	}
}
<commit_msg>minor<commit_after>// Package goarmorlogs by chi example
// <https://github.com/pressly/chi/blob/master/_examples/logging/main.go>
package goarmorlogs

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

	"github.com/go-chi/chi/middleware"
	"github.com/sirupsen/logrus"
)

func NewStructuredLogger(logger *logrus.Logger) func(next http.Handler) http.Handler {
	return middleware.RequestLogger(&StructuredLogger{logger})
}

type StructuredLogger struct {
	Logger *logrus.Logger `json:"logger"`
}

func (l *StructuredLogger) NewLogEntry(r *http.Request) middleware.LogEntry {
	entry := &StructuredLoggerEntry{Logger: logrus.NewEntry(l.Logger)}
	logFields := logrus.Fields{}

	logFields["ts"] = time.Now().UTC().Format(time.RFC1123)

	if reqID := middleware.GetReqID(r.Context()); reqID != "" {
		logFields["reqID"] = reqID
	}

	scheme := "http"
	if r.TLS != nil {
		scheme = "https"
	}
	logFields["httpScheme"] = scheme
	logFields["httpProto"] = r.Proto
	logFields["httpMethod"] = r.Method

	logFields["remoteAddr"] = r.RemoteAddr
	logFields["userAgent"] = r.UserAgent()

	logFields["uri"] = fmt.Sprintf("%s://%s%s", scheme, r.Host, r.RequestURI)

	entry.Logger = entry.Logger.WithFields(logFields)

	entry.Logger.Debugln("request started")

	return entry
}

type StructuredLoggerEntry struct {
	Logger logrus.FieldLogger `json:"logger"`
}

func (l *StructuredLoggerEntry) Write(status, bytes int, elapsed time.Duration) {
	l.Logger = l.Logger.WithFields(logrus.Fields{
		"respStatus":      status,
		"respBytesLength": bytes,
		"respElaspedMs":   float64(elapsed.Nanoseconds()) / 1000000.0,
	})

	l.Logger.Debugln("request complete")
}

func (l *StructuredLoggerEntry) Panic(v interface{}, stack []byte) {
	l.Logger = l.Logger.WithFields(logrus.Fields{
		"stack": string(stack),
		"panic": fmt.Sprintf("%+v", v),
	})
}

// Helper methods used by the application to get the request-scoped
// logger entry and set additional fields between handlers.
//
// This is a useful pattern to use to set state on the entry as it
// passes through the handler chain, which at any point can be logged
// with a call to .Print(), .Info(), etc.

func GetLogEntry(r *http.Request) logrus.FieldLogger {
	entry, _ := middleware.GetLogEntry(r).(*StructuredLoggerEntry)
	return entry.Logger
}

func LogEntrySetField(r *http.Request, key string, value interface{}) {
	if entry, ok := r.Context().Value(middleware.LogEntryCtxKey).(*StructuredLoggerEntry); ok {
		entry.Logger = entry.Logger.WithField(key, value)
	}
}

func LogEntrySetFields(r *http.Request, fields map[string]interface{}) {
	if entry, ok := r.Context().Value(middleware.LogEntryCtxKey).(*StructuredLoggerEntry); ok {
		entry.Logger = entry.Logger.WithFields(fields)
	}
}
<|endoftext|>