<commit_before>package api

import (
	"math/big"

	"github.com/bytom/blockchain/query"
	"github.com/bytom/consensus/difficulty"
	chainjson "github.com/bytom/encoding/json"
	"github.com/bytom/protocol/bc"
	"github.com/bytom/protocol/bc/types"
)

// return best block hash
func (a *API) getBestBlockHash() Response {
	blockHash := map[string]string{"block_hash": a.chain.BestBlockHash().String()}
	return NewSuccessResponse(blockHash)
}

// return current block count
func (a *API) getBlockCount() Response {
	blockHeight := map[string]uint64{"block_count": a.chain.BestBlockHeight()}
	return NewSuccessResponse(blockHeight)
}

// BlockTx is the tx struct for getBlock func
type BlockTx struct {
	ID         bc.Hash                  `json:"id"`
	Version    uint64                   `json:"version"`
	Size       uint64                   `json:"size"`
	TimeRange  uint64                   `json:"time_range"`
	Inputs     []*query.AnnotatedInput  `json:"inputs"`
	Outputs    []*query.AnnotatedOutput `json:"outputs"`
	StatusFail bool                     `json:"status_fail"`
}

// BlockReq is used to handle getBlock req
type BlockReq struct {
	BlockHeight uint64             `json:"block_height"`
	BlockHash   chainjson.HexBytes `json:"block_hash"`
}

// GetBlockResp is the resp for getBlock api
type GetBlockResp struct {
	Hash                   *bc.Hash   `json:"hash"`
	Size                   uint64     `json:"size"`
	Version                uint64     `json:"version"`
	Height                 uint64     `json:"height"`
	PreviousBlockHash      *bc.Hash   `json:"previous_block_hash"`
	Timestamp              uint64     `json:"timestamp"`
	Nonce                  uint64     `json:"nonce"`
	Bits                   uint64     `json:"bits"`
	Difficulty             string     `json:"difficulty"`
	TransactionsMerkleRoot *bc.Hash   `json:"transaction_merkle_root"`
	TransactionStatusHash  *bc.Hash   `json:"transaction_status_hash"`
	Transactions           []*BlockTx `json:"transactions"`
}

// return block by hash
func (a *API) getBlock(ins BlockReq) Response {
	var err error
	block := &types.Block{}
	if len(ins.BlockHash) == 32 {
		b32 := [32]byte{}
		copy(b32[:], ins.BlockHash)
		hash := bc.NewHash(b32)
		block, err = a.chain.GetBlockByHash(&hash)
	} else {
		block, err = a.chain.GetBlockByHeight(ins.BlockHeight)
	}
	if err != nil {
		return NewErrorResponse(err)
	}

	blockHash := block.Hash()
	txStatus, err := a.chain.GetTransactionStatus(&blockHash)
	rawBlock, err := block.MarshalText()
	if err != nil {
		return NewErrorResponse(err)
	}

	resp := &GetBlockResp{
		Hash:                   &blockHash,
		Size:                   uint64(len(rawBlock)),
		Version:                block.Version,
		Height:                 block.Height,
		PreviousBlockHash:      &block.PreviousBlockHash,
		Timestamp:              block.Timestamp,
		Nonce:                  block.Nonce,
		Bits:                   block.Bits,
		Difficulty:             difficulty.CalcWork(block.Bits).String(),
		TransactionsMerkleRoot: &block.TransactionsMerkleRoot,
		TransactionStatusHash:  &block.TransactionStatusHash,
		Transactions:           []*BlockTx{},
	}

	for i, orig := range block.Transactions {
		tx := &BlockTx{
			ID:        orig.ID,
			Version:   orig.Version,
			Size:      orig.SerializedSize,
			TimeRange: orig.TimeRange,
			Inputs:    []*query.AnnotatedInput{},
			Outputs:   []*query.AnnotatedOutput{},
		}
		tx.StatusFail, err = txStatus.GetStatus(i)
		if err != nil {
			NewSuccessResponse(resp)
		}

		for i := range orig.Inputs {
			tx.Inputs = append(tx.Inputs, a.wallet.BuildAnnotatedInput(orig, uint32(i)))
		}
		for i := range orig.Outputs {
			tx.Outputs = append(tx.Outputs, a.wallet.BuildAnnotatedOutput(orig, i))
		}
		resp.Transactions = append(resp.Transactions, tx)
	}
	return NewSuccessResponse(resp)
}

// GetBlockHeaderResp is resp struct for getBlockHeader API
type GetBlockHeaderResp struct {
	BlockHeader *types.BlockHeader `json:"block_header"`
	Reward      uint64             `json:"reward"`
}

func (a *API) getBlockHeader(ins BlockReq) Response {
	var err error
	block := &types.Block{}
	if len(ins.BlockHash) == 32 {
		b32 := [32]byte{}
		copy(b32[:], ins.BlockHash)
		hash := bc.NewHash(b32)
		block, err = a.chain.GetBlockByHash(&hash)
	} else {
		block, err = a.chain.GetBlockByHeight(ins.BlockHeight)
	}
	if err != nil {
		return NewErrorResponse(err)
	}

	resp := &GetBlockHeaderResp{
		BlockHeader: &block.BlockHeader,
		Reward:      block.Transactions[0].Outputs[0].Amount,
	}
	return NewSuccessResponse(resp)
}

// GetDifficultyResp is resp struct for getDifficulty API
type GetDifficultyResp struct {
	BlockHash   *bc.Hash `json:"hash"`
	BlockHeight uint64   `json:"height"`
	Bits        uint64   `json:"bits"`
	Difficulty  string   `json:"difficulty"`
}

func (a *API) getDifficulty(ins *BlockReq) Response {
	var err error
	block := &types.Block{}

	if len(ins.BlockHash) == 32 && ins.BlockHash != nil {
		b32 := [32]byte{}
		copy(b32[:], ins.BlockHash)
		hash := bc.NewHash(b32)
		block, err = a.chain.GetBlockByHash(&hash)
	} else if ins.BlockHeight > 0 {
		block, err = a.chain.GetBlockByHeight(ins.BlockHeight)
	} else {
		hash := a.chain.BestBlockHash()
		block, err = a.chain.GetBlockByHash(hash)
	}

	if err != nil {
		return NewErrorResponse(err)
	}

	blockHash := block.Hash()
	resp := &GetDifficultyResp{
		BlockHash:   &blockHash,
		BlockHeight: block.Height,
		Bits:        block.Bits,
		Difficulty:  difficulty.CalcWork(block.Bits).String(),
	}
	return NewSuccessResponse(resp)
}

// getHashRateResp is resp struct for getHashRate API
type getHashRateResp struct {
	BlockHash   *bc.Hash `json:"hash"`
	BlockHeight uint64   `json:"height"`
	HashRate    uint64   `json:"hash_rate"`
}

func (a *API) getHashRate(ins BlockReq) Response {
	var err error
	block := &types.Block{}

	if len(ins.BlockHash) == 32 && ins.BlockHash != nil {
		b32 := [32]byte{}
		copy(b32[:], ins.BlockHash)
		hash := bc.NewHash(b32)
		block, err = a.chain.GetBlockByHash(&hash)
	} else if ins.BlockHeight > 0 {
		block, err = a.chain.GetBlockByHeight(ins.BlockHeight)
	} else {
		hash := a.chain.BestBlockHash()
		block, err = a.chain.GetBlockByHash(hash)
	}

	if err != nil {
		return NewErrorResponse(err)
	}

	preBlock, err := a.chain.GetBlockByHash(&block.PreviousBlockHash)
	if err != nil {
		return NewErrorResponse(err)
	}

	diffTime := block.Timestamp - preBlock.Timestamp
	hashCount := difficulty.CalcWork(block.Bits)
	hashRate := new(big.Int).Div(hashCount, big.NewInt(int64(diffTime)))

	blockHash := block.Hash()
	resp := &getHashRateResp{
		BlockHash:   &blockHash,
		BlockHeight: block.Height,
		HashRate:    hashRate.Uint64(),
	}
	return NewSuccessResponse(resp)
}
<commit_msg>get-block response transaction add source_id<commit_after>package api

import (
	"math/big"

	"github.com/bytom/blockchain/query"
	"github.com/bytom/consensus/difficulty"
	chainjson "github.com/bytom/encoding/json"
	"github.com/bytom/protocol/bc"
	"github.com/bytom/protocol/bc/types"
)

// return best block hash
func (a *API) getBestBlockHash() Response {
	blockHash := map[string]string{"block_hash": a.chain.BestBlockHash().String()}
	return NewSuccessResponse(blockHash)
}

// return current block count
func (a *API) getBlockCount() Response {
	blockHeight := map[string]uint64{"block_count": a.chain.BestBlockHeight()}
	return NewSuccessResponse(blockHeight)
}

// BlockTx is the tx struct for getBlock func
type BlockTx struct {
	ID         bc.Hash                  `json:"id"`
	Version    uint64                   `json:"version"`
	Size       uint64                   `json:"size"`
	TimeRange  uint64                   `json:"time_range"`
	Inputs     []*query.AnnotatedInput  `json:"inputs"`
	Outputs    []*query.AnnotatedOutput `json:"outputs"`
	StatusFail bool                     `json:"status_fail"`
	SourceID   bc.Hash                  `json:"source_id"`
}

// BlockReq is used to handle getBlock req
type BlockReq struct {
	BlockHeight uint64             `json:"block_height"`
	BlockHash   chainjson.HexBytes `json:"block_hash"`
}

// GetBlockResp is the resp for getBlock api
type GetBlockResp struct {
	Hash                   *bc.Hash   `json:"hash"`
	Size                   uint64     `json:"size"`
	Version                uint64     `json:"version"`
	Height                 uint64     `json:"height"`
	PreviousBlockHash      *bc.Hash   `json:"previous_block_hash"`
	Timestamp              uint64     `json:"timestamp"`
	Nonce                  uint64     `json:"nonce"`
	Bits                   uint64     `json:"bits"`
	Difficulty             string     `json:"difficulty"`
	TransactionsMerkleRoot *bc.Hash   `json:"transaction_merkle_root"`
	TransactionStatusHash  *bc.Hash   `json:"transaction_status_hash"`
	Transactions           []*BlockTx `json:"transactions"`
}

// return block by hash
func (a *API) getBlock(ins BlockReq) Response {
	var err error
	block := &types.Block{}
	if len(ins.BlockHash) == 32 {
		b32 := [32]byte{}
		copy(b32[:], ins.BlockHash)
		hash := bc.NewHash(b32)
		block, err = a.chain.GetBlockByHash(&hash)
	} else {
		block, err = a.chain.GetBlockByHeight(ins.BlockHeight)
	}
	if err != nil {
		return NewErrorResponse(err)
	}

	blockHash := block.Hash()
	txStatus, err := a.chain.GetTransactionStatus(&blockHash)
	rawBlock, err := block.MarshalText()
	if err != nil {
		return NewErrorResponse(err)
	}

	resp := &GetBlockResp{
		Hash:                   &blockHash,
		Size:                   uint64(len(rawBlock)),
		Version:                block.Version,
		Height:                 block.Height,
		PreviousBlockHash:      &block.PreviousBlockHash,
		Timestamp:              block.Timestamp,
		Nonce:                  block.Nonce,
		Bits:                   block.Bits,
		Difficulty:             difficulty.CalcWork(block.Bits).String(),
		TransactionsMerkleRoot: &block.TransactionsMerkleRoot,
		TransactionStatusHash:  &block.TransactionStatusHash,
		Transactions:           []*BlockTx{},
	}

	for i, orig := range block.Transactions {
		tx := &BlockTx{
			ID:        orig.ID,
			Version:   orig.Version,
			Size:      orig.SerializedSize,
			TimeRange: orig.TimeRange,
			Inputs:    []*query.AnnotatedInput{},
			Outputs:   []*query.AnnotatedOutput{},
		}
		tx.StatusFail, err = txStatus.GetStatus(i)
		if err != nil {
			NewSuccessResponse(resp)
		}

		for id, e := range orig.Entries {
			switch e.(type) {
			case *bc.Mux:
				tx.SourceID = id
			default:
				continue
			}
		}

		for i := range orig.Inputs {
			tx.Inputs = append(tx.Inputs, a.wallet.BuildAnnotatedInput(orig, uint32(i)))
		}
		for i := range orig.Outputs {
			tx.Outputs = append(tx.Outputs, a.wallet.BuildAnnotatedOutput(orig, i))
		}
		resp.Transactions = append(resp.Transactions, tx)
	}
	return NewSuccessResponse(resp)
}

// GetBlockHeaderResp is resp struct for getBlockHeader API
type GetBlockHeaderResp struct {
	BlockHeader *types.BlockHeader `json:"block_header"`
	Reward      uint64             `json:"reward"`
}

func (a *API) getBlockHeader(ins BlockReq) Response {
	var err error
	block := &types.Block{}
	if len(ins.BlockHash) == 32 {
		b32 := [32]byte{}
		copy(b32[:], ins.BlockHash)
		hash := bc.NewHash(b32)
		block, err = a.chain.GetBlockByHash(&hash)
	} else {
		block, err = a.chain.GetBlockByHeight(ins.BlockHeight)
	}
	if err != nil {
		return NewErrorResponse(err)
	}

	resp := &GetBlockHeaderResp{
		BlockHeader: &block.BlockHeader,
		Reward:      block.Transactions[0].Outputs[0].Amount,
	}
	return NewSuccessResponse(resp)
}

// GetDifficultyResp is resp struct for getDifficulty API
type GetDifficultyResp struct {
	BlockHash   *bc.Hash `json:"hash"`
	BlockHeight uint64   `json:"height"`
	Bits        uint64   `json:"bits"`
	Difficulty  string   `json:"difficulty"`
}

func (a *API) getDifficulty(ins *BlockReq) Response {
	var err error
	block := &types.Block{}

	if len(ins.BlockHash) == 32 && ins.BlockHash != nil {
		b32 := [32]byte{}
		copy(b32[:], ins.BlockHash)
		hash := bc.NewHash(b32)
		block, err = a.chain.GetBlockByHash(&hash)
	} else if ins.BlockHeight > 0 {
		block, err = a.chain.GetBlockByHeight(ins.BlockHeight)
	} else {
		hash := a.chain.BestBlockHash()
		block, err = a.chain.GetBlockByHash(hash)
	}

	if err != nil {
		return NewErrorResponse(err)
	}

	blockHash := block.Hash()
	resp := &GetDifficultyResp{
		BlockHash:   &blockHash,
		BlockHeight: block.Height,
		Bits:        block.Bits,
		Difficulty:  difficulty.CalcWork(block.Bits).String(),
	}
	return NewSuccessResponse(resp)
}

// getHashRateResp is resp struct for getHashRate API
type getHashRateResp struct {
	BlockHash   *bc.Hash `json:"hash"`
	BlockHeight uint64   `json:"height"`
	HashRate    uint64   `json:"hash_rate"`
}

func (a *API) getHashRate(ins BlockReq) Response {
	var err error
	block := &types.Block{}

	if len(ins.BlockHash) == 32 && ins.BlockHash != nil {
		b32 := [32]byte{}
		copy(b32[:], ins.BlockHash)
		hash := bc.NewHash(b32)
		block, err = a.chain.GetBlockByHash(&hash)
	} else if ins.BlockHeight > 0 {
		block, err = a.chain.GetBlockByHeight(ins.BlockHeight)
	} else {
		hash := a.chain.BestBlockHash()
		block, err = a.chain.GetBlockByHash(hash)
	}

	if err != nil {
		return NewErrorResponse(err)
	}

	preBlock, err := a.chain.GetBlockByHash(&block.PreviousBlockHash)
	if err != nil {
		return NewErrorResponse(err)
	}

	diffTime := block.Timestamp - preBlock.Timestamp
	hashCount := difficulty.CalcWork(block.Bits)
	hashRate := new(big.Int).Div(hashCount, big.NewInt(int64(diffTime)))

	blockHash := block.Hash()
	resp := &getHashRateResp{
		BlockHash:   &blockHash,
		BlockHeight: block.Height,
		HashRate:    hashRate.Uint64(),
	}
	return NewSuccessResponse(resp)
}
<|endoftext|>


<commit_before>package server

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

// Version of IronFunctions
var Version = "0.1.102"

func handleVersion(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{"version": Version})
}
<commit_msg>release 0.2<commit_after>package server

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

// Version of IronFunctions
var Version = "0.2.0"

func handleVersion(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{"version": Version})
}
<|endoftext|>


<commit_before>package server

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

// Version of IronFunctions
var Version = "0.0.77"

func handleVersion(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{"version": Version})
}
<commit_msg>functions: 0.0.78 release [skip ci]<commit_after>package server

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

// Version of IronFunctions
var Version = "0.0.78"

func handleVersion(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{"version": Version})
}
<|endoftext|>


<commit_before>package api

import (
	"encoding/json"
	"net/http"

	"github.com/FederationOfFathers/dashboard/bridge"
	"go.uber.org/zap"
)

func init() {
	// legacy - use old slack name
	Router.Path("/api/v0/auth/team-tool").Methods("GET").HandlerFunc(
		func(w http.ResponseWriter, r *http.Request) {
			var err error
			r, err = authorized(w, r)
			if err != nil {
				w.Write([]byte(`""`))
				return
			}
			w.Header().Set("Content-Type", "application/json")
			id := getSlackUserID(r)
			user, _ := bridge.Data.Slack.User(id)
			json.NewEncoder(w).Encode(bridge.OldEventToolAuthorization(user.Name))
		},
	)

	// V1 - uses member ID in the auth
	Router.Path("/api/v1/auth/team-tool").Methods("GET").HandlerFunc(
		func(w http.ResponseWriter, r *http.Request) {
			var err error
			r, err = authorized(w, r)
			if err != nil {
				w.Write([]byte(`""`))
				return
			}
			w.Header().Set("Content-Type", "application/json")
			id := getSlackUserID(r)
			member, err := DB.MemberBySlackID(id)
			if err != nil {
				Logger.Error("Unable to get member", zap.Error(err), zap.String("slackId", id))
			}
			json.NewEncoder(w).Encode(bridge.OldEventToolAuthorization(string(member.ID)))
		},
	)
}
<commit_msg>Converting int properly to string<commit_after>package api

import (
	"encoding/json"
	"net/http"
	"strconv"

	"github.com/FederationOfFathers/dashboard/bridge"
	"go.uber.org/zap"
)

func init() {
	// legacy - use old slack name
	Router.Path("/api/v0/auth/team-tool").Methods("GET").HandlerFunc(
		func(w http.ResponseWriter, r *http.Request) {
			var err error
			r, err = authorized(w, r)
			if err != nil {
				w.Write([]byte(`""`))
				return
			}
			w.Header().Set("Content-Type", "application/json")
			id := getSlackUserID(r)
			user, _ := bridge.Data.Slack.User(id)
			json.NewEncoder(w).Encode(bridge.OldEventToolAuthorization(user.Name))
		},
	)

	// V1 - uses member ID in the auth
	Router.Path("/api/v1/auth/team-tool").Methods("GET").HandlerFunc(
		func(w http.ResponseWriter, r *http.Request) {
			var err error
			r, err = authorized(w, r)
			if err != nil {
				w.Write([]byte(`""`))
				return
			}
			w.Header().Set("Content-Type", "application/json")
			id := getSlackUserID(r)
			member, err := DB.MemberBySlackID(id)
			if err != nil {
				Logger.Error("Unable to get member", zap.Error(err), zap.String("slackId", id))
			}
			json.NewEncoder(w).Encode(bridge.OldEventToolAuthorization(strconv.Itoa(member.ID)))
		},
	)
}
<|endoftext|>


<commit_before>package oraclegen

import (
	"errors"
	"fmt"
	"os"

	"github.com/rbastic/dyndao/object"
	"github.com/rbastic/dyndao/schema"
)

// BindingDelete generates the appropriate SQL, binding args, and binding where clause parameters
// to execute the requested delete operation. 'obj' is not required to be a
func (g Generator) BindingDelete(sch *schema.Schema, queryVals *object.Object) (string, []interface{}, error) {
	table := queryVals.Type
	schTable, ok := sch.Tables[table]
	if !ok {
		return "", nil, errors.New("BindingDelete: Table map unavailable for table " + table)
	}
	tableName := schema.GetTableName(schTable.Name, table)
	fieldsMap := schTable.Fields
	if fieldsMap == nil {
		return "", nil, errors.New("BindingDelete: Field map unavailable for table " + table)
	}

	whereClause, bindWhere, err := renderWhereClause(schTable, fieldsMap, queryVals)
	if err != nil {
		return "", nil, err
	}

	whereString := "WHERE"
	if len(bindWhere) == 0 {
		whereString = ""
	}
	// TODO: Replicate this fix to sqlite sqlgen
	sqlStr := fmt.Sprintf("DELETE FROM %s %s %s", tableName, whereString, whereClause)
	if os.Getenv("DEBUG") != "" {
		fmt.Println(sqlStr)
	}
	return sqlStr, bindWhere, nil
}
<commit_msg>implement table aliasing for BindingDelete<commit_after>package oraclegen

import (
	"errors"
	"fmt"
	"os"

	"github.com/rbastic/dyndao/object"
	"github.com/rbastic/dyndao/schema"
)

// BindingDelete generates the appropriate SQL, binding args, and binding where clause parameters
// to execute the requested delete operation. 'obj' is not required to be a
func (g Generator) BindingDelete(sch *schema.Schema, queryVals *object.Object) (string, []interface{}, error) {
	table := queryVals.Type
	schTable := sch.GetTable(table)
	if schTable == nil {
		return "", nil, errors.New("BindingDelete: Table map unavailable for table " + table)
	}
	tableName := schema.GetTableName(schTable.Name, table)
	fieldsMap := schTable.Fields
	if fieldsMap == nil {
		return "", nil, errors.New("BindingDelete: Field map unavailable for table " + table)
	}

	whereClause, bindWhere, err := renderWhereClause(schTable, fieldsMap, queryVals)
	if err != nil {
		return "", nil, err
	}

	whereString := "WHERE"
	if len(bindWhere) == 0 {
		whereString = ""
	}
	// TODO: Replicate this fix to sqlite sqlgen
	sqlStr := fmt.Sprintf("DELETE FROM %s %s %s", tableName, whereString, whereClause)
	if os.Getenv("DEBUG") != "" {
		fmt.Println(sqlStr)
	}
	return sqlStr, bindWhere, nil
}
<|endoftext|>


<commit_before>// Package errors implements functions to manipulate compression errors.
//
// In idiomatic Go, it is an anti-pattern to use panics as a form of error
// reporting in the API. Instead, the expected way to transmit errors is by
// returning an error value. Unfortunately, the checking of "err != nil" in
// tight loops commonly found in compression causes non-negligible performance
// degradation. While this may not be idiomatic, the internal packages of this
// repository rely on panics as a normal means to convey errors. In order to
// ensure that these panics do not leak across the public API, the public
// packages must recover from these panics and present an error value.
//
// The Panic and Recover functions in this package provide a safe way to
// recover from errors only generated from within this repository.
//
// Example usage:
//	func Foo() (err error) {
//		defer errors.Recover(&err)
//
//		if rand.Intn(2) == 0 {
//			// Unexpected panics will not be caught by Recover.
//			io.Closer(nil).Close()
//		} else {
//			// Errors thrown by Panic will be caught by Recover.
//			errors.Panic(errors.New("whoopsie"))
//		}
//	}
//
package errors

import "strings"

const (
	// Unknown indicates that there is no classification for this error.
	Unknown = iota

	// Internal indicates that this error is due to an internal bug.
	// Users should file a issue report if this type of error is encountered.
	Internal

	// Invalid indicates that this error is due to the user misusing the API
	// and is indicative of a bug on the user's part.
	Invalid

	// Deprecated indicates the use of a deprecated and unsupported feature.
	Deprecated

	// Corrupted indicates that the input stream is corrupted.
	Corrupted

	// Closed indicates that the handlers are closed.
	Closed
)

var codeMap = map[int]string{
	Unknown:    "unknown error",
	Internal:   "internal error",
	Invalid:    "invalid argument",
	Deprecated: "deprecated format",
	Corrupted:  "corrupted input",
	Closed:     "closed handler",
}

type Error struct {
	Code int    // The error type
	Pkg  string // Name of the package where the error originated
	Msg  string // Descriptive message about the error (optional)
}

func (e Error) Error() string {
	var ss []string
	for _, s := range []string{e.Pkg, codeMap[e.Code], e.Msg} {
		if s != "" {
			ss = append(ss, s)
		}
	}
	return strings.Join(ss, ": ")
}

func (e Error) CompressError()     {}
func (e Error) IsInternal() bool   { return e.Code == Internal }
func (e Error) IsInvalid() bool    { return e.Code == Invalid }
func (e Error) IsDeprecated() bool { return e.Code == Deprecated }
func (e Error) IsCorrupted() bool  { return e.Code == Corrupted }
func (e Error) IsClosed() bool     { return e.Code == Closed }

func IsInternal(err error) bool   { return isCode(err, Internal) }
func IsInvalid(err error) bool    { return isCode(err, Invalid) }
func IsDeprecated(err error) bool { return isCode(err, Deprecated) }
func IsCorrupted(err error) bool  { return isCode(err, Corrupted) }
func IsClosed(err error) bool     { return isCode(err, Closed) }

func isCode(err error, code int) bool {
	if cerr, ok := err.(Error); ok && cerr.Code == code {
		return true
	}
	return false
}

// errWrap is used by Panic and Recover to ensure that only errors raised by
// Panic are recovered by Recover.
type errWrap struct{ e *error }

func Recover(err *error) {
	switch ex := recover().(type) {
	case nil:
		// Do nothing.
	case errWrap:
		*err = *ex.e
	default:
		panic(ex)
	}
}

func Panic(err error) {
	panic(errWrap{&err})
}
<commit_msg>internal/errors: add license header<commit_after>// Copyright 2016, Joe Tsai. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file.

// Package errors implements functions to manipulate compression errors.
//
// In idiomatic Go, it is an anti-pattern to use panics as a form of error
// reporting in the API. Instead, the expected way to transmit errors is by
// returning an error value. Unfortunately, the checking of "err != nil" in
// tight loops commonly found in compression causes non-negligible performance
// degradation. While this may not be idiomatic, the internal packages of this
// repository rely on panics as a normal means to convey errors. In order to
// ensure that these panics do not leak across the public API, the public
// packages must recover from these panics and present an error value.
//
// The Panic and Recover functions in this package provide a safe way to
// recover from errors only generated from within this repository.
//
// Example usage:
//	func Foo() (err error) {
//		defer errors.Recover(&err)
//
//		if rand.Intn(2) == 0 {
//			// Unexpected panics will not be caught by Recover.
//			io.Closer(nil).Close()
//		} else {
//			// Errors thrown by Panic will be caught by Recover.
//			errors.Panic(errors.New("whoopsie"))
//		}
//	}
//
package errors

import "strings"

const (
	// Unknown indicates that there is no classification for this error.
	Unknown = iota

	// Internal indicates that this error is due to an internal bug.
	// Users should file a issue report if this type of error is encountered.
	Internal

	// Invalid indicates that this error is due to the user misusing the API
	// and is indicative of a bug on the user's part.
	Invalid

	// Deprecated indicates the use of a deprecated and unsupported feature.
	Deprecated

	// Corrupted indicates that the input stream is corrupted.
	Corrupted

	// Closed indicates that the handlers are closed.
	Closed
)

var codeMap = map[int]string{
	Unknown:    "unknown error",
	Internal:   "internal error",
	Invalid:    "invalid argument",
	Deprecated: "deprecated format",
	Corrupted:  "corrupted input",
	Closed:     "closed handler",
}

type Error struct {
	Code int    // The error type
	Pkg  string // Name of the package where the error originated
	Msg  string // Descriptive message about the error (optional)
}

func (e Error) Error() string {
	var ss []string
	for _, s := range []string{e.Pkg, codeMap[e.Code], e.Msg} {
		if s != "" {
			ss = append(ss, s)
		}
	}
	return strings.Join(ss, ": ")
}

func (e Error) CompressError()     {}
func (e Error) IsInternal() bool   { return e.Code == Internal }
func (e Error) IsInvalid() bool    { return e.Code == Invalid }
func (e Error) IsDeprecated() bool { return e.Code == Deprecated }
func (e Error) IsCorrupted() bool  { return e.Code == Corrupted }
func (e Error) IsClosed() bool     { return e.Code == Closed }

func IsInternal(err error) bool   { return isCode(err, Internal) }
func IsInvalid(err error) bool    { return isCode(err, Invalid) }
func IsDeprecated(err error) bool { return isCode(err, Deprecated) }
func IsCorrupted(err error) bool  { return isCode(err, Corrupted) }
func IsClosed(err error) bool     { return isCode(err, Closed) }

func isCode(err error, code int) bool {
	if cerr, ok := err.(Error); ok && cerr.Code == code {
		return true
	}
	return false
}

// errWrap is used by Panic and Recover to ensure that only errors raised by
// Panic are recovered by Recover.
type errWrap struct{ e *error }

func Recover(err *error) {
	switch ex := recover().(type) {
	case nil:
		// Do nothing.
	case errWrap:
		*err = *ex.e
	default:
		panic(ex)
	}
}

func Panic(err error) {
	panic(errWrap{&err})
}
<|endoftext|>


<commit_before>package helper

import (
	"context"
	"crypto/tls"
	"crypto/x509"
	"errors"
	"io/ioutil"
	"net/http"
	"strings"

	"github.com/micro/cli"
	"github.com/micro/go-micro/metadata"
)

func ACMEHosts(ctx *cli.Context) []string {
	var hosts []string
	for _, host := range strings.Split(ctx.String("acme_hosts"), ",") {
		if len(host) > 0 {
			hosts = append(hosts, host)
		}
	}
	return hosts
}

func RequestToContext(r *http.Request) context.Context {
	ctx := context.Background()
	md := make(metadata.Metadata)
	for k, v := range r.Header {
		md[k] = strings.Join(v, ",")
	}
	return metadata.NewContext(ctx, md)
}

func TLSConfig(ctx *cli.Context) (*tls.Config, error) {
	cert := ctx.GlobalString("tls_cert_file")
	key := ctx.GlobalString("tls_key_file")
	ca := ctx.GlobalString("tls_client_ca_file")

	if len(cert) > 0 && len(key) > 0 {
		certs, err := tls.LoadX509KeyPair(cert, key)
		if err != nil {
			return nil, err
		}

		if len(ca) > 0 {
			caCert, err := ioutil.ReadFile(ca)
			if err != nil {
				return nil, err
			}

			caCertPool := x509.NewCertPool()
			caCertPool.AppendCertsFromPEM(caCert)

			return &tls.Config{
				Certificates: []tls.Certificate{certs},
				ClientCAs:    caCertPool,
				ClientAuth:   tls.RequireAndVerifyClientCert,
			}, nil
		}

		return &tls.Config{
			Certificates: []tls.Certificate{certs}, NextProtos: []string{"h2", "http/1.1"},
		}, nil
	}

	return nil, errors.New("TLS certificate and key files not specified")
}
<commit_msg>Update helper.go<commit_after>package helper

import (
	"context"
	"crypto/tls"
	"crypto/x509"
	"errors"
	"io/ioutil"
	"net/http"
	"strings"

	"github.com/micro/cli"
	"github.com/micro/go-micro/metadata"
)

func ACMEHosts(ctx *cli.Context) []string {
	var hosts []string
	for _, host := range strings.Split(ctx.String("acme_hosts"), ",") {
		if len(host) > 0 {
			hosts = append(hosts, host)
		}
	}
	return hosts
}

func RequestToContext(r *http.Request) context.Context {
	ctx := context.Background()
	md := make(metadata.Metadata)
	for k, v := range r.Header {
		md[k] = strings.Join(v, ",")
	}
	return metadata.NewContext(ctx, md)
}

func TLSConfig(ctx *cli.Context) (*tls.Config, error) {
	cert := ctx.GlobalString("tls_cert_file")
	key := ctx.GlobalString("tls_key_file")
	ca := ctx.GlobalString("tls_client_ca_file")

	if len(cert) > 0 && len(key) > 0 {
		certs, err := tls.LoadX509KeyPair(cert, key)
		if err != nil {
			return nil, err
		}

		if len(ca) > 0 {
			caCert, err := ioutil.ReadFile(ca)
			if err != nil {
				return nil, err
			}

			caCertPool := x509.NewCertPool()
			caCertPool.AppendCertsFromPEM(caCert)

			return &tls.Config{
				Certificates: []tls.Certificate{certs},
				ClientCAs:    caCertPool,
				ClientAuth:   tls.RequireAndVerifyClientCert,
				NextProtos: []string{"h2", "http/1.1"},
			}, nil
		}

		return &tls.Config{
			Certificates: []tls.Certificate{certs}, NextProtos: []string{"h2", "http/1.1"},
		}, nil
	}

	return nil, errors.New("TLS certificate and key files not specified")
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/exec"
	"strconv"
	"sync"
	"time"

	"github.com/BurntSushi/toml"
	xj "github.com/basgys/goxml2json"
	"github.com/gorilla/websocket"
)

//VERSION of the program
var version = "undefined-autogenerated"

//gobal variable to store all websocket connections for the update
var cons = make(map[*websocket.Conn]bool)

//mutex to lock the NMAP JSON information
var lock = sync.RWMutex{}

var nmapJSON *bytes.Buffer

//just for development
type msg struct {
	Command string
	Num     int
}

//Config data struct to read the config file
type Config struct {
	NMAPRange    string
	NMAPPorts    string //comma separated
	HTTPPort     int
	ScanInterval int //seconds
}

func echo(conn *websocket.Conn) {
	for {
		m := msg{}
		err := conn.ReadJSON(&m)
		if err != nil {
			log.Println("Error reading json.", err)
			break
		}
		lock.RLock()
		if nmapJSON != nil {
			err := conn.WriteMessage(1, nmapJSON.Bytes())
			if err != nil {
				log.Println(err)
				break
			}
		}
		lock.RUnlock()
	}
	delete(cons, conn)
	conn.Close()
}

//ReadConfig reads the config file
func readConfig(configfile string) Config {
	var config Config
	if _, err := toml.DecodeFile(configfile, &config); err != nil {
		log.Fatal(err)
	}
	return config
}

func callNMAP(conf Config) {
	log.Println("Starting nmap caller")
	var counter = 1
	var scanResultsFileName = "scan.xml"

	for {
		cmd := exec.Command("nmap", "-p", conf.NMAPPorts, "-oX", scanResultsFileName, conf.NMAPRange)
		log.Println("Init NMAP scan no:", counter)
		var out bytes.Buffer
		cmd.Stdout = &out
		err := cmd.Run()
		if err != nil {
			log.Println(err)
		}
		log.Println("Scan no.", counter, "complete")
		counter = counter + 1

		//read the xml file, convert to json and send via the websockets
		xmlfile, err := os.Open(scanResultsFileName)
		if err != nil {
			log.Println(err)
		}
		lock.Lock()
		nmapJSON, err = xj.Convert(xmlfile)
		lock.Unlock()
		if err != nil {
			log.Println(err)
		}
		log.Println("Writing to websockets")
		for c := range cons {
			c.WriteMessage(1, nmapJSON.Bytes())
		}
		<-time.After(time.Duration(conf.ScanInterval) * time.Second)
	}
}

func wsHandler(w http.ResponseWriter, r *http.Request) {
	log.Println("Ws request from:", r.Header.Get("Origin"))
	// log.Println("accepted from: http://" + r.Host)
	// if r.Header.Get("Origin") != "http://"+r.Host {
	// 	http.Error(w, "Origin not allowed", 403)
	// 	log.Println("Origin not allowed")
	// 	return
	// }
	conn, err := websocket.Upgrade(w, r, w.Header(), 0, 0)
	if err != nil {
		http.Error(w, "Could not open websocket connection", http.StatusBadRequest)
		log.Println("Upgrade error")
	}

	//add the connection to the pool for broadcast
	cons[conn] = true
	go echo(conn)
}

func main() {
	log.Println("Starting lan-monitor-server ver: " + version)

	//process the config
	//1st the config file is read and set parameters applied
	//2nd the command line parameters are interpreted,
	//if they are set they will overrule the config file
	//3rd if none of the above is applied the program reverts to the hardcoded defaults

	//defaults
	var config Config
	defaultConfigFileLocation := "/etc/lan-monitor.conf"
	config.HTTPPort = 8080
	config.NMAPRange = "192.168.0.1/24"
	config.NMAPPorts = "22,80"
	config.ScanInterval = 120 //seconds

	displayVersion := flag.Bool("version", false, "Prints the version number")
	cmdlineHTTPPort := flag.Int("port", config.HTTPPort, "HTTP port for the webserver")
	cmdlineNMAPScanRange := flag.String("range", config.NMAPRange, "The range NMAP should scan e.g. 192.168.1.1/24 it has to be nmap compatible")
	cmdlineScanInterval := flag.Int("scan-rate", config.ScanInterval, "The interval of the scans in seconds")
	configFileLocation := flag.String("config-file", defaultConfigFileLocation, "Location of the config file")
	cmdlinePorts := flag.String("scan-ports", config.NMAPPorts, "The ports that will be scanned")
	flag.Parse()

	//try to read the configfile
	_, err := os.Stat(*configFileLocation)
	if err == nil {
		config = readConfig(*configFileLocation)
	} else {
		log.Println("Config file is missing - looked at:", *configFileLocation)
		log.Println("Reverting to commandline/defaults")
	}

	//if no range is defined in the config file
	if config.NMAPRange == "" {
		config.NMAPRange = *cmdlineNMAPScanRange
	}

	//if no port is defined in the config file
	if config.HTTPPort == 0 {
		config.HTTPPort = *cmdlineHTTPPort
	}

	//if no scan interval is defined in the config file
	if config.ScanInterval == 0 {
		config.ScanInterval = *cmdlineScanInterval
	}

	//if no ports to be scanned are defined
	if config.NMAPPorts == "" {
		config.NMAPPorts = *cmdlinePorts
	}

	log.Println("Config - range:", config.NMAPRange, "webserver port:", config.HTTPPort, "interval:", config.ScanInterval, "sec", "scan-ports", config.NMAPPorts)

	if *displayVersion == true {
		fmt.Println("Version: " + version)
		return
	}

	workingDir, _ := os.Getwd()
	log.Println("Dir:" + workingDir)

	//init the scanning routine
	go callNMAP(config)

	//starting and configuring the webserver
	fs := http.FileServer(http.Dir(workingDir))
	http.HandleFunc("/ws", wsHandler)
	http.Handle("/", fs)
	listenAddress := ":" + strconv.Itoa(config.HTTPPort)
	log.Fatal(http.ListenAndServe(listenAddress, nil))
}
<commit_msg>change to use JSON as config and create a democonfig<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"strconv"
	"sync"
	"time"

	xj "github.com/basgys/goxml2json"
	"github.com/gorilla/websocket"
)

//VERSION of the program
var version = "undefined-autogenerated"

//gobal variable to store all websocket connections for the update
var cons = make(map[*websocket.Conn]bool)

//mutex to lock the NMAP JSON information
var lock = sync.RWMutex{}

var nmapJSON *bytes.Buffer

//just for development
type msg struct {
	Command string
	Num     int
}

//Config data struct to read the config file
type Config struct {
	NMAPRange    string
	NMAPPorts    string //comma separated
	HTTPPort     int
	ScanInterval int //seconds
}

func echo(conn *websocket.Conn) {
	for {
		m := msg{}
		err := conn.ReadJSON(&m)
		if err != nil {
			log.Println("Error reading json.", err)
			break
		}
		lock.RLock()
		if nmapJSON != nil {
			err := conn.WriteMessage(1, nmapJSON.Bytes())
			if err != nil {
				log.Println(err)
				break
			}
		}
		lock.RUnlock()
	}
	delete(cons, conn)
	conn.Close()
}

//ReadConfig reads the config file
func readConfig(configfile string) Config {
	var config Config
	data, err := ioutil.ReadFile(configfile)
	if err != nil {
		log.Println("Error opening for JSON parsing - reverting to defaults")
	}

	err = json.Unmarshal(data, &config)
	if err != nil {
		log.Println("Error parsing json config:", err)
		log.Println("Continuing with defaults", err)
	}

	return config
}

func callNMAP(conf Config) {
	log.Println("Starting nmap caller")
	var counter = 1
	var scanResultsFileName = "scan.xml"

	for {
		cmd := exec.Command("nmap", "-p", conf.NMAPPorts, "-oX", scanResultsFileName, conf.NMAPRange)
		log.Println("Init NMAP scan no:", counter)
		var out bytes.Buffer
		cmd.Stdout = &out
		err := cmd.Run()
		if err != nil {
			log.Println(err)
		}
		log.Println("Scan no.", counter, "complete")
		counter = counter + 1

		//read the xml file, convert to json and send via the websockets
		xmlfile, err := os.Open(scanResultsFileName)
		if err != nil {
			log.Println(err)
		}
		lock.Lock()
		nmapJSON, err = xj.Convert(xmlfile)
		lock.Unlock()
		if err != nil {
			log.Println(err)
		}
		log.Println("Writing to websockets")
		for c := range cons {
			c.WriteMessage(1, nmapJSON.Bytes())
		}
		<-time.After(time.Duration(conf.ScanInterval) * time.Second)
	}
}

func wsHandler(w http.ResponseWriter, r *http.Request) {
	log.Println("Ws request from:", r.Header.Get("Origin"))
	// log.Println("accepted from: http://" + r.Host)
	// if r.Header.Get("Origin") != "http://"+r.Host {
	// 	http.Error(w, "Origin not allowed", 403)
	// 	log.Println("Origin not allowed")
	// 	return
	// }
	conn, err := websocket.Upgrade(w, r, w.Header(), 0, 0)
	if err != nil {
		http.Error(w, "Could not open websocket connection", http.StatusBadRequest)
		log.Println("Upgrade error")
	}

	//add the connection to the pool for broadcast
	cons[conn] = true
	go echo(conn)
}

func main() {
	log.Println("Starting lan-monitor-server ver: " + version)

	//process the config
	//1st the config file is read and set parameters applied
	//2nd the command line parameters are interpreted,
	//if they are set they will overrule the config file
	//3rd if none of the above is applied the program reverts to the hardcoded defaults

	//defaults
	var config Config
	defaultConfigFileLocation := "/etc/lan-monitor.json"
	config.HTTPPort = 8080
	config.NMAPRange = "192.168.0.1/24"
	config.NMAPPorts = "22,80"
	config.ScanInterval = 120 //seconds

	displayVersion := flag.Bool("version", false, "Prints the version number")
	createExampleConfig := flag.Bool("config", false, "Writes the lan-monitor.json to local dir as example")
	cmdlineHTTPPort := flag.Int("port", config.HTTPPort, "HTTP port for the webserver")
	cmdlineNMAPScanRange := flag.String("range", config.NMAPRange, "The range NMAP should scan e.g. 192.168.1.1/24 it has to be nmap compatible")
	cmdlineScanInterval := flag.Int("scan-rate", config.ScanInterval, "The interval of the scans in seconds")
	configFileLocation := flag.String("config-file", defaultConfigFileLocation, "Location of the config file")
	cmdlinePorts := flag.String("scan-ports", config.NMAPPorts, "The ports that will be scanned")
	flag.Parse()

	//try to read the configfile
	_, err := os.Stat(*configFileLocation)
	if err == nil {
		config = readConfig(*configFileLocation)
	} else {
		log.Println("Config file is missing - looked at:", *configFileLocation)
		log.Println("Reverting to commandline/defaults")
	}

	//if no range is defined in the config file
	if config.NMAPRange == "" {
		config.NMAPRange = *cmdlineNMAPScanRange
	}

	//if no port is defined in the config file
	if config.HTTPPort == 0 {
		config.HTTPPort = *cmdlineHTTPPort
	}

	//if no scan interval is defined in the config file
	if config.ScanInterval == 0 {
		config.ScanInterval = *cmdlineScanInterval
	}

	//if no ports to be scanned are defined
	if config.NMAPPorts == "" {
		config.NMAPPorts = *cmdlinePorts
	}

	log.Println("Config - range:", config.NMAPRange, "webserver port:", config.HTTPPort, "interval:", config.ScanInterval, "sec", "scan-ports", config.NMAPPorts)

	if *displayVersion == true {
		fmt.Println("Version: " + version)
		return
	}

	if *createExampleConfig == true {
		workingDir, _ := os.Getwd()
		fmt.Println("Config in JSON format written to:", workingDir)
		configJSON, _ := json.Marshal(config)
		err := ioutil.WriteFile("lan-monitor.json", configJSON, 0644)
		if err != nil {
			fmt.Println("Error writing demo config file")
		}
		return
	}

	workingDir, _ := os.Getwd()
	log.Println("Dir:" + workingDir)

	//init the scanning routine
	go callNMAP(config)

	//starting and configuring the webserver
	fs := http.FileServer(http.Dir(workingDir))
	http.HandleFunc("/ws", wsHandler)
	http.Handle("/", fs)
	listenAddress := ":" + strconv.Itoa(config.HTTPPort)
	log.Fatal(http.ListenAndServe(listenAddress, nil))
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"net/url"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"

	"golang.org/x/net/context"
)

type (
	CommandConfig struct {
		Template []string            `json:"-"`
		Options  map[string][]string `json:"options,omitempty"`
		Dryrun   bool                `json:"dryrun,omitempty"`
	}

	Job struct {
		config *CommandConfig
		// https://godoc.org/google.golang.org/genproto/googleapis/pubsub/v1#ReceivedMessage
		message      *JobMessage
		notification *ProgressNotification
		storage      Storage

		// These are set at at setupWorkspace
		workspace     string
		downloads_dir string
		uploads_dir   string

		// These are set at setupDownloadFiles
		downloadFileMap     map[string]string
		remoteDownloadFiles interface{}
		localDownloadFiles  interface{}

		cmd *exec.Cmd
	}
)

func (job *Job) run(ctx context.Context) error {
	verr := job.message.Validate()
	if verr != nil {
		log.Printf("Invalid Message: MessageId: %v, Message: %v, error: %v\n", job.message.MessageId(), job.message.raw.Message, verr)
		err := job.withNotify(CANCELLING, job.message.Ack)()
		if err != nil {
			return err
		}
		return nil
	}

	go job.message.sendMADPeriodically()
	defer job.message.Done()

	job.notification.notify(PROCESSING, job.message.MessageId(), "info")

	err := job.setupWorkspace()
	if err != nil {
		return err
	}

	defer job.clearWorkspace()

	err = job.withNotify(PREPARING, job.setupDownloadFiles)()
	if err != nil {
		return err
	}

	err = job.withNotify(DOWNLOADING, job.downloadFiles)()
	if err != nil {
		return err
	}

	err := job.build()
	if err != nil {
		log.Fatalf("Command build Error template: %v msg: %v cause of %v\n", job.config.Template, job.message, err)
		return err
	}

	err = job.withNotify(EXECUTING, job.execute)()
	if err != nil {
		return err
	}

	err = job.withNotify(UPLOADING, job.uploadFiles)()
	if err != nil {
		return err
	}

	err = job.withNotify(ACKSENDING, job.message.Ack)()
	if err != nil {
		return err
	}

	job.notification.notify(CLEANUP, job.message.MessageId(), "info")
	return err
}

func (job *Job) withNotify(progress int, f func() error) func() error {
	msg_id := job.message.MessageId()
	return func() error {
		job.notification.notify(progress, msg_id, "info")
		err := f()
		if err != nil {
			job.notification.notify(progress+2, msg_id, "error")
			return err
		}
		job.notification.notify(progress+1, msg_id, "info")
		return nil
	}
}

func (job *Job) setupWorkspace() error {
	dir, err := ioutil.TempDir("", "workspace")
	if err != nil {
		log.Fatal(err)
		return err
	}

	subdirs := []string{
		filepath.Join(dir, "downloads"),
		filepath.Join(dir, "uploads"),
	}
	for _, subdir := range subdirs {
		err := os.MkdirAll(subdir, 0700)
		if err != nil {
			return err
		}
	}
	job.workspace = dir
	job.downloads_dir = subdirs[0]
	job.uploads_dir = subdirs[1]
	return nil
}

func (job *Job) clearWorkspace() error {
	return os.RemoveAll(job.workspace)
}

func (job *Job) setupDownloadFiles() error {
	job.downloadFileMap = map[string]string{}
	job.remoteDownloadFiles = job.message.DownloadFiles()
	objects := job.flatten(job.remoteDownloadFiles)
	remoteUrls := []string{}
	for _, obj := range objects {
		switch obj.(type) {
		case string:
			remoteUrls = append(remoteUrls, obj.(string))
		default:
			log.Printf("Invalid download file URL: %v [%T]", obj, obj)
		}
	}
	for _, remote_url := range remoteUrls {
		url, err := url.Parse(remote_url)
		if err != nil {
			log.Fatalf("Invalid URL: %v because of %v\n", remote_url, err)
			return err
		}
		urlstr := fmt.Sprintf("gs://%v%v", url.Host, url.Path)
		destPath := filepath.Join(job.downloads_dir, url.Host, url.Path)
		job.downloadFileMap[urlstr] = destPath
	}
	job.localDownloadFiles = job.copyWithFileMap(job.remoteDownloadFiles)
	return nil
}

func (job *Job) copyWithFileMap(obj interface{}) interface{} {
	switch obj.(type) {
	case map[string]interface{}:
		result := map[string]interface{}{}
		for k, v := range obj.(map[string]interface{}) {
			result[k] = job.copyWithFileMap(v)
		}
		return result
	case []interface{}:
		result := []interface{}{}
		for _, v := range obj.([]interface{}) {
			result = append(result, job.copyWithFileMap(v))
		}
		return result
	case string:
		return job.downloadFileMap[obj.(string)]
	default:
		return obj
	}
}

func (job *Job) buildVariable() *Variable {
	return &Variable{
		data: map[string]interface{}{
			"workspace":             job.workspace,
			"downloads_dir":         job.downloads_dir,
			"uploads_dir":           job.uploads_dir,
			"download_files":        job.localDownloadFiles,
			"local_download_files":  job.localDownloadFiles,
			"remote_download_files": job.remoteDownloadFiles,
			"attrs":                 job.message.raw.Message.Attributes,
			"attributes":            job.message.raw.Message.Attributes,
			"data":                  job.message.raw.Message.Data,
		},
	}
}

func (job *Job) build() error {
	v := job.buildVariable()

	values, err := job.extract(v, job.config.Template)
	if err != nil {
		return err
	}
	if len(job.config.Options) > 0 {
		key := strings.Join(values, " ")
		t := job.config.Options[key]
		if t == nil {
			t = job.config.Options["default"]
		}
		if t != nil {
			values, err = job.extract(v, t)
			if err != nil {
				return err
			}
		}
	}
	job.cmd = exec.Command(values[0], values[1:]...)
	return nil
}

func (job *Job) extract(v *Variable, values []string) ([]string, error) {
	result := []string{}
	for _, src := range values {
		extracted, err := v.expand(src)
		if err != nil {
			return nil, err
		}
		vals := strings.Split(extracted, v.separator)
		for _, val := range vals {
			result = append(result, val)
		}
	}
	return result, nil
}

func (job *Job) downloadFiles() error {
	for remoteURL, destPath := range job.downloadFileMap {
		url, err := url.Parse(remoteURL)
		if err != nil {
			log.Fatalf("Invalid URL: %v because of %v\n", remoteURL, err)
			return err
		}

		dir := path.Dir(destPath)
		err = os.MkdirAll(dir, 0700)
		if err != nil {
			return err
		}

		err = job.storage.Download(url.Host, url.Path[1:], destPath)
		if err != nil {
			return err
		}
	}
	return nil
}

func (job *Job) execute() error {
	var out bytes.Buffer
	job.cmd.Stdout = &out
	job.cmd.Stderr = &out
	log.Printf("EXECUTE running: %v\n", job.cmd)
	err = job.cmd.Run()
	if err != nil {
		log.Printf("Command Error: cmd: %v cause of %v\n%v\n", job.cmd, err, out.String())
		return err
	}
	return nil
}

func (job *Job) uploadFiles() error {
	localPaths, err := job.listFiles(job.uploads_dir)
	if err != nil {
		return err
	}
	for _, localPath := range localPaths {
		relPath, err := filepath.Rel(job.uploads_dir, localPath)
		if err != nil {
			log.Fatalf("Error getting relative path of %v: %v\n", localPath, err)
			return err
		}
		sep := string([]rune{os.PathSeparator})
		parts := strings.Split(relPath, sep)
		bucket := parts[0]
		object := strings.Join(parts[1:], sep)
		err = job.storage.Upload(bucket, object, localPath)
		if err != nil {
			log.Fatalf("Error uploading %v to gs://%v/%v: %v\n", localPath, bucket, object, err)
			return err
		}
	}
	return nil
}

func (job *Job) listFiles(dir string) ([]string, error) {
	result := []string{}
	err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		if !info.IsDir() {
			result = append(result, path)
		}
		return nil
	})
	if err != nil {
		log.Fatalf("Error listing upload files: %v\n", err)
		return nil, err
	}
	return result, nil
}

func (job *Job) flatten(obj interface{}) []interface{} {
	// Support only unmarshalled object from JSON
	// See https://golang.org/pkg/encoding/json/#Unmarshal also
	switch obj.(type) {
	case []interface{}:
		res := []interface{}{}
		for _, i := range obj.([]interface{}) {
			switch i.(type) {
			case bool, float64, string, nil:
				res = append(res, i)
			default:
				for _, j := range job.flatten(i) {
					res = append(res, j)
				}
			}
		}
		return res
	case map[string]interface{}:
		values := []interface{}{}
		for _, val := range obj.(map[string]interface{}) {
			values = append(values, val)
		}
		return job.flatten(values)
	default:
		return []interface{}{obj}
	}
}
<commit_msg>:+1: Call build before calling downloadFiles<commit_after>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"net/url"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"

	"golang.org/x/net/context"
)

type (
	CommandConfig struct {
		Template []string            `json:"-"`
		Options  map[string][]string `json:"options,omitempty"`
		Dryrun   bool                `json:"dryrun,omitempty"`
	}

	Job struct {
		config *CommandConfig
		// https://godoc.org/google.golang.org/genproto/googleapis/pubsub/v1#ReceivedMessage
		message      *JobMessage
		notification *ProgressNotification
		storage      Storage

		// These are set at at setupWorkspace
		workspace     string
		downloads_dir string
		uploads_dir   string

		// These are set at setupDownloadFiles
		downloadFileMap     map[string]string
		remoteDownloadFiles interface{}
		localDownloadFiles  interface{}

		cmd *exec.Cmd
	}
)

func (job *Job) run(ctx context.Context) error {
	verr := job.message.Validate()
	if verr != nil {
		log.Printf("Invalid Message: MessageId: %v, Message: %v, error: %v\n", job.message.MessageId(), job.message.raw.Message, verr)
		err := job.withNotify(CANCELLING, job.message.Ack)()
		if err != nil {
			return err
		}
		return nil
	}

	go job.message.sendMADPeriodically()
	defer job.message.Done()

	job.notification.notify(PROCESSING, job.message.MessageId(), "info")

	err := job.setupWorkspace()
	if err != nil {
		return err
	}

	defer job.clearWorkspace()

	err = job.withNotify(PREPARING, job.setupDownloadFiles)()
	if err != nil {
		return err
	}

	err := job.build()
	if err != nil {
		log.Fatalf("Command build Error template: %v msg: %v cause of %v\n", job.config.Template, job.message, err)
		return err
	}

	err = job.withNotify(DOWNLOADING, job.downloadFiles)()
	if err != nil {
		return err
	}

	err = job.withNotify(EXECUTING, job.execute)()
	if err != nil {
		return err
	}

	err = job.withNotify(UPLOADING, job.uploadFiles)()
	if err != nil {
		return err
	}

	err = job.withNotify(ACKSENDING, job.message.Ack)()
	if err != nil {
		return err
	}

	job.notification.notify(CLEANUP, job.message.MessageId(), "info")
	return err
}

func (job *Job) withNotify(progress int, f func() error) func() error {
	msg_id := job.message.MessageId()
	return func() error {
		job.notification.notify(progress, msg_id, "info")
		err := f()
		if err != nil {
			job.notification.notify(progress+2, msg_id, "error")
			return err
		}
		job.notification.notify(progress+1, msg_id, "info")
		return nil
	}
}

func (job *Job) setupWorkspace() error {
	dir, err := ioutil.TempDir("", "workspace")
	if err != nil {
		log.Fatal(err)
		return err
	}

	subdirs := []string{
		filepath.Join(dir, "downloads"),
		filepath.Join(dir, "uploads"),
	}
	for _, subdir := range subdirs {
		err := os.MkdirAll(subdir, 0700)
		if err != nil {
			return err
		}
	}
	job.workspace = dir
	job.downloads_dir = subdirs[0]
	job.uploads_dir = subdirs[1]
	return nil
}

func (job *Job) clearWorkspace() error {
	return os.RemoveAll(job.workspace)
}

func (job *Job) setupDownloadFiles() error {
	job.downloadFileMap = map[string]string{}
	job.remoteDownloadFiles = job.message.DownloadFiles()
	objects := job.flatten(job.remoteDownloadFiles)
	remoteUrls := []string{}
	for _, obj := range objects {
		switch obj.(type) {
		case string:
			remoteUrls = append(remoteUrls, obj.(string))
		default:
			log.Printf("Invalid download file URL: %v [%T]", obj, obj)
		}
	}
	for _, remote_url := range remoteUrls {
		url, err := url.Parse(remote_url)
		if err != nil {
			log.Fatalf("Invalid URL: %v because of %v\n", remote_url, err)
			return err
		}
		urlstr := fmt.Sprintf("gs://%v%v", url.Host, url.Path)
		destPath := filepath.Join(job.downloads_dir, url.Host, url.Path)
		job.downloadFileMap[urlstr] = destPath
	}
	job.localDownloadFiles = job.copyWithFileMap(job.remoteDownloadFiles)
	return nil
}

func (job *Job) copyWithFileMap(obj interface{}) interface{} {
	switch obj.(type) {
	case map[string]interface{}:
		result := map[string]interface{}{}
		for k, v := range obj.(map[string]interface{}) {
			result[k] = job.copyWithFileMap(v)
		}
		return result
	case []interface{}:
		result := []interface{}{}
		for _, v := range obj.([]interface{}) {
			result = append(result, job.copyWithFileMap(v))
		}
		return result
	case string:
		return job.downloadFileMap[obj.(string)]
	default:
		return obj
	}
}

func (job *Job) buildVariable() *Variable {
	return &Variable{
		data: map[string]interface{}{
			"workspace":             job.workspace,
			"downloads_dir":         job.downloads_dir,
			"uploads_dir":           job.uploads_dir,
			"download_files":        job.localDownloadFiles,
			"local_download_files":  job.localDownloadFiles,
			"remote_download_files": job.remoteDownloadFiles,
			"attrs":                 job.message.raw.Message.Attributes,
			"attributes":            job.message.raw.Message.Attributes,
			"data":                  job.message.raw.Message.Data,
		},
	}
}

func (job *Job) build() error {
	v := job.buildVariable()

	values, err := job.extract(v, job.config.Template)
	if err != nil {
		return err
	}
	if len(job.config.Options) > 0 {
		key := strings.Join(values, " ")
		t := job.config.Options[key]
		if t == nil {
			t = job.config.Options["default"]
		}
		if t != nil {
			values, err = job.extract(v, t)
			if err != nil {
				return err
			}
		}
	}
	job.cmd = exec.Command(values[0], values[1:]...)
	return nil
}

func (job *Job) extract(v *Variable, values []string) ([]string, error) {
	result := []string{}
	for _, src := range values {
		extracted, err := v.expand(src)
		if err != nil {
			return nil, err
		}
		vals := strings.Split(extracted, v.separator)
		for _, val := range vals {
			result = append(result, val)
		}
	}
	return result, nil
}

func (job *Job) downloadFiles() error {
	for remoteURL, destPath := range job.downloadFileMap {
		url, err := url.Parse(remoteURL)
		if err != nil {
			log.Fatalf("Invalid URL: %v because of %v\n", remoteURL, err)
			return err
		}

		dir := path.Dir(destPath)
		err = os.MkdirAll(dir, 0700)
		if err != nil {
			return err
		}

		err = job.storage.Download(url.Host, url.Path[1:], destPath)
		if err != nil {
			return err
		}
	}
	return nil
}

func (job *Job) execute() error {
	var out bytes.Buffer
	job.cmd.Stdout = &out
	job.cmd.Stderr = &out
	log.Printf("EXECUTE running: %v\n", job.cmd)
	err = job.cmd.Run()
	if err != nil {
		log.Printf("Command Error: cmd: %v cause of %v\n%v\n", job.cmd, err, out.String())
		return err
	}
	return nil
}

func (job *Job) uploadFiles() error {
	localPaths, err := job.listFiles(job.uploads_dir)
	if err != nil {
		return err
	}
	for _, localPath := range localPaths {
		relPath, err := filepath.Rel(job.uploads_dir, localPath)
		if err != nil {
			log.Fatalf("Error getting relative path of %v: %v\n", localPath, err)
			return err
		}
		sep := string([]rune{os.PathSeparator})
		parts := strings.Split(relPath, sep)
		bucket := parts[0]
		object := strings.Join(parts[1:], sep)
		err = job.storage.Upload(bucket, object, localPath)
		if err != nil {
			log.Fatalf("Error uploading %v to gs://%v/%v: %v\n", localPath, bucket, object, err)
			return err
		}
	}
	return nil
}

func (job *Job) listFiles(dir string) ([]string, error) {
	result := []string{}
	err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		if !info.IsDir() {
			result = append(result, path)
		}
		return nil
	})
	if err != nil {
		log.Fatalf("Error listing upload files: %v\n", err)
		return nil, err
	}
	return result, nil
}

func (job *Job) flatten(obj interface{}) []interface{} {
	// Support only unmarshalled object from JSON
	// See https://golang.org/pkg/encoding/json/#Unmarshal also
	switch obj.(type) {
	case []interface{}:
		res := []interface{}{}
		for _, i := range obj.([]interface{}) {
			switch i.(type) {
			case bool, float64, string, nil:
				res = append(res, i)
			default:
				for _, j := range job.flatten(i) {
					res = append(res, j)
				}
			}
		}
		return res
	case map[string]interface{}:
		values := []interface{}{}
		for _, val := range obj.(map[string]interface{}) {
			values = append(values, val)
		}
		return job.flatten(values)
	default:
		return []interface{}{obj}
	}
}
<|endoftext|>


<commit_before>package discovery

import (
	"context"
	"math/rand"
	"net/url"
	"strings"
	"sync"
	"time"

	"github.com/livepeer/go-livepeer/core"
	"github.com/livepeer/go-livepeer/net"
	"github.com/livepeer/go-livepeer/server"

	"github.com/golang/glog"
)

const GetOrchestratorsTimeoutLoop = 1 * time.Hour

type orchestratorPool struct {
	uris  []*url.URL
	bcast server.Broadcaster
}

var perm = func(len int) []int { return rand.Perm(len) }

func NewOrchestratorPool(node *core.LivepeerNode, addresses []string) *orchestratorPool {
	var uris []*url.URL

	for _, addr := range addresses {
		if !strings.HasPrefix(addr, "http") {
			addr = "https://" + addr
		}
		uri, err := url.ParseRequestURI(addr)
		if err != nil {
			glog.Error("Could not parse orchestrator URI: ", err)
			continue
		}
		uris = append(uris, uri)
	}

	if len(uris) <= 0 {
		glog.Error("Could not parse orchAddresses given - no URIs returned ")
	}

	var randomizedUris []*url.URL
	for _, i := range perm(len(uris)) {
		uri := uris[i]
		randomizedUris = append(randomizedUris, uri)
	}

	bcast := core.NewBroadcaster(node)
	return &orchestratorPool{bcast: bcast, uris: randomizedUris}
}

func NewOnchainOrchestratorPool(node *core.LivepeerNode) *orchestratorPool {
	// if livepeer running in offchain mode, return nil
	if node.Eth == nil {
		glog.Error("Could not refresh DB list of orchestrators: LivepeerNode nil")
		return nil
	}

	orchestrators, err := node.Eth.RegisteredTranscoders()
	if err != nil {
		glog.Error("Could not refresh DB list of orchestrators: ", err)
		return nil
	}

	var addresses []string
	for _, orch := range orchestrators {
		addresses = append(addresses, orch.ServiceURI)
	}

	return NewOrchestratorPool(node, addresses)
}

func (o *orchestratorPool) GetOrchestrators(numOrchestrators int) ([]*net.OrchestratorInfo, error) {
	ctx, cancel := context.WithTimeout(context.Background(), GetOrchestratorsTimeoutLoop)
	orchInfos := []*net.OrchestratorInfo{}
	orchChan := make(chan struct{})
	numResp := 0
	numSuccessResp := 0
	respLock := sync.Mutex{}

	getOrchInfo := func(uri *url.URL) {
		info, err := server.GetOrchestratorInfo(ctx, o.bcast, uri)
		respLock.Lock()
		defer respLock.Unlock()
		numResp++
		if err == nil {
			orchInfos = append(orchInfos, info)
			numSuccessResp++
		}
		if numSuccessResp >= numOrchestrators || numResp >= len(o.uris) {
			orchChan <- struct{}{}
		}
	}

	for _, uri := range o.uris {
		go getOrchInfo(uri)
	}

	select {
	case <-ctx.Done():
		respLock.Lock()
		returnOrchs := orchInfos[:numOrchestrators]
		respLock.Unlock()
		glog.Info("Done fetching orch info for orchestrators, context timeout: ", returnOrchs)
		cancel()
		return returnOrchs, nil
	case <-orchChan:
		respLock.Lock()
		returnOrchs := orchInfos[:numOrchestrators]
		respLock.Unlock()
		glog.Info("Done fetching orch info for orchestrators, numResponses fetched: ", returnOrchs)
		cancel()
		return returnOrchs, nil
	}
}
<commit_msg>Fix 'slice bounds out of range' panic.<commit_after>package discovery

import (
	"context"
	"math/rand"
	"net/url"
	"strings"
	"sync"
	"time"

	"github.com/livepeer/go-livepeer/core"
	"github.com/livepeer/go-livepeer/net"
	"github.com/livepeer/go-livepeer/server"

	"github.com/golang/glog"
)

const GetOrchestratorsTimeoutLoop = 1 * time.Hour

type orchestratorPool struct {
	uris  []*url.URL
	bcast server.Broadcaster
}

var perm = func(len int) []int { return rand.Perm(len) }

func NewOrchestratorPool(node *core.LivepeerNode, addresses []string) *orchestratorPool {
	var uris []*url.URL

	for _, addr := range addresses {
		if !strings.HasPrefix(addr, "http") {
			addr = "https://" + addr
		}
		uri, err := url.ParseRequestURI(addr)
		if err != nil {
			glog.Error("Could not parse orchestrator URI: ", err)
			continue
		}
		uris = append(uris, uri)
	}

	if len(uris) <= 0 {
		glog.Error("Could not parse orchAddresses given - no URIs returned ")
	}

	var randomizedUris []*url.URL
	for _, i := range perm(len(uris)) {
		uri := uris[i]
		randomizedUris = append(randomizedUris, uri)
	}

	bcast := core.NewBroadcaster(node)
	return &orchestratorPool{bcast: bcast, uris: randomizedUris}
}

func NewOnchainOrchestratorPool(node *core.LivepeerNode) *orchestratorPool {
	// if livepeer running in offchain mode, return nil
	if node.Eth == nil {
		glog.Error("Could not refresh DB list of orchestrators: LivepeerNode nil")
		return nil
	}

	orchestrators, err := node.Eth.RegisteredTranscoders()
	if err != nil {
		glog.Error("Could not refresh DB list of orchestrators: ", err)
		return nil
	}

	var addresses []string
	for _, orch := range orchestrators {
		addresses = append(addresses, orch.ServiceURI)
	}

	return NewOrchestratorPool(node, addresses)
}

func (o *orchestratorPool) GetOrchestrators(numOrchestrators int) ([]*net.OrchestratorInfo, error) {
	ctx, cancel := context.WithTimeout(context.Background(), GetOrchestratorsTimeoutLoop)
	orchInfos := []*net.OrchestratorInfo{}
	orchChan := make(chan struct{})
	numResp := 0
	numSuccessResp := 0
	respLock := sync.Mutex{}

	getOrchInfo := func(uri *url.URL) {
		info, err := server.GetOrchestratorInfo(ctx, o.bcast, uri)
		respLock.Lock()
		defer respLock.Unlock()
		numResp++
		if err == nil {
			orchInfos = append(orchInfos, info)
			numSuccessResp++
		}
		if numSuccessResp >= numOrchestrators || numResp >= len(o.uris) {
			orchChan <- struct{}{}
		}
	}

	for _, uri := range o.uris {
		go getOrchInfo(uri)
	}

	select {
	case <-ctx.Done():
		respLock.Lock()
		if len(orchInfos) < numOrchestrators {
			numOrchestrators = len(orchInfos)
		}
		returnOrchs := orchInfos[:numOrchestrators]
		respLock.Unlock()
		glog.Info("Done fetching orch info for orchestrators, context timeout: ", returnOrchs)
		cancel()
		return returnOrchs, nil
	case <-orchChan:
		respLock.Lock()
		if len(orchInfos) < numOrchestrators {
			numOrchestrators = len(orchInfos)
		}
		returnOrchs := orchInfos[:numOrchestrators]
		respLock.Unlock()
		glog.Info("Done fetching orch info for orchestrators, numResponses fetched: ", returnOrchs)
		cancel()
		return returnOrchs, nil
	}
}
<|endoftext|>


<commit_before>// Package zerolog provides a lightweight logging library dedicated to JSON logging.
//
// A global Logger can be use for simple logging:
//
//     import "github.com/rs/zerolog/log"
//
//     log.Info().Msg("hello world")
//     // Output: {"time":1494567715,"level":"info","message":"hello world"}
//
// NOTE: To import the global logger, import the "log" subpackage "github.com/rs/zerolog/log".
//
// Fields can be added to log messages:
//
//     log.Info().Str("foo", "bar").Msg("hello world")
//     // Output: {"time":1494567715,"level":"info","message":"hello world","foo":"bar"}
//
// Create logger instance to manage different outputs:
//
//     logger := zerolog.New(os.Stderr).With().Timestamp().Logger()
//     logger.Info().
//            Str("foo", "bar").
//            Msg("hello world")
//     // Output: {"time":1494567715,"level":"info","message":"hello world","foo":"bar"}
//
// Sub-loggers let you chain loggers with additional context:
//
//     sublogger := log.With().Str("component": "foo").Logger()
//     sublogger.Info().Msg("hello world")
//     // Output: {"time":1494567715,"level":"info","message":"hello world","component":"foo"}
//
// Level logging
//
//     zerolog.SetGlobalLevel(zerolog.InfoLevel)
//
//     log.Debug().Msg("filtered out message")
//     log.Info().Msg("routed message")
//
//     if e := log.Debug(); e.Enabled() {
//         // Compute log output only if enabled.
//         value := compute()
//         e.Str("foo": value).Msg("some debug message")
//     }
//     // Output: {"level":"info","time":1494567715,"routed message"}
//
// Customize automatic field names:
//
//     log.TimestampFieldName = "t"
//     log.LevelFieldName = "p"
//     log.MessageFieldName = "m"
//
//     log.Info().Msg("hello world")
//     // Output: {"t":1494567715,"p":"info","m":"hello world"}
//
// Log with no level and message:
//
//     log.Log().Str("foo","bar").Msg("")
//     // Output: {"time":1494567715,"foo":"bar"}
//
// Add contextual fields to global Logger:
//
//     log.Logger = log.With().Str("foo", "bar").Logger()
//
// Sample logs:
//
//     sampled := log.Sample(10)
//     sampled.Info().Msg("will be logged every 10 messages")
//
package zerolog

import (
	"io"
	"os"
	"sync/atomic"
)

type parentLogger interface {
	addContextField(Event)
}

// Level defines log levels.
type Level uint8

const (
	// DebugLevel defines debug log level.
	DebugLevel Level = iota
	// InfoLevel defines info log level.
	InfoLevel
	// WarnLevel defines warn log level.
	WarnLevel
	// ErrorLevel defines error log level.
	ErrorLevel
	// FatalLevel defines fatal log level.
	FatalLevel
	// PanicLevel defines panic log level.
	PanicLevel
	// Disabled disables the logger.
	Disabled
)

func (l Level) String() string {
	switch l {
	case DebugLevel:
		return "debug"
	case InfoLevel:
		return "info"
	case WarnLevel:
		return "warning"
	case ErrorLevel:
		return "error"
	case FatalLevel:
		return "fatal"
	case PanicLevel:
		return "panic"
	}
	return ""
}

const (
	// Often samples log every 10 events.
	Often = int64(10)
	// Sometimes samples log every 100 events.
	Sometimes = int64(100)
	// Rarely samples log every 1000 events.
	Rarely = int64(1000)
)

// A Logger represents an active logging object that generates lines
// of JSON output to an io.Writer. Each logging operation makes a single
// call to the Writer's Write method. There is no guaranty on access
// serialization to the Writer. If your Writer is not thread safe,
// you may consider a sync wrapper.
type Logger struct {
	root    bool
	parent  parentLogger
	w       LevelWriter
	field   field
	level   Level
	sample  uint32
	counter *uint32
}

// New creates a root logger with given output writer. If the output writer implements
// the LevelWriter interface, the WriteLevel method will be called instead of the Write
// one.
//
// Each logging operation makes a single call to the Writer's Write method. There is no
// guaranty on access serialization to the Writer. If your Writer is not thread safe,
// you may consider using sync wrapper.
func New(w io.Writer) Logger {
	if w == nil {
		panic("w is nil")
	}
	lw, ok := w.(LevelWriter)
	if !ok {
		lw = levelWriterAdapter{w}
	}
	return Logger{
		root: true,
		w:    lw,
	}
}

// With creates a child logger with the field added to its context.
func (l Logger) With() Context {
	return Context{l}
}

// Level crestes a child logger with the minium accepted level set to level.
func (l Logger) Level(lvl Level) Logger {
	return Logger{
		parent:  l,
		w:       l.w,
		level:   lvl,
		sample:  l.sample,
		counter: l.counter,
	}
}

// Sample returns a logger that only let one message out of every to pass thru.
func (l Logger) Sample(every int) Logger {
	if every == 0 {
		// Create a child with no sampling.
		return Logger{
			parent: l,
			w:      l.w,
			level:  l.level,
		}
	}
	return Logger{
		parent:  l,
		w:       l.w,
		level:   l.level,
		sample:  uint32(every),
		counter: new(uint32),
	}
}

// Debug starts a new message with debug level.
//
// You must call Msg on the returned event in order to send the event.
func (l Logger) Debug() Event {
	return l.newEvent(DebugLevel, true, nil)
}

// Info starts a new message with info level.
//
// You must call Msg on the returned event in order to send the event.
func (l Logger) Info() Event {
	return l.newEvent(InfoLevel, true, nil)
}

// Warn starts a new message with warn level.
//
// You must call Msg on the returned event in order to send the event.
func (l Logger) Warn() Event {
	return l.newEvent(WarnLevel, true, nil)
}

// Error starts a new message with error level.
//
// You must call Msg on the returned event in order to send the event.
func (l Logger) Error() Event {
	return l.newEvent(ErrorLevel, true, nil)
}

// Fatal starts a new message with fatal level. The os.Exit(1) function
// is called by the Msg method.
//
// You must call Msg on the returned event in order to send the event.
func (l Logger) Fatal() Event {
	return l.newEvent(FatalLevel, true, func(msg string) { os.Exit(1) })
}

// Panic starts a new message with panic level. The message is also sent
// to the panic function.
//
// You must call Msg on the returned event in order to send the event.
func (l Logger) Panic() Event {
	return l.newEvent(PanicLevel, true, func(msg string) { panic(msg) })
}

// Log starts a new message with no level. Setting GlobalLevel to Disabled
// will still disable events produced by this method.
//
// You must call Msg on the returned event in order to send the event.
func (l Logger) Log() Event {
	return l.newEvent(ErrorLevel, false, nil)
}

func (l Logger) newEvent(level Level, addLevelField bool, done func(string)) Event {
	lvl := InfoLevel
	if addLevelField {
		lvl = level
	}
	e := newEvent(l.w, lvl, l.should(level))
	if addLevelField {
		e.Str(LevelFieldName, level.String())
	}
	if l.sample > 0 && SampleFieldName != "" {
		e.Uint32(SampleFieldName, l.sample)
	}
	l.addContextField(e)
	return e
}

// should returns true if the log event should be logged.
func (l Logger) should(lvl Level) bool {
	if lvl < l.level || lvl < globalLevel() {
		return false
	}
	if l.sample > 0 && l.counter != nil && !samplingDisabled() {
		c := atomic.AddUint32(l.counter, 1)
		return c%l.sample == 0
	}
	return true
}

func (l Logger) addContextField(e Event) {
	if !l.root {
		l.parent.addContextField(e)
	}
	if l.field.mode != zeroFieldMode {
		e.append(l.field)
	}
}
<commit_msg>Fix sample template types<commit_after>// Package zerolog provides a lightweight logging library dedicated to JSON logging.
//
// A global Logger can be use for simple logging:
//
//     import "github.com/rs/zerolog/log"
//
//     log.Info().Msg("hello world")
//     // Output: {"time":1494567715,"level":"info","message":"hello world"}
//
// NOTE: To import the global logger, import the "log" subpackage "github.com/rs/zerolog/log".
//
// Fields can be added to log messages:
//
//     log.Info().Str("foo", "bar").Msg("hello world")
//     // Output: {"time":1494567715,"level":"info","message":"hello world","foo":"bar"}
//
// Create logger instance to manage different outputs:
//
//     logger := zerolog.New(os.Stderr).With().Timestamp().Logger()
//     logger.Info().
//            Str("foo", "bar").
//            Msg("hello world")
//     // Output: {"time":1494567715,"level":"info","message":"hello world","foo":"bar"}
//
// Sub-loggers let you chain loggers with additional context:
//
//     sublogger := log.With().Str("component": "foo").Logger()
//     sublogger.Info().Msg("hello world")
//     // Output: {"time":1494567715,"level":"info","message":"hello world","component":"foo"}
//
// Level logging
//
//     zerolog.SetGlobalLevel(zerolog.InfoLevel)
//
//     log.Debug().Msg("filtered out message")
//     log.Info().Msg("routed message")
//
//     if e := log.Debug(); e.Enabled() {
//         // Compute log output only if enabled.
//         value := compute()
//         e.Str("foo": value).Msg("some debug message")
//     }
//     // Output: {"level":"info","time":1494567715,"routed message"}
//
// Customize automatic field names:
//
//     log.TimestampFieldName = "t"
//     log.LevelFieldName = "p"
//     log.MessageFieldName = "m"
//
//     log.Info().Msg("hello world")
//     // Output: {"t":1494567715,"p":"info","m":"hello world"}
//
// Log with no level and message:
//
//     log.Log().Str("foo","bar").Msg("")
//     // Output: {"time":1494567715,"foo":"bar"}
//
// Add contextual fields to global Logger:
//
//     log.Logger = log.With().Str("foo", "bar").Logger()
//
// Sample logs:
//
//     sampled := log.Sample(10)
//     sampled.Info().Msg("will be logged every 10 messages")
//
package zerolog

import (
	"io"
	"os"
	"sync/atomic"
)

type parentLogger interface {
	addContextField(Event)
}

// Level defines log levels.
type Level uint8

const (
	// DebugLevel defines debug log level.
	DebugLevel Level = iota
	// InfoLevel defines info log level.
	InfoLevel
	// WarnLevel defines warn log level.
	WarnLevel
	// ErrorLevel defines error log level.
	ErrorLevel
	// FatalLevel defines fatal log level.
	FatalLevel
	// PanicLevel defines panic log level.
	PanicLevel
	// Disabled disables the logger.
	Disabled
)

func (l Level) String() string {
	switch l {
	case DebugLevel:
		return "debug"
	case InfoLevel:
		return "info"
	case WarnLevel:
		return "warning"
	case ErrorLevel:
		return "error"
	case FatalLevel:
		return "fatal"
	case PanicLevel:
		return "panic"
	}
	return ""
}

const (
	// Often samples log every 10 events.
	Often = 10
	// Sometimes samples log every 100 events.
	Sometimes = 100
	// Rarely samples log every 1000 events.
	Rarely = 1000
)

// A Logger represents an active logging object that generates lines
// of JSON output to an io.Writer. Each logging operation makes a single
// call to the Writer's Write method. There is no guaranty on access
// serialization to the Writer. If your Writer is not thread safe,
// you may consider a sync wrapper.
type Logger struct {
	root    bool
	parent  parentLogger
	w       LevelWriter
	field   field
	level   Level
	sample  uint32
	counter *uint32
}

// New creates a root logger with given output writer. If the output writer implements
// the LevelWriter interface, the WriteLevel method will be called instead of the Write
// one.
//
// Each logging operation makes a single call to the Writer's Write method. There is no
// guaranty on access serialization to the Writer. If your Writer is not thread safe,
// you may consider using sync wrapper.
func New(w io.Writer) Logger {
	if w == nil {
		panic("w is nil")
	}
	lw, ok := w.(LevelWriter)
	if !ok {
		lw = levelWriterAdapter{w}
	}
	return Logger{
		root: true,
		w:    lw,
	}
}

// With creates a child logger with the field added to its context.
func (l Logger) With() Context {
	return Context{l}
}

// Level crestes a child logger with the minium accepted level set to level.
func (l Logger) Level(lvl Level) Logger {
	return Logger{
		parent:  l,
		w:       l.w,
		level:   lvl,
		sample:  l.sample,
		counter: l.counter,
	}
}

// Sample returns a logger that only let one message out of every to pass thru.
func (l Logger) Sample(every int) Logger {
	if every == 0 {
		// Create a child with no sampling.
		return Logger{
			parent: l,
			w:      l.w,
			level:  l.level,
		}
	}
	return Logger{
		parent:  l,
		w:       l.w,
		level:   l.level,
		sample:  uint32(every),
		counter: new(uint32),
	}
}

// Debug starts a new message with debug level.
//
// You must call Msg on the returned event in order to send the event.
func (l Logger) Debug() Event {
	return l.newEvent(DebugLevel, true, nil)
}

// Info starts a new message with info level.
//
// You must call Msg on the returned event in order to send the event.
func (l Logger) Info() Event {
	return l.newEvent(InfoLevel, true, nil)
}

// Warn starts a new message with warn level.
//
// You must call Msg on the returned event in order to send the event.
func (l Logger) Warn() Event {
	return l.newEvent(WarnLevel, true, nil)
}

// Error starts a new message with error level.
//
// You must call Msg on the returned event in order to send the event.
func (l Logger) Error() Event {
	return l.newEvent(ErrorLevel, true, nil)
}

// Fatal starts a new message with fatal level. The os.Exit(1) function
// is called by the Msg method.
//
// You must call Msg on the returned event in order to send the event.
func (l Logger) Fatal() Event {
	return l.newEvent(FatalLevel, true, func(msg string) { os.Exit(1) })
}

// Panic starts a new message with panic level. The message is also sent
// to the panic function.
//
// You must call Msg on the returned event in order to send the event.
func (l Logger) Panic() Event {
	return l.newEvent(PanicLevel, true, func(msg string) { panic(msg) })
}

// Log starts a new message with no level. Setting GlobalLevel to Disabled
// will still disable events produced by this method.
//
// You must call Msg on the returned event in order to send the event.
func (l Logger) Log() Event {
	return l.newEvent(ErrorLevel, false, nil)
}

func (l Logger) newEvent(level Level, addLevelField bool, done func(string)) Event {
	lvl := InfoLevel
	if addLevelField {
		lvl = level
	}
	e := newEvent(l.w, lvl, l.should(level))
	if addLevelField {
		e.Str(LevelFieldName, level.String())
	}
	if l.sample > 0 && SampleFieldName != "" {
		e.Uint32(SampleFieldName, l.sample)
	}
	l.addContextField(e)
	return e
}

// should returns true if the log event should be logged.
func (l Logger) should(lvl Level) bool {
	if lvl < l.level || lvl < globalLevel() {
		return false
	}
	if l.sample > 0 && l.counter != nil && !samplingDisabled() {
		c := atomic.AddUint32(l.counter, 1)
		return c%l.sample == 0
	}
	return true
}

func (l Logger) addContextField(e Event) {
	if !l.root {
		l.parent.addContextField(e)
	}
	if l.field.mode != zeroFieldMode {
		e.append(l.field)
	}
}
<|endoftext|>


<commit_before>package main

// GetEnglishVerbs returns map of english irregular verbs
func GetEnglishVerbs() map[string][]string {
	var verbs map[string][]string
	verbs = make(map[string][]string)
	verbs["arise"] = []string{"arose", "arisen"}
	verbs["awake"] = []string{"awoke", "awoken"}
	verbs["bear"] = []string{"bore", "borne"}
	verbs["beat"] = []string{"beat", "beaten"}
	verbs["become"] = []string{"became", "become"}
	verbs["begin"] = []string{"began", "begun"}
	verbs["bend"] = []string{"bent", "bent"}
	verbs["beset"] = []string{"beset", "beset"}
	verbs["bet"] = []string{"bet", "bet"}
	verbs["bid"] = []string{"bid", "bid"}
	verbs["bind"] = []string{"bound", "bound"}
	verbs["bite"] = []string{"bit", "bitten"}
	verbs["bleed"] = []string{"bled", "bled"}
	verbs["blow"] = []string{"blew", "blown"}
	verbs["break"] = []string{"broke", "broken"}
	verbs["breed"] = []string{"bred", "bred"}
	verbs["bring"] = []string{"brought", "brought"}
	verbs["broadcast"] = []string{"broadcast", "broadcast"}
	verbs["build"] = []string{"built", "built"}
	verbs["burst"] = []string{"burst", "burst"}
	verbs["buy"] = []string{"bought", "bought"}
	verbs["cast"] = []string{"cast", "cast"}
	verbs["catch"] = []string{"caught", "caught"}
	verbs["choose"] = []string{"chose", "chosen"}
	verbs["cling"] = []string{"clung", "clung"}
	verbs["come"] = []string{"came", "come"}
	verbs["cost"] = []string{"cost", "cost"}
	verbs["creep"] = []string{"crept", "crept"}
	verbs["cut"] = []string{"cut", "cut"}
	verbs["deal"] = []string{"dealt", "dealt"}
	verbs["dig"] = []string{"dug", "dug"}
	verbs["do"] = []string{"did", "done"}
	verbs["draw"] = []string{"drew", "drawn"}
	verbs["drink"] = []string{"drank", "drunk"}
	verbs["drive"] = []string{"drove", "driven"}
	verbs["eat"] = []string{"ate", "eaten"}
	verbs["fall"] = []string{"fell", "fallen"}
	verbs["feed"] = []string{"fed", "fed"}
	verbs["feel"] = []string{"felt", "felt"}
	verbs["fight"] = []string{"fought", "fought"}
	verbs["find"] = []string{"found", "found"}
	verbs["fit"] = []string{"fit", "fit"}
	verbs["flee"] = []string{"fled", "fled"}
	verbs["fling"] = []string{"flung", "flung"}
	verbs["fly"] = []string{"flew", "flown"}
	verbs["forbid"] = []string{"forbade", "forbidden"}
	verbs["forget"] = []string{"forgot", "forgotten"}
	verbs["forego"] = []string{"forewent", "foregone"}
	verbs["forgive"] = []string{"forgave", "forgiven"}
	verbs["forsake"] = []string{"forsook", "forsaken"}
	verbs["foretell"] = []string{"foretold", "foretold"}
	verbs["freeze"] = []string{"froze", "frozen"}
	verbs["get"] = []string{"got", "gotten"}
	verbs["give"] = []string{"gave", "given"}
	verbs["go"] = []string{"went", "gone"}
	verbs["grind"] = []string{"ground", "ground"}
	verbs["grow"] = []string{"grew", "grown"}
	verbs["hang"] = []string{"hung", "hung"}
	verbs["hang"] = []string{"hanged", "hanged"}
	verbs["have"] = []string{"had", "had"}
	verbs["hear"] = []string{"heard", "heard"}
	verbs["hide"] = []string{"hid", "hidden"}
	verbs["hit"] = []string{"hit", "hit"}
	verbs["hold"] = []string{"held", "held"}
	verbs["hurt"] = []string{"hurt", "hurt"}
	verbs["keep"] = []string{"kept", "kept"}
	verbs["kneel"] = []string{"knelt", "knelt"}
	verbs["know"] = []string{"knew", "known"}
	verbs["lay"] = []string{"laid", "laid"}
	verbs["lead"] = []string{"led", "led"}
	verbs["leave"] = []string{"left", "left"}
	verbs["lend"] = []string{"lent", "lent"}
	verbs["let"] = []string{"let", "let"}
	verbs["lie"] = []string{"lay", "lain"}
	verbs["light"] = []string{"lit", "lit"}
	verbs["lose"] = []string{"lost", "lost"}
	verbs["make"] = []string{"made", "made"}
	verbs["mean"] = []string{"meant", "meant"}
	verbs["meet"] = []string{"met", "met"}
	verbs["mistake"] = []string{"mistook", "mistaken"}
	verbs["overcome"] = []string{"overcame", "overcome"}
	verbs["overdo"] = []string{"overdid", "overdone"}
	verbs["overtake"] = []string{"overtook", "overtaken"}
	verbs["overthrow"] = []string{"overthrew", "overthrown"}
	verbs["pay"] = []string{"paid", "paid"}
	verbs["prove"] = []string{"proved", "proven"}
	verbs["put"] = []string{"put", "put"}
	verbs["quit"] = []string{"quit", "quit"}
	verbs["read"] = []string{"read", "read"}
	verbs["rid"] = []string{"rid", "rid"}
	verbs["ride"] = []string{"rode", "ridden"}
	verbs["ring"] = []string{"rang", "rung"}
	verbs["rise"] = []string{"rose", "risen"}
	verbs["run"] = []string{"ran", "run"}
	verbs["say"] = []string{"said", "said"}
	verbs["see"] = []string{"saw", "seen"}
	verbs["seek"] = []string{"sought", "sought"}
	verbs["sell"] = []string{"sold", "sold"}
	verbs["send"] = []string{"sent", "sent"}
	verbs["set"] = []string{"set", "set"}
	verbs["shake"] = []string{"shook", "shaken"}
	verbs["shed"] = []string{"shed", "shed"}
	verbs["shine"] = []string{"shone", "shone"}
	verbs["shoot"] = []string{"shot", "shot"}
	verbs["show"] = []string{"showed", "shown"}
	verbs["shrink"] = []string{"shrank", "shrunk"}
	verbs["shut"] = []string{"shut", "shut"}
	verbs["sing"] = []string{"sang", "sung"}
	verbs["sink"] = []string{"sank", "sunk"}
	verbs["sit"] = []string{"sat", "sat"}
	verbs["sleep"] = []string{"slept", "slept"}
	verbs["slay"] = []string{"slew", "slain"}
	verbs["slide"] = []string{"slid", "slid"}
	verbs["sling"] = []string{"slung", "slung"}
	verbs["slit"] = []string{"slit", "slit"}
	verbs["smite"] = []string{"smote", "smitten"}
	verbs["speak"] = []string{"spoke", "spoken"}
	verbs["speed"] = []string{"sped", "sped"}
	verbs["spend"] = []string{"spent", "spent"}
	verbs["spin"] = []string{"spun", "spun"}
	verbs["spit"] = []string{"spat", "spat"}
	verbs["split"] = []string{"split", "split"}
	verbs["spread"] = []string{"spread", "spread"}
	verbs["spring"] = []string{"sprang", "sprung"}
	verbs["stand"] = []string{"stood", "stood"}
	verbs["steal"] = []string{"stole", "stolen"}
	verbs["stick"] = []string{"stuck", "stuck"}
	verbs["sting"] = []string{"stung", "stung"}
	verbs["stink"] = []string{"stank", "stunk"}
	verbs["stride"] = []string{"strode", "stridden"}
	verbs["strike"] = []string{"struck", "struck"}
	verbs["strive"] = []string{"strove", "striven"}
	verbs["swear"] = []string{"swore", "sworn"}
	verbs["sweep"] = []string{"swept", "swept"}
	verbs["swim"] = []string{"swam", "swum"}
	verbs["swing"] = []string{"swung", "swung"}
	verbs["take"] = []string{"took", "taken"}
	verbs["teach"] = []string{"taught", "taught"}
	verbs["tear"] = []string{"tore", "torn"}
	verbs["tell"] = []string{"told", "told"}
	verbs["think"] = []string{"thought", "thought"}
	verbs["throw"] = []string{"threw", "thrown"}
	verbs["thrust"] = []string{"thrust", "thrust"}
	verbs["tread"] = []string{"trod", "trodden"}
	verbs["understand"] = []string{"understood", "understood"}
	verbs["uphold"] = []string{"upheld", "upheld"}
	verbs["upset"] = []string{"upset", "upset"}
	verbs["wake"] = []string{"woke", "woken"}
	verbs["wear"] = []string{"wore", "worn"}
	verbs["weep"] = []string{"wept", "wept"}
	verbs["win"] = []string{"won", "won"}
	verbs["wind"] = []string{"wound", "wound"}
	verbs["withdraw"] = []string{"withdrew", "withdrawn"}
	verbs["withhold"] = []string{"withheld", "withheld"}
	verbs["withstand"] = []string{"withstood", "withstood"}
	verbs["wring"] = []string{"wrung", "wrung"}
	verbs["write"] = []string{"wrote", "written"}
	return verbs
}
<commit_msg>Remove verb duplicate<commit_after>package main

// GetEnglishVerbs returns map of english irregular verbs
func GetEnglishVerbs() map[string][]string {
	var verbs map[string][]string
	verbs = make(map[string][]string)
	verbs["arise"] = []string{"arose", "arisen"}
	verbs["awake"] = []string{"awoke", "awoken"}
	verbs["bear"] = []string{"bore", "borne"}
	verbs["beat"] = []string{"beat", "beaten"}
	verbs["become"] = []string{"became", "become"}
	verbs["begin"] = []string{"began", "begun"}
	verbs["bend"] = []string{"bent", "bent"}
	verbs["beset"] = []string{"beset", "beset"}
	verbs["bet"] = []string{"bet", "bet"}
	verbs["bid"] = []string{"bid", "bid"}
	verbs["bind"] = []string{"bound", "bound"}
	verbs["bite"] = []string{"bit", "bitten"}
	verbs["bleed"] = []string{"bled", "bled"}
	verbs["blow"] = []string{"blew", "blown"}
	verbs["break"] = []string{"broke", "broken"}
	verbs["breed"] = []string{"bred", "bred"}
	verbs["bring"] = []string{"brought", "brought"}
	verbs["broadcast"] = []string{"broadcast", "broadcast"}
	verbs["build"] = []string{"built", "built"}
	verbs["burst"] = []string{"burst", "burst"}
	verbs["buy"] = []string{"bought", "bought"}
	verbs["cast"] = []string{"cast", "cast"}
	verbs["catch"] = []string{"caught", "caught"}
	verbs["choose"] = []string{"chose", "chosen"}
	verbs["cling"] = []string{"clung", "clung"}
	verbs["come"] = []string{"came", "come"}
	verbs["cost"] = []string{"cost", "cost"}
	verbs["creep"] = []string{"crept", "crept"}
	verbs["cut"] = []string{"cut", "cut"}
	verbs["deal"] = []string{"dealt", "dealt"}
	verbs["dig"] = []string{"dug", "dug"}
	verbs["do"] = []string{"did", "done"}
	verbs["draw"] = []string{"drew", "drawn"}
	verbs["drink"] = []string{"drank", "drunk"}
	verbs["drive"] = []string{"drove", "driven"}
	verbs["eat"] = []string{"ate", "eaten"}
	verbs["fall"] = []string{"fell", "fallen"}
	verbs["feed"] = []string{"fed", "fed"}
	verbs["feel"] = []string{"felt", "felt"}
	verbs["fight"] = []string{"fought", "fought"}
	verbs["find"] = []string{"found", "found"}
	verbs["fit"] = []string{"fit", "fit"}
	verbs["flee"] = []string{"fled", "fled"}
	verbs["fling"] = []string{"flung", "flung"}
	verbs["fly"] = []string{"flew", "flown"}
	verbs["forbid"] = []string{"forbade", "forbidden"}
	verbs["forget"] = []string{"forgot", "forgotten"}
	verbs["forego"] = []string{"forewent", "foregone"}
	verbs["forgive"] = []string{"forgave", "forgiven"}
	verbs["forsake"] = []string{"forsook", "forsaken"}
	verbs["foretell"] = []string{"foretold", "foretold"}
	verbs["freeze"] = []string{"froze", "frozen"}
	verbs["get"] = []string{"got", "gotten"}
	verbs["give"] = []string{"gave", "given"}
	verbs["go"] = []string{"went", "gone"}
	verbs["grind"] = []string{"ground", "ground"}
	verbs["grow"] = []string{"grew", "grown"}
	verbs["hang"] = []string{"hung", "hung"}
	verbs["have"] = []string{"had", "had"}
	verbs["hear"] = []string{"heard", "heard"}
	verbs["hide"] = []string{"hid", "hidden"}
	verbs["hit"] = []string{"hit", "hit"}
	verbs["hold"] = []string{"held", "held"}
	verbs["hurt"] = []string{"hurt", "hurt"}
	verbs["keep"] = []string{"kept", "kept"}
	verbs["kneel"] = []string{"knelt", "knelt"}
	verbs["know"] = []string{"knew", "known"}
	verbs["lay"] = []string{"laid", "laid"}
	verbs["lead"] = []string{"led", "led"}
	verbs["leave"] = []string{"left", "left"}
	verbs["lend"] = []string{"lent", "lent"}
	verbs["let"] = []string{"let", "let"}
	verbs["lie"] = []string{"lay", "lain"}
	verbs["light"] = []string{"lit", "lit"}
	verbs["lose"] = []string{"lost", "lost"}
	verbs["make"] = []string{"made", "made"}
	verbs["mean"] = []string{"meant", "meant"}
	verbs["meet"] = []string{"met", "met"}
	verbs["mistake"] = []string{"mistook", "mistaken"}
	verbs["overcome"] = []string{"overcame", "overcome"}
	verbs["overdo"] = []string{"overdid", "overdone"}
	verbs["overtake"] = []string{"overtook", "overtaken"}
	verbs["overthrow"] = []string{"overthrew", "overthrown"}
	verbs["pay"] = []string{"paid", "paid"}
	verbs["prove"] = []string{"proved", "proven"}
	verbs["put"] = []string{"put", "put"}
	verbs["quit"] = []string{"quit", "quit"}
	verbs["read"] = []string{"read", "read"}
	verbs["rid"] = []string{"rid", "rid"}
	verbs["ride"] = []string{"rode", "ridden"}
	verbs["ring"] = []string{"rang", "rung"}
	verbs["rise"] = []string{"rose", "risen"}
	verbs["run"] = []string{"ran", "run"}
	verbs["say"] = []string{"said", "said"}
	verbs["see"] = []string{"saw", "seen"}
	verbs["seek"] = []string{"sought", "sought"}
	verbs["sell"] = []string{"sold", "sold"}
	verbs["send"] = []string{"sent", "sent"}
	verbs["set"] = []string{"set", "set"}
	verbs["shake"] = []string{"shook", "shaken"}
	verbs["shed"] = []string{"shed", "shed"}
	verbs["shine"] = []string{"shone", "shone"}
	verbs["shoot"] = []string{"shot", "shot"}
	verbs["show"] = []string{"showed", "shown"}
	verbs["shrink"] = []string{"shrank", "shrunk"}
	verbs["shut"] = []string{"shut", "shut"}
	verbs["sing"] = []string{"sang", "sung"}
	verbs["sink"] = []string{"sank", "sunk"}
	verbs["sit"] = []string{"sat", "sat"}
	verbs["sleep"] = []string{"slept", "slept"}
	verbs["slay"] = []string{"slew", "slain"}
	verbs["slide"] = []string{"slid", "slid"}
	verbs["sling"] = []string{"slung", "slung"}
	verbs["slit"] = []string{"slit", "slit"}
	verbs["smite"] = []string{"smote", "smitten"}
	verbs["speak"] = []string{"spoke", "spoken"}
	verbs["speed"] = []string{"sped", "sped"}
	verbs["spend"] = []string{"spent", "spent"}
	verbs["spin"] = []string{"spun", "spun"}
	verbs["spit"] = []string{"spat", "spat"}
	verbs["split"] = []string{"split", "split"}
	verbs["spread"] = []string{"spread", "spread"}
	verbs["spring"] = []string{"sprang", "sprung"}
	verbs["stand"] = []string{"stood", "stood"}
	verbs["steal"] = []string{"stole", "stolen"}
	verbs["stick"] = []string{"stuck", "stuck"}
	verbs["sting"] = []string{"stung", "stung"}
	verbs["stink"] = []string{"stank", "stunk"}
	verbs["stride"] = []string{"strode", "stridden"}
	verbs["strike"] = []string{"struck", "struck"}
	verbs["strive"] = []string{"strove", "striven"}
	verbs["swear"] = []string{"swore", "sworn"}
	verbs["sweep"] = []string{"swept", "swept"}
	verbs["swim"] = []string{"swam", "swum"}
	verbs["swing"] = []string{"swung", "swung"}
	verbs["take"] = []string{"took", "taken"}
	verbs["teach"] = []string{"taught", "taught"}
	verbs["tear"] = []string{"tore", "torn"}
	verbs["tell"] = []string{"told", "told"}
	verbs["think"] = []string{"thought", "thought"}
	verbs["throw"] = []string{"threw", "thrown"}
	verbs["thrust"] = []string{"thrust", "thrust"}
	verbs["tread"] = []string{"trod", "trodden"}
	verbs["understand"] = []string{"understood", "understood"}
	verbs["uphold"] = []string{"upheld", "upheld"}
	verbs["upset"] = []string{"upset", "upset"}
	verbs["wake"] = []string{"woke", "woken"}
	verbs["wear"] = []string{"wore", "worn"}
	verbs["weep"] = []string{"wept", "wept"}
	verbs["win"] = []string{"won", "won"}
	verbs["wind"] = []string{"wound", "wound"}
	verbs["withdraw"] = []string{"withdrew", "withdrawn"}
	verbs["withhold"] = []string{"withheld", "withheld"}
	verbs["withstand"] = []string{"withstood", "withstood"}
	verbs["wring"] = []string{"wrung", "wrung"}
	verbs["write"] = []string{"wrote", "written"}
	return verbs
}
<|endoftext|>


<commit_before>package todo

import (
	"encoding/json"
	"time"

	"github.com/antlinker/go-mqtt/client"
	"github.com/antlinker/sdk/asapi"
	"github.com/satori/go.uuid"
)

// NewHandle 创建待办事项处理
func NewHandle(auh *asapi.AuthorizeHandle, mqcli client.MqttClienter) *Handle {
	return &Handle{
		auh:   auh,
		mqcli: mqcli,
	}
}

// Handle 待办事项处理
type Handle struct {
	auh   *asapi.AuthorizeHandle
	mqcli client.MqttClienter
}

// AddRequest 增加待办事项请求参数
type AddRequest struct {
	UIDs         []string
	BuID         string
	TodoType     string
	ContentValue map[string]string
	URIValue     map[string]string
	PubTime      time.Time
	EndTime      time.Time
	Status       int
}

// Add 增加待办事项
func (h *Handle) Add(req *AddRequest) (err error) {
	auids, ar := h.auh.GetAntUIDList("", req.UIDs...)
	if ar != nil {
		err = ar
		return
	}

	mreq := map[string]interface{}{
		"MT":           "ADDTODO",
		"AID":          uuid.NewV4().String(),
		"UIDs":         auids,
		"TodoType":     req.TodoType,
		"ContentValue": req.ContentValue,
		"URIValue":     req.URIValue,
		"Status":       req.Status,
		"BuID":         req.BuID,
	}

	if !req.PubTime.IsZero() {
		mreq["PubTime"] = req.PubTime.Format("20060102150405")
	}

	if !req.EndTime.IsZero() {
		mreq["EndTime"] = req.EndTime.Format("20060102150405")
	}

	err = h.publish(mreq)
	return
}

// DoneRequest 完成待办事项请求参数
type DoneRequest struct {
	UID      string
	BuID     string
	TodoType string
}

// Done 完成待办事项
func (h *Handle) Done(req *DoneRequest) (err error) {
	auids, ar := h.auh.GetAntUIDList("", req.UID)
	if ar != nil {
		err = ar
		return
	} else if len(auids) == 0 {
		return
	}

	mreq := map[string]interface{}{
		"MT":       "COMPLETETODO",
		"UID":      auids[0],
		"BuID":     req.BuID,
		"TodoType": req.TodoType,
	}
	err = h.publish(mreq)
	return
}

// DelRequest 删除待办事项请求参数
type DelRequest struct {
	UID      string
	BuID     string
	TodoType string
}

// Del 删除待办事项
func (h *Handle) Del(req *DelRequest) (err error) {
	auids, ar := h.auh.GetAntUIDList("", req.UID)
	if ar != nil {
		err = ar
		return
	} else if len(auids) == 0 {
		return
	}

	mreq := map[string]interface{}{
		"MT":       "DELTODO",
		"UID":      auids[0],
		"BuID":     req.BuID,
		"TodoType": req.TodoType,
	}
	err = h.publish(mreq)
	return
}

func (h *Handle) publish(data interface{}) (err error) {
	buf, err := json.Marshal(data)
	if err != nil {
		return
	}

	_, err = h.mqcli.Publish("S/TODO", client.QoS1, false, buf)
	return
}
<commit_msg>更新todo<commit_after>package todo

import (
	"encoding/json"
	"time"

	"github.com/antlinker/go-mqtt/client"
	"github.com/antlinker/sdk/asapi"
	"github.com/satori/go.uuid"
)

// NewHandle 创建待办事项处理
func NewHandle(auh *asapi.AuthorizeHandle, mqcli client.MqttClienter) *Handle {
	return &Handle{
		auh:   auh,
		mqcli: mqcli,
	}
}

// Handle 待办事项处理
type Handle struct {
	auh   *asapi.AuthorizeHandle
	mqcli client.MqttClienter
}

// AddRequest 增加待办事项请求参数
type AddRequest struct {
	UIDs         []string
	BuID         string
	TodoType     string
	ContentValue map[string]string
	URIValue     map[string]string
	PubTime      time.Time
	EndTime      time.Time
	Status       int
}

// Add 增加待办事项
func (h *Handle) Add(req *AddRequest) (err error) {
	auids, ar := h.auh.GetAntUIDList("", req.UIDs...)
	if ar != nil {
		err = ar
		return
	}

	mreq := map[string]interface{}{
		"MT":           "ADDTODO",
		"AID":          uuid.NewV4().String(),
		"UIDs":         auids,
		"TodoType":     req.TodoType,
		"ContentValue": req.ContentValue,
		"URIValue":     req.URIValue,
		"Status":       req.Status,
		"BuID":         req.BuID,
	}

	if !req.PubTime.IsZero() {
		mreq["PubTime"] = req.PubTime.Format("20060102150405")
	}

	if !req.EndTime.IsZero() {
		mreq["EndTime"] = req.EndTime.Format("20060102150405")
	}

	err = h.publish(mreq)
	return
}

// DoneRequest 完成待办事项请求参数
type DoneRequest struct {
	UID      string
	BuID     string
	TodoType string
}

// Done 完成待办事项
func (h *Handle) Done(req *DoneRequest) (err error) {
	auids, ar := h.auh.GetAntUIDList("", req.UID)
	if ar != nil {
		err = ar
		return
	} else if len(auids) == 0 {
		return
	}

	mreq := map[string]interface{}{
		"MT":       "DONETODO",
		"UID":      auids[0],
		"BuID":     req.BuID,
		"TodoType": req.TodoType,
	}
	err = h.publish(mreq)
	return
}

// DelRequest 删除待办事项请求参数
type DelRequest struct {
	UID      string
	BuID     string
	TodoType string
}

// Del 删除待办事项
func (h *Handle) Del(req *DelRequest) (err error) {
	auids, ar := h.auh.GetAntUIDList("", req.UID)
	if ar != nil {
		err = ar
		return
	} else if len(auids) == 0 {
		return
	}

	mreq := map[string]interface{}{
		"MT":       "DELTODO",
		"UID":      auids[0],
		"BuID":     req.BuID,
		"TodoType": req.TodoType,
	}
	err = h.publish(mreq)
	return
}

func (h *Handle) publish(data interface{}) (err error) {
	buf, err := json.Marshal(data)
	if err != nil {
		return
	}

	_, err = h.mqcli.Publish("S/TODO", client.QoS1, false, buf)
	return
}
<|endoftext|>