<commit_before>package gps

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

const (
	successChar   = "✓"
	successCharSp = successChar + " "
	failChar      = "✗"
	failCharSp    = failChar + " "
	backChar      = "←"
	innerIndent   = "  "
)

func (s *solver) traceCheckPkgs(bmi bimodalIdentifier) {
	if s.tl == nil {
		return
	}

	prefix := getprei(len(s.vqs) + 1)
	s.tl.Printf("%s\n", tracePrefix(fmt.Sprintf("? revisit %s to add %v pkgs", bmi.id.errString(), len(bmi.pl)), prefix, prefix))
}

func (s *solver) traceCheckQueue(q *versionQueue, bmi bimodalIdentifier, cont bool, offset int) {
	if s.tl == nil {
		return
	}

	prefix := getprei(len(s.vqs) + offset)
	vlen := strconv.Itoa(len(q.pi))
	if !q.allLoaded {
		vlen = "at least " + vlen
	}

	// TODO(sdboyer) how...to list the packages in the limited space we have?
	var verb string
	indent := ""
	if cont {
		// Continue is an "inner" message.. indenting
		verb = "continue"
		vlen = vlen + " more"
		indent = innerIndent
	} else {
		verb = "attempt"
	}

	s.tl.Printf("%s\n", tracePrefix(fmt.Sprintf("%s? %s %s with %v pkgs; %s versions to try",indent, verb, bmi.id.errString(), len(bmi.pl), vlen), prefix, prefix))
}

// traceStartBacktrack is called with the bmi that first failed, thus initiating
// backtracking
func (s *solver) traceStartBacktrack(bmi bimodalIdentifier, err error, pkgonly bool) {
	if s.tl == nil {
		return
	}

	var msg string
	if pkgonly {
		msg = fmt.Sprintf("%s%s could not add %v pkgs to %s; begin backtrack",innerIndent, backChar, len(bmi.pl), bmi.id.errString())
	} else {
		msg = fmt.Sprintf("%s%s no more versions of %s to try; begin backtrack",innerIndent, backChar, bmi.id.errString())
	}

	prefix := getprei(len(s.sel.projects))
	s.tl.Printf("%s\n", tracePrefix(msg, prefix, prefix))
}

// traceBacktrack is called when a package or project is poppped off during
// backtracking
func (s *solver) traceBacktrack(bmi bimodalIdentifier, pkgonly bool) {
	if s.tl == nil {
		return
	}

	var msg string
	if pkgonly {
		msg = fmt.Sprintf("%s backtrack: popped %v pkgs from %s", backChar, len(bmi.pl), bmi.id.errString())
	} else {
		msg = fmt.Sprintf("%s backtrack: no more versions of %s to try", backChar, bmi.id.errString())
	}

	prefix := getprei(len(s.sel.projects))
	s.tl.Printf("%s\n", tracePrefix(msg, prefix, prefix))
}

// Called just once after solving has finished, whether success or not
func (s *solver) traceFinish(sol solution, err error) {
	if s.tl == nil {
		return
	}

	if err == nil {
		var pkgcount int
		for _, lp := range sol.Projects() {
			pkgcount += len(lp.pkgs)
		}
		s.tl.Printf("%s%s found solution with %v packages from %v projects",innerIndent, successChar, pkgcount, len(sol.Projects()))
	} else {
		s.tl.Printf("%s%s solving failed",innerIndent, failChar)
	}
}

// traceSelectRoot is called just once, when the root project is selected
func (s *solver) traceSelectRoot(ptree PackageTree, cdeps []completeDep) {
	if s.tl == nil {
		return
	}

	// This duplicates work a bit, but we're in trace mode and it's only once,
	// so who cares
	rm := ptree.ExternalReach(true, true, s.rd.ig)

	s.tl.Printf("Root project is %q", s.rd.rpt.ImportRoot)

	var expkgs int
	for _, cdep := range cdeps {
		expkgs += len(cdep.pl)
	}

	// TODO(sdboyer) include info on ignored pkgs/imports, etc.
	s.tl.Printf(" %v transitively valid internal packages", len(rm))
	s.tl.Printf(" %v external packages imported from %v projects", expkgs, len(cdeps))
	s.tl.Printf("(0)   " + successCharSp + "select (root)")
}

// traceSelect is called when an atom is successfully selected
func (s *solver) traceSelect(awp atomWithPackages, pkgonly bool) {
	if s.tl == nil {
		return
	}

	var msg string
	if pkgonly {
		msg = fmt.Sprintf("%s%s include %v more pkgs from %s",innerIndent, successChar, len(awp.pl), a2vs(awp.a))
	} else {
		msg = fmt.Sprintf("%s select %s w/%v pkgs", successChar, a2vs(awp.a), len(awp.pl))
	}

	prefix := getprei(len(s.sel.projects) - 1)
	s.tl.Printf("%s\n", tracePrefix(msg, prefix, prefix))
}

func (s *solver) traceInfo(args ...interface{}) {
	if s.tl == nil {
		return
	}

	if len(args) == 0 {
		panic("must pass at least one param to traceInfo")
	}

	preflen := len(s.sel.projects)
	var msg string
	switch data := args[0].(type) {
	case string:
		msg = tracePrefix(innerIndent + fmt.Sprintf(data, args[1:]...), "  ", "  ")
	case traceError:
		preflen++
		// We got a special traceError, use its custom method
		msg = tracePrefix(innerIndent + data.traceString(), "  ", failCharSp)
	case error:
		// Regular error; still use the x leader but default Error() string
		msg = tracePrefix(innerIndent + data.Error(), "  ", failCharSp)
	default:
		// panic here because this can *only* mean a stupid internal bug
		panic(fmt.Sprintf("%scanary - unknown type passed as first param to traceInfo %T", innerIndent, data))
	}

	prefix := getprei(preflen)
	s.tl.Printf("%s\n", tracePrefix(msg, prefix, prefix))
}

func getprei(i int) string {
	var s string
	if i < 10 {
		s = fmt.Sprintf("(%d)	", i)
	} else if i < 100 {
		s = fmt.Sprintf("(%d)  ", i)
	} else {
		s = fmt.Sprintf("(%d) ", i)
	}
	return s
}

func tracePrefix(msg, sep, fsep string) string {
	parts := strings.Split(strings.TrimSuffix(msg, "\n"), "\n")
	for k, str := range parts {
		if k == 0 {
			parts[k] = fsep + str
		} else {
			parts[k] = sep + str
		}
	}

	return strings.Join(parts, "\n")
}
<commit_msg>Remove indent on panic<commit_after>package gps

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

const (
	successChar   = "✓"
	successCharSp = successChar + " "
	failChar      = "✗"
	failCharSp    = failChar + " "
	backChar      = "←"
	innerIndent   = "  "
)

func (s *solver) traceCheckPkgs(bmi bimodalIdentifier) {
	if s.tl == nil {
		return
	}

	prefix := getprei(len(s.vqs) + 1)
	s.tl.Printf("%s\n", tracePrefix(fmt.Sprintf("? revisit %s to add %v pkgs", bmi.id.errString(), len(bmi.pl)), prefix, prefix))
}

func (s *solver) traceCheckQueue(q *versionQueue, bmi bimodalIdentifier, cont bool, offset int) {
	if s.tl == nil {
		return
	}

	prefix := getprei(len(s.vqs) + offset)
	vlen := strconv.Itoa(len(q.pi))
	if !q.allLoaded {
		vlen = "at least " + vlen
	}

	// TODO(sdboyer) how...to list the packages in the limited space we have?
	var verb string
	indent := ""
	if cont {
		// Continue is an "inner" message.. indenting
		verb = "continue"
		vlen = vlen + " more"
		indent = innerIndent
	} else {
		verb = "attempt"
	}

	s.tl.Printf("%s\n", tracePrefix(fmt.Sprintf("%s? %s %s with %v pkgs; %s versions to try",indent, verb, bmi.id.errString(), len(bmi.pl), vlen), prefix, prefix))
}

// traceStartBacktrack is called with the bmi that first failed, thus initiating
// backtracking
func (s *solver) traceStartBacktrack(bmi bimodalIdentifier, err error, pkgonly bool) {
	if s.tl == nil {
		return
	}

	var msg string
	if pkgonly {
		msg = fmt.Sprintf("%s%s could not add %v pkgs to %s; begin backtrack",innerIndent, backChar, len(bmi.pl), bmi.id.errString())
	} else {
		msg = fmt.Sprintf("%s%s no more versions of %s to try; begin backtrack",innerIndent, backChar, bmi.id.errString())
	}

	prefix := getprei(len(s.sel.projects))
	s.tl.Printf("%s\n", tracePrefix(msg, prefix, prefix))
}

// traceBacktrack is called when a package or project is poppped off during
// backtracking
func (s *solver) traceBacktrack(bmi bimodalIdentifier, pkgonly bool) {
	if s.tl == nil {
		return
	}

	var msg string
	if pkgonly {
		msg = fmt.Sprintf("%s backtrack: popped %v pkgs from %s", backChar, len(bmi.pl), bmi.id.errString())
	} else {
		msg = fmt.Sprintf("%s backtrack: no more versions of %s to try", backChar, bmi.id.errString())
	}

	prefix := getprei(len(s.sel.projects))
	s.tl.Printf("%s\n", tracePrefix(msg, prefix, prefix))
}

// Called just once after solving has finished, whether success or not
func (s *solver) traceFinish(sol solution, err error) {
	if s.tl == nil {
		return
	}

	if err == nil {
		var pkgcount int
		for _, lp := range sol.Projects() {
			pkgcount += len(lp.pkgs)
		}
		s.tl.Printf("%s%s found solution with %v packages from %v projects",innerIndent, successChar, pkgcount, len(sol.Projects()))
	} else {
		s.tl.Printf("%s%s solving failed",innerIndent, failChar)
	}
}

// traceSelectRoot is called just once, when the root project is selected
func (s *solver) traceSelectRoot(ptree PackageTree, cdeps []completeDep) {
	if s.tl == nil {
		return
	}

	// This duplicates work a bit, but we're in trace mode and it's only once,
	// so who cares
	rm := ptree.ExternalReach(true, true, s.rd.ig)

	s.tl.Printf("Root project is %q", s.rd.rpt.ImportRoot)

	var expkgs int
	for _, cdep := range cdeps {
		expkgs += len(cdep.pl)
	}

	// TODO(sdboyer) include info on ignored pkgs/imports, etc.
	s.tl.Printf(" %v transitively valid internal packages", len(rm))
	s.tl.Printf(" %v external packages imported from %v projects", expkgs, len(cdeps))
	s.tl.Printf("(0)   " + successCharSp + "select (root)")
}

// traceSelect is called when an atom is successfully selected
func (s *solver) traceSelect(awp atomWithPackages, pkgonly bool) {
	if s.tl == nil {
		return
	}

	var msg string
	if pkgonly {
		msg = fmt.Sprintf("%s%s include %v more pkgs from %s",innerIndent, successChar, len(awp.pl), a2vs(awp.a))
	} else {
		msg = fmt.Sprintf("%s select %s w/%v pkgs", successChar, a2vs(awp.a), len(awp.pl))
	}

	prefix := getprei(len(s.sel.projects) - 1)
	s.tl.Printf("%s\n", tracePrefix(msg, prefix, prefix))
}

func (s *solver) traceInfo(args ...interface{}) {
	if s.tl == nil {
		return
	}

	if len(args) == 0 {
		panic("must pass at least one param to traceInfo")
	}

	preflen := len(s.sel.projects)
	var msg string
	switch data := args[0].(type) {
	case string:
		msg = tracePrefix(innerIndent + fmt.Sprintf(data, args[1:]...), "  ", "  ")
	case traceError:
		preflen++
		// We got a special traceError, use its custom method
		msg = tracePrefix(innerIndent + data.traceString(), "  ", failCharSp)
	case error:
		// Regular error; still use the x leader but default Error() string
		msg = tracePrefix(innerIndent + data.Error(), "  ", failCharSp)
	default:
		// panic here because this can *only* mean a stupid internal bug
		panic(fmt.Sprintf("%canary - unknown type passed as first param to traceInfo %T", data))
	}

	prefix := getprei(preflen)
	s.tl.Printf("%s\n", tracePrefix(msg, prefix, prefix))
}

func getprei(i int) string {
	var s string
	if i < 10 {
		s = fmt.Sprintf("(%d)	", i)
	} else if i < 100 {
		s = fmt.Sprintf("(%d)  ", i)
	} else {
		s = fmt.Sprintf("(%d) ", i)
	}
	return s
}

func tracePrefix(msg, sep, fsep string) string {
	parts := strings.Split(strings.TrimSuffix(msg, "\n"), "\n")
	for k, str := range parts {
		if k == 0 {
			parts[k] = fsep + str
		} else {
			parts[k] = sep + str
		}
	}

	return strings.Join(parts, "\n")
}
<|endoftext|>


<commit_before>package controllers

import "github.com/revel/revel"

type App struct {
	*revel.Controller
}

func (c App) Index() revel.Result {
	greeting := "Aloha World"
	return c.Render(greeting)
}

func (c App) Hello(myName string) revel.Result {

	c.Validation.Required(myName).Message("Your name is required!")
	c.Validation.MinSize(myName, 3).Message("Your name is not long enough!")

	if c.Validation.HasErrors() {
		c.Validation.Keep()
		c.FlashParams()
		return c.Redirect(App.Index)
	}

	return c.Render(myName)

}

func (c App) TestJson() revel.Result {

	//TODO

	return c.Render(App.Index)
}<commit_msg>sql tests<commit_after>package controllers

import "github.com/revel/revel"
import "database/sql"
import _ "github.com/go-sql-driver/mysql"
import "fmt"

type App struct {
	*revel.Controller
}

func (c App) Index() revel.Result {

	db, err := sql.Open("mysql", "root:kazuki69@/golang")

    if err != nil {
        panic(err.Error())  // Just for example purpose. You should use proper error handling instead of panic
    }
    defer db.Close()

    // Prepare statement for inserting data
    stmtIns, err := db.Prepare("INSERT INTO squareNum VALUES( ?, ? )") // ? = placeholder
    if err != nil {
    	fmt.Printf("%s", err.Error());
    }
    defer stmtIns.Close() // Close the statement when we leave main() / the program terminates

    // Prepare statement for reading data
    stmtOut, err := db.Prepare("SELECT squareNumber FROM squareNum WHERE number = ?")
    if err != nil {
    	fmt.Printf("%s", err.Error());
    }
    defer stmtOut.Close()

    // Insert square numbers for 0-24 in the database
    for i := 0; i < 25; i++ {
        _, err = stmtIns.Exec(i, (i * i)) // Insert tuples (i, i^2)
        if err != nil {
    		fmt.Printf("%s", err.Error());
        }
    }

    var squareNum int // we "scan" the result in here

    // Query the square-number of 13
    err = stmtOut.QueryRow(13).Scan(&squareNum) // WHERE number = 13
    if err != nil {
    	fmt.Printf("%s", err.Error());
    }
    fmt.Printf("The square number of 13 is: %d", squareNum)

    // Query another number.. 1 maybe?
    err = stmtOut.QueryRow(1).Scan(&squareNum) // WHERE number = 1
    if err != nil {
    	fmt.Printf("%s", err.Error());
    }
    fmt.Printf("The square number of 1 is: %d", squareNum)

	greeting := "test json"
	return c.Render(greeting)
}

func (c App) Hello(myName string) revel.Result {

	c.Validation.Required(myName).Message("Your name is required!")
	c.Validation.MinSize(myName, 3).Message("Your name is not long enough!")

	if c.Validation.HasErrors() {
		c.Validation.Keep()
		c.FlashParams()
		return c.Redirect(App.Index)
	}

	return c.Render(myName)

}

func (c App) TestJson() revel.Result {

	//TODO

	return c.Render(App.Index)
}<|endoftext|>


<commit_before>// Copyright 2017 ibelie, Chen Jie, Joungtao. All rights reserved.
// Use of this source code is governed by The MIT License
// that can be found in the LICENSE file.

package tygo

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"path"
	"sort"
	"strings"

	"io/ioutil"
)

func Javascript(dir string, name string, types []Type) {
	var head bytes.Buffer
	var body bytes.Buffer
	head.Write([]byte(`// Generated for tyts by tygo.  DO NOT EDIT!
`))
	body.Write([]byte(`
`))

	var sortedObjects []string
	objects := make(map[string]*Object)
	for _, t := range types {
		if object, ok := t.(*Object); ok {
			if o, exist := objects[object.Name]; exist {
				log.Fatalf("[Tygo][Javascript] Object already exists: %v %v", o, object)
			}
			objects[object.Name] = object
			sortedObjects = append(sortedObjects, object.Name)
		}
	}
	sort.Strings(sortedObjects)

	var requires map[string]string
	genTypes := make(map[string]Type)
	for _, name := range sortedObjects {
		js, rs := objects[name].Javascript(&body, genTypes, objects)
		requires = update(requires, rs)
		head.Write([]byte(fmt.Sprintf(`
goog.provide('%s');`, name)))
		body.Write([]byte(js))
	}

	var sortedRequires []string
	for require, _ := range requires {
		if strings.HasPrefix(require, "goog.require('tyts.") {
			sortedRequires = append(sortedRequires, require)
		}
	}
	sort.Strings(sortedRequires)
	head.Write([]byte("\n\n" + strings.Join(sortedRequires, "\n")))

	sortedRequires = nil
	for require, _ := range requires {
		if !strings.HasPrefix(require, "goog.require('tyts.") {
			sortedRequires = append(sortedRequires, require)
		}
	}
	sort.Strings(sortedRequires)
	head.Write([]byte("\n\n" + strings.Join(sortedRequires, "\n")))

	head.Write(body.Bytes())
	ioutil.WriteFile(path.Join(dir, name+".js"), head.Bytes(), 0666)
}

func (t *Enum) Javascript(writer io.Writer, types map[string]Type, objects map[string]*Object) (string, map[string]string) {
	return "", nil
}

func (t *Method) Javascript(writer io.Writer, types map[string]Type, objects map[string]*Object) (string, map[string]string) {
	return "", nil
}

func typeListJavascript(name string, ts []Type, writer io.Writer, types map[string]Type, objects map[string]*Object) (string, map[string]string) {
	requires := map[string]string{"goog.require('tyts.Method');": ""}
	var items []string
	for i, t := range ts {
		js, rs := t.Javascript(writer, types, objects)
		update(requires, rs)
		items = append(items, fmt.Sprintf(`
	{tag: %d, tagsize: %d, type: %s}`, _MAKE_TAG(i+1, t.WireType()), TAG_SIZE(i+1), js))
	}
	return fmt.Sprintf(`
new tyts.Method('%s', %d, [%s
]);
`, name, _MAKE_CUTOFF(len(items)), strings.Join(items, ",")), requires
}

func (t *Object) Javascript(writer io.Writer, types map[string]Type, objects map[string]*Object) (string, map[string]string) {
	if _, exist := types[t.Name]; exist {
		return "", nil
	}

	var fields []string
	requires := map[string]string{"goog.require('tyts.Object');": ""}
	for i, field := range t.AllFields(objects) {
		wiretype := field.WireType()
		js, rs := field.Javascript(writer, types, objects)
		requires = update(requires, rs)
		fields = append(fields, fmt.Sprintf(`
	{name: '%s', tag: %d, tagsize: %d, type: %s}`, field.Name, _MAKE_TAG(i+1, wiretype), TAG_SIZE(i+1), js))
	}

	types[t.Name] = t
	var method_props []string
	var method_types []string
	for i, method := range t.Methods {
		js_p, rs_p := typeListJavascript(t.Name+method.Name+"Param", method.Params, writer, types, objects)
		js_r, rs_r := typeListJavascript(t.Name+method.Name+"Result", method.Results, writer, types, objects)
		update(requires, rs_p)
		update(requires, rs_r)
		method_props = append(method_props, fmt.Sprintf(`
	{name: '%s%s', type: null}`, method.Name, "Param"))
		method_props = append(method_props, fmt.Sprintf(`
	{name: '%s%s', type: null}`, method.Name, "Result"))
		method_types = append(method_types, fmt.Sprintf(`
_%s.methods[%d].type = %s`, t.Name, i*2, js_p))
		method_types = append(method_types, fmt.Sprintf(`
_%s.methods[%d].type = %s`, t.Name, i*2+1, js_r))
	}

	return fmt.Sprintf(`
var _%s = new tyts.Object('%s', %d, [%s
], [%s
]);%s
var %s = _%s.Type;
`, t.Name, t.Name, _MAKE_CUTOFF(len(fields)), strings.Join(fields, ","), strings.Join(method_props, ","), strings.Join(method_types, ""), t.Name, t.Name), requires
}

func (t UnknownType) Javascript(writer io.Writer, types map[string]Type, objects map[string]*Object) (string, map[string]string) {
	return "", nil
}

func (t SimpleType) Javascript(writer io.Writer, types map[string]Type, objects map[string]*Object) (string, map[string]string) {
	switch t {
	case SimpleType_INT32:
		fallthrough
	case SimpleType_INT64:
		fallthrough
	case SimpleType_UINT32:
		fallthrough
	case SimpleType_UINT64:
		return "tyts.Integer", map[string]string{"goog.require('tyts.Integer');": ""}
	case SimpleType_BYTES:
		return "tyts.Bytes", map[string]string{"goog.require('tyts.Bytes');": ""}
	case SimpleType_STRING:
		return "tyts.String", map[string]string{"goog.require('tyts.String');": ""}
	case SimpleType_BOOL:
		return "tyts.Bool", map[string]string{"goog.require('tyts.Bool');": ""}
	case SimpleType_FLOAT32:
		return "tyts.Float32", map[string]string{"goog.require('tyts.Float32');": ""}
	case SimpleType_FLOAT64:
		return "tyts.Float64", map[string]string{"goog.require('tyts.Float64');": ""}
	default:
		log.Fatalf("[Tygo][SimpleType] Unexpect enum value for Javascript: %d", t)
		return "", nil
	}
}

func (t *EnumType) Javascript(writer io.Writer, types map[string]Type, objects map[string]*Object) (string, map[string]string) {
	return "tyts.Integer", map[string]string{"goog.require('tyts.Integer');": ""}
}

func (t *InstanceType) Javascript(writer io.Writer, types map[string]Type, objects map[string]*Object) (string, map[string]string) {
	if object, ok := objects[t.Name]; ok {
		js, rs := object.Javascript(writer, types, objects)
		writer.Write([]byte(js))
		return "_" + t.Name, rs
	} else {
		identifier := t.Name + "Delegate"
		if _, exist := types[identifier]; !exist {
			writer.Write([]byte(fmt.Sprintf(`
var %s = new tyts.Extension('%s', %s)
`, identifier, identifier, t.Name)))
			types[identifier] = t
		}
		return identifier, map[string]string{
			"goog.require('tyts.Extension');":          "",
			fmt.Sprintf("goog.require('%s');", t.Name): "",
		}
	}
}

func (t *FixedPointType) Javascript(writer io.Writer, types map[string]Type, objects map[string]*Object) (string, map[string]string) {
	identifier := t.Identifier()
	if _, exist := types[identifier]; !exist {
		writer.Write([]byte(fmt.Sprintf(`
var %s = new tyts.FixedPoint(%d, %d)
`, identifier, t.Floor, t.Precision)))
		types[identifier] = t
	}
	return identifier, map[string]string{"goog.require('tyts.FixedPoint');": ""}
}

func (t *ListType) Javascript(writer io.Writer, types map[string]Type, objects map[string]*Object) (string, map[string]string) {
	identifier := t.Identifier()
	requires := map[string]string{"goog.require('tyts.List');": ""}
	if _, exist := types[identifier]; !exist {
		js, rs := t.E.Javascript(writer, types, objects)
		requires = update(requires, rs)
		writer.Write([]byte(fmt.Sprintf(`
var %s = new tyts.List('%s', %s)
`, identifier, identifier, js)))
		types[identifier] = t
	}
	return identifier, requires
}

func (t *DictType) Javascript(writer io.Writer, types map[string]Type, objects map[string]*Object) (string, map[string]string) {
	identifier := t.Identifier()
	requires := map[string]string{"goog.require('tyts.Dict');": ""}
	if _, exist := types[identifier]; !exist {
		js_k, rs_k := t.K.Javascript(writer, types, objects)
		js_v, rs_v := t.V.Javascript(writer, types, objects)
		requires = update(requires, rs_k)
		requires = update(requires, rs_v)
		writer.Write([]byte(fmt.Sprintf(`
var %s = new tyts.Dict('%s', %s, %s)
`, identifier, identifier, js_k, js_v)))
		types[identifier] = t
	}
	return identifier, requires
}

func (t *VariantType) Javascript(writer io.Writer, types map[string]Type, objects map[string]*Object) (string, map[string]string) {
	identifier := t.Identifier()
	requires := map[string]string{"goog.require('tyts.Variant');": ""}
	if _, exist := types[identifier]; !exist {
		var codes []string
		for i, st := range t.Ts {
			if s, ok := st.(SimpleType); ok && s == SimpleType_NIL {
				continue
			}
			js, rs := st.Javascript(writer, types, objects)
			wiretype := st.WireType()
			requires = update(requires, rs)
			codes = append(codes, fmt.Sprintf(`
	{tag: %d, tagsize: %d, type: %s}`, _MAKE_TAG(i+1, wiretype), TAG_SIZE(i+1), js))
		}
		writer.Write([]byte(fmt.Sprintf(`
var %s = new tyts.Variant('%s', %d, [%s
])
`, identifier, identifier, _MAKE_CUTOFF(len(codes)), strings.Join(codes, ","))))
		types[identifier] = t
	}
	return identifier, requires
}
<commit_msg>support browser and node.js<commit_after>// Copyright 2017 ibelie, Chen Jie, Joungtao. All rights reserved.
// Use of this source code is governed by The MIT License
// that can be found in the LICENSE file.

package tygo

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"path"
	"sort"
	"strings"

	"io/ioutil"
)

func Javascript(dir string, name string, types []Type) {
	var head bytes.Buffer
	var body bytes.Buffer
	head.Write([]byte(`// Generated for tyts by tygo.  DO NOT EDIT!
`))
	body.Write([]byte(`
`))

	var sortedObjects []string
	objects := make(map[string]*Object)
	for _, t := range types {
		if object, ok := t.(*Object); ok {
			if o, exist := objects[object.Name]; exist {
				log.Fatalf("[Tygo][Javascript] Object already exists: %v %v", o, object)
			}
			objects[object.Name] = object
			sortedObjects = append(sortedObjects, object.Name)
		}
	}
	sort.Strings(sortedObjects)

	var requires map[string]string
	genTypes := make(map[string]Type)
	for _, name := range sortedObjects {
		js, rs := objects[name].Javascript(&body, genTypes, objects)
		requires = update(requires, rs)
		head.Write([]byte(fmt.Sprintf(`
goog.provide('%s');`, name)))
		body.Write([]byte(js))
	}

	var sortedRequires []string
	for require, _ := range requires {
		if strings.HasPrefix(require, "goog.require('tyts.") {
			sortedRequires = append(sortedRequires, require)
		}
	}
	sort.Strings(sortedRequires)
	head.Write([]byte("\n\n" + strings.Join(sortedRequires, "\n")))

	sortedRequires = nil
	for require, _ := range requires {
		if !strings.HasPrefix(require, "goog.require('tyts.") {
			sortedRequires = append(sortedRequires, require)
		}
	}
	sort.Strings(sortedRequires)
	head.Write([]byte("\n\n" + strings.Join(sortedRequires, "\n")))

	head.Write(body.Bytes())
	ioutil.WriteFile(path.Join(dir, name+".js"), head.Bytes(), 0666)
}

func (t *Enum) Javascript(writer io.Writer, types map[string]Type, objects map[string]*Object) (string, map[string]string) {
	return "", nil
}

func (t *Method) Javascript(writer io.Writer, types map[string]Type, objects map[string]*Object) (string, map[string]string) {
	return "", nil
}

func typeListJavascript(name string, ts []Type, writer io.Writer, types map[string]Type, objects map[string]*Object) (string, map[string]string) {
	requires := map[string]string{"goog.require('tyts.Method');": ""}
	var items []string
	for i, t := range ts {
		js, rs := t.Javascript(writer, types, objects)
		update(requires, rs)
		items = append(items, fmt.Sprintf(`
	{tag: %d, tagsize: %d, type: %s}`, _MAKE_TAG(i+1, t.WireType()), TAG_SIZE(i+1), js))
	}
	return fmt.Sprintf(`new tyts.Method('%s', %d, [%s
]);
`, name, _MAKE_CUTOFF(len(items)), strings.Join(items, ",")), requires
}

func (t *Object) Javascript(writer io.Writer, types map[string]Type, objects map[string]*Object) (string, map[string]string) {
	if _, exist := types[t.Name]; exist {
		return "", nil
	}

	var fields []string
	requires := map[string]string{"goog.require('tyts.Object');": ""}
	for i, field := range t.AllFields(objects) {
		wiretype := field.WireType()
		js, rs := field.Javascript(writer, types, objects)
		requires = update(requires, rs)
		fields = append(fields, fmt.Sprintf(`
	{name: '%s', tag: %d, tagsize: %d, type: %s}`, field.Name, _MAKE_TAG(i+1, wiretype), TAG_SIZE(i+1), js))
	}

	types[t.Name] = t
	var method_props []string
	var method_types []string
	for i, method := range t.Methods {
		js_p, rs_p := typeListJavascript(t.Name+method.Name+"Param", method.Params, writer, types, objects)
		js_r, rs_r := typeListJavascript(t.Name+method.Name+"Result", method.Results, writer, types, objects)
		update(requires, rs_p)
		update(requires, rs_r)
		method_props = append(method_props, fmt.Sprintf(`
	{name: '%s%s', type: null}`, method.Name, "Param"))
		method_props = append(method_props, fmt.Sprintf(`
	{name: '%s%s', type: null}`, method.Name, "Result"))
		method_types = append(method_types, fmt.Sprintf(`
_%s.methods[%d].type = %s`, t.Name, i*2, js_p))
		method_types = append(method_types, fmt.Sprintf(`
_%s.methods[%d].type = %s`, t.Name, i*2+1, js_r))
	}

	return fmt.Sprintf(`
var _%s = new tyts.Object('%s', %d, [%s
], [%s
]);%s
%s = _%s.Type;
if (typeof(module) != 'undefined') {
	module.exports.%s = %s;
}
`, t.Name, t.Name, _MAKE_CUTOFF(len(fields)), strings.Join(fields, ","),
		strings.Join(method_props, ","), strings.Join(method_types, ""),
		t.Name, t.Name, t.Name, t.Name), requires
}

func (t UnknownType) Javascript(writer io.Writer, types map[string]Type, objects map[string]*Object) (string, map[string]string) {
	return "", nil
}

func (t SimpleType) Javascript(writer io.Writer, types map[string]Type, objects map[string]*Object) (string, map[string]string) {
	switch t {
	case SimpleType_INT32:
		fallthrough
	case SimpleType_INT64:
		fallthrough
	case SimpleType_UINT32:
		fallthrough
	case SimpleType_UINT64:
		return "tyts.Integer", map[string]string{"goog.require('tyts.Integer');": ""}
	case SimpleType_BYTES:
		return "tyts.Bytes", map[string]string{"goog.require('tyts.Bytes');": ""}
	case SimpleType_STRING:
		return "tyts.String", map[string]string{"goog.require('tyts.String');": ""}
	case SimpleType_BOOL:
		return "tyts.Bool", map[string]string{"goog.require('tyts.Bool');": ""}
	case SimpleType_FLOAT32:
		return "tyts.Float32", map[string]string{"goog.require('tyts.Float32');": ""}
	case SimpleType_FLOAT64:
		return "tyts.Float64", map[string]string{"goog.require('tyts.Float64');": ""}
	default:
		log.Fatalf("[Tygo][SimpleType] Unexpect enum value for Javascript: %d", t)
		return "", nil
	}
}

func (t *EnumType) Javascript(writer io.Writer, types map[string]Type, objects map[string]*Object) (string, map[string]string) {
	return "tyts.Integer", map[string]string{"goog.require('tyts.Integer');": ""}
}

func (t *InstanceType) Javascript(writer io.Writer, types map[string]Type, objects map[string]*Object) (string, map[string]string) {
	if object, ok := objects[t.Name]; ok {
		js, rs := object.Javascript(writer, types, objects)
		writer.Write([]byte(js))
		return "_" + t.Name, rs
	} else {
		identifier := t.Name + "Delegate"
		if _, exist := types[identifier]; !exist {
			writer.Write([]byte(fmt.Sprintf(`
%s = new tyts.Extension('%s', %s)
`, identifier, identifier, t.Name)))
			types[identifier] = t
		}
		return identifier, map[string]string{
			"goog.require('tyts.Extension');":          "",
			fmt.Sprintf("goog.require('%s');", t.Name): "",
		}
	}
}

func (t *FixedPointType) Javascript(writer io.Writer, types map[string]Type, objects map[string]*Object) (string, map[string]string) {
	identifier := t.Identifier()
	if _, exist := types[identifier]; !exist {
		writer.Write([]byte(fmt.Sprintf(`
%s = new tyts.FixedPoint(%d, %d)
`, identifier, t.Floor, t.Precision)))
		types[identifier] = t
	}
	return identifier, map[string]string{"goog.require('tyts.FixedPoint');": ""}
}

func (t *ListType) Javascript(writer io.Writer, types map[string]Type, objects map[string]*Object) (string, map[string]string) {
	identifier := t.Identifier()
	requires := map[string]string{"goog.require('tyts.List');": ""}
	if _, exist := types[identifier]; !exist {
		js, rs := t.E.Javascript(writer, types, objects)
		requires = update(requires, rs)
		writer.Write([]byte(fmt.Sprintf(`
%s = new tyts.List('%s', %s)
`, identifier, identifier, js)))
		types[identifier] = t
	}
	return identifier, requires
}

func (t *DictType) Javascript(writer io.Writer, types map[string]Type, objects map[string]*Object) (string, map[string]string) {
	identifier := t.Identifier()
	requires := map[string]string{"goog.require('tyts.Dict');": ""}
	if _, exist := types[identifier]; !exist {
		js_k, rs_k := t.K.Javascript(writer, types, objects)
		js_v, rs_v := t.V.Javascript(writer, types, objects)
		requires = update(requires, rs_k)
		requires = update(requires, rs_v)
		writer.Write([]byte(fmt.Sprintf(`
%s = new tyts.Dict('%s', %s, %s)
`, identifier, identifier, js_k, js_v)))
		types[identifier] = t
	}
	return identifier, requires
}

func (t *VariantType) Javascript(writer io.Writer, types map[string]Type, objects map[string]*Object) (string, map[string]string) {
	identifier := t.Identifier()
	requires := map[string]string{"goog.require('tyts.Variant');": ""}
	if _, exist := types[identifier]; !exist {
		var codes []string
		for i, st := range t.Ts {
			if s, ok := st.(SimpleType); ok && s == SimpleType_NIL {
				continue
			}
			js, rs := st.Javascript(writer, types, objects)
			wiretype := st.WireType()
			requires = update(requires, rs)
			codes = append(codes, fmt.Sprintf(`
	{tag: %d, tagsize: %d, type: %s}`, _MAKE_TAG(i+1, wiretype), TAG_SIZE(i+1), js))
		}
		writer.Write([]byte(fmt.Sprintf(`
%s = new tyts.Variant('%s', %d, [%s
])
`, identifier, identifier, _MAKE_CUTOFF(len(codes)), strings.Join(codes, ","))))
		types[identifier] = t
	}
	return identifier, requires
}
<|endoftext|>


<commit_before>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package provisioner

import (
	"fmt"
	"sync/atomic"
	"time"

	"github.com/juju/errors"
	"github.com/juju/loggo"
	"github.com/juju/mutex"
	"github.com/juju/utils/clock"
	"gopkg.in/juju/names.v2"

	"github.com/juju/juju/agent"
	"github.com/juju/juju/api/common"
	apiprovisioner "github.com/juju/juju/api/provisioner"
	"github.com/juju/juju/apiserver/params"
	"github.com/juju/juju/cloudconfig/instancecfg"
	"github.com/juju/juju/container"
	"github.com/juju/juju/container/kvm"
	"github.com/juju/juju/container/lxd"
	"github.com/juju/juju/environs"
	"github.com/juju/juju/instance"
	"github.com/juju/juju/network"
	"github.com/juju/juju/state"
	"github.com/juju/juju/watcher"
	"github.com/juju/juju/worker"
)

var (
	systemNetworkInterfacesFile = "/etc/network/interfaces"
	activateBridgesTimeout      = 5 * time.Minute
)

// ContainerSetup is a StringsWatchHandler that is notified when containers
// are created on the given machine. It will set up the machine to be able
// to create containers and start a suitable provisioner.
type ContainerSetup struct {
	runner              worker.Runner
	supportedContainers []instance.ContainerType
	provisioner         *apiprovisioner.State
	machine             *apiprovisioner.Machine
	config              agent.Config
	initLockName        string

	// Save the workerName so the worker thread can be stopped.
	workerName string
	// setupDone[containerType] is non zero if the container setup has been invoked
	// for that container type.
	setupDone map[instance.ContainerType]*int32
	// The number of provisioners started. Once all necessary provisioners have
	// been started, the container watcher can be stopped.
	numberProvisioners int32
}

// ContainerSetupParams are used to initialise a container setup handler.
type ContainerSetupParams struct {
	Runner              worker.Runner
	WorkerName          string
	SupportedContainers []instance.ContainerType
	Machine             *apiprovisioner.Machine
	Provisioner         *apiprovisioner.State
	Config              agent.Config
	InitLockName        string
}

// NewContainerSetupHandler returns a StringsWatchHandler which is notified when
// containers are created on the given machine.
func NewContainerSetupHandler(params ContainerSetupParams) watcher.StringsHandler {
	return &ContainerSetup{
		runner:              params.Runner,
		machine:             params.Machine,
		supportedContainers: params.SupportedContainers,
		provisioner:         params.Provisioner,
		config:              params.Config,
		workerName:          params.WorkerName,
		initLockName:        params.InitLockName,
	}
}

// SetUp is defined on the StringsWatchHandler interface.
func (cs *ContainerSetup) SetUp() (watcher watcher.StringsWatcher, err error) {
	// Set up the semaphores for each container type.
	cs.setupDone = make(map[instance.ContainerType]*int32, len(instance.ContainerTypes))
	for _, containerType := range instance.ContainerTypes {
		zero := int32(0)
		cs.setupDone[containerType] = &zero
	}
	// Listen to all container lifecycle events on our machine.
	if watcher, err = cs.machine.WatchAllContainers(); err != nil {
		return nil, err
	}
	return watcher, nil
}

// Handle is called whenever containers change on the machine being watched.
// Machines start out with no containers so the first time Handle is called,
// it will be because a container has been added.
func (cs *ContainerSetup) Handle(abort <-chan struct{}, containerIds []string) (resultError error) {
	// Consume the initial watcher event.
	if len(containerIds) == 0 {
		return nil
	}

	logger.Infof("initial container setup with ids: %v", containerIds)
	for _, id := range containerIds {
		containerType := state.ContainerTypeFromId(id)
		// If this container type has been dealt with, do nothing.
		if atomic.LoadInt32(cs.setupDone[containerType]) != 0 {
			continue
		}
		if err := cs.initialiseAndStartProvisioner(abort, containerType); err != nil {
			logger.Errorf("starting container provisioner for %v: %v", containerType, err)
			// Just because dealing with one type of container fails, we won't exit the entire
			// function because we still want to try and start other container types. So we
			// take note of and return the first such error.
			if resultError == nil {
				resultError = err
			}
		}
	}
	return resultError
}

func (cs *ContainerSetup) initialiseAndStartProvisioner(abort <-chan struct{}, containerType instance.ContainerType) (resultError error) {
	// Flag that this container type has been handled.
	atomic.StoreInt32(cs.setupDone[containerType], 1)

	defer func() {
		if resultError != nil {
			logger.Warningf("not stopping machine agent container watcher due to error: %v", resultError)
			return
		}
		if atomic.AddInt32(&cs.numberProvisioners, 1) == int32(len(cs.supportedContainers)) {
			// We only care about the initial container creation.
			// This worker has done its job so stop it.
			// We do not expect there will be an error, and there's not much we can do anyway.
			if err := cs.runner.StopWorker(cs.workerName); err != nil {
				logger.Warningf("stopping machine agent container watcher: %v", err)
			}
		}
	}()

	logger.Debugf("setup and start provisioner for %s containers", containerType)
	toolsFinder := getToolsFinder(cs.provisioner)
	initialiser, broker, toolsFinder, err := cs.getContainerArtifacts(containerType, toolsFinder)
	if err != nil {
		return errors.Annotate(err, "initialising container infrastructure on host machine")
	}
	if err := cs.runInitialiser(abort, containerType, initialiser); err != nil {
		return errors.Annotate(err, "setting up container dependencies on host machine")
	}
	return StartProvisioner(cs.runner, containerType, cs.provisioner, cs.config, broker, toolsFinder)
}

// acquireLock tries to grab the machine lock (initLockName), and either
// returns it in a locked state, or returns an error.
func (cs *ContainerSetup) acquireLock(abort <-chan struct{}) (mutex.Releaser, error) {
	spec := mutex.Spec{
		Name:  cs.initLockName,
		Clock: clock.WallClock,
		// If we don't get the lock straight away, there is no point trying multiple
		// times per second for an operation that is likelty to take multiple seconds.
		Delay:  time.Second,
		Cancel: abort,
	}
	return mutex.Acquire(spec)
}

// runInitialiser runs the container initialiser with the initialisation hook held.
func (cs *ContainerSetup) runInitialiser(abort <-chan struct{}, containerType instance.ContainerType, initialiser container.Initialiser) error {
	logger.Debugf("running initialiser for %s containers, acquiring lock %q", containerType, cs.initLockName)
	releaser, err := cs.acquireLock(abort)
	if err != nil {
		return errors.Annotate(err, "failed to acquire initialization lock")
	}
	logger.Debugf("lock %q acquired", cs.initLockName)
	defer logger.Debugf("release lock %q for container initialisation", cs.initLockName)
	defer releaser.Release()

	if err := initialiser.Initialise(); err != nil {
		return errors.Trace(err)
	}

	return nil
}

// TearDown is defined on the StringsWatchHandler interface.
func (cs *ContainerSetup) TearDown() error {
	// Nothing to do here.
	return nil
}

func (cs *ContainerSetup) prepareHost(containerTag names.MachineTag, log loggo.Logger) error {
	devicesToBridge, reconfigureDelay, err := cs.provisioner.HostChangesForContainer(containerTag)
	if err != nil {
		return errors.Annotate(err, "unable to setup network")
	}

	if len(devicesToBridge) == 0 {
		log.Debugf("container %q requires no additional bridges", containerTag)
		return nil
	}

	bridger, err := network.DefaultEtcNetworkInterfacesBridger(activateBridgesTimeout, instancecfg.DefaultBridgePrefix, systemNetworkInterfacesFile)
	if err != nil {
		return errors.Trace(err)
	}

	log.Debugf("Bridging %+v devices on host %q with delay=%v, acquiring lock %q",
		devicesToBridge, cs.machine.MachineTag().String(), reconfigureDelay, cs.initLockName)
	// TODO(jam): 2017-02-08 figure out how to thread catacomb.Dying() into
	// this function, so that we can stop trying to acquire the lock if we are
	// stopping.
	releaser, err := cs.acquireLock(nil)
	if err != nil {
		return errors.Annotatef(err, "failed to acquire lock %q for bridging", cs.initLockName)
	}
	defer log.Debugf("releasing lock %q for bridging", cs.initLockName)
	defer releaser.Release()
	err = bridger.Bridge(devicesToBridge, reconfigureDelay)
	if err != nil {
		return errors.Annotate(err, "failed to bridge devices")
	}

	// We just changed the hosts' network setup so discover new
	// interfaces/devices and propagate to state.
	observedConfig, err := getObservedNetworkConfig(common.DefaultNetworkConfigSource())
	if err != nil {
		return errors.Annotate(err, "cannot discover observed network config")
	}

	if len(observedConfig) > 0 {
		err := cs.provisioner.SetHostMachineNetworkConfig(cs.machine.MachineTag(), observedConfig)
		if err != nil {
			return errors.Trace(err)
		}
		logger.Debugf("observed network config updated")
	}

	return nil
}

// getContainerArtifacts returns type-specific interfaces for
// managing containers.
//
// The ToolsFinder passed in may be replaced or wrapped to
// enforce container-specific constraints.
func (cs *ContainerSetup) getContainerArtifacts(
	containerType instance.ContainerType, toolsFinder ToolsFinder,
) (
	container.Initialiser,
	environs.InstanceBroker,
	ToolsFinder,
	error,
) {
	var initialiser container.Initialiser
	var broker environs.InstanceBroker

	managerConfig, err := containerManagerConfig(containerType, cs.provisioner, cs.config)
	if err != nil {
		return nil, nil, nil, err
	}

	bridger, err := network.DefaultEtcNetworkInterfacesBridger(activateBridgesTimeout, instancecfg.DefaultBridgePrefix, systemNetworkInterfacesFile)
	if err != nil {
		return nil, nil, nil, err
	}

	switch containerType {
	case instance.KVM:
		initialiser = kvm.NewContainerInitialiser()
		broker, err = NewKvmBroker(
			bridger,
			cs.machine.MachineTag(),
			cs.provisioner,
			cs.config,
			managerConfig,
		)
		if err != nil {
			logger.Errorf("failed to create new kvm broker")
			return nil, nil, nil, err
		}
	case instance.LXD:
		series, err := cs.machine.Series()
		if err != nil {
			return nil, nil, nil, err
		}

		initialiser = lxd.NewContainerInitialiser(series)
		manager, err := lxd.NewContainerManager(managerConfig)
		if err != nil {
			return nil, nil, nil, err
		}
		broker, err = NewLXDBroker(
			cs.prepareHost,
			cs.provisioner,
			manager,
			cs.config,
		)
		if err != nil {
			logger.Errorf("failed to create new lxd broker")
			return nil, nil, nil, err
		}
	default:
		return nil, nil, nil, fmt.Errorf("unknown container type: %v", containerType)
	}

	return initialiser, broker, toolsFinder, nil
}

func containerManagerConfig(
	containerType instance.ContainerType,
	provisioner *apiprovisioner.State,
	agentConfig agent.Config,
) (container.ManagerConfig, error) {
	// Ask the provisioner for the container manager configuration.
	managerConfigResult, err := provisioner.ContainerManagerConfig(
		params.ContainerManagerConfigParams{Type: containerType},
	)
	if err != nil {
		return nil, errors.Trace(err)
	}
	managerConfig := container.ManagerConfig(managerConfigResult.ManagerConfig)
	return managerConfig, nil
}

// Override for testing.
var StartProvisioner = startProvisionerWorker

// startProvisionerWorker kicks off a provisioner task responsible for creating containers
// of the specified type on the machine.
func startProvisionerWorker(
	runner worker.Runner,
	containerType instance.ContainerType,
	provisioner *apiprovisioner.State,
	config agent.Config,
	broker environs.InstanceBroker,
	toolsFinder ToolsFinder,
) error {

	workerName := fmt.Sprintf("%s-provisioner", containerType)
	// The provisioner task is created after a container record has
	// already been added to the machine. It will see that the
	// container does not have an instance yet and create one.
	return runner.StartWorker(workerName, func() (worker.Worker, error) {
		w, err := NewContainerProvisioner(containerType, provisioner, config, broker, toolsFinder)
		if err != nil {
			return nil, errors.Trace(err)
		}
		return w, nil
	})
}
<commit_msg>minimal fix for bug #1664437<commit_after>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package provisioner

import (
	"fmt"
	"sync/atomic"
	"time"

	"github.com/juju/errors"
	"github.com/juju/loggo"
	"github.com/juju/mutex"
	"github.com/juju/utils/clock"
	"gopkg.in/juju/names.v2"

	"github.com/juju/juju/agent"
	"github.com/juju/juju/api/common"
	apiprovisioner "github.com/juju/juju/api/provisioner"
	"github.com/juju/juju/apiserver/params"
	"github.com/juju/juju/cloudconfig/instancecfg"
	"github.com/juju/juju/container"
	"github.com/juju/juju/container/kvm"
	"github.com/juju/juju/container/lxd"
	"github.com/juju/juju/environs"
	"github.com/juju/juju/instance"
	"github.com/juju/juju/network"
	"github.com/juju/juju/state"
	"github.com/juju/juju/watcher"
	"github.com/juju/juju/worker"
)

var (
	systemNetworkInterfacesFile = "/etc/network/interfaces"
	activateBridgesTimeout      = 5 * time.Minute
)

// ContainerSetup is a StringsWatchHandler that is notified when containers
// are created on the given machine. It will set up the machine to be able
// to create containers and start a suitable provisioner.
type ContainerSetup struct {
	runner              worker.Runner
	supportedContainers []instance.ContainerType
	provisioner         *apiprovisioner.State
	machine             *apiprovisioner.Machine
	config              agent.Config
	initLockName        string

	// Save the workerName so the worker thread can be stopped.
	workerName string
	// setupDone[containerType] is non zero if the container setup has been invoked
	// for that container type.
	setupDone map[instance.ContainerType]*int32
	// The number of provisioners started. Once all necessary provisioners have
	// been started, the container watcher can be stopped.
	numberProvisioners int32
}

// ContainerSetupParams are used to initialise a container setup handler.
type ContainerSetupParams struct {
	Runner              worker.Runner
	WorkerName          string
	SupportedContainers []instance.ContainerType
	Machine             *apiprovisioner.Machine
	Provisioner         *apiprovisioner.State
	Config              agent.Config
	InitLockName        string
}

// NewContainerSetupHandler returns a StringsWatchHandler which is notified when
// containers are created on the given machine.
func NewContainerSetupHandler(params ContainerSetupParams) watcher.StringsHandler {
	return &ContainerSetup{
		runner:              params.Runner,
		machine:             params.Machine,
		supportedContainers: params.SupportedContainers,
		provisioner:         params.Provisioner,
		config:              params.Config,
		workerName:          params.WorkerName,
		initLockName:        params.InitLockName,
	}
}

// SetUp is defined on the StringsWatchHandler interface.
func (cs *ContainerSetup) SetUp() (watcher watcher.StringsWatcher, err error) {
	// Set up the semaphores for each container type.
	cs.setupDone = make(map[instance.ContainerType]*int32, len(instance.ContainerTypes))
	for _, containerType := range instance.ContainerTypes {
		zero := int32(0)
		cs.setupDone[containerType] = &zero
	}
	// Listen to all container lifecycle events on our machine.
	if watcher, err = cs.machine.WatchAllContainers(); err != nil {
		return nil, err
	}
	return watcher, nil
}

// Handle is called whenever containers change on the machine being watched.
// Machines start out with no containers so the first time Handle is called,
// it will be because a container has been added.
func (cs *ContainerSetup) Handle(abort <-chan struct{}, containerIds []string) (resultError error) {
	// Consume the initial watcher event.
	if len(containerIds) == 0 {
		return nil
	}

	logger.Infof("initial container setup with ids: %v", containerIds)
	for _, id := range containerIds {
		containerType := state.ContainerTypeFromId(id)
		// If this container type has been dealt with, do nothing.
		if atomic.LoadInt32(cs.setupDone[containerType]) != 0 {
			continue
		}
		if err := cs.initialiseAndStartProvisioner(abort, containerType); err != nil {
			logger.Errorf("starting container provisioner for %v: %v", containerType, err)
			// Just because dealing with one type of container fails, we won't exit the entire
			// function because we still want to try and start other container types. So we
			// take note of and return the first such error.
			if resultError == nil {
				resultError = err
			}
		}
	}
	return resultError
}

func (cs *ContainerSetup) initialiseAndStartProvisioner(abort <-chan struct{}, containerType instance.ContainerType) (resultError error) {
	// Flag that this container type has been handled.
	atomic.StoreInt32(cs.setupDone[containerType], 1)

	defer func() {
		if resultError != nil {
			logger.Warningf("not stopping machine agent container watcher due to error: %v", resultError)
			return
		}
		if atomic.AddInt32(&cs.numberProvisioners, 1) == int32(len(cs.supportedContainers)) {
			// We only care about the initial container creation.
			// This worker has done its job so stop it.
			// We do not expect there will be an error, and there's not much we can do anyway.
			if err := cs.runner.StopWorker(cs.workerName); err != nil {
				logger.Warningf("stopping machine agent container watcher: %v", err)
			}
		}
	}()

	logger.Debugf("setup and start provisioner for %s containers", containerType)
	toolsFinder := getToolsFinder(cs.provisioner)
	initialiser, broker, toolsFinder, err := cs.getContainerArtifacts(containerType, toolsFinder)
	if err != nil {
		return errors.Annotate(err, "initialising container infrastructure on host machine")
	}
	if err := cs.runInitialiser(abort, containerType, initialiser); err != nil {
		return errors.Annotate(err, "setting up container dependencies on host machine")
	}
	return StartProvisioner(cs.runner, containerType, cs.provisioner, cs.config, broker, toolsFinder)
}

// acquireLock tries to grab the machine lock (initLockName), and either
// returns it in a locked state, or returns an error.
func (cs *ContainerSetup) acquireLock(abort <-chan struct{}) (mutex.Releaser, error) {
	spec := mutex.Spec{
		Name:  cs.initLockName,
		Clock: clock.WallClock,
		// If we don't get the lock straight away, there is no point trying multiple
		// times per second for an operation that is likelty to take multiple seconds.
		Delay:  time.Second,
		Cancel: abort,
	}
	return mutex.Acquire(spec)
}

// runInitialiser runs the container initialiser with the initialisation hook held.
func (cs *ContainerSetup) runInitialiser(abort <-chan struct{}, containerType instance.ContainerType, initialiser container.Initialiser) error {
	logger.Debugf("running initialiser for %s containers, acquiring lock %q", containerType, cs.initLockName)
	releaser, err := cs.acquireLock(abort)
	if err != nil {
		return errors.Annotate(err, "failed to acquire initialization lock")
	}
	logger.Debugf("lock %q acquired", cs.initLockName)
	defer logger.Debugf("release lock %q for container initialisation", cs.initLockName)
	defer releaser.Release()

	if err := initialiser.Initialise(); err != nil {
		return errors.Trace(err)
	}

	return nil
}

// TearDown is defined on the StringsWatchHandler interface.
func (cs *ContainerSetup) TearDown() error {
	// Nothing to do here.
	return nil
}

func (cs *ContainerSetup) prepareHost(containerTag names.MachineTag, log loggo.Logger) error {
	devicesToBridge, reconfigureDelay, err := cs.provisioner.HostChangesForContainer(containerTag)
	if err != nil {
		return errors.Annotate(err, "unable to setup network")
	}

	if len(devicesToBridge) == 0 {
		log.Debugf("container %q requires no additional bridges", containerTag)
		return nil
	}

	bridger, err := network.DefaultEtcNetworkInterfacesBridger(activateBridgesTimeout, instancecfg.DefaultBridgePrefix, systemNetworkInterfacesFile)
	if err != nil {
		return errors.Trace(err)
	}

	log.Debugf("Bridging %+v devices on host %q for container %q with delay=%v, acquiring lock %q",
		devicesToBridge, cs.machine.MachineTag().String(), containerTag.String(), reconfigureDelay, cs.initLockName)
	// TODO(jam): 2017-02-08 figure out how to thread catacomb.Dying() into
	// this function, so that we can stop trying to acquire the lock if we are
	// stopping.
	releaser, err := cs.acquireLock(nil)
	if err != nil {
		return errors.Annotatef(err, "failed to acquire lock %q for bridging", cs.initLockName)
	}
	defer log.Debugf("releasing lock %q for bridging machine %q for container %q", cs.initLockName, cs.machine.MachineTag().String(), containerTag.String())
	defer releaser.Release()
	err = bridger.Bridge(devicesToBridge, reconfigureDelay)
	if err != nil {
		return errors.Annotate(err, "failed to bridge devices")
	}

	// We just changed the hosts' network setup so discover new
	// interfaces/devices and propagate to state.
	observedConfig, err := getObservedNetworkConfig(common.DefaultNetworkConfigSource())
	if err != nil {
		return errors.Annotate(err, "cannot discover observed network config")
	}

	if len(observedConfig) > 0 {
		err := cs.provisioner.SetHostMachineNetworkConfig(cs.machine.MachineTag(), observedConfig)
		if err != nil {
			return errors.Trace(err)
		}
		logger.Debugf("observed network config updated")
	}

	return nil
}

// getContainerArtifacts returns type-specific interfaces for
// managing containers.
//
// The ToolsFinder passed in may be replaced or wrapped to
// enforce container-specific constraints.
func (cs *ContainerSetup) getContainerArtifacts(
	containerType instance.ContainerType, toolsFinder ToolsFinder,
) (
	container.Initialiser,
	environs.InstanceBroker,
	ToolsFinder,
	error,
) {
	var initialiser container.Initialiser
	var broker environs.InstanceBroker

	managerConfig, err := containerManagerConfig(containerType, cs.provisioner, cs.config)
	if err != nil {
		return nil, nil, nil, err
	}

	switch containerType {
	case instance.KVM:
		initialiser = kvm.NewContainerInitialiser()
		manager, err := kvm.NewContainerManager(managerConfig)
		if err != nil {
			return nil, nil, nil, err
		}
		broker, err = NewKVMBroker(
			cs.prepareHost,
			cs.provisioner,
			manager,
			cs.config,
		)
		if err != nil {
			logger.Errorf("failed to create new kvm broker")
			return nil, nil, nil, err
		}
	case instance.LXD:
		series, err := cs.machine.Series()
		if err != nil {
			return nil, nil, nil, err
		}

		initialiser = lxd.NewContainerInitialiser(series)
		manager, err := lxd.NewContainerManager(managerConfig)
		if err != nil {
			return nil, nil, nil, err
		}
		broker, err = NewLXDBroker(
			cs.prepareHost,
			cs.provisioner,
			manager,
			cs.config,
		)
		if err != nil {
			logger.Errorf("failed to create new lxd broker")
			return nil, nil, nil, err
		}
	default:
		return nil, nil, nil, fmt.Errorf("unknown container type: %v", containerType)
	}

	return initialiser, broker, toolsFinder, nil
}

func containerManagerConfig(
	containerType instance.ContainerType,
	provisioner *apiprovisioner.State,
	agentConfig agent.Config,
) (container.ManagerConfig, error) {
	// Ask the provisioner for the container manager configuration.
	managerConfigResult, err := provisioner.ContainerManagerConfig(
		params.ContainerManagerConfigParams{Type: containerType},
	)
	if err != nil {
		return nil, errors.Trace(err)
	}
	managerConfig := container.ManagerConfig(managerConfigResult.ManagerConfig)
	return managerConfig, nil
}

// Override for testing.
var StartProvisioner = startProvisionerWorker

// startProvisionerWorker kicks off a provisioner task responsible for creating containers
// of the specified type on the machine.
func startProvisionerWorker(
	runner worker.Runner,
	containerType instance.ContainerType,
	provisioner *apiprovisioner.State,
	config agent.Config,
	broker environs.InstanceBroker,
	toolsFinder ToolsFinder,
) error {

	workerName := fmt.Sprintf("%s-provisioner", containerType)
	// The provisioner task is created after a container record has
	// already been added to the machine. It will see that the
	// container does not have an instance yet and create one.
	return runner.StartWorker(workerName, func() (worker.Worker, error) {
		w, err := NewContainerProvisioner(containerType, provisioner, config, broker, toolsFinder)
		if err != nil {
			return nil, errors.Trace(err)
		}
		return w, nil
	})
}
<|endoftext|>


<commit_before>package btce

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha512"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"time"
)

// TradeAPI allows to trade on the exchange and receive information about the account.
//
// To use this API, you need to create an API key. An API key can be created in your Profile in the API Keys section. After creating an API key you’ll receive a key and a secret.
// Note that the Secret can be received only during the first hour after the creation of the Key.
// API key information is used for authentication.
type TradeAPI struct {
	API_KEY    string
	API_SECRET string
	lastNonce  int64
}

const tradeURL = "https://btc-e.com/tapi"

// Auth provides API key and secret setting for Trade API
func (tapi *TradeAPI) Auth(key string, secret string) {
	tapi.API_KEY = key
	tapi.API_SECRET = secret
}

// GetInfo returns information about the user’s current balance, API-key privileges, the number of open orders and Server Time.
// To use this method you need a privilege of the key info.
func (tapi *TradeAPI) GetInfo() (AccountInfo, error) {
	info := AccountInfo{}
	err := tapi.call("getInfo", &info, nil)
	if err == nil {
		return info, nil
	}
	return info, err
}

// GetInfoAuth provides GetInfo capability with authorization
func (tapi *TradeAPI) GetInfoAuth(key string, secret string) (AccountInfo, error) {
	tapi.Auth(key, secret)
	return tapi.GetInfo()

}

// Trade provide method that can be used for creating orders and trading on the exchange.
// To use this method you need an API key privilege to trade.
//
// You can only create limit orders using this method, but you can emulate market orders using rate parameters. E.g. using rate=0.1 you can sell at the best market price.
//
// Each pair has a different limit on the minimum / maximum amounts, the minimum amount and the number of digits after the decimal point. All limitations can be obtained using the info method in PublicAPI.
func (tapi *TradeAPI) Trade(pair string, orderType string, rate float64, amount float64) (TradeResponse, error) {

	tradeResponse := TradeResponse{}

	orderParams := make(map[string]string, 4)
	orderParams["pair"] = pair
	orderParams["type"] = orderType
	orderParams["rate"] = strconv.FormatFloat(rate, 'f', -1, 64)
	orderParams["amount"] = strconv.FormatFloat(amount, 'f', -1, 64)

	err := tapi.call("Trade", &tradeResponse, orderParams)

	if err == nil {
		return tradeResponse, nil
	}
	return tradeResponse, err
}

// TradeAuth provides Trade capability with authorization
func (tapi *TradeAPI) TradeAuth(key string, secret string, pair string, orderType string, rate float64, amount float64) (TradeResponse, error) {
	tapi.Auth(key, secret)
	return tapi.Trade(pair, orderType, rate, amount)

}

// ActiveOrders returns the list of your active orders.  To use this method you need a privilege of the info key.
// If the order disappears from the list, it was either executed or canceled.
func (tapi *TradeAPI) ActiveOrders(pair string) (ActiveOrders, error) {

	orderParams := make(map[string]string, 4)
	orderParams["pair"] = pair

	activeOrders := make(ActiveOrders, 0)
	err := tapi.call("ActiveOrders", &activeOrders, orderParams)
	if err == nil {
		return activeOrders, nil
	}
	return activeOrders, err
}

// ActiveOrdersAuth provides ActiveOrders capability with authorization
func (tapi *TradeAPI) ActiveOrdersAuth(key string, secret string, pair string) (ActiveOrders, error) {
	tapi.Auth(key, secret)
	return tapi.ActiveOrders(pair)
}

// OrderInfo provides the information on particular order. To use this method you need a privilege of the info key.
func (tapi *TradeAPI) OrderInfo(orderID string) (OrderInfo, error) {

	orderInfo := OrderInfo{}

	orderParams := make(map[string]string, 1)
	orderParams["order_id"] = orderID

	err := tapi.call("OrderInfo", &orderInfo, orderParams)
	if err == nil {
		return orderInfo, nil
	}
	return orderInfo, err
}

// OrderInfoAuth provides OrderInfo capability with authorization
func (tapi *TradeAPI) OrderInfoAuth(key string, secret string, orderID string) (OrderInfo, error) {
	tapi.Auth(key, secret)
	return tapi.OrderInfo(orderID)

}

// CancelOrder provides method used for order cancellation. To use this method you need a privilege of the trade key.
func (tapi *TradeAPI) CancelOrder(orderID string) (CancelOrder, error) {

	cancelReponse := CancelOrder{}

	orderParams := make(map[string]string, 1)
	orderParams["order_id"] = orderID

	err := tapi.call("CancelOrder", &cancelReponse, orderParams)

	if err == nil {
		return cancelReponse, nil
	}
	return cancelReponse, err
}

// CancelOrderAuth provides CancelOrder capability with authorization
func (tapi *TradeAPI) CancelOrderAuth(key string, secret string, orderID string) (CancelOrder, error) {
	tapi.Auth(key, secret)
	return tapi.CancelOrder(orderID)

}

// TradeHistory returns trade history. To use this method you need a privilege of the info key.
func (tapi *TradeAPI) TradeHistory(filter HistoryFilter, pair string) (TradeHistory, error) {

	tradeHistory := TradeHistory{}

	historyParams := historyFilterParams(filter)
	if pair != "" {
		historyParams["pair"] = pair
	}

	err := tapi.call("TradeHistory", &tradeHistory, historyParams)

	if err == nil {
		return tradeHistory, nil
	}
	return tradeHistory, err
}

// TradeHistoryAuth provides TradeHistory capability with authorization
func (tapi *TradeAPI) TradeHistoryAuth(key string, secret string, filter HistoryFilter, pair string) (TradeHistory, error) {
	tapi.Auth(key, secret)
	return tapi.TradeHistory(filter, pair)

}

// TransactionHistory returns the history of transactions. To use this method you need a privilege of the info key.
func (tapi *TradeAPI) TransactionHistory(filter HistoryFilter) (TransactionHistory, error) {

	transactionHistory := TransactionHistory{}

	historyParams := historyFilterParams(filter)

	err := tapi.call("TransHistory", &transactionHistory, historyParams)

	if err == nil {
		return transactionHistory, nil
	}
	return transactionHistory, err
}

// TransactionHistoryAuth provides TransactionHistory capability with authorization
func (tapi *TradeAPI) TransactionHistoryAuth(key string, secret string, filter HistoryFilter) (TransactionHistory, error) {
	tapi.Auth(key, secret)
	return tapi.TransactionHistory(filter)

}

// WithdrawCoin provides cryptocurrency withdrawals. You need to have the privilege of the Withdraw key to be able to use this method.
func (tapi *TradeAPI) WithdrawCoin(coinName string, amount float64, address string) (WithdrawCoin, error) {

	response := WithdrawCoin{}

	orderParams := make(map[string]string, 3)
	orderParams["coinName"] = coinName
	orderParams["amount"] = strconv.FormatFloat(amount, 'f', -1, 64)
	orderParams["address"] = address

	err := tapi.call("WithdrawCoin", &response, orderParams)

	if err == nil {
		return response, nil
	}
	return response, err
}

// WithdrawCoinAuth provides WithdrawCoin capability with authorization
func (tapi *TradeAPI) WithdrawCoinAuth(key string, secret string, coinName string, amount float64, address string) (WithdrawCoin, error) {
	tapi.Auth(key, secret)
	return tapi.WithdrawCoin(coinName, amount, address)

}

// CreateCoupon allows you to create Coupons. In order to use this method, you need the Coupon key privilege.
func (tapi *TradeAPI) CreateCoupon(currency string, amount float64) (CreateCoupon, error) {

	response := CreateCoupon{}

	params := make(map[string]string, 2)
	params["currency"] = currency
	params["amount"] = strconv.FormatFloat(amount, 'f', -1, 64)

	err := tapi.call("CreateCoupon", &response, params)

	if err == nil {
		return response, nil
	}
	return response, err
}

// CreateCouponAuth provides CreateCoupon capability with authorization
func (tapi *TradeAPI) CreateCouponAuth(key string, secret string, currency string, amount float64) (CreateCoupon, error) {
	tapi.Auth(key, secret)
	return tapi.CreateCoupon(currency, amount)
}

// RedeemCoupon method is used to redeem coupons. In order to use this method, you need the Coupon key privilege.
func (tapi *TradeAPI) RedeemCoupon(coupon string) (RedeemCoupon, error) {

	response := RedeemCoupon{}

	params := make(map[string]string, 1)
	params["coupon"] = coupon

	err := tapi.call("RedeemCoupon", &response, params)

	if err == nil {
		return response, nil
	}
	return response, err
}

// RedeemCouponAuth provides RedeemCoupon capability with authorization
func (tapi *TradeAPI) RedeemCouponAuth(key string, secret string, coupon string) (RedeemCoupon, error) {
	tapi.Auth(key, secret)
	return tapi.RedeemCoupon(coupon)
}

func (tapi *TradeAPI) encodePostData(method string, params map[string]string) string {
	if tapi.lastNonce == 0 {
		tapi.lastNonce = time.Now().Unix()
	}
	tapi.lastNonce += 1
	result := fmt.Sprintf("method=%s&nonce=%d", method, tapi.lastNonce)

	if len(params) > 0 {
		v := url.Values{}
		for key := range params {
			v.Add(key, params[key])
		}
		result = result + "&" + v.Encode()
	}
	return result
}

func sign(secret string, payload string) string {
	mac := hmac.New(sha512.New, []byte(secret))
	mac.Write([]byte(payload))
	return hex.EncodeToString(mac.Sum(nil))
}

func (tapi *TradeAPI) call(method string, v interface{}, params map[string]string) error {

	postData := tapi.encodePostData(method, params)

	req, err := http.NewRequest("POST", tradeURL, bytes.NewBufferString(postData))

	if err != nil {
		return err
	}

	req.Header.Add("Key", tapi.API_KEY)
	req.Header.Add("Sign", sign(tapi.API_SECRET, postData))
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Add("Content-Length", strconv.Itoa(len(postData)))

	client := &http.Client{}
	resp, err := client.Do(req)

	if err != nil {
		return err
	}

	return marshalResponse(resp, v)
}

func marshalResponse(resp *http.Response, v interface{}) error {
	// read the response
	defer resp.Body.Close()
	bytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	data := Response{}

	if err = json.Unmarshal(bytes, &data); err != nil {
		return err
	}

	if data.Success == 1 {
		if err = json.Unmarshal(data.Return, &v); err != nil {
			return err
		}
	} else {
		return TradeError{data.Error}
	}

	return nil
}

// custom error type for server/trading errors
type TradeError struct {
	msg string
}

func (e TradeError) Error() string {
	return fmt.Sprintf("trading error: %v", e.msg)
}

// historyFilterParams creates map[string]string mapping of HistoryFilter
func historyFilterParams(filter HistoryFilter) map[string]string {
	params := make(map[string]string, 0)

	if filter.From > 0 {
		params["from"] = strconv.Itoa(filter.From)
	}
	if filter.Count > 0 {
		params["count"] = strconv.Itoa(filter.Count)
	}
	if filter.FromID > 0 {
		params["from_id"] = strconv.Itoa(filter.FromID)
	}
	if filter.EndID > 0 {
		params["end_id"] = strconv.Itoa(filter.EndID)
	}
	if filter.Order == "ASC" || filter.Order == "DESC" {
		params["order"] = filter.Order
	}
	if filter.Since.Unix() > 0 {
		params["since"] = strconv.FormatInt(filter.Since.Unix(), 10)
	}
	if filter.End.Unix() > 0 {
		params["end"] = strconv.FormatInt(filter.End.Unix(), 10)
	}
	return params
}
<commit_msg>Revert nonce handling<commit_after>package btce

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha512"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"time"
)

// TradeAPI allows to trade on the exchange and receive information about the account.
//
// To use this API, you need to create an API key. An API key can be created in your Profile in the API Keys section. After creating an API key you’ll receive a key and a secret.
// Note that the Secret can be received only during the first hour after the creation of the Key.
// API key information is used for authentication.
type TradeAPI struct {
	API_KEY    string
	API_SECRET string
	lastNonce  int64
}

const tradeURL = "https://btc-e.com/tapi"

// Auth provides API key and secret setting for Trade API
func (tapi *TradeAPI) Auth(key string, secret string) {
	tapi.API_KEY = key
	tapi.API_SECRET = secret
}

// GetInfo returns information about the user’s current balance, API-key privileges, the number of open orders and Server Time.
// To use this method you need a privilege of the key info.
func (tapi *TradeAPI) GetInfo() (AccountInfo, error) {
	info := AccountInfo{}
	err := tapi.call("getInfo", &info, nil)
	if err == nil {
		return info, nil
	}
	return info, err
}

// GetInfoAuth provides GetInfo capability with authorization
func (tapi *TradeAPI) GetInfoAuth(key string, secret string) (AccountInfo, error) {
	tapi.Auth(key, secret)
	return tapi.GetInfo()

}

// Trade provide method that can be used for creating orders and trading on the exchange.
// To use this method you need an API key privilege to trade.
//
// You can only create limit orders using this method, but you can emulate market orders using rate parameters. E.g. using rate=0.1 you can sell at the best market price.
//
// Each pair has a different limit on the minimum / maximum amounts, the minimum amount and the number of digits after the decimal point. All limitations can be obtained using the info method in PublicAPI.
func (tapi *TradeAPI) Trade(pair string, orderType string, rate float64, amount float64) (TradeResponse, error) {

	tradeResponse := TradeResponse{}

	orderParams := make(map[string]string, 4)
	orderParams["pair"] = pair
	orderParams["type"] = orderType
	orderParams["rate"] = strconv.FormatFloat(rate, 'f', -1, 64)
	orderParams["amount"] = strconv.FormatFloat(amount, 'f', -1, 64)

	err := tapi.call("Trade", &tradeResponse, orderParams)

	if err == nil {
		return tradeResponse, nil
	}
	return tradeResponse, err
}

// TradeAuth provides Trade capability with authorization
func (tapi *TradeAPI) TradeAuth(key string, secret string, pair string, orderType string, rate float64, amount float64) (TradeResponse, error) {
	tapi.Auth(key, secret)
	return tapi.Trade(pair, orderType, rate, amount)

}

// ActiveOrders returns the list of your active orders.  To use this method you need a privilege of the info key.
// If the order disappears from the list, it was either executed or canceled.
func (tapi *TradeAPI) ActiveOrders(pair string) (ActiveOrders, error) {

	orderParams := make(map[string]string, 4)
	orderParams["pair"] = pair

	activeOrders := make(ActiveOrders, 0)
	err := tapi.call("ActiveOrders", &activeOrders, orderParams)
	if err == nil {
		return activeOrders, nil
	}
	return activeOrders, err
}

// ActiveOrdersAuth provides ActiveOrders capability with authorization
func (tapi *TradeAPI) ActiveOrdersAuth(key string, secret string, pair string) (ActiveOrders, error) {
	tapi.Auth(key, secret)
	return tapi.ActiveOrders(pair)
}

// OrderInfo provides the information on particular order. To use this method you need a privilege of the info key.
func (tapi *TradeAPI) OrderInfo(orderID string) (OrderInfo, error) {

	orderInfo := OrderInfo{}

	orderParams := make(map[string]string, 1)
	orderParams["order_id"] = orderID

	err := tapi.call("OrderInfo", &orderInfo, orderParams)
	if err == nil {
		return orderInfo, nil
	}
	return orderInfo, err
}

// OrderInfoAuth provides OrderInfo capability with authorization
func (tapi *TradeAPI) OrderInfoAuth(key string, secret string, orderID string) (OrderInfo, error) {
	tapi.Auth(key, secret)
	return tapi.OrderInfo(orderID)

}

// CancelOrder provides method used for order cancellation. To use this method you need a privilege of the trade key.
func (tapi *TradeAPI) CancelOrder(orderID string) (CancelOrder, error) {

	cancelReponse := CancelOrder{}

	orderParams := make(map[string]string, 1)
	orderParams["order_id"] = orderID

	err := tapi.call("CancelOrder", &cancelReponse, orderParams)

	if err == nil {
		return cancelReponse, nil
	}
	return cancelReponse, err
}

// CancelOrderAuth provides CancelOrder capability with authorization
func (tapi *TradeAPI) CancelOrderAuth(key string, secret string, orderID string) (CancelOrder, error) {
	tapi.Auth(key, secret)
	return tapi.CancelOrder(orderID)

}

// TradeHistory returns trade history. To use this method you need a privilege of the info key.
func (tapi *TradeAPI) TradeHistory(filter HistoryFilter, pair string) (TradeHistory, error) {

	tradeHistory := TradeHistory{}

	historyParams := historyFilterParams(filter)
	if pair != "" {
		historyParams["pair"] = pair
	}

	err := tapi.call("TradeHistory", &tradeHistory, historyParams)

	if err == nil {
		return tradeHistory, nil
	}
	return tradeHistory, err
}

// TradeHistoryAuth provides TradeHistory capability with authorization
func (tapi *TradeAPI) TradeHistoryAuth(key string, secret string, filter HistoryFilter, pair string) (TradeHistory, error) {
	tapi.Auth(key, secret)
	return tapi.TradeHistory(filter, pair)

}

// TransactionHistory returns the history of transactions. To use this method you need a privilege of the info key.
func (tapi *TradeAPI) TransactionHistory(filter HistoryFilter) (TransactionHistory, error) {

	transactionHistory := TransactionHistory{}

	historyParams := historyFilterParams(filter)

	err := tapi.call("TransHistory", &transactionHistory, historyParams)

	if err == nil {
		return transactionHistory, nil
	}
	return transactionHistory, err
}

// TransactionHistoryAuth provides TransactionHistory capability with authorization
func (tapi *TradeAPI) TransactionHistoryAuth(key string, secret string, filter HistoryFilter) (TransactionHistory, error) {
	tapi.Auth(key, secret)
	return tapi.TransactionHistory(filter)

}

// WithdrawCoin provides cryptocurrency withdrawals. You need to have the privilege of the Withdraw key to be able to use this method.
func (tapi *TradeAPI) WithdrawCoin(coinName string, amount float64, address string) (WithdrawCoin, error) {

	response := WithdrawCoin{}

	orderParams := make(map[string]string, 3)
	orderParams["coinName"] = coinName
	orderParams["amount"] = strconv.FormatFloat(amount, 'f', -1, 64)
	orderParams["address"] = address

	err := tapi.call("WithdrawCoin", &response, orderParams)

	if err == nil {
		return response, nil
	}
	return response, err
}

// WithdrawCoinAuth provides WithdrawCoin capability with authorization
func (tapi *TradeAPI) WithdrawCoinAuth(key string, secret string, coinName string, amount float64, address string) (WithdrawCoin, error) {
	tapi.Auth(key, secret)
	return tapi.WithdrawCoin(coinName, amount, address)

}

// CreateCoupon allows you to create Coupons. In order to use this method, you need the Coupon key privilege.
func (tapi *TradeAPI) CreateCoupon(currency string, amount float64) (CreateCoupon, error) {

	response := CreateCoupon{}

	params := make(map[string]string, 2)
	params["currency"] = currency
	params["amount"] = strconv.FormatFloat(amount, 'f', -1, 64)

	err := tapi.call("CreateCoupon", &response, params)

	if err == nil {
		return response, nil
	}
	return response, err
}

// CreateCouponAuth provides CreateCoupon capability with authorization
func (tapi *TradeAPI) CreateCouponAuth(key string, secret string, currency string, amount float64) (CreateCoupon, error) {
	tapi.Auth(key, secret)
	return tapi.CreateCoupon(currency, amount)
}

// RedeemCoupon method is used to redeem coupons. In order to use this method, you need the Coupon key privilege.
func (tapi *TradeAPI) RedeemCoupon(coupon string) (RedeemCoupon, error) {

	response := RedeemCoupon{}

	params := make(map[string]string, 1)
	params["coupon"] = coupon

	err := tapi.call("RedeemCoupon", &response, params)

	if err == nil {
		return response, nil
	}
	return response, err
}

// RedeemCouponAuth provides RedeemCoupon capability with authorization
func (tapi *TradeAPI) RedeemCouponAuth(key string, secret string, coupon string) (RedeemCoupon, error) {
	tapi.Auth(key, secret)
	return tapi.RedeemCoupon(coupon)
}

func (tapi *TradeAPI) encodePostData(method string, params map[string]string) string {
	nonce := time.Now().Unix()
	if nonce <= tapi.lastNonce {
		nonce = tapi.lastNonce + 1
	}
	tapi.lastNonce = nonce

	result := fmt.Sprintf("method=%s&nonce=%d", method, nonce)

	if len(params) > 0 {
		v := url.Values{}
		for key := range params {
			v.Add(key, params[key])
		}
		result = result + "&" + v.Encode()
	}
	return result
}

func sign(secret string, payload string) string {
	mac := hmac.New(sha512.New, []byte(secret))
	mac.Write([]byte(payload))
	return hex.EncodeToString(mac.Sum(nil))
}

func (tapi *TradeAPI) call(method string, v interface{}, params map[string]string) error {

	postData := tapi.encodePostData(method, params)

	req, err := http.NewRequest("POST", tradeURL, bytes.NewBufferString(postData))

	if err != nil {
		return err
	}

	req.Header.Add("Key", tapi.API_KEY)
	req.Header.Add("Sign", sign(tapi.API_SECRET, postData))
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Add("Content-Length", strconv.Itoa(len(postData)))

	client := &http.Client{}
	resp, err := client.Do(req)

	if err != nil {
		return err
	}

	return marshalResponse(resp, v)
}

func marshalResponse(resp *http.Response, v interface{}) error {
	// read the response
	defer resp.Body.Close()
	bytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	data := Response{}

	if err = json.Unmarshal(bytes, &data); err != nil {
		return err
	}

	if data.Success == 1 {
		if err = json.Unmarshal(data.Return, &v); err != nil {
			return err
		}
	} else {
		return TradeError{data.Error}
	}

	return nil
}

// custom error type for server/trading errors
type TradeError struct {
	msg string
}

func (e TradeError) Error() string {
	return fmt.Sprintf("trading error: %v", e.msg)
}

// historyFilterParams creates map[string]string mapping of HistoryFilter
func historyFilterParams(filter HistoryFilter) map[string]string {
	params := make(map[string]string, 0)

	if filter.From > 0 {
		params["from"] = strconv.Itoa(filter.From)
	}
	if filter.Count > 0 {
		params["count"] = strconv.Itoa(filter.Count)
	}
	if filter.FromID > 0 {
		params["from_id"] = strconv.Itoa(filter.FromID)
	}
	if filter.EndID > 0 {
		params["end_id"] = strconv.Itoa(filter.EndID)
	}
	if filter.Order == "ASC" || filter.Order == "DESC" {
		params["order"] = filter.Order
	}
	if filter.Since.Unix() > 0 {
		params["since"] = strconv.FormatInt(filter.Since.Unix(), 10)
	}
	if filter.End.Unix() > 0 {
		params["end"] = strconv.FormatInt(filter.End.Unix(), 10)
	}
	return params
}
<|endoftext|>


<commit_before>package filersink

import (
	"context"
	"fmt"

	"github.com/chrislusf/seaweedfs/weed/filer2"
	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
	"github.com/chrislusf/seaweedfs/weed/replication/sink"
	"github.com/chrislusf/seaweedfs/weed/replication/source"
	"github.com/chrislusf/seaweedfs/weed/util"
)

type FilerSink struct {
	filerSource *source.FilerSource
	grpcAddress string
	dir         string
	replication string
	collection  string
	ttlSec      int32
	dataCenter  string
}

func init() {
	sink.Sinks = append(sink.Sinks, &FilerSink{})
}

func (fs *FilerSink) GetName() string {
	return "filer"
}

func (fs *FilerSink) GetSinkToDirectory() string {
	return fs.dir
}

func (fs *FilerSink) Initialize(configuration util.Configuration) error {
	return fs.initialize(
		configuration.GetString("grpcAddress"),
		configuration.GetString("directory"),
		configuration.GetString("replication"),
		configuration.GetString("collection"),
		configuration.GetInt("ttlSec"),
	)
}

func (fs *FilerSink) SetSourceFiler(s *source.FilerSource) {
	fs.filerSource = s
}

func (fs *FilerSink) initialize(grpcAddress string, dir string,
	replication string, collection string, ttlSec int) (err error) {
	fs.grpcAddress = grpcAddress
	fs.dir = dir
	fs.replication = replication
	fs.collection = collection
	fs.ttlSec = int32(ttlSec)
	return nil
}

func (fs *FilerSink) DeleteEntry(key string, isDirectory, deleteIncludeChunks bool) error {
	return fs.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {

		dir, name := filer2.FullPath(key).DirAndName()

		request := &filer_pb.DeleteEntryRequest{
			Directory:    dir,
			Name:         name,
			IsDirectory:  isDirectory,
			IsDeleteData: deleteIncludeChunks,
		}

		glog.V(1).Infof("delete entry: %v", request)
		_, err := client.DeleteEntry(context.Background(), request)
		if err != nil {
			glog.V(0).Infof("delete entry %s: %v", key, err)
			return fmt.Errorf("delete entry %s: %v", key, err)
		}

		return nil
	})
}

func (fs *FilerSink) CreateEntry(key string, entry *filer_pb.Entry) error {

	return fs.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {

		dir, name := filer2.FullPath(key).DirAndName()
		ctx := context.Background()

		// look up existing entry
		lookupRequest := &filer_pb.LookupDirectoryEntryRequest{
			Directory: dir,
			Name:      name,
		}
		glog.V(1).Infof("lookup: %v", lookupRequest)
		if resp, err := client.LookupDirectoryEntry(ctx, lookupRequest); err == nil {
			if filer2.ETag(resp.Entry.Chunks) == filer2.ETag(entry.Chunks) {
				glog.V(0).Infof("already replicated %s", key)
				return nil
			}
		}

		replicatedChunks, err := fs.replicateChunks(entry.Chunks)

		if err != nil {
			glog.V(0).Infof("replicate entry chunks %s: %v", key, err)
			return fmt.Errorf("replicate entry chunks %s: %v", key, err)
		}

		glog.V(0).Infof("replicated %s %+v ===> %+v", key, entry.Chunks, replicatedChunks)

		request := &filer_pb.CreateEntryRequest{
			Directory: dir,
			Entry: &filer_pb.Entry{
				Name:        name,
				IsDirectory: entry.IsDirectory,
				Attributes:  entry.Attributes,
				Chunks:      replicatedChunks,
			},
		}

		glog.V(1).Infof("create: %v", request)
		if _, err := client.CreateEntry(ctx, request); err != nil {
			glog.V(0).Infof("create entry %s: %v", key, err)
			return fmt.Errorf("create entry %s: %v", key, err)
		}

		return nil
	})
}

func (fs *FilerSink) UpdateEntry(key string, oldEntry, newEntry *filer_pb.Entry, deleteIncludeChunks bool) (foundExistingEntry bool, err error) {

	ctx := context.Background()

	dir, name := filer2.FullPath(key).DirAndName()

	// read existing entry
	var existingEntry *filer_pb.Entry
	err = fs.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {

		request := &filer_pb.LookupDirectoryEntryRequest{
			Directory: dir,
			Name:      name,
		}

		glog.V(4).Infof("lookup entry: %v", request)
		resp, err := client.LookupDirectoryEntry(ctx, request)
		if err != nil {
			glog.V(0).Infof("lookup %s: %v", key, err)
			return err
		}

		existingEntry = resp.Entry

		return nil
	})

	if err != nil {
		return false, fmt.Errorf("lookup %s: %v", key, err)
	}

	glog.V(0).Infof("oldEntry %+v, newEntry %+v, existingEntry: %+v", oldEntry, newEntry, existingEntry)

	if filer2.ETag(newEntry.Chunks) == filer2.ETag(existingEntry.Chunks) {
		// skip if no change
		// this usually happens when retrying the replication
		glog.V(0).Infof("already replicated %s", key)
	} else {
		// find out what changed
		deletedChunks, newChunks := compareChunks(oldEntry, newEntry)

		// delete the chunks that are deleted from the source
		if deleteIncludeChunks {
			// remove the deleted chunks. Actual data deletion happens in filer UpdateEntry FindUnusedFileChunks
			existingEntry.Chunks = minusChunks(existingEntry.Chunks, deletedChunks)
		}

		// replicate the chunks that are new in the source
		replicatedChunks, err := fs.replicateChunks(newChunks)
		if err != nil {
			return true, fmt.Errorf("replicte %s chunks error: %v", key, err)
		}
		existingEntry.Chunks = append(existingEntry.Chunks, replicatedChunks...)
	}

	// save updated meta data
	return true, fs.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {

		request := &filer_pb.UpdateEntryRequest{
			Directory: dir,
			Entry:     existingEntry,
		}

		if _, err := client.UpdateEntry(ctx, request); err != nil {
			return fmt.Errorf("update existingEntry %s: %v", key, err)
		}

		return nil
	})

}
func compareChunks(oldEntry, newEntry *filer_pb.Entry) (deletedChunks, newChunks []*filer_pb.FileChunk) {
	deletedChunks = minusChunks(oldEntry.Chunks, newEntry.Chunks)
	newChunks = minusChunks(newEntry.Chunks, oldEntry.Chunks)
	return
}

func minusChunks(as, bs []*filer_pb.FileChunk) (delta []*filer_pb.FileChunk) {
	for _, a := range as {
		found := false
		for _, b := range bs {
			if a.FileId == b.FileId {
				found = true
				break
			}
		}
		if !found {
			delta = append(delta, a)
		}
	}
	return
}
<commit_msg>filer ordered notifications<commit_after>package filersink

import (
	"context"
	"fmt"

	"github.com/chrislusf/seaweedfs/weed/filer2"
	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
	"github.com/chrislusf/seaweedfs/weed/replication/sink"
	"github.com/chrislusf/seaweedfs/weed/replication/source"
	"github.com/chrislusf/seaweedfs/weed/util"
)

type FilerSink struct {
	filerSource *source.FilerSource
	grpcAddress string
	dir         string
	replication string
	collection  string
	ttlSec      int32
	dataCenter  string
}

func init() {
	sink.Sinks = append(sink.Sinks, &FilerSink{})
}

func (fs *FilerSink) GetName() string {
	return "filer"
}

func (fs *FilerSink) GetSinkToDirectory() string {
	return fs.dir
}

func (fs *FilerSink) Initialize(configuration util.Configuration) error {
	return fs.initialize(
		configuration.GetString("grpcAddress"),
		configuration.GetString("directory"),
		configuration.GetString("replication"),
		configuration.GetString("collection"),
		configuration.GetInt("ttlSec"),
	)
}

func (fs *FilerSink) SetSourceFiler(s *source.FilerSource) {
	fs.filerSource = s
}

func (fs *FilerSink) initialize(grpcAddress string, dir string,
	replication string, collection string, ttlSec int) (err error) {
	fs.grpcAddress = grpcAddress
	fs.dir = dir
	fs.replication = replication
	fs.collection = collection
	fs.ttlSec = int32(ttlSec)
	return nil
}

func (fs *FilerSink) DeleteEntry(key string, isDirectory, deleteIncludeChunks bool) error {
	return fs.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {

		dir, name := filer2.FullPath(key).DirAndName()

		request := &filer_pb.DeleteEntryRequest{
			Directory:    dir,
			Name:         name,
			IsDirectory:  isDirectory,
			IsDeleteData: deleteIncludeChunks,
		}

		glog.V(1).Infof("delete entry: %v", request)
		_, err := client.DeleteEntry(context.Background(), request)
		if err != nil {
			glog.V(0).Infof("delete entry %s: %v", key, err)
			return fmt.Errorf("delete entry %s: %v", key, err)
		}

		return nil
	})
}

func (fs *FilerSink) CreateEntry(key string, entry *filer_pb.Entry) error {

	return fs.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {

		dir, name := filer2.FullPath(key).DirAndName()
		ctx := context.Background()

		// look up existing entry
		lookupRequest := &filer_pb.LookupDirectoryEntryRequest{
			Directory: dir,
			Name:      name,
		}
		glog.V(1).Infof("lookup: %v", lookupRequest)
		if resp, err := client.LookupDirectoryEntry(ctx, lookupRequest); err == nil {
			if filer2.ETag(resp.Entry.Chunks) == filer2.ETag(entry.Chunks) {
				glog.V(0).Infof("already replicated %s", key)
				return nil
			}
		}

		replicatedChunks, err := fs.replicateChunks(entry.Chunks)

		if err != nil {
			glog.V(0).Infof("replicate entry chunks %s: %v", key, err)
			return fmt.Errorf("replicate entry chunks %s: %v", key, err)
		}

		glog.V(0).Infof("replicated %s %+v ===> %+v", key, entry.Chunks, replicatedChunks)

		request := &filer_pb.CreateEntryRequest{
			Directory: dir,
			Entry: &filer_pb.Entry{
				Name:        name,
				IsDirectory: entry.IsDirectory,
				Attributes:  entry.Attributes,
				Chunks:      replicatedChunks,
			},
		}

		glog.V(1).Infof("create: %v", request)
		if _, err := client.CreateEntry(ctx, request); err != nil {
			glog.V(0).Infof("create entry %s: %v", key, err)
			return fmt.Errorf("create entry %s: %v", key, err)
		}

		return nil
	})
}

func (fs *FilerSink) UpdateEntry(key string, oldEntry, newEntry *filer_pb.Entry, deleteIncludeChunks bool) (foundExistingEntry bool, err error) {

	ctx := context.Background()

	dir, name := filer2.FullPath(key).DirAndName()

	// read existing entry
	var existingEntry *filer_pb.Entry
	err = fs.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {

		request := &filer_pb.LookupDirectoryEntryRequest{
			Directory: dir,
			Name:      name,
		}

		glog.V(4).Infof("lookup entry: %v", request)
		resp, err := client.LookupDirectoryEntry(ctx, request)
		if err != nil {
			glog.V(0).Infof("lookup %s: %v", key, err)
			return err
		}

		existingEntry = resp.Entry

		return nil
	})

	if err != nil {
		return false, fmt.Errorf("lookup %s: %v", key, err)
	}

	glog.V(0).Infof("oldEntry %+v, newEntry %+v, existingEntry: %+v", oldEntry, newEntry, existingEntry)

	if existingEntry.Attributes.Mtime > newEntry.Attributes.Mtime {
		// skip if already changed
		// this usually happens when the messages are not ordered
		glog.V(0).Infof("late updates %s", key)
	} else if filer2.ETag(newEntry.Chunks) == filer2.ETag(existingEntry.Chunks) {
		// skip if no change
		// this usually happens when retrying the replication
		glog.V(0).Infof("already replicated %s", key)
	} else {
		// find out what changed
		deletedChunks, newChunks := compareChunks(oldEntry, newEntry)

		// delete the chunks that are deleted from the source
		if deleteIncludeChunks {
			// remove the deleted chunks. Actual data deletion happens in filer UpdateEntry FindUnusedFileChunks
			existingEntry.Chunks = minusChunks(existingEntry.Chunks, deletedChunks)
		}

		// replicate the chunks that are new in the source
		replicatedChunks, err := fs.replicateChunks(newChunks)
		if err != nil {
			return true, fmt.Errorf("replicte %s chunks error: %v", key, err)
		}
		existingEntry.Chunks = append(existingEntry.Chunks, replicatedChunks...)
	}

	// save updated meta data
	return true, fs.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {

		request := &filer_pb.UpdateEntryRequest{
			Directory: dir,
			Entry:     existingEntry,
		}

		if _, err := client.UpdateEntry(ctx, request); err != nil {
			return fmt.Errorf("update existingEntry %s: %v", key, err)
		}

		return nil
	})

}
func compareChunks(oldEntry, newEntry *filer_pb.Entry) (deletedChunks, newChunks []*filer_pb.FileChunk) {
	deletedChunks = minusChunks(oldEntry.Chunks, newEntry.Chunks)
	newChunks = minusChunks(newEntry.Chunks, oldEntry.Chunks)
	return
}

func minusChunks(as, bs []*filer_pb.FileChunk) (delta []*filer_pb.FileChunk) {
	for _, a := range as {
		found := false
		for _, b := range bs {
			if a.FileId == b.FileId {
				found = true
				break
			}
		}
		if !found {
			delta = append(delta, a)
		}
	}
	return
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"gopkg.in/yaml.v2"
	"io/ioutil"
	"os"
)

func removeDirectories(directories []string) {
	for _, directory := range directories {

		if err := os.RemoveAll(directory); err != nil {
			fmt.Println(err)
		}
	}
}

func readConfigFile() {
	configFile := os.Getenv("HOME") + "/.houki.yml"

	buf, err := ioutil.ReadFile(configFile)
	if err != nil {
		fmt.Println(err)
		return
	}

	m := make(map[interface{}]interface{})
	err = yaml.Unmarshal(buf, &m)
	if err != nil {
		panic(err)
	}

	fmt.Printf("%s\n", m["Directory"])
}

func main() {
	readConfigFile()
	directories := []string{"tmp"}
	removeDirectories(directories)

	fmt.Println("Have cleaned")
}
<commit_msg>use data that is specified in the config<commit_after>package main

import (
	"fmt"
	"gopkg.in/yaml.v2"
	"io/ioutil"
	"os"
)

type Config struct {
	Directory []string `yaml:"Directory"`
}

func removeDirectories(directories []string) {
	for _, directory := range directories {

		if err := os.RemoveAll(directory); err != nil {
			fmt.Println(err)
		}
		fmt.Printf("Remove: %s\n", directory)
	}
}

func readConfigFile() Config {
	configFile := os.Getenv("HOME") + "/.houki.yml"

	buf, err := ioutil.ReadFile(configFile)
	if err != nil {
		panic(err)
	}

	var parsedMap Config
	if err = yaml.Unmarshal(buf, &parsedMap); err != nil {
		panic(err)
	}

	return parsedMap
}

func main() {
	config := readConfigFile()
	removeDirectories(config.Directory)

	fmt.Println("Have cleaned")
}
<|endoftext|>