<commit_before>package main

type raynode struct {
	Cost int
}

type rayMap map[position]*raynode

func (rm rayMap) get(p position) *raynode {
	r, ok := rm[p]
	if !ok {
		r = &raynode{}
		rm[p] = r
	}
	return r
}

func (g *game) bestParent(rm rayMap, from, pos position) (position, int) {
	p := pos.Parents(from)
	b := p[0]
	if len(p) > 1 && rm[p[1]].Cost+g.losCost(p[1]) < rm[b].Cost+g.losCost(b) {
		b = p[1]
	}
	return b, rm[b].Cost + g.losCost(b)
}

func (g *game) losCost(pos position) int {
	if g.Player.Pos == pos {
		return 0
	}
	c := g.Dungeon.Cell(pos)
	if c.T == WallCell {
		return g.LosRange()
	}
	if _, ok := g.Clouds[pos]; ok {
		return g.LosRange()
	}
	if _, ok := g.Doors[pos]; ok {
		if pos != g.Player.Pos {
			mons, _ := g.MonsterAt(pos)
			if !mons.Exists() {
				return g.LosRange()
			}
		}
	}
	if _, ok := g.Fungus[pos]; ok {
		return g.LosRange() - 1
	}
	return 1
}

func (g *game) buildRayMap(from position, distance int) rayMap {
	rm := rayMap{}
	rm[from] = &raynode{Cost: 0}
	for d := 1; d <= distance; d++ {
		for x := -d + from.X; x <= d+from.X; x++ {
			for _, pos := range []position{{x, from.Y + d}, {x, from.Y - d}} {
				if !pos.valid() {
					continue
				}
				_, c := g.bestParent(rm, from, pos)
				rm[pos] = &raynode{Cost: c}
			}
		}
		for y := -d + 1 + from.Y; y <= d-1+from.Y; y++ {
			for _, pos := range []position{{from.X + d, y}, {from.X - d, y}} {
				if !pos.valid() {
					continue
				}
				_, c := g.bestParent(rm, from, pos)
				rm[pos] = &raynode{Cost: c}
			}
		}
	}
	return rm
}

func (g *game) LosRange() int {
	losRange := 6
	if g.Player.Aptitudes[AptStealthyLOS] {
		losRange -= 2
	}
	return losRange
}

func (g *game) StopAuto() {
	g.AutoHalt = true
	g.AutoDir = nil
	g.AutoTarget = nil
	g.Resting = false
}

func (g *game) ComputeLOS() {
	m := map[position]bool{}
	losRange := g.LosRange()
	g.Player.Rays = g.buildRayMap(g.Player.Pos, losRange)
	for pos, n := range g.Player.Rays {
		if n.Cost < g.LosRange() {
			m[pos] = true
			g.SeePosition(pos)
		}
	}
	g.Player.LOS = m
	for _, mons := range g.Monsters {
		if !mons.Seen && mons.Exists() && g.Player.LOS[mons.Pos] {
			mons.Seen = true
			if mons.Kind.Dangerousness() > 10 {
				g.StoryPrint(mons.Kind.SeenStoryText())
			}
		}
	}
}

func (g *game) SeePosition(pos position) {
	if !g.Dungeon.Cell(pos).Explored {
		if c, ok := g.Collectables[pos]; ok {
			g.StopAuto()
			if c.Quantity > 1 {
				g.Printf("You see %d %s.", c.Quantity, c.Consumable.Plural())
			} else {
				g.Printf("You see %s.", Indefinite(c.Consumable.String(), false))
			}
		} else if _, ok := g.Stairs[pos]; ok {
			g.StopAuto()
			g.Printf("You see stairs.")
		} else if eq, ok := g.Equipables[pos]; ok {
			g.StopAuto()
			g.Printf("You see %s.", Indefinite(eq.String(), false))
		} else if rod, ok := g.Rods[pos]; ok {
			g.StopAuto()
			g.Printf("You see %s.", Indefinite(rod.String(), false))
		}
		g.FairAction()
		g.Dungeon.SetExplored(pos)
		g.DijkstraMapRebuild = true
	} else if g.UnknownDig[pos] {
		g.StopAuto()
		g.Printf("There is no more a wall there.")
		g.DijkstraMapRebuild = true
	}
	if g.UnknownDig[pos] {
		delete(g.UnknownDig, pos)
		delete(g.TemporalWalls, pos)
	}
}

func (g *game) ComputeExclusion(pos position, toggle bool) {
	exclusionRange := g.LosRange()
	rays := g.buildRayMap(pos, exclusionRange)
	for pos, n := range rays {
		if n.Cost < g.LosRange() {
			g.ExclusionsMap[pos] = toggle
		}
	}
	for d := 1; d <= exclusionRange; d++ {
		for x := -d + pos.X; x <= d+pos.X; x++ {
			for _, pos := range []position{{x, pos.Y + d}, {x, pos.Y - d}} {
				if !pos.valid() {
					continue
				}
				if !g.Player.LOS[pos] {
					g.ExclusionsMap[pos] = toggle
				}
			}
		}
		for y := -d + 1 + pos.Y; y <= d-1+pos.Y; y++ {
			for _, pos := range []position{{pos.X + d, y}, {pos.X - d, y}} {
				if !pos.valid() {
					continue
				}
				if !g.Player.LOS[pos] {
					g.ExclusionsMap[pos] = toggle
				}
			}
		}
	}
}

func (g *game) Ray(pos position) []position {
	if !g.Player.LOS[pos] {
		return nil
	}
	ray := []position{}
	for pos != g.Player.Pos {
		ray = append(ray, pos)
		pos, _ = g.bestParent(g.Player.Rays, g.Player.Pos, pos)
	}
	return ray
}

func (g *game) ComputeRayHighlight(pos position) {
	g.Highlight = map[position]bool{}
	ray := g.Ray(pos)
	for _, p := range ray {
		g.Highlight[p] = true
	}
}

func (g *game) ComputeNoise() {
	dij := &noisePath{game: g}
	nm := Dijkstra(dij, []position{g.Player.Pos}, g.LosRange()+2)
	count := 0
	noise := map[position]bool{}
	for pos := range nm {
		if g.Player.LOS[pos] {
			continue
		}
		mons, _ := g.MonsterAt(pos)
		if mons.Exists() && mons.State != Resting && RandInt(3) == 0 {
			switch mons.Kind {
			case MonsMirrorSpecter, MonsGiantBee, MonsSatowalgaPlant:
				// no footsteps
			default:
				noise[pos] = true
				count++
			}
		}
	}
	if count > 0 {
		if count > 1 {
			g.Printf("You hear some footsteps (%dx).", count)
		} else {
			g.Print("You hear some footsteps.")
		}
		g.StopAuto()
	}
	g.Noise = noise
}
<commit_msg>increase excluded zones radius by one, because it generally is what you want<commit_after>package main

type raynode struct {
	Cost int
}

type rayMap map[position]*raynode

func (rm rayMap) get(p position) *raynode {
	r, ok := rm[p]
	if !ok {
		r = &raynode{}
		rm[p] = r
	}
	return r
}

func (g *game) bestParent(rm rayMap, from, pos position) (position, int) {
	p := pos.Parents(from)
	b := p[0]
	if len(p) > 1 && rm[p[1]].Cost+g.losCost(p[1]) < rm[b].Cost+g.losCost(b) {
		b = p[1]
	}
	return b, rm[b].Cost + g.losCost(b)
}

func (g *game) losCost(pos position) int {
	if g.Player.Pos == pos {
		return 0
	}
	c := g.Dungeon.Cell(pos)
	if c.T == WallCell {
		return g.LosRange()
	}
	if _, ok := g.Clouds[pos]; ok {
		return g.LosRange()
	}
	if _, ok := g.Doors[pos]; ok {
		if pos != g.Player.Pos {
			mons, _ := g.MonsterAt(pos)
			if !mons.Exists() {
				return g.LosRange()
			}
		}
	}
	if _, ok := g.Fungus[pos]; ok {
		return g.LosRange() - 1
	}
	return 1
}

func (g *game) buildRayMap(from position, distance int) rayMap {
	rm := rayMap{}
	rm[from] = &raynode{Cost: 0}
	for d := 1; d <= distance; d++ {
		for x := -d + from.X; x <= d+from.X; x++ {
			for _, pos := range []position{{x, from.Y + d}, {x, from.Y - d}} {
				if !pos.valid() {
					continue
				}
				_, c := g.bestParent(rm, from, pos)
				rm[pos] = &raynode{Cost: c}
			}
		}
		for y := -d + 1 + from.Y; y <= d-1+from.Y; y++ {
			for _, pos := range []position{{from.X + d, y}, {from.X - d, y}} {
				if !pos.valid() {
					continue
				}
				_, c := g.bestParent(rm, from, pos)
				rm[pos] = &raynode{Cost: c}
			}
		}
	}
	return rm
}

func (g *game) LosRange() int {
	losRange := 6
	if g.Player.Aptitudes[AptStealthyLOS] {
		losRange -= 2
	}
	return losRange
}

func (g *game) StopAuto() {
	g.AutoHalt = true
	g.AutoDir = nil
	g.AutoTarget = nil
	g.Resting = false
}

func (g *game) ComputeLOS() {
	m := map[position]bool{}
	losRange := g.LosRange()
	g.Player.Rays = g.buildRayMap(g.Player.Pos, losRange)
	for pos, n := range g.Player.Rays {
		if n.Cost < g.LosRange() {
			m[pos] = true
			g.SeePosition(pos)
		}
	}
	g.Player.LOS = m
	for _, mons := range g.Monsters {
		if !mons.Seen && mons.Exists() && g.Player.LOS[mons.Pos] {
			mons.Seen = true
			if mons.Kind.Dangerousness() > 10 {
				g.StoryPrint(mons.Kind.SeenStoryText())
			}
		}
	}
}

func (g *game) SeePosition(pos position) {
	if !g.Dungeon.Cell(pos).Explored {
		if c, ok := g.Collectables[pos]; ok {
			g.StopAuto()
			if c.Quantity > 1 {
				g.Printf("You see %d %s.", c.Quantity, c.Consumable.Plural())
			} else {
				g.Printf("You see %s.", Indefinite(c.Consumable.String(), false))
			}
		} else if _, ok := g.Stairs[pos]; ok {
			g.StopAuto()
			g.Printf("You see stairs.")
		} else if eq, ok := g.Equipables[pos]; ok {
			g.StopAuto()
			g.Printf("You see %s.", Indefinite(eq.String(), false))
		} else if rod, ok := g.Rods[pos]; ok {
			g.StopAuto()
			g.Printf("You see %s.", Indefinite(rod.String(), false))
		}
		g.FairAction()
		g.Dungeon.SetExplored(pos)
		g.DijkstraMapRebuild = true
	} else if g.UnknownDig[pos] {
		g.StopAuto()
		g.Printf("There is no more a wall there.")
		g.DijkstraMapRebuild = true
	}
	if g.UnknownDig[pos] {
		delete(g.UnknownDig, pos)
		delete(g.TemporalWalls, pos)
	}
}

func (g *game) ComputeExclusion(pos position, toggle bool) {
	exclusionRange := g.LosRange()
	rays := g.buildRayMap(pos, exclusionRange)
	for pos, n := range rays {
		if n.Cost <= g.LosRange() {
			g.ExclusionsMap[pos] = toggle
		}
	}
	for d := 1; d <= exclusionRange; d++ {
		for x := -d + pos.X; x <= d+pos.X; x++ {
			for _, pos := range []position{{x, pos.Y + d}, {x, pos.Y - d}} {
				if !pos.valid() {
					continue
				}
				if !g.Player.LOS[pos] {
					g.ExclusionsMap[pos] = toggle
				}
			}
		}
		for y := -d + 1 + pos.Y; y <= d-1+pos.Y; y++ {
			for _, pos := range []position{{pos.X + d, y}, {pos.X - d, y}} {
				if !pos.valid() {
					continue
				}
				if !g.Player.LOS[pos] {
					g.ExclusionsMap[pos] = toggle
				}
			}
		}
	}
}

func (g *game) Ray(pos position) []position {
	if !g.Player.LOS[pos] {
		return nil
	}
	ray := []position{}
	for pos != g.Player.Pos {
		ray = append(ray, pos)
		pos, _ = g.bestParent(g.Player.Rays, g.Player.Pos, pos)
	}
	return ray
}

func (g *game) ComputeRayHighlight(pos position) {
	g.Highlight = map[position]bool{}
	ray := g.Ray(pos)
	for _, p := range ray {
		g.Highlight[p] = true
	}
}

func (g *game) ComputeNoise() {
	dij := &noisePath{game: g}
	nm := Dijkstra(dij, []position{g.Player.Pos}, g.LosRange()+2)
	count := 0
	noise := map[position]bool{}
	for pos := range nm {
		if g.Player.LOS[pos] {
			continue
		}
		mons, _ := g.MonsterAt(pos)
		if mons.Exists() && mons.State != Resting && RandInt(3) == 0 {
			switch mons.Kind {
			case MonsMirrorSpecter, MonsGiantBee, MonsSatowalgaPlant:
				// no footsteps
			default:
				noise[pos] = true
				count++
			}
		}
	}
	if count > 0 {
		if count > 1 {
			g.Printf("You hear some footsteps (%dx).", count)
		} else {
			g.Print("You hear some footsteps.")
		}
		g.StopAuto()
	}
	g.Noise = noise
}
<|endoftext|>


<commit_before>package main

import "fmt"
import "io"
import "os"
import "os/exec"
import "strings"
import "unsafe"

import . "./lua"
import "./alias"
import "./conio"
import "./dos"
import "./interpreter"
import "./mbcs"

import "github.com/shiena/ansicolor"

const nyagos_exec_cmd = "nyagos.exec.cmd"

type LuaFunction struct {
	L            *Lua
	registoryKey string
}

func (this LuaFunction) String() string {
	return "<<Lua-function>>"
}

func (this LuaFunction) Call(cmd *exec.Cmd) (interpreter.NextT, error) {
	this.L.GetField(Registory, this.registoryKey)
	this.L.NewTable()
	for i, arg1 := range cmd.Args {
		this.L.PushInteger(i)
		this.L.PushString(arg1)
		this.L.SetTable(-3)
	}
	this.L.PushLightUserData(unsafe.Pointer(cmd))
	this.L.SetField(Registory, nyagos_exec_cmd)
	err := this.L.Call(1, 0)
	return interpreter.CONTINUE, err
}

func cmdAlias(L *Lua) int {
	name, nameErr := L.ToString(1)
	if nameErr != nil {
		L.PushNil()
		L.PushString(nameErr.Error())
		return 2
	}
	key := strings.ToLower(name)
	switch L.GetType(2) {
	case TSTRING:
		value, err := L.ToString(2)
		if err == nil {
			alias.Table[key] = alias.New(value)
		} else {
			L.PushNil()
			L.PushString(err.Error())
			return 2
		}
	case TFUNCTION:
		regkey := "nyagos.alias." + key
		L.SetField(Registory, regkey)
		alias.Table[key] = LuaFunction{L, regkey}
	}
	L.PushBool(true)
	return 1
}

func cmdSetEnv(L *Lua) int {
	name, nameErr := L.ToString(1)
	if nameErr != nil {
		L.PushNil()
		L.PushString(nameErr.Error())
		return 2
	}
	value, valueErr := L.ToString(2)
	if valueErr != nil {
		L.PushNil()
		L.PushString(valueErr.Error())
		return 2
	}
	os.Setenv(name, value)
	L.PushBool(true)
	return 1
}

func cmdGetEnv(L *Lua) int {
	name, nameErr := L.ToString(1)
	if nameErr != nil {
		L.PushNil()
		return 1
	}
	value := os.Getenv(name)
	if len(value) > 0 {
		L.PushString(value)
	} else {
		L.PushNil()
	}
	return 1
}

func cmdExec(L *Lua) int {
	statement, statementErr := L.ToString(1)
	if statementErr != nil {
		L.PushNil()
		L.PushString(statementErr.Error())
		return 2
	}
	_, err := interpreter.Interpret(statement, nil)

	if err != nil {
		L.PushNil()
		L.PushString(err.Error())
		return 2
	}
	L.PushBool(true)
	return 1
}

func cmdEval(L *Lua) int {
	statement, statementErr := L.ToString(1)
	if statementErr != nil {
		L.PushNil()
		L.PushString(statementErr.Error())
		return 2
	}
	r, w, err := os.Pipe()
	if err != nil {
		L.PushNil()
		L.PushString(err.Error())
		return 2
	}
	go func(statement string, w *os.File) {
		interpreter.Interpret(statement, &interpreter.Stdio{Stdout: w})
		w.Close()
	}(statement, w)

	var result = []byte{}
	for {
		buffer := make([]byte, 256)
		size, err := r.Read(buffer)
		if err != nil || size <= 0 {
			break
		}
		result = append(result, buffer[0:size]...)
	}
	r.Close()
	L.PushAnsiString(result)
	return 1
}

func cmdWrite(L *Lua) int {
	var out io.Writer = os.Stdout
	L.GetField(Registory, nyagos_exec_cmd)
	if L.GetType(-1) == TLIGHTUSERDATA {
		if cmd := (*exec.Cmd)(L.ToUserData(-1)); cmd != nil {
			out = cmd.Stdout
		}
	}
	L.Pop(1)
	out = ansicolor.NewAnsiColorWriter(out)

	n := L.GetTop()
	for i := 1; i <= n; i++ {
		str, err := L.ToString(i)
		if err != nil {
			L.PushNil()
			L.PushString(err.Error())
			return 2
		}
		if i > 1 {
			fmt.Fprint(out, "\t")
		}
		fmt.Fprint(out, str)
	}
	L.PushBool(true)
	return 1
}

func cmdGetwd(L *Lua) int {
	wd, err := os.Getwd()
	if err == nil {
		L.PushString(wd)
		return 1
	} else {
		return 0
	}
}

func cmdWhich(L *Lua) int {
	if L.GetType(-1) != TSTRING {
		return 0
	}
	name, nameErr := L.ToString(-1)
	if nameErr != nil {
		L.PushNil()
		L.PushString(nameErr.Error())
		return 2
	}
	path, err := exec.LookPath(name)
	if err == nil {
		L.PushString(path)
		return 1
	} else {
		L.PushNil()
		L.PushString(err.Error())
		return 2
	}
}

func cmdAtoU(L *Lua) int {
	str, err := mbcs.AtoU(L.ToAnsiString(1))
	if err == nil {
		L.PushString(str)
		return 1
	} else {
		return 0
	}
}

func cmdUtoA(L *Lua) int {
	utf8, utf8err := L.ToString(1)
	if utf8err != nil {
		L.PushNil()
		L.PushString(utf8err.Error())
		return 2
	}
	str, err := mbcs.UtoA(utf8)
	if err == nil {
		if len(str) >= 1 {
			L.PushAnsiString(str[:len(str)-1])
		} else {
			L.PushString("")
		}
		L.PushNil()
		return 2
	} else {
		L.PushNil()
		L.PushString(err.Error())
		return 2
	}
}

func cmdGlob(L *Lua) int {
	if !L.IsString(-1) {
		return 0
	}
	wildcard, wildcardErr := L.ToString(-1)
	if wildcardErr != nil {
		L.PushNil()
		L.PushString(wildcardErr.Error())
		return 2
	}
	list, err := dos.Glob(wildcard)
	if err != nil {
		L.PushNil()
		L.PushString(err.Error())
		return 2
	} else {
		L.NewTable()
		for i := 0; i < len(list); i++ {
			L.PushInteger(i + 1)
			L.PushString(list[i])
			L.SetTable(-3)
		}
		return 1
	}
}

func cmdBindKey(L *Lua) int {
	key, keyErr := L.ToString(-2)
	if keyErr != nil {
		L.PushString(keyErr.Error())
		return 1
	}
	val, valErr := L.ToString(-1)
	if valErr != nil {
		L.PushString(valErr.Error())
		return 1
	}
	err := conio.BindKeySymbol(key, val)
	if err != nil {
		L.PushNil()
		L.PushString(err.Error())
		return 2
	} else {
		L.PushBool(true)
		return 1
	}
}

func SetLuaFunctions(this *Lua) {
	stackPos := this.GetTop()
	defer this.SetTop(stackPos)
	this.NewTable()
	this.PushGoFunction(cmdAlias)
	this.SetField(-2, "alias")
	this.PushGoFunction(cmdSetEnv)
	this.SetField(-2, "setenv")
	this.PushGoFunction(cmdGetEnv)
	this.SetField(-2, "getenv")
	this.PushGoFunction(cmdExec)
	this.SetField(-2, "exec")
	this.PushGoFunction(cmdWrite)
	this.SetField(-2, "write")
	this.PushGoFunction(cmdAtoU)
	this.SetField(-2, "atou")
	this.PushGoFunction(cmdUtoA)
	this.SetField(-2, "utoa")
	this.PushGoFunction(cmdGetwd)
	this.SetField(-2, "getwd")
	this.PushGoFunction(cmdWhich)
	this.SetField(-2, "which")
	this.PushGoFunction(cmdEval)
	this.SetField(-2, "eval")
	this.PushGoFunction(cmdGlob)
	this.SetField(-2, "glob")
	this.PushGoFunction(cmdBindKey)
	this.SetField(-2, "bindkey")
	exeName, exeNameErr := dos.GetModuleFileName()
	if exeNameErr != nil {
		fmt.Fprintln(os.Stderr, exeNameErr)
	} else {
		this.PushString(exeName)
		this.SetField(-2, "exe")
	}
	this.SetGlobal("nyagos")

	// replace io.getenv
	this.GetGlobal("os")
	this.PushGoFunction(cmdGetEnv)
	this.SetField(-2, "getenv")

	var orgArgHook func([]string) []string
	orgArgHook = interpreter.SetArgsHook(func(args []string) []string {
		pos := this.GetTop()
		defer this.SetTop(pos)
		this.GetGlobal("nyagos")
		this.GetField(-1, "argsfilter")
		if !this.IsFunction(-1) {
			return orgArgHook(args)
		}
		this.NewTable()
		for i := 0; i < len(args); i++ {
			this.PushInteger(i)
			this.PushString(args[i])
			this.SetTable(-3)
		}
		if err := this.Call(1, 1); err != nil {
			fmt.Fprintf(os.Stderr, "%s\n", err)
			return orgArgHook(args)
		}
		if this.GetType(-1) != TTABLE {
			return orgArgHook(args)
		}
		newargs := []string{}
		for i := 0; true; i++ {
			this.PushInteger(i)
			this.GetTable(-2)
			if this.GetType(-1) == TNIL {
				break
			}
			arg1, arg1err := this.ToString(-1)
			if arg1err == nil {
				newargs = append(newargs, arg1)
			} else {
				fmt.Fprintln(os.Stderr, arg1err.Error())
			}
			this.Pop(1)
		}
		return orgArgHook(newargs)
	})
}
<commit_msg>nyagos.writeが落ちるので、標準入出力の受渡しにLuaのレジストリを使わず、Go側のマップを使うようにした<commit_after>package main

import "fmt"
import "io"
import "os"
import "os/exec"
import "strings"

import . "./lua"
import "./alias"
import "./conio"
import "./dos"
import "./interpreter"
import "./mbcs"

import "github.com/shiena/ansicolor"

type LuaFunction struct {
	L            *Lua
	registoryKey string
}

var LuaInstanceToCmd = map[*Lua]*exec.Cmd{}

func (this LuaFunction) String() string {
	return "<<Lua-function>>"
}

func (this LuaFunction) Call(cmd *exec.Cmd) (interpreter.NextT, error) {
	this.L.GetField(Registory, this.registoryKey)
	this.L.NewTable()
	for i, arg1 := range cmd.Args {
		this.L.PushInteger(i)
		this.L.PushString(arg1)
		this.L.SetTable(-3)
	}
	LuaInstanceToCmd[this.L] = cmd
	err := this.L.Call(1, 0)
	return interpreter.CONTINUE, err
}

func cmdAlias(L *Lua) int {
	name, nameErr := L.ToString(1)
	if nameErr != nil {
		L.PushNil()
		L.PushString(nameErr.Error())
		return 2
	}
	key := strings.ToLower(name)
	switch L.GetType(2) {
	case TSTRING:
		value, err := L.ToString(2)
		if err == nil {
			alias.Table[key] = alias.New(value)
		} else {
			L.PushNil()
			L.PushString(err.Error())
			return 2
		}
	case TFUNCTION:
		regkey := "nyagos.alias." + key
		L.SetField(Registory, regkey)
		alias.Table[key] = LuaFunction{L, regkey}
	}
	L.PushBool(true)
	return 1
}

func cmdSetEnv(L *Lua) int {
	name, nameErr := L.ToString(1)
	if nameErr != nil {
		L.PushNil()
		L.PushString(nameErr.Error())
		return 2
	}
	value, valueErr := L.ToString(2)
	if valueErr != nil {
		L.PushNil()
		L.PushString(valueErr.Error())
		return 2
	}
	os.Setenv(name, value)
	L.PushBool(true)
	return 1
}

func cmdGetEnv(L *Lua) int {
	name, nameErr := L.ToString(1)
	if nameErr != nil {
		L.PushNil()
		return 1
	}
	value := os.Getenv(name)
	if len(value) > 0 {
		L.PushString(value)
	} else {
		L.PushNil()
	}
	return 1
}

func cmdExec(L *Lua) int {
	statement, statementErr := L.ToString(1)
	if statementErr != nil {
		L.PushNil()
		L.PushString(statementErr.Error())
		return 2
	}
	_, err := interpreter.Interpret(statement, nil)

	if err != nil {
		L.PushNil()
		L.PushString(err.Error())
		return 2
	}
	L.PushBool(true)
	return 1
}

func cmdEval(L *Lua) int {
	statement, statementErr := L.ToString(1)
	if statementErr != nil {
		L.PushNil()
		L.PushString(statementErr.Error())
		return 2
	}
	r, w, err := os.Pipe()
	if err != nil {
		L.PushNil()
		L.PushString(err.Error())
		return 2
	}
	go func(statement string, w *os.File) {
		interpreter.Interpret(statement, &interpreter.Stdio{Stdout: w})
		w.Close()
	}(statement, w)

	var result = []byte{}
	for {
		buffer := make([]byte, 256)
		size, err := r.Read(buffer)
		if err != nil || size <= 0 {
			break
		}
		result = append(result, buffer[0:size]...)
	}
	r.Close()
	L.PushAnsiString(result)
	return 1
}

func cmdWrite(L *Lua) int {
	var out io.Writer = os.Stdout
	if cmd, cmdOk := LuaInstanceToCmd[L]; cmdOk && cmd.Stdout != nil {
		out = cmd.Stdout
	}
	switch out.(type) {
	case *os.File:
		out = ansicolor.NewAnsiColorWriter(out)
	}

	n := L.GetTop()
	for i := 1; i <= n; i++ {
		str, err := L.ToString(i)
		if err != nil {
			L.PushNil()
			L.PushString(err.Error())
			return 2
		}
		if i > 1 {
			fmt.Fprint(out, "\t")
		}
		fmt.Fprint(out, str)
	}
	L.PushBool(true)
	return 1
}

func cmdGetwd(L *Lua) int {
	wd, err := os.Getwd()
	if err == nil {
		L.PushString(wd)
		return 1
	} else {
		return 0
	}
}

func cmdWhich(L *Lua) int {
	if L.GetType(-1) != TSTRING {
		return 0
	}
	name, nameErr := L.ToString(-1)
	if nameErr != nil {
		L.PushNil()
		L.PushString(nameErr.Error())
		return 2
	}
	path, err := exec.LookPath(name)
	if err == nil {
		L.PushString(path)
		return 1
	} else {
		L.PushNil()
		L.PushString(err.Error())
		return 2
	}
}

func cmdAtoU(L *Lua) int {
	str, err := mbcs.AtoU(L.ToAnsiString(1))
	if err == nil {
		L.PushString(str)
		return 1
	} else {
		return 0
	}
}

func cmdUtoA(L *Lua) int {
	utf8, utf8err := L.ToString(1)
	if utf8err != nil {
		L.PushNil()
		L.PushString(utf8err.Error())
		return 2
	}
	str, err := mbcs.UtoA(utf8)
	if err == nil {
		if len(str) >= 1 {
			L.PushAnsiString(str[:len(str)-1])
		} else {
			L.PushString("")
		}
		L.PushNil()
		return 2
	} else {
		L.PushNil()
		L.PushString(err.Error())
		return 2
	}
}

func cmdGlob(L *Lua) int {
	if !L.IsString(-1) {
		return 0
	}
	wildcard, wildcardErr := L.ToString(-1)
	if wildcardErr != nil {
		L.PushNil()
		L.PushString(wildcardErr.Error())
		return 2
	}
	list, err := dos.Glob(wildcard)
	if err != nil {
		L.PushNil()
		L.PushString(err.Error())
		return 2
	} else {
		L.NewTable()
		for i := 0; i < len(list); i++ {
			L.PushInteger(i + 1)
			L.PushString(list[i])
			L.SetTable(-3)
		}
		return 1
	}
}

func cmdBindKey(L *Lua) int {
	key, keyErr := L.ToString(-2)
	if keyErr != nil {
		L.PushString(keyErr.Error())
		return 1
	}
	val, valErr := L.ToString(-1)
	if valErr != nil {
		L.PushString(valErr.Error())
		return 1
	}
	err := conio.BindKeySymbol(key, val)
	if err != nil {
		L.PushNil()
		L.PushString(err.Error())
		return 2
	} else {
		L.PushBool(true)
		return 1
	}
}

func SetLuaFunctions(this *Lua) {
	stackPos := this.GetTop()
	defer this.SetTop(stackPos)
	this.NewTable()
	this.PushGoFunction(cmdAlias)
	this.SetField(-2, "alias")
	this.PushGoFunction(cmdSetEnv)
	this.SetField(-2, "setenv")
	this.PushGoFunction(cmdGetEnv)
	this.SetField(-2, "getenv")
	this.PushGoFunction(cmdExec)
	this.SetField(-2, "exec")
	this.PushGoFunction(cmdWrite)
	this.SetField(-2, "write")
	this.PushGoFunction(cmdAtoU)
	this.SetField(-2, "atou")
	this.PushGoFunction(cmdUtoA)
	this.SetField(-2, "utoa")
	this.PushGoFunction(cmdGetwd)
	this.SetField(-2, "getwd")
	this.PushGoFunction(cmdWhich)
	this.SetField(-2, "which")
	this.PushGoFunction(cmdEval)
	this.SetField(-2, "eval")
	this.PushGoFunction(cmdGlob)
	this.SetField(-2, "glob")
	this.PushGoFunction(cmdBindKey)
	this.SetField(-2, "bindkey")
	exeName, exeNameErr := dos.GetModuleFileName()
	if exeNameErr != nil {
		fmt.Fprintln(os.Stderr, exeNameErr)
	} else {
		this.PushString(exeName)
		this.SetField(-2, "exe")
	}
	this.SetGlobal("nyagos")

	// replace io.getenv
	this.GetGlobal("os")
	this.PushGoFunction(cmdGetEnv)
	this.SetField(-2, "getenv")

	var orgArgHook func([]string) []string
	orgArgHook = interpreter.SetArgsHook(func(args []string) []string {
		pos := this.GetTop()
		defer this.SetTop(pos)
		this.GetGlobal("nyagos")
		this.GetField(-1, "argsfilter")
		if !this.IsFunction(-1) {
			return orgArgHook(args)
		}
		this.NewTable()
		for i := 0; i < len(args); i++ {
			this.PushInteger(i)
			this.PushString(args[i])
			this.SetTable(-3)
		}
		if err := this.Call(1, 1); err != nil {
			fmt.Fprintf(os.Stderr, "%s\n", err)
			return orgArgHook(args)
		}
		if this.GetType(-1) != TTABLE {
			return orgArgHook(args)
		}
		newargs := []string{}
		for i := 0; true; i++ {
			this.PushInteger(i)
			this.GetTable(-2)
			if this.GetType(-1) == TNIL {
				break
			}
			arg1, arg1err := this.ToString(-1)
			if arg1err == nil {
				newargs = append(newargs, arg1)
			} else {
				fmt.Fprintln(os.Stderr, arg1err.Error())
			}
			this.Pop(1)
		}
		return orgArgHook(newargs)
	})
}
<|endoftext|>


<commit_before>package main

////////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2016-2020, Gianluca Fiore
//
////////////////////////////////////////////////////////////////////////////////

import (
	"flag"
	"fmt"
	"os"
	"path"
	"regexp"
	"strconv"
)

var mgntType string
var watchdir string

var usageMessage = `
m2t [-t|-type <type>] [-w|watchdir <directory>] <magnetlink>

M2T (Magnet To Torrent) will convert magnet links to torrent files. It works by using the "watch directory" feature of many torrent clients

Arguments:
	-t|-type <type>
		The type of the file contained in the magnet link. Defaults to "others"

	-w|-watchdir <directory>
		The directory where the torrent client watches for new torrents.
		It must exist. Defaults to '/media/private/torrent/watch
	`

// Parse flags
func init() {

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, usageMessage)
	}

	const (
		defWatchdir = "/media/private/torrent/watch"
		defType     = "others"
	)

	flag.StringVar(&mgntType, "type", defType, "")
	flag.StringVar(&mgntType, "t", defType, "")
	flag.StringVar(&watchdir, "watchdir", defWatchdir, "")
	flag.StringVar(&watchdir, "w", defWatchdir, "")

}

func main() {
	var torrentFilename, fileName string

	// initialize cli arguments
	flag.Parse()

	// at least the magnet link is needed, bail out if it was not given
	if flag.NArg() == 0 {
		fmt.Println("No magnet link given, exiting...")
		os.Exit(1)
	}

	// Compose the watch dir's path for the torrent file
	outputDir := path.Join(watchdir, mgntType)
	// Reassign first flag to a variable
	magnetLink := flag.Arg(0)

	// Compile a couple of regexp we need
	var validMagnet = regexp.MustCompile(`xt=urn(\.[0-9]*)?:btih:([^&/]+)`)
	var displayName = regexp.MustCompile(`dn=([^&/]+)`)
	var infoHash = regexp.MustCompile(`btih:([^&/]+)`)

	if validMagnet.MatchString(magnetLink) {
		if displayName.MatchString(magnetLink) {
			torrentFilename = displayName.FindString(magnetLink)
		} else if infoHash.MatchString(magnetLink) {
			//torrentFilename = infoHash.FindString(magnetLink)
			torrentFilename = validMagnet.FindString(magnetLink)
		} else {
			fmt.Println("Format of magnet URI not supported")
			os.Exit(1)
		}

		// split at '='
		fileName = regexp.MustCompile(`=`).Split(torrentFilename, -1)[1]
		if len(fileName) == 0 {
			xt := validMagnet.FindString(magnetLink)
			fileName = regexp.MustCompile(`:`).Split(xt, -1)[2]
		}
		// Add torrent extension
		fileName = fileName + ".torrent"
	} else {
		// not a valid magnet URI given
		fmt.Println("The magnet URI is not correct or unparseable")
		os.Exit(1)
	}

	// Create torrent file and output magnet link string to it
	f, err := os.Create(path.Join(outputDir, fileName))
	if err != nil {
		panic(err)
	}
	_, wErr := f.WriteString("d10:magnet-uri" + strconv.Itoa(len(magnetLink)) + ":" + magnetLink + "e")
	if wErr != nil {
		panic(err)
	}

	defer f.Close()

	os.Exit(0)
}
<commit_msg>changed default watch directory<commit_after>package main

////////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2016-2020, Gianluca Fiore
//
////////////////////////////////////////////////////////////////////////////////

import (
	"flag"
	"fmt"
	"os"
	"path"
	"regexp"
	"strconv"
)

var mgntType string
var watchdir string

var usageMessage = `
m2t [-t|-type <type>] [-w|watchdir <directory>] <magnetlink>

M2T (Magnet To Torrent) will convert magnet links to torrent files. It works by using the "watch directory" feature of many torrent clients

Arguments:
	-t|-type <type>
		The type of the file contained in the magnet link. Defaults to "others"

	-w|-watchdir <directory>
		The directory where the torrent client watches for new torrents.
		It must exist. Defaults to '/mnt/private/torrent/watch
	`

// Parse flags
func init() {

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, usageMessage)
	}

	const (
		defWatchdir = "/mnt/private/torrent/watch"
		defType     = "others"
	)

	flag.StringVar(&mgntType, "type", defType, "")
	flag.StringVar(&mgntType, "t", defType, "")
	flag.StringVar(&watchdir, "watchdir", defWatchdir, "")
	flag.StringVar(&watchdir, "w", defWatchdir, "")

}

func main() {
	var torrentFilename, fileName string

	// initialize cli arguments
	flag.Parse()

	// at least the magnet link is needed, bail out if it was not given
	if flag.NArg() == 0 {
		fmt.Println("No magnet link given, exiting...")
		os.Exit(1)
	}

	// Compose the watch dir's path for the torrent file
	outputDir := path.Join(watchdir, mgntType)
	// Reassign first flag to a variable
	magnetLink := flag.Arg(0)

	// Compile a couple of regexp we need
	var validMagnet = regexp.MustCompile(`xt=urn(\.[0-9]*)?:btih:([^&/]+)`)
	var displayName = regexp.MustCompile(`dn=([^&/]+)`)
	var infoHash = regexp.MustCompile(`btih:([^&/]+)`)

	if validMagnet.MatchString(magnetLink) {
		if displayName.MatchString(magnetLink) {
			torrentFilename = displayName.FindString(magnetLink)
		} else if infoHash.MatchString(magnetLink) {
			//torrentFilename = infoHash.FindString(magnetLink)
			torrentFilename = validMagnet.FindString(magnetLink)
		} else {
			fmt.Println("Format of magnet URI not supported")
			os.Exit(1)
		}

		// split at '='
		fileName = regexp.MustCompile(`=`).Split(torrentFilename, -1)[1]
		if len(fileName) == 0 {
			xt := validMagnet.FindString(magnetLink)
			fileName = regexp.MustCompile(`:`).Split(xt, -1)[2]
		}
		// Add torrent extension
		fileName = fileName + ".torrent"
	} else {
		// not a valid magnet URI given
		fmt.Println("The magnet URI is not correct or unparseable")
		os.Exit(1)
	}

	// Create torrent file and output magnet link string to it
	f, err := os.Create(path.Join(outputDir, fileName))
	if err != nil {
		panic(err)
	}
	_, wErr := f.WriteString("d10:magnet-uri" + strconv.Itoa(len(magnetLink)) + ":" + magnetLink + "e")
	if wErr != nil {
		panic(err)
	}

	defer f.Close()

	os.Exit(0)
}
<|endoftext|>


<commit_before>// Copyright (C) 2015 Thomas de Zeeuw.
//
// Licensed onder the MIT license that can be found in the LICENSE file.

package logger

import (
	"fmt"
	"math"
	"strings"
	"time"
)

// Msg is a message created by a log operation.
type Msg struct {
	Level     LogLevel
	Msg       string
	Tags      Tags
	Timestamp time.Time
}

// String creates a string message in the following format:
//	YYYY-MM-DD HH:MM:SS [LEVEL] tag1, tag2: message
func (msg *Msg) String() string {
	return string(msg.Bytes())
}

// Bytes does the same as Tags.String, but returns a byte slice.
func (msg *Msg) Bytes() []byte {
	var buf []byte

	// Write the date and time.
	// Format: "YYYY-MM-DD HH:MM:SS ".
	year, month, day := msg.Timestamp.Date()
	hour, min, sec := msg.Timestamp.Clock()
	itoa(&buf, year, 4)
	buf = append(buf, '-')
	itoa(&buf, int(month), 2)
	buf = append(buf, '-')
	itoa(&buf, day, 2)
	buf = append(buf, ' ')
	itoa(&buf, hour, 2)
	buf = append(buf, ':')
	itoa(&buf, min, 2)
	buf = append(buf, ':')
	itoa(&buf, sec, 2)
	buf = append(buf, ' ')

	// Write the log level.
	// Format: "[LEVEL] ".
	buf = append(buf, '[')
	buf = append(buf, msg.Level.Bytes()...)
	buf = append(buf, ']')
	buf = append(buf, ' ')

	// Write the tags.
	// Format: "tag1, tag2: ".
	buf = append(buf, msg.Tags.Bytes()...)
	buf = append(buf, ':')
	buf = append(buf, ' ')

	// The actual message.
	buf = append(buf, strings.TrimSpace(msg.Msg)...)
	buf = append(buf, '\n')

	return buf
}

// Cheap integer to fixed-width decimal ASCII. Modified version from the Golang
// logger package.
func itoa(buf *[]byte, i int, wid int) {
	var b [4]byte // only used for year, month and day so 4 is enough.
	bp := len(b) - 1
	for i >= 10 || wid > 1 {
		wid--
		q := i / 10
		b[bp] = byte('0' + i - q*10)
		bp--
		i = q
	}
	b[bp] = byte('0' + i)
	*buf = append(*buf, b[bp:]...)
}

type LogLevel uint8

// Log levels available by default.
const (
	Debug LogLevel = iota
	Thumb
	Info
	Warn
	Error
	Fatal
)

var (
	logLevelNames   = "DebugThumbInfoWarnErrorFatal"
	logLevelIndices = []int{0, 5, 10, 14, 18, 23, 28}
)

func (lvl LogLevel) String() string {
	if int(lvl) >= len(logLevelIndices)-1 {
		return fmt.Sprintf("LogLevel(%d)", lvl)
	}

	startIndex := logLevelIndices[lvl]
	endIndex := logLevelIndices[lvl+1]
	return logLevelNames[startIndex:endIndex]
}

func (lvl LogLevel) Bytes() []byte {
	return []byte(lvl.String())
}

// NewLogLevel creates a new fully supported custom log level for used in
//  logging, this function makes sure that LogLevel.String and LogLevel.Bytes
// return the correct given name.
//
// Note: THIS FUNCTION IS NOT THREAD SAFE, use it before starting to log.
//
// Note: The maximum number of custom log levels is 248, if more are created
// this function will panic.
func NewLogLevel(name string) LogLevel {
	if len(logLevelIndices) >= math.MaxUint8 {
		panic("ini: can't have more then 255 log levels")
	}

	logLevelNames += name
	logLevelIndices = append(logLevelIndices, len(logLevelNames))
	return LogLevel(len(logLevelIndices) - 2)
}
<commit_msg>Doc LogLevel<commit_after>// Copyright (C) 2015 Thomas de Zeeuw.
//
// Licensed onder the MIT license that can be found in the LICENSE file.

package logger

import (
	"fmt"
	"math"
	"strings"
	"time"
)

// Msg is a message created by a log operation.
type Msg struct {
	Level     LogLevel
	Msg       string
	Tags      Tags
	Timestamp time.Time
}

// String creates a string message in the following format:
//	YYYY-MM-DD HH:MM:SS [LEVEL] tag1, tag2: message
func (msg *Msg) String() string {
	return string(msg.Bytes())
}

// Bytes does the same as Tags.String, but returns a byte slice.
func (msg *Msg) Bytes() []byte {
	var buf []byte

	// Write the date and time.
	// Format: "YYYY-MM-DD HH:MM:SS ".
	year, month, day := msg.Timestamp.Date()
	hour, min, sec := msg.Timestamp.Clock()
	itoa(&buf, year, 4)
	buf = append(buf, '-')
	itoa(&buf, int(month), 2)
	buf = append(buf, '-')
	itoa(&buf, day, 2)
	buf = append(buf, ' ')
	itoa(&buf, hour, 2)
	buf = append(buf, ':')
	itoa(&buf, min, 2)
	buf = append(buf, ':')
	itoa(&buf, sec, 2)
	buf = append(buf, ' ')

	// Write the log level.
	// Format: "[LEVEL] ".
	buf = append(buf, '[')
	buf = append(buf, msg.Level.Bytes()...)
	buf = append(buf, ']')
	buf = append(buf, ' ')

	// Write the tags.
	// Format: "tag1, tag2: ".
	buf = append(buf, msg.Tags.Bytes()...)
	buf = append(buf, ':')
	buf = append(buf, ' ')

	// The actual message.
	buf = append(buf, strings.TrimSpace(msg.Msg)...)
	buf = append(buf, '\n')

	return buf
}

// Cheap integer to fixed-width decimal ASCII. Modified version from the Golang
// logger package.
func itoa(buf *[]byte, i int, wid int) {
	var b [4]byte // only used for year, month and day so 4 is enough.
	bp := len(b) - 1
	for i >= 10 || wid > 1 {
		wid--
		q := i / 10
		b[bp] = byte('0' + i - q*10)
		bp--
		i = q
	}
	b[bp] = byte('0' + i)
	*buf = append(*buf, b[bp:]...)
}

// LogLevel indicent which level of detail a log operation has.
type LogLevel uint8

// Log levels available by default.
const (
	Debug LogLevel = iota
	Thumb
	Info
	Warn
	Error
	Fatal
)

var (
	logLevelNames   = "DebugThumbInfoWarnErrorFatal"
	logLevelIndices = []int{0, 5, 10, 14, 18, 23, 28}
)

// String return the name of the log level. Examples:
//
//	Debug.String() // "Debug"
//	Info.String() // "Info"
//	Fatal.String() // "Fatal"
//
// Custom levels are also supported, if created with NewLogLevel.
func (lvl LogLevel) String() string {
	if int(lvl) >= len(logLevelIndices)-1 {
		return fmt.Sprintf("LogLevel(%d)", lvl)
	}

	startIndex := logLevelIndices[lvl]
	endIndex := logLevelIndices[lvl+1]
	return logLevelNames[startIndex:endIndex]
}

// Bytes does the same as LogLevel.String, but returns a byte slice.
func (lvl LogLevel) Bytes() []byte {
	return []byte(lvl.String())
}

// NewLogLevel creates a new fully supported custom log level for used in
//  logging, this function makes sure that LogLevel.String and LogLevel.Bytes
// return the correct given name.
//
// Note: THIS FUNCTION IS NOT THREAD SAFE, use it before starting to log.
//
// Note: The maximum number of custom log levels is 248, if more are created
// this function will panic.
func NewLogLevel(name string) LogLevel {
	if len(logLevelIndices) >= math.MaxUint8 {
		panic("ini: can't have more then 255 log levels")
	}

	logLevelNames += name
	logLevelIndices = append(logLevelIndices, len(logLevelNames))
	return LogLevel(len(logLevelIndices) - 2)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"os"
)

func printMtl(w io.Writer, blockId uint16) {
	if !noColor {
		if blockId&0xff == blockId {
			fmt.Fprintln(w, "usemtl", blockId)
		} else {
			fmt.Fprintf(w, "usemtl %d_%d", blockId&0xff, blockId>>8)
		}
	}
}

func writeMtlFile(filename string) os.Error {
	if noColor {
		return nil
	}

	var outFile, outErr = os.Open(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
	if outErr != nil {
		return outErr
	}
	defer outFile.Close()

	var p = 0

	for i := 0; i < 256; i++ {
		var matched = false

		for p < len(colors) && colors[p].blockId == byte(i) {
			matched = true
			colors[p].Print(outFile)
			p++
		}

		if !matched {
			var mtl = MTL{byte(i), 255, 0x7f7f7f, "Unknown", Voxel}
			mtl.Print(outFile)
		}
	}

	return nil
}

type MTL struct {
	blockId  byte
	metadata byte
	color    uint32
	name     string
	model    BlockModel
}

type BlockModel int

const (
	Voxel BlockModel = iota
	Mesh
)

func (mtl *MTL) Print(w io.Writer) {
	var (
		r = mtl.color >> 24
		g = mtl.color >> 16 & 0xff
		b = mtl.color >> 8 & 0xff
		a = mtl.color & 0xff
	)

	if mtl.metadata == 255 {
		fmt.Fprintf(w, "# %s\nnewmtl %d\nKd %.4f %.4f %.4f\nd %.4f\nillum 1\n\n", mtl.name, mtl.blockId, float64(r)/255, float64(g)/255, float64(b)/255, float64(a)/255)
	} else {
		fmt.Fprintf(w, "# %s\nnewmtl %d_%d\nKd %.4f %.4f %.4f\nd %.4f\nillum 1\n\n", mtl.name, mtl.blockId, mtl.metadata, float64(r)/255, float64(g)/255, float64(b)/255, float64(a)/255)
	}
}

func (mtl *MTL) colorId() uint16 {
	var id = uint16(mtl.blockId)
	if mtl.metadata != 255 {
		id += uint16(mtl.metadata) << 8
	}
	return id
}

func IsMeshBlockId(blockId uint16) bool {
	var value, present = nonVoxelBlocks[blockId]
	return value && present
}

func init() {
	nonVoxelBlocks = make(map[uint16]bool)
	for _, mtl := range colors {
		if mtl.model != Voxel {
			nonVoxelBlocks[mtl.colorId()] = true
		}
	}
}

var (
	nonVoxelBlocks map[uint16]bool

	colors = []MTL{
		MTL{0, 255, 0xff0000ff, "Air", Voxel},
		MTL{1, 255, 0x7f7f7fff, "Stone", Voxel},
		MTL{2, 255, 0x2e6d05ff, "Grass", Voxel},
		MTL{3, 255, 0x79553aff, "Dirt", Voxel},
		MTL{4, 255, 0xa8a8a8ff, "Cobblestone", Voxel},
		MTL{5, 255, 0xbc9862ff, "Wooden Plank", Voxel},
		MTL{6, 255, 0x006400ff, "Sapling", Voxel},
		MTL{7, 255, 0x575757ff, "Bedrock", Voxel},
		MTL{8, 255, 0x009affff, "Water", Voxel},
		MTL{9, 255, 0x002affff, "Stationary water", Voxel},
		MTL{10, 255, 0x002affff, "Lava", Voxel},
		MTL{11, 255, 0xfc4a00ff, "Stationary lava", Voxel},
		MTL{12, 255, 0xf2e7bbff, "Sand", Voxel},
		MTL{13, 255, 0x9a9b9fff, "Gravel", Voxel},
		MTL{14, 255, 0xfff144ff, "Gold ore", Voxel},
		MTL{15, 255, 0xe2c0aaff, "Iron ore", Voxel},
		MTL{16, 255, 0x454545ff, "Coal ore", Voxel},
		MTL{17, 255, 0x695433ff, "Wood", Voxel},
		MTL{18, 255, 0x509026ff, "Leaves", Voxel},
		MTL{19, 255, 0xe5e54eff, "Sponge", Voxel},
		MTL{20, 255, 0xffffff10, "Glass", Voxel},
		MTL{21, 255, 0x224da1ff, "Lapis Lazuli Ore", Voxel},
		MTL{22, 255, 0x224dffff, "Lapis Lazuli Block", Voxel},
		MTL{23, 255, 0x7f7f7fff, "Dispenser", Voxel},
		MTL{24, 255, 0xdad2abff, "Sandstone", Voxel},
		MTL{25, 255, 0x9b664bff, "Note Block", Voxel},
		MTL{35, 0, 0xd1d1d1ff, "Wool - White", Voxel},
		MTL{35, 1, 0xe97a2eff, "Wool - Orange", Voxel},
		MTL{35, 2, 0xbc3ec7ff, "Wool - Magenta", Voxel},
		MTL{35, 3, 0x5980d0ff, "Wool - Light Blue", Voxel},
		MTL{35, 4, 0xb6a918ff, "Wool - Yellow", Voxel},
		MTL{35, 5, 0x37b32cff, "Wool - Light Green", Voxel},
		MTL{35, 6, 0xd57690ff, "Wool - Pink", Voxel},
		MTL{35, 7, 0x3f3f3fff, "Wool - Gray", Voxel},
		MTL{35, 8, 0x949d9dff, "Wool - Light Gray", Voxel},
		MTL{35, 9, 0xbc3ec7ff, "Wool - Cyan", Voxel},
		MTL{35, 10, 0x7a2fbcff, "Wool - Purple", Voxel},
		MTL{35, 11, 0x243091ff, "Wool - Blue", Voxel},
		MTL{35, 12, 0x51301aff, "Wool - Brown", Voxel},
		MTL{35, 13, 0x344817ff, "Wool - Dark Green", Voxel},
		MTL{35, 14, 0x9b2a26ff, "Wool - Red", Voxel},
		MTL{35, 15, 0x171313ff, "Wool - Black", Voxel},
		MTL{37, 255, 0xf1f902ff, "Yellow flower", Mesh},
		MTL{38, 255, 0xf11102ff, "Red rose", Mesh},
		MTL{39, 255, 0xba7038ff, "Brown Mushroom", Mesh},
		MTL{40, 255, 0xcf3626ff, "Red Mushroom", Mesh},
		MTL{41, 255, 0xfff199ff, "Gold Block", Voxel},
		MTL{42, 255, 0xdededeff, "Iron Block", Voxel},
		MTL{43, 255, 0xc8c8c8ff, "Double Stone Slab", Voxel},
		MTL{44, 255, 0xa8a8a8ff, "Stone Slab", Voxel},
		MTL{45, 255, 0xa14f38ff, "Brick", Voxel},
		MTL{46, 255, 0xdb441aff, "TNT", Voxel},
		MTL{47, 255, 0x9f844dff, "Bookshelf", Voxel},
		MTL{48, 255, 0xa7a8a7ff, "Moss Stone", Voxel},
		MTL{49, 255, 0x101019ff, "Obsidian", Voxel},
		MTL{50, 255, 0xffae0c99, "Torch", Mesh},
		MTL{51, 255, 0xff000099, "Fire", Voxel},
		MTL{52, 255, 0x929292ff, "Monster Spawner", Voxel},
		MTL{53, 255, 0x9c743aff, "Wooden Stairs", Voxel},
		MTL{54, 255, 0xab792dff, "Chest", Voxel},
		MTL{55, 255, 0xcc0000ff, "Redstone Wire", Voxel},
		MTL{56, 255, 0x50aba6ff, "Diamond Ore", Voxel},
		MTL{57, 255, 0x69dfdaff, "Diamond Block", Voxel},
		MTL{58, 255, 0xab9472ff, "Workbench", Voxel},
		MTL{59, 255, 0x1a7508ff, "Crops", Voxel},
		MTL{60, 255, 0x573d2aff, "Soil", Voxel},
		MTL{61, 255, 0x919191ff, "Furnace", Voxel},
		MTL{62, 255, 0x919191ff, "Burning Furnace", Voxel},
		MTL{63, 255, 0xd6b88bff, "Sign Post", Mesh},
		MTL{64, 255, 0x82592cff, "Wooden Door", Mesh},
		MTL{65, 255, 0xab8944ff, "Ladder", Mesh},
		MTL{66, 255, 0xc7c7c7ff, "Minecart Tracks", Mesh},
		MTL{67, 255, 0x919191ff, "Cobblestone Stairs", Voxel}, // Should be Mesh
		MTL{68, 255, 0xd6b88bff, "Wall Sign", Mesh},
		MTL{69, 255, 0xd6b88bff, "Lever", Mesh},
		MTL{70, 255, 0x919191ff, "Stone Pressure Plate", Mesh},
		MTL{71, 255, 0xbababaff, "Iron Door", Mesh},
		MTL{72, 255, 0x7a6340ff, "Wooden Pressure Plate", Mesh},
		MTL{73, 255, 0xbd0000ff, "Redstone Ore", Voxel},
		MTL{74, 255, 0xff0000ff, "Glowing Redstone Ore", Voxel},
		MTL{75, 255, 0xbd0000ff, "Redstone torch (\"off\" state)", Mesh},
		MTL{76, 255, 0xff0000ff, "Redstone torch (\"on\" state)", Mesh},
		MTL{77, 255, 0x919191ff, "Stone Button", Mesh},
		MTL{78, 255, 0xfefefeff, "Snow", Voxel},
		MTL{79, 255, 0x77a9ffff, "Ice", Voxel},
		MTL{80, 255, 0xfcfcfcff, "Snow Block", Voxel},
		MTL{81, 255, 0x11801eff, "Cactus", Voxel},
		MTL{82, 255, 0xaaaebeff, "Clay", Voxel},
		MTL{83, 255, 0x3c6e0aff, "Sugar Cane", Voxel},
		MTL{84, 255, 0x9b664bff, "Jukebox", Voxel},
		MTL{85, 255, 0x7a6340ff, "Fence", Voxel},
		MTL{86, 255, 0xa05a0bff, "Pumpkin", Voxel},
		MTL{87, 255, 0xb66b6bff, "Netherrack", Voxel},
		MTL{88, 255, 0x453125ff, "Soul Sand", Voxel},
		MTL{89, 255, 0xfff894ff, "Glowstone", Voxel},
		MTL{90, 255, 0x381d55ff, "Portal", Voxel},
		MTL{91, 255, 0xe9b416ff, "Jack-O-Lantern", Voxel},
		MTL{92, 255, 0xbd9075ff, "Cake Block", Voxel},
	}
)
<commit_msg>Updated colors from WormSlayer<commit_after>package main

import (
	"fmt"
	"io"
	"os"
)

func printMtl(w io.Writer, blockId uint16) {
	if !noColor {
		if blockId&0xff == blockId {
			fmt.Fprintln(w, "usemtl", blockId)
		} else {
			fmt.Fprintf(w, "usemtl %d_%d", blockId&0xff, blockId>>8)
		}
	}
}

func writeMtlFile(filename string) os.Error {
	if noColor {
		return nil
	}

	var outFile, outErr = os.Open(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
	if outErr != nil {
		return outErr
	}
	defer outFile.Close()

	var p = 0

	for i := 0; i < 256; i++ {
		var matched = false

		for p < len(colors) && colors[p].blockId == byte(i) {
			matched = true
			colors[p].Print(outFile)
			p++
		}

		if !matched {
			var mtl = MTL{byte(i), 255, 0x7f7f7f, "Unknown", Voxel}
			mtl.Print(outFile)
		}
	}

	return nil
}

type MTL struct {
	blockId  byte
	metadata byte
	color    uint32
	name     string
	model    BlockModel
}

type BlockModel int

const (
	Voxel BlockModel = iota
	Mesh
)

func (mtl *MTL) Print(w io.Writer) {
	var (
		r = mtl.color >> 24
		g = mtl.color >> 16 & 0xff
		b = mtl.color >> 8 & 0xff
		a = mtl.color & 0xff
	)

	if mtl.metadata == 255 {
		fmt.Fprintf(w, "# %s\nnewmtl %d\nKd %.4f %.4f %.4f\nd %.4f\nillum 1\n\n", mtl.name, mtl.blockId, float64(r)/255, float64(g)/255, float64(b)/255, float64(a)/255)
	} else {
		fmt.Fprintf(w, "# %s\nnewmtl %d_%d\nKd %.4f %.4f %.4f\nd %.4f\nillum 1\n\n", mtl.name, mtl.blockId, mtl.metadata, float64(r)/255, float64(g)/255, float64(b)/255, float64(a)/255)
	}
}

func (mtl *MTL) colorId() uint16 {
	var id = uint16(mtl.blockId)
	if mtl.metadata != 255 {
		id += uint16(mtl.metadata) << 8
	}
	return id
}

func IsMeshBlockId(blockId uint16) bool {
	var value, present = nonVoxelBlocks[blockId]
	return value && present
}

func init() {
	nonVoxelBlocks = make(map[uint16]bool)
	for _, mtl := range colors {
		if mtl.model != Voxel {
			nonVoxelBlocks[mtl.colorId()] = true
		}
	}
}

var (
	nonVoxelBlocks map[uint16]bool

	colors = []MTL{
		MTL{0, 255, 0xff0000ff, "Air", Voxel},
		MTL{1, 255, 0x7f7f7fff, "Stone", Voxel},
		MTL{2, 255, 0x509026ff, "Grass", Voxel},
		MTL{3, 255, 0x79553aff, "Dirt", Voxel},
		MTL{4, 255, 0xa8a8a8ff, "Cobblestone", Voxel},
		MTL{5, 255, 0x9e8052ff, "Wooden Plank", Voxel},
		MTL{6, 255, 0x006400ff, "Sapling", Voxel},
		MTL{7, 255, 0x575757ff, "Bedrock", Voxel},
		MTL{8, 255, 0x009affaa, "Water", Voxel},
		MTL{9, 255, 0x002affff, "Stationary water", Voxel},
		MTL{10, 255, 0x002affff, "Lava", Voxel},
		MTL{11, 255, 0xfc4a00ff, "Stationary lava", Voxel},
		MTL{12, 255, 0xcfc393ff, "Sand", Voxel},
		MTL{13, 255, 0x9a9b9fff, "Gravel", Voxel},
		MTL{14, 255, 0xfff144ff, "Gold ore", Voxel},
		MTL{15, 255, 0xe2c0aaff, "Iron ore", Voxel},
		MTL{16, 255, 0x454545ff, "Coal ore", Voxel},
		MTL{17, 255, 0x695433ff, "Wood", Voxel},
		MTL{18, 255, 0x2e6d05ff, "Leaves", Voxel},
		MTL{19, 255, 0xe5e54eff, "Sponge", Voxel},
		MTL{20, 255, 0xffffff10, "Glass", Voxel},
		MTL{21, 255, 0x224da1ff, "Lapis Lazuli Ore", Voxel},
		MTL{22, 255, 0x224dffff, "Lapis Lazuli Block", Voxel},
		MTL{23, 255, 0x7f7f7fff, "Dispenser", Voxel},
		MTL{24, 255, 0xdad2abff, "Sandstone", Voxel},
		MTL{25, 255, 0x9b664bff, "Note Block", Voxel},
		MTL{35, 0, 0xd1d1d1ff, "Wool - White", Voxel},
		MTL{35, 1, 0xe97a2eff, "Wool - Orange", Voxel},
		MTL{35, 2, 0xbc3ec7ff, "Wool - Magenta", Voxel},
		MTL{35, 3, 0x5980d0ff, "Wool - Light Blue", Voxel},
		MTL{35, 4, 0xb6a918ff, "Wool - Yellow", Voxel},
		MTL{35, 5, 0x37b32cff, "Wool - Light Green", Voxel},
		MTL{35, 6, 0xd57690ff, "Wool - Pink", Voxel},
		MTL{35, 7, 0x3f3f3fff, "Wool - Gray", Voxel},
		MTL{35, 8, 0x949d9dff, "Wool - Light Gray", Voxel},
		MTL{35, 9, 0xbc3ec7ff, "Wool - Cyan", Voxel},
		MTL{35, 10, 0x7a2fbcff, "Wool - Purple", Voxel},
		MTL{35, 11, 0x243091ff, "Wool - Blue", Voxel},
		MTL{35, 12, 0x51301aff, "Wool - Brown", Voxel},
		MTL{35, 13, 0x344817ff, "Wool - Dark Green", Voxel},
		MTL{35, 14, 0x9b2a26ff, "Wool - Red", Voxel},
		MTL{35, 15, 0x171313ff, "Wool - Black", Voxel},
		MTL{37, 255, 0xf1f902ff, "Yellow flower", Mesh},
		MTL{38, 255, 0xf11102ff, "Red rose", Mesh},
		MTL{39, 255, 0xba7038ff, "Brown Mushroom", Mesh},
		MTL{40, 255, 0xcf3626ff, "Red Mushroom", Mesh},
		MTL{41, 255, 0xfff199ff, "Gold Block", Voxel},
		MTL{42, 255, 0xdededeff, "Iron Block", Voxel},
		MTL{43, 255, 0xc8c8c8ff, "Double Stone Slab", Voxel},
		MTL{44, 255, 0xa8a8a8ff, "Stone Slab", Voxel},
		MTL{45, 255, 0xa14f38ff, "Brick", Voxel},
		MTL{46, 255, 0xdb441aff, "TNT", Voxel},
		MTL{47, 255, 0x9f844dff, "Bookshelf", Voxel},
		MTL{48, 255, 0xa7a8a7ff, "Moss Stone", Voxel},
		MTL{49, 255, 0x101019ff, "Obsidian", Voxel},
		MTL{50, 255, 0xffae0c99, "Torch", Mesh},
		MTL{51, 255, 0xff000099, "Fire", Voxel},
		MTL{52, 255, 0x929292ff, "Monster Spawner", Voxel},
		MTL{53, 255, 0x9c743aff, "Wooden Stairs", Voxel},
		MTL{54, 255, 0xab792dff, "Chest", Voxel},
		MTL{55, 255, 0xcc0000ff, "Redstone Wire", Voxel},
		MTL{56, 255, 0x50aba6ff, "Diamond Ore", Voxel},
		MTL{57, 255, 0x69dfdaff, "Diamond Block", Voxel},
		MTL{58, 255, 0xab9472ff, "Workbench", Voxel},
		MTL{59, 255, 0x1a7508ff, "Crops", Voxel},
		MTL{60, 255, 0x573d2aff, "Soil", Voxel},
		MTL{61, 255, 0x919191ff, "Furnace", Voxel},
		MTL{62, 255, 0x919191ff, "Burning Furnace", Voxel},
		MTL{63, 255, 0xd6b88bff, "Sign Post", Mesh},
		MTL{64, 255, 0x82592cff, "Wooden Door", Mesh},
		MTL{65, 255, 0xab8944ff, "Ladder", Mesh},
		MTL{66, 255, 0xc7c7c7ff, "Minecart Tracks", Mesh},
		MTL{67, 255, 0x919191ff, "Cobblestone Stairs", Voxel}, // Should be Mesh
		MTL{68, 255, 0xd6b88bff, "Wall Sign", Mesh},
		MTL{69, 255, 0xd6b88bff, "Lever", Mesh},
		MTL{70, 255, 0x919191ff, "Stone Pressure Plate", Mesh},
		MTL{71, 255, 0xbababaff, "Iron Door", Mesh},
		MTL{72, 255, 0x7a6340ff, "Wooden Pressure Plate", Mesh},
		MTL{73, 255, 0xbd0000ff, "Redstone Ore", Voxel},
		MTL{74, 255, 0xff0000ff, "Glowing Redstone Ore", Voxel},
		MTL{75, 255, 0xbd0000ff, "Redstone torch (\"off\" state)", Mesh},
		MTL{76, 255, 0xff0000ff, "Redstone torch (\"on\" state)", Mesh},
		MTL{77, 255, 0x919191ff, "Stone Button", Mesh},
		MTL{78, 255, 0xfefefeff, "Snow", Voxel},
		MTL{79, 255, 0x77a9ffff, "Ice", Voxel},
		MTL{80, 255, 0xfcfcfcff, "Snow Block", Voxel},
		MTL{81, 255, 0x11801eff, "Cactus", Voxel},
		MTL{82, 255, 0xaaaebeff, "Clay", Voxel},
		MTL{83, 255, 0x3c6e0aff, "Sugar Cane", Voxel},
		MTL{84, 255, 0x9b664bff, "Jukebox", Voxel},
		MTL{85, 255, 0x7a6340ff, "Fence", Voxel},
		MTL{86, 255, 0xa05a0bff, "Pumpkin", Voxel},
		MTL{87, 255, 0xb66b6bff, "Netherrack", Voxel},
		MTL{88, 255, 0x453125ff, "Soul Sand", Voxel},
		MTL{89, 255, 0xfff894ff, "Glowstone", Voxel},
		MTL{90, 255, 0x381d55ff, "Portal", Voxel},
		MTL{91, 255, 0xe9b416ff, "Jack-O-Lantern", Voxel},
		MTL{92, 255, 0xbd9075ff, "Cake Block", Voxel},
	}
)
<|endoftext|>


<commit_before>// Copyright 2015 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package mux

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

	"github.com/gorilla/context"
)

// NewRouter returns a new router instance.
func NewRouter() *Router {
	return &Router{namedRoutes: make(map[string]*Route), KeepContext: false}
}

// Router registers routes to be matched and dispatches a handler.
//
// It implements the http.Handler interface, so it can be registered to serve
// requests:
//
//     var router = mux.NewRouter()
//
//     func main() {
//         http.Handle("/", router)
//     }
//
// Or, for Google App Engine, register it in a init() function:
//
//     func init() {
//         http.Handle("/", router)
//     }
//
// This will send all incoming requests to the router.
type Router struct {
	// Configurable Handler to be used when no route matches.
	NotFoundHandler http.Handler
	// Middleware handlers to be run
	middleware []MiddlewareHandler
	// Parent route, if this is a subrouter.
	parent parentRoute
	// Routes to be matched, in order.
	routes []*Route
	// Routes by name for URL building.
	namedRoutes map[string]*Route
	// See Router.StrictSlash(). This defines the flag for new routes.
	strictSlash bool
	// If true, do not clear the request context after handling the request
	KeepContext bool
}

// clone creates a deep-copied clone of a router
func (r *Router) clone() *Router {
	clone := *r
	clone.middleware = append([]MiddlewareHandler{}, r.middleware...)
	clone.routes = append([]*Route{}, r.routes...)
	clone.namedRoutes = make(map[string]*Route)
	for k, v := range r.namedRoutes {
		clone.namedRoutes[k] = v
	}
	return &clone
}

// Match matches registered routes against the request.
func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
	for _, route := range r.routes {
		if route.Match(req, match) {
			return true
		}
	}
	return false
}

// ServeHTTP dispatches the handler registered in the matched route.
//
// When there is a match, the route variables can be retrieved calling
// mux.Vars(request).
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	// Clean path to canonical form and redirect.
	if p := cleanPath(req.URL.Path); p != req.URL.Path {

		// Added 3 lines (Philip Schlump) - It was droping the query string and #whatever from query.
		// This matches with fix in go 1.2 r.c. 4 for same problem.  Go Issue:
		// http://code.google.com/p/go/issues/detail?id=5252
		url := *req.URL
		url.Path = p
		p = url.String()

		w.Header().Set("Location", p)
		w.WriteHeader(http.StatusMovedPermanently)
		return
	}
	var match RouteMatch
	var handler http.Handler
	if r.Match(req, &match) {
		handler = match.Handler
		setVars(req, match.Vars)
		setCurrentRoute(req, match.Route)
	}
	if handler == nil {
		handler = r.NotFoundHandler
		if handler == nil {
			handler = http.NotFoundHandler()
		}
	}
	if !r.KeepContext {
		defer context.Clear(req)
	}

	buildMiddleware(r.middleware, handler).ServeHTTP(w, req)
}

// Get returns a route registered with the given name.
func (r *Router) Get(name string) *Route {
	return r.getNamedRoutes()[name]
}

// GetRoute returns a route registered with the given name. This method
// was renamed to Get() and remains here for backwards compatibility.
func (r *Router) GetRoute(name string) *Route {
	return r.getNamedRoutes()[name]
}

// StrictSlash defines the trailing slash behavior for new routes. The initial
// value is false.
//
// When true, if the route path is "/path/", accessing "/path" will redirect
// to the former and vice versa. In other words, your application will always
// see the path as specified in the route.
//
// When false, if the route path is "/path", accessing "/path/" will not match
// this route and vice versa.
//
// Special case: when a route sets a path prefix using the PathPrefix() method,
// strict slash is ignored for that route because the redirect behavior can't
// be determined from a prefix alone. However, any subrouters created from that
// route inherit the original StrictSlash setting.
func (r *Router) StrictSlash(value bool) *Router {
	r.strictSlash = value
	return r
}

// ----------------------------------------------------------------------------
// parentRoute
// ----------------------------------------------------------------------------

// getNamedRoutes returns the map where named routes are registered.
func (r *Router) getNamedRoutes() map[string]*Route {
	if r.namedRoutes == nil {
		if r.parent != nil {
			r.namedRoutes = r.parent.getNamedRoutes()
		} else {
			r.namedRoutes = make(map[string]*Route)
		}
	}
	return r.namedRoutes
}

// getRegexpGroup returns regexp definitions from the parent route, if any.
func (r *Router) getRegexpGroup() *routeRegexpGroup {
	if r.parent != nil {
		return r.parent.getRegexpGroup()
	}
	return nil
}

func (r *Router) buildVars(m map[string]string) map[string]string {
	if r.parent != nil {
		m = r.parent.buildVars(m)
	}
	return m
}

// ----------------------------------------------------------------------------
// Middleware -- kindly borrowed from negroni
// ----------------------------------------------------------------------------

// MiddlewareHandler is an interface that objects can implement to be registered to serve as middleware
// in the mux middleware stack.
// ServeHTTP should yield to the next middleware in the chain by invoking the next http.HandlerFunc
// passed in.
//
// If the MiddlewareHandler writes to the ResponseWriter, the next http.HandlerFunc should not be invoked.
type MiddlewareHandler interface {
	ServeHTTP(http.ResponseWriter, *http.Request, http.HandlerFunc)
}

// MiddlewareHandlerFunc is an adapter to allow the use of ordinary functions as middleware handlers.
// If f is a function with the appropriate signature, MiddlewareHandlerFunc(f) is a MiddlewareHandler object that calls f.
type MiddlewareHandlerFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)

func (h MiddlewareHandlerFunc) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	h(rw, r, next)
}

// WrapMiddleware converts a http.Handler into a mux.MiddlewareHandler so it can be used as mux
// middleware. The next http.HandlerFunc is automatically called after the MiddlewareHandler
// is executed.
func WrapMiddleware(handler http.Handler) MiddlewareHandler {
	return MiddlewareHandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
		handler.ServeHTTP(rw, r)
		next(rw, r)
	})
}

type middleware struct {
	handler MiddlewareHandler
	next    *middleware
}

func (m middleware) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
	m.handler.ServeHTTP(rw, r, m.next.ServeHTTP)
}

func buildMiddleware(handlers []MiddlewareHandler, final http.Handler) middleware {
	var next middleware

	if len(handlers) == 0 {
		return finalMiddleware(final)
	} else if len(handlers) > 1 {
		next = buildMiddleware(handlers[1:], final)
	} else {
		next = finalMiddleware(final)
	}

	return middleware{handlers[0], &next}
}

func finalMiddleware(final http.Handler) middleware {
	return middleware{
		MiddlewareHandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { final.ServeHTTP(rw, r) }),
		&middleware{},
	}
}

func (r *Router) UseMiddleware(m MiddlewareHandler) {
	r.middleware = append(r.middleware, m)
}

func (r *Router) UseMiddlewareFunc(m func(http.ResponseWriter, *http.Request, http.HandlerFunc)) {
	r.middleware = append(r.middleware, MiddlewareHandlerFunc(m))
}

func (r *Router) UseMiddlewareHandler(m http.Handler) {
	r.middleware = append(r.middleware, WrapMiddleware(m))
}

func (r *Router) UseMiddlewareHandlerFunc(m func(http.ResponseWriter, *http.Request)) {
	r.middleware = append(r.middleware, WrapMiddleware(http.HandlerFunc(m)))
}

// ----------------------------------------------------------------------------
// Route factories
// ----------------------------------------------------------------------------

// NewRoute registers an empty route.
func (r *Router) NewRoute() *Route {
	route := &Route{parent: r, strictSlash: r.strictSlash}
	r.routes = append(r.routes, route)
	return route
}

// Handle registers a new route with a matcher for the URL path.
// See Route.Path() and Route.Handler().
func (r *Router) Handle(path string, handler http.Handler) *Route {
	return r.NewRoute().Path(path).Handler(handler)
}

// HandleFunc registers a new route with a matcher for the URL path.
// See Route.Path() and Route.HandlerFunc().
func (r *Router) HandleFunc(path string, f func(http.ResponseWriter,
	*http.Request)) *Route {
	return r.NewRoute().Path(path).HandlerFunc(f)
}

// Headers registers a new route with a matcher for request header values.
// See Route.Headers().
func (r *Router) Headers(pairs ...string) *Route {
	return r.NewRoute().Headers(pairs...)
}

// Host registers a new route with a matcher for the URL host.
// See Route.Host().
func (r *Router) Host(tpl string) *Route {
	return r.NewRoute().Host(tpl)
}

// MatcherFunc registers a new route with a custom matcher function.
// See Route.MatcherFunc().
func (r *Router) MatcherFunc(f MatcherFunc) *Route {
	return r.NewRoute().MatcherFunc(f)
}

// Methods registers a new route with a matcher for HTTP methods.
// See Route.Methods().
func (r *Router) Methods(methods ...string) *Route {
	return r.NewRoute().Methods(methods...)
}

// Path registers a new route with a matcher for the URL path.
// See Route.Path().
func (r *Router) Path(tpl string) *Route {
	return r.NewRoute().Path(tpl)
}

// PathPrefix registers a new route with a matcher for the URL path prefix.
// See Route.PathPrefix().
func (r *Router) PathPrefix(tpl string) *Route {
	return r.NewRoute().PathPrefix(tpl)
}

// Queries registers a new route with a matcher for URL query values.
// See Route.Queries().
func (r *Router) Queries(pairs ...string) *Route {
	return r.NewRoute().Queries(pairs...)
}

// Schemes registers a new route with a matcher for URL schemes.
// See Route.Schemes().
func (r *Router) Schemes(schemes ...string) *Route {
	return r.NewRoute().Schemes(schemes...)
}

// BuildVars registers a new route with a custom function for modifying
// route variables before building a URL.
func (r *Router) BuildVarsFunc(f BuildVarsFunc) *Route {
	return r.NewRoute().BuildVarsFunc(f)
}

// ----------------------------------------------------------------------------
// Context
// ----------------------------------------------------------------------------

// RouteMatch stores information about a matched route.
type RouteMatch struct {
	Route   *Route
	Handler http.Handler
	Vars    map[string]string
}

type contextKey int

const (
	varsKey contextKey = iota
	routeKey
)

// Vars returns the route variables for the current request, if any.
func Vars(r *http.Request) map[string]string {
	if rv := context.Get(r, varsKey); rv != nil {
		return rv.(map[string]string)
	}
	return nil
}

// CurrentRoute returns the matched route for the current request, if any.
func CurrentRoute(r *http.Request) *Route {
	if rv := context.Get(r, routeKey); rv != nil {
		return rv.(*Route)
	}
	return nil
}

func setVars(r *http.Request, val interface{}) {
	context.Set(r, varsKey, val)
}

func setCurrentRoute(r *http.Request, val interface{}) {
	context.Set(r, routeKey, val)
}

// ----------------------------------------------------------------------------
// Helpers
// ----------------------------------------------------------------------------

// cleanPath returns the canonical path for p, eliminating . and .. elements.
// Borrowed from the net/http package.
func cleanPath(p string) string {
	if p == "" {
		return "/"
	}
	if p[0] != '/' {
		p = "/" + p
	}
	np := path.Clean(p)
	// path.Clean removes trailing slash except for root;
	// put the trailing slash back if necessary.
	if p[len(p)-1] == '/' && np != "/" {
		np += "/"
	}
	return np
}

// uniqueVars returns an error if two slices contain duplicated strings.
func uniqueVars(s1, s2 []string) error {
	for _, v1 := range s1 {
		for _, v2 := range s2 {
			if v1 == v2 {
				return fmt.Errorf("mux: duplicated route variable %q", v2)
			}
		}
	}
	return nil
}

// mapFromPairs converts variadic string parameters to a string map.
func mapFromPairs(pairs ...string) (map[string]string, error) {
	length := len(pairs)
	if length%2 != 0 {
		return nil, fmt.Errorf(
			"mux: number of parameters must be multiple of 2, got %v", pairs)
	}
	m := make(map[string]string, length/2)
	for i := 0; i < length; i += 2 {
		m[pairs[i]] = pairs[i+1]
	}
	return m, nil
}

// matchInArray returns true if the given string value is in the array.
func matchInArray(arr []string, value string) bool {
	for _, v := range arr {
		if v == value {
			return true
		}
	}
	return false
}

// matchMap returns true if the given key/value pairs exist in a given map.
func matchMap(toCheck map[string]string, toMatch map[string][]string,
	canonicalKey bool) bool {
	for k, v := range toCheck {
		// Check if key exists.
		if canonicalKey {
			k = http.CanonicalHeaderKey(k)
		}
		if values := toMatch[k]; values == nil {
			return false
		} else if v != "" {
			// If value was defined as an empty string we only check that the
			// key exists. Otherwise we also check for equality.
			valueExists := false
			for _, value := range values {
				if v == value {
					valueExists = true
					break
				}
			}
			if !valueExists {
				return false
			}
		}
	}
	return true
}
<commit_msg>added GetMiddleware()<commit_after>// Copyright 2015 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package mux

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

	"github.com/gorilla/context"
)

// NewRouter returns a new router instance.
func NewRouter() *Router {
	return &Router{namedRoutes: make(map[string]*Route), KeepContext: false}
}

// Router registers routes to be matched and dispatches a handler.
//
// It implements the http.Handler interface, so it can be registered to serve
// requests:
//
//     var router = mux.NewRouter()
//
//     func main() {
//         http.Handle("/", router)
//     }
//
// Or, for Google App Engine, register it in a init() function:
//
//     func init() {
//         http.Handle("/", router)
//     }
//
// This will send all incoming requests to the router.
type Router struct {
	// Configurable Handler to be used when no route matches.
	NotFoundHandler http.Handler
	// Middleware handlers to be run
	middleware []MiddlewareHandler
	// Parent route, if this is a subrouter.
	parent parentRoute
	// Routes to be matched, in order.
	routes []*Route
	// Routes by name for URL building.
	namedRoutes map[string]*Route
	// See Router.StrictSlash(). This defines the flag for new routes.
	strictSlash bool
	// If true, do not clear the request context after handling the request
	KeepContext bool
}

// clone creates a deep-copied clone of a router
func (r *Router) clone() *Router {
	clone := *r
	clone.middleware = append([]MiddlewareHandler{}, r.middleware...)
	clone.routes = append([]*Route{}, r.routes...)
	clone.namedRoutes = make(map[string]*Route)
	for k, v := range r.namedRoutes {
		clone.namedRoutes[k] = v
	}
	return &clone
}

// Match matches registered routes against the request.
func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
	for _, route := range r.routes {
		if route.Match(req, match) {
			return true
		}
	}
	return false
}

// ServeHTTP dispatches the handler registered in the matched route.
//
// When there is a match, the route variables can be retrieved calling
// mux.Vars(request).
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	// Clean path to canonical form and redirect.
	if p := cleanPath(req.URL.Path); p != req.URL.Path {

		// Added 3 lines (Philip Schlump) - It was droping the query string and #whatever from query.
		// This matches with fix in go 1.2 r.c. 4 for same problem.  Go Issue:
		// http://code.google.com/p/go/issues/detail?id=5252
		url := *req.URL
		url.Path = p
		p = url.String()

		w.Header().Set("Location", p)
		w.WriteHeader(http.StatusMovedPermanently)
		return
	}
	var match RouteMatch
	var handler http.Handler
	if r.Match(req, &match) {
		handler = match.Handler
		setVars(req, match.Vars)
		setCurrentRoute(req, match.Route)
	}
	if handler == nil {
		handler = r.NotFoundHandler
		if handler == nil {
			handler = http.NotFoundHandler()
		}
	}
	if !r.KeepContext {
		defer context.Clear(req)
	}

	buildMiddleware(r.middleware, handler).ServeHTTP(w, req)
}

// Get returns a route registered with the given name.
func (r *Router) Get(name string) *Route {
	return r.getNamedRoutes()[name]
}

// GetRoute returns a route registered with the given name. This method
// was renamed to Get() and remains here for backwards compatibility.
func (r *Router) GetRoute(name string) *Route {
	return r.getNamedRoutes()[name]
}

// StrictSlash defines the trailing slash behavior for new routes. The initial
// value is false.
//
// When true, if the route path is "/path/", accessing "/path" will redirect
// to the former and vice versa. In other words, your application will always
// see the path as specified in the route.
//
// When false, if the route path is "/path", accessing "/path/" will not match
// this route and vice versa.
//
// Special case: when a route sets a path prefix using the PathPrefix() method,
// strict slash is ignored for that route because the redirect behavior can't
// be determined from a prefix alone. However, any subrouters created from that
// route inherit the original StrictSlash setting.
func (r *Router) StrictSlash(value bool) *Router {
	r.strictSlash = value
	return r
}

// ----------------------------------------------------------------------------
// parentRoute
// ----------------------------------------------------------------------------

// getNamedRoutes returns the map where named routes are registered.
func (r *Router) getNamedRoutes() map[string]*Route {
	if r.namedRoutes == nil {
		if r.parent != nil {
			r.namedRoutes = r.parent.getNamedRoutes()
		} else {
			r.namedRoutes = make(map[string]*Route)
		}
	}
	return r.namedRoutes
}

// getRegexpGroup returns regexp definitions from the parent route, if any.
func (r *Router) getRegexpGroup() *routeRegexpGroup {
	if r.parent != nil {
		return r.parent.getRegexpGroup()
	}
	return nil
}

func (r *Router) buildVars(m map[string]string) map[string]string {
	if r.parent != nil {
		m = r.parent.buildVars(m)
	}
	return m
}

// ----------------------------------------------------------------------------
// Middleware -- kindly borrowed from negroni
// ----------------------------------------------------------------------------

// MiddlewareHandler is an interface that objects can implement to be registered to serve as middleware
// in the mux middleware stack.
// ServeHTTP should yield to the next middleware in the chain by invoking the next http.HandlerFunc
// passed in.
//
// If the MiddlewareHandler writes to the ResponseWriter, the next http.HandlerFunc should not be invoked.
type MiddlewareHandler interface {
	ServeHTTP(http.ResponseWriter, *http.Request, http.HandlerFunc)
}

// MiddlewareHandlerFunc is an adapter to allow the use of ordinary functions as middleware handlers.
// If f is a function with the appropriate signature, MiddlewareHandlerFunc(f) is a MiddlewareHandler object that calls f.
type MiddlewareHandlerFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)

func (h MiddlewareHandlerFunc) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	h(rw, r, next)
}

// WrapMiddleware converts a http.Handler into a mux.MiddlewareHandler so it can be used as mux
// middleware. The next http.HandlerFunc is automatically called after the MiddlewareHandler
// is executed.
func WrapMiddleware(handler http.Handler) MiddlewareHandler {
	return MiddlewareHandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
		handler.ServeHTTP(rw, r)
		next(rw, r)
	})
}

type middleware struct {
	handler MiddlewareHandler
	next    *middleware
}

func (m middleware) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
	m.handler.ServeHTTP(rw, r, m.next.ServeHTTP)
}

func buildMiddleware(handlers []MiddlewareHandler, final http.Handler) middleware {
	var next middleware

	if len(handlers) == 0 {
		return finalMiddleware(final)
	} else if len(handlers) > 1 {
		next = buildMiddleware(handlers[1:], final)
	} else {
		next = finalMiddleware(final)
	}

	return middleware{handlers[0], &next}
}

func finalMiddleware(final http.Handler) middleware {
	return middleware{
		MiddlewareHandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { final.ServeHTTP(rw, r) }),
		&middleware{},
	}
}

func (r *Router) UseMiddleware(m MiddlewareHandler) {
	r.middleware = append(r.middleware, m)
}

func (r *Router) UseMiddlewareFunc(m func(http.ResponseWriter, *http.Request, http.HandlerFunc)) {
	r.middleware = append(r.middleware, MiddlewareHandlerFunc(m))
}

func (r *Router) UseMiddlewareHandler(m http.Handler) {
	r.middleware = append(r.middleware, WrapMiddleware(m))
}

func (r *Router) UseMiddlewareHandlerFunc(m func(http.ResponseWriter, *http.Request)) {
	r.middleware = append(r.middleware, WrapMiddleware(http.HandlerFunc(m)))
}

func (r *Router) GetMiddleware() []MiddlewareHandler {
	return append([]MiddlewareHandler{}, r.middleware...)
}

// ----------------------------------------------------------------------------
// Route factories
// ----------------------------------------------------------------------------

// NewRoute registers an empty route.
func (r *Router) NewRoute() *Route {
	route := &Route{parent: r, strictSlash: r.strictSlash}
	r.routes = append(r.routes, route)
	return route
}

// Handle registers a new route with a matcher for the URL path.
// See Route.Path() and Route.Handler().
func (r *Router) Handle(path string, handler http.Handler) *Route {
	return r.NewRoute().Path(path).Handler(handler)
}

// HandleFunc registers a new route with a matcher for the URL path.
// See Route.Path() and Route.HandlerFunc().
func (r *Router) HandleFunc(path string, f func(http.ResponseWriter,
	*http.Request)) *Route {
	return r.NewRoute().Path(path).HandlerFunc(f)
}

// Headers registers a new route with a matcher for request header values.
// See Route.Headers().
func (r *Router) Headers(pairs ...string) *Route {
	return r.NewRoute().Headers(pairs...)
}

// Host registers a new route with a matcher for the URL host.
// See Route.Host().
func (r *Router) Host(tpl string) *Route {
	return r.NewRoute().Host(tpl)
}

// MatcherFunc registers a new route with a custom matcher function.
// See Route.MatcherFunc().
func (r *Router) MatcherFunc(f MatcherFunc) *Route {
	return r.NewRoute().MatcherFunc(f)
}

// Methods registers a new route with a matcher for HTTP methods.
// See Route.Methods().
func (r *Router) Methods(methods ...string) *Route {
	return r.NewRoute().Methods(methods...)
}

// Path registers a new route with a matcher for the URL path.
// See Route.Path().
func (r *Router) Path(tpl string) *Route {
	return r.NewRoute().Path(tpl)
}

// PathPrefix registers a new route with a matcher for the URL path prefix.
// See Route.PathPrefix().
func (r *Router) PathPrefix(tpl string) *Route {
	return r.NewRoute().PathPrefix(tpl)
}

// Queries registers a new route with a matcher for URL query values.
// See Route.Queries().
func (r *Router) Queries(pairs ...string) *Route {
	return r.NewRoute().Queries(pairs...)
}

// Schemes registers a new route with a matcher for URL schemes.
// See Route.Schemes().
func (r *Router) Schemes(schemes ...string) *Route {
	return r.NewRoute().Schemes(schemes...)
}

// BuildVars registers a new route with a custom function for modifying
// route variables before building a URL.
func (r *Router) BuildVarsFunc(f BuildVarsFunc) *Route {
	return r.NewRoute().BuildVarsFunc(f)
}

// ----------------------------------------------------------------------------
// Context
// ----------------------------------------------------------------------------

// RouteMatch stores information about a matched route.
type RouteMatch struct {
	Route   *Route
	Handler http.Handler
	Vars    map[string]string
}

type contextKey int

const (
	varsKey contextKey = iota
	routeKey
)

// Vars returns the route variables for the current request, if any.
func Vars(r *http.Request) map[string]string {
	if rv := context.Get(r, varsKey); rv != nil {
		return rv.(map[string]string)
	}
	return nil
}

// CurrentRoute returns the matched route for the current request, if any.
func CurrentRoute(r *http.Request) *Route {
	if rv := context.Get(r, routeKey); rv != nil {
		return rv.(*Route)
	}
	return nil
}

func setVars(r *http.Request, val interface{}) {
	context.Set(r, varsKey, val)
}

func setCurrentRoute(r *http.Request, val interface{}) {
	context.Set(r, routeKey, val)
}

// ----------------------------------------------------------------------------
// Helpers
// ----------------------------------------------------------------------------

// cleanPath returns the canonical path for p, eliminating . and .. elements.
// Borrowed from the net/http package.
func cleanPath(p string) string {
	if p == "" {
		return "/"
	}
	if p[0] != '/' {
		p = "/" + p
	}
	np := path.Clean(p)
	// path.Clean removes trailing slash except for root;
	// put the trailing slash back if necessary.
	if p[len(p)-1] == '/' && np != "/" {
		np += "/"
	}
	return np
}

// uniqueVars returns an error if two slices contain duplicated strings.
func uniqueVars(s1, s2 []string) error {
	for _, v1 := range s1 {
		for _, v2 := range s2 {
			if v1 == v2 {
				return fmt.Errorf("mux: duplicated route variable %q", v2)
			}
		}
	}
	return nil
}

// mapFromPairs converts variadic string parameters to a string map.
func mapFromPairs(pairs ...string) (map[string]string, error) {
	length := len(pairs)
	if length%2 != 0 {
		return nil, fmt.Errorf(
			"mux: number of parameters must be multiple of 2, got %v", pairs)
	}
	m := make(map[string]string, length/2)
	for i := 0; i < length; i += 2 {
		m[pairs[i]] = pairs[i+1]
	}
	return m, nil
}

// matchInArray returns true if the given string value is in the array.
func matchInArray(arr []string, value string) bool {
	for _, v := range arr {
		if v == value {
			return true
		}
	}
	return false
}

// matchMap returns true if the given key/value pairs exist in a given map.
func matchMap(toCheck map[string]string, toMatch map[string][]string,
	canonicalKey bool) bool {
	for k, v := range toCheck {
		// Check if key exists.
		if canonicalKey {
			k = http.CanonicalHeaderKey(k)
		}
		if values := toMatch[k]; values == nil {
			return false
		} else if v != "" {
			// If value was defined as an empty string we only check that the
			// key exists. Otherwise we also check for equality.
			valueExists := false
			for _, value := range values {
				if v == value {
					valueExists = true
					break
				}
			}
			if !valueExists {
				return false
			}
		}
	}
	return true
}
<|endoftext|>


<commit_before>package nsf

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"time"

	"github.com/mjibson/mog/codec"
	"github.com/mjibson/mog/codec/nsf/cpu6502"
)

const (
	// 1.79 MHz
	cpuClock = 236250000 / 11 / 12
)

var (
	// DefaultSampleRate is the default sample rate of a track after calling
	// Init().
	DefaultSampleRate int64 = 44100
	ErrUnrecognized         = errors.New("nsf: unrecognized format")
)

func init() {
	codec.RegisterCodec("NSF", "NESM\u001a", ReadNSFSongs)
}

const (
	NSF_HEADER_LEN = 0x80
	NSF_VERSION    = 0x5
	NSF_SONGS      = 0x6
	NSF_START      = 0x7
	NSF_LOAD       = 0x8
	NSF_INIT       = 0xa
	NSF_PLAY       = 0xc
	NSF_SONG       = 0xe
	NSF_ARTIST     = 0x2e
	NSF_COPYRIGHT  = 0x4e
	NSF_SPEED_NTSC = 0x6e
	NSF_BANKSWITCH = 0x70
	NSF_SPEED_PAL  = 0x78
	NSF_PAL_NTSC   = 0x7a
	NSF_EXTRA      = 0x7b
	NSF_ZERO       = 0x7c
)

func ReadNSFSongs(r io.Reader) ([]codec.Song, error) {
	n, err := ReadNSF(r)
	if err != nil {
		return nil, err
	}
	songs := make([]codec.Song, n.Songs)
	for i := range songs {
		songs[i] = &NSFSong{n, i + 1}
	}
	return songs, nil
}

type NSFSong struct {
	*NSF
	Index int
}

func (n *NSFSong) Play(samples int) []float32 {
	if n.playing == 0 {
		n.Init(n.Index)
	}
	return n.Play(samples)
}

func (n *NSFSong) Close() {
	// todo: implement
}

func (n *NSFSong) Info() codec.SongInfo {
	return codec.SongInfo{
		Time:       time.Minute * 2,
		Artist:     n.Artist,
		Album:      n.Song,
		Track:      n.Index,
		Title:      fmt.Sprintf("%s:%d", n.Song, n.Index),
		SampleRate: int(n.SampleRate),
		Channels:   1,
	}
}

func ReadNSF(r io.Reader) (n *NSF, err error) {
	n = New()
	n.b, err = ioutil.ReadAll(r)
	if err != nil {
		return
	}
	if len(n.b) < NSF_HEADER_LEN ||
		string(n.b[0:NSF_VERSION]) != "NESM\u001a" {
		return nil, ErrUnrecognized
	}
	n.Version = n.b[NSF_VERSION]
	n.Songs = n.b[NSF_SONGS]
	n.Start = n.b[NSF_START]
	n.LoadAddr = bLEtoUint16(n.b[NSF_LOAD:])
	n.InitAddr = bLEtoUint16(n.b[NSF_INIT:])
	n.PlayAddr = bLEtoUint16(n.b[NSF_PLAY:])
	n.Song = bToString(n.b[NSF_SONG:])
	n.Artist = bToString(n.b[NSF_ARTIST:])
	n.Copyright = bToString(n.b[NSF_COPYRIGHT:])
	n.SpeedNTSC = bLEtoUint16(n.b[NSF_SPEED_NTSC:])
	copy(n.Bankswitch[:], n.b[NSF_BANKSWITCH:NSF_SPEED_PAL])
	n.SpeedPAL = bLEtoUint16(n.b[NSF_SPEED_PAL:])
	n.PALNTSC = n.b[NSF_PAL_NTSC]
	n.Extra = n.b[NSF_EXTRA]
	n.Data = n.b[NSF_HEADER_LEN:]
	if n.SampleRate == 0 {
		n.SampleRate = DefaultSampleRate
	}
	copy(n.Ram.M[n.LoadAddr:], n.Data)
	return
}

type NSF struct {
	*Ram
	*cpu6502.Cpu

	b []byte // raw NSF data

	Version byte
	Songs   byte
	Start   byte

	LoadAddr uint16
	InitAddr uint16
	PlayAddr uint16

	Song      string
	Artist    string
	Copyright string

	SpeedNTSC  uint16
	Bankswitch [8]byte
	SpeedPAL   uint16
	PALNTSC    byte
	Extra      byte
	Data       []byte

	// SampleRate is the sample rate at which samples will be generated. If not
	// set before Init(), it is set to DefaultSampleRate.
	SampleRate  int64
	totalTicks  int64
	frameTicks  int64
	sampleTicks int64
	playTicks   int64
	samples     []float32
	prevs       [4]float32
	pi          int // prevs index
	playing     int // 1-based index of currently-playing song
}

func New() *NSF {
	n := NSF{
		Ram: new(Ram),
	}
	n.Cpu = cpu6502.New(n.Ram)
	n.Cpu.T = &n
	n.Cpu.DisableDecimal = true
	n.Cpu.P = 0x24
	n.Cpu.S = 0xfd
	return &n
}

func (n *NSF) Tick() {
	n.Ram.A.Step()
	n.totalTicks++
	n.frameTicks++
	if n.frameTicks == cpuClock/240 {
		n.frameTicks = 0
		n.Ram.A.FrameStep()
	}
	n.sampleTicks++
	if n.SampleRate > 0 && n.sampleTicks >= cpuClock/n.SampleRate {
		n.sampleTicks = 0
		n.append(n.Ram.A.Volume())
	}
	n.playTicks++
}

func (n *NSF) append(v float32) {
	n.prevs[n.pi] = v
	n.pi++
	if n.pi >= len(n.prevs) {
		n.pi = 0
	}
	var sum float32
	for _, s := range n.prevs {
		sum += s
	}
	sum /= float32(len(n.prevs))
	n.samples = append(n.samples, sum)
}

func (n *NSF) Init(song int) {
	n.Ram.A.Init()
	n.Cpu.A = byte(song - 1)
	n.Cpu.PC = n.InitAddr
	n.Cpu.T = nil
	n.Cpu.Run()
	n.Cpu.T = n
}

func (n *NSF) Step() {
	n.Cpu.Step()
	if !n.Cpu.I() && n.Ram.A.Interrupt {
		n.Cpu.Interrupt()
	}
}

func (n *NSF) Play(samples int) []float32 {
	playDur := time.Duration(n.SpeedNTSC) * time.Nanosecond * 1000
	ticksPerPlay := int64(playDur / (time.Second / cpuClock))
	n.samples = make([]float32, 0, samples)
	for len(n.samples) < samples {
		n.playTicks = 0
		n.Cpu.PC = n.PlayAddr
		for n.Cpu.PC != 0 && len(n.samples) < samples {
			n.Step()
		}
		for i := ticksPerPlay - n.playTicks; i > 0 && len(n.samples) < samples; i-- {
			n.Tick()
		}
	}
	return n.samples
}

// little-endian [2]byte to uint16 conversion
func bLEtoUint16(b []byte) uint16 {
	return uint16(b[1])<<8 + uint16(b[0])
}

// null-terminated bytes to string
func bToString(b []byte) string {
	i := 0
	for i = range b {
		if b[i] == 0 {
			break
		}
	}
	return string(b[:i])
}

type Ram struct {
	M [0xffff + 1]byte
	A Apu
}

func (r *Ram) Read(v uint16) byte {
	switch v {
	case 0x4015:
		return r.A.Read(v)
	default:
		return r.M[v]
	}
}

func (r *Ram) Write(v uint16, b byte) {
	r.M[v] = b
	if v&0xf000 == 0x4000 {
		r.A.Write(v, b)
	}
}

func (n *NSF) Seek(t time.Time) {
	// todo: implement
}
<commit_msg>Call correct embedded function<commit_after>package nsf

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"time"

	"github.com/mjibson/mog/codec"
	"github.com/mjibson/mog/codec/nsf/cpu6502"
)

const (
	// 1.79 MHz
	cpuClock = 236250000 / 11 / 12
)

var (
	// DefaultSampleRate is the default sample rate of a track after calling
	// Init().
	DefaultSampleRate int64 = 44100
	ErrUnrecognized         = errors.New("nsf: unrecognized format")
)

func init() {
	codec.RegisterCodec("NSF", "NESM\u001a", ReadNSFSongs)
}

const (
	NSF_HEADER_LEN = 0x80
	NSF_VERSION    = 0x5
	NSF_SONGS      = 0x6
	NSF_START      = 0x7
	NSF_LOAD       = 0x8
	NSF_INIT       = 0xa
	NSF_PLAY       = 0xc
	NSF_SONG       = 0xe
	NSF_ARTIST     = 0x2e
	NSF_COPYRIGHT  = 0x4e
	NSF_SPEED_NTSC = 0x6e
	NSF_BANKSWITCH = 0x70
	NSF_SPEED_PAL  = 0x78
	NSF_PAL_NTSC   = 0x7a
	NSF_EXTRA      = 0x7b
	NSF_ZERO       = 0x7c
)

func ReadNSFSongs(r io.Reader) ([]codec.Song, error) {
	n, err := ReadNSF(r)
	if err != nil {
		return nil, err
	}
	songs := make([]codec.Song, n.Songs)
	for i := range songs {
		songs[i] = &NSFSong{n, i + 1}
	}
	return songs, nil
}

type NSFSong struct {
	*NSF
	Index int
}

func (n *NSFSong) Play(samples int) []float32 {
	if n.playing == 0 {
		n.Init(n.Index)
	}
	return n.NSF.Play(samples)
}

func (n *NSFSong) Close() {
	// todo: implement
}

func (n *NSFSong) Info() codec.SongInfo {
	return codec.SongInfo{
		Time:       time.Minute * 2,
		Artist:     n.Artist,
		Album:      n.Song,
		Track:      n.Index,
		Title:      fmt.Sprintf("%s:%d", n.Song, n.Index),
		SampleRate: int(n.SampleRate),
		Channels:   1,
	}
}

func ReadNSF(r io.Reader) (n *NSF, err error) {
	n = New()
	n.b, err = ioutil.ReadAll(r)
	if err != nil {
		return
	}
	if len(n.b) < NSF_HEADER_LEN ||
		string(n.b[0:NSF_VERSION]) != "NESM\u001a" {
		return nil, ErrUnrecognized
	}
	n.Version = n.b[NSF_VERSION]
	n.Songs = n.b[NSF_SONGS]
	n.Start = n.b[NSF_START]
	n.LoadAddr = bLEtoUint16(n.b[NSF_LOAD:])
	n.InitAddr = bLEtoUint16(n.b[NSF_INIT:])
	n.PlayAddr = bLEtoUint16(n.b[NSF_PLAY:])
	n.Song = bToString(n.b[NSF_SONG:])
	n.Artist = bToString(n.b[NSF_ARTIST:])
	n.Copyright = bToString(n.b[NSF_COPYRIGHT:])
	n.SpeedNTSC = bLEtoUint16(n.b[NSF_SPEED_NTSC:])
	copy(n.Bankswitch[:], n.b[NSF_BANKSWITCH:NSF_SPEED_PAL])
	n.SpeedPAL = bLEtoUint16(n.b[NSF_SPEED_PAL:])
	n.PALNTSC = n.b[NSF_PAL_NTSC]
	n.Extra = n.b[NSF_EXTRA]
	n.Data = n.b[NSF_HEADER_LEN:]
	if n.SampleRate == 0 {
		n.SampleRate = DefaultSampleRate
	}
	copy(n.Ram.M[n.LoadAddr:], n.Data)
	return
}

type NSF struct {
	*Ram
	*cpu6502.Cpu

	b []byte // raw NSF data

	Version byte
	Songs   byte
	Start   byte

	LoadAddr uint16
	InitAddr uint16
	PlayAddr uint16

	Song      string
	Artist    string
	Copyright string

	SpeedNTSC  uint16
	Bankswitch [8]byte
	SpeedPAL   uint16
	PALNTSC    byte
	Extra      byte
	Data       []byte

	// SampleRate is the sample rate at which samples will be generated. If not
	// set before Init(), it is set to DefaultSampleRate.
	SampleRate  int64
	totalTicks  int64
	frameTicks  int64
	sampleTicks int64
	playTicks   int64
	samples     []float32
	prevs       [4]float32
	pi          int // prevs index
	playing     int // 1-based index of currently-playing song
}

func New() *NSF {
	n := NSF{
		Ram: new(Ram),
	}
	n.Cpu = cpu6502.New(n.Ram)
	n.Cpu.T = &n
	n.Cpu.DisableDecimal = true
	n.Cpu.P = 0x24
	n.Cpu.S = 0xfd
	return &n
}

func (n *NSF) Tick() {
	n.Ram.A.Step()
	n.totalTicks++
	n.frameTicks++
	if n.frameTicks == cpuClock/240 {
		n.frameTicks = 0
		n.Ram.A.FrameStep()
	}
	n.sampleTicks++
	if n.SampleRate > 0 && n.sampleTicks >= cpuClock/n.SampleRate {
		n.sampleTicks = 0
		n.append(n.Ram.A.Volume())
	}
	n.playTicks++
}

func (n *NSF) append(v float32) {
	n.prevs[n.pi] = v
	n.pi++
	if n.pi >= len(n.prevs) {
		n.pi = 0
	}
	var sum float32
	for _, s := range n.prevs {
		sum += s
	}
	sum /= float32(len(n.prevs))
	n.samples = append(n.samples, sum)
}

func (n *NSF) Init(song int) {
	n.Ram.A.Init()
	n.Cpu.A = byte(song - 1)
	n.Cpu.PC = n.InitAddr
	n.Cpu.T = nil
	n.Cpu.Run()
	n.Cpu.T = n
}

func (n *NSF) Step() {
	n.Cpu.Step()
	if !n.Cpu.I() && n.Ram.A.Interrupt {
		n.Cpu.Interrupt()
	}
}

func (n *NSF) Play(samples int) []float32 {
	playDur := time.Duration(n.SpeedNTSC) * time.Nanosecond * 1000
	ticksPerPlay := int64(playDur / (time.Second / cpuClock))
	n.samples = make([]float32, 0, samples)
	for len(n.samples) < samples {
		n.playTicks = 0
		n.Cpu.PC = n.PlayAddr
		for n.Cpu.PC != 0 && len(n.samples) < samples {
			n.Step()
		}
		for i := ticksPerPlay - n.playTicks; i > 0 && len(n.samples) < samples; i-- {
			n.Tick()
		}
	}
	return n.samples
}

// little-endian [2]byte to uint16 conversion
func bLEtoUint16(b []byte) uint16 {
	return uint16(b[1])<<8 + uint16(b[0])
}

// null-terminated bytes to string
func bToString(b []byte) string {
	i := 0
	for i = range b {
		if b[i] == 0 {
			break
		}
	}
	return string(b[:i])
}

type Ram struct {
	M [0xffff + 1]byte
	A Apu
}

func (r *Ram) Read(v uint16) byte {
	switch v {
	case 0x4015:
		return r.A.Read(v)
	default:
		return r.M[v]
	}
}

func (r *Ram) Write(v uint16, b byte) {
	r.M[v] = b
	if v&0xf000 == 0x4000 {
		r.A.Write(v, b)
	}
}

func (n *NSF) Seek(t time.Time) {
	// todo: implement
}
<|endoftext|>


<commit_before>package nsf

import (
	"errors"
	"io"
	"io/ioutil"
	"time"

	"github.com/mjibson/mog/codec/nsf/cpu6502"
)

const (
	// 1.79 MHz
	cpuClock = 236250000 / 11 / 12
)

var (
	// DefaultSampleRate is the default sample rate of a track after calling
	// Init().
	DefaultSampleRate = 44100
	ErrUnrecognized   = errors.New("nsf: unrecognized format")
)

const (
	NSF_HEADER_LEN = 0x80
	NSF_VERSION    = 0x5
	NSF_SONGS      = 0x6
	NSF_START      = 0x7
	NSF_LOAD       = 0x8
	NSF_INIT       = 0xa
	NSF_PLAY       = 0xc
	NSF_SONG       = 0xe
	NSF_ARTIST     = 0x2e
	NSF_COPYRIGHT  = 0x4e
	NSF_SPEED_NTSC = 0x6e
	NSF_BANKSWITCH = 0x70
	NSF_SPEED_PAL  = 0x78
	NSF_PAL_NTSC   = 0x7a
	NSF_EXTRA      = 0x7b
	NSF_ZERO       = 0x7c
)

func ReadNSF(r io.Reader) (n *NSF, err error) {
	n = &NSF{}
	n.b, err = ioutil.ReadAll(r)
	if err != nil {
		return
	}
	if len(n.b) < NSF_HEADER_LEN ||
		string(n.b[0:NSF_VERSION]) != "NESM\u001a" {
		return nil, ErrUnrecognized
	}
	n.Version = n.b[NSF_VERSION]
	n.Songs = n.b[NSF_SONGS]
	n.Start = n.b[NSF_START]
	n.LoadAddr = bLEtoUint16(n.b[NSF_LOAD:])
	n.InitAddr = bLEtoUint16(n.b[NSF_INIT:])
	n.PlayAddr = bLEtoUint16(n.b[NSF_PLAY:])
	n.Song = bToString(n.b[NSF_SONG:])
	n.Artist = bToString(n.b[NSF_ARTIST:])
	n.Copyright = bToString(n.b[NSF_COPYRIGHT:])
	n.SpeedNTSC = bLEtoUint16(n.b[NSF_SPEED_NTSC:])
	copy(n.Bankswitch[:], n.b[NSF_BANKSWITCH:NSF_SPEED_PAL])
	n.SpeedPAL = bLEtoUint16(n.b[NSF_SPEED_PAL:])
	n.PALNTSC = n.b[NSF_PAL_NTSC]
	n.Extra = n.b[NSF_EXTRA]
	n.Data = n.b[NSF_HEADER_LEN:]
	return
}

type NSF struct {
	*Ram
	*cpu6502.Cpu

	b []byte // raw NSF data

	Version byte
	Songs   byte
	Start   byte

	LoadAddr uint16
	InitAddr uint16
	PlayAddr uint16

	Song      string
	Artist    string
	Copyright string

	SpeedNTSC  uint16
	Bankswitch [8]byte
	SpeedPAL   uint16
	PALNTSC    byte
	Extra      byte
	Data       []byte

	// SampleRate is the sample rate at which samples will be generated. If not
	// set before Init(), it is set to DefaultSampleRate.
	SampleRate  int64
	totalTicks  int64
	frameTicks  int64
	sampleTicks int64
	playTicks   int64
	samples     []float32
	prevs       [4]float32
	pi          int // prevs index
}

func (n *NSF) Tick() {
	n.Ram.A.Step()
	n.totalTicks++
	n.frameTicks++
	if n.frameTicks == cpuClock/240 {
		n.frameTicks = 0
		n.Ram.A.FrameStep()
	}
	n.sampleTicks++
	if n.sampleTicks >= cpuClock/n.SampleRate {
		n.sampleTicks = 0
		n.append(n.Ram.A.Volume())
	}
	n.playTicks++
}

func (n *NSF) append(v float32) {
	n.prevs[n.pi] = v
	n.pi++
	if n.pi >= len(n.prevs) {
		n.pi = 0
	}
	var sum float32
	for _, s := range n.prevs {
		sum += s
	}
	sum /= float32(len(n.prevs))
	n.samples = append(n.samples, sum)
}

func (n *NSF) Init(song byte) {
	if n.SampleRate == 0 {
		n.SampleRate = int64(DefaultSampleRate)
	}
	n.Ram = new(Ram)
	n.Cpu = cpu6502.New(n.Ram)
	copy(n.Ram.M[n.LoadAddr:], n.Data)
	n.Ram.A.Init()
	n.Cpu.A = song - 1
	n.Cpu.PC = n.InitAddr
	n.Cpu.T = nil
	n.Cpu.Run()
	n.Cpu.T = n
}

func (n *NSF) Play(samples int) []float32 {
	playDur := time.Duration(n.SpeedNTSC) * time.Nanosecond * 1000
	ticksPerPlay := int64(playDur / (time.Second / cpuClock))
	n.samples = make([]float32, 0, samples)
	for len(n.samples) < samples {
		n.playTicks = 0
		n.Cpu.PC = n.PlayAddr
		n.Cpu.Halt = false
		for !n.Cpu.Halt && len(n.samples) < samples {
			n.Cpu.Step()
			if !n.Cpu.I() {
				panic("INTERRUPT")
			}
		}
		for i := ticksPerPlay - n.playTicks; i > 0 && len(n.samples) < samples; i-- {
			n.Tick()
		}
	}
	return n.samples
}

// little-endian [2]byte to uint16 conversion
func bLEtoUint16(b []byte) uint16 {
	return uint16(b[1])<<8 + uint16(b[0])
}

// null-terminated bytes to string
func bToString(b []byte) string {
	i := 0
	for i = range b {
		if b[i] == 0 {
			break
		}
	}
	return string(b[:i])
}

type Ram struct {
	M [0xffff + 1]byte
	A Apu
}

func (r *Ram) Read(v uint16) byte {
	switch v {
	//case 0x2002:
	//return 0x80
	case 0x4015:
		return r.A.Read(v)
	default:
		return r.M[v]
	}
}

func (r *Ram) Write(v uint16, b byte) {
	r.M[v] = b
	if v&0xf000 == 0x4000 {
		r.A.Write(v, b)
	}
}
<commit_msg>Correctly init the CPU<commit_after>package nsf

import (
	"errors"
	"io"
	"io/ioutil"
	"time"

	"github.com/mjibson/mog/codec/nsf/cpu6502"
)

const (
	// 1.79 MHz
	cpuClock = 236250000 / 11 / 12
)

var (
	// DefaultSampleRate is the default sample rate of a track after calling
	// Init().
	DefaultSampleRate = 44100
	ErrUnrecognized   = errors.New("nsf: unrecognized format")
)

const (
	NSF_HEADER_LEN = 0x80
	NSF_VERSION    = 0x5
	NSF_SONGS      = 0x6
	NSF_START      = 0x7
	NSF_LOAD       = 0x8
	NSF_INIT       = 0xa
	NSF_PLAY       = 0xc
	NSF_SONG       = 0xe
	NSF_ARTIST     = 0x2e
	NSF_COPYRIGHT  = 0x4e
	NSF_SPEED_NTSC = 0x6e
	NSF_BANKSWITCH = 0x70
	NSF_SPEED_PAL  = 0x78
	NSF_PAL_NTSC   = 0x7a
	NSF_EXTRA      = 0x7b
	NSF_ZERO       = 0x7c
)

func ReadNSF(r io.Reader) (n *NSF, err error) {
	n = &NSF{}
	n.b, err = ioutil.ReadAll(r)
	if err != nil {
		return
	}
	if len(n.b) < NSF_HEADER_LEN ||
		string(n.b[0:NSF_VERSION]) != "NESM\u001a" {
		return nil, ErrUnrecognized
	}
	n.Version = n.b[NSF_VERSION]
	n.Songs = n.b[NSF_SONGS]
	n.Start = n.b[NSF_START]
	n.LoadAddr = bLEtoUint16(n.b[NSF_LOAD:])
	n.InitAddr = bLEtoUint16(n.b[NSF_INIT:])
	n.PlayAddr = bLEtoUint16(n.b[NSF_PLAY:])
	n.Song = bToString(n.b[NSF_SONG:])
	n.Artist = bToString(n.b[NSF_ARTIST:])
	n.Copyright = bToString(n.b[NSF_COPYRIGHT:])
	n.SpeedNTSC = bLEtoUint16(n.b[NSF_SPEED_NTSC:])
	copy(n.Bankswitch[:], n.b[NSF_BANKSWITCH:NSF_SPEED_PAL])
	n.SpeedPAL = bLEtoUint16(n.b[NSF_SPEED_PAL:])
	n.PALNTSC = n.b[NSF_PAL_NTSC]
	n.Extra = n.b[NSF_EXTRA]
	n.Data = n.b[NSF_HEADER_LEN:]
	return
}

type NSF struct {
	*Ram
	*cpu6502.Cpu

	b []byte // raw NSF data

	Version byte
	Songs   byte
	Start   byte

	LoadAddr uint16
	InitAddr uint16
	PlayAddr uint16

	Song      string
	Artist    string
	Copyright string

	SpeedNTSC  uint16
	Bankswitch [8]byte
	SpeedPAL   uint16
	PALNTSC    byte
	Extra      byte
	Data       []byte

	// SampleRate is the sample rate at which samples will be generated. If not
	// set before Init(), it is set to DefaultSampleRate.
	SampleRate  int64
	totalTicks  int64
	frameTicks  int64
	sampleTicks int64
	playTicks   int64
	samples     []float32
	prevs       [4]float32
	pi          int // prevs index
}

func New() *NSF {
	n := NSF{
		Ram: new(Ram),
	}
	n.Cpu = cpu6502.New(n.Ram)
	n.Cpu.DisableDecimal = true
	n.Cpu.P = 0x24
	n.Cpu.S = 0xfd
	return &n
}

func (n *NSF) Tick() {
	n.Ram.A.Step()
	n.totalTicks++
	n.frameTicks++
	if n.frameTicks == cpuClock/240 {
		n.frameTicks = 0
		n.Ram.A.FrameStep()
	}
	n.sampleTicks++
	if n.sampleTicks >= cpuClock/n.SampleRate {
		n.sampleTicks = 0
		n.append(n.Ram.A.Volume())
	}
	n.playTicks++
}

func (n *NSF) append(v float32) {
	n.prevs[n.pi] = v
	n.pi++
	if n.pi >= len(n.prevs) {
		n.pi = 0
	}
	var sum float32
	for _, s := range n.prevs {
		sum += s
	}
	sum /= float32(len(n.prevs))
	n.samples = append(n.samples, sum)
}

func (n *NSF) Init(song byte) {
	if n.SampleRate == 0 {
		n.SampleRate = int64(DefaultSampleRate)
	}
	copy(n.Ram.M[n.LoadAddr:], n.Data)
	n.Ram.A.Init()
	n.Cpu.A = song - 1
	n.Cpu.PC = n.InitAddr
	n.Cpu.T = nil
	n.Cpu.Run()
	n.Cpu.T = n
}

func (n *NSF) Play(samples int) []float32 {
	playDur := time.Duration(n.SpeedNTSC) * time.Nanosecond * 1000
	ticksPerPlay := int64(playDur / (time.Second / cpuClock))
	n.samples = make([]float32, 0, samples)
	for len(n.samples) < samples {
		n.playTicks = 0
		n.Cpu.PC = n.PlayAddr
		n.Cpu.Halt = false
		for !n.Cpu.Halt && len(n.samples) < samples {
			n.Cpu.Step()
			if !n.Cpu.I() {
				panic("INTERRUPT")
			}
		}
		for i := ticksPerPlay - n.playTicks; i > 0 && len(n.samples) < samples; i-- {
			n.Tick()
		}
	}
	return n.samples
}

// little-endian [2]byte to uint16 conversion
func bLEtoUint16(b []byte) uint16 {
	return uint16(b[1])<<8 + uint16(b[0])
}

// null-terminated bytes to string
func bToString(b []byte) string {
	i := 0
	for i = range b {
		if b[i] == 0 {
			break
		}
	}
	return string(b[:i])
}

type Ram struct {
	M [0xffff + 1]byte
	A Apu
}

func (r *Ram) Read(v uint16) byte {
	switch v {
	//case 0x2002:
	//return 0x80
	case 0x4015:
		return r.A.Read(v)
	default:
		return r.M[v]
	}
}

func (r *Ram) Write(v uint16, b byte) {
	r.M[v] = b
	if v&0xf000 == 0x4000 {
		r.A.Write(v, b)
	}
}
<|endoftext|>