<commit_before>/*
 Copyright 2017 Crunchy Data Solutions, Inc.
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
*/

package proxy

import (
	"bytes"
	"encoding/binary"
	"github.com/crunchydata/crunchy-proxy/config"
	"github.com/golang/glog"
	"net"
)

func ListenAndServe() {
	var listener net.Listener

	tcpAddr, err := net.ResolveTCPAddr("tcp", config.Cfg.HostPort)
	checkError(err)

	listener, err = net.ListenTCP("tcp", tcpAddr)
	checkError(err)

	glog.Infof("[proxy] Listening on: %s", config.Cfg.HostPort)

	handleListener(listener)
}

func handleListener(listener net.Listener) {
	for {

		conn, err := listener.Accept()

		if err != nil {
			continue
		}

		go handleClientConnection(conn)
	}
}

func handleClientConnection(client net.Conn) {
	authenticated := AuthenticateClient(client)

	// If the client could not authenticate then go no further.
	if !authenticated {
		glog.Errorln("[proxy] client could not authenticate and connect.")
		return
	}

	defer client.Close()

	var err error
	masterBuf := make([]byte, 4096)
	var writeLen int
	var readLen int
	var msgType string
	var writeCase, startCase, finishCase = false, false, false
	var reqLen int
	var nextNode *config.Node
	var backendConn *net.TCPConn
	var poolIndex int
	var statementBlock = false

	for {

		reqLen, err = client.Read(masterBuf)
		if err != nil {
			glog.Errorln("[proxy] error reading from client conn" + err.Error())
			return
		}

		msgType = string(masterBuf[0])

		// adapt inbound data
		err = config.Cfg.Adapter.Do(masterBuf, reqLen)
		if err != nil {
			glog.Errorln("[proxy] error adapting inbound" + err.Error())
		}

		if msgType == "X" {
			glog.V(2).Infoln("termination msg received")
			return
		} else if msgType == "Q" {
			poolIndex = -1

			// Determine if the query has an annotation.
			writeCase, startCase, finishCase = IsWriteAnno(config.Cfg.ReadAnnotation,
				config.Cfg.StartAnnotation, config.Cfg.FinishAnnotation, masterBuf)

			glog.V(2).Infof("writeCase=%t startCase=%t finishCase=%t\n", writeCase, startCase, finishCase)

			if statementBlock {
				glog.V(2).Infof("[proxy] inside a statementBlock") // keep using the same node and connection
			} else {
				if startCase {
					statementBlock = true
				}

				nextNode, err = config.Cfg.GetNextNode(writeCase)

				if err != nil {
					glog.Errorln(err.Error())
					return
				}

				//get pool index from pool channel
				poolIndex = <-nextNode.Pool.Channel

				glog.V(2).Infof("query sending to %s pool Index=%d\n", nextNode.HostPort, poolIndex)
				backendConn = nextNode.Pool.Connections[poolIndex]
			}

			if finishCase {
				statementBlock = false
				glog.V(2).Infof("outside a statementBlock")
			}

			nextNode.Stats.Queries = nextNode.Stats.Queries + 1

			var clientErr error
			clientErr, err = processBackend(client, backendConn, masterBuf, reqLen)
			if clientErr != nil {
				glog.Errorln(clientErr.Error())
				glog.Errorln("[proxy] client write error..giving up on statement")
				return
			}

			if err != nil {
				glog.Errorln(err.Error())
				glog.Errorln("[proxy] backend write error..retrying...")
				//retry logic
				//mark node as unhealthy
				config.UpdateHealth(nextNode, false)
				//return connection index to pool
				ReturnConnection(nextNode.Pool.Channel, poolIndex)
				//get new connection on master
				nextNode, err = config.Cfg.GetNextNode(true)
				poolIndex = <-nextNode.Pool.Channel
				backendConn = nextNode.Pool.Connections[poolIndex]
				clientErr, err = processBackend(client, backendConn, masterBuf, reqLen)
				if clientErr != nil {
					glog.Errorln(clientErr.Error())
					glog.Errorln("[proxy] client write erroron retry..giving up on statement")
					return
				}
				if err != nil {
					glog.Errorln("retry of query also failed, giving up on this statement...")
					ReturnConnection(nextNode.Pool.Channel, poolIndex)
					config.UpdateHealth(nextNode, false)
					writeLen, err = client.Write(GetTerminateMessage())
					if err != nil {
						glog.Errorln(err.Error())
					}
					return
				}
			}

			if poolIndex != -1 {
				ReturnConnection(nextNode.Pool.Channel, poolIndex)
			}

		} else {

			glog.V(2).Infoln("XXXX msgType here is " + msgType)

			config.Cfg.GetAllConnections()

			writeLen, err = config.Cfg.Master.TCPConn.Write(masterBuf[:reqLen])
			readLen, err = config.Cfg.Master.TCPConn.Read(masterBuf)

			if err != nil {
				glog.Errorln("master WriteRead error:" + err.Error())
			}

			msgType = string(masterBuf[0])

			//write to client only the master response
			writeLen, err = client.Write(masterBuf[:readLen])

			if err != nil {
				glog.Errorln("[proxy] closing client conn" + err.Error())
				return
			}

			glog.V(2).Infof("[proxy] wrote3 to pg client %d\n", writeLen)
		}

	}
	glog.V(2).Infoln("[proxy] closing client conn")
}
func checkError(err error) {
	if err != nil {
		glog.Fatalf("Fatal	error:	%s", err.Error())
	}
}

func getMessageTypeAndLength(buf []byte) (string, int) {
	var msgLen int32

	// Read the message length.
	reader := bytes.NewReader(buf[1:5])
	binary.Read(reader, binary.BigEndian, &msgLen)

	glog.V(2).Infof("[protocol] %d msgLen\n", msgLen)

	return string(buf[0]), int(msgLen)
}

func processBackend(client net.Conn, backendConn *net.TCPConn, masterBuf []byte, reqLen int) (error, error) {
	var writeLen, msgLen, readLen int
	var msgType string
	var err error
	var clienterr error

	writeLen, err = backendConn.Write(masterBuf[:reqLen])
	glog.V(2).Infof("wrote outbuf reqLen=%d writeLen=%d\n", reqLen, writeLen)
	if err != nil {
		glog.Errorln("[proxy] error writing to backend " + err.Error())
		return clienterr, err
	}

	for {
		readLen, err = backendConn.Read(masterBuf)
		if err != nil {
			glog.Errorln("[proxy] error reading from backend " + err.Error())
			return clienterr, err
		}
		glog.V(6).Infof("read from backend..%d\n", readLen)

		for startPos := 0; startPos < readLen; {
			msgType, msgLen = getMessageTypeAndLength(masterBuf[startPos:])

			msgLen = msgLen + 1 // add 1 for the message first byte

			//adapt msgs going back to client
			err = config.Cfg.Adapter.Do(masterBuf, readLen)

			if err != nil {
				glog.Errorln("[proxy] error adapting outbound" + err.Error())
			}

			writeLen, clienterr = client.Write(masterBuf[startPos : msgLen+startPos])
			if clienterr != nil {
				glog.Errorln("[proxy] error writing to client " + err.Error())
				return clienterr, err
			}

			glog.V(3).Infof("[proxy] wrote1 to pg client %d\n", writeLen)

			startPos = startPos + msgLen

			glog.V(3).Infof("[proxy] startPos is now %d\n", startPos)
		}
		if msgType == "Z" {
			glog.V(2).Infof("[proxy] Z msg found")
			return clienterr, err
		}
	}

	return clienterr, err
}
<commit_msg>Update proxy.go to use message type constants.<commit_after>/*
 Copyright 2017 Crunchy Data Solutions, Inc.
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
*/

package proxy

import (
	"bytes"
	"encoding/binary"
	"github.com/crunchydata/crunchy-proxy/config"
	"github.com/golang/glog"
	"net"
)

func ListenAndServe() {
	var listener net.Listener

	tcpAddr, err := net.ResolveTCPAddr("tcp", config.Cfg.HostPort)
	checkError(err)

	listener, err = net.ListenTCP("tcp", tcpAddr)
	checkError(err)

	glog.Infof("[proxy] Listening on: %s", config.Cfg.HostPort)

	handleListener(listener)
}

func handleListener(listener net.Listener) {
	for {

		conn, err := listener.Accept()

		if err != nil {
			continue
		}

		go handleClientConnection(conn)
	}
}

func handleClientConnection(client net.Conn) {
	authenticated := AuthenticateClient(client)

	// If the client could not authenticate then go no further.
	if !authenticated {
		glog.Errorln("[proxy] client could not authenticate and connect.")
		return
	}

	defer client.Close()

	var err error
	masterBuf := make([]byte, 4096)
	var writeLen int
	var readLen int
	var messageType byte
	var writeCase, startCase, finishCase = false, false, false
	var reqLen int
	var nextNode *config.Node
	var backendConn *net.TCPConn
	var poolIndex int
	var statementBlock = false

	for {

		reqLen, err = client.Read(masterBuf)
		if err != nil {
			glog.Errorln("[proxy] error reading from client conn" + err.Error())
			return
		}

		messageType = getMessageType(masterBuf)

		// adapt inbound data
		err = config.Cfg.Adapter.Do(masterBuf, reqLen)
		if err != nil {
			glog.Errorln("[proxy] error adapting inbound" + err.Error())
		}

		if messageType == TERMINATE_MESSAGE_TYPE {
			glog.V(2).Infoln("termination msg received")
			return
		} else if messageType == QUERY_MESSAGE_TYPE {
			poolIndex = -1

			// Determine if the query has an annotation.
			writeCase, startCase, finishCase = IsWriteAnno(config.Cfg.ReadAnnotation,
				config.Cfg.StartAnnotation, config.Cfg.FinishAnnotation, masterBuf)

			glog.V(2).Infof("writeCase=%t startCase=%t finishCase=%t\n", writeCase, startCase, finishCase)

			if statementBlock {
				glog.V(2).Infof("[proxy] inside a statementBlock") // keep using the same node and connection
			} else {
				if startCase {
					statementBlock = true
				}

				nextNode, err = config.Cfg.GetNextNode(writeCase)

				if err != nil {
					glog.Errorln(err.Error())
					return
				}

				//get pool index from pool channel
				poolIndex = <-nextNode.Pool.Channel

				glog.V(2).Infof("query sending to %s pool Index=%d\n", nextNode.HostPort, poolIndex)
				backendConn = nextNode.Pool.Connections[poolIndex]
			}

			if finishCase {
				statementBlock = false
				glog.V(2).Infof("outside a statementBlock")
			}

			nextNode.Stats.Queries = nextNode.Stats.Queries + 1

			var clientErr error
			clientErr, err = processBackend(client, backendConn, masterBuf, reqLen)
			if clientErr != nil {
				glog.Errorln(clientErr.Error())
				glog.Errorln("[proxy] client write error..giving up on statement")
				return
			}

			if err != nil {
				glog.Errorln(err.Error())
				glog.Errorln("[proxy] backend write error..retrying...")
				//retry logic
				//mark node as unhealthy
				config.UpdateHealth(nextNode, false)
				//return connection index to pool
				ReturnConnection(nextNode.Pool.Channel, poolIndex)
				//get new connection on master
				nextNode, err = config.Cfg.GetNextNode(true)
				poolIndex = <-nextNode.Pool.Channel
				backendConn = nextNode.Pool.Connections[poolIndex]
				clientErr, err = processBackend(client, backendConn, masterBuf, reqLen)
				if clientErr != nil {
					glog.Errorln(clientErr.Error())
					glog.Errorln("[proxy] client write erroron retry..giving up on statement")
					return
				}
				if err != nil {
					glog.Errorln("retry of query also failed, giving up on this statement...")
					ReturnConnection(nextNode.Pool.Channel, poolIndex)
					config.UpdateHealth(nextNode, false)
					writeLen, err = client.Write(GetTerminateMessage())
					if err != nil {
						glog.Errorln(err.Error())
					}
					return
				}
			}

			if poolIndex != -1 {
				ReturnConnection(nextNode.Pool.Channel, poolIndex)
			}

		} else {

			glog.V(2).Infoln("XXXX msgType here is " + string(messageType))

			config.Cfg.GetAllConnections()

			writeLen, err = config.Cfg.Master.TCPConn.Write(masterBuf[:reqLen])
			readLen, err = config.Cfg.Master.TCPConn.Read(masterBuf)

			if err != nil {
				glog.Errorln("master WriteRead error:" + err.Error())
			}

			messageType = getMessageType(masterBuf)

			//write to client only the master response
			writeLen, err = client.Write(masterBuf[:readLen])

			if err != nil {
				glog.Errorln("[proxy] closing client conn" + err.Error())
				return
			}

			glog.V(2).Infof("[proxy] wrote3 to pg client %d\n", writeLen)
		}

	}
	glog.V(2).Infoln("[proxy] closing client conn")
}

func checkError(err error) {
	if err != nil {
		glog.Fatalf("Fatal	error:	%s", err.Error())
	}
}

func getMessageTypeAndLength(buf []byte) (string, int) {
	var msgLen int32

	// Read the message length.
	reader := bytes.NewReader(buf[1:5])
	binary.Read(reader, binary.BigEndian, &msgLen)

	glog.V(2).Infof("[protocol] %d msgLen\n", msgLen)

	return string(buf[0]), int(msgLen)
}

func processBackend(client net.Conn, backendConn *net.TCPConn, masterBuf []byte, reqLen int) (error, error) {
	var writeLen, msgLen, readLen int
	var msgType string
	var err error
	var clienterr error

	writeLen, err = backendConn.Write(masterBuf[:reqLen])
	glog.V(2).Infof("wrote outbuf reqLen=%d writeLen=%d\n", reqLen, writeLen)
	if err != nil {
		glog.Errorln("[proxy] error writing to backend " + err.Error())
		return clienterr, err
	}

	for {
		readLen, err = backendConn.Read(masterBuf)
		if err != nil {
			glog.Errorln("[proxy] error reading from backend " + err.Error())
			return clienterr, err
		}
		glog.V(6).Infof("read from backend..%d\n", readLen)

		for startPos := 0; startPos < readLen; {
			msgType, msgLen = getMessageTypeAndLength(masterBuf[startPos:])

			msgLen = msgLen + 1 // add 1 for the message first byte

			//adapt msgs going back to client
			err = config.Cfg.Adapter.Do(masterBuf, readLen)

			if err != nil {
				glog.Errorln("[proxy] error adapting outbound" + err.Error())
			}

			writeLen, clienterr = client.Write(masterBuf[startPos : msgLen+startPos])
			if clienterr != nil {
				glog.Errorln("[proxy] error writing to client " + err.Error())
				return clienterr, err
			}

			glog.V(3).Infof("[proxy] wrote1 to pg client %d\n", writeLen)

			startPos = startPos + msgLen

			glog.V(3).Infof("[proxy] startPos is now %d\n", startPos)
		}
		if msgType == "Z" {
			glog.V(2).Infof("[proxy] Z msg found")
			return clienterr, err
		}
	}

	return clienterr, err
}
<|endoftext|>


<commit_before>package pt

type Material struct {
	Color       Color
	Texture     Texture
	Emittance   float64
	Attenuation Attenuation
	Index       float64 // refractive index
	Gloss       float64 // reflection cone angle in radians
	Tint        float64 // specular tinting
	Transparent bool
}

func DiffuseMaterial(color Color) Material {
	return Material{color, nil, 0, NoAttenuation, 1, 0, 0, false}
}

func SpecularMaterial(color Color, index float64) Material {
	return Material{color, nil, 0, NoAttenuation, index, 0, 0, false}
}

func GlossyMaterial(color Color, index, gloss float64) Material {
	return Material{color, nil, 0, NoAttenuation, index, gloss, 0, false}
}

func LightMaterial(color Color, emittance float64, attenuation Attenuation) Material {
	return Material{color, nil, emittance, attenuation, 1, 0, 0, false}
}
<commit_msg>TransparentMaterial<commit_after>package pt

type Material struct {
	Color       Color
	Texture     Texture
	Emittance   float64
	Attenuation Attenuation
	Index       float64 // refractive index
	Gloss       float64 // reflection cone angle in radians
	Tint        float64 // specular tinting
	Transparent bool
}

func DiffuseMaterial(color Color) Material {
	return Material{color, nil, 0, NoAttenuation, 1, 0, 0, false}
}

func SpecularMaterial(color Color, index float64) Material {
	return Material{color, nil, 0, NoAttenuation, index, 0, 0, false}
}

func GlossyMaterial(color Color, index, gloss float64) Material {
	return Material{color, nil, 0, NoAttenuation, index, gloss, 0, false}
}

func TransparentMaterial(color Color, index, gloss, tint float64) Material {
	return Material{color, nil, 0, NoAttenuation, index, gloss, tint, true}
}

func LightMaterial(color Color, emittance float64, attenuation Attenuation) Material {
	return Material{color, nil, emittance, attenuation, 1, 0, 0, false}
}
<|endoftext|>


<commit_before><commit_msg>Updated autoupdate.js to be able to handle new and removed items<commit_after><|endoftext|>


<commit_before>package apig

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

	"github.com/gedex/inflector"
	"github.com/serenize/snaker"
	"github.com/wantedly/apig/util"
)

const templateDir = "_templates"

var funcMap = template.FuncMap{
	"apibDefaultValue": apibDefaultValue,
	"apibType":         apibType,
	"pluralize":        inflector.Pluralize,
	"requestParams":    requestParams,
	"tolower":          strings.ToLower,
	"toSnakeCase":      snaker.CamelToSnake,
	"title":            strings.Title,
}

var managedFields = []string{
	"ID",
	"CreatedAt",
	"UpdatedAt",
}

func apibDefaultValue(field *Field) string {
	switch field.Type {
	case "bool":
		return "false"
	case "string":
		return strings.ToUpper(field.Name)
	case "time.Time":
		return "`2000-01-01 00:00:00`"
	case "*time.Time":
		return "`2000-01-01 00:00:00`"
	case "uint":
		return "1"
	}

	return ""
}

func apibType(field *Field) string {
	switch field.Type {
	case "bool":
		return "boolean"
	case "string":
		return "string"
	case "time.Time":
		return "string"
	case "*time.Time":
		return "string"
	case "uint":
		return "number"
	}

	switch field.Association.Type {
	case AssociationBelongsTo:
		return inflector.Pluralize(strings.ToLower(strings.Replace(field.Type, "*", "", -1)))
	case AssociationHasMany:
		return fmt.Sprintf("array[%s]", inflector.Pluralize(strings.ToLower(strings.Replace(field.Type, "[]", "", -1))))
	case AssociationHasOne:
		return inflector.Pluralize(strings.ToLower(strings.Replace(field.Type, "*", "", -1)))
	}

	return ""
}

func requestParams(fields []*Field) []*Field {
	var managed bool

	params := []*Field{}

	for _, field := range fields {
		managed = false

		for _, name := range managedFields {
			if field.Name == name {
				managed = true
			}
		}

		if !managed {
			params = append(params, field)
		}
	}

	return params
}

func generateApibIndex(detail *Detail, outDir string) error {
	body, err := Asset(filepath.Join(templateDir, "index.apib.tmpl"))

	if err != nil {
		return err
	}

	tmpl, err := template.New("apib").Funcs(funcMap).Parse(string(body))

	if err != nil {
		return err
	}

	var buf bytes.Buffer

	if err := tmpl.Execute(&buf, detail); err != nil {
		return err
	}

	dstPath := filepath.Join(outDir, "docs", "index.apib")

	if !util.FileExists(filepath.Dir(dstPath)) {
		if err := util.Mkdir(filepath.Dir(dstPath)); err != nil {
			return err
		}
	}

	if err := ioutil.WriteFile(dstPath, buf.Bytes(), 0644); err != nil {

		return err
	}

	fmt.Fprintf(os.Stdout, "\t\x1b[32m%s\x1b[0m %s\n", "create", dstPath)

	return nil
}

func generateApibModel(detail *Detail, outDir string) error {
	body, err := Asset(filepath.Join(templateDir, "model.apib.tmpl"))

	if err != nil {
		return err
	}

	tmpl, err := template.New("apib").Funcs(funcMap).Parse(string(body))

	if err != nil {
		return err
	}

	var buf bytes.Buffer

	if err := tmpl.Execute(&buf, detail); err != nil {
		return err
	}

	dstPath := filepath.Join(outDir, "docs", snaker.CamelToSnake(detail.Model.Name)+".apib")

	if !util.FileExists(filepath.Dir(dstPath)) {
		if err := util.Mkdir(filepath.Dir(dstPath)); err != nil {
			return err
		}
	}

	if err := ioutil.WriteFile(dstPath, buf.Bytes(), 0644); err != nil {
		return err
	}

	fmt.Fprintf(os.Stdout, "\t\x1b[32m%s\x1b[0m %s\n", "create", dstPath)

	return nil
}

func generateController(detail *Detail, outDir string) error {
	body, err := Asset(filepath.Join(templateDir, "controller.go.tmpl"))

	if err != nil {
		return err
	}

	tmpl, err := template.New("controller").Funcs(funcMap).Parse(string(body))

	if err != nil {
		return err
	}

	var buf bytes.Buffer

	if err := tmpl.Execute(&buf, detail); err != nil {
		return err
	}

	dstPath := filepath.Join(outDir, "controllers", snaker.CamelToSnake(detail.Model.Name)+".go")

	if !util.FileExists(filepath.Dir(dstPath)) {
		if err := util.Mkdir(filepath.Dir(dstPath)); err != nil {
			return err
		}
	}

	if err := ioutil.WriteFile(dstPath, buf.Bytes(), 0644); err != nil {
		return err
	}

	fmt.Printf("\t\x1b[32m%s\x1b[0m %s\n", "create", dstPath)

	return nil
}

func generateRootController(detail *Detail, outDir string) error {
	body, err := Asset(filepath.Join(templateDir, "root_controller.go.tmpl"))

	if err != nil {
		return err
	}

	tmpl, err := template.New("root_controller").Funcs(funcMap).Parse(string(body))

	if err != nil {
		return err
	}

	var buf bytes.Buffer

	if err := tmpl.Execute(&buf, detail); err != nil {
		return err
	}

	dstPath := filepath.Join(outDir, "controllers", "root.go")

	if !util.FileExists(filepath.Dir(dstPath)) {
		if err := util.Mkdir(filepath.Dir(dstPath)); err != nil {
			return err
		}
	}

	if err := ioutil.WriteFile(dstPath, buf.Bytes(), 0644); err != nil {
		return err
	}

	fmt.Printf("\t\x1b[32m%s\x1b[0m %s\n", "create", dstPath)

	return nil
}

func generateREADME(detail *Detail, outDir string) error {
	body, err := Asset(filepath.Join(templateDir, "README.md.tmpl"))

	if err != nil {
		return err
	}

	tmpl, err := template.New("readme").Funcs(funcMap).Parse(string(body))

	if err != nil {
		return err
	}

	var buf bytes.Buffer

	if err := tmpl.Execute(&buf, detail); err != nil {
		return err
	}

	dstPath := filepath.Join(outDir, "README.md")

	if !util.FileExists(filepath.Dir(dstPath)) {
		if err := util.Mkdir(filepath.Dir(dstPath)); err != nil {
			return err
		}
	}

	if err := ioutil.WriteFile(dstPath, buf.Bytes(), 0644); err != nil {
		return err
	}

	fmt.Fprintf(os.Stdout, "\t\x1b[32m%s\x1b[0m %s\n", "update", dstPath)

	return nil
}

func generateRouter(detail *Detail, outDir string) error {
	body, err := Asset(filepath.Join(templateDir, "router.go.tmpl"))

	if err != nil {
		return err
	}

	tmpl, err := template.New("router").Funcs(funcMap).Parse(string(body))

	if err != nil {
		return err
	}

	var buf bytes.Buffer

	if err := tmpl.Execute(&buf, detail); err != nil {
		return err
	}

	dstPath := filepath.Join(outDir, "router", "router.go")

	if !util.FileExists(filepath.Dir(dstPath)) {
		if err := util.Mkdir(filepath.Dir(dstPath)); err != nil {
			return err
		}
	}

	if err := ioutil.WriteFile(dstPath, buf.Bytes(), 0644); err != nil {
		return err
	}

	fmt.Fprintf(os.Stdout, "\t\x1b[32m%s\x1b[0m %s\n", "update", dstPath)

	return nil
}

func generateDB(detail *Detail, outDir string) error {
	body, err := Asset(filepath.Join(templateDir, "db.go.tmpl"))

	if err != nil {
		return err
	}

	tmpl, err := template.New("db").Funcs(funcMap).Parse(string(body))

	if err != nil {
		return err
	}

	var buf bytes.Buffer

	if err := tmpl.Execute(&buf, detail); err != nil {
		return err
	}

	dstPath := filepath.Join(outDir, "db", "db.go")

	if !util.FileExists(filepath.Dir(dstPath)) {
		if err := util.Mkdir(filepath.Dir(dstPath)); err != nil {
			return err
		}
	}

	if err := ioutil.WriteFile(dstPath, buf.Bytes(), 0644); err != nil {
		return err
	}

	fmt.Fprintf(os.Stdout, "\t\x1b[32m%s\x1b[0m %s\n", "update", dstPath)

	return nil
}

func Generate(outDir, modelDir, targetFile string, all bool) int {
	outModelDir := filepath.Join(outDir, modelDir)
	files, err := ioutil.ReadDir(outModelDir)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}

	var models Models
	var wg sync.WaitGroup
	modelMap := make(map[string]*Model)
	errCh := make(chan error)
	modelsCh := make(chan []*Model)
	doneCh := make(chan struct{})
	go func() {
		defer close(doneCh)
		for _, file := range files {
			wg.Add(1)
			go func(f os.FileInfo) {
				defer wg.Done()
				if f.IsDir() {
					return
				}
				if !strings.HasSuffix(f.Name(), ".go") {
					return
				}

				modelPath := filepath.Join(outModelDir, f.Name())
				ms, err := parseModel(modelPath)
				if err != nil {
					errCh <- err
				}
				modelsCh <- ms
			}(file)
		}
		wg.Wait()
	}()

	go func() {
		defer close(errCh)
	loop:
		for {
			select {
			case ms := <-modelsCh:
				for _, model := range ms {
					models = append(models, model)
					modelMap[model.Name] = model
				}
			case <-doneCh:
				errCh <- nil
				break loop
			}
		}
	}()

	err = <-errCh
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}

	sort.Sort(models)

	importPaths, err := parseImport(filepath.Join(outDir, targetFile))
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}
	importDir := formatImportDir(importPaths)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}
	switch {
	case len(importDir) > 1:
		fmt.Fprintln(os.Stderr, "Conflict import path. Please check 'main.go'.")
		return 1
	case len(importDir) == 0:
		fmt.Fprintln(os.Stderr, "Can't refer import path. Please check 'main.go'.")
		return 1
	}

	dirs := strings.SplitN(importDir[0], "/", 3)
	vcs := dirs[0]
	user := dirs[1]
	project := dirs[2]
	errCh = make(chan error)

	for _, model := range models {
		// Check association, stdout "model.Fields[0].Association.Type"
		resolveAssociate(model, modelMap, make(map[string]bool))
	}

	go func() {
		defer close(errCh)
		for _, model := range models {
			wg.Add(1)
			go func(m *Model) {
				defer wg.Done()
				d := &Detail{
					Model:     m,
					ImportDir: importDir[0],
					VCS:       vcs,
					User:      user,
					Project:   project,
				}
				if err := generateApibModel(d, outDir); err != nil {
					fmt.Fprintln(os.Stderr, err)
					errCh <- err
				}
				if err := generateController(d, outDir); err != nil {
					fmt.Fprintln(os.Stderr, err)
					errCh <- err
				}
			}(model)
		}
		wg.Wait()
	}()

	err = <-errCh
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}

	namespace, err := parseNamespace(filepath.Join(outDir, "router", "router.go"))
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}

	detail := &Detail{
		Models:    models,
		ImportDir: importDir[0],
		VCS:       vcs,
		User:      user,
		Project:   project,
		Namespace: namespace,
	}
	if all {
		if err := generateSkeleton(detail, outDir); err != nil {
			fmt.Fprintln(os.Stderr, err)
			return 1
		}
	}
	if err := generateApibIndex(detail, outDir); err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}
	if err := generateRouter(detail, outDir); err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}
	if err := generateDB(detail, outDir); err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}
	if err := generateREADME(detail, outDir); err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}
	fmt.Println("===> Generated...")
	return 0
}
<commit_msg>Generate root controller<commit_after>package apig

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

	"github.com/gedex/inflector"
	"github.com/serenize/snaker"
	"github.com/wantedly/apig/util"
)

const templateDir = "_templates"

var funcMap = template.FuncMap{
	"apibDefaultValue": apibDefaultValue,
	"apibType":         apibType,
	"pluralize":        inflector.Pluralize,
	"requestParams":    requestParams,
	"tolower":          strings.ToLower,
	"toSnakeCase":      snaker.CamelToSnake,
	"title":            strings.Title,
}

var managedFields = []string{
	"ID",
	"CreatedAt",
	"UpdatedAt",
}

func apibDefaultValue(field *Field) string {
	switch field.Type {
	case "bool":
		return "false"
	case "string":
		return strings.ToUpper(field.Name)
	case "time.Time":
		return "`2000-01-01 00:00:00`"
	case "*time.Time":
		return "`2000-01-01 00:00:00`"
	case "uint":
		return "1"
	}

	return ""
}

func apibType(field *Field) string {
	switch field.Type {
	case "bool":
		return "boolean"
	case "string":
		return "string"
	case "time.Time":
		return "string"
	case "*time.Time":
		return "string"
	case "uint":
		return "number"
	}

	switch field.Association.Type {
	case AssociationBelongsTo:
		return inflector.Pluralize(strings.ToLower(strings.Replace(field.Type, "*", "", -1)))
	case AssociationHasMany:
		return fmt.Sprintf("array[%s]", inflector.Pluralize(strings.ToLower(strings.Replace(field.Type, "[]", "", -1))))
	case AssociationHasOne:
		return inflector.Pluralize(strings.ToLower(strings.Replace(field.Type, "*", "", -1)))
	}

	return ""
}

func requestParams(fields []*Field) []*Field {
	var managed bool

	params := []*Field{}

	for _, field := range fields {
		managed = false

		for _, name := range managedFields {
			if field.Name == name {
				managed = true
			}
		}

		if !managed {
			params = append(params, field)
		}
	}

	return params
}

func generateApibIndex(detail *Detail, outDir string) error {
	body, err := Asset(filepath.Join(templateDir, "index.apib.tmpl"))

	if err != nil {
		return err
	}

	tmpl, err := template.New("apib").Funcs(funcMap).Parse(string(body))

	if err != nil {
		return err
	}

	var buf bytes.Buffer

	if err := tmpl.Execute(&buf, detail); err != nil {
		return err
	}

	dstPath := filepath.Join(outDir, "docs", "index.apib")

	if !util.FileExists(filepath.Dir(dstPath)) {
		if err := util.Mkdir(filepath.Dir(dstPath)); err != nil {
			return err
		}
	}

	if err := ioutil.WriteFile(dstPath, buf.Bytes(), 0644); err != nil {

		return err
	}

	fmt.Fprintf(os.Stdout, "\t\x1b[32m%s\x1b[0m %s\n", "create", dstPath)

	return nil
}

func generateApibModel(detail *Detail, outDir string) error {
	body, err := Asset(filepath.Join(templateDir, "model.apib.tmpl"))

	if err != nil {
		return err
	}

	tmpl, err := template.New("apib").Funcs(funcMap).Parse(string(body))

	if err != nil {
		return err
	}

	var buf bytes.Buffer

	if err := tmpl.Execute(&buf, detail); err != nil {
		return err
	}

	dstPath := filepath.Join(outDir, "docs", snaker.CamelToSnake(detail.Model.Name)+".apib")

	if !util.FileExists(filepath.Dir(dstPath)) {
		if err := util.Mkdir(filepath.Dir(dstPath)); err != nil {
			return err
		}
	}

	if err := ioutil.WriteFile(dstPath, buf.Bytes(), 0644); err != nil {
		return err
	}

	fmt.Fprintf(os.Stdout, "\t\x1b[32m%s\x1b[0m %s\n", "create", dstPath)

	return nil
}

func generateController(detail *Detail, outDir string) error {
	body, err := Asset(filepath.Join(templateDir, "controller.go.tmpl"))

	if err != nil {
		return err
	}

	tmpl, err := template.New("controller").Funcs(funcMap).Parse(string(body))

	if err != nil {
		return err
	}

	var buf bytes.Buffer

	if err := tmpl.Execute(&buf, detail); err != nil {
		return err
	}

	dstPath := filepath.Join(outDir, "controllers", snaker.CamelToSnake(detail.Model.Name)+".go")

	if !util.FileExists(filepath.Dir(dstPath)) {
		if err := util.Mkdir(filepath.Dir(dstPath)); err != nil {
			return err
		}
	}

	if err := ioutil.WriteFile(dstPath, buf.Bytes(), 0644); err != nil {
		return err
	}

	fmt.Printf("\t\x1b[32m%s\x1b[0m %s\n", "create", dstPath)

	return nil
}

func generateRootController(detail *Detail, outDir string) error {
	body, err := Asset(filepath.Join(templateDir, "root_controller.go.tmpl"))

	if err != nil {
		return err
	}

	tmpl, err := template.New("root_controller").Funcs(funcMap).Parse(string(body))

	if err != nil {
		return err
	}

	var buf bytes.Buffer

	if err := tmpl.Execute(&buf, detail); err != nil {
		return err
	}

	dstPath := filepath.Join(outDir, "controllers", "root.go")

	if !util.FileExists(filepath.Dir(dstPath)) {
		if err := util.Mkdir(filepath.Dir(dstPath)); err != nil {
			return err
		}
	}

	if err := ioutil.WriteFile(dstPath, buf.Bytes(), 0644); err != nil {
		return err
	}

	fmt.Printf("\t\x1b[32m%s\x1b[0m %s\n", "create", dstPath)

	return nil
}

func generateREADME(detail *Detail, outDir string) error {
	body, err := Asset(filepath.Join(templateDir, "README.md.tmpl"))

	if err != nil {
		return err
	}

	tmpl, err := template.New("readme").Funcs(funcMap).Parse(string(body))

	if err != nil {
		return err
	}

	var buf bytes.Buffer

	if err := tmpl.Execute(&buf, detail); err != nil {
		return err
	}

	dstPath := filepath.Join(outDir, "README.md")

	if !util.FileExists(filepath.Dir(dstPath)) {
		if err := util.Mkdir(filepath.Dir(dstPath)); err != nil {
			return err
		}
	}

	if err := ioutil.WriteFile(dstPath, buf.Bytes(), 0644); err != nil {
		return err
	}

	fmt.Fprintf(os.Stdout, "\t\x1b[32m%s\x1b[0m %s\n", "update", dstPath)

	return nil
}

func generateRouter(detail *Detail, outDir string) error {
	body, err := Asset(filepath.Join(templateDir, "router.go.tmpl"))

	if err != nil {
		return err
	}

	tmpl, err := template.New("router").Funcs(funcMap).Parse(string(body))

	if err != nil {
		return err
	}

	var buf bytes.Buffer

	if err := tmpl.Execute(&buf, detail); err != nil {
		return err
	}

	dstPath := filepath.Join(outDir, "router", "router.go")

	if !util.FileExists(filepath.Dir(dstPath)) {
		if err := util.Mkdir(filepath.Dir(dstPath)); err != nil {
			return err
		}
	}

	if err := ioutil.WriteFile(dstPath, buf.Bytes(), 0644); err != nil {
		return err
	}

	fmt.Fprintf(os.Stdout, "\t\x1b[32m%s\x1b[0m %s\n", "update", dstPath)

	return nil
}

func generateDB(detail *Detail, outDir string) error {
	body, err := Asset(filepath.Join(templateDir, "db.go.tmpl"))

	if err != nil {
		return err
	}

	tmpl, err := template.New("db").Funcs(funcMap).Parse(string(body))

	if err != nil {
		return err
	}

	var buf bytes.Buffer

	if err := tmpl.Execute(&buf, detail); err != nil {
		return err
	}

	dstPath := filepath.Join(outDir, "db", "db.go")

	if !util.FileExists(filepath.Dir(dstPath)) {
		if err := util.Mkdir(filepath.Dir(dstPath)); err != nil {
			return err
		}
	}

	if err := ioutil.WriteFile(dstPath, buf.Bytes(), 0644); err != nil {
		return err
	}

	fmt.Fprintf(os.Stdout, "\t\x1b[32m%s\x1b[0m %s\n", "update", dstPath)

	return nil
}

func Generate(outDir, modelDir, targetFile string, all bool) int {
	outModelDir := filepath.Join(outDir, modelDir)
	files, err := ioutil.ReadDir(outModelDir)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}

	var models Models
	var wg sync.WaitGroup
	modelMap := make(map[string]*Model)
	errCh := make(chan error)
	modelsCh := make(chan []*Model)
	doneCh := make(chan struct{})
	go func() {
		defer close(doneCh)
		for _, file := range files {
			wg.Add(1)
			go func(f os.FileInfo) {
				defer wg.Done()
				if f.IsDir() {
					return
				}
				if !strings.HasSuffix(f.Name(), ".go") {
					return
				}

				modelPath := filepath.Join(outModelDir, f.Name())
				ms, err := parseModel(modelPath)
				if err != nil {
					errCh <- err
				}
				modelsCh <- ms
			}(file)
		}
		wg.Wait()
	}()

	go func() {
		defer close(errCh)
	loop:
		for {
			select {
			case ms := <-modelsCh:
				for _, model := range ms {
					models = append(models, model)
					modelMap[model.Name] = model
				}
			case <-doneCh:
				errCh <- nil
				break loop
			}
		}
	}()

	err = <-errCh
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}

	sort.Sort(models)

	importPaths, err := parseImport(filepath.Join(outDir, targetFile))
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}
	importDir := formatImportDir(importPaths)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}
	switch {
	case len(importDir) > 1:
		fmt.Fprintln(os.Stderr, "Conflict import path. Please check 'main.go'.")
		return 1
	case len(importDir) == 0:
		fmt.Fprintln(os.Stderr, "Can't refer import path. Please check 'main.go'.")
		return 1
	}

	dirs := strings.SplitN(importDir[0], "/", 3)
	vcs := dirs[0]
	user := dirs[1]
	project := dirs[2]
	errCh = make(chan error)

	for _, model := range models {
		// Check association, stdout "model.Fields[0].Association.Type"
		resolveAssociate(model, modelMap, make(map[string]bool))
	}

	go func() {
		defer close(errCh)
		for _, model := range models {
			wg.Add(1)
			go func(m *Model) {
				defer wg.Done()
				d := &Detail{
					Model:     m,
					ImportDir: importDir[0],
					VCS:       vcs,
					User:      user,
					Project:   project,
				}
				if err := generateApibModel(d, outDir); err != nil {
					fmt.Fprintln(os.Stderr, err)
					errCh <- err
				}
				if err := generateController(d, outDir); err != nil {
					fmt.Fprintln(os.Stderr, err)
					errCh <- err
				}
			}(model)
		}
		wg.Wait()
	}()

	err = <-errCh
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}

	namespace, err := parseNamespace(filepath.Join(outDir, "router", "router.go"))
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}

	detail := &Detail{
		Models:    models,
		ImportDir: importDir[0],
		VCS:       vcs,
		User:      user,
		Project:   project,
		Namespace: namespace,
	}
	if all {
		if err := generateSkeleton(detail, outDir); err != nil {
			fmt.Fprintln(os.Stderr, err)
			return 1
		}
	}
	if err := generateRootController(detail, outDir); err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}
	if err := generateApibIndex(detail, outDir); err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}
	if err := generateRouter(detail, outDir); err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}
	if err := generateDB(detail, outDir); err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}
	if err := generateREADME(detail, outDir); err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}
	fmt.Println("===> Generated...")
	return 0
}
<|endoftext|>


<commit_before>/*
   Copyright 2015 Shlomi Noach.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package util

import (
	"errors"
	"fmt"
	"regexp"
	"strconv"
	"time"
)

// ParseSimpleTime parses input in the format 7s, 55m, 3h, 31d, 4w (second, minute, hour, day, week)
// The time.ParseDuration() function should have done this, but it does not support "d" and "w" extensions.
func ParseSimpleTime(simpleTime string) (time.Duration, error) {
	if matched, _ := regexp.MatchString("^[0-9]+s$", simpleTime); matched {
		i, _ := strconv.Atoi(simpleTime[0 : len(simpleTime)-1])
		return time.Duration(i) * time.Second, nil
	}
	if matched, _ := regexp.MatchString("^[0-9]+m$", simpleTime); matched {
		i, _ := strconv.Atoi(simpleTime[0 : len(simpleTime)-1])
		return time.Duration(i) * time.Minute, nil
	}
	if matched, _ := regexp.MatchString("^[0-9]+h$", simpleTime); matched {
		i, _ := strconv.Atoi(simpleTime[0 : len(simpleTime)-1])
		return time.Duration(i) * time.Hour, nil
	}
	if matched, _ := regexp.MatchString("^[0-9]+d$", simpleTime); matched {
		i, _ := strconv.Atoi(simpleTime[0 : len(simpleTime)-1])
		return time.Duration(i) * time.Hour * 24, nil
	}
	if matched, _ := regexp.MatchString("^[0-9]+w$", simpleTime); matched {
		i, _ := strconv.Atoi(simpleTime[0 : len(simpleTime)-1])
		return time.Duration(i) * time.Hour * 24 * 7, nil
	}
	return 0, errors.New(fmt.Sprintf("Cannot parse simple time: %s", simpleTime))
}
<commit_msg>ParseSimpleTime changed to SimpleTimeToSeconds<commit_after>/*
   Copyright 2015 Shlomi Noach.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package util

import (
	"errors"
	"fmt"
	"regexp"
	"strconv"
)

// ParseSimpleTime parses input in the format 7s, 55m, 3h, 31d, 4w (second, minute, hour, day, week)
// The time.ParseDuration() function should have done this, but it does not support "d" and "w" extensions.
func SimpleTimeToSeconds(simpleTime string) (int, error) {
	if matched, _ := regexp.MatchString("^[0-9]+s$", simpleTime); matched {
		i, _ := strconv.Atoi(simpleTime[0 : len(simpleTime)-1])
		return i, nil
	}
	if matched, _ := regexp.MatchString("^[0-9]+m$", simpleTime); matched {
		i, _ := strconv.Atoi(simpleTime[0 : len(simpleTime)-1])
		return i * 60, nil
	}
	if matched, _ := regexp.MatchString("^[0-9]+h$", simpleTime); matched {
		i, _ := strconv.Atoi(simpleTime[0 : len(simpleTime)-1])
		return i * 60 * 60, nil
	}
	if matched, _ := regexp.MatchString("^[0-9]+d$", simpleTime); matched {
		i, _ := strconv.Atoi(simpleTime[0 : len(simpleTime)-1])
		return i * 60 * 60 * 24, nil
	}
	if matched, _ := regexp.MatchString("^[0-9]+w$", simpleTime); matched {
		i, _ := strconv.Atoi(simpleTime[0 : len(simpleTime)-1])
		return i * 60 * 60 * 24 * 7, nil
	}
	return 0, errors.New(fmt.Sprintf("Cannot parse simple time: %s", simpleTime))
}
<|endoftext|>


<commit_before>package util

import (
	"fmt"
	"github.com/go-martini/martini"
	"github.com/leptonyu/goeast/db"
	"github.com/leptonyu/goeast/wechat"
	"html/template"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"
)

func Template(key string, m interface{}) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		t := template.New(key)
		t, _ = t.ParseFiles("templates/" + key)
		t.Execute(w, m)
	}
}

func Interval(wait time.Duration, keys ...string) {
	if len(keys) > 0 {
		go func() {
			for !c.close {
				time.Sleep(wait)
				for _, v := range keys {
					c.update(v)
				}
			}
		}()
	}
}

func StartWeb(port int, dbname string, api string) {
	m := martini.Classic()
	m.NotFound(Template("404.tpl", m))
	m.Use(martini.Static("static", martini.StaticOptions{Prefix: "static"}))
	m.Get("/", Template("index.tpl", m))
	config := db.NewDBConfig(api)
	wc, err := config.CreateWeChat(dbname, api)
	if err != nil {
		panic(err)
	}
	if port == 8080 {
		go func() {
			for {
				a, err := wc.UpdateAccessToken()
				time.Sleep((-1 * time.Since(a.ExpireTime).Seconds()) + time.Second)
			}
		}()
		f := func(wait time.Duration, keys ...string) {
			if len(keys) > 0 {
				for {
					time.Sleep(wait)
					for _, v := range keys {
						config.Update(v)
					}
				}
			}
		}
		go f(30*time.Minute, db.Blog, db.Events)
		go f(24*time.Hour,
			db.Home,
			db.Campus,
			db.Contact,
			db.Galleries,
			db.One2one,
			db.Online,
			db.Onsite,
			db.Teachers,
			db.Testimonials)
	}
	wc.HandleFunc(wechat.MsgTypeText, func(w wechat.ResponseWriter, r *wechat.Request) {
		txt := r.Content
		sig := strings.ToLower(txt)
		v, ok := mr[sig]
		if ok {
			v(w, c)
		} else {
			w.ReplyText(txt)
		}
	})
	//Create api route
	ff := wc.CreateHandlerFunc()
	m.Get("/"+c.Api, ff)
	m.Post("/"+c.Api, ff)
	err = http.ListenAndServe(":"+strconv.Itoa(port), m)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	fmt.Println("stop!")
	c.Session.Close()
	os.Exit(0)
}
<commit_msg>wechat<commit_after>package util

import (
	"fmt"
	"github.com/go-martini/martini"
	"github.com/leptonyu/goeast/db"
	"github.com/leptonyu/goeast/wechat"
	"html/template"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"
)

func Template(key string, m interface{}) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		t := template.New(key)
		t, _ = t.ParseFiles("templates/" + key)
		t.Execute(w, m)
	}
}

func StartWeb(port int, dbname string, api string) {
	m := martini.Classic()
	m.NotFound(Template("404.tpl", m))
	m.Use(martini.Static("static", martini.StaticOptions{Prefix: "static"}))
	m.Get("/", Template("index.tpl", m))
	config := db.NewDBConfig(api)
	wc, err := config.CreateWeChat(dbname, api)
	if err != nil {
		panic(err)
	}
	if port == 8080 {
		go func() {
			for {
				a, err := wc.UpdateAccessToken()
				time.Sleep((-1 * time.Since(a.ExpireTime).Seconds()) + time.Second)
			}
		}()
		f := func(wait time.Duration, keys ...string) {
			if len(keys) > 0 {
				for {
					time.Sleep(wait)
					for _, v := range keys {
						config.Update(v)
					}
				}
			}
		}
		go f(30*time.Minute, db.Blog, db.Events)
		go f(24*time.Hour,
			db.Home,
			db.Campus,
			db.Contact,
			db.Galleries,
			db.One2one,
			db.Online,
			db.Onsite,
			db.Teachers,
			db.Testimonials)
	}
	wc.HandleFunc(wechat.MsgTypeText, func(w wechat.ResponseWriter, r *wechat.Request) {
		txt := r.Content
		sig := strings.ToLower(txt)
		v, ok := mr[sig]
		if ok {
			v(w, c)
		} else {
			w.ReplyText(txt)
		}
	})
	//Create api route
	ff := wc.CreateHandlerFunc()
	m.Get("/"+c.Api, ff)
	m.Post("/"+c.Api, ff)
	err = http.ListenAndServe(":"+strconv.Itoa(port), m)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	fmt.Println("stop!")
	c.Session.Close()
	os.Exit(0)
}
<|endoftext|>


<commit_before>// Tests functions from "util.go".

package zoossh

import (
	"os"
	"testing"
	"time"
)

// Run the file "setup_tests.sh" in the scripts/ directory to obtain these
// files.
const (
	serverDescriptorDir  = "/tmp/collector-descriptors/"
	serverDescriptorFile = "/tmp/server-descriptors"
	consensusFile        = "/tmp/consensus"
)

// Benchmark the time it takes to look up a descriptor.
func BenchmarkDescriptorLookup(b *testing.B) {

	digest := "88827c73d5fd35e9638f820c44187ccdf8403b0f"
	date := time.Date(2014, time.December, 10, 0, 0, 0, 0, time.UTC)

	// Only run this benchmark if the descriptors file is there.
	if _, err := os.Stat(serverDescriptorDir); err == nil {
		for i := 0; i < b.N; i++ {
			LoadDescriptorFromDigest(serverDescriptorDir, digest, date)
		}
	}
}

// Test the function Base64ToString().
func TestBase64ToString(t *testing.T) {

	// Use a typical Base64-encoded 20-byte fingerprint.
	dec, err := Base64ToString("OVSyFvUCAKNSYpz8ZPArMLqf0Ds=")
	if err != nil {
		t.Error("Failed to decode Base64.")
	}

	if dec != "3954b216f50200a352629cfc64f02b30ba9fd03b" {
		t.Error("Base64 chunk decoded incorrectly.")
	}

	dec, err = Base64ToString("OVSyFvUCAKNSYpz8ZPArMLqf0Ds")
	if err != nil {
		t.Error("Failed to decode Base64 (with missing padding).")
	}

	if dec != "3954b216f50200a352629cfc64f02b30ba9fd03b" {
		t.Error("Base64 chunk decoded incorrectly.")
	}
}

// Test the function StringToPort().
func TestStringToPort(t *testing.T) {

	port := StringToPort("65536")
	if port != 0 {
		t.Error("Bad return value for invalid port.")
	}

	port = StringToPort("65535")
	if port != 65535 {
		t.Error("Bad return value for valid port.")
	}

	port = StringToPort("foobar")
	if port != 0 {
		t.Error("Bad return value for invalid input.")
	}
}

// Test the function String().
func TestAnnotationString(t *testing.T) {

	a := Annotation{"foobar", "0", "0"}
	s := a.String()

	if s != "@type foobar 0.0" {
		t.Errorf("Badly formatted annotation: %s", s)
	}
}

// Test the function Equals().
func TestAnnotationEquals(t *testing.T) {

	a := Annotation{"a", "b", "c"}
	b := Annotation{"a", "b", "c"}
	z := Annotation{"x", "y", "z"}

	if !a.Equals(&b) || !b.Equals(&a) {
		t.Error("Equals() incorrectly classified annotations as unequal.")
	}

	if a.Equals(&z) || z.Equals(&a) || b.Equals(&z) || z.Equals(&b) {
		t.Error("Equals() incorrectly classified annotations as equal.")
	}
}

// Test the function GetAnnotation().
func TestGetAnnotation(t *testing.T) {

	expectedDescriptorAnnotation := &Annotation{"server-descriptor", "1", "0"}
	expectedConsensusAnnotation := &Annotation{"network-status-consensus-3", "1", "0"}

	// Parse our provided server descriptor file which should work.
	if _, err := os.Stat(serverDescriptorFile); err == nil {
		annotation, err := GetAnnotation(serverDescriptorFile)
		if err != nil {
			t.Fatalf("GetAnnotation() failed to fetch annotation from \"%s\".", serverDescriptorFile)
		}

		if !annotation.Equals(expectedDescriptorAnnotation) {
			t.Errorf("Extracted annotation not as expected in \"%s\".", serverDescriptorFile)
		}
	}

	// Parse our provided consensus file which should work.
	if _, err := os.Stat(consensusFile); err == nil {
		annotation, err := GetAnnotation(consensusFile)
		if err != nil {
			t.Fatalf("GetAnnotation() failed to fetch annotation from \"%s\".", consensusFile)
		}

		if !annotation.Equals(expectedConsensusAnnotation) {
			t.Errorf("Extracted annotation not as expected in \"%s\".", consensusFile)
		}
	}

	// Make sure that a bogus file raises an error.
	_, err := GetAnnotation("/dev/zero")
	if err == nil {
		t.Error("GetAnnotation() failed to raise an error for /dev/zero.")
	}
}

// Test the function CheckAnnotation().
func TestCheckAnnotation(t *testing.T) {

	var err error

	fd, err := os.Open("/dev/zero")
	if err == nil {
		err = CheckAnnotation(fd, descriptorAnnotations)
		if err == nil {
			t.Error("CheckAnnotation() considers /dev/zero valid.")
		}
	}
	defer fd.Close()

	// Only run this test if the descriptors file is there.
	if _, err = os.Stat(serverDescriptorFile); err == nil {

		fd, err := os.Open(serverDescriptorFile)
		if err != nil {
			return
		}
		defer fd.Close()

		err = CheckAnnotation(fd, descriptorAnnotations)
		if err != nil {
			t.Error("CheckAnnotation() failed to accept annotation: ", err)
		}
		fd.Seek(0, 0)

		err = CheckAnnotation(fd, consensusAnnotations)
		if err == nil {
			t.Error("CheckAnnotation() failed to reject annotation.")
		}
	}

	// Only run this test if the consensus file is there.
	if _, err = os.Stat(consensusFile); err == nil {

		fd, err := os.Open(consensusFile)
		if err != nil {
			return
		}
		defer fd.Close()

		err = CheckAnnotation(fd, consensusAnnotations)
		if err != nil {
			t.Error("CheckAnnotation() failed to accept annotation: ", err)
		}
		fd.Seek(0, 0)

		err = CheckAnnotation(fd, descriptorAnnotations)
		if err == nil {
			t.Error("CheckAnnotation() failed to reject annotation.")
		}
	}
}

func TestSanitiseFingerprint(t *testing.T) {

	if SanitiseFingerprint(" foo bar\n \t") != "FOO BAR" {
		t.Error("Fingerprint not sanitised successfully.")
	}
}

func TestLoadDescriptorFromDigest(t *testing.T) {

	_, err := LoadDescriptorFromDigest("", "foobar", time.Now())
	if err == nil {
		t.Error("Non-existant digest did not return error.")
	}

	date := time.Date(2014, 12, 8, 0, 0, 0, 0, time.UTC)
	if _, err := os.Stat(serverDescriptorDir); err == nil {
		desc, err := LoadDescriptorFromDigest(serverDescriptorDir,
			"7aef3ff4d6a3b20c03ebefef94e6dfca4d9b663a", date)
		if err != nil {
			t.Fatalf("Could not find and return descriptor.")
		}

		if desc.Fingerprint != Fingerprint("7BD84CB63845E0D61C1CFA83914A1B8C968482B1") {
			t.Error("Invalid descriptor returned.")
		}

		// Test previous month.
		desc, err = LoadDescriptorFromDigest(serverDescriptorDir,
			"88827c73d5fd35e9638f820c44187ccdf8403b0f", date)
		if err != nil {
			t.Fatalf("Could not find and return descriptor from previous month.")
		}

		if desc.Fingerprint != Fingerprint("7BD84CB63845E0D61C1CFA83914A1B8C968482B1") {
			t.Error("Invalid descriptor returned.")
		}
	}
}
<commit_msg>Add tests for parseAnnotation.<commit_after>// Tests functions from "util.go".

package zoossh

import (
	"os"
	"testing"
	"time"
)

// Run the file "setup_tests.sh" in the scripts/ directory to obtain these
// files.
const (
	serverDescriptorDir  = "/tmp/collector-descriptors/"
	serverDescriptorFile = "/tmp/server-descriptors"
	consensusFile        = "/tmp/consensus"
)

// Benchmark the time it takes to look up a descriptor.
func BenchmarkDescriptorLookup(b *testing.B) {

	digest := "88827c73d5fd35e9638f820c44187ccdf8403b0f"
	date := time.Date(2014, time.December, 10, 0, 0, 0, 0, time.UTC)

	// Only run this benchmark if the descriptors file is there.
	if _, err := os.Stat(serverDescriptorDir); err == nil {
		for i := 0; i < b.N; i++ {
			LoadDescriptorFromDigest(serverDescriptorDir, digest, date)
		}
	}
}

// Test the function Base64ToString().
func TestBase64ToString(t *testing.T) {

	// Use a typical Base64-encoded 20-byte fingerprint.
	dec, err := Base64ToString("OVSyFvUCAKNSYpz8ZPArMLqf0Ds=")
	if err != nil {
		t.Error("Failed to decode Base64.")
	}

	if dec != "3954b216f50200a352629cfc64f02b30ba9fd03b" {
		t.Error("Base64 chunk decoded incorrectly.")
	}

	dec, err = Base64ToString("OVSyFvUCAKNSYpz8ZPArMLqf0Ds")
	if err != nil {
		t.Error("Failed to decode Base64 (with missing padding).")
	}

	if dec != "3954b216f50200a352629cfc64f02b30ba9fd03b" {
		t.Error("Base64 chunk decoded incorrectly.")
	}
}

// Test the function StringToPort().
func TestStringToPort(t *testing.T) {

	port := StringToPort("65536")
	if port != 0 {
		t.Error("Bad return value for invalid port.")
	}

	port = StringToPort("65535")
	if port != 65535 {
		t.Error("Bad return value for valid port.")
	}

	port = StringToPort("foobar")
	if port != 0 {
		t.Error("Bad return value for invalid input.")
	}
}

// Test the function String().
func TestAnnotationString(t *testing.T) {

	a := Annotation{"foobar", "0", "0"}
	s := a.String()

	if s != "@type foobar 0.0" {
		t.Errorf("Badly formatted annotation: %s", s)
	}
}

// Test the function Equals().
func TestAnnotationEquals(t *testing.T) {

	a := Annotation{"a", "b", "c"}
	b := Annotation{"a", "b", "c"}
	z := Annotation{"x", "y", "z"}

	if !a.Equals(&b) || !b.Equals(&a) {
		t.Error("Equals() incorrectly classified annotations as unequal.")
	}

	if a.Equals(&z) || z.Equals(&a) || b.Equals(&z) || z.Equals(&b) {
		t.Error("Equals() incorrectly classified annotations as equal.")
	}
}

// Test the function parseAnnotation().
func TestParseAnnotation(t *testing.T) {

	goodTests := []struct {
		s        string
		expected Annotation
	}{
		{"@type server-descriptor 1.0", Annotation{"server-descriptor", "1", "0"}},
		{"@type server-descriptor 1.2", Annotation{"server-descriptor", "1", "2"}},
		{"@type server-descriptor 2.0", Annotation{"server-descriptor", "2", "0"}},
		{"@type extra-info 2.0", Annotation{"extra-info", "2", "0"}},
		{"@type CASE 1.0", Annotation{"CASE", "1", "0"}},
	}
	badTests := []string{
		"",
		"@type test",
		"@type 1.0",
		"@type test 1",
		"@type test 1.",
		"@type test .0",
		"@type test 1.0 more",
		"@TYPE test 1.0",
		"@typo test 1.0",
		"type test 1.0",
	}

	for _, test := range goodTests {
		annotation, err := parseAnnotation(test.s)
		if err != nil {
			t.Errorf("%q resulted in an error: %s", test.s, err)
		}
		if !annotation.Equals(&test.expected) {
			t.Errorf("%q did not compare equal to %q", test.s, test.expected)
		}
	}

	for _, s := range badTests {
		_, err := parseAnnotation(s)
		if err == nil {
			t.Errorf("%q resulted in no error", s)
		}
	}
}

// Test the function GetAnnotation().
func TestGetAnnotation(t *testing.T) {

	expectedDescriptorAnnotation := &Annotation{"server-descriptor", "1", "0"}
	expectedConsensusAnnotation := &Annotation{"network-status-consensus-3", "1", "0"}

	// Parse our provided server descriptor file which should work.
	if _, err := os.Stat(serverDescriptorFile); err == nil {
		annotation, err := GetAnnotation(serverDescriptorFile)
		if err != nil {
			t.Fatalf("GetAnnotation() failed to fetch annotation from \"%s\".", serverDescriptorFile)
		}

		if !annotation.Equals(expectedDescriptorAnnotation) {
			t.Errorf("Extracted annotation not as expected in \"%s\".", serverDescriptorFile)
		}
	}

	// Parse our provided consensus file which should work.
	if _, err := os.Stat(consensusFile); err == nil {
		annotation, err := GetAnnotation(consensusFile)
		if err != nil {
			t.Fatalf("GetAnnotation() failed to fetch annotation from \"%s\".", consensusFile)
		}

		if !annotation.Equals(expectedConsensusAnnotation) {
			t.Errorf("Extracted annotation not as expected in \"%s\".", consensusFile)
		}
	}

	// Make sure that a bogus file raises an error.
	_, err := GetAnnotation("/dev/zero")
	if err == nil {
		t.Error("GetAnnotation() failed to raise an error for /dev/zero.")
	}
}

// Test the function CheckAnnotation().
func TestCheckAnnotation(t *testing.T) {

	var err error

	fd, err := os.Open("/dev/zero")
	if err == nil {
		err = CheckAnnotation(fd, descriptorAnnotations)
		if err == nil {
			t.Error("CheckAnnotation() considers /dev/zero valid.")
		}
	}
	defer fd.Close()

	// Only run this test if the descriptors file is there.
	if _, err = os.Stat(serverDescriptorFile); err == nil {

		fd, err := os.Open(serverDescriptorFile)
		if err != nil {
			return
		}
		defer fd.Close()

		err = CheckAnnotation(fd, descriptorAnnotations)
		if err != nil {
			t.Error("CheckAnnotation() failed to accept annotation: ", err)
		}
		fd.Seek(0, 0)

		err = CheckAnnotation(fd, consensusAnnotations)
		if err == nil {
			t.Error("CheckAnnotation() failed to reject annotation.")
		}
	}

	// Only run this test if the consensus file is there.
	if _, err = os.Stat(consensusFile); err == nil {

		fd, err := os.Open(consensusFile)
		if err != nil {
			return
		}
		defer fd.Close()

		err = CheckAnnotation(fd, consensusAnnotations)
		if err != nil {
			t.Error("CheckAnnotation() failed to accept annotation: ", err)
		}
		fd.Seek(0, 0)

		err = CheckAnnotation(fd, descriptorAnnotations)
		if err == nil {
			t.Error("CheckAnnotation() failed to reject annotation.")
		}
	}
}

func TestSanitiseFingerprint(t *testing.T) {

	if SanitiseFingerprint(" foo bar\n \t") != "FOO BAR" {
		t.Error("Fingerprint not sanitised successfully.")
	}
}

func TestLoadDescriptorFromDigest(t *testing.T) {

	_, err := LoadDescriptorFromDigest("", "foobar", time.Now())
	if err == nil {
		t.Error("Non-existant digest did not return error.")
	}

	date := time.Date(2014, 12, 8, 0, 0, 0, 0, time.UTC)
	if _, err := os.Stat(serverDescriptorDir); err == nil {
		desc, err := LoadDescriptorFromDigest(serverDescriptorDir,
			"7aef3ff4d6a3b20c03ebefef94e6dfca4d9b663a", date)
		if err != nil {
			t.Fatalf("Could not find and return descriptor.")
		}

		if desc.Fingerprint != Fingerprint("7BD84CB63845E0D61C1CFA83914A1B8C968482B1") {
			t.Error("Invalid descriptor returned.")
		}

		// Test previous month.
		desc, err = LoadDescriptorFromDigest(serverDescriptorDir,
			"88827c73d5fd35e9638f820c44187ccdf8403b0f", date)
		if err != nil {
			t.Fatalf("Could not find and return descriptor from previous month.")
		}

		if desc.Fingerprint != Fingerprint("7BD84CB63845E0D61C1CFA83914A1B8C968482B1") {
			t.Error("Invalid descriptor returned.")
		}
	}
}
<|endoftext|>


<commit_before>package atomas
import (
	"container/list"
)

const (
	PLUS_SIGN  int = 0
)

func EvaluateBoard(arrayBoard []int) (int, []int) {
	score, multiplier, board := lookForPossibleCombinations(toList(arrayBoard), 1, 0)
	return score * multiplier, toArray(board)
}

func lookForPossibleCombinations(board *list.List, multiplier int, score int) (int, int, *list.List) {
	for e := board.Front(); e != nil; e = e.Next() {
		if e.Value == PLUS_SIGN && shouldMergeElements(board, e) {
			score, multiplier, board = combineElements(board, e, multiplier, score)
		}
	}
	return score, multiplier, board
}

func combineElements(board *list.List, element *list.Element, multiplier int, score int) (int, int, *list.List) {
	next := nextWithLoop(board, element)
	prev := prevWithLoop(board, element)
	surroundingValue := next.Value.(int)
	score += surroundingValue * 2
	element.Value = Max(surroundingValue, element.Value.(int)) + 1
	board.Remove(prev)
	board.Remove(next)
	if (shouldMergeElements(board, element)) {
		return combineElements(board, element, multiplier + 1, score)
	} else if (aNewMergeEmerged(board)) {
		return lookForPossibleCombinations(board, multiplier + 1, score)
	}else {
		return score, multiplier, board
	}
}

func shouldMergeElements(board *list.List, element *list.Element) bool {
	return (board.Len() > 2 && isSurroundingSame(board, element) && theyAreProperElement(board, element))
}

func aNewMergeEmerged(board *list.List) bool {
	for e := board.Front(); e != nil; e = e.Next() {
		if e.Value == PLUS_SIGN && shouldMergeElements(board, e) {
			return true
		}
	}
	return false
}

func theyAreProperElement(board *list.List, element *list.Element) bool {
	return nextWithLoop(board, element).Value.(int) > 0
}

func nextWithLoop(board *list.List, element *list.Element) *list.Element {
	if (element.Next() != nil ) {
		return element.Next()
	}else {
		return board.Front()
	}
}

func prevWithLoop(board *list.List, element *list.Element) *list.Element {
	if (element.Prev() != nil ) {
		return element.Prev()
	}else {
		return board.Back()
	}
}

func isSurroundingSame(board *list.List, element *list.Element) bool {
	return nextWithLoop(board, element).Value == prevWithLoop(board, element).Value
}

func toList(board []int) *list.List {
	result := list.New()
	for _, element := range board {
		result.PushBack(int(element))
	}
	return result
}

func toArray(board *list.List) []int {
	array := make([]int, board.Len())
	i := 0
	for e := board.Front(); e != nil; e = e.Next() {
		array[i] = e.Value.(int)
		i += 1
	}
	return array
}
<commit_msg>simplify lookForPossibleCombinations<commit_after>package atomas
import (
	"container/list"
)

const (
	PLUS_SIGN  int = 0
)

func EvaluateBoard(arrayBoard []int) (int, []int) {
	score, multiplier, board := lookForPossibleCombinations(toList(arrayBoard), 1, 0)
	return score * multiplier, toArray(board)
}

func lookForPossibleCombinations(board *list.List, multiplier int, score int) (int, int, *list.List) {
	mergablePlusSign := findMergablePlusSign(board)
	if (mergablePlusSign == nil) {
		return score, multiplier, board
	}else {
		return applyPlusSign(board, mergablePlusSign, multiplier, score)
	}
}

func applyPlusSign(board *list.List, element *list.Element, multiplier int, score int) (int, int, *list.List) {
	next := nextWithLoop(board, element)
	prev := prevWithLoop(board, element)
	surroundingValue := next.Value.(int)
	score += surroundingValue * 2
	element.Value = Max(surroundingValue, element.Value.(int)) + 1
	board.Remove(prev)
	board.Remove(next)
	if (shouldMergeElements(board, element)) {
		return applyPlusSign(board, element, multiplier + 1, score)
	} else if (findMergablePlusSign(board) != nil) {
		return lookForPossibleCombinations(board, multiplier + 1, score)
	}else {
		return score, multiplier, board
	}
}

func shouldMergeElements(board *list.List, element *list.Element) bool {
	return (board.Len() > 2 && isSurroundingSame(board, element) && theyAreProperElement(board, element))
}

func findMergablePlusSign(board *list.List) *list.Element {
	for e := board.Front(); e != nil; e = e.Next() {
		if e.Value == PLUS_SIGN && shouldMergeElements(board, e) {
			return e
		}
	}
	return nil
}

func theyAreProperElement(board *list.List, element *list.Element) bool {
	return nextWithLoop(board, element).Value.(int) > 0
}

func nextWithLoop(board *list.List, element *list.Element) *list.Element {
	if (element.Next() != nil ) {
		return element.Next()
	}else {
		return board.Front()
	}
}

func prevWithLoop(board *list.List, element *list.Element) *list.Element {
	if (element.Prev() != nil ) {
		return element.Prev()
	}else {
		return board.Back()
	}
}

func isSurroundingSame(board *list.List, element *list.Element) bool {
	return nextWithLoop(board, element).Value == prevWithLoop(board, element).Value
}

func toList(board []int) *list.List {
	result := list.New()
	for _, element := range board {
		result.PushBack(int(element))
	}
	return result
}

func toArray(board *list.List) []int {
	array := make([]int, board.Len())
	i := 0
	for e := board.Front(); e != nil; e = e.Next() {
		array[i] = e.Value.(int)
		i += 1
	}
	return array
}
<|endoftext|>


<commit_before>package gat

import (
	libgit "github.com/libgit2/git2go"

	"polydawn.net/danggit/api"
)

type treeEntry struct {
	Filename string          // use full path
	Filemode libgit.Filemode // TODO git off my lawn c consts good lord
	Content  []byte          // for files
	// gitlinks not yet described by this struct
}

func createCommit(
	repo *libgit.Repository,
	commitHeaders *git.Commit, // treeID will be replaced
	contents []treeEntry,
) git.CommitID {
	if commitHeaders.TreeID != "" {
		panic("misuse: treeID will be set based on the contents you provided")
	}

	// assemble tree
	var treeOid *libgit.Oid
	func() {
		treeBuilder, err := repo.TreeBuilder()
		maybePanic(err)
		defer treeBuilder.Free()

		for _, content := range contents {
			switch content.Filemode {
			case libgit.FilemodeTree:
				panic("TODO")
			case libgit.FilemodeBlob, libgit.FilemodeBlobExecutable:
				// save blob
				blobOid, err := repo.CreateBlobFromBuffer(content.Content)
				maybePanic(err)
				// insert
				treeBuilder.Insert(content.Filename, blobOid, content.Filemode)
			case libgit.FilemodeLink:
				panic("TODO")
			case libgit.FilemodeCommit:
				panic("TODO")
			}

		}

		// write tree
		treeOid, err = treeBuilder.Write()
		maybePanic(err)
	}()
	// immediately look it up again because silly api
	tree, err := repo.LookupTree(treeOid)
	maybePanic(err)

	// assemble commit (mostly translating structs)
	commitOid, err := repo.CreateCommit(
		"",
		&libgit.Signature{
			Name:  commitHeaders.Author.Name,
			Email: commitHeaders.Author.Email,
			When:  commitHeaders.Author.When,
		},
		&libgit.Signature{
			Name:  commitHeaders.Committer.Name,
			Email: commitHeaders.Committer.Email,
			When:  commitHeaders.Committer.When,
		},
		commitHeaders.Message,
		tree,
	)
	maybePanic(err)
	return git.CommitID(commitOid.String())
}
<commit_msg>Don't drop errors from treebuilder.<commit_after>package gat

import (
	libgit "github.com/libgit2/git2go"

	"polydawn.net/danggit/api"
)

type treeEntry struct {
	Filename string          // use full path
	Filemode libgit.Filemode // TODO git off my lawn c consts good lord
	Content  []byte          // for files
	// gitlinks not yet described by this struct
}

func createCommit(
	repo *libgit.Repository,
	commitHeaders *git.Commit, // treeID will be replaced
	contents []treeEntry,
) git.CommitID {
	if commitHeaders.TreeID != "" {
		panic("misuse: treeID will be set based on the contents you provided")
	}

	// assemble tree
	var treeOid *libgit.Oid
	func() {
		treeBuilder, err := repo.TreeBuilder()
		maybePanic(err)
		defer treeBuilder.Free()

		for _, content := range contents {
			switch content.Filemode {
			case libgit.FilemodeTree:
				panic("TODO")
			case libgit.FilemodeBlob, libgit.FilemodeBlobExecutable:
				// save blob
				blobOid, err := repo.CreateBlobFromBuffer(content.Content)
				maybePanic(err)
				// insert
				err = treeBuilder.Insert(content.Filename, blobOid, content.Filemode)
				maybePanic(err)
			case libgit.FilemodeLink:
				panic("TODO")
			case libgit.FilemodeCommit:
				panic("TODO")
			}

		}

		// write tree
		treeOid, err = treeBuilder.Write()
		maybePanic(err)
	}()
	// immediately look it up again because silly api
	tree, err := repo.LookupTree(treeOid)
	maybePanic(err)

	// assemble commit (mostly translating structs)
	commitOid, err := repo.CreateCommit(
		"",
		&libgit.Signature{
			Name:  commitHeaders.Author.Name,
			Email: commitHeaders.Author.Email,
			When:  commitHeaders.Author.When,
		},
		&libgit.Signature{
			Name:  commitHeaders.Committer.Name,
			Email: commitHeaders.Committer.Email,
			When:  commitHeaders.Committer.When,
		},
		commitHeaders.Message,
		tree,
	)
	maybePanic(err)
	return git.CommitID(commitOid.String())
}
<|endoftext|>


<commit_before><commit_msg>Make IsPDB smarter. Detect SCOP domains, support new syntax, etc.<commit_after><|endoftext|>


<commit_before>package suss

import (
	"encoding/binary"
	"math"
	"math/rand"
)

type SliceGen struct {
	Avg int
	Min int
	Max int

	f func()
}

// Generator generates
// data to be used in a test.
// Fill should draw bytes from the Data interface
// and change its own value based off those bytes.
//
// Generators can be passed to the Runner.Draw function
// to be supplied with a Data to draw bytes from.
// This is the main way to get varying data that might
// cause tests to fail.
type Generator interface {
	Fill(d Data)
}

// Data is an interface passed to Fill methods on types implementing
// the Generator interface. It is the main method for getting random
// data from the Suspicion runner.
type Data interface {
	// Draw is the main way to get random data
	// for a Suspicion test. It takes a number of bytes
	// to draw and a Sample function. The Sample function
	// should return a valid byte sequence for the value.
	//
	// Since return values from Sample is used as examples
	// during execution, it is adventageous to return
	// interesting values. Floating point Not-a-Number
	// and Infinity values is a good example of such a
	// value.
	//
	// During test execution, Draw might return the value
	// from Sample or a random one. Callers must handle
	// any random byte sequence, either by reinterpreting it
	// or calling Invalid.
	Draw(n int, smp Sample) []byte

	// StartExample and EndExample are used to specify boundaries for
	// draws. The shrinking algorithm uses these boundaries to make
	// decisions about how to shrink.
	//
	// Most users will not need to
	// explicitly call these functions, since Draw inserts StartExample
	// and EndExample calls around calls to Fill.
	//
	// Calls to these functions can be nested.
	StartExample()
	EndExample()
}

// Slice returns a generator for a slice value.
// It will repeatedly call the given function
// during fill. It is the functions responsibility
// to build the slice wanted.
//
// An example of the proper use of
// Slice:
//
//	var f []float64
//	s := suss.Slice(func() {
//		f = append(f, runner.Float64())
//	})
//	runner.Draw(s)
func Slice(f func()) *SliceGen {
	return &SliceGen{
		Avg: 50,
		Min: 0,
		Max: int(^uint(0) >> 1),
		f:   f,
	}
}

func (s *SliceGen) Fill(d Data) {
	// The intuitive way to turn an infinite bytestream into a
	// slice would be to grab a value at the beginning
	// and then generate that number of elements
	// However, this gets in the way of shrinking
	//
	// Instead, for each element, grab a byte
	// asking us if we want more elements.
	// That way, deleting a span in the byte
	// stream turns into the element not being
	// added.
	l := uint64(0)
	stopvalue := 1 - (1.0 / (1 + float64(s.Avg)))
	if s.Min < 0 {
		panic("invalid min slice length")
	}
	min := uint64(s.Min)
	max := uint64(s.Max)
	for l < max {
		d.StartExample()
		more := biasBool(d, stopvalue)
		if !more && l >= min {
			d.EndExample()
			return
		}
		l++
		s.f()
		d.EndExample()
	}
}

// BoolGen implements a generator for boolean values.
type BoolGen bool

func (b *BoolGen) Fill(d Data) {
	byt := d.Draw(1, Uniform)
	*b = byt[0]&1 == 1
}

// Bool is a convenience function that returns
// a boolean value from the Runner.
func (r *Runner) Bool() bool {
	var bgen BoolGen
	r.Draw(&bgen)
	return bool(bgen)
}

// Float64 is a convenience function that returns
// a float64 value from the Runner.
func (r *Runner) Float64() float64 {
	var f Float64Gen
	r.Draw(&f)
	return float64(f)
}

// Float64Gen implements a generator for float64 values.
type Float64Gen float64

func (f *Float64Gen) Fill(d Data) {
	fbits := d.Draw(10, func(r *rand.Rand, n int) []byte {
		if n != 10 {
			panic("bad float size")
		}
		flavor := r.Intn(5)
		var f float64
		switch flavor {
		case 0:
			f = math.NaN()
		case 1:
			f = math.Inf(0)
		case 2:
			f = math.Inf(-1)
		case 3:
			// TODO incorporate evil floats from hypothesis
			f = 0
		default:
			f = r.Float64()
			f *= math.MaxFloat64
			if r.Intn(2) == 1 {
				f = -f
			}
		}
		b := encodefloat64(f)
		return b[:]
	})
	fl, invalid := decodefloat64(fbits)
	if invalid {
		Invalid()
	}
	*f = Float64Gen(fl)
}

// encodefloat64 attempts to encode a floating point number
// so that its lexicographical ordering follows human intuition
//
// Design goals were:
// - Integers are simpler than fractionals
// - positive numbers are simpler than negative ones
// - exponents of smaller magnitude are simpler, regardless of sign
// - 0 is the simplest number, 1 is the second most simple number
func encodefloat64(f float64) [10]byte {
	var b [10]byte
	bits := math.Float64bits(f)
	// encode the sign bit as a single byte
	b[0] = byte((bits & (1 << 63)) >> 63)

	// for the mantissa, we want simpler fractions
	// This means we get numbers that require fewer
	// digits to print it
	// Encoding as a little endian number
	// makes shrinking go towards a number with
	// fewer significant digits
	mant := bits & (^uint64(0) >> (64 - 52))
	binary.LittleEndian.PutUint64(b[1:], mant)

	// if the exponent is 0, that means this value
	// is a zero. don't unbias the exponent in this case
	// TODO: handle subnormals so that they're more complex
	sexp := int16((bits >> 52) & 0x7ff)
	var exp uint16
	if sexp == 0 {
		if mant != 0 {
			// subnormal number, use the extra range we get from
			// int16 to signal this
			exp = sint16tolex16(-1024)
		}
	} else if sexp == 0x7ff {
		// infinity and NaN, they're more complex that negative
		// exponent and subnormals
		exp = sint16tolex16(-1025)
	} else {
		// regular exponent
		// unbias
		sexp -= 1023
		// if exponent is positive, bias it +1
		// so that an exponent of 1 becomes 0
		// This keeps the invariant that 0 is
		// simpler than 1
		if sexp >= 0 {
			exp = uint16(sexp) + 1
		} else {
			// for negative exponents
			// use signed regular integer
			// This makes -1 simpler than -2
			// when interpreted as a byte stream
			// the sign keeps the invariant that
			// integers are simpler than fractionals
			exp = sint16tolex16(sexp)
		}
	}
	binary.BigEndian.PutUint16(b[8:], exp)
	return b
}

func sint16tolex16(s int16) uint16 {
	s *= -1
	exp := uint16(s)
	exp ^= (1 << 15)
	return exp
}

func decodefloat64(b []byte) (float64, bool) {
	fbits := uint64(0)
	sign := b[0]
	if sign != 0 && sign != 1 {
		return 0, true
	}
	fbits = uint64(sign) << 63
	// mantissa only take 7 bytes in our binary packing
	// but binary only lets us read in chunks of 8
	// copy the mantissa value into an empty array
	// and then decode to make sure that we don't
	var mb [8]byte
	copy(mb[:], b[1:8])
	mant := binary.LittleEndian.Uint64(mb[:])

	exp := binary.BigEndian.Uint16(b[8:])
	if exp&(1<<15) != 0 {
		// this is a signed exponent
		// clear the sign bit
		sexp := int16(exp & (^uint16(0) >> 1))
		if sexp == 1024 {
			exp = 0
		} else if sexp == 1025 {
			exp = 0x7ff
		} else {
			// this is a regular negative exponent
			// make into negative number
			sexp *= -1
			// bias
			sexp += 1023
			exp = uint16(sexp)
		}
	} else if exp != 0 {
		// positive exponent
		exp -= 1
		exp += 1023
	} else if mant != 0 {
		mant = 0
	}
	fbits ^= mant & (^uint64(0) >> (64 - 52))
	fbits ^= uint64(exp) << 52
	return math.Float64frombits(fbits), false
}

// Uint64Gen implements a generator for uint64 values.
type Uint64Gen uint64

func (u *Uint64Gen) Fill(d Data) {
	b := d.Draw(8, Uniform)
	*u = Uint64Gen(binary.BigEndian.Uint64(b))
}

// Uint64 is a convenience function that returns
// a uint64 value from the Runner.
func (r *Runner) Uint64() uint64 {
	var u Uint64Gen
	r.Draw(&u)
	return uint64(u)
}

// Int16Gen implements a generator for int16 values.
type Int16Gen int16

func (i *Int16Gen) Fill(d Data) {
	f := d.Draw(2, Uniform)
	*i = Int16Gen(binary.BigEndian.Uint16(f))
}

// Int16 is a convenience function that returns
// a int16 value from the Runner.
func (r *Runner) Int16() int16 {
	var i Int16Gen
	r.Draw(&i)
	return int16(i)
}

// ByteGen implements a generator for byte values.
type ByteGen byte

func (b *ByteGen) Fill(d Data) {
	*b = ByteGen(d.Draw(1, Uniform)[0])
}

// Byte is a convenience function that returns
// a byte value from the Runner.
func (r *Runner) Byte() byte {
	var b ByteGen
	r.Draw(&b)
	return byte(b)
}

func biasBool(d Data, f float64) bool {
	bits := d.Draw(1, func(r *rand.Rand, n int) []byte {
		roll := r.Float64()
		b := byte(0)
		if roll < f {
			b = 1
		}
		return []byte{b}
	})
	return bits[0] != 0
}
<commit_msg>add Int63n generator<commit_after>package suss

import (
	"encoding/binary"
	"math"
	"math/rand"
)

type SliceGen struct {
	Avg int
	Min int
	Max int

	f func()
}

// Generator generates
// data to be used in a test.
// Fill should draw bytes from the Data interface
// and change its own value based off those bytes.
//
// Generators can be passed to the Runner.Draw function
// to be supplied with a Data to draw bytes from.
// This is the main way to get varying data that might
// cause tests to fail.
type Generator interface {
	Fill(d Data)
}

// Data is an interface passed to Fill methods on types implementing
// the Generator interface. It is the main method for getting random
// data from the Suspicion runner.
type Data interface {
	// Draw is the main way to get random data
	// for a Suspicion test. It takes a number of bytes
	// to draw and a Sample function. The Sample function
	// should return a valid byte sequence for the value.
	//
	// Since return values from Sample is used as examples
	// during execution, it is adventageous to return
	// interesting values. Floating point Not-a-Number
	// and Infinity values is a good example of such a
	// value.
	//
	// During test execution, Draw might return the value
	// from Sample or a random one. Callers must handle
	// any random byte sequence, either by reinterpreting it
	// or calling Invalid.
	Draw(n int, smp Sample) []byte

	// StartExample and EndExample are used to specify boundaries for
	// draws. The shrinking algorithm uses these boundaries to make
	// decisions about how to shrink.
	//
	// Most users will not need to
	// explicitly call these functions, since Draw inserts StartExample
	// and EndExample calls around calls to Fill.
	//
	// Calls to these functions can be nested.
	StartExample()
	EndExample()
}

// Slice returns a generator for a slice value.
// It will repeatedly call the given function
// during fill. It is the functions responsibility
// to build the slice wanted.
//
// An example of the proper use of
// Slice:
//
//	var f []float64
//	s := suss.Slice(func() {
//		f = append(f, runner.Float64())
//	})
//	runner.Draw(s)
func Slice(f func()) *SliceGen {
	return &SliceGen{
		Avg: 50,
		Min: 0,
		Max: int(^uint(0) >> 1),
		f:   f,
	}
}

func (s *SliceGen) Fill(d Data) {
	// The intuitive way to turn an infinite bytestream into a
	// slice would be to grab a value at the beginning
	// and then generate that number of elements
	// However, this gets in the way of shrinking
	//
	// Instead, for each element, grab a byte
	// asking us if we want more elements.
	// That way, deleting a span in the byte
	// stream turns into the element not being
	// added.
	l := uint64(0)
	stopvalue := 1 - (1.0 / (1 + float64(s.Avg)))
	if s.Min < 0 {
		panic("invalid min slice length")
	}
	min := uint64(s.Min)
	max := uint64(s.Max)
	for l < max {
		d.StartExample()
		more := biasBool(d, stopvalue)
		if !more && l >= min {
			d.EndExample()
			return
		}
		l++
		s.f()
		d.EndExample()
	}
}

// BoolGen implements a generator for boolean values.
type BoolGen bool

func (b *BoolGen) Fill(d Data) {
	byt := d.Draw(1, Uniform)
	*b = byt[0]&1 == 1
}

// Bool is a convenience function that returns
// a boolean value from the Runner.
func (r *Runner) Bool() bool {
	var bgen BoolGen
	r.Draw(&bgen)
	return bool(bgen)
}

// Float64 is a convenience function that returns
// a float64 value from the Runner.
func (r *Runner) Float64() float64 {
	var f Float64Gen
	r.Draw(&f)
	return float64(f)
}

// Float64Gen implements a generator for float64 values.
type Float64Gen float64

func (f *Float64Gen) Fill(d Data) {
	fbits := d.Draw(10, func(r *rand.Rand, n int) []byte {
		if n != 10 {
			panic("bad float size")
		}
		flavor := r.Intn(5)
		var f float64
		switch flavor {
		case 0:
			f = math.NaN()
		case 1:
			f = math.Inf(0)
		case 2:
			f = math.Inf(-1)
		case 3:
			// TODO incorporate evil floats from hypothesis
			f = 0
		default:
			f = r.Float64()
			f *= math.MaxFloat64
			if r.Intn(2) == 1 {
				f = -f
			}
		}
		b := encodefloat64(f)
		return b[:]
	})
	fl, invalid := decodefloat64(fbits)
	if invalid {
		Invalid()
	}
	*f = Float64Gen(fl)
}

// encodefloat64 attempts to encode a floating point number
// so that its lexicographical ordering follows human intuition
//
// Design goals were:
// - Integers are simpler than fractionals
// - positive numbers are simpler than negative ones
// - exponents of smaller magnitude are simpler, regardless of sign
// - 0 is the simplest number, 1 is the second most simple number
func encodefloat64(f float64) [10]byte {
	var b [10]byte
	bits := math.Float64bits(f)
	// encode the sign bit as a single byte
	b[0] = byte((bits & (1 << 63)) >> 63)

	// for the mantissa, we want simpler fractions
	// This means we get numbers that require fewer
	// digits to print it
	// Encoding as a little endian number
	// makes shrinking go towards a number with
	// fewer significant digits
	mant := bits & (^uint64(0) >> (64 - 52))
	binary.LittleEndian.PutUint64(b[1:], mant)

	// if the exponent is 0, that means this value
	// is a zero. don't unbias the exponent in this case
	// TODO: handle subnormals so that they're more complex
	sexp := int16((bits >> 52) & 0x7ff)
	var exp uint16
	if sexp == 0 {
		if mant != 0 {
			// subnormal number, use the extra range we get from
			// int16 to signal this
			exp = sint16tolex16(-1024)
		}
	} else if sexp == 0x7ff {
		// infinity and NaN, they're more complex that negative
		// exponent and subnormals
		exp = sint16tolex16(-1025)
	} else {
		// regular exponent
		// unbias
		sexp -= 1023
		// if exponent is positive, bias it +1
		// so that an exponent of 1 becomes 0
		// This keeps the invariant that 0 is
		// simpler than 1
		if sexp >= 0 {
			exp = uint16(sexp) + 1
		} else {
			// for negative exponents
			// use signed regular integer
			// This makes -1 simpler than -2
			// when interpreted as a byte stream
			// the sign keeps the invariant that
			// integers are simpler than fractionals
			exp = sint16tolex16(sexp)
		}
	}
	binary.BigEndian.PutUint16(b[8:], exp)
	return b
}

func sint16tolex16(s int16) uint16 {
	s *= -1
	exp := uint16(s)
	exp ^= (1 << 15)
	return exp
}

func decodefloat64(b []byte) (float64, bool) {
	fbits := uint64(0)
	sign := b[0]
	if sign != 0 && sign != 1 {
		return 0, true
	}
	fbits = uint64(sign) << 63
	// mantissa only take 7 bytes in our binary packing
	// but binary only lets us read in chunks of 8
	// copy the mantissa value into an empty array
	// and then decode to make sure that we don't
	var mb [8]byte
	copy(mb[:], b[1:8])
	mant := binary.LittleEndian.Uint64(mb[:])

	exp := binary.BigEndian.Uint16(b[8:])
	if exp&(1<<15) != 0 {
		// this is a signed exponent
		// clear the sign bit
		sexp := int16(exp & (^uint16(0) >> 1))
		if sexp == 1024 {
			exp = 0
		} else if sexp == 1025 {
			exp = 0x7ff
		} else {
			// this is a regular negative exponent
			// make into negative number
			sexp *= -1
			// bias
			sexp += 1023
			exp = uint16(sexp)
		}
	} else if exp != 0 {
		// positive exponent
		exp -= 1
		exp += 1023
	} else if mant != 0 {
		mant = 0
	}
	fbits ^= mant & (^uint64(0) >> (64 - 52))
	fbits ^= uint64(exp) << 52
	return math.Float64frombits(fbits), false
}

// Uint64Gen implements a generator for uint64 values.
type Uint64Gen uint64

func (u *Uint64Gen) Fill(d Data) {
	b := d.Draw(8, Uniform)
	*u = Uint64Gen(binary.BigEndian.Uint64(b))
}

// Uint64 is a convenience function that returns
// a uint64 value from the Runner.
func (r *Runner) Uint64() uint64 {
	var u Uint64Gen
	r.Draw(&u)
	return uint64(u)
}

// Int16Gen implements a generator for int16 values.
type Int16Gen int16

func (i *Int16Gen) Fill(d Data) {
	f := d.Draw(2, Uniform)
	*i = Int16Gen(binary.BigEndian.Uint16(f))
}

// Int16 is a convenience function that returns
// a int16 value from the Runner.
func (r *Runner) Int16() int16 {
	var i Int16Gen
	r.Draw(&i)
	return int16(i)
}

// ByteGen implements a generator for byte values.
type ByteGen byte

func (b *ByteGen) Fill(d Data) {
	*b = ByteGen(d.Draw(1, Uniform)[0])
}

// Byte is a convenience function that returns
// a byte value from the Runner.
func (r *Runner) Byte() byte {
	var b ByteGen
	r.Draw(&b)
	return byte(b)
}

// Int63nGen generates a int64 between 0 and N, following
// the pattern of the math/rand function. After Fill
// the value can be read from Value
type Int63nGen struct {
	Value int64
	N     int64
}

func (i *Int63nGen) Fill(d Data) {
	bits := d.Draw(8, func(r *rand.Rand, n int) []byte {
		var b [8]byte
		val := r.Int63n(i.N)
		binary.BigEndian.PutUint64(b[:], uint64(val))
		return b[:]
	})
	val := int64(binary.BigEndian.Uint64(bits))
	if val >= i.N || val < 0 {
		Invalid()
	}
	i.Value = val
}

func biasBool(d Data, f float64) bool {
	bits := d.Draw(1, func(r *rand.Rand, n int) []byte {
		roll := r.Float64()
		b := byte(0)
		if roll < f {
			b = 1
		}
		return []byte{b}
	})
	return bits[0] != 0
}
<|endoftext|>


<commit_before><commit_msg>Add GetTransitions method<commit_after><|endoftext|>