<commit_before>package email

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"io/ioutil"
	"net/smtp"
	"path/filepath"
	"strings"
	"time"
)

const (
	server       = "localhost:25"
	nlgidsPrefix = "[NLgids] "
)

var from = "nlgids@x64.atoom.net"

func NewContact(from, subject string, body *bytes.Buffer) *Message {
	m := NewMessage(nlgidsPrefix+subject, body.String())
	m.ReplyTo = from
	return m
}

func NewBooking(from, subject string, body *bytes.Buffer) *Message {
	m := NewMessage(nlgidsPrefix+subject, body.String())
	m.ReplyTo = from
	return m
}

func NewInvoice(subject string, body *bytes.Buffer, pdfName string, pdf []byte) *Message {
	m := NewMessage(nlgidsPrefix+subject, body.String())
	m.AttachBytes(pdfName, pdf)
	return m
}

// Do sends an email message using the default to and from.
func (m *Message) Do(rcpts []string) error {
	m.From = from
	m.To = rcpts
	return Send(server, nil, m)
}

// Everything below:

// Copyright 2012 Santiago Corredoira
// Distributed under a BSD-like license.

type Attachment struct {
	Filename string
	Data     []byte
	Inline   bool
}

type Message struct {
	From            string
	To              []string
	Cc              []string
	Bcc             []string
	ReplyTo         string
	Subject         string
	Body            string
	BodyContentType string
	Attachments     map[string]*Attachment
}

func (m *Message) attach(file string, inline bool) error {
	data, err := ioutil.ReadFile(file)
	if err != nil {
		return err
	}
	m.attachBytes(file, data, inline)
	return nil
}

func (m *Message) attachBytes(file string, data []byte, inline bool) {
	_, filename := filepath.Split(file)

	m.Attachments[filename] = &Attachment{
		Filename: filename,
		Data:     data,
		Inline:   inline,
	}
}

func (m *Message) AttachBytes(file string, data []byte) {
	m.attachBytes(file, data, false)
}

func (m *Message) InlineBytes(file string, data []byte) {
	m.attachBytes(file, data, true)
}

func (m *Message) Attach(file string) error {
	return m.attach(file, false)
}

func (m *Message) Inline(file string) error {
	return m.attach(file, true)
}

func newMessage(subject string, body string, bodyContentType string) *Message {
	m := &Message{Subject: subject, Body: body, BodyContentType: bodyContentType}

	m.Attachments = make(map[string]*Attachment)

	return m
}

// NewMessage returns a new Message that can compose an email with attachments
func NewMessage(subject string, body string) *Message {
	return newMessage(subject, body, "text/plain")
}

// NewMessage returns a new Message that can compose an HTML email with attachments
func NewHTMLMessage(subject string, body string) *Message {
	return newMessage(subject, body, "text/html")
}

// ToList returns all the recipients of the email
func (m *Message) Tolist() []string {
	tolist := m.To

	for _, cc := range m.Cc {
		tolist = append(tolist, cc)
	}

	for _, bcc := range m.Bcc {
		tolist = append(tolist, bcc)
	}

	return tolist
}

// Bytes returns the mail data
func (m *Message) Bytes() []byte {
	buf := bytes.NewBuffer(nil)

	buf.WriteString("From: " + m.From + "\r\n")

	t := time.Now()
	buf.WriteString("Date: " + t.Format(time.RFC822) + "\r\n")

	buf.WriteString("To: " + strings.Join(m.To, ",") + "\r\n")
	if len(m.Cc) > 0 {
		buf.WriteString("Cc: " + strings.Join(m.Cc, ",") + "\r\n")
	}

	buf.WriteString("Subject: " + m.Subject + "\r\n")

	if len(m.ReplyTo) > 0 {
		buf.WriteString("Reply-To: " + m.ReplyTo + "\r\n")
	}

	buf.WriteString("MIME-Version: 1.0\r\n")

	boundary := "f46d043c813270fc6b04c2d223da"

	if len(m.Attachments) > 0 {
		buf.WriteString("Content-Type: multipart/mixed; boundary=" + boundary + "\r\n")
		buf.WriteString("--" + boundary + "\r\n")
	}

	buf.WriteString(fmt.Sprintf("Content-Type: %s; charset=utf-8\r\n\r\n", m.BodyContentType))
	buf.WriteString(m.Body)
	buf.WriteString("\r\n")

	if len(m.Attachments) > 0 {
		for _, attachment := range m.Attachments {
			buf.WriteString("\r\n\r\n--" + boundary + "\r\n")

			if attachment.Inline {
				buf.WriteString("Content-Type: message/rfc822\r\n")
				buf.WriteString("Content-Disposition: inline; filename=\"" + attachment.Filename + "\"\r\n\r\n")

				buf.Write(attachment.Data)
			} else {
				buf.WriteString("Content-Type: application/octet-stream\r\n")
				buf.WriteString("Content-Transfer-Encoding: base64\r\n")
				buf.WriteString("Content-Disposition: attachment; filename=\"" + attachment.Filename + "\"\r\n\r\n")

				b := make([]byte, base64.StdEncoding.EncodedLen(len(attachment.Data)))
				base64.StdEncoding.Encode(b, attachment.Data)

				// write base64 content in lines of up to 76 chars
				for i, l := 0, len(b); i < l; i++ {
					buf.WriteByte(b[i])
					if (i+1)%76 == 0 {
						buf.WriteString("\r\n")
					}
				}
			}

			buf.WriteString("\r\n--" + boundary)
		}

		buf.WriteString("--")
	}

	return buf.Bytes()
}

func Send(addr string, auth smtp.Auth, m *Message) error {
	return smtp.SendMail(addr, auth, m.From, m.Tolist(), m.Bytes())
}
<commit_msg>Fix for deb<commit_after>package email

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"io/ioutil"
	"net/smtp"
	"path/filepath"
	"strings"
	"time"
)

const (
	server       = "localhost:25"
	nlgidsPrefix = "[NLgids] "
)

var from = "nlgids@deb.atoom.net"

func NewContact(from, subject string, body *bytes.Buffer) *Message {
	m := NewMessage(nlgidsPrefix+subject, body.String())
	m.ReplyTo = from
	return m
}

func NewBooking(from, subject string, body *bytes.Buffer) *Message {
	m := NewMessage(nlgidsPrefix+subject, body.String())
	m.ReplyTo = from
	return m
}

func NewInvoice(subject string, body *bytes.Buffer, pdfName string, pdf []byte) *Message {
	m := NewMessage(nlgidsPrefix+subject, body.String())
	m.AttachBytes(pdfName, pdf)
	return m
}

// Do sends an email message using the default to and from.
func (m *Message) Do(rcpts []string) error {
	m.From = from
	m.To = rcpts
	return Send(server, nil, m)
}

// Everything below:

// Copyright 2012 Santiago Corredoira
// Distributed under a BSD-like license.

type Attachment struct {
	Filename string
	Data     []byte
	Inline   bool
}

type Message struct {
	From            string
	To              []string
	Cc              []string
	Bcc             []string
	ReplyTo         string
	Subject         string
	Body            string
	BodyContentType string
	Attachments     map[string]*Attachment
}

func (m *Message) attach(file string, inline bool) error {
	data, err := ioutil.ReadFile(file)
	if err != nil {
		return err
	}
	m.attachBytes(file, data, inline)
	return nil
}

func (m *Message) attachBytes(file string, data []byte, inline bool) {
	_, filename := filepath.Split(file)

	m.Attachments[filename] = &Attachment{
		Filename: filename,
		Data:     data,
		Inline:   inline,
	}
}

func (m *Message) AttachBytes(file string, data []byte) {
	m.attachBytes(file, data, false)
}

func (m *Message) InlineBytes(file string, data []byte) {
	m.attachBytes(file, data, true)
}

func (m *Message) Attach(file string) error {
	return m.attach(file, false)
}

func (m *Message) Inline(file string) error {
	return m.attach(file, true)
}

func newMessage(subject string, body string, bodyContentType string) *Message {
	m := &Message{Subject: subject, Body: body, BodyContentType: bodyContentType}

	m.Attachments = make(map[string]*Attachment)

	return m
}

// NewMessage returns a new Message that can compose an email with attachments
func NewMessage(subject string, body string) *Message {
	return newMessage(subject, body, "text/plain")
}

// NewMessage returns a new Message that can compose an HTML email with attachments
func NewHTMLMessage(subject string, body string) *Message {
	return newMessage(subject, body, "text/html")
}

// ToList returns all the recipients of the email
func (m *Message) Tolist() []string {
	tolist := m.To

	for _, cc := range m.Cc {
		tolist = append(tolist, cc)
	}

	for _, bcc := range m.Bcc {
		tolist = append(tolist, bcc)
	}

	return tolist
}

// Bytes returns the mail data
func (m *Message) Bytes() []byte {
	buf := bytes.NewBuffer(nil)

	buf.WriteString("From: " + m.From + "\r\n")

	t := time.Now()
	buf.WriteString("Date: " + t.Format(time.RFC822) + "\r\n")

	buf.WriteString("To: " + strings.Join(m.To, ",") + "\r\n")
	if len(m.Cc) > 0 {
		buf.WriteString("Cc: " + strings.Join(m.Cc, ",") + "\r\n")
	}

	buf.WriteString("Subject: " + m.Subject + "\r\n")

	if len(m.ReplyTo) > 0 {
		buf.WriteString("Reply-To: " + m.ReplyTo + "\r\n")
	}

	buf.WriteString("MIME-Version: 1.0\r\n")

	boundary := "f46d043c813270fc6b04c2d223da"

	if len(m.Attachments) > 0 {
		buf.WriteString("Content-Type: multipart/mixed; boundary=" + boundary + "\r\n")
		buf.WriteString("--" + boundary + "\r\n")
	}

	buf.WriteString(fmt.Sprintf("Content-Type: %s; charset=utf-8\r\n\r\n", m.BodyContentType))
	buf.WriteString(m.Body)
	buf.WriteString("\r\n")

	if len(m.Attachments) > 0 {
		for _, attachment := range m.Attachments {
			buf.WriteString("\r\n\r\n--" + boundary + "\r\n")

			if attachment.Inline {
				buf.WriteString("Content-Type: message/rfc822\r\n")
				buf.WriteString("Content-Disposition: inline; filename=\"" + attachment.Filename + "\"\r\n\r\n")

				buf.Write(attachment.Data)
			} else {
				buf.WriteString("Content-Type: application/octet-stream\r\n")
				buf.WriteString("Content-Transfer-Encoding: base64\r\n")
				buf.WriteString("Content-Disposition: attachment; filename=\"" + attachment.Filename + "\"\r\n\r\n")

				b := make([]byte, base64.StdEncoding.EncodedLen(len(attachment.Data)))
				base64.StdEncoding.Encode(b, attachment.Data)

				// write base64 content in lines of up to 76 chars
				for i, l := 0, len(b); i < l; i++ {
					buf.WriteByte(b[i])
					if (i+1)%76 == 0 {
						buf.WriteString("\r\n")
					}
				}
			}

			buf.WriteString("\r\n--" + boundary)
		}

		buf.WriteString("--")
	}

	return buf.Bytes()
}

func Send(addr string, auth smtp.Auth, m *Message) error {
	return smtp.SendMail(addr, auth, m.From, m.Tolist(), m.Bytes())
}
<|endoftext|>


<commit_before>package emil

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"time"
)

var IN_TEST = false
var errNowNewAnalysis = errors.New("errNowNewAnalysis")

// EndGameDb to query for mate in 1,2, etc.
type EndGameDb struct {
	Start       time.Time            `json:"startTime"`
	Duration    time.Duration        `json:"duration"`
	AnalysisMap map[string]*Analysis `json:"analysis"`
	dtmDb       []map[string]bool    `json:"dtms"`
}

func (db *EndGameDb) Find(p *position) (bestMove *Move) {
	if DEBUG {
		fmt.Printf("Find:\n%s\n", p.board)
	}
	a := db.AnalysisMap[p.board.String()]
	if DEBUG {
		fmt.Printf("Found: AnalysisMap with dtms %v\n", a.DTMs(p.player))
	}
	return a.BestMove(p.player)
}

func (db *EndGameDb) FindMatesIn(dtm int) (as []*Analysis) {
	if dtm == -1 {
		for _, a := range db.AnalysisMap {
			if a.playerHaveDTMs() {
				as = append(as, a)
			}
		}
	} else {
		for str := range db.dtmDb[dtm] {
			as = append(as, db.AnalysisMap[str])
		}
	}
	return as
}

func (db *EndGameDb) FindMates() (as []*Analysis) {
	return db.FindMatesIn(0)
}

func (db *EndGameDb) FindMate(piece, square int) (boards []*Board) {
	for str := range db.dtmDb[0] {
		a := db.AnalysisMap[str]
		if a.Board.Squares[square] == piece {
			boards = append(boards, a.Board)
		}
	}
	return boards
}

func (db *EndGameDb) addPosition(board *Board) {
	a := &Analysis{
		DtmWhite: make([]*DTM, 0),
		DtmBlack: make([]*DTM, 0),
		Board:    board,
		moves:    make(map[string]bool)}
	db.AnalysisMap[a.Board.String()] = a
}

func (db *EndGameDb) addAnalysis(board *Board, dtm int, move *Move) {
	a := db.AnalysisMap[board.String()]
	if move != nil {
		a.addDTM(move.reverse(), dtm)
	}
	if dtm >= 0 {
		if move != nil {
			playerForStep := playerForStepN(dtm)
			if playerForStep != move.player {
				panic("playerForStep != move.player")
			}
		}
		db.dtmDb[dtm][board.String()] = true
	}
}

func (db *EndGameDb) positions() int {
	return len(db.AnalysisMap)
}

// find positions where black is checkmate
func (db *EndGameDb) retrogradeAnalysisStep1() {
	db.dtmDb = append(db.dtmDb, make(map[string]bool))

	start := time.Now()

	player := BLACK
	for boardStr, a := range db.AnalysisMap {
		// mate only on border square
		blackKingSquare := BoardSquares[a.Board.blackKing]
		if !blackKingSquare.isBorder {
			continue
		}
		// mate only with help from king
		if squaresDistances[a.Board.blackKing][a.Board.whiteKing] > 2 {
			continue
		}

		p := NewPosition(a.Board, player)

		move := Search(p)
		if move == nil {
			if isKingInCheck(p) {
				db.addAnalysis(a.Board, 0, nil)
				if DEBUG {
					fmt.Printf("mate:\n%s\n", boardStr)
				}
			}
		}
	}
	end := time.Now()
	if DEBUG {
		fmt.Printf("db.dtmDb[0] %d\n", len(db.dtmDb[0]))
		fmt.Printf("duration %v\n\n\n", end.Sub(start))
	}
}
func playerForStepN(dtm int) (player int) {
	if dtm%2 == 0 {
		return BLACK
	}
	return WHITE
}

func (db *EndGameDb) retrogradeAnalysisStepN(dtm int) (noError error) {
	start := time.Now()
	db.dtmDb = append(db.dtmDb, make(map[string]bool))

	player := playerForStepN(dtm)

	positions := 0
	if player == WHITE {
		if DEBUG {
			fmt.Printf("WHITE Start positions %d\n", len(db.dtmDb[dtm-1]))
		}
		for str := range db.dtmDb[dtm-1] {
			a := db.AnalysisMap[str]
			p := NewPosition(a.Board, player)
			list := generateMoves(p)
			moves := filterKingCaptures(p, list)
			moves = filterKingCaptures(NewPosition(a.Board, otherPlayer(player)), list)

			for _, m := range moves {
				newBoard := a.Board.doMove(m)
				db.addAnalysis(newBoard, dtm, m)
			}
		}
	} else {
		for _, a := range db.AnalysisMap {
			if db.isMateIn0246(a.Board, dtm) >= 0 {
				positions++
			}
		}
		if DEBUG {
			fmt.Printf("BLACK Start positions %d\n", len(db.AnalysisMap)-positions)
		}
		for _, a := range db.AnalysisMap {
			if db.isMateIn0246(a.Board, dtm) >= 0 {
				continue
			}
			p := NewPosition(a.Board, player)
			moves := GenerateMoves(p)

			found := 0
			maxDTM := -1
			for _, m := range moves {
				newBoard := a.Board.doMove(m)
				newDtm := db.isMateIn1357(newBoard, dtm)
				if newDtm > maxDTM {
					maxDTM = newDtm
				}
				if db.isMateIn1357(newBoard, dtm) >= 0 {
					found++
				}
			}

			if found == len(moves) {
				for _, m := range moves {
					db.addAnalysis(a.Board, maxDTM+1, m)
				}
			}
		}
	}
	end := time.Now()

	if DEBUG {
		fmt.Printf("db.dtmDb[%d] %d\n", dtm, len(db.dtmDb[dtm]))
		fmt.Printf("duration %v\n\n\n", end.Sub(start))
	}

	if len(db.dtmDb[dtm]) == 0 {
		return errNowNewAnalysis
	}
	return noError
}
func (db *EndGameDb) isMateIn0246(board *Board, maxDtm int) int {
	for dtm := 0; dtm < maxDtm; dtm += 2 {
		_, ok := db.dtmDb[dtm][board.String()]
		if ok {
			return dtm
		}
	}
	return -1
}
func (db *EndGameDb) isMateIn1357(board *Board, maxDtm int) int {
	for dtm := 1; dtm < maxDtm; dtm += 2 {
		_, ok := db.dtmDb[dtm][board.String()]
		if ok {
			return dtm
		}
	}
	return -1
}

func (db *EndGameDb) MaxDtm() int {
	return len(db.dtmDb)
}

func (db *EndGameDb) retrogradeAnalysis() {
	// find positions where black is checkmate
	db.retrogradeAnalysisStep1()
	dtm := 1
	for {
		err := db.retrogradeAnalysisStepN(dtm)
		if err != nil {
			break
		}
		if IN_TEST {
			return
		}
		dtm++
	}
}
func GenerateMoves(p *position) (list []*Move) {
	for _, m := range generateMoves(p) {
		b := p.board.DoMove(m)
		if !IsTheKingInCheck(NewPosition(b, WHITE)) {
			list = append(list, m)
		}
	}
	return list
}
func generateMoves(p *position) (list []*Move) {
	for src, piece := range p.board.Squares {
		if isOwnPiece(p.player, piece) {
			switch abs(piece) {
			case kingValue:
				for _, dst := range kingDestinationsFrom(src) {
					capture := p.board.Squares[dst]
					if isOtherKing(p.player, capture) {
						continue
					}
					if capture == Empty {
						list = append(list, newSilentMove(p.player, piece, src, dst))
					} else if !isOwnPiece(p.player, capture) {
						list = append(list, newCaptureMove(p.player, piece, capture, src, dst))
					}
				}
			case rockValue:
				for _, dsts := range rockDestinationsFrom(src) {
					for _, dst := range dsts {
						capture := p.board.Squares[dst]
						if isOtherKing(p.player, capture) {
							break
						}
						if capture == Empty {
							list = append(list, newSilentMove(p.player, piece, src, dst))
						} else if !isOwnPiece(p.player, capture) {
							list = append(list, newCaptureMove(p.player, piece, capture, src, dst))
							break
						} else {
							break // onOwnPiece
						}
					}
				}
			}
		}
	}
	return list
}

// SaveEndGameDb saves the an end game DB for KRK to file
func SaveEndGameDb(db *EndGameDb) error {
	filename := "EndGameDb.json"
	fmt.Println("WriteDataToFile: ", filename)

	var data EndGameDb
	data = *db

	b, err := json.MarshalIndent(data, "", "  ")
	if err != nil {
		return err
	}

	return ioutil.WriteFile(filename, b, 0666)
}

// NewEndGameDb generates an end game DB for KRK
func NewEndGameDb() *EndGameDb {
	var err error

	endGames := &EndGameDb{
		Start:       time.Now(),
		AnalysisMap: make(map[string]*Analysis),
		dtmDb:       make([]map[string]bool, 0)}

	for wk := A1; wk <= H8; wk++ {
		//for wk := E3; wk <= E3; wk++ {
		if DEBUG {
			fmt.Printf("White king on %s\n", BoardSquares[wk])
		}
		for wr := A1; wr <= H8; wr++ {
			for bk := A1; bk <= H8; bk++ {

				board := NewBoard()

				err = board.Setup(WhiteKing, wk)
				if err != nil {
					continue
				}

				err = board.Setup(WhiteRock, wr)
				if err != nil {
					continue
				}

				err = board.Setup(BlackKing, bk)
				if err != nil {
					continue
				}

				err = board.kingsToClose()
				if err != nil {
					continue
				}

				endGames.addPosition(board)
			}
		}
	}
	end := time.Now()
	endGames.Duration = end.Sub(endGames.Start)
	if DEBUG {
		fmt.Printf("all positions %d\n", 64*63*62)
		fmt.Printf("endGames.positions() %d\n", endGames.positions())
		fmt.Printf("difference %d\n", 64*63*62-endGames.positions())
		fmt.Printf("duration %v\n", endGames.Duration)
	}
	endGames.retrogradeAnalysis()

	return endGames
}
<commit_msg>fix endgame_db.go<commit_after>package emil

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"time"
)

var IN_TEST = false
var errNowNewAnalysis = errors.New("errNowNewAnalysis")

// EndGameDb to query for mate in 1,2, etc.
type EndGameDb struct {
	Start       time.Time            `json:"startTime"`
	Duration    time.Duration        `json:"duration"`
	AnalysisMap map[string]*Analysis `json:"analysis"`
	dtmDb       []map[string]bool    `json:"dtms"`
}

func (db *EndGameDb) Find(p *position) (bestMove *Move) {
	if DEBUG {
		fmt.Printf("Find:\n%s\n", p.board)
	}
	a := db.AnalysisMap[p.board.String()]
	if DEBUG {
		fmt.Printf("Found: AnalysisMap with dtms %v\n", a.DTMs(p.player))
	}
	return a.BestMove(p.player)
}

func (db *EndGameDb) FindMatesIn(dtm int) (as []*Analysis) {
	if dtm == -1 {
		for _, a := range db.AnalysisMap {
			if a.playerHaveDTMs() {
				as = append(as, a)
			}
		}
	} else {
		for str := range db.dtmDb[dtm] {
			as = append(as, db.AnalysisMap[str])
		}
	}
	return as
}

func (db *EndGameDb) FindMates() (as []*Analysis) {
	return db.FindMatesIn(0)
}

func (db *EndGameDb) FindMate(piece, square int) (boards []*Board) {
	for str := range db.dtmDb[0] {
		a := db.AnalysisMap[str]
		if a.Board.squares[square] == piece {
			boards = append(boards, a.Board)
		}
	}
	return boards
}

func (db *EndGameDb) addPosition(board *Board) {
	a := &Analysis{
		DtmWhite: make([]*DTM, 0),
		DtmBlack: make([]*DTM, 0),
		Board:    board,
		moves:    make(map[string]bool)}
	db.AnalysisMap[a.Board.String()] = a
}

func (db *EndGameDb) addAnalysis(board *Board, dtm int, move *Move) {
	a := db.AnalysisMap[board.String()]
	if move != nil {
		a.addDTM(move.reverse(), dtm)
	}
	if dtm >= 0 {
		if move != nil {
			playerForStep := playerForStepN(dtm)
			if playerForStep != move.player {
				panic("playerForStep != move.player")
			}
		}
		db.dtmDb[dtm][board.String()] = true
	}
}

func (db *EndGameDb) positions() int {
	return len(db.AnalysisMap)
}

// find positions where black is checkmate
func (db *EndGameDb) retrogradeAnalysisStep1() {
	db.dtmDb = append(db.dtmDb, make(map[string]bool))

	start := time.Now()

	player := BLACK
	for boardStr, a := range db.AnalysisMap {
		// mate only on border square
		blackKingSquare := BoardSquares[a.Board.blackKing]
		if !blackKingSquare.isBorder {
			continue
		}
		// mate only with help from king
		if squaresDistances[a.Board.blackKing][a.Board.whiteKing] > 2 {
			continue
		}

		p := NewPosition(a.Board, player)

		move := Search(p)
		if move == nil {
			if isKingInCheck(p) {
				db.addAnalysis(a.Board, 0, nil)
				if DEBUG {
					fmt.Printf("mate:\n%s\n", boardStr)
				}
			}
		}
	}
	end := time.Now()
	if DEBUG {
		fmt.Printf("db.dtmDb[0] %d\n", len(db.dtmDb[0]))
		fmt.Printf("duration %v\n\n\n", end.Sub(start))
	}
}
func playerForStepN(dtm int) (player int) {
	if dtm%2 == 0 {
		return BLACK
	}
	return WHITE
}

func (db *EndGameDb) retrogradeAnalysisStepN(dtm int) (noError error) {
	start := time.Now()
	db.dtmDb = append(db.dtmDb, make(map[string]bool))

	player := playerForStepN(dtm)

	positions := 0
	if player == WHITE {
		if DEBUG {
			fmt.Printf("WHITE Start positions %d\n", len(db.dtmDb[dtm-1]))
		}
		for str := range db.dtmDb[dtm-1] {
			a := db.AnalysisMap[str]
			p := NewPosition(a.Board, player)
			list := generateMoves(p)
			moves := filterKingCaptures(p, list)
			moves = filterKingCaptures(NewPosition(a.Board, otherPlayer(player)), list)

			for _, m := range moves {
				newBoard := a.Board.doMove(m)
				db.addAnalysis(newBoard, dtm, m)
			}
		}
	} else {
		for _, a := range db.AnalysisMap {
			if db.isMateIn0246(a.Board, dtm) >= 0 {
				positions++
			}
		}
		if DEBUG {
			fmt.Printf("BLACK Start positions %d\n", len(db.AnalysisMap)-positions)
		}
		for _, a := range db.AnalysisMap {
			if db.isMateIn0246(a.Board, dtm) >= 0 {
				continue
			}
			p := NewPosition(a.Board, player)
			moves := GenerateMoves(p)

			found := 0
			maxDTM := -1
			for _, m := range moves {
				newBoard := a.Board.doMove(m)
				newDtm := db.isMateIn1357(newBoard, dtm)
				if newDtm > maxDTM {
					maxDTM = newDtm
				}
				if db.isMateIn1357(newBoard, dtm) >= 0 {
					found++
				}
			}

			if found == len(moves) {
				for _, m := range moves {
					db.addAnalysis(a.Board, maxDTM+1, m)
				}
			}
		}
	}
	end := time.Now()

	if DEBUG {
		fmt.Printf("db.dtmDb[%d] %d\n", dtm, len(db.dtmDb[dtm]))
		fmt.Printf("duration %v\n\n\n", end.Sub(start))
	}

	if len(db.dtmDb[dtm]) == 0 {
		return errNowNewAnalysis
	}
	return noError
}
func (db *EndGameDb) isMateIn0246(board *Board, maxDtm int) int {
	for dtm := 0; dtm < maxDtm; dtm += 2 {
		_, ok := db.dtmDb[dtm][board.String()]
		if ok {
			return dtm
		}
	}
	return -1
}
func (db *EndGameDb) isMateIn1357(board *Board, maxDtm int) int {
	for dtm := 1; dtm < maxDtm; dtm += 2 {
		_, ok := db.dtmDb[dtm][board.String()]
		if ok {
			return dtm
		}
	}
	return -1
}

func (db *EndGameDb) MaxDtm() int {
	return len(db.dtmDb)
}

func (db *EndGameDb) retrogradeAnalysis() {
	// find positions where black is checkmate
	db.retrogradeAnalysisStep1()
	dtm := 1
	for {
		err := db.retrogradeAnalysisStepN(dtm)
		if err != nil {
			break
		}
		if IN_TEST {
			return
		}
		dtm++
	}
}
func GenerateMoves(p *position) (list []*Move) {
	for _, m := range generateMoves(p) {
		b := p.board.DoMove(m)
		if !IsTheKingInCheck(NewPosition(b, WHITE)) {
			list = append(list, m)
		}
	}
	return list
}
func generateMoves(p *position) (list []*Move) {
	for src, piece := range p.board.squares {
		if isOwnPiece(p.player, piece) {
			switch abs(piece) {
			case kingValue:
				for _, dst := range kingDestinationsFrom(src) {
					capture := p.board.squares[dst]
					if isOtherKing(p.player, capture) {
						continue
					}
					if capture == Empty {
						list = append(list, newSilentMove(p.player, piece, src, dst))
					} else if !isOwnPiece(p.player, capture) {
						list = append(list, newCaptureMove(p.player, piece, capture, src, dst))
					}
				}
			case rockValue:
				for _, dsts := range rockDestinationsFrom(src) {
					for _, dst := range dsts {
						capture := p.board.squares[dst]
						if isOtherKing(p.player, capture) {
							break
						}
						if capture == Empty {
							list = append(list, newSilentMove(p.player, piece, src, dst))
						} else if !isOwnPiece(p.player, capture) {
							list = append(list, newCaptureMove(p.player, piece, capture, src, dst))
							break
						} else {
							break // onOwnPiece
						}
					}
				}
			}
		}
	}
	return list
}

// SaveEndGameDb saves the an end game DB for KRK to file
func SaveEndGameDb(db *EndGameDb) error {
	filename := "EndGameDb.json"
	fmt.Println("WriteDataToFile: ", filename)

	var data EndGameDb
	data = *db

	b, err := json.MarshalIndent(data, "", "  ")
	if err != nil {
		return err
	}

	return ioutil.WriteFile(filename, b, 0666)
}

// NewEndGameDb generates an end game DB for KRK
func NewEndGameDb() *EndGameDb {
	var err error

	endGames := &EndGameDb{
		Start:       time.Now(),
		AnalysisMap: make(map[string]*Analysis),
		dtmDb:       make([]map[string]bool, 0)}

	for wk := A1; wk <= H8; wk++ {
		//for wk := E3; wk <= E3; wk++ {
		if DEBUG {
			fmt.Printf("White king on %s\n", BoardSquares[wk])
		}
		for wr := A1; wr <= H8; wr++ {
			for bk := A1; bk <= H8; bk++ {

				board := NewBoard()

				err = board.Setup(WhiteKing, wk)
				if err != nil {
					continue
				}

				err = board.Setup(WhiteRock, wr)
				if err != nil {
					continue
				}

				err = board.Setup(BlackKing, bk)
				if err != nil {
					continue
				}

				err = board.kingsToClose()
				if err != nil {
					continue
				}

				endGames.addPosition(board)
			}
		}
	}
	end := time.Now()
	endGames.Duration = end.Sub(endGames.Start)
	if DEBUG {
		fmt.Printf("all positions %d\n", 64*63*62)
		fmt.Printf("endGames.positions() %d\n", endGames.positions())
		fmt.Printf("difference %d\n", 64*63*62-endGames.positions())
		fmt.Printf("duration %v\n", endGames.Duration)
	}
	endGames.retrogradeAnalysis()

	return endGames
}
<|endoftext|>


<commit_before>package nsqlookup

import (
	"context"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"reflect"
	"sort"
	"strings"
	"testing"
	"time"
)

func TestResolveServers(t *testing.T) {
	tests := []struct {
		servers Servers
		results []string
	}{
		{
			servers: nil,
			results: nil,
		},
		{
			servers: Servers{},
			results: nil,
		},
		{
			servers: Servers{"A"},
			results: []string{"A"},
		},
		{
			servers: Servers{"A", "B"},
			results: []string{"A", "B"},
		},
		{
			servers: Servers{"A", "B", "C"},
			results: []string{"A", "B", "C"},
		},
	}

	for _, test := range tests {
		t.Run(strings.Join(test.results, ","), func(t *testing.T) {
			ctx, cancel := context.WithCancel(context.Background())
			res, err := test.servers.Resolve(ctx)

			if err != nil {
				t.Error(err)
			}

			if !reflect.DeepEqual(res, test.results) {
				t.Error(res)
			}

			cancel()
			_, err = test.servers.Resolve(ctx)
			if err != context.Canceled {
				t.Error("bad error after the context was canceled:", err)
			}
		})
	}
}

func TestResolveCached(t *testing.T) {
	servers := Servers{
		"A",
		"B",
		"C",
	}

	miss := 0
	rslv := &CachedResolver{
		Resolver: ResolverFunc(func(ctx context.Context) ([]string, error) {
			miss++
			return servers.Resolve(ctx)
		}),
		Timeout: 10 * time.Millisecond,
	}

	ctx, cancel := context.WithCancel(context.Background())

	for i := 0; i != 3; i++ {
		for j := 0; j != 10; j++ {
			res, err := rslv.Resolve(ctx)

			if err != nil {
				t.Error(err)
			}

			if !reflect.DeepEqual(res, ([]string)(servers)) {
				t.Error(res)
			}
		}

		if miss != (i + 1) {
			t.Error("too many cache misses:", miss)
		}

		// Sleep for a little while so the cache entry expires.
		time.Sleep(20 * time.Millisecond)
	}

	cancel()
	_, err := rslv.Resolve(ctx)
	if err.String() != "net/http: request canceled" {
		t.Error("bad error after the context was canceled:", err)
	}
}

func TestResolveConsul(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
		if req.URL.Path != "/v1/catalog/service/nsqlookupd" {
			t.Error("bad URL path:", req.URL.Path)
		}
		res.Header().Set("Content-Type", "application/json; charset=utf-8")
		json.NewEncoder(res).Encode([]struct {
			ServiceAddress string
			ServicePort    int
		}{
			{
				ServiceAddress: "127.0.0.1",
				ServicePort:    4242,
			},
			{
				ServiceAddress: "192.168.0.1",
				ServicePort:    4161,
			},
			{
				ServiceAddress: "192.168.0.2",
				ServicePort:    4161,
			},
		})
	}))
	defer server.Close()

	rslv := &ConsulResolver{
		Address: server.URL,
	}

	ctx, cancel := context.WithCancel(context.Background())

	res, err := rslv.Resolve(ctx)
	if err != nil {
		t.Error(err)
	}
	if !reflect.DeepEqual(res, []string{
		"127.0.0.1:4242",
		"192.168.0.1:4161",
		"192.168.0.2:4161",
	}) {
		t.Error(res)
	}

	cancel()
	_, err = rslv.Resolve(ctx)
	if err != context.Canceled {
		t.Error("bad error after the context was canceled:", err)
	}
}

func TestResolveMulti(t *testing.T) {
	rslv := MultiResolver(
		Servers{},
		Servers{"A"},
		Servers{"B", "C"},
	)

	res, err := rslv.Resolve(nil)
	sort.Strings(res)

	if err != nil {
		t.Error(err)
	}

	if !reflect.DeepEqual(res, []string{"A", "B", "C"}) {
		t.Error(res)
	}
}
<commit_msg>fix error checks<commit_after>package nsqlookup

import (
	"context"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"reflect"
	"sort"
	"strings"
	"testing"
	"time"
)

func TestResolveServers(t *testing.T) {
	tests := []struct {
		servers Servers
		results []string
	}{
		{
			servers: nil,
			results: nil,
		},
		{
			servers: Servers{},
			results: nil,
		},
		{
			servers: Servers{"A"},
			results: []string{"A"},
		},
		{
			servers: Servers{"A", "B"},
			results: []string{"A", "B"},
		},
		{
			servers: Servers{"A", "B", "C"},
			results: []string{"A", "B", "C"},
		},
	}

	for _, test := range tests {
		t.Run(strings.Join(test.results, ","), func(t *testing.T) {
			ctx, cancel := context.WithCancel(context.Background())
			res, err := test.servers.Resolve(ctx)

			if err != nil {
				t.Error(err)
			}

			if !reflect.DeepEqual(res, test.results) {
				t.Error(res)
			}

			cancel()
			_, err = test.servers.Resolve(ctx)
			if err == nil {
				t.Error("bad error after the context was canceled:", err)
			}
		})
	}
}

func TestResolveCached(t *testing.T) {
	servers := Servers{
		"A",
		"B",
		"C",
	}

	miss := 0
	rslv := &CachedResolver{
		Resolver: ResolverFunc(func(ctx context.Context) ([]string, error) {
			miss++
			return servers.Resolve(ctx)
		}),
		Timeout: 10 * time.Millisecond,
	}

	ctx, cancel := context.WithCancel(context.Background())

	for i := 0; i != 3; i++ {
		for j := 0; j != 10; j++ {
			res, err := rslv.Resolve(ctx)

			if err != nil {
				t.Error(err)
			}

			if !reflect.DeepEqual(res, ([]string)(servers)) {
				t.Error(res)
			}
		}

		if miss != (i + 1) {
			t.Error("too many cache misses:", miss)
		}

		// Sleep for a little while so the cache entry expires.
		time.Sleep(20 * time.Millisecond)
	}

	cancel()
	_, err := rslv.Resolve(ctx)
	if err == nil {
		t.Error("bad error after the context was canceled:", err)
	}
}

func TestResolveConsul(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
		if req.URL.Path != "/v1/catalog/service/nsqlookupd" {
			t.Error("bad URL path:", req.URL.Path)
		}
		res.Header().Set("Content-Type", "application/json; charset=utf-8")
		json.NewEncoder(res).Encode([]struct {
			ServiceAddress string
			ServicePort    int
		}{
			{
				ServiceAddress: "127.0.0.1",
				ServicePort:    4242,
			},
			{
				ServiceAddress: "192.168.0.1",
				ServicePort:    4161,
			},
			{
				ServiceAddress: "192.168.0.2",
				ServicePort:    4161,
			},
		})
	}))
	defer server.Close()

	rslv := &ConsulResolver{
		Address: server.URL,
	}

	ctx, cancel := context.WithCancel(context.Background())

	res, err := rslv.Resolve(ctx)
	if err != nil {
		t.Error(err)
	}
	if !reflect.DeepEqual(res, []string{
		"127.0.0.1:4242",
		"192.168.0.1:4161",
		"192.168.0.2:4161",
	}) {
		t.Error(res)
	}

	cancel()
	_, err = rslv.Resolve(ctx)
	if err == nil {
		t.Error("bad error after the context was canceled:", err)
	}
}

func TestResolveMulti(t *testing.T) {
	rslv := MultiResolver(
		Servers{},
		Servers{"A"},
		Servers{"B", "C"},
	)

	res, err := rslv.Resolve(nil)
	sort.Strings(res)

	if err != nil {
		t.Error(err)
	}

	if !reflect.DeepEqual(res, []string{"A", "B", "C"}) {
		t.Error(res)
	}
}
<|endoftext|>


<commit_before>package config

import (
	"fmt"
	"io"
	"os"
	"sort"
)

// AppInfo describes a Go program that uses go-config. It is used primarily in Usage(), or when a user uses -help.
type AppInfo struct {
	Name        string
	Description string
	Version     string
	Examples    []Example
}

// Example describes an example of a proper way to invoke the current Go program.
type Example struct {
	Cmd         string
	Description string
}

// App is the AppInfo for the current Go program.
var App = AppInfo{
	Name:     os.Args[0],
	Examples: []Example{},
}

// UsageWriter is the io.Writer to use for outputting Usage(). Defaults to stdout.
var UsageWriter io.Writer = os.Stdout

type sortedUsageOptionSlice []Option

func (s sortedUsageOptionSlice) Less(a, b int) bool {
	if s[a].Options.SortOrder < s[b].Options.SortOrder {
		return true
	} else if s[a].Options.SortOrder > s[b].Options.SortOrder {
		return false
	}

	return s[a].Name < s[b].Name
}

func (s sortedUsageOptionSlice) Swap(a, b int) { s[a], s[b] = s[b], s[a] }
func (s sortedUsageOptionSlice) Len() int      { return len(s) }

// Usage prints the help information to UsageWriter (defaults to stdout).
func Usage() {

	uprintf := func(strFmt string, args ...interface{}) {
		fmt.Fprintf(UsageWriter, strFmt, args...)
	}

	uprintln := func(strFmt string, args ...interface{}) {
		uprintf(strFmt+"\n", args...)
	}

	mlen := 0
	opts := []Option{}
	for _, opt := range baseOptionSet {
		opts = append(opts, *opt)
		s := fmt.Sprintf("%s", opt.Name)
		if len(s) > mlen {
			mlen = len(s)
		}
	}

	sort.Sort(sortedUsageOptionSlice(opts))

	uprintln(`Usage of %s:`, App.Name)
	if App.Description != "" {
		uprintln(`  %s`, App.Description)
	}

	uprintln("")

	if len(App.Examples) > 0 {
		uprintln("  Examples:")
		for _, v := range App.Examples {
			uprintln("     %s\n     %s\n", v.Cmd, v.Description)
		}
	}

	if len(opts) > 0 {
		uprintln("  Flags:")

		lastSort := opts[0].Options.SortOrder

		fmtStr := fmt.Sprintf("    -%%-%ds (default: %%s)\n     %%s\n", mlen)
		for _, opt := range opts {
			if opt.Options.SortOrder != lastSort {
				uprintln("")
			}

			uprintln(fmtStr,
				opt.Name,
				opt.defaultValueString("<empty>"),
				opt.Description,
			)

			lastSort = opt.Options.SortOrder
		}
	}
}
<commit_msg>Improving Usage() formatting<commit_after>package config

import (
	"fmt"
	"io"
	"os"
	"sort"
)

// AppInfo describes a Go program that uses go-config. It is used primarily in Usage(), or when a user uses -help.
type AppInfo struct {
	Name        string
	Description string
	Version     string
	Examples    []Example
}

// Example describes an example of a proper way to invoke the current Go program.
type Example struct {
	Cmd         string
	Description string
}

// App is the AppInfo for the current Go program.
var App = AppInfo{
	Name:     os.Args[0],
	Examples: []Example{},
}

// UsageWriter is the io.Writer to use for outputting Usage(). Defaults to stdout.
var UsageWriter io.Writer = os.Stdout

type sortedUsageOptionSlice []Option

func (s sortedUsageOptionSlice) Less(a, b int) bool {
	if s[a].Options.SortOrder < s[b].Options.SortOrder {
		return true
	} else if s[a].Options.SortOrder > s[b].Options.SortOrder {
		return false
	}

	return s[a].Name < s[b].Name
}

func (s sortedUsageOptionSlice) Swap(a, b int) { s[a], s[b] = s[b], s[a] }
func (s sortedUsageOptionSlice) Len() int      { return len(s) }

// Usage prints the help information to UsageWriter (defaults to stdout).
func Usage() {

	uprintf := func(strFmt string, args ...interface{}) {
		fmt.Fprintf(UsageWriter, strFmt, args...)
	}

	uprintln := func(strFmt string, args ...interface{}) {
		uprintf(strFmt+"\n", args...)
	}

	mlen := 0
	opts := []Option{}
	for _, opt := range baseOptionSet {
		opts = append(opts, *opt)
		s := fmt.Sprintf("%s", opt.Name)
		if len(s) > mlen {
			mlen = len(s)
		}
	}

	sort.Sort(sortedUsageOptionSlice(opts))

	if App.Version != "" {
		uprintln(`%s (ver. %s)`, App.Name, App.Version)
	} else {
		uprintln(`%s`, App.Name)
	}

	if App.Description != "" {
		uprintln(`%s`, App.Description)
	}

	uprintln("")

	if len(App.Examples) > 0 {
		uprintln("Examples:")
		for _, v := range App.Examples {
			uprintln(" $ %s\n      %s\n", v.Cmd, v.Description)
		}
	}

	if len(opts) > 0 {
		uprintln("Flags:")

		lastSort := opts[0].Options.SortOrder

		fmtStr := fmt.Sprintf(" -%%-%ds (default: %%s)\n     %%s\n", mlen)
		for _, opt := range opts {
			if opt.Options.SortOrder != lastSort {
				uprintln("")
			}

			uprintln(fmtStr,
				opt.Name,
				opt.defaultValueString("<empty>"),
				opt.Description,
			)

			lastSort = opt.Options.SortOrder
		}
	}
}
<|endoftext|>


<commit_before>package shh

import (
	"bytes"
	"os/exec"
	"strings"
	"time"

	"github.com/heroku/slog"
)

type Nagios3StatsPoller struct {
	measurements chan<- Measurement
	metricNames  []string
}

func NewNagios3StatsPoller(measurements chan<- Measurement, config Config) Nagios3StatsPoller {
	return Nagios3StatsPoller{
		measurements: measurements,
		metricNames:  config.Nagios3MetricNames,
	}
}

func (poller Nagios3StatsPoller) Poll(tick time.Time) {
	ctx := slog.Context{"poller": poller.Name(), "fn": "Poll", "tick": tick}

	if len(poller.metricNames) > 0 {
		cmd := exec.Command("nagios3stats", "-m", "-d", strings.Join(poller.metricNames, ","))
		var stdout, stderr bytes.Buffer
		cmd.Stdout = &stdout
		cmd.Stderr = &stderr

		if err := cmd.Run(); err != nil {
			LogError(ctx, err, "running sub command: "+string(stderr.Bytes()))
			poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{"error"}, 1, Errors}
			return
		}

		data := strings.Split(stdout.String(), "\n")
		if len(data) != len(poller.metricNames) {
			// some sort of error
		} else {
			for i, name := range poller.metricNames {
				poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{strings.ToLower(name)}, Atouint64(data[i]), Empty}
			}
		}
	}

}

func (poller Nagios3StatsPoller) Name() string {
	return "nagios3stats"
}

func (poller Nagios3StatsPoller) Exit() {}
<commit_msg>Fix length difference<commit_after>package shh

import (
	"bytes"
	"fmt"
	"os/exec"
	"strings"
	"time"

	"github.com/heroku/slog"
)

type Nagios3StatsPoller struct {
	measurements chan<- Measurement
	metricNames  []string
}

func NewNagios3StatsPoller(measurements chan<- Measurement, config Config) Nagios3StatsPoller {
	return Nagios3StatsPoller{
		measurements: measurements,
		metricNames:  config.Nagios3MetricNames,
	}
}

func (poller Nagios3StatsPoller) Poll(tick time.Time) {
	ctx := slog.Context{"poller": poller.Name(), "fn": "Poll", "tick": tick}

	if len(poller.metricNames) > 0 {
		cmd := exec.Command("nagios3stats", "-m", "-d", strings.Join(poller.metricNames, ","))
		var stdout, stderr bytes.Buffer
		cmd.Stdout = &stdout
		cmd.Stderr = &stderr

		if err := cmd.Run(); err != nil {
			LogError(ctx, err, "running sub command: "+string(stderr.Bytes()))
			poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{"error"}, 1, Errors}
			return
		}

		data := strings.Split(stdout.String(), "\n")
		if (len(data) - 1) != len(poller.metricNames) {
			LogError(ctx, fmt.Errorf("Length of requested metrics and returned metrics differs: %d vs %d", len(poller.metricNames), len(data)-1), "checking stdout")
		} else {
			for i, name := range poller.metricNames {
				poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{strings.ToLower(name)}, Atouint64(data[i]), Empty}
			}
		}
	}

}

func (poller Nagios3StatsPoller) Name() string {
	return "nagios3stats"
}

func (poller Nagios3StatsPoller) Exit() {}
<|endoftext|>


<commit_before>package goinsta

import (
	"encoding/json"
	"errors"
	"fmt"
)

type Users struct {
	inst *Instagram

	// It's a bit confusing have the same structure
	// in the Instagram strucure and in the multiple users
	// calls

	endpoint string

	Status   string `json:"status"`
	BigList  bool   `json:"big_list"`
	Users    []User `json:"users"`
	PageSize int    `json:"page_size"`
	NextID   string `json:"next_max_id"`
}

func newUsers(inst *Instagram) *Users {
	users := &Users{inst: inst}

	return users
}

// SetInstagram sets new instagram to user structure
func (users *Users) SetInstagram(inst *Instagram) {
	users.inst = inst
}

var ErrNoMore = errors.New("User list end reached")

// Next allows to paginate after calling:
// Account.Follow* and User.Follow*
//
// New user list is stored inside Users
//
// returns ErrNoMore when list reach the end.
func (users *Users) Next() error {
	insta := users.inst
	endpoint := users.endpoint

	body, err := insta.sendRequest(
		&reqOptions{
			Endpoint: endpoint,
			Query: map[string]string{
				"max_id":             users.NextID,
				"ig_sig_key_version": goInstaSigKeyVersion,
				"rank_token":         insta.rankToken,
			},
		},
	)
	if err == nil {
		usrs := Users{}
		err = json.Unmarshal(body, &usrs)
		if err == nil {
			if !usrs.BigList || usrs.NextID == "" {
				err = ErrNoMore
			}
			*users = usrs
			users.inst = insta
			users.endpoint = endpoint
		}
	}
	return err
}

type userResp struct {
	Status string `json:"status"`
	User   User   `json:"user"`
}

// User is the representation of instagram's user profile
type User struct {
	//Feed *Feed
	//Followers *Followers
	//Following *Following
	//Status *Friendship
	//Story *Story
	//Messages *Messages
	inst *Instagram

	ID                         int64        `json:"pk"`
	Username                   string       `json:"username"`
	FullName                   string       `json:"full_name"`
	Biography                  string       `json:"biography"`
	ProfilePicURL              string       `json:"profile_pic_url"`
	Email                      string       `json:"email"`
	PhoneNumber                string       `json:"phone_number"`
	IsBusiness                 bool         `json:"is_business"`
	Gender                     int          `json:"gender"`
	ProfilePicID               string       `json:"profile_pic_id"`
	HasAnonymousProfilePicture bool         `json:"has_anonymous_profile_picture"`
	IsPrivate                  bool         `json:"is_private"`
	IsVerified                 bool         `json:"is_verified"`
	MediaCount                 int          `json:"media_count"`
	FollowerCount              int          `json:"follower_count"`
	FollowingCount             int          `json:"following_count"`
	GeoMediaCount              int          `json:"geo_media_count"`
	ExternalURL                string       `json:"external_url"`
	HasBiographyTranslation    bool         `json:"has_biography_translation"`
	ExternalLynxURL            string       `json:"external_lynx_url"`
	HdProfilePicURLInfo        PicURLInfo   `json:"hd_profile_pic_url_info"`
	HdProfilePicVersions       []PicURLInfo `json:"hd_profile_pic_versions"`
	UsertagsCount              int          `json:"usertags_count"`
	HasChaining                bool         `json:"has_chaining"`
	IsFavorite                 bool         `json:"is_favorite"`
	ReelAutoArchive            string       `json:"reel_auto_archive"`
	School                     School       `json:"school"`
	PublicEmail                string       `json:"public_email"`
	PublicPhoneNumber          string       `json:"public_phone_number"`
	PublicPhoneCountryCode     string       `json:"public_phone_country_code"`
	ContactPhoneNumber         string       `json:"contact_phone_number"`
	CityID                     int64        `json:"city_id"`
	CityName                   string       `json:"city_name"`
	AddressStreet              string       `json:"address_street"`
	DirectMessaging            string       `json:"direct_messaging"`
	Latitude                   float64      `json:"latitude"`
	Longitude                  float64      `json:"longitude"`
	Category                   string       `json:"category"`
	BusinessContactMethod      string       `json:"business_contact_method"`
	IsCallToActionEnabled      bool         `json:"is_call_to_action_enabled"`
	FbPageCallToActionID       string       `json:"fb_page_call_to_action_id"`
	Zip                        string       `json:"zip"`
	Friendship                 Friendship   `json:"friendship_status"`
}

// Following returns a list of user following.
//
// Users.Next can be used to paginate
func (user *User) Following() (*Users, error) {
	endpoint := fmt.Sprintf(urlFollowing, user.ID)
	body, err := user.inst.sendRequest(
		&reqOptions{
			Endpoint: endpoint,
			Query: map[string]string{
				"max_id":             "",
				"ig_sig_key_version": goInstaSigKeyVersion,
				"rank_token":         user.inst.rankToken,
			},
		},
	)
	if err == nil {
		users := &Users{}
		err = json.Unmarshal(body, users)
		users.inst = user.inst
		users.endpoint = endpoint
		return users, err
	}
	return nil, err
}

// Followers returns a list of user followers.
//
// Users.Next can be used to paginate
func (user *User) Followers() (*Users, error) {
	endpoint := fmt.Sprintf(urlFollowers, user.ID)
	body, err := user.inst.sendRequest(
		&reqOptions{
			Endpoint: endpoint,
			Query: map[string]string{
				"max_id":             "",
				"ig_sig_key_version": goInstaSigKeyVersion,
				"rank_token":         user.inst.rankToken,
			},
		},
	)
	if err == nil {
		users := &Users{}
		err = json.Unmarshal(body, users)
		users.inst = user.inst
		users.endpoint = endpoint
		return users, err
	}
	return nil, err
}

// Block blocks user
//
// This function updates current User structure.
func (user *User) Block() error {
	insta := user.inst
	data, err := insta.prepareData(
		map[string]interface{}{
			"user_id": user.ID,
		},
	)
	if err == nil {
		body, err := insta.sendRequest(
			&reqOptions{
				Endpoint: fmt.Sprintf(urlUserBlock, user.ID),
				Query:    generateSignature(data),
				IsPost:   true,
			},
		)
		if err == nil {
			usr := User{}
			err = json.Unmarshal(body, &usr)
			if err == nil {
				*user = usr
				user.inst = insta
			}
		}
	}
	return err
}

// Unblock unblocks user
//
// This function updates current User structure.
func (user *User) Unblock() error {
	insta := user.inst
	data, err := insta.prepareData(
		map[string]interface{}{
			"user_id": user.ID,
		},
	)
	if err == nil {
		body, err := insta.sendRequest(
			&reqOptions{
				Endpoint: fmt.Sprintf(urlUserUnblock, user.ID),
				Query:    generateSignature(data),
				IsPost:   true,
			},
		)
		if err == nil {
			usr := User{}
			err = json.Unmarshal(body, &usr)
			if err == nil {
				*user = usr
				user.inst = insta
			}
		}
	}
	return err
}

// Follow started following some user
//
// This function performs a follow call. If user is private
// you have to wait until he/she accepts you.
//
// If the account is public User.Friendship will be updated
func (user *User) Follow() error {
	insta := user.inst
	data, err := insta.prepareData(
		map[string]interface{}{
			"user_id": user.ID,
		},
	)
	if err == nil {
		body, err := insta.sendRequest(
			&reqOptions{
				Endpoint: fmt.Sprintf(urlUserFollow, user.ID),
				Query:    generateSignature(data),
				IsPost:   true,
			},
		)
		if err == nil {
			resp := friendResp{}
			err = json.Unmarshal(body, &resp)
			user.Friendship = resp.Friendship
		}
	}
	return err
}
<commit_msg>Changed block and unblock functions (internally) and updated Friendship structure<commit_after>package goinsta

import (
	"encoding/json"
	"errors"
	"fmt"
)

type Users struct {
	inst *Instagram

	// It's a bit confusing have the same structure
	// in the Instagram strucure and in the multiple users
	// calls

	endpoint string

	Status   string `json:"status"`
	BigList  bool   `json:"big_list"`
	Users    []User `json:"users"`
	PageSize int    `json:"page_size"`
	NextID   string `json:"next_max_id"`
}

func newUsers(inst *Instagram) *Users {
	users := &Users{inst: inst}

	return users
}

// SetInstagram sets new instagram to user structure
func (users *Users) SetInstagram(inst *Instagram) {
	users.inst = inst
}

var ErrNoMore = errors.New("User list end reached")

// Next allows to paginate after calling:
// Account.Follow* and User.Follow*
//
// New user list is stored inside Users
//
// returns ErrNoMore when list reach the end.
func (users *Users) Next() error {
	insta := users.inst
	endpoint := users.endpoint

	body, err := insta.sendRequest(
		&reqOptions{
			Endpoint: endpoint,
			Query: map[string]string{
				"max_id":             users.NextID,
				"ig_sig_key_version": goInstaSigKeyVersion,
				"rank_token":         insta.rankToken,
			},
		},
	)
	if err == nil {
		usrs := Users{}
		err = json.Unmarshal(body, &usrs)
		if err == nil {
			if !usrs.BigList || usrs.NextID == "" {
				err = ErrNoMore
			}
			*users = usrs
			users.inst = insta
			users.endpoint = endpoint
		}
	}
	return err
}

type userResp struct {
	Status string `json:"status"`
	User   User   `json:"user"`
}

// User is the representation of instagram's user profile
type User struct {
	//Feed *Feed
	//Followers *Followers
	//Following *Following
	//Status *Friendship
	//Story *Story
	//Messages *Messages
	inst *Instagram

	ID                         int64        `json:"pk"`
	Username                   string       `json:"username"`
	FullName                   string       `json:"full_name"`
	Biography                  string       `json:"biography"`
	ProfilePicURL              string       `json:"profile_pic_url"`
	Email                      string       `json:"email"`
	PhoneNumber                string       `json:"phone_number"`
	IsBusiness                 bool         `json:"is_business"`
	Gender                     int          `json:"gender"`
	ProfilePicID               string       `json:"profile_pic_id"`
	HasAnonymousProfilePicture bool         `json:"has_anonymous_profile_picture"`
	IsPrivate                  bool         `json:"is_private"`
	IsVerified                 bool         `json:"is_verified"`
	MediaCount                 int          `json:"media_count"`
	FollowerCount              int          `json:"follower_count"`
	FollowingCount             int          `json:"following_count"`
	GeoMediaCount              int          `json:"geo_media_count"`
	ExternalURL                string       `json:"external_url"`
	HasBiographyTranslation    bool         `json:"has_biography_translation"`
	ExternalLynxURL            string       `json:"external_lynx_url"`
	HdProfilePicURLInfo        PicURLInfo   `json:"hd_profile_pic_url_info"`
	HdProfilePicVersions       []PicURLInfo `json:"hd_profile_pic_versions"`
	UsertagsCount              int          `json:"usertags_count"`
	HasChaining                bool         `json:"has_chaining"`
	IsFavorite                 bool         `json:"is_favorite"`
	ReelAutoArchive            string       `json:"reel_auto_archive"`
	School                     School       `json:"school"`
	PublicEmail                string       `json:"public_email"`
	PublicPhoneNumber          string       `json:"public_phone_number"`
	PublicPhoneCountryCode     string       `json:"public_phone_country_code"`
	ContactPhoneNumber         string       `json:"contact_phone_number"`
	CityID                     int64        `json:"city_id"`
	CityName                   string       `json:"city_name"`
	AddressStreet              string       `json:"address_street"`
	DirectMessaging            string       `json:"direct_messaging"`
	Latitude                   float64      `json:"latitude"`
	Longitude                  float64      `json:"longitude"`
	Category                   string       `json:"category"`
	BusinessContactMethod      string       `json:"business_contact_method"`
	IsCallToActionEnabled      bool         `json:"is_call_to_action_enabled"`
	FbPageCallToActionID       string       `json:"fb_page_call_to_action_id"`
	Zip                        string       `json:"zip"`
	Friendship                 Friendship   `json:"friendship_status"`
}

// Following returns a list of user following.
//
// Users.Next can be used to paginate
func (user *User) Following() (*Users, error) {
	endpoint := fmt.Sprintf(urlFollowing, user.ID)
	body, err := user.inst.sendRequest(
		&reqOptions{
			Endpoint: endpoint,
			Query: map[string]string{
				"max_id":             "",
				"ig_sig_key_version": goInstaSigKeyVersion,
				"rank_token":         user.inst.rankToken,
			},
		},
	)
	if err == nil {
		users := &Users{}
		err = json.Unmarshal(body, users)
		users.inst = user.inst
		users.endpoint = endpoint
		return users, err
	}
	return nil, err
}

// Followers returns a list of user followers.
//
// Users.Next can be used to paginate
func (user *User) Followers() (*Users, error) {
	endpoint := fmt.Sprintf(urlFollowers, user.ID)
	body, err := user.inst.sendRequest(
		&reqOptions{
			Endpoint: endpoint,
			Query: map[string]string{
				"max_id":             "",
				"ig_sig_key_version": goInstaSigKeyVersion,
				"rank_token":         user.inst.rankToken,
			},
		},
	)
	if err == nil {
		users := &Users{}
		err = json.Unmarshal(body, users)
		users.inst = user.inst
		users.endpoint = endpoint
		return users, err
	}
	return nil, err
}

// Block blocks user
//
// This function updates current User.Friendship structure.
func (user *User) Block() error {
	insta := user.inst
	data, err := insta.prepareData(
		map[string]interface{}{
			"user_id": user.ID,
		},
	)
	if err == nil {
		body, err := insta.sendRequest(
			&reqOptions{
				Endpoint: fmt.Sprintf(urlUserBlock, user.ID),
				Query:    generateSignature(data),
				IsPost:   true,
			},
		)
		if err == nil {
			resp := friendResp{}
			err = json.Unmarshal(body, &resp)
			user.Friendship = resp.Friendship
		}
	}
	return err
}

// Unblock unblocks user
//
// This function updates current User structure.
func (user *User) Unblock() error {
	insta := user.inst
	data, err := insta.prepareData(
		map[string]interface{}{
			"user_id": user.ID,
		},
	)
	if err == nil {
		body, err := insta.sendRequest(
			&reqOptions{
				Endpoint: fmt.Sprintf(urlUserUnblock, user.ID),
				Query:    generateSignature(data),
				IsPost:   true,
			},
		)
		if err == nil {
			resp := friendResp{}
			err = json.Unmarshal(body, &resp)
			user.Friendship = resp.Friendship
		}
	}
	return err
}

// Follow started following some user
//
// This function performs a follow call. If user is private
// you have to wait until he/she accepts you.
//
// If the account is public User.Friendship will be updated
func (user *User) Follow() error {
	insta := user.inst
	data, err := insta.prepareData(
		map[string]interface{}{
			"user_id": user.ID,
		},
	)
	if err == nil {
		body, err := insta.sendRequest(
			&reqOptions{
				Endpoint: fmt.Sprintf(urlUserFollow, user.ID),
				Query:    generateSignature(data),
				IsPost:   true,
			},
		)
		if err == nil {
			resp := friendResp{}
			err = json.Unmarshal(body, &resp)
			user.Friendship = resp.Friendship
		}
	}
	return err
}
<|endoftext|>


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

// Package textproto implements generic support for text-based request/response
// protocols in the style of HTTP, NNTP, and SMTP.
//
// The package provides:
//
// Error, which represents a numeric error response from
// a server.
//
// Pipeline, to manage pipelined requests and responses
// in a client.
//
// Reader, to read numeric response code lines,
// key: value headers, lines wrapped with leading spaces
// on continuation lines, and whole text blocks ending
// with a dot on a line by itself.
//
// Writer, to write dot-encoded text blocks.
//
package textproto

import (
	"bufio"
	"fmt"
	"io"
	"net"
)

// An Error represents a numeric error response from a server.
type Error struct {
	Code int
	Msg  string
}

func (e *Error) Error() string {
	return fmt.Sprintf("%03d %s", e.Code, e.Msg)
}

// A ProtocolError describes a protocol violation such
// as an invalid response or a hung-up connection.
type ProtocolError string

func (p ProtocolError) Error() string {
	return string(p)
}

// A Conn represents a textual network protocol connection.
// It consists of a Reader and Writer to manage I/O
// and a Pipeline to sequence concurrent requests on the connection.
// These embedded types carry methods with them;
// see the documentation of those types for details.
type Conn struct {
	Reader
	Writer
	Pipeline
	conn io.ReadWriteCloser
}

// NewConn returns a new Conn using conn for I/O.
func NewConn(conn io.ReadWriteCloser) *Conn {
	return &Conn{
		Reader: Reader{R: bufio.NewReader(conn)},
		Writer: Writer{W: bufio.NewWriter(conn)},
		conn:   conn,
	}
}

// Close closes the connection.
func (c *Conn) Close() error {
	return c.conn.Close()
}

// Dial connects to the given address on the given network using net.Dial
// and then returns a new Conn for the connection.
func Dial(network, addr string) (*Conn, error) {
	c, err := net.Dial(network, addr)
	if err != nil {
		return nil, err
	}
	return NewConn(c), nil
}

// Cmd is a convenience method that sends a command after
// waiting its turn in the pipeline.  The command text is the
// result of formatting format with args and appending \r\n.
// Cmd returns the id of the command, for use with StartResponse and EndResponse.
//
// For example, a client might run a HELP command that returns a dot-body
// by using:
//
//	id, err := c.Cmd("HELP")
//	if err != nil {
//		return nil, err
//	}
//
//	c.StartResponse(id)
//	defer c.EndResponse(id)
//
//	if _, _, err = c.ReadCodeLine(110); err != nil {
//		return nil, err
//	}
//	text, err := c.ReadDotAll()
//	if err != nil {
//		return nil, err
//	}
//	return c.ReadCodeLine(250)
//
func (c *Conn) Cmd(format string, args ...interface{}) (id uint, err error) {
	id = c.Next()
	c.StartRequest(id)
	err = c.PrintfLine(format, args...)
	c.EndRequest(id)
	if err != nil {
		return 0, err
	}
	return id, nil
}
<commit_msg>net/textproto: add Conn to doc comment<commit_after>// Copyright 2010 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package textproto implements generic support for text-based request/response
// protocols in the style of HTTP, NNTP, and SMTP.
//
// The package provides:
//
// Error, which represents a numeric error response from
// a server.
//
// Pipeline, to manage pipelined requests and responses
// in a client.
//
// Reader, to read numeric response code lines,
// key: value headers, lines wrapped with leading spaces
// on continuation lines, and whole text blocks ending
// with a dot on a line by itself.
//
// Writer, to write dot-encoded text blocks.
//
// Conn, a convenient packaging of Reader, Writer, and Pipeline for use
// with a single network connection."
//
package textproto

import (
	"bufio"
	"fmt"
	"io"
	"net"
)

// An Error represents a numeric error response from a server.
type Error struct {
	Code int
	Msg  string
}

func (e *Error) Error() string {
	return fmt.Sprintf("%03d %s", e.Code, e.Msg)
}

// A ProtocolError describes a protocol violation such
// as an invalid response or a hung-up connection.
type ProtocolError string

func (p ProtocolError) Error() string {
	return string(p)
}

// A Conn represents a textual network protocol connection.
// It consists of a Reader and Writer to manage I/O
// and a Pipeline to sequence concurrent requests on the connection.
// These embedded types carry methods with them;
// see the documentation of those types for details.
type Conn struct {
	Reader
	Writer
	Pipeline
	conn io.ReadWriteCloser
}

// NewConn returns a new Conn using conn for I/O.
func NewConn(conn io.ReadWriteCloser) *Conn {
	return &Conn{
		Reader: Reader{R: bufio.NewReader(conn)},
		Writer: Writer{W: bufio.NewWriter(conn)},
		conn:   conn,
	}
}

// Close closes the connection.
func (c *Conn) Close() error {
	return c.conn.Close()
}

// Dial connects to the given address on the given network using net.Dial
// and then returns a new Conn for the connection.
func Dial(network, addr string) (*Conn, error) {
	c, err := net.Dial(network, addr)
	if err != nil {
		return nil, err
	}
	return NewConn(c), nil
}

// Cmd is a convenience method that sends a command after
// waiting its turn in the pipeline.  The command text is the
// result of formatting format with args and appending \r\n.
// Cmd returns the id of the command, for use with StartResponse and EndResponse.
//
// For example, a client might run a HELP command that returns a dot-body
// by using:
//
//	id, err := c.Cmd("HELP")
//	if err != nil {
//		return nil, err
//	}
//
//	c.StartResponse(id)
//	defer c.EndResponse(id)
//
//	if _, _, err = c.ReadCodeLine(110); err != nil {
//		return nil, err
//	}
//	text, err := c.ReadDotAll()
//	if err != nil {
//		return nil, err
//	}
//	return c.ReadCodeLine(250)
//
func (c *Conn) Cmd(format string, args ...interface{}) (id uint, err error) {
	id = c.Next()
	c.StartRequest(id)
	err = c.PrintfLine(format, args...)
	c.EndRequest(id)
	if err != nil {
		return 0, err
	}
	return id, nil
}
<|endoftext|>


<commit_before>package heka_clever_plugins

import (
	"fmt"
	"strings"
	"sync"
	"time"

	"github.com/Clever/heka-clever-plugins/postgres"
	_ "github.com/lib/pq"
	"github.com/mozilla-services/heka/message"
	. "github.com/mozilla-services/heka/pipeline"
)

// Redshift does not allow more than 32767 params in a query, so queries of type INSERT...VALUES($1, $2, ...)
// will not work if the number of params crosses 32767
const redshiftParamsLimit = 32767

type PostgresOutput struct {
	db                        *postgres.PostgresDB
	helper                    PluginHelper
	runner                    OutputRunner
	lastMsgLoopCount          uint
	insertSchema              string
	insertTable               string
	insertMessageFields       []string
	insertTableColumns        []string
	flushInterval             uint32
	flushCount                int // Max messages before flush
	allowMissingMessageFields bool
	queryTimeout              uint32
}

type PostgresOutputConfig struct {
	// Table name and colums. Message fields to write.
	InsertSchema        string `toml:"insert_schema"`
	InsertTable         string `toml:"insert_table"`
	InsertTableColumns  string `toml:"insert_table_columns"`
	InsertMessageFields string `toml:"insert_message_fields"`
	// If a field is missing in the Heka message, allow writing NULL
	AllowMissingMessageFields bool `toml:"allow_missing_message_fields"`

	// Database Connection
	DBHost               string `toml:"db_host"`
	DBPort               int    `toml:"db_port"`
	DBName               string `toml:"db_name"`
	DBUser               string `toml:"db_user"`
	DBPassword           string `toml:"db_password"`
	DBConnectionTimeout  int    `toml:"db_connection_timeout"`
	DBMaxOpenConnections int    `toml:"db_max_open_connections"`
	DBSSLMode            string `toml:"db_ssl_mode"`

	// Interval at which accumulated messages should be written to Postgres,
	// in milliseconds (default 1000, i.e. 1 second)
	FlushInterval uint32 `toml:"flush_interval"`
	// Number of messages that triggers a write to Postgres (default 10000)
	FlushCount int `toml:"flush_count"`
	// The time in milliseconds that the plugin will wait before giving up
	// on a Postgres query (defaults to 300000, i.e. 5 minute)
	QueryTimeout uint32 `toml:"query_timeout"`
}

func (po *PostgresOutput) ConfigStruct() interface{} {
	return &PostgresOutputConfig{
		AllowMissingMessageFields: true,
		DBConnectionTimeout:       5,
		DBMaxOpenConnections:      10,
		DBSSLMode:                 "require",
		FlushInterval:             uint32(1000),
		FlushCount:                5000,
		InsertSchema:              "public",
		QueryTimeout:              uint32(300000),
	}
}

func (po *PostgresOutput) Init(rawConf interface{}) error {
	config := rawConf.(*PostgresOutputConfig)
	po.flushInterval = config.FlushInterval
	po.flushCount = config.FlushCount
	po.queryTimeout = config.QueryTimeout
	po.insertSchema = config.InsertSchema
	po.insertTable = config.InsertTable
	if config.InsertMessageFields == "" {
		return fmt.Errorf("config item 'insert_message_fields' cannot be empty string")
	}
	po.insertMessageFields = strings.Split(config.InsertMessageFields, " ")
	if config.InsertTableColumns == "" {
		return fmt.Errorf("config item 'insert_table_columns' cannot be empty string")
	}
	po.insertTableColumns = strings.Split(config.InsertTableColumns, " ")
	po.allowMissingMessageFields = config.AllowMissingMessageFields
	p := postgres.DBConnectionParams{
		Host:           config.DBHost,
		Port:           config.DBPort,
		DBName:         config.DBName,
		User:           config.DBUser,
		Password:       config.DBPassword,
		ConnectTimeout: config.DBConnectionTimeout,
		SSLMode:        config.DBSSLMode,
	}

	// since Redshift does not allow more than 32767 params, the query should be flushed
	// before the number of params crosses that amount
	if po.flushCount*len(po.insertTableColumns) > 32767 {
		po.flushCount = int(32767 / len(po.insertTableColumns))
	}

	db, err := postgres.New(&p)
	if err != nil {
		return err
	}
	db.SetMaxOpenConns(config.DBMaxOpenConnections)
	po.db = db
	return nil
}

func (o *PostgresOutput) Run(or OutputRunner, h PluginHelper) (err error) {
	defer o.db.Close()

	o.runner = or
	o.helper = h

	var wg sync.WaitGroup
	wg.Add(1)

	committers := o.makeCommitters(5, &wg)
	go o.receiver(committers, &wg)

	wg.Wait()
	return
}

// Runs in a separate goroutine, accepting incoming messages, buffering output
// data until the ticker triggers the buffered data should be put onto the
// committer channel.
func (o *PostgresOutput) receiver(committers chan<- [][]interface{}, wg *sync.WaitGroup) {
	var pack *PipelinePack

	ticker := time.Tick(time.Duration(o.flushInterval) * time.Millisecond)
	batch := [][]interface{}{}

	for ok := true; ok; {
		select {
		case pack, ok = <-o.runner.InChan():
			if !ok {
				// Closed inChan => we're shutting down, flush data
				committers <- batch
				close(committers)
				break
			}

			// Read values from message fields
			vals, err := o.convertMessageToValues(pack.Message, o.insertMessageFields)

			o.lastMsgLoopCount = pack.MsgLoopCount // here to help prevent infinite error loops
			pack.Recycle()

			if err != nil {
				o.logError(err)
			} else {
				batch = append(batch, vals)
				if len(batch) >= o.flushCount {
					committers <- batch
					batch = [][]interface{}{}
				}
			}
		case <-ticker:
			committers <- batch
			batch = [][]interface{}{}
		}
	}
	wg.Done()
}

// Runs in a separate goroutine, waits for buffered data on the committer
// channel, bulk inserts it into Postgres, and puts the now empty buffer on the
// return channel for reuse.
func (o *PostgresOutput) makeCommitters(count int, wg *sync.WaitGroup) chan<- [][]interface{} {
	batches := make(chan [][]interface{})

	for i := 0; i < count; i++ {
		wg.Add(1)
		go func(i int) {
			for batch := range batches {
				if len(batch) <= 0 {
					continue
				}

				done := o.commit(batch)
				timeout := time.NewTimer(time.Duration(o.queryTimeout) * time.Millisecond)

				select {
				case <-done:
					timeout.Stop()
				case <-timeout.C:
					o.logError(fmt.Errorf("Postgres insert took more than %dms.", o.queryTimeout))
				}
			}
			wg.Done()
		}(i)
	}

	return batches
}

func (o *PostgresOutput) commit(batch [][]interface{}) <-chan struct{} {
	done := make(chan struct{})

	go func() {
		err := o.db.Insert(o.insertSchema, o.insertTable, o.insertTableColumns, batch)
		if err != nil {
			o.logError(err)
		}
		done <- struct{}{}
	}()

	return done
}

// convertMessageToValue reads a Heka Message and returns a slice of field values
func (po *PostgresOutput) convertMessageToValues(m *message.Message, insertFields []string) (fieldValues []interface{}, err error) {
	fieldValues = []interface{}{}
	missingFields := []string{}
	for _, field := range insertFields {
		// Special case: get "Timestamp" from Heka message
		if field == "Timestamp" {
			// Convert Heka time (Unix timestamp in nanoseconds) to Golang time
			v := time.Unix(0, m.GetTimestamp())
			fieldValues = append(fieldValues, v)
		} else {
			v, ok := m.GetFieldValue(field)
			if !ok {
				// If configured to do so, write NULL when a FieldValue isn't found in the Heka message
				if po.allowMissingMessageFields {
					v = nil
				} else {
					missingFields = append(missingFields, field)
					continue
				}
			}
			fieldValues = append(fieldValues, v)
		}
	}

	if len(missingFields) > 0 {
		return []interface{}{}, fmt.Errorf("message is missing expected fields: %s", strings.Join(missingFields, ", "))
	}

	return fieldValues, nil
}

// Injects a pack with an error message back into the heka pipeline so it can be alerted on
func (po *PostgresOutput) logError(err error) {
	pack := po.helper.PipelinePack(po.lastMsgLoopCount)
	if pack == nil {
		err = fmt.Errorf(
			"system.postgres-output exceeded MaxMsgLoops = %d, err: %s",
			po.lastMsgLoopCount, err.Error(),
		)
		po.runner.LogError(err)
		return
	}
	pack.Message.SetLogger(po.runner.Name())
	pack.Message.SetType("system.postgres-output")
	pack.Message.SetPayload(err.Error())
	go func() { po.helper.PipelineConfig().Router().InChan() <- pack }() // Don't block sending
}

func init() {
	RegisterPlugin("PostgresOutput", func() interface{} {
		return new(PostgresOutput)
	})
}
<commit_msg>using redshiftParamsLimit which was defined for this purpose<commit_after>package heka_clever_plugins

import (
	"fmt"
	"strings"
	"sync"
	"time"

	"github.com/Clever/heka-clever-plugins/postgres"
	_ "github.com/lib/pq"
	"github.com/mozilla-services/heka/message"
	. "github.com/mozilla-services/heka/pipeline"
)

// Redshift does not allow more than 32767 params in a query, so queries of type INSERT...VALUES($1, $2, ...)
// will not work if the number of params crosses 32767
const redshiftParamsLimit = 32767

type PostgresOutput struct {
	db                        *postgres.PostgresDB
	helper                    PluginHelper
	runner                    OutputRunner
	lastMsgLoopCount          uint
	insertSchema              string
	insertTable               string
	insertMessageFields       []string
	insertTableColumns        []string
	flushInterval             uint32
	flushCount                int // Max messages before flush
	allowMissingMessageFields bool
	queryTimeout              uint32
}

type PostgresOutputConfig struct {
	// Table name and colums. Message fields to write.
	InsertSchema        string `toml:"insert_schema"`
	InsertTable         string `toml:"insert_table"`
	InsertTableColumns  string `toml:"insert_table_columns"`
	InsertMessageFields string `toml:"insert_message_fields"`
	// If a field is missing in the Heka message, allow writing NULL
	AllowMissingMessageFields bool `toml:"allow_missing_message_fields"`

	// Database Connection
	DBHost               string `toml:"db_host"`
	DBPort               int    `toml:"db_port"`
	DBName               string `toml:"db_name"`
	DBUser               string `toml:"db_user"`
	DBPassword           string `toml:"db_password"`
	DBConnectionTimeout  int    `toml:"db_connection_timeout"`
	DBMaxOpenConnections int    `toml:"db_max_open_connections"`
	DBSSLMode            string `toml:"db_ssl_mode"`

	// Interval at which accumulated messages should be written to Postgres,
	// in milliseconds (default 1000, i.e. 1 second)
	FlushInterval uint32 `toml:"flush_interval"`
	// Number of messages that triggers a write to Postgres (default 10000)
	FlushCount int `toml:"flush_count"`
	// The time in milliseconds that the plugin will wait before giving up
	// on a Postgres query (defaults to 300000, i.e. 5 minute)
	QueryTimeout uint32 `toml:"query_timeout"`
}

func (po *PostgresOutput) ConfigStruct() interface{} {
	return &PostgresOutputConfig{
		AllowMissingMessageFields: true,
		DBConnectionTimeout:       5,
		DBMaxOpenConnections:      10,
		DBSSLMode:                 "require",
		FlushInterval:             uint32(1000),
		FlushCount:                5000,
		InsertSchema:              "public",
		QueryTimeout:              uint32(300000),
	}
}

func (po *PostgresOutput) Init(rawConf interface{}) error {
	config := rawConf.(*PostgresOutputConfig)
	po.flushInterval = config.FlushInterval
	po.flushCount = config.FlushCount
	po.queryTimeout = config.QueryTimeout
	po.insertSchema = config.InsertSchema
	po.insertTable = config.InsertTable
	if config.InsertMessageFields == "" {
		return fmt.Errorf("config item 'insert_message_fields' cannot be empty string")
	}
	po.insertMessageFields = strings.Split(config.InsertMessageFields, " ")
	if config.InsertTableColumns == "" {
		return fmt.Errorf("config item 'insert_table_columns' cannot be empty string")
	}
	po.insertTableColumns = strings.Split(config.InsertTableColumns, " ")
	po.allowMissingMessageFields = config.AllowMissingMessageFields
	p := postgres.DBConnectionParams{
		Host:           config.DBHost,
		Port:           config.DBPort,
		DBName:         config.DBName,
		User:           config.DBUser,
		Password:       config.DBPassword,
		ConnectTimeout: config.DBConnectionTimeout,
		SSLMode:        config.DBSSLMode,
	}

	// since Redshift does not allow more than `redshiftParamsLimit` params, the query should be flushed
	// before the number of params crosses that amount
	if po.flushCount*len(po.insertTableColumns) > redshiftParamsLimit {
		po.flushCount = int(redshiftParamsLimit / len(po.insertTableColumns))
	}

	db, err := postgres.New(&p)
	if err != nil {
		return err
	}
	db.SetMaxOpenConns(config.DBMaxOpenConnections)
	po.db = db
	return nil
}

func (o *PostgresOutput) Run(or OutputRunner, h PluginHelper) (err error) {
	defer o.db.Close()

	o.runner = or
	o.helper = h

	var wg sync.WaitGroup
	wg.Add(1)

	committers := o.makeCommitters(5, &wg)
	go o.receiver(committers, &wg)

	wg.Wait()
	return
}

// Runs in a separate goroutine, accepting incoming messages, buffering output
// data until the ticker triggers the buffered data should be put onto the
// committer channel.
func (o *PostgresOutput) receiver(committers chan<- [][]interface{}, wg *sync.WaitGroup) {
	var pack *PipelinePack

	ticker := time.Tick(time.Duration(o.flushInterval) * time.Millisecond)
	batch := [][]interface{}{}

	for ok := true; ok; {
		select {
		case pack, ok = <-o.runner.InChan():
			if !ok {
				// Closed inChan => we're shutting down, flush data
				committers <- batch
				close(committers)
				break
			}

			// Read values from message fields
			vals, err := o.convertMessageToValues(pack.Message, o.insertMessageFields)

			o.lastMsgLoopCount = pack.MsgLoopCount // here to help prevent infinite error loops
			pack.Recycle()

			if err != nil {
				o.logError(err)
			} else {
				batch = append(batch, vals)
				if len(batch) >= o.flushCount {
					committers <- batch
					batch = [][]interface{}{}
				}
			}
		case <-ticker:
			committers <- batch
			batch = [][]interface{}{}
		}
	}
	wg.Done()
}

// Runs in a separate goroutine, waits for buffered data on the committer
// channel, bulk inserts it into Postgres, and puts the now empty buffer on the
// return channel for reuse.
func (o *PostgresOutput) makeCommitters(count int, wg *sync.WaitGroup) chan<- [][]interface{} {
	batches := make(chan [][]interface{})

	for i := 0; i < count; i++ {
		wg.Add(1)
		go func(i int) {
			for batch := range batches {
				if len(batch) <= 0 {
					continue
				}

				done := o.commit(batch)
				timeout := time.NewTimer(time.Duration(o.queryTimeout) * time.Millisecond)

				select {
				case <-done:
					timeout.Stop()
				case <-timeout.C:
					o.logError(fmt.Errorf("Postgres insert took more than %dms.", o.queryTimeout))
				}
			}
			wg.Done()
		}(i)
	}

	return batches
}

func (o *PostgresOutput) commit(batch [][]interface{}) <-chan struct{} {
	done := make(chan struct{})

	go func() {
		err := o.db.Insert(o.insertSchema, o.insertTable, o.insertTableColumns, batch)
		if err != nil {
			o.logError(err)
		}
		done <- struct{}{}
	}()

	return done
}

// convertMessageToValue reads a Heka Message and returns a slice of field values
func (po *PostgresOutput) convertMessageToValues(m *message.Message, insertFields []string) (fieldValues []interface{}, err error) {
	fieldValues = []interface{}{}
	missingFields := []string{}
	for _, field := range insertFields {
		// Special case: get "Timestamp" from Heka message
		if field == "Timestamp" {
			// Convert Heka time (Unix timestamp in nanoseconds) to Golang time
			v := time.Unix(0, m.GetTimestamp())
			fieldValues = append(fieldValues, v)
		} else {
			v, ok := m.GetFieldValue(field)
			if !ok {
				// If configured to do so, write NULL when a FieldValue isn't found in the Heka message
				if po.allowMissingMessageFields {
					v = nil
				} else {
					missingFields = append(missingFields, field)
					continue
				}
			}
			fieldValues = append(fieldValues, v)
		}
	}

	if len(missingFields) > 0 {
		return []interface{}{}, fmt.Errorf("message is missing expected fields: %s", strings.Join(missingFields, ", "))
	}

	return fieldValues, nil
}

// Injects a pack with an error message back into the heka pipeline so it can be alerted on
func (po *PostgresOutput) logError(err error) {
	pack := po.helper.PipelinePack(po.lastMsgLoopCount)
	if pack == nil {
		err = fmt.Errorf(
			"system.postgres-output exceeded MaxMsgLoops = %d, err: %s",
			po.lastMsgLoopCount, err.Error(),
		)
		po.runner.LogError(err)
		return
	}
	pack.Message.SetLogger(po.runner.Name())
	pack.Message.SetType("system.postgres-output")
	pack.Message.SetPayload(err.Error())
	go func() { po.helper.PipelineConfig().Router().InChan() <- pack }() // Don't block sending
}

func init() {
	RegisterPlugin("PostgresOutput", func() interface{} {
		return new(PostgresOutput)
	})
}
<|endoftext|>


<commit_before>package osm

import (
	"fmt"
	"reflect"
	"strconv"
	"time"
)

const (
	format_Date     = "2006-01-02"
	format_DateTime = "2006-01-02 15:04:05"
)

type strTo string

// set string
func (f *strTo) Set(v string) {
	if v != "" {
		*f = strTo(v)
	} else {
		f.Clear()
	}
}

// clean string
func (f *strTo) Clear() {
	*f = strTo(0x1E)
}

// check string exist
func (f strTo) Exist() bool {
	return string(f) != string(0x1E)
}

// string to bool
func (f strTo) Bool() (bool, error) {
	return strconv.ParseBool(f.String())
}

// string to float32
func (f strTo) Float32() (float32, error) {
	v, err := strconv.ParseFloat(f.String(), 32)
	return float32(v), err
}

// string to float64
func (f strTo) Float64() (float64, error) {
	return strconv.ParseFloat(f.String(), 64)
}

// string to int
func (f strTo) Int() (int, error) {
	v, err := strconv.ParseInt(f.String(), 10, 32)
	return int(v), err
}

// string to int8
func (f strTo) Int8() (int8, error) {
	v, err := strconv.ParseInt(f.String(), 10, 8)
	return int8(v), err
}

// string to int16
func (f strTo) Int16() (int16, error) {
	v, err := strconv.ParseInt(f.String(), 10, 16)
	return int16(v), err
}

// string to int32
func (f strTo) Int32() (int32, error) {
	v, err := strconv.ParseInt(f.String(), 10, 32)
	return int32(v), err
}

// string to int64
func (f strTo) Int64() (int64, error) {
	v, err := strconv.ParseInt(f.String(), 10, 64)
	return int64(v), err
}

// string to uint
func (f strTo) Uint() (uint, error) {
	v, err := strconv.ParseUint(f.String(), 10, 32)
	return uint(v), err
}

// string to uint8
func (f strTo) Uint8() (uint8, error) {
	v, err := strconv.ParseUint(f.String(), 10, 8)
	return uint8(v), err
}

// string to uint16
func (f strTo) Uint16() (uint16, error) {
	v, err := strconv.ParseUint(f.String(), 10, 16)
	return uint16(v), err
}

// string to uint31
func (f strTo) Uint32() (uint32, error) {
	v, err := strconv.ParseUint(f.String(), 10, 32)
	return uint32(v), err
}

// string to uint64
func (f strTo) Uint64() (uint64, error) {
	v, err := strconv.ParseUint(f.String(), 10, 64)
	return uint64(v), err
}

// string to string
func (f strTo) String() string {
	if f.Exist() {
		return string(f)
	}
	return ""
}

// interface to string
func toStr(value interface{}, args ...int) (s string) {
	switch v := value.(type) {
	case bool:
		s = strconv.FormatBool(v)
	case float32:
		s = strconv.FormatFloat(float64(v), 'f', argInt(args).Get(0, -1), argInt(args).Get(1, 32))
	case float64:
		s = strconv.FormatFloat(v, 'f', argInt(args).Get(0, -1), argInt(args).Get(1, 64))
	case int:
		s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
	case int8:
		s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
	case int16:
		s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
	case int32:
		s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
	case int64:
		s = strconv.FormatInt(v, argInt(args).Get(0, 10))
	case uint:
		s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
	case uint8:
		s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
	case uint16:
		s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
	case uint32:
		s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
	case uint64:
		s = strconv.FormatUint(v, argInt(args).Get(0, 10))
	case string:
		s = v
	case []byte:
		s = string(v)
	default:
		s = fmt.Sprintf("%v", v)
	}
	return s
}

// type argString []string

// // get string by index from string slice
// func (a argString) Get(i int, args ...string) (r string) {
// 	if i >= 0 && i < len(a) {
// 		r = a[i]
// 	} else if len(args) > 0 {
// 		r = args[0]
// 	}
// 	return
// }

type argInt []int

// get int by index from int slice
func (a argInt) Get(i int, args ...int) (r int) {
	if i >= 0 && i < len(a) {
		r = a[i]
	}
	if len(args) > 0 {
		r = args[0]
	}
	return
}

// type argAny []interface{}

// // get interface by index from interface slice
// func (a argAny) Get(i int, args ...interface{}) (r interface{}) {
// 	if i >= 0 && i < len(a) {
// 		r = a[i]
// 	}
// 	if len(args) > 0 {
// 		r = args[0]
// 	}
// 	return
// }

// // parse time to string with location
// func timeParse(dateString, format string) (time.Time, error) {
// 	tp, err := time.Parse(format, dateString)
// 	return tp, err
// }

// format time string
func timeFormat(t time.Time, format string) string {
	return t.Format(format)
}

// // get pointer indirect type
// func indirectType(v reflect.Type) reflect.Type {
// 	switch v.Kind() {
// 	case reflect.Ptr:
// 		return indirectType(v.Elem())
// 	default:
// 		return v
// 	}
// 	return v
// }

// set data to reflect.Value
func setDataToValue(value reflect.Value, data interface{}) {
	switch value.Kind() {
	case reflect.Bool:
		if data == nil {
			value.SetBool(false)
		} else if v, ok := data.(bool); ok {
			value.SetBool(v)
		} else {
			v, _ := strTo(toStr(data)).Bool()
			value.SetBool(v)
		}

	case reflect.String:
		if data == nil {
			value.SetString("")
		} else {
			value.SetString(toStr(data))
		}

	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		if data == nil {
			value.SetInt(0)
		} else {
			val := reflect.ValueOf(data)
			switch val.Kind() {
			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
				value.SetInt(val.Int())
			case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
				value.SetInt(int64(val.Uint()))
			default:
				v, _ := strTo(toStr(data)).Int64()
				value.SetInt(v)
			}
		}
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		if data == nil {
			value.SetUint(0)
		} else {
			val := reflect.ValueOf(data)
			switch val.Kind() {
			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
				value.SetUint(uint64(val.Int()))
			case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
				value.SetUint(val.Uint())
			default:
				v, _ := strTo(toStr(data)).Uint64()
				value.SetUint(v)
			}
		}
	case reflect.Float64, reflect.Float32:
		if data == nil {
			value.SetFloat(0)
		} else {
			val := reflect.ValueOf(data)
			switch val.Kind() {
			case reflect.Float64:
				value.SetFloat(val.Float())
			default:
				v, _ := strTo(toStr(data)).Float64()
				value.SetFloat(v)
			}
		}

	case reflect.Struct:
		if data == nil {
			value.Set(reflect.Zero(value.Type()))

		} else if _, ok := value.Interface().(time.Time); ok {
			var str string
			switch d := data.(type) {
			case time.Time:
				value.Set(reflect.ValueOf(d))
			case []byte:
				str = string(d)
			case string:
				str = d
			}
			if str != "" {
				if len(str) >= 19 {
					str = str[:19]
					t, err := time.Parse(format_DateTime, str)
					if err == nil {
						value.Set(reflect.ValueOf(t))
					}
				} else if len(str) >= 10 {
					str = str[:10]
					t, err := time.Parse(format_Date, str)
					if err == nil {
						value.Set(reflect.ValueOf(t))
					}
				}
			}
		}
	}
}

// // camel string, xx_yy to XxYy
// func toGoName(s string) string {
// 	data := make([]byte, 0, len(s))
// 	j := false
// 	k := false
// 	num := len(s) - 1
// 	for i := 0; i <= num; i++ {
// 		d := s[i]
// 		if k == false && d >= 'A' && d <= 'Z' {
// 			k = true
// 		}
// 		if d >= 'a' && d <= 'z' && (j || k == false) {
// 			d = d - 32
// 			j = false
// 			k = true
// 		}
// 		if k && d == '_' && num > i /**&& s[i+1] >= 'a' && s[i+1] <= 'z'**/ {
// 			j = true
// 			continue
// 		}
// 		data = append(data, d)
// 	}
// 	return string(data[:len(data)])
// }

// func toGoName(name string) string {
// 	names := strings.Split(name, "_")

// 	newName := ""
// 	for _, ntemp := range names {
// 		newName += strings.ToUpper(ntemp[0:1]) + strings.ToLower(ntemp[1:len(ntemp)])
// 	}
// 	return newName
// }

// camel string, xx_yy to XxYy, 特列字符 ID,JSON
func toGoName(name string) string {
	num := len(name)
	data := make([]byte, len(name))
	j := 0
	k := true
	for i := 0; i < num; i++ {
		d := name[i]
		if d == '_' {
			k = true
			if j >= 2 && data[j-2] == 'I' && data[j-1] == 'd' {
				data[j-1] = 'D'
			}
			if j >= 4 && data[j-4] == 'J' && data[j-3] == 's' && data[j-2] == 'o' && data[j-1] == 'n' {
				data[j-3] = 'S'
				data[j-2] = 'O'
				data[j-1] = 'N'
			}
		} else {
			if k {
				if d >= 'a' && d <= 'z' {
					d = d - 32
				}
			} else {
				if d >= 'A' && d <= 'Z' {
					d = d + 32
				}
			}
			data[j] = d
			j++
			k = false
		}
	}
	if j > 1 && data[j-1] == 'd' && data[j-2] == 'I' {
		data[j-1] = 'D'
	}
	if j >= 4 && data[j-4] == 'J' && data[j-3] == 's' && data[j-2] == 'o' && data[j-1] == 'n' {
		data[j-3] = 'S'
		data[j-2] = 'O'
		data[j-1] = 'N'
	}
	return string(data[:j])
}
<commit_msg>只处理ID<commit_after>package osm

import (
	"fmt"
	"reflect"
	"strconv"
	"time"
)

const (
	format_Date     = "2006-01-02"
	format_DateTime = "2006-01-02 15:04:05"
)

type strTo string

// set string
func (f *strTo) Set(v string) {
	if v != "" {
		*f = strTo(v)
	} else {
		f.Clear()
	}
}

// clean string
func (f *strTo) Clear() {
	*f = strTo(0x1E)
}

// check string exist
func (f strTo) Exist() bool {
	return string(f) != string(0x1E)
}

// string to bool
func (f strTo) Bool() (bool, error) {
	return strconv.ParseBool(f.String())
}

// string to float32
func (f strTo) Float32() (float32, error) {
	v, err := strconv.ParseFloat(f.String(), 32)
	return float32(v), err
}

// string to float64
func (f strTo) Float64() (float64, error) {
	return strconv.ParseFloat(f.String(), 64)
}

// string to int
func (f strTo) Int() (int, error) {
	v, err := strconv.ParseInt(f.String(), 10, 32)
	return int(v), err
}

// string to int8
func (f strTo) Int8() (int8, error) {
	v, err := strconv.ParseInt(f.String(), 10, 8)
	return int8(v), err
}

// string to int16
func (f strTo) Int16() (int16, error) {
	v, err := strconv.ParseInt(f.String(), 10, 16)
	return int16(v), err
}

// string to int32
func (f strTo) Int32() (int32, error) {
	v, err := strconv.ParseInt(f.String(), 10, 32)
	return int32(v), err
}

// string to int64
func (f strTo) Int64() (int64, error) {
	v, err := strconv.ParseInt(f.String(), 10, 64)
	return int64(v), err
}

// string to uint
func (f strTo) Uint() (uint, error) {
	v, err := strconv.ParseUint(f.String(), 10, 32)
	return uint(v), err
}

// string to uint8
func (f strTo) Uint8() (uint8, error) {
	v, err := strconv.ParseUint(f.String(), 10, 8)
	return uint8(v), err
}

// string to uint16
func (f strTo) Uint16() (uint16, error) {
	v, err := strconv.ParseUint(f.String(), 10, 16)
	return uint16(v), err
}

// string to uint31
func (f strTo) Uint32() (uint32, error) {
	v, err := strconv.ParseUint(f.String(), 10, 32)
	return uint32(v), err
}

// string to uint64
func (f strTo) Uint64() (uint64, error) {
	v, err := strconv.ParseUint(f.String(), 10, 64)
	return uint64(v), err
}

// string to string
func (f strTo) String() string {
	if f.Exist() {
		return string(f)
	}
	return ""
}

// interface to string
func toStr(value interface{}, args ...int) (s string) {
	switch v := value.(type) {
	case bool:
		s = strconv.FormatBool(v)
	case float32:
		s = strconv.FormatFloat(float64(v), 'f', argInt(args).Get(0, -1), argInt(args).Get(1, 32))
	case float64:
		s = strconv.FormatFloat(v, 'f', argInt(args).Get(0, -1), argInt(args).Get(1, 64))
	case int:
		s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
	case int8:
		s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
	case int16:
		s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
	case int32:
		s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
	case int64:
		s = strconv.FormatInt(v, argInt(args).Get(0, 10))
	case uint:
		s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
	case uint8:
		s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
	case uint16:
		s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
	case uint32:
		s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
	case uint64:
		s = strconv.FormatUint(v, argInt(args).Get(0, 10))
	case string:
		s = v
	case []byte:
		s = string(v)
	default:
		s = fmt.Sprintf("%v", v)
	}
	return s
}

// type argString []string

// // get string by index from string slice
// func (a argString) Get(i int, args ...string) (r string) {
// 	if i >= 0 && i < len(a) {
// 		r = a[i]
// 	} else if len(args) > 0 {
// 		r = args[0]
// 	}
// 	return
// }

type argInt []int

// get int by index from int slice
func (a argInt) Get(i int, args ...int) (r int) {
	if i >= 0 && i < len(a) {
		r = a[i]
	}
	if len(args) > 0 {
		r = args[0]
	}
	return
}

// type argAny []interface{}

// // get interface by index from interface slice
// func (a argAny) Get(i int, args ...interface{}) (r interface{}) {
// 	if i >= 0 && i < len(a) {
// 		r = a[i]
// 	}
// 	if len(args) > 0 {
// 		r = args[0]
// 	}
// 	return
// }

// // parse time to string with location
// func timeParse(dateString, format string) (time.Time, error) {
// 	tp, err := time.Parse(format, dateString)
// 	return tp, err
// }

// format time string
func timeFormat(t time.Time, format string) string {
	return t.Format(format)
}

// // get pointer indirect type
// func indirectType(v reflect.Type) reflect.Type {
// 	switch v.Kind() {
// 	case reflect.Ptr:
// 		return indirectType(v.Elem())
// 	default:
// 		return v
// 	}
// 	return v
// }

// set data to reflect.Value
func setDataToValue(value reflect.Value, data interface{}) {
	switch value.Kind() {
	case reflect.Bool:
		if data == nil {
			value.SetBool(false)
		} else if v, ok := data.(bool); ok {
			value.SetBool(v)
		} else {
			v, _ := strTo(toStr(data)).Bool()
			value.SetBool(v)
		}

	case reflect.String:
		if data == nil {
			value.SetString("")
		} else {
			value.SetString(toStr(data))
		}

	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		if data == nil {
			value.SetInt(0)
		} else {
			val := reflect.ValueOf(data)
			switch val.Kind() {
			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
				value.SetInt(val.Int())
			case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
				value.SetInt(int64(val.Uint()))
			default:
				v, _ := strTo(toStr(data)).Int64()
				value.SetInt(v)
			}
		}
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		if data == nil {
			value.SetUint(0)
		} else {
			val := reflect.ValueOf(data)
			switch val.Kind() {
			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
				value.SetUint(uint64(val.Int()))
			case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
				value.SetUint(val.Uint())
			default:
				v, _ := strTo(toStr(data)).Uint64()
				value.SetUint(v)
			}
		}
	case reflect.Float64, reflect.Float32:
		if data == nil {
			value.SetFloat(0)
		} else {
			val := reflect.ValueOf(data)
			switch val.Kind() {
			case reflect.Float64:
				value.SetFloat(val.Float())
			default:
				v, _ := strTo(toStr(data)).Float64()
				value.SetFloat(v)
			}
		}

	case reflect.Struct:
		if data == nil {
			value.Set(reflect.Zero(value.Type()))

		} else if _, ok := value.Interface().(time.Time); ok {
			var str string
			switch d := data.(type) {
			case time.Time:
				value.Set(reflect.ValueOf(d))
			case []byte:
				str = string(d)
			case string:
				str = d
			}
			if str != "" {
				if len(str) >= 19 {
					str = str[:19]
					t, err := time.Parse(format_DateTime, str)
					if err == nil {
						value.Set(reflect.ValueOf(t))
					}
				} else if len(str) >= 10 {
					str = str[:10]
					t, err := time.Parse(format_Date, str)
					if err == nil {
						value.Set(reflect.ValueOf(t))
					}
				}
			}
		}
	}
}

// // camel string, xx_yy to XxYy
// func toGoName(s string) string {
// 	data := make([]byte, 0, len(s))
// 	j := false
// 	k := false
// 	num := len(s) - 1
// 	for i := 0; i <= num; i++ {
// 		d := s[i]
// 		if k == false && d >= 'A' && d <= 'Z' {
// 			k = true
// 		}
// 		if d >= 'a' && d <= 'z' && (j || k == false) {
// 			d = d - 32
// 			j = false
// 			k = true
// 		}
// 		if k && d == '_' && num > i /**&& s[i+1] >= 'a' && s[i+1] <= 'z'**/ {
// 			j = true
// 			continue
// 		}
// 		data = append(data, d)
// 	}
// 	return string(data[:len(data)])
// }

// func toGoName(name string) string {
// 	names := strings.Split(name, "_")

// 	newName := ""
// 	for _, ntemp := range names {
// 		newName += strings.ToUpper(ntemp[0:1]) + strings.ToLower(ntemp[1:len(ntemp)])
// 	}
// 	return newName
// }

// camel string, xx_yy to XxYy, 特列字符 ID
func toGoName(name string) string {
	num := len(name)
	data := make([]byte, len(name))
	j := 0
	k := true
	for i := 0; i < num; i++ {
		d := name[i]
		if d == '_' {
			k = true
			if j >= 2 && data[j-2] == 'I' && data[j-1] == 'd' {
				data[j-1] = 'D'
			}
		} else {
			if k {
				if d >= 'a' && d <= 'z' {
					d = d - 32
				}
			} else {
				if d >= 'A' && d <= 'Z' {
					d = d + 32
				}
			}
			data[j] = d
			j++
			k = false
		}
	}
	if j > 1 && data[j-1] == 'd' && data[j-2] == 'I' {
		data[j-1] = 'D'
	}
	return string(data[:j])
}
<|endoftext|>


<commit_before>/*
 * utils.go: Go bindings for lxc
 *
 * Copyright © 2013, S.Çağlar Onur
 *
 * Authors:
 * S.Çağlar Onur <caglar@10ur.org>
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2, as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

package lxc

// #include <stdlib.h>
import "C"

import (
	"unsafe"
)

func makeArgs(args []string) []*C.char {
	ret := make([]*C.char, len(args))
	for i, s := range args {
		ret[i] = C.CString(s)
	}
	return ret
}

func freeArgs(cArgs []*C.char) {
	for _, s := range cArgs {
		C.free(unsafe.Pointer(s))
	}
}
<commit_msg>create requires NULL terminated array<commit_after>/*
 * utils.go: Go bindings for lxc
 *
 * Copyright © 2013, S.Çağlar Onur
 *
 * Authors:
 * S.Çağlar Onur <caglar@10ur.org>
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2, as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

package lxc

// #include <stdlib.h>
import "C"

import (
	"unsafe"
)

func makeArgs(args []string) []*C.char {
	ret := make([]*C.char, len(args) + 1)
	for i, s := range args {
		ret[i] = C.CString(s)
	}
	ret[len(ret) - 1] = nil
	return ret
}

func freeArgs(cArgs []*C.char) {
	for _, s := range cArgs {
		C.free(unsafe.Pointer(s))
	}
}
<|endoftext|>