<commit_before>package mssql

import (
	"bytes"
	"database/sql"
	"database/sql/driver"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"math"
	"strconv"
	"strings"
	"time"
)

func init() {
	sql.Register("mssql", &MssqlDriver{})
}

type MssqlDriver struct {
}

type MssqlConn struct {
	sess *tdsSession
}

func (c *MssqlConn) Commit() error {
	headers := []headerStruct{
		{hdrtype: dataStmHdrTransDescr,
			data: transDescrHdr{c.sess.tranid, 1}.pack()},
	}
	if err := sendCommitXact(c.sess.buf, headers, "", 0, 0, ""); err != nil {
		return err
	}

	tokchan := make(chan tokenStruct, 5)
	go processResponse(c.sess, tokchan)
	for tok := range tokchan {
		switch token := tok.(type) {
		case error:
			return token
		}
	}
	return nil
}

func (c *MssqlConn) Rollback() error {
	headers := []headerStruct{
		{hdrtype: dataStmHdrTransDescr,
			data: transDescrHdr{c.sess.tranid, 1}.pack()},
	}
	if err := sendRollbackXact(c.sess.buf, headers, "", 0, 0, ""); err != nil {
		return err
	}

	tokchan := make(chan tokenStruct, 5)
	go processResponse(c.sess, tokchan)
	for tok := range tokchan {
		switch token := tok.(type) {
		case error:
			return token
		}
	}
	return nil
}

func (c *MssqlConn) Begin() (driver.Tx, error) {
	headers := []headerStruct{
		{hdrtype: dataStmHdrTransDescr,
			data: transDescrHdr{0, 1}.pack()},
	}
	if err := sendBeginXact(c.sess.buf, headers, 0, ""); err != nil {
		return nil, err
	}
	tokchan := make(chan tokenStruct, 5)
	go processResponse(c.sess, tokchan)
	for tok := range tokchan {
		switch token := tok.(type) {
		case error:
			return nil, token
		}
	}
	// successful BEGINXACT request will return sess.tranid
	// for started transaction
	return c, nil
}

func parseConnectionString(dsn string) (res map[string]string) {
	res = map[string]string{}
	parts := strings.Split(dsn, ";")
	for _, part := range parts {
		if len(part) == 0 {
			continue
		}
		lst := strings.SplitN(part, "=", 2)
		name := strings.ToLower(lst[0])
		if len(name) == 0 {
			continue
		}
		var value string = ""
		if len(lst) > 1 {
			value = lst[1]
		}
		res[name] = value
	}
	return res
}

func (d *MssqlDriver) Open(dsn string) (driver.Conn, error) {
	params := parseConnectionString(dsn)
	buf, err := connect(params)
	if err != nil {
		return nil, err
	}
	return &MssqlConn{buf}, nil
}

func (c *MssqlConn) Close() error {
	return c.sess.buf.transport.Close()
}

type MssqlStmt struct {
	c          *MssqlConn
	query      string
	paramCount int
}

func (c *MssqlConn) Prepare(query string) (driver.Stmt, error) {
	q, paramCount := parseParams(query)
	return &MssqlStmt{c, q, paramCount}, nil
}

func (s *MssqlStmt) Close() error {
	return nil
}

func (s *MssqlStmt) NumInput() int {
	return -1
}

func (s *MssqlStmt) sendQuery(args []driver.Value) (err error) {
	headers := []headerStruct{
		{hdrtype: dataStmHdrTransDescr,
			data: transDescrHdr{s.c.sess.tranid, 1}.pack()},
	}
	if len(args) != s.paramCount {
		return errors.New(fmt.Sprintf("sql: expected %d parameters, got %d", s.paramCount, len(args)))
	}
	if len(args) == 0 {
		if err = sendSqlBatch72(s.c.sess.buf, s.query, headers); err != nil {
			return
		}
	} else {
		params := make([]Param, len(args)+2)
		decls := make([]string, len(args))
		params[0], err = s.makeParam(s.query)
		if err != nil {
			return
		}
		for i, val := range args {
			params[i+2], err = s.makeParam(val)
			if err != nil {
				return
			}
			name := fmt.Sprintf("@p%d", i+1)
			params[i+2].Name = name
			decls[i] = fmt.Sprintf("%s %s", name, makeDecl(params[i+2].ti))
		}
		params[1], err = s.makeParam(strings.Join(decls, ","))
		if err != nil {
			return
		}
		if err = sendRpc(s.c.sess.buf, headers, Sp_ExecuteSql, 0, params); err != nil {
			return
		}
	}
	return
}

func (s *MssqlStmt) Query(args []driver.Value) (res driver.Rows, err error) {
	if err = s.sendQuery(args); err != nil {
		return
	}
	tokchan := make(chan tokenStruct, 5)
	go processResponse(s.c.sess, tokchan)
	// process metadata
	var cols []string
loop:
	for tok := range tokchan {
		switch token := tok.(type) {
		case doneStruct:
			break loop
		case []columnStruct:
			cols = make([]string, len(token))
			for i, col := range token {
				cols[i] = col.ColName
			}
			break loop
		case error:
			return nil, token
		}
	}
	return &MssqlRows{sess: s.c.sess, tokchan: tokchan, cols: cols}, nil
}

func (s *MssqlStmt) Exec(args []driver.Value) (res driver.Result, err error) {
	if err = s.sendQuery(args); err != nil {
		return
	}
	tokchan := make(chan tokenStruct, 5)
	go processResponse(s.c.sess, tokchan)
	for token := range tokchan {
		switch token := token.(type) {
		case doneStruct:
			return &MssqlResult{s.c, int64(token.RowCount)}, nil
		case error:
			return nil, token
		}
	}
	return driver.ResultNoRows, nil
}

type MssqlRows struct {
	sess    *tdsSession
	nc      int
	cols    []string
	tokchan chan tokenStruct
}

func (rc *MssqlRows) Close() error {
	rc.tokchan = nil
	return nil
}

func (rc *MssqlRows) Columns() (res []string) {
	return rc.cols
}

func (rc *MssqlRows) Next(dest []driver.Value) (err error) {
	for tok := range rc.tokchan {
		switch tokdata := tok.(type) {
		case []columnStruct:
			return streamErrorf("Unexpected token COLMETADATA")
		case []interface{}:
			for i := range dest {
				dest[i] = tokdata[i]
			}
			return nil
		case error:
			return tokdata
		}
	}
	return io.EOF
}

const (
	normalState = iota
	quotedState
	doubleQuotedState
	bracketState
	endBracketState
	dashState
	doubleDashState
	slashState
	commentState
	slashCommentState
	starState
	paramDigitState
)

func parseParams(query string) (string, int) {
	var buf bytes.Buffer
	var paramCount int
	var paramN int
	var paramMax int
	var nestedComments int
	state := normalState
	for _, r := range query {
	retry:
		switch state {
		case normalState:
			switch r {
			case '$', ':', '?':
				paramN = 0
				state = paramDigitState
			case '\'':
				buf.WriteRune(r)
				state = quotedState
			case '"':
				buf.WriteRune(r)
				state = doubleQuotedState
			case '[':
				buf.WriteRune(r)
				state = bracketState
			case '-':
				buf.WriteRune(r)
				state = dashState
			case '/':
				buf.WriteRune(r)
				state = slashState
			default:
				buf.WriteRune(r)
			}
		case quotedState:
			if r == '\'' {
				state = normalState
			}
			buf.WriteRune(r)
		case doubleQuotedState:
			if r == '"' {
				state = normalState
			}
			buf.WriteRune(r)
		case bracketState:
			if r == ']' {
				state = endBracketState
			}
			buf.WriteRune(r)
		case endBracketState:
			if r == ']' {
				state = bracketState
			} else {
				state = normalState
				goto retry
			}
			buf.WriteRune(r)
		case dashState:
			if r == '-' {
				state = doubleDashState
			} else {
				state = normalState
				goto retry
			}
			buf.WriteRune(r)
		case doubleDashState:
			if r == '\n' {
				state = normalState
			}
			buf.WriteRune(r)
		case slashState:
			if r == '*' {
				state = commentState
			} else {
				state = normalState
				goto retry
			}
			buf.WriteRune(r)
		case commentState:
			if r == '*' {
				state = starState
			} else if r == '/' {
				state = slashCommentState
			}
			buf.WriteRune(r)
		case slashCommentState:
			if r == '*' {
				nestedComments++
			} else if r != '/' {
				state = commentState
			}
			buf.WriteRune(r)
		case starState:
			if r == '/' {
				if nestedComments > 0 {
					nestedComments--
					state = commentState
				} else {
					state = normalState
				}
			} else if r != '*' {
				state = commentState
			}
			buf.WriteRune(r)
		case paramDigitState:
			if r >= '0' && r <= '9' {
				paramN = paramN*10 + int(r-'0')
			} else {
				if paramN == 0 {
					paramCount++
					paramN = paramCount
				} else if paramN > paramMax {
					paramMax = paramN
				}
				buf.WriteString("@p")
				buf.WriteString(strconv.Itoa(paramN))
				state = normalState
				goto retry
			}
		}
	}
	if state == paramDigitState {
		if paramN == 0 {
			paramCount++
			paramN = paramCount
		} else if paramN > paramMax {
			paramMax = paramN
		}
		buf.WriteString("@p")
		buf.WriteString(strconv.Itoa(paramN))
	}
	if paramMax > paramCount {
		paramCount = paramMax
	}
	return buf.String(), paramCount
}

func (s *MssqlStmt) makeParam(val driver.Value) (res Param, err error) {
	if val == nil {
		res.ti.TypeId = typeNVarChar
		res.buffer = nil
		res.ti.Size = 2
		return
	}
	switch val := val.(type) {
	case int64:
		res.ti.TypeId = typeIntN
		res.buffer = make([]byte, 8)
		res.ti.Size = 8
		binary.LittleEndian.PutUint64(res.buffer, uint64(val))
	case float64:
		res.ti.TypeId = typeFltN
		res.ti.Size = 8
		res.buffer = make([]byte, 8)
		binary.LittleEndian.PutUint64(res.buffer, math.Float64bits(val))
	case []byte:
		res.ti.TypeId = typeBigVarBin
		res.ti.Size = len(val)
		res.buffer = val
	case string:
		res.ti.TypeId = typeNVarChar
		res.buffer = str2ucs2(val)
		res.ti.Size = len(res.buffer)
	case bool:
		res.ti.TypeId = typeBitN
		res.ti.Size = 1
		res.buffer = make([]byte, 1)
		if val {
			res.buffer[0] = 1
		}
	case time.Time:
		if s.c.sess.loginAck.TDSVersion >= verTDS73 {
			res.ti.TypeId = typeDateTimeOffsetN
			res.ti.Scale = 7
			res.ti.Size = 10
			buf := make([]byte, 10)
			res.buffer = buf
			days, ns := dateTime2(val)
			ns /= 100
			buf[0] = byte(ns)
			buf[1] = byte(ns >> 8)
			buf[2] = byte(ns >> 16)
			buf[3] = byte(ns >> 24)
			buf[4] = byte(ns >> 32)
			buf[5] = byte(days)
			buf[6] = byte(days >> 8)
			buf[7] = byte(days >> 16)
			_, offset := val.Zone()
			offset /= 60
			buf[8] = byte(offset)
			buf[9] = byte(offset >> 8)
		} else {
			res.ti.TypeId = typeDateTimeN
			res.ti.Size = 8
			res.buffer = make([]byte, 8)
			ref := time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC)
			dur := val.Sub(ref)
			days := dur / (24 * time.Hour)
			tm := (300 * (dur % (24 * time.Hour))) / time.Second
			binary.LittleEndian.PutUint32(res.buffer[0:4], uint32(days))
			binary.LittleEndian.PutUint32(res.buffer[4:8], uint32(tm))
		}
	default:
		err = fmt.Errorf("mssql: unknown type for %T", val)
		return
	}
	return
}

type MssqlResult struct {
	c            *MssqlConn
	rowsAffected int64
}

func (r *MssqlResult) RowsAffected() (int64, error) {
	return r.rowsAffected, nil
}

func (r *MssqlResult) LastInsertId() (int64, error) {
	s, err := r.c.Prepare("select cast(@@identity as bigint)")
	if err != nil {
		return 0, err
	}
	defer s.Close()
	rows, err := s.Query(nil)
	if err != nil {
		return 0, err
	}
	defer rows.Close()
	dest := make([]driver.Value, 1)
	err = rows.Next(dest)
	if err != nil {
		return 0, err
	}
	lastInsertId := dest[0].(int64)
	return lastInsertId, nil
}
<commit_msg>simplify parameter count calculation<commit_after>package mssql

import (
	"bytes"
	"database/sql"
	"database/sql/driver"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"math"
	"strconv"
	"strings"
	"time"
)

func init() {
	sql.Register("mssql", &MssqlDriver{})
}

type MssqlDriver struct {
}

type MssqlConn struct {
	sess *tdsSession
}

func (c *MssqlConn) Commit() error {
	headers := []headerStruct{
		{hdrtype: dataStmHdrTransDescr,
			data: transDescrHdr{c.sess.tranid, 1}.pack()},
	}
	if err := sendCommitXact(c.sess.buf, headers, "", 0, 0, ""); err != nil {
		return err
	}

	tokchan := make(chan tokenStruct, 5)
	go processResponse(c.sess, tokchan)
	for tok := range tokchan {
		switch token := tok.(type) {
		case error:
			return token
		}
	}
	return nil
}

func (c *MssqlConn) Rollback() error {
	headers := []headerStruct{
		{hdrtype: dataStmHdrTransDescr,
			data: transDescrHdr{c.sess.tranid, 1}.pack()},
	}
	if err := sendRollbackXact(c.sess.buf, headers, "", 0, 0, ""); err != nil {
		return err
	}

	tokchan := make(chan tokenStruct, 5)
	go processResponse(c.sess, tokchan)
	for tok := range tokchan {
		switch token := tok.(type) {
		case error:
			return token
		}
	}
	return nil
}

func (c *MssqlConn) Begin() (driver.Tx, error) {
	headers := []headerStruct{
		{hdrtype: dataStmHdrTransDescr,
			data: transDescrHdr{0, 1}.pack()},
	}
	if err := sendBeginXact(c.sess.buf, headers, 0, ""); err != nil {
		return nil, err
	}
	tokchan := make(chan tokenStruct, 5)
	go processResponse(c.sess, tokchan)
	for tok := range tokchan {
		switch token := tok.(type) {
		case error:
			return nil, token
		}
	}
	// successful BEGINXACT request will return sess.tranid
	// for started transaction
	return c, nil
}

func parseConnectionString(dsn string) (res map[string]string) {
	res = map[string]string{}
	parts := strings.Split(dsn, ";")
	for _, part := range parts {
		if len(part) == 0 {
			continue
		}
		lst := strings.SplitN(part, "=", 2)
		name := strings.ToLower(lst[0])
		if len(name) == 0 {
			continue
		}
		var value string = ""
		if len(lst) > 1 {
			value = lst[1]
		}
		res[name] = value
	}
	return res
}

func (d *MssqlDriver) Open(dsn string) (driver.Conn, error) {
	params := parseConnectionString(dsn)
	buf, err := connect(params)
	if err != nil {
		return nil, err
	}
	return &MssqlConn{buf}, nil
}

func (c *MssqlConn) Close() error {
	return c.sess.buf.transport.Close()
}

type MssqlStmt struct {
	c          *MssqlConn
	query      string
	paramCount int
}

func (c *MssqlConn) Prepare(query string) (driver.Stmt, error) {
	q, paramCount := parseParams(query)
	return &MssqlStmt{c, q, paramCount}, nil
}

func (s *MssqlStmt) Close() error {
	return nil
}

func (s *MssqlStmt) NumInput() int {
	return -1
}

func (s *MssqlStmt) sendQuery(args []driver.Value) (err error) {
	headers := []headerStruct{
		{hdrtype: dataStmHdrTransDescr,
			data: transDescrHdr{s.c.sess.tranid, 1}.pack()},
	}
	if len(args) != s.paramCount {
		return errors.New(fmt.Sprintf("sql: expected %d parameters, got %d", s.paramCount, len(args)))
	}
	if len(args) == 0 {
		if err = sendSqlBatch72(s.c.sess.buf, s.query, headers); err != nil {
			return
		}
	} else {
		params := make([]Param, len(args)+2)
		decls := make([]string, len(args))
		params[0], err = s.makeParam(s.query)
		if err != nil {
			return
		}
		for i, val := range args {
			params[i+2], err = s.makeParam(val)
			if err != nil {
				return
			}
			name := fmt.Sprintf("@p%d", i+1)
			params[i+2].Name = name
			decls[i] = fmt.Sprintf("%s %s", name, makeDecl(params[i+2].ti))
		}
		params[1], err = s.makeParam(strings.Join(decls, ","))
		if err != nil {
			return
		}
		if err = sendRpc(s.c.sess.buf, headers, Sp_ExecuteSql, 0, params); err != nil {
			return
		}
	}
	return
}

func (s *MssqlStmt) Query(args []driver.Value) (res driver.Rows, err error) {
	if err = s.sendQuery(args); err != nil {
		return
	}
	tokchan := make(chan tokenStruct, 5)
	go processResponse(s.c.sess, tokchan)
	// process metadata
	var cols []string
loop:
	for tok := range tokchan {
		switch token := tok.(type) {
		case doneStruct:
			break loop
		case []columnStruct:
			cols = make([]string, len(token))
			for i, col := range token {
				cols[i] = col.ColName
			}
			break loop
		case error:
			return nil, token
		}
	}
	return &MssqlRows{sess: s.c.sess, tokchan: tokchan, cols: cols}, nil
}

func (s *MssqlStmt) Exec(args []driver.Value) (res driver.Result, err error) {
	if err = s.sendQuery(args); err != nil {
		return
	}
	tokchan := make(chan tokenStruct, 5)
	go processResponse(s.c.sess, tokchan)
	for token := range tokchan {
		switch token := token.(type) {
		case doneStruct:
			return &MssqlResult{s.c, int64(token.RowCount)}, nil
		case error:
			return nil, token
		}
	}
	return driver.ResultNoRows, nil
}

type MssqlRows struct {
	sess    *tdsSession
	nc      int
	cols    []string
	tokchan chan tokenStruct
}

func (rc *MssqlRows) Close() error {
	rc.tokchan = nil
	return nil
}

func (rc *MssqlRows) Columns() (res []string) {
	return rc.cols
}

func (rc *MssqlRows) Next(dest []driver.Value) (err error) {
	for tok := range rc.tokchan {
		switch tokdata := tok.(type) {
		case []columnStruct:
			return streamErrorf("Unexpected token COLMETADATA")
		case []interface{}:
			for i := range dest {
				dest[i] = tokdata[i]
			}
			return nil
		case error:
			return tokdata
		}
	}
	return io.EOF
}

const (
	normalState = iota
	quotedState
	doubleQuotedState
	bracketState
	endBracketState
	dashState
	doubleDashState
	slashState
	commentState
	slashCommentState
	starState
	paramDigitState
)

func parseParams(query string) (string, int) {
	var buf bytes.Buffer
	var paramCount int
	var paramN int
	var paramMax int
	var nestedComments int
	state := normalState
	for _, r := range query {
	retry:
		switch state {
		case normalState:
			switch r {
			case '$', ':', '?':
				paramN = 0
				state = paramDigitState
			case '\'':
				buf.WriteRune(r)
				state = quotedState
			case '"':
				buf.WriteRune(r)
				state = doubleQuotedState
			case '[':
				buf.WriteRune(r)
				state = bracketState
			case '-':
				buf.WriteRune(r)
				state = dashState
			case '/':
				buf.WriteRune(r)
				state = slashState
			default:
				buf.WriteRune(r)
			}
		case quotedState:
			if r == '\'' {
				state = normalState
			}
			buf.WriteRune(r)
		case doubleQuotedState:
			if r == '"' {
				state = normalState
			}
			buf.WriteRune(r)
		case bracketState:
			if r == ']' {
				state = endBracketState
			}
			buf.WriteRune(r)
		case endBracketState:
			if r == ']' {
				state = bracketState
			} else {
				state = normalState
				goto retry
			}
			buf.WriteRune(r)
		case dashState:
			if r == '-' {
				state = doubleDashState
			} else {
				state = normalState
				goto retry
			}
			buf.WriteRune(r)
		case doubleDashState:
			if r == '\n' {
				state = normalState
			}
			buf.WriteRune(r)
		case slashState:
			if r == '*' {
				state = commentState
			} else {
				state = normalState
				goto retry
			}
			buf.WriteRune(r)
		case commentState:
			if r == '*' {
				state = starState
			} else if r == '/' {
				state = slashCommentState
			}
			buf.WriteRune(r)
		case slashCommentState:
			if r == '*' {
				nestedComments++
			} else if r != '/' {
				state = commentState
			}
			buf.WriteRune(r)
		case starState:
			if r == '/' {
				if nestedComments > 0 {
					nestedComments--
					state = commentState
				} else {
					state = normalState
				}
			} else if r != '*' {
				state = commentState
			}
			buf.WriteRune(r)
		case paramDigitState:
			if r >= '0' && r <= '9' {
				paramN = paramN*10 + int(r-'0')
			} else {
				if paramN == 0 {
					paramCount++
					paramN = paramCount
				}
				if paramN > paramMax {
					paramMax = paramN
				}
				buf.WriteString("@p")
				buf.WriteString(strconv.Itoa(paramN))
				state = normalState
				goto retry
			}
		}
	}
	if state == paramDigitState {
		if paramN == 0 {
			paramCount++
			paramN = paramCount
		}
		if paramN > paramMax {
			paramMax = paramN
		}
		buf.WriteString("@p")
		buf.WriteString(strconv.Itoa(paramN))
	}
	return buf.String(), paramMax
}

func (s *MssqlStmt) makeParam(val driver.Value) (res Param, err error) {
	if val == nil {
		res.ti.TypeId = typeNVarChar
		res.buffer = nil
		res.ti.Size = 2
		return
	}
	switch val := val.(type) {
	case int64:
		res.ti.TypeId = typeIntN
		res.buffer = make([]byte, 8)
		res.ti.Size = 8
		binary.LittleEndian.PutUint64(res.buffer, uint64(val))
	case float64:
		res.ti.TypeId = typeFltN
		res.ti.Size = 8
		res.buffer = make([]byte, 8)
		binary.LittleEndian.PutUint64(res.buffer, math.Float64bits(val))
	case []byte:
		res.ti.TypeId = typeBigVarBin
		res.ti.Size = len(val)
		res.buffer = val
	case string:
		res.ti.TypeId = typeNVarChar
		res.buffer = str2ucs2(val)
		res.ti.Size = len(res.buffer)
	case bool:
		res.ti.TypeId = typeBitN
		res.ti.Size = 1
		res.buffer = make([]byte, 1)
		if val {
			res.buffer[0] = 1
		}
	case time.Time:
		if s.c.sess.loginAck.TDSVersion >= verTDS73 {
			res.ti.TypeId = typeDateTimeOffsetN
			res.ti.Scale = 7
			res.ti.Size = 10
			buf := make([]byte, 10)
			res.buffer = buf
			days, ns := dateTime2(val)
			ns /= 100
			buf[0] = byte(ns)
			buf[1] = byte(ns >> 8)
			buf[2] = byte(ns >> 16)
			buf[3] = byte(ns >> 24)
			buf[4] = byte(ns >> 32)
			buf[5] = byte(days)
			buf[6] = byte(days >> 8)
			buf[7] = byte(days >> 16)
			_, offset := val.Zone()
			offset /= 60
			buf[8] = byte(offset)
			buf[9] = byte(offset >> 8)
		} else {
			res.ti.TypeId = typeDateTimeN
			res.ti.Size = 8
			res.buffer = make([]byte, 8)
			ref := time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC)
			dur := val.Sub(ref)
			days := dur / (24 * time.Hour)
			tm := (300 * (dur % (24 * time.Hour))) / time.Second
			binary.LittleEndian.PutUint32(res.buffer[0:4], uint32(days))
			binary.LittleEndian.PutUint32(res.buffer[4:8], uint32(tm))
		}
	default:
		err = fmt.Errorf("mssql: unknown type for %T", val)
		return
	}
	return
}

type MssqlResult struct {
	c            *MssqlConn
	rowsAffected int64
}

func (r *MssqlResult) RowsAffected() (int64, error) {
	return r.rowsAffected, nil
}

func (r *MssqlResult) LastInsertId() (int64, error) {
	s, err := r.c.Prepare("select cast(@@identity as bigint)")
	if err != nil {
		return 0, err
	}
	defer s.Close()
	rows, err := s.Query(nil)
	if err != nil {
		return 0, err
	}
	defer rows.Close()
	dest := make([]driver.Value, 1)
	err = rows.Next(dest)
	if err != nil {
		return 0, err
	}
	lastInsertId := dest[0].(int64)
	return lastInsertId, nil
}
<|endoftext|>


<commit_before>package lib

import (
	"bytes"
	"strconv"
	"time"
)

// S Provide a string conversions
type S string

// String Convert S to string
func (s S) String() string {
	return string(s)
}

// Bytes Convert string to []byte
func (s S) Bytes() []byte {
	return []byte(s.String())
}

// Buffer Convert string to buffer
func (s S) Buffer() *bytes.Buffer {
	return bytes.NewBufferString(s.String())
}

// Int64 Convert string to int64
func (s S) Int64() (int64, error) {
	return strconv.ParseInt(s.String(), 10, 64)
}

// DefaultInt64 Convert string to int64
func (s S) DefaultInt64(defaultVal int64) int64 {
	v, err := s.Int64()
	if err != nil {
		return defaultVal
	}
	return v
}

// Uint64 Convert string to uint64
func (s S) Uint64() (uint64, error) {
	return strconv.ParseUint(s.String(), 10, 64)
}

// DefaultUint64 Convert string to Uint64
func (s S) DefaultUint64(defaultVal uint64) uint64 {
	v, err := s.Uint64()
	if err != nil {
		return defaultVal
	}
	return v
}

// Float64 Convert string to float64
func (s S) Float64() (float64, error) {
	return strconv.ParseFloat(s.String(), 64)
}

// DefaultFloat64 Convert string to float64
func (s S) DefaultFloat64(defaultVal float64) float64 {
	v, err := s.Float64()
	if err != nil {
		return defaultVal
	}
	return v
}

// Bool Convert string to bool
func (s S) Bool() (bool, error) {
	return strconv.ParseBool(s.String())
}

// DefaultBool Convert string to bool
func (s S) DefaultBool() bool {
	v, err := s.Bool()
	if err != nil {
		return false
	}
	return v
}

// Time Convert string to time
func (s S) Time(layout string) (time.Time, error) {
	return time.Parse(layout, s.String())
}

// DefaultTime Convert string to time,
// If conversion errors,return time.Now()
func (s S) DefaultTime(layout string) time.Time {
	v, err := s.Time(layout)
	if err != nil {
		return time.Now()
	}
	return v
}
<commit_msg>String add functions<commit_after>package lib

import (
	"bytes"
	"strconv"
	"time"
)

// S Provide a string conversions
type S string

// String Convert S to string
func (s S) String() string {
	return string(s)
}

// Bytes Convert string to []byte
func (s S) Bytes() []byte {
	return []byte(s.String())
}

// Buffer Convert string to buffer
func (s S) Buffer() *bytes.Buffer {
	return bytes.NewBufferString(s.String())
}

// Int64 Convert string to int64
func (s S) Int64() (int64, error) {
	return strconv.ParseInt(s.String(), 10, 64)
}

// Int Convert string to int
func (s S) Int() (int, error) {
	i, err := s.Int64()
	if err != nil {
		return 0, err
	}
	return int(i), nil
}

// DefaultInt64 Convert string to int64
func (s S) DefaultInt64(defaultVal int64) int64 {
	v, err := s.Int64()
	if err != nil {
		return defaultVal
	}
	return v
}

// DefaultInt Convert string to int
func (s S) DefaultInt(defaultVal int) int {
	v, err := s.Int()
	if err != nil {
		return defaultVal
	}
	return v
}

// Uint64 Convert string to uint64
func (s S) Uint64() (uint64, error) {
	return strconv.ParseUint(s.String(), 10, 64)
}

// DefaultUint64 Convert string to Uint64
func (s S) DefaultUint64(defaultVal uint64) uint64 {
	v, err := s.Uint64()
	if err != nil {
		return defaultVal
	}
	return v
}

// Float64 Convert string to float64
func (s S) Float64() (float64, error) {
	return strconv.ParseFloat(s.String(), 64)
}

// Float32 Convert string to float32
func (s S) Float32() (float32, error) {
	f, err := s.Float64()
	if err != nil {
		return 0, err
	}
	return float32(f), nil
}

// DefaultFloat64 Convert string to float64
func (s S) DefaultFloat64(defaultVal float64) float64 {
	v, err := s.Float64()
	if err != nil {
		return defaultVal
	}
	return v
}

// DefaultFloat32 Convert string to float32
func (s S) DefaultFloat32(defaultVal float32) float32 {
	v, err := s.Float32()
	if err != nil {
		return defaultVal
	}
	return v
}

// Bool Convert string to bool
func (s S) Bool() (bool, error) {
	return strconv.ParseBool(s.String())
}

// DefaultBool Convert string to bool
func (s S) DefaultBool() bool {
	v, err := s.Bool()
	if err != nil {
		return false
	}
	return v
}

// Time Convert string to time
func (s S) Time(layout string) (time.Time, error) {
	return time.Parse(layout, s.String())
}

// DefaultTime Convert string to time,
// If conversion errors,return time.Now()
func (s S) DefaultTime(layout string) time.Time {
	v, err := s.Time(layout)
	if err != nil {
		return time.Now()
	}
	return v
}
<|endoftext|>


<commit_before>package goutils

import (
    "fmt"
    "regexp"
     "strings"
)

/**
* parse str
    style='width:1' class="hello" checked=on
  as
  map[style:width:1 class:hello checked:on]
*/
func StringToMap(str string) (data map[string]string) {
    re := regexp.MustCompile(`\s*([\w-]+)\s*=\s*(['"]?)(.*)`)
    data = make(map[string]string)
    matches := re.FindAllStringSubmatch(str, -1)
    if len(matches) > 0 {
        first := matches[0]
        var reg2_txt string
        if first[2] == "'" || first[2] == `"` {
            reg2_txt = fmt.Sprintf(`([^%s]*)%s(\s+.*)?`, first[2], first[2])
        } else if first[2] == "" {
            reg2_txt = `(\S+)\s*(.*)`
        }
        re2 := regexp.MustCompile(reg2_txt)
        subResult := re2.FindAllStringSubmatch(first[3], -1)

        if len(subResult) > 0 && len(subResult[0]) > 1 {
            data[first[1]] = subResult[0][1]
            if len(subResult[0][2]) > 0 {
                _subResult := StringToMap(subResult[0][2])
                for k, v := range _subResult {
                    data[k] = v
                }
            }
        }
    }
    return
}

func isChar(ru rune) bool {
    return (ru >= 0 && ru <= 9) || (ru >= 'a' && ru <= 'z') || (ru >= 'A' && ru <= 'Z') || ru == '_' || ru == '-'
}

func LoadText2Slice(text string) (result [][]string){
  lines:=strings.Split(text,"\n")
  r:=regexp.MustCompile(`\s+`)
  for _,v:=range lines{
     index:=strings.IndexByte(v,'#')
     if(index==0){
       continue
     }
     if(index>0){
        v=v[:index]
     }
     v=strings.TrimSpace(v)
     if (v==""){
        continue
     }
     result=append(result,r.Split(v,-1))
  }
 return
}
<commit_msg>strmd5<commit_after>package goutils

import (
    "fmt"
    "regexp"
     "strings"
     "crypto/md5"
)

/**
* parse str
    style='width:1' class="hello" checked=on
  as
  map[style:width:1 class:hello checked:on]
*/
func StringToMap(str string) (data map[string]string) {
    re := regexp.MustCompile(`\s*([\w-]+)\s*=\s*(['"]?)(.*)`)
    data = make(map[string]string)
    matches := re.FindAllStringSubmatch(str, -1)
    if len(matches) > 0 {
        first := matches[0]
        var reg2_txt string
        if first[2] == "'" || first[2] == `"` {
            reg2_txt = fmt.Sprintf(`([^%s]*)%s(\s+.*)?`, first[2], first[2])
        } else if first[2] == "" {
            reg2_txt = `(\S+)\s*(.*)`
        }
        re2 := regexp.MustCompile(reg2_txt)
        subResult := re2.FindAllStringSubmatch(first[3], -1)

        if len(subResult) > 0 && len(subResult[0]) > 1 {
            data[first[1]] = subResult[0][1]
            if len(subResult[0][2]) > 0 {
                _subResult := StringToMap(subResult[0][2])
                for k, v := range _subResult {
                    data[k] = v
                }
            }
        }
    }
    return
}

func isChar(ru rune) bool {
    return (ru >= 0 && ru <= 9) || (ru >= 'a' && ru <= 'z') || (ru >= 'A' && ru <= 'Z') || ru == '_' || ru == '-'
}

func LoadText2Slice(text string) (result [][]string){
  lines:=strings.Split(text,"\n")
  r:=regexp.MustCompile(`\s+`)
  for _,v:=range lines{
     index:=strings.IndexByte(v,'#')
     if(index==0){
       continue
     }
     if(index>0){
        v=v[:index]
     }
     v=strings.TrimSpace(v)
     if (v==""){
        continue
     }
     result=append(result,r.Split(v,-1))
  }
 return
}

func StrMd5(mystr string)string{
  h := md5.New()
  h.Write([]byte(mystr))
  return fmt.Sprintf("%x",h.Sum(nil))
}
<|endoftext|>


<commit_before>package cache

import (
	"fmt"
	"os"

	"github.com/boltdb/bolt"
	"github.com/johnny-morrice/godless/api"
	"github.com/johnny-morrice/godless/crdt"
	"github.com/pkg/errors"

	pb "github.com/gogo/protobuf/proto"
)

type BoltOptions struct {
	DBOptions *bolt.Options
	FilePath  string
	Mode      os.FileMode
	Db        *bolt.DB
}

type BoltFactory struct {
	BoltOptions
}

func (factory BoltFactory) MakeCache() (api.Cache, error) {
	const failMsg = "BoltFactory.MakeCache failed"

	cache := boltCache{db: factory.Db}

	err := cache.initBuckets()

	if err != nil {
		return nil, errors.Wrap(err, failMsg)
	}

	return cache, nil
}

func (factory BoltFactory) MakeMemoryImage() (api.MemoryImage, error) {
	const failMsg = "BoltFactory.MakeMemoryImage failed"

	memImg := boltMemoryImage{db: factory.Db}

	err := memImg.initBuckets()

	if err != nil {
		return nil, errors.Wrap(err, failMsg)
	}

	return memImg, nil
}

func MakeBoltCacheFactory(options BoltOptions) (BoltFactory, error) {
	const failMsg = "MakeBoltCacheFactory"

	db, err := connectBolt(options)

	if err != nil {
		return BoltFactory{}, errors.Wrap(err, failMsg)
	}

	factory := BoltFactory{
		BoltOptions: options,
	}
	factory.Db = db

	return factory, nil
}

type boltCache struct {
	db *bolt.DB
}

func (cache boltCache) initBuckets() error {
	panic("not implemented")
}

func (cache boltCache) Close() error {
	panic("not implemented")
}

func (cache boltCache) GetHead() (crdt.IPFSPath, error) {
	panic("not implemented")
}

func (cache boltCache) SetHead(head crdt.IPFSPath) error {
	panic("not implemented")
}

func (cache boltCache) GetIndex(indexAddr crdt.IPFSPath) (crdt.Index, error) {
	panic("not implemented")
}

func (cache boltCache) SetIndex(indexAddr crdt.IPFSPath, index crdt.Index) error {
	panic("not implemented")
}

func (cache boltCache) GetNamespace(namespaceAddr crdt.IPFSPath) (crdt.Namespace, error) {
	panic("not implemented")
}

func (cache boltCache) SetNamespace(namespaceAddr crdt.IPFSPath, namespace crdt.Namespace) error {
	panic("not implemented")
}

func (cache boltCache) CloseCache() error {
	panic("not implemented")
}

type boltMemoryImage struct {
	db *bolt.DB
}

func (memimg boltMemoryImage) initBuckets() error {
	return initBucket(memimg.db, BOLT_MEMORY_IMAGE_BUCKET_NAME)
}

func (memimg boltMemoryImage) GetIndex() (crdt.Index, error) {
	panic("not implemented")
}

func (memimg boltMemoryImage) JoinIndex(index crdt.Index) error {
	panic("not implemented")
}

func connectBolt(options BoltOptions) (*bolt.DB, error) {
	return bolt.Open(options.FilePath, options.Mode, options.DBOptions)
}

func initBucket(db *bolt.DB, bucketName []byte) error {
	return db.Update(func(transaction *bolt.Tx) error {
		_, err := transaction.CreateBucketIfNotExists(bucketName)
		return err
	})
}

func putMessage(bucket *bolt.Bucket, key []byte, value pb.Message) error {
	keyText := string(key)
	valueBytes, err := pb.Marshal(value)

	if err != nil {
		msg := fmt.Sprintf("Failed to Marshal protobuf message for Bolt key: %v", keyText)
		return errors.Wrap(err, msg)
	}

	err = bucket.Put(key, valueBytes)

	if err != nil {
		msg := fmt.Sprintf("Failed to Put value at Bolt key: %v", keyText)
		return errors.Wrap(err, msg)
	}

	return nil
}

func getMessage(bucket *bolt.Bucket, key []byte, value pb.Message) error {
	keyText := string(key)
	valueBytes := bucket.Get(key)

	if valueBytes == nil {
		return fmt.Errorf("Failed to Get value at Bolt key: %v", keyText)
	}

	err := pb.Unmarshal(valueBytes, value)

	if err != nil {
		msg := fmt.Sprintf("Failed to Unmarshal protobuf message for Bolt key: %v", keyText)
		return errors.Wrap(err, msg)
	}

	return nil
}

var CURRENT_INDEX_KEY = []byte("current_index")
var BOLT_MEMORY_IMAGE_BUCKET_NAME = []byte("memory_image")
var BOLT_CACHE_BUCKET_NAME = []byte("cache")
<commit_msg>Implement boltMemoryImage<commit_after>package cache

import (
	"fmt"
	"os"

	"github.com/boltdb/bolt"
	"github.com/johnny-morrice/godless/api"
	"github.com/johnny-morrice/godless/crdt"
	"github.com/johnny-morrice/godless/proto"
	"github.com/pkg/errors"

	pb "github.com/gogo/protobuf/proto"
)

type BoltOptions struct {
	DBOptions *bolt.Options
	FilePath  string
	Mode      os.FileMode
	Db        *bolt.DB
}

type BoltFactory struct {
	BoltOptions
}

func (factory BoltFactory) MakeCache() (api.Cache, error) {
	const failMsg = "BoltFactory.MakeCache failed"

	cache := boltCache{db: factory.Db}

	err := cache.initBuckets()

	if err != nil {
		return nil, errors.Wrap(err, failMsg)
	}

	return cache, nil
}

func (factory BoltFactory) MakeMemoryImage() (api.MemoryImage, error) {
	const failMsg = "BoltFactory.MakeMemoryImage failed"

	memImg := boltMemoryImage{db: factory.Db}

	err := memImg.initBuckets()

	if err != nil {
		return nil, errors.Wrap(err, failMsg)
	}

	return memImg, nil
}

func MakeBoltCacheFactory(options BoltOptions) (BoltFactory, error) {
	const failMsg = "MakeBoltCacheFactory"

	db, err := connectBolt(options)

	if err != nil {
		return BoltFactory{}, errors.Wrap(err, failMsg)
	}

	factory := BoltFactory{
		BoltOptions: options,
	}
	factory.Db = db

	return factory, nil
}

type boltCache struct {
	db *bolt.DB
}

func (cache boltCache) initBuckets() error {
	panic("not implemented")
}

func (cache boltCache) Close() error {
	panic("not implemented")
}

func (cache boltCache) GetHead() (crdt.IPFSPath, error) {
	panic("not implemented")
}

func (cache boltCache) SetHead(head crdt.IPFSPath) error {
	panic("not implemented")
}

func (cache boltCache) GetIndex(indexAddr crdt.IPFSPath) (crdt.Index, error) {
	panic("not implemented")
}

func (cache boltCache) SetIndex(indexAddr crdt.IPFSPath, index crdt.Index) error {
	panic("not implemented")
}

func (cache boltCache) GetNamespace(namespaceAddr crdt.IPFSPath) (crdt.Namespace, error) {
	panic("not implemented")
}

func (cache boltCache) SetNamespace(namespaceAddr crdt.IPFSPath, namespace crdt.Namespace) error {
	panic("not implemented")
}

func (cache boltCache) CloseCache() error {
	panic("not implemented")
}

type boltMemoryImage struct {
	db *bolt.DB
}

func (memimg boltMemoryImage) initBuckets() error {
	return initBucket(memimg.db, BOLT_MEMORY_IMAGE_BUCKET_NAME)
}

func (memimg boltMemoryImage) GetIndex() (crdt.Index, error) {
	const failMsg = "boltMemoryIndex.GetIndex failed"
	indexMessage := &proto.IndexMessage{}

	err := memimg.view(func(bucket *bolt.Bucket) error {
		return getMessage(bucket, BOLT_MEMORY_IMAGE_INDEX_KEY, indexMessage)
	})

	if err != nil {
		return crdt.EmptyIndex(), errors.Wrap(err, failMsg)
	}

	// TODO handle the invalid entries.
	index, _ := crdt.ReadIndexMessage(indexMessage)

	return index, nil
}

func (memimg boltMemoryImage) JoinIndex(index crdt.Index) error {
	const failMsg = "boltMemoryIndex.JoinIndex failed"

	currentIndex, err := memimg.GetIndex()

	if err != nil {
		return errors.Wrap(err, failMsg)
	}

	joinedIndex := currentIndex.JoinIndex(index)

	// TODO handle the invalid entries.
	joinedMessage, _ := crdt.MakeIndexMessage(joinedIndex)

	err = memimg.update(func(bucket *bolt.Bucket) error {
		return putMessage(bucket, BOLT_MEMORY_IMAGE_INDEX_KEY, joinedMessage)
	})

	if err != nil {
		return errors.Wrap(err, failMsg)
	}

	return nil
}

func (memimg boltMemoryImage) view(viewer func(bucket *bolt.Bucket) error) error {
	return memimg.db.View(func(transaction *bolt.Tx) error {
		bucket := transaction.Bucket(BOLT_MEMORY_IMAGE_BUCKET_NAME)
		return viewer(bucket)
	})
}

func (memimg boltMemoryImage) update(updater func(bucket *bolt.Bucket) error) error {
	return memimg.db.Update(func(transaction *bolt.Tx) error {
		bucket := transaction.Bucket(BOLT_MEMORY_IMAGE_BUCKET_NAME)
		return updater(bucket)
	})
}

func connectBolt(options BoltOptions) (*bolt.DB, error) {
	return bolt.Open(options.FilePath, options.Mode, options.DBOptions)
}

func initBucket(db *bolt.DB, bucketName []byte) error {
	return db.Update(func(transaction *bolt.Tx) error {
		_, err := transaction.CreateBucketIfNotExists(bucketName)
		return err
	})
}

func putMessage(bucket *bolt.Bucket, key []byte, value pb.Message) error {
	keyText := string(key)
	valueBytes, err := pb.Marshal(value)

	if err != nil {
		msg := fmt.Sprintf("Failed to Marshal protobuf message for Bolt key: %v", keyText)
		return errors.Wrap(err, msg)
	}

	err = bucket.Put(key, valueBytes)

	if err != nil {
		msg := fmt.Sprintf("Failed to Put value at Bolt key: %v", keyText)
		return errors.Wrap(err, msg)
	}

	return nil
}

func getMessage(bucket *bolt.Bucket, key []byte, value pb.Message) error {
	keyText := string(key)
	valueBytes := bucket.Get(key)

	if valueBytes == nil {
		return fmt.Errorf("Failed to Get value at Bolt key: %v", keyText)
	}

	err := pb.Unmarshal(valueBytes, value)

	if err != nil {
		msg := fmt.Sprintf("Failed to Unmarshal protobuf message for Bolt key: %v", keyText)
		return errors.Wrap(err, msg)
	}

	return nil
}

var BOLT_MEMORY_IMAGE_INDEX_KEY = []byte("current_index")
var BOLT_MEMORY_IMAGE_BUCKET_NAME = []byte("memory_image")
var BOLT_CACHE_BUCKET_NAME = []byte("cache")
<|endoftext|>


<commit_before>package caixa

import (
	"time"

	"github.com/mundipagg/boleto-api/models"
	"github.com/mundipagg/boleto-api/test"
)

const day = time.Hour * 24

type stubBoletoRequestCaixa struct {
	test.StubBoletoRequest
}

//newStubBoletoRequestCaixa Cria um novo StubBoletoRequest com valores default validáveis para Caixa
func newStubBoletoRequestCaixa() *stubBoletoRequestCaixa {
	expirationDate := time.Now().Add(5 * day)

	base := test.NewStubBoletoRequest(models.Caixa)
	s := &stubBoletoRequestCaixa{
		StubBoletoRequest: *base,
	}

	s.Agreement = models.Agreement{
		AgreementNumber: 123456,
		Agency:          "1234",
	}

	s.Title = models.Title{
		ExpireDateTime: expirationDate,
		ExpireDate:     expirationDate.Format("2006-01-02"),
		OurNumber:      12345678901234,
		AmountInCents:  200,
		DocumentNumber: "1234567890A",
		Instructions:   "Campo de instruções -  max 40 caracteres",
		BoletoType:     "OUT",
		BoletoTypeCode: "99",
	}

	s.Recipient = models.Recipient{
		Document: models.Document{
			Type:   "CNPJ",
			Number: "12123123000112",
		},
	}

	s.Buyer = models.Buyer{
		Name: "Willian Jadson Bezerra Menezes Tupinambá",
		Document: models.Document{
			Type:   "CPF",
			Number: "12312312312",
		},
		Address: models.Address{
			Street:     "Rua da Assunção de Sá",
			Number:     "123",
			Complement: "Seção A, s 02",
			ZipCode:    "20520051",
			City:       "Belém do Pará",
			District:   "Açaí",
			StateCode:  "PA",
		},
	}
	return s
}

func (s *stubBoletoRequestCaixa) WithStrictRules() *stubBoletoRequestCaixa {
	s.Title.Rules = &models.Rules{
		AcceptDivergentAmount: false,
		MaxDaysToPayPastDue:   0,
	}
	return s
}

func (s *stubBoletoRequestCaixa) WithFlexRules() *stubBoletoRequestCaixa {
	s.Title.Rules = &models.Rules{
		AcceptDivergentAmount: true,
		MaxDaysToPayPastDue:   60,
	}
	return s
}
<commit_msg>refactor: altera a funcao de teste  WithStrictRules para a nova regra de D+1 da caixa economica<commit_after>package caixa

import (
	"time"

	"github.com/mundipagg/boleto-api/models"
	"github.com/mundipagg/boleto-api/test"
)

const day = time.Hour * 24

type stubBoletoRequestCaixa struct {
	test.StubBoletoRequest
}

//newStubBoletoRequestCaixa Cria um novo StubBoletoRequest com valores default validáveis para Caixa
func newStubBoletoRequestCaixa() *stubBoletoRequestCaixa {
	expirationDate := time.Now().Add(5 * day)

	base := test.NewStubBoletoRequest(models.Caixa)
	s := &stubBoletoRequestCaixa{
		StubBoletoRequest: *base,
	}

	s.Agreement = models.Agreement{
		AgreementNumber: 123456,
		Agency:          "1234",
	}

	s.Title = models.Title{
		ExpireDateTime: expirationDate,
		ExpireDate:     expirationDate.Format("2006-01-02"),
		OurNumber:      12345678901234,
		AmountInCents:  200,
		DocumentNumber: "1234567890A",
		Instructions:   "Campo de instruções -  max 40 caracteres",
		BoletoType:     "OUT",
		BoletoTypeCode: "99",
	}

	s.Recipient = models.Recipient{
		Document: models.Document{
			Type:   "CNPJ",
			Number: "12123123000112",
		},
	}

	s.Buyer = models.Buyer{
		Name: "Willian Jadson Bezerra Menezes Tupinambá",
		Document: models.Document{
			Type:   "CPF",
			Number: "12312312312",
		},
		Address: models.Address{
			Street:     "Rua da Assunção de Sá",
			Number:     "123",
			Complement: "Seção A, s 02",
			ZipCode:    "20520051",
			City:       "Belém do Pará",
			District:   "Açaí",
			StateCode:  "PA",
		},
	}
	return s
}

func (s *stubBoletoRequestCaixa) WithStrictRules() *stubBoletoRequestCaixa {
	s.Title.Rules = &models.Rules{
		AcceptDivergentAmount: false,
		MaxDaysToPayPastDue:   1,
	}
	return s
}

func (s *stubBoletoRequestCaixa) WithFlexRules() *stubBoletoRequestCaixa {
	s.Title.Rules = &models.Rules{
		AcceptDivergentAmount: true,
		MaxDaysToPayPastDue:   60,
	}
	return s
}
<|endoftext|>


<commit_before>// Copyright 2017 Authors of Cilium
//
// 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 helpers

import (
	"fmt"
)

// ContainerExec executes cmd in the container with the provided name.
func (s *SSHMeta) ContainerExec(name string, cmd string) *CmdRes {
	return s.ExecWithSudo(fmt.Sprintf("docker exec -i %s %s", name, cmd))
}

// ContainerCreate is a wrapper for `docker run`. It runs an instance of the
// specified Docker image with the provided network, name, and options.
func (s *SSHMeta) ContainerCreate(name, image, net, options string) *CmdRes {
	cmd := fmt.Sprintf(
		"docker run -d --name %s --net %s %s %s", name, net, options, image)
	log.Debugf("spinning up container with command '%v'", cmd)
	return s.ExecWithSudo(cmd)
}

// ContainerRm is a wrapper around `docker rm -f`. It forcibly removes the
// Docker container of the provided name.
func (s *SSHMeta) ContainerRm(name string) *CmdRes {
	return s.ExecWithSudo(fmt.Sprintf("docker rm -f %s", name))
}

// ContainerInspect runs `docker inspect` for the container with the provided
// name.
func (s *SSHMeta) ContainerInspect(name string) *CmdRes {
	return s.ExecWithSudo(fmt.Sprintf("docker inspect %s", name))
}

// ContainerInspectNet returns a map of Docker networking information fields and
// their associated values for the container of the provided name. An error
// is returned if the networking information could not be retrieved.
func (s *SSHMeta) ContainerInspectNet(name string) (map[string]string, error) {
	res := s.ContainerInspect(name)
	properties := map[string]string{
		"EndpointID":        "EndpointID",
		"GlobalIPv6Address": IPv6,
		"IPAddress":         IPv4,
		"NetworkID":         "NetworkID",
	}

	if !res.WasSuccessful() {
		return nil, fmt.Errorf("could not inspect container %s", name)
	}
	filter := fmt.Sprintf(`{ [0].NetworkSettings.Networks.%s }`, CiliumDockerNetwork)
	result := map[string]string{
		Name: name,
	}
	data, err := res.FindResults(filter)
	if err != nil {
		return nil, err
	}
	for _, val := range data {
		iface := val.Interface()
		for k, v := range iface.(map[string]interface{}) {
			if key, ok := properties[k]; ok {
				result[key] = fmt.Sprintf("%s", v)
			}
		}
	}
	return result, nil
}

// NetworkCreate creates a Docker network of the provided name with the
// specified subnet. It is a wrapper around `docker network create`.
func (s *SSHMeta) NetworkCreate(name string, subnet string) *CmdRes {
	if subnet == "" {
		subnet = "::1/112"
	}
	cmd := fmt.Sprintf(
		"docker network create --ipv6 --subnet %s --driver cilium --ipam-driver cilium %s",
		subnet, name)
	return s.ExecWithSudo(cmd)
}

// NetworkDelete deletes the Docker network of the provided name. It is a wrapper
// around `docker network rm`.
func (s *SSHMeta) NetworkDelete(name string) *CmdRes {
	return s.ExecWithSudo(fmt.Sprintf("docker network rm  %s", name))
}

// NetworkGet returns all of the Docker network configuration for the provided
// network. It is a wrapper around `docker network inspect`.
func (s *SSHMeta) NetworkGet(name string) *CmdRes {
	return s.ExecWithSudo(fmt.Sprintf("docker network inspect %s", name))
}

func (s *SSHMeta) execCmd(cmd string) *CmdRes {
	return s.ExecWithSudo(cmd)
}

// SampleContainersActions creates or deletes various containers used for
// testing Cilium and adds said containers to the provided Docker network.
func (s *SSHMeta) SampleContainersActions(mode string, networkName string) {
	images := map[string]string{
		Httpd1: HttpdImage,
		Httpd2: HttpdImage,
		Httpd3: HttpdImage,
		App1:   NetperfImage,
		App2:   NetperfImage,
		App3:   NetperfImage,
	}

	switch mode {
	case Create:
		for k, v := range images {
			s.ContainerCreate(k, v, networkName, fmt.Sprintf("-l id.%s", k))
		}
	case Delete:
		for k := range images {
			s.ContainerRm(k)
		}
	}
}
<commit_msg>test/helpers: add log to ContainerRm function<commit_after>// Copyright 2017 Authors of Cilium
//
// 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 helpers

import (
	"fmt"
)

// ContainerExec executes cmd in the container with the provided name.
func (s *SSHMeta) ContainerExec(name string, cmd string) *CmdRes {
	return s.ExecWithSudo(fmt.Sprintf("docker exec -i %s %s", name, cmd))
}

// ContainerCreate is a wrapper for `docker run`. It runs an instance of the
// specified Docker image with the provided network, name, and options.
func (s *SSHMeta) ContainerCreate(name, image, net, options string) *CmdRes {
	cmd := fmt.Sprintf(
		"docker run -d --name %s --net %s %s %s", name, net, options, image)
	log.Debugf("spinning up container with command '%v'", cmd)
	return s.ExecWithSudo(cmd)
}

// ContainerRm is a wrapper around `docker rm -f`. It forcibly removes the
// Docker container of the provided name.
func (s *SSHMeta) ContainerRm(name string) *CmdRes {
	cmd := fmt.Sprintf("docker rm -f %s", name)
	log.Debugf("removing container with command '%v", cmd)
	return s.ExecWithSudo(cmd)
}

// ContainerInspect runs `docker inspect` for the container with the provided
// name.
func (s *SSHMeta) ContainerInspect(name string) *CmdRes {
	return s.ExecWithSudo(fmt.Sprintf("docker inspect %s", name))
}

// ContainerInspectNet returns a map of Docker networking information fields and
// their associated values for the container of the provided name. An error
// is returned if the networking information could not be retrieved.
func (s *SSHMeta) ContainerInspectNet(name string) (map[string]string, error) {
	res := s.ContainerInspect(name)
	properties := map[string]string{
		"EndpointID":        "EndpointID",
		"GlobalIPv6Address": IPv6,
		"IPAddress":         IPv4,
		"NetworkID":         "NetworkID",
	}

	if !res.WasSuccessful() {
		return nil, fmt.Errorf("could not inspect container %s", name)
	}
	filter := fmt.Sprintf(`{ [0].NetworkSettings.Networks.%s }`, CiliumDockerNetwork)
	result := map[string]string{
		Name: name,
	}
	data, err := res.FindResults(filter)
	if err != nil {
		return nil, err
	}
	for _, val := range data {
		iface := val.Interface()
		for k, v := range iface.(map[string]interface{}) {
			if key, ok := properties[k]; ok {
				result[key] = fmt.Sprintf("%s", v)
			}
		}
	}
	return result, nil
}

// NetworkCreate creates a Docker network of the provided name with the
// specified subnet. It is a wrapper around `docker network create`.
func (s *SSHMeta) NetworkCreate(name string, subnet string) *CmdRes {
	if subnet == "" {
		subnet = "::1/112"
	}
	cmd := fmt.Sprintf(
		"docker network create --ipv6 --subnet %s --driver cilium --ipam-driver cilium %s",
		subnet, name)
	return s.ExecWithSudo(cmd)
}

// NetworkDelete deletes the Docker network of the provided name. It is a wrapper
// around `docker network rm`.
func (s *SSHMeta) NetworkDelete(name string) *CmdRes {
	return s.ExecWithSudo(fmt.Sprintf("docker network rm  %s", name))
}

// NetworkGet returns all of the Docker network configuration for the provided
// network. It is a wrapper around `docker network inspect`.
func (s *SSHMeta) NetworkGet(name string) *CmdRes {
	return s.ExecWithSudo(fmt.Sprintf("docker network inspect %s", name))
}

func (s *SSHMeta) execCmd(cmd string) *CmdRes {
	return s.ExecWithSudo(cmd)
}

// SampleContainersActions creates or deletes various containers used for
// testing Cilium and adds said containers to the provided Docker network.
func (s *SSHMeta) SampleContainersActions(mode string, networkName string) {
	images := map[string]string{
		Httpd1: HttpdImage,
		Httpd2: HttpdImage,
		Httpd3: HttpdImage,
		App1:   NetperfImage,
		App2:   NetperfImage,
		App3:   NetperfImage,
	}

	switch mode {
	case Create:
		for k, v := range images {
			s.ContainerCreate(k, v, networkName, fmt.Sprintf("-l id.%s", k))
		}
	case Delete:
		for k := range images {
			s.ContainerRm(k)
		}
	}
}
<|endoftext|>


<commit_before>package connpool

import (
	"net"
	"sync"
	"time"

	"github.com/getlantern/golog"
)

const (
	DefaultClaimTimeout         = 10 * time.Minute
	DefaultRedialDelayIncrement = 50 * time.Millisecond
	DefaultMaxRedialDelay       = 1 * time.Second
)

var (
	log = golog.LoggerFor("connpool")
)

type DialFunc func() (net.Conn, error)

// Pool is a pool of connections. Connections are pooled lazily up to Size and
// expire after ClaimTimeout. Lazily here means that the Pool won't start to
// fill until the first request for a connection. As long as the Pool is
// actively being used, it will attempt to always have Size number of
// connections ready to use.
type Pool struct {
	// Size: while active, the pool will attempt to maintain at these many
	// connections.
	Size int

	// ClaimTimeout: connections will be removed from pool if unclaimed for
	// longer than ClaimTimeout. The default ClaimTimeout is 10 minutes. Once
	// connections have been removed from the Pool, they won't be replaced until
	// another connection is requested, at which point the pool will fill again.
	ClaimTimeout time.Duration

	// RedialDelayIncrement: amount by which to increase the redial delay with
	// each consecutive dial failure.
	RedialDelayIncrement time.Duration

	// MaxRedialDelay: the maximum amount of time to wait before redialing.
	MaxRedialDelay time.Duration

	// Dial: specifies the function used to create new connections
	Dial DialFunc

	runMutex   sync.Mutex
	running    bool
	actualSize int
	freshenCh  chan interface{}
	connCh     chan net.Conn
	stopCh     chan *sync.WaitGroup
}

// Start starts the pool, filling it to the Size and maintaining fresh
// connections.
func (p *Pool) Start() {
	p.runMutex.Lock()
	defer p.runMutex.Unlock()

	if p.running {
		log.Trace("Already running, ignoring additional Start() call")
		return
	}

	log.Tracef("Starting connection pool with size %d", p.Size)
	if p.ClaimTimeout == 0 {
		log.Tracef("Defaulting ClaimTimeout to %s", DefaultClaimTimeout)
		p.ClaimTimeout = DefaultClaimTimeout
	}
	if p.RedialDelayIncrement == 0 {
		log.Tracef("Defaulting p.RedialDelayIncrement to %s", DefaultRedialDelayIncrement)
		p.RedialDelayIncrement = DefaultRedialDelayIncrement
	}
	if p.MaxRedialDelay == 0 {
		log.Tracef("Defaulting p.MaxRedialDelay to %s", DefaultMaxRedialDelay)
		p.MaxRedialDelay = DefaultMaxRedialDelay
	}

	p.freshenCh = make(chan interface{}, p.Size)
	p.connCh = make(chan net.Conn)
	p.stopCh = make(chan *sync.WaitGroup, p.Size)

	log.Tracef("Remembering actual size %d in case Size is later changed", p.Size)
	p.actualSize = p.Size
	for i := 0; i < p.actualSize; i++ {
		go p.feedConn()
	}

	p.running = true
}

// Stop stops the goroutines that are filling the pool, blocking until they've
// all terminated.
func (p *Pool) Stop() {
	p.runMutex.Lock()
	defer p.runMutex.Unlock()

	if !p.running {
		log.Trace("Not running, ignoring Stop() call")
		return
	}

	log.Trace("Stopping all feedConn goroutines")
	var wg sync.WaitGroup
	wg.Add(p.actualSize)
	for i := 0; i < p.actualSize; i++ {
		p.stopCh <- &wg
	}
	wg.Wait()

	p.running = false
}

func (p *Pool) Get() (net.Conn, error) {
	log.Trace("Getting conn")
	defer p.freshen()
	select {
	case conn := <-p.connCh:
		log.Trace("Using pooled conn")
		return conn, nil
	default:
		log.Trace("No pooled conn, dialing our own")
		return p.Dial()
	}
}

func (p *Pool) freshen() {
	for {
		select {
		case p.freshenCh <- nil:
			log.Trace("Freshened one connection")
		default:
			log.Trace("No more to freshen")
			return
		}
	}
}

// feedConn works on continuously feeding the connCh with fresh connections.
func (p *Pool) feedConn() {
	newConnTimedOut := time.NewTimer(0)
	consecutiveDialFailures := time.Duration(0)
	nextDialAt := time.Now()

	for {
		select {
		case wg := <-p.stopCh:
			log.Trace("Stopped before next dial")
			wg.Done()
			return
		case <-p.freshenCh:
			delay := nextDialAt.Sub(time.Now())
			if delay > 0 {
				log.Tracef("Sleeping %s before dialing again", delay)
				time.Sleep(delay)
			}

			log.Trace("Dialing")
			conn, err := p.Dial()
			if err != nil {
				log.Tracef("Error dialing: %s", err)
				delay := consecutiveDialFailures * p.RedialDelayIncrement
				if delay > p.MaxRedialDelay {
					delay = p.MaxRedialDelay
				}
				nextDialAt = time.Now().Add(delay)
				consecutiveDialFailures = consecutiveDialFailures + 1
				continue
			}
			log.Trace("Dial successful")
			consecutiveDialFailures = 0
			newConnTimedOut.Reset(p.ClaimTimeout)

			select {
			case p.connCh <- conn:
				log.Trace("Fed conn")
			case <-newConnTimedOut.C:
				log.Trace("Queued conn timed out, closing")
				err := conn.Close()
				if err != nil {
					log.Tracef("Unable to close timed out queued conn: %s", err)
				}
			case wg := <-p.stopCh:
				log.Trace("Closing queued conn")
				err := conn.Close()
				if err != nil {
					log.Tracef("Unable to close queued conn: %s", err)
				}
				wg.Done()
				return
			}
		}
	}
}
<commit_msg>Tweak to logging freshening<commit_after>package connpool

import (
	"net"
	"sync"
	"time"

	"github.com/getlantern/golog"
)

const (
	DefaultClaimTimeout         = 10 * time.Minute
	DefaultRedialDelayIncrement = 50 * time.Millisecond
	DefaultMaxRedialDelay       = 1 * time.Second
)

var (
	log = golog.LoggerFor("connpool")
)

type DialFunc func() (net.Conn, error)

// Pool is a pool of connections. Connections are pooled lazily up to Size and
// expire after ClaimTimeout. Lazily here means that the Pool won't start to
// fill until the first request for a connection. As long as the Pool is
// actively being used, it will attempt to always have Size number of
// connections ready to use.
type Pool struct {
	// Size: while active, the pool will attempt to maintain at these many
	// connections.
	Size int

	// ClaimTimeout: connections will be removed from pool if unclaimed for
	// longer than ClaimTimeout. The default ClaimTimeout is 10 minutes. Once
	// connections have been removed from the Pool, they won't be replaced until
	// another connection is requested, at which point the pool will fill again.
	ClaimTimeout time.Duration

	// RedialDelayIncrement: amount by which to increase the redial delay with
	// each consecutive dial failure.
	RedialDelayIncrement time.Duration

	// MaxRedialDelay: the maximum amount of time to wait before redialing.
	MaxRedialDelay time.Duration

	// Dial: specifies the function used to create new connections
	Dial DialFunc

	runMutex   sync.Mutex
	running    bool
	actualSize int
	freshenCh  chan interface{}
	connCh     chan net.Conn
	stopCh     chan *sync.WaitGroup
}

// Start starts the pool, filling it to the Size and maintaining fresh
// connections.
func (p *Pool) Start() {
	p.runMutex.Lock()
	defer p.runMutex.Unlock()

	if p.running {
		log.Trace("Already running, ignoring additional Start() call")
		return
	}

	log.Tracef("Starting connection pool with size %d", p.Size)
	if p.ClaimTimeout == 0 {
		log.Tracef("Defaulting ClaimTimeout to %s", DefaultClaimTimeout)
		p.ClaimTimeout = DefaultClaimTimeout
	}
	if p.RedialDelayIncrement == 0 {
		log.Tracef("Defaulting p.RedialDelayIncrement to %s", DefaultRedialDelayIncrement)
		p.RedialDelayIncrement = DefaultRedialDelayIncrement
	}
	if p.MaxRedialDelay == 0 {
		log.Tracef("Defaulting p.MaxRedialDelay to %s", DefaultMaxRedialDelay)
		p.MaxRedialDelay = DefaultMaxRedialDelay
	}

	p.freshenCh = make(chan interface{}, p.Size)
	p.connCh = make(chan net.Conn)
	p.stopCh = make(chan *sync.WaitGroup, p.Size)

	log.Tracef("Remembering actual size %d in case Size is later changed", p.Size)
	p.actualSize = p.Size
	for i := 0; i < p.actualSize; i++ {
		go p.feedConn()
	}

	p.running = true
}

// Stop stops the goroutines that are filling the pool, blocking until they've
// all terminated.
func (p *Pool) Stop() {
	p.runMutex.Lock()
	defer p.runMutex.Unlock()

	if !p.running {
		log.Trace("Not running, ignoring Stop() call")
		return
	}

	log.Trace("Stopping all feedConn goroutines")
	var wg sync.WaitGroup
	wg.Add(p.actualSize)
	for i := 0; i < p.actualSize; i++ {
		p.stopCh <- &wg
	}
	wg.Wait()

	p.running = false
}

func (p *Pool) Get() (net.Conn, error) {
	log.Trace("Getting conn")
	defer p.freshen()
	select {
	case conn := <-p.connCh:
		log.Trace("Using pooled conn")
		return conn, nil
	default:
		log.Trace("No pooled conn, dialing our own")
		return p.Dial()
	}
}

func (p *Pool) freshen() {
	log.Trace("Freshen requested")

	freshened := 0
	for {
		select {
		case p.freshenCh <- nil:
			freshened += 1
		default:
			log.Tracef("No more to freshen, freshened %d connections", freshened)
			return
		}
	}
}

// feedConn works on continuously feeding the connCh with fresh connections.
func (p *Pool) feedConn() {
	newConnTimedOut := time.NewTimer(0)
	consecutiveDialFailures := time.Duration(0)
	nextDialAt := time.Now()

	for {
		select {
		case wg := <-p.stopCh:
			log.Trace("Stopped before next dial")
			wg.Done()
			return
		case <-p.freshenCh:
			delay := nextDialAt.Sub(time.Now())
			if delay > 0 {
				log.Tracef("Sleeping %s before dialing again", delay)
				time.Sleep(delay)
			}

			log.Trace("Dialing")
			conn, err := p.Dial()
			if err != nil {
				log.Tracef("Error dialing: %s", err)
				delay := consecutiveDialFailures * p.RedialDelayIncrement
				if delay > p.MaxRedialDelay {
					delay = p.MaxRedialDelay
				}
				nextDialAt = time.Now().Add(delay)
				consecutiveDialFailures = consecutiveDialFailures + 1
				continue
			}
			log.Trace("Dial successful")
			consecutiveDialFailures = 0
			newConnTimedOut.Reset(p.ClaimTimeout)

			select {
			case p.connCh <- conn:
				log.Trace("Fed conn")
			case <-newConnTimedOut.C:
				log.Trace("Queued conn timed out, closing")
				err := conn.Close()
				if err != nil {
					log.Tracef("Unable to close timed out queued conn: %s", err)
				}
			case wg := <-p.stopCh:
				log.Trace("Closing queued conn")
				err := conn.Close()
				if err != nil {
					log.Tracef("Unable to close queued conn: %s", err)
				}
				wg.Done()
				return
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strconv"
	"strings"
)

var numTable = map[int]string{
	0:  "twelve",
	1:  "one",
	2:  "two",
	3:  "three",
	4:  "four",
	5:  "five",
	6:  "six",
	7:  "seven",
	8:  "eight",
	9:  "nine",
	10: "ten",
	11: "eleven",

	// below code is for minutes

	12: "twelve",
	13: "thirteen",
	14: "fourteen",
	15: "fifteen",
	16: "sixteen",
	17: "seventeen",
	18: "eighteen",
	19: "nineteen",

	20: "twenty",
	30: "thirty",
	40: "fourty",
	50: "fifty",
}

func hoursParse(input string) (string, string) {
	num, _ := strconv.Atoi(input)

	if num >= 12 {
		return numTable[num-12], "pm"
	} else {
		return numTable[num], "am"
	}
}

func minuteParse(input string) string {
	num, _ := strconv.Atoi(input)

	if num == 0 {
		return ""
	} else if num < 10 {
		return fmt.Sprintf("oh %s", numTable[num])
	} else if num <= 20 {
		return fmt.Sprintf("%s", numTable[num])
	} else if num < 60 {
		if num < 30 {
			return fmt.Sprintf("%s %s", numTable[20], numTable[num-20])
		}
		if num == 30 {
			return fmt.Sprintf("%s", numTable[30])
		}
		if num < 40 {
			return fmt.Sprintf("%s %s", numTable[30], numTable[num-30])
		}
		if num == 40 {
			return fmt.Sprintf("%s", numTable[40])
		}
		if num < 50 {
			return fmt.Sprintf("%s %s", numTable[40], numTable[num-40])
		}
		if num == 50 {
			return fmt.Sprintf("%s", numTable[50])
		}
		return fmt.Sprintf("%s %s", numTable[50], numTable[num-50])
	} else {
		panic("minutes wrong")
	}
}

func main() {
	testData := []string{
		"00:00",
		"01:30",
		"12:05",
		"14:01",
		"20:29",
		"21:00",
	}

	for _, data := range testData {
		splitString := strings.Split(data, ":")

		hours, noon := hoursParse(splitString[0])
		minutes := minuteParse(splitString[1])

		if minutes == "" {
			fmt.Printf("It's %s %s\n", hours, noon)
		} else {
			fmt.Printf("It's %s %s %s\n", hours, minutes, noon)
		}
	}

}
<commit_msg>add a bit<commit_after>package main

import (
	"fmt"
	"strconv"
	"strings"
)

var numTable = map[int]string{
	0:  "twelve",
	1:  "one",
	2:  "two",
	3:  "three",
	4:  "four",
	5:  "five",
	6:  "six",
	7:  "seven",
	8:  "eight",
	9:  "nine",
	10: "ten",
	11: "eleven",

	// below code is for minutes

	12: "twelve",
	13: "thirteen",
	14: "fourteen",
	15: "fifteen",
	16: "sixteen",
	17: "seventeen",
	18: "eighteen",
	19: "nineteen",

	20: "twenty",
	30: "thirty",
	40: "fourty",
	50: "fifty",
}

func hoursParse(input string) (string, string) {
	num, _ := strconv.Atoi(input)

	if num > 23 {
		panic("hours wrong")
	}

	if num >= 12 {
		return numTable[num-12], "pm"
	} else {
		return numTable[num], "am"
	}
}

func minuteParse(input string) string {
	num, _ := strconv.Atoi(input)

	if num == 0 {
		return ""
	} else if num < 10 {
		return fmt.Sprintf("oh %s", numTable[num])
	} else if num <= 20 {
		return fmt.Sprintf("%s", numTable[num])
	} else if num < 60 {
		if num < 30 {
			return fmt.Sprintf("%s %s", numTable[20], numTable[num-20])
		}
		if num == 30 {
			return fmt.Sprintf("%s", numTable[30])
		}
		if num < 40 {
			return fmt.Sprintf("%s %s", numTable[30], numTable[num-30])
		}
		if num == 40 {
			return fmt.Sprintf("%s", numTable[40])
		}
		if num < 50 {
			return fmt.Sprintf("%s %s", numTable[40], numTable[num-40])
		}
		if num == 50 {
			return fmt.Sprintf("%s", numTable[50])
		}
		return fmt.Sprintf("%s %s", numTable[50], numTable[num-50])
	} else {
		panic("minutes wrong")
	}
}

func main() {
	testData := []string{
		"00:00",
		"01:30",
		"12:05",
		"14:01",
		"20:29",
		"21:00",
	}

	for _, data := range testData {
		splitString := strings.Split(data, ":")

		hours, noon := hoursParse(splitString[0])
		minutes := minuteParse(splitString[1])

		if minutes == "" {
			fmt.Printf("It's %s %s\n", hours, noon)
		} else {
			fmt.Printf("It's %s %s %s\n", hours, minutes, noon)
		}
	}

}
<|endoftext|>


<commit_before>package irma

import (
	"time"

	"github.com/go-errors/errors"
	"github.com/mhe/gabi"
	"github.com/mhe/gabi/big"
)

// ProofStatus is the status of the complete proof
type ProofStatus string

// Status is the proof status of a single attribute
type AttributeProofStatus string

const (
	ProofStatusValid             = ProofStatus("VALID")              // Proof is valid
	ProofStatusInvalid           = ProofStatus("INVALID")            // Proof is invalid
	ProofStatusInvalidTimestamp  = ProofStatus("INVALID_TIMESTAMP")  // Attribute-based signature had invalid timestamp
	ProofStatusUnmatchedRequest  = ProofStatus("UNMATCHED_REQUEST")  // Proof does not correspond to a specified request
	ProofStatusMissingAttributes = ProofStatus("MISSING_ATTRIBUTES") // Proof does not contain all requested attributes

	// The contained attributes are currently expired, but it is not certain if they already were expired
	// during creation of the attribute-based signature.
	ProofStatusExpired = ProofStatus("EXPIRED")

	AttributeProofStatusPresent      = AttributeProofStatus("PRESENT")       // Attribute is disclosed and matches the value
	AttributeProofStatusExtra        = AttributeProofStatus("EXTRA")         // Attribute is disclosed, but wasn't requested in request
	AttributeProofStatusMissing      = AttributeProofStatus("MISSING")       // Attribute is NOT disclosed, but should be according to request
	AttributeProofStatusInvalidValue = AttributeProofStatus("INVALID_VALUE") // Attribute is disclosed, but has invalid value according to request
)

// DisclosedAttribute represents a disclosed attribute.
type DisclosedAttribute struct {
	Value      TranslatedString        `json:"value"` // Value of the disclosed attribute
	Identifier AttributeTypeIdentifier `json:"id"`
	Status     AttributeProofStatus    `json:"status"`
}

// ProofList is a gabi.ProofList with some extra methods.
type ProofList gabi.ProofList

var ErrorMissingPublicKey = errors.New("Missing public key")

// ExtractPublicKeys returns the public keys of each proof in the proofList, in the same order,
// for later use in verification of the proofList. If one of the proofs is not a ProofD
// an error is returned.
func (pl ProofList) ExtractPublicKeys(configuration *Configuration) ([]*gabi.PublicKey, error) {
	var publicKeys = make([]*gabi.PublicKey, 0, len(pl))

	for _, v := range pl {
		switch v.(type) {
		case *gabi.ProofD:
			proof := v.(*gabi.ProofD)
			metadata := MetadataFromInt(proof.ADisclosed[1], configuration) // index 1 is metadata attribute
			publicKey, err := metadata.PublicKey()
			if err != nil {
				return nil, err
			}
			if publicKey == nil {
				return nil, ErrorMissingPublicKey
			}
			publicKeys = append(publicKeys, publicKey)
		default:
			return nil, errors.New("Cannot extract public key, not a disclosure proofD")
		}
	}
	return publicKeys, nil
}

// VerifyProofs verifies the proofs cryptographically.
func (pl ProofList) VerifyProofs(configuration *Configuration, context *big.Int, nonce *big.Int, publickeys []*gabi.PublicKey, isSig bool) (bool, error) {
	if publickeys == nil {
		var err error
		publickeys, err = pl.ExtractPublicKeys(configuration)
		if err != nil {
			return false, err
		}
	}

	if len(pl) != len(publickeys) {
		return false, errors.New("Insufficient public keys to verify the proofs")
	}

	// If the secret key comes from a credential whose scheme manager has a keyshare server,
	// then the secretkey = userpart + keysharepart.
	// So, we can only expect two secret key responses to be equal if their credentials
	// are both associated to either no keyshare server, or the same keyshare server.
	// (We have to check this here instead of in gabi, because gabi is unaware of schemes
	// and whether or not they are distributed.)
	secretkeyResponses := make(map[SchemeManagerIdentifier]*big.Int)
	nonKssSchemeID := NewSchemeManagerIdentifier(".") // We use this id for all schemes that don't use a kss
	for i, proof := range pl {
		schemeID := NewIssuerIdentifier(publickeys[i].Issuer).SchemeManagerIdentifier()
		if !configuration.SchemeManagers[schemeID].Distributed() {
			schemeID = nonKssSchemeID
		}
		if response, contains := secretkeyResponses[schemeID]; !contains {
			secretkeyResponses[schemeID] = proof.SecretKeyResponse()
		} else {
			if response.Cmp(proof.SecretKeyResponse()) != 0 {
				return false, nil
			}
		}
	}

	return gabi.ProofList(pl).Verify(publickeys, context, nonce, isSig), nil
}

// Expired returns true if any of the contained disclosure proofs is specified at the specified time,
// or now, when the specified time is nil.
func (pl ProofList) Expired(configuration *Configuration, t *time.Time) bool {
	if t == nil {
		temp := time.Now()
		t = &temp
	}
	for _, proof := range pl {
		proofd, ok := proof.(*gabi.ProofD)
		if !ok {
			continue
		}
		metadata := MetadataFromInt(proofd.ADisclosed[1], configuration) // index 1 is metadata attribute
		if metadata.Expiry().Before(*t) {
			return true
		}
	}
	return false
}

// DisclosedAttributes returns a slice containing the disclosed attributes that are present in the proof list.
// If a non-empty and non-nil AttributeDisjunctionList is included, then the first attributes in the returned slice match
// with the disjunction list in the disjunction list. If any of the given disjunctions is not matched by one
// of the disclosed attributes, then the corresponding item in the returned slice has status AttributeProofStatusMissing.
// The first return parameter of this function indicates whether or not all disjunctions (if present) are satisfied.
func (pl ProofList) DisclosedAttributes(configuration *Configuration, disjunctions AttributeDisjunctionList) (bool, []*DisclosedAttribute, error) {
	var list []*DisclosedAttribute
	list = make([]*DisclosedAttribute, len(disjunctions))
	for i := range list {
		// Populate list with AttributeProofStatusMissing; if an attribute that satisfies a disjunction
		// is found below, the corresponding entry in the list is overwritten
		list[i] = &DisclosedAttribute{
			Status: AttributeProofStatusMissing,
		}
	}

	// Temp slice for attributes that have not yet been matched to one of the disjunctions of the request
	// When we are done matching disclosed attributes against the request, filling the first few slots of list,
	// we append these to list just before returning
	extraAttrs := map[AttributeTypeIdentifier]*DisclosedAttribute{}

	for _, proof := range pl {
		proofd, ok := proof.(*gabi.ProofD)
		if !ok {
			continue
		}
		metadata := MetadataFromInt(proofd.ADisclosed[1], configuration) // index 1 is metadata attribute
		credtype := metadata.CredentialType()
		if credtype == nil {
			return false, nil, errors.New("ProofList contained a disclosure proof of an unkown credential type")
		}

		for k, v := range proofd.ADisclosed {
			if k < 2 {
				continue // skip metadata attribute
			}

			attrid := credtype.Attributes[k-2].GetAttributeTypeIdentifier()
			attrval := decodeAttribute(v, metadata.Version())
			attr := &DisclosedAttribute{
				Value:      translateAttribute(attrval),
				Identifier: attrid,
				Status:     AttributeProofStatusExtra,
			}
			extraAttrs[attrid] = attr
			if len(disjunctions) == 0 {
				continue
			}

			// See if the current attribute satisfies one of the disjunctions, if so, delete it from extraAttrs
			for i, disjunction := range disjunctions {
				if disjunction.attemptSatisfy(attrid, attrval) {
					if disjunction.satisfied() {
						attr.Status = AttributeProofStatusPresent
					} else {
						attr.Status = AttributeProofStatusInvalidValue
					}
					list[i] = attr
					delete(extraAttrs, attrid)
				}
			}
		}
	}

	// Any attributes still in here do not satisfy any of the specified disjunctions; append them now
	for _, attr := range extraAttrs {
		list = append(list, attr)
	}

	return len(disjunctions) == 0 || disjunctions.satisfied(), list, nil
}

func (pl ProofList) VerifyAgainstDisjunctions(
	configuration *Configuration,
	required AttributeDisjunctionList,
	context, nonce *big.Int,
	publickeys []*gabi.PublicKey,
	issig bool,
) ([]*DisclosedAttribute, ProofStatus, error) {
	// Cryptographically verify the IRMA disclosure proofs in the signature
	valid, err := pl.VerifyProofs(configuration, context, nonce, publickeys, issig)
	if !valid || err != nil {
		return nil, ProofStatusInvalid, err
	}

	// Next extract the contained attributes from the proofs, and match them to the signature request if present
	allmatched, list, err := pl.DisclosedAttributes(configuration, required)
	if err != nil {
		return nil, ProofStatusInvalid, err
	}

	// Return MISSING_ATTRIBUTES as proofstatus if one of the disjunctions in the request (if present) is not satisfied
	if !allmatched {
		return list, ProofStatusMissingAttributes, nil
	}

	return list, ProofStatusValid, nil
}

func (pl ProofList) Verify(configuration *Configuration, request *DisclosureRequest) ([]*DisclosedAttribute, ProofStatus, error) {
	list, status, err := pl.VerifyAgainstDisjunctions(configuration, request.Content, request.Context, request.Nonce, nil, false)
	if err != nil {
		return list, status, err
	}

	now := time.Now()
	if expired := pl.Expired(configuration, &now); expired {
		return list, ProofStatusExpired, nil
	}

	return list, status, nil
}

// Verify the attribute-based signature, optionally against a corresponding signature request. If the request is present
// (i.e. not nil), then the first attributes in the returned result match with the disjunction list in the request
// (that is, the i'th attribute in the result should satisfy the i'th disjunction in the request). If the request is not
// fully satisfied in this fasion, the Status of the result is ProofStatusMissingAttributes. Any remaining attributes
// (i.e. not asked for by the request) are also included in the result, after the attributes that match disjunctions
// in the request.
//
// The signature request is optional; if it is nil then the attribute-based signature is still verified, and all
// containing attributes returned in the result.
func (sm *SignedMessage) Verify(configuration *Configuration, request *SignatureRequest) ([]*DisclosedAttribute, ProofStatus, error) {
	var message string

	// First check if this signature matches the request
	if request != nil {
		request.Timestamp = sm.Timestamp
		if !sm.MatchesNonceAndContext(request) {
			return nil, ProofStatusUnmatchedRequest, nil
		}
		// If there is a request, then the signed message must be that of the request
		message = request.Message
	} else {
		// If not, we just verify that the signed message is a valid signature over its contained message
		message = sm.Message
	}

	// Verify the timestamp
	if sm.Timestamp != nil {
		if err := sm.VerifyTimestamp(message, configuration); err != nil {
			return nil, ProofStatusInvalidTimestamp, nil
		}
	}

	// Now, cryptographically verify the IRMA disclosure proofs in the signature
	pl := ProofList(sm.Signature)
	var required AttributeDisjunctionList
	if request != nil {
		required = request.Content
	}
	result, status, err := pl.VerifyAgainstDisjunctions(configuration, required, sm.Context, sm.GetNonce(), nil, true)
	if status != ProofStatusValid || err != nil {
		return result, status, err
	}

	// Check if a credential is expired
	var t time.Time
	if sm.Timestamp != nil {
		t = time.Unix(sm.Timestamp.Time, 0)
	}
	if expired := pl.Expired(configuration, &t); expired {
		if sm.Timestamp == nil {
			// At least one of the contained attributes has currently expired. We don't know the
			// creation time of the ABS so we can't ascertain that the attributes were still valid then.
			// Otherwise the signature is valid.
			status = ProofStatusExpired
		} else {
			// The ABS contains attributes that were expired at the time of creation of the ABS.
			// This must not happen and in this case the signature is invalid
			status = ProofStatusInvalid
		}
		return result, status, nil
	}

	// All disjunctions satisfied and nothing expired, proof is valid!
	return result, ProofStatusValid, nil
}
<commit_msg>Move secret key equality check in prooflist verification back to gabi<commit_after>package irma

import (
	"time"

	"github.com/go-errors/errors"
	"github.com/mhe/gabi"
	"github.com/mhe/gabi/big"
)

// ProofStatus is the status of the complete proof
type ProofStatus string

// Status is the proof status of a single attribute
type AttributeProofStatus string

const (
	ProofStatusValid             = ProofStatus("VALID")              // Proof is valid
	ProofStatusInvalid           = ProofStatus("INVALID")            // Proof is invalid
	ProofStatusInvalidTimestamp  = ProofStatus("INVALID_TIMESTAMP")  // Attribute-based signature had invalid timestamp
	ProofStatusUnmatchedRequest  = ProofStatus("UNMATCHED_REQUEST")  // Proof does not correspond to a specified request
	ProofStatusMissingAttributes = ProofStatus("MISSING_ATTRIBUTES") // Proof does not contain all requested attributes

	// The contained attributes are currently expired, but it is not certain if they already were expired
	// during creation of the attribute-based signature.
	ProofStatusExpired = ProofStatus("EXPIRED")

	AttributeProofStatusPresent      = AttributeProofStatus("PRESENT")       // Attribute is disclosed and matches the value
	AttributeProofStatusExtra        = AttributeProofStatus("EXTRA")         // Attribute is disclosed, but wasn't requested in request
	AttributeProofStatusMissing      = AttributeProofStatus("MISSING")       // Attribute is NOT disclosed, but should be according to request
	AttributeProofStatusInvalidValue = AttributeProofStatus("INVALID_VALUE") // Attribute is disclosed, but has invalid value according to request
)

// DisclosedAttribute represents a disclosed attribute.
type DisclosedAttribute struct {
	Value      TranslatedString        `json:"value"` // Value of the disclosed attribute
	Identifier AttributeTypeIdentifier `json:"id"`
	Status     AttributeProofStatus    `json:"status"`
}

// ProofList is a gabi.ProofList with some extra methods.
type ProofList gabi.ProofList

var ErrorMissingPublicKey = errors.New("Missing public key")

// ExtractPublicKeys returns the public keys of each proof in the proofList, in the same order,
// for later use in verification of the proofList. If one of the proofs is not a ProofD
// an error is returned.
func (pl ProofList) ExtractPublicKeys(configuration *Configuration) ([]*gabi.PublicKey, error) {
	var publicKeys = make([]*gabi.PublicKey, 0, len(pl))

	for _, v := range pl {
		switch v.(type) {
		case *gabi.ProofD:
			proof := v.(*gabi.ProofD)
			metadata := MetadataFromInt(proof.ADisclosed[1], configuration) // index 1 is metadata attribute
			publicKey, err := metadata.PublicKey()
			if err != nil {
				return nil, err
			}
			if publicKey == nil {
				return nil, ErrorMissingPublicKey
			}
			publicKeys = append(publicKeys, publicKey)
		default:
			return nil, errors.New("Cannot extract public key, not a disclosure proofD")
		}
	}
	return publicKeys, nil
}

// VerifyProofs verifies the proofs cryptographically.
func (pl ProofList) VerifyProofs(configuration *Configuration, context *big.Int, nonce *big.Int, publickeys []*gabi.PublicKey, isSig bool) (bool, error) {
	if publickeys == nil {
		var err error
		publickeys, err = pl.ExtractPublicKeys(configuration)
		if err != nil {
			return false, err
		}
	}

	if len(pl) != len(publickeys) {
		return false, errors.New("Insufficient public keys to verify the proofs")
	}

	// Compute slice to inform gabi of which proofs should be verified to share the same secret key
	keyshareServers := make([]string, len(pl))
	for i := range pl {
		schemeID := NewIssuerIdentifier(publickeys[i].Issuer).SchemeManagerIdentifier()
		if !configuration.SchemeManagers[schemeID].Distributed() {
			keyshareServers[i] = "." // dummy value: no IRMA scheme will ever have this name
		} else {
			keyshareServers[i] = schemeID.Name()
		}
	}

	return gabi.ProofList(pl).Verify(publickeys, context, nonce, isSig, keyshareServers), nil
}

// Expired returns true if any of the contained disclosure proofs is specified at the specified time,
// or now, when the specified time is nil.
func (pl ProofList) Expired(configuration *Configuration, t *time.Time) bool {
	if t == nil {
		temp := time.Now()
		t = &temp
	}
	for _, proof := range pl {
		proofd, ok := proof.(*gabi.ProofD)
		if !ok {
			continue
		}
		metadata := MetadataFromInt(proofd.ADisclosed[1], configuration) // index 1 is metadata attribute
		if metadata.Expiry().Before(*t) {
			return true
		}
	}
	return false
}

// DisclosedAttributes returns a slice containing the disclosed attributes that are present in the proof list.
// If a non-empty and non-nil AttributeDisjunctionList is included, then the first attributes in the returned slice match
// with the disjunction list in the disjunction list. If any of the given disjunctions is not matched by one
// of the disclosed attributes, then the corresponding item in the returned slice has status AttributeProofStatusMissing.
// The first return parameter of this function indicates whether or not all disjunctions (if present) are satisfied.
func (pl ProofList) DisclosedAttributes(configuration *Configuration, disjunctions AttributeDisjunctionList) (bool, []*DisclosedAttribute, error) {
	var list []*DisclosedAttribute
	list = make([]*DisclosedAttribute, len(disjunctions))
	for i := range list {
		// Populate list with AttributeProofStatusMissing; if an attribute that satisfies a disjunction
		// is found below, the corresponding entry in the list is overwritten
		list[i] = &DisclosedAttribute{
			Status: AttributeProofStatusMissing,
		}
	}

	// Temp slice for attributes that have not yet been matched to one of the disjunctions of the request
	// When we are done matching disclosed attributes against the request, filling the first few slots of list,
	// we append these to list just before returning
	extraAttrs := map[AttributeTypeIdentifier]*DisclosedAttribute{}

	for _, proof := range pl {
		proofd, ok := proof.(*gabi.ProofD)
		if !ok {
			continue
		}
		metadata := MetadataFromInt(proofd.ADisclosed[1], configuration) // index 1 is metadata attribute
		credtype := metadata.CredentialType()
		if credtype == nil {
			return false, nil, errors.New("ProofList contained a disclosure proof of an unkown credential type")
		}

		for k, v := range proofd.ADisclosed {
			if k < 2 {
				continue // skip metadata attribute
			}

			attrid := credtype.Attributes[k-2].GetAttributeTypeIdentifier()
			attrval := decodeAttribute(v, metadata.Version())
			attr := &DisclosedAttribute{
				Value:      translateAttribute(attrval),
				Identifier: attrid,
				Status:     AttributeProofStatusExtra,
			}
			extraAttrs[attrid] = attr
			if len(disjunctions) == 0 {
				continue
			}

			// See if the current attribute satisfies one of the disjunctions, if so, delete it from extraAttrs
			for i, disjunction := range disjunctions {
				if disjunction.attemptSatisfy(attrid, attrval) {
					if disjunction.satisfied() {
						attr.Status = AttributeProofStatusPresent
					} else {
						attr.Status = AttributeProofStatusInvalidValue
					}
					list[i] = attr
					delete(extraAttrs, attrid)
				}
			}
		}
	}

	// Any attributes still in here do not satisfy any of the specified disjunctions; append them now
	for _, attr := range extraAttrs {
		list = append(list, attr)
	}

	return len(disjunctions) == 0 || disjunctions.satisfied(), list, nil
}

func (pl ProofList) VerifyAgainstDisjunctions(
	configuration *Configuration,
	required AttributeDisjunctionList,
	context, nonce *big.Int,
	publickeys []*gabi.PublicKey,
	issig bool,
) ([]*DisclosedAttribute, ProofStatus, error) {
	// Cryptographically verify the IRMA disclosure proofs in the signature
	valid, err := pl.VerifyProofs(configuration, context, nonce, publickeys, issig)
	if !valid || err != nil {
		return nil, ProofStatusInvalid, err
	}

	// Next extract the contained attributes from the proofs, and match them to the signature request if present
	allmatched, list, err := pl.DisclosedAttributes(configuration, required)
	if err != nil {
		return nil, ProofStatusInvalid, err
	}

	// Return MISSING_ATTRIBUTES as proofstatus if one of the disjunctions in the request (if present) is not satisfied
	if !allmatched {
		return list, ProofStatusMissingAttributes, nil
	}

	return list, ProofStatusValid, nil
}

func (pl ProofList) Verify(configuration *Configuration, request *DisclosureRequest) ([]*DisclosedAttribute, ProofStatus, error) {
	list, status, err := pl.VerifyAgainstDisjunctions(configuration, request.Content, request.Context, request.Nonce, nil, false)
	if err != nil {
		return list, status, err
	}

	now := time.Now()
	if expired := pl.Expired(configuration, &now); expired {
		return list, ProofStatusExpired, nil
	}

	return list, status, nil
}

// Verify the attribute-based signature, optionally against a corresponding signature request. If the request is present
// (i.e. not nil), then the first attributes in the returned result match with the disjunction list in the request
// (that is, the i'th attribute in the result should satisfy the i'th disjunction in the request). If the request is not
// fully satisfied in this fasion, the Status of the result is ProofStatusMissingAttributes. Any remaining attributes
// (i.e. not asked for by the request) are also included in the result, after the attributes that match disjunctions
// in the request.
//
// The signature request is optional; if it is nil then the attribute-based signature is still verified, and all
// containing attributes returned in the result.
func (sm *SignedMessage) Verify(configuration *Configuration, request *SignatureRequest) ([]*DisclosedAttribute, ProofStatus, error) {
	var message string

	// First check if this signature matches the request
	if request != nil {
		request.Timestamp = sm.Timestamp
		if !sm.MatchesNonceAndContext(request) {
			return nil, ProofStatusUnmatchedRequest, nil
		}
		// If there is a request, then the signed message must be that of the request
		message = request.Message
	} else {
		// If not, we just verify that the signed message is a valid signature over its contained message
		message = sm.Message
	}

	// Verify the timestamp
	if sm.Timestamp != nil {
		if err := sm.VerifyTimestamp(message, configuration); err != nil {
			return nil, ProofStatusInvalidTimestamp, nil
		}
	}

	// Now, cryptographically verify the IRMA disclosure proofs in the signature
	pl := ProofList(sm.Signature)
	var required AttributeDisjunctionList
	if request != nil {
		required = request.Content
	}
	result, status, err := pl.VerifyAgainstDisjunctions(configuration, required, sm.Context, sm.GetNonce(), nil, true)
	if status != ProofStatusValid || err != nil {
		return result, status, err
	}

	// Check if a credential is expired
	var t time.Time
	if sm.Timestamp != nil {
		t = time.Unix(sm.Timestamp.Time, 0)
	}
	if expired := pl.Expired(configuration, &t); expired {
		if sm.Timestamp == nil {
			// At least one of the contained attributes has currently expired. We don't know the
			// creation time of the ABS so we can't ascertain that the attributes were still valid then.
			// Otherwise the signature is valid.
			status = ProofStatusExpired
		} else {
			// The ABS contains attributes that were expired at the time of creation of the ABS.
			// This must not happen and in this case the signature is invalid
			status = ProofStatusInvalid
		}
		return result, status, nil
	}

	// All disjunctions satisfied and nothing expired, proof is valid!
	return result, ProofStatusValid, nil
}
<|endoftext|>