func (a *App) Run(requester *client.Requester) {
	line := liner.NewLiner()
	defer line.Close()
	line.SetCompleter(func(line string) (c []string) {
		return
	})
	if f, err := os.Open(a.historyFn); err == nil {
		line.ReadHistory(f)
		f.Close()
	}
	a.requester = requester
	a.prompt(line)
	if f, err := os.Create(a.historyFn); err != nil {
		fmt.Fprintf(os.Stderr, "error writing history file: %v", err)
	} else {
		line.WriteHistory(f)
		f.Close()
	}
}
Run begins SensorBee command line tool to management SensorBee
and execute BQL/UDF/UDTF statements.
package shell
import (
	"bufio"
	"fmt"
	"github.com/peterh/liner"
	"gopkg.in/sensorbee/sensorbee.v0/client"
	"io"
	"os"
	"path"
	"runtime"
	"strings"
)
type App struct {
	historyFn  string
	requester  *client.Requester
	commandMap map[string]Command
}
func SetUpCommands(commands []Command) App {
	histDir := os.Getenv("HOME")
	if runtime.GOOS == "windows" {
		histDir = path.Join(os.Getenv("APPDATA"), "PFN", "SensorBee")
		if err := os.MkdirAll(histDir, os.ModeDir); err != nil {
			fmt.Fprintf(os.Stderr, "failed to create application directory '%s': %s\n", histDir, err)
		}
	}
	app := App{
		historyFn:  path.Join(histDir, ".sensorbee_liner_history"),
		commandMap: map[string]Command{},
	}
	if len(commands) == 0 {
		return app
	}
	for _, cmd := range commands {
		cmd.Init()
		for _, v := range cmd.Name() {
			app.commandMap[v] = cmd
		}
	}
	return app
}
func (a *App) prompt(line *liner.State) {
	getNextLine := func(continued bool) (string, error) {
		promptStart := promptLineStart
		if currentTopology.name != "" {
			promptStart = fmt.Sprintf("%s%s", currentTopology.name,
				promptLineStart)
		}
		if continued {
			promptStart = ""
		}
		input, err := line.Prompt(promptStart)
		if err == nil && input != "" {
			line.AppendHistory(input)
		}
		return input, err
	}
	for a.readStartOfNextCommand(getNextLine, true) {
	}
}
func (a *App) readStartOfNextCommand(getNextLine func(bool) (string, error), topLevel bool) bool {
	input, err := getNextLine(false)
	if err != nil {
		if err != io.EOF {
			fmt.Fprintf(os.Stderr, "error reading line: %v", err)
		}
		if topLevel {
			fmt.Println("")
		}
		return false
	}
	if input != "" {
		if strings.ToLower(input) == "exit" {
			if !topLevel {
				fmt.Fprintln(os.Stdout, "exit from file processing")
			}
			return false
		}
		if strings.HasPrefix(input, "--") {  
			return true
		}
		in := strings.ToLower(strings.Split(input, " ")[0])
		if cmd, ok := a.commandMap[in]; ok {
			a.readCompleteCommand(cmd, input, getNextLine)
		} else {
			fmt.Fprintf(os.Stderr, "undefined command: %v\n", in)
		}
	}
	return true
}
func (a *App) readCompleteCommand(cmd Command, input string, getNextLine func(bool) (string, error)) {
	for {
		if input != "" {
			status, err := cmd.Input(input)
			switch status {
			case invalidCMD:
				fmt.Fprintf(os.Stderr, "input command is invalid: %v\n", err)
				return
			case preparedCMD:
				if fileCmd, ok := cmd.(*fileLoadCmd); ok {
					r := strings.NewReader(fileCmd.queries)
					b := bufio.NewReader(r)
					getNextLineInFile := func(continued bool) (string, error) {
						s, err := b.ReadString('\n')
						return strings.TrimSuffix(s, "\n"), err
					}
					path := fileCmd.filePath
					fmt.Printf("-- process %s --\n", path)
					for a.readStartOfNextCommand(getNextLineInFile, false) {
					}
					fmt.Printf("-- end %s --\n", path)
					return
				}
				cmd.Eval(a.requester)
				return
			}
		}
		var err error
		input, err = getNextLine(true)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			return
		}
	}
}