<commit_before>/*--------------------------------------------------------*\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: https://hprose.com                     |
|                                                          |
| io/encoding/value_encode_test.go                         |
|                                                          |
| LastModified: Feb 22, 2020                               |
| Author: Ma Bingyao <andot@hprose.com>                    |
|                                                          |
\*________________________________________________________*/

package encoding

import (
	"math"
	"math/big"
	"strings"
	"testing"
	"time"
)

func TestWriteInt(t *testing.T) {
	sb := new(strings.Builder)
	if err := WriteInt(sb, -1); err != nil {
		t.Error(err)
	}
	if err := WriteInt(sb, 0); err != nil {
		t.Error(err)
	}
	if err := WriteInt(sb, 1); err != nil {
		t.Error(err)
	}
	if err := WriteInt(sb, 123); err != nil {
		t.Error(err)
	}
	if err := WriteInt(sb, math.MinInt64); err != nil {
		t.Error(err)
	}
	if err := WriteInt(sb, -math.MaxInt64); err != nil {
		t.Error(err)
	}
	if err := WriteInt(sb, math.MaxInt64); err != nil {
		t.Error(err)
	}
	if sb.String() != "i-1;01i123;l-9223372036854775808;l-9223372036854775807;l9223372036854775807;" {
		t.Error(sb)
	}
}

func TestWriteUint(t *testing.T) {
	sb := new(strings.Builder)
	if err := WriteUint(sb, 0); err != nil {
		t.Error(err)
	}
	if err := WriteUint(sb, 1); err != nil {
		t.Error(err)
	}
	if err := WriteUint(sb, 123); err != nil {
		t.Error(err)
	}
	if err := WriteUint(sb, math.MaxUint64); err != nil {
		t.Error(err)
	}
	if err := WriteUint(sb, math.MaxUint32); err != nil {
		t.Error(err)
	}
	if err := WriteUint(sb, math.MaxInt32); err != nil {
		t.Error(err)
	}
	if sb.String() != "01i123;l18446744073709551615;l4294967295;i2147483647;" {
		t.Error(sb)
	}
}

func TestWriteInt32(t *testing.T) {
	sb := &strings.Builder{}
	if err := WriteInt32(sb, -1); err != nil {
		t.Error(err)
	}
	if err := WriteInt32(sb, 0); err != nil {
		t.Error(err)
	}
	if err := WriteInt32(sb, 1); err != nil {
		t.Error(err)
	}
	if err := WriteInt32(sb, 123); err != nil {
		t.Error(err)
	}
	if err := WriteInt32(sb, math.MinInt32); err != nil {
		t.Error(err)
	}
	if err := WriteInt32(sb, math.MaxInt32); err != nil {
		t.Error(err)
	}
	if sb.String() != "i-1;01i123;i-2147483648;i2147483647;" {
		t.Error(sb)
	}
}

func TestWriteUint32(t *testing.T) {
	sb := &strings.Builder{}
	if err := WriteUint32(sb, 0); err != nil {
		t.Error(err)
	}
	if err := WriteUint32(sb, 1); err != nil {
		t.Error(err)
	}
	if err := WriteUint32(sb, 123); err != nil {
		t.Error(err)
	}
	if err := WriteUint32(sb, math.MaxUint32); err != nil {
		t.Error(err)
	}
	if err := WriteUint32(sb, math.MaxInt32); err != nil {
		t.Error(err)
	}
	if sb.String() != "01i123;l4294967295;i2147483647;" {
		t.Error(sb)
	}
}

func TestWriteUint16(t *testing.T) {
	sb := &strings.Builder{}
	if err := WriteUint16(sb, 0); err != nil {
		t.Error(err)
	}
	if err := WriteUint16(sb, 1); err != nil {
		t.Error(err)
	}
	if err := WriteUint16(sb, 123); err != nil {
		t.Error(err)
	}
	if err := WriteUint16(sb, math.MaxUint16); err != nil {
		t.Error(err)
	}
	if err := WriteUint16(sb, math.MaxInt16); err != nil {
		t.Error(err)
	}
	if sb.String() != "01i123;i65535;i32767;" {
		t.Error(sb)
	}
}

func TestWriteInt16(t *testing.T) {
	sb := &strings.Builder{}
	if err := WriteInt16(sb, 0); err != nil {
		t.Error(err)
	}
	if err := WriteInt16(sb, 1); err != nil {
		t.Error(err)
	}
	if err := WriteInt16(sb, 123); err != nil {
		t.Error(err)
	}
	if err := WriteInt16(sb, math.MinInt16); err != nil {
		t.Error(err)
	}
	if err := WriteInt16(sb, math.MaxInt16); err != nil {
		t.Error(err)
	}
	if sb.String() != "01i123;i-32768;i32767;" {
		t.Error(sb)
	}
}

func TestWriteUint8(t *testing.T) {
	sb := &strings.Builder{}
	if err := WriteUint8(sb, 0); err != nil {
		t.Error(err)
	}
	if err := WriteUint8(sb, 1); err != nil {
		t.Error(err)
	}
	if err := WriteUint8(sb, 123); err != nil {
		t.Error(err)
	}
	if err := WriteUint8(sb, math.MaxUint8); err != nil {
		t.Error(err)
	}
	if err := WriteUint8(sb, math.MaxInt8); err != nil {
		t.Error(err)
	}
	if sb.String() != "01i123;i255;i127;" {
		t.Error(sb)
	}
}

func TestWriteInt8(t *testing.T) {
	sb := &strings.Builder{}
	if err := WriteInt8(sb, 0); err != nil {
		t.Error(err)
	}
	if err := WriteInt8(sb, 1); err != nil {
		t.Error(err)
	}
	if err := WriteInt8(sb, 123); err != nil {
		t.Error(err)
	}
	if err := WriteInt8(sb, math.MinInt8); err != nil {
		t.Error(err)
	}
	if err := WriteInt8(sb, math.MaxInt8); err != nil {
		t.Error(err)
	}
	if sb.String() != "01i123;i-128;i127;" {
		t.Error(sb)
	}
}

func TestWriteNil(t *testing.T) {
	sb := &strings.Builder{}
	if err := WriteNil(sb); err != nil {
		t.Error(err)
	}
	if sb.String() != "n" {
		t.Error(sb)
	}
}

func TestWriteBool(t *testing.T) {
	sb := &strings.Builder{}
	if err := WriteBool(sb, true); err != nil {
		t.Error(err)
	}
	if err := WriteBool(sb, false); err != nil {
		t.Error(err)
	}
	if sb.String() != "tf" {
		t.Error(sb)
	}
}

func TestWriteFloat(t *testing.T) {
	sb := &strings.Builder{}
	if err := WriteFloat32(sb, math.E); err != nil {
		t.Error(err)
	}
	if err := WriteFloat32(sb, math.Pi); err != nil {
		t.Error(err)
	}
	if err := WriteFloat64(sb, math.E); err != nil {
		t.Error(err)
	}
	if err := WriteFloat64(sb, math.Pi); err != nil {
		t.Error(err)
	}
	if err := WriteFloat64(sb, math.Log(1)); err != nil {
		t.Error(err)
	}
	if err := WriteFloat64(sb, math.Log(0)); err != nil {
		t.Error(err)
	}
	if err := WriteFloat64(sb, -math.Log(0)); err != nil {
		t.Error(err)
	}
	if err := WriteFloat64(sb, math.Log(-1)); err != nil {
		t.Error(err)
	}
	if sb.String() != "d2.7182817;d3.1415927;d2.718281828459045;d3.141592653589793;d0;I-I+N" {
		t.Error(sb)
	}
}

func TestWriteString(t *testing.T) {
	sb := &strings.Builder{}
	if err := WriteString(sb, ""); err != nil {
		t.Error(err)
	}
	if err := WriteString(sb, "Hello"); err != nil {
		t.Error(err)
	}
	if err := WriteString(sb, "Pokémon"); err != nil {
		t.Error(err)
	}
	if err := WriteString(sb, "中文"); err != nil {
		t.Error(err)
	}
	if err := WriteString(sb, "🐱🐶"); err != nil {
		t.Error(err)
	}
	if err := WriteString(sb, "👩👩👧👧"); err != nil {
		t.Error(err)
	}
	if sb.String() != `s""s5"Hello"s7"Pokémon"s2"中文"s4"🐱🐶"s11"👩👩👧👧"` {
		t.Error(sb)
	}
}

func TestWriteBytes(t *testing.T) {
	sb := &strings.Builder{}
	if err := WriteBytes(sb, []byte("")); err != nil {
		t.Error(err)
	}
	if err := WriteBytes(sb, []byte("Hello")); err != nil {
		t.Error(err)
	}
	if err := WriteBytes(sb, []byte("Pokémon")); err != nil {
		t.Error(err)
	}
	if err := WriteBytes(sb, []byte("中文")); err != nil {
		t.Error(err)
	}
	if err := WriteBytes(sb, []byte("🐱🐶")); err != nil {
		t.Error(err)
	}
	if err := WriteBytes(sb, []byte("👩👩👧👧")); err != nil {
		t.Error(err)
	}
	if sb.String() != `b""b5"Hello"b8"Pokémon"b6"中文"b8"🐱🐶"b25"👩👩👧👧"` {
		t.Error(sb)
	}
}

func TestWriteBigInt(t *testing.T) {
	sb := &strings.Builder{}
	if err := WriteBigInt(sb, big.NewInt(math.MaxInt64)); err != nil {
		t.Error(err)
	}
	if sb.String() != "l9223372036854775807;" {
		t.Error(sb)
	}
}

func TestWriteBigFloat(t *testing.T) {
	sb := &strings.Builder{}
	if err := WriteBigFloat(sb, big.NewFloat(math.MaxFloat64)); err != nil {
		t.Error(err)
	}
	if sb.String() != "d1.7976931348623157e+308;" {
		t.Error(sb)
	}
}

func TestWriteTime(t *testing.T) {
	sb := &strings.Builder{}
	if err := WriteTime(sb, time.Date(2020, 2, 22, 0, 0, 0, 0, time.UTC)); err != nil {
		t.Error(err)
	}
	if err := WriteTime(sb, time.Date(1970, 1, 1, 12, 12, 12, 0, time.UTC)); err != nil {
		t.Error(err)
	}
	if err := WriteTime(sb, time.Date(1970, 1, 1, 12, 12, 12, 123456789, time.Local)); err != nil {
		t.Error(err)
	}
	if err := WriteTime(sb, time.Date(2020, 2, 22, 12, 12, 12, 123456000, time.Local)); err != nil {
		t.Error(err)
	}
	if err := WriteTime(sb, time.Date(2020, 2, 22, 12, 12, 12, 123000000, time.UTC)); err != nil {
		t.Error(err)
	}
	if sb.String() != "D20200222ZT121212ZT121212.123456789;D20200222T121212.123456;D20200222T121212.123Z" {
		t.Error(sb)
	}
}
<commit_msg>Delete value_encode_test.go<commit_after><|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	".."
)

func main(){
	stdOut := bufio.NewWriter(colorable.NewColorableStdout())

	fmt.Fprint(stdOut,"\x1B[3GMove to 3rd Column\n")
	fmt.Fprint(stdOut,"\x1B[1;2HMove to 2nd Column on 1st Line\n")
	stdOut.Flush()
}
<commit_msg>look absolutely<commit_after>package main

import (
	"bufio"
	"fmt"

	"github.com/mattn/go-colorable"
)

func main() {
	stdOut := bufio.NewWriter(colorable.NewColorableStdout())

	fmt.Fprint(stdOut, "\x1B[3GMove to 3rd Column\n")
	fmt.Fprint(stdOut, "\x1B[1;2HMove to 2nd Column on 1st Line\n")
	stdOut.Flush()
}
<|endoftext|>


<commit_before>// Copyright 2014 The gocui 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 main

import (
	"fmt"
	"io"
	"io/ioutil"
	"log"

	"github.com/jroimartin/gocui"
)

func nextView(g *gocui.Gui, v *gocui.View) error {
	if v == nil || v.Name() == "side" {
		return g.SetCurrentView("main")
	}
	return g.SetCurrentView("side")
}

func cursorDown(g *gocui.Gui, v *gocui.View) error {
	if v != nil {
		cx, cy := v.Cursor()
		if err := v.SetCursor(cx, cy+1); err != nil {
			ox, oy := v.Origin()
			if err := v.SetOrigin(ox, oy+1); err != nil {
				return err
			}
		}
	}
	return nil
}

func cursorUp(g *gocui.Gui, v *gocui.View) error {
	if v != nil {
		ox, oy := v.Origin()
		cx, cy := v.Cursor()
		if err := v.SetCursor(cx, cy-1); err != nil && oy > 0 {
			if err := v.SetOrigin(ox, oy-1); err != nil {
				return err
			}
		}
	}
	return nil
}

func cursorLeft(g *gocui.Gui, v *gocui.View) error {
	if v != nil {
		ox, oy := v.Origin()
		cx, cy := v.Cursor()
		if err := v.SetCursor(cx-1, cy); err != nil && ox > 0 {
			if err := v.SetOrigin(ox-1, oy); err != nil {
				return err
			}
		}
	}
	return nil
}

func cursorRight(g *gocui.Gui, v *gocui.View) error {
	if v != nil {
		cx, cy := v.Cursor()
		if err := v.SetCursor(cx+1, cy); err != nil {
			ox, oy := v.Origin()
			if err := v.SetOrigin(ox+1, oy); err != nil {
				return err
			}
		}
	}
	return nil
}

func getLine(g *gocui.Gui, v *gocui.View) error {
	var l string
	var err error

	_, cy := v.Cursor()
	if l, err = v.Line(cy); err != nil {
		l = ""
	}

	maxX, maxY := g.Size()
	if v, err := g.SetView("msg", maxX/2-30, maxY/2, maxX/2+30, maxY/2+2); err != nil {
		if err != gocui.ErrorUnkView {
			return err
		}
		fmt.Fprintln(v, l)
		if err := g.SetCurrentView("msg"); err != nil {
			return err
		}
	}
	return nil
}

func delMsg(g *gocui.Gui, v *gocui.View) error {
	if err := g.DeleteView("msg"); err != nil {
		return err
	}
	if err := g.SetCurrentView("side"); err != nil {
		return err
	}
	return nil
}

func quit(g *gocui.Gui, v *gocui.View) error {
	return gocui.Quit
}

func keybindings(g *gocui.Gui) error {
	if err := g.SetKeybinding("side", gocui.KeyCtrlSpace, gocui.ModNone, nextView); err != nil {
		return err
	}
	if err := g.SetKeybinding("main", gocui.KeyCtrlSpace, gocui.ModNone, nextView); err != nil {
		return err
	}
	if err := g.SetKeybinding("", gocui.KeyArrowDown, gocui.ModNone, cursorDown); err != nil {
		return err
	}
	if err := g.SetKeybinding("", gocui.KeyArrowUp, gocui.ModNone, cursorUp); err != nil {
		return err
	}
	if err := g.SetKeybinding("", gocui.KeyArrowLeft, gocui.ModNone, cursorLeft); err != nil {
		return err
	}
	if err := g.SetKeybinding("", gocui.KeyArrowRight, gocui.ModNone, cursorRight); err != nil {
		return err
	}
	if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
		return err
	}
	if err := g.SetKeybinding("side", gocui.KeyEnter, gocui.ModNone, getLine); err != nil {
		return err
	}
	if err := g.SetKeybinding("msg", gocui.KeyEnter, gocui.ModNone, delMsg); err != nil {
		return err
	}

	if err := g.SetKeybinding("main", gocui.KeyCtrlS, gocui.ModNone, saveMain); err != nil {
		return err
	}
	return nil
}

func saveMain(g *gocui.Gui, v *gocui.View) error {
	f, err := ioutil.TempFile("", "gocui_demo_")
	if err != nil {
		return err
	}
	defer f.Close()

	p := make([]byte, 5)
	v.Rewind()
	for {
		n, err := v.Read(p)
		if n > 0 {
			if _, err := f.Write(p[:n]); err != nil {
				return err
			}
		}
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}
	}
	return nil
}

func layout(g *gocui.Gui) error {
	maxX, maxY := g.Size()
	if v, err := g.SetView("side", -1, -1, 30, maxY); err != nil {
		if err != gocui.ErrorUnkView {
			return err
		}
		v.Highlight = true
		fmt.Fprintln(v, "Item 1")
		fmt.Fprintln(v, "Item 2")
		fmt.Fprintln(v, "Item 3")
		fmt.Fprint(v, "\rWill be")
		fmt.Fprintln(v, "deleted\rItem 4\nItem 5")
	}
	if v, err := g.SetView("main", 30, -1, maxX, maxY); err != nil {
		if err != gocui.ErrorUnkView {
			return err
		}
		b, err := ioutil.ReadFile("Mark.Twain-Tom.Sawyer.txt")
		if err != nil {
			panic(err)
		}
		fmt.Fprintf(v, "%s", b)
		v.Editable = true
		if err := g.SetCurrentView("main"); err != nil {
			return err
		}
	}
	return nil
}

func main() {
	var err error

	g := gocui.NewGui()
	if err := g.Init(); err != nil {
		log.Panicln(err)
	}
	defer g.Close()

	g.SetLayout(layout)
	if err := keybindings(g); err != nil {
		log.Panicln(err)
	}
	g.SelBgColor = gocui.ColorGreen
	g.SelFgColor = gocui.ColorBlack
	g.ShowCursor = true

	err = g.MainLoop()
	if err != nil && err != gocui.Quit {
		log.Panicln(err)
	}
}
<commit_msg>Minor fix in _examples/demo.go<commit_after>// Copyright 2014 The gocui 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 main

import (
	"fmt"
	"io"
	"io/ioutil"
	"log"

	"github.com/jroimartin/gocui"
)

func nextView(g *gocui.Gui, v *gocui.View) error {
	if v == nil || v.Name() == "side" {
		return g.SetCurrentView("main")
	}
	return g.SetCurrentView("side")
}

func cursorDown(g *gocui.Gui, v *gocui.View) error {
	if v != nil {
		cx, cy := v.Cursor()
		if err := v.SetCursor(cx, cy+1); err != nil {
			ox, oy := v.Origin()
			if err := v.SetOrigin(ox, oy+1); err != nil {
				return err
			}
		}
	}
	return nil
}

func cursorUp(g *gocui.Gui, v *gocui.View) error {
	if v != nil {
		ox, oy := v.Origin()
		cx, cy := v.Cursor()
		if err := v.SetCursor(cx, cy-1); err != nil && oy > 0 {
			if err := v.SetOrigin(ox, oy-1); err != nil {
				return err
			}
		}
	}
	return nil
}

func cursorLeft(g *gocui.Gui, v *gocui.View) error {
	if v != nil {
		ox, oy := v.Origin()
		cx, cy := v.Cursor()
		if err := v.SetCursor(cx-1, cy); err != nil && ox > 0 {
			if err := v.SetOrigin(ox-1, oy); err != nil {
				return err
			}
		}
	}
	return nil
}

func cursorRight(g *gocui.Gui, v *gocui.View) error {
	if v != nil {
		cx, cy := v.Cursor()
		if err := v.SetCursor(cx+1, cy); err != nil {
			ox, oy := v.Origin()
			if err := v.SetOrigin(ox+1, oy); err != nil {
				return err
			}
		}
	}
	return nil
}

func getLine(g *gocui.Gui, v *gocui.View) error {
	var l string
	var err error

	_, cy := v.Cursor()
	if l, err = v.Line(cy); err != nil {
		l = ""
	}

	maxX, maxY := g.Size()
	if v, err := g.SetView("msg", maxX/2-30, maxY/2, maxX/2+30, maxY/2+2); err != nil {
		if err != gocui.ErrorUnkView {
			return err
		}
		fmt.Fprintln(v, l)
		if err := g.SetCurrentView("msg"); err != nil {
			return err
		}
	}
	return nil
}

func delMsg(g *gocui.Gui, v *gocui.View) error {
	if err := g.DeleteView("msg"); err != nil {
		return err
	}
	if err := g.SetCurrentView("side"); err != nil {
		return err
	}
	return nil
}

func quit(g *gocui.Gui, v *gocui.View) error {
	return gocui.Quit
}

func keybindings(g *gocui.Gui) error {
	if err := g.SetKeybinding("side", gocui.KeyCtrlSpace, gocui.ModNone, nextView); err != nil {
		return err
	}
	if err := g.SetKeybinding("main", gocui.KeyCtrlSpace, gocui.ModNone, nextView); err != nil {
		return err
	}
	if err := g.SetKeybinding("", gocui.KeyArrowDown, gocui.ModNone, cursorDown); err != nil {
		return err
	}
	if err := g.SetKeybinding("", gocui.KeyArrowUp, gocui.ModNone, cursorUp); err != nil {
		return err
	}
	if err := g.SetKeybinding("", gocui.KeyArrowLeft, gocui.ModNone, cursorLeft); err != nil {
		return err
	}
	if err := g.SetKeybinding("", gocui.KeyArrowRight, gocui.ModNone, cursorRight); err != nil {
		return err
	}
	if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
		return err
	}
	if err := g.SetKeybinding("side", gocui.KeyEnter, gocui.ModNone, getLine); err != nil {
		return err
	}
	if err := g.SetKeybinding("msg", gocui.KeyEnter, gocui.ModNone, delMsg); err != nil {
		return err
	}

	if err := g.SetKeybinding("main", gocui.KeyCtrlS, gocui.ModNone, saveMain); err != nil {
		return err
	}
	return nil
}

func saveMain(g *gocui.Gui, v *gocui.View) error {
	f, err := ioutil.TempFile("", "gocui_demo_")
	if err != nil {
		return err
	}
	defer f.Close()

	p := make([]byte, 5)
	v.Rewind()
	for {
		n, err := v.Read(p)
		if n > 0 {
			if _, err := f.Write(p[:n]); err != nil {
				return err
			}
		}
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}
	}
	return nil
}

func layout(g *gocui.Gui) error {
	maxX, maxY := g.Size()
	if v, err := g.SetView("side", -1, -1, 30, maxY); err != nil {
		if err != gocui.ErrorUnkView {
			return err
		}
		v.Highlight = true
		fmt.Fprintln(v, "Item 1")
		fmt.Fprintln(v, "Item 2")
		fmt.Fprintln(v, "Item 3")
		fmt.Fprint(v, "\rWill be")
		fmt.Fprint(v, "deleted\rItem 4\nItem 5")
	}
	if v, err := g.SetView("main", 30, -1, maxX, maxY); err != nil {
		if err != gocui.ErrorUnkView {
			return err
		}
		b, err := ioutil.ReadFile("Mark.Twain-Tom.Sawyer.txt")
		if err != nil {
			panic(err)
		}
		fmt.Fprintf(v, "%s", b)
		v.Editable = true
		if err := g.SetCurrentView("main"); err != nil {
			return err
		}
	}
	return nil
}

func main() {
	var err error

	g := gocui.NewGui()
	if err := g.Init(); err != nil {
		log.Panicln(err)
	}
	defer g.Close()

	g.SetLayout(layout)
	if err := keybindings(g); err != nil {
		log.Panicln(err)
	}
	g.SelBgColor = gocui.ColorGreen
	g.SelFgColor = gocui.ColorBlack
	g.ShowCursor = true

	err = g.MainLoop()
	if err != nil && err != gocui.Quit {
		log.Panicln(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/gorilla/mux"
	"io/ioutil"
	"mime"
	"net/http"
	"os"
	"path"
	"strings"
)

func redirectLogin(w http.ResponseWriter, r *http.Request) {
	http.Redirect(w, r, os.Getenv("ORIGIN")+"/login", 301)
}

type staticPlugs struct {
	Origin    string
	CdnPrefix string
	Footer    string
}

var asset map[string][]byte = make(map[string][]byte)
var contentType map[string]string = make(map[string]string)
var footer string
var compress bool

func fileDetemplate(f string) ([]byte, error) {
	contents, err := ioutil.ReadFile(f)
	if err != nil {
		logger.Errorf("cannot read file %s: %v", f, err)
		return []byte{}, err
	}

	x := string(contents)
	x = strings.Replace(x, "[[[.Origin]]]", os.Getenv("ORIGIN"), -1)
	x = strings.Replace(x, "[[[.CdnPrefix]]]", os.Getenv("CDN_PREFIX"), -1)
	x = strings.Replace(x, "[[[.Footer]]]", footer, -1)

	return []byte(x), nil
}

func footerInit() error {
	contents, err := fileDetemplate(os.Getenv("STATIC") + "/footer.html")
	if err != nil {
		logger.Errorf("cannot init footer: %v", err)
		return err
	}

	footer = string(contents)
	return nil
}

func fileLoad(f string) ([]byte, error) {
	b, err := fileDetemplate(f)
	if err != nil {
		logger.Errorf("cannot load file %s: %v", f, err)
		return []byte{}, err
	}

	if !compress {
		return b, nil
	}

	return gzipStatic(b)
}

func staticRouterInit(router *mux.Router) error {
	var err error

	subdir := pathStrip(os.Getenv("ORIGIN"))

	if err = footerInit(); err != nil {
		logger.Errorf("error initialising static router: %v", err)
		return err
	}

	for _, dir := range []string{"/js", "/css", "/images", "/fonts"} {
		files, err := ioutil.ReadDir(os.Getenv("STATIC") + dir)
		if err != nil {
			logger.Errorf("cannot read directory %s%s: %v", os.Getenv("STATIC"), dir, err)
			return err
		}

		for _, file := range files {
			f := dir + "/" + file.Name()
			asset[subdir+f], err = fileLoad(os.Getenv("STATIC") + f)
			if err != nil {
				logger.Errorf("cannot detemplate %s%s: %v", os.Getenv("STATIC"), f, err)
				return err
			}
		}
	}

	pages := []string{
		"/login",
		"/forgot",
		"/reset-password",
		"/signup",
		"/confirm-email",
		"/unsubscribe",
		"/dashboard",
		"/logout",
	}

	for _, page := range pages {
		f := page + ".html"
		asset[subdir+page], err = fileLoad(os.Getenv("STATIC") + f)
		if err != nil {
			logger.Errorf("cannot detemplate %s%s: %v", os.Getenv("STATIC"), f, err)
			return err
		}
	}

	for p, _ := range asset {
		if path.Ext(p) != "" {
			contentType[p] = mime.TypeByExtension(path.Ext(p))
		} else {
			contentType[p] = mime.TypeByExtension("html")
		}

		router.HandleFunc(p, func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("Content-Type", contentType[r.URL.Path])
			if compress {
				w.Header().Set("Content-Encoding", "gzip")
			}
			w.Write(asset[r.URL.Path])
		})
	}

	router.HandleFunc("/", redirectLogin)

	return nil
}
<commit_msg>router_static.go: add charset for html content<commit_after>package main

import (
	"github.com/gorilla/mux"
	"io/ioutil"
	"mime"
	"net/http"
	"os"
	"path"
	"strings"
)

func redirectLogin(w http.ResponseWriter, r *http.Request) {
	http.Redirect(w, r, os.Getenv("ORIGIN")+"/login", 301)
}

type staticPlugs struct {
	Origin    string
	CdnPrefix string
	Footer    string
}

var asset map[string][]byte = make(map[string][]byte)
var contentType map[string]string = make(map[string]string)
var footer string
var compress bool

func fileDetemplate(f string) ([]byte, error) {
	contents, err := ioutil.ReadFile(f)
	if err != nil {
		logger.Errorf("cannot read file %s: %v", f, err)
		return []byte{}, err
	}

	x := string(contents)
	x = strings.Replace(x, "[[[.Origin]]]", os.Getenv("ORIGIN"), -1)
	x = strings.Replace(x, "[[[.CdnPrefix]]]", os.Getenv("CDN_PREFIX"), -1)
	x = strings.Replace(x, "[[[.Footer]]]", footer, -1)

	return []byte(x), nil
}

func footerInit() error {
	contents, err := fileDetemplate(os.Getenv("STATIC") + "/footer.html")
	if err != nil {
		logger.Errorf("cannot init footer: %v", err)
		return err
	}

	footer = string(contents)
	return nil
}

func fileLoad(f string) ([]byte, error) {
	b, err := fileDetemplate(f)
	if err != nil {
		logger.Errorf("cannot load file %s: %v", f, err)
		return []byte{}, err
	}

	if !compress {
		return b, nil
	}

	return gzipStatic(b)
}

func staticRouterInit(router *mux.Router) error {
	var err error

	subdir := pathStrip(os.Getenv("ORIGIN"))

	if err = footerInit(); err != nil {
		logger.Errorf("error initialising static router: %v", err)
		return err
	}

	for _, dir := range []string{"/js", "/css", "/images", "/fonts"} {
		files, err := ioutil.ReadDir(os.Getenv("STATIC") + dir)
		if err != nil {
			logger.Errorf("cannot read directory %s%s: %v", os.Getenv("STATIC"), dir, err)
			return err
		}

		for _, file := range files {
			f := dir + "/" + file.Name()
			asset[subdir+f], err = fileLoad(os.Getenv("STATIC") + f)
			if err != nil {
				logger.Errorf("cannot detemplate %s%s: %v", os.Getenv("STATIC"), f, err)
				return err
			}
		}
	}

	pages := []string{
		"/login",
		"/forgot",
		"/reset-password",
		"/signup",
		"/confirm-email",
		"/unsubscribe",
		"/dashboard",
		"/logout",
	}

	for _, page := range pages {
		f := page + ".html"
		asset[subdir+page], err = fileLoad(os.Getenv("STATIC") + f)
		if err != nil {
			logger.Errorf("cannot detemplate %s%s: %v", os.Getenv("STATIC"), f, err)
			return err
		}
	}

	for p, _ := range asset {
		if path.Ext(p) != "" {
			contentType[p] = mime.TypeByExtension(path.Ext(p))
		} else {
			contentType[p] = "text/html; charset=utf-8"
		}

		router.HandleFunc(p, func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("Content-Type", contentType[r.URL.Path])
			if compress {
				w.Header().Set("Content-Encoding", "gzip")
			}
			w.Write(asset[r.URL.Path])
		})
	}

	router.HandleFunc("/", redirectLogin)

	return nil
}
<|endoftext|>


<commit_before>// Reddit audiences crawler
// Rémy Mathieu © 2016
package api

import (
	"encoding/json"
	"log"
	"net/http"
	"time"

	"github.com/remeh/reddit-audiences/api/object"
	"github.com/remeh/reddit-audiences/app"
	"github.com/remeh/reddit-audiences/db"

	"github.com/gorilla/mux"
)

type TodayHandler struct {
	App *app.App
}

type todayHandlerResp struct {
	Audiences       []object.Audience   `json:"audiences"`
	Average         int64               `json:"average"`
	LowestAudience  object.Audience     `json:"lowest_audience"`
	HighestAudience object.Audience     `json:"highest_audience"`
	Articles        []object.Article    `json:"articles"`
	Annotations     []object.Annotation `json:"annotations"`
	DemoModeMessage bool                `json:"demo_mode_message"`
}

func (c TodayHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)

	subreddit := vars["subreddit"]
	if len(subreddit) == 0 {
		w.WriteHeader(400)
		return
	}

	r.ParseForm()
	t := r.Form.Get("t")
	hours := 36

	// ensure the right to retrieve more than 36h
	// ----------------------
	tmplParams := app.TmplParams(c.App, r, "ApiToday")

	demoModeMessage := false
	if len(t) > 0 && t != "36h" && len(tmplParams.User.Email) == 0 {
		// not auth user, demo message and stay on 36h
		demoModeMessage = true
	} else {
		// auth user, test if he wants 7 days of data
		if t == "7d" {
			hours = 24 * 7
		}
	}

	// retrieve data
	// ----------------------

	dataAudiences, dataRankings, dataArticles, err := c.getData(subreddit, hours)
	if err != nil {
		log.Println("err:", err.Error())
		w.WriteHeader(500)
		return
	}

	audiences := object.AudiencesFromApp(dataAudiences)
	lowest, highest := app.LowestHighest(dataAudiences)
	articles := object.ArticlesFromApp(dataArticles, dataRankings)

	// If the user is logged in, we need to
	// retrieve its annotations.
	// ----------------------
	user := app.GetUser(c.App.DB(), r)

	annotations := make([]object.Annotation, 0)
	if len(user.Email) > 0 {
		after := time.Now().Add(-time.Hour * time.Duration(hours))
		values, err := c.App.DB().FindAnnotations(subreddit, user.Uuid, after)
		if err != nil {
			log.Println("err:", err.Error())
			w.WriteHeader(500)
			return
		}
		for _, a := range values {
			annotations = append(annotations, object.Annotation{
				Message: a.Message,
				Time:    a.Time,
			})
		}
	}

	// serialize and send response
	// ----------------------

	buff, err := json.Marshal(todayHandlerResp{
		Audiences:       audiences,
		Average:         app.Average(dataAudiences),
		Articles:        articles,
		DemoModeMessage: demoModeMessage,
		Annotations:     annotations,
		LowestAudience:  object.AudienceFromApp(lowest),
		HighestAudience: object.AudienceFromApp(highest),
	})

	if err != nil {
		log.Println("err:", err.Error())
		w.WriteHeader(500)
		return
	}
	w.Write(buff)

}

func (c TodayHandler) getData(subreddit string, hours int) ([]db.Audience, map[string][]db.Ranking, []db.Article, error) {
	var start, end time.Time

	end = time.Now()
	start = time.Now().Add(-time.Hour * time.Duration(hours))

	audiences, err := c.App.DB().FindAudiencesInterval(subreddit, start, end)
	if err != nil {
		return nil, nil, nil, err
	}

	rankings, err := c.App.DB().FindArticlesRanking(subreddit, start, end)
	if err != nil {
		return nil, nil, nil, err
	}

	articles, err := c.App.DB().FindArticles(subreddit, start, end)
	if err != nil {
		return nil, nil, nil, err
	}

	return audiences, rankings, articles, nil
}
<commit_msg>api/today_handler: use render method.<commit_after>// Reddit audiences crawler
// Rémy Mathieu © 2016
package api

import (
	"log"
	"net/http"
	"time"

	"github.com/remeh/reddit-audiences/api/object"
	"github.com/remeh/reddit-audiences/app"
	"github.com/remeh/reddit-audiences/db"

	"github.com/gorilla/mux"
)

type TodayHandler struct {
	App *app.App
}

type todayHandlerResp struct {
	Audiences       []object.Audience   `json:"audiences"`
	Average         int64               `json:"average"`
	LowestAudience  object.Audience     `json:"lowest_audience"`
	HighestAudience object.Audience     `json:"highest_audience"`
	Articles        []object.Article    `json:"articles"`
	Annotations     []object.Annotation `json:"annotations"`
	DemoModeMessage bool                `json:"demo_mode_message"`
}

func (c TodayHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)

	subreddit := vars["subreddit"]
	if len(subreddit) == 0 {
		w.WriteHeader(400)
		return
	}

	r.ParseForm()
	t := r.Form.Get("t")
	hours := 36

	// ensure the right to retrieve more than 36h
	// ----------------------
	tmplParams := app.TmplParams(c.App, r, "ApiToday")

	demoModeMessage := false
	if len(t) > 0 && t != "36h" && len(tmplParams.User.Email) == 0 {
		// not auth user, demo message and stay on 36h
		demoModeMessage = true
	} else {
		// auth user, test if he wants 7 days of data
		if t == "7d" {
			hours = 24 * 7
		}
	}

	// retrieve data
	// ----------------------

	dataAudiences, dataRankings, dataArticles, err := c.getData(subreddit, hours)
	if err != nil {
		log.Println("err:", err.Error())
		w.WriteHeader(500)
		return
	}

	audiences := object.AudiencesFromApp(dataAudiences)
	lowest, highest := app.LowestHighest(dataAudiences)
	articles := object.ArticlesFromApp(dataArticles, dataRankings)

	// If the user is logged in, we need to
	// retrieve its annotations.
	// ----------------------
	user := app.GetUser(c.App.DB(), r)

	annotations := make([]object.Annotation, 0)
	if len(user.Email) > 0 {
		after := time.Now().Add(-time.Hour * time.Duration(hours))
		values, err := c.App.DB().FindAnnotations(subreddit, user.Uuid, after)
		if err != nil {
			log.Println("err:", err.Error())
			w.WriteHeader(500)
			return
		}
		for _, a := range values {
			annotations = append(annotations, object.Annotation{
				Message: a.Message,
				Time:    a.Time,
			})
		}
	}

	// serialize and send response
	// ----------------------

	render(w, 200, todayHandlerResp{
		Audiences:       audiences,
		Average:         app.Average(dataAudiences),
		Articles:        articles,
		DemoModeMessage: demoModeMessage,
		Annotations:     annotations,
		LowestAudience:  object.AudienceFromApp(lowest),
		HighestAudience: object.AudienceFromApp(highest),
	})
}

func (c TodayHandler) getData(subreddit string, hours int) ([]db.Audience, map[string][]db.Ranking, []db.Article, error) {
	var start, end time.Time

	end = time.Now()
	start = time.Now().Add(-time.Hour * time.Duration(hours))

	audiences, err := c.App.DB().FindAudiencesInterval(subreddit, start, end)
	if err != nil {
		return nil, nil, nil, err
	}

	rankings, err := c.App.DB().FindArticlesRanking(subreddit, start, end)
	if err != nil {
		return nil, nil, nil, err
	}

	articles, err := c.App.DB().FindArticles(subreddit, start, end)
	if err != nil {
		return nil, nil, nil, err
	}

	return audiences, rankings, articles, nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"html/template"
	"log"
	"net/http"

	"github.com/wallaceicy06/sign-server/config"
)

var templates = template.Must(template.ParseFiles("templates/index.html"))

var port = flag.Int("port", 8080, "the port to serve this webserver")

func main() {
	flag.Parse()
	http.HandleFunc("/", rootHandler)
	if err := http.ListenAndServe(fmt.Sprintf(":%d", *port), nil); err != nil {
		log.Fatalf("Error starting web server on port %d: %v", port, err)
	}
}

func rootHandler(w http.ResponseWriter, r *http.Request) {
	config, err := config.GetConfig()
	if err != nil {
		http.Error(w, fmt.Sprintf("Internal error: %v", err), http.StatusInternalServerError)
	}
	if err := templates.ExecuteTemplate(w, "index.html", config); err != nil {
		http.Error(w, fmt.Sprintf("Internal error: %v", err), http.StatusInternalServerError)
	}
}
<commit_msg>Updated server for config package changes.<commit_after>package main

import (
	"flag"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"os"

	"github.com/wallaceicy06/muni-sign/admin/config"
)

var templates = template.Must(template.ParseFiles("templates/index.html"))

var configFilePath = flag.String("config_file", "", "the path to the file that stores the configuration for the sign")
var port = flag.Int("port", 8080, "the port to serve this webserver")

type Server struct {
	cfg *config.SignConfig
}

func main() {
	flag.Parse()

	if *configFilePath == "" {
		fmt.Fprintln(os.Stderr, "A config file path is required.")
		os.Exit(1)
	}

	sc := config.NewSignConfig(*configFilePath)
	server := &Server{
		cfg: sc,
	}
	server.serve()
}

func (s *Server) serve() {
	http.HandleFunc("/", s.rootHandler)
	if err := http.ListenAndServe(fmt.Sprintf(":%d", *port), nil); err != nil {
		log.Fatalf("Error starting web server on port %d: %v", port, err)
	}
}

func (s *Server) rootHandler(w http.ResponseWriter, r *http.Request) {
	c, err := s.cfg.Get()
	if err != nil {
		http.Error(w, fmt.Sprintf("Internal error: %v", err), http.StatusInternalServerError)
		return
	}
	if err := templates.ExecuteTemplate(w, "index.html", c); err != nil {
		http.Error(w, fmt.Sprintf("Internal error: %v", err), http.StatusInternalServerError)
		return
	}
}
<|endoftext|>


<commit_before>package mcts

import (
	"log"
	"math"
	"math/rand"
	"sort"
	"strings"
	"time"

	"context"

	"github.com/nelhage/taktician/ai"
	"github.com/nelhage/taktician/bitboard"
	"github.com/nelhage/taktician/ptn"
	"github.com/nelhage/taktician/tak"
)

type MCTSConfig struct {
	Debug int
	Limit time.Duration
	C     float64
	Seed  int64

	InitialVisits int
	MMDepth       int
	MaxRollout    int
	EvalThreshold int64
	Policy        string

	Size int

	DumpTree string
}

type Policy interface {
	Select(ctx context.Context, m *MonteCarloAI, p *tak.Position) *tak.Position
}

type MonteCarloAI struct {
	c bitboard.Constants

	cfg  MCTSConfig
	mm   *ai.MinimaxAI
	eval ai.EvaluationFunc

	policy Policy

	r *rand.Rand
}

type tree struct {
	position    *tak.Position
	move        tak.Move
	simulations int

	proven int
	value  int

	parent   *tree
	children []*tree
}

func (t *tree) ucb(C float64, N int) float64 {
	if t.proven > 0 {
		return -100
	} else if t.proven < 0 {
		return 100
	} else if t.simulations == 0 {
		return 10
	} else {
		return -float64(t.value)/float64(t.simulations) +
			C*math.Sqrt(math.Log(float64(N))/float64(t.simulations))
	}
}

type bySims []*tree

func (b bySims) Len() int           { return len(b) }
func (b bySims) Less(i, j int) bool { return b[j].simulations < b[i].simulations }
func (b bySims) Swap(i, j int) {
	b[i], b[j] = b[j], b[i]
}

func (ai *MonteCarloAI) GetMove(ctx context.Context, p *tak.Position) tak.Move {
	tree := &tree{
		position: p,
	}
	start := time.Now()
	deadline, limited := ctx.Deadline()
	if !limited || deadline.Sub(start) > ai.cfg.Limit {
		deadline = time.Now().Add(ai.cfg.Limit)
	}

	var tick <-chan time.Time
	if ai.cfg.Debug > 2 {
		ticker := time.NewTicker(time.Second)
		defer ticker.Stop()
		tick = ticker.C
	}
	for time.Now().Before(deadline) {
		node := ai.descend(tree)
		ai.populate(ctx, node)
		if tree.proven != 0 {
			break
		}
		var val int
		if node.proven == 0 {
			val = ai.rollout(ctx, node)
		}
		if ai.cfg.Debug > 4 {
			var s []string
			t := node
			for t.parent != nil {
				s = append(s, ptn.FormatMove(t.move))
				t = t.parent
			}
			log.Printf("evaluate: [%s] = %d p=%d",
				strings.Join(s, "<-"), val, node.proven)
		}
		ai.update(node, val)
		if tick != nil {
			select {
			case <-tick:
				ai.printdbg(tree)
			default:
			}
		}
	}
	if tree.proven != 0 {
		return ai.mm.GetMove(ctx, p)
	}
	best := tree.children[0]
	i := 0
	sort.Sort(bySims(tree.children))
	if ai.cfg.Debug > 2 {
		log.Printf("=== mcts done ===")
	}
	for _, c := range tree.children {
		if ai.cfg.Debug > 2 {
			log.Printf("[mcts][%s]: n=%d v=%d:%d(%0.3f) ucb=%f",
				ptn.FormatMove(c.move), c.simulations, c.proven, c.value,
				float64(c.value)/float64(c.simulations),
				c.ucb(ai.cfg.C, tree.simulations),
			)
		}
		if c.simulations > best.simulations {
			best = c
			i = 1
		} else if c.simulations == best.simulations {
			i++
			if ai.r.Intn(i) == 0 {
				best = c
				i = 1
			}
		}
	}
	if ai.cfg.Debug > 1 {
		log.Printf("[mcts] evaluated simulations=%d value=%d", tree.simulations, tree.value)
	}
	if ai.cfg.DumpTree != "" {
		ai.dumpTree(tree)
	}
	return best.move
}

func (mc *MonteCarloAI) printdbg(t *tree) {
	log.Printf("===")
	for _, c := range t.children {
		if c.simulations*20 > t.simulations {
			log.Printf("[mcts][%s]: n=%d v=%d:%d(%0.3f) ucb=%f",
				ptn.FormatMove(c.move), c.simulations, c.proven, c.value,
				float64(c.value)/float64(c.simulations),
				c.ucb(mc.cfg.C, t.simulations),
			)
		}
	}
}

func (mc *MonteCarloAI) populate(ctx context.Context, t *tree) {
	_, v, _ := mc.mm.Analyze(ctx, t.position)
	if v > ai.WinThreshold {
		t.proven = 1
		return
	} else if v < -ai.WinThreshold {
		t.proven = -1
		return
	}

	moves := t.position.AllMoves(nil)
	t.children = make([]*tree, 0, len(moves))
	for _, m := range moves {
		child, e := t.position.Move(m)
		if e != nil {
			continue
		}
		t.children = append(t.children, &tree{
			position: child,
			move:     m,
			parent:   t,
		})
	}
}

func (ai *MonteCarloAI) descend(t *tree) *tree {
	if t.children == nil {
		return t
	}
	var best *tree
	var val float64
	i := 0
	for _, c := range t.children {
		var s float64
		if c.proven > 0 {
			s = 0.01
		} else if c.proven < 0 {
			s = 100
		} else if c.simulations == 0 {
			s = 10
		} else {
			s = -float64(c.value)/float64(c.simulations) +
				ai.cfg.C*math.Sqrt(math.Log(float64(t.simulations))/float64(c.simulations))
		}
		if s > val {
			best = c
			val = s
			i = 1
		} else if s == val {
			i++
			if ai.r.Intn(i) == 0 {
				best = c
			}
		}
	}
	if best == nil {
		return t.children[0]
	}
	return ai.descend(best)
}

func (ai *MonteCarloAI) rollout(ctx context.Context, t *tree) int {
	p := t.position.Clone()

	for i := 0; i < ai.cfg.MaxRollout; i++ {
		if ok, c := p.GameOver(); ok {
			switch c {
			case tak.NoColor:
				return 0
			case t.position.ToMove():
				return 1
			default:
				return -1
			}
		}
		next := ai.policy.Select(ctx, ai, p)
		if next == nil {
			return 0
		}
		p = next
	}
	v := ai.eval(&ai.c, p)
	if v > ai.cfg.EvalThreshold {
		return 1
	} else if v < -ai.cfg.EvalThreshold {
		return -1
	}
	return 0
}

func (mc *MonteCarloAI) update(t *tree, value int) {
	for t != nil {
		t.simulations++
		if t.proven != 0 {
			if t.parent == nil {
				return
			}
			// Minimax backup
			if t.proven < 0 {
				// My best move is a loss; therefore
				// my parent should choose this branch
				// and win
				t.parent.proven = 1
				value = -1
			} else {
				// This move is a win for me; My
				// parent is a loss only if *all* of
				// its children are wins
				all := true
				for _, ch := range t.parent.children {
					if ch.proven <= 0 {
						all = false
						break
					}
				}
				if all {
					t.parent.proven = -1
				}
				value = 1
			}
		} else {
			t.value += value
		}
		value = -value
		t = t.parent
	}
}

func NewMonteCarlo(cfg MCTSConfig) *MonteCarloAI {
	mc := &MonteCarloAI{
		cfg: cfg,
		c:   bitboard.Precompute(uint(cfg.Size)),
	}
	if mc.cfg.C == 0 {
		mc.cfg.C = 0.7
	}
	if mc.cfg.Seed == 0 {
		mc.cfg.Seed = time.Now().Unix()
	}
	if mc.cfg.InitialVisits == 0 {
		mc.cfg.InitialVisits = 3
	}
	if mc.cfg.MMDepth == 0 {
		mc.cfg.MMDepth = 3
	}
	if mc.cfg.MaxRollout == 0 {
		mc.cfg.MaxRollout = 50
	}
	if mc.cfg.EvalThreshold == 0 {
		mc.cfg.EvalThreshold = 2000
	}
	mc.policy = mc.buildPolicy()
	mc.r = rand.New(rand.NewSource(mc.cfg.Seed))
	mc.mm = ai.NewMinimax(ai.MinimaxConfig{
		Size:     cfg.Size,
		Evaluate: ai.EvaluateWinner,
		Depth:    mc.cfg.MMDepth,
		Seed:     mc.cfg.Seed,
	})
	mc.eval = ai.MakeEvaluator(mc.cfg.Size, nil)
	return mc
}
<commit_msg>ever visit negative nodes<commit_after>package mcts

import (
	"log"
	"math"
	"math/rand"
	"sort"
	"strings"
	"time"

	"context"

	"github.com/nelhage/taktician/ai"
	"github.com/nelhage/taktician/bitboard"
	"github.com/nelhage/taktician/ptn"
	"github.com/nelhage/taktician/tak"
)

type MCTSConfig struct {
	Debug int
	Limit time.Duration
	C     float64
	Seed  int64

	InitialVisits int
	MMDepth       int
	MaxRollout    int
	EvalThreshold int64
	Policy        string

	Size int

	DumpTree string
}

type Policy interface {
	Select(ctx context.Context, m *MonteCarloAI, p *tak.Position) *tak.Position
}

type MonteCarloAI struct {
	c bitboard.Constants

	cfg  MCTSConfig
	mm   *ai.MinimaxAI
	eval ai.EvaluationFunc

	policy Policy

	r *rand.Rand
}

type tree struct {
	position    *tak.Position
	move        tak.Move
	simulations int

	proven int
	value  int

	parent   *tree
	children []*tree
}

func (t *tree) ucb(C float64, N int) float64 {
	if t.proven > 0 {
		return -100
	} else if t.proven < 0 {
		return 100
	} else if t.simulations == 0 {
		return 10
	} else {
		return -float64(t.value)/float64(t.simulations) +
			C*math.Sqrt(math.Log(float64(N))/float64(t.simulations))
	}
}

type bySims []*tree

func (b bySims) Len() int           { return len(b) }
func (b bySims) Less(i, j int) bool { return b[j].simulations < b[i].simulations }
func (b bySims) Swap(i, j int) {
	b[i], b[j] = b[j], b[i]
}

func (ai *MonteCarloAI) GetMove(ctx context.Context, p *tak.Position) tak.Move {
	tree := &tree{
		position: p,
	}
	start := time.Now()
	deadline, limited := ctx.Deadline()
	if !limited || deadline.Sub(start) > ai.cfg.Limit {
		deadline = time.Now().Add(ai.cfg.Limit)
	}

	var tick <-chan time.Time
	if ai.cfg.Debug > 2 {
		ticker := time.NewTicker(time.Second)
		defer ticker.Stop()
		tick = ticker.C
	}
	for time.Now().Before(deadline) {
		node := ai.descend(tree)
		ai.populate(ctx, node)
		if tree.proven != 0 {
			break
		}
		var val int
		if node.proven == 0 {
			val = ai.rollout(ctx, node)
		}
		if ai.cfg.Debug > 4 {
			var s []string
			t := node
			for t.parent != nil {
				s = append(s, ptn.FormatMove(t.move))
				t = t.parent
			}
			log.Printf("evaluate: [%s] = %d p=%d",
				strings.Join(s, "<-"), val, node.proven)
		}
		ai.update(node, val)
		if tick != nil {
			select {
			case <-tick:
				ai.printdbg(tree)
			default:
			}
		}
	}
	if tree.proven != 0 {
		return ai.mm.GetMove(ctx, p)
	}
	best := tree.children[0]
	i := 0
	sort.Sort(bySims(tree.children))
	if ai.cfg.Debug > 2 {
		log.Printf("=== mcts done ===")
	}
	for _, c := range tree.children {
		if ai.cfg.Debug > 2 {
			log.Printf("[mcts][%s]: n=%d v=%d:%d(%0.3f) ucb=%f",
				ptn.FormatMove(c.move), c.simulations, c.proven, c.value,
				float64(c.value)/float64(c.simulations),
				c.ucb(ai.cfg.C, tree.simulations),
			)
		}
		if c.simulations > best.simulations {
			best = c
			i = 1
		} else if c.simulations == best.simulations {
			i++
			if ai.r.Intn(i) == 0 {
				best = c
				i = 1
			}
		}
	}
	if ai.cfg.Debug > 1 {
		log.Printf("[mcts] evaluated simulations=%d value=%d", tree.simulations, tree.value)
	}
	if ai.cfg.DumpTree != "" {
		ai.dumpTree(tree)
	}
	return best.move
}

func (mc *MonteCarloAI) printdbg(t *tree) {
	log.Printf("===")
	for _, c := range t.children {
		if c.simulations*20 > t.simulations {
			log.Printf("[mcts][%s]: n=%d v=%d:%d(%0.3f) ucb=%f",
				ptn.FormatMove(c.move), c.simulations, c.proven, c.value,
				float64(c.value)/float64(c.simulations),
				c.ucb(mc.cfg.C, t.simulations),
			)
		}
	}
}

func (mc *MonteCarloAI) populate(ctx context.Context, t *tree) {
	_, v, _ := mc.mm.Analyze(ctx, t.position)
	if v > ai.WinThreshold {
		t.proven = 1
		return
	} else if v < -ai.WinThreshold {
		t.proven = -1
		return
	}

	moves := t.position.AllMoves(nil)
	t.children = make([]*tree, 0, len(moves))
	for _, m := range moves {
		child, e := t.position.Move(m)
		if e != nil {
			continue
		}
		t.children = append(t.children, &tree{
			position: child,
			move:     m,
			parent:   t,
		})
	}
}

func (ai *MonteCarloAI) descend(t *tree) *tree {
	if t.children == nil {
		return t
	}
	var best *tree
	var val float64 = math.Inf(-1)
	i := 0
	for _, c := range t.children {
		s := c.ucb(ai.cfg.C, t.simulations)

		if s > val {
			best = c
			val = s
			i = 1
		} else if s == val {
			i++
			if ai.r.Intn(i) == 0 {
				best = c
			}
		}
	}
	if best == nil {
		return t.children[0]
	}
	return ai.descend(best)
}

func (ai *MonteCarloAI) rollout(ctx context.Context, t *tree) int {
	p := t.position.Clone()

	for i := 0; i < ai.cfg.MaxRollout; i++ {
		if ok, c := p.GameOver(); ok {
			switch c {
			case tak.NoColor:
				return 0
			case t.position.ToMove():
				return 1
			default:
				return -1
			}
		}
		next := ai.policy.Select(ctx, ai, p)
		if next == nil {
			return 0
		}
		p = next
	}
	v := ai.eval(&ai.c, p)
	if v > ai.cfg.EvalThreshold {
		return 1
	} else if v < -ai.cfg.EvalThreshold {
		return -1
	}
	return 0
}

func (mc *MonteCarloAI) update(t *tree, value int) {
	for t != nil {
		t.simulations++
		if t.proven != 0 {
			if t.parent == nil {
				return
			}
			// Minimax backup
			if t.proven < 0 {
				// My best move is a loss; therefore
				// my parent should choose this branch
				// and win
				t.parent.proven = 1
				value = -1
			} else {
				// This move is a win for me; My
				// parent is a loss only if *all* of
				// its children are wins
				all := true
				for _, ch := range t.parent.children {
					if ch.proven <= 0 {
						all = false
						break
					}
				}
				if all {
					t.parent.proven = -1
				}
				value = 1
			}
		} else {
			t.value += value
		}
		value = -value
		t = t.parent
	}
}

func NewMonteCarlo(cfg MCTSConfig) *MonteCarloAI {
	mc := &MonteCarloAI{
		cfg: cfg,
		c:   bitboard.Precompute(uint(cfg.Size)),
	}
	if mc.cfg.C == 0 {
		mc.cfg.C = 0.7
	}
	if mc.cfg.Seed == 0 {
		mc.cfg.Seed = time.Now().Unix()
	}
	if mc.cfg.InitialVisits == 0 {
		mc.cfg.InitialVisits = 3
	}
	if mc.cfg.MMDepth == 0 {
		mc.cfg.MMDepth = 3
	}
	if mc.cfg.MaxRollout == 0 {
		mc.cfg.MaxRollout = 50
	}
	if mc.cfg.EvalThreshold == 0 {
		mc.cfg.EvalThreshold = 2000
	}
	mc.policy = mc.buildPolicy()
	mc.r = rand.New(rand.NewSource(mc.cfg.Seed))
	mc.mm = ai.NewMinimax(ai.MinimaxConfig{
		Size:     cfg.Size,
		Evaluate: ai.EvaluateWinner,
		Depth:    mc.cfg.MMDepth,
		Seed:     mc.cfg.Seed,
	})
	mc.eval = ai.MakeEvaluator(mc.cfg.Size, nil)
	return mc
}
<|endoftext|>


<commit_before>package gluatest

import (
	"fmt"
	"sort"
	"strings"
	"testing"

	"github.com/bmatsuo/lark/gluamodule"
	"github.com/yuin/gopher-lua"
)

// FuncSetup is the name of a global variable containing a "setup" function.
// The setup function will be executed before each test function.  If any setup
// function fails the test function that would follow it will not execute.
var FuncSetup = "__test_setup"

// FuncTeardown is the name of a global variable containing a "teardown"
// function.  A teardown function will execute after each test function or
// after a setup function has failed.
var FuncTeardown = "__test_teardown"

// File is a test file for a lua module.
type File struct {
	Module gluamodule.Module
	Path   string
}

// preload runs the loader to register the module name.
func (m *File) preload(t testing.TB) (*lua.LState, *lua.LFunction) {
	l := lua.NewState()
	gluamodule.Preload(l, gluamodule.Resolve(m.Module)...)
	lfunc, err := l.LoadFile(m.Path)
	if err != nil {
		t.Fatal(err)
	}
	return l, lfunc
}

// Load runs the loader to register module and then executes the test file.
func (m *File) Load(t testing.TB) *lua.LState {
	l, lfunc := m.preload(t)
	l.Push(lfunc)
	err := l.PCall(0, 0, l.NewFunction(errTraceback))
	if err != nil {
		l.Close()
		t.Fatal(err)
	}
	return l
}

// Test runs the specified test function
func (m *File) Test(t testing.TB) {
	testFuncs := m.getTestFuncs(t)
	for _, fname := range testFuncs {
		m.runTest(t, fname, getGlobalFunction(fname))
	}
}

func (m *File) getTestFuncs(t testing.TB) []string {
	l := m.Load(t)
	defer l.Close()

	return getTestFuncs(l)
}

type lfuncGetter func(*lua.LState) (*lua.LFunction, error)

func (m *File) runTest(t testing.TB, name string, getfunc lfuncGetter) {
	var fatal bool
	defer func() {
		if fatal {
			t.Fatal("FATAL")
		}
	}()

	l := m.Load(t)
	defer l.Close()

	failmsg := func(name string, err error) string {
		return fmt.Sprintf("FAIL   %s\n%s", name, err)
	}

	errFn := l.NewFunction(errTraceback)

	lfunc, err := getfunc(l)
	if err != nil {
		t.Errorf("FAIL\n%s", err)
		return
	}
	setup := l.GetGlobal(FuncSetup)
	teardown := l.GetGlobal(FuncTeardown)

	if setup != lua.LNil {
		l.Push(setup)
		err := l.PCall(0, 0, errFn)
		if err != nil {
			fatal = true
			t.Error(failmsg("SETUP", err))
		}
	}

	if !fatal {
		t.Logf("ENTER  %s", name)
		l.Push(lfunc)
		err = l.PCall(0, 0, errFn)
		if err != nil {
			t.Error(failmsg(name, err))
		} else {
			t.Logf("PASS   %s", name)
		}
	}

	if teardown != lua.LNil {
		l.Push(teardown)
		err := l.PCall(0, 0, errFn)
		if err != nil {
			fatal = true
			t.Error(failmsg("TEARDOWN", err))
		}
	}
}

func getTestFuncs(L *lua.LState) []string {
	funcs := getGlobals(L, selTestFuncs)
	sort.Strings(funcs)
	return funcs
}

func selTestFuncs(L *lua.LState, k, v lua.LValue) bool {
	s := string(k.(lua.LString))
	if !strings.HasPrefix(s, "test_") {
		return false
	}
	return true
}

func getGlobalFunction(fname string) lfuncGetter {
	return func(l *lua.LState) (*lua.LFunction, error) {
		lfunc, ok := l.GetGlobal(fname).(*lua.LFunction)
		if !ok {
			return nil, fmt.Errorf("not a function: %s", lfunc)
		}
		return lfunc, nil
	}
}

func getGlobals(L *lua.LState, sel func(L *lua.LState, k, v lua.LValue) bool) []string {
	var sels []string
	globals := L.Get(lua.GlobalsIndex).(*lua.LTable)
	L.ForEach(globals, func(k, v lua.LValue) {
		s, ok := k.(lua.LString)
		if !ok {
			return
		}
		if sel(L, k, v) {
			sels = append(sels, string(s))
		}
	})
	return sels
}

func errTraceback(L *lua.LState) int {
	msg := L.Get(1)
	L.SetTop(0)
	L.Push(L.GetField(L.GetGlobal("debug"), "traceback"))
	L.Push(msg)
	L.Push(lua.LNumber(3))
	L.Call(2, 1)
	return 1
}
<commit_msg>gluatest: add simple benchmark function to get a "startup" time metric<commit_after>package gluatest

import (
	"fmt"
	"sort"
	"strings"
	"testing"

	"github.com/bmatsuo/lark/gluamodule"
	"github.com/yuin/gopher-lua"
)

// FuncSetup is the name of a global variable containing a "setup" function.
// The setup function will be executed before each test function.  If any setup
// function fails the test function that would follow it will not execute.
var FuncSetup = "__test_setup"

// FuncTeardown is the name of a global variable containing a "teardown"
// function.  A teardown function will execute after each test function or
// after a setup function has failed.
var FuncTeardown = "__test_teardown"

// File is a test file for a lua module.
type File struct {
	Module gluamodule.Module
	Path   string
}

// preload runs the loader to register the module name.
func (m *File) preload(t testing.TB) (*lua.LState, *lua.LFunction) {
	l := lua.NewState()
	gluamodule.Preload(l, gluamodule.Resolve(m.Module)...)
	lfunc, err := l.LoadFile(m.Path)
	if err != nil {
		t.Fatal(err)
	}
	return l, lfunc
}

// Load runs the loader to register module and then executes the test file.
func (m *File) Load(t testing.TB) *lua.LState {
	l, lfunc := m.preload(t)
	l.Push(lfunc)
	err := l.PCall(0, 0, l.NewFunction(errTraceback))
	if err != nil {
		l.Close()
		t.Fatal(err)
	}
	return l
}

// BenchmarkRequireModule benchmarks the execution of the preload function (not
// the act of registering it).
func (m *File) BenchmarkRequireModule(b *testing.B) {
	b.StopTimer()
	for i := 0; i <= b.N; i++ {
		l, fn := m.preload(b)
		l.Push(fn)
		b.StartTimer()
		err := l.PCall(0, 0, nil)
		b.StopTimer()
		if err != nil {
			b.Fatal(err)
		}
	}
}

// Test runs the specified test function
func (m *File) Test(t testing.TB) {
	testFuncs := m.getTestFuncs(t)
	for _, fname := range testFuncs {
		m.runTest(t, fname, getGlobalFunction(fname))
	}
}

func (m *File) getTestFuncs(t testing.TB) []string {
	l := m.Load(t)
	defer l.Close()

	return getTestFuncs(l)
}

type lfuncGetter func(*lua.LState) (*lua.LFunction, error)

func (m *File) runTest(t testing.TB, name string, getfunc lfuncGetter) {
	var fatal bool
	defer func() {
		if fatal {
			t.Fatal("FATAL")
		}
	}()

	l := m.Load(t)
	defer l.Close()

	failmsg := func(name string, err error) string {
		return fmt.Sprintf("FAIL   %s\n%s", name, err)
	}

	errFn := l.NewFunction(errTraceback)

	lfunc, err := getfunc(l)
	if err != nil {
		t.Errorf("FAIL\n%s", err)
		return
	}
	setup := l.GetGlobal(FuncSetup)
	teardown := l.GetGlobal(FuncTeardown)

	if setup != lua.LNil {
		l.Push(setup)
		err := l.PCall(0, 0, errFn)
		if err != nil {
			fatal = true
			t.Error(failmsg("SETUP", err))
		}
	}

	if !fatal {
		t.Logf("ENTER  %s", name)
		l.Push(lfunc)
		err = l.PCall(0, 0, errFn)
		if err != nil {
			t.Error(failmsg(name, err))
		} else {
			t.Logf("PASS   %s", name)
		}
	}

	if teardown != lua.LNil {
		l.Push(teardown)
		err := l.PCall(0, 0, errFn)
		if err != nil {
			fatal = true
			t.Error(failmsg("TEARDOWN", err))
		}
	}
}

func getTestFuncs(L *lua.LState) []string {
	funcs := getGlobals(L, selTestFuncs)
	sort.Strings(funcs)
	return funcs
}

func selTestFuncs(L *lua.LState, k, v lua.LValue) bool {
	s := string(k.(lua.LString))
	if !strings.HasPrefix(s, "test_") {
		return false
	}
	return true
}

func getGlobalFunction(fname string) lfuncGetter {
	return func(l *lua.LState) (*lua.LFunction, error) {
		lfunc, ok := l.GetGlobal(fname).(*lua.LFunction)
		if !ok {
			return nil, fmt.Errorf("not a function: %s", lfunc)
		}
		return lfunc, nil
	}
}

func getGlobals(L *lua.LState, sel func(L *lua.LState, k, v lua.LValue) bool) []string {
	var sels []string
	globals := L.Get(lua.GlobalsIndex).(*lua.LTable)
	L.ForEach(globals, func(k, v lua.LValue) {
		s, ok := k.(lua.LString)
		if !ok {
			return
		}
		if sel(L, k, v) {
			sels = append(sels, string(s))
		}
	})
	return sels
}

func errTraceback(L *lua.LState) int {
	msg := L.Get(1)
	L.SetTop(0)
	L.Push(L.GetField(L.GetGlobal("debug"), "traceback"))
	L.Push(msg)
	L.Push(lua.LNumber(3))
	L.Call(2, 1)
	return 1
}
<|endoftext|>


<commit_before>//go:build js

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

package message

import (
	"syscall/js"

	"github.com/google/chrome-ssh-agent/go/chrome"
	"github.com/google/chrome-ssh-agent/go/jsutil"
)

var (
	chromeObj = js.Global().Get("chrome")
	runtime =  func() js.Value  {
		if chromeObj.IsUndefined() {
			return js.Undefined()
		}
		return chromeObj.Get("runtime")
	}()
)

// Sender specifies the interface for a type that sends messages.
type Sender interface {
	// Send sends a message. Callback is invoked with either the response
	// or an error.  See:
	//   https://developer.chrome.com/docs/extensions/reference/runtime/#method-sendMessage
	Send(msg js.Value, callback func(rsp js.Value, err error))
}

// ExtSender sends messages to a single extension.
//
// ExtSender implements the Sender interface.
type ExtSender struct {
	// extensionID is the unique ID for the target extension.
	extensionID string
}

// NewLocalSender returns a ExtSender for sending messages within our own
// extension.
func NewLocalSender() *ExtSender {
	return &ExtSender{
		extensionID: chrome.ExtensionID(),
	}
}

// Send implements Sender.Send().
func (e *ExtSender) Send(msg js.Value, callback func(rsp js.Value, err error)) {
	jsutil.AsPromise(runtime.Call("sendMessage", e.extensionID, msg)).Then(
		func(val js.Value) { callback(val, nil) },
		func(err error) { callback(js.Undefined(), err) },
	)
}
<commit_msg>Run gofmt<commit_after>//go:build js

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

package message

import (
	"syscall/js"

	"github.com/google/chrome-ssh-agent/go/chrome"
	"github.com/google/chrome-ssh-agent/go/jsutil"
)

var (
	chromeObj = js.Global().Get("chrome")
	runtime   = func() js.Value {
		if chromeObj.IsUndefined() {
			return js.Undefined()
		}
		return chromeObj.Get("runtime")
	}()
)

// Sender specifies the interface for a type that sends messages.
type Sender interface {
	// Send sends a message. Callback is invoked with either the response
	// or an error.  See:
	//   https://developer.chrome.com/docs/extensions/reference/runtime/#method-sendMessage
	Send(msg js.Value, callback func(rsp js.Value, err error))
}

// ExtSender sends messages to a single extension.
//
// ExtSender implements the Sender interface.
type ExtSender struct {
	// extensionID is the unique ID for the target extension.
	extensionID string
}

// NewLocalSender returns a ExtSender for sending messages within our own
// extension.
func NewLocalSender() *ExtSender {
	return &ExtSender{
		extensionID: chrome.ExtensionID(),
	}
}

// Send implements Sender.Send().
func (e *ExtSender) Send(msg js.Value, callback func(rsp js.Value, err error)) {
	jsutil.AsPromise(runtime.Call("sendMessage", e.extensionID, msg)).Then(
		func(val js.Value) { callback(val, nil) },
		func(err error) { callback(js.Undefined(), err) },
	)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"os/user"
	"path"
	"time"

	"github.com/dotcloud/docker/pkg/mount"
)

// Must be true everywhere.
const databoxGid = 10000

var pamUser = os.Getenv("PAM_USER")

func Fatal(first string, args ...interface{}) {
	// TODO(pwaller): send to syslog?
	log.Fatalf("pam script: "+first, args...)
}

func isDataboxUser() bool {
	u, err := user.Lookup(pamUser)
	if err != nil {
		Fatal("Failed to obtain passwd entry for", pamUser)
	}
	return u.Gid == fmt.Sprint(databoxGid)
}

func initMounts() {
	home := path.Join("/var/lib/cobalt/home/", pamUser)

	mounts := []struct{ src, tgt string }{
		{"/opt/basejail", "/jail"},
		{"/dev", "/jail/dev"},
		{"/dev/pts", "/jail/dev/pts"},
		{"/proc", "/jail/proc"},
		{"/var/spool/cron/crontabs", "/jail/var/spool/cron/crontabs"},
		{"/var/lib/extrausers", "/jail/var/lib/extrausers"},
		{home, "/jail/home"},
	}

	for _, m := range mounts {
		// Note the use of recursive bind mounts.
		// We could avoid some mounts by just arranging that /opt/basejail
		// already has most of the mounts.
		err := mount.Mount(m.src, m.tgt, "", "rbind")
		if err != nil {
			log.Fatalf("pamscript: Failed to mount %s -> %s: %q", m.src, m.tgt, err)
		}
	}
}

func cgcreate() error {
	args := []string{"-t", pamUser, "-g", "memory,cpu,cpuacct:" + pamUser}
	cmd := exec.Command("cgcreate", args...)
	return cmd.Run()
}

func initCgroup() {
	_, err := exec.LookPath("cgcreate")
	if err != nil {
		// cgroups isn't installed on this machine, NOOP.
		return
	}

	if _, err := os.Stat(path.Join("/sys/fs/cgroup/cpu", pamUser)); err != nil {
		err = cgcreate()
		if err != nil {
			Fatal("Failed to create cgroup")
		}
	}

	// 512MiB
	const memoryLimit = 512 * 1024 * 1024

	f := path.Join("/sys/fs/cgroup/memory", pamUser, "/memory.limit_in_bytes")
	err = ioutil.WriteFile(f, []byte(fmt.Sprint(memoryLimit)), 0)
	if err != nil {
		Fatal("Failed to write", f, ":", err)
	}

	// echo $MemoryLimit > /sys/fs/cgroup/memory/$PAM_USER/memory.limit_in_bytes

	// TODO(pwaller): do we want this? Maybe? Is there some other way we can give
	// system things priority?

	// # CPU share is form of priority. By specifying a low number here, we
	// # ensure that important system services get a higher share of the CPU
	// # and thus remain responsive.
	// Priority=12
	// echo $Priority > /sys/fs/cgroup/cpu/$PAM_USER/cpu.shares

	// Put the owning process (usually the "su -l" or cron child process)
	// into the cgroup (and therefore all of its future children)

	files := []string{
		path.Join("/sys/fs/cgroup/cpu", pamUser, "/tasks"),
		path.Join("/sys/fs/cgroup/memory", pamUser, "/tasks"),
		path.Join("/sys/fs/cgroup/cpuacct", pamUser, "/tasks"),
	}

	parentPid := []byte(fmt.Sprint(os.Getppid()))
	for _, f := range files {
		err = ioutil.WriteFile(f, parentPid, 0)
		if err != nil {
			Fatal("Failed to write", f, ":", err)
		}
	}
}

func verifyMountNamespace() {
	// if [[ "$(readlink /proc/1/ns/mnt)" == "$(readlink /proc/self/ns/mnt)" ]]; then
	initMountNS, err := os.Readlink("/proc/1/ns/mnt")
	if err != nil {
		Fatal("Unable to readlink(/proc/1/ns/mnt). Aborting.")
	}
	myMountNS, err := os.Readlink("/proc/self/ns/mnt")
	if err != nil {
		Fatal("Unable to readlink(/proc/self/ns/mnt). Aborting.")
	}
	if initMountNS == myMountNS {
		Fatal("Not in mount namespace. Abort.")
	}
}

func main() {
	start := time.Now()
	defer func() {
		log.Println("pam_script_ses_open took", time.Since(start))
	}()

	if !isDataboxUser() {
		// log.Println("Skip non-databox user")
		// skip non-databox login
		return
	}

	if pamUser == "" {
		Fatal("PAM_USER not set. Abort.")
	}

	verifyMountNamespace()

	initCgroup()
	initMounts()
}
<commit_msg>Make pam_script_ses_open log to syslog<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"log/syslog"
	"os"
	"os/exec"
	"os/user"
	"path"
	"time"

	"github.com/dotcloud/docker/pkg/mount"
)

// Must be true everywhere.
const databoxGid = 10000

var pamUser = os.Getenv("PAM_USER")
var log, _ = syslog.NewLogger(syslog.LOG_WARNING | syslog.LOG_AUTH, 0)

func Fatal(first string, args ...interface{}) {
	// TODO(pwaller): send to syslog?
	log.Fatalf("pam script: "+first, args...)
}

func isDataboxUser() bool {
	u, err := user.Lookup(pamUser)
	if err != nil {
		Fatal("Failed to obtain passwd entry for %q", pamUser)
	}
	return u.Gid == fmt.Sprint(databoxGid)
}

func initMounts() {
	home := path.Join("/var/lib/cobalt/home/", pamUser)

	mounts := []struct{ src, tgt string }{
		{"/opt/basejail", "/jail"},
		{"/dev", "/jail/dev"},
		{"/dev/pts", "/jail/dev/pts"},
		{"/proc", "/jail/proc"},
		{"/var/spool/cron/crontabs", "/jail/var/spool/cron/crontabs"},
		{"/var/lib/extrausers", "/jail/var/lib/extrausers"},
		{home, "/jail/home"},
	}

	for _, m := range mounts {
		// Note the use of recursive bind mounts.
		// We could avoid some mounts by just arranging that /opt/basejail
		// already has most of the mounts.
		err := mount.Mount(m.src, m.tgt, "", "rbind")
		if err != nil {
			log.Fatalf("pamscript: Failed to mount %s -> %s: %q", m.src, m.tgt, err)
		}
	}
}

func cgcreate() error {
	args := []string{"-t", pamUser, "-g", "memory,cpu,cpuacct:" + pamUser}
	cmd := exec.Command("cgcreate", args...)
	return cmd.Run()
}

func initCgroup() {
	_, err := exec.LookPath("cgcreate")
	if err != nil {
		// cgroups isn't installed on this machine, NOOP.
		return
	}

	if _, err := os.Stat(path.Join("/sys/fs/cgroup/cpu", pamUser)); err != nil {
		err = cgcreate()
		if err != nil {
			Fatal("Failed to create cgroup")
		}
	}

	// 512MiB
	const memoryLimit = 512 * 1024 * 1024

	f := path.Join("/sys/fs/cgroup/memory", pamUser, "/memory.limit_in_bytes")
	err = ioutil.WriteFile(f, []byte(fmt.Sprint(memoryLimit)), 0)
	if err != nil {
		Fatal("Failed to write", f, ":", err)
	}

	// echo $MemoryLimit > /sys/fs/cgroup/memory/$PAM_USER/memory.limit_in_bytes

	// TODO(pwaller): do we want this? Maybe? Is there some other way we can give
	// system things priority?

	// # CPU share is form of priority. By specifying a low number here, we
	// # ensure that important system services get a higher share of the CPU
	// # and thus remain responsive.
	// Priority=12
	// echo $Priority > /sys/fs/cgroup/cpu/$PAM_USER/cpu.shares

	// Put the owning process (usually the "su -l" or cron child process)
	// into the cgroup (and therefore all of its future children)

	files := []string{
		path.Join("/sys/fs/cgroup/cpu", pamUser, "/tasks"),
		path.Join("/sys/fs/cgroup/memory", pamUser, "/tasks"),
		path.Join("/sys/fs/cgroup/cpuacct", pamUser, "/tasks"),
	}

	parentPid := []byte(fmt.Sprint(os.Getppid()))
	for _, f := range files {
		err = ioutil.WriteFile(f, parentPid, 0)
		if err != nil {
			Fatal("Failed to write", f, ":", err)
		}
	}
}

func verifyMountNamespace() {
	// if [[ "$(readlink /proc/1/ns/mnt)" == "$(readlink /proc/self/ns/mnt)" ]]; then
	initMountNS, err := os.Readlink("/proc/1/ns/mnt")
	if err != nil {
		Fatal("Unable to readlink(/proc/1/ns/mnt). Aborting.")
	}
	myMountNS, err := os.Readlink("/proc/self/ns/mnt")
	if err != nil {
		Fatal("Unable to readlink(/proc/self/ns/mnt). Aborting.")
	}
	if initMountNS == myMountNS {
		Fatal("Not in mount namespace. Abort.")
	}
}

func main() {
	start := time.Now()
	defer func() {
		log.Println("pam_script_ses_open took", time.Since(start))
	}()

	if !isDataboxUser() {
		log.Println("Skip non-databox user")
		// skip non-databox login
		return
	}

	if pamUser == "" {
		Fatal("PAM_USER not set. Abort.")
	}

	verifyMountNamespace()

	initCgroup()
	initMounts()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os/exec"
	"time"

	pb "github.com/brotherlogic/gobuildslave/proto"
	"github.com/brotherlogic/goserver/utils"
	pbt "github.com/brotherlogic/tracer/proto"
	"golang.org/x/net/context"
)

const (
	pendWait = time.Minute
)

func (s *Server) runTransition(ctx context.Context, job *pb.JobAssignment) {
	utils.SendTrace(ctx, fmt.Sprintf("run_transition_%v", job.State), time.Now(), pbt.Milestone_MARKER, job.Job.Name)
	stState := job.State
	switch job.State {
	case pb.State_ACKNOWLEDGED:
		key := s.scheduleBuild(ctx, job.Job)
		s.stateMutex.Lock()
		s.stateMap[job.Job.Name] = fmt.Sprintf("SCHED: %v", key)
		s.stateMutex.Unlock()
		if job.Job.NonBootstrap {
			if key != "" {
				job.Server = s.Registry.Identifier
				job.State = pb.State_BUILT
				job.RunningVersion = key
			}
		} else {
			job.CommandKey = key
			job.State = pb.State_BUILDING
			job.Server = s.Registry.Identifier
		}
	case pb.State_BUILDING:
		s.stateMutex.Lock()
		s.stateMap[job.Job.Name] = fmt.Sprintf("BUILD(%v): %v", job.CommandKey, s.scheduler.getState(job.CommandKey))
		s.stateMutex.Unlock()
		if s.taskComplete(job.CommandKey) {
			job.State = pb.State_BUILT
		}
	case pb.State_BUILT:
		output := s.scheduler.getOutput(job.CommandKey)
		s.stateMutex.Lock()
		s.stateMap[job.Job.Name] = fmt.Sprintf("BUILT(%v): (%v): %v", job.CommandKey, len(output), output)
		s.stateMutex.Unlock()
		if !job.Job.NonBootstrap && len(output) > 0 {
			if job.BuildFail == 5 {
				s.deliverCrashReport(ctx, job, output)
				job.BuildFail = 0
			}
			job.BuildFail++
			job.State = pb.State_DIED
		} else {
			job.BuildFail = 0
			key := s.scheduleRun(job.Job)
			job.CommandKey = key
			job.StartTime = time.Now().Unix()
			job.State = pb.State_PENDING
			if _, ok := s.pendingMap[time.Now().Weekday()]; !ok {
				s.pendingMap[time.Now().Weekday()] = make(map[string]int)
			}
			s.pendingMap[time.Now().Weekday()][job.Job.Name]++
		}
	case pb.State_PENDING:
		s.stateMutex.Lock()
		s.stateMap[job.Job.Name] = fmt.Sprintf("OUTPUT = %v", s.scheduler.getOutput(job.CommandKey))
		s.stateMutex.Unlock()
		if time.Now().Add(-time.Minute).Unix() > job.StartTime {
			job.State = pb.State_RUNNING
		}
	case pb.State_RUNNING:
		output := s.scheduler.getOutput(job.CommandKey)
		if s.taskComplete(job.CommandKey) {
			s.stateMutex.Lock()
			s.stateMap[job.Job.Name] = fmt.Sprintf("COMPLETE = %v", output)
			s.stateMutex.Unlock()
			s.deliverCrashReport(ctx, job, output)
			job.State = pb.State_DIED
		}

		err := s.discover.discover(job.Job.Name, s.Registry.Identifier)
		if err != nil {
			if job.DiscoverCount > 30 {
				s.RaiseIssue(ctx, "Cannot Discover Running Server", fmt.Sprintf("%v on %v is not discoverable, despite running (%v)", job.Job.Name, s.Registry.Identifier, err), false)
			}
			job.DiscoverCount++
		} else {
			job.DiscoverCount = 0
		}

		// Restart this job if we need to
		if job.Job.NonBootstrap {
			version := s.getVersion(ctx, job.Job)
			if version != job.RunningVersion {
				s.stateMutex.Lock()
				s.stateMap[job.Job.Name] = fmt.Sprintf("VERSION_MISMATCH = %v,%v", version, job.RunningVersion)
				s.stateMutex.Unlock()
				s.scheduler.killJob(job.CommandKey)
				job.State = pb.State_ACKNOWLEDGED
			}
		}
	case pb.State_DIED:
		s.stateMutex.Lock()
		s.stateMap[job.Job.Name] = fmt.Sprintf("DIED %v", job.CommandKey)
		s.stateMutex.Unlock()
		s.scheduler.removeJob(job.CommandKey)
		job.State = pb.State_ACKNOWLEDGED
	}

	if job.State != stState {
		s.stateTime[job.Job.Name] = time.Now()
	}

	if job.State == pb.State_DIED {
	}

	utils.SendTrace(ctx, fmt.Sprintf("end_transition_%v_%v", job.State, stState), time.Now(), pbt.Milestone_MARKER, job.Job.Name)
	utils.SendTrace(ctx, fmt.Sprintf("end_transition_func_%v", job.State), time.Now(), pbt.Milestone_MARKER, job.Job.Name)
}

type translator interface {
	build(job *pb.Job) *exec.Cmd
	run(job *pb.Job) *exec.Cmd
}

type checker interface {
	isAlive(ctx context.Context, job *pb.JobAssignment) bool
}

func (s *Server) getVersion(ctx context.Context, job *pb.Job) string {
	versions, _ := s.builder.build(ctx, job)

	if len(versions) == 0 {
		return ""
	}

	return versions[0].Version

}

// scheduleBuild builds out the job, returning the current version
func (s *Server) scheduleBuild(ctx context.Context, job *pb.Job) string {
	utils.SendTrace(ctx, fmt.Sprintf("schedule_build_%v", job.NonBootstrap), time.Now(), pbt.Milestone_MARKER, job.Name)
	if !job.NonBootstrap {
		c := s.translator.build(job)
		return s.scheduler.Schedule(&rCommand{command: c})
	}

	versions, err := s.builder.build(ctx, job)

	if len(versions) == 0 {
		s.stateMutex.Lock()
		s.stateMap[job.Name] = fmt.Sprintf("No Versions: %v", err)
		s.stateMutex.Unlock()
		return ""
	}

	t := time.Now()
	err = s.builder.copy(ctx, versions[0])
	if err != nil {
		s.stateMutex.Lock()
		s.stateMap[job.Name] = fmt.Sprintf("Copy fail (%v) -> %v", time.Now().Sub(t), err)
		s.stateMutex.Unlock()
		return ""
	}
	s.stateMutex.Lock()
	s.stateMap[job.Name] = fmt.Sprintf("Found version %v", versions[0].Version)
	s.stateMutex.Unlock()
	return versions[0].Version
}

func (s *Server) scheduleRun(job *pb.Job) string {
	c := s.translator.run(job)
	return s.scheduler.Schedule(&rCommand{command: c})
}

func (s *Server) taskComplete(key string) bool {
	return s.scheduler.schedulerComplete(key)
}
<commit_msg>Improves discover message. This closes #274<commit_after>package main

import (
	"fmt"
	"os/exec"
	"time"

	pb "github.com/brotherlogic/gobuildslave/proto"
	"github.com/brotherlogic/goserver/utils"
	pbt "github.com/brotherlogic/tracer/proto"
	"golang.org/x/net/context"
)

const (
	pendWait = time.Minute
)

func (s *Server) runTransition(ctx context.Context, job *pb.JobAssignment) {
	utils.SendTrace(ctx, fmt.Sprintf("run_transition_%v", job.State), time.Now(), pbt.Milestone_MARKER, job.Job.Name)
	stState := job.State
	switch job.State {
	case pb.State_ACKNOWLEDGED:
		key := s.scheduleBuild(ctx, job.Job)
		s.stateMutex.Lock()
		s.stateMap[job.Job.Name] = fmt.Sprintf("SCHED: %v", key)
		s.stateMutex.Unlock()
		if job.Job.NonBootstrap {
			if key != "" {
				job.Server = s.Registry.Identifier
				job.State = pb.State_BUILT
				job.RunningVersion = key
			}
		} else {
			job.CommandKey = key
			job.State = pb.State_BUILDING
			job.Server = s.Registry.Identifier
		}
	case pb.State_BUILDING:
		s.stateMutex.Lock()
		s.stateMap[job.Job.Name] = fmt.Sprintf("BUILD(%v): %v", job.CommandKey, s.scheduler.getState(job.CommandKey))
		s.stateMutex.Unlock()
		if s.taskComplete(job.CommandKey) {
			job.State = pb.State_BUILT
		}
	case pb.State_BUILT:
		output := s.scheduler.getOutput(job.CommandKey)
		s.stateMutex.Lock()
		s.stateMap[job.Job.Name] = fmt.Sprintf("BUILT(%v): (%v): %v", job.CommandKey, len(output), output)
		s.stateMutex.Unlock()
		if !job.Job.NonBootstrap && len(output) > 0 {
			if job.BuildFail == 5 {
				s.deliverCrashReport(ctx, job, output)
				job.BuildFail = 0
			}
			job.BuildFail++
			job.State = pb.State_DIED
		} else {
			job.BuildFail = 0
			key := s.scheduleRun(job.Job)
			job.CommandKey = key
			job.StartTime = time.Now().Unix()
			job.State = pb.State_PENDING
			if _, ok := s.pendingMap[time.Now().Weekday()]; !ok {
				s.pendingMap[time.Now().Weekday()] = make(map[string]int)
			}
			s.pendingMap[time.Now().Weekday()][job.Job.Name]++
		}
	case pb.State_PENDING:
		s.stateMutex.Lock()
		s.stateMap[job.Job.Name] = fmt.Sprintf("OUTPUT = %v", s.scheduler.getOutput(job.CommandKey))
		s.stateMutex.Unlock()
		if time.Now().Add(-time.Minute).Unix() > job.StartTime {
			job.State = pb.State_RUNNING
		}
	case pb.State_RUNNING:
		output := s.scheduler.getOutput(job.CommandKey)
		if s.taskComplete(job.CommandKey) {
			s.stateMutex.Lock()
			s.stateMap[job.Job.Name] = fmt.Sprintf("COMPLETE = %v", output)
			s.stateMutex.Unlock()
			s.deliverCrashReport(ctx, job, output)
			job.State = pb.State_DIED
		}

		err := s.discover.discover(job.Job.Name, s.Registry.Identifier)
		if err != nil {
			if job.DiscoverCount > 30 {
				s.RaiseIssue(ctx, "Cannot Discover Running Server", fmt.Sprintf("%v on %v is not discoverable, despite running (%v) the output says %v", job.Job.Name, s.Registry.Identifier, err, output), false)
			}
			job.DiscoverCount++
		} else {
			job.DiscoverCount = 0
		}

		// Restart this job if we need to
		if job.Job.NonBootstrap {
			version := s.getVersion(ctx, job.Job)
			if version != job.RunningVersion {
				s.stateMutex.Lock()
				s.stateMap[job.Job.Name] = fmt.Sprintf("VERSION_MISMATCH = %v,%v", version, job.RunningVersion)
				s.stateMutex.Unlock()
				s.scheduler.killJob(job.CommandKey)
				job.State = pb.State_ACKNOWLEDGED
			}
		}
	case pb.State_DIED:
		s.stateMutex.Lock()
		s.stateMap[job.Job.Name] = fmt.Sprintf("DIED %v", job.CommandKey)
		s.stateMutex.Unlock()
		s.scheduler.removeJob(job.CommandKey)
		job.State = pb.State_ACKNOWLEDGED
	}

	if job.State != stState {
		s.stateTime[job.Job.Name] = time.Now()
	}

	if job.State == pb.State_DIED {
	}

	utils.SendTrace(ctx, fmt.Sprintf("end_transition_%v_%v", job.State, stState), time.Now(), pbt.Milestone_MARKER, job.Job.Name)
	utils.SendTrace(ctx, fmt.Sprintf("end_transition_func_%v", job.State), time.Now(), pbt.Milestone_MARKER, job.Job.Name)
}

type translator interface {
	build(job *pb.Job) *exec.Cmd
	run(job *pb.Job) *exec.Cmd
}

type checker interface {
	isAlive(ctx context.Context, job *pb.JobAssignment) bool
}

func (s *Server) getVersion(ctx context.Context, job *pb.Job) string {
	versions, _ := s.builder.build(ctx, job)

	if len(versions) == 0 {
		return ""
	}

	return versions[0].Version

}

// scheduleBuild builds out the job, returning the current version
func (s *Server) scheduleBuild(ctx context.Context, job *pb.Job) string {
	utils.SendTrace(ctx, fmt.Sprintf("schedule_build_%v", job.NonBootstrap), time.Now(), pbt.Milestone_MARKER, job.Name)
	if !job.NonBootstrap {
		c := s.translator.build(job)
		return s.scheduler.Schedule(&rCommand{command: c})
	}

	versions, err := s.builder.build(ctx, job)

	if len(versions) == 0 {
		s.stateMutex.Lock()
		s.stateMap[job.Name] = fmt.Sprintf("No Versions: %v", err)
		s.stateMutex.Unlock()
		return ""
	}

	t := time.Now()
	err = s.builder.copy(ctx, versions[0])
	if err != nil {
		s.stateMutex.Lock()
		s.stateMap[job.Name] = fmt.Sprintf("Copy fail (%v) -> %v", time.Now().Sub(t), err)
		s.stateMutex.Unlock()
		return ""
	}
	s.stateMutex.Lock()
	s.stateMap[job.Name] = fmt.Sprintf("Found version %v", versions[0].Version)
	s.stateMutex.Unlock()
	return versions[0].Version
}

func (s *Server) scheduleRun(job *pb.Job) string {
	c := s.translator.run(job)
	return s.scheduler.Schedule(&rCommand{command: c})
}

func (s *Server) taskComplete(key string) bool {
	return s.scheduler.schedulerComplete(key)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os/exec"
	"time"

	pb "github.com/brotherlogic/gobuildslave/proto"
	pbt "github.com/brotherlogic/tracer/proto"

	"github.com/brotherlogic/goserver/utils"
	"golang.org/x/net/context"
)

const (
	pendWait = time.Minute
)

func (s *Server) runTransition(ctx context.Context, job *pb.JobAssignment) {
	utils.SendTrace(ctx, fmt.Sprintf("run_transition_%v", job.State), time.Now(), pbt.Milestone_MARKER, job.Job.Name)
	stState := job.State
	switch job.State {
	case pb.State_ACKNOWLEDGED:
		key := s.scheduleBuild(ctx, job.Job)
		if job.Job.NonBootstrap {
			if key != "" {
				job.Server = s.Registry.Identifier
				job.State = pb.State_BUILT
				job.RunningVersion = key
			}
		} else {
			job.CommandKey = key
			job.State = pb.State_BUILDING
			job.Server = s.Registry.Identifier
		}
	case pb.State_BUILDING:
		if s.taskComplete(job.CommandKey) {
			job.State = pb.State_BUILT
		}
	case pb.State_BUILT:
		output := s.scheduler.getOutput(job.CommandKey)
		if len(output) > 0 {
			if job.BuildFail == 5 {
				s.deliverCrashReport(ctx, job, output)
			}
			job.BuildFail++
			job.State = pb.State_DIED
		} else {
			job.BuildFail = 0
			key := s.scheduleRun(job.Job)
			job.CommandKey = key
			job.StartTime = time.Now().Unix()
			job.State = pb.State_PENDING
		}
	case pb.State_PENDING:
		if time.Now().Add(-time.Minute).Unix() > job.StartTime {
			job.State = pb.State_RUNNING
		}
	case pb.State_RUNNING:
		if s.taskComplete(job.CommandKey) {
			output := s.scheduler.getOutput(job.CommandKey)
			s.deliverCrashReport(ctx, job, output)
			job.State = pb.State_DIED
		}

		// Restart this job if we need to
		if job.Job.NonBootstrap {
			version := s.getVersion(ctx, job.Job)
			if version != job.RunningVersion {
				s.Log(fmt.Sprintf("KILLING %v", job.Job.Name))
				s.scheduler.killJob(job.CommandKey)
				job.State = pb.State_ACKNOWLEDGED
			}
		}
	case pb.State_DIED:
		job.State = pb.State_ACKNOWLEDGED
	}
	if job.State != stState {
		s.Log(fmt.Sprintf("Job %v went from %v to %v", job.Job.Name, stState, job.State))
	}
}

type translator interface {
	build(job *pb.Job) *exec.Cmd
	run(job *pb.Job) *exec.Cmd
}

type checker interface {
	isAlive(ctx context.Context, job *pb.JobAssignment) bool
}

func (s *Server) getVersion(ctx context.Context, job *pb.Job) string {
	versions := s.builder.build(ctx, job)

	if len(versions) == 0 {
		s.Log(fmt.Sprintf("No versions received for %v", job.Name))
		return ""
	}

	return versions[0].Version

}

// scheduleBuild builds out the job, returning the current version
func (s *Server) scheduleBuild(ctx context.Context, job *pb.Job) string {
	if !job.NonBootstrap {
		c := s.translator.build(job)
		return s.scheduler.Schedule(&rCommand{command: c})
	}

	versions := s.builder.build(ctx, job)

	if len(versions) == 0 {
		s.Log(fmt.Sprintf("No versions received for %v", job.Name))
		return ""
	}

	s.Log(fmt.Sprintf("COPYING WITH %v", s.builder))
	err := s.builder.copy(ctx, versions[0])
	if err != nil {
		return ""
	}
	return versions[0].Version
}

func (s *Server) scheduleRun(job *pb.Job) string {
	c := s.translator.run(job)
	return s.scheduler.Schedule(&rCommand{command: c})
}

func (s *Server) taskComplete(key string) bool {
	return s.scheduler.schedulerComplete(key)
}
<commit_msg>More logging<commit_after>package main

import (
	"fmt"
	"os/exec"
	"time"

	pb "github.com/brotherlogic/gobuildslave/proto"
	pbt "github.com/brotherlogic/tracer/proto"

	"github.com/brotherlogic/goserver/utils"
	"golang.org/x/net/context"
)

const (
	pendWait = time.Minute
)

func (s *Server) runTransition(ctx context.Context, job *pb.JobAssignment) {
	utils.SendTrace(ctx, fmt.Sprintf("run_transition_%v", job.State), time.Now(), pbt.Milestone_MARKER, job.Job.Name)
	stState := job.State
	switch job.State {
	case pb.State_ACKNOWLEDGED:
		key := s.scheduleBuild(ctx, job.Job)
		if job.Job.NonBootstrap {
			if key != "" {
				job.Server = s.Registry.Identifier
				job.State = pb.State_BUILT
				job.RunningVersion = key
			}
		} else {
			job.CommandKey = key
			job.State = pb.State_BUILDING
			job.Server = s.Registry.Identifier
		}
	case pb.State_BUILDING:
		if s.taskComplete(job.CommandKey) {
			job.State = pb.State_BUILT
		}
	case pb.State_BUILT:
		output := s.scheduler.getOutput(job.CommandKey)
		if len(output) > 0 {
			if job.BuildFail == 5 {
				s.deliverCrashReport(ctx, job, output)
			}
			job.BuildFail++
			job.State = pb.State_DIED
		} else {
			job.BuildFail = 0
			key := s.scheduleRun(job.Job)
			job.CommandKey = key
			job.StartTime = time.Now().Unix()
			job.State = pb.State_PENDING
		}
	case pb.State_PENDING:
		if time.Now().Add(-time.Minute).Unix() > job.StartTime {
			job.State = pb.State_RUNNING
		}
	case pb.State_RUNNING:
		if s.taskComplete(job.CommandKey) {
			output := s.scheduler.getOutput(job.CommandKey)
			s.deliverCrashReport(ctx, job, output)
			job.State = pb.State_DIED
		}

		// Restart this job if we need to
		if job.Job.NonBootstrap {
			version := s.getVersion(ctx, job.Job)
			if version != job.RunningVersion {
				s.Log(fmt.Sprintf("KILLING %v", job.Job.Name))
				s.scheduler.killJob(job.CommandKey)
				job.State = pb.State_ACKNOWLEDGED
			}
		}
	case pb.State_DIED:
		job.State = pb.State_ACKNOWLEDGED
	}
	if job.State != stState {
		s.Log(fmt.Sprintf("Job %v went from %v to %v", job.Job.Name, stState, job.State))
	}
}

type translator interface {
	build(job *pb.Job) *exec.Cmd
	run(job *pb.Job) *exec.Cmd
}

type checker interface {
	isAlive(ctx context.Context, job *pb.JobAssignment) bool
}

func (s *Server) getVersion(ctx context.Context, job *pb.Job) string {
	versions := s.builder.build(ctx, job)

	if len(versions) == 0 {
		s.Log(fmt.Sprintf("No versions received for %v", job.Name))
		return ""
	}

	return versions[0].Version

}

// scheduleBuild builds out the job, returning the current version
func (s *Server) scheduleBuild(ctx context.Context, job *pb.Job) string {
	if !job.NonBootstrap {
		c := s.translator.build(job)
		return s.scheduler.Schedule(&rCommand{command: c})
	}

	s.Log(fmt.Sprintf("BUILDING %v", job.Name))
	versions := s.builder.build(ctx, job)

	if len(versions) == 0 {
		s.Log(fmt.Sprintf("No versions received for %v", job.Name))
		return ""
	}

	s.Log(fmt.Sprintf("COPYING WITH %v", s.builder))
	err := s.builder.copy(ctx, versions[0])
	if err != nil {
		return ""
	}
	return versions[0].Version
}

func (s *Server) scheduleRun(job *pb.Job) string {
	c := s.translator.run(job)
	return s.scheduler.Schedule(&rCommand{command: c})
}

func (s *Server) taskComplete(key string) bool {
	return s.scheduler.schedulerComplete(key)
}
<|endoftext|>


<commit_before>package gopherjs_http

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
	"os"
	pathpkg "path"
	"strings"
	"time"
)

// NewFS returns an http.FileSystem that is exactly like source, except all Go packages are compiled to JavaScript with GopherJS.
//
// For example:
//
// 	/mypkg/foo.go
// 	/mypkg/bar.go
//
// Become replaced with:
//
// 	/mypkg/mypkg.js
//
// Where mypkg.js is the result of building mypkg with GopherJS.
func NewFS(source http.FileSystem) http.FileSystem {
	return &gopherJSFS{source: source}
}

type gopherJSFS struct {
	source http.FileSystem
}

func (fs *gopherJSFS) Open(path string) (http.File, error) {
	switch dir, file := pathpkg.Split(path); {
	case file == pathpkg.Base(dir)+".js":
		return fs.compileGoPackage(dir)
	default:
		return fs.openSource(path)
	}
}

func (fs *gopherJSFS) openSource(path string) (http.File, error) {
	f, err := fs.source.Open(path)
	if err != nil {
		return nil, err
	}

	fi, err := f.Stat()
	if err != nil {
		f.Close()
		return nil, err
	}

	switch {
	// Files with .go and ".inc.js" extensions are consumed and no longer exist
	// in output filesystem.
	case !fi.IsDir() && pathpkg.Ext(fi.Name()) == ".go":
		fallthrough
	case !fi.IsDir() && strings.HasSuffix(fi.Name(), ".inc.js"):
		f.Close()
		return nil, &os.PathError{Op: "open", Path: path, Err: os.ErrNotExist}
	case !fi.IsDir():
		return f, nil
	}
	defer f.Close()

	fis, err := f.Readdir(0)
	if err != nil {
		return nil, err
	}

	// Include all subfolders, non-.go files.
	var entries []os.FileInfo
	var haveGo []os.FileInfo
	for _, fi := range fis {
		switch {
		case !fi.IsDir() && pathpkg.Ext(fi.Name()) == ".go":
			haveGo = append(haveGo, fi)
		case !fi.IsDir() && strings.HasSuffix(fi.Name(), ".inc.js"):
			// TODO: Handle ".inc.js" files correctly.
			entries = append(entries, fi)
		default:
			entries = append(entries, fi)
		}
	}

	// If it has any .go files, present the Go package compiled with GopherJS as an additional virtual file.
	if len(haveGo) > 0 {
		entries = append(entries, &file{
			name:    fi.Name() + ".js",
			size:    0,           // TODO.
			modTime: time.Time{}, // TODO.
		})
	}

	return &dir{
		name:    fi.Name(),
		entries: entries,
		modTime: fi.ModTime(),
	}, nil
}

func (fs *gopherJSFS) compileGoPackage(dir string) (http.File, error) {
	f, err := fs.source.Open(dir)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	fi, err := f.Stat()
	if err != nil {
		return nil, err
	}

	if !fi.IsDir() {
		return nil, fmt.Errorf("%s is not a dir", dir)
	}

	fis, err := f.Readdir(0)
	if err != nil {
		return nil, err
	}

	var goFiles []os.FileInfo
	for _, f := range fis {
		// TODO: Use build.Import or equivalent to get GoFiles and CgoFiles. The below approximates it, but fails to use build tags correctly, etc.
		if f.IsDir() {
			continue
		}
		if pathpkg.Ext(f.Name()) != ".go" {
			continue
		}
		if strings.HasPrefix(f.Name(), ".") || strings.HasPrefix(f.Name(), "_") {
			continue
		}
		if strings.HasSuffix(f.Name(), "_test.go") {
			continue
		}
		goFiles = append(goFiles, f)
	}
	if len(goFiles) == 0 {
		return nil, fmt.Errorf("%s has no matching .go files", dir)
	}

	// TODO: Clean this up.
	{
		name := pathpkg.Base(dir) + ".js"

		var names []string
		var goReaders []io.Reader
		var goClosers []io.Closer
		for _, goFile := range goFiles {
			file, err := fs.source.Open(pathpkg.Join(dir, goFile.Name()))
			if err != nil {
				return nil, err
			}
			names = append(names, goFile.Name())
			goReaders = append(goReaders, file)
			goClosers = append(goClosers, file)
		}

		fmt.Printf("REBUILDING SOURCE for: %s using %+v\n", name, names)
		content := []byte(handleJsError(goReadersToJs(names, goReaders)))

		for _, closer := range goClosers {
			closer.Close()
		}

		return &file{
			name:    name,
			size:    int64(len(content)),
			modTime: time.Now(),
			Reader:  bytes.NewReader(content),
		}, nil
	}
}

// file is an opened file instance.
type file struct {
	name    string
	modTime time.Time
	size    int64
	*bytes.Reader
}

func (f *file) Readdir(count int) ([]os.FileInfo, error) {
	return nil, fmt.Errorf("cannot Readdir from file %s", f.name)
}
func (f *file) Stat() (os.FileInfo, error) { return f, nil }

func (f *file) Name() string       { return f.name }
func (f *file) Size() int64        { return f.size }
func (f *file) Mode() os.FileMode  { return 0444 }
func (f *file) ModTime() time.Time { return f.modTime }
func (f *file) IsDir() bool        { return false }
func (f *file) Sys() interface{}   { return nil }

func (f *file) Close() error {
	return nil
}

// dir is an opened dir instance.
type dir struct {
	name    string
	modTime time.Time
	entries []os.FileInfo
	pos     int // Position within entries for Seek and Readdir.
}

func (d *dir) Read([]byte) (int, error) {
	return 0, fmt.Errorf("cannot Read from directory %s", d.name)
}
func (d *dir) Close() error               { return nil }
func (d *dir) Stat() (os.FileInfo, error) { return d, nil }

func (d *dir) Name() string       { return d.name }
func (d *dir) Size() int64        { return 0 }
func (d *dir) Mode() os.FileMode  { return 0755 | os.ModeDir }
func (d *dir) ModTime() time.Time { return d.modTime }
func (d *dir) IsDir() bool        { return true }
func (d *dir) Sys() interface{}   { return nil }

func (d *dir) Seek(offset int64, whence int) (int64, error) {
	if offset == 0 && whence == os.SEEK_SET {
		d.pos = 0
		return 0, nil
	}
	return 0, fmt.Errorf("unsupported Seek in directory %s", d.name)
}

func (d *dir) Readdir(count int) ([]os.FileInfo, error) {
	if d.pos >= len(d.entries) && count > 0 {
		return nil, io.EOF
	}
	if count <= 0 || count > len(d.entries)-d.pos {
		count = len(d.entries) - d.pos
	}
	e := d.entries[d.pos : d.pos+count]
	d.pos += count
	return e, nil
}
<commit_msg>gopherjs_http: Replace deprecated os.SEEK_{SET,CUR,END} with io.Seek{Start,Current,End}.<commit_after>package gopherjs_http

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
	"os"
	pathpkg "path"
	"strings"
	"time"
)

// NewFS returns an http.FileSystem that is exactly like source, except all Go packages are compiled to JavaScript with GopherJS.
//
// For example:
//
// 	/mypkg/foo.go
// 	/mypkg/bar.go
//
// Become replaced with:
//
// 	/mypkg/mypkg.js
//
// Where mypkg.js is the result of building mypkg with GopherJS.
func NewFS(source http.FileSystem) http.FileSystem {
	return &gopherJSFS{source: source}
}

type gopherJSFS struct {
	source http.FileSystem
}

func (fs *gopherJSFS) Open(path string) (http.File, error) {
	switch dir, file := pathpkg.Split(path); {
	case file == pathpkg.Base(dir)+".js":
		return fs.compileGoPackage(dir)
	default:
		return fs.openSource(path)
	}
}

func (fs *gopherJSFS) openSource(path string) (http.File, error) {
	f, err := fs.source.Open(path)
	if err != nil {
		return nil, err
	}

	fi, err := f.Stat()
	if err != nil {
		f.Close()
		return nil, err
	}

	switch {
	// Files with .go and ".inc.js" extensions are consumed and no longer exist
	// in output filesystem.
	case !fi.IsDir() && pathpkg.Ext(fi.Name()) == ".go":
		fallthrough
	case !fi.IsDir() && strings.HasSuffix(fi.Name(), ".inc.js"):
		f.Close()
		return nil, &os.PathError{Op: "open", Path: path, Err: os.ErrNotExist}
	case !fi.IsDir():
		return f, nil
	}
	defer f.Close()

	fis, err := f.Readdir(0)
	if err != nil {
		return nil, err
	}

	// Include all subfolders, non-.go files.
	var entries []os.FileInfo
	var haveGo []os.FileInfo
	for _, fi := range fis {
		switch {
		case !fi.IsDir() && pathpkg.Ext(fi.Name()) == ".go":
			haveGo = append(haveGo, fi)
		case !fi.IsDir() && strings.HasSuffix(fi.Name(), ".inc.js"):
			// TODO: Handle ".inc.js" files correctly.
			entries = append(entries, fi)
		default:
			entries = append(entries, fi)
		}
	}

	// If it has any .go files, present the Go package compiled with GopherJS as an additional virtual file.
	if len(haveGo) > 0 {
		entries = append(entries, &file{
			name:    fi.Name() + ".js",
			size:    0,           // TODO.
			modTime: time.Time{}, // TODO.
		})
	}

	return &dir{
		name:    fi.Name(),
		entries: entries,
		modTime: fi.ModTime(),
	}, nil
}

func (fs *gopherJSFS) compileGoPackage(dir string) (http.File, error) {
	f, err := fs.source.Open(dir)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	fi, err := f.Stat()
	if err != nil {
		return nil, err
	}

	if !fi.IsDir() {
		return nil, fmt.Errorf("%s is not a dir", dir)
	}

	fis, err := f.Readdir(0)
	if err != nil {
		return nil, err
	}

	var goFiles []os.FileInfo
	for _, f := range fis {
		// TODO: Use build.Import or equivalent to get GoFiles and CgoFiles. The below approximates it, but fails to use build tags correctly, etc.
		if f.IsDir() {
			continue
		}
		if pathpkg.Ext(f.Name()) != ".go" {
			continue
		}
		if strings.HasPrefix(f.Name(), ".") || strings.HasPrefix(f.Name(), "_") {
			continue
		}
		if strings.HasSuffix(f.Name(), "_test.go") {
			continue
		}
		goFiles = append(goFiles, f)
	}
	if len(goFiles) == 0 {
		return nil, fmt.Errorf("%s has no matching .go files", dir)
	}

	// TODO: Clean this up.
	{
		name := pathpkg.Base(dir) + ".js"

		var names []string
		var goReaders []io.Reader
		var goClosers []io.Closer
		for _, goFile := range goFiles {
			file, err := fs.source.Open(pathpkg.Join(dir, goFile.Name()))
			if err != nil {
				return nil, err
			}
			names = append(names, goFile.Name())
			goReaders = append(goReaders, file)
			goClosers = append(goClosers, file)
		}

		fmt.Printf("REBUILDING SOURCE for: %s using %+v\n", name, names)
		content := []byte(handleJsError(goReadersToJs(names, goReaders)))

		for _, closer := range goClosers {
			closer.Close()
		}

		return &file{
			name:    name,
			size:    int64(len(content)),
			modTime: time.Now(),
			Reader:  bytes.NewReader(content),
		}, nil
	}
}

// file is an opened file instance.
type file struct {
	name    string
	modTime time.Time
	size    int64
	*bytes.Reader
}

func (f *file) Readdir(count int) ([]os.FileInfo, error) {
	return nil, fmt.Errorf("cannot Readdir from file %s", f.name)
}
func (f *file) Stat() (os.FileInfo, error) { return f, nil }

func (f *file) Name() string       { return f.name }
func (f *file) Size() int64        { return f.size }
func (f *file) Mode() os.FileMode  { return 0444 }
func (f *file) ModTime() time.Time { return f.modTime }
func (f *file) IsDir() bool        { return false }
func (f *file) Sys() interface{}   { return nil }

func (f *file) Close() error {
	return nil
}

// dir is an opened dir instance.
type dir struct {
	name    string
	modTime time.Time
	entries []os.FileInfo
	pos     int // Position within entries for Seek and Readdir.
}

func (d *dir) Read([]byte) (int, error) {
	return 0, fmt.Errorf("cannot Read from directory %s", d.name)
}
func (d *dir) Close() error               { return nil }
func (d *dir) Stat() (os.FileInfo, error) { return d, nil }

func (d *dir) Name() string       { return d.name }
func (d *dir) Size() int64        { return 0 }
func (d *dir) Mode() os.FileMode  { return 0755 | os.ModeDir }
func (d *dir) ModTime() time.Time { return d.modTime }
func (d *dir) IsDir() bool        { return true }
func (d *dir) Sys() interface{}   { return nil }

func (d *dir) Seek(offset int64, whence int) (int64, error) {
	if offset == 0 && whence == io.SeekStart {
		d.pos = 0
		return 0, nil
	}
	return 0, fmt.Errorf("unsupported Seek in directory %s", d.name)
}

func (d *dir) Readdir(count int) ([]os.FileInfo, error) {
	if d.pos >= len(d.entries) && count > 0 {
		return nil, io.EOF
	}
	if count <= 0 || count > len(d.entries)-d.pos {
		count = len(d.entries) - d.pos
	}
	e := d.entries[d.pos : d.pos+count]
	d.pos += count
	return e, nil
}
<|endoftext|>