<commit_before>package ole

import (
	"errors"
	"fmt"
	"time"

	"github.com/go-ole/go-ole"
	"github.com/go-ole/go-ole/oleutil"
	"github.com/yuin/gopher-lua"
)

type Lua = *lua.LState

var initializedRequired = true

type capsuleT struct {
	Data *ole.IDispatch
}

type methodT struct {
	Name string
	Data *ole.IDispatch
}

func (c capsuleT) ToLValue(L Lua) lua.LValue {
	ud := L.NewUserData()
	ud.Value = &c
	meta := L.NewTable()
	L.SetField(meta, "__gc", L.NewFunction(gc))
	L.SetField(meta, "__index", L.NewFunction(index))
	L.SetField(meta, "__newindex", L.NewFunction(set))
	L.SetMetatable(ud, meta)
	return ud
}

func gc(L Lua) int {
	ud := L.ToUserData(1)
	p, ok := ud.Value.(*capsuleT)
	if !ok {
		return lerror(L, "gc: not capsult_t instance")
	}
	if p.Data != nil {
		p.Data.Release()
		p.Data = nil
	}
	return 0
}

func lua2interface(L Lua, index int) (interface{}, error) {
	valueTmp := L.Get(index)
	if valueTmp == lua.LNil {
		return nil, nil
	} else if valueTmp == lua.LTrue {
		return true, nil
	} else if valueTmp == lua.LFalse {
		return false, nil
	}
	switch value := valueTmp.(type) {
	default:
		return nil, errors.New("lua2interface: not support type")
	case lua.LString:
		return string(value), nil
	case lua.LNumber:
		return float64(value), nil
	case *lua.LUserData:
		c, ok := value.Value.(*capsuleT)
		if !ok {
			return nil, errors.New("lua2interface: not a OBJECT")
		}
		return c.Data, nil
	}
}

func lua2interfaceS(L Lua, start, end int) ([]interface{}, error) {
	result := make([]interface{}, end-start+1)
	for i := start; i <= end; i++ {
		val, err := lua2interface(L, i)
		if err != nil {
			return nil, err
		}
		result[i-start] = val
	}
	return result, nil
}

// this:_call("METHODNAME",params...)
func call1(L Lua) int {
	ud, ok := L.Get(1).(*lua.LUserData)
	if !ok { // OBJECT_T
		return lerror(L, "call1: not found object")
	}
	p, ok := ud.Value.(*capsuleT)
	if !ok {
		return lerror(L, "call1: not found capsuleT")
	}
	name, ok := L.Get(2).(lua.LString)
	if !ok {
		return lerror(L, "call1: not found methodname")
	}
	return callCommon(L, p.Data, string(name))
}

// this:METHODNAME(params...)
func call2(L Lua) int {
	ud, ok := L.Get(1).(*lua.LUserData)
	if !ok {
		return lerror(L, "call2: not found userdata for methodT")
	}
	method, ok := ud.Value.(*methodT)
	if !ok || method.Name == "" {
		return lerror(L, "call2: not found methodT")
	}
	ud, ok = L.Get(2).(*lua.LUserData)
	if !ok {
		return lerror(L, "call2: not found userdata for object_t")
	}
	obj, ok := ud.Value.(*capsuleT)
	if !ok {
		if method.Data == nil {
			return lerror(L, "call2: receiver is not found")
		}
		return callCommon(L, method.Data, method.Name)
		// this code enables `OLEOBJ.PROPERTY.PROPERTY:METHOD()`
	}
	if obj.Data == nil {
		return lerror(L, "call2: OLEOBJECT(): the receiver is null")
	}
	return callCommon(L, obj.Data, method.Name)
}

func callCommon(L Lua, com1 *ole.IDispatch, name string) int {
	count := L.GetTop()
	params, err := lua2interfaceS(L, 3, count)
	if err != nil {
		return lerror(L, fmt.Sprintf("callCommon: %s", err.Error()))
	}
	result, err := com1.CallMethod(name, params...)
	if err != nil {
		return lerror(L, fmt.Sprintf("oleutil.CallMethod(%s): %s", name, err.Error()))
	}
	L.Push(variantToLValue(L, result))
	return 1
}

func set(L Lua) int {
	ud, ok := L.Get(1).(*lua.LUserData)
	if !ok {
		return lerror(L, "set: the 1st argument is not usedata")
	}
	p, ok := ud.Value.(*capsuleT)
	if !ok {
		return lerror(L, "set: the 1st argument is not *capsuleT")
	}
	name, ok := L.Get(2).(lua.LString)
	if !ok {
		return lerror(L, "set: the 2nd argument is not string")
	}
	key, err := lua2interfaceS(L, 3, L.GetTop())
	if err != nil {
		return lerror(L, fmt.Sprintf("set: %s", err.Error()))
	}
	p.Data.PutProperty(string(name), key...)
	L.Push(lua.LTrue)
	L.Push(lua.LNil)
	return 2
}

func get(L Lua) int {
	ud, ok := L.Get(1).(*lua.LUserData)
	if !ok {
		return lerror(L, "get: 1st argument is not a userdata.")
	}
	p, ok := ud.Value.(*capsuleT)
	if !ok {
		return lerror(L, "get: 1st argument is not *capsuleT")
	}

	name, ok := L.Get(2).(lua.LString)
	if !ok {
		return lerror(L, "get: 2nd argument is not string")
	}

	key, err := lua2interfaceS(L, 3, L.GetTop())
	if err != nil {
		return lerror(L, fmt.Sprintf("get: %s", err.Error()))
	}
	result, err := p.Data.GetProperty(string(name), key...)
	if err != nil {
		return lerror(L, fmt.Sprintf("oleutil.GetProperty: %s", err.Error()))
	}
	L.Push(variantToLValue(L, result))
	return 1
}

func indexSub(L Lua, thisIndex int, nameIndex int) int {
	name, ok := L.Get(nameIndex).(lua.LString)
	if !ok {
		return lerror(L, "indexSub: not a string")
	}
	switch string(name) {
	case "_call":
		L.Push(L.NewFunction(call1))
		L.Push(lua.LNil)
		return 2
	case "_set":
		L.Push(L.NewFunction(set))
		L.Push(lua.LNil)
		return 2
	case "_get":
		L.Push(L.NewFunction(get))
		L.Push(lua.LNil)
		return 2
	default:
		m := &methodT{Name: string(name)}
		if ud, ok := L.Get(thisIndex).(*lua.LUserData); ok {
			if p, ok := ud.Value.(*capsuleT); ok {
				m.Data = p.Data
			}
		}
		ud := L.NewUserData()
		ud.Value = m

		meta := L.NewTable()
		L.SetField(meta, "__newindex", L.NewFunction(set))
		L.SetField(meta, "__call", L.NewFunction(call2))
		L.SetField(meta, "__index", L.NewFunction(get2))
		L.SetMetatable(ud, meta)
		L.Push(ud)

		return 1
	}
}

func index(L Lua) int {
	return indexSub(L, 1, 2)
}

// THIS.member.member
func get2(L Lua) int {
	ud, ok := L.Get(1).(*lua.LUserData)
	if !ok {
		return lerror(L, "get2: not a userdata")
	}
	m, ok := ud.Value.(*methodT)
	if !ok {
		return lerror(L, "get: not a methodT")
	}
	result, err := m.Data.GetProperty(m.Name)
	if err != nil {
		return lerror(L, fmt.Sprintf("oleutil.GetProperty: %s", err.Error()))
	}
	L.Push(variantToLValue(L, result))
	return indexSub(L, 3, 2)
}

// CreateObject creates Lua-Object to access COM
func CreateObject(L Lua) int {
	if initializedRequired {
		ole.CoInitialize(0)
		initializedRequired = false
	}
	name, ok := L.Get(1).(lua.LString)
	if !ok {
		return lerror(L, "CreateObject: parameter not a string")
	}
	unknown, err := oleutil.CreateObject(string(name))
	if err != nil {
		return lerror(L, fmt.Sprintf("oleutil.CreateObject: %s", err.Error()))
	}
	obj, err := unknown.QueryInterface(ole.IID_IDispatch)
	if err != nil {
		return lerror(L, fmt.Sprintf("unknown.QueryInterfce: %s", err.Error()))
	}
	L.Push(capsuleT{obj}.ToLValue(L))
	return 1
}

func lerror(L Lua, s string) int {
	L.Push(lua.LNil)
	L.Push(lua.LString(s))
	return 2
}

func variantToLValue(L Lua, v *ole.VARIANT) lua.LValue {
	switch v.VT {
	case ole.VT_I1:
		return lua.LNumber(v.Value().(int))
	case ole.VT_UI1:
		return lua.LNumber(v.Value().(uint8))
	case ole.VT_I2:
		return lua.LNumber(v.Value().(int16))
	case ole.VT_UI2:
		return lua.LNumber(v.Value().(uint16))
	case ole.VT_I4:
		return lua.LNumber(v.Value().(int32))
	case ole.VT_UI4:
		return lua.LNumber(v.Value().(uint32))
	case ole.VT_I8:
		return lua.LNumber(v.Value().(int64))
	case ole.VT_UI8:
		return lua.LNumber(v.Value().(uint64))
	case ole.VT_INT:
		return lua.LNumber(v.Value().(int))
	case ole.VT_UINT:
		return lua.LNumber(v.Value().(uint))
	case ole.VT_INT_PTR:
		return lua.LNumber(v.Value().(uintptr))
	case ole.VT_UINT_PTR:
		return lua.LNumber(v.Value().(uintptr))
	case ole.VT_R4:
		return lua.LNumber(v.Value().(float32))
	case ole.VT_R8:
		return lua.LNumber(v.Value().(float64))
	case ole.VT_BSTR:
		return lua.LString(v.ToString())
	case ole.VT_DATE:
		if date, ok := v.Value().(time.Time); ok {
			t := L.NewTable()
			L.SetField(t, "year", lua.LNumber(date.Year()))
			L.SetField(t, "month", lua.LNumber(int(date.Month())))
			L.SetField(t, "day", lua.LNumber(date.Day()))
			L.SetField(t, "hour", lua.LNumber(date.Hour()))
			L.SetField(t, "min", lua.LNumber(date.Minute()))
			L.SetField(t, "sec", lua.LNumber(date.Second()))
			return t
		} else if floatValue, ok := v.Value().(float64); ok {
			return lua.LNumber(floatValue)
		} else {
			panic("can not convert ole.VT_DATE")
		}
	case ole.VT_UNKNOWN:
		panic("can not convert ole.VT_UNKNOW")
	case ole.VT_DISPATCH:
		return capsuleT{v.ToIDispatch()}.ToLValue(L)
	case ole.VT_BOOL:
		if v.Value().(bool) {
			return lua.LTrue
		} else {
			return lua.LFalse
		}
	default:
		return lua.LNil
	}
}
<commit_msg>Implemented "glua-ole".ToOleInteger<commit_after>package ole

import (
	"errors"
	"fmt"
	"time"

	"github.com/go-ole/go-ole"
	"github.com/go-ole/go-ole/oleutil"
	"github.com/yuin/gopher-lua"
)

type Lua = *lua.LState

var initializedRequired = true

type capsuleT struct {
	Data *ole.IDispatch
}

type methodT struct {
	Name string
	Data *ole.IDispatch
}

func (c capsuleT) ToLValue(L Lua) lua.LValue {
	ud := L.NewUserData()
	ud.Value = &c
	meta := L.NewTable()
	L.SetField(meta, "__gc", L.NewFunction(gc))
	L.SetField(meta, "__index", L.NewFunction(index))
	L.SetField(meta, "__newindex", L.NewFunction(set))
	L.SetMetatable(ud, meta)
	return ud
}

func gc(L Lua) int {
	ud := L.ToUserData(1)
	p, ok := ud.Value.(*capsuleT)
	if !ok {
		return lerror(L, "gc: not capsult_t instance")
	}
	if p.Data != nil {
		p.Data.Release()
		p.Data = nil
	}
	return 0
}

func lua2interface(L Lua, index int) (interface{}, error) {
	valueTmp := L.Get(index)
	if valueTmp == lua.LNil {
		return nil, nil
	} else if valueTmp == lua.LTrue {
		return true, nil
	} else if valueTmp == lua.LFalse {
		return false, nil
	}
	switch value := valueTmp.(type) {
	default:
		return nil, errors.New("lua2interface: not support type")
	case lua.LString:
		return string(value), nil
	case lua.LNumber:
		return float64(value), nil
	case *lua.LUserData:
		if v, ok := value.Value.(int); ok {
			return int(v), nil
		}
		if c, ok := value.Value.(*capsuleT); ok {
			return c.Data, nil
		}
		return nil, errors.New("lua2interface: not a OBJECT")
	}
}

func lua2interfaceS(L Lua, start, end int) ([]interface{}, error) {
	result := make([]interface{}, end-start+1)
	for i := start; i <= end; i++ {
		val, err := lua2interface(L, i)
		if err != nil {
			return nil, err
		}
		result[i-start] = val
	}
	return result, nil
}

// this:_call("METHODNAME",params...)
func call1(L Lua) int {
	ud, ok := L.Get(1).(*lua.LUserData)
	if !ok { // OBJECT_T
		return lerror(L, "call1: not found object")
	}
	p, ok := ud.Value.(*capsuleT)
	if !ok {
		return lerror(L, "call1: not found capsuleT")
	}
	name, ok := L.Get(2).(lua.LString)
	if !ok {
		return lerror(L, "call1: not found methodname")
	}
	return callCommon(L, p.Data, string(name))
}

// this:METHODNAME(params...)
func call2(L Lua) int {
	ud, ok := L.Get(1).(*lua.LUserData)
	if !ok {
		return lerror(L, "call2: not found userdata for methodT")
	}
	method, ok := ud.Value.(*methodT)
	if !ok || method.Name == "" {
		return lerror(L, "call2: not found methodT")
	}
	ud, ok = L.Get(2).(*lua.LUserData)
	if !ok {
		return lerror(L, "call2: not found userdata for object_t")
	}
	obj, ok := ud.Value.(*capsuleT)
	if !ok {
		if method.Data == nil {
			return lerror(L, "call2: receiver is not found")
		}
		return callCommon(L, method.Data, method.Name)
		// this code enables `OLEOBJ.PROPERTY.PROPERTY:METHOD()`
	}
	if obj.Data == nil {
		return lerror(L, "call2: OLEOBJECT(): the receiver is null")
	}
	return callCommon(L, obj.Data, method.Name)
}

func callCommon(L Lua, com1 *ole.IDispatch, name string) int {
	count := L.GetTop()
	params, err := lua2interfaceS(L, 3, count)
	if err != nil {
		return lerror(L, fmt.Sprintf("callCommon: %s", err.Error()))
	}
	result, err := com1.CallMethod(name, params...)
	if err != nil {
		return lerror(L, fmt.Sprintf("oleutil.CallMethod(%s): %s", name, err.Error()))
	}
	L.Push(variantToLValue(L, result))
	return 1
}

func set(L Lua) int {
	ud, ok := L.Get(1).(*lua.LUserData)
	if !ok {
		return lerror(L, "set: the 1st argument is not usedata")
	}
	p, ok := ud.Value.(*capsuleT)
	if !ok {
		return lerror(L, "set: the 1st argument is not *capsuleT")
	}
	name, ok := L.Get(2).(lua.LString)
	if !ok {
		return lerror(L, "set: the 2nd argument is not string")
	}
	key, err := lua2interfaceS(L, 3, L.GetTop())
	if err != nil {
		return lerror(L, fmt.Sprintf("set: %s", err.Error()))
	}
	p.Data.PutProperty(string(name), key...)
	L.Push(lua.LTrue)
	L.Push(lua.LNil)
	return 2
}

func get(L Lua) int {
	ud, ok := L.Get(1).(*lua.LUserData)
	if !ok {
		return lerror(L, "get: 1st argument is not a userdata.")
	}
	p, ok := ud.Value.(*capsuleT)
	if !ok {
		return lerror(L, "get: 1st argument is not *capsuleT")
	}

	name, ok := L.Get(2).(lua.LString)
	if !ok {
		return lerror(L, "get: 2nd argument is not string")
	}

	key, err := lua2interfaceS(L, 3, L.GetTop())
	if err != nil {
		return lerror(L, fmt.Sprintf("get: %s", err.Error()))
	}
	result, err := p.Data.GetProperty(string(name), key...)
	if err != nil {
		return lerror(L, fmt.Sprintf("oleutil.GetProperty: %s", err.Error()))
	}
	L.Push(variantToLValue(L, result))
	return 1
}

func indexSub(L Lua, thisIndex int, nameIndex int) int {
	name, ok := L.Get(nameIndex).(lua.LString)
	if !ok {
		return lerror(L, "indexSub: not a string")
	}
	switch string(name) {
	case "_call":
		L.Push(L.NewFunction(call1))
		L.Push(lua.LNil)
		return 2
	case "_set":
		L.Push(L.NewFunction(set))
		L.Push(lua.LNil)
		return 2
	case "_get":
		L.Push(L.NewFunction(get))
		L.Push(lua.LNil)
		return 2
	default:
		m := &methodT{Name: string(name)}
		if ud, ok := L.Get(thisIndex).(*lua.LUserData); ok {
			if p, ok := ud.Value.(*capsuleT); ok {
				m.Data = p.Data
			}
		}
		ud := L.NewUserData()
		ud.Value = m

		meta := L.NewTable()
		L.SetField(meta, "__newindex", L.NewFunction(set))
		L.SetField(meta, "__call", L.NewFunction(call2))
		L.SetField(meta, "__index", L.NewFunction(get2))
		L.SetMetatable(ud, meta)
		L.Push(ud)

		return 1
	}
}

func index(L Lua) int {
	return indexSub(L, 1, 2)
}

// THIS.member.member
func get2(L Lua) int {
	ud, ok := L.Get(1).(*lua.LUserData)
	if !ok {
		return lerror(L, "get2: not a userdata")
	}
	m, ok := ud.Value.(*methodT)
	if !ok {
		return lerror(L, "get: not a methodT")
	}
	result, err := m.Data.GetProperty(m.Name)
	if err != nil {
		return lerror(L, fmt.Sprintf("oleutil.GetProperty: %s", err.Error()))
	}
	L.Push(variantToLValue(L, result))
	return indexSub(L, 3, 2)
}

// CreateObject creates Lua-Object to access COM
func CreateObject(L Lua) int {
	if initializedRequired {
		ole.CoInitialize(0)
		initializedRequired = false
	}
	name, ok := L.Get(1).(lua.LString)
	if !ok {
		return lerror(L, "CreateObject: parameter not a string")
	}
	unknown, err := oleutil.CreateObject(string(name))
	if err != nil {
		return lerror(L, fmt.Sprintf("oleutil.CreateObject: %s", err.Error()))
	}
	obj, err := unknown.QueryInterface(ole.IID_IDispatch)
	if err != nil {
		return lerror(L, fmt.Sprintf("unknown.QueryInterfce: %s", err.Error()))
	}
	L.Push(capsuleT{obj}.ToLValue(L))
	return 1
}

// ToOleInteger converts LNumber to integer which can be used by OLE parameter only.
func ToOleInteger(L Lua) int {
	var value int
	if v, ok := L.Get(-1).(lua.LNumber); ok {
		value = int(v)
	}
	ud := L.NewUserData()
	ud.Value = value
	L.Push(ud)
	return 1
}

func lerror(L Lua, s string) int {
	L.Push(lua.LNil)
	L.Push(lua.LString(s))
	return 2
}

func variantToLValue(L Lua, v *ole.VARIANT) lua.LValue {
	switch v.VT {
	case ole.VT_I1:
		return lua.LNumber(v.Value().(int))
	case ole.VT_UI1:
		return lua.LNumber(v.Value().(uint8))
	case ole.VT_I2:
		return lua.LNumber(v.Value().(int16))
	case ole.VT_UI2:
		return lua.LNumber(v.Value().(uint16))
	case ole.VT_I4:
		return lua.LNumber(v.Value().(int32))
	case ole.VT_UI4:
		return lua.LNumber(v.Value().(uint32))
	case ole.VT_I8:
		return lua.LNumber(v.Value().(int64))
	case ole.VT_UI8:
		return lua.LNumber(v.Value().(uint64))
	case ole.VT_INT:
		return lua.LNumber(v.Value().(int))
	case ole.VT_UINT:
		return lua.LNumber(v.Value().(uint))
	case ole.VT_INT_PTR:
		return lua.LNumber(v.Value().(uintptr))
	case ole.VT_UINT_PTR:
		return lua.LNumber(v.Value().(uintptr))
	case ole.VT_R4:
		return lua.LNumber(v.Value().(float32))
	case ole.VT_R8:
		return lua.LNumber(v.Value().(float64))
	case ole.VT_BSTR:
		return lua.LString(v.ToString())
	case ole.VT_DATE:
		if date, ok := v.Value().(time.Time); ok {
			t := L.NewTable()
			L.SetField(t, "year", lua.LNumber(date.Year()))
			L.SetField(t, "month", lua.LNumber(int(date.Month())))
			L.SetField(t, "day", lua.LNumber(date.Day()))
			L.SetField(t, "hour", lua.LNumber(date.Hour()))
			L.SetField(t, "min", lua.LNumber(date.Minute()))
			L.SetField(t, "sec", lua.LNumber(date.Second()))
			return t
		} else if floatValue, ok := v.Value().(float64); ok {
			return lua.LNumber(floatValue)
		} else {
			panic("can not convert ole.VT_DATE")
		}
	case ole.VT_UNKNOWN:
		panic("can not convert ole.VT_UNKNOW")
	case ole.VT_DISPATCH:
		return capsuleT{v.ToIDispatch()}.ToLValue(L)
	case ole.VT_BOOL:
		if v.Value().(bool) {
			return lua.LTrue
		} else {
			return lua.LFalse
		}
	default:
		return lua.LNil
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/base64"
	"encoding/json"
	"flag"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/zenazn/goji"
	"github.com/zenazn/goji/web"
)

const fifo string = "omxcontrol"

var commands *strings.Replacer = strings.NewReplacer(
	"play", "p",
	"pause", "p",
	"subs", "m",
	"quit", "q",
	"forward", "\x5b\x43",
)

var videosPath string

type Page struct {
	Title string
}

type Video struct {
	File string `json:"file"`
	Hash string `json:"hash"`
}

func home(c web.C, w http.ResponseWriter, r *http.Request) {
	p := &Page{Title: "gomxremote"}
	tmpl, err := FSString(false, "/views/index.html")
	if err != nil {
		fmt.Println(err.Error())
	}

	t, _ := template.New("index").Parse(tmpl)
	t.Execute(w, p)
}

func videoFiles(c web.C, w http.ResponseWriter, r *http.Request) {
	var files []*Video
	var root = videosPath
	_ = filepath.Walk(root, func(path string, f os.FileInfo, _ error) error {
		if f.IsDir() == false {
			if filepath.Ext(path) == ".mkv" || filepath.Ext(path) == ".mp4" || filepath.Ext(path) == ".avi" {
				files = append(files, &Video{File: filepath.Base(path), Hash: base64.StdEncoding.EncodeToString([]byte(path))})
			}
		}
		return nil
	})
	encoder := json.NewEncoder(w)
	encoder.Encode(files)
}

func startVideo(c web.C, w http.ResponseWriter, r *http.Request) {
	filename, _ := base64.StdEncoding.DecodeString(c.URLParams["name"])
	string_filename := string(filename[:])
	escapePathReplacer := strings.NewReplacer(
		"[", "\\[",
		"]", "\\]",
		"(", "\\(",
		")", "\\)",
		"'", "\\'",
		" ", "\\ ",
		"*", "\\*",
		"?", "\\?",
	)
	escapedPath := escapePathReplacer.Replace(string_filename)

	fifo_cmd := exec.Command("mkfifo", fifo)
	fifo_cmd.Run()

	cmd := exec.Command("bash", "-c", "omxplayer -o hdmi "+escapedPath+" < "+fifo)
	err := cmd.Start()
	if err != nil {
		log.Fatal(err)
	}

	startErr := exec.Command("bash", "-c", "echo . > "+fifo).Run()
	if startErr != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	err = cmd.Wait()

	fmt.Fprintf(w, "%s", string_filename)
}

func togglePlayVideo(c web.C, w http.ResponseWriter, r *http.Request) {

	err := sendCommand("play")
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	fmt.Fprintf(w, "1")
}

func stopVideo(c web.C, w http.ResponseWriter, r *http.Request) {

	err := sendCommand("quit")
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	os.Remove(fifo)

	fmt.Fprintf(w, "1")
}

func toggleSubsVideo(c web.C, w http.ResponseWriter, r *http.Request) {

	err := sendCommand("subs")
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	fmt.Fprintf(w, "1")
}

func forwardVideo(c web.C, w http.ResponseWriter, r *http.Request) {

	err := sendCommand("forward")
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	fmt.Fprintf(w, "1")
}

func backwardVideo(c web.C, w http.ResponseWriter, r *http.Request) {

	err := sendCommand("backward")
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	fmt.Fprintf(w, "1")
}

func sendCommand(command string) error {
	commandString := "echo -n " + commands.Replace(command) + " > " + fifo
	cmd := exec.Command("bash", "-c", commandString)
	err := cmd.Run()
	return err
}

func main() {

	flag.StringVar(&videosPath, "media", ".", "path to look for videos in")

	goji.Get("/", home)
	goji.Get("/files", videoFiles)

	goji.Post("/file/:name/start", startVideo)
	goji.Post("/file/:name/play", togglePlayVideo)
	goji.Post("/file/:name/pause", togglePlayVideo)
	goji.Post("/file/:name/stop", stopVideo)
	goji.Post("/file/:name/subs", toggleSubsVideo)
	goji.Post("/file/:name/forward", forwardVideo)
	goji.Post("/file/:name/backward", backwardVideo)

	goji.Handle("/assets/*", http.FileServer(FS(false)))

	goji.Serve()
}
<commit_msg>move commands replacer into sendCommand<commit_after>package main

import (
	"encoding/base64"
	"encoding/json"
	"flag"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/zenazn/goji"
	"github.com/zenazn/goji/web"
)

const fifo string = "omxcontrol"

var videosPath string

type Page struct {
	Title string
}

type Video struct {
	File string `json:"file"`
	Hash string `json:"hash"`
}

func home(c web.C, w http.ResponseWriter, r *http.Request) {
	p := &Page{Title: "gomxremote"}
	tmpl, err := FSString(false, "/views/index.html")
	if err != nil {
		fmt.Println(err.Error())
	}

	t, _ := template.New("index").Parse(tmpl)
	t.Execute(w, p)
}

func videoFiles(c web.C, w http.ResponseWriter, r *http.Request) {
	var files []*Video
	var root = videosPath
	_ = filepath.Walk(root, func(path string, f os.FileInfo, _ error) error {
		if f.IsDir() == false {
			if filepath.Ext(path) == ".mkv" || filepath.Ext(path) == ".mp4" || filepath.Ext(path) == ".avi" {
				files = append(files, &Video{File: filepath.Base(path), Hash: base64.StdEncoding.EncodeToString([]byte(path))})
			}
		}
		return nil
	})
	encoder := json.NewEncoder(w)
	encoder.Encode(files)
}

func startVideo(c web.C, w http.ResponseWriter, r *http.Request) {
	filename, _ := base64.StdEncoding.DecodeString(c.URLParams["name"])
	string_filename := string(filename[:])
	escapePathReplacer := strings.NewReplacer(
		"[", "\\[",
		"]", "\\]",
		"(", "\\(",
		")", "\\)",
		"'", "\\'",
		" ", "\\ ",
		"*", "\\*",
		"?", "\\?",
	)
	escapedPath := escapePathReplacer.Replace(string_filename)

	fifo_cmd := exec.Command("mkfifo", fifo)
	fifo_cmd.Run()

	cmd := exec.Command("bash", "-c", "omxplayer -o hdmi "+escapedPath+" < "+fifo)
	err := cmd.Start()
	if err != nil {
		log.Fatal(err)
	}

	startErr := exec.Command("bash", "-c", "echo . > "+fifo).Run()
	if startErr != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	err = cmd.Wait()

	fmt.Fprintf(w, "%s", string_filename)
}

func togglePlayVideo(c web.C, w http.ResponseWriter, r *http.Request) {

	err := sendCommand("play")
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	fmt.Fprintf(w, "1")
}

func stopVideo(c web.C, w http.ResponseWriter, r *http.Request) {

	err := sendCommand("quit")
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	os.Remove(fifo)

	fmt.Fprintf(w, "1")
}

func toggleSubsVideo(c web.C, w http.ResponseWriter, r *http.Request) {

	err := sendCommand("subs")
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	fmt.Fprintf(w, "1")
}

func forwardVideo(c web.C, w http.ResponseWriter, r *http.Request) {

	err := sendCommand("forward")
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	fmt.Fprintf(w, "1")
}

func backwardVideo(c web.C, w http.ResponseWriter, r *http.Request) {

	err := sendCommand("backward")
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	fmt.Fprintf(w, "1")
}

func sendCommand(command string) error {
	commands := strings.NewReplacer(
		"play", "p",
		"pause", "p",
		"subs", "m",
		"quit", "q",
		"forward", "\x5b\x43",
		"backward", "\x5b\x44",
	)

	commandString := "echo -n " + commands.Replace(command) + " > " + fifo
	cmd := exec.Command("bash", "-c", commandString)
	err := cmd.Run()
	return err
}

func main() {

	flag.StringVar(&videosPath, "media", ".", "path to look for videos in")

	goji.Get("/", home)
	goji.Get("/files", videoFiles)

	goji.Post("/file/:name/start", startVideo)
	goji.Post("/file/:name/play", togglePlayVideo)
	goji.Post("/file/:name/pause", togglePlayVideo)
	goji.Post("/file/:name/stop", stopVideo)
	goji.Post("/file/:name/subs", toggleSubsVideo)
	goji.Post("/file/:name/forward", forwardVideo)
	goji.Post("/file/:name/backward", backwardVideo)

	goji.Handle("/assets/*", http.FileServer(FS(false)))

	goji.Serve()
}
<|endoftext|>


<commit_before>// Package gohinetradio is to get hichannel radio path and with token to play without flash.
package gohinetradio

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"runtime"
	"sort"
	"strconv"
	"sync"
	"text/tabwriter"
)

var nCPU = runtime.NumCPU()

// Init.
func init() {
	runtime.GOMAXPROCS(nCPU)
}

// Base URL.
const (
	PLAYURL  string = "http://hichannel.hinet.net/radio/play.do?id=%s"
	LISTURL  string = "http://hichannel.hinet.net/radio/channelList.do?radioType=&freqType=&freq=&area=&pN=%d"
	LISTPAGE int    = 4
)

// RadioData is the json of `http://hichannel.hinet.net/radio/play.do?id=232`
type RadioData struct {
	ChannelTitle   string `json:"channel_title"`
	PlayRadio      string `json:"playRadio"`
	ProgramName    string `json:"programName"`
	ChannelCollect bool   `json:"channel_collect"`
}

// GetURL is getting radio channel url with token.
func GetURL(No string) (RadioData, error) {
	resp, _ := http.Get(fmt.Sprintf(PLAYURL, No))
	defer resp.Body.Close()
	var r RadioData
	var err error
	data, _ := ioutil.ReadAll(resp.Body)
	jsonData := json.NewDecoder(bytes.NewReader(data))
	jsonData.Decode(&r)
	if len(r.PlayRadio) == 0 {
		err = errors.New("No channel data.")
	}
	return r, err
}

// RadioListData is the json of `http://hichannel.hinet.net/radio/channelList.do?radioType=&freqType=&freq=&area=&pN=1`
type RadioListData struct {
	PageNo   int              `json:"pageNo"`
	PageSize int              `json:"pageSize"`
	List     []RadioListDatas `json:"list"`
}

//RadioListDatas is RadioListData.List type.
type RadioListDatas struct {
	ChannelImage string `json:"channel_image"`
	ChannelTitle string `json:"channel_title"`
	RadioType    string `json:"radio_type"`
	IsChannel    bool   `json:"isChannel"`
	ProgramName  string `json:"program_name"`
	ChannelID    string `json:"channel_id"`
}

func getRadioPageList(page int) RadioListData {
	resp, _ := http.Get(fmt.Sprintf(LISTURL, page))
	defer resp.Body.Close()
	var r RadioListData
	data, _ := ioutil.ReadAll(resp.Body)
	jsonData := json.NewDecoder(bytes.NewReader(data))
	jsonData.Decode(&r)
	return r
}

// GetRadioList is getting all channel list.
func GetRadioList() []RadioListDatas {
	queue := make(chan RadioListData, nCPU)
	var wg sync.WaitGroup
	wg.Add(LISTPAGE)
	for i := 1; i <= LISTPAGE; i++ {
		go func(i int) {
			runtime.Gosched()
			queue <- getRadioPageList(i)
		}(i)
	}
	var r []RadioListDatas
	go func() {
		for v := range queue {
			for _, data := range v.List {
				r = append(r, data)
			}
			wg.Done()
		}
	}()
	wg.Wait()
	close(queue)
	return r
}

type byChannel []RadioListDatas

func (c byChannel) Len() int      { return len(c) }
func (c byChannel) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c byChannel) Less(i, j int) bool {
	a, _ := strconv.Atoi(c[i].ChannelID)
	b, _ := strconv.Atoi(c[j].ChannelID)
	return a < b
}

// GenList is to output table list.
func GenList() {
	w := new(tabwriter.Writer)
	w.Init(os.Stdout, 0, 8, 0, '\t', 0)
	var output string
	var no int
	radioList := GetRadioList()
	sort.Sort(byChannel(radioList))
	for _, data := range radioList {
		if data.IsChannel {
			output += fmt.Sprintf("%d. [%v] %s\t", no+1, data.ChannelID, data.ChannelTitle)
			if (no+1)%3 == 0 {
				fmt.Fprintln(w, output)
				output = ""
			}
			no++
		}
	}
	fmt.Fprintln(w, output)
	w.Flush()
}

// PrintChannel is my fav channel XD.
func PrintChannel() {
	fmt.Println("[207] 中廣新聞網")
	fmt.Println("[205] 中廣流行網 i like")
	fmt.Println("[206] 中廣音樂網i radio")
	fmt.Println("[232] 飛碟電台")
	fmt.Println("[222] HitFm聯播網 Taipei 北部")
	fmt.Println("[156] KISS RADIO 大眾廣播電台")
	fmt.Println("[308] KISS RADIO 網路音樂台")
	fmt.Println("[187] NEWS98新聞網")
	fmt.Println("[370] POP Radio 台北流行廣播電台")
}
<commit_msg>Using defer.<commit_after>// Package gohinetradio is to get hichannel radio path and with token to play without flash.
package gohinetradio

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"runtime"
	"sort"
	"strconv"
	"sync"
	"text/tabwriter"
)

var nCPU = runtime.NumCPU()

// Init.
func init() {
	runtime.GOMAXPROCS(nCPU)
}

// Base URL.
const (
	PLAYURL  string = "http://hichannel.hinet.net/radio/play.do?id=%s"
	LISTURL  string = "http://hichannel.hinet.net/radio/channelList.do?radioType=&freqType=&freq=&area=&pN=%d"
	LISTPAGE int    = 4
)

// RadioData is the json of `http://hichannel.hinet.net/radio/play.do?id=232`
type RadioData struct {
	ChannelTitle   string `json:"channel_title"`
	PlayRadio      string `json:"playRadio"`
	ProgramName    string `json:"programName"`
	ChannelCollect bool   `json:"channel_collect"`
}

// GetURL is getting radio channel url with token.
func GetURL(No string) (RadioData, error) {
	resp, _ := http.Get(fmt.Sprintf(PLAYURL, No))
	defer resp.Body.Close()
	var r RadioData
	var err error
	data, _ := ioutil.ReadAll(resp.Body)
	jsonData := json.NewDecoder(bytes.NewReader(data))
	jsonData.Decode(&r)
	if len(r.PlayRadio) == 0 {
		err = errors.New("No channel data.")
	}
	return r, err
}

// RadioListData is the json of `http://hichannel.hinet.net/radio/channelList.do?radioType=&freqType=&freq=&area=&pN=1`
type RadioListData struct {
	PageNo   int              `json:"pageNo"`
	PageSize int              `json:"pageSize"`
	List     []RadioListDatas `json:"list"`
}

//RadioListDatas is RadioListData.List type.
type RadioListDatas struct {
	ChannelImage string `json:"channel_image"`
	ChannelTitle string `json:"channel_title"`
	RadioType    string `json:"radio_type"`
	IsChannel    bool   `json:"isChannel"`
	ProgramName  string `json:"program_name"`
	ChannelID    string `json:"channel_id"`
}

func getRadioPageList(page int) RadioListData {
	resp, _ := http.Get(fmt.Sprintf(LISTURL, page))
	defer resp.Body.Close()
	var r RadioListData
	data, _ := ioutil.ReadAll(resp.Body)
	jsonData := json.NewDecoder(bytes.NewReader(data))
	jsonData.Decode(&r)
	return r
}

// GetRadioList is getting all channel list.
func GetRadioList() []RadioListDatas {
	queue := make(chan RadioListData, nCPU)
	defer close(queue)

	var wg sync.WaitGroup
	wg.Add(LISTPAGE)
	for i := 1; i <= LISTPAGE; i++ {
		go func(i int) {
			runtime.Gosched()
			queue <- getRadioPageList(i)
		}(i)
	}
	var r []RadioListDatas
	go func() {
		for v := range queue {
			for _, data := range v.List {
				r = append(r, data)
			}
			wg.Done()
		}
	}()
	wg.Wait()
	return r
}

type byChannel []RadioListDatas

func (c byChannel) Len() int      { return len(c) }
func (c byChannel) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c byChannel) Less(i, j int) bool {
	a, _ := strconv.Atoi(c[i].ChannelID)
	b, _ := strconv.Atoi(c[j].ChannelID)
	return a < b
}

// GenList is to output table list.
func GenList() {
	w := new(tabwriter.Writer)
	w.Init(os.Stdout, 0, 8, 0, '\t', 0)
	var output string
	var no int
	radioList := GetRadioList()
	sort.Sort(byChannel(radioList))
	for _, data := range radioList {
		if data.IsChannel {
			output += fmt.Sprintf("%d. [%v] %s\t", no+1, data.ChannelID, data.ChannelTitle)
			if (no+1)%3 == 0 {
				fmt.Fprintln(w, output)
				output = ""
			}
			no++
		}
	}
	fmt.Fprintln(w, output)
	w.Flush()
}

// PrintChannel is my fav channel XD.
func PrintChannel() {
	fmt.Println("[207] 中廣新聞網")
	fmt.Println("[205] 中廣流行網 i like")
	fmt.Println("[206] 中廣音樂網i radio")
	fmt.Println("[232] 飛碟電台")
	fmt.Println("[222] HitFm聯播網 Taipei 北部")
	fmt.Println("[156] KISS RADIO 大眾廣播電台")
	fmt.Println("[308] KISS RADIO 網路音樂台")
	fmt.Println("[187] NEWS98新聞網")
	fmt.Println("[370] POP Radio 台北流行廣播電台")
}
<|endoftext|>


<commit_before>package bagins

/*

"Oft in lies truth is hidden."

- Glorfindel

*/

import (
	"bufio"
	"errors"
	"fmt"
	"github.com/APTrust/bagins/bagutil"
	"hash"
	"os"
	"path/filepath"
	"regexp"
	"strings"
)

/*
 Manifest represents information about a BagIt manifest file.  As of BagIt spec
 0.97 this means only manifest-<algo>.txt and tagmanifest-<algo>.txt files.

 For more information see:
   manifest: http://tools.ietf.org/html/draft-kunze-bagit-09#section-2.1.3
   tagmanifest: http://tools.ietf.org/html/draft-kunze-bagit-09#section-2.2.1
*/
type Manifest struct {
	name     string            // Path to the
	Data     map[string]string // Map of filepath key and checksum value for that file
	hashFunc func() hash.Hash
}

// Returns a pointer to a new manifest or returns an error if improperly named.
func NewManifest(pth string, hashName string) (*Manifest, error) {
	if _, err := os.Stat(pth); err != nil {
		if os.IsNotExist(err) {
			return nil, fmt.Errorf("Unable to create manifest.  Path does not exist: %s", pth)
		} else {
			return nil, fmt.Errorf("Unexpected error creating manifest: %s", err)
		}
	}
	m := new(Manifest)
	hashFunc, err := bagutil.LookupHash(hashName)
	if err != nil {
		return nil, err
	}
	m.hashFunc = hashFunc
	m.Data = make(map[string]string)

	// TODO: Fix this!
	// First option is required if user passed a manifest file name into Bag.ReadBag().
	// Second option is required if no manifest file name was passed in to Bag.ReadBag().
	if filepath.Dir(pth) != "" && strings.Contains(pth, "manifest-") {
		m.name = pth
	} else {
		m.name = filepath.Join(pth, "manifest-"+strings.ToLower(hashName)+".txt")
	}

	return m, nil
}

/*
  Opens a manifest file, parses attemps to parse the hashtype from the filename, parses
  the file contents and returns a pointer to a Manifest.  Error slice may comprise multiple
  parsing errors when attempting to read data for fault tolerance.
*/
func ReadManifest(name string) (*Manifest, []error) {
	var errs []error

	hashName, err := parseAlgoName(name)
	if err != nil {
		return nil, append(errs, err)
	}

	file, err := os.Open(name)
	if err != nil {
		return nil, append(errs, err)
	}

	data, e := parseManifestData(file)
	if e != nil {
		errs = append(errs, e...)
	}

	m, err := NewManifest(name, hashName)
	if err != nil {
		return nil, append(errs, err)
	}
	m.Data = data

	return m, errs

}

/*
  Calculates a checksum for files listed in the manifest and compares it to the value
  stored in manifest file.  Returns an error for each file that fails the fixity check.
*/
func (m *Manifest) RunChecksums() []error {
	var invalidSums []error

	for key, sum := range m.Data {
		pth := filepath.Join(filepath.Dir(m.name), key)
		fileChecksum, err := bagutil.FileChecksum(pth, m.hashFunc())
		if sum != fileChecksum {
			invalidSums = append(invalidSums, fmt.Errorf("File checksum %s is not valid for %s:%s", sum, key, fileChecksum))
		}
		if err != nil {
			invalidSums = append(invalidSums, err)
		}
	}

	return invalidSums
}

// Writes key value pairs to a manifest file.
func (m *Manifest) Create() error {
	if m.Name() == "" {
		return errors.New("Manifest must have values for basename and algo set to create a file.")
	}
	// Create directory if needed.
	basepath := filepath.Dir(m.name)

	if err := os.MkdirAll(basepath, 0777); err != nil {
		return err
	}

	// Create the tagfile.
	fileOut, err := os.Create(m.name)
	if err != nil {
		return err
	}
	defer fileOut.Close()

	// Write fields and data to the file.
	for fName, ckSum := range m.Data {
		_, err := fmt.Fprintln(fileOut, ckSum, fName)
		if err != nil {
			return errors.New("Error writing line to manifest: " + err.Error())
		}
	}
	return nil
}

// Returns the contents of the manifest in the form of a string.
// Useful if you don't want to write directly to disk.
func (m *Manifest) ToString() string {
	str := ""
	for fName, ckSum := range m.Data {
		str += fmt.Sprintf("%s %s\n", ckSum, fName)
	}
	return str
}

// Returns a sting of the filename for this manifest file based on Path, BaseName and Algo
func (m *Manifest) Name() string {
	return filepath.Clean(m.name)
}

// Tries to parse the algorithm name from a manifest filename.  Returns
// an error if unable to do so.
func parseAlgoName(name string) (string, error) {
	filename := filepath.Base(name)
	re, err := regexp.Compile(`(^.*\-)(.*)(\.txt$)`)
	if err != nil {
		return "", err
	}
	matches := re.FindStringSubmatch(filename)
	if len(matches) < 2 {
		return "", errors.New("Unable to determine algorithm from filename!")
	}
	algo := matches[2]
	return algo, nil
}

// Reads the contents of file and parses checksum and file information in manifest format as
// per the bagit specification.
func parseManifestData(file *os.File) (map[string]string, []error) {
	var errs []error
	// See regexp examples at http://play.golang.org/p/_msLJ-lBEu
	// Regex matches these reqs from the bagit spec: "One or
	// more linear whitespace characters (spaces or tabs) MUST separate
	// CHECKSUM from FILENAME." as specified here:
	// http://tools.ietf.org/html/draft-kunze-bagit-10#section-2.1.3
	re := regexp.MustCompile(`^(\S*)\s*(.*)`)

	scanner := bufio.NewScanner(file)
	values := make(map[string]string)

	for scanner.Scan() {
		line := scanner.Text()
		if re.MatchString(line) {
			data := re.FindStringSubmatch(line)
			values[data[2]] = data[1]
		} else {
			errs = append(errs, fmt.Errorf("Unable to parse data from line: %s", line))
		}
	}

	return values, errs
}
<commit_msg>Check for existence of manifest directory, not file, when creating new manifest.<commit_after>package bagins

/*

"Oft in lies truth is hidden."

- Glorfindel

*/

import (
	"bufio"
	"errors"
	"fmt"
	"github.com/APTrust/bagins/bagutil"
	"hash"
	"os"
	"path/filepath"
	"regexp"
	"strings"
)

/*
 Manifest represents information about a BagIt manifest file.  As of BagIt spec
 0.97 this means only manifest-<algo>.txt and tagmanifest-<algo>.txt files.

 For more information see:
   manifest: http://tools.ietf.org/html/draft-kunze-bagit-09#section-2.1.3
   tagmanifest: http://tools.ietf.org/html/draft-kunze-bagit-09#section-2.2.1
*/
type Manifest struct {
	name     string            // Path to the
	Data     map[string]string // Map of filepath key and checksum value for that file
	hashFunc func() hash.Hash
}

// Returns a pointer to a new manifest or returns an error if improperly named.
func NewManifest(pth string, hashName string) (*Manifest, error) {
	if _, err := os.Stat(filepath.Dir(pth)); err != nil {
		if os.IsNotExist(err) {
			return nil, fmt.Errorf("Unable to create manifest. Path does not exist: %s", pth)
		} else {
			return nil, fmt.Errorf("Unexpected error creating manifest: %s", err)
		}
	}
	m := new(Manifest)
	hashFunc, err := bagutil.LookupHash(hashName)
	if err != nil {
		return nil, err
	}
	m.hashFunc = hashFunc
	m.Data = make(map[string]string)

	// TODO: Fix this!
	// First option is required if user passed a manifest file name into Bag.ReadBag().
	// Second option is required if no manifest file name was passed in to Bag.ReadBag().
	if filepath.Dir(pth) != "" && strings.Contains(pth, "manifest-") {
		m.name = pth
	} else {
		m.name = filepath.Join(pth, "manifest-"+strings.ToLower(hashName)+".txt")
	}

	return m, nil
}

/*
  Opens a manifest file, parses attemps to parse the hashtype from the filename, parses
  the file contents and returns a pointer to a Manifest.  Error slice may comprise multiple
  parsing errors when attempting to read data for fault tolerance.
*/
func ReadManifest(name string) (*Manifest, []error) {
	var errs []error

	hashName, err := parseAlgoName(name)
	if err != nil {
		return nil, append(errs, err)
	}

	file, err := os.Open(name)
	if err != nil {
		return nil, append(errs, err)
	}

	data, e := parseManifestData(file)
	if e != nil {
		errs = append(errs, e...)
	}

	m, err := NewManifest(name, hashName)
	if err != nil {
		return nil, append(errs, err)
	}
	m.Data = data

	return m, errs

}

/*
  Calculates a checksum for files listed in the manifest and compares it to the value
  stored in manifest file.  Returns an error for each file that fails the fixity check.
*/
func (m *Manifest) RunChecksums() []error {
	var invalidSums []error

	for key, sum := range m.Data {
		pth := filepath.Join(filepath.Dir(m.name), key)
		fileChecksum, err := bagutil.FileChecksum(pth, m.hashFunc())
		if sum != fileChecksum {
			invalidSums = append(invalidSums, fmt.Errorf("File checksum %s is not valid for %s:%s", sum, key, fileChecksum))
		}
		if err != nil {
			invalidSums = append(invalidSums, err)
		}
	}

	return invalidSums
}

// Writes key value pairs to a manifest file.
func (m *Manifest) Create() error {
	if m.Name() == "" {
		return errors.New("Manifest must have values for basename and algo set to create a file.")
	}
	// Create directory if needed.
	basepath := filepath.Dir(m.name)

	if err := os.MkdirAll(basepath, 0777); err != nil {
		return err
	}

	// Create the tagfile.
	fileOut, err := os.Create(m.name)
	if err != nil {
		return err
	}
	defer fileOut.Close()

	// Write fields and data to the file.
	for fName, ckSum := range m.Data {
		_, err := fmt.Fprintln(fileOut, ckSum, fName)
		if err != nil {
			return errors.New("Error writing line to manifest: " + err.Error())
		}
	}
	return nil
}

// Returns the contents of the manifest in the form of a string.
// Useful if you don't want to write directly to disk.
func (m *Manifest) ToString() string {
	str := ""
	for fName, ckSum := range m.Data {
		str += fmt.Sprintf("%s %s\n", ckSum, fName)
	}
	return str
}

// Returns a sting of the filename for this manifest file based on Path, BaseName and Algo
func (m *Manifest) Name() string {
	return filepath.Clean(m.name)
}

// Tries to parse the algorithm name from a manifest filename.  Returns
// an error if unable to do so.
func parseAlgoName(name string) (string, error) {
	filename := filepath.Base(name)
	re, err := regexp.Compile(`(^.*\-)(.*)(\.txt$)`)
	if err != nil {
		return "", err
	}
	matches := re.FindStringSubmatch(filename)
	if len(matches) < 2 {
		return "", errors.New("Unable to determine algorithm from filename!")
	}
	algo := matches[2]
	return algo, nil
}

// Reads the contents of file and parses checksum and file information in manifest format as
// per the bagit specification.
func parseManifestData(file *os.File) (map[string]string, []error) {
	var errs []error
	// See regexp examples at http://play.golang.org/p/_msLJ-lBEu
	// Regex matches these reqs from the bagit spec: "One or
	// more linear whitespace characters (spaces or tabs) MUST separate
	// CHECKSUM from FILENAME." as specified here:
	// http://tools.ietf.org/html/draft-kunze-bagit-10#section-2.1.3
	re := regexp.MustCompile(`^(\S*)\s*(.*)`)

	scanner := bufio.NewScanner(file)
	values := make(map[string]string)

	for scanner.Scan() {
		line := scanner.Text()
		if re.MatchString(line) {
			data := re.FindStringSubmatch(line)
			values[data[2]] = data[1]
		} else {
			errs = append(errs, fmt.Errorf("Unable to parse data from line: %s", line))
		}
	}

	return values, errs
}
<|endoftext|>


<commit_before>package golcrypt

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"errors"
	"io"
)

type AESBlock struct {
	DataBlob []byte
	Cipher   []byte
	Key      []byte
}

func (aesBlock *AESBlock) Encrypt() error {
	crypt, err := aes.NewCipher(aesBlock.Key)
	if err != nil {
		return err
	}

	galoisCounterMode, err := cipher.NewGCM(crypt)
	if err != nil {
		return err
	}

	nonce := make([]byte, galoisCounterMode.NonceSize())
	if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
		return err
	}

	aesBlock.Cipher = galoisCounterMode.Seal(nonce, nonce, aesBlock.DataBlob, nil)
	return nil
}

func (aesBlock *AESBlock) Decrypt() error {
	crypt, err := aes.NewCipher(aesBlock.Key)
	if err != nil {
		return err
	}

	galoisCounterMode, err := cipher.NewGCM(crypt)
	if err != nil {
		return err
	}

	nonceSize := galoisCounterMode.NonceSize()
	if len(aesBlock.Cipher) < nonceSize {
		return errors.New("ciphertext too short")
	}

	var nonce []byte
	nonce, aesBlock.Cipher = aesBlock.Cipher[:nonceSize], aesBlock.Cipher[nonceSize:]
	aesBlock.DataBlob, err = galoisCounterMode.Open(nil, nonce, aesBlock.Cipher, nil)
	return err
}
<commit_msg>golcrypt AESBlock constructs extracted as separate types<commit_after>package golcrypt

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"errors"
	"io"
)

type DataBlob []byte
type Cipher []byte
type Key []byte

type AESBlock struct {
	DataBlob DataBlob
	Cipher   Cipher
	Key      Key
}

func (aesBlock *AESBlock) Encrypt() error {
	crypt, err := aes.NewCipher(aesBlock.Key)
	if err != nil {
		return err
	}

	galoisCounterMode, err := cipher.NewGCM(crypt)
	if err != nil {
		return err
	}

	nonce := make([]byte, galoisCounterMode.NonceSize())
	if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
		return err
	}

	aesBlock.Cipher = galoisCounterMode.Seal(nonce, nonce, aesBlock.DataBlob, nil)
	return nil
}

func (aesBlock *AESBlock) Decrypt() error {
	crypt, err := aes.NewCipher(aesBlock.Key)
	if err != nil {
		return err
	}

	galoisCounterMode, err := cipher.NewGCM(crypt)
	if err != nil {
		return err
	}

	nonceSize := galoisCounterMode.NonceSize()
	if len(aesBlock.Cipher) < nonceSize {
		return errors.New("ciphertext too short")
	}

	var nonce []byte
	nonce, aesBlock.Cipher = aesBlock.Cipher[:nonceSize], aesBlock.Cipher[nonceSize:]
	aesBlock.DataBlob, err = galoisCounterMode.Open(nil, nonce, aesBlock.Cipher, nil)
	return err
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/docopt/docopt-go"
	"strconv"
)

type config struct {
	prepare bool
	train bool
	classify bool
	interpolate bool
	plot bool
	functions bool

	file string
	directory string
	data string
	width int
	height int
	initialization string
	initialLearningRate float64
	trainingSteps int
	input string
	weighted bool
	nearestNeighbors int
	size int
}

func parseConfig() *config {
	usage := `Self organizing maps for go.

Usage:
  gosom prepare <file> <data> <width> <height> [-i <im>]
  gosom train <file> <data> [-l <lr> -s <ts>]
  gosom classify <file> <input>
  gosom interpolate <file> <input> [-w -k <nn>]
  gosom plot <file> <directory> <size>
  gosom -h
  gosom -v
  gosom -f

Options:
  -h       Show help.
  -v       Show version.
  -f       Plot functions to current directoy.
  -i <im>  Initialization method (random, datapoints) [default: datapoints].
  -l <lr>  Initial learning rate [default: 0.5].
  -s <ts>  Number of training steps [default: 10000].
  -k <nn>  Number of nearest neighbors to consider [default: 5].
  -w       Use weighted interpolation.`

	a, err := docopt.Parse(usage, nil, true, "gosom 0.1", false)
	if err != nil {
		panic(err)
	}

	return &config{
		prepare: getBool(a["prepare"]),
		train: getBool(a["train"]),
		classify: getBool(a["classify"]),
		interpolate: getBool(a["interpolate"]),
		plot: getBool(a["plot"]),
		functions: getBool(a["-f"]),
		file: getString(a["<file>"]),
		directory: getString(a["<directory>"]),
		data: getString(a["<data>"]),
		width: getInt(a["<width>"]),
		height: getInt(a["<height>"]),
		initialization: getString(a["-i"]),
		initialLearningRate: getFloat(a["-l"]),
		trainingSteps: getInt(a["-s"]),
		input: getString(a["<input>"]),
		weighted: getBool(a["-w"]),
		nearestNeighbors: getInt(a["-k"]),
		size: getInt(a["<size>"]),
	}
}

func getBool(v interface{}) bool {
	b, ok := v.(bool)

	if !ok {
		return false
	} else {
		return b
	}
}

func getString(v interface{}) string {
	s, ok := v.(string)

	if !ok {
		return ""
	} else {
		return s
	}
}

func getInt(v interface{}) int {
	s := getString(v)

	i, err := strconv.Atoi(s)
	if err != nil {
		return 0
	} else {
		return i
	}
}

func getFloat(v interface{}) float64 {
	s := getString(v)

	f, err := strconv.ParseFloat(s, 64)
	if err != nil {
		return 0.0
	} else {
		return f
	}
}
<commit_msg>plot size as option<commit_after>package main

import (
	"github.com/docopt/docopt-go"
	"strconv"
)

type config struct {
	prepare bool
	train bool
	classify bool
	interpolate bool
	plot bool
	functions bool

	file string
	directory string
	data string
	width int
	height int
	initialization string
	initialLearningRate float64
	trainingSteps int
	input string
	weighted bool
	nearestNeighbors int
	size int
}

func parseConfig() *config {
	usage := `Self organizing maps for go.

Usage:
  gosom prepare <file> <data> <width> <height> [-i <im>]
  gosom train <file> <data> [-l <lr> -t <ts>]
  gosom classify <file> <input>
  gosom interpolate <file> <input> [-w -k <nn>]
  gosom plot <file> <directory> [-s <ns>]
  gosom -h
  gosom -v
  gosom -f

Options:
  -h       Show help.
  -v       Show version.
  -f       Plot functions to current directoy.
  -i <im>  Initialization method (random, datapoints) [default: datapoints].
  -l <lr>  Initial learning rate [default: 0.5].
  -t <ts>  Number of training steps [default: 10000].
  -k <nn>  Number of nearest neighbors to consider [default: 5].
  -w       Use weighted interpolation.
  -s <ns>  Size of the individual nodes [default: 10].`

	a, err := docopt.Parse(usage, nil, true, "gosom 0.1", false)
	if err != nil {
		panic(err)
	}

	return &config{
		prepare: getBool(a["prepare"]),
		train: getBool(a["train"]),
		classify: getBool(a["classify"]),
		interpolate: getBool(a["interpolate"]),
		plot: getBool(a["plot"]),
		functions: getBool(a["-f"]),
		file: getString(a["<file>"]),
		directory: getString(a["<directory>"]),
		data: getString(a["<data>"]),
		width: getInt(a["<width>"]),
		height: getInt(a["<height>"]),
		initialization: getString(a["-i"]),
		initialLearningRate: getFloat(a["-l"]),
		trainingSteps: getInt(a["-t"]),
		input: getString(a["<input>"]),
		weighted: getBool(a["-w"]),
		nearestNeighbors: getInt(a["-k"]),
		size: getInt(a["-s"]),
	}
}

func getBool(v interface{}) bool {
	b, ok := v.(bool)

	if !ok {
		return false
	} else {
		return b
	}
}

func getString(v interface{}) string {
	s, ok := v.(string)

	if !ok {
		return ""
	} else {
		return s
	}
}

func getInt(v interface{}) int {
	s := getString(v)

	i, err := strconv.Atoi(s)
	if err != nil {
		return 0
	} else {
		return i
	}
}

func getFloat(v interface{}) float64 {
	s := getString(v)

	f, err := strconv.ParseFloat(s, 64)
	if err != nil {
		return 0.0
	} else {
		return f
	}
}
<|endoftext|>


<commit_before>package gottyclient

import (
	"bufio"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"unicode/utf8"
	"unsafe"

	"github.com/Sirupsen/logrus"
	"github.com/gorilla/websocket"
	"golang.org/x/crypto/ssh/terminal"
)

// GetWebsocketURL transforms a GoTTY http URL to its WebSocket URL
func GetWebsocketURL(httpURL string) (*url.URL, error) {
	target, err := url.Parse(httpURL)
	if err != nil {
		return nil, err
	}

	if target.Scheme == "https" {
		target.Scheme = "wss"
	} else {
		target.Scheme = "ws"
	}

	target.Path = strings.TrimLeft(target.Path+"ws", "/")

	return target, nil
}

type Client struct {
	Dialer    *websocket.Dialer
	Conn      *websocket.Conn
	Headers   http.Header
	Target    string
	Connected bool
}

// Connect tries to dial a websocket server
func (c *Client) Connect() error {
	conn, _, err := c.Dialer.Dial(c.Target, c.Headers)
	if err != nil {
		return err
	}
	c.Conn = conn
	return nil
}

// Close will nicely close the dialer
func (c *Client) Close() {
	c.Conn.Close()
}

// Loop will look indefinitely for new messages
func (c *Client) Loop() error {
	if !c.Connected {
		err := c.Connect()
		if err != nil {
			return err
		}
	}

	done := make(chan bool)
	go c.readLoop(done)
	go c.writeLoop(done)
	go c.termsizeLoop(done)
	<-done
	return nil
}

type winsize struct {
	Rows    uint16 `json:"rows"`
	Columns uint16 `json:"columns"`
	// unused
	x uint16
	y uint16
}

func (c *Client) termsizeLoop(done chan bool) {
	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGWINCH)
	ws := winsize{}

	for {
		syscall.Syscall(syscall.SYS_IOCTL,
			uintptr(0), uintptr(syscall.TIOCGWINSZ),
			uintptr(unsafe.Pointer(&ws)))

		b, err := json.Marshal(ws)
		if err != nil {
			logrus.Warnf("json.Marshal error: %v", err)
		}

		err = c.Conn.WriteMessage(websocket.TextMessage, append([]byte("1"), b...))
		if err != nil {
			logrus.Warnf("ws.WriteMessage failed: %v", err)
		}

		<-ch
	}
}

func (c *Client) writeLoop(done chan bool) {
	oldState, err := terminal.MakeRaw(0)
	if err == nil {
		defer terminal.Restore(0, oldState)
	}

	reader := bufio.NewReader(os.Stdin)
	for {
		x, size, err := reader.ReadRune()
		if size <= 0 || err != nil {
			done <- true
			return
		}

		p := make([]byte, size)
		utf8.EncodeRune(p, x)

		err = c.Conn.WriteMessage(websocket.TextMessage, append([]byte("0"), p...))
		if err != nil {
			done <- true
			return
		}
	}
}

func (c *Client) readLoop(done chan bool) {
	for {
		_, data, err := c.Conn.ReadMessage()
		if err != nil {
			done <- true
			logrus.Warnf("c.Conn.ReadMessage: %v", err)
			return
		}

		switch data[0] {
		case '0': // data
			fmt.Print(string(data[1:]))
		case '1': // new title
			newTitle := string(data[1:])
			fmt.Printf("\033]0;%s\007", newTitle)
		case '2': // json prefs
			logrus.Warnf("Unhandled protocol message: json pref: %s", string(data))
		default:
			logrus.Warnf("Unhandled protocol message: %s", string(data))
		}
	}
}

// NewClient returns a GoTTY client object
func NewClient(httpURL string) (*Client, error) {
	target, err := GetWebsocketURL(httpURL)
	if err != nil {
		return nil, err
	}

	return &Client{
		Dialer: &websocket.Dialer{},
		Target: target.String(),
	}, nil
}
<commit_msg>Handling Basic Auth<commit_after>package gottyclient

import (
	"bufio"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"unicode/utf8"
	"unsafe"

	"github.com/Sirupsen/logrus"
	"github.com/gorilla/websocket"
	"golang.org/x/crypto/ssh/terminal"
)

// GetWebsocketURL transforms a GoTTY http URL to its WebSocket URL
func GetWebsocketURL(httpURL string) (*url.URL, *http.Header, error) {
	header := http.Header{}
	target, err := url.Parse(httpURL)
	if err != nil {
		return nil, nil, err
	}

	if target.Scheme == "https" {
		target.Scheme = "wss"
	} else {
		target.Scheme = "ws"
	}

	target.Path = strings.TrimLeft(target.Path+"ws", "/")

	if target.User != nil {
		header.Add("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(target.User.String())))
		target.User = nil
	}

	return target, &header, nil
}

type Client struct {
	Dialer    *websocket.Dialer
	Conn      *websocket.Conn
	Headers   *http.Header
	Target    string
	Connected bool
}

// Connect tries to dial a websocket server
func (c *Client) Connect() error {
	conn, _, err := c.Dialer.Dial(c.Target, *c.Headers)
	if err != nil {
		return err
	}
	c.Conn = conn
	return nil
}

// Close will nicely close the dialer
func (c *Client) Close() {
	c.Conn.Close()
}

// Loop will look indefinitely for new messages
func (c *Client) Loop() error {
	if !c.Connected {
		err := c.Connect()
		if err != nil {
			return err
		}
	}

	done := make(chan bool)
	go c.readLoop(done)
	go c.writeLoop(done)
	go c.termsizeLoop(done)
	<-done
	return nil
}

type winsize struct {
	Rows    uint16 `json:"rows"`
	Columns uint16 `json:"columns"`
	// unused
	x uint16
	y uint16
}

func (c *Client) termsizeLoop(done chan bool) {
	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGWINCH)
	ws := winsize{}

	for {
		syscall.Syscall(syscall.SYS_IOCTL,
			uintptr(0), uintptr(syscall.TIOCGWINSZ),
			uintptr(unsafe.Pointer(&ws)))

		b, err := json.Marshal(ws)
		if err != nil {
			logrus.Warnf("json.Marshal error: %v", err)
		}

		err = c.Conn.WriteMessage(websocket.TextMessage, append([]byte("1"), b...))
		if err != nil {
			logrus.Warnf("ws.WriteMessage failed: %v", err)
		}

		<-ch
	}
}

func (c *Client) writeLoop(done chan bool) {
	oldState, err := terminal.MakeRaw(0)
	if err == nil {
		defer terminal.Restore(0, oldState)
	}

	reader := bufio.NewReader(os.Stdin)
	for {
		x, size, err := reader.ReadRune()
		if size <= 0 || err != nil {
			done <- true
			return
		}

		p := make([]byte, size)
		utf8.EncodeRune(p, x)

		err = c.Conn.WriteMessage(websocket.TextMessage, append([]byte("0"), p...))
		if err != nil {
			done <- true
			return
		}
	}
}

func (c *Client) readLoop(done chan bool) {
	for {
		_, data, err := c.Conn.ReadMessage()
		if err != nil {
			done <- true
			logrus.Warnf("c.Conn.ReadMessage: %v", err)
			return
		}

		switch data[0] {
		case '0': // data
			fmt.Print(string(data[1:]))
		case '1': // new title
			newTitle := string(data[1:])
			fmt.Printf("\033]0;%s\007", newTitle)
		case '2': // json prefs
			logrus.Debugf("Unhandled protocol message: json pref: %s", string(data))
		default:
			logrus.Warnf("Unhandled protocol message: %s", string(data))
		}
	}
}

// NewClient returns a GoTTY client object
func NewClient(httpURL string) (*Client, error) {
	target, header, err := GetWebsocketURL(httpURL)
	if err != nil {
		return nil, err
	}

	return &Client{
		Dialer:  &websocket.Dialer{},
		Target:  target.String(),
		Headers: header,
	}, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"
	"os"
	"path/filepath"

	"github.com/gorilla/handlers"
	"github.com/gorilla/mux"
	"github.com/maputnik/desktop/filewatch"
	"github.com/urfave/cli"
)

func main() {
	app := cli.NewApp()
	app.Name = "maputnik"
	app.Usage = "Server for integrating Maputnik locally"
	app.Version = "Desktop: 1.0.3; Editor: 1.5.0"

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "file, f",
			Usage: "Allow access to JSON style from web client",
		},
		cli.BoolFlag{
			Name:  "watch",
			Usage: "Notify web client about JSON style file changes",
		},
	}

	app.Action = func(c *cli.Context) error {
		gui := http.FileServer(assetFS())

		router := mux.NewRouter().StrictSlash(true)

		filename := c.String("file")
		if filename != "" {
			fmt.Printf("%s is accessible via Maputnik\n", filename)
			// Allow access to reading and writing file on the local system
			path, _ := filepath.Abs(filename)
			accessor := StyleFileAccessor(path)
			router.Path("/styles").Methods("GET").HandlerFunc(accessor.ListFiles)
			router.Path("/styles/{styleId}").Methods("GET").HandlerFunc(accessor.ReadFile)
			router.Path("/styles/{styleId}").Methods("PUT").HandlerFunc(accessor.SaveFile)

			// Register websocket to notify we clients about file changes
			if c.Bool("watch") {
				router.Path("/ws").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
					filewatch.ServeWebsocketFileWatcher(filename, w, r)
				})
			}
		}

		router.PathPrefix("/").Handler(http.StripPrefix("/", gui))
		loggedRouter := handlers.LoggingHandler(os.Stdout, router)
		corsRouter := handlers.CORS(handlers.AllowedHeaders([]string{"Content-Type"}), handlers.AllowedMethods([]string{"GET", "PUT"}), handlers.AllowedOrigins([]string{"*"}), handlers.AllowCredentials())(loggedRouter)

		fmt.Println("Exposing Maputnik on http://localhost:8000")
		return http.ListenAndServe(":8000", corsRouter)
	}

	app.Run(os.Args)
}
<commit_msg>Switch around editor and desktop in version field so that it prints nicer<commit_after>package main

import (
	"fmt"
	"net/http"
	"os"
	"path/filepath"

	"github.com/gorilla/handlers"
	"github.com/gorilla/mux"
	"github.com/maputnik/desktop/filewatch"
	"github.com/urfave/cli"
)

func main() {
	app := cli.NewApp()
	app.Name = "maputnik"
	app.Usage = "Server for integrating Maputnik locally"
	app.Version = "Editor: 1.5.0; Desktop: 1.0.3"

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "file, f",
			Usage: "Allow access to JSON style from web client",
		},
		cli.BoolFlag{
			Name:  "watch",
			Usage: "Notify web client about JSON style file changes",
		},
	}

	app.Action = func(c *cli.Context) error {
		gui := http.FileServer(assetFS())

		router := mux.NewRouter().StrictSlash(true)

		filename := c.String("file")
		if filename != "" {
			fmt.Printf("%s is accessible via Maputnik\n", filename)
			// Allow access to reading and writing file on the local system
			path, _ := filepath.Abs(filename)
			accessor := StyleFileAccessor(path)
			router.Path("/styles").Methods("GET").HandlerFunc(accessor.ListFiles)
			router.Path("/styles/{styleId}").Methods("GET").HandlerFunc(accessor.ReadFile)
			router.Path("/styles/{styleId}").Methods("PUT").HandlerFunc(accessor.SaveFile)

			// Register websocket to notify we clients about file changes
			if c.Bool("watch") {
				router.Path("/ws").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
					filewatch.ServeWebsocketFileWatcher(filename, w, r)
				})
			}
		}

		router.PathPrefix("/").Handler(http.StripPrefix("/", gui))
		loggedRouter := handlers.LoggingHandler(os.Stdout, router)
		corsRouter := handlers.CORS(handlers.AllowedHeaders([]string{"Content-Type"}), handlers.AllowedMethods([]string{"GET", "PUT"}), handlers.AllowedOrigins([]string{"*"}), handlers.AllowCredentials())(loggedRouter)

		fmt.Println("Exposing Maputnik on http://localhost:8000")
		return http.ListenAndServe(":8000", corsRouter)
	}

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


<commit_before>package main

import (
	"bufio"
	"fmt"
	"os"
	"path/filepath"

	"github.com/jessevdk/go-flags"
)

const version = "v0.0.1"

type opts struct {
	Help    bool   `short:"h" long:"help" description:"Print this message and quit"`
	Version bool   `short:"v" long:"version" description:"Print version information and quit"`
	OutDir  string `short:"o" long:"output" description:"Specify an output directory for Ghost posts"`
}

func init() {
}

func main() {
	opts := &opts{}
	p := flags.NewParser(opts, flags.PrintErrors)
	args, err := p.Parse()
	if err != nil {
		return
	}

	if opts.Help || (len(args) == 0 && len(os.Args) < 2) {
		fmt.Fprintf(os.Stderr, helpText)
		return
	}

	if opts.Version {
		fmt.Fprintf(os.Stderr, "md2ghost: %s\n", version)
		return
	}

	var fp *os.File
	var pattern string

	// MEMO: args[0] != "" だと panic: runtime error: index out of range
	if len(args) != 0 {
		pattern = args[0] + "/*.md"
	} else {
		pattern = "." + "/*.md"
	}

	files, err := filepath.Glob(pattern)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return
	}
	for _, file := range files {
		fp, err = os.Open(file)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			return
		}
		defer fp.Close()

		scanner := bufio.NewScanner(fp)
		for scanner.Scan() {
			fmt.Println(scanner.Text())
		}
		if err := scanner.Err(); err != nil {
			fmt.Fprintln(os.Stderr, err)
			return
		}
	}
}

const helpText = `md2ghost - Convert a markdown files into Ghost posts.

Usage: md2ghost [option] <file|directory>

Options:

  -o, --output  Specify an output directory for Ghost posts
  -h, --help    Print this message and quit
  -v, --version Print version information and quit

Example:

  $ md2ghost .
  $ md2ghost -o path/to/output_directory path/to/your_directory
`
<commit_msg>Add Ghost JSON format structure<commit_after>package main

import (
	"bufio"
	"fmt"
	"os"
	"path/filepath"

	"github.com/jessevdk/go-flags"
)

const version = "v0.0.1"

type opts struct {
	Help    bool   `short:"h" long:"help" description:"Print this message and quit"`
	Version bool   `short:"v" long:"version" description:"Print version information and quit"`
	OutDir  string `short:"o" long:"output" description:"Specify an output directory for Ghost posts"`
}

type GhostJSON struct {
	Meta struct {
		ExportedOn float64 `json:"exported_on"`
		Version    string  `json:"version"`
	} `json:"meta"`
	Data struct {
		Posts []struct {
			AuthorID        float64     `json:"author_id"`
			CreatedAt       float64     `json:"created_at"`
			CreatedBy       float64     `json:"created_by"`
			Featured        float64     `json:"featured"`
			HTML            string      `json:"html"`
			ID              float64     `json:"id"`
			Image           interface{} `json:"image"`
			Language        string      `json:"language"`
			Markdown        string      `json:"markdown"`
			MetaDescription interface{} `json:"meta_description"`
			MetaTitle       interface{} `json:"meta_title"`
			Page            float64     `json:"page"`
			PublishedAt     float64     `json:"published_at"`
			PublishedBy     float64     `json:"published_by"`
			Slug            string      `json:"slug"`
			Status          string      `json:"status"`
			Title           string      `json:"title"`
			UpdatedAt       float64     `json:"updated_at"`
			UpdatedBy       float64     `json:"updated_by"`
		} `json:"posts"`
		PostsTags []struct {
			PostID float64 `json:"post_id"`
			TagID  float64 `json:"tag_id"`
		} `json:"posts_tags"`
		RolesUsers []struct {
			RoleID float64 `json:"role_id"`
			UserID float64 `json:"user_id"`
		} `json:"roles_users"`
		Tags []struct {
			Description string  `json:"description"`
			ID          float64 `json:"id"`
			Name        string  `json:"name"`
			Slug        string  `json:"slug"`
		} `json:"tags"`
		Users []struct {
			Accessibility   interface{} `json:"accessibility"`
			Bio             interface{} `json:"bio"`
			Cover           interface{} `json:"cover"`
			CreatedAt       float64     `json:"created_at"`
			CreatedBy       float64     `json:"created_by"`
			Email           string      `json:"email"`
			ID              float64     `json:"id"`
			Image           interface{} `json:"image"`
			Language        string      `json:"language"`
			LastLogin       interface{} `json:"last_login"`
			Location        interface{} `json:"location"`
			MetaDescription interface{} `json:"meta_description"`
			MetaTitle       interface{} `json:"meta_title"`
			Name            string      `json:"name"`
			Slug            string      `json:"slug"`
			Status          string      `json:"status"`
			UpdatedAt       float64     `json:"updated_at"`
			UpdatedBy       float64     `json:"updated_by"`
			Website         interface{} `json:"website"`
		} `json:"users"`
	} `json:"data"`
}

func main() {
	opts := &opts{}
	p := flags.NewParser(opts, flags.PrintErrors)
	args, err := p.Parse()
	if err != nil {
		return
	}

	if opts.Help || (len(args) == 0 && len(os.Args) < 2) {
		fmt.Fprintf(os.Stderr, helpText)
		return
	}

	if opts.Version {
		fmt.Fprintf(os.Stderr, "md2ghost: %s\n", version)
		return
	}

	var fp *os.File
	var pattern string

	// MEMO: args[0] != "" だと panic: runtime error: index out of range
	if len(args) != 0 {
		pattern = args[0] + "/*.md"
	} else {
		pattern = "." + "/*.md"
	}

	files, err := filepath.Glob(pattern)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return
	}
	for _, file := range files {
		fp, err = os.Open(file)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			return
		}
		defer fp.Close()

		scanner := bufio.NewScanner(fp)
		for scanner.Scan() {
			fmt.Println(scanner.Text())
		}
		if err := scanner.Err(); err != nil {
			fmt.Fprintln(os.Stderr, err)
			return
		}
	}
}

const helpText = `md2ghost - Convert a markdown files into Ghost posts.

Usage: md2ghost [option] <file|directory>

Options:

  -o, --output  Specify an output directory for Ghost posts
  -h, --help    Print this message and quit
  -v, --version Print version information and quit

Example:

  $ md2ghost .
  $ md2ghost -o path/to/output_directory path/to/your_directory
`
<|endoftext|>


<commit_before>package nosurf

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
)

func TestDefaultFailureHandler(t *testing.T) {
	writer := httptest.NewRecorder()
	req := dummyGet()

	defaultFailureHandler(writer, req)

	if writer.Code != FailureCode {
		t.Errorf("Wrong status code for defaultFailure Handler: "+
			"expected %d, got %d", FailureCode, writer.Code)
	}
}

func TestRegenerateToken(t *testing.T) {
	hand := New(nil)
	writer := httptest.NewRecorder()

	req := dummyGet()
	token := b64encode(unmaskToken(b64decode(hand.RegenerateToken(writer, req))))

	header := writer.Header().Get("Set-Cookie")
	expectedPart := fmt.Sprintf("csrf_token=%s;", token)

	if !strings.Contains(header, expectedPart) {
		t.Errorf("Expected header to contain %v, it doesn't. The header is %v.",
			expectedPart, header)
	}

}

// Kind of a duplication of TestRegenerateToken,
// but it's still good to test this too.
func TestsetTokenCookie(t *testing.T) {
	hand := New(nil)

	writer := httptest.NewRecorder()
	req := dummyGet()

	token := []byte("dummy")
	hand.setTokenCookie(writer, req, token)

	header := writer.Header().Get("Set-Cookie")
	expected_part := fmt.Sprintf("csrf_token=%s;", token)

	if !strings.Contains(header, expected_part) {
		t.Errorf("Expected header to contain %v, it doesn't. The header is %v.",
			expected_part, header)
	}

	tokenInContext := unmaskToken(b64decode(Token(req)))
	if !bytes.Equal(tokenInContext, token) {
		t.Errorf("RegenerateToken didn't set the token in the context map!"+
			" Expected %v, got %v", token, tokenInContext)
	}
}

func TestSafeMethodsPass(t *testing.T) {
	handler := New(http.HandlerFunc(succHand))

	for _, method := range safeMethods {
		req, err := http.NewRequest(method, "http://dummy.us", nil)

		if err != nil {
			t.Fatal(err)
		}

		writer := httptest.NewRecorder()
		handler.ServeHTTP(writer, req)

		expected := 200

		if writer.Code != expected {
			t.Errorf("A safe method didn't pass the CSRF check."+
				"Expected HTTP status %d, got %d", expected, writer.Code)
		}

		writer.Flush()
	}
}

func TestExemptedPass(t *testing.T) {
	handler := New(http.HandlerFunc(succHand))
	handler.ExemptPath("/faq")

	req, err := http.NewRequest("POST", "http://dummy.us/faq", strings.NewReader("a=b"))
	if err != nil {
		t.Fatal(err)
	}

	writer := httptest.NewRecorder()
	handler.ServeHTTP(writer, req)

	expected := 200

	if writer.Code != expected {
		t.Errorf("An exempted URL didn't pass the CSRF check."+
			"Expected HTTP status %d, got %d", expected, writer.Code)
	}

	writer.Flush()
}

func TestManualVerify(t *testing.T) {
	var keepToken string
	hand := New(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "POST" {
			if !VerifyToken(Token(r), keepToken) {
				http.Error(w, "error", http.StatusBadRequest)
			}
		} else {
			keepToken = Token(r)
		}
	}))
	hand.ExemptPath("/")
	hand.SetFailureHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		t.Errorf("Test failed. Reason: %v", Reason(r))
	}))

	server := httptest.NewServer(hand)
	defer server.Close()

	// issue the first request to get the token
	resp, err := http.Get(server.URL)
	if err != nil {
		t.Fatal(err)
	}

	cookie := getRespCookie(resp, CookieName)
	if cookie == nil {
		t.Fatal("Cookie was not found in the response.")
	}

	// finalToken := b64encode(maskToken(b64decode(cookie.Value)))

	vals := [][]string{
		{"name", "Jolene"},
	}

	// Test usual POST
	{
		req, err := http.NewRequest("POST", server.URL, formBodyR(vals))
		if err != nil {
			t.Fatal(err)
		}
		req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
		req.AddCookie(cookie)

		resp, err = http.DefaultClient.Do(req)

		if err != nil {
			t.Fatal(err)
		}
		if resp.StatusCode != 200 {
			t.Errorf("The request should have succeeded, but it didn't. Instead, the code was %d",
				resp.StatusCode)
		}
	}
}

// Tests that the token/reason context is accessible
// in the success/failure handlers
func TestContextIsAccessible(t *testing.T) {
	// case 1: success
	succHand := func(w http.ResponseWriter, r *http.Request) {
		token := Token(r)
		if token == "" {
			t.Errorf("Token is inaccessible in the success handler")
		}
	}

	hand := New(http.HandlerFunc(succHand))

	// we need a request that passes. Let's just use a safe method for that.
	req := dummyGet()
	writer := httptest.NewRecorder()

	hand.ServeHTTP(writer, req)
}

// Confusing test name. Tests that nosurf's context is accessible
// when a request with golang's context is passed into Token().
func TestContextIsAccessibleWithContext(t *testing.T) {
	succHand := func(w http.ResponseWriter, r *http.Request) {
		r = r.WithContext(context.WithValue(r.Context(), "dummykey", "dummyval"))
		token := Token(r)
		if token == "" {
			t.Errorf("Token is inaccessible in the success handler")
		}
	}

	hand := New(http.HandlerFunc(succHand))

	// we need a request that passes. Let's just use a safe method for that.
	req := dummyGet()
	writer := httptest.NewRecorder()

	hand.ServeHTTP(writer, req)
}

func TestEmptyRefererFails(t *testing.T) {
	hand := New(http.HandlerFunc(succHand))
	fhand := correctReason(t, ErrNoReferer)
	hand.SetFailureHandler(fhand)

	req, err := http.NewRequest("POST", "https://dummy.us/", strings.NewReader("a=b"))
	if err != nil {
		t.Fatal(err)
	}
	writer := httptest.NewRecorder()

	hand.ServeHTTP(writer, req)

	if writer.Code != FailureCode {
		t.Errorf("A POST request with no Referer should have failed with the code %d, but it didn't.",
			writer.Code)
	}
}

func TestDifferentOriginRefererFails(t *testing.T) {
	hand := New(http.HandlerFunc(succHand))
	fhand := correctReason(t, ErrBadReferer)
	hand.SetFailureHandler(fhand)

	req, err := http.NewRequest("POST", "https://dummy.us/", strings.NewReader("a=b"))
	if err != nil {
		t.Fatal(err)
	}
	req.Header.Set("Referer", "http://attack-on-golang.com")
	writer := httptest.NewRecorder()

	hand.ServeHTTP(writer, req)

	if writer.Code != FailureCode {
		t.Errorf("A POST request with a Referer from a different origin"+
			"should have failed with the code %d, but it didn't.", writer.Code)
	}
}

func TestNoTokenFails(t *testing.T) {
	hand := New(http.HandlerFunc(succHand))
	fhand := correctReason(t, ErrBadToken)
	hand.SetFailureHandler(fhand)

	vals := [][]string{
		{"name", "Jolene"},
	}

	req, err := http.NewRequest("POST", "http://dummy.us", formBodyR(vals))
	if err != nil {
		panic(err)
	}
	writer := httptest.NewRecorder()

	hand.ServeHTTP(writer, req)

	if writer.Code != FailureCode {
		t.Errorf("The check should've failed with the code %d, but instead, it"+
			" returned code %d", FailureCode, writer.Code)
	}

	expectedContentType := "text/plain; charset=utf-8"
	actualContentType := writer.Header().Get("Content-Type")
	if actualContentType != expectedContentType {
		t.Errorf("The check should've failed with content type %s, but instead, it"+
			" returned content type %s", expectedContentType, actualContentType)
	}
}

func TestWrongTokenFails(t *testing.T) {
	hand := New(http.HandlerFunc(succHand))
	fhand := correctReason(t, ErrBadToken)
	hand.SetFailureHandler(fhand)

	vals := [][]string{
		{"name", "Jolene"},
		// this won't EVER be a valid value with the current scheme
		{FormFieldName, "$#%^&"},
	}

	req, err := http.NewRequest("POST", "http://dummy.us", formBodyR(vals))
	if err != nil {
		panic(err)
	}
	writer := httptest.NewRecorder()

	hand.ServeHTTP(writer, req)

	if writer.Code != FailureCode {
		t.Errorf("The check should've failed with the code %d, but instead, it"+
			" returned code %d", FailureCode, writer.Code)
	}

	expectedContentType := "text/plain; charset=utf-8"
	actualContentType := writer.Header().Get("Content-Type")
	if actualContentType != expectedContentType {
		t.Errorf("The check should've failed with content type %s, but instead, it"+
			" returned content type %s", expectedContentType, actualContentType)
	}
}

// For this and similar tests we start a test server
// Since it's much easier to get the cookie
// from a normal http.Response than from the recorder
func TestCorrectTokenPasses(t *testing.T) {
	hand := New(http.HandlerFunc(succHand))
	hand.SetFailureHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		t.Errorf("Test failed. Reason: %v", Reason(r))
	}))

	server := httptest.NewServer(hand)
	defer server.Close()

	// issue the first request to get the token
	resp, err := http.Get(server.URL)
	if err != nil {
		t.Fatal(err)
	}

	cookie := getRespCookie(resp, CookieName)
	if cookie == nil {
		t.Fatal("Cookie was not found in the response.")
	}

	finalToken := b64encode(maskToken(b64decode(cookie.Value)))

	vals := [][]string{
		{"name", "Jolene"},
		{FormFieldName, finalToken},
	}

	// Test usual POST
	/*
		{
			req, err := http.NewRequest("POST", server.URL, formBodyR(vals))
			if err != nil {
				t.Fatal(err)
			}
			req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
			req.AddCookie(cookie)

			resp, err = http.DefaultClient.Do(req)

			if err != nil {
				t.Fatal(err)
			}
			if resp.StatusCode != 200 {
				t.Errorf("The request should have succeeded, but it didn't. Instead, the code was %d",
					resp.StatusCode)
			}
		}
	*/

	// Test multipart
	{
		prd, pwr := io.Pipe()
		wr := multipart.NewWriter(pwr)
		go func() {

			for _, v := range vals {
				wr.WriteField(v[0], v[1])
			}

			err := wr.Close()
			if err != nil {
				t.Fatal(err)
			}
			err = pwr.Close()
			if err != nil {
				t.Fatal(err)
			}
		}()

		// Prepare a multipart request
		req, err := http.NewRequest("POST", server.URL, prd)
		if err != nil {
			t.Fatal(err)
		}

		req.Header.Add("Content-Type", wr.FormDataContentType())
		req.AddCookie(cookie)

		resp, err := http.DefaultClient.Do(req)
		if err != nil {
			t.Fatal(err)
		}
		if resp.StatusCode != 200 {
			t.Errorf("The request should have succeeded, but it didn't. Instead, the code was %d",
				resp.StatusCode)
		}
	}
}

func TestPrefersHeaderOverFormValue(t *testing.T) {
	// Let's do a nice trick to find out this:
	// We'll set the correct token in the header
	// And a wrong one in the form.
	// That way, if it succeeds,
	// it will mean that it prefered the header.

	hand := New(http.HandlerFunc(succHand))

	server := httptest.NewServer(hand)
	defer server.Close()

	resp, err := http.Get(server.URL)
	if err != nil {
		t.Fatal(err)
	}

	cookie := getRespCookie(resp, CookieName)
	if cookie == nil {
		t.Fatal("Cookie was not found in the response.")
	}

	finalToken := b64encode(maskToken(b64decode(cookie.Value)))

	vals := [][]string{
		{"name", "Jolene"},
		{FormFieldName, "a very wrong value"},
	}

	req, err := http.NewRequest("POST", server.URL, formBodyR(vals))
	if err != nil {
		t.Fatal(err)
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Set(HeaderName, finalToken)
	req.AddCookie(cookie)

	resp, err = http.DefaultClient.Do(req)

	if err != nil {
		t.Fatal(err)
	}
	if resp.StatusCode != 200 {
		t.Errorf("The request should have succeeded, but it didn't. Instead, the code was %d",
			resp.StatusCode)
	}
}

func TestAddsVaryCookieHeader(t *testing.T) {
	hand := New(http.HandlerFunc(succHand))
	writer := httptest.NewRecorder()
	req := dummyGet()

	hand.ServeHTTP(writer, req)

	if !sContains(writer.Header()["Vary"], "Cookie") {
		t.Errorf("CSRFHandler didn't add a `Vary: Cookie` header.")
	}
}
<commit_msg>Remove legacy tests<commit_after>package nosurf

import (
	"context"
	"io"
	"mime/multipart"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
)

func TestDefaultFailureHandler(t *testing.T) {
	writer := httptest.NewRecorder()
	req := dummyGet()

	defaultFailureHandler(writer, req)

	if writer.Code != FailureCode {
		t.Errorf("Wrong status code for defaultFailure Handler: "+
			"expected %d, got %d", FailureCode, writer.Code)
	}
}

func TestSafeMethodsPass(t *testing.T) {
	handler := New(http.HandlerFunc(succHand))

	for _, method := range safeMethods {
		req, err := http.NewRequest(method, "http://dummy.us", nil)

		if err != nil {
			t.Fatal(err)
		}

		writer := httptest.NewRecorder()
		handler.ServeHTTP(writer, req)

		expected := 200

		if writer.Code != expected {
			t.Errorf("A safe method didn't pass the CSRF check."+
				"Expected HTTP status %d, got %d", expected, writer.Code)
		}

		writer.Flush()
	}
}

func TestExemptedPass(t *testing.T) {
	handler := New(http.HandlerFunc(succHand))
	handler.ExemptPath("/faq")

	req, err := http.NewRequest("POST", "http://dummy.us/faq", strings.NewReader("a=b"))
	if err != nil {
		t.Fatal(err)
	}

	writer := httptest.NewRecorder()
	handler.ServeHTTP(writer, req)

	expected := 200

	if writer.Code != expected {
		t.Errorf("An exempted URL didn't pass the CSRF check."+
			"Expected HTTP status %d, got %d", expected, writer.Code)
	}

	writer.Flush()
}

func TestManualVerify(t *testing.T) {
	var keepToken string
	hand := New(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "POST" {
			if !VerifyToken(Token(r), keepToken) {
				http.Error(w, "error", http.StatusBadRequest)
			}
		} else {
			keepToken = Token(r)
		}
	}))
	hand.ExemptPath("/")
	hand.SetFailureHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		t.Errorf("Test failed. Reason: %v", Reason(r))
	}))

	server := httptest.NewServer(hand)
	defer server.Close()

	// issue the first request to get the token
	resp, err := http.Get(server.URL)
	if err != nil {
		t.Fatal(err)
	}

	cookie := getRespCookie(resp, CookieName)
	if cookie == nil {
		t.Fatal("Cookie was not found in the response.")
	}

	// finalToken := b64encode(maskToken(b64decode(cookie.Value)))

	vals := [][]string{
		{"name", "Jolene"},
	}

	// Test usual POST
	{
		req, err := http.NewRequest("POST", server.URL, formBodyR(vals))
		if err != nil {
			t.Fatal(err)
		}
		req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
		req.AddCookie(cookie)

		resp, err = http.DefaultClient.Do(req)

		if err != nil {
			t.Fatal(err)
		}
		if resp.StatusCode != 200 {
			t.Errorf("The request should have succeeded, but it didn't. Instead, the code was %d",
				resp.StatusCode)
		}
	}
}

// Tests that the token/reason context is accessible
// in the success/failure handlers
func TestContextIsAccessible(t *testing.T) {
	// case 1: success
	succHand := func(w http.ResponseWriter, r *http.Request) {
		token := Token(r)
		if token == "" {
			t.Errorf("Token is inaccessible in the success handler")
		}
	}

	hand := New(http.HandlerFunc(succHand))

	// we need a request that passes. Let's just use a safe method for that.
	req := dummyGet()
	writer := httptest.NewRecorder()

	hand.ServeHTTP(writer, req)
}

// Confusing test name. Tests that nosurf's context is accessible
// when a request with golang's context is passed into Token().
func TestContextIsAccessibleWithContext(t *testing.T) {
	succHand := func(w http.ResponseWriter, r *http.Request) {
		r = r.WithContext(context.WithValue(r.Context(), "dummykey", "dummyval"))
		token := Token(r)
		if token == "" {
			t.Errorf("Token is inaccessible in the success handler")
		}
	}

	hand := New(http.HandlerFunc(succHand))

	// we need a request that passes. Let's just use a safe method for that.
	req := dummyGet()
	writer := httptest.NewRecorder()

	hand.ServeHTTP(writer, req)
}

func TestEmptyRefererFails(t *testing.T) {
	hand := New(http.HandlerFunc(succHand))
	fhand := correctReason(t, ErrNoReferer)
	hand.SetFailureHandler(fhand)

	req, err := http.NewRequest("POST", "https://dummy.us/", strings.NewReader("a=b"))
	if err != nil {
		t.Fatal(err)
	}
	writer := httptest.NewRecorder()

	hand.ServeHTTP(writer, req)

	if writer.Code != FailureCode {
		t.Errorf("A POST request with no Referer should have failed with the code %d, but it didn't.",
			writer.Code)
	}
}

func TestDifferentOriginRefererFails(t *testing.T) {
	hand := New(http.HandlerFunc(succHand))
	fhand := correctReason(t, ErrBadReferer)
	hand.SetFailureHandler(fhand)

	req, err := http.NewRequest("POST", "https://dummy.us/", strings.NewReader("a=b"))
	if err != nil {
		t.Fatal(err)
	}
	req.Header.Set("Referer", "http://attack-on-golang.com")
	writer := httptest.NewRecorder()

	hand.ServeHTTP(writer, req)

	if writer.Code != FailureCode {
		t.Errorf("A POST request with a Referer from a different origin"+
			"should have failed with the code %d, but it didn't.", writer.Code)
	}
}

func TestNoTokenFails(t *testing.T) {
	hand := New(http.HandlerFunc(succHand))
	fhand := correctReason(t, ErrBadToken)
	hand.SetFailureHandler(fhand)

	vals := [][]string{
		{"name", "Jolene"},
	}

	req, err := http.NewRequest("POST", "http://dummy.us", formBodyR(vals))
	if err != nil {
		panic(err)
	}
	writer := httptest.NewRecorder()

	hand.ServeHTTP(writer, req)

	if writer.Code != FailureCode {
		t.Errorf("The check should've failed with the code %d, but instead, it"+
			" returned code %d", FailureCode, writer.Code)
	}

	expectedContentType := "text/plain; charset=utf-8"
	actualContentType := writer.Header().Get("Content-Type")
	if actualContentType != expectedContentType {
		t.Errorf("The check should've failed with content type %s, but instead, it"+
			" returned content type %s", expectedContentType, actualContentType)
	}
}

func TestWrongTokenFails(t *testing.T) {
	hand := New(http.HandlerFunc(succHand))
	fhand := correctReason(t, ErrBadToken)
	hand.SetFailureHandler(fhand)

	vals := [][]string{
		{"name", "Jolene"},
		// this won't EVER be a valid value with the current scheme
		{FormFieldName, "$#%^&"},
	}

	req, err := http.NewRequest("POST", "http://dummy.us", formBodyR(vals))
	if err != nil {
		panic(err)
	}
	writer := httptest.NewRecorder()

	hand.ServeHTTP(writer, req)

	if writer.Code != FailureCode {
		t.Errorf("The check should've failed with the code %d, but instead, it"+
			" returned code %d", FailureCode, writer.Code)
	}

	expectedContentType := "text/plain; charset=utf-8"
	actualContentType := writer.Header().Get("Content-Type")
	if actualContentType != expectedContentType {
		t.Errorf("The check should've failed with content type %s, but instead, it"+
			" returned content type %s", expectedContentType, actualContentType)
	}
}

// For this and similar tests we start a test server
// Since it's much easier to get the cookie
// from a normal http.Response than from the recorder
func TestCorrectTokenPasses(t *testing.T) {
	hand := New(http.HandlerFunc(succHand))
	hand.SetFailureHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		t.Errorf("Test failed. Reason: %v", Reason(r))
	}))

	server := httptest.NewServer(hand)
	defer server.Close()

	// issue the first request to get the token
	resp, err := http.Get(server.URL)
	if err != nil {
		t.Fatal(err)
	}

	cookie := getRespCookie(resp, CookieName)
	if cookie == nil {
		t.Fatal("Cookie was not found in the response.")
	}

	finalToken := b64encode(maskToken(b64decode(cookie.Value)))

	vals := [][]string{
		{"name", "Jolene"},
		{FormFieldName, finalToken},
	}

	// Test usual POST
	/*
		{
			req, err := http.NewRequest("POST", server.URL, formBodyR(vals))
			if err != nil {
				t.Fatal(err)
			}
			req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
			req.AddCookie(cookie)

			resp, err = http.DefaultClient.Do(req)

			if err != nil {
				t.Fatal(err)
			}
			if resp.StatusCode != 200 {
				t.Errorf("The request should have succeeded, but it didn't. Instead, the code was %d",
					resp.StatusCode)
			}
		}
	*/

	// Test multipart
	{
		prd, pwr := io.Pipe()
		wr := multipart.NewWriter(pwr)
		go func() {

			for _, v := range vals {
				wr.WriteField(v[0], v[1])
			}

			err := wr.Close()
			if err != nil {
				t.Fatal(err)
			}
			err = pwr.Close()
			if err != nil {
				t.Fatal(err)
			}
		}()

		// Prepare a multipart request
		req, err := http.NewRequest("POST", server.URL, prd)
		if err != nil {
			t.Fatal(err)
		}

		req.Header.Add("Content-Type", wr.FormDataContentType())
		req.AddCookie(cookie)

		resp, err := http.DefaultClient.Do(req)
		if err != nil {
			t.Fatal(err)
		}
		if resp.StatusCode != 200 {
			t.Errorf("The request should have succeeded, but it didn't. Instead, the code was %d",
				resp.StatusCode)
		}
	}
}

func TestPrefersHeaderOverFormValue(t *testing.T) {
	// Let's do a nice trick to find out this:
	// We'll set the correct token in the header
	// And a wrong one in the form.
	// That way, if it succeeds,
	// it will mean that it prefered the header.

	hand := New(http.HandlerFunc(succHand))

	server := httptest.NewServer(hand)
	defer server.Close()

	resp, err := http.Get(server.URL)
	if err != nil {
		t.Fatal(err)
	}

	cookie := getRespCookie(resp, CookieName)
	if cookie == nil {
		t.Fatal("Cookie was not found in the response.")
	}

	finalToken := b64encode(maskToken(b64decode(cookie.Value)))

	vals := [][]string{
		{"name", "Jolene"},
		{FormFieldName, "a very wrong value"},
	}

	req, err := http.NewRequest("POST", server.URL, formBodyR(vals))
	if err != nil {
		t.Fatal(err)
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Set(HeaderName, finalToken)
	req.AddCookie(cookie)

	resp, err = http.DefaultClient.Do(req)

	if err != nil {
		t.Fatal(err)
	}
	if resp.StatusCode != 200 {
		t.Errorf("The request should have succeeded, but it didn't. Instead, the code was %d",
			resp.StatusCode)
	}
}

func TestAddsVaryCookieHeader(t *testing.T) {
	hand := New(http.HandlerFunc(succHand))
	writer := httptest.NewRecorder()
	req := dummyGet()

	hand.ServeHTTP(writer, req)

	if !sContains(writer.Header()["Vary"], "Cookie") {
		t.Errorf("CSRFHandler didn't add a `Vary: Cookie` header.")
	}
}
<|endoftext|>


<commit_before>package handlers

import (
	"net/http"
	"time"

	"fmt"

	"github.com/gorilla/feeds"
	"github.com/gorilla/mux"
	"github.com/teambrookie/showrss/betaseries"
	"github.com/teambrookie/showrss/dao"
)

type rssHandler struct {
	store           dao.EpisodeStore
	episodeProvider betaseries.EpisodeProvider
}

func (h *rssHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	token := mux.Vars(r)["user"]
	if token == "" {
		http.Error(w, "token must be set in query params", http.StatusNotAcceptable)
		return
	}

	now := time.Now()
	feed := &feeds.Feed{
		Title:       "ShowRSS by binou",
		Link:        &feeds.Link{Href: "https://github.com/TeamBrookie/showrss"},
		Description: "A list of torrent for your unseen Betaseries episodes",
		Author:      &feeds.Author{Name: "Fabien Foerster", Email: "fabienfoerster@gmail.com"},
		Created:     now,
	}
	episodes, err := h.episodeProvider.Episodes(token)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	for _, ep := range episodes {
		episode, err := h.store.GetEpisode(ep.Name)
		if episode.MagnetLink == "" || err != nil {
			continue
		}
		description := fmt.Sprintf("MagnetLink", episode.MagnetLink)
		item := &feeds.Item{
			Title:       episode.Name,
			Link:        &feeds.Link{Href: episode.MagnetLink},
			Description: description,
			Created:     episode.LastModified,
		}
		feed.Add(item)
	}

	w.Header().Set("Content-Type", "text/xml")
	feed.WriteRss(w)
	return

}

func RSSHandler(store dao.EpisodeStore, episodeProvider betaseries.EpisodeProvider) http.Handler {
	return &rssHandler{
		store:           store,
		episodeProvider: episodeProvider,
	}
}
<commit_msg>add missing return on error<commit_after>package handlers

import (
	"net/http"
	"time"

	"fmt"

	"github.com/gorilla/feeds"
	"github.com/gorilla/mux"
	"github.com/teambrookie/showrss/betaseries"
	"github.com/teambrookie/showrss/dao"
)

type rssHandler struct {
	store           dao.EpisodeStore
	episodeProvider betaseries.EpisodeProvider
}

func (h *rssHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	token := mux.Vars(r)["user"]
	if token == "" {
		http.Error(w, "token must be set in query params", http.StatusNotAcceptable)
		return
	}

	now := time.Now()
	feed := &feeds.Feed{
		Title:       "ShowRSS by binou",
		Link:        &feeds.Link{Href: "https://github.com/TeamBrookie/showrss"},
		Description: "A list of torrent for your unseen Betaseries episodes",
		Author:      &feeds.Author{Name: "Fabien Foerster", Email: "fabienfoerster@gmail.com"},
		Created:     now,
	}
	episodes, err := h.episodeProvider.Episodes(token)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	for _, ep := range episodes {
		episode, err := h.store.GetEpisode(ep.Name)
		if episode.MagnetLink == "" || err != nil {
			continue
		}
		description := fmt.Sprintf("MagnetLink", episode.MagnetLink)
		item := &feeds.Item{
			Title:       episode.Name,
			Link:        &feeds.Link{Href: episode.MagnetLink},
			Description: description,
			Created:     episode.LastModified,
		}
		feed.Add(item)
	}

	w.Header().Set("Content-Type", "text/xml")
	feed.WriteRss(w)
	return

}

func RSSHandler(store dao.EpisodeStore, episodeProvider betaseries.EpisodeProvider) http.Handler {
	return &rssHandler{
		store:           store,
		episodeProvider: episodeProvider,
	}
}
<|endoftext|>


<commit_before>package hashids

import (
	"testing"
)

func TestEncryptDecrypt(t *testing.T) {
	hdata := NewData()
	hdata.MinLength = 30
	hdata.Salt = "this is my salt"

	hid := NewWithData(hdata)

	numbers := []int{45, 434, 1313, 99}
	hash, err := hid.Encode(numbers)
	if err != nil {
		t.Fatal(err)
	}
	dec := hid.Decode(hash)

	t.Logf("%v -> %v -> %v", numbers, hash, dec)

	if len(numbers) != len(dec) {
		t.Error("lengths do not match")
	}

	for i, n := range numbers {
		if n != dec[i] {
			t.Fail()
		}
	}
}

func TestDefaultLength(t *testing.T) {
	hdata := NewData()
	hdata.Salt = "this is my salt"

	hid := NewWithData(hdata)

	numbers := []int{45, 434, 1313, 99}
	hash, err := hid.Encode(numbers)
	if err != nil {
		t.Fatal(err)
	}
	dec := hid.Decode(hash)

	t.Logf("%v -> %v -> %v", numbers, hash, dec)

	if len(numbers) != len(dec) {
		t.Error("lengths do not match")
	}

	for i, n := range numbers {
		if n != dec[i] {
			t.Fail()
		}
	}
}

func TestMinLength(t *testing.T) {
	hdata := NewData()
	hdata.Salt = "salt1"
	hdata.MinLength = 10
	hid := NewWithData(hdata)
	hid.Encode([]int{0})
}

func TestCustomAlphabet(t *testing.T) {
	hdata := NewData()
	hdata.Alphabet = "PleasAkMEFoThStx"
	hdata.Salt = "this is my salt"

	hid := NewWithData(hdata)

	numbers := []int{45, 434, 1313, 99}
	hash, err := hid.Encode(numbers)
	if err != nil {
		t.Fatal(err)
	}
	dec := hid.Decode(hash)

	t.Logf("%v -> %v -> %v", numbers, hash, dec)

	if len(numbers) != len(dec) {
		t.Error("lengths do not match")
	}

	for i, n := range numbers {
		if n != dec[i] {
			t.Fail()
		}
	}
}
<commit_msg>Add known hash tests<commit_after>package hashids

import (
	"testing"
)

func TestEncryptDecrypt(t *testing.T) {
	hdata := NewData()
	hdata.MinLength = 30
	hdata.Salt = "this is my salt"

	hid := NewWithData(hdata)

	numbers := []int{45, 434, 1313, 99}
	hash, err := hid.Encode(numbers)
	if err != nil {
		t.Fatal(err)
	}
	dec := hid.Decode(hash)

	t.Logf("%v -> %v -> %v", numbers, hash, dec)

	if len(numbers) != len(dec) {
		t.Error("lengths do not match")
	}

	for i, n := range numbers {
		if n != dec[i] {
			t.Fail()
		}
	}
}

func TestEncryptWithKnownHash(t *testing.T) {
	hdata := NewData()
	hdata.MinLength = 0
	hdata.Salt = "this is my salt"

	hid := NewWithData(hdata)

	numbers := []int{45, 434, 1313, 99}
	hash, err := hid.Encode(numbers)
	if err != nil {
		t.Fatal(err)
	}

	t.Logf("%v -> %v", numbers, hash)

	if hash != "7nnhzEsDkiYa" {
		t.Error("hash does not match expected one")
	}
}

func TestDecryptWithKnownHash(t *testing.T) {
	hdata := NewData()
	hdata.MinLength = 0
	hdata.Salt = "this is my salt"

	hid := NewWithData(hdata)

	hash := "7nnhzEsDkiYa"
	numbers := hid.Decode(hash)

	t.Logf("%v -> %v", hash, numbers)

	expected := []int{45, 434, 1313, 99}
	for i, n := range numbers {
		if n != expected[i] {
			t.Fail()
		}
	}
}

func TestDefaultLength(t *testing.T) {
	hdata := NewData()
	hdata.Salt = "this is my salt"

	hid := NewWithData(hdata)

	numbers := []int{45, 434, 1313, 99}
	hash, err := hid.Encode(numbers)
	if err != nil {
		t.Fatal(err)
	}
	dec := hid.Decode(hash)

	t.Logf("%v -> %v -> %v", numbers, hash, dec)

	if len(numbers) != len(dec) {
		t.Error("lengths do not match")
	}

	for i, n := range numbers {
		if n != dec[i] {
			t.Fail()
		}
	}
}

func TestMinLength(t *testing.T) {
	hdata := NewData()
	hdata.Salt = "salt1"
	hdata.MinLength = 10
	hid := NewWithData(hdata)
	hid.Encode([]int{0})
}

func TestCustomAlphabet(t *testing.T) {
	hdata := NewData()
	hdata.Alphabet = "PleasAkMEFoThStx"
	hdata.Salt = "this is my salt"

	hid := NewWithData(hdata)

	numbers := []int{45, 434, 1313, 99}
	hash, err := hid.Encode(numbers)
	if err != nil {
		t.Fatal(err)
	}
	dec := hid.Decode(hash)

	t.Logf("%v -> %v -> %v", numbers, hash, dec)

	if len(numbers) != len(dec) {
		t.Error("lengths do not match")
	}

	for i, n := range numbers {
		if n != dec[i] {
			t.Fail()
		}
	}
}
<|endoftext|>