<commit_before>package ghist

import "fmt"

func (h Histogram) String() (str string) {
	str = fmt.Sprintf("%d bin ghist summarizing %d items\n", len(h.Bins), h.Count)
	str += fmt.Sprintf("Mean: %2f    Median: %2f\n", h.Mean(), h.Median())
	str += fmt.Sprintf("Mode: %v\n\nBins:\n", h.Mode().String())
	if h.MaxBinRatio > 0 {
		str += fmt.Sprintf("MaxBinRatio: %d\n", h.MaxBinRatio)
	}
	for i, bin := range h.Bins {
		str += fmt.Sprintf("%d: %v\n", i, bin.String())
	}
	return
}

func (b Bin) String() string {
	return fmt.Sprintf("%d in [%.10f:%.10f] totaling %f", b.Count, b.Max, b.Min, b.Sum)
}
<commit_msg>revert stringer to use default float precision<commit_after>package ghist

import "fmt"

func (h Histogram) String() (str string) {
	str = fmt.Sprintf("%d bin ghist summarizing %d items\n", len(h.Bins), h.Count)
	str += fmt.Sprintf("Mean: %2f    Median: %2f\n", h.Mean(), h.Median())
	str += fmt.Sprintf("Mode: %v\n\nBins:\n", h.Mode().String())
	if h.MaxBinRatio > 0 {
		str += fmt.Sprintf("MaxBinRatio: %d\n", h.MaxBinRatio)
	}
	for i, bin := range h.Bins {
		str += fmt.Sprintf("%d: %v\n", i, bin.String())
	}
	return
}

func (b Bin) String() string {
	return fmt.Sprintf("%d in [%f:%f] totaling %f", b.Count, b.Max, b.Min, b.Sum)
}
<|endoftext|>


<commit_before>package logger

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/Sirupsen/logrus"
	"net/http"
	"os"
	"strings"
)

type SumoLogicHook struct {
	Url             string
	HttpClient      *http.Client
	AppName         string
}

func NewSumo(config Config) Client {
	var client Client
	host, _ := os.Hostname()
	client.Logger = logrus.New()
	client.Logger.Formatter = &logrus.TextFormatter{
		ForceColors: false,
	}
	hook, err := NewSumoHook(config.Host, host)
	if err != nil {
		fmt.Println(err.Error())
		return client
	}
	client.Logger.Hooks.Add(hook)
	return client
}

func NewSumoHook(url string, appname string) (*SumoLogicHook, error) {
	if url == "" {
		return nil, fmt.Errorf("Unable to send logs to Sumo Logic. SUMO_ENDPOINT not provided")
	}
	client := &http.Client{}
	return &SumoLogicHook{url, client, appname}, nil
}

func (hook *SumoLogicHook) Fire(entry *logrus.Entry) error {
	data := make(logrus.Fields, len(entry.Data))
	for k, v := range entry.Data {
		switch v := v.(type) {
		case error:
			data[k] = v.Error()
		default:
			data[k] = v
		}
	}
	data["tstamp"] = entry.Time.Format(logrus.DefaultTimestampFormat)
	data["message"] = strings.Replace(entry.Message, "\"", "'", -1)
	data["level"] = entry.Level.String()
	s, err := json.Marshal(data)
	if err != nil {
		return fmt.Errorf("Failed to build json: %v", err)
	}
	err = hook.httpPost(s)
	if err != nil {
		return err
	}
	return nil
}

func (hook *SumoLogicHook) httpPost(s []byte) error {
	// already printed error about sumo_endpoint so be silent
	if hook.Url == "" || len(s) == 0 {
		// avoid panic and return if no url
		return nil
	}
	body := bytes.NewBuffer(s)
	req, err := http.NewRequest("POST", hook.Url, body)
	client := http.Client{}
	if req == nil {
		return fmt.Errorf("Something went wrong")
	}
	req.Header.Add("X-Sumo-Name", hook.AppName)
	resp, err := client.Do(req)
	if err != nil || resp == nil {
		return fmt.Errorf("Failed to post data: %s", err.Error())
	} else if resp.StatusCode != 200 {
		return fmt.Errorf("Failed to post data: %s", resp.Status)
	} else {
		return nil
	}
}

func (s *SumoLogicHook) Levels() []logrus.Level {
	return []logrus.Level{
		logrus.PanicLevel,
		logrus.FatalLevel,
		logrus.ErrorLevel,
		logrus.WarnLevel,
		logrus.InfoLevel,
		logrus.DebugLevel,
	}
}
<commit_msg>try closing the connections<commit_after>package logger

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/Sirupsen/logrus"
	"net/http"
	"os"
	"strings"
)

type SumoLogicHook struct {
	Url        string
	HttpClient *http.Client
	AppName    string
}

func NewSumo(config Config) Client {
	var client Client
	host, _ := os.Hostname()
	client.Logger = logrus.New()
	client.Logger.Formatter = &logrus.TextFormatter{
		ForceColors: false,
	}
	hook, err := NewSumoHook(config.Host, host)
	if err != nil {
		fmt.Println(err.Error())
		return client
	}
	client.Logger.Hooks.Add(hook)
	return client
}

func NewSumoHook(url string, appname string) (*SumoLogicHook, error) {
	if url == "" {
		return nil, fmt.Errorf("Unable to send logs to Sumo Logic. SUMO_ENDPOINT not provided")
	}
	client := &http.Client{}
	return &SumoLogicHook{url, client, appname}, nil
}

func (hook *SumoLogicHook) Fire(entry *logrus.Entry) error {
	data := make(logrus.Fields, len(entry.Data))
	for k, v := range entry.Data {
		switch v := v.(type) {
		case error:
			data[k] = v.Error()
		default:
			data[k] = v
		}
	}
	data["tstamp"] = entry.Time.Format(logrus.DefaultTimestampFormat)
	data["message"] = strings.Replace(entry.Message, "\"", "'", -1)
	data["level"] = entry.Level.String()
	s, err := json.Marshal(data)
	if err != nil {
		return fmt.Errorf("Failed to build json: %v", err)
	}
	err = hook.httpPost(s)
	if err != nil {
		return err
	}
	return nil
}

func (hook *SumoLogicHook) httpPost(s []byte) error {
	// already printed error about sumo_endpoint so be silent
	if hook.Url == "" || len(s) == 0 {
		// avoid panic and return if no url
		return nil
	}

	body := bytes.NewBuffer(s)
	req, err := http.NewRequest("POST", hook.Url, body)
	if err != nil {
		return fmt.Errorf("Error creating the request: %s", err.Error())
	}

	req.Close = true
	req.Header.Add("X-Sumo-Name", hook.AppName)
	client := http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return fmt.Errorf("Failed to post data: %s", err.Error())
	}

	defer resp.Body.Close()
	if resp.StatusCode != 200 {
		return fmt.Errorf("Failed to post data: %s", resp.Status)
	}
	return nil
}

func (s *SumoLogicHook) Levels() []logrus.Level {
	return []logrus.Level{
		logrus.PanicLevel,
		logrus.FatalLevel,
		logrus.ErrorLevel,
		logrus.WarnLevel,
		logrus.InfoLevel,
		logrus.DebugLevel,
	}
}
<|endoftext|>


<commit_before>package superast

import (
	"go/ast"
	"go/token"
	"log"
	"strconv"
)

var allowedImports = map[string]struct{}{
	"fmt": struct{}{},
	"log": struct{}{},
}

type block struct {
	ID    int         `json:"id"`
	Stmts []statement `json:"statements"`
}

type dataType struct {
	ID   int    `json:"id"`
	Name string `json:"name"`
}

type parameter struct {
	ID       int      `json:"id"`
	Name     string   `json:"name"`
	DataType dataType `json:"data-type"`
}

type statement struct {
	ID      int         `json:"id"`
	Line    int         `json:"line"`
	Type    string      `json:"type"`
	Name    string      `json:"name,omitempty"`
	Value   string      `json:"value,omitempty"`
	RetType *dataType   `json:"return-type,omitempty"`
	Params  []parameter `json:"parameters,omitempty"`
	Args    []statement `json:"arguments,omitempty"`
	Left    *statement  `json:"left,omitempty"`
	Right   *statement  `json:"right,omitempty"`
	Block   *block      `json:"block,omitempty"`
}

type AST struct {
	curID      int
	RootBlock  *block
	nodeStack  []ast.Node
	stmtsStack []*[]statement
	fset       *token.FileSet
}

func NewAST(fset *token.FileSet) *AST {
	a := &AST{
		curID: 1,
		fset:  fset,
		RootBlock: &block{
			ID:    0,
			Stmts: make([]statement, 0),
		},
	}
	a.pushStmts(&a.RootBlock.Stmts)
	return a
}

func (a *AST) newID() int {
	i := a.curID
	a.curID++
	return i
}

func (a *AST) pushNode(node ast.Node) {
	a.nodeStack = append(a.nodeStack, node)
}

func (a *AST) curNode() ast.Node {
	if len(a.nodeStack) == 0 {
		return nil
	}
	return a.nodeStack[len(a.nodeStack)-1]
}

func (a *AST) popNode() {
	if len(a.nodeStack) == 0 {
		return
	}
	a.nodeStack = a.nodeStack[:len(a.nodeStack)-1]
}

func (a *AST) pushStmts(stmts *[]statement) {
	a.stmtsStack = append(a.stmtsStack, stmts)
}

func (a *AST) addStmt(stmt statement) {
	if len(a.stmtsStack) == 0 {
		return
	}
	curStmts := a.stmtsStack[len(a.stmtsStack)-1]
	*curStmts = append(*curStmts, stmt)
}

func (a *AST) popStmts() {
	if len(a.stmtsStack) == 0 {
		return
	}
	a.stmtsStack = a.stmtsStack[:len(a.stmtsStack)-1]
}

func strUnquote(s string) string {
	u, err := strconv.Unquote(s)
	if err != nil {
		log.Fatalf("Error when unquoting string: %s", err)
	}
	return u
}

func exprToString(x ast.Expr) string {
	switch t := x.(type) {
	case *ast.Ident:
		return t.Name
	case *ast.SelectorExpr:
		return exprToString(t.X) + "." + t.Sel.Name
	case *ast.StarExpr:
		return exprToString(t.X)
	}
	return ""
}

var funcNames = map[string]string{
	"fmt.Println": "print",
	"println":     "print",
}

type field struct {
	varName, typeName string
}

func flattenFieldList(fieldList *ast.FieldList) []field {
	var fields []field
	for _, f := range fieldList.List {
		t := exprToString(f.Type)
		for _, n := range f.Names {
			fields = append(fields, field{
				varName:  n.Name,
				typeName: t,
			})
		}
	}
	return fields
}

func (a *AST) Visit(node ast.Node) ast.Visitor {
	parentNode := a.curNode()
	if node == nil {
		switch parentNode.(type) {
		case *ast.CallExpr:
			a.popStmts()
		case *ast.FuncDecl:
			a.popStmts()
		}
		a.popNode()
		return nil
	}
	pos := a.fset.Position(node.Pos())
	switch x := node.(type) {
	case *ast.File:
		pname := x.Name.Name
		if pname != "main" {
			log.Fatalf(`Package name is not "main": "%s"`, pname)
		}
		imports := x.Imports
		for _, imp := range imports {
			path := strUnquote(imp.Path.Value)
			if _, e := allowedImports[path]; !e {
				log.Fatalf(`Import path not allowed: "%s"`, path)
			}
		}
	case *ast.BasicLit:
		lit := statement{
			ID:    a.newID(),
			Line:  pos.Line,
			Type:  "string",
			Value: strUnquote(x.Value),
		}
		a.addStmt(lit)
	case *ast.CallExpr:
		name := exprToString(x.Fun)
		if newname, e := funcNames[name]; e {
			name = newname
		}
		call := statement{
			ID:   a.newID(),
			Line: pos.Line,
			Type: "function-call",
			Name: name,
		}
		a.addStmt(call)
		a.pushStmts(&call.Args)
	case *ast.FuncDecl:
		name := x.Name.Name
		fn := statement{
			ID:   a.newID(),
			Line: pos.Line,
			Type: "function-declaration",
			Name: name,
			RetType: &dataType{
				ID: a.newID(),
			},
			Block: &block{
				ID:    a.newID(),
				Stmts: make([]statement, 0),
			},
		}
		for _, f := range flattenFieldList(x.Type.Params) {
			param := parameter{
				ID:   a.newID(),
				Name: f.varName,
				DataType: dataType{
					ID:   a.newID(),
					Name: f.typeName,
				},
			}
			fn.Params = append(fn.Params, param)
		}
		results := x.Type.Results
		switch results.NumFields() {
		case 0:
			fn.RetType.Name = "void"
			if name == "main" {
				fn.RetType.Name = "int"
			}
		case 1:
			fn.RetType.Name = exprToString(results.List[0].Type)
		}
		a.addStmt(fn)
		a.pushStmts(&fn.Block.Stmts)
	case *ast.BlockStmt:
	case *ast.ExprStmt:
	case *ast.FieldList:
	case *ast.FuncType:
	case *ast.GenDecl:
	case *ast.Ident:
	case *ast.SelectorExpr:
	default:
		return nil
	}
	a.pushNode(node)
	return a
}
<commit_msg>Ignore FuncType subtrees<commit_after>package superast

import (
	"go/ast"
	"go/token"
	"log"
	"strconv"
)

var allowedImports = map[string]struct{}{
	"fmt": struct{}{},
	"log": struct{}{},
}

type block struct {
	ID    int         `json:"id"`
	Stmts []statement `json:"statements"`
}

type dataType struct {
	ID   int    `json:"id"`
	Name string `json:"name"`
}

type parameter struct {
	ID       int      `json:"id"`
	Name     string   `json:"name"`
	DataType dataType `json:"data-type"`
}

type statement struct {
	ID      int         `json:"id"`
	Line    int         `json:"line"`
	Type    string      `json:"type"`
	Name    string      `json:"name,omitempty"`
	Value   string      `json:"value,omitempty"`
	RetType *dataType   `json:"return-type,omitempty"`
	Params  []parameter `json:"parameters,omitempty"`
	Args    []statement `json:"arguments,omitempty"`
	Left    *statement  `json:"left,omitempty"`
	Right   *statement  `json:"right,omitempty"`
	Block   *block      `json:"block,omitempty"`
}

type AST struct {
	curID      int
	RootBlock  *block
	nodeStack  []ast.Node
	stmtsStack []*[]statement
	fset       *token.FileSet
}

func NewAST(fset *token.FileSet) *AST {
	a := &AST{
		curID: 1,
		fset:  fset,
		RootBlock: &block{
			ID:    0,
			Stmts: make([]statement, 0),
		},
	}
	a.pushStmts(&a.RootBlock.Stmts)
	return a
}

func (a *AST) newID() int {
	i := a.curID
	a.curID++
	return i
}

func (a *AST) pushNode(node ast.Node) {
	a.nodeStack = append(a.nodeStack, node)
}

func (a *AST) curNode() ast.Node {
	if len(a.nodeStack) == 0 {
		return nil
	}
	return a.nodeStack[len(a.nodeStack)-1]
}

func (a *AST) popNode() {
	if len(a.nodeStack) == 0 {
		return
	}
	a.nodeStack = a.nodeStack[:len(a.nodeStack)-1]
}

func (a *AST) pushStmts(stmts *[]statement) {
	a.stmtsStack = append(a.stmtsStack, stmts)
}

func (a *AST) addStmt(stmt statement) {
	if len(a.stmtsStack) == 0 {
		return
	}
	curStmts := a.stmtsStack[len(a.stmtsStack)-1]
	*curStmts = append(*curStmts, stmt)
}

func (a *AST) popStmts() {
	if len(a.stmtsStack) == 0 {
		return
	}
	a.stmtsStack = a.stmtsStack[:len(a.stmtsStack)-1]
}

func strUnquote(s string) string {
	u, err := strconv.Unquote(s)
	if err != nil {
		log.Fatalf("Error when unquoting string: %s", err)
	}
	return u
}

func exprToString(x ast.Expr) string {
	switch t := x.(type) {
	case *ast.Ident:
		return t.Name
	case *ast.SelectorExpr:
		return exprToString(t.X) + "." + t.Sel.Name
	case *ast.StarExpr:
		return exprToString(t.X)
	}
	return ""
}

var funcNames = map[string]string{
	"fmt.Println": "print",
	"println":     "print",
}

type field struct {
	varName, typeName string
}

func flattenFieldList(fieldList *ast.FieldList) []field {
	var fields []field
	for _, f := range fieldList.List {
		t := exprToString(f.Type)
		for _, n := range f.Names {
			fields = append(fields, field{
				varName:  n.Name,
				typeName: t,
			})
		}
	}
	return fields
}

func (a *AST) Visit(node ast.Node) ast.Visitor {
	parentNode := a.curNode()
	if node == nil {
		switch parentNode.(type) {
		case *ast.CallExpr:
			a.popStmts()
		case *ast.FuncDecl:
			a.popStmts()
		}
		a.popNode()
		return nil
	}
	pos := a.fset.Position(node.Pos())
	switch x := node.(type) {
	case *ast.File:
		pname := x.Name.Name
		if pname != "main" {
			log.Fatalf(`Package name is not "main": "%s"`, pname)
		}
		imports := x.Imports
		for _, imp := range imports {
			path := strUnquote(imp.Path.Value)
			if _, e := allowedImports[path]; !e {
				log.Fatalf(`Import path not allowed: "%s"`, path)
			}
		}
	case *ast.BasicLit:
		lit := statement{
			ID:    a.newID(),
			Line:  pos.Line,
			Type:  "string",
			Value: strUnquote(x.Value),
		}
		a.addStmt(lit)
	case *ast.CallExpr:
		name := exprToString(x.Fun)
		if newname, e := funcNames[name]; e {
			name = newname
		}
		call := statement{
			ID:   a.newID(),
			Line: pos.Line,
			Type: "function-call",
			Name: name,
		}
		a.addStmt(call)
		a.pushStmts(&call.Args)
	case *ast.FuncDecl:
		name := x.Name.Name
		fn := statement{
			ID:   a.newID(),
			Line: pos.Line,
			Type: "function-declaration",
			Name: name,
			RetType: &dataType{
				ID: a.newID(),
			},
			Block: &block{
				ID:    a.newID(),
				Stmts: make([]statement, 0),
			},
		}
		for _, f := range flattenFieldList(x.Type.Params) {
			param := parameter{
				ID:   a.newID(),
				Name: f.varName,
				DataType: dataType{
					ID:   a.newID(),
					Name: f.typeName,
				},
			}
			fn.Params = append(fn.Params, param)
		}
		results := x.Type.Results
		switch results.NumFields() {
		case 0:
			fn.RetType.Name = "void"
			if name == "main" {
				fn.RetType.Name = "int"
			}
		case 1:
			fn.RetType.Name = exprToString(results.List[0].Type)
		}
		a.addStmt(fn)
		a.pushStmts(&fn.Block.Stmts)
	case *ast.BlockStmt:
	case *ast.ExprStmt:
	case *ast.FieldList:
	case *ast.GenDecl:
	case *ast.Ident:
	case *ast.SelectorExpr:
	default:
		return nil
	}
	a.pushNode(node)
	return a
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"reflect"
	"regexp"

	"github.com/codegangsta/cli"
	"github.com/olekukonko/tablewriter"
	"github.com/wsxiaoys/terminal/color"
	"gopkg.in/yaml.v1"
)

const (
	LIST_PROJECTS_PATH         = "/projects"
	CREATE_PROJECT_PATH        = "/projects"
	LIVE_EVAL_PATH             = "/evaluate"
	SUPPORTED_DEPENDENCY_FILES = `(Gemfile|Gemfile\.lock|.*\.gemspec|package\.json|npm-shrinkwrap\.json|setup\.py|requirements\.txt|requires\.txt|composer\.json|composer\.lock)$`
)

// List projects on gemnasium
// TODO: Add a flag to display unmonitored projects too
func ListProjects(config *Config, privateProjectsOnly bool) error {
	client := &http.Client{}
	url := config.APIEndpoint + LIST_PROJECTS_PATH
	req, err := NewAPIRequest("GET", url, config.APIKey, nil)
	if err != nil {
		return err
	}
	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("Server returned non-200 status: %v\n", resp.Status)
	}

	// if RawFormat flag is set, don't format the output
	if config.RawFormat {
		fmt.Printf("%s", body)
		return nil
	}

	// Parse server response
	var projects map[string][]Project
	if err := json.Unmarshal(body, &projects); err != nil {
		return err
	}
	for owner, _ := range projects {
		MonitoredProjectsCount := 0
		if owner != "owned" {
			fmt.Printf("\nShared by: %s\n\n", owner)
		}
		table := tablewriter.NewWriter(os.Stdout)
		table.SetHeader([]string{"Name", "Slug", "Private"})
		for _, project := range projects[owner] {
			if !project.Monitored || (!project.Private && privateProjectsOnly) {
				continue
			}

			var private string
			if project.Private {
				private = "private"
			} else {
				private = ""
			}
			table.Append([]string{project.Name, project.Slug, private})
			MonitoredProjectsCount += 1
		}
		table.Render()
		color.Printf("@{g!}Found %d projects (%d unmonitored are hidden)\n\n", MonitoredProjectsCount, len(projects[owner])-MonitoredProjectsCount)
	}
	return nil
}

// Display project details
// http://docs.gemnasium.apiary.io/#get-%2Fprojects%2F%7Bslug%7D
func ShowProject(slug string, config *Config) error {
	if slug == "" {
		return errors.New("[slug] can't be empty")
	}
	client := &http.Client{}
	url := fmt.Sprintf("%s/projects/%s", config.APIEndpoint, slug)
	req, err := NewAPIRequest("GET", url, config.APIKey, nil)
	if err != nil {
		return err
	}
	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("Server returned non-200 status: %v\n", resp.Status)
	}

	// if RawFormat flag is set, don't format the output
	if config.RawFormat {
		fmt.Printf("%s", body)
		return nil
	}

	// Parse server response
	var project Project
	if err := json.Unmarshal(body, &project); err != nil {
		return err
	}
	s := reflect.ValueOf(&project).Elem()
	typeOfT := s.Type()
	for i := 0; i < s.NumField(); i++ {
		f := s.Field(i)
		if typeOfT.Field(i).Name == "Status" {
			color.Println(fmt.Sprintf("%18.18s: %s", "Status", statusDots(project.Status)))
		} else {
			fmt.Printf("%18.18s: %v\n", typeOfT.Field(i).Name, f.Interface())
		}
	}

	return nil
}

// Update project details
// http://docs.gemnasium.apiary.io/#patch-%2Fprojects%2F%7Bslug%7D
func UpdateProject(slug string, config *Config, name, desc *string, monitored *bool) error {
	if slug == "" {
		return errors.New("[slug] can't be empty")
	}

	if name == nil && desc == nil && monitored == nil {
		return errors.New("Please specify at least one thing to update (name, desc, or monitored")
	}

	update := make(map[string]interface{})
	if name != nil {
		update["name"] = *name
	}
	if desc != nil {
		update["desc"] = *desc
	}
	if monitored != nil {
		update["monitored"] = *monitored
	}
	projectAsJson, err := json.Marshal(update)
	if err != nil {
		return err
	}
	client := &http.Client{}
	url := fmt.Sprintf("%s/projects/%s", config.APIEndpoint, slug)
	req, err := NewAPIRequest("PATCH", url, config.APIKey, bytes.NewReader(projectAsJson))

	if err != nil {
		return err
	}
	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("Server returned non-200 status: %v\n", resp.Status)
	}

	// if RawFormat flag is set, don't format the output
	if config.RawFormat {
		fmt.Printf("%s", body)
		return nil
	}

	color.Printf("@gProject %s updated succesfully\n", slug)

	return nil
}

// Create a new project on gemnasium.
// The first arg is used as the project name.
// If no arg is provided, the user will be prompted to enter a project name.
// http://docs.gemnasium.apiary.io/#post-%2Fprojects
func CreateProject(projectName string, config *Config, r io.Reader) error {
	project := &Project{Name: projectName}
	if project.Name == "" {
		fmt.Printf("Enter project name: ")
		_, err := fmt.Scanln(&project.Name)
		if err != nil {
			return err
		}
	}
	fmt.Printf("Enter project description: ")
	_, err := fmt.Fscanf(r, "%s", &project.Description)
	if err != nil {
		return err
	}
	fmt.Println("") // quickfix for goconvey

	projectAsJson, err := json.Marshal(project)
	if err != nil {
		return err
	}
	client := &http.Client{}
	req, err := http.NewRequest("POST", config.APIEndpoint+CREATE_PROJECT_PATH, bytes.NewReader(projectAsJson))
	if err != nil {
		return err
	}
	req.SetBasicAuth("x", config.APIKey)
	req.Header.Add("Content-Type", "application/json")
	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("Server returned non-200 status: %v\n", resp.Status)
	}

	// Parse server response
	var jsonResp map[string]interface{}
	if err := json.Unmarshal(body, &jsonResp); err != nil {
		return err
	}
	fmt.Printf("Project '%s' created! (Remaining private slots: %v)\n", project.Name, jsonResp["remaining_slot_count"])
	fmt.Printf("To configure this project, use the following command:\ngemnasium projects configure %s\n", jsonResp["slug"])
	return nil
}

// Create a project config gile (.gemnasium.yml)
func ConfigureProject(slug string, config *Config, r io.Reader, f *os.File) error {

	if slug == "" {
		fmt.Printf("Enter project slug: ")
		_, err := fmt.Scanln(&slug)
		if err != nil {
			return err
		}
	}

	// We just create a file with project_config for now.
	projectConfig := &map[string]string{"project_slug": slug}
	body, err := yaml.Marshal(&projectConfig)
	if err != nil {
		log.Fatalf("error: %v", err)
	}
	// write content to the file
	_, err = f.Write(body)
	if err != nil {
		return err
	}
	// Issue a Sync to flush writes to stable storage.
	f.Sync()
	return nil
}

// Push project dependencies
// Not yet implemented and WIP
func PushDependencies(ctx *cli.Context, config *Config) error {
	deps := []DependencyFile{}
	searchDeps := func(path string, info os.FileInfo, err error) error {

		// Skip excluded paths
		if info.IsDir() && info.Name() == ".git" {
			return filepath.SkipDir
		}
		matched, err := regexp.MatchString(SUPPORTED_DEPENDENCY_FILES, info.Name())
		if err != nil {
			return err
		}

		if matched {
			fmt.Printf("[debug] Found: %s\n", info.Name())
			deps = append(deps, DependencyFile{Name: info.Name(), SHA: "sha", Content: []byte("content")})
		}
		return nil
	}
	filepath.Walk(".", searchDeps)
	fmt.Printf("deps %+v\n", deps)
	return nil
}

// Start project synchronization
// http://docs.gemnasium.apiary.io/#post-%2Fprojects%2F%7Bslug%7D%2Fsync
func SyncProject(projectSlug string, config *Config) error {
	if projectSlug == "" {
		return errors.New("[projectSlug] can't be empty")
	}
	client := &http.Client{}
	url := fmt.Sprintf("%s/projects/%s/sync", config.APIEndpoint, projectSlug)
	req, err := NewAPIRequest("POST", url, config.APIKey, nil)
	if err != nil {
		return err
	}

	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusNoContent {
		return fmt.Errorf("Server returned non-200 status: %v\n", resp.Status)
	}

	color.Printf("@gSynchronization started for project %s\n", projectSlug)
	return nil
}
<commit_msg>Use NewAPIRequest helper<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"reflect"
	"regexp"

	"github.com/codegangsta/cli"
	"github.com/olekukonko/tablewriter"
	"github.com/wsxiaoys/terminal/color"
	"gopkg.in/yaml.v1"
)

const (
	LIST_PROJECTS_PATH         = "/projects"
	CREATE_PROJECT_PATH        = "/projects"
	LIVE_EVAL_PATH             = "/evaluate"
	SUPPORTED_DEPENDENCY_FILES = `(Gemfile|Gemfile\.lock|.*\.gemspec|package\.json|npm-shrinkwrap\.json|setup\.py|requirements\.txt|requires\.txt|composer\.json|composer\.lock)$`
)

// List projects on gemnasium
// TODO: Add a flag to display unmonitored projects too
func ListProjects(config *Config, privateProjectsOnly bool) error {
	client := &http.Client{}
	url := config.APIEndpoint + LIST_PROJECTS_PATH
	req, err := NewAPIRequest("GET", url, config.APIKey, nil)
	if err != nil {
		return err
	}
	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("Server returned non-200 status: %v\n", resp.Status)
	}

	// if RawFormat flag is set, don't format the output
	if config.RawFormat {
		fmt.Printf("%s", body)
		return nil
	}

	// Parse server response
	var projects map[string][]Project
	if err := json.Unmarshal(body, &projects); err != nil {
		return err
	}
	for owner, _ := range projects {
		MonitoredProjectsCount := 0
		if owner != "owned" {
			fmt.Printf("\nShared by: %s\n\n", owner)
		}
		table := tablewriter.NewWriter(os.Stdout)
		table.SetHeader([]string{"Name", "Slug", "Private"})
		for _, project := range projects[owner] {
			if !project.Monitored || (!project.Private && privateProjectsOnly) {
				continue
			}

			var private string
			if project.Private {
				private = "private"
			} else {
				private = ""
			}
			table.Append([]string{project.Name, project.Slug, private})
			MonitoredProjectsCount += 1
		}
		table.Render()
		color.Printf("@{g!}Found %d projects (%d unmonitored are hidden)\n\n", MonitoredProjectsCount, len(projects[owner])-MonitoredProjectsCount)
	}
	return nil
}

// Display project details
// http://docs.gemnasium.apiary.io/#get-%2Fprojects%2F%7Bslug%7D
func ShowProject(slug string, config *Config) error {
	if slug == "" {
		return errors.New("[slug] can't be empty")
	}
	client := &http.Client{}
	url := fmt.Sprintf("%s/projects/%s", config.APIEndpoint, slug)
	req, err := NewAPIRequest("GET", url, config.APIKey, nil)
	if err != nil {
		return err
	}
	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("Server returned non-200 status: %v\n", resp.Status)
	}

	// if RawFormat flag is set, don't format the output
	if config.RawFormat {
		fmt.Printf("%s", body)
		return nil
	}

	// Parse server response
	var project Project
	if err := json.Unmarshal(body, &project); err != nil {
		return err
	}
	s := reflect.ValueOf(&project).Elem()
	typeOfT := s.Type()
	for i := 0; i < s.NumField(); i++ {
		f := s.Field(i)
		if typeOfT.Field(i).Name == "Status" {
			color.Println(fmt.Sprintf("%18.18s: %s", "Status", statusDots(project.Status)))
		} else {
			fmt.Printf("%18.18s: %v\n", typeOfT.Field(i).Name, f.Interface())
		}
	}

	return nil
}

// Update project details
// http://docs.gemnasium.apiary.io/#patch-%2Fprojects%2F%7Bslug%7D
func UpdateProject(slug string, config *Config, name, desc *string, monitored *bool) error {
	if slug == "" {
		return errors.New("[slug] can't be empty")
	}

	if name == nil && desc == nil && monitored == nil {
		return errors.New("Please specify at least one thing to update (name, desc, or monitored")
	}

	update := make(map[string]interface{})
	if name != nil {
		update["name"] = *name
	}
	if desc != nil {
		update["desc"] = *desc
	}
	if monitored != nil {
		update["monitored"] = *monitored
	}
	projectAsJson, err := json.Marshal(update)
	if err != nil {
		return err
	}
	client := &http.Client{}
	url := fmt.Sprintf("%s/projects/%s", config.APIEndpoint, slug)
	req, err := NewAPIRequest("PATCH", url, config.APIKey, bytes.NewReader(projectAsJson))

	if err != nil {
		return err
	}
	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("Server returned non-200 status: %v\n", resp.Status)
	}

	// if RawFormat flag is set, don't format the output
	if config.RawFormat {
		fmt.Printf("%s", body)
		return nil
	}

	color.Printf("@gProject %s updated succesfully\n", slug)

	return nil
}

// Create a new project on gemnasium.
// The first arg is used as the project name.
// If no arg is provided, the user will be prompted to enter a project name.
// http://docs.gemnasium.apiary.io/#post-%2Fprojects
func CreateProject(projectName string, config *Config, r io.Reader) error {
	project := &Project{Name: projectName}
	if project.Name == "" {
		fmt.Printf("Enter project name: ")
		_, err := fmt.Scanln(&project.Name)
		if err != nil {
			return err
		}
	}
	fmt.Printf("Enter project description: ")
	_, err := fmt.Fscanf(r, "%s", &project.Description)
	if err != nil {
		return err
	}
	fmt.Println("") // quickfix for goconvey

	projectAsJson, err := json.Marshal(project)
	if err != nil {
		return err
	}
	client := &http.Client{}
	req, err := NewAPIRequest("POST", config.APIEndpoint+CREATE_PROJECT_PATH, config.APIKey, bytes.NewReader(projectAsJson))
	if err != nil {
		return err
	}
	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("Server returned non-200 status: %v\n", resp.Status)
	}

	// Parse server response
	var jsonResp map[string]interface{}
	if err := json.Unmarshal(body, &jsonResp); err != nil {
		return err
	}
	fmt.Printf("Project '%s' created! (Remaining private slots: %v)\n", project.Name, jsonResp["remaining_slot_count"])
	fmt.Printf("To configure this project, use the following command:\ngemnasium projects configure %s\n", jsonResp["slug"])
	return nil
}

// Create a project config gile (.gemnasium.yml)
func ConfigureProject(slug string, config *Config, r io.Reader, f *os.File) error {

	if slug == "" {
		fmt.Printf("Enter project slug: ")
		_, err := fmt.Scanln(&slug)
		if err != nil {
			return err
		}
	}

	// We just create a file with project_config for now.
	projectConfig := &map[string]string{"project_slug": slug}
	body, err := yaml.Marshal(&projectConfig)
	if err != nil {
		log.Fatalf("error: %v", err)
	}
	// write content to the file
	_, err = f.Write(body)
	if err != nil {
		return err
	}
	// Issue a Sync to flush writes to stable storage.
	f.Sync()
	return nil
}

// Push project dependencies
// Not yet implemented and WIP
func PushDependencies(ctx *cli.Context, config *Config) error {
	deps := []DependencyFile{}
	searchDeps := func(path string, info os.FileInfo, err error) error {

		// Skip excluded paths
		if info.IsDir() && info.Name() == ".git" {
			return filepath.SkipDir
		}
		matched, err := regexp.MatchString(SUPPORTED_DEPENDENCY_FILES, info.Name())
		if err != nil {
			return err
		}

		if matched {
			fmt.Printf("[debug] Found: %s\n", info.Name())
			deps = append(deps, DependencyFile{Name: info.Name(), SHA: "sha", Content: []byte("content")})
		}
		return nil
	}
	filepath.Walk(".", searchDeps)
	fmt.Printf("deps %+v\n", deps)
	return nil
}

// Start project synchronization
// http://docs.gemnasium.apiary.io/#post-%2Fprojects%2F%7Bslug%7D%2Fsync
func SyncProject(projectSlug string, config *Config) error {
	if projectSlug == "" {
		return errors.New("[projectSlug] can't be empty")
	}
	client := &http.Client{}
	url := fmt.Sprintf("%s/projects/%s/sync", config.APIEndpoint, projectSlug)
	req, err := NewAPIRequest("POST", url, config.APIKey, nil)
	if err != nil {
		return err
	}

	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusNoContent {
		return fmt.Errorf("Server returned non-200 status: %v\n", resp.Status)
	}

	color.Printf("@gSynchronization started for project %s\n", projectSlug)
	return nil
}
<|endoftext|>


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

package walk

type Property struct {
	name                  string
	get                   func() interface{}
	set                   func(v interface{}) error
	validator             Validator
	source                interface{}
	sourceChangedHandle   int
	changedEventPublisher *EventPublisher
	customChangedEvent    *Event
}

func NewProperty(name string, get func() interface{}, set func(v interface{}) error, customChangedEvent *Event) *Property {
	p := &Property{name: name, get: get, set: set}

	if customChangedEvent != nil {
		p.customChangedEvent = customChangedEvent
	} else {
		p.changedEventPublisher = new(EventPublisher)
	}

	return p
}

func (p *Property) Name() string {
	return p.name
}

func (p *Property) Get() interface{} {
	return p.get()
}

func (p *Property) Set(v interface{}) error {
	p.assertNotReadOnly()

	if v == p.Get() {
		return nil
	}

	if err := p.set(v); err != nil {
		return err
	}

	if p.customChangedEvent == nil {
		p.changedEventPublisher.Publish()
	}

	return nil
}

func (p *Property) Validator() Validator {
	return p.validator
}

func (p *Property) SetValidator(v Validator) {
	p.validator = v
}

func (p *Property) Source() interface{} {
	return p.source
}

func (p *Property) SetSource(source interface{}) {
	switch source := source.(type) {
	case *Property:
		if source != nil {
			p.assertNotReadOnly()
		}

		for cur := source; cur != nil; cur, _ = cur.source.(*Property) {
			if cur == p {
				panic("source cycle")
			}
		}

		if source != nil {
			p.Set(source.Get())

			p.sourceChangedHandle = source.Changed().Attach(func() {
				p.Set(source.Get())
			})
		}

	case string:
		// nop

	default:
		panic("invalid source type")
	}

	if oldProp, ok := p.source.(*Property); ok {
		oldProp.Changed().Detach(p.sourceChangedHandle)
	}

	p.source = source
}

func (p *Property) Changed() *Event {
	if p.customChangedEvent != nil {
		return p.customChangedEvent
	}

	return p.changedEventPublisher.Event()
}

func (p *Property) ReadOnly() bool {
	return p.set == nil
}

func (p *Property) assertNotReadOnly() {
	if p.ReadOnly() {
		panic("property is read-only")
	}
}
<commit_msg>Property: Workaround Visible property not working properly<commit_after>// Copyright 2012 The Walk Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package walk

type Property struct {
	name                  string
	get                   func() interface{}
	set                   func(v interface{}) error
	validator             Validator
	source                interface{}
	sourceChangedHandle   int
	changedEventPublisher *EventPublisher
	customChangedEvent    *Event
}

func NewProperty(name string, get func() interface{}, set func(v interface{}) error, customChangedEvent *Event) *Property {
	p := &Property{name: name, get: get, set: set}

	if customChangedEvent != nil {
		p.customChangedEvent = customChangedEvent
	} else {
		p.changedEventPublisher = new(EventPublisher)
	}

	return p
}

func (p *Property) Name() string {
	return p.name
}

func (p *Property) Get() interface{} {
	return p.get()
}

func (p *Property) Set(v interface{}) error {
	p.assertNotReadOnly()

	// FIXME: Ugly special case for Visible property
	if p.name != "Visible" && v == p.Get() {
		return nil
	}

	if err := p.set(v); err != nil {
		return err
	}

	if p.customChangedEvent == nil {
		p.changedEventPublisher.Publish()
	}

	return nil
}

func (p *Property) Validator() Validator {
	return p.validator
}

func (p *Property) SetValidator(v Validator) {
	p.validator = v
}

func (p *Property) Source() interface{} {
	return p.source
}

func (p *Property) SetSource(source interface{}) {
	switch source := source.(type) {
	case *Property:
		if source != nil {
			p.assertNotReadOnly()
		}

		for cur := source; cur != nil; cur, _ = cur.source.(*Property) {
			if cur == p {
				panic("source cycle")
			}
		}

		if source != nil {
			p.Set(source.Get())

			p.sourceChangedHandle = source.Changed().Attach(func() {
				p.Set(source.Get())
			})
		}

	case string:
		// nop

	default:
		panic("invalid source type")
	}

	if oldProp, ok := p.source.(*Property); ok {
		oldProp.Changed().Detach(p.sourceChangedHandle)
	}

	p.source = source
}

func (p *Property) Changed() *Event {
	if p.customChangedEvent != nil {
		return p.customChangedEvent
	}

	return p.changedEventPublisher.Event()
}

func (p *Property) ReadOnly() bool {
	return p.set == nil
}

func (p *Property) assertNotReadOnly() {
	if p.ReadOnly() {
		panic("property is read-only")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"archive/tar"
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"os/user"
	"path/filepath"
)

/*
Markdownd uses pygments, a Python tool, for syntax highlighting. If possible, I want to ship markdownd as a
single binary. To this end, I'm using the following strategy:

1. Tar up the vendor directory (containing pygments) and calculate the md5sum.
2. Use github.com/jteeuwen/go-bindata to write a Go file that embeds the tarball
3. Add the md5 to that file as well
4. When markdownd runs, first check for a vendored pygments colocated with the binary (in case we're running in
   development, for example).
5. If it does not exist, check for ~/.markdownd/.
6. If ~/.markdownd exists, then ~/.markdownd/md5 should contain an md5 checksum. See if it matches.
7. If the checksum doesn't match, or if ~/.markdownd doesn't exist, write out and untar the vendored data into
   ~/.markdownd, along with the current checksum.
8. Use pygments in ~/.markdownd.

1-3 are accomplished by the 'make vendor_data.go' task.
*/

const (
	pygmentPath = "vendor/pygments/pygmentize"
	// Relative to the user's home dir.
	pygmentsCache    = ".markdownd"
	cacheMD5Filename = "checksum"
)

func findPygments() (string, error) {
	// First see if pygments is located alongside the binary.
	exe, err := exec.LookPath(os.Args[0])
	if err == nil {
		pygmentize = filepath.Join(filepath.Dir(exe), pygmentPath)
		if _, err := os.Stat(pygmentize); err == nil {
			dbg.Println("found dev pygments in", filepath.Dir(exe))
			return pygmentize, nil
		}
	}

	// Next see if the cached version exists and is up-to-date.
	u, err := user.Current()
	if err != nil {
		return "", err
	}
	cache := filepath.Join(u.HomeDir, pygmentsCache)
	md5File := filepath.Join(cache, cacheMD5Filename)
	pygmentize = filepath.Join(cache, pygmentPath)
	oldMD5, err := ioutil.ReadFile(md5File)
	if err == nil {
		if string(bytes.TrimSpace(oldMD5)) == VendorMD5 {
			// Up-to-date
			dbg.Println("found up-to-date cached pygments.")
			return pygmentPath, nil
		}
		fmt.Fprintln(os.Stderr, "Updating stale cache in", cache)
	}

	// Need to delete the existing, stale cache version (if it exists) and write out a new one.
	fmt.Fprintln(os.Stderr, "Writing out pygments cache to", cache)
	if err := os.RemoveAll(cache); err != nil {
		return "", err
	}
	if err := os.Mkdir(cache, 0755); err != nil {
		return "", err
	}

	if err := expandTarArchive(cache); err != nil {
		return "", err
	}
	if err := ioutil.WriteFile(md5File, []byte(VendorMD5), 0600); err != nil {
		return "", err
	}

	return pygmentize, nil
}

func expandTarArchive(loc string) error {
	vendorData := bytes.NewBuffer(VendorData())
	reader := tar.NewReader(vendorData)
	for {
		f, err := reader.Next()
		if err == io.EOF {
			break
		} else if err != nil {
			return err
		}
		if f.Typeflag != tar.TypeReg && f.Typeflag != tar.TypeRegA {
			continue
		}
		name := filepath.Join(loc, f.Name)
		if err := os.MkdirAll(filepath.Dir(name), 0755); err != nil {
			return err
		}
		flags := os.O_WRONLY | os.O_CREATE | os.O_EXCL
		file, err := os.OpenFile(name, flags, os.FileMode(f.Mode))
		if err != nil {
			return err
		}
		defer file.Close()
		if _, err := io.Copy(file, reader); err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>Bug fix.<commit_after>package main

import (
	"archive/tar"
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"os/user"
	"path/filepath"
)

/*
Markdownd uses pygments, a Python tool, for syntax highlighting. If possible, I want to ship markdownd as a
single binary. To this end, I'm using the following strategy:

1. Tar up the vendor directory (containing pygments) and calculate the md5sum.
2. Use github.com/jteeuwen/go-bindata to write a Go file that embeds the tarball
3. Add the md5 to that file as well
4. When markdownd runs, first check for a vendored pygments colocated with the binary (in case we're running in
   development, for example).
5. If it does not exist, check for ~/.markdownd/.
6. If ~/.markdownd exists, then ~/.markdownd/md5 should contain an md5 checksum. See if it matches.
7. If the checksum doesn't match, or if ~/.markdownd doesn't exist, write out and untar the vendored data into
   ~/.markdownd, along with the current checksum.
8. Use pygments in ~/.markdownd.

1-3 are accomplished by the 'make vendor_data.go' task.
*/

const (
	pygmentPath = "vendor/pygments/pygmentize"
	// Relative to the user's home dir.
	pygmentsCache    = ".markdownd"
	cacheMD5Filename = "checksum"
)

func findPygments() (string, error) {
	// First see if pygments is located alongside the binary.
	exe, err := exec.LookPath(os.Args[0])
	if err == nil {
		pygmentize = filepath.Join(filepath.Dir(exe), pygmentPath)
		if _, err := os.Stat(pygmentize); err == nil {
			dbg.Println("found dev pygments in", filepath.Dir(exe))
			return pygmentize, nil
		}
	}

	// Next see if the cached version exists and is up-to-date.
	u, err := user.Current()
	if err != nil {
		return "", err
	}
	cache := filepath.Join(u.HomeDir, pygmentsCache)
	md5File := filepath.Join(cache, cacheMD5Filename)
	pygmentize = filepath.Join(cache, pygmentPath)
	oldMD5, err := ioutil.ReadFile(md5File)
	if err == nil {
		if string(bytes.TrimSpace(oldMD5)) == VendorMD5 {
			// Up-to-date
			dbg.Println("found up-to-date cached pygments.")
			return pygmentize, nil
		}
		fmt.Fprintln(os.Stderr, "Updating stale cache in", cache)
	}

	// Need to delete the existing, stale cache version (if it exists) and write out a new one.
	fmt.Fprintln(os.Stderr, "Writing out pygments cache to", cache)
	if err := os.RemoveAll(cache); err != nil {
		return "", err
	}
	if err := os.Mkdir(cache, 0755); err != nil {
		return "", err
	}

	if err := expandTarArchive(cache); err != nil {
		return "", err
	}
	if err := ioutil.WriteFile(md5File, []byte(VendorMD5), 0600); err != nil {
		return "", err
	}

	return pygmentize, nil
}

func expandTarArchive(loc string) error {
	vendorData := bytes.NewBuffer(VendorData())
	reader := tar.NewReader(vendorData)
	for {
		f, err := reader.Next()
		if err == io.EOF {
			break
		} else if err != nil {
			return err
		}
		if f.Typeflag != tar.TypeReg && f.Typeflag != tar.TypeRegA {
			continue
		}
		name := filepath.Join(loc, f.Name)
		if err := os.MkdirAll(filepath.Dir(name), 0755); err != nil {
			return err
		}
		flags := os.O_WRONLY | os.O_CREATE | os.O_EXCL
		file, err := os.OpenFile(name, flags, os.FileMode(f.Mode))
		if err != nil {
			return err
		}
		defer file.Close()
		if _, err := io.Copy(file, reader); err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package resource

import (
	"errors"
	"reflect"

	"github.com/jinzhu/gorm"
	"github.com/qor/qor"
	"github.com/qor/qor/roles"
)

var (
	ErrProcessorRecordNotFound = errors.New("resource: record not found")
	ErrProcessorSkipLeft       = errors.New("resource: skip left")
)

type processor struct {
	Result     interface{}
	Resource   Resourcer
	Context    *qor.Context
	MetaValues *MetaValues
	SkipLeft   bool
	newRecord  bool
}

func DecodeToResource(res Resourcer, result interface{}, metaValues *MetaValues, context *qor.Context) *processor {
	scope := &gorm.Scope{Value: result}
	return &processor{Resource: res, Result: result, Context: context, MetaValues: metaValues, newRecord: scope.PrimaryKeyZero()}
}

func (processor *processor) checkSkipLeft(errs ...error) bool {
	if processor.SkipLeft {
		return true
	}

	for _, err := range errs {
		if err == ErrProcessorSkipLeft {
			processor.SkipLeft = true
			break
		}
	}
	return processor.SkipLeft
}

func (processor *processor) Initialize() error {
	err := processor.Resource.CallFindOne(processor.Result, processor.MetaValues, processor.Context)
	processor.checkSkipLeft(err)
	return err
}

func (processor *processor) Validate() error {
	var errors qor.Errors
	if processor.checkSkipLeft() {
		return nil
	}

	for _, fc := range processor.Resource.GetResource().validators {
		if errors.AddError(fc(processor.Result, processor.MetaValues, processor.Context)); !errors.HasError() {
			if processor.checkSkipLeft(errors.GetErrors()...) {
				break
			}
		}
	}
	return errors
}

func (processor *processor) decode() (errors []error) {
	if processor.checkSkipLeft() {
		return
	}

	for _, metaValue := range processor.MetaValues.Values {
		meta := metaValue.Meta
		if meta == nil {
			continue
		}

		if processor.newRecord && !meta.HasPermission(roles.Create, processor.Context) {
			continue
		} else if !meta.HasPermission(roles.Update, processor.Context) {
			continue
		}

		if metaValue.MetaValues == nil {
			if setter := meta.GetSetter(); setter != nil {
				setter(processor.Result, metaValue, processor.Context)
			}
			continue
		}

		res := metaValue.Meta.GetResource()
		if res == nil {
			continue
		}

		field := reflect.Indirect(reflect.ValueOf(processor.Result)).FieldByName(meta.GetFieldName())
		if field.Kind() == reflect.Struct {
			association := field.Addr().Interface()
			DecodeToResource(res, association, metaValue.MetaValues, processor.Context).Start()
		} else if field.Kind() == reflect.Slice {
			value := reflect.New(field.Type().Elem())
			associationProcessor := DecodeToResource(res, value.Interface(), metaValue.MetaValues, processor.Context)
			associationProcessor.Start()
			if !associationProcessor.SkipLeft {
				if !reflect.DeepEqual(reflect.Zero(field.Type().Elem()).Interface(), value.Elem().Interface()) {
					field.Set(reflect.Append(field, value.Elem()))
				}
			}
		}
	}

	return
}

func (processor *processor) Commit() error {
	var errors qor.Errors
	errors.AddError(processor.decode()...)
	if processor.checkSkipLeft(errors.GetErrors()...) {
		return nil
	}

	for _, fc := range processor.Resource.GetResource().processors {
		if err := fc(processor.Result, processor.MetaValues, processor.Context); err != nil {
			if processor.checkSkipLeft(err) {
				break
			}
			errors.AddError(err)
		}
	}
	return errors
}

func (processor *processor) Start() error {
	var errors qor.Errors
	processor.Initialize()
	if errors.AddError(processor.Validate()); !errors.HasError() {
		errors.AddError(processor.Commit())
	}
	return errors
}
<commit_msg>Support pointer slice for relations<commit_after>package resource

import (
	"errors"
	"reflect"

	"github.com/jinzhu/gorm"
	"github.com/qor/qor"
	"github.com/qor/qor/roles"
)

var (
	ErrProcessorRecordNotFound = errors.New("resource: record not found")
	ErrProcessorSkipLeft       = errors.New("resource: skip left")
)

type processor struct {
	Result     interface{}
	Resource   Resourcer
	Context    *qor.Context
	MetaValues *MetaValues
	SkipLeft   bool
	newRecord  bool
}

func DecodeToResource(res Resourcer, result interface{}, metaValues *MetaValues, context *qor.Context) *processor {
	scope := &gorm.Scope{Value: result}
	return &processor{Resource: res, Result: result, Context: context, MetaValues: metaValues, newRecord: scope.PrimaryKeyZero()}
}

func (processor *processor) checkSkipLeft(errs ...error) bool {
	if processor.SkipLeft {
		return true
	}

	for _, err := range errs {
		if err == ErrProcessorSkipLeft {
			processor.SkipLeft = true
			break
		}
	}
	return processor.SkipLeft
}

func (processor *processor) Initialize() error {
	err := processor.Resource.CallFindOne(processor.Result, processor.MetaValues, processor.Context)
	processor.checkSkipLeft(err)
	return err
}

func (processor *processor) Validate() error {
	var errors qor.Errors
	if processor.checkSkipLeft() {
		return nil
	}

	for _, fc := range processor.Resource.GetResource().validators {
		if errors.AddError(fc(processor.Result, processor.MetaValues, processor.Context)); !errors.HasError() {
			if processor.checkSkipLeft(errors.GetErrors()...) {
				break
			}
		}
	}
	return errors
}

func (processor *processor) decode() (errors []error) {
	if processor.checkSkipLeft() {
		return
	}

	for _, metaValue := range processor.MetaValues.Values {
		meta := metaValue.Meta
		if meta == nil {
			continue
		}

		if processor.newRecord && !meta.HasPermission(roles.Create, processor.Context) {
			continue
		} else if !meta.HasPermission(roles.Update, processor.Context) {
			continue
		}

		if metaValue.MetaValues == nil {
			if setter := meta.GetSetter(); setter != nil {
				setter(processor.Result, metaValue, processor.Context)
			}
			continue
		}

		res := metaValue.Meta.GetResource()
		if res == nil {
			continue
		}

		field := reflect.Indirect(reflect.ValueOf(processor.Result)).FieldByName(meta.GetFieldName())
		if field.Kind() == reflect.Struct {
			association := field.Addr().Interface()
			DecodeToResource(res, association, metaValue.MetaValues, processor.Context).Start()
		} else if field.Kind() == reflect.Slice {
			var fieldType = field.Type().Elem()
			var isPtr bool
			if fieldType.Kind() == reflect.Ptr {
				fieldType = fieldType.Elem()
				isPtr = true
			}

			value := reflect.New(fieldType)
			associationProcessor := DecodeToResource(res, value.Interface(), metaValue.MetaValues, processor.Context)
			associationProcessor.Start()
			if !associationProcessor.SkipLeft {
				if !reflect.DeepEqual(reflect.Zero(fieldType).Interface(), value.Elem().Interface()) {
					if isPtr {
						field.Set(reflect.Append(field, value))
					} else {
						field.Set(reflect.Append(field, value.Elem()))
					}
				}
			}
		}
	}

	return
}

func (processor *processor) Commit() error {
	var errors qor.Errors
	errors.AddError(processor.decode()...)
	if processor.checkSkipLeft(errors.GetErrors()...) {
		return nil
	}

	for _, fc := range processor.Resource.GetResource().processors {
		if err := fc(processor.Result, processor.MetaValues, processor.Context); err != nil {
			if processor.checkSkipLeft(err) {
				break
			}
			errors.AddError(err)
		}
	}
	return errors
}

func (processor *processor) Start() error {
	var errors qor.Errors
	processor.Initialize()
	if errors.AddError(processor.Validate()); !errors.HasError() {
		errors.AddError(processor.Commit())
	}
	return errors
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"time"

	"github.com/ebilling/pool-controller/weather"
)

const (
	mftr       = "Bonnie Labs"
	waterGpio  = 25
	roofGpio   = 24
	buttonGpio = 18
)

// The PoolPumpController manages the relays that control the pumps based on
// data from temperature probes and the weather.
type PoolPumpController struct {
	config      *Config
	weather     *weather.Weather
	switches    *Switches
	pumpTemp    Thermometer
	runningTemp Thermometer
	roofTemp    Thermometer
	button      *Button
	tempRrd     *Rrd
	pumpRrd     *Rrd
	done        chan bool
}

// RunningWaterThermometer creates a thermometer that remembers the temperature of the water when the
// pumps were running.  This is more reprsentative of the actual water temperature,
// as the water temperature probe is near the pump, not actually in the pool.
func RunningWaterThermometer(t Thermometer, s *Switches) *SelectiveThermometer {
	return NewSelectiveThermometer("Pool", mftr, t, func() bool {
		return s.State() > STATE_OFF
	})
}

// NewPoolPumpController creates a new pump controller
func NewPoolPumpController(config *Config) *PoolPumpController {
	ppc := PoolPumpController{
		config:   config,
		weather:  weather.NewWeather(config.cfg.WeatherUndergroundAppID, 20*time.Minute),
		switches: NewSwitches(mftr),
		pumpTemp: NewGpioThermometer("Pumphouse", mftr, waterGpio),
		roofTemp: NewGpioThermometer("Poolhouse Roof", mftr, roofGpio),
		tempRrd:  NewRrd(*config.dataDirectory + "/temperature.rrd"),
		pumpRrd:  NewRrd(*config.dataDirectory + "/pumpstatus.rrd"),
		done:     make(chan bool),
	}
	ppc.SyncAdjustments()
	ppc.runningTemp = RunningWaterThermometer(ppc.pumpTemp, ppc.switches)
	return &ppc
}

// Update the solar configuration parameters from the config file (if changed)
// and updates the values of the Thermometers.
func (ppc *PoolPumpController) Update() {
	ppc.config.Save()
	ppc.pumpTemp.Update()
	ppc.roofTemp.Update()
	ppc.runningTemp.Update()
	if ppc.config.cfg.ButtonDisabled {
		ppc.button.Disable()
	} else {
		ppc.button.Enable()
	}
}

// A return value of 'True' indicates that the pool is too hot and the roof is cold
// (probably at night), running the pumps with solar on would help bring the water
// down to the target temperature.
func (ppc *PoolPumpController) shouldCool() bool {
	return false
	if ppc.config.cfg.SolarDisabled {
		return false
	}
	return ppc.pumpTemp.Temperature() > ppc.config.cfg.Target+ppc.config.cfg.Tolerance &&
		ppc.pumpTemp.Temperature() > ppc.roofTemp.Temperature()+ppc.config.cfg.DeltaT
}

// A return value of 'True' indicates that the pool is too cool and the roof is hot, running
// the pumps with solar on would help bring the water up to the target temperature.
func (ppc *PoolPumpController) shouldWarm() bool {
	if ppc.config.cfg.SolarDisabled {
		return false
	}
	return ppc.pumpTemp.Temperature() < ppc.config.cfg.Target-ppc.config.cfg.Tolerance &&
		ppc.pumpTemp.Temperature() < ppc.roofTemp.Temperature()-ppc.config.cfg.DeltaT
}

// RunPumpsIfNeeded - If the water is not within the tolerance limit of the target, and the roof
// temperature would help get the temperature to be closer to the target, the pumps will be
// turned on.  If the outdoor temperature is low or the pool is very cold, the sweep will also be
// run to help mix the water as it approaches the target.
func (ppc *PoolPumpController) RunPumpsIfNeeded() {
	state := ppc.switches.State()
	if ppc.switches.ManualState() {
		return
	}
	if state == STATE_DISABLED && !ppc.config.cfg.Disabled && !ppc.config.cfg.SolarDisabled {
		ppc.switches.setSwitches(false, false, false, false, STATE_OFF)
		return
	}
	if ppc.config.cfg.Disabled {
		if state > STATE_DISABLED {
			ppc.switches.setSwitches(false, false, false, false, STATE_DISABLED)
		}
		return
	}
	wd, werr := ppc.weather.GetWeatherByZip(ppc.config.cfg.Zip)
	if ppc.shouldCool() || ppc.shouldWarm() {
		// Wide deltaT between target and temp or when it's cold, run sweep
		if ppc.pumpTemp.Temperature() < ppc.config.cfg.Target-ppc.config.cfg.DeltaT ||
			(werr == nil && wd.CurrentTempC < ppc.config.cfg.Target) || // Cool Weather
			ppc.pumpTemp.Temperature() > ppc.config.cfg.Target+ppc.config.cfg.Tolerance {
			ppc.switches.SetState(STATE_SOLAR_MIXING, false)
		} else {
			// Just push water through the panels
			ppc.switches.SetState(STATE_SOLAR, false)
		}
		return
	}
	// If the pumps havent run in a day, wait til midnight then start them
	if time.Now().Sub(ppc.switches.GetStopTime()) > 22*time.Hour {
		ppc.switches.SetState(STATE_SWEEP, false) // Clean pool
		if time.Now().Sub(ppc.switches.GetStartTime()) > 2*time.Hour {
			ppc.switches.StopAll(false) // End daily
		}
		return
	}
	// If there is no reason to turn on the pumps and it's not manual, turn off
	if state > STATE_OFF && ppc.switches.GetStartTime().Add(time.Hour).Before(time.Now()) {
		ppc.switches.StopAll(false)
	}
}

// Runs calls PoolPumpController.Update() and PoolPumpController.RunPumpsIfNeeded()
// repeatedly until PoolPumpController.Stop() is called
func (ppc *PoolPumpController) runLoop() {
	interval := time.Minute
	postStatus := time.Now()
	keepRunning := true
	for keepRunning {
		if postStatus.Before(time.Now()) {
			postStatus = time.Now().Add(5 * time.Minute)
			Info(ppc.Status())
		}
		ppc.SyncAdjustments()
		select {
		case <-ppc.done:
			ppc.button.Stop()
			// Turn off the pumps, and don't let them turn back on
			ppc.switches.Disable()
			keepRunning = false
			break
		case <-time.After(interval):
			ppc.Update()
			ppc.RunPumpsIfNeeded()
			ppc.UpdateRrd()
		}
	}
	Alert("Exiting Controller")
}

// Start finishes initializing the PoolPumpController, and kicks off the control thread.
func (ppc *PoolPumpController) Start() {
	ppc.button = NewGpioButton(buttonGpio, func() {
		switch ppc.switches.State() {
		case STATE_OFF:
			ppc.switches.SetState(STATE_PUMP, true)
		case STATE_PUMP:
			ppc.switches.SetState(STATE_SWEEP, true)
		case STATE_SOLAR:
			ppc.switches.SetState(STATE_SOLAR_MIXING, true)
		case STATE_DISABLED:
		default:
			ppc.switches.SetState(STATE_OFF, true)
		}
	})
	// Initialize RRDs
	ppc.createRrds()

	// Start go routines
	ppc.Update()
	ppc.button.Start()
	go ppc.runLoop()
}

// Stop stops all of the pumps
func (ppc *PoolPumpController) Stop() {
	ppc.switches.StopAll(true)
	ppc.done <- true
}

// PersistCalibration saves the callibration data
func (ppc *PoolPumpController) PersistCalibration() {
	t, ok := ppc.pumpTemp.(*GpioThermometer)
	if ok {
		ppc.config.cfg.PumpAdjustment = t.adjust
	}
	t, ok = ppc.roofTemp.(*GpioThermometer)
	if ok {
		ppc.config.cfg.RoofAdjustment = t.adjust
	}
}

// SyncAdjustments syncrhonizes the adjustments to temperature sensors
func (ppc *PoolPumpController) SyncAdjustments() {
	t, ok := ppc.pumpTemp.(*GpioThermometer)
	if ok {
		t.adjust = ppc.config.cfg.PumpAdjustment
	}
	t, ok = ppc.roofTemp.(*GpioThermometer)
	if ok {
		t.adjust = ppc.config.cfg.RoofAdjustment
	}
}

// WeatherC returns the current temperature outside in degrees Celsius
func (ppc *PoolPumpController) WeatherC() float64 {
	wd, err := ppc.weather.GetWeatherByZip(ppc.config.cfg.Zip)
	if err != nil || wd == nil {
		Error("Error while reading weather: %v", err)
		return 0.0
	}
	return wd.CurrentTempC
}

// Status prints the status of the system
func (ppc *PoolPumpController) Status() string {
	return fmt.Sprintf(
		"Status(%s) Button(%s) Solar(%s) Pump(%s) Sweep(%s) Manual(%t) Target(%0.1f) "+
			"Pool(%0.1f) Pump(%0.1f) Roof(%0.1f) CurrentTemp(%0.1f)",
		ppc.switches.State(), ppc.button.pin.Read(), ppc.switches.solar.Status(),
		ppc.switches.pump.Status(), ppc.switches.sweep.Status(),
		ppc.switches.ManualState(), ppc.config.cfg.Target,
		ppc.runningTemp.Temperature(), ppc.pumpTemp.Temperature(),
		ppc.roofTemp.Temperature(), ppc.WeatherC())
}
<commit_msg>re-enable rrd writes<commit_after>package main

import (
	"fmt"
	"time"

	"github.com/ebilling/pool-controller/weather"
)

const (
	mftr       = "Bonnie Labs"
	waterGpio  = 25
	roofGpio   = 24
	buttonGpio = 18
)

// The PoolPumpController manages the relays that control the pumps based on
// data from temperature probes and the weather.
type PoolPumpController struct {
	config      *Config
	weather     *weather.Weather
	switches    *Switches
	pumpTemp    Thermometer
	runningTemp Thermometer
	roofTemp    Thermometer
	button      *Button
	tempRrd     *Rrd
	pumpRrd     *Rrd
	done        chan bool
}

// RunningWaterThermometer creates a thermometer that remembers the temperature of the water when the
// pumps were running.  This is more reprsentative of the actual water temperature,
// as the water temperature probe is near the pump, not actually in the pool.
func RunningWaterThermometer(t Thermometer, s *Switches) *SelectiveThermometer {
	return NewSelectiveThermometer("Pool", mftr, t, func() bool {
		return s.State() > STATE_OFF
	})
}

// NewPoolPumpController creates a new pump controller
func NewPoolPumpController(config *Config) *PoolPumpController {
	ppc := PoolPumpController{
		config:   config,
		weather:  weather.NewWeather(config.cfg.WeatherUndergroundAppID, 20*time.Minute),
		switches: NewSwitches(mftr),
		pumpTemp: NewGpioThermometer("Pumphouse", mftr, waterGpio),
		roofTemp: NewGpioThermometer("Poolhouse Roof", mftr, roofGpio),
		tempRrd:  NewRrd(*config.dataDirectory + "/temperature.rrd"),
		pumpRrd:  NewRrd(*config.dataDirectory + "/pumpstatus.rrd"),
		done:     make(chan bool),
	}
	ppc.SyncAdjustments()
	ppc.runningTemp = RunningWaterThermometer(ppc.pumpTemp, ppc.switches)
	return &ppc
}

// Update the solar configuration parameters from the config file (if changed)
// and updates the values of the Thermometers.
func (ppc *PoolPumpController) Update() {
	ppc.config.Save()
	ppc.pumpTemp.Update()
	ppc.roofTemp.Update()
	ppc.runningTemp.Update()
	if ppc.config.cfg.ButtonDisabled {
		ppc.button.Disable()
	} else {
		ppc.button.Enable()
	}
}

// A return value of 'True' indicates that the pool is too hot and the roof is cold
// (probably at night), running the pumps with solar on would help bring the water
// down to the target temperature.
func (ppc *PoolPumpController) shouldCool() bool {
	return false
	if ppc.config.cfg.SolarDisabled {
		return false
	}
	return ppc.pumpTemp.Temperature() > ppc.config.cfg.Target+ppc.config.cfg.Tolerance &&
		ppc.pumpTemp.Temperature() > ppc.roofTemp.Temperature()+ppc.config.cfg.DeltaT
}

// A return value of 'True' indicates that the pool is too cool and the roof is hot, running
// the pumps with solar on would help bring the water up to the target temperature.
func (ppc *PoolPumpController) shouldWarm() bool {
	if ppc.config.cfg.SolarDisabled {
		return false
	}
	return ppc.pumpTemp.Temperature() < ppc.config.cfg.Target-ppc.config.cfg.Tolerance &&
		ppc.pumpTemp.Temperature() < ppc.roofTemp.Temperature()-ppc.config.cfg.DeltaT
}

// RunPumpsIfNeeded - If the water is not within the tolerance limit of the target, and the roof
// temperature would help get the temperature to be closer to the target, the pumps will be
// turned on.  If the outdoor temperature is low or the pool is very cold, the sweep will also be
// run to help mix the water as it approaches the target.
func (ppc *PoolPumpController) RunPumpsIfNeeded() {
	state := ppc.switches.State()
	if ppc.switches.ManualState() {
		return
	}
	if state == STATE_DISABLED && !ppc.config.cfg.Disabled && !ppc.config.cfg.SolarDisabled {
		ppc.switches.setSwitches(false, false, false, false, STATE_OFF)
		return
	}
	if ppc.config.cfg.Disabled {
		if state > STATE_DISABLED {
			ppc.switches.setSwitches(false, false, false, false, STATE_DISABLED)
		}
		return
	}
	wd, werr := ppc.weather.GetWeatherByZip(ppc.config.cfg.Zip)
	if ppc.shouldCool() || ppc.shouldWarm() {
		// Wide deltaT between target and temp or when it's cold, run sweep
		if ppc.pumpTemp.Temperature() < ppc.config.cfg.Target-ppc.config.cfg.DeltaT ||
			(werr == nil && wd.CurrentTempC < ppc.config.cfg.Target) || // Cool Weather
			ppc.pumpTemp.Temperature() > ppc.config.cfg.Target+ppc.config.cfg.Tolerance {
			ppc.switches.SetState(STATE_SOLAR_MIXING, false)
		} else {
			// Just push water through the panels
			ppc.switches.SetState(STATE_SOLAR, false)
		}
		return
	}
	// If the pumps havent run in a day, wait til midnight then start them
	if time.Now().Sub(ppc.switches.GetStopTime()) > 22*time.Hour {
		ppc.switches.SetState(STATE_SWEEP, false) // Clean pool
		if time.Now().Sub(ppc.switches.GetStartTime()) > 2*time.Hour {
			ppc.switches.StopAll(false) // End daily
		}
		return
	}
	// If there is no reason to turn on the pumps and it's not manual, turn off
	if state > STATE_OFF && ppc.switches.GetStartTime().Add(time.Hour).Before(time.Now()) {
		ppc.switches.StopAll(false)
	}
}

// Runs calls PoolPumpController.Update() and PoolPumpController.RunPumpsIfNeeded()
// repeatedly until PoolPumpController.Stop() is called
func (ppc *PoolPumpController) runLoop() {
	interval := time.Second * 5
	postStatus := time.Now()
	keepRunning := true
	for keepRunning {
		if postStatus.Before(time.Now()) {
			postStatus = time.Now().Add(5 * time.Minute)
			Info(ppc.Status())
		}
		ppc.SyncAdjustments()
		select {
		case <-ppc.done:
			ppc.button.Stop()
			// Turn off the pumps, and don't let them turn back on
			ppc.switches.Disable()
			keepRunning = false
			break
		case <-time.After(interval):
			ppc.Update()
			ppc.RunPumpsIfNeeded()
			ppc.UpdateRrd()
		}
	}
	Alert("Exiting Controller")
}

// Start finishes initializing the PoolPumpController, and kicks off the control thread.
func (ppc *PoolPumpController) Start() {
	ppc.button = NewGpioButton(buttonGpio, func() {
		switch ppc.switches.State() {
		case STATE_OFF:
			ppc.switches.SetState(STATE_PUMP, true)
		case STATE_PUMP:
			ppc.switches.SetState(STATE_SWEEP, true)
		case STATE_SOLAR:
			ppc.switches.SetState(STATE_SOLAR_MIXING, true)
		case STATE_DISABLED:
		default:
			ppc.switches.SetState(STATE_OFF, true)
		}
	})
	// Initialize RRDs
	ppc.createRrds()

	// Start go routines
	ppc.Update()
	ppc.button.Start()
	go ppc.runLoop()
}

// Stop stops all of the pumps
func (ppc *PoolPumpController) Stop() {
	ppc.switches.StopAll(true)
	ppc.done <- true
}

// PersistCalibration saves the callibration data
func (ppc *PoolPumpController) PersistCalibration() {
	t, ok := ppc.pumpTemp.(*GpioThermometer)
	if ok {
		ppc.config.cfg.PumpAdjustment = t.adjust
	}
	t, ok = ppc.roofTemp.(*GpioThermometer)
	if ok {
		ppc.config.cfg.RoofAdjustment = t.adjust
	}
}

// SyncAdjustments syncrhonizes the adjustments to temperature sensors
func (ppc *PoolPumpController) SyncAdjustments() {
	t, ok := ppc.pumpTemp.(*GpioThermometer)
	if ok {
		t.adjust = ppc.config.cfg.PumpAdjustment
	}
	t, ok = ppc.roofTemp.(*GpioThermometer)
	if ok {
		t.adjust = ppc.config.cfg.RoofAdjustment
	}
}

// WeatherC returns the current temperature outside in degrees Celsius
func (ppc *PoolPumpController) WeatherC() float64 {
	wd, err := ppc.weather.GetWeatherByZip(ppc.config.cfg.Zip)
	if err != nil || wd == nil {
		Error("Error while reading weather: %v", err)
		return 0.0
	}
	return wd.CurrentTempC
}

// Status prints the status of the system
func (ppc *PoolPumpController) Status() string {
	return fmt.Sprintf(
		"Status(%s) Button(%s) Solar(%s) Pump(%s) Sweep(%s) Manual(%t) Target(%0.1f) "+
			"Pool(%0.1f) Pump(%0.1f) Roof(%0.1f) CurrentTemp(%0.1f)",
		ppc.switches.State(), ppc.button.pin.Read(), ppc.switches.solar.Status(),
		ppc.switches.pump.Status(), ppc.switches.sweep.Status(),
		ppc.switches.ManualState(), ppc.config.cfg.Target,
		ppc.runningTemp.Temperature(), ppc.pumpTemp.Temperature(),
		ppc.roofTemp.Temperature(), ppc.WeatherC())
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2014 by Michael Dvorkin. All Rights Reserved.
// Use of this source code is governed by a MIT-style license that can
// be found in the LICENSE file.

package donna

import (
	`bytes`
)

var tree [1024]Position
var node, rootNode int

type Position struct {
	game       *Game
	enpassant  int         // En-passant square caused by previous move.
	color      int         // Side to make next move.
	reversible bool        // Is this position reversible?
	castles    uint8       // Castle rights mask.
	hash       uint64      // Polyglot hash value for the position.
	hashPawn   uint64      // Polyglot hash value for position's pawn structure.
	board      Bitmask     // Bitmask of all pieces on the board.
	king       [2]int      // King's square for both colors.
	count      [14]int     // Counts of each piece on the board, ex. white pawns: 6, etc.
	pieces     [64]Piece   // Array of 64 squares with pieces on them.
	outposts   [14]Bitmask // Bitmasks of each piece on the board; [0] all white, [1] all black.
	tally      Score       // Material score based on PST.
}

func NewPosition(game *Game, pieces [64]Piece, color int) *Position {
	tree[node] = Position{game: game, pieces: pieces, color: color}
	p := &tree[node]

	p.castles = castleKingside[White] | castleQueenside[White] |
		castleKingside[Black] | castleQueenside[Black]

	if p.pieces[E1] != King || p.pieces[H1] != Rook {
		p.castles &= ^castleKingside[White]
	}
	if p.pieces[E1] != King || p.pieces[A1] != Rook {
		p.castles &= ^castleQueenside[White]
	}

	if p.pieces[E8] != BlackKing || p.pieces[H8] != BlackRook {
		p.castles &= ^castleKingside[Black]
	}
	if p.pieces[E8] != BlackKing || p.pieces[A8] != BlackRook {
		p.castles &= ^castleQueenside[Black]
	}

	for square, piece := range p.pieces {
		if piece != 0 {
			p.outposts[piece].set(square)
			p.outposts[piece.color()].set(square)
			p.count[piece]++
			if piece.isKing() {
				p.king[piece.color()] = square
			}
		}
	}

	p.reversible = true
	p.board = p.outposts[White] | p.outposts[Black]
	p.hash, p.hashPawn = p.polyglot()
	p.tally = p.material()

	return p
}

func (p *Position) movePiece(piece Piece, from, to int) *Position {
	p.pieces[from], p.pieces[to] = 0, piece
	p.outposts[piece] ^= bit[from] | bit[to]
	p.outposts[piece.color()] ^= bit[from] | bit[to]

	// Update position's hash values.
	random := piece.polyglot(from) ^ piece.polyglot(to)
	p.hash ^= random
	if piece.isPawn() {
		p.hashPawn ^= random
	}

	// Update material score.
	p.tally.subtract(pst[piece][from]).add(pst[piece][to])

	return p
}

func (p *Position) promotePawn(piece Piece, from, to int, promo Piece) *Position {
	p.pieces[from], p.pieces[to] = 0, promo
	p.outposts[piece] ^= bit[from]
	p.outposts[promo] ^= bit[to]
	p.outposts[piece.color()] ^= bit[from] | bit[to]
	p.count[piece]--
	p.count[promo]++

	// Update position's hash values.
	random := piece.polyglot(from)
	p.hash ^= random
	p.hashPawn ^= random
	p.hash ^= promo.polyglot(to)

	// Update material score.
	p.tally.subtract(pst[piece][from]).add(pst[promo][to])

	return p
}

func (p *Position) capturePiece(capture Piece, from, to int) *Position {
	p.outposts[capture] ^= bit[to]
	p.outposts[capture.color()] ^= bit[to]
	p.count[capture]--

	// Update position's hash values.
	random := capture.polyglot(to)
	p.hash ^= random
	if capture.isPawn() {
		p.hashPawn ^= random
	}

	// Update material score.
	p.tally.subtract(pst[capture][to])

	return p
}

func (p *Position) captureEnpassant(capture Piece, from, to int) *Position {
	enpassant := to - eight[capture.color()^1]

	p.pieces[enpassant] = 0
	p.outposts[capture] ^= bit[enpassant]
	p.outposts[capture.color()] ^= bit[enpassant]
	p.count[capture]--

	// Update position's hash values.
	random := capture.polyglot(enpassant)
	p.hash ^= random
	p.hashPawn ^= random

	// Update material score.
	p.tally.subtract(pst[capture][enpassant])

	return p
}

func (p *Position) MakeMove(move Move) *Position {
	color := move.color()
	from, to, piece, capture := move.split()

	// Copy over the contents of previous tree node to the current one.
	node++
	tree[node] = *p // => tree[node] = tree[node - 1]
	pp := &tree[node]

	pp.enpassant, pp.reversible = 0, true

	if capture != 0 {
		pp.reversible = false
		if to != 0 && to == p.enpassant {
			pp.captureEnpassant(pawn(color^1), from, to)
		} else {
			pp.capturePiece(capture, from, to)
		}
	}

	if promo := move.promo(); promo == 0 {
		pp.movePiece(piece, from, to)

		if piece.isKing() {
			pp.king[color] = to
			if move.isCastle() {
				pp.reversible = false
				switch to {
				case G1:
					pp.movePiece(Rook, H1, F1)
				case C1:
					pp.movePiece(Rook, A1, D1)
				case G8:
					pp.movePiece(BlackRook, H8, F8)
				case C8:
					pp.movePiece(BlackRook, A8, D8)
				}
			}
		} else if piece.isPawn() {
			pp.reversible = false
			if move.isEnpassant() {
				pp.enpassant = from + eight[color] // Save the en-passant square.
				pp.hash ^= hashEnpassant[Col(pp.enpassant)]
			}
		}
	} else {
		pp.reversible = false
		pp.promotePawn(piece, from, to, promo)
	}

	pp.board = pp.outposts[White] | pp.outposts[Black]

	// Ready to validate new position we have after making the move: if it is not
	// valid then revert back the node pointer and return nil.
	if pp.isInCheck(color) {
		node--
		return nil
	}

	// OK, the position after making the move is valid: all that's left is updating
	// castle rights, finishing off incremental hash value, and flipping the color.
	pp.castles &= castleRights[from] & castleRights[to]
	pp.hash ^= hashCastle[p.castles] ^ hashCastle[pp.castles]

	if p.enpassant != 0 {
		pp.hash ^= hashEnpassant[Col(p.enpassant)]
	}

	pp.hash ^= polyglotRandomWhite
	pp.color ^= 1 // <-- Flip side to move.

	return &tree[node] // pp
}

// Makes "null" move by copying over previous node position (i.e. preserving all pieces
// intact) and flipping the color.
func (p *Position) MakeNullMove() *Position {
	node++
	tree[node] = *p // => tree[node] = tree[node - 1]
	pp := &tree[node]

	// Flipping side to move obviously invalidates the enpassant square.
	if pp.enpassant != 0 {
		pp.hash ^= hashEnpassant[Col(pp.enpassant)]
		pp.enpassant = 0
	}
	pp.hash ^= polyglotRandomWhite
	pp.color ^= 1 // <-- Flip side to move.

	return &tree[node] // pp
}

// Restores previous position effectively taking back the last move made.
func (p *Position) TakeBack(move Move) *Position {
	node--
	return &tree[node]
}

func (p *Position) TakeBackNullMove() *Position {
	p.hash ^= polyglotRandomWhite
	p.color ^= 1

	return p.TakeBack(Move(0))
}

func (p *Position) isInCheck(color int) bool {
	return p.isAttacked(p.king[color], color^1)
}

func (p *Position) isNull() bool {
	return node > 0 && tree[node].board == tree[node-1].board
}

func (p *Position) isRepetition() bool {
	if !p.reversible {
		return false
	}

	for reps, prevNode := 1, node-1; prevNode >= 0; prevNode-- {
		if !tree[prevNode].reversible {
			return false
		}
		if tree[prevNode].color == p.color && tree[prevNode].hash == p.hash {
			reps++
			if reps == 3 {
				return true
			}
		}
	}
	return false
}

func (p *Position) isInsufficient() bool {
	return false
}

func (p *Position) canCastle(color int) (kingside, queenside bool) {
	attacks := p.allAttacks(color ^ 1)
	kingside = p.castles & castleKingside[color] != 0 &&
		(gapKing[color] & p.board == 0) &&
		(castleKing[color] & attacks == 0)

	queenside = p.castles&castleQueenside[color] != 0 &&
		(gapQueen[color] & p.board == 0) &&
		(castleQueen[color] & attacks == 0)
	return
}

// Reports game status for current position or after the given move. The status
// help to determine whether to continue with search or if the game is over.
func (p *Position) status(move Move, blendedScore int) int {
	if move != Move(0) {
		p = p.MakeMove(move)
		defer func() { p = p.TakeBack(move) }()
	}

	switch ply, score := Ply(), Abs(blendedScore); score {
	case 0:
		if ply == 1 {
			if p.isRepetition() {
				return Repetition
			} else if p.isInsufficient() {
				return Insufficient
			}
		}
		if !NewGen(p, ply+1).generateMoves().anyValid(p) {
			return Stalemate
		}
	case Checkmate - ply:
		if p.isInCheck(p.color) {
			if p.color == White {
				return BlackWon
			}
			return WhiteWon
		}
		return Stalemate
	default:
		if score > Checkmate-MaxDepth && (score+ply)/2 > 0 {
			if p.color == White {
				return BlackWinning
			}
			return WhiteWinning
		}
	}
	return InProgress
}

// Calculates game phase based on what pieces are on the board (256 for the
// initial position, 0 for bare kings).
func (p *Position) phase() int {
	return 12 * (p.count[Knight] + p.count[BlackKnight]) +
	       12 * (p.count[Bishop] + p.count[BlackBishop]) +
	       18 * (p.count[Rook]   + p.count[BlackRook]) +
	       44 * (p.count[Queen]  + p.count[BlackQueen])
}

// Computes initial values of position's polyglot hash (entire board) and pawn
// hash (pawns only). When making a move the values get updated incrementally.
func (p *Position) polyglot() (hash, hashPawn uint64) {
	board := p.board
	for board != 0 {
		square := board.pop()
		piece := p.pieces[square]
		seed := piece.polyglot(square)
		hash ^= seed
		if piece.isPawn() {
			hashPawn ^= seed
		}
	}

	hash ^= hashCastle[p.castles]
	if p.enpassant != 0 {
		hash ^= hashEnpassant[Col(p.enpassant)]
	}
	if p.color == White {
		hash ^= polyglotRandomWhite
	}

	return
}

// Computes position's cumulative material score. When making a move the
// material score gets updated incrementally.
func (p *Position) material() (score Score) {
	board := p.board
	for board != 0 {
		square := board.pop()
		piece := p.pieces[square]
		score.add(pst[piece][square])
	}
	return
}

func (p *Position) String() string {
	buffer := bytes.NewBufferString("  a b c d e f g h")
	if !p.isInCheck(p.color) {
		buffer.WriteString("\n")
	} else {
		buffer.WriteString("  Check to " + C(p.color) + "\n")
	}
	for row := 7; row >= 0; row-- {
		buffer.WriteByte('1' + byte(row))
		for col := 0; col <= 7; col++ {
			square := Square(row, col)
			buffer.WriteByte(' ')
			if piece := p.pieces[square]; piece != 0 {
				buffer.WriteString(piece.String())
			} else {
				buffer.WriteString("\u22C5")
			}
		}
		buffer.WriteByte('\n')
	}
	return buffer.String()
}
<commit_msg>Incremental material hash calculation when making moves<commit_after>// Copyright (c) 2013-2014 by Michael Dvorkin. All Rights Reserved.
// Use of this source code is governed by a MIT-style license that can
// be found in the LICENSE file.

package donna

import (
	`bytes`
)

var tree [1024]Position
var node, rootNode int

type Position struct {
	game         *Game
	enpassant    int         // En-passant square caused by previous move.
	color        int         // Side to make next move.
	reversible   bool        // Is this position reversible?
	castles      uint8       // Castle rights mask.
	hash         uint64      // Polyglot hash value for the position.
	hashPawns    uint64      // Polyglot hash value for position's pawn structure.
	hashMaterial uint64      // Polyglot hash for position's playing material.
	board        Bitmask     // Bitmask of all pieces on the board.
	king         [2]int      // King's square for both colors.
	count        [14]int     // Counts of each piece on the board.
	pieces       [64]Piece   // Array of 64 squares with pieces on them.
	outposts     [14]Bitmask // Bitmasks of each piece on the board; [0] all white, [1] all black.
	tally        Score       // Positional valuation score based on PST.
}

func NewPosition(game *Game, pieces [64]Piece, color int) *Position {
	tree[node] = Position{game: game, pieces: pieces, color: color}
	p := &tree[node]

	p.castles = castleKingside[White] | castleQueenside[White] |
		castleKingside[Black] | castleQueenside[Black]

	if p.pieces[E1] != King || p.pieces[H1] != Rook {
		p.castles &= ^castleKingside[White]
	}
	if p.pieces[E1] != King || p.pieces[A1] != Rook {
		p.castles &= ^castleQueenside[White]
	}

	if p.pieces[E8] != BlackKing || p.pieces[H8] != BlackRook {
		p.castles &= ^castleKingside[Black]
	}
	if p.pieces[E8] != BlackKing || p.pieces[A8] != BlackRook {
		p.castles &= ^castleQueenside[Black]
	}

	for square, piece := range p.pieces {
		if piece != 0 {
			p.outposts[piece].set(square)
			p.outposts[piece.color()].set(square)
			p.count[piece]++
			if piece.isKing() {
				p.king[piece.color()] = square
			}
		}
	}

	p.reversible = true
	p.board = p.outposts[White] | p.outposts[Black]
	p.hash, p.hashPawns, p.hashMaterial = p.polyglot()
	p.tally = p.valuation()

	return p
}

func (p *Position) movePiece(piece Piece, from, to int) *Position {
	p.pieces[from], p.pieces[to] = 0, piece
	p.outposts[piece] ^= bit[from] | bit[to]
	p.outposts[piece.color()] ^= bit[from] | bit[to]

	// Update position's hash values.
	random := piece.polyglot(from) ^ piece.polyglot(to)
	p.hash ^= random
	if piece.isPawn() {
		p.hashPawns ^= random
	}

	// Update positional score.
	p.tally.subtract(pst[piece][from]).add(pst[piece][to])

	return p
}

func (p *Position) promotePawn(piece Piece, from, to int, promo Piece) *Position {
	p.pieces[from], p.pieces[to] = 0, promo
	p.outposts[piece] ^= bit[from]
	p.outposts[promo] ^= bit[to]
	p.outposts[piece.color()] ^= bit[from] | bit[to]
	p.count[piece]--

	// Update position's hash values.
	random := piece.polyglot(from)
	p.hash ^= random ^ promo.polyglot(to)
	p.hashPawns ^= random
	p.hashMaterial ^= piece.polyglot(p.count[piece]) ^ promo.polyglot(p.count[promo])
	p.count[promo]++

	// Update positional score.
	p.tally.subtract(pst[piece][from]).add(pst[promo][to])

	return p
}

func (p *Position) capturePiece(capture Piece, from, to int) *Position {
	p.outposts[capture] ^= bit[to]
	p.outposts[capture.color()] ^= bit[to]
	p.count[capture]--

	// Update position's hash values and count.
	random := capture.polyglot(to)
	p.hash ^= random
	if capture.isPawn() {
		p.hashPawns ^= random
	}
	p.hashMaterial ^= capture.polyglot(p.count[capture])

	// Update positional score.
	p.tally.subtract(pst[capture][to])

	return p
}

func (p *Position) captureEnpassant(capture Piece, from, to int) *Position {
	enpassant := to - eight[capture.color()^1]

	p.pieces[enpassant] = 0
	p.outposts[capture] ^= bit[enpassant]
	p.outposts[capture.color()] ^= bit[enpassant]
	p.count[capture]--

	// Update position's hash values and count.
	random := capture.polyglot(enpassant)
	p.hash ^= random
	p.hashPawns ^= random
	p.hashMaterial ^= capture.polyglot(p.count[capture])

	// Update positional score.
	p.tally.subtract(pst[capture][enpassant])

	return p
}

func (p *Position) MakeMove(move Move) *Position {
	color := move.color()
	from, to, piece, capture := move.split()

	// Copy over the contents of previous tree node to the current one.
	node++
	tree[node] = *p // => tree[node] = tree[node - 1]
	pp := &tree[node]

	pp.enpassant, pp.reversible = 0, true

	if capture != 0 {
		pp.reversible = false
		if to != 0 && to == p.enpassant {
			pp.captureEnpassant(pawn(color^1), from, to)
		} else {
			pp.capturePiece(capture, from, to)
		}
	}

	if promo := move.promo(); promo == 0 {
		pp.movePiece(piece, from, to)

		if piece.isKing() {
			pp.king[color] = to
			if move.isCastle() {
				pp.reversible = false
				switch to {
				case G1:
					pp.movePiece(Rook, H1, F1)
				case C1:
					pp.movePiece(Rook, A1, D1)
				case G8:
					pp.movePiece(BlackRook, H8, F8)
				case C8:
					pp.movePiece(BlackRook, A8, D8)
				}
			}
		} else if piece.isPawn() {
			pp.reversible = false
			if move.isEnpassant() {
				pp.enpassant = from + eight[color] // Save the en-passant square.
				pp.hash ^= hashEnpassant[Col(pp.enpassant)]
			}
		}
	} else {
		pp.reversible = false
		pp.promotePawn(piece, from, to, promo)
	}

	pp.board = pp.outposts[White] | pp.outposts[Black]

	// Ready to validate new position we have after making the move: if it is not
	// valid then revert back the node pointer and return nil.
	if pp.isInCheck(color) {
		node--
		return nil
	}

	// OK, the position after making the move is valid: all that's left is updating
	// castle rights, finishing off incremental hash value, and flipping the color.
	pp.castles &= castleRights[from] & castleRights[to]
	pp.hash ^= hashCastle[p.castles] ^ hashCastle[pp.castles]

	if p.enpassant != 0 {
		pp.hash ^= hashEnpassant[Col(p.enpassant)]
	}

	pp.hash ^= polyglotRandomWhite
	pp.color ^= 1 // <-- Flip side to move.

	return &tree[node] // pp
}

// Makes "null" move by copying over previous node position (i.e. preserving all pieces
// intact) and flipping the color.
func (p *Position) MakeNullMove() *Position {
	node++
	tree[node] = *p // => tree[node] = tree[node - 1]
	pp := &tree[node]

	// Flipping side to move obviously invalidates the enpassant square.
	if pp.enpassant != 0 {
		pp.hash ^= hashEnpassant[Col(pp.enpassant)]
		pp.enpassant = 0
	}
	pp.hash ^= polyglotRandomWhite
	pp.color ^= 1 // <-- Flip side to move.

	return &tree[node] // pp
}

// Restores previous position effectively taking back the last move made.
func (p *Position) TakeBack(move Move) *Position {
	node--
	return &tree[node]
}

func (p *Position) TakeBackNullMove() *Position {
	p.hash ^= polyglotRandomWhite
	p.color ^= 1

	return p.TakeBack(Move(0))
}

func (p *Position) isInCheck(color int) bool {
	return p.isAttacked(p.king[color], color^1)
}

func (p *Position) isNull() bool {
	return node > 0 && tree[node].board == tree[node-1].board
}

func (p *Position) isRepetition() bool {
	if !p.reversible {
		return false
	}

	for reps, prevNode := 1, node-1; prevNode >= 0; prevNode-- {
		if !tree[prevNode].reversible {
			return false
		}
		if tree[prevNode].color == p.color && tree[prevNode].hash == p.hash {
			reps++
			if reps == 3 {
				return true
			}
		}
	}
	return false
}

func (p *Position) isInsufficient() bool {
	return false
}

func (p *Position) canCastle(color int) (kingside, queenside bool) {
	attacks := p.allAttacks(color ^ 1)
	kingside = p.castles & castleKingside[color] != 0 &&
		(gapKing[color] & p.board == 0) &&
		(castleKing[color] & attacks == 0)

	queenside = p.castles&castleQueenside[color] != 0 &&
		(gapQueen[color] & p.board == 0) &&
		(castleQueen[color] & attacks == 0)
	return
}

// Reports game status for current position or after the given move. The status
// help to determine whether to continue with search or if the game is over.
func (p *Position) status(move Move, blendedScore int) int {
	if move != Move(0) {
		p = p.MakeMove(move)
		defer func() { p = p.TakeBack(move) }()
	}

	switch ply, score := Ply(), Abs(blendedScore); score {
	case 0:
		if ply == 1 {
			if p.isRepetition() {
				return Repetition
			} else if p.isInsufficient() {
				return Insufficient
			}
		}
		if !NewGen(p, ply+1).generateMoves().anyValid(p) {
			return Stalemate
		}
	case Checkmate - ply:
		if p.isInCheck(p.color) {
			if p.color == White {
				return BlackWon
			}
			return WhiteWon
		}
		return Stalemate
	default:
		if score > Checkmate-MaxDepth && (score+ply)/2 > 0 {
			if p.color == White {
				return BlackWinning
			}
			return WhiteWinning
		}
	}
	return InProgress
}

// Calculates game phase based on what pieces are on the board (256 for the
// initial position, 0 for bare kings).
func (p *Position) phase() int {
	return 12 * (p.count[Knight] + p.count[BlackKnight]) +
	       12 * (p.count[Bishop] + p.count[BlackBishop]) +
	       18 * (p.count[Rook]   + p.count[BlackRook]) +
	       44 * (p.count[Queen]  + p.count[BlackQueen])
}

// Computes initial values of position's polyglot hash, pawn hash, and material
// hash. When making a move these values get updated incrementally.
func (p *Position) polyglot() (hash, hashPawns, hashMaterial uint64) {
	board := p.board
	for board != 0 {
		square := board.pop()
		piece := p.pieces[square]
		random := piece.polyglot(square)
		hash ^= random
		if piece.isPawn() {
			hashPawns ^= random
		}
	}

	hash ^= hashCastle[p.castles]
	if p.enpassant != 0 {
		hash ^= hashEnpassant[Col(p.enpassant)]
	}
	if p.color == White {
		hash ^= polyglotRandomWhite
	}

	for piece := Pawn; piece <= BlackQueen; piece++ {
		for count := 0; count < p.count[piece]; count++ {
			hashMaterial ^= Piece(piece).polyglot(count)
		}
	}

	return
}

// Computes positional valuation score based on PST. When making a move the
// valuation tally gets updated incrementally.
func (p *Position) valuation() (score Score) {
	board := p.board
	for board != 0 {
		square := board.pop()
		piece := p.pieces[square]
		score.add(pst[piece][square])
	}
	return
}

func (p *Position) String() string {
	buffer := bytes.NewBufferString("  a b c d e f g h")
	if !p.isInCheck(p.color) {
		buffer.WriteString("\n")
	} else {
		buffer.WriteString("  Check to " + C(p.color) + "\n")
	}
	for row := 7; row >= 0; row-- {
		buffer.WriteByte('1' + byte(row))
		for col := 0; col <= 7; col++ {
			square := Square(row, col)
			buffer.WriteByte(' ')
			if piece := p.pieces[square]; piece != 0 {
				buffer.WriteString(piece.String())
			} else {
				buffer.WriteString("\u22C5")
			}
		}
		buffer.WriteByte('\n')
	}
	return buffer.String()
}
<|endoftext|>


<commit_before>package video

var scan = [2][8][8]int{
	{
		{0, 1, 5, 6, 14, 15, 27, 28},
		{2, 4, 7, 13, 16, 26, 29, 42},
		{3, 8, 12, 17, 25, 30, 41, 43},
		{9, 11, 18, 24, 31, 40, 44, 53},
		{10, 19, 23, 32, 39, 45, 52, 54},
		{20, 22, 33, 38, 46, 51, 55, 60},
		{21, 34, 37, 47, 50, 56, 59, 61},
		{35, 36, 48, 49, 57, 58, 62, 63},
	},
	{
		{0, 4, 6, 20, 22, 36, 38, 52},
		{1, 5, 7, 21, 23, 37, 39, 53},
		{2, 8, 19, 24, 34, 40, 50, 54},
		{3, 9, 18, 25, 35, 41, 51, 55},
		{10, 17, 26, 30, 42, 46, 56, 60},
		{11, 16, 27, 31, 43, 47, 57, 61},
		{12, 15, 28, 32, 44, 48, 58, 62},
		{13, 14, 29, 33, 45, 49, 59, 63},
	},
}

func sign(i int32) int32 {
	if i > 0 {
		return 1
	}
	if i < 0 {
		return -1
	}
	return 0
}

type intermediaryblock [8][8]int32

func (self *VideoSequence) decode_block(cc int, QFS *block, F *block, macroblock_intra bool) error {
	var QF intermediaryblock
	var Fpp intermediaryblock
	var Fp intermediaryblock

	// inverse scan
	{
		alternate_scan := self.PictureCodingExtension.alternate_scan
		for v := 0; v < 8; v++ {
			for u := 0; u < 8; u++ {
				QF[v][u] = QFS[scan[alternate_scan][v][u]]
			}
		}
	}

	// Inverse quantisation
	{
		q_scale_type := self.PictureCodingExtension.q_scale_type
		quantiser_scale_code := self.currentQSC
		quantiser_scale := quantiser_scale_tables[q_scale_type][quantiser_scale_code]

		var w int
		if cc == 0 {
			if macroblock_intra {
				w = 0
			} else {
				w = 1
			}
		} else {
			if self.SequenceExtension.chroma_format == ChromaFormat_4_2_0 {
				if macroblock_intra {
					w = 0
				} else {
					w = 1
				}
			} else {
				if macroblock_intra {
					w = 2
				} else {
					w = 3
				}
			}
		}

		W := self.quantisationMatricies

		for v := 0; v < 8; v++ {
			for u := 0; u < 8; u++ {
				if (u == 0) && (v == 0) && (macroblock_intra) {
					// Table 7-4
					intra_dc_mult := int32(1) << (3 - self.PictureCodingExtension.intra_dc_precision)
					Fpp[v][u] = intra_dc_mult * QF[v][u]
				} else {
					if macroblock_intra {
						Fpp[v][u] = (QF[v][u] * int32(W[w][v][u]) * quantiser_scale * 2) / 32
					} else {
						Fpp[v][u] = (((QF[v][u] * 2) + sign(QF[v][u])) * int32(W[w][v][u]) *
							quantiser_scale) / 32
					}
				}
			}
		}
	}

	{
		// Saturation
		var sum int32 = 0
		for v := 0; v < 8; v++ {
			for u := 0; u < 8; u++ {
				if Fpp[v][u] > 2047 {
					Fp[v][u] = 2047
				} else if Fpp[v][u] < -2048 {
					Fp[v][u] = -2048
				} else {
					Fp[v][u] = Fpp[v][u]
				}
				sum = sum + Fp[v][u]
				F[v*8+u] = Fp[v][u]
			}
		}

		// Mismatch control
		if (sum & 1) == 0 {
			if (F[7*8+7] & 1) != 0 {
				F[7*8+7] = Fp[7][7] - 1
			} else {
				F[7*8+7] = Fp[7][7] + 1
			}
		}
	}

	return nil
}
<commit_msg>stylistic<commit_after>package video

var scan = [2][8][8]int{
	{
		{0, 1, 5, 6, 14, 15, 27, 28},
		{2, 4, 7, 13, 16, 26, 29, 42},
		{3, 8, 12, 17, 25, 30, 41, 43},
		{9, 11, 18, 24, 31, 40, 44, 53},
		{10, 19, 23, 32, 39, 45, 52, 54},
		{20, 22, 33, 38, 46, 51, 55, 60},
		{21, 34, 37, 47, 50, 56, 59, 61},
		{35, 36, 48, 49, 57, 58, 62, 63},
	},
	{
		{0, 4, 6, 20, 22, 36, 38, 52},
		{1, 5, 7, 21, 23, 37, 39, 53},
		{2, 8, 19, 24, 34, 40, 50, 54},
		{3, 9, 18, 25, 35, 41, 51, 55},
		{10, 17, 26, 30, 42, 46, 56, 60},
		{11, 16, 27, 31, 43, 47, 57, 61},
		{12, 15, 28, 32, 44, 48, 58, 62},
		{13, 14, 29, 33, 45, 49, 59, 63},
	},
}

func sign(i int32) int32 {
	if i > 0 {
		return 1
	} else if i < 0 {
		return -1
	}
	return 0
}

type intermediaryblock [8][8]int32

func (self *VideoSequence) decode_block(cc int, QFS *block, F *block, macroblock_intra bool) error {
	var QF intermediaryblock
	var Fpp intermediaryblock
	var Fp intermediaryblock

	// inverse scan
	{
		alternate_scan := self.PictureCodingExtension.alternate_scan
		for v := 0; v < 8; v++ {
			for u := 0; u < 8; u++ {
				QF[v][u] = QFS[scan[alternate_scan][v][u]]
			}
		}
	}

	// Inverse quantisation
	{
		q_scale_type := self.PictureCodingExtension.q_scale_type
		quantiser_scale_code := self.currentQSC
		quantiser_scale := quantiser_scale_tables[q_scale_type][quantiser_scale_code]

		var w int
		if cc == 0 {
			if macroblock_intra {
				w = 0
			} else {
				w = 1
			}
		} else {
			if self.SequenceExtension.chroma_format == ChromaFormat_4_2_0 {
				if macroblock_intra {
					w = 0
				} else {
					w = 1
				}
			} else {
				if macroblock_intra {
					w = 2
				} else {
					w = 3
				}
			}
		}

		W := self.quantisationMatricies

		for v := 0; v < 8; v++ {
			for u := 0; u < 8; u++ {
				if (u == 0) && (v == 0) && (macroblock_intra) {
					// Table 7-4
					intra_dc_mult := int32(1) << (3 - self.PictureCodingExtension.intra_dc_precision)
					Fpp[v][u] = intra_dc_mult * QF[v][u]
				} else {
					if macroblock_intra {
						Fpp[v][u] = (QF[v][u] * int32(W[w][v][u]) * quantiser_scale * 2) / 32
					} else {
						Fpp[v][u] = (((QF[v][u] * 2) + sign(QF[v][u])) * int32(W[w][v][u]) *
							quantiser_scale) / 32
					}
				}
			}
		}
	}

	{
		// Saturation
		var sum int32 = 0
		for v := 0; v < 8; v++ {
			for u := 0; u < 8; u++ {
				if Fpp[v][u] > 2047 {
					Fp[v][u] = 2047
				} else if Fpp[v][u] < -2048 {
					Fp[v][u] = -2048
				} else {
					Fp[v][u] = Fpp[v][u]
				}
				sum = sum + Fp[v][u]
				F[v*8+u] = Fp[v][u]
			}
		}

		// Mismatch control
		if (sum & 1) == 0 {
			if (F[7*8+7] & 1) != 0 {
				F[7*8+7] = Fp[7][7] - 1
			} else {
				F[7*8+7] = Fp[7][7] + 1
			}
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package lunk

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

// An EntryRecorder records entries, e.g. to a streaming processing system or an
// OLAP database.
type EntryRecorder interface {
	Record(Entry) error
}

// NewNormalizedCSVEntryRecorder returns an EntryRecorder which writes events to
// one CSV file and properties to another.
func NewNormalizedCSVEntryRecorder(events, props *csv.Writer) EntryRecorder {
	return nCSVRecorder{
		events: events,
		props:  props,
	}
}

// NewDenormalizedCSVEntryRecorder returns an EntryRecorder which writes events
// and their properties to a single CSV file, duplicating event data when
// necessary.
func NewDenormalizedCSVEntryRecorder(w *csv.Writer) EntryRecorder {
	return dCSVRecorder{
		w: w,
	}
}

var (
	// NormalizedEventHeaders are the set of headers used for storing events in
	// normalized CSV files.
	NormalizedEventHeaders = []string{
		"root",
		"id",
		"parent",
		"schema",
		"time",
		"host",
		"pid",
		"deploy",
	}

	// NormalizedPropertyHeaders are the set of headers used for storing
	// properties in normalized CSV files.
	NormalizedPropertyHeaders = []string{
		"root",
		"id",
		"parent",
		"prop_name",
		"prop_value",
	}

	// DenormalizedEventHeaders are the set of headers used for storing events
	// in denormalized CSV files.
	DenormalizedEventHeaders = []string{
		"root",
		"id",
		"parent",
		"schema",
		"time",
		"host",
		"pid",
		"deploy",
		"prop_name",
		"prop_value",
	}
)

type nCSVRecorder struct {
	events *csv.Writer
	props  *csv.Writer
}

func (r nCSVRecorder) Record(e Entry) error {
	root, id, parent := e.Root.String(), e.ID.String(), e.Parent.String()

	if err := r.events.Write([]string{
		root,
		id,
		parent,
		e.Schema,
		e.Time.Format(time.RFC3339Nano),
		e.Host,
		strconv.Itoa(e.PID),
		e.Deploy,
	}); err != nil {
		return err
	}

	for k, v := range e.Properties {
		if err := r.props.Write([]string{
			root,
			id,
			parent,
			k,
			v,
		}); err != nil {
			return err
		}

	}

	return nil
}

type dCSVRecorder struct {
	w *csv.Writer
}

func (r dCSVRecorder) Record(e Entry) error {
	root, id, parent := e.Root.String(), e.ID.String(), e.Parent.String()
	time := e.Time.Format(time.RFC3339Nano)
	pid := strconv.Itoa(e.PID)

	for k, v := range e.Properties {
		if err := r.w.Write([]string{
			root,
			id,
			parent,
			e.Schema,
			time,
			e.Host,
			pid,
			e.Deploy,
			k,
			v,
		}); err != nil {
			return err
		}

	}

	return nil
}
<commit_msg>Ensure a consistent order for CSV lines.<commit_after>package lunk

import (
	"encoding/csv"
	"sort"
	"strconv"
	"time"
)

// An EntryRecorder records entries, e.g. to a streaming processing system or an
// OLAP database.
type EntryRecorder interface {
	Record(Entry) error
}

// NewNormalizedCSVEntryRecorder returns an EntryRecorder which writes events to
// one CSV file and properties to another.
func NewNormalizedCSVEntryRecorder(events, props *csv.Writer) EntryRecorder {
	return nCSVRecorder{
		events: events,
		props:  props,
	}
}

// NewDenormalizedCSVEntryRecorder returns an EntryRecorder which writes events
// and their properties to a single CSV file, duplicating event data when
// necessary.
func NewDenormalizedCSVEntryRecorder(w *csv.Writer) EntryRecorder {
	return dCSVRecorder{
		w: w,
	}
}

var (
	// NormalizedEventHeaders are the set of headers used for storing events in
	// normalized CSV files.
	NormalizedEventHeaders = []string{
		"root",
		"id",
		"parent",
		"schema",
		"time",
		"host",
		"pid",
		"deploy",
	}

	// NormalizedPropertyHeaders are the set of headers used for storing
	// properties in normalized CSV files.
	NormalizedPropertyHeaders = []string{
		"root",
		"id",
		"parent",
		"prop_name",
		"prop_value",
	}

	// DenormalizedEventHeaders are the set of headers used for storing events
	// in denormalized CSV files.
	DenormalizedEventHeaders = []string{
		"root",
		"id",
		"parent",
		"schema",
		"time",
		"host",
		"pid",
		"deploy",
		"prop_name",
		"prop_value",
	}
)

type nCSVRecorder struct {
	events *csv.Writer
	props  *csv.Writer
}

func (r nCSVRecorder) Record(e Entry) error {
	root, id, parent := e.Root.String(), e.ID.String(), e.Parent.String()

	if err := r.events.Write([]string{
		root,
		id,
		parent,
		e.Schema,
		e.Time.Format(time.RFC3339Nano),
		e.Host,
		strconv.Itoa(e.PID),
		e.Deploy,
	}); err != nil {
		return err
	}

	keys := make([]string, 0, len(e.Properties))
	for k := range e.Properties {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	for _, k := range keys {
		v := e.Properties[k]
		if err := r.props.Write([]string{
			root,
			id,
			parent,
			k,
			v,
		}); err != nil {
			return err
		}

	}

	return nil
}

type dCSVRecorder struct {
	w *csv.Writer
}

func (r dCSVRecorder) Record(e Entry) error {
	root, id, parent := e.Root.String(), e.ID.String(), e.Parent.String()
	time := e.Time.Format(time.RFC3339Nano)
	pid := strconv.Itoa(e.PID)

	for k, v := range e.Properties {
		if err := r.w.Write([]string{
			root,
			id,
			parent,
			e.Schema,
			time,
			e.Host,
			pid,
			e.Deploy,
			k,
			v,
		}); err != nil {
			return err
		}

	}

	return nil
}
<|endoftext|>