<commit_before>package dynamic

import (
	"bytes"
	"reflect"
	"testing"

	"github.com/golang/protobuf/jsonpb"
	"github.com/golang/protobuf/proto"
	"github.com/jhump/protoreflect/desc"
	"github.com/jhump/protoreflect/internal/testprotos"
	"github.com/jhump/protoreflect/internal/testutil"
)

func TestJSONUnaryFields(t *testing.T) {
	jsonTranslationParty(t, unaryFieldsMsg)
}

func TestJSONRepeatedFields(t *testing.T) {
	jsonTranslationParty(t, repeatedFieldsMsg)
}

func TestJSONMapKeyFields(t *testing.T) {
	// translation party wants deterministic marshalling to bytes
	sort_map_keys = true
	defer func() {
		sort_map_keys = false
	}()

	jsonTranslationParty(t, mapKeyFieldsMsg)
}

func TestJSONMapValueFields(t *testing.T) {
	// translation party wants deterministic marshalling to bytes
	sort_map_keys = true
	defer func() {
		sort_map_keys = false
	}()

	jsonTranslationParty(t, mapValueFieldsMsg)
}

func TestJSONExtensionFields(t *testing.T) {
	// TODO
}

func TestMarshalJSONEmitDefaults(t *testing.T) {
	md, err := desc.LoadMessageDescriptorForMessage((*testprotos.ReallySimpleMessage)(nil))
	testutil.Ok(t, err)
	dm := NewMessage(md)
	js, err := dm.MarshalJSON()
	testutil.Ok(t, err)
	testutil.Eq(t, `{}`, string(js))
	jsDefaults, err := dm.MarshalJSONPB(&jsonpb.Marshaler{EmitDefaults: true})
	testutil.Ok(t, err)
	testutil.Eq(t, `{"id":0,"name":""}`, string(jsDefaults))
}

func TestMarshalJSONEnumsAsInts(t *testing.T) {
	md, err := desc.LoadMessageDescriptorForMessage((*testprotos.TestRequest)(nil))
	testutil.Ok(t, err)
	dm := NewMessage(md)
	dm.SetFieldByNumber(1, []int32{1})
	dm.SetFieldByNumber(2, "bedazzle")
	js, err := dm.MarshalJSONPB(&jsonpb.Marshaler{EnumsAsInts: true})
	testutil.Ok(t, err)
	testutil.Eq(t, `{"foo":[1],"bar":"bedazzle"}`, string(js))
}

func TestMarshalJSONOrigName(t *testing.T) {
	// TODO
}

func TestMarshalJSONIndent(t *testing.T) {
	md, err := desc.LoadMessageDescriptorForMessage((*testprotos.TestRequest)(nil))
	testutil.Ok(t, err)
	dm := NewMessage(md)
	dm.SetFieldByNumber(1, []int32{1})
	dm.SetFieldByNumber(2, "bedazzle")
	js, err := dm.MarshalJSON()
	testutil.Ok(t, err)
	testutil.Eq(t, `{"foo":["VALUE1"],"bar":"bedazzle"}`, string(js))
	jsIndent, err := dm.MarshalJSONIndent()
	testutil.Ok(t, err)
	testutil.Eq(t, "{\n  \"foo\": [\n    \"VALUE1\"\n  ],\n  \"bar\": \"bedazzle\"\n}", string(jsIndent))
	jsIndent, err = dm.MarshalJSONPB(&jsonpb.Marshaler{Indent: "\t"})
	testutil.Ok(t, err)
	testutil.Eq(t, "{\n\t\"foo\": [\n\t\t\"VALUE1\"\n\t],\n\t\"bar\": \"bedazzle\"\n}", string(jsIndent))
}

func TestUnmarshalJSON(t *testing.T) {
	md, err := desc.LoadMessageDescriptorForMessage((*testprotos.TestRequest)(nil))
	testutil.Ok(t, err)

	js1 := []byte(`{"foo":["VALUE1"],"bar":"bedazzle"}`)
	dm1 := NewMessage(md)
	err = dm1.UnmarshalJSON(js1)
	testutil.Ok(t, err)
	foo1 := dm1.GetFieldByNumber(1)
	bar1 := dm1.GetFieldByNumber(2)
	testutil.Eq(t, coerceSlice([]int32{1}, reflect.Int32), foo1)
	testutil.Eq(t, coerceSlice("bedazzle", reflect.String), bar1)

	js2 := []byte("{\n  \"foo\": [\n    \"VALUE1\"\n  ],\n  \"bar\": \"bedazzle\"\n}")
	dm2 := NewMessage(md)
	err = dm2.UnmarshalJSON(js2)
	testutil.Ok(t, err)
	foo2 := dm2.GetFieldByNumber(1)
	bar2 := dm2.GetFieldByNumber(2)
	testutil.Eq(t, coerceSlice([]int32{1}, reflect.Int32), foo2)
	testutil.Eq(t, coerceSlice("bedazzle", reflect.String), bar2)
}

func TestUnmarshalJSONAllowUnknownFields(t *testing.T) {
	md, err := desc.LoadMessageDescriptorForMessage((*testprotos.TestRequest)(nil))
	testutil.Ok(t, err)
	js := []byte(`{"foo":["VALUE1"],"bar":"bedazzle","xxx": 1}`)
	dm := NewMessage(md)
	err = dm.UnmarshalJSON(js)
	testutil.Nok(t, err)
	unmarshaler := &jsonpb.Unmarshaler{AllowUnknownFields: true}
	err = dm.UnmarshalJSONPB(unmarshaler, js)
	testutil.Ok(t, err)
	foo := dm.GetFieldByNumber(1)
	bar := dm.GetFieldByNumber(2)
	testutil.Eq(t, coerceSlice([]int32{1}, reflect.Int32), foo)
	testutil.Eq(t, coerceSlice("bedazzle", reflect.String), bar)
}

func jsonTranslationParty(t *testing.T, msg proto.Message) {
	doTranslationParty(t, msg,
		func(pm proto.Message) ([]byte, error) {
			m := jsonpb.Marshaler{}
			var b bytes.Buffer
			err := m.Marshal(&b, pm)
			if err != nil {
				return nil, err
			} else {
				return b.Bytes(), nil
			}
		},
		func(b []byte, pm proto.Message) error {
			return jsonpb.Unmarshal(bytes.NewReader(b), pm)
		},
		(*Message).MarshalJSON, (*Message).UnmarshalJSON)
}
<commit_msg>fix redandancy for test<commit_after>package dynamic

import (
	"bytes"
	"testing"

	"github.com/golang/protobuf/jsonpb"
	"github.com/golang/protobuf/proto"
	"github.com/jhump/protoreflect/desc"
	"github.com/jhump/protoreflect/internal/testprotos"
	"github.com/jhump/protoreflect/internal/testutil"
)

func TestJSONUnaryFields(t *testing.T) {
	jsonTranslationParty(t, unaryFieldsMsg)
}

func TestJSONRepeatedFields(t *testing.T) {
	jsonTranslationParty(t, repeatedFieldsMsg)
}

func TestJSONMapKeyFields(t *testing.T) {
	// translation party wants deterministic marshalling to bytes
	sort_map_keys = true
	defer func() {
		sort_map_keys = false
	}()

	jsonTranslationParty(t, mapKeyFieldsMsg)
}

func TestJSONMapValueFields(t *testing.T) {
	// translation party wants deterministic marshalling to bytes
	sort_map_keys = true
	defer func() {
		sort_map_keys = false
	}()

	jsonTranslationParty(t, mapValueFieldsMsg)
}

func TestJSONExtensionFields(t *testing.T) {
	// TODO
}

func TestMarshalJSONEmitDefaults(t *testing.T) {
	md, err := desc.LoadMessageDescriptorForMessage((*testprotos.ReallySimpleMessage)(nil))
	testutil.Ok(t, err)
	dm := NewMessage(md)
	js, err := dm.MarshalJSON()
	testutil.Ok(t, err)
	testutil.Eq(t, `{}`, string(js))
	jsDefaults, err := dm.MarshalJSONPB(&jsonpb.Marshaler{EmitDefaults: true})
	testutil.Ok(t, err)
	testutil.Eq(t, `{"id":0,"name":""}`, string(jsDefaults))
}

func TestMarshalJSONEnumsAsInts(t *testing.T) {
	md, err := desc.LoadMessageDescriptorForMessage((*testprotos.TestRequest)(nil))
	testutil.Ok(t, err)
	dm := NewMessage(md)
	dm.SetFieldByNumber(1, []int32{1})
	dm.SetFieldByNumber(2, "bedazzle")
	js, err := dm.MarshalJSONPB(&jsonpb.Marshaler{EnumsAsInts: true})
	testutil.Ok(t, err)
	testutil.Eq(t, `{"foo":[1],"bar":"bedazzle"}`, string(js))
}

func TestMarshalJSONOrigName(t *testing.T) {
	// TODO
}

func TestMarshalJSONIndent(t *testing.T) {
	md, err := desc.LoadMessageDescriptorForMessage((*testprotos.TestRequest)(nil))
	testutil.Ok(t, err)
	dm := NewMessage(md)
	dm.SetFieldByNumber(1, []int32{1})
	dm.SetFieldByNumber(2, "bedazzle")
	js, err := dm.MarshalJSON()
	testutil.Ok(t, err)
	testutil.Eq(t, `{"foo":["VALUE1"],"bar":"bedazzle"}`, string(js))
	jsIndent, err := dm.MarshalJSONIndent()
	testutil.Ok(t, err)
	testutil.Eq(t, "{\n  \"foo\": [\n    \"VALUE1\"\n  ],\n  \"bar\": \"bedazzle\"\n}", string(jsIndent))
	jsIndent, err = dm.MarshalJSONPB(&jsonpb.Marshaler{Indent: "\t"})
	testutil.Ok(t, err)
	testutil.Eq(t, "{\n\t\"foo\": [\n\t\t\"VALUE1\"\n\t],\n\t\"bar\": \"bedazzle\"\n}", string(jsIndent))
}

func TestUnmarshalJSONAllowUnknownFields(t *testing.T) {
	md, err := desc.LoadMessageDescriptorForMessage((*testprotos.TestRequest)(nil))
	testutil.Ok(t, err)
	js := []byte(`{"foo":["VALUE1"],"bar":"bedazzle","xxx": 1}`)
	dm := NewMessage(md)
	err = dm.UnmarshalJSON(js)
	testutil.Nok(t, err)
	unmarshaler := &jsonpb.Unmarshaler{AllowUnknownFields: true}
	err = dm.UnmarshalJSONPB(unmarshaler, js)
	testutil.Ok(t, err)
	foo := dm.GetFieldByNumber(1)
	bar := dm.GetFieldByNumber(2)
	testutil.Eq(t, []int32{1}, foo)
	testutil.Eq(t, "bedazzle", bar)
}

func jsonTranslationParty(t *testing.T, msg proto.Message) {
	doTranslationParty(t, msg,
		func(pm proto.Message) ([]byte, error) {
			m := jsonpb.Marshaler{}
			var b bytes.Buffer
			err := m.Marshal(&b, pm)
			if err != nil {
				return nil, err
			} else {
				return b.Bytes(), nil
			}
		},
		func(b []byte, pm proto.Message) error {
			return jsonpb.Unmarshal(bytes.NewReader(b), pm)
		},
		(*Message).MarshalJSON, (*Message).UnmarshalJSON)
}
<|endoftext|>


<commit_before>package handlers

import (
	"github.com/gorilla/schema"
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/sqlite"
	_ "github.com/mattn/go-sqlite3"
	"html/template"
	"log"
	"net/http"
	"path/filepath"
)

type Environment struct {
	DB        *gorm.DB
	Decoder   *schema.Decoder
	Templates *template.Template
}

func NewEnvironment(pathToServerRoot, dbFilePath string) *Environment {
	return &Environment{
		DB:        initDBConnection(dbFilePath),
		Decoder:   schema.NewDecoder(),
		Templates: compileTemplates(pathToServerRoot),
	}
}

func compileTemplates(pathToServerRoot string) *template.Template {
	templateDir, _ := filepath.Abs(filepath.Join(pathToServerRoot, "templates", "*.html"))
	log.Println("Loading templates:", templateDir)
	return template.Must(template.ParseGlob(templateDir))
}

// TODO: This is also used by the easy_store_setup app.
// Put it on one place, and don't rely on testutil.GetPathToSchema()
// as that file and directory exist in dev mode only, and users
// won't have them.
func initDBConnection(dbFilePath string) *gorm.DB {
	db, err := gorm.Open("sqlite3", dbFilePath)
	if err != nil {
		panic(err.Error())
	}
	db.LogMode(true)
	return db
}

type CustomHandler interface {
	HandleRequest(env *Environment, w http.ResponseWriter, r *http.Request) error
}

func WrapHandler(env *Environment, customHandler CustomHandler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		logRequest(r)
		err := customHandler.HandleRequest(env, w, r)
		if err != nil {
			HandleError(w, r, err)
		}
	})
}
<commit_msg>Simplify and comment middleware wrapper<commit_after>package handlers

import (
	"github.com/gorilla/schema"
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/sqlite"
	_ "github.com/mattn/go-sqlite3"
	"html/template"
	"log"
	"net/http"
	"path/filepath"
)

type Environment struct {
	DB        *gorm.DB
	Decoder   *schema.Decoder
	Templates *template.Template
}

func NewEnvironment(pathToServerRoot, dbFilePath string) *Environment {
	return &Environment{
		DB:        initDBConnection(dbFilePath),
		Decoder:   schema.NewDecoder(),
		Templates: compileTemplates(pathToServerRoot),
	}
}

func compileTemplates(pathToServerRoot string) *template.Template {
	templateDir, _ := filepath.Abs(filepath.Join(pathToServerRoot, "templates", "*.html"))
	log.Println("Loading templates:", templateDir)
	return template.Must(template.ParseGlob(templateDir))
}

// TODO: This is also used by the easy_store_setup app.
// Put it on one place, and don't rely on testutil.GetPathToSchema()
// as that file and directory exist in dev mode only, and users
// won't have them.
func initDBConnection(dbFilePath string) *gorm.DB {
	db, err := gorm.Open("sqlite3", dbFilePath)
	if err != nil {
		panic(err.Error())
	}
	db.LogMode(true)
	return db
}

// WrapHandler wraps a custom HTTP request handler inside a standard Go
// HTTP request handler, and returns the standard handler. We wrap
// the handler functions for a number of reasons:
//
// First, we want to pass in some resources that all handlers need,
// such as the connection to the database and a reference to the
// HTML templates.
//
// Second we want to standardize logging and error handling in a
// single location, so we want our custom HTTP handlers to quit
// early and return an error when necessary. The standard Go HTTP
// handlers don't return anything.
//
// Third, this wrapper allows us to inject middleware as needed.
// While Go's standard middleware pattern already allows this, we do
// need this custom implementation if we want to be able to pass
// environment data and receive errors.
func WrapHandler(env *Environment, handler func(env *Environment, w http.ResponseWriter, r *http.Request) error) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		logRequest(r)
		err := handler(env, w, r)
		if err != nil {
			HandleError(w, r, err)
		}
	})
}
<|endoftext|>


<commit_before>package server

import (
	"fmt"
	"testing"

	"github.com/siddontang/goredis"
)

func checkScanValues(t *testing.T, ay interface{}, values ...interface{}) {
	a, err := goredis.Strings(ay, nil)
	if err != nil {
		t.Error(err)
	}

	if len(a) != len(values) {
		t.Error(fmt.Sprintf("len %d != %d", len(a), len(values)))
	}
	for i, v := range a {
		vv := fmt.Sprintf("%v", values[i])
		if string(v) != vv {
			if len(v) == len(vv)+8 {
				if string(v[:len(vv)]) != vv {
					t.Errorf(fmt.Sprintf("%d %s != %v", i, string(v), values[i]))
				}
			} else if len(v)+8 == len(vv) {
				if string(v) != vv[:len(v)] {
					t.Errorf(fmt.Sprintf("%d %s != %v", i, string(v), values[i]))
				}
			} else {
				t.Errorf(fmt.Sprintf("%d %s != %v", i, string(v), values[i]))
			}
		}
	}
}

func checkAdvanceScan(t *testing.T, c *goredis.PoolConn, tp string) {
	var cursor string
	if ay, err := goredis.Values(c.Do("ADVSCAN", "default:testscan:", tp, "count", 5)); err != nil {
		t.Error(err)
	} else if len(ay) != 2 {
		t.Fatal(len(ay))
		//} else if n := ay[0].([]byte); string(n) != "MDpkR1Z6ZEhOallXNDZOQT09Ow==" {
	} else if n := ay[0].([]byte); string(n) != "MDpOQT09Ow==" {
		t.Fatal(string(n))
	} else {
		cursor = string(n)
		checkScanValues(t, ay[1], "0", "1", "2", "3", "4")
	}

	if ay, err := goredis.Values(c.Do("ADVSCAN", "default:testscan:"+cursor, tp, "count", 6)); err != nil {
		t.Fatal(err)
	} else if len(ay) != 2 {
		t.Fatal(len(ay))
	} else if n := ay[0].([]byte); string(n) != "" {
		t.Fatal(string(n))
	} else {
		checkScanValues(t, ay[1], "5", "6", "7", "8", "9")
	}

	// cursor 9 for base64(0:base64(9);) is MDpPUT09Ow==
	if ay, err := goredis.Values(c.Do("ADVSCAN", "default:testscan:MDpPUT09Ow==", tp, "count", 1)); err != nil {
		t.Fatal(err)
	} else if len(ay) != 2 {
		t.Fatal(len(ay))
	} else if n := ay[0].([]byte); string(n) != "" {
		t.Fatal(string(n))
	} else {
		if len(ay[1].([]interface{})) != 0 {
			t.Fatal(ay[1])
		}
	}
}

func checkAdvanceRevScan(t *testing.T, c *goredis.PoolConn, tp string) {
	var cursor string
	// use cursor 0::; to search, base64 is base64(0:base64(:);)
	if ay, err := goredis.Values(c.Do("ADVREVSCAN", "default:testscan:MDpPZz09Ow==", tp, "count", 5)); err != nil {
		t.Error(err)
		return
	} else if len(ay) != 2 {
		t.Fatal(len(ay))
		//} else if n := ay[0].([]byte); string(n) != "MDpkR1Z6ZEhOallXNDZOQT09Ow==" {
	} else if n := ay[0].([]byte); string(n) != "MDpOUT09Ow==" {
		t.Fatal(string(n))
	} else {
		cursor = string(n)
		checkScanValues(t, ay[1], "9", "8", "7", "6", "5")
	}

	if ay, err := goredis.Values(c.Do("ADVREVSCAN", "default:testscan:"+cursor, tp, "count", 6)); err != nil {
		t.Error(err)
		return
	} else if len(ay) != 2 {
		t.Fatal(len(ay))
	} else if n := ay[0].([]byte); string(n) != "" {
		t.Fatal(string(n))
	} else {
		checkScanValues(t, ay[1], "4", "3", "2", "1", "0")
	}

	// testscan:9 for base64 is MDpkR1Z6ZEhOallXNDZPUT09Ow=
	if ay, err := goredis.Values(c.Do("ADVREVSCAN", "default:testscan:", tp, "count", 1)); err != nil {
		t.Error(err)
		return
	} else if len(ay) != 2 {
		t.Fatal(len(ay))
	} else if n := ay[0].([]byte); string(n) != "" {
		t.Fatal(string(n))
	} else {
		if len(ay[1].([]interface{})) != 0 {
			t.Fatal(ay[1])
		}
	}
}

func TestScan(t *testing.T) {
	c := getTestConn(t)
	defer c.Close()

	if testing.Verbose() {
		changeLogLevel(t, 4, redisport+1)
	}
	testKVScan(t, c)
	testHashKeyScan(t, c)
	testListKeyScan(t, c)
	testZSetKeyScan(t, c)
	testSetKeyScan(t, c)
	changeLogLevel(t, 2, redisport+1)
}

func testKVScan(t *testing.T, c *goredis.PoolConn) {
	for i := 0; i < 10; i++ {
		if _, err := c.Do("set", "default:testscan:"+fmt.Sprintf("%d", i), []byte("value")); err != nil {
			t.Fatal(err)
		}
	}
	checkAdvanceScan(t, c, "KV")
	checkAdvanceRevScan(t, c, "KV")
}

func testHashKeyScan(t *testing.T, c *goredis.PoolConn) {
	for i := 0; i < 10; i++ {
		if _, err := c.Do("hset", "default:testscan:"+fmt.Sprintf("%d", i), fmt.Sprintf("%d", i), []byte("value")); err != nil {
			t.Fatal(err)
		}
	}

	checkAdvanceScan(t, c, "HASH")
	checkAdvanceRevScan(t, c, "HASH")
}

func testListKeyScan(t *testing.T, c *goredis.PoolConn) {
	for i := 0; i < 10; i++ {
		if _, err := c.Do("lpush", "default:testscan:"+fmt.Sprintf("%d", i), fmt.Sprintf("%d", i)); err != nil {
			t.Fatal(err)
		}
	}

	checkAdvanceScan(t, c, "LIST")
	checkAdvanceRevScan(t, c, "HASH")
}

func testZSetKeyScan(t *testing.T, c *goredis.PoolConn) {
	for i := 0; i < 10; i++ {
		if _, err := c.Do("zadd", "default:testscan:"+fmt.Sprintf("%d", i), i, []byte("value")); err != nil {
			t.Fatal(err)
		}
	}

	checkAdvanceScan(t, c, "ZSET")
	checkAdvanceRevScan(t, c, "HASH")
}

func testSetKeyScan(t *testing.T, c *goredis.PoolConn) {
	for i := 0; i < 10; i++ {
		if _, err := c.Do("sadd", "default:testscan:"+fmt.Sprintf("%d", i), fmt.Sprintf("%d", i)); err != nil {
			t.Fatal(err)
		}
	}

	checkAdvanceScan(t, c, "SET")
	checkAdvanceRevScan(t, c, "HASH")
}

func TestHashScan(t *testing.T) {
	c := getTestConn(t)
	defer c.Close()

	key := "default:testscan:scan_hash"
	c.Do("HMSET", key, "a", 1, "b", 2)

	if ay, err := goredis.Values(c.Do("HSCAN", key, "")); err != nil {
		t.Fatal(err)
	} else if len(ay) != 2 {
		t.Fatal(len(ay))
	} else {
		checkScanValues(t, ay[1], "a", 1, "b", 2)
	}

	if ay, err := goredis.Values(c.Do("HREVSCAN", key, "c")); err != nil {
		t.Fatal(err)
	} else if len(ay) != 2 {
		t.Fatal(len(ay))
	} else {
		checkScanValues(t, ay[1], "b", 2, "a", 1)
	}
	// TODO: test scan expired hash key
	// TODO: test scan expired and new created hash key
}

func TestSetScan(t *testing.T) {
	c := getTestConn(t)
	defer c.Close()

	if testing.Verbose() {
		changeLogLevel(t, 4, redisport+1)
	}
	key := "default:test:scan_set"
	c.Do("SADD", key, "a", "b")

	if ay, err := goredis.Values(c.Do("SSCAN", key, "")); err != nil {
		t.Fatal(err)
	} else if len(ay) != 2 {
		t.Fatal(len(ay))
	} else {
		checkScanValues(t, ay[1], "a", "b")
	}

	if ay, err := goredis.Values(c.Do("SREVSCAN", key, "c")); err != nil {
		t.Fatal(err)
	} else if len(ay) != 2 {
		t.Fatal(len(ay))
	} else {
		checkScanValues(t, ay[1], "b", "a")
	}
	changeLogLevel(t, 2, redisport+1)
}

func TestZSetScan(t *testing.T) {
	c := getTestConn(t)
	defer c.Close()

	key := "default:test:scan_zset"
	c.Do("ZADD", key, 1, "a", 2, "b")

	if ay, err := goredis.Values(c.Do("ZSCAN", key, "")); err != nil {
		t.Fatal(err)
	} else if len(ay) != 2 {
		t.Fatal(len(ay))
	} else {
		checkScanValues(t, ay[1], "a", 1, "b", 2)
	}

	if ay, err := goredis.Values(c.Do("ZREVSCAN", key, "c")); err != nil {
		t.Fatal(err)
	} else if len(ay) != 2 {
		t.Fatal(len(ay))
	} else {
		checkScanValues(t, ay[1], "b", 2, "a", 1)
	}
}
<commit_msg>add hash expire test for scan<commit_after>package server

import (
	"fmt"
	"testing"
	"time"

	"github.com/siddontang/goredis"
	"github.com/stretchr/testify/assert"
)

func checkScanValues(t *testing.T, ay interface{}, values ...interface{}) {
	a, err := goredis.Strings(ay, nil)
	if err != nil {
		t.Error(err)
	}

	if len(a) != len(values) {
		t.Error(fmt.Sprintf("len %d != %d", len(a), len(values)))
	}
	for i, v := range a {
		vv := fmt.Sprintf("%v", values[i])
		if string(v) != vv {
			if len(v) == len(vv)+8 {
				if string(v[:len(vv)]) != vv {
					t.Errorf(fmt.Sprintf("%d %s != %v", i, string(v), values[i]))
				}
			} else if len(v)+8 == len(vv) {
				if string(v) != vv[:len(v)] {
					t.Errorf(fmt.Sprintf("%d %s != %v", i, string(v), values[i]))
				}
			} else {
				t.Errorf(fmt.Sprintf("%d %s != %v", i, string(v), values[i]))
			}
		}
	}
}

func checkAdvanceScan(t *testing.T, c *goredis.PoolConn, tp string) {
	var cursor string
	if ay, err := goredis.Values(c.Do("ADVSCAN", "default:testscan:", tp, "count", 5)); err != nil {
		t.Error(err)
	} else if len(ay) != 2 {
		t.Fatal(len(ay))
		//} else if n := ay[0].([]byte); string(n) != "MDpkR1Z6ZEhOallXNDZOQT09Ow==" {
	} else if n := ay[0].([]byte); string(n) != "MDpOQT09Ow==" {
		t.Fatal(string(n))
	} else {
		cursor = string(n)
		checkScanValues(t, ay[1], "0", "1", "2", "3", "4")
	}

	if ay, err := goredis.Values(c.Do("ADVSCAN", "default:testscan:"+cursor, tp, "count", 6)); err != nil {
		t.Fatal(err)
	} else if len(ay) != 2 {
		t.Fatal(len(ay))
	} else if n := ay[0].([]byte); string(n) != "" {
		t.Fatal(string(n))
	} else {
		checkScanValues(t, ay[1], "5", "6", "7", "8", "9")
	}

	// cursor 9 for base64(0:base64(9);) is MDpPUT09Ow==
	if ay, err := goredis.Values(c.Do("ADVSCAN", "default:testscan:MDpPUT09Ow==", tp, "count", 1)); err != nil {
		t.Fatal(err)
	} else if len(ay) != 2 {
		t.Fatal(len(ay))
	} else if n := ay[0].([]byte); string(n) != "" {
		t.Fatal(string(n))
	} else {
		if len(ay[1].([]interface{})) != 0 {
			t.Fatal(ay[1])
		}
	}
}

func checkAdvanceRevScan(t *testing.T, c *goredis.PoolConn, tp string) {
	var cursor string
	// use cursor 0::; to search, base64 is base64(0:base64(:);)
	if ay, err := goredis.Values(c.Do("ADVREVSCAN", "default:testscan:MDpPZz09Ow==", tp, "count", 5)); err != nil {
		t.Error(err)
		return
	} else if len(ay) != 2 {
		t.Fatal(len(ay))
		//} else if n := ay[0].([]byte); string(n) != "MDpkR1Z6ZEhOallXNDZOQT09Ow==" {
	} else if n := ay[0].([]byte); string(n) != "MDpOUT09Ow==" {
		t.Fatal(string(n))
	} else {
		cursor = string(n)
		checkScanValues(t, ay[1], "9", "8", "7", "6", "5")
	}

	if ay, err := goredis.Values(c.Do("ADVREVSCAN", "default:testscan:"+cursor, tp, "count", 6)); err != nil {
		t.Error(err)
		return
	} else if len(ay) != 2 {
		t.Fatal(len(ay))
	} else if n := ay[0].([]byte); string(n) != "" {
		t.Fatal(string(n))
	} else {
		checkScanValues(t, ay[1], "4", "3", "2", "1", "0")
	}

	// testscan:9 for base64 is MDpkR1Z6ZEhOallXNDZPUT09Ow=
	if ay, err := goredis.Values(c.Do("ADVREVSCAN", "default:testscan:", tp, "count", 1)); err != nil {
		t.Error(err)
		return
	} else if len(ay) != 2 {
		t.Fatal(len(ay))
	} else if n := ay[0].([]byte); string(n) != "" {
		t.Fatal(string(n))
	} else {
		if len(ay[1].([]interface{})) != 0 {
			t.Fatal(ay[1])
		}
	}
}

func TestScan(t *testing.T) {
	c := getTestConn(t)
	defer c.Close()

	if testing.Verbose() {
		changeLogLevel(t, 4, redisport+1)
	}
	testKVScan(t, c)
	testHashKeyScan(t, c)
	testListKeyScan(t, c)
	testZSetKeyScan(t, c)
	testSetKeyScan(t, c)
	changeLogLevel(t, 2, redisport+1)
}

func testKVScan(t *testing.T, c *goredis.PoolConn) {
	for i := 0; i < 10; i++ {
		if _, err := c.Do("set", "default:testscan:"+fmt.Sprintf("%d", i), []byte("value")); err != nil {
			t.Fatal(err)
		}
	}
	checkAdvanceScan(t, c, "KV")
	checkAdvanceRevScan(t, c, "KV")
}

func testHashKeyScan(t *testing.T, c *goredis.PoolConn) {
	for i := 0; i < 10; i++ {
		if _, err := c.Do("hset", "default:testscan:"+fmt.Sprintf("%d", i), fmt.Sprintf("%d", i), []byte("value")); err != nil {
			t.Fatal(err)
		}
	}

	checkAdvanceScan(t, c, "HASH")
	checkAdvanceRevScan(t, c, "HASH")
}

func testListKeyScan(t *testing.T, c *goredis.PoolConn) {
	for i := 0; i < 10; i++ {
		if _, err := c.Do("lpush", "default:testscan:"+fmt.Sprintf("%d", i), fmt.Sprintf("%d", i)); err != nil {
			t.Fatal(err)
		}
	}

	checkAdvanceScan(t, c, "LIST")
	checkAdvanceRevScan(t, c, "HASH")
}

func testZSetKeyScan(t *testing.T, c *goredis.PoolConn) {
	for i := 0; i < 10; i++ {
		if _, err := c.Do("zadd", "default:testscan:"+fmt.Sprintf("%d", i), i, []byte("value")); err != nil {
			t.Fatal(err)
		}
	}

	checkAdvanceScan(t, c, "ZSET")
	checkAdvanceRevScan(t, c, "HASH")
}

func testSetKeyScan(t *testing.T, c *goredis.PoolConn) {
	for i := 0; i < 10; i++ {
		if _, err := c.Do("sadd", "default:testscan:"+fmt.Sprintf("%d", i), fmt.Sprintf("%d", i)); err != nil {
			t.Fatal(err)
		}
	}

	checkAdvanceScan(t, c, "SET")
	checkAdvanceRevScan(t, c, "HASH")
}

func TestHashScan(t *testing.T) {
	c := getTestConn(t)
	defer c.Close()

	key := "default:testscan:scan_hash"
	c.Do("HMSET", key, "a", 1, "b", 2)

	if ay, err := goredis.Values(c.Do("HSCAN", key, "")); err != nil {
		t.Fatal(err)
	} else if len(ay) != 2 {
		t.Fatal(len(ay))
	} else {
		checkScanValues(t, ay[1], "a", 1, "b", 2)
	}

	if ay, err := goredis.Values(c.Do("HREVSCAN", key, "c")); err != nil {
		t.Fatal(err)
	} else if len(ay) != 2 {
		t.Fatal(len(ay))
	} else {
		checkScanValues(t, ay[1], "b", 2, "a", 1)
	}
	// test scan expired hash key
	c.Do("hexpire", key, 1)
	time.Sleep(time.Second * 2)
	ay, err := goredis.Values(c.Do("HSCAN", key, ""))
	assert.Nil(t, err)
	assert.Equal(t, 2, len(ay))
	ayv, err := goredis.Strings(ay[1], nil)
	assert.Equal(t, 0, len(ayv))

	ay, err = goredis.Values(c.Do("HREVSCAN", key, "c"))
	assert.Nil(t, err)
	assert.Equal(t, 2, len(ay))
	ayv, err = goredis.Strings(ay[1], nil)
	assert.Equal(t, 0, len(ayv))
	// test scan expired and new created hash key
	c.Do("HMSET", key, "a", 1, "b", 2)
	ay, err = goredis.Values(c.Do("HSCAN", key, ""))
	assert.Nil(t, err)
	assert.Equal(t, 2, len(ay))
	checkScanValues(t, ay[1], "a", 1, "b", 2)

	ay, err = goredis.Values(c.Do("HREVSCAN", key, "c"))
	assert.Nil(t, err)
	assert.Equal(t, 2, len(ay))
	checkScanValues(t, ay[1], "b", 2, "a", 1)
}

func TestSetScan(t *testing.T) {
	c := getTestConn(t)
	defer c.Close()

	if testing.Verbose() {
		changeLogLevel(t, 4, redisport+1)
	}
	key := "default:test:scan_set"
	c.Do("SADD", key, "a", "b")

	if ay, err := goredis.Values(c.Do("SSCAN", key, "")); err != nil {
		t.Fatal(err)
	} else if len(ay) != 2 {
		t.Fatal(len(ay))
	} else {
		checkScanValues(t, ay[1], "a", "b")
	}

	if ay, err := goredis.Values(c.Do("SREVSCAN", key, "c")); err != nil {
		t.Fatal(err)
	} else if len(ay) != 2 {
		t.Fatal(len(ay))
	} else {
		checkScanValues(t, ay[1], "b", "a")
	}
	changeLogLevel(t, 2, redisport+1)
}

func TestZSetScan(t *testing.T) {
	c := getTestConn(t)
	defer c.Close()

	key := "default:test:scan_zset"
	c.Do("ZADD", key, 1, "a", 2, "b")

	if ay, err := goredis.Values(c.Do("ZSCAN", key, "")); err != nil {
		t.Fatal(err)
	} else if len(ay) != 2 {
		t.Fatal(len(ay))
	} else {
		checkScanValues(t, ay[1], "a", 1, "b", 2)
	}

	if ay, err := goredis.Values(c.Do("ZREVSCAN", key, "c")); err != nil {
		t.Fatal(err)
	} else if len(ay) != 2 {
		t.Fatal(len(ay))
	} else {
		checkScanValues(t, ay[1], "b", 2, "a", 1)
	}
}
<|endoftext|>


<commit_before>package effects

import (
	"math"

	"github.com/faiface/beep"
)

type (

	// This parametric equalizer is based on the GK Nilsen's post at:
	// https://octovoid.com/2017/11/04/coding-a-parametric-equalizer-for-audio-applications/
	equalizer struct {
		streamer beep.Streamer
		sections []section
	}

	section struct {
		a, b         []float64
		xPast, yPast [][2]float64
	}

	EqualizerSection struct {
		// F0 (center frequency) sets the mid-point of the section’s
		// frequency range and is given in Hertz [Hz].
		F0 float64

		// Bf (bandwidth) represents the width of the section across
		// frequency and is measured in Hertz [Hz]. A low bandwidth
		// corresponds to a narrow frequency range meaning that the
		// section will concentrate its operation to only the
		// frequencies close to the center frequency. On the other hand,
		// a high bandwidth yields a section of wide frequency range —
		// affecting a broader range of frequencies surrounding the
		// center frequency.
		Bf float64

		// GB (bandwidth gain) is given in decibels [dB] and represents
		// the level at which the bandwidth is measured. That is, to
		// have a meaningful measure of bandwidth, we must define the
		// level at which it is measured.
		GB float64

		// G0 (reference gain) is given in decibels [dB] and simply
		// represents the level of the section’s offset.
		G0 float64

		// G (boost/cut gain) is given in decibels [dB] and prescribes
		// the effect imposed on the audio loudness for the section’s
		// frequency range. A boost/cut level of 0 dB corresponds to
		// unity (no operation), whereas negative numbers corresponds to
		// cut (volume down) and positive numbers to boost (volume up).
		G float64
	}
)

func (s *section) apply(x [][2]float64) [][2]float64 {
	ord := len(s.a) - 1
	np := len(x) - 1

	if np < ord {
		x = append(x, make([][2]float64, ord-np)...)
		np = ord
	}

	y := make([][2]float64, len(x))

	if len(s.xPast) == 0 {
		s.xPast = make([][2]float64, len(x))
	}

	if len(s.yPast) == 0 {
		s.yPast = make([][2]float64, len(x))
	}

	for i := 0; i < len(x); i++ {
		for j := 0; j < ord+1; j++ {
			if i-j < 0 {
				y[i][0] = y[i][0] + s.b[j]*s.xPast[len(s.xPast)-j][0]
				y[i][1] = y[i][1] + s.b[j]*s.xPast[len(s.xPast)-j][1]
			} else {
				y[i][0] = y[i][0] + s.b[j]*x[i-j][0]
				y[i][1] = y[i][1] + s.b[j]*x[i-j][1]
			}
		}

		for j := 0; j < ord; j++ {
			if i-j-1 < 0 {
				y[i][0] = y[i][0] - s.a[j+1]*s.yPast[len(s.yPast)-j-1][0]
				y[i][1] = y[i][1] - s.a[j+1]*s.yPast[len(s.yPast)-j-1][1]
			} else {
				y[i][0] = y[i][0] - s.a[j+1]*y[i-j-1][0]
				y[i][1] = y[i][1] - s.a[j+1]*y[i-j-1][1]
			}

			y[i][0] = y[i][0] / s.a[0]
			y[i][1] = y[i][1] / s.a[0]
		}
	}

	s.xPast = x
	s.yPast = y
	return y
}

// NewEqualizer returns a beep.Streamer that modifies the stream based on the EqualizerSection slice that is passed in.
// The sample frequency (fs) must match that of the Streamer.
func NewEqualizer(s beep.Streamer, fs float64, sections []EqualizerSection) beep.Streamer {
	out := &equalizer{
		streamer: s,
	}

	for _, s := range sections {
		beta := math.Tan(s.Bf/2.0*math.Pi/(fs/2.0)) *
			math.Sqrt(math.Abs(math.Pow(math.Pow(10, s.GB/20.0), 2.0)-
				math.Pow(math.Pow(10.0, s.G0/20.0), 2.0))) /
			math.Sqrt(math.Abs(math.Pow(math.Pow(10.0, s.G/20.0), 2.0)-
				math.Pow(math.Pow(10.0, s.GB/20.0), 2.0)))

		b := []float64{
			(math.Pow(10.0, s.G0/20.0) + math.Pow(10.0, s.G/20.0)*beta) / (1 + beta),
			(-2 * math.Pow(10.0, s.G0/20.0) * math.Cos(s.F0*math.Pi/(fs/2.0))) / (1 + beta),
			(math.Pow(10.0, s.G0/20) - math.Pow(10.0, s.G/20.0)*beta) / (1 + beta),
		}

		a := []float64{
			1.0,
			-2 * math.Cos(s.F0*math.Pi/(fs/2.0)) / (1 + beta),
			(1 - beta) / (1 + beta),
		}
		out.sections = append(out.sections, section{a: a, b: b})
	}
	return out
}

// Stream streams the wrapped Streamer modified by Equalizer.
func (e *equalizer) Stream(samples [][2]float64) (n int, ok bool) {
	n, ok = e.streamer.Stream(samples)
	for _, s := range e.sections {
		copy(samples, s.apply(samples))
	}
	return n, ok
}

// Err propagates the wrapped Streamer's errors.
func (e *equalizer) Err() error {
	return e.streamer.Err()
}
<commit_msg>use beep.SampleRate<commit_after>package effects

import (
	"math"

	"github.com/faiface/beep"
)

type (

	// This parametric equalizer is based on the GK Nilsen's post at:
	// https://octovoid.com/2017/11/04/coding-a-parametric-equalizer-for-audio-applications/
	equalizer struct {
		streamer beep.Streamer
		sections []section
	}

	section struct {
		a, b         []float64
		xPast, yPast [][2]float64
	}

	EqualizerSection struct {
		// F0 (center frequency) sets the mid-point of the section’s
		// frequency range and is given in Hertz [Hz].
		F0 float64

		// Bf (bandwidth) represents the width of the section across
		// frequency and is measured in Hertz [Hz]. A low bandwidth
		// corresponds to a narrow frequency range meaning that the
		// section will concentrate its operation to only the
		// frequencies close to the center frequency. On the other hand,
		// a high bandwidth yields a section of wide frequency range —
		// affecting a broader range of frequencies surrounding the
		// center frequency.
		Bf float64

		// GB (bandwidth gain) is given in decibels [dB] and represents
		// the level at which the bandwidth is measured. That is, to
		// have a meaningful measure of bandwidth, we must define the
		// level at which it is measured.
		GB float64

		// G0 (reference gain) is given in decibels [dB] and simply
		// represents the level of the section’s offset.
		G0 float64

		// G (boost/cut gain) is given in decibels [dB] and prescribes
		// the effect imposed on the audio loudness for the section’s
		// frequency range. A boost/cut level of 0 dB corresponds to
		// unity (no operation), whereas negative numbers corresponds to
		// cut (volume down) and positive numbers to boost (volume up).
		G float64
	}
)

func (s *section) apply(x [][2]float64) [][2]float64 {
	ord := len(s.a) - 1
	np := len(x) - 1

	if np < ord {
		x = append(x, make([][2]float64, ord-np)...)
		np = ord
	}

	y := make([][2]float64, len(x))

	if len(s.xPast) == 0 {
		s.xPast = make([][2]float64, len(x))
	}

	if len(s.yPast) == 0 {
		s.yPast = make([][2]float64, len(x))
	}

	for i := 0; i < len(x); i++ {
		for j := 0; j < ord+1; j++ {
			if i-j < 0 {
				y[i][0] = y[i][0] + s.b[j]*s.xPast[len(s.xPast)-j][0]
				y[i][1] = y[i][1] + s.b[j]*s.xPast[len(s.xPast)-j][1]
			} else {
				y[i][0] = y[i][0] + s.b[j]*x[i-j][0]
				y[i][1] = y[i][1] + s.b[j]*x[i-j][1]
			}
		}

		for j := 0; j < ord; j++ {
			if i-j-1 < 0 {
				y[i][0] = y[i][0] - s.a[j+1]*s.yPast[len(s.yPast)-j-1][0]
				y[i][1] = y[i][1] - s.a[j+1]*s.yPast[len(s.yPast)-j-1][1]
			} else {
				y[i][0] = y[i][0] - s.a[j+1]*y[i-j-1][0]
				y[i][1] = y[i][1] - s.a[j+1]*y[i-j-1][1]
			}

			y[i][0] = y[i][0] / s.a[0]
			y[i][1] = y[i][1] / s.a[0]
		}
	}

	s.xPast = x
	s.yPast = y
	return y
}

// NewEqualizer returns a beep.Streamer that modifies the stream based on the EqualizerSection slice that is passed in.
// The SampleRate (sr) must match that of the Streamer.
func NewEqualizer(s beep.Streamer, sr beep.SampleRate, sections []EqualizerSection) beep.Streamer {
	fs := float64(sr)
	out := &equalizer{
		streamer: s,
	}

	for _, s := range sections {
		beta := math.Tan(s.Bf/2.0*math.Pi/(fs/2.0)) *
			math.Sqrt(math.Abs(math.Pow(math.Pow(10, s.GB/20.0), 2.0)-
				math.Pow(math.Pow(10.0, s.G0/20.0), 2.0))) /
			math.Sqrt(math.Abs(math.Pow(math.Pow(10.0, s.G/20.0), 2.0)-
				math.Pow(math.Pow(10.0, s.GB/20.0), 2.0)))

		b := []float64{
			(math.Pow(10.0, s.G0/20.0) + math.Pow(10.0, s.G/20.0)*beta) / (1 + beta),
			(-2 * math.Pow(10.0, s.G0/20.0) * math.Cos(s.F0*math.Pi/(fs/2.0))) / (1 + beta),
			(math.Pow(10.0, s.G0/20) - math.Pow(10.0, s.G/20.0)*beta) / (1 + beta),
		}

		a := []float64{
			1.0,
			-2 * math.Cos(s.F0*math.Pi/(fs/2.0)) / (1 + beta),
			(1 - beta) / (1 + beta),
		}
		out.sections = append(out.sections, section{a: a, b: b})
	}
	return out
}

// Stream streams the wrapped Streamer modified by Equalizer.
func (e *equalizer) Stream(samples [][2]float64) (n int, ok bool) {
	n, ok = e.streamer.Stream(samples)
	for _, s := range e.sections {
		copy(samples, s.apply(samples))
	}
	return n, ok
}

// Err propagates the wrapped Streamer's errors.
func (e *equalizer) Err() error {
	return e.streamer.Err()
}
<|endoftext|>


<commit_before>package services

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"

	datatypes "github.com/maximilien/softlayer-go/data_types"
	softlayer "github.com/maximilien/softlayer-go/softlayer"
)

type softLayer_Ssh_Key_Service struct {
	client softlayer.Client
}

func NewSoftLayer_Ssh_Key_Service(client softlayer.Client) *softLayer_Ssh_Key_Service {
	return &softLayer_Ssh_Key_Service{
		client: client,
	}
}

func (slsks *softLayer_Ssh_Key_Service) GetName() string {
	return "SoftLayer_Security_Ssh_Key"
}

func (slsks *softLayer_Ssh_Key_Service) CreateObject(template datatypes.SoftLayer_Ssh_Key) (datatypes.SoftLayer_Ssh_Key, error) {
	parameters := datatypes.SoftLayer_Shh_Key_Parameters{
		Parameters: []datatypes.SoftLayer_Ssh_Key{
			template,
		},
	}

	requestBody, err := json.Marshal(parameters)
	if err != nil {
		return datatypes.SoftLayer_Ssh_Key{}, err
	}

	data, err := slsks.client.DoRawHttpRequest(fmt.Sprintf("%s/createObject", slsks.GetName()), "POST", bytes.NewBuffer(requestBody))
	if err != nil {
		return datatypes.SoftLayer_Ssh_Key{}, err
	}

	err = slsks.client.CheckForHttpResponseErrors(data)
	if err != nil {
		return datatypes.SoftLayer_Ssh_Key{}, err
	}

	softLayer_Ssh_Key := datatypes.SoftLayer_Ssh_Key{}
	err = json.Unmarshal(data, &softLayer_Ssh_Key)
	if err != nil {
		return datatypes.SoftLayer_Ssh_Key{}, err
	}

	return softLayer_Ssh_Key, nil
}

func (slsks *softLayer_Ssh_Key_Service) DeleteObject(sshKeyId int) (bool, error) {
	response, err := slsks.client.DoRawHttpRequest(fmt.Sprintf("SoftLayer_Ssh_Key/%d.json", sshKeyId), "DELETE", new(bytes.Buffer))

	if res := string(response[:]); res != "true" {
		return false, errors.New(fmt.Sprintf("Failed to destroy and instance wit id '%d', got '%s' as response from the API.", sshKeyId, res))
	}

	return true, err
}
<commit_msg>correct name for SL_Ssh_Key service as Security_Ssh_Key<commit_after>package services

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"

	datatypes "github.com/maximilien/softlayer-go/data_types"
	softlayer "github.com/maximilien/softlayer-go/softlayer"
)

type softLayer_Ssh_Key_Service struct {
	client softlayer.Client
}

func NewSoftLayer_Ssh_Key_Service(client softlayer.Client) *softLayer_Ssh_Key_Service {
	return &softLayer_Ssh_Key_Service{
		client: client,
	}
}

func (slsks *softLayer_Ssh_Key_Service) GetName() string {
	return "SoftLayer_Security_Ssh_Key"
}

func (slsks *softLayer_Ssh_Key_Service) CreateObject(template datatypes.SoftLayer_Ssh_Key) (datatypes.SoftLayer_Ssh_Key, error) {
	parameters := datatypes.SoftLayer_Shh_Key_Parameters{
		Parameters: []datatypes.SoftLayer_Ssh_Key{
			template,
		},
	}

	requestBody, err := json.Marshal(parameters)
	if err != nil {
		return datatypes.SoftLayer_Ssh_Key{}, err
	}

	data, err := slsks.client.DoRawHttpRequest(fmt.Sprintf("%s/createObject", slsks.GetName()), "POST", bytes.NewBuffer(requestBody))
	if err != nil {
		return datatypes.SoftLayer_Ssh_Key{}, err
	}

	err = slsks.client.CheckForHttpResponseErrors(data)
	if err != nil {
		return datatypes.SoftLayer_Ssh_Key{}, err
	}

	softLayer_Ssh_Key := datatypes.SoftLayer_Ssh_Key{}
	err = json.Unmarshal(data, &softLayer_Ssh_Key)
	if err != nil {
		return datatypes.SoftLayer_Ssh_Key{}, err
	}

	return softLayer_Ssh_Key, nil
}

func (slsks *softLayer_Ssh_Key_Service) DeleteObject(sshKeyId int) (bool, error) {
	response, err := slsks.client.DoRawHttpRequest(fmt.Sprintf("%s/%d.json", slsks.GetName(), sshKeyId), "DELETE", new(bytes.Buffer))

	if res := string(response[:]); res != "true" {
		return false, errors.New(fmt.Sprintf("Failed to destroy ssh key with id '%d', got '%s' as response from the API.", sshKeyId, res))
	}

	return true, err
}
<|endoftext|>


<commit_before>package exec

import (
	"fmt"
	"strings"

	u "github.com/araddon/gou"

	"github.com/araddon/qlbridge/datasource"
	"github.com/araddon/qlbridge/datasource/membtree"
	"github.com/araddon/qlbridge/expr"
	"github.com/araddon/qlbridge/plan"
	"github.com/araddon/qlbridge/value"
)

const (
	MaxAllowedPacket = 1024 * 1024
)

func (m *JobBuilder) VisitSelect(stmt *expr.SqlSelect) (expr.Task, expr.VisitStatus, error) {

	//u.Debugf("VisitSelect %+v", stmt)

	tasks := make(Tasks, 0)

	if len(stmt.From) == 0 {
		if stmt.SystemQry() {
			return m.VisitSelectSystemInfo(stmt)
		}
		u.Warnf("no from? %v", stmt.String())
		return nil, expr.VisitError, fmt.Errorf("No From for %v", stmt.String())

	} else if len(stmt.From) == 1 {

		stmt.From[0].Source = stmt
		srcPlan, err := plan.NewSourcePlan(m.Conf, stmt.From[0], true)
		if err != nil {
			return nil, expr.VisitError, err
		}
		task, status, err := m.VisitSourceSelect(srcPlan)
		if err != nil {
			return nil, status, err
		}
		if status == expr.VisitFinal {
			u.Debugf("subselect visit final returning job.proj: %p", m.Projection)
			return task, status, nil
		}
		tasks.Add(task.(TaskRunner))

		// Add a Final Projection to choose the columns for results
		projection := NewProjectionFinal(stmt)
		//u.Infof("adding projection: %#v", projection)
		tasks.Add(projection)

		return NewSequential("select", tasks), expr.VisitContinue, nil

	} else {

		var prevTask TaskRunner
		var prevFrom *expr.SqlSource

		for i, from := range stmt.From {

			// Need to rewrite the From statement
			from.Rewrite(stmt)
			srcPlan, err := plan.NewSourcePlan(m.Conf, from, false)
			if err != nil {
				return nil, expr.VisitError, err
			}
			sourceTask, status, err := m.VisitSourceSelect(srcPlan)
			if err != nil {
				u.Errorf("Could not visitsubselect %v  %s", err, from)
				return nil, status, err
			}

			// now fold into previous task
			curTask := sourceTask.(TaskRunner)
			if i != 0 {
				from.Seekable = true
				twoTasks := []TaskRunner{prevTask, curTask}
				curMergeTask := NewTaskParallel("select-sources", nil, twoTasks)
				tasks.Add(curMergeTask)

				// fold this source into previous
				in, err := NewJoinNaiveMerge(prevTask, curTask, prevFrom, from, m.Conf)
				if err != nil {
					return nil, expr.VisitError, err
				}
				tasks.Add(in)
			}
			prevTask = curTask
			prevFrom = from
			//u.Debugf("got task: %T", prevTask)
		}
	}

	if stmt.Where != nil {
		switch {
		case stmt.Where.Source != nil:
			u.Warnf("Found un-supported subquery: %#v", stmt.Where)
			return nil, expr.VisitError, fmt.Errorf("Unsupported Where Type")
		case stmt.Where.Expr != nil:
			//u.Debugf("adding where: %q", stmt.Where.Expr)
			where := NewWhereFinal(stmt.Where.Expr, stmt)
			tasks.Add(where)
		default:
			u.Warnf("Found un-supported where type: %#v", stmt.Where)
			return nil, expr.VisitError, fmt.Errorf("Unsupported Where Type")
		}

	}

	// Add a Final Projection to choose the columns for results
	projection := NewProjectionFinal(stmt)
	m.Projection = nil
	u.Debugf("exec.projection: %p added  %s", projection, stmt.String())
	tasks.Add(projection)

	return NewSequential("select", tasks), expr.VisitContinue, nil
}

// Build Column Name to Position index for given *source* (from) used to interpret
// positional []driver.Value args, mutate the *from* itself to hold this map
func buildColIndex(colSchema datasource.SchemaColumns, sp *plan.SourcePlan) error {
	if sp.Source == nil {
		u.Errorf("Couldnot build colindex bc no source %#v", sp)
		return nil
	}
	sp.BuildColIndex(colSchema.Columns())
	return nil
}

func (m *JobBuilder) VisitSourceSelect(sp *plan.SourcePlan) (expr.Task, expr.VisitStatus, error) {

	if sp.Source != nil {
		u.Debugf("VisitSubselect from.source = %q", sp.Source)
	} else {
		u.Debugf("VisitSubselect from=%q", sp)
	}

	tasks := make(Tasks, 0)
	needsJoinKey := false
	from := sp.SqlSource

	source, err := sp.DataSource.DataSource.Open(sp.SourceName())
	if err != nil {
		return nil, expr.VisitError, err
	}
	if sp.Source != nil && len(sp.JoinNodes()) > 0 {
		needsJoinKey = true
	}

	sourcePlan, implementsSourceBuilder := source.(plan.SourceSelectPlanner)
	//u.Debugf("source: tbl:%q  Builder?%v   %T  %#v", from.SourceName(), implementsSourceBuilder, source, source)
	// Must provider either Scanner, SourcePlanner, Seeker interfaces
	if implementsSourceBuilder {

		task, status, err := sourcePlan.VisitSourceSelect(sp)
		if err != nil {
			// PolyFill instead?
			return nil, status, err
		}
		if status == expr.VisitFinal {

			//m.Projection, _ = sourcePlan.Projection()
			tasks.Add(task.(TaskRunner))

			if needsJoinKey {
				if schemaCols, ok := sourcePlan.(datasource.SchemaColumns); ok {
					u.Warnf("schemaCols: %T  ", schemaCols)
					if err := buildColIndex(schemaCols, sp); err != nil {
						return nil, expr.VisitError, err
					}
				} else {
					u.Errorf("Didn't implement schema task: %T source: %T", task, sourcePlan)
				}

				joinKeyTask, err := NewJoinKey(sp.SqlSource, m.Conf)
				if err != nil {
					return nil, expr.VisitError, err
				}
				tasks.Add(joinKeyTask)
			}
			return NewSequential("sub-select", tasks), status, nil
			//return task, status, nil
		}
		if task != nil {
			//u.Infof("found task?")
			//tasks.Add(task)
			//return NewSequential("source-planner", tasks), nil
			return task, expr.VisitContinue, nil
		}
		u.Errorf("Could not source plan for %v  %T %#v", from.SourceName(), source, source)
	}
	scanner, hasScanner := source.(datasource.Scanner)
	if !hasScanner {
		u.Warnf("source %T does not implement datasource.Scanner", source)
		return nil, expr.VisitError, fmt.Errorf("%T Must Implement Scanner for %q", source, from.String())
	}

	switch {

	case needsJoinKey: //from.Source != nil && len(from.JoinNodes()) > 0:
		// This is a source that is part of a join expression
		if err := buildColIndex(scanner, sp); err != nil {
			return nil, expr.VisitError, err
		}
		sourceTask := NewSourceJoin(from, scanner)
		tasks.Add(sourceTask)

	default:
		// If we have table name and no Source(sub-query/join-query) then just read source
		if err := buildColIndex(scanner, sp); err != nil {
			return nil, expr.VisitError, err
		}
		sourceTask := NewSource(sp.SqlSource, scanner)
		tasks.Add(sourceTask)

	}

	if from.Source != nil && from.Source.Where != nil {
		switch {
		case from.Source.Where.Expr != nil:
			//u.Debugf("adding where: %q", from.Source.Where.Expr)
			where := NewWhereFilter(from.Source.Where.Expr, from.Source)
			tasks.Add(where)
		default:
			u.Warnf("Found un-supported where type: %#v", from.Source)
			return nil, expr.VisitError, fmt.Errorf("Unsupported Where clause:  %q", from)
		}
	}

	// Add a Non-Final Projection to choose the columns for results
	if !sp.Final {
		projection := NewProjectionInProcess(from.Source)
		u.Debugf("source projection: %p added  %s", projection, from.Source.String())
		tasks.Add(projection)
	}

	if needsJoinKey {
		joinKeyTask, err := NewJoinKey(from, m.Conf)
		if err != nil {
			return nil, expr.VisitError, err
		}
		tasks.Add(joinKeyTask)
	}

	// TODO: projection, groupby, having
	// Plan?   Parallel?  hash?
	return NewSequential("sub-select", tasks), expr.VisitContinue, nil
}

// queries for internal schema/variables such as:
//
//    select @@max_allowed_packets
//    select current_user()
//    select connection_id()
//    select timediff(curtime(), utc_time())
//
func (m *JobBuilder) VisitSelectSystemInfo(stmt *expr.SqlSelect) (expr.Task, expr.VisitStatus, error) {

	//u.Debugf("VisitSelectSchemaInfo %+v", stmt)

	if stmt.IsSysQuery() {
		return m.VisitSysQuery(stmt)
	} else if len(stmt.From) == 0 && len(stmt.Columns) == 1 && strings.ToLower(stmt.Columns[0].As) == "database" {
		return m.VisitSelectDatabase(stmt)
	}

	tasks := make(Tasks, 0)

	srcPlan, err := plan.NewSourcePlan(m.Conf, stmt.From[0], true)
	if err != nil {
		return nil, expr.VisitError, err
	}
	task, status, err := m.VisitSourceSelect(srcPlan)
	if err != nil {
		return nil, expr.VisitError, err
	}
	if status == expr.VisitFinal {
		return task, status, nil
	}
	tasks.Add(task.(TaskRunner))

	if stmt.Where != nil {
		switch {
		case stmt.Where.Source != nil:
			u.Warnf("Found un-supported subquery: %#v", stmt.Where)
			return nil, expr.VisitError, fmt.Errorf("Unsupported Where Type")
		case stmt.Where.Expr != nil:
			//u.Debugf("adding where: %q", stmt.Where.Expr)
			where := NewWhereFinal(stmt.Where.Expr, stmt)
			tasks.Add(where)
		default:
			u.Warnf("Found un-supported where type: %#v", stmt.Where)
			return nil, expr.VisitError, fmt.Errorf("Unsupported Where Type")
		}

	}

	// Add a Projection to choose the columns for results
	projection := NewProjectionInProcess(stmt)
	//u.Infof("adding projection: %#v", projection)
	tasks.Add(projection)

	return NewSequential("select-schemainfo", tasks), expr.VisitContinue, nil
}

func (m *JobBuilder) VisitSelectDatabase(stmt *expr.SqlSelect) (expr.Task, expr.VisitStatus, error) {
	//u.Debugf("VisitSelectDatabase %+v", stmt)

	tasks := make(Tasks, 0)
	val := m.connInfo
	static := membtree.NewStaticDataValue(val, "database")
	sourceTask := NewSource(nil, static)
	tasks.Add(sourceTask)
	m.Projection = StaticProjection("database", value.StringType)
	return NewSequential("database", tasks), expr.VisitContinue, nil
}

func (m *JobBuilder) VisitSysQuery(stmt *expr.SqlSelect) (expr.Task, expr.VisitStatus, error) {
	//u.Debugf("VisitSysVariable %+v", stmt)

	p := expr.NewProjection()

	for _, col := range stmt.Columns {
		if col.Expr == nil {
			return nil, expr.VisitError, fmt.Errorf("no column info? %#v", col.Expr)
		}
		switch n := col.Expr.(type) {
		case *expr.IdentityNode:
			coln := strings.ToLower(n.Text)
			if strings.HasPrefix(coln, "@@") {
				u.Debugf("m.Ctx? %#v", m.Ctx)
				u.Debugf("m.Ctx.Session? %#v", m.Ctx.Session)
				val, ok := m.Ctx.Session.Get(coln)
				if ok {
					p.AddColumnShort(coln, val.Type())
				} else {
					p.AddColumnShort(coln, value.NilType)
				}

			}
			// SELECT current_user
		case *expr.FuncNode:
			// SELECT current_user()
			// n.String()
		}
	}
	m.Projection = plan.NewProjectionStatic(p)

	//u.Errorf("unknown var: %v", sysVar)
	return nil, expr.VisitError, fmt.Errorf("Unrecognized System Variable: %v", sysVar)

	col1 := "fake"
	switch sysVar := strings.ToLower(col1); sysVar {
	case "@@max_allowed_packet":
		//u.Infof("max allowed")
		m.Projection = StaticProjection("@@max_allowed_packet", value.IntType)
		return m.sysVarTasks(sysVar, MaxAllowedPacket)
	case "current_user()", "current_user":
		return m.sysVarTasks(sysVar, "user")
	case "connection_id()":
		return m.sysVarTasks(sysVar, 1)
	case "timediff(curtime(), utc_time())":
		return m.sysVarTasks("timediff", "00:00:00.000000")
		//
	default:
		u.Errorf("unknown var: %v", sysVar)
		return nil, expr.VisitError, fmt.Errorf("Unrecognized System Variable: %v", sysVar)
	}
}

// A very simple tasks/builder for system variables
//
func (m *JobBuilder) sysVarTasks(name string, val interface{}) (expr.Task, expr.VisitStatus, error) {
	tasks := make(Tasks, 0)
	static := membtree.NewStaticDataValue(name, val)
	sourceTask := NewSource(nil, static)
	tasks.Add(sourceTask)
	switch val.(type) {
	case int, int64:
		m.Projection = StaticProjection(name, value.IntType)
	case string:
		m.Projection = StaticProjection(name, value.StringType)
	case float32, float64:
		m.Projection = StaticProjection(name, value.NumberType)
	case bool:
		m.Projection = StaticProjection(name, value.BoolType)
	default:
		u.Errorf("unknown var: %v", val)
		return nil, expr.VisitError, fmt.Errorf("Unrecognized Data Type: %v", val)
	}
	return NewSequential("sys-var", tasks), expr.VisitContinue, nil
}

// A very simple projection of name=value, for single row/column
//   select @@max_bytes
//
func StaticProjection(name string, vt value.ValueType) *plan.Projection {
	p := expr.NewProjection()
	p.AddColumnShort(name, vt)
	return plan.NewProjectionStatic(p)
}
<commit_msg>schema query<commit_after>package exec

import (
	"fmt"
	"strings"

	u "github.com/araddon/gou"

	"github.com/araddon/qlbridge/datasource"
	"github.com/araddon/qlbridge/datasource/membtree"
	"github.com/araddon/qlbridge/expr"
	"github.com/araddon/qlbridge/plan"
	"github.com/araddon/qlbridge/value"
)

const (
	MaxAllowedPacket = 1024 * 1024
)

func (m *JobBuilder) VisitSelect(stmt *expr.SqlSelect) (expr.Task, expr.VisitStatus, error) {

	//u.Debugf("VisitSelect %+v", stmt)

	tasks := make(Tasks, 0)

	if len(stmt.From) == 0 {
		if stmt.SystemQry() {
			return m.VisitSelectSystemInfo(stmt)
		}
		u.Warnf("no from? %v", stmt.String())
		return nil, expr.VisitError, fmt.Errorf("No From for %v", stmt.String())

	} else if len(stmt.From) == 1 {

		stmt.From[0].Source = stmt
		srcPlan, err := plan.NewSourcePlan(m.Conf, stmt.From[0], true)
		if err != nil {
			return nil, expr.VisitError, err
		}
		task, status, err := m.VisitSourceSelect(srcPlan)
		if err != nil {
			return nil, status, err
		}
		if status == expr.VisitFinal {
			u.Debugf("subselect visit final returning job.proj: %p", m.Projection)
			return task, status, nil
		}
		tasks.Add(task.(TaskRunner))

		// Add a Final Projection to choose the columns for results
		projection := NewProjectionFinal(stmt)
		//u.Infof("adding projection: %#v", projection)
		tasks.Add(projection)

		return NewSequential("select", tasks), expr.VisitContinue, nil

	} else {

		var prevTask TaskRunner
		var prevFrom *expr.SqlSource

		for i, from := range stmt.From {

			// Need to rewrite the From statement
			from.Rewrite(stmt)
			srcPlan, err := plan.NewSourcePlan(m.Conf, from, false)
			if err != nil {
				return nil, expr.VisitError, err
			}
			sourceTask, status, err := m.VisitSourceSelect(srcPlan)
			if err != nil {
				u.Errorf("Could not visitsubselect %v  %s", err, from)
				return nil, status, err
			}

			// now fold into previous task
			curTask := sourceTask.(TaskRunner)
			if i != 0 {
				from.Seekable = true
				twoTasks := []TaskRunner{prevTask, curTask}
				curMergeTask := NewTaskParallel("select-sources", nil, twoTasks)
				tasks.Add(curMergeTask)

				// fold this source into previous
				in, err := NewJoinNaiveMerge(prevTask, curTask, prevFrom, from, m.Conf)
				if err != nil {
					return nil, expr.VisitError, err
				}
				tasks.Add(in)
			}
			prevTask = curTask
			prevFrom = from
			//u.Debugf("got task: %T", prevTask)
		}
	}

	if stmt.Where != nil {
		switch {
		case stmt.Where.Source != nil:
			u.Warnf("Found un-supported subquery: %#v", stmt.Where)
			return nil, expr.VisitError, fmt.Errorf("Unsupported Where Type")
		case stmt.Where.Expr != nil:
			//u.Debugf("adding where: %q", stmt.Where.Expr)
			where := NewWhereFinal(stmt.Where.Expr, stmt)
			tasks.Add(where)
		default:
			u.Warnf("Found un-supported where type: %#v", stmt.Where)
			return nil, expr.VisitError, fmt.Errorf("Unsupported Where Type")
		}

	}

	// Add a Final Projection to choose the columns for results
	projection := NewProjectionFinal(stmt)
	m.Projection = nil
	u.Debugf("exec.projection: %p added  %s", projection, stmt.String())
	tasks.Add(projection)

	return NewSequential("select", tasks), expr.VisitContinue, nil
}

// Build Column Name to Position index for given *source* (from) used to interpret
// positional []driver.Value args, mutate the *from* itself to hold this map
func buildColIndex(colSchema datasource.SchemaColumns, sp *plan.SourcePlan) error {
	if sp.Source == nil {
		u.Errorf("Couldnot build colindex bc no source %#v", sp)
		return nil
	}
	sp.BuildColIndex(colSchema.Columns())
	return nil
}

func (m *JobBuilder) VisitSourceSelect(sp *plan.SourcePlan) (expr.Task, expr.VisitStatus, error) {

	if sp.Source != nil {
		u.Debugf("VisitSubselect from.source = %q", sp.Source)
	} else {
		u.Debugf("VisitSubselect from=%q", sp)
	}

	tasks := make(Tasks, 0)
	needsJoinKey := false
	from := sp.SqlSource

	source, err := sp.DataSource.DataSource.Open(sp.SourceName())
	if err != nil {
		return nil, expr.VisitError, err
	}
	if sp.Source != nil && len(sp.JoinNodes()) > 0 {
		needsJoinKey = true
	}

	sourcePlan, implementsSourceBuilder := source.(plan.SourceSelectPlanner)
	//u.Debugf("source: tbl:%q  Builder?%v   %T  %#v", from.SourceName(), implementsSourceBuilder, source, source)
	// Must provider either Scanner, SourcePlanner, Seeker interfaces
	if implementsSourceBuilder {

		task, status, err := sourcePlan.VisitSourceSelect(sp)
		if err != nil {
			// PolyFill instead?
			return nil, status, err
		}
		if status == expr.VisitFinal {

			//m.Projection, _ = sourcePlan.Projection()
			tasks.Add(task.(TaskRunner))

			if needsJoinKey {
				if schemaCols, ok := sourcePlan.(datasource.SchemaColumns); ok {
					u.Warnf("schemaCols: %T  ", schemaCols)
					if err := buildColIndex(schemaCols, sp); err != nil {
						return nil, expr.VisitError, err
					}
				} else {
					u.Errorf("Didn't implement schema task: %T source: %T", task, sourcePlan)
				}

				joinKeyTask, err := NewJoinKey(sp.SqlSource, m.Conf)
				if err != nil {
					return nil, expr.VisitError, err
				}
				tasks.Add(joinKeyTask)
			}
			return NewSequential("sub-select", tasks), status, nil
			//return task, status, nil
		}
		if task != nil {
			//u.Infof("found task?")
			//tasks.Add(task)
			//return NewSequential("source-planner", tasks), nil
			return task, expr.VisitContinue, nil
		}
		u.Errorf("Could not source plan for %v  %T %#v", from.SourceName(), source, source)
	}
	scanner, hasScanner := source.(datasource.Scanner)
	if !hasScanner {
		u.Warnf("source %T does not implement datasource.Scanner", source)
		return nil, expr.VisitError, fmt.Errorf("%T Must Implement Scanner for %q", source, from.String())
	}

	switch {

	case needsJoinKey: //from.Source != nil && len(from.JoinNodes()) > 0:
		// This is a source that is part of a join expression
		if err := buildColIndex(scanner, sp); err != nil {
			return nil, expr.VisitError, err
		}
		sourceTask := NewSourceJoin(from, scanner)
		tasks.Add(sourceTask)

	default:
		// If we have table name and no Source(sub-query/join-query) then just read source
		if err := buildColIndex(scanner, sp); err != nil {
			return nil, expr.VisitError, err
		}
		sourceTask := NewSource(sp.SqlSource, scanner)
		tasks.Add(sourceTask)

	}

	if from.Source != nil && from.Source.Where != nil {
		switch {
		case from.Source.Where.Expr != nil:
			//u.Debugf("adding where: %q", from.Source.Where.Expr)
			where := NewWhereFilter(from.Source.Where.Expr, from.Source)
			tasks.Add(where)
		default:
			u.Warnf("Found un-supported where type: %#v", from.Source)
			return nil, expr.VisitError, fmt.Errorf("Unsupported Where clause:  %q", from)
		}
	}

	// Add a Non-Final Projection to choose the columns for results
	if !sp.Final {
		projection := NewProjectionInProcess(from.Source)
		u.Debugf("source projection: %p added  %s", projection, from.Source.String())
		tasks.Add(projection)
	}

	if needsJoinKey {
		joinKeyTask, err := NewJoinKey(from, m.Conf)
		if err != nil {
			return nil, expr.VisitError, err
		}
		tasks.Add(joinKeyTask)
	}

	// TODO: projection, groupby, having
	// Plan?   Parallel?  hash?
	return NewSequential("sub-select", tasks), expr.VisitContinue, nil
}

// queries for internal schema/variables such as:
//
//    select @@max_allowed_packets
//    select current_user()
//    select connection_id()
//    select timediff(curtime(), utc_time())
//
func (m *JobBuilder) VisitSelectSystemInfo(stmt *expr.SqlSelect) (expr.Task, expr.VisitStatus, error) {

	//u.Debugf("VisitSelectSchemaInfo %+v", stmt)

	if stmt.IsSysQuery() {
		return m.VisitSysQuery(stmt)
	} else if len(stmt.From) == 0 && len(stmt.Columns) == 1 && strings.ToLower(stmt.Columns[0].As) == "database" {
		return m.VisitSelectDatabase(stmt)
	}

	tasks := make(Tasks, 0)

	srcPlan, err := plan.NewSourcePlan(m.Conf, stmt.From[0], true)
	if err != nil {
		return nil, expr.VisitError, err
	}
	task, status, err := m.VisitSourceSelect(srcPlan)
	if err != nil {
		return nil, expr.VisitError, err
	}
	if status == expr.VisitFinal {
		return task, status, nil
	}
	tasks.Add(task.(TaskRunner))

	if stmt.Where != nil {
		switch {
		case stmt.Where.Source != nil:
			u.Warnf("Found un-supported subquery: %#v", stmt.Where)
			return nil, expr.VisitError, fmt.Errorf("Unsupported Where Type")
		case stmt.Where.Expr != nil:
			//u.Debugf("adding where: %q", stmt.Where.Expr)
			where := NewWhereFinal(stmt.Where.Expr, stmt)
			tasks.Add(where)
		default:
			u.Warnf("Found un-supported where type: %#v", stmt.Where)
			return nil, expr.VisitError, fmt.Errorf("Unsupported Where Type")
		}

	}

	// Add a Projection to choose the columns for results
	projection := NewProjectionInProcess(stmt)
	//u.Infof("adding projection: %#v", projection)
	tasks.Add(projection)

	return NewSequential("select-schemainfo", tasks), expr.VisitContinue, nil
}

func (m *JobBuilder) VisitSelectDatabase(stmt *expr.SqlSelect) (expr.Task, expr.VisitStatus, error) {
	//u.Debugf("VisitSelectDatabase %+v", stmt)

	tasks := make(Tasks, 0)
	val := m.connInfo
	static := membtree.NewStaticDataValue(val, "database")
	sourceTask := NewSource(nil, static)
	tasks.Add(sourceTask)
	m.Projection = StaticProjection("database", value.StringType)
	return NewSequential("database", tasks), expr.VisitContinue, nil
}

func (m *JobBuilder) VisitSysQuery(stmt *expr.SqlSelect) (expr.Task, expr.VisitStatus, error) {
	//u.Debugf("VisitSysVariable %+v", stmt)

	static := membtree.NewStaticData("schema")

	p := expr.NewProjection()
	cols := make([]string, len(stmt.Columns))
	for i, col := range stmt.Columns {
		if col.Expr == nil {
			return nil, expr.VisitError, fmt.Errorf("no column info? %#v", col.Expr)
		}
		switch n := col.Expr.(type) {
		case *expr.IdentityNode:
			coln := strings.ToLower(n.Text)
			cols[i] = coln
			if strings.HasPrefix(coln, "@@") {
				//u.Debugf("m.Ctx? %#v", m.Ctx)
				//u.Debugf("m.Ctx.Session? %#v", m.Ctx.Session)
				val, ok := m.Ctx.Session.Get(coln)
				u.Debugf("session? %v=%#v", coln, val)
				if ok {
					p.AddColumnShort(coln, val.Type())
					static.Put(nil, nil, val.Value())
				} else {
					p.AddColumnShort(coln, value.NilType)
				}

			}
			// SELECT current_user
		case *expr.FuncNode:
			// SELECT current_user()
			// n.String()
		}
	}
	m.Projection = plan.NewProjectionStatic(p)
	tasks := make(Tasks, 0)
	sourceTask := NewSource(nil, static)
	tasks.Add(sourceTask)
	return NewSequential("sys-var", tasks), expr.VisitContinue, nil
	//u.Errorf("unknown var: %v", sysVar)
	//return nil, expr.VisitError, fmt.Errorf("Unrecognized System Variable: ")

	col1 := "fake"
	switch sysVar := strings.ToLower(col1); sysVar {
	case "@@max_allowed_packet":
		//u.Infof("max allowed")
		m.Projection = StaticProjection("@@max_allowed_packet", value.IntType)
		return m.sysVarTasks(sysVar, MaxAllowedPacket)
	case "current_user()", "current_user":
		return m.sysVarTasks(sysVar, "user")
	case "connection_id()":
		return m.sysVarTasks(sysVar, 1)
	case "timediff(curtime(), utc_time())":
		return m.sysVarTasks("timediff", "00:00:00.000000")
		//
	default:
		u.Errorf("unknown var: %v", sysVar)
		return nil, expr.VisitError, fmt.Errorf("Unrecognized System Variable: %v", sysVar)
	}
}

// A very simple tasks/builder for system variables
//
func (m *JobBuilder) sysVarTasks(name string, val interface{}) (expr.Task, expr.VisitStatus, error) {
	tasks := make(Tasks, 0)
	static := membtree.NewStaticDataValue(name, val)
	sourceTask := NewSource(nil, static)
	tasks.Add(sourceTask)
	switch val.(type) {
	case int, int64:
		m.Projection = StaticProjection(name, value.IntType)
	case string:
		m.Projection = StaticProjection(name, value.StringType)
	case float32, float64:
		m.Projection = StaticProjection(name, value.NumberType)
	case bool:
		m.Projection = StaticProjection(name, value.BoolType)
	default:
		u.Errorf("unknown var: %v", val)
		return nil, expr.VisitError, fmt.Errorf("Unrecognized Data Type: %v", val)
	}
	return NewSequential("sys-var", tasks), expr.VisitContinue, nil
}

// A very simple projection of name=value, for single row/column
//   select @@max_bytes
//
func StaticProjection(name string, vt value.ValueType) *plan.Projection {
	p := expr.NewProjection()
	p.AddColumnShort(name, vt)
	return plan.NewProjectionStatic(p)
}
<|endoftext|>


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

package thumbnail

import (
	"fmt"
	"github.com/andreaskoch/allmark2/common/config"
	"github.com/andreaskoch/allmark2/common/logger"
	"github.com/andreaskoch/allmark2/common/route"
	"github.com/andreaskoch/allmark2/common/shutdown"
	"github.com/andreaskoch/allmark2/common/util/fsutil"
	"github.com/andreaskoch/allmark2/dataaccess"
	"github.com/andreaskoch/allmark2/services/imageconversion"
	"io"
	"path/filepath"
	"time"
)

func NewConversionService(logger logger.Logger, config config.Config, repository dataaccess.Repository) *ConversionService {

	// assemble the index file path
	indexFilePath := filepath.Join(config.MetaDataFolder(), "thumbnail.index")
	index, err := loadIndex(indexFilePath)
	if err != nil {
		logger.Debug("No thumbnail index loaded (%s). Creating a new one.", err.Error())
	}

	// prepare the target folder
	targetFolder := filepath.Join(config.MetaDataFolder(), "thumbnails")
	logger.Debug("Creating a thumbnail folder at %q.", targetFolder)
	if !fsutil.CreateDirectory(targetFolder) {
		logger.Warn("Could not create the thumbnail folder %q", targetFolder)
		return nil
	}

	// create a new conversion service
	conversionService := &ConversionService{
		logger:     logger,
		config:     config,
		repository: repository,

		isRunning: true,

		// thumbnail index
		indexFilePath: indexFilePath,
		index:         index,

		thumbnailFolder: targetFolder,
	}

	// start the conversion
	go conversionService.startConversion()

	// stop the conversion on shutdown
	shutdown.Register(func() error {
		logger.Info("Stopping the conversion process")
		conversionService.isRunning = false
		return nil
	})

	// save the index on shutdown
	shutdown.Register(func() error {
		logger.Info("Saving the index")
		return saveIndex(index, indexFilePath)
	})

	return conversionService
}

type ConversionService struct {
	logger     logger.Logger
	config     config.Config
	repository dataaccess.Repository

	isRunning bool

	indexFilePath string
	index         Index

	thumbnailFolder string
}

func (conversion *ConversionService) startConversion() {

	conversion.createThumbnails()

	updateChannel := make(chan bool, 1)
	conversion.repository.AfterReindex(updateChannel)

	// refresh control
	go func() {
		for conversion.isRunning {
			select {
			case <-updateChannel:
				conversion.logger.Debug("Refreshing thumbnails")
				conversion.createThumbnails()
			}
		}
	}()

}

func (conversion *ConversionService) createThumbnails() {
	for _, item := range conversion.repository.Items() {

		for _, file := range item.Files() {

			// create the thumbnail
			conversion.createThumbnail(file, 200, 0)
			conversion.createThumbnail(file, 400, 0)
			conversion.createThumbnail(file, 800, 0)

			// wait before processing the next image
			time.Sleep(5 * time.Second)
		}
	}
}

func (conversion *ConversionService) createThumbnail(file *dataaccess.File, maxWidth, maxHeight uint) {

	// get the mime type
	mimeType, err := file.MimeType()
	if err != nil {
		conversion.logger.Warn("Unable to detect mime type for file. Error: %s", err.Error())
		return
	}

	// check the mime type
	if !imageconversion.MimeTypeIsSupported(mimeType) {
		conversion.logger.Debug("The mime-type %q is currently not supported.", mimeType)
		return
	}

	// determine the file name
	fileExtension := imageconversion.GetFileExtensionFromMimeType(mimeType)
	filename := fmt.Sprintf("%s-%v-%v.%s", file.Id(), maxWidth, maxHeight, fileExtension)

	// assemble the full file route
	fullFileRoute, err := route.Combine(file.Parent(), file.Route())
	if err != nil {
		conversion.logger.Warn("Unable to combine routes %q and %q.", file.Parent(), file.Route())
		return
	}

	thumb := newThumb(fullFileRoute, filename, maxWidth, maxHeight)

	// check the index
	if conversion.isInIndex(thumb) {
		conversion.logger.Debug("Thumb %q already available in the index", thumb.String())
		return
	}

	// determine the file path
	filePath := filepath.Join(conversion.thumbnailFolder, filename)

	// open the target file
	target, err := fsutil.OpenFile(filePath)
	if err != nil {
		conversion.logger.Warn("Unable to detect mime type for file. Error: %s", err.Error())
		return
	}

	defer target.Close()

	// convert the image
	conversionError := file.Data(func(content io.ReadSeeker) error {
		return imageconversion.Resize(content, mimeType, maxWidth, maxHeight, target)
	})

	// handle errors
	if conversionError != nil {
		conversion.logger.Warn("Unable to create thumbnail for file %q. Error: %s", file, err.Error())
		return
	}

	// add to index
	conversion.addToIndex(thumb)
	conversion.logger.Debug("Adding Thumb %q to index", thumb.String())
}

func (conversion *ConversionService) isInIndex(thumb Thumb) bool {
	thumbs, entryExists := conversion.index[thumb.Route]
	if !entryExists {
		return false
	}

	_, thumbExists := thumbs[thumb.Dimensions.String()]
	return thumbExists
}

func (conversion *ConversionService) addToIndex(thumb Thumb) {
	thumbs, entryExists := conversion.index[thumb.Route]
	if !entryExists {
		thumbs = make(Thumbs)
	}

	thumbs[thumb.Dimensions.String()] = thumb
	conversion.index[thumb.Route] = thumbs
}
<commit_msg>Check if thumbnails exist<commit_after>// Copyright 2013 Andreas Koch. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package thumbnail

import (
	"fmt"
	"github.com/andreaskoch/allmark2/common/config"
	"github.com/andreaskoch/allmark2/common/logger"
	"github.com/andreaskoch/allmark2/common/route"
	"github.com/andreaskoch/allmark2/common/shutdown"
	"github.com/andreaskoch/allmark2/common/util/fsutil"
	"github.com/andreaskoch/allmark2/dataaccess"
	"github.com/andreaskoch/allmark2/services/imageconversion"
	"io"
	"path/filepath"
	"time"
)

func NewConversionService(logger logger.Logger, config config.Config, repository dataaccess.Repository) *ConversionService {

	// assemble the index file path
	indexFilePath := filepath.Join(config.MetaDataFolder(), "thumbnail.index")
	index, err := loadIndex(indexFilePath)
	if err != nil {
		logger.Debug("No thumbnail index loaded (%s). Creating a new one.", err.Error())
	}

	// prepare the target folder
	targetFolder := filepath.Join(config.MetaDataFolder(), "thumbnails")
	logger.Debug("Creating a thumbnail folder at %q.", targetFolder)
	if !fsutil.CreateDirectory(targetFolder) {
		logger.Warn("Could not create the thumbnail folder %q", targetFolder)
		return nil
	}

	// create a new conversion service
	conversionService := &ConversionService{
		logger:     logger,
		config:     config,
		repository: repository,

		isRunning: true,

		// thumbnail index
		indexFilePath: indexFilePath,
		index:         index,

		thumbnailFolder: targetFolder,
	}

	// start the conversion
	go conversionService.startConversion()

	// stop the conversion on shutdown
	shutdown.Register(func() error {
		logger.Info("Stopping the conversion process")
		conversionService.isRunning = false
		return nil
	})

	// save the index on shutdown
	shutdown.Register(func() error {
		logger.Info("Saving the index")
		return saveIndex(index, indexFilePath)
	})

	return conversionService
}

type ConversionService struct {
	logger     logger.Logger
	config     config.Config
	repository dataaccess.Repository

	isRunning bool

	indexFilePath string
	index         Index

	thumbnailFolder string
}

func (conversion *ConversionService) startConversion() {

	conversion.createThumbnails()

	updateChannel := make(chan bool, 1)
	conversion.repository.AfterReindex(updateChannel)

	// refresh control
	go func() {
		for conversion.isRunning {
			select {
			case <-updateChannel:
				conversion.logger.Debug("Refreshing thumbnails")
				conversion.createThumbnails()
			}
		}
	}()

}

func (conversion *ConversionService) createThumbnails() {
	for _, item := range conversion.repository.Items() {

		for _, file := range item.Files() {

			// create the thumbnail
			conversion.createThumbnail(file, 200, 0)
			conversion.createThumbnail(file, 400, 0)
			conversion.createThumbnail(file, 800, 0)

			// wait before processing the next image
			time.Sleep(5 * time.Second)
		}
	}
}

func (conversion *ConversionService) createThumbnail(file *dataaccess.File, maxWidth, maxHeight uint) {

	// get the mime type
	mimeType, err := file.MimeType()
	if err != nil {
		conversion.logger.Warn("Unable to detect mime type for file. Error: %s", err.Error())
		return
	}

	// check the mime type
	if !imageconversion.MimeTypeIsSupported(mimeType) {
		conversion.logger.Debug("The mime-type %q is currently not supported.", mimeType)
		return
	}

	// determine the file name
	fileExtension := imageconversion.GetFileExtensionFromMimeType(mimeType)
	filename := fmt.Sprintf("%s-%v-%v.%s", file.Id(), maxWidth, maxHeight, fileExtension)

	// assemble the full file route
	fullFileRoute, err := route.Combine(file.Parent(), file.Route())
	if err != nil {
		conversion.logger.Warn("Unable to combine routes %q and %q.", file.Parent(), file.Route())
		return
	}

	thumb := newThumb(fullFileRoute, filename, maxWidth, maxHeight)

	// check the index
	if conversion.isInIndex(thumb) {
		conversion.logger.Debug("Thumb %q already available in the index", thumb.String())
		return
	}

	// determine the file path
	filePath := filepath.Join(conversion.thumbnailFolder, filename)

	// open the target file
	target, err := fsutil.OpenFile(filePath)
	if err != nil {
		conversion.logger.Warn("Unable to detect mime type for file. Error: %s", err.Error())
		return
	}

	defer target.Close()

	// convert the image
	conversionError := file.Data(func(content io.ReadSeeker) error {
		return imageconversion.Resize(content, mimeType, maxWidth, maxHeight, target)
	})

	// handle errors
	if conversionError != nil {
		conversion.logger.Warn("Unable to create thumbnail for file %q. Error: %s", file, err.Error())
		return
	}

	// add to index
	conversion.addToIndex(thumb)
	conversion.logger.Debug("Adding Thumb %q to index", thumb.String())
}

func (conversion *ConversionService) isInIndex(thumb Thumb) bool {

	// check if there are thumb for the route
	thumbs, entryExists := conversion.index[thumb.Route]
	if !entryExists {
		return false
	}

	// check if there is a thumb with that dimensions
	if _, thumbExists := thumbs[thumb.Dimensions.String()]; thumbExists {
		// check if the file exists
		return fsutil.FileExists(filepath.Join(conversion.thumbnailFolder, thumb.Path))

	}

	return false
}

func (conversion *ConversionService) addToIndex(thumb Thumb) {
	thumbs, entryExists := conversion.index[thumb.Route]
	if !entryExists {
		thumbs = make(Thumbs)
	}

	thumbs[thumb.Dimensions.String()] = thumb
	conversion.index[thumb.Route] = thumbs
}
<|endoftext|>


<commit_before>// vim: ts=4 sts=4 sw=4
package executor

import (
	"sync"
)

//////////////
// Executor //
//////////////

type QuitChan chan bool

type Runer interface {
	Run(QuitChan)
}

type Executor struct {
	quitChan	QuitChan
	waitGroup	*sync.WaitGroup
}

func New() *Executor {
	return &Executor{make(QuitChan, 100), new(sync.WaitGroup)}
}

func (executor *Executor) Run(routine func(QuitChan)) func(QuitChan) {
	executor.waitGroup.Add(1)
	go func() {
		routine(executor.quitChan)
		executor.waitGroup.Done()
	}()
	// Fluent
	return routine
}

func (executor *Executor) Loop(runable Runer) Runer {
	executor.Run(func(quitChan QuitChan) {
		RunLoop: for {
			select {
				case <-quitChan:
					break RunLoop
				default:
					runable.Run(quitChan)
			}
		}
	})
	// Fluent
	return runable
}

func (executor *Executor) Wait() {
	// Wait for the WaitGroup to be entirely closed
	executor.waitGroup.Wait()
}

func (executor *Executor) Interrupt() {
	// Wait for the WaitGroup to be entirely closed,
	// then close the quitChan
	go func() {
		executor.Wait()
		close(executor.quitChan)
	}()
	defer func() {
		// Expected:
		//   (runtime.errorCString) runtime error: send on closed channel,
		// when the above goroutine has finished waiting for the WaitGroup
		recover()
	}()
	// The following loop breaks in panic when channel closed,
	// and exits the function cleanly
	for {
		executor.quitChan <- true
	}
}
<commit_msg>Safer way of closing Executor<commit_after>// vim: ts=4 sts=4 sw=4
package executor

import (
	"sync"
)

//////////////
// Executor //
//////////////

type QuitChan chan bool

type Runer interface {
	Run(QuitChan)
}

type Executor struct {
	quitChan	QuitChan
	waitGroup	*sync.WaitGroup
}

func New() *Executor {
	return &Executor{make(QuitChan), new(sync.WaitGroup)}
}

func (executor *Executor) Run(routine func(QuitChan)) func(QuitChan) {
	executor.waitGroup.Add(1)
	go func() {
		routine(executor.quitChan)
		executor.waitGroup.Done()
	}()
	// Fluent
	return routine
}

func (executor *Executor) Loop(runable Runer) Runer {
	executor.Run(func(quitChan QuitChan) {
		RunLoop: for {
			select {
				case <-quitChan:
					break RunLoop
				default:
					runable.Run(quitChan)
			}
		}
	})
	// Fluent
	return runable
}

func (executor *Executor) Wait() {
	// Wait for the WaitGroup to be entirely closed
	executor.waitGroup.Wait()
}

func (executor *Executor) Interrupt() {
	// Closing the QuitChan will unlock every receive operations on it
	close(executor.quitChan)
	// Create another one for future reuse of the Executor
	executor.quitChan = make(QuitChan)
	// Wait for the WaitGroup to be entirely closed,
	executor.Wait()
}
<|endoftext|>


<commit_before>package beachplug

import (
	"fmt"
	"html/template"
	"log"
	"net/http"
	"net/url"
	"sort"
	"time"

	"github.com/vincent-petithory/kraken/fileserver"
)

var Server fileserver.Constructor = func(root string, params fileserver.Params) fileserver.Server {
	return &server{
		root: root,
		fs:   http.Dir(root),
	}
}

type server struct {
	fs   http.FileSystem
	root string
}

func (s server) Root() string {
	return s.root
}

func (s server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path[0] != '/' {
		r.URL.Path = "/" + r.URL.Path
	}
	f, err := s.fs.Open(r.URL.Path)
	if err != nil {
		http.NotFound(w, r)
		return
	}
	defer f.Close()

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

	if !fi.IsDir() {
		http.ServeContent(w, r, fi.Name(), fi.ModTime(), f)
		return
	}
	if r.URL.Path[len(r.URL.Path)-1] != '/' {
		w.Header().Set("Location", r.URL.Path+"/")
		w.WriteHeader(http.StatusMovedPermanently)
		return
	}

	// Dir listing
	ctx := tplCtx{
		Root:        r.URL.Path,
		Files:       make(filelist, 0),
		Directories: make(dirlist, 0),
	}
	for {
		fis, err := f.Readdir(100)
		if err != nil || len(fis) == 0 {
			break
		}
		for _, fi := range fis {
			if fi.IsDir() {
				ctx.Directories = append(ctx.Directories, fi.Name())
			} else {
				f := file{fi.Name(), fi.Size(), fi.ModTime().Truncate(time.Second)}
				ctx.Files = append(ctx.Files, f)
			}
		}
	}
	if r.URL.Path != "/" {
		ctx.Directories = append(dirlist{".."}, ctx.Directories...)
	}
	ctx.NumFiles = len(ctx.Files)
	ctx.NumDirectories = len(ctx.Directories)

	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	w.WriteHeader(http.StatusOK)
	if err := tpl.Execute(w, ctx); err != nil {
		log.Print(err)
	}
}

type tplCtx struct {
	Root           string
	Files          filelist
	Directories    dirlist
	NumFiles       int
	NumDirectories int
}

type file struct {
	Name    string
	Size    int64
	ModTime time.Time
}

type dirlist []string

func (l dirlist) Less(i int, j int) bool {
	return l[i] < l[j]
}
func (l dirlist) Swap(i int, j int) { l[i], l[j] = l[j], l[i] }
func (l dirlist) Len() int          { return len(l) }

type filelist []file

func (l filelist) Less(i int, j int) bool {
	if l[i].Name == l[j].Name {
		return l[i].ModTime.Before(l[j].ModTime)
	}
	return l[i].Name < l[j].Name
}
func (l filelist) Swap(i int, j int) { l[i], l[j] = l[j], l[i] }
func (l filelist) Len() int          { return len(l) }

var fm = map[string]interface{}{
	"urlpath": func(path string) string {
		return (&url.URL{Path: path}).String()
	},
	"sorted": func(v interface{}) interface{} {
		if sv, ok := v.(sort.Interface); ok {
			sort.Sort(sv)
		}
		return v
	},
}
var tpl = template.Must(template.New("").Funcs(fm).Parse(tplstr))

var tplstr = fmt.Sprintf(`<!DOCTYPE html>

    <meta charset="utf-8">
    <title>Index on {{.Root}}</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">

{{.Root}}

  {{range sorted .Directories}}

      {{ . }}/

  {{end}}
  {{ if and .NumDirectories .NumFiles }}

  {{ end }}

    File
    Size
    Mod time

  {{range sorted .Files}}

      {{ .Name }}
      {{ .Size }}
      {{ .ModTime }}

  {{end}}

`, css)

const css = `
html {
  color: #222;
  font-size: 10px;
  font-family: Monospace;
}

hr {
  display: block;
  height: 1px;
  border: 0;
  border-top: 1px solid #ccc;
  margin: 1em 0;
  padding: 0;
}

th {
  font-weight: bold;
  text-align: left;
}
`
<commit_msg>beachplug fileserver: add a simple theme<commit_after>package beachplug

import (
	"fmt"
	"html/template"
	"log"
	"net/http"
	"net/url"
	"sort"
	"time"
	"unicode/utf8"

	"github.com/vincent-petithory/kraken/fileserver"
)

// Server defines the beachplug server constructor.
var Server fileserver.Constructor = func(root string, params fileserver.Params) fileserver.Server {
	return &server{
		root: root,
		fs:   http.Dir(root),
	}
}

type server struct {
	fs   http.FileSystem
	root string
}

func (s server) Root() string {
	return s.root
}

func (s server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path[0] != '/' {
		r.URL.Path = "/" + r.URL.Path
	}
	f, err := s.fs.Open(r.URL.Path)
	if err != nil {
		http.NotFound(w, r)
		return
	}
	defer f.Close()

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

	if !fi.IsDir() {
		http.ServeContent(w, r, fi.Name(), fi.ModTime(), f)
		return
	}
	if r.URL.Path[len(r.URL.Path)-1] != '/' {
		w.Header().Set("Location", r.URL.Path+"/")
		w.WriteHeader(http.StatusMovedPermanently)
		return
	}

	// Dir listing
	ctx := tplCtx{
		Root:        r.URL.Path,
		Style:       css,
		Files:       make(filelist, 0),
		Directories: make(dirlist, 0),
	}
	for {
		fis, err := f.Readdir(100)
		if err != nil || len(fis) == 0 {
			break
		}
		for _, fi := range fis {
			if fi.IsDir() {
				ctx.Directories = append(ctx.Directories, fi.Name())
			} else {
				f := file{fi.Name(), fi.Size(), fi.ModTime().Truncate(time.Second)}
				ctx.Files = append(ctx.Files, f)
			}
		}
	}
	if r.URL.Path != "/" {
		ctx.Directories = append(dirlist{".."}, ctx.Directories...)
	}
	ctx.NumFiles = len(ctx.Files)
	ctx.NumDirectories = len(ctx.Directories)

	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	w.WriteHeader(http.StatusOK)
	if err := tpl.Execute(w, ctx); err != nil {
		log.Print(err)
	}
}

type tplCtx struct {
	Root           string
	Style          template.CSS
	Files          filelist
	Directories    dirlist
	NumFiles       int
	NumDirectories int
}

type file struct {
	Name    string
	Size    int64
	ModTime time.Time
}

type dirlist []string

func (l dirlist) Less(i int, j int) bool {
	return l[i] < l[j]
}
func (l dirlist) Swap(i int, j int) { l[i], l[j] = l[j], l[i] }
func (l dirlist) Len() int          { return len(l) }

type filelist []file

func (l filelist) Less(i int, j int) bool {
	if l[i].Name == l[j].Name {
		return l[i].ModTime.Before(l[j].ModTime)
	}
	return l[i].Name < l[j].Name
}
func (l filelist) Swap(i int, j int) { l[i], l[j] = l[j], l[i] }
func (l filelist) Len() int          { return len(l) }

const (
	kib = 1024
	mib = 1024 * 1024
	gib = 1024 * 1024 * 1024
)

var fm = map[string]interface{}{
	"urlpath": func(path string) string {
		return (&url.URL{Path: path}).String()
	},
	"sorted": func(v interface{}) interface{} {
		if sv, ok := v.(sort.Interface); ok {
			sort.Sort(sv)
		}
		return v
	},
	"fmttime": func(t time.Time) string {
		return t.Format("2006-01-02 15:04:05")
	},
	"humanbytes": func(n int64) string {
		switch {
		case n > gib:
			return fmt.Sprintf("%.1f GiB", float64(n)/gib)
		case n > mib:
			return fmt.Sprintf("%.1f MiB", float64(n)/mib)
		case n > kib:
			return fmt.Sprintf("%.1f KiB", float64(n)/kib)
		default:
			return fmt.Sprintf("%d B", n)
		}
	},
	"ellipsis": func(s string, max int) string {
		if utf8.RuneCountInString(s) > max {
			return fmt.Sprintf("%."+fmt.Sprintf("%d", max-1)+"s…", s)
		}
		return s
	},
}

var tpl = template.Must(template.New("").Funcs(fm).Parse(tplstr))

var tplstr = `<!DOCTYPE html>

    <meta charset="utf-8">
    <title>Index on {{.Root}}</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">

  kraken

{{.Root}}

    {{range sorted .Directories}}

        {{ . }}/

    {{end}}

    {{ if and .NumDirectories .NumFiles }}

    {{ end }}

    {{ if .NumFiles }}

      File
      Size
      Mod time

    {{range sorted .Files}}

        {{ ellipsis .Name 50 }}
        {{ humanbytes .Size }}
        {{ fmttime .ModTime }}

    {{end}}

    {{end}}

`

const css = template.CSS(`
* {
  padding: 0;
  margin: 0;
}

html {
  color: rgb(55, 55, 55);
  font-family: Sans;
}

body {
  background: rgb(255, 233, 198);
}

hr {
  display: block;
  border: 0;
  border-top: 3px solid rgb(199, 65, 79);
  margin: 1em 0;
  padding: 0;
}

th {
  font-weight: bold;
  text-align: left;
}

th, td {
  padding: 2px;
}

.header {
  background: rgb(199, 65, 79);
  padding: 22px 15px;
}
.header a, .header a:visited {
  float: right;
  color: rgb(55, 55, 55);
  font-size: 1.2em;
  font-weight: bold;
  transition: color 0.2s;
  text-decoration: none;
}
.header a:hover {
  color: rgb(75, 75, 75);
  transition: color 0.2s;
}

.contents {
  margin-top: 20px;
  margin-left: 20%;
  margin-right: 20%;
  font-size: 0.7em;
}

.contents a, .contents a:visited {
  color: rgb(199, 65, 79);
  padding: 2px;
  background: transparent;
  transition: background 0.3s, color 0.2s;
  text-decoration: none;
}
.contents a:hover {
  background: rgb(199, 65, 79);
  color: rgb(255, 233, 198);
  transition: background 0.2s, color 0.2s;
}
`)
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strconv"
)

// TYPES --------------------------------------------

type VType interface {
	String()  string
	Value()   interface{}
}

// SPECIALS ---------------------------------------------

type VNilType struct { }

func (v *VNilType) String() string {
	return "nil"
}

func (v *VNilType) Value() interface{} {
	return nil
}

func VNil() *VNilType {
	r := new(VNilType)
	return r
}

// BOOLEAN ---------------------------------------------

type VBoolean struct {
	value bool
}

func (v *VBoolean) String() string {
	if v.value {
		return "true"
	}
	return "false"
}

func (v *VBoolean) Value() interface{} {
	return v.value
}

func VTrue() *VBoolean {
	b := new(VBoolean)
	b.value = true
	return b
}

func VFalse() *VBoolean {
	b := new(VBoolean)
	b.value = false
	return b
}

// TOKENS ---------------------------------------------

type VTokens struct {
	value string
}

func (v *VTokens) String() string {
	return "[" + v.value + "]"
}

func (v *VTokens) Value() interface{} {
	return Parse(v.value)
}

func NewVTokens(s string) *VTokens {
	r := new(VTokens)
	r.value = s
	return r
}

// STRING ---------------------------------------------

type VString struct {
	value string
}

func (v *VString) String() string {
	return v.value
}

func (v *VString) Value() interface{} {
	return v.value
}

func NewVString(s string) *VString {
	r := new(VString)
	r.value = s
	return r
}

// Integer ------------------------------------------------

type VInteger struct {
	value int
}

func (v *VInteger) String() string {
	return strconv.Itob(v.value, 10)
}

func (v *VInteger) Value() interface{} {
	return v.value
}

func NewVInteger(s string) *VInteger {
	r := new(VInteger)
	r.value, _ = strconv.Atoi(s)
	return r
}

func NewVIntegerInt(i int) *VInteger {
	r := new(VInteger)
	r.value = i
	return r
}

func BootedTable() *Table {
	tbl := NewTable()

	t := map[string] Function {

		// Type conversion

		"string": func(s *Stack, t *Table) VType {
			v := s.popString()
			s.push(v)
			return v
		},

		// Basic I/O

		"print": func(s *Stack, t *Table) VType {
			v := s.popString()
			fmt.Println(v.String())
			return v
		},

		// Stack operations

		"pop": func(s *Stack, t *Table) VType {
			v := s.pop()
			return v
		},
		"size": func(s *Stack, t *Table) VType {
			v := NewVIntegerInt(s.size())
			s.push(v)
			return v
		},
		"dup": func(s *Stack, t *Table) VType {
			v := s.top()
			s.push(v)
			return v
		},
		"swap": func(s *Stack, t *Table) VType {
			a := s.pop()
			b := s.pop()
			s.push(b)
			s.push(a)
			return a
		},
		"swapp": func(s *Stack, t *Table) VType {
			a := s.pop()
			b := s.pop()
			c := s.pop()
			s.push(b)
			s.push(a)
			s.push(c)
			return c
		},
		"drop": func(s *Stack, t *Table) VType {
			s.clear()
			return VNil()
		},

		// Arithmetic operations

		"add": func(s *Stack, t *Table) VType {
			add := NewVIntegerInt(s.pop().Value().(int) + s.pop().Value().(int))
			s.push(add)
			return add
		},
		"prod": func(s *Stack, t *Table) VType {
			prod := NewVIntegerInt(s.pop().Value().(int) * s.pop().Value().(int))
			s.push(prod)
			return prod
		},
		"sub": func(s *Stack, t *Table) VType {
			sub := NewVIntegerInt(s.pop().Value().(int) - s.pop().Value().(int))
			s.push(sub)
			return sub
		},
		"div": func(s *Stack, t *Table) VType {
			div := NewVIntegerInt(s.pop().Value().(int) / s.pop().Value().(int))
			s.push(div)
			return div
		},

		// Logical

		"true": func(s *Stack, t *Table) VType {
			s.push(VTrue())
			return VNil()
		},
		"false": func(s *Stack, t *Table) VType {
			s.push(VFalse())
			return VNil()
		},
		"nil": func(s *Stack, t *Table) VType {
			s.push(VNil())
			return VNil()
		},

		"or": func(s *Stack, t *Table) VType {
			a := s.pop().Value().(bool)
			b := s.pop().Value().(bool)
			val := VFalse()
			if a || b {
				val = VTrue()
			}
			s.push(val)
			return VNil()
		},
		"and": func(s *Stack, t *Table) VType {
			a := s.pop().Value().(bool)
			b := s.pop().Value().(bool)
			val := VFalse()
			if a && b {
				val = VTrue()
			}
			s.push(val)
			return VNil()
		},
		"not": func(s *Stack, t *Table) VType {
			a := s.pop().Value().(bool)
			val := VTrue()
			if a {
				val = VFalse()
			}
			s.push(val)
			return VNil()
		},

		"eq?": func(s *Stack, t *Table) VType {
			val := VFalse()
			if s.pop().Value() == s.pop().Value() {
				val = VTrue()
			}
			s.push(val)
			return val
		},
		// "gt?": func(s *Stack, t *Table) VType {
		// 	val := VFalse()
		// 	if s.pop().Value() > s.pop().Value() {
		// 		val = VTrue()
		// 	}
		// 	s.push(val)
		// 	return val
		// },
		// "lt?": func(s *Stack, t *Table) VType {
		// 	val := VFalse()
		// 	if s.pop().Value() < s.pop().Value() {
		// 		val = VTrue()
		// 	}
		// 	s.push(val)
		// 	return val
		// },

		// Control flow

		"if": func(s *Stack, t *Table) VType {
			o := s.pop().Value().(*Tokens)
			cond := s.pop()
			if cond.Value().(bool) {
				s, t, _ = Run(o, s, t)
			}
			return VNil()
		},
		"unless": func(s *Stack, t *Table) VType {
			o := s.pop().Value().(*Tokens)
			cond := s.pop().Value().(bool)
			if cond {
				s, t, _ = Run(o, s, t)
			}
			return VNil()
		},
		"if-else": func(s *Stack, t *Table) VType {
			a := s.pop().Value().(*Tokens)
			b := s.pop().Value().(*Tokens)
			cond := s.pop().Value().(bool)
			if cond {
				s, t, _ = Run(b, s, t)
			} else {
				s, t, _ = Run(a, s, t)
			}
			return VNil()
		},
		"else-if": func(s *Stack, t *Table) VType {
			b := s.pop().Value().(*Tokens)
			a := s.pop().Value().(*Tokens)
			cond := s.pop().Value().(bool)
			if cond {
				s, t, _ = Run(b, s, t)
			} else {
				s, t, _ = Run(a, s, t)
			}
			return VNil()
		},
		"call": func(s *Stack, t *Table) VType {
			a := s.pop().Value().(*Tokens)
			Run(a, s, t)
			return VNil()
		},
	}

	tbl.functions = t

	tbl.alias("+", "add")
	tbl.alias("*", "prod")
	tbl.alias("-", "sub")
	tbl.alias("/", "div")

	return tbl
}

func BareEval(code string) {
	tokens := Parse(code)
	Run(tokens, NewStack(), BootedTable())
}

func Eval(code string, stk *Stack, tbl *Table) (s *Stack, t *Table, v VType) {
	tokens := Parse(code)
	return Run(tokens, stk, tbl)
}

func Run(tokens *Tokens, stk *Stack, tbl *Table) (s *Stack, t *Table, v VType) {
	var val VType = VNil()

	for _, tok := range *tokens {
		switch tok.key {
		case "str":
			stk.push(NewVInteger(tok.val))

		case "int":
			stk.push(NewVInteger(tok.val))

		case "stm":
			stk.push(NewVTokens(tok.val))

		case "fun":
			if tbl.has(tok.val) {
				f := tbl.get(tok.val)
				val = f(stk, tbl)
			} else {
				// no function error!
			}

		default:
			// problem?

		}
	}

	// If no value has been set show stack
	if val.Value() == nil {
		val = VNil()
	}

	return stk, tbl, val
}
<commit_msg>Added times function<commit_after>package main

import (
	"fmt"
	"strconv"
)

// TYPES --------------------------------------------

type VType interface {
	String()  string
	Value()   interface{}
}

// SPECIALS ---------------------------------------------

type VNilType struct { }

func (v *VNilType) String() string {
	return "nil"
}

func (v *VNilType) Value() interface{} {
	return nil
}

func VNil() *VNilType {
	r := new(VNilType)
	return r
}

// BOOLEAN ---------------------------------------------

type VBoolean struct {
	value bool
}

func (v *VBoolean) String() string {
	if v.value {
		return "true"
	}
	return "false"
}

func (v *VBoolean) Value() interface{} {
	return v.value
}

func VTrue() *VBoolean {
	b := new(VBoolean)
	b.value = true
	return b
}

func VFalse() *VBoolean {
	b := new(VBoolean)
	b.value = false
	return b
}

// TOKENS ---------------------------------------------

type VTokens struct {
	value string
}

func (v *VTokens) String() string {
	return "[" + v.value + "]"
}

func (v *VTokens) Value() interface{} {
	return Parse(v.value)
}

func NewVTokens(s string) *VTokens {
	r := new(VTokens)
	r.value = s
	return r
}

// STRING ---------------------------------------------

type VString struct {
	value string
}

func (v *VString) String() string {
	return v.value
}

func (v *VString) Value() interface{} {
	return v.value
}

func NewVString(s string) *VString {
	r := new(VString)
	r.value = s
	return r
}

// Integer ------------------------------------------------

type VInteger struct {
	value int
}

func (v *VInteger) String() string {
	return strconv.Itob(v.value, 10)
}

func (v *VInteger) Value() interface{} {
	return v.value
}

func NewVInteger(s string) *VInteger {
	r := new(VInteger)
	r.value, _ = strconv.Atoi(s)
	return r
}

func NewVIntegerInt(i int) *VInteger {
	r := new(VInteger)
	r.value = i
	return r
}

func BootedTable() *Table {
	tbl := NewTable()

	t := map[string] Function {

		// Type conversion

		"string": func(s *Stack, t *Table) VType {
			v := s.popString()
			s.push(v)
			return v
		},

		// Basic I/O

		"print": func(s *Stack, t *Table) VType {
			v := s.popString()
			fmt.Println(v.String())
			return v
		},

		// Stack operations

		"pop": func(s *Stack, t *Table) VType {
			v := s.pop()
			return v
		},
		"size": func(s *Stack, t *Table) VType {
			v := NewVIntegerInt(s.size())
			s.push(v)
			return v
		},
		"dup": func(s *Stack, t *Table) VType {
			v := s.top()
			s.push(v)
			return v
		},
		"swap": func(s *Stack, t *Table) VType {
			a := s.pop()
			b := s.pop()
			s.push(b)
			s.push(a)
			return a
		},
		"swapp": func(s *Stack, t *Table) VType {
			a := s.pop()
			b := s.pop()
			c := s.pop()
			s.push(b)
			s.push(a)
			s.push(c)
			return c
		},
		"drop": func(s *Stack, t *Table) VType {
			s.clear()
			return VNil()
		},

		// Arithmetic operations

		"add": func(s *Stack, t *Table) VType {
			add := NewVIntegerInt(s.pop().Value().(int) + s.pop().Value().(int))
			s.push(add)
			return add
		},
		"prod": func(s *Stack, t *Table) VType {
			prod := NewVIntegerInt(s.pop().Value().(int) * s.pop().Value().(int))
			s.push(prod)
			return prod
		},
		"sub": func(s *Stack, t *Table) VType {
			sub := NewVIntegerInt(s.pop().Value().(int) - s.pop().Value().(int))
			s.push(sub)
			return sub
		},
		"div": func(s *Stack, t *Table) VType {
			div := NewVIntegerInt(s.pop().Value().(int) / s.pop().Value().(int))
			s.push(div)
			return div
		},

		// Logical

		"true": func(s *Stack, t *Table) VType {
			s.push(VTrue())
			return VNil()
		},
		"false": func(s *Stack, t *Table) VType {
			s.push(VFalse())
			return VNil()
		},
		"nil": func(s *Stack, t *Table) VType {
			s.push(VNil())
			return VNil()
		},

		"or": func(s *Stack, t *Table) VType {
			a := s.pop().Value().(bool)
			b := s.pop().Value().(bool)
			val := VFalse()
			if a || b {
				val = VTrue()
			}
			s.push(val)
			return VNil()
		},
		"and": func(s *Stack, t *Table) VType {
			a := s.pop().Value().(bool)
			b := s.pop().Value().(bool)
			val := VFalse()
			if a && b {
				val = VTrue()
			}
			s.push(val)
			return VNil()
		},
		"not": func(s *Stack, t *Table) VType {
			a := s.pop().Value().(bool)
			val := VTrue()
			if a {
				val = VFalse()
			}
			s.push(val)
			return VNil()
		},

		"eq?": func(s *Stack, t *Table) VType {
			val := VFalse()
			if s.pop().Value() == s.pop().Value() {
				val = VTrue()
			}
			s.push(val)
			return val
		},
		// "gt?": func(s *Stack, t *Table) VType {
		// 	val := VFalse()
		// 	if s.pop().Value() > s.pop().Value() {
		// 		val = VTrue()
		// 	}
		// 	s.push(val)
		// 	return val
		// },
		// "lt?": func(s *Stack, t *Table) VType {
		// 	val := VFalse()
		// 	if s.pop().Value() < s.pop().Value() {
		// 		val = VTrue()
		// 	}
		// 	s.push(val)
		// 	return val
		// },

		// Control flow

		"if": func(s *Stack, t *Table) VType {
			o := s.pop().Value().(*Tokens)
			cond := s.pop()
			if cond.Value().(bool) {
				s, t, _ = Run(o, s, t)
			}
			return VNil()
		},
		"unless": func(s *Stack, t *Table) VType {
			o := s.pop().Value().(*Tokens)
			cond := s.pop().Value().(bool)
			if cond {
				s, t, _ = Run(o, s, t)
			}
			return VNil()
		},
		"if-else": func(s *Stack, t *Table) VType {
			a := s.pop().Value().(*Tokens)
			b := s.pop().Value().(*Tokens)
			cond := s.pop().Value().(bool)
			if cond {
				s, t, _ = Run(b, s, t)
			} else {
				s, t, _ = Run(a, s, t)
			}
			return VNil()
		},
		"else-if": func(s *Stack, t *Table) VType {
			b := s.pop().Value().(*Tokens)
			a := s.pop().Value().(*Tokens)
			cond := s.pop().Value().(bool)
			if cond {
				s, t, _ = Run(b, s, t)
			} else {
				s, t, _ = Run(a, s, t)
			}
			return VNil()
		},
		"call": func(s *Stack, t *Table) VType {
			a := s.pop().Value().(*Tokens)
			Run(a, s, t)
			return VNil()
		},
		"times": func(s *Stack, t *Table) VType {
			n := s.pop().Value().(int)
			f := s.pop().Value().(*Tokens)
			for i := 0; i < n; i++ {
				s, t, _ = Run(f, s, t)
			}
			return VNil()
		},

	}

	tbl.functions = t

	tbl.alias("+", "add")
	tbl.alias("*", "prod")
	tbl.alias("-", "sub")
	tbl.alias("/", "div")

	return tbl
}

func BareEval(code string) {
	tokens := Parse(code)
	Run(tokens, NewStack(), BootedTable())
}

func Eval(code string, stk *Stack, tbl *Table) (s *Stack, t *Table, v VType) {
	tokens := Parse(code)
	return Run(tokens, stk, tbl)
}

func Run(tokens *Tokens, stk *Stack, tbl *Table) (s *Stack, t *Table, v VType) {
	var val VType = VNil()

	for _, tok := range *tokens {
		switch tok.key {
		case "str":
			stk.push(NewVInteger(tok.val))

		case "int":
			stk.push(NewVInteger(tok.val))

		case "stm":
			stk.push(NewVTokens(tok.val))

		case "fun":
			if tbl.has(tok.val) {
				f := tbl.get(tok.val)
				val = f(stk, tbl)
			} else {
				// no function error!
			}

		default:
			// problem?

		}
	}

	// If no value has been set show stack
	if val.Value() == nil {
		val = VNil()
	}

	return stk, tbl, val
}
<|endoftext|>