<commit_before>package data

import a "github.com/hivdb/nucamino/types/amino"

var (
	HCV1ASEQ_NS3 = a.ReadString(`
		APITAYAQQTRGLLGCIITSLTGRDKNQVEGEVQIVSTATQTFLATCINGVCWTVYHGAGTRTIASPKGP
		VIQMYTNVDQDLVGWPAPQGSRSLTPCTCGSSDLYLVTRHADVIPVRRRGDSRGSLLSPRPISYLKGSSG
		GPLLCPAGHAVGLFRAAVCTRGVAKAVDFIPVENLETTMRSPVFTDNSSPPAVPQSFQVAHLHAPTGSGK
		STKVPAAYAAQGYKVLVLNPSVAATLGFGAYMSKAHGVDPNIRTGVRTITTGSPITYSTYGKFLADGGCS
		GGAYDIIICDECHSTDATSILGIGTVLDQAETAGARLVVLATATPPGSVTVSHPNIEEVALSTTGEIPFY
		GKAIPLEVIKGGRHLIFCHSKKKCDELAAKLVALGINAVAYYRGLDVSVIPTSGDVVVVSTDALMTGFTG
		DFDSVIDCNTCVTQTVDFSLDPTFTIETTTLPQDAVSRTQRRGRTGRGKPGIYRFVAPGERPSGMFDSSV
		LCECYDAGCAWYELTPAETTVRLRAYMNTPGLPVCQDHLEFWEGVFTGLTHIDAHFLSQTKQSGENFPYL
		VAYQATVCARAQAPPPSWDQMWKCLIRLKPTLHGPTPLLYRLGAVQNEVTLTHPITKYIMTCMSADLEVV
		TSTWVLVGGVLAALAAYCLSTGCVVIVGRIVLSGKPAIIPDREVLYQEFDEMEE
	`)
	HCV1ASEQ_NS5A = a.ReadString(`
		SGSWLRDIWDWICEVLSDFKTWLKAKLMPQLPGIPFVSCQRGYRGVWRGDGIMHTRCHCGAEITGHVKNG
		TMRIVGPRTCRNMWSGTFPINAYTTGPCTPLPAPNYKFALWRVSAEEYVEIRRVGDFHYVSGMTTDNLKC
		PCQIPSPEFFTELDGVRLHRFAPPCKPLLREEVSFRVGLHEYPVGSQLPCEPEPDVAVLTSMLTDPSHIT
		AEAAGRRLARGSPPSMASSSASQLSAPSLKATCTANHDSPDAELIEANLLWRQEMGGNITRVESENKVVI
		LDSFDPLVAEEDEREVSVPAEILRKSRRFARALPVWARPDYNPPLVETWKKPDYEPPVVHGCPLPPPRSP
		PVPPPRKKRTVVLTESTLSTALAELATKSFGSSSTSGITGDNTTTSSEPAPSGCPPDSDVESYSSMPPLE
		GEPGDPDLSDGSWSTVSSGADTEDVVC
	`)
	HCV1ASEQ_NS5B = a.ReadString(`
		SMSYSWTGALVTPCAAEEQKLPINALSNSLLRHHNLVYSTTSRSACQRQKKVTFDRLQVLDSHYQDVLKE
		VKAAASKVKANLLSVEEACSLTPPHSAKSKFGYGAKDVRCHARKAVAHINSVWKDLLEDSVTPIDTTIMA
		KNEVFCVQPEKGGRKPARLIVFPDLGVRVCEKMALYDVVSKLPLAVMGSSYGFQYSPGQRVEFLVQAWKS
		KKTPMGFSYDTRCFDSTVTESDIRTEEAIYQCCDLDPQARVAIKSLTERLYVGGPLTNSRGENCGYRRCR
		ASGVLTTSCGNTLTCYIKARAACRAAGLQDCTMLVCGDDLVVICESAGVQEDAASLRAFTEAMTRYSAPP
		GDPPQPEYDLELITSCSSNVSVAHDGAGKRVYYLTRDPTTPLARAAWETARHTPVNSWLGNIIMFAPTLW
		ARMILMTHFFSVLIARDQLEQALNCEIYGACYSIEPLDLPPIIQRLHGLSAFSLHSYSPGEINRVAACLR
		KLGVPPLRAWRHRARSVRARLLSRGGRAAICGKYLFNWAVRTKLKLTPIAAAGRLDLSGWFTAGYSGGDI
		YHSVSHARPRWFWFCLLLLAAGVGIYLLPNR
	`)
)

var HCV1ARefLookup = map[string][]a.AminoAcid{
	"NS3": HCV1ASEQ_NS3,
	"NS5A": HCV1ASEQ_NS5A,
	"NS5B": HCV1ASEQ_NS5B,
}
<commit_msg>Corrections to HCV1A reference sequence<commit_after>package data

import a "github.com/hivdb/nucamino/types/amino"

// Genebank accession ID: NC_004102.1

var (
	HCV1ASEQ_NS3 = a.ReadString(`
		APITAYAQQTRGLLGCIITSLTGRDKNQVEGEVQIVSTATQTFLATCINGVCWTVYHGAGTRTIASPKGP
		VIQMYTNVDQDLVGWPAPQGSRSLTPCTCGSSDLYLVTRHADVIPVRRRGDSRGSLLSPRPISYLKGSSG
		GPLLCPAGHAVGLFRAAVCTRGVAKAVDFIPVENLETTMRSPVFTDNSSPPAVPQSFQVAHLHAPTGSGK
		STKVPAAYAAQGYKVLVLNPSVAATLGFGAYMSKAHGVDPNIRTGVRTITTGSPITYSTYGKFLADGGCS
		GGAYDIIICDECHSTDATSILGIGTVLDQAETAGARLVVLATATPPGSVTVSHPNIEEVALSTTGEIPFY
		GKAIPLEVIKGGRHLIFCHSKKKCDELAAKLVALGINAVAYYRGLDVSVIPTSGDVVVVSTDALMTGFTG
		DFDSVIDCNTCVTQTVDFSLDPTFTIETTTLPQDAVSRTQRRGRTGRGKPGIYRFVAPGERPSGMFDSSV
		LCECYDAGCAWYELTPAETTVRLRAYMNTPGLPVCQDHLEFWEGVFTGLTHIDAHFLSQTKQSGENFPYL
		VAYQATVCARAQAPPPSWDQMWKCLIRLKPTLHGPTPLLYRLGAVQNEVTLTHPITKYIMTCMSADLEVVT
	`)
	HCV1ASEQ_NS5A = a.ReadString(`
		SGSWLRDIWDWICEVLSDFKTWLKAKLMPQLPGIPFVSCQRGYRGVWRGDGIMHTRCHCGAEITGHVKNG
		TMRIVGPRTCRNMWSGTFPINAYTTGPCTPLPAPNYKFALWRVSAEEYVEIRRVGDFHYVSGMTTDNLKC
		PCQIPSPEFFTELDGVRLHRFAPPCKPLLREEVSFRVGLHEYPVGSQLPCEPEPDVAVLTSMLTDPSHIT
		AEAAGRRLARGSPPSMASSSASQLSAPSLKATCTANHDSPDAELIEANLLWRQEMGGNITRVESENKVVI
		LDSFDPLVAEEDEREVSVPAEILRKSRRFARALPVWARPDYNPPLVETWKKPDYEPPVVHGCPLPPPRSP
		PVPPPRKKRTVVLTESTLSTALAELATKSFGSSSTSGITGDNTTTSSEPAPSGCPPDSDVESYSSMPPLE
		GEPGDPDLSDGSWSTVSSGADTEDVVCC
	`)
	HCV1ASEQ_NS5B = a.ReadString(`
		SMSYSWTGALVTPCAAEEQKLPINALSNSLLRHHNLVYSTTSRSACQRQKKVTFDRLQVLDSHYQDVLKE
		VKAAASKVKANLLSVEEACSLTPPHSAKSKFGYGAKDVRCHARKAVAHINSVWKDLLEDSVTPIDTTIMA
		KNEVFCVQPEKGGRKPARLIVFPDLGVRVCEKMALYDVVSKLPLAVMGSSYGFQYSPGQRVEFLVQAWKS
		KKTPMGFSYDTRCFDSTVTESDIRTEEAIYQCCDLDPQARVAIKSLTERLYVGGPLTNSRGENCGYRRCR
		ASGVLTTSCGNTLTCYIKARAACRAAGLQDCTMLVCGDDLVVICESAGVQEDAASLRAFTEAMTRYSAPP
		GDPPQPEYDLELITSCSSNVSVAHDGAGKRVYYLTRDPTTPLARAAWETARHTPVNSWLGNIIMFAPTLW
		ARMILMTHFFSVLIARDQLEQALNCEIYGACYSIEPLDLPPIIQRLHGLSAFSLHSYSPGEINRVAACLR
		KLGVPPLRAWRHRARSVRARLLSRGGRAAICGKYLFNWAVRTKLKLTPIAAAGRLDLSGWFTAGYSGGDI
		YHSVSHARPRWFWFCLLLLAAGVGIYLLPNR
	`)
)

var HCV1ARefLookup = map[string][]a.AminoAcid{
	"NS3": HCV1ASEQ_NS3,
	"NS5A": HCV1ASEQ_NS5A,
	"NS5B": HCV1ASEQ_NS5B,
}
<|endoftext|>


<commit_before>package libkb

import (
	"github.com/keybase/go-jsonw"
)

type ProofEngine struct {
	Force              bool
	Service, Username  string
	me                 *User
	st                 ServiceType
	usernameNormalized string
	supersede          bool
	proof              *jsonw.Wrapper
	sig                string
	sigId              *SigId
	postRes            *PostProofRes
	ProveUI            ProveUI
	LoginUI            LoginUI
}

func (v *ProofEngine) Init() error {
	if v.ProveUI == nil {
		v.ProveUI = G.UI.GetProveUI()
	}
	if v.LoginUI == nil {
		v.LoginUI = G.UI.GetLoginUI()
	}
	return nil
}

func (v *ProofEngine) Login() (err error) {
	return G.LoginState.Login(LoginArg{Ui: v.LoginUI})
}

func (v *ProofEngine) LoadMe() (err error) {
	v.me, err = LoadMe(LoadUserArg{LoadSecrets: true, AllKeys: false})
	return
}

func (v *ProofEngine) CheckExists1() (err error) {
	proofs := v.me.IdTable.GetActiveProofsFor(v.st)
	if len(proofs) != 0 && !v.Force && v.st.LastWriterWins() {
		lst := proofs[len(proofs)-1]
		var redo bool
		redo, err = v.ProveUI.PromptOverwrite1(lst.ToDisplayString())
		if err != nil {
		} else if !redo {
			err = NotConfirmedError{}
		} else {
			v.supersede = true
		}
	}
	return
}

func (v *ProofEngine) PromptRemoteName() (err error) {
	if len(v.Username) == 0 {
		var prevErr error
		for len(v.Username) == 0 && err == nil {
			var un string
			un, err = v.ProveUI.PromptUsername(v.st.GetPrompt(), prevErr)
			if err != nil {
				prevErr = v.st.CheckUsername(un)
				if prevErr == nil {
					v.Username = un
				}
			}
		}
	} else {
		err = v.st.CheckUsername(v.Username)
	}
	return
}

func (v *ProofEngine) NormalizeRemoteName() (err error) {
	v.usernameNormalized, err = v.st.NormalizeUsername(v.Username)
	return
}

func (v *ProofEngine) CheckExists2() (err error) {
	G.Log.Debug("+ CheckExists2")
	defer func() { G.Log.Debug("- CheckExists2 -> %s", ErrToOk(err)) }()
	if !v.st.LastWriterWins() {
		var found RemoteProofChainLink
		for _, p := range v.me.IdTable.GetActiveProofsFor(v.st) {
			_, name := p.ToKeyValuePair()
			if Cicmp(name, v.usernameNormalized) {
				found = p
				break
			}
		}
		if found != nil {
			var redo bool
			redo, err = v.ProveUI.PromptOverwrite2(found.ToDisplayString())
			if err != nil {
			} else if !redo {
				err = NotConfirmedError{}
			} else {
				v.supersede = true
			}
		}
	}
	return
}

func (v *ProofEngine) DoPrechecks() (err error) {
	var w *Markup
	w, err = v.st.PreProofCheck(v.usernameNormalized)
	if w != nil {
		v.ProveUI.OutputPrechecks(w.Export())
	}
	return
}

func (v *ProofEngine) DoWarnings() (err error) {
	if mu := v.st.PreProofWarning(v.usernameNormalized); mu != nil {
		var ok bool
		if ok, err = v.ProveUI.PreProofWarning(mu.Export()); err == nil && !ok {
			err = NotConfirmedError{}
		}
	}
	return
}
func (v *ProofEngine) GenerateProof() (err error) {
	var key *PgpKeyBundle
	if v.proof, err = v.me.ServiceProof(v.st, v.usernameNormalized); err != nil {
		return
	}
	if key, err = G.Keyrings.GetSecretKey("proof signature"); err != nil {
		return
	}
	if v.sig, v.sigId, err = SignJson(v.proof, key); err != nil {
		return
	}
	return
}

func (v *ProofEngine) PostProofToServer() (err error) {
	arg := PostProofArg{
		Sig:            v.sig,
		ProofType:      v.st.GetProofType(),
		Id:             *v.sigId,
		Supersede:      v.supersede,
		RemoteUsername: v.usernameNormalized,
		RemoteKey:      v.st.GetApiArgKey(),
	}
	v.postRes, err = PostProof(arg)
	return
}

func (v *ProofEngine) InstructAction() (err error) {
	mkp := v.st.PostInstructions(v.usernameNormalized)
	var txt string
	if txt, err = v.st.FormatProofText(v.postRes); err != nil {
		return
	}
	err = v.ProveUI.OutputInstructions(mkp.Export(), txt)
	return
}

func (v *ProofEngine) PromptPostedLoop() (err error) {
	found := false
	for i := 0; ; i++ {
		var retry bool
		var status int
		var warn *Markup
		retry, err = v.ProveUI.OkToCheck(v.st.DisplayName(v.usernameNormalized), i)
		if !retry || err != nil {
			break
		}
		found, status, err = CheckPosted(v.postRes.Id)
		if found || err != nil {
			break
		}
		warn, err = v.st.RecheckProofPosting(status, i)
		if warn != nil {
			v.ProveUI.DisplayRecheckWarning(warn.Export())
		}
		if err != nil {
			break
		}
	}
	if !found && err == nil {
		err = ProofNotYetAvailableError{}
	}

	return
}

func (v *ProofEngine) CheckProofText() error {
	return v.st.CheckProofText(v.postRes.Text, *v.sigId, v.sig)
}

func (v *ProofEngine) GetServiceType() (err error) {
	if v.st = GetServiceType(v.Service); v.st == nil {
		err = BadServiceError{v.Service}
	}
	return
}

func (v *ProofEngine) Run() (err error) {

	if err = v.Init(); err != nil {
		return
	}
	if err = v.GetServiceType(); err != nil {
		return
	}
	if err = v.Login(); err != nil {
		return
	}
	if err = v.LoadMe(); err != nil {
		return
	}
	if err = v.CheckExists1(); err != nil {
		return
	}
	if err = v.PromptRemoteName(); err != nil {
		return
	}
	if err = v.NormalizeRemoteName(); err != nil {
		return
	}
	if err = v.CheckExists2(); err != nil {
		return
	}
	if err = v.DoPrechecks(); err != nil {
		return
	}
	if err = v.DoWarnings(); err != nil {
		return
	}
	if err = v.GenerateProof(); err != nil {
		return
	}
	if err = v.PostProofToServer(); err != nil {
		return
	}
	if err = v.CheckProofText(); err != nil {
		return
	}
	if err = v.InstructAction(); err != nil {
		return
	}
	if err = v.PromptPostedLoop(); err != nil {
		return
	}
	G.Log.Notice("Success!")
	return nil
}
<commit_msg>bugfix for keybase/go-client#20<commit_after>package libkb

import (
	"github.com/keybase/go-jsonw"
)

type ProofEngine struct {
	Force              bool
	Service, Username  string
	me                 *User
	st                 ServiceType
	usernameNormalized string
	supersede          bool
	proof              *jsonw.Wrapper
	sig                string
	sigId              *SigId
	postRes            *PostProofRes
	ProveUI            ProveUI
	LoginUI            LoginUI
}

func (v *ProofEngine) Init() error {
	if v.ProveUI == nil {
		v.ProveUI = G.UI.GetProveUI()
	}
	if v.LoginUI == nil {
		v.LoginUI = G.UI.GetLoginUI()
	}
	return nil
}

func (v *ProofEngine) Login() (err error) {
	return G.LoginState.Login(LoginArg{Ui: v.LoginUI})
}

func (v *ProofEngine) LoadMe() (err error) {
	v.me, err = LoadMe(LoadUserArg{LoadSecrets: true, AllKeys: false})
	return
}

func (v *ProofEngine) CheckExists1() (err error) {
	proofs := v.me.IdTable.GetActiveProofsFor(v.st)
	if len(proofs) != 0 && !v.Force && v.st.LastWriterWins() {
		lst := proofs[len(proofs)-1]
		var redo bool
		redo, err = v.ProveUI.PromptOverwrite1(lst.ToDisplayString())
		if err != nil {
		} else if !redo {
			err = NotConfirmedError{}
		} else {
			v.supersede = true
		}
	}
	return
}

func (v *ProofEngine) PromptRemoteName() (err error) {
	if len(v.Username) == 0 {
		var prevErr error
		for len(v.Username) == 0 && err == nil {
			var un string
			un, err = v.ProveUI.PromptUsername(v.st.GetPrompt(), prevErr)
			if err == nil {
				prevErr = v.st.CheckUsername(un)
				if prevErr == nil {
					v.Username = un
				}
			}
		}
	} else {
		err = v.st.CheckUsername(v.Username)
	}
	return
}

func (v *ProofEngine) NormalizeRemoteName() (err error) {
	v.usernameNormalized, err = v.st.NormalizeUsername(v.Username)
	return
}

func (v *ProofEngine) CheckExists2() (err error) {
	G.Log.Debug("+ CheckExists2")
	defer func() { G.Log.Debug("- CheckExists2 -> %s", ErrToOk(err)) }()
	if !v.st.LastWriterWins() {
		var found RemoteProofChainLink
		for _, p := range v.me.IdTable.GetActiveProofsFor(v.st) {
			_, name := p.ToKeyValuePair()
			if Cicmp(name, v.usernameNormalized) {
				found = p
				break
			}
		}
		if found != nil {
			var redo bool
			redo, err = v.ProveUI.PromptOverwrite2(found.ToDisplayString())
			if err != nil {
			} else if !redo {
				err = NotConfirmedError{}
			} else {
				v.supersede = true
			}
		}
	}
	return
}

func (v *ProofEngine) DoPrechecks() (err error) {
	var w *Markup
	w, err = v.st.PreProofCheck(v.usernameNormalized)
	if w != nil {
		v.ProveUI.OutputPrechecks(w.Export())
	}
	return
}

func (v *ProofEngine) DoWarnings() (err error) {
	if mu := v.st.PreProofWarning(v.usernameNormalized); mu != nil {
		var ok bool
		if ok, err = v.ProveUI.PreProofWarning(mu.Export()); err == nil && !ok {
			err = NotConfirmedError{}
		}
	}
	return
}
func (v *ProofEngine) GenerateProof() (err error) {
	var key *PgpKeyBundle
	if v.proof, err = v.me.ServiceProof(v.st, v.usernameNormalized); err != nil {
		return
	}
	if key, err = G.Keyrings.GetSecretKey("proof signature"); err != nil {
		return
	}
	if v.sig, v.sigId, err = SignJson(v.proof, key); err != nil {
		return
	}
	return
}

func (v *ProofEngine) PostProofToServer() (err error) {
	arg := PostProofArg{
		Sig:            v.sig,
		ProofType:      v.st.GetProofType(),
		Id:             *v.sigId,
		Supersede:      v.supersede,
		RemoteUsername: v.usernameNormalized,
		RemoteKey:      v.st.GetApiArgKey(),
	}
	v.postRes, err = PostProof(arg)
	return
}

func (v *ProofEngine) InstructAction() (err error) {
	mkp := v.st.PostInstructions(v.usernameNormalized)
	var txt string
	if txt, err = v.st.FormatProofText(v.postRes); err != nil {
		return
	}
	err = v.ProveUI.OutputInstructions(mkp.Export(), txt)
	return
}

func (v *ProofEngine) PromptPostedLoop() (err error) {
	found := false
	for i := 0; ; i++ {
		var retry bool
		var status int
		var warn *Markup
		retry, err = v.ProveUI.OkToCheck(v.st.DisplayName(v.usernameNormalized), i)
		if !retry || err != nil {
			break
		}
		found, status, err = CheckPosted(v.postRes.Id)
		if found || err != nil {
			break
		}
		warn, err = v.st.RecheckProofPosting(status, i)
		if warn != nil {
			v.ProveUI.DisplayRecheckWarning(warn.Export())
		}
		if err != nil {
			break
		}
	}
	if !found && err == nil {
		err = ProofNotYetAvailableError{}
	}

	return
}

func (v *ProofEngine) CheckProofText() error {
	return v.st.CheckProofText(v.postRes.Text, *v.sigId, v.sig)
}

func (v *ProofEngine) GetServiceType() (err error) {
	if v.st = GetServiceType(v.Service); v.st == nil {
		err = BadServiceError{v.Service}
	}
	return
}

func (v *ProofEngine) Run() (err error) {

	if err = v.Init(); err != nil {
		return
	}
	if err = v.GetServiceType(); err != nil {
		return
	}
	if err = v.Login(); err != nil {
		return
	}
	if err = v.LoadMe(); err != nil {
		return
	}
	if err = v.CheckExists1(); err != nil {
		return
	}
	if err = v.PromptRemoteName(); err != nil {
		return
	}
	if err = v.NormalizeRemoteName(); err != nil {
		return
	}
	if err = v.CheckExists2(); err != nil {
		return
	}
	if err = v.DoPrechecks(); err != nil {
		return
	}
	if err = v.DoWarnings(); err != nil {
		return
	}
	if err = v.GenerateProof(); err != nil {
		return
	}
	if err = v.PostProofToServer(); err != nil {
		return
	}
	if err = v.CheckProofText(); err != nil {
		return
	}
	if err = v.InstructAction(); err != nil {
		return
	}
	if err = v.PromptPostedLoop(); err != nil {
		return
	}
	G.Log.Notice("Success!")
	return nil
}
<|endoftext|>


<commit_before>package dblentry

import "fmt"
import "sort"
import "time"
import "strings"

import "github.com/prataprc/goparsec"
import "github.com/prataprc/golog"
import "github.com/tn47/goledger/api"

// ParsePhase state to be tracked at datastore.
type ParsePhase int

const (
	// DBSTART is parsing started.
	DBSTART ParsePhase = iota + 1
	// DBFIRSTPASS is all Firstpass() calls are completed.
	DBFIRSTPASS
	// DBSECONDPASS is all Secondpass() calls are completed.
	DBSECONDPASS
)

// Datastore managing accounts, commodities, transactions and posting and
// every thing else that are related.
type Datastore struct {
	// immutable from first initialization.
	name string

	// immutable once firstpass is ok
	firstpass

	// changes with every second pass.
	reporter    api.Reporter
	pass        ParsePhase
	commodities map[string]*Commodity
	accntdb     map[string]*Account // full account-name -> account
	dclrdacc    []string
	dclrdcomm   []string
	dclrdpayee  []string
	de          *DoubleEntry
	transdb     *DB
	pricedb     *DB

	// configuration
	periodtill *time.Time
}

// NewDatastore return a new datastore.
func NewDatastore(name string, reporter api.Reporter) *Datastore {
	db := &Datastore{
		name:     name,
		reporter: reporter,

		pass:        DBSTART,
		transdb:     NewDB(fmt.Sprintf("%v-transactions", name)),
		pricedb:     NewDB(fmt.Sprintf("%v-pricedb", name)),
		accntdb:     map[string]*Account{},
		commodities: map[string]*Commodity{},
		de:          NewDoubleEntry("master"),
	}
	db.initfirstpass()
	db.defaultprices()
	return db
}

//---- local accessors

func (db *Datastore) assertfirstpass() {
	if db.pass < DBFIRSTPASS {
		panic("impossible situation")
	}
}

func (db *Datastore) getCommodity(name string, defcomm *Commodity) *Commodity {
	defaultcomm := db.getDefaultcomm()
	if name == "" && defaultcomm != "" {
		return db.commodities[defaultcomm]
	}
	if defaultcomm == "" && name != "" {
		db.setDefaultcomm(name)
	}
	if comm, ok := db.commodities[name]; ok {
		return comm
	}
	log.Debugf("commodity %q added\n", name)
	if defcomm == nil {
		defcomm = NewCommodity(name)
	}
	db.commodities[name] = defcomm
	return defcomm
}

//---- exported accessors

func (db *Datastore) GetCommodity(name string) api.Commoditiser {
	return db.getCommodity(name, nil)
}

func (db *Datastore) Applytill(till time.Time) {
	periodtill := till
	db.periodtill = &periodtill
}

// Firstpassok to track parsephase
func (db *Datastore) Firstpassok() {
	db.pass = DBFIRSTPASS
}

// Secondpassok to track parsephase
func (db *Datastore) Secondpassok() {
	db.pass = DBSECONDPASS
}

// PrintAccounts is a debug api for application.
func (db *Datastore) PrintAccounts() {
	for _, accname := range db.Accountnames() {
		log.Debugf("-- %v\n", db.accntdb[accname])
	}
}

//---- api.Datastorer methods

func (db *Datastore) IsCommodityDeclared(name string) bool {
	for _, xname := range db.dclrdcomm {
		if xname == name {
			return true
		}
	}
	return false
}

func (db *Datastore) IsAccountDeclared(name string) bool {
	for _, xname := range db.dclrdacc {
		if xname == name {
			return true
		}
	}
	return false
}

func (db *Datastore) IsPayeeDeclared(name string) bool {
	for _, xname := range db.dclrdpayee {
		if xname == name {
			return true
		}
	}
	return false
}

func (db *Datastore) GetAccount(name string) api.Accounter {
	if name == "" {
		return (*Account)(nil)
	}
	account, ok := db.accntdb[name]
	if ok == false {
		account = NewAccount(name)
	}
	db.accntdb[name] = account
	return account
}

func (db *Datastore) Accountnames() []string {
	db.assertfirstpass()

	accnames := []string{}
	for name := range db.accntdb {
		accnames = append(accnames, name)
	}
	sort.Strings(accnames)
	return accnames
}

func (db *Datastore) Commoditynames() []string {
	db.assertfirstpass()

	cnames := []string{}
	for name := range db.commodities {
		cnames = append(cnames, name)
	}
	sort.Strings(cnames)
	return cnames
}

func (db *Datastore) Balance(obj interface{}) (balance api.Commoditiser) {
	db.assertfirstpass()
	return db.de.Balance(obj)
}

func (db *Datastore) Balances() []api.Commoditiser {
	db.assertfirstpass()
	return db.de.Balances()
}

func (db *Datastore) Debit(obj interface{}) (balance api.Commoditiser) {
	db.assertfirstpass()
	return db.de.Debit(obj)
}

func (db *Datastore) Debits() []api.Commoditiser {
	db.assertfirstpass()
	return db.de.Debits()
}

func (db *Datastore) Credit(obj interface{}) (balance api.Commoditiser) {
	db.assertfirstpass()
	return db.de.Credit(obj)
}

func (db *Datastore) Credits() []api.Commoditiser {
	db.assertfirstpass()
	return db.de.Credits()
}

func (db *Datastore) AggregateTotal(trans api.Transactor, p api.Poster) error {
	posting := p.(*Posting)
	names := SplitAccount(posting.account.name)
	parts := []string{}
	for _, name := range names[:len(names)-1] {
		parts = append(parts, name)
		fullname := strings.Join(parts, ":")
		consacc := db.GetAccount(fullname).(*Account)
		if err := consacc.addBalance(posting.commodity); err != nil {
			return err
		}
		err := db.reporter.BubblePosting(db, trans, posting, consacc)
		if err != nil {
			return err
		}
	}
	return nil
}

//---- engine

func (db *Datastore) Firstpass(obj interface{}) (err error) {
	if trans, ok := obj.(*Transaction); ok {
		if err := trans.Firstpass(db); err != nil {
			return err
		}
		db.setCurrentDate(trans.date)
		db.transdb.Insert(trans.date, trans)

	} else if price, ok := obj.(*Price); ok {
		err = db.pricedb.Insert(price.when, price)

	} else if directive, ok := obj.(*Directive); ok {
		err = directive.Firstpass(db)

	} else if comment, ok := obj.(*Comment); ok {
		err = comment.Firstpass(db)
		db.addComment(comment.line)
	}
	return err
}

func (db *Datastore) Secondpass() error {
	entries := []api.TimeEntry{}

	for _, entry := range db.transdb.Range(nil, nil, "both", entries) {
		trans := entry.Value().(*Transaction)
		if db.periodtill == nil || trans.Date().Before(*db.periodtill) {
			if err := trans.Secondpass(db); err != nil {
				return err
			}
		}
	}
	return nil
}

func (db *Datastore) Clone(nreporter api.Reporter) api.Datastorer {
	ndb := *db
	ndb.reporter = nreporter

	ndb.commodities = map[string]*Commodity{}
	for name, commodity := range db.commodities {
		ndb.commodities[name] = commodity.Clone(&ndb)
	}

	ndb.accntdb = map[string]*Account{}
	for name, account := range db.accntdb {
		ndb.accntdb[name] = account.Clone(&ndb)
	}

	ndb.de = db.de.Clone()

	ndb.transdb = NewDB(fmt.Sprintf("%v-transactions", ndb.name))
	entries := []api.TimeEntry{}
	for _, entry := range db.transdb.Range(nil, nil, "both", entries) {
		k, ntrans := entry.Key(), entry.Value().(*Transaction).Clone(&ndb)
		ndb.transdb.Insert(k, ntrans)
	}

	ndb.pricedb = NewDB(fmt.Sprintf("%v-pricedb", ndb.name))
	entries = []api.TimeEntry{}
	for _, entry := range db.pricedb.Range(nil, nil, "both", entries) {
		k, nprice := entry.Key(), entry.Value().(*Price).Clone(&ndb)
		ndb.pricedb.Insert(k, nprice)
	}
	return &ndb
}

func (db *Datastore) addBalance(commodity *Commodity) error {
	return db.de.AddBalance(commodity)
}

// directive-account

func (db *Datastore) declare(value interface{}) error {
	switch v := value.(type) {
	case *Directive:
		d := v
		switch d.dtype {
		case "account":
			db.addAlias(d.accalias, d.accname)
			err := db.addPayee(d.accpayee, d.accname)
			if err != nil {
				return err
			}
			account := db.GetAccount(d.accname).(*Account)
			if len(d.acctypes) > 0 {
				account.types = append(account.types, d.acctypes...)
			}
			account.addNote(d.note)
			account.addAlias(d.accalias)
			account.addPayee(d.accpayee)
			account.addComments(d.comments...)
			if d.ndefault {
				db.setBalancingaccount(account.name)
			}
			db.dclrdacc = append(db.dclrdacc, d.accname)

		case "commodity":
			scanner := parsec.NewScanner([]byte(d.commdfmt))
			node, _ := NewCommodity("").Yledger(db)(scanner)
			commodity := node.(*Commodity)
			if commodity.name != d.commdname {
				x, y := commodity.name, d.commdname
				return fmt.Errorf("name mismatching %q vs %q", x, y)
			}
			commodity.addNote(d.note)
			if d.ndefault {
				db.setDefaultcomm(commodity.name)
			}
			if d.commdnmrkt {
				commodity.nomarket = true
			}
			// now finally update the datastore.commodity db.
			db.commodities[commodity.name] = commodity
			db.dclrdcomm = append(db.dclrdcomm, d.commdname)

		case "payee":
			payee := db.findpayee(d.dpayee)
			for _, alias := range d.dpayeealias {
				if err := payee.addAlias(alias); err != nil {
					return err
				}
			}
			for _, uuid := range d.dpayeeuuid {
				payee.addUuid(uuid)
			}
			db.dclrdpayee = append(db.dclrdpayee, d.dpayee)

		}
		return nil
	}
	panic("unreachable code")
}

//---- api.Reporter methods

func (db *Datastore) FmtBalances(
	_ api.Datastorer, trans api.Transactor, p api.Poster,
	acc api.Accounter) [][]string {

	var rows [][]string

	if len(db.Balances()) == 0 {
		return append(rows, []string{"", "", "-"})
	}

	for _, balance := range db.Balances() {
		rows = append(rows, []string{"", "", balance.String()})
	}
	if len(rows) > 0 { // last row to include date.
		lastrow := rows[len(rows)-1]
		date := trans.Date().Format("2006/Jan/02")
		lastrow[0] = date
	}
	return rows
}

func (db *Datastore) FmtDCBalances(
	_ api.Datastorer, trans api.Transactor, p api.Poster,
	acc api.Accounter) [][]string {

	var rows [][]string

	if len(db.Balances()) == 0 {
		return append(rows, []string{"", "", "-", "-", "-"})
	}

	for _, bal := range db.Balances() {
		name := bal.Name()
		dr, cr := db.Debit(name), db.Credit(name)
		cols := []string{"", "", dr.String(), cr.String(), bal.String()}
		rows = append(rows, cols)
	}
	if len(rows) > 0 { // last row to include date.
		lastrow := rows[len(rows)-1]
		date := trans.Date().Format("2006/Jan/02")
		lastrow[0] = date
	}
	return rows
}

func (db *Datastore) FmtEquity(
	_ api.Datastorer, trans api.Transactor, _ api.Poster,
	_ api.Accounter) [][]string {

	panic("not supported")
}

func (db *Datastore) FmtPassbook(
	_ api.Datastorer, trans api.Transactor, _ api.Poster,
	_ api.Accounter) [][]string {

	panic("not supported")
}

func (db *Datastore) FmtRegister(
	_ api.Datastorer, trans api.Transactor, p api.Poster,
	acc api.Accounter) [][]string {

	panic("not supported")
}

func (db *Datastore) defaultprices() {
	_ = []string{
		"P 01/01/2000 kb 1024b",
		"P 01/01/2000 mb 1024kb",
		"P 01/01/2000 gb 1024mb",
		"P 01/01/2000 tb 1024gb",
		"P 01/01/2000 pb 1024tb",

		"P 01/01/2000 m 60s",
		"P 01/01/2000 h 60m",
	}
}
<commit_msg>Fix error in accounting type declaration.<commit_after>package dblentry

import "fmt"
import "sort"
import "time"
import "strings"

import "github.com/prataprc/goparsec"
import "github.com/prataprc/golog"
import "github.com/tn47/goledger/api"

// ParsePhase state to be tracked at datastore.
type ParsePhase int

const (
	// DBSTART is parsing started.
	DBSTART ParsePhase = iota + 1
	// DBFIRSTPASS is all Firstpass() calls are completed.
	DBFIRSTPASS
	// DBSECONDPASS is all Secondpass() calls are completed.
	DBSECONDPASS
)

// Datastore managing accounts, commodities, transactions and posting and
// every thing else that are related.
type Datastore struct {
	// immutable from first initialization.
	name string

	// immutable once firstpass is ok
	firstpass

	// changes with every second pass.
	reporter    api.Reporter
	pass        ParsePhase
	commodities map[string]*Commodity
	accntdb     map[string]*Account // full account-name -> account
	dclrdacc    []string
	dclrdcomm   []string
	dclrdpayee  []string
	de          *DoubleEntry
	transdb     *DB
	pricedb     *DB

	// configuration
	periodtill *time.Time
}

// NewDatastore return a new datastore.
func NewDatastore(name string, reporter api.Reporter) *Datastore {
	db := &Datastore{
		name:     name,
		reporter: reporter,

		pass:        DBSTART,
		transdb:     NewDB(fmt.Sprintf("%v-transactions", name)),
		pricedb:     NewDB(fmt.Sprintf("%v-pricedb", name)),
		accntdb:     map[string]*Account{},
		commodities: map[string]*Commodity{},
		de:          NewDoubleEntry("master"),
	}
	db.initfirstpass()
	db.defaultprices()
	return db
}

//---- local accessors

func (db *Datastore) assertfirstpass() {
	if db.pass < DBFIRSTPASS {
		panic("impossible situation")
	}
}

func (db *Datastore) getCommodity(name string, defcomm *Commodity) *Commodity {
	defaultcomm := db.getDefaultcomm()
	if name == "" && defaultcomm != "" {
		return db.commodities[defaultcomm]
	}
	if defaultcomm == "" && name != "" {
		db.setDefaultcomm(name)
	}
	if comm, ok := db.commodities[name]; ok {
		return comm
	}
	log.Debugf("commodity %q added\n", name)
	if defcomm == nil {
		defcomm = NewCommodity(name)
	}
	db.commodities[name] = defcomm
	return defcomm
}

//---- exported accessors

func (db *Datastore) GetCommodity(name string) api.Commoditiser {
	return db.getCommodity(name, nil)
}

func (db *Datastore) Applytill(till time.Time) {
	periodtill := till
	db.periodtill = &periodtill
}

// Firstpassok to track parsephase
func (db *Datastore) Firstpassok() {
	db.pass = DBFIRSTPASS
}

// Secondpassok to track parsephase
func (db *Datastore) Secondpassok() {
	db.pass = DBSECONDPASS
}

// PrintAccounts is a debug api for application.
func (db *Datastore) PrintAccounts() {
	for _, accname := range db.Accountnames() {
		log.Debugf("-- %v\n", db.accntdb[accname])
	}
}

//---- api.Datastorer methods

func (db *Datastore) IsCommodityDeclared(name string) bool {
	for _, xname := range db.dclrdcomm {
		if xname == name {
			return true
		}
	}
	return false
}

func (db *Datastore) IsAccountDeclared(name string) bool {
	for _, xname := range db.dclrdacc {
		if xname == name {
			return true
		}
	}
	return false
}

func (db *Datastore) IsPayeeDeclared(name string) bool {
	for _, xname := range db.dclrdpayee {
		if xname == name {
			return true
		}
	}
	return false
}

func (db *Datastore) GetAccount(name string) api.Accounter {
	if name == "" {
		return (*Account)(nil)
	}
	account, ok := db.accntdb[name]
	if ok == false {
		account = NewAccount(name)
	}
	db.accntdb[name] = account
	return account
}

func (db *Datastore) Accountnames() []string {
	db.assertfirstpass()

	accnames := []string{}
	for name := range db.accntdb {
		accnames = append(accnames, name)
	}
	sort.Strings(accnames)
	return accnames
}

func (db *Datastore) Commoditynames() []string {
	db.assertfirstpass()

	cnames := []string{}
	for name := range db.commodities {
		cnames = append(cnames, name)
	}
	sort.Strings(cnames)
	return cnames
}

func (db *Datastore) Balance(obj interface{}) (balance api.Commoditiser) {
	db.assertfirstpass()
	return db.de.Balance(obj)
}

func (db *Datastore) Balances() []api.Commoditiser {
	db.assertfirstpass()
	return db.de.Balances()
}

func (db *Datastore) Debit(obj interface{}) (balance api.Commoditiser) {
	db.assertfirstpass()
	return db.de.Debit(obj)
}

func (db *Datastore) Debits() []api.Commoditiser {
	db.assertfirstpass()
	return db.de.Debits()
}

func (db *Datastore) Credit(obj interface{}) (balance api.Commoditiser) {
	db.assertfirstpass()
	return db.de.Credit(obj)
}

func (db *Datastore) Credits() []api.Commoditiser {
	db.assertfirstpass()
	return db.de.Credits()
}

func (db *Datastore) AggregateTotal(trans api.Transactor, p api.Poster) error {
	posting := p.(*Posting)
	names := SplitAccount(posting.account.name)
	parts := []string{}
	for _, name := range names[:len(names)-1] {
		parts = append(parts, name)
		fullname := strings.Join(parts, ":")
		consacc := db.GetAccount(fullname).(*Account)
		if err := consacc.addBalance(posting.commodity); err != nil {
			return err
		}
		err := db.reporter.BubblePosting(db, trans, posting, consacc)
		if err != nil {
			return err
		}
	}
	return nil
}

//---- engine

func (db *Datastore) Firstpass(obj interface{}) (err error) {
	if trans, ok := obj.(*Transaction); ok {
		if err := trans.Firstpass(db); err != nil {
			return err
		}
		db.setCurrentDate(trans.date)
		db.transdb.Insert(trans.date, trans)

	} else if price, ok := obj.(*Price); ok {
		err = db.pricedb.Insert(price.when, price)

	} else if directive, ok := obj.(*Directive); ok {
		err = directive.Firstpass(db)

	} else if comment, ok := obj.(*Comment); ok {
		err = comment.Firstpass(db)
		db.addComment(comment.line)
	}
	return err
}

func (db *Datastore) Secondpass() error {
	entries := []api.TimeEntry{}

	for _, entry := range db.transdb.Range(nil, nil, "both", entries) {
		trans := entry.Value().(*Transaction)
		if db.periodtill == nil || trans.Date().Before(*db.periodtill) {
			if err := trans.Secondpass(db); err != nil {
				return err
			}
		}
	}
	return nil
}

func (db *Datastore) Clone(nreporter api.Reporter) api.Datastorer {
	ndb := *db
	ndb.reporter = nreporter

	ndb.commodities = map[string]*Commodity{}
	for name, commodity := range db.commodities {
		ndb.commodities[name] = commodity.Clone(&ndb)
	}

	ndb.accntdb = map[string]*Account{}
	for name, account := range db.accntdb {
		ndb.accntdb[name] = account.Clone(&ndb)
	}

	ndb.de = db.de.Clone()

	ndb.transdb = NewDB(fmt.Sprintf("%v-transactions", ndb.name))
	entries := []api.TimeEntry{}
	for _, entry := range db.transdb.Range(nil, nil, "both", entries) {
		k, ntrans := entry.Key(), entry.Value().(*Transaction).Clone(&ndb)
		ndb.transdb.Insert(k, ntrans)
	}

	ndb.pricedb = NewDB(fmt.Sprintf("%v-pricedb", ndb.name))
	entries = []api.TimeEntry{}
	for _, entry := range db.pricedb.Range(nil, nil, "both", entries) {
		k, nprice := entry.Key(), entry.Value().(*Price).Clone(&ndb)
		ndb.pricedb.Insert(k, nprice)
	}
	return &ndb
}

func (db *Datastore) addBalance(commodity *Commodity) error {
	return db.de.AddBalance(commodity)
}

// directive-account

func (db *Datastore) declare(value interface{}) error {
	switch v := value.(type) {
	case *Directive:
		d := v
		switch d.dtype {
		case "account":
			db.addAlias(d.accalias, d.accname)
			err := db.addPayee(d.accpayee, d.accname)
			if err != nil {
				return err
			}
			account := db.GetAccount(d.accname).(*Account)
			if len(d.acctypes) > 0 {
				account.types = d.addAccounttype(d.acctypes, account.types)
			}
			account.addNote(d.note)
			account.addAlias(d.accalias)
			account.addPayee(d.accpayee)
			account.addComments(d.comments...)
			if d.ndefault {
				db.setBalancingaccount(account.name)
			}
			db.dclrdacc = append(db.dclrdacc, d.accname)

		case "commodity":
			scanner := parsec.NewScanner([]byte(d.commdfmt))
			node, _ := NewCommodity("").Yledger(db)(scanner)
			commodity := node.(*Commodity)
			if commodity.name != d.commdname {
				x, y := commodity.name, d.commdname
				return fmt.Errorf("name mismatching %q vs %q", x, y)
			}
			commodity.addNote(d.note)
			if d.ndefault {
				db.setDefaultcomm(commodity.name)
			}
			if d.commdnmrkt {
				commodity.nomarket = true
			}
			// now finally update the datastore.commodity db.
			db.commodities[commodity.name] = commodity
			db.dclrdcomm = append(db.dclrdcomm, d.commdname)

		case "payee":
			payee := db.findpayee(d.dpayee)
			for _, alias := range d.dpayeealias {
				if err := payee.addAlias(alias); err != nil {
					return err
				}
			}
			for _, uuid := range d.dpayeeuuid {
				payee.addUuid(uuid)
			}
			db.dclrdpayee = append(db.dclrdpayee, d.dpayee)

		}
		return nil
	}
	panic("unreachable code")
}

//---- api.Reporter methods

func (db *Datastore) FmtBalances(
	_ api.Datastorer, trans api.Transactor, p api.Poster,
	acc api.Accounter) [][]string {

	var rows [][]string

	if len(db.Balances()) == 0 {
		return append(rows, []string{"", "", "-"})
	}

	for _, balance := range db.Balances() {
		rows = append(rows, []string{"", "", balance.String()})
	}
	if len(rows) > 0 { // last row to include date.
		lastrow := rows[len(rows)-1]
		date := trans.Date().Format("2006/Jan/02")
		lastrow[0] = date
	}
	return rows
}

func (db *Datastore) FmtDCBalances(
	_ api.Datastorer, trans api.Transactor, p api.Poster,
	acc api.Accounter) [][]string {

	var rows [][]string

	if len(db.Balances()) == 0 {
		return append(rows, []string{"", "", "-", "-", "-"})
	}

	for _, bal := range db.Balances() {
		name := bal.Name()
		dr, cr := db.Debit(name), db.Credit(name)
		cols := []string{"", "", dr.String(), cr.String(), bal.String()}
		rows = append(rows, cols)
	}
	if len(rows) > 0 { // last row to include date.
		lastrow := rows[len(rows)-1]
		date := trans.Date().Format("2006/Jan/02")
		lastrow[0] = date
	}
	return rows
}

func (db *Datastore) FmtEquity(
	_ api.Datastorer, trans api.Transactor, _ api.Poster,
	_ api.Accounter) [][]string {

	panic("not supported")
}

func (db *Datastore) FmtPassbook(
	_ api.Datastorer, trans api.Transactor, _ api.Poster,
	_ api.Accounter) [][]string {

	panic("not supported")
}

func (db *Datastore) FmtRegister(
	_ api.Datastorer, trans api.Transactor, p api.Poster,
	acc api.Accounter) [][]string {

	panic("not supported")
}

func (db *Datastore) defaultprices() {
	_ = []string{
		"P 01/01/2000 kb 1024b",
		"P 01/01/2000 mb 1024kb",
		"P 01/01/2000 gb 1024mb",
		"P 01/01/2000 tb 1024gb",
		"P 01/01/2000 pb 1024tb",

		"P 01/01/2000 m 60s",
		"P 01/01/2000 h 60m",
	}
}
<|endoftext|>


<commit_before>// Copyright 2017 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package dbtesterpb

import (
	"image/color"
	"sort"

	"github.com/gonum/plot/plotutil"
)

// IsValidDatabaseID returns false if the database id is not supported.
func IsValidDatabaseID(id string) bool {
	_, ok := DatabaseID_value[id]
	return ok
}

// GetAllDatabaseIDs returns all database ids.
func GetAllDatabaseIDs() []string {
	var ids []string
	for k := range DatabaseID_value {
		ids = append(ids, k)
	}
	sort.Strings(ids)
	return ids
}

func GetRGBI(databaseID string, i int) color.Color {
	switch databaseID {
	case "etcd__v2_3":
		return color.RGBA{218, 97, 229, 255} // purple
	case "etcd__v3_1":
		return color.RGBA{0, 229, 255, 255} // cyan
	case "etcd__v3_2":
		return color.RGBA{63, 81, 181, 255} // indigo
	case "etcd__tip":
		return color.RGBA{24, 90, 169, 255} // blue
	case "zookeeper__r3_5_2_alpha":
		return color.RGBA{38, 169, 24, 255} // green
	case "zookeeper__r3_5_3_beta":
		return color.RGBA{229, 255, 102, 255} // green
	case "consul__v0_7_5":
		return color.RGBA{198, 53, 53, 255} // red
	case "consul__v0_8_0":
		return color.RGBA{212, 88, 102, 255} // red
	case "consul__v0_8_3":
		return color.RGBA{254, 25, 102, 255} // red
	case "zetcd__beta":
		return color.RGBA{251, 206, 0, 255} // yellow
	case "cetcd__beta":
		return color.RGBA{205, 220, 57, 255} // lime
	}
	return plotutil.Color(i)
}

func GetRGBII(databaseID string, i int) color.Color {
	switch databaseID {
	case "etcd__v2_3":
		return color.RGBA{229, 212, 231, 255} // light-purple
	case "etcd__v3_1":
		return color.RGBA{132, 255, 255, 255} // light-cyan
	case "etcd__v3_2":
		return color.RGBA{159, 168, 218, 255} // light-indigo
	case "etcd__tip":
		return color.RGBA{129, 212, 247, 255} // light-blue
	case "zookeeper__r3_5_2_alpha":
		return color.RGBA{129, 247, 152, 255} // light-green
	case "zookeeper__r3_5_3_beta":
		return color.RGBA{236, 254, 102, 255} // light-green
	case "consul__v0_7_5":
		return color.RGBA{247, 156, 156, 255} // light-red
	case "consul__v0_8_0":
		return color.RGBA{238, 148, 178, 255} // light-red
	case "consul__v0_8_3":
		return color.RGBA{255, 202, 178, 255} // light-red
	case "zetcd__beta":
		return color.RGBA{245, 247, 166, 255} // light-yellow
	case "cetcd__beta":
		return color.RGBA{238, 255, 65, 255} // light-lime
	}
	return plotutil.Color(i)
}

func GetRGBIII(databaseID string, i int) color.Color {
	switch databaseID {
	case "etcd__v2_3":
		return color.RGBA{165, 8, 180, 255} // deep-purple
	case "etcd__v3_1":
		return color.RGBA{0, 96, 100, 255} // deep-cyan
	case "etcd__v3_2":
		return color.RGBA{26, 35, 126, 255} // deep-indigo
	case "etcd__tip":
		return color.RGBA{37, 29, 191, 255} // deep-blue
	case "zookeeper__r3_5_2_alpha":
		return color.RGBA{7, 64, 35, 255} // deep-green
	case "zookeeper__r3_5_3_beta":
		return color.RGBA{129, 210, 178, 255} // deep-green
	case "consul__v0_7_5":
		return color.RGBA{212, 8, 46, 255} // deep-red
	case "consul__v0_8_0":
		return color.RGBA{251, 110, 84, 255} // deep-red
	case "consul__v0_8_3":
		return color.RGBA{245, 144, 84, 255} // deep-red
	case "zetcd__beta":
		return color.RGBA{229, 255, 0, 255} // deep-yellow
	case "cetcd__beta":
		return color.RGBA{205, 220, 57, 255} // deep-lime
	}
	return plotutil.Color(i)
}
<commit_msg>dbtesterpb: adjust colors for Zookeeper<commit_after>// Copyright 2017 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package dbtesterpb

import (
	"image/color"
	"sort"

	"github.com/gonum/plot/plotutil"
)

// IsValidDatabaseID returns false if the database id is not supported.
func IsValidDatabaseID(id string) bool {
	_, ok := DatabaseID_value[id]
	return ok
}

// GetAllDatabaseIDs returns all database ids.
func GetAllDatabaseIDs() []string {
	var ids []string
	for k := range DatabaseID_value {
		ids = append(ids, k)
	}
	sort.Strings(ids)
	return ids
}

func GetRGBI(databaseID string, i int) color.Color {
	switch databaseID {
	case "etcd__v2_3":
		return color.RGBA{218, 97, 229, 255} // purple
	case "etcd__v3_1":
		return color.RGBA{0, 229, 255, 255} // cyan
	case "etcd__v3_2":
		return color.RGBA{63, 81, 181, 255} // indigo
	case "etcd__tip":
		return color.RGBA{24, 90, 169, 255} // blue
	case "zookeeper__r3_5_3_beta":
		return color.RGBA{94, 191, 30, 255} // green
	case "consul__v0_7_5":
		return color.RGBA{198, 53, 53, 255} // red
	case "consul__v0_8_0":
		return color.RGBA{212, 88, 102, 255} // red
	case "consul__v0_8_3":
		return color.RGBA{254, 25, 102, 255} // red
	case "zetcd__beta":
		return color.RGBA{251, 206, 0, 255} // yellow
	case "cetcd__beta":
		return color.RGBA{205, 220, 57, 255} // lime
	}
	return plotutil.Color(i)
}

func GetRGBII(databaseID string, i int) color.Color {
	switch databaseID {
	case "etcd__v2_3":
		return color.RGBA{229, 212, 231, 255} // light-purple
	case "etcd__v3_1":
		return color.RGBA{132, 255, 255, 255} // light-cyan
	case "etcd__v3_2":
		return color.RGBA{159, 168, 218, 255} // light-indigo
	case "etcd__tip":
		return color.RGBA{129, 212, 247, 255} // light-blue
	case "zookeeper__r3_5_3_beta":
		return color.RGBA{155, 176, 29, 255} // light-green
	case "consul__v0_7_5":
		return color.RGBA{247, 156, 156, 255} // light-red
	case "consul__v0_8_0":
		return color.RGBA{238, 148, 178, 255} // light-red
	case "consul__v0_8_3":
		return color.RGBA{255, 202, 178, 255} // light-red
	case "zetcd__beta":
		return color.RGBA{245, 247, 166, 255} // light-yellow
	case "cetcd__beta":
		return color.RGBA{238, 255, 65, 255} // light-lime
	}
	return plotutil.Color(i)
}

func GetRGBIII(databaseID string, i int) color.Color {
	switch databaseID {
	case "etcd__v2_3":
		return color.RGBA{165, 8, 180, 255} // deep-purple
	case "etcd__v3_1":
		return color.RGBA{0, 96, 100, 255} // deep-cyan
	case "etcd__v3_2":
		return color.RGBA{26, 35, 126, 255} // deep-indigo
	case "etcd__tip":
		return color.RGBA{37, 29, 191, 255} // deep-blue
	case "zookeeper__r3_5_3_beta":
		return color.RGBA{129, 210, 178, 255} // mid-cyan
	case "consul__v0_7_5":
		return color.RGBA{212, 8, 46, 255} // deep-red
	case "consul__v0_8_0":
		return color.RGBA{251, 110, 84, 255} // deep-red
	case "consul__v0_8_3":
		return color.RGBA{245, 144, 84, 255} // deep-red
	case "zetcd__beta":
		return color.RGBA{229, 255, 0, 255} // deep-yellow
	case "cetcd__beta":
		return color.RGBA{205, 220, 57, 255} // deep-lime
	}
	return plotutil.Color(i)
}
<|endoftext|>


<commit_before>package main

/*
conference.go -- server-side Go App Engine API;
    uses Google Cloud Endpoints

*/

import (
	"log"
	"github.com/GoogleCloudPlatform/go-endpoints/endpoints"
	"net/http"
)

type ConferenceApi struct {
}

func copyProfileToForm(r *http.Request, prof *Profile) (*ProfileForm, error) {
	//Copy relevant fields from Profile to ProfileForm.
	pf := &ProfileForm{
			DisplayName: prof.DisplayName,
			MainEmail: prof.MainEmail,
			TeeShirtSize: StringEnumToTeeShirtSize(prof.TeeShirtSize),
	}
	return pf, nil
}

func getProfileFromUser(r *http.Request) (*Profile, error) {
	//Return user Profile from datastore, creating new one if non-existent.
	//TODO
	//make sure user is authed
	//c := endpoints.NewContext(r)
	//user, err := endpoints.CurrentUser(c, []string{endpoints.EmailScope},
	//	[]string{WEB_CLIENT_ID, endpoints.APIExplorerClientID}, []string{WEB_CLIENT_ID, endpoints.APIExplorerClientID})
	//if err != nil {
	//	return nil, err
	//}
	//if user == nil {
	//	return nil, endpoints.UnauthorizedError
	//}
	var profile *Profile
	if profile == nil {
		profile = &Profile{
			DisplayName: "Test",
			MainEmail: "",
			TeeShirtSize: TeeShirtSizeToStringEnum(NOT_SPECIFIED),
		}
		//TODO
	}
	return profile, nil
}

func doProfile(r *http.Request, saveRequest *ProfileMiniForm) (*ProfileForm, error) {
	//Get user Profile and return to user, possibly updating it first.
	//get user Profile
	prof, err := getProfileFromUser(r)
	if err != nil {
		return nil, err
	}

	//if saveProfile(), process user-modifyable fields
	if saveRequest != nil {
		prof.TeeShirtSize = TeeShirtSizeToStringEnum(saveRequest.TeeShirtSize)
		prof.DisplayName = saveRequest.DisplayName
	}

	//return ProfileForm
	return copyProfileToForm(r, prof)
}

func (h *ConferenceApi) GetProfile(r *http.Request) (*ProfileForm, error) {
	//Return user profile.
	return doProfile(r, nil)
}

func (h *ConferenceApi) SaveProfile(r *http.Request) (*ProfileForm, error) {
	//Update & return user profile.
	return doProfile(r, nil)
}

func init() {
	//Conference API v0.1
	conference := &ConferenceApi{}
	//registers API
	api, err := endpoints.RegisterService(conference, "conference", "v1", "Conference API", true)
	if err != nil {
		log.Fatalf("Register service: %v", err)
	}

	register := func(orig, name, method, path, desc string) {
		m := api.MethodByName(orig)
		if m == nil {
			log.Fatalf("Missing method %s", orig)
		}
		i := m.Info()
		i.Name, i.HTTPMethod, i.Path, i.Desc = name, method, path, desc
		i.Scopes = []string{endpoints.EmailScope}
		i.ClientIds = []string{WEB_CLIENT_ID, endpoints.APIExplorerClientID}
	}

	register("GetProfile", "getProfile", "GET", "profile", "Get profile")
	register("SaveProfile", "saveProfile", "POST", "profile", "Save profile")
	endpoints.HandleHTTP()
}
<commit_msg>changed how user-modified fields processed in lines 64-69 - empty fields allow defaults or previous values to persist in lab 3<commit_after>package main

/*
conference.go -- server-side Go App Engine API;
    uses Google Cloud Endpoints

*/

import (
	"log"
	"github.com/GoogleCloudPlatform/go-endpoints/endpoints"
	"net/http"
)

type ConferenceApi struct {
}

func copyProfileToForm(r *http.Request, prof *Profile) (*ProfileForm, error) {
	//Copy relevant fields from Profile to ProfileForm.
	pf := &ProfileForm{
			DisplayName: prof.DisplayName,
			MainEmail: prof.MainEmail,
			TeeShirtSize: StringEnumToTeeShirtSize(prof.TeeShirtSize),
	}
	return pf, nil
}

func getProfileFromUser(r *http.Request) (*Profile, error) {
	//Return user Profile from datastore, creating new one if non-existent.
	//TODO
	//make sure user is authed
	//c := endpoints.NewContext(r)
	//user, err := endpoints.CurrentUser(c, []string{endpoints.EmailScope},
	//	[]string{WEB_CLIENT_ID, endpoints.APIExplorerClientID}, []string{WEB_CLIENT_ID, endpoints.APIExplorerClientID})
	//if err != nil {
	//	return nil, err
	//}
	//if user == nil {
	//	return nil, endpoints.UnauthorizedError
	//}
	var profile *Profile
	if profile == nil {
		profile = &Profile{
			DisplayName: "Test",
			MainEmail: "",
			TeeShirtSize: TeeShirtSizeToStringEnum(NOT_SPECIFIED),
		}
		//TODO
	}
	return profile, nil
}

func doProfile(r *http.Request, saveRequest *ProfileMiniForm) (*ProfileForm, error) {
	//Get user Profile and return to user, possibly updating it first.
	//get user Profile
	prof, err := getProfileFromUser(r)
	if err != nil {
		return nil, err
	}

	//if saveProfile(), process user-modifyable fields
	if saveRequest != nil {
		if saveRequest.DisplayName != "" {
			prof.DisplayName = saveRequest.DisplayName
		}
		if TeeShirtSizeToStringEnum(saveRequest.TeeShirtSize) != "" {
			prof.TeeShirtSize = TeeShirtSizeToStringEnum(saveRequest.TeeShirtSize)
		}
	}
	//return ProfileForm
	return copyProfileToForm(r, prof)
}

func (h *ConferenceApi) GetProfile(r *http.Request) (*ProfileForm, error) {
	//Return user profile.
	return doProfile(r, nil)
}

func (h *ConferenceApi) SaveProfile(r *http.Request) (*ProfileForm, error) {
	//Update & return user profile.
	return doProfile(r, nil)
}

func init() {
	//Conference API v0.1
	conference := &ConferenceApi{}
	//registers API
	api, err := endpoints.RegisterService(conference, "conference", "v1", "Conference API", true)
	if err != nil {
		log.Fatalf("Register service: %v", err)
	}

	register := func(orig, name, method, path, desc string) {
		m := api.MethodByName(orig)
		if m == nil {
			log.Fatalf("Missing method %s", orig)
		}
		i := m.Info()
		i.Name, i.HTTPMethod, i.Path, i.Desc = name, method, path, desc
		i.Scopes = []string{endpoints.EmailScope}
		i.ClientIds = []string{WEB_CLIENT_ID, endpoints.APIExplorerClientID}
	}

	register("GetProfile", "getProfile", "GET", "profile", "Get profile")
	register("SaveProfile", "saveProfile", "POST", "profile", "Save profile")
	endpoints.HandleHTTP()
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"strings"

	"github.com/m-nakada/slackposter"
)

type GitHubAPI struct {
	AccessToken string
	Owner       string
	Repo        string
	UsersMap    UsersMap
}

type PullRequest struct {
	Assignees []struct {
		Login string `json:"login"`
	} `json:"assignees"`
	ClosedAt  interface{} `json:"closed_at"`
	CreatedAt string      `json:"created_at"`
	HTMLURL   string      `json:"html_url"`
	ID        int64       `json:"id"`
	IssueURL  string      `json:"issue_url"`
	Number    int64       `json:"number"`
	State     string      `json:"state"`
	Title     string      `json:"title"`
	UpdatedAt string      `json:"updated_at"`
	URL       string      `json:"url"`
	User      struct {
		Login string `json:"login"`
	} `json:"user"`
}

func (pr PullRequest) SlackAttachment(usersMap UsersMap) slackposter.Attachment {
	attachment := slackposter.Attachment{
		Fallback: fmt.Sprintf("#%d, %s (%s)", pr.Number, pr.Title, pr.HTMLURL, pr.assigneesString(usersMap, true)),
		Text:     pr.titleString() + " " + pr.assigneesString(usersMap, true),
		Color:    "warning",
	}

	return attachment
}

func (pr PullRequest) titleString() string {
	return fmt.Sprintf("\t<%s|#%d, %s>", pr.HTMLURL, pr.Number, pr.Title)
}

func (pr PullRequest) assigneesString(usersMap UsersMap, needsArrow bool) string {
	var str = ""
	if needsArrow && len(pr.Assignees) > 0 {
		str += " => "
	}
	for _, assignee := range pr.Assignees {
		name := assignee.Login
		if v, ok := usersMap[assignee.Login]; ok {
			name = v
		}
		str += "@" + name + " "
	}

	return str
}

func (pr PullRequest) SlackMessage(usersMap UsersMap) string {
	var str = pr.titleString()
	str += pr.assigneesString(usersMap, true)
	str += "\n"
	return str
}

func isWIP(title string) bool {
	return strings.Contains(strings.ToUpper(title), "WIP")
}

func filterdPulls(pulls []PullRequest) []PullRequest {
	var array []PullRequest
	for _, pull := range pulls {
		if isWIP(pull.Title) {
			continue
		}
		array = append(array, pull)
	}
	return array
}

func headerString(owner string, repo string, pullsCount int) string {
	url := "https://github.com/" + owner + "/" + repo
	link := fmt.Sprintf("<%s|%s/%s>", url, owner, repo)

	var summary string
	switch pullsCount {
	case 0:
		summary = fmt.Sprintf("There's no open pull request for %s :tada: Let's take a break :dango: :tea:", link)
	case 1:
		summary = fmt.Sprintf("There's only one open pull request for %s :point_up:", link)
	default:
		summary = fmt.Sprintf("I found %d open pull requests for %s:\n", pullsCount, link)
	}
	return summary
}

func (gh GitHubAPI) SlackPayload(pulls []PullRequest) slackposter.Payload {
	var payload slackposter.Payload

	if len(pulls) == 0 {
		return payload
	}

	filterd := filterdPulls(pulls)
	var attachments []slackposter.Attachment

	for _, pull := range filterd {
		attachment := pull.SlackAttachment(gh.UsersMap)
		attachments = append(attachments, attachment)
	}

	payload.Text = headerString(gh.Owner, gh.Repo, len(filterd))
	payload.Attachments = attachments

	return payload
}

func (gh GitHubAPI) SlackMessage(pulls []PullRequest) string {
	if len(pulls) == 0 {
		return ""
	}

	filterd := filterdPulls(pulls)
	var str = headerString(gh.Owner, gh.Repo, len(filterd))
	for _, pull := range filterd {
		str += pull.SlackMessage(gh.UsersMap)
	}
	return str
}

func (gh GitHubAPI) urlString() string {
	return "https://api.github.com/repos/" + gh.Owner + "/" + gh.Repo + "/pulls" + "?access_token=" + gh.AccessToken
}

func (gh GitHubAPI) GetPulls() ([]PullRequest, error) {
	var pulls []PullRequest

	// Prepare HTTP Request
	url := gh.urlString()
	req, err := http.NewRequest("GET", url, nil)

	parseFormErr := req.ParseForm()
	if parseFormErr != nil {
		fmt.Fprintln(os.Stderr, "[Error] Parse HTTP request form:", parseFormErr)
		return pulls, parseFormErr
	}

	// Fetch Request
	client := &http.Client{}
	res, err := client.Do(req)
	if err != nil {
		fmt.Fprintln(os.Stderr, "[Error] Fetch pulls: ", err)
		return pulls, err
	}

	// Read Response Body
	resBody, _ := ioutil.ReadAll(res.Body)

	// Decode JSON
	if err := json.Unmarshal(resBody, &pulls); err != nil {
		fmt.Fprintln(os.Stderr, "[Error] JSON unmarshal:", err)
		return pulls, err
	}

	return pulls, nil
}

func NewGitHubAPI(config Config) GitHubAPI {
	var gh = GitHubAPI{}
	gh.AccessToken = config.GitHub.AccessToken
	gh.Owner = config.GitHub.Owner
	gh.Repo = config.GitHub.Repo
	return gh
}
<commit_msg>Fix function name<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"strings"

	"github.com/m-nakada/slackposter"
)

type GitHubAPI struct {
	AccessToken string
	Owner       string
	Repo        string
	UsersMap    UsersMap
}

type PullRequest struct {
	Assignees []struct {
		Login string `json:"login"`
	} `json:"assignees"`
	ClosedAt  interface{} `json:"closed_at"`
	CreatedAt string      `json:"created_at"`
	HTMLURL   string      `json:"html_url"`
	ID        int64       `json:"id"`
	IssueURL  string      `json:"issue_url"`
	Number    int64       `json:"number"`
	State     string      `json:"state"`
	Title     string      `json:"title"`
	UpdatedAt string      `json:"updated_at"`
	URL       string      `json:"url"`
	User      struct {
		Login string `json:"login"`
	} `json:"user"`
}

func (pr PullRequest) SlackAttachment(usersMap UsersMap) slackposter.Attachment {
	attachment := slackposter.Attachment{
		Fallback: fmt.Sprintf("#%d, %s (%s)", pr.Number, pr.Title, pr.HTMLURL, pr.assigneesString(usersMap, true)),
		Text:     pr.titleString() + " " + pr.assigneesString(usersMap, true),
		Color:    "warning",
	}

	return attachment
}

func (pr PullRequest) titleString() string {
	return fmt.Sprintf("\t<%s|#%d, %s>", pr.HTMLURL, pr.Number, pr.Title)
}

func (pr PullRequest) assigneesString(usersMap UsersMap, needsArrow bool) string {
	var str = ""
	if needsArrow && len(pr.Assignees) > 0 {
		str += " => "
	}
	for _, assignee := range pr.Assignees {
		name := assignee.Login
		if v, ok := usersMap[assignee.Login]; ok {
			name = v
		}
		str += "@" + name + " "
	}

	return str
}

func (pr PullRequest) SlackMessage(usersMap UsersMap) string {
	var str = pr.titleString()
	str += pr.assigneesString(usersMap, true)
	str += "\n"
	return str
}

func isWIP(title string) bool {
	return strings.Contains(strings.ToUpper(title), "WIP")
}

func filterdPulls(pulls []PullRequest) []PullRequest {
	var array []PullRequest
	for _, pull := range pulls {
		if isWIP(pull.Title) {
			continue
		}
		array = append(array, pull)
	}
	return array
}

func summaryString(owner string, repo string, pullsCount int) string {
	url := "https://github.com/" + owner + "/" + repo
	link := fmt.Sprintf("<%s|%s/%s>", url, owner, repo)

	var summary string
	switch pullsCount {
	case 0:
		summary = fmt.Sprintf("There's no open pull request for %s :tada: Let's take a break :dango: :tea:", link)
	case 1:
		summary = fmt.Sprintf("There's only one open pull request for %s :point_up:", link)
	default:
		summary = fmt.Sprintf("I found %d open pull requests for %s:\n", pullsCount, link)
	}
	return summary
}

func (gh GitHubAPI) SlackPayload(pulls []PullRequest) slackposter.Payload {
	var payload slackposter.Payload

	if len(pulls) == 0 {
		return payload
	}

	filterd := filterdPulls(pulls)
	var attachments []slackposter.Attachment

	for _, pull := range filterd {
		attachment := pull.SlackAttachment(gh.UsersMap)
		attachments = append(attachments, attachment)
	}

	payload.Text = summaryString(gh.Owner, gh.Repo, len(filterd))
	payload.Attachments = attachments

	return payload
}

func (gh GitHubAPI) SlackMessage(pulls []PullRequest) string {
	if len(pulls) == 0 {
		return ""
	}

	filterd := filterdPulls(pulls)
	var str = summaryString(gh.Owner, gh.Repo, len(filterd))
	for _, pull := range filterd {
		str += pull.SlackMessage(gh.UsersMap)
	}
	return str
}

func (gh GitHubAPI) urlString() string {
	return "https://api.github.com/repos/" + gh.Owner + "/" + gh.Repo + "/pulls" + "?access_token=" + gh.AccessToken
}

func (gh GitHubAPI) GetPulls() ([]PullRequest, error) {
	var pulls []PullRequest

	// Prepare HTTP Request
	url := gh.urlString()
	req, err := http.NewRequest("GET", url, nil)

	parseFormErr := req.ParseForm()
	if parseFormErr != nil {
		fmt.Fprintln(os.Stderr, "[Error] Parse HTTP request form:", parseFormErr)
		return pulls, parseFormErr
	}

	// Fetch Request
	client := &http.Client{}
	res, err := client.Do(req)
	if err != nil {
		fmt.Fprintln(os.Stderr, "[Error] Fetch pulls: ", err)
		return pulls, err
	}

	// Read Response Body
	resBody, _ := ioutil.ReadAll(res.Body)

	// Decode JSON
	if err := json.Unmarshal(resBody, &pulls); err != nil {
		fmt.Fprintln(os.Stderr, "[Error] JSON unmarshal:", err)
		return pulls, err
	}

	return pulls, nil
}

func NewGitHubAPI(config Config) GitHubAPI {
	var gh = GitHubAPI{}
	gh.AccessToken = config.GitHub.AccessToken
	gh.Owner = config.GitHub.Owner
	gh.Repo = config.GitHub.Repo
	return gh
}
<|endoftext|>


<commit_before>// Broadcast over channels.
package bcast

/*
   bcast package for Go. Broadcasting on a set of channels.

   Copyright © 2013 Alexander I.Grafov <grafov@gmail.com>.
   All rights reserved.
   Use of this source code is governed by a BSD-style
   license that can be found in the LICENSE file.
*/

import (
	"time"
	"sync"
)

// Internal structure to pack messages together with info about sender.
type Message struct {
	sender  chan interface{}
	payload interface{}
}

// Represents member of broadcast group.
type Member struct {
	group *Group           // send messages to others directly to group.In
	In    chan interface{} // (public) get messages from others to own channel
}

// Represents broadcast group.
type Group struct {
	l   sync.Mutex
	in  chan Message       // receive broadcasts from members
	out []chan interface{} // broadcast messages to members
	count int

}

// Create new broadcast group.
func NewGroup() *Group {
	in := make(chan Message)
	return &Group{in: in}
}

func (r *Group) MemberCount() int {
	return r.count
}

func (r *Group) Members() []chan interface{} {
	r.l.Lock()
	res := r.out[:]
	r.count = len(r.out)
	r.l.Unlock()
	return res
}

func (r *Group) Add(out chan interface{}) {
	r.l.Lock()
	r.out = append(r.out, out)
	r.count = len(r.out)
	r.l.Unlock()
	return
}

func (r *Group) Remove(received Message) {
	r.l.Lock()
	for i, addr := range r.out {
		if addr == received.payload.(Member).In && received.sender == received.payload.(Member).In {
			r.out = append(r.out[:i], r.out[i+1:]...)
			break
		}
	}
	r.l.Unlock()
	return
}

// Broadcast messages received from one group member to others.
// If incoming messages not arrived during `timeout` then function returns.
// Set `timeout` to zero to set unlimited timeout or use Broadcasting().
func (r *Group) Broadcasting(timeout time.Duration) {
	for {
		select {
		case received := <-r.in:
			switch received.payload.(type) {
			default: // receive a payload and broadcast it
					for _, member := range r.Members() {
						if received.sender != member { // not return broadcast to sender

							go func(out chan interface{}, received *Message) { // non blocking
								out <- received.payload
							}(member, &received)

						}
					}
			}
		case <-time.After(timeout):
			if timeout > 0 {
				return
			}
		}
	}
}

// Broadcast message to all group members.
func (r *Group) Send(val interface{}) {
	r.in <- Message{sender: nil, payload: val}
}

// Join new member to broadcast.
func (r *Group) Join() *Member {
	out := make(chan interface{})
	r.Add(out)
	//r.out = append(r.out, out)
	return &Member{group: r, In: out}
}

// Unjoin member from broadcast group.
func (r *Member) Close() {
	r.group.Remove(Message{sender: r.In, payload: *r})
	//r.group.in <- Message{sender: r.In, payload: *r} // broadcasting of self means member closing
}

// Broadcast message from one member to others except sender.
func (r *Member) Send(val interface{}) {
	r.group.in <- Message{sender: r.In, payload: val}
}

// Get broadcast message.
// As alternative you may get it from `In` channel.
func (r *Member) Recv() interface{} {
	return <-r.In
}
<commit_msg>fix in remove calculate the new membercount<commit_after>// Broadcast over channels.
package bcast

/*
   bcast package for Go. Broadcasting on a set of channels.

   Copyright © 2013 Alexander I.Grafov <grafov@gmail.com>.
   All rights reserved.
   Use of this source code is governed by a BSD-style
   license that can be found in the LICENSE file.
*/

import (
	"time"
	"sync"
)

// Internal structure to pack messages together with info about sender.
type Message struct {
	sender  chan interface{}
	payload interface{}
}

// Represents member of broadcast group.
type Member struct {
	group *Group           // send messages to others directly to group.In
	In    chan interface{} // (public) get messages from others to own channel
}

// Represents broadcast group.
type Group struct {
	l   sync.Mutex
	in  chan Message       // receive broadcasts from members
	out []chan interface{} // broadcast messages to members
	count int

}

// Create new broadcast group.
func NewGroup() *Group {
	in := make(chan Message)
	return &Group{in: in}
}

func (r *Group) MemberCount() int {
	return r.count
}

func (r *Group) Members() []chan interface{} {
	r.l.Lock()
	res := r.out[:]
	r.count = len(r.out)
	r.l.Unlock()
	return res
}

func (r *Group) Add(out chan interface{}) {
	r.l.Lock()
	r.out = append(r.out, out)
	r.count = len(r.out)
	r.l.Unlock()
	return
}

func (r *Group) Remove(received Message) {
	r.l.Lock()
	for i, addr := range r.out {
		if addr == received.payload.(Member).In && received.sender == received.payload.(Member).In {
			r.out = append(r.out[:i], r.out[i+1:]...)
      r.count = len(r.out)
			break
		}
	}
	r.l.Unlock()
	return
}

// Broadcast messages received from one group member to others.
// If incoming messages not arrived during `timeout` then function returns.
// Set `timeout` to zero to set unlimited timeout or use Broadcasting().
func (r *Group) Broadcasting(timeout time.Duration) {
	for {
		select {
		case received := <-r.in:
			switch received.payload.(type) {
			default: // receive a payload and broadcast it
					for _, member := range r.Members() {
						if received.sender != member { // not return broadcast to sender

							go func(out chan interface{}, received *Message) { // non blocking
								out <- received.payload
							}(member, &received)

						}
					}
			}
		case <-time.After(timeout):
			if timeout > 0 {
				return
			}
		}
	}
}

// Broadcast message to all group members.
func (r *Group) Send(val interface{}) {
	r.in <- Message{sender: nil, payload: val}
}

// Join new member to broadcast.
func (r *Group) Join() *Member {
	out := make(chan interface{})
	r.Add(out)
	//r.out = append(r.out, out)
	return &Member{group: r, In: out}
}

// Unjoin member from broadcast group.
func (r *Member) Close() {
	r.group.Remove(Message{sender: r.In, payload: *r})
	//r.group.in <- Message{sender: r.In, payload: *r} // broadcasting of self means member closing
}

// Broadcast message from one member to others except sender.
func (r *Member) Send(val interface{}) {
	r.group.in <- Message{sender: r.In, payload: val}
}

// Get broadcast message.
// As alternative you may get it from `In` channel.
func (r *Member) Recv() interface{} {
	return <-r.In
}
<|endoftext|>


<commit_before>// Package main is a script that reads a filesystem full of dcm files and
// generates a json report.
package main

import (
	"encoding/binary"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	// "strconv"
	"log"
	"strings"

	"github.com/davidgamba/go-dicom/dcmdump/tag"
	"github.com/davidgamba/go-dicom/dcmdump/ts"
	vri "github.com/davidgamba/go-dicom/dcmdump/vr"
	"github.com/davidgamba/go-getoptions"
)

var debug bool

func debugf(format string, a ...interface{}) (n int, err error) {
	if debug {
		return fmt.Printf(format, a...)
	}
	return 0, nil
}
func debugln(a ...interface{}) (n int, err error) {
	if debug {
		return fmt.Println(a...)
	}
	return 0, nil
}

type stringSlice []string

func (s stringSlice) contains(a string) bool {
	for _, b := range s {
		if a == b {
			return true
		}
	}
	return false
}

type dicomqr struct {
	Empty [128]byte
	DICM  [4]byte
	Rest  []byte
}

// DataElement -
type DataElement struct {
	N        int
	TagGroup []byte // [2]byte
	TagElem  []byte // [2]byte
	TagStr   string
	VR       []byte // [2]byte
	VRStr    string
	VRLen    int
	Len      uint32
	Data     []byte
	PartOfSQ bool
}

// String -
func (de *DataElement) String() string {
	tn := tag.Tag[de.TagStr]["name"]
	if _, ok := tag.Tag[de.TagStr]; !ok {
		tn = "MISSING"
	}
	padding := ""
	if de.PartOfSQ {
		padding = "    "
	}
	if de.Len < 128 {
		return fmt.Sprintf("%s%04d (%s) %s %d %d %s %s", padding, de.N, de.TagStr, de.VRStr, de.VRLen, de.Len, tn, de.stringData())
	}
	return fmt.Sprintf("%s%04d (%s) %s %d %d %s %s", padding, de.N, de.TagStr, de.VRStr, de.VRLen, de.Len, tn, "...")
}

type fh os.File

func readNBytes(f *os.File, size int) ([]byte, error) {
	data := make([]byte, size)
	for {
		data = data[:cap(data)]
		n, err := f.Read(data)
		if err != nil {
			if err == io.EOF {
				break
			}
			return nil, err
		}
		data = data[:n]
	}
	return data, nil
}

// http://rosettacode.org/wiki/Strip_control_codes_and_extended_characters_from_a_string#Go
// two UTF-8 functions identical except for operator comparing c to 127
func stripCtlFromUTF8(str string) string {
	return strings.Map(func(r rune) rune {
		if r >= 32 && r != 127 {
			return r
		}
		return '.'
	}, str)
}

func tagString(b []byte) string {
	tag := strings.ToUpper(fmt.Sprintf("%02x%02x%02x%02x", b[1], b[0], b[3], b[2]))
	return tag
}

func printBytes(b []byte) {
	if !debug {
		return
	}
	l := len(b)
	var s string
	for i := 0; i < l; i++ {
		s += stripCtlFromUTF8(string(b[i]))
		if i != 0 && i%8 == 0 {
			if i%16 == 0 {
				fmt.Printf(" - %s\n", s)
				s = ""
			} else {
				fmt.Printf(" - ")
			}
		}
		fmt.Printf("%2x ", b[i])
		if i == l-1 {
			if 15-i%16 > 7 {
				fmt.Printf(" - ")
			}
			for j := 0; j < 15-i%16; j++ {
				// fmt.Printf("   ")
				fmt.Printf("   ")
			}
			fmt.Printf(" - %s\n", s)
			s = ""
		}
	}
	fmt.Printf("\n")
}

func (de *DataElement) stringData() string {
	if de.TagStr == "00020010" {
		if tsStr, ok := ts.TS[string(de.Data)]; ok {
			return string(de.Data) + " " + tsStr["name"].(string)
		}
	}
	if _, ok := vri.VR[de.VRStr]["fixed"]; ok && vri.VR[de.VRStr]["fixed"].(bool) {
		s := ""
		l := len(de.Data)
		n := 0
		vrl := vri.VR[de.VRStr]["len"].(int)
		switch vrl {
		case 1:
			for n+1 <= l {
				s += fmt.Sprintf("%d ", de.Data[n])
				n++
			}
			return s
		case 2:
			for n+2 <= l {
				e := binary.LittleEndian.Uint16(de.Data[n : n+2])
				s += fmt.Sprintf("%d ", e)
				n += 2
			}
			return s
		case 4:
			for n+4 <= l {
				e := binary.LittleEndian.Uint32(de.Data[n : n+4])
				s += fmt.Sprintf("%d ", e)
				n += 4
			}
			return s
		default:
			return string(de.Data)
		}
	} else {
		if _, ok := vri.VR[de.VRStr]["padded"]; ok && vri.VR[de.VRStr]["padded"].(bool) {
			l := len(de.Data)
			if de.Data[l-1] == 0x0 {
				return string(de.Data[:l-1])
			}
			return string(de.Data)
		}
		return string(de.Data)
	}
}

func parseDataElement(bytes []byte, n int, explicit bool) {
	log.Printf("parseDataElement")
	l := len(bytes)
	// Data element
	m := n
	for n <= l && m+4 <= l {
		undefinedLen := false
		de := DataElement{N: n}
		m += 4
		t := bytes[n:m]
		de.TagGroup = bytes[n : n+2]
		de.TagElem = bytes[n+2 : n+4]
		de.TagStr = tagString(t)
		// TODO: Clean up tagString
		tagStr := tagString(t)
		log.Printf("n: %d, Tag: %X -> %s\n", n, t, tagStr)
		printBytes(bytes[n:m])
		n = m
		if tagStr == "" {
			log.Printf("%d Empty Tag: %s\n", n, tagStr)
		} else if _, ok := tag.Tag[tagStr]; !ok {
			fmt.Fprintf(os.Stderr, "INFO: %d Missing tag '%s'\n", n, tagStr)
		} else {
			log.Printf("Tag Name: %s\n", tag.Tag[tagStr]["name"])
		}
		var len uint32
		var vr string
		if explicit {
			debugf("%d VR\n", n)
			m += 2
			printBytes(bytes[n:m])
			de.VR = bytes[n:m]
			de.VRStr = string(bytes[n:m])
			vr = string(bytes[n:m])
			if _, ok := vri.VR[vr]; !ok {
				if bytes[n] == 0x0 && bytes[n+1] == 0x0 {
					fmt.Fprintf(os.Stderr, "INFO: Blank VR\n")
					vr = "00"
					de.VRStr = "00"
				} else {
					fmt.Fprintf(os.Stderr, "ERROR: %d Missing VR '%s'\n", n, vr)
					printBytes(bytes[n:])
					return
				}
			}
			n = m
			if vr == "OB" ||
				vr == "OD" ||
				vr == "OF" ||
				vr == "OL" ||
				vr == "OW" ||
				vr == "SQ" ||
				vr == "UC" ||
				vr == "UR" ||
				vr == "UT" ||
				vr == "UN" {
				debugln("Reserved")
				m += 2
				printBytes(bytes[n:m])
				n = m
				debugln("Lenght")
				m += 4
				printBytes(bytes[n:m])
				len = binary.LittleEndian.Uint32(bytes[n:m])
				n = m
			} else {
				debugln("Lenght")
				m += 2
				printBytes(bytes[n:m])
				len16 := binary.LittleEndian.Uint16(bytes[n:m])
				len = uint32(len16)
				n = m
			}
		} else {
			debugln("Lenght")
			m += 4
			printBytes(bytes[n:m])
			len = binary.LittleEndian.Uint32(bytes[n:m])
			n = m
		}
		if len == 0xFFFFFFFF {
			undefinedLen = true
			for {
				// Find FFFEE0DD: SequenceDelimitationItem
				endTag := bytes[m : m+4]
				endTagStr := tagString(endTag)
				if endTagStr == "FFFEE0DD" {
					log.Printf("found SequenceDelimitationItem at %d", m)
					len = uint32(m - n)
					m = n
					break
				} else {
					m++
					if m >= l {
						fmt.Fprintf(os.Stderr, "ERROR: Couldn't find SequenceDelimitationItem\n")
						printBytes(bytes[n:l])
						return
					}
				}
			}
		}
		de.Len = len
		debugf("Lenght: %d\n", len)
		m += int(len)
		printBytes(bytes[n:m])
		if vr == "SQ" {
			de.Data = []byte{}
			fmt.Println(de.String())
			log.Printf("parseDataElement SQ")
			if undefinedLen {
				m += 8
			}
			parseDataElement(bytes[n:m], n, explicit)
			log.Printf("parseDataElement SQ Complete")
		} else {
			de.Data = bytes[n:m]
			fmt.Println(de.String())
			if undefinedLen {
				m += 8
			}
		}
		n = m
	}
	log.Printf("parseDataElement Complete")
}

func parseSQDataElements(bytes []byte, n int, explicit bool) int {
	log.Printf("parseSQDataElements")
	l := len(bytes)
	m := n
	for n <= l && m+4 <= l {
		de := DataElement{N: n}
		m := n + 4
		printBytes(bytes[n:m])
		t := bytes[n:m]
		tagStr := tagString(t)
		de.TagGroup = bytes[n : n+2]
		de.TagElem = bytes[n+2 : n+4]
		de.TagStr = tagString(t)
		log.Printf("n: %d, Tag: %X -> %s\n", n, t, tagStr)
		if _, ok := tag.Tag[tagStr]; !ok {
			fmt.Fprintf(os.Stderr, "ERROR: %d Missing tag '%s'\n", n, tagStr)
		}
		// if _, ok := tag.Tag[tagStr]; ok && tag.Tag[tagStr]["name"] == "ItemDelimitationItem" {
		// 	sequenceDelimitationItem = true
		// }
		for m <= l {
			// Find FFFEE00D: ItemDelimitationItem
			endTag := bytes[m : m+4]
			endTagStr := tagString(endTag)
			if endTagStr == "FFFEE00D" {
				debugln("Item Delim found")
				de.Data = bytes[n:m]
				printBytes(bytes[n:m])
				log.Printf("Tag: %X -> %s\n", endTag, endTagStr)
				m += 4
				n = m
				// m += 4
				// printBytes(bytes[n:m])
				// n = m
				break
			} else {
				m++
			}
		}
		fmt.Println(de.String())
	}
	log.Printf("parseSQDataElement Complete")
	return n
}

func synopsis() {
	synopsis := `dcmdump <dcm_file> [--debug]
`
	fmt.Fprintln(os.Stderr, synopsis)
}

func main() {

	var file string
	opt := getoptions.New()
	opt.Bool("help", false)
	opt.BoolVar(&debug, "debug", false)
	remaining, err := opt.Parse(os.Args[1:])
	if err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: %s\n", err)
		os.Exit(1)
	}
	if opt.Called("help") {
		synopsis()
		os.Exit(1)
	}
	if len(remaining) < 1 {
		fmt.Fprintf(os.Stderr, "ERROR: Missing file\n")
		synopsis()
		os.Exit(1)
	}
	file = remaining[0]
	if !debug {
		log.SetOutput(ioutil.Discard)
	}
	bytes, err := ioutil.ReadFile(file)
	if err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: failed to read file: '%s'\n", err)
		os.Exit(1)
	}

	// Intro
	n := 128
	printBytes(bytes[0:n])
	// DICM
	m := n + 4
	printBytes(bytes[n:m])
	n = m

	explicit := true

	parseDataElement(bytes, n, explicit)
}
<commit_msg>dcmdump: handle padding for trasnfer syntax field<commit_after>// Package main is a script that reads a filesystem full of dcm files and
// generates a json report.
package main

import (
	"encoding/binary"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	// "strconv"
	"log"
	"strings"

	"github.com/davidgamba/go-dicom/dcmdump/tag"
	"github.com/davidgamba/go-dicom/dcmdump/ts"
	vri "github.com/davidgamba/go-dicom/dcmdump/vr"
	"github.com/davidgamba/go-getoptions"
)

var debug bool

func debugf(format string, a ...interface{}) (n int, err error) {
	if debug {
		return fmt.Printf(format, a...)
	}
	return 0, nil
}
func debugln(a ...interface{}) (n int, err error) {
	if debug {
		return fmt.Println(a...)
	}
	return 0, nil
}

type stringSlice []string

func (s stringSlice) contains(a string) bool {
	for _, b := range s {
		if a == b {
			return true
		}
	}
	return false
}

type dicomqr struct {
	Empty [128]byte
	DICM  [4]byte
	Rest  []byte
}

// DataElement -
type DataElement struct {
	N        int
	TagGroup []byte // [2]byte
	TagElem  []byte // [2]byte
	TagStr   string
	VR       []byte // [2]byte
	VRStr    string
	VRLen    int
	Len      uint32
	Data     []byte
	PartOfSQ bool
}

// String -
func (de *DataElement) String() string {
	tn := tag.Tag[de.TagStr]["name"]
	if _, ok := tag.Tag[de.TagStr]; !ok {
		tn = "MISSING"
	}
	padding := ""
	if de.PartOfSQ {
		padding = "    "
	}
	if de.Len < 128 {
		return fmt.Sprintf("%s%04d (%s) %s %d %d %s %s", padding, de.N, de.TagStr, de.VRStr, de.VRLen, de.Len, tn, de.stringData())
	}
	return fmt.Sprintf("%s%04d (%s) %s %d %d %s %s", padding, de.N, de.TagStr, de.VRStr, de.VRLen, de.Len, tn, "...")
}

type fh os.File

func readNBytes(f *os.File, size int) ([]byte, error) {
	data := make([]byte, size)
	for {
		data = data[:cap(data)]
		n, err := f.Read(data)
		if err != nil {
			if err == io.EOF {
				break
			}
			return nil, err
		}
		data = data[:n]
	}
	return data, nil
}

// http://rosettacode.org/wiki/Strip_control_codes_and_extended_characters_from_a_string#Go
// two UTF-8 functions identical except for operator comparing c to 127
func stripCtlFromUTF8(str string) string {
	return strings.Map(func(r rune) rune {
		if r >= 32 && r != 127 {
			return r
		}
		return '.'
	}, str)
}

func tagString(b []byte) string {
	tag := strings.ToUpper(fmt.Sprintf("%02x%02x%02x%02x", b[1], b[0], b[3], b[2]))
	return tag
}

func printBytes(b []byte) {
	if !debug {
		return
	}
	l := len(b)
	var s string
	for i := 0; i < l; i++ {
		s += stripCtlFromUTF8(string(b[i]))
		if i != 0 && i%8 == 0 {
			if i%16 == 0 {
				fmt.Printf(" - %s\n", s)
				s = ""
			} else {
				fmt.Printf(" - ")
			}
		}
		fmt.Printf("%2x ", b[i])
		if i == l-1 {
			if 15-i%16 > 7 {
				fmt.Printf(" - ")
			}
			for j := 0; j < 15-i%16; j++ {
				// fmt.Printf("   ")
				fmt.Printf("   ")
			}
			fmt.Printf(" - %s\n", s)
			s = ""
		}
	}
	fmt.Printf("\n")
}

func (de *DataElement) stringData() string {
	if de.TagStr == "00020010" {
		dataStr := string(de.Data)
		l := len(de.Data)
		if de.Data[l-1] == 0x0 {
			dataStr = string(de.Data[:l-1])
		}
		if tsStr, ok := ts.TS[dataStr]; ok {
			return dataStr + " " + tsStr["name"].(string)
		}
	}
	if _, ok := vri.VR[de.VRStr]["fixed"]; ok && vri.VR[de.VRStr]["fixed"].(bool) {
		s := ""
		l := len(de.Data)
		n := 0
		vrl := vri.VR[de.VRStr]["len"].(int)
		switch vrl {
		case 1:
			for n+1 <= l {
				s += fmt.Sprintf("%d ", de.Data[n])
				n++
			}
			return s
		case 2:
			for n+2 <= l {
				e := binary.LittleEndian.Uint16(de.Data[n : n+2])
				s += fmt.Sprintf("%d ", e)
				n += 2
			}
			return s
		case 4:
			for n+4 <= l {
				e := binary.LittleEndian.Uint32(de.Data[n : n+4])
				s += fmt.Sprintf("%d ", e)
				n += 4
			}
			return s
		default:
			return string(de.Data)
		}
	} else {
		if _, ok := vri.VR[de.VRStr]["padded"]; ok && vri.VR[de.VRStr]["padded"].(bool) {
			l := len(de.Data)
			if de.Data[l-1] == 0x0 {
				return string(de.Data[:l-1])
			}
			return string(de.Data)
		}
		return string(de.Data)
	}
}

func parseDataElement(bytes []byte, n int, explicit bool) {
	log.Printf("parseDataElement")
	l := len(bytes)
	// Data element
	m := n
	for n <= l && m+4 <= l {
		undefinedLen := false
		de := DataElement{N: n}
		m += 4
		t := bytes[n:m]
		de.TagGroup = bytes[n : n+2]
		de.TagElem = bytes[n+2 : n+4]
		de.TagStr = tagString(t)
		// TODO: Clean up tagString
		tagStr := tagString(t)
		log.Printf("n: %d, Tag: %X -> %s\n", n, t, tagStr)
		printBytes(bytes[n:m])
		n = m
		if tagStr == "" {
			log.Printf("%d Empty Tag: %s\n", n, tagStr)
		} else if _, ok := tag.Tag[tagStr]; !ok {
			fmt.Fprintf(os.Stderr, "INFO: %d Missing tag '%s'\n", n, tagStr)
		} else {
			log.Printf("Tag Name: %s\n", tag.Tag[tagStr]["name"])
		}
		var len uint32
		var vr string
		if explicit {
			debugf("%d VR\n", n)
			m += 2
			printBytes(bytes[n:m])
			de.VR = bytes[n:m]
			de.VRStr = string(bytes[n:m])
			vr = string(bytes[n:m])
			if _, ok := vri.VR[vr]; !ok {
				if bytes[n] == 0x0 && bytes[n+1] == 0x0 {
					fmt.Fprintf(os.Stderr, "INFO: Blank VR\n")
					vr = "00"
					de.VRStr = "00"
				} else {
					fmt.Fprintf(os.Stderr, "ERROR: %d Missing VR '%s'\n", n, vr)
					printBytes(bytes[n:])
					return
				}
			}
			n = m
			if vr == "OB" ||
				vr == "OD" ||
				vr == "OF" ||
				vr == "OL" ||
				vr == "OW" ||
				vr == "SQ" ||
				vr == "UC" ||
				vr == "UR" ||
				vr == "UT" ||
				vr == "UN" {
				debugln("Reserved")
				m += 2
				printBytes(bytes[n:m])
				n = m
				debugln("Lenght")
				m += 4
				printBytes(bytes[n:m])
				len = binary.LittleEndian.Uint32(bytes[n:m])
				n = m
			} else {
				debugln("Lenght")
				m += 2
				printBytes(bytes[n:m])
				len16 := binary.LittleEndian.Uint16(bytes[n:m])
				len = uint32(len16)
				n = m
			}
		} else {
			debugln("Lenght")
			m += 4
			printBytes(bytes[n:m])
			len = binary.LittleEndian.Uint32(bytes[n:m])
			n = m
		}
		if len == 0xFFFFFFFF {
			undefinedLen = true
			for {
				// Find FFFEE0DD: SequenceDelimitationItem
				endTag := bytes[m : m+4]
				endTagStr := tagString(endTag)
				if endTagStr == "FFFEE0DD" {
					log.Printf("found SequenceDelimitationItem at %d", m)
					len = uint32(m - n)
					m = n
					break
				} else {
					m++
					if m >= l {
						fmt.Fprintf(os.Stderr, "ERROR: Couldn't find SequenceDelimitationItem\n")
						printBytes(bytes[n:l])
						return
					}
				}
			}
		}
		de.Len = len
		debugf("Lenght: %d\n", len)
		m += int(len)
		printBytes(bytes[n:m])
		if vr == "SQ" {
			de.Data = []byte{}
			fmt.Println(de.String())
			log.Printf("parseDataElement SQ")
			if undefinedLen {
				m += 8
			}
			parseDataElement(bytes[n:m], n, explicit)
			log.Printf("parseDataElement SQ Complete")
		} else {
			de.Data = bytes[n:m]
			fmt.Println(de.String())
			if undefinedLen {
				m += 8
			}
		}
		n = m
	}
	log.Printf("parseDataElement Complete")
}

func parseSQDataElements(bytes []byte, n int, explicit bool) int {
	log.Printf("parseSQDataElements")
	l := len(bytes)
	m := n
	for n <= l && m+4 <= l {
		de := DataElement{N: n}
		m := n + 4
		printBytes(bytes[n:m])
		t := bytes[n:m]
		tagStr := tagString(t)
		de.TagGroup = bytes[n : n+2]
		de.TagElem = bytes[n+2 : n+4]
		de.TagStr = tagString(t)
		log.Printf("n: %d, Tag: %X -> %s\n", n, t, tagStr)
		if _, ok := tag.Tag[tagStr]; !ok {
			fmt.Fprintf(os.Stderr, "ERROR: %d Missing tag '%s'\n", n, tagStr)
		}
		// if _, ok := tag.Tag[tagStr]; ok && tag.Tag[tagStr]["name"] == "ItemDelimitationItem" {
		// 	sequenceDelimitationItem = true
		// }
		for m <= l {
			// Find FFFEE00D: ItemDelimitationItem
			endTag := bytes[m : m+4]
			endTagStr := tagString(endTag)
			if endTagStr == "FFFEE00D" {
				debugln("Item Delim found")
				de.Data = bytes[n:m]
				printBytes(bytes[n:m])
				log.Printf("Tag: %X -> %s\n", endTag, endTagStr)
				m += 4
				n = m
				// m += 4
				// printBytes(bytes[n:m])
				// n = m
				break
			} else {
				m++
			}
		}
		fmt.Println(de.String())
	}
	log.Printf("parseSQDataElement Complete")
	return n
}

func synopsis() {
	synopsis := `dcmdump <dcm_file> [--debug]
`
	fmt.Fprintln(os.Stderr, synopsis)
}

func main() {

	var file string
	opt := getoptions.New()
	opt.Bool("help", false)
	opt.BoolVar(&debug, "debug", false)
	remaining, err := opt.Parse(os.Args[1:])
	if err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: %s\n", err)
		os.Exit(1)
	}
	if opt.Called("help") {
		synopsis()
		os.Exit(1)
	}
	if len(remaining) < 1 {
		fmt.Fprintf(os.Stderr, "ERROR: Missing file\n")
		synopsis()
		os.Exit(1)
	}
	file = remaining[0]
	if !debug {
		log.SetOutput(ioutil.Discard)
	}
	bytes, err := ioutil.ReadFile(file)
	if err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: failed to read file: '%s'\n", err)
		os.Exit(1)
	}

	// Intro
	n := 128
	printBytes(bytes[0:n])
	// DICM
	m := n + 4
	printBytes(bytes[n:m])
	n = m

	explicit := true

	parseDataElement(bytes, n, explicit)
}
<|endoftext|>