<commit_before>package restserver

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"path/filepath"

	"github.com/gorilla/handlers"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/restic/rest-server/quota"
)

const (
	GiB = 1024 * 1024 * 1024
)

func (s *Server) debugHandler(next http.Handler) http.Handler {
	return http.HandlerFunc(
		func(w http.ResponseWriter, r *http.Request) {
			log.Printf("%s %s", r.Method, r.URL)
			next.ServeHTTP(w, r)
		})
}

func (s *Server) logHandler(next http.Handler) http.Handler {
	accessLog, err := os.OpenFile(s.Log, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
	if err != nil {
		log.Fatalf("error: %v", err)
	}

	return handlers.CombinedLoggingHandler(accessLog, next)
}

func (s *Server) checkAuth(r *http.Request) (username string, ok bool) {
	if s.NoAuth {
		return username, true
	}
	var password string
	username, password, ok = r.BasicAuth()
	if !ok || !s.htpasswdFile.Validate(username, password) {
		return "", false
	}
	return username, true
}

// NewHandler returns the master HTTP multiplexer/router.
func NewHandler(server *Server) (http.Handler, error) {
	if !server.NoAuth {
		var err error
		server.htpasswdFile, err = NewHtpasswdFromFile(filepath.Join(server.Path, ".htpasswd"))
		if err != nil {
			return nil, fmt.Errorf("cannot load .htpasswd (use --no-auth to disable): %v", err)
		}
	}

	if server.MaxRepoSize > 0 {
		log.Printf("Initializing quota (can take a while)...")
		qm, err := quota.New(server.Path, server.MaxRepoSize)
		if err != nil {
			return nil, err
		}
		server.quotaManager = qm
		log.Printf("Quota initialized, currenly using %.2f GiB", float64(qm.SpaceUsed())/GiB)
	}

	mux := http.NewServeMux()
	if server.Prometheus {
		// FIXME: need auth like in previous version?
		mux.Handle("/metrics", promhttp.Handler())
	}
	mux.Handle("/", server)

	var handler http.Handler = mux
	if server.Debug {
		handler = server.debugHandler(handler)
	}
	if server.Log != "" {
		handler = server.logHandler(handler)
	}
	return handler, nil
}
<commit_msg>Fix typo in error message<commit_after>package restserver

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"path/filepath"

	"github.com/gorilla/handlers"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/restic/rest-server/quota"
)

const (
	GiB = 1024 * 1024 * 1024
)

func (s *Server) debugHandler(next http.Handler) http.Handler {
	return http.HandlerFunc(
		func(w http.ResponseWriter, r *http.Request) {
			log.Printf("%s %s", r.Method, r.URL)
			next.ServeHTTP(w, r)
		})
}

func (s *Server) logHandler(next http.Handler) http.Handler {
	accessLog, err := os.OpenFile(s.Log, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
	if err != nil {
		log.Fatalf("error: %v", err)
	}

	return handlers.CombinedLoggingHandler(accessLog, next)
}

func (s *Server) checkAuth(r *http.Request) (username string, ok bool) {
	if s.NoAuth {
		return username, true
	}
	var password string
	username, password, ok = r.BasicAuth()
	if !ok || !s.htpasswdFile.Validate(username, password) {
		return "", false
	}
	return username, true
}

// NewHandler returns the master HTTP multiplexer/router.
func NewHandler(server *Server) (http.Handler, error) {
	if !server.NoAuth {
		var err error
		server.htpasswdFile, err = NewHtpasswdFromFile(filepath.Join(server.Path, ".htpasswd"))
		if err != nil {
			return nil, fmt.Errorf("cannot load .htpasswd (use --no-auth to disable): %v", err)
		}
	}

	if server.MaxRepoSize > 0 {
		log.Printf("Initializing quota (can take a while)...")
		qm, err := quota.New(server.Path, server.MaxRepoSize)
		if err != nil {
			return nil, err
		}
		server.quotaManager = qm
		log.Printf("Quota initialized, currently using %.2f GiB", float64(qm.SpaceUsed())/GiB)
	}

	mux := http.NewServeMux()
	if server.Prometheus {
		// FIXME: need auth like in previous version?
		mux.Handle("/metrics", promhttp.Handler())
	}
	mux.Handle("/", server)

	var handler http.Handler = mux
	if server.Debug {
		handler = server.debugHandler(handler)
	}
	if server.Log != "" {
		handler = server.logHandler(handler)
	}
	return handler, nil
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/rand"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path"
	"path/filepath"
	"strings"
)

const (
	createDatabaseMigrationName = "Create-Database"
	createTablesMigrationName   = "Create-Tables"
)

// RunNew creates a new fragmenta project given the argument
// Usage: fragmenta new [app|cms|api| valid repo path e.g. github.com/fragmenta/fragmenta-cms]
func RunNew(args []string) {

	// Remove fragmenta backup from args list
	args = args[2:]

	// We expect two args left:
	if len(args) < 2 {
		log.Printf("Both a project path and a project type or URL are required to create a new site\n")
		return
	}

	repo := args[0]
	projectPath, err := filepath.Abs(args[1])
	if err != nil {
		log.Printf("Error expanding file path\n")
		return
	}

	if !strings.HasPrefix(projectPath, path.Join(os.Getenv("GOPATH"), "src")) {
		log.Printf("You must create your project in $GOPATH/src\n")
		return
	}

	if fileExists(projectPath) {
		log.Printf("A folder already exists at path %s\n", projectPath)
		return
	}

	switch repo {
	case "app":
		repo = "github.com/fragmenta/fragmenta-app"
	case "cms":
		repo = "github.com/fragmenta/fragmenta-cms"
	case "blog":
		repo = "github.com/fragmenta/fragmenta-blog"
	default:
		// TODO clean repo if it contains https or .git...
	}

	// Go get the project url, to make sure it is up to date, should use -u
	result, err := runCommand("go", "get", repo)
	if err != nil {
		log.Printf("Error calling go get %s", err)
		return
	}
	log.Printf("%s", string(result))

	// Copy the pristine new site over
	goProjectPath := path.Join(os.Getenv("GOPATH"), "src", repo)
	err = copyNewSite(goProjectPath, projectPath)
	if err != nil {
		log.Printf("Error copying project %s", err)
		return
	}

	// Generate config files
	err = generateConfig(projectPath)
	if err != nil {
		log.Printf("Error generating config %s", err)
		return
	}

	// Generate a migration AND run it
	err = generateCreateSQL(projectPath)
	if err != nil {
		log.Printf("Error generating migrations %s", err)
		return
	}

	// Output instructions to let them change setup first if they wish
	showNewSiteHelp(projectPath)

}

func copyNewSite(goProjectPath, projectPath string) error {

	// Now copy that over to a new project at projectPath - it should be in GOPATH/src/repo
	// Unfortunately there is no simple facility for this in golang stdlib, so we use unix command (sorry windows!)
	// FIXME - do not rely on unix commands

	result, err := runCommand("cp", "-r", goProjectPath, projectPath)
	if err != nil {
		log.Printf("Error copying site %s", err)
		return err
	}
	log.Printf("%s", string(result))

	// Delete the .git folder at that path
	gitPath := path.Join(projectPath, ".git")
	log.Printf("Removing all at:%s", gitPath)
	err = os.RemoveAll(gitPath)
	if err != nil {
		return err
	}

	// Run git init to get a new git repo here
	result, err = runCommand("git", "init", projectPath)
	if err != nil {
		return err
	}
	log.Printf("Initialising new git repo at:%s", projectPath)

	// Now reifyNewSite
	return reifyNewSite(goProjectPath, projectPath)
}

// reifyNewSite changes import refs within go files to the correct format
func reifyNewSite(goProjectPath, projectPath string) error {
	files, err := collectFiles(projectPath, []string{".go"})
	if err != nil {
		return err
	}

	// For each go file within project, make sure the refs are to the new site, not to the template site
	relGoProjectPath := projectPathRelative(goProjectPath)
	relProjectPath := projectPathRelative(projectPath)
	for _, f := range files {
		// Load the file, if it contains refs to goprojectpath, replace them with relative project path imports
		data, err := ioutil.ReadFile(f)
		if err != nil {
			return err
		}

		// Substitutions - consider reifying instead if it is any more complex
		fileString := string(data)
		if strings.Contains(fileString, relGoProjectPath) {
			fileString = strings.Replace(fileString, relGoProjectPath, relProjectPath, -1)
		}

		err = ioutil.WriteFile(f, []byte(fileString), permissions)
		if err != nil {
			return err
		}

	}

	return nil
}

// the user should be prompted to:

func showNewSiteHelp(projectPath string) {
	helpString := fragmentaDivider
	helpString += "Congratulations, we've made a new website at " + projectPathRelative(projectPath)
	helpString += "\n  if you wish you can edit the database config at secrets/fragmenta.json and sql at db/migrate"
	helpString += "\n  To get started, run the following commands:"
	helpString += "\n  cd " + projectPath
	helpString += "\n  fragmenta migrate"
	helpString += "\n  fragmenta"
	helpString += fragmentaDivider
	log.Print(helpString)
}

// generateCreateSQL generates an SQL migration file to create the database user and database referred to in config
func generateCreateSQL(projectPath string) error {

	// Set up a Create-Database migration, which comes first
	name := path.Base(projectPath)
	d := ConfigDevelopment["db"]
	u := ConfigDevelopment["db_user"]
	p := ConfigDevelopment["db_pass"]
	sql := fmt.Sprintf("/* Setup database for %s */\nCREATE USER \"%s\" WITH PASSWORD '%s';\nCREATE DATABASE \"%s\" WITH OWNER \"%s\";", name, u, p, d, u)

	// Generate a migration to create db with today's date
	file := migrationPath(projectPath, createDatabaseMigrationName)
	err := ioutil.WriteFile(file, []byte(sql), 0744)
	if err != nil {
		return err
	}

	// If we have a Create-Tables file, copy it out to a new migration with today's date
	createTablesPath := path.Join(projectPath, "db", "migrate", createTablesMigrationName+".sql.tmpl")
	if fileExists(createTablesPath) {
		sql, err := ioutil.ReadFile(createTablesPath)
		if err != nil {
			return err
		}

		// Now vivify the template, for now we just replace one key
		sqlString := reifyString(string(sql))

		file = migrationPath(projectPath, createTablesMigrationName)
		err = ioutil.WriteFile(file, []byte(sqlString), 0744)
		if err != nil {
			return err
		}
		// Remove the old file
		os.Remove(createTablesPath)

	} else {
		fmt.Printf("NO TABLES %s", createTablesPath)
	}

	return nil
}

func projectPathRelative(projectPath string) string {
	goSrc := os.Getenv("GOPATH") + "/src/"
	return strings.Replace(projectPath, goSrc, "", 1)
}

func generateConfig(projectPath string) error {
	configPath := configPath(projectPath)
	prefix := path.Base(projectPath)
	log.Printf("Generating new config at %s", configPath)

	ConfigProduction = map[string]string{}
	ConfigDevelopment = map[string]string{}
	ConfigTest = map[string]string{
		"port":            "3000",
		"log":             "log/test.log",
		"db_adapter":      "postgres",
		"db":              prefix + "_test",
		"db_user":         prefix + "_server",
		"db_pass":         randomKey(8),
		"assets_compiled": "no",
		"path":            projectPathRelative(projectPath),
		"hmac_key":        randomKey(32),
		"secret_key":      randomKey(32),
	}

	// Should we ask for db prefix when setting up?
	// hmm, in fact can we do this setup here at all!!
	for k, v := range ConfigTest {
		ConfigDevelopment[k] = v
		ConfigProduction[k] = v
	}
	ConfigDevelopment["db"] = prefix + "_development"
	ConfigDevelopment["log"] = "log/development.log"
	ConfigDevelopment["hmac_key"] = randomKey(32)
	ConfigDevelopment["secret_key"] = randomKey(32)

	ConfigProduction["db"] = prefix + "_production"
	ConfigProduction["log"] = "log/production.log"
	ConfigProduction["port"] = "80"
	ConfigProduction["assets_compiled"] = "yes"
	ConfigProduction["hmac_key"] = randomKey(32)
	ConfigProduction["secret_key"] = randomKey(32)

	configs := map[string]map[string]string{
		"production":  ConfigProduction,
		"development": ConfigDevelopment,
		"test":        ConfigTest,
	}

	configJSON, err := json.MarshalIndent(configs, "", "\t")
	if err != nil {
		log.Printf("Error parsing config %s %v", configPath, err)
		return err
	}

	// Write the config json file
	err = ioutil.WriteFile(configPath, configJSON, permissions)
	if err != nil {
		log.Printf("Error writing config %s %v", configPath, err)
		return err
	}

	return nil
}

// Generate a random 32 byte key encoded in base64
func randomKey(l int64) string {
	k := make([]byte, l)
	if _, err := io.ReadFull(rand.Reader, k); err != nil {
		return ""
	}
	return hex.EncodeToString(k)
}

// Collect the files with these extensions under src
func collectFiles(dir string, extensions []string) ([]string, error) {

	files := []string{}

	err := filepath.Walk(dir, func(file string, info os.FileInfo, err error) error {
		// If we have an err pass it up
		if err != nil {
			return err
		}

		// Deal with files only
		if !info.IsDir() {
			// Check for go files
			name := path.Base(file)
			if !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") {
				files = append(files, file)
			}
		}

		return nil
	})

	if err != nil {
		return files, err
	}

	return files, nil

}
<commit_msg>Updated logging, added comments on use of cp -r for dir copy<commit_after>package main

import (
	"crypto/rand"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path"
	"path/filepath"
	"strings"
)

const (
	createDatabaseMigrationName = "Create-Database"
	createTablesMigrationName   = "Create-Tables"
)

// RunNew creates a new fragmenta project given the argument
// Usage: fragmenta new [app|cms|api| valid repo path e.g. github.com/fragmenta/fragmenta-cms]
func RunNew(args []string) {

	// Remove fragmenta backup from args list
	args = args[2:]

	// We expect two args left:
	if len(args) < 2 {
		log.Printf("Both a project path and a project type or URL are required to create a new site\n")
		return
	}

	repo := args[0]
	projectPath, err := filepath.Abs(args[1])
	if err != nil {
		log.Printf("Error expanding file path\n")
		return
	}

	if !strings.HasPrefix(projectPath, path.Join(os.Getenv("GOPATH"), "src")) {
		log.Printf("You must create your project in $GOPATH/src\n")
		return
	}

	if fileExists(projectPath) {
		log.Printf("A folder already exists at path %s\n", projectPath)
		return
	}

	switch repo {
	case "app":
		repo = "github.com/fragmenta/fragmenta-app"
	case "cms":
		repo = "github.com/fragmenta/fragmenta-cms"
	case "blog":
		repo = "github.com/fragmenta/fragmenta-blog"
	default:
		// TODO clean repo if it contains https or .git...
	}

	// Log fetching our files
	log.Printf("Fetching from url: %s\n", repo)

	// Go get the project url, to make sure it is up to date, should use -u
	_, err = runCommand("go", "get", repo)
	if err != nil {
		log.Printf("Error calling go get %s", err)
		return
	}

	// Copy the pristine new site over
	goProjectPath := path.Join(os.Getenv("GOPATH"), "src", repo)
	err = copyNewSite(goProjectPath, projectPath)
	if err != nil {
		log.Printf("Error copying project %s", err)
		return
	}

	// Generate config files
	err = generateConfig(projectPath)
	if err != nil {
		log.Printf("Error generating config %s", err)
		return
	}

	// Generate a migration AND run it
	err = generateCreateSQL(projectPath)
	if err != nil {
		log.Printf("Error generating migrations %s", err)
		return
	}

	// Output instructions to let them change setup first if they wish
	showNewSiteHelp(projectPath)

}

func copyNewSite(goProjectPath, projectPath string) error {

	// Check that the folders up to the path exist, if not create them
	err := os.MkdirAll(projectPath, permissions)
	if err != nil {
		log.Printf("The project path could not be created: %s", err)
		return err
	}

	// Now recursively copy over the files from the original repo to project path
	log.Printf("Creating files at: %s", projectPath)
	_, err = copyPath(goProjectPath+"/", projectPath)
	if err != nil {
		return err
	}

	// Delete the .git folder at that path
	gitPath := path.Join(projectPath, ".git")
	log.Printf("Removing all at:%s", gitPath)
	err = os.RemoveAll(gitPath)
	if err != nil {
		return err
	}

	// Run git init to get a new git repo here
	log.Printf("Initialising new git repo at:%s", projectPath)
	_, err = runCommand("git", "init", projectPath)
	if err != nil {
		return err
	}

	// Now reifyNewSite
	log.Printf("Updating import paths to: %s", projectPathRelative(projectPath))
	return reifyNewSite(goProjectPath, projectPath)
}

// Copy a path to another one - at present this is unix only
// Unfortunately there is no simple facility for this in golang stdlib,
// so we use unix command (sorry windows!)
// FIXME - do not rely on unix commands and do this properly
func copyPath(src, dst string) ([]byte, error) {
	// Replace this with an os independent version using filepath.Walk
	return runCommand("cp", "-r", src, dst)
}

// reifyNewSite changes import refs within go files to the correct format
func reifyNewSite(goProjectPath, projectPath string) error {
	files, err := collectFiles(projectPath, []string{".go"})
	if err != nil {
		return err
	}

	// For each go file within project, make sure the refs are to the new site,
	// not to the template site
	relGoProjectPath := projectPathRelative(goProjectPath)
	relProjectPath := projectPathRelative(projectPath)
	for _, f := range files {
		// Load the file, if it contains refs to goprojectpath, replace them with relative project path imports
		data, err := ioutil.ReadFile(f)
		if err != nil {
			return err
		}

		// Substitutions - consider reifying instead if it is any more complex
		fileString := string(data)
		if strings.Contains(fileString, relGoProjectPath) {
			fileString = strings.Replace(fileString, relGoProjectPath, relProjectPath, -1)
		}

		err = ioutil.WriteFile(f, []byte(fileString), permissions)
		if err != nil {
			return err
		}

	}

	return nil
}

// the user should be prompted to:

func showNewSiteHelp(projectPath string) {
	helpString := fragmentaDivider
	helpString += "Congratulations, we've made a new website at " + projectPathRelative(projectPath)
	helpString += "\n  if you wish you can edit the database config at secrets/fragmenta.json and sql at db/migrate"
	helpString += "\n  To get started, run the following commands:"
	helpString += "\n  cd " + projectPath
	helpString += "\n  fragmenta migrate"
	helpString += "\n  fragmenta"
	helpString += fragmentaDivider + "\n"
	fmt.Print(helpString) // fmt to avoid time output
}

// generateCreateSQL generates an SQL migration file to create the database user and database referred to in config
func generateCreateSQL(projectPath string) error {

	// Set up a Create-Database migration, which comes first
	name := path.Base(projectPath)
	d := ConfigDevelopment["db"]
	u := ConfigDevelopment["db_user"]
	p := ConfigDevelopment["db_pass"]
	sql := fmt.Sprintf("/* Setup database for %s */\nCREATE USER \"%s\" WITH PASSWORD '%s';\nCREATE DATABASE \"%s\" WITH OWNER \"%s\";", name, u, p, d, u)

	// Generate a migration to create db with today's date
	file := migrationPath(projectPath, createDatabaseMigrationName)
	err := ioutil.WriteFile(file, []byte(sql), 0744)
	if err != nil {
		return err
	}

	// If we have a Create-Tables file, copy it out to a new migration with today's date
	createTablesPath := path.Join(projectPath, "db", "migrate", createTablesMigrationName+".sql.tmpl")
	if fileExists(createTablesPath) {
		sql, err := ioutil.ReadFile(createTablesPath)
		if err != nil {
			return err
		}

		// Now vivify the template, for now we just replace one key
		sqlString := reifyString(string(sql))

		file = migrationPath(projectPath, createTablesMigrationName)
		err = ioutil.WriteFile(file, []byte(sqlString), 0744)
		if err != nil {
			return err
		}
		// Remove the old file
		os.Remove(createTablesPath)

	} else {
		log.Printf("Error: No Tables found at:%s", createTablesPath)
	}

	return nil
}

func projectPathRelative(projectPath string) string {
	goSrc := os.Getenv("GOPATH") + "/src/"
	return strings.Replace(projectPath, goSrc, "", 1)
}

func generateConfig(projectPath string) error {
	configPath := configPath(projectPath)
	prefix := path.Base(projectPath)
	log.Printf("Generating new config at %s", configPath)

	ConfigProduction = map[string]string{}
	ConfigDevelopment = map[string]string{}
	ConfigTest = map[string]string{
		"port":            "3000",
		"log":             "log/test.log",
		"db_adapter":      "postgres",
		"db":              prefix + "_test",
		"db_user":         prefix + "_server",
		"db_pass":         randomKey(8),
		"assets_compiled": "no",
		"path":            projectPathRelative(projectPath),
		"hmac_key":        randomKey(32),
		"secret_key":      randomKey(32),
	}

	// Should we ask for db prefix when setting up?
	// hmm, in fact can we do this setup here at all!!
	for k, v := range ConfigTest {
		ConfigDevelopment[k] = v
		ConfigProduction[k] = v
	}
	ConfigDevelopment["db"] = prefix + "_development"
	ConfigDevelopment["log"] = "log/development.log"
	ConfigDevelopment["hmac_key"] = randomKey(32)
	ConfigDevelopment["secret_key"] = randomKey(32)

	ConfigProduction["db"] = prefix + "_production"
	ConfigProduction["log"] = "log/production.log"
	ConfigProduction["port"] = "80"
	ConfigProduction["assets_compiled"] = "yes"
	ConfigProduction["hmac_key"] = randomKey(32)
	ConfigProduction["secret_key"] = randomKey(32)

	configs := map[string]map[string]string{
		"production":  ConfigProduction,
		"development": ConfigDevelopment,
		"test":        ConfigTest,
	}

	configJSON, err := json.MarshalIndent(configs, "", "\t")
	if err != nil {
		log.Printf("Error parsing config %s %v", configPath, err)
		return err
	}

	// Write the config json file
	err = ioutil.WriteFile(configPath, configJSON, permissions)
	if err != nil {
		log.Printf("Error writing config %s %v", configPath, err)
		return err
	}

	return nil
}

// Generate a random 32 byte key encoded in base64
func randomKey(l int64) string {
	k := make([]byte, l)
	if _, err := io.ReadFull(rand.Reader, k); err != nil {
		return ""
	}
	return hex.EncodeToString(k)
}

// Collect the files with these extensions under src
func collectFiles(dir string, extensions []string) ([]string, error) {

	files := []string{}

	err := filepath.Walk(dir, func(file string, info os.FileInfo, err error) error {
		// If we have an err pass it up
		if err != nil {
			return err
		}

		// Deal with files only
		if !info.IsDir() {
			// Check for go files
			name := path.Base(file)
			if !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") {
				files = append(files, file)
			}
		}

		return nil
	})

	if err != nil {
		return files, err
	}

	return files, nil

}
<|endoftext|>


<commit_before>package configmanager

import "fmt"

type optType int

func (ot optType) String() string {
	return optTypeMap[ot]
}

const (
	noneType optType = iota
	stringType
	intType
	int8Type
	int16Type
	int32Type
	int64Type
	uintType
	uint8Type
	uint16Type
	uint32Type
	uint64Type
	float32Type
	float64Type

	stringsType
	intsType
	int64sType
	uintsType
	uint64sType
)

var optTypeMap = map[optType]string{
	noneType:    "none",
	stringType:  "string",
	intType:     "int",
	int8Type:    "int8",
	int16Type:   "int16",
	int32Type:   "int32",
	int64Type:   "int64",
	uintType:    "uint",
	uint8Type:   "uint8",
	uint16Type:  "uint16",
	uint32Type:  "uint32",
	uint64Type:  "uint64",
	float32Type: "float32",
	float64Type: "float64",

	stringsType: "[]string",
	intsType:    "[]int",
	int64sType:  "[]int64",
	uintsType:   "[]uint",
	uint64sType: "[]uint64",
}

type baseOpt struct {
	Name     string
	Help     string
	Short    string
	Required bool
	Default  interface{}

	_type optType
}

var _ Opt = baseOpt{}

func newBaseOpt(short, name string, _default interface{}, required bool,
	help string, optType optType) baseOpt {
	o := baseOpt{
		Short:    short,
		Name:     name,
		Help:     help,
		Required: required,
		Default:  _default,
		_type:    optType,
	}
	o.GetDefault()
	return o
}

// GetName returns the name of the option.
func (o baseOpt) GetName() string {
	return o.Name
}

// GetShort returns the shorthand name of the option.
func (o baseOpt) GetShort() string {
	return o.Short
}

// IsRequired returns ture if the option must have the value, or false.
func (o baseOpt) IsRequired() bool {
	return o.Required
}

// GetHelp returns the help doc of the option.
func (o baseOpt) GetHelp() string {
	return o.Help
}

// GetDefault returns the default value of the option.
func (o baseOpt) GetDefault() interface{} {
	if o.Default == nil {
		return nil
	}

	switch o._type {
	case stringType:
		return o.Default.(string)
	case intType:
		return o.Default.(int)
	default:
		panic(fmt.Errorf("don't support the type '%s'", o._type))
	}
}

// Parse parses the value of the option to a certain type.
func (o baseOpt) Parse(data string) (interface{}, error) {
	switch o._type {
	case stringType:
		return ToString(data)
	case intType:
		_v, err := ToInt64(data)
		if err != nil {
			return nil, err
		}
		return int(_v), nil
	default:
		panic(fmt.Errorf("don't support the type '%s'", o._type))
	}
}

// NewStrOpt return a new string option.
//
// Notice: the type of the default value must be string or nil.
// If no default, it's nil.
func NewStrOpt(short, name string, _default interface{}, required bool, help string) Opt {
	return newBaseOpt(short, name, _default, required, help, stringType)
}

// NewIntOpt return a new int option.
//
// Notice: the type of the default value must be int or nil.
// If no default, it's nil.
func NewIntOpt(short, name string, _default interface{}, required bool, help string) Opt {
	return newBaseOpt(short, name, _default, required, help, stringType)
}

// NewInt8Opt return a new int8 option.
//
// Notice: the type of the default value must be int8 or nil.
// If no default, it's nil.
func NewInt8Opt(short, name string, _default interface{}, required bool, help string) Opt {
	return newBaseOpt(short, name, _default, required, help, int8Type)
}

// NewInt16Opt return a new int16 option.
//
// Notice: the type of the default value must be int16 or nil.
// If no default, it's nil.
func NewInt16Opt(short, name string, _default interface{}, required bool, help string) Opt {
	return newBaseOpt(short, name, _default, required, help, int16Type)
}
<commit_msg>Fix a bug<commit_after>package configmanager

import "fmt"

type optType int

func (ot optType) String() string {
	return optTypeMap[ot]
}

const (
	noneType optType = iota
	stringType
	intType
	int8Type
	int16Type
	int32Type
	int64Type
	uintType
	uint8Type
	uint16Type
	uint32Type
	uint64Type
	float32Type
	float64Type

	stringsType
	intsType
	int64sType
	uintsType
	uint64sType
)

var optTypeMap = map[optType]string{
	noneType:    "none",
	stringType:  "string",
	intType:     "int",
	int8Type:    "int8",
	int16Type:   "int16",
	int32Type:   "int32",
	int64Type:   "int64",
	uintType:    "uint",
	uint8Type:   "uint8",
	uint16Type:  "uint16",
	uint32Type:  "uint32",
	uint64Type:  "uint64",
	float32Type: "float32",
	float64Type: "float64",

	stringsType: "[]string",
	intsType:    "[]int",
	int64sType:  "[]int64",
	uintsType:   "[]uint",
	uint64sType: "[]uint64",
}

type baseOpt struct {
	Name     string
	Help     string
	Short    string
	Required bool
	Default  interface{}

	_type optType
}

var _ Opt = baseOpt{}

func newBaseOpt(short, name string, _default interface{}, required bool,
	help string, optType optType) baseOpt {
	o := baseOpt{
		Short:    short,
		Name:     name,
		Help:     help,
		Required: required,
		Default:  _default,
		_type:    optType,
	}
	o.GetDefault()
	return o
}

// GetName returns the name of the option.
func (o baseOpt) GetName() string {
	return o.Name
}

// GetShort returns the shorthand name of the option.
func (o baseOpt) GetShort() string {
	return o.Short
}

// IsRequired returns ture if the option must have the value, or false.
func (o baseOpt) IsRequired() bool {
	return o.Required
}

// GetHelp returns the help doc of the option.
func (o baseOpt) GetHelp() string {
	return o.Help
}

// GetDefault returns the default value of the option.
func (o baseOpt) GetDefault() interface{} {
	if o.Default == nil {
		return nil
	}

	switch o._type {
	case stringType:
		return o.Default.(string)
	case intType:
		return o.Default.(int)
	default:
		panic(fmt.Errorf("don't support the type '%s'", o._type))
	}
}

// Parse parses the value of the option to a certain type.
func (o baseOpt) Parse(data string) (interface{}, error) {
	switch o._type {
	case stringType:
		return ToString(data)
	case intType:
		_v, err := ToInt64(data)
		if err != nil {
			return nil, err
		}
		return int(_v), nil
	default:
		panic(fmt.Errorf("don't support the type '%s'", o._type))
	}
}

// NewStrOpt return a new string option.
//
// Notice: the type of the default value must be string or nil.
// If no default, it's nil.
func NewStrOpt(short, name string, _default interface{}, required bool, help string) Opt {
	return newBaseOpt(short, name, _default, required, help, stringType)
}

// NewIntOpt return a new int option.
//
// Notice: the type of the default value must be int or nil.
// If no default, it's nil.
func NewIntOpt(short, name string, _default interface{}, required bool, help string) Opt {
	return newBaseOpt(short, name, _default, required, help, intType)
}

// NewInt8Opt return a new int8 option.
//
// Notice: the type of the default value must be int8 or nil.
// If no default, it's nil.
func NewInt8Opt(short, name string, _default interface{}, required bool, help string) Opt {
	return newBaseOpt(short, name, _default, required, help, int8Type)
}

// NewInt16Opt return a new int16 option.
//
// Notice: the type of the default value must be int16 or nil.
// If no default, it's nil.
func NewInt16Opt(short, name string, _default interface{}, required bool, help string) Opt {
	return newBaseOpt(short, name, _default, required, help, int16Type)
}
<|endoftext|>


<commit_before>// Copyright (c) 2014 by Christoph Hack <christoph@tux21b.org>
// All rights reserved. Distributed under the Simplified BSD License.

package main

import (
	"bufio"
	"bytes"
	"crypto/md5"
	"encoding/binary"
	"fmt"
	"image"
	"image/jpeg"
	"io"
	"math"
	"time"
	"unicode"

	"github.com/tux21b/imp/font"
)

type PDFWriter struct {
	w    *bufio.Writer
	pos  int
	err  error
	xref []int

	inTJ bool
}

func NewPDFWriter(out io.Writer) *PDFWriter {
	return &PDFWriter{w: bufio.NewWriter(out)}
}

func (w *PDFWriter) WriteString(s string) (int, error) {
	if w.err != nil {
		return 0, w.err
	}
	var n int
	n, w.err = w.w.WriteString(s)
	w.pos += n
	return n, w.err
}

func (w *PDFWriter) WriteStreamPlain(s string) error {
	if w.err != nil {
		return w.err
	}
	fmt.Fprintf(w, "<< /Length %d >>\n", len(s))
	w.WriteString("stream\n")
	w.WriteString(s)
	w.WriteString("\nendstream\n")
	return w.err
}

func (w *PDFWriter) WriteObjectStart(id int) int {
	if id <= 0 {
		id = w.NextID()
	}
	w.xref[id-1] = w.pos
	fmt.Fprintf(w, "%d 0 obj\n", id)
	return id
}

func (w *PDFWriter) WriteObjectEnd() {
	w.WriteString("endobj\n")
}

func (w *PDFWriter) WriteObjectf(id int, format string, args ...interface{}) int {
	id = w.WriteObjectStart(id)
	fmt.Fprintf(w, format, args...)
	w.WriteString("\n")
	w.WriteObjectEnd()
	return id
}

func (w *PDFWriter) NextID() int {
	w.xref = append(w.xref, 0)
	return len(w.xref)
}

func (w *PDFWriter) WriteHeader() {
	w.WriteString("%PDF-1.4\n")
	w.WriteString("%âãÏÓ\n")
}

func (w *PDFWriter) WriteFooter(root, info int) {
	startxref := w.pos
	fmt.Fprintf(w, "xref\n0 %d\n0000000000 65535 f \n", len(w.xref)+1)
	for _, pos := range w.xref {
		fmt.Fprintf(w, "%010d 00000 n \n", pos)
	}
	w.WriteString("trailer\n")

	h := md5.New()
	binary.Write(h, binary.BigEndian, time.Now().UnixNano())
	id := h.Sum(nil)

	fmt.Fprintf(w, `<<
  /Size %d
  /Info %d 0 R
  /Root %d 0 R
  /ID [<%x> <%x>]
>>
`, len(w.xref)+1, info, root, id, id)
	fmt.Fprintf(w, "startxref\n%d\n", startxref)
	w.WriteString("%%EOF\n")
	w.w.Flush()
}

func (w *PDFWriter) WriteFontEmbedded(id int, f *font.Font) {
	var (
		fontBase       = id
		fontDescedant  = w.NextID()
		fontDescriptor = w.NextID()
		fontStream     = w.NextID()
		fontUnicode    = w.NextID()
	)

	name := encodeName(f.PostscriptName)
	cff := f.CFF()

	// base font object
	w.WriteObjectf(fontBase, `<<
  /Type /Font
  /Subtype /Type0
  /BaseFont %s
  /Encoding /Identity-H
  /ToUnicode %d 0 R
  /DescendantFonts [%d 0 R]
>>`, name, fontUnicode, fontDescedant)

	// font descedant
	widths := make([]int, f.NumGlyphs())
	for i := 0; i < len(widths); i++ {
		widths[i] = f.Scale(f.HMetric(font.Index(i)).Width, 1000)
	}
	fontType := 2
	if cff != nil {
		fontType = 0
	}
	w.WriteObjectf(fontDescedant, `<<
  /Type /Font
  /Subtype /CIDFontType%d
  /BaseFont %s
  /CIDSystemInfo
  <<
    /Registry (Adobe)
    /Ordering (Identity)
    /Supplement 0
  >>
  /DW %d
  /W [0 %v]
  /FontDescriptor %d 0 R
>>`, fontType, name, widths[0], widths, fontDescriptor)

	// font descriptor
	fontFile := 2
	if cff != nil {
		fontFile = 3
	}
	flags := 0
	if f.ItalicAngle != 0 {
		flags |= 0x40 // italic
	}
	flags |= 0x20 // non-symbolic font
	w.WriteObjectf(fontDescriptor, `<<
  /Type /FontDescriptor
  /FontName %s
  /Ascent %d
  /Descent %d
  /CapHeight %d
  /FontBBox [%d %d %d %d]
  /ItalicAngle %.4f
  /Flags %d
  /StemV 0
  /FontFile%d %d 0 R
>>`, name, f.Scale(f.Ascender, 1000), f.Scale(f.Descender, 1000),
		f.Scale(f.CapHeight, 1000), f.Scale(f.XMin, 1000),
		f.Scale(f.YMin, 1000), f.Scale(f.XMax, 1000),
		f.Scale(f.YMax, 1000), f.ItalicAngle, flags, fontFile, fontStream)

	// font stream
	w.WriteObjectStart(fontStream)
	if cff == nil {
		ttf := f.TTF()
		fmt.Fprintf(w, "<< /Length %d /Length1 %d >>\n", len(ttf), len(ttf))
		fmt.Fprintf(w, "stream\n%s\nendstream\n", ttf)
	} else {
		fmt.Fprintf(w, "<< /Length %d /Length1 %d /Subtype /CIDFontType0C >>\n", len(cff), len(cff)) // CIDType0C or Type1C depending on the font
		fmt.Fprintf(w, "stream\n%s\nendstream\n", cff)
	}
	w.WriteObjectEnd()

	// to unicode mapping
	w.WriteObjectStart(fontUnicode)
	buf := &bytes.Buffer{}
	fmt.Fprintf(buf, `/CIDInit /ProcSet findresource begin
12 dict begin
begincmap
/CIDSystemInfo << /Registry (FontSpecific) /Ordering (%s) /Supplement 0 >> def
/CMapName /FontSpecific-%s def
/CMapType 2 def
1 begincodespacerange
<0000> <FFFF>
endcodespacerange
`, name[1:], name[1:])
	glyphs := make([]rune, f.NumGlyphs())
	for i := 0; i < math.MaxUint16; i++ {
		glyphs[f.Index(rune(i))] = rune(i)
	}
	total := 0
	for i := 0; i < len(glyphs); i++ {
		if glyphs[i] != 0 {
			total++
		}
	}
	section := 0
	inside := false
	for i := 0; i < len(glyphs); i++ {
		if glyphs[i] == 0 {
			continue
		}
		if section--; section < 0 {
			if section = total; section > 100 {
				section = 100
			}
			total -= section
			if inside {
				fmt.Fprintf(buf, "endbfchar\n")
			}
			fmt.Fprintf(buf, "%d beginbfchar\n", section)
			inside = true
		}
		fmt.Fprintf(buf, "<%04x> <%04x>\n", i, glyphs[i])
	}
	if inside {
		fmt.Fprintf(buf, "endbfchar\n")
	}
	fmt.Fprintf(buf, `endcmap
CMapName currentdict /CMap defineresource pop
end
end`)
	w.WriteStreamPlain(buf.String())
	w.WriteObjectEnd()
}

func (w *PDFWriter) WriteImageJPEG(id int, img image.Image) {
	w.WriteObjectStart(id)
	buf := &bytes.Buffer{}
	jpeg.Encode(buf, img, nil)
	s := img.Bounds().Size()
	fmt.Fprintf(w, `<<
  /Type /XObject
  /Subtype /Image
  /Width %d
  /Height %d
  /ColorSpace /DeviceRGB
  /BitsPerComponent 8
  /Interpolate true
  /Filter [/DCTDecode]
  /Length %d
>>
stream
%s
endstream
`, s.X, s.Y, buf.Len(), buf.Bytes())
	w.WriteObjectEnd()
}

func (w *PDFWriter) Write(p []byte) (int, error) {
	if w.err != nil {
		return 0, w.err
	}
	var n int
	n, w.err = w.w.Write(p)
	w.pos += n
	return n, w.err
}

func u(v int) float32 {
	return float32(v) / 1000
}

func (w *PDFWriter) Pos() int {
	return w.pos
}

func mmToPt(v float32) float32 {
	return v * 72.0 / 25.4
}

func mm(v float32) int {
	return int(v * 72.0 / 25.4 * 1000)
}

func encodeName(s string) string {
	buf := &bytes.Buffer{}
	buf.WriteByte('/')
	for i, r := range s {
		if i == 0 && r == '/' {
			continue
		}
		if unicode.IsLetter(r) {
			buf.WriteRune(r)
		} else if r <= 0xff {
			fmt.Fprintf(buf, "#%02x", r)
		}
	}
	return buf.String()
}
<commit_msg>updated example<commit_after>// Copyright (c) 2014 by Christoph Hack <christoph@tux21b.org>
// All rights reserved. Distributed under the Simplified BSD License.

package main

import (
	"bufio"
	"bytes"
	"crypto/md5"
	"encoding/ascii85"
	"encoding/binary"
	"fmt"
	"image"
	"image/jpeg"
	"io"
	"math"
	"time"
	"unicode"

	"github.com/tux21b/imp/font"
)

type PDFWriter struct {
	w    *bufio.Writer
	pos  int
	err  error
	xref []int

	inTJ bool
}

func NewPDFWriter(out io.Writer) *PDFWriter {
	return &PDFWriter{w: bufio.NewWriter(out)}
}

func (w *PDFWriter) WriteString(s string) (int, error) {
	if w.err != nil {
		return 0, w.err
	}
	var n int
	n, w.err = w.w.WriteString(s)
	w.pos += n
	return n, w.err
}

func (w *PDFWriter) WriteStreamPlain(s string) error {
	if w.err != nil {
		return w.err
	}
	fmt.Fprintf(w, "<< /Length %d >>\n", len(s))
	w.WriteString("stream\n")
	w.WriteString(s)
	w.WriteString("\nendstream\n")
	return w.err
}

func (w *PDFWriter) WriteObjectStart(id int) int {
	if id <= 0 {
		id = w.NextID()
	}
	w.xref[id-1] = w.pos
	fmt.Fprintf(w, "%d 0 obj\n", id)
	return id
}

func (w *PDFWriter) WriteObjectEnd() {
	w.WriteString("endobj\n")
}

func (w *PDFWriter) WriteObjectf(id int, format string, args ...interface{}) int {
	id = w.WriteObjectStart(id)
	fmt.Fprintf(w, format, args...)
	w.WriteString("\n")
	w.WriteObjectEnd()
	return id
}

func (w *PDFWriter) NextID() int {
	w.xref = append(w.xref, 0)
	return len(w.xref)
}

func (w *PDFWriter) WriteHeader() {
	w.WriteString("%PDF-1.4\n")
	w.WriteString("%âãÏÓ\n")
}

func (w *PDFWriter) WriteFooter(root, info int) {
	startxref := w.pos
	fmt.Fprintf(w, "xref\n0 %d\n0000000000 65535 f \n", len(w.xref)+1)
	for _, pos := range w.xref {
		fmt.Fprintf(w, "%010d 00000 n \n", pos)
	}
	w.WriteString("trailer\n")

	h := md5.New()
	binary.Write(h, binary.BigEndian, time.Now().UnixNano())
	id := h.Sum(nil)

	fmt.Fprintf(w, `<<
  /Size %d
  /Info %d 0 R
  /Root %d 0 R
  /ID [<%x> <%x>]
>>
`, len(w.xref)+1, info, root, id, id)
	fmt.Fprintf(w, "startxref\n%d\n", startxref)
	w.WriteString("%%EOF\n")
	w.w.Flush()
}

func (w *PDFWriter) WriteFontEmbedded(id int, f *font.Font) {
	var (
		fontBase       = id
		fontDescedant  = w.NextID()
		fontDescriptor = w.NextID()
		fontStream     = w.NextID()
		fontUnicode    = w.NextID()
	)

	name := encodeName(f.PostscriptName)
	cff := f.CFF()

	// base font object
	w.WriteObjectf(fontBase, `<<
  /Type /Font
  /Subtype /Type0
  /BaseFont %s
  /Encoding /Identity-H
  /ToUnicode %d 0 R
  /DescendantFonts [%d 0 R]
>>`, name, fontUnicode, fontDescedant)

	// font descedant
	widths := make([]int, f.NumGlyphs())
	for i := 0; i < len(widths); i++ {
		widths[i] = f.Scale(f.HMetric(font.Index(i)).Width, 1000)
	}
	fontType := 2
	if cff != nil {
		fontType = 0
	}
	w.WriteObjectf(fontDescedant, `<<
  /Type /Font
  /Subtype /CIDFontType%d
  /BaseFont %s
  /CIDSystemInfo
  <<
    /Registry (Adobe)
    /Ordering (Identity)
    /Supplement 0
  >>
  /DW %d
  /W [0 %v]
  /FontDescriptor %d 0 R
>>`, fontType, name, widths[0], widths, fontDescriptor)

	// font descriptor
	fontFile := 2
	if cff != nil {
		fontFile = 3
	}
	flags := 0
	if f.ItalicAngle != 0 {
		flags |= 0x40 // italic
	}
	flags |= 0x20 // non-symbolic font
	w.WriteObjectf(fontDescriptor, `<<
  /Type /FontDescriptor
  /FontName %s
  /Ascent %d
  /Descent %d
  /CapHeight %d
  /FontBBox [%d %d %d %d]
  /ItalicAngle %.4f
  /Flags %d
  /StemV 0
  /FontFile%d %d 0 R
>>`, name, f.Scale(f.Ascender, 1000), f.Scale(f.Descender, 1000),
		f.Scale(f.CapHeight, 1000), f.Scale(f.XMin, 1000),
		f.Scale(f.YMin, 1000), f.Scale(f.XMax, 1000),
		f.Scale(f.YMax, 1000), f.ItalicAngle, flags, fontFile, fontStream)

	// font stream
	w.WriteObjectStart(fontStream)
	streamBuf := &bytes.Buffer{}
	enc := ascii85.NewEncoder(streamBuf)
	enc.Write(cff)
	enc.Close()
	fontStreamBytes := streamBuf.Bytes()

	if cff == nil {
		ttf := f.TTF()
		fmt.Fprintf(w, "<< /Length %d /Length1 %d >>\n", len(ttf), len(ttf))
		fmt.Fprintf(w, "stream\n%s\nendstream\n", ttf)
	} else {
		fmt.Fprintf(w, "<< /Length %d /Length1 %d /Filter /ASCII85Decode /Subtype /CIDFontType0C >>\n", len(fontStreamBytes), len(cff)) // CIDType0C or Type1C depending on the font
		fmt.Fprintf(w, "stream\n%s\nendstream\n", fontStreamBytes)
	}
	w.WriteObjectEnd()

	// to unicode mapping
	w.WriteObjectStart(fontUnicode)
	buf := &bytes.Buffer{}
	fmt.Fprintf(buf, `/CIDInit /ProcSet findresource begin
12 dict begin
begincmap
/CIDSystemInfo << /Registry (FontSpecific) /Ordering (%s) /Supplement 0 >> def
/CMapName /FontSpecific-%s def
/CMapType 2 def
1 begincodespacerange
<0000> <FFFF>
endcodespacerange
`, name[1:], name[1:])
	glyphs := make([]rune, f.NumGlyphs())
	for i := 0; i < math.MaxUint16; i++ {
		glyphs[f.Index(rune(i))] = rune(i)
	}
	total := 0
	for i := 0; i < len(glyphs); i++ {
		if glyphs[i] != 0 {
			total++
		}
	}
	section := 0
	inside := false
	for i := 0; i < len(glyphs); i++ {
		if glyphs[i] == 0 {
			continue
		}
		if section--; section < 0 {
			if section = total; section > 100 {
				section = 100
			}
			total -= section
			if inside {
				fmt.Fprintf(buf, "endbfchar\n")
			}
			fmt.Fprintf(buf, "%d beginbfchar\n", section)
			inside = true
		}
		fmt.Fprintf(buf, "<%04x> <%04x>\n", i, glyphs[i])
	}
	if inside {
		fmt.Fprintf(buf, "endbfchar\n")
	}
	fmt.Fprintf(buf, `endcmap
CMapName currentdict /CMap defineresource pop
end
end`)
	w.WriteStreamPlain(buf.String())
	w.WriteObjectEnd()
}

func (w *PDFWriter) WriteImageJPEG(id int, img image.Image) {
	w.WriteObjectStart(id)
	buf := &bytes.Buffer{}
	jpeg.Encode(buf, img, nil)
	s := img.Bounds().Size()
	fmt.Fprintf(w, `<<
  /Type /XObject
  /Subtype /Image
  /Width %d
  /Height %d
  /ColorSpace /DeviceRGB
  /BitsPerComponent 8
  /Interpolate true
  /Filter [/DCTDecode]
  /Length %d
>>
stream
%s
endstream
`, s.X, s.Y, buf.Len(), buf.Bytes())
	w.WriteObjectEnd()
}

func (w *PDFWriter) Write(p []byte) (int, error) {
	if w.err != nil {
		return 0, w.err
	}
	var n int
	n, w.err = w.w.Write(p)
	w.pos += n
	return n, w.err
}

func u(v int) float32 {
	return float32(v) / 1000
}

func (w *PDFWriter) Pos() int {
	return w.pos
}

func mmToPt(v float32) float32 {
	return v * 72.0 / 25.4
}

func mm(v float32) int {
	return int(v * 72.0 / 25.4 * 1000)
}

func encodeName(s string) string {
	buf := &bytes.Buffer{}
	buf.WriteByte('/')
	for i, r := range s {
		if i == 0 && r == '/' {
			continue
		}
		if unicode.IsLetter(r) {
			buf.WriteRune(r)
		} else if r <= 0xff {
			fmt.Fprintf(buf, "#%02x", r)
		}
	}
	return buf.String()
}
<|endoftext|>


<commit_before>package rps

import(
	`time`
	`errors`
	`regexp`
	`strings`
	`github.com/0xor1/oak`
	`github.com/0xor1/joak`
	`github.com/gorilla/mux`
)

const(
	_ACT 		= `act`
	_RESTART 	= `restart`
	_CHOOSE 	= `choose`
	_VAL 		= `val`
)

func RouteLocalTest(router *mux.Router, options []string, resultHalfMatrix [][]int, millisecsPerChoice int, newAuthKey string, newCrypKey string, oldAuthKey string, oldCrypKey string){
	initStaticProperties(options, resultHalfMatrix, millisecsPerChoice)
	deleteAfter, _ := time.ParseDuration(_DELETE_AFTER)
	joak.RouteLocalTest(router, newGame, initGame, 60, `rps`, newAuthKey, newCrypKey, oldAuthKey, oldCrypKey, newGame(), getJoinResp, getEntityChangeResp, performAct, deleteAfter)
}

func RouteGaeProd(router *mux.Router, options []string, resultHalfMatrix [][]int, millisecsPerChoice int, newAuthKey string, newCrypKey string, oldAuthKey string, oldCrypKey string, ctxFactory joak.ContextFactory) error {
	initStaticProperties(options, resultHalfMatrix, millisecsPerChoice)
	deleteAfter, _ := time.ParseDuration(_DELETE_AFTER)
	clearAfter, _ := time.ParseDuration(_DELETE_AFTER)
	return joak.RouteGaeProd(router, newGame, initGame, 60, `rps`, newAuthKey, newCrypKey, oldAuthKey, oldCrypKey, newGame(), getJoinResp, getEntityChangeResp, performAct, deleteAfter, clearAfter, `game`, ctxFactory)
}

func initStaticProperties(ops []string, rhm [][]int, millisecsPerChoice int){
	options = ops
	resultHalfMatrix = rhm
	turnLength = millisecsPerChoice * len(options)
	validInput = regexp.MustCompile(`^(`+strings.Join(options, `|`)+`)$`)
}

func getJoinResp(userId string, e oak.Entity) oak.Json {
	resp := getEntityChangeResp(userId, e)
	g, _ := e.(*game)
	resp[`options`] = options
	resp[`pastChoices`] = g.PastChoices
	resp[`resultHalfMatrix`] = resultHalfMatrix
	resp[`turnLength`] = turnLength
	resp[`rematchTimeLimit`] = _REMATCH_TIME_LIMIT
	resp[`maxTurns`] = _DOUBLE_MAX_TURNS / 2
	resp[`myIdx`] = g.getPlayerIdx(userId)
	return resp
}

func getEntityChangeResp(userId string, e oak.Entity) oak.Json {
	g, _ := e.(*game)
	pastChoicesLen := len(g.PastChoices)
	json := oak.Json{
		`turnStart`: g.TurnStart,
		`state`: g.State,
		`currentChoices`: g.CurrentChoices,
		`pastChoicesLen`: pastChoicesLen,
	}
	if pastChoicesLen > 0 {
		json[`penultimateChoices`] = g.PastChoices[pastChoicesLen - 2:]
	}
	if g.State == _GAME_IN_PROGRESS {
		idx := g.getPlayerIdx(userId)
		if idx == -1 || g.CurrentChoices[idx] == `` {
			json[`currentChoices`] = []string{``, ``}
		}
	}
	return json
}

func performAct(json oak.Json, userId string, e oak.Entity) (err error) {
	g, _ := e.(*game)
	if actParam, exists := json[_ACT]; exists {
		if act, ok := actParam.(string); ok {
			if act == _RESTART {
				return g.restart(userId)
			} else if act == _CHOOSE {
				if valParam, exists := json[_VAL]; exists {
					if val, ok := valParam.(string); ok {
						return g.makeChoice(userId, val)
					}else {
						return errors.New(_VAL + ` must be a string value`)
					}
				} else {
					return errors.New(_VAL + ` value must be included in request`)
				}
			} else {
				return errors.New(_ACT + ` must be either ` + _RESTART + ` or ` + _CHOOSE)
			}
		} else {
			return errors.New(_ACT + ` must be a string value`)
		}
	} else {
		return errors.New(_ACT + ` value must be included in request`)
	}
}<commit_msg>increase cookie life to ten minutes to match deactivation time limit<commit_after>package rps

import(
	`time`
	`errors`
	`regexp`
	`strings`
	`github.com/0xor1/oak`
	`github.com/0xor1/joak`
	`github.com/gorilla/mux`
)

const(
	_ACT 		= `act`
	_RESTART 	= `restart`
	_CHOOSE 	= `choose`
	_VAL 		= `val`
)

func RouteLocalTest(router *mux.Router, options []string, resultHalfMatrix [][]int, millisecsPerChoice int, newAuthKey string, newCrypKey string, oldAuthKey string, oldCrypKey string){
	initStaticProperties(options, resultHalfMatrix, millisecsPerChoice)
	deleteAfter, _ := time.ParseDuration(_DELETE_AFTER)
	joak.RouteLocalTest(router, newGame, initGame, 600, `rps`, newAuthKey, newCrypKey, oldAuthKey, oldCrypKey, newGame(), getJoinResp, getEntityChangeResp, performAct, deleteAfter)
}

func RouteGaeProd(router *mux.Router, options []string, resultHalfMatrix [][]int, millisecsPerChoice int, newAuthKey string, newCrypKey string, oldAuthKey string, oldCrypKey string, ctxFactory joak.ContextFactory) error {
	initStaticProperties(options, resultHalfMatrix, millisecsPerChoice)
	deleteAfter, _ := time.ParseDuration(_DELETE_AFTER)
	clearAfter, _ := time.ParseDuration(_DELETE_AFTER)
	return joak.RouteGaeProd(router, newGame, initGame, 600, `rps`, newAuthKey, newCrypKey, oldAuthKey, oldCrypKey, newGame(), getJoinResp, getEntityChangeResp, performAct, deleteAfter, clearAfter, `game`, ctxFactory)
}

func initStaticProperties(ops []string, rhm [][]int, millisecsPerChoice int){
	options = ops
	resultHalfMatrix = rhm
	turnLength = millisecsPerChoice * len(options)
	validInput = regexp.MustCompile(`^(`+strings.Join(options, `|`)+`)$`)
}

func getJoinResp(userId string, e oak.Entity) oak.Json {
	resp := getEntityChangeResp(userId, e)
	g, _ := e.(*game)
	resp[`options`] = options
	resp[`pastChoices`] = g.PastChoices
	resp[`resultHalfMatrix`] = resultHalfMatrix
	resp[`turnLength`] = turnLength
	resp[`rematchTimeLimit`] = _REMATCH_TIME_LIMIT
	resp[`maxTurns`] = _DOUBLE_MAX_TURNS / 2
	resp[`myIdx`] = g.getPlayerIdx(userId)
	return resp
}

func getEntityChangeResp(userId string, e oak.Entity) oak.Json {
	g, _ := e.(*game)
	pastChoicesLen := len(g.PastChoices)
	json := oak.Json{
		`turnStart`: g.TurnStart,
		`state`: g.State,
		`currentChoices`: g.CurrentChoices,
		`pastChoicesLen`: pastChoicesLen,
	}
	if pastChoicesLen > 0 {
		json[`penultimateChoices`] = g.PastChoices[pastChoicesLen - 2:]
	}
	if g.State == _GAME_IN_PROGRESS {
		idx := g.getPlayerIdx(userId)
		if idx == -1 || g.CurrentChoices[idx] == `` {
			json[`currentChoices`] = []string{``, ``}
		}
	}
	return json
}

func performAct(json oak.Json, userId string, e oak.Entity) (err error) {
	g, _ := e.(*game)
	if actParam, exists := json[_ACT]; exists {
		if act, ok := actParam.(string); ok {
			if act == _RESTART {
				return g.restart(userId)
			} else if act == _CHOOSE {
				if valParam, exists := json[_VAL]; exists {
					if val, ok := valParam.(string); ok {
						return g.makeChoice(userId, val)
					}else {
						return errors.New(_VAL + ` must be a string value`)
					}
				} else {
					return errors.New(_VAL + ` value must be included in request`)
				}
			} else {
				return errors.New(_ACT + ` must be either ` + _RESTART + ` or ` + _CHOOSE)
			}
		} else {
			return errors.New(_ACT + ` must be a string value`)
		}
	} else {
		return errors.New(_ACT + ` value must be included in request`)
	}
}<|endoftext|>


<commit_before>package main

import (
	"crypto/md5"
	"encoding/base64"
	"fmt"
	"net/http"
	"strings"
	"time"

	"github.com/gorilla/feeds"

	"google.golang.org/appengine"
	"google.golang.org/appengine/datastore"
)

func GetRSS(rw http.ResponseWriter, req *http.Request) {
	now := time.Now()
	feed := &feeds.Feed{
		Title:       "benjojo blog",
		Link:        &feeds.Link{Href: "https://blog.benjojo.co.uk"},
		Description: "Programming, Networking and some things I found hard to fix at some point",
		Author:      &feeds.Author{"Ben Cartwright-Cox", "ben@benjojo.co.uk"},
		Created:     now,
	}

	c := appengine.NewContext(req)
	q := datastore.NewQuery("Post").Order("-Date").Limit(100)
	posts := make([]Post, 0, 100)

	if _, err := q.GetAll(c, &posts); err != nil {
		http.Error(rw, err.Error(), http.StatusInternalServerError)
		return
	}

	feed.Items = []*feeds.Item{}

	for _, v := range posts {
		if !strings.HasPrefix(v.Slug, "DRAFT-") {
			// newpost := PostFormatted{
			// 	Author:  v.Author,
			// 	Content: v.Content,
			// 	Date:    v.Date.Format("2006-01-02 15:04:05"),
			// 	Slug:    v.Slug,
			// 	Title:   v.Title,
			// }
			// FormattedPosts = append(FormattedPosts, newpost)
			postd, _ := base64.StdEncoding.DecodeString(v.Content)
			wot := &feeds.Item{
				Title:       v.Title,
				Link:        &feeds.Link{Href: fmt.Sprintf("https://blog.benjojo.co.uk/post/%s", v.Slug)},
				Description: string(postd[:256]),
				Author:      &feeds.Author{"ben@benjojo.co.uk", "ben@benjojo.co.uk"},
				Created:     v.Date,
				Id:          generateBadUUID(v.Title),
			}
			feed.Items = append(feed.Items, wot)
		}
	}

	rss, err := feed.ToRss()
	if err != nil {
		http.Error(rw, fmt.Sprintf("argh %s", err), http.StatusInternalServerError)
		return
	}
	rw.Header().Add("Content-Type", "application/rss+xml")
	rw.Write([]byte(rss))
}

// This is a hack as you might have guessed. This blogging system was
// never designed with UUIDs in mind, so I'm sort of just generating one
// out of the title, MD5 is fine since I don't think I am going attack
// myself with colliding titles.
func generateBadUUID(title string) string {
	hashbytes := md5.Sum([]byte(title))
	return fmt.Sprintf("%1x%1x%1x%1x-%1x%1x-40%1x-%1x%1x-%1x%1x%1x%1x%1x%1x",
		hashbytes[0], hashbytes[1], hashbytes[2], hashbytes[3], hashbytes[4],
		hashbytes[5], hashbytes[6], hashbytes[7], hashbytes[8], hashbytes[9],
		hashbytes[10], hashbytes[11], hashbytes[12], hashbytes[13],
		hashbytes[14])

}
<commit_msg>RSS should be UTF-8<commit_after>package main

import (
	"crypto/md5"
	"encoding/base64"
	"fmt"
	"net/http"
	"strings"
	"time"

	"github.com/gorilla/feeds"

	"google.golang.org/appengine"
	"google.golang.org/appengine/datastore"
)

func GetRSS(rw http.ResponseWriter, req *http.Request) {
	now := time.Now()
	feed := &feeds.Feed{
		Title:       "benjojo blog",
		Link:        &feeds.Link{Href: "https://blog.benjojo.co.uk"},
		Description: "Programming, Networking and some things I found hard to fix at some point",
		Author:      &feeds.Author{"Ben Cartwright-Cox", "ben@benjojo.co.uk"},
		Created:     now,
	}

	c := appengine.NewContext(req)
	q := datastore.NewQuery("Post").Order("-Date").Limit(100)
	posts := make([]Post, 0, 100)

	if _, err := q.GetAll(c, &posts); err != nil {
		http.Error(rw, err.Error(), http.StatusInternalServerError)
		return
	}

	feed.Items = []*feeds.Item{}

	for _, v := range posts {
		if !strings.HasPrefix(v.Slug, "DRAFT-") {
			// newpost := PostFormatted{
			// 	Author:  v.Author,
			// 	Content: v.Content,
			// 	Date:    v.Date.Format("2006-01-02 15:04:05"),
			// 	Slug:    v.Slug,
			// 	Title:   v.Title,
			// }
			// FormattedPosts = append(FormattedPosts, newpost)
			postd, _ := base64.StdEncoding.DecodeString(v.Content)
			wot := &feeds.Item{
				Title:       v.Title,
				Link:        &feeds.Link{Href: fmt.Sprintf("https://blog.benjojo.co.uk/post/%s", v.Slug)},
				Description: string(postd[:256]),
				Author:      &feeds.Author{"ben@benjojo.co.uk", "ben@benjojo.co.uk"},
				Created:     v.Date,
				Id:          generateBadUUID(v.Title),
			}
			feed.Items = append(feed.Items, wot)
		}
	}

	rss, err := feed.ToRss()
	if err != nil {
		http.Error(rw, fmt.Sprintf("argh %s", err), http.StatusInternalServerError)
		return
	}
	rw.Header().Add("Content-Type", "application/rss+xml; charset=utf-8")
	rw.Write([]byte(rss))
}

// This is a hack as you might have guessed. This blogging system was
// never designed with UUIDs in mind, so I'm sort of just generating one
// out of the title, MD5 is fine since I don't think I am going attack
// myself with colliding titles.
func generateBadUUID(title string) string {
	hashbytes := md5.Sum([]byte(title))
	return fmt.Sprintf("%1x%1x%1x%1x-%1x%1x-40%1x-%1x%1x-%1x%1x%1x%1x%1x%1x",
		hashbytes[0], hashbytes[1], hashbytes[2], hashbytes[3], hashbytes[4],
		hashbytes[5], hashbytes[6], hashbytes[7], hashbytes[8], hashbytes[9],
		hashbytes[10], hashbytes[11], hashbytes[12], hashbytes[13],
		hashbytes[14])

}
<|endoftext|>


<commit_before>package feeds

// rss support
// validation done according to spec here:
//    http://cyber.law.harvard.edu/rss/rss.html

import (
	"encoding/xml"
	"fmt"
	"strconv"
	"time"
)

// private wrapper around the RssFeed which gives us the <rss>..</rss> xml
type rssFeedXml struct {
	XMLName xml.Name `xml:"rss"`
	Version string   `xml:"version,attr"`
	Channel *RssFeed
}

type RssImage struct {
	XMLName xml.Name `xml:"image"`
	Url     string   `xml:"url"`
	Title   string   `xml:"title"`
	Link    string   `xml:"link"`
	Width   int      `xml:"width,omitempty"`
	Height  int      `xml:"height,omitempty"`
}

type RssTextInput struct {
	XMLName     xml.Name `xml:"textInput"`
	Title       string   `xml:"title"`
	Description string   `xml:"description"`
	Name        string   `xml:"name"`
	Link        string   `xml:"link"`
}

type RssFeed struct {
	XMLName        xml.Name `xml:"channel"`
	Title          string   `xml:"title"`       // required
	Link           string   `xml:"link"`        // required
	Description    string   `xml:"description"` // required
	Language       string   `xml:"language,omitempty"`
	Copyright      string   `xml:"copyright,omitempty"`
	ManagingEditor string   `xml:"managingEditor,omitempty"` // Author used
	WebMaster      string   `xml:"webMaster,omitempty"`
	PubDate        string   `xml:"pubDate,omitempty"`       // created or updated
	LastBuildDate  string   `xml:"lastBuildDate,omitempty"` // updated used
	Category       string   `xml:"category,omitempty"`
	Generator      string   `xml:"generator,omitempty"`
	Docs           string   `xml:"docs,omitempty"`
	Cloud          string   `xml:"cloud,omitempty"`
	Ttl            int      `xml:"ttl,omitempty"`
	Rating         string   `xml:"rating,omitempty"`
	SkipHours      string   `xml:"skipHours,omitempty"`
	SkipDays       string   `xml:"skipDays,omitempty"`
	Image          *RssImage
	TextInput      *RssTextInput
	Items          []*RssItem
}

type RssItem struct {
	XMLName     xml.Name `xml:"item"`
	Title       string   `xml:"title"`       // required
	Link        string   `xml:"link"`        // required
	Description string   `xml:"description"` // required
	Author      string   `xml:"author,omitempty"`
	Category    string   `xml:"category,omitempty"`
	Comments    string   `xml:"comments,omitempty"`
	Enclosure   *RssEnclosure
	Guid        string `xml:"guid,omitempty"`    // Id used
	PubDate     string `xml:"pubDate,omitempty"` // created or updated
	Source      string `xml:"source,omitempty"`
}

type RssEnclosure struct {
	//RSS 2.0 <enclosure url="http://example.com/file.mp3" length="123456789" type="audio/mpeg" />
	XMLName xml.Name `xml:"enclosure"`
	Url     string   `xml:"url,attr"`
	Length  string   `xml:"length,attr"`
	Type    string   `xml:"type,attr"`
}

type Rss struct {
	*Feed
}

// create a new RssItem with a generic Item struct's data
func newRssItem(i *Item) *RssItem {
	item := &RssItem{
		Title:       i.Title,
		Link:        i.Link.Href,
		Description: i.Description,
		Guid:        i.Id,
		PubDate:     anyTimeFormat("2006-01-02T15:04:05-07:00", i.Created, i.Updated),
	}

	intLength, err := strconv.ParseInt(i.Link.Length, 10, 64)

	if err == nil && (intLength > 0 || i.Link.Type != "") {
		item.Enclosure = &RssEnclosure{Url: i.Link.Href, Type: i.Link.Type, Length: i.Link.Length}
	}
	if i.Author != nil {
		item.Author = i.Author.Name
	}
	return item
}

// create a new RssFeed with a generic Feed struct's data
func (r *Rss) RssFeed() *RssFeed {
	pub := anyTimeFormat("2006-01-02T15:04:05-07:00", r.Created, r.Updated)
	build := anyTimeFormat("2006-01-02T15:04:05-07:00", r.Updated)
	author := ""
	if r.Author != nil {
		author = r.Author.Email
		if len(r.Author.Name) > 0 {
			author = fmt.Sprintf("%s (%s)", r.Author.Email, r.Author.Name)
		}
	}

	channel := &RssFeed{
		Title:          r.Title,
		Link:           r.Link.Href,
		Description:    r.Description,
		ManagingEditor: author,
		PubDate:        pub,
		LastBuildDate:  build,
		Copyright:      r.Copyright,
	}
	for _, i := range r.Items {
		channel.Items = append(channel.Items, newRssItem(i))
	}
	return channel
}

// return an XML-Ready object for an Rss object
func (r *Rss) FeedXml() interface{} {
	// only generate version 2.0 feeds for now
	return r.RssFeed().FeedXml()

}

// return an XML-ready object for an RssFeed object
func (r *RssFeed) FeedXml() interface{} {
	return &rssFeedXml{Version: "2.0", Channel: r}
}
<commit_msg>Remove unused time import<commit_after>package feeds

// rss support
// validation done according to spec here:
//    http://cyber.law.harvard.edu/rss/rss.html

import (
	"encoding/xml"
	"fmt"
	"strconv"
)

// private wrapper around the RssFeed which gives us the <rss>..</rss> xml
type rssFeedXml struct {
	XMLName xml.Name `xml:"rss"`
	Version string   `xml:"version,attr"`
	Channel *RssFeed
}

type RssImage struct {
	XMLName xml.Name `xml:"image"`
	Url     string   `xml:"url"`
	Title   string   `xml:"title"`
	Link    string   `xml:"link"`
	Width   int      `xml:"width,omitempty"`
	Height  int      `xml:"height,omitempty"`
}

type RssTextInput struct {
	XMLName     xml.Name `xml:"textInput"`
	Title       string   `xml:"title"`
	Description string   `xml:"description"`
	Name        string   `xml:"name"`
	Link        string   `xml:"link"`
}

type RssFeed struct {
	XMLName        xml.Name `xml:"channel"`
	Title          string   `xml:"title"`       // required
	Link           string   `xml:"link"`        // required
	Description    string   `xml:"description"` // required
	Language       string   `xml:"language,omitempty"`
	Copyright      string   `xml:"copyright,omitempty"`
	ManagingEditor string   `xml:"managingEditor,omitempty"` // Author used
	WebMaster      string   `xml:"webMaster,omitempty"`
	PubDate        string   `xml:"pubDate,omitempty"`       // created or updated
	LastBuildDate  string   `xml:"lastBuildDate,omitempty"` // updated used
	Category       string   `xml:"category,omitempty"`
	Generator      string   `xml:"generator,omitempty"`
	Docs           string   `xml:"docs,omitempty"`
	Cloud          string   `xml:"cloud,omitempty"`
	Ttl            int      `xml:"ttl,omitempty"`
	Rating         string   `xml:"rating,omitempty"`
	SkipHours      string   `xml:"skipHours,omitempty"`
	SkipDays       string   `xml:"skipDays,omitempty"`
	Image          *RssImage
	TextInput      *RssTextInput
	Items          []*RssItem
}

type RssItem struct {
	XMLName     xml.Name `xml:"item"`
	Title       string   `xml:"title"`       // required
	Link        string   `xml:"link"`        // required
	Description string   `xml:"description"` // required
	Author      string   `xml:"author,omitempty"`
	Category    string   `xml:"category,omitempty"`
	Comments    string   `xml:"comments,omitempty"`
	Enclosure   *RssEnclosure
	Guid        string `xml:"guid,omitempty"`    // Id used
	PubDate     string `xml:"pubDate,omitempty"` // created or updated
	Source      string `xml:"source,omitempty"`
}

type RssEnclosure struct {
	//RSS 2.0 <enclosure url="http://example.com/file.mp3" length="123456789" type="audio/mpeg" />
	XMLName xml.Name `xml:"enclosure"`
	Url     string   `xml:"url,attr"`
	Length  string   `xml:"length,attr"`
	Type    string   `xml:"type,attr"`
}

type Rss struct {
	*Feed
}

// create a new RssItem with a generic Item struct's data
func newRssItem(i *Item) *RssItem {
	item := &RssItem{
		Title:       i.Title,
		Link:        i.Link.Href,
		Description: i.Description,
		Guid:        i.Id,
		PubDate:     anyTimeFormat("2006-01-02T15:04:05-07:00", i.Created, i.Updated),
	}

	intLength, err := strconv.ParseInt(i.Link.Length, 10, 64)

	if err == nil && (intLength > 0 || i.Link.Type != "") {
		item.Enclosure = &RssEnclosure{Url: i.Link.Href, Type: i.Link.Type, Length: i.Link.Length}
	}
	if i.Author != nil {
		item.Author = i.Author.Name
	}
	return item
}

// create a new RssFeed with a generic Feed struct's data
func (r *Rss) RssFeed() *RssFeed {
	pub := anyTimeFormat("2006-01-02T15:04:05-07:00", r.Created, r.Updated)
	build := anyTimeFormat("2006-01-02T15:04:05-07:00", r.Updated)
	author := ""
	if r.Author != nil {
		author = r.Author.Email
		if len(r.Author.Name) > 0 {
			author = fmt.Sprintf("%s (%s)", r.Author.Email, r.Author.Name)
		}
	}

	channel := &RssFeed{
		Title:          r.Title,
		Link:           r.Link.Href,
		Description:    r.Description,
		ManagingEditor: author,
		PubDate:        pub,
		LastBuildDate:  build,
		Copyright:      r.Copyright,
	}
	for _, i := range r.Items {
		channel.Items = append(channel.Items, newRssItem(i))
	}
	return channel
}

// return an XML-Ready object for an Rss object
func (r *Rss) FeedXml() interface{} {
	// only generate version 2.0 feeds for now
	return r.RssFeed().FeedXml()

}

// return an XML-ready object for an RssFeed object
func (r *RssFeed) FeedXml() interface{} {
	return &rssFeedXml{Version: "2.0", Channel: r}
}
<|endoftext|>


<commit_before>package rss

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"time"
)

// Parse RSS or Atom data.
func Parse(data []byte) (*Feed, error) {

	if strings.Contains(string(data), "<rss") {
		return parseRSS2(data, database)
	} else if strings.Contains(string(data), "xmlns=\"http://purl.org/rss/1.0/\"") {
		return parseRSS1(data, database)
	} else {
		return parseAtom(data, database)
	}

	panic("Unreachable.")
}

// CacheParsedItemIDs enables or disable Item.ID caching when parsing feeds.
// Returns whether Item.ID were cached prior to function call.
func CacheParsedItemIDs(flag bool) (didCache bool) {
	didCache = !disabled
	disabled = !flag
	return
}

type FetchFunc func() (resp *http.Response, err error)

// Fetch downloads and parses the RSS feed at the given URL
func Fetch(url string) (*Feed, error) {
	return FetchByClient(url, http.DefaultClient)
}

func FetchByClient(url string, client *http.Client) (*Feed, error) {
	fetchFunc := func() (resp *http.Response, err error) {
		return client.Get(url)
	}
	return FetchByFunc(fetchFunc, url)
}

func FetchByFunc(fetchFunc FetchFunc, url string) (*Feed, error) {
	resp, err := fetchFunc()
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	out, err := Parse(body)
	if err != nil {
		return nil, err
	}

	if out.Link == "" {
		out.Link = url
	}

	out.UpdateURL = url

	return out, nil
}

// Feed is the top-level structure.
type Feed struct {
	Nickname    string // This is not set by the package, but could be helpful.
	Title       string
	Description string
	Link        string // Link to the creator's website.
	UpdateURL   string // URL of the feed itself.
	Image       *Image // Feed icon.
	Items       []*Item
	ItemMap     map[string]struct{} // Used in checking whether an item has been seen before.
	Refresh     time.Time           // Earliest time this feed should next be checked.
	Unread      uint32              // Number of unread items. Used by aggregators.
}

// Update fetches any new items and updates f.
func (f *Feed) Update() error {

	// Check that we don't update too often.
	if f.Refresh.After(time.Now()) {
		return nil
	}

	if f.UpdateURL == "" {
		return errors.New("Error: feed has no URL.")
	}

	if f.ItemMap == nil {
		f.ItemMap = make(map[string]struct{})
		for _, item := range f.Items {
			if _, ok := f.ItemMap[item.ID]; !ok {
				f.ItemMap[item.ID] = struct{}{}
			}
		}
	}

	update, err := Fetch(f.UpdateURL)
	if err != nil {
		return err
	}

	f.Refresh = update.Refresh
	f.Title = update.Title
	f.Description = update.Description

	for _, item := range update.Items {
		if _, ok := f.ItemMap[item.ID]; !ok {
			f.Items = append(f.Items, item)
			f.ItemMap[item.ID] = struct{}{}
			f.Unread++
		}
	}

	return nil
}

func (f *Feed) String() string {
	buf := new(bytes.Buffer)
	buf.WriteString(fmt.Sprintf("Feed %q\n\t%q\n\t%q\n\t%s\n\tRefresh at %s\n\tUnread: %d\n\tItems:\n",
		f.Title, f.Description, f.Link, f.Image, f.Refresh.Format("Mon 2 Jan 2006 15:04:05 MST"), f.Unread))
	for _, item := range f.Items {
		buf.WriteString(fmt.Sprintf("\t%s\n", item.Format("\t\t")))
	}
	return buf.String()
}

// Item represents a single story.
type Item struct {
	Title   string
	Summary string
	Content string
	Link    string
	Date    time.Time
	ID      string
	Read    bool
}

func (i *Item) String() string {
	return i.Format("")
}

func (i *Item) Format(s string) string {
	return fmt.Sprintf("Item %q\n\t%s%q\n\t%s%s\n\t%s%q\n\t%sRead: %v\n\t%s%q", i.Title, s, i.Link, s,
		i.Date.Format("Mon 2 Jan 2006 15:04:05 MST"), s, i.ID, s, i.Read, s, i.Content)
}

type Image struct {
	Title  string
	Url    string
	Height uint32
	Width  uint32
}

func (i *Image) String() string {
	return fmt.Sprintf("Image %q", i.Title)
}
<commit_msg>Improved structure printing<commit_after>package rss

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"text/tabwriter"
	"time"
)

// Parse RSS or Atom data.
func Parse(data []byte) (*Feed, error) {

	if strings.Contains(string(data), "<rss") {
		return parseRSS2(data, database)
	} else if strings.Contains(string(data), "xmlns=\"http://purl.org/rss/1.0/\"") {
		return parseRSS1(data, database)
	} else {
		return parseAtom(data, database)
	}

	panic("Unreachable.")
}

// CacheParsedItemIDs enables or disable Item.ID caching when parsing feeds.
// Returns whether Item.ID were cached prior to function call.
func CacheParsedItemIDs(flag bool) (didCache bool) {
	didCache = !disabled
	disabled = !flag
	return
}

type FetchFunc func() (resp *http.Response, err error)

// Fetch downloads and parses the RSS feed at the given URL
func Fetch(url string) (*Feed, error) {
	return FetchByClient(url, http.DefaultClient)
}

func FetchByClient(url string, client *http.Client) (*Feed, error) {
	fetchFunc := func() (resp *http.Response, err error) {
		return client.Get(url)
	}
	return FetchByFunc(fetchFunc, url)
}

func FetchByFunc(fetchFunc FetchFunc, url string) (*Feed, error) {
	resp, err := fetchFunc()
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	out, err := Parse(body)
	if err != nil {
		return nil, err
	}

	if out.Link == "" {
		out.Link = url
	}

	out.UpdateURL = url

	return out, nil
}

// Feed is the top-level structure.
type Feed struct {
	Nickname    string // This is not set by the package, but could be helpful.
	Title       string
	Description string
	Link        string // Link to the creator's website.
	UpdateURL   string // URL of the feed itself.
	Image       *Image // Feed icon.
	Items       []*Item
	ItemMap     map[string]struct{} // Used in checking whether an item has been seen before.
	Refresh     time.Time           // Earliest time this feed should next be checked.
	Unread      uint32              // Number of unread items. Used by aggregators.
}

// Update fetches any new items and updates f.
func (f *Feed) Update() error {

	// Check that we don't update too often.
	if f.Refresh.After(time.Now()) {
		return nil
	}

	if f.UpdateURL == "" {
		return errors.New("Error: feed has no URL.")
	}

	if f.ItemMap == nil {
		f.ItemMap = make(map[string]struct{})
		for _, item := range f.Items {
			if _, ok := f.ItemMap[item.ID]; !ok {
				f.ItemMap[item.ID] = struct{}{}
			}
		}
	}

	update, err := Fetch(f.UpdateURL)
	if err != nil {
		return err
	}

	f.Refresh = update.Refresh
	f.Title = update.Title
	f.Description = update.Description

	for _, item := range update.Items {
		if _, ok := f.ItemMap[item.ID]; !ok {
			f.Items = append(f.Items, item)
			f.ItemMap[item.ID] = struct{}{}
			f.Unread++
		}
	}

	return nil
}

func (f *Feed) String() string {
	buf := new(bytes.Buffer)
	if debug {
		w := tabwriter.NewWriter(buf, 0, 8, 0, '\t', tabwriter.StripEscape)
		fmt.Fprintf(w, "Feed {\n")
		fmt.Fprintf(w, "\xff\t\xffNickname:\t%q\n", f.Nickname)
		fmt.Fprintf(w, "\xff\t\xffTitle:\t%q\n", f.Title)
		fmt.Fprintf(w, "\xff\t\xffDescription:\t%q\n", f.Description)
		fmt.Fprintf(w, "\xff\t\xffLink:\t%q\n", f.Link)
		fmt.Fprintf(w, "\xff\t\xffUpdateURL:\t%q\n", f.UpdateURL)
		fmt.Fprintf(w, "\xff\t\xffImage:\t%q (%s)\n", f.Image.Title, f.Image.Url)
		fmt.Fprintf(w, "\xff\t\xffRefresh:\t%s\n", f.Refresh.Format(DATE))
		fmt.Fprintf(w, "\xff\t\xffUnread:\t%d\n", f.Unread)
		fmt.Fprintf(w, "\xff\t\xffItems:\t(%d) {\n", len(f.Items))
		for _, item := range f.Items {
			fmt.Fprintf(w, "%s\n", item.Format(2))
		}
		fmt.Fprintf(w, "\xff\t\xff}\n}\n")
		w.Flush()
	} else {
		w := buf
		fmt.Fprintf(w, "Feed %q\n", f.Title)
		fmt.Fprintf(w, "\t%q\n", f.Description)
		fmt.Fprintf(w, "\t%q\n", f.Link)
		fmt.Fprintf(w, "\t%s\n", f.Image)
		fmt.Fprintf(w, "\tRefresh at %s\n", f.Refresh.Format(DATE))
		fmt.Fprintf(w, "\tUnread: %d\n", f.Unread)
		fmt.Fprintf(w, "\tItems:\n")
		for _, item := range f.Items {
			fmt.Fprintf(w, "\t%s\n", item.Format(2))
		}
	}
	return buf.String()
}

// Item represents a single story.
type Item struct {
	Title   string
	Summary string
	Content string
	Link    string
	Date    time.Time
	ID      string
	Read    bool
}

func (i *Item) String() string {
	return i.Format(0)
}

func (i *Item) Format(indent int) string {
	buf := new(bytes.Buffer)
	single := strings.Repeat("\t", indent)
	double := single + "\t"
	if debug {
		w := tabwriter.NewWriter(buf, 0, 8, 0, '\t', tabwriter.StripEscape)
		fmt.Fprintf(w, "\xff%s\xffItem {\n", single)
		fmt.Fprintf(w, "\xff%s\xffTitle:\t%q\n", double, i.Title)
		fmt.Fprintf(w, "\xff%s\xffSummary:\t%q\n", double, i.Summary)
		fmt.Fprintf(w, "\xff%s\xffLink:\t%s\n", double, i.Link)
		fmt.Fprintf(w, "\xff%s\xffDate:\t%s\n", double, i.Date.Format(DATE))
		fmt.Fprintf(w, "\xff%s\xffID:\t%s\n", double, i.ID)
		fmt.Fprintf(w, "\xff%s\xffRead:\t%v\n", double, i.Read)
		fmt.Fprintf(w, "\xff%s\xffContent:\t%q\n", double, i.Content)
		fmt.Fprintf(w, "\xff%s\xff}\n", single)
		w.Flush()
	} else {
		w := buf
		fmt.Fprintf(w, "%sItem %q\n", single, i.Title)
		fmt.Fprintf(w, "%s%q\n", double, i.Link)
		fmt.Fprintf(w, "%s%s\n", double, i.Date.Format(DATE))
		fmt.Fprintf(w, "%s%q\n", double, i.ID)
		fmt.Fprintf(w, "%sRead: %v\n", double, i.Read)
		fmt.Fprintf(w, "%s%q\n", double, i.Content)
	}
	return buf.String()
}

type Image struct {
	Title  string
	Url    string
	Height uint32
	Width  uint32
}

func (i *Image) String() string {
	return fmt.Sprintf("Image %q", i.Title)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"crypto/tls"
	"io"
	"log"
	"net/url"
	"os"
	"os/signal"
	"strconv"
	"strings"
	"syscall"

	"github.com/bgentry/heroku-go"
	"github.com/heroku/hk/term"
)

var (
	detachedRun bool
	dynoSize    string
)

var cmdRun = &Command{
	Run:      runRun,
	Usage:    "run [-s <size>] [-d] <command> [<argument>...]",
	Category: "dyno",
	Short:    "run a process in a dyno",
	Long: `
Run a process on Heroku

Options:

    -s <size>  set the size for this dyno (e.g. 2X)
    -d         run in detached mode instead of attached to terminal

Examples:

    $ hk run echo "hello"
    Running ` + "`" + `echo "hello"` + "`" + ` on myapp as run.1234:
    "hello"

    $ hk run -s 2X console
    Running ` + "`" + `console` + "`" + ` on myapp as run.5678:
    Loading production environment (Rails 3.2.14)
    irb(main):001:0> ...

    $ hk run -d bin/my_worker
    Ran ` + "`" + `bin/my_worker` + "`" + ` on myapp as run.4321, detached.
`,
}

func init() {
	cmdRun.Flag.BoolVarP(&detachedRun, "detached", "d", false, "detached")
	cmdRun.Flag.StringVarP(&dynoSize, "size", "s", "", "dyno size")
	cmdRun.Flag.StringVarP(&flagApp, "app", "a", "", "app name")
}

func runRun(cmd *Command, args []string) {
	if len(args) == 0 {
		cmd.printUsage()
		os.Exit(2)
	}
	appname := mustApp()

	cols, err := term.Cols()
	if err != nil {
		printFatal(err.Error())
	}
	lines, err := term.Lines()
	if err != nil {
		printFatal(err.Error())
	}

	attached := !detachedRun
	opts := heroku.DynoCreateOpts{Attach: &attached}
	if attached {
		env := map[string]string{
			"COLUMNS": strconv.Itoa(cols),
			"LINES":   strconv.Itoa(lines),
			"TERM":    os.Getenv("TERM"),
		}
		opts.Env = &env
	}
	if dynoSize != "" {
		if !strings.HasSuffix(dynoSize, "X") {
			cmd.printUsage()
			os.Exit(2)
		}
		opts.Size = &dynoSize
	}

	command := strings.Join(args, " ")
	dyno, err := client.DynoCreate(appname, command, &opts)
	must(err)

	if detachedRun {
		log.Printf("Ran `%s` on %s as %s, detached.", dyno.Command, appname, dyno.Name)
		return
	}
	log.Printf("Running `%s` on %s as %s:", dyno.Command, appname, dyno.Name)

	u, err := url.Parse(*dyno.AttachURL)
	if err != nil {
		printFatal(err.Error())
	}

	cn, err := tls.Dial("tcp", u.Host, nil)
	if err != nil {
		printFatal(err.Error())
	}
	defer cn.Close()

	br := bufio.NewReader(cn)

	_, err = io.WriteString(cn, u.Path[1:]+"\r\n")
	if err != nil {
		printFatal(err.Error())
	}

	for {
		_, pre, err := br.ReadLine()
		if err != nil {
			printFatal(err.Error())
		}
		if !pre {
			break
		}
	}

	if term.IsTerminal(os.Stdin) && term.IsTerminal(os.Stdout) {
		err = term.MakeRaw(os.Stdin)
		if err != nil {
			printFatal(err.Error())
		}
		defer term.Restore(os.Stdin)

		sig := make(chan os.Signal)
		signal.Notify(sig, os.Signal(syscall.SIGQUIT), os.Interrupt)
		go func() {
			defer term.Restore(os.Stdin)
			for sg := range sig {
				switch sg {
				case os.Interrupt:
					cn.Write([]byte{3})
				case os.Signal(syscall.SIGQUIT):
					cn.Write([]byte{28})
				default:
					panic("not reached")
				}
			}
		}()
	}

	errc := make(chan error)
	cp := func(a io.Writer, b io.Reader) {
		_, err := io.Copy(a, b)
		errc <- err
	}

	go cp(os.Stdout, br)
	go cp(cn, os.Stdin)
	if err = <-errc; err != nil {
		printFatal(err.Error())
	}
}
<commit_msg>improve help for run command<commit_after>package main

import (
	"bufio"
	"crypto/tls"
	"io"
	"log"
	"net/url"
	"os"
	"os/signal"
	"strconv"
	"strings"
	"syscall"

	"github.com/bgentry/heroku-go"
	"github.com/heroku/hk/term"
)

var (
	detachedRun bool
	dynoSize    string
)

var cmdRun = &Command{
	Run:      runRun,
	Usage:    "run [-s <size>] [-d] <command> [<argument>...]",
	Category: "dyno",
	Short:    "run a process in a dyno",
	Long: `
Run a process on Heroku. Flags such as` + " `-a` " + `may be parsed out of
the command unless the command is quoted or provided after a
double-dash (--).

Options:

    -s <size>  set the size for this dyno (e.g. 2X)
    -d         run in detached mode instead of attached to terminal

Examples:

    $ hk run echo "hello"
    Running ` + "`echo \"hello\"`" + ` on myapp as run.1234:
    "hello"

    $ hk run console
    Running ` + "`console`" + ` on myapp as run.5678:
    Loading production environment (Rails 3.2.14)
    irb(main):001:0> ...

    $ hk run -d -s 2X bin/my_worker
    Ran ` + "`bin/my_worker`" + ` on myapp as run.4321, detached.

    $ hk run -a myapp -- ls -a /
    Running ` + "`ls -a bin /`" + ` on myapp as run.8650:
    /:
    .  ..  app  bin  dev  etc  home  lib  lib64  lost+found  proc  sbin  tmp  usr  var
`,
}

func init() {
	cmdRun.Flag.BoolVarP(&detachedRun, "detached", "d", false, "detached")
	cmdRun.Flag.StringVarP(&dynoSize, "size", "s", "", "dyno size")
	cmdRun.Flag.StringVarP(&flagApp, "app", "a", "", "app name")
}

func runRun(cmd *Command, args []string) {
	if len(args) == 0 {
		cmd.printUsage()
		os.Exit(2)
	}
	appname := mustApp()

	cols, err := term.Cols()
	if err != nil {
		printFatal(err.Error())
	}
	lines, err := term.Lines()
	if err != nil {
		printFatal(err.Error())
	}

	attached := !detachedRun
	opts := heroku.DynoCreateOpts{Attach: &attached}
	if attached {
		env := map[string]string{
			"COLUMNS": strconv.Itoa(cols),
			"LINES":   strconv.Itoa(lines),
			"TERM":    os.Getenv("TERM"),
		}
		opts.Env = &env
	}
	if dynoSize != "" {
		if !strings.HasSuffix(dynoSize, "X") {
			cmd.printUsage()
			os.Exit(2)
		}
		opts.Size = &dynoSize
	}

	command := strings.Join(args, " ")
	dyno, err := client.DynoCreate(appname, command, &opts)
	must(err)

	if detachedRun {
		log.Printf("Ran `%s` on %s as %s, detached.", dyno.Command, appname, dyno.Name)
		return
	}
	log.Printf("Running `%s` on %s as %s:", dyno.Command, appname, dyno.Name)

	u, err := url.Parse(*dyno.AttachURL)
	if err != nil {
		printFatal(err.Error())
	}

	cn, err := tls.Dial("tcp", u.Host, nil)
	if err != nil {
		printFatal(err.Error())
	}
	defer cn.Close()

	br := bufio.NewReader(cn)

	_, err = io.WriteString(cn, u.Path[1:]+"\r\n")
	if err != nil {
		printFatal(err.Error())
	}

	for {
		_, pre, err := br.ReadLine()
		if err != nil {
			printFatal(err.Error())
		}
		if !pre {
			break
		}
	}

	if term.IsTerminal(os.Stdin) && term.IsTerminal(os.Stdout) {
		err = term.MakeRaw(os.Stdin)
		if err != nil {
			printFatal(err.Error())
		}
		defer term.Restore(os.Stdin)

		sig := make(chan os.Signal)
		signal.Notify(sig, os.Signal(syscall.SIGQUIT), os.Interrupt)
		go func() {
			defer term.Restore(os.Stdin)
			for sg := range sig {
				switch sg {
				case os.Interrupt:
					cn.Write([]byte{3})
				case os.Signal(syscall.SIGQUIT):
					cn.Write([]byte{28})
				default:
					panic("not reached")
				}
			}
		}()
	}

	errc := make(chan error)
	cp := func(a io.Writer, b io.Reader) {
		_, err := io.Copy(a, b)
		errc <- err
	}

	go cp(os.Stdout, br)
	go cp(cn, os.Stdin)
	if err = <-errc; err != nil {
		printFatal(err.Error())
	}
}
<|endoftext|>


<commit_before>package immortal

import (
	"bufio"
	"io"
	"os/exec"
	"strconv"
	"sync/atomic"
	"syscall"
)

func (self *Daemon) stdHandler(p io.ReadCloser, e bool) {
	in := bufio.NewScanner(p)
	for in.Scan() {
		if e {
			Log(Red(in.Text()))
		} else {
			Log(in.Text())
		}
	}
}

func (self *Daemon) Run() {
	atomic.AddInt64(&self.count, 1)

	cmd := exec.Command(self.command[0], self.command[1:]...)

	sysProcAttr := new(syscall.SysProcAttr)
	// set owner
	if self.owner != nil {
		uid, err := strconv.Atoi(self.owner.Uid)
		if err != nil {
			self.ctrl.err <- err
			return
		}

		gid, err := strconv.Atoi(self.owner.Gid)
		if err != nil {
			self.ctrl.err <- err
			return
		}

		//	https://golang.org/pkg/syscall/#SysProcAttr
		sysProcAttr.Credential = &syscall.Credential{
			Uid: uint32(uid),
			Gid: uint32(gid),
		}
	}

	// Set process group ID to Pgid, or, if Pgid == 0, to new pid
	sysProcAttr.Setpgid = true
	sysProcAttr.Pgid = 0

	cmd.SysProcAttr = sysProcAttr

	stdout, err := cmd.StdoutPipe()
	if err != nil {
		self.ctrl.err <- err
		return
	}

	stderr, err := cmd.StderrPipe()
	if err != nil {
		self.ctrl.err <- err
		return
	}

	if err := cmd.Start(); err != nil {
		self.ctrl.err <- err
		return
	}

	go self.stdHandler(stdout, false)
	go self.stdHandler(stderr, true)

	self.pid = cmd.Process.Pid

	self.ctrl.state <- cmd.Wait()
}
<commit_msg>modified:   run.go<commit_after>package immortal

import (
	"bufio"
	"io"
	"os/exec"
	"strconv"
	"sync/atomic"
	"syscall"
)

func (self *Daemon) stdHandler(p io.ReadCloser, e bool) {
	in := bufio.NewScanner(p)
	for in.Scan() {
		if e {
			Log(Red(in.Text()))
		} else {
			Log(in.Text())
		}
	}
}

func (self *Daemon) Run() {
	atomic.AddInt64(&self.count, 1)

	cmd := exec.Command(self.command[0], self.command[1:]...)

	sysProcAttr := new(syscall.SysProcAttr)
	// set owner
	if self.owner != nil {
		uid, err := strconv.Atoi(self.owner.Uid)
		if err != nil {
			self.ctrl.err <- err
			return
		}

		gid, err := strconv.Atoi(self.owner.Gid)
		if err != nil {
			self.ctrl.err <- err
			return
		}

		//	https://golang.org/pkg/syscall/#SysProcAttr
		sysProcAttr.Credential = &syscall.Credential{
			Uid: uint32(uid),
			Gid: uint32(gid),
		}
	}

	// Set process group ID to Pgid, or, if Pgid == 0, to new pid
	sysProcAttr.Setpgid = true
	sysProcAttr.Pgid = 0

	cmd.SysProcAttr = sysProcAttr

	stdout, err := cmd.StdoutPipe()
	if err != nil {
		self.ctrl.err <- err
		return
	}

	stderr, err := cmd.StderrPipe()
	if err != nil {
		self.ctrl.err <- err
		return
	}

	go self.stdHandler(stdout, false)
	go self.stdHandler(stderr, true)

	if err := cmd.Start(); err != nil {
		self.ctrl.err <- err
		return
	}

	self.pid = cmd.Process.Pid

	self.ctrl.state <- cmd.Wait()
}
<|endoftext|>


<commit_before>// Copyright 2016 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

// chipsmoketest verifies that basic Chip specific functionality works.
package chipsmoketest

import (
	"fmt"
	"sort"

	"github.com/google/periph/conn/gpio"
	"github.com/google/periph/host/allwinner"
	"github.com/google/periph/host/chip"
	"github.com/google/periph/host/headers"
)

// testChipPresent verifies that CHIP and Allwinner are indeed detected.
func testChipPresent() error {
	if !chip.Present() {
		return fmt.Errorf("did not detect presence of CHIP")
	}
	if !allwinner.Present() {
		return fmt.Errorf("did not detect presence of Allwinner CPU")
	}
	return nil
}

// testChipHeaders verifies that the appropriate headers with the right pin count show
// up and point checks that a couple of pins are correct.
func testChipHeaders() error {
	h := headers.All()
	if len(h) != 2 {
		return fmt.Errorf("expected to find 2 headers, not %d", len(h))
	}
	if len(h["U13"]) != 20 {
		return fmt.Errorf("expected U13 to have 20 rows, not %d", len(h["U13"]))
	}
	if len(h["U14"]) != 20 {
		return fmt.Errorf("expected U13 to have 20 rows, not %d", len(h["U13"]))
	}

	for r := range h["U13"] {
		if len(h["U13"][r]) != 2 {
			return fmt.Errorf("expected row %d of U13 to have 2 pins, not %d",
				r, len(h["U13"][r]))
		}
		if len(h["U14"][r]) != 2 {
			return fmt.Errorf("expected row %d of U14 to have 2 pins, not %d",
				r, len(h["U14"][r]))
		}
	}

	u13_17 := h["U13"][8][0]
	if u13_17.Name() != "PD2" {
		return fmt.Errorf("expected U13_17 to be PD2, not %s", u13_17.Name())
	}
	p := gpio.ByName("PD2")
	if p == nil || p.Name() != u13_17.Name() { // p is gpio.PinIO while u13_17 is pins.Pin
		return fmt.Errorf(`expected gpio.ByName("PD2") to equal h["U13"][8][0], instead `+
			"got %s and %s", p, u13_17)
	}

	u14_24 := h["U14"][11][1]
	if p == nil || u14_24.Name() != "PB3" {
		return fmt.Errorf("expected U14_24 to be PB3, not %s", u14_24.Name())
	}

	u14_17 := h["U14"][8][0]
	if p == nil || u14_17.Name() != "GPIO1020" {
		return fmt.Errorf("expected U14_17 to be GPIO1020, not %s", u14_17.Name())
	}
	return nil
}

// testChipGpioNumbers tests that the gpio pins get the right numbers.
func testChipGpioNumbers() error {
	must := map[int]string{34: "PB2", 108: "PD12", 139: "PE11", 1022: "GPIO1022"}
	for number, name := range must {
		pin := gpio.ByNumber(number)
		if pin == nil {
			return fmt.Errorf("could not get gpio pin %d (should be %s)", number, name)
		}
		if pin.Name() != name {
			return fmt.Errorf("expected gpio pin %d to be %s but it's %s",
				number, name, pin.Name())
		}
	}
	return nil
}

// testChipGpioNames tests that the gpio pins get the right names.
func testChipGpioNames() error {
	all := []string{}
	for _, p := range gpio.All() {
		all = append(all, p.Name())
	}
	sort.Strings(all)

	must := []string{"PB2", "PE11", "GPIO1022"}
	for _, name := range must {
		ix := sort.SearchStrings(all, name)
		if ix >= len(all) || all[ix] != name {
			return fmt.Errorf("expected to find gpio pin %s but it's missing", name)
		}
	}
	return nil
}

// testChipAliases tests that the various gpio pin aliases get set-up
func testChipAliases() error {
	tests := map[string]string{ // alias->real
		"XIO-P4": "GPIO1020", "LCD-D2": "PD2", "GPIO98": "PD2",
	}
	for a, r := range tests {
		p := gpio.ByName(a)
		if p == nil {
			return fmt.Errorf("failed to open %s", a)
		}
		pa, ok := p.(gpio.RealPin)
		if !ok {
			return fmt.Errorf("expected that pin %s is an alias, not %T", a, p)
		}
		if pr := pa.Real(); pr.Name() != r {
			return fmt.Errorf("expected that alias %s have real pin %s but it's %s",
				a, r, pr.Name())
		}
	}
	return nil
}

type SmokeTest struct {
}

func (s *SmokeTest) Name() string {
	return "chip"
}

func (s *SmokeTest) Description() string {
	return "Single CPU low cost board available at getchip.com"
}

func (s *SmokeTest) Run(args []string) error {
	tests := []func() error{
		testChipPresent, testChipHeaders, testChipGpioNames, testChipAliases,
	}
	for _, t := range tests {
		err := t()
		if err != nil {
			return err
		}
	}
	return nil
}

/* The following gpio tests are commented out for now in favor of using gpio-test via a shell
 * script. Once the test startegy settles this can be deleted if it's not used.

// testChipGpioMem tests two connected pins using memory-mapped gpio
func testChipGpioMem() error {
	p1, err := pinByName(t, "PB2")
	if err != nil {
		return err
	}
	p2, err := pinByName(t, "PB3")
	if err != nil {
		return err
	}
	err = gpio.TestCycle(p1, p2, noPull, false)
	if err != nil {
		return err
	}
	err = gpio.TestCycle(p2, p1, noPull, false)
	if err != nil {
		return err
	}
}

// testChipGpioSysfs tests two connected pins using sysfs gpio
func testChipGpioSysfs() error {
	p1, err := pinByNumber(t, 34)
	if err != nil {
		return err
	}
	p2, err := pinByNumber(t, 35)
	if err != nil {
		return err
	}
	err = gpio.TestCycle(p1, p2, noPull, false)
	if err != nil {
		return err
	}
	err = gpio.TestCycle(p2, p1, noPull, false)
	if err != nil {
		return err
	}
}

// testChipGpioXIO tests two connected XIO pins using sysfs gpio
func testChipGpioXIO() error {
	p1, err := pinByNumber(t, 1022)
	if err != nil {
		return err
	}
	p2, err := pinByNumber(t, 1023)
	if err != nil {
		return err
	}
	err = gpio.TestCycle(p1, p2, noPull, false)
	if err != nil {
		return err
	}
	err = gpio.TestCycle(p2, p1, noPull, false)
	if err != nil {
		return err
	}
}

// pinByName gets a gpio pin by name and calls Fatal if it fails
func pinByName(name string) (gpio.PinIO, error) {
	p := gpio.ByName(name)
	if p == nil {
		return nil, fmt.Errorf("Failed to open %s", name)
	}
	return p, nil
}

// pinByNumber gets a *sysfs* pin by number and calls Fatal if it fails
func pinByNumber(n int) (gpio.PinIO, error) {
	p, err := sysfs.PinByNumber(n)
	if p == nil {
		return nil, fmt.Errorf("Failed to open sysfs(%d): %s", n, err)
	}
	return p, nil
}

*/
<commit_msg>chipsmoketest: fix it to enroll in gohci. (#76)<commit_after>// Copyright 2016 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

// chipsmoketest verifies that basic CHIP specific functionality works.
package chipsmoketest

import (
	"fmt"
	"sort"

	"github.com/google/periph/conn/gpio"
	"github.com/google/periph/host/allwinner"
	"github.com/google/periph/host/chip"
	"github.com/google/periph/host/headers"
)

// testChipPresent verifies that CHIP and Allwinner are indeed detected.
func testChipPresent() error {
	if !chip.Present() {
		return fmt.Errorf("did not detect presence of CHIP")
	}
	if !allwinner.Present() {
		return fmt.Errorf("did not detect presence of Allwinner CPU")
	}
	return nil
}

// testChipHeaders verifies that the appropriate headers with the right pin count show
// up and point checks that a couple of pins are correct.
func testChipHeaders() error {
	h := headers.All()
	if len(h) != 2 {
		return fmt.Errorf("expected to find 2 headers, not %d", len(h))
	}
	if len(h["U13"]) != 20 {
		return fmt.Errorf("expected U13 to have 20 rows, not %d", len(h["U13"]))
	}
	if len(h["U14"]) != 20 {
		return fmt.Errorf("expected U13 to have 20 rows, not %d", len(h["U13"]))
	}

	for r := range h["U13"] {
		if len(h["U13"][r]) != 2 {
			return fmt.Errorf("expected row %d of U13 to have 2 pins, not %d",
				r, len(h["U13"][r]))
		}
		if len(h["U14"][r]) != 2 {
			return fmt.Errorf("expected row %d of U14 to have 2 pins, not %d",
				r, len(h["U14"][r]))
		}
	}

	u13_17 := h["U13"][8][0]
	if u13_17.Name() != "PD2" {
		return fmt.Errorf("expected U13_17 to be PD2, not %s", u13_17.Name())
	}
	p := gpio.ByName("PD2")
	if p == nil || p.Name() != u13_17.Name() { // p is gpio.PinIO while u13_17 is pins.Pin
		return fmt.Errorf(`expected gpio.ByName("PD2") to equal h["U13"][8][0], instead `+
			"got %s and %s", p, u13_17)
	}

	u14_24 := h["U14"][11][1]
	if p == nil || u14_24.Name() != "PB3" {
		return fmt.Errorf("expected U14_24 to be PB3, not %s", u14_24.Name())
	}

	u14_17 := h["U14"][8][0]
	if p == nil || u14_17.Name() != "GPIO1020" {
		return fmt.Errorf("expected U14_17 to be GPIO1020, not %s", u14_17.Name())
	}
	return nil
}

// testChipGpioNumbers tests that the gpio pins get the right numbers.
func testChipGpioNumbers() error {
	must := map[int]string{34: "PB2", 108: "PD12", 139: "PE11", 1022: "GPIO1022"}
	for number, name := range must {
		pin := gpio.ByNumber(number)
		if pin == nil {
			return fmt.Errorf("could not get gpio pin %d (should be %s)", number, name)
		}
		if pin.Name() != name {
			return fmt.Errorf("expected gpio pin %d to be %s but it's %s",
				number, name, pin.Name())
		}
	}
	return nil
}

// testChipGpioNames tests that the gpio pins get the right names.
func testChipGpioNames() error {
	all := []string{}
	for _, p := range gpio.All() {
		all = append(all, p.Name())
	}
	sort.Strings(all)

	must := []string{"PB2", "PE11", "GPIO1022"}
	for _, name := range must {
		ix := sort.SearchStrings(all, name)
		if ix >= len(all) || all[ix] != name {
			return fmt.Errorf("expected to find gpio pin %s but it's missing", name)
		}
	}
	return nil
}

// testChipAliases tests that the various gpio pin aliases get set-up
func testChipAliases() error {
	tests := map[string]string{ // alias->real
		"XIO-P4": "GPIO1020", "LCD-D2": "PD2",
	}
	for a, r := range tests {
		p := gpio.ByName(a)
		if p == nil {
			return fmt.Errorf("failed to open %s", a)
		}
		pa, ok := p.(gpio.RealPin)
		if !ok {
			return fmt.Errorf("expected that pin %s is an alias, not %T", a, p)
		}
		if pr := pa.Real(); pr.Name() != r {
			return fmt.Errorf("expected that alias %s have real pin %s but it's %s",
				a, r, pr.Name())
		}
	}
	return nil
}

type SmokeTest struct {
}

func (s *SmokeTest) Name() string {
	return "chip"
}

func (s *SmokeTest) Description() string {
	return "Single CPU low cost board available at getchip.com"
}

func (s *SmokeTest) Run(args []string) error {
	tests := []func() error{
		testChipPresent, testChipHeaders, testChipGpioNumbers, testChipGpioNames, testChipAliases,
	}
	for _, t := range tests {
		if err := t(); err != nil {
			return err
		}
	}
	return nil
}

/* The following gpio tests are commented out for now in favor of using gpio-test via a shell
 * script. Once the test startegy settles this can be deleted if it's not used.

// testChipGpioMem tests two connected pins using memory-mapped gpio
func testChipGpioMem() error {
	p1, err := pinByName(t, "PB2")
	if err != nil {
		return err
	}
	p2, err := pinByName(t, "PB3")
	if err != nil {
		return err
	}
	err = gpio.TestCycle(p1, p2, noPull, false)
	if err != nil {
		return err
	}
	err = gpio.TestCycle(p2, p1, noPull, false)
	if err != nil {
		return err
	}
}

// testChipGpioSysfs tests two connected pins using sysfs gpio
func testChipGpioSysfs() error {
	p1, err := pinByNumber(t, 34)
	if err != nil {
		return err
	}
	p2, err := pinByNumber(t, 35)
	if err != nil {
		return err
	}
	err = gpio.TestCycle(p1, p2, noPull, false)
	if err != nil {
		return err
	}
	err = gpio.TestCycle(p2, p1, noPull, false)
	if err != nil {
		return err
	}
}

// testChipGpioXIO tests two connected XIO pins using sysfs gpio
func testChipGpioXIO() error {
	p1, err := pinByNumber(t, 1022)
	if err != nil {
		return err
	}
	p2, err := pinByNumber(t, 1023)
	if err != nil {
		return err
	}
	err = gpio.TestCycle(p1, p2, noPull, false)
	if err != nil {
		return err
	}
	err = gpio.TestCycle(p2, p1, noPull, false)
	if err != nil {
		return err
	}
}

// pinByName gets a gpio pin by name and calls Fatal if it fails
func pinByName(name string) (gpio.PinIO, error) {
	p := gpio.ByName(name)
	if p == nil {
		return nil, fmt.Errorf("Failed to open %s", name)
	}
	return p, nil
}

// pinByNumber gets a *sysfs* pin by number and calls Fatal if it fails
func pinByNumber(n int) (gpio.PinIO, error) {
	p, err := sysfs.PinByNumber(n)
	if p == nil {
		return nil, fmt.Errorf("Failed to open sysfs(%d): %s", n, err)
	}
	return p, nil
}

*/
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/simulatedsimian/emu6502/core6502"
)

func main() {
	var ctx core6502.BasicCPUContext
	core6502.HardResetCPU(&ctx, 0x400)

	for opcode := 0; opcode < 256; opcode++ {
		ctx.Poke(0x400, uint8(opcode))

		dis, _ := core6502.Disassemble(&ctx, 0x400)
		fmt.Printf("$%02x %s\n", opcode, dis)
	}
}
<commit_msg>print full hex opcode<commit_after>package main

import (
	"fmt"
	"github.com/simulatedsimian/emu6502/core6502"
)

func main() {
	var ctx core6502.BasicCPUContext
	core6502.HardResetCPU(&ctx, 0x400)
	ctx.PokeWord(0x401, 0xeeff)

	for opcode := 0; opcode < 256; opcode++ {
		ctx.Poke(0x400, uint8(opcode))

		dis, len := core6502.Disassemble(&ctx, 0x400)
		if len == 1 {
			fmt.Printf("$%02x:              %s\n", opcode, dis)
		} else if len == 2 {
			fmt.Printf("$%02x $%02x:          %s\n", opcode, ctx.Peek(0x401), dis)
		} else if len == 3 {
			fmt.Printf("$%02x $%02x $%02x:      %s\n", opcode, ctx.Peek(0x401), ctx.Peek(0x402), dis)
		}
	}
}
<|endoftext|>