<commit_before>package just

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"runtime/debug"
	"strconv"
	"strings"
	"sync"
)

const (
	Version      = "v0.1.18"
	DebugEnvName = "JUST_DEBUG_MODE"
)

// Debug mode.
var (
	debugMutex = sync.RWMutex{}
	debugMode  = true
)

// Errors
var (
	ErrInvalidContext         = errors.New("invalid context")
	ErrRecoverInvalidResponse = errors.New("invalid response, recover panic")
)

// JUST Application interface.
type IApplication interface {
	IRouter

	Profiler() IProfiler
	Translator() ITranslator
	SerializerManager() ISerializerManager
	TemplatingManager() ITemplatingManager

	LocalDo(req *http.Request) IResponse

	SetProfiler(p IProfiler) IApplication
	SetTranslator(t ITranslator) IApplication
	SetNoRouteHandler(handler HandlerFunc) IApplication
	SetNoImplementedHandler(handler HandlerFunc) IApplication

	ServeHTTP(w http.ResponseWriter, req *http.Request)

	Run(address string) error
	RunTLS(address, certFile, keyFile string) error
}

type application struct {
	Router
	pool sync.Pool

	// Стандартные обработчики ошибок
	noRouteHandler       HandlerFunc
	noImplementedHandler HandlerFunc

	// Менеджер сериализаторов с поддержкой многопоточности
	serializerManager serializerManager

	// Менеджер для работы с шаблонами
	templatingManager templatingManager

	// Транлятор локализации i18n
	translator ITranslator

	// Менеджер профилирования
	profiler IProfiler
}

func (app *application) printWelcomeMessage(address string, tls bool) {
	fmt.Print("[WELCOME] Just Web Framework ", Version)
	if tls {
		fmt.Println(" [RUN ON", address, "/ TLS]")
	} else {
		fmt.Println(" [RUN ON", address+"]")
	}
}

func (app *application) Translator() ITranslator {
	return app.translator
}

func (app *application) Profiler() IProfiler {
	return app.profiler
}

func (app *application) TemplatingManager() ITemplatingManager {
	return &app.templatingManager
}

func (app *application) SetProfiler(p IProfiler) IApplication {
	app.profiler = p
	return app
}

func (app *application) SetTranslator(t ITranslator) IApplication {
	app.translator = t
	return app
}

func (app *application) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	// Усли поступил несуществующий запрос - выходим
	if req == nil || w == nil {
		return
	}
	// Берем контекст из пула
	c := app.pool.Get().(*Context).reset()
	c.Request, c.IsFrozenRequestBody = req, true
	// Передаем контекст в обработчик запросов для заполнения ответа
	app.handleHttpRequest(w, c)
	// Складываем контекст в пул
	app.pool.Put(c)
}

func (app *application) checkMethodForHaveBody(method string) bool {
	return method == "POST" || method == "PATCH" || method == "PUT"
}

func (app *application) handleHttpRequest(w http.ResponseWriter, c *Context) {
	if !c.IsValid() {
		if app.profiler != nil {
			app.profiler.Warning(ErrInvalidContext)
		}
		return
	}
	httpMethod, path := c.Request.Method, c.Request.URL.Path
	if app.checkMethodForHaveBody(httpMethod) && c.Request.Body != nil {
		// Преобразовываем данные
		if b, _ := ioutil.ReadAll(c.Request.Body); len(b) > 0 {
			c.Request.Body.Close()
			// Новое тело запроса с возможностью сбрасывания позиции чтения
			c.Request.Body = ioutil.NopCloser(bytes.NewReader(b))
		}
	}
	if app.profiler != nil {
		// Фиксация начала обработки запроса
		app.profiler.OnStartRequest(c.Request)
		// Профилирование выходных данных
		w = &profiledResponseWriter{
			profiler: app.profiler,
			writer:   w,
		}
	}
	// Recover
	defer func() {
		if rvr := recover(); rvr != nil {

			fmt.Fprintf(os.Stderr, "Panic: %+v\n", rvr)
			debug.PrintStack()

			http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
			if app.profiler != nil {
				app.profiler.Error(ErrRecoverInvalidResponse)
			}
		}
	}()
	// Выполняем handlers из роутеров
	response, existRoute := app.handleRouter(&app.Router, httpMethod, path, c)
	// Если ответ пустой
	if response == nil {
		// Если ответа так и нет, но был найден роут -> выдаем ошибку пустого ответа
		if existRoute {
			// 501 ошибка
			response = app.noImplementedHandler(c)
		} else {
			// Если ничего так и нет, выводим 404 ошибку
			// но перед этим прогоняем все обработчики
			if response = c.resetRoute(app, nil).Next(); response == nil {
				response = app.noRouteHandler(c)
			}
		}
	}
	if app.profiler != nil {
		// Фиксация выбора роута
		app.profiler.OnSelectRoute(c.Request, c.routeInfo)
	}
	// Отправляем response клиенту
	if response != nil {
		if streamFunc, ok := response.GetStreamHandler(); ok {
			streamFunc(w, c.Request)
		} else {
			if response.HasHeaders() {
				// Обработка заголовков
				for key, value := range response.GetHeaders() {
					if key == StrongRedirectHeaderKey {
						http.Redirect(w, c.Request, value, response.GetStatus())
						return
					} else if key == ServeFileHeaderKey {
						http.ServeFile(w, c.Request, value)
						return
					}
					w.Header().Set(key, value)
				}
			}
			w.WriteHeader(response.GetStatus())
			w.Write(response.GetData())
		}
		return
	}
	// Если ничего не смогли сделать, выдаем 405 ошибку
	http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
	if app.profiler != nil {
		app.profiler.Error(http.ErrNotSupported)
	}
}

// Локальный вызов запроса внутри движка
func (app *application) LocalDo(req *http.Request) IResponse {
	if req == nil {
		return nil
	}
	c := app.pool.Get().(*Context).reset()
	defer app.pool.Put(c)

	c.Request, c.IsFrozenRequestBody = req, true
	c.isLocalRequest = true

	httpMethod, path := c.Request.Method, c.Request.URL.Path
	if app.checkMethodForHaveBody(httpMethod) && c.Request.Body != nil {
		if b, _ := ioutil.ReadAll(c.Request.Body); len(b) > 0 {
			c.Request.Body.Close()
			c.Request.Body = ioutil.NopCloser(bytes.NewReader(b))
		}
	}
	defer func() {
		if rvr := recover(); rvr != nil {
			fmt.Fprintf(os.Stderr, "Panic: %+v\n", rvr)
			debug.PrintStack()
		}
	}()
	response, _ := app.handleRouter(&app.Router, httpMethod, path, c)
	return response
}

func (app *application) handleRouter(router *Router, httpMethod, path string, c *Context) (IResponse, bool) {
	if router != nil {
		// Поиск роута
		if router.routes != nil && len(router.routes) > 0 {
			if routes, ok := router.routes[httpMethod]; ok && len(routes) > 0 {
				for _, route := range routes {
					if params, ok := route.CheckPath(path); ok {
						return c.resetRoute(route, params).nextHandler()
					}
				}
			}
		}
		// Поиск следующего роутера
		if router.groups != nil && len(router.groups) > 0 {
			for _, r := range router.groups {
				if strings.Index(r.basePath, "{") >= 0 && r.rxPath != nil {
					if _, ok := r.CheckPath(path); ok {
						return app.handleRouter(r, httpMethod, path, c)
					}
					continue
				}
				if strings.Index(path, r.basePath) >= 0 {
					return app.handleRouter(r, httpMethod, path, c)
				}
			}
		}
	}
	return nil, false
}

func (app *application) Run(address string) error {
	app.printWelcomeMessage(address, false)
	return http.ListenAndServe(address, app)
}

func (app *application) RunTLS(address, certFile, keyFile string) error {
	app.printWelcomeMessage(address, true)
	return http.ListenAndServeTLS(address, certFile, keyFile, app)
}

func (app *application) SerializerManager() ISerializerManager {
	return &app.serializerManager
}

func (app *application) SetNoRouteHandler(handler HandlerFunc) IApplication {
	app.noRouteHandler = handler
	return app
}

func (app *application) SetNoImplementedHandler(handler HandlerFunc) IApplication {
	app.noImplementedHandler = handler
	return app
}

func noRouteDefHandler(c *Context) IResponse {
	return c.Serializer().Response(404,
		NewError("404", c.Trans("Route not found")).SetMetadata(H{
			"method": c.Request.Method,
			"path":   c.Request.URL.Path,
		}))
}

func noImplementedDefHandler(c *Context) IResponse {
	meta := H{
		"method": c.Request.Method,
		"path":   c.Request.URL.Path,
	}
	if c.routeInfo != nil {
		meta["route"] = c.routeInfo.BasePath()
	}
	return c.Serializer().Response(501,
		NewError("501", c.Trans("Response not implemented for current Route")).SetMetadata(meta))
}

func (app *application) initPool() *application {
	app.pool.New = func() interface{} {
		return &Context{app: app}
	}
	return app
}

// Set default serializer to just application (json, xml, form-data, x-www-form-urlencoded)
func SetDefSerializers(app IApplication) IApplication {
	app.SerializerManager().SetSerializer("json", []string{
		"application/json",
	}, &JsonSerializer{Ch: "utf-8"}).SetSerializer("xml", []string{
		"text/xml",
		"application/xml",
	}, &XmlSerializer{Ch: "utf-8"}).SetSerializer("form", []string{
		"multipart/form-data",
		"application/x-www-form-urlencoded",
	}, &FormSerializer{Ch: "utf-8", OnlyDeserialize: true}).SetDefaultName("json")
	return app
}

// Set default renderers (HTML UTF-8)
func SetDefRenderers(app IApplication) IApplication {
	app.TemplatingManager().SetRenderer("html", &HTMLRenderer{Charset: "utf-8"})
	return app
}

// Create new clear JUST application.
// Without serializers and renderers.
func NewClear() IApplication {
	app := &application{
		Router: Router{
			basePath:        "/",
			handlers:        nil,
			routeParamNames: nil,
			groups:          nil,
			routes:          nil,
		},
		noRouteHandler:       noRouteDefHandler,
		noImplementedHandler: noImplementedDefHandler,
		translator:           &baseTranslator{defaultLocale: "en"},
	}
	return app.initPool()
}

// Create new default JUST application.
func New() IApplication {
	return SetDefSerializers(SetDefRenderers(NewClear()))
}

// Change debug mode
func SetDebugMode(value bool) {
	debugMutex.RLock()
	defer debugMutex.RUnlock()
	debugMode = value
}

func IsDebug() bool {
	debugMutex.Lock()
	defer debugMutex.Unlock()
	return debugMode
}

func init() {
	if value, err := strconv.ParseBool(os.Getenv(DebugEnvName)); err == nil {
		SetDebugMode(value)
	}
}
<commit_msg>- The headings inside the redirection and serve files<commit_after>package just

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"runtime/debug"
	"strconv"
	"strings"
	"sync"
)

const (
	Version      = "v0.1.18"
	DebugEnvName = "JUST_DEBUG_MODE"
)

// Debug mode.
var (
	debugMutex = sync.RWMutex{}
	debugMode  = true
)

// Errors
var (
	ErrInvalidContext         = errors.New("invalid context")
	ErrRecoverInvalidResponse = errors.New("invalid response, recover panic")
)

// JUST Application interface.
type IApplication interface {
	IRouter

	Profiler() IProfiler
	Translator() ITranslator
	SerializerManager() ISerializerManager
	TemplatingManager() ITemplatingManager

	LocalDo(req *http.Request) IResponse

	SetProfiler(p IProfiler) IApplication
	SetTranslator(t ITranslator) IApplication
	SetNoRouteHandler(handler HandlerFunc) IApplication
	SetNoImplementedHandler(handler HandlerFunc) IApplication

	ServeHTTP(w http.ResponseWriter, req *http.Request)

	Run(address string) error
	RunTLS(address, certFile, keyFile string) error
}

type application struct {
	Router
	pool sync.Pool

	// Стандартные обработчики ошибок
	noRouteHandler       HandlerFunc
	noImplementedHandler HandlerFunc

	// Менеджер сериализаторов с поддержкой многопоточности
	serializerManager serializerManager

	// Менеджер для работы с шаблонами
	templatingManager templatingManager

	// Транлятор локализации i18n
	translator ITranslator

	// Менеджер профилирования
	profiler IProfiler
}

func (app *application) printWelcomeMessage(address string, tls bool) {
	fmt.Print("[WELCOME] Just Web Framework ", Version)
	if tls {
		fmt.Println(" [RUN ON", address, "/ TLS]")
	} else {
		fmt.Println(" [RUN ON", address+"]")
	}
}

func (app *application) Translator() ITranslator {
	return app.translator
}

func (app *application) Profiler() IProfiler {
	return app.profiler
}

func (app *application) TemplatingManager() ITemplatingManager {
	return &app.templatingManager
}

func (app *application) SetProfiler(p IProfiler) IApplication {
	app.profiler = p
	return app
}

func (app *application) SetTranslator(t ITranslator) IApplication {
	app.translator = t
	return app
}

func (app *application) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	// Усли поступил несуществующий запрос - выходим
	if req == nil || w == nil {
		return
	}
	// Берем контекст из пула
	c := app.pool.Get().(*Context).reset()
	c.Request, c.IsFrozenRequestBody = req, true
	// Передаем контекст в обработчик запросов для заполнения ответа
	app.handleHttpRequest(w, c)
	// Складываем контекст в пул
	app.pool.Put(c)
}

func (app *application) checkMethodForHaveBody(method string) bool {
	return method == "POST" || method == "PATCH" || method == "PUT"
}

func (app *application) handleHttpRequest(w http.ResponseWriter, c *Context) {
	if !c.IsValid() {
		if app.profiler != nil {
			app.profiler.Warning(ErrInvalidContext)
		}
		return
	}
	httpMethod, path := c.Request.Method, c.Request.URL.Path
	if app.checkMethodForHaveBody(httpMethod) && c.Request.Body != nil {
		// Преобразовываем данные
		if b, _ := ioutil.ReadAll(c.Request.Body); len(b) > 0 {
			c.Request.Body.Close()
			// Новое тело запроса с возможностью сбрасывания позиции чтения
			c.Request.Body = ioutil.NopCloser(bytes.NewReader(b))
		}
	}
	if app.profiler != nil {
		// Фиксация начала обработки запроса
		app.profiler.OnStartRequest(c.Request)
		// Профилирование выходных данных
		w = &profiledResponseWriter{
			profiler: app.profiler,
			writer:   w,
		}
	}
	// Recover
	defer func() {
		if rvr := recover(); rvr != nil {

			fmt.Fprintf(os.Stderr, "Panic: %+v\n", rvr)
			debug.PrintStack()

			http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
			if app.profiler != nil {
				app.profiler.Error(ErrRecoverInvalidResponse)
			}
		}
	}()
	// Выполняем handlers из роутеров
	response, existRoute := app.handleRouter(&app.Router, httpMethod, path, c)
	// Если ответ пустой
	if response == nil {
		// Если ответа так и нет, но был найден роут -> выдаем ошибку пустого ответа
		if existRoute {
			// 501 ошибка
			response = app.noImplementedHandler(c)
		} else {
			// Если ничего так и нет, выводим 404 ошибку
			// но перед этим прогоняем все обработчики
			if response = c.resetRoute(app, nil).Next(); response == nil {
				response = app.noRouteHandler(c)
			}
		}
	}
	if app.profiler != nil {
		// Фиксация выбора роута
		app.profiler.OnSelectRoute(c.Request, c.routeInfo)
	}
	// Отправляем response клиенту
	if response != nil {
		if streamFunc, ok := response.GetStreamHandler(); ok {
			streamFunc(w, c.Request)
		} else {
			if response.HasHeaders() {
				// Обработка заголовков
				headers, hasRedirect, hasServeFiles := response.GetHeaders(), false, false
				for key, value := range headers {
					if key == StrongRedirectHeaderKey {
						hasRedirect = true
						continue
					} else if key == ServeFileHeaderKey {
						hasServeFiles = true
						continue
					}
					w.Header().Set(key, value)
				}
				if hasRedirect {
					http.Redirect(w, c.Request, headers[StrongRedirectHeaderKey], response.GetStatus())
					return
				} else if hasServeFiles {
					http.ServeFile(w, c.Request, headers[ServeFileHeaderKey])
					return
				}
			}
			w.WriteHeader(response.GetStatus())
			w.Write(response.GetData())
		}
		return
	}
	// Если ничего не смогли сделать, выдаем 405 ошибку
	http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
	if app.profiler != nil {
		app.profiler.Error(http.ErrNotSupported)
	}
}

// Локальный вызов запроса внутри движка
func (app *application) LocalDo(req *http.Request) IResponse {
	if req == nil {
		return nil
	}
	c := app.pool.Get().(*Context).reset()
	defer app.pool.Put(c)

	c.Request, c.IsFrozenRequestBody = req, true
	c.isLocalRequest = true

	httpMethod, path := c.Request.Method, c.Request.URL.Path
	if app.checkMethodForHaveBody(httpMethod) && c.Request.Body != nil {
		if b, _ := ioutil.ReadAll(c.Request.Body); len(b) > 0 {
			c.Request.Body.Close()
			c.Request.Body = ioutil.NopCloser(bytes.NewReader(b))
		}
	}
	defer func() {
		if rvr := recover(); rvr != nil {
			fmt.Fprintf(os.Stderr, "Panic: %+v\n", rvr)
			debug.PrintStack()
		}
	}()
	response, _ := app.handleRouter(&app.Router, httpMethod, path, c)
	return response
}

func (app *application) handleRouter(router *Router, httpMethod, path string, c *Context) (IResponse, bool) {
	if router != nil {
		// Поиск роута
		if router.routes != nil && len(router.routes) > 0 {
			if routes, ok := router.routes[httpMethod]; ok && len(routes) > 0 {
				for _, route := range routes {
					if params, ok := route.CheckPath(path); ok {
						return c.resetRoute(route, params).nextHandler()
					}
				}
			}
		}
		// Поиск следующего роутера
		if router.groups != nil && len(router.groups) > 0 {
			for _, r := range router.groups {
				if strings.Index(r.basePath, "{") >= 0 && r.rxPath != nil {
					if _, ok := r.CheckPath(path); ok {
						return app.handleRouter(r, httpMethod, path, c)
					}
					continue
				}
				if strings.Index(path, r.basePath) >= 0 {
					return app.handleRouter(r, httpMethod, path, c)
				}
			}
		}
	}
	return nil, false
}

func (app *application) Run(address string) error {
	app.printWelcomeMessage(address, false)
	return http.ListenAndServe(address, app)
}

func (app *application) RunTLS(address, certFile, keyFile string) error {
	app.printWelcomeMessage(address, true)
	return http.ListenAndServeTLS(address, certFile, keyFile, app)
}

func (app *application) SerializerManager() ISerializerManager {
	return &app.serializerManager
}

func (app *application) SetNoRouteHandler(handler HandlerFunc) IApplication {
	app.noRouteHandler = handler
	return app
}

func (app *application) SetNoImplementedHandler(handler HandlerFunc) IApplication {
	app.noImplementedHandler = handler
	return app
}

func noRouteDefHandler(c *Context) IResponse {
	return c.Serializer().Response(404,
		NewError("404", c.Trans("Route not found")).SetMetadata(H{
			"method": c.Request.Method,
			"path":   c.Request.URL.Path,
		}))
}

func noImplementedDefHandler(c *Context) IResponse {
	meta := H{
		"method": c.Request.Method,
		"path":   c.Request.URL.Path,
	}
	if c.routeInfo != nil {
		meta["route"] = c.routeInfo.BasePath()
	}
	return c.Serializer().Response(501,
		NewError("501", c.Trans("Response not implemented for current Route")).SetMetadata(meta))
}

func (app *application) initPool() *application {
	app.pool.New = func() interface{} {
		return &Context{app: app}
	}
	return app
}

// Set default serializer to just application (json, xml, form-data, x-www-form-urlencoded)
func SetDefSerializers(app IApplication) IApplication {
	app.SerializerManager().SetSerializer("json", []string{
		"application/json",
	}, &JsonSerializer{Ch: "utf-8"}).SetSerializer("xml", []string{
		"text/xml",
		"application/xml",
	}, &XmlSerializer{Ch: "utf-8"}).SetSerializer("form", []string{
		"multipart/form-data",
		"application/x-www-form-urlencoded",
	}, &FormSerializer{Ch: "utf-8", OnlyDeserialize: true}).SetDefaultName("json")
	return app
}

// Set default renderers (HTML UTF-8)
func SetDefRenderers(app IApplication) IApplication {
	app.TemplatingManager().SetRenderer("html", &HTMLRenderer{Charset: "utf-8"})
	return app
}

// Create new clear JUST application.
// Without serializers and renderers.
func NewClear() IApplication {
	app := &application{
		Router: Router{
			basePath:        "/",
			handlers:        nil,
			routeParamNames: nil,
			groups:          nil,
			routes:          nil,
		},
		noRouteHandler:       noRouteDefHandler,
		noImplementedHandler: noImplementedDefHandler,
		translator:           &baseTranslator{defaultLocale: "en"},
	}
	return app.initPool()
}

// Create new default JUST application.
func New() IApplication {
	return SetDefSerializers(SetDefRenderers(NewClear()))
}

// Change debug mode
func SetDebugMode(value bool) {
	debugMutex.RLock()
	defer debugMutex.RUnlock()
	debugMode = value
}

func IsDebug() bool {
	debugMutex.Lock()
	defer debugMutex.Unlock()
	return debugMode
}

func init() {
	if value, err := strconv.ParseBool(os.Getenv(DebugEnvName)); err == nil {
		SetDebugMode(value)
	}
}
<|endoftext|>


<commit_before>package juzz

import (
	"reflect"
	"sync"
	"time"

	"lodeo.dynamic/util/logs"
)

type StartFunc func() (string, interface{}, error)
type WorkerFunc func(ctx interface{}) (string, interface{}, error)

type Finalizable interface {
	Finalize() error
}

type Worker struct {
	name         string
	numReferers  int
	in           chan interface{}
	fn           WorkerFunc
	nexts        map[string]*Worker
	multiplicity int
	sync.Mutex
}

func (w *Worker) SetNext(next *Worker) *Worker {
	w.SetNexts(map[string]*Worker{"": next})
	return next
}

func (w *Worker) SetNexts(nexts map[string]*Worker) {
	w.nexts = nexts

	for _, next := range nexts {
		next.numReferers++
	}
}

func (w *Worker) Run() {
	go func() {
		wg := &sync.WaitGroup{}
		for i := 0; i < w.multiplicity; i++ {
			i := i

			wg.Add(1)
			go func() {
				defer wg.Done()
				w.runSingle(i)
			}()
		}
		wg.Wait()

		for _, next := range w.nexts {
			next := next

			func() {
				next.Lock()
				defer next.Unlock()

				next.numReferers--
				if next.numReferers == 0 {
					close(next.in)
				}
			}()
		}
	}()
}

func (w *Worker) runSingle(index int) {
	for ctx := range w.in {
		func(ctx interface{}) {
			cancelFinalize := false
			if f, ok := ctx.(Finalizable); ok {
				defer func() {
					if !cancelFinalize {
						if err := f.Finalize(); err != nil {
							logs.Warn.Printf("context finalize error. %v", err)
						}
					}
				}()
			}

			logs.Info.Printf("processing %s[%d]...", w.name, index)
			start := time.Now()

			result, ctx, err := w.fn(ctx)
			if err != nil {
				logs.Error.Printf("failed %s[%d]. err:%v", w.name, index, err)
				return
			}
			if ctx == nil || reflect.ValueOf(ctx).IsNil() {
				// if fn returns null context, end process.
				return
			}

			logs.Info.Printf("%s[%d] done. time:%f", w.name, index, time.Now().Sub(start).Seconds())

			if w.nexts != nil {
				if next, ok := w.nexts[result]; ok {
					cancelFinalize = true
					next.in <- ctx
				} else {
					logs.Warn.Printf("%s[%d] next worker not found: %s", w.name, index, result)
				}
			}
		}(ctx)
	}
}

type Workers struct {
	starter *Worker
	workers []*Worker
	closeCh chan struct{}
}

func (ws *Workers) NewStarter(name string, fn StartFunc, multiplicity int) *Worker {
	if ws.starter != nil {
		panic("NewStarter can be called only once.")
	}

	wfn := func(_ interface{}) (string, interface{}, error) {
		return fn()
	}
	ws.starter = ws.NewWorker(name, wfn, multiplicity)
	return ws.starter
}

func (ws *Workers) NewWorker(name string, fn WorkerFunc, multiplicity int) *Worker {
	w := &Worker{name: name, fn: fn, multiplicity: multiplicity}
	w.in = make(chan interface{})
	ws.workers = append(ws.workers, w)
	return w
}

func (ws *Workers) Run() {
	if ws.starter == nil {
		panic("starter required.")
	}

	if ws.closeCh != nil {
		panic("already Ran")
	}

	ws.closeCh = make(chan struct{})

	for _, w := range ws.workers {
		w.Run()
	}

	go func() {
	L:
		for {
			select {
			case <-ws.closeCh:
				close(ws.starter.in)
				break L
			case ws.starter.in <- nil:
			}
		}
	}()
}

func (ws *Workers) Close(timeout time.Duration) {
	ws.closeCh <- struct{}{}

	// sleep for now
	// TODO: wait for the last channel close
	time.Sleep(timeout)
}
<commit_msg>rename the method name.<commit_after>package juzz

import (
	"reflect"
	"sync"
	"time"

	"lodeo.dynamic/util/logs"
)

type StartFunc func() (string, interface{}, error)
type WorkerFunc func(ctx interface{}) (string, interface{}, error)

type Finalizable interface {
	Finalize() error
}

type Worker struct {
	name         string
	numReferers  int
	in           chan interface{}
	fn           WorkerFunc
	nexts        map[string]*Worker
	multiplicity int
	sync.Mutex
}

func (w *Worker) Next(next *Worker) *Worker {
	w.NextFor("", next)
	return next
}

func (w *Worker) Nexts(nexts map[string]*Worker) {
	for k, v := range nexts {
		w.NextFor(k, v)
	}
}

func (w *Worker) NextFor(result string, next *Worker) {
	if w.nexts == nil {
		w.nexts = make(map[string]*Worker)
	}
	next.numReferers++
	w.nexts[result] = next
}

func (w *Worker) run(wswg *sync.WaitGroup) {
	wswg.Add(1)
	go func() {
		defer wswg.Done()

		wg := &sync.WaitGroup{}
		for i := 0; i < w.multiplicity; i++ {
			i := i

			wg.Add(1)
			go func() {
				defer wg.Done()
				w.runSingle(i)
			}()
		}
		wg.Wait()

		for _, next := range w.nexts {
			next := next

			func() {
				next.Lock()
				defer next.Unlock()

				next.numReferers--
				if next.numReferers <= 0 {
					close(next.in)
				}
			}()
		}
	}()
}

func (w *Worker) runSingle(index int) {
	for ctx := range w.in {
		func(ctx interface{}) {
			cancelFinalize := false
			if f, ok := ctx.(Finalizable); ok {
				defer func() {
					if !cancelFinalize {
						if err := f.Finalize(); err != nil {
							logs.Warn.Printf("context finalize error. %v", err)
						}
					}
				}()
			}

			logs.Info.Printf("processing %s[%d]...", w.name, index)
			start := time.Now()

			result, ctx, err := w.fn(ctx)
			if err != nil {
				logs.Error.Printf("failed %s[%d]. err:%v", w.name, index, err)
				return
			}
			if ctx == nil || reflect.ValueOf(ctx).IsNil() {
				// if fn returns null context, end process.
				return
			}

			logs.Info.Printf("%s[%d] done. time:%f", w.name, index, time.Now().Sub(start).Seconds())

			if w.nexts != nil {
				if next, ok := w.nexts[result]; ok {
					cancelFinalize = true
					next.in <- ctx
				} else {
					logs.Warn.Printf("%s[%d] next worker not found: %s", w.name, index, result)
				}
			}
		}(ctx)
	}
	logs.Info.Printf("%s[%d] was shutdown.", w.name, index)
}

type Workers struct {
	starter    *Worker
	workers    []*Worker
	shutdownCh chan struct{}
	sync.WaitGroup
}

func (ws *Workers) NewStarter(name string, fn StartFunc, multiplicity int) *Worker {
	if ws.starter != nil {
		panic("NewStarter can be called only once.")
	}

	wfn := func(_ interface{}) (string, interface{}, error) {
		return fn()
	}
	ws.starter = ws.NewWorker(name, wfn, multiplicity)
	return ws.starter
}

func (ws *Workers) NewWorker(name string, fn WorkerFunc, multiplicity int) *Worker {
	w := &Worker{name: name, fn: fn, multiplicity: multiplicity}
	w.in = make(chan interface{})
	ws.workers = append(ws.workers, w)
	return w
}

func (ws *Workers) Run() {
	if ws.starter == nil {
		panic("starter required.")
	}

	if ws.shutdownCh != nil {
		panic("already Ran")
	}

	ws.shutdownCh = make(chan struct{})

	for _, w := range ws.workers {
		w.run(&ws.WaitGroup)
	}

	go func() {
	L:
		for {
			select {
			case <-ws.shutdownCh:
				close(ws.starter.in)
				break L
			case ws.starter.in <- nil:
			}
		}
	}()
}

func (ws *Workers) Shutdown() {
	ws.shutdownCh <- struct{}{}
	ws.Wait()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"log"
	"os"
	"syscall"
	"unsafe"
)

/*** defines ***/

const KILO_VERSION = "0.0.1"
const (
	ARROW_LEFT  = 1000 + iota
	ARROW_RIGHT = 1000 + iota
	ARROW_UP    = 1000 + iota
	ARROW_DOWN  = 1000 + iota
	DEL_KEY     = 1000 + iota
	HOME_KEY    = 1000 + iota
	END_KEY     = 1000 + iota
	PAGE_UP     = 1000 + iota
	PAGE_DOWN   = 1000 + iota
)

/*** data ***/

type Termios struct {
	Iflag  uint32
	Oflag  uint32
	Cflag  uint32
	Lflag  uint32
	Cc     [20]byte
	Ispeed uint32
	Ospeed uint32
}

type erow struct {
	chars []byte
}

type editorConfig struct {
	cx          int
	cy          int
	screenRows  int
	screenCols  int
	numRows     int
	rows        erow
	origTermios *Termios
}

type WinSize struct {
	Row    uint16
	Col    uint16
	Xpixel uint16
	Ypixel uint16
}

var E editorConfig

/*** terminal ***/

func die(err error) {
	disableRawMode()
	io.WriteString(os.Stdout, "\x1b[2J")
	io.WriteString(os.Stdout, "\x1b[H")
	log.Fatal(err)
}

func TcSetAttr(fd uintptr, termios *Termios) error {
	// TCSETS+1 == TCSETSW, because TCSAFLUSH doesn't exist
	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(syscall.TCSETS+1), uintptr(unsafe.Pointer(termios))); err != 0 {
		return err
	}
	return nil
}

func TcGetAttr(fd uintptr) *Termios {
	var termios = &Termios{}
	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, syscall.TCGETS, uintptr(unsafe.Pointer(termios))); err != 0 {
		log.Fatalf("Problem getting terminal attributes: %s\n", err)
	}
	return termios
}

func enableRawMode() {
	E.origTermios = TcGetAttr(os.Stdin.Fd())
	var raw Termios
	raw = *E.origTermios
	raw.Iflag &^= syscall.BRKINT | syscall.ICRNL | syscall.INPCK | syscall.ISTRIP | syscall.IXON
	raw.Oflag &^= syscall.OPOST
	raw.Cflag |= syscall.CS8
	raw.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.IEXTEN | syscall.ISIG
	raw.Cc[syscall.VMIN+1] = 0
	raw.Cc[syscall.VTIME+1] = 1
	if e := TcSetAttr(os.Stdin.Fd(), &raw); e != nil {
		log.Fatalf("Problem enabling raw mode: %s\n", e)
	}
}

func disableRawMode() {
	if e := TcSetAttr(os.Stdin.Fd(), E.origTermios); e != nil {
		log.Fatalf("Problem disabling raw mode: %s\n", e)
	}
}

func editorReadKey() int {
	var buffer [1]byte
	var cc int
	var err error
	for cc, err = os.Stdin.Read(buffer[:]); cc != 1; cc, err = os.Stdin.Read(buffer[:]) {
	}
	if err != nil {
		die(err)
	}
	if buffer[0] == '\x1b' {
		var seq [2]byte
		if cc, _ = os.Stdin.Read(seq[:]); cc != 2 {
			return '\x1b'
		}

		if seq[0] == '[' {
			if seq[1] >= '0' && seq[1] <= '9' {
				if cc, err = os.Stdin.Read(buffer[:]); cc != 1 {
					return '\x1b'
				}
				if buffer[0] == '~' {
					switch seq[1] {
					case '1':
						return HOME_KEY
					case '3':
						return DEL_KEY
					case '4':
						return END_KEY
					case '5':
						return PAGE_UP
					case '6':
						return PAGE_DOWN
					case '7':
						return HOME_KEY
					case '8':
						return END_KEY
					}
				}
				// XXX - what happens here?
			} else {
				switch seq[1] {
				case 'A':
					return ARROW_UP
				case 'B':
					return ARROW_DOWN
				case 'C':
					return ARROW_RIGHT
				case 'D':
					return ARROW_LEFT
				case 'H':
					return HOME_KEY
				case 'F':
					return END_KEY
				}
			}
		} else if seq[0] == '0' {
			switch seq[1] {
			case 'H':
				return HOME_KEY
			case 'F':
				return END_KEY
			}
		}

		return '\x1b'
	}
	return int(buffer[0])
}

func getCursorPosition(rows *int, cols *int) int {
	io.WriteString(os.Stdout, "\x1b[6n")
	var buffer [1]byte
	var buf []byte
	var cc int
	for cc, _ = os.Stdin.Read(buffer[:]); cc == 1; cc, _ = os.Stdin.Read(buffer[:]) {
		if buffer[0] == 'R' {
			break
		}
		buf = append(buf, buffer[0])
	}
	if string(buf[0:2]) != "\x1b[" {
		log.Printf("Failed to read rows;cols from tty\n")
		return -1
	}
	if n, e := fmt.Sscanf(string(buf[2:]), "%d;%d", rows, cols); n != 2 || e != nil {
		if e != nil {
			log.Printf("getCursorPosition: fmt.Sscanf() failed: %s\n", e)
		}
		if n != 2 {
			log.Printf("getCursorPosition: got %d items, wanted 2\n", n)
		}
		return -1
	}
	return 0
}

func getWindowSize(rows *int, cols *int) int {
	var w WinSize
	_, _, err := syscall.Syscall(syscall.SYS_IOCTL,
		os.Stdout.Fd(),
		syscall.TIOCGWINSZ,
		uintptr(unsafe.Pointer(&w)),
	)
	if err != 0 { // type syscall.Errno
		io.WriteString(os.Stdout, "\x1b[999C\x1b[999B")
		return getCursorPosition(rows, cols)
	} else {
		*rows = int(w.Row)
		*cols = int(w.Col)
		return 0
	}
	return -1
}

/*** file I/O ***/

func editorOpen() {
	var line = "Hello, World!"

	E.rows.chars = []byte(line)
	E.numRows = 1
}

/*** input ***/

func editorMoveCursor(key int) {
	switch key {
	case ARROW_LEFT:
		if E.cx != 0 {
			E.cx--
		}
	case ARROW_RIGHT:
		if E.cx != E.screenCols-1 {
			E.cx++
		}
	case ARROW_UP:
		if E.cy != 0 {
			E.cy--
		}
	case ARROW_DOWN:
		if E.cy != E.screenRows-1 {
			E.cy++
		}
	}
}

func editorProcessKeypress() {
	c := editorReadKey()
	switch c {
	case ('q' & 0x1f):
		io.WriteString(os.Stdout, "\x1b[2J")
		io.WriteString(os.Stdout, "\x1b[H")
		disableRawMode()
		os.Exit(0)
	case HOME_KEY:
		E.cx = 0
	case END_KEY:
		E.cx = E.screenCols - 1
	case PAGE_UP, PAGE_DOWN:
		dir := ARROW_DOWN
		if c == PAGE_UP {
			dir = ARROW_UP
		}
		for times := E.screenRows; times > 0; times-- {
			editorMoveCursor(dir)
		}
	case ARROW_UP, ARROW_DOWN, ARROW_LEFT, ARROW_RIGHT:
		editorMoveCursor(c)
	}
}

/*** append buffer ***/

type abuf struct {
	buf []byte
}

func (p abuf) String() string {
	return string(p.buf)
}

func (p *abuf) abAppend(s string) {
	p.buf = append(p.buf, []byte(s)...)
}

func (p *abuf) abAppendBytes(b []byte) {
	p.buf = append(p.buf, b...)
}

/*** output ***/

func editorRefreshScreen() {
	var ab abuf
	ab.abAppend("\x1b[25l")
	ab.abAppend("\x1b[H")
	editorDrawRows(&ab)
	ab.abAppend(fmt.Sprintf("\x1b[%d;%dH", E.cy+1, E.cx+1))
	ab.abAppend("\x1b[25h")
	io.WriteString(os.Stdout, ab.String())
}

func editorDrawRows(ab *abuf) {
	for y := 0; y < E.screenRows-1; y++ {
		if y >= E.numRows {
			if y == E.screenRows/3 {
				w := fmt.Sprintf("Kilo editor -- version %s", KILO_VERSION)
				if len(w) > E.screenCols {
					w = w[0:E.screenCols]
				}
				pad := "~ "
				for padding := (E.screenCols - len(w)) / 2; padding > 0; padding-- {
					ab.abAppend(pad)
					pad = " "
				}
				ab.abAppend(w)
			} else {
				ab.abAppend("~")
			}
		} else {
			length := len(E.rows.chars)
			if length > E.screenCols { length = E.screenCols }
			ab.abAppendBytes(E.rows.chars[:length])
		}
		ab.abAppend("\x1b[K")
		if y < E.screenRows-1 {
			ab.abAppend("\r\n")
		}
	}
}

/*** init ***/

func initEditor() {
	if getWindowSize(&E.screenRows, &E.screenCols) == -1 {
		die(fmt.Errorf("couldn't get screen size"))
	}
}

func main() {
	enableRawMode()
	defer disableRawMode()
	initEditor()
	editorOpen()

	for {
		editorRefreshScreen()
		editorProcessKeypress()
	}
}
<commit_msg>Step 58 - read in one line from a file.<commit_after>package main

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"os"
	"syscall"
	"unsafe"
)

/*** defines ***/

const KILO_VERSION = "0.0.1"
const (
	ARROW_LEFT  = 1000 + iota
	ARROW_RIGHT = 1000 + iota
	ARROW_UP    = 1000 + iota
	ARROW_DOWN  = 1000 + iota
	DEL_KEY     = 1000 + iota
	HOME_KEY    = 1000 + iota
	END_KEY     = 1000 + iota
	PAGE_UP     = 1000 + iota
	PAGE_DOWN   = 1000 + iota
)

/*** data ***/

type Termios struct {
	Iflag  uint32
	Oflag  uint32
	Cflag  uint32
	Lflag  uint32
	Cc     [20]byte
	Ispeed uint32
	Ospeed uint32
}

type erow struct {
	chars []byte
}

type editorConfig struct {
	cx          int
	cy          int
	screenRows  int
	screenCols  int
	numRows     int
	rows        erow
	origTermios *Termios
}

type WinSize struct {
	Row    uint16
	Col    uint16
	Xpixel uint16
	Ypixel uint16
}

var E editorConfig

/*** terminal ***/

func die(err error) {
	disableRawMode()
	io.WriteString(os.Stdout, "\x1b[2J")
	io.WriteString(os.Stdout, "\x1b[H")
	log.Fatal(err)
}

func TcSetAttr(fd uintptr, termios *Termios) error {
	// TCSETS+1 == TCSETSW, because TCSAFLUSH doesn't exist
	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(syscall.TCSETS+1), uintptr(unsafe.Pointer(termios))); err != 0 {
		return err
	}
	return nil
}

func TcGetAttr(fd uintptr) *Termios {
	var termios = &Termios{}
	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, syscall.TCGETS, uintptr(unsafe.Pointer(termios))); err != 0 {
		log.Fatalf("Problem getting terminal attributes: %s\n", err)
	}
	return termios
}

func enableRawMode() {
	E.origTermios = TcGetAttr(os.Stdin.Fd())
	var raw Termios
	raw = *E.origTermios
	raw.Iflag &^= syscall.BRKINT | syscall.ICRNL | syscall.INPCK | syscall.ISTRIP | syscall.IXON
	raw.Oflag &^= syscall.OPOST
	raw.Cflag |= syscall.CS8
	raw.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.IEXTEN | syscall.ISIG
	raw.Cc[syscall.VMIN+1] = 0
	raw.Cc[syscall.VTIME+1] = 1
	if e := TcSetAttr(os.Stdin.Fd(), &raw); e != nil {
		log.Fatalf("Problem enabling raw mode: %s\n", e)
	}
}

func disableRawMode() {
	if e := TcSetAttr(os.Stdin.Fd(), E.origTermios); e != nil {
		log.Fatalf("Problem disabling raw mode: %s\n", e)
	}
}

func editorReadKey() int {
	var buffer [1]byte
	var cc int
	var err error
	for cc, err = os.Stdin.Read(buffer[:]); cc != 1; cc, err = os.Stdin.Read(buffer[:]) {
	}
	if err != nil {
		die(err)
	}
	if buffer[0] == '\x1b' {
		var seq [2]byte
		if cc, _ = os.Stdin.Read(seq[:]); cc != 2 {
			return '\x1b'
		}

		if seq[0] == '[' {
			if seq[1] >= '0' && seq[1] <= '9' {
				if cc, err = os.Stdin.Read(buffer[:]); cc != 1 {
					return '\x1b'
				}
				if buffer[0] == '~' {
					switch seq[1] {
					case '1':
						return HOME_KEY
					case '3':
						return DEL_KEY
					case '4':
						return END_KEY
					case '5':
						return PAGE_UP
					case '6':
						return PAGE_DOWN
					case '7':
						return HOME_KEY
					case '8':
						return END_KEY
					}
				}
				// XXX - what happens here?
			} else {
				switch seq[1] {
				case 'A':
					return ARROW_UP
				case 'B':
					return ARROW_DOWN
				case 'C':
					return ARROW_RIGHT
				case 'D':
					return ARROW_LEFT
				case 'H':
					return HOME_KEY
				case 'F':
					return END_KEY
				}
			}
		} else if seq[0] == '0' {
			switch seq[1] {
			case 'H':
				return HOME_KEY
			case 'F':
				return END_KEY
			}
		}

		return '\x1b'
	}
	return int(buffer[0])
}

func getCursorPosition(rows *int, cols *int) int {
	io.WriteString(os.Stdout, "\x1b[6n")
	var buffer [1]byte
	var buf []byte
	var cc int
	for cc, _ = os.Stdin.Read(buffer[:]); cc == 1; cc, _ = os.Stdin.Read(buffer[:]) {
		if buffer[0] == 'R' {
			break
		}
		buf = append(buf, buffer[0])
	}
	if string(buf[0:2]) != "\x1b[" {
		log.Printf("Failed to read rows;cols from tty\n")
		return -1
	}
	if n, e := fmt.Sscanf(string(buf[2:]), "%d;%d", rows, cols); n != 2 || e != nil {
		if e != nil {
			log.Printf("getCursorPosition: fmt.Sscanf() failed: %s\n", e)
		}
		if n != 2 {
			log.Printf("getCursorPosition: got %d items, wanted 2\n", n)
		}
		return -1
	}
	return 0
}

func getWindowSize(rows *int, cols *int) int {
	var w WinSize
	_, _, err := syscall.Syscall(syscall.SYS_IOCTL,
		os.Stdout.Fd(),
		syscall.TIOCGWINSZ,
		uintptr(unsafe.Pointer(&w)),
	)
	if err != 0 { // type syscall.Errno
		io.WriteString(os.Stdout, "\x1b[999C\x1b[999B")
		return getCursorPosition(rows, cols)
	} else {
		*rows = int(w.Row)
		*cols = int(w.Col)
		return 0
	}
	return -1
}

/*** file I/O ***/

func editorOpen(filename string) {
	fd, err := os.Open(filename)
	if err != nil {
		die(err)
	}
	defer fd.Close()
	fp := bufio.NewReader(fd)

	line, err := fp.ReadBytes('\n')
	if err != nil {
		die(err)
	}
	E.rows.chars = line[:len(line)-1]
	E.numRows = 1
}

/*** input ***/

func editorMoveCursor(key int) {
	switch key {
	case ARROW_LEFT:
		if E.cx != 0 {
			E.cx--
		}
	case ARROW_RIGHT:
		if E.cx != E.screenCols-1 {
			E.cx++
		}
	case ARROW_UP:
		if E.cy != 0 {
			E.cy--
		}
	case ARROW_DOWN:
		if E.cy != E.screenRows-1 {
			E.cy++
		}
	}
}

func editorProcessKeypress() {
	c := editorReadKey()
	switch c {
	case ('q' & 0x1f):
		io.WriteString(os.Stdout, "\x1b[2J")
		io.WriteString(os.Stdout, "\x1b[H")
		disableRawMode()
		os.Exit(0)
	case HOME_KEY:
		E.cx = 0
	case END_KEY:
		E.cx = E.screenCols - 1
	case PAGE_UP, PAGE_DOWN:
		dir := ARROW_DOWN
		if c == PAGE_UP {
			dir = ARROW_UP
		}
		for times := E.screenRows; times > 0; times-- {
			editorMoveCursor(dir)
		}
	case ARROW_UP, ARROW_DOWN, ARROW_LEFT, ARROW_RIGHT:
		editorMoveCursor(c)
	}
}

/*** append buffer ***/

type abuf struct {
	buf []byte
}

func (p abuf) String() string {
	return string(p.buf)
}

func (p *abuf) abAppend(s string) {
	p.buf = append(p.buf, []byte(s)...)
}

func (p *abuf) abAppendBytes(b []byte) {
	p.buf = append(p.buf, b...)
}

/*** output ***/

func editorRefreshScreen() {
	var ab abuf
	ab.abAppend("\x1b[25l")
	ab.abAppend("\x1b[H")
	editorDrawRows(&ab)
	ab.abAppend(fmt.Sprintf("\x1b[%d;%dH", E.cy+1, E.cx+1))
	ab.abAppend("\x1b[25h")
	io.WriteString(os.Stdout, ab.String())
}

func editorDrawRows(ab *abuf) {
	for y := 0; y < E.screenRows-1; y++ {
		if y >= E.numRows {
			if y == E.screenRows/3 {
				w := fmt.Sprintf("Kilo editor -- version %s", KILO_VERSION)
				if len(w) > E.screenCols {
					w = w[0:E.screenCols]
				}
				pad := "~ "
				for padding := (E.screenCols - len(w)) / 2; padding > 0; padding-- {
					ab.abAppend(pad)
					pad = " "
				}
				ab.abAppend(w)
			} else {
				ab.abAppend("~")
			}
		} else {
			length := len(E.rows.chars)
			if length > E.screenCols { length = E.screenCols }
			ab.abAppendBytes(E.rows.chars[:length])
		}
		ab.abAppend("\x1b[K")
		if y < E.screenRows-1 {
			ab.abAppend("\r\n")
		}
	}
}

/*** init ***/

func initEditor() {
	if getWindowSize(&E.screenRows, &E.screenCols) == -1 {
		die(fmt.Errorf("couldn't get screen size"))
	}
}

func main() {
	enableRawMode()
	defer disableRawMode()
	initEditor()
	if len(os.Args) > 1 {
		editorOpen(os.Args[1])
	}

	for {
		editorRefreshScreen()
		editorProcessKeypress()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path"
	"runtime/pprof"
)

var (
	envUser  = os.Getenv("USER")
	envHome  = os.Getenv("HOME")
	envHost  = os.Getenv("HOSTNAME")
	envPath  = os.Getenv("PATH")
	envShell = os.Getenv("SHELL")
)

var (
	gExitFlag      bool
	gLastDirPath   string
	gSelectionPath string
	gSocketPath    string
	gLogPath       string
	gServerLogPath string
	gConfigPath    string
)

func init() {
	if envUser == "" {
		log.Fatal("$USER not set")
	}
	if envHome == "" {
		envHome = "/home/" + envUser
	}
	if envHost == "" {
		host, err := os.Hostname()
		if err != nil {
			log.Printf("hostname: %s", err)
		}
		envHost = host
	}

	tmp := os.TempDir()

	gSocketPath = path.Join(tmp, fmt.Sprintf("lf.%s.sock", envUser))

	// TODO: unique log file for each client
	gLogPath = path.Join(tmp, fmt.Sprintf("lf.%s.log", envUser))
	gServerLogPath = path.Join(tmp, fmt.Sprintf("lf.%s.server.log", envUser))

	// TODO: xdg-config-home etc.
	gConfigPath = path.Join(envHome, ".config", "lf", "lfrc")
}

func startServer() {
	cmd := exec.Command(os.Args[0], "-server")
	if err := cmd.Start(); err != nil {
		log.Printf("starting server: %s", err)
	}
}

func main() {
	serverMode := flag.Bool("server", false, "start server (automatic)")
	cpuprofile := flag.String("cpuprofile", "", "path to the file to write the cpu profile")
	flag.StringVar(&gLastDirPath, "last-dir-path", "", "path to the file to write the last dir on exit (to use for cd)")
	flag.StringVar(&gSelectionPath, "selection-path", "", "path to the file to write selected files on exit (to use as open file dialog)")

	flag.Parse()

	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			log.Fatal("could not create CPU profile: ", err)
		}
		if err := pprof.StartCPUProfile(f); err != nil {
			log.Fatal("could not start CPU profile: ", err)
		}
		defer pprof.StopCPUProfile()
	}

	if *serverMode {
		serve()
	} else {
		// TODO: check if the socket is working
		if _, err := os.Stat(gSocketPath); os.IsNotExist(err) {
			startServer()
		}

		client()
	}
}
<commit_msg>use XDG_CONFIG_HOME if set<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path"
	"runtime/pprof"
)

var (
	envUser   = os.Getenv("USER")
	envHome   = os.Getenv("HOME")
	envHost   = os.Getenv("HOSTNAME")
	envPath   = os.Getenv("PATH")
	envShell  = os.Getenv("SHELL")
	envConfig = os.Getenv("XDG_CONFIG_HOME")
)

var (
	gExitFlag      bool
	gLastDirPath   string
	gSelectionPath string
	gSocketPath    string
	gLogPath       string
	gServerLogPath string
	gConfigPath    string
)

func init() {
	if envUser == "" {
		log.Fatal("$USER not set")
	}
	if envHome == "" {
		envHome = "/home/" + envUser
	}
	if envHost == "" {
		host, err := os.Hostname()
		if err != nil {
			log.Printf("hostname: %s", err)
		}
		envHost = host
	}
	if envConfig == "" {
		envConfig = path.Join(envHome, ".config")
	}

	tmp := os.TempDir()

	gSocketPath = path.Join(tmp, fmt.Sprintf("lf.%s.sock", envUser))

	// TODO: unique log file for each client
	gLogPath = path.Join(tmp, fmt.Sprintf("lf.%s.log", envUser))
	gServerLogPath = path.Join(tmp, fmt.Sprintf("lf.%s.server.log", envUser))

	gConfigPath = path.Join(envConfig, "lf", "lfrc")
}

func startServer() {
	cmd := exec.Command(os.Args[0], "-server")
	if err := cmd.Start(); err != nil {
		log.Printf("starting server: %s", err)
	}
}

func main() {
	serverMode := flag.Bool("server", false, "start server (automatic)")
	cpuprofile := flag.String("cpuprofile", "", "path to the file to write the cpu profile")
	flag.StringVar(&gLastDirPath, "last-dir-path", "", "path to the file to write the last dir on exit (to use for cd)")
	flag.StringVar(&gSelectionPath, "selection-path", "", "path to the file to write selected files on exit (to use as open file dialog)")

	flag.Parse()

	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			log.Fatal("could not create CPU profile: ", err)
		}
		if err := pprof.StartCPUProfile(f); err != nil {
			log.Fatal("could not start CPU profile: ", err)
		}
		defer pprof.StopCPUProfile()
	}

	if *serverMode {
		serve()
	} else {
		// TODO: check if the socket is working
		if _, err := os.Stat(gSocketPath); os.IsNotExist(err) {
			startServer()
		}

		client()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"
)

func shortUsage() {
	os.Stderr.WriteString(`
usage: vub [option(s)] <repository-uri>
try 'vub --help' for more information.
`[1:])
}

func usage() {
	os.Stderr.WriteString(`
usage: vub [option(s)] <repository-uri>
install Vim plugin to under the management of vim-unbundle.

repository-uri:
  sunaku/vim-unbundle                    # short URI
  https://github.com/sunaku/vim-unbundle # full URI

options:
  -f, --filetype=TYPE       installing under the ftbundle/TYPE
  -v, --verbose             display the process
  -h, --help                show this help message
`[1:])
}

func main() {
	filetype, verbose := "", false
	flag.StringVar(&filetype, "f", "", "")
	flag.StringVar(&filetype, "filetype", "", "")

	isHelp := false
	flag.BoolVar(&isHelp, "h", false, "")
	flag.BoolVar(&isHelp, "help", false, "")
	flag.Usage = usage
	flag.Parse()
	switch {
	case isHelp:
		usage()
		os.Exit(0)
	case flag.NArg() < 1:
		shortUsage()
		os.Exit(2)
	}
	uri := flag.Arg(0)

	p, err := NewPackage(uri, filetype)
	if err != nil {
		fmt.Fprintln(os.Stderr, "vub:", err)
		os.Exit(2)
	}
	p.Verbose(verbose)

	if err := p.Install(os.Stdout); err != nil {
		fmt.Fprintln(os.Stderr, "vub:", err)
		os.Exit(1)
	}
}
<commit_msg>Fix bug cannot use -v option<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
)

func shortUsage() {
	os.Stderr.WriteString(`
usage: vub [option(s)] <repository-uri>
try 'vub --help' for more information.
`[1:])
}

func usage() {
	os.Stderr.WriteString(`
usage: vub [option(s)] <repository-uri>
install Vim plugin to under the management of vim-unbundle.

repository-uri:
  sunaku/vim-unbundle                    # short URI
  https://github.com/sunaku/vim-unbundle # full URI

options:
  -f, --filetype=TYPE       installing under the ftbundle/TYPE
  -v, --verbose             display the process
  -h, --help                show this help message
`[1:])
}

func main() {
	filetype, verbose := "", false
	flag.StringVar(&filetype, "f", "", "")
	flag.StringVar(&filetype, "filetype", "", "")
	flag.BoolVar(&verbose, "v", false, "")
	flag.BoolVar(&verbose, "verbose", false, "")

	isHelp := false
	flag.BoolVar(&isHelp, "h", false, "")
	flag.BoolVar(&isHelp, "help", false, "")
	flag.Usage = usage
	flag.Parse()
	switch {
	case isHelp:
		usage()
		os.Exit(0)
	case flag.NArg() < 1:
		shortUsage()
		os.Exit(2)
	}
	uri := flag.Arg(0)

	p, err := NewPackage(uri, filetype)
	if err != nil {
		fmt.Fprintln(os.Stderr, "vub:", err)
		os.Exit(2)
	}
	p.Verbose(verbose)

	if err := p.Install(os.Stdout); err != nil {
		fmt.Fprintln(os.Stderr, "vub:", err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"math/rand"
	"time"
)

func main() {

	/*
		log.Print("started.")
		// チャネル
		sleep1_finished := make(chan bool)

		go func() {
			// 0.2秒かかるコマンド
			log.Print("sleep1 started.")
			time.Sleep(200 * 1000 * 1000 * time.Nanosecond)
			log.Print("sleep1 finished.")
			sleep1_finished <- true
		}()

		// 終わるまで待つ
		<- sleep1_finished
	*/

	// 136枚の中から14枚返したい
	list := shuffled_cards()

	// 出力
	// digit_output(list)
	solve(list)
	string_output(list)
}

// http://d.hatena.ne.jp/hake/20150930/p1
func shuffle(list []int) {
	for i := len(list); i > 1; i-- {
		j := rand.Intn(i) // 0　.. i-1 の乱数発生
		list[i-1], list[j] = list[j], list[i-1]
	}
}

func shuffled_cards() []int {
	rand.Seed(time.Now().UnixNano())

	// データ要素数指定、および初期データ作成
	size := 136
	list := make([]int, size, size)
	for i := 0; i < size; i++ {
		list[i] = i
	}

	// シャッフル
	shuffle(list)

	return list[:14]
}

// 単純出力
func digit_output(list []int) {
	for j := 0; j < 14; j++ {
		log.Println(list[j])
	}
}

// 牌の出力
func string_output(list []int) {
	// http://qiita.com/ruiu/items/2bb83b29baeae2433a79
	// サイズ0、内部バッファの長さ69の[]byteの値を割り当てる
	b := make([]byte, 0, 70)

	// bに文字列を追加
	for j := 0; j < 14; j++ {
		// 126976 is 'ton'
		// https://codepoints.net/U+1F000
		b = append(b, string(list[j]/4+126976)...) // ...が必要
		b = append(b, string(32)...)               // ...が必要
	}
	log.Print(string(b))
}

// solve
// 字マンソーピンのリストをつくる
func solve(list []int) {
	matrix := [][]int{{}, {}, {}, {}}
	for _, value := range list {
		group(matrix, value)
	}
	log.Println(matrix)
}

// スート分類してくれる
func group(m [][]int, j int) {
	// 4で割ると本来のインデックスに
	i := j / 4
	switch {
	case i < 7:
		m[0] = append(m[0], i)
		log.Println(i)
	case i < 7+(9*1):
		m[1] = append(m[1], i-7)
		log.Println(i)
	case i < 7+(9*2):
		m[2] = append(m[2], i-7-(9*1))
		log.Println(i)
	case i < 7+(9*3):
		m[3] = append(m[3], i-7-(9*2))
		log.Println(i)
	}
}
<commit_msg>Update<commit_after>package main

import (
	"log"
	"math/rand"
	"time"
)

func main() {
	aa := []int{101, 100, 70, 70, 60, 60, 50, 50, 40, 40, 30, 30, 20, 20}
	if is_chitoitsu(aa) {
		log.Println("a")
	} else {
		log.Println("b")
	}
	return

	/*
		log.Print("started.")
		// チャネル
		sleep1_finished := make(chan bool)

		go func() {
			// 0.2秒かかるコマンド
			log.Print("sleep1 started.")
			time.Sleep(200 * 1000 * 1000 * time.Nanosecond)
			log.Print("sleep1 finished.")
			sleep1_finished <- true
		}()

		// 終わるまで待つ
		<- sleep1_finished
	*/

	// 136枚の中から14枚返したい
	list := shuffled_cards()

	// 出力
	// digit_output(list)
	solve(list)
	string_output(list)
}

// http://d.hatena.ne.jp/hake/20150930/p1
func shuffle(list []int) {
	for i := len(list); i > 1; i-- {
		j := rand.Intn(i) // 0　.. i-1 の乱数発生
		list[i-1], list[j] = list[j], list[i-1]
	}
}

func shuffled_cards() []int {
	rand.Seed(time.Now().UnixNano())

	// データ要素数指定、および初期データ作成
	size := 136
	list := make([]int, size, size)
	for i := 0; i < size; i++ {
		list[i] = i
	}

	// シャッフル
	shuffle(list)

	return list[:14]
}

// 単純出力
func digit_output(list []int) {
	for j := 0; j < 14; j++ {
		log.Println(list[j])
	}
}

// 牌の出力
func string_output(list []int) {
	// http://qiita.com/ruiu/items/2bb83b29baeae2433a79
	// サイズ0、内部バッファの長さ69の[]byteの値を割り当てる
	b := make([]byte, 0, 70)

	// bに文字列を追加
	for j := 0; j < 14; j++ {
		// 126976 is 'ton'
		// https://codepoints.net/U+1F000
		b = append(b, string(list[j]/4+126976)...) // ...が必要
		b = append(b, string(32)...)               // ...が必要
	}
	log.Print(string(b))
}

// solve
// 字マンソーピンのリストをつくる
func solve(list []int) {
	matrix := [][]int{{}, {}, {}, {}}
	for _, value := range list {
		group(matrix, value)
	}
	log.Println(matrix)
}

// スート分類してくれる
func group(m [][]int, j int) {
	// 4で割ると本来のインデックスに
	i := j / 4
	switch {
	case i < 7:
		m[0] = append(m[0], i)
		log.Println(i)
	case i < 7+(9*1):
		m[1] = append(m[1], i-7)
		log.Println(i)
	case i < 7+(9*2):
		m[2] = append(m[2], i-7-(9*1))
		log.Println(i)
	case i < 7+(9*3):
		m[3] = append(m[3], i-7-(9*2))
		log.Println(i)
	}
}

func is_chitoitsu(list []int) bool {
	//カウンタ
	c := map[int]int{}

	//コピー
	l := list

	for _, v := range l {
		count, ok := c[v]
		if ok {
			if count == 1 {
				c[v] = 2
			} else {
				// c[v] == 2
				return false
			}
		} else {
			c[v] = 1
		}
		//8個チェック
		if len(c) >= 8 {
			return false
		}
	}
	return true
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	"github.com/fatih/images/command"
	"github.com/mitchellh/cli"
)

const (
	Version = "0.0.1"
	Name    = "images"
)

func main() {
	// Call realMain instead of doing the work here so we can use
	// `defer` statements within the function and have them work properly.
	// (defers aren't called with os.Exit)
	os.Exit(realMain())
}

func realMain() int {
	c := cli.NewCLI(Name, Version)
	c.Args = os.Args[1:]
	c.Commands = map[string]cli.CommandFactory{
		"list":   command.NewList,
		"modify": command.NewModify,
		"delete": func() (cli.Command, error) {
			return &cli.MockCommand{SynopsisText: "Delete images"}, nil
		},
		"copy": func() (cli.Command, error) {
			return &cli.MockCommand{SynopsisText: "Copy images to different region"}, nil
		},
	}

	exitCode, err := c.Run()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error executing CLI: %s\n", err)
		return 1
	}

	return exitCode
}
<commit_msg>main: return zero if no sub commands are passed<commit_after>package main

import (
	"fmt"
	"os"

	"github.com/fatih/images/command"
	"github.com/mitchellh/cli"
)

const (
	Version = "0.0.1"
	Name    = "images"
)

func main() {
	// Call realMain instead of doing the work here so we can use
	// `defer` statements within the function and have them work properly.
	// (defers aren't called with os.Exit)
	os.Exit(realMain())
}

func realMain() int {
	c := cli.NewCLI(Name, Version)
	c.Args = os.Args[1:]
	c.Commands = map[string]cli.CommandFactory{
		"list":   command.NewList,
		"modify": command.NewModify,
		"delete": func() (cli.Command, error) {
			return &cli.MockCommand{SynopsisText: "Delete images"}, nil
		},
		"copy": func() (cli.Command, error) {
			return &cli.MockCommand{SynopsisText: "Copy images to different region"}, nil
		},
	}

	_, err := c.Run()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error executing CLI: %s\n", err)
		return 1
	}

	return 0
}
<|endoftext|>


<commit_before>package main

import (
    "fmt"
    "os"
    "net/http"
    "io/ioutil"
    "errors"
    "github.com/codegangsta/cli"
)

func findRegion() (string, error) {
    resp, err := http.Get("http://169.254.169.254/latest/meta-data/placement/availability-zone/")
    if err != nil {
        return "", errors.New("Error reading region")
    }
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return "", errors.New("Error reading region")
    }
    bodyStr := string(body)
    return bodyStr[:len(bodyStr)-1], nil
}

func download(s3svc *S3Service, args []string) {
    from := args[0]
    bucket, key, err := ParseS3Spec(from)
    if err != nil {
        panic(err)
    }

    var to string
    if len(args) == 2 {
        to = args[1]
    } else {
        to = GetFileName(key)
    }
    s3svc.Get(&bucket, &key, &to)
}

func getRegion(c *cli.Context) string {
    region := c.GlobalString("region")
    if region == "" {
        awsRegion, err := findRegion()
        if err != nil {
            panic(err)
        }
        region = awsRegion
    }
    return region
}

func NewLsCommand() cli.Command {
    return cli.Command {
        Name:  "ls",
        Usage: "list <bucket>",
        Action: func(c *cli.Context) {
            if len(c.Args()) == 0 {
                cli.ShowAppHelp(c)
                os.Exit(1)
            }
            region := getRegion(c)
            debug := c.GlobalBool("debug")
            s3svc := NewS3Service(region, debug)
            bucket := c.Args().First()
            s3svc.List(&bucket)
        },
    }
}

func NewDlCommand() cli.Command {
    return cli.Command {
        Name:      "dl",
        Usage:     "<from> [<to>]\n   from/to: <s3://bucket/key>",
        Action: func(c *cli.Context) {
            fmt.Println("dl")
            fmt.Println(c.GlobalString("region"))

            region := getRegion(c)
            debug := c.GlobalBool("debug")
            s3svc := NewS3Service(region, debug)
            fmt.Println(c.Args())
            if len(c.Args()) == 0 {
                cli.ShowAppHelp(c)
                os.Exit(1)
            }

            download(s3svc, c.Args())
        },
    }
}

func main() {
    app := cli.NewApp()
    app.Name = "s3t"
    app.Usage = "Usage: %v [options] <command>\n"
    app.Action = func(c *cli.Context) {
        println("s3t -h for usage")
    }

    // global level flags
    app.Flags = []cli.Flag{
        cli.BoolFlag{
            Name:  "debug",
            Usage: "Show more output",
        },
        cli.StringFlag{
            Name:  "region",
            Usage: "aws region",
        },
    }

    // Commands
    app.Commands = []cli.Command{
        NewLsCommand(),
        NewDlCommand(),
    }

    app.Run(os.Args)
}
<commit_msg>Added version<commit_after>package main

import (
    "fmt"
    "os"
    "net/http"
    "io/ioutil"
    "errors"
    "github.com/codegangsta/cli"
)

func findRegion() (string, error) {
    resp, err := http.Get("http://169.254.169.254/latest/meta-data/placement/availability-zone/")
    if err != nil {
        return "", errors.New("Error reading region")
    }
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return "", errors.New("Error reading region")
    }
    bodyStr := string(body)
    return bodyStr[:len(bodyStr)-1], nil
}

func download(s3svc *S3Service, args []string) {
    from := args[0]
    bucket, key, err := ParseS3Spec(from)
    if err != nil {
        panic(err)
    }

    var to string
    if len(args) == 2 {
        to = args[1]
    } else {
        to = GetFileName(key)
    }
    s3svc.Get(&bucket, &key, &to)
}

func getRegion(c *cli.Context) string {
    region := c.GlobalString("region")
    if region == "" {
        awsRegion, err := findRegion()
        if err != nil {
            panic(err)
        }
        region = awsRegion
    }
    return region
}

func NewLsCommand() cli.Command {
    return cli.Command {
        Name:  "ls",
        Usage: "list <bucket>",
        Action: func(c *cli.Context) {
            if len(c.Args()) == 0 {
                cli.ShowAppHelp(c)
                os.Exit(1)
            }
            region := getRegion(c)
            debug := c.GlobalBool("debug")
            s3svc := NewS3Service(region, debug)
            bucket := c.Args().First()
            s3svc.List(&bucket)
        },
    }
}

func NewDlCommand() cli.Command {
    return cli.Command {
        Name:      "dl",
        Usage:     "<from> [<to>]\n   from/to: <s3://bucket/key>",
        Action: func(c *cli.Context) {
            fmt.Println("dl")
            fmt.Println(c.GlobalString("region"))

            region := getRegion(c)
            debug := c.GlobalBool("debug")
            s3svc := NewS3Service(region, debug)
            fmt.Println(c.Args())
            if len(c.Args()) == 0 {
                cli.ShowAppHelp(c)
                os.Exit(1)
            }

            download(s3svc, c.Args())
        },
    }
}

func main() {
    app := cli.NewApp()
    app.Name = "s3t"
    app.Usage = "Usage: %v [options] <command>\n"
    app.Action = func(c *cli.Context) {
        println("s3t -h for usage")
    }
    app.Version = "v0.0.1"

    // global level flags
    app.Flags = []cli.Flag{
        cli.BoolFlag{
            Name:  "debug",
            Usage: "Show more output",
        },
        cli.StringFlag{
            Name:  "region",
            Usage: "aws region",
        },
    }

    // Commands
    app.Commands = []cli.Command{
        NewLsCommand(),
        NewDlCommand(),
    }

    app.Run(os.Args)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"os"

	"github.com/ogier/pflag"
	"github.com/yuya-takeyama/argf"
)

var (
	name    = "ltsvp"
	version = "0.5.0"

	flagset         = pflag.NewFlagSet(name, pflag.ContinueOnError)
	list            = flagset.StringP("keys", "k", "", "")
	outputDelimiter = flagset.StringP("output-delimiter", "D", "\t", "")
	remainLTSV      = flagset.BoolP("remain-ltsv", "r", false, "")
	isHelp          = flagset.BoolP("help", "h", false, "")
	isVersion       = flagset.BoolP("version", "v", false, "")
)

func printUsage() {
	fmt.Fprintf(os.Stderr, `
Usage: %s OPTION... [FILE]...
Print selected parts of LTSV from each FILE to standard output.

Options:
  -k, --keys=LIST
                 select only these keys (required)
  -D, --output-delimiter=STRING
                 use STRING to separate parts (default: \t)
  -r, --remain-ltsv
                 print selected parts as LTSV
  -h, --help
                 display this help text and exit
  -v, --version
                 output version information and exit

LIST is made up of keys separated by commas.
  host           # Select host
  host,time,ua   # Select host, time, and ua
`[1:], name)
}

func printVersion() {
	fmt.Fprintln(os.Stderr, version)
}

func printErr(err interface{}) {
	fmt.Fprintf(os.Stderr, "%s: %s\n", name, err)
}

func guideToHelp() {
	fmt.Fprintf(os.Stderr, "Try '%s --help' for more information.\n", name)
}

func do(l *LTSVScanner) error {
	for l.Scan() {
		fmt.Println(l.Text())
	}
	return l.Err()
}

func main() {
	flagset.SetOutput(ioutil.Discard)
	if err := flagset.Parse(os.Args[1:]); err != nil {
		printErr(err)
		guideToHelp()
		os.Exit(2)
	}
	if *isHelp {
		printUsage()
		os.Exit(0)
	}
	if *isVersion {
		printVersion()
		os.Exit(0)
	}

	specifiedList := false
	flagset.Visit(func(f *pflag.Flag) {
		if f.Name == "keys" {
			specifiedList = true
		}
	})
	if !specifiedList {
		printErr("no specify LIST")
		guideToHelp()
		os.Exit(2)
	}
	keys := ParseKeysList(*list)

	r, err := argf.From(flagset.Args())
	if err != nil {
		printErr(err)
		guideToHelp()
		os.Exit(2)
	}

	l := NewLTSVScanner(keys, r)
	l.OutputDelimiter = *outputDelimiter
	l.RemainLTSV = *remainLTSV
	if err := do(l); err != nil {
		printErr(err)
		os.Exit(1)
	}
	os.Exit(0)
}
<commit_msg>s/&main.name/&main.cmdName/<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"os"

	"github.com/ogier/pflag"
	"github.com/yuya-takeyama/argf"
)

var (
	cmdName = "ltsvp"
	version = "0.5.0"

	flagset         = pflag.NewFlagSet(cmdName, pflag.ContinueOnError)
	list            = flagset.StringP("keys", "k", "", "")
	outputDelimiter = flagset.StringP("output-delimiter", "D", "\t", "")
	remainLTSV      = flagset.BoolP("remain-ltsv", "r", false, "")
	isHelp          = flagset.BoolP("help", "h", false, "")
	isVersion       = flagset.BoolP("version", "v", false, "")
)

func printUsage() {
	fmt.Fprintf(os.Stderr, `
Usage: %s OPTION... [FILE]...
Print selected parts of LTSV from each FILE to standard output.

Options:
  -k, --keys=LIST
                 select only these keys (required)
  -D, --output-delimiter=STRING
                 use STRING to separate parts (default: \t)
  -r, --remain-ltsv
                 print selected parts as LTSV
  -h, --help
                 display this help text and exit
  -v, --version
                 output version information and exit

LIST is made up of keys separated by commas.
  host           # Select host
  host,time,ua   # Select host, time, and ua
`[1:], cmdName)
}

func printVersion() {
	fmt.Fprintln(os.Stderr, version)
}

func printErr(err interface{}) {
	fmt.Fprintf(os.Stderr, "%s: %s\n", cmdName, err)
}

func guideToHelp() {
	fmt.Fprintf(os.Stderr, "Try '%s --help' for more information.\n", cmdName)
}

func do(l *LTSVScanner) error {
	for l.Scan() {
		fmt.Println(l.Text())
	}
	return l.Err()
}

func main() {
	flagset.SetOutput(ioutil.Discard)
	if err := flagset.Parse(os.Args[1:]); err != nil {
		printErr(err)
		guideToHelp()
		os.Exit(2)
	}
	if *isHelp {
		printUsage()
		os.Exit(0)
	}
	if *isVersion {
		printVersion()
		os.Exit(0)
	}

	specifiedList := false
	flagset.Visit(func(f *pflag.Flag) {
		if f.Name == "keys" {
			specifiedList = true
		}
	})
	if !specifiedList {
		printErr("no specify LIST")
		guideToHelp()
		os.Exit(2)
	}
	keys := ParseKeysList(*list)

	r, err := argf.From(flagset.Args())
	if err != nil {
		printErr(err)
		guideToHelp()
		os.Exit(2)
	}

	l := NewLTSVScanner(keys, r)
	l.OutputDelimiter = *outputDelimiter
	l.RemainLTSV = *remainLTSV
	if err := do(l); err != nil {
		printErr(err)
		os.Exit(1)
	}
	os.Exit(0)
}
<|endoftext|>


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

package main

import (
	"fmt"
	"log"
	"net/http"
	"os"

	"github.com/line/line-bot-sdk-go/linebot"
)

var bot *linebot.Client

func main() {
	var err error
	bot, err = linebot.New(os.Getenv("ChannelSecret"), os.Getenv("ChannelAccessToken"))
	log.Println("Bot:", bot, " err:", err)
	http.HandleFunc("/callback", callbackHandler)
	port := os.Getenv("PORT")
	addr := fmt.Sprintf(":%s", port)
	http.ListenAndServe(addr, nil)
}

func getSimsimi(word string){
	resp, err := http.Get("http://sandbox.api.simsimi.com/request.p?key=1b4f97fa-a422-45f0-8faf-0122ddd2dc5c&lc=id&ft=1.0&text=" + word)
	if err != nil{
		log.Print(err)
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	return string(body)
}

func callbackHandler(w http.ResponseWriter, r *http.Request) {
	events, err := bot.ParseRequest(r)

	if err != nil {
		if err == linebot.ErrInvalidSignature {
			w.WriteHeader(400)
		} else {
			w.WriteHeader(500)
		}
		return
	}

	for _, event := range events {
		if event.Type == linebot.EventTypeMessage {
			switch message := event.Message.(type) {
			case *linebot.TextMessage:
				if _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(message.ID+":"+message.Text+" -> "+getSimsimi(message.Text))).Do(); err != nil {
					log.Print(err)
				}
			}
		}
	}
}
<commit_msg>I am n00b<commit_after>// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"io/ioutil"

	"github.com/line/line-bot-sdk-go/linebot"
)

var bot *linebot.Client

func main() {
	var err error
	bot, err = linebot.New(os.Getenv("ChannelSecret"), os.Getenv("ChannelAccessToken"))
	log.Println("Bot:", bot, " err:", err)
	http.HandleFunc("/callback", callbackHandler)
	port := os.Getenv("PORT")
	addr := fmt.Sprintf(":%s", port)
	http.ListenAndServe(addr, nil)
}

func getSimsimi(word string) string{
	resp, err := http.Get("http://sandbox.api.simsimi.com/request.p?key=1b4f97fa-a422-45f0-8faf-0122ddd2dc5c&lc=id&ft=1.0&text=" + word)
	if err != nil{
		log.Print(err)
	}
	defer resp.Body.Close()
	return string(resp.Body)
}

func callbackHandler(w http.ResponseWriter, r *http.Request) {
	events, err := bot.ParseRequest(r)

	if err != nil {
		if err == linebot.ErrInvalidSignature {
			w.WriteHeader(400)
		} else {
			w.WriteHeader(500)
		}
		return
	}

	for _, event := range events {
		if event.Type == linebot.EventTypeMessage {
			switch message := event.Message.(type) {
			case *linebot.TextMessage:
				if _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(message.ID+":"+message.Text+" -> "+getSimsimi(message.Text))).Do(); err != nil {
					log.Print(err)
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"flag"
	"fmt"
	"os"
	"os/exec"

	"github.com/google/go-github/github"
	"golang.org/x/oauth2"
)

type config struct {
	owner  string
	repo   string
	sshUrl string
	token  string
}

func main() {
	cfg := new(config)

	flag.StringVar(&cfg.owner, "owner", "", "GitHub owner")
	flag.StringVar(&cfg.repo, "repo", "", "GitHub repo")
	flag.StringVar(&cfg.token, "token", "", "GitHub token")

	flag.Parse()

	if cfg.owner == "" {
		fmt.Println("Missing GitHub owner")
		os.Exit(-1)
	}

	if cfg.repo == "" {
		fmt.Println("Missing GitHub repo")
		os.Exit(-1)
	}

	if cfg.token == "" {
		fmt.Println("Missing GitHub token")
		os.Exit(-1)
	}

	cfg.sshUrl = fmt.Sprintf("git@github.com:%v/%v.git", cfg.owner, cfg.repo)

	ctx := context.Background()
	sts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: cfg.token})
	client := github.NewClient(oauth2.NewClient(ctx, sts))

	forks, _, err := client.Repositories.ListForks(ctx, cfg.owner, cfg.repo, nil)
	if err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}

	cmd := exec.Command("git", "clone", cfg.sshUrl)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err = cmd.Run()
	if err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}

	for _, fork := range forks {
		fmt.Println(*fork.SSHURL)
	}
}
<commit_msg>Setup forks<commit_after>package main

import (
	"context"
	"flag"
	"fmt"
	"os"
	"os/exec"

	"github.com/google/go-github/github"
	"golang.org/x/oauth2"
)

type config struct {
	owner  string
	repo   string
	sshUrl string
	token  string
}

func main() {
	cfg := new(config)

	flag.StringVar(&cfg.owner, "owner", "", "GitHub owner")
	flag.StringVar(&cfg.repo, "repo", "", "GitHub repo")
	flag.StringVar(&cfg.token, "token", "", "GitHub token")

	flag.Parse()

	if cfg.owner == "" {
		fmt.Println("Missing GitHub owner")
		os.Exit(-1)
	}

	if cfg.repo == "" {
		fmt.Println("Missing GitHub repo")
		os.Exit(-1)
	}

	if cfg.token == "" {
		fmt.Println("Missing GitHub token")
		os.Exit(-1)
	}

	cfg.sshUrl = fmt.Sprintf("git@github.com:%v/%v.git", cfg.owner, cfg.repo)

	ctx := context.Background()
	sts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: cfg.token})
	client := github.NewClient(oauth2.NewClient(ctx, sts))

	forks, _, err := client.Repositories.ListForks(ctx, cfg.owner, cfg.repo, nil)
	if err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}

	cmd := exec.Command("git", "clone", cfg.sshUrl)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err = cmd.Run()
	if err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}

	cmd = exec.Command("git", "-C", cfg.repo, "remote", "rename", "origin", "upstream")
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err = cmd.Run()
	if err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}

	for _, fork := range forks {
		cmd = exec.Command("git", "-C", cfg.repo, "remote", "add", *fork.Owner.Login, *fork.SSHURL)
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
		err = cmd.Run()
		if err != nil {
			fmt.Println(err)
			os.Exit(-1)
		}
	}
}
<|endoftext|>


<commit_before>/*
The MIT License (MIT)

transfer.sh was originally written by and
Copyright (c) 2014 DutchCoders [https://github.com/dutchcoders/]

Some modifications
Copyright (c) 2015 John Ko

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

package main

import (
	"flag"
	"fmt"
	"github.com/PuerkitoBio/ghost/handlers"
	"github.com/gorilla/mux"
	"log"
	"math/rand"
	"net/http"
	"os"
	"time"
)

const SERVER_INFO = "dtfc"
const SERVER_VERSION = "0.0.1"

// we use these commands to reduce the amount of garbage collection golang needs to do
const cmdSHASUMFreeBSD = "/usr/local/bin/shasum"

// or on Apple using Macports
const cmdSHASUMApple = "/opt/local/bin/shasum"
const cmdSHA512 = "/sbin/sha512"
const cmdTAIL = "/usr/bin/tail"

const timeLayout = "2006-01-02 15:04:05 MST"
const timeHTTPLayout = "Mon, 2 Jan 2006 15:04:05 MST"

// parse request with maximum memory of _24Kilobits
const _24K = (1 << 20) * 24

var config struct {
	ALLOWDELETE string
	ALLOWGET    string
	ALLOWPUT    string
	Temp        string
	ME          string
	PEERS       []string
}

var storage Storage

var cmdSHASUM string

func init() {
	config.Temp = os.TempDir()
}

func main() {
	rand.Seed(time.Now().UTC().UnixNano())

	var err error
	if _, err = os.Lstat(cmdSHASUMFreeBSD); err == nil {
		cmdSHASUM = cmdSHASUMFreeBSD
	}
	if _, err = os.Lstat(cmdSHASUMApple); err == nil {
		cmdSHASUM = cmdSHASUMApple
	}
	if _, err = os.Lstat(cmdSHASUM); err != nil {
		log.Panic("Error while looking for shasum executable.")
	}
	if _, err = os.Lstat(cmdTAIL); err != nil {
		log.Panic("Error while looking for tail executable.")
	}

	port := flag.String("port", "8080", "port number, default: 8080")
	temp := flag.String("temp", config.Temp, "")
	basedir := flag.String("basedir", "", "")
	logpath := flag.String("log", "", "")
	provider := flag.String("provider", "local", "")
	allowdelete := flag.String("allowdelete", "true", "true or false, default: true")
	allowget := flag.String("allowget", "true", "true or false, default: true")
	allowput := flag.String("allowput", "true", "true or false, default: true")
	me := flag.String("me", "", "example http://127.0.0.1:8080/")
	melist := flag.String("melist", "", "text file with first line as me")
	peerlist := flag.String("peerlist", "", "text file with one peer per line")

	flag.Parse()

	if *logpath != "" {
		f, err := os.OpenFile(*logpath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
		if err != nil {
			log.Fatalf("Error opening file: %v", err)
		}
		defer f.Close()
		log.SetOutput(f)
	}

	config.Temp = *temp
	config.ALLOWDELETE = *allowdelete
	config.ALLOWGET = *allowget
	config.ALLOWPUT = *allowput
	// usually string empty test is == ""
	// the following test can be nil because *string can be nil
	if me != nil {
		config.ME = *me
	}
	if (config.ME == "") && (melist != nil) {
		var arraystring []string
		arraystring, err = readLines(*melist)
		if err != nil {
			log.Panic("Error while reading melist.", err)
		} else {
			config.ME = arraystring[0]
		}
	}
	if strings.Trim(config.ME, " ") == "" {
		log.Panic("Error while trying to figure out me.")
	}
	log.Printf("config.ME: %s", config.ME)
	config.PEERS, err = readLines(*peerlist)
	if err != nil {
		log.Panic("Error while reading peerlist.", err)
	}

	r := mux.NewRouter()

	r.HandleFunc("/health.html", healthHandler).Methods("GET")
	r.HandleFunc("/{hash}", getHandler).Methods("GET")

	//r.HandleFunc("/{hash}", headHandler).Methods("HEAD")

	r.HandleFunc("/{filename}", putHandler).Methods("PUT")

	r.NotFoundHandler = http.HandlerFunc(notFoundHandler)

	switch *provider {
	case "local":
		if *basedir == "" {
			log.Panic("Error basedir not set.")
		}
		storage, err = NewLocalStorage(*basedir)
	}
	if err != nil {
		log.Panic("Error while creating storage.", err)
	}

	log.Printf("%s/%s server started. listening on port: %v",
		SERVER_INFO, SERVER_VERSION, *port)
	log.Printf("using temp folder: %s, using storage provider: %s",
		config.Temp, *provider)
	log.Printf("allow delete: %s, allow get: %s, allow put: %s",
		config.ALLOWDELETE, config.ALLOWGET, config.ALLOWPUT)
	log.Printf("---------------------------")

	s := &http.Server{
		Addr:    fmt.Sprintf(":%s", *port),
		Handler: handlers.PanicHandler(RedirectHandler(handlers.LogHandler(r, handlers.NewLogOptions(log.Printf, "_default_"))), nil),
	}

	log.Panic(s.ListenAndServe())
	log.Printf("Server stopped.")
}
<commit_msg>needs to import strings<commit_after>/*
The MIT License (MIT)

transfer.sh was originally written by and
Copyright (c) 2014 DutchCoders [https://github.com/dutchcoders/]

Some modifications
Copyright (c) 2015 John Ko

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

package main

import (
	"flag"
	"fmt"
	"github.com/PuerkitoBio/ghost/handlers"
	"github.com/gorilla/mux"
	"log"
	"math/rand"
	"net/http"
	"os"
	"strings"
	"time"
)

const SERVER_INFO = "dtfc"
const SERVER_VERSION = "0.0.1"

// we use these commands to reduce the amount of garbage collection golang needs to do
const cmdSHASUMFreeBSD = "/usr/local/bin/shasum"

// or on Apple using Macports
const cmdSHASUMApple = "/opt/local/bin/shasum"
const cmdSHA512 = "/sbin/sha512"
const cmdTAIL = "/usr/bin/tail"

const timeLayout = "2006-01-02 15:04:05 MST"
const timeHTTPLayout = "Mon, 2 Jan 2006 15:04:05 MST"

// parse request with maximum memory of _24Kilobits
const _24K = (1 << 20) * 24

var config struct {
	ALLOWDELETE string
	ALLOWGET    string
	ALLOWPUT    string
	Temp        string
	ME          string
	PEERS       []string
}

var storage Storage

var cmdSHASUM string

func init() {
	config.Temp = os.TempDir()
}

func main() {
	rand.Seed(time.Now().UTC().UnixNano())

	var err error
	if _, err = os.Lstat(cmdSHASUMFreeBSD); err == nil {
		cmdSHASUM = cmdSHASUMFreeBSD
	}
	if _, err = os.Lstat(cmdSHASUMApple); err == nil {
		cmdSHASUM = cmdSHASUMApple
	}
	if _, err = os.Lstat(cmdSHASUM); err != nil {
		log.Panic("Error while looking for shasum executable.")
	}
	if _, err = os.Lstat(cmdTAIL); err != nil {
		log.Panic("Error while looking for tail executable.")
	}

	port := flag.String("port", "8080", "port number, default: 8080")
	temp := flag.String("temp", config.Temp, "")
	basedir := flag.String("basedir", "", "")
	logpath := flag.String("log", "", "")
	provider := flag.String("provider", "local", "")
	allowdelete := flag.String("allowdelete", "true", "true or false, default: true")
	allowget := flag.String("allowget", "true", "true or false, default: true")
	allowput := flag.String("allowput", "true", "true or false, default: true")
	me := flag.String("me", "", "example http://127.0.0.1:8080/")
	melist := flag.String("melist", "", "text file with first line as me")
	peerlist := flag.String("peerlist", "", "text file with one peer per line")

	flag.Parse()

	if *logpath != "" {
		f, err := os.OpenFile(*logpath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
		if err != nil {
			log.Fatalf("Error opening file: %v", err)
		}
		defer f.Close()
		log.SetOutput(f)
	}

	config.Temp = *temp
	config.ALLOWDELETE = *allowdelete
	config.ALLOWGET = *allowget
	config.ALLOWPUT = *allowput
	// usually string empty test is == ""
	// the following test can be nil because *string can be nil
	if me != nil {
		config.ME = *me
	}
	if (config.ME == "") && (melist != nil) {
		var arraystring []string
		arraystring, err = readLines(*melist)
		if err != nil {
			log.Panic("Error while reading melist.", err)
		} else {
			config.ME = arraystring[0]
		}
	}
	if strings.Trim(config.ME, " ") == "" {
		log.Panic("Error while trying to figure out me.")
	}
	log.Printf("config.ME: %s", config.ME)
	config.PEERS, err = readLines(*peerlist)
	if err != nil {
		log.Panic("Error while reading peerlist.", err)
	}

	r := mux.NewRouter()

	r.HandleFunc("/health.html", healthHandler).Methods("GET")
	r.HandleFunc("/{hash}", getHandler).Methods("GET")

	//r.HandleFunc("/{hash}", headHandler).Methods("HEAD")

	r.HandleFunc("/{filename}", putHandler).Methods("PUT")

	r.NotFoundHandler = http.HandlerFunc(notFoundHandler)

	switch *provider {
	case "local":
		if *basedir == "" {
			log.Panic("Error basedir not set.")
		}
		storage, err = NewLocalStorage(*basedir)
	}
	if err != nil {
		log.Panic("Error while creating storage.", err)
	}

	log.Printf("%s/%s server started. listening on port: %v",
		SERVER_INFO, SERVER_VERSION, *port)
	log.Printf("using temp folder: %s, using storage provider: %s",
		config.Temp, *provider)
	log.Printf("allow delete: %s, allow get: %s, allow put: %s",
		config.ALLOWDELETE, config.ALLOWGET, config.ALLOWPUT)
	log.Printf("---------------------------")

	s := &http.Server{
		Addr:    fmt.Sprintf(":%s", *port),
		Handler: handlers.PanicHandler(RedirectHandler(handlers.LogHandler(r, handlers.NewLogOptions(log.Printf, "_default_"))), nil),
	}

	log.Panic(s.ListenAndServe())
	log.Printf("Server stopped.")
}
<|endoftext|>


<commit_before>package main

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

type Instructions struct {
	Instruction []Instruction `instructions`
}

type Instruction struct {
	CurrentState string `current-state`
	SymbolR      string `symbol-read`
	SymbolW      string `symbol-write`
	Head         string `head`
	NextState    string `next-state`
}

type TuringTape struct {
	Tape     []string // ****11010101****
	Position int
	State    string
}

func (i Instruction) String() string {
	return fmt.Sprintf("%s %s -> %s %s %s", i.CurrentState, i.SymbolR, i.SymbolW, i.Head, i.NextState)
}

func (t TuringTape) String() string {
	return fmt.Sprintf("Position: %d State: %s\nTape: %s", t.Position, t.State, t.Tape)
}

func parseInstructions(path string) ([]Instruction, error) {
	var instructions Instructions
	source, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, fmt.Errorf("Reading file %s: %v", path, err)
	}
	err = yaml.Unmarshal(source, &instructions)
	if err != nil {
		return nil, fmt.Errorf("Unmarshalling YAML %s: %v", path, err)
	}
	return instructions.Instruction, nil
}

func moveAndWrite(instructions []Instruction, t TuringTape, symbol string) (int, string) {
	for _, ins := range instructions {
		if ins.CurrentState == t.State && ins.SymbolR == symbol {
			fmt.Println("Symbol: ", symbol)
			fmt.Println("Instruction: ", ins)
			t.Tape[t.Position] = ins.SymbolW
			fmt.Println("Wrote: ", ins.SymbolW)
			t.State = ins.NextState
			switch ins.Head {
			case "R":
				t.Position++
				fmt.Println(t.Tape)
				break
			case "L":
				t.Position--
				fmt.Println(t.Tape)
				break
			case "N":
				fmt.Println(t.Tape)
				break
			}
		}
	}
	return t.Position, t.State
}

func compute(instructions []Instruction, t TuringTape) TuringTape {
	var symbol, state string
	var pos int
	for {
		if t.State == "F" {
			return t
		}
		fmt.Println("-----------------------------------------------")
		fmt.Printf("State: %s\nPosition: %d\n", t.State, t.Position)
		symbol = t.Tape[t.Position]
		switch symbol {
		case "0":
			pos, state = moveAndWrite(instructions, t, symbol)
			break
		case "1":
			pos, state = moveAndWrite(instructions, t, symbol)
			break
		case "*":
			pos, state = moveAndWrite(instructions, t, symbol)
			break
		}
		t.Position = pos
		t.State = state
	}
	return t
}

func main() {
	args := os.Args[1:]
	if len(args) < 2 {
		fmt.Println("Please give a file and tape content: ./turing-go [filepath] [tape]")
		os.Exit(1)
	}
	path := args[0]
	tape_raw := args[1]
	var tape_array []string
	for i := 0; i < len(tape_raw); i++ {
		tape_array = append(tape_array, string(tape_raw[i]))
	}
	tape := TuringTape{Tape: tape_array, Position: 4, State: "A"} // position 4, because of 4 leading *
	instructions, err := parseInstructions(path)
	if err != nil {
		panic(err)
	}
	set := compute(instructions, tape)
	fmt.Println("-----------------------------------------------")
	fmt.Println("Finished: ", set)
}
<commit_msg>fixed cli args<commit_after>package main

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

type Instructions struct {
	Instruction []Instruction `instructions`
}

type Instruction struct {
	CurrentState string `current-state`
	SymbolR      string `symbol-read`
	SymbolW      string `symbol-write`
	Head         string `head`
	NextState    string `next-state`
}

type TuringTape struct {
	Tape     []string // ****11010101****
	Position int
	State    string
}

func (i Instruction) String() string {
	return fmt.Sprintf("%s %s -> %s %s %s", i.CurrentState, i.SymbolR, i.SymbolW, i.Head, i.NextState)
}

func (t TuringTape) String() string {
	return fmt.Sprintf("Position: %d State: %s\nTape: %s", t.Position, t.State, t.Tape)
}

func parseInstructions(path string) ([]Instruction, error) {
	var instructions Instructions
	source, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, fmt.Errorf("Reading file %s: %v", path, err)
	}
	err = yaml.Unmarshal(source, &instructions)
	if err != nil {
		return nil, fmt.Errorf("Unmarshalling YAML %s: %v", path, err)
	}
	return instructions.Instruction, nil
}

func moveAndWrite(instructions []Instruction, t TuringTape, symbol string) (int, string) {
	for _, ins := range instructions {
		if ins.CurrentState == t.State && ins.SymbolR == symbol {
			fmt.Println("Symbol: ", symbol)
			fmt.Println("Instruction: ", ins)
			t.Tape[t.Position] = ins.SymbolW
			fmt.Println("Wrote: ", ins.SymbolW)
			t.State = ins.NextState
			switch ins.Head {
			case "R":
				t.Position++
				fmt.Println(t.Tape)
				break
			case "L":
				t.Position--
				fmt.Println(t.Tape)
				break
			case "N":
				fmt.Println(t.Tape)
				break
			}
		}
	}
	return t.Position, t.State
}

func compute(instructions []Instruction, t TuringTape) TuringTape {
	var symbol, state string
	var pos int
	for {
		if t.State == "F" {
			return t
		}
		fmt.Println("-----------------------------------------------")
		fmt.Printf("State: %s\nPosition: %d\n", t.State, t.Position)
		symbol = t.Tape[t.Position]
		switch symbol {
		case "0":
			pos, state = moveAndWrite(instructions, t, symbol)
			break
		case "1":
			pos, state = moveAndWrite(instructions, t, symbol)
			break
		case "*":
			pos, state = moveAndWrite(instructions, t, symbol)
			break
		}
		t.Position = pos
		t.State = state
	}
	return t
}

func main() {
	args := os.Args[1:]
	if len(args) != 2 {
		fmt.Println("Please give a file and tape content: ./turing-go [filepath] [tape]")
		os.Exit(1)
	}
	path := args[0]
	tape_raw := args[1]
	var tape_array []string
	for i := 0; i < len(tape_raw); i++ {
		tape_array = append(tape_array, string(tape_raw[i]))
	}
	tape := TuringTape{Tape: tape_array, Position: 4, State: "A"} // position 4, because of 4 leading *
	instructions, err := parseInstructions(path)
	if err != nil {
		panic(err)
	}
	set := compute(instructions, tape)
	fmt.Println("-----------------------------------------------")
	fmt.Println("Finished: ", set)
}
<|endoftext|>


<commit_before>package main

import "io"
import "fmt"
import "net"
import "net/http"
import "log"
import "os"
import "os/exec"
import "flag"
import "strings"
import "strconv"

import "github.com/gorilla/websocket"
import "github.com/kr/pty"
import "github.com/creack/goterm/win"

func start() (*os.File, *exec.Cmd) {
	var err error

	cmdString := "/bin/bash"
	cmd := exec.Command(cmdString)
	ptym, err := pty.Start(cmd)
	if err != nil {
		fmt.Println("Failed to start command: ", err)
	}

	return ptym, cmd
}

func stop(ptym *os.File, cmd *exec.Cmd, conn *websocket.Conn) {
	ptym.Close()
	conn.Close()
	cmd.Wait()
}

// Read from the websocket, copying to the pty master.
func handleInput(ptym *os.File, conn *websocket.Conn) {
	for {
		mt, payload, err := conn.ReadMessage()
		if err != nil {
			if err != io.EOF {
				fmt.Println("conn.ReadMessage failed: ", err)
				return
			}
		}

		if mt == -1 {
			// The client has likely disconnected.
			return
		}

		switch mt {
		case websocket.BinaryMessage:
			ptym.Write(payload)
		default:
			fmt.Println("Invalid message type: ", mt)
			return
		}
	}
}

// Copy everything from the pty master to the websocket.
func handleOutput(ptym *os.File, conn *websocket.Conn) {
	buf := make([]byte, 512)
	// TODO: more graceful exit on socket close / process exit
	for {
		n, err := ptym.Read(buf)
		if err != nil {
			fmt.Println("Failed to read from pty master: ", err)
			return
		}

		err = conn.WriteMessage(websocket.BinaryMessage, buf[0:n])

		if err != nil {
			fmt.Println("Failed to send %d bytes on websocket: %s", n, err)
			return
		}
	}
}

func setPtySize(ptym *os.File, size string) {
	sizeArr := strings.Split(size, "x")
	lines, _ := strconv.Atoi(sizeArr[0])
	cols, _ := strconv.Atoi(sizeArr[1])
	if err := win.SetWinsize(ptym.Fd(), &win.Winsize{Height: uint16(lines), Width: uint16(cols)}); err != nil {
		panic(err)
	}
}

func ptyHandler(w http.ResponseWriter, r *http.Request, sizeFlag string) {
	var upgrader = websocket.Upgrader{
		ReadBufferSize:  1,
		WriteBufferSize: 1,
		CheckOrigin: func(r *http.Request) bool {
			return true
		},
	}

	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		fmt.Println("Websocket upgrade failed: ", err)
	}

	ptym, cmd := start()
	setPtySize(ptym, sizeFlag)

	go func() {
		handleOutput(ptym, conn)
	}()

	go func() {
		handleInput(ptym, conn)
	}()

	// Listen for a new winsize on stdin.
	for {
		var newSize string
		_, scanErr := fmt.Scanln(&newSize)
		if scanErr != nil {
			fmt.Println("scan failed: ", scanErr)
		}

		setPtySize(ptym, newSize)
		fmt.Println("new size: ", newSize)
	}

	stop(ptym, cmd, conn)
}

func main() {
	addrFlag := flag.String("addr", ":0", "IP:PORT or :PORT address to listen on")
	sizeFlag := flag.String("size", "24x80", "initial size for the tty")

	flag.Parse()

	http.HandleFunc("/pty", func(w http.ResponseWriter, r *http.Request) {
		fmt.Println("client connected.")
		ptyHandler(w, r, *sizeFlag)
	})

	listener, err := net.Listen("tcp", *addrFlag)
	if err != nil {
		log.Fatal("listen: %s", err)
	}

	fmt.Println("now listening on: " + listener.Addr().String())

	err = http.Serve(listener, nil)
	if err != nil {
		fmt.Println("net.http could not listen on address '%s': %s", addrFlag, err)
	}
}
<commit_msg>Added valid utf-8 check for outgoing payloads<commit_after>package main

import "io"
import "fmt"
import "net"
import "net/http"
import "log"
import "os"
import "os/exec"
import "flag"
import "strings"
import "strconv"
import "unicode/utf8"

import "github.com/gorilla/websocket"
import "github.com/kr/pty"
import "github.com/creack/goterm/win"

func start() (*os.File, *exec.Cmd) {
	var err error

	cmdString := "/bin/bash"
	cmd := exec.Command(cmdString)
	ptym, err := pty.Start(cmd)
	if err != nil {
		fmt.Println("Failed to start command: ", err)
	}

	return ptym, cmd
}

func stop(ptym *os.File, cmd *exec.Cmd, conn *websocket.Conn) {
	ptym.Close()
	conn.Close()
	cmd.Wait()
}

// Read from the websocket, copying to the pty master.
func handleInput(ptym *os.File, conn *websocket.Conn) {
	for {
		mt, payload, err := conn.ReadMessage()
		if err != nil {
			if err != io.EOF {
				fmt.Println("conn.ReadMessage failed: ", err)
				return
			}
		}

		if mt == -1 {
			// The client has likely disconnected.
			return
		}

		switch mt {
		case websocket.BinaryMessage:
			ptym.Write(payload)
		default:
			fmt.Println("Invalid message type: ", mt)
			return
		}
	}
}

// Copy everything from the pty master to the websocket.
func handleOutput(ptym *os.File, conn *websocket.Conn) {
	buf := make([]byte, 512)
	var payload, overflow []byte
	// TODO: more graceful exit on socket close / process exit.
	for {
		n, err := ptym.Read(buf)
		if err != nil {
			fmt.Println("Failed to read from pty master: ", err)
			return
		}

		// Empty the overflow from the last read into the payload first.
		payload = append(payload[0:], overflow...)
		overflow = nil
		// Then empty the new buf read into the payload.
		payload = append(payload, buf[:n]...)

		// Strip out any incomplete utf-8 from current payload into overflow.
		for !utf8.Valid(payload) {
			overflow = append(overflow, payload[len(payload) - 1:len(payload)]...)
			payload = payload[:len(payload) - 1]
		}

		// Send out the finished payload.
		err = conn.WriteMessage(websocket.BinaryMessage, payload[:len(payload)])
		if err != nil {
			fmt.Println("Failed to send bytes on websocket: ", err)
			return
		}

		// Empty the payload.
		payload = nil
	}
}

func setPtySize(ptym *os.File, size string) {
	sizeArr := strings.Split(size, "x")
	lines, _ := strconv.Atoi(sizeArr[0])
	cols, _ := strconv.Atoi(sizeArr[1])
	if err := win.SetWinsize(ptym.Fd(), &win.Winsize{Height: uint16(lines), Width: uint16(cols)}); err != nil {
		panic(err)
	}
}

func ptyHandler(w http.ResponseWriter, r *http.Request, sizeFlag string) {
	var upgrader = websocket.Upgrader{
		ReadBufferSize:  1,
		WriteBufferSize: 1,
		CheckOrigin: func(r *http.Request) bool {
			return true
		},
	}

	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		fmt.Println("Websocket upgrade failed: ", err)
	}

	ptym, cmd := start()
	setPtySize(ptym, sizeFlag)

	go func() {
		handleOutput(ptym, conn)
	}()

	go func() {
		handleInput(ptym, conn)
	}()

	// Listen for a new winsize on stdin.
	for {
		var newSize string
		_, scanErr := fmt.Scanln(&newSize)
		if scanErr != nil {
			fmt.Println("scan failed: ", scanErr)
		}

		setPtySize(ptym, newSize)
		fmt.Println("new size: ", newSize)
	}

	stop(ptym, cmd, conn)
}

func main() {
	addrFlag := flag.String("addr", ":0", "IP:PORT or :PORT address to listen on")
	sizeFlag := flag.String("size", "24x80", "initial size for the tty")

	flag.Parse()

	http.HandleFunc("/pty", func(w http.ResponseWriter, r *http.Request) {
		fmt.Println("client connected.")
		ptyHandler(w, r, *sizeFlag)
	})

	listener, err := net.Listen("tcp", *addrFlag)
	if err != nil {
		log.Fatal("listen: %s", err)
	}

	fmt.Println("now listening on: " + listener.Addr().String())

	err = http.Serve(listener, nil)
	if err != nil {
		fmt.Println("net.http could not listen on address '%s': %s", addrFlag, err)
	}
}
<|endoftext|>