<commit_before>// Version 1.82
// Supports Windows, Linux, Mac, and Raspberry Pi, Beagle Bone Black

package main

import (
	"flag"
	log "github.com/Sirupsen/logrus"
	"github.com/gin-gonic/gin"
	"github.com/itsjamie/gin-cors"
	"github.com/kardianos/osext"
	"github.com/vharitonsky/iniflags"
	"os"
	"os/user"
	"path/filepath"
	"runtime/debug"
	"text/template"
	"time"
	//"github.com/sanbornm/go-selfupdate/selfupdate" #included in update.go to change heavily
)

var (
	version              = "x.x.x-dev" //don't modify it, Jenkins will take care
	git_revision         = "xxxxxxxx"  //don't modify it, Jenkins will take care
	embedded_autoupdate  = true
	embedded_autoextract = false
	hibernate            = flag.Bool("hibernate", false, "start hibernated")
	addr                 = flag.String("addr", ":8989", "http service address")
	addrSSL              = flag.String("addrSSL", ":8990", "https service address")
	verbose              = flag.Bool("v", true, "show debug logging")
	//verbose = flag.Bool("v", false, "show debug logging")
	isLaunchSelf = flag.Bool("ls", false, "launch self 5 seconds later")
	configIni    = flag.String("configFile", "config.ini", "config file path")
	regExpFilter = flag.String("regex", "usb|acm|com", "Regular expression to filter serial port list")
	gcType       = flag.String("gc", "std", "Type of garbage collection. std = Normal garbage collection allowing system to decide (this has been known to cause a stop the world in the middle of a CNC job which can cause lost responses from the CNC controller and thus stalled jobs. use max instead to solve.), off = let memory grow unbounded (you have to send in the gc command manually to garbage collect or you will run out of RAM eventually), max = Force garbage collection on each recv or send on a serial port (this minimizes stop the world events and thus lost serial responses, but increases CPU usage)")
	logDump      = flag.String("log", "off", "off = (default)")
	// hostname. allow user to override, otherwise we look it up
	hostname       = flag.String("hostname", "unknown-hostname", "Override the hostname we get from the OS")
	updateUrl      = flag.String("updateUrl", "", "")
	appName        = flag.String("appName", "", "")
	globalToolsMap = make(map[string]string)
	tempToolsPath  = createToolsDir()
)

type NullWriter int

func (NullWriter) Write([]byte) (int, error) { return 0, nil }

type logWriter struct{}

func (u *logWriter) Write(p []byte) (n int, err error) {
	h.broadcastSys <- p
	return 0, nil
}

var logger_ws logWriter

func createToolsDir() string {
	usr, _ := user.Current()
	return usr.HomeDir + "/.arduino-create"
}

func homeHandler(c *gin.Context) {
	homeTemplate.Execute(c.Writer, c.Request.Host)
}

func launchSelfLater() {
	log.Println("Going to launch myself 2 seconds later.")
	time.Sleep(2 * 1000 * time.Millisecond)
	log.Println("Done waiting 2 secs. Now launching...")
}

func main() {

	flag.Parse()
	go func() {

		// autoextract self
		src, _ := osext.Executable()
		dest := filepath.Dir(src)

		os.Mkdir(tempToolsPath, 0777)
		hideFile(tempToolsPath)

		if embedded_autoextract {
			// save the config.ini (if it exists)
			if _, err := os.Stat(dest + "/" + *configIni); os.IsNotExist(err) {
				log.Println("First run, unzipping self")
				err := Unzip(src, dest)
				log.Println("Self extraction, err:", err)
			}

			if _, err := os.Stat(dest + "/" + *configIni); os.IsNotExist(err) {
				flag.Parse()
				log.Println("No config.ini at", *configIni)
			} else {
				flag.Parse()
				flag.Set("config", dest+"/"+*configIni)
				iniflags.Parse()
			}
		} else {
			flag.Set("config", dest+"/"+*configIni)
			iniflags.Parse()
		}

		//log.SetFormatter(&log.JSONFormatter{})

		log.SetLevel(log.InfoLevel)

		log.SetOutput(os.Stderr)

		// see if we are supposed to wait 5 seconds
		if *isLaunchSelf {
			launchSelfLater()
		}

		if embedded_autoupdate {

			var updater = &Updater{
				CurrentVersion: version,
				ApiURL:         *updateUrl,
				BinURL:         *updateUrl,
				DiffURL:        "",
				Dir:            "update/",
				CmdName:        *appName,
			}

			if updater != nil {
				go updater.BackgroundRun()
			}
		}

		f := flag.Lookup("addr")
		log.Println("Version:" + version)

		// hostname
		hn, _ := os.Hostname()
		if *hostname == "unknown-hostname" {
			*hostname = hn
		}
		log.Println("Hostname:", *hostname)

		// turn off garbage collection
		// this is dangerous, as u could overflow memory
		//if *isGC {
		if *gcType == "std" {
			log.Println("Garbage collection is on using Standard mode, meaning we just let Golang determine when to garbage collect.")
		} else if *gcType == "max" {
			log.Println("Garbage collection is on for MAXIMUM real-time collecting on each send/recv from serial port. Higher CPU, but less stopping of the world to garbage collect since it is being done on a constant basis.")
		} else {
			log.Println("Garbage collection is off. Memory use will grow unbounded. You WILL RUN OUT OF RAM unless you send in the gc command to manually force garbage collection. Lower CPU, but progressive memory footprint.")
			debug.SetGCPercent(-1)
		}

		ip := "0.0.0.0"
		log.Print("Starting server and websocket on " + ip + "" + f.Value.String())

		log.Println("The Arduino Create Agent is now running")

		// see if they provided a regex filter
		if len(*regExpFilter) > 0 {
			log.Printf("You specified a serial port regular expression filter: %v\n", *regExpFilter)
		}

		// list serial ports
		portList, _ := GetList(false)
		log.Println("Your serial ports:")
		if len(portList) == 0 {
			log.Println("\tThere are no serial ports to list.")
		}
		for _, element := range portList {
			log.Printf("\t%v\n", element)

		}

		if !*verbose {
			log.Println("You can enter verbose mode to see all logging by starting with the -v command line switch.")
			log.SetOutput(new(NullWriter)) //route all logging to nullwriter
		}

		// launch the hub routine which is the singleton for the websocket server
		go h.run()
		// launch our serial port routine
		go sh.run()
		// launch our dummy data routine
		//go d.run()

		go discoverLoop()

		r := gin.New()

		socketHandler := wsHandler().ServeHTTP

		r.Use(cors.Middleware(cors.Config{
			Origins:         "https://create.arduino.cc, http://create.arduino.cc, https://create-dev.arduino.cc, http://create-dev.arduino.cc, http://webide.arduino.cc:8080, http://create-staging.arduino.cc, https://create-staging.arduino.cc, http://localhost:8989, https://localhost:8990",
			Methods:         "GET, PUT, POST, DELETE",
			RequestHeaders:  "Origin, Authorization, Content-Type",
			ExposedHeaders:  "",
			MaxAge:          50 * time.Second,
			Credentials:     true,
			ValidateHeaders: false,
		}))

		r.GET("/", homeHandler)
		r.POST("/upload", uploadHandler)
		r.GET("/socket.io/", socketHandler)
		r.POST("/socket.io/", socketHandler)
		r.Handle("WS", "/socket.io/", socketHandler)
		r.Handle("WSS", "/socket.io/", socketHandler)
		go func() {
			if err := r.RunTLS(*addrSSL, filepath.Join(dest, "cert.pem"), filepath.Join(dest, "key.pem")); err != nil {
				log.Printf("Error trying to bind to port: %v, so exiting...", err)
				log.Fatal("Error ListenAndServe:", err)
			}
		}()

		if err := r.Run(*addr); err != nil {
			log.Printf("Error trying to bind to port: %v, so exiting...", err)
			log.Fatal("Error ListenAndServe:", err)
		}
	}()
	setupSysTray()
}

var homeTemplate = template.Must(template.New("home").Parse(homeTemplateHtml))

// If you navigate to this server's homepage, you'll get this HTML
// so you can directly interact with the serial port server
const homeTemplateHtml = `<!DOCTYPE html>

<title>Serial Port Example</title>

<form id="form">
    <input type="submit" value="Send" />
    <input type="text" id="msg" size="64"/>
    <input name="pause" type="checkbox" value="pause" id="myCheck"/> Pause

</form>

`
<commit_msg>Default log on<commit_after>// Version 1.82
// Supports Windows, Linux, Mac, and Raspberry Pi, Beagle Bone Black

package main

import (
	"flag"
	log "github.com/Sirupsen/logrus"
	"github.com/gin-gonic/gin"
	"github.com/itsjamie/gin-cors"
	"github.com/kardianos/osext"
	"github.com/vharitonsky/iniflags"
	"os"
	"os/user"
	"path/filepath"
	"runtime/debug"
	"text/template"
	"time"
	//"github.com/sanbornm/go-selfupdate/selfupdate" #included in update.go to change heavily
)

var (
	version              = "x.x.x-dev" //don't modify it, Jenkins will take care
	git_revision         = "xxxxxxxx"  //don't modify it, Jenkins will take care
	embedded_autoupdate  = true
	embedded_autoextract = false
	hibernate            = flag.Bool("hibernate", false, "start hibernated")
	addr                 = flag.String("addr", ":8989", "http service address")
	addrSSL              = flag.String("addrSSL", ":8990", "https service address")
	verbose              = flag.Bool("v", true, "show debug logging")
	//verbose = flag.Bool("v", false, "show debug logging")
	isLaunchSelf = flag.Bool("ls", false, "launch self 5 seconds later")
	configIni    = flag.String("configFile", "config.ini", "config file path")
	regExpFilter = flag.String("regex", "usb|acm|com", "Regular expression to filter serial port list")
	gcType       = flag.String("gc", "std", "Type of garbage collection. std = Normal garbage collection allowing system to decide (this has been known to cause a stop the world in the middle of a CNC job which can cause lost responses from the CNC controller and thus stalled jobs. use max instead to solve.), off = let memory grow unbounded (you have to send in the gc command manually to garbage collect or you will run out of RAM eventually), max = Force garbage collection on each recv or send on a serial port (this minimizes stop the world events and thus lost serial responses, but increases CPU usage)")
	logDump      = flag.String("log", "off", "off = (default)")
	// hostname. allow user to override, otherwise we look it up
	hostname       = flag.String("hostname", "unknown-hostname", "Override the hostname we get from the OS")
	updateUrl      = flag.String("updateUrl", "", "")
	appName        = flag.String("appName", "", "")
	globalToolsMap = make(map[string]string)
	tempToolsPath  = createToolsDir()
)

type NullWriter int

func (NullWriter) Write([]byte) (int, error) { return 0, nil }

type logWriter struct{}

func (u *logWriter) Write(p []byte) (n int, err error) {
	h.broadcastSys <- p
	return 0, nil
}

var logger_ws logWriter

func createToolsDir() string {
	usr, _ := user.Current()
	return usr.HomeDir + "/.arduino-create"
}

func homeHandler(c *gin.Context) {
	homeTemplate.Execute(c.Writer, c.Request.Host)
}

func launchSelfLater() {
	log.Println("Going to launch myself 2 seconds later.")
	time.Sleep(2 * 1000 * time.Millisecond)
	log.Println("Done waiting 2 secs. Now launching...")
}

func main() {

	flag.Parse()
	go func() {

		// autoextract self
		src, _ := osext.Executable()
		dest := filepath.Dir(src)

		os.Mkdir(tempToolsPath, 0777)
		hideFile(tempToolsPath)

		if embedded_autoextract {
			// save the config.ini (if it exists)
			if _, err := os.Stat(dest + "/" + *configIni); os.IsNotExist(err) {
				log.Println("First run, unzipping self")
				err := Unzip(src, dest)
				log.Println("Self extraction, err:", err)
			}

			if _, err := os.Stat(dest + "/" + *configIni); os.IsNotExist(err) {
				flag.Parse()
				log.Println("No config.ini at", *configIni)
			} else {
				flag.Parse()
				flag.Set("config", dest+"/"+*configIni)
				iniflags.Parse()
			}
		} else {
			flag.Set("config", dest+"/"+*configIni)
			iniflags.Parse()
		}

		//log.SetFormatter(&log.JSONFormatter{})

		log.SetLevel(log.InfoLevel)

		log.SetOutput(os.Stderr)

		// see if we are supposed to wait 5 seconds
		if *isLaunchSelf {
			launchSelfLater()
		}

		if embedded_autoupdate {

			var updater = &Updater{
				CurrentVersion: version,
				ApiURL:         *updateUrl,
				BinURL:         *updateUrl,
				DiffURL:        "",
				Dir:            "update/",
				CmdName:        *appName,
			}

			if updater != nil {
				go updater.BackgroundRun()
			}
		}

		f := flag.Lookup("addr")
		log.Println("Version:" + version)

		// hostname
		hn, _ := os.Hostname()
		if *hostname == "unknown-hostname" {
			*hostname = hn
		}
		log.Println("Hostname:", *hostname)

		// turn off garbage collection
		// this is dangerous, as u could overflow memory
		//if *isGC {
		if *gcType == "std" {
			log.Println("Garbage collection is on using Standard mode, meaning we just let Golang determine when to garbage collect.")
		} else if *gcType == "max" {
			log.Println("Garbage collection is on for MAXIMUM real-time collecting on each send/recv from serial port. Higher CPU, but less stopping of the world to garbage collect since it is being done on a constant basis.")
		} else {
			log.Println("Garbage collection is off. Memory use will grow unbounded. You WILL RUN OUT OF RAM unless you send in the gc command to manually force garbage collection. Lower CPU, but progressive memory footprint.")
			debug.SetGCPercent(-1)
		}

		ip := "0.0.0.0"
		log.Print("Starting server and websocket on " + ip + "" + f.Value.String())

		log.Println("The Arduino Create Agent is now running")

		// see if they provided a regex filter
		if len(*regExpFilter) > 0 {
			log.Printf("You specified a serial port regular expression filter: %v\n", *regExpFilter)
		}

		// list serial ports
		portList, _ := GetList(false)
		log.Println("Your serial ports:")
		if len(portList) == 0 {
			log.Println("\tThere are no serial ports to list.")
		}
		for _, element := range portList {
			log.Printf("\t%v\n", element)

		}

		if !*verbose {
			log.Println("You can enter verbose mode to see all logging by starting with the -v command line switch.")
			log.SetOutput(new(NullWriter)) //route all logging to nullwriter
		}

		// launch the hub routine which is the singleton for the websocket server
		go h.run()
		// launch our serial port routine
		go sh.run()
		// launch our dummy data routine
		//go d.run()

		go discoverLoop()

		r := gin.New()

		socketHandler := wsHandler().ServeHTTP

		r.Use(cors.Middleware(cors.Config{
			Origins:         "https://create.arduino.cc, http://create.arduino.cc, https://create-dev.arduino.cc, http://create-dev.arduino.cc, http://webide.arduino.cc:8080, http://create-staging.arduino.cc, https://create-staging.arduino.cc, http://localhost:8989, https://localhost:8990",
			Methods:         "GET, PUT, POST, DELETE",
			RequestHeaders:  "Origin, Authorization, Content-Type",
			ExposedHeaders:  "",
			MaxAge:          50 * time.Second,
			Credentials:     true,
			ValidateHeaders: false,
		}))

		r.GET("/", homeHandler)
		r.POST("/upload", uploadHandler)
		r.GET("/socket.io/", socketHandler)
		r.POST("/socket.io/", socketHandler)
		r.Handle("WS", "/socket.io/", socketHandler)
		r.Handle("WSS", "/socket.io/", socketHandler)
		go func() {
			if err := r.RunTLS(*addrSSL, filepath.Join(dest, "cert.pem"), filepath.Join(dest, "key.pem")); err != nil {
				log.Printf("Error trying to bind to port: %v, so exiting...", err)
				log.Fatal("Error ListenAndServe:", err)
			}
		}()

		if err := r.Run(*addr); err != nil {
			log.Printf("Error trying to bind to port: %v, so exiting...", err)
			log.Fatal("Error ListenAndServe:", err)
		}
	}()
	setupSysTray()
}

var homeTemplate = template.Must(template.New("home").Parse(homeTemplateHtml))

// If you navigate to this server's homepage, you'll get this HTML
// so you can directly interact with the serial port server
const homeTemplateHtml = `<!DOCTYPE html>

<title>Serial Port Example</title>

<form id="form">
    <input type="submit" value="Send" />
    <input type="text" id="msg" size="64"/>
    <input name="pause" type="checkbox" value="pause" id="myCheck"/> Pause

</form>

`
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"io"
	"log"
	"math"
	"math/rand"
	"os"
	"regexp"
	"time"

	"github.com/kelseyhightower/envconfig"
	"github.com/owulveryck/min-char-rnn/rnn"
	"gonum.org/v1/gonum/stat/distuv"
)

type configuration struct {
	Choice          string `default:"soft" required:"true"`
	Epochs          int    `default:"100" required:"true"`
	BatchSize       int    `default:"20" required:"true"`
	SampleSize      int    `default:"100" required:"true"`
	SampleFrequency int    `default:"1000" required:"true"`
}

var conf configuration

func usage(err error) error {
	flag.Usage()
	err = envconfig.Usage("MIN_CHAR", &conf)
	if err != nil {
		log.Fatal(err)
	}
	return err
}

func main() {
	vocab := flag.String("vocab", "data/vocab.txt", "the file holds the vocabulary")
	input := flag.String("input", "data/input.txt", "the input text to train the network")
	start := flag.String("sampleStart", "Hello,", "the input text to train the network")
	num := flag.Int("sampleSize", 500, "size of the sample to generate")
	endRegexp := flag.String("sampleEndRegexp", "", "If ca generated char match the regexp, it stops")
	help := flag.Bool("h", false, "display help")
	flag.Parse()
	if *help {
		log.Fatal(usage(nil))
	}
	err := envconfig.Usage("MIN_CHAR", &conf)
	if err != nil {
		log.Fatal(err)
	}
	err = envconfig.Process("MIN_CHAR", &conf)
	if err != nil {
		log.Fatal(usage(err))
	}

	runesToIx, ixToRunes, err := getVocabIndexesFromFile(*vocab)
	if err != nil {
		log.Fatal(usage(err))
	}
	// Open the sample text file
	data, err := os.Open(*input)
	if err != nil {
		log.Fatal(usage(err))
	}
	defer data.Close()
	// Create the sampling object
	sample := newSample(ixToRunes, runesToIx, *start, *endRegexp, conf.Choice, *num)

	inputNeurons := len(runesToIx)
	outputNeurons := len(ixToRunes)

	// Create a new RNNs
	neuralNet := rnn.NewRNN(inputNeurons, outputNeurons)
	// Triggering the Training
	feed, info := neuralNet.Train()
	r := bufio.NewReader(data)
	tset := rnn.TrainingSet{
		Inputs:  make([][]float64, conf.BatchSize),
		Targets: make([][]float64, conf.BatchSize),
	}

	n := 0
	epoch := 1
	// loss at iteration 0
	smoothLoss := -math.Log(float64(1)/float64(len(runesToIx))) * float64(conf.BatchSize)
	log.Println(smoothLoss)
	for {
		// Filling a training set
		for i := 0; i < conf.BatchSize+1; i++ {
			// Create the 1-of-k encoder vector
			oneOfK := make([]float64, inputNeurons)
			// Read a character
			if c, _, err := r.ReadRune(); err != nil {
				if err == io.EOF {
					// Restart the training if it's not the last epoch
					if epoch < conf.Epochs {
						if _, err := data.Seek(0, io.SeekStart); err != nil {
							log.Fatal(err)
						}
						epoch++
						break
					} else {
						return
					}
				} else {
					log.Fatal(err)
				}
			} else {
				oneOfK[runesToIx[c]] = 1
			}

			switch i {
			case 0:
				tset.Inputs[i] = oneOfK
			case conf.BatchSize:
				tset.Targets[i-1] = oneOfK
			default:
				tset.Inputs[i] = oneOfK
				tset.Targets[i-1] = oneOfK
			}
		}
		// Feeding the network
		feed <- tset
		loss := <-info

		smoothLoss = smoothLoss*0.999 + loss*0.001
		if n%100 == 0 {
			fmt.Printf("Epoch %v, iteration: %v, loss: %v\r", epoch, n, smoothLoss)
		}
		if n%conf.SampleFrequency == 0 {
			sample.sampling(neuralNet)
		}
		n++
	}
}

type sample struct {
	ixToRune     map[int]rune
	runeToIx     map[rune]int
	sampleStart  [][]float64 // The sampling in form of an array of 1-of-k encoded chars
	numChars     int
	endRegexp    *regexp.Regexp
	distribution func(p []float64) int // This is for the character generation
}

func newSample(ixToRune map[int]rune, runesToIx map[rune]int, start, end, choice string, num int) *sample {
	s := &sample{}
	// check if end is a number of characters
	s.numChars = num
	if end != "" {
		s.endRegexp = regexp.MustCompile(end)
	}
	xs := make([][]float64, 0)
	r := bufio.NewReader(bytes.NewBufferString(start))
	for {
		oneOfK := make([]float64, len(runesToIx))
		if c, _, err := r.ReadRune(); err != nil {
			if err == io.EOF {
				break
			} else {
				return nil
			}
		} else {
			oneOfK[runesToIx[c]] = 1
			xs = append(xs, oneOfK)
		}
	}

	s.sampleStart = xs
	s.ixToRune = ixToRune
	s.runeToIx = runesToIx
	switch choice {
	case "hard":
		s.distribution = func(p []float64) int {
			best := float64(0)
			bestIdx := 0
			for i, v := range p {
				if v > best {
					best = v
					bestIdx = i
				}
			}
			return bestIdx
		}
	case "soft":
		s.distribution = func(p []float64) int {
			sample := distuv.NewCategorical(p, rand.New(rand.NewSource(time.Now().UnixNano())))
			return int(sample.Rand())
		}

	default:
		log.Println("Unknown choice")
		return nil
	}

	return s
}

func (s *sample) sampling(neuralNet *rnn.RNN) {

	var index []int
	index = neuralNet.Sample(s.sampleStart, s.numChars, s.distribution)

	fmt.Printf("\n------------\n")
	for _, idx := range index {
		str := fmt.Sprintf("%c", s.ixToRune[idx])
		fmt.Printf("%v", str)
		if s.endRegexp != nil {
			if s.endRegexp.MatchString(str) {
				break
			}
		}
	}
	fmt.Printf("\n------------\n")

}
<commit_msg>Log on stderr<commit_after>package main

import (
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"io"
	"log"
	"math"
	"math/rand"
	"os"
	"regexp"
	"time"

	"github.com/kelseyhightower/envconfig"
	"github.com/owulveryck/min-char-rnn/rnn"
	"gonum.org/v1/gonum/stat/distuv"
)

type configuration struct {
	Choice          string `default:"soft" required:"true"`
	Epochs          int    `default:"100" required:"true"`
	BatchSize       int    `default:"20" required:"true"`
	SampleSize      int    `default:"100" required:"true"`
	SampleFrequency int    `default:"1000" required:"true"`
}

var conf configuration

func usage(err error) error {
	flag.Usage()
	err = envconfig.Usage("MIN_CHAR", &conf)
	if err != nil {
		log.Fatal(err)
	}
	return err
}

func main() {
	vocab := flag.String("vocab", "data/vocab.txt", "the file holds the vocabulary")
	input := flag.String("input", "data/input.txt", "the input text to train the network")
	start := flag.String("sampleStart", "Hello,", "the input text to train the network")
	num := flag.Int("sampleSize", 500, "size of the sample to generate")
	endRegexp := flag.String("sampleEndRegexp", "", "If ca generated char match the regexp, it stops")
	help := flag.Bool("h", false, "display help")
	flag.Parse()
	if *help {
		log.Fatal(usage(nil))
	}
	err := envconfig.Usage("MIN_CHAR", &conf)
	if err != nil {
		log.Fatal(err)
	}
	err = envconfig.Process("MIN_CHAR", &conf)
	if err != nil {
		log.Fatal(usage(err))
	}

	runesToIx, ixToRunes, err := getVocabIndexesFromFile(*vocab)
	if err != nil {
		log.Fatal(usage(err))
	}
	// Open the sample text file
	data, err := os.Open(*input)
	if err != nil {
		log.Fatal(usage(err))
	}
	defer data.Close()
	// Create the sampling object
	sample := newSample(ixToRunes, runesToIx, *start, *endRegexp, conf.Choice, *num)

	inputNeurons := len(runesToIx)
	outputNeurons := len(ixToRunes)

	// Create a new RNNs
	neuralNet := rnn.NewRNN(inputNeurons, outputNeurons)
	// Triggering the Training
	feed, info := neuralNet.Train()
	r := bufio.NewReader(data)
	tset := rnn.TrainingSet{
		Inputs:  make([][]float64, conf.BatchSize),
		Targets: make([][]float64, conf.BatchSize),
	}

	n := 0
	epoch := 1
	// loss at iteration 0
	smoothLoss := -math.Log(float64(1)/float64(len(runesToIx))) * float64(conf.BatchSize)
	log.Println(smoothLoss)
	for {
		// Filling a training set
		for i := 0; i < conf.BatchSize+1; i++ {
			// Create the 1-of-k encoder vector
			oneOfK := make([]float64, inputNeurons)
			// Read a character
			if c, _, err := r.ReadRune(); err != nil {
				if err == io.EOF {
					// Restart the training if it's not the last epoch
					if epoch < conf.Epochs {
						if _, err := data.Seek(0, io.SeekStart); err != nil {
							log.Fatal(err)
						}
						epoch++
						break
					} else {
						return
					}
				} else {
					log.Fatal(err)
				}
			} else {
				oneOfK[runesToIx[c]] = 1
			}

			switch i {
			case 0:
				tset.Inputs[i] = oneOfK
			case conf.BatchSize:
				tset.Targets[i-1] = oneOfK
			default:
				tset.Inputs[i] = oneOfK
				tset.Targets[i-1] = oneOfK
			}
		}
		// Feeding the network
		feed <- tset
		loss := <-info

		smoothLoss = smoothLoss*0.999 + loss*0.001
		if n%100 == 0 {
			log.Printf("Epoch %v, iteration: %v, loss: %v", epoch, n, smoothLoss)
		}
		if n%conf.SampleFrequency == 0 {
			sample.sampling(neuralNet)
		}
		n++
	}
}

type sample struct {
	ixToRune     map[int]rune
	runeToIx     map[rune]int
	sampleStart  [][]float64 // The sampling in form of an array of 1-of-k encoded chars
	numChars     int
	endRegexp    *regexp.Regexp
	distribution func(p []float64) int // This is for the character generation
}

func newSample(ixToRune map[int]rune, runesToIx map[rune]int, start, end, choice string, num int) *sample {
	s := &sample{}
	// check if end is a number of characters
	s.numChars = num
	if end != "" {
		s.endRegexp = regexp.MustCompile(end)
	}
	xs := make([][]float64, 0)
	r := bufio.NewReader(bytes.NewBufferString(start))
	for {
		oneOfK := make([]float64, len(runesToIx))
		if c, _, err := r.ReadRune(); err != nil {
			if err == io.EOF {
				break
			} else {
				return nil
			}
		} else {
			oneOfK[runesToIx[c]] = 1
			xs = append(xs, oneOfK)
		}
	}

	s.sampleStart = xs
	s.ixToRune = ixToRune
	s.runeToIx = runesToIx
	switch choice {
	case "hard":
		s.distribution = func(p []float64) int {
			best := float64(0)
			bestIdx := 0
			for i, v := range p {
				if v > best {
					best = v
					bestIdx = i
				}
			}
			return bestIdx
		}
	case "soft":
		s.distribution = func(p []float64) int {
			sample := distuv.NewCategorical(p, rand.New(rand.NewSource(time.Now().UnixNano())))
			return int(sample.Rand())
		}

	default:
		log.Println("Unknown choice")
		return nil
	}

	return s
}

func (s *sample) sampling(neuralNet *rnn.RNN) {

	var index []int
	index = neuralNet.Sample(s.sampleStart, s.numChars, s.distribution)

	fmt.Printf("\n------------\n")
	for _, idx := range index {
		str := fmt.Sprintf("%c", s.ixToRune[idx])
		fmt.Printf("%v", str)
		if s.endRegexp != nil {
			if s.endRegexp.MatchString(str) {
				break
			}
		}
	}
	fmt.Printf("\n------------\n")

}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"os"
	"strconv"

	"github.com/Telmate/proxmox-api-go/proxmox"
)

func main() {
	var insecure *bool
	insecure = flag.Bool("insecure", false, "TLS insecure mode")
	proxmox.Debug = flag.Bool("debug", false, "debug mode")
	taskTimeout := flag.Int("timeout", 300, "api task timeout in seconds")
	fvmid := flag.Int("vmid", -1, "custom vmid (instead of auto)")
	flag.Parse()
	tlsconf := &tls.Config{InsecureSkipVerify: true}
	if !*insecure {
		tlsconf = nil
	}
	c, _ := proxmox.NewClient(os.Getenv("PM_API_URL"), nil, tlsconf, *taskTimeout)
	err := c.Login(os.Getenv("PM_USER"), os.Getenv("PM_PASS"), os.Getenv("PM_OTP"))
	if err != nil {
		log.Fatal(err)
	}

	vmid := *fvmid
	if vmid < 0 {
		fmt.Println("here")
		if len(flag.Args()) > 1 {
			vmid, err = strconv.Atoi(flag.Args()[len(flag.Args())-1])
			if err != nil {
				vmid = 0
			}
		} else if len(flag.Args()) == 0 || (flag.Args()[0] == "idstatus") {
			vmid = 0
		}
	}

	var jbody interface{}
	var vmr *proxmox.VmRef

	if len(flag.Args()) == 0 {
		fmt.Printf("Missing action, try start|stop vmid\n")
		os.Exit(0)
	}

	switch flag.Args()[0] {
	case "start":
		vmr = proxmox.NewVmRef(vmid)
		jbody, err = c.StartVm(vmr)
		failError(err)

	case "stop":

		vmr = proxmox.NewVmRef(vmid)
		jbody, err = c.StopVm(vmr)
		failError(err)

	case "destroy":
		vmr = proxmox.NewVmRef(vmid)
		jbody, err = c.StopVm(vmr)
		failError(err)
		jbody, err = c.DeleteVm(vmr)
		failError(err)

	case "getConfig":
		vmr = proxmox.NewVmRef(vmid)
		err := c.CheckVmRef(vmr)
		failError(err)
		vmType := vmr.GetVmType()
		var config interface{}
		if vmType == "qemu" {
			config, err = proxmox.NewConfigQemuFromApi(vmr, c)
		} else if vmType == "lxc" {
			config, err = proxmox.NewConfigLxcFromApi(vmr, c)
		}
		failError(err)
		cj, err := json.MarshalIndent(config, "", "  ")
		log.Println(string(cj))

	case "getNetworkInterfaces":
		vmr = proxmox.NewVmRef(vmid)
		err := c.CheckVmRef(vmr)
		failError(err)
		networkInterfaces, err := c.GetVmAgentNetworkInterfaces(vmr)
		failError(err)

		networkInterfaceJson, err := json.Marshal(networkInterfaces)
		fmt.Println(string(networkInterfaceJson))

	case "createQemu":
		config, err := proxmox.NewConfigQemuFromJson(os.Stdin)
		failError(err)
		vmr = proxmox.NewVmRef(vmid)
		vmr.SetNode(flag.Args()[2])
		failError(config.CreateVm(vmr, c))
		log.Println("Complete")

	case "createLxc":
		config, err := proxmox.NewConfigLxcFromJson(os.Stdin)
		failError(err)
		vmr = proxmox.NewVmRef(vmid)
		vmr.SetNode(flag.Args()[2])
		failError(config.CreateLxc(vmr, c))
		log.Println("Complete")

	case "installQemu":
		config, err := proxmox.NewConfigQemuFromJson(os.Stdin)
		failError(err)
		if vmid > 0 {
			vmr = proxmox.NewVmRef(vmid)
		} else {
			nextid, err := c.GetNextID(0)
			failError(err)
			vmr = proxmox.NewVmRef(nextid)
		}
		vmr.SetNode(flag.Args()[1])
		log.Print("Creating node: ")
		log.Println(vmr)
		failError(config.CreateVm(vmr, c))
		_, err = c.StartVm(vmr)
		failError(err)
		sshPort, err := proxmox.SshForwardUsernet(vmr, c)
		failError(err)
		log.Println("Waiting for CDRom install shutdown (at least 5 minutes)")
		failError(proxmox.WaitForShutdown(vmr, c))
		log.Println("Restarting")
		_, err = c.StartVm(vmr)
		failError(err)
		sshPort, err = proxmox.SshForwardUsernet(vmr, c)
		failError(err)
		log.Println("SSH Portforward on:" + sshPort)
		log.Println("Complete")

	case "idstatus":
		maxid, err := proxmox.MaxVmId(c)
		failError(err)
		nextid, err := c.GetNextID(vmid)
		failError(err)
		log.Println("---")
		log.Printf("MaxID: %d\n", maxid)
		log.Printf("NextID: %d\n", nextid)
		log.Println("---")

	case "cloneQemu":
		config, err := proxmox.NewConfigQemuFromJson(os.Stdin)
		failError(err)
		log.Println("Looking for template: " + flag.Args()[1])
		sourceVmr, err := c.GetVmRefByName(flag.Args()[1])
		failError(err)
		if sourceVmr == nil {
			log.Fatal("Can't find template")
			return
		}
		if vmid == 0 {
			vmid, err = c.GetNextID(0)
		}
		vmr = proxmox.NewVmRef(vmid)
		vmr.SetNode(flag.Args()[2])
		log.Print("Creating node: ")
		log.Println(vmr)
		failError(config.CloneVm(sourceVmr, vmr, c))
		failError(config.UpdateConfig(vmr, c))
		log.Println("Complete")

	case "createQemuSnapshot":
		sourceVmr, err := c.GetVmRefByName(flag.Args()[1])
		jbody, err = c.CreateQemuSnapshot(sourceVmr, flag.Args()[2])
		failError(err)

	case "deleteQemuSnapshot":
		sourceVmr, err := c.GetVmRefByName(flag.Args()[1])
		jbody, err = c.DeleteQemuSnapshot(sourceVmr, flag.Args()[2])
		failError(err)

	case "listQemuSnapshot":
		sourceVmr, err := c.GetVmRefByName(flag.Args()[1])
		jbody, _, err = c.ListQemuSnapshot(sourceVmr)
		if rec, ok := jbody.(map[string]interface{}); ok {
			temp := rec["data"].([]interface{})
			for _, val := range temp {
				snapshotName := val.(map[string]interface{})
				if snapshotName["name"] != "current" {
					fmt.Println(snapshotName["name"])
				}
			}
		} else {
			fmt.Printf("record not a map[string]interface{}: %v\n", jbody)
		}
		failError(err)

	case "rollbackQemu":
		sourceVmr, err := c.GetVmRefByName(flag.Args()[1])
		jbody, err = c.RollbackQemuVm(sourceVmr, flag.Args()[2])
		failError(err)

	case "sshforward":
		vmr = proxmox.NewVmRef(vmid)
		sshPort, err := proxmox.SshForwardUsernet(vmr, c)
		failError(err)
		log.Println("SSH Portforward on:" + sshPort)

	case "sshbackward":
		vmr = proxmox.NewVmRef(vmid)
		err = proxmox.RemoveSshForwardUsernet(vmr, c)
		failError(err)
		log.Println("SSH Portforward off")

	case "sendstring":
		vmr = proxmox.NewVmRef(vmid)
		err = proxmox.SendKeysString(vmr, c, flag.Args()[2])
		failError(err)
		log.Println("Keys sent")

	case "nextid":
		id, err := c.GetNextID(0)
		failError(err)
		log.Printf("Getting Next Free ID: %d\n", id)

	case "checkid":
		i, err := strconv.Atoi(flag.Args()[1])
		failError(err)
		id, err := c.VMIdExists(i)
		failError(err)
		log.Printf("Selected ID is free: %d\n", id)

	case "migrate":
		vmr := proxmox.NewVmRef(vmid)
		c.GetVmInfo(vmr)
		args := flag.Args()
		if len(args) <= 1 {
			fmt.Printf("Missing target node\n")
			os.Exit(1)
		}
		_, err := c.MigrateNode(vmr, args[1], true)

		if err != nil {
			log.Printf("Error to move %+v\n", err)
			os.Exit(1)
		}
		log.Printf("VM %d is moved on %s\n", vmid, args[1])

	default:
		fmt.Printf("unknown action, try start|stop vmid\n")
	}
	if jbody != nil {
		log.Println(jbody)
	}
	//log.Println(vmr)
}

func failError(err error) {
	if err != nil {
		log.Fatal(err)
	}
	return
}
<commit_msg>Removed Erroneous Println<commit_after>package main

import (
	"crypto/tls"
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"os"
	"strconv"

	"github.com/Telmate/proxmox-api-go/proxmox"
)

func main() {
	var insecure *bool
	insecure = flag.Bool("insecure", false, "TLS insecure mode")
	proxmox.Debug = flag.Bool("debug", false, "debug mode")
	taskTimeout := flag.Int("timeout", 300, "api task timeout in seconds")
	fvmid := flag.Int("vmid", -1, "custom vmid (instead of auto)")
	flag.Parse()
	tlsconf := &tls.Config{InsecureSkipVerify: true}
	if !*insecure {
		tlsconf = nil
	}
	c, _ := proxmox.NewClient(os.Getenv("PM_API_URL"), nil, tlsconf, *taskTimeout)
	err := c.Login(os.Getenv("PM_USER"), os.Getenv("PM_PASS"), os.Getenv("PM_OTP"))
	if err != nil {
		log.Fatal(err)
	}

	vmid := *fvmid
	if vmid < 0 {
		if len(flag.Args()) > 1 {
			vmid, err = strconv.Atoi(flag.Args()[len(flag.Args())-1])
			if err != nil {
				vmid = 0
			}
		} else if len(flag.Args()) == 0 || (flag.Args()[0] == "idstatus") {
			vmid = 0
		}
	}

	var jbody interface{}
	var vmr *proxmox.VmRef

	if len(flag.Args()) == 0 {
		fmt.Printf("Missing action, try start|stop vmid\n")
		os.Exit(0)
	}

	switch flag.Args()[0] {
	case "start":
		vmr = proxmox.NewVmRef(vmid)
		jbody, err = c.StartVm(vmr)
		failError(err)

	case "stop":

		vmr = proxmox.NewVmRef(vmid)
		jbody, err = c.StopVm(vmr)
		failError(err)

	case "destroy":
		vmr = proxmox.NewVmRef(vmid)
		jbody, err = c.StopVm(vmr)
		failError(err)
		jbody, err = c.DeleteVm(vmr)
		failError(err)

	case "getConfig":
		vmr = proxmox.NewVmRef(vmid)
		err := c.CheckVmRef(vmr)
		failError(err)
		vmType := vmr.GetVmType()
		var config interface{}
		if vmType == "qemu" {
			config, err = proxmox.NewConfigQemuFromApi(vmr, c)
		} else if vmType == "lxc" {
			config, err = proxmox.NewConfigLxcFromApi(vmr, c)
		}
		failError(err)
		cj, err := json.MarshalIndent(config, "", "  ")
		log.Println(string(cj))

	case "getNetworkInterfaces":
		vmr = proxmox.NewVmRef(vmid)
		err := c.CheckVmRef(vmr)
		failError(err)
		networkInterfaces, err := c.GetVmAgentNetworkInterfaces(vmr)
		failError(err)

		networkInterfaceJson, err := json.Marshal(networkInterfaces)
		fmt.Println(string(networkInterfaceJson))

	case "createQemu":
		config, err := proxmox.NewConfigQemuFromJson(os.Stdin)
		failError(err)
		vmr = proxmox.NewVmRef(vmid)
		vmr.SetNode(flag.Args()[2])
		failError(config.CreateVm(vmr, c))
		log.Println("Complete")

	case "createLxc":
		config, err := proxmox.NewConfigLxcFromJson(os.Stdin)
		failError(err)
		vmr = proxmox.NewVmRef(vmid)
		vmr.SetNode(flag.Args()[2])
		failError(config.CreateLxc(vmr, c))
		log.Println("Complete")

	case "installQemu":
		config, err := proxmox.NewConfigQemuFromJson(os.Stdin)
		failError(err)
		if vmid > 0 {
			vmr = proxmox.NewVmRef(vmid)
		} else {
			nextid, err := c.GetNextID(0)
			failError(err)
			vmr = proxmox.NewVmRef(nextid)
		}
		vmr.SetNode(flag.Args()[1])
		log.Print("Creating node: ")
		log.Println(vmr)
		failError(config.CreateVm(vmr, c))
		_, err = c.StartVm(vmr)
		failError(err)
		sshPort, err := proxmox.SshForwardUsernet(vmr, c)
		failError(err)
		log.Println("Waiting for CDRom install shutdown (at least 5 minutes)")
		failError(proxmox.WaitForShutdown(vmr, c))
		log.Println("Restarting")
		_, err = c.StartVm(vmr)
		failError(err)
		sshPort, err = proxmox.SshForwardUsernet(vmr, c)
		failError(err)
		log.Println("SSH Portforward on:" + sshPort)
		log.Println("Complete")

	case "idstatus":
		maxid, err := proxmox.MaxVmId(c)
		failError(err)
		nextid, err := c.GetNextID(vmid)
		failError(err)
		log.Println("---")
		log.Printf("MaxID: %d\n", maxid)
		log.Printf("NextID: %d\n", nextid)
		log.Println("---")

	case "cloneQemu":
		config, err := proxmox.NewConfigQemuFromJson(os.Stdin)
		failError(err)
		log.Println("Looking for template: " + flag.Args()[1])
		sourceVmr, err := c.GetVmRefByName(flag.Args()[1])
		failError(err)
		if sourceVmr == nil {
			log.Fatal("Can't find template")
			return
		}
		if vmid == 0 {
			vmid, err = c.GetNextID(0)
		}
		vmr = proxmox.NewVmRef(vmid)
		vmr.SetNode(flag.Args()[2])
		log.Print("Creating node: ")
		log.Println(vmr)
		failError(config.CloneVm(sourceVmr, vmr, c))
		failError(config.UpdateConfig(vmr, c))
		log.Println("Complete")

	case "createQemuSnapshot":
		sourceVmr, err := c.GetVmRefByName(flag.Args()[1])
		jbody, err = c.CreateQemuSnapshot(sourceVmr, flag.Args()[2])
		failError(err)

	case "deleteQemuSnapshot":
		sourceVmr, err := c.GetVmRefByName(flag.Args()[1])
		jbody, err = c.DeleteQemuSnapshot(sourceVmr, flag.Args()[2])
		failError(err)

	case "listQemuSnapshot":
		sourceVmr, err := c.GetVmRefByName(flag.Args()[1])
		jbody, _, err = c.ListQemuSnapshot(sourceVmr)
		if rec, ok := jbody.(map[string]interface{}); ok {
			temp := rec["data"].([]interface{})
			for _, val := range temp {
				snapshotName := val.(map[string]interface{})
				if snapshotName["name"] != "current" {
					fmt.Println(snapshotName["name"])
				}
			}
		} else {
			fmt.Printf("record not a map[string]interface{}: %v\n", jbody)
		}
		failError(err)

	case "rollbackQemu":
		sourceVmr, err := c.GetVmRefByName(flag.Args()[1])
		jbody, err = c.RollbackQemuVm(sourceVmr, flag.Args()[2])
		failError(err)

	case "sshforward":
		vmr = proxmox.NewVmRef(vmid)
		sshPort, err := proxmox.SshForwardUsernet(vmr, c)
		failError(err)
		log.Println("SSH Portforward on:" + sshPort)

	case "sshbackward":
		vmr = proxmox.NewVmRef(vmid)
		err = proxmox.RemoveSshForwardUsernet(vmr, c)
		failError(err)
		log.Println("SSH Portforward off")

	case "sendstring":
		vmr = proxmox.NewVmRef(vmid)
		err = proxmox.SendKeysString(vmr, c, flag.Args()[2])
		failError(err)
		log.Println("Keys sent")

	case "nextid":
		id, err := c.GetNextID(0)
		failError(err)
		log.Printf("Getting Next Free ID: %d\n", id)

	case "checkid":
		i, err := strconv.Atoi(flag.Args()[1])
		failError(err)
		id, err := c.VMIdExists(i)
		failError(err)
		log.Printf("Selected ID is free: %d\n", id)

	case "migrate":
		vmr := proxmox.NewVmRef(vmid)
		c.GetVmInfo(vmr)
		args := flag.Args()
		if len(args) <= 1 {
			fmt.Printf("Missing target node\n")
			os.Exit(1)
		}
		_, err := c.MigrateNode(vmr, args[1], true)

		if err != nil {
			log.Printf("Error to move %+v\n", err)
			os.Exit(1)
		}
		log.Printf("VM %d is moved on %s\n", vmid, args[1])

	default:
		fmt.Printf("unknown action, try start|stop vmid\n")
	}
	if jbody != nil {
		log.Println(jbody)
	}
	//log.Println(vmr)
}

func failError(err error) {
	if err != nil {
		log.Fatal(err)
	}
	return
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strconv"
	"time"

	"github.com/macarrie/flemzerd/configuration"
	log "github.com/macarrie/flemzerd/logging"
	flag "github.com/ogier/pflag"

	provider "github.com/macarrie/flemzerd/providers"
	"github.com/macarrie/flemzerd/providers/impl/tvdb"

	indexer "github.com/macarrie/flemzerd/indexers"
	"github.com/macarrie/flemzerd/indexers/impl/torznab"

	notifier "github.com/macarrie/flemzerd/notifiers"
	"github.com/macarrie/flemzerd/notifiers/impl/desktop"
	"github.com/macarrie/flemzerd/notifiers/impl/pushbullet"

	downloader "github.com/macarrie/flemzerd/downloaders"
	"github.com/macarrie/flemzerd/downloaders/impl/transmission"

	. "github.com/macarrie/flemzerd/objects"
)

func initProviders() {
	log.Debug("Initializing Providers")

	var newProviders []provider.Provider
	for providerType, providerElt := range configuration.Config.Providers {
		switch providerType {
		case "tvdb":
			np, _ := impl.New(providerElt["apikey"])
			newProviders = append(newProviders, np)
		default:
			log.WithFields(log.Fields{
				"providerType": providerType,
			}).Warning("Unknown provider type")
		}

		if len(newProviders) != 0 {
			for _, newProvider := range newProviders {
				provider.AddProvider(newProvider)
				log.WithFields(log.Fields{
					"provider": providerType,
				}).Info("Provider added to list of providers")
			}
			newProviders = []provider.Provider{}
		}
	}
}

func initIndexers() {
	log.Debug("Initializing Indexers")

	var newIndexers []indexer.Indexer
	for indexerType, indexerList := range configuration.Config.Indexers {
		switch indexerType {
		case "torznab":
			for _, indexer := range indexerList {
				newIndexers = append(newIndexers, torznab.New(indexer["name"], indexer["url"], indexer["apikey"]))
			}
		default:
			log.WithFields(log.Fields{
				"indexerType": indexerType,
			}).Warning("Unknown indexer type")
		}

		if len(newIndexers) != 0 {
			for _, newIndexer := range newIndexers {
				indexer.AddIndexer(newIndexer)
				log.WithFields(log.Fields{
					"indexer": newIndexer.GetName(),
				}).Info("Indexer added to list of indexers")
			}
			newIndexers = []indexer.Indexer{}
		}
	}
}

func initDownloaders() {
	log.Debug("Initializing Downloaders")

	var newDownloaders []downloader.Downloader
	for name, downloaderObject := range configuration.Config.Downloaders {
		switch name {
		case "transmission":
			address := downloaderObject["address"]
			port, _ := strconv.Atoi(downloaderObject["port"])
			user, authNeeded := downloaderObject["user"]
			password := downloaderObject["password"]
			if !authNeeded {
				user = ""
				password = ""
			}

			transmissionDownloader := transmission.New(address, port, user, password)
			newDownloaders = append(newDownloaders, transmissionDownloader)
		default:
			log.WithFields(log.Fields{
				"downloaderType": name,
			}).Warning("Unknown downloader type")
		}

		if len(newDownloaders) != 0 {
			for _, newDownloader := range newDownloaders {
				newDownloader.Init()
				downloader.AddDownloader(newDownloader)
				log.WithFields(log.Fields{
					"downloader": name,
				}).Info("Downloader added to list of downloaders")
			}
			newDownloaders = []downloader.Downloader{}
		}
	}
}

func initNotifiers() {
	log.Debug("Initializing Notifiers")

	for name, notifierObject := range configuration.Config.Notifiers {
		switch name {
		case "pushbullet":
			pushbulletNotifier := pushbullet.New(map[string]string{"AccessToken": notifierObject["accesstoken"]})
			notifier.AddNotifier(pushbulletNotifier)

			log.WithFields(log.Fields{
				"notifier": name,
			}).Info("Notifier added to list of notifiers")

		case "desktop":
			desktopNotifier := desktop.New()
			notifier.AddNotifier(desktopNotifier)

			log.WithFields(log.Fields{
				"notifier": name,
			}).Info("Notifier added to list of notifiers")

		default:
			log.WithFields(log.Fields{
				"notifierType": name,
			}).Warning("Unknown notifier type")
		}
	}
}

func main() {
	debugMode := flag.BoolP("debug", "d", false, "Start in debug mode")
	configFilePath := flag.StringP("config", "c", "", "Configuration file path to use")

	flag.Parse()

	if *debugMode {
		log.Setup(true)
	} else {
		log.Setup(false)
	}

	if *configFilePath != "" {
		log.Info("Loading provided configuration file")
		configuration.UseFile(*configFilePath)
	}

	err := configuration.Load()
	if err != nil {
		log.WithFields(log.Fields{
			"error": err,
		}).Fatal("Cannot load configuration file")
	}

	err = configuration.Check()
	if err != nil {
		log.WithFields(log.Fields{
			"error": err,
		}).Fatal("Errors in configuration file")
	}

	initNotifiers()
	initProviders()
	initIndexers()
	initDownloaders()

	//	 Load configuration objects
	var showObjects []TvShow

	for _, show := range configuration.Config.Shows {
		showName := show
		show, err := provider.FindShow(show)
		if err != nil {
			log.WithFields(log.Fields{
				"error": err,
				"show":  showName,
			}).Warning("Unable to get show informations")
		} else {
			showObjects = append(showObjects, show)
		}
	}
	if len(showObjects) == 0 {
		log.Fatal("Impossible to get show informations for shows defined in configuration. Shutting down")
	}

	torrentErr := downloader.AddTorrent("http://localhost:9117/dl/kickasstorrent/?jackett_apikey=cigs498n8oqmtwqygegelo9hdgjd28ag&path=Wm5YUXk4bUFPdkkyQTJ2aFhSaEZlVnNIMmczc3VjdXdqZjR5dGd2R3hNVXR0ckhQdm9vWExWbnIyOXp5QXk2SGRDN3VIU00rN2s2cmN2YloraC9ZMVpRUldXRWoxeVcvbi9JYjVjRTN2N0JOc0g2c01RTHVYUjZIMnFQbXh5UTIxamVCR3UxOVpMZ0xwbXRMeWtCS3E0S2hGZDI1eTdpL1dicGJBaDhXbEZCc0toKzVwR3VsczRHUlg3NEU2UFdzOHVPcmxLOHg4eUtxQ2wzd2dXdU9MNkIydGc2RVpvcXdrMlBaaE1kKzQ2RHR6U0RYVDRHOVlZazNRbFVsNXpTaC9pZVorNitkcTJxODg5L2w2MkNOajEzSXRXbVpFMmNkNk9oeUF3RUdhajhONVJjV2RTODcrTThOUGFPQk5kVVdGQXg3ZEE5SmNxNitiejF6d1hHcGpkMzJqcWVqTWFFR0lFZ0xpZ3gvRXdrPQ2&file=Brooklyn+Nine-Nine+S05E02+The+Big+House+2+1080p+AMZN+WEB-DL+DD%2B5.1+H+264-ViSUM.torrent")
	if torrentErr != nil {
		log.Debug("Add torrent error: ", torrentErr)
	} else {
		log.Debug("Torrent added")
	}

	log.Debug("Starting polling loop")
	// TODO: Ticker interval is set in seconds for dev. Ticker interval must be changed from time.Second to time.Minute.
	loopTicker := time.NewTicker(time.Duration(configuration.Config.System.EpisodeCheckInterval) * time.Second)
	for {
		log.Debug("========== Polling loop start ==========")

		for _, show := range showObjects {
			recentEpisodes, err := provider.FindRecentlyAiredEpisodesForShow(show)
			if err != nil {
				log.WithFields(log.Fields{
					"error": err,
					"show":  show.Name,
				}).Warning("No recent episodes found")
				continue
			}

			for _, recentEpisode := range recentEpisodes {
				err := notifier.NotifyRecentEpisode(show, recentEpisode)
				if err != nil {
					log.Warning(err)
				}

				torrentList, err := indexer.GetTorrentForEpisode(show.Name, recentEpisode.Season, recentEpisode.Number)
				if err != nil {
					log.Warning(err)
				}
				log.Debug("Torrents found: ", len(torrentList))
				for _, torrent := range torrentList {
					log.Debug(fmt.Sprintf("Torrent (%04v) %v", torrent.Attributes["seeders"], torrent.Title))
				}
			}
		}

		log.Debug("========== Polling loop end ==========\n")
		<-loopTicker.C
	}
}
<commit_msg>Fixed tests<commit_after>package main

import (
	"fmt"
	"strconv"
	"time"

	"github.com/macarrie/flemzerd/configuration"
	log "github.com/macarrie/flemzerd/logging"
	flag "github.com/ogier/pflag"

	provider "github.com/macarrie/flemzerd/providers"
	"github.com/macarrie/flemzerd/providers/impl/tvdb"

	indexer "github.com/macarrie/flemzerd/indexers"
	"github.com/macarrie/flemzerd/indexers/impl/torznab"

	notifier "github.com/macarrie/flemzerd/notifiers"
	"github.com/macarrie/flemzerd/notifiers/impl/desktop"
	"github.com/macarrie/flemzerd/notifiers/impl/pushbullet"

	downloader "github.com/macarrie/flemzerd/downloaders"
	"github.com/macarrie/flemzerd/downloaders/impl/transmission"

	. "github.com/macarrie/flemzerd/objects"
)

func initProviders() {
	log.Debug("Initializing Providers")

	var newProviders []provider.Provider
	for providerType, providerElt := range configuration.Config.Providers {
		switch providerType {
		case "tvdb":
			np, _ := impl.New(providerElt["apikey"])
			newProviders = append(newProviders, np)
		default:
			log.WithFields(log.Fields{
				"providerType": providerType,
			}).Warning("Unknown provider type")
		}

		if len(newProviders) != 0 {
			for _, newProvider := range newProviders {
				provider.AddProvider(newProvider)
				log.WithFields(log.Fields{
					"provider": providerType,
				}).Info("Provider added to list of providers")
			}
			newProviders = []provider.Provider{}
		}
	}
}

func initIndexers() {
	log.Debug("Initializing Indexers")

	var newIndexers []indexer.Indexer
	for indexerType, indexerList := range configuration.Config.Indexers {
		switch indexerType {
		case "torznab":
			for _, indexer := range indexerList {
				newIndexers = append(newIndexers, torznab.New(indexer["name"], indexer["url"], indexer["apikey"]))
			}
		default:
			log.WithFields(log.Fields{
				"indexerType": indexerType,
			}).Warning("Unknown indexer type")
		}

		if len(newIndexers) != 0 {
			for _, newIndexer := range newIndexers {
				indexer.AddIndexer(newIndexer)
				log.WithFields(log.Fields{
					"indexer": newIndexer.GetName(),
				}).Info("Indexer added to list of indexers")
			}
			newIndexers = []indexer.Indexer{}
		}
	}
}

func initDownloaders() {
	log.Debug("Initializing Downloaders")

	var newDownloaders []downloader.Downloader
	for name, downloaderObject := range configuration.Config.Downloaders {
		switch name {
		case "transmission":
			address := downloaderObject["address"]
			port, _ := strconv.Atoi(downloaderObject["port"])
			user, authNeeded := downloaderObject["user"]
			password := downloaderObject["password"]
			if !authNeeded {
				user = ""
				password = ""
			}

			transmissionDownloader := transmission.New(address, port, user, password)
			newDownloaders = append(newDownloaders, transmissionDownloader)
		default:
			log.WithFields(log.Fields{
				"downloaderType": name,
			}).Warning("Unknown downloader type")
		}

		if len(newDownloaders) != 0 {
			for _, newDownloader := range newDownloaders {
				newDownloader.Init()
				downloader.AddDownloader(newDownloader)
				log.WithFields(log.Fields{
					"downloader": name,
				}).Info("Downloader added to list of downloaders")
			}
			newDownloaders = []downloader.Downloader{}
		}
	}
}

func initNotifiers() {
	log.Debug("Initializing Notifiers")

	for name, notifierObject := range configuration.Config.Notifiers {
		switch name {
		case "pushbullet":
			pushbulletNotifier := pushbullet.New(map[string]string{"AccessToken": notifierObject["accesstoken"]})
			notifier.AddNotifier(pushbulletNotifier)

			log.WithFields(log.Fields{
				"notifier": name,
			}).Info("Notifier added to list of notifiers")

		case "desktop":
			desktopNotifier := desktop.New()
			notifier.AddNotifier(desktopNotifier)

			log.WithFields(log.Fields{
				"notifier": name,
			}).Info("Notifier added to list of notifiers")

		default:
			log.WithFields(log.Fields{
				"notifierType": name,
			}).Warning("Unknown notifier type")
		}
	}
}

func main() {
	debugMode := flag.BoolP("debug", "d", false, "Start in debug mode")
	configFilePath := flag.StringP("config", "c", "", "Configuration file path to use")

	flag.Parse()

	if *debugMode {
		log.Setup(true)
	} else {
		log.Setup(false)
	}

	if *configFilePath != "" {
		log.Info("Loading provided configuration file")
		configuration.UseFile(*configFilePath)
	}

	err := configuration.Load()
	if err != nil {
		log.WithFields(log.Fields{
			"error": err,
		}).Fatal("Cannot load configuration file")
	}

	err = configuration.Check()
	if err != nil {
		log.WithFields(log.Fields{
			"error": err,
		}).Fatal("Errors in configuration file")
	}

	initNotifiers()
	initProviders()
	initIndexers()
	initDownloaders()

	//	 Load configuration objects
	var showObjects []TvShow

	for _, show := range configuration.Config.Shows {
		showName := show
		show, err := provider.FindShow(show)
		if err != nil {
			log.WithFields(log.Fields{
				"error": err,
				"show":  showName,
			}).Warning("Unable to get show informations")
		} else {
			showObjects = append(showObjects, show)
		}
	}
	if len(showObjects) == 0 {
		log.Fatal("Impossible to get show informations for shows defined in configuration. Shutting down")
	}

	//torrentErr := downloader.AddTorrent("http://localhost:9117/dl/kickasstorrent/?jackett_apikey=cigs498n8oqmtwqygegelo9hdgjd28ag&path=Wm5YUXk4bUFPdkkyQTJ2aFhSaEZlVnNIMmczc3VjdXdqZjR5dGd2R3hNVXR0ckhQdm9vWExWbnIyOXp5QXk2SGRDN3VIU00rN2s2cmN2YloraC9ZMVpRUldXRWoxeVcvbi9JYjVjRTN2N0JOc0g2c01RTHVYUjZIMnFQbXh5UTIxamVCR3UxOVpMZ0xwbXRMeWtCS3E0S2hGZDI1eTdpL1dicGJBaDhXbEZCc0toKzVwR3VsczRHUlg3NEU2UFdzOHVPcmxLOHg4eUtxQ2wzd2dXdU9MNkIydGc2RVpvcXdrMlBaaE1kKzQ2RHR6U0RYVDRHOVlZazNRbFVsNXpTaC9pZVorNitkcTJxODg5L2w2MkNOajEzSXRXbVpFMmNkNk9oeUF3RUdhajhONVJjV2RTODcrTThOUGFPQk5kVVdGQXg3ZEE5SmNxNitiejF6d1hHcGpkMzJqcWVqTWFFR0lFZ0xpZ3gvRXdrPQ2&file=Brooklyn+Nine-Nine+S05E02+The+Big+House+2+1080p+AMZN+WEB-DL+DD%2B5.1+H+264-ViSUM.torrent")
	//if torrentErr != nil {
	//log.Debug("Add torrent error: ", torrentErr)
	//} else {
	//log.Debug("Torrent added")
	//}

	log.Debug("Starting polling loop")
	// TODO: Ticker interval is set in seconds for dev. Ticker interval must be changed from time.Second to time.Minute.
	loopTicker := time.NewTicker(time.Duration(configuration.Config.System.EpisodeCheckInterval) * time.Second)
	for {
		log.Debug("========== Polling loop start ==========")

		for _, show := range showObjects {
			recentEpisodes, err := provider.FindRecentlyAiredEpisodesForShow(show)
			if err != nil {
				log.WithFields(log.Fields{
					"error": err,
					"show":  show.Name,
				}).Warning("No recent episodes found")
				continue
			}

			for _, recentEpisode := range recentEpisodes {
				err := notifier.NotifyRecentEpisode(show, recentEpisode)
				if err != nil {
					log.Warning(err)
				}

				torrentList, err := indexer.GetTorrentForEpisode(show.Name, recentEpisode.Season, recentEpisode.Number)
				if err != nil {
					log.Warning(err)
				}
				log.Debug("Torrents found: ", len(torrentList))
				for _, torrent := range torrentList {
					log.Debug(fmt.Sprintf("Torrent (%04v) %v", torrent.Attributes["seeders"], torrent.Title))
				}
			}
		}

		log.Debug("========== Polling loop end ==========\n")
		<-loopTicker.C
	}
}
<|endoftext|>


<commit_before>package toscalib

// We define a type status used in the PropertyDefinition
type Status int64

// Valid values for Status as described in Appendix 5.7.3
const (
	Supported    Status = 1
	Unsupported  Status = 2
	Experimental Status = 3
	Deprecated   Status = 4
)

// ConstraintClauses definition as described in Appendix 5.2.
// This is a map where the index is a string that may have a value in
// {"equal","greater_than", ...} (see Appendix 5.2) a,s value is an interface
// for the definition.
// Example: ConstraintClauses may be [ "greater_than": 3 ]
type ConstraintClauses map[string]interface{}

// Evaluate the constraint and return a boolean
func (this *ConstraintClauses) Evaluate(interface{}) bool { return true }

// TODO: implement the Mashaler YAML interface for the constraint type
func (this *ConstraintClauses) UnmarshalYAML() {}

// PropertyDefinition as described in Appendix 5.7:
// A property definition defines a named, typed value and related data
// that can be associated with an entity defined in this specification
// (e.g., Node Types, Relation ship Types, Capability Types, etc.).
// Properties are used by template authors to provide input values to
// TOSCA entities which indicate their “desired state” when they are instantiated.
// The value of a property can be retrieved using the
// get_property function within TOSCA Service Templates
type PropertyDefinition struct {
	Type        string            `yaml:"type"`                  // The required data type for the property
	Description string            `yaml:"description,omitempty"` // The optional description for the property.
	Required    bool              `yaml:"required"`              // An optional key that declares a property as required ( true) or not ( false) Default: true
	Default     interface{}       `yaml:"default"`
	Status      Status            `yaml:"status"`
	Constraints ConstraintClauses `yaml:"constraints,inline,omitempty"`
	EntrySchema string            `yaml:"entry_schema,omitempty"`
}

// Input corresponds to  `yaml:"inputs,omitempty"`
type Input struct {
	Type             string            `yaml:"type"`
	Description      string            `yaml:"description,omitempty"` // Not required
	Constraints      ConstraintClauses `yaml:"constraints,omitempty,inline"`
	ValidSourceTypes interface{}       `yaml:"valid_source_types,omitempty"`
	Occurrences      interface{}       `yaml:"occurrences,omitempty"`
}

type Output struct {
	Value       interface{} `yaml:"value"`
	Description string      `yaml:"description"`
}

// TODO: Implement the type as defined in Appendix 5.9
type AttributeDefinition interface{}

// RequirementDefinition as described in Appendix 6.2
type RequirementDefinition struct {
	Capability   string     `yaml:"capability"`             // The required reserved keyname used that can be used to provide the name of a valid Capability Type that can fulfil the requirement
	node         string     `yaml:"node,omitempty"`         // The optional reserved keyname used to provide the name of a valid Node Type that contains the capability definition that can be used to fulfil the requirement
	Relationship string     `yaml:"relationship,omitempty"` //The optional reserved keyname used to provide the name of a valid Relationship Type to construct when fulfilling the requirement.
	Occurrences  ToscaRange `yaml:"occurences,omitempty"`   // The optional minimum and maximum occurrences for the requirement.  Note: the keyword UNBOUNDED is also supported to represent any positive integer
}

//TODO: Appendix 6.1
type CapabilityDefinition interface{}

// TODO: Appendix 5.12
type InterfaceDefinition interface{}

// TODO: Appendix 5.5
type ArtifactDefinition interface{}

// TODO Appendix 5.4
// A node filter definition defines criteria for selection of a TOSCA Node Template based upon the template’s property values, capabilities and capability properties.
type NodeFilter interface{}

// NodeType as described is Appendix 6.8.
// A Node Type is a reusable entity that defines the type of one or more Node Templates. As such, a Node Type defines the structure of observable properties via a Properties Definition, the Requirements and Capabilities of the node as well as its supported interfaces.
type NodeType struct {
	DerivedFrom  string                           `yaml:"derived_from,omitempty"` // An optional parent Node Type name this new Node Type derives from
	Description  string                           `yaml:"description,omitempty"`  // An optional description for the Node Type
	Properties   map[string]PropertyDefinition    `yaml:"properties,omitempty"`   // An optional list of property definitions for the Node Type.
	Attributes   map[string]AttributeDefinition   `yaml:"attributes,omitempty"`   // An optional list of attribute definitions for the Node Type.
	Requirements map[string]RequirementDefinition `yaml:"requirements,omitempty"` // An optional sequenced list of requirement definitions for the Node Type
	Capabilities map[string]CapabilityDefinition  `yaml:"capabilities,omitempty"` // An optional list of capability definitions for the Node Type
	Interfaces   map[string]InterfaceDefinition   `yaml:"interfaces,omitempty"`   // An optional list of interface definitions supported by the Node Type
	Artifacts    map[string]ArtifactDefinition    `yaml:"artifacts,omitempty" `   // An optional list of named artifact definitions for the Node Type
	Copy         string                           `yaml:"copy"`                   // The optional (symbolic) name of another node template to copy into (all keynames and values) and use as a basis for this node template.
}

// DataType as described in Appendix 6.5
// A Data Type definition defines the schema for new named datatypes in TOSCA.
type DataType struct {
	DerivedFrom string                        `yaml:"derived_from,omitempty"` // The optional key used when a datatype is derived from an existing TOSCA Data Type.
	Description string                        `yaml:"description,omitempty"`  // The optional description for the Data Type.
	Constraints ConstraintClauses             `yaml:"constraints"`            // The optional list of sequenced constraint clauses for the Data Type.
	Properties  map[string]PropertyDefinition `yaml:"properties"`             // The optional list property definitions that comprise the schema for a complex Data Type in TOSCA.
}

// NodeTemplate as described in Appendix 7.3
// A Node Template specifies the occurrence of a manageable software component as part of an application’s topology model which is defined in a TOSCA Service Template.  A Node template is an instance of a specified Node Type and can provide customized properties, constraints or operations which override the defaults provided by its Node Type and its implementations.
type NodeTemplate struct {
	Type         string                         `yaml:"type"`                   // The required name of the Node Type the Node Template is based upon.
	Decription   string                         `yaml:"description,omitempty"`  // An optional description for the Node Template.
	Directives   []string                       `yaml:"directives,omitempty"`   // An optional list of directive values to provide processing instructions to orchestrators and tooling.
	Properties   map[string]interface{}         `yaml:"properties,omitempty"`   // An optional list of property value assignments for the Node Template.
	Attributes   map[string]interface{}         `yaml:"attributes,omitempty"`   // An optional list of attribute value assignments for the Node Template.
	Requirements interface{}                    `yaml:"requirements,omitempty"` // An optional sequenced list of requirement assignments for the Node Template.
	Capabilities map[string]interface{}         `yaml:"capabilities,omitempty"` // An optional list of capability assignments for the Node Template.
	Interfaces   map[string]InterfaceDefinition `yaml:"interfaces,omitempty"`   // An optional list of named interface definitions for the Node Template.
	Artifcats    map[string]ArtifactDefinition  `yaml:"artifcats,omitempty"`    // An optional list of named artifact definitions for the Node Template.
	NodeFilter   map[string]NodeFilter          `yaml:"node_filter,omitempty"`  // The optional filter definition that TOSCA orchestrators would use to select the correct target node.  This keyname is only valid if the directive has the value of “selectable” set.
}

// RepositoryDefinition as desribed in Appendix 5.6
// A repository definition defines a named external repository which contains deployment and implementation artifacts that are referenced within the TOSCA Service Template.
type RepositoryDefinition struct {
	Description string               `yaml:"description,omitempty"` // The optional description for the repository.
	Url         string               `yaml:"url"`                   // The required URL or network address used to access the repository.
	Credential  CredentialDefinition `yaml:"credential"`            // The optional Credential used to authorize access to the repository.
}

// RelationshipType as described in appendix 6.9
// A Relationship Type is a reusable entity that defines the type of one or more relationships between Node Types or Node Templates.
// TODO
type RelationshipType interface{}

// CapabilityType as described in appendix 6.6
//A Capability Type is a reusable entity that describes a kind of capability that a Node Type can declare to expose.  Requirements (implicit or explicit) that are declared as part of one node can be matched to (i.e., fulfilled by) the Capabilities declared by another node.
// TODO
type CapabilityType interface{}

// ArtifactType as described in appendix 6.3
//An Artifact Type is a reusable entity that defines the type of one or more files which Node Types or Node Templates can have dependent relationships and used during operations such as during installation or deployment.
// TODO
type ArtifactType interface{}

// InterfaceType as described in Appendix A 6.4
// An Interface Type is a reusable entity that describes a set of operations that can be used to interact with or manage a node or relationship in a TOSCA topology.
type InterfaceType struct {
	Inputs map[string]PropertyDefinition `yaml:"inputs"` // The optional list of input parameter definitions.
}

// TopologyTemplateType as described in appendix A 8
// This section defines the topology template of a cloud application. The main ingredients of the topology template are node templates representing components of the application and relationship templates representing links between the components. These elements are defined in the nested node_templates section and the nested relationship_templates sections, respectively.  Furthermore, a topology template allows for defining input parameters, output parameters as well as grouping of node templates.
type TopologyTemplateType struct {
	Inputs        map[string]Input        `yaml:"inputs,omitempty"`
	NodeTemplates map[string]NodeTemplate `yaml:"node_templates"`
	Outputs       map[string]Output       `yaml:"outputs,omitempty"`
}

// TopologyStructure as defined in
//http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/csd03/TOSCA-Simple-Profile-YAML-v1.0-csd03.html
type TopologyTemplateStruct struct {
	DefinitionsVersion string                          `yaml:"tosca_definitions_version"` // A.9.3.1 tosca_definitions_version
	Description        string                          `yaml:"description,omitempty"`
	Imports            []string                        `yaml:"imports,omitempty"`            // Declares import statements external TOSCA Definitions documents. For example, these may be file location or URIs relative to the service template file within the same TOSCA CSAR file.
	Repositories       map[string]RepositoryDefinition `yaml:"repositories,omitempty"`       // Declares the list of external repositories which contain artifacts that are referenced in the service template along with their addresses and necessary credential information used to connect to them in order to retrieve the artifacts.
	DataTypes          map[string]DataType             `yaml:"data_types,omitempty"`         // Declares a list of optional TOSCA Data Type definitions.
	NodeTypes          map[string]NodeType             `yaml:"node_types,omitempty"`         // This section contains a set of node type definitions for use in service templates.
	RelationshipTypes  map[string]RelationshipType     `yaml:"relationship_types,omitempty"` // This section contains a set of relationship type definitions for use in service templates.
	CapabilityTypes    map[string]CapabilityType       `yaml:"capability_types,omitempty"`   // This section contains an optional list of capability type definitions for use in service templates.
	ArtifactTypes      map[string]ArtifactType         `yaml:"artifact_types,omitempty"`     // This section contains an optional list of artifact type definitions for use in service templates
	DlsDefinitions     interface{}                     `yaml:"dsl_definitions,omitempty"`    // Declares optional DSL-specific definitions and conventions.  For example, in YAML, this allows defining reusable YAML macros (i.e., YAML alias anchors) for use throughout the TOSCA Service Template.
	InterfaceTypes     map[string]InterfaceType        `yaml:"interface_types,omitempty"`    // This section contains an optional list of interface type definitions for use in service templates.
	TopologyTemplate   TopologyTemplateType            `yaml:"topology_template"`            // Defines the topology template of an application or service, consisting of node templates that represent the application’s or service’s components, as well as relationship templates representing relations between the components.
}
<commit_msg>Comments are more accurate<commit_after>package toscalib

// Status is used in the PropertyDefinition
type Status int64

// Valid values for Status as described in Appendix 5.7.3
const (
	Supported    Status = 1
	Unsupported  Status = 2
	Experimental Status = 3
	Deprecated   Status = 4
)

// ConstraintClauses definition as described in Appendix 5.2.
// This is a map where the index is a string that may have a value in
// {"equal","greater_than", ...} (see Appendix 5.2) a,s value is an interface
// for the definition.
// Example: ConstraintClauses may be [ "greater_than": 3 ]
type ConstraintClauses map[string]interface{}

// Evaluate the constraint and return a boolean
func (constraint *ConstraintClauses) Evaluate(interface{}) bool { return true }

// UnmarshalYAML TODO: implement the Mashaler YAML interface for the constraint type
func (constraint *ConstraintClauses) UnmarshalYAML() {}

// PropertyDefinition as described in Appendix 5.7:
// A property definition defines a named, typed value and related data
// that can be associated with an entity defined in this specification
// (e.g., Node Types, Relation ship Types, Capability Types, etc.).
// Properties are used by template authors to provide input values to
// TOSCA entities which indicate their “desired state” when they are instantiated.
// The value of a property can be retrieved using the
// get_property function within TOSCA Service Templates
type PropertyDefinition struct {
	Type        string            `yaml:"type"`                  // The required data type for the property
	Description string            `yaml:"description,omitempty"` // The optional description for the property.
	Required    bool              `yaml:"required"`              // An optional key that declares a property as required ( true) or not ( false) Default: true
	Default     interface{}       `yaml:"default"`
	Status      Status            `yaml:"status"`
	Constraints ConstraintClauses `yaml:"constraints,inline,omitempty"`
	EntrySchema string            `yaml:"entry_schema,omitempty"`
}

// Input corresponds to  `yaml:"inputs,omitempty"`
type Input struct {
	Type             string            `yaml:"type"`
	Description      string            `yaml:"description,omitempty"` // Not required
	Constraints      ConstraintClauses `yaml:"constraints,omitempty,inline"`
	ValidSourceTypes interface{}       `yaml:"valid_source_types,omitempty"`
	Occurrences      interface{}       `yaml:"occurrences,omitempty"`
}

// Output is the output of the topology
type Output struct {
	Value       interface{} `yaml:"value"`
	Description string      `yaml:"description"`
}

// AttributeDefinition TODO: Implement the type as defined in Appendix 5.9
type AttributeDefinition interface{}

// RequirementDefinition as described in Appendix 6.2
type RequirementDefinition struct {
	Capability   string     `yaml:"capability"`             // The required reserved keyname used that can be used to provide the name of a valid Capability Type that can fulfil the requirement
	node         string     `yaml:"node,omitempty"`         // The optional reserved keyname used to provide the name of a valid Node Type that contains the capability definition that can be used to fulfil the requirement
	Relationship string     `yaml:"relationship,omitempty"` //The optional reserved keyname used to provide the name of a valid Relationship Type to construct when fulfilling the requirement.
	Occurrences  ToscaRange `yaml:"occurences,omitempty"`   // The optional minimum and maximum occurrences for the requirement.  Note: the keyword UNBOUNDED is also supported to represent any positive integer
}

// CapabilityDefinition TODO: Appendix 6.1
type CapabilityDefinition interface{}

// InterfaceDefinition TODO: Appendix 5.12
type InterfaceDefinition interface{}

// ArtifactDefinition TODO: Appendix 5.5
type ArtifactDefinition interface{}

// NodeFilter TODO Appendix 5.4
// A node filter definition defines criteria for selection of a TOSCA Node Template based upon the template’s property values, capabilities and capability properties.
type NodeFilter interface{}

// NodeType as described is Appendix 6.8.
// A Node Type is a reusable entity that defines the type of one or more Node Templates. As such, a Node Type defines the structure of observable properties via a Properties Definition, the Requirements and Capabilities of the node as well as its supported interfaces.
type NodeType struct {
	DerivedFrom  string                           `yaml:"derived_from,omitempty"` // An optional parent Node Type name this new Node Type derives from
	Description  string                           `yaml:"description,omitempty"`  // An optional description for the Node Type
	Properties   map[string]PropertyDefinition    `yaml:"properties,omitempty"`   // An optional list of property definitions for the Node Type.
	Attributes   map[string]AttributeDefinition   `yaml:"attributes,omitempty"`   // An optional list of attribute definitions for the Node Type.
	Requirements map[string]RequirementDefinition `yaml:"requirements,omitempty"` // An optional sequenced list of requirement definitions for the Node Type
	Capabilities map[string]CapabilityDefinition  `yaml:"capabilities,omitempty"` // An optional list of capability definitions for the Node Type
	Interfaces   map[string]InterfaceDefinition   `yaml:"interfaces,omitempty"`   // An optional list of interface definitions supported by the Node Type
	Artifacts    map[string]ArtifactDefinition    `yaml:"artifacts,omitempty" `   // An optional list of named artifact definitions for the Node Type
	Copy         string                           `yaml:"copy"`                   // The optional (symbolic) name of another node template to copy into (all keynames and values) and use as a basis for this node template.
}

// DataType as described in Appendix 6.5
// A Data Type definition defines the schema for new named datatypes in TOSCA.
type DataType struct {
	DerivedFrom string                        `yaml:"derived_from,omitempty"` // The optional key used when a datatype is derived from an existing TOSCA Data Type.
	Description string                        `yaml:"description,omitempty"`  // The optional description for the Data Type.
	Constraints ConstraintClauses             `yaml:"constraints"`            // The optional list of sequenced constraint clauses for the Data Type.
	Properties  map[string]PropertyDefinition `yaml:"properties"`             // The optional list property definitions that comprise the schema for a complex Data Type in TOSCA.
}

// NodeTemplate as described in Appendix 7.3
// A Node Template specifies the occurrence of a manageable software component as part of an application’s topology model which is defined in a TOSCA Service Template.  A Node template is an instance of a specified Node Type and can provide customized properties, constraints or operations which override the defaults provided by its Node Type and its implementations.
type NodeTemplate struct {
	Type         string                         `yaml:"type"`                   // The required name of the Node Type the Node Template is based upon.
	Decription   string                         `yaml:"description,omitempty"`  // An optional description for the Node Template.
	Directives   []string                       `yaml:"directives,omitempty"`   // An optional list of directive values to provide processing instructions to orchestrators and tooling.
	Properties   map[string]interface{}         `yaml:"properties,omitempty"`   // An optional list of property value assignments for the Node Template.
	Attributes   map[string]interface{}         `yaml:"attributes,omitempty"`   // An optional list of attribute value assignments for the Node Template.
	Requirements interface{}                    `yaml:"requirements,omitempty"` // An optional sequenced list of requirement assignments for the Node Template.
	Capabilities map[string]interface{}         `yaml:"capabilities,omitempty"` // An optional list of capability assignments for the Node Template.
	Interfaces   map[string]InterfaceDefinition `yaml:"interfaces,omitempty"`   // An optional list of named interface definitions for the Node Template.
	Artifcats    map[string]ArtifactDefinition  `yaml:"artifcats,omitempty"`    // An optional list of named artifact definitions for the Node Template.
	NodeFilter   map[string]NodeFilter          `yaml:"node_filter,omitempty"`  // The optional filter definition that TOSCA orchestrators would use to select the correct target node.  This keyname is only valid if the directive has the value of “selectable” set.
}

// RepositoryDefinition as desribed in Appendix 5.6
// A repository definition defines a named external repository which contains deployment and implementation artifacts that are referenced within the TOSCA Service Template.
type RepositoryDefinition struct {
	Description string               `yaml:"description,omitempty"` // The optional description for the repository.
	Url         string               `yaml:"url"`                   // The required URL or network address used to access the repository.
	Credential  CredentialDefinition `yaml:"credential"`            // The optional Credential used to authorize access to the repository.
}

// RelationshipType as described in appendix 6.9
// A Relationship Type is a reusable entity that defines the type of one or more relationships between Node Types or Node Templates.
// TODO
type RelationshipType interface{}

// CapabilityType as described in appendix 6.6
//A Capability Type is a reusable entity that describes a kind of capability that a Node Type can declare to expose.  Requirements (implicit or explicit) that are declared as part of one node can be matched to (i.e., fulfilled by) the Capabilities declared by another node.
// TODO
type CapabilityType interface{}

// ArtifactType as described in appendix 6.3
//An Artifact Type is a reusable entity that defines the type of one or more files which Node Types or Node Templates can have dependent relationships and used during operations such as during installation or deployment.
// TODO
type ArtifactType interface{}

// InterfaceType as described in Appendix A 6.4
// An Interface Type is a reusable entity that describes a set of operations that can be used to interact with or manage a node or relationship in a TOSCA topology.
type InterfaceType struct {
	Inputs map[string]PropertyDefinition `yaml:"inputs"` // The optional list of input parameter definitions.
}

// TopologyTemplateType as described in appendix A 8
// This section defines the topology template of a cloud application. The main ingredients of the topology template are node templates representing components of the application and relationship templates representing links between the components. These elements are defined in the nested node_templates section and the nested relationship_templates sections, respectively.  Furthermore, a topology template allows for defining input parameters, output parameters as well as grouping of node templates.
type TopologyTemplateType struct {
	Inputs        map[string]Input        `yaml:"inputs,omitempty"`
	NodeTemplates map[string]NodeTemplate `yaml:"node_templates"`
	Outputs       map[string]Output       `yaml:"outputs,omitempty"`
}

// TopologyTemplateStruct as defined in
//http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/csd03/TOSCA-Simple-Profile-YAML-v1.0-csd03.html
type TopologyTemplateStruct struct {
	DefinitionsVersion string                          `yaml:"tosca_definitions_version"` // A.9.3.1 tosca_definitions_version
	Description        string                          `yaml:"description,omitempty"`
	Imports            []string                        `yaml:"imports,omitempty"`            // Declares import statements external TOSCA Definitions documents. For example, these may be file location or URIs relative to the service template file within the same TOSCA CSAR file.
	Repositories       map[string]RepositoryDefinition `yaml:"repositories,omitempty"`       // Declares the list of external repositories which contain artifacts that are referenced in the service template along with their addresses and necessary credential information used to connect to them in order to retrieve the artifacts.
	DataTypes          map[string]DataType             `yaml:"data_types,omitempty"`         // Declares a list of optional TOSCA Data Type definitions.
	NodeTypes          map[string]NodeType             `yaml:"node_types,omitempty"`         // This section contains a set of node type definitions for use in service templates.
	RelationshipTypes  map[string]RelationshipType     `yaml:"relationship_types,omitempty"` // This section contains a set of relationship type definitions for use in service templates.
	CapabilityTypes    map[string]CapabilityType       `yaml:"capability_types,omitempty"`   // This section contains an optional list of capability type definitions for use in service templates.
	ArtifactTypes      map[string]ArtifactType         `yaml:"artifact_types,omitempty"`     // This section contains an optional list of artifact type definitions for use in service templates
	DlsDefinitions     interface{}                     `yaml:"dsl_definitions,omitempty"`    // Declares optional DSL-specific definitions and conventions.  For example, in YAML, this allows defining reusable YAML macros (i.e., YAML alias anchors) for use throughout the TOSCA Service Template.
	InterfaceTypes     map[string]InterfaceType        `yaml:"interface_types,omitempty"`    // This section contains an optional list of interface type definitions for use in service templates.
	TopologyTemplate   TopologyTemplateType            `yaml:"topology_template"`            // Defines the topology template of an application or service, consisting of node templates that represent the application’s or service’s components, as well as relationship templates representing relations between the components.
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"net"
	"os"
	"pkg/proxy"
)

func main() {
	host, container := parseHostContainerAddrs()

	err := exposePort(host)
	if err != nil {
		sendError(err)
	}
	p, err := proxy.NewProxy(host, container)
	if err != nil {
		unexposePort(host)
		sendError(err)
	}
	go handleStopSignals(p)
	sendOK()
	p.Run()
	unexposePort(host)
	os.Exit(0)
}

func exposePort(host net.Addr) error {
	log.Printf("exposePort %#v\n", host)
	return nil
}

func unexposePort(host net.Addr) {
	log.Printf("unexposePort %#v\n", host)
}
<commit_msg>proxy: set up and tear down host port forwards<commit_after>package main

import (
	"errors"
	"fmt"
	"log"
	"net"
	"os"
	"pkg/proxy"
	"strings"
)

func main() {
	host, container := parseHostContainerAddrs()

	err := exposePort(host)
	if err != nil {
		sendError(err)
	}
	p, err := proxy.NewProxy(host, container)
	if err != nil {
		unexposePort(host)
		sendError(err)
	}
	go handleStopSignals(p)
	sendOK()
	p.Run()
	unexposePort(host)
	os.Exit(0)
}

func exposePort(host net.Addr) error {
	name := host.String()
	log.Printf("exposePort %s\n", name)
	err := os.Mkdir("/port/"+name, 0)
	if err != nil {
		log.Printf("Failed to mkdir /port/%s: %#v\n", name, err)
		return err
	}
	ctl, err := os.OpenFile("/port/"+name+"/ctl", os.O_RDWR, 0)
	if err != nil {
		log.Printf("Failed to open /port/%s/ctl: %#v\n", name, err)
		return err
	}
	_, err = ctl.WriteString(fmt.Sprintf("%s:%s", name, name))
	if err != nil {
		log.Printf("Failed to open /port/%s/ctl: %#v\n", name, err)
		return err
	}
	_, err = ctl.Seek(0, 0)
	if err != nil {
		log.Printf("Failed to seek on /port/%s/ctl: %#v\n", name, err)
		return err
	}
	results := make([]byte, 100)
	count, err := ctl.Read(results)
	if err != nil {
		log.Printf("Failed to read from /port/%s/ctl: %#v\n", name, err)
		return err
	}
	response := string(results[0:count])
	if strings.HasPrefix(response, "ERROR ") {
		os.Remove("/port/" + name + "/ctl")
		response = strings.Trim(response[6:], " \t\r\n")
		return errors.New(response)
	}
	// TODO: consider whether close/clunk of ctl would be a better tear down
	// signal
	return nil
}

func unexposePort(host net.Addr) {
	name := host.String()
	log.Printf("unexposePort %s\n", name)
	err := os.Remove("/port/" + name)
	if err != nil {
		log.Printf("Failed to remove /port/%s: %#v\n", name, err)
	}
}
<|endoftext|>